diff options
author | Yury Gitman <yuryg@google.com> | 2016-07-18 15:44:40 -0700 |
---|---|---|
committer | Yury Gitman <yuryg@google.com> | 2016-08-25 10:55:14 -0700 |
commit | 292d221fed21a84b3a9902bcaecda00cc08e6029 (patch) | |
tree | c824981a245faa906afcaef28898e25b7a0c4f40 /vp9 | |
parent | c0180325793e7f1dcd50bf8a30dfe2ce41e6ae75 (diff) | |
download | libvpx-292d221fed21a84b3a9902bcaecda00cc08e6029.tar libvpx-292d221fed21a84b3a9902bcaecda00cc08e6029.tar.gz libvpx-292d221fed21a84b3a9902bcaecda00cc08e6029.tar.bz2 libvpx-292d221fed21a84b3a9902bcaecda00cc08e6029.zip |
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
Diffstat (limited to 'vp9')
-rw-r--r-- | vp9/encoder/vp9_alt_ref_aq.c | 61 | ||||
-rw-r--r-- | vp9/encoder/vp9_alt_ref_aq.h | 124 | ||||
-rw-r--r-- | vp9/encoder/vp9_alt_ref_aq_private.h | 35 | ||||
-rw-r--r-- | vp9/encoder/vp9_encodeframe.c | 10 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.c | 61 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.h | 5 | ||||
-rw-r--r-- | vp9/vp9cx.mk | 3 |
7 files changed, 297 insertions, 2 deletions
diff --git a/vp9/encoder/vp9_alt_ref_aq.c b/vp9/encoder/vp9_alt_ref_aq.c new file mode 100644 index 000000000..d7fbdc6f7 --- /dev/null +++ b/vp9/encoder/vp9_alt_ref_aq.c @@ -0,0 +1,61 @@ +/* + * 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; +} diff --git a/vp9/encoder/vp9_alt_ref_aq.h b/vp9/encoder/vp9_alt_ref_aq.h new file mode 100644 index 000000000..e12d7682e --- /dev/null +++ b/vp9/encoder/vp9_alt_ref_aq.h @@ -0,0 +1,124 @@ +/* + * 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_ diff --git a/vp9/encoder/vp9_alt_ref_aq_private.h b/vp9/encoder/vp9_alt_ref_aq_private.h new file mode 100644 index 000000000..31dc5f75a --- /dev/null +++ b/vp9/encoder/vp9_alt_ref_aq_private.h @@ -0,0 +1,35 @@ +/* + * 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_ diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index bd0f99eaa..93f12d203 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -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) { diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 7ecf9a446..cc5dde349 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -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; } diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index ce31ffb98..66e41492b 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -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]; diff --git a/vp9/vp9cx.mk b/vp9/vp9cx.mk index b8342b9e1..91530c444 100644 --- a/vp9/vp9cx.mk +++ b/vp9/vp9cx.mk @@ -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 |