xref: /aosp_15_r20/external/libaom/av1/encoder/svc_layercontext.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2019, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker #include <assert.h>
13*77c1e3ccSAndroid Build Coastguard Worker #include <math.h>
14*77c1e3ccSAndroid Build Coastguard Worker 
15*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder.h"
16*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder_alloc.h"
17*77c1e3ccSAndroid Build Coastguard Worker 
swap_ptr(void * a,void * b)18*77c1e3ccSAndroid Build Coastguard Worker static void swap_ptr(void *a, void *b) {
19*77c1e3ccSAndroid Build Coastguard Worker   void **a_p = (void **)a;
20*77c1e3ccSAndroid Build Coastguard Worker   void **b_p = (void **)b;
21*77c1e3ccSAndroid Build Coastguard Worker   void *c = *a_p;
22*77c1e3ccSAndroid Build Coastguard Worker   *a_p = *b_p;
23*77c1e3ccSAndroid Build Coastguard Worker   *b_p = c;
24*77c1e3ccSAndroid Build Coastguard Worker }
25*77c1e3ccSAndroid Build Coastguard Worker 
av1_init_layer_context(AV1_COMP * const cpi)26*77c1e3ccSAndroid Build Coastguard Worker void av1_init_layer_context(AV1_COMP *const cpi) {
27*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
28*77c1e3ccSAndroid Build Coastguard Worker   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
29*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
30*77c1e3ccSAndroid Build Coastguard Worker   int mi_rows = cpi->common.mi_params.mi_rows;
31*77c1e3ccSAndroid Build Coastguard Worker   int mi_cols = cpi->common.mi_params.mi_cols;
32*77c1e3ccSAndroid Build Coastguard Worker   svc->base_framerate = 30.0;
33*77c1e3ccSAndroid Build Coastguard Worker   svc->current_superframe = 0;
34*77c1e3ccSAndroid Build Coastguard Worker   svc->force_zero_mode_spatial_ref = 1;
35*77c1e3ccSAndroid Build Coastguard Worker   svc->num_encoded_top_layer = 0;
36*77c1e3ccSAndroid Build Coastguard Worker   svc->use_flexible_mode = 0;
37*77c1e3ccSAndroid Build Coastguard Worker   svc->has_lower_quality_layer = 0;
38*77c1e3ccSAndroid Build Coastguard Worker 
39*77c1e3ccSAndroid Build Coastguard Worker   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) {
40*77c1e3ccSAndroid Build Coastguard Worker     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
41*77c1e3ccSAndroid Build Coastguard Worker       int layer = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers);
42*77c1e3ccSAndroid Build Coastguard Worker       LAYER_CONTEXT *const lc = &svc->layer_context[layer];
43*77c1e3ccSAndroid Build Coastguard Worker       RATE_CONTROL *const lrc = &lc->rc;
44*77c1e3ccSAndroid Build Coastguard Worker       PRIMARY_RATE_CONTROL *const lp_rc = &lc->p_rc;
45*77c1e3ccSAndroid Build Coastguard Worker       lrc->ni_av_qi = oxcf->rc_cfg.worst_allowed_q;
46*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->total_actual_bits = 0;
47*77c1e3ccSAndroid Build Coastguard Worker       lrc->ni_tot_qi = 0;
48*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->tot_q = 0.0;
49*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->avg_q = 0.0;
50*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->ni_frames = 0;
51*77c1e3ccSAndroid Build Coastguard Worker       lrc->decimation_count = 0;
52*77c1e3ccSAndroid Build Coastguard Worker       lrc->decimation_factor = 0;
53*77c1e3ccSAndroid Build Coastguard Worker       lrc->worst_quality = av1_quantizer_to_qindex(lc->max_q);
54*77c1e3ccSAndroid Build Coastguard Worker       lrc->best_quality = av1_quantizer_to_qindex(lc->min_q);
55*77c1e3ccSAndroid Build Coastguard Worker       lrc->rtc_external_ratectrl = 0;
56*77c1e3ccSAndroid Build Coastguard Worker       for (int i = 0; i < RATE_FACTOR_LEVELS; ++i) {
57*77c1e3ccSAndroid Build Coastguard Worker         lp_rc->rate_correction_factors[i] = 1.0;
58*77c1e3ccSAndroid Build Coastguard Worker       }
59*77c1e3ccSAndroid Build Coastguard Worker       lc->target_bandwidth = lc->layer_target_bitrate;
60*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->last_q[INTER_FRAME] = lrc->worst_quality;
61*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->avg_frame_qindex[INTER_FRAME] = lrc->worst_quality;
62*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->avg_frame_qindex[KEY_FRAME] = lrc->worst_quality;
63*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->buffer_level =
64*77c1e3ccSAndroid Build Coastguard Worker           oxcf->rc_cfg.starting_buffer_level_ms * lc->target_bandwidth / 1000;
65*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->bits_off_target = lp_rc->buffer_level;
66*77c1e3ccSAndroid Build Coastguard Worker       // Initialize the cyclic refresh parameters. If spatial layers are used
67*77c1e3ccSAndroid Build Coastguard Worker       // (i.e., ss_number_layers > 1), these need to be updated per spatial
68*77c1e3ccSAndroid Build Coastguard Worker       // layer. Cyclic refresh is only applied on base temporal layer.
69*77c1e3ccSAndroid Build Coastguard Worker       if (svc->number_spatial_layers > 1 && tl == 0) {
70*77c1e3ccSAndroid Build Coastguard Worker         lc->sb_index = 0;
71*77c1e3ccSAndroid Build Coastguard Worker         lc->actual_num_seg1_blocks = 0;
72*77c1e3ccSAndroid Build Coastguard Worker         lc->actual_num_seg2_blocks = 0;
73*77c1e3ccSAndroid Build Coastguard Worker         lc->counter_encode_maxq_scene_change = 0;
74*77c1e3ccSAndroid Build Coastguard Worker         aom_free(lc->map);
75*77c1e3ccSAndroid Build Coastguard Worker         CHECK_MEM_ERROR(cm, lc->map,
76*77c1e3ccSAndroid Build Coastguard Worker                         aom_calloc(mi_rows * mi_cols, sizeof(*lc->map)));
77*77c1e3ccSAndroid Build Coastguard Worker       }
78*77c1e3ccSAndroid Build Coastguard Worker     }
79*77c1e3ccSAndroid Build Coastguard Worker     svc->downsample_filter_type[sl] = BILINEAR;
80*77c1e3ccSAndroid Build Coastguard Worker     svc->downsample_filter_phase[sl] = 8;
81*77c1e3ccSAndroid Build Coastguard Worker     svc->last_layer_dropped[sl] = false;
82*77c1e3ccSAndroid Build Coastguard Worker     svc->drop_spatial_layer[sl] = false;
83*77c1e3ccSAndroid Build Coastguard Worker   }
84*77c1e3ccSAndroid Build Coastguard Worker   if (svc->number_spatial_layers == 3) {
85*77c1e3ccSAndroid Build Coastguard Worker     svc->downsample_filter_type[0] = EIGHTTAP_SMOOTH;
86*77c1e3ccSAndroid Build Coastguard Worker   }
87*77c1e3ccSAndroid Build Coastguard Worker }
88*77c1e3ccSAndroid Build Coastguard Worker 
av1_alloc_layer_context(AV1_COMP * cpi,int num_layers)89*77c1e3ccSAndroid Build Coastguard Worker bool av1_alloc_layer_context(AV1_COMP *cpi, int num_layers) {
90*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
91*77c1e3ccSAndroid Build Coastguard Worker   if (svc->layer_context == NULL || svc->num_allocated_layers < num_layers) {
92*77c1e3ccSAndroid Build Coastguard Worker     assert(num_layers > 1);
93*77c1e3ccSAndroid Build Coastguard Worker     aom_free(svc->layer_context);
94*77c1e3ccSAndroid Build Coastguard Worker     svc->num_allocated_layers = 0;
95*77c1e3ccSAndroid Build Coastguard Worker     svc->layer_context =
96*77c1e3ccSAndroid Build Coastguard Worker         (LAYER_CONTEXT *)aom_calloc(num_layers, sizeof(*svc->layer_context));
97*77c1e3ccSAndroid Build Coastguard Worker     if (svc->layer_context == NULL) return false;
98*77c1e3ccSAndroid Build Coastguard Worker     svc->num_allocated_layers = num_layers;
99*77c1e3ccSAndroid Build Coastguard Worker   }
100*77c1e3ccSAndroid Build Coastguard Worker   return true;
101*77c1e3ccSAndroid Build Coastguard Worker }
102*77c1e3ccSAndroid Build Coastguard Worker 
103*77c1e3ccSAndroid Build Coastguard Worker // Update the layer context from a change_config() call.
av1_update_layer_context_change_config(AV1_COMP * const cpi,const int64_t target_bandwidth)104*77c1e3ccSAndroid Build Coastguard Worker void av1_update_layer_context_change_config(AV1_COMP *const cpi,
105*77c1e3ccSAndroid Build Coastguard Worker                                             const int64_t target_bandwidth) {
106*77c1e3ccSAndroid Build Coastguard Worker   const RATE_CONTROL *const rc = &cpi->rc;
107*77c1e3ccSAndroid Build Coastguard Worker   const PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
108*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
109*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
110*77c1e3ccSAndroid Build Coastguard Worker   int layer = 0;
111*77c1e3ccSAndroid Build Coastguard Worker   int64_t spatial_layer_target = 0;
112*77c1e3ccSAndroid Build Coastguard Worker   float bitrate_alloc = 1.0;
113*77c1e3ccSAndroid Build Coastguard Worker   const int mi_rows = cm->mi_params.mi_rows;
114*77c1e3ccSAndroid Build Coastguard Worker   const int mi_cols = cm->mi_params.mi_cols;
115*77c1e3ccSAndroid Build Coastguard Worker   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) {
116*77c1e3ccSAndroid Build Coastguard Worker     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
117*77c1e3ccSAndroid Build Coastguard Worker       layer = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers);
118*77c1e3ccSAndroid Build Coastguard Worker       LAYER_CONTEXT *const lc = &svc->layer_context[layer];
119*77c1e3ccSAndroid Build Coastguard Worker       svc->layer_context[layer].target_bandwidth = lc->layer_target_bitrate;
120*77c1e3ccSAndroid Build Coastguard Worker     }
121*77c1e3ccSAndroid Build Coastguard Worker     spatial_layer_target = svc->layer_context[layer].target_bandwidth;
122*77c1e3ccSAndroid Build Coastguard Worker     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
123*77c1e3ccSAndroid Build Coastguard Worker       LAYER_CONTEXT *const lc =
124*77c1e3ccSAndroid Build Coastguard Worker           &svc->layer_context[sl * svc->number_temporal_layers + tl];
125*77c1e3ccSAndroid Build Coastguard Worker       RATE_CONTROL *const lrc = &lc->rc;
126*77c1e3ccSAndroid Build Coastguard Worker       PRIMARY_RATE_CONTROL *const lp_rc = &lc->p_rc;
127*77c1e3ccSAndroid Build Coastguard Worker       lc->spatial_layer_target_bandwidth = spatial_layer_target;
128*77c1e3ccSAndroid Build Coastguard Worker       if (target_bandwidth != 0) {
129*77c1e3ccSAndroid Build Coastguard Worker         bitrate_alloc = (float)lc->target_bandwidth / target_bandwidth;
130*77c1e3ccSAndroid Build Coastguard Worker       }
131*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->starting_buffer_level =
132*77c1e3ccSAndroid Build Coastguard Worker           (int64_t)(p_rc->starting_buffer_level * bitrate_alloc);
133*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->optimal_buffer_level =
134*77c1e3ccSAndroid Build Coastguard Worker           (int64_t)(p_rc->optimal_buffer_level * bitrate_alloc);
135*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->maximum_buffer_size =
136*77c1e3ccSAndroid Build Coastguard Worker           (int64_t)(p_rc->maximum_buffer_size * bitrate_alloc);
137*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->bits_off_target =
138*77c1e3ccSAndroid Build Coastguard Worker           AOMMIN(lp_rc->bits_off_target, lp_rc->maximum_buffer_size);
139*77c1e3ccSAndroid Build Coastguard Worker       lp_rc->buffer_level =
140*77c1e3ccSAndroid Build Coastguard Worker           AOMMIN(lp_rc->buffer_level, lp_rc->maximum_buffer_size);
141*77c1e3ccSAndroid Build Coastguard Worker       lc->framerate = cpi->framerate / lc->framerate_factor;
142*77c1e3ccSAndroid Build Coastguard Worker       lrc->avg_frame_bandwidth =
143*77c1e3ccSAndroid Build Coastguard Worker           (int)round(lc->target_bandwidth / lc->framerate);
144*77c1e3ccSAndroid Build Coastguard Worker       lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
145*77c1e3ccSAndroid Build Coastguard Worker       lrc->rtc_external_ratectrl = rc->rtc_external_ratectrl;
146*77c1e3ccSAndroid Build Coastguard Worker       lrc->worst_quality = av1_quantizer_to_qindex(lc->max_q);
147*77c1e3ccSAndroid Build Coastguard Worker       lrc->best_quality = av1_quantizer_to_qindex(lc->min_q);
148*77c1e3ccSAndroid Build Coastguard Worker       if (rc->use_external_qp_one_pass) {
149*77c1e3ccSAndroid Build Coastguard Worker         lrc->worst_quality = rc->worst_quality;
150*77c1e3ccSAndroid Build Coastguard Worker         lrc->best_quality = rc->best_quality;
151*77c1e3ccSAndroid Build Coastguard Worker       }
152*77c1e3ccSAndroid Build Coastguard Worker       // Reset the cyclic refresh parameters, if needed (map is NULL),
153*77c1e3ccSAndroid Build Coastguard Worker       // or number of spatial layers has changed.
154*77c1e3ccSAndroid Build Coastguard Worker       // Cyclic refresh is only applied on base temporal layer.
155*77c1e3ccSAndroid Build Coastguard Worker       if (svc->number_spatial_layers > 1 && tl == 0 &&
156*77c1e3ccSAndroid Build Coastguard Worker           (lc->map == NULL ||
157*77c1e3ccSAndroid Build Coastguard Worker            svc->prev_number_spatial_layers != svc->number_spatial_layers)) {
158*77c1e3ccSAndroid Build Coastguard Worker         lc->sb_index = 0;
159*77c1e3ccSAndroid Build Coastguard Worker         lc->actual_num_seg1_blocks = 0;
160*77c1e3ccSAndroid Build Coastguard Worker         lc->actual_num_seg2_blocks = 0;
161*77c1e3ccSAndroid Build Coastguard Worker         lc->counter_encode_maxq_scene_change = 0;
162*77c1e3ccSAndroid Build Coastguard Worker         aom_free(lc->map);
163*77c1e3ccSAndroid Build Coastguard Worker         CHECK_MEM_ERROR(cm, lc->map,
164*77c1e3ccSAndroid Build Coastguard Worker                         aom_calloc(mi_rows * mi_cols, sizeof(*lc->map)));
165*77c1e3ccSAndroid Build Coastguard Worker       }
166*77c1e3ccSAndroid Build Coastguard Worker     }
167*77c1e3ccSAndroid Build Coastguard Worker   }
168*77c1e3ccSAndroid Build Coastguard Worker }
169*77c1e3ccSAndroid Build Coastguard Worker 
170*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Return layer context for current layer.
171*77c1e3ccSAndroid Build Coastguard Worker  *
172*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup rate_control
173*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]       cpi   Top level encoder structure
174*77c1e3ccSAndroid Build Coastguard Worker  *
175*77c1e3ccSAndroid Build Coastguard Worker  * \return LAYER_CONTEXT for current layer.
176*77c1e3ccSAndroid Build Coastguard Worker  */
get_layer_context(AV1_COMP * const cpi)177*77c1e3ccSAndroid Build Coastguard Worker static LAYER_CONTEXT *get_layer_context(AV1_COMP *const cpi) {
178*77c1e3ccSAndroid Build Coastguard Worker   return &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
179*77c1e3ccSAndroid Build Coastguard Worker                                      cpi->svc.number_temporal_layers +
180*77c1e3ccSAndroid Build Coastguard Worker                                  cpi->svc.temporal_layer_id];
181*77c1e3ccSAndroid Build Coastguard Worker }
182*77c1e3ccSAndroid Build Coastguard Worker 
av1_update_temporal_layer_framerate(AV1_COMP * const cpi)183*77c1e3ccSAndroid Build Coastguard Worker void av1_update_temporal_layer_framerate(AV1_COMP *const cpi) {
184*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
185*77c1e3ccSAndroid Build Coastguard Worker   LAYER_CONTEXT *const lc = get_layer_context(cpi);
186*77c1e3ccSAndroid Build Coastguard Worker   RATE_CONTROL *const lrc = &lc->rc;
187*77c1e3ccSAndroid Build Coastguard Worker   const int tl = svc->temporal_layer_id;
188*77c1e3ccSAndroid Build Coastguard Worker   lc->framerate = cpi->framerate / lc->framerate_factor;
189*77c1e3ccSAndroid Build Coastguard Worker   lrc->avg_frame_bandwidth = (int)round(lc->target_bandwidth / lc->framerate);
190*77c1e3ccSAndroid Build Coastguard Worker   lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth;
191*77c1e3ccSAndroid Build Coastguard Worker   // Update the average layer frame size (non-cumulative per-frame-bw).
192*77c1e3ccSAndroid Build Coastguard Worker   if (tl == 0) {
193*77c1e3ccSAndroid Build Coastguard Worker     lc->avg_frame_size = lrc->avg_frame_bandwidth;
194*77c1e3ccSAndroid Build Coastguard Worker   } else {
195*77c1e3ccSAndroid Build Coastguard Worker     int prev_layer = svc->spatial_layer_id * svc->number_temporal_layers +
196*77c1e3ccSAndroid Build Coastguard Worker                      svc->temporal_layer_id - 1;
197*77c1e3ccSAndroid Build Coastguard Worker     LAYER_CONTEXT *const lcprev = &svc->layer_context[prev_layer];
198*77c1e3ccSAndroid Build Coastguard Worker     const double prev_layer_framerate =
199*77c1e3ccSAndroid Build Coastguard Worker         cpi->framerate / lcprev->framerate_factor;
200*77c1e3ccSAndroid Build Coastguard Worker     const int64_t prev_layer_target_bandwidth = lcprev->layer_target_bitrate;
201*77c1e3ccSAndroid Build Coastguard Worker     if (lc->framerate > prev_layer_framerate) {
202*77c1e3ccSAndroid Build Coastguard Worker       lc->avg_frame_size =
203*77c1e3ccSAndroid Build Coastguard Worker           (int)round((lc->target_bandwidth - prev_layer_target_bandwidth) /
204*77c1e3ccSAndroid Build Coastguard Worker                      (lc->framerate - prev_layer_framerate));
205*77c1e3ccSAndroid Build Coastguard Worker     } else {
206*77c1e3ccSAndroid Build Coastguard Worker       lc->avg_frame_size = (int)round(lc->target_bandwidth / lc->framerate);
207*77c1e3ccSAndroid Build Coastguard Worker     }
208*77c1e3ccSAndroid Build Coastguard Worker   }
209*77c1e3ccSAndroid Build Coastguard Worker }
210*77c1e3ccSAndroid Build Coastguard Worker 
av1_check_ref_is_low_spatial_res_super_frame(AV1_COMP * const cpi,int ref_frame)211*77c1e3ccSAndroid Build Coastguard Worker bool av1_check_ref_is_low_spatial_res_super_frame(AV1_COMP *const cpi,
212*77c1e3ccSAndroid Build Coastguard Worker                                                   int ref_frame) {
213*77c1e3ccSAndroid Build Coastguard Worker   SVC *svc = &cpi->svc;
214*77c1e3ccSAndroid Build Coastguard Worker   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref;
215*77c1e3ccSAndroid Build Coastguard Worker   int ref_frame_idx = rtc_ref->ref_idx[ref_frame - 1];
216*77c1e3ccSAndroid Build Coastguard Worker   return rtc_ref->buffer_time_index[ref_frame_idx] == svc->current_superframe &&
217*77c1e3ccSAndroid Build Coastguard Worker          rtc_ref->buffer_spatial_layer[ref_frame_idx] <=
218*77c1e3ccSAndroid Build Coastguard Worker              svc->spatial_layer_id - 1;
219*77c1e3ccSAndroid Build Coastguard Worker }
220*77c1e3ccSAndroid Build Coastguard Worker 
av1_restore_layer_context(AV1_COMP * const cpi)221*77c1e3ccSAndroid Build Coastguard Worker void av1_restore_layer_context(AV1_COMP *const cpi) {
222*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
223*77c1e3ccSAndroid Build Coastguard Worker   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref;
224*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
225*77c1e3ccSAndroid Build Coastguard Worker   LAYER_CONTEXT *const lc = get_layer_context(cpi);
226*77c1e3ccSAndroid Build Coastguard Worker   const int old_frame_since_key = cpi->rc.frames_since_key;
227*77c1e3ccSAndroid Build Coastguard Worker   const int old_frame_to_key = cpi->rc.frames_to_key;
228*77c1e3ccSAndroid Build Coastguard Worker   const int frames_since_scene_change = cpi->rc.frames_since_scene_change;
229*77c1e3ccSAndroid Build Coastguard Worker   const int last_encoded_size_keyframe = cpi->rc.last_encoded_size_keyframe;
230*77c1e3ccSAndroid Build Coastguard Worker   const int last_target_size_keyframe = cpi->rc.last_target_size_keyframe;
231*77c1e3ccSAndroid Build Coastguard Worker   const int max_consec_drop = cpi->rc.max_consec_drop;
232*77c1e3ccSAndroid Build Coastguard Worker   const int postencode_drop = cpi->rc.postencode_drop;
233*77c1e3ccSAndroid Build Coastguard Worker   const int static_since_last_scene_change =
234*77c1e3ccSAndroid Build Coastguard Worker       cpi->rc.static_since_last_scene_change;
235*77c1e3ccSAndroid Build Coastguard Worker   // Restore layer rate control.
236*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc = lc->rc;
237*77c1e3ccSAndroid Build Coastguard Worker   cpi->ppi->p_rc = lc->p_rc;
238*77c1e3ccSAndroid Build Coastguard Worker   cpi->oxcf.rc_cfg.target_bandwidth = lc->target_bandwidth;
239*77c1e3ccSAndroid Build Coastguard Worker   cpi->gf_frame_index = 0;
240*77c1e3ccSAndroid Build Coastguard Worker   cpi->mv_search_params.max_mv_magnitude = lc->max_mv_magnitude;
241*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->mv_search_params.max_mv_magnitude == 0)
242*77c1e3ccSAndroid Build Coastguard Worker     cpi->mv_search_params.max_mv_magnitude = AOMMAX(cm->width, cm->height);
243*77c1e3ccSAndroid Build Coastguard Worker   // Reset the following parameters to their values before
244*77c1e3ccSAndroid Build Coastguard Worker   // the layer restore. Keep these defined for the stream (not layer).
245*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc.frames_since_key = old_frame_since_key;
246*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc.frames_to_key = old_frame_to_key;
247*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc.frames_since_scene_change = frames_since_scene_change;
248*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc.last_encoded_size_keyframe = last_encoded_size_keyframe;
249*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc.last_target_size_keyframe = last_target_size_keyframe;
250*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc.max_consec_drop = max_consec_drop;
251*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc.postencode_drop = postencode_drop;
252*77c1e3ccSAndroid Build Coastguard Worker   cpi->rc.static_since_last_scene_change = static_since_last_scene_change;
253*77c1e3ccSAndroid Build Coastguard Worker   // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers,
254*77c1e3ccSAndroid Build Coastguard Worker   // for the base temporal layer.
255*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ &&
256*77c1e3ccSAndroid Build Coastguard Worker       svc->number_spatial_layers > 1 && svc->temporal_layer_id == 0) {
257*77c1e3ccSAndroid Build Coastguard Worker     CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
258*77c1e3ccSAndroid Build Coastguard Worker     swap_ptr(&cr->map, &lc->map);
259*77c1e3ccSAndroid Build Coastguard Worker     cr->sb_index = lc->sb_index;
260*77c1e3ccSAndroid Build Coastguard Worker     cr->actual_num_seg1_blocks = lc->actual_num_seg1_blocks;
261*77c1e3ccSAndroid Build Coastguard Worker     cr->actual_num_seg2_blocks = lc->actual_num_seg2_blocks;
262*77c1e3ccSAndroid Build Coastguard Worker     cr->counter_encode_maxq_scene_change = lc->counter_encode_maxq_scene_change;
263*77c1e3ccSAndroid Build Coastguard Worker   }
264*77c1e3ccSAndroid Build Coastguard Worker   svc->skip_mvsearch_last = 0;
265*77c1e3ccSAndroid Build Coastguard Worker   svc->skip_mvsearch_gf = 0;
266*77c1e3ccSAndroid Build Coastguard Worker   svc->skip_mvsearch_altref = 0;
267*77c1e3ccSAndroid Build Coastguard Worker   // For each reference (LAST/GOLDEN) set the skip_mvsearch_last/gf frame flags.
268*77c1e3ccSAndroid Build Coastguard Worker   // This is to skip searching mv for that reference if it was last
269*77c1e3ccSAndroid Build Coastguard Worker   // refreshed (i.e., buffer slot holding that reference was refreshed) on the
270*77c1e3ccSAndroid Build Coastguard Worker   // previous spatial layer(s) at the same time (current_superframe).
271*77c1e3ccSAndroid Build Coastguard Worker   if (rtc_ref->set_ref_frame_config && svc->force_zero_mode_spatial_ref &&
272*77c1e3ccSAndroid Build Coastguard Worker       cpi->sf.rt_sf.use_nonrd_pick_mode) {
273*77c1e3ccSAndroid Build Coastguard Worker     if (av1_check_ref_is_low_spatial_res_super_frame(cpi, LAST_FRAME)) {
274*77c1e3ccSAndroid Build Coastguard Worker       svc->skip_mvsearch_last = 1;
275*77c1e3ccSAndroid Build Coastguard Worker     }
276*77c1e3ccSAndroid Build Coastguard Worker     if (av1_check_ref_is_low_spatial_res_super_frame(cpi, GOLDEN_FRAME)) {
277*77c1e3ccSAndroid Build Coastguard Worker       svc->skip_mvsearch_gf = 1;
278*77c1e3ccSAndroid Build Coastguard Worker     }
279*77c1e3ccSAndroid Build Coastguard Worker     if (av1_check_ref_is_low_spatial_res_super_frame(cpi, ALTREF_FRAME)) {
280*77c1e3ccSAndroid Build Coastguard Worker       svc->skip_mvsearch_altref = 1;
281*77c1e3ccSAndroid Build Coastguard Worker     }
282*77c1e3ccSAndroid Build Coastguard Worker   }
283*77c1e3ccSAndroid Build Coastguard Worker }
284*77c1e3ccSAndroid Build Coastguard Worker 
av1_svc_update_buffer_slot_refreshed(AV1_COMP * const cpi)285*77c1e3ccSAndroid Build Coastguard Worker void av1_svc_update_buffer_slot_refreshed(AV1_COMP *const cpi) {
286*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
287*77c1e3ccSAndroid Build Coastguard Worker   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref;
288*77c1e3ccSAndroid Build Coastguard Worker   const unsigned int current_frame =
289*77c1e3ccSAndroid Build Coastguard Worker       cpi->ppi->use_svc ? svc->current_superframe
290*77c1e3ccSAndroid Build Coastguard Worker                         : cpi->common.current_frame.frame_number;
291*77c1e3ccSAndroid Build Coastguard Worker   // For any buffer slot that is refreshed, update it with
292*77c1e3ccSAndroid Build Coastguard Worker   // the spatial_layer_id and the current_superframe.
293*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->common.current_frame.frame_type == KEY_FRAME) {
294*77c1e3ccSAndroid Build Coastguard Worker     // All slots are refreshed on KEY.
295*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < REF_FRAMES; i++) {
296*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->buffer_time_index[i] = current_frame;
297*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->buffer_spatial_layer[i] = svc->spatial_layer_id;
298*77c1e3ccSAndroid Build Coastguard Worker     }
299*77c1e3ccSAndroid Build Coastguard Worker   } else if (rtc_ref->set_ref_frame_config) {
300*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) {
301*77c1e3ccSAndroid Build Coastguard Worker       const int ref_frame_map_idx = rtc_ref->ref_idx[i];
302*77c1e3ccSAndroid Build Coastguard Worker       if (rtc_ref->refresh[ref_frame_map_idx]) {
303*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->buffer_time_index[ref_frame_map_idx] = current_frame;
304*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->buffer_spatial_layer[ref_frame_map_idx] =
305*77c1e3ccSAndroid Build Coastguard Worker             svc->spatial_layer_id;
306*77c1e3ccSAndroid Build Coastguard Worker       }
307*77c1e3ccSAndroid Build Coastguard Worker     }
308*77c1e3ccSAndroid Build Coastguard Worker   }
309*77c1e3ccSAndroid Build Coastguard Worker }
310*77c1e3ccSAndroid Build Coastguard Worker 
av1_save_layer_context(AV1_COMP * const cpi)311*77c1e3ccSAndroid Build Coastguard Worker void av1_save_layer_context(AV1_COMP *const cpi) {
312*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
313*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
314*77c1e3ccSAndroid Build Coastguard Worker   LAYER_CONTEXT *lc = get_layer_context(cpi);
315*77c1e3ccSAndroid Build Coastguard Worker   lc->rc = cpi->rc;
316*77c1e3ccSAndroid Build Coastguard Worker   lc->p_rc = cpi->ppi->p_rc;
317*77c1e3ccSAndroid Build Coastguard Worker   lc->target_bandwidth = (int)cpi->oxcf.rc_cfg.target_bandwidth;
318*77c1e3ccSAndroid Build Coastguard Worker   lc->group_index = cpi->gf_frame_index;
319*77c1e3ccSAndroid Build Coastguard Worker   lc->max_mv_magnitude = cpi->mv_search_params.max_mv_magnitude;
320*77c1e3ccSAndroid Build Coastguard Worker   if (svc->spatial_layer_id == 0) svc->base_framerate = cpi->framerate;
321*77c1e3ccSAndroid Build Coastguard Worker   // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers,
322*77c1e3ccSAndroid Build Coastguard Worker   // for the base temporal layer.
323*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ &&
324*77c1e3ccSAndroid Build Coastguard Worker       cpi->svc.number_spatial_layers > 1 && svc->temporal_layer_id == 0) {
325*77c1e3ccSAndroid Build Coastguard Worker     CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
326*77c1e3ccSAndroid Build Coastguard Worker     signed char *temp = lc->map;
327*77c1e3ccSAndroid Build Coastguard Worker     lc->map = cr->map;
328*77c1e3ccSAndroid Build Coastguard Worker     cr->map = temp;
329*77c1e3ccSAndroid Build Coastguard Worker     lc->sb_index = cr->sb_index;
330*77c1e3ccSAndroid Build Coastguard Worker     lc->actual_num_seg1_blocks = cr->actual_num_seg1_blocks;
331*77c1e3ccSAndroid Build Coastguard Worker     lc->actual_num_seg2_blocks = cr->actual_num_seg2_blocks;
332*77c1e3ccSAndroid Build Coastguard Worker     lc->counter_encode_maxq_scene_change = cr->counter_encode_maxq_scene_change;
333*77c1e3ccSAndroid Build Coastguard Worker   }
334*77c1e3ccSAndroid Build Coastguard Worker   if (!cpi->is_dropped_frame) {
335*77c1e3ccSAndroid Build Coastguard Worker     av1_svc_update_buffer_slot_refreshed(cpi);
336*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < REF_FRAMES; i++) {
337*77c1e3ccSAndroid Build Coastguard Worker       if (frame_is_intra_only(cm) ||
338*77c1e3ccSAndroid Build Coastguard Worker           cm->current_frame.refresh_frame_flags & (1 << i)) {
339*77c1e3ccSAndroid Build Coastguard Worker         svc->spatial_layer_fb[i] = svc->spatial_layer_id;
340*77c1e3ccSAndroid Build Coastguard Worker         svc->temporal_layer_fb[i] = svc->temporal_layer_id;
341*77c1e3ccSAndroid Build Coastguard Worker       }
342*77c1e3ccSAndroid Build Coastguard Worker     }
343*77c1e3ccSAndroid Build Coastguard Worker   }
344*77c1e3ccSAndroid Build Coastguard Worker   if (svc->spatial_layer_id == svc->number_spatial_layers - 1) {
345*77c1e3ccSAndroid Build Coastguard Worker     svc->current_superframe++;
346*77c1e3ccSAndroid Build Coastguard Worker     // Reset drop flag to false for next superframe.
347*77c1e3ccSAndroid Build Coastguard Worker     for (int sl = 0; sl < svc->number_spatial_layers; sl++)
348*77c1e3ccSAndroid Build Coastguard Worker       svc->drop_spatial_layer[sl] = false;
349*77c1e3ccSAndroid Build Coastguard Worker   }
350*77c1e3ccSAndroid Build Coastguard Worker }
351*77c1e3ccSAndroid Build Coastguard Worker 
av1_svc_primary_ref_frame(const AV1_COMP * const cpi)352*77c1e3ccSAndroid Build Coastguard Worker int av1_svc_primary_ref_frame(const AV1_COMP *const cpi) {
353*77c1e3ccSAndroid Build Coastguard Worker   const SVC *const svc = &cpi->svc;
354*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
355*77c1e3ccSAndroid Build Coastguard Worker   int fb_idx = -1;
356*77c1e3ccSAndroid Build Coastguard Worker   int primary_ref_frame = PRIMARY_REF_NONE;
357*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->svc.number_spatial_layers > 1 ||
358*77c1e3ccSAndroid Build Coastguard Worker       cpi->svc.number_temporal_layers > 1) {
359*77c1e3ccSAndroid Build Coastguard Worker     // Set the primary_ref_frame to LAST_FRAME if that buffer slot for LAST
360*77c1e3ccSAndroid Build Coastguard Worker     // was last updated on a lower temporal layer (or base TL0) and for the
361*77c1e3ccSAndroid Build Coastguard Worker     // same spatial layer. For RTC patterns this allows for continued decoding
362*77c1e3ccSAndroid Build Coastguard Worker     // when set of enhancement layers are dropped (continued decoding starting
363*77c1e3ccSAndroid Build Coastguard Worker     // at next base TL0), so error_resilience can be off/0 for all layers.
364*77c1e3ccSAndroid Build Coastguard Worker     fb_idx = get_ref_frame_map_idx(cm, LAST_FRAME);
365*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->ppi->rtc_ref.reference[0] == 1 &&
366*77c1e3ccSAndroid Build Coastguard Worker         svc->spatial_layer_fb[fb_idx] == svc->spatial_layer_id &&
367*77c1e3ccSAndroid Build Coastguard Worker         (svc->temporal_layer_fb[fb_idx] < svc->temporal_layer_id ||
368*77c1e3ccSAndroid Build Coastguard Worker          svc->temporal_layer_fb[fb_idx] == 0)) {
369*77c1e3ccSAndroid Build Coastguard Worker       primary_ref_frame = 0;  // LAST_FRAME: ref_frame - LAST_FRAME
370*77c1e3ccSAndroid Build Coastguard Worker     }
371*77c1e3ccSAndroid Build Coastguard Worker   } else if (cpi->ppi->rtc_ref.set_ref_frame_config) {
372*77c1e3ccSAndroid Build Coastguard Worker     const ExternalFlags *const ext_flags = &cpi->ext_flags;
373*77c1e3ccSAndroid Build Coastguard Worker     int flags = ext_flags->ref_frame_flags;
374*77c1e3ccSAndroid Build Coastguard Worker     if (flags & AOM_LAST_FLAG) {
375*77c1e3ccSAndroid Build Coastguard Worker       primary_ref_frame = 0;  // LAST_FRAME: ref_frame - LAST_FRAME
376*77c1e3ccSAndroid Build Coastguard Worker     } else if (flags & AOM_GOLD_FLAG) {
377*77c1e3ccSAndroid Build Coastguard Worker       primary_ref_frame = GOLDEN_FRAME - LAST_FRAME;
378*77c1e3ccSAndroid Build Coastguard Worker     } else if (flags & AOM_ALT_FLAG) {
379*77c1e3ccSAndroid Build Coastguard Worker       primary_ref_frame = ALTREF_FRAME - LAST_FRAME;
380*77c1e3ccSAndroid Build Coastguard Worker     }
381*77c1e3ccSAndroid Build Coastguard Worker   }
382*77c1e3ccSAndroid Build Coastguard Worker   return primary_ref_frame;
383*77c1e3ccSAndroid Build Coastguard Worker }
384*77c1e3ccSAndroid Build Coastguard Worker 
av1_free_svc_cyclic_refresh(AV1_COMP * const cpi)385*77c1e3ccSAndroid Build Coastguard Worker void av1_free_svc_cyclic_refresh(AV1_COMP *const cpi) {
386*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
387*77c1e3ccSAndroid Build Coastguard Worker   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) {
388*77c1e3ccSAndroid Build Coastguard Worker     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
389*77c1e3ccSAndroid Build Coastguard Worker       int layer = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers);
390*77c1e3ccSAndroid Build Coastguard Worker       LAYER_CONTEXT *const lc = &svc->layer_context[layer];
391*77c1e3ccSAndroid Build Coastguard Worker       aom_free(lc->map);
392*77c1e3ccSAndroid Build Coastguard Worker       lc->map = NULL;
393*77c1e3ccSAndroid Build Coastguard Worker     }
394*77c1e3ccSAndroid Build Coastguard Worker   }
395*77c1e3ccSAndroid Build Coastguard Worker }
396*77c1e3ccSAndroid Build Coastguard Worker 
av1_svc_reset_temporal_layers(AV1_COMP * const cpi,int is_key)397*77c1e3ccSAndroid Build Coastguard Worker void av1_svc_reset_temporal_layers(AV1_COMP *const cpi, int is_key) {
398*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
399*77c1e3ccSAndroid Build Coastguard Worker   LAYER_CONTEXT *lc = NULL;
400*77c1e3ccSAndroid Build Coastguard Worker   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) {
401*77c1e3ccSAndroid Build Coastguard Worker     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
402*77c1e3ccSAndroid Build Coastguard Worker       lc = &cpi->svc.layer_context[sl * svc->number_temporal_layers + tl];
403*77c1e3ccSAndroid Build Coastguard Worker       if (is_key) lc->frames_from_key_frame = 0;
404*77c1e3ccSAndroid Build Coastguard Worker     }
405*77c1e3ccSAndroid Build Coastguard Worker   }
406*77c1e3ccSAndroid Build Coastguard Worker   av1_update_temporal_layer_framerate(cpi);
407*77c1e3ccSAndroid Build Coastguard Worker   av1_restore_layer_context(cpi);
408*77c1e3ccSAndroid Build Coastguard Worker }
409*77c1e3ccSAndroid Build Coastguard Worker 
av1_get_layer_resolution(const int width_org,const int height_org,const int num,const int den,int * width_out,int * height_out)410*77c1e3ccSAndroid Build Coastguard Worker void av1_get_layer_resolution(const int width_org, const int height_org,
411*77c1e3ccSAndroid Build Coastguard Worker                               const int num, const int den, int *width_out,
412*77c1e3ccSAndroid Build Coastguard Worker                               int *height_out) {
413*77c1e3ccSAndroid Build Coastguard Worker   int w, h;
414*77c1e3ccSAndroid Build Coastguard Worker   if (width_out == NULL || height_out == NULL || den == 0) return;
415*77c1e3ccSAndroid Build Coastguard Worker   if (den == 1 && num == 1) {
416*77c1e3ccSAndroid Build Coastguard Worker     *width_out = width_org;
417*77c1e3ccSAndroid Build Coastguard Worker     *height_out = height_org;
418*77c1e3ccSAndroid Build Coastguard Worker     return;
419*77c1e3ccSAndroid Build Coastguard Worker   }
420*77c1e3ccSAndroid Build Coastguard Worker   w = width_org * num / den;
421*77c1e3ccSAndroid Build Coastguard Worker   h = height_org * num / den;
422*77c1e3ccSAndroid Build Coastguard Worker   // Make height and width even.
423*77c1e3ccSAndroid Build Coastguard Worker   w += w % 2;
424*77c1e3ccSAndroid Build Coastguard Worker   h += h % 2;
425*77c1e3ccSAndroid Build Coastguard Worker   *width_out = w;
426*77c1e3ccSAndroid Build Coastguard Worker   *height_out = h;
427*77c1e3ccSAndroid Build Coastguard Worker }
428*77c1e3ccSAndroid Build Coastguard Worker 
av1_one_pass_cbr_svc_start_layer(AV1_COMP * const cpi)429*77c1e3ccSAndroid Build Coastguard Worker void av1_one_pass_cbr_svc_start_layer(AV1_COMP *const cpi) {
430*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
431*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
432*77c1e3ccSAndroid Build Coastguard Worker   LAYER_CONTEXT *lc = NULL;
433*77c1e3ccSAndroid Build Coastguard Worker   int width = 0, height = 0;
434*77c1e3ccSAndroid Build Coastguard Worker   lc = &svc->layer_context[svc->spatial_layer_id * svc->number_temporal_layers +
435*77c1e3ccSAndroid Build Coastguard Worker                            svc->temporal_layer_id];
436*77c1e3ccSAndroid Build Coastguard Worker   // Set the lower quality layer flag.
437*77c1e3ccSAndroid Build Coastguard Worker   svc->has_lower_quality_layer = 0;
438*77c1e3ccSAndroid Build Coastguard Worker   if (cpi->svc.spatial_layer_id > 0) {
439*77c1e3ccSAndroid Build Coastguard Worker     const LAYER_CONTEXT *lc_prev =
440*77c1e3ccSAndroid Build Coastguard Worker         &svc->layer_context[(svc->spatial_layer_id - 1) *
441*77c1e3ccSAndroid Build Coastguard Worker                                 svc->number_temporal_layers +
442*77c1e3ccSAndroid Build Coastguard Worker                             svc->temporal_layer_id];
443*77c1e3ccSAndroid Build Coastguard Worker     if (lc_prev->scaling_factor_den == 1 && lc_prev->scaling_factor_num == 1)
444*77c1e3ccSAndroid Build Coastguard Worker       svc->has_lower_quality_layer = 1;
445*77c1e3ccSAndroid Build Coastguard Worker   }
446*77c1e3ccSAndroid Build Coastguard Worker   av1_get_layer_resolution(cpi->oxcf.frm_dim_cfg.width,
447*77c1e3ccSAndroid Build Coastguard Worker                            cpi->oxcf.frm_dim_cfg.height, lc->scaling_factor_num,
448*77c1e3ccSAndroid Build Coastguard Worker                            lc->scaling_factor_den, &width, &height);
449*77c1e3ccSAndroid Build Coastguard Worker   // Use Eightap_smooth for low resolutions.
450*77c1e3ccSAndroid Build Coastguard Worker   if (width * height <= 320 * 240)
451*77c1e3ccSAndroid Build Coastguard Worker     svc->downsample_filter_type[svc->spatial_layer_id] = EIGHTTAP_SMOOTH;
452*77c1e3ccSAndroid Build Coastguard Worker 
453*77c1e3ccSAndroid Build Coastguard Worker   cm->width = width;
454*77c1e3ccSAndroid Build Coastguard Worker   cm->height = height;
455*77c1e3ccSAndroid Build Coastguard Worker   alloc_mb_mode_info_buffers(cpi);
456*77c1e3ccSAndroid Build Coastguard Worker   av1_update_frame_size(cpi);
457*77c1e3ccSAndroid Build Coastguard Worker   if (svc->spatial_layer_id == svc->number_spatial_layers - 1) {
458*77c1e3ccSAndroid Build Coastguard Worker     svc->mi_cols_full_resoln = cm->mi_params.mi_cols;
459*77c1e3ccSAndroid Build Coastguard Worker     svc->mi_rows_full_resoln = cm->mi_params.mi_rows;
460*77c1e3ccSAndroid Build Coastguard Worker   }
461*77c1e3ccSAndroid Build Coastguard Worker }
462*77c1e3ccSAndroid Build Coastguard Worker 
463*77c1e3ccSAndroid Build Coastguard Worker enum {
464*77c1e3ccSAndroid Build Coastguard Worker   SVC_LAST_FRAME = 0,
465*77c1e3ccSAndroid Build Coastguard Worker   SVC_LAST2_FRAME,
466*77c1e3ccSAndroid Build Coastguard Worker   SVC_LAST3_FRAME,
467*77c1e3ccSAndroid Build Coastguard Worker   SVC_GOLDEN_FRAME,
468*77c1e3ccSAndroid Build Coastguard Worker   SVC_BWDREF_FRAME,
469*77c1e3ccSAndroid Build Coastguard Worker   SVC_ALTREF2_FRAME,
470*77c1e3ccSAndroid Build Coastguard Worker   SVC_ALTREF_FRAME
471*77c1e3ccSAndroid Build Coastguard Worker };
472*77c1e3ccSAndroid Build Coastguard Worker 
473*77c1e3ccSAndroid Build Coastguard Worker // For fixed svc mode: fixed pattern is set based on the number of
474*77c1e3ccSAndroid Build Coastguard Worker // spatial and temporal layers, and the ksvc_fixed_mode.
av1_set_svc_fixed_mode(AV1_COMP * const cpi)475*77c1e3ccSAndroid Build Coastguard Worker void av1_set_svc_fixed_mode(AV1_COMP *const cpi) {
476*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
477*77c1e3ccSAndroid Build Coastguard Worker   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref;
478*77c1e3ccSAndroid Build Coastguard Worker   int i;
479*77c1e3ccSAndroid Build Coastguard Worker   assert(svc->use_flexible_mode == 0);
480*77c1e3ccSAndroid Build Coastguard Worker   // Fixed SVC mode only supports at most 3 spatial or temporal layers.
481*77c1e3ccSAndroid Build Coastguard Worker   assert(svc->number_spatial_layers >= 1 && svc->number_spatial_layers <= 3 &&
482*77c1e3ccSAndroid Build Coastguard Worker          svc->number_temporal_layers >= 1 && svc->number_temporal_layers <= 3);
483*77c1e3ccSAndroid Build Coastguard Worker   rtc_ref->set_ref_frame_config = 1;
484*77c1e3ccSAndroid Build Coastguard Worker   int superframe_cnt = svc->current_superframe;
485*77c1e3ccSAndroid Build Coastguard Worker   // Set the reference map buffer idx for the 7 references:
486*77c1e3ccSAndroid Build Coastguard Worker   // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3),
487*77c1e3ccSAndroid Build Coastguard Worker   // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
488*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < INTER_REFS_PER_FRAME; i++) {
489*77c1e3ccSAndroid Build Coastguard Worker     rtc_ref->reference[i] = 0;
490*77c1e3ccSAndroid Build Coastguard Worker     rtc_ref->ref_idx[i] = i;
491*77c1e3ccSAndroid Build Coastguard Worker   }
492*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < REF_FRAMES; i++) rtc_ref->refresh[i] = 0;
493*77c1e3ccSAndroid Build Coastguard Worker   // Always reference LAST, and reference GOLDEN on SL > 0.
494*77c1e3ccSAndroid Build Coastguard Worker   // For KSVC: GOLDEN reference will be removed on INTER_FRAMES later
495*77c1e3ccSAndroid Build Coastguard Worker   // when frame_type is set.
496*77c1e3ccSAndroid Build Coastguard Worker   rtc_ref->reference[SVC_LAST_FRAME] = 1;
497*77c1e3ccSAndroid Build Coastguard Worker   if (svc->spatial_layer_id > 0) rtc_ref->reference[SVC_GOLDEN_FRAME] = 1;
498*77c1e3ccSAndroid Build Coastguard Worker   if (svc->temporal_layer_id == 0) {
499*77c1e3ccSAndroid Build Coastguard Worker     // Base temporal layer.
500*77c1e3ccSAndroid Build Coastguard Worker     if (svc->spatial_layer_id == 0) {
501*77c1e3ccSAndroid Build Coastguard Worker       // Set all buffer_idx to 0. Update slot 0 (LAST).
502*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0;
503*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->refresh[0] = 1;
504*77c1e3ccSAndroid Build Coastguard Worker     } else if (svc->spatial_layer_id == 1) {
505*77c1e3ccSAndroid Build Coastguard Worker       // Set buffer_idx for LAST to slot 1, GOLDEN (and all other refs) to
506*77c1e3ccSAndroid Build Coastguard Worker       // slot 0. Update slot 1 (LAST).
507*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0;
508*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 1;
509*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->refresh[1] = 1;
510*77c1e3ccSAndroid Build Coastguard Worker     } else if (svc->spatial_layer_id == 2) {
511*77c1e3ccSAndroid Build Coastguard Worker       // Set buffer_idx for LAST to slot 2, GOLDEN (and all other refs) to
512*77c1e3ccSAndroid Build Coastguard Worker       // slot 1. Update slot 2 (LAST).
513*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 1;
514*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 2;
515*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->refresh[2] = 1;
516*77c1e3ccSAndroid Build Coastguard Worker     }
517*77c1e3ccSAndroid Build Coastguard Worker   } else if (svc->temporal_layer_id == 2 && (superframe_cnt - 1) % 4 == 0) {
518*77c1e3ccSAndroid Build Coastguard Worker     // First top temporal enhancement layer.
519*77c1e3ccSAndroid Build Coastguard Worker     if (svc->spatial_layer_id == 0) {
520*77c1e3ccSAndroid Build Coastguard Worker       // Reference LAST (slot 0).
521*77c1e3ccSAndroid Build Coastguard Worker       // Set GOLDEN to slot 3 and update slot 3.
522*77c1e3ccSAndroid Build Coastguard Worker       // Set all other buffer_idx to slot 0.
523*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0;
524*77c1e3ccSAndroid Build Coastguard Worker       if (svc->spatial_layer_id < svc->number_spatial_layers - 1) {
525*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 3;
526*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->refresh[3] = 1;
527*77c1e3ccSAndroid Build Coastguard Worker       }
528*77c1e3ccSAndroid Build Coastguard Worker     } else if (svc->spatial_layer_id == 1) {
529*77c1e3ccSAndroid Build Coastguard Worker       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1,
530*77c1e3ccSAndroid Build Coastguard Worker       // GOLDEN (and all other refs) to slot 3.
531*77c1e3ccSAndroid Build Coastguard Worker       // Set LAST2 to slot 4 and Update slot 4.
532*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 3;
533*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 1;
534*77c1e3ccSAndroid Build Coastguard Worker       if (svc->spatial_layer_id < svc->number_spatial_layers - 1) {
535*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->ref_idx[SVC_LAST2_FRAME] = 4;
536*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->refresh[4] = 1;
537*77c1e3ccSAndroid Build Coastguard Worker       }
538*77c1e3ccSAndroid Build Coastguard Worker     } else if (svc->spatial_layer_id == 2) {
539*77c1e3ccSAndroid Build Coastguard Worker       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2,
540*77c1e3ccSAndroid Build Coastguard Worker       // GOLDEN (and all other refs) to slot 4.
541*77c1e3ccSAndroid Build Coastguard Worker       // No update.
542*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 4;
543*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 2;
544*77c1e3ccSAndroid Build Coastguard Worker     }
545*77c1e3ccSAndroid Build Coastguard Worker   } else if (svc->temporal_layer_id == 1) {
546*77c1e3ccSAndroid Build Coastguard Worker     // Middle temporal enhancement layer.
547*77c1e3ccSAndroid Build Coastguard Worker     if (svc->spatial_layer_id == 0) {
548*77c1e3ccSAndroid Build Coastguard Worker       // Reference LAST.
549*77c1e3ccSAndroid Build Coastguard Worker       // Set all buffer_idx to 0.
550*77c1e3ccSAndroid Build Coastguard Worker       // Set GOLDEN to slot 5 and update slot 5.
551*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0;
552*77c1e3ccSAndroid Build Coastguard Worker       if (svc->temporal_layer_id < svc->number_temporal_layers - 1 ||
553*77c1e3ccSAndroid Build Coastguard Worker           svc->spatial_layer_id < svc->number_spatial_layers - 1) {
554*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 5;
555*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->refresh[5] = 1;
556*77c1e3ccSAndroid Build Coastguard Worker       }
557*77c1e3ccSAndroid Build Coastguard Worker     } else if (svc->spatial_layer_id == 1) {
558*77c1e3ccSAndroid Build Coastguard Worker       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1,
559*77c1e3ccSAndroid Build Coastguard Worker       // GOLDEN (and all other refs) to slot 5.
560*77c1e3ccSAndroid Build Coastguard Worker       // Set LAST3 to slot 6 and update slot 6.
561*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 5;
562*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 1;
563*77c1e3ccSAndroid Build Coastguard Worker       if (svc->temporal_layer_id < svc->number_temporal_layers - 1 ||
564*77c1e3ccSAndroid Build Coastguard Worker           svc->spatial_layer_id < svc->number_spatial_layers - 1) {
565*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->ref_idx[SVC_LAST3_FRAME] = 6;
566*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->refresh[6] = 1;
567*77c1e3ccSAndroid Build Coastguard Worker       }
568*77c1e3ccSAndroid Build Coastguard Worker     } else if (svc->spatial_layer_id == 2) {
569*77c1e3ccSAndroid Build Coastguard Worker       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2,
570*77c1e3ccSAndroid Build Coastguard Worker       // GOLDEN (and all other refs) to slot 6.
571*77c1e3ccSAndroid Build Coastguard Worker       // Set LAST3 to slot 7 and update slot 7.
572*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 6;
573*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 2;
574*77c1e3ccSAndroid Build Coastguard Worker       if (svc->temporal_layer_id < svc->number_temporal_layers - 1) {
575*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->ref_idx[SVC_LAST3_FRAME] = 7;
576*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->refresh[7] = 1;
577*77c1e3ccSAndroid Build Coastguard Worker       }
578*77c1e3ccSAndroid Build Coastguard Worker     }
579*77c1e3ccSAndroid Build Coastguard Worker   } else if (svc->temporal_layer_id == 2 && (superframe_cnt - 3) % 4 == 0) {
580*77c1e3ccSAndroid Build Coastguard Worker     // Second top temporal enhancement layer.
581*77c1e3ccSAndroid Build Coastguard Worker     if (svc->spatial_layer_id == 0) {
582*77c1e3ccSAndroid Build Coastguard Worker       // Set LAST to slot 5 and reference LAST.
583*77c1e3ccSAndroid Build Coastguard Worker       // Set GOLDEN to slot 3 and update slot 3.
584*77c1e3ccSAndroid Build Coastguard Worker       // Set all other buffer_idx to 0.
585*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0;
586*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 5;
587*77c1e3ccSAndroid Build Coastguard Worker       if (svc->spatial_layer_id < svc->number_spatial_layers - 1) {
588*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 3;
589*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->refresh[3] = 1;
590*77c1e3ccSAndroid Build Coastguard Worker       }
591*77c1e3ccSAndroid Build Coastguard Worker     } else if (svc->spatial_layer_id == 1) {
592*77c1e3ccSAndroid Build Coastguard Worker       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 6,
593*77c1e3ccSAndroid Build Coastguard Worker       // GOLDEN to slot 3. Set LAST2 to slot 4 and update slot 4.
594*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0;
595*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 6;
596*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 3;
597*77c1e3ccSAndroid Build Coastguard Worker       if (svc->spatial_layer_id < svc->number_spatial_layers - 1) {
598*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->ref_idx[SVC_LAST2_FRAME] = 4;
599*77c1e3ccSAndroid Build Coastguard Worker         rtc_ref->refresh[4] = 1;
600*77c1e3ccSAndroid Build Coastguard Worker       }
601*77c1e3ccSAndroid Build Coastguard Worker     } else if (svc->spatial_layer_id == 2) {
602*77c1e3ccSAndroid Build Coastguard Worker       // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 7,
603*77c1e3ccSAndroid Build Coastguard Worker       // GOLDEN to slot 4. No update.
604*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < INTER_REFS_PER_FRAME; i++) rtc_ref->ref_idx[i] = 0;
605*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_LAST_FRAME] = 7;
606*77c1e3ccSAndroid Build Coastguard Worker       rtc_ref->ref_idx[SVC_GOLDEN_FRAME] = 4;
607*77c1e3ccSAndroid Build Coastguard Worker     }
608*77c1e3ccSAndroid Build Coastguard Worker   }
609*77c1e3ccSAndroid Build Coastguard Worker }
610*77c1e3ccSAndroid Build Coastguard Worker 
av1_svc_check_reset_layer_rc_flag(AV1_COMP * const cpi)611*77c1e3ccSAndroid Build Coastguard Worker void av1_svc_check_reset_layer_rc_flag(AV1_COMP *const cpi) {
612*77c1e3ccSAndroid Build Coastguard Worker   SVC *const svc = &cpi->svc;
613*77c1e3ccSAndroid Build Coastguard Worker   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) {
614*77c1e3ccSAndroid Build Coastguard Worker     // Check for reset based on avg_frame_bandwidth for spatial layer sl.
615*77c1e3ccSAndroid Build Coastguard Worker     // If avg_frame_bandwidth for top temporal layer is not set
616*77c1e3ccSAndroid Build Coastguard Worker     // (because enhancement layer was inactive), use the base TL0
617*77c1e3ccSAndroid Build Coastguard Worker     int layer = LAYER_IDS_TO_IDX(sl, svc->number_temporal_layers - 1,
618*77c1e3ccSAndroid Build Coastguard Worker                                  svc->number_temporal_layers);
619*77c1e3ccSAndroid Build Coastguard Worker     LAYER_CONTEXT *lc = &svc->layer_context[layer];
620*77c1e3ccSAndroid Build Coastguard Worker     RATE_CONTROL *lrc = &lc->rc;
621*77c1e3ccSAndroid Build Coastguard Worker     int avg_frame_bandwidth = lrc->avg_frame_bandwidth;
622*77c1e3ccSAndroid Build Coastguard Worker     int prev_avg_frame_bandwidth = lrc->prev_avg_frame_bandwidth;
623*77c1e3ccSAndroid Build Coastguard Worker     if (avg_frame_bandwidth == 0 || prev_avg_frame_bandwidth == 0) {
624*77c1e3ccSAndroid Build Coastguard Worker       // Use base TL0.
625*77c1e3ccSAndroid Build Coastguard Worker       layer = LAYER_IDS_TO_IDX(sl, 0, svc->number_temporal_layers);
626*77c1e3ccSAndroid Build Coastguard Worker       lc = &svc->layer_context[layer];
627*77c1e3ccSAndroid Build Coastguard Worker       lrc = &lc->rc;
628*77c1e3ccSAndroid Build Coastguard Worker       avg_frame_bandwidth = lrc->avg_frame_bandwidth;
629*77c1e3ccSAndroid Build Coastguard Worker       prev_avg_frame_bandwidth = lrc->prev_avg_frame_bandwidth;
630*77c1e3ccSAndroid Build Coastguard Worker     }
631*77c1e3ccSAndroid Build Coastguard Worker     if (avg_frame_bandwidth / 3 > (prev_avg_frame_bandwidth >> 1) ||
632*77c1e3ccSAndroid Build Coastguard Worker         avg_frame_bandwidth < (prev_avg_frame_bandwidth >> 1)) {
633*77c1e3ccSAndroid Build Coastguard Worker       // Reset for all temporal layers with spatial layer sl.
634*77c1e3ccSAndroid Build Coastguard Worker       for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
635*77c1e3ccSAndroid Build Coastguard Worker         int layer2 = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers);
636*77c1e3ccSAndroid Build Coastguard Worker         LAYER_CONTEXT *lc2 = &svc->layer_context[layer2];
637*77c1e3ccSAndroid Build Coastguard Worker         RATE_CONTROL *lrc2 = &lc2->rc;
638*77c1e3ccSAndroid Build Coastguard Worker         PRIMARY_RATE_CONTROL *lp_rc2 = &lc2->p_rc;
639*77c1e3ccSAndroid Build Coastguard Worker         PRIMARY_RATE_CONTROL *const lp_rc = &lc2->p_rc;
640*77c1e3ccSAndroid Build Coastguard Worker         lrc2->rc_1_frame = 0;
641*77c1e3ccSAndroid Build Coastguard Worker         lrc2->rc_2_frame = 0;
642*77c1e3ccSAndroid Build Coastguard Worker         lp_rc2->bits_off_target = lp_rc->optimal_buffer_level;
643*77c1e3ccSAndroid Build Coastguard Worker         lp_rc2->buffer_level = lp_rc->optimal_buffer_level;
644*77c1e3ccSAndroid Build Coastguard Worker       }
645*77c1e3ccSAndroid Build Coastguard Worker     }
646*77c1e3ccSAndroid Build Coastguard Worker   }
647*77c1e3ccSAndroid Build Coastguard Worker }
648*77c1e3ccSAndroid Build Coastguard Worker 
av1_svc_set_last_source(AV1_COMP * const cpi,EncodeFrameInput * frame_input,YV12_BUFFER_CONFIG * prev_source)649*77c1e3ccSAndroid Build Coastguard Worker void av1_svc_set_last_source(AV1_COMP *const cpi, EncodeFrameInput *frame_input,
650*77c1e3ccSAndroid Build Coastguard Worker                              YV12_BUFFER_CONFIG *prev_source) {
651*77c1e3ccSAndroid Build Coastguard Worker   frame_input->last_source = prev_source != NULL ? prev_source : NULL;
652*77c1e3ccSAndroid Build Coastguard Worker   if (!cpi->ppi->use_svc && cpi->rc.prev_frame_is_dropped &&
653*77c1e3ccSAndroid Build Coastguard Worker       cpi->rc.frame_number_encoded > 0) {
654*77c1e3ccSAndroid Build Coastguard Worker     frame_input->last_source = &cpi->svc.source_last_TL0;
655*77c1e3ccSAndroid Build Coastguard Worker   } else {
656*77c1e3ccSAndroid Build Coastguard Worker     RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref;
657*77c1e3ccSAndroid Build Coastguard Worker     if (cpi->svc.spatial_layer_id == 0) {
658*77c1e3ccSAndroid Build Coastguard Worker       // For base spatial layer: if the LAST reference (index 0) is not
659*77c1e3ccSAndroid Build Coastguard Worker       // the previous (super)frame set the last_source to the source
660*77c1e3ccSAndroid Build Coastguard Worker       // corresponding to the last TL0, otherwise keep it at prev_source.
661*77c1e3ccSAndroid Build Coastguard Worker       // Always use source_last_TL0 if previous base TL0 was dropped.
662*77c1e3ccSAndroid Build Coastguard Worker       if (cpi->svc.current_superframe > 0) {
663*77c1e3ccSAndroid Build Coastguard Worker         const int buffslot_last = rtc_ref->ref_idx[0];
664*77c1e3ccSAndroid Build Coastguard Worker         // Check if previous frame was dropped on base TL0 layer.
665*77c1e3ccSAndroid Build Coastguard Worker         const int layer =
666*77c1e3ccSAndroid Build Coastguard Worker             LAYER_IDS_TO_IDX(0, 0, cpi->svc.number_temporal_layers);
667*77c1e3ccSAndroid Build Coastguard Worker         LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer];
668*77c1e3ccSAndroid Build Coastguard Worker         RATE_CONTROL *lrc = &lc->rc;
669*77c1e3ccSAndroid Build Coastguard Worker         if (lrc->prev_frame_is_dropped ||
670*77c1e3ccSAndroid Build Coastguard Worker             rtc_ref->buffer_time_index[buffslot_last] <
671*77c1e3ccSAndroid Build Coastguard Worker                 cpi->svc.current_superframe - 1) {
672*77c1e3ccSAndroid Build Coastguard Worker           frame_input->last_source = &cpi->svc.source_last_TL0;
673*77c1e3ccSAndroid Build Coastguard Worker         }
674*77c1e3ccSAndroid Build Coastguard Worker       }
675*77c1e3ccSAndroid Build Coastguard Worker     } else if (cpi->svc.spatial_layer_id > 0) {
676*77c1e3ccSAndroid Build Coastguard Worker       // For spatial enhancement layers: the previous source (prev_source)
677*77c1e3ccSAndroid Build Coastguard Worker       // corresponds to the lower spatial layer (which is the same source so
678*77c1e3ccSAndroid Build Coastguard Worker       // we can't use that), so always set the last_source to the source of the
679*77c1e3ccSAndroid Build Coastguard Worker       // last TL0.
680*77c1e3ccSAndroid Build Coastguard Worker       if (cpi->svc.current_superframe > 0)
681*77c1e3ccSAndroid Build Coastguard Worker         frame_input->last_source = &cpi->svc.source_last_TL0;
682*77c1e3ccSAndroid Build Coastguard Worker       else
683*77c1e3ccSAndroid Build Coastguard Worker         frame_input->last_source = NULL;
684*77c1e3ccSAndroid Build Coastguard Worker     }
685*77c1e3ccSAndroid Build Coastguard Worker   }
686*77c1e3ccSAndroid Build Coastguard Worker }
687*77c1e3ccSAndroid Build Coastguard Worker 
av1_svc_get_min_ref_dist(const AV1_COMP * cpi)688*77c1e3ccSAndroid Build Coastguard Worker int av1_svc_get_min_ref_dist(const AV1_COMP *cpi) {
689*77c1e3ccSAndroid Build Coastguard Worker   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref;
690*77c1e3ccSAndroid Build Coastguard Worker   int min_dist = INT_MAX;
691*77c1e3ccSAndroid Build Coastguard Worker   const unsigned int current_frame_num =
692*77c1e3ccSAndroid Build Coastguard Worker       cpi->ppi->use_svc ? cpi->svc.current_superframe
693*77c1e3ccSAndroid Build Coastguard Worker                         : cpi->common.current_frame.frame_number;
694*77c1e3ccSAndroid Build Coastguard Worker   for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) {
695*77c1e3ccSAndroid Build Coastguard Worker     if (rtc_ref->reference[i]) {
696*77c1e3ccSAndroid Build Coastguard Worker       const int ref_frame_map_idx = rtc_ref->ref_idx[i];
697*77c1e3ccSAndroid Build Coastguard Worker       const int dist =
698*77c1e3ccSAndroid Build Coastguard Worker           current_frame_num - rtc_ref->buffer_time_index[ref_frame_map_idx];
699*77c1e3ccSAndroid Build Coastguard Worker       if (dist < min_dist) min_dist = dist;
700*77c1e3ccSAndroid Build Coastguard Worker     }
701*77c1e3ccSAndroid Build Coastguard Worker   }
702*77c1e3ccSAndroid Build Coastguard Worker   return min_dist;
703*77c1e3ccSAndroid Build Coastguard Worker }
704*77c1e3ccSAndroid Build Coastguard Worker 
av1_svc_set_reference_was_previous(AV1_COMP * cpi)705*77c1e3ccSAndroid Build Coastguard Worker void av1_svc_set_reference_was_previous(AV1_COMP *cpi) {
706*77c1e3ccSAndroid Build Coastguard Worker   RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref;
707*77c1e3ccSAndroid Build Coastguard Worker   // Check if the encoded frame had some reference that was the
708*77c1e3ccSAndroid Build Coastguard Worker   // previous frame.
709*77c1e3ccSAndroid Build Coastguard Worker   const unsigned int current_frame =
710*77c1e3ccSAndroid Build Coastguard Worker       cpi->ppi->use_svc ? cpi->svc.current_superframe
711*77c1e3ccSAndroid Build Coastguard Worker                         : cpi->common.current_frame.frame_number;
712*77c1e3ccSAndroid Build Coastguard Worker   rtc_ref->reference_was_previous_frame = true;
713*77c1e3ccSAndroid Build Coastguard Worker   if (current_frame > 0) {
714*77c1e3ccSAndroid Build Coastguard Worker     rtc_ref->reference_was_previous_frame = false;
715*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) {
716*77c1e3ccSAndroid Build Coastguard Worker       if (rtc_ref->reference[i]) {
717*77c1e3ccSAndroid Build Coastguard Worker         const int ref_frame_map_idx = rtc_ref->ref_idx[i];
718*77c1e3ccSAndroid Build Coastguard Worker         if (rtc_ref->buffer_time_index[ref_frame_map_idx] == current_frame - 1)
719*77c1e3ccSAndroid Build Coastguard Worker           rtc_ref->reference_was_previous_frame = true;
720*77c1e3ccSAndroid Build Coastguard Worker       }
721*77c1e3ccSAndroid Build Coastguard Worker     }
722*77c1e3ccSAndroid Build Coastguard Worker   }
723*77c1e3ccSAndroid Build Coastguard Worker }
724