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:
trav90 2018-10-15 21:45:30 -05:00 • committed by Roy Tam
commit edc8d83307
989 changed files with 470949 additions and 0 deletions

View 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;
}
}
}

View 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_

View 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;
}

View 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_

View 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);
}

View 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_

View 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);
}

View 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);
}

View 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

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

53
third_party/aom/av1/encoder/bitstream.h vendored Normal file
View 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
View 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
View 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;
}

View 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;
}

View 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_ */

View 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;
}

View 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_

View 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;
}

View 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
View 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
View 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_

View 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

File diff suppressed because it is too large Load diff

51
third_party/aom/av1/encoder/encint.h vendored Normal file
View 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

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

92
third_party/aom/av1/encoder/encodemb.h vendored Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

883
third_party/aom/av1/encoder/encoder.h vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

202
third_party/aom/av1/encoder/firstpass.h vendored Normal file
View 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_

View 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);
}

View 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;
}

View 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_

View 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

View 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_

View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

163
third_party/aom/av1/encoder/mcomp.h vendored Normal file
View 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_

View 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;
}

View 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;
}
}

View 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);
}

View 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);
}

View 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_

View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

30
third_party/aom/av1/encoder/pickrst.h vendored Normal file
View 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_

View 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;
}

View 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

File diff suppressed because it is too large Load diff

44
third_party/aom/av1/encoder/ransac.h vendored Normal file
View 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

File diff suppressed because it is too large Load diff

284
third_party/aom/av1/encoder/ratectrl.h vendored Normal file
View 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_

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

505
third_party/aom/av1/encoder/rd.h vendored Normal file
View 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

File diff suppressed because it is too large Load diff

142
third_party/aom/av1/encoder/rdopt.h vendored Normal file
View 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_

View 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);
}

View 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_

View 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;
}

View 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
View 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
View 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_

View 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);
}

View 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
View 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
View 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_

View 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);
}

View 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_

View 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;
}

View 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_ */

View 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);
}

View 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;
}
}

View 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;
}
}

View 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

View 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

File diff suppressed because it is too large Load diff

View 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