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