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