/src/aom/av1/encoder/superres_scale.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2020, Alliance for Open Media. All rights reserved. |
3 | | * |
4 | | * This source code is subject to the terms of the BSD 2 Clause License and |
5 | | * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
6 | | * was not distributed with this source code in the LICENSE file, you can |
7 | | * obtain it at www.aomedia.org/license/software. If the Alliance for Open |
8 | | * Media Patent License 1.0 was not distributed with this source code in the |
9 | | * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
10 | | */ |
11 | | |
12 | | #include "av1/encoder/encoder_alloc.h" |
13 | | #include "av1/encoder/superres_scale.h" |
14 | | #include "av1/encoder/random.h" |
15 | | |
16 | | // Compute the horizontal frequency components' energy in a frame |
17 | | // by calculuating the 16x4 Horizontal DCT. This is to be used to |
18 | | // decide the superresolution parameters. |
19 | 0 | static void analyze_hor_freq(const AV1_COMP *cpi, double *energy) { |
20 | 0 | uint64_t freq_energy[16] = { 0 }; |
21 | 0 | const YV12_BUFFER_CONFIG *buf = cpi->source; |
22 | 0 | const int bd = cpi->td.mb.e_mbd.bd; |
23 | 0 | const int width = buf->y_crop_width; |
24 | 0 | const int height = buf->y_crop_height; |
25 | 0 | DECLARE_ALIGNED(16, int32_t, coeff[16 * 4]); |
26 | 0 | int n = 0; |
27 | 0 | memset(freq_energy, 0, sizeof(freq_energy)); |
28 | 0 | if (buf->flags & YV12_FLAG_HIGHBITDEPTH) { |
29 | 0 | const int16_t *src16 = (const int16_t *)CONVERT_TO_SHORTPTR(buf->y_buffer); |
30 | 0 | for (int i = 0; i < height - 4; i += 4) { |
31 | 0 | for (int j = 0; j < width - 16; j += 16) { |
32 | 0 | av1_fwd_txfm2d_16x4(src16 + i * buf->y_stride + j, coeff, buf->y_stride, |
33 | 0 | H_DCT, bd); |
34 | 0 | for (int k = 1; k < 16; ++k) { |
35 | 0 | const uint64_t this_energy = |
36 | 0 | ((int64_t)coeff[k] * coeff[k]) + |
37 | 0 | ((int64_t)coeff[k + 16] * coeff[k + 16]) + |
38 | 0 | ((int64_t)coeff[k + 32] * coeff[k + 32]) + |
39 | 0 | ((int64_t)coeff[k + 48] * coeff[k + 48]); |
40 | 0 | freq_energy[k] += ROUND_POWER_OF_TWO(this_energy, 2 + 2 * (bd - 8)); |
41 | 0 | } |
42 | 0 | n++; |
43 | 0 | } |
44 | 0 | } |
45 | 0 | } else { |
46 | 0 | assert(bd == 8); |
47 | 0 | DECLARE_ALIGNED(16, int16_t, src16[16 * 4]); |
48 | 0 | for (int i = 0; i < height - 4; i += 4) { |
49 | 0 | for (int j = 0; j < width - 16; j += 16) { |
50 | 0 | for (int ii = 0; ii < 4; ++ii) |
51 | 0 | for (int jj = 0; jj < 16; ++jj) |
52 | 0 | src16[ii * 16 + jj] = |
53 | 0 | buf->y_buffer[(i + ii) * buf->y_stride + (j + jj)]; |
54 | 0 | av1_fwd_txfm2d_16x4(src16, coeff, 16, H_DCT, bd); |
55 | 0 | for (int k = 1; k < 16; ++k) { |
56 | 0 | const uint64_t this_energy = |
57 | 0 | ((int64_t)coeff[k] * coeff[k]) + |
58 | 0 | ((int64_t)coeff[k + 16] * coeff[k + 16]) + |
59 | 0 | ((int64_t)coeff[k + 32] * coeff[k + 32]) + |
60 | 0 | ((int64_t)coeff[k + 48] * coeff[k + 48]); |
61 | 0 | freq_energy[k] += ROUND_POWER_OF_TWO(this_energy, 2); |
62 | 0 | } |
63 | 0 | n++; |
64 | 0 | } |
65 | 0 | } |
66 | 0 | } |
67 | 0 | if (n) { |
68 | 0 | for (int k = 1; k < 16; ++k) energy[k] = (double)freq_energy[k] / n; |
69 | | // Convert to cumulative energy |
70 | 0 | for (int k = 14; k > 0; --k) energy[k] += energy[k + 1]; |
71 | 0 | } else { |
72 | 0 | for (int k = 1; k < 16; ++k) energy[k] = 1e+20; |
73 | 0 | } |
74 | 0 | } |
75 | | |
76 | 0 | static uint8_t calculate_next_resize_scale(const AV1_COMP *cpi) { |
77 | | // Choose an arbitrary random number |
78 | 0 | static unsigned int seed = 56789; |
79 | 0 | const ResizeCfg *resize_cfg = &cpi->oxcf.resize_cfg; |
80 | 0 | if (is_stat_generation_stage(cpi)) return SCALE_NUMERATOR; |
81 | 0 | uint8_t new_denom = SCALE_NUMERATOR; |
82 | |
|
83 | 0 | if (cpi->common.seq_params->reduced_still_picture_hdr) return SCALE_NUMERATOR; |
84 | 0 | switch (resize_cfg->resize_mode) { |
85 | 0 | case RESIZE_NONE: new_denom = SCALE_NUMERATOR; break; |
86 | 0 | case RESIZE_FIXED: |
87 | 0 | if (cpi->common.current_frame.frame_type == KEY_FRAME) |
88 | 0 | new_denom = resize_cfg->resize_kf_scale_denominator; |
89 | 0 | else |
90 | 0 | new_denom = resize_cfg->resize_scale_denominator; |
91 | 0 | break; |
92 | 0 | case RESIZE_RANDOM: new_denom = lcg_rand16(&seed) % 9 + 8; break; |
93 | 0 | default: assert(0); |
94 | 0 | } |
95 | 0 | return new_denom; |
96 | 0 | } |
97 | | |
98 | 0 | int av1_superres_in_recode_allowed(const AV1_COMP *const cpi) { |
99 | 0 | const AV1EncoderConfig *const oxcf = &cpi->oxcf; |
100 | | // Empirically found to not be beneficial for image coding. |
101 | 0 | return oxcf->superres_cfg.superres_mode == AOM_SUPERRES_AUTO && |
102 | 0 | cpi->sf.hl_sf.superres_auto_search_type != SUPERRES_AUTO_SOLO && |
103 | 0 | cpi->rc.frames_to_key > 1; |
104 | 0 | } |
105 | | |
106 | 0 | #define SUPERRES_ENERGY_BY_Q2_THRESH_KEYFRAME_SOLO 0.012 |
107 | 0 | #define SUPERRES_ENERGY_BY_Q2_THRESH_KEYFRAME 0.008 |
108 | 0 | #define SUPERRES_ENERGY_BY_Q2_THRESH_ARFFRAME 0.008 |
109 | 0 | #define SUPERRES_ENERGY_BY_AC_THRESH 0.2 |
110 | | |
111 | | static double get_energy_by_q2_thresh(const GF_GROUP *gf_group, |
112 | | const RATE_CONTROL *rc, |
113 | 0 | int gf_frame_index) { |
114 | | // TODO(now): Return keyframe thresh * factor based on frame type / pyramid |
115 | | // level. |
116 | 0 | if (gf_group->update_type[gf_frame_index] == ARF_UPDATE) { |
117 | 0 | return SUPERRES_ENERGY_BY_Q2_THRESH_ARFFRAME; |
118 | 0 | } else if (gf_group->update_type[gf_frame_index] == KF_UPDATE) { |
119 | 0 | if (rc->frames_to_key <= 1) |
120 | 0 | return SUPERRES_ENERGY_BY_Q2_THRESH_KEYFRAME_SOLO; |
121 | 0 | else |
122 | 0 | return SUPERRES_ENERGY_BY_Q2_THRESH_KEYFRAME; |
123 | 0 | } else { |
124 | 0 | assert(0); |
125 | 0 | } |
126 | 0 | return 0; |
127 | 0 | } |
128 | | |
129 | | static uint8_t get_superres_denom_from_qindex_energy(int qindex, double *energy, |
130 | | double threshq, |
131 | 0 | double threshp) { |
132 | 0 | const double q = av1_convert_qindex_to_q(qindex, AOM_BITS_8); |
133 | 0 | const double tq = threshq * q * q; |
134 | 0 | const double tp = threshp * energy[1]; |
135 | 0 | const double thresh = AOMMIN(tq, tp); |
136 | 0 | int k; |
137 | 0 | for (k = SCALE_NUMERATOR * 2; k > SCALE_NUMERATOR; --k) { |
138 | 0 | if (energy[k - 1] > thresh) break; |
139 | 0 | } |
140 | 0 | return 3 * SCALE_NUMERATOR - k; |
141 | 0 | } |
142 | | |
143 | | static uint8_t get_superres_denom_for_qindex(const AV1_COMP *cpi, int qindex, |
144 | 0 | int sr_kf, int sr_arf) { |
145 | | // Use superres for Key-frames and Alt-ref frames only. |
146 | 0 | const GF_GROUP *gf_group = &cpi->ppi->gf_group; |
147 | 0 | if (gf_group->update_type[cpi->gf_frame_index] != KF_UPDATE && |
148 | 0 | gf_group->update_type[cpi->gf_frame_index] != ARF_UPDATE) { |
149 | 0 | return SCALE_NUMERATOR; |
150 | 0 | } |
151 | 0 | if (gf_group->update_type[cpi->gf_frame_index] == KF_UPDATE && !sr_kf) { |
152 | 0 | return SCALE_NUMERATOR; |
153 | 0 | } |
154 | 0 | if (gf_group->update_type[cpi->gf_frame_index] == ARF_UPDATE && !sr_arf) { |
155 | 0 | return SCALE_NUMERATOR; |
156 | 0 | } |
157 | | |
158 | 0 | double energy[16]; |
159 | 0 | analyze_hor_freq(cpi, energy); |
160 | |
|
161 | 0 | const double energy_by_q2_thresh = |
162 | 0 | get_energy_by_q2_thresh(gf_group, &cpi->rc, cpi->gf_frame_index); |
163 | 0 | int denom = get_superres_denom_from_qindex_energy( |
164 | 0 | qindex, energy, energy_by_q2_thresh, SUPERRES_ENERGY_BY_AC_THRESH); |
165 | | /* |
166 | | printf("\nenergy = ["); |
167 | | for (int k = 1; k < 16; ++k) printf("%f, ", energy[k]); |
168 | | printf("]\n"); |
169 | | printf("boost = %d\n", |
170 | | (gf_group->update_type[cpi->gf_frame_index] == KF_UPDATE) |
171 | | ? cpi->ppi->p_rc.kf_boost |
172 | | : cpi->rc.gfu_boost); |
173 | | printf("denom = %d\n", denom); |
174 | | */ |
175 | 0 | if (av1_superres_in_recode_allowed(cpi)) { |
176 | 0 | assert(cpi->superres_mode != AOM_SUPERRES_NONE); |
177 | | // Force superres to be tried in the recode loop, as full-res is also going |
178 | | // to be tried anyway. |
179 | 0 | denom = AOMMAX(denom, SCALE_NUMERATOR + 1); |
180 | 0 | } |
181 | 0 | return denom; |
182 | 0 | } |
183 | | |
184 | 0 | static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) { |
185 | | // Choose an arbitrary random number |
186 | 0 | static unsigned int seed = 34567; |
187 | 0 | const AV1EncoderConfig *oxcf = &cpi->oxcf; |
188 | 0 | const SuperResCfg *const superres_cfg = &oxcf->superres_cfg; |
189 | 0 | const FrameDimensionCfg *const frm_dim_cfg = &oxcf->frm_dim_cfg; |
190 | 0 | const RateControlCfg *const rc_cfg = &oxcf->rc_cfg; |
191 | |
|
192 | 0 | if (is_stat_generation_stage(cpi)) return SCALE_NUMERATOR; |
193 | 0 | uint8_t new_denom = SCALE_NUMERATOR; |
194 | | |
195 | | // Make sure that superres mode of the frame is consistent with the |
196 | | // sequence-level flag. |
197 | 0 | assert(IMPLIES(superres_cfg->superres_mode != AOM_SUPERRES_NONE, |
198 | 0 | cpi->common.seq_params->enable_superres)); |
199 | 0 | assert(IMPLIES(!cpi->common.seq_params->enable_superres, |
200 | 0 | superres_cfg->superres_mode == AOM_SUPERRES_NONE)); |
201 | | // Make sure that superres mode for current encoding is consistent with user |
202 | | // provided superres mode. |
203 | 0 | assert(IMPLIES(superres_cfg->superres_mode != AOM_SUPERRES_AUTO, |
204 | 0 | cpi->superres_mode == superres_cfg->superres_mode)); |
205 | | |
206 | | // Note: we must look at the current superres_mode to be tried in 'cpi' here, |
207 | | // not the user given mode in 'oxcf'. |
208 | 0 | switch (cpi->superres_mode) { |
209 | 0 | case AOM_SUPERRES_NONE: new_denom = SCALE_NUMERATOR; break; |
210 | 0 | case AOM_SUPERRES_FIXED: |
211 | 0 | if (cpi->common.current_frame.frame_type == KEY_FRAME) |
212 | 0 | new_denom = superres_cfg->superres_kf_scale_denominator; |
213 | 0 | else |
214 | 0 | new_denom = superres_cfg->superres_scale_denominator; |
215 | 0 | break; |
216 | 0 | case AOM_SUPERRES_RANDOM: new_denom = lcg_rand16(&seed) % 9 + 8; break; |
217 | 0 | case AOM_SUPERRES_QTHRESH: { |
218 | | // Do not use superres when screen content tools are used. |
219 | 0 | if (cpi->common.features.allow_screen_content_tools) break; |
220 | 0 | if (rc_cfg->mode == AOM_VBR || rc_cfg->mode == AOM_CQ) |
221 | 0 | av1_set_target_rate(cpi, frm_dim_cfg->width, frm_dim_cfg->height); |
222 | | |
223 | | // Now decide the use of superres based on 'q'. |
224 | 0 | int bottom_index, top_index; |
225 | 0 | const int q = av1_rc_pick_q_and_bounds( |
226 | 0 | cpi, frm_dim_cfg->width, frm_dim_cfg->height, cpi->gf_frame_index, |
227 | 0 | &bottom_index, &top_index); |
228 | |
|
229 | 0 | const int qthresh = (frame_is_intra_only(&cpi->common)) |
230 | 0 | ? superres_cfg->superres_kf_qthresh |
231 | 0 | : superres_cfg->superres_qthresh; |
232 | 0 | if (q <= qthresh) { |
233 | 0 | new_denom = SCALE_NUMERATOR; |
234 | 0 | } else { |
235 | 0 | new_denom = get_superres_denom_for_qindex(cpi, q, 1, 1); |
236 | 0 | } |
237 | 0 | break; |
238 | 0 | } |
239 | 0 | case AOM_SUPERRES_AUTO: { |
240 | 0 | if (cpi->common.features.allow_screen_content_tools) break; |
241 | 0 | if (rc_cfg->mode == AOM_VBR || rc_cfg->mode == AOM_CQ) |
242 | 0 | av1_set_target_rate(cpi, frm_dim_cfg->width, frm_dim_cfg->height); |
243 | | |
244 | | // Now decide the use of superres based on 'q'. |
245 | 0 | int bottom_index, top_index; |
246 | 0 | const int q = av1_rc_pick_q_and_bounds( |
247 | 0 | cpi, frm_dim_cfg->width, frm_dim_cfg->height, cpi->gf_frame_index, |
248 | 0 | &bottom_index, &top_index); |
249 | |
|
250 | 0 | const SUPERRES_AUTO_SEARCH_TYPE sr_search_type = |
251 | 0 | cpi->sf.hl_sf.superres_auto_search_type; |
252 | 0 | const int qthresh = (sr_search_type == SUPERRES_AUTO_SOLO) ? 128 : 0; |
253 | 0 | if (q <= qthresh) { |
254 | 0 | new_denom = SCALE_NUMERATOR; // Don't use superres. |
255 | 0 | } else { |
256 | 0 | if (sr_search_type == SUPERRES_AUTO_ALL) { |
257 | 0 | if (cpi->common.current_frame.frame_type == KEY_FRAME) |
258 | 0 | new_denom = superres_cfg->superres_kf_scale_denominator; |
259 | 0 | else |
260 | 0 | new_denom = superres_cfg->superres_scale_denominator; |
261 | 0 | } else { |
262 | 0 | new_denom = get_superres_denom_for_qindex(cpi, q, 1, 1); |
263 | 0 | } |
264 | 0 | } |
265 | 0 | break; |
266 | 0 | } |
267 | 0 | default: assert(0); |
268 | 0 | } |
269 | 0 | return new_denom; |
270 | 0 | } |
271 | | |
272 | 0 | static int dimension_is_ok(int orig_dim, int resized_dim, int denom) { |
273 | 0 | return (resized_dim * SCALE_NUMERATOR >= orig_dim * denom / 2); |
274 | 0 | } |
275 | | |
276 | 0 | static int dimensions_are_ok(int owidth, int oheight, size_params_type *rsz) { |
277 | | // Only need to check the width, as scaling is horizontal only. |
278 | 0 | (void)oheight; |
279 | 0 | return dimension_is_ok(owidth, rsz->resize_width, rsz->superres_denom); |
280 | 0 | } |
281 | | |
282 | | static int validate_size_scales(RESIZE_MODE resize_mode, |
283 | | aom_superres_mode superres_mode, int owidth, |
284 | 0 | int oheight, size_params_type *rsz) { |
285 | 0 | if (dimensions_are_ok(owidth, oheight, rsz)) { // Nothing to do. |
286 | 0 | return 1; |
287 | 0 | } |
288 | | |
289 | | // Calculate current resize scale. |
290 | 0 | int resize_denom = |
291 | 0 | AOMMAX(DIVIDE_AND_ROUND(owidth * SCALE_NUMERATOR, rsz->resize_width), |
292 | 0 | DIVIDE_AND_ROUND(oheight * SCALE_NUMERATOR, rsz->resize_height)); |
293 | |
|
294 | 0 | if (resize_mode != RESIZE_RANDOM && superres_mode == AOM_SUPERRES_RANDOM) { |
295 | | // Alter superres scale as needed to enforce conformity. |
296 | 0 | rsz->superres_denom = |
297 | 0 | (2 * SCALE_NUMERATOR * SCALE_NUMERATOR) / resize_denom; |
298 | 0 | if (!dimensions_are_ok(owidth, oheight, rsz)) { |
299 | 0 | if (rsz->superres_denom > SCALE_NUMERATOR) --rsz->superres_denom; |
300 | 0 | } |
301 | 0 | } else if (resize_mode == RESIZE_RANDOM && |
302 | 0 | superres_mode != AOM_SUPERRES_RANDOM) { |
303 | | // Alter resize scale as needed to enforce conformity. |
304 | 0 | resize_denom = |
305 | 0 | (2 * SCALE_NUMERATOR * SCALE_NUMERATOR) / rsz->superres_denom; |
306 | 0 | rsz->resize_width = owidth; |
307 | 0 | rsz->resize_height = oheight; |
308 | 0 | av1_calculate_scaled_size(&rsz->resize_width, &rsz->resize_height, |
309 | 0 | resize_denom); |
310 | 0 | if (!dimensions_are_ok(owidth, oheight, rsz)) { |
311 | 0 | if (resize_denom > SCALE_NUMERATOR) { |
312 | 0 | --resize_denom; |
313 | 0 | rsz->resize_width = owidth; |
314 | 0 | rsz->resize_height = oheight; |
315 | 0 | av1_calculate_scaled_size(&rsz->resize_width, &rsz->resize_height, |
316 | 0 | resize_denom); |
317 | 0 | } |
318 | 0 | } |
319 | 0 | } else if (resize_mode == RESIZE_RANDOM && |
320 | 0 | superres_mode == AOM_SUPERRES_RANDOM) { |
321 | | // Alter both resize and superres scales as needed to enforce conformity. |
322 | 0 | do { |
323 | 0 | if (resize_denom > rsz->superres_denom) |
324 | 0 | --resize_denom; |
325 | 0 | else |
326 | 0 | --rsz->superres_denom; |
327 | 0 | rsz->resize_width = owidth; |
328 | 0 | rsz->resize_height = oheight; |
329 | 0 | av1_calculate_scaled_size(&rsz->resize_width, &rsz->resize_height, |
330 | 0 | resize_denom); |
331 | 0 | } while (!dimensions_are_ok(owidth, oheight, rsz) && |
332 | 0 | (resize_denom > SCALE_NUMERATOR || |
333 | 0 | rsz->superres_denom > SCALE_NUMERATOR)); |
334 | 0 | } else { // We are allowed to alter neither resize scale nor superres |
335 | | // scale. |
336 | 0 | return 0; |
337 | 0 | } |
338 | 0 | return dimensions_are_ok(owidth, oheight, rsz); |
339 | 0 | } |
340 | | |
341 | | // Calculates resize and superres params for next frame |
342 | 0 | static size_params_type calculate_next_size_params(AV1_COMP *cpi) { |
343 | 0 | const AV1EncoderConfig *oxcf = &cpi->oxcf; |
344 | 0 | ResizePendingParams *resize_pending_params = &cpi->resize_pending_params; |
345 | 0 | const FrameDimensionCfg *const frm_dim_cfg = &oxcf->frm_dim_cfg; |
346 | 0 | size_params_type rsz = { frm_dim_cfg->width, frm_dim_cfg->height, |
347 | 0 | SCALE_NUMERATOR }; |
348 | 0 | int resize_denom = SCALE_NUMERATOR; |
349 | 0 | if (has_no_stats_stage(cpi) && cpi->ppi->use_svc && |
350 | 0 | (cpi->common.width != cpi->oxcf.frm_dim_cfg.width || |
351 | 0 | cpi->common.height != cpi->oxcf.frm_dim_cfg.height)) { |
352 | 0 | rsz.resize_width = cpi->common.width; |
353 | 0 | rsz.resize_height = cpi->common.height; |
354 | 0 | return rsz; |
355 | 0 | } |
356 | 0 | if (is_stat_generation_stage(cpi)) return rsz; |
357 | 0 | if (resize_pending_params->width && resize_pending_params->height) { |
358 | 0 | rsz.resize_width = resize_pending_params->width; |
359 | 0 | rsz.resize_height = resize_pending_params->height; |
360 | 0 | resize_pending_params->width = resize_pending_params->height = 0; |
361 | 0 | if (oxcf->superres_cfg.superres_mode == AOM_SUPERRES_NONE) return rsz; |
362 | 0 | } else { |
363 | 0 | resize_denom = calculate_next_resize_scale(cpi); |
364 | 0 | rsz.resize_width = frm_dim_cfg->width; |
365 | 0 | rsz.resize_height = frm_dim_cfg->height; |
366 | 0 | av1_calculate_scaled_size(&rsz.resize_width, &rsz.resize_height, |
367 | 0 | resize_denom); |
368 | 0 | } |
369 | 0 | rsz.superres_denom = calculate_next_superres_scale(cpi); |
370 | 0 | if (!validate_size_scales(oxcf->resize_cfg.resize_mode, cpi->superres_mode, |
371 | 0 | frm_dim_cfg->width, frm_dim_cfg->height, &rsz)) |
372 | 0 | assert(0 && "Invalid scale parameters"); |
373 | 0 | return rsz; |
374 | 0 | } |
375 | | |
376 | | static void setup_frame_size_from_params(AV1_COMP *cpi, |
377 | 0 | const size_params_type *rsz) { |
378 | 0 | int encode_width = rsz->resize_width; |
379 | 0 | int encode_height = rsz->resize_height; |
380 | |
|
381 | 0 | AV1_COMMON *cm = &cpi->common; |
382 | 0 | cm->superres_upscaled_width = encode_width; |
383 | 0 | cm->superres_upscaled_height = encode_height; |
384 | 0 | cm->superres_scale_denominator = rsz->superres_denom; |
385 | 0 | av1_calculate_scaled_superres_size(&encode_width, &encode_height, |
386 | 0 | rsz->superres_denom); |
387 | 0 | av1_set_frame_size(cpi, encode_width, encode_height); |
388 | 0 | } |
389 | | |
390 | 0 | void av1_setup_frame_size(AV1_COMP *cpi) { |
391 | 0 | AV1_COMMON *cm = &cpi->common; |
392 | | // Reset superres params from previous frame. |
393 | 0 | cm->superres_scale_denominator = SCALE_NUMERATOR; |
394 | 0 | const size_params_type rsz = calculate_next_size_params(cpi); |
395 | 0 | setup_frame_size_from_params(cpi, &rsz); |
396 | |
|
397 | 0 | assert(av1_is_min_tile_width_satisfied(cm)); |
398 | 0 | } |
399 | | |
400 | 0 | void av1_superres_post_encode(AV1_COMP *cpi) { |
401 | 0 | AV1_COMMON *cm = &cpi->common; |
402 | |
|
403 | 0 | assert(cpi->oxcf.superres_cfg.enable_superres); |
404 | 0 | assert(!is_lossless_requested(&cpi->oxcf.rc_cfg)); |
405 | 0 | assert(!cm->features.all_lossless); |
406 | |
|
407 | 0 | av1_superres_upscale(cm, NULL, cpi->alloc_pyramid); |
408 | | |
409 | | // If regular resizing is occurring the source will need to be downscaled to |
410 | | // match the upscaled superres resolution. Otherwise the original source is |
411 | | // used. |
412 | 0 | if (!av1_resize_scaled(cm)) { |
413 | 0 | cpi->source = cpi->unscaled_source; |
414 | 0 | if (cpi->last_source != NULL) cpi->last_source = cpi->unscaled_last_source; |
415 | 0 | } else { |
416 | 0 | assert(cpi->unscaled_source->y_crop_width != cm->superres_upscaled_width); |
417 | 0 | assert(cpi->unscaled_source->y_crop_height != cm->superres_upscaled_height); |
418 | | // Do downscale. cm->(width|height) has been updated by |
419 | | // av1_superres_upscale |
420 | 0 | cpi->source = realloc_and_scale_source(cpi, cm->superres_upscaled_width, |
421 | 0 | cm->superres_upscaled_height); |
422 | 0 | } |
423 | 0 | } |