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);
}
}
}
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment