Commit 179479fe authored by Cheng Chen's avatar Cheng Chen

Dual deblocking filter strength thresholds

A new experiment for deblocking filter that separates vertical
and horizontal filter strengths. This experiment is based on the
assumption that non-flatness characteristics of vertical and
horizontal direction may differ. Therefore selecting different
filter strengths for vertical and horizontal can improve deblocking
performance.

The process of finding proper filter strength:
1. Search through the filter level under the constraint that
   (vertical == horizontal), and find the best solution.
2. Fix vertical level as the best solution found in step 1 and vary
   horizontal level to find the best value.
3. Fix the selected horizontal level, vary vertical level to find
   its best value.

The experiment is working with UV_LVL, sharing the same config flag.
The searching for horizontal and vertical filter strength only applies
on Y plane for now.

The experimental flag should be changed to filter_level later.

Change-Id: I164eec8d3ccb3da7ff109c5c55f4b52c1536ddf1
parent 680b9b17
...@@ -595,6 +595,9 @@ static void update_sharpness(loop_filter_info_n *lfi, int sharpness_lvl) { ...@@ -595,6 +595,9 @@ static void update_sharpness(loop_filter_info_n *lfi, int sharpness_lvl) {
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
static uint8_t get_filter_level(const AV1_COMMON *cm, static uint8_t get_filter_level(const AV1_COMMON *cm,
const loop_filter_info_n *lfi_n, const loop_filter_info_n *lfi_n,
#if CONFIG_UV_LVL
const int dir_idx,
#endif
const MB_MODE_INFO *mbmi) { const MB_MODE_INFO *mbmi) {
#if CONFIG_SUPERTX #if CONFIG_SUPERTX
const int segment_id = AOMMIN(mbmi->segment_id, mbmi->segment_id_supertx); const int segment_id = AOMMIN(mbmi->segment_id, mbmi->segment_id_supertx);
...@@ -606,8 +609,14 @@ static uint8_t get_filter_level(const AV1_COMMON *cm, ...@@ -606,8 +609,14 @@ static uint8_t get_filter_level(const AV1_COMMON *cm,
const int segment_id = mbmi->segment_id; const int segment_id = mbmi->segment_id;
#endif // CONFIG_SUPERTX #endif // CONFIG_SUPERTX
if (cm->delta_lf_present_flag) { if (cm->delta_lf_present_flag) {
#if CONFIG_UV_LVL
int lvl_seg =
clamp(mbmi->current_delta_lf_from_base + cm->lf.filter_level[dir_idx],
0, MAX_LOOP_FILTER);
#else
int lvl_seg = clamp(mbmi->current_delta_lf_from_base + cm->lf.filter_level, int lvl_seg = clamp(mbmi->current_delta_lf_from_base + cm->lf.filter_level,
0, MAX_LOOP_FILTER); 0, MAX_LOOP_FILTER);
#endif
const int scale = 1 << (lvl_seg >> 5); const int scale = 1 << (lvl_seg >> 5);
if (segfeature_active(&cm->seg, segment_id, SEG_LVL_ALT_LF)) { if (segfeature_active(&cm->seg, segment_id, SEG_LVL_ALT_LF)) {
const int data = get_segdata(&cm->seg, segment_id, SEG_LVL_ALT_LF); const int data = get_segdata(&cm->seg, segment_id, SEG_LVL_ALT_LF);
...@@ -624,7 +633,12 @@ static uint8_t get_filter_level(const AV1_COMMON *cm, ...@@ -624,7 +633,12 @@ static uint8_t get_filter_level(const AV1_COMMON *cm,
} }
return lvl_seg; return lvl_seg;
} else { } else {
#if CONFIG_UV_LVL
return lfi_n
->lvl[segment_id][dir_idx][mbmi->ref_frame[0]][mode_lf_lut[mbmi->mode]];
#else
return lfi_n->lvl[segment_id][mbmi->ref_frame[0]][mode_lf_lut[mbmi->mode]]; return lfi_n->lvl[segment_id][mbmi->ref_frame[0]][mode_lf_lut[mbmi->mode]];
#endif
} }
} }
#else #else
...@@ -658,12 +672,13 @@ void av1_loop_filter_init(AV1_COMMON *cm) { ...@@ -658,12 +672,13 @@ void av1_loop_filter_init(AV1_COMMON *cm) {
memset(lfi->lfthr[lvl].hev_thr, (lvl >> 4), SIMD_WIDTH); memset(lfi->lfthr[lvl].hev_thr, (lvl >> 4), SIMD_WIDTH);
} }
void av1_loop_filter_frame_init(AV1_COMMON *cm, int default_filt_lvl) { void av1_loop_filter_frame_init(AV1_COMMON *cm, int default_filt_lvl,
int default_filt_lvl_r) {
int seg_id; int seg_id;
// n_shift is the multiplier for lf_deltas // n_shift is the multiplier for lf_deltas
// the multiplier is 1 for when filter_lvl is between 0 and 31; // the multiplier is 1 for when filter_lvl is between 0 and 31;
// 2 when filter_lvl is between 32 and 63 // 2 when filter_lvl is between 32 and 63
const int scale = 1 << (default_filt_lvl >> 5); int scale = 1 << (default_filt_lvl >> 5);
loop_filter_info_n *const lfi = &cm->lf_info; loop_filter_info_n *const lfi = &cm->lf_info;
struct loopfilter *const lf = &cm->lf; struct loopfilter *const lf = &cm->lf;
const struct segmentation *const seg = &cm->seg; const struct segmentation *const seg = &cm->seg;
...@@ -689,6 +704,26 @@ void av1_loop_filter_frame_init(AV1_COMMON *cm, int default_filt_lvl) { ...@@ -689,6 +704,26 @@ void av1_loop_filter_frame_init(AV1_COMMON *cm, int default_filt_lvl) {
memset(lfi->lvl[seg_id], lvl_seg, sizeof(lfi->lvl[seg_id])); memset(lfi->lvl[seg_id], lvl_seg, sizeof(lfi->lvl[seg_id]));
} else { } else {
int ref, mode; int ref, mode;
#if CONFIG_UV_LVL
for (int dir = 0; dir < 2; ++dir) {
lvl_seg = (dir == 0) ? default_filt_lvl : default_filt_lvl_r;
scale = 1 << (lvl_seg >> 5);
const int intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME] * scale;
lfi->lvl[seg_id][dir][INTRA_FRAME][0] =
clamp(intra_lvl, 0, MAX_LOOP_FILTER);
for (ref = LAST_FRAME; ref < TOTAL_REFS_PER_FRAME; ++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][dir][ref][mode] =
clamp(inter_lvl, 0, MAX_LOOP_FILTER);
}
}
}
#else
(void)default_filt_lvl_r;
const int intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME] * scale; 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); lfi->lvl[seg_id][INTRA_FRAME][0] = clamp(intra_lvl, 0, MAX_LOOP_FILTER);
...@@ -699,6 +734,7 @@ void av1_loop_filter_frame_init(AV1_COMMON *cm, int default_filt_lvl) { ...@@ -699,6 +734,7 @@ void av1_loop_filter_frame_init(AV1_COMMON *cm, int default_filt_lvl) {
lfi->lvl[seg_id][ref][mode] = clamp(inter_lvl, 0, MAX_LOOP_FILTER); lfi->lvl[seg_id][ref][mode] = clamp(inter_lvl, 0, MAX_LOOP_FILTER);
} }
} }
#endif
} }
} }
} }
...@@ -1394,7 +1430,11 @@ static void build_masks(AV1_COMMON *const cm, ...@@ -1394,7 +1430,11 @@ static void build_masks(AV1_COMMON *const cm,
const TX_SIZE tx_size_uv_above = const TX_SIZE tx_size_uv_above =
txsize_vert_map[uv_txsize_lookup[block_size][mbmi->tx_size][1][1]]; txsize_vert_map[uv_txsize_lookup[block_size][mbmi->tx_size][1][1]];
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
#if CONFIG_UV_LVL
const int filter_level = get_filter_level(cm, lfi_n, 0, mbmi);
#else
const int filter_level = get_filter_level(cm, lfi_n, mbmi); const int filter_level = get_filter_level(cm, lfi_n, mbmi);
#endif
#else #else
const int filter_level = get_filter_level(lfi_n, mbmi); const int filter_level = get_filter_level(lfi_n, mbmi);
(void)cm; (void)cm;
...@@ -1488,7 +1528,11 @@ static void build_y_mask(AV1_COMMON *const cm, ...@@ -1488,7 +1528,11 @@ static void build_y_mask(AV1_COMMON *const cm,
const BLOCK_SIZE block_size = mbmi->sb_type; const BLOCK_SIZE block_size = mbmi->sb_type;
#endif #endif
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
#if CONFIG_UV_LVL
const int filter_level = get_filter_level(cm, lfi_n, 0, mbmi);
#else
const int filter_level = get_filter_level(cm, lfi_n, mbmi); const int filter_level = get_filter_level(cm, lfi_n, mbmi);
#endif
#else #else
const int filter_level = get_filter_level(lfi_n, mbmi); const int filter_level = get_filter_level(lfi_n, mbmi);
(void)cm; (void)cm;
...@@ -2093,7 +2137,12 @@ static void get_filter_level_and_masks_non420( ...@@ -2093,7 +2137,12 @@ static void get_filter_level_and_masks_non420(
// Filter level can vary per MI // Filter level can vary per MI
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
#if CONFIG_UV_LVL
if (!(lfl_r[c_step] = get_filter_level(cm, &cm->lf_info, 0, mbmi)))
continue;
#else
if (!(lfl_r[c_step] = get_filter_level(cm, &cm->lf_info, mbmi))) continue; if (!(lfl_r[c_step] = get_filter_level(cm, &cm->lf_info, mbmi))) continue;
#endif
#else #else
if (!(lfl_r[c_step] = get_filter_level(&cm->lf_info, mbmi))) continue; if (!(lfl_r[c_step] = get_filter_level(&cm->lf_info, mbmi))) continue;
#endif #endif
...@@ -2786,7 +2835,12 @@ static void set_lpf_parameters( ...@@ -2786,7 +2835,12 @@ static void set_lpf_parameters(
plane_ptr, scale_horz, scale_vert); plane_ptr, scale_horz, scale_vert);
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
#if CONFIG_UV_LVL
const uint32_t curr_level =
get_filter_level(cm, &cm->lf_info, edge_dir, mbmi);
#else
const uint32_t curr_level = get_filter_level(cm, &cm->lf_info, mbmi); const uint32_t curr_level = get_filter_level(cm, &cm->lf_info, mbmi);
#endif
#else #else
const uint32_t curr_level = get_filter_level(&cm->lf_info, mbmi); const uint32_t curr_level = get_filter_level(&cm->lf_info, mbmi);
#endif // CONFIG_EXT_DELTA_Q #endif // CONFIG_EXT_DELTA_Q
...@@ -2818,8 +2872,13 @@ static void set_lpf_parameters( ...@@ -2818,8 +2872,13 @@ static void set_lpf_parameters(
plane_ptr, scale_horz, scale_vert); plane_ptr, scale_horz, scale_vert);
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
#if CONFIG_UV_LVL
const uint32_t pv_lvl =
get_filter_level(cm, &cm->lf_info, edge_dir, &mi_prev->mbmi);
#else
const uint32_t pv_lvl = const uint32_t pv_lvl =
get_filter_level(cm, &cm->lf_info, &mi_prev->mbmi); get_filter_level(cm, &cm->lf_info, &mi_prev->mbmi);
#endif
#else #else
const uint32_t pv_lvl = const uint32_t pv_lvl =
get_filter_level(&cm->lf_info, &mi_prev->mbmi); get_filter_level(&cm->lf_info, &mi_prev->mbmi);
...@@ -3392,13 +3451,25 @@ void av1_loop_filter_rows(YV12_BUFFER_CONFIG *frame_buffer, AV1_COMMON *cm, ...@@ -3392,13 +3451,25 @@ void av1_loop_filter_rows(YV12_BUFFER_CONFIG *frame_buffer, AV1_COMMON *cm,
} }
void av1_loop_filter_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, void av1_loop_filter_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
MACROBLOCKD *xd, int frame_filter_level, int y_only, MACROBLOCKD *xd, int frame_filter_level,
int partial_frame) { #if CONFIG_UV_LVL
int frame_filter_level_r,
#endif
int y_only, int partial_frame) {
int start_mi_row, end_mi_row, mi_rows_to_filter; int start_mi_row, end_mi_row, mi_rows_to_filter;
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
#if CONFIG_UV_LVL
int orig_filter_level[2] = { cm->lf.filter_level[0], cm->lf.filter_level[1] };
#else
int orig_filter_level = cm->lf.filter_level; int orig_filter_level = cm->lf.filter_level;
#endif #endif
#endif
#if CONFIG_UV_LVL
if (!frame_filter_level && !frame_filter_level_r) return;
#else
if (!frame_filter_level) return; if (!frame_filter_level) return;
#endif
start_mi_row = 0; start_mi_row = 0;
mi_rows_to_filter = cm->mi_rows; mi_rows_to_filter = cm->mi_rows;
if (partial_frame && cm->mi_rows > 8) { if (partial_frame && cm->mi_rows > 8) {
...@@ -3407,14 +3478,29 @@ void av1_loop_filter_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, ...@@ -3407,14 +3478,29 @@ void av1_loop_filter_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
mi_rows_to_filter = AOMMAX(cm->mi_rows / 8, 8); mi_rows_to_filter = AOMMAX(cm->mi_rows / 8, 8);
} }
end_mi_row = start_mi_row + mi_rows_to_filter; end_mi_row = start_mi_row + mi_rows_to_filter;
av1_loop_filter_frame_init(cm, frame_filter_level); #if CONFIG_UV_LVL
av1_loop_filter_frame_init(cm, frame_filter_level, frame_filter_level_r);
#else
av1_loop_filter_frame_init(cm, frame_filter_level, frame_filter_level);
#endif
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
#if CONFIG_UV_LVL
cm->lf.filter_level[0] = frame_filter_level;
cm->lf.filter_level[1] = frame_filter_level_r;
#else
cm->lf.filter_level = frame_filter_level; cm->lf.filter_level = frame_filter_level;
#endif
#endif #endif
av1_loop_filter_rows(frame, cm, xd->plane, start_mi_row, end_mi_row, y_only); av1_loop_filter_rows(frame, cm, xd->plane, start_mi_row, end_mi_row, y_only);
#if CONFIG_EXT_DELTA_Q #if CONFIG_EXT_DELTA_Q
#if CONFIG_UV_LVL
cm->lf.filter_level[0] = orig_filter_level[0];
cm->lf.filter_level[1] = orig_filter_level[1];
#else
cm->lf.filter_level = orig_filter_level; cm->lf.filter_level = orig_filter_level;
#endif #endif
#endif
} }
void av1_loop_filter_data_reset( void av1_loop_filter_data_reset(
......
...@@ -36,10 +36,12 @@ enum lf_path { ...@@ -36,10 +36,12 @@ enum lf_path {
}; };
struct loopfilter { struct loopfilter {
int filter_level;
#if CONFIG_UV_LVL #if CONFIG_UV_LVL
int filter_level[2];
int filter_level_u; int filter_level_u;
int filter_level_v; int filter_level_v;
#else
int filter_level;
#endif #endif
int sharpness_level; int sharpness_level;
...@@ -69,7 +71,11 @@ typedef struct { ...@@ -69,7 +71,11 @@ typedef struct {
typedef struct { typedef struct {
loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1]; loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
#if CONFIG_UV_LVL
uint8_t lvl[MAX_SEGMENTS][2][TOTAL_REFS_PER_FRAME][MAX_MODE_LF_DELTAS];
#else
uint8_t lvl[MAX_SEGMENTS][TOTAL_REFS_PER_FRAME][MAX_MODE_LF_DELTAS]; uint8_t lvl[MAX_SEGMENTS][TOTAL_REFS_PER_FRAME][MAX_MODE_LF_DELTAS];
#endif
} loop_filter_info_n; } loop_filter_info_n;
// This structure holds bit masks for all 8x8 blocks in a 64x64 region. // This structure holds bit masks for all 8x8 blocks in a 64x64 region.
...@@ -132,10 +138,14 @@ void av1_loop_filter_init(struct AV1Common *cm); ...@@ -132,10 +138,14 @@ void av1_loop_filter_init(struct AV1Common *cm);
// This should be called before av1_loop_filter_rows(), // This should be called before av1_loop_filter_rows(),
// av1_loop_filter_frame() // av1_loop_filter_frame()
// calls this function directly. // calls this function directly.
void av1_loop_filter_frame_init(struct AV1Common *cm, int default_filt_lvl); void av1_loop_filter_frame_init(struct AV1Common *cm, int default_filt_lvl,
int default_filt_lvl_r);
void av1_loop_filter_frame(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm, void av1_loop_filter_frame(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm,
struct macroblockd *mbd, int filter_level, struct macroblockd *mbd, int filter_level,
#if CONFIG_UV_LVL
int filter_level_r,
#endif
int y_only, int partial_frame); int y_only, int partial_frame);
// Apply the loop filter to [start, stop) macro block rows in frame_buffer. // Apply the loop filter to [start, stop) macro block rows in frame_buffer.
......
...@@ -416,8 +416,11 @@ static void loop_filter_rows_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, ...@@ -416,8 +416,11 @@ static void loop_filter_rows_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
void av1_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, void av1_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
struct macroblockd_plane planes[MAX_MB_PLANE], struct macroblockd_plane planes[MAX_MB_PLANE],
int frame_filter_level, int y_only, int frame_filter_level,
int partial_frame, AVxWorker *workers, #if CONFIG_UV_LVL
int frame_filter_level_r,
#endif
int y_only, int partial_frame, AVxWorker *workers,
int num_workers, AV1LfSync *lf_sync) { int num_workers, AV1LfSync *lf_sync) {
int start_mi_row, end_mi_row, mi_rows_to_filter; int start_mi_row, end_mi_row, mi_rows_to_filter;
...@@ -431,8 +434,11 @@ void av1_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, ...@@ -431,8 +434,11 @@ void av1_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
mi_rows_to_filter = AOMMAX(cm->mi_rows / 8, 8); mi_rows_to_filter = AOMMAX(cm->mi_rows / 8, 8);
} }
end_mi_row = start_mi_row + mi_rows_to_filter; end_mi_row = start_mi_row + mi_rows_to_filter;
av1_loop_filter_frame_init(cm, frame_filter_level); #if CONFIG_UV_LVL
av1_loop_filter_frame_init(cm, frame_filter_level, frame_filter_level_r);
#else
av1_loop_filter_frame_init(cm, frame_filter_level, frame_filter_level);
#endif // CONFIG_UV_LVL
loop_filter_rows_mt(frame, cm, planes, start_mi_row, end_mi_row, y_only, loop_filter_rows_mt(frame, cm, planes, start_mi_row, end_mi_row, y_only,
workers, num_workers, lf_sync); workers, num_workers, lf_sync);
} }
......
...@@ -50,8 +50,11 @@ void av1_loop_filter_dealloc(AV1LfSync *lf_sync); ...@@ -50,8 +50,11 @@ void av1_loop_filter_dealloc(AV1LfSync *lf_sync);
// Multi-threaded loopfilter that uses the tile threads. // Multi-threaded loopfilter that uses the tile threads.
void av1_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm, void av1_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm,
struct macroblockd_plane planes[MAX_MB_PLANE], struct macroblockd_plane planes[MAX_MB_PLANE],
int frame_filter_level, int y_only, int frame_filter_level,
int partial_frame, AVxWorker *workers, #if CONFIG_UV_LVL
int frame_filter_level_r,
#endif
int y_only, int partial_frame, AVxWorker *workers,
int num_workers, AV1LfSync *lf_sync); int num_workers, AV1LfSync *lf_sync);
void av1_accumulate_frame_counts(struct FRAME_COUNTS *acc_counts, void av1_accumulate_frame_counts(struct FRAME_COUNTS *acc_counts,
......
...@@ -2842,12 +2842,15 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) { ...@@ -2842,12 +2842,15 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
static void setup_loopfilter(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { static void setup_loopfilter(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) {
struct loopfilter *lf = &cm->lf; struct loopfilter *lf = &cm->lf;
lf->filter_level = aom_rb_read_literal(rb, 6);
#if CONFIG_UV_LVL #if CONFIG_UV_LVL
if (lf->filter_level > 0) { lf->filter_level[0] = aom_rb_read_literal(rb, 6);
lf->filter_level[1] = aom_rb_read_literal(rb, 6);
if (lf->filter_level[0] || lf->filter_level[1]) {
lf->filter_level_u = aom_rb_read_literal(rb, 6); lf->filter_level_u = aom_rb_read_literal(rb, 6);
lf->filter_level_v = aom_rb_read_literal(rb, 6); lf->filter_level_v = aom_rb_read_literal(rb, 6);
} }
#else
lf->filter_level = aom_rb_read_literal(rb, 6);
#endif #endif
lf->sharpness_level = aom_rb_read_literal(rb, 3); lf->sharpness_level = aom_rb_read_literal(rb, 3);
...@@ -3808,13 +3811,13 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data, ...@@ -3808,13 +3811,13 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data,
#if CONFIG_VAR_TX || CONFIG_CB4X4 #if CONFIG_VAR_TX || CONFIG_CB4X4
// Loopfilter the whole frame. // Loopfilter the whole frame.
#if CONFIG_UV_LVL #if CONFIG_UV_LVL
if (cm->lf.filter_level > 0) { if (cm->lf.filter_level[0] || cm->lf.filter_level[1]) {
av1_loop_filter_frame(get_frame_new_buffer(cm), cm, &pbi->mb, av1_loop_filter_frame(get_frame_new_buffer(cm), cm, &pbi->mb,
cm->lf.filter_level, 0, 0); cm->lf.filter_level[0], cm->lf.filter_level[1], 0, 0);
av1_loop_filter_frame(get_frame_new_buffer(cm), cm, &pbi->mb, av1_loop_filter_frame(get_frame_new_buffer(cm), cm, &pbi->mb,
cm->lf.filter_level_u, 1, 0); cm->lf.filter_level_u, cm->lf.filter_level_u, 1, 0);
av1_loop_filter_frame(get_frame_new_buffer(cm), cm, &pbi->mb, av1_loop_filter_frame(get_frame_new_buffer(cm), cm, &pbi->mb,
cm->lf.filter_level_v, 2, 0); cm->lf.filter_level_v, cm->lf.filter_level_v, 2, 0);
} }
#else #else
av1_loop_filter_frame(get_frame_new_buffer(cm), cm, &pbi->mb, av1_loop_filter_frame(get_frame_new_buffer(cm), cm, &pbi->mb,
...@@ -4340,7 +4343,12 @@ static size_t read_uncompressed_header(AV1Decoder *pbi, ...@@ -4340,7 +4343,12 @@ static size_t read_uncompressed_header(AV1Decoder *pbi,
ref_cnt_fb(frame_bufs, &cm->new_fb_idx, frame_to_show); ref_cnt_fb(frame_bufs, &cm->new_fb_idx, frame_to_show);
unlock_buffer_pool(pool); unlock_buffer_pool(pool);
#if CONFIG_UV_LVL
cm->lf.filter_level[0] = 0;
cm->lf.filter_level[1] = 0;
#else
cm->lf.filter_level = 0; cm->lf.filter_level = 0;
#endif
cm->show_frame = 1; cm->show_frame = 1;
pbi->refresh_frame_flags = 0; pbi->refresh_frame_flags = 0;
...@@ -5265,9 +5273,17 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data, ...@@ -5265,9 +5273,17 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Decode failed. Frame data header is corrupted."); "Decode failed. Frame data header is corrupted.");
#if CONFIG_UV_LVL
if ((cm->lf.filter_level[0] || cm->lf.filter_level[1]) &&
!cm->skip_loop_filter) {
av1_loop_filter_frame_init(cm, cm->lf.filter_level[0],
cm->lf.filter_level[1]);
}
#else
if (cm->lf.filter_level && !cm->skip_loop_filter) { if (cm->lf.filter_level && !cm->skip_loop_filter) {
av1_loop_filter_frame_init(cm, cm->lf.filter_level); av1_loop_filter_frame_init(cm, cm->lf.filter_level, cm->lf.filter_level);
} }
#endif
// If encoded in frame parallel mode, frame context is ready after decoding // If encoded in frame parallel mode, frame context is ready after decoding
// the frame header. // the frame header.
...@@ -5303,11 +5319,18 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data, ...@@ -5303,11 +5319,18 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
*p_data_end = decode_tiles_mt(pbi, data + first_partition_size, data_end); *p_data_end = decode_tiles_mt(pbi, data + first_partition_size, data_end);
if (!xd->corrupted) { if (!xd->corrupted) {
if (!cm->skip_loop_filter) { if (!cm->skip_loop_filter) {
// If multiple threads are used to decode tiles, then we use those // If multiple threads are used to decode tiles, then we use those
// threads to do parallel loopfiltering. // threads to do parallel loopfiltering.
#if CONFIG_UV_LVL
av1_loop_filter_frame_mt(new_fb, cm, pbi->mb.plane,
cm->lf.filter_level[0], cm->lf.filter_level[1],
0, 0, pbi->tile_workers, pbi->num_tile_workers,
&pbi->lf_row_sync);
#else
av1_loop_filter_frame_mt(new_fb, cm, pbi->mb.plane, cm->lf.filter_level, av1_loop_filter_frame_mt(new_fb, cm, pbi->mb.plane, cm->lf.filter_level,
0, 0, pbi->tile_workers, pbi->num_tile_workers, 0, 0, pbi->tile_workers, pbi->num_tile_workers,
&pbi->lf_row_sync); &pbi->lf_row_sync);
#endif // CONFIG_UV_LVL
} }
} else { } else {
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
......
...@@ -181,7 +181,12 @@ void av1_frameworker_copy_context(AVxWorker *const dst_worker, ...@@ -181,7 +181,12 @@ void av1_frameworker_copy_context(AVxWorker *const dst_worker,
memcpy(dst_cm->lf_info.lfthr, src_cm->lf_info.lfthr, memcpy(dst_cm->lf_info.lfthr, src_cm->lf_info.lfthr,
(MAX_LOOP_FILTER + 1) * sizeof(loop_filter_thresh)); (MAX_LOOP_FILTER + 1) * sizeof(loop_filter_thresh));
dst_cm->lf.last_sharpness_level = src_cm->lf.sharpness_level; dst_cm->lf.last_sharpness_level = src_cm->lf.sharpness_level;
#if CONFIG_UV_LVL
dst_cm->lf.filter_level[0] = src_cm->lf.filter_level[0];
dst_cm->lf.filter_level[1] = src_cm->lf.filter_level[1];
#else
dst_cm->lf.filter_level = src_cm->lf.filter_level; dst_cm->lf.filter_level = src_cm->lf.filter_level;
#endif
memcpy(dst_cm->lf.ref_deltas, src_cm->lf.ref_deltas, TOTAL_REFS_PER_FRAME); memcpy(dst_cm->lf.ref_deltas, src_cm->lf.ref_deltas, TOTAL_REFS_PER_FRAME);
memcpy(dst_cm->lf.mode_deltas, src_cm->lf.mode_deltas, MAX_MODE_LF_DELTAS); memcpy(dst_cm->lf.mode_deltas, src_cm->lf.mode_deltas, MAX_MODE_LF_DELTAS);
dst_cm->seg = src_cm->seg; dst_cm->seg = src_cm->seg;
......
...@@ -3418,13 +3418,16 @@ static void encode_loopfilter(AV1_COMMON *cm, struct aom_write_bit_buffer *wb) { ...@@ -3418,13 +3418,16 @@ static void encode_loopfilter(AV1_COMMON *cm, struct aom_write_bit_buffer *wb) {
int i; int i;
struct loopfilter *lf = &cm->lf; struct loopfilter *lf = &cm->lf;
// Encode the loop filter level and type // Encode the loop filter level and type
aom_wb_write_literal(wb, lf->filter_level, 6);
#if CONFIG_UV_LVL #if CONFIG_UV_LVL
if (lf->filter_level > 0) { aom_wb_write_literal(wb, lf->filter_level[0], 6);
aom_wb_write_literal(wb, lf->filter_level[1], 6);
if (lf->filter_level[0] || lf->filter_level[1]) {
aom_wb_write_literal(wb, lf->filter_level_u, 6); aom_wb_write_literal(wb, lf->filter_level_u, 6);
aom_wb_write_literal(wb, lf->filter_level_v, 6); aom_wb_write_literal(wb, lf->filter_level_v, 6);
} }
#else
aom_wb_write_literal(wb, lf->filter_level, 6);
#endif #endif
aom_wb_write_literal(wb, lf->sharpness_level, 3); aom_wb_write_literal(wb, lf->sharpness_level, 3);
......
...@@ -4134,7 +4134,12 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { ...@@ -4134,7 +4134,12 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) {
#endif // CONFIG_EXT_TILE #endif // CONFIG_EXT_TILE
if (no_loopfilter) { if (no_loopfilter) {
#if CONFIG_UV_LVL
lf->filter_level[0] = 0;
lf->filter_level[1] = 0;
#else
lf->filter_level = 0; lf->filter_level = 0;
#endif
} else { } else {
struct aom_usec_timer timer; struct aom_usec_timer timer;
...@@ -4148,12 +4153,21 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { ...@@ -4148,12 +4153,21 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) {
cpi->time_pick_lpf += aom_usec_timer_elapsed(&timer); cpi->time_pick_lpf += aom_usec_timer_elapsed(&timer);
} }
if (lf->filter_level > 0) { #if CONFIG_UV_LVL
if (lf->filter_level[0] || lf->filter_level[1])
#else
if (lf->filter_level > 0)
#endif
{
#if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4 #if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
#if CONFIG_UV_LVL #if CONFIG_UV_LVL
av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0); av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level[0],
av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level_u, 1, 0); lf->filter_level[1], 0, 0);
av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level_v, 2, 0); av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level_u,
lf->filter_level_u, 1, 0);
av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level_v,
lf->filter_level_v, 2, 0);
#else #else
av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0); av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
#endif // CONFIG_UV_LVL #endif // CONFIG_UV_LVL
......
...@@ -51,7 +51,7 @@ static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd, ...@@ -51,7 +51,7 @@ static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd,
int partial_frame int partial_frame
#if CONFIG_UV_LVL #if CONFIG_UV_LVL
, ,
int plane int plane, int dir
#endif #endif
) { ) {
AV1_COMMON *const cm = &cpi->common; AV1_COMMON *const cm = &cpi->common;
...@@ -60,8 +60,12 @@ static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd, ...@@ -60,8 +60,12 @@ static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd,
#if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4 #if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
#if CONFIG_UV_LVL #if CONFIG_UV_LVL
assert(plane >= 0 && plane <= 2); assert(plane >= 0 && plane <= 2);
av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level, int filter_level[2] = { filt_level, filt_level };
plane, partial_frame); if (plane == 0 && dir == 0) filter_level[1] = cm->lf.filter_level[1];
if (plane == 0 && dir == 1) filter_level[0] = cm->lf.filter_level[0];
av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd,
filter_level[0], filter_level[1], plane, partial_frame);
#else #else
av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level, 1, av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level, 1,
partial_frame); partial_frame);
...@@ -100,7 +104,7 @@ int av1_search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi, ...@@ -100,7 +104,7 @@ int av1_search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
int partial_frame, double *best_cost_ret int partial_frame, double *best_cost_ret
#if CONFIG_UV_LVL #if CONFIG_UV_LVL
,