xref: /aosp_15_r20/external/libaom/av1/encoder/picklpf.h (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker #ifndef AOM_AV1_ENCODER_PICKLPF_H_
13*77c1e3ccSAndroid Build Coastguard Worker #define AOM_AV1_ENCODER_PICKLPF_H_
14*77c1e3ccSAndroid Build Coastguard Worker 
15*77c1e3ccSAndroid Build Coastguard Worker #ifdef __cplusplus
16*77c1e3ccSAndroid Build Coastguard Worker extern "C" {
17*77c1e3ccSAndroid Build Coastguard Worker #endif
18*77c1e3ccSAndroid Build Coastguard Worker 
19*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder.h"
20*77c1e3ccSAndroid Build Coastguard Worker 
21*77c1e3ccSAndroid Build Coastguard Worker struct yv12_buffer_config;
22*77c1e3ccSAndroid Build Coastguard Worker struct AV1_COMP;
23*77c1e3ccSAndroid Build Coastguard Worker 
24*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Algorithm for AV1 loop filter level selection.
25*77c1e3ccSAndroid Build Coastguard Worker  *
26*77c1e3ccSAndroid Build Coastguard Worker  * \ingroup in_loop_filter
27*77c1e3ccSAndroid Build Coastguard Worker  * This function determines proper filter levels used for in-loop filter
28*77c1e3ccSAndroid Build Coastguard Worker  * (deblock filter).
29*77c1e3ccSAndroid Build Coastguard Worker  *
30*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]    sd             The pointer of frame buffer
31*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]    cpi            Top-level encoder structure
32*77c1e3ccSAndroid Build Coastguard Worker  * \param[in]    method         The method used to select filter levels
33*77c1e3ccSAndroid Build Coastguard Worker  *
34*77c1e3ccSAndroid Build Coastguard Worker  * \par
35*77c1e3ccSAndroid Build Coastguard Worker  * method includes:
36*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c LPF_PICK_FROM_FULL_IMAGE:  Try the full image with different values.
37*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c LPF_PICK_FROM_FULL_IMAGE_NON_DUAL: Try the full image filter search
38*77c1e3ccSAndroid Build Coastguard Worker  * with non-dual filter only.
39*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c LPF_PICK_FROM_SUBIMAGE: Try a small portion of the image with
40*77c1e3ccSAndroid Build Coastguard Worker  * different values.
41*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c LPF_PICK_FROM_Q: Estimate the level based on quantizer and frame type
42*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c LPF_PICK_MINIMAL_LPF: Pick 0 to disable LPF if LPF was enabled last
43*77c1e3ccSAndroid Build Coastguard Worker  * frame
44*77c1e3ccSAndroid Build Coastguard Worker  *
45*77c1e3ccSAndroid Build Coastguard Worker  * \remark Nothing is returned. Instead, filter levels below are stored in the
46*77c1e3ccSAndroid Build Coastguard Worker  * "loopfilter" structure inside "cpi":
47*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c filter_level[0]: the vertical filter level for Y plane
48*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c filter_level[1]: the horizontal filter level for Y plane
49*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c filter_level_u: the filter level for U plane
50*77c1e3ccSAndroid Build Coastguard Worker  * \arg \c filter_level_v: the filter level for V plane
51*77c1e3ccSAndroid Build Coastguard Worker  *
52*77c1e3ccSAndroid Build Coastguard Worker  * \n
53*77c1e3ccSAndroid Build Coastguard Worker  * \b Overview
54*77c1e3ccSAndroid Build Coastguard Worker  * \par
55*77c1e3ccSAndroid Build Coastguard Worker  * The workflow of deblock filter is shown in Fig.1. \n
56*77c1e3ccSAndroid Build Coastguard Worker  * Boundary pixels pass through a non-flatness check, followed by a step that
57*77c1e3ccSAndroid Build Coastguard Worker  * determines smoothness and selects proper types of filters
58*77c1e3ccSAndroid Build Coastguard Worker  * (4-, 6-, 8-, 14-tap filter). \n
59*77c1e3ccSAndroid Build Coastguard Worker  * If non-flatness criteria is not satisfied, the encoder will not apply
60*77c1e3ccSAndroid Build Coastguard Worker  * deblock filtering on these boundary pixels.
61*77c1e3ccSAndroid Build Coastguard Worker  * \image html filter_flow.png "Fig.1. The workflow of deblock filter" width=70%
62*77c1e3ccSAndroid Build Coastguard Worker  *
63*77c1e3ccSAndroid Build Coastguard Worker  * \par
64*77c1e3ccSAndroid Build Coastguard Worker  * The non-flatness is determined by the boundary pixels and thresholds as shown
65*77c1e3ccSAndroid Build Coastguard Worker  * in Fig.2. \n
66*77c1e3ccSAndroid Build Coastguard Worker  * Filtering is applied when \n
67*77c1e3ccSAndroid Build Coastguard Worker  * \f$|p_0-p_1|<thr_1\f$   and   \f$|q_0-q_1|<thr_1\f$   and
68*77c1e3ccSAndroid Build Coastguard Worker  * \f$2*|p_0-q_0|+|p_1-q_1|/2<thr_2\f$ \n
69*77c1e3ccSAndroid Build Coastguard Worker  * \image html filter_thr.png "Fig.2. Non-flatness of pixel boundary" height=40%
70*77c1e3ccSAndroid Build Coastguard Worker  *
71*77c1e3ccSAndroid Build Coastguard Worker  * \par
72*77c1e3ccSAndroid Build Coastguard Worker  * Thresholds ("thr_1" and "thr_2") are determined by the filter level. \n
73*77c1e3ccSAndroid Build Coastguard Worker  * In AV1, for each frame, we employ the four filter levels, based on these
74*77c1e3ccSAndroid Build Coastguard Worker  * observations: \n
75*77c1e3ccSAndroid Build Coastguard Worker  * Luma and chroma planes have different characteristics, including subsampling
76*77c1e3ccSAndroid Build Coastguard Worker  * (different plane size), coding quality (chroma planes are better coded). \n
77*77c1e3ccSAndroid Build Coastguard Worker  * Therefore chroma planes need less deblocking filtering than luma plane. \n
78*77c1e3ccSAndroid Build Coastguard Worker  * In addition, content texture has different spatial characteristics: vertical
79*77c1e3ccSAndroid Build Coastguard Worker  * and horizontal direction may need different level of filtering. \n
80*77c1e3ccSAndroid Build Coastguard Worker  * The selection of these filter levels is described in the following section.
81*77c1e3ccSAndroid Build Coastguard Worker  *
82*77c1e3ccSAndroid Build Coastguard Worker  * \par
83*77c1e3ccSAndroid Build Coastguard Worker  * \b Algorithm
84*77c1e3ccSAndroid Build Coastguard Worker  * \par
85*77c1e3ccSAndroid Build Coastguard Worker  * The encoder selects filter levels given the current frame buffer, and the
86*77c1e3ccSAndroid Build Coastguard Worker  * method. \n
87*77c1e3ccSAndroid Build Coastguard Worker  * By default, "LPF_PICK_FROM_FULL_IMAGE" is used, which should provide
88*77c1e3ccSAndroid Build Coastguard Worker  * the most appropriate filter levels. \n
89*77c1e3ccSAndroid Build Coastguard Worker  * For video on demand (VOD) mode, if speed setting is larger than 5,
90*77c1e3ccSAndroid Build Coastguard Worker  * "LPF_PICK_FROM_FULL_IMAGE_NON_DUAL" is used. \n
91*77c1e3ccSAndroid Build Coastguard Worker  * For real-time mode, if speed setting is larger than 5, "LPF_PICK_FROM_Q" is
92*77c1e3ccSAndroid Build Coastguard Worker  * used.
93*77c1e3ccSAndroid Build Coastguard Worker  *
94*77c1e3ccSAndroid Build Coastguard Worker  * \par
95*77c1e3ccSAndroid Build Coastguard Worker  * "LPF_PICK_FROM_FULL_IMAGE" method: determine filter levels sequentially
96*77c1e3ccSAndroid Build Coastguard Worker  * by a filter level search procedure (function "search_filter_level"). \n
97*77c1e3ccSAndroid Build Coastguard Worker  * The order is: \n
98*77c1e3ccSAndroid Build Coastguard Worker  * First search and determine the filter level for Y plane.
99*77c1e3ccSAndroid Build Coastguard Worker  * Let vertical filter level (filter_level[0]) and the horizontal filter level
100*77c1e3ccSAndroid Build Coastguard Worker  * (filter_level[1]) be equal to it. \n
101*77c1e3ccSAndroid Build Coastguard Worker  * Keep the horizontal filter level the same and search and determine the
102*77c1e3ccSAndroid Build Coastguard Worker  * vertical filter level. \n
103*77c1e3ccSAndroid Build Coastguard Worker  * Search and determine the horizontal filter level. \n
104*77c1e3ccSAndroid Build Coastguard Worker  * Search and determine filter level for U plane. \n
105*77c1e3ccSAndroid Build Coastguard Worker  * Search and determine filter level for V plane.
106*77c1e3ccSAndroid Build Coastguard Worker  *
107*77c1e3ccSAndroid Build Coastguard Worker  * \par
108*77c1e3ccSAndroid Build Coastguard Worker  * Search and determine filter level is fulfilled by function
109*77c1e3ccSAndroid Build Coastguard Worker  * "search_filter_level". \n
110*77c1e3ccSAndroid Build Coastguard Worker  * It starts with a base filter level ("filt_mid") initialized by the
111*77c1e3ccSAndroid Build Coastguard Worker  * corresponding last frame's filter level. \n
112*77c1e3ccSAndroid Build Coastguard Worker  * A filter step ("filter_step") is determined as:
113*77c1e3ccSAndroid Build Coastguard Worker  * filter_step = filt_mid < 16 ? 4 : filt_mid / 4. \n
114*77c1e3ccSAndroid Build Coastguard Worker  * Then a modified binary search strategy is employed to find a proper
115*77c1e3ccSAndroid Build Coastguard Worker  * filter level. \n
116*77c1e3ccSAndroid Build Coastguard Worker  * In each iteration, set filt_low = filt_mid - filter_step,
117*77c1e3ccSAndroid Build Coastguard Worker  * filt_high = filt_mid + filter_step. \n
118*77c1e3ccSAndroid Build Coastguard Worker  * We now have three candidate levels, "filt_mid", "filt_low" and "filt_high".
119*77c1e3ccSAndroid Build Coastguard Worker  * \n
120*77c1e3ccSAndroid Build Coastguard Worker  * Deblock filtering is applied on the current frame with candidate filter
121*77c1e3ccSAndroid Build Coastguard Worker  * levels and the sum of squared error (SSE) between source and filtered frame
122*77c1e3ccSAndroid Build Coastguard Worker  * is computed. \n
123*77c1e3ccSAndroid Build Coastguard Worker  * Set "filt_best" to the filter level of the smallest SSE. If "filter_best"
124*77c1e3ccSAndroid Build Coastguard Worker  * equals to "filt_mid", halve the filter_step. Otherwise, set filt_mid =
125*77c1e3ccSAndroid Build Coastguard Worker  * filt_best. \n
126*77c1e3ccSAndroid Build Coastguard Worker  * Go to the next iteration until "filter_step" is 0. \n
127*77c1e3ccSAndroid Build Coastguard Worker  * Note that in the comparison of SSEs between SSE[filt_low] and SSE[filt_mid],
128*77c1e3ccSAndroid Build Coastguard Worker  * a "bias" is introduced to slightly raise the filter level. \n
129*77c1e3ccSAndroid Build Coastguard Worker  * It is based on the observation that low filter levels tend to yield a smaller
130*77c1e3ccSAndroid Build Coastguard Worker  * SSE and produce a higher PSNR for the current frame, \n
131*77c1e3ccSAndroid Build Coastguard Worker  * while oversmoothing it and degradating the quality for prediction for future
132*77c1e3ccSAndroid Build Coastguard Worker  * frames and leanding to a suboptimal performance overall. \n
133*77c1e3ccSAndroid Build Coastguard Worker  * Function "try_filter_frame" is the referrence for applying deblock filtering
134*77c1e3ccSAndroid Build Coastguard Worker  * with a given filter level and computatition of SSE.
135*77c1e3ccSAndroid Build Coastguard Worker  *
136*77c1e3ccSAndroid Build Coastguard Worker  * \par
137*77c1e3ccSAndroid Build Coastguard Worker  * "LPF_PICK_FROM_FULL_IMAGE_NON_DUAL" method: almost the same as
138*77c1e3ccSAndroid Build Coastguard Worker  * "LPF_PICK_FROM_FULL_IMAGE", \n
139*77c1e3ccSAndroid Build Coastguard Worker  * just without separately searching for appropriate filter levels for vertical
140*77c1e3ccSAndroid Build Coastguard Worker  * and horizontal filters.
141*77c1e3ccSAndroid Build Coastguard Worker  *
142*77c1e3ccSAndroid Build Coastguard Worker  * \par
143*77c1e3ccSAndroid Build Coastguard Worker  * "LPF_PICK_FROM_Q" method: filter levels are determined by the
144*77c1e3ccSAndroid Build Coastguard Worker  * quantization factor (q). \n
145*77c1e3ccSAndroid Build Coastguard Worker  * For 8 bit: \n
146*77c1e3ccSAndroid Build Coastguard Worker  *   Keyframes: filt_guess = q * 0.06699 - 1.60817 \n
147*77c1e3ccSAndroid Build Coastguard Worker  *   Other frames: filt_guess = q * inter_frame_multiplier + 2.48225 \n
148*77c1e3ccSAndroid Build Coastguard Worker  *   inter_frame_multiplier = q > 700 ? 0.04590 : 0.02295 \n
149*77c1e3ccSAndroid Build Coastguard Worker  * For 10 bit and 12 bit: \n
150*77c1e3ccSAndroid Build Coastguard Worker  * filt_guess = q * 0.316206 + 3.87252 \n
151*77c1e3ccSAndroid Build Coastguard Worker  * Then filter_level[0] = filter_level[1] = filter_level_u = filter_level_v =
152*77c1e3ccSAndroid Build Coastguard Worker  * clamp(filt_guess, min_filter_level, max_filter_level) \n
153*77c1e3ccSAndroid Build Coastguard Worker  * Where min_filter_level = 0, max_filter_level = 64 \n
154*77c1e3ccSAndroid Build Coastguard Worker  * The equations were determined by linear fitting using filter levels
155*77c1e3ccSAndroid Build Coastguard Worker  * generated by "LPF_PICK_FROM_FULL_IMAGE" method.
156*77c1e3ccSAndroid Build Coastguard Worker  *
157*77c1e3ccSAndroid Build Coastguard Worker  */
158*77c1e3ccSAndroid Build Coastguard Worker void av1_pick_filter_level(const struct yv12_buffer_config *sd,
159*77c1e3ccSAndroid Build Coastguard Worker                            struct AV1_COMP *cpi, LPF_PICK_METHOD method);
160*77c1e3ccSAndroid Build Coastguard Worker #ifdef __cplusplus
161*77c1e3ccSAndroid Build Coastguard Worker }  // extern "C"
162*77c1e3ccSAndroid Build Coastguard Worker #endif
163*77c1e3ccSAndroid Build Coastguard Worker 
164*77c1e3ccSAndroid Build Coastguard Worker #endif  // AOM_AV1_ENCODER_PICKLPF_H_
165