Commit 292d221f authored by Yury Gitman's avatar Yury Gitman

Create interface for the ALT_REF_AQ class

Current commit is just an API template  for the rest of the code, and
I will add inner logic later.

Altref  frames  generate a  lot  of  bitrate  and  at the  same  time
other  frames  refer to  them  a  lot, so  it  makes  sense to  apply
special  compensation-based adaptive  quantization scheme  for altref
frames. E.g.,  for blocks  that are  good predictors  for the  future
apply rate-control  chosen quantizer  while for bad  predictors apply
worse one.

Change-Id: Iba3f8ec349470673b7249f6a125f6859336a47c8
parent c0180325
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file in the root of the source tree. An additional
* intellectual property rights grant can be found in the file PATENTS.
* All contributing project authors may be found in the AUTHORS file in
* the root of the source tree.
*/
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_alt_ref_aq_private.h"
#include "vp9/encoder/vp9_alt_ref_aq.h"
struct ALT_REF_AQ *vp9_alt_ref_aq_create() {
return (struct ALT_REF_AQ *)vpx_malloc(sizeof(struct ALT_REF_AQ));
}
void vp9_alt_ref_aq_destroy(struct ALT_REF_AQ *const self) { vpx_free(self); }
void vp9_alt_ref_aq_upload_map(struct ALT_REF_AQ *const self,
const struct MATX_8U *segmentation_map) {
(void)self;
(void)segmentation_map;
}
void vp9_alt_ref_aq_set_nsegments(struct ALT_REF_AQ *const self,
int nsegments) {
(void)self;
(void)nsegments;
}
void vp9_alt_ref_aq_setup_mode(struct ALT_REF_AQ *const self,
struct VP9_COMP *const cpi) {
(void)cpi;
(void)self;
}
// set basic segmentation to the altref's one
void vp9_alt_ref_aq_setup_map(struct ALT_REF_AQ *const self,
struct VP9_COMP *const cpi) {
(void)cpi;
(void)self;
}
// restore cpi->aq_mode
void vp9_alt_ref_aq_unset_all(struct ALT_REF_AQ *const self,
struct VP9_COMP *const cpi) {
(void)cpi;
(void)self;
}
int vp9_alt_ref_aq_disable_if(const struct ALT_REF_AQ *self,
int segmentation_overhead, int bandwidth) {
(void)bandwidth;
(void)self;
(void)segmentation_overhead;
return 0;
}
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file in the root of the source tree. An additional
* intellectual property rights grant can be found in the file PATENTS.
* All contributing project authors may be found in the AUTHORS file in
* the root of the source tree.
*/
/*
* \file vp9_alt_ref_aq.h
*
* This file contains public interface for setting up adaptive segmentation
* for altref frames. Go to alt_ref_aq_private.h for implmentation details.
*/
#ifndef VP9_ENCODER_VP9_ALT_REF_AQ_H_
#define VP9_ENCODER_VP9_ALT_REF_AQ_H_
#include "vpx/vpx_integer.h"
// Where to disable segmentation
#define ALT_REF_AQ_LOW_BITRATE_BOUNDARY 150
// Last frame always has overall quality = 0,
// so it is questionable if I can process it
#define ALT_REF_AQ_APPLY_TO_LAST_FRAME 1
// If I should try to compare gain
// against segmentation overhead
#define ALT_REF_AQ_PROTECT_GAIN 0
// Threshold to disable segmentation
#define ALT_REF_AQ_PROTECT_GAIN_THRESH 0.5
#ifdef __cplusplus
extern "C" {
#endif
// Simple structure for storing images
struct MATX_8U {
int rows;
int cols;
int stride;
uint8_t *data;
};
struct VP9_COMP;
struct ALT_REF_AQ;
/*!\brief Constructor
*
* \return Instance of the class
*/
struct ALT_REF_AQ *vp9_alt_ref_aq_create();
/*!\brief Upload segmentation_map to self object
*
* \param self Instance of the class
* \param segmentation_map Segmentation map to upload
*/
void vp9_alt_ref_aq_upload_map(struct ALT_REF_AQ *const self,
const struct MATX_8U *segmentation_map);
/*!\brief Return pointer to the altref segmentation map
*
* \param self Instance of the class
* \param segmentation_overhead Segmentation overhead in bytes
* \param bandwidth Current frame bandwidth in bytes
*
* \return Boolean value to disable segmentation
*/
int vp9_alt_ref_aq_disable_if(const struct ALT_REF_AQ *self,
int segmentation_overhead, int bandwidth);
/*!\brief Set number of segments
*
* It is used for delta quantizer computations
* and thus it can be larger than
* maximum value of the segmentation map
*
* \param self Instance of the class
* \param nsegments Maximum number of segments
*/
void vp9_alt_ref_aq_set_nsegments(struct ALT_REF_AQ *self, int nsegments);
/*!\brief Set up LOOKAHEAD_AQ segmentation mode
*
* Set up segmentation mode to LOOKAHEAD_AQ
* (expected future frames prediction
* quality refering to the current frame).
*
* \param self Instance of the class
* \param cpi Encoder context
*/
void vp9_alt_ref_aq_setup_mode(struct ALT_REF_AQ *self, struct VP9_COMP *cpi);
/*!\brief Set up LOOKAHEAD_AQ segmentation map and delta quantizers
*
* \param self Instance of the class
* \param cpi Encoder context
*/
void vp9_alt_ref_aq_setup_map(struct ALT_REF_AQ *self, struct VP9_COMP *cpi);
/*!\brief Restore main segmentation map mode and reset the class variables
*
* \param self Instance of the class
* \param cpi Encoder context
*/
void vp9_alt_ref_aq_unset_all(struct ALT_REF_AQ *self, struct VP9_COMP *cpi);
/*!\brief Destructor
*
* \param self Instance of the class
*/
void vp9_alt_ref_aq_destroy(struct ALT_REF_AQ *self);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_ALT_REF_AQ_H_
/*
* Copyright (c) 2016 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file in the root of the source tree. An additional
* intellectual property rights grant can be found in the file PATENTS.
* All contributing project authors may be found in the AUTHORS file in
* the root of the source tree.
*/
/*
* \file vp9_alt_ref_aq_private.h
*
* This file describes class used for setting up adaptive segmentation
* for altref frames. It is private file and most likely you need
* alt_ref_aq.h instead.
*/
#ifndef VP9_ENCODER_VP9_ALT_REF_AQ_PRIVATE_H_
#define VP9_ENCODER_VP9_ALT_REF_AQ_PRIVATE_H_
#include "vp9/encoder/vp9_alt_ref_aq.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ALT_REF_AQ {};
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_ALT_REF_AQ_PRIVATE_H_
......@@ -216,7 +216,7 @@ static void set_offsets(VP9_COMP *cpi, const TileInfo *const tile,
// Setup segment ID.
if (seg->enabled) {
if (cpi->oxcf.aq_mode != VARIANCE_AQ &&
if (cpi->oxcf.aq_mode != VARIANCE_AQ && cpi->oxcf.aq_mode != LOOKAHEAD_AQ &&
cpi->oxcf.aq_mode != EQUATOR360_AQ) {
const uint8_t *const map =
seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map;
......@@ -1354,6 +1354,11 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, TileDataEnc *tile_data,
mi->segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col);
}
x->rdmult = set_segment_rdmult(cpi, x, mi->segment_id);
} else if (aq_mode == LOOKAHEAD_AQ) {
const uint8_t *const map = cpi->segmentation_map;
// I do not change rdmult here consciously.
mi->segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col);
} else if (aq_mode == EQUATOR360_AQ) {
if (cm->frame_type == KEY_FRAME || cpi->force_update_segmentation) {
mi->segment_id = vp9_360aq_segment_id(mi_row, cm->mi_rows);
......@@ -2501,7 +2506,8 @@ static void rd_pick_partition(VP9_COMP *cpi, ThreadData *td,
set_offsets(cpi, tile_info, x, mi_row, mi_col, bsize);
if (bsize == BLOCK_16X16 && cpi->oxcf.aq_mode != NO_AQ)
if (bsize == BLOCK_16X16 && cpi->oxcf.aq_mode != NO_AQ &&
cpi->oxcf.aq_mode != LOOKAHEAD_AQ)
x->mb_energy = vp9_block_energy(cpi, x, bsize);
if (cpi->sf.cb_partition_search && bsize == BLOCK_16X16) {
......
......@@ -36,6 +36,7 @@
#include "vp9/common/vp9_reconintra.h"
#include "vp9/common/vp9_tile_common.h"
#include "vp9/encoder/vp9_alt_ref_aq.h"
#include "vp9/encoder/vp9_aq_360.h"
#include "vp9/encoder/vp9_aq_complexity.h"
#include "vp9/encoder/vp9_aq_cyclicrefresh.h"
......@@ -1618,6 +1619,8 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf,
cpi->use_skin_detection = 0;
cpi->common.buffer_pool = pool;
cpi->force_update_segmentation = 0;
init_config(cpi, oxcf);
vp9_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc);
......@@ -1627,6 +1630,8 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf,
realloc_segmentation_maps(cpi);
CHECK_MEM_ERROR(cm, cpi->alt_ref_aq, vp9_alt_ref_aq_create());
CHECK_MEM_ERROR(
cm, cpi->consec_zero_mv,
vpx_calloc(cm->mi_rows * cm->mi_cols, sizeof(*cpi->consec_zero_mv)));
......@@ -2024,6 +2029,8 @@ void vp9_remove_compressor(VP9_COMP *cpi) {
if (cpi->num_workers > 1) vp9_loop_filter_dealloc(&cpi->lf_row_sync);
vp9_alt_ref_aq_destroy(cpi->alt_ref_aq);
dealloc_compressor_data(cpi);
for (i = 0; i < sizeof(cpi->mbgraph_stats) / sizeof(cpi->mbgraph_stats[0]);
......@@ -3138,6 +3145,7 @@ static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
setup_frame(cpi);
suppress_active_map(cpi);
// Variance adaptive and in frame q adjustment experiments are mutually
// exclusive.
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
......@@ -3148,7 +3156,12 @@ static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
vp9_setup_in_frame_q_adj(cpi);
} else if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
vp9_cyclic_refresh_setup(cpi);
} else if (cpi->oxcf.aq_mode == LOOKAHEAD_AQ) {
// it may be pretty bad for rate-control,
// and I should handle it somehow
vp9_alt_ref_aq_setup_map(cpi->alt_ref_aq, cpi);
}
apply_active_map(cpi);
vp9_encode_frame(cpi);
......@@ -3286,6 +3299,8 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size,
vp9_360aq_frame_setup(cpi);
} else if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) {
vp9_setup_in_frame_q_adj(cpi);
} else if (cpi->oxcf.aq_mode == LOOKAHEAD_AQ) {
vp9_alt_ref_aq_setup_map(cpi->alt_ref_aq, cpi);
}
vp9_encode_frame(cpi);
......@@ -3748,6 +3763,30 @@ static void spatial_denoise_frame(VP9_COMP *cpi) {
}
#endif // ENABLE_KF_DENOISE
static void vp9_try_disable_lookahead_aq(VP9_COMP *cpi, size_t *size,
uint8_t *dest) {
if (cpi->common.seg.enabled)
if (ALT_REF_AQ_PROTECT_GAIN) {
size_t nsize = *size;
int overhead;
// TODO(yuryg): optimize this, as
// we don't really need to repack
save_coding_context(cpi);
vp9_disable_segmentation(&cpi->common.seg);
vp9_pack_bitstream(cpi, dest, &nsize);
restore_coding_context(cpi);
overhead = (int)*size - (int)nsize;
if (vp9_alt_ref_aq_disable_if(cpi->alt_ref_aq, overhead, (int)*size))
vp9_encode_frame(cpi);
else
vp9_enable_segmentation(&cpi->common.seg);
}
}
static void encode_frame_to_data_rate(VP9_COMP *cpi, size_t *size,
uint8_t *dest,
unsigned int *frame_flags) {
......@@ -3873,6 +3912,10 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, size_t *size,
encode_with_recode_loop(cpi, size, dest);
}
// Disable segmentation if it decrease rate/distortion ratio
if (cpi->oxcf.aq_mode == LOOKAHEAD_AQ)
vp9_try_disable_lookahead_aq(cpi, size, dest);
#if CONFIG_VP9_TEMPORAL_DENOISING
#ifdef OUTPUT_YUV_DENOISED
if (oxcf->noise_sensitivity > 0) {
......@@ -3996,6 +4039,11 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, size_t *size,
cpi->svc.number_temporal_layers +
cpi->svc.temporal_layer_id]
.last_frame_type = cm->frame_type;
cpi->force_update_segmentation = 0;
if (cpi->oxcf.aq_mode == LOOKAHEAD_AQ)
vp9_alt_ref_aq_unset_all(cpi->alt_ref_aq, cpi);
}
static void SvcEncode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
......@@ -4424,9 +4472,21 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
#endif
if ((oxcf->arnr_max_frames > 0) && (oxcf->arnr_strength > 0)) {
int bitrate = cpi->rc.avg_frame_bandwidth / 40;
int not_low_bitrate = bitrate > ALT_REF_AQ_LOW_BITRATE_BOUNDARY;
int not_last_frame = (cpi->lookahead->sz - arf_src_index > 1);
not_last_frame |= ALT_REF_AQ_APPLY_TO_LAST_FRAME;
// Produce the filtered ARF frame.
vp9_temporal_filter(cpi, arf_src_index);
vpx_extend_frame_borders(&cpi->alt_ref_buffer);
// for small bitrates segmentation overhead usually
// eats all bitrate gain from enabling delta quantizers
if (cpi->oxcf.alt_ref_aq != 0 && not_low_bitrate && not_last_frame)
vp9_alt_ref_aq_setup_mode(cpi->alt_ref_aq, cpi);
force_src_buffer = &cpi->alt_ref_buffer;
}
......@@ -4788,6 +4848,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
cpi->svc.spatial_layer_to_encode = 0;
}
}
vpx_clear_system_state();
return 0;
}
......
......@@ -29,6 +29,7 @@
#include "vp9/common/vp9_thread_common.h"
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/encoder/vp9_alt_ref_aq.h"
#include "vp9/encoder/vp9_aq_cyclicrefresh.h"
#include "vp9/encoder/vp9_context_tree.h"
#include "vp9/encoder/vp9_encodemb.h"
......@@ -488,6 +489,10 @@ typedef struct VP9_COMP {
YV12_BUFFER_CONFIG alt_ref_buffer;
// class responsible for adaptive
// quantization of altref frames
struct ALT_REF_AQ *alt_ref_aq;
#if CONFIG_INTERNAL_STATS
unsigned int mode_chosen_counts[MAX_MODES];
......
......@@ -81,6 +81,9 @@ VP9_CX_SRCS-yes += encoder/vp9_aq_cyclicrefresh.c
VP9_CX_SRCS-yes += encoder/vp9_aq_cyclicrefresh.h
VP9_CX_SRCS-yes += encoder/vp9_aq_complexity.c
VP9_CX_SRCS-yes += encoder/vp9_aq_complexity.h
VP9_CX_SRCS-yes += encoder/vp9_alt_ref_aq_private.h
VP9_CX_SRCS-yes += encoder/vp9_alt_ref_aq.h
VP9_CX_SRCS-yes += encoder/vp9_alt_ref_aq.c
VP9_CX_SRCS-yes += encoder/vp9_skin_detection.c
VP9_CX_SRCS-yes += encoder/vp9_skin_detection.h
VP9_CX_SRCS-yes += encoder/vp9_noise_estimate.c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment