|  | /* | 
|  | * Copyright (c) 2021, 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/ratectrl_rtc.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <new> | 
|  |  | 
|  | #include "aom/aomcx.h" | 
|  | #include "aom/aom_encoder.h" | 
|  | #include "aom_mem/aom_mem.h" | 
|  | #include "av1/encoder/encoder.h" | 
|  | #include "av1/encoder/encoder_utils.h" | 
|  | #include "av1/encoder/pickcdef.h" | 
|  | #include "av1/encoder/picklpf.h" | 
|  | #include "av1/encoder/ratectrl.h" | 
|  | #include "av1/encoder/rc_utils.h" | 
|  | #include "av1/encoder/svc_layercontext.h" | 
|  |  | 
|  | namespace aom { | 
|  |  | 
|  | AV1RateControlRtcConfig::AV1RateControlRtcConfig() { | 
|  | width = 1280; | 
|  | height = 720; | 
|  | max_quantizer = 63; | 
|  | min_quantizer = 2; | 
|  | target_bandwidth = 1000; | 
|  | buf_initial_sz = 600; | 
|  | buf_optimal_sz = 600; | 
|  | buf_sz = 1000; | 
|  | undershoot_pct = overshoot_pct = 50; | 
|  | max_intra_bitrate_pct = 50; | 
|  | max_inter_bitrate_pct = 0; | 
|  | frame_drop_thresh = 0; | 
|  | max_consec_drop = 0; | 
|  | framerate = 30.0; | 
|  | ss_number_layers = 1; | 
|  | ts_number_layers = 1; | 
|  | aq_mode = 0; | 
|  | layer_target_bitrate[0] = static_cast<int>(target_bandwidth); | 
|  | ts_rate_decimator[0] = 1; | 
|  | av1_zero(max_quantizers); | 
|  | av1_zero(min_quantizers); | 
|  | av1_zero(scaling_factor_den); | 
|  | av1_zero(scaling_factor_num); | 
|  | av1_zero(layer_target_bitrate); | 
|  | av1_zero(ts_rate_decimator); | 
|  | scaling_factor_num[0] = 1; | 
|  | scaling_factor_den[0] = 1; | 
|  | max_quantizers[0] = max_quantizer; | 
|  | min_quantizers[0] = min_quantizer; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<AV1RateControlRTC> AV1RateControlRTC::Create( | 
|  | const AV1RateControlRtcConfig &cfg) { | 
|  | std::unique_ptr<AV1RateControlRTC> rc_api(new (std::nothrow) | 
|  | AV1RateControlRTC()); | 
|  | if (!rc_api) return nullptr; | 
|  | rc_api->cpi_ = static_cast<AV1_COMP *>(aom_memalign(32, sizeof(*cpi_))); | 
|  | if (!rc_api->cpi_) return nullptr; | 
|  | av1_zero(*rc_api->cpi_); | 
|  | rc_api->cpi_->ppi = | 
|  | static_cast<AV1_PRIMARY *>(aom_memalign(32, sizeof(AV1_PRIMARY))); | 
|  | if (!rc_api->cpi_->ppi) return nullptr; | 
|  | av1_zero(*rc_api->cpi_->ppi); | 
|  | rc_api->cpi_->common.seq_params = &rc_api->cpi_->ppi->seq_params; | 
|  | av1_zero(*rc_api->cpi_->common.seq_params); | 
|  | if (!rc_api->InitRateControl(cfg)) return nullptr; | 
|  | if (cfg.aq_mode) { | 
|  | AV1_COMP *const cpi = rc_api->cpi_; | 
|  | cpi->enc_seg.map = static_cast<uint8_t *>(aom_calloc( | 
|  | cpi->common.mi_params.mi_rows * cpi->common.mi_params.mi_cols, | 
|  | sizeof(*cpi->enc_seg.map))); | 
|  | if (!cpi->enc_seg.map) return nullptr; | 
|  | cpi->cyclic_refresh = av1_cyclic_refresh_alloc( | 
|  | cpi->common.mi_params.mi_rows, cpi->common.mi_params.mi_cols); | 
|  | if (!cpi->cyclic_refresh) return nullptr; | 
|  | } | 
|  | return rc_api; | 
|  | } | 
|  |  | 
|  | AV1RateControlRTC::~AV1RateControlRTC() { | 
|  | if (cpi_) { | 
|  | if (cpi_->svc.number_spatial_layers > 1 || | 
|  | cpi_->svc.number_temporal_layers > 1) { | 
|  | for (int sl = 0; sl < cpi_->svc.number_spatial_layers; sl++) { | 
|  | for (int tl = 0; tl < cpi_->svc.number_temporal_layers; tl++) { | 
|  | int layer = | 
|  | LAYER_IDS_TO_IDX(sl, tl, cpi_->svc.number_temporal_layers); | 
|  | LAYER_CONTEXT *const lc = &cpi_->svc.layer_context[layer]; | 
|  | aom_free(lc->map); | 
|  | } | 
|  | } | 
|  | } | 
|  | aom_free(cpi_->svc.layer_context); | 
|  | cpi_->svc.layer_context = nullptr; | 
|  |  | 
|  | if (cpi_->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ) { | 
|  | aom_free(cpi_->enc_seg.map); | 
|  | cpi_->enc_seg.map = nullptr; | 
|  | av1_cyclic_refresh_free(cpi_->cyclic_refresh); | 
|  | } | 
|  | aom_free(cpi_->ppi); | 
|  | aom_free(cpi_); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool AV1RateControlRTC::InitRateControl(const AV1RateControlRtcConfig &rc_cfg) { | 
|  | AV1_COMMON *cm = &cpi_->common; | 
|  | AV1EncoderConfig *oxcf = &cpi_->oxcf; | 
|  | RATE_CONTROL *const rc = &cpi_->rc; | 
|  | cm->seq_params->profile = PROFILE_0; | 
|  | cm->seq_params->bit_depth = AOM_BITS_8; | 
|  | cm->show_frame = 1; | 
|  | oxcf->profile = cm->seq_params->profile; | 
|  | oxcf->mode = REALTIME; | 
|  | oxcf->rc_cfg.mode = AOM_CBR; | 
|  | oxcf->pass = AOM_RC_ONE_PASS; | 
|  | oxcf->q_cfg.aq_mode = rc_cfg.aq_mode ? CYCLIC_REFRESH_AQ : NO_AQ; | 
|  | oxcf->tune_cfg.content = AOM_CONTENT_DEFAULT; | 
|  | oxcf->rc_cfg.drop_frames_water_mark = rc_cfg.frame_drop_thresh; | 
|  | rc->max_consec_drop = rc_cfg.max_consec_drop; | 
|  | cpi_->svc.framedrop_mode = AOM_FULL_SUPERFRAME_DROP; | 
|  | oxcf->tool_cfg.bit_depth = AOM_BITS_8; | 
|  | oxcf->tool_cfg.superblock_size = AOM_SUPERBLOCK_SIZE_DYNAMIC; | 
|  | oxcf->algo_cfg.loopfilter_control = LOOPFILTER_ALL; | 
|  | cm->current_frame.frame_number = 0; | 
|  | cpi_->ppi->p_rc.kf_boost = DEFAULT_KF_BOOST_RT; | 
|  | for (auto &lvl_idx : oxcf->target_seq_level_idx) lvl_idx = SEQ_LEVEL_MAX; | 
|  |  | 
|  | memcpy(cpi_->ppi->level_params.target_seq_level_idx, | 
|  | oxcf->target_seq_level_idx, sizeof(oxcf->target_seq_level_idx)); | 
|  | if (!UpdateRateControl(rc_cfg)) return false; | 
|  | set_sb_size(cm->seq_params, | 
|  | av1_select_sb_size(oxcf, cm->width, cm->height, | 
|  | cpi_->svc.number_spatial_layers)); | 
|  | cpi_->ppi->use_svc = cpi_->svc.number_spatial_layers > 1 || | 
|  | cpi_->svc.number_temporal_layers > 1; | 
|  | av1_primary_rc_init(oxcf, &cpi_->ppi->p_rc); | 
|  | rc->rc_1_frame = 0; | 
|  | rc->rc_2_frame = 0; | 
|  | av1_rc_init_minq_luts(); | 
|  | av1_rc_init(oxcf, rc); | 
|  | // Enable external rate control. | 
|  | cpi_->rc.rtc_external_ratectrl = 1; | 
|  | cpi_->sf.rt_sf.use_nonrd_pick_mode = 1; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool AV1RateControlRTC::UpdateRateControl( | 
|  | const AV1RateControlRtcConfig &rc_cfg) { | 
|  | if (rc_cfg.ss_number_layers < 1 || | 
|  | rc_cfg.ss_number_layers > AOM_MAX_SS_LAYERS || | 
|  | rc_cfg.ts_number_layers < 1 || | 
|  | rc_cfg.ts_number_layers > AOM_MAX_TS_LAYERS) { | 
|  | return false; | 
|  | } | 
|  | const int num_layers = rc_cfg.ss_number_layers * rc_cfg.ts_number_layers; | 
|  | if (num_layers > 1 && !av1_alloc_layer_context(cpi_, num_layers)) { | 
|  | return false; | 
|  | } | 
|  | AV1_COMMON *cm = &cpi_->common; | 
|  | AV1EncoderConfig *oxcf = &cpi_->oxcf; | 
|  | RATE_CONTROL *const rc = &cpi_->rc; | 
|  | initial_width_ = rc_cfg.width; | 
|  | initial_height_ = rc_cfg.height; | 
|  | cm->width = rc_cfg.width; | 
|  | cm->height = rc_cfg.height; | 
|  | oxcf->frm_dim_cfg.width = rc_cfg.width; | 
|  | oxcf->frm_dim_cfg.height = rc_cfg.height; | 
|  | oxcf->rc_cfg.worst_allowed_q = av1_quantizer_to_qindex(rc_cfg.max_quantizer); | 
|  | oxcf->rc_cfg.best_allowed_q = av1_quantizer_to_qindex(rc_cfg.min_quantizer); | 
|  | rc->worst_quality = oxcf->rc_cfg.worst_allowed_q; | 
|  | rc->best_quality = oxcf->rc_cfg.best_allowed_q; | 
|  | oxcf->input_cfg.init_framerate = rc_cfg.framerate; | 
|  | oxcf->rc_cfg.target_bandwidth = rc_cfg.target_bandwidth > INT64_MAX / 1000 | 
|  | ? INT64_MAX | 
|  | : 1000 * rc_cfg.target_bandwidth; | 
|  | oxcf->rc_cfg.starting_buffer_level_ms = rc_cfg.buf_initial_sz; | 
|  | oxcf->rc_cfg.optimal_buffer_level_ms = rc_cfg.buf_optimal_sz; | 
|  | oxcf->rc_cfg.maximum_buffer_size_ms = rc_cfg.buf_sz; | 
|  | oxcf->rc_cfg.under_shoot_pct = rc_cfg.undershoot_pct; | 
|  | oxcf->rc_cfg.over_shoot_pct = rc_cfg.overshoot_pct; | 
|  | oxcf->rc_cfg.drop_frames_water_mark = rc_cfg.frame_drop_thresh; | 
|  | rc->max_consec_drop = rc_cfg.max_consec_drop; | 
|  | oxcf->rc_cfg.max_intra_bitrate_pct = rc_cfg.max_intra_bitrate_pct; | 
|  | oxcf->rc_cfg.max_inter_bitrate_pct = rc_cfg.max_inter_bitrate_pct; | 
|  | cpi_->framerate = rc_cfg.framerate; | 
|  | if (rc_cfg.is_screen) { | 
|  | cpi_->oxcf.tune_cfg.content = AOM_CONTENT_SCREEN; | 
|  | cpi_->is_screen_content_type = 1; | 
|  | } | 
|  | cpi_->svc.number_spatial_layers = rc_cfg.ss_number_layers; | 
|  | cpi_->svc.number_temporal_layers = rc_cfg.ts_number_layers; | 
|  | set_primary_rc_buffer_sizes(oxcf, cpi_->ppi); | 
|  | enc_set_mb_mi(&cm->mi_params, cm->width, cm->height, BLOCK_8X8); | 
|  | av1_new_framerate(cpi_, cpi_->framerate); | 
|  | if (cpi_->svc.number_temporal_layers > 1 || | 
|  | cpi_->svc.number_spatial_layers > 1) { | 
|  | int64_t target_bandwidth_svc = 0; | 
|  | for (int sl = 0; sl < cpi_->svc.number_spatial_layers; ++sl) { | 
|  | for (int tl = 0; tl < cpi_->svc.number_temporal_layers; ++tl) { | 
|  | const int layer = | 
|  | LAYER_IDS_TO_IDX(sl, tl, cpi_->svc.number_temporal_layers); | 
|  | LAYER_CONTEXT *lc = &cpi_->svc.layer_context[layer]; | 
|  | RATE_CONTROL *const lrc = &lc->rc; | 
|  | lc->layer_target_bitrate = 1000 * rc_cfg.layer_target_bitrate[layer]; | 
|  | lc->max_q = rc_cfg.max_quantizers[layer]; | 
|  | lc->min_q = rc_cfg.min_quantizers[layer]; | 
|  | lrc->worst_quality = | 
|  | av1_quantizer_to_qindex(rc_cfg.max_quantizers[layer]); | 
|  | lrc->best_quality = | 
|  | av1_quantizer_to_qindex(rc_cfg.min_quantizers[layer]); | 
|  | lc->scaling_factor_num = rc_cfg.scaling_factor_num[sl]; | 
|  | lc->scaling_factor_den = rc_cfg.scaling_factor_den[sl]; | 
|  | lc->framerate_factor = rc_cfg.ts_rate_decimator[tl]; | 
|  | if (tl == cpi_->svc.number_temporal_layers - 1) | 
|  | target_bandwidth_svc += lc->layer_target_bitrate; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (cm->current_frame.frame_number == 0) av1_init_layer_context(cpi_); | 
|  | // This is needed to initialize external RC flag in layer context structure. | 
|  | cpi_->rc.rtc_external_ratectrl = 1; | 
|  | av1_update_layer_context_change_config(cpi_, target_bandwidth_svc); | 
|  | } | 
|  | check_reset_rc_flag(cpi_); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | FrameDropDecision AV1RateControlRTC::ComputeQP( | 
|  | const AV1FrameParamsRTC &frame_params) { | 
|  | AV1_COMMON *const cm = &cpi_->common; | 
|  | int width, height; | 
|  | GF_GROUP *const gf_group = &cpi_->ppi->gf_group; | 
|  | cpi_->svc.spatial_layer_id = frame_params.spatial_layer_id; | 
|  | cpi_->svc.temporal_layer_id = frame_params.temporal_layer_id; | 
|  | if (cpi_->svc.number_spatial_layers > 1) { | 
|  | const int layer = LAYER_IDS_TO_IDX(cpi_->svc.spatial_layer_id, | 
|  | cpi_->svc.temporal_layer_id, | 
|  | cpi_->svc.number_temporal_layers); | 
|  | LAYER_CONTEXT *lc = &cpi_->svc.layer_context[layer]; | 
|  | av1_get_layer_resolution(initial_width_, initial_height_, | 
|  | lc->scaling_factor_num, lc->scaling_factor_den, | 
|  | &width, &height); | 
|  | cm->width = width; | 
|  | cm->height = height; | 
|  | } | 
|  | enc_set_mb_mi(&cm->mi_params, cm->width, cm->height, BLOCK_8X8); | 
|  | cm->current_frame.frame_type = frame_params.frame_type; | 
|  | cpi_->refresh_frame.golden_frame = | 
|  | (cm->current_frame.frame_type == KEY_FRAME) ? 1 : 0; | 
|  | cpi_->sf.rt_sf.use_nonrd_pick_mode = 1; | 
|  |  | 
|  | if (frame_params.frame_type == kKeyFrame) { | 
|  | gf_group->update_type[cpi_->gf_frame_index] = KF_UPDATE; | 
|  | gf_group->frame_type[cpi_->gf_frame_index] = KEY_FRAME; | 
|  | gf_group->refbuf_state[cpi_->gf_frame_index] = REFBUF_RESET; | 
|  | if (cpi_->ppi->use_svc) { | 
|  | const int layer = LAYER_IDS_TO_IDX(cpi_->svc.spatial_layer_id, | 
|  | cpi_->svc.temporal_layer_id, | 
|  | cpi_->svc.number_temporal_layers); | 
|  | if (cm->current_frame.frame_number > 0) | 
|  | av1_svc_reset_temporal_layers(cpi_, 1); | 
|  | cpi_->svc.layer_context[layer].is_key_frame = 1; | 
|  | } | 
|  | } else { | 
|  | gf_group->update_type[cpi_->gf_frame_index] = LF_UPDATE; | 
|  | gf_group->frame_type[cpi_->gf_frame_index] = INTER_FRAME; | 
|  | gf_group->refbuf_state[cpi_->gf_frame_index] = REFBUF_UPDATE; | 
|  | if (cpi_->ppi->use_svc) { | 
|  | const int layer = LAYER_IDS_TO_IDX(cpi_->svc.spatial_layer_id, | 
|  | cpi_->svc.temporal_layer_id, | 
|  | cpi_->svc.number_temporal_layers); | 
|  | cpi_->svc.layer_context[layer].is_key_frame = 0; | 
|  | } | 
|  | } | 
|  | if (cpi_->svc.spatial_layer_id == cpi_->svc.number_spatial_layers - 1) | 
|  | cpi_->rc.frames_since_key++; | 
|  | if (cpi_->svc.number_spatial_layers > 1 || | 
|  | cpi_->svc.number_temporal_layers > 1) { | 
|  | av1_update_temporal_layer_framerate(cpi_); | 
|  | av1_restore_layer_context(cpi_); | 
|  | } | 
|  | int target = 0; | 
|  | if (cpi_->oxcf.rc_cfg.mode == AOM_CBR) { | 
|  | if (cpi_->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ) | 
|  | av1_cyclic_refresh_update_parameters(cpi_); | 
|  | if (frame_is_intra_only(cm)) { | 
|  | target = av1_calc_iframe_target_size_one_pass_cbr(cpi_); | 
|  | cpi_->common.current_frame.frame_number = 0; | 
|  | } else { | 
|  | target = av1_calc_pframe_target_size_one_pass_cbr( | 
|  | cpi_, gf_group->update_type[cpi_->gf_frame_index]); | 
|  | } | 
|  | } | 
|  | av1_rc_set_frame_target(cpi_, target, cm->width, cm->height); | 
|  | // Always drop for spatial enhancement layer if layer bandwidth is 0. | 
|  | // Otherwise check for frame-dropping based on buffer level in | 
|  | // av1_rc_drop_frame(). | 
|  | if ((cpi_->svc.spatial_layer_id > 0 && | 
|  | cpi_->oxcf.rc_cfg.target_bandwidth == 0) || | 
|  | av1_rc_drop_frame(cpi_)) { | 
|  | cpi_->is_dropped_frame = true; | 
|  | av1_rc_postencode_update_drop_frame(cpi_); | 
|  | cpi_->frame_index_set.show_frame_count++; | 
|  | cpi_->common.current_frame.frame_number++; | 
|  | return FrameDropDecision::kDrop; | 
|  | } | 
|  | int bottom_index = 0, top_index = 0; | 
|  | cpi_->common.quant_params.base_qindex = | 
|  | av1_rc_pick_q_and_bounds(cpi_, cm->width, cm->height, | 
|  | cpi_->gf_frame_index, &bottom_index, &top_index); | 
|  | if (cpi_->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ) | 
|  | av1_cyclic_refresh_setup(cpi_); | 
|  | return FrameDropDecision::kOk; | 
|  | } | 
|  |  | 
|  | int AV1RateControlRTC::GetQP() const { | 
|  | return cpi_->common.quant_params.base_qindex; | 
|  | } | 
|  |  | 
|  | AV1LoopfilterLevel AV1RateControlRTC::GetLoopfilterLevel() const { | 
|  | av1_pick_filter_level(nullptr, cpi_, LPF_PICK_FROM_Q); | 
|  | AV1LoopfilterLevel lpf_level; | 
|  | lpf_level.filter_level[0] = cpi_->common.lf.filter_level[0]; | 
|  | lpf_level.filter_level[1] = cpi_->common.lf.filter_level[1]; | 
|  | lpf_level.filter_level_u = cpi_->common.lf.filter_level_u; | 
|  | lpf_level.filter_level_v = cpi_->common.lf.filter_level_v; | 
|  |  | 
|  | return lpf_level; | 
|  | } | 
|  |  | 
|  | AV1CdefInfo AV1RateControlRTC::GetCdefInfo() const { | 
|  | av1_pick_cdef_from_qp(&cpi_->common, 0, 0); | 
|  | AV1CdefInfo cdef_level; | 
|  | cdef_level.cdef_strength_y = cpi_->common.cdef_info.cdef_strengths[0]; | 
|  | cdef_level.cdef_strength_uv = cpi_->common.cdef_info.cdef_uv_strengths[0]; | 
|  | cdef_level.damping = cpi_->common.cdef_info.cdef_damping; | 
|  |  | 
|  | return cdef_level; | 
|  | } | 
|  |  | 
|  | bool AV1RateControlRTC::GetSegmentationData( | 
|  | AV1SegmentationData *segmentation_data) const { | 
|  | if (cpi_->oxcf.q_cfg.aq_mode == 0) { | 
|  | return false; | 
|  | } | 
|  | segmentation_data->segmentation_map = cpi_->enc_seg.map; | 
|  | segmentation_data->segmentation_map_size = | 
|  | cpi_->common.mi_params.mi_rows * cpi_->common.mi_params.mi_cols; | 
|  | segmentation_data->delta_q = cpi_->cyclic_refresh->qindex_delta; | 
|  | segmentation_data->delta_q_size = 3u; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void AV1RateControlRTC::PostEncodeUpdate(uint64_t encoded_frame_size) { | 
|  | cpi_->common.current_frame.frame_number++; | 
|  | if (cpi_->svc.spatial_layer_id == cpi_->svc.number_spatial_layers - 1) | 
|  | cpi_->svc.prev_number_spatial_layers = cpi_->svc.number_spatial_layers; | 
|  | av1_rc_postencode_update(cpi_, encoded_frame_size); | 
|  | if (cpi_->svc.number_spatial_layers > 1 || | 
|  | cpi_->svc.number_temporal_layers > 1) | 
|  | av1_save_layer_context(cpi_); | 
|  | } | 
|  |  | 
|  | }  // namespace aom |