| /* | 
 |  * Copyright (c) 2019, 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 "av1/encoder/encoder.h" | 
 | #include "av1/encoder/encoder_alloc.h" | 
 |  | 
 | static void swap_ptr(void *a, void *b) { | 
 |   void **a_p = (void **)a; | 
 |   void **b_p = (void **)b; | 
 |   void *c = *a_p; | 
 |   *a_p = *b_p; | 
 |   *b_p = c; | 
 | } | 
 |  | 
 | void av1_init_layer_context(AV1_COMP *const cpi) { | 
 |   AV1_COMMON *const cm = &cpi->common; | 
 |   const AV1EncoderConfig *const oxcf = &cpi->oxcf; | 
 |   SVC *const svc = &cpi->svc; | 
 |   int mi_rows = cpi->common.mi_params.mi_rows; | 
 |   int mi_cols = cpi->common.mi_params.mi_cols; | 
 |   svc->base_framerate = 30.0; | 
 |   svc->current_superframe = 0; | 
 |   svc->force_zero_mode_spatial_ref = 1; | 
 |   svc->num_encoded_top_layer = 0; | 
 |   svc->use_flexible_mode = 0; | 
 |   svc->has_lower_quality_layer = 0; | 
 |  | 
 |   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) { | 
 |     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) { | 
 |       int layer = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers); | 
 |       LAYER_CONTEXT *const lc = &svc->layer_context[layer]; | 
 |       RATE_CONTROL *const lrc = &lc->rc; | 
 |       PRIMARY_RATE_CONTROL *const lp_rc = &lc->p_rc; | 
 |       lrc->ni_av_qi = oxcf->rc_cfg.worst_allowed_q; | 
 |       lp_rc->total_actual_bits = 0; | 
 |       lrc->ni_tot_qi = 0; | 
 |       lp_rc->tot_q = 0.0; | 
 |       lp_rc->avg_q = 0.0; | 
 |       lp_rc->ni_frames = 0; | 
 |       lrc->decimation_count = 0; | 
 |       lrc->decimation_factor = 0; | 
 |       lrc->worst_quality = av1_quantizer_to_qindex(lc->max_q); | 
 |       lrc->best_quality = av1_quantizer_to_qindex(lc->min_q); | 
 |       lrc->rtc_external_ratectrl = 0; | 
 |       for (int i = 0; i < RATE_FACTOR_LEVELS; ++i) { | 
 |         lp_rc->rate_correction_factors[i] = 1.0; | 
 |       } | 
 |       lc->target_bandwidth = lc->layer_target_bitrate; | 
 |       lp_rc->last_q[INTER_FRAME] = lrc->worst_quality; | 
 |       lp_rc->avg_frame_qindex[INTER_FRAME] = lrc->worst_quality; | 
 |       lp_rc->avg_frame_qindex[KEY_FRAME] = lrc->worst_quality; | 
 |       lp_rc->buffer_level = | 
 |           oxcf->rc_cfg.starting_buffer_level_ms * lc->target_bandwidth / 1000; | 
 |       lp_rc->bits_off_target = lp_rc->buffer_level; | 
 |       // Initialize the cyclic refresh parameters. If spatial layers are used | 
 |       // (i.e., ss_number_layers > 1), these need to be updated per spatial | 
 |       // layer. Cyclic refresh is only applied on base temporal layer. | 
 |       if (svc->number_spatial_layers > 1 && tl == 0) { | 
 |         lc->sb_index = 0; | 
 |         lc->actual_num_seg1_blocks = 0; | 
 |         lc->actual_num_seg2_blocks = 0; | 
 |         lc->counter_encode_maxq_scene_change = 0; | 
 |         aom_free(lc->map); | 
 |         CHECK_MEM_ERROR(cm, lc->map, | 
 |                         aom_calloc(mi_rows * mi_cols, sizeof(*lc->map))); | 
 |       } | 
 |     } | 
 |     svc->downsample_filter_type[sl] = BILINEAR; | 
 |     svc->downsample_filter_phase[sl] = 8; | 
 |     svc->last_layer_dropped[sl] = false; | 
 |     svc->drop_spatial_layer[sl] = false; | 
 |   } | 
 |   if (svc->number_spatial_layers == 3) { | 
 |     svc->downsample_filter_type[0] = EIGHTTAP_SMOOTH; | 
 |   } | 
 | } | 
 |  | 
 | bool av1_alloc_layer_context(AV1_COMP *cpi, int num_layers) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   if (svc->layer_context == NULL || svc->num_allocated_layers < num_layers) { | 
 |     assert(num_layers > 1); | 
 |     aom_free(svc->layer_context); | 
 |     svc->num_allocated_layers = 0; | 
 |     svc->layer_context = | 
 |         (LAYER_CONTEXT *)aom_calloc(num_layers, sizeof(*svc->layer_context)); | 
 |     if (svc->layer_context == NULL) return false; | 
 |     svc->num_allocated_layers = num_layers; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | // Update the layer context from a change_config() call. | 
 | void av1_update_layer_context_change_config(AV1_COMP *const cpi, | 
 |                                             const int64_t target_bandwidth) { | 
 |   const RATE_CONTROL *const rc = &cpi->rc; | 
 |   const PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc; | 
 |   AV1_COMMON *const cm = &cpi->common; | 
 |   SVC *const svc = &cpi->svc; | 
 |   int layer = 0; | 
 |   int64_t spatial_layer_target = 0; | 
 |   float bitrate_alloc = 1.0; | 
 |   const int mi_rows = cm->mi_params.mi_rows; | 
 |   const int mi_cols = cm->mi_params.mi_cols; | 
 |   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) { | 
 |     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) { | 
 |       layer = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers); | 
 |       LAYER_CONTEXT *const lc = &svc->layer_context[layer]; | 
 |       svc->layer_context[layer].target_bandwidth = lc->layer_target_bitrate; | 
 |     } | 
 |     spatial_layer_target = svc->layer_context[layer].target_bandwidth; | 
 |     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) { | 
 |       LAYER_CONTEXT *const lc = | 
 |           &svc->layer_context[sl * svc->number_temporal_layers + tl]; | 
 |       RATE_CONTROL *const lrc = &lc->rc; | 
 |       PRIMARY_RATE_CONTROL *const lp_rc = &lc->p_rc; | 
 |       lc->spatial_layer_target_bandwidth = spatial_layer_target; | 
 |       if (target_bandwidth != 0) { | 
 |         bitrate_alloc = (float)lc->target_bandwidth / target_bandwidth; | 
 |       } | 
 |       lp_rc->starting_buffer_level = | 
 |           (int64_t)(p_rc->starting_buffer_level * bitrate_alloc); | 
 |       lp_rc->optimal_buffer_level = | 
 |           (int64_t)(p_rc->optimal_buffer_level * bitrate_alloc); | 
 |       lp_rc->maximum_buffer_size = | 
 |           (int64_t)(p_rc->maximum_buffer_size * bitrate_alloc); | 
 |       lp_rc->bits_off_target = | 
 |           AOMMIN(lp_rc->bits_off_target, lp_rc->maximum_buffer_size); | 
 |       lp_rc->buffer_level = | 
 |           AOMMIN(lp_rc->buffer_level, lp_rc->maximum_buffer_size); | 
 |       lc->framerate = cpi->framerate / lc->framerate_factor; | 
 |       lrc->avg_frame_bandwidth = | 
 |           (int)round(lc->target_bandwidth / lc->framerate); | 
 |       lrc->max_frame_bandwidth = rc->max_frame_bandwidth; | 
 |       lrc->rtc_external_ratectrl = rc->rtc_external_ratectrl; | 
 |       lrc->worst_quality = av1_quantizer_to_qindex(lc->max_q); | 
 |       lrc->best_quality = av1_quantizer_to_qindex(lc->min_q); | 
 |       if (rc->use_external_qp_one_pass) { | 
 |         lrc->worst_quality = rc->worst_quality; | 
 |         lrc->best_quality = rc->best_quality; | 
 |       } | 
 |       // Reset the cyclic refresh parameters, if needed (map is NULL), | 
 |       // or number of spatial layers has changed. | 
 |       // Cyclic refresh is only applied on base temporal layer. | 
 |       if (svc->number_spatial_layers > 1 && tl == 0 && | 
 |           (lc->map == NULL || | 
 |            svc->prev_number_spatial_layers != svc->number_spatial_layers)) { | 
 |         lc->sb_index = 0; | 
 |         lc->actual_num_seg1_blocks = 0; | 
 |         lc->actual_num_seg2_blocks = 0; | 
 |         lc->counter_encode_maxq_scene_change = 0; | 
 |         aom_free(lc->map); | 
 |         CHECK_MEM_ERROR(cm, lc->map, | 
 |                         aom_calloc(mi_rows * mi_cols, sizeof(*lc->map))); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /*!\brief Return layer context for current layer. | 
 |  * | 
 |  * \ingroup rate_control | 
 |  * \param[in]       cpi   Top level encoder structure | 
 |  * | 
 |  * \return LAYER_CONTEXT for current layer. | 
 |  */ | 
 | static LAYER_CONTEXT *get_layer_context(AV1_COMP *const cpi) { | 
 |   return &cpi->svc.layer_context[cpi->svc.spatial_layer_id * | 
 |                                      cpi->svc.number_temporal_layers + | 
 |                                  cpi->svc.temporal_layer_id]; | 
 | } | 
 |  | 
 | void av1_update_temporal_layer_framerate(AV1_COMP *const cpi) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   LAYER_CONTEXT *const lc = get_layer_context(cpi); | 
 |   RATE_CONTROL *const lrc = &lc->rc; | 
 |   const int tl = svc->temporal_layer_id; | 
 |   lc->framerate = cpi->framerate / lc->framerate_factor; | 
 |   lrc->avg_frame_bandwidth = | 
 |       saturate_cast_double_to_int(round(lc->target_bandwidth / lc->framerate)); | 
 |   lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth; | 
 |   // Update the average layer frame size (non-cumulative per-frame-bw). | 
 |   if (tl == 0) { | 
 |     lc->avg_frame_size = lrc->avg_frame_bandwidth; | 
 |   } else { | 
 |     int prev_layer = svc->spatial_layer_id * svc->number_temporal_layers + | 
 |                      svc->temporal_layer_id - 1; | 
 |     LAYER_CONTEXT *const lcprev = &svc->layer_context[prev_layer]; | 
 |     const double prev_layer_framerate = | 
 |         cpi->framerate / lcprev->framerate_factor; | 
 |     const int64_t prev_layer_target_bandwidth = lcprev->layer_target_bitrate; | 
 |     if (lc->framerate > prev_layer_framerate) { | 
 |       lc->avg_frame_size = | 
 |           (int)round((lc->target_bandwidth - prev_layer_target_bandwidth) / | 
 |                      (lc->framerate - prev_layer_framerate)); | 
 |     } else { | 
 |       lc->avg_frame_size = (int)round(lc->target_bandwidth / lc->framerate); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | bool av1_check_ref_is_low_spatial_res_super_frame(AV1_COMP *const cpi, | 
 |                                                   int ref_frame) { | 
 |   SVC *svc = &cpi->svc; | 
 |   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref; | 
 |   int ref_frame_idx = rtc_ref->ref_idx[ref_frame - 1]; | 
 |   return rtc_ref->buffer_time_index[ref_frame_idx] == svc->current_superframe && | 
 |          rtc_ref->buffer_spatial_layer[ref_frame_idx] <= | 
 |              svc->spatial_layer_id - 1; | 
 | } | 
 |  | 
 | void av1_restore_layer_context(AV1_COMP *const cpi) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref; | 
 |   const AV1_COMMON *const cm = &cpi->common; | 
 |   LAYER_CONTEXT *const lc = get_layer_context(cpi); | 
 |   const int old_frame_since_key = cpi->rc.frames_since_key; | 
 |   const int old_frame_to_key = cpi->rc.frames_to_key; | 
 |   const int frames_since_scene_change = cpi->rc.frames_since_scene_change; | 
 |   const int last_encoded_size_keyframe = cpi->rc.last_encoded_size_keyframe; | 
 |   const int last_target_size_keyframe = cpi->rc.last_target_size_keyframe; | 
 |   const int max_consec_drop = cpi->rc.max_consec_drop; | 
 |   const int postencode_drop = cpi->rc.postencode_drop; | 
 |   const int static_since_last_scene_change = | 
 |       cpi->rc.static_since_last_scene_change; | 
 |   // Restore layer rate control. | 
 |   cpi->rc = lc->rc; | 
 |   cpi->ppi->p_rc = lc->p_rc; | 
 |   cpi->oxcf.rc_cfg.target_bandwidth = lc->target_bandwidth; | 
 |   cpi->gf_frame_index = 0; | 
 |   cpi->mv_search_params.max_mv_magnitude = lc->max_mv_magnitude; | 
 |   if (cpi->mv_search_params.max_mv_magnitude == 0) | 
 |     cpi->mv_search_params.max_mv_magnitude = AOMMAX(cm->width, cm->height); | 
 |   // Reset the following parameters to their values before | 
 |   // the layer restore. Keep these defined for the stream (not layer). | 
 |   cpi->rc.frames_since_key = old_frame_since_key; | 
 |   cpi->rc.frames_to_key = old_frame_to_key; | 
 |   cpi->rc.frames_since_scene_change = frames_since_scene_change; | 
 |   cpi->rc.last_encoded_size_keyframe = last_encoded_size_keyframe; | 
 |   cpi->rc.last_target_size_keyframe = last_target_size_keyframe; | 
 |   cpi->rc.max_consec_drop = max_consec_drop; | 
 |   cpi->rc.postencode_drop = postencode_drop; | 
 |   cpi->rc.static_since_last_scene_change = static_since_last_scene_change; | 
 |   // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers, | 
 |   // for the base temporal layer. | 
 |   if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && | 
 |       svc->number_spatial_layers > 1 && svc->temporal_layer_id == 0) { | 
 |     CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; | 
 |     swap_ptr(&cr->map, &lc->map); | 
 |     cr->sb_index = lc->sb_index; | 
 |     cr->actual_num_seg1_blocks = lc->actual_num_seg1_blocks; | 
 |     cr->actual_num_seg2_blocks = lc->actual_num_seg2_blocks; | 
 |     cr->counter_encode_maxq_scene_change = lc->counter_encode_maxq_scene_change; | 
 |   } | 
 |   svc->skip_mvsearch_last = 0; | 
 |   svc->skip_mvsearch_gf = 0; | 
 |   svc->skip_mvsearch_altref = 0; | 
 |   // For each reference (LAST/GOLDEN) set the skip_mvsearch_last/gf frame flags. | 
 |   // This is to skip searching mv for that reference if it was last | 
 |   // refreshed (i.e., buffer slot holding that reference was refreshed) on the | 
 |   // previous spatial layer(s) at the same time (current_superframe). | 
 |   if (rtc_ref->set_ref_frame_config && svc->force_zero_mode_spatial_ref && | 
 |       cpi->sf.rt_sf.use_nonrd_pick_mode) { | 
 |     if (av1_check_ref_is_low_spatial_res_super_frame(cpi, LAST_FRAME)) { | 
 |       svc->skip_mvsearch_last = 1; | 
 |     } | 
 |     if (av1_check_ref_is_low_spatial_res_super_frame(cpi, GOLDEN_FRAME)) { | 
 |       svc->skip_mvsearch_gf = 1; | 
 |     } | 
 |     if (av1_check_ref_is_low_spatial_res_super_frame(cpi, ALTREF_FRAME)) { | 
 |       svc->skip_mvsearch_altref = 1; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void av1_svc_update_buffer_slot_refreshed(AV1_COMP *const cpi) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref; | 
 |   const unsigned int current_frame = | 
 |       cpi->ppi->use_svc ? svc->current_superframe | 
 |                         : cpi->common.current_frame.frame_number; | 
 |   // For any buffer slot that is refreshed, update it with | 
 |   // the spatial_layer_id and the current_superframe. | 
 |   if (cpi->common.current_frame.frame_type == KEY_FRAME) { | 
 |     // All slots are refreshed on KEY. | 
 |     for (unsigned int i = 0; i < REF_FRAMES; i++) { | 
 |       rtc_ref->buffer_time_index[i] = current_frame; | 
 |       rtc_ref->buffer_spatial_layer[i] = svc->spatial_layer_id; | 
 |     } | 
 |   } else if (rtc_ref->set_ref_frame_config) { | 
 |     for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) { | 
 |       const int ref_frame_map_idx = rtc_ref->ref_idx[i]; | 
 |       if (rtc_ref->refresh[ref_frame_map_idx]) { | 
 |         rtc_ref->buffer_time_index[ref_frame_map_idx] = current_frame; | 
 |         rtc_ref->buffer_spatial_layer[ref_frame_map_idx] = | 
 |             svc->spatial_layer_id; | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void av1_save_layer_context(AV1_COMP *const cpi) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   const AV1_COMMON *const cm = &cpi->common; | 
 |   LAYER_CONTEXT *lc = get_layer_context(cpi); | 
 |   lc->rc = cpi->rc; | 
 |   lc->p_rc = cpi->ppi->p_rc; | 
 |   lc->target_bandwidth = (int)cpi->oxcf.rc_cfg.target_bandwidth; | 
 |   lc->group_index = cpi->gf_frame_index; | 
 |   lc->max_mv_magnitude = cpi->mv_search_params.max_mv_magnitude; | 
 |   if (svc->spatial_layer_id == 0) svc->base_framerate = cpi->framerate; | 
 |   // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers, | 
 |   // for the base temporal layer. | 
 |   if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && | 
 |       cpi->svc.number_spatial_layers > 1 && svc->temporal_layer_id == 0) { | 
 |     CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; | 
 |     signed char *temp = lc->map; | 
 |     lc->map = cr->map; | 
 |     cr->map = temp; | 
 |     lc->sb_index = cr->sb_index; | 
 |     lc->actual_num_seg1_blocks = cr->actual_num_seg1_blocks; | 
 |     lc->actual_num_seg2_blocks = cr->actual_num_seg2_blocks; | 
 |     lc->counter_encode_maxq_scene_change = cr->counter_encode_maxq_scene_change; | 
 |   } | 
 |   if (!cpi->is_dropped_frame) { | 
 |     av1_svc_update_buffer_slot_refreshed(cpi); | 
 |     for (unsigned int i = 0; i < REF_FRAMES; i++) { | 
 |       if (frame_is_intra_only(cm) || | 
 |           cm->current_frame.refresh_frame_flags & (1 << i)) { | 
 |         svc->spatial_layer_fb[i] = svc->spatial_layer_id; | 
 |         svc->temporal_layer_fb[i] = svc->temporal_layer_id; | 
 |       } | 
 |     } | 
 |   } | 
 |   if (svc->spatial_layer_id == svc->number_spatial_layers - 1) { | 
 |     svc->current_superframe++; | 
 |     // Reset drop flag to false for next superframe. | 
 |     for (int sl = 0; sl < svc->number_spatial_layers; sl++) | 
 |       svc->drop_spatial_layer[sl] = false; | 
 |   } | 
 | } | 
 |  | 
 | int av1_svc_primary_ref_frame(const AV1_COMP *const cpi) { | 
 |   const SVC *const svc = &cpi->svc; | 
 |   const AV1_COMMON *const cm = &cpi->common; | 
 |   int fb_idx = -1; | 
 |   int primary_ref_frame = PRIMARY_REF_NONE; | 
 |   if (cpi->svc.number_spatial_layers > 1 || | 
 |       cpi->svc.number_temporal_layers > 1) { | 
 |     // Set the primary_ref_frame to LAST_FRAME if that buffer slot for LAST | 
 |     // was last updated on a lower temporal layer (or base TL0) and for the | 
 |     // same spatial layer. For RTC patterns this allows for continued decoding | 
 |     // when set of enhancement layers are dropped (continued decoding starting | 
 |     // at next base TL0), so error_resilience can be off/0 for all layers. | 
 |     fb_idx = get_ref_frame_map_idx(cm, LAST_FRAME); | 
 |     if (cpi->ppi->rtc_ref.reference[0] == 1 && | 
 |         svc->spatial_layer_fb[fb_idx] == svc->spatial_layer_id && | 
 |         (svc->temporal_layer_fb[fb_idx] < svc->temporal_layer_id || | 
 |          svc->temporal_layer_fb[fb_idx] == 0)) { | 
 |       primary_ref_frame = 0;  // LAST_FRAME: ref_frame - LAST_FRAME | 
 |     } | 
 |   } else if (cpi->ppi->rtc_ref.set_ref_frame_config) { | 
 |     const ExternalFlags *const ext_flags = &cpi->ext_flags; | 
 |     int flags = ext_flags->ref_frame_flags; | 
 |     if (flags & AOM_LAST_FLAG) { | 
 |       primary_ref_frame = 0;  // LAST_FRAME: ref_frame - LAST_FRAME | 
 |     } else if (flags & AOM_GOLD_FLAG) { | 
 |       primary_ref_frame = GOLDEN_FRAME - LAST_FRAME; | 
 |     } else if (flags & AOM_ALT_FLAG) { | 
 |       primary_ref_frame = ALTREF_FRAME - LAST_FRAME; | 
 |     } | 
 |   } | 
 |   return primary_ref_frame; | 
 | } | 
 |  | 
 | void av1_free_svc_cyclic_refresh(AV1_COMP *const cpi) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) { | 
 |     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) { | 
 |       int layer = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers); | 
 |       LAYER_CONTEXT *const lc = &svc->layer_context[layer]; | 
 |       aom_free(lc->map); | 
 |       lc->map = NULL; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void av1_svc_reset_temporal_layers(AV1_COMP *const cpi, int is_key) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   LAYER_CONTEXT *lc = NULL; | 
 |   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) { | 
 |     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) { | 
 |       lc = &cpi->svc.layer_context[sl * svc->number_temporal_layers + tl]; | 
 |       if (is_key) lc->frames_from_key_frame = 0; | 
 |     } | 
 |   } | 
 |   av1_update_temporal_layer_framerate(cpi); | 
 |   av1_restore_layer_context(cpi); | 
 | } | 
 |  | 
 | void av1_get_layer_resolution(const int width_org, const int height_org, | 
 |                               const int num, const int den, int *width_out, | 
 |                               int *height_out) { | 
 |   int w, h; | 
 |   if (width_out == NULL || height_out == NULL || den == 0) return; | 
 |   if (den == 1 && num == 1) { | 
 |     *width_out = width_org; | 
 |     *height_out = height_org; | 
 |     return; | 
 |   } | 
 |   w = width_org * num / den; | 
 |   h = height_org * num / den; | 
 |   // Make height and width even. | 
 |   w += w % 2; | 
 |   h += h % 2; | 
 |   *width_out = w; | 
 |   *height_out = h; | 
 | } | 
 |  | 
 | void av1_one_pass_cbr_svc_start_layer(AV1_COMP *const cpi) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   AV1_COMMON *const cm = &cpi->common; | 
 |   LAYER_CONTEXT *lc = NULL; | 
 |   int width = 0, height = 0; | 
 |   lc = &svc->layer_context[svc->spatial_layer_id * svc->number_temporal_layers + | 
 |                            svc->temporal_layer_id]; | 
 |   // Set the lower quality layer flag. | 
 |   svc->has_lower_quality_layer = 0; | 
 |   if (cpi->svc.spatial_layer_id > 0) { | 
 |     const LAYER_CONTEXT *lc_prev = | 
 |         &svc->layer_context[(svc->spatial_layer_id - 1) * | 
 |                                 svc->number_temporal_layers + | 
 |                             svc->temporal_layer_id]; | 
 |     if (lc_prev->scaling_factor_den == 1 && lc_prev->scaling_factor_num == 1) | 
 |       svc->has_lower_quality_layer = 1; | 
 |   } | 
 |   av1_get_layer_resolution(cpi->oxcf.frm_dim_cfg.width, | 
 |                            cpi->oxcf.frm_dim_cfg.height, lc->scaling_factor_num, | 
 |                            lc->scaling_factor_den, &width, &height); | 
 |   // Use Eightap_smooth for low resolutions. | 
 |   if (width * height <= 320 * 240) | 
 |     svc->downsample_filter_type[svc->spatial_layer_id] = EIGHTTAP_SMOOTH; | 
 |  | 
 |   cm->width = width; | 
 |   cm->height = height; | 
 |   alloc_mb_mode_info_buffers(cpi); | 
 |   av1_update_frame_size(cpi); | 
 |   if (svc->spatial_layer_id == svc->number_spatial_layers - 1) { | 
 |     svc->mi_cols_full_resoln = cm->mi_params.mi_cols; | 
 |     svc->mi_rows_full_resoln = cm->mi_params.mi_rows; | 
 |   } | 
 | } | 
 |  | 
 | enum { | 
 |   SVC_LAST_FRAME = 0, | 
 |   SVC_LAST2_FRAME, | 
 |   SVC_LAST3_FRAME, | 
 |   SVC_GOLDEN_FRAME, | 
 |   SVC_BWDREF_FRAME, | 
 |   SVC_ALTREF2_FRAME, | 
 |   SVC_ALTREF_FRAME | 
 | }; | 
 |  | 
 | // For fixed svc mode: fixed pattern is set based on the number of | 
 | // spatial and temporal layers, and the ksvc_fixed_mode. | 
 | void av1_set_svc_fixed_mode(AV1_COMP *const cpi) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref; | 
 |   int i; | 
 |   assert(svc->use_flexible_mode == 0); | 
 |   assert(svc->number_spatial_layers >= 1 && svc->number_temporal_layers >= 1); | 
 |   // Fixed SVC mode only supports at most 3 spatial or temporal layers. | 
 |   if (svc->number_spatial_layers > 3 || svc->number_temporal_layers > 3) { | 
 |     aom_internal_error(&cpi->ppi->error, AOM_CODEC_INVALID_PARAM, | 
 |                        "Invalid number of spatial/temporal layers for fixed " | 
 |                        "SVC mode (max: 3)"); | 
 |   } | 
 |   rtc_ref->set_ref_frame_config = 1; | 
 |   int superframe_cnt = svc->current_superframe; | 
 |   // Set the reference map buffer idx for the 7 references: | 
 |   // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3), | 
 |   // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6). | 
 |   for (i = 0; i < INTER_REFS_PER_FRAME; i++) { | 
 |     rtc_ref->reference[i] = 0; | 
 |     rtc_ref->ref_idx[i] = i; | 
 |   } | 
 |   for (i = 0; i < REF_FRAMES; i++) rtc_ref->refresh[i] = 0; | 
 |   // Always reference LAST, and reference GOLDEN on SL > 0. | 
 |   // For KSVC: GOLDEN reference will be removed on INTER_FRAMES later | 
 |   // when frame_type is set. | 
 |   rtc_ref->reference[SVC_LAST_FRAME] = 1; | 
 |   if (svc->spatial_layer_id > 0) rtc_ref->reference[SVC_GOLDEN_FRAME] = 1; | 
 |   if (svc->temporal_layer_id == 0) { | 
 |     // Base temporal layer. | 
 |     if (svc->spatial_layer_id == 0) { | 
 |       // Set all buffer_idx to 0. Update slot 0 (LAST). | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0; | 
 |       rtc_ref->refresh[0] = 1; | 
 |     } else if (svc->spatial_layer_id == 1) { | 
 |       // Set buffer_idx for LAST to slot 1, GOLDEN (and all other refs) to | 
 |       // slot 0. Update slot 1 (LAST). | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 1; | 
 |       rtc_ref->refresh[1] = 1; | 
 |     } else if (svc->spatial_layer_id == 2) { | 
 |       // Set buffer_idx for LAST to slot 2, GOLDEN (and all other refs) to | 
 |       // slot 1. Update slot 2 (LAST). | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 1; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 2; | 
 |       rtc_ref->refresh[2] = 1; | 
 |     } | 
 |   } else if (svc->temporal_layer_id == 2 && (superframe_cnt - 1) % 4 == 0) { | 
 |     // First top temporal enhancement layer. | 
 |     if (svc->spatial_layer_id == 0) { | 
 |       // Reference LAST (slot 0). | 
 |       // Set GOLDEN to slot 3 and update slot 3. | 
 |       // Set all other buffer_idx to slot 0. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0; | 
 |       if (svc->spatial_layer_id < svc->number_spatial_layers - 1) { | 
 |         rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 3; | 
 |         rtc_ref->refresh[3] = 1; | 
 |       } | 
 |     } else if (svc->spatial_layer_id == 1) { | 
 |       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1, | 
 |       // GOLDEN (and all other refs) to slot 3. | 
 |       // Set LAST2 to slot 4 and Update slot 4. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 3; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 1; | 
 |       if (svc->spatial_layer_id < svc->number_spatial_layers - 1) { | 
 |         rtc_ref->ref_idx[SVC_LAST2_FRAME] = 4; | 
 |         rtc_ref->refresh[4] = 1; | 
 |       } | 
 |     } else if (svc->spatial_layer_id == 2) { | 
 |       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2, | 
 |       // GOLDEN (and all other refs) to slot 4. | 
 |       // No update. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 4; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 2; | 
 |     } | 
 |   } else if (svc->temporal_layer_id == 1) { | 
 |     // Middle temporal enhancement layer. | 
 |     if (svc->spatial_layer_id == 0) { | 
 |       // Reference LAST. | 
 |       // Set all buffer_idx to 0. | 
 |       // Set GOLDEN to slot 5 and update slot 5. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0; | 
 |       if (svc->temporal_layer_id < svc->number_temporal_layers - 1 || | 
 |           svc->spatial_layer_id < svc->number_spatial_layers - 1) { | 
 |         rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 5; | 
 |         rtc_ref->refresh[5] = 1; | 
 |       } | 
 |     } else if (svc->spatial_layer_id == 1) { | 
 |       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1, | 
 |       // GOLDEN (and all other refs) to slot 5. | 
 |       // Set LAST3 to slot 6 and update slot 6. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 5; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 1; | 
 |       if (svc->temporal_layer_id < svc->number_temporal_layers - 1 || | 
 |           svc->spatial_layer_id < svc->number_spatial_layers - 1) { | 
 |         rtc_ref->ref_idx[SVC_LAST3_FRAME] = 6; | 
 |         rtc_ref->refresh[6] = 1; | 
 |       } | 
 |     } else if (svc->spatial_layer_id == 2) { | 
 |       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2, | 
 |       // GOLDEN (and all other refs) to slot 6. | 
 |       // Set LAST3 to slot 7 and update slot 7. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 6; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 2; | 
 |       if (svc->temporal_layer_id < svc->number_temporal_layers - 1) { | 
 |         rtc_ref->ref_idx[SVC_LAST3_FRAME] = 7; | 
 |         rtc_ref->refresh[7] = 1; | 
 |       } | 
 |     } | 
 |   } else if (svc->temporal_layer_id == 2 && (superframe_cnt - 3) % 4 == 0) { | 
 |     // Second top temporal enhancement layer. | 
 |     if (svc->spatial_layer_id == 0) { | 
 |       // Set LAST to slot 5 and reference LAST. | 
 |       // Set GOLDEN to slot 3 and update slot 3. | 
 |       // Set all other buffer_idx to 0. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 5; | 
 |       if (svc->spatial_layer_id < svc->number_spatial_layers - 1) { | 
 |         rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 3; | 
 |         rtc_ref->refresh[3] = 1; | 
 |       } | 
 |     } else if (svc->spatial_layer_id == 1) { | 
 |       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 6, | 
 |       // GOLDEN to slot 3. Set LAST2 to slot 4 and update slot 4. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 6; | 
 |       rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 3; | 
 |       if (svc->spatial_layer_id < svc->number_spatial_layers - 1) { | 
 |         rtc_ref->ref_idx[SVC_LAST2_FRAME] = 4; | 
 |         rtc_ref->refresh[4] = 1; | 
 |       } | 
 |     } else if (svc->spatial_layer_id == 2) { | 
 |       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 7, | 
 |       // GOLDEN to slot 4. No update. | 
 |       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0; | 
 |       rtc_ref->ref_idx[SVC_LAST_FRAME] = 7; | 
 |       rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 4; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void av1_svc_check_reset_layer_rc_flag(AV1_COMP *const cpi) { | 
 |   SVC *const svc = &cpi->svc; | 
 |   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) { | 
 |     // Check for reset based on avg_frame_bandwidth for spatial layer sl. | 
 |     // If avg_frame_bandwidth for top temporal layer is not set | 
 |     // (because enhancement layer was inactive), use the base TL0 | 
 |     int layer = LAYER_IDS_TO_IDX(sl, svc->number_temporal_layers - 1, | 
 |                                  svc->number_temporal_layers); | 
 |     LAYER_CONTEXT *lc = &svc->layer_context[layer]; | 
 |     RATE_CONTROL *lrc = &lc->rc; | 
 |     int avg_frame_bandwidth = lrc->avg_frame_bandwidth; | 
 |     int prev_avg_frame_bandwidth = lrc->prev_avg_frame_bandwidth; | 
 |     if (avg_frame_bandwidth == 0 || prev_avg_frame_bandwidth == 0) { | 
 |       // Use base TL0. | 
 |       layer = LAYER_IDS_TO_IDX(sl, 0, svc->number_temporal_layers); | 
 |       lc = &svc->layer_context[layer]; | 
 |       lrc = &lc->rc; | 
 |       avg_frame_bandwidth = lrc->avg_frame_bandwidth; | 
 |       prev_avg_frame_bandwidth = lrc->prev_avg_frame_bandwidth; | 
 |     } | 
 |     if (avg_frame_bandwidth / 3 > (prev_avg_frame_bandwidth >> 1) || | 
 |         avg_frame_bandwidth < (prev_avg_frame_bandwidth >> 1)) { | 
 |       // Reset for all temporal layers with spatial layer sl. | 
 |       for (int tl = 0; tl < svc->number_temporal_layers; ++tl) { | 
 |         int layer2 = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers); | 
 |         LAYER_CONTEXT *lc2 = &svc->layer_context[layer2]; | 
 |         RATE_CONTROL *lrc2 = &lc2->rc; | 
 |         PRIMARY_RATE_CONTROL *lp_rc2 = &lc2->p_rc; | 
 |         PRIMARY_RATE_CONTROL *const lp_rc = &lc2->p_rc; | 
 |         lrc2->rc_1_frame = 0; | 
 |         lrc2->rc_2_frame = 0; | 
 |         lp_rc2->bits_off_target = lp_rc->optimal_buffer_level; | 
 |         lp_rc2->buffer_level = lp_rc->optimal_buffer_level; | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void av1_svc_set_last_source(AV1_COMP *const cpi, EncodeFrameInput *frame_input, | 
 |                              YV12_BUFFER_CONFIG *prev_source) { | 
 |   frame_input->last_source = prev_source != NULL ? prev_source : NULL; | 
 |   if (!cpi->ppi->use_svc && cpi->rc.prev_frame_is_dropped && | 
 |       cpi->rc.frame_number_encoded > 0) { | 
 |     frame_input->last_source = &cpi->svc.source_last_TL0; | 
 |   } else { | 
 |     RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref; | 
 |     if (cpi->svc.spatial_layer_id == 0) { | 
 |       // For base spatial layer: if the LAST reference (index 0) is not | 
 |       // the previous (super)frame set the last_source to the source | 
 |       // corresponding to the last TL0, otherwise keep it at prev_source. | 
 |       // Always use source_last_TL0 if previous base TL0 was dropped. | 
 |       if (cpi->svc.current_superframe > 0) { | 
 |         const int buffslot_last = rtc_ref->ref_idx[0]; | 
 |         // Check if previous frame was dropped on base TL0 layer. | 
 |         const int layer = | 
 |             LAYER_IDS_TO_IDX(0, 0, cpi->svc.number_temporal_layers); | 
 |         LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer]; | 
 |         RATE_CONTROL *lrc = &lc->rc; | 
 |         if (lrc->prev_frame_is_dropped || | 
 |             rtc_ref->buffer_time_index[buffslot_last] < | 
 |                 cpi->svc.current_superframe - 1) { | 
 |           frame_input->last_source = &cpi->svc.source_last_TL0; | 
 |         } | 
 |       } | 
 |     } else if (cpi->svc.spatial_layer_id > 0) { | 
 |       // For spatial enhancement layers: the previous source (prev_source) | 
 |       // corresponds to the lower spatial layer (which is the same source so | 
 |       // we can't use that), so always set the last_source to the source of the | 
 |       // last TL0. | 
 |       if (cpi->svc.current_superframe > 0) | 
 |         frame_input->last_source = &cpi->svc.source_last_TL0; | 
 |       else | 
 |         frame_input->last_source = NULL; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | int av1_svc_get_min_ref_dist(const AV1_COMP *cpi) { | 
 |   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref; | 
 |   int min_dist = INT_MAX; | 
 |   const unsigned int current_frame_num = | 
 |       cpi->ppi->use_svc ? cpi->svc.current_superframe | 
 |                         : cpi->common.current_frame.frame_number; | 
 |   for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) { | 
 |     if (rtc_ref->reference[i]) { | 
 |       const int ref_frame_map_idx = rtc_ref->ref_idx[i]; | 
 |       const int dist = (1 + current_frame_num) - | 
 |                        rtc_ref->buffer_time_index[ref_frame_map_idx]; | 
 |       if (dist < min_dist) min_dist = dist; | 
 |     } | 
 |   } | 
 |   return min_dist; | 
 | } | 
 |  | 
 | void av1_svc_set_reference_was_previous(AV1_COMP *cpi) { | 
 |   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref; | 
 |   // Check if the encoded frame had some reference that was the | 
 |   // previous frame. | 
 |   const unsigned int current_frame = | 
 |       cpi->ppi->use_svc ? cpi->svc.current_superframe | 
 |                         : cpi->common.current_frame.frame_number; | 
 |   rtc_ref->reference_was_previous_frame = true; | 
 |   if (current_frame > 0) { | 
 |     rtc_ref->reference_was_previous_frame = false; | 
 |     for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) { | 
 |       if (rtc_ref->reference[i]) { | 
 |         const int ref_frame_map_idx = rtc_ref->ref_idx[i]; | 
 |         if (rtc_ref->buffer_time_index[ref_frame_map_idx] == current_frame - 1) | 
 |           rtc_ref->reference_was_previous_frame = true; | 
 |       } | 
 |     } | 
 |   } | 
 | } |