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