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]); + } }