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_dsp_rtcd.h"
13#include "./vpx_scale_rtcd.h"
14#include "vp8/common/onyxc_int.h"
15#include "onyx_int.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, YV12_BUFFER_CONFIG *dest);
26
27static void yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc,
28                                    YV12_BUFFER_CONFIG *dst_ybc)
29{
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{
59    int i, j;
60    int Total = 0;
61    int srcoffset, dstoffset;
62    unsigned char *src = source->y_buffer;
63    unsigned char *dst = dest->y_buffer;
64
65    int linestocopy;
66
67    /* number of MB rows to use in partial filtering */
68    linestocopy = (source->y_height >> 4) / PARTIAL_FRAME_FRACTION;
69    linestocopy = linestocopy ? linestocopy << 4 : 16;     /* 16 lines per MB */
70
71
72    /* partial image starts at ~middle of frame (macroblock border)*/
73    srcoffset = source->y_stride * ((dest->y_height >> 5) * 16);
74    dstoffset = dest->y_stride   * ((dest->y_height >> 5) * 16);
75
76    src += srcoffset;
77    dst += dstoffset;
78
79    /* Loop through the Y plane raw and reconstruction data summing
80     * (square differences)
81     */
82    for (i = 0; i < linestocopy; i += 16)
83    {
84        for (j = 0; j < source->y_width; j += 16)
85        {
86            unsigned int sse;
87            Total += vpx_mse16x16(src + j, source->y_stride,
88                                                     dst + j, dest->y_stride,
89                                                     &sse);
90        }
91
92        src += 16 * source->y_stride;
93        dst += 16 * dest->y_stride;
94    }
95
96    return Total;
97}
98
99/* Enforce a minimum filter level based upon baseline Q */
100static int get_min_filter_level(VP8_COMP *cpi, int base_qindex)
101{
102    int min_filter_level;
103
104    if (cpi->source_alt_ref_active && cpi->common.refresh_golden_frame &&
105        !cpi->common.refresh_alt_ref_frame)
106        min_filter_level = 0;
107    else
108    {
109        if (base_qindex <= 6)
110            min_filter_level = 0;
111        else if (base_qindex <= 16)
112            min_filter_level = 1;
113        else
114            min_filter_level = (base_qindex / 8);
115    }
116
117    return min_filter_level;
118}
119
120/* Enforce a maximum filter level based upon baseline Q */
121static int get_max_filter_level(VP8_COMP *cpi, int base_qindex)
122{
123    /* PGW August 2006: Highest filter values almost always a bad idea */
124
125    /* jbb chg: 20100118 - not so any more with this overquant stuff allow
126     * high values with lots of intra coming in.
127     */
128    int max_filter_level = MAX_LOOP_FILTER;
129    (void)base_qindex;
130
131    if (cpi->twopass.section_intra_rating > 8)
132        max_filter_level = MAX_LOOP_FILTER * 3 / 4;
133
134    return max_filter_level;
135}
136
137void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi)
138{
139    VP8_COMMON *cm = &cpi->common;
140
141    int best_err = 0;
142    int filt_err = 0;
143    int min_filter_level = get_min_filter_level(cpi, cm->base_qindex);
144    int max_filter_level = get_max_filter_level(cpi, cm->base_qindex);
145    int filt_val;
146    int best_filt_val;
147    YV12_BUFFER_CONFIG * saved_frame = cm->frame_to_show;
148
149    /* Replace unfiltered frame buffer with a new one */
150    cm->frame_to_show = &cpi->pick_lf_lvl_frame;
151
152    if (cm->frame_type == KEY_FRAME)
153        cm->sharpness_level = 0;
154    else
155        cm->sharpness_level = cpi->oxcf.Sharpness;
156
157    if (cm->sharpness_level != cm->last_sharpness_level)
158    {
159        vp8_loop_filter_update_sharpness(&cm->lf_info, cm->sharpness_level);
160        cm->last_sharpness_level = cm->sharpness_level;
161    }
162
163    /* Start the search at the previous frame filter level unless it is
164     * now out of range.
165     */
166    if (cm->filter_level < min_filter_level)
167        cm->filter_level = min_filter_level;
168    else if (cm->filter_level > max_filter_level)
169        cm->filter_level = max_filter_level;
170
171    filt_val = cm->filter_level;
172    best_filt_val = filt_val;
173
174    /* Get the err using the previous frame's filter value. */
175
176    /* Copy the unfiltered / processed recon buffer to the new buffer */
177    yv12_copy_partial_frame(saved_frame, cm->frame_to_show);
178    vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);
179
180    best_err = calc_partial_ssl_err(sd, cm->frame_to_show);
181
182    filt_val -= 1 + (filt_val > 10);
183
184    /* Search lower filter levels */
185    while (filt_val >= min_filter_level)
186    {
187        /* Apply the loop filter */
188        yv12_copy_partial_frame(saved_frame, cm->frame_to_show);
189        vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);
190
191        /* Get the err for filtered frame */
192        filt_err = calc_partial_ssl_err(sd, cm->frame_to_show);
193
194        /* Update the best case record or exit loop. */
195        if (filt_err < best_err)
196        {
197            best_err = filt_err;
198            best_filt_val = filt_val;
199        }
200        else
201            break;
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    {
212        /* Resist raising filter level for very small gains */
213        best_err -= (best_err >> 10);
214
215        while (filt_val < max_filter_level)
216        {
217            /* Apply the loop filter */
218            yv12_copy_partial_frame(saved_frame, cm->frame_to_show);
219
220            vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);
221
222            /* Get the err for filtered frame */
223            filt_err = calc_partial_ssl_err(sd, cm->frame_to_show);
224
225            /* Update the best case record or exit loop. */
226            if (filt_err < best_err)
227            {
228                /* Do not raise filter level if improvement is < 1 part
229                 * in 4096
230                 */
231                best_err = filt_err - (filt_err >> 10);
232
233                best_filt_val = filt_val;
234            }
235            else
236                break;
237
238            /* Adjust filter level */
239            filt_val += 1 + (filt_val > 10);
240        }
241    }
242
243    cm->filter_level = best_filt_val;
244
245    if (cm->filter_level < min_filter_level)
246        cm->filter_level = min_filter_level;
247
248    if (cm->filter_level > max_filter_level)
249        cm->filter_level = max_filter_level;
250
251    /* restore unfiltered frame pointer */
252    cm->frame_to_show = saved_frame;
253}
254
255/* Stub function for now Alt LF not used */
256void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val)
257{
258    MACROBLOCKD *mbd = &cpi->mb.e_mbd;
259    (void) filt_val;
260
261    mbd->segment_feature_data[MB_LVL_ALT_LF][0] = cpi->segment_feature_data[MB_LVL_ALT_LF][0];
262    mbd->segment_feature_data[MB_LVL_ALT_LF][1] = cpi->segment_feature_data[MB_LVL_ALT_LF][1];
263    mbd->segment_feature_data[MB_LVL_ALT_LF][2] = cpi->segment_feature_data[MB_LVL_ALT_LF][2];
264    mbd->segment_feature_data[MB_LVL_ALT_LF][3] = cpi->segment_feature_data[MB_LVL_ALT_LF][3];
265}
266
267void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi)
268{
269    VP8_COMMON *cm = &cpi->common;
270
271    int best_err = 0;
272    int filt_err = 0;
273    int min_filter_level = get_min_filter_level(cpi, cm->base_qindex);
274    int max_filter_level = get_max_filter_level(cpi, cm->base_qindex);
275
276    int filter_step;
277    int filt_high = 0;
278    int filt_mid;
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    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