Commit 8f209a87 authored by Debargha Mukherjee's avatar Debargha Mukherjee

Add guided projection filter to loop restoration

BDRATE:
lowres: -1.01% (up from -0.7%)
midres: -1.90% (up from -1.5%)
hdres:  -2.11% (up from ~1.7%)

Change-Id: I1fe04ec9ef90ccc4cc990e09cd45eea82c752e0c
parent fdb4216d
......@@ -89,6 +89,8 @@ void av1_free_restoration_buffers(AV1_COMMON *cm) {
cm->rst_info.bilateral_info = NULL;
aom_free(cm->rst_info.wiener_info);
cm->rst_info.wiener_info = NULL;
aom_free(cm->rst_info.sgrproj_info);
cm->rst_info.sgrproj_info = NULL;
}
#endif // CONFIG_LOOP_RESTORATION
......
......@@ -951,13 +951,13 @@ static const aom_prob default_tx_size_prob[MAX_TX_DEPTH][TX_SIZE_CONTEXTS]
};
#if CONFIG_LOOP_RESTORATION
const aom_tree_index
av1_switchable_restore_tree[TREE_SIZE(RESTORE_SWITCHABLE_TYPES)] = {
-RESTORE_NONE, 2, -RESTORE_BILATERAL, -RESTORE_WIENER,
};
const aom_tree_index av1_switchable_restore_tree[TREE_SIZE(
RESTORE_SWITCHABLE_TYPES)] = {
-RESTORE_NONE, 2, -RESTORE_SGRPROJ, 4, -RESTORE_BILATERAL, -RESTORE_WIENER,
};
static const aom_prob
default_switchable_restore_prob[RESTORE_SWITCHABLE_TYPES - 1] = { 32, 128 };
static const aom_prob default_switchable_restore_prob[RESTORE_SWITCHABLE_TYPES -
1] = { 32, 85, 128 };
#endif // CONFIG_LOOP_RESTORATION
#if CONFIG_EXT_TX && CONFIG_RECT_TX && CONFIG_VAR_TX
......
......@@ -343,6 +343,7 @@ extern const aom_tree_index av1_motion_mode_tree[TREE_SIZE(MOTION_MODES)];
#endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
#if CONFIG_LOOP_RESTORATION
#define RESTORE_NONE_SGRPROJ_PROB 64
#define RESTORE_NONE_BILATERAL_PROB 16
#define RESTORE_NONE_WIENER_PROB 64
extern const aom_tree_index
......
......@@ -463,10 +463,11 @@ typedef uint8_t TXFM_CONTEXT;
#if CONFIG_LOOP_RESTORATION
typedef enum {
RESTORE_NONE,
RESTORE_BILATERAL,
RESTORE_WIENER,
RESTORE_SWITCHABLE,
RESTORE_NONE = 0,
RESTORE_SGRPROJ = 1,
RESTORE_BILATERAL = 2,
RESTORE_WIENER = 3,
RESTORE_SWITCHABLE = 4,
RESTORE_SWITCHABLE_TYPES = RESTORE_SWITCHABLE,
RESTORE_TYPES,
} RestorationType;
......
This diff is collapsed.
......@@ -20,14 +20,35 @@
extern "C" {
#endif
#define RESTORATION_TILESIZE_SML 128
#define RESTORATION_TILESIZE_BIG 256
#define RESTORATION_TILEPELS_MAX \
(RESTORATION_TILESIZE_BIG * RESTORATION_TILESIZE_BIG * 9 / 4)
#define SGRPROJ_TMPBUF_SIZE (RESTORATION_TILEPELS_MAX * 5 * 8)
#define SGRPROJ_PARAMS_BITS 3
#define SGRPROJ_PARAMS (1 << SGRPROJ_PARAMS_BITS)
// Precision bits for projection
#define SGRPROJ_PRJ_BITS 7
// Restoration precision bits generated higher than source before projection
#define SGRPROJ_RST_BITS 4
// Internal precision bits for core selfguided_restoration
#define SGRPROJ_SGR_BITS 8
#define SGRPROJ_SGR (1 << SGRPROJ_SGR_BITS)
#define SGRPROJ_PRJ_MIN0 (-(1 << SGRPROJ_PRJ_BITS) / 4)
#define SGRPROJ_PRJ_MAX0 (SGRPROJ_PRJ_MIN0 + (1 << SGRPROJ_PRJ_BITS) - 1)
#define SGRPROJ_PRJ_MIN1 (-(1 << SGRPROJ_PRJ_BITS) / 4)
#define SGRPROJ_PRJ_MAX1 (SGRPROJ_PRJ_MIN1 + (1 << SGRPROJ_PRJ_BITS) - 1)
#define SGRPROJ_BITS (SGRPROJ_PRJ_BITS * 2 + SGRPROJ_PARAMS_BITS)
#define BILATERAL_LEVEL_BITS_KF 4
#define BILATERAL_LEVELS_KF (1 << BILATERAL_LEVEL_BITS_KF)
#define BILATERAL_LEVEL_BITS 3
#define BILATERAL_LEVELS (1 << BILATERAL_LEVEL_BITS)
// #define DEF_BILATERAL_LEVEL 2
#define RESTORATION_TILESIZE_SML 128
#define RESTORATION_TILESIZE_BIG 256
#define BILATERAL_SUBTILE_BITS 1
#define BILATERAL_SUBTILES (1 << (2 * BILATERAL_SUBTILE_BITS))
......@@ -64,6 +85,19 @@ typedef struct {
int vfilter[RESTORATION_WIN], hfilter[RESTORATION_WIN];
} WienerInfo;
typedef struct {
int r1;
int e1;
int r2;
int e2;
} sgr_params_type;
typedef struct {
int level;
int ep;
int xqd[2];
} SgrprojInfo;
typedef struct {
RestorationType frame_restoration_type;
RestorationType *restoration_type;
......@@ -71,6 +105,8 @@ typedef struct {
BilateralInfo *bilateral_info;
// Wiener filter
WienerInfo *wiener_info;
// Selfguided proj filter
SgrprojInfo *sgrproj_info;
} RestorationInfo;
typedef struct {
......@@ -140,6 +176,11 @@ static INLINE void av1_get_rest_tile_limits(
}
}
extern const sgr_params_type sgr_params[SGRPROJ_PARAMS];
void av1_selfguided_restoration(int64_t *dgd, int width, int height, int stride,
int bit_depth, int r, int eps, void *tmpbuf);
void decode_xq(int *xqd, int *xq);
int av1_bilateral_level_bits(const struct AV1Common *const cm);
void av1_loop_restoration_init(RestorationInternal *rst, RestorationInfo *rsi,
int kf, int width, int height);
......
......@@ -2204,14 +2204,60 @@ static void decode_restoration_mode(AV1_COMMON *cm,
struct aom_read_bit_buffer *rb) {
RestorationInfo *rsi = &cm->rst_info;
if (aom_rb_read_bit(rb)) {
rsi->frame_restoration_type =
aom_rb_read_bit(rb) ? RESTORE_WIENER : RESTORE_BILATERAL;
if (aom_rb_read_bit(rb))
rsi->frame_restoration_type =
(aom_rb_read_bit(rb) ? RESTORE_WIENER : RESTORE_BILATERAL);
else
rsi->frame_restoration_type = RESTORE_SGRPROJ;
} else {
rsi->frame_restoration_type =
aom_rb_read_bit(rb) ? RESTORE_SWITCHABLE : RESTORE_NONE;
}
}
static void read_wiener_filter(WienerInfo *wiener_info, aom_reader *rb) {
wiener_info->vfilter[0] =
aom_read_literal(rb, WIENER_FILT_TAP0_BITS, ACCT_STR) +
WIENER_FILT_TAP0_MINV;
wiener_info->vfilter[1] =
aom_read_literal(rb, WIENER_FILT_TAP1_BITS, ACCT_STR) +
WIENER_FILT_TAP1_MINV;
wiener_info->vfilter[2] =
aom_read_literal(rb, WIENER_FILT_TAP2_BITS, ACCT_STR) +
WIENER_FILT_TAP2_MINV;
wiener_info->hfilter[0] =
aom_read_literal(rb, WIENER_FILT_TAP0_BITS, ACCT_STR) +
WIENER_FILT_TAP0_MINV;
wiener_info->hfilter[1] =
aom_read_literal(rb, WIENER_FILT_TAP1_BITS, ACCT_STR) +
WIENER_FILT_TAP1_MINV;
wiener_info->hfilter[2] =
aom_read_literal(rb, WIENER_FILT_TAP2_BITS, ACCT_STR) +
WIENER_FILT_TAP2_MINV;
}
static void read_sgrproj_filter(SgrprojInfo *sgrproj_info, aom_reader *rb) {
sgrproj_info->ep = aom_read_literal(rb, SGRPROJ_PARAMS_BITS, ACCT_STR);
sgrproj_info->xqd[0] =
aom_read_literal(rb, SGRPROJ_PRJ_BITS, ACCT_STR) + SGRPROJ_PRJ_MIN0;
sgrproj_info->xqd[1] =
aom_read_literal(rb, SGRPROJ_PRJ_BITS, ACCT_STR) + SGRPROJ_PRJ_MIN1;
}
static void read_bilateral_filter(const AV1_COMMON *cm,
BilateralInfo *bilateral_info,
aom_reader *rb) {
int s;
for (s = 0; s < BILATERAL_SUBTILES; ++s) {
if (aom_read(rb, RESTORE_NONE_BILATERAL_PROB, ACCT_STR)) {
bilateral_info->level[s] =
aom_read_literal(rb, av1_bilateral_level_bits(cm), ACCT_STR);
} else {
bilateral_info->level[s] = -1;
}
}
}
static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
int i;
RestorationInfo *rsi = &cm->rst_info;
......@@ -2227,45 +2273,26 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
rsi->wiener_info = (WienerInfo *)aom_realloc(
rsi->wiener_info, sizeof(*rsi->wiener_info) * ntiles);
assert(rsi->wiener_info != NULL);
rsi->sgrproj_info = (SgrprojInfo *)aom_realloc(
rsi->sgrproj_info, sizeof(*rsi->sgrproj_info) * ntiles);
assert(rsi->sgrproj_info != NULL);
for (i = 0; i < ntiles; ++i) {
rsi->restoration_type[i] =
aom_read_tree(rb, av1_switchable_restore_tree,
cm->fc->switchable_restore_prob, ACCT_STR);
if (rsi->restoration_type[i] == RESTORE_WIENER) {
rsi->wiener_info[i].level = 1;
rsi->wiener_info[i].vfilter[0] =
aom_read_literal(rb, WIENER_FILT_TAP0_BITS, ACCT_STR) +
WIENER_FILT_TAP0_MINV;
rsi->wiener_info[i].vfilter[1] =
aom_read_literal(rb, WIENER_FILT_TAP1_BITS, ACCT_STR) +
WIENER_FILT_TAP1_MINV;
rsi->wiener_info[i].vfilter[2] =
aom_read_literal(rb, WIENER_FILT_TAP2_BITS, ACCT_STR) +
WIENER_FILT_TAP2_MINV;
rsi->wiener_info[i].hfilter[0] =
aom_read_literal(rb, WIENER_FILT_TAP0_BITS, ACCT_STR) +
WIENER_FILT_TAP0_MINV;
rsi->wiener_info[i].hfilter[1] =
aom_read_literal(rb, WIENER_FILT_TAP1_BITS, ACCT_STR) +
WIENER_FILT_TAP1_MINV;
rsi->wiener_info[i].hfilter[2] =
aom_read_literal(rb, WIENER_FILT_TAP2_BITS, ACCT_STR) +
WIENER_FILT_TAP2_MINV;
read_wiener_filter(&rsi->wiener_info[i], rb);
} else if (rsi->restoration_type[i] == RESTORE_BILATERAL) {
int s;
for (s = 0; s < BILATERAL_SUBTILES; ++s) {
#if BILATERAL_SUBTILES == 0
rsi->bilateral_info[i].level[s] =
aom_read_literal(rb, av1_bilateral_level_bits(cm), ACCT_STR);
rsi->bilateral_info[i].level[0] =
aom_read_literal(rb, av1_bilateral_level_bits(cm), ACCT_STR);
#else
if (aom_read(rb, RESTORE_NONE_BILATERAL_PROB, ACCT_STR)) {
rsi->bilateral_info[i].level[s] =
aom_read_literal(rb, av1_bilateral_level_bits(cm), ACCT_STR);
} else {
rsi->bilateral_info[i].level[s] = -1;
}
read_bilateral_filter(cm, &rsi->bilateral_info[i], rb);
#endif
}
} else if (rsi->restoration_type[i] == RESTORE_SGRPROJ) {
rsi->sgrproj_info[i].level = 1;
read_sgrproj_filter(&rsi->sgrproj_info[i], rb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_WIENER) {
......@@ -2274,50 +2301,37 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
assert(rsi->wiener_info != NULL);
for (i = 0; i < ntiles; ++i) {
if (aom_read(rb, RESTORE_NONE_WIENER_PROB, ACCT_STR)) {
rsi->wiener_info[i].level = 1;
rsi->restoration_type[i] = RESTORE_WIENER;
rsi->wiener_info[i].vfilter[0] =
aom_read_literal(rb, WIENER_FILT_TAP0_BITS, ACCT_STR) +
WIENER_FILT_TAP0_MINV;
rsi->wiener_info[i].vfilter[1] =
aom_read_literal(rb, WIENER_FILT_TAP1_BITS, ACCT_STR) +
WIENER_FILT_TAP1_MINV;
rsi->wiener_info[i].vfilter[2] =
aom_read_literal(rb, WIENER_FILT_TAP2_BITS, ACCT_STR) +
WIENER_FILT_TAP2_MINV;
rsi->wiener_info[i].hfilter[0] =
aom_read_literal(rb, WIENER_FILT_TAP0_BITS, ACCT_STR) +
WIENER_FILT_TAP0_MINV;
rsi->wiener_info[i].hfilter[1] =
aom_read_literal(rb, WIENER_FILT_TAP1_BITS, ACCT_STR) +
WIENER_FILT_TAP1_MINV;
rsi->wiener_info[i].hfilter[2] =
aom_read_literal(rb, WIENER_FILT_TAP2_BITS, ACCT_STR) +
WIENER_FILT_TAP2_MINV;
rsi->wiener_info[i].level = 1;
read_wiener_filter(&rsi->wiener_info[i], rb);
} else {
rsi->wiener_info[i].level = 0;
rsi->restoration_type[i] = RESTORE_NONE;
}
}
} else {
} else if (rsi->frame_restoration_type == RESTORE_BILATERAL) {
rsi->bilateral_info = (BilateralInfo *)aom_realloc(
rsi->bilateral_info, sizeof(*rsi->bilateral_info) * ntiles);
assert(rsi->bilateral_info != NULL);
for (i = 0; i < ntiles; ++i) {
int s;
rsi->restoration_type[i] = RESTORE_BILATERAL;
for (s = 0; s < BILATERAL_SUBTILES; ++s) {
if (aom_read(rb, RESTORE_NONE_BILATERAL_PROB, ACCT_STR)) {
rsi->bilateral_info[i].level[s] =
aom_read_literal(rb, av1_bilateral_level_bits(cm), ACCT_STR);
} else {
rsi->bilateral_info[i].level[s] = -1;
}
read_bilateral_filter(cm, &rsi->bilateral_info[i], rb);
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
rsi->sgrproj_info = (SgrprojInfo *)aom_realloc(
rsi->sgrproj_info, sizeof(*rsi->sgrproj_info) * ntiles);
assert(rsi->sgrproj_info != NULL);
for (i = 0; i < ntiles; ++i) {
if (aom_read(rb, RESTORE_NONE_SGRPROJ_PROB, ACCT_STR)) {
rsi->restoration_type[i] = RESTORE_SGRPROJ;
rsi->sgrproj_info[i].level = 1;
read_sgrproj_filter(&rsi->sgrproj_info[i], rb);
} else {
rsi->sgrproj_info[i].level = 0;
rsi->restoration_type[i] = RESTORE_NONE;
}
}
}
} else {
rsi->frame_restoration_type = RESTORE_NONE;
}
}
#endif // CONFIG_LOOP_RESTORATION
......
......@@ -174,9 +174,9 @@ void av1_encode_token_init(void) {
an in-order traversal of the av1_switchable_interp_tree structure. */
av1_indices_from_tree(av1_switchable_interp_ind, av1_switchable_interp_inv,
SWITCHABLE_FILTERS, av1_switchable_interp_tree);
/* This hack is necessary because the four TX_TYPES are not consecutive,
e.g., 0, 1, 2, 3, when doing an in-order traversal of the av1_ext_tx_tree
structure. */
/* This hack is necessary because the four TX_TYPES are not consecutive,
e.g., 0, 1, 2, 3, when doing an in-order traversal of the av1_ext_tx_tree
structure. */
#if !CONFIG_EXT_TX
av1_indices_from_tree(av1_ext_tx_ind, av1_ext_tx_inv, TX_TYPES,
av1_ext_tx_tree);
......@@ -2897,11 +2897,17 @@ static void encode_restoration_mode(AV1_COMMON *cm,
aom_wb_write_bit(wb, 0);
aom_wb_write_bit(wb, 1);
break;
case RESTORE_SGRPROJ:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 0);
break;
case RESTORE_BILATERAL:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 0);
break;
case RESTORE_WIENER:
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 1);
aom_wb_write_bit(wb, 1);
break;
......@@ -2909,6 +2915,42 @@ static void encode_restoration_mode(AV1_COMMON *cm,
}
}
static void write_wiener_filter(WienerInfo *wiener_info, aom_writer *wb) {
aom_write_literal(wb, wiener_info->vfilter[0] - WIENER_FILT_TAP0_MINV,
WIENER_FILT_TAP0_BITS);
aom_write_literal(wb, wiener_info->vfilter[1] - WIENER_FILT_TAP1_MINV,
WIENER_FILT_TAP1_BITS);
aom_write_literal(wb, wiener_info->vfilter[2] - WIENER_FILT_TAP2_MINV,
WIENER_FILT_TAP2_BITS);
aom_write_literal(wb, wiener_info->hfilter[0] - WIENER_FILT_TAP0_MINV,
WIENER_FILT_TAP0_BITS);
aom_write_literal(wb, wiener_info->hfilter[1] - WIENER_FILT_TAP1_MINV,
WIENER_FILT_TAP1_BITS);
aom_write_literal(wb, wiener_info->hfilter[2] - WIENER_FILT_TAP2_MINV,
WIENER_FILT_TAP2_BITS);
}
static void write_sgrproj_filter(SgrprojInfo *sgrproj_info, aom_writer *wb) {
aom_write_literal(wb, sgrproj_info->ep, SGRPROJ_PARAMS_BITS);
aom_write_literal(wb, sgrproj_info->xqd[0] - SGRPROJ_PRJ_MIN0,
SGRPROJ_PRJ_BITS);
aom_write_literal(wb, sgrproj_info->xqd[1] - SGRPROJ_PRJ_MIN1,
SGRPROJ_PRJ_BITS);
}
static void write_bilateral_filter(const AV1_COMMON *cm,
BilateralInfo *bilateral_info,
aom_writer *wb) {
int s;
for (s = 0; s < BILATERAL_SUBTILES; ++s) {
aom_write(wb, bilateral_info->level[s] >= 0, RESTORE_NONE_BILATERAL_PROB);
if (bilateral_info->level[s] >= 0) {
aom_write_literal(wb, bilateral_info->level[s],
av1_bilateral_level_bits(cm));
}
}
}
static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
int i;
RestorationInfo *rsi = &cm->rst_info;
......@@ -2920,75 +2962,35 @@ static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
wb, av1_switchable_restore_tree, cm->fc->switchable_restore_prob,
&switchable_restore_encodings[rsi->restoration_type[i]]);
if (rsi->restoration_type[i] == RESTORE_BILATERAL) {
int s;
for (s = 0; s < BILATERAL_SUBTILES; ++s) {
#if BILATERAL_SUBTILES == 0
aom_write_literal(wb, rsi->bilateral_info[i].level[s],
av1_bilateral_level_bits(cm));
aom_write_literal(wb, rsi->bilateral_info[i].level[0],
av1_bilateral_level_bits(cm));
#else
aom_write(wb, rsi->bilateral_info[i].level[s] >= 0,
RESTORE_NONE_BILATERAL_PROB);
if (rsi->bilateral_info[i].level[s] >= 0) {
aom_write_literal(wb, rsi->bilateral_info[i].level[s],
av1_bilateral_level_bits(cm));
}
write_bilateral_filter(cm, &rsi->bilateral_info[i], wb);
#endif
}
} else if (rsi->restoration_type[i] == RESTORE_WIENER) {
aom_write_literal(
wb, rsi->wiener_info[i].vfilter[0] - WIENER_FILT_TAP0_MINV,
WIENER_FILT_TAP0_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].vfilter[1] - WIENER_FILT_TAP1_MINV,
WIENER_FILT_TAP1_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].vfilter[2] - WIENER_FILT_TAP2_MINV,
WIENER_FILT_TAP2_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].hfilter[0] - WIENER_FILT_TAP0_MINV,
WIENER_FILT_TAP0_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].hfilter[1] - WIENER_FILT_TAP1_MINV,
WIENER_FILT_TAP1_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].hfilter[2] - WIENER_FILT_TAP2_MINV,
WIENER_FILT_TAP2_BITS);
write_wiener_filter(&rsi->wiener_info[i], wb);
} else if (rsi->restoration_type[i] == RESTORE_SGRPROJ) {
write_sgrproj_filter(&rsi->sgrproj_info[i], wb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_BILATERAL) {
for (i = 0; i < cm->rst_internal.ntiles; ++i) {
int s;
for (s = 0; s < BILATERAL_SUBTILES; ++s) {
aom_write(wb, rsi->bilateral_info[i].level[s] >= 0,
RESTORE_NONE_BILATERAL_PROB);
if (rsi->bilateral_info[i].level[s] >= 0) {
aom_write_literal(wb, rsi->bilateral_info[i].level[s],
av1_bilateral_level_bits(cm));
}
}
write_bilateral_filter(cm, &rsi->bilateral_info[i], wb);
}
} else if (rsi->frame_restoration_type == RESTORE_WIENER) {
for (i = 0; i < cm->rst_internal.ntiles; ++i) {
aom_write(wb, rsi->wiener_info[i].level != 0, RESTORE_NONE_WIENER_PROB);
if (rsi->wiener_info[i].level) {
aom_write_literal(
wb, rsi->wiener_info[i].vfilter[0] - WIENER_FILT_TAP0_MINV,
WIENER_FILT_TAP0_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].vfilter[1] - WIENER_FILT_TAP1_MINV,
WIENER_FILT_TAP1_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].vfilter[2] - WIENER_FILT_TAP2_MINV,
WIENER_FILT_TAP2_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].hfilter[0] - WIENER_FILT_TAP0_MINV,
WIENER_FILT_TAP0_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].hfilter[1] - WIENER_FILT_TAP1_MINV,
WIENER_FILT_TAP1_BITS);
aom_write_literal(
wb, rsi->wiener_info[i].hfilter[2] - WIENER_FILT_TAP2_MINV,
WIENER_FILT_TAP2_BITS);
write_wiener_filter(&rsi->wiener_info[i], wb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
for (i = 0; i < cm->rst_internal.ntiles; ++i) {
aom_write(wb, rsi->sgrproj_info[i].level != 0,
RESTORE_NONE_SGRPROJ_PROB);
if (rsi->sgrproj_info[i].level) {
write_sgrproj_filter(&rsi->sgrproj_info[i], wb);
}
}
}
......
......@@ -33,7 +33,7 @@ typedef double (*search_restore_type)(const YV12_BUFFER_CONFIG *src,
int partial_frame, RestorationInfo *info,
double *best_tile_cost);
const int frame_level_restore_bits[RESTORE_TYPES] = { 2, 2, 2, 2 };
const int frame_level_restore_bits[RESTORE_TYPES] = { 2, 2, 3, 3, 2 };
static int64_t sse_restoration_tile(const YV12_BUFFER_CONFIG *src,
AV1_COMMON *const cm, int h_start,
......@@ -100,6 +100,228 @@ static int64_t try_restoration_frame(const YV12_BUFFER_CONFIG *src,
return filt_err;
}
static int64_t get_pixel_proj_error(int64_t *src, int width, int height,
int src_stride, int64_t *dgd,
int dgd_stride, int64_t *flt1,
int flt1_stride, int64_t *flt2,
int flt2_stride, int *xqd) {
int i, j;
int64_t err = 0;
int xq[2];
decode_xq(xqd, xq);
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
const int64_t s = (int64_t)src[i * src_stride + j];
const int64_t u = (int64_t)dgd[i * dgd_stride + j];
const int64_t f1 = (int64_t)flt1[i * flt1_stride + j] - u;
const int64_t f2 = (int64_t)flt2[i * flt2_stride + j] - u;
const int64_t v = xq[0] * f1 + xq[1] * f2 + (u << SGRPROJ_PRJ_BITS);
const int64_t e =
ROUND_POWER_OF_TWO(v, SGRPROJ_RST_BITS + SGRPROJ_PRJ_BITS) -
ROUND_POWER_OF_TWO(s, SGRPROJ_RST_BITS);
err += e * e;
}
}
return err;
}
static void get_proj_subspace(int64_t *src, int width, int height,
int src_stride, int64_t *dgd, int dgd_stride,
int64_t *flt1, int flt1_stride, int64_t *flt2,
int flt2_stride, int *xq) {
int i, j;
double H[2][2] = { { 0, 0 }, { 0, 0 } };
double C[2] = { 0, 0 };
double Det;
double x[2];
const int size = width * height;
xq[0] = -(1 << SGRPROJ_PRJ_BITS) / 4;
xq[1] = (1 << SGRPROJ_PRJ_BITS) - xq[0];
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
const double u = (double)dgd[i * dgd_stride + j];
const double s = (double)src[i * src_stride + j] - u;
const double f1 = (double)flt1[i * flt1_stride + j] - u;
const double f2 = (double)flt2[i * flt2_stride + j] - u;
H[0][0] += f1 * f1;
H[1][1] += f2 * f2;
H[0][1] += f1 * f2;
C[0] += f1 * s;
C[1] += f2 * s;
}
}
H[0][0] /= size;
H[0][1] /= size;
H[1][1] /= size;
H[1][0] = H[0][1];
C[0] /= size;
C[1] /= size;
Det = (H[0][0] * H[1][1] - H[0][1] * H[1][0]);
if (Det < 1e-8) return; // ill-posed, return default values
x[0] = (H[1][1] * C[0] - H[0][1] * C[1]) / Det;
x[1] = (H[0][0] * C[1] - H[1][0] * C[0]) / Det;
xq[0] = (int)rint(x[0] * (1 << SGRPROJ_PRJ_BITS));
xq[1] = (int)rint(x[1] * (1 << SGRPROJ_PRJ_BITS));
}
void encode_xq(int *xq, int *xqd) {
xqd[0] = -xq[0];
xqd[0] = clamp(xqd[0], SGRPROJ_PRJ_MIN0, SGRPROJ_PRJ_MAX0);
xqd[1] = (1 << SGRPROJ_PRJ_BITS) + xqd[0] - xq[1];
xqd[1] = clamp(xqd[1], SGRPROJ_PRJ_MIN1, SGRPROJ_PRJ_MAX1);
}
static void search_selfguided_restoration(uint8_t *dat8, int width, int height,
int dat_stride, uint8_t *src8,
int src_stride, int bit_depth,
int *eps, int *xqd, void *tmpbuf) {
int64_t *flt1 = (int64_t *)tmpbuf;
int64_t *flt2 = flt1 + RESTORATION_TILEPELS_MAX;
uint8_t *tmpbuf2 = (uint8_t *)(flt2 + RESTORATION_TILEPELS_MAX);
int64_t srd[RESTORATION_TILEPELS_MAX];
int64_t dgd[RESTORATION_TILEPELS_MAX];
int i, j, ep, bestep = 0;
int64_t err, besterr = -1;
int exqd[2], bestxqd[2] = { 0, 0 };
for (ep = 0; ep < SGRPROJ_PARAMS; ep++) {
int exq[2];
if (bit_depth > 8) {
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
uint16_t *dat = CONVERT_TO_SHORTPTR(dat8);
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {