• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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