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