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