xref: /aosp_15_r20/external/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.c (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1*fb1b10abSAndroid Build Coastguard Worker /*
2*fb1b10abSAndroid Build Coastguard Worker  *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
3*fb1b10abSAndroid Build Coastguard Worker  *
4*fb1b10abSAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*fb1b10abSAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*fb1b10abSAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*fb1b10abSAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*fb1b10abSAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*fb1b10abSAndroid Build Coastguard Worker  */
10*fb1b10abSAndroid Build Coastguard Worker 
11*fb1b10abSAndroid Build Coastguard Worker #include <limits.h>
12*fb1b10abSAndroid Build Coastguard Worker #include <math.h>
13*fb1b10abSAndroid Build Coastguard Worker 
14*fb1b10abSAndroid Build Coastguard Worker #include "vpx_dsp/vpx_dsp_common.h"
15*fb1b10abSAndroid Build Coastguard Worker #include "vpx_ports/system_state.h"
16*fb1b10abSAndroid Build Coastguard Worker 
17*fb1b10abSAndroid Build Coastguard Worker #include "vp9/encoder/vp9_aq_cyclicrefresh.h"
18*fb1b10abSAndroid Build Coastguard Worker 
19*fb1b10abSAndroid Build Coastguard Worker #include "vp9/common/vp9_seg_common.h"
20*fb1b10abSAndroid Build Coastguard Worker 
21*fb1b10abSAndroid Build Coastguard Worker #include "vp9/encoder/vp9_ratectrl.h"
22*fb1b10abSAndroid Build Coastguard Worker #include "vp9/encoder/vp9_segmentation.h"
23*fb1b10abSAndroid Build Coastguard Worker 
24*fb1b10abSAndroid Build Coastguard Worker static const uint8_t VP9_VAR_OFFS[64] = {
25*fb1b10abSAndroid Build Coastguard Worker   128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
26*fb1b10abSAndroid Build Coastguard Worker   128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
27*fb1b10abSAndroid Build Coastguard Worker   128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
28*fb1b10abSAndroid Build Coastguard Worker   128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
29*fb1b10abSAndroid Build Coastguard Worker   128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
30*fb1b10abSAndroid Build Coastguard Worker };
31*fb1b10abSAndroid Build Coastguard Worker 
vp9_cyclic_refresh_alloc(int mi_rows,int mi_cols)32*fb1b10abSAndroid Build Coastguard Worker CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols) {
33*fb1b10abSAndroid Build Coastguard Worker   size_t last_coded_q_map_size;
34*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = vpx_calloc(1, sizeof(*cr));
35*fb1b10abSAndroid Build Coastguard Worker   if (cr == NULL) return NULL;
36*fb1b10abSAndroid Build Coastguard Worker 
37*fb1b10abSAndroid Build Coastguard Worker   cr->map = vpx_calloc(mi_rows * mi_cols, sizeof(*cr->map));
38*fb1b10abSAndroid Build Coastguard Worker   if (cr->map == NULL) {
39*fb1b10abSAndroid Build Coastguard Worker     vp9_cyclic_refresh_free(cr);
40*fb1b10abSAndroid Build Coastguard Worker     return NULL;
41*fb1b10abSAndroid Build Coastguard Worker   }
42*fb1b10abSAndroid Build Coastguard Worker   last_coded_q_map_size = mi_rows * mi_cols * sizeof(*cr->last_coded_q_map);
43*fb1b10abSAndroid Build Coastguard Worker   cr->last_coded_q_map = vpx_malloc(last_coded_q_map_size);
44*fb1b10abSAndroid Build Coastguard Worker   if (cr->last_coded_q_map == NULL) {
45*fb1b10abSAndroid Build Coastguard Worker     vp9_cyclic_refresh_free(cr);
46*fb1b10abSAndroid Build Coastguard Worker     return NULL;
47*fb1b10abSAndroid Build Coastguard Worker   }
48*fb1b10abSAndroid Build Coastguard Worker   assert(MAXQ <= 255);
49*fb1b10abSAndroid Build Coastguard Worker   memset(cr->last_coded_q_map, MAXQ, last_coded_q_map_size);
50*fb1b10abSAndroid Build Coastguard Worker   cr->counter_encode_maxq_scene_change = 0;
51*fb1b10abSAndroid Build Coastguard Worker   cr->content_mode = 1;
52*fb1b10abSAndroid Build Coastguard Worker   return cr;
53*fb1b10abSAndroid Build Coastguard Worker }
54*fb1b10abSAndroid Build Coastguard Worker 
vp9_cyclic_refresh_free(CYCLIC_REFRESH * cr)55*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_free(CYCLIC_REFRESH *cr) {
56*fb1b10abSAndroid Build Coastguard Worker   if (cr != NULL) {
57*fb1b10abSAndroid Build Coastguard Worker     vpx_free(cr->map);
58*fb1b10abSAndroid Build Coastguard Worker     vpx_free(cr->last_coded_q_map);
59*fb1b10abSAndroid Build Coastguard Worker     vpx_free(cr);
60*fb1b10abSAndroid Build Coastguard Worker   }
61*fb1b10abSAndroid Build Coastguard Worker }
62*fb1b10abSAndroid Build Coastguard Worker 
63*fb1b10abSAndroid Build Coastguard Worker // Check if this coding block, of size bsize, should be considered for refresh
64*fb1b10abSAndroid Build Coastguard Worker // (lower-qp coding). Decision can be based on various factors, such as
65*fb1b10abSAndroid Build Coastguard Worker // size of the coding block (i.e., below min_block size rejected), coding
66*fb1b10abSAndroid Build Coastguard Worker // mode, and rate/distortion.
candidate_refresh_aq(const CYCLIC_REFRESH * cr,const MODE_INFO * mi,int64_t rate,int64_t dist,int bsize)67*fb1b10abSAndroid Build Coastguard Worker static int candidate_refresh_aq(const CYCLIC_REFRESH *cr, const MODE_INFO *mi,
68*fb1b10abSAndroid Build Coastguard Worker                                 int64_t rate, int64_t dist, int bsize) {
69*fb1b10abSAndroid Build Coastguard Worker   MV mv = mi->mv[0].as_mv;
70*fb1b10abSAndroid Build Coastguard Worker   // Reject the block for lower-qp coding if projected distortion
71*fb1b10abSAndroid Build Coastguard Worker   // is above the threshold, and any of the following is true:
72*fb1b10abSAndroid Build Coastguard Worker   // 1) mode uses large mv
73*fb1b10abSAndroid Build Coastguard Worker   // 2) mode is an intra-mode
74*fb1b10abSAndroid Build Coastguard Worker   // Otherwise accept for refresh.
75*fb1b10abSAndroid Build Coastguard Worker   if (dist > cr->thresh_dist_sb &&
76*fb1b10abSAndroid Build Coastguard Worker       (mv.row > cr->motion_thresh || mv.row < -cr->motion_thresh ||
77*fb1b10abSAndroid Build Coastguard Worker        mv.col > cr->motion_thresh || mv.col < -cr->motion_thresh ||
78*fb1b10abSAndroid Build Coastguard Worker        !is_inter_block(mi)))
79*fb1b10abSAndroid Build Coastguard Worker     return CR_SEGMENT_ID_BASE;
80*fb1b10abSAndroid Build Coastguard Worker   else if (bsize >= BLOCK_16X16 && rate < cr->thresh_rate_sb &&
81*fb1b10abSAndroid Build Coastguard Worker            is_inter_block(mi) && mi->mv[0].as_int == 0 &&
82*fb1b10abSAndroid Build Coastguard Worker            cr->rate_boost_fac > 10)
83*fb1b10abSAndroid Build Coastguard Worker     // More aggressive delta-q for bigger blocks with zero motion.
84*fb1b10abSAndroid Build Coastguard Worker     return CR_SEGMENT_ID_BOOST2;
85*fb1b10abSAndroid Build Coastguard Worker   else
86*fb1b10abSAndroid Build Coastguard Worker     return CR_SEGMENT_ID_BOOST1;
87*fb1b10abSAndroid Build Coastguard Worker }
88*fb1b10abSAndroid Build Coastguard Worker 
89*fb1b10abSAndroid Build Coastguard Worker // Compute delta-q for the segment.
compute_deltaq(const VP9_COMP * cpi,int q,double rate_factor)90*fb1b10abSAndroid Build Coastguard Worker static int compute_deltaq(const VP9_COMP *cpi, int q, double rate_factor) {
91*fb1b10abSAndroid Build Coastguard Worker   const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
92*fb1b10abSAndroid Build Coastguard Worker   const RATE_CONTROL *const rc = &cpi->rc;
93*fb1b10abSAndroid Build Coastguard Worker   int deltaq = vp9_compute_qdelta_by_rate(rc, cpi->common.frame_type, q,
94*fb1b10abSAndroid Build Coastguard Worker                                           rate_factor, cpi->common.bit_depth);
95*fb1b10abSAndroid Build Coastguard Worker   if ((-deltaq) > cr->max_qdelta_perc * q / 100) {
96*fb1b10abSAndroid Build Coastguard Worker     deltaq = -cr->max_qdelta_perc * q / 100;
97*fb1b10abSAndroid Build Coastguard Worker   }
98*fb1b10abSAndroid Build Coastguard Worker   return deltaq;
99*fb1b10abSAndroid Build Coastguard Worker }
100*fb1b10abSAndroid Build Coastguard Worker 
101*fb1b10abSAndroid Build Coastguard Worker // For the just encoded frame, estimate the bits, incorporating the delta-q
102*fb1b10abSAndroid Build Coastguard Worker // from non-base segment. For now ignore effect of multiple segments
103*fb1b10abSAndroid Build Coastguard Worker // (with different delta-q). Note this function is called in the postencode
104*fb1b10abSAndroid Build Coastguard Worker // (called from rc_update_rate_correction_factors()).
vp9_cyclic_refresh_estimate_bits_at_q(const VP9_COMP * cpi,double correction_factor)105*fb1b10abSAndroid Build Coastguard Worker int vp9_cyclic_refresh_estimate_bits_at_q(const VP9_COMP *cpi,
106*fb1b10abSAndroid Build Coastguard Worker                                           double correction_factor) {
107*fb1b10abSAndroid Build Coastguard Worker   const VP9_COMMON *const cm = &cpi->common;
108*fb1b10abSAndroid Build Coastguard Worker   const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
109*fb1b10abSAndroid Build Coastguard Worker   int estimated_bits;
110*fb1b10abSAndroid Build Coastguard Worker   int mbs = cm->MBs;
111*fb1b10abSAndroid Build Coastguard Worker   int num8x8bl = mbs << 2;
112*fb1b10abSAndroid Build Coastguard Worker   // Weight for non-base segments: use actual number of blocks refreshed in
113*fb1b10abSAndroid Build Coastguard Worker   // previous/just encoded frame. Note number of blocks here is in 8x8 units.
114*fb1b10abSAndroid Build Coastguard Worker   double weight_segment1 = (double)cr->actual_num_seg1_blocks / num8x8bl;
115*fb1b10abSAndroid Build Coastguard Worker   double weight_segment2 = (double)cr->actual_num_seg2_blocks / num8x8bl;
116*fb1b10abSAndroid Build Coastguard Worker   // Take segment weighted average for estimated bits.
117*fb1b10abSAndroid Build Coastguard Worker   estimated_bits = (int)round(
118*fb1b10abSAndroid Build Coastguard Worker       (1.0 - weight_segment1 - weight_segment2) *
119*fb1b10abSAndroid Build Coastguard Worker           vp9_estimate_bits_at_q(cm->frame_type, cm->base_qindex, mbs,
120*fb1b10abSAndroid Build Coastguard Worker                                  correction_factor, cm->bit_depth) +
121*fb1b10abSAndroid Build Coastguard Worker       weight_segment1 *
122*fb1b10abSAndroid Build Coastguard Worker           vp9_estimate_bits_at_q(cm->frame_type,
123*fb1b10abSAndroid Build Coastguard Worker                                  cm->base_qindex + cr->qindex_delta[1], mbs,
124*fb1b10abSAndroid Build Coastguard Worker                                  correction_factor, cm->bit_depth) +
125*fb1b10abSAndroid Build Coastguard Worker       weight_segment2 *
126*fb1b10abSAndroid Build Coastguard Worker           vp9_estimate_bits_at_q(cm->frame_type,
127*fb1b10abSAndroid Build Coastguard Worker                                  cm->base_qindex + cr->qindex_delta[2], mbs,
128*fb1b10abSAndroid Build Coastguard Worker                                  correction_factor, cm->bit_depth));
129*fb1b10abSAndroid Build Coastguard Worker   return estimated_bits;
130*fb1b10abSAndroid Build Coastguard Worker }
131*fb1b10abSAndroid Build Coastguard Worker 
132*fb1b10abSAndroid Build Coastguard Worker // Prior to encoding the frame, estimate the bits per mb, for a given q = i and
133*fb1b10abSAndroid Build Coastguard Worker // a corresponding delta-q (for segment 1). This function is called in the
134*fb1b10abSAndroid Build Coastguard Worker // rc_regulate_q() to set the base qp index.
135*fb1b10abSAndroid Build Coastguard Worker // Note: the segment map is set to either 0/CR_SEGMENT_ID_BASE (no refresh) or
136*fb1b10abSAndroid Build Coastguard Worker // to 1/CR_SEGMENT_ID_BOOST1 (refresh) for each superblock, prior to encoding.
vp9_cyclic_refresh_rc_bits_per_mb(const VP9_COMP * cpi,int i,double correction_factor)137*fb1b10abSAndroid Build Coastguard Worker int vp9_cyclic_refresh_rc_bits_per_mb(const VP9_COMP *cpi, int i,
138*fb1b10abSAndroid Build Coastguard Worker                                       double correction_factor) {
139*fb1b10abSAndroid Build Coastguard Worker   const VP9_COMMON *const cm = &cpi->common;
140*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
141*fb1b10abSAndroid Build Coastguard Worker   int bits_per_mb;
142*fb1b10abSAndroid Build Coastguard Worker   int deltaq = 0;
143*fb1b10abSAndroid Build Coastguard Worker   if (cpi->oxcf.speed < 8)
144*fb1b10abSAndroid Build Coastguard Worker     deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta);
145*fb1b10abSAndroid Build Coastguard Worker   else
146*fb1b10abSAndroid Build Coastguard Worker     deltaq = -(cr->max_qdelta_perc * i) / 200;
147*fb1b10abSAndroid Build Coastguard Worker   // Take segment weighted average for bits per mb.
148*fb1b10abSAndroid Build Coastguard Worker   bits_per_mb =
149*fb1b10abSAndroid Build Coastguard Worker       (int)round((1.0 - cr->weight_segment) *
150*fb1b10abSAndroid Build Coastguard Worker                      vp9_rc_bits_per_mb(cm->frame_type, i, correction_factor,
151*fb1b10abSAndroid Build Coastguard Worker                                         cm->bit_depth) +
152*fb1b10abSAndroid Build Coastguard Worker                  cr->weight_segment *
153*fb1b10abSAndroid Build Coastguard Worker                      vp9_rc_bits_per_mb(cm->frame_type, i + deltaq,
154*fb1b10abSAndroid Build Coastguard Worker                                         correction_factor, cm->bit_depth));
155*fb1b10abSAndroid Build Coastguard Worker   return bits_per_mb;
156*fb1b10abSAndroid Build Coastguard Worker }
157*fb1b10abSAndroid Build Coastguard Worker 
158*fb1b10abSAndroid Build Coastguard Worker // Prior to coding a given prediction block, of size bsize at (mi_row, mi_col),
159*fb1b10abSAndroid Build Coastguard Worker // check if we should reset the segment_id, and update the cyclic_refresh map
160*fb1b10abSAndroid Build Coastguard Worker // and segmentation map.
vp9_cyclic_refresh_update_segment(VP9_COMP * const cpi,MODE_INFO * const mi,int mi_row,int mi_col,BLOCK_SIZE bsize,int64_t rate,int64_t dist,int skip,struct macroblock_plane * const p)161*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_update_segment(VP9_COMP *const cpi, MODE_INFO *const mi,
162*fb1b10abSAndroid Build Coastguard Worker                                        int mi_row, int mi_col, BLOCK_SIZE bsize,
163*fb1b10abSAndroid Build Coastguard Worker                                        int64_t rate, int64_t dist, int skip,
164*fb1b10abSAndroid Build Coastguard Worker                                        struct macroblock_plane *const p) {
165*fb1b10abSAndroid Build Coastguard Worker   const VP9_COMMON *const cm = &cpi->common;
166*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
167*fb1b10abSAndroid Build Coastguard Worker   const int bw = num_8x8_blocks_wide_lookup[bsize];
168*fb1b10abSAndroid Build Coastguard Worker   const int bh = num_8x8_blocks_high_lookup[bsize];
169*fb1b10abSAndroid Build Coastguard Worker   const int xmis = VPXMIN(cm->mi_cols - mi_col, bw);
170*fb1b10abSAndroid Build Coastguard Worker   const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
171*fb1b10abSAndroid Build Coastguard Worker   const int block_index = mi_row * cm->mi_cols + mi_col;
172*fb1b10abSAndroid Build Coastguard Worker   int refresh_this_block = candidate_refresh_aq(cr, mi, rate, dist, bsize);
173*fb1b10abSAndroid Build Coastguard Worker   // Default is to not update the refresh map.
174*fb1b10abSAndroid Build Coastguard Worker   int new_map_value = cr->map[block_index];
175*fb1b10abSAndroid Build Coastguard Worker   int x = 0;
176*fb1b10abSAndroid Build Coastguard Worker   int y = 0;
177*fb1b10abSAndroid Build Coastguard Worker 
178*fb1b10abSAndroid Build Coastguard Worker   int is_skin = 0;
179*fb1b10abSAndroid Build Coastguard Worker   if (refresh_this_block == 0 && bsize <= BLOCK_16X16 &&
180*fb1b10abSAndroid Build Coastguard Worker       cpi->use_skin_detection) {
181*fb1b10abSAndroid Build Coastguard Worker     is_skin =
182*fb1b10abSAndroid Build Coastguard Worker         vp9_compute_skin_block(p[0].src.buf, p[1].src.buf, p[2].src.buf,
183*fb1b10abSAndroid Build Coastguard Worker                                p[0].src.stride, p[1].src.stride, bsize, 0, 0);
184*fb1b10abSAndroid Build Coastguard Worker     if (is_skin) refresh_this_block = 1;
185*fb1b10abSAndroid Build Coastguard Worker   }
186*fb1b10abSAndroid Build Coastguard Worker 
187*fb1b10abSAndroid Build Coastguard Worker   if (cpi->oxcf.rc_mode == VPX_VBR && mi->ref_frame[0] == GOLDEN_FRAME)
188*fb1b10abSAndroid Build Coastguard Worker     refresh_this_block = 0;
189*fb1b10abSAndroid Build Coastguard Worker 
190*fb1b10abSAndroid Build Coastguard Worker   // If this block is labeled for refresh, check if we should reset the
191*fb1b10abSAndroid Build Coastguard Worker   // segment_id.
192*fb1b10abSAndroid Build Coastguard Worker   if (cpi->sf.use_nonrd_pick_mode &&
193*fb1b10abSAndroid Build Coastguard Worker       cyclic_refresh_segment_id_boosted(mi->segment_id)) {
194*fb1b10abSAndroid Build Coastguard Worker     mi->segment_id = refresh_this_block;
195*fb1b10abSAndroid Build Coastguard Worker     // Reset segment_id if it will be skipped.
196*fb1b10abSAndroid Build Coastguard Worker     if (skip) mi->segment_id = CR_SEGMENT_ID_BASE;
197*fb1b10abSAndroid Build Coastguard Worker   }
198*fb1b10abSAndroid Build Coastguard Worker 
199*fb1b10abSAndroid Build Coastguard Worker   // Update the cyclic refresh map, to be used for setting segmentation map
200*fb1b10abSAndroid Build Coastguard Worker   // for the next frame. If the block  will be refreshed this frame, mark it
201*fb1b10abSAndroid Build Coastguard Worker   // as clean. The magnitude of the -ve influences how long before we consider
202*fb1b10abSAndroid Build Coastguard Worker   // it for refresh again.
203*fb1b10abSAndroid Build Coastguard Worker   if (cyclic_refresh_segment_id_boosted(mi->segment_id)) {
204*fb1b10abSAndroid Build Coastguard Worker     new_map_value = -cr->time_for_refresh;
205*fb1b10abSAndroid Build Coastguard Worker   } else if (refresh_this_block) {
206*fb1b10abSAndroid Build Coastguard Worker     // Else if it is accepted as candidate for refresh, and has not already
207*fb1b10abSAndroid Build Coastguard Worker     // been refreshed (marked as 1) then mark it as a candidate for cleanup
208*fb1b10abSAndroid Build Coastguard Worker     // for future time (marked as 0), otherwise don't update it.
209*fb1b10abSAndroid Build Coastguard Worker     if (cr->map[block_index] == 1) new_map_value = 0;
210*fb1b10abSAndroid Build Coastguard Worker   } else {
211*fb1b10abSAndroid Build Coastguard Worker     // Leave it marked as block that is not candidate for refresh.
212*fb1b10abSAndroid Build Coastguard Worker     new_map_value = 1;
213*fb1b10abSAndroid Build Coastguard Worker   }
214*fb1b10abSAndroid Build Coastguard Worker 
215*fb1b10abSAndroid Build Coastguard Worker   // Update entries in the cyclic refresh map with new_map_value, and
216*fb1b10abSAndroid Build Coastguard Worker   // copy mbmi->segment_id into global segmentation map.
217*fb1b10abSAndroid Build Coastguard Worker   for (y = 0; y < ymis; y++)
218*fb1b10abSAndroid Build Coastguard Worker     for (x = 0; x < xmis; x++) {
219*fb1b10abSAndroid Build Coastguard Worker       int map_offset = block_index + y * cm->mi_cols + x;
220*fb1b10abSAndroid Build Coastguard Worker       cr->map[map_offset] = new_map_value;
221*fb1b10abSAndroid Build Coastguard Worker       cpi->segmentation_map[map_offset] = mi->segment_id;
222*fb1b10abSAndroid Build Coastguard Worker     }
223*fb1b10abSAndroid Build Coastguard Worker }
224*fb1b10abSAndroid Build Coastguard Worker 
vp9_cyclic_refresh_update_sb_postencode(VP9_COMP * const cpi,const MODE_INFO * const mi,int mi_row,int mi_col,BLOCK_SIZE bsize)225*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_update_sb_postencode(VP9_COMP *const cpi,
226*fb1b10abSAndroid Build Coastguard Worker                                              const MODE_INFO *const mi,
227*fb1b10abSAndroid Build Coastguard Worker                                              int mi_row, int mi_col,
228*fb1b10abSAndroid Build Coastguard Worker                                              BLOCK_SIZE bsize) {
229*fb1b10abSAndroid Build Coastguard Worker   const VP9_COMMON *const cm = &cpi->common;
230*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
231*fb1b10abSAndroid Build Coastguard Worker   const int bw = num_8x8_blocks_wide_lookup[bsize];
232*fb1b10abSAndroid Build Coastguard Worker   const int bh = num_8x8_blocks_high_lookup[bsize];
233*fb1b10abSAndroid Build Coastguard Worker   const int xmis = VPXMIN(cm->mi_cols - mi_col, bw);
234*fb1b10abSAndroid Build Coastguard Worker   const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
235*fb1b10abSAndroid Build Coastguard Worker   const int block_index = mi_row * cm->mi_cols + mi_col;
236*fb1b10abSAndroid Build Coastguard Worker   int x, y;
237*fb1b10abSAndroid Build Coastguard Worker   for (y = 0; y < ymis; y++)
238*fb1b10abSAndroid Build Coastguard Worker     for (x = 0; x < xmis; x++) {
239*fb1b10abSAndroid Build Coastguard Worker       int map_offset = block_index + y * cm->mi_cols + x;
240*fb1b10abSAndroid Build Coastguard Worker       // Inter skip blocks were clearly not coded at the current qindex, so
241*fb1b10abSAndroid Build Coastguard Worker       // don't update the map for them. For cases where motion is non-zero or
242*fb1b10abSAndroid Build Coastguard Worker       // the reference frame isn't the previous frame, the previous value in
243*fb1b10abSAndroid Build Coastguard Worker       // the map for this spatial location is not entirely correct.
244*fb1b10abSAndroid Build Coastguard Worker       if ((!is_inter_block(mi) || !mi->skip) &&
245*fb1b10abSAndroid Build Coastguard Worker           mi->segment_id <= CR_SEGMENT_ID_BOOST2) {
246*fb1b10abSAndroid Build Coastguard Worker         cr->last_coded_q_map[map_offset] =
247*fb1b10abSAndroid Build Coastguard Worker             clamp(cm->base_qindex + cr->qindex_delta[mi->segment_id], 0, MAXQ);
248*fb1b10abSAndroid Build Coastguard Worker       } else if (is_inter_block(mi) && mi->skip &&
249*fb1b10abSAndroid Build Coastguard Worker                  mi->segment_id <= CR_SEGMENT_ID_BOOST2) {
250*fb1b10abSAndroid Build Coastguard Worker         cr->last_coded_q_map[map_offset] = VPXMIN(
251*fb1b10abSAndroid Build Coastguard Worker             clamp(cm->base_qindex + cr->qindex_delta[mi->segment_id], 0, MAXQ),
252*fb1b10abSAndroid Build Coastguard Worker             cr->last_coded_q_map[map_offset]);
253*fb1b10abSAndroid Build Coastguard Worker       }
254*fb1b10abSAndroid Build Coastguard Worker     }
255*fb1b10abSAndroid Build Coastguard Worker }
256*fb1b10abSAndroid Build Coastguard Worker 
257*fb1b10abSAndroid Build Coastguard Worker // From the just encoded frame: update the actual number of blocks that were
258*fb1b10abSAndroid Build Coastguard Worker // applied the segment delta q, and the amount of low motion in the frame.
259*fb1b10abSAndroid Build Coastguard Worker // Also check conditions for forcing golden update, or preventing golden
260*fb1b10abSAndroid Build Coastguard Worker // update if the period is up.
vp9_cyclic_refresh_postencode(VP9_COMP * const cpi)261*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_postencode(VP9_COMP *const cpi) {
262*fb1b10abSAndroid Build Coastguard Worker   VP9_COMMON *const cm = &cpi->common;
263*fb1b10abSAndroid Build Coastguard Worker   MODE_INFO **mi = cm->mi_grid_visible;
264*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
265*fb1b10abSAndroid Build Coastguard Worker   RATE_CONTROL *const rc = &cpi->rc;
266*fb1b10abSAndroid Build Coastguard Worker   unsigned char *const seg_map = cpi->segmentation_map;
267*fb1b10abSAndroid Build Coastguard Worker   double fraction_low = 0.0;
268*fb1b10abSAndroid Build Coastguard Worker   int force_gf_refresh = 0;
269*fb1b10abSAndroid Build Coastguard Worker   int low_content_frame = 0;
270*fb1b10abSAndroid Build Coastguard Worker   int mi_row, mi_col;
271*fb1b10abSAndroid Build Coastguard Worker   cr->actual_num_seg1_blocks = 0;
272*fb1b10abSAndroid Build Coastguard Worker   cr->actual_num_seg2_blocks = 0;
273*fb1b10abSAndroid Build Coastguard Worker   for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
274*fb1b10abSAndroid Build Coastguard Worker     for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
275*fb1b10abSAndroid Build Coastguard Worker       MV mv = mi[0]->mv[0].as_mv;
276*fb1b10abSAndroid Build Coastguard Worker       int map_index = mi_row * cm->mi_cols + mi_col;
277*fb1b10abSAndroid Build Coastguard Worker       if (cyclic_refresh_segment_id(seg_map[map_index]) == CR_SEGMENT_ID_BOOST1)
278*fb1b10abSAndroid Build Coastguard Worker         cr->actual_num_seg1_blocks++;
279*fb1b10abSAndroid Build Coastguard Worker       else if (cyclic_refresh_segment_id(seg_map[map_index]) ==
280*fb1b10abSAndroid Build Coastguard Worker                CR_SEGMENT_ID_BOOST2)
281*fb1b10abSAndroid Build Coastguard Worker         cr->actual_num_seg2_blocks++;
282*fb1b10abSAndroid Build Coastguard Worker       // Accumulate low_content_frame.
283*fb1b10abSAndroid Build Coastguard Worker       if (is_inter_block(mi[0]) && abs(mv.row) < 16 && abs(mv.col) < 16)
284*fb1b10abSAndroid Build Coastguard Worker         low_content_frame++;
285*fb1b10abSAndroid Build Coastguard Worker       mi++;
286*fb1b10abSAndroid Build Coastguard Worker     }
287*fb1b10abSAndroid Build Coastguard Worker     mi += 8;
288*fb1b10abSAndroid Build Coastguard Worker   }
289*fb1b10abSAndroid Build Coastguard Worker   // Check for golden frame update: only for non-SVC and non-golden boost.
290*fb1b10abSAndroid Build Coastguard Worker   if (!cpi->use_svc && cpi->ext_refresh_frame_flags_pending == 0 &&
291*fb1b10abSAndroid Build Coastguard Worker       !cpi->oxcf.gf_cbr_boost_pct) {
292*fb1b10abSAndroid Build Coastguard Worker     // Force this frame as a golden update frame if this frame changes the
293*fb1b10abSAndroid Build Coastguard Worker     // resolution (resize_pending != 0).
294*fb1b10abSAndroid Build Coastguard Worker     if (cpi->resize_pending != 0) {
295*fb1b10abSAndroid Build Coastguard Worker       vp9_cyclic_refresh_set_golden_update(cpi);
296*fb1b10abSAndroid Build Coastguard Worker       rc->frames_till_gf_update_due = rc->baseline_gf_interval;
297*fb1b10abSAndroid Build Coastguard Worker       if (rc->frames_till_gf_update_due > rc->frames_to_key)
298*fb1b10abSAndroid Build Coastguard Worker         rc->frames_till_gf_update_due = rc->frames_to_key;
299*fb1b10abSAndroid Build Coastguard Worker       cpi->refresh_golden_frame = 1;
300*fb1b10abSAndroid Build Coastguard Worker       force_gf_refresh = 1;
301*fb1b10abSAndroid Build Coastguard Worker     }
302*fb1b10abSAndroid Build Coastguard Worker     // Update average of low content/motion in the frame.
303*fb1b10abSAndroid Build Coastguard Worker     fraction_low = (double)low_content_frame / (cm->mi_rows * cm->mi_cols);
304*fb1b10abSAndroid Build Coastguard Worker     cr->low_content_avg = (fraction_low + 3 * cr->low_content_avg) / 4;
305*fb1b10abSAndroid Build Coastguard Worker     if (!force_gf_refresh && cpi->refresh_golden_frame == 1 &&
306*fb1b10abSAndroid Build Coastguard Worker         rc->frames_since_key > rc->frames_since_golden + 1) {
307*fb1b10abSAndroid Build Coastguard Worker       // Don't update golden reference if the amount of low_content for the
308*fb1b10abSAndroid Build Coastguard Worker       // current encoded frame is small, or if the recursive average of the
309*fb1b10abSAndroid Build Coastguard Worker       // low_content over the update interval window falls below threshold.
310*fb1b10abSAndroid Build Coastguard Worker       if (fraction_low < 0.65 || cr->low_content_avg < 0.6) {
311*fb1b10abSAndroid Build Coastguard Worker         cpi->refresh_golden_frame = 0;
312*fb1b10abSAndroid Build Coastguard Worker       }
313*fb1b10abSAndroid Build Coastguard Worker       // Reset for next internal.
314*fb1b10abSAndroid Build Coastguard Worker       cr->low_content_avg = fraction_low;
315*fb1b10abSAndroid Build Coastguard Worker     }
316*fb1b10abSAndroid Build Coastguard Worker   }
317*fb1b10abSAndroid Build Coastguard Worker }
318*fb1b10abSAndroid Build Coastguard Worker 
319*fb1b10abSAndroid Build Coastguard Worker // Set golden frame update interval, for non-svc 1 pass CBR mode.
vp9_cyclic_refresh_set_golden_update(VP9_COMP * const cpi)320*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_set_golden_update(VP9_COMP *const cpi) {
321*fb1b10abSAndroid Build Coastguard Worker   RATE_CONTROL *const rc = &cpi->rc;
322*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
323*fb1b10abSAndroid Build Coastguard Worker   // Set minimum gf_interval for GF update to a multiple of the refresh period,
324*fb1b10abSAndroid Build Coastguard Worker   // with some max limit. Depending on past encoding stats, GF flag may be
325*fb1b10abSAndroid Build Coastguard Worker   // reset and update may not occur until next baseline_gf_interval.
326*fb1b10abSAndroid Build Coastguard Worker   if (cr->percent_refresh > 0)
327*fb1b10abSAndroid Build Coastguard Worker     rc->baseline_gf_interval = VPXMIN(4 * (100 / cr->percent_refresh), 40);
328*fb1b10abSAndroid Build Coastguard Worker   else
329*fb1b10abSAndroid Build Coastguard Worker     rc->baseline_gf_interval = 40;
330*fb1b10abSAndroid Build Coastguard Worker   if (cpi->oxcf.rc_mode == VPX_VBR) rc->baseline_gf_interval = 20;
331*fb1b10abSAndroid Build Coastguard Worker   if (rc->avg_frame_low_motion < 50 && rc->frames_since_key > 40 &&
332*fb1b10abSAndroid Build Coastguard Worker       cr->content_mode)
333*fb1b10abSAndroid Build Coastguard Worker     rc->baseline_gf_interval = 10;
334*fb1b10abSAndroid Build Coastguard Worker }
335*fb1b10abSAndroid Build Coastguard Worker 
is_superblock_flat_static(VP9_COMP * const cpi,int sb_row_index,int sb_col_index)336*fb1b10abSAndroid Build Coastguard Worker static int is_superblock_flat_static(VP9_COMP *const cpi, int sb_row_index,
337*fb1b10abSAndroid Build Coastguard Worker                                      int sb_col_index) {
338*fb1b10abSAndroid Build Coastguard Worker   unsigned int source_variance;
339*fb1b10abSAndroid Build Coastguard Worker   const uint8_t *src_y = cpi->Source->y_buffer;
340*fb1b10abSAndroid Build Coastguard Worker   const int ystride = cpi->Source->y_stride;
341*fb1b10abSAndroid Build Coastguard Worker   unsigned int sse;
342*fb1b10abSAndroid Build Coastguard Worker   const BLOCK_SIZE bsize = BLOCK_64X64;
343*fb1b10abSAndroid Build Coastguard Worker   src_y += (sb_row_index << 6) * ystride + (sb_col_index << 6);
344*fb1b10abSAndroid Build Coastguard Worker   source_variance =
345*fb1b10abSAndroid Build Coastguard Worker       cpi->fn_ptr[bsize].vf(src_y, ystride, VP9_VAR_OFFS, 0, &sse);
346*fb1b10abSAndroid Build Coastguard Worker   if (source_variance == 0) {
347*fb1b10abSAndroid Build Coastguard Worker     uint64_t block_sad;
348*fb1b10abSAndroid Build Coastguard Worker     const uint8_t *last_src_y = cpi->Last_Source->y_buffer;
349*fb1b10abSAndroid Build Coastguard Worker     const int last_ystride = cpi->Last_Source->y_stride;
350*fb1b10abSAndroid Build Coastguard Worker     last_src_y += (sb_row_index << 6) * ystride + (sb_col_index << 6);
351*fb1b10abSAndroid Build Coastguard Worker     block_sad =
352*fb1b10abSAndroid Build Coastguard Worker         cpi->fn_ptr[bsize].sdf(src_y, ystride, last_src_y, last_ystride);
353*fb1b10abSAndroid Build Coastguard Worker     if (block_sad == 0) return 1;
354*fb1b10abSAndroid Build Coastguard Worker   }
355*fb1b10abSAndroid Build Coastguard Worker   return 0;
356*fb1b10abSAndroid Build Coastguard Worker }
357*fb1b10abSAndroid Build Coastguard Worker 
358*fb1b10abSAndroid Build Coastguard Worker // Update the segmentation map, and related quantities: cyclic refresh map,
359*fb1b10abSAndroid Build Coastguard Worker // refresh sb_index, and target number of blocks to be refreshed.
360*fb1b10abSAndroid Build Coastguard Worker // The map is set to either 0/CR_SEGMENT_ID_BASE (no refresh) or to
361*fb1b10abSAndroid Build Coastguard Worker // 1/CR_SEGMENT_ID_BOOST1 (refresh) for each superblock.
362*fb1b10abSAndroid Build Coastguard Worker // Blocks labeled as BOOST1 may later get set to BOOST2 (during the
363*fb1b10abSAndroid Build Coastguard Worker // encoding of the superblock).
cyclic_refresh_update_map(VP9_COMP * const cpi)364*fb1b10abSAndroid Build Coastguard Worker static void cyclic_refresh_update_map(VP9_COMP *const cpi) {
365*fb1b10abSAndroid Build Coastguard Worker   VP9_COMMON *const cm = &cpi->common;
366*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
367*fb1b10abSAndroid Build Coastguard Worker   unsigned char *const seg_map = cpi->segmentation_map;
368*fb1b10abSAndroid Build Coastguard Worker   int i, block_count, bl_index, sb_rows, sb_cols, sbs_in_frame;
369*fb1b10abSAndroid Build Coastguard Worker   int xmis, ymis, x, y;
370*fb1b10abSAndroid Build Coastguard Worker   int consec_zero_mv_thresh = 0;
371*fb1b10abSAndroid Build Coastguard Worker   int qindex_thresh = 0;
372*fb1b10abSAndroid Build Coastguard Worker   int count_sel = 0;
373*fb1b10abSAndroid Build Coastguard Worker   int count_tot = 0;
374*fb1b10abSAndroid Build Coastguard Worker   memset(seg_map, CR_SEGMENT_ID_BASE, cm->mi_rows * cm->mi_cols);
375*fb1b10abSAndroid Build Coastguard Worker   sb_cols = (cm->mi_cols + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
376*fb1b10abSAndroid Build Coastguard Worker   sb_rows = (cm->mi_rows + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
377*fb1b10abSAndroid Build Coastguard Worker   sbs_in_frame = sb_cols * sb_rows;
378*fb1b10abSAndroid Build Coastguard Worker   // Number of target blocks to get the q delta (segment 1).
379*fb1b10abSAndroid Build Coastguard Worker   block_count = cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100;
380*fb1b10abSAndroid Build Coastguard Worker   // Set the segmentation map: cycle through the superblocks, starting at
381*fb1b10abSAndroid Build Coastguard Worker   // cr->mb_index, and stopping when either block_count blocks have been found
382*fb1b10abSAndroid Build Coastguard Worker   // to be refreshed, or we have passed through whole frame.
383*fb1b10abSAndroid Build Coastguard Worker   assert(cr->sb_index < sbs_in_frame);
384*fb1b10abSAndroid Build Coastguard Worker   i = cr->sb_index;
385*fb1b10abSAndroid Build Coastguard Worker   cr->target_num_seg_blocks = 0;
386*fb1b10abSAndroid Build Coastguard Worker   if (cpi->oxcf.content != VP9E_CONTENT_SCREEN) {
387*fb1b10abSAndroid Build Coastguard Worker     consec_zero_mv_thresh = 100;
388*fb1b10abSAndroid Build Coastguard Worker   }
389*fb1b10abSAndroid Build Coastguard Worker   qindex_thresh =
390*fb1b10abSAndroid Build Coastguard Worker       cpi->oxcf.content == VP9E_CONTENT_SCREEN
391*fb1b10abSAndroid Build Coastguard Worker           ? vp9_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST2, cm->base_qindex)
392*fb1b10abSAndroid Build Coastguard Worker           : vp9_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST1, cm->base_qindex);
393*fb1b10abSAndroid Build Coastguard Worker   // More aggressive settings for noisy content.
394*fb1b10abSAndroid Build Coastguard Worker   if (cpi->noise_estimate.enabled && cpi->noise_estimate.level >= kMedium &&
395*fb1b10abSAndroid Build Coastguard Worker       cr->content_mode) {
396*fb1b10abSAndroid Build Coastguard Worker     consec_zero_mv_thresh = 60;
397*fb1b10abSAndroid Build Coastguard Worker     qindex_thresh =
398*fb1b10abSAndroid Build Coastguard Worker         VPXMAX(vp9_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST1, cm->base_qindex),
399*fb1b10abSAndroid Build Coastguard Worker                cm->base_qindex);
400*fb1b10abSAndroid Build Coastguard Worker   }
401*fb1b10abSAndroid Build Coastguard Worker   do {
402*fb1b10abSAndroid Build Coastguard Worker     int sum_map = 0;
403*fb1b10abSAndroid Build Coastguard Worker     int consec_zero_mv_thresh_block = consec_zero_mv_thresh;
404*fb1b10abSAndroid Build Coastguard Worker     // Get the mi_row/mi_col corresponding to superblock index i.
405*fb1b10abSAndroid Build Coastguard Worker     int sb_row_index = (i / sb_cols);
406*fb1b10abSAndroid Build Coastguard Worker     int sb_col_index = i - sb_row_index * sb_cols;
407*fb1b10abSAndroid Build Coastguard Worker     int mi_row = sb_row_index * MI_BLOCK_SIZE;
408*fb1b10abSAndroid Build Coastguard Worker     int mi_col = sb_col_index * MI_BLOCK_SIZE;
409*fb1b10abSAndroid Build Coastguard Worker     int flat_static_blocks = 0;
410*fb1b10abSAndroid Build Coastguard Worker     int compute_content = 1;
411*fb1b10abSAndroid Build Coastguard Worker     assert(mi_row >= 0 && mi_row < cm->mi_rows);
412*fb1b10abSAndroid Build Coastguard Worker     assert(mi_col >= 0 && mi_col < cm->mi_cols);
413*fb1b10abSAndroid Build Coastguard Worker #if CONFIG_VP9_HIGHBITDEPTH
414*fb1b10abSAndroid Build Coastguard Worker     if (cpi->common.use_highbitdepth) compute_content = 0;
415*fb1b10abSAndroid Build Coastguard Worker #endif
416*fb1b10abSAndroid Build Coastguard Worker     if (cr->content_mode == 0 || cpi->Last_Source == NULL ||
417*fb1b10abSAndroid Build Coastguard Worker         cpi->Last_Source->y_width != cpi->Source->y_width ||
418*fb1b10abSAndroid Build Coastguard Worker         cpi->Last_Source->y_height != cpi->Source->y_height)
419*fb1b10abSAndroid Build Coastguard Worker       compute_content = 0;
420*fb1b10abSAndroid Build Coastguard Worker     bl_index = mi_row * cm->mi_cols + mi_col;
421*fb1b10abSAndroid Build Coastguard Worker     // Loop through all 8x8 blocks in superblock and update map.
422*fb1b10abSAndroid Build Coastguard Worker     xmis =
423*fb1b10abSAndroid Build Coastguard Worker         VPXMIN(cm->mi_cols - mi_col, num_8x8_blocks_wide_lookup[BLOCK_64X64]);
424*fb1b10abSAndroid Build Coastguard Worker     ymis =
425*fb1b10abSAndroid Build Coastguard Worker         VPXMIN(cm->mi_rows - mi_row, num_8x8_blocks_high_lookup[BLOCK_64X64]);
426*fb1b10abSAndroid Build Coastguard Worker     if (cpi->noise_estimate.enabled && cpi->noise_estimate.level >= kMedium &&
427*fb1b10abSAndroid Build Coastguard Worker         (xmis <= 2 || ymis <= 2))
428*fb1b10abSAndroid Build Coastguard Worker       consec_zero_mv_thresh_block = 4;
429*fb1b10abSAndroid Build Coastguard Worker     for (y = 0; y < ymis; y++) {
430*fb1b10abSAndroid Build Coastguard Worker       for (x = 0; x < xmis; x++) {
431*fb1b10abSAndroid Build Coastguard Worker         const int bl_index2 = bl_index + y * cm->mi_cols + x;
432*fb1b10abSAndroid Build Coastguard Worker         // If the block is as a candidate for clean up then mark it
433*fb1b10abSAndroid Build Coastguard Worker         // for possible boost/refresh (segment 1). The segment id may get
434*fb1b10abSAndroid Build Coastguard Worker         // reset to 0 later depending on the coding mode.
435*fb1b10abSAndroid Build Coastguard Worker         if (cr->map[bl_index2] == 0) {
436*fb1b10abSAndroid Build Coastguard Worker           count_tot++;
437*fb1b10abSAndroid Build Coastguard Worker           if (cr->content_mode == 0 ||
438*fb1b10abSAndroid Build Coastguard Worker               cr->last_coded_q_map[bl_index2] > qindex_thresh ||
439*fb1b10abSAndroid Build Coastguard Worker               cpi->consec_zero_mv[bl_index2] < consec_zero_mv_thresh_block) {
440*fb1b10abSAndroid Build Coastguard Worker             sum_map++;
441*fb1b10abSAndroid Build Coastguard Worker             count_sel++;
442*fb1b10abSAndroid Build Coastguard Worker           }
443*fb1b10abSAndroid Build Coastguard Worker         } else if (cr->map[bl_index2] < 0) {
444*fb1b10abSAndroid Build Coastguard Worker           cr->map[bl_index2]++;
445*fb1b10abSAndroid Build Coastguard Worker         }
446*fb1b10abSAndroid Build Coastguard Worker       }
447*fb1b10abSAndroid Build Coastguard Worker     }
448*fb1b10abSAndroid Build Coastguard Worker     // Enforce constant segment over superblock.
449*fb1b10abSAndroid Build Coastguard Worker     // If segment is at least half of superblock, set to 1.
450*fb1b10abSAndroid Build Coastguard Worker     if (sum_map >= xmis * ymis / 2) {
451*fb1b10abSAndroid Build Coastguard Worker       // This superblock is a candidate for refresh:
452*fb1b10abSAndroid Build Coastguard Worker       // compute spatial variance and exclude blocks that are spatially flat
453*fb1b10abSAndroid Build Coastguard Worker       // and stationary. Note: this is currently only done for screne content
454*fb1b10abSAndroid Build Coastguard Worker       // mode.
455*fb1b10abSAndroid Build Coastguard Worker       if (compute_content && cr->skip_flat_static_blocks)
456*fb1b10abSAndroid Build Coastguard Worker         flat_static_blocks =
457*fb1b10abSAndroid Build Coastguard Worker             is_superblock_flat_static(cpi, sb_row_index, sb_col_index);
458*fb1b10abSAndroid Build Coastguard Worker       if (!flat_static_blocks) {
459*fb1b10abSAndroid Build Coastguard Worker         // Label this superblock as segment 1.
460*fb1b10abSAndroid Build Coastguard Worker         for (y = 0; y < ymis; y++)
461*fb1b10abSAndroid Build Coastguard Worker           for (x = 0; x < xmis; x++) {
462*fb1b10abSAndroid Build Coastguard Worker             seg_map[bl_index + y * cm->mi_cols + x] = CR_SEGMENT_ID_BOOST1;
463*fb1b10abSAndroid Build Coastguard Worker           }
464*fb1b10abSAndroid Build Coastguard Worker         cr->target_num_seg_blocks += xmis * ymis;
465*fb1b10abSAndroid Build Coastguard Worker       }
466*fb1b10abSAndroid Build Coastguard Worker     }
467*fb1b10abSAndroid Build Coastguard Worker     i++;
468*fb1b10abSAndroid Build Coastguard Worker     if (i == sbs_in_frame) {
469*fb1b10abSAndroid Build Coastguard Worker       i = 0;
470*fb1b10abSAndroid Build Coastguard Worker     }
471*fb1b10abSAndroid Build Coastguard Worker   } while (cr->target_num_seg_blocks < block_count && i != cr->sb_index);
472*fb1b10abSAndroid Build Coastguard Worker   cr->sb_index = i;
473*fb1b10abSAndroid Build Coastguard Worker   cr->reduce_refresh = 0;
474*fb1b10abSAndroid Build Coastguard Worker   if (cpi->oxcf.content != VP9E_CONTENT_SCREEN)
475*fb1b10abSAndroid Build Coastguard Worker     if (count_sel < (3 * count_tot) >> 2) cr->reduce_refresh = 1;
476*fb1b10abSAndroid Build Coastguard Worker }
477*fb1b10abSAndroid Build Coastguard Worker 
478*fb1b10abSAndroid Build Coastguard Worker // Set cyclic refresh parameters.
vp9_cyclic_refresh_update_parameters(VP9_COMP * const cpi)479*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_update_parameters(VP9_COMP *const cpi) {
480*fb1b10abSAndroid Build Coastguard Worker   const RATE_CONTROL *const rc = &cpi->rc;
481*fb1b10abSAndroid Build Coastguard Worker   const VP9_COMMON *const cm = &cpi->common;
482*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
483*fb1b10abSAndroid Build Coastguard Worker   int num8x8bl = cm->MBs << 2;
484*fb1b10abSAndroid Build Coastguard Worker   int target_refresh = 0;
485*fb1b10abSAndroid Build Coastguard Worker   double weight_segment_target = 0;
486*fb1b10abSAndroid Build Coastguard Worker   double weight_segment = 0;
487*fb1b10abSAndroid Build Coastguard Worker   int thresh_low_motion = 20;
488*fb1b10abSAndroid Build Coastguard Worker   int qp_thresh = VPXMIN((cpi->oxcf.content == VP9E_CONTENT_SCREEN) ? 35 : 20,
489*fb1b10abSAndroid Build Coastguard Worker                          rc->best_quality << 1);
490*fb1b10abSAndroid Build Coastguard Worker   int qp_max_thresh = 117 * MAXQ >> 7;
491*fb1b10abSAndroid Build Coastguard Worker   cr->apply_cyclic_refresh = 1;
492*fb1b10abSAndroid Build Coastguard Worker   if (frame_is_intra_only(cm) || cpi->svc.temporal_layer_id > 0 ||
493*fb1b10abSAndroid Build Coastguard Worker       is_lossless_requested(&cpi->oxcf) ||
494*fb1b10abSAndroid Build Coastguard Worker       rc->avg_frame_qindex[INTER_FRAME] < qp_thresh ||
495*fb1b10abSAndroid Build Coastguard Worker       (cpi->use_svc &&
496*fb1b10abSAndroid Build Coastguard Worker        cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) ||
497*fb1b10abSAndroid Build Coastguard Worker       (!cpi->use_svc && cr->content_mode &&
498*fb1b10abSAndroid Build Coastguard Worker        rc->avg_frame_low_motion < thresh_low_motion &&
499*fb1b10abSAndroid Build Coastguard Worker        rc->frames_since_key > 40) ||
500*fb1b10abSAndroid Build Coastguard Worker       (!cpi->use_svc && rc->avg_frame_qindex[INTER_FRAME] > qp_max_thresh &&
501*fb1b10abSAndroid Build Coastguard Worker        rc->frames_since_key > 20) ||
502*fb1b10abSAndroid Build Coastguard Worker       (cpi->roi.enabled && cpi->roi.skip[BACKGROUND_SEG_SKIP_ID] &&
503*fb1b10abSAndroid Build Coastguard Worker        rc->frames_since_key > FRAMES_NO_SKIPPING_AFTER_KEY)) {
504*fb1b10abSAndroid Build Coastguard Worker     cr->apply_cyclic_refresh = 0;
505*fb1b10abSAndroid Build Coastguard Worker     return;
506*fb1b10abSAndroid Build Coastguard Worker   }
507*fb1b10abSAndroid Build Coastguard Worker   cr->percent_refresh = 10;
508*fb1b10abSAndroid Build Coastguard Worker   if (cr->reduce_refresh) cr->percent_refresh = 5;
509*fb1b10abSAndroid Build Coastguard Worker   cr->max_qdelta_perc = 60;
510*fb1b10abSAndroid Build Coastguard Worker   cr->time_for_refresh = 0;
511*fb1b10abSAndroid Build Coastguard Worker   cr->motion_thresh = 32;
512*fb1b10abSAndroid Build Coastguard Worker   cr->rate_boost_fac = 15;
513*fb1b10abSAndroid Build Coastguard Worker   // Use larger delta-qp (increase rate_ratio_qdelta) for first few (~4)
514*fb1b10abSAndroid Build Coastguard Worker   // periods of the refresh cycle, after a key frame.
515*fb1b10abSAndroid Build Coastguard Worker   // Account for larger interval on base layer for temporal layers.
516*fb1b10abSAndroid Build Coastguard Worker   if (cr->percent_refresh > 0 &&
517*fb1b10abSAndroid Build Coastguard Worker       rc->frames_since_key <
518*fb1b10abSAndroid Build Coastguard Worker           (4 * cpi->svc.number_temporal_layers) * (100 / cr->percent_refresh)) {
519*fb1b10abSAndroid Build Coastguard Worker     cr->rate_ratio_qdelta = 3.0;
520*fb1b10abSAndroid Build Coastguard Worker   } else {
521*fb1b10abSAndroid Build Coastguard Worker     cr->rate_ratio_qdelta = 2.0;
522*fb1b10abSAndroid Build Coastguard Worker     if (cr->content_mode && cpi->noise_estimate.enabled &&
523*fb1b10abSAndroid Build Coastguard Worker         cpi->noise_estimate.level >= kMedium) {
524*fb1b10abSAndroid Build Coastguard Worker       // Reduce the delta-qp if the estimated source noise is above threshold.
525*fb1b10abSAndroid Build Coastguard Worker       cr->rate_ratio_qdelta = 1.7;
526*fb1b10abSAndroid Build Coastguard Worker       cr->rate_boost_fac = 13;
527*fb1b10abSAndroid Build Coastguard Worker     }
528*fb1b10abSAndroid Build Coastguard Worker   }
529*fb1b10abSAndroid Build Coastguard Worker   // For screen-content: keep rate_ratio_qdelta to 2.0 (segment#1 boost) and
530*fb1b10abSAndroid Build Coastguard Worker   // percent_refresh (refresh rate) to 10. But reduce rate boost for segment#2
531*fb1b10abSAndroid Build Coastguard Worker   // (rate_boost_fac = 10 disables segment#2).
532*fb1b10abSAndroid Build Coastguard Worker   if (cpi->oxcf.content == VP9E_CONTENT_SCREEN) {
533*fb1b10abSAndroid Build Coastguard Worker     // Only enable feature of skipping flat_static blocks for top layer
534*fb1b10abSAndroid Build Coastguard Worker     // under screen content mode.
535*fb1b10abSAndroid Build Coastguard Worker     if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1)
536*fb1b10abSAndroid Build Coastguard Worker       cr->skip_flat_static_blocks = 1;
537*fb1b10abSAndroid Build Coastguard Worker     cr->percent_refresh = (cr->skip_flat_static_blocks) ? 5 : 10;
538*fb1b10abSAndroid Build Coastguard Worker     // Increase the amount of refresh on scene change that is encoded at max Q,
539*fb1b10abSAndroid Build Coastguard Worker     // increase for a few cycles of the refresh period (~100 / percent_refresh).
540*fb1b10abSAndroid Build Coastguard Worker     if (cr->content_mode && cr->counter_encode_maxq_scene_change < 30)
541*fb1b10abSAndroid Build Coastguard Worker       cr->percent_refresh = (cr->skip_flat_static_blocks) ? 10 : 15;
542*fb1b10abSAndroid Build Coastguard Worker     cr->rate_ratio_qdelta = 2.0;
543*fb1b10abSAndroid Build Coastguard Worker     cr->rate_boost_fac = 10;
544*fb1b10abSAndroid Build Coastguard Worker   }
545*fb1b10abSAndroid Build Coastguard Worker   // Adjust some parameters for low resolutions.
546*fb1b10abSAndroid Build Coastguard Worker   if (cm->width * cm->height <= 352 * 288) {
547*fb1b10abSAndroid Build Coastguard Worker     if (rc->avg_frame_bandwidth < 3000) {
548*fb1b10abSAndroid Build Coastguard Worker       cr->motion_thresh = 64;
549*fb1b10abSAndroid Build Coastguard Worker       cr->rate_boost_fac = 13;
550*fb1b10abSAndroid Build Coastguard Worker     } else {
551*fb1b10abSAndroid Build Coastguard Worker       cr->max_qdelta_perc = 70;
552*fb1b10abSAndroid Build Coastguard Worker       cr->rate_ratio_qdelta = VPXMAX(cr->rate_ratio_qdelta, 2.5);
553*fb1b10abSAndroid Build Coastguard Worker     }
554*fb1b10abSAndroid Build Coastguard Worker   }
555*fb1b10abSAndroid Build Coastguard Worker   if (cpi->oxcf.rc_mode == VPX_VBR) {
556*fb1b10abSAndroid Build Coastguard Worker     // To be adjusted for VBR mode, e.g., based on gf period and boost.
557*fb1b10abSAndroid Build Coastguard Worker     // For now use smaller qp-delta (than CBR), no second boosted seg, and
558*fb1b10abSAndroid Build Coastguard Worker     // turn-off (no refresh) on golden refresh (since it's already boosted).
559*fb1b10abSAndroid Build Coastguard Worker     cr->percent_refresh = 10;
560*fb1b10abSAndroid Build Coastguard Worker     cr->rate_ratio_qdelta = 1.5;
561*fb1b10abSAndroid Build Coastguard Worker     cr->rate_boost_fac = 10;
562*fb1b10abSAndroid Build Coastguard Worker     if (cpi->refresh_golden_frame == 1 && !cpi->use_svc) {
563*fb1b10abSAndroid Build Coastguard Worker       cr->percent_refresh = 0;
564*fb1b10abSAndroid Build Coastguard Worker       cr->rate_ratio_qdelta = 1.0;
565*fb1b10abSAndroid Build Coastguard Worker     }
566*fb1b10abSAndroid Build Coastguard Worker   }
567*fb1b10abSAndroid Build Coastguard Worker   // Weight for segment prior to encoding: take the average of the target
568*fb1b10abSAndroid Build Coastguard Worker   // number for the frame to be encoded and the actual from the previous frame.
569*fb1b10abSAndroid Build Coastguard Worker   // Use the target if its less. To be used for setting the base qp for the
570*fb1b10abSAndroid Build Coastguard Worker   // frame in vp9_rc_regulate_q.
571*fb1b10abSAndroid Build Coastguard Worker   target_refresh = cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100;
572*fb1b10abSAndroid Build Coastguard Worker   weight_segment_target = (double)(target_refresh) / num8x8bl;
573*fb1b10abSAndroid Build Coastguard Worker   weight_segment = (double)((target_refresh + cr->actual_num_seg1_blocks +
574*fb1b10abSAndroid Build Coastguard Worker                              cr->actual_num_seg2_blocks) >>
575*fb1b10abSAndroid Build Coastguard Worker                             1) /
576*fb1b10abSAndroid Build Coastguard Worker                    num8x8bl;
577*fb1b10abSAndroid Build Coastguard Worker   if (weight_segment_target < 7 * weight_segment / 8)
578*fb1b10abSAndroid Build Coastguard Worker     weight_segment = weight_segment_target;
579*fb1b10abSAndroid Build Coastguard Worker   // For screen-content: don't include target for the weight segment,
580*fb1b10abSAndroid Build Coastguard Worker   // since for all flat areas the segment is reset, so its more accurate
581*fb1b10abSAndroid Build Coastguard Worker   // to just use the previous actual number of seg blocks for the weight.
582*fb1b10abSAndroid Build Coastguard Worker   if (cpi->oxcf.content == VP9E_CONTENT_SCREEN)
583*fb1b10abSAndroid Build Coastguard Worker     weight_segment =
584*fb1b10abSAndroid Build Coastguard Worker         (double)(cr->actual_num_seg1_blocks + cr->actual_num_seg2_blocks) /
585*fb1b10abSAndroid Build Coastguard Worker         num8x8bl;
586*fb1b10abSAndroid Build Coastguard Worker   cr->weight_segment = weight_segment;
587*fb1b10abSAndroid Build Coastguard Worker   if (cr->content_mode == 0) {
588*fb1b10abSAndroid Build Coastguard Worker     cr->actual_num_seg1_blocks =
589*fb1b10abSAndroid Build Coastguard Worker         cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100;
590*fb1b10abSAndroid Build Coastguard Worker     cr->actual_num_seg2_blocks = 0;
591*fb1b10abSAndroid Build Coastguard Worker     cr->weight_segment = (double)(cr->actual_num_seg1_blocks) / num8x8bl;
592*fb1b10abSAndroid Build Coastguard Worker   }
593*fb1b10abSAndroid Build Coastguard Worker }
594*fb1b10abSAndroid Build Coastguard Worker 
595*fb1b10abSAndroid Build Coastguard Worker // Setup cyclic background refresh: set delta q and segmentation map.
vp9_cyclic_refresh_setup(VP9_COMP * const cpi)596*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) {
597*fb1b10abSAndroid Build Coastguard Worker   VP9_COMMON *const cm = &cpi->common;
598*fb1b10abSAndroid Build Coastguard Worker   const RATE_CONTROL *const rc = &cpi->rc;
599*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
600*fb1b10abSAndroid Build Coastguard Worker   struct segmentation *const seg = &cm->seg;
601*fb1b10abSAndroid Build Coastguard Worker   int scene_change_detected =
602*fb1b10abSAndroid Build Coastguard Worker       cpi->rc.high_source_sad ||
603*fb1b10abSAndroid Build Coastguard Worker       (cpi->use_svc && cpi->svc.high_source_sad_superframe);
604*fb1b10abSAndroid Build Coastguard Worker   if (cm->current_video_frame == 0) cr->low_content_avg = 0.0;
605*fb1b10abSAndroid Build Coastguard Worker   // Reset if resoluton change has occurred.
606*fb1b10abSAndroid Build Coastguard Worker   if (cpi->resize_pending != 0) vp9_cyclic_refresh_reset_resize(cpi);
607*fb1b10abSAndroid Build Coastguard Worker   if (!cr->apply_cyclic_refresh || (cpi->force_update_segmentation) ||
608*fb1b10abSAndroid Build Coastguard Worker       scene_change_detected) {
609*fb1b10abSAndroid Build Coastguard Worker     // Set segmentation map to 0 and disable.
610*fb1b10abSAndroid Build Coastguard Worker     unsigned char *const seg_map = cpi->segmentation_map;
611*fb1b10abSAndroid Build Coastguard Worker     memset(seg_map, 0, cm->mi_rows * cm->mi_cols);
612*fb1b10abSAndroid Build Coastguard Worker     vp9_disable_segmentation(&cm->seg);
613*fb1b10abSAndroid Build Coastguard Worker     if (cm->frame_type == KEY_FRAME || scene_change_detected) {
614*fb1b10abSAndroid Build Coastguard Worker       memset(cr->last_coded_q_map, MAXQ,
615*fb1b10abSAndroid Build Coastguard Worker              cm->mi_rows * cm->mi_cols * sizeof(*cr->last_coded_q_map));
616*fb1b10abSAndroid Build Coastguard Worker       cr->sb_index = 0;
617*fb1b10abSAndroid Build Coastguard Worker       cr->reduce_refresh = 0;
618*fb1b10abSAndroid Build Coastguard Worker       cr->counter_encode_maxq_scene_change = 0;
619*fb1b10abSAndroid Build Coastguard Worker     }
620*fb1b10abSAndroid Build Coastguard Worker     return;
621*fb1b10abSAndroid Build Coastguard Worker   } else {
622*fb1b10abSAndroid Build Coastguard Worker     int qindex_delta = 0;
623*fb1b10abSAndroid Build Coastguard Worker     int qindex2;
624*fb1b10abSAndroid Build Coastguard Worker     const double q = vp9_convert_qindex_to_q(cm->base_qindex, cm->bit_depth);
625*fb1b10abSAndroid Build Coastguard Worker     cr->counter_encode_maxq_scene_change++;
626*fb1b10abSAndroid Build Coastguard Worker     vpx_clear_system_state();
627*fb1b10abSAndroid Build Coastguard Worker     // Set rate threshold to some multiple (set to 2 for now) of the target
628*fb1b10abSAndroid Build Coastguard Worker     // rate (target is given by sb64_target_rate and scaled by 256).
629*fb1b10abSAndroid Build Coastguard Worker     cr->thresh_rate_sb = ((int64_t)(rc->sb64_target_rate) << 8) << 2;
630*fb1b10abSAndroid Build Coastguard Worker     // Distortion threshold, quadratic in Q, scale factor to be adjusted.
631*fb1b10abSAndroid Build Coastguard Worker     // q will not exceed 457, so (q * q) is within 32bit; see:
632*fb1b10abSAndroid Build Coastguard Worker     // vp9_convert_qindex_to_q(), vp9_ac_quant(), ac_qlookup*[].
633*fb1b10abSAndroid Build Coastguard Worker     cr->thresh_dist_sb = ((int64_t)(q * q)) << 2;
634*fb1b10abSAndroid Build Coastguard Worker 
635*fb1b10abSAndroid Build Coastguard Worker     // Set up segmentation.
636*fb1b10abSAndroid Build Coastguard Worker     // Clear down the segment map.
637*fb1b10abSAndroid Build Coastguard Worker     vp9_enable_segmentation(&cm->seg);
638*fb1b10abSAndroid Build Coastguard Worker     vp9_clearall_segfeatures(seg);
639*fb1b10abSAndroid Build Coastguard Worker     // Select delta coding method.
640*fb1b10abSAndroid Build Coastguard Worker     seg->abs_delta = SEGMENT_DELTADATA;
641*fb1b10abSAndroid Build Coastguard Worker 
642*fb1b10abSAndroid Build Coastguard Worker     // Note: setting temporal_update has no effect, as the seg-map coding method
643*fb1b10abSAndroid Build Coastguard Worker     // (temporal or spatial) is determined in vp9_choose_segmap_coding_method(),
644*fb1b10abSAndroid Build Coastguard Worker     // based on the coding cost of each method. For error_resilient mode on the
645*fb1b10abSAndroid Build Coastguard Worker     // last_frame_seg_map is set to 0, so if temporal coding is used, it is
646*fb1b10abSAndroid Build Coastguard Worker     // relative to 0 previous map.
647*fb1b10abSAndroid Build Coastguard Worker     // seg->temporal_update = 0;
648*fb1b10abSAndroid Build Coastguard Worker 
649*fb1b10abSAndroid Build Coastguard Worker     // Segment BASE "Q" feature is disabled so it defaults to the baseline Q.
650*fb1b10abSAndroid Build Coastguard Worker     vp9_disable_segfeature(seg, CR_SEGMENT_ID_BASE, SEG_LVL_ALT_Q);
651*fb1b10abSAndroid Build Coastguard Worker     // Use segment BOOST1 for in-frame Q adjustment.
652*fb1b10abSAndroid Build Coastguard Worker     vp9_enable_segfeature(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q);
653*fb1b10abSAndroid Build Coastguard Worker     // Use segment BOOST2 for more aggressive in-frame Q adjustment.
654*fb1b10abSAndroid Build Coastguard Worker     vp9_enable_segfeature(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q);
655*fb1b10abSAndroid Build Coastguard Worker 
656*fb1b10abSAndroid Build Coastguard Worker     // Set the q delta for segment BOOST1.
657*fb1b10abSAndroid Build Coastguard Worker     qindex_delta = compute_deltaq(cpi, cm->base_qindex, cr->rate_ratio_qdelta);
658*fb1b10abSAndroid Build Coastguard Worker     cr->qindex_delta[1] = qindex_delta;
659*fb1b10abSAndroid Build Coastguard Worker 
660*fb1b10abSAndroid Build Coastguard Worker     // Compute rd-mult for segment BOOST1.
661*fb1b10abSAndroid Build Coastguard Worker     qindex2 = clamp(cm->base_qindex + cm->y_dc_delta_q + qindex_delta, 0, MAXQ);
662*fb1b10abSAndroid Build Coastguard Worker 
663*fb1b10abSAndroid Build Coastguard Worker     cr->rdmult = vp9_compute_rd_mult(cpi, qindex2);
664*fb1b10abSAndroid Build Coastguard Worker 
665*fb1b10abSAndroid Build Coastguard Worker     vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q, qindex_delta);
666*fb1b10abSAndroid Build Coastguard Worker 
667*fb1b10abSAndroid Build Coastguard Worker     // Set a more aggressive (higher) q delta for segment BOOST2.
668*fb1b10abSAndroid Build Coastguard Worker     qindex_delta = compute_deltaq(
669*fb1b10abSAndroid Build Coastguard Worker         cpi, cm->base_qindex,
670*fb1b10abSAndroid Build Coastguard Worker         VPXMIN(CR_MAX_RATE_TARGET_RATIO,
671*fb1b10abSAndroid Build Coastguard Worker                0.1 * cr->rate_boost_fac * cr->rate_ratio_qdelta));
672*fb1b10abSAndroid Build Coastguard Worker     cr->qindex_delta[2] = qindex_delta;
673*fb1b10abSAndroid Build Coastguard Worker     vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q, qindex_delta);
674*fb1b10abSAndroid Build Coastguard Worker 
675*fb1b10abSAndroid Build Coastguard Worker     // Update the segmentation and refresh map.
676*fb1b10abSAndroid Build Coastguard Worker     cyclic_refresh_update_map(cpi);
677*fb1b10abSAndroid Build Coastguard Worker   }
678*fb1b10abSAndroid Build Coastguard Worker }
679*fb1b10abSAndroid Build Coastguard Worker 
vp9_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH * cr)680*fb1b10abSAndroid Build Coastguard Worker int vp9_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH *cr) {
681*fb1b10abSAndroid Build Coastguard Worker   return cr->rdmult;
682*fb1b10abSAndroid Build Coastguard Worker }
683*fb1b10abSAndroid Build Coastguard Worker 
vp9_cyclic_refresh_reset_resize(VP9_COMP * const cpi)684*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_reset_resize(VP9_COMP *const cpi) {
685*fb1b10abSAndroid Build Coastguard Worker   const VP9_COMMON *const cm = &cpi->common;
686*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
687*fb1b10abSAndroid Build Coastguard Worker   memset(cr->map, 0, cm->mi_rows * cm->mi_cols);
688*fb1b10abSAndroid Build Coastguard Worker   memset(cr->last_coded_q_map, MAXQ,
689*fb1b10abSAndroid Build Coastguard Worker          cm->mi_rows * cm->mi_cols * sizeof(*cr->last_coded_q_map));
690*fb1b10abSAndroid Build Coastguard Worker   cr->sb_index = 0;
691*fb1b10abSAndroid Build Coastguard Worker   cpi->refresh_golden_frame = 1;
692*fb1b10abSAndroid Build Coastguard Worker   cpi->refresh_alt_ref_frame = 1;
693*fb1b10abSAndroid Build Coastguard Worker   cr->counter_encode_maxq_scene_change = 0;
694*fb1b10abSAndroid Build Coastguard Worker }
695*fb1b10abSAndroid Build Coastguard Worker 
vp9_cyclic_refresh_limit_q(const VP9_COMP * cpi,int * q)696*fb1b10abSAndroid Build Coastguard Worker void vp9_cyclic_refresh_limit_q(const VP9_COMP *cpi, int *q) {
697*fb1b10abSAndroid Build Coastguard Worker   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
698*fb1b10abSAndroid Build Coastguard Worker   // For now apply hard limit to frame-level decrease in q, if the cyclic
699*fb1b10abSAndroid Build Coastguard Worker   // refresh is active (percent_refresh > 0).
700*fb1b10abSAndroid Build Coastguard Worker   if (cr->percent_refresh > 0 && cpi->rc.q_1_frame - *q > 8) {
701*fb1b10abSAndroid Build Coastguard Worker     *q = cpi->rc.q_1_frame - 8;
702*fb1b10abSAndroid Build Coastguard Worker   }
703*fb1b10abSAndroid Build Coastguard Worker }
704