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