| /* |
| * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <memory.h> |
| #include <stdbool.h> |
| |
| #include "./vpx_config.h" |
| #include "vp9/common/vp9_loopfilter.h" |
| #include "vpx_dsp/vpx_dsp_common.h" |
| #include "vpx_ports/mem.h" |
| |
| #include "vp9/common/vp9_seg_common.h" |
| |
| static void update_sharpness(loop_filter_info_n *lfi, int sharpness_lvl) { |
| int lvl; |
| |
| // For each possible value for the loop filter fill out limits |
| for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) { |
| // Set loop filter parameters that control sharpness. |
| int block_inside_limit = lvl >> ((sharpness_lvl > 0) + (sharpness_lvl > 4)); |
| |
| if (sharpness_lvl > 0) { |
| if (block_inside_limit > (9 - sharpness_lvl)) |
| block_inside_limit = (9 - sharpness_lvl); |
| } |
| |
| if (block_inside_limit < 1) block_inside_limit = 1; |
| |
| memset(lfi->lfthr[lvl].lim, block_inside_limit, SIMD_WIDTH); |
| memset(lfi->lfthr[lvl].mblim, (2 * (lvl + 2) + block_inside_limit), |
| SIMD_WIDTH); |
| } |
| } |
| |
| void vp9_loop_filter_init(loop_filter_info_n *lfi, struct loopfilter *lf) { |
| int lvl; |
| |
| // init limits for given sharpness |
| update_sharpness(lfi, lf->sharpness_level); |
| lf->last_sharpness_level = lf->sharpness_level; |
| |
| // init hev threshold const vectors |
| for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) |
| memset(lfi->lfthr[lvl].hev_thr, (lvl >> 4), SIMD_WIDTH); |
| } |
| |
| void vp9_loop_filter_frame_init(struct loopfilter *lf, loop_filter_info_n *lfi, |
| struct segmentation *seg, int default_filt_lvl, |
| bool *sharpness_updated_out) { |
| int seg_id; |
| // n_shift is the multiplier for lf_deltas |
| // the multiplier is 1 for when filter_lvl is between 0 and 31; |
| // 2 when filter_lvl is between 32 and 63 |
| const int scale = 1 << (default_filt_lvl >> 5); |
| |
| *sharpness_updated_out = false; |
| // update limits if sharpness has changed |
| if (lf->last_sharpness_level != lf->sharpness_level) { |
| update_sharpness(lfi, lf->sharpness_level); |
| lf->last_sharpness_level = lf->sharpness_level; |
| *sharpness_updated_out = true; |
| } |
| |
| for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) { |
| int lvl_seg = default_filt_lvl; |
| if (segfeature_active(seg, seg_id, SEG_LVL_ALT_LF)) { |
| const int data = get_segdata(seg, seg_id, SEG_LVL_ALT_LF); |
| lvl_seg = clamp( |
| seg->abs_delta == SEGMENT_ABSDATA ? data : default_filt_lvl + data, 0, |
| MAX_LOOP_FILTER); |
| } |
| |
| if (!lf->mode_ref_delta_enabled) { |
| // we could get rid of this if we assume that deltas are set to |
| // zero when not in use; encoder always uses deltas |
| memset(lfi->lvl[seg_id], lvl_seg, sizeof(lfi->lvl[seg_id])); |
| } else { |
| int ref, mode; |
| const int intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME] * scale; |
| lfi->lvl[seg_id][INTRA_FRAME][0] = clamp(intra_lvl, 0, MAX_LOOP_FILTER); |
| |
| for (ref = LAST_FRAME; ref < MAX_REF_FRAMES; ++ref) { |
| for (mode = 0; mode < MAX_MODE_LF_DELTAS; ++mode) { |
| const int inter_lvl = lvl_seg + lf->ref_deltas[ref] * scale + |
| lf->mode_deltas[mode] * scale; |
| lfi->lvl[seg_id][ref][mode] = clamp(inter_lvl, 0, MAX_LOOP_FILTER); |
| } |
| } |
| } |
| } |
| } |
| |