mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-14 19:27:30 +09:00
Import aom library
This is the reference implementation for the Alliance for Open Media's av1 video code. The commit used was 4d668d7feb1f8abd809d1bca0418570a7f142a36.
This commit is contained in:
parent
eb8cd130a8
commit
edc8d83307
989 changed files with 470949 additions and 0 deletions
163
third_party/aom/av1/encoder/aq_complexity.c
vendored
Normal file
163
third_party/aom/av1/encoder/aq_complexity.c
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "av1/encoder/aq_complexity.h"
|
||||
#include "av1/encoder/aq_variance.h"
|
||||
#include "av1/encoder/encodeframe.h"
|
||||
#include "av1/common/seg_common.h"
|
||||
#include "av1/encoder/segmentation.h"
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_ports/system_state.h"
|
||||
|
||||
#define AQ_C_SEGMENTS 5
|
||||
#define DEFAULT_AQ2_SEG 3 // Neutral Q segment
|
||||
#define AQ_C_STRENGTHS 3
|
||||
static const double aq_c_q_adj_factor[AQ_C_STRENGTHS][AQ_C_SEGMENTS] = {
|
||||
{ 1.75, 1.25, 1.05, 1.00, 0.90 },
|
||||
{ 2.00, 1.50, 1.15, 1.00, 0.85 },
|
||||
{ 2.50, 1.75, 1.25, 1.00, 0.80 }
|
||||
};
|
||||
static const double aq_c_transitions[AQ_C_STRENGTHS][AQ_C_SEGMENTS] = {
|
||||
{ 0.15, 0.30, 0.55, 2.00, 100.0 },
|
||||
{ 0.20, 0.40, 0.65, 2.00, 100.0 },
|
||||
{ 0.25, 0.50, 0.75, 2.00, 100.0 }
|
||||
};
|
||||
static const double aq_c_var_thresholds[AQ_C_STRENGTHS][AQ_C_SEGMENTS] = {
|
||||
{ -4.0, -3.0, -2.0, 100.00, 100.0 },
|
||||
{ -3.5, -2.5, -1.5, 100.00, 100.0 },
|
||||
{ -3.0, -2.0, -1.0, 100.00, 100.0 }
|
||||
};
|
||||
|
||||
#define DEFAULT_COMPLEXITY 64
|
||||
|
||||
static int get_aq_c_strength(int q_index, aom_bit_depth_t bit_depth) {
|
||||
// Approximate base quatizer (truncated to int)
|
||||
const int base_quant = av1_ac_quant(q_index, 0, bit_depth) / 4;
|
||||
return (base_quant > 10) + (base_quant > 25);
|
||||
}
|
||||
|
||||
void av1_setup_in_frame_q_adj(AV1_COMP *cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
struct segmentation *const seg = &cm->seg;
|
||||
|
||||
// Make SURE use of floating point in this function is safe.
|
||||
aom_clear_system_state();
|
||||
|
||||
if (frame_is_intra_only(cm) || cm->error_resilient_mode ||
|
||||
cpi->refresh_alt_ref_frame ||
|
||||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) {
|
||||
int segment;
|
||||
const int aq_strength = get_aq_c_strength(cm->base_qindex, cm->bit_depth);
|
||||
|
||||
// Clear down the segment map.
|
||||
memset(cpi->segmentation_map, DEFAULT_AQ2_SEG, cm->mi_rows * cm->mi_cols);
|
||||
|
||||
av1_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) {
|
||||
av1_disable_segmentation(seg);
|
||||
return;
|
||||
}
|
||||
|
||||
av1_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.
|
||||
av1_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 = av1_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) {
|
||||
av1_enable_segfeature(seg, segment, SEG_LVL_ALT_Q);
|
||||
av1_set_segdata(seg, segment, SEG_LVL_ALT_Q, qindex_delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFAULT_LV_THRESH 10.0
|
||||
#define MIN_DEFAULT_LV_THRESH 8.0
|
||||
#define VAR_STRENGTH_STEP 0.25
|
||||
// Select a segment for the current block.
|
||||
// The choice of segment for a block depends on the ratio of the projected
|
||||
// bits for the block vs a target average and its spatial complexity.
|
||||
void av1_caq_select_segment(const AV1_COMP *cpi, MACROBLOCK *mb, BLOCK_SIZE bs,
|
||||
int mi_row, int mi_col, int projected_rate) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
|
||||
const int mi_offset = mi_row * cm->mi_cols + mi_col;
|
||||
const int xmis = AOMMIN(cm->mi_cols - mi_col, mi_size_wide[bs]);
|
||||
const int ymis = AOMMIN(cm->mi_rows - mi_row, mi_size_high[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 int64_t num = (int64_t)cpi->rc.sb64_target_rate * xmis * ymis * 256;
|
||||
const int denom = cm->mib_size * cm->mib_size;
|
||||
const int target_rate = (int)(num / denom);
|
||||
double logvar;
|
||||
double low_var_thresh;
|
||||
const int aq_strength = get_aq_c_strength(cm->base_qindex, cm->bit_depth);
|
||||
|
||||
aom_clear_system_state();
|
||||
low_var_thresh = (cpi->oxcf.pass == 2) ? AOMMAX(cpi->twopass.mb_av_energy,
|
||||
MIN_DEFAULT_LV_THRESH)
|
||||
: DEFAULT_LV_THRESH;
|
||||
|
||||
av1_setup_src_planes(mb, cpi->source, mi_row, mi_col);
|
||||
logvar = av1_log_block_var(cpi, mb, bs);
|
||||
|
||||
segment = AQ_C_SEGMENTS - 1; // Just in case no break out below.
|
||||
for (i = 0; i < AQ_C_SEGMENTS; ++i) {
|
||||
// Test rate against a threshold value and variance against a threshold.
|
||||
// Increasing segment number (higher variance and complexity) = higher Q.
|
||||
if ((projected_rate < target_rate * aq_c_transitions[aq_strength][i]) &&
|
||||
(logvar < (low_var_thresh + aq_c_var_thresholds[aq_strength][i]))) {
|
||||
segment = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the entires in the segment map corresponding to this SB64.
|
||||
for (y = 0; y < ymis; y++) {
|
||||
for (x = 0; x < xmis; x++) {
|
||||
cpi->segmentation_map[mi_offset + y * cm->mi_cols + x] = segment;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
third_party/aom/av1/encoder/aq_complexity.h
vendored
Normal file
37
third_party/aom/av1/encoder/aq_complexity.h
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_AQ_COMPLEXITY_H_
|
||||
#define AV1_ENCODER_AQ_COMPLEXITY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
struct AV1_COMP;
|
||||
struct macroblock;
|
||||
|
||||
// Select a segment for the current Block.
|
||||
void av1_caq_select_segment(const struct AV1_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 av1_setup_in_frame_q_adj(struct AV1_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_AQ_COMPLEXITY_H_
|
||||
566
third_party/aom/av1/encoder/aq_cyclicrefresh.c
vendored
Normal file
566
third_party/aom/av1/encoder/aq_cyclicrefresh.c
vendored
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "av1/common/seg_common.h"
|
||||
#include "av1/encoder/aq_cyclicrefresh.h"
|
||||
#include "av1/encoder/ratectrl.h"
|
||||
#include "av1/encoder/segmentation.h"
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_ports/system_state.h"
|
||||
|
||||
struct CYCLIC_REFRESH {
|
||||
// Percentage of blocks per frame that are targeted as candidates
|
||||
// for cyclic refresh.
|
||||
int percent_refresh;
|
||||
// Maximum q-delta as percentage of base q.
|
||||
int max_qdelta_perc;
|
||||
// Superblock starting index for cycling through the frame.
|
||||
int sb_index;
|
||||
// Controls how long block will need to wait to be refreshed again, in
|
||||
// excess of the cycle time, i.e., in the case of all zero motion, block
|
||||
// will be refreshed every (100/percent_refresh + time_for_refresh) frames.
|
||||
int time_for_refresh;
|
||||
// Target number of (8x8) blocks that are set for delta-q.
|
||||
int target_num_seg_blocks;
|
||||
// Actual number of (8x8) blocks that were applied delta-q.
|
||||
int actual_num_seg1_blocks;
|
||||
int actual_num_seg2_blocks;
|
||||
// RD mult. parameters for segment 1.
|
||||
int rdmult;
|
||||
// Cyclic refresh map.
|
||||
signed char *map;
|
||||
// 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];
|
||||
};
|
||||
|
||||
CYCLIC_REFRESH *av1_cyclic_refresh_alloc(int mi_rows, int mi_cols) {
|
||||
size_t last_coded_q_map_size;
|
||||
CYCLIC_REFRESH *const cr = aom_calloc(1, sizeof(*cr));
|
||||
if (cr == NULL) return NULL;
|
||||
|
||||
cr->map = aom_calloc(mi_rows * mi_cols, sizeof(*cr->map));
|
||||
if (cr->map == NULL) {
|
||||
av1_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 = aom_malloc(last_coded_q_map_size);
|
||||
if (cr->last_coded_q_map == NULL) {
|
||||
av1_cyclic_refresh_free(cr);
|
||||
return NULL;
|
||||
}
|
||||
assert(MAXQ <= 255);
|
||||
memset(cr->last_coded_q_map, MAXQ, last_coded_q_map_size);
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
void av1_cyclic_refresh_free(CYCLIC_REFRESH *cr) {
|
||||
aom_free(cr->map);
|
||||
aom_free(cr->last_coded_q_map);
|
||||
aom_free(cr);
|
||||
}
|
||||
|
||||
// Check if we should turn off cyclic refresh based on bitrate condition.
|
||||
static int apply_cyclic_refresh_bitrate(const AV1_COMMON *cm,
|
||||
const RATE_CONTROL *rc) {
|
||||
// Turn off cyclic refresh if bits available per frame is not sufficiently
|
||||
// larger than bit cost of segmentation. Segment map bit cost should scale
|
||||
// with number of seg blocks, so compare available bits to number of blocks.
|
||||
// Average bits available per frame = avg_frame_bandwidth
|
||||
// Number of (8x8) blocks in frame = mi_rows * mi_cols;
|
||||
const float factor = 0.25;
|
||||
const int number_blocks = cm->mi_rows * cm->mi_cols;
|
||||
// The condition below corresponds to turning off at target bitrates:
|
||||
// (at 30fps), ~12kbps for CIF, 36kbps for VGA, 100kps for HD/720p.
|
||||
// Also turn off at very small frame sizes, to avoid too large fraction of
|
||||
// superblocks to be refreshed per frame. Threshold below is less than QCIF.
|
||||
if (rc->avg_frame_bandwidth < factor * number_blocks ||
|
||||
number_blocks / 64 < 5)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if this coding block, of size bsize, should be considered for refresh
|
||||
// (lower-qp coding). Decision can be based on various factors, such as
|
||||
// size of the coding block (i.e., below min_block size rejected), coding
|
||||
// mode, and rate/distortion.
|
||||
static int candidate_refresh_aq(const CYCLIC_REFRESH *cr,
|
||||
const MB_MODE_INFO *mbmi, int64_t rate,
|
||||
int64_t dist, int bsize) {
|
||||
MV mv = mbmi->mv[0].as_mv;
|
||||
// Reject the block for lower-qp coding if projected distortion
|
||||
// is above the threshold, and any of the following is true:
|
||||
// 1) mode uses large mv
|
||||
// 2) mode is an intra-mode
|
||||
// Otherwise accept for refresh.
|
||||
if (dist > cr->thresh_dist_sb &&
|
||||
(mv.row > cr->motion_thresh || mv.row < -cr->motion_thresh ||
|
||||
mv.col > cr->motion_thresh || mv.col < -cr->motion_thresh ||
|
||||
!is_inter_block(mbmi)))
|
||||
return CR_SEGMENT_ID_BASE;
|
||||
else if (bsize >= BLOCK_16X16 && rate < cr->thresh_rate_sb &&
|
||||
is_inter_block(mbmi) && mbmi->mv[0].as_int == 0 &&
|
||||
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 AV1_COMP *cpi, int q, double rate_factor) {
|
||||
const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
int deltaq = av1_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 av1_cyclic_refresh_estimate_bits_at_q(const AV1_COMP *cpi,
|
||||
double correction_factor) {
|
||||
const AV1_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) *
|
||||
av1_estimate_bits_at_q(cm->frame_type, cm->base_qindex, mbs,
|
||||
correction_factor, cm->bit_depth) +
|
||||
weight_segment1 *
|
||||
av1_estimate_bits_at_q(cm->frame_type,
|
||||
cm->base_qindex + cr->qindex_delta[1],
|
||||
mbs, correction_factor, cm->bit_depth) +
|
||||
weight_segment2 *
|
||||
av1_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 av1_cyclic_refresh_rc_bits_per_mb(const AV1_COMP *cpi, int i,
|
||||
double correction_factor) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
int bits_per_mb;
|
||||
int num8x8bl = cm->MBs << 2;
|
||||
// Weight for segment prior to encoding: take the average of the target
|
||||
// number for the frame to be encoded and the actual from the previous frame.
|
||||
double weight_segment =
|
||||
(double)((cr->target_num_seg_blocks + cr->actual_num_seg1_blocks +
|
||||
cr->actual_num_seg2_blocks) >>
|
||||
1) /
|
||||
num8x8bl;
|
||||
// Compute delta-q corresponding to qindex i.
|
||||
int deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta);
|
||||
// Take segment weighted average for bits per mb.
|
||||
bits_per_mb = (int)((1.0 - weight_segment) *
|
||||
av1_rc_bits_per_mb(cm->frame_type, i,
|
||||
correction_factor, cm->bit_depth) +
|
||||
weight_segment *
|
||||
av1_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 av1_cyclic_refresh_update_segment(const AV1_COMP *cpi,
|
||||
MB_MODE_INFO *const mbmi, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize,
|
||||
int64_t rate, int64_t dist, int skip) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
const int bw = mi_size_wide[bsize];
|
||||
const int bh = mi_size_high[bsize];
|
||||
const int xmis = AOMMIN(cm->mi_cols - mi_col, bw);
|
||||
const int ymis = AOMMIN(cm->mi_rows - mi_row, bh);
|
||||
const int block_index = mi_row * cm->mi_cols + mi_col;
|
||||
const int refresh_this_block =
|
||||
candidate_refresh_aq(cr, mbmi, rate, dist, bsize);
|
||||
// Default is to not update the refresh map.
|
||||
int new_map_value = cr->map[block_index];
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
// If this block is labeled for refresh, check if we should reset the
|
||||
// segment_id.
|
||||
if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) {
|
||||
mbmi->segment_id = refresh_this_block;
|
||||
// Reset segment_id if will be skipped.
|
||||
if (skip) mbmi->segment_id = CR_SEGMENT_ID_BASE;
|
||||
}
|
||||
|
||||
// Update the cyclic refresh map, to be used for setting segmentation map
|
||||
// for the next frame. If the block will be refreshed this frame, mark it
|
||||
// as clean. The magnitude of the -ve influences how long before we consider
|
||||
// it for refresh again.
|
||||
if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) {
|
||||
new_map_value = -cr->time_for_refresh;
|
||||
} else if (refresh_this_block) {
|
||||
// Else if it is accepted as candidate for refresh, and has not already
|
||||
// been refreshed (marked as 1) then mark it as a candidate for cleanup
|
||||
// for future time (marked as 0), otherwise don't update it.
|
||||
if (cr->map[block_index] == 1) new_map_value = 0;
|
||||
} else {
|
||||
// Leave it marked as block that is not candidate for refresh.
|
||||
new_map_value = 1;
|
||||
}
|
||||
|
||||
// Update entries in the cyclic refresh map with new_map_value, and
|
||||
// copy mbmi->segment_id into global segmentation map.
|
||||
for (y = 0; y < ymis; y++)
|
||||
for (x = 0; x < xmis; x++) {
|
||||
int map_offset = block_index + y * cm->mi_cols + x;
|
||||
cr->map[map_offset] = new_map_value;
|
||||
cpi->segmentation_map[map_offset] = mbmi->segment_id;
|
||||
// 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(mbmi) || !skip) &&
|
||||
mbmi->segment_id <= CR_SEGMENT_ID_BOOST2) {
|
||||
cr->last_coded_q_map[map_offset] = clamp(
|
||||
cm->base_qindex + cr->qindex_delta[mbmi->segment_id], 0, MAXQ);
|
||||
} else if (is_inter_block(mbmi) && skip &&
|
||||
mbmi->segment_id <= CR_SEGMENT_ID_BOOST2) {
|
||||
cr->last_coded_q_map[map_offset] =
|
||||
AOMMIN(clamp(cm->base_qindex + cr->qindex_delta[mbmi->segment_id],
|
||||
0, MAXQ),
|
||||
cr->last_coded_q_map[map_offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the actual number of blocks that were applied the segment delta q.
|
||||
void av1_cyclic_refresh_postencode(AV1_COMP *const cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
unsigned char *const seg_map = cpi->segmentation_map;
|
||||
int mi_row, mi_col;
|
||||
cr->actual_num_seg1_blocks = 0;
|
||||
cr->actual_num_seg2_blocks = 0;
|
||||
for (mi_row = 0; mi_row < cm->mi_rows; mi_row++)
|
||||
for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
|
||||
if (cyclic_refresh_segment_id(seg_map[mi_row * cm->mi_cols + mi_col]) ==
|
||||
CR_SEGMENT_ID_BOOST1)
|
||||
cr->actual_num_seg1_blocks++;
|
||||
else if (cyclic_refresh_segment_id(
|
||||
seg_map[mi_row * cm->mi_cols + mi_col]) ==
|
||||
CR_SEGMENT_ID_BOOST2)
|
||||
cr->actual_num_seg2_blocks++;
|
||||
}
|
||||
}
|
||||
|
||||
// Set golden frame update interval, for 1 pass CBR mode.
|
||||
void av1_cyclic_refresh_set_golden_update(AV1_COMP *const cpi) {
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
// Set minimum gf_interval for GF update to a multiple (== 2) of refresh
|
||||
// period. Depending on past encoding stats, GF flag may be reset and update
|
||||
// may not occur until next baseline_gf_interval.
|
||||
if (cr->percent_refresh > 0)
|
||||
rc->baseline_gf_interval = 4 * (100 / cr->percent_refresh);
|
||||
else
|
||||
rc->baseline_gf_interval = 40;
|
||||
}
|
||||
|
||||
// Update some encoding stats (from the just encoded frame). If this frame's
|
||||
// background has high motion, refresh the golden frame. Otherwise, if the
|
||||
// golden reference is to be updated check if we should NOT update the golden
|
||||
// ref.
|
||||
void av1_cyclic_refresh_check_golden_update(AV1_COMP *const cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
int mi_row, mi_col;
|
||||
double fraction_low = 0.0;
|
||||
int low_content_frame = 0;
|
||||
|
||||
MODE_INFO **mi;
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
const int rows = cm->mi_rows, cols = cm->mi_cols;
|
||||
int cnt1 = 0, cnt2 = 0;
|
||||
int force_gf_refresh = 0;
|
||||
|
||||
for (mi_row = 0; mi_row < rows; mi_row++) {
|
||||
mi = cm->mi_grid_visible + mi_row * cm->mi_stride;
|
||||
|
||||
for (mi_col = 0; mi_col < cols; mi_col++) {
|
||||
int16_t abs_mvr = mi[0]->mbmi.mv[0].as_mv.row >= 0
|
||||
? mi[0]->mbmi.mv[0].as_mv.row
|
||||
: -1 * mi[0]->mbmi.mv[0].as_mv.row;
|
||||
int16_t abs_mvc = mi[0]->mbmi.mv[0].as_mv.col >= 0
|
||||
? mi[0]->mbmi.mv[0].as_mv.col
|
||||
: -1 * mi[0]->mbmi.mv[0].as_mv.col;
|
||||
|
||||
// Calculate the motion of the background.
|
||||
if (abs_mvr <= 16 && abs_mvc <= 16) {
|
||||
cnt1++;
|
||||
if (abs_mvr == 0 && abs_mvc == 0) cnt2++;
|
||||
}
|
||||
mi++;
|
||||
|
||||
// Accumulate low_content_frame.
|
||||
if (cr->map[mi_row * cols + mi_col] < 1) low_content_frame++;
|
||||
}
|
||||
}
|
||||
|
||||
// For video conference clips, if the background has high motion in current
|
||||
// frame because of the camera movement, set this frame as the golden frame.
|
||||
// Use 70% and 5% as the thresholds for golden frame refreshing.
|
||||
// Also, force this frame as a golden update frame if this frame will change
|
||||
// the resolution (resize_pending != 0).
|
||||
if (cpi->resize_pending != 0 ||
|
||||
(cnt1 * 10 > (70 * rows * cols) && cnt2 * 20 < cnt1)) {
|
||||
av1_cyclic_refresh_set_golden_update(cpi);
|
||||
rc->frames_till_gf_update_due = rc->baseline_gf_interval;
|
||||
|
||||
if (rc->frames_till_gf_update_due > rc->frames_to_key)
|
||||
rc->frames_till_gf_update_due = rc->frames_to_key;
|
||||
cpi->refresh_golden_frame = 1;
|
||||
force_gf_refresh = 1;
|
||||
}
|
||||
|
||||
fraction_low = (double)low_content_frame / (rows * cols);
|
||||
// Update average.
|
||||
cr->low_content_avg = (fraction_low + 3 * cr->low_content_avg) / 4;
|
||||
if (!force_gf_refresh && cpi->refresh_golden_frame == 1) {
|
||||
// Don't update golden reference if the amount of low_content for the
|
||||
// current encoded frame is small, or if the recursive average of the
|
||||
// low_content over the update interval window falls below threshold.
|
||||
if (fraction_low < 0.8 || cr->low_content_avg < 0.7)
|
||||
cpi->refresh_golden_frame = 0;
|
||||
// Reset for next internal.
|
||||
cr->low_content_avg = fraction_low;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the segmentation map, and related quantities: cyclic refresh map,
|
||||
// refresh sb_index, and target number of blocks to be refreshed.
|
||||
// The map is set to either 0/CR_SEGMENT_ID_BASE (no refresh) or to
|
||||
// 1/CR_SEGMENT_ID_BOOST1 (refresh) for each superblock.
|
||||
// Blocks labeled as BOOST1 may later get set to BOOST2 (during the
|
||||
// encoding of the superblock).
|
||||
static void cyclic_refresh_update_map(AV1_COMP *const cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
unsigned char *const seg_map = cpi->segmentation_map;
|
||||
int i, block_count, bl_index, sb_rows, sb_cols, sbs_in_frame;
|
||||
int xmis, ymis, x, y;
|
||||
memset(seg_map, CR_SEGMENT_ID_BASE, cm->mi_rows * cm->mi_cols);
|
||||
sb_cols = (cm->mi_cols + cm->mib_size - 1) / cm->mib_size;
|
||||
sb_rows = (cm->mi_rows + cm->mib_size - 1) / cm->mib_size;
|
||||
sbs_in_frame = sb_cols * sb_rows;
|
||||
// Number of target blocks to get the q delta (segment 1).
|
||||
block_count = cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100;
|
||||
// Set the segmentation map: cycle through the superblocks, starting at
|
||||
// cr->mb_index, and stopping when either block_count blocks have been found
|
||||
// to be refreshed, or we have passed through whole frame.
|
||||
assert(cr->sb_index < sbs_in_frame);
|
||||
i = cr->sb_index;
|
||||
cr->target_num_seg_blocks = 0;
|
||||
do {
|
||||
int sum_map = 0;
|
||||
// Get the mi_row/mi_col corresponding to superblock index i.
|
||||
int sb_row_index = (i / sb_cols);
|
||||
int sb_col_index = i - sb_row_index * sb_cols;
|
||||
int mi_row = sb_row_index * cm->mib_size;
|
||||
int mi_col = sb_col_index * cm->mib_size;
|
||||
int qindex_thresh =
|
||||
cpi->oxcf.content == AOM_CONTENT_SCREEN
|
||||
? av1_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST2, cm->base_qindex)
|
||||
: 0;
|
||||
assert(mi_row >= 0 && mi_row < cm->mi_rows);
|
||||
assert(mi_col >= 0 && mi_col < cm->mi_cols);
|
||||
bl_index = mi_row * cm->mi_cols + mi_col;
|
||||
// Loop through all MI blocks in superblock and update map.
|
||||
xmis = AOMMIN(cm->mi_cols - mi_col, cm->mib_size);
|
||||
ymis = AOMMIN(cm->mi_rows - mi_row, cm->mib_size);
|
||||
for (y = 0; y < ymis; y++) {
|
||||
for (x = 0; x < xmis; x++) {
|
||||
const int bl_index2 = bl_index + y * cm->mi_cols + x;
|
||||
// If the block is as a candidate for clean up then mark it
|
||||
// for possible boost/refresh (segment 1). The segment id may get
|
||||
// reset to 0 later if block gets coded anything other than ZEROMV.
|
||||
if (cr->map[bl_index2] == 0) {
|
||||
if (cr->last_coded_q_map[bl_index2] > qindex_thresh) sum_map++;
|
||||
} else if (cr->map[bl_index2] < 0) {
|
||||
cr->map[bl_index2]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Enforce constant segment over superblock.
|
||||
// If segment is at least half of superblock, set to 1.
|
||||
if (sum_map >= xmis * ymis / 2) {
|
||||
for (y = 0; y < ymis; y++)
|
||||
for (x = 0; x < xmis; x++) {
|
||||
seg_map[bl_index + y * cm->mi_cols + x] = CR_SEGMENT_ID_BOOST1;
|
||||
}
|
||||
cr->target_num_seg_blocks += xmis * ymis;
|
||||
}
|
||||
i++;
|
||||
if (i == sbs_in_frame) {
|
||||
i = 0;
|
||||
}
|
||||
} while (cr->target_num_seg_blocks < block_count && i != cr->sb_index);
|
||||
cr->sb_index = i;
|
||||
}
|
||||
|
||||
// Set cyclic refresh parameters.
|
||||
void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) {
|
||||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
cr->percent_refresh = 10;
|
||||
cr->max_qdelta_perc = 50;
|
||||
cr->time_for_refresh = 0;
|
||||
// Use larger delta-qp (increase rate_ratio_qdelta) for first few (~4)
|
||||
// periods of the refresh cycle, after a key frame.
|
||||
if (rc->frames_since_key < 4 * cr->percent_refresh)
|
||||
cr->rate_ratio_qdelta = 3.0;
|
||||
else
|
||||
cr->rate_ratio_qdelta = 2.0;
|
||||
// Adjust some parameters for low resolutions at low bitrates.
|
||||
if (cm->width <= 352 && cm->height <= 288 && rc->avg_frame_bandwidth < 3400) {
|
||||
cr->motion_thresh = 4;
|
||||
cr->rate_boost_fac = 10;
|
||||
} else {
|
||||
cr->motion_thresh = 32;
|
||||
cr->rate_boost_fac = 17;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup cyclic background refresh: set delta q and segmentation map.
|
||||
void av1_cyclic_refresh_setup(AV1_COMP *const cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
const RATE_CONTROL *const rc = &cpi->rc;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
struct segmentation *const seg = &cm->seg;
|
||||
const int apply_cyclic_refresh = apply_cyclic_refresh_bitrate(cm, rc);
|
||||
if (cm->current_video_frame == 0) cr->low_content_avg = 0.0;
|
||||
// Don't apply refresh on key frame or enhancement layer frames.
|
||||
if (!apply_cyclic_refresh || cm->frame_type == KEY_FRAME) {
|
||||
// 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);
|
||||
av1_disable_segmentation(&cm->seg);
|
||||
if (cm->frame_type == KEY_FRAME) {
|
||||
memset(cr->last_coded_q_map, MAXQ,
|
||||
cm->mi_rows * cm->mi_cols * sizeof(*cr->last_coded_q_map));
|
||||
cr->sb_index = 0;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
int qindex_delta = 0;
|
||||
int qindex2;
|
||||
const double q = av1_convert_qindex_to_q(cm->base_qindex, cm->bit_depth);
|
||||
aom_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:
|
||||
// av1_convert_qindex_to_q(), av1_ac_quant(), ac_qlookup*[].
|
||||
cr->thresh_dist_sb = ((int64_t)(q * q)) << 2;
|
||||
|
||||
// Set up segmentation.
|
||||
// Clear down the segment map.
|
||||
av1_enable_segmentation(&cm->seg);
|
||||
av1_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
|
||||
// av1_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.
|
||||
av1_disable_segfeature(seg, CR_SEGMENT_ID_BASE, SEG_LVL_ALT_Q);
|
||||
// Use segment BOOST1 for in-frame Q adjustment.
|
||||
av1_enable_segfeature(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q);
|
||||
// Use segment BOOST2 for more aggressive in-frame Q adjustment.
|
||||
av1_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 = av1_compute_rd_mult(cpi, qindex2);
|
||||
|
||||
av1_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,
|
||||
AOMMIN(CR_MAX_RATE_TARGET_RATIO,
|
||||
0.1 * cr->rate_boost_fac * cr->rate_ratio_qdelta));
|
||||
cr->qindex_delta[2] = qindex_delta;
|
||||
av1_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 av1_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH *cr) {
|
||||
return cr->rdmult;
|
||||
}
|
||||
|
||||
void av1_cyclic_refresh_reset_resize(AV1_COMP *const cpi) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
|
||||
memset(cr->map, 0, cm->mi_rows * cm->mi_cols);
|
||||
cr->sb_index = 0;
|
||||
cpi->refresh_golden_frame = 1;
|
||||
}
|
||||
98
third_party/aom/av1/encoder/aq_cyclicrefresh.h
vendored
Normal file
98
third_party/aom/av1/encoder/aq_cyclicrefresh.h
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_AQ_CYCLICREFRESH_H_
|
||||
#define AV1_ENCODER_AQ_CYCLICREFRESH_H_
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// The segment ids used in cyclic refresh: from base (no boost) to increasing
|
||||
// boost (higher delta-qp).
|
||||
#define CR_SEGMENT_ID_BASE 0
|
||||
#define CR_SEGMENT_ID_BOOST1 1
|
||||
#define CR_SEGMENT_ID_BOOST2 2
|
||||
|
||||
// Maximum rate target ratio for setting segment delta-qp.
|
||||
#define CR_MAX_RATE_TARGET_RATIO 4.0
|
||||
|
||||
struct AV1_COMP;
|
||||
|
||||
struct CYCLIC_REFRESH;
|
||||
typedef struct CYCLIC_REFRESH CYCLIC_REFRESH;
|
||||
|
||||
CYCLIC_REFRESH *av1_cyclic_refresh_alloc(int mi_rows, int mi_cols);
|
||||
|
||||
void av1_cyclic_refresh_free(CYCLIC_REFRESH *cr);
|
||||
|
||||
// Estimate the bits, incorporating the delta-q from segment 1, after encoding
|
||||
// the frame.
|
||||
int av1_cyclic_refresh_estimate_bits_at_q(const struct AV1_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 av1_cyclic_refresh_rc_bits_per_mb(const struct AV1_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 av1_cyclic_refresh_update_segment(const struct AV1_COMP *cpi,
|
||||
MB_MODE_INFO *const mbmi, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize,
|
||||
int64_t rate, int64_t dist, int skip);
|
||||
|
||||
// Update the segmentation map, and related quantities: cyclic refresh map,
|
||||
// refresh sb_index, and target number of blocks to be refreshed.
|
||||
void av1_cyclic_refresh_update__map(struct AV1_COMP *const cpi);
|
||||
|
||||
// Update the actual number of blocks that were applied the segment delta q.
|
||||
void av1_cyclic_refresh_postencode(struct AV1_COMP *const cpi);
|
||||
|
||||
// Set golden frame update interval, for 1 pass CBR mode.
|
||||
void av1_cyclic_refresh_set_golden_update(struct AV1_COMP *const cpi);
|
||||
|
||||
// Check if we should not update golden reference, based on past refresh stats.
|
||||
void av1_cyclic_refresh_check_golden_update(struct AV1_COMP *const cpi);
|
||||
|
||||
// Set/update global/frame level refresh parameters.
|
||||
void av1_cyclic_refresh_update_parameters(struct AV1_COMP *const cpi);
|
||||
|
||||
// Setup cyclic background refresh: set delta q and segmentation map.
|
||||
void av1_cyclic_refresh_setup(struct AV1_COMP *const cpi);
|
||||
|
||||
int av1_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH *cr);
|
||||
|
||||
void av1_cyclic_refresh_reset_resize(struct AV1_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;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_AQ_CYCLICREFRESH_H_
|
||||
207
third_party/aom/av1/encoder/aq_variance.c
vendored
Normal file
207
third_party/aom/av1/encoder/aq_variance.c
vendored
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "aom_ports/mem.h"
|
||||
|
||||
#include "av1/encoder/aq_variance.h"
|
||||
|
||||
#include "av1/common/seg_common.h"
|
||||
#include "av1/encoder/ratectrl.h"
|
||||
#include "av1/encoder/rd.h"
|
||||
#include "av1/encoder/segmentation.h"
|
||||
#include "aom_ports/system_state.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, av1_all_zeros[MAX_SB_SIZE]) = { 0 };
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
DECLARE_ALIGNED(16, static const uint16_t,
|
||||
av1_highbd_all_zeros[MAX_SB_SIZE]) = { 0 };
|
||||
#endif
|
||||
|
||||
unsigned int av1_vaq_segment_id(int energy) {
|
||||
ENERGY_IN_BOUNDS(energy);
|
||||
return SEGMENT_ID(energy);
|
||||
}
|
||||
|
||||
void av1_vaq_frame_setup(AV1_COMP *cpi) {
|
||||
AV1_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->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) {
|
||||
cpi->vaq_refresh = 1;
|
||||
|
||||
av1_enable_segmentation(seg);
|
||||
av1_clearall_segfeatures(seg);
|
||||
|
||||
seg->abs_delta = SEGMENT_DELTADATA;
|
||||
|
||||
aom_clear_system_state();
|
||||
|
||||
for (i = 0; i < MAX_SEGMENTS; ++i) {
|
||||
int qindex_delta =
|
||||
av1_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;
|
||||
}
|
||||
|
||||
av1_set_segdata(seg, i, SEG_LVL_ALT_Q, qindex_delta);
|
||||
av1_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_HIGHBITDEPTH
|
||||
static void aq_highbd_variance64(const uint8_t *a8, int a_stride,
|
||||
const uint8_t *b8, int b_stride, int w, int h,
|
||||
uint64_t *sse, uint64_t *sum) {
|
||||
int i, j;
|
||||
|
||||
uint16_t *a = CONVERT_TO_SHORTPTR(a8);
|
||||
uint16_t *b = CONVERT_TO_SHORTPTR(b8);
|
||||
*sum = 0;
|
||||
*sse = 0;
|
||||
|
||||
for (i = 0; i < h; i++) {
|
||||
for (j = 0; j < w; j++) {
|
||||
const int diff = a[j] - b[j];
|
||||
*sum += diff;
|
||||
*sse += diff * diff;
|
||||
}
|
||||
a += a_stride;
|
||||
b += b_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void aq_highbd_8_variance(const uint8_t *a8, int a_stride,
|
||||
const uint8_t *b8, int b_stride, int w, int h,
|
||||
unsigned int *sse, int *sum) {
|
||||
uint64_t sse_long = 0;
|
||||
uint64_t sum_long = 0;
|
||||
aq_highbd_variance64(a8, a_stride, b8, b_stride, w, h, &sse_long, &sum_long);
|
||||
*sse = (unsigned int)sse_long;
|
||||
*sum = (int)sum_long;
|
||||
}
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
|
||||
static unsigned int block_variance(const AV1_COMP *const 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 * mi_size_wide[bs] - right_overflow;
|
||||
const int bh = 8 * mi_size_high[bs] - bottom_overflow;
|
||||
int avg;
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
aq_highbd_8_variance(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
CONVERT_TO_BYTEPTR(av1_highbd_all_zeros), 0, bw, bh,
|
||||
&sse, &avg);
|
||||
sse >>= 2 * (xd->bd - 8);
|
||||
avg >>= (xd->bd - 8);
|
||||
} else {
|
||||
aq_variance(x->plane[0].src.buf, x->plane[0].src.stride, av1_all_zeros, 0,
|
||||
bw, bh, &sse, &avg);
|
||||
}
|
||||
#else
|
||||
aq_variance(x->plane[0].src.buf, x->plane[0].src.stride, av1_all_zeros, 0,
|
||||
bw, bh, &sse, &avg);
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
var = sse - (unsigned int)(((int64_t)avg * avg) / (bw * bh));
|
||||
return (unsigned int)((uint64_t)var * 256) / (bw * bh);
|
||||
} else {
|
||||
#if CONFIG_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(av1_highbd_all_zeros), 0, &sse);
|
||||
} else {
|
||||
var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
av1_all_zeros, 0, &sse);
|
||||
}
|
||||
#else
|
||||
var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
av1_all_zeros, 0, &sse);
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
return (unsigned int)((uint64_t)var * 256) >> num_pels_log2_lookup[bs];
|
||||
}
|
||||
}
|
||||
|
||||
double av1_log_block_var(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) {
|
||||
unsigned int var = block_variance(cpi, x, bs);
|
||||
aom_clear_system_state();
|
||||
return log(var + 1.0);
|
||||
}
|
||||
|
||||
#define DEFAULT_E_MIDPOINT 10.0
|
||||
int av1_block_energy(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) {
|
||||
double energy;
|
||||
double energy_midpoint;
|
||||
aom_clear_system_state();
|
||||
energy_midpoint =
|
||||
(cpi->oxcf.pass == 2) ? cpi->twopass.mb_av_energy : DEFAULT_E_MIDPOINT;
|
||||
energy = av1_log_block_var(cpi, x, bs) - energy_midpoint;
|
||||
return clamp((int)round(energy), ENERGY_MIN, ENERGY_MAX);
|
||||
}
|
||||
31
third_party/aom/av1/encoder/aq_variance.h
vendored
Normal file
31
third_party/aom/av1/encoder/aq_variance.h
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_AQ_VARIANCE_H_
|
||||
#define AV1_ENCODER_AQ_VARIANCE_H_
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned int av1_vaq_segment_id(int energy);
|
||||
void av1_vaq_frame_setup(AV1_COMP *cpi);
|
||||
|
||||
int av1_block_energy(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs);
|
||||
double av1_log_block_var(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_AQ_VARIANCE_H_
|
||||
36
third_party/aom/av1/encoder/arm/neon/dct_neon.c
vendored
Normal file
36
third_party/aom/av1/encoder/arm/neon/dct_neon.c
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
#include "./aom_config.h"
|
||||
#include "./aom_dsp_rtcd.h"
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
#include "aom_dsp/txfm_common.h"
|
||||
|
||||
void av1_fdct8x8_quant_neon(const int16_t *input, int stride,
|
||||
int16_t *coeff_ptr, intptr_t n_coeffs,
|
||||
int skip_block, const int16_t *zbin_ptr,
|
||||
const int16_t *round_ptr, const int16_t *quant_ptr,
|
||||
const int16_t *quant_shift_ptr, int16_t *qcoeff_ptr,
|
||||
int16_t *dqcoeff_ptr, const int16_t *dequant_ptr,
|
||||
uint16_t *eob_ptr, const int16_t *scan_ptr,
|
||||
const int16_t *iscan_ptr) {
|
||||
int16_t temp_buffer[64];
|
||||
(void)coeff_ptr;
|
||||
|
||||
aom_fdct8x8_neon(input, temp_buffer, stride);
|
||||
av1_quantize_fp_neon(temp_buffer, n_coeffs, skip_block, zbin_ptr, round_ptr,
|
||||
quant_ptr, quant_shift_ptr, qcoeff_ptr, dqcoeff_ptr,
|
||||
dequant_ptr, eob_ptr, scan_ptr, iscan_ptr);
|
||||
}
|
||||
42
third_party/aom/av1/encoder/arm/neon/error_neon.c
vendored
Normal file
42
third_party/aom/av1/encoder/arm/neon/error_neon.c
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <arm_neon.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
|
||||
int64_t av1_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);
|
||||
}
|
||||
118
third_party/aom/av1/encoder/arm/neon/quantize_neon.c
vendored
Normal file
118
third_party/aom/av1/encoder/arm/neon/quantize_neon.c
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "aom_mem/aom_mem.h"
|
||||
|
||||
#include "av1/common/quant_common.h"
|
||||
#include "av1/common/seg_common.h"
|
||||
|
||||
#include "av1/encoder/av1_quantize.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/rd.h"
|
||||
|
||||
void av1_quantize_fp_neon(const int16_t *coeff_ptr, intptr_t count,
|
||||
int skip_block, const int16_t *zbin_ptr,
|
||||
const int16_t *round_ptr, const int16_t *quant_ptr,
|
||||
const int16_t *quant_shift_ptr, int16_t *qcoeff_ptr,
|
||||
int16_t *dqcoeff_ptr, const int16_t *dequant_ptr,
|
||||
uint16_t *eob_ptr, const int16_t *scan,
|
||||
const int16_t *iscan) {
|
||||
// TODO(jingning) Decide the need of these arguments after the
|
||||
// quantization process is completed.
|
||||
(void)zbin_ptr;
|
||||
(void)quant_shift_ptr;
|
||||
(void)scan;
|
||||
|
||||
if (!skip_block) {
|
||||
// Quantization pass: All coefficients with index >= zero_flag are
|
||||
// skippable. Note: zero_flag can be zero.
|
||||
int i;
|
||||
const int16x8_t v_zero = vdupq_n_s16(0);
|
||||
const int16x8_t v_one = vdupq_n_s16(1);
|
||||
int16x8_t v_eobmax_76543210 = vdupq_n_s16(-1);
|
||||
int16x8_t v_round = vmovq_n_s16(round_ptr[1]);
|
||||
int16x8_t v_quant = vmovq_n_s16(quant_ptr[1]);
|
||||
int16x8_t v_dequant = vmovq_n_s16(dequant_ptr[1]);
|
||||
// adjust for dc
|
||||
v_round = vsetq_lane_s16(round_ptr[0], v_round, 0);
|
||||
v_quant = vsetq_lane_s16(quant_ptr[0], v_quant, 0);
|
||||
v_dequant = vsetq_lane_s16(dequant_ptr[0], v_dequant, 0);
|
||||
// process dc and the first seven ac coeffs
|
||||
{
|
||||
const int16x8_t v_iscan = vld1q_s16(&iscan[0]);
|
||||
const int16x8_t v_coeff = vld1q_s16(&coeff_ptr[0]);
|
||||
const int16x8_t v_coeff_sign = vshrq_n_s16(v_coeff, 15);
|
||||
const int16x8_t v_tmp = vabaq_s16(v_round, v_coeff, v_zero);
|
||||
const int32x4_t v_tmp_lo =
|
||||
vmull_s16(vget_low_s16(v_tmp), vget_low_s16(v_quant));
|
||||
const int32x4_t v_tmp_hi =
|
||||
vmull_s16(vget_high_s16(v_tmp), vget_high_s16(v_quant));
|
||||
const int16x8_t v_tmp2 =
|
||||
vcombine_s16(vshrn_n_s32(v_tmp_lo, 16), vshrn_n_s32(v_tmp_hi, 16));
|
||||
const uint16x8_t v_nz_mask = vceqq_s16(v_tmp2, v_zero);
|
||||
const int16x8_t v_iscan_plus1 = vaddq_s16(v_iscan, v_one);
|
||||
const int16x8_t v_nz_iscan = vbslq_s16(v_nz_mask, v_zero, v_iscan_plus1);
|
||||
const int16x8_t v_qcoeff_a = veorq_s16(v_tmp2, v_coeff_sign);
|
||||
const int16x8_t v_qcoeff = vsubq_s16(v_qcoeff_a, v_coeff_sign);
|
||||
const int16x8_t v_dqcoeff = vmulq_s16(v_qcoeff, v_dequant);
|
||||
v_eobmax_76543210 = vmaxq_s16(v_eobmax_76543210, v_nz_iscan);
|
||||
vst1q_s16(&qcoeff_ptr[0], v_qcoeff);
|
||||
vst1q_s16(&dqcoeff_ptr[0], v_dqcoeff);
|
||||
v_round = vmovq_n_s16(round_ptr[1]);
|
||||
v_quant = vmovq_n_s16(quant_ptr[1]);
|
||||
v_dequant = vmovq_n_s16(dequant_ptr[1]);
|
||||
}
|
||||
// now process the rest of the ac coeffs
|
||||
for (i = 8; i < count; i += 8) {
|
||||
const int16x8_t v_iscan = vld1q_s16(&iscan[i]);
|
||||
const int16x8_t v_coeff = vld1q_s16(&coeff_ptr[i]);
|
||||
const int16x8_t v_coeff_sign = vshrq_n_s16(v_coeff, 15);
|
||||
const int16x8_t v_tmp = vabaq_s16(v_round, v_coeff, v_zero);
|
||||
const int32x4_t v_tmp_lo =
|
||||
vmull_s16(vget_low_s16(v_tmp), vget_low_s16(v_quant));
|
||||
const int32x4_t v_tmp_hi =
|
||||
vmull_s16(vget_high_s16(v_tmp), vget_high_s16(v_quant));
|
||||
const int16x8_t v_tmp2 =
|
||||
vcombine_s16(vshrn_n_s32(v_tmp_lo, 16), vshrn_n_s32(v_tmp_hi, 16));
|
||||
const uint16x8_t v_nz_mask = vceqq_s16(v_tmp2, v_zero);
|
||||
const int16x8_t v_iscan_plus1 = vaddq_s16(v_iscan, v_one);
|
||||
const int16x8_t v_nz_iscan = vbslq_s16(v_nz_mask, v_zero, v_iscan_plus1);
|
||||
const int16x8_t v_qcoeff_a = veorq_s16(v_tmp2, v_coeff_sign);
|
||||
const int16x8_t v_qcoeff = vsubq_s16(v_qcoeff_a, v_coeff_sign);
|
||||
const int16x8_t v_dqcoeff = vmulq_s16(v_qcoeff, v_dequant);
|
||||
v_eobmax_76543210 = vmaxq_s16(v_eobmax_76543210, v_nz_iscan);
|
||||
vst1q_s16(&qcoeff_ptr[i], v_qcoeff);
|
||||
vst1q_s16(&dqcoeff_ptr[i], v_dqcoeff);
|
||||
}
|
||||
{
|
||||
const int16x4_t v_eobmax_3210 = vmax_s16(
|
||||
vget_low_s16(v_eobmax_76543210), vget_high_s16(v_eobmax_76543210));
|
||||
const int64x1_t v_eobmax_xx32 =
|
||||
vshr_n_s64(vreinterpret_s64_s16(v_eobmax_3210), 32);
|
||||
const int16x4_t v_eobmax_tmp =
|
||||
vmax_s16(v_eobmax_3210, vreinterpret_s16_s64(v_eobmax_xx32));
|
||||
const int64x1_t v_eobmax_xxx3 =
|
||||
vshr_n_s64(vreinterpret_s64_s16(v_eobmax_tmp), 16);
|
||||
const int16x4_t v_eobmax_final =
|
||||
vmax_s16(v_eobmax_tmp, vreinterpret_s16_s64(v_eobmax_xxx3));
|
||||
|
||||
*eob_ptr = (uint16_t)vget_lane_s16(v_eobmax_final, 0);
|
||||
}
|
||||
} else {
|
||||
memset(qcoeff_ptr, 0, count * sizeof(int16_t));
|
||||
memset(dqcoeff_ptr, 0, count * sizeof(int16_t));
|
||||
*eob_ptr = 0;
|
||||
}
|
||||
}
|
||||
1790
third_party/aom/av1/encoder/av1_quantize.c
vendored
Normal file
1790
third_party/aom/av1/encoder/av1_quantize.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
184
third_party/aom/av1/encoder/av1_quantize.h
vendored
Normal file
184
third_party/aom/av1/encoder/av1_quantize.h
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_QUANTIZE_H_
|
||||
#define AV1_ENCODER_QUANTIZE_H_
|
||||
|
||||
#include "./aom_config.h"
|
||||
#include "av1/common/quant_common.h"
|
||||
#include "av1/common/scan.h"
|
||||
#include "av1/encoder/block.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct QUANT_PARAM {
|
||||
int log_scale;
|
||||
#if CONFIG_NEW_QUANT
|
||||
TX_SIZE tx_size;
|
||||
int dq;
|
||||
#endif // CONFIG_NEW_QUANT
|
||||
#if CONFIG_AOM_QM
|
||||
const qm_val_t *qmatrix;
|
||||
const qm_val_t *iqmatrix;
|
||||
#endif // CONFIG_AOM_QM
|
||||
} QUANT_PARAM;
|
||||
|
||||
typedef void (*AV1_QUANT_FACADE)(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
|
||||
typedef struct {
|
||||
#if CONFIG_NEW_QUANT
|
||||
DECLARE_ALIGNED(
|
||||
16, tran_low_t,
|
||||
y_cuml_bins_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS][NUQ_KNOTS]);
|
||||
DECLARE_ALIGNED(
|
||||
16, tran_low_t,
|
||||
uv_cuml_bins_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS][NUQ_KNOTS]);
|
||||
#endif // CONFIG_NEW_QUANT
|
||||
// 0: dc 1: ac 2-8: ac repeated to SIMD width
|
||||
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;
|
||||
|
||||
struct AV1_COMP;
|
||||
struct AV1Common;
|
||||
|
||||
void av1_frame_init_quantizer(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_init_plane_quantizers(const struct AV1_COMP *cpi, MACROBLOCK *x,
|
||||
int segment_id);
|
||||
|
||||
void av1_init_quantizer(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_set_quantizer(struct AV1Common *cm, int q);
|
||||
|
||||
int av1_quantizer_to_qindex(int quantizer);
|
||||
|
||||
int av1_qindex_to_quantizer(int qindex);
|
||||
|
||||
void av1_quantize_skip(intptr_t n_coeffs, tran_low_t *qcoeff_ptr,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr);
|
||||
|
||||
void av1_quantize_fp_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
const MACROBLOCK_PLANE *p, tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc, const QUANT_PARAM *qparam);
|
||||
|
||||
void av1_quantize_b_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
const MACROBLOCK_PLANE *p, tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd, tran_low_t *dqcoeff_ptr,
|
||||
uint16_t *eob_ptr, const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
|
||||
void av1_quantize_dc_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
const MACROBLOCK_PLANE *p, tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc, const QUANT_PARAM *qparam);
|
||||
|
||||
#if CONFIG_NEW_QUANT
|
||||
void av1_quantize_fp_nuq_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
|
||||
void av1_quantize_b_nuq_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc, const QUANT_PARAM *qparam);
|
||||
|
||||
void av1_quantize_dc_nuq_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
|
||||
const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
#endif // CONFIG_NEW_QUANT
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
void av1_highbd_quantize_fp_facade(const tran_low_t *coeff_ptr,
|
||||
intptr_t n_coeffs, const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
|
||||
void av1_highbd_quantize_b_facade(const tran_low_t *coeff_ptr,
|
||||
intptr_t n_coeffs, const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
|
||||
void av1_highbd_quantize_dc_facade(const tran_low_t *coeff_ptr,
|
||||
intptr_t n_coeffs, const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr,
|
||||
const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr,
|
||||
const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
|
||||
#if CONFIG_NEW_QUANT
|
||||
void av1_highbd_quantize_fp_nuq_facade(
|
||||
const tran_low_t *coeff_ptr, intptr_t n_coeffs, const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr, const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr, const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
|
||||
void av1_highbd_quantize_b_nuq_facade(
|
||||
const tran_low_t *coeff_ptr, intptr_t n_coeffs, const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr, const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr, const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
|
||||
void av1_highbd_quantize_dc_nuq_facade(
|
||||
const tran_low_t *coeff_ptr, intptr_t n_coeffs, const MACROBLOCK_PLANE *p,
|
||||
tran_low_t *qcoeff_ptr, const MACROBLOCKD_PLANE *pd,
|
||||
tran_low_t *dqcoeff_ptr, uint16_t *eob_ptr, const SCAN_ORDER *sc,
|
||||
const QUANT_PARAM *qparam);
|
||||
#endif // CONFIG_NEW_QUANT
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_QUANTIZE_H_
|
||||
5399
third_party/aom/av1/encoder/bitstream.c
vendored
Normal file
5399
third_party/aom/av1/encoder/bitstream.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
53
third_party/aom/av1/encoder/bitstream.h
vendored
Normal file
53
third_party/aom/av1/encoder/bitstream.h
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_BITSTREAM_H_
|
||||
#define AV1_ENCODER_BITSTREAM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
#if CONFIG_REFERENCE_BUFFER
|
||||
void write_sequence_header(SequenceHeader *seq_params);
|
||||
#endif
|
||||
|
||||
void av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dest, size_t *size);
|
||||
|
||||
void av1_encode_token_init(void);
|
||||
|
||||
static INLINE int av1_preserve_existing_gf(AV1_COMP *cpi) {
|
||||
#if CONFIG_EXT_REFS
|
||||
// Do not swap gf and arf indices for internal overlay frames
|
||||
return !cpi->multi_arf_allowed && cpi->rc.is_src_frame_alt_ref &&
|
||||
!cpi->rc.is_src_frame_ext_arf;
|
||||
#else
|
||||
return !cpi->multi_arf_allowed && cpi->refresh_golden_frame &&
|
||||
cpi->rc.is_src_frame_alt_ref;
|
||||
#endif // CONFIG_EXT_REFS
|
||||
}
|
||||
|
||||
void av1_write_tx_type(const AV1_COMMON *const cm, const MACROBLOCKD *xd,
|
||||
#if CONFIG_SUPERTX
|
||||
const int supertx_enabled,
|
||||
#endif
|
||||
#if CONFIG_TXK_SEL
|
||||
int block, int plane,
|
||||
#endif
|
||||
aom_writer *w);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_BITSTREAM_H_
|
||||
241
third_party/aom/av1/encoder/block.h
vendored
Normal file
241
third_party/aom/av1/encoder/block.h
vendored
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_BLOCK_H_
|
||||
#define AV1_ENCODER_BLOCK_H_
|
||||
|
||||
#include "av1/common/entropymv.h"
|
||||
#include "av1/common/entropy.h"
|
||||
#if CONFIG_PVQ
|
||||
#include "av1/encoder/encint.h"
|
||||
#endif
|
||||
#if CONFIG_REF_MV
|
||||
#include "av1/common/mvref_common.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_PVQ
|
||||
// Maximum possible # of tx blocks in luma plane, which is currently 256,
|
||||
// since there can be 16x16 of 4x4 tx.
|
||||
#define MAX_PVQ_BLOCKS_IN_SB (MAX_SB_SQUARE >> 2 * OD_LOG_BSIZE0)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned int sse;
|
||||
int sum;
|
||||
unsigned int var;
|
||||
} DIFF;
|
||||
|
||||
typedef struct macroblock_plane {
|
||||
DECLARE_ALIGNED(16, int16_t, src_diff[MAX_SB_SQUARE]);
|
||||
#if CONFIG_PVQ
|
||||
DECLARE_ALIGNED(16, int16_t, src_int16[MAX_SB_SQUARE]);
|
||||
#endif
|
||||
tran_low_t *qcoeff;
|
||||
tran_low_t *coeff;
|
||||
uint16_t *eobs;
|
||||
#if CONFIG_LV_MAP
|
||||
uint8_t *txb_entropy_ctx;
|
||||
#endif
|
||||
struct buf_2d src;
|
||||
|
||||
// Quantizer setings
|
||||
const int16_t *quant_fp;
|
||||
const int16_t *round_fp;
|
||||
const int16_t *quant;
|
||||
const int16_t *quant_shift;
|
||||
const int16_t *zbin;
|
||||
const int16_t *round;
|
||||
#if CONFIG_NEW_QUANT
|
||||
const cuml_bins_type_nuq *cuml_bins_nuq[QUANT_PROFILES];
|
||||
#endif // CONFIG_NEW_QUANT
|
||||
} MACROBLOCK_PLANE;
|
||||
|
||||
/* 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 av1_coeff_cost[PLANE_TYPES][REF_TYPES][COEF_BANDS][2]
|
||||
[COEFF_CONTEXTS][ENTROPY_TOKENS];
|
||||
|
||||
typedef struct {
|
||||
int_mv ref_mvs[MODE_CTX_REF_FRAMES][MAX_MV_REF_CANDIDATES];
|
||||
int16_t mode_context[MODE_CTX_REF_FRAMES];
|
||||
#if CONFIG_LV_MAP
|
||||
// TODO(angiebird): Reduce the buffer size according to sb_type
|
||||
tran_low_t tcoeff[MAX_MB_PLANE][MAX_SB_SQUARE];
|
||||
uint16_t eobs[MAX_MB_PLANE][MAX_SB_SQUARE / (TX_SIZE_W_MIN * TX_SIZE_H_MIN)];
|
||||
uint8_t txb_skip_ctx[MAX_MB_PLANE]
|
||||
[MAX_SB_SQUARE / (TX_SIZE_W_MIN * TX_SIZE_H_MIN)];
|
||||
int dc_sign_ctx[MAX_MB_PLANE]
|
||||
[MAX_SB_SQUARE / (TX_SIZE_W_MIN * TX_SIZE_H_MIN)];
|
||||
#endif
|
||||
#if CONFIG_REF_MV
|
||||
uint8_t ref_mv_count[MODE_CTX_REF_FRAMES];
|
||||
CANDIDATE_MV ref_mv_stack[MODE_CTX_REF_FRAMES][MAX_REF_MV_STACK_SIZE];
|
||||
#if CONFIG_EXT_INTER
|
||||
int16_t compound_mode_context[MODE_CTX_REF_FRAMES];
|
||||
#endif // CONFIG_EXT_INTER
|
||||
#endif
|
||||
} MB_MODE_INFO_EXT;
|
||||
|
||||
typedef struct {
|
||||
int col_min;
|
||||
int col_max;
|
||||
int row_min;
|
||||
int row_max;
|
||||
} MvLimits;
|
||||
|
||||
#if CONFIG_PALETTE
|
||||
typedef struct {
|
||||
uint8_t best_palette_color_map[MAX_SB_SQUARE];
|
||||
float kmeans_data_buf[2 * MAX_SB_SQUARE];
|
||||
} PALETTE_BUFFER;
|
||||
#endif // CONFIG_PALETTE
|
||||
|
||||
typedef struct macroblock MACROBLOCK;
|
||||
struct macroblock {
|
||||
struct macroblock_plane plane[MAX_MB_PLANE];
|
||||
|
||||
MACROBLOCKD e_mbd;
|
||||
MB_MODE_INFO_EXT *mbmi_ext;
|
||||
int skip_block;
|
||||
int qindex;
|
||||
|
||||
// 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 mb_energy;
|
||||
int *m_search_count_ptr;
|
||||
int *ex_search_count_ptr;
|
||||
|
||||
#if CONFIG_VAR_TX
|
||||
unsigned int txb_split_count;
|
||||
#endif
|
||||
|
||||
// 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[TOTAL_REFS_PER_FRAME];
|
||||
unsigned int max_mv_context[TOTAL_REFS_PER_FRAME];
|
||||
unsigned int source_variance;
|
||||
unsigned int pred_sse[TOTAL_REFS_PER_FRAME];
|
||||
int pred_mv_sad[TOTAL_REFS_PER_FRAME];
|
||||
|
||||
#if CONFIG_REF_MV
|
||||
int *nmvjointcost;
|
||||
int nmv_vec_cost[NMV_CONTEXTS][MV_JOINTS];
|
||||
int *nmvcost[NMV_CONTEXTS][2];
|
||||
int *nmvcost_hp[NMV_CONTEXTS][2];
|
||||
int **mv_cost_stack[NMV_CONTEXTS];
|
||||
int *nmvjointsadcost;
|
||||
#else
|
||||
int nmvjointcost[MV_JOINTS];
|
||||
int *nmvcost[2];
|
||||
int *nmvcost_hp[2];
|
||||
int nmvjointsadcost[MV_JOINTS];
|
||||
#endif
|
||||
|
||||
int **mvcost;
|
||||
int *nmvsadcost[2];
|
||||
int *nmvsadcost_hp[2];
|
||||
int **mvsadcost;
|
||||
#if CONFIG_MOTION_VAR
|
||||
int32_t *wsrc_buf;
|
||||
int32_t *mask_buf;
|
||||
#endif // CONFIG_MOTION_VAR
|
||||
|
||||
#if CONFIG_PALETTE
|
||||
PALETTE_BUFFER *palette_buffer;
|
||||
#endif // CONFIG_PALETTE
|
||||
|
||||
// These define limits to motion vector components to prevent them
|
||||
// from extending outside the UMV borders
|
||||
MvLimits mv_limits;
|
||||
|
||||
#if CONFIG_VAR_TX
|
||||
uint8_t blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE * 8];
|
||||
#if CONFIG_REF_MV
|
||||
uint8_t blk_skip_drl[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE * 8];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int skip;
|
||||
|
||||
#if CONFIG_CB4X4
|
||||
int skip_chroma_rd;
|
||||
#endif
|
||||
|
||||
// note that token_costs is the cost when eob node is skipped
|
||||
av1_coeff_cost token_costs[TX_SIZES];
|
||||
|
||||
int optimize;
|
||||
|
||||
// Used to store sub partition's choices.
|
||||
MV pred_mv[TOTAL_REFS_PER_FRAME];
|
||||
|
||||
// Store the best motion vector during motion search
|
||||
int_mv best_mv;
|
||||
// Store the second best motion vector during full-pixel motion search
|
||||
int_mv second_best_mv;
|
||||
|
||||
// use default transform and skip transform type search for intra modes
|
||||
int use_default_intra_tx_type;
|
||||
// use default transform and skip transform type search for inter modes
|
||||
int use_default_inter_tx_type;
|
||||
#if CONFIG_PVQ
|
||||
int rate;
|
||||
// 1 if neither AC nor DC is coded. Only used during RDO.
|
||||
int pvq_skip[MAX_MB_PLANE];
|
||||
PVQ_QUEUE *pvq_q;
|
||||
|
||||
// Storage for PVQ tx block encodings in a superblock.
|
||||
// There can be max 16x16 of 4x4 blocks (and YUV) encode by PVQ
|
||||
// 256 is the max # of 4x4 blocks in a SB (64x64), which comes from:
|
||||
// 1) Since PVQ is applied to each trasnform-ed block
|
||||
// 2) 4x4 is the smallest tx size in AV1
|
||||
// 3) AV1 allows using smaller tx size than block (i.e. partition) size
|
||||
// TODO(yushin) : The memory usage could be improved a lot, since this has
|
||||
// storage for 10 bands and 128 coefficients for every 4x4 block,
|
||||
PVQ_INFO pvq[MAX_PVQ_BLOCKS_IN_SB][MAX_MB_PLANE];
|
||||
daala_enc_ctx daala_enc;
|
||||
int pvq_speed;
|
||||
int pvq_coded; // Indicates whether pvq_info needs be stored to tokenize
|
||||
#endif
|
||||
#if CONFIG_DAALA_DIST
|
||||
// Keep rate of each 4x4 block in the current macroblock during RDO
|
||||
// This is needed when using the 8x8 Daala distortion metric during RDO,
|
||||
// because it evaluates distortion in a different order than the underlying
|
||||
// 4x4 blocks are coded.
|
||||
int rate_4x4[256];
|
||||
#endif
|
||||
#if CONFIG_CFL
|
||||
// Whether luma needs to be stored during RDO.
|
||||
int cfl_store_y;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_BLOCK_H_
|
||||
142
third_party/aom/av1/encoder/blockiness.c
vendored
Normal file
142
third_party/aom/av1/encoder/blockiness.c
vendored
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
#include "./aom_config.h"
|
||||
#include "./aom_dsp_rtcd.h"
|
||||
#include "av1/common/common.h"
|
||||
#include "av1/common/filter.h"
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_dsp/aom_convolve.h"
|
||||
#include "aom_dsp/aom_filter.h"
|
||||
#include "aom_ports/mem.h"
|
||||
#include "aom_ports/system_state.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 av1_get_blockiness(const unsigned char *img1, int img1_pitch,
|
||||
const unsigned char *img2, int img2_pitch, int width,
|
||||
int height) {
|
||||
double blockiness = 0;
|
||||
int i, j;
|
||||
aom_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;
|
||||
}
|
||||
331
third_party/aom/av1/encoder/context_tree.c
vendored
Normal file
331
third_party/aom/av1/encoder/context_tree.c
vendored
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "av1/encoder/context_tree.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
static const BLOCK_SIZE square[MAX_SB_SIZE_LOG2 - 1] = {
|
||||
#if CONFIG_CB4X4
|
||||
BLOCK_4X4,
|
||||
#endif
|
||||
BLOCK_8X8, BLOCK_16X16, BLOCK_32X32, BLOCK_64X64,
|
||||
#if CONFIG_EXT_PARTITION
|
||||
BLOCK_128X128,
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
};
|
||||
|
||||
static void alloc_mode_context(AV1_COMMON *cm, int num_4x4_blk,
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
PARTITION_TYPE partition,
|
||||
#endif
|
||||
PICK_MODE_CONTEXT *ctx) {
|
||||
const int num_blk = (num_4x4_blk < 4 ? 4 : num_4x4_blk);
|
||||
const int num_pix = num_blk * tx_size_2d[0];
|
||||
int i;
|
||||
#if CONFIG_CB4X4 && CONFIG_VAR_TX
|
||||
ctx->num_4x4_blk = num_blk / 4;
|
||||
#else
|
||||
ctx->num_4x4_blk = num_blk;
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
ctx->partition = partition;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
#if CONFIG_VAR_TX
|
||||
CHECK_MEM_ERROR(cm, ctx->blk_skip[i], aom_calloc(num_blk, sizeof(uint8_t)));
|
||||
#endif
|
||||
CHECK_MEM_ERROR(cm, ctx->coeff[i],
|
||||
aom_memalign(32, num_pix * sizeof(*ctx->coeff[i])));
|
||||
CHECK_MEM_ERROR(cm, ctx->qcoeff[i],
|
||||
aom_memalign(32, num_pix * sizeof(*ctx->qcoeff[i])));
|
||||
CHECK_MEM_ERROR(cm, ctx->dqcoeff[i],
|
||||
aom_memalign(32, num_pix * sizeof(*ctx->dqcoeff[i])));
|
||||
CHECK_MEM_ERROR(cm, ctx->eobs[i],
|
||||
aom_memalign(32, num_blk * sizeof(*ctx->eobs[i])));
|
||||
#if CONFIG_LV_MAP
|
||||
CHECK_MEM_ERROR(
|
||||
cm, ctx->txb_entropy_ctx[i],
|
||||
aom_memalign(32, num_blk * sizeof(*ctx->txb_entropy_ctx[i])));
|
||||
#endif
|
||||
|
||||
#if CONFIG_PVQ
|
||||
CHECK_MEM_ERROR(cm, ctx->pvq_ref_coeff[i],
|
||||
aom_memalign(32, num_pix * sizeof(*ctx->pvq_ref_coeff[i])));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_PALETTE
|
||||
if (cm->allow_screen_content_tools) {
|
||||
for (i = 0; i < 2; ++i) {
|
||||
CHECK_MEM_ERROR(
|
||||
cm, ctx->color_index_map[i],
|
||||
aom_memalign(32, num_pix * sizeof(*ctx->color_index_map[i])));
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_PALETTE
|
||||
}
|
||||
|
||||
static void free_mode_context(PICK_MODE_CONTEXT *ctx) {
|
||||
int i;
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
#if CONFIG_VAR_TX
|
||||
aom_free(ctx->blk_skip[i]);
|
||||
ctx->blk_skip[i] = 0;
|
||||
#endif
|
||||
aom_free(ctx->coeff[i]);
|
||||
ctx->coeff[i] = 0;
|
||||
aom_free(ctx->qcoeff[i]);
|
||||
ctx->qcoeff[i] = 0;
|
||||
aom_free(ctx->dqcoeff[i]);
|
||||
ctx->dqcoeff[i] = 0;
|
||||
#if CONFIG_PVQ
|
||||
aom_free(ctx->pvq_ref_coeff[i]);
|
||||
ctx->pvq_ref_coeff[i] = 0;
|
||||
#endif
|
||||
aom_free(ctx->eobs[i]);
|
||||
ctx->eobs[i] = 0;
|
||||
#if CONFIG_LV_MAP
|
||||
aom_free(ctx->txb_entropy_ctx[i]);
|
||||
ctx->txb_entropy_ctx[i] = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_PALETTE
|
||||
for (i = 0; i < 2; ++i) {
|
||||
aom_free(ctx->color_index_map[i]);
|
||||
ctx->color_index_map[i] = 0;
|
||||
}
|
||||
#endif // CONFIG_PALETTE
|
||||
}
|
||||
|
||||
static void alloc_tree_contexts(AV1_COMMON *cm, PC_TREE *tree,
|
||||
int num_4x4_blk) {
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
alloc_mode_context(cm, num_4x4_blk, PARTITION_NONE, &tree->none);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, PARTITION_HORZ, &tree->horizontal[0]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, PARTITION_VERT, &tree->vertical[0]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, PARTITION_VERT, &tree->horizontal[1]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, PARTITION_VERT, &tree->vertical[1]);
|
||||
|
||||
alloc_mode_context(cm, num_4x4_blk / 4, PARTITION_HORZ_A,
|
||||
&tree->horizontala[0]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 4, PARTITION_HORZ_A,
|
||||
&tree->horizontala[1]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, PARTITION_HORZ_A,
|
||||
&tree->horizontala[2]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, PARTITION_HORZ_B,
|
||||
&tree->horizontalb[0]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 4, PARTITION_HORZ_B,
|
||||
&tree->horizontalb[1]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 4, PARTITION_HORZ_B,
|
||||
&tree->horizontalb[2]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 4, PARTITION_VERT_A,
|
||||
&tree->verticala[0]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 4, PARTITION_VERT_A,
|
||||
&tree->verticala[1]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, PARTITION_VERT_A,
|
||||
&tree->verticala[2]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 2, PARTITION_VERT_B,
|
||||
&tree->verticalb[0]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 4, PARTITION_VERT_B,
|
||||
&tree->verticalb[1]);
|
||||
alloc_mode_context(cm, num_4x4_blk / 4, PARTITION_VERT_B,
|
||||
&tree->verticalb[2]);
|
||||
#ifdef CONFIG_SUPERTX
|
||||
alloc_mode_context(cm, num_4x4_blk, PARTITION_HORZ,
|
||||
&tree->horizontal_supertx);
|
||||
alloc_mode_context(cm, num_4x4_blk, PARTITION_VERT, &tree->vertical_supertx);
|
||||
alloc_mode_context(cm, num_4x4_blk, PARTITION_SPLIT, &tree->split_supertx);
|
||||
alloc_mode_context(cm, num_4x4_blk, PARTITION_HORZ_A,
|
||||
&tree->horizontala_supertx);
|
||||
alloc_mode_context(cm, num_4x4_blk, PARTITION_HORZ_B,
|
||||
&tree->horizontalb_supertx);
|
||||
alloc_mode_context(cm, num_4x4_blk, PARTITION_VERT_A,
|
||||
&tree->verticala_supertx);
|
||||
alloc_mode_context(cm, num_4x4_blk, PARTITION_VERT_B,
|
||||
&tree->verticalb_supertx);
|
||||
#endif // CONFIG_SUPERTX
|
||||
#else
|
||||
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]);
|
||||
#ifdef CONFIG_SUPERTX
|
||||
alloc_mode_context(cm, num_4x4_blk, &tree->horizontal_supertx);
|
||||
alloc_mode_context(cm, num_4x4_blk, &tree->vertical_supertx);
|
||||
alloc_mode_context(cm, num_4x4_blk, &tree->split_supertx);
|
||||
#endif
|
||||
|
||||
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]));
|
||||
}
|
||||
#endif // CONFIG_EXT_PARTITION_TYPES
|
||||
}
|
||||
|
||||
static void free_tree_contexts(PC_TREE *tree) {
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
free_mode_context(&tree->horizontala[i]);
|
||||
free_mode_context(&tree->horizontalb[i]);
|
||||
free_mode_context(&tree->verticala[i]);
|
||||
free_mode_context(&tree->verticalb[i]);
|
||||
}
|
||||
#endif // CONFIG_EXT_PARTITION_TYPES
|
||||
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]);
|
||||
#ifdef CONFIG_SUPERTX
|
||||
free_mode_context(&tree->horizontal_supertx);
|
||||
free_mode_context(&tree->vertical_supertx);
|
||||
free_mode_context(&tree->split_supertx);
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
free_mode_context(&tree->horizontala_supertx);
|
||||
free_mode_context(&tree->horizontalb_supertx);
|
||||
free_mode_context(&tree->verticala_supertx);
|
||||
free_mode_context(&tree->verticalb_supertx);
|
||||
#endif // CONFIG_EXT_PARTITION_TYPES
|
||||
#endif // CONFIG_SUPERTX
|
||||
}
|
||||
|
||||
// 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 av1_setup_pc_tree(AV1_COMMON *cm, ThreadData *td) {
|
||||
int i, j;
|
||||
// TODO(jingning): The pc_tree allocation is redundant. We can take out all
|
||||
// the leaf nodes after cb4x4 mode is enabled.
|
||||
#if CONFIG_CB4X4
|
||||
#if CONFIG_EXT_PARTITION
|
||||
const int tree_nodes_inc = 1024;
|
||||
#else
|
||||
const int tree_nodes_inc = 256;
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
const int leaf_factor = 4;
|
||||
#else
|
||||
const int tree_nodes_inc = 0;
|
||||
const int leaf_factor = 1;
|
||||
#endif
|
||||
#if CONFIG_EXT_PARTITION
|
||||
const int leaf_nodes = 256 * leaf_factor;
|
||||
const int tree_nodes = tree_nodes_inc + 256 + 64 + 16 + 4 + 1;
|
||||
#else
|
||||
const int leaf_nodes = 64 * leaf_factor;
|
||||
const int tree_nodes = tree_nodes_inc + 64 + 16 + 4 + 1;
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
int pc_tree_index = 0;
|
||||
PC_TREE *this_pc;
|
||||
PICK_MODE_CONTEXT *this_leaf;
|
||||
int square_index = 1;
|
||||
int nodes;
|
||||
|
||||
aom_free(td->leaf_tree);
|
||||
CHECK_MEM_ERROR(cm, td->leaf_tree,
|
||||
aom_calloc(leaf_nodes, sizeof(*td->leaf_tree)));
|
||||
aom_free(td->pc_tree);
|
||||
CHECK_MEM_ERROR(cm, td->pc_tree,
|
||||
aom_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) {
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
alloc_mode_context(cm, 4, PARTITION_NONE, &td->leaf_tree[i]);
|
||||
#else
|
||||
alloc_mode_context(cm, 16, &td->leaf_tree[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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];
|
||||
#if CONFIG_CB4X4
|
||||
alloc_tree_contexts(cm, tree, 16);
|
||||
#else
|
||||
alloc_tree_contexts(cm, tree, 4);
|
||||
#endif
|
||||
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 = leaf_nodes >> 2; nodes > 0; nodes >>= 2) {
|
||||
for (i = 0; i < nodes; ++i) {
|
||||
PC_TREE *const tree = &td->pc_tree[pc_tree_index];
|
||||
#if CONFIG_CB4X4
|
||||
alloc_tree_contexts(cm, tree, 16 << (2 * square_index));
|
||||
#else
|
||||
alloc_tree_contexts(cm, tree, 4 << (2 * square_index));
|
||||
#endif
|
||||
tree->block_size = square[square_index];
|
||||
for (j = 0; j < 4; j++) tree->split[j] = this_pc++;
|
||||
++pc_tree_index;
|
||||
}
|
||||
++square_index;
|
||||
}
|
||||
|
||||
// Set up the root node for the largest superblock size
|
||||
i = MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2;
|
||||
td->pc_root[i] = &td->pc_tree[tree_nodes - 1];
|
||||
td->pc_root[i]->none.best_mode_index = 2;
|
||||
// Set up the root nodes for the rest of the possible superblock sizes
|
||||
while (--i >= 0) {
|
||||
td->pc_root[i] = td->pc_root[i + 1]->split[0];
|
||||
td->pc_root[i]->none.best_mode_index = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void av1_free_pc_tree(ThreadData *td) {
|
||||
#if CONFIG_CB4X4
|
||||
#if CONFIG_EXT_PARTITION
|
||||
const int tree_nodes_inc = 1024;
|
||||
#else
|
||||
const int tree_nodes_inc = 256;
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
const int leaf_factor = 4;
|
||||
#else
|
||||
const int tree_nodes_inc = 0;
|
||||
const int leaf_factor = 1;
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXT_PARTITION
|
||||
const int leaf_nodes = 256 * leaf_factor;
|
||||
const int tree_nodes = tree_nodes_inc + 256 + 64 + 16 + 4 + 1;
|
||||
#else
|
||||
const int leaf_nodes = 64 * leaf_factor;
|
||||
const int tree_nodes = tree_nodes_inc + 64 + 16 + 4 + 1;
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
int i;
|
||||
|
||||
// Set up all 4x4 mode contexts
|
||||
for (i = 0; i < leaf_nodes; ++i) free_mode_context(&td->leaf_tree[i]);
|
||||
|
||||
// Sets up all the leaf nodes in the tree.
|
||||
for (i = 0; i < tree_nodes; ++i) free_tree_contexts(&td->pc_tree[i]);
|
||||
|
||||
aom_free(td->pc_tree);
|
||||
td->pc_tree = NULL;
|
||||
aom_free(td->leaf_tree);
|
||||
td->leaf_tree = NULL;
|
||||
}
|
||||
111
third_party/aom/av1/encoder/context_tree.h
vendored
Normal file
111
third_party/aom/av1/encoder/context_tree.h
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_CONTEXT_TREE_H_
|
||||
#define AV1_ENCODER_CONTEXT_TREE_H_
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/encoder/block.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct AV1_COMP;
|
||||
struct AV1Common;
|
||||
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;
|
||||
#if CONFIG_PALETTE
|
||||
uint8_t *color_index_map[2];
|
||||
#endif // CONFIG_PALETTE
|
||||
#if CONFIG_VAR_TX
|
||||
uint8_t *blk_skip[MAX_MB_PLANE];
|
||||
#endif
|
||||
|
||||
// dual buffer pointers, 0: in use, 1: best in store
|
||||
tran_low_t *coeff[MAX_MB_PLANE];
|
||||
tran_low_t *qcoeff[MAX_MB_PLANE];
|
||||
tran_low_t *dqcoeff[MAX_MB_PLANE];
|
||||
#if CONFIG_PVQ
|
||||
tran_low_t *pvq_ref_coeff[MAX_MB_PLANE];
|
||||
#endif
|
||||
uint16_t *eobs[MAX_MB_PLANE];
|
||||
#if CONFIG_LV_MAP
|
||||
uint8_t *txb_entropy_ctx[MAX_MB_PLANE];
|
||||
#endif
|
||||
|
||||
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;
|
||||
int best_mode_index;
|
||||
int hybrid_pred_diff;
|
||||
int comp_pred_diff;
|
||||
int single_pred_diff;
|
||||
|
||||
// TODO(jingning) Use RD_COST struct here instead. This involves a boarder
|
||||
// scope of refactoring.
|
||||
int rate;
|
||||
int64_t dist;
|
||||
|
||||
// motion vector cache for adaptive motion search control in partition
|
||||
// search loop
|
||||
MV pred_mv[TOTAL_REFS_PER_FRAME];
|
||||
InterpFilter pred_interp_filter;
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
PARTITION_TYPE partition;
|
||||
#endif
|
||||
} 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];
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
PICK_MODE_CONTEXT horizontala[3];
|
||||
PICK_MODE_CONTEXT horizontalb[3];
|
||||
PICK_MODE_CONTEXT verticala[3];
|
||||
PICK_MODE_CONTEXT verticalb[3];
|
||||
#endif
|
||||
union {
|
||||
struct PC_TREE *split[4];
|
||||
PICK_MODE_CONTEXT *leaf_split[4];
|
||||
};
|
||||
#ifdef CONFIG_SUPERTX
|
||||
PICK_MODE_CONTEXT horizontal_supertx;
|
||||
PICK_MODE_CONTEXT vertical_supertx;
|
||||
PICK_MODE_CONTEXT split_supertx;
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
PICK_MODE_CONTEXT horizontala_supertx;
|
||||
PICK_MODE_CONTEXT horizontalb_supertx;
|
||||
PICK_MODE_CONTEXT verticala_supertx;
|
||||
PICK_MODE_CONTEXT verticalb_supertx;
|
||||
#endif
|
||||
#endif
|
||||
} PC_TREE;
|
||||
|
||||
void av1_setup_pc_tree(struct AV1Common *cm, struct ThreadData *td);
|
||||
void av1_free_pc_tree(struct ThreadData *td);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* AV1_ENCODER_CONTEXT_TREE_H_ */
|
||||
37
third_party/aom/av1/encoder/corner_detect.c
vendored
Normal file
37
third_party/aom/av1/encoder/corner_detect.c
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "third_party/fastfeat/fast.h"
|
||||
|
||||
#include "av1/encoder/corner_detect.h"
|
||||
|
||||
// Fast_9 wrapper
|
||||
#define FAST_BARRIER 18
|
||||
int fast_corner_detect(unsigned char *buf, int width, int height, int stride,
|
||||
int *points, int max_points) {
|
||||
int num_points;
|
||||
xy *const frm_corners_xy = fast9_detect_nonmax(buf, width, height, stride,
|
||||
FAST_BARRIER, &num_points);
|
||||
num_points = (num_points <= max_points ? num_points : max_points);
|
||||
if (num_points > 0 && frm_corners_xy) {
|
||||
memcpy(points, frm_corners_xy, sizeof(*frm_corners_xy) * num_points);
|
||||
free(frm_corners_xy);
|
||||
return num_points;
|
||||
}
|
||||
free(frm_corners_xy);
|
||||
return 0;
|
||||
}
|
||||
22
third_party/aom/av1/encoder/corner_detect.h
vendored
Normal file
22
third_party/aom/av1/encoder/corner_detect.h
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_CORNER_DETECT_H_
|
||||
#define AV1_ENCODER_CORNER_DETECT_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
|
||||
int fast_corner_detect(unsigned char *buf, int width, int height, int stride,
|
||||
int *points, int max_points);
|
||||
|
||||
#endif // AV1_ENCODER_CORNER_DETECT_H_
|
||||
193
third_party/aom/av1/encoder/corner_match.c
vendored
Normal file
193
third_party/aom/av1/encoder/corner_match.c
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "av1/encoder/corner_match.h"
|
||||
|
||||
#define MATCH_SZ 13
|
||||
#define MATCH_SZ_BY2 ((MATCH_SZ - 1) / 2)
|
||||
#define MATCH_SZ_SQ (MATCH_SZ * MATCH_SZ)
|
||||
#define SEARCH_SZ 9
|
||||
#define SEARCH_SZ_BY2 ((SEARCH_SZ - 1) / 2)
|
||||
|
||||
#define THRESHOLD_NCC 0.75
|
||||
|
||||
/* Compute var(im) * MATCH_SZ_SQ over a MATCH_SZ by MATCH_SZ window of im,
|
||||
centered at (x, y).
|
||||
*/
|
||||
static double compute_variance(unsigned char *im, int stride, int x, int y) {
|
||||
int sum = 0.0;
|
||||
int sumsq = 0.0;
|
||||
int var;
|
||||
int i, j;
|
||||
for (i = 0; i < MATCH_SZ; ++i)
|
||||
for (j = 0; j < MATCH_SZ; ++j) {
|
||||
sum += im[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)];
|
||||
sumsq += im[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)] *
|
||||
im[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)];
|
||||
}
|
||||
var = sumsq * MATCH_SZ_SQ - sum * sum;
|
||||
return (double)var;
|
||||
}
|
||||
|
||||
/* Compute corr(im1, im2) * MATCH_SZ * stddev(im1), where the
|
||||
correlation/standard deviation are taken over MATCH_SZ by MATCH_SZ windows
|
||||
of each image, centered at (x1, y1) and (x2, y2) respectively.
|
||||
*/
|
||||
static double compute_cross_correlation(unsigned char *im1, int stride1, int x1,
|
||||
int y1, unsigned char *im2, int stride2,
|
||||
int x2, int y2) {
|
||||
int v1, v2;
|
||||
int sum1 = 0;
|
||||
int sum2 = 0;
|
||||
int sumsq2 = 0;
|
||||
int cross = 0;
|
||||
int var2, cov;
|
||||
int i, j;
|
||||
for (i = 0; i < MATCH_SZ; ++i)
|
||||
for (j = 0; j < MATCH_SZ; ++j) {
|
||||
v1 = im1[(i + y1 - MATCH_SZ_BY2) * stride1 + (j + x1 - MATCH_SZ_BY2)];
|
||||
v2 = im2[(i + y2 - MATCH_SZ_BY2) * stride2 + (j + x2 - MATCH_SZ_BY2)];
|
||||
sum1 += v1;
|
||||
sum2 += v2;
|
||||
sumsq2 += v2 * v2;
|
||||
cross += v1 * v2;
|
||||
}
|
||||
var2 = sumsq2 * MATCH_SZ_SQ - sum2 * sum2;
|
||||
cov = cross * MATCH_SZ_SQ - sum1 * sum2;
|
||||
return cov / sqrt((double)var2);
|
||||
}
|
||||
|
||||
static int is_eligible_point(int pointx, int pointy, int width, int height) {
|
||||
return (pointx >= MATCH_SZ_BY2 && pointy >= MATCH_SZ_BY2 &&
|
||||
pointx + MATCH_SZ_BY2 < width && pointy + MATCH_SZ_BY2 < height);
|
||||
}
|
||||
|
||||
static int is_eligible_distance(int point1x, int point1y, int point2x,
|
||||
int point2y, int width, int height) {
|
||||
const int thresh = (width < height ? height : width) >> 4;
|
||||
return ((point1x - point2x) * (point1x - point2x) +
|
||||
(point1y - point2y) * (point1y - point2y)) <= thresh * thresh;
|
||||
}
|
||||
|
||||
static void improve_correspondence(unsigned char *frm, unsigned char *ref,
|
||||
int width, int height, int frm_stride,
|
||||
int ref_stride,
|
||||
Correspondence *correspondences,
|
||||
int num_correspondences) {
|
||||
int i;
|
||||
for (i = 0; i < num_correspondences; ++i) {
|
||||
int x, y, best_x = 0, best_y = 0;
|
||||
double best_match_ncc = 0.0;
|
||||
for (y = -SEARCH_SZ_BY2; y <= SEARCH_SZ_BY2; ++y) {
|
||||
for (x = -SEARCH_SZ_BY2; x <= SEARCH_SZ_BY2; ++x) {
|
||||
double match_ncc;
|
||||
if (!is_eligible_point(correspondences[i].rx + x,
|
||||
correspondences[i].ry + y, width, height))
|
||||
continue;
|
||||
if (!is_eligible_distance(correspondences[i].x, correspondences[i].y,
|
||||
correspondences[i].rx + x,
|
||||
correspondences[i].ry + y, width, height))
|
||||
continue;
|
||||
match_ncc = compute_cross_correlation(
|
||||
frm, frm_stride, correspondences[i].x, correspondences[i].y, ref,
|
||||
ref_stride, correspondences[i].rx + x, correspondences[i].ry + y);
|
||||
if (match_ncc > best_match_ncc) {
|
||||
best_match_ncc = match_ncc;
|
||||
best_y = y;
|
||||
best_x = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
correspondences[i].rx += best_x;
|
||||
correspondences[i].ry += best_y;
|
||||
}
|
||||
for (i = 0; i < num_correspondences; ++i) {
|
||||
int x, y, best_x = 0, best_y = 0;
|
||||
double best_match_ncc = 0.0;
|
||||
for (y = -SEARCH_SZ_BY2; y <= SEARCH_SZ_BY2; ++y)
|
||||
for (x = -SEARCH_SZ_BY2; x <= SEARCH_SZ_BY2; ++x) {
|
||||
double match_ncc;
|
||||
if (!is_eligible_point(correspondences[i].x + x,
|
||||
correspondences[i].y + y, width, height))
|
||||
continue;
|
||||
if (!is_eligible_distance(
|
||||
correspondences[i].x + x, correspondences[i].y + y,
|
||||
correspondences[i].rx, correspondences[i].ry, width, height))
|
||||
continue;
|
||||
match_ncc = compute_cross_correlation(
|
||||
ref, ref_stride, correspondences[i].rx, correspondences[i].ry, frm,
|
||||
frm_stride, correspondences[i].x + x, correspondences[i].y + y);
|
||||
if (match_ncc > best_match_ncc) {
|
||||
best_match_ncc = match_ncc;
|
||||
best_y = y;
|
||||
best_x = x;
|
||||
}
|
||||
}
|
||||
correspondences[i].x += best_x;
|
||||
correspondences[i].y += best_y;
|
||||
}
|
||||
}
|
||||
|
||||
int determine_correspondence(unsigned char *frm, int *frm_corners,
|
||||
int num_frm_corners, unsigned char *ref,
|
||||
int *ref_corners, int num_ref_corners, int width,
|
||||
int height, int frm_stride, int ref_stride,
|
||||
int *correspondence_pts) {
|
||||
// TODO(sarahparker) Improve this to include 2-way match
|
||||
int i, j;
|
||||
Correspondence *correspondences = (Correspondence *)correspondence_pts;
|
||||
int num_correspondences = 0;
|
||||
for (i = 0; i < num_frm_corners; ++i) {
|
||||
double best_match_ncc = 0.0;
|
||||
double template_norm;
|
||||
int best_match_j = -1;
|
||||
if (!is_eligible_point(frm_corners[2 * i], frm_corners[2 * i + 1], width,
|
||||
height))
|
||||
continue;
|
||||
for (j = 0; j < num_ref_corners; ++j) {
|
||||
double match_ncc;
|
||||
if (!is_eligible_point(ref_corners[2 * j], ref_corners[2 * j + 1], width,
|
||||
height))
|
||||
continue;
|
||||
if (!is_eligible_distance(frm_corners[2 * i], frm_corners[2 * i + 1],
|
||||
ref_corners[2 * j], ref_corners[2 * j + 1],
|
||||
width, height))
|
||||
continue;
|
||||
match_ncc = compute_cross_correlation(
|
||||
frm, frm_stride, frm_corners[2 * i], frm_corners[2 * i + 1], ref,
|
||||
ref_stride, ref_corners[2 * j], ref_corners[2 * j + 1]);
|
||||
if (match_ncc > best_match_ncc) {
|
||||
best_match_ncc = match_ncc;
|
||||
best_match_j = j;
|
||||
}
|
||||
}
|
||||
// Note: We want to test if the best correlation is >= THRESHOLD_NCC,
|
||||
// but need to account for the normalization in compute_cross_correlation.
|
||||
template_norm = compute_variance(frm, frm_stride, frm_corners[2 * i],
|
||||
frm_corners[2 * i + 1]);
|
||||
if (best_match_ncc > THRESHOLD_NCC * sqrt(template_norm)) {
|
||||
correspondences[num_correspondences].x = frm_corners[2 * i];
|
||||
correspondences[num_correspondences].y = frm_corners[2 * i + 1];
|
||||
correspondences[num_correspondences].rx = ref_corners[2 * best_match_j];
|
||||
correspondences[num_correspondences].ry =
|
||||
ref_corners[2 * best_match_j + 1];
|
||||
num_correspondences++;
|
||||
}
|
||||
}
|
||||
improve_correspondence(frm, ref, width, height, frm_stride, ref_stride,
|
||||
correspondences, num_correspondences);
|
||||
return num_correspondences;
|
||||
}
|
||||
29
third_party/aom/av1/encoder/corner_match.h
vendored
Normal file
29
third_party/aom/av1/encoder/corner_match.h
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#ifndef AV1_ENCODER_CORNER_MATCH_H_
|
||||
#define AV1_ENCODER_CORNER_MATCH_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
|
||||
typedef struct {
|
||||
int x, y;
|
||||
int rx, ry;
|
||||
} Correspondence;
|
||||
|
||||
int determine_correspondence(unsigned char *frm, int *frm_corners,
|
||||
int num_frm_corners, unsigned char *ref,
|
||||
int *ref_corners, int num_ref_corners, int width,
|
||||
int height, int frm_stride, int ref_stride,
|
||||
int *correspondence_pts);
|
||||
|
||||
#endif // AV1_ENCODER_CORNER_MATCH_H_
|
||||
67
third_party/aom/av1/encoder/cost.c
vendored
Normal file
67
third_party/aom/av1/encoder/cost.c
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#include <assert.h>
|
||||
|
||||
#include "av1/encoder/cost.h"
|
||||
#include "av1/common/entropy.h"
|
||||
|
||||
/* round(-log2(i/256.) * (1 << AV1_PROB_COST_SHIFT))
|
||||
Begins with a bogus entry for simpler addressing. */
|
||||
const uint16_t av1_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, aom_tree tree, const aom_prob *probs, int i,
|
||||
int c) {
|
||||
const aom_prob prob = probs[i / 2];
|
||||
int b;
|
||||
|
||||
assert(prob != 0);
|
||||
for (b = 0; b <= 1; ++b) {
|
||||
const int cc = c + av1_cost_bit(prob, b);
|
||||
const aom_tree_index ii = tree[i + b];
|
||||
|
||||
if (ii <= 0)
|
||||
costs[-ii] = cc;
|
||||
else
|
||||
cost(costs, tree, probs, ii, cc);
|
||||
}
|
||||
}
|
||||
|
||||
void av1_cost_tokens(int *costs, const aom_prob *probs, aom_tree tree) {
|
||||
cost(costs, tree, probs, 0, 0);
|
||||
}
|
||||
|
||||
void av1_cost_tokens_skip(int *costs, const aom_prob *probs, aom_tree tree) {
|
||||
assert(tree[0] <= 0 && tree[1] > 0);
|
||||
|
||||
costs[-tree[0]] = av1_cost_bit(probs[0], 0);
|
||||
cost(costs, tree, probs, 2, 0);
|
||||
}
|
||||
63
third_party/aom/av1/encoder/cost.h
vendored
Normal file
63
third_party/aom/av1/encoder/cost.h
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_COST_H_
|
||||
#define AV1_ENCODER_COST_H_
|
||||
|
||||
#include "aom_dsp/prob.h"
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const uint16_t av1_prob_cost[256];
|
||||
|
||||
// The factor to scale from cost in bits to cost in av1_prob_cost units.
|
||||
#define AV1_PROB_COST_SHIFT 9
|
||||
|
||||
#define av1_cost_zero(prob) (av1_prob_cost[prob])
|
||||
|
||||
#define av1_cost_one(prob) av1_cost_zero(256 - (prob))
|
||||
|
||||
#define av1_cost_bit(prob, bit) av1_cost_zero((bit) ? 256 - (prob) : (prob))
|
||||
|
||||
// Cost of coding an n bit literal, using 128 (i.e. 50%) probability
|
||||
// for each bit.
|
||||
#define av1_cost_literal(n) ((n) * (1 << AV1_PROB_COST_SHIFT))
|
||||
|
||||
static INLINE unsigned int cost_branch256(const unsigned int ct[2],
|
||||
aom_prob p) {
|
||||
return ct[0] * av1_cost_zero(p) + ct[1] * av1_cost_one(p);
|
||||
}
|
||||
|
||||
static INLINE int treed_cost(aom_tree tree, const aom_prob *probs, int bits,
|
||||
int len) {
|
||||
int cost = 0;
|
||||
aom_tree_index i = 0;
|
||||
|
||||
do {
|
||||
const int bit = (bits >> --len) & 1;
|
||||
cost += av1_cost_bit(probs[i >> 1], bit);
|
||||
i = tree[i + bit];
|
||||
} while (len);
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
void av1_cost_tokens(int *costs, const aom_prob *probs, aom_tree tree);
|
||||
void av1_cost_tokens_skip(int *costs, const aom_prob *probs, aom_tree tree);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_COST_H_
|
||||
30
third_party/aom/av1/encoder/daala_compat_enc.c
vendored
Normal file
30
third_party/aom/av1/encoder/daala_compat_enc.c
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "encint.h"
|
||||
|
||||
void od_encode_checkpoint(const daala_enc_ctx *enc, od_rollback_buffer *rbuf) {
|
||||
#if CONFIG_DAALA_EC
|
||||
od_ec_enc_checkpoint(&rbuf->ec, &enc->w.ec);
|
||||
#else
|
||||
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
OD_COPY(&rbuf->adapt, enc->state.adapt, 1);
|
||||
}
|
||||
|
||||
void od_encode_rollback(daala_enc_ctx *enc, const od_rollback_buffer *rbuf) {
|
||||
#if CONFIG_DAALA_EC
|
||||
od_ec_enc_rollback(&enc->w.ec, &rbuf->ec);
|
||||
#else
|
||||
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
OD_COPY(enc->state.adapt, &rbuf->adapt, 1);
|
||||
}
|
||||
2228
third_party/aom/av1/encoder/dct.c
vendored
Normal file
2228
third_party/aom/av1/encoder/dct.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
51
third_party/aom/av1/encoder/encint.h
vendored
Normal file
51
third_party/aom/av1/encoder/encint.h
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
/* clang-format off */
|
||||
|
||||
#if !defined(_encint_H)
|
||||
# define _encint_H (1)
|
||||
|
||||
typedef struct daala_enc_ctx od_enc_ctx;
|
||||
typedef struct od_params_ctx od_params_ctx;
|
||||
typedef struct od_rollback_buffer od_rollback_buffer;
|
||||
|
||||
# include "aom_dsp/entenc.h"
|
||||
# include "av1/common/odintrin.h"
|
||||
# include "av1/common/pvq_state.h"
|
||||
|
||||
struct daala_enc_ctx{
|
||||
/* Stores context-adaptive CDFs for PVQ. */
|
||||
od_state state;
|
||||
/* AOM entropy encoder. */
|
||||
aom_writer w;
|
||||
int use_activity_masking;
|
||||
/* Mode of quantization matrice : FLAT (0) or HVS (1) */
|
||||
int qm;
|
||||
/*Normalized PVQ lambda for use where we've already performed
|
||||
quantization.*/
|
||||
double pvq_norm_lambda;
|
||||
double pvq_norm_lambda_dc;
|
||||
};
|
||||
|
||||
// from daalaenc.h
|
||||
/**The encoder context.*/
|
||||
typedef struct daala_enc_ctx daala_enc_ctx;
|
||||
|
||||
/** Holds important encoder information so we can roll back decisions */
|
||||
struct od_rollback_buffer {
|
||||
od_ec_enc ec;
|
||||
od_adapt_ctx adapt;
|
||||
};
|
||||
|
||||
void od_encode_checkpoint(const daala_enc_ctx *enc, od_rollback_buffer *rbuf);
|
||||
void od_encode_rollback(daala_enc_ctx *enc, const od_rollback_buffer *rbuf);
|
||||
|
||||
#endif
|
||||
7160
third_party/aom/av1/encoder/encodeframe.c
vendored
Normal file
7160
third_party/aom/av1/encoder/encodeframe.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
58
third_party/aom/av1/encoder/encodeframe.h
vendored
Normal file
58
third_party/aom/av1/encoder/encodeframe.h
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_ENCODEFRAME_H_
|
||||
#define AV1_ENCODER_ENCODEFRAME_H_
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct macroblock;
|
||||
struct yv12_buffer_config;
|
||||
struct AV1_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 av1_setup_src_planes(struct macroblock *x,
|
||||
const struct yv12_buffer_config *src, int mi_row,
|
||||
int mi_col);
|
||||
|
||||
void av1_encode_frame(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_init_tile_data(struct AV1_COMP *cpi);
|
||||
void av1_encode_tile(struct AV1_COMP *cpi, struct ThreadData *td, int tile_row,
|
||||
int tile_col);
|
||||
|
||||
void av1_set_variance_partition_thresholds(struct AV1_COMP *cpi, int q);
|
||||
|
||||
void av1_update_tx_type_count(const struct AV1Common *cm, MACROBLOCKD *xd,
|
||||
#if CONFIG_TXK_SEL
|
||||
int block, int plane,
|
||||
#endif
|
||||
BLOCK_SIZE bsize, TX_SIZE tx_size,
|
||||
FRAME_COUNTS *counts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_ENCODEFRAME_H_
|
||||
1671
third_party/aom/av1/encoder/encodemb.c
vendored
Normal file
1671
third_party/aom/av1/encoder/encodemb.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
92
third_party/aom/av1/encoder/encodemb.h
vendored
Normal file
92
third_party/aom/av1/encoder/encodemb.h
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_ENCODEMB_H_
|
||||
#define AV1_ENCODER_ENCODEMB_H_
|
||||
|
||||
#include "./aom_config.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/encoder/block.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct optimize_ctx {
|
||||
ENTROPY_CONTEXT ta[MAX_MB_PLANE][2 * MAX_MIB_SIZE];
|
||||
ENTROPY_CONTEXT tl[MAX_MB_PLANE][2 * MAX_MIB_SIZE];
|
||||
};
|
||||
|
||||
struct encode_b_args {
|
||||
AV1_COMMON *cm;
|
||||
MACROBLOCK *x;
|
||||
struct optimize_ctx *ctx;
|
||||
int8_t *skip;
|
||||
ENTROPY_CONTEXT *ta;
|
||||
ENTROPY_CONTEXT *tl;
|
||||
int8_t enable_optimize_b;
|
||||
};
|
||||
|
||||
typedef enum AV1_XFORM_QUANT {
|
||||
AV1_XFORM_QUANT_FP = 0,
|
||||
AV1_XFORM_QUANT_B = 1,
|
||||
AV1_XFORM_QUANT_DC = 2,
|
||||
AV1_XFORM_QUANT_SKIP_QUANT,
|
||||
AV1_XFORM_QUANT_TYPES,
|
||||
} AV1_XFORM_QUANT;
|
||||
|
||||
void av1_encode_sb(AV1_COMMON *cm, MACROBLOCK *x, BLOCK_SIZE bsize, int mi_row,
|
||||
int mi_col);
|
||||
#if CONFIG_SUPERTX
|
||||
void av1_encode_sb_supertx(AV1_COMMON *cm, MACROBLOCK *x, BLOCK_SIZE bsize);
|
||||
#endif // CONFIG_SUPERTX
|
||||
void av1_encode_sby_pass1(AV1_COMMON *cm, MACROBLOCK *x, BLOCK_SIZE bsize);
|
||||
void av1_xform_quant(const AV1_COMMON *cm, MACROBLOCK *x, int plane, int block,
|
||||
int blk_row, int blk_col, BLOCK_SIZE plane_bsize,
|
||||
TX_SIZE tx_size, int ctx, AV1_XFORM_QUANT xform_quant_idx);
|
||||
|
||||
int av1_optimize_b(const AV1_COMMON *cm, MACROBLOCK *mb, int plane, int block,
|
||||
TX_SIZE tx_size, int ctx);
|
||||
|
||||
void av1_subtract_txb(MACROBLOCK *x, int plane, BLOCK_SIZE plane_bsize,
|
||||
int blk_col, int blk_row, TX_SIZE tx_size);
|
||||
|
||||
void av1_subtract_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
|
||||
|
||||
void av1_set_txb_context(MACROBLOCK *x, int plane, int block, TX_SIZE tx_size,
|
||||
ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l);
|
||||
|
||||
void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg);
|
||||
|
||||
void av1_encode_intra_block_plane(AV1_COMMON *cm, MACROBLOCK *x,
|
||||
BLOCK_SIZE bsize, int plane,
|
||||
int enable_optimize_b, int mi_row,
|
||||
int mi_col);
|
||||
|
||||
#if CONFIG_PVQ
|
||||
PVQ_SKIP_TYPE av1_pvq_encode_helper(MACROBLOCK *x, tran_low_t *const coeff,
|
||||
tran_low_t *ref_coeff,
|
||||
tran_low_t *const dqcoeff, uint16_t *eob,
|
||||
const int16_t *quant, int plane,
|
||||
int tx_size, TX_TYPE tx_type, int *rate,
|
||||
int speed, PVQ_INFO *pvq_info);
|
||||
|
||||
void av1_store_pvq_enc_info(PVQ_INFO *pvq_info, int *qg, int *theta, int *k,
|
||||
od_coeff *y, int nb_bands, const int *off,
|
||||
int *size, int skip_rest, int skip_dir, int bs);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_ENCODEMB_H_
|
||||
497
third_party/aom/av1/encoder/encodemv.c
vendored
Normal file
497
third_party/aom/av1/encoder/encodemv.c
vendored
Normal file
|
|
@ -0,0 +1,497 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "av1/common/common.h"
|
||||
#include "av1/common/entropymode.h"
|
||||
|
||||
#include "av1/encoder/cost.h"
|
||||
#include "av1/encoder/encodemv.h"
|
||||
#include "av1/encoder/subexp.h"
|
||||
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
|
||||
static struct av1_token mv_joint_encodings[MV_JOINTS];
|
||||
static struct av1_token mv_class_encodings[MV_CLASSES];
|
||||
static struct av1_token mv_fp_encodings[MV_FP_SIZE];
|
||||
|
||||
void av1_entropy_mv_init(void) {
|
||||
av1_tokens_from_tree(mv_joint_encodings, av1_mv_joint_tree);
|
||||
av1_tokens_from_tree(mv_class_encodings, av1_mv_class_tree);
|
||||
av1_tokens_from_tree(mv_fp_encodings, av1_mv_fp_tree);
|
||||
}
|
||||
|
||||
static void encode_mv_component(aom_writer *w, int comp, nmv_component *mvcomp,
|
||||
int usehp) {
|
||||
int offset;
|
||||
const int sign = comp < 0;
|
||||
const int mag = sign ? -comp : comp;
|
||||
const int mv_class = av1_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
|
||||
aom_write(w, sign, mvcomp->sign);
|
||||
|
||||
// Class
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
aom_write_symbol(w, mv_class, mvcomp->class_cdf, MV_CLASSES);
|
||||
#else
|
||||
av1_write_token(w, av1_mv_class_tree, mvcomp->classes,
|
||||
&mv_class_encodings[mv_class]);
|
||||
#endif
|
||||
|
||||
// Integer bits
|
||||
if (mv_class == MV_CLASS_0) {
|
||||
aom_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) aom_write(w, (d >> i) & 1, mvcomp->bits[i]);
|
||||
}
|
||||
|
||||
// Fractional bits
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
aom_write_symbol(
|
||||
w, fr, mv_class == MV_CLASS_0 ? mvcomp->class0_fp_cdf[d] : mvcomp->fp_cdf,
|
||||
MV_FP_SIZE);
|
||||
#else
|
||||
av1_write_token(w, av1_mv_fp_tree,
|
||||
mv_class == MV_CLASS_0 ? mvcomp->class0_fp[d] : mvcomp->fp,
|
||||
&mv_fp_encodings[fr]);
|
||||
#endif
|
||||
|
||||
// High precision bit
|
||||
if (usehp)
|
||||
aom_write(w, hp, mv_class == MV_CLASS_0 ? mvcomp->class0_hp : mvcomp->hp);
|
||||
}
|
||||
|
||||
static void build_nmv_component_cost_table(int *mvcost,
|
||||
const nmv_component *const mvcomp,
|
||||
int usehp) {
|
||||
int i, v;
|
||||
int sign_cost[2], class_cost[MV_CLASSES], class0_cost[CLASS0_SIZE];
|
||||
int bits_cost[MV_OFFSET_BITS][2];
|
||||
int class0_fp_cost[CLASS0_SIZE][MV_FP_SIZE], fp_cost[MV_FP_SIZE];
|
||||
int class0_hp_cost[2], hp_cost[2];
|
||||
|
||||
sign_cost[0] = av1_cost_zero(mvcomp->sign);
|
||||
sign_cost[1] = av1_cost_one(mvcomp->sign);
|
||||
av1_cost_tokens(class_cost, mvcomp->classes, av1_mv_class_tree);
|
||||
av1_cost_tokens(class0_cost, mvcomp->class0, av1_mv_class0_tree);
|
||||
for (i = 0; i < MV_OFFSET_BITS; ++i) {
|
||||
bits_cost[i][0] = av1_cost_zero(mvcomp->bits[i]);
|
||||
bits_cost[i][1] = av1_cost_one(mvcomp->bits[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < CLASS0_SIZE; ++i)
|
||||
av1_cost_tokens(class0_fp_cost[i], mvcomp->class0_fp[i], av1_mv_fp_tree);
|
||||
av1_cost_tokens(fp_cost, mvcomp->fp, av1_mv_fp_tree);
|
||||
|
||||
if (usehp) {
|
||||
class0_hp_cost[0] = av1_cost_zero(mvcomp->class0_hp);
|
||||
class0_hp_cost[1] = av1_cost_one(mvcomp->class0_hp);
|
||||
hp_cost[0] = av1_cost_zero(mvcomp->hp);
|
||||
hp_cost[1] = av1_cost_one(mvcomp->hp);
|
||||
}
|
||||
mvcost[0] = 0;
|
||||
for (v = 1; v <= MV_MAX; ++v) {
|
||||
int z, c, o, d, e, f, cost = 0;
|
||||
z = v - 1;
|
||||
c = av1_get_mv_class(z, &o);
|
||||
cost += class_cost[c];
|
||||
d = (o >> 3); /* int mv data */
|
||||
f = (o >> 1) & 3; /* fractional pel mv data */
|
||||
e = (o & 1); /* high precision mv data */
|
||||
if (c == MV_CLASS_0) {
|
||||
cost += class0_cost[d];
|
||||
} else {
|
||||
const int b = c + CLASS0_BITS - 1; /* number of bits */
|
||||
for (i = 0; i < b; ++i) cost += bits_cost[i][((d >> i) & 1)];
|
||||
}
|
||||
if (c == MV_CLASS_0) {
|
||||
cost += class0_fp_cost[d][f];
|
||||
} else {
|
||||
cost += fp_cost[f];
|
||||
}
|
||||
if (usehp) {
|
||||
if (c == MV_CLASS_0) {
|
||||
cost += class0_hp_cost[e];
|
||||
} else {
|
||||
cost += hp_cost[e];
|
||||
}
|
||||
}
|
||||
mvcost[v] = cost + sign_cost[0];
|
||||
mvcost[-v] = cost + sign_cost[1];
|
||||
}
|
||||
}
|
||||
|
||||
static void update_mv(aom_writer *w, const unsigned int ct[2], aom_prob *cur_p,
|
||||
aom_prob upd_p) {
|
||||
(void)upd_p;
|
||||
#if CONFIG_TILE_GROUPS
|
||||
// Just use the default maximum number of tile groups to avoid passing in the
|
||||
// actual
|
||||
// number
|
||||
av1_cond_prob_diff_update(w, cur_p, ct, DEFAULT_MAX_NUM_TG);
|
||||
#else
|
||||
av1_cond_prob_diff_update(w, cur_p, ct, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !CONFIG_EC_ADAPT
|
||||
static void write_mv_update(const aom_tree_index *tree,
|
||||
aom_prob probs[/*n - 1*/],
|
||||
const unsigned int counts[/*n - 1*/], int n,
|
||||
aom_writer *w) {
|
||||
int i;
|
||||
unsigned int branch_ct[32][2];
|
||||
|
||||
// Assuming max number of probabilities <= 32
|
||||
assert(n <= 32);
|
||||
|
||||
av1_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);
|
||||
}
|
||||
#endif
|
||||
|
||||
void av1_write_nmv_probs(AV1_COMMON *cm, int usehp, aom_writer *w,
|
||||
nmv_context_counts *const nmv_counts) {
|
||||
int i;
|
||||
#if CONFIG_REF_MV
|
||||
int nmv_ctx = 0;
|
||||
for (nmv_ctx = 0; nmv_ctx < NMV_CONTEXTS; ++nmv_ctx) {
|
||||
nmv_context *const mvc = &cm->fc->nmvc[nmv_ctx];
|
||||
nmv_context_counts *const counts = &nmv_counts[nmv_ctx];
|
||||
#if !CONFIG_EC_ADAPT
|
||||
write_mv_update(av1_mv_joint_tree, mvc->joints, counts->joints, MV_JOINTS,
|
||||
w);
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
int j;
|
||||
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(av1_mv_class_tree, comp->classes, comp_counts->classes,
|
||||
MV_CLASSES, w);
|
||||
write_mv_update(av1_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) {
|
||||
int j;
|
||||
for (j = 0; j < CLASS0_SIZE; ++j)
|
||||
write_mv_update(av1_mv_fp_tree, mvc->comps[i].class0_fp[j],
|
||||
counts->comps[i].class0_fp[j], MV_FP_SIZE, w);
|
||||
|
||||
write_mv_update(av1_mv_fp_tree, mvc->comps[i].fp, counts->comps[i].fp,
|
||||
MV_FP_SIZE, w);
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
nmv_context *const mvc = &cm->fc->nmvc;
|
||||
nmv_context_counts *const counts = nmv_counts;
|
||||
|
||||
#if !CONFIG_EC_ADAPT
|
||||
write_mv_update(av1_mv_joint_tree, mvc->joints, counts->joints, MV_JOINTS, w);
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
int j;
|
||||
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(av1_mv_class_tree, comp->classes, comp_counts->classes,
|
||||
MV_CLASSES, w);
|
||||
write_mv_update(av1_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) {
|
||||
int j;
|
||||
for (j = 0; j < CLASS0_SIZE; ++j) {
|
||||
write_mv_update(av1_mv_fp_tree, mvc->comps[i].class0_fp[j],
|
||||
counts->comps[i].class0_fp[j], MV_FP_SIZE, w);
|
||||
}
|
||||
write_mv_update(av1_mv_fp_tree, mvc->comps[i].fp, counts->comps[i].fp,
|
||||
MV_FP_SIZE, w);
|
||||
}
|
||||
#endif // !CONFIG_EC_ADAPT
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void av1_encode_mv(AV1_COMP *cpi, aom_writer *w, const MV *mv, const MV *ref,
|
||||
nmv_context *mvctx, int usehp) {
|
||||
const MV diff = { mv->row - ref->row, mv->col - ref->col };
|
||||
const MV_JOINT_TYPE j = av1_get_mv_joint(&diff);
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
aom_write_symbol(w, j, mvctx->joint_cdf, MV_JOINTS);
|
||||
#else
|
||||
av1_write_token(w, av1_mv_joint_tree, mvctx->joints, &mv_joint_encodings[j]);
|
||||
#endif
|
||||
if (mv_joint_vertical(j))
|
||||
encode_mv_component(w, diff.row, &mvctx->comps[0], usehp);
|
||||
|
||||
if (mv_joint_horizontal(j))
|
||||
encode_mv_component(w, diff.col, &mvctx->comps[1], usehp);
|
||||
|
||||
// If auto_mv_step_size is enabled then keep track of the largest
|
||||
// motion vector component used.
|
||||
if (cpi->sf.mv.auto_mv_step_size) {
|
||||
unsigned int maxv = AOMMAX(abs(mv->row), abs(mv->col)) >> 3;
|
||||
cpi->max_mv_magnitude = AOMMAX(maxv, cpi->max_mv_magnitude);
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_INTRABC
|
||||
void av1_encode_dv(aom_writer *w, const MV *mv, const MV *ref,
|
||||
nmv_context *mvctx) {
|
||||
const MV diff = { mv->row - ref->row, mv->col - ref->col };
|
||||
const MV_JOINT_TYPE j = av1_get_mv_joint(&diff);
|
||||
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
aom_write_symbol(w, j, mvctx->joint_cdf, MV_JOINTS);
|
||||
#else
|
||||
av1_write_token(w, av1_mv_joint_tree, mvctx->joints, &mv_joint_encodings[j]);
|
||||
#endif
|
||||
if (mv_joint_vertical(j))
|
||||
encode_mv_component(w, diff.row, &mvctx->comps[0], 0);
|
||||
|
||||
if (mv_joint_horizontal(j))
|
||||
encode_mv_component(w, diff.col, &mvctx->comps[1], 0);
|
||||
}
|
||||
#endif // CONFIG_INTRABC
|
||||
|
||||
void av1_build_nmv_cost_table(int *mvjoint, int *mvcost[2],
|
||||
const nmv_context *ctx, int usehp) {
|
||||
av1_cost_tokens(mvjoint, ctx->joints, av1_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);
|
||||
}
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
static void inc_mvs(const MB_MODE_INFO *mbmi, const MB_MODE_INFO_EXT *mbmi_ext,
|
||||
const int_mv mvs[2],
|
||||
#if CONFIG_REF_MV
|
||||
const int_mv pred_mvs[2],
|
||||
#endif
|
||||
nmv_context_counts *nmv_counts) {
|
||||
int i;
|
||||
PREDICTION_MODE mode = mbmi->mode;
|
||||
#if !CONFIG_REF_MV
|
||||
nmv_context_counts *counts = nmv_counts;
|
||||
#endif
|
||||
|
||||
if (mode == NEWMV || mode == NEW_NEWMV) {
|
||||
for (i = 0; i < 1 + has_second_ref(mbmi); ++i) {
|
||||
const MV *ref = &mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0].as_mv;
|
||||
const MV diff = { mvs[i].as_mv.row - ref->row,
|
||||
mvs[i].as_mv.col - ref->col };
|
||||
#if CONFIG_REF_MV
|
||||
int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame);
|
||||
int nmv_ctx =
|
||||
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
|
||||
mbmi_ext->ref_mv_stack[rf_type], i, mbmi->ref_mv_idx);
|
||||
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
|
||||
(void)pred_mvs;
|
||||
#endif
|
||||
av1_inc_mv(&diff, counts, 1);
|
||||
}
|
||||
} else if (mode == NEAREST_NEWMV || mode == NEAR_NEWMV) {
|
||||
const MV *ref = &mbmi_ext->ref_mvs[mbmi->ref_frame[1]][0].as_mv;
|
||||
const MV diff = { mvs[1].as_mv.row - ref->row,
|
||||
mvs[1].as_mv.col - ref->col };
|
||||
#if CONFIG_REF_MV
|
||||
int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame);
|
||||
int nmv_ctx =
|
||||
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
|
||||
mbmi_ext->ref_mv_stack[rf_type], 1, mbmi->ref_mv_idx);
|
||||
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
|
||||
#endif
|
||||
av1_inc_mv(&diff, counts, 1);
|
||||
} else if (mode == NEW_NEARESTMV || mode == NEW_NEARMV) {
|
||||
const MV *ref = &mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0].as_mv;
|
||||
const MV diff = { mvs[0].as_mv.row - ref->row,
|
||||
mvs[0].as_mv.col - ref->col };
|
||||
#if CONFIG_REF_MV
|
||||
int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame);
|
||||
int nmv_ctx =
|
||||
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
|
||||
mbmi_ext->ref_mv_stack[rf_type], 0, mbmi->ref_mv_idx);
|
||||
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
|
||||
#endif
|
||||
av1_inc_mv(&diff, counts, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void inc_mvs_sub8x8(const MODE_INFO *mi, int block, const int_mv mvs[2],
|
||||
#if CONFIG_REF_MV
|
||||
const MB_MODE_INFO_EXT *mbmi_ext,
|
||||
#endif
|
||||
nmv_context_counts *nmv_counts) {
|
||||
int i;
|
||||
PREDICTION_MODE mode = mi->bmi[block].as_mode;
|
||||
#if CONFIG_REF_MV
|
||||
const MB_MODE_INFO *mbmi = &mi->mbmi;
|
||||
#else
|
||||
nmv_context_counts *counts = nmv_counts;
|
||||
#endif
|
||||
|
||||
if (mode == NEWMV || mode == NEW_NEWMV) {
|
||||
for (i = 0; i < 1 + has_second_ref(&mi->mbmi); ++i) {
|
||||
const MV *ref = &mi->bmi[block].ref_mv[i].as_mv;
|
||||
const MV diff = { mvs[i].as_mv.row - ref->row,
|
||||
mvs[i].as_mv.col - ref->col };
|
||||
#if CONFIG_REF_MV
|
||||
int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame);
|
||||
int nmv_ctx =
|
||||
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
|
||||
mbmi_ext->ref_mv_stack[rf_type], i, mbmi->ref_mv_idx);
|
||||
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
|
||||
#endif
|
||||
av1_inc_mv(&diff, counts, 1);
|
||||
}
|
||||
} else if (mode == NEAREST_NEWMV || mode == NEAR_NEWMV) {
|
||||
const MV *ref = &mi->bmi[block].ref_mv[1].as_mv;
|
||||
const MV diff = { mvs[1].as_mv.row - ref->row,
|
||||
mvs[1].as_mv.col - ref->col };
|
||||
#if CONFIG_REF_MV
|
||||
int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame);
|
||||
int nmv_ctx =
|
||||
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
|
||||
mbmi_ext->ref_mv_stack[rf_type], 1, mbmi->ref_mv_idx);
|
||||
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
|
||||
#endif
|
||||
av1_inc_mv(&diff, counts, 1);
|
||||
} else if (mode == NEW_NEARESTMV || mode == NEW_NEARMV) {
|
||||
const MV *ref = &mi->bmi[block].ref_mv[0].as_mv;
|
||||
const MV diff = { mvs[0].as_mv.row - ref->row,
|
||||
mvs[0].as_mv.col - ref->col };
|
||||
#if CONFIG_REF_MV
|
||||
int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame);
|
||||
int nmv_ctx =
|
||||
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
|
||||
mbmi_ext->ref_mv_stack[rf_type], 0, mbmi->ref_mv_idx);
|
||||
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
|
||||
#endif
|
||||
av1_inc_mv(&diff, counts, 1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void inc_mvs(const MB_MODE_INFO *mbmi, const MB_MODE_INFO_EXT *mbmi_ext,
|
||||
const int_mv mvs[2],
|
||||
#if CONFIG_REF_MV
|
||||
const int_mv pred_mvs[2],
|
||||
#endif
|
||||
nmv_context_counts *nmv_counts) {
|
||||
int i;
|
||||
#if !CONFIG_REF_MV
|
||||
nmv_context_counts *counts = nmv_counts;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 1 + has_second_ref(mbmi); ++i) {
|
||||
#if CONFIG_REF_MV
|
||||
int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame);
|
||||
int nmv_ctx =
|
||||
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
|
||||
mbmi_ext->ref_mv_stack[rf_type], i, mbmi->ref_mv_idx);
|
||||
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
|
||||
const MV *ref = &pred_mvs[i].as_mv;
|
||||
#else
|
||||
const MV *ref = &mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0].as_mv;
|
||||
#endif
|
||||
const MV diff = { mvs[i].as_mv.row - ref->row,
|
||||
mvs[i].as_mv.col - ref->col };
|
||||
av1_inc_mv(&diff, counts, 1);
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EXT_INTER
|
||||
|
||||
void av1_update_mv_count(ThreadData *td) {
|
||||
const MACROBLOCKD *xd = &td->mb.e_mbd;
|
||||
const MODE_INFO *mi = xd->mi[0];
|
||||
const MB_MODE_INFO *const mbmi = &mi->mbmi;
|
||||
const MB_MODE_INFO_EXT *mbmi_ext = td->mb.mbmi_ext;
|
||||
#if CONFIG_CB4X4
|
||||
const int unify_bsize = 1;
|
||||
#else
|
||||
const int unify_bsize = 0;
|
||||
#endif
|
||||
|
||||
if (mbmi->sb_type < BLOCK_8X8 && !unify_bsize) {
|
||||
const int num_4x4_w = num_4x4_blocks_wide_lookup[mbmi->sb_type];
|
||||
const int num_4x4_h = num_4x4_blocks_high_lookup[mbmi->sb_type];
|
||||
int idx, idy;
|
||||
|
||||
for (idy = 0; idy < 2; idy += num_4x4_h) {
|
||||
for (idx = 0; idx < 2; idx += num_4x4_w) {
|
||||
const int i = idy * 2 + idx;
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
if (have_newmv_in_inter_mode(mi->bmi[i].as_mode))
|
||||
inc_mvs_sub8x8(mi, i, mi->bmi[i].as_mv,
|
||||
#if CONFIG_REF_MV
|
||||
mbmi_ext, td->counts->mv);
|
||||
#else
|
||||
&td->counts->mv);
|
||||
#endif
|
||||
#else
|
||||
if (mi->bmi[i].as_mode == NEWMV)
|
||||
inc_mvs(mbmi, mbmi_ext, mi->bmi[i].as_mv,
|
||||
#if CONFIG_REF_MV
|
||||
mi->bmi[i].pred_mv, td->counts->mv);
|
||||
#else
|
||||
&td->counts->mv);
|
||||
#endif
|
||||
#endif // CONFIG_EXT_INTER
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if CONFIG_EXT_INTER
|
||||
if (have_newmv_in_inter_mode(mbmi->mode))
|
||||
#else
|
||||
if (mbmi->mode == NEWMV)
|
||||
#endif // CONFIG_EXT_INTER
|
||||
inc_mvs(mbmi, mbmi_ext, mbmi->mv,
|
||||
#if CONFIG_REF_MV
|
||||
mbmi->pred_mv, td->counts->mv);
|
||||
#else
|
||||
&td->counts->mv);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
43
third_party/aom/av1/encoder/encodemv.h
vendored
Normal file
43
third_party/aom/av1/encoder/encodemv.h
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_ENCODEMV_H_
|
||||
#define AV1_ENCODER_ENCODEMV_H_
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void av1_entropy_mv_init(void);
|
||||
|
||||
void av1_write_nmv_probs(AV1_COMMON *cm, int usehp, aom_writer *w,
|
||||
nmv_context_counts *const counts);
|
||||
|
||||
void av1_encode_mv(AV1_COMP *cpi, aom_writer *w, const MV *mv, const MV *ref,
|
||||
nmv_context *mvctx, int usehp);
|
||||
|
||||
void av1_build_nmv_cost_table(int *mvjoint, int *mvcost[2],
|
||||
const nmv_context *mvctx, int usehp);
|
||||
|
||||
void av1_update_mv_count(ThreadData *td);
|
||||
|
||||
#if CONFIG_INTRABC
|
||||
void av1_encode_dv(aom_writer *w, const MV *mv, const MV *ref,
|
||||
nmv_context *mvctx);
|
||||
#endif // CONFIG_INTRABC
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_ENCODEMV_H_
|
||||
5980
third_party/aom/av1/encoder/encoder.c
vendored
Normal file
5980
third_party/aom/av1/encoder/encoder.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
883
third_party/aom/av1/encoder/encoder.h
vendored
Normal file
883
third_party/aom/av1/encoder/encoder.h
vendored
Normal file
|
|
@ -0,0 +1,883 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_ENCODER_H_
|
||||
#define AV1_ENCODER_ENCODER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "./aom_config.h"
|
||||
#include "aom/aomcx.h"
|
||||
|
||||
#include "av1/common/alloccommon.h"
|
||||
#include "av1/common/entropymode.h"
|
||||
#include "av1/common/thread_common.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/encoder/aq_cyclicrefresh.h"
|
||||
#if CONFIG_ANS
|
||||
#include "aom_dsp/ans.h"
|
||||
#include "aom_dsp/buf_ans.h"
|
||||
#endif
|
||||
#include "av1/encoder/av1_quantize.h"
|
||||
#include "av1/encoder/context_tree.h"
|
||||
#include "av1/encoder/encodemb.h"
|
||||
#include "av1/encoder/firstpass.h"
|
||||
#include "av1/encoder/lookahead.h"
|
||||
#include "av1/encoder/mbgraph.h"
|
||||
#include "av1/encoder/mcomp.h"
|
||||
#include "av1/encoder/ratectrl.h"
|
||||
#include "av1/encoder/rd.h"
|
||||
#include "av1/encoder/speed_features.h"
|
||||
#include "av1/encoder/tokenize.h"
|
||||
#include "av1/encoder/variance_tree.h"
|
||||
#if CONFIG_XIPHRC
|
||||
#include "av1/encoder/ratectrl_xiph.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_INTERNAL_STATS
|
||||
#include "aom_dsp/ssim.h"
|
||||
#endif
|
||||
#include "aom_dsp/variance.h"
|
||||
#include "aom/internal/aom_codec_internal.h"
|
||||
#include "aom_util/aom_thread.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int nmvjointcost[MV_JOINTS];
|
||||
int nmvcosts[2][MV_VALS];
|
||||
int nmvcosts_hp[2][MV_VALS];
|
||||
|
||||
#if CONFIG_REF_MV
|
||||
int nmv_vec_cost[NMV_CONTEXTS][MV_JOINTS];
|
||||
int nmv_costs[NMV_CONTEXTS][2][MV_VALS];
|
||||
int nmv_costs_hp[NMV_CONTEXTS][2][MV_VALS];
|
||||
#endif
|
||||
|
||||
// 0 = Intra, Last, GF, ARF
|
||||
signed char last_ref_lf_deltas[TOTAL_REFS_PER_FRAME];
|
||||
// 0 = ZERO_MV, MV
|
||||
signed char last_mode_lf_deltas[MAX_MODE_LF_DELTAS];
|
||||
|
||||
FRAME_CONTEXT fc;
|
||||
} CODING_CONTEXT;
|
||||
|
||||
typedef enum {
|
||||
// regular inter frame
|
||||
REGULAR_FRAME = 0,
|
||||
// alternate reference frame
|
||||
ARF_FRAME = 1,
|
||||
// overlay frame
|
||||
OVERLAY_FRAME = 2,
|
||||
// golden frame
|
||||
GLD_FRAME = 3,
|
||||
#if CONFIG_EXT_REFS
|
||||
// backward reference frame
|
||||
BRF_FRAME = 4,
|
||||
// extra alternate reference frame
|
||||
EXT_ARF_FRAME = 5
|
||||
#endif
|
||||
} FRAME_CONTEXT_INDEX;
|
||||
|
||||
typedef enum {
|
||||
NORMAL = 0,
|
||||
FOURFIVE = 1,
|
||||
THREEFIVE = 2,
|
||||
ONETWO = 3
|
||||
} AOM_SCALING;
|
||||
|
||||
typedef enum {
|
||||
// Good Quality Fast Encoding. The encoder balances quality with the amount of
|
||||
// time it takes to encode the output. Speed setting controls how fast.
|
||||
GOOD
|
||||
} MODE;
|
||||
|
||||
typedef enum {
|
||||
FRAMEFLAGS_KEY = 1 << 0,
|
||||
FRAMEFLAGS_GOLDEN = 1 << 1,
|
||||
#if CONFIG_EXT_REFS
|
||||
FRAMEFLAGS_BWDREF = 1 << 2,
|
||||
FRAMEFLAGS_ALTREF = 1 << 3,
|
||||
#else
|
||||
FRAMEFLAGS_ALTREF = 1 << 2,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
} FRAMETYPE_FLAGS;
|
||||
|
||||
typedef enum {
|
||||
NO_AQ = 0,
|
||||
VARIANCE_AQ = 1,
|
||||
COMPLEXITY_AQ = 2,
|
||||
CYCLIC_REFRESH_AQ = 3,
|
||||
#if CONFIG_DELTA_Q && !CONFIG_EXT_DELTA_Q
|
||||
DELTA_AQ = 4,
|
||||
#endif
|
||||
AQ_MODE_COUNT // This should always be the last member of the enum
|
||||
} AQ_MODE;
|
||||
#if CONFIG_EXT_DELTA_Q
|
||||
typedef enum {
|
||||
NO_DELTA_Q = 0,
|
||||
DELTA_Q_ONLY = 1,
|
||||
DELTA_Q_LF = 2,
|
||||
DELTAQ_MODE_COUNT // This should always be the last member of the enum
|
||||
} DELTAQ_MODE;
|
||||
#endif
|
||||
typedef enum {
|
||||
RESIZE_NONE = 0, // No frame resizing allowed.
|
||||
RESIZE_FIXED = 1, // All frames are coded at the specified dimension.
|
||||
RESIZE_DYNAMIC = 2 // Coded size of each frame is determined by the codec.
|
||||
} RESIZE_TYPE;
|
||||
|
||||
typedef struct AV1EncoderConfig {
|
||||
BITSTREAM_PROFILE profile;
|
||||
aom_bit_depth_t bit_depth; // Codec bit-depth.
|
||||
int width; // width of data passed to the compressor
|
||||
int height; // height of data passed to the compressor
|
||||
unsigned int input_bit_depth; // Input bit depth.
|
||||
double init_framerate; // set to passed in framerate
|
||||
int64_t target_bandwidth; // bandwidth to be used in bits per second
|
||||
|
||||
int noise_sensitivity; // pre processing blur: recommendation 0
|
||||
int sharpness; // sharpening output: recommendation 0:
|
||||
int speed;
|
||||
// maximum allowed bitrate for any intra frame in % of bitrate target.
|
||||
unsigned int rc_max_intra_bitrate_pct;
|
||||
// maximum allowed bitrate for any inter frame in % of bitrate target.
|
||||
unsigned int rc_max_inter_bitrate_pct;
|
||||
// percent of rate boost for golden frame in CBR mode.
|
||||
unsigned int gf_cbr_boost_pct;
|
||||
|
||||
MODE mode;
|
||||
int pass;
|
||||
|
||||
// Key Framing Operations
|
||||
int auto_key; // autodetect cut scenes and set the keyframes
|
||||
int key_freq; // maximum distance to key frame.
|
||||
|
||||
int lag_in_frames; // how many frames lag before we start encoding
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// DATARATE CONTROL OPTIONS
|
||||
|
||||
// vbr, cbr, constrained quality or constant quality
|
||||
enum aom_rc_mode rc_mode;
|
||||
|
||||
// buffer targeting aggressiveness
|
||||
int under_shoot_pct;
|
||||
int over_shoot_pct;
|
||||
|
||||
// buffering parameters
|
||||
int64_t starting_buffer_level_ms;
|
||||
int64_t optimal_buffer_level_ms;
|
||||
int64_t maximum_buffer_size_ms;
|
||||
|
||||
// Frame drop threshold.
|
||||
int drop_frames_water_mark;
|
||||
|
||||
// controlling quality
|
||||
int fixed_q;
|
||||
int worst_allowed_q;
|
||||
int best_allowed_q;
|
||||
int cq_level;
|
||||
AQ_MODE aq_mode; // Adaptive Quantization mode
|
||||
#if CONFIG_EXT_DELTA_Q
|
||||
DELTAQ_MODE deltaq_mode;
|
||||
#endif
|
||||
#if CONFIG_AOM_QM
|
||||
int using_qm;
|
||||
int qm_minlevel;
|
||||
int qm_maxlevel;
|
||||
#endif
|
||||
#if CONFIG_TILE_GROUPS
|
||||
unsigned int num_tile_groups;
|
||||
unsigned int mtu;
|
||||
#endif
|
||||
|
||||
#if CONFIG_TEMPMV_SIGNALING
|
||||
unsigned int disable_tempmv;
|
||||
#endif
|
||||
// Internal frame size scaling.
|
||||
RESIZE_TYPE resize_mode;
|
||||
int scaled_frame_width;
|
||||
int scaled_frame_height;
|
||||
|
||||
// Enable feature to reduce the frame quantization every x frames.
|
||||
int frame_periodic_boost;
|
||||
|
||||
// two pass datarate control
|
||||
int two_pass_vbrbias; // two pass datarate control tweaks
|
||||
int two_pass_vbrmin_section;
|
||||
int two_pass_vbrmax_section;
|
||||
// END DATARATE CONTROL OPTIONS
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
int enable_auto_arf;
|
||||
#if CONFIG_EXT_REFS
|
||||
int enable_auto_brf; // (b)ackward (r)ef (f)rame
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
/* Bitfield defining the error resiliency features to enable.
|
||||
* Can provide decodable frames after losses in previous
|
||||
* frames and decodable partitions after losses in the same frame.
|
||||
*/
|
||||
unsigned int error_resilient_mode;
|
||||
|
||||
/* Bitfield defining the parallel decoding mode where the
|
||||
* decoding in successive frames may be conducted in parallel
|
||||
* just by decoding the frame headers.
|
||||
*/
|
||||
unsigned int frame_parallel_decoding_mode;
|
||||
|
||||
int arnr_max_frames;
|
||||
int arnr_strength;
|
||||
|
||||
int min_gf_interval;
|
||||
int max_gf_interval;
|
||||
|
||||
int tile_columns;
|
||||
int tile_rows;
|
||||
#if CONFIG_DEPENDENT_HORZTILES
|
||||
int dependent_horz_tiles;
|
||||
#endif
|
||||
#if CONFIG_LOOPFILTERING_ACROSS_TILES
|
||||
int loop_filter_across_tiles_enabled;
|
||||
#endif // CONFIG_LOOPFILTERING_ACROSS_TILES
|
||||
|
||||
int max_threads;
|
||||
|
||||
aom_fixed_buf_t two_pass_stats_in;
|
||||
struct aom_codec_pkt_list *output_pkt_list;
|
||||
|
||||
#if CONFIG_FP_MB_STATS
|
||||
aom_fixed_buf_t firstpass_mb_stats_in;
|
||||
#endif
|
||||
|
||||
aom_tune_metric tuning;
|
||||
aom_tune_content content;
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int use_highbitdepth;
|
||||
#endif
|
||||
aom_color_space_t color_space;
|
||||
int color_range;
|
||||
int render_width;
|
||||
int render_height;
|
||||
|
||||
#if CONFIG_EXT_PARTITION
|
||||
aom_superblock_size_t superblock_size;
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
#if CONFIG_ANS && ANS_MAX_SYMBOLS
|
||||
int ans_window_size_log2;
|
||||
#endif // CONFIG_ANS && ANS_MAX_SYMBOLS
|
||||
#if CONFIG_EXT_TILE
|
||||
unsigned int tile_encoding_mode;
|
||||
#endif // CONFIG_EXT_TILE
|
||||
|
||||
unsigned int motion_vector_unit_test;
|
||||
} AV1EncoderConfig;
|
||||
|
||||
static INLINE int is_lossless_requested(const AV1EncoderConfig *cfg) {
|
||||
return cfg->best_allowed_q == 0 && cfg->worst_allowed_q == 0;
|
||||
}
|
||||
|
||||
// TODO(jingning) All spatially adaptive variables should go to TileDataEnc.
|
||||
typedef struct TileDataEnc {
|
||||
TileInfo tile_info;
|
||||
int thresh_freq_fact[BLOCK_SIZES][MAX_MODES];
|
||||
int mode_map[BLOCK_SIZES][MAX_MODES];
|
||||
int m_search_count;
|
||||
int ex_search_count;
|
||||
#if CONFIG_PVQ
|
||||
PVQ_QUEUE pvq_q;
|
||||
#endif
|
||||
#if CONFIG_CFL
|
||||
CFL_CTX cfl;
|
||||
#endif
|
||||
#if CONFIG_EC_ADAPT
|
||||
DECLARE_ALIGNED(16, FRAME_CONTEXT, tctx);
|
||||
#endif
|
||||
} TileDataEnc;
|
||||
|
||||
typedef struct RD_COUNTS {
|
||||
av1_coeff_count coef_counts[TX_SIZES][PLANE_TYPES];
|
||||
int64_t comp_pred_diff[REFERENCE_MODES];
|
||||
#if CONFIG_GLOBAL_MOTION
|
||||
// Stores number of 4x4 blocks using global motion per reference frame.
|
||||
int global_motion_used[TOTAL_REFS_PER_FRAME];
|
||||
#endif // CONFIG_GLOBAL_MOTION
|
||||
} RD_COUNTS;
|
||||
|
||||
typedef struct ThreadData {
|
||||
MACROBLOCK mb;
|
||||
RD_COUNTS rd_counts;
|
||||
FRAME_COUNTS *counts;
|
||||
|
||||
PICK_MODE_CONTEXT *leaf_tree;
|
||||
PC_TREE *pc_tree;
|
||||
PC_TREE *pc_root[MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2 + 1];
|
||||
|
||||
VAR_TREE *var_tree;
|
||||
VAR_TREE *var_root[MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2 + 1];
|
||||
} ThreadData;
|
||||
|
||||
struct EncWorkerData;
|
||||
|
||||
typedef struct ActiveMap {
|
||||
int enabled;
|
||||
int update;
|
||||
unsigned char *map;
|
||||
} ActiveMap;
|
||||
|
||||
#define NUM_STAT_TYPES 4 // types of stats: Y, U, V and ALL
|
||||
|
||||
typedef struct IMAGE_STAT {
|
||||
double stat[NUM_STAT_TYPES];
|
||||
double worst;
|
||||
} ImageStat;
|
||||
|
||||
#undef NUM_STAT_TYPES
|
||||
|
||||
typedef struct {
|
||||
int ref_count;
|
||||
YV12_BUFFER_CONFIG buf;
|
||||
} EncRefCntBuffer;
|
||||
|
||||
#if CONFIG_SUBFRAME_PROB_UPDATE
|
||||
typedef struct SUBFRAME_STATS {
|
||||
av1_coeff_probs_model coef_probs_buf[COEF_PROBS_BUFS][TX_SIZES][PLANE_TYPES];
|
||||
av1_coeff_count coef_counts_buf[COEF_PROBS_BUFS][TX_SIZES][PLANE_TYPES];
|
||||
unsigned int eob_counts_buf[COEF_PROBS_BUFS][TX_SIZES][PLANE_TYPES][REF_TYPES]
|
||||
[COEF_BANDS][COEFF_CONTEXTS];
|
||||
av1_coeff_probs_model enc_starting_coef_probs[TX_SIZES][PLANE_TYPES];
|
||||
} SUBFRAME_STATS;
|
||||
#endif // CONFIG_SUBFRAME_PROB_UPDATE
|
||||
|
||||
typedef struct TileBufferEnc {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
} TileBufferEnc;
|
||||
|
||||
typedef struct AV1_COMP {
|
||||
QUANTS quants;
|
||||
ThreadData td;
|
||||
MB_MODE_INFO_EXT *mbmi_ext_base;
|
||||
DECLARE_ALIGNED(16, int16_t, y_dequant[QINDEX_RANGE][8]); // 8: SIMD width
|
||||
DECLARE_ALIGNED(16, int16_t, uv_dequant[QINDEX_RANGE][8]); // 8: SIMD width
|
||||
#if CONFIG_NEW_QUANT
|
||||
DECLARE_ALIGNED(16, dequant_val_type_nuq,
|
||||
y_dequant_val_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS]);
|
||||
DECLARE_ALIGNED(16, dequant_val_type_nuq,
|
||||
uv_dequant_val_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS]);
|
||||
#endif // CONFIG_NEW_QUANT
|
||||
AV1_COMMON common;
|
||||
AV1EncoderConfig oxcf;
|
||||
struct lookahead_ctx *lookahead;
|
||||
struct lookahead_entry *alt_ref_source;
|
||||
|
||||
YV12_BUFFER_CONFIG *source;
|
||||
YV12_BUFFER_CONFIG *last_source; // NULL for first frame and alt_ref frames
|
||||
YV12_BUFFER_CONFIG *un_scaled_source;
|
||||
YV12_BUFFER_CONFIG scaled_source;
|
||||
YV12_BUFFER_CONFIG *unscaled_last_source;
|
||||
YV12_BUFFER_CONFIG scaled_last_source;
|
||||
|
||||
// Up-sampled reference buffers
|
||||
// NOTE(zoeliu): It is needed to allocate sufficient space to the up-sampled
|
||||
// reference buffers, which should include the up-sampled version of all the
|
||||
// possibly stored references plus the currently coded frame itself.
|
||||
EncRefCntBuffer upsampled_ref_bufs[REF_FRAMES + 1];
|
||||
int upsampled_ref_idx[REF_FRAMES + 1];
|
||||
|
||||
// For a still frame, this flag is set to 1 to skip partition search.
|
||||
int partition_search_skippable_frame;
|
||||
|
||||
int scaled_ref_idx[TOTAL_REFS_PER_FRAME];
|
||||
#if CONFIG_EXT_REFS
|
||||
int lst_fb_idxes[LAST_REF_FRAMES];
|
||||
#else
|
||||
int lst_fb_idx;
|
||||
#endif // CONFIG_EXT_REFS
|
||||
int gld_fb_idx;
|
||||
#if CONFIG_EXT_REFS
|
||||
int bwd_fb_idx; // BWD_REF_FRAME
|
||||
#endif // CONFIG_EXT_REFS
|
||||
int alt_fb_idx;
|
||||
|
||||
int last_show_frame_buf_idx; // last show frame buffer index
|
||||
|
||||
int refresh_last_frame;
|
||||
int refresh_golden_frame;
|
||||
#if CONFIG_EXT_REFS
|
||||
int refresh_bwd_ref_frame;
|
||||
#endif // CONFIG_EXT_REFS
|
||||
int refresh_alt_ref_frame;
|
||||
|
||||
int ext_refresh_frame_flags_pending;
|
||||
int ext_refresh_last_frame;
|
||||
int ext_refresh_golden_frame;
|
||||
int ext_refresh_alt_ref_frame;
|
||||
|
||||
int ext_refresh_frame_context_pending;
|
||||
int ext_refresh_frame_context;
|
||||
|
||||
YV12_BUFFER_CONFIG last_frame_uf;
|
||||
#if CONFIG_LOOP_RESTORATION
|
||||
YV12_BUFFER_CONFIG last_frame_db;
|
||||
YV12_BUFFER_CONFIG trial_frame_rst;
|
||||
uint8_t *extra_rstbuf; // Extra buffers used in restoration search
|
||||
RestorationInfo rst_search[MAX_MB_PLANE]; // Used for encoder side search
|
||||
#endif // CONFIG_LOOP_RESTORATION
|
||||
|
||||
// Ambient reconstruction err target for force key frames
|
||||
int64_t ambient_err;
|
||||
|
||||
RD_OPT rd;
|
||||
|
||||
CODING_CONTEXT coding_context;
|
||||
|
||||
#if CONFIG_REF_MV
|
||||
int nmv_costs[NMV_CONTEXTS][2][MV_VALS];
|
||||
int nmv_costs_hp[NMV_CONTEXTS][2][MV_VALS];
|
||||
#endif
|
||||
|
||||
int nmvcosts[2][MV_VALS];
|
||||
int nmvcosts_hp[2][MV_VALS];
|
||||
int nmvsadcosts[2][MV_VALS];
|
||||
int nmvsadcosts_hp[2][MV_VALS];
|
||||
|
||||
int64_t last_time_stamp_seen;
|
||||
int64_t last_end_time_stamp_seen;
|
||||
int64_t first_time_stamp_ever;
|
||||
|
||||
RATE_CONTROL rc;
|
||||
#if CONFIG_XIPHRC
|
||||
od_rc_state od_rc;
|
||||
#endif
|
||||
double framerate;
|
||||
|
||||
// NOTE(zoeliu): Any inter frame allows maximum of REF_FRAMES inter
|
||||
// references; Plus the currently coded frame itself, it is needed to allocate
|
||||
// sufficient space to the size of the maximum possible number of frames.
|
||||
int interp_filter_selected[REF_FRAMES + 1][SWITCHABLE];
|
||||
|
||||
struct aom_codec_pkt_list *output_pkt_list;
|
||||
|
||||
MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS];
|
||||
int mbgraph_n_frames; // number of frames filled in the above
|
||||
int static_mb_pct; // % forced skip mbs by segmentation
|
||||
int ref_frame_flags;
|
||||
|
||||
SPEED_FEATURES sf;
|
||||
|
||||
unsigned int max_mv_magnitude;
|
||||
int mv_step_param;
|
||||
|
||||
int allow_comp_inter_inter;
|
||||
|
||||
uint8_t *segmentation_map;
|
||||
|
||||
CYCLIC_REFRESH *cyclic_refresh;
|
||||
ActiveMap active_map;
|
||||
|
||||
fractional_mv_step_fp *find_fractional_mv_step;
|
||||
av1_full_search_fn_t full_search_sad; // It is currently unused.
|
||||
av1_diamond_search_fn_t diamond_search_sad;
|
||||
aom_variance_fn_ptr_t fn_ptr[BLOCK_SIZES];
|
||||
uint64_t time_receive_data;
|
||||
uint64_t time_compress_data;
|
||||
uint64_t time_pick_lpf;
|
||||
uint64_t time_encode_sb_row;
|
||||
|
||||
#if CONFIG_FP_MB_STATS
|
||||
int use_fp_mb_stats;
|
||||
#endif
|
||||
|
||||
TWO_PASS twopass;
|
||||
|
||||
YV12_BUFFER_CONFIG alt_ref_buffer;
|
||||
|
||||
#if CONFIG_INTERNAL_STATS
|
||||
unsigned int mode_chosen_counts[MAX_MODES];
|
||||
|
||||
int count;
|
||||
uint64_t total_sq_error;
|
||||
uint64_t total_samples;
|
||||
ImageStat psnr;
|
||||
|
||||
double total_blockiness;
|
||||
double worst_blockiness;
|
||||
|
||||
int bytes;
|
||||
double summed_quality;
|
||||
double summed_weights;
|
||||
unsigned int tot_recode_hits;
|
||||
double worst_ssim;
|
||||
|
||||
ImageStat fastssim;
|
||||
ImageStat psnrhvs;
|
||||
|
||||
int b_calculate_blockiness;
|
||||
int b_calculate_consistency;
|
||||
|
||||
double total_inconsistency;
|
||||
double worst_consistency;
|
||||
Ssimv *ssim_vars;
|
||||
Metrics metrics;
|
||||
#endif
|
||||
int b_calculate_psnr;
|
||||
|
||||
int droppable;
|
||||
|
||||
int initial_width;
|
||||
int initial_height;
|
||||
int initial_mbs; // Number of MBs in the full-size frame; to be used to
|
||||
// normalize the firstpass stats. This will differ from the
|
||||
// number of MBs in the current frame when the frame is
|
||||
// scaled.
|
||||
|
||||
// Store frame variance info in SOURCE_VAR_BASED_PARTITION search type.
|
||||
DIFF *source_diff_var;
|
||||
// The threshold used in SOURCE_VAR_BASED_PARTITION search type.
|
||||
unsigned int source_var_thresh;
|
||||
int frames_till_next_var_check;
|
||||
|
||||
int frame_flags;
|
||||
|
||||
search_site_config ss_cfg;
|
||||
|
||||
int mbmode_cost[BLOCK_SIZE_GROUPS][INTRA_MODES];
|
||||
#if CONFIG_REF_MV
|
||||
int newmv_mode_cost[NEWMV_MODE_CONTEXTS][2];
|
||||
int zeromv_mode_cost[ZEROMV_MODE_CONTEXTS][2];
|
||||
int refmv_mode_cost[REFMV_MODE_CONTEXTS][2];
|
||||
int drl_mode_cost0[DRL_MODE_CONTEXTS][2];
|
||||
#endif
|
||||
|
||||
unsigned int inter_mode_cost[INTER_MODE_CONTEXTS][INTER_MODES];
|
||||
#if CONFIG_EXT_INTER
|
||||
unsigned int inter_compound_mode_cost[INTER_MODE_CONTEXTS]
|
||||
[INTER_COMPOUND_MODES];
|
||||
unsigned int interintra_mode_cost[BLOCK_SIZE_GROUPS][INTERINTRA_MODES];
|
||||
#endif // CONFIG_EXT_INTER
|
||||
#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
|
||||
int motion_mode_cost[BLOCK_SIZES][MOTION_MODES];
|
||||
#if CONFIG_MOTION_VAR && CONFIG_WARPED_MOTION
|
||||
int motion_mode_cost1[BLOCK_SIZES][2];
|
||||
#endif // CONFIG_MOTION_VAR && CONFIG_WARPED_MOTION
|
||||
#endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
|
||||
int intra_uv_mode_cost[INTRA_MODES][INTRA_MODES];
|
||||
int y_mode_costs[INTRA_MODES][INTRA_MODES][INTRA_MODES];
|
||||
int switchable_interp_costs[SWITCHABLE_FILTER_CONTEXTS][SWITCHABLE_FILTERS];
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
int partition_cost[PARTITION_CONTEXTS + CONFIG_UNPOISON_PARTITION_CTX]
|
||||
[EXT_PARTITION_TYPES];
|
||||
#else
|
||||
int partition_cost[PARTITION_CONTEXTS + CONFIG_UNPOISON_PARTITION_CTX]
|
||||
[PARTITION_TYPES];
|
||||
#endif
|
||||
#if CONFIG_PALETTE
|
||||
int palette_y_size_cost[PALETTE_BLOCK_SIZES][PALETTE_SIZES];
|
||||
int palette_uv_size_cost[PALETTE_BLOCK_SIZES][PALETTE_SIZES];
|
||||
int palette_y_color_cost[PALETTE_SIZES][PALETTE_COLOR_INDEX_CONTEXTS]
|
||||
[PALETTE_COLORS];
|
||||
int palette_uv_color_cost[PALETTE_SIZES][PALETTE_COLOR_INDEX_CONTEXTS]
|
||||
[PALETTE_COLORS];
|
||||
#endif // CONFIG_PALETTE
|
||||
int tx_size_cost[TX_SIZES - 1][TX_SIZE_CONTEXTS][TX_SIZES];
|
||||
#if CONFIG_EXT_TX
|
||||
int inter_tx_type_costs[EXT_TX_SETS_INTER][EXT_TX_SIZES][TX_TYPES];
|
||||
int intra_tx_type_costs[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
|
||||
[TX_TYPES];
|
||||
#else
|
||||
int intra_tx_type_costs[EXT_TX_SIZES][TX_TYPES][TX_TYPES];
|
||||
int inter_tx_type_costs[EXT_TX_SIZES][TX_TYPES];
|
||||
#endif // CONFIG_EXT_TX
|
||||
#if CONFIG_EXT_INTRA
|
||||
#if CONFIG_INTRA_INTERP
|
||||
int intra_filter_cost[INTRA_FILTERS + 1][INTRA_FILTERS];
|
||||
#endif // CONFIG_INTRA_INTERP
|
||||
#endif // CONFIG_EXT_INTRA
|
||||
#if CONFIG_LOOP_RESTORATION
|
||||
int switchable_restore_cost[RESTORE_SWITCHABLE_TYPES];
|
||||
#endif // CONFIG_LOOP_RESTORATION
|
||||
#if CONFIG_GLOBAL_MOTION
|
||||
int gmtype_cost[TRANS_TYPES];
|
||||
int gmparams_cost[TOTAL_REFS_PER_FRAME];
|
||||
#endif // CONFIG_GLOBAL_MOTION
|
||||
|
||||
int multi_arf_allowed;
|
||||
int multi_arf_enabled;
|
||||
int multi_arf_last_grp_enabled;
|
||||
|
||||
TileDataEnc *tile_data;
|
||||
int allocated_tiles; // Keep track of memory allocated for tiles.
|
||||
|
||||
TOKENEXTRA *tile_tok[MAX_TILE_ROWS][MAX_TILE_COLS];
|
||||
unsigned int tok_count[MAX_TILE_ROWS][MAX_TILE_COLS];
|
||||
|
||||
TileBufferEnc tile_buffers[MAX_TILE_ROWS][MAX_TILE_COLS];
|
||||
|
||||
int resize_pending;
|
||||
int resize_state;
|
||||
int resize_scale_num;
|
||||
int resize_scale_den;
|
||||
int resize_avg_qp;
|
||||
int resize_buffer_underflow;
|
||||
int resize_count;
|
||||
|
||||
// VAR_BASED_PARTITION thresholds
|
||||
// 0 - threshold_128x128;
|
||||
// 1 - threshold_64x64;
|
||||
// 2 - threshold_32x32;
|
||||
// 3 - threshold_16x16;
|
||||
// 4 - threshold_8x8;
|
||||
int64_t vbp_thresholds[5];
|
||||
int64_t vbp_threshold_minmax;
|
||||
int64_t vbp_threshold_sad;
|
||||
BLOCK_SIZE vbp_bsize_min;
|
||||
|
||||
// VARIANCE_AQ segment map refresh
|
||||
int vaq_refresh;
|
||||
|
||||
// Multi-threading
|
||||
int num_workers;
|
||||
AVxWorker *workers;
|
||||
struct EncWorkerData *tile_thr_data;
|
||||
AV1LfSync lf_row_sync;
|
||||
#if CONFIG_SUBFRAME_PROB_UPDATE
|
||||
SUBFRAME_STATS subframe_stats;
|
||||
// TODO(yaowu): minimize the size of count buffers
|
||||
SUBFRAME_STATS wholeframe_stats;
|
||||
av1_coeff_stats branch_ct_buf[COEF_PROBS_BUFS][TX_SIZES][PLANE_TYPES];
|
||||
#endif // CONFIG_SUBFRAME_PROB_UPDATE
|
||||
#if CONFIG_ANS
|
||||
struct BufAnsCoder buf_ans;
|
||||
#endif
|
||||
#if CONFIG_EXT_REFS
|
||||
int refresh_frame_mask;
|
||||
int existing_fb_idx_to_show;
|
||||
int is_arf_filter_off[MAX_EXT_ARFS + 1];
|
||||
int num_extra_arfs;
|
||||
int arf_map[MAX_EXT_ARFS + 1];
|
||||
#endif // CONFIG_EXT_REFS
|
||||
#if CONFIG_GLOBAL_MOTION
|
||||
int global_motion_search_done;
|
||||
#endif
|
||||
#if CONFIG_REFERENCE_BUFFER
|
||||
SequenceHeader seq_params;
|
||||
#endif
|
||||
#if CONFIG_LV_MAP
|
||||
tran_low_t *tcoeff_buf[MAX_MB_PLANE];
|
||||
#endif
|
||||
} AV1_COMP;
|
||||
|
||||
void av1_initialize_enc(void);
|
||||
|
||||
struct AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf,
|
||||
BufferPool *const pool);
|
||||
void av1_remove_compressor(AV1_COMP *cpi);
|
||||
|
||||
void av1_change_config(AV1_COMP *cpi, const AV1EncoderConfig *oxcf);
|
||||
|
||||
// receive a frames worth of data. caller can assume that a copy of this
|
||||
// frame is made and not just a copy of the pointer..
|
||||
int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags,
|
||||
YV12_BUFFER_CONFIG *sd, int64_t time_stamp,
|
||||
int64_t end_time_stamp);
|
||||
|
||||
int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
|
||||
size_t *size, uint8_t *dest, int64_t *time_stamp,
|
||||
int64_t *time_end, int flush);
|
||||
|
||||
int av1_get_preview_raw_frame(AV1_COMP *cpi, YV12_BUFFER_CONFIG *dest);
|
||||
|
||||
int av1_get_last_show_frame(AV1_COMP *cpi, YV12_BUFFER_CONFIG *frame);
|
||||
|
||||
int av1_use_as_reference(AV1_COMP *cpi, int ref_frame_flags);
|
||||
|
||||
void av1_update_reference(AV1_COMP *cpi, int ref_frame_flags);
|
||||
|
||||
int av1_copy_reference_enc(AV1_COMP *cpi, AOM_REFFRAME ref_frame_flag,
|
||||
YV12_BUFFER_CONFIG *sd);
|
||||
|
||||
int av1_set_reference_enc(AV1_COMP *cpi, AOM_REFFRAME ref_frame_flag,
|
||||
YV12_BUFFER_CONFIG *sd);
|
||||
|
||||
int av1_update_entropy(AV1_COMP *cpi, int update);
|
||||
|
||||
int av1_set_active_map(AV1_COMP *cpi, unsigned char *map, int rows, int cols);
|
||||
|
||||
int av1_get_active_map(AV1_COMP *cpi, unsigned char *map, int rows, int cols);
|
||||
|
||||
int av1_set_internal_size(AV1_COMP *cpi, AOM_SCALING horiz_mode,
|
||||
AOM_SCALING vert_mode);
|
||||
|
||||
int av1_set_size_literal(AV1_COMP *cpi, unsigned int width,
|
||||
unsigned int height);
|
||||
|
||||
int av1_get_quantizer(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_full_to_model_counts(av1_coeff_count_model *model_count,
|
||||
av1_coeff_count *full_count);
|
||||
|
||||
static INLINE int frame_is_kf_gf_arf(const AV1_COMP *cpi) {
|
||||
return frame_is_intra_only(&cpi->common) || cpi->refresh_alt_ref_frame ||
|
||||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref);
|
||||
}
|
||||
|
||||
static INLINE int get_ref_frame_map_idx(const AV1_COMP *cpi,
|
||||
MV_REFERENCE_FRAME ref_frame) {
|
||||
#if CONFIG_EXT_REFS
|
||||
if (ref_frame >= LAST_FRAME && ref_frame <= LAST3_FRAME)
|
||||
return cpi->lst_fb_idxes[ref_frame - 1];
|
||||
#else
|
||||
if (ref_frame == LAST_FRAME) return cpi->lst_fb_idx;
|
||||
#endif // CONFIG_EXT_REFS
|
||||
else if (ref_frame == GOLDEN_FRAME)
|
||||
return cpi->gld_fb_idx;
|
||||
#if CONFIG_EXT_REFS
|
||||
else if (ref_frame == BWDREF_FRAME)
|
||||
return cpi->bwd_fb_idx;
|
||||
#endif // CONFIG_EXT_REFS
|
||||
else
|
||||
return cpi->alt_fb_idx;
|
||||
}
|
||||
|
||||
static INLINE int get_ref_frame_buf_idx(const AV1_COMP *cpi,
|
||||
MV_REFERENCE_FRAME ref_frame) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const int map_idx = get_ref_frame_map_idx(cpi, ref_frame);
|
||||
return (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : INVALID_IDX;
|
||||
}
|
||||
|
||||
static INLINE YV12_BUFFER_CONFIG *get_ref_frame_buffer(
|
||||
const AV1_COMP *cpi, MV_REFERENCE_FRAME ref_frame) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const int buf_idx = get_ref_frame_buf_idx(cpi, ref_frame);
|
||||
return buf_idx != INVALID_IDX ? &cm->buffer_pool->frame_bufs[buf_idx].buf
|
||||
: NULL;
|
||||
}
|
||||
|
||||
static INLINE const YV12_BUFFER_CONFIG *get_upsampled_ref(
|
||||
const AV1_COMP *cpi, const MV_REFERENCE_FRAME ref_frame) {
|
||||
// Use up-sampled reference frames.
|
||||
const int buf_idx =
|
||||
cpi->upsampled_ref_idx[get_ref_frame_map_idx(cpi, ref_frame)];
|
||||
return &cpi->upsampled_ref_bufs[buf_idx].buf;
|
||||
}
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
static INLINE int enc_is_ref_frame_buf(AV1_COMP *cpi, RefCntBuffer *frame_buf) {
|
||||
MV_REFERENCE_FRAME ref_frame;
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
|
||||
const int buf_idx = get_ref_frame_buf_idx(cpi, ref_frame);
|
||||
if (buf_idx == INVALID_IDX) continue;
|
||||
if (frame_buf == &cm->buffer_pool->frame_bufs[buf_idx]) break;
|
||||
}
|
||||
return (ref_frame <= ALTREF_FRAME);
|
||||
}
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
static INLINE unsigned int get_token_alloc(int mb_rows, int mb_cols) {
|
||||
// We assume 3 planes all at full resolution. We assume up to 1 token per
|
||||
// pixel, and then allow a head room of 1 EOSB token per 4x4 block per plane,
|
||||
// plus EOSB_TOKEN per plane.
|
||||
return mb_rows * mb_cols * (16 * 16 + 17) * 3;
|
||||
}
|
||||
|
||||
// Get the allocated token size for a tile. It does the same calculation as in
|
||||
// the frame token allocation.
|
||||
static INLINE unsigned int allocated_tokens(TileInfo tile) {
|
||||
#if CONFIG_CB4X4
|
||||
int tile_mb_rows = (tile.mi_row_end - tile.mi_row_start + 2) >> 2;
|
||||
int tile_mb_cols = (tile.mi_col_end - tile.mi_col_start + 2) >> 2;
|
||||
#else
|
||||
int tile_mb_rows = (tile.mi_row_end - tile.mi_row_start + 1) >> 1;
|
||||
int tile_mb_cols = (tile.mi_col_end - tile.mi_col_start + 1) >> 1;
|
||||
#endif
|
||||
|
||||
return get_token_alloc(tile_mb_rows, tile_mb_cols);
|
||||
}
|
||||
|
||||
void av1_alloc_compressor_data(AV1_COMP *cpi);
|
||||
|
||||
void av1_scale_references(AV1_COMP *cpi);
|
||||
|
||||
void av1_update_reference_frames(AV1_COMP *cpi);
|
||||
|
||||
void av1_set_high_precision_mv(AV1_COMP *cpi, int allow_high_precision_mv);
|
||||
#if CONFIG_TEMPMV_SIGNALING
|
||||
void av1_set_temporal_mv_prediction(AV1_COMP *cpi, int allow_tempmv_prediction);
|
||||
#endif
|
||||
|
||||
YV12_BUFFER_CONFIG *av1_scale_if_required_fast(AV1_COMMON *cm,
|
||||
YV12_BUFFER_CONFIG *unscaled,
|
||||
YV12_BUFFER_CONFIG *scaled);
|
||||
|
||||
YV12_BUFFER_CONFIG *av1_scale_if_required(AV1_COMMON *cm,
|
||||
YV12_BUFFER_CONFIG *unscaled,
|
||||
YV12_BUFFER_CONFIG *scaled);
|
||||
|
||||
void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags);
|
||||
|
||||
static INLINE int is_altref_enabled(const AV1_COMP *const cpi) {
|
||||
return cpi->oxcf.lag_in_frames > 0 && cpi->oxcf.enable_auto_arf;
|
||||
}
|
||||
|
||||
// TODO(zoeliu): To set up cpi->oxcf.enable_auto_brf
|
||||
#if 0 && CONFIG_EXT_REFS
|
||||
static INLINE int is_bwdref_enabled(const AV1_COMP *const cpi) {
|
||||
// NOTE(zoeliu): The enabling of bi-predictive frames depends on the use of
|
||||
// alt_ref, and now will be off when the alt_ref interval is
|
||||
// not sufficiently large.
|
||||
return is_altref_enabled(cpi) && cpi->oxcf.enable_auto_brf;
|
||||
}
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
static INLINE void set_ref_ptrs(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
MV_REFERENCE_FRAME ref0,
|
||||
MV_REFERENCE_FRAME ref1) {
|
||||
xd->block_refs[0] =
|
||||
&cm->frame_refs[ref0 >= LAST_FRAME ? ref0 - LAST_FRAME : 0];
|
||||
xd->block_refs[1] =
|
||||
&cm->frame_refs[ref1 >= LAST_FRAME ? ref1 - LAST_FRAME : 0];
|
||||
}
|
||||
|
||||
static INLINE int get_chessboard_index(int frame_index) {
|
||||
return frame_index & 0x1;
|
||||
}
|
||||
|
||||
static INLINE int *cond_cost_list(const struct AV1_COMP *cpi, int *cost_list) {
|
||||
return cpi->sf.mv.subpel_search_method != SUBPEL_TREE ? cost_list : NULL;
|
||||
}
|
||||
|
||||
void av1_new_framerate(AV1_COMP *cpi, double framerate);
|
||||
|
||||
#define LAYER_IDS_TO_IDX(sl, tl, num_tl) ((sl) * (num_tl) + (tl))
|
||||
|
||||
// Update up-sampled reference frame index.
|
||||
static INLINE void uref_cnt_fb(EncRefCntBuffer *ubufs, int *uidx,
|
||||
int new_uidx) {
|
||||
const int ref_index = *uidx;
|
||||
|
||||
if (ref_index >= 0 && ubufs[ref_index].ref_count > 0)
|
||||
ubufs[ref_index].ref_count--;
|
||||
|
||||
*uidx = new_uidx;
|
||||
ubufs[new_uidx].ref_count++;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_ENCODER_H_
|
||||
784
third_party/aom/av1/encoder/encodetxb.c
vendored
Normal file
784
third_party/aom/av1/encoder/encodetxb.c
vendored
Normal file
|
|
@ -0,0 +1,784 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "av1/common/scan.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/idct.h"
|
||||
#include "av1/common/pred_common.h"
|
||||
#include "av1/encoder/bitstream.h"
|
||||
#include "av1/encoder/encodeframe.h"
|
||||
#include "av1/encoder/cost.h"
|
||||
#include "av1/encoder/encodetxb.h"
|
||||
#include "av1/encoder/rdopt.h"
|
||||
#include "av1/encoder/subexp.h"
|
||||
#include "av1/encoder/tokenize.h"
|
||||
|
||||
void av1_alloc_txb_buf(AV1_COMP *cpi) {
|
||||
#if 0
|
||||
AV1_COMMON *cm = &cpi->common;
|
||||
int mi_block_size = 1 << MI_SIZE_LOG2;
|
||||
// TODO(angiebird): Make sure cm->subsampling_x/y is set correctly, and then
|
||||
// use precise buffer size according to cm->subsampling_x/y
|
||||
int pixel_stride = mi_block_size * cm->mi_cols;
|
||||
int pixel_height = mi_block_size * cm->mi_rows;
|
||||
int i;
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
CHECK_MEM_ERROR(
|
||||
cm, cpi->tcoeff_buf[i],
|
||||
aom_malloc(sizeof(*cpi->tcoeff_buf[i]) * pixel_stride * pixel_height));
|
||||
}
|
||||
#else
|
||||
(void)cpi;
|
||||
#endif
|
||||
}
|
||||
|
||||
void av1_free_txb_buf(AV1_COMP *cpi) {
|
||||
#if 0
|
||||
int i;
|
||||
for (i = 0; i < MAX_MB_PLANE; ++i) {
|
||||
aom_free(cpi->tcoeff_buf[i]);
|
||||
}
|
||||
#else
|
||||
(void)cpi;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void write_golomb(aom_writer *w, int level) {
|
||||
int x = level + 1;
|
||||
int i = x;
|
||||
int length = 0;
|
||||
|
||||
while (i) {
|
||||
i >>= 1;
|
||||
++length;
|
||||
}
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length - 1; ++i) aom_write_bit(w, 0);
|
||||
|
||||
for (i = length - 1; i >= 0; --i) aom_write_bit(w, (x >> i) & 0x01);
|
||||
}
|
||||
|
||||
void av1_write_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCKD *xd,
|
||||
aom_writer *w, int block, int plane,
|
||||
const tran_low_t *tcoeff, uint16_t eob,
|
||||
TXB_CTX *txb_ctx) {
|
||||
aom_prob *nz_map;
|
||||
aom_prob *eob_flag;
|
||||
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
||||
const PLANE_TYPE plane_type = get_plane_type(plane);
|
||||
const TX_SIZE tx_size = get_tx_size(plane, xd);
|
||||
const TX_TYPE tx_type = get_tx_type(plane_type, xd, block, tx_size);
|
||||
const SCAN_ORDER *const scan_order =
|
||||
get_scan(cm, tx_size, tx_type, is_inter_block(mbmi));
|
||||
const int16_t *scan = scan_order->scan;
|
||||
int c;
|
||||
int is_nz;
|
||||
const int bwl = b_width_log2_lookup[txsize_to_bsize[tx_size]] + 2;
|
||||
const int seg_eob = tx_size_2d[tx_size];
|
||||
uint8_t txb_mask[32 * 32] = { 0 };
|
||||
uint16_t update_eob = 0;
|
||||
|
||||
aom_write(w, eob == 0, cm->fc->txb_skip[tx_size][txb_ctx->txb_skip_ctx]);
|
||||
|
||||
if (eob == 0) return;
|
||||
#if CONFIG_TXK_SEL
|
||||
av1_write_tx_type(cm, xd, block, plane, w);
|
||||
#endif
|
||||
|
||||
nz_map = cm->fc->nz_map[tx_size][plane_type];
|
||||
eob_flag = cm->fc->eob_flag[tx_size][plane_type];
|
||||
|
||||
for (c = 0; c < eob; ++c) {
|
||||
int coeff_ctx = get_nz_map_ctx(tcoeff, txb_mask, scan[c], bwl);
|
||||
int eob_ctx = get_eob_ctx(tcoeff, scan[c], bwl);
|
||||
|
||||
tran_low_t v = tcoeff[scan[c]];
|
||||
is_nz = (v != 0);
|
||||
|
||||
if (c == seg_eob - 1) break;
|
||||
|
||||
aom_write(w, is_nz, nz_map[coeff_ctx]);
|
||||
|
||||
if (is_nz) {
|
||||
aom_write(w, c == (eob - 1), eob_flag[eob_ctx]);
|
||||
}
|
||||
txb_mask[scan[c]] = 1;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < NUM_BASE_LEVELS; ++i) {
|
||||
aom_prob *coeff_base = cm->fc->coeff_base[tx_size][plane_type][i];
|
||||
|
||||
update_eob = 0;
|
||||
for (c = eob - 1; c >= 0; --c) {
|
||||
tran_low_t v = tcoeff[scan[c]];
|
||||
tran_low_t level = abs(v);
|
||||
int sign = (v < 0) ? 1 : 0;
|
||||
int ctx;
|
||||
|
||||
if (level <= i) continue;
|
||||
|
||||
ctx = get_base_ctx(tcoeff, scan[c], bwl, i + 1);
|
||||
|
||||
if (level == i + 1) {
|
||||
aom_write(w, 1, coeff_base[ctx]);
|
||||
if (c == 0) {
|
||||
aom_write(w, sign, cm->fc->dc_sign[plane_type][txb_ctx->dc_sign_ctx]);
|
||||
} else {
|
||||
aom_write_bit(w, sign);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
aom_write(w, 0, coeff_base[ctx]);
|
||||
update_eob = AOMMAX(update_eob, c);
|
||||
}
|
||||
}
|
||||
|
||||
for (c = update_eob; c >= 0; --c) {
|
||||
tran_low_t v = tcoeff[scan[c]];
|
||||
tran_low_t level = abs(v);
|
||||
int sign = (v < 0) ? 1 : 0;
|
||||
int idx;
|
||||
int ctx;
|
||||
|
||||
if (level <= NUM_BASE_LEVELS) continue;
|
||||
|
||||
if (c == 0) {
|
||||
aom_write(w, sign, cm->fc->dc_sign[plane_type][txb_ctx->dc_sign_ctx]);
|
||||
} else {
|
||||
aom_write_bit(w, sign);
|
||||
}
|
||||
|
||||
// level is above 1.
|
||||
ctx = get_level_ctx(tcoeff, scan[c], bwl);
|
||||
for (idx = 0; idx < COEFF_BASE_RANGE; ++idx) {
|
||||
if (level == (idx + 1 + NUM_BASE_LEVELS)) {
|
||||
aom_write(w, 1, cm->fc->coeff_lps[tx_size][plane_type][ctx]);
|
||||
break;
|
||||
}
|
||||
aom_write(w, 0, cm->fc->coeff_lps[tx_size][plane_type][ctx]);
|
||||
}
|
||||
if (idx < COEFF_BASE_RANGE) continue;
|
||||
|
||||
// use 0-th order Golomb code to handle the residual level.
|
||||
write_golomb(w, level - COEFF_BASE_RANGE - 1 - NUM_BASE_LEVELS);
|
||||
}
|
||||
}
|
||||
|
||||
void av1_write_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x,
|
||||
aom_writer *w, int plane) {
|
||||
MACROBLOCKD *xd = &x->e_mbd;
|
||||
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
||||
BLOCK_SIZE bsize = mbmi->sb_type;
|
||||
struct macroblockd_plane *pd = &xd->plane[plane];
|
||||
|
||||
#if CONFIG_CB4X4
|
||||
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
|
||||
#else
|
||||
const BLOCK_SIZE plane_bsize =
|
||||
get_plane_block_size(AOMMAX(bsize, BLOCK_8X8), pd);
|
||||
#endif
|
||||
const int max_blocks_wide = max_block_wide(xd, plane_bsize, plane);
|
||||
const int max_blocks_high = max_block_high(xd, plane_bsize, plane);
|
||||
TX_SIZE tx_size = get_tx_size(plane, xd);
|
||||
const int bkw = tx_size_wide_unit[tx_size];
|
||||
const int bkh = tx_size_high_unit[tx_size];
|
||||
const int step = tx_size_wide_unit[tx_size] * tx_size_high_unit[tx_size];
|
||||
int row, col;
|
||||
int block = 0;
|
||||
for (row = 0; row < max_blocks_high; row += bkh) {
|
||||
for (col = 0; col < max_blocks_wide; col += bkw) {
|
||||
tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block);
|
||||
uint16_t eob = x->mbmi_ext->eobs[plane][block];
|
||||
TXB_CTX txb_ctx = { x->mbmi_ext->txb_skip_ctx[plane][block],
|
||||
x->mbmi_ext->dc_sign_ctx[plane][block] };
|
||||
av1_write_coeffs_txb(cm, xd, w, block, plane, tcoeff, eob, &txb_ctx);
|
||||
block += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void get_base_ctx_set(const tran_low_t *tcoeffs,
|
||||
int c, // raster order
|
||||
const int bwl,
|
||||
int ctx_set[NUM_BASE_LEVELS]) {
|
||||
const int row = c >> bwl;
|
||||
const int col = c - (row << bwl);
|
||||
const int stride = 1 << bwl;
|
||||
int mag[NUM_BASE_LEVELS] = { 0 };
|
||||
int idx;
|
||||
tran_low_t abs_coeff;
|
||||
int i;
|
||||
|
||||
for (idx = 0; idx < BASE_CONTEXT_POSITION_NUM; ++idx) {
|
||||
int ref_row = row + base_ref_offset[idx][0];
|
||||
int ref_col = col + base_ref_offset[idx][1];
|
||||
int pos = (ref_row << bwl) + ref_col;
|
||||
|
||||
if (ref_row < 0 || ref_col < 0 || ref_row >= stride || ref_col >= stride)
|
||||
continue;
|
||||
|
||||
abs_coeff = abs(tcoeffs[pos]);
|
||||
|
||||
for (i = 0; i < NUM_BASE_LEVELS; ++i) {
|
||||
ctx_set[i] += abs_coeff > i;
|
||||
if (base_ref_offset[idx][0] >= 0 && base_ref_offset[idx][1] >= 0)
|
||||
mag[i] |= abs_coeff > (i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_BASE_LEVELS; ++i) {
|
||||
ctx_set[i] = (ctx_set[i] + 1) >> 1;
|
||||
|
||||
if (row == 0 && col == 0)
|
||||
ctx_set[i] = (ctx_set[i] << 1) + mag[i];
|
||||
else if (row == 0)
|
||||
ctx_set[i] = 8 + (ctx_set[i] << 1) + mag[i];
|
||||
else if (col == 0)
|
||||
ctx_set[i] = 18 + (ctx_set[i] << 1) + mag[i];
|
||||
else
|
||||
ctx_set[i] = 28 + (ctx_set[i] << 1) + mag[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int av1_cost_coeffs_txb(const AV1_COMP *const cpi, MACROBLOCK *x, int plane,
|
||||
int block, TXB_CTX *txb_ctx) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
const TX_SIZE tx_size = get_tx_size(plane, xd);
|
||||
const PLANE_TYPE plane_type = get_plane_type(plane);
|
||||
const TX_TYPE tx_type = get_tx_type(plane_type, xd, block, tx_size);
|
||||
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
||||
const struct macroblock_plane *p = &x->plane[plane];
|
||||
const int eob = p->eobs[block];
|
||||
const tran_low_t *const qcoeff = BLOCK_OFFSET(p->qcoeff, block);
|
||||
int c, cost;
|
||||
const int seg_eob = AOMMIN(eob, tx_size_2d[tx_size] - 1);
|
||||
int txb_skip_ctx = txb_ctx->txb_skip_ctx;
|
||||
aom_prob *nz_map = xd->fc->nz_map[tx_size][plane_type];
|
||||
|
||||
const int bwl = b_width_log2_lookup[txsize_to_bsize[tx_size]] + 2;
|
||||
// txb_mask is only initialized for once here. After that, it will be set when
|
||||
// coding zero map and then reset when coding level 1 info.
|
||||
uint8_t txb_mask[32 * 32] = { 0 };
|
||||
aom_prob(*coeff_base)[COEFF_BASE_CONTEXTS] =
|
||||
xd->fc->coeff_base[tx_size][plane_type];
|
||||
|
||||
const SCAN_ORDER *const scan_order =
|
||||
get_scan(cm, tx_size, tx_type, is_inter_block(mbmi));
|
||||
const int16_t *scan = scan_order->scan;
|
||||
|
||||
cost = 0;
|
||||
|
||||
if (eob == 0) {
|
||||
cost = av1_cost_bit(xd->fc->txb_skip[tx_size][txb_skip_ctx], 1);
|
||||
return cost;
|
||||
}
|
||||
|
||||
cost = av1_cost_bit(xd->fc->txb_skip[tx_size][txb_skip_ctx], 0);
|
||||
|
||||
#if CONFIG_TXK_SEL
|
||||
cost += av1_tx_type_cost(cpi, xd, mbmi->sb_type, plane, tx_size, tx_type);
|
||||
#endif
|
||||
|
||||
for (c = 0; c < eob; ++c) {
|
||||
tran_low_t v = qcoeff[scan[c]];
|
||||
int is_nz = (v != 0);
|
||||
int level = abs(v);
|
||||
|
||||
if (c < seg_eob) {
|
||||
int coeff_ctx = get_nz_map_ctx(qcoeff, txb_mask, scan[c], bwl);
|
||||
cost += av1_cost_bit(nz_map[coeff_ctx], is_nz);
|
||||
}
|
||||
|
||||
if (is_nz) {
|
||||
int ctx_ls[NUM_BASE_LEVELS] = { 0 };
|
||||
int sign = (v < 0) ? 1 : 0;
|
||||
|
||||
// sign bit cost
|
||||
if (c == 0) {
|
||||
int dc_sign_ctx = txb_ctx->dc_sign_ctx;
|
||||
|
||||
cost += av1_cost_bit(xd->fc->dc_sign[plane_type][dc_sign_ctx], sign);
|
||||
} else {
|
||||
cost += av1_cost_bit(128, sign);
|
||||
}
|
||||
|
||||
get_base_ctx_set(qcoeff, scan[c], bwl, ctx_ls);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < NUM_BASE_LEVELS; ++i) {
|
||||
if (level <= i) continue;
|
||||
|
||||
if (level == i + 1) {
|
||||
cost += av1_cost_bit(coeff_base[i][ctx_ls[i]], 1);
|
||||
continue;
|
||||
}
|
||||
cost += av1_cost_bit(coeff_base[i][ctx_ls[i]], 0);
|
||||
}
|
||||
|
||||
if (level > NUM_BASE_LEVELS) {
|
||||
int idx;
|
||||
int ctx;
|
||||
|
||||
ctx = get_level_ctx(qcoeff, scan[c], bwl);
|
||||
|
||||
for (idx = 0; idx < COEFF_BASE_RANGE; ++idx) {
|
||||
if (level == (idx + 1 + NUM_BASE_LEVELS)) {
|
||||
cost +=
|
||||
av1_cost_bit(xd->fc->coeff_lps[tx_size][plane_type][ctx], 1);
|
||||
break;
|
||||
}
|
||||
cost += av1_cost_bit(xd->fc->coeff_lps[tx_size][plane_type][ctx], 0);
|
||||
}
|
||||
|
||||
if (idx >= COEFF_BASE_RANGE) {
|
||||
// residual cost
|
||||
int r = level - COEFF_BASE_RANGE - NUM_BASE_LEVELS;
|
||||
int ri = r;
|
||||
int length = 0;
|
||||
|
||||
while (ri) {
|
||||
ri >>= 1;
|
||||
++length;
|
||||
}
|
||||
|
||||
for (ri = 0; ri < length - 1; ++ri) cost += av1_cost_bit(128, 0);
|
||||
|
||||
for (ri = length - 1; ri >= 0; --ri)
|
||||
cost += av1_cost_bit(128, (r >> ri) & 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
if (c < seg_eob) {
|
||||
int eob_ctx = get_eob_ctx(qcoeff, scan[c], bwl);
|
||||
cost += av1_cost_bit(xd->fc->eob_flag[tx_size][plane_type][eob_ctx],
|
||||
c == (eob - 1));
|
||||
}
|
||||
}
|
||||
|
||||
txb_mask[scan[c]] = 1;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
typedef struct TxbParams {
|
||||
const AV1_COMP *cpi;
|
||||
ThreadData *td;
|
||||
int rate;
|
||||
} TxbParams;
|
||||
|
||||
int av1_get_txb_entropy_context(const tran_low_t *qcoeff,
|
||||
const SCAN_ORDER *scan_order, int eob) {
|
||||
const int16_t *scan = scan_order->scan;
|
||||
int cul_level = 0;
|
||||
int c;
|
||||
for (c = 0; c < eob; ++c) {
|
||||
cul_level += abs(qcoeff[scan[c]]);
|
||||
}
|
||||
|
||||
cul_level = AOMMIN(COEFF_CONTEXT_MASK, cul_level);
|
||||
set_dc_sign(&cul_level, qcoeff[0]);
|
||||
|
||||
return cul_level;
|
||||
}
|
||||
|
||||
static void update_txb_context(int plane, int block, int blk_row, int blk_col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
|
||||
void *arg) {
|
||||
TxbParams *const args = arg;
|
||||
const AV1_COMP *cpi = args->cpi;
|
||||
const AV1_COMMON *cm = &cpi->common;
|
||||
ThreadData *const td = args->td;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
||||
struct macroblock_plane *p = &x->plane[plane];
|
||||
struct macroblockd_plane *pd = &xd->plane[plane];
|
||||
const uint16_t eob = p->eobs[block];
|
||||
const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
|
||||
const PLANE_TYPE plane_type = pd->plane_type;
|
||||
const TX_TYPE tx_type = get_tx_type(plane_type, xd, block, tx_size);
|
||||
const SCAN_ORDER *const scan_order =
|
||||
get_scan(cm, tx_size, tx_type, is_inter_block(mbmi));
|
||||
(void)plane_bsize;
|
||||
|
||||
int cul_level = av1_get_txb_entropy_context(qcoeff, scan_order, eob);
|
||||
av1_set_contexts(xd, pd, plane, tx_size, cul_level, blk_col, blk_row);
|
||||
}
|
||||
|
||||
static void update_and_record_txb_context(int plane, int block, int blk_row,
|
||||
int blk_col, BLOCK_SIZE plane_bsize,
|
||||
TX_SIZE tx_size, void *arg) {
|
||||
TxbParams *const args = arg;
|
||||
const AV1_COMP *cpi = args->cpi;
|
||||
const AV1_COMMON *cm = &cpi->common;
|
||||
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];
|
||||
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
||||
int eob = p->eobs[block], update_eob = 0;
|
||||
const PLANE_TYPE plane_type = pd->plane_type;
|
||||
const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
|
||||
tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block);
|
||||
const int segment_id = mbmi->segment_id;
|
||||
const TX_TYPE tx_type = get_tx_type(plane_type, xd, block, tx_size);
|
||||
const SCAN_ORDER *const scan_order =
|
||||
get_scan(cm, tx_size, tx_type, is_inter_block(mbmi));
|
||||
const int16_t *scan = scan_order->scan;
|
||||
const int seg_eob = get_tx_eob(&cpi->common.seg, segment_id, tx_size);
|
||||
int c, i;
|
||||
TXB_CTX txb_ctx;
|
||||
get_txb_ctx(plane_bsize, tx_size, plane, pd->above_context + blk_col,
|
||||
pd->left_context + blk_row, &txb_ctx);
|
||||
const int bwl = b_width_log2_lookup[txsize_to_bsize[tx_size]] + 2;
|
||||
int cul_level = 0;
|
||||
unsigned int(*nz_map_count)[SIG_COEF_CONTEXTS][2];
|
||||
uint8_t txb_mask[32 * 32] = { 0 };
|
||||
|
||||
nz_map_count = &td->counts->nz_map[tx_size][plane_type];
|
||||
|
||||
memcpy(tcoeff, qcoeff, sizeof(*tcoeff) * seg_eob);
|
||||
|
||||
++td->counts->txb_skip[tx_size][txb_ctx.txb_skip_ctx][eob == 0];
|
||||
x->mbmi_ext->txb_skip_ctx[plane][block] = txb_ctx.txb_skip_ctx;
|
||||
|
||||
x->mbmi_ext->eobs[plane][block] = eob;
|
||||
|
||||
if (eob == 0) {
|
||||
av1_set_contexts(xd, pd, plane, tx_size, 0, blk_col, blk_row);
|
||||
return;
|
||||
}
|
||||
|
||||
#if CONFIG_TXK_SEL
|
||||
av1_update_tx_type_count(cm, xd, block, plane, mbmi->sb_type, tx_size,
|
||||
td->counts);
|
||||
#endif
|
||||
|
||||
for (c = 0; c < eob; ++c) {
|
||||
tran_low_t v = qcoeff[scan[c]];
|
||||
int is_nz = (v != 0);
|
||||
int coeff_ctx = get_nz_map_ctx(tcoeff, txb_mask, scan[c], bwl);
|
||||
int eob_ctx = get_eob_ctx(tcoeff, scan[c], bwl);
|
||||
|
||||
if (c == seg_eob - 1) break;
|
||||
|
||||
++(*nz_map_count)[coeff_ctx][is_nz];
|
||||
|
||||
if (is_nz) {
|
||||
++td->counts->eob_flag[tx_size][plane_type][eob_ctx][c == (eob - 1)];
|
||||
}
|
||||
txb_mask[scan[c]] = 1;
|
||||
}
|
||||
|
||||
// Reverse process order to handle coefficient level and sign.
|
||||
for (i = 0; i < NUM_BASE_LEVELS; ++i) {
|
||||
update_eob = 0;
|
||||
for (c = eob - 1; c >= 0; --c) {
|
||||
tran_low_t v = qcoeff[scan[c]];
|
||||
tran_low_t level = abs(v);
|
||||
int ctx;
|
||||
|
||||
if (level <= i) continue;
|
||||
|
||||
ctx = get_base_ctx(tcoeff, scan[c], bwl, i + 1);
|
||||
|
||||
if (level == i + 1) {
|
||||
++td->counts->coeff_base[tx_size][plane_type][i][ctx][1];
|
||||
if (c == 0) {
|
||||
int dc_sign_ctx = txb_ctx.dc_sign_ctx;
|
||||
|
||||
++td->counts->dc_sign[plane_type][dc_sign_ctx][v < 0];
|
||||
x->mbmi_ext->dc_sign_ctx[plane][block] = dc_sign_ctx;
|
||||
}
|
||||
cul_level += level;
|
||||
continue;
|
||||
}
|
||||
++td->counts->coeff_base[tx_size][plane_type][i][ctx][0];
|
||||
update_eob = AOMMAX(update_eob, c);
|
||||
}
|
||||
}
|
||||
|
||||
for (c = update_eob; c >= 0; --c) {
|
||||
tran_low_t v = qcoeff[scan[c]];
|
||||
tran_low_t level = abs(v);
|
||||
int idx;
|
||||
int ctx;
|
||||
|
||||
if (level <= NUM_BASE_LEVELS) continue;
|
||||
|
||||
cul_level += level;
|
||||
if (c == 0) {
|
||||
int dc_sign_ctx = txb_ctx.dc_sign_ctx;
|
||||
|
||||
++td->counts->dc_sign[plane_type][dc_sign_ctx][v < 0];
|
||||
x->mbmi_ext->dc_sign_ctx[plane][block] = dc_sign_ctx;
|
||||
}
|
||||
|
||||
// level is above 1.
|
||||
ctx = get_level_ctx(tcoeff, scan[c], bwl);
|
||||
for (idx = 0; idx < COEFF_BASE_RANGE; ++idx) {
|
||||
if (level == (idx + 1 + NUM_BASE_LEVELS)) {
|
||||
++td->counts->coeff_lps[tx_size][plane_type][ctx][1];
|
||||
break;
|
||||
}
|
||||
++td->counts->coeff_lps[tx_size][plane_type][ctx][0];
|
||||
}
|
||||
if (idx < COEFF_BASE_RANGE) continue;
|
||||
|
||||
// use 0-th order Golomb code to handle the residual level.
|
||||
}
|
||||
|
||||
cul_level = AOMMIN(COEFF_CONTEXT_MASK, cul_level);
|
||||
|
||||
// DC value
|
||||
set_dc_sign(&cul_level, tcoeff[0]);
|
||||
av1_set_contexts(xd, pd, plane, tx_size, cul_level, blk_col, blk_row);
|
||||
|
||||
#if CONFIG_ADAPT_SCAN
|
||||
// Since dqcoeff is not available here, we pass qcoeff into
|
||||
// av1_update_scan_count_facade(). The update behavior should be the same
|
||||
// because av1_update_scan_count_facade() only cares if coefficients are zero
|
||||
// or not.
|
||||
av1_update_scan_count_facade((AV1_COMMON *)cm, td->counts, tx_size, tx_type,
|
||||
qcoeff, eob);
|
||||
#endif
|
||||
}
|
||||
|
||||
void av1_update_txb_context(const AV1_COMP *cpi, ThreadData *td,
|
||||
RUN_TYPE dry_run, BLOCK_SIZE bsize, int *rate,
|
||||
int mi_row, int mi_col) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
|
||||
const int ctx = av1_get_skip_context(xd);
|
||||
const int skip_inc =
|
||||
!segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP);
|
||||
struct TxbParams arg = { cpi, td, 0 };
|
||||
(void)rate;
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
if (mbmi->skip) {
|
||||
if (!dry_run) td->counts->skip[ctx][1] += skip_inc;
|
||||
reset_skip_context(xd, bsize);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dry_run) {
|
||||
td->counts->skip[ctx][0] += skip_inc;
|
||||
av1_foreach_transformed_block(xd, bsize, mi_row, mi_col,
|
||||
update_and_record_txb_context, &arg);
|
||||
} else if (dry_run == DRY_RUN_NORMAL) {
|
||||
av1_foreach_transformed_block(xd, bsize, mi_row, mi_col, update_txb_context,
|
||||
&arg);
|
||||
} else {
|
||||
printf("DRY_RUN_COSTCOEFFS is not supported yet\n");
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void find_new_prob(unsigned int *branch_cnt, aom_prob *oldp,
|
||||
int *savings, int *update, aom_writer *const bc) {
|
||||
const aom_prob upd = DIFF_UPDATE_PROB;
|
||||
int u = 0;
|
||||
aom_prob newp = get_binary_prob(branch_cnt[0], branch_cnt[1]);
|
||||
int s = av1_prob_diff_update_savings_search(branch_cnt, *oldp, &newp, upd, 1);
|
||||
|
||||
if (s > 0 && newp != *oldp) u = 1;
|
||||
|
||||
if (u)
|
||||
*savings += s - (int)(av1_cost_zero(upd)); // TODO(jingning): 1?
|
||||
else
|
||||
*savings -= (int)(av1_cost_zero(upd));
|
||||
|
||||
if (update) {
|
||||
++update[u];
|
||||
return;
|
||||
}
|
||||
|
||||
aom_write(bc, u, upd);
|
||||
if (u) {
|
||||
/* send/use new probability */
|
||||
av1_write_prob_diff_update(bc, newp, *oldp);
|
||||
*oldp = newp;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_txb_probs(aom_writer *const bc, AV1_COMP *cpi,
|
||||
TX_SIZE tx_size) {
|
||||
FRAME_CONTEXT *fc = cpi->common.fc;
|
||||
FRAME_COUNTS *counts = cpi->td.counts;
|
||||
int savings = 0;
|
||||
int update[2] = { 0, 0 };
|
||||
int plane, ctx, level;
|
||||
|
||||
for (ctx = 0; ctx < TXB_SKIP_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->txb_skip[tx_size][ctx], &fc->txb_skip[tx_size][ctx],
|
||||
&savings, update, bc);
|
||||
}
|
||||
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane) {
|
||||
for (ctx = 0; ctx < SIG_COEF_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->nz_map[tx_size][plane][ctx],
|
||||
&fc->nz_map[tx_size][plane][ctx], &savings, update, bc);
|
||||
}
|
||||
}
|
||||
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane) {
|
||||
for (ctx = 0; ctx < EOB_COEF_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->eob_flag[tx_size][plane][ctx],
|
||||
&fc->eob_flag[tx_size][plane][ctx], &savings, update, bc);
|
||||
}
|
||||
}
|
||||
|
||||
for (level = 0; level < NUM_BASE_LEVELS; ++level) {
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane) {
|
||||
for (ctx = 0; ctx < COEFF_BASE_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->coeff_base[tx_size][plane][level][ctx],
|
||||
&fc->coeff_base[tx_size][plane][level][ctx], &savings,
|
||||
update, bc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane) {
|
||||
for (ctx = 0; ctx < LEVEL_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->coeff_lps[tx_size][plane][ctx],
|
||||
&fc->coeff_lps[tx_size][plane][ctx], &savings, update, bc);
|
||||
}
|
||||
}
|
||||
|
||||
// Decide if to update the model for this tx_size
|
||||
if (update[1] == 0 || savings < 0) {
|
||||
aom_write_bit(bc, 0);
|
||||
return;
|
||||
}
|
||||
aom_write_bit(bc, 1);
|
||||
|
||||
for (ctx = 0; ctx < TXB_SKIP_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->txb_skip[tx_size][ctx], &fc->txb_skip[tx_size][ctx],
|
||||
&savings, NULL, bc);
|
||||
}
|
||||
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane) {
|
||||
for (ctx = 0; ctx < SIG_COEF_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->nz_map[tx_size][plane][ctx],
|
||||
&fc->nz_map[tx_size][plane][ctx], &savings, NULL, bc);
|
||||
}
|
||||
}
|
||||
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane) {
|
||||
for (ctx = 0; ctx < EOB_COEF_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->eob_flag[tx_size][plane][ctx],
|
||||
&fc->eob_flag[tx_size][plane][ctx], &savings, NULL, bc);
|
||||
}
|
||||
}
|
||||
|
||||
for (level = 0; level < NUM_BASE_LEVELS; ++level) {
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane) {
|
||||
for (ctx = 0; ctx < COEFF_BASE_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->coeff_base[tx_size][plane][level][ctx],
|
||||
&fc->coeff_base[tx_size][plane][level][ctx], &savings,
|
||||
NULL, bc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane) {
|
||||
for (ctx = 0; ctx < LEVEL_CONTEXTS; ++ctx) {
|
||||
find_new_prob(counts->coeff_lps[tx_size][plane][ctx],
|
||||
&fc->coeff_lps[tx_size][plane][ctx], &savings, NULL, bc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av1_write_txb_probs(AV1_COMP *cpi, aom_writer *w) {
|
||||
const TX_MODE tx_mode = cpi->common.tx_mode;
|
||||
const TX_SIZE max_tx_size = tx_mode_to_biggest_tx_size[tx_mode];
|
||||
TX_SIZE tx_size;
|
||||
int ctx, plane;
|
||||
|
||||
for (plane = 0; plane < PLANE_TYPES; ++plane)
|
||||
for (ctx = 0; ctx < DC_SIGN_CONTEXTS; ++ctx)
|
||||
av1_cond_prob_diff_update(w, &cpi->common.fc->dc_sign[plane][ctx],
|
||||
cpi->td.counts->dc_sign[plane][ctx], 1);
|
||||
|
||||
for (tx_size = TX_4X4; tx_size <= max_tx_size; ++tx_size)
|
||||
write_txb_probs(w, cpi, tx_size);
|
||||
}
|
||||
|
||||
#if CONFIG_TXK_SEL
|
||||
int64_t av1_search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane,
|
||||
int block, int blk_row, int blk_col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
|
||||
const ENTROPY_CONTEXT *a, const ENTROPY_CONTEXT *l,
|
||||
int use_fast_coef_costing, RD_STATS *rd_stats) {
|
||||
const AV1_COMMON *cm = &cpi->common;
|
||||
MACROBLOCKD *xd = &x->e_mbd;
|
||||
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
||||
TX_TYPE txk_start = DCT_DCT;
|
||||
TX_TYPE txk_end = TX_TYPES - 1;
|
||||
TX_TYPE best_tx_type = txk_start;
|
||||
int64_t best_rd = INT64_MAX;
|
||||
const int coeff_ctx = combine_entropy_contexts(*a, *l);
|
||||
TX_TYPE tx_type;
|
||||
for (tx_type = txk_start; tx_type <= txk_end; ++tx_type) {
|
||||
if (plane == 0) mbmi->txk_type[block] = tx_type;
|
||||
TX_TYPE ref_tx_type =
|
||||
get_tx_type(get_plane_type(plane), xd, block, tx_size);
|
||||
if (tx_type != ref_tx_type) {
|
||||
// use get_tx_type() to check if the tx_type is valid for the current mode
|
||||
// if it's not, we skip it here.
|
||||
continue;
|
||||
}
|
||||
RD_STATS this_rd_stats;
|
||||
av1_invalid_rd_stats(&this_rd_stats);
|
||||
av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size,
|
||||
coeff_ctx, AV1_XFORM_QUANT_FP);
|
||||
if (x->plane[plane].eobs[block] && !xd->lossless[mbmi->segment_id])
|
||||
av1_optimize_b(cm, x, plane, block, tx_size, coeff_ctx);
|
||||
av1_dist_block(cpi, x, plane, plane_bsize, block, blk_row, blk_col, tx_size,
|
||||
&this_rd_stats.dist, &this_rd_stats.sse,
|
||||
OUTPUT_HAS_PREDICTED_PIXELS);
|
||||
const SCAN_ORDER *scan_order =
|
||||
get_scan(cm, tx_size, tx_type, is_inter_block(mbmi));
|
||||
this_rd_stats.rate = av1_cost_coeffs(
|
||||
cpi, x, plane, block, tx_size, scan_order, a, l, use_fast_coef_costing);
|
||||
int rd =
|
||||
RDCOST(x->rdmult, x->rddiv, this_rd_stats.rate, this_rd_stats.dist);
|
||||
if (rd < best_rd) {
|
||||
best_rd = rd;
|
||||
*rd_stats = this_rd_stats;
|
||||
best_tx_type = tx_type;
|
||||
}
|
||||
}
|
||||
if (plane == 0) mbmi->txk_type[block] = best_tx_type;
|
||||
// TODO(angiebird): Instead of re-call av1_xform_quant and av1_optimize_b,
|
||||
// copy the best result in the above tx_type search for loop
|
||||
av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size,
|
||||
coeff_ctx, AV1_XFORM_QUANT_FP);
|
||||
if (x->plane[plane].eobs[block] && !xd->lossless[mbmi->segment_id])
|
||||
av1_optimize_b(cm, x, plane, block, tx_size, coeff_ctx);
|
||||
if (!is_inter_block(mbmi)) {
|
||||
// intra mode needs decoded result such that the next transform block
|
||||
// can use it for prediction.
|
||||
av1_inverse_transform_block_facade(xd, plane, block, blk_row, blk_col,
|
||||
x->plane[plane].eobs[block]);
|
||||
}
|
||||
return best_rd;
|
||||
}
|
||||
#endif // CONFIG_TXK_SEL
|
||||
53
third_party/aom/av1/encoder/encodetxb.h
vendored
Normal file
53
third_party/aom/av1/encoder/encodetxb.h
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef ENCODETXB_H_
|
||||
#define ENCODETXB_H_
|
||||
|
||||
#include "./aom_config.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/common/txb_common.h"
|
||||
#include "av1/encoder/block.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void av1_alloc_txb_buf(AV1_COMP *cpi);
|
||||
void av1_free_txb_buf(AV1_COMP *cpi);
|
||||
int av1_cost_coeffs_txb(const AV1_COMP *const cpi, MACROBLOCK *x, int plane,
|
||||
int block, TXB_CTX *txb_ctx);
|
||||
void av1_write_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCKD *xd,
|
||||
aom_writer *w, int block, int plane,
|
||||
const tran_low_t *tcoeff, uint16_t eob,
|
||||
TXB_CTX *txb_ctx);
|
||||
void av1_write_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x,
|
||||
aom_writer *w, int plane);
|
||||
int av1_get_txb_entropy_context(const tran_low_t *qcoeff,
|
||||
const SCAN_ORDER *scan_order, int eob);
|
||||
void av1_update_txb_context(const AV1_COMP *cpi, ThreadData *td,
|
||||
RUN_TYPE dry_run, BLOCK_SIZE bsize, int *rate,
|
||||
const int mi_row, const int mi_col);
|
||||
void av1_write_txb_probs(AV1_COMP *cpi, aom_writer *w);
|
||||
|
||||
#if CONFIG_TXK_SEL
|
||||
int64_t av1_search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane,
|
||||
int block, int blk_row, int blk_col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
|
||||
const ENTROPY_CONTEXT *a, const ENTROPY_CONTEXT *l,
|
||||
int use_fast_coef_costing, RD_STATS *rd_stats);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // COEFFS_CODING_H_
|
||||
176
third_party/aom/av1/encoder/ethread.c
vendored
Normal file
176
third_party/aom/av1/encoder/ethread.c
vendored
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "av1/encoder/encodeframe.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/ethread.h"
|
||||
#include "aom_dsp/aom_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];
|
||||
|
||||
#if CONFIG_GLOBAL_MOTION
|
||||
for (i = 0; i < TOTAL_REFS_PER_FRAME; i++)
|
||||
td->rd_counts.global_motion_used[i] +=
|
||||
td_t->rd_counts.global_motion_used[i];
|
||||
#endif // CONFIG_GLOBAL_MOTION
|
||||
|
||||
for (i = 0; i < TX_SIZES; i++)
|
||||
for (j = 0; j < PLANE_TYPES; j++)
|
||||
for (k = 0; k < REF_TYPES; k++)
|
||||
for (l = 0; l < COEF_BANDS; l++)
|
||||
for (m = 0; m < COEFF_CONTEXTS; m++)
|
||||
for (n = 0; n < ENTROPY_TOKENS; n++)
|
||||
td->rd_counts.coef_counts[i][j][k][l][m][n] +=
|
||||
td_t->rd_counts.coef_counts[i][j][k][l][m][n];
|
||||
}
|
||||
|
||||
static int enc_worker_hook(EncWorkerData *const thread_data, void *unused) {
|
||||
AV1_COMP *const cpi = thread_data->cpi;
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = cm->tile_cols;
|
||||
const int tile_rows = cm->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;
|
||||
|
||||
av1_encode_tile(cpi, thread_data->td, tile_row, tile_col);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void av1_encode_tiles_mt(AV1_COMP *cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
const int tile_cols = cm->tile_cols;
|
||||
const AVxWorkerInterface *const winterface = aom_get_worker_interface();
|
||||
const int num_workers = AOMMIN(cpi->oxcf.max_threads, tile_cols);
|
||||
int i;
|
||||
|
||||
av1_init_tile_data(cpi);
|
||||
|
||||
// Only run once to create threads and allocate thread data.
|
||||
if (cpi->num_workers == 0) {
|
||||
CHECK_MEM_ERROR(cm, cpi->workers,
|
||||
aom_malloc(num_workers * sizeof(*cpi->workers)));
|
||||
|
||||
CHECK_MEM_ERROR(cm, cpi->tile_thr_data,
|
||||
aom_calloc(num_workers, sizeof(*cpi->tile_thr_data)));
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = &cpi->tile_thr_data[i];
|
||||
|
||||
++cpi->num_workers;
|
||||
winterface->init(worker);
|
||||
|
||||
thread_data->cpi = cpi;
|
||||
|
||||
if (i < num_workers - 1) {
|
||||
// Allocate thread data.
|
||||
CHECK_MEM_ERROR(cm, thread_data->td,
|
||||
aom_memalign(32, sizeof(*thread_data->td)));
|
||||
av1_zero(*thread_data->td);
|
||||
|
||||
// Set up pc_tree.
|
||||
thread_data->td->leaf_tree = NULL;
|
||||
thread_data->td->pc_tree = NULL;
|
||||
av1_setup_pc_tree(cm, thread_data->td);
|
||||
|
||||
// Set up variance tree if needed.
|
||||
if (cpi->sf.partition_search_type == VAR_BASED_PARTITION)
|
||||
av1_setup_var_tree(cm, thread_data->td);
|
||||
|
||||
// Allocate frame counters in thread data.
|
||||
CHECK_MEM_ERROR(cm, thread_data->td->counts,
|
||||
aom_calloc(1, sizeof(*thread_data->td->counts)));
|
||||
|
||||
// Create threads
|
||||
if (!winterface->reset(worker))
|
||||
aom_internal_error(&cm->error, AOM_CODEC_ERROR,
|
||||
"Tile encoder thread creation failed");
|
||||
} else {
|
||||
// Main thread acts as a worker and uses the thread data in cpi.
|
||||
thread_data->td = &cpi->td;
|
||||
}
|
||||
|
||||
winterface->sync(worker);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *thread_data;
|
||||
|
||||
worker->hook = (AVxWorkerHook)enc_worker_hook;
|
||||
worker->data1 = &cpi->tile_thr_data[i];
|
||||
worker->data2 = NULL;
|
||||
thread_data = (EncWorkerData *)worker->data1;
|
||||
|
||||
// Before encoding a frame, copy the thread data from cpi.
|
||||
if (thread_data->td != &cpi->td) {
|
||||
thread_data->td->mb = cpi->td.mb;
|
||||
thread_data->td->rd_counts = cpi->td.rd_counts;
|
||||
}
|
||||
if (thread_data->td->counts != &cpi->common.counts) {
|
||||
memcpy(thread_data->td->counts, &cpi->common.counts,
|
||||
sizeof(cpi->common.counts));
|
||||
}
|
||||
|
||||
#if CONFIG_PALETTE
|
||||
// Allocate buffers used by palette coding mode.
|
||||
if (cpi->common.allow_screen_content_tools && i < num_workers - 1) {
|
||||
MACROBLOCK *x = &thread_data->td->mb;
|
||||
CHECK_MEM_ERROR(cm, x->palette_buffer,
|
||||
aom_memalign(16, sizeof(*x->palette_buffer)));
|
||||
}
|
||||
#endif // CONFIG_PALETTE
|
||||
}
|
||||
|
||||
// Encode a frame
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
AVxWorker *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++) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
winterface->sync(worker);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_workers; i++) {
|
||||
AVxWorker *const worker = &cpi->workers[i];
|
||||
EncWorkerData *const thread_data = (EncWorkerData *)worker->data1;
|
||||
|
||||
// Accumulate counters.
|
||||
if (i < cpi->num_workers - 1) {
|
||||
av1_accumulate_frame_counts(&cm->counts, thread_data->td->counts);
|
||||
accumulate_rd_opt(&cpi->td, thread_data->td);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
third_party/aom/av1/encoder/ethread.h
vendored
Normal file
34
third_party/aom/av1/encoder/ethread.h
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_ETHREAD_H_
|
||||
#define AV1_ENCODER_ETHREAD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct AV1_COMP;
|
||||
struct ThreadData;
|
||||
|
||||
typedef struct EncWorkerData {
|
||||
struct AV1_COMP *cpi;
|
||||
struct ThreadData *td;
|
||||
int start;
|
||||
} EncWorkerData;
|
||||
|
||||
void av1_encode_tiles_mt(struct AV1_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_ETHREAD_H_
|
||||
192
third_party/aom/av1/encoder/extend.c
vendored
Normal file
192
third_party/aom/av1/encoder/extend.c
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "aom_ports/mem.h"
|
||||
|
||||
#include "av1/common/common.h"
|
||||
#include "av1/encoder/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_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++) {
|
||||
aom_memset16(dst_ptr1, src_ptr1[0], extend_left);
|
||||
memcpy(dst_ptr1 + extend_left, src_ptr1, w * sizeof(src_ptr1[0]));
|
||||
aom_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_HIGHBITDEPTH
|
||||
|
||||
void av1_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 =
|
||||
AOMMAX(src->y_width + 16, ALIGN_POWER_OF_TWO(src->y_width, 6)) -
|
||||
src->y_crop_width;
|
||||
const int eb_y =
|
||||
AOMMAX(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_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_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 av1_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);
|
||||
}
|
||||
32
third_party/aom/av1/encoder/extend.h
vendored
Normal file
32
third_party/aom/av1/encoder/extend.h
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_EXTEND_H_
|
||||
#define AV1_ENCODER_EXTEND_H_
|
||||
|
||||
#include "aom_scale/yv12config.h"
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void av1_copy_and_extend_frame(const YV12_BUFFER_CONFIG *src,
|
||||
YV12_BUFFER_CONFIG *dst);
|
||||
|
||||
void av1_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 // AV1_ENCODER_EXTEND_H_
|
||||
3026
third_party/aom/av1/encoder/firstpass.c
vendored
Normal file
3026
third_party/aom/av1/encoder/firstpass.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
202
third_party/aom/av1/encoder/firstpass.h
vendored
Normal file
202
third_party/aom/av1/encoder/firstpass.h
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_FIRSTPASS_H_
|
||||
#define AV1_ENCODER_FIRSTPASS_H_
|
||||
|
||||
#include "av1/encoder/lookahead.h"
|
||||
#include "av1/encoder/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
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
// Length of the bi-predictive frame group (BFG)
|
||||
// NOTE: Currently each BFG contains one backward ref (BWF) frame plus a certain
|
||||
// number of bi-predictive frames.
|
||||
#define BFG_INTERVAL 2
|
||||
// The maximum number of extra ALT_REF's
|
||||
// NOTE: This number cannot be greater than 2 or the reference frame buffer will
|
||||
// overflow.
|
||||
#define MAX_EXT_ARFS 2
|
||||
#define MIN_EXT_ARF_INTERVAL 4
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
#define VLOW_MOTION_THRESHOLD 950
|
||||
|
||||
typedef struct {
|
||||
double frame;
|
||||
double weight;
|
||||
double intra_error;
|
||||
double coded_error;
|
||||
double sr_coded_error;
|
||||
double pcnt_inter;
|
||||
double pcnt_motion;
|
||||
double pcnt_second_ref;
|
||||
double pcnt_neutral;
|
||||
double intra_skip_pct;
|
||||
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 new_mv_count;
|
||||
double duration;
|
||||
double count;
|
||||
} FIRSTPASS_STATS;
|
||||
|
||||
typedef enum {
|
||||
KF_UPDATE = 0,
|
||||
LF_UPDATE = 1,
|
||||
GF_UPDATE = 2,
|
||||
ARF_UPDATE = 3,
|
||||
OVERLAY_UPDATE = 4,
|
||||
#if CONFIG_EXT_REFS
|
||||
BRF_UPDATE = 5, // Backward Reference Frame
|
||||
LAST_BIPRED_UPDATE = 6, // Last Bi-predictive Frame
|
||||
BIPRED_UPDATE = 7, // Bi-predictive Frame, but not the last one
|
||||
INTNL_OVERLAY_UPDATE = 8, // Internal Overlay Frame
|
||||
FRAME_UPDATE_TYPES = 9
|
||||
#else
|
||||
FRAME_UPDATE_TYPES = 5
|
||||
#endif // CONFIG_EXT_REFS
|
||||
} 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_LAG_BUFFERS * 2) + 1];
|
||||
FRAME_UPDATE_TYPE update_type[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char arf_src_offset[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char arf_update_idx[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char arf_ref_idx[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
#if CONFIG_EXT_REFS
|
||||
unsigned char brf_src_offset[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
unsigned char bidir_pred_enabled[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
#endif // CONFIG_EXT_REFS
|
||||
int bit_allocation[(MAX_LAG_BUFFERS * 2) + 1];
|
||||
} GF_GROUP;
|
||||
|
||||
typedef struct {
|
||||
unsigned int section_intra_rating;
|
||||
FIRSTPASS_STATS total_stats;
|
||||
FIRSTPASS_STATS this_frame_stats;
|
||||
const FIRSTPASS_STATS *stats_in;
|
||||
const FIRSTPASS_STATS *stats_in_start;
|
||||
const FIRSTPASS_STATS *stats_in_end;
|
||||
FIRSTPASS_STATS total_left_stats;
|
||||
int first_pass_done;
|
||||
int64_t bits_left;
|
||||
double modified_error_min;
|
||||
double modified_error_max;
|
||||
double modified_error_left;
|
||||
double mb_av_energy;
|
||||
|
||||
#if CONFIG_FP_MB_STATS
|
||||
uint8_t *frame_mb_stats_buf;
|
||||
uint8_t *this_frame_mb_stats;
|
||||
FIRSTPASS_MB_STATS firstpass_mb_stats;
|
||||
#endif
|
||||
// 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
|
||||
int64_t kf_group_error_left;
|
||||
|
||||
// The fraction for a kf groups total bits allocated to the inter frames
|
||||
double kfgroup_inter_fraction;
|
||||
|
||||
int sr_update_lag;
|
||||
|
||||
int kf_zeromotion_pct;
|
||||
int last_kfgroup_zeromotion_pct;
|
||||
int gf_zeromotion_pct;
|
||||
int active_worst_quality;
|
||||
int baseline_active_worst_quality;
|
||||
int extend_minq;
|
||||
int extend_maxq;
|
||||
int extend_minq_fast;
|
||||
|
||||
GF_GROUP gf_group;
|
||||
} TWO_PASS;
|
||||
|
||||
struct AV1_COMP;
|
||||
|
||||
void av1_init_first_pass(struct AV1_COMP *cpi);
|
||||
void av1_rc_get_first_pass_params(struct AV1_COMP *cpi);
|
||||
void av1_first_pass(struct AV1_COMP *cpi, const struct lookahead_entry *source);
|
||||
void av1_end_first_pass(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_init_second_pass(struct AV1_COMP *cpi);
|
||||
void av1_rc_get_second_pass_params(struct AV1_COMP *cpi);
|
||||
void av1_twopass_postencode_update(struct AV1_COMP *cpi);
|
||||
|
||||
// Post encode update of the rate control parameters for 2-pass
|
||||
void av1_twopass_postencode_update(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_init_subsampling(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_calculate_coded_size(struct AV1_COMP *cpi, int *scaled_frame_width,
|
||||
int *scaled_frame_height);
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
static INLINE int get_number_of_extra_arfs(int interval, int arf_pending) {
|
||||
if (arf_pending && MAX_EXT_ARFS > 0)
|
||||
return interval >= MIN_EXT_ARF_INTERVAL * (MAX_EXT_ARFS + 1)
|
||||
? MAX_EXT_ARFS
|
||||
: interval >= MIN_EXT_ARF_INTERVAL * MAX_EXT_ARFS
|
||||
? MAX_EXT_ARFS - 1
|
||||
: 0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_FIRSTPASS_H_
|
||||
157
third_party/aom/av1/encoder/generic_encoder.c
vendored
Normal file
157
third_party/aom/av1/encoder/generic_encoder.c
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
#include "av1/common/generic_code.h"
|
||||
#include "av1/common/odintrin.h"
|
||||
#include "pvq_encoder.h"
|
||||
|
||||
/** Encodes a value from 0 to N-1 (with N up to 16) based on a cdf and adapts
|
||||
* the cdf accordingly.
|
||||
*
|
||||
* @param [in,out] w multi-symbol entropy encoder
|
||||
* @param [in] val variable being encoded
|
||||
* @param [in,out] cdf CDF of the variable (Q15)
|
||||
* @param [in] n number of values possible
|
||||
* @param [in,out] count number of symbols encoded with that cdf so far
|
||||
* @param [in] rate adaptation rate shift (smaller is faster)
|
||||
*/
|
||||
void aom_encode_cdf_adapt_q15(aom_writer *w, int val, uint16_t *cdf, int n,
|
||||
int *count, int rate) {
|
||||
int i;
|
||||
if (*count == 0) {
|
||||
/* On the first call, we normalize the cdf to (32768 - n). This should
|
||||
eventually be moved to the state init, but for now it makes it much
|
||||
easier to experiment and convert symbols to the Q15 adaptation.*/
|
||||
int ft;
|
||||
ft = cdf[n - 1];
|
||||
for (i = 0; i < n; i++) {
|
||||
cdf[i] = AOM_ICDF(cdf[i]*32768/ft);
|
||||
}
|
||||
}
|
||||
aom_write_cdf(w, val, cdf, n);
|
||||
aom_cdf_adapt_q15(val, cdf, n, count, rate);
|
||||
}
|
||||
|
||||
/** Encodes a random variable using a "generic" model, assuming that the
|
||||
* distribution is one-sided (zero and up), has a single mode, and decays
|
||||
* exponentially past the model.
|
||||
*
|
||||
* @param [in,out] w multi-symbol entropy encoder
|
||||
* @param [in,out] model generic probability model
|
||||
* @param [in] x variable being encoded
|
||||
* @param [in,out] ExQ16 expectation of x (adapted)
|
||||
* @param [in] integration integration period of ExQ16 (leaky average over
|
||||
* 1<<integration samples)
|
||||
*/
|
||||
void generic_encode(aom_writer *w, generic_encoder *model, int x,
|
||||
int *ex_q16, int integration) {
|
||||
int lg_q1;
|
||||
int shift;
|
||||
int id;
|
||||
uint16_t *cdf;
|
||||
int xs;
|
||||
lg_q1 = log_ex(*ex_q16);
|
||||
OD_LOG((OD_LOG_ENTROPY_CODER, OD_LOG_DEBUG,
|
||||
"%d %d", *ex_q16, lg_q1));
|
||||
/* If expectation is too large, shift x to ensure that
|
||||
all we have past xs=15 is the exponentially decaying tail
|
||||
of the distribution */
|
||||
shift = OD_MAXI(0, (lg_q1 - 5) >> 1);
|
||||
/* Choose the cdf to use: we have two per "octave" of ExQ16 */
|
||||
id = OD_MINI(GENERIC_TABLES - 1, lg_q1);
|
||||
cdf = model->cdf[id];
|
||||
xs = (x + (1 << shift >> 1)) >> shift;
|
||||
aom_write_symbol_pvq(w, OD_MINI(15, xs), cdf, 16);
|
||||
if (xs >= 15) {
|
||||
int e;
|
||||
unsigned decay;
|
||||
/* Estimate decay based on the assumption that the distribution is close
|
||||
to Laplacian for large values. We should probably have an adaptive
|
||||
estimate instead. Note: The 2* is a kludge that's not fully understood
|
||||
yet. */
|
||||
OD_ASSERT(*ex_q16 < INT_MAX >> 1);
|
||||
e = ((2**ex_q16 >> 8) + (1 << shift >> 1)) >> shift;
|
||||
decay = OD_MAXI(2, OD_MINI(254, 256*e/(e + 256)));
|
||||
/* Encode the tail of the distribution assuming exponential decay. */
|
||||
aom_laplace_encode_special(w, xs - 15, decay);
|
||||
}
|
||||
if (shift != 0) {
|
||||
int special;
|
||||
/* Because of the rounding, there's only half the number of possibilities
|
||||
for xs=0. */
|
||||
special = xs == 0;
|
||||
if (shift - special > 0) {
|
||||
aom_write_literal(w, x - (xs << shift) + (!special << (shift - 1)),
|
||||
shift - special);
|
||||
}
|
||||
}
|
||||
generic_model_update(ex_q16, x, integration);
|
||||
OD_LOG((OD_LOG_ENTROPY_CODER, OD_LOG_DEBUG,
|
||||
"enc: %d %d %d %d %d %x", *ex_q16, x, shift, id, xs, enc->rng));
|
||||
}
|
||||
|
||||
/** Estimates the cost of encoding a value with generic_encode().
|
||||
*
|
||||
* @param [in,out] model generic probability model
|
||||
* @param [in] x variable being encoded
|
||||
* @param [in,out] ExQ16 expectation of x (adapted)
|
||||
* @return number of bits (approximation)
|
||||
*/
|
||||
double generic_encode_cost(generic_encoder *model, int x, int *ex_q16) {
|
||||
int lg_q1;
|
||||
int shift;
|
||||
int id;
|
||||
uint16_t *cdf;
|
||||
int xs;
|
||||
int extra;
|
||||
lg_q1 = log_ex(*ex_q16);
|
||||
/* If expectation is too large, shift x to ensure that
|
||||
all we have past xs=15 is the exponentially decaying tail
|
||||
of the distribution */
|
||||
shift = OD_MAXI(0, (lg_q1 - 5) >> 1);
|
||||
/* Choose the cdf to use: we have two per "octave" of ExQ16 */
|
||||
id = OD_MINI(GENERIC_TABLES - 1, lg_q1);
|
||||
cdf = model->cdf[id];
|
||||
xs = (x + (1 << shift >> 1)) >> shift;
|
||||
extra = 0;
|
||||
if (shift) extra = shift - (xs == 0);
|
||||
xs = OD_MINI(15, xs);
|
||||
/* Shortcut: assume it's going to cost 2 bits for the Laplace coder. */
|
||||
if (xs == 15) extra += 2;
|
||||
return
|
||||
extra - OD_LOG2((double)(cdf[xs] - (xs == 0 ? 0 : cdf[xs - 1]))/cdf[15]);
|
||||
}
|
||||
|
||||
/*Estimates the cost of encoding a value with a given CDF.*/
|
||||
double od_encode_cdf_cost(int val, uint16_t *cdf, int n) {
|
||||
int total_prob;
|
||||
int prev_prob;
|
||||
double val_prob;
|
||||
OD_ASSERT(n > 0);
|
||||
total_prob = cdf[n - 1];
|
||||
if (val == 0) {
|
||||
prev_prob = 0;
|
||||
}
|
||||
else {
|
||||
prev_prob = cdf[val - 1];
|
||||
}
|
||||
val_prob = (cdf[val] - prev_prob) / (double)total_prob;
|
||||
return -OD_LOG2(val_prob);
|
||||
}
|
||||
319
third_party/aom/av1/encoder/global_motion.c
vendored
Normal file
319
third_party/aom/av1/encoder/global_motion.c
vendored
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "av1/encoder/global_motion.h"
|
||||
|
||||
#include "av1/common/warped_motion.h"
|
||||
|
||||
#include "av1/encoder/segmentation.h"
|
||||
#include "av1/encoder/corner_detect.h"
|
||||
#include "av1/encoder/corner_match.h"
|
||||
#include "av1/encoder/ransac.h"
|
||||
|
||||
#define MAX_CORNERS 4096
|
||||
#define MIN_INLIER_PROB 0.1
|
||||
|
||||
#define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
|
||||
|
||||
// Border over which to compute the global motion
|
||||
#define ERRORADV_BORDER 0
|
||||
|
||||
#define ERRORADV_MAX_THRESH 0.995
|
||||
#define ERRORADV_COST_PRODUCT_THRESH 26000
|
||||
|
||||
int is_enough_erroradvantage(double best_erroradvantage, int params_cost) {
|
||||
return best_erroradvantage < ERRORADV_MAX_THRESH &&
|
||||
best_erroradvantage * params_cost < ERRORADV_COST_PRODUCT_THRESH;
|
||||
}
|
||||
|
||||
static void convert_to_params(const double *params, int32_t *model) {
|
||||
int i;
|
||||
int alpha_present = 0;
|
||||
model[0] = (int32_t)floor(params[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
|
||||
model[1] = (int32_t)floor(params[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
|
||||
model[0] = (int32_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) *
|
||||
GM_TRANS_DECODE_FACTOR;
|
||||
model[1] = (int32_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) *
|
||||
GM_TRANS_DECODE_FACTOR;
|
||||
|
||||
for (i = 2; i < 6; ++i) {
|
||||
const int diag_value = ((i == 2 || i == 5) ? (1 << GM_ALPHA_PREC_BITS) : 0);
|
||||
model[i] = (int32_t)floor(params[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
|
||||
model[i] =
|
||||
(int32_t)clamp(model[i] - diag_value, GM_ALPHA_MIN, GM_ALPHA_MAX);
|
||||
alpha_present |= (model[i] != 0);
|
||||
model[i] = (model[i] + diag_value) * GM_ALPHA_DECODE_FACTOR;
|
||||
}
|
||||
for (; i < 8; ++i) {
|
||||
model[i] = (int32_t)floor(params[i] * (1 << GM_ROW3HOMO_PREC_BITS) + 0.5);
|
||||
model[i] = (int32_t)clamp(model[i], GM_ROW3HOMO_MIN, GM_ROW3HOMO_MAX) *
|
||||
GM_ROW3HOMO_DECODE_FACTOR;
|
||||
alpha_present |= (model[i] != 0);
|
||||
}
|
||||
|
||||
if (!alpha_present) {
|
||||
if (abs(model[0]) < MIN_TRANS_THRESH && abs(model[1]) < MIN_TRANS_THRESH) {
|
||||
model[0] = 0;
|
||||
model[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convert_model_to_params(const double *params, WarpedMotionParams *model) {
|
||||
convert_to_params(params, model->wmmat);
|
||||
model->wmtype = get_gmtype(model);
|
||||
}
|
||||
|
||||
// Adds some offset to a global motion parameter and handles
|
||||
// all of the necessary precision shifts, clamping, and
|
||||
// zero-centering.
|
||||
static int32_t add_param_offset(int param_index, int32_t param_value,
|
||||
int32_t offset) {
|
||||
const int scale_vals[3] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF,
|
||||
GM_ROW3HOMO_PREC_DIFF };
|
||||
const int clamp_vals[3] = { GM_TRANS_MAX, GM_ALPHA_MAX, GM_ROW3HOMO_MAX };
|
||||
// type of param: 0 - translation, 1 - affine, 2 - homography
|
||||
const int param_type = (param_index < 2 ? 0 : (param_index < 6 ? 1 : 2));
|
||||
const int is_one_centered = (param_index == 2 || param_index == 5);
|
||||
|
||||
// Make parameter zero-centered and offset the shift that was done to make
|
||||
// it compatible with the warped model
|
||||
param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
|
||||
scale_vals[param_type];
|
||||
// Add desired offset to the rescaled/zero-centered parameter
|
||||
param_value += offset;
|
||||
// Clamp the parameter so it does not overflow the number of bits allotted
|
||||
// to it in the bitstream
|
||||
param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
|
||||
clamp_vals[param_type]);
|
||||
// Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
|
||||
// with the warped motion library
|
||||
param_value *= (1 << scale_vals[param_type]);
|
||||
|
||||
// Undo the zero-centering step if necessary
|
||||
return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
|
||||
}
|
||||
|
||||
static void force_wmtype(WarpedMotionParams *wm, TransformationType wmtype) {
|
||||
switch (wmtype) {
|
||||
case IDENTITY: wm->wmmat[0] = 0; wm->wmmat[1] = 0;
|
||||
case TRANSLATION:
|
||||
wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS;
|
||||
wm->wmmat[3] = 0;
|
||||
case ROTZOOM: wm->wmmat[4] = -wm->wmmat[3]; wm->wmmat[5] = wm->wmmat[2];
|
||||
case AFFINE: wm->wmmat[6] = wm->wmmat[7] = 0; break;
|
||||
case HORTRAPEZOID: wm->wmmat[6] = wm->wmmat[4] = 0; break;
|
||||
case VERTRAPEZOID: wm->wmmat[7] = wm->wmmat[3] = 0; break;
|
||||
case HOMOGRAPHY: break;
|
||||
default: assert(0);
|
||||
}
|
||||
wm->wmtype = wmtype;
|
||||
}
|
||||
|
||||
double refine_integerized_param(WarpedMotionParams *wm,
|
||||
TransformationType wmtype,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int use_hbd, int bd,
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
uint8_t *ref, int r_width, int r_height,
|
||||
int r_stride, uint8_t *dst, int d_width,
|
||||
int d_height, int d_stride, int n_refinements) {
|
||||
static const int max_trans_model_params[TRANS_TYPES] = {
|
||||
0, 2, 4, 6, 8, 8, 8
|
||||
};
|
||||
const int border = ERRORADV_BORDER;
|
||||
int i = 0, p;
|
||||
int n_params = max_trans_model_params[wmtype];
|
||||
int32_t *param_mat = wm->wmmat;
|
||||
double step_error;
|
||||
int32_t step;
|
||||
int32_t *param;
|
||||
int32_t curr_param;
|
||||
int32_t best_param;
|
||||
double best_error;
|
||||
|
||||
force_wmtype(wm, wmtype);
|
||||
best_error = av1_warp_erroradv(wm,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
use_hbd, bd,
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
ref, r_width, r_height, r_stride,
|
||||
dst + border * d_stride + border, border,
|
||||
border, d_width - 2 * border,
|
||||
d_height - 2 * border, d_stride, 0, 0, 16, 16);
|
||||
step = 1 << (n_refinements + 1);
|
||||
for (i = 0; i < n_refinements; i++, step >>= 1) {
|
||||
for (p = 0; p < n_params; ++p) {
|
||||
int step_dir = 0;
|
||||
// Skip searches for parameters that are forced to be 0
|
||||
if (wmtype == HORTRAPEZOID && (p == 4 || p == 6)) continue;
|
||||
if (wmtype == VERTRAPEZOID && (p == 3 || p == 7)) continue;
|
||||
param = param_mat + p;
|
||||
curr_param = *param;
|
||||
best_param = curr_param;
|
||||
// look to the left
|
||||
*param = add_param_offset(p, curr_param, -step);
|
||||
step_error = av1_warp_erroradv(
|
||||
wm,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
use_hbd, bd,
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
ref, r_width, r_height, r_stride, dst + border * d_stride + border,
|
||||
border, border, d_width - 2 * border, d_height - 2 * border, d_stride,
|
||||
0, 0, 16, 16);
|
||||
if (step_error < best_error) {
|
||||
best_error = step_error;
|
||||
best_param = *param;
|
||||
step_dir = -1;
|
||||
}
|
||||
|
||||
// look to the right
|
||||
*param = add_param_offset(p, curr_param, step);
|
||||
step_error = av1_warp_erroradv(
|
||||
wm,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
use_hbd, bd,
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
ref, r_width, r_height, r_stride, dst + border * d_stride + border,
|
||||
border, border, d_width - 2 * border, d_height - 2 * border, d_stride,
|
||||
0, 0, 16, 16);
|
||||
if (step_error < best_error) {
|
||||
best_error = step_error;
|
||||
best_param = *param;
|
||||
step_dir = 1;
|
||||
}
|
||||
*param = best_param;
|
||||
|
||||
// look to the direction chosen above repeatedly until error increases
|
||||
// for the biggest step size
|
||||
while (step_dir) {
|
||||
*param = add_param_offset(p, best_param, step * step_dir);
|
||||
step_error = av1_warp_erroradv(
|
||||
wm,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
use_hbd, bd,
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
ref, r_width, r_height, r_stride, dst + border * d_stride + border,
|
||||
border, border, d_width - 2 * border, d_height - 2 * border,
|
||||
d_stride, 0, 0, 16, 16);
|
||||
if (step_error < best_error) {
|
||||
best_error = step_error;
|
||||
best_param = *param;
|
||||
} else {
|
||||
*param = best_param;
|
||||
step_dir = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
force_wmtype(wm, wmtype);
|
||||
wm->wmtype = get_gmtype(wm);
|
||||
return best_error;
|
||||
}
|
||||
|
||||
static INLINE RansacFunc get_ransac_type(TransformationType type) {
|
||||
switch (type) {
|
||||
case HOMOGRAPHY: return ransac_homography;
|
||||
case HORTRAPEZOID: return ransac_hortrapezoid;
|
||||
case VERTRAPEZOID: return ransac_vertrapezoid;
|
||||
case AFFINE: return ransac_affine;
|
||||
case ROTZOOM: return ransac_rotzoom;
|
||||
case TRANSLATION: return ransac_translation;
|
||||
default: assert(0); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
static unsigned char *downconvert_frame(YV12_BUFFER_CONFIG *frm,
|
||||
int bit_depth) {
|
||||
int i, j;
|
||||
uint16_t *orig_buf = CONVERT_TO_SHORTPTR(frm->y_buffer);
|
||||
uint8_t *buf = malloc(frm->y_height * frm->y_stride * sizeof(*buf));
|
||||
|
||||
for (i = 0; i < frm->y_height; ++i)
|
||||
for (j = 0; j < frm->y_width; ++j)
|
||||
buf[i * frm->y_stride + j] =
|
||||
orig_buf[i * frm->y_stride + j] >> (bit_depth - 8);
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
int compute_global_motion_feature_based(
|
||||
TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int bit_depth,
|
||||
#endif
|
||||
int *num_inliers_by_motion, double *params_by_motion, int num_motions) {
|
||||
int i;
|
||||
int num_frm_corners, num_ref_corners;
|
||||
int num_correspondences;
|
||||
int *correspondences;
|
||||
int frm_corners[2 * MAX_CORNERS], ref_corners[2 * MAX_CORNERS];
|
||||
unsigned char *frm_buffer = frm->y_buffer;
|
||||
unsigned char *ref_buffer = ref->y_buffer;
|
||||
RansacFunc ransac = get_ransac_type(type);
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
if (frm->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
// The frame buffer is 16-bit, so we need to convert to 8 bits for the
|
||||
// following code. We cache the result until the frame is released.
|
||||
if (frm->y_buffer_8bit)
|
||||
frm_buffer = frm->y_buffer_8bit;
|
||||
else
|
||||
frm_buffer = frm->y_buffer_8bit = downconvert_frame(frm, bit_depth);
|
||||
}
|
||||
if (ref->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
if (ref->y_buffer_8bit)
|
||||
ref_buffer = ref->y_buffer_8bit;
|
||||
else
|
||||
ref_buffer = ref->y_buffer_8bit = downconvert_frame(ref, bit_depth);
|
||||
}
|
||||
#endif
|
||||
|
||||
// compute interest points in images using FAST features
|
||||
num_frm_corners = fast_corner_detect(frm_buffer, frm->y_width, frm->y_height,
|
||||
frm->y_stride, frm_corners, MAX_CORNERS);
|
||||
num_ref_corners = fast_corner_detect(ref_buffer, ref->y_width, ref->y_height,
|
||||
ref->y_stride, ref_corners, MAX_CORNERS);
|
||||
|
||||
// find correspondences between the two images
|
||||
correspondences =
|
||||
(int *)malloc(num_frm_corners * 4 * sizeof(*correspondences));
|
||||
num_correspondences = determine_correspondence(
|
||||
frm_buffer, (int *)frm_corners, num_frm_corners, ref_buffer,
|
||||
(int *)ref_corners, num_ref_corners, frm->y_width, frm->y_height,
|
||||
frm->y_stride, ref->y_stride, correspondences);
|
||||
|
||||
ransac(correspondences, num_correspondences, num_inliers_by_motion,
|
||||
params_by_motion, num_motions);
|
||||
|
||||
free(correspondences);
|
||||
|
||||
// Set num_inliers = 0 for motions with too few inliers so they are ignored.
|
||||
for (i = 0; i < num_motions; ++i) {
|
||||
if (num_inliers_by_motion[i] < MIN_INLIER_PROB * num_correspondences) {
|
||||
num_inliers_by_motion[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if any one of the motions has inliers.
|
||||
for (i = 0; i < num_motions; ++i) {
|
||||
if (num_inliers_by_motion[i] > 0) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
62
third_party/aom/av1/encoder/global_motion.h
vendored
Normal file
62
third_party/aom/av1/encoder/global_motion.h
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_GLOBAL_MOTION_H_
|
||||
#define AV1_ENCODER_GLOBAL_MOTION_H_
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_scale/yv12config.h"
|
||||
#include "av1/common/mv.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RANSAC_NUM_MOTIONS 1
|
||||
|
||||
void convert_model_to_params(const double *params, WarpedMotionParams *model);
|
||||
|
||||
int is_enough_erroradvantage(double erroradv, int params_cost);
|
||||
|
||||
double refine_integerized_param(WarpedMotionParams *wm,
|
||||
TransformationType wmtype,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int use_hbd, int bd,
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
uint8_t *ref, int r_width, int r_height,
|
||||
int r_stride, uint8_t *dst, int d_width,
|
||||
int d_height, int d_stride, int n_refinements);
|
||||
|
||||
/*
|
||||
Computes "num_motions" candidate global motion parameters between two frames.
|
||||
The array "params_by_motion" should be length 8 * "num_motions". The ordering
|
||||
of each set of parameters is best described by the homography:
|
||||
|
||||
[x' (m2 m3 m0 [x
|
||||
z . y' = m4 m5 m1 * y
|
||||
1] m6 m7 1) 1]
|
||||
|
||||
where m{i} represents the ith value in any given set of parameters.
|
||||
|
||||
"num_inliers" should be length "num_motions", and will be populated with the
|
||||
number of inlier feature points for each motion. Params for which the
|
||||
num_inliers entry is 0 should be ignored by the caller.
|
||||
*/
|
||||
int compute_global_motion_feature_based(
|
||||
TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int bit_depth,
|
||||
#endif
|
||||
int *num_inliers_by_motion, double *params_by_motion, int num_motions);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif // AV1_ENCODER_GLOBAL_MOTION_H_
|
||||
499
third_party/aom/av1/encoder/hybrid_fwd_txfm.c
vendored
Normal file
499
third_party/aom/av1/encoder/hybrid_fwd_txfm.c
vendored
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
#include "./aom_config.h"
|
||||
#include "./aom_dsp_rtcd.h"
|
||||
|
||||
#include "av1/common/idct.h"
|
||||
#include "av1/encoder/hybrid_fwd_txfm.h"
|
||||
|
||||
#if CONFIG_CB4X4
|
||||
static void fwd_txfm_2x2(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type, int lossless) {
|
||||
tran_high_t a1 = src_diff[0];
|
||||
tran_high_t b1 = src_diff[1];
|
||||
tran_high_t c1 = src_diff[diff_stride];
|
||||
tran_high_t d1 = src_diff[1 + diff_stride];
|
||||
|
||||
tran_high_t a2 = a1 + c1;
|
||||
tran_high_t b2 = b1 + d1;
|
||||
tran_high_t c2 = a1 - c1;
|
||||
tran_high_t d2 = b1 - d1;
|
||||
|
||||
a1 = a2 + b2;
|
||||
b1 = a2 - b2;
|
||||
c1 = c2 + d2;
|
||||
d1 = c2 - d2;
|
||||
|
||||
coeff[0] = (tran_low_t)(4 * a1);
|
||||
coeff[1] = (tran_low_t)(4 * b1);
|
||||
coeff[2] = (tran_low_t)(4 * c1);
|
||||
coeff[3] = (tran_low_t)(4 * d1);
|
||||
|
||||
(void)tx_type;
|
||||
(void)lossless;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fwd_txfm_4x4(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type, int lossless) {
|
||||
if (lossless) {
|
||||
assert(tx_type == DCT_DCT);
|
||||
av1_fwht4x4(src_diff, coeff, diff_stride);
|
||||
return;
|
||||
}
|
||||
|
||||
av1_fht4x4(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_4x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht4x8(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_8x4(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht8x4(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_8x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht8x16(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_16x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht16x8(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_16x32(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht16x32(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_32x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht32x16(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_8x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht8x8(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_16x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht16x16(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void fwd_txfm_32x32(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
av1_fht32x32(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
#if CONFIG_TX64X64
|
||||
static void fwd_txfm_64x64(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt) {
|
||||
(void)fwd_txfm_opt;
|
||||
#if CONFIG_EXT_TX
|
||||
if (tx_type == IDTX)
|
||||
av1_fwd_idtx_c(src_diff, coeff, diff_stride, 64, tx_type);
|
||||
else
|
||||
#endif
|
||||
av1_fht64x64(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
#endif // CONFIG_TX64X64
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
#if CONFIG_CB4X4
|
||||
static void highbd_fwd_txfm_2x2(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type, int lossless,
|
||||
const int bd) {
|
||||
tran_high_t a1 = src_diff[0];
|
||||
tran_high_t b1 = src_diff[1];
|
||||
tran_high_t c1 = src_diff[diff_stride];
|
||||
tran_high_t d1 = src_diff[1 + diff_stride];
|
||||
|
||||
tran_high_t a2 = a1 + c1;
|
||||
tran_high_t b2 = b1 + d1;
|
||||
tran_high_t c2 = a1 - c1;
|
||||
tran_high_t d2 = b1 - d1;
|
||||
|
||||
a1 = a2 + b2;
|
||||
b1 = a2 - b2;
|
||||
c1 = c2 + d2;
|
||||
d1 = c2 - d2;
|
||||
|
||||
coeff[0] = (tran_low_t)(4 * a1);
|
||||
coeff[1] = (tran_low_t)(4 * b1);
|
||||
coeff[2] = (tran_low_t)(4 * c1);
|
||||
coeff[3] = (tran_low_t)(4 * d1);
|
||||
|
||||
(void)tx_type;
|
||||
(void)lossless;
|
||||
(void)bd;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void highbd_fwd_txfm_4x4(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type, int lossless,
|
||||
const int bd) {
|
||||
if (lossless) {
|
||||
assert(tx_type == DCT_DCT);
|
||||
av1_highbd_fwht4x4(src_diff, coeff, diff_stride);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
case ADST_DCT:
|
||||
case DCT_ADST:
|
||||
case ADST_ADST:
|
||||
av1_fwd_txfm2d_4x4(src_diff, coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
#if CONFIG_EXT_TX
|
||||
case FLIPADST_DCT:
|
||||
case DCT_FLIPADST:
|
||||
case FLIPADST_FLIPADST:
|
||||
case ADST_FLIPADST:
|
||||
case FLIPADST_ADST:
|
||||
av1_fwd_txfm2d_4x4(src_diff, coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
av1_highbd_fht4x4_c(src_diff, coeff, diff_stride, tx_type);
|
||||
break;
|
||||
case IDTX: av1_fwd_idtx_c(src_diff, coeff, diff_stride, 4, tx_type); break;
|
||||
#endif // CONFIG_EXT_TX
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_4x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
(void)bd;
|
||||
av1_highbd_fht4x8(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_8x4(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
(void)bd;
|
||||
av1_highbd_fht8x4(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_8x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
(void)bd;
|
||||
av1_highbd_fht8x16(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_16x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
(void)bd;
|
||||
av1_highbd_fht16x8(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_16x32(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
(void)bd;
|
||||
av1_highbd_fht16x32(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_32x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
(void)bd;
|
||||
av1_highbd_fht32x16(src_diff, coeff, diff_stride, tx_type);
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_8x8(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
case ADST_DCT:
|
||||
case DCT_ADST:
|
||||
case ADST_ADST:
|
||||
av1_fwd_txfm2d_8x8(src_diff, coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
#if CONFIG_EXT_TX
|
||||
case FLIPADST_DCT:
|
||||
case DCT_FLIPADST:
|
||||
case FLIPADST_FLIPADST:
|
||||
case ADST_FLIPADST:
|
||||
case FLIPADST_ADST:
|
||||
av1_fwd_txfm2d_8x8(src_diff, coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
// Use C version since DST exists only in C
|
||||
av1_highbd_fht8x8_c(src_diff, coeff, diff_stride, tx_type);
|
||||
break;
|
||||
case IDTX: av1_fwd_idtx_c(src_diff, coeff, diff_stride, 8, tx_type); break;
|
||||
#endif // CONFIG_EXT_TX
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_16x16(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
case ADST_DCT:
|
||||
case DCT_ADST:
|
||||
case ADST_ADST:
|
||||
av1_fwd_txfm2d_16x16(src_diff, coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
#if CONFIG_EXT_TX
|
||||
case FLIPADST_DCT:
|
||||
case DCT_FLIPADST:
|
||||
case FLIPADST_FLIPADST:
|
||||
case ADST_FLIPADST:
|
||||
case FLIPADST_ADST:
|
||||
av1_fwd_txfm2d_16x16(src_diff, coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
// Use C version since DST exists only in C
|
||||
av1_highbd_fht16x16_c(src_diff, coeff, diff_stride, tx_type);
|
||||
break;
|
||||
case IDTX: av1_fwd_idtx_c(src_diff, coeff, diff_stride, 16, tx_type); break;
|
||||
#endif // CONFIG_EXT_TX
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_fwd_txfm_32x32(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
av1_fwd_txfm2d_32x32(src_diff, coeff, diff_stride, tx_type, bd);
|
||||
break;
|
||||
#if CONFIG_EXT_TX
|
||||
case ADST_DCT:
|
||||
case DCT_ADST:
|
||||
case ADST_ADST:
|
||||
case FLIPADST_DCT:
|
||||
case DCT_FLIPADST:
|
||||
case FLIPADST_FLIPADST:
|
||||
case ADST_FLIPADST:
|
||||
case FLIPADST_ADST:
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
av1_highbd_fht32x32_c(src_diff, coeff, diff_stride, tx_type);
|
||||
break;
|
||||
case IDTX: av1_fwd_idtx_c(src_diff, coeff, diff_stride, 32, tx_type); break;
|
||||
#endif // CONFIG_EXT_TX
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_TX64X64
|
||||
static void highbd_fwd_txfm_64x64(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TX_TYPE tx_type,
|
||||
FWD_TXFM_OPT fwd_txfm_opt, const int bd) {
|
||||
(void)fwd_txfm_opt;
|
||||
(void)bd;
|
||||
switch (tx_type) {
|
||||
case DCT_DCT:
|
||||
av1_highbd_fht64x64(src_diff, coeff, diff_stride, tx_type);
|
||||
break;
|
||||
#if CONFIG_EXT_TX
|
||||
case ADST_DCT:
|
||||
case DCT_ADST:
|
||||
case ADST_ADST:
|
||||
case FLIPADST_DCT:
|
||||
case DCT_FLIPADST:
|
||||
case FLIPADST_FLIPADST:
|
||||
case ADST_FLIPADST:
|
||||
case FLIPADST_ADST:
|
||||
case V_DCT:
|
||||
case H_DCT:
|
||||
case V_ADST:
|
||||
case H_ADST:
|
||||
case V_FLIPADST:
|
||||
case H_FLIPADST:
|
||||
av1_highbd_fht64x64(src_diff, coeff, diff_stride, tx_type);
|
||||
break;
|
||||
case IDTX: av1_fwd_idtx_c(src_diff, coeff, diff_stride, 64, tx_type); break;
|
||||
#endif // CONFIG_EXT_TX
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_TX64X64
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
|
||||
void av1_fwd_txfm(const int16_t *src_diff, tran_low_t *coeff, int diff_stride,
|
||||
FWD_TXFM_PARAM *fwd_txfm_param) {
|
||||
const int fwd_txfm_opt = FWD_TXFM_OPT_NORMAL;
|
||||
const TX_TYPE tx_type = fwd_txfm_param->tx_type;
|
||||
const TX_SIZE tx_size = fwd_txfm_param->tx_size;
|
||||
const int lossless = fwd_txfm_param->lossless;
|
||||
switch (tx_size) {
|
||||
#if CONFIG_TX64X64
|
||||
case TX_64X64:
|
||||
fwd_txfm_64x64(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
#endif // CONFIG_TX64X64
|
||||
case TX_32X32:
|
||||
fwd_txfm_32x32(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_16X16:
|
||||
fwd_txfm_16x16(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_8X8:
|
||||
fwd_txfm_8x8(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_4X8:
|
||||
fwd_txfm_4x8(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_8X4:
|
||||
fwd_txfm_8x4(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_8X16:
|
||||
fwd_txfm_8x16(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_16X8:
|
||||
fwd_txfm_16x8(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_16X32:
|
||||
fwd_txfm_16x32(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_32X16:
|
||||
fwd_txfm_32x16(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt);
|
||||
break;
|
||||
case TX_4X4:
|
||||
fwd_txfm_4x4(src_diff, coeff, diff_stride, tx_type, lossless);
|
||||
break;
|
||||
#if CONFIG_CB4X4
|
||||
case TX_2X2:
|
||||
fwd_txfm_2x2(src_diff, coeff, diff_stride, tx_type, lossless);
|
||||
break;
|
||||
#endif
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
void av1_highbd_fwd_txfm(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, FWD_TXFM_PARAM *fwd_txfm_param) {
|
||||
const int fwd_txfm_opt = FWD_TXFM_OPT_NORMAL;
|
||||
const TX_TYPE tx_type = fwd_txfm_param->tx_type;
|
||||
const TX_SIZE tx_size = fwd_txfm_param->tx_size;
|
||||
const int lossless = fwd_txfm_param->lossless;
|
||||
const int bd = fwd_txfm_param->bd;
|
||||
switch (tx_size) {
|
||||
#if CONFIG_TX64X64
|
||||
case TX_64X64:
|
||||
highbd_fwd_txfm_64x64(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
#endif // CONFIG_TX64X64
|
||||
case TX_32X32:
|
||||
highbd_fwd_txfm_32x32(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_16X16:
|
||||
highbd_fwd_txfm_16x16(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_8X8:
|
||||
highbd_fwd_txfm_8x8(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_4X8:
|
||||
highbd_fwd_txfm_4x8(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_8X4:
|
||||
highbd_fwd_txfm_8x4(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_8X16:
|
||||
highbd_fwd_txfm_8x16(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_16X8:
|
||||
highbd_fwd_txfm_16x8(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_16X32:
|
||||
highbd_fwd_txfm_16x32(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_32X16:
|
||||
highbd_fwd_txfm_32x16(src_diff, coeff, diff_stride, tx_type, fwd_txfm_opt,
|
||||
bd);
|
||||
break;
|
||||
case TX_4X4:
|
||||
highbd_fwd_txfm_4x4(src_diff, coeff, diff_stride, tx_type, lossless, bd);
|
||||
break;
|
||||
#if CONFIG_CB4X4
|
||||
case TX_2X2:
|
||||
highbd_fwd_txfm_2x2(src_diff, coeff, diff_stride, tx_type, lossless, bd);
|
||||
break;
|
||||
#endif
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
44
third_party/aom/av1/encoder/hybrid_fwd_txfm.h
vendored
Normal file
44
third_party/aom/av1/encoder/hybrid_fwd_txfm.h
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_HYBRID_FWD_TXFM_H_
|
||||
#define AV1_ENCODER_HYBRID_FWD_TXFM_H_
|
||||
|
||||
#include "./aom_config.h"
|
||||
|
||||
typedef enum FWD_TXFM_OPT { FWD_TXFM_OPT_NORMAL } FWD_TXFM_OPT;
|
||||
|
||||
typedef struct FWD_TXFM_PARAM {
|
||||
TX_TYPE tx_type;
|
||||
TX_SIZE tx_size;
|
||||
int lossless;
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int bd;
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
} FWD_TXFM_PARAM;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void av1_fwd_txfm(const int16_t *src_diff, tran_low_t *coeff, int diff_stride,
|
||||
FWD_TXFM_PARAM *fwd_txfm_param);
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
void av1_highbd_fwd_txfm(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, FWD_TXFM_PARAM *fwd_txfm_param);
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_HYBRID_FWD_TXFM_H_
|
||||
107
third_party/aom/av1/encoder/laplace_encoder.c
vendored
Normal file
107
third_party/aom/av1/encoder/laplace_encoder.c
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
#include "av1/common/odintrin.h"
|
||||
#include "av1/common/pvq.h"
|
||||
#include "pvq_encoder.h"
|
||||
|
||||
static void aom_encode_pvq_split(aom_writer *w, od_pvq_codeword_ctx *adapt,
|
||||
int count, int sum, int ctx) {
|
||||
int shift;
|
||||
int rest;
|
||||
int fctx;
|
||||
if (sum == 0) return;
|
||||
shift = OD_MAXI(0, OD_ILOG(sum) - 3);
|
||||
if (shift) {
|
||||
rest = count & ((1 << shift) - 1);
|
||||
count >>= shift;
|
||||
sum >>= shift;
|
||||
}
|
||||
fctx = 7*ctx + sum - 1;
|
||||
aom_write_symbol_pvq(w, count, adapt->pvq_split_cdf[fctx], sum + 1);
|
||||
if (shift) aom_write_literal(w, rest, shift);
|
||||
}
|
||||
|
||||
void aom_encode_band_pvq_splits(aom_writer *w, od_pvq_codeword_ctx *adapt,
|
||||
const int *y, int n, int k, int level) {
|
||||
int mid;
|
||||
int i;
|
||||
int count_right;
|
||||
if (n <= 1 || k == 0) return;
|
||||
if (k == 1 && n <= 16) {
|
||||
int cdf_id;
|
||||
int pos;
|
||||
cdf_id = od_pvq_k1_ctx(n, level == 0);
|
||||
for (pos = 0; !y[pos]; pos++);
|
||||
OD_ASSERT(pos < n);
|
||||
aom_write_symbol_pvq(w, pos, adapt->pvq_k1_cdf[cdf_id], n);
|
||||
}
|
||||
else {
|
||||
mid = n >> 1;
|
||||
count_right = k;
|
||||
for (i = 0; i < mid; i++) count_right -= abs(y[i]);
|
||||
aom_encode_pvq_split(w, adapt, count_right, k, od_pvq_size_ctx(n));
|
||||
aom_encode_band_pvq_splits(w, adapt, y, mid, k - count_right, level + 1);
|
||||
aom_encode_band_pvq_splits(w, adapt, y + mid, n - mid, count_right,
|
||||
level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Encodes the tail of a Laplace-distributed variable, i.e. it doesn't
|
||||
* do anything special for the zero case.
|
||||
*
|
||||
* @param [in,out] enc range encoder
|
||||
* @param [in] x variable to encode (has to be positive)
|
||||
* @param [in] decay decay factor of the distribution in Q8 format,
|
||||
* i.e. pdf ~= decay^x
|
||||
*/
|
||||
void aom_laplace_encode_special(aom_writer *w, int x, unsigned decay) {
|
||||
int shift;
|
||||
int xs;
|
||||
int sym;
|
||||
const uint16_t *cdf;
|
||||
shift = 0;
|
||||
/* We don't want a large decay value because that would require too many
|
||||
symbols. */
|
||||
while (decay > 235) {
|
||||
decay = (decay*decay + 128) >> 8;
|
||||
shift++;
|
||||
}
|
||||
decay = OD_MINI(decay, 254);
|
||||
decay = OD_MAXI(decay, 2);
|
||||
xs = x >> shift;
|
||||
cdf = EXP_CDF_TABLE[(decay + 1) >> 1];
|
||||
OD_LOG((OD_LOG_PVQ, OD_LOG_DEBUG, "decay = %d", decay));
|
||||
do {
|
||||
sym = OD_MINI(xs, 15);
|
||||
{
|
||||
int i;
|
||||
OD_LOG((OD_LOG_PVQ, OD_LOG_DEBUG, "%d %d %d %d %d\n", x, xs, shift,
|
||||
sym, max));
|
||||
for (i = 0; i < 16; i++) {
|
||||
OD_LOG_PARTIAL((OD_LOG_PVQ, OD_LOG_DEBUG, "%d ", cdf[i]));
|
||||
}
|
||||
OD_LOG_PARTIAL((OD_LOG_PVQ, OD_LOG_DEBUG, "\n"));
|
||||
}
|
||||
aom_write_cdf(w, sym, cdf, 16);
|
||||
xs -= 15;
|
||||
} while (sym >= 15);
|
||||
if (shift) aom_write_literal(w, x & ((1 << shift) - 1), shift);
|
||||
}
|
||||
225
third_party/aom/av1/encoder/lookahead.c
vendored
Normal file
225
third_party/aom/av1/encoder/lookahead.c
vendored
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./aom_config.h"
|
||||
|
||||
#include "av1/common/common.h"
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/extend.h"
|
||||
#include "av1/encoder/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 av1_lookahead_destroy(struct lookahead_ctx *ctx) {
|
||||
if (ctx) {
|
||||
if (ctx->buf) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ctx->max_sz; i++) aom_free_frame_buffer(&ctx->buf[i].img);
|
||||
free(ctx->buf);
|
||||
}
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
struct lookahead_ctx *av1_lookahead_init(unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int subsampling_x,
|
||||
unsigned int subsampling_y,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
unsigned int depth) {
|
||||
struct lookahead_ctx *ctx = NULL;
|
||||
|
||||
// Clamp the lookahead queue depth
|
||||
depth = clamp(depth, 1, MAX_LAG_BUFFERS);
|
||||
|
||||
// Allocate memory to keep previous source frames available.
|
||||
depth += MAX_PRE_FRAMES;
|
||||
|
||||
// Allocate the lookahead structures
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx) {
|
||||
const int legacy_byte_alignment = 0;
|
||||
unsigned int i;
|
||||
ctx->max_sz = depth;
|
||||
ctx->buf = calloc(depth, sizeof(*ctx->buf));
|
||||
if (!ctx->buf) goto bail;
|
||||
for (i = 0; i < depth; i++)
|
||||
if (aom_alloc_frame_buffer(&ctx->buf[i].img, width, height, subsampling_x,
|
||||
subsampling_y,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
use_highbitdepth,
|
||||
#endif
|
||||
AOM_BORDER_IN_PIXELS, legacy_byte_alignment))
|
||||
goto bail;
|
||||
}
|
||||
return ctx;
|
||||
bail:
|
||||
av1_lookahead_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define USE_PARTIAL_COPY 0
|
||||
|
||||
int av1_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
|
||||
int64_t ts_start, int64_t ts_end,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
aom_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 (ctx->sz + 1 + MAX_PRE_FRAMES > ctx->max_sz) return 1;
|
||||
ctx->sz++;
|
||||
buf = pop(ctx, &ctx->write_idx);
|
||||
|
||||
new_dimensions = width != buf->img.y_crop_width ||
|
||||
height != buf->img.y_crop_height ||
|
||||
uv_width != buf->img.uv_crop_width ||
|
||||
uv_height != buf->img.uv_crop_height;
|
||||
larger_dimensions = width > buf->img.y_width || height > buf->img.y_height ||
|
||||
uv_width > buf->img.uv_width ||
|
||||
uv_height > buf->img.uv_height;
|
||||
assert(!larger_dimensions || new_dimensions);
|
||||
|
||||
#if USE_PARTIAL_COPY
|
||||
// TODO(jkoleszar): This is disabled for now, as
|
||||
// av1_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.
|
||||
av1_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 (aom_alloc_frame_buffer(&new_img, width, height, subsampling_x,
|
||||
subsampling_y,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
use_highbitdepth,
|
||||
#endif
|
||||
AOM_BORDER_IN_PIXELS, 0))
|
||||
return 1;
|
||||
aom_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
|
||||
av1_copy_and_extend_frame(src, &buf->img);
|
||||
#if USE_PARTIAL_COPY
|
||||
}
|
||||
#endif
|
||||
|
||||
buf->ts_start = ts_start;
|
||||
buf->ts_end = ts_end;
|
||||
buf->flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lookahead_entry *av1_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 *av1_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 += (int)(ctx->read_idx);
|
||||
if (index < 0) index += (int)(ctx->max_sz);
|
||||
buf = ctx->buf + index;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
unsigned int av1_lookahead_depth(struct lookahead_ctx *ctx) { return ctx->sz; }
|
||||
114
third_party/aom/av1/encoder/lookahead.h
vendored
Normal file
114
third_party/aom/av1/encoder/lookahead.h
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_LOOKAHEAD_H_
|
||||
#define AV1_ENCODER_LOOKAHEAD_H_
|
||||
|
||||
#include "aom_scale/yv12config.h"
|
||||
#include "aom/aom_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;
|
||||
aom_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 */
|
||||
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 *av1_lookahead_init(unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int subsampling_x,
|
||||
unsigned int subsampling_y,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
unsigned int depth);
|
||||
|
||||
/**\brief Destroys the lookahead stage
|
||||
*/
|
||||
void av1_lookahead_destroy(struct lookahead_ctx *ctx);
|
||||
|
||||
/**\brief Enqueue a source buffer
|
||||
*
|
||||
* This function will copy the source image into a new framebuffer with
|
||||
* the expected stride/border.
|
||||
*
|
||||
* If active_map is non-NULL and there is only one frame in the queue, then copy
|
||||
* only active macroblocks.
|
||||
*
|
||||
* \param[in] ctx Pointer to the lookahead context
|
||||
* \param[in] src Pointer to the image to enqueue
|
||||
* \param[in] ts_start Timestamp for the start of this frame
|
||||
* \param[in] ts_end Timestamp for the end of this frame
|
||||
* \param[in] flags Flags set on this frame
|
||||
* \param[in] active_map Map that specifies which macroblock is active
|
||||
*/
|
||||
int av1_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
|
||||
int64_t ts_start, int64_t ts_end,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int use_highbitdepth,
|
||||
#endif
|
||||
aom_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 *av1_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 *av1_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 av1_lookahead_depth(struct lookahead_ctx *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_LOOKAHEAD_H_
|
||||
398
third_party/aom/av1/encoder/mbgraph.c
vendored
Normal file
398
third_party/aom/av1/encoder/mbgraph.c
vendored
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
#include "./aom_dsp_rtcd.h"
|
||||
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "aom_ports/system_state.h"
|
||||
#include "av1/encoder/segmentation.h"
|
||||
#include "av1/encoder/mcomp.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/reconinter.h"
|
||||
#include "av1/common/reconintra.h"
|
||||
|
||||
static unsigned int do_16x16_motion_iteration(AV1_COMP *cpi, const MV *ref_mv,
|
||||
int mb_row, int mb_col) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
const MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv;
|
||||
const aom_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 = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 2);
|
||||
|
||||
av1_set_mv_search_range(&x->mv_limits, ref_mv);
|
||||
|
||||
ref_full.col = ref_mv->col >> 3;
|
||||
ref_full.row = ref_mv->row >> 3;
|
||||
|
||||
/*cpi->sf.search_method == HEX*/
|
||||
av1_hex_search(x, &ref_full, step_param, x->errorperbit, 0,
|
||||
cond_cost_list(cpi, cost_list), &v_fn_ptr, 0, ref_mv);
|
||||
|
||||
// Try sub-pixel MC
|
||||
// if (bestsme > error_thresh && bestsme < INT_MAX)
|
||||
{
|
||||
int distortion;
|
||||
unsigned int sse;
|
||||
cpi->find_fractional_mv_step(x, ref_mv, cpi->common.allow_high_precision_mv,
|
||||
x->errorperbit, &v_fn_ptr, 0,
|
||||
mv_sf->subpel_iters_per_step,
|
||||
cond_cost_list(cpi, cost_list), NULL, NULL,
|
||||
&distortion, &sse, NULL, 0, 0, 0);
|
||||
}
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
if (has_second_ref(&xd->mi[0]->mbmi))
|
||||
xd->mi[0]->mbmi.mode = NEW_NEWMV;
|
||||
else
|
||||
#endif // CONFIG_EXT_INTER
|
||||
xd->mi[0]->mbmi.mode = NEWMV;
|
||||
|
||||
xd->mi[0]->mbmi.mv[0] = x->best_mv;
|
||||
#if CONFIG_EXT_INTER
|
||||
xd->mi[0]->mbmi.ref_frame[1] = NONE_FRAME;
|
||||
#endif // CONFIG_EXT_INTER
|
||||
|
||||
av1_build_inter_predictors_sby(xd, mb_row, mb_col, NULL, BLOCK_16X16);
|
||||
|
||||
/* restore UMV window */
|
||||
x->mv_limits = tmp_mv_limits;
|
||||
|
||||
return aom_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(AV1_COMP *cpi, const MV *ref_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 best_mv;
|
||||
|
||||
// Try zero MV first
|
||||
// FIXME should really use something like near/nearest MV and/or MV prediction
|
||||
err = aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
|
||||
xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);
|
||||
best_mv.col = best_mv.row = 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, mb_row, mb_col);
|
||||
if (tmp_err < err) {
|
||||
err = tmp_err;
|
||||
best_mv = x->best_mv.as_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) {
|
||||
MV zero_ref_mv = { 0, 0 };
|
||||
|
||||
tmp_err = do_16x16_motion_iteration(cpi, &zero_ref_mv, mb_row, mb_col);
|
||||
if (tmp_err < err) {
|
||||
err = tmp_err;
|
||||
best_mv = x->best_mv.as_mv;
|
||||
}
|
||||
}
|
||||
|
||||
x->best_mv.as_mv = best_mv;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_16x16_zerozero_search(AV1_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 = aom_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(AV1_COMP *cpi, PREDICTION_MODE *pbest_mode) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
PREDICTION_MODE best_mode = -1, mode;
|
||||
unsigned int best_err = INT_MAX;
|
||||
|
||||
// calculate SATD for each intra prediction mode;
|
||||
// we're intentionally not doing 4x4, we just want a rough estimate
|
||||
for (mode = DC_PRED; mode <= TM_PRED; mode++) {
|
||||
unsigned int err;
|
||||
|
||||
xd->mi[0]->mbmi.mode = mode;
|
||||
av1_predict_intra_block(xd, 16, 16, BLOCK_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 = aom_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(AV1_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;
|
||||
AV1_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, mb_row, mb_col);
|
||||
stats->ref[GOLDEN_FRAME].m.mv = x->best_mv;
|
||||
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(AV1_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;
|
||||
AV1_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;
|
||||
|
||||
av1_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;
|
||||
xd->up_available = 0;
|
||||
xd->plane[0].dst.stride = buf->y_stride;
|
||||
xd->plane[0].pre[0].stride = buf->y_stride;
|
||||
xd->plane[1].dst.stride = buf->uv_stride;
|
||||
xd->mi[0] = &mi_local;
|
||||
mi_local.mbmi.sb_type = BLOCK_16X16;
|
||||
mi_local.mbmi.ref_frame[0] = LAST_FRAME;
|
||||
mi_local.mbmi.ref_frame[1] = NONE_FRAME;
|
||||
|
||||
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;
|
||||
xd->left_available = 0;
|
||||
|
||||
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
|
||||
MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col];
|
||||
|
||||
update_mbgraph_mb_stats(cpi, mb_stats, buf, mb_y_in_offset, golden_ref,
|
||||
&gld_left_mv, alt_ref, mb_row, mb_col);
|
||||
gld_left_mv = mb_stats->ref[GOLDEN_FRAME].m.mv.as_mv;
|
||||
if (mb_col == 0) {
|
||||
gld_top_mv = gld_left_mv;
|
||||
}
|
||||
xd->left_available = 1;
|
||||
mb_y_in_offset += 16;
|
||||
gld_y_in_offset += 16;
|
||||
arf_y_in_offset += 16;
|
||||
x->mv_limits.col_min -= 16;
|
||||
x->mv_limits.col_max -= 16;
|
||||
}
|
||||
xd->up_available = 1;
|
||||
mb_y_offset += buf->y_stride * 16;
|
||||
gld_y_offset += golden_ref->y_stride * 16;
|
||||
if (alt_ref) arf_y_offset += alt_ref->y_stride * 16;
|
||||
x->mv_limits.row_min -= 16;
|
||||
x->mv_limits.row_max -= 16;
|
||||
offset += cm->mb_cols;
|
||||
}
|
||||
}
|
||||
|
||||
// void separate_arf_mbs_byzz
|
||||
static void separate_arf_mbs(AV1_COMP *cpi) {
|
||||
AV1_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,
|
||||
aom_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;
|
||||
|
||||
av1_enable_segmentation(&cm->seg);
|
||||
} else {
|
||||
cpi->static_mb_pct = 0;
|
||||
av1_disable_segmentation(&cm->seg);
|
||||
}
|
||||
|
||||
// Free localy allocated storage
|
||||
aom_free(arf_not_zz);
|
||||
}
|
||||
|
||||
void av1_update_mbgraph_stats(AV1_COMP *cpi) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
int i, n_frames = av1_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 = av1_lookahead_peek(cpi->lookahead, i);
|
||||
|
||||
assert(q_cur != NULL);
|
||||
|
||||
update_mbgraph_frame_stats(cpi, frame_stats, &q_cur->img, golden_ref,
|
||||
cpi->source);
|
||||
}
|
||||
|
||||
aom_clear_system_state();
|
||||
|
||||
separate_arf_mbs(cpi);
|
||||
}
|
||||
39
third_party/aom/av1/encoder/mbgraph.h
vendored
Normal file
39
third_party/aom/av1/encoder/mbgraph.h
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_MBGRAPH_H_
|
||||
#define AV1_ENCODER_MBGRAPH_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
int err;
|
||||
union {
|
||||
int_mv mv;
|
||||
PREDICTION_MODE mode;
|
||||
} m;
|
||||
} ref[TOTAL_REFS_PER_FRAME];
|
||||
} MBGRAPH_MB_STATS;
|
||||
|
||||
typedef struct { MBGRAPH_MB_STATS *mb_stats; } MBGRAPH_FRAME_STATS;
|
||||
|
||||
struct AV1_COMP;
|
||||
|
||||
void av1_update_mbgraph_stats(struct AV1_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_MBGRAPH_H_
|
||||
3493
third_party/aom/av1/encoder/mcomp.c
vendored
Normal file
3493
third_party/aom/av1/encoder/mcomp.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
163
third_party/aom/av1/encoder/mcomp.h
vendored
Normal file
163
third_party/aom/av1/encoder/mcomp.h
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_MCOMP_H_
|
||||
#define AV1_ENCODER_MCOMP_H_
|
||||
|
||||
#include "av1/encoder/block.h"
|
||||
#include "aom_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 + AOM_INTERP_EXTEND)
|
||||
|
||||
// motion search site
|
||||
typedef struct search_site {
|
||||
MV mv;
|
||||
int offset;
|
||||
} search_site;
|
||||
|
||||
typedef struct search_site_config {
|
||||
search_site ss[8 * MAX_MVSEARCH_STEPS + 1];
|
||||
int ss_count;
|
||||
int searches_per_step;
|
||||
} search_site_config;
|
||||
|
||||
void av1_init_dsmotion_compensation(search_site_config *cfg, int stride);
|
||||
void av1_init3smotion_compensation(search_site_config *cfg, int stride);
|
||||
|
||||
void av1_set_mv_search_range(MvLimits *mv_limits, const MV *mv);
|
||||
|
||||
int av1_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 av1_get_mvpred_var(const MACROBLOCK *x, const MV *best_mv,
|
||||
const MV *center_mv, const aom_variance_fn_ptr_t *vfp,
|
||||
int use_mvcost);
|
||||
int av1_get_mvpred_av_var(const MACROBLOCK *x, const MV *best_mv,
|
||||
const MV *center_mv, const uint8_t *second_pred,
|
||||
const aom_variance_fn_ptr_t *vfp, int use_mvcost);
|
||||
|
||||
struct AV1_COMP;
|
||||
struct SPEED_FEATURES;
|
||||
|
||||
int av1_init_search_range(int size);
|
||||
|
||||
int av1_refining_search_sad(struct macroblock *x, struct mv *ref_mv,
|
||||
int sad_per_bit, int distance,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const struct mv *center_mv);
|
||||
|
||||
// Runs sequence of diamond searches in smaller steps for RD.
|
||||
int av1_full_pixel_diamond(const struct AV1_COMP *cpi, MACROBLOCK *x,
|
||||
MV *mvp_full, int step_param, int sadpb,
|
||||
int further_steps, int do_refine, int *cost_list,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *ref_mv, MV *dst_mv);
|
||||
|
||||
// Perform integral projection based motion estimation.
|
||||
unsigned int av1_int_pro_motion_estimation(const struct AV1_COMP *cpi,
|
||||
MACROBLOCK *x, BLOCK_SIZE bsize,
|
||||
int mi_row, int mi_col);
|
||||
|
||||
int av1_hex_search(MACROBLOCK *x, MV *start_mv, int search_param,
|
||||
int sad_per_bit, int do_init_search, int *cost_list,
|
||||
const aom_variance_fn_ptr_t *vfp, int use_mvcost,
|
||||
const MV *center_mv);
|
||||
|
||||
typedef int(fractional_mv_step_fp)(
|
||||
MACROBLOCK *x, const MV *ref_mv, int allow_hp, int error_per_bit,
|
||||
const aom_variance_fn_ptr_t *vfp,
|
||||
int forced_stop, // 0 - full, 1 - qtr only, 2 - half only
|
||||
int iters_per_step, int *cost_list, int *mvjcost, int *mvcost[2],
|
||||
int *distortion, unsigned int *sse1, const uint8_t *second_pred, int w,
|
||||
int h, int use_upsampled_ref);
|
||||
|
||||
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree;
|
||||
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned;
|
||||
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned_more;
|
||||
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned_evenmore;
|
||||
extern fractional_mv_step_fp av1_return_max_sub_pixel_mv;
|
||||
extern fractional_mv_step_fp av1_return_min_sub_pixel_mv;
|
||||
|
||||
typedef int (*av1_full_search_fn_t)(const MACROBLOCK *x, const MV *ref_mv,
|
||||
int sad_per_bit, int distance,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv, MV *best_mv);
|
||||
|
||||
typedef int (*av1_diamond_search_fn_t)(
|
||||
MACROBLOCK *x, const search_site_config *cfg, MV *ref_mv, MV *best_mv,
|
||||
int search_param, int sad_per_bit, int *num00,
|
||||
const aom_variance_fn_ptr_t *fn_ptr, const MV *center_mv);
|
||||
|
||||
int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *center_mv, const uint8_t *second_pred);
|
||||
|
||||
struct AV1_COMP;
|
||||
|
||||
int av1_full_pixel_search(const struct AV1_COMP *cpi, MACROBLOCK *x,
|
||||
BLOCK_SIZE bsize, MV *mvp_full, int step_param,
|
||||
int error_per_bit, int *cost_list, const MV *ref_mv,
|
||||
int var_max, int rd);
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
int av1_find_best_masked_sub_pixel_tree(
|
||||
const MACROBLOCK *x, const uint8_t *mask, int mask_stride, MV *bestmv,
|
||||
const MV *ref_mv, int allow_hp, int error_per_bit,
|
||||
const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step,
|
||||
int *mvjcost, int *mvcost[2], int *distortion, unsigned int *sse1,
|
||||
int is_second);
|
||||
int av1_find_best_masked_sub_pixel_tree_up(
|
||||
const struct AV1_COMP *cpi, MACROBLOCK *x, const uint8_t *mask,
|
||||
int mask_stride, int mi_row, int mi_col, MV *bestmv, const MV *ref_mv,
|
||||
int allow_hp, int error_per_bit, const aom_variance_fn_ptr_t *vfp,
|
||||
int forced_stop, int iters_per_step, int *mvjcost, int *mvcost[2],
|
||||
int *distortion, unsigned int *sse1, int is_second, int use_upsampled_ref);
|
||||
int av1_masked_full_pixel_diamond(const struct AV1_COMP *cpi, MACROBLOCK *x,
|
||||
const uint8_t *mask, int mask_stride,
|
||||
MV *mvp_full, int step_param, int sadpb,
|
||||
int further_steps, int do_refine,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *ref_mv, MV *dst_mv, int is_second);
|
||||
#endif // CONFIG_EXT_INTER
|
||||
|
||||
#if CONFIG_MOTION_VAR
|
||||
int av1_obmc_full_pixel_diamond(const struct AV1_COMP *cpi, MACROBLOCK *x,
|
||||
MV *mvp_full, int step_param, int sadpb,
|
||||
int further_steps, int do_refine,
|
||||
const aom_variance_fn_ptr_t *fn_ptr,
|
||||
const MV *ref_mv, MV *dst_mv, int is_second);
|
||||
int av1_find_best_obmc_sub_pixel_tree_up(
|
||||
const struct AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col,
|
||||
MV *bestmv, const MV *ref_mv, int allow_hp, int error_per_bit,
|
||||
const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step,
|
||||
int *mvjcost, int *mvcost[2], int *distortion, unsigned int *sse1,
|
||||
int is_second, int use_upsampled_ref);
|
||||
#endif // CONFIG_MOTION_VAR
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_MCOMP_H_
|
||||
108
third_party/aom/av1/encoder/mips/msa/error_msa.c
vendored
Normal file
108
third_party/aom/av1/encoder/mips/msa/error_msa.c
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
#include "aom_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; \
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
BLOCK_ERROR_BLOCKSIZE_MSA(16)
|
||||
BLOCK_ERROR_BLOCKSIZE_MSA(64)
|
||||
BLOCK_ERROR_BLOCKSIZE_MSA(256)
|
||||
BLOCK_ERROR_BLOCKSIZE_MSA(1024)
|
||||
/* clang-format on */
|
||||
|
||||
int64_t av1_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 = av1_block_error_c(coeff_ptr, dq_coeff_ptr, blk_size, ssz);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
436
third_party/aom/av1/encoder/mips/msa/fdct16x16_msa.c
vendored
Normal file
436
third_party/aom/av1/encoder/mips/msa/fdct16x16_msa.c
vendored
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "av1/common/enums.h"
|
||||
#include "av1/encoder/mips/msa/fdct_msa.h"
|
||||
#include "aom_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_step2_msa_helper(int16_t *int_buf, const int32_t *const0,
|
||||
int16_t *out, int16_t *out_ptr) {
|
||||
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_cols_step2_msa(int16_t *int_buf, const int32_t *const0,
|
||||
int16_t *out) {
|
||||
fadst16_step2_msa_helper(int_buf, const0, out, out + 128);
|
||||
}
|
||||
|
||||
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) {
|
||||
fadst16_step2_msa_helper(int_buf, const0, out, out + 8);
|
||||
}
|
||||
|
||||
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 av1_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;
|
||||
}
|
||||
}
|
||||
98
third_party/aom/av1/encoder/mips/msa/fdct4x4_msa.c
vendored
Normal file
98
third_party/aom/av1/encoder/mips/msa/fdct4x4_msa.c
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "av1/common/enums.h"
|
||||
#include "av1/encoder/mips/msa/fdct_msa.h"
|
||||
|
||||
void av1_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 av1_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:
|
||||
AOM_FDCT4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
AOM_FDCT4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
AOM_FADST4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
AOM_FDCT4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
AOM_FDCT4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
AOM_FADST4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
break;
|
||||
case ADST_ADST:
|
||||
AOM_FADST4(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
TRANSPOSE4x4_SH_SH(in0, in1, in2, in3, in0, in1, in2, in3);
|
||||
AOM_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);
|
||||
}
|
||||
65
third_party/aom/av1/encoder/mips/msa/fdct8x8_msa.c
vendored
Normal file
65
third_party/aom/av1/encoder/mips/msa/fdct8x8_msa.c
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "av1/common/enums.h"
|
||||
#include "av1/encoder/mips/msa/fdct_msa.h"
|
||||
|
||||
void av1_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:
|
||||
AOM_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);
|
||||
AOM_FDCT8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
case ADST_DCT:
|
||||
AOM_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);
|
||||
AOM_FDCT8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
case DCT_ADST:
|
||||
AOM_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);
|
||||
AOM_ADST8(in0, in1, in2, in3, in4, in5, in6, in7, in0, in1, in2, in3, in4,
|
||||
in5, in6, in7);
|
||||
break;
|
||||
case ADST_ADST:
|
||||
AOM_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);
|
||||
AOM_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);
|
||||
}
|
||||
117
third_party/aom/av1/encoder/mips/msa/fdct_msa.h
vendored
Normal file
117
third_party/aom/av1/encoder/mips/msa/fdct_msa.h
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_MIPS_MSA_AV1_FDCT_MSA_H_
|
||||
#define AV1_ENCODER_MIPS_MSA_AV1_FDCT_MSA_H_
|
||||
|
||||
#include "aom_dsp/mips/fwd_txfm_msa.h"
|
||||
#include "aom_dsp/mips/txfm_macros_msa.h"
|
||||
#include "aom_ports/mem.h"
|
||||
|
||||
#define AOM_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 AOM_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 // AV1_ENCODER_MIPS_MSA_AV1_FDCT_MSA_H_
|
||||
284
third_party/aom/av1/encoder/mips/msa/temporal_filter_msa.c
vendored
Normal file
284
third_party/aom/av1/encoder/mips/msa/temporal_filter_msa.c
vendored
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
#include "aom_dsp/mips/macros_msa.h"
|
||||
|
||||
static void temporal_filter_apply_8size_msa(uint8_t *frm1_ptr, uint32_t stride,
|
||||
uint8_t *frm2_ptr, int32_t filt_sth,
|
||||
int32_t filt_wgt, uint32_t *acc,
|
||||
uint16_t *cnt) {
|
||||
uint32_t row;
|
||||
uint64_t f0, f1, f2, f3;
|
||||
v16i8 frm2, frm1 = { 0 };
|
||||
v16i8 frm4, frm3 = { 0 };
|
||||
v16u8 frm_r, frm_l;
|
||||
v8i16 frm2_r, frm2_l;
|
||||
v8i16 diff0, diff1, mod0_h, mod1_h;
|
||||
v4i32 cnst3, cnst16, filt_wt, strength;
|
||||
v4i32 mod0_w, mod1_w, mod2_w, mod3_w;
|
||||
v4i32 diff0_r, diff0_l, diff1_r, diff1_l;
|
||||
v4i32 frm2_rr, frm2_rl, frm2_lr, frm2_ll;
|
||||
v4i32 acc0, acc1, acc2, acc3;
|
||||
v8i16 cnt0, cnt1;
|
||||
|
||||
filt_wt = __msa_fill_w(filt_wgt);
|
||||
strength = __msa_fill_w(filt_sth);
|
||||
cnst3 = __msa_ldi_w(3);
|
||||
cnst16 = __msa_ldi_w(16);
|
||||
|
||||
for (row = 2; row--;) {
|
||||
LD4(frm1_ptr, stride, f0, f1, f2, f3);
|
||||
frm1_ptr += (4 * stride);
|
||||
|
||||
LD_SB2(frm2_ptr, 16, frm2, frm4);
|
||||
frm2_ptr += 32;
|
||||
|
||||
LD_SW2(acc, 4, acc0, acc1);
|
||||
LD_SW2(acc + 8, 4, acc2, acc3);
|
||||
LD_SH2(cnt, 8, cnt0, cnt1);
|
||||
|
||||
INSERT_D2_SB(f0, f1, frm1);
|
||||
INSERT_D2_SB(f2, f3, frm3);
|
||||
ILVRL_B2_UB(frm1, frm2, frm_r, frm_l);
|
||||
HSUB_UB2_SH(frm_r, frm_l, diff0, diff1);
|
||||
UNPCK_SH_SW(diff0, diff0_r, diff0_l);
|
||||
UNPCK_SH_SW(diff1, diff1_r, diff1_l);
|
||||
MUL4(diff0_r, diff0_r, diff0_l, diff0_l, diff1_r, diff1_r, diff1_l, diff1_l,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
MUL4(mod0_w, cnst3, mod1_w, cnst3, mod2_w, cnst3, mod3_w, cnst3, mod0_w,
|
||||
mod1_w, mod2_w, mod3_w);
|
||||
SRAR_W4_SW(mod0_w, mod1_w, mod2_w, mod3_w, strength);
|
||||
|
||||
diff0_r = (mod0_w < cnst16);
|
||||
diff0_l = (mod1_w < cnst16);
|
||||
diff1_r = (mod2_w < cnst16);
|
||||
diff1_l = (mod3_w < cnst16);
|
||||
|
||||
SUB4(cnst16, mod0_w, cnst16, mod1_w, cnst16, mod2_w, cnst16, mod3_w, mod0_w,
|
||||
mod1_w, mod2_w, mod3_w);
|
||||
|
||||
mod0_w = diff0_r & mod0_w;
|
||||
mod1_w = diff0_l & mod1_w;
|
||||
mod2_w = diff1_r & mod2_w;
|
||||
mod3_w = diff1_l & mod3_w;
|
||||
|
||||
MUL4(mod0_w, filt_wt, mod1_w, filt_wt, mod2_w, filt_wt, mod3_w, filt_wt,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
PCKEV_H2_SH(mod1_w, mod0_w, mod3_w, mod2_w, mod0_h, mod1_h);
|
||||
ADD2(mod0_h, cnt0, mod1_h, cnt1, mod0_h, mod1_h);
|
||||
ST_SH2(mod0_h, mod1_h, cnt, 8);
|
||||
cnt += 16;
|
||||
|
||||
UNPCK_UB_SH(frm2, frm2_r, frm2_l);
|
||||
UNPCK_SH_SW(frm2_r, frm2_rr, frm2_rl);
|
||||
UNPCK_SH_SW(frm2_l, frm2_lr, frm2_ll);
|
||||
MUL4(mod0_w, frm2_rr, mod1_w, frm2_rl, mod2_w, frm2_lr, mod3_w, frm2_ll,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
ADD4(mod0_w, acc0, mod1_w, acc1, mod2_w, acc2, mod3_w, acc3, mod0_w, mod1_w,
|
||||
mod2_w, mod3_w);
|
||||
|
||||
ST_SW2(mod0_w, mod1_w, acc, 4);
|
||||
acc += 8;
|
||||
ST_SW2(mod2_w, mod3_w, acc, 4);
|
||||
acc += 8;
|
||||
|
||||
LD_SW2(acc, 4, acc0, acc1);
|
||||
LD_SW2(acc + 8, 4, acc2, acc3);
|
||||
LD_SH2(cnt, 8, cnt0, cnt1);
|
||||
|
||||
ILVRL_B2_UB(frm3, frm4, frm_r, frm_l);
|
||||
HSUB_UB2_SH(frm_r, frm_l, diff0, diff1);
|
||||
UNPCK_SH_SW(diff0, diff0_r, diff0_l);
|
||||
UNPCK_SH_SW(diff1, diff1_r, diff1_l);
|
||||
MUL4(diff0_r, diff0_r, diff0_l, diff0_l, diff1_r, diff1_r, diff1_l, diff1_l,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
MUL4(mod0_w, cnst3, mod1_w, cnst3, mod2_w, cnst3, mod3_w, cnst3, mod0_w,
|
||||
mod1_w, mod2_w, mod3_w);
|
||||
SRAR_W4_SW(mod0_w, mod1_w, mod2_w, mod3_w, strength);
|
||||
|
||||
diff0_r = (mod0_w < cnst16);
|
||||
diff0_l = (mod1_w < cnst16);
|
||||
diff1_r = (mod2_w < cnst16);
|
||||
diff1_l = (mod3_w < cnst16);
|
||||
|
||||
SUB4(cnst16, mod0_w, cnst16, mod1_w, cnst16, mod2_w, cnst16, mod3_w, mod0_w,
|
||||
mod1_w, mod2_w, mod3_w);
|
||||
|
||||
mod0_w = diff0_r & mod0_w;
|
||||
mod1_w = diff0_l & mod1_w;
|
||||
mod2_w = diff1_r & mod2_w;
|
||||
mod3_w = diff1_l & mod3_w;
|
||||
|
||||
MUL4(mod0_w, filt_wt, mod1_w, filt_wt, mod2_w, filt_wt, mod3_w, filt_wt,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
PCKEV_H2_SH(mod1_w, mod0_w, mod3_w, mod2_w, mod0_h, mod1_h);
|
||||
ADD2(mod0_h, cnt0, mod1_h, cnt1, mod0_h, mod1_h);
|
||||
ST_SH2(mod0_h, mod1_h, cnt, 8);
|
||||
cnt += 16;
|
||||
UNPCK_UB_SH(frm4, frm2_r, frm2_l);
|
||||
UNPCK_SH_SW(frm2_r, frm2_rr, frm2_rl);
|
||||
UNPCK_SH_SW(frm2_l, frm2_lr, frm2_ll);
|
||||
MUL4(mod0_w, frm2_rr, mod1_w, frm2_rl, mod2_w, frm2_lr, mod3_w, frm2_ll,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
ADD4(mod0_w, acc0, mod1_w, acc1, mod2_w, acc2, mod3_w, acc3, mod0_w, mod1_w,
|
||||
mod2_w, mod3_w);
|
||||
|
||||
ST_SW2(mod0_w, mod1_w, acc, 4);
|
||||
acc += 8;
|
||||
ST_SW2(mod2_w, mod3_w, acc, 4);
|
||||
acc += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void temporal_filter_apply_16size_msa(uint8_t *frm1_ptr, uint32_t stride,
|
||||
uint8_t *frm2_ptr,
|
||||
int32_t filt_sth, int32_t filt_wgt,
|
||||
uint32_t *acc, uint16_t *cnt) {
|
||||
uint32_t row;
|
||||
v16i8 frm1, frm2, frm3, frm4;
|
||||
v16u8 frm_r, frm_l;
|
||||
v16i8 zero = { 0 };
|
||||
v8u16 frm2_r, frm2_l;
|
||||
v8i16 diff0, diff1, mod0_h, mod1_h;
|
||||
v4i32 cnst3, cnst16, filt_wt, strength;
|
||||
v4i32 mod0_w, mod1_w, mod2_w, mod3_w;
|
||||
v4i32 diff0_r, diff0_l, diff1_r, diff1_l;
|
||||
v4i32 frm2_rr, frm2_rl, frm2_lr, frm2_ll;
|
||||
v4i32 acc0, acc1, acc2, acc3;
|
||||
v8i16 cnt0, cnt1;
|
||||
|
||||
filt_wt = __msa_fill_w(filt_wgt);
|
||||
strength = __msa_fill_w(filt_sth);
|
||||
cnst3 = __msa_ldi_w(3);
|
||||
cnst16 = __msa_ldi_w(16);
|
||||
|
||||
for (row = 8; row--;) {
|
||||
LD_SB2(frm1_ptr, stride, frm1, frm3);
|
||||
frm1_ptr += stride;
|
||||
|
||||
LD_SB2(frm2_ptr, 16, frm2, frm4);
|
||||
frm2_ptr += 16;
|
||||
|
||||
LD_SW2(acc, 4, acc0, acc1);
|
||||
LD_SW2(acc, 4, acc2, acc3);
|
||||
LD_SH2(cnt, 8, cnt0, cnt1);
|
||||
|
||||
ILVRL_B2_UB(frm1, frm2, frm_r, frm_l);
|
||||
HSUB_UB2_SH(frm_r, frm_l, diff0, diff1);
|
||||
UNPCK_SH_SW(diff0, diff0_r, diff0_l);
|
||||
UNPCK_SH_SW(diff1, diff1_r, diff1_l);
|
||||
MUL4(diff0_r, diff0_r, diff0_l, diff0_l, diff1_r, diff1_r, diff1_l, diff1_l,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
MUL4(mod0_w, cnst3, mod1_w, cnst3, mod2_w, cnst3, mod3_w, cnst3, mod0_w,
|
||||
mod1_w, mod2_w, mod3_w);
|
||||
SRAR_W4_SW(mod0_w, mod1_w, mod2_w, mod3_w, strength);
|
||||
|
||||
diff0_r = (mod0_w < cnst16);
|
||||
diff0_l = (mod1_w < cnst16);
|
||||
diff1_r = (mod2_w < cnst16);
|
||||
diff1_l = (mod3_w < cnst16);
|
||||
|
||||
SUB4(cnst16, mod0_w, cnst16, mod1_w, cnst16, mod2_w, cnst16, mod3_w, mod0_w,
|
||||
mod1_w, mod2_w, mod3_w);
|
||||
|
||||
mod0_w = diff0_r & mod0_w;
|
||||
mod1_w = diff0_l & mod1_w;
|
||||
mod2_w = diff1_r & mod2_w;
|
||||
mod3_w = diff1_l & mod3_w;
|
||||
|
||||
MUL4(mod0_w, filt_wt, mod1_w, filt_wt, mod2_w, filt_wt, mod3_w, filt_wt,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
PCKEV_H2_SH(mod1_w, mod0_w, mod3_w, mod2_w, mod0_h, mod1_h);
|
||||
ADD2(mod0_h, cnt0, mod1_h, cnt1, mod0_h, mod1_h);
|
||||
ST_SH2(mod0_h, mod1_h, cnt, 8);
|
||||
cnt += 16;
|
||||
|
||||
ILVRL_B2_UH(zero, frm2, frm2_r, frm2_l);
|
||||
UNPCK_SH_SW(frm2_r, frm2_rr, frm2_rl);
|
||||
UNPCK_SH_SW(frm2_l, frm2_lr, frm2_ll);
|
||||
MUL4(mod0_w, frm2_rr, mod1_w, frm2_rl, mod2_w, frm2_lr, mod3_w, frm2_ll,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
ADD4(mod0_w, acc0, mod1_w, acc1, mod2_w, acc2, mod3_w, acc3, mod0_w, mod1_w,
|
||||
mod2_w, mod3_w);
|
||||
|
||||
ST_SW2(mod0_w, mod1_w, acc, 4);
|
||||
acc += 8;
|
||||
ST_SW2(mod2_w, mod3_w, acc, 4);
|
||||
acc += 8;
|
||||
|
||||
LD_SW2(acc, 4, acc0, acc1);
|
||||
LD_SW2(acc + 8, 4, acc2, acc3);
|
||||
LD_SH2(cnt, 8, cnt0, cnt1);
|
||||
|
||||
ILVRL_B2_UB(frm3, frm4, frm_r, frm_l);
|
||||
HSUB_UB2_SH(frm_r, frm_l, diff0, diff1);
|
||||
UNPCK_SH_SW(diff0, diff0_r, diff0_l);
|
||||
UNPCK_SH_SW(diff1, diff1_r, diff1_l);
|
||||
MUL4(diff0_r, diff0_r, diff0_l, diff0_l, diff1_r, diff1_r, diff1_l, diff1_l,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
MUL4(mod0_w, cnst3, mod1_w, cnst3, mod2_w, cnst3, mod3_w, cnst3, mod0_w,
|
||||
mod1_w, mod2_w, mod3_w);
|
||||
SRAR_W4_SW(mod0_w, mod1_w, mod2_w, mod3_w, strength);
|
||||
|
||||
diff0_r = (mod0_w < cnst16);
|
||||
diff0_l = (mod1_w < cnst16);
|
||||
diff1_r = (mod2_w < cnst16);
|
||||
diff1_l = (mod3_w < cnst16);
|
||||
|
||||
SUB4(cnst16, mod0_w, cnst16, mod1_w, cnst16, mod2_w, cnst16, mod3_w, mod0_w,
|
||||
mod1_w, mod2_w, mod3_w);
|
||||
|
||||
mod0_w = diff0_r & mod0_w;
|
||||
mod1_w = diff0_l & mod1_w;
|
||||
mod2_w = diff1_r & mod2_w;
|
||||
mod3_w = diff1_l & mod3_w;
|
||||
|
||||
MUL4(mod0_w, filt_wt, mod1_w, filt_wt, mod2_w, filt_wt, mod3_w, filt_wt,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
PCKEV_H2_SH(mod1_w, mod0_w, mod3_w, mod2_w, mod0_h, mod1_h);
|
||||
ADD2(mod0_h, cnt0, mod1_h, cnt1, mod0_h, mod1_h);
|
||||
ST_SH2(mod0_h, mod1_h, cnt, 8);
|
||||
cnt += 16;
|
||||
|
||||
ILVRL_B2_UH(zero, frm4, frm2_r, frm2_l);
|
||||
UNPCK_SH_SW(frm2_r, frm2_rr, frm2_rl);
|
||||
UNPCK_SH_SW(frm2_l, frm2_lr, frm2_ll);
|
||||
MUL4(mod0_w, frm2_rr, mod1_w, frm2_rl, mod2_w, frm2_lr, mod3_w, frm2_ll,
|
||||
mod0_w, mod1_w, mod2_w, mod3_w);
|
||||
ADD4(mod0_w, acc0, mod1_w, acc1, mod2_w, acc2, mod3_w, acc3, mod0_w, mod1_w,
|
||||
mod2_w, mod3_w);
|
||||
ST_SW2(mod0_w, mod1_w, acc, 4);
|
||||
acc += 8;
|
||||
ST_SW2(mod2_w, mod3_w, acc, 4);
|
||||
acc += 8;
|
||||
|
||||
frm1_ptr += stride;
|
||||
frm2_ptr += 16;
|
||||
}
|
||||
}
|
||||
|
||||
void av1_temporal_filter_apply_msa(uint8_t *frame1_ptr, uint32_t stride,
|
||||
uint8_t *frame2_ptr, uint32_t blk_w,
|
||||
uint32_t blk_h, int32_t strength,
|
||||
int32_t filt_wgt, uint32_t *accu,
|
||||
uint16_t *cnt) {
|
||||
if (8 == (blk_w * blk_h)) {
|
||||
temporal_filter_apply_8size_msa(frame1_ptr, stride, frame2_ptr, strength,
|
||||
filt_wgt, accu, cnt);
|
||||
} else if (16 == (blk_w * blk_h)) {
|
||||
temporal_filter_apply_16size_msa(frame1_ptr, stride, frame2_ptr, strength,
|
||||
filt_wgt, accu, cnt);
|
||||
} else {
|
||||
av1_temporal_filter_apply_c(frame1_ptr, stride, frame2_ptr, blk_w, blk_h,
|
||||
strength, filt_wgt, accu, cnt);
|
||||
}
|
||||
}
|
||||
277
third_party/aom/av1/encoder/palette.c
vendored
Normal file
277
third_party/aom/av1/encoder/palette.c
vendored
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "av1/encoder/cost.h"
|
||||
#include "av1/encoder/palette.h"
|
||||
|
||||
static float calc_dist(const float *p1, const float *p2, int dim) {
|
||||
float dist = 0;
|
||||
int i;
|
||||
for (i = 0; i < dim; ++i) {
|
||||
const float diff = p1[i] - p2[i];
|
||||
dist += diff * diff;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
void av1_calc_indices(const float *data, const float *centroids,
|
||||
uint8_t *indices, int n, int k, int dim) {
|
||||
int i, j;
|
||||
for (i = 0; i < n; ++i) {
|
||||
float min_dist = calc_dist(data + i * dim, centroids, dim);
|
||||
indices[i] = 0;
|
||||
for (j = 1; j < k; ++j) {
|
||||
const float this_dist =
|
||||
calc_dist(data + i * dim, centroids + j * dim, dim);
|
||||
if (this_dist < min_dist) {
|
||||
min_dist = this_dist;
|
||||
indices[i] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a random number in the range [0, 32768).
|
||||
static unsigned int lcg_rand16(unsigned int *state) {
|
||||
*state = (unsigned int)(*state * 1103515245ULL + 12345);
|
||||
return *state / 65536 % 32768;
|
||||
}
|
||||
|
||||
static void calc_centroids(const float *data, float *centroids,
|
||||
const uint8_t *indices, int n, int k, int dim) {
|
||||
int i, j, index;
|
||||
int count[PALETTE_MAX_SIZE];
|
||||
unsigned int rand_state = (unsigned int)data[0];
|
||||
|
||||
assert(n <= 32768);
|
||||
|
||||
memset(count, 0, sizeof(count[0]) * k);
|
||||
memset(centroids, 0, sizeof(centroids[0]) * k * dim);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
index = indices[i];
|
||||
assert(index < k);
|
||||
++count[index];
|
||||
for (j = 0; j < dim; ++j) {
|
||||
centroids[index * dim + j] += data[i * dim + j];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < k; ++i) {
|
||||
if (count[i] == 0) {
|
||||
memcpy(centroids + i * dim, data + (lcg_rand16(&rand_state) % n) * dim,
|
||||
sizeof(centroids[0]) * dim);
|
||||
} else {
|
||||
const float norm = 1.0f / count[i];
|
||||
for (j = 0; j < dim; ++j) centroids[i * dim + j] *= norm;
|
||||
}
|
||||
}
|
||||
|
||||
// Round to nearest integers.
|
||||
for (i = 0; i < k * dim; ++i) {
|
||||
centroids[i] = roundf(centroids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static float calc_total_dist(const float *data, const float *centroids,
|
||||
const uint8_t *indices, int n, int k, int dim) {
|
||||
float dist = 0;
|
||||
int i;
|
||||
(void)k;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
dist += calc_dist(data + i * dim, centroids + indices[i] * dim, dim);
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
void av1_k_means(const float *data, float *centroids, uint8_t *indices, int n,
|
||||
int k, int dim, int max_itr) {
|
||||
int i;
|
||||
float this_dist;
|
||||
float pre_centroids[2 * PALETTE_MAX_SIZE];
|
||||
uint8_t pre_indices[MAX_SB_SQUARE];
|
||||
|
||||
av1_calc_indices(data, centroids, indices, n, k, dim);
|
||||
this_dist = calc_total_dist(data, centroids, indices, n, k, dim);
|
||||
|
||||
for (i = 0; i < max_itr; ++i) {
|
||||
const float pre_dist = this_dist;
|
||||
memcpy(pre_centroids, centroids, sizeof(pre_centroids[0]) * k * dim);
|
||||
memcpy(pre_indices, indices, sizeof(pre_indices[0]) * n);
|
||||
|
||||
calc_centroids(data, centroids, indices, n, k, dim);
|
||||
av1_calc_indices(data, centroids, indices, n, k, dim);
|
||||
this_dist = calc_total_dist(data, centroids, indices, n, k, dim);
|
||||
|
||||
if (this_dist > pre_dist) {
|
||||
memcpy(centroids, pre_centroids, sizeof(pre_centroids[0]) * k * dim);
|
||||
memcpy(indices, pre_indices, sizeof(pre_indices[0]) * n);
|
||||
break;
|
||||
}
|
||||
if (!memcmp(centroids, pre_centroids, sizeof(pre_centroids[0]) * k * dim))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int float_comparer(const void *a, const void *b) {
|
||||
const float fa = *(const float *)a;
|
||||
const float fb = *(const float *)b;
|
||||
return (fa > fb) - (fa < fb);
|
||||
}
|
||||
|
||||
int av1_remove_duplicates(float *centroids, int num_centroids) {
|
||||
int num_unique; // number of unique centroids
|
||||
int i;
|
||||
qsort(centroids, num_centroids, sizeof(*centroids), float_comparer);
|
||||
// Remove duplicates.
|
||||
num_unique = 1;
|
||||
for (i = 1; i < num_centroids; ++i) {
|
||||
if (centroids[i] != centroids[i - 1]) { // found a new unique centroid
|
||||
centroids[num_unique++] = centroids[i];
|
||||
}
|
||||
}
|
||||
return num_unique;
|
||||
}
|
||||
|
||||
int av1_count_colors(const uint8_t *src, int stride, int rows, int cols) {
|
||||
int n = 0, r, c, i, val_count[256];
|
||||
uint8_t val;
|
||||
memset(val_count, 0, sizeof(val_count));
|
||||
|
||||
for (r = 0; r < rows; ++r) {
|
||||
for (c = 0; c < cols; ++c) {
|
||||
val = src[r * stride + c];
|
||||
++val_count[val];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
if (val_count[i]) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#if CONFIG_PALETTE_DELTA_ENCODING
|
||||
int av1_get_palette_delta_bits_y(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth, int *min_bits) {
|
||||
const int n = pmi->palette_size[0];
|
||||
int max_d = 0, i;
|
||||
*min_bits = bit_depth - 3;
|
||||
for (i = 1; i < n; ++i) {
|
||||
const int delta = pmi->palette_colors[i] - pmi->palette_colors[i - 1];
|
||||
assert(delta > 0);
|
||||
if (delta > max_d) max_d = delta;
|
||||
}
|
||||
return AOMMAX(av1_ceil_log2(max_d), *min_bits);
|
||||
}
|
||||
|
||||
int av1_get_palette_delta_bits_u(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth, int *min_bits) {
|
||||
const int n = pmi->palette_size[1];
|
||||
int max_d = 0, i;
|
||||
*min_bits = bit_depth - 3;
|
||||
for (i = 1; i < n; ++i) {
|
||||
const int delta = pmi->palette_colors[PALETTE_MAX_SIZE + i] -
|
||||
pmi->palette_colors[PALETTE_MAX_SIZE + i - 1];
|
||||
assert(delta >= 0);
|
||||
if (delta > max_d) max_d = delta;
|
||||
}
|
||||
return AOMMAX(av1_ceil_log2(max_d + 1), *min_bits);
|
||||
}
|
||||
|
||||
int av1_get_palette_delta_bits_v(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth, int *zero_count,
|
||||
int *min_bits) {
|
||||
const int n = pmi->palette_size[1];
|
||||
const int max_val = 1 << bit_depth;
|
||||
int max_d = 0, i;
|
||||
*min_bits = bit_depth - 4;
|
||||
*zero_count = 0;
|
||||
for (i = 1; i < n; ++i) {
|
||||
const int delta = pmi->palette_colors[2 * PALETTE_MAX_SIZE + i] -
|
||||
pmi->palette_colors[2 * PALETTE_MAX_SIZE + i - 1];
|
||||
const int v = abs(delta);
|
||||
const int d = AOMMIN(v, max_val - v);
|
||||
if (d > max_d) max_d = d;
|
||||
if (d == 0) ++(*zero_count);
|
||||
}
|
||||
return AOMMAX(av1_ceil_log2(max_d + 1), *min_bits);
|
||||
}
|
||||
#endif // CONFIG_PALETTE_DELTA_ENCODING
|
||||
|
||||
int av1_palette_color_cost_y(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth) {
|
||||
const int n = pmi->palette_size[0];
|
||||
#if CONFIG_PALETTE_DELTA_ENCODING
|
||||
int min_bits = 0;
|
||||
const int bits = av1_get_palette_delta_bits_y(pmi, bit_depth, &min_bits);
|
||||
return av1_cost_bit(128, 0) * (2 + bit_depth + bits * (n - 1));
|
||||
#else
|
||||
return bit_depth * n * av1_cost_bit(128, 0);
|
||||
#endif // CONFIG_PALETTE_DELTA_ENCODING
|
||||
}
|
||||
|
||||
int av1_palette_color_cost_uv(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth) {
|
||||
const int n = pmi->palette_size[1];
|
||||
#if CONFIG_PALETTE_DELTA_ENCODING
|
||||
int cost = 0;
|
||||
// U channel palette color cost.
|
||||
int min_bits_u = 0;
|
||||
const int bits_u = av1_get_palette_delta_bits_u(pmi, bit_depth, &min_bits_u);
|
||||
cost += av1_cost_bit(128, 0) * (2 + bit_depth + bits_u * (n - 1));
|
||||
// V channel palette color cost.
|
||||
int zero_count = 0, min_bits_v = 0;
|
||||
const int bits_v =
|
||||
av1_get_palette_delta_bits_v(pmi, bit_depth, &zero_count, &min_bits_v);
|
||||
const int bits_using_delta =
|
||||
2 + bit_depth + (bits_v + 1) * (n - 1) - zero_count;
|
||||
const int bits_using_raw = bit_depth * n;
|
||||
cost += av1_cost_bit(128, 0) * (1 + AOMMIN(bits_using_delta, bits_using_raw));
|
||||
return cost;
|
||||
#else
|
||||
return 2 * bit_depth * n * av1_cost_bit(128, 0);
|
||||
#endif // CONFIG_PALETTE_DELTA_ENCODING
|
||||
}
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int av1_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols,
|
||||
int bit_depth) {
|
||||
int n = 0, r, c, i;
|
||||
uint16_t val;
|
||||
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
|
||||
int val_count[1 << 12];
|
||||
|
||||
assert(bit_depth <= 12);
|
||||
memset(val_count, 0, (1 << 12) * sizeof(val_count[0]));
|
||||
for (r = 0; r < rows; ++r) {
|
||||
for (c = 0; c < cols; ++c) {
|
||||
val = src[r * stride + c];
|
||||
++val_count[val];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < (1 << bit_depth); ++i) {
|
||||
if (val_count[i]) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
73
third_party/aom/av1/encoder/palette.h
vendored
Normal file
73
third_party/aom/av1/encoder/palette.h
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_PALETTE_H_
|
||||
#define AV1_ENCODER_PALETTE_H_
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Given 'n' 'data' points and 'k' 'centroids' each of dimension 'dim',
|
||||
// calculate the centroid 'indices' for the data points.
|
||||
void av1_calc_indices(const float *data, const float *centroids,
|
||||
uint8_t *indices, int n, int k, int dim);
|
||||
|
||||
// Given 'n' 'data' points and an initial guess of 'k' 'centroids' each of
|
||||
// dimension 'dim', runs up to 'max_itr' iterations of k-means algorithm to get
|
||||
// updated 'centroids' and the centroid 'indices' for elements in 'data'.
|
||||
// Note: the output centroids are rounded off to nearest integers.
|
||||
void av1_k_means(const float *data, float *centroids, uint8_t *indices, int n,
|
||||
int k, int dim, int max_itr);
|
||||
|
||||
// Given a list of centroids, returns the unique number of centroids 'k', and
|
||||
// puts these unique centroids in first 'k' indices of 'centroids' array.
|
||||
// Ideally, the centroids should be rounded to integers before calling this
|
||||
// method.
|
||||
int av1_remove_duplicates(float *centroids, int num_centroids);
|
||||
|
||||
// Returns the number of colors in 'src'.
|
||||
int av1_count_colors(const uint8_t *src, int stride, int rows, int cols);
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
// Same as av1_count_colors(), but for high-bitdepth mode.
|
||||
int av1_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols,
|
||||
int bit_depth);
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
|
||||
#if CONFIG_PALETTE_DELTA_ENCODING
|
||||
// Return the number of bits used to transmit each luma palette color delta.
|
||||
int av1_get_palette_delta_bits_y(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth, int *min_bits);
|
||||
|
||||
// Return the number of bits used to transmit each U palette color delta.
|
||||
int av1_get_palette_delta_bits_u(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth, int *min_bits);
|
||||
|
||||
// Return the number of bits used to transmit each v palette color delta;
|
||||
// assign zero_count with the number of deltas being 0.
|
||||
int av1_get_palette_delta_bits_v(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth, int *zero_count, int *min_bits);
|
||||
#endif // CONFIG_PALETTE_DELTA_ENCODING
|
||||
|
||||
// Return the rate cost for transmitting luma palette color values.
|
||||
int av1_palette_color_cost_y(const PALETTE_MODE_INFO *const pmi, int bit_depth);
|
||||
|
||||
// Return the rate cost for transmitting chroma palette color values.
|
||||
int av1_palette_color_cost_uv(const PALETTE_MODE_INFO *const pmi,
|
||||
int bit_depth);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* AV1_ENCODER_PALETTE_H_ */
|
||||
490
third_party/aom/av1/encoder/pickcdef.c
vendored
Normal file
490
third_party/aom/av1/encoder/pickcdef.c
vendored
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./aom_scale_rtcd.h"
|
||||
#include "aom/aom_integer.h"
|
||||
#include "av1/common/cdef.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/common/reconinter.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
#define TOTAL_STRENGTHS (DERING_STRENGTHS * CLPF_STRENGTHS)
|
||||
|
||||
/* Search for the best strength to add as an option, knowing we
|
||||
already selected nb_strengths options. */
|
||||
static uint64_t search_one(int *lev, int nb_strengths,
|
||||
uint64_t mse[][TOTAL_STRENGTHS], int sb_count) {
|
||||
uint64_t tot_mse[TOTAL_STRENGTHS];
|
||||
int i, j;
|
||||
uint64_t best_tot_mse = (uint64_t)1 << 63;
|
||||
int best_id = 0;
|
||||
memset(tot_mse, 0, sizeof(tot_mse));
|
||||
for (i = 0; i < sb_count; i++) {
|
||||
int gi;
|
||||
uint64_t best_mse = (uint64_t)1 << 63;
|
||||
/* Find best mse among already selected options. */
|
||||
for (gi = 0; gi < nb_strengths; gi++) {
|
||||
if (mse[i][lev[gi]] < best_mse) {
|
||||
best_mse = mse[i][lev[gi]];
|
||||
}
|
||||
}
|
||||
/* Find best mse when adding each possible new option. */
|
||||
for (j = 0; j < TOTAL_STRENGTHS; j++) {
|
||||
uint64_t best = best_mse;
|
||||
if (mse[i][j] < best) best = mse[i][j];
|
||||
tot_mse[j] += best;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < TOTAL_STRENGTHS; j++) {
|
||||
if (tot_mse[j] < best_tot_mse) {
|
||||
best_tot_mse = tot_mse[j];
|
||||
best_id = j;
|
||||
}
|
||||
}
|
||||
lev[nb_strengths] = best_id;
|
||||
return best_tot_mse;
|
||||
}
|
||||
|
||||
/* Search for the best luma+chroma strength to add as an option, knowing we
|
||||
already selected nb_strengths options. */
|
||||
static uint64_t search_one_dual(int *lev0, int *lev1, int nb_strengths,
|
||||
uint64_t (**mse)[TOTAL_STRENGTHS],
|
||||
int sb_count) {
|
||||
uint64_t tot_mse[TOTAL_STRENGTHS][TOTAL_STRENGTHS];
|
||||
int i, j;
|
||||
uint64_t best_tot_mse = (uint64_t)1 << 63;
|
||||
int best_id0 = 0;
|
||||
int best_id1 = 0;
|
||||
memset(tot_mse, 0, sizeof(tot_mse));
|
||||
for (i = 0; i < sb_count; i++) {
|
||||
int gi;
|
||||
uint64_t best_mse = (uint64_t)1 << 63;
|
||||
/* Find best mse among already selected options. */
|
||||
for (gi = 0; gi < nb_strengths; gi++) {
|
||||
uint64_t curr = mse[0][i][lev0[gi]];
|
||||
curr += mse[1][i][lev1[gi]];
|
||||
if (curr < best_mse) {
|
||||
best_mse = curr;
|
||||
}
|
||||
}
|
||||
/* Find best mse when adding each possible new option. */
|
||||
for (j = 0; j < TOTAL_STRENGTHS; j++) {
|
||||
int k;
|
||||
for (k = 0; k < TOTAL_STRENGTHS; k++) {
|
||||
uint64_t best = best_mse;
|
||||
uint64_t curr = mse[0][i][j];
|
||||
curr += mse[1][i][k];
|
||||
if (curr < best) best = curr;
|
||||
tot_mse[j][k] += best;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (j = 0; j < TOTAL_STRENGTHS; j++) {
|
||||
int k;
|
||||
for (k = 0; k < TOTAL_STRENGTHS; k++) {
|
||||
if (tot_mse[j][k] < best_tot_mse) {
|
||||
best_tot_mse = tot_mse[j][k];
|
||||
best_id0 = j;
|
||||
best_id1 = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
lev0[nb_strengths] = best_id0;
|
||||
lev1[nb_strengths] = best_id1;
|
||||
return best_tot_mse;
|
||||
}
|
||||
|
||||
/* Search for the set of strengths that minimizes mse. */
|
||||
static uint64_t joint_strength_search(int *best_lev, int nb_strengths,
|
||||
uint64_t mse[][TOTAL_STRENGTHS],
|
||||
int sb_count) {
|
||||
uint64_t best_tot_mse;
|
||||
int i;
|
||||
best_tot_mse = (uint64_t)1 << 63;
|
||||
/* Greedy search: add one strength options at a time. */
|
||||
for (i = 0; i < nb_strengths; i++) {
|
||||
best_tot_mse = search_one(best_lev, i, mse, sb_count);
|
||||
}
|
||||
/* Trying to refine the greedy search by reconsidering each
|
||||
already-selected option. */
|
||||
for (i = 0; i < 4 * nb_strengths; i++) {
|
||||
int j;
|
||||
for (j = 0; j < nb_strengths - 1; j++) best_lev[j] = best_lev[j + 1];
|
||||
best_tot_mse = search_one(best_lev, nb_strengths - 1, mse, sb_count);
|
||||
}
|
||||
return best_tot_mse;
|
||||
}
|
||||
|
||||
/* Search for the set of luma+chroma strengths that minimizes mse. */
|
||||
static uint64_t joint_strength_search_dual(int *best_lev0, int *best_lev1,
|
||||
int nb_strengths,
|
||||
uint64_t (**mse)[TOTAL_STRENGTHS],
|
||||
int sb_count) {
|
||||
uint64_t best_tot_mse;
|
||||
int i;
|
||||
best_tot_mse = (uint64_t)1 << 63;
|
||||
/* Greedy search: add one strength options at a time. */
|
||||
for (i = 0; i < nb_strengths; i++) {
|
||||
best_tot_mse = search_one_dual(best_lev0, best_lev1, i, mse, sb_count);
|
||||
}
|
||||
/* Trying to refine the greedy search by reconsidering each
|
||||
already-selected option. */
|
||||
for (i = 0; i < 4 * nb_strengths; i++) {
|
||||
int j;
|
||||
for (j = 0; j < nb_strengths - 1; j++) {
|
||||
best_lev0[j] = best_lev0[j + 1];
|
||||
best_lev1[j] = best_lev1[j + 1];
|
||||
}
|
||||
best_tot_mse =
|
||||
search_one_dual(best_lev0, best_lev1, nb_strengths - 1, mse, sb_count);
|
||||
}
|
||||
return best_tot_mse;
|
||||
}
|
||||
|
||||
/* FIXME: SSE-optimize this. */
|
||||
static void copy_sb16_16(uint16_t *dst, int dstride, const uint16_t *src,
|
||||
int src_voffset, int src_hoffset, int sstride,
|
||||
int vsize, int hsize) {
|
||||
int r, c;
|
||||
const uint16_t *base = &src[src_voffset * sstride + src_hoffset];
|
||||
for (r = 0; r < vsize; r++) {
|
||||
for (c = 0; c < hsize; c++) {
|
||||
dst[r * dstride + c] = base[r * sstride + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE uint64_t dist_8x8_16bit(uint16_t *dst, int dstride, uint16_t *src,
|
||||
int sstride, int coeff_shift) {
|
||||
uint64_t svar = 0;
|
||||
uint64_t dvar = 0;
|
||||
uint64_t sum_s = 0;
|
||||
uint64_t sum_d = 0;
|
||||
uint64_t sum_s2 = 0;
|
||||
uint64_t sum_d2 = 0;
|
||||
uint64_t sum_sd = 0;
|
||||
int i, j;
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
sum_s += src[i * sstride + j];
|
||||
sum_d += dst[i * dstride + j];
|
||||
sum_s2 += src[i * sstride + j] * src[i * sstride + j];
|
||||
sum_d2 += dst[i * dstride + j] * dst[i * dstride + j];
|
||||
sum_sd += src[i * sstride + j] * dst[i * dstride + j];
|
||||
}
|
||||
}
|
||||
/* Compute the variance -- the calculation cannot go negative. */
|
||||
svar = sum_s2 - ((sum_s * sum_s + 32) >> 6);
|
||||
dvar = sum_d2 - ((sum_d * sum_d + 32) >> 6);
|
||||
return (uint64_t)floor(
|
||||
.5 +
|
||||
(sum_d2 + sum_s2 - 2 * sum_sd) * .5 *
|
||||
(svar + dvar + (400 << 2 * coeff_shift)) /
|
||||
(sqrt((20000 << 4 * coeff_shift) + svar * (double)dvar)));
|
||||
}
|
||||
|
||||
static INLINE uint64_t mse_8x8_16bit(uint16_t *dst, int dstride, uint16_t *src,
|
||||
int sstride) {
|
||||
uint64_t sum = 0;
|
||||
int i, j;
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
int e = dst[i * dstride + j] - src[i * sstride + j];
|
||||
sum += e * e;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
static INLINE uint64_t mse_4x4_16bit(uint16_t *dst, int dstride, uint16_t *src,
|
||||
int sstride) {
|
||||
uint64_t sum = 0;
|
||||
int i, j;
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
int e = dst[i * dstride + j] - src[i * sstride + j];
|
||||
sum += e * e;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/* Compute MSE only on the blocks we filtered. */
|
||||
uint64_t compute_dering_dist(uint16_t *dst, int dstride, uint16_t *src,
|
||||
dering_list *dlist, int dering_count,
|
||||
BLOCK_SIZE bsize, int coeff_shift, int pli) {
|
||||
uint64_t sum = 0;
|
||||
int bi, bx, by;
|
||||
if (bsize == BLOCK_8X8) {
|
||||
for (bi = 0; bi < dering_count; bi++) {
|
||||
by = dlist[bi].by;
|
||||
bx = dlist[bi].bx;
|
||||
if (pli == 0) {
|
||||
sum += dist_8x8_16bit(&dst[(by << 3) * dstride + (bx << 3)], dstride,
|
||||
&src[bi << (3 + 3)], 8, coeff_shift);
|
||||
} else {
|
||||
sum += mse_8x8_16bit(&dst[(by << 3) * dstride + (bx << 3)], dstride,
|
||||
&src[bi << (3 + 3)], 8);
|
||||
}
|
||||
}
|
||||
} else if (bsize == BLOCK_4X8) {
|
||||
for (bi = 0; bi < dering_count; bi++) {
|
||||
by = dlist[bi].by;
|
||||
bx = dlist[bi].bx;
|
||||
sum += mse_4x4_16bit(&dst[(by << 3) * dstride + (bx << 2)], dstride,
|
||||
&src[bi << (3 + 2)], 4);
|
||||
sum += mse_4x4_16bit(&dst[((by << 3) + 4) * dstride + (bx << 2)], dstride,
|
||||
&src[(bi << (3 + 2)) + 4 * 4], 4);
|
||||
}
|
||||
} else if (bsize == BLOCK_8X4) {
|
||||
for (bi = 0; bi < dering_count; bi++) {
|
||||
by = dlist[bi].by;
|
||||
bx = dlist[bi].bx;
|
||||
sum += mse_4x4_16bit(&dst[(by << 2) * dstride + (bx << 3)], dstride,
|
||||
&src[bi << (2 + 3)], 8);
|
||||
sum += mse_4x4_16bit(&dst[(by << 2) * dstride + (bx << 3) + 4], dstride,
|
||||
&src[(bi << (2 + 3)) + 4], 8);
|
||||
}
|
||||
} else {
|
||||
assert(bsize == BLOCK_4X4);
|
||||
for (bi = 0; bi < dering_count; bi++) {
|
||||
by = dlist[bi].by;
|
||||
bx = dlist[bi].bx;
|
||||
sum += mse_4x4_16bit(&dst[(by << 2) * dstride + (bx << 2)], dstride,
|
||||
&src[bi << (2 + 2)], 4);
|
||||
}
|
||||
}
|
||||
return sum >> 2 * coeff_shift;
|
||||
}
|
||||
|
||||
void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref,
|
||||
AV1_COMMON *cm, MACROBLOCKD *xd) {
|
||||
int r, c;
|
||||
int sbr, sbc;
|
||||
uint16_t *src[3];
|
||||
uint16_t *ref_coeff[3];
|
||||
dering_list dlist[MAX_MIB_SIZE * MAX_MIB_SIZE];
|
||||
int dir[OD_DERING_NBLOCKS][OD_DERING_NBLOCKS] = { { 0 } };
|
||||
int var[OD_DERING_NBLOCKS][OD_DERING_NBLOCKS] = { { 0 } };
|
||||
int stride[3];
|
||||
int bsize[3];
|
||||
int mi_wide_l2[3];
|
||||
int mi_high_l2[3];
|
||||
int xdec[3];
|
||||
int ydec[3];
|
||||
int pli;
|
||||
int dering_count;
|
||||
int coeff_shift = AOMMAX(cm->bit_depth - 8, 0);
|
||||
uint64_t best_tot_mse = (uint64_t)1 << 63;
|
||||
uint64_t tot_mse;
|
||||
int sb_count;
|
||||
int nvsb = (cm->mi_rows + MAX_MIB_SIZE - 1) / MAX_MIB_SIZE;
|
||||
int nhsb = (cm->mi_cols + MAX_MIB_SIZE - 1) / MAX_MIB_SIZE;
|
||||
int *sb_index = aom_malloc(nvsb * nhsb * sizeof(*sb_index));
|
||||
int *selected_strength = aom_malloc(nvsb * nhsb * sizeof(*sb_index));
|
||||
uint64_t(*mse[2])[TOTAL_STRENGTHS];
|
||||
int clpf_damping = 3 + (cm->base_qindex >> 6);
|
||||
int dering_damping = 6;
|
||||
int i;
|
||||
int nb_strengths;
|
||||
int nb_strength_bits;
|
||||
int quantizer;
|
||||
double lambda;
|
||||
int nplanes = 3;
|
||||
DECLARE_ALIGNED(32, uint16_t, inbuf[OD_DERING_INBUF_SIZE]);
|
||||
uint16_t *in;
|
||||
DECLARE_ALIGNED(32, uint16_t, tmp_dst[MAX_SB_SQUARE]);
|
||||
int chroma_dering =
|
||||
xd->plane[1].subsampling_x == xd->plane[1].subsampling_y &&
|
||||
xd->plane[2].subsampling_x == xd->plane[2].subsampling_y;
|
||||
quantizer =
|
||||
av1_ac_quant(cm->base_qindex, 0, cm->bit_depth) >> (cm->bit_depth - 8);
|
||||
lambda = .12 * quantizer * quantizer / 256.;
|
||||
|
||||
av1_setup_dst_planes(xd->plane, cm->sb_size, frame, 0, 0);
|
||||
mse[0] = aom_malloc(sizeof(**mse) * nvsb * nhsb);
|
||||
mse[1] = aom_malloc(sizeof(**mse) * nvsb * nhsb);
|
||||
for (pli = 0; pli < nplanes; pli++) {
|
||||
uint8_t *ref_buffer;
|
||||
int ref_stride;
|
||||
switch (pli) {
|
||||
case 0:
|
||||
ref_buffer = ref->y_buffer;
|
||||
ref_stride = ref->y_stride;
|
||||
break;
|
||||
case 1:
|
||||
ref_buffer = ref->u_buffer;
|
||||
ref_stride = ref->uv_stride;
|
||||
break;
|
||||
case 2:
|
||||
ref_buffer = ref->v_buffer;
|
||||
ref_stride = ref->uv_stride;
|
||||
break;
|
||||
}
|
||||
src[pli] = aom_memalign(
|
||||
32, sizeof(*src) * cm->mi_rows * cm->mi_cols * MI_SIZE * MI_SIZE);
|
||||
ref_coeff[pli] = aom_memalign(
|
||||
32, sizeof(*ref_coeff) * cm->mi_rows * cm->mi_cols * MI_SIZE * MI_SIZE);
|
||||
xdec[pli] = xd->plane[pli].subsampling_x;
|
||||
ydec[pli] = xd->plane[pli].subsampling_y;
|
||||
bsize[pli] = ydec[pli] ? (xdec[pli] ? BLOCK_4X4 : BLOCK_8X4)
|
||||
: (xdec[pli] ? BLOCK_4X8 : BLOCK_8X8);
|
||||
stride[pli] = cm->mi_cols << MI_SIZE_LOG2;
|
||||
mi_wide_l2[pli] = MI_SIZE_LOG2 - xd->plane[pli].subsampling_x;
|
||||
mi_high_l2[pli] = MI_SIZE_LOG2 - xd->plane[pli].subsampling_y;
|
||||
|
||||
const int frame_height =
|
||||
(cm->mi_rows * MI_SIZE) >> xd->plane[pli].subsampling_y;
|
||||
const int frame_width =
|
||||
(cm->mi_cols * MI_SIZE) >> xd->plane[pli].subsampling_x;
|
||||
|
||||
for (r = 0; r < frame_height; ++r) {
|
||||
for (c = 0; c < frame_width; ++c) {
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
if (cm->use_highbitdepth) {
|
||||
src[pli][r * stride[pli] + c] = CONVERT_TO_SHORTPTR(
|
||||
xd->plane[pli].dst.buf)[r * xd->plane[pli].dst.stride + c];
|
||||
ref_coeff[pli][r * stride[pli] + c] =
|
||||
CONVERT_TO_SHORTPTR(ref_buffer)[r * ref_stride + c];
|
||||
} else {
|
||||
#endif
|
||||
src[pli][r * stride[pli] + c] =
|
||||
xd->plane[pli].dst.buf[r * xd->plane[pli].dst.stride + c];
|
||||
ref_coeff[pli][r * stride[pli] + c] = ref_buffer[r * ref_stride + c];
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
in = inbuf + OD_FILT_VBORDER * OD_FILT_BSTRIDE + OD_FILT_HBORDER;
|
||||
sb_count = 0;
|
||||
for (sbr = 0; sbr < nvsb; ++sbr) {
|
||||
for (sbc = 0; sbc < nhsb; ++sbc) {
|
||||
int nvb, nhb;
|
||||
int gi;
|
||||
int dirinit = 0;
|
||||
nhb = AOMMIN(MAX_MIB_SIZE, cm->mi_cols - MAX_MIB_SIZE * sbc);
|
||||
nvb = AOMMIN(MAX_MIB_SIZE, cm->mi_rows - MAX_MIB_SIZE * sbr);
|
||||
cm->mi_grid_visible[MAX_MIB_SIZE * sbr * cm->mi_stride +
|
||||
MAX_MIB_SIZE * sbc]
|
||||
->mbmi.cdef_strength = -1;
|
||||
if (sb_all_skip(cm, sbr * MAX_MIB_SIZE, sbc * MAX_MIB_SIZE)) continue;
|
||||
dering_count = sb_compute_dering_list(cm, sbr * MAX_MIB_SIZE,
|
||||
sbc * MAX_MIB_SIZE, dlist, 1);
|
||||
for (pli = 0; pli < nplanes; pli++) {
|
||||
for (i = 0; i < OD_DERING_INBUF_SIZE; i++)
|
||||
inbuf[i] = OD_DERING_VERY_LARGE;
|
||||
for (gi = 0; gi < TOTAL_STRENGTHS; gi++) {
|
||||
int threshold;
|
||||
uint64_t curr_mse;
|
||||
int clpf_strength;
|
||||
threshold = gi / CLPF_STRENGTHS;
|
||||
if (pli > 0 && !chroma_dering) threshold = 0;
|
||||
/* We avoid filtering the pixels for which some of the pixels to
|
||||
average
|
||||
are outside the frame. We could change the filter instead, but it
|
||||
would add special cases for any future vectorization. */
|
||||
int yoff = OD_FILT_VBORDER * (sbr != 0);
|
||||
int xoff = OD_FILT_HBORDER * (sbc != 0);
|
||||
int ysize = (nvb << mi_high_l2[pli]) +
|
||||
OD_FILT_VBORDER * (sbr != nvsb - 1) + yoff;
|
||||
int xsize = (nhb << mi_wide_l2[pli]) +
|
||||
OD_FILT_HBORDER * (sbc != nhsb - 1) + xoff;
|
||||
clpf_strength = gi % CLPF_STRENGTHS;
|
||||
if (clpf_strength == 0)
|
||||
copy_sb16_16(&in[(-yoff * OD_FILT_BSTRIDE - xoff)], OD_FILT_BSTRIDE,
|
||||
src[pli],
|
||||
(sbr * MAX_MIB_SIZE << mi_high_l2[pli]) - yoff,
|
||||
(sbc * MAX_MIB_SIZE << mi_wide_l2[pli]) - xoff,
|
||||
stride[pli], ysize, xsize);
|
||||
od_dering(clpf_strength ? NULL : (uint8_t *)in, OD_FILT_BSTRIDE,
|
||||
tmp_dst, in, xdec[pli], ydec[pli], dir, &dirinit, var, pli,
|
||||
dlist, dering_count, threshold,
|
||||
clpf_strength + (clpf_strength == 3), clpf_damping,
|
||||
dering_damping, coeff_shift, clpf_strength != 0, 1);
|
||||
curr_mse = compute_dering_dist(
|
||||
ref_coeff[pli] +
|
||||
(sbr * MAX_MIB_SIZE << mi_high_l2[pli]) * stride[pli] +
|
||||
(sbc * MAX_MIB_SIZE << mi_wide_l2[pli]),
|
||||
stride[pli], tmp_dst, dlist, dering_count, bsize[pli],
|
||||
coeff_shift, pli);
|
||||
if (pli < 2)
|
||||
mse[pli][sb_count][gi] = curr_mse;
|
||||
else
|
||||
mse[1][sb_count][gi] += curr_mse;
|
||||
sb_index[sb_count] =
|
||||
MAX_MIB_SIZE * sbr * cm->mi_stride + MAX_MIB_SIZE * sbc;
|
||||
}
|
||||
}
|
||||
sb_count++;
|
||||
}
|
||||
}
|
||||
nb_strength_bits = 0;
|
||||
/* Search for different number of signalling bits. */
|
||||
for (i = 0; i <= 3; i++) {
|
||||
int j;
|
||||
int best_lev0[CDEF_MAX_STRENGTHS];
|
||||
int best_lev1[CDEF_MAX_STRENGTHS] = { 0 };
|
||||
nb_strengths = 1 << i;
|
||||
if (nplanes >= 3)
|
||||
tot_mse = joint_strength_search_dual(best_lev0, best_lev1, nb_strengths,
|
||||
mse, sb_count);
|
||||
else
|
||||
tot_mse =
|
||||
joint_strength_search(best_lev0, nb_strengths, mse[0], sb_count);
|
||||
/* Count superblock signalling cost. */
|
||||
tot_mse += (uint64_t)(sb_count * lambda * i);
|
||||
/* Count header signalling cost. */
|
||||
tot_mse += (uint64_t)(nb_strengths * lambda * CDEF_STRENGTH_BITS);
|
||||
if (tot_mse < best_tot_mse) {
|
||||
best_tot_mse = tot_mse;
|
||||
nb_strength_bits = i;
|
||||
for (j = 0; j < 1 << nb_strength_bits; j++) {
|
||||
cm->cdef_strengths[j] = best_lev0[j];
|
||||
cm->cdef_uv_strengths[j] = best_lev1[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
nb_strengths = 1 << nb_strength_bits;
|
||||
|
||||
cm->cdef_bits = nb_strength_bits;
|
||||
cm->nb_cdef_strengths = nb_strengths;
|
||||
for (i = 0; i < sb_count; i++) {
|
||||
int gi;
|
||||
int best_gi;
|
||||
uint64_t best_mse = (uint64_t)1 << 63;
|
||||
best_gi = 0;
|
||||
for (gi = 0; gi < cm->nb_cdef_strengths; gi++) {
|
||||
uint64_t curr = mse[0][i][cm->cdef_strengths[gi]];
|
||||
if (nplanes >= 3) curr += mse[1][i][cm->cdef_uv_strengths[gi]];
|
||||
if (curr < best_mse) {
|
||||
best_gi = gi;
|
||||
best_mse = curr;
|
||||
}
|
||||
}
|
||||
selected_strength[i] = best_gi;
|
||||
cm->mi_grid_visible[sb_index[i]]->mbmi.cdef_strength = best_gi;
|
||||
}
|
||||
cm->cdef_dering_damping = dering_damping;
|
||||
cm->cdef_clpf_damping = clpf_damping;
|
||||
aom_free(mse[0]);
|
||||
aom_free(mse[1]);
|
||||
for (pli = 0; pli < nplanes; pli++) {
|
||||
aom_free(src[pli]);
|
||||
aom_free(ref_coeff[pli]);
|
||||
}
|
||||
aom_free(sb_index);
|
||||
aom_free(selected_strength);
|
||||
}
|
||||
211
third_party/aom/av1/encoder/picklpf.c
vendored
Normal file
211
third_party/aom/av1/encoder/picklpf.c
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "./aom_scale_rtcd.h"
|
||||
|
||||
#include "aom_dsp/psnr.h"
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "aom_ports/mem.h"
|
||||
|
||||
#include "av1/common/av1_loopfilter.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/common/quant_common.h"
|
||||
|
||||
#include "av1/encoder/av1_quantize.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/picklpf.h"
|
||||
|
||||
int av1_get_max_filter_level(const AV1_COMP *cpi) {
|
||||
if (cpi->oxcf.pass == 2) {
|
||||
return cpi->twopass.section_intra_rating > 8 ? MAX_LOOP_FILTER * 3 / 4
|
||||
: MAX_LOOP_FILTER;
|
||||
} else {
|
||||
return MAX_LOOP_FILTER;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd,
|
||||
AV1_COMP *const cpi, int filt_level,
|
||||
int partial_frame) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
int64_t filt_err;
|
||||
|
||||
#if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
|
||||
av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level, 1,
|
||||
partial_frame);
|
||||
#else
|
||||
if (cpi->num_workers > 1)
|
||||
av1_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
|
||||
av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level,
|
||||
1, partial_frame);
|
||||
#endif
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
if (cm->use_highbitdepth) {
|
||||
filt_err = aom_highbd_get_y_sse(sd, cm->frame_to_show);
|
||||
} else {
|
||||
filt_err = aom_get_y_sse(sd, cm->frame_to_show);
|
||||
}
|
||||
#else
|
||||
filt_err = aom_get_y_sse(sd, cm->frame_to_show);
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
|
||||
// Re-instate the unfiltered frame
|
||||
aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
|
||||
|
||||
return filt_err;
|
||||
}
|
||||
|
||||
int av1_search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
|
||||
int partial_frame, double *best_cost_ret) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
const struct loopfilter *const lf = &cm->lf;
|
||||
const int min_filter_level = 0;
|
||||
const int max_filter_level = av1_get_max_filter_level(cpi);
|
||||
int filt_direction = 0;
|
||||
int64_t best_err;
|
||||
int filt_best;
|
||||
MACROBLOCK *x = &cpi->td.mb;
|
||||
|
||||
// Start the search at the previous frame filter level unless it is now out of
|
||||
// range.
|
||||
int filt_mid = clamp(lf->filter_level, min_filter_level, max_filter_level);
|
||||
int filter_step = filt_mid < 16 ? 4 : filt_mid / 4;
|
||||
// Sum squared error at each filter level
|
||||
int64_t ss_err[MAX_LOOP_FILTER + 1];
|
||||
|
||||
// Set each entry to -1
|
||||
memset(ss_err, 0xFF, sizeof(ss_err));
|
||||
|
||||
// Make a copy of the unfiltered / processed recon buffer
|
||||
aom_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 = AOMMIN(filt_mid + filter_step, max_filter_level);
|
||||
const int filt_low = AOMMAX(filt_mid - filter_step, min_filter_level);
|
||||
|
||||
// Bias against raising loop filter in favor of lowering it.
|
||||
int64_t bias = (best_err >> (15 - (filt_mid / 8))) * filter_step;
|
||||
|
||||
if ((cpi->oxcf.pass == 2) && (cpi->twopass.section_intra_rating < 20))
|
||||
bias = (bias * cpi->twopass.section_intra_rating) / 20;
|
||||
|
||||
// yx, bias less for large block size
|
||||
if (cm->tx_mode != ONLY_4X4) bias >>= 1;
|
||||
|
||||
if (filt_direction <= 0 && filt_low != filt_mid) {
|
||||
// Get Low filter error score
|
||||
if (ss_err[filt_low] < 0) {
|
||||
ss_err[filt_low] = try_filter_frame(sd, cpi, filt_low, partial_frame);
|
||||
}
|
||||
// If value is close to the best so far then bias towards a lower loop
|
||||
// filter value.
|
||||
if (ss_err[filt_low] < (best_err + bias)) {
|
||||
// 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);
|
||||
}
|
||||
// If value is significantly better than previous best, bias added against
|
||||
// raising filter value
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Update best error
|
||||
best_err = ss_err[filt_best];
|
||||
|
||||
if (best_cost_ret)
|
||||
*best_cost_ret = RDCOST_DBL(x->rdmult, x->rddiv, 0, best_err);
|
||||
return filt_best;
|
||||
}
|
||||
|
||||
void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
|
||||
LPF_PICK_METHOD method) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
struct loopfilter *const lf = &cm->lf;
|
||||
|
||||
lf->sharpness_level = cm->frame_type == KEY_FRAME ? 0 : cpi->oxcf.sharpness;
|
||||
|
||||
if (method == LPF_PICK_MINIMAL_LPF && lf->filter_level) {
|
||||
lf->filter_level = 0;
|
||||
} else if (method >= LPF_PICK_FROM_Q) {
|
||||
const int min_filter_level = 0;
|
||||
const int max_filter_level = av1_get_max_filter_level(cpi);
|
||||
const int q = av1_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_HIGHBITDEPTH
|
||||
int filt_guess;
|
||||
switch (cm->bit_depth) {
|
||||
case AOM_BITS_8:
|
||||
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
|
||||
break;
|
||||
case AOM_BITS_10:
|
||||
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 4060632, 20);
|
||||
break;
|
||||
case AOM_BITS_12:
|
||||
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 16242526, 22);
|
||||
break;
|
||||
default:
|
||||
assert(0 &&
|
||||
"bit_depth should be AOM_BITS_8, AOM_BITS_10 "
|
||||
"or AOM_BITS_12");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
int filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
if (cm->frame_type == KEY_FRAME) filt_guess -= 4;
|
||||
lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
|
||||
} else {
|
||||
lf->filter_level = av1_search_filter_level(
|
||||
sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL);
|
||||
}
|
||||
|
||||
#if CONFIG_EXT_TILE
|
||||
// TODO(any): 0 loopfilter level is only necessary if individual tile
|
||||
// decoding is required. We need to communicate this requirement to this
|
||||
// code and force loop filter level 0 only if required.
|
||||
if (cm->tile_encoding_mode) lf->filter_level = 0;
|
||||
#endif // CONFIG_EXT_TILE
|
||||
}
|
||||
32
third_party/aom/av1/encoder/picklpf.h
vendored
Normal file
32
third_party/aom/av1/encoder/picklpf.h
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_PICKLPF_H_
|
||||
#define AV1_ENCODER_PICKLPF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
struct yv12_buffer_config;
|
||||
struct AV1_COMP;
|
||||
int av1_get_max_filter_level(const AV1_COMP *cpi);
|
||||
int av1_search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
|
||||
int partial_frame, double *err);
|
||||
void av1_pick_filter_level(const struct yv12_buffer_config *sd,
|
||||
struct AV1_COMP *cpi, LPF_PICK_METHOD method);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_PICKLPF_H_
|
||||
1269
third_party/aom/av1/encoder/pickrst.c
vendored
Normal file
1269
third_party/aom/av1/encoder/pickrst.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
30
third_party/aom/av1/encoder/pickrst.h
vendored
Normal file
30
third_party/aom/av1/encoder/pickrst.h
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#ifndef AV1_ENCODER_PICKRST_H_
|
||||
#define AV1_ENCODER_PICKRST_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
struct yv12_buffer_config;
|
||||
struct AV1_COMP;
|
||||
|
||||
void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
|
||||
LPF_PICK_METHOD method);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_PICKRST_H_
|
||||
988
third_party/aom/av1/encoder/pvq_encoder.c
vendored
Normal file
988
third_party/aom/av1/encoder/pvq_encoder.c
vendored
Normal file
|
|
@ -0,0 +1,988 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "aom_dsp/entcode.h"
|
||||
#include "aom_dsp/entenc.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/odintrin.h"
|
||||
#include "av1/common/partition.h"
|
||||
#include "av1/common/pvq_state.h"
|
||||
#include "av1/encoder/encodemb.h"
|
||||
#include "av1/encoder/pvq_encoder.h"
|
||||
#include "aom_ports/system_state.h"
|
||||
|
||||
/*Shift to ensure that the upper bound (i.e. for the max blocksize) of the
|
||||
dot-product of the 1st band of chroma with the luma ref doesn't overflow.*/
|
||||
#define OD_CFL_FLIP_SHIFT (OD_LIMIT_BSIZE_MAX + 0)
|
||||
|
||||
void aom_write_symbol_pvq(aom_writer *w, int symb, aom_cdf_prob *cdf,
|
||||
int nsymbs) {
|
||||
if (cdf[0] == 0)
|
||||
aom_cdf_init_q15_1D(cdf, nsymbs, CDF_SIZE(nsymbs));
|
||||
aom_write_symbol(w, symb, cdf, nsymbs);
|
||||
}
|
||||
|
||||
static void aom_encode_pvq_codeword(aom_writer *w, od_pvq_codeword_ctx *adapt,
|
||||
const od_coeff *in, int n, int k) {
|
||||
int i;
|
||||
aom_encode_band_pvq_splits(w, adapt, in, n, k, 0);
|
||||
for (i = 0; i < n; i++) if (in[i]) aom_write_bit(w, in[i] < 0);
|
||||
}
|
||||
|
||||
/* Computes 1/sqrt(i) using a table for small values. */
|
||||
static double od_rsqrt_table(int i) {
|
||||
static double table[16] = {
|
||||
1.000000, 0.707107, 0.577350, 0.500000,
|
||||
0.447214, 0.408248, 0.377964, 0.353553,
|
||||
0.333333, 0.316228, 0.301511, 0.288675,
|
||||
0.277350, 0.267261, 0.258199, 0.250000};
|
||||
if (i <= 16) return table[i-1];
|
||||
else return 1./sqrt(i);
|
||||
}
|
||||
|
||||
/*Computes 1/sqrt(start+2*i+1) using a lookup table containing the results
|
||||
where 0 <= i < table_size.*/
|
||||
static double od_custom_rsqrt_dynamic_table(const double* table,
|
||||
const int table_size, const double start, const int i) {
|
||||
if (i < table_size) return table[i];
|
||||
else return od_rsqrt_table((int)(start + 2*i + 1));
|
||||
}
|
||||
|
||||
/*Fills tables used in od_custom_rsqrt_dynamic_table for a given start.*/
|
||||
static void od_fill_dynamic_rsqrt_table(double *table, const int table_size,
|
||||
const double start) {
|
||||
int i;
|
||||
for (i = 0; i < table_size; i++)
|
||||
table[i] = od_rsqrt_table((int)(start + 2*i + 1));
|
||||
}
|
||||
|
||||
/** Find the codepoint on the given PSphere closest to the desired
|
||||
* vector. Double-precision PVQ search just to make sure our tests
|
||||
* aren't limited by numerical accuracy.
|
||||
*
|
||||
* @param [in] xcoeff input vector to quantize (x in the math doc)
|
||||
* @param [in] n number of dimensions
|
||||
* @param [in] k number of pulses
|
||||
* @param [out] ypulse optimal codevector found (y in the math doc)
|
||||
* @param [out] g2 multiplier for the distortion (typically squared
|
||||
* gain units)
|
||||
* @param [in] pvq_norm_lambda enc->pvq_norm_lambda for quantized RDO
|
||||
* @param [in] prev_k number of pulses already in ypulse that we should
|
||||
* reuse for the search (or 0 for a new search)
|
||||
* @return cosine distance between x and y (between 0 and 1)
|
||||
*/
|
||||
double pvq_search_rdo_double_c(const od_val16 *xcoeff, int n, int k,
|
||||
od_coeff *ypulse, double g2, double pvq_norm_lambda, int prev_k) {
|
||||
int i, j;
|
||||
double xy;
|
||||
double yy;
|
||||
/* TODO - This blows our 8kB stack space budget and should be fixed when
|
||||
converting PVQ to fixed point. */
|
||||
double x[MAXN];
|
||||
double xx;
|
||||
double lambda;
|
||||
double norm_1;
|
||||
int rdo_pulses;
|
||||
double delta_rate;
|
||||
xx = xy = yy = 0;
|
||||
for (j = 0; j < n; j++) {
|
||||
x[j] = fabs((float)xcoeff[j]);
|
||||
xx += x[j]*x[j];
|
||||
}
|
||||
norm_1 = 1./sqrt(1e-30 + xx);
|
||||
lambda = pvq_norm_lambda/(1e-30 + g2);
|
||||
i = 0;
|
||||
if (prev_k > 0 && prev_k <= k) {
|
||||
/* We reuse pulses from a previous search so we don't have to search them
|
||||
again. */
|
||||
for (j = 0; j < n; j++) {
|
||||
ypulse[j] = abs(ypulse[j]);
|
||||
xy += x[j]*ypulse[j];
|
||||
yy += ypulse[j]*ypulse[j];
|
||||
i += ypulse[j];
|
||||
}
|
||||
}
|
||||
else if (k > 2) {
|
||||
double l1_norm;
|
||||
double l1_inv;
|
||||
l1_norm = 0;
|
||||
for (j = 0; j < n; j++) l1_norm += x[j];
|
||||
l1_inv = 1./OD_MAXF(l1_norm, 1e-100);
|
||||
for (j = 0; j < n; j++) {
|
||||
double tmp;
|
||||
tmp = k*x[j]*l1_inv;
|
||||
ypulse[j] = OD_MAXI(0, (int)floor(tmp));
|
||||
xy += x[j]*ypulse[j];
|
||||
yy += ypulse[j]*ypulse[j];
|
||||
i += ypulse[j];
|
||||
}
|
||||
}
|
||||
else OD_CLEAR(ypulse, n);
|
||||
|
||||
/* Only use RDO on the last few pulses. This not only saves CPU, but using
|
||||
RDO on all pulses actually makes the results worse for reasons I don't
|
||||
fully understand. */
|
||||
rdo_pulses = 1 + k/4;
|
||||
/* Rough assumption for now, the last position costs about 3 bits more than
|
||||
the first. */
|
||||
delta_rate = 3./n;
|
||||
/* Search one pulse at a time */
|
||||
for (; i < k - rdo_pulses; i++) {
|
||||
int pos;
|
||||
double best_xy;
|
||||
double best_yy;
|
||||
pos = 0;
|
||||
best_xy = -10;
|
||||
best_yy = 1;
|
||||
for (j = 0; j < n; j++) {
|
||||
double tmp_xy;
|
||||
double tmp_yy;
|
||||
tmp_xy = xy + x[j];
|
||||
tmp_yy = yy + 2*ypulse[j] + 1;
|
||||
tmp_xy *= tmp_xy;
|
||||
if (j == 0 || tmp_xy*best_yy > best_xy*tmp_yy) {
|
||||
best_xy = tmp_xy;
|
||||
best_yy = tmp_yy;
|
||||
pos = j;
|
||||
}
|
||||
}
|
||||
xy = xy + x[pos];
|
||||
yy = yy + 2*ypulse[pos] + 1;
|
||||
ypulse[pos]++;
|
||||
}
|
||||
/* Search last pulses with RDO. Distortion is D = (x-y)^2 = x^2 - 2*x*y + y^2
|
||||
and since x^2 and y^2 are constant, we just maximize x*y, plus a
|
||||
lambda*rate term. Note that since x and y aren't normalized here,
|
||||
we need to divide by sqrt(x^2)*sqrt(y^2). */
|
||||
for (; i < k; i++) {
|
||||
double rsqrt_table[4];
|
||||
int rsqrt_table_size = 4;
|
||||
int pos;
|
||||
double best_cost;
|
||||
pos = 0;
|
||||
best_cost = -1e5;
|
||||
/*Fill the small rsqrt lookup table with inputs relative to yy.
|
||||
Specifically, the table of n values is filled with
|
||||
rsqrt(yy + 1), rsqrt(yy + 2 + 1) .. rsqrt(yy + 2*(n-1) + 1).*/
|
||||
od_fill_dynamic_rsqrt_table(rsqrt_table, rsqrt_table_size, yy);
|
||||
for (j = 0; j < n; j++) {
|
||||
double tmp_xy;
|
||||
double tmp_yy;
|
||||
tmp_xy = xy + x[j];
|
||||
/*Calculate rsqrt(yy + 2*ypulse[j] + 1) using an optimized method.*/
|
||||
tmp_yy = od_custom_rsqrt_dynamic_table(rsqrt_table, rsqrt_table_size,
|
||||
yy, ypulse[j]);
|
||||
tmp_xy = 2*tmp_xy*norm_1*tmp_yy - lambda*j*delta_rate;
|
||||
if (j == 0 || tmp_xy > best_cost) {
|
||||
best_cost = tmp_xy;
|
||||
pos = j;
|
||||
}
|
||||
}
|
||||
xy = xy + x[pos];
|
||||
yy = yy + 2*ypulse[pos] + 1;
|
||||
ypulse[pos]++;
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
if (xcoeff[i] < 0) ypulse[i] = -ypulse[i];
|
||||
}
|
||||
return xy/(1e-100 + sqrt(xx*yy));
|
||||
}
|
||||
|
||||
/** Encodes the gain so that the return value increases with the
|
||||
* distance |x-ref|, so that we can encode a zero when x=ref. The
|
||||
* value x=0 is not covered because it is only allowed in the noref
|
||||
* case.
|
||||
*
|
||||
* @param [in] x quantized gain to encode
|
||||
* @param [in] ref quantized gain of the reference
|
||||
* @return interleave-encoded quantized gain value
|
||||
*/
|
||||
static int neg_interleave(int x, int ref) {
|
||||
if (x < ref) return -2*(x - ref) - 1;
|
||||
else if (x < 2*ref) return 2*(x - ref);
|
||||
else return x-1;
|
||||
}
|
||||
|
||||
int od_vector_is_null(const od_coeff *x, int len) {
|
||||
int i;
|
||||
for (i = 0; i < len; i++) if (x[i]) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static double od_pvq_rate(int qg, int icgr, int theta, int ts,
|
||||
const od_adapt_ctx *adapt, const od_coeff *y0, int k, int n, int speed) {
|
||||
double rate;
|
||||
if (k == 0) rate = 0;
|
||||
else if (speed > 0) {
|
||||
int i;
|
||||
int sum;
|
||||
double f;
|
||||
/* Compute "center of mass" of the pulse vector. */
|
||||
sum = 0;
|
||||
for (i = 0; i < n - (theta != -1); i++) sum += i*abs(y0[i]);
|
||||
f = sum/(double)(k*n);
|
||||
/* Estimates the number of bits it will cost to encode K pulses in
|
||||
N dimensions based on hand-tuned fit for bitrate vs K, N and
|
||||
"center of mass". */
|
||||
rate = (1 + .4*f)*n*OD_LOG2(1 + OD_MAXF(0, log(n*2*(1*f + .025))*k/n)) + 3;
|
||||
}
|
||||
else {
|
||||
aom_writer w;
|
||||
od_pvq_codeword_ctx cd;
|
||||
int tell;
|
||||
#if CONFIG_DAALA_EC
|
||||
od_ec_enc_init(&w.ec, 1000);
|
||||
#else
|
||||
# error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
OD_COPY(&cd, &adapt->pvq.pvq_codeword_ctx, 1);
|
||||
#if CONFIG_DAALA_EC
|
||||
tell = od_ec_enc_tell_frac(&w.ec);
|
||||
#else
|
||||
# error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
aom_encode_pvq_codeword(&w, &cd, y0, n - (theta != -1), k);
|
||||
#if CONFIG_DAALA_EC
|
||||
rate = (od_ec_enc_tell_frac(&w.ec)-tell)/8.;
|
||||
od_ec_enc_clear(&w.ec);
|
||||
#else
|
||||
# error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
}
|
||||
if (qg > 0 && theta >= 0) {
|
||||
/* Approximate cost of entropy-coding theta */
|
||||
rate += .9*OD_LOG2(ts);
|
||||
if (qg == icgr) rate -= .5;
|
||||
}
|
||||
return rate;
|
||||
}
|
||||
|
||||
#define MAX_PVQ_ITEMS (20)
|
||||
/* This stores the information about a PVQ search candidate, so we can sort
|
||||
based on K. */
|
||||
typedef struct {
|
||||
int gain;
|
||||
int k;
|
||||
od_val32 qtheta;
|
||||
int theta;
|
||||
int ts;
|
||||
od_val32 qcg;
|
||||
} pvq_search_item;
|
||||
|
||||
int items_compare(pvq_search_item *a, pvq_search_item *b) {
|
||||
/* Break ties in K with gain to ensure a stable sort.
|
||||
Otherwise, the order depends on qsort implementation. */
|
||||
return a->k == b->k ? a->gain - b->gain : a->k - b->k;
|
||||
}
|
||||
|
||||
/** Perform PVQ quantization with prediction, trying several
|
||||
* possible gains and angles. See draft-valin-videocodec-pvq and
|
||||
* http://jmvalin.ca/slides/pvq.pdf for more details.
|
||||
*
|
||||
* @param [out] out coefficients after quantization
|
||||
* @param [in] x0 coefficients before quantization
|
||||
* @param [in] r0 reference, aka predicted coefficients
|
||||
* @param [in] n number of dimensions
|
||||
* @param [in] q0 quantization step size
|
||||
* @param [out] y pulse vector (i.e. selected PVQ codevector)
|
||||
* @param [out] itheta angle between input and reference (-1 if noref)
|
||||
* @param [out] vk total number of pulses
|
||||
* @param [in] beta per-band activity masking beta param
|
||||
* @param [out] skip_diff distortion cost of skipping this block
|
||||
* (accumulated)
|
||||
* @param [in] is_keyframe whether we're encoding a keyframe
|
||||
* @param [in] pli plane index
|
||||
* @param [in] adapt probability adaptation context
|
||||
* @param [in] qm QM with magnitude compensation
|
||||
* @param [in] qm_inv Inverse of QM with magnitude compensation
|
||||
* @param [in] pvq_norm_lambda enc->pvq_norm_lambda for quantized RDO
|
||||
* @param [in] speed Make search faster by making approximations
|
||||
* @return gain index of the quatized gain
|
||||
*/
|
||||
static int pvq_theta(od_coeff *out, const od_coeff *x0, const od_coeff *r0,
|
||||
int n, int q0, od_coeff *y, int *itheta, int *vk,
|
||||
od_val16 beta, double *skip_diff, int is_keyframe, int pli,
|
||||
const od_adapt_ctx *adapt, const int16_t *qm, const int16_t *qm_inv,
|
||||
double pvq_norm_lambda, int speed) {
|
||||
od_val32 g;
|
||||
od_val32 gr;
|
||||
od_coeff y_tmp[MAXN + 3];
|
||||
int i;
|
||||
/* Number of pulses. */
|
||||
int k;
|
||||
/* Companded gain of x and reference, normalized to q. */
|
||||
od_val32 cg;
|
||||
od_val32 cgr;
|
||||
int icgr;
|
||||
int qg;
|
||||
/* Best RDO cost (D + lamdba*R) so far. */
|
||||
double best_cost;
|
||||
double dist0;
|
||||
/* Distortion (D) that corresponds to the best RDO cost. */
|
||||
double best_dist;
|
||||
double dist;
|
||||
/* Sign of Householder reflection. */
|
||||
int s;
|
||||
/* Dimension on which Householder reflects. */
|
||||
int m;
|
||||
od_val32 theta;
|
||||
double corr;
|
||||
int best_k;
|
||||
od_val32 best_qtheta;
|
||||
od_val32 gain_offset;
|
||||
int noref;
|
||||
double skip_dist;
|
||||
int cfl_enabled;
|
||||
int skip;
|
||||
double gain_weight;
|
||||
od_val16 x16[MAXN];
|
||||
od_val16 r16[MAXN];
|
||||
int xshift;
|
||||
int rshift;
|
||||
/* Give more weight to gain error when calculating the total distortion. */
|
||||
gain_weight = 1.0;
|
||||
OD_ASSERT(n > 1);
|
||||
corr = 0;
|
||||
#if !defined(OD_FLOAT_PVQ)
|
||||
/* Shift needed to make x fit in 16 bits even after rotation.
|
||||
This shift value is not normative (it can be changed without breaking
|
||||
the bitstream) */
|
||||
xshift = OD_MAXI(0, od_vector_log_mag(x0, n) - 15);
|
||||
/* Shift needed to make the reference fit in 15 bits, so that the Householder
|
||||
vector can fit in 16 bits.
|
||||
This shift value *is* normative, and has to match the decoder. */
|
||||
rshift = OD_MAXI(0, od_vector_log_mag(r0, n) - 14);
|
||||
#else
|
||||
xshift = 0;
|
||||
rshift = 0;
|
||||
#endif
|
||||
for (i = 0; i < n; i++) {
|
||||
#if defined(OD_FLOAT_PVQ)
|
||||
/*This is slightly different from the original float PVQ code,
|
||||
where the qm was applied in the accumulation in od_pvq_compute_gain and
|
||||
the vectors were od_coeffs, not od_val16 (i.e. double).*/
|
||||
x16[i] = x0[i]*(double)qm[i]*OD_QM_SCALE_1;
|
||||
r16[i] = r0[i]*(double)qm[i]*OD_QM_SCALE_1;
|
||||
#else
|
||||
x16[i] = OD_SHR_ROUND(x0[i]*qm[i], OD_QM_SHIFT + xshift);
|
||||
r16[i] = OD_SHR_ROUND(r0[i]*qm[i], OD_QM_SHIFT + rshift);
|
||||
#endif
|
||||
corr += OD_MULT16_16(x16[i], r16[i]);
|
||||
}
|
||||
cfl_enabled = is_keyframe && pli != 0 && !OD_DISABLE_CFL;
|
||||
cg = od_pvq_compute_gain(x16, n, q0, &g, beta, xshift);
|
||||
cgr = od_pvq_compute_gain(r16, n, q0, &gr, beta, rshift);
|
||||
if (cfl_enabled) cgr = OD_CGAIN_SCALE;
|
||||
/* gain_offset is meant to make sure one of the quantized gains has
|
||||
exactly the same gain as the reference. */
|
||||
#if defined(OD_FLOAT_PVQ)
|
||||
icgr = (int)floor(.5 + cgr);
|
||||
#else
|
||||
icgr = OD_SHR_ROUND(cgr, OD_CGAIN_SHIFT);
|
||||
#endif
|
||||
gain_offset = cgr - OD_SHL(icgr, OD_CGAIN_SHIFT);
|
||||
/* Start search with null case: gain=0, no pulse. */
|
||||
qg = 0;
|
||||
dist = gain_weight*cg*cg*OD_CGAIN_SCALE_2;
|
||||
best_dist = dist;
|
||||
best_cost = dist + pvq_norm_lambda*od_pvq_rate(0, 0, -1, 0, adapt, NULL, 0,
|
||||
n, speed);
|
||||
noref = 1;
|
||||
best_k = 0;
|
||||
*itheta = -1;
|
||||
OD_CLEAR(y, n);
|
||||
best_qtheta = 0;
|
||||
m = 0;
|
||||
s = 1;
|
||||
corr = corr/(1e-100 + g*(double)gr/OD_SHL(1, xshift + rshift));
|
||||
corr = OD_MAXF(OD_MINF(corr, 1.), -1.);
|
||||
if (is_keyframe) skip_dist = gain_weight*cg*cg*OD_CGAIN_SCALE_2;
|
||||
else {
|
||||
skip_dist = gain_weight*(cg - cgr)*(cg - cgr)
|
||||
+ cgr*(double)cg*(2 - 2*corr);
|
||||
skip_dist *= OD_CGAIN_SCALE_2;
|
||||
}
|
||||
if (!is_keyframe) {
|
||||
/* noref, gain=0 isn't allowed, but skip is allowed. */
|
||||
od_val32 scgr;
|
||||
scgr = OD_MAXF(0,gain_offset);
|
||||
if (icgr == 0) {
|
||||
best_dist = gain_weight*(cg - scgr)*(cg - scgr)
|
||||
+ scgr*(double)cg*(2 - 2*corr);
|
||||
best_dist *= OD_CGAIN_SCALE_2;
|
||||
}
|
||||
best_cost = best_dist + pvq_norm_lambda*od_pvq_rate(0, icgr, 0, 0, adapt,
|
||||
NULL, 0, n, speed);
|
||||
best_qtheta = 0;
|
||||
*itheta = 0;
|
||||
noref = 0;
|
||||
}
|
||||
dist0 = best_dist;
|
||||
if (n <= OD_MAX_PVQ_SIZE && !od_vector_is_null(r0, n) && corr > 0) {
|
||||
od_val16 xr[MAXN];
|
||||
int gain_bound;
|
||||
int prev_k;
|
||||
pvq_search_item items[MAX_PVQ_ITEMS];
|
||||
int idx;
|
||||
int nitems;
|
||||
double cos_dist;
|
||||
idx = 0;
|
||||
gain_bound = OD_SHR(cg - gain_offset, OD_CGAIN_SHIFT);
|
||||
/* Perform theta search only if prediction is useful. */
|
||||
theta = OD_ROUND32(OD_THETA_SCALE*acos(corr));
|
||||
m = od_compute_householder(r16, n, gr, &s, rshift);
|
||||
od_apply_householder(xr, x16, r16, n);
|
||||
prev_k = 0;
|
||||
for (i = m; i < n - 1; i++) xr[i] = xr[i + 1];
|
||||
/* Compute all candidate PVQ searches within a reasonable range of gain
|
||||
and theta. */
|
||||
for (i = OD_MAXI(1, gain_bound - 1); i <= gain_bound + 1; i++) {
|
||||
int j;
|
||||
od_val32 qcg;
|
||||
int ts;
|
||||
int theta_lower;
|
||||
int theta_upper;
|
||||
/* Quantized companded gain */
|
||||
qcg = OD_SHL(i, OD_CGAIN_SHIFT) + gain_offset;
|
||||
/* Set angular resolution (in ra) to match the encoded gain */
|
||||
ts = od_pvq_compute_max_theta(qcg, beta);
|
||||
theta_lower = OD_MAXI(0, (int)floor(.5 +
|
||||
theta*OD_THETA_SCALE_1*2/M_PI*ts) - 2);
|
||||
theta_upper = OD_MINI(ts - 1, (int)ceil(theta*OD_THETA_SCALE_1*2/M_PI*ts));
|
||||
/* Include the angles within a reasonable range. */
|
||||
for (j = theta_lower; j <= theta_upper; j++) {
|
||||
od_val32 qtheta;
|
||||
qtheta = od_pvq_compute_theta(j, ts);
|
||||
k = od_pvq_compute_k(qcg, j, 0, n, beta);
|
||||
items[idx].gain = i;
|
||||
items[idx].theta = j;
|
||||
items[idx].k = k;
|
||||
items[idx].qcg = qcg;
|
||||
items[idx].qtheta = qtheta;
|
||||
items[idx].ts = ts;
|
||||
idx++;
|
||||
OD_ASSERT(idx < MAX_PVQ_ITEMS);
|
||||
}
|
||||
}
|
||||
nitems = idx;
|
||||
cos_dist = 0;
|
||||
/* Sort PVQ search candidates in ascending order of pulses K so that
|
||||
we can reuse all the previously searched pulses across searches. */
|
||||
qsort(items, nitems, sizeof(items[0]),
|
||||
(int (*)(const void *, const void *))items_compare);
|
||||
/* Search for the best gain/theta in order. */
|
||||
for (idx = 0; idx < nitems; idx++) {
|
||||
int j;
|
||||
od_val32 qcg;
|
||||
int ts;
|
||||
double cost;
|
||||
double dist_theta;
|
||||
double sin_prod;
|
||||
od_val32 qtheta;
|
||||
/* Quantized companded gain */
|
||||
qcg = items[idx].qcg;
|
||||
i = items[idx].gain;
|
||||
j = items[idx].theta;
|
||||
/* Set angular resolution (in ra) to match the encoded gain */
|
||||
ts = items[idx].ts;
|
||||
/* Search for the best angle within a reasonable range. */
|
||||
qtheta = items[idx].qtheta;
|
||||
k = items[idx].k;
|
||||
/* Compute the minimal possible distortion by not taking the PVQ
|
||||
cos_dist into account. */
|
||||
dist_theta = 2 - 2.*od_pvq_cos(theta - qtheta)*OD_TRIG_SCALE_1;
|
||||
dist = gain_weight*(qcg - cg)*(qcg - cg) + qcg*(double)cg*dist_theta;
|
||||
dist *= OD_CGAIN_SCALE_2;
|
||||
/* If we have no hope of beating skip (including a 1-bit worst-case
|
||||
penalty), stop now. */
|
||||
if (dist > dist0 + 1.0*pvq_norm_lambda && k != 0) continue;
|
||||
sin_prod = od_pvq_sin(theta)*OD_TRIG_SCALE_1*od_pvq_sin(qtheta)*
|
||||
OD_TRIG_SCALE_1;
|
||||
/* PVQ search, using a gain of qcg*cg*sin(theta)*sin(qtheta) since
|
||||
that's the factor by which cos_dist is multiplied to get the
|
||||
distortion metric. */
|
||||
if (k == 0) {
|
||||
cos_dist = 0;
|
||||
OD_CLEAR(y_tmp, n-1);
|
||||
}
|
||||
else if (k != prev_k) {
|
||||
cos_dist = pvq_search_rdo_double(xr, n - 1, k, y_tmp,
|
||||
qcg*(double)cg*sin_prod*OD_CGAIN_SCALE_2, pvq_norm_lambda, prev_k);
|
||||
}
|
||||
prev_k = k;
|
||||
/* See Jmspeex' Journal of Dubious Theoretical Results. */
|
||||
dist_theta = 2 - 2.*od_pvq_cos(theta - qtheta)*OD_TRIG_SCALE_1
|
||||
+ sin_prod*(2 - 2*cos_dist);
|
||||
dist = gain_weight*(qcg - cg)*(qcg - cg) + qcg*(double)cg*dist_theta;
|
||||
dist *= OD_CGAIN_SCALE_2;
|
||||
/* Do approximate RDO. */
|
||||
cost = dist + pvq_norm_lambda*od_pvq_rate(i, icgr, j, ts, adapt, y_tmp,
|
||||
k, n, speed);
|
||||
if (cost < best_cost) {
|
||||
best_cost = cost;
|
||||
best_dist = dist;
|
||||
qg = i;
|
||||
best_k = k;
|
||||
best_qtheta = qtheta;
|
||||
*itheta = j;
|
||||
noref = 0;
|
||||
OD_COPY(y, y_tmp, n - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Don't bother with no-reference version if there's a reasonable
|
||||
correlation. */
|
||||
if (n <= OD_MAX_PVQ_SIZE && (corr < .5
|
||||
|| cg < (od_val32)(OD_SHL(2, OD_CGAIN_SHIFT)))) {
|
||||
int gain_bound;
|
||||
int prev_k;
|
||||
gain_bound = OD_SHR(cg, OD_CGAIN_SHIFT);
|
||||
prev_k = 0;
|
||||
/* Search for the best gain (haven't determined reasonable range yet). */
|
||||
for (i = OD_MAXI(1, gain_bound); i <= gain_bound + 1; i++) {
|
||||
double cos_dist;
|
||||
double cost;
|
||||
od_val32 qcg;
|
||||
qcg = OD_SHL(i, OD_CGAIN_SHIFT);
|
||||
k = od_pvq_compute_k(qcg, -1, 1, n, beta);
|
||||
/* Compute the minimal possible distortion by not taking the PVQ
|
||||
cos_dist into account. */
|
||||
dist = gain_weight*(qcg - cg)*(qcg - cg);
|
||||
dist *= OD_CGAIN_SCALE_2;
|
||||
if (dist > dist0 && k != 0) continue;
|
||||
cos_dist = pvq_search_rdo_double(x16, n, k, y_tmp,
|
||||
qcg*(double)cg*OD_CGAIN_SCALE_2, pvq_norm_lambda, prev_k);
|
||||
prev_k = k;
|
||||
/* See Jmspeex' Journal of Dubious Theoretical Results. */
|
||||
dist = gain_weight*(qcg - cg)*(qcg - cg)
|
||||
+ qcg*(double)cg*(2 - 2*cos_dist);
|
||||
dist *= OD_CGAIN_SCALE_2;
|
||||
/* Do approximate RDO. */
|
||||
cost = dist + pvq_norm_lambda*od_pvq_rate(i, 0, -1, 0, adapt, y_tmp, k,
|
||||
n, speed);
|
||||
if (cost <= best_cost) {
|
||||
best_cost = cost;
|
||||
best_dist = dist;
|
||||
qg = i;
|
||||
noref = 1;
|
||||
best_k = k;
|
||||
*itheta = -1;
|
||||
OD_COPY(y, y_tmp, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
k = best_k;
|
||||
theta = best_qtheta;
|
||||
skip = 0;
|
||||
if (noref) {
|
||||
if (qg == 0) skip = OD_PVQ_SKIP_ZERO;
|
||||
}
|
||||
else {
|
||||
if (!is_keyframe && qg == 0) {
|
||||
skip = (icgr ? OD_PVQ_SKIP_ZERO : OD_PVQ_SKIP_COPY);
|
||||
}
|
||||
if (qg == icgr && *itheta == 0 && !cfl_enabled) skip = OD_PVQ_SKIP_COPY;
|
||||
}
|
||||
/* Synthesize like the decoder would. */
|
||||
if (skip) {
|
||||
if (skip == OD_PVQ_SKIP_COPY) OD_COPY(out, r0, n);
|
||||
else OD_CLEAR(out, n);
|
||||
}
|
||||
else {
|
||||
if (noref) gain_offset = 0;
|
||||
g = od_gain_expand(OD_SHL(qg, OD_CGAIN_SHIFT) + gain_offset, q0, beta);
|
||||
od_pvq_synthesis_partial(out, y, r16, n, noref, g, theta, m, s,
|
||||
qm_inv);
|
||||
}
|
||||
*vk = k;
|
||||
*skip_diff += skip_dist - best_dist;
|
||||
/* Encode gain differently depending on whether we use prediction or not.
|
||||
Special encoding on inter frames where qg=0 is allowed for noref=0
|
||||
but not noref=1.*/
|
||||
if (is_keyframe) return noref ? qg : neg_interleave(qg, icgr);
|
||||
else return noref ? qg - 1 : neg_interleave(qg + 1, icgr + 1);
|
||||
}
|
||||
|
||||
/** Encodes a single vector of integers (eg, a partition within a
|
||||
* coefficient block) using PVQ
|
||||
*
|
||||
* @param [in,out] w multi-symbol entropy encoder
|
||||
* @param [in] qg quantized gain
|
||||
* @param [in] theta quantized post-prediction theta
|
||||
* @param [in] in coefficient vector to code
|
||||
* @param [in] n number of coefficients in partition
|
||||
* @param [in] k number of pulses in partition
|
||||
* @param [in,out] model entropy encoder state
|
||||
* @param [in,out] adapt adaptation context
|
||||
* @param [in,out] exg ExQ16 expectation of gain value
|
||||
* @param [in,out] ext ExQ16 expectation of theta value
|
||||
* @param [in] cdf_ctx selects which cdf context to use
|
||||
* @param [in] is_keyframe whether we're encoding a keyframe
|
||||
* @param [in] code_skip whether the "skip rest" flag is allowed
|
||||
* @param [in] skip_rest when set, we skip all higher bands
|
||||
* @param [in] encode_flip whether we need to encode the CfL flip flag now
|
||||
* @param [in] flip value of the CfL flip flag
|
||||
*/
|
||||
void pvq_encode_partition(aom_writer *w,
|
||||
int qg,
|
||||
int theta,
|
||||
const od_coeff *in,
|
||||
int n,
|
||||
int k,
|
||||
generic_encoder model[3],
|
||||
od_adapt_ctx *adapt,
|
||||
int *exg,
|
||||
int *ext,
|
||||
int cdf_ctx,
|
||||
int is_keyframe,
|
||||
int code_skip,
|
||||
int skip_rest,
|
||||
int encode_flip,
|
||||
int flip) {
|
||||
int noref;
|
||||
int id;
|
||||
noref = (theta == -1);
|
||||
id = (qg > 0) + 2*OD_MINI(theta + 1,3) + 8*code_skip*skip_rest;
|
||||
if (is_keyframe) {
|
||||
OD_ASSERT(id != 8);
|
||||
if (id >= 8) id--;
|
||||
}
|
||||
else {
|
||||
OD_ASSERT(id != 10);
|
||||
if (id >= 10) id--;
|
||||
}
|
||||
/* Jointly code gain, theta and noref for small values. Then we handle
|
||||
larger gain and theta values. For noref, theta = -1. */
|
||||
aom_write_symbol_pvq(w, id, &adapt->pvq.pvq_gaintheta_cdf[cdf_ctx][0],
|
||||
8 + 7*code_skip);
|
||||
if (encode_flip) {
|
||||
/* We could eventually do some smarter entropy coding here, but it would
|
||||
have to be good enough to overcome the overhead of the entropy coder.
|
||||
An early attempt using a "toogle" flag with simple adaptation wasn't
|
||||
worth the trouble. */
|
||||
aom_write_bit(w, flip);
|
||||
}
|
||||
if (qg > 0) {
|
||||
int tmp;
|
||||
tmp = *exg;
|
||||
generic_encode(w, &model[!noref], qg - 1, &tmp, 2);
|
||||
OD_IIR_DIADIC(*exg, qg << 16, 2);
|
||||
}
|
||||
if (theta > 1) {
|
||||
int tmp;
|
||||
tmp = *ext;
|
||||
generic_encode(w, &model[2], theta - 2, &tmp, 2);
|
||||
OD_IIR_DIADIC(*ext, theta << 16, 2);
|
||||
}
|
||||
aom_encode_pvq_codeword(w, &adapt->pvq.pvq_codeword_ctx, in,
|
||||
n - (theta != -1), k);
|
||||
}
|
||||
|
||||
/** Quantizes a scalar with rate-distortion optimization (RDO)
|
||||
* @param [in] x unquantized value
|
||||
* @param [in] q quantization step size
|
||||
* @param [in] delta0 rate increase for encoding a 1 instead of a 0
|
||||
* @param [in] pvq_norm_lambda enc->pvq_norm_lambda for quantized RDO
|
||||
* @retval quantized value
|
||||
*/
|
||||
int od_rdo_quant(od_coeff x, int q, double delta0, double pvq_norm_lambda) {
|
||||
int n;
|
||||
/* Optimal quantization threshold is 1/2 + lambda*delta_rate/2. See
|
||||
Jmspeex' Journal of Dubious Theoretical Results for details. */
|
||||
n = OD_DIV_R0(abs(x), q);
|
||||
if ((double)abs(x)/q < (double)n/2 + pvq_norm_lambda*delta0/(2*n)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return OD_DIV_R0(x, q);
|
||||
}
|
||||
}
|
||||
|
||||
/** Encode a coefficient block (excepting DC) using PVQ
|
||||
*
|
||||
* @param [in,out] enc daala encoder context
|
||||
* @param [in] ref 'reference' (prediction) vector
|
||||
* @param [in] in coefficient block to quantize and encode
|
||||
* @param [out] out quantized coefficient block
|
||||
* @param [in] q0 scale/quantizer
|
||||
* @param [in] pli plane index
|
||||
* @param [in] bs log of the block size minus two
|
||||
* @param [in] beta per-band activity masking beta param
|
||||
* @param [in] is_keyframe whether we're encoding a keyframe
|
||||
* @param [in] qm QM with magnitude compensation
|
||||
* @param [in] qm_inv Inverse of QM with magnitude compensation
|
||||
* @param [in] speed Make search faster by making approximations
|
||||
* @param [in] pvq_info If null, conisdered as RDO search mode
|
||||
* @return Returns block skip info indicating whether DC/AC are coded.
|
||||
* bit0: DC is coded, bit1: AC is coded (1 means coded)
|
||||
*
|
||||
*/
|
||||
PVQ_SKIP_TYPE od_pvq_encode(daala_enc_ctx *enc,
|
||||
od_coeff *ref,
|
||||
const od_coeff *in,
|
||||
od_coeff *out,
|
||||
int q_dc,
|
||||
int q_ac,
|
||||
int pli,
|
||||
int bs,
|
||||
const od_val16 *beta,
|
||||
int is_keyframe,
|
||||
const int16_t *qm,
|
||||
const int16_t *qm_inv,
|
||||
int speed,
|
||||
PVQ_INFO *pvq_info){
|
||||
int theta[PVQ_MAX_PARTITIONS];
|
||||
int qg[PVQ_MAX_PARTITIONS];
|
||||
int k[PVQ_MAX_PARTITIONS];
|
||||
od_coeff y[OD_TXSIZE_MAX*OD_TXSIZE_MAX];
|
||||
int *exg;
|
||||
int *ext;
|
||||
int nb_bands;
|
||||
int i;
|
||||
const int *off;
|
||||
int size[PVQ_MAX_PARTITIONS];
|
||||
generic_encoder *model;
|
||||
double skip_diff;
|
||||
int tell;
|
||||
uint16_t *skip_cdf;
|
||||
od_rollback_buffer buf;
|
||||
int dc_quant;
|
||||
int flip;
|
||||
int cfl_encoded;
|
||||
int skip_rest;
|
||||
int skip_dir;
|
||||
int skip_theta_value;
|
||||
const unsigned char *pvq_qm;
|
||||
double dc_rate;
|
||||
int use_masking;
|
||||
PVQ_SKIP_TYPE ac_dc_coded;
|
||||
|
||||
aom_clear_system_state();
|
||||
|
||||
use_masking = enc->use_activity_masking;
|
||||
|
||||
if (use_masking)
|
||||
pvq_qm = &enc->state.pvq_qm_q4[pli][0];
|
||||
else
|
||||
pvq_qm = 0;
|
||||
|
||||
exg = &enc->state.adapt->pvq.pvq_exg[pli][bs][0];
|
||||
ext = enc->state.adapt->pvq.pvq_ext + bs*PVQ_MAX_PARTITIONS;
|
||||
skip_cdf = enc->state.adapt->skip_cdf[2*bs + (pli != 0)];
|
||||
model = enc->state.adapt->pvq.pvq_param_model;
|
||||
nb_bands = OD_BAND_OFFSETS[bs][0];
|
||||
off = &OD_BAND_OFFSETS[bs][1];
|
||||
|
||||
if (use_masking)
|
||||
dc_quant = OD_MAXI(1, q_dc * pvq_qm[od_qm_get_index(bs, 0)] >> 4);
|
||||
else
|
||||
dc_quant = OD_MAXI(1, q_dc);
|
||||
|
||||
tell = 0;
|
||||
for (i = 0; i < nb_bands; i++) size[i] = off[i+1] - off[i];
|
||||
skip_diff = 0;
|
||||
flip = 0;
|
||||
/*If we are coding a chroma block of a keyframe, we are doing CfL.*/
|
||||
if (pli != 0 && is_keyframe) {
|
||||
od_val32 xy;
|
||||
xy = 0;
|
||||
/*Compute the dot-product of the first band of chroma with the luma ref.*/
|
||||
for (i = off[0]; i < off[1]; i++) {
|
||||
#if defined(OD_FLOAT_PVQ)
|
||||
xy += ref[i]*(double)qm[i]*OD_QM_SCALE_1*
|
||||
(double)in[i]*(double)qm[i]*OD_QM_SCALE_1;
|
||||
#else
|
||||
od_val32 rq;
|
||||
od_val32 inq;
|
||||
rq = ref[i]*qm[i];
|
||||
inq = in[i]*qm[i];
|
||||
xy += OD_SHR(rq*(int64_t)inq, OD_SHL(OD_QM_SHIFT + OD_CFL_FLIP_SHIFT,
|
||||
1));
|
||||
#endif
|
||||
}
|
||||
/*If cos(theta) < 0, then |theta| > pi/2 and we should negate the ref.*/
|
||||
if (xy < 0) {
|
||||
flip = 1;
|
||||
for(i = off[0]; i < off[nb_bands]; i++) ref[i] = -ref[i];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < nb_bands; i++) {
|
||||
int q;
|
||||
|
||||
if (use_masking)
|
||||
q = OD_MAXI(1, q_ac * pvq_qm[od_qm_get_index(bs, i + 1)] >> 4);
|
||||
else
|
||||
q = OD_MAXI(1, q_ac);
|
||||
|
||||
qg[i] = pvq_theta(out + off[i], in + off[i], ref + off[i], size[i],
|
||||
q, y + off[i], &theta[i], &k[i], beta[i], &skip_diff, is_keyframe,
|
||||
pli, enc->state.adapt, qm + off[i], qm_inv + off[i],
|
||||
enc->pvq_norm_lambda, speed);
|
||||
}
|
||||
od_encode_checkpoint(enc, &buf);
|
||||
if (is_keyframe) out[0] = 0;
|
||||
else {
|
||||
int n;
|
||||
n = OD_DIV_R0(abs(in[0] - ref[0]), dc_quant);
|
||||
if (n == 0) {
|
||||
out[0] = 0;
|
||||
} else {
|
||||
int tell2;
|
||||
od_rollback_buffer dc_buf;
|
||||
|
||||
dc_rate = -OD_LOG2((double)(skip_cdf[3] - skip_cdf[2])/
|
||||
(double)(skip_cdf[2] - skip_cdf[1]));
|
||||
dc_rate += 1;
|
||||
|
||||
#if CONFIG_DAALA_EC
|
||||
tell2 = od_ec_enc_tell_frac(&enc->w.ec);
|
||||
#else
|
||||
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
od_encode_checkpoint(enc, &dc_buf);
|
||||
generic_encode(&enc->w, &enc->state.adapt->model_dc[pli],
|
||||
n - 1, &enc->state.adapt->ex_dc[pli][bs][0], 2);
|
||||
#if CONFIG_DAALA_EC
|
||||
tell2 = od_ec_enc_tell_frac(&enc->w.ec) - tell2;
|
||||
#else
|
||||
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
dc_rate += tell2/8.0;
|
||||
od_encode_rollback(enc, &dc_buf);
|
||||
|
||||
out[0] = od_rdo_quant(in[0] - ref[0], dc_quant, dc_rate,
|
||||
enc->pvq_norm_lambda);
|
||||
}
|
||||
}
|
||||
#if CONFIG_DAALA_EC
|
||||
tell = od_ec_enc_tell_frac(&enc->w.ec);
|
||||
#else
|
||||
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
/* Code as if we're not skipping. */
|
||||
aom_write_symbol(&enc->w, 2 + (out[0] != 0), skip_cdf, 4);
|
||||
ac_dc_coded = AC_CODED + (out[0] != 0);
|
||||
cfl_encoded = 0;
|
||||
skip_rest = 1;
|
||||
skip_theta_value = is_keyframe ? -1 : 0;
|
||||
for (i = 1; i < nb_bands; i++) {
|
||||
if (theta[i] != skip_theta_value || qg[i]) skip_rest = 0;
|
||||
}
|
||||
skip_dir = 0;
|
||||
if (nb_bands > 1) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
int j;
|
||||
int tmp;
|
||||
tmp = 1;
|
||||
// ToDo(yaowu): figure out better stop condition without gcc warning.
|
||||
for (j = i + 1; j < nb_bands && j < PVQ_MAX_PARTITIONS; j += 3) {
|
||||
if (theta[j] != skip_theta_value || qg[j]) tmp = 0;
|
||||
}
|
||||
skip_dir |= tmp << i;
|
||||
}
|
||||
}
|
||||
if (theta[0] == skip_theta_value && qg[0] == 0 && skip_rest) nb_bands = 0;
|
||||
|
||||
/* NOTE: There was no other better place to put this function. */
|
||||
if (pvq_info)
|
||||
av1_store_pvq_enc_info(pvq_info, qg, theta, k, y, nb_bands, off, size,
|
||||
skip_rest, skip_dir, bs);
|
||||
|
||||
for (i = 0; i < nb_bands; i++) {
|
||||
int encode_flip;
|
||||
/* Encode CFL flip bit just after the first time it's used. */
|
||||
encode_flip = pli != 0 && is_keyframe && theta[i] != -1 && !cfl_encoded;
|
||||
if (i == 0 || (!skip_rest && !(skip_dir & (1 << ((i - 1)%3))))) {
|
||||
pvq_encode_partition(&enc->w, qg[i], theta[i], y + off[i],
|
||||
size[i], k[i], model, enc->state.adapt, exg + i, ext + i,
|
||||
(pli != 0)*OD_TXSIZES*PVQ_MAX_PARTITIONS + bs*PVQ_MAX_PARTITIONS + i,
|
||||
is_keyframe, i == 0 && (i < nb_bands - 1), skip_rest, encode_flip, flip);
|
||||
}
|
||||
if (i == 0 && !skip_rest && bs > 0) {
|
||||
aom_write_symbol(&enc->w, skip_dir,
|
||||
&enc->state.adapt->pvq.pvq_skip_dir_cdf[(pli != 0) + 2*(bs - 1)][0], 7);
|
||||
}
|
||||
if (encode_flip) cfl_encoded = 1;
|
||||
}
|
||||
#if CONFIG_DAALA_EC
|
||||
tell = od_ec_enc_tell_frac(&enc->w.ec) - tell;
|
||||
#else
|
||||
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
/* Account for the rate of skipping the AC, based on the same DC decision
|
||||
we made when trying to not skip AC. */
|
||||
{
|
||||
double skip_rate;
|
||||
if (out[0] != 0) {
|
||||
skip_rate = -OD_LOG2((skip_cdf[1] - skip_cdf[0])/
|
||||
(double)skip_cdf[3]);
|
||||
}
|
||||
else {
|
||||
skip_rate = -OD_LOG2(skip_cdf[0]/
|
||||
(double)skip_cdf[3]);
|
||||
}
|
||||
tell -= (int)floor(.5+8*skip_rate);
|
||||
}
|
||||
if (nb_bands == 0 || skip_diff <= enc->pvq_norm_lambda/8*tell) {
|
||||
if (is_keyframe) out[0] = 0;
|
||||
else {
|
||||
int n;
|
||||
n = OD_DIV_R0(abs(in[0] - ref[0]), dc_quant);
|
||||
if (n == 0) {
|
||||
out[0] = 0;
|
||||
} else {
|
||||
int tell2;
|
||||
od_rollback_buffer dc_buf;
|
||||
|
||||
dc_rate = -OD_LOG2((double)(skip_cdf[1] - skip_cdf[0])/
|
||||
(double)skip_cdf[0]);
|
||||
dc_rate += 1;
|
||||
|
||||
#if CONFIG_DAALA_EC
|
||||
tell2 = od_ec_enc_tell_frac(&enc->w.ec);
|
||||
#else
|
||||
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
od_encode_checkpoint(enc, &dc_buf);
|
||||
generic_encode(&enc->w, &enc->state.adapt->model_dc[pli],
|
||||
n - 1, &enc->state.adapt->ex_dc[pli][bs][0], 2);
|
||||
#if CONFIG_DAALA_EC
|
||||
tell2 = od_ec_enc_tell_frac(&enc->w.ec) - tell2;
|
||||
#else
|
||||
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
|
||||
#endif
|
||||
dc_rate += tell2/8.0;
|
||||
od_encode_rollback(enc, &dc_buf);
|
||||
|
||||
out[0] = od_rdo_quant(in[0] - ref[0], dc_quant, dc_rate,
|
||||
enc->pvq_norm_lambda);
|
||||
}
|
||||
}
|
||||
/* We decide to skip, roll back everything as it was before. */
|
||||
od_encode_rollback(enc, &buf);
|
||||
aom_write_symbol(&enc->w, out[0] != 0, skip_cdf, 4);
|
||||
ac_dc_coded = (out[0] != 0);
|
||||
if (is_keyframe) for (i = 1; i < 1 << (2*bs + 4); i++) out[i] = 0;
|
||||
else for (i = 1; i < 1 << (2*bs + 4); i++) out[i] = ref[i];
|
||||
}
|
||||
if (pvq_info)
|
||||
pvq_info->ac_dc_coded = ac_dc_coded;
|
||||
return ac_dc_coded;
|
||||
}
|
||||
53
third_party/aom/av1/encoder/pvq_encoder.h
vendored
Normal file
53
third_party/aom/av1/encoder/pvq_encoder.h
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#if !defined(_pvq_encoder_H)
|
||||
# define _pvq_encoder_H (1)
|
||||
# include "aom_dsp/bitwriter.h"
|
||||
# include "aom_dsp/entenc.h"
|
||||
# include "av1/common/blockd.h"
|
||||
# include "av1/common/pvq.h"
|
||||
# include "av1/encoder/encint.h"
|
||||
|
||||
void aom_write_symbol_pvq(aom_writer *w, int symb, aom_cdf_prob *cdf,
|
||||
int nsymbs);
|
||||
|
||||
void aom_encode_band_pvq_splits(aom_writer *w, od_pvq_codeword_ctx *adapt,
|
||||
const int *y, int n, int k, int level);
|
||||
|
||||
void aom_laplace_encode_special(aom_writer *w, int x, unsigned decay);
|
||||
|
||||
void pvq_encode_partition(aom_writer *w,
|
||||
int qg,
|
||||
int theta,
|
||||
const od_coeff *in,
|
||||
int n,
|
||||
int k,
|
||||
generic_encoder model[3],
|
||||
od_adapt_ctx *adapt,
|
||||
int *exg,
|
||||
int *ext,
|
||||
int cdf_ctx,
|
||||
int is_keyframe,
|
||||
int code_skip,
|
||||
int skip_rest,
|
||||
int encode_flip,
|
||||
int flip);
|
||||
|
||||
PVQ_SKIP_TYPE od_pvq_encode(daala_enc_ctx *enc, od_coeff *ref,
|
||||
const od_coeff *in, od_coeff *out, int q_dc, int q_ac, int pli, int bs,
|
||||
const od_val16 *beta, int is_keyframe,
|
||||
const int16_t *qm, const int16_t *qm_inv, int speed,
|
||||
PVQ_INFO *pvq_info);
|
||||
|
||||
#endif
|
||||
1210
third_party/aom/av1/encoder/ransac.c
vendored
Normal file
1210
third_party/aom/av1/encoder/ransac.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
44
third_party/aom/av1/encoder/ransac.h
vendored
Normal file
44
third_party/aom/av1/encoder/ransac.h
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_RANSAC_H_
|
||||
#define AV1_ENCODER_RANSAC_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "av1/common/warped_motion.h"
|
||||
|
||||
typedef int (*RansacFunc)(int *matched_points, int npoints,
|
||||
int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions);
|
||||
|
||||
/* Each of these functions fits a motion model from a set of
|
||||
corresponding points in 2 frames using RANSAC. */
|
||||
int ransac_homography(int *matched_points, int npoints,
|
||||
int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions);
|
||||
int ransac_affine(int *matched_points, int npoints, int *num_inliers_by_motion,
|
||||
double *params_by_motion, int num_motions);
|
||||
int ransac_hortrapezoid(int *matched_points, int npoints,
|
||||
int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions);
|
||||
int ransac_vertrapezoid(int *matched_points, int npoints,
|
||||
int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions);
|
||||
int ransac_rotzoom(int *matched_points, int npoints, int *num_inliers_by_motion,
|
||||
double *params_by_motion, int num_motions);
|
||||
int ransac_translation(int *matched_points, int npoints,
|
||||
int *num_inliers_by_motion, double *params_by_motion,
|
||||
int num_motions);
|
||||
#endif // AV1_ENCODER_RANSAC_H_
|
||||
1759
third_party/aom/av1/encoder/ratectrl.c
vendored
Normal file
1759
third_party/aom/av1/encoder/ratectrl.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
284
third_party/aom/av1/encoder/ratectrl.h
vendored
Normal file
284
third_party/aom/av1/encoder/ratectrl.h
vendored
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_RATECTRL_H_
|
||||
#define AV1_ENCODER_RATECTRL_H_
|
||||
|
||||
#include "aom/aom_codec.h"
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
typedef enum {
|
||||
INTER_NORMAL = 0,
|
||||
INTER_LOW = 1,
|
||||
INTER_HIGH = 2,
|
||||
GF_ARF_LOW = 3,
|
||||
GF_ARF_STD = 4,
|
||||
KF_STD = 5,
|
||||
RATE_FACTOR_LEVELS = 6
|
||||
} RATE_FACTOR_LEVEL;
|
||||
#else
|
||||
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;
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
// Internal frame scaling level.
|
||||
typedef enum {
|
||||
UNSCALED = 0, // Frame is unscaled.
|
||||
SCALE_STEP1 = 1, // First-level down-scaling.
|
||||
FRAME_SCALE_STEPS
|
||||
} FRAME_SCALE_LEVEL;
|
||||
|
||||
// Frame dimensions multiplier wrt the native frame size, in 1/16ths,
|
||||
// specified for the scale-up case.
|
||||
// e.g. 24 => 16/24 = 2/3 of native size. The restriction to 1/16th is
|
||||
// intended to match the capabilities of the normative scaling filters,
|
||||
// giving precedence to the up-scaling accuracy.
|
||||
static const int frame_scale_factor[FRAME_SCALE_STEPS] = { 16, 24 };
|
||||
|
||||
// Multiplier of the target rate to be used as threshold for triggering scaling.
|
||||
static const double rate_thresh_mult[FRAME_SCALE_STEPS] = { 1.0, 2.0 };
|
||||
|
||||
// Scale dependent Rate Correction Factor multipliers. Compensates for the
|
||||
// greater number of bits per pixel generated in down-scaled frames.
|
||||
static const double rcf_mult[FRAME_SCALE_STEPS] = { 1.0, 2.0 };
|
||||
|
||||
typedef struct {
|
||||
// Rate targetting variables
|
||||
int base_frame_target; // A baseline frame target before adjustment
|
||||
// for previous under or over shoot.
|
||||
int this_frame_target; // Actual frame target after rc adjustment.
|
||||
int projected_frame_size;
|
||||
int sb64_target_rate;
|
||||
int last_q[FRAME_TYPES]; // Separate values for Intra/Inter
|
||||
int last_boosted_qindex; // Last boosted GF/KF/ARF q
|
||||
int last_kf_qindex; // Q index of the last key frame coded.
|
||||
|
||||
int gfu_boost;
|
||||
int last_boost;
|
||||
int kf_boost;
|
||||
|
||||
double rate_correction_factors[RATE_FACTOR_LEVELS];
|
||||
|
||||
int frames_since_golden;
|
||||
int frames_till_gf_update_due;
|
||||
int min_gf_interval;
|
||||
int max_gf_interval;
|
||||
int static_scene_max_gf_interval;
|
||||
int baseline_gf_interval;
|
||||
int constrained_gf_group;
|
||||
int frames_to_key;
|
||||
int frames_since_key;
|
||||
int this_key_frame_forced;
|
||||
int next_key_frame_forced;
|
||||
int source_alt_ref_pending;
|
||||
int source_alt_ref_active;
|
||||
int is_src_frame_alt_ref;
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
// Length of the bi-predictive frame group interval
|
||||
int bipred_group_interval;
|
||||
|
||||
// NOTE: Different types of frames may have different bits allocated
|
||||
// accordingly, aiming to achieve the overall optimal RD performance.
|
||||
int is_bwd_ref_frame;
|
||||
int is_last_bipred_frame;
|
||||
int is_bipred_frame;
|
||||
int is_src_frame_ext_arf;
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
int avg_frame_bandwidth; // Average frame size target for clip
|
||||
int min_frame_bandwidth; // Minimum allocation used for any frame
|
||||
int max_frame_bandwidth; // Maximum burst rate allowed for a frame.
|
||||
|
||||
int ni_av_qi;
|
||||
int ni_tot_qi;
|
||||
int ni_frames;
|
||||
int avg_frame_qindex[FRAME_TYPES];
|
||||
double tot_q;
|
||||
double avg_q;
|
||||
|
||||
int64_t buffer_level;
|
||||
int64_t bits_off_target;
|
||||
int64_t vbr_bits_off_target;
|
||||
int64_t vbr_bits_off_target_fast;
|
||||
|
||||
int decimation_factor;
|
||||
int decimation_count;
|
||||
|
||||
int rolling_target_bits;
|
||||
int rolling_actual_bits;
|
||||
|
||||
int long_rolling_target_bits;
|
||||
int long_rolling_actual_bits;
|
||||
|
||||
int rate_error_estimate;
|
||||
|
||||
int64_t total_actual_bits;
|
||||
int64_t total_target_bits;
|
||||
int64_t total_target_vs_actual;
|
||||
|
||||
int worst_quality;
|
||||
int best_quality;
|
||||
|
||||
int64_t starting_buffer_level;
|
||||
int64_t optimal_buffer_level;
|
||||
int64_t maximum_buffer_size;
|
||||
|
||||
// rate control history for last frame(1) and the frame before(2).
|
||||
// -1: undershot
|
||||
// 1: overshoot
|
||||
// 0: not initialized.
|
||||
int rc_1_frame;
|
||||
int rc_2_frame;
|
||||
int q_1_frame;
|
||||
int q_2_frame;
|
||||
|
||||
// Auto frame-scaling variables.
|
||||
FRAME_SCALE_LEVEL frame_size_selector;
|
||||
FRAME_SCALE_LEVEL next_frame_size_selector;
|
||||
int frame_width[FRAME_SCALE_STEPS];
|
||||
int frame_height[FRAME_SCALE_STEPS];
|
||||
int rf_level_maxq[RATE_FACTOR_LEVELS];
|
||||
} RATE_CONTROL;
|
||||
|
||||
struct AV1_COMP;
|
||||
struct AV1EncoderConfig;
|
||||
|
||||
void av1_rc_init(const struct AV1EncoderConfig *oxcf, int pass,
|
||||
RATE_CONTROL *rc);
|
||||
|
||||
int av1_estimate_bits_at_q(FRAME_TYPE frame_kind, int q, int mbs,
|
||||
double correction_factor, aom_bit_depth_t bit_depth);
|
||||
|
||||
double av1_convert_qindex_to_q(int qindex, aom_bit_depth_t bit_depth);
|
||||
|
||||
void av1_rc_init_minq_luts(void);
|
||||
|
||||
int av1_rc_get_default_min_gf_interval(int width, int height, double framerate);
|
||||
// Note av1_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 bis
|
||||
// as that.
|
||||
int av1_rc_get_default_max_gf_interval(double framerate, int min_frame_rate);
|
||||
|
||||
// Generally at the high level, the following flow is expected
|
||||
// to be enforced for rate control:
|
||||
// First call per frame, one of:
|
||||
// av1_rc_get_one_pass_vbr_params()
|
||||
// av1_rc_get_one_pass_cbr_params()
|
||||
// av1_rc_get_first_pass_params()
|
||||
// av1_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:
|
||||
// av1_rc_postencode_update()
|
||||
// av1_rc_postencode_update_drop_frame()
|
||||
//
|
||||
// The majority of rate control parameters are only expected
|
||||
// to be set in the av1_rc_get_..._params() functions and
|
||||
// updated during the av1_rc_postencode_update...() functions.
|
||||
// The only exceptions are av1_rc_drop_frame() and
|
||||
// av1_rc_update_rate_correction_factors() functions.
|
||||
|
||||
// Functions to set parameters for encoding before the actual
|
||||
// encode_frame_to_data_rate() function.
|
||||
void av1_rc_get_one_pass_vbr_params(struct AV1_COMP *cpi);
|
||||
void av1_rc_get_one_pass_cbr_params(struct AV1_COMP *cpi);
|
||||
|
||||
// Post encode update of the rate control parameters based
|
||||
// on bytes used
|
||||
void av1_rc_postencode_update(struct AV1_COMP *cpi, uint64_t bytes_used);
|
||||
// Post encode update of the rate control parameters for dropped frames
|
||||
void av1_rc_postencode_update_drop_frame(struct AV1_COMP *cpi);
|
||||
|
||||
// Updates rate correction factors
|
||||
// Changes only the rate correction factors in the rate control structure.
|
||||
void av1_rc_update_rate_correction_factors(struct AV1_COMP *cpi);
|
||||
|
||||
// Decide if we should drop this frame: For 1-pass CBR.
|
||||
// Changes only the decimation count in the rate control structure
|
||||
int av1_rc_drop_frame(struct AV1_COMP *cpi);
|
||||
|
||||
// Computes frame size bounds.
|
||||
void av1_rc_compute_frame_size_bounds(const struct AV1_COMP *cpi,
|
||||
int this_frame_target,
|
||||
int *frame_under_shoot_limit,
|
||||
int *frame_over_shoot_limit);
|
||||
|
||||
// Picks q and q bounds given the target for bits
|
||||
int av1_rc_pick_q_and_bounds(const struct AV1_COMP *cpi, int *bottom_index,
|
||||
int *top_index);
|
||||
|
||||
// Estimates q to achieve a target bits per frame
|
||||
int av1_rc_regulate_q(const struct AV1_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 av1_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex,
|
||||
double correction_factor, aom_bit_depth_t bit_depth);
|
||||
|
||||
// Clamping utilities for bitrate targets for iframes and pframes.
|
||||
int av1_rc_clamp_iframe_target_size(const struct AV1_COMP *const cpi,
|
||||
int target);
|
||||
int av1_rc_clamp_pframe_target_size(const struct AV1_COMP *const cpi,
|
||||
int target);
|
||||
// Utility to set frame_target into the RATE_CONTROL structure
|
||||
// This function is called only from the av1_rc_get_..._params() functions.
|
||||
void av1_rc_set_frame_target(struct AV1_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 av1_compute_qdelta(const RATE_CONTROL *rc, double qstart, double qtarget,
|
||||
aom_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 av1_compute_qdelta_by_rate(const RATE_CONTROL *rc, FRAME_TYPE frame_type,
|
||||
int qindex, double rate_target_ratio,
|
||||
aom_bit_depth_t bit_depth);
|
||||
|
||||
int av1_frame_type_qdelta(const struct AV1_COMP *cpi, int rf_level, int q);
|
||||
|
||||
void av1_rc_update_framerate(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_rc_set_gf_interval_range(const struct AV1_COMP *const cpi,
|
||||
RATE_CONTROL *const rc);
|
||||
|
||||
void av1_set_target_rate(struct AV1_COMP *cpi);
|
||||
|
||||
int av1_resize_one_pass_cbr(struct AV1_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_RATECTRL_H_
|
||||
1244
third_party/aom/av1/encoder/ratectrl_xiph.c
vendored
Normal file
1244
third_party/aom/av1/encoder/ratectrl_xiph.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
200
third_party/aom/av1/encoder/ratectrl_xiph.h
vendored
Normal file
200
third_party/aom/av1/encoder/ratectrl_xiph.h
vendored
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#if !defined(_ratectrl_xiph_H)
|
||||
#define _ratectrl_xiph_H (1)
|
||||
|
||||
#include "av1/encoder/ratectrl.h"
|
||||
#include "aom/internal/aom_codec_internal.h"
|
||||
|
||||
/*Frame types.*/
|
||||
#define OD_I_FRAME (0)
|
||||
#define OD_P_FRAME (1)
|
||||
#define OD_GOLDEN_P_FRAME (2)
|
||||
#define OD_ALTREF_P_FRAME (3)
|
||||
|
||||
#define OD_FRAME_NSUBTYPES (OD_ALTREF_P_FRAME + 1)
|
||||
|
||||
/* Periodic boost (in between golden frames) strength - lower is more */
|
||||
#define OD_PERIODIC_BOOST_DIV (10)
|
||||
|
||||
/* Constants for frame QP modulation <- tweak these
|
||||
* Adjusts how the rate control system decides the quantizers per frame
|
||||
* (sub)type */
|
||||
#define OD_MQP_I (0.98)
|
||||
#define OD_MQP_P (1.06)
|
||||
#define OD_MQP_GP (0.99)
|
||||
#define OD_MQP_AP (0.92)
|
||||
#define OD_DQP_I (-2)
|
||||
#define OD_DQP_P (0)
|
||||
#define OD_DQP_GP (-2)
|
||||
#define OD_DQP_AP (-2)
|
||||
|
||||
/*Fractional_coded_quantizer ~=
|
||||
log2(quantizer / (1 << OD_COEFF_SHIFT))*6.307 + 6.235*/
|
||||
/*Base/scale factor for linear quantizer to fractional coded quantizer
|
||||
conversion (6.307 * 2^12) */
|
||||
#define OD_LOG_QUANTIZER_BASE_Q12 (0x0064EB)
|
||||
/*Inverse of above scale factor.*/
|
||||
#define OD_LOG_QUANTIZER_EXP_Q12 (0x000289)
|
||||
/*Offset for linear quantizer to fractional coded quantizer
|
||||
conversion (6.235 * 2^45) */
|
||||
#define OD_LOG_QUANTIZER_OFFSET_Q45 (0x0000C7851EB851ECLL)
|
||||
|
||||
#define OD_RC_2PASS_MAGIC (0x53015641) /* [A, V, 1, S] in little endian */
|
||||
#define OD_RC_2PASS_SUMMARY_SZ (4 + 1 + (4 + 4 + 8) * OD_FRAME_NSUBTYPES)
|
||||
#define OD_RC_2PASS_PACKET_SZ (1 + 4)
|
||||
#define OD_RC_2PASS_MIN (OD_RC_2PASS_PACKET_SZ + OD_RC_2PASS_SUMMARY_SZ)
|
||||
#define OD_RC_2PASS_VERSION (1)
|
||||
|
||||
/*A 2nd order low-pass Bessel follower.
|
||||
We use this for rate control because it has fast reaction time, but is
|
||||
critically damped.*/
|
||||
typedef struct od_iir_bessel2 {
|
||||
int32_t c[2];
|
||||
int64_t g;
|
||||
int32_t x[2];
|
||||
int32_t y[2];
|
||||
} od_iir_bessel2;
|
||||
|
||||
/* The 2-pass metrics associated with a single frame. */
|
||||
typedef struct od_frame_metrics {
|
||||
/*The log base 2 of the scale factor for this frame in Q24 format.*/
|
||||
int64_t log_scale;
|
||||
/*The frame type from pass 1.*/
|
||||
unsigned frame_type : 1;
|
||||
} od_frame_metrics;
|
||||
|
||||
/*Rate control setup and working state information.*/
|
||||
typedef struct od_rc_state {
|
||||
/* Image format */
|
||||
int frame_width;
|
||||
int frame_height;
|
||||
int bit_depth;
|
||||
|
||||
/* Framerate */
|
||||
double framerate;
|
||||
/* Keyframe rate */
|
||||
int keyframe_rate;
|
||||
/* Golden frame period */
|
||||
int goldenframe_rate;
|
||||
/* Altref frame period */
|
||||
int altref_rate;
|
||||
/*The target bit-rate in bits per second.*/
|
||||
int64_t target_bitrate;
|
||||
/* Quality level for non-bitrate-targeting */
|
||||
int quality;
|
||||
/* Copied from oxcf->frame_periodic_boost */
|
||||
int periodic_boosts;
|
||||
/* Max Q */
|
||||
int maxq;
|
||||
/* Min Q */
|
||||
int minq;
|
||||
/* Quantizer to use for the first pass */
|
||||
int firstpass_quant;
|
||||
|
||||
/* 2-pass metrics */
|
||||
od_frame_metrics cur_metrics;
|
||||
|
||||
/* 2-pass state */
|
||||
int64_t scale_sum[OD_FRAME_NSUBTYPES];
|
||||
int nframes[OD_FRAME_NSUBTYPES];
|
||||
|
||||
/* 2-pass bytestream reader/writer context */
|
||||
uint8_t *twopass_buffer;
|
||||
int twopass_buffer_bytes;
|
||||
|
||||
/* Pass 1 stats packet storage */
|
||||
uint8_t firstpass_buffer[OD_RC_2PASS_SUMMARY_SZ];
|
||||
|
||||
/* Every state packet from the first pass in a single buffer */
|
||||
uint8_t *twopass_allframes_buf;
|
||||
size_t twopass_allframes_buf_size;
|
||||
|
||||
/* Actual returned quantizer */
|
||||
int target_quantizer;
|
||||
/*The full-precision, unmodulated quantizer upon which
|
||||
our modulated quantizers are based.*/
|
||||
int base_quantizer;
|
||||
|
||||
/* Increments by 1 for each frame. */
|
||||
int64_t cur_frame;
|
||||
|
||||
/* End of input flag */
|
||||
int end_of_input;
|
||||
/* Closed GOP flag */
|
||||
int closed_gop;
|
||||
/*The number of frames over which to distribute the reservoir usage.*/
|
||||
int reservoir_frame_delay;
|
||||
/*Will we drop frames to meet bitrate target?*/
|
||||
unsigned char drop_frames;
|
||||
/*Do we respect the maximum reservoir fullness?*/
|
||||
unsigned char cap_overflow;
|
||||
/*Can the reservoir go negative?*/
|
||||
unsigned char cap_underflow;
|
||||
/*Two-pass mode state.
|
||||
0 => 1-pass encoding.
|
||||
1 => 1st pass of 2-pass encoding.
|
||||
2 => 2nd pass of 2-pass encoding.*/
|
||||
int twopass_state;
|
||||
/*The log of the number of pixels in a frame in Q57 format.*/
|
||||
int64_t log_npixels;
|
||||
/*The target average bits per frame.*/
|
||||
int64_t bits_per_frame;
|
||||
/*The current bit reservoir fullness (bits available to be used).*/
|
||||
int64_t reservoir_fullness;
|
||||
/*The target buffer fullness.
|
||||
This is where we'd like to be by the last keyframe the appears in the next
|
||||
buf_delay frames.*/
|
||||
int64_t reservoir_target;
|
||||
/*The maximum buffer fullness (total size of the buffer).*/
|
||||
int64_t reservoir_max;
|
||||
/*The log of estimated scale factor for the rate model in Q57 format.*/
|
||||
int64_t log_scale[OD_FRAME_NSUBTYPES];
|
||||
/*The exponent used in the rate model in Q8 format.*/
|
||||
unsigned exp[OD_FRAME_NSUBTYPES];
|
||||
/*The log of an estimated scale factor used to obtain the real framerate, for
|
||||
VFR sources or, e.g., 12 fps content doubled to 24 fps, etc.*/
|
||||
int64_t log_drop_scale[OD_FRAME_NSUBTYPES];
|
||||
/*The total drop count from the previous frame.*/
|
||||
uint32_t prev_drop_count[OD_FRAME_NSUBTYPES];
|
||||
/*Second-order lowpass filters to track scale and VFR/drops.*/
|
||||
od_iir_bessel2 scalefilter[OD_FRAME_NSUBTYPES];
|
||||
od_iir_bessel2 vfrfilter[OD_FRAME_NSUBTYPES];
|
||||
int frame_count[OD_FRAME_NSUBTYPES];
|
||||
int inter_p_delay;
|
||||
int inter_delay_target;
|
||||
/*The total accumulated estimation bias.*/
|
||||
int64_t rate_bias;
|
||||
} od_rc_state;
|
||||
|
||||
int od_enc_rc_init(od_rc_state *rc, int64_t bitrate, int delay_ms);
|
||||
|
||||
int od_enc_rc_select_quantizers_and_lambdas(od_rc_state *rc,
|
||||
int is_golden_frame,
|
||||
int is_altref_frame, int frame_type,
|
||||
int *bottom_idx, int *top_idx);
|
||||
|
||||
/* Returns 1 if the frame should be dropped */
|
||||
int od_enc_rc_update_state(od_rc_state *rc, int64_t bits, int is_golden_frame,
|
||||
int is_altref_frame, int frame_type, int droppable);
|
||||
|
||||
int od_frame_type(od_rc_state *rc, int64_t coding_frame_count, int *is_golden,
|
||||
int *is_altref, int64_t *ip_count);
|
||||
|
||||
int od_enc_rc_resize(od_rc_state *rc);
|
||||
|
||||
int od_enc_rc_2pass_out(od_rc_state *rc, struct aom_codec_pkt_list *pkt_list,
|
||||
int summary);
|
||||
|
||||
int od_enc_rc_2pass_in(od_rc_state *rc);
|
||||
|
||||
#endif
|
||||
1204
third_party/aom/av1/encoder/rd.c
vendored
Normal file
1204
third_party/aom/av1/encoder/rd.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
505
third_party/aom/av1/encoder/rd.h
vendored
Normal file
505
third_party/aom/av1/encoder/rd.h
vendored
Normal file
|
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_RD_H_
|
||||
#define AV1_ENCODER_RD_H_
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if CONFIG_ANS
|
||||
#include "aom_dsp/ans.h"
|
||||
#endif // CONFIG_ANS
|
||||
#include "av1/common/blockd.h"
|
||||
|
||||
#include "av1/encoder/block.h"
|
||||
#include "av1/encoder/context_tree.h"
|
||||
#include "av1/encoder/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), AV1_PROB_COST_SHIFT) + (D << DM))
|
||||
|
||||
#define RDCOST_DBL(RM, DM, R, D) \
|
||||
(((((double)(R)) * (RM)) / (double)(1 << AV1_PROB_COST_SHIFT)) + \
|
||||
((double)(D) * (1 << (DM))))
|
||||
|
||||
#define QIDX_SKIP_THRESH 115
|
||||
|
||||
#define MV_COST_WEIGHT 108
|
||||
#define MV_COST_WEIGHT_SUB 120
|
||||
|
||||
#define INVALID_MV 0x80008000
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
#define MAX_REFS 15
|
||||
#else
|
||||
#define MAX_REFS 6
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
#define RD_THRESH_MAX_FACT 64
|
||||
#define RD_THRESH_INC 1
|
||||
|
||||
// This enumerator type needs to be kept aligned with the mode order in
|
||||
// const MODE_DEFINITION av1_mode_order[MAX_MODES] used in the rd code.
|
||||
typedef enum {
|
||||
THR_NEARESTMV,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_NEARESTL2,
|
||||
THR_NEARESTL3,
|
||||
THR_NEARESTB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_NEARESTA,
|
||||
THR_NEARESTG,
|
||||
|
||||
THR_DC,
|
||||
|
||||
THR_NEWMV,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_NEWL2,
|
||||
THR_NEWL3,
|
||||
THR_NEWB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_NEWA,
|
||||
THR_NEWG,
|
||||
|
||||
THR_NEARMV,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_NEARL2,
|
||||
THR_NEARL3,
|
||||
THR_NEARB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_NEARA,
|
||||
THR_NEARG,
|
||||
|
||||
THR_ZEROMV,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_ZEROL2,
|
||||
THR_ZEROL3,
|
||||
THR_ZEROB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_ZEROG,
|
||||
THR_ZEROA,
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
|
||||
THR_COMP_NEAREST_NEARESTLA,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_NEAREST_NEARESTL2A,
|
||||
THR_COMP_NEAREST_NEARESTL3A,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_COMP_NEAREST_NEARESTGA,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_NEAREST_NEARESTLB,
|
||||
THR_COMP_NEAREST_NEARESTL2B,
|
||||
THR_COMP_NEAREST_NEARESTL3B,
|
||||
THR_COMP_NEAREST_NEARESTGB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
#else // CONFIG_EXT_INTER
|
||||
|
||||
THR_COMP_NEARESTLA,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_NEARESTL2A,
|
||||
THR_COMP_NEARESTL3A,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_COMP_NEARESTGA,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_NEARESTLB,
|
||||
THR_COMP_NEARESTL2B,
|
||||
THR_COMP_NEARESTL3B,
|
||||
THR_COMP_NEARESTGB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
#endif // CONFIG_EXT_INTER
|
||||
|
||||
THR_TM,
|
||||
|
||||
#if CONFIG_ALT_INTRA
|
||||
THR_SMOOTH,
|
||||
#endif // CONFIG_ALT_INTRA
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
|
||||
THR_COMP_NEAR_NEARESTLA,
|
||||
THR_COMP_NEAREST_NEARLA,
|
||||
THR_COMP_NEAR_NEARLA,
|
||||
THR_COMP_NEW_NEARESTLA,
|
||||
THR_COMP_NEAREST_NEWLA,
|
||||
THR_COMP_NEW_NEARLA,
|
||||
THR_COMP_NEAR_NEWLA,
|
||||
THR_COMP_NEW_NEWLA,
|
||||
THR_COMP_ZERO_ZEROLA,
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_NEAR_NEARESTL2A,
|
||||
THR_COMP_NEAREST_NEARL2A,
|
||||
THR_COMP_NEAR_NEARL2A,
|
||||
THR_COMP_NEW_NEARESTL2A,
|
||||
THR_COMP_NEAREST_NEWL2A,
|
||||
THR_COMP_NEW_NEARL2A,
|
||||
THR_COMP_NEAR_NEWL2A,
|
||||
THR_COMP_NEW_NEWL2A,
|
||||
THR_COMP_ZERO_ZEROL2A,
|
||||
|
||||
THR_COMP_NEAR_NEARESTL3A,
|
||||
THR_COMP_NEAREST_NEARL3A,
|
||||
THR_COMP_NEAR_NEARL3A,
|
||||
THR_COMP_NEW_NEARESTL3A,
|
||||
THR_COMP_NEAREST_NEWL3A,
|
||||
THR_COMP_NEW_NEARL3A,
|
||||
THR_COMP_NEAR_NEWL3A,
|
||||
THR_COMP_NEW_NEWL3A,
|
||||
THR_COMP_ZERO_ZEROL3A,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
THR_COMP_NEAR_NEARESTGA,
|
||||
THR_COMP_NEAREST_NEARGA,
|
||||
THR_COMP_NEAR_NEARGA,
|
||||
THR_COMP_NEW_NEARESTGA,
|
||||
THR_COMP_NEAREST_NEWGA,
|
||||
THR_COMP_NEW_NEARGA,
|
||||
THR_COMP_NEAR_NEWGA,
|
||||
THR_COMP_NEW_NEWGA,
|
||||
THR_COMP_ZERO_ZEROGA,
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_NEAR_NEARESTLB,
|
||||
THR_COMP_NEAREST_NEARLB,
|
||||
THR_COMP_NEAR_NEARLB,
|
||||
THR_COMP_NEW_NEARESTLB,
|
||||
THR_COMP_NEAREST_NEWLB,
|
||||
THR_COMP_NEW_NEARLB,
|
||||
THR_COMP_NEAR_NEWLB,
|
||||
THR_COMP_NEW_NEWLB,
|
||||
THR_COMP_ZERO_ZEROLB,
|
||||
|
||||
THR_COMP_NEAR_NEARESTL2B,
|
||||
THR_COMP_NEAREST_NEARL2B,
|
||||
THR_COMP_NEAR_NEARL2B,
|
||||
THR_COMP_NEW_NEARESTL2B,
|
||||
THR_COMP_NEAREST_NEWL2B,
|
||||
THR_COMP_NEW_NEARL2B,
|
||||
THR_COMP_NEAR_NEWL2B,
|
||||
THR_COMP_NEW_NEWL2B,
|
||||
THR_COMP_ZERO_ZEROL2B,
|
||||
|
||||
THR_COMP_NEAR_NEARESTL3B,
|
||||
THR_COMP_NEAREST_NEARL3B,
|
||||
THR_COMP_NEAR_NEARL3B,
|
||||
THR_COMP_NEW_NEARESTL3B,
|
||||
THR_COMP_NEAREST_NEWL3B,
|
||||
THR_COMP_NEW_NEARL3B,
|
||||
THR_COMP_NEAR_NEWL3B,
|
||||
THR_COMP_NEW_NEWL3B,
|
||||
THR_COMP_ZERO_ZEROL3B,
|
||||
|
||||
THR_COMP_NEAR_NEARESTGB,
|
||||
THR_COMP_NEAREST_NEARGB,
|
||||
THR_COMP_NEAR_NEARGB,
|
||||
THR_COMP_NEW_NEARESTGB,
|
||||
THR_COMP_NEAREST_NEWGB,
|
||||
THR_COMP_NEW_NEARGB,
|
||||
THR_COMP_NEAR_NEWGB,
|
||||
THR_COMP_NEW_NEWGB,
|
||||
THR_COMP_ZERO_ZEROGB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
#else // CONFIG_EXT_INTER
|
||||
|
||||
THR_COMP_NEARLA,
|
||||
THR_COMP_NEWLA,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_NEARL2A,
|
||||
THR_COMP_NEWL2A,
|
||||
THR_COMP_NEARL3A,
|
||||
THR_COMP_NEWL3A,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_COMP_NEARGA,
|
||||
THR_COMP_NEWGA,
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_NEARLB,
|
||||
THR_COMP_NEWLB,
|
||||
THR_COMP_NEARL2B,
|
||||
THR_COMP_NEWL2B,
|
||||
THR_COMP_NEARL3B,
|
||||
THR_COMP_NEWL3B,
|
||||
THR_COMP_NEARGB,
|
||||
THR_COMP_NEWGB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
THR_COMP_ZEROLA,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_ZEROL2A,
|
||||
THR_COMP_ZEROL3A,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_COMP_ZEROGA,
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_ZEROLB,
|
||||
THR_COMP_ZEROL2B,
|
||||
THR_COMP_ZEROL3B,
|
||||
THR_COMP_ZEROGB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
#endif // CONFIG_EXT_INTER
|
||||
|
||||
THR_H_PRED,
|
||||
THR_V_PRED,
|
||||
THR_D135_PRED,
|
||||
THR_D207_PRED,
|
||||
THR_D153_PRED,
|
||||
THR_D63_PRED,
|
||||
THR_D117_PRED,
|
||||
THR_D45_PRED,
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
THR_COMP_INTERINTRA_ZEROL,
|
||||
THR_COMP_INTERINTRA_NEARESTL,
|
||||
THR_COMP_INTERINTRA_NEARL,
|
||||
THR_COMP_INTERINTRA_NEWL,
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_INTERINTRA_ZEROL2,
|
||||
THR_COMP_INTERINTRA_NEARESTL2,
|
||||
THR_COMP_INTERINTRA_NEARL2,
|
||||
THR_COMP_INTERINTRA_NEWL2,
|
||||
|
||||
THR_COMP_INTERINTRA_ZEROL3,
|
||||
THR_COMP_INTERINTRA_NEARESTL3,
|
||||
THR_COMP_INTERINTRA_NEARL3,
|
||||
THR_COMP_INTERINTRA_NEWL3,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
THR_COMP_INTERINTRA_ZEROG,
|
||||
THR_COMP_INTERINTRA_NEARESTG,
|
||||
THR_COMP_INTERINTRA_NEARG,
|
||||
THR_COMP_INTERINTRA_NEWG,
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_INTERINTRA_ZEROB,
|
||||
THR_COMP_INTERINTRA_NEARESTB,
|
||||
THR_COMP_INTERINTRA_NEARB,
|
||||
THR_COMP_INTERINTRA_NEWB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
THR_COMP_INTERINTRA_ZEROA,
|
||||
THR_COMP_INTERINTRA_NEARESTA,
|
||||
THR_COMP_INTERINTRA_NEARA,
|
||||
THR_COMP_INTERINTRA_NEWA,
|
||||
#endif // CONFIG_EXT_INTER
|
||||
MAX_MODES
|
||||
} THR_MODES;
|
||||
|
||||
typedef enum {
|
||||
THR_LAST,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_LAST2,
|
||||
THR_LAST3,
|
||||
THR_BWDR,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_GOLD,
|
||||
THR_ALTR,
|
||||
|
||||
THR_COMP_LA,
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_L2A,
|
||||
THR_COMP_L3A,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
THR_COMP_GA,
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
THR_COMP_LB,
|
||||
THR_COMP_L2B,
|
||||
THR_COMP_L3B,
|
||||
THR_COMP_GB,
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
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[TOTAL_REFS_PER_FRAME][REFERENCE_MODES];
|
||||
|
||||
int RDMULT;
|
||||
int RDDIV;
|
||||
} RD_OPT;
|
||||
|
||||
static INLINE void av1_init_rd_stats(RD_STATS *rd_stats) {
|
||||
#if CONFIG_RD_DEBUG
|
||||
int plane;
|
||||
#endif
|
||||
rd_stats->rate = 0;
|
||||
rd_stats->dist = 0;
|
||||
rd_stats->rdcost = 0;
|
||||
rd_stats->sse = 0;
|
||||
rd_stats->skip = 1;
|
||||
#if CONFIG_RD_DEBUG
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
||||
rd_stats->txb_coeff_cost[plane] = 0;
|
||||
#if CONFIG_VAR_TX
|
||||
{
|
||||
int r, c;
|
||||
for (r = 0; r < TXB_COEFF_COST_MAP_SIZE; ++r)
|
||||
for (c = 0; c < TXB_COEFF_COST_MAP_SIZE; ++c)
|
||||
rd_stats->txb_coeff_cost_map[plane][r][c] = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void av1_invalid_rd_stats(RD_STATS *rd_stats) {
|
||||
#if CONFIG_RD_DEBUG
|
||||
int plane;
|
||||
#endif
|
||||
rd_stats->rate = INT_MAX;
|
||||
rd_stats->dist = INT64_MAX;
|
||||
rd_stats->rdcost = INT64_MAX;
|
||||
rd_stats->sse = INT64_MAX;
|
||||
rd_stats->skip = 0;
|
||||
#if CONFIG_RD_DEBUG
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
||||
rd_stats->txb_coeff_cost[plane] = INT_MAX;
|
||||
#if CONFIG_VAR_TX
|
||||
{
|
||||
int r, c;
|
||||
for (r = 0; r < TXB_COEFF_COST_MAP_SIZE; ++r)
|
||||
for (c = 0; c < TXB_COEFF_COST_MAP_SIZE; ++c)
|
||||
rd_stats->txb_coeff_cost_map[plane][r][c] = INT_MAX;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void av1_merge_rd_stats(RD_STATS *rd_stats_dst,
|
||||
const RD_STATS *rd_stats_src) {
|
||||
#if CONFIG_RD_DEBUG
|
||||
int plane;
|
||||
#endif
|
||||
rd_stats_dst->rate += rd_stats_src->rate;
|
||||
rd_stats_dst->dist += rd_stats_src->dist;
|
||||
rd_stats_dst->sse += rd_stats_src->sse;
|
||||
rd_stats_dst->skip &= rd_stats_src->skip;
|
||||
#if CONFIG_RD_DEBUG
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
||||
rd_stats_dst->txb_coeff_cost[plane] += rd_stats_src->txb_coeff_cost[plane];
|
||||
#if CONFIG_VAR_TX
|
||||
{
|
||||
// TODO(angiebird): optimize this part
|
||||
int r, c;
|
||||
int ref_txb_coeff_cost = 0;
|
||||
for (r = 0; r < TXB_COEFF_COST_MAP_SIZE; ++r)
|
||||
for (c = 0; c < TXB_COEFF_COST_MAP_SIZE; ++c) {
|
||||
rd_stats_dst->txb_coeff_cost_map[plane][r][c] +=
|
||||
rd_stats_src->txb_coeff_cost_map[plane][r][c];
|
||||
ref_txb_coeff_cost += rd_stats_dst->txb_coeff_cost_map[plane][r][c];
|
||||
}
|
||||
assert(ref_txb_coeff_cost == rd_stats_dst->txb_coeff_cost[plane]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct TileInfo;
|
||||
struct TileDataEnc;
|
||||
struct AV1_COMP;
|
||||
struct macroblock;
|
||||
|
||||
int av1_compute_rd_mult(const struct AV1_COMP *cpi, int qindex);
|
||||
|
||||
void av1_initialize_rd_consts(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_initialize_me_consts(const struct AV1_COMP *cpi, MACROBLOCK *x,
|
||||
int qindex);
|
||||
|
||||
void av1_model_rd_from_var_lapndz(int64_t var, unsigned int n,
|
||||
unsigned int qstep, int *rate, int64_t *dist);
|
||||
|
||||
int av1_get_switchable_rate(const struct AV1_COMP *cpi, const MACROBLOCKD *xd);
|
||||
|
||||
int av1_raster_block_offset(BLOCK_SIZE plane_bsize, int raster_block,
|
||||
int stride);
|
||||
|
||||
int16_t *av1_raster_block_offset_int16(BLOCK_SIZE plane_bsize, int raster_block,
|
||||
int16_t *base);
|
||||
|
||||
YV12_BUFFER_CONFIG *av1_get_scaled_ref_frame(const struct AV1_COMP *cpi,
|
||||
int ref_frame);
|
||||
|
||||
void av1_init_me_luts(void);
|
||||
|
||||
#if CONFIG_REF_MV
|
||||
void av1_set_mvcost(MACROBLOCK *x, MV_REFERENCE_FRAME ref_frame, int ref,
|
||||
int ref_mv_idx);
|
||||
#endif
|
||||
|
||||
void av1_get_entropy_contexts(BLOCK_SIZE bsize, TX_SIZE tx_size,
|
||||
const struct macroblockd_plane *pd,
|
||||
ENTROPY_CONTEXT t_above[2 * MAX_MIB_SIZE],
|
||||
ENTROPY_CONTEXT t_left[2 * MAX_MIB_SIZE]);
|
||||
|
||||
void av1_set_rd_speed_thresholds(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_set_rd_speed_thresholds_sub8x8(struct AV1_COMP *cpi);
|
||||
|
||||
void av1_update_rd_thresh_fact(const AV1_COMMON *const cm,
|
||||
int (*fact)[MAX_MODES], int rd_thresh, int bsize,
|
||||
int best_mode_index);
|
||||
|
||||
void av1_fill_token_costs(av1_coeff_cost *c,
|
||||
av1_coeff_probs_model (*p)[PLANE_TYPES]);
|
||||
|
||||
static INLINE int rd_less_than_thresh(int64_t best_rd, int thresh,
|
||||
int thresh_fact) {
|
||||
return best_rd < ((int64_t)thresh * thresh_fact >> 5) || thresh == INT_MAX;
|
||||
}
|
||||
|
||||
void av1_mv_pred(const struct AV1_COMP *cpi, MACROBLOCK *x,
|
||||
uint8_t *ref_y_buffer, int ref_y_stride, int ref_frame,
|
||||
BLOCK_SIZE block_size);
|
||||
|
||||
static INLINE void set_error_per_bit(MACROBLOCK *x, int rdmult) {
|
||||
x->errorperbit = rdmult >> RD_EPB_SHIFT;
|
||||
x->errorperbit += (x->errorperbit == 0);
|
||||
}
|
||||
|
||||
void av1_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 av1_get_intra_cost_penalty(int qindex, int qdelta,
|
||||
aom_bit_depth_t bit_depth);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_RD_H_
|
||||
12713
third_party/aom/av1/encoder/rdopt.c
vendored
Normal file
12713
third_party/aom/av1/encoder/rdopt.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
142
third_party/aom/av1/encoder/rdopt.h
vendored
Normal file
142
third_party/aom/av1/encoder/rdopt.h
vendored
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_RDOPT_H_
|
||||
#define AV1_ENCODER_RDOPT_H_
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
|
||||
#include "av1/encoder/block.h"
|
||||
#include "av1/encoder/context_tree.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct TileInfo;
|
||||
struct AV1_COMP;
|
||||
struct macroblock;
|
||||
struct RD_STATS;
|
||||
|
||||
#if CONFIG_RD_DEBUG
|
||||
static INLINE void av1_update_txb_coeff_cost(RD_STATS *rd_stats, int plane,
|
||||
TX_SIZE tx_size, int blk_row,
|
||||
int blk_col, int txb_coeff_cost) {
|
||||
(void)blk_row;
|
||||
(void)blk_col;
|
||||
(void)tx_size;
|
||||
rd_stats->txb_coeff_cost[plane] += txb_coeff_cost;
|
||||
|
||||
#if CONFIG_VAR_TX
|
||||
{
|
||||
const int txb_h = tx_size_high_unit[tx_size];
|
||||
const int txb_w = tx_size_wide_unit[tx_size];
|
||||
int idx, idy;
|
||||
for (idy = 0; idy < txb_h; ++idy)
|
||||
for (idx = 0; idx < txb_w; ++idx)
|
||||
rd_stats->txb_coeff_cost_map[plane][blk_row + idy][blk_col + idx] = 0;
|
||||
|
||||
rd_stats->txb_coeff_cost_map[plane][blk_row][blk_col] = txb_coeff_cost;
|
||||
}
|
||||
assert(blk_row < TXB_COEFF_COST_MAP_SIZE);
|
||||
assert(blk_col < TXB_COEFF_COST_MAP_SIZE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef enum OUTPUT_STATUS {
|
||||
OUTPUT_HAS_PREDICTED_PIXELS,
|
||||
OUTPUT_HAS_DECODED_PIXELS
|
||||
} OUTPUT_STATUS;
|
||||
|
||||
void av1_dist_block(const AV1_COMP *cpi, MACROBLOCK *x, int plane,
|
||||
BLOCK_SIZE plane_bsize, int block, int blk_row, int blk_col,
|
||||
TX_SIZE tx_size, int64_t *out_dist, int64_t *out_sse,
|
||||
OUTPUT_STATUS output_status);
|
||||
|
||||
#if !CONFIG_PVQ || CONFIG_VAR_TX
|
||||
int av1_cost_coeffs(const AV1_COMP *const cpi, MACROBLOCK *x, int plane,
|
||||
int block, TX_SIZE tx_size, const SCAN_ORDER *scan_order,
|
||||
const ENTROPY_CONTEXT *a, const ENTROPY_CONTEXT *l,
|
||||
int use_fast_coef_costing);
|
||||
#endif
|
||||
void av1_rd_pick_intra_mode_sb(const struct AV1_COMP *cpi, struct macroblock *x,
|
||||
struct RD_STATS *rd_cost, BLOCK_SIZE bsize,
|
||||
PICK_MODE_CONTEXT *ctx, int64_t best_rd);
|
||||
|
||||
unsigned int av1_get_sby_perpixel_variance(const AV1_COMP *cpi,
|
||||
const struct buf_2d *ref,
|
||||
BLOCK_SIZE bs);
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
unsigned int av1_high_get_sby_perpixel_variance(const AV1_COMP *cpi,
|
||||
const struct buf_2d *ref,
|
||||
BLOCK_SIZE bs, int bd);
|
||||
#endif
|
||||
|
||||
void av1_rd_pick_inter_mode_sb(const struct AV1_COMP *cpi,
|
||||
struct TileDataEnc *tile_data,
|
||||
struct macroblock *x, int mi_row, int mi_col,
|
||||
struct RD_STATS *rd_cost,
|
||||
#if CONFIG_SUPERTX
|
||||
int *returnrate_nocoef,
|
||||
#endif // CONFIG_SUPERTX
|
||||
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
|
||||
int64_t best_rd_so_far);
|
||||
|
||||
void av1_rd_pick_inter_mode_sb_seg_skip(
|
||||
const struct AV1_COMP *cpi, struct TileDataEnc *tile_data,
|
||||
struct macroblock *x, int mi_row, int mi_col, struct RD_STATS *rd_cost,
|
||||
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far);
|
||||
|
||||
int av1_internal_image_edge(const struct AV1_COMP *cpi);
|
||||
int av1_active_h_edge(const struct AV1_COMP *cpi, int mi_row, int mi_step);
|
||||
int av1_active_v_edge(const struct AV1_COMP *cpi, int mi_col, int mi_step);
|
||||
int av1_active_edge_sb(const struct AV1_COMP *cpi, int mi_row, int mi_col);
|
||||
|
||||
void av1_rd_pick_inter_mode_sub8x8(const struct AV1_COMP *cpi,
|
||||
struct TileDataEnc *tile_data,
|
||||
struct macroblock *x, int mi_row, int mi_col,
|
||||
struct RD_STATS *rd_cost,
|
||||
#if CONFIG_SUPERTX
|
||||
int *returnrate_nocoef,
|
||||
#endif // CONFIG_SUPERTX
|
||||
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
|
||||
int64_t best_rd_so_far);
|
||||
|
||||
#if CONFIG_MOTION_VAR && CONFIG_NCOBMC
|
||||
void av1_check_ncobmc_rd(const struct AV1_COMP *cpi, struct macroblock *x,
|
||||
int mi_row, int mi_col);
|
||||
#endif // CONFIG_MOTION_VAR && CONFIG_NCOBMC
|
||||
|
||||
#if CONFIG_SUPERTX
|
||||
#if CONFIG_VAR_TX
|
||||
void av1_tx_block_rd_b(const AV1_COMP *cpi, MACROBLOCK *x, TX_SIZE tx_size,
|
||||
int blk_row, int blk_col, int plane, int block,
|
||||
int plane_bsize, const ENTROPY_CONTEXT *a,
|
||||
const ENTROPY_CONTEXT *l, RD_STATS *rd_stats);
|
||||
#endif
|
||||
|
||||
void av1_txfm_rd_in_plane_supertx(MACROBLOCK *x, const AV1_COMP *cpi, int *rate,
|
||||
int64_t *distortion, int *skippable,
|
||||
int64_t *sse, int64_t ref_best_rd, int plane,
|
||||
BLOCK_SIZE bsize, TX_SIZE tx_size,
|
||||
int use_fast_coef_casting);
|
||||
#endif // CONFIG_SUPERTX
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
int av1_tx_type_cost(const AV1_COMP *cpi, const MACROBLOCKD *xd,
|
||||
BLOCK_SIZE bsize, int plane, TX_SIZE tx_size,
|
||||
TX_TYPE tx_type);
|
||||
|
||||
#endif // AV1_ENCODER_RDOPT_H_
|
||||
394
third_party/aom/av1/encoder/segmentation.c
vendored
Normal file
394
third_party/aom/av1/encoder/segmentation.c
vendored
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "aom_mem/aom_mem.h"
|
||||
|
||||
#include "av1/common/pred_common.h"
|
||||
#include "av1/common/tile_common.h"
|
||||
|
||||
#include "av1/encoder/cost.h"
|
||||
#include "av1/encoder/segmentation.h"
|
||||
#include "av1/encoder/subexp.h"
|
||||
|
||||
void av1_enable_segmentation(struct segmentation *seg) {
|
||||
seg->enabled = 1;
|
||||
seg->update_map = 1;
|
||||
seg->update_data = 1;
|
||||
}
|
||||
|
||||
void av1_disable_segmentation(struct segmentation *seg) {
|
||||
seg->enabled = 0;
|
||||
seg->update_map = 0;
|
||||
seg->update_data = 0;
|
||||
}
|
||||
|
||||
void av1_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 av1_disable_segfeature(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id) {
|
||||
seg->feature_mask[segment_id] &= ~(1 << feature_id);
|
||||
}
|
||||
|
||||
void av1_clear_segdata(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id) {
|
||||
seg->feature_data[segment_id][feature_id] = 0;
|
||||
}
|
||||
|
||||
// Based on set of segment counts calculate a probability tree
|
||||
static void calc_segtree_probs(unsigned *segcounts,
|
||||
aom_prob *segment_tree_probs,
|
||||
const aom_prob *cur_tree_probs,
|
||||
const int probwt) {
|
||||
// Work out probabilities of each segment
|
||||
const unsigned cc[4] = { segcounts[0] + segcounts[1],
|
||||
segcounts[2] + segcounts[3],
|
||||
segcounts[4] + segcounts[5],
|
||||
segcounts[6] + segcounts[7] };
|
||||
const unsigned ccc[2] = { cc[0] + cc[1], cc[2] + cc[3] };
|
||||
int i;
|
||||
|
||||
segment_tree_probs[0] = get_binary_prob(ccc[0], ccc[1]);
|
||||
segment_tree_probs[1] = get_binary_prob(cc[0], cc[1]);
|
||||
segment_tree_probs[2] = get_binary_prob(cc[2], cc[3]);
|
||||
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]);
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
const unsigned *ct =
|
||||
i == 0 ? ccc : i < 3 ? cc + (i & 2) : segcounts + (i - 3) * 2;
|
||||
av1_prob_diff_update_savings_search(ct, cur_tree_probs[i],
|
||||
&segment_tree_probs[i],
|
||||
DIFF_UPDATE_PROB, probwt);
|
||||
}
|
||||
}
|
||||
|
||||
// Based on set of segment counts and probabilities calculate a cost estimate
|
||||
static int cost_segmap(unsigned *segcounts, aom_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 * av1_cost_zero(probs[0]) + c4567 * av1_cost_one(probs[0]);
|
||||
|
||||
// Cost subsequent levels
|
||||
if (c0123 > 0) {
|
||||
cost += c01 * av1_cost_zero(probs[1]) + c23 * av1_cost_one(probs[1]);
|
||||
|
||||
if (c01 > 0)
|
||||
cost += segcounts[0] * av1_cost_zero(probs[3]) +
|
||||
segcounts[1] * av1_cost_one(probs[3]);
|
||||
if (c23 > 0)
|
||||
cost += segcounts[2] * av1_cost_zero(probs[4]) +
|
||||
segcounts[3] * av1_cost_one(probs[4]);
|
||||
}
|
||||
|
||||
if (c4567 > 0) {
|
||||
cost += c45 * av1_cost_zero(probs[2]) + c67 * av1_cost_one(probs[2]);
|
||||
|
||||
if (c45 > 0)
|
||||
cost += segcounts[4] * av1_cost_zero(probs[5]) +
|
||||
segcounts[5] * av1_cost_one(probs[5]);
|
||||
if (c67 > 0)
|
||||
cost += segcounts[6] * av1_cost_zero(probs[6]) +
|
||||
segcounts[7] * av1_cost_one(probs[6]);
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
static void count_segs(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
const TileInfo *tile, MODE_INFO **mi,
|
||||
unsigned *no_pred_segcounts,
|
||||
unsigned (*temporal_predictor_count)[2],
|
||||
unsigned *t_unpred_seg_counts, int bw, int bh,
|
||||
int mi_row, int mi_col) {
|
||||
int segment_id;
|
||||
|
||||
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
|
||||
|
||||
xd->mi = mi;
|
||||
segment_id = xd->mi[0]->mbmi.segment_id;
|
||||
|
||||
set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw,
|
||||
#if CONFIG_DEPENDENT_HORZTILES
|
||||
cm->dependent_horz_tiles,
|
||||
#endif // CONFIG_DEPENDENT_HORZTILES
|
||||
cm->mi_rows, cm->mi_cols);
|
||||
|
||||
// Count the number of hits on each segment with no prediction
|
||||
no_pred_segcounts[segment_id]++;
|
||||
|
||||
// Temporal prediction not allowed on key frames
|
||||
if (cm->frame_type != KEY_FRAME) {
|
||||
const BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type;
|
||||
// Test to see if the segment id matches the predicted value.
|
||||
const int pred_segment_id =
|
||||
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 = av1_get_pred_context_seg_id(xd);
|
||||
|
||||
// Store the prediction status for this mb and update counts
|
||||
// as appropriate
|
||||
xd->mi[0]->mbmi.seg_id_predicted = pred_flag;
|
||||
temporal_predictor_count[pred_context][pred_flag]++;
|
||||
|
||||
// Update the "unpredicted" segment count
|
||||
if (!pred_flag) t_unpred_seg_counts[segment_id]++;
|
||||
}
|
||||
}
|
||||
|
||||
static void count_segs_sb(const AV1_COMMON *cm, MACROBLOCKD *xd,
|
||||
const TileInfo *tile, MODE_INFO **mi,
|
||||
unsigned *no_pred_segcounts,
|
||||
unsigned (*temporal_predictor_count)[2],
|
||||
unsigned *t_unpred_seg_counts, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize) {
|
||||
const int mis = cm->mi_stride;
|
||||
const int bs = mi_size_wide[bsize], hbs = bs / 2;
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
PARTITION_TYPE partition;
|
||||
#else
|
||||
int bw, bh;
|
||||
#endif // CONFIG_EXT_PARTITION_TYPES
|
||||
|
||||
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
|
||||
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
if (bsize == BLOCK_8X8)
|
||||
partition = PARTITION_NONE;
|
||||
else
|
||||
partition = get_partition(cm, mi_row, mi_col, bsize);
|
||||
switch (partition) {
|
||||
case PARTITION_NONE:
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, bs, bs, mi_row, mi_col);
|
||||
break;
|
||||
case PARTITION_HORZ:
|
||||
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);
|
||||
break;
|
||||
case PARTITION_VERT:
|
||||
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);
|
||||
break;
|
||||
case PARTITION_HORZ_A:
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, hbs, hbs, mi_row, mi_col);
|
||||
count_segs(cm, xd, tile, mi + hbs, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, hbs, hbs,
|
||||
mi_row, mi_col + hbs);
|
||||
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);
|
||||
break;
|
||||
case PARTITION_HORZ_B:
|
||||
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, hbs, hbs,
|
||||
mi_row + hbs, mi_col);
|
||||
count_segs(cm, xd, tile, mi + hbs + hbs * mis, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, hbs, hbs,
|
||||
mi_row + hbs, mi_col + hbs);
|
||||
break;
|
||||
case PARTITION_VERT_A:
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, hbs, hbs, mi_row, mi_col);
|
||||
count_segs(cm, xd, tile, mi + hbs * mis, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, hbs, hbs,
|
||||
mi_row + hbs, 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);
|
||||
break;
|
||||
case PARTITION_VERT_B:
|
||||
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, hbs,
|
||||
mi_row, mi_col + hbs);
|
||||
count_segs(cm, xd, tile, mi + hbs + hbs * mis, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, hbs, hbs,
|
||||
mi_row + hbs, mi_col + hbs);
|
||||
break;
|
||||
case PARTITION_SPLIT: {
|
||||
const BLOCK_SIZE subsize = subsize_lookup[PARTITION_SPLIT][bsize];
|
||||
int n;
|
||||
|
||||
assert(num_8x8_blocks_wide_lookup[mi[0]->mbmi.sb_type] < bs &&
|
||||
num_8x8_blocks_high_lookup[mi[0]->mbmi.sb_type] < 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);
|
||||
}
|
||||
} break;
|
||||
default: assert(0);
|
||||
}
|
||||
#else
|
||||
bw = mi_size_wide[mi[0]->mbmi.sb_type];
|
||||
bh = mi_size_high[mi[0]->mbmi.sb_type];
|
||||
|
||||
if (bw == bs && bh == bs) {
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, bs, bs, mi_row, mi_col);
|
||||
} else if (bw == bs && bh < bs) {
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, bs, hbs, mi_row, mi_col);
|
||||
count_segs(cm, xd, tile, mi + hbs * mis, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, bs, hbs,
|
||||
mi_row + hbs, mi_col);
|
||||
} else if (bw < bs && bh == bs) {
|
||||
count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count,
|
||||
t_unpred_seg_counts, hbs, bs, mi_row, mi_col);
|
||||
count_segs(cm, xd, tile, mi + hbs, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, hbs, bs, mi_row,
|
||||
mi_col + hbs);
|
||||
} else {
|
||||
const BLOCK_SIZE subsize = subsize_lookup[PARTITION_SPLIT][bsize];
|
||||
int n;
|
||||
|
||||
assert(bw < bs && bh < bs);
|
||||
|
||||
for (n = 0; n < 4; n++) {
|
||||
const int mi_dc = hbs * (n & 1);
|
||||
const int mi_dr = hbs * (n >> 1);
|
||||
|
||||
count_segs_sb(cm, xd, tile, &mi[mi_dr * mis + mi_dc], no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts,
|
||||
mi_row + mi_dr, mi_col + mi_dc, subsize);
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EXT_PARTITION_TYPES
|
||||
}
|
||||
|
||||
void av1_choose_segmap_coding_method(AV1_COMMON *cm, MACROBLOCKD *xd) {
|
||||
struct segmentation *seg = &cm->seg;
|
||||
struct segmentation_probs *segp = &cm->fc->seg;
|
||||
|
||||
int no_pred_cost;
|
||||
int t_pred_cost = INT_MAX;
|
||||
|
||||
int i, tile_col, tile_row, mi_row, mi_col;
|
||||
#if CONFIG_TILE_GROUPS
|
||||
const int probwt = cm->num_tg;
|
||||
#else
|
||||
const int probwt = 1;
|
||||
#endif
|
||||
|
||||
unsigned(*temporal_predictor_count)[2] = cm->counts.seg.pred;
|
||||
unsigned *no_pred_segcounts = cm->counts.seg.tree_total;
|
||||
unsigned *t_unpred_seg_counts = cm->counts.seg.tree_mispred;
|
||||
|
||||
aom_prob no_pred_tree[SEG_TREE_PROBS];
|
||||
aom_prob t_pred_tree[SEG_TREE_PROBS];
|
||||
aom_prob t_nopred_prob[PREDICTION_PROBS];
|
||||
|
||||
(void)xd;
|
||||
|
||||
// We are about to recompute all the segment counts, so zero the accumulators.
|
||||
av1_zero(cm->counts.seg);
|
||||
|
||||
// First of all generate stats regarding how well the last segment map
|
||||
// predicts this one
|
||||
for (tile_row = 0; tile_row < cm->tile_rows; tile_row++) {
|
||||
TileInfo tile_info;
|
||||
av1_tile_set_row(&tile_info, cm, tile_row);
|
||||
for (tile_col = 0; tile_col < cm->tile_cols; tile_col++) {
|
||||
MODE_INFO **mi_ptr;
|
||||
av1_tile_set_col(&tile_info, cm, tile_col);
|
||||
#if CONFIG_TILE_GROUPS && CONFIG_DEPENDENT_HORZTILES
|
||||
av1_tile_set_tg_boundary(&tile_info, cm, tile_row, tile_col);
|
||||
#endif
|
||||
mi_ptr = cm->mi_grid_visible + tile_info.mi_row_start * cm->mi_stride +
|
||||
tile_info.mi_col_start;
|
||||
for (mi_row = tile_info.mi_row_start; mi_row < tile_info.mi_row_end;
|
||||
mi_row += cm->mib_size, mi_ptr += cm->mib_size * cm->mi_stride) {
|
||||
MODE_INFO **mi = mi_ptr;
|
||||
for (mi_col = tile_info.mi_col_start; mi_col < tile_info.mi_col_end;
|
||||
mi_col += cm->mib_size, mi += cm->mib_size) {
|
||||
count_segs_sb(cm, xd, &tile_info, mi, no_pred_segcounts,
|
||||
temporal_predictor_count, t_unpred_seg_counts, mi_row,
|
||||
mi_col, cm->sb_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Work out probability tree for coding segments without prediction
|
||||
// and the cost.
|
||||
calc_segtree_probs(no_pred_segcounts, no_pred_tree, segp->tree_probs, probwt);
|
||||
no_pred_cost = cost_segmap(no_pred_segcounts, no_pred_tree);
|
||||
|
||||
// Key frames cannot use temporal prediction
|
||||
if (!frame_is_intra_only(cm) && !cm->error_resilient_mode) {
|
||||
// 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, segp->tree_probs,
|
||||
probwt);
|
||||
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);
|
||||
av1_prob_diff_update_savings_search(
|
||||
temporal_predictor_count[i], segp->pred_probs[i], &t_nopred_prob[i],
|
||||
DIFF_UPDATE_PROB, probwt);
|
||||
|
||||
// Add in the predictor signaling cost
|
||||
t_pred_cost += count0 * av1_cost_zero(t_nopred_prob[i]) +
|
||||
count1 * av1_cost_one(t_nopred_prob[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now choose which coding method to use.
|
||||
if (t_pred_cost < no_pred_cost) {
|
||||
assert(!cm->error_resilient_mode);
|
||||
seg->temporal_update = 1;
|
||||
} else {
|
||||
seg->temporal_update = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void av1_reset_segment_features(AV1_COMMON *cm) {
|
||||
struct segmentation *seg = &cm->seg;
|
||||
|
||||
// Set up default state for MB feature flags
|
||||
seg->enabled = 0;
|
||||
seg->update_map = 0;
|
||||
seg->update_data = 0;
|
||||
av1_clearall_segfeatures(seg);
|
||||
}
|
||||
51
third_party/aom/av1/encoder/segmentation.h
vendored
Normal file
51
third_party/aom/av1/encoder/segmentation.h
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_SEGMENTATION_H_
|
||||
#define AV1_ENCODER_SEGMENTATION_H_
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void av1_enable_segmentation(struct segmentation *seg);
|
||||
void av1_disable_segmentation(struct segmentation *seg);
|
||||
|
||||
void av1_disable_segfeature(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id);
|
||||
void av1_clear_segdata(struct segmentation *seg, int segment_id,
|
||||
SEG_LVL_FEATURES feature_id);
|
||||
|
||||
// The values given for each segment can be either deltas (from the default
|
||||
// value chosen for the frame) or absolute values.
|
||||
//
|
||||
// Valid range for abs values is (0-127 for MB_LVL_ALT_Q), (0-63 for
|
||||
// SEGMENT_ALT_LF)
|
||||
// Valid range for delta values are (+/-127 for MB_LVL_ALT_Q), (+/-63 for
|
||||
// SEGMENT_ALT_LF)
|
||||
//
|
||||
// abs_delta = SEGMENT_DELTADATA (deltas) abs_delta = SEGMENT_ABSDATA (use
|
||||
// the absolute values given).
|
||||
void av1_set_segment_data(struct segmentation *seg, signed char *feature_data,
|
||||
unsigned char abs_delta);
|
||||
|
||||
void av1_choose_segmap_coding_method(AV1_COMMON *cm, MACROBLOCKD *xd);
|
||||
|
||||
void av1_reset_segment_features(AV1_COMMON *cm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_SEGMENTATION_H_
|
||||
506
third_party/aom/av1/encoder/speed_features.c
vendored
Normal file
506
third_party/aom/av1/encoder/speed_features.c
vendored
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/speed_features.h"
|
||||
#include "av1/encoder/rdopt.h"
|
||||
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
|
||||
#define MAX_MESH_SPEED 5 // Max speed setting for mesh motion method
|
||||
static MESH_PATTERN
|
||||
good_quality_mesh_patterns[MAX_MESH_SPEED + 1][MAX_MESH_STEP] = {
|
||||
{ { 64, 8 }, { 28, 4 }, { 15, 1 }, { 7, 1 } },
|
||||
{ { 64, 8 }, { 28, 4 }, { 15, 1 }, { 7, 1 } },
|
||||
{ { 64, 8 }, { 14, 2 }, { 7, 1 }, { 7, 1 } },
|
||||
{ { 64, 16 }, { 24, 8 }, { 12, 4 }, { 7, 1 } },
|
||||
{ { 64, 16 }, { 24, 8 }, { 12, 4 }, { 7, 1 } },
|
||||
{ { 64, 16 }, { 24, 8 }, { 12, 4 }, { 7, 1 } },
|
||||
};
|
||||
static unsigned char good_quality_max_mesh_pct[MAX_MESH_SPEED + 1] = {
|
||||
50, 25, 15, 5, 1, 1
|
||||
};
|
||||
|
||||
#if CONFIG_INTRABC
|
||||
// TODO(aconverse@google.com): These settings are pretty relaxed, tune them for
|
||||
// each speed setting
|
||||
static MESH_PATTERN intrabc_mesh_patterns[MAX_MESH_SPEED + 1][MAX_MESH_STEP] = {
|
||||
{ { 64, 1 }, { 64, 1 }, { 0, 0 }, { 0, 0 } },
|
||||
{ { 64, 1 }, { 64, 1 }, { 0, 0 }, { 0, 0 } },
|
||||
{ { 64, 1 }, { 64, 1 }, { 0, 0 }, { 0, 0 } },
|
||||
{ { 64, 4 }, { 16, 1 }, { 0, 0 }, { 0, 0 } },
|
||||
{ { 64, 4 }, { 16, 1 }, { 0, 0 }, { 0, 0 } },
|
||||
{ { 64, 4 }, { 16, 1 }, { 0, 0 }, { 0, 0 } },
|
||||
};
|
||||
static uint8_t intrabc_max_mesh_pct[MAX_MESH_SPEED + 1] = { 100, 100, 100,
|
||||
25, 25, 10 };
|
||||
#endif
|
||||
|
||||
// Intra only frames, golden frames (except alt ref overlays) and
|
||||
// alt ref frames tend to be coded at a higher than ambient quality
|
||||
static int frame_is_boosted(const AV1_COMP *cpi) {
|
||||
return frame_is_kf_gf_arf(cpi);
|
||||
}
|
||||
|
||||
// Sets a partition size down to which the auto partition code will always
|
||||
// search (can go lower), based on the image dimensions. The logic here
|
||||
// is that the extent to which ringing artefacts are offensive, depends
|
||||
// partly on the screen area that over which they propogate. Propogation is
|
||||
// limited by transform block size but the screen area take up by a given block
|
||||
// size will be larger for a small image format stretched to full screen.
|
||||
static BLOCK_SIZE set_partition_min_limit(AV1_COMMON *const cm) {
|
||||
unsigned int screen_area = (cm->width * cm->height);
|
||||
|
||||
// Select block size based on image format size.
|
||||
if (screen_area < 1280 * 720) {
|
||||
// Formats smaller in area than 720P
|
||||
return BLOCK_4X4;
|
||||
} else if (screen_area < 1920 * 1080) {
|
||||
// Format >= 720P and < 1080P
|
||||
return BLOCK_8X8;
|
||||
} else {
|
||||
// Formats 1080P and up
|
||||
return BLOCK_16X16;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_good_speed_feature_framesize_dependent(AV1_COMP *cpi,
|
||||
SPEED_FEATURES *sf,
|
||||
int speed) {
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
|
||||
if (speed >= 1) {
|
||||
if (AOMMIN(cm->width, cm->height) >= 720) {
|
||||
sf->disable_split_mask =
|
||||
cm->show_frame ? DISABLE_ALL_SPLIT : DISABLE_ALL_INTER_SPLIT;
|
||||
sf->partition_search_breakout_dist_thr = (1 << 23);
|
||||
} else {
|
||||
sf->disable_split_mask = DISABLE_COMPOUND_SPLIT;
|
||||
sf->partition_search_breakout_dist_thr = (1 << 21);
|
||||
}
|
||||
}
|
||||
|
||||
if (speed >= 2) {
|
||||
if (AOMMIN(cm->width, cm->height) >= 720) {
|
||||
sf->disable_split_mask =
|
||||
cm->show_frame ? DISABLE_ALL_SPLIT : DISABLE_ALL_INTER_SPLIT;
|
||||
sf->adaptive_pred_interp_filter = 0;
|
||||
sf->partition_search_breakout_dist_thr = (1 << 24);
|
||||
sf->partition_search_breakout_rate_thr = 120;
|
||||
} else {
|
||||
sf->disable_split_mask = LAST_AND_INTRA_SPLIT_ONLY;
|
||||
sf->partition_search_breakout_dist_thr = (1 << 22);
|
||||
sf->partition_search_breakout_rate_thr = 100;
|
||||
}
|
||||
sf->rd_auto_partition_min_limit = set_partition_min_limit(cm);
|
||||
}
|
||||
|
||||
if (speed >= 3) {
|
||||
if (AOMMIN(cm->width, cm->height) >= 720) {
|
||||
sf->disable_split_mask = DISABLE_ALL_SPLIT;
|
||||
sf->schedule_mode_search = cm->base_qindex < 220 ? 1 : 0;
|
||||
sf->partition_search_breakout_dist_thr = (1 << 25);
|
||||
sf->partition_search_breakout_rate_thr = 200;
|
||||
} else {
|
||||
sf->max_intra_bsize = BLOCK_32X32;
|
||||
sf->disable_split_mask = DISABLE_ALL_INTER_SPLIT;
|
||||
sf->schedule_mode_search = cm->base_qindex < 175 ? 1 : 0;
|
||||
sf->partition_search_breakout_dist_thr = (1 << 23);
|
||||
sf->partition_search_breakout_rate_thr = 120;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a two pass clip that fits the criteria for animated or
|
||||
// graphics content then reset disable_split_mask for speeds 1-4.
|
||||
// Also if the image edge is internal to the coded area.
|
||||
if ((speed >= 1) && (cpi->oxcf.pass == 2) &&
|
||||
((cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION) ||
|
||||
(av1_internal_image_edge(cpi)))) {
|
||||
sf->disable_split_mask = DISABLE_COMPOUND_SPLIT;
|
||||
}
|
||||
|
||||
if (speed >= 4) {
|
||||
if (AOMMIN(cm->width, cm->height) >= 720) {
|
||||
sf->partition_search_breakout_dist_thr = (1 << 26);
|
||||
} else {
|
||||
sf->partition_search_breakout_dist_thr = (1 << 24);
|
||||
}
|
||||
sf->disable_split_mask = DISABLE_ALL_SPLIT;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_good_speed_feature(AV1_COMP *cpi, AV1_COMMON *cm,
|
||||
SPEED_FEATURES *sf, int speed) {
|
||||
const int boosted = frame_is_boosted(cpi);
|
||||
|
||||
if (speed >= 1) {
|
||||
sf->tx_type_search.fast_intra_tx_type_search = 1;
|
||||
sf->tx_type_search.fast_inter_tx_type_search = 1;
|
||||
}
|
||||
|
||||
if (speed >= 2) {
|
||||
if ((cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION) ||
|
||||
av1_internal_image_edge(cpi)) {
|
||||
sf->use_square_partition_only = !frame_is_boosted(cpi);
|
||||
} else {
|
||||
sf->use_square_partition_only = !frame_is_intra_only(cm);
|
||||
}
|
||||
|
||||
sf->less_rectangular_check = 1;
|
||||
|
||||
sf->use_rd_breakout = 1;
|
||||
sf->adaptive_motion_search = 1;
|
||||
sf->mv.auto_mv_step_size = 1;
|
||||
sf->adaptive_rd_thresh = 1;
|
||||
sf->mv.subpel_iters_per_step = 1;
|
||||
sf->mode_skip_start = 10;
|
||||
sf->adaptive_pred_interp_filter = 1;
|
||||
|
||||
sf->recode_loop = ALLOW_RECODE_KFARFGF;
|
||||
#if CONFIG_TX64X64
|
||||
sf->intra_y_mode_mask[TX_64X64] = INTRA_DC_H_V;
|
||||
sf->intra_uv_mode_mask[TX_64X64] = INTRA_DC_H_V;
|
||||
#endif // CONFIG_TX64X64
|
||||
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V;
|
||||
sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC_H_V;
|
||||
sf->intra_y_mode_mask[TX_16X16] = INTRA_DC_H_V;
|
||||
sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
|
||||
|
||||
sf->tx_size_search_breakout = 1;
|
||||
sf->partition_search_breakout_rate_thr = 80;
|
||||
sf->tx_type_search.prune_mode = PRUNE_ONE;
|
||||
// Use transform domain distortion.
|
||||
// Note var-tx expt always uses pixel domain distortion.
|
||||
sf->use_transform_domain_distortion = 1;
|
||||
#if CONFIG_EXT_INTER
|
||||
sf->disable_wedge_search_var_thresh = 100;
|
||||
sf->fast_wedge_sign_estimate = 1;
|
||||
#endif // CONFIG_EXT_INTER
|
||||
}
|
||||
|
||||
if (speed >= 3) {
|
||||
sf->tx_size_search_method =
|
||||
frame_is_boosted(cpi) ? USE_FULL_RD : USE_LARGESTALL;
|
||||
sf->mode_search_skip_flags =
|
||||
(cm->frame_type == KEY_FRAME)
|
||||
? 0
|
||||
: FLAG_SKIP_INTRA_DIRMISMATCH | FLAG_SKIP_INTRA_BESTINTER |
|
||||
FLAG_SKIP_COMP_BESTINTRA | FLAG_SKIP_INTRA_LOWVAR;
|
||||
sf->disable_filter_search_var_thresh = 100;
|
||||
sf->comp_inter_joint_search_thresh = BLOCK_SIZES;
|
||||
sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX;
|
||||
sf->allow_partition_search_skip = 1;
|
||||
sf->use_upsampled_references = 0;
|
||||
sf->adaptive_rd_thresh = 2;
|
||||
#if CONFIG_EXT_TX
|
||||
sf->tx_type_search.prune_mode = PRUNE_TWO;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (speed >= 4) {
|
||||
sf->use_square_partition_only = !frame_is_intra_only(cm);
|
||||
sf->tx_size_search_method =
|
||||
frame_is_intra_only(cm) ? USE_FULL_RD : USE_LARGESTALL;
|
||||
sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED;
|
||||
sf->adaptive_pred_interp_filter = 0;
|
||||
sf->adaptive_mode_search = 1;
|
||||
sf->cb_partition_search = !boosted;
|
||||
sf->cb_pred_filter_search = 1;
|
||||
sf->alt_ref_search_fp = 1;
|
||||
sf->recode_loop = ALLOW_RECODE_KFMAXBW;
|
||||
sf->adaptive_rd_thresh = 3;
|
||||
sf->mode_skip_start = 6;
|
||||
#if CONFIG_TX64X64
|
||||
sf->intra_y_mode_mask[TX_64X64] = INTRA_DC;
|
||||
sf->intra_uv_mode_mask[TX_64X64] = INTRA_DC;
|
||||
#endif // CONFIG_TX64X64
|
||||
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC;
|
||||
sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC;
|
||||
sf->adaptive_interp_filter_search = 1;
|
||||
}
|
||||
|
||||
if (speed >= 5) {
|
||||
sf->use_square_partition_only = 1;
|
||||
sf->tx_size_search_method = USE_LARGESTALL;
|
||||
sf->mv.search_method = BIGDIA;
|
||||
sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED_MORE;
|
||||
sf->adaptive_rd_thresh = 4;
|
||||
if (cm->frame_type != KEY_FRAME)
|
||||
sf->mode_search_skip_flags |= FLAG_EARLY_TERMINATE;
|
||||
sf->disable_filter_search_var_thresh = 200;
|
||||
sf->use_fast_coef_updates = ONE_LOOP_REDUCED;
|
||||
sf->use_fast_coef_costing = 1;
|
||||
sf->partition_search_breakout_rate_thr = 300;
|
||||
}
|
||||
|
||||
if (speed >= 6) {
|
||||
int i;
|
||||
sf->optimize_coefficients = 0;
|
||||
sf->mv.search_method = HEX;
|
||||
sf->disable_filter_search_var_thresh = 500;
|
||||
for (i = 0; i < TX_SIZES; ++i) {
|
||||
sf->intra_y_mode_mask[i] = INTRA_DC;
|
||||
sf->intra_uv_mode_mask[i] = INTRA_DC;
|
||||
}
|
||||
sf->partition_search_breakout_rate_thr = 500;
|
||||
sf->mv.reduce_first_step_size = 1;
|
||||
sf->simple_model_rd_from_var = 1;
|
||||
}
|
||||
if (speed >= 7) {
|
||||
const int is_keyframe = cm->frame_type == KEY_FRAME;
|
||||
const int frames_since_key = is_keyframe ? 0 : cpi->rc.frames_since_key;
|
||||
sf->default_max_partition_size = BLOCK_32X32;
|
||||
sf->default_min_partition_size = BLOCK_8X8;
|
||||
#if CONFIG_TX64X64
|
||||
sf->intra_y_mode_mask[TX_64X64] = INTRA_DC;
|
||||
#endif // CONFIG_TX64X64
|
||||
sf->intra_y_mode_mask[TX_32X32] = INTRA_DC;
|
||||
sf->frame_parameter_update = 0;
|
||||
sf->mv.search_method = FAST_HEX;
|
||||
sf->inter_mode_mask[BLOCK_32X32] = INTER_NEAREST_NEAR_NEW;
|
||||
sf->inter_mode_mask[BLOCK_32X64] = INTER_NEAREST;
|
||||
sf->inter_mode_mask[BLOCK_64X32] = INTER_NEAREST;
|
||||
sf->inter_mode_mask[BLOCK_64X64] = INTER_NEAREST;
|
||||
#if CONFIG_EXT_PARTITION
|
||||
sf->inter_mode_mask[BLOCK_64X128] = INTER_NEAREST;
|
||||
sf->inter_mode_mask[BLOCK_128X64] = INTER_NEAREST;
|
||||
sf->inter_mode_mask[BLOCK_128X128] = INTER_NEAREST;
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
sf->partition_search_type = REFERENCE_PARTITION;
|
||||
sf->default_min_partition_size = BLOCK_8X8;
|
||||
sf->reuse_inter_pred_sby = 1;
|
||||
sf->force_frame_boost =
|
||||
is_keyframe ||
|
||||
(frames_since_key % (sf->last_partitioning_redo_frequency << 1) == 1);
|
||||
sf->max_delta_qindex = is_keyframe ? 20 : 15;
|
||||
sf->coeff_prob_appx_step = 4;
|
||||
sf->mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi) {
|
||||
SPEED_FEATURES *const sf = &cpi->sf;
|
||||
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
RD_OPT *const rd = &cpi->rd;
|
||||
int i;
|
||||
|
||||
// Limit memory usage for high resolutions
|
||||
#if CONFIG_EXT_REFS
|
||||
// TODO(zoeliu): Temporary solution to resolve the insufficient RAM issue for
|
||||
// ext-refs. Need to work with @yunqingwang to have a more
|
||||
// effective solution.
|
||||
if (AOMMIN(cm->width, cm->height) > 720) {
|
||||
// Turn off the use of upsampled references for HD resolution
|
||||
sf->use_upsampled_references = 0;
|
||||
} else if ((AOMMIN(cm->width, cm->height) > 540) &&
|
||||
(oxcf->profile != PROFILE_0)) {
|
||||
sf->use_upsampled_references = 0;
|
||||
}
|
||||
#else
|
||||
if (AOMMIN(cm->width, cm->height) > 1080) {
|
||||
sf->use_upsampled_references = 0;
|
||||
} else if ((AOMMIN(cm->width, cm->height) > 720) &&
|
||||
(oxcf->profile != PROFILE_0)) {
|
||||
sf->use_upsampled_references = 0;
|
||||
}
|
||||
#endif // CONFIG_EXT_REFS
|
||||
|
||||
if (oxcf->mode == GOOD) {
|
||||
set_good_speed_feature_framesize_dependent(cpi, sf, oxcf->speed);
|
||||
}
|
||||
|
||||
if (sf->disable_split_mask == DISABLE_ALL_SPLIT) {
|
||||
sf->adaptive_pred_interp_filter = 0;
|
||||
}
|
||||
|
||||
// Check for masked out split cases.
|
||||
for (i = 0; i < MAX_REFS; ++i) {
|
||||
if (sf->disable_split_mask & (1 << i)) {
|
||||
rd->thresh_mult_sub8x8[i] = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
// This is only used in motion vector unit test.
|
||||
if (cpi->oxcf.motion_vector_unit_test == 1)
|
||||
cpi->find_fractional_mv_step = av1_return_max_sub_pixel_mv;
|
||||
else if (cpi->oxcf.motion_vector_unit_test == 2)
|
||||
cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv;
|
||||
}
|
||||
|
||||
void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
|
||||
SPEED_FEATURES *const sf = &cpi->sf;
|
||||
AV1_COMMON *const cm = &cpi->common;
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
int i;
|
||||
|
||||
// best quality defaults
|
||||
sf->frame_parameter_update = 1;
|
||||
sf->mv.search_method = NSTEP;
|
||||
sf->recode_loop = ALLOW_RECODE;
|
||||
sf->mv.subpel_search_method = SUBPEL_TREE;
|
||||
sf->mv.subpel_iters_per_step = 2;
|
||||
sf->mv.subpel_force_stop = 0;
|
||||
sf->optimize_coefficients = !is_lossless_requested(&cpi->oxcf);
|
||||
sf->mv.reduce_first_step_size = 0;
|
||||
sf->coeff_prob_appx_step = 1;
|
||||
sf->mv.auto_mv_step_size = 0;
|
||||
sf->mv.fullpel_search_step_param = 6;
|
||||
sf->comp_inter_joint_search_thresh = BLOCK_4X4;
|
||||
sf->adaptive_rd_thresh = 0;
|
||||
sf->tx_size_search_method = USE_FULL_RD;
|
||||
sf->adaptive_motion_search = 0;
|
||||
sf->adaptive_pred_interp_filter = 0;
|
||||
sf->adaptive_mode_search = 0;
|
||||
sf->cb_pred_filter_search = 0;
|
||||
sf->cb_partition_search = 0;
|
||||
sf->alt_ref_search_fp = 0;
|
||||
sf->partition_search_type = SEARCH_PARTITION;
|
||||
sf->tx_type_search.prune_mode = NO_PRUNE;
|
||||
sf->tx_type_search.fast_intra_tx_type_search = 0;
|
||||
sf->tx_type_search.fast_inter_tx_type_search = 0;
|
||||
sf->less_rectangular_check = 0;
|
||||
sf->use_square_partition_only = 0;
|
||||
sf->auto_min_max_partition_size = NOT_IN_USE;
|
||||
sf->rd_auto_partition_min_limit = BLOCK_4X4;
|
||||
sf->default_max_partition_size = BLOCK_LARGEST;
|
||||
sf->default_min_partition_size = BLOCK_4X4;
|
||||
sf->adjust_partitioning_from_last_frame = 0;
|
||||
sf->last_partitioning_redo_frequency = 4;
|
||||
sf->disable_split_mask = 0;
|
||||
sf->mode_search_skip_flags = 0;
|
||||
sf->force_frame_boost = 0;
|
||||
sf->max_delta_qindex = 0;
|
||||
sf->disable_filter_search_var_thresh = 0;
|
||||
sf->adaptive_interp_filter_search = 0;
|
||||
sf->allow_partition_search_skip = 0;
|
||||
sf->use_upsampled_references = 1;
|
||||
#if CONFIG_EXT_INTER
|
||||
sf->disable_wedge_search_var_thresh = 0;
|
||||
sf->fast_wedge_sign_estimate = 0;
|
||||
#endif // CONFIG_EXT_INTER
|
||||
|
||||
for (i = 0; i < TX_SIZES; i++) {
|
||||
sf->intra_y_mode_mask[i] = INTRA_ALL;
|
||||
sf->intra_uv_mode_mask[i] = INTRA_ALL;
|
||||
}
|
||||
sf->use_rd_breakout = 0;
|
||||
sf->lpf_pick = LPF_PICK_FROM_FULL_IMAGE;
|
||||
sf->use_fast_coef_updates = TWO_LOOP;
|
||||
sf->use_fast_coef_costing = 0;
|
||||
sf->mode_skip_start = MAX_MODES; // Mode index at which mode skip mask set
|
||||
sf->schedule_mode_search = 0;
|
||||
for (i = 0; i < BLOCK_SIZES; ++i) sf->inter_mode_mask[i] = INTER_ALL;
|
||||
sf->max_intra_bsize = BLOCK_LARGEST;
|
||||
sf->reuse_inter_pred_sby = 0;
|
||||
// This setting only takes effect when partition_search_type is set
|
||||
// to FIXED_PARTITION.
|
||||
sf->always_this_block_size = BLOCK_16X16;
|
||||
sf->search_type_check_frequency = 50;
|
||||
// Recode loop tolerance %.
|
||||
sf->recode_tolerance = 25;
|
||||
sf->default_interp_filter = SWITCHABLE;
|
||||
sf->tx_size_search_breakout = 0;
|
||||
sf->partition_search_breakout_dist_thr = 0;
|
||||
sf->partition_search_breakout_rate_thr = 0;
|
||||
sf->simple_model_rd_from_var = 0;
|
||||
|
||||
// Set this at the appropriate speed levels
|
||||
sf->use_transform_domain_distortion = 0;
|
||||
|
||||
if (oxcf->mode == GOOD
|
||||
#if CONFIG_XIPHRC
|
||||
|| oxcf->pass == 1
|
||||
#endif
|
||||
)
|
||||
set_good_speed_feature(cpi, cm, sf, oxcf->speed);
|
||||
|
||||
// sf->partition_search_breakout_dist_thr is set assuming max 64x64
|
||||
// blocks. Normalise this if the blocks are bigger.
|
||||
if (MAX_SB_SIZE_LOG2 > 6) {
|
||||
sf->partition_search_breakout_dist_thr <<= 2 * (MAX_SB_SIZE_LOG2 - 6);
|
||||
}
|
||||
|
||||
cpi->full_search_sad = av1_full_search_sad;
|
||||
cpi->diamond_search_sad = av1_diamond_search_sad;
|
||||
|
||||
sf->allow_exhaustive_searches = 1;
|
||||
int speed = (oxcf->speed > MAX_MESH_SPEED) ? MAX_MESH_SPEED : oxcf->speed;
|
||||
if (cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION)
|
||||
sf->exhaustive_searches_thresh = (1 << 24);
|
||||
else
|
||||
sf->exhaustive_searches_thresh = (1 << 25);
|
||||
sf->max_exaustive_pct = good_quality_max_mesh_pct[speed];
|
||||
if (speed > 0)
|
||||
sf->exhaustive_searches_thresh = sf->exhaustive_searches_thresh << 1;
|
||||
|
||||
for (i = 0; i < MAX_MESH_STEP; ++i) {
|
||||
sf->mesh_patterns[i].range = good_quality_mesh_patterns[speed][i].range;
|
||||
sf->mesh_patterns[i].interval =
|
||||
good_quality_mesh_patterns[speed][i].interval;
|
||||
}
|
||||
#if CONFIG_INTRABC
|
||||
if ((frame_is_intra_only(cm) && cm->allow_screen_content_tools) &&
|
||||
(cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION ||
|
||||
cpi->oxcf.content == AOM_CONTENT_SCREEN)) {
|
||||
for (i = 0; i < MAX_MESH_STEP; ++i) {
|
||||
sf->mesh_patterns[i].range = intrabc_mesh_patterns[speed][i].range;
|
||||
sf->mesh_patterns[i].interval = intrabc_mesh_patterns[speed][i].interval;
|
||||
}
|
||||
sf->max_exaustive_pct = intrabc_max_mesh_pct[speed];
|
||||
}
|
||||
#endif // CONFIG_INTRABC
|
||||
|
||||
#if !CONFIG_XIPHRC
|
||||
// Slow quant, dct and trellis not worthwhile for first pass
|
||||
// so make sure they are always turned off.
|
||||
if (oxcf->pass == 1) sf->optimize_coefficients = 0;
|
||||
#endif
|
||||
|
||||
// No recode for 1 pass.
|
||||
if (oxcf->pass == 0) {
|
||||
sf->recode_loop = DISALLOW_RECODE;
|
||||
sf->optimize_coefficients = 0;
|
||||
}
|
||||
|
||||
if (sf->mv.subpel_search_method == SUBPEL_TREE) {
|
||||
cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree;
|
||||
} else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED) {
|
||||
cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree_pruned;
|
||||
} else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED_MORE) {
|
||||
cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree_pruned_more;
|
||||
} else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED_EVENMORE) {
|
||||
cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree_pruned_evenmore;
|
||||
}
|
||||
|
||||
#if !CONFIG_AOM_QM
|
||||
x->optimize = sf->optimize_coefficients == 1 && oxcf->pass != 1;
|
||||
#else
|
||||
// FIXME: trellis not very efficient for quantisation matrices
|
||||
x->optimize = 0;
|
||||
#endif
|
||||
|
||||
x->min_partition_size = sf->default_min_partition_size;
|
||||
x->max_partition_size = sf->default_max_partition_size;
|
||||
|
||||
if (!cpi->oxcf.frame_periodic_boost) {
|
||||
sf->max_delta_qindex = 0;
|
||||
}
|
||||
|
||||
// This is only used in motion vector unit test.
|
||||
if (cpi->oxcf.motion_vector_unit_test == 1)
|
||||
cpi->find_fractional_mv_step = av1_return_max_sub_pixel_mv;
|
||||
else if (cpi->oxcf.motion_vector_unit_test == 2)
|
||||
cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv;
|
||||
}
|
||||
484
third_party/aom/av1/encoder/speed_features.h
vendored
Normal file
484
third_party/aom/av1/encoder/speed_features.h
vendored
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_SPEED_FEATURES_H_
|
||||
#define AV1_ENCODER_SPEED_FEATURES_H_
|
||||
|
||||
#include "av1/common/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) |
|
||||
#if CONFIG_ALT_INTRA
|
||||
(1 << SMOOTH_PRED) |
|
||||
#endif // CONFIG_ALT_INTRA
|
||||
(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)
|
||||
};
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
enum {
|
||||
INTER_ALL = (1 << NEARESTMV) | (1 << NEARMV) | (1 << ZEROMV) | (1 << NEWMV) |
|
||||
(1 << NEAREST_NEARESTMV) | (1 << NEAR_NEARMV) |
|
||||
(1 << NEAREST_NEARMV) | (1 << NEAR_NEARESTMV) | (1 << NEW_NEWMV) |
|
||||
(1 << NEAREST_NEWMV) | (1 << NEAR_NEWMV) | (1 << NEW_NEARMV) |
|
||||
(1 << NEW_NEARESTMV) | (1 << ZERO_ZEROMV),
|
||||
INTER_NEAREST = (1 << NEARESTMV) | (1 << NEAREST_NEARESTMV) |
|
||||
(1 << NEAREST_NEARMV) | (1 << NEAR_NEARESTMV) |
|
||||
(1 << NEW_NEARESTMV) | (1 << NEAREST_NEWMV),
|
||||
INTER_NEAREST_NEW = (1 << NEARESTMV) | (1 << NEWMV) |
|
||||
(1 << NEAREST_NEARESTMV) | (1 << NEW_NEWMV) |
|
||||
(1 << NEAR_NEARESTMV) | (1 << NEAREST_NEARMV) |
|
||||
(1 << NEW_NEARESTMV) | (1 << NEAREST_NEWMV) |
|
||||
(1 << NEW_NEARMV) | (1 << NEAR_NEWMV),
|
||||
INTER_NEAREST_ZERO = (1 << NEARESTMV) | (1 << ZEROMV) |
|
||||
(1 << NEAREST_NEARESTMV) | (1 << ZERO_ZEROMV) |
|
||||
(1 << NEAREST_NEARMV) | (1 << NEAR_NEARESTMV) |
|
||||
(1 << NEAREST_NEWMV) | (1 << NEW_NEARESTMV),
|
||||
INTER_NEAREST_NEW_ZERO =
|
||||
(1 << NEARESTMV) | (1 << ZEROMV) | (1 << NEWMV) |
|
||||
(1 << NEAREST_NEARESTMV) | (1 << ZERO_ZEROMV) | (1 << NEW_NEWMV) |
|
||||
(1 << NEAREST_NEARMV) | (1 << NEAR_NEARESTMV) | (1 << NEW_NEARESTMV) |
|
||||
(1 << NEAREST_NEWMV) | (1 << NEW_NEARMV) | (1 << NEAR_NEWMV),
|
||||
INTER_NEAREST_NEAR_NEW =
|
||||
(1 << NEARESTMV) | (1 << NEARMV) | (1 << NEWMV) |
|
||||
(1 << NEAREST_NEARESTMV) | (1 << NEW_NEWMV) | (1 << NEAREST_NEARMV) |
|
||||
(1 << NEAR_NEARESTMV) | (1 << NEW_NEARESTMV) | (1 << NEAREST_NEWMV) |
|
||||
(1 << NEW_NEARMV) | (1 << NEAR_NEWMV) | (1 << NEAR_NEARMV),
|
||||
INTER_NEAREST_NEAR_ZERO =
|
||||
(1 << NEARESTMV) | (1 << NEARMV) | (1 << ZEROMV) |
|
||||
(1 << NEAREST_NEARESTMV) | (1 << ZERO_ZEROMV) | (1 << NEAREST_NEARMV) |
|
||||
(1 << NEAR_NEARESTMV) | (1 << NEAREST_NEWMV) | (1 << NEW_NEARESTMV) |
|
||||
(1 << NEW_NEARMV) | (1 << NEAR_NEWMV) | (1 << NEAR_NEARMV),
|
||||
};
|
||||
#else
|
||||
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),
|
||||
};
|
||||
#endif // CONFIG_EXT_INTER
|
||||
|
||||
enum {
|
||||
DISABLE_ALL_INTER_SPLIT = (1 << THR_COMP_GA) | (1 << THR_COMP_LA) |
|
||||
(1 << THR_ALTR) | (1 << THR_GOLD) | (1 << THR_LAST),
|
||||
|
||||
DISABLE_ALL_SPLIT = (1 << THR_INTRA) | DISABLE_ALL_INTER_SPLIT,
|
||||
|
||||
DISABLE_COMPOUND_SPLIT = (1 << THR_COMP_GA) | (1 << THR_COMP_LA),
|
||||
|
||||
LAST_AND_INTRA_SPLIT_ONLY = (1 << THR_COMP_GA) | (1 << THR_COMP_LA) |
|
||||
(1 << THR_ALTR) | (1 << THR_GOLD)
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
DIAMOND = 0,
|
||||
NSTEP = 1,
|
||||
HEX = 2,
|
||||
BIGDIA = 3,
|
||||
SQUARE = 4,
|
||||
FAST_HEX = 5,
|
||||
FAST_DIAMOND = 6
|
||||
} SEARCH_METHODS;
|
||||
|
||||
typedef enum {
|
||||
// No recode.
|
||||
DISALLOW_RECODE = 0,
|
||||
// Allow recode for KF and exceeding maximum frame bandwidth.
|
||||
ALLOW_RECODE_KFMAXBW = 1,
|
||||
// Allow recode only for KF/ARF/GF frames.
|
||||
ALLOW_RECODE_KFARFGF = 2,
|
||||
// Allow recode for all frames based on bitrate constraints.
|
||||
ALLOW_RECODE = 3,
|
||||
} RECODE_LOOP_TYPE;
|
||||
|
||||
typedef enum {
|
||||
SUBPEL_TREE = 0,
|
||||
SUBPEL_TREE_PRUNED = 1, // Prunes 1/2-pel searches
|
||||
SUBPEL_TREE_PRUNED_MORE = 2, // Prunes 1/2-pel searches more aggressively
|
||||
SUBPEL_TREE_PRUNED_EVENMORE = 3, // Prunes 1/2- and 1/4-pel searches
|
||||
// Other methods to come
|
||||
} SUBPEL_SEARCH_METHODS;
|
||||
|
||||
typedef enum {
|
||||
NO_MOTION_THRESHOLD = 0,
|
||||
LOW_MOTION_THRESHOLD = 7
|
||||
} MOTION_THRESHOLD;
|
||||
|
||||
typedef enum {
|
||||
USE_FULL_RD = 0,
|
||||
USE_LARGESTALL,
|
||||
USE_TX_8X8
|
||||
} TX_SIZE_SEARCH_METHOD;
|
||||
|
||||
typedef enum {
|
||||
NOT_IN_USE = 0,
|
||||
RELAXED_NEIGHBORING_MIN_MAX = 1
|
||||
} 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_REGULAR = 1 << EIGHTTAP_REGULAR,
|
||||
FLAG_SKIP_EIGHTTAP_SMOOTH = 1 << EIGHTTAP_SMOOTH,
|
||||
FLAG_SKIP_MULTITAP_SHARP = 1 << MULTITAP_SHARP,
|
||||
} INTERP_FILTER_MASK;
|
||||
|
||||
typedef enum {
|
||||
NO_PRUNE = 0,
|
||||
// eliminates one tx type in vertical and horizontal direction
|
||||
PRUNE_ONE = 1,
|
||||
#if CONFIG_EXT_TX
|
||||
// eliminates two tx types in each direction
|
||||
PRUNE_TWO = 2,
|
||||
#endif
|
||||
} TX_TYPE_PRUNE_MODE;
|
||||
|
||||
typedef struct {
|
||||
TX_TYPE_PRUNE_MODE prune_mode;
|
||||
int fast_intra_tx_type_search;
|
||||
int fast_inter_tx_type_search;
|
||||
} TX_TYPE_SEARCH;
|
||||
|
||||
typedef enum {
|
||||
// Search partitions using RD criterion
|
||||
SEARCH_PARTITION,
|
||||
|
||||
// Always use a fixed size partition
|
||||
FIXED_PARTITION,
|
||||
|
||||
REFERENCE_PARTITION,
|
||||
|
||||
// Use an arbitrary partitioning scheme based on source variance within
|
||||
// a 64X64 SB
|
||||
VAR_BASED_PARTITION,
|
||||
|
||||
// Use non-fixed partitions based on source variance
|
||||
SOURCE_VAR_BASED_PARTITION
|
||||
} PARTITION_SEARCH_TYPE;
|
||||
|
||||
typedef enum {
|
||||
// Does a dry run to see if any of the contexts need to be updated or not,
|
||||
// before the final run.
|
||||
TWO_LOOP = 0,
|
||||
|
||||
// No dry run, also only half the coef contexts and bands are updated.
|
||||
// The rest are not updated at all.
|
||||
ONE_LOOP_REDUCED = 1
|
||||
} FAST_COEFF_UPDATE;
|
||||
|
||||
typedef struct MV_SPEED_FEATURES {
|
||||
// Motion search method (Diamond, NSTEP, Hex, Big Diamond, Square, etc).
|
||||
SEARCH_METHODS search_method;
|
||||
|
||||
// This parameter controls which step in the n-step process we start at.
|
||||
// It's changed adaptively based on circumstances.
|
||||
int reduce_first_step_size;
|
||||
|
||||
// If this is set to 1, we limit the motion search range to 2 times the
|
||||
// largest motion vector found in the last frame.
|
||||
int auto_mv_step_size;
|
||||
|
||||
// Subpel_search_method can only be subpel_tree which does a subpixel
|
||||
// logarithmic search that keeps stepping at 1/2 pixel units until
|
||||
// you stop getting a gain, and then goes on to 1/4 and repeats
|
||||
// the same process. Along the way it skips many diagonals.
|
||||
SUBPEL_SEARCH_METHODS subpel_search_method;
|
||||
|
||||
// Maximum number of steps in logarithmic subpel search before giving up.
|
||||
int subpel_iters_per_step;
|
||||
|
||||
// Control when to stop subpel search
|
||||
int subpel_force_stop;
|
||||
|
||||
// This variable sets the step_param used in full pel motion search.
|
||||
int fullpel_search_step_param;
|
||||
} MV_SPEED_FEATURES;
|
||||
|
||||
#define MAX_MESH_STEP 4
|
||||
|
||||
typedef struct MESH_PATTERN {
|
||||
int range;
|
||||
int interval;
|
||||
} MESH_PATTERN;
|
||||
|
||||
typedef struct SPEED_FEATURES {
|
||||
MV_SPEED_FEATURES mv;
|
||||
|
||||
// Frame level coding parameter update
|
||||
int frame_parameter_update;
|
||||
|
||||
RECODE_LOOP_TYPE recode_loop;
|
||||
|
||||
// Trellis (dynamic programming) optimization of quantized values (+1, 0).
|
||||
int optimize_coefficients;
|
||||
|
||||
// Always set to 0. If on it enables 0 cost background transmission
|
||||
// (except for the initial transmission of the segmentation). The feature is
|
||||
// disabled because the addition of very large block sizes make the
|
||||
// backgrounds very to cheap to encode, and the segmentation we have
|
||||
// adds overhead.
|
||||
int static_segmentation;
|
||||
|
||||
// If 1 we iterate finding a best reference for 2 ref frames together - via
|
||||
// a log search that iterates 4 times (check around mv for last for best
|
||||
// error of combined predictor then check around mv for alt). If 0 we
|
||||
// we just use the best motion vector found for each frame by itself.
|
||||
BLOCK_SIZE comp_inter_joint_search_thresh;
|
||||
|
||||
// This variable is used to cap the maximum number of times we skip testing a
|
||||
// mode to be evaluated. A high value means we will be faster.
|
||||
int adaptive_rd_thresh;
|
||||
|
||||
// Coefficient probability model approximation step size
|
||||
int coeff_prob_appx_step;
|
||||
|
||||
// The threshold is to determine how slow the motino is, it is used when
|
||||
// use_lastframe_partitioning is set to LAST_FRAME_PARTITION_LOW_MOTION
|
||||
MOTION_THRESHOLD lf_motion_threshold;
|
||||
|
||||
// Determine which method we use to determine transform size. We can choose
|
||||
// between options like full rd, largest for prediction size, largest
|
||||
// for intra and model coefs for the rest.
|
||||
TX_SIZE_SEARCH_METHOD tx_size_search_method;
|
||||
|
||||
// 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;
|
||||
|
||||
PARTITION_SEARCH_TYPE partition_search_type;
|
||||
|
||||
TX_TYPE_SEARCH tx_type_search;
|
||||
|
||||
// Used if partition_search_type = FIXED_SIZE_PARTITION
|
||||
BLOCK_SIZE always_this_block_size;
|
||||
|
||||
// Skip rectangular partition test when partition type none gives better
|
||||
// rd than partition type split.
|
||||
int less_rectangular_check;
|
||||
|
||||
// Disable testing non square partitions. (eg 16x32)
|
||||
int use_square_partition_only;
|
||||
|
||||
// Sets min and max partition sizes for this superblock based on the
|
||||
// same superblock 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;
|
||||
|
||||
// Flag for allowing some use of exhaustive searches;
|
||||
int allow_exhaustive_searches;
|
||||
|
||||
// Threshold for allowing exhaistive motion search.
|
||||
int exhaustive_searches_thresh;
|
||||
|
||||
// Maximum number of exhaustive searches for a frame.
|
||||
int max_exaustive_pct;
|
||||
|
||||
// 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 alt_ref_search_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;
|
||||
|
||||
#if CONFIG_EXT_INTER
|
||||
// A source variance threshold below which wedge search is disabled
|
||||
unsigned int disable_wedge_search_var_thresh;
|
||||
|
||||
// Whether fast wedge sign estimate is used
|
||||
int fast_wedge_sign_estimate;
|
||||
#endif // CONFIG_EXT_INTER
|
||||
|
||||
// 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 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;
|
||||
|
||||
// A binary mask indicating if NEARESTMV, NEARMV, ZEROMV, NEWMV
|
||||
// modes are used in order from LSB to MSB for each BLOCK_SIZE.
|
||||
int inter_mode_mask[BLOCK_SIZES];
|
||||
|
||||
// This feature controls whether we do the expensive context update and
|
||||
// calculation in the rd coefficient costing loop.
|
||||
int use_fast_coef_costing;
|
||||
|
||||
// This feature controls the tolerence vs target used in deciding whether to
|
||||
// recode a frame. It has no meaning if recode is disabled.
|
||||
int recode_tolerance;
|
||||
|
||||
// This variable controls the maximum block size where intra blocks can be
|
||||
// used in inter frames.
|
||||
// TODO(aconverse): Fold this into one of the other many mode skips
|
||||
BLOCK_SIZE max_intra_bsize;
|
||||
|
||||
// The frequency that we check if SOURCE_VAR_BASED_PARTITION or
|
||||
// FIXED_PARTITION search type should be used.
|
||||
int search_type_check_frequency;
|
||||
|
||||
// When partition is pre-set, the inter prediction result from pick_inter_mode
|
||||
// can be reused in final block encoding process. It is enabled only for real-
|
||||
// time mode speed 6.
|
||||
int reuse_inter_pred_sby;
|
||||
|
||||
// default interp filter choice
|
||||
InterpFilter default_interp_filter;
|
||||
|
||||
// Early termination in transform size search, which only applies while
|
||||
// tx_size_search_method is USE_FULL_RD.
|
||||
int tx_size_search_breakout;
|
||||
|
||||
// adaptive interp_filter search to allow skip of certain filter types.
|
||||
int adaptive_interp_filter_search;
|
||||
|
||||
// mask for skip evaluation of certain interp_filter type.
|
||||
INTERP_FILTER_MASK interp_filter_search_mask;
|
||||
|
||||
// Partition search early breakout thresholds.
|
||||
int64_t partition_search_breakout_dist_thr;
|
||||
int partition_search_breakout_rate_thr;
|
||||
|
||||
// Allow skipping partition search for still image frame
|
||||
int allow_partition_search_skip;
|
||||
|
||||
// Fast approximation of av1_model_rd_from_var_lapndz
|
||||
int simple_model_rd_from_var;
|
||||
|
||||
// Do sub-pixel search in up-sampled reference frames
|
||||
int use_upsampled_references;
|
||||
|
||||
// Whether to compute distortion in the image domain (slower but
|
||||
// more accurate), or in the transform domain (faster but less acurate).
|
||||
int use_transform_domain_distortion;
|
||||
} SPEED_FEATURES;
|
||||
|
||||
struct AV1_COMP;
|
||||
|
||||
void av1_set_speed_features_framesize_independent(struct AV1_COMP *cpi);
|
||||
void av1_set_speed_features_framesize_dependent(struct AV1_COMP *cpi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_SPEED_FEATURES_H_
|
||||
282
third_party/aom/av1/encoder/subexp.c
vendored
Normal file
282
third_party/aom/av1/encoder/subexp.c
vendored
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
|
||||
#include "av1/common/common.h"
|
||||
#include "av1/common/entropy.h"
|
||||
#include "av1/encoder/cost.h"
|
||||
#include "av1/encoder/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, 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, 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;
|
||||
|
||||
i = map_table[i];
|
||||
return i;
|
||||
}
|
||||
|
||||
static int prob_diff_update_cost(aom_prob newp, aom_prob oldp) {
|
||||
int delp = remap_prob(newp, oldp);
|
||||
return update_bits[delp] << AV1_PROB_COST_SHIFT;
|
||||
}
|
||||
|
||||
static void encode_uniform(aom_writer *w, int v) {
|
||||
const int l = 8;
|
||||
const int m = (1 << l) - 190;
|
||||
if (v < m) {
|
||||
aom_write_literal(w, v, l - 1);
|
||||
} else {
|
||||
aom_write_literal(w, m + ((v - m) >> 1), l - 1);
|
||||
aom_write_literal(w, (v - m) & 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE int write_bit_gte(aom_writer *w, int word, int test) {
|
||||
aom_write_literal(w, word >= test, 1);
|
||||
return word >= test;
|
||||
}
|
||||
|
||||
static void encode_term_subexp(aom_writer *w, int word) {
|
||||
if (!write_bit_gte(w, word, 16)) {
|
||||
aom_write_literal(w, word, 4);
|
||||
} else if (!write_bit_gte(w, word, 32)) {
|
||||
aom_write_literal(w, word - 16, 4);
|
||||
} else if (!write_bit_gte(w, word, 64)) {
|
||||
aom_write_literal(w, word - 32, 5);
|
||||
} else {
|
||||
encode_uniform(w, word - 64);
|
||||
}
|
||||
}
|
||||
|
||||
void av1_write_prob_diff_update(aom_writer *w, aom_prob newp, aom_prob oldp) {
|
||||
const int delp = remap_prob(newp, oldp);
|
||||
encode_term_subexp(w, delp);
|
||||
}
|
||||
|
||||
int av1_prob_diff_update_savings_search(const unsigned int *ct, aom_prob oldp,
|
||||
aom_prob *bestp, aom_prob upd,
|
||||
int probwt) {
|
||||
const uint32_t old_b = cost_branch256(ct, oldp);
|
||||
int bestsavings = 0;
|
||||
aom_prob newp, bestnewp = oldp;
|
||||
const int step = *bestp > oldp ? -1 : 1;
|
||||
const int upd_cost = av1_cost_one(upd) - av1_cost_zero(upd);
|
||||
|
||||
if (old_b > (uint32_t)upd_cost + (MIN_DELP_BITS << AV1_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 = (int)((int64_t)old_b - new_b - update_b * probwt);
|
||||
if (savings > bestsavings) {
|
||||
bestsavings = savings;
|
||||
bestnewp = newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
*bestp = bestnewp;
|
||||
return bestsavings;
|
||||
}
|
||||
|
||||
int av1_prob_diff_update_savings_search_model(const unsigned int *ct,
|
||||
const aom_prob oldp,
|
||||
aom_prob *bestp, aom_prob upd,
|
||||
int stepsize, int probwt) {
|
||||
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 = av1_cost_one(upd) - av1_cost_zero(upd);
|
||||
const aom_prob *newplist, *oldplist;
|
||||
aom_prob bestnewp;
|
||||
oldplist = av1_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 << AV1_PROB_COST_SHIFT)) {
|
||||
for (newp = *bestp; (newp - oldp) * step_sign < 0; newp += step) {
|
||||
if (newp < 1 || newp > 255) continue;
|
||||
newplist = av1_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 * probwt;
|
||||
if (savings > bestsavings) {
|
||||
bestsavings = savings;
|
||||
bestnewp = newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*bestp = bestnewp;
|
||||
return bestsavings;
|
||||
}
|
||||
|
||||
#if CONFIG_SUBFRAME_PROB_UPDATE
|
||||
static int get_cost(unsigned int ct[][2], aom_prob p, int n) {
|
||||
int i, p0 = p;
|
||||
unsigned int total_ct[2] = { 0, 0 };
|
||||
int cost = 0;
|
||||
|
||||
for (i = 0; i <= n; ++i) {
|
||||
cost += cost_branch256(ct[i], p);
|
||||
total_ct[0] += ct[i][0];
|
||||
total_ct[1] += ct[i][1];
|
||||
if (i < n)
|
||||
p = av1_merge_probs(p0, total_ct, COEF_COUNT_SAT, COEF_MAX_UPDATE_FACTOR);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
int av1_prob_update_search_subframe(unsigned int ct[][2], aom_prob oldp,
|
||||
aom_prob *bestp, aom_prob upd, int n) {
|
||||
const int old_b = get_cost(ct, oldp, n);
|
||||
int bestsavings = 0;
|
||||
const int upd_cost = av1_cost_one(upd) - av1_cost_zero(upd);
|
||||
aom_prob newp, bestnewp = oldp;
|
||||
const int step = *bestp > oldp ? -1 : 1;
|
||||
|
||||
for (newp = *bestp; newp != oldp; newp += step) {
|
||||
const int new_b = get_cost(ct, newp, n);
|
||||
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 av1_prob_update_search_model_subframe(
|
||||
unsigned int ct[ENTROPY_NODES][COEF_PROBS_BUFS][2], const aom_prob *oldp,
|
||||
aom_prob *bestp, aom_prob upd, int stepsize, int n) {
|
||||
int i, old_b, new_b, update_b, savings, bestsavings;
|
||||
int newp;
|
||||
const int step_sign = *bestp > oldp[PIVOT_NODE] ? -1 : 1;
|
||||
const int step = stepsize * step_sign;
|
||||
const int upd_cost = av1_cost_one(upd) - av1_cost_zero(upd);
|
||||
aom_prob bestnewp, newplist[ENTROPY_NODES], oldplist[ENTROPY_NODES];
|
||||
av1_model_to_full_probs(oldp, oldplist);
|
||||
memcpy(newplist, oldp, sizeof(aom_prob) * UNCONSTRAINED_NODES);
|
||||
for (i = UNCONSTRAINED_NODES, old_b = 0; i < ENTROPY_NODES; ++i)
|
||||
old_b += get_cost(ct[i], oldplist[i], n);
|
||||
old_b += get_cost(ct[PIVOT_NODE], oldplist[PIVOT_NODE], n);
|
||||
|
||||
bestsavings = 0;
|
||||
bestnewp = oldp[PIVOT_NODE];
|
||||
|
||||
assert(stepsize > 0);
|
||||
|
||||
for (newp = *bestp; (newp - oldp[PIVOT_NODE]) * step_sign < 0; newp += step) {
|
||||
if (newp < 1 || newp > 255) continue;
|
||||
newplist[PIVOT_NODE] = newp;
|
||||
av1_model_to_full_probs(newplist, newplist);
|
||||
for (i = UNCONSTRAINED_NODES, new_b = 0; i < ENTROPY_NODES; ++i)
|
||||
new_b += get_cost(ct[i], newplist[i], n);
|
||||
new_b += get_cost(ct[PIVOT_NODE], newplist[PIVOT_NODE], n);
|
||||
update_b = prob_diff_update_cost(newp, oldp[PIVOT_NODE]) + upd_cost;
|
||||
savings = old_b - new_b - update_b;
|
||||
if (savings > bestsavings) {
|
||||
bestsavings = savings;
|
||||
bestnewp = newp;
|
||||
}
|
||||
}
|
||||
|
||||
*bestp = bestnewp;
|
||||
return bestsavings;
|
||||
}
|
||||
#endif // CONFIG_SUBFRAME_PROB_UPDATE
|
||||
|
||||
void av1_cond_prob_diff_update(aom_writer *w, aom_prob *oldp,
|
||||
const unsigned int ct[2], int probwt) {
|
||||
const aom_prob upd = DIFF_UPDATE_PROB;
|
||||
aom_prob newp = get_binary_prob(ct[0], ct[1]);
|
||||
const int savings =
|
||||
av1_prob_diff_update_savings_search(ct, *oldp, &newp, upd, probwt);
|
||||
assert(newp >= 1);
|
||||
if (savings > 0) {
|
||||
aom_write(w, 1, upd);
|
||||
av1_write_prob_diff_update(w, newp, *oldp);
|
||||
*oldp = newp;
|
||||
} else {
|
||||
aom_write(w, 0, upd);
|
||||
}
|
||||
}
|
||||
|
||||
int av1_cond_prob_diff_update_savings(aom_prob *oldp, const unsigned int ct[2],
|
||||
int probwt) {
|
||||
const aom_prob upd = DIFF_UPDATE_PROB;
|
||||
aom_prob newp = get_binary_prob(ct[0], ct[1]);
|
||||
const int savings =
|
||||
av1_prob_diff_update_savings_search(ct, *oldp, &newp, upd, probwt);
|
||||
return savings;
|
||||
}
|
||||
49
third_party/aom/av1/encoder/subexp.h
vendored
Normal file
49
third_party/aom/av1/encoder/subexp.h
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_SUBEXP_H_
|
||||
#define AV1_ENCODER_SUBEXP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
#include "aom_dsp/prob.h"
|
||||
|
||||
void av1_write_prob_diff_update(aom_writer *w, aom_prob newp, aom_prob oldpm);
|
||||
|
||||
void av1_cond_prob_diff_update(aom_writer *w, aom_prob *oldp,
|
||||
const unsigned int ct[2], int probwt);
|
||||
|
||||
int av1_prob_diff_update_savings_search(const unsigned int *ct, aom_prob oldp,
|
||||
aom_prob *bestp, aom_prob upd,
|
||||
int probwt);
|
||||
|
||||
int av1_prob_diff_update_savings_search_model(const unsigned int *ct,
|
||||
const aom_prob oldp,
|
||||
aom_prob *bestp, aom_prob upd,
|
||||
int stepsize, int probwt);
|
||||
|
||||
int av1_cond_prob_diff_update_savings(aom_prob *oldp, const unsigned int ct[2],
|
||||
int probwt);
|
||||
#if CONFIG_SUBFRAME_PROB_UPDATE
|
||||
int av1_prob_update_search_subframe(unsigned int ct[][2], aom_prob oldp,
|
||||
aom_prob *bestp, aom_prob upd, int n);
|
||||
int av1_prob_update_search_model_subframe(
|
||||
unsigned int ct[ENTROPY_NODES][COEF_PROBS_BUFS][2], const aom_prob *oldp,
|
||||
aom_prob *bestp, aom_prob upd, int stepsize, int n);
|
||||
#endif // CONFIG_SUBFRAME_PROB_UPDATE
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_SUBEXP_H_
|
||||
719
third_party/aom/av1/encoder/temporal_filter.c
vendored
Normal file
719
third_party/aom/av1/encoder/temporal_filter.c
vendored
Normal file
|
|
@ -0,0 +1,719 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "./aom_config.h"
|
||||
#include "av1/common/alloccommon.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/common/quant_common.h"
|
||||
#include "av1/common/reconinter.h"
|
||||
#include "av1/common/odintrin.h"
|
||||
#include "av1/encoder/av1_quantize.h"
|
||||
#include "av1/encoder/extend.h"
|
||||
#include "av1/encoder/firstpass.h"
|
||||
#include "av1/encoder/mcomp.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/ratectrl.h"
|
||||
#include "av1/encoder/segmentation.h"
|
||||
#include "av1/encoder/temporal_filter.h"
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "aom_ports/mem.h"
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "aom_scale/aom_scale.h"
|
||||
|
||||
static void temporal_filter_predictors_mb_c(
|
||||
MACROBLOCKD *xd, uint8_t *y_mb_ptr, uint8_t *u_mb_ptr, uint8_t *v_mb_ptr,
|
||||
int stride, int uv_block_width, int uv_block_height, int mv_row, int mv_col,
|
||||
uint8_t *pred, struct scale_factors *scale, int x, int y) {
|
||||
const int which_mv = 0;
|
||||
const MV mv = { mv_row, mv_col };
|
||||
enum mv_precision mv_precision_uv;
|
||||
int uv_stride;
|
||||
// TODO(angiebird): change plane setting accordingly
|
||||
ConvolveParams conv_params = get_conv_params(which_mv, 0);
|
||||
|
||||
#if USE_TEMPORALFILTER_12TAP
|
||||
#if CONFIG_DUAL_FILTER
|
||||
const InterpFilter interp_filter[4] = { TEMPORALFILTER_12TAP,
|
||||
TEMPORALFILTER_12TAP,
|
||||
TEMPORALFILTER_12TAP,
|
||||
TEMPORALFILTER_12TAP };
|
||||
#else
|
||||
const InterpFilter interp_filter = TEMPORALFILTER_12TAP;
|
||||
#endif
|
||||
(void)xd;
|
||||
#else
|
||||
const InterpFilter interp_filter = xd->mi[0]->mbmi.interp_filter;
|
||||
#endif // USE_TEMPORALFILTER_12TAP
|
||||
#if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
WarpTypesAllowed warp_types;
|
||||
memset(&warp_types, 0, sizeof(WarpTypesAllowed));
|
||||
#endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
|
||||
if (uv_block_width == 8) {
|
||||
uv_stride = (stride + 1) >> 1;
|
||||
mv_precision_uv = MV_PRECISION_Q4;
|
||||
} else {
|
||||
uv_stride = stride;
|
||||
mv_precision_uv = MV_PRECISION_Q3;
|
||||
}
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
av1_highbd_build_inter_predictor(y_mb_ptr, stride, &pred[0], 16, &mv, scale,
|
||||
16, 16, which_mv, interp_filter,
|
||||
#if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
&warp_types, x, y,
|
||||
#endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
0, MV_PRECISION_Q3, x, y, xd);
|
||||
|
||||
av1_highbd_build_inter_predictor(u_mb_ptr, uv_stride, &pred[256],
|
||||
uv_block_width, &mv, scale, uv_block_width,
|
||||
uv_block_height, which_mv, interp_filter,
|
||||
#if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
&warp_types, x, y,
|
||||
#endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
1, mv_precision_uv, x, y, xd);
|
||||
|
||||
av1_highbd_build_inter_predictor(v_mb_ptr, uv_stride, &pred[512],
|
||||
uv_block_width, &mv, scale, uv_block_width,
|
||||
uv_block_height, which_mv, interp_filter,
|
||||
#if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
&warp_types, x, y,
|
||||
#endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
2, mv_precision_uv, x, y, xd);
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
av1_build_inter_predictor(y_mb_ptr, stride, &pred[0], 16, &mv, scale, 16, 16,
|
||||
&conv_params, interp_filter,
|
||||
#if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
&warp_types, x, y, 0, 0,
|
||||
#endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
MV_PRECISION_Q3, x, y, xd);
|
||||
|
||||
av1_build_inter_predictor(u_mb_ptr, uv_stride, &pred[256], uv_block_width,
|
||||
&mv, scale, uv_block_width, uv_block_height,
|
||||
&conv_params, interp_filter,
|
||||
#if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
&warp_types, x, y, 1, 0,
|
||||
#endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
mv_precision_uv, x, y, xd);
|
||||
|
||||
av1_build_inter_predictor(v_mb_ptr, uv_stride, &pred[512], uv_block_width,
|
||||
&mv, scale, uv_block_width, uv_block_height,
|
||||
&conv_params, interp_filter,
|
||||
#if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
&warp_types, x, y, 2, 0,
|
||||
#endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
|
||||
mv_precision_uv, x, y, xd);
|
||||
}
|
||||
|
||||
void av1_temporal_filter_apply_c(uint8_t *frame1, unsigned int stride,
|
||||
uint8_t *frame2, unsigned int block_width,
|
||||
unsigned int block_height, int strength,
|
||||
int filter_weight, unsigned int *accumulator,
|
||||
uint16_t *count) {
|
||||
unsigned int i, j, k;
|
||||
int modifier;
|
||||
int byte = 0;
|
||||
const int rounding = strength > 0 ? 1 << (strength - 1) : 0;
|
||||
|
||||
for (i = 0, k = 0; i < block_height; i++) {
|
||||
for (j = 0; j < block_width; j++, k++) {
|
||||
int pixel_value = *frame2;
|
||||
|
||||
// non-local mean approach
|
||||
int diff_sse[9] = { 0 };
|
||||
int idx, idy, index = 0;
|
||||
|
||||
for (idy = -1; idy <= 1; ++idy) {
|
||||
for (idx = -1; idx <= 1; ++idx) {
|
||||
int row = (int)i + idy;
|
||||
int col = (int)j + idx;
|
||||
|
||||
if (row >= 0 && row < (int)block_height && col >= 0 &&
|
||||
col < (int)block_width) {
|
||||
int diff = frame1[byte + idy * (int)stride + idx] -
|
||||
frame2[idy * (int)block_width + idx];
|
||||
diff_sse[index] = diff * diff;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(index > 0);
|
||||
|
||||
modifier = 0;
|
||||
for (idx = 0; idx < 9; ++idx) modifier += diff_sse[idx];
|
||||
|
||||
modifier *= 3;
|
||||
modifier /= index;
|
||||
|
||||
++frame2;
|
||||
|
||||
modifier += rounding;
|
||||
modifier >>= strength;
|
||||
|
||||
if (modifier > 16) modifier = 16;
|
||||
|
||||
modifier = 16 - modifier;
|
||||
modifier *= filter_weight;
|
||||
|
||||
count[k] += modifier;
|
||||
accumulator[k] += modifier * pixel_value;
|
||||
|
||||
byte++;
|
||||
}
|
||||
|
||||
byte += stride - block_width;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
void av1_highbd_temporal_filter_apply_c(
|
||||
uint8_t *frame1_8, unsigned int stride, uint8_t *frame2_8,
|
||||
unsigned int block_width, unsigned int block_height, int strength,
|
||||
int filter_weight, unsigned int *accumulator, uint16_t *count) {
|
||||
uint16_t *frame1 = CONVERT_TO_SHORTPTR(frame1_8);
|
||||
uint16_t *frame2 = CONVERT_TO_SHORTPTR(frame2_8);
|
||||
unsigned int i, j, k;
|
||||
int modifier;
|
||||
int byte = 0;
|
||||
const int rounding = strength > 0 ? 1 << (strength - 1) : 0;
|
||||
|
||||
for (i = 0, k = 0; i < block_height; i++) {
|
||||
for (j = 0; j < block_width; j++, k++) {
|
||||
int pixel_value = *frame2;
|
||||
|
||||
// non-local mean approach
|
||||
int diff_sse[9] = { 0 };
|
||||
int idx, idy, index = 0;
|
||||
|
||||
for (idy = -1; idy <= 1; ++idy) {
|
||||
for (idx = -1; idx <= 1; ++idx) {
|
||||
int row = (int)i + idy;
|
||||
int col = (int)j + idx;
|
||||
|
||||
if (row >= 0 && row < (int)block_height && col >= 0 &&
|
||||
col < (int)block_width) {
|
||||
int diff = frame1[byte + idy * (int)stride + idx] -
|
||||
frame2[idy * (int)block_width + idx];
|
||||
diff_sse[index] = diff * diff;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(index > 0);
|
||||
|
||||
modifier = 0;
|
||||
for (idx = 0; idx < 9; ++idx) modifier += diff_sse[idx];
|
||||
|
||||
modifier *= 3;
|
||||
modifier /= index;
|
||||
|
||||
++frame2;
|
||||
|
||||
modifier += rounding;
|
||||
modifier >>= strength;
|
||||
|
||||
if (modifier > 16) modifier = 16;
|
||||
|
||||
modifier = 16 - modifier;
|
||||
modifier *= filter_weight;
|
||||
|
||||
count[k] += modifier;
|
||||
accumulator[k] += modifier * pixel_value;
|
||||
|
||||
byte++;
|
||||
}
|
||||
|
||||
byte += stride - block_width;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
|
||||
static int temporal_filter_find_matching_mb_c(AV1_COMP *cpi,
|
||||
uint8_t *arf_frame_buf,
|
||||
uint8_t *frame_ptr_buf,
|
||||
int stride) {
|
||||
MACROBLOCK *const x = &cpi->td.mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
const MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv;
|
||||
int step_param;
|
||||
int sadpb = x->sadperbit16;
|
||||
int bestsme = INT_MAX;
|
||||
int distortion;
|
||||
unsigned int sse;
|
||||
int cost_list[5];
|
||||
MvLimits tmp_mv_limits = x->mv_limits;
|
||||
|
||||
MV best_ref_mv1 = { 0, 0 };
|
||||
MV best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */
|
||||
|
||||
// Save input state
|
||||
struct buf_2d src = x->plane[0].src;
|
||||
struct buf_2d pre = xd->plane[0].pre[0];
|
||||
|
||||
best_ref_mv1_full.col = best_ref_mv1.col >> 3;
|
||||
best_ref_mv1_full.row = best_ref_mv1.row >> 3;
|
||||
|
||||
// Setup frame pointers
|
||||
x->plane[0].src.buf = arf_frame_buf;
|
||||
x->plane[0].src.stride = stride;
|
||||
xd->plane[0].pre[0].buf = frame_ptr_buf;
|
||||
xd->plane[0].pre[0].stride = stride;
|
||||
|
||||
step_param = mv_sf->reduce_first_step_size;
|
||||
step_param = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 2);
|
||||
|
||||
av1_set_mv_search_range(&x->mv_limits, &best_ref_mv1);
|
||||
|
||||
#if CONFIG_REF_MV
|
||||
x->mvcost = x->mv_cost_stack[0];
|
||||
x->nmvjointcost = x->nmv_vec_cost[0];
|
||||
x->mvsadcost = x->mvcost;
|
||||
x->nmvjointsadcost = x->nmvjointcost;
|
||||
#endif
|
||||
|
||||
// Ignore mv costing by sending NULL pointer instead of cost arrays
|
||||
av1_hex_search(x, &best_ref_mv1_full, step_param, sadpb, 1,
|
||||
cond_cost_list(cpi, cost_list), &cpi->fn_ptr[BLOCK_16X16], 0,
|
||||
&best_ref_mv1);
|
||||
|
||||
x->mv_limits = tmp_mv_limits;
|
||||
|
||||
// Ignore mv costing by sending NULL pointer instead of cost array
|
||||
bestsme = cpi->find_fractional_mv_step(
|
||||
x, &best_ref_mv1, cpi->common.allow_high_precision_mv, x->errorperbit,
|
||||
&cpi->fn_ptr[BLOCK_16X16], 0, mv_sf->subpel_iters_per_step,
|
||||
cond_cost_list(cpi, cost_list), NULL, NULL, &distortion, &sse, NULL, 0, 0,
|
||||
0);
|
||||
|
||||
x->e_mbd.mi[0]->bmi[0].as_mv[0] = x->best_mv;
|
||||
|
||||
// Restore input state
|
||||
x->plane[0].src = src;
|
||||
xd->plane[0].pre[0] = pre;
|
||||
|
||||
return bestsme;
|
||||
}
|
||||
|
||||
static void temporal_filter_iterate_c(AV1_COMP *cpi,
|
||||
YV12_BUFFER_CONFIG **frames,
|
||||
int frame_count, int alt_ref_index,
|
||||
int strength,
|
||||
struct scale_factors *scale) {
|
||||
int byte;
|
||||
int frame;
|
||||
int mb_col, mb_row;
|
||||
unsigned int filter_weight;
|
||||
int mb_cols = (frames[alt_ref_index]->y_crop_width + 15) >> 4;
|
||||
int mb_rows = (frames[alt_ref_index]->y_crop_height + 15) >> 4;
|
||||
int mb_y_offset = 0;
|
||||
int mb_uv_offset = 0;
|
||||
DECLARE_ALIGNED(16, unsigned int, accumulator[16 * 16 * 3]);
|
||||
DECLARE_ALIGNED(16, uint16_t, count[16 * 16 * 3]);
|
||||
MACROBLOCKD *mbd = &cpi->td.mb.e_mbd;
|
||||
YV12_BUFFER_CONFIG *f = frames[alt_ref_index];
|
||||
uint8_t *dst1, *dst2;
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
DECLARE_ALIGNED(16, uint16_t, predictor16[16 * 16 * 3]);
|
||||
DECLARE_ALIGNED(16, uint8_t, predictor8[16 * 16 * 3]);
|
||||
uint8_t *predictor;
|
||||
#else
|
||||
DECLARE_ALIGNED(16, uint8_t, predictor[16 * 16 * 3]);
|
||||
#endif
|
||||
const int mb_uv_height = 16 >> mbd->plane[1].subsampling_y;
|
||||
const int mb_uv_width = 16 >> mbd->plane[1].subsampling_x;
|
||||
|
||||
// Save input state
|
||||
uint8_t *input_buffer[MAX_MB_PLANE];
|
||||
int i;
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
if (mbd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
predictor = CONVERT_TO_BYTEPTR(predictor16);
|
||||
} else {
|
||||
predictor = predictor8;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAX_MB_PLANE; i++) input_buffer[i] = mbd->plane[i].pre[0].buf;
|
||||
|
||||
for (mb_row = 0; mb_row < mb_rows; mb_row++) {
|
||||
// Source frames are extended to 16 pixels. This is different than
|
||||
// L/A/G reference frames that have a border of 32 (AV1ENCBORDERINPIXELS)
|
||||
// A 6/8 tap filter is used for motion search. This requires 2 pixels
|
||||
// before and 3 pixels after. So the largest Y mv on a border would
|
||||
// then be 16 - AOM_INTERP_EXTEND. The UV blocks are half the size of the
|
||||
// Y and therefore only extended by 8. The largest mv that a UV block
|
||||
// can support is 8 - AOM_INTERP_EXTEND. A UV mv is half of a Y mv.
|
||||
// (16 - AOM_INTERP_EXTEND) >> 1 which is greater than
|
||||
// 8 - AOM_INTERP_EXTEND.
|
||||
// To keep the mv in play for both Y and UV planes the max that it
|
||||
// can be on a border is therefore 16 - (2*AOM_INTERP_EXTEND+1).
|
||||
cpi->td.mb.mv_limits.row_min =
|
||||
-((mb_row * 16) + (17 - 2 * AOM_INTERP_EXTEND));
|
||||
cpi->td.mb.mv_limits.row_max =
|
||||
((mb_rows - 1 - mb_row) * 16) + (17 - 2 * AOM_INTERP_EXTEND);
|
||||
|
||||
for (mb_col = 0; mb_col < mb_cols; mb_col++) {
|
||||
int j, k;
|
||||
int stride;
|
||||
|
||||
memset(accumulator, 0, 16 * 16 * 3 * sizeof(accumulator[0]));
|
||||
memset(count, 0, 16 * 16 * 3 * sizeof(count[0]));
|
||||
|
||||
cpi->td.mb.mv_limits.col_min =
|
||||
-((mb_col * 16) + (17 - 2 * AOM_INTERP_EXTEND));
|
||||
cpi->td.mb.mv_limits.col_max =
|
||||
((mb_cols - 1 - mb_col) * 16) + (17 - 2 * AOM_INTERP_EXTEND);
|
||||
|
||||
for (frame = 0; frame < frame_count; frame++) {
|
||||
const int thresh_low = 10000;
|
||||
const int thresh_high = 20000;
|
||||
|
||||
if (frames[frame] == NULL) continue;
|
||||
|
||||
mbd->mi[0]->bmi[0].as_mv[0].as_mv.row = 0;
|
||||
mbd->mi[0]->bmi[0].as_mv[0].as_mv.col = 0;
|
||||
|
||||
if (frame == alt_ref_index) {
|
||||
filter_weight = 2;
|
||||
} else {
|
||||
// Find best match in this frame by MC
|
||||
int err = temporal_filter_find_matching_mb_c(
|
||||
cpi, frames[alt_ref_index]->y_buffer + mb_y_offset,
|
||||
frames[frame]->y_buffer + mb_y_offset, frames[frame]->y_stride);
|
||||
|
||||
// Assign higher weight to matching MB if it's error
|
||||
// score is lower. If not applying MC default behavior
|
||||
// is to weight all MBs equal.
|
||||
filter_weight = err < thresh_low ? 2 : err < thresh_high ? 1 : 0;
|
||||
}
|
||||
|
||||
if (filter_weight != 0) {
|
||||
// Construct the predictors
|
||||
temporal_filter_predictors_mb_c(
|
||||
mbd, frames[frame]->y_buffer + mb_y_offset,
|
||||
frames[frame]->u_buffer + mb_uv_offset,
|
||||
frames[frame]->v_buffer + mb_uv_offset, frames[frame]->y_stride,
|
||||
mb_uv_width, mb_uv_height, mbd->mi[0]->bmi[0].as_mv[0].as_mv.row,
|
||||
mbd->mi[0]->bmi[0].as_mv[0].as_mv.col, predictor, scale,
|
||||
mb_col * 16, mb_row * 16);
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
if (mbd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
int adj_strength = strength + 2 * (mbd->bd - 8);
|
||||
// Apply the filter (YUV)
|
||||
av1_highbd_temporal_filter_apply(
|
||||
f->y_buffer + mb_y_offset, f->y_stride, predictor, 16, 16,
|
||||
adj_strength, filter_weight, accumulator, count);
|
||||
av1_highbd_temporal_filter_apply(
|
||||
f->u_buffer + mb_uv_offset, f->uv_stride, predictor + 256,
|
||||
mb_uv_width, mb_uv_height, adj_strength, filter_weight,
|
||||
accumulator + 256, count + 256);
|
||||
av1_highbd_temporal_filter_apply(
|
||||
f->v_buffer + mb_uv_offset, f->uv_stride, predictor + 512,
|
||||
mb_uv_width, mb_uv_height, adj_strength, filter_weight,
|
||||
accumulator + 512, count + 512);
|
||||
} else {
|
||||
// Apply the filter (YUV)
|
||||
av1_temporal_filter_apply_c(f->y_buffer + mb_y_offset, f->y_stride,
|
||||
predictor, 16, 16, strength,
|
||||
filter_weight, accumulator, count);
|
||||
av1_temporal_filter_apply_c(
|
||||
f->u_buffer + mb_uv_offset, f->uv_stride, predictor + 256,
|
||||
mb_uv_width, mb_uv_height, strength, filter_weight,
|
||||
accumulator + 256, count + 256);
|
||||
av1_temporal_filter_apply_c(
|
||||
f->v_buffer + mb_uv_offset, f->uv_stride, predictor + 512,
|
||||
mb_uv_width, mb_uv_height, strength, filter_weight,
|
||||
accumulator + 512, count + 512);
|
||||
}
|
||||
#else
|
||||
// Apply the filter (YUV)
|
||||
av1_temporal_filter_apply_c(f->y_buffer + mb_y_offset, f->y_stride,
|
||||
predictor, 16, 16, strength,
|
||||
filter_weight, accumulator, count);
|
||||
av1_temporal_filter_apply_c(f->u_buffer + mb_uv_offset, f->uv_stride,
|
||||
predictor + 256, mb_uv_width,
|
||||
mb_uv_height, strength, filter_weight,
|
||||
accumulator + 256, count + 256);
|
||||
av1_temporal_filter_apply_c(f->v_buffer + mb_uv_offset, f->uv_stride,
|
||||
predictor + 512, mb_uv_width,
|
||||
mb_uv_height, strength, filter_weight,
|
||||
accumulator + 512, count + 512);
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
if (mbd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
|
||||
uint16_t *dst1_16;
|
||||
uint16_t *dst2_16;
|
||||
// Normalize filter output to produce AltRef frame
|
||||
dst1 = cpi->alt_ref_buffer.y_buffer;
|
||||
dst1_16 = CONVERT_TO_SHORTPTR(dst1);
|
||||
stride = cpi->alt_ref_buffer.y_stride;
|
||||
byte = mb_y_offset;
|
||||
for (i = 0, k = 0; i < 16; i++) {
|
||||
for (j = 0; j < 16; j++, k++) {
|
||||
dst1_16[byte] =
|
||||
(uint16_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]);
|
||||
|
||||
// move to next pixel
|
||||
byte++;
|
||||
}
|
||||
|
||||
byte += stride - 16;
|
||||
}
|
||||
|
||||
dst1 = cpi->alt_ref_buffer.u_buffer;
|
||||
dst2 = cpi->alt_ref_buffer.v_buffer;
|
||||
dst1_16 = CONVERT_TO_SHORTPTR(dst1);
|
||||
dst2_16 = CONVERT_TO_SHORTPTR(dst2);
|
||||
stride = cpi->alt_ref_buffer.uv_stride;
|
||||
byte = mb_uv_offset;
|
||||
for (i = 0, k = 256; i < mb_uv_height; i++) {
|
||||
for (j = 0; j < mb_uv_width; j++, k++) {
|
||||
int m = k + 256;
|
||||
|
||||
// U
|
||||
dst1_16[byte] =
|
||||
(uint16_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]);
|
||||
|
||||
// V
|
||||
dst2_16[byte] =
|
||||
(uint16_t)OD_DIVU(accumulator[m] + (count[m] >> 1), count[m]);
|
||||
|
||||
// move to next pixel
|
||||
byte++;
|
||||
}
|
||||
|
||||
byte += stride - mb_uv_width;
|
||||
}
|
||||
} else {
|
||||
// Normalize filter output to produce AltRef frame
|
||||
dst1 = cpi->alt_ref_buffer.y_buffer;
|
||||
stride = cpi->alt_ref_buffer.y_stride;
|
||||
byte = mb_y_offset;
|
||||
for (i = 0, k = 0; i < 16; i++) {
|
||||
for (j = 0; j < 16; j++, k++) {
|
||||
dst1[byte] =
|
||||
(uint8_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]);
|
||||
|
||||
// move to next pixel
|
||||
byte++;
|
||||
}
|
||||
byte += stride - 16;
|
||||
}
|
||||
|
||||
dst1 = cpi->alt_ref_buffer.u_buffer;
|
||||
dst2 = cpi->alt_ref_buffer.v_buffer;
|
||||
stride = cpi->alt_ref_buffer.uv_stride;
|
||||
byte = mb_uv_offset;
|
||||
for (i = 0, k = 256; i < mb_uv_height; i++) {
|
||||
for (j = 0; j < mb_uv_width; j++, k++) {
|
||||
int m = k + 256;
|
||||
|
||||
// U
|
||||
dst1[byte] =
|
||||
(uint8_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]);
|
||||
|
||||
// V
|
||||
dst2[byte] =
|
||||
(uint8_t)OD_DIVU(accumulator[m] + (count[m] >> 1), count[m]);
|
||||
|
||||
// move to next pixel
|
||||
byte++;
|
||||
}
|
||||
byte += stride - mb_uv_width;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Normalize filter output to produce AltRef frame
|
||||
dst1 = cpi->alt_ref_buffer.y_buffer;
|
||||
stride = cpi->alt_ref_buffer.y_stride;
|
||||
byte = mb_y_offset;
|
||||
for (i = 0, k = 0; i < 16; i++) {
|
||||
for (j = 0; j < 16; j++, k++) {
|
||||
dst1[byte] =
|
||||
(uint8_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]);
|
||||
|
||||
// move to next pixel
|
||||
byte++;
|
||||
}
|
||||
byte += stride - 16;
|
||||
}
|
||||
|
||||
dst1 = cpi->alt_ref_buffer.u_buffer;
|
||||
dst2 = cpi->alt_ref_buffer.v_buffer;
|
||||
stride = cpi->alt_ref_buffer.uv_stride;
|
||||
byte = mb_uv_offset;
|
||||
for (i = 0, k = 256; i < mb_uv_height; i++) {
|
||||
for (j = 0; j < mb_uv_width; j++, k++) {
|
||||
int m = k + 256;
|
||||
|
||||
// U
|
||||
dst1[byte] =
|
||||
(uint8_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]);
|
||||
|
||||
// V
|
||||
dst2[byte] =
|
||||
(uint8_t)OD_DIVU(accumulator[m] + (count[m] >> 1), count[m]);
|
||||
|
||||
// move to next pixel
|
||||
byte++;
|
||||
}
|
||||
byte += stride - mb_uv_width;
|
||||
}
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
mb_y_offset += 16;
|
||||
mb_uv_offset += mb_uv_width;
|
||||
}
|
||||
mb_y_offset += 16 * (f->y_stride - mb_cols);
|
||||
mb_uv_offset += mb_uv_height * f->uv_stride - mb_uv_width * mb_cols;
|
||||
}
|
||||
|
||||
// Restore input state
|
||||
for (i = 0; i < MAX_MB_PLANE; i++) mbd->plane[i].pre[0].buf = input_buffer[i];
|
||||
}
|
||||
|
||||
// Apply buffer limits and context specific adjustments to arnr filter.
|
||||
static void adjust_arnr_filter(AV1_COMP *cpi, int distance, int group_boost,
|
||||
int *arnr_frames, int *arnr_strength) {
|
||||
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
const int frames_after_arf =
|
||||
av1_lookahead_depth(cpi->lookahead) - distance - 1;
|
||||
int frames_fwd = (cpi->oxcf.arnr_max_frames - 1) >> 1;
|
||||
int frames_bwd;
|
||||
int q, frames, strength;
|
||||
|
||||
// Define the forward and backwards filter limits for this arnr group.
|
||||
if (frames_fwd > frames_after_arf) frames_fwd = frames_after_arf;
|
||||
if (frames_fwd > distance) frames_fwd = distance;
|
||||
|
||||
frames_bwd = frames_fwd;
|
||||
|
||||
// For even length filter there is one more frame backward
|
||||
// than forward: e.g. len=6 ==> bbbAff, len=7 ==> bbbAfff.
|
||||
if (frames_bwd < distance) frames_bwd += (oxcf->arnr_max_frames + 1) & 0x1;
|
||||
|
||||
// Set the baseline active filter size.
|
||||
frames = frames_bwd + 1 + frames_fwd;
|
||||
|
||||
// Adjust the strength based on active max q.
|
||||
if (cpi->common.current_video_frame > 1)
|
||||
q = ((int)av1_convert_qindex_to_q(cpi->rc.avg_frame_qindex[INTER_FRAME],
|
||||
cpi->common.bit_depth));
|
||||
else
|
||||
q = ((int)av1_convert_qindex_to_q(cpi->rc.avg_frame_qindex[KEY_FRAME],
|
||||
cpi->common.bit_depth));
|
||||
if (q > 16) {
|
||||
strength = oxcf->arnr_strength;
|
||||
} else {
|
||||
strength = oxcf->arnr_strength - ((16 - q) / 2);
|
||||
if (strength < 0) strength = 0;
|
||||
}
|
||||
|
||||
// Adjust number of frames in filter and strength based on gf boost level.
|
||||
if (frames > group_boost / 150) {
|
||||
frames = group_boost / 150;
|
||||
frames += !(frames & 1);
|
||||
}
|
||||
|
||||
if (strength > group_boost / 300) {
|
||||
strength = group_boost / 300;
|
||||
}
|
||||
|
||||
// Adjustments for second level arf in multi arf case.
|
||||
if (cpi->oxcf.pass == 2 && cpi->multi_arf_allowed) {
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
if (gf_group->rf_level[gf_group->index] != GF_ARF_STD) {
|
||||
strength >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
*arnr_frames = frames;
|
||||
*arnr_strength = strength;
|
||||
}
|
||||
|
||||
void av1_temporal_filter(AV1_COMP *cpi, int distance) {
|
||||
RATE_CONTROL *const rc = &cpi->rc;
|
||||
int frame;
|
||||
int frames_to_blur;
|
||||
int start_frame;
|
||||
int strength;
|
||||
int frames_to_blur_backward;
|
||||
int frames_to_blur_forward;
|
||||
struct scale_factors sf;
|
||||
YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS] = { NULL };
|
||||
#if CONFIG_EXT_REFS
|
||||
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
|
||||
#endif
|
||||
|
||||
// Apply context specific adjustments to the arnr filter parameters.
|
||||
adjust_arnr_filter(cpi, distance, rc->gfu_boost, &frames_to_blur, &strength);
|
||||
// TODO(weitinglin): Currently, we enforce the filtering strength on
|
||||
// extra ARFs' to be zeros. We should investigate in which
|
||||
// case it is more beneficial to use non-zero strength
|
||||
// filtering.
|
||||
#if CONFIG_EXT_REFS
|
||||
if (gf_group->rf_level[gf_group->index] == GF_ARF_LOW) {
|
||||
strength = 0;
|
||||
frames_to_blur = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXT_REFS
|
||||
if (strength == 0 && frames_to_blur == 1) {
|
||||
cpi->is_arf_filter_off[gf_group->arf_update_idx[gf_group->index]] = 1;
|
||||
} else {
|
||||
cpi->is_arf_filter_off[gf_group->arf_update_idx[gf_group->index]] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
frames_to_blur_backward = (frames_to_blur / 2);
|
||||
frames_to_blur_forward = ((frames_to_blur - 1) / 2);
|
||||
start_frame = distance + frames_to_blur_forward;
|
||||
|
||||
// Setup frame pointers, NULL indicates frame not included in filter.
|
||||
for (frame = 0; frame < frames_to_blur; ++frame) {
|
||||
const int which_buffer = start_frame - frame;
|
||||
struct lookahead_entry *buf =
|
||||
av1_lookahead_peek(cpi->lookahead, which_buffer);
|
||||
frames[frames_to_blur - 1 - frame] = &buf->img;
|
||||
}
|
||||
|
||||
if (frames_to_blur > 0) {
|
||||
// Setup scaling factors. Scaling on each of the arnr frames is not
|
||||
// supported.
|
||||
// ARF is produced at the native frame size and resized when coded.
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
av1_setup_scale_factors_for_frame(
|
||||
&sf, frames[0]->y_crop_width, frames[0]->y_crop_height,
|
||||
frames[0]->y_crop_width, frames[0]->y_crop_height,
|
||||
cpi->common.use_highbitdepth);
|
||||
#else
|
||||
av1_setup_scale_factors_for_frame(
|
||||
&sf, frames[0]->y_crop_width, frames[0]->y_crop_height,
|
||||
frames[0]->y_crop_width, frames[0]->y_crop_height);
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
}
|
||||
|
||||
temporal_filter_iterate_c(cpi, frames, frames_to_blur,
|
||||
frames_to_blur_backward, strength, &sf);
|
||||
}
|
||||
25
third_party/aom/av1/encoder/temporal_filter.h
vendored
Normal file
25
third_party/aom/av1/encoder/temporal_filter.h
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_TEMPORAL_FILTER_H_
|
||||
#define AV1_ENCODER_TEMPORAL_FILTER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void av1_temporal_filter(AV1_COMP *cpi, int distance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_TEMPORAL_FILTER_H_
|
||||
887
third_party/aom/av1/encoder/tokenize.c
vendored
Normal file
887
third_party/aom/av1/encoder/tokenize.c
vendored
Normal file
|
|
@ -0,0 +1,887 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aom_mem/aom_mem.h"
|
||||
|
||||
#include "av1/common/entropy.h"
|
||||
#include "av1/common/pred_common.h"
|
||||
#include "av1/common/scan.h"
|
||||
#include "av1/common/seg_common.h"
|
||||
|
||||
#include "av1/encoder/cost.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
#include "av1/encoder/rdopt.h"
|
||||
#include "av1/encoder/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 *av1_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 av1_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 *av1_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 aom_tree_index av1_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 av1_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 int av1_cat6_high_cost[CAT6_HIGH_COST_ENTRIES] = {
|
||||
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,
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
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 uint8_t av1_cat6_skipped_bits_discount[8] = {
|
||||
0, 3, 6, 9, 12, 18, 24, 30
|
||||
};
|
||||
|
||||
#if CONFIG_NEW_MULTISYMBOL
|
||||
const av1_extra_bit av1_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
|
||||
{ av1_cat1_cdf, 1, CAT1_MIN_VAL, cat1_cost }, // CATEGORY1_TOKEN
|
||||
{ av1_cat2_cdf, 2, CAT2_MIN_VAL, cat2_cost }, // CATEGORY2_TOKEN
|
||||
{ av1_cat3_cdf, 3, CAT3_MIN_VAL, cat3_cost }, // CATEGORY3_TOKEN
|
||||
{ av1_cat4_cdf, 4, CAT4_MIN_VAL, cat4_cost }, // CATEGORY4_TOKEN
|
||||
{ av1_cat5_cdf, 5, CAT5_MIN_VAL, cat5_cost }, // CATEGORY5_TOKEN
|
||||
{ av1_cat6_cdf, 18, CAT6_MIN_VAL, 0 }, // CATEGORY6_TOKEN
|
||||
{ 0, 0, 0, zero_cost } // EOB_TOKEN
|
||||
};
|
||||
#else
|
||||
const av1_extra_bit av1_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
|
||||
{ av1_cat1_prob, 1, CAT1_MIN_VAL, cat1_cost }, // CATEGORY1_TOKEN
|
||||
{ av1_cat2_prob, 2, CAT2_MIN_VAL, cat2_cost }, // CATEGORY2_TOKEN
|
||||
{ av1_cat3_prob, 3, CAT3_MIN_VAL, cat3_cost }, // CATEGORY3_TOKEN
|
||||
{ av1_cat4_prob, 4, CAT4_MIN_VAL, cat4_cost }, // CATEGORY4_TOKEN
|
||||
{ av1_cat5_prob, 5, CAT5_MIN_VAL, cat5_cost }, // CATEGORY5_TOKEN
|
||||
{ av1_cat6_prob, 18, CAT6_MIN_VAL, 0 }, // CATEGORY6_TOKEN
|
||||
{ 0, 0, 0, zero_cost } // EOB_TOKEN
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !CONFIG_EC_MULTISYMBOL
|
||||
const struct av1_token av1_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 }
|
||||
};
|
||||
#endif // !CONFIG_EC_MULTISYMBOL
|
||||
|
||||
struct tokenize_b_args {
|
||||
const AV1_COMP *cpi;
|
||||
ThreadData *td;
|
||||
TOKENEXTRA **tp;
|
||||
int this_rate;
|
||||
};
|
||||
|
||||
#if !CONFIG_PVQ || CONFIG_VAR_TX
|
||||
static void cost_coeffs_b(int plane, int block, int blk_row, int blk_col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg) {
|
||||
struct tokenize_b_args *const args = arg;
|
||||
const AV1_COMP *const cpi = args->cpi;
|
||||
const AV1_COMMON *cm = &cpi->common;
|
||||
ThreadData *const td = args->td;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
||||
struct macroblock_plane *p = &x->plane[plane];
|
||||
struct macroblockd_plane *pd = &xd->plane[plane];
|
||||
const PLANE_TYPE type = pd->plane_type;
|
||||
const int ref = is_inter_block(mbmi);
|
||||
const TX_TYPE tx_type = get_tx_type(type, xd, block, tx_size);
|
||||
const SCAN_ORDER *const scan_order = get_scan(cm, tx_size, tx_type, ref);
|
||||
const int rate = av1_cost_coeffs(cpi, x, plane, block, tx_size, scan_order,
|
||||
pd->above_context + blk_col,
|
||||
pd->left_context + blk_row, 0);
|
||||
args->this_rate += rate;
|
||||
(void)plane_bsize;
|
||||
av1_set_contexts(xd, pd, plane, tx_size, p->eobs[block] > 0, blk_col,
|
||||
blk_row);
|
||||
}
|
||||
|
||||
static void set_entropy_context_b(int plane, int block, int blk_row,
|
||||
int blk_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];
|
||||
(void)plane_bsize;
|
||||
av1_set_contexts(xd, pd, plane, tx_size, p->eobs[block] > 0, blk_col,
|
||||
blk_row);
|
||||
}
|
||||
|
||||
#if CONFIG_NEW_TOKENSET
|
||||
static INLINE void add_token(TOKENEXTRA **t,
|
||||
aom_cdf_prob (*tail_cdf)[CDF_SIZE(ENTROPY_TOKENS)],
|
||||
aom_cdf_prob (*head_cdf)[CDF_SIZE(ENTROPY_TOKENS)],
|
||||
int eob_val, int first_val, int32_t extra,
|
||||
uint8_t token) {
|
||||
(*t)->token = token;
|
||||
(*t)->extra = extra;
|
||||
(*t)->tail_cdf = tail_cdf;
|
||||
(*t)->head_cdf = head_cdf;
|
||||
(*t)->eob_val = eob_val;
|
||||
(*t)->first_val = first_val;
|
||||
(*t)++;
|
||||
}
|
||||
|
||||
#else // CONFIG_NEW_TOKENSET
|
||||
static INLINE void add_token(
|
||||
TOKENEXTRA **t, const aom_prob *context_tree,
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
aom_cdf_prob (*token_cdf)[CDF_SIZE(ENTROPY_TOKENS)],
|
||||
#endif // CONFIG_EC_MULTISYMBOL
|
||||
int32_t extra, uint8_t token, uint8_t skip_eob_node, unsigned int *counts) {
|
||||
(*t)->token = token;
|
||||
(*t)->extra = extra;
|
||||
(*t)->context_tree = context_tree;
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
(*t)->token_cdf = token_cdf;
|
||||
#endif // CONFIG_EC_MULTISYMBOL
|
||||
(*t)->skip_eob_node = skip_eob_node;
|
||||
(*t)++;
|
||||
++counts[token];
|
||||
}
|
||||
#endif // CONFIG_NEW_TOKENSET
|
||||
#endif // !CONFIG_PVQ || CONFIG_VAR_TX
|
||||
|
||||
#if CONFIG_PALETTE
|
||||
void av1_tokenize_palette_sb(const AV1_COMP *cpi,
|
||||
const struct ThreadData *const td, int plane,
|
||||
TOKENEXTRA **t, RUN_TYPE dry_run, BLOCK_SIZE bsize,
|
||||
int *rate) {
|
||||
const MACROBLOCK *const x = &td->mb;
|
||||
const MACROBLOCKD *const xd = &x->e_mbd;
|
||||
const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
|
||||
const uint8_t *const color_map = xd->plane[plane].color_index_map;
|
||||
const PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
|
||||
const int n = pmi->palette_size[plane];
|
||||
int i, j;
|
||||
int this_rate = 0;
|
||||
uint8_t color_order[PALETTE_MAX_SIZE];
|
||||
const aom_prob(
|
||||
*const probs)[PALETTE_COLOR_INDEX_CONTEXTS][PALETTE_COLORS - 1] =
|
||||
plane == 0 ? av1_default_palette_y_color_index_prob
|
||||
: av1_default_palette_uv_color_index_prob;
|
||||
int plane_block_width, rows, cols;
|
||||
av1_get_block_dimensions(bsize, plane, xd, &plane_block_width, NULL, &rows,
|
||||
&cols);
|
||||
assert(plane == 0 || plane == 1);
|
||||
|
||||
#if CONFIG_PALETTE_THROUGHPUT
|
||||
int k;
|
||||
for (k = 1; k < rows + cols - 1; ++k) {
|
||||
for (j = AOMMIN(k, cols - 1); j >= AOMMAX(0, k - rows + 1); --j) {
|
||||
i = k - j;
|
||||
#else
|
||||
for (i = 0; i < rows; ++i) {
|
||||
for (j = (i == 0 ? 1 : 0); j < cols; ++j) {
|
||||
#endif // CONFIG_PALETTE_THROUGHPUT
|
||||
int color_new_idx;
|
||||
const int color_ctx = av1_get_palette_color_index_context(
|
||||
color_map, plane_block_width, i, j, n, color_order, &color_new_idx);
|
||||
assert(color_new_idx >= 0 && color_new_idx < n);
|
||||
if (dry_run == DRY_RUN_COSTCOEFFS)
|
||||
this_rate += cpi->palette_y_color_cost[n - PALETTE_MIN_SIZE][color_ctx]
|
||||
[color_new_idx];
|
||||
(*t)->token = color_new_idx;
|
||||
(*t)->context_tree = probs[n - PALETTE_MIN_SIZE][color_ctx];
|
||||
(*t)->skip_eob_node = 0;
|
||||
++(*t);
|
||||
}
|
||||
}
|
||||
if (rate) *rate += this_rate;
|
||||
}
|
||||
#endif // CONFIG_PALETTE
|
||||
|
||||
#if CONFIG_PVQ
|
||||
static void add_pvq_block(AV1_COMMON *const cm, MACROBLOCK *const x,
|
||||
PVQ_INFO *pvq) {
|
||||
PVQ_QUEUE *q = x->pvq_q;
|
||||
if (q->curr_pos >= q->buf_len) {
|
||||
int new_buf_len = 2 * q->buf_len + 1;
|
||||
PVQ_INFO *new_buf;
|
||||
CHECK_MEM_ERROR(cm, new_buf, aom_malloc(new_buf_len * sizeof(PVQ_INFO)));
|
||||
memcpy(new_buf, q->buf, q->buf_len * sizeof(PVQ_INFO));
|
||||
aom_free(q->buf);
|
||||
q->buf = new_buf;
|
||||
q->buf_len = new_buf_len;
|
||||
}
|
||||
OD_COPY(q->buf + q->curr_pos, pvq, 1);
|
||||
++q->curr_pos;
|
||||
}
|
||||
|
||||
// NOTE: This does not actually generate tokens, instead we store the encoding
|
||||
// decisions made for PVQ in a queue that we will read from when
|
||||
// actually writing the bitstream in write_modes_b
|
||||
static void tokenize_pvq(int plane, int block, int blk_row, int blk_col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg) {
|
||||
struct tokenize_b_args *const args = arg;
|
||||
const AV1_COMP *cpi = args->cpi;
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
ThreadData *const td = args->td;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
PVQ_INFO *pvq_info;
|
||||
|
||||
(void)block;
|
||||
(void)blk_row;
|
||||
(void)blk_col;
|
||||
(void)plane_bsize;
|
||||
(void)tx_size;
|
||||
|
||||
assert(block < MAX_PVQ_BLOCKS_IN_SB);
|
||||
pvq_info = &x->pvq[block][plane];
|
||||
add_pvq_block((AV1_COMMON * const)cm, x, pvq_info);
|
||||
}
|
||||
#endif // CONFIG_PVQ
|
||||
|
||||
static void tokenize_b(int plane, int block, int blk_row, int blk_col,
|
||||
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg) {
|
||||
#if !CONFIG_PVQ
|
||||
struct tokenize_b_args *const args = arg;
|
||||
const AV1_COMP *cpi = args->cpi;
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
ThreadData *const td = args->td;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
TOKENEXTRA **tp = args->tp;
|
||||
uint8_t token_cache[MAX_TX_SQUARE];
|
||||
struct macroblock_plane *p = &x->plane[plane];
|
||||
struct macroblockd_plane *pd = &xd->plane[plane];
|
||||
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
|
||||
int pt; /* near block/prev token context index */
|
||||
int c;
|
||||
TOKENEXTRA *t = *tp; /* store tokens starting here */
|
||||
const int eob = p->eobs[block];
|
||||
const PLANE_TYPE type = pd->plane_type;
|
||||
const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
|
||||
#if CONFIG_SUPERTX
|
||||
const int segment_id = AOMMIN(mbmi->segment_id, mbmi->segment_id_supertx);
|
||||
#else
|
||||
const int segment_id = mbmi->segment_id;
|
||||
#endif // CONFIG_SUEPRTX
|
||||
const int16_t *scan, *nb;
|
||||
const TX_TYPE tx_type = get_tx_type(type, xd, block, tx_size);
|
||||
const SCAN_ORDER *const scan_order =
|
||||
get_scan(cm, tx_size, tx_type, is_inter_block(mbmi));
|
||||
const int ref = is_inter_block(mbmi);
|
||||
unsigned int(*const counts)[COEFF_CONTEXTS][ENTROPY_TOKENS] =
|
||||
td->rd_counts.coef_counts[txsize_sqr_map[tx_size]][type][ref];
|
||||
#if !CONFIG_NEW_TOKENSET
|
||||
#if CONFIG_SUBFRAME_PROB_UPDATE
|
||||
const aom_prob(*coef_probs)[COEFF_CONTEXTS][UNCONSTRAINED_NODES] =
|
||||
cpi->subframe_stats.coef_probs_buf[cpi->common.coef_probs_update_idx]
|
||||
[txsize_sqr_map[tx_size]][type][ref];
|
||||
#else
|
||||
aom_prob(*const coef_probs)[COEFF_CONTEXTS][UNCONSTRAINED_NODES] =
|
||||
cpi->common.fc->coef_probs[txsize_sqr_map[tx_size]][type][ref];
|
||||
#endif // CONFIG_SUBFRAME_PROB_UPDATE
|
||||
#endif // !CONFIG_NEW_TOKENSET
|
||||
#if CONFIG_EC_ADAPT
|
||||
FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
|
||||
#elif CONFIG_EC_MULTISYMBOL
|
||||
FRAME_CONTEXT *ec_ctx = cpi->common.fc;
|
||||
#endif
|
||||
#if CONFIG_NEW_TOKENSET
|
||||
aom_cdf_prob(
|
||||
*const coef_head_cdfs)[COEFF_CONTEXTS][CDF_SIZE(ENTROPY_TOKENS)] =
|
||||
ec_ctx->coef_head_cdfs[txsize_sqr_map[tx_size]][type][ref];
|
||||
aom_cdf_prob(
|
||||
*const coef_tail_cdfs)[COEFF_CONTEXTS][CDF_SIZE(ENTROPY_TOKENS)] =
|
||||
ec_ctx->coef_tail_cdfs[txsize_sqr_map[tx_size]][type][ref];
|
||||
unsigned int(*const blockz_count)[2] =
|
||||
td->counts->blockz_count[txsize_sqr_map[tx_size]][type][ref];
|
||||
int eob_val;
|
||||
int first_val = 1;
|
||||
#else
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
aom_cdf_prob(*const coef_cdfs)[COEFF_CONTEXTS][CDF_SIZE(ENTROPY_TOKENS)] =
|
||||
ec_ctx->coef_cdfs[txsize_sqr_map[tx_size]][type][ref];
|
||||
#endif
|
||||
int skip_eob = 0;
|
||||
#endif
|
||||
const int seg_eob = get_tx_eob(&cpi->common.seg, segment_id, tx_size);
|
||||
unsigned int(*const eob_branch)[COEFF_CONTEXTS] =
|
||||
td->counts->eob_branch[txsize_sqr_map[tx_size]][type][ref];
|
||||
const uint8_t *const band = get_band_translate(tx_size);
|
||||
int16_t token;
|
||||
EXTRABIT extra;
|
||||
(void)plane_bsize;
|
||||
pt = get_entropy_context(tx_size, pd->above_context + blk_col,
|
||||
pd->left_context + blk_row);
|
||||
scan = scan_order->scan;
|
||||
nb = scan_order->neighbors;
|
||||
c = 0;
|
||||
|
||||
#if CONFIG_NEW_TOKENSET
|
||||
if (eob == 0)
|
||||
add_token(&t, &coef_tail_cdfs[band[c]][pt], &coef_head_cdfs[band[c]][pt], 1,
|
||||
1, 0, BLOCK_Z_TOKEN);
|
||||
|
||||
++blockz_count[pt][eob != 0];
|
||||
|
||||
while (c < eob) {
|
||||
int v = qcoeff[scan[c]];
|
||||
first_val = (c == 0);
|
||||
|
||||
if (!v) {
|
||||
add_token(&t, &coef_tail_cdfs[band[c]][pt], &coef_head_cdfs[band[c]][pt],
|
||||
0, first_val, 0, ZERO_TOKEN);
|
||||
++counts[band[c]][pt][ZERO_TOKEN];
|
||||
token_cache[scan[c]] = 0;
|
||||
} else {
|
||||
eob_val =
|
||||
(c + 1 == eob) ? (c + 1 == seg_eob ? LAST_EOB : EARLY_EOB) : NO_EOB;
|
||||
|
||||
av1_get_token_extra(v, &token, &extra);
|
||||
|
||||
add_token(&t, &coef_tail_cdfs[band[c]][pt], &coef_head_cdfs[band[c]][pt],
|
||||
eob_val, first_val, extra, (uint8_t)token);
|
||||
|
||||
if (eob_val != LAST_EOB) {
|
||||
++counts[band[c]][pt][token];
|
||||
++eob_branch[band[c]][pt];
|
||||
counts[band[c]][pt][EOB_TOKEN] += eob_val != NO_EOB;
|
||||
}
|
||||
|
||||
token_cache[scan[c]] = av1_pt_energy_class[token];
|
||||
}
|
||||
++c;
|
||||
pt = get_coef_context(nb, token_cache, AOMMIN(c, eob - 1));
|
||||
}
|
||||
#else
|
||||
while (c < eob) {
|
||||
const int v = qcoeff[scan[c]];
|
||||
eob_branch[band[c]][pt] += !skip_eob;
|
||||
|
||||
av1_get_token_extra(v, &token, &extra);
|
||||
|
||||
add_token(&t, coef_probs[band[c]][pt],
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
&coef_cdfs[band[c]][pt],
|
||||
#endif
|
||||
extra, (uint8_t)token, (uint8_t)skip_eob, counts[band[c]][pt]);
|
||||
|
||||
token_cache[scan[c]] = av1_pt_energy_class[token];
|
||||
++c;
|
||||
pt = get_coef_context(nb, token_cache, c);
|
||||
skip_eob = (token == ZERO_TOKEN);
|
||||
}
|
||||
if (c < seg_eob) {
|
||||
add_token(&t, coef_probs[band[c]][pt],
|
||||
#if CONFIG_EC_MULTISYMBOL
|
||||
NULL,
|
||||
#endif
|
||||
0, EOB_TOKEN, 0, counts[band[c]][pt]);
|
||||
++eob_branch[band[c]][pt];
|
||||
}
|
||||
#endif // CONFIG_NEW_TOKENSET
|
||||
|
||||
#if CONFIG_COEF_INTERLEAVE
|
||||
t->token = EOSB_TOKEN;
|
||||
t++;
|
||||
#endif
|
||||
|
||||
*tp = t;
|
||||
|
||||
#if CONFIG_ADAPT_SCAN
|
||||
// Since dqcoeff is not available here, we pass qcoeff into
|
||||
// av1_update_scan_count_facade(). The update behavior should be the same
|
||||
// because av1_update_scan_count_facade() only cares if coefficients are zero
|
||||
// or not.
|
||||
av1_update_scan_count_facade((AV1_COMMON *)cm, td->counts, tx_size, tx_type,
|
||||
qcoeff, c);
|
||||
#endif
|
||||
|
||||
av1_set_contexts(xd, pd, plane, tx_size, c > 0, blk_col, blk_row);
|
||||
#else // !CONFIG_PVQ
|
||||
tokenize_pvq(plane, block, blk_row, blk_col, plane_bsize, tx_size, arg);
|
||||
#endif // !CONFIG_PVQ
|
||||
}
|
||||
|
||||
struct is_skippable_args {
|
||||
uint16_t *eobs;
|
||||
int *skippable;
|
||||
};
|
||||
static void is_skippable(int plane, int block, int blk_row, int blk_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)blk_row;
|
||||
(void)blk_col;
|
||||
args->skippable[0] &= (!args->eobs[block]);
|
||||
}
|
||||
|
||||
// TODO(yaowu): rewrite and optimize this function to remove the usage of
|
||||
// av1_foreach_transform_block() and simplify is_skippable().
|
||||
int av1_is_skippable_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane) {
|
||||
int result = 1;
|
||||
struct is_skippable_args args = { x->plane[plane].eobs, &result };
|
||||
av1_foreach_transformed_block_in_plane(&x->e_mbd, bsize, plane, is_skippable,
|
||||
&args);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if CONFIG_VAR_TX
|
||||
void tokenize_vartx(ThreadData *td, TOKENEXTRA **t, RUN_TYPE dry_run,
|
||||
TX_SIZE tx_size, BLOCK_SIZE plane_bsize, int blk_row,
|
||||
int blk_col, int block, int plane, void *arg) {
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
|
||||
const struct macroblockd_plane *const pd = &xd->plane[plane];
|
||||
const BLOCK_SIZE bsize = txsize_to_bsize[tx_size];
|
||||
const int tx_row = blk_row >> (1 - pd->subsampling_y);
|
||||
const int tx_col = blk_col >> (1 - pd->subsampling_x);
|
||||
const int max_blocks_high = max_block_high(xd, plane_bsize, plane);
|
||||
const int max_blocks_wide = max_block_wide(xd, plane_bsize, plane);
|
||||
TX_SIZE plane_tx_size;
|
||||
|
||||
if (blk_row >= max_blocks_high || blk_col >= max_blocks_wide) return;
|
||||
|
||||
plane_tx_size =
|
||||
plane ? uv_txsize_lookup[bsize][mbmi->inter_tx_size[tx_row][tx_col]][0][0]
|
||||
: mbmi->inter_tx_size[tx_row][tx_col];
|
||||
|
||||
if (tx_size == plane_tx_size) {
|
||||
plane_bsize = get_plane_block_size(mbmi->sb_type, pd);
|
||||
if (!dry_run)
|
||||
tokenize_b(plane, block, blk_row, blk_col, plane_bsize, tx_size, arg);
|
||||
else if (dry_run == DRY_RUN_NORMAL)
|
||||
set_entropy_context_b(plane, block, blk_row, blk_col, plane_bsize,
|
||||
tx_size, arg);
|
||||
else if (dry_run == DRY_RUN_COSTCOEFFS)
|
||||
cost_coeffs_b(plane, block, blk_row, blk_col, plane_bsize, tx_size, arg);
|
||||
} else {
|
||||
// Half the block size in transform block unit.
|
||||
const TX_SIZE sub_txs = sub_tx_size_map[tx_size];
|
||||
const int bsl = tx_size_wide_unit[sub_txs];
|
||||
int i;
|
||||
|
||||
assert(bsl > 0);
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
const int offsetr = blk_row + ((i >> 1) * bsl);
|
||||
const int offsetc = blk_col + ((i & 0x01) * bsl);
|
||||
|
||||
int step = tx_size_wide_unit[sub_txs] * tx_size_high_unit[sub_txs];
|
||||
|
||||
if (offsetr >= max_blocks_high || offsetc >= max_blocks_wide) continue;
|
||||
|
||||
tokenize_vartx(td, t, dry_run, sub_txs, plane_bsize, offsetr, offsetc,
|
||||
block, plane, arg);
|
||||
block += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av1_tokenize_sb_vartx(const AV1_COMP *cpi, ThreadData *td, TOKENEXTRA **t,
|
||||
RUN_TYPE dry_run, int mi_row, int mi_col,
|
||||
BLOCK_SIZE bsize, int *rate) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
|
||||
TOKENEXTRA *t_backup = *t;
|
||||
const int ctx = av1_get_skip_context(xd);
|
||||
const int skip_inc =
|
||||
!segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP);
|
||||
struct tokenize_b_args arg = { cpi, td, t, 0 };
|
||||
int plane;
|
||||
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
|
||||
|
||||
if (mbmi->skip) {
|
||||
if (!dry_run) td->counts->skip[ctx][1] += skip_inc;
|
||||
reset_skip_context(xd, bsize);
|
||||
if (dry_run) *t = t_backup;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dry_run)
|
||||
td->counts->skip[ctx][0] += skip_inc;
|
||||
else
|
||||
*t = t_backup;
|
||||
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
||||
#if CONFIG_CB4X4
|
||||
if (!is_chroma_reference(mi_row, mi_col, bsize,
|
||||
xd->plane[plane].subsampling_x,
|
||||
xd->plane[plane].subsampling_y)) {
|
||||
#if !CONFIG_PVQ
|
||||
if (!dry_run) {
|
||||
(*t)->token = EOSB_TOKEN;
|
||||
(*t)++;
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
const struct macroblockd_plane *const pd = &xd->plane[plane];
|
||||
#if CONFIG_CB4X4 && !CONFIG_CHROMA_2X2
|
||||
const BLOCK_SIZE plane_bsize =
|
||||
AOMMAX(BLOCK_4X4, get_plane_block_size(bsize, pd));
|
||||
#else
|
||||
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
|
||||
#endif
|
||||
const int mi_width = block_size_wide[plane_bsize] >> tx_size_wide_log2[0];
|
||||
const int mi_height = block_size_high[plane_bsize] >> tx_size_wide_log2[0];
|
||||
const TX_SIZE max_tx_size = get_vartx_max_txsize(mbmi, plane_bsize);
|
||||
const BLOCK_SIZE txb_size = txsize_to_bsize[max_tx_size];
|
||||
int bw = block_size_wide[txb_size] >> tx_size_wide_log2[0];
|
||||
int bh = block_size_high[txb_size] >> tx_size_wide_log2[0];
|
||||
int idx, idy;
|
||||
int block = 0;
|
||||
int step = tx_size_wide_unit[max_tx_size] * tx_size_high_unit[max_tx_size];
|
||||
for (idy = 0; idy < mi_height; idy += bh) {
|
||||
for (idx = 0; idx < mi_width; idx += bw) {
|
||||
tokenize_vartx(td, t, dry_run, max_tx_size, plane_bsize, idy, idx,
|
||||
block, plane, &arg);
|
||||
block += step;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dry_run) {
|
||||
(*t)->token = EOSB_TOKEN;
|
||||
(*t)++;
|
||||
}
|
||||
}
|
||||
if (rate) *rate += arg.this_rate;
|
||||
}
|
||||
#endif // CONFIG_VAR_TX
|
||||
|
||||
void av1_tokenize_sb(const AV1_COMP *cpi, ThreadData *td, TOKENEXTRA **t,
|
||||
RUN_TYPE dry_run, BLOCK_SIZE bsize, int *rate,
|
||||
const int mi_row, const int mi_col) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
MACROBLOCK *const x = &td->mb;
|
||||
MACROBLOCKD *const xd = &x->e_mbd;
|
||||
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
|
||||
const int ctx = av1_get_skip_context(xd);
|
||||
const int skip_inc =
|
||||
!segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP);
|
||||
struct tokenize_b_args arg = { cpi, td, t, 0 };
|
||||
if (mbmi->skip) {
|
||||
if (!dry_run) td->counts->skip[ctx][1] += skip_inc;
|
||||
reset_skip_context(xd, bsize);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dry_run) {
|
||||
#if CONFIG_COEF_INTERLEAVE
|
||||
td->counts->skip[ctx][0] += skip_inc;
|
||||
av1_foreach_transformed_block_interleave(xd, bsize, tokenize_b, &arg);
|
||||
#else
|
||||
int plane;
|
||||
|
||||
td->counts->skip[ctx][0] += skip_inc;
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
||||
#if CONFIG_CB4X4
|
||||
if (!is_chroma_reference(mi_row, mi_col, bsize,
|
||||
xd->plane[plane].subsampling_x,
|
||||
xd->plane[plane].subsampling_y)) {
|
||||
#if !CONFIG_PVQ
|
||||
(*t)->token = EOSB_TOKEN;
|
||||
(*t)++;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
#endif
|
||||
av1_foreach_transformed_block_in_plane(xd, bsize, plane, tokenize_b,
|
||||
&arg);
|
||||
#if !CONFIG_PVQ
|
||||
(*t)->token = EOSB_TOKEN;
|
||||
(*t)++;
|
||||
#endif // !CONFIG_PVQ
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if !CONFIG_PVQ
|
||||
else if (dry_run == DRY_RUN_NORMAL) {
|
||||
int plane;
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
||||
#if CONFIG_CB4X4
|
||||
if (!is_chroma_reference(mi_row, mi_col, bsize,
|
||||
xd->plane[plane].subsampling_x,
|
||||
xd->plane[plane].subsampling_y))
|
||||
continue;
|
||||
#else
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
#endif
|
||||
av1_foreach_transformed_block_in_plane(xd, bsize, plane,
|
||||
set_entropy_context_b, &arg);
|
||||
}
|
||||
} else if (dry_run == DRY_RUN_COSTCOEFFS) {
|
||||
int plane;
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
||||
#if CONFIG_CB4X4
|
||||
if (!is_chroma_reference(mi_row, mi_col, bsize,
|
||||
xd->plane[plane].subsampling_x,
|
||||
xd->plane[plane].subsampling_y))
|
||||
continue;
|
||||
#else
|
||||
(void)mi_row;
|
||||
(void)mi_col;
|
||||
#endif
|
||||
av1_foreach_transformed_block_in_plane(xd, bsize, plane, cost_coeffs_b,
|
||||
&arg);
|
||||
}
|
||||
}
|
||||
#endif // !CONFIG_PVQ
|
||||
|
||||
if (rate) *rate += arg.this_rate;
|
||||
}
|
||||
|
||||
#if CONFIG_SUPERTX
|
||||
void av1_tokenize_sb_supertx(const AV1_COMP *cpi, ThreadData *td,
|
||||
TOKENEXTRA **t, RUN_TYPE dry_run, BLOCK_SIZE bsize,
|
||||
int *rate) {
|
||||
const AV1_COMMON *const cm = &cpi->common;
|
||||
MACROBLOCKD *const xd = &td->mb.e_mbd;
|
||||
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
|
||||
TOKENEXTRA *t_backup = *t;
|
||||
const int ctx = av1_get_skip_context(xd);
|
||||
const int skip_inc =
|
||||
!segfeature_active(&cm->seg, mbmi->segment_id_supertx, SEG_LVL_SKIP);
|
||||
struct tokenize_b_args arg = { cpi, td, t, 0 };
|
||||
if (mbmi->skip) {
|
||||
if (!dry_run) td->counts->skip[ctx][1] += skip_inc;
|
||||
reset_skip_context(xd, bsize);
|
||||
if (dry_run) *t = t_backup;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dry_run) {
|
||||
int plane;
|
||||
td->counts->skip[ctx][0] += skip_inc;
|
||||
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
|
||||
av1_foreach_transformed_block_in_plane(xd, bsize, plane, tokenize_b,
|
||||
&arg);
|
||||
(*t)->token = EOSB_TOKEN;
|
||||
(*t)++;
|
||||
}
|
||||
} else if (dry_run == DRY_RUN_NORMAL) {
|
||||
int plane;
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane)
|
||||
av1_foreach_transformed_block_in_plane(xd, bsize, plane,
|
||||
set_entropy_context_b, &arg);
|
||||
*t = t_backup;
|
||||
} else if (dry_run == DRY_RUN_COSTCOEFFS) {
|
||||
int plane;
|
||||
for (plane = 0; plane < MAX_MB_PLANE; ++plane)
|
||||
av1_foreach_transformed_block_in_plane(xd, bsize, plane, cost_coeffs_b,
|
||||
&arg);
|
||||
}
|
||||
if (rate) *rate += arg.this_rate;
|
||||
}
|
||||
#endif // CONFIG_SUPERTX
|
||||
151
third_party/aom/av1/encoder/tokenize.h
vendored
Normal file
151
third_party/aom/av1/encoder/tokenize.h
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_TOKENIZE_H_
|
||||
#define AV1_ENCODER_TOKENIZE_H_
|
||||
|
||||
#include "av1/common/entropy.h"
|
||||
|
||||
#include "av1/encoder/block.h"
|
||||
#include "av1/encoder/treewriter.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EOSB_TOKEN 127 // Not signalled, encoder only
|
||||
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
typedef int32_t EXTRABIT;
|
||||
#else
|
||||
typedef int16_t EXTRABIT;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int16_t token;
|
||||
EXTRABIT extra;
|
||||
} TOKENVALUE;
|
||||
|
||||
typedef struct {
|
||||
#if CONFIG_NEW_TOKENSET
|
||||
aom_cdf_prob (*tail_cdf)[CDF_SIZE(ENTROPY_TOKENS)];
|
||||
aom_cdf_prob (*head_cdf)[CDF_SIZE(ENTROPY_TOKENS)];
|
||||
int eob_val;
|
||||
int first_val;
|
||||
#elif CONFIG_EC_MULTISYMBOL
|
||||
aom_cdf_prob (*token_cdf)[CDF_SIZE(ENTROPY_TOKENS)];
|
||||
#endif
|
||||
const aom_prob *context_tree;
|
||||
EXTRABIT extra;
|
||||
uint8_t token;
|
||||
uint8_t skip_eob_node;
|
||||
} TOKENEXTRA;
|
||||
|
||||
extern const aom_tree_index av1_coef_tree[];
|
||||
extern const aom_tree_index av1_coef_con_tree[];
|
||||
#if !CONFIG_EC_MULTISYMBOL
|
||||
extern const struct av1_token av1_coef_encodings[];
|
||||
#endif // !CONFIG_EC_MULTISYMBOL
|
||||
|
||||
int av1_is_skippable_in_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
|
||||
|
||||
struct AV1_COMP;
|
||||
struct ThreadData;
|
||||
|
||||
typedef enum {
|
||||
OUTPUT_ENABLED = 0,
|
||||
DRY_RUN_NORMAL,
|
||||
DRY_RUN_COSTCOEFFS,
|
||||
} RUN_TYPE;
|
||||
|
||||
// Note in all the tokenize functions rate if non NULL is incremented
|
||||
// with the coefficient token cost only if dry_run = DRY_RUN_COSTCOEFS,
|
||||
// otherwise rate is not incremented.
|
||||
#if CONFIG_VAR_TX
|
||||
void av1_tokenize_sb_vartx(const struct AV1_COMP *cpi, struct ThreadData *td,
|
||||
TOKENEXTRA **t, RUN_TYPE dry_run, int mi_row,
|
||||
int mi_col, BLOCK_SIZE bsize, int *rate);
|
||||
#endif
|
||||
#if CONFIG_PALETTE
|
||||
void av1_tokenize_palette_sb(const struct AV1_COMP *cpi,
|
||||
const struct ThreadData *const td, int plane,
|
||||
TOKENEXTRA **t, RUN_TYPE dry_run, BLOCK_SIZE bsize,
|
||||
int *rate);
|
||||
#endif // CONFIG_PALETTE
|
||||
void av1_tokenize_sb(const struct AV1_COMP *cpi, struct ThreadData *td,
|
||||
TOKENEXTRA **t, RUN_TYPE dry_run, BLOCK_SIZE bsize,
|
||||
int *rate, const int mi_row, const int mi_col);
|
||||
#if CONFIG_SUPERTX
|
||||
void av1_tokenize_sb_supertx(const struct AV1_COMP *cpi, struct ThreadData *td,
|
||||
TOKENEXTRA **t, RUN_TYPE dry_run, BLOCK_SIZE bsize,
|
||||
int *rate);
|
||||
#endif
|
||||
|
||||
extern const int16_t *av1_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 *av1_dct_value_tokens_ptr;
|
||||
extern const TOKENVALUE *av1_dct_cat_lt_10_value_tokens;
|
||||
extern const int *av1_dct_cat_lt_10_value_cost;
|
||||
extern const int16_t av1_cat6_low_cost[256];
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
#define CAT6_HIGH_COST_ENTRIES 1024
|
||||
#else
|
||||
#define CAT6_HIGH_COST_ENTRIES 64
|
||||
#endif
|
||||
extern const int av1_cat6_high_cost[CAT6_HIGH_COST_ENTRIES];
|
||||
extern const uint8_t av1_cat6_skipped_bits_discount[8];
|
||||
|
||||
static INLINE void av1_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 = av1_dct_cat_lt_10_value_tokens[v].token;
|
||||
*extra = av1_dct_cat_lt_10_value_tokens[v].extra;
|
||||
}
|
||||
static INLINE int16_t av1_get_token(int v) {
|
||||
if (v >= CAT6_MIN_VAL || v <= -CAT6_MIN_VAL) return 10;
|
||||
return av1_dct_cat_lt_10_value_tokens[v].token;
|
||||
}
|
||||
|
||||
static INLINE int av1_get_token_cost(int v, int16_t *token, int cat6_bits) {
|
||||
if (v >= CAT6_MIN_VAL || v <= -CAT6_MIN_VAL) {
|
||||
EXTRABIT extrabits;
|
||||
*token = CATEGORY6_TOKEN;
|
||||
extrabits = abs(v) - CAT6_MIN_VAL;
|
||||
return av1_cat6_low_cost[extrabits & 0xff] +
|
||||
av1_cat6_high_cost[extrabits >> 8] -
|
||||
av1_cat6_skipped_bits_discount[18 - cat6_bits];
|
||||
}
|
||||
*token = av1_dct_cat_lt_10_value_tokens[v].token;
|
||||
return av1_dct_cat_lt_10_value_cost[v];
|
||||
}
|
||||
|
||||
#if !CONFIG_PVQ || CONFIG_VAR_TX
|
||||
static INLINE int get_tx_eob(const struct segmentation *seg, int segment_id,
|
||||
TX_SIZE tx_size) {
|
||||
const int eob_max = tx_size_2d[tx_size];
|
||||
return segfeature_active(seg, segment_id, SEG_LVL_SKIP) ? 0 : eob_max;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_TOKENIZE_H_
|
||||
59
third_party/aom/av1/encoder/treewriter.c
vendored
Normal file
59
third_party/aom/av1/encoder/treewriter.c
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "av1/encoder/treewriter.h"
|
||||
|
||||
static void tree2tok(struct av1_token *tokens, const aom_tree_index *tree,
|
||||
int i, int v, int l) {
|
||||
v += v;
|
||||
++l;
|
||||
|
||||
do {
|
||||
const aom_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 av1_tokens_from_tree(struct av1_token *tokens,
|
||||
const aom_tree_index *tree) {
|
||||
tree2tok(tokens, tree, 0, 0, 0);
|
||||
}
|
||||
|
||||
static unsigned int convert_distribution(unsigned int i, aom_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 av1_tree_probs_from_distribution(aom_tree tree,
|
||||
unsigned int branch_ct[/* n-1 */][2],
|
||||
const unsigned int num_events[/* n */]) {
|
||||
convert_distribution(0, tree, branch_ct, num_events);
|
||||
}
|
||||
42
third_party/aom/av1/encoder/treewriter.h
vendored
Normal file
42
third_party/aom/av1/encoder/treewriter.h
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_TREEWRITER_H_
|
||||
#define AV1_ENCODER_TREEWRITER_H_
|
||||
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void av1_tree_probs_from_distribution(aom_tree tree,
|
||||
unsigned int branch_ct[/* n - 1 */][2],
|
||||
const unsigned int num_events[/* n */]);
|
||||
|
||||
struct av1_token {
|
||||
int value;
|
||||
int len;
|
||||
};
|
||||
|
||||
void av1_tokens_from_tree(struct av1_token *, const aom_tree_index *);
|
||||
|
||||
static INLINE void av1_write_token(aom_writer *w, const aom_tree_index *tree,
|
||||
const aom_prob *probs,
|
||||
const struct av1_token *token) {
|
||||
aom_write_tree(w, tree, probs, token->value, token->len, 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_ENCODER_TREEWRITER_H_
|
||||
61
third_party/aom/av1/encoder/variance_tree.c
vendored
Normal file
61
third_party/aom/av1/encoder/variance_tree.c
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "av1/encoder/variance_tree.h"
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
void av1_setup_var_tree(struct AV1Common *cm, ThreadData *td) {
|
||||
int i, j;
|
||||
#if CONFIG_EXT_PARTITION
|
||||
const int leaf_nodes = 1024;
|
||||
const int tree_nodes = 1024 + 256 + 64 + 16 + 4 + 1;
|
||||
#else
|
||||
const int leaf_nodes = 256;
|
||||
const int tree_nodes = 256 + 64 + 16 + 4 + 1;
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
int index = 0;
|
||||
VAR_TREE *this_var;
|
||||
int nodes;
|
||||
|
||||
aom_free(td->var_tree);
|
||||
CHECK_MEM_ERROR(cm, td->var_tree,
|
||||
aom_calloc(tree_nodes, sizeof(*td->var_tree)));
|
||||
|
||||
this_var = &td->var_tree[0];
|
||||
|
||||
// Sets up all the leaf nodes in the tree.
|
||||
for (index = 0; index < leaf_nodes; ++index) {
|
||||
VAR_TREE *const leaf = &td->var_tree[index];
|
||||
leaf->split[0] = NULL;
|
||||
}
|
||||
|
||||
// Each node has 4 leaf nodes, fill in the child pointers
|
||||
// from leafs to the root.
|
||||
for (nodes = leaf_nodes >> 2; nodes > 0; nodes >>= 2) {
|
||||
for (i = 0; i < nodes; ++i, ++index) {
|
||||
VAR_TREE *const node = &td->var_tree[index];
|
||||
for (j = 0; j < 4; j++) node->split[j] = this_var++;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the root node for the largest superblock size
|
||||
i = MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2;
|
||||
td->var_root[i] = &td->var_tree[tree_nodes - 1];
|
||||
// Set up the root nodes for the rest of the possible superblock sizes
|
||||
while (--i >= 0) {
|
||||
td->var_root[i] = td->var_root[i + 1]->split[0];
|
||||
}
|
||||
}
|
||||
|
||||
void av1_free_var_tree(ThreadData *td) {
|
||||
aom_free(td->var_tree);
|
||||
td->var_tree = NULL;
|
||||
}
|
||||
96
third_party/aom/av1/encoder/variance_tree.h
vendored
Normal file
96
third_party/aom/av1/encoder/variance_tree.h
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_ENCODER_VARIANCE_TREE_H_
|
||||
#define AV1_ENCODER_VARIANCE_TREE_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "./aom_config.h"
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct AV1Common;
|
||||
struct ThreadData;
|
||||
|
||||
typedef struct {
|
||||
int64_t sum_square_error;
|
||||
int64_t sum_error;
|
||||
int log2_count;
|
||||
int variance;
|
||||
} VAR;
|
||||
|
||||
typedef struct {
|
||||
VAR none;
|
||||
VAR horz[2];
|
||||
VAR vert[2];
|
||||
} partition_variance;
|
||||
|
||||
typedef struct VAR_TREE {
|
||||
int force_split;
|
||||
partition_variance variances;
|
||||
struct VAR_TREE *split[4];
|
||||
BLOCK_SIZE bsize;
|
||||
const uint8_t *src;
|
||||
const uint8_t *ref;
|
||||
int src_stride;
|
||||
int ref_stride;
|
||||
int width;
|
||||
int height;
|
||||
#if CONFIG_HIGHBITDEPTH
|
||||
int highbd;
|
||||
#endif // CONFIG_HIGHBITDEPTH
|
||||
} VAR_TREE;
|
||||
|
||||
void av1_setup_var_tree(struct AV1Common *cm, struct ThreadData *td);
|
||||
void av1_free_var_tree(struct ThreadData *td);
|
||||
|
||||
// Set variance values given sum square error, sum error, count.
|
||||
static INLINE void fill_variance(int64_t s2, int64_t s, int c, VAR *v) {
|
||||
v->sum_square_error = s2;
|
||||
v->sum_error = s;
|
||||
v->log2_count = c;
|
||||
v->variance =
|
||||
(int)(256 * (v->sum_square_error -
|
||||
((v->sum_error * v->sum_error) >> v->log2_count)) >>
|
||||
v->log2_count);
|
||||
}
|
||||
|
||||
static INLINE void sum_2_variances(const VAR *a, const VAR *b, VAR *r) {
|
||||
assert(a->log2_count == b->log2_count);
|
||||
fill_variance(a->sum_square_error + b->sum_square_error,
|
||||
a->sum_error + b->sum_error, a->log2_count + 1, r);
|
||||
}
|
||||
|
||||
static INLINE void fill_variance_node(VAR_TREE *vt) {
|
||||
sum_2_variances(&vt->split[0]->variances.none, &vt->split[1]->variances.none,
|
||||
&vt->variances.horz[0]);
|
||||
sum_2_variances(&vt->split[2]->variances.none, &vt->split[3]->variances.none,
|
||||
&vt->variances.horz[1]);
|
||||
sum_2_variances(&vt->split[0]->variances.none, &vt->split[2]->variances.none,
|
||||
&vt->variances.vert[0]);
|
||||
sum_2_variances(&vt->split[1]->variances.none, &vt->split[3]->variances.none,
|
||||
&vt->variances.vert[1]);
|
||||
sum_2_variances(&vt->variances.vert[0], &vt->variances.vert[1],
|
||||
&vt->variances.none);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* AV1_ENCODER_VARIANCE_TREE_H_ */
|
||||
125
third_party/aom/av1/encoder/wedge_utils.c
vendored
Normal file
125
third_party/aom/av1/encoder/wedge_utils.c
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
#include "aom_ports/mem.h"
|
||||
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
|
||||
#include "av1/common/reconinter.h"
|
||||
|
||||
#define MAX_MASK_VALUE (1 << WEDGE_WEIGHT_BITS)
|
||||
|
||||
/**
|
||||
* Computes SSE of a compound predictor constructed from 2 fundamental
|
||||
* predictors p0 and p1 using blending with mask.
|
||||
*
|
||||
* r1: Residuals of p1.
|
||||
* (source - p1)
|
||||
* d: Difference of p1 and p0.
|
||||
* (p1 - p0)
|
||||
* m: The blending mask
|
||||
* N: Number of pixels
|
||||
*
|
||||
* 'r1', 'd', and 'm' are contiguous.
|
||||
*
|
||||
* Computes:
|
||||
* Sum((MAX_MASK_VALUE*r1 + mask*d)**2), which is equivalent to:
|
||||
* Sum((mask*r0 + (MAX_MASK_VALUE-mask)*r1)**2),
|
||||
* where r0 is (source - p0), and r1 is (source - p1), which is in turn
|
||||
* is equivalent to:
|
||||
* Sum((source*MAX_MASK_VALUE - (mask*p0 + (MAX_MASK_VALUE-mask)*p1))**2),
|
||||
* which is the SSE of the residuals of the compound predictor scaled up by
|
||||
* MAX_MASK_VALUE**2.
|
||||
*
|
||||
* Note that we clamp the partial term in the loop to 16 bits signed. This is
|
||||
* to facilitate equivalent SIMD implementation. It should have no effect if
|
||||
* residuals are within 16 - WEDGE_WEIGHT_BITS (=10) signed, which always
|
||||
* holds for 8 bit input, and on real input, it should hold practically always,
|
||||
* as residuals are expected to be small.
|
||||
*/
|
||||
uint64_t av1_wedge_sse_from_residuals_c(const int16_t *r1, const int16_t *d,
|
||||
const uint8_t *m, int N) {
|
||||
uint64_t csse = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
int32_t t = MAX_MASK_VALUE * r1[i] + m[i] * d[i];
|
||||
t = clamp(t, INT16_MIN, INT16_MAX);
|
||||
csse += t * t;
|
||||
}
|
||||
return ROUND_POWER_OF_TWO(csse, 2 * WEDGE_WEIGHT_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose the mask sign for a compound predictor.
|
||||
*
|
||||
* ds: Difference of the squares of the residuals.
|
||||
* r0**2 - r1**2
|
||||
* m: The blending mask
|
||||
* N: Number of pixels
|
||||
* limit: Pre-computed threshold value.
|
||||
* MAX_MASK_VALUE/2 * (sum(r0**2) - sum(r1**2))
|
||||
*
|
||||
* 'ds' and 'm' are contiguous.
|
||||
*
|
||||
* Returns true if the negated mask has lower SSE compared to the positive
|
||||
* mask. Computation is based on:
|
||||
* Sum((mask*r0 + (MAX_MASK_VALUE-mask)*r1)**2)
|
||||
* >
|
||||
* Sum(((MAX_MASK_VALUE-mask)*r0 + mask*r1)**2)
|
||||
*
|
||||
* which can be simplified to:
|
||||
*
|
||||
* Sum(mask*(r0**2 - r1**2)) > MAX_MASK_VALUE/2 * (sum(r0**2) - sum(r1**2))
|
||||
*
|
||||
* The right hand side does not depend on the mask, and needs to be passed as
|
||||
* the 'limit' parameter.
|
||||
*
|
||||
* After pre-computing (r0**2 - r1**2), which is passed in as 'ds', the left
|
||||
* hand side is simply a scalar product between an int16_t and uint8_t vector.
|
||||
*
|
||||
* Note that for efficiency, ds is stored on 16 bits. Real input residuals
|
||||
* being small, this should not cause a noticeable issue.
|
||||
*/
|
||||
int av1_wedge_sign_from_residuals_c(const int16_t *ds, const uint8_t *m, int N,
|
||||
int64_t limit) {
|
||||
int64_t acc = 0;
|
||||
|
||||
do {
|
||||
acc += *ds++ * *m++;
|
||||
} while (--N);
|
||||
|
||||
return acc > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the element-wise difference of the squares of 2 arrays.
|
||||
*
|
||||
* d: Difference of the squares of the inputs: a**2 - b**2
|
||||
* a: First input array
|
||||
* b: Second input array
|
||||
* N: Number of elements
|
||||
*
|
||||
* 'd', 'a', and 'b' are contiguous.
|
||||
*
|
||||
* The result is saturated to signed 16 bits.
|
||||
*/
|
||||
void av1_wedge_compute_delta_squares_c(int16_t *d, const int16_t *a,
|
||||
const int16_t *b, int N) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
d[i] = clamp(a[i] * a[i] - b[i] * b[i], INT16_MIN, INT16_MAX);
|
||||
}
|
||||
193
third_party/aom/av1/encoder/x86/av1_highbd_quantize_sse4.c
vendored
Normal file
193
third_party/aom/av1/encoder/x86/av1_highbd_quantize_sse4.c
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <smmintrin.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
|
||||
// Coefficient quantization phase 1
|
||||
// param[0-2] : rounding/quan/dequan constants
|
||||
static INLINE void quantize_coeff_phase1(__m128i *coeff, const __m128i *param,
|
||||
const int shift, const int scale,
|
||||
__m128i *qcoeff, __m128i *dquan,
|
||||
__m128i *sign) {
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
const __m128i one = _mm_set1_epi32(1);
|
||||
|
||||
*sign = _mm_cmplt_epi32(*coeff, zero);
|
||||
*sign = _mm_or_si128(*sign, one);
|
||||
*coeff = _mm_abs_epi32(*coeff);
|
||||
|
||||
qcoeff[0] = _mm_add_epi32(*coeff, param[0]);
|
||||
qcoeff[1] = _mm_unpackhi_epi32(qcoeff[0], zero);
|
||||
qcoeff[0] = _mm_unpacklo_epi32(qcoeff[0], zero);
|
||||
|
||||
qcoeff[0] = _mm_mul_epi32(qcoeff[0], param[1]);
|
||||
qcoeff[0] = _mm_srli_epi64(qcoeff[0], shift);
|
||||
dquan[0] = _mm_mul_epi32(qcoeff[0], param[2]);
|
||||
dquan[0] = _mm_srli_epi64(dquan[0], scale);
|
||||
}
|
||||
|
||||
// Coefficient quantization phase 2
|
||||
static INLINE void quantize_coeff_phase2(__m128i *qcoeff, __m128i *dquan,
|
||||
const __m128i *sign,
|
||||
const __m128i *param, const int shift,
|
||||
const int scale, tran_low_t *qAddr,
|
||||
tran_low_t *dqAddr) {
|
||||
__m128i mask0L = _mm_set_epi32(-1, -1, 0, 0);
|
||||
__m128i mask0H = _mm_set_epi32(0, 0, -1, -1);
|
||||
|
||||
qcoeff[1] = _mm_mul_epi32(qcoeff[1], param[1]);
|
||||
qcoeff[1] = _mm_srli_epi64(qcoeff[1], shift);
|
||||
dquan[1] = _mm_mul_epi32(qcoeff[1], param[2]);
|
||||
dquan[1] = _mm_srli_epi64(dquan[1], scale);
|
||||
|
||||
// combine L&H
|
||||
qcoeff[0] = _mm_shuffle_epi32(qcoeff[0], 0xd8);
|
||||
qcoeff[1] = _mm_shuffle_epi32(qcoeff[1], 0x8d);
|
||||
|
||||
qcoeff[0] = _mm_and_si128(qcoeff[0], mask0H);
|
||||
qcoeff[1] = _mm_and_si128(qcoeff[1], mask0L);
|
||||
|
||||
dquan[0] = _mm_shuffle_epi32(dquan[0], 0xd8);
|
||||
dquan[1] = _mm_shuffle_epi32(dquan[1], 0x8d);
|
||||
|
||||
dquan[0] = _mm_and_si128(dquan[0], mask0H);
|
||||
dquan[1] = _mm_and_si128(dquan[1], mask0L);
|
||||
|
||||
qcoeff[0] = _mm_or_si128(qcoeff[0], qcoeff[1]);
|
||||
dquan[0] = _mm_or_si128(dquan[0], dquan[1]);
|
||||
|
||||
qcoeff[0] = _mm_sign_epi32(qcoeff[0], *sign);
|
||||
dquan[0] = _mm_sign_epi32(dquan[0], *sign);
|
||||
|
||||
_mm_storeu_si128((__m128i *)qAddr, qcoeff[0]);
|
||||
_mm_storeu_si128((__m128i *)dqAddr, dquan[0]);
|
||||
}
|
||||
|
||||
static INLINE void find_eob(tran_low_t *qcoeff_ptr, const int16_t *iscan,
|
||||
__m128i *eob) {
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
__m128i mask, iscanIdx;
|
||||
const __m128i q0 = _mm_loadu_si128((__m128i const *)qcoeff_ptr);
|
||||
const __m128i q1 = _mm_loadu_si128((__m128i const *)(qcoeff_ptr + 4));
|
||||
__m128i nz_flag0 = _mm_cmpeq_epi32(q0, zero);
|
||||
__m128i nz_flag1 = _mm_cmpeq_epi32(q1, zero);
|
||||
|
||||
nz_flag0 = _mm_cmpeq_epi32(nz_flag0, zero);
|
||||
nz_flag1 = _mm_cmpeq_epi32(nz_flag1, zero);
|
||||
|
||||
mask = _mm_packs_epi32(nz_flag0, nz_flag1);
|
||||
iscanIdx = _mm_loadu_si128((__m128i const *)iscan);
|
||||
iscanIdx = _mm_sub_epi16(iscanIdx, mask);
|
||||
iscanIdx = _mm_and_si128(iscanIdx, mask);
|
||||
*eob = _mm_max_epi16(*eob, iscanIdx);
|
||||
}
|
||||
|
||||
static INLINE uint16_t get_accumulated_eob(__m128i *eob) {
|
||||
__m128i eob_shuffled;
|
||||
uint16_t eobValue;
|
||||
eob_shuffled = _mm_shuffle_epi32(*eob, 0xe);
|
||||
*eob = _mm_max_epi16(*eob, eob_shuffled);
|
||||
eob_shuffled = _mm_shufflelo_epi16(*eob, 0xe);
|
||||
*eob = _mm_max_epi16(*eob, eob_shuffled);
|
||||
eob_shuffled = _mm_shufflelo_epi16(*eob, 0x1);
|
||||
*eob = _mm_max_epi16(*eob, eob_shuffled);
|
||||
eobValue = _mm_extract_epi16(*eob, 0);
|
||||
return eobValue;
|
||||
}
|
||||
|
||||
void av1_highbd_quantize_fp_sse4_1(
|
||||
const tran_low_t *coeff_ptr, intptr_t count, int skip_block,
|
||||
const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr,
|
||||
const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
|
||||
tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
|
||||
const int16_t *scan, const int16_t *iscan, int log_scale) {
|
||||
__m128i coeff[2], qcoeff[2], dequant[2], qparam[3], coeff_sign;
|
||||
__m128i eob = _mm_setzero_si128();
|
||||
const tran_low_t *src = coeff_ptr;
|
||||
tran_low_t *quanAddr = qcoeff_ptr;
|
||||
tran_low_t *dquanAddr = dqcoeff_ptr;
|
||||
const int shift = 16 - log_scale;
|
||||
const int coeff_stride = 4;
|
||||
const int quan_stride = coeff_stride;
|
||||
(void)skip_block;
|
||||
(void)zbin_ptr;
|
||||
(void)quant_shift_ptr;
|
||||
(void)scan;
|
||||
|
||||
memset(quanAddr, 0, count * sizeof(quanAddr[0]));
|
||||
memset(dquanAddr, 0, count * sizeof(dquanAddr[0]));
|
||||
|
||||
if (!skip_block) {
|
||||
coeff[0] = _mm_loadu_si128((__m128i const *)src);
|
||||
|
||||
qparam[0] =
|
||||
_mm_set_epi32(round_ptr[1], round_ptr[1], round_ptr[1], round_ptr[0]);
|
||||
qparam[1] = _mm_set_epi64x(quant_ptr[1], quant_ptr[0]);
|
||||
qparam[2] = _mm_set_epi64x(dequant_ptr[1], dequant_ptr[0]);
|
||||
|
||||
// DC and first 3 AC
|
||||
quantize_coeff_phase1(&coeff[0], qparam, shift, log_scale, qcoeff, dequant,
|
||||
&coeff_sign);
|
||||
|
||||
// update round/quan/dquan for AC
|
||||
qparam[0] = _mm_unpackhi_epi64(qparam[0], qparam[0]);
|
||||
qparam[1] = _mm_set_epi64x(quant_ptr[1], quant_ptr[1]);
|
||||
qparam[2] = _mm_set_epi64x(dequant_ptr[1], dequant_ptr[1]);
|
||||
|
||||
quantize_coeff_phase2(qcoeff, dequant, &coeff_sign, qparam, shift,
|
||||
log_scale, quanAddr, dquanAddr);
|
||||
|
||||
// next 4 AC
|
||||
coeff[1] = _mm_loadu_si128((__m128i const *)(src + coeff_stride));
|
||||
quantize_coeff_phase1(&coeff[1], qparam, shift, log_scale, qcoeff, dequant,
|
||||
&coeff_sign);
|
||||
quantize_coeff_phase2(qcoeff, dequant, &coeff_sign, qparam, shift,
|
||||
log_scale, quanAddr + quan_stride,
|
||||
dquanAddr + quan_stride);
|
||||
|
||||
find_eob(quanAddr, iscan, &eob);
|
||||
|
||||
count -= 8;
|
||||
|
||||
// loop for the rest of AC
|
||||
while (count > 0) {
|
||||
src += coeff_stride << 1;
|
||||
quanAddr += quan_stride << 1;
|
||||
dquanAddr += quan_stride << 1;
|
||||
iscan += quan_stride << 1;
|
||||
|
||||
coeff[0] = _mm_loadu_si128((__m128i const *)src);
|
||||
coeff[1] = _mm_loadu_si128((__m128i const *)(src + coeff_stride));
|
||||
|
||||
quantize_coeff_phase1(&coeff[0], qparam, shift, log_scale, qcoeff,
|
||||
dequant, &coeff_sign);
|
||||
quantize_coeff_phase2(qcoeff, dequant, &coeff_sign, qparam, shift,
|
||||
log_scale, quanAddr, dquanAddr);
|
||||
|
||||
quantize_coeff_phase1(&coeff[1], qparam, shift, log_scale, qcoeff,
|
||||
dequant, &coeff_sign);
|
||||
quantize_coeff_phase2(qcoeff, dequant, &coeff_sign, qparam, shift,
|
||||
log_scale, quanAddr + quan_stride,
|
||||
dquanAddr + quan_stride);
|
||||
|
||||
find_eob(quanAddr, iscan, &eob);
|
||||
|
||||
count -= 8;
|
||||
}
|
||||
*eob_ptr = get_accumulated_eob(&eob);
|
||||
} else {
|
||||
*eob_ptr = 0;
|
||||
}
|
||||
}
|
||||
211
third_party/aom/av1/encoder/x86/av1_quantize_sse2.c
vendored
Normal file
211
third_party/aom/av1/encoder/x86/av1_quantize_sse2.c
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <emmintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "./av1_rtcd.h"
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
void av1_quantize_fp_sse2(const int16_t *coeff_ptr, intptr_t n_coeffs,
|
||||
int skip_block, const int16_t *zbin_ptr,
|
||||
const int16_t *round_ptr, const int16_t *quant_ptr,
|
||||
const int16_t *quant_shift_ptr, int16_t *qcoeff_ptr,
|
||||
int16_t *dqcoeff_ptr, const int16_t *dequant_ptr,
|
||||
uint16_t *eob_ptr, const int16_t *scan_ptr,
|
||||
const int16_t *iscan_ptr) {
|
||||
__m128i zero;
|
||||
__m128i thr;
|
||||
int16_t nzflag;
|
||||
(void)scan_ptr;
|
||||
(void)zbin_ptr;
|
||||
(void)quant_shift_ptr;
|
||||
|
||||
coeff_ptr += n_coeffs;
|
||||
iscan_ptr += n_coeffs;
|
||||
qcoeff_ptr += n_coeffs;
|
||||
dqcoeff_ptr += n_coeffs;
|
||||
n_coeffs = -n_coeffs;
|
||||
zero = _mm_setzero_si128();
|
||||
|
||||
if (!skip_block) {
|
||||
__m128i eob;
|
||||
__m128i round, quant, dequant;
|
||||
{
|
||||
__m128i coeff0, coeff1;
|
||||
|
||||
// Setup global values
|
||||
{
|
||||
round = _mm_load_si128((const __m128i *)round_ptr);
|
||||
quant = _mm_load_si128((const __m128i *)quant_ptr);
|
||||
dequant = _mm_load_si128((const __m128i *)dequant_ptr);
|
||||
}
|
||||
|
||||
{
|
||||
__m128i coeff0_sign, coeff1_sign;
|
||||
__m128i qcoeff0, qcoeff1;
|
||||
__m128i qtmp0, qtmp1;
|
||||
// Do DC and first 15 AC
|
||||
coeff0 = _mm_load_si128((const __m128i *)(coeff_ptr + n_coeffs));
|
||||
coeff1 = _mm_load_si128((const __m128i *)(coeff_ptr + n_coeffs) + 1);
|
||||
|
||||
// Poor man's sign extract
|
||||
coeff0_sign = _mm_srai_epi16(coeff0, 15);
|
||||
coeff1_sign = _mm_srai_epi16(coeff1, 15);
|
||||
qcoeff0 = _mm_xor_si128(coeff0, coeff0_sign);
|
||||
qcoeff1 = _mm_xor_si128(coeff1, coeff1_sign);
|
||||
qcoeff0 = _mm_sub_epi16(qcoeff0, coeff0_sign);
|
||||
qcoeff1 = _mm_sub_epi16(qcoeff1, coeff1_sign);
|
||||
|
||||
qcoeff0 = _mm_adds_epi16(qcoeff0, round);
|
||||
round = _mm_unpackhi_epi64(round, round);
|
||||
qcoeff1 = _mm_adds_epi16(qcoeff1, round);
|
||||
qtmp0 = _mm_mulhi_epi16(qcoeff0, quant);
|
||||
quant = _mm_unpackhi_epi64(quant, quant);
|
||||
qtmp1 = _mm_mulhi_epi16(qcoeff1, quant);
|
||||
|
||||
// Reinsert signs
|
||||
qcoeff0 = _mm_xor_si128(qtmp0, coeff0_sign);
|
||||
qcoeff1 = _mm_xor_si128(qtmp1, coeff1_sign);
|
||||
qcoeff0 = _mm_sub_epi16(qcoeff0, coeff0_sign);
|
||||
qcoeff1 = _mm_sub_epi16(qcoeff1, coeff1_sign);
|
||||
|
||||
_mm_store_si128((__m128i *)(qcoeff_ptr + n_coeffs), qcoeff0);
|
||||
_mm_store_si128((__m128i *)(qcoeff_ptr + n_coeffs) + 1, qcoeff1);
|
||||
|
||||
coeff0 = _mm_mullo_epi16(qcoeff0, dequant);
|
||||
dequant = _mm_unpackhi_epi64(dequant, dequant);
|
||||
coeff1 = _mm_mullo_epi16(qcoeff1, dequant);
|
||||
|
||||
_mm_store_si128((__m128i *)(dqcoeff_ptr + n_coeffs), coeff0);
|
||||
_mm_store_si128((__m128i *)(dqcoeff_ptr + n_coeffs) + 1, coeff1);
|
||||
}
|
||||
|
||||
{
|
||||
// Scan for eob
|
||||
__m128i zero_coeff0, zero_coeff1;
|
||||
__m128i nzero_coeff0, nzero_coeff1;
|
||||
__m128i iscan0, iscan1;
|
||||
__m128i eob1;
|
||||
zero_coeff0 = _mm_cmpeq_epi16(coeff0, zero);
|
||||
zero_coeff1 = _mm_cmpeq_epi16(coeff1, zero);
|
||||
nzero_coeff0 = _mm_cmpeq_epi16(zero_coeff0, zero);
|
||||
nzero_coeff1 = _mm_cmpeq_epi16(zero_coeff1, zero);
|
||||
iscan0 = _mm_load_si128((const __m128i *)(iscan_ptr + n_coeffs));
|
||||
iscan1 = _mm_load_si128((const __m128i *)(iscan_ptr + n_coeffs) + 1);
|
||||
// Add one to convert from indices to counts
|
||||
iscan0 = _mm_sub_epi16(iscan0, nzero_coeff0);
|
||||
iscan1 = _mm_sub_epi16(iscan1, nzero_coeff1);
|
||||
eob = _mm_and_si128(iscan0, nzero_coeff0);
|
||||
eob1 = _mm_and_si128(iscan1, nzero_coeff1);
|
||||
eob = _mm_max_epi16(eob, eob1);
|
||||
}
|
||||
n_coeffs += 8 * 2;
|
||||
}
|
||||
|
||||
thr = _mm_srai_epi16(dequant, 1);
|
||||
|
||||
// AC only loop
|
||||
while (n_coeffs < 0) {
|
||||
__m128i coeff0, coeff1;
|
||||
{
|
||||
__m128i coeff0_sign, coeff1_sign;
|
||||
__m128i qcoeff0, qcoeff1;
|
||||
__m128i qtmp0, qtmp1;
|
||||
|
||||
coeff0 = _mm_load_si128((const __m128i *)(coeff_ptr + n_coeffs));
|
||||
coeff1 = _mm_load_si128((const __m128i *)(coeff_ptr + n_coeffs) + 1);
|
||||
|
||||
// Poor man's sign extract
|
||||
coeff0_sign = _mm_srai_epi16(coeff0, 15);
|
||||
coeff1_sign = _mm_srai_epi16(coeff1, 15);
|
||||
qcoeff0 = _mm_xor_si128(coeff0, coeff0_sign);
|
||||
qcoeff1 = _mm_xor_si128(coeff1, coeff1_sign);
|
||||
qcoeff0 = _mm_sub_epi16(qcoeff0, coeff0_sign);
|
||||
qcoeff1 = _mm_sub_epi16(qcoeff1, coeff1_sign);
|
||||
|
||||
nzflag = _mm_movemask_epi8(_mm_cmpgt_epi16(qcoeff0, thr)) |
|
||||
_mm_movemask_epi8(_mm_cmpgt_epi16(qcoeff1, thr));
|
||||
|
||||
if (nzflag) {
|
||||
qcoeff0 = _mm_adds_epi16(qcoeff0, round);
|
||||
qcoeff1 = _mm_adds_epi16(qcoeff1, round);
|
||||
qtmp0 = _mm_mulhi_epi16(qcoeff0, quant);
|
||||
qtmp1 = _mm_mulhi_epi16(qcoeff1, quant);
|
||||
|
||||
// Reinsert signs
|
||||
qcoeff0 = _mm_xor_si128(qtmp0, coeff0_sign);
|
||||
qcoeff1 = _mm_xor_si128(qtmp1, coeff1_sign);
|
||||
qcoeff0 = _mm_sub_epi16(qcoeff0, coeff0_sign);
|
||||
qcoeff1 = _mm_sub_epi16(qcoeff1, coeff1_sign);
|
||||
|
||||
_mm_store_si128((__m128i *)(qcoeff_ptr + n_coeffs), qcoeff0);
|
||||
_mm_store_si128((__m128i *)(qcoeff_ptr + n_coeffs) + 1, qcoeff1);
|
||||
|
||||
coeff0 = _mm_mullo_epi16(qcoeff0, dequant);
|
||||
coeff1 = _mm_mullo_epi16(qcoeff1, dequant);
|
||||
|
||||
_mm_store_si128((__m128i *)(dqcoeff_ptr + n_coeffs), coeff0);
|
||||
_mm_store_si128((__m128i *)(dqcoeff_ptr + n_coeffs) + 1, coeff1);
|
||||
} else {
|
||||
_mm_store_si128((__m128i *)(qcoeff_ptr + n_coeffs), zero);
|
||||
_mm_store_si128((__m128i *)(qcoeff_ptr + n_coeffs) + 1, zero);
|
||||
|
||||
_mm_store_si128((__m128i *)(dqcoeff_ptr + n_coeffs), zero);
|
||||
_mm_store_si128((__m128i *)(dqcoeff_ptr + n_coeffs) + 1, zero);
|
||||
}
|
||||
}
|
||||
|
||||
if (nzflag) {
|
||||
// Scan for eob
|
||||
__m128i zero_coeff0, zero_coeff1;
|
||||
__m128i nzero_coeff0, nzero_coeff1;
|
||||
__m128i iscan0, iscan1;
|
||||
__m128i eob0, eob1;
|
||||
zero_coeff0 = _mm_cmpeq_epi16(coeff0, zero);
|
||||
zero_coeff1 = _mm_cmpeq_epi16(coeff1, zero);
|
||||
nzero_coeff0 = _mm_cmpeq_epi16(zero_coeff0, zero);
|
||||
nzero_coeff1 = _mm_cmpeq_epi16(zero_coeff1, zero);
|
||||
iscan0 = _mm_load_si128((const __m128i *)(iscan_ptr + n_coeffs));
|
||||
iscan1 = _mm_load_si128((const __m128i *)(iscan_ptr + n_coeffs) + 1);
|
||||
// Add one to convert from indices to counts
|
||||
iscan0 = _mm_sub_epi16(iscan0, nzero_coeff0);
|
||||
iscan1 = _mm_sub_epi16(iscan1, nzero_coeff1);
|
||||
eob0 = _mm_and_si128(iscan0, nzero_coeff0);
|
||||
eob1 = _mm_and_si128(iscan1, nzero_coeff1);
|
||||
eob0 = _mm_max_epi16(eob0, eob1);
|
||||
eob = _mm_max_epi16(eob, eob0);
|
||||
}
|
||||
n_coeffs += 8 * 2;
|
||||
}
|
||||
|
||||
// Accumulate EOB
|
||||
{
|
||||
__m128i eob_shuffled;
|
||||
eob_shuffled = _mm_shuffle_epi32(eob, 0xe);
|
||||
eob = _mm_max_epi16(eob, eob_shuffled);
|
||||
eob_shuffled = _mm_shufflelo_epi16(eob, 0xe);
|
||||
eob = _mm_max_epi16(eob, eob_shuffled);
|
||||
eob_shuffled = _mm_shufflelo_epi16(eob, 0x1);
|
||||
eob = _mm_max_epi16(eob, eob_shuffled);
|
||||
*eob_ptr = _mm_extract_epi16(eob, 1);
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
_mm_store_si128((__m128i *)(dqcoeff_ptr + n_coeffs), zero);
|
||||
_mm_store_si128((__m128i *)(dqcoeff_ptr + n_coeffs) + 1, zero);
|
||||
_mm_store_si128((__m128i *)(qcoeff_ptr + n_coeffs), zero);
|
||||
_mm_store_si128((__m128i *)(qcoeff_ptr + n_coeffs) + 1, zero);
|
||||
n_coeffs += 8 * 2;
|
||||
} while (n_coeffs < 0);
|
||||
*eob_ptr = 0;
|
||||
}
|
||||
}
|
||||
204
third_party/aom/av1/encoder/x86/av1_quantize_ssse3_x86_64.asm
vendored
Normal file
204
third_party/aom/av1/encoder/x86/av1_quantize_ssse3_x86_64.asm
vendored
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
;
|
||||
; Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
;
|
||||
; This source code is subject to the terms of the BSD 2 Clause License and
|
||||
; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
; was not distributed with this source code in the LICENSE file, you can
|
||||
; obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
; Media Patent License 1.0 was not distributed with this source code in the
|
||||
; PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
;
|
||||
|
||||
;
|
||||
|
||||
%define private_prefix av1
|
||||
|
||||
%include "third_party/x86inc/x86inc.asm"
|
||||
|
||||
SECTION_RODATA
|
||||
pw_1: times 8 dw 1
|
||||
|
||||
SECTION .text
|
||||
|
||||
%macro QUANTIZE_FP 2
|
||||
cglobal quantize_%1, 0, %2, 15, coeff, ncoeff, skip, zbin, round, quant, \
|
||||
shift, qcoeff, dqcoeff, dequant, \
|
||||
eob, scan, iscan
|
||||
cmp dword skipm, 0
|
||||
jne .blank
|
||||
|
||||
; actual quantize loop - setup pointers, rounders, etc.
|
||||
movifnidn coeffq, coeffmp
|
||||
movifnidn ncoeffq, ncoeffmp
|
||||
mov r2, dequantmp
|
||||
movifnidn zbinq, zbinmp
|
||||
movifnidn roundq, roundmp
|
||||
movifnidn quantq, quantmp
|
||||
mova m1, [roundq] ; m1 = round
|
||||
mova m2, [quantq] ; m2 = quant
|
||||
%ifidn %1, fp_32x32
|
||||
pcmpeqw m5, m5
|
||||
psrlw m5, 15
|
||||
paddw m1, m5
|
||||
psrlw m1, 1 ; m1 = (m1 + 1) / 2
|
||||
%endif
|
||||
mova m3, [r2q] ; m3 = dequant
|
||||
mov r3, qcoeffmp
|
||||
mov r4, dqcoeffmp
|
||||
mov r5, iscanmp
|
||||
%ifidn %1, fp_32x32
|
||||
psllw m2, 1
|
||||
%endif
|
||||
pxor m5, m5 ; m5 = dedicated zero
|
||||
|
||||
lea coeffq, [ coeffq+ncoeffq*2]
|
||||
lea r5q, [ r5q+ncoeffq*2]
|
||||
lea r3q, [ r3q+ncoeffq*2]
|
||||
lea r4q, [r4q+ncoeffq*2]
|
||||
neg ncoeffq
|
||||
|
||||
; get DC and first 15 AC coeffs
|
||||
mova m9, [ coeffq+ncoeffq*2+ 0] ; m9 = c[i]
|
||||
mova m10, [ coeffq+ncoeffq*2+16] ; m10 = c[i]
|
||||
pabsw m6, m9 ; m6 = abs(m9)
|
||||
pabsw m11, m10 ; m11 = abs(m10)
|
||||
pcmpeqw m7, m7
|
||||
|
||||
paddsw m6, m1 ; m6 += round
|
||||
punpckhqdq m1, m1
|
||||
paddsw m11, m1 ; m11 += round
|
||||
pmulhw m8, m6, m2 ; m8 = m6*q>>16
|
||||
punpckhqdq m2, m2
|
||||
pmulhw m13, m11, m2 ; m13 = m11*q>>16
|
||||
psignw m8, m9 ; m8 = reinsert sign
|
||||
psignw m13, m10 ; m13 = reinsert sign
|
||||
mova [r3q+ncoeffq*2+ 0], m8
|
||||
mova [r3q+ncoeffq*2+16], m13
|
||||
%ifidn %1, fp_32x32
|
||||
pabsw m8, m8
|
||||
pabsw m13, m13
|
||||
%endif
|
||||
pmullw m8, m3 ; r4[i] = r3[i] * q
|
||||
punpckhqdq m3, m3
|
||||
pmullw m13, m3 ; r4[i] = r3[i] * q
|
||||
%ifidn %1, fp_32x32
|
||||
psrlw m8, 1
|
||||
psrlw m13, 1
|
||||
psignw m8, m9
|
||||
psignw m13, m10
|
||||
psrlw m0, m3, 2
|
||||
%else
|
||||
psrlw m0, m3, 1
|
||||
%endif
|
||||
mova [r4q+ncoeffq*2+ 0], m8
|
||||
mova [r4q+ncoeffq*2+16], m13
|
||||
pcmpeqw m8, m5 ; m8 = c[i] == 0
|
||||
pcmpeqw m13, m5 ; m13 = c[i] == 0
|
||||
mova m6, [ r5q+ncoeffq*2+ 0] ; m6 = scan[i]
|
||||
mova m11, [ r5q+ncoeffq*2+16] ; m11 = scan[i]
|
||||
psubw m6, m7 ; m6 = scan[i] + 1
|
||||
psubw m11, m7 ; m11 = scan[i] + 1
|
||||
pandn m8, m6 ; m8 = max(eob)
|
||||
pandn m13, m11 ; m13 = max(eob)
|
||||
pmaxsw m8, m13
|
||||
add ncoeffq, mmsize
|
||||
jz .accumulate_eob
|
||||
|
||||
.ac_only_loop:
|
||||
mova m9, [ coeffq+ncoeffq*2+ 0] ; m9 = c[i]
|
||||
mova m10, [ coeffq+ncoeffq*2+16] ; m10 = c[i]
|
||||
pabsw m6, m9 ; m6 = abs(m9)
|
||||
pabsw m11, m10 ; m11 = abs(m10)
|
||||
|
||||
pcmpgtw m7, m6, m0
|
||||
pcmpgtw m12, m11, m0
|
||||
pmovmskb r6d, m7
|
||||
pmovmskb r2d, m12
|
||||
|
||||
or r6, r2
|
||||
jz .skip_iter
|
||||
|
||||
pcmpeqw m7, m7
|
||||
|
||||
paddsw m6, m1 ; m6 += round
|
||||
paddsw m11, m1 ; m11 += round
|
||||
pmulhw m14, m6, m2 ; m14 = m6*q>>16
|
||||
pmulhw m13, m11, m2 ; m13 = m11*q>>16
|
||||
psignw m14, m9 ; m14 = reinsert sign
|
||||
psignw m13, m10 ; m13 = reinsert sign
|
||||
mova [r3q+ncoeffq*2+ 0], m14
|
||||
mova [r3q+ncoeffq*2+16], m13
|
||||
%ifidn %1, fp_32x32
|
||||
pabsw m14, m14
|
||||
pabsw m13, m13
|
||||
%endif
|
||||
pmullw m14, m3 ; r4[i] = r3[i] * q
|
||||
pmullw m13, m3 ; r4[i] = r3[i] * q
|
||||
%ifidn %1, fp_32x32
|
||||
psrlw m14, 1
|
||||
psrlw m13, 1
|
||||
psignw m14, m9
|
||||
psignw m13, m10
|
||||
%endif
|
||||
mova [r4q+ncoeffq*2+ 0], m14
|
||||
mova [r4q+ncoeffq*2+16], m13
|
||||
pcmpeqw m14, m5 ; m14 = c[i] == 0
|
||||
pcmpeqw m13, m5 ; m13 = c[i] == 0
|
||||
mova m6, [ r5q+ncoeffq*2+ 0] ; m6 = scan[i]
|
||||
mova m11, [ r5q+ncoeffq*2+16] ; m11 = scan[i]
|
||||
psubw m6, m7 ; m6 = scan[i] + 1
|
||||
psubw m11, m7 ; m11 = scan[i] + 1
|
||||
pandn m14, m6 ; m14 = max(eob)
|
||||
pandn m13, m11 ; m13 = max(eob)
|
||||
pmaxsw m8, m14
|
||||
pmaxsw m8, m13
|
||||
add ncoeffq, mmsize
|
||||
jl .ac_only_loop
|
||||
|
||||
jmp .accumulate_eob
|
||||
.skip_iter:
|
||||
mova [r3q+ncoeffq*2+ 0], m5
|
||||
mova [r3q+ncoeffq*2+16], m5
|
||||
mova [r4q+ncoeffq*2+ 0], m5
|
||||
mova [r4q+ncoeffq*2+16], m5
|
||||
add ncoeffq, mmsize
|
||||
jl .ac_only_loop
|
||||
|
||||
.accumulate_eob:
|
||||
; horizontally accumulate/max eobs and write into [eob] memory pointer
|
||||
mov r2, eobmp
|
||||
pshufd m7, m8, 0xe
|
||||
pmaxsw m8, m7
|
||||
pshuflw m7, m8, 0xe
|
||||
pmaxsw m8, m7
|
||||
pshuflw m7, m8, 0x1
|
||||
pmaxsw m8, m7
|
||||
pextrw r6, m8, 0
|
||||
mov [r2], r6
|
||||
RET
|
||||
|
||||
; skip-block, i.e. just write all zeroes
|
||||
.blank:
|
||||
mov r0, dqcoeffmp
|
||||
movifnidn ncoeffq, ncoeffmp
|
||||
mov r2, qcoeffmp
|
||||
mov r3, eobmp
|
||||
|
||||
lea r0q, [r0q+ncoeffq*2]
|
||||
lea r2q, [r2q+ncoeffq*2]
|
||||
neg ncoeffq
|
||||
pxor m7, m7
|
||||
.blank_loop:
|
||||
mova [r0q+ncoeffq*2+ 0], m7
|
||||
mova [r0q+ncoeffq*2+16], m7
|
||||
mova [r2q+ncoeffq*2+ 0], m7
|
||||
mova [r2q+ncoeffq*2+16], m7
|
||||
add ncoeffq, mmsize
|
||||
jl .blank_loop
|
||||
mov word [r3q], 0
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM ssse3
|
||||
QUANTIZE_FP fp, 7
|
||||
QUANTIZE_FP fp_32x32, 7
|
||||
219
third_party/aom/av1/encoder/x86/av1_ssim_opt_x86_64.asm
vendored
Normal file
219
third_party/aom/av1/encoder/x86/av1_ssim_opt_x86_64.asm
vendored
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
;
|
||||
; Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
;
|
||||
; This source code is subject to the terms of the BSD 2 Clause License and
|
||||
; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
; was not distributed with this source code in the LICENSE file, you can
|
||||
; obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
; Media Patent License 1.0 was not distributed with this source code in the
|
||||
; PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
;
|
||||
|
||||
;
|
||||
|
||||
%include "aom_ports/x86_abi_support.asm"
|
||||
|
||||
; tabulate_ssim - sums sum_s,sum_r,sum_sq_s,sum_sq_r, sum_sxr
|
||||
%macro TABULATE_SSIM 0
|
||||
paddusw xmm15, xmm3 ; sum_s
|
||||
paddusw xmm14, xmm4 ; sum_r
|
||||
movdqa xmm1, xmm3
|
||||
pmaddwd xmm1, xmm1
|
||||
paddd xmm13, xmm1 ; sum_sq_s
|
||||
movdqa xmm2, xmm4
|
||||
pmaddwd xmm2, xmm2
|
||||
paddd xmm12, xmm2 ; sum_sq_r
|
||||
pmaddwd xmm3, xmm4
|
||||
paddd xmm11, xmm3 ; sum_sxr
|
||||
%endmacro
|
||||
|
||||
; Sum across the register %1 starting with q words
|
||||
%macro SUM_ACROSS_Q 1
|
||||
movdqa xmm2,%1
|
||||
punpckldq %1,xmm0
|
||||
punpckhdq xmm2,xmm0
|
||||
paddq %1,xmm2
|
||||
movdqa xmm2,%1
|
||||
punpcklqdq %1,xmm0
|
||||
punpckhqdq xmm2,xmm0
|
||||
paddq %1,xmm2
|
||||
%endmacro
|
||||
|
||||
; Sum across the register %1 starting with q words
|
||||
%macro SUM_ACROSS_W 1
|
||||
movdqa xmm1, %1
|
||||
punpcklwd %1,xmm0
|
||||
punpckhwd xmm1,xmm0
|
||||
paddd %1, xmm1
|
||||
SUM_ACROSS_Q %1
|
||||
%endmacro
|
||||
;void ssim_parms_sse2(
|
||||
; unsigned char *s,
|
||||
; int sp,
|
||||
; unsigned char *r,
|
||||
; int rp
|
||||
; unsigned long *sum_s,
|
||||
; unsigned long *sum_r,
|
||||
; unsigned long *sum_sq_s,
|
||||
; unsigned long *sum_sq_r,
|
||||
; unsigned long *sum_sxr);
|
||||
;
|
||||
; TODO: Use parm passing through structure, probably don't need the pxors
|
||||
; ( calling app will initialize to 0 ) could easily fit everything in sse2
|
||||
; without too much hastle, and can probably do better estimates with psadw
|
||||
; or pavgb At this point this is just meant to be first pass for calculating
|
||||
; all the parms needed for 16x16 ssim so we can play with dssim as distortion
|
||||
; in mode selection code.
|
||||
global sym(av1_ssim_parms_16x16_sse2) PRIVATE
|
||||
sym(av1_ssim_parms_16x16_sse2):
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
SHADOW_ARGS_TO_STACK 9
|
||||
SAVE_XMM 15
|
||||
push rsi
|
||||
push rdi
|
||||
; end prolog
|
||||
|
||||
mov rsi, arg(0) ;s
|
||||
mov rcx, arg(1) ;sp
|
||||
mov rdi, arg(2) ;r
|
||||
mov rax, arg(3) ;rp
|
||||
|
||||
pxor xmm0, xmm0
|
||||
pxor xmm15,xmm15 ;sum_s
|
||||
pxor xmm14,xmm14 ;sum_r
|
||||
pxor xmm13,xmm13 ;sum_sq_s
|
||||
pxor xmm12,xmm12 ;sum_sq_r
|
||||
pxor xmm11,xmm11 ;sum_sxr
|
||||
|
||||
mov rdx, 16 ;row counter
|
||||
.NextRow:
|
||||
|
||||
;grab source and reference pixels
|
||||
movdqu xmm5, [rsi]
|
||||
movdqu xmm6, [rdi]
|
||||
movdqa xmm3, xmm5
|
||||
movdqa xmm4, xmm6
|
||||
punpckhbw xmm3, xmm0 ; high_s
|
||||
punpckhbw xmm4, xmm0 ; high_r
|
||||
|
||||
TABULATE_SSIM
|
||||
|
||||
movdqa xmm3, xmm5
|
||||
movdqa xmm4, xmm6
|
||||
punpcklbw xmm3, xmm0 ; low_s
|
||||
punpcklbw xmm4, xmm0 ; low_r
|
||||
|
||||
TABULATE_SSIM
|
||||
|
||||
add rsi, rcx ; next s row
|
||||
add rdi, rax ; next r row
|
||||
|
||||
dec rdx ; counter
|
||||
jnz .NextRow
|
||||
|
||||
SUM_ACROSS_W xmm15
|
||||
SUM_ACROSS_W xmm14
|
||||
SUM_ACROSS_Q xmm13
|
||||
SUM_ACROSS_Q xmm12
|
||||
SUM_ACROSS_Q xmm11
|
||||
|
||||
mov rdi,arg(4)
|
||||
movd [rdi], xmm15;
|
||||
mov rdi,arg(5)
|
||||
movd [rdi], xmm14;
|
||||
mov rdi,arg(6)
|
||||
movd [rdi], xmm13;
|
||||
mov rdi,arg(7)
|
||||
movd [rdi], xmm12;
|
||||
mov rdi,arg(8)
|
||||
movd [rdi], xmm11;
|
||||
|
||||
; begin epilog
|
||||
pop rdi
|
||||
pop rsi
|
||||
RESTORE_XMM
|
||||
UNSHADOW_ARGS
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
;void ssim_parms_sse2(
|
||||
; unsigned char *s,
|
||||
; int sp,
|
||||
; unsigned char *r,
|
||||
; int rp
|
||||
; unsigned long *sum_s,
|
||||
; unsigned long *sum_r,
|
||||
; unsigned long *sum_sq_s,
|
||||
; unsigned long *sum_sq_r,
|
||||
; unsigned long *sum_sxr);
|
||||
;
|
||||
; TODO: Use parm passing through structure, probably don't need the pxors
|
||||
; ( calling app will initialize to 0 ) could easily fit everything in sse2
|
||||
; without too much hastle, and can probably do better estimates with psadw
|
||||
; or pavgb At this point this is just meant to be first pass for calculating
|
||||
; all the parms needed for 16x16 ssim so we can play with dssim as distortion
|
||||
; in mode selection code.
|
||||
global sym(av1_ssim_parms_8x8_sse2) PRIVATE
|
||||
sym(av1_ssim_parms_8x8_sse2):
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
SHADOW_ARGS_TO_STACK 9
|
||||
SAVE_XMM 15
|
||||
push rsi
|
||||
push rdi
|
||||
; end prolog
|
||||
|
||||
mov rsi, arg(0) ;s
|
||||
mov rcx, arg(1) ;sp
|
||||
mov rdi, arg(2) ;r
|
||||
mov rax, arg(3) ;rp
|
||||
|
||||
pxor xmm0, xmm0
|
||||
pxor xmm15,xmm15 ;sum_s
|
||||
pxor xmm14,xmm14 ;sum_r
|
||||
pxor xmm13,xmm13 ;sum_sq_s
|
||||
pxor xmm12,xmm12 ;sum_sq_r
|
||||
pxor xmm11,xmm11 ;sum_sxr
|
||||
|
||||
mov rdx, 8 ;row counter
|
||||
.NextRow:
|
||||
|
||||
;grab source and reference pixels
|
||||
movq xmm3, [rsi]
|
||||
movq xmm4, [rdi]
|
||||
punpcklbw xmm3, xmm0 ; low_s
|
||||
punpcklbw xmm4, xmm0 ; low_r
|
||||
|
||||
TABULATE_SSIM
|
||||
|
||||
add rsi, rcx ; next s row
|
||||
add rdi, rax ; next r row
|
||||
|
||||
dec rdx ; counter
|
||||
jnz .NextRow
|
||||
|
||||
SUM_ACROSS_W xmm15
|
||||
SUM_ACROSS_W xmm14
|
||||
SUM_ACROSS_Q xmm13
|
||||
SUM_ACROSS_Q xmm12
|
||||
SUM_ACROSS_Q xmm11
|
||||
|
||||
mov rdi,arg(4)
|
||||
movd [rdi], xmm15;
|
||||
mov rdi,arg(5)
|
||||
movd [rdi], xmm14;
|
||||
mov rdi,arg(6)
|
||||
movd [rdi], xmm13;
|
||||
mov rdi,arg(7)
|
||||
movd [rdi], xmm12;
|
||||
mov rdi,arg(8)
|
||||
movd [rdi], xmm11;
|
||||
|
||||
; begin epilog
|
||||
pop rdi
|
||||
pop rsi
|
||||
RESTORE_XMM
|
||||
UNSHADOW_ARGS
|
||||
pop rbp
|
||||
ret
|
||||
3884
third_party/aom/av1/encoder/x86/dct_intrin_sse2.c
vendored
Normal file
3884
third_party/aom/av1/encoder/x86/dct_intrin_sse2.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
87
third_party/aom/av1/encoder/x86/dct_sse2.asm
vendored
Normal file
87
third_party/aom/av1/encoder/x86/dct_sse2.asm
vendored
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
;
|
||||
; Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
;
|
||||
; This source code is subject to the terms of the BSD 2 Clause License and
|
||||
; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
; was not distributed with this source code in the LICENSE file, you can
|
||||
; obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
; Media Patent License 1.0 was not distributed with this source code in the
|
||||
; PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
;
|
||||
|
||||
%define private_prefix av1
|
||||
|
||||
%include "third_party/x86inc/x86inc.asm"
|
||||
|
||||
SECTION .text
|
||||
|
||||
%macro TRANSFORM_COLS 0
|
||||
paddw m0, m1
|
||||
movq m4, m0
|
||||
psubw m3, m2
|
||||
psubw m4, m3
|
||||
psraw m4, 1
|
||||
movq m5, m4
|
||||
psubw m5, m1 ;b1
|
||||
psubw m4, m2 ;c1
|
||||
psubw m0, m4
|
||||
paddw m3, m5
|
||||
; m0 a0
|
||||
SWAP 1, 4 ; m1 c1
|
||||
SWAP 2, 3 ; m2 d1
|
||||
SWAP 3, 5 ; m3 b1
|
||||
%endmacro
|
||||
|
||||
%macro TRANSPOSE_4X4 0
|
||||
; 00 01 02 03
|
||||
; 10 11 12 13
|
||||
; 20 21 22 23
|
||||
; 30 31 32 33
|
||||
punpcklwd m0, m1 ; 00 10 01 11 02 12 03 13
|
||||
punpcklwd m2, m3 ; 20 30 21 31 22 32 23 33
|
||||
mova m1, m0
|
||||
punpckldq m0, m2 ; 00 10 20 30 01 11 21 31
|
||||
punpckhdq m1, m2 ; 02 12 22 32 03 13 23 33
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
cglobal fwht4x4, 3, 4, 8, input, output, stride
|
||||
lea r3q, [inputq + strideq*4]
|
||||
movq m0, [inputq] ;a1
|
||||
movq m1, [inputq + strideq*2] ;b1
|
||||
movq m2, [r3q] ;c1
|
||||
movq m3, [r3q + strideq*2] ;d1
|
||||
|
||||
TRANSFORM_COLS
|
||||
TRANSPOSE_4X4
|
||||
SWAP 1, 2
|
||||
psrldq m1, m0, 8
|
||||
psrldq m3, m2, 8
|
||||
TRANSFORM_COLS
|
||||
TRANSPOSE_4X4
|
||||
|
||||
psllw m0, 2
|
||||
psllw m1, 2
|
||||
|
||||
%if CONFIG_HIGHBITDEPTH
|
||||
; sign extension
|
||||
mova m2, m0
|
||||
mova m3, m1
|
||||
punpcklwd m0, m0
|
||||
punpcklwd m1, m1
|
||||
punpckhwd m2, m2
|
||||
punpckhwd m3, m3
|
||||
psrad m0, 16
|
||||
psrad m1, 16
|
||||
psrad m2, 16
|
||||
psrad m3, 16
|
||||
mova [outputq], m0
|
||||
mova [outputq + 16], m2
|
||||
mova [outputq + 32], m1
|
||||
mova [outputq + 48], m3
|
||||
%else
|
||||
mova [outputq], m0
|
||||
mova [outputq + 16], m1
|
||||
%endif
|
||||
|
||||
RET
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue