Add tiled version of UV wiener restoration
Slight improvement in midres and hdres sets of 0.02% and 0.0.9%
respectively.
This is also a better design anyways.
Change-Id: I15b60b8836070a2132641e5b1d8e9f68df426c08
diff --git a/av1/common/restoration.c b/av1/common/restoration.c
index 8228170..50a1eec 100644
--- a/av1/common/restoration.c
+++ b/av1/common/restoration.c
@@ -146,7 +146,7 @@
DECLARE_ALIGNED(16, InterpKernel, hkernel);
DECLARE_ALIGNED(16, InterpKernel, vkernel);
- if (rst->rsi->wiener_info[tile_idx].level == 0) {
+ if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
loop_copy_tile(data, tile_idx, 0, 0, width, height, stride, rst, dst,
dst_stride);
return;
@@ -632,7 +632,7 @@
int h_start, h_end, v_start, v_end;
uint8_t *data_p, *dst_p;
- if (rst->rsi->sgrproj_info[tile_idx].level == 0) {
+ if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
loop_copy_tile(data, tile_idx, 0, 0, width, height, stride, rst, dst,
dst_stride);
return;
@@ -791,7 +791,7 @@
int h_start, h_end, v_start, v_end;
int32_t *tmpbuf = (int32_t *)rst->tmpbuf;
- if (rst->rsi->domaintxfmrf_info[tile_idx].level == 0) {
+ if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
loop_copy_tile(data, tile_idx, 0, 0, width, height, stride, rst, dst,
dst_stride);
return;
@@ -886,7 +886,7 @@
DECLARE_ALIGNED(16, InterpKernel, hkernel);
DECLARE_ALIGNED(16, InterpKernel, vkernel);
- if (rst->rsi->wiener_info[tile_idx].level == 0) {
+ if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
loop_copy_tile_highbd(data, tile_idx, 0, 0, width, height, stride, rst, dst,
dst_stride);
return;
@@ -979,7 +979,7 @@
int h_start, h_end, v_start, v_end;
uint16_t *data_p, *dst_p;
- if (rst->rsi->sgrproj_info[tile_idx].level == 0) {
+ if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
loop_copy_tile_highbd(data, tile_idx, 0, 0, width, height, stride, rst, dst,
dst_stride);
return;
@@ -1109,7 +1109,7 @@
int h_start, h_end, v_start, v_end;
int32_t *tmpbuf = (int32_t *)rst->tmpbuf;
- if (rst->rsi->domaintxfmrf_info[tile_idx].level == 0) {
+ if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
loop_copy_tile_highbd(data, tile_idx, 0, 0, width, height, stride, rst, dst,
dst_stride);
return;
diff --git a/av1/common/restoration.h b/av1/common/restoration.h
index cb596c6..ecc6276 100644
--- a/av1/common/restoration.h
+++ b/av1/common/restoration.h
@@ -114,10 +114,7 @@
// Max of SGRPROJ_EXTBUF_SIZE, DOMAINTXFMRF_EXTBUF_SIZE, WIENER_EXTBUF_SIZE
#define RESTORATION_EXTBUF_SIZE (DOMAINTXFMRF_EXTBUF_SIZE)
-typedef struct {
- int level;
- int vfilter[WIENER_WIN], hfilter[WIENER_WIN];
-} WienerInfo;
+typedef struct { int vfilter[WIENER_WIN], hfilter[WIENER_WIN]; } WienerInfo;
typedef struct {
int r1;
@@ -127,15 +124,11 @@
} sgr_params_type;
typedef struct {
- int level;
int ep;
int xqd[2];
} SgrprojInfo;
-typedef struct {
- int level;
- int sigma_r;
-} DomaintxfmrfInfo;
+typedef struct { int sigma_r; } DomaintxfmrfInfo;
typedef struct {
RestorationType frame_restoration_type;
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index b946ddb..cf0d4d5 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -2359,7 +2359,7 @@
const int ntiles =
av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
const int ntiles_uv = av1_get_rest_ntiles(cm->width >> cm->subsampling_x,
- cm->height >> cm->subsampling_x,
+ cm->height >> cm->subsampling_y,
NULL, NULL, NULL, NULL);
RestorationInfo *rsi = &cm->rst_info[0];
if (rsi->frame_restoration_type != RESTORE_NONE) {
@@ -2369,13 +2369,10 @@
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;
read_wiener_filter(&rsi->wiener_info[i], rb);
} 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->restoration_type[i] == RESTORE_DOMAINTXFMRF) {
- rsi->domaintxfmrf_info[i].level = 1;
read_domaintxfmrf_filter(&rsi->domaintxfmrf_info[i], rb);
}
}
@@ -2383,10 +2380,8 @@
for (i = 0; i < ntiles; ++i) {
if (aom_read(rb, RESTORE_NONE_WIENER_PROB, ACCT_STR)) {
rsi->restoration_type[i] = RESTORE_WIENER;
- 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;
}
}
@@ -2394,10 +2389,8 @@
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;
}
}
@@ -2405,10 +2398,8 @@
for (i = 0; i < ntiles; ++i) {
if (aom_read(rb, RESTORE_NONE_DOMAINTXFMRF_PROB, ACCT_STR)) {
rsi->restoration_type[i] = RESTORE_DOMAINTXFMRF;
- rsi->domaintxfmrf_info[i].level = 1;
read_domaintxfmrf_filter(&rsi->domaintxfmrf_info[i], rb);
} else {
- rsi->domaintxfmrf_info[i].level = 0;
rsi->restoration_type[i] = RESTORE_NONE;
}
}
@@ -2417,13 +2408,16 @@
for (p = 1; p < MAX_MB_PLANE; ++p) {
rsi = &cm->rst_info[p];
if (rsi->frame_restoration_type == RESTORE_WIENER) {
- rsi->restoration_type[0] = RESTORE_WIENER;
- rsi->wiener_info[0].level = 1;
- read_wiener_filter(&rsi->wiener_info[0], rb);
- for (i = 1; i < ntiles_uv; ++i) {
- rsi->restoration_type[i] = RESTORE_WIENER;
- memcpy(&rsi->wiener_info[i], &rsi->wiener_info[0],
- sizeof(rsi->wiener_info[0]));
+ for (i = 0; i < ntiles_uv; ++i) {
+ if (ntiles_uv > 1)
+ rsi->restoration_type[i] =
+ aom_read(rb, RESTORE_NONE_WIENER_PROB, ACCT_STR) ? RESTORE_WIENER
+ : RESTORE_NONE;
+ else
+ rsi->restoration_type[i] = RESTORE_WIENER;
+ if (rsi->restoration_type[i] == RESTORE_WIENER) {
+ read_wiener_filter(&rsi->wiener_info[i], rb);
+ }
}
}
}
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index ae2c36e..a047a90 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3088,6 +3088,9 @@
int i, p;
const int ntiles =
av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
+ const int ntiles_uv = av1_get_rest_ntiles(cm->width >> cm->subsampling_x,
+ cm->height >> cm->subsampling_y,
+ NULL, NULL, NULL, NULL);
RestorationInfo *rsi = &cm->rst_info[0];
if (rsi->frame_restoration_type != RESTORE_NONE) {
if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
@@ -3106,24 +3109,25 @@
}
} else if (rsi->frame_restoration_type == RESTORE_WIENER) {
for (i = 0; i < ntiles; ++i) {
- aom_write(wb, rsi->wiener_info[i].level != 0, RESTORE_NONE_WIENER_PROB);
- if (rsi->wiener_info[i].level) {
+ aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
+ RESTORE_NONE_WIENER_PROB);
+ if (rsi->restoration_type[i] != RESTORE_NONE) {
write_wiener_filter(&rsi->wiener_info[i], wb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
for (i = 0; i < ntiles; ++i) {
- aom_write(wb, rsi->sgrproj_info[i].level != 0,
+ aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
RESTORE_NONE_SGRPROJ_PROB);
- if (rsi->sgrproj_info[i].level) {
+ if (rsi->restoration_type[i] != RESTORE_NONE) {
write_sgrproj_filter(&rsi->sgrproj_info[i], wb);
}
}
} else if (rsi->frame_restoration_type == RESTORE_DOMAINTXFMRF) {
for (i = 0; i < ntiles; ++i) {
- aom_write(wb, rsi->domaintxfmrf_info[i].level != 0,
+ aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
RESTORE_NONE_DOMAINTXFMRF_PROB);
- if (rsi->domaintxfmrf_info[i].level) {
+ if (rsi->restoration_type[i] != RESTORE_NONE) {
write_domaintxfmrf_filter(&rsi->domaintxfmrf_info[i], wb);
}
}
@@ -3132,7 +3136,14 @@
for (p = 1; p < MAX_MB_PLANE; ++p) {
rsi = &cm->rst_info[p];
if (rsi->frame_restoration_type == RESTORE_WIENER) {
- write_wiener_filter(&rsi->wiener_info[0], wb);
+ for (i = 0; i < ntiles_uv; ++i) {
+ if (ntiles_uv > 1)
+ aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
+ RESTORE_NONE_WIENER_PROB);
+ if (rsi->restoration_type[i] != RESTORE_NONE) {
+ write_wiener_filter(&rsi->wiener_info[i], wb);
+ }
+ }
} else if (rsi->frame_restoration_type != RESTORE_NONE) {
assert(0);
}
diff --git a/av1/encoder/pickrst.c b/av1/encoder/pickrst.c
index f8a374e..8de1bd4 100644
--- a/av1/encoder/pickrst.c
+++ b/av1/encoder/pickrst.c
@@ -33,6 +33,7 @@
typedef double (*search_restore_type)(const YV12_BUFFER_CONFIG *src,
AV1_COMP *cpi, int filter_level,
int partial_frame, RestorationInfo *info,
+ RestorationType *rest_level,
double *best_tile_cost,
YV12_BUFFER_CONFIG *dst_frame);
@@ -327,7 +328,8 @@
static double search_sgrproj(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
int filter_level, int partial_frame,
- RestorationInfo *info, double *best_tile_cost,
+ RestorationInfo *info, RestorationType *type,
+ double *best_tile_cost,
YV12_BUFFER_CONFIG *dst_frame) {
SgrprojInfo *sgrproj_info = info->sgrproj_info;
double err, cost_norestore, cost_sgrproj;
@@ -349,8 +351,9 @@
rsi->frame_restoration_type = RESTORE_SGRPROJ;
- for (tile_idx = 0; tile_idx < ntiles; ++tile_idx)
- rsi->sgrproj_info[tile_idx].level = 0;
+ for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+ rsi->restoration_type[tile_idx] = RESTORE_NONE;
+ }
// Compute best Sgrproj filters for each tile
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
@@ -373,15 +376,16 @@
#endif // CONFIG_AOM_HIGHBITDEPTH
&rsi->sgrproj_info[tile_idx].ep, rsi->sgrproj_info[tile_idx].xqd,
cm->rst_internal.tmpbuf);
- rsi->sgrproj_info[tile_idx].level = 1;
+ rsi->restoration_type[tile_idx] = RESTORE_SGRPROJ;
err = try_restoration_tile(src, cpi, rsi, 1, partial_frame, tile_idx, 0, 0,
dst_frame);
bits = SGRPROJ_BITS << AV1_PROB_COST_SHIFT;
bits += av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, 1);
cost_sgrproj = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
if (cost_sgrproj >= cost_norestore) {
- sgrproj_info[tile_idx].level = 0;
+ type[tile_idx] = RESTORE_NONE;
} else {
+ type[tile_idx] = RESTORE_SGRPROJ;
memcpy(&sgrproj_info[tile_idx], &rsi->sgrproj_info[tile_idx],
sizeof(sgrproj_info[tile_idx]));
bits = SGRPROJ_BITS << AV1_PROB_COST_SHIFT;
@@ -389,19 +393,20 @@
x->rdmult, x->rddiv,
(bits + cpi->switchable_restore_cost[RESTORE_SGRPROJ]) >> 4, err);
}
- rsi->sgrproj_info[tile_idx].level = 0;
+ rsi->restoration_type[tile_idx] = RESTORE_NONE;
}
// Cost for Sgrproj filtering
bits = frame_level_restore_bits[rsi->frame_restoration_type]
<< AV1_PROB_COST_SHIFT;
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
bits +=
- av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, sgrproj_info[tile_idx].level);
+ av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, type[tile_idx] != RESTORE_NONE);
memcpy(&rsi->sgrproj_info[tile_idx], &sgrproj_info[tile_idx],
sizeof(sgrproj_info[tile_idx]));
- if (sgrproj_info[tile_idx].level) {
+ if (type[tile_idx] == RESTORE_SGRPROJ) {
bits += (SGRPROJ_BITS << AV1_PROB_COST_SHIFT);
}
+ rsi->restoration_type[tile_idx] = type[tile_idx];
}
err = try_restoration_frame(src, cpi, rsi, 1, partial_frame, dst_frame);
cost_sgrproj = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
@@ -543,7 +548,8 @@
static double search_domaintxfmrf(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
int filter_level, int partial_frame,
- RestorationInfo *info, double *best_tile_cost,
+ RestorationInfo *info, RestorationType *type,
+ double *best_tile_cost,
YV12_BUFFER_CONFIG *dst_frame) {
DomaintxfmrfInfo *domaintxfmrf_info = info->domaintxfmrf_info;
double cost_norestore, cost_domaintxfmrf;
@@ -565,8 +571,9 @@
rsi->frame_restoration_type = RESTORE_DOMAINTXFMRF;
- for (tile_idx = 0; tile_idx < ntiles; ++tile_idx)
- rsi->domaintxfmrf_info[tile_idx].level = 0;
+ for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+ rsi->restoration_type[tile_idx] = RESTORE_NONE;
+ }
// Compute best Domaintxfm filters for each tile
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
@@ -591,15 +598,16 @@
&rsi->domaintxfmrf_info[tile_idx].sigma_r, cpi->extra_rstbuf,
cm->rst_internal.tmpbuf);
- rsi->domaintxfmrf_info[tile_idx].level = 1;
+ rsi->restoration_type[tile_idx] = RESTORE_DOMAINTXFMRF;
err = try_restoration_tile(src, cpi, rsi, 1, partial_frame, tile_idx, 0, 0,
dst_frame);
bits = DOMAINTXFMRF_PARAMS_BITS << AV1_PROB_COST_SHIFT;
bits += av1_cost_bit(RESTORE_NONE_DOMAINTXFMRF_PROB, 1);
cost_domaintxfmrf = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
if (cost_domaintxfmrf >= cost_norestore) {
- domaintxfmrf_info[tile_idx].level = 0;
+ type[tile_idx] = RESTORE_NONE;
} else {
+ type[tile_idx] = RESTORE_DOMAINTXFMRF;
memcpy(&domaintxfmrf_info[tile_idx], &rsi->domaintxfmrf_info[tile_idx],
sizeof(domaintxfmrf_info[tile_idx]));
bits = DOMAINTXFMRF_PARAMS_BITS << AV1_PROB_COST_SHIFT;
@@ -608,19 +616,20 @@
(bits + cpi->switchable_restore_cost[RESTORE_DOMAINTXFMRF]) >> 4,
err);
}
- rsi->domaintxfmrf_info[tile_idx].level = 0;
+ rsi->restoration_type[tile_idx] = RESTORE_NONE;
}
// Cost for Domaintxfmrf filtering
bits = frame_level_restore_bits[rsi->frame_restoration_type]
<< AV1_PROB_COST_SHIFT;
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
bits += av1_cost_bit(RESTORE_NONE_DOMAINTXFMRF_PROB,
- domaintxfmrf_info[tile_idx].level);
+ type[tile_idx] != RESTORE_NONE);
memcpy(&rsi->domaintxfmrf_info[tile_idx], &domaintxfmrf_info[tile_idx],
sizeof(domaintxfmrf_info[tile_idx]));
- if (domaintxfmrf_info[tile_idx].level) {
+ if (type[tile_idx] == RESTORE_DOMAINTXFMRF) {
bits += (DOMAINTXFMRF_PARAMS_BITS << AV1_PROB_COST_SHIFT);
}
+ rsi->restoration_type[tile_idx] = type[tile_idx];
}
err = try_restoration_frame(src, cpi, rsi, 1, partial_frame, dst_frame);
cost_domaintxfmrf = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
@@ -942,14 +951,14 @@
static double search_wiener_uv(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
int filter_level, int partial_frame, int plane,
- RestorationInfo *info,
+ RestorationInfo *info, RestorationType *type,
YV12_BUFFER_CONFIG *dst_frame) {
WienerInfo *wiener_info = info->wiener_info;
AV1_COMMON *const cm = &cpi->common;
RestorationInfo *rsi = cpi->rst_search;
int64_t err;
int bits;
- double cost_wiener = 0, cost_norestore = 0;
+ double cost_wiener, cost_norestore, cost_wiener_frame, cost_norestore_frame;
MACROBLOCK *x = &cpi->td.mb;
double M[WIENER_WIN2];
double H[WIENER_WIN2 * WIENER_WIN2];
@@ -961,9 +970,9 @@
const int dgd_stride = dgd->uv_stride;
double score;
int tile_idx, tile_width, tile_height, nhtiles, nvtiles;
+ int h_start, h_end, v_start, v_end;
const int ntiles = av1_get_rest_ntiles(width, height, &tile_width,
&tile_height, &nhtiles, &nvtiles);
-
assert(width == dgd->uv_crop_width);
assert(height == dgd->uv_crop_height);
@@ -978,100 +987,123 @@
aom_yv12_copy_v(cm->frame_to_show, &cpi->last_frame_db);
rsi[plane].frame_restoration_type = RESTORE_NONE;
-
err = sse_restoration_frame(src, cm->frame_to_show, (1 << plane));
bits = 0;
- cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+ cost_norestore_frame = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
rsi[plane].frame_restoration_type = RESTORE_WIENER;
-#if CONFIG_AOM_HIGHBITDEPTH
- if (cm->use_highbitdepth) {
+ for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+ rsi[plane].restoration_type[tile_idx] = RESTORE_NONE;
+ }
+
+ // Compute best Wiener filters for each tile
+ for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+ av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
+ tile_height, width, height, 0, 0, &h_start, &h_end,
+ &v_start, &v_end);
+ err = sse_restoration_tile(src, cm->frame_to_show, cm, h_start,
+ h_end - h_start, v_start, v_end - v_start,
+ 1 << plane);
+ // #bits when a tile is not restored
+ bits = av1_cost_bit(RESTORE_NONE_WIENER_PROB, 0);
+ cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+ // best_tile_cost[tile_idx] = DBL_MAX;
+
+ av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
+ tile_height, width, height, WIENER_HALFWIN,
+ WIENER_HALFWIN, &h_start, &h_end, &v_start,
+ &v_end);
if (plane == AOM_PLANE_U) {
- extend_frame_highbd(CONVERT_TO_SHORTPTR(dgd->u_buffer), width, height,
- dgd_stride);
- compute_stats_highbd(dgd->u_buffer, src->u_buffer, 0, width, 0, height,
- dgd_stride, src_stride, M, H);
+#if CONFIG_AOM_HIGHBITDEPTH
+ if (cm->use_highbitdepth)
+ compute_stats_highbd(dgd->u_buffer, src->u_buffer, h_start, h_end,
+ v_start, v_end, dgd_stride, src_stride, M, H);
+ else
+#endif // CONFIG_AOM_HIGHBITDEPTH
+ compute_stats(dgd->u_buffer, src->u_buffer, h_start, h_end, v_start,
+ v_end, dgd_stride, src_stride, M, H);
} else if (plane == AOM_PLANE_V) {
- extend_frame_highbd(CONVERT_TO_SHORTPTR(dgd->v_buffer), width, height,
- dgd_stride);
- compute_stats_highbd(dgd->v_buffer, src->v_buffer, 0, width, 0, height,
- dgd_stride, src_stride, M, H);
+#if CONFIG_AOM_HIGHBITDEPTH
+ if (cm->use_highbitdepth)
+ compute_stats_highbd(dgd->v_buffer, src->v_buffer, h_start, h_end,
+ v_start, v_end, dgd_stride, src_stride, M, H);
+ else
+#endif // CONFIG_AOM_HIGHBITDEPTH
+ compute_stats(dgd->v_buffer, src->v_buffer, h_start, h_end, v_start,
+ v_end, dgd_stride, src_stride, M, H);
} else {
assert(0);
}
- } else {
-#endif
- if (plane == AOM_PLANE_U) {
- extend_frame(dgd->u_buffer, width, height, dgd_stride);
- compute_stats(dgd->u_buffer, src->u_buffer, 0, width, 0, height,
- dgd_stride, src_stride, M, H);
- } else if (plane == AOM_PLANE_V) {
- extend_frame(dgd->v_buffer, width, height, dgd_stride);
- compute_stats(dgd->v_buffer, src->v_buffer, 0, width, 0, height,
- dgd_stride, src_stride, M, H);
- } else {
- assert(0);
+
+ type[tile_idx] = RESTORE_WIENER;
+
+ if (!wiener_decompose_sep_sym(M, H, vfilterd, hfilterd)) {
+ type[tile_idx] = RESTORE_NONE;
+ continue;
}
-#if CONFIG_AOM_HIGHBITDEPTH
- }
-#endif
+ quantize_sym_filter(vfilterd, rsi[plane].wiener_info[tile_idx].vfilter);
+ quantize_sym_filter(hfilterd, rsi[plane].wiener_info[tile_idx].hfilter);
- if (!wiener_decompose_sep_sym(M, H, vfilterd, hfilterd)) {
- info->frame_restoration_type = RESTORE_NONE;
- aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
- aom_yv12_copy_u(&cpi->last_frame_uf, cm->frame_to_show);
- aom_yv12_copy_v(&cpi->last_frame_uf, cm->frame_to_show);
- return cost_norestore;
- }
- quantize_sym_filter(vfilterd, rsi[plane].wiener_info[0].vfilter);
- quantize_sym_filter(hfilterd, rsi[plane].wiener_info[0].hfilter);
+ // Filter score computes the value of the function x'*A*x - x'*b for the
+ // learned filter and compares it against identity filer. If there is no
+ // reduction in the function, the filter is reverted back to identity
+ score = compute_score(M, H, rsi[plane].wiener_info[tile_idx].vfilter,
+ rsi[plane].wiener_info[tile_idx].hfilter);
+ if (score > 0.0) {
+ type[tile_idx] = RESTORE_NONE;
+ continue;
+ }
- // Filter score computes the value of the function x'*A*x - x'*b for the
- // learned filter and compares it against identity filer. If there is no
- // reduction in the function, the filter is reverted back to identity
- score = compute_score(M, H, rsi[plane].wiener_info[0].vfilter,
- rsi[plane].wiener_info[0].hfilter);
- if (score > 0.0) {
- info->frame_restoration_type = RESTORE_NONE;
- aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
- aom_yv12_copy_u(&cpi->last_frame_uf, cm->frame_to_show);
- aom_yv12_copy_v(&cpi->last_frame_uf, cm->frame_to_show);
- return cost_norestore;
+ rsi[plane].restoration_type[tile_idx] = RESTORE_WIENER;
+ err = try_restoration_tile(src, cpi, rsi, 1 << plane, partial_frame,
+ tile_idx, 0, 0, dst_frame);
+ bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
+ bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, 1);
+ cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+ if (cost_wiener >= cost_norestore) {
+ type[tile_idx] = RESTORE_NONE;
+ } else {
+ type[tile_idx] = RESTORE_WIENER;
+ memcpy(&wiener_info[tile_idx], &rsi[plane].wiener_info[tile_idx],
+ sizeof(wiener_info[tile_idx]));
+ }
+ rsi[plane].restoration_type[tile_idx] = RESTORE_NONE;
}
-
- info->frame_restoration_type = RESTORE_WIENER;
- rsi[plane].restoration_type[0] = info->restoration_type[0] = RESTORE_WIENER;
- rsi[plane].wiener_info[0].level = 1;
- memcpy(&wiener_info[0], &rsi[plane].wiener_info[0], sizeof(wiener_info[0]));
- for (tile_idx = 1; tile_idx < ntiles; ++tile_idx) {
- info->restoration_type[tile_idx] = RESTORE_WIENER;
- memcpy(&rsi[plane].wiener_info[tile_idx], &rsi[plane].wiener_info[0],
- sizeof(rsi[plane].wiener_info[0]));
- memcpy(&wiener_info[tile_idx], &rsi[plane].wiener_info[0],
- sizeof(rsi[plane].wiener_info[0]));
+ aom_yv12_copy_frame(&cpi->last_frame_db, cm->frame_to_show);
+ // Cost for Wiener filtering
+ bits = 0;
+ for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+ bits +=
+ av1_cost_bit(RESTORE_NONE_WIENER_PROB, type[tile_idx] != RESTORE_NONE);
+ memcpy(&rsi[plane].wiener_info[tile_idx], &wiener_info[tile_idx],
+ sizeof(wiener_info[tile_idx]));
+ if (type[tile_idx] == RESTORE_WIENER) {
+ bits += (WIENER_FILT_BITS << AV1_PROB_COST_SHIFT);
+ }
+ rsi[plane].restoration_type[tile_idx] = type[tile_idx];
}
- err = try_restoration_frame(src, cpi, rsi, (1 << plane), partial_frame,
+ err = try_restoration_frame(src, cpi, rsi, 1 << plane, partial_frame,
dst_frame);
- bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
- cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
- if (cost_wiener > cost_norestore) {
+ cost_wiener_frame = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+
+ if (cost_wiener_frame < cost_norestore_frame) {
+ info->frame_restoration_type = RESTORE_WIENER;
+ } else {
info->frame_restoration_type = RESTORE_NONE;
- aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
- aom_yv12_copy_u(&cpi->last_frame_uf, cm->frame_to_show);
- aom_yv12_copy_v(&cpi->last_frame_uf, cm->frame_to_show);
- return cost_norestore;
}
aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
aom_yv12_copy_u(&cpi->last_frame_uf, cm->frame_to_show);
aom_yv12_copy_v(&cpi->last_frame_uf, cm->frame_to_show);
- return cost_wiener;
+ return info->frame_restoration_type == RESTORE_WIENER ? cost_wiener_frame
+ : cost_norestore_frame;
}
static double search_wiener(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
int filter_level, int partial_frame,
- RestorationInfo *info, double *best_tile_cost,
+ RestorationInfo *info, RestorationType *type,
+ double *best_tile_cost,
YV12_BUFFER_CONFIG *dst_frame) {
WienerInfo *wiener_info = info->wiener_info;
AV1_COMMON *const cm = &cpi->common;
@@ -1091,7 +1123,6 @@
double score;
int tile_idx, tile_width, tile_height, nhtiles, nvtiles;
int h_start, h_end, v_start, v_end;
- int i;
const int ntiles = av1_get_rest_ntiles(width, height, &tile_width,
&tile_height, &nhtiles, &nvtiles);
assert(width == dgd->y_crop_width);
@@ -1107,8 +1138,9 @@
rsi->frame_restoration_type = RESTORE_WIENER;
- for (tile_idx = 0; tile_idx < ntiles; ++tile_idx)
- rsi->wiener_info[tile_idx].level = 0;
+ for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+ rsi->restoration_type[tile_idx] = RESTORE_NONE;
+ }
// Construct a (WIENER_HALFWIN)-pixel border around the frame
#if CONFIG_AOM_HIGHBITDEPTH
@@ -1143,9 +1175,10 @@
compute_stats(dgd->y_buffer, src->y_buffer, h_start, h_end, v_start,
v_end, dgd_stride, src_stride, M, H);
- wiener_info[tile_idx].level = 1;
+ type[tile_idx] = RESTORE_WIENER;
+
if (!wiener_decompose_sep_sym(M, H, vfilterd, hfilterd)) {
- wiener_info[tile_idx].level = 0;
+ type[tile_idx] = RESTORE_NONE;
continue;
}
quantize_sym_filter(vfilterd, rsi->wiener_info[tile_idx].vfilter);
@@ -1157,48 +1190,41 @@
score = compute_score(M, H, rsi->wiener_info[tile_idx].vfilter,
rsi->wiener_info[tile_idx].hfilter);
if (score > 0.0) {
- wiener_info[tile_idx].level = 0;
+ type[tile_idx] = RESTORE_NONE;
continue;
}
- rsi->wiener_info[tile_idx].level = 1;
+ rsi->restoration_type[tile_idx] = RESTORE_WIENER;
err = try_restoration_tile(src, cpi, rsi, 1, partial_frame, tile_idx, 0, 0,
dst_frame);
bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, 1);
cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
if (cost_wiener >= cost_norestore) {
- wiener_info[tile_idx].level = 0;
+ type[tile_idx] = RESTORE_NONE;
} else {
- wiener_info[tile_idx].level = 1;
- for (i = 0; i < WIENER_WIN; ++i) {
- wiener_info[tile_idx].vfilter[i] =
- rsi->wiener_info[tile_idx].vfilter[i];
- wiener_info[tile_idx].hfilter[i] =
- rsi->wiener_info[tile_idx].hfilter[i];
- }
+ type[tile_idx] = RESTORE_WIENER;
+ memcpy(&wiener_info[tile_idx], &rsi->wiener_info[tile_idx],
+ sizeof(wiener_info[tile_idx]));
bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
best_tile_cost[tile_idx] = RDCOST_DBL(
x->rdmult, x->rddiv,
(bits + cpi->switchable_restore_cost[RESTORE_WIENER]) >> 4, err);
}
- rsi->wiener_info[tile_idx].level = 0;
+ rsi->restoration_type[tile_idx] = RESTORE_NONE;
}
// Cost for Wiener filtering
bits = frame_level_restore_bits[rsi->frame_restoration_type]
<< AV1_PROB_COST_SHIFT;
for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
- bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, wiener_info[tile_idx].level);
- rsi->wiener_info[tile_idx].level = wiener_info[tile_idx].level;
- if (wiener_info[tile_idx].level) {
+ bits +=
+ av1_cost_bit(RESTORE_NONE_WIENER_PROB, type[tile_idx] != RESTORE_NONE);
+ memcpy(&rsi->wiener_info[tile_idx], &wiener_info[tile_idx],
+ sizeof(wiener_info[tile_idx]));
+ if (type[tile_idx] == RESTORE_WIENER) {
bits += (WIENER_FILT_BITS << AV1_PROB_COST_SHIFT);
- for (i = 0; i < WIENER_WIN; ++i) {
- rsi->wiener_info[tile_idx].vfilter[i] =
- wiener_info[tile_idx].vfilter[i];
- rsi->wiener_info[tile_idx].hfilter[i] =
- wiener_info[tile_idx].hfilter[i];
- }
}
+ rsi->restoration_type[tile_idx] = type[tile_idx];
}
err = try_restoration_frame(src, cpi, rsi, 1, partial_frame, dst_frame);
cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
@@ -1209,7 +1235,8 @@
static double search_norestore(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
int filter_level, int partial_frame,
- RestorationInfo *info, double *best_tile_cost,
+ RestorationInfo *info, RestorationType *type,
+ double *best_tile_cost,
YV12_BUFFER_CONFIG *dst_frame) {
double err, cost_norestore;
int bits;
@@ -1237,6 +1264,7 @@
best_tile_cost[tile_idx] =
RDCOST_DBL(x->rdmult, x->rddiv,
(cpi->switchable_restore_cost[RESTORE_NONE] >> 4), err);
+ type[tile_idx] = RESTORE_NONE;
}
// RD cost associated with no restoration
err = sse_restoration_tile(src, cm->frame_to_show, cm, 0, cm->width, 0,
@@ -1291,14 +1319,18 @@
struct loopfilter *const lf = &cm->lf;
double cost_restore[RESTORE_TYPES];
double *tile_cost[RESTORE_SWITCHABLE_TYPES];
+ RestorationType *restore_types[RESTORE_SWITCHABLE_TYPES];
double best_cost_restore;
RestorationType r, best_restore;
const int ntiles =
av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
- for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++)
+ for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++) {
tile_cost[r] = (double *)aom_malloc(sizeof(*tile_cost[0]) * ntiles);
+ restore_types[r] =
+ (RestorationType *)aom_malloc(sizeof(*restore_types[0]) * ntiles);
+ }
lf->sharpness_level = cm->frame_type == KEY_FRAME ? 0 : cpi->oxcf.sharpness;
@@ -1342,7 +1374,8 @@
for (r = 0; r < RESTORE_SWITCHABLE_TYPES; ++r) {
cost_restore[r] = search_restore_fun[r](
src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
- &cm->rst_info[0], tile_cost[r], &cpi->trial_frame_rst);
+ &cm->rst_info[0], restore_types[r], tile_cost[r],
+ &cpi->trial_frame_rst);
}
cost_restore[RESTORE_SWITCHABLE] = search_switchable_restoration(
cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE, &cm->rst_info[0],
@@ -1357,13 +1390,19 @@
}
}
cm->rst_info[0].frame_restoration_type = best_restore;
+ if (best_restore != RESTORE_SWITCHABLE) {
+ memcpy(cm->rst_info[0].restoration_type, restore_types[best_restore],
+ ntiles * sizeof(restore_types[best_restore][0]));
+ }
// Color components
search_wiener_uv(src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
AOM_PLANE_U, &cm->rst_info[AOM_PLANE_U],
+ cm->rst_info[AOM_PLANE_U].restoration_type,
&cpi->trial_frame_rst);
search_wiener_uv(src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
AOM_PLANE_V, &cm->rst_info[AOM_PLANE_V],
+ cm->rst_info[AOM_PLANE_V].restoration_type,
&cpi->trial_frame_rst);
/*
printf("Frame %d/%d restore types: %d %d %d\n",
@@ -1380,5 +1419,8 @@
cost_restore[2], cost_restore[3], cost_restore[4]);
*/
- for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++) aom_free(tile_cost[r]);
+ for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++) {
+ aom_free(tile_cost[r]);
+ aom_free(restore_types[r]);
+ }
}