1 /*
2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "./vpx_dsp_rtcd.h"
12 #include "./vpx_scale_rtcd.h"
13 #include "vp8/common/onyxc_int.h"
14 #include "onyx_int.h"
15 #include "vp8/encoder/quantize.h"
16 #include "vpx_mem/vpx_mem.h"
17 #include "vpx_scale/vpx_scale.h"
18 #include "vp8/common/alloccommon.h"
19 #include "vp8/common/loopfilter.h"
20 #if ARCH_ARM
21 #include "vpx_ports/arm.h"
22 #endif
23
24 extern int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source,
25 YV12_BUFFER_CONFIG *dest);
26
yv12_copy_partial_frame(YV12_BUFFER_CONFIG * src_ybc,YV12_BUFFER_CONFIG * dst_ybc)27 static void yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc,
28 YV12_BUFFER_CONFIG *dst_ybc) {
29 unsigned char *src_y, *dst_y;
30 int yheight;
31 int ystride;
32 int yoffset;
33 int linestocopy;
34
35 yheight = src_ybc->y_height;
36 ystride = src_ybc->y_stride;
37
38 /* number of MB rows to use in partial filtering */
39 linestocopy = (yheight >> 4) / PARTIAL_FRAME_FRACTION;
40 linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */
41
42 /* Copy extra 4 so that full filter context is available if filtering done
43 * on the copied partial frame and not original. Partial filter does mb
44 * filtering for top row also, which can modify3 pixels above.
45 */
46 linestocopy += 4;
47 /* partial image starts at ~middle of frame (macroblock border)*/
48 yoffset = ystride * (((yheight >> 5) * 16) - 4);
49 src_y = src_ybc->y_buffer + yoffset;
50 dst_y = dst_ybc->y_buffer + yoffset;
51
52 memcpy(dst_y, src_y, ystride * linestocopy);
53 }
54
calc_partial_ssl_err(YV12_BUFFER_CONFIG * source,YV12_BUFFER_CONFIG * dest)55 static int calc_partial_ssl_err(YV12_BUFFER_CONFIG *source,
56 YV12_BUFFER_CONFIG *dest) {
57 int i, j;
58 int Total = 0;
59 int srcoffset, dstoffset;
60 unsigned char *src = source->y_buffer;
61 unsigned char *dst = dest->y_buffer;
62
63 int linestocopy;
64
65 /* number of MB rows to use in partial filtering */
66 linestocopy = (source->y_height >> 4) / PARTIAL_FRAME_FRACTION;
67 linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */
68
69 /* partial image starts at ~middle of frame (macroblock border)*/
70 srcoffset = source->y_stride * ((dest->y_height >> 5) * 16);
71 dstoffset = dest->y_stride * ((dest->y_height >> 5) * 16);
72
73 src += srcoffset;
74 dst += dstoffset;
75
76 /* Loop through the Y plane raw and reconstruction data summing
77 * (square differences)
78 */
79 for (i = 0; i < linestocopy; i += 16) {
80 for (j = 0; j < source->y_width; j += 16) {
81 unsigned int sse;
82 Total += vpx_mse16x16(src + j, source->y_stride, dst + j, dest->y_stride,
83 &sse);
84 }
85
86 src += 16 * source->y_stride;
87 dst += 16 * dest->y_stride;
88 }
89
90 return Total;
91 }
92
93 /* Enforce a minimum filter level based upon baseline Q */
get_min_filter_level(VP8_COMP * cpi,int base_qindex)94 static int get_min_filter_level(VP8_COMP *cpi, int base_qindex) {
95 int min_filter_level;
96
97 if (cpi->source_alt_ref_active && cpi->common.refresh_golden_frame &&
98 !cpi->common.refresh_alt_ref_frame) {
99 min_filter_level = 0;
100 } else {
101 if (base_qindex <= 6) {
102 min_filter_level = 0;
103 } else if (base_qindex <= 16) {
104 min_filter_level = 1;
105 } else {
106 min_filter_level = (base_qindex / 8);
107 }
108 }
109
110 return min_filter_level;
111 }
112
113 /* Enforce a maximum filter level based upon baseline Q */
get_max_filter_level(VP8_COMP * cpi,int base_qindex)114 static int get_max_filter_level(VP8_COMP *cpi, int base_qindex) {
115 /* PGW August 2006: Highest filter values almost always a bad idea */
116
117 /* jbb chg: 20100118 - not so any more with this overquant stuff allow
118 * high values with lots of intra coming in.
119 */
120 int max_filter_level = MAX_LOOP_FILTER;
121 (void)base_qindex;
122
123 if (cpi->twopass.section_intra_rating > 8) {
124 max_filter_level = MAX_LOOP_FILTER * 3 / 4;
125 }
126
127 return max_filter_level;
128 }
129
vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG * sd,VP8_COMP * cpi)130 void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) {
131 VP8_COMMON *cm = &cpi->common;
132
133 int best_err = 0;
134 int filt_err = 0;
135 int min_filter_level = get_min_filter_level(cpi, cm->base_qindex);
136 int max_filter_level = get_max_filter_level(cpi, cm->base_qindex);
137 int filt_val;
138 int best_filt_val;
139 YV12_BUFFER_CONFIG *saved_frame = cm->frame_to_show;
140
141 /* Replace unfiltered frame buffer with a new one */
142 cm->frame_to_show = &cpi->pick_lf_lvl_frame;
143
144 if (cm->frame_type == KEY_FRAME) {
145 cm->sharpness_level = 0;
146 } else {
147 cm->sharpness_level = cpi->oxcf.Sharpness;
148 }
149
150 if (cm->sharpness_level != cm->last_sharpness_level) {
151 vp8_loop_filter_update_sharpness(&cm->lf_info, cm->sharpness_level);
152 cm->last_sharpness_level = cm->sharpness_level;
153 }
154
155 /* Start the search at the previous frame filter level unless it is
156 * now out of range.
157 */
158 if (cm->filter_level < min_filter_level) {
159 cm->filter_level = min_filter_level;
160 } else if (cm->filter_level > max_filter_level) {
161 cm->filter_level = max_filter_level;
162 }
163
164 filt_val = cm->filter_level;
165 best_filt_val = filt_val;
166
167 /* Get the err using the previous frame's filter value. */
168
169 /* Copy the unfiltered / processed recon buffer to the new buffer */
170 yv12_copy_partial_frame(saved_frame, cm->frame_to_show);
171 vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);
172
173 best_err = calc_partial_ssl_err(sd, cm->frame_to_show);
174
175 filt_val -= 1 + (filt_val > 10);
176
177 /* Search lower filter levels */
178 while (filt_val >= min_filter_level) {
179 /* Apply the loop filter */
180 yv12_copy_partial_frame(saved_frame, cm->frame_to_show);
181 vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);
182
183 /* Get the err for filtered frame */
184 filt_err = calc_partial_ssl_err(sd, cm->frame_to_show);
185
186 /* Update the best case record or exit loop. */
187 if (filt_err < best_err) {
188 best_err = filt_err;
189 best_filt_val = filt_val;
190 } else {
191 break;
192 }
193
194 /* Adjust filter level */
195 filt_val -= 1 + (filt_val > 10);
196 }
197
198 /* Search up (note that we have already done filt_val = cm->filter_level) */
199 filt_val = cm->filter_level + 1 + (filt_val > 10);
200
201 if (best_filt_val == cm->filter_level) {
202 /* Resist raising filter level for very small gains */
203 best_err -= (best_err >> 10);
204
205 while (filt_val < max_filter_level) {
206 /* Apply the loop filter */
207 yv12_copy_partial_frame(saved_frame, cm->frame_to_show);
208
209 vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);
210
211 /* Get the err for filtered frame */
212 filt_err = calc_partial_ssl_err(sd, cm->frame_to_show);
213
214 /* Update the best case record or exit loop. */
215 if (filt_err < best_err) {
216 /* Do not raise filter level if improvement is < 1 part
217 * in 4096
218 */
219 best_err = filt_err - (filt_err >> 10);
220
221 best_filt_val = filt_val;
222 } else {
223 break;
224 }
225
226 /* Adjust filter level */
227 filt_val += 1 + (filt_val > 10);
228 }
229 }
230
231 cm->filter_level = best_filt_val;
232
233 if (cm->filter_level < min_filter_level) cm->filter_level = min_filter_level;
234
235 if (cm->filter_level > max_filter_level) cm->filter_level = max_filter_level;
236
237 /* restore unfiltered frame pointer */
238 cm->frame_to_show = saved_frame;
239 }
240
241 /* Stub function for now Alt LF not used */
vp8cx_set_alt_lf_level(VP8_COMP * cpi,int filt_val)242 void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val) {
243 MACROBLOCKD *mbd = &cpi->mb.e_mbd;
244 (void)filt_val;
245
246 mbd->segment_feature_data[MB_LVL_ALT_LF][0] =
247 cpi->segment_feature_data[MB_LVL_ALT_LF][0];
248 mbd->segment_feature_data[MB_LVL_ALT_LF][1] =
249 cpi->segment_feature_data[MB_LVL_ALT_LF][1];
250 mbd->segment_feature_data[MB_LVL_ALT_LF][2] =
251 cpi->segment_feature_data[MB_LVL_ALT_LF][2];
252 mbd->segment_feature_data[MB_LVL_ALT_LF][3] =
253 cpi->segment_feature_data[MB_LVL_ALT_LF][3];
254 }
255
vp8cx_pick_filter_level(YV12_BUFFER_CONFIG * sd,VP8_COMP * cpi)256 void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) {
257 VP8_COMMON *cm = &cpi->common;
258
259 int best_err = 0;
260 int filt_err = 0;
261 int min_filter_level = get_min_filter_level(cpi, cm->base_qindex);
262 int max_filter_level = get_max_filter_level(cpi, cm->base_qindex);
263
264 int filter_step;
265 int filt_high = 0;
266 int filt_mid;
267 int filt_low = 0;
268 int filt_best;
269 int filt_direction = 0;
270
271 /* Bias against raising loop filter and in favor of lowering it */
272 int Bias = 0;
273
274 int ss_err[MAX_LOOP_FILTER + 1];
275
276 YV12_BUFFER_CONFIG *saved_frame = cm->frame_to_show;
277
278 memset(ss_err, 0, sizeof(ss_err));
279
280 /* Replace unfiltered frame buffer with a new one */
281 cm->frame_to_show = &cpi->pick_lf_lvl_frame;
282
283 if (cm->frame_type == KEY_FRAME) {
284 cm->sharpness_level = 0;
285 } else {
286 cm->sharpness_level = cpi->oxcf.Sharpness;
287 }
288
289 /* Start the search at the previous frame filter level unless it is
290 * now out of range.
291 */
292 filt_mid = cm->filter_level;
293
294 if (filt_mid < min_filter_level) {
295 filt_mid = min_filter_level;
296 } else if (filt_mid > max_filter_level) {
297 filt_mid = max_filter_level;
298 }
299
300 /* Define the initial step size */
301 filter_step = (filt_mid < 16) ? 4 : filt_mid / 4;
302
303 /* Get baseline error score */
304
305 /* Copy the unfiltered / processed recon buffer to the new buffer */
306 vpx_yv12_copy_y(saved_frame, cm->frame_to_show);
307
308 vp8cx_set_alt_lf_level(cpi, filt_mid);
309 vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_mid);
310
311 best_err = vp8_calc_ss_err(sd, cm->frame_to_show);
312
313 ss_err[filt_mid] = best_err;
314
315 filt_best = filt_mid;
316
317 while (filter_step > 0) {
318 Bias = (best_err >> (15 - (filt_mid / 8))) * filter_step;
319
320 if (cpi->twopass.section_intra_rating < 20) {
321 Bias = Bias * cpi->twopass.section_intra_rating / 20;
322 }
323
324 filt_high = ((filt_mid + filter_step) > max_filter_level)
325 ? max_filter_level
326 : (filt_mid + filter_step);
327 filt_low = ((filt_mid - filter_step) < min_filter_level)
328 ? min_filter_level
329 : (filt_mid - filter_step);
330
331 if ((filt_direction <= 0) && (filt_low != filt_mid)) {
332 if (ss_err[filt_low] == 0) {
333 /* Get Low filter error score */
334 vpx_yv12_copy_y(saved_frame, cm->frame_to_show);
335 vp8cx_set_alt_lf_level(cpi, filt_low);
336 vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_low);
337
338 filt_err = vp8_calc_ss_err(sd, cm->frame_to_show);
339 ss_err[filt_low] = filt_err;
340 } else {
341 filt_err = ss_err[filt_low];
342 }
343
344 /* If value is close to the best so far then bias towards a
345 * lower loop filter value.
346 */
347 if ((filt_err - Bias) < best_err) {
348 /* Was it actually better than the previous best? */
349 if (filt_err < best_err) best_err = filt_err;
350
351 filt_best = filt_low;
352 }
353 }
354
355 /* Now look at filt_high */
356 if ((filt_direction >= 0) && (filt_high != filt_mid)) {
357 if (ss_err[filt_high] == 0) {
358 vpx_yv12_copy_y(saved_frame, cm->frame_to_show);
359 vp8cx_set_alt_lf_level(cpi, filt_high);
360 vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_high);
361
362 filt_err = vp8_calc_ss_err(sd, cm->frame_to_show);
363 ss_err[filt_high] = filt_err;
364 } else {
365 filt_err = ss_err[filt_high];
366 }
367
368 /* Was it better than the previous best? */
369 if (filt_err < (best_err - Bias)) {
370 best_err = filt_err;
371 filt_best = filt_high;
372 }
373 }
374
375 /* Half the step distance if the best filter value was the same
376 * as last time
377 */
378 if (filt_best == filt_mid) {
379 filter_step = filter_step / 2;
380 filt_direction = 0;
381 } else {
382 filt_direction = (filt_best < filt_mid) ? -1 : 1;
383 filt_mid = filt_best;
384 }
385 }
386
387 cm->filter_level = filt_best;
388
389 /* restore unfiltered frame pointer */
390 cm->frame_to_show = saved_frame;
391 }
392