Make LOOPFILTER_LEVEL support EXT_DELTA_Q
Before LOOPFILTER_LEVEL, there's one filter level,
now we have four filter levels for y plane vertical,
y plane horizontal, u plane and v plane.
This patch enables experiment LOOPFILTER_LEVEL to support per
superblock loop filter level update.
Change-Id: Ib11a1564471eb3076c26e73e5cdf7b5a3045ef97
diff --git a/av1/common/av1_loopfilter.c b/av1/common/av1_loopfilter.c
index a548a43..a3c3527 100644
--- a/av1/common/av1_loopfilter.c
+++ b/av1/common/av1_loopfilter.c
@@ -27,6 +27,12 @@
{ SEG_LVL_ALT_LF_U, SEG_LVL_ALT_LF_U },
{ SEG_LVL_ALT_LF_V, SEG_LVL_ALT_LF_V }
};
+
+#if CONFIG_EXT_DELTA_Q
+static const int delta_lf_id_lut[MAX_MB_PLANE][2] = {
+ { 0, 1 }, { 2, 2 }, { 3, 3 }
+};
+#endif // CONFIG_EXT_DELTA_Q
#endif // CONFIG_LOOPFILTER_LEVEL
#if CONFIG_LPF_DIRECT
@@ -645,9 +651,10 @@
#endif // CONFIG_SUPERTX
if (cm->delta_lf_present_flag) {
#if CONFIG_LOOPFILTER_LEVEL
+ const int delta_lf_idx = delta_lf_id_lut[plane][dir_idx];
+ const int delta_lf = mbmi->curr_delta_lf[delta_lf_idx];
int lvl_seg =
- clamp(mbmi->current_delta_lf_from_base + cm->lf.filter_level[dir_idx],
- 0, MAX_LOOP_FILTER);
+ clamp(delta_lf + 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,
0, MAX_LOOP_FILTER);
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index 0c9f6b7..01214f3 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -445,6 +445,9 @@
int current_q_index;
#if CONFIG_EXT_DELTA_Q
int current_delta_lf_from_base;
+#if CONFIG_LOOPFILTER_LEVEL
+ int curr_delta_lf[FRAME_LF_COUNT];
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif
#if CONFIG_RD_DEBUG
RD_STATS rd_stats;
@@ -805,6 +808,23 @@
// superblock's actual lf and current lf.
int prev_delta_lf_from_base;
int current_delta_lf_from_base;
+#if CONFIG_LOOPFILTER_LEVEL
+ // For this experiment, we have four frame filter levels for different plane
+ // and direction. So, to support the per superblock update, we need to add
+ // a few more params as below.
+ // 0: delta loop filter level for y plane vertical
+ // 1: delta loop filter level for y plane horizontal
+ // 2: delta loop filter level for u plane
+ // 3: delta loop filter level for v plane
+ // To make it consistent with the reference to each filter level in segment,
+ // we need to -1, since
+ // SEG_LVL_ALT_LF_Y_V = 1;
+ // SEG_LVL_ALT_LF_Y_H = 2;
+ // SEG_LVL_ALT_LF_U = 3;
+ // SEG_LVL_ALT_LF_V = 4;
+ int prev_delta_lf[FRAME_LF_COUNT];
+ int curr_delta_lf[FRAME_LF_COUNT];
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif
#if CONFIG_ADAPT_SCAN
const EobThresholdMD *eob_threshold_md;
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index a69f691..9742ad2 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -1683,11 +1683,24 @@
AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0
};
#if CONFIG_EXT_DELTA_Q
+#if CONFIG_LOOPFILTER_LEVEL
+static const aom_prob default_delta_lf_probs[FRAME_LF_COUNT][DELTA_LF_PROBS] = {
+ { 220, 220, 220 }, { 220, 220, 220 }, { 220, 220, 220 }, { 220, 220, 220 }
+};
+static const aom_cdf_prob
+ default_delta_lf_cdf[FRAME_LF_COUNT][CDF_SIZE(DELTA_LF_PROBS + 1)] = {
+ { AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0 },
+ { AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0 },
+ { AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0 },
+ { AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0 }
+ };
+#else
static const aom_prob default_delta_lf_probs[DELTA_LF_PROBS] = { 220, 220,
220 };
static const aom_cdf_prob default_delta_lf_cdf[CDF_SIZE(DELTA_LF_PROBS + 1)] = {
AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0
};
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif
#if CONFIG_SMOOTH_HV
@@ -5287,9 +5300,16 @@
fc->delta_q_prob[i] =
mode_mv_merge_probs(pre_fc->delta_q_prob[i], counts->delta_q[i]);
#if CONFIG_EXT_DELTA_Q
+#if CONFIG_LOOPFILTER_LEVEL
+ for (i = 0; i < FRAME_LF_COUNT; ++i)
+ for (int j = 0; j < DELTA_LF_PROBS; ++j)
+ fc->delta_lf_prob[i][j] = mode_mv_merge_probs(pre_fc->delta_lf_prob[i][j],
+ counts->delta_lf[i][j]);
+#else
for (i = 0; i < DELTA_LF_PROBS; ++i)
fc->delta_lf_prob[i] =
mode_mv_merge_probs(pre_fc->delta_lf_prob[i], counts->delta_lf[i]);
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif // CONFIG_EXT_DELTA_Q
#if CONFIG_EXT_INTRA
#if CONFIG_INTRA_INTERP
diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h
index 1dcd283..c9f2d4e 100644
--- a/av1/common/entropymode.h
+++ b/av1/common/entropymode.h
@@ -360,7 +360,11 @@
[CDF_SIZE(MAX_TX_DEPTH + 1)];
aom_cdf_prob delta_q_cdf[CDF_SIZE(DELTA_Q_PROBS + 1)];
#if CONFIG_EXT_DELTA_Q
+#if CONFIG_LOOPFILTER_LEVEL
+ aom_cdf_prob delta_lf_cdf[FRAME_LF_COUNT][CDF_SIZE(DELTA_LF_PROBS + 1)];
+#else
aom_cdf_prob delta_lf_cdf[CDF_SIZE(DELTA_LF_PROBS + 1)];
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif
#if CONFIG_EXT_TX
aom_cdf_prob intra_ext_tx_cdf[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
@@ -376,7 +380,11 @@
#endif // CONFIG_EXT_INTRA && CONFIG_INTRA_INTERP
aom_prob delta_q_prob[DELTA_Q_PROBS];
#if CONFIG_EXT_DELTA_Q
+#if CONFIG_LOOPFILTER_LEVEL
+ aom_prob delta_lf_prob[FRAME_LF_COUNT][DELTA_LF_PROBS];
+#else
aom_prob delta_lf_prob[DELTA_LF_PROBS];
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif
#if CONFIG_PVQ
// TODO(any): If PVQ is enabled, most of coefficient related cdf,
@@ -507,7 +515,11 @@
#endif
unsigned int delta_q[DELTA_Q_PROBS][2];
#if CONFIG_EXT_DELTA_Q
+#if CONFIG_LOOPFILTER_LEVEL
+ unsigned int delta_lf[FRAME_LF_COUNT][DELTA_LF_PROBS][2];
+#else
unsigned int delta_lf[DELTA_LF_PROBS][2];
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif
#if CONFIG_EXT_TX && CONFIG_RECT_TX
unsigned int tx_size_implied[TX_SIZES][TX_SIZES];
diff --git a/av1/common/enums.h b/av1/common/enums.h
index 5f3e589..6648138 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -82,6 +82,12 @@
#define MI_SIZE_64X64 (64 >> MI_SIZE_LOG2)
+#if CONFIG_LOOPFILTER_LEVEL
+// 4 frame filter levels: y plane vertical, y plane horizontal,
+// u plane, and v plane
+#define FRAME_LF_COUNT 4
+#endif // CONFIG_LOOPFILTER_LEVEL
+
#if CONFIG_LPF_SB
#define LPF_DELTA_BITS 3
#define LPF_STEP 2
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 1ba7795..84446c7 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -5069,6 +5069,10 @@
assert(!segment_quantizer_active);
cm->delta_lf_present_flag = aom_rb_read_bit(rb);
if (cm->delta_lf_present_flag) {
+#if CONFIG_LOOPFILTER_LEVEL
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
+ xd->prev_delta_lf[lf_id] = 0;
+#endif // CONFIG_LOOPFILTER_LEVEL
xd->prev_delta_lf_from_base = 0;
cm->delta_lf_res = 1 << aom_rb_read_literal(rb, 2);
}
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 4591cc9..f89ab0f 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -79,6 +79,9 @@
}
#if CONFIG_EXT_DELTA_Q
static int read_delta_lflevel(AV1_COMMON *cm, MACROBLOCKD *xd, aom_reader *r,
+#if CONFIG_LOOPFILTER_LEVEL
+ int lf_id,
+#endif
MB_MODE_INFO *const mbmi, int mi_col,
int mi_row) {
FRAME_COUNTS *counts = xd->counts;
@@ -93,12 +96,22 @@
(void)cm;
if ((bsize != BLOCK_64X64 || mbmi->skip == 0) && read_delta_lf_flag) {
+#if CONFIG_LOOPFILTER_LEVEL
+ abs = aom_read_symbol(r, ec_ctx->delta_lf_cdf[lf_id], DELTA_LF_PROBS + 1,
+ ACCT_STR);
+#else
abs =
aom_read_symbol(r, ec_ctx->delta_lf_cdf, DELTA_LF_PROBS + 1, ACCT_STR);
+#endif // CONFIG_LOOPFILTER_LEVEL
smallval = (abs < DELTA_LF_SMALL);
if (counts) {
+#if CONFIG_LOOPFILTER_LEVEL
+ for (i = 0; i < abs; ++i) counts->delta_lf[lf_id][i][1]++;
+ if (smallval) counts->delta_lf[lf_id][abs][0]++;
+#else
for (i = 0; i < abs; ++i) counts->delta_lf[i][1]++;
if (smallval) counts->delta_lf[abs][0]++;
+#endif // CONFIG_LOOPFILTER_LEVEL
}
if (!smallval) {
rem_bits = aom_read_literal(r, 3, ACCT_STR) + 1;
@@ -1102,11 +1115,21 @@
xd->prev_qindex = xd->current_qindex;
#if CONFIG_EXT_DELTA_Q
if (cm->delta_lf_present_flag) {
+#if CONFIG_LOOPFILTER_LEVEL
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+ mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
+ xd->prev_delta_lf[lf_id] +
+ read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
+ cm->delta_lf_res;
+ xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
+ }
+#else
mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
xd->prev_delta_lf_from_base +
read_delta_lflevel(cm, xd, r, mbmi, mi_col, mi_row) *
cm->delta_lf_res;
xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
+#endif // CONFIG_LOOPFILTER_LEVEL
}
#endif
}
@@ -2853,11 +2876,21 @@
xd->prev_qindex = xd->current_qindex;
#if CONFIG_EXT_DELTA_Q
if (cm->delta_lf_present_flag) {
+#if CONFIG_LOOPFILTER_LEVEL
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+ mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
+ xd->prev_delta_lf[lf_id] +
+ read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
+ cm->delta_lf_res;
+ xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
+ }
+#else
mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
xd->prev_delta_lf_from_base +
read_delta_lflevel(cm, xd, r, mbmi, mi_col, mi_row) *
cm->delta_lf_res;
xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
+#endif // CONFIG_LOOPFILTER_LEVEL
}
#endif
}
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 8140380..a56553b 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -529,6 +529,9 @@
#if CONFIG_EXT_DELTA_Q
static void write_delta_lflevel(const AV1_COMMON *cm, const MACROBLOCKD *xd,
+#if CONFIG_LOOPFILTER_LEVEL
+ int lf_id,
+#endif
int delta_lflevel, aom_writer *w) {
int sign = delta_lflevel < 0;
int abs = sign ? -delta_lflevel : delta_lflevel;
@@ -537,8 +540,13 @@
FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
(void)cm;
+#if CONFIG_LOOPFILTER_LEVEL
+ aom_write_symbol(w, AOMMIN(abs, DELTA_LF_SMALL), ec_ctx->delta_lf_cdf[lf_id],
+ DELTA_LF_PROBS + 1);
+#else
aom_write_symbol(w, AOMMIN(abs, DELTA_LF_SMALL), ec_ctx->delta_lf_cdf,
DELTA_LF_PROBS + 1);
+#endif // CONFIG_LOOPFILTER_LEVEL
if (!smallval) {
rem_bits = OD_ILOG_NZ(abs - 1) - 1;
@@ -1715,6 +1723,17 @@
write_delta_qindex(cm, xd, reduced_delta_qindex, w);
xd->prev_qindex = mbmi->current_q_index;
#if CONFIG_EXT_DELTA_Q
+#if CONFIG_LOOPFILTER_LEVEL
+ if (cm->delta_lf_present_flag) {
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+ int reduced_delta_lflevel =
+ (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+ cm->delta_lf_res;
+ write_delta_lflevel(cm, xd, lf_id, reduced_delta_lflevel, w);
+ xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+ }
+ }
+#else
if (cm->delta_lf_present_flag) {
int reduced_delta_lflevel =
(mbmi->current_delta_lf_from_base - xd->prev_delta_lf_from_base) /
@@ -1722,6 +1741,7 @@
write_delta_lflevel(cm, xd, reduced_delta_lflevel, w);
xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
}
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif // CONFIG_EXT_DELTA_Q
}
}
@@ -2098,6 +2118,17 @@
write_delta_qindex(cm, xd, reduced_delta_qindex, w);
xd->prev_qindex = mbmi->current_q_index;
#if CONFIG_EXT_DELTA_Q
+#if CONFIG_LOOPFILTER_LEVEL
+ if (cm->delta_lf_present_flag) {
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+ int reduced_delta_lflevel =
+ (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+ cm->delta_lf_res;
+ write_delta_lflevel(cm, xd, lf_id, reduced_delta_lflevel, w);
+ xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+ }
+ }
+#else
if (cm->delta_lf_present_flag) {
int reduced_delta_lflevel =
(mbmi->current_delta_lf_from_base - xd->prev_delta_lf_from_base) /
@@ -2105,6 +2136,7 @@
write_delta_lflevel(cm, xd, reduced_delta_lflevel, w);
xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
}
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif // CONFIG_EXT_DELTA_Q
}
}
@@ -3223,6 +3255,10 @@
xd->prev_qindex = cpi->common.base_qindex;
#if CONFIG_EXT_DELTA_Q
if (cpi->common.delta_lf_present_flag) {
+#if CONFIG_LOOPFILTER_LEVEL
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
+ xd->prev_delta_lf[lf_id] = 0;
+#endif // CONFIG_LOOPFILTER_LEVEL
xd->prev_delta_lf_from_base = 0;
}
#endif // CONFIG_EXT_DELTA_Q
@@ -4731,6 +4767,10 @@
aom_wb_write_bit(wb, cm->delta_lf_present_flag);
if (cm->delta_lf_present_flag) {
aom_wb_write_literal(wb, OD_ILOG_NZ(cm->delta_lf_res) - 1, 2);
+#if CONFIG_LOOPFILTER_LEVEL
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
+ xd->prev_delta_lf[lf_id] = 0;
+#endif // CONFIG_LOOPFILTER_LEVEL
xd->prev_delta_lf_from_base = 0;
}
#endif // CONFIG_EXT_DELTA_Q
@@ -5086,6 +5126,10 @@
aom_wb_write_bit(wb, cm->delta_lf_present_flag);
if (cm->delta_lf_present_flag) {
aom_wb_write_literal(wb, OD_ILOG_NZ(cm->delta_lf_res) - 1, 2);
+#if CONFIG_LOOPFILTER_LEVEL
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
+ xd->prev_delta_lf[lf_id] = 0;
+#endif // CONFIG_LOOPFILTER_LEVEL
xd->prev_delta_lf_from_base = 0;
}
#endif // CONFIG_EXT_DELTA_Q
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index d4b3e4c..294692c 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1622,6 +1622,23 @@
if (absdq < DELTA_Q_SMALL) td->counts->delta_q[absdq][0]++;
xd->prev_qindex = mbmi->current_q_index;
#if CONFIG_EXT_DELTA_Q
+#if CONFIG_LOOPFILTER_LEVEL
+ if (cm->delta_lf_present_flag) {
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+ const int delta_lf =
+ (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+ cm->delta_lf_res;
+ const int abs_delta_lf = abs(delta_lf);
+ for (i = 0; i < AOMMIN(abs_delta_lf, DELTA_LF_SMALL); ++i) {
+ td->counts->delta_lf[lf_id][i][1]++;
+ }
+ if (abs_delta_lf < DELTA_LF_SMALL)
+ td->counts->delta_lf[lf_id][abs_delta_lf][0]++;
+ xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+ }
+ xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
+ }
+#else
if (cm->delta_lf_present_flag) {
const int dlf =
(mbmi->current_delta_lf_from_base - xd->prev_delta_lf_from_base) /
@@ -1633,6 +1650,7 @@
if (absdlf < DELTA_LF_SMALL) td->counts->delta_lf[absdlf][0]++;
xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
}
+#endif // CONFIG_LOOPFILTER_LEVEL
#endif
}
if (!frame_is_intra_only(cm)) {
@@ -2141,6 +2159,10 @@
mbmi = &xd->mi[0]->mbmi;
if (bsize == BLOCK_64X64 && mbmi->skip == 1 &&
cpi->common.delta_lf_present_flag) {
+#if CONFIG_LOOPFILTER_LEVEL
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
+ mbmi->curr_delta_lf[lf_id] = xd->prev_delta_lf[lf_id];
+#endif // CONFIG_LOOPFILTER_LEVEL
mbmi->current_delta_lf_from_base = xd->prev_delta_lf_from_base;
}
#endif
@@ -4604,8 +4626,14 @@
if (cm->delta_q_present_flag)
if (mi_row == tile_info->mi_row_start) xd->prev_qindex = cm->base_qindex;
#if CONFIG_EXT_DELTA_Q
- if (cm->delta_lf_present_flag)
+ if (cm->delta_lf_present_flag) {
+#if CONFIG_LOOPFILTER_LEVEL
+ if (mi_row == tile_info->mi_row_start)
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
+ xd->prev_delta_lf[lf_id] = 0;
+#endif // CONFIG_LOOPFILTER_LEVEL
if (mi_row == tile_info->mi_row_start) xd->prev_delta_lf_from_base = 0;
+ }
#endif
// Code each SB in the row
@@ -4702,6 +4730,12 @@
for (k = 0; k < AOMMIN(cm->mib_size, cm->mi_cols - mi_col); k++) {
cm->mi[(mi_row + j) * cm->mi_stride + (mi_col + k)]
.mbmi.current_delta_lf_from_base = current_delta_lf_from_base;
+#if CONFIG_LOOPFILTER_LEVEL
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+ cm->mi[(mi_row + j) * cm->mi_stride + (mi_col + k)]
+ .mbmi.curr_delta_lf[lf_id] = current_delta_lf_from_base;
+ }
+#endif // CONFIG_LOOPFILTER_LEVEL
}
}
}