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 "vp8/common/onyxc_int.h"
13#include "onyx_int.h"
14#include "quantize.h"
15#include "vpx_mem/vpx_mem.h"
16#include "vpx_scale/yv12extend.h"
17#include "vpx_scale/vpxscale.h"
18#include "vp8/common/alloccommon.h"
19#if ARCH_ARM
20#include "vpx_ports/arm.h"
21#endif
22
23extern void vp8_loop_filter_frame(VP8_COMMON *cm,    MACROBLOCKD *mbd,  int filt_val);
24extern void vp8_loop_filter_frame_yonly(VP8_COMMON *cm,    MACROBLOCKD *mbd,  int filt_val, int sharpness_lvl);
25extern int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, const vp8_variance_rtcd_vtable_t *rtcd);
26#if HAVE_ARMV7
27extern void vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc);
28#endif
29
30#if CONFIG_RUNTIME_CPU_DETECT
31#define IF_RTCD(x) (x)
32#else
33#define IF_RTCD(x) NULL
34#endif
35
36extern void
37(*vp8_yv12_copy_partial_frame_ptr)(YV12_BUFFER_CONFIG *src_ybc,
38                                   YV12_BUFFER_CONFIG *dst_ybc,
39                                   int Fraction);
40void
41vp8_yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction)
42{
43    unsigned char *src_y, *dst_y;
44    int yheight;
45    int ystride;
46    int border;
47    int yoffset;
48    int linestocopy;
49
50    border   = src_ybc->border;
51    yheight  = src_ybc->y_height;
52    ystride  = src_ybc->y_stride;
53
54    linestocopy = (yheight >> (Fraction + 4));
55
56    if (linestocopy < 1)
57        linestocopy = 1;
58
59    linestocopy <<= 4;
60
61    yoffset  = ystride * ((yheight >> 5) * 16 - 8);
62    src_y = src_ybc->y_buffer + yoffset;
63    dst_y = dst_ybc->y_buffer + yoffset;
64
65    vpx_memcpy(dst_y, src_y, ystride *(linestocopy + 16));
66}
67
68static int vp8_calc_partial_ssl_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, int Fraction, const vp8_variance_rtcd_vtable_t *rtcd)
69{
70    int i, j;
71    int Total = 0;
72    int srcoffset, dstoffset;
73    unsigned char *src = source->y_buffer;
74    unsigned char *dst = dest->y_buffer;
75
76    int linestocopy = (source->y_height >> (Fraction + 4));
77    (void)rtcd;
78
79    if (linestocopy < 1)
80        linestocopy = 1;
81
82    linestocopy <<= 4;
83
84
85    srcoffset = source->y_stride   * (dest->y_height >> 5) * 16;
86    dstoffset = dest->y_stride     * (dest->y_height >> 5) * 16;
87
88    src += srcoffset;
89    dst += dstoffset;
90
91    // Loop through the Y plane raw and reconstruction data summing (square differences)
92    for (i = 0; i < linestocopy; i += 16)
93    {
94        for (j = 0; j < source->y_width; j += 16)
95        {
96            unsigned int sse;
97            Total += VARIANCE_INVOKE(rtcd, mse16x16)(src + j, source->y_stride, dst + j, dest->y_stride, &sse);
98        }
99
100        src += 16 * source->y_stride;
101        dst += 16 * dest->y_stride;
102    }
103
104    return Total;
105}
106
107extern void vp8_loop_filter_partial_frame
108(
109    VP8_COMMON *cm,
110    MACROBLOCKD *mbd,
111    int default_filt_lvl,
112    int sharpness_lvl,
113    int Fraction
114);
115
116// Enforce a minimum filter level based upon baseline Q
117static int get_min_filter_level(VP8_COMP *cpi, int base_qindex)
118{
119    int min_filter_level;
120
121    if (cpi->source_alt_ref_active && cpi->common.refresh_golden_frame && !cpi->common.refresh_alt_ref_frame)
122        min_filter_level = 0;
123    else
124    {
125        if (base_qindex <= 6)
126            min_filter_level = 0;
127        else if (base_qindex <= 16)
128            min_filter_level = 1;
129        else
130            min_filter_level = (base_qindex / 8);
131    }
132
133    return min_filter_level;
134}
135
136// Enforce a maximum filter level based upon baseline Q
137static int get_max_filter_level(VP8_COMP *cpi, int base_qindex)
138{
139    // PGW August 2006: Highest filter values almost always a bad idea
140
141    // jbb chg: 20100118 - not so any more with this overquant stuff allow high values
142    // with lots of intra coming in.
143    int max_filter_level = MAX_LOOP_FILTER ;//* 3 / 4;
144
145    if (cpi->section_intra_rating > 8)
146        max_filter_level = MAX_LOOP_FILTER * 3 / 4;
147
148    (void) cpi;
149    (void) base_qindex;
150
151    return max_filter_level;
152}
153
154void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi)
155{
156    VP8_COMMON *cm = &cpi->common;
157
158    int best_err = 0;
159    int filt_err = 0;
160    int min_filter_level = 0;
161    int max_filter_level = MAX_LOOP_FILTER * 3 / 4;   // PGW August 2006: Highest filter values almost always a bad idea
162    int filt_val;
163    int best_filt_val = cm->filter_level;
164
165    //  Make a copy of the unfiltered / processed recon buffer
166    //vp8_yv12_copy_frame_ptr( cm->frame_to_show, &cpi->last_frame_uf  );
167    vp8_yv12_copy_partial_frame_ptr(cm->frame_to_show, &cpi->last_frame_uf, 3);
168
169    if (cm->frame_type == KEY_FRAME)
170        cm->sharpness_level = 0;
171    else
172        cm->sharpness_level = cpi->oxcf.Sharpness;
173
174    // Enforce a minimum filter level based upon Q
175    min_filter_level = get_min_filter_level(cpi, cm->base_qindex);
176    max_filter_level = get_max_filter_level(cpi, cm->base_qindex);
177
178    // Start the search at the previous frame filter level unless it is now out of range.
179    if (cm->filter_level < min_filter_level)
180        cm->filter_level = min_filter_level;
181    else if (cm->filter_level > max_filter_level)
182        cm->filter_level = max_filter_level;
183
184    filt_val = cm->filter_level;
185    best_filt_val = filt_val;
186
187    // Set up alternate filter values
188
189    // Get the err using the previous frame's filter value.
190    vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val, 0  , 3);
191    cm->last_frame_type = cm->frame_type;
192    cm->last_filter_type = cm->filter_type;
193    cm->last_sharpness_level = cm->sharpness_level;
194
195    best_err = vp8_calc_partial_ssl_err(sd, cm->frame_to_show, 3, IF_RTCD(&cpi->rtcd.variance));
196
197    //  Re-instate the unfiltered frame
198    vp8_yv12_copy_partial_frame_ptr(&cpi->last_frame_uf, cm->frame_to_show, 3);
199
200    filt_val -= (1 + ((filt_val > 10) ? 1 : 0));
201
202    // Search lower filter levels
203    while (filt_val >= min_filter_level)
204    {
205        // Apply the loop filter
206        vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val, 0, 3);
207        cm->last_frame_type = cm->frame_type;
208        cm->last_filter_type = cm->filter_type;
209        cm->last_sharpness_level = cm->sharpness_level;
210
211        // Get the err for filtered frame
212        filt_err = vp8_calc_partial_ssl_err(sd, cm->frame_to_show, 3, IF_RTCD(&cpi->rtcd.variance));
213
214
215        //  Re-instate the unfiltered frame
216        vp8_yv12_copy_partial_frame_ptr(&cpi->last_frame_uf, cm->frame_to_show, 3);
217
218
219        // Update the best case record or exit loop.
220        if (filt_err < best_err)
221        {
222            best_err = filt_err;
223            best_filt_val = filt_val;
224        }
225        else
226            break;
227
228        // Adjust filter level
229        filt_val -= (1 + ((filt_val > 10) ? 1 : 0));
230    }
231
232    // Search up (note that we have already done filt_val = cm->filter_level)
233    filt_val = cm->filter_level + (1 + ((filt_val > 10) ? 1 : 0));
234
235    if (best_filt_val == cm->filter_level)
236    {
237        // Resist raising filter level for very small gains
238        best_err -= (best_err >> 10);
239
240        while (filt_val < max_filter_level)
241        {
242            // Apply the loop filter
243            vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val, 0, 3);
244            cm->last_frame_type = cm->frame_type;
245            cm->last_filter_type = cm->filter_type;
246            cm->last_sharpness_level = cm->sharpness_level;
247
248            // Get the err for filtered frame
249            filt_err = vp8_calc_partial_ssl_err(sd, cm->frame_to_show, 3, IF_RTCD(&cpi->rtcd.variance));
250
251            //  Re-instate the unfiltered frame
252            vp8_yv12_copy_partial_frame_ptr(&cpi->last_frame_uf, cm->frame_to_show, 3);
253
254            // Update the best case record or exit loop.
255            if (filt_err < best_err)
256            {
257                // Do not raise filter level if improvement is < 1 part in 4096
258                best_err = filt_err - (filt_err >> 10);
259
260                best_filt_val = filt_val;
261            }
262            else
263                break;
264
265            // Adjust filter level
266            filt_val += (1 + ((filt_val > 10) ? 1 : 0));
267        }
268    }
269
270    cm->filter_level = best_filt_val;
271
272    if (cm->filter_level < min_filter_level)
273        cm->filter_level = min_filter_level;
274
275    if (cm->filter_level > max_filter_level)
276        cm->filter_level = max_filter_level;
277}
278
279// Stub function for now Alt LF not used
280void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val)
281{
282    MACROBLOCKD *mbd = &cpi->mb.e_mbd;
283    (void) filt_val;
284
285    mbd->segment_feature_data[MB_LVL_ALT_LF][0] = cpi->segment_feature_data[MB_LVL_ALT_LF][0];
286    mbd->segment_feature_data[MB_LVL_ALT_LF][1] = cpi->segment_feature_data[MB_LVL_ALT_LF][1];
287    mbd->segment_feature_data[MB_LVL_ALT_LF][2] = cpi->segment_feature_data[MB_LVL_ALT_LF][2];
288    mbd->segment_feature_data[MB_LVL_ALT_LF][3] = cpi->segment_feature_data[MB_LVL_ALT_LF][3];
289}
290
291void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi)
292{
293    VP8_COMMON *cm = &cpi->common;
294
295    int best_err = 0;
296    int filt_err = 0;
297    int min_filter_level;
298    int max_filter_level;
299
300    int filter_step;
301    int filt_high = 0;
302    int filt_mid = cm->filter_level;      // Start search at previous frame filter level
303    int filt_low = 0;
304    int filt_best;
305    int filt_direction = 0;
306
307    int Bias = 0;                       // Bias against raising loop filter and in favour of lowering it
308
309    //  Make a copy of the unfiltered / processed recon buffer
310#if HAVE_ARMV7
311#if CONFIG_RUNTIME_CPU_DETECT
312    if (cm->rtcd.flags & HAS_NEON)
313#endif
314    {
315        vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(cm->frame_to_show, &cpi->last_frame_uf);
316    }
317#if CONFIG_RUNTIME_CPU_DETECT
318    else
319#endif
320#endif
321#if !HAVE_ARMV7 || CONFIG_RUNTIME_CPU_DETECT
322    {
323        vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cpi->last_frame_uf);
324    }
325#endif
326
327    if (cm->frame_type == KEY_FRAME)
328        cm->sharpness_level = 0;
329    else
330        cm->sharpness_level = cpi->oxcf.Sharpness;
331
332    // Enforce a minimum filter level based upon Q
333    min_filter_level = get_min_filter_level(cpi, cm->base_qindex);
334    max_filter_level = get_max_filter_level(cpi, cm->base_qindex);
335
336    // Start the search at the previous frame filter level unless it is now out of range.
337    filt_mid = cm->filter_level;
338
339    if (filt_mid < min_filter_level)
340        filt_mid = min_filter_level;
341    else if (filt_mid > max_filter_level)
342        filt_mid = max_filter_level;
343
344    // Define the initial step size
345    filter_step = (filt_mid < 16) ? 4 : filt_mid / 4;
346
347    // Get baseline error score
348    vp8cx_set_alt_lf_level(cpi, filt_mid);
349    vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_mid, 0);
350    cm->last_frame_type = cm->frame_type;
351    cm->last_filter_type = cm->filter_type;
352    cm->last_sharpness_level = cm->sharpness_level;
353
354    best_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance));
355    filt_best = filt_mid;
356
357    //  Re-instate the unfiltered frame
358#if HAVE_ARMV7
359#if CONFIG_RUNTIME_CPU_DETECT
360    if (cm->rtcd.flags & HAS_NEON)
361#endif
362    {
363        vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show);
364    }
365#if CONFIG_RUNTIME_CPU_DETECT
366    else
367#endif
368#endif
369#if !HAVE_ARMV7 || CONFIG_RUNTIME_CPU_DETECT
370    {
371        vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show);
372    }
373#endif
374
375    while (filter_step > 0)
376    {
377        Bias = (best_err >> (15 - (filt_mid / 8))) * filter_step; //PGW change 12/12/06 for small images
378
379        // jbb chg: 20100118 - in sections with lots of new material coming in don't bias as much to a low filter value
380        if (cpi->section_intra_rating < 20)
381            Bias = Bias * cpi->section_intra_rating / 20;
382
383        filt_high = ((filt_mid + filter_step) > max_filter_level) ? max_filter_level : (filt_mid + filter_step);
384        filt_low = ((filt_mid - filter_step) < min_filter_level) ? min_filter_level : (filt_mid - filter_step);
385
386        if ((filt_direction <= 0) && (filt_low != filt_mid))
387        {
388            // Get Low filter error score
389            vp8cx_set_alt_lf_level(cpi, filt_low);
390            vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_low, 0);
391            cm->last_frame_type = cm->frame_type;
392            cm->last_filter_type = cm->filter_type;
393            cm->last_sharpness_level = cm->sharpness_level;
394
395            filt_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance));
396
397            //  Re-instate the unfiltered frame
398#if HAVE_ARMV7
399#if CONFIG_RUNTIME_CPU_DETECT
400            if (cm->rtcd.flags & HAS_NEON)
401#endif
402            {
403                vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show);
404            }
405#if CONFIG_RUNTIME_CPU_DETECT
406            else
407#endif
408#endif
409#if !HAVE_ARMV7 || CONFIG_RUNTIME_CPU_DETECT
410            {
411                vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show);
412            }
413#endif
414
415            // If value is close to the best so far then bias towards a lower loop filter value.
416            if ((filt_err - Bias) < best_err)
417            {
418                // Was it actually better than the previous best?
419                if (filt_err < best_err)
420                    best_err = filt_err;
421
422                filt_best = filt_low;
423            }
424        }
425
426        // Now look at filt_high
427        if ((filt_direction >= 0) && (filt_high != filt_mid))
428        {
429            vp8cx_set_alt_lf_level(cpi, filt_high);
430            vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_high, 0);
431            cm->last_frame_type = cm->frame_type;
432            cm->last_filter_type = cm->filter_type;
433            cm->last_sharpness_level = cm->sharpness_level;
434
435            filt_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance));
436
437            //  Re-instate the unfiltered frame
438#if HAVE_ARMV7
439#if CONFIG_RUNTIME_CPU_DETECT
440            if (cm->rtcd.flags & HAS_NEON)
441#endif
442            {
443                vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show);
444            }
445#if CONFIG_RUNTIME_CPU_DETECT
446            else
447#endif
448#endif
449#if !HAVE_ARMV7 || CONFIG_RUNTIME_CPU_DETECT
450            {
451                vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show);
452            }
453#endif
454
455            // Was it better than the previous best?
456            if (filt_err < (best_err - Bias))
457            {
458                best_err = filt_err;
459                filt_best = filt_high;
460            }
461        }
462
463        // Half the step distance if the best filter value was the same as last time
464        if (filt_best == filt_mid)
465        {
466            filter_step = filter_step / 2;
467            filt_direction = 0;
468        }
469        else
470        {
471            filt_direction = (filt_best < filt_mid) ? -1 : 1;
472            filt_mid = filt_best;
473        }
474    }
475
476    cm->filter_level = filt_best;
477    cpi->last_auto_filt_val = filt_best;
478    cpi->last_auto_filt_q  = cm->base_qindex;
479
480    cpi->frames_since_auto_filter = 0;
481}
482