Commit a43a2d98 authored by Debargha Mukherjee's avatar Debargha Mukherjee

Add UV wiener loop restoration

Enables Wiener based loop restoration only for the UV
frames. The selfguided and domaintranform filters do not
work very well for UV components, hence they are disabled.
For each UV frame a single set of wiener parameters are
sent. They are applied tile-wise, but all tiles use the
same parameters.

BDRATE (Global PSNR) results:
-----------------------------
lowres: -1.266% (up from -0.666%, good improvement)
midres: -1.815% (up from -1.792%, tiny improvement)

Tiling on UV components will be explored subsequently.

Change-Id: Ib5be93121c4e88e05edf3c36c46488df3cfcd1e2
parent 8fcfcc57
......@@ -18,10 +18,14 @@ if (aom_config("CONFIG_SPATIAL_RESAMPLING") eq "yes") {
add_proto qw/void aom_yv12_extend_frame_borders/, "struct yv12_buffer_config *ybf";
add_proto qw/void aom_yv12_copy_frame/, "const struct yv12_buffer_config *src_ybc, struct yv12_buffer_config *dst_ybc";
add_proto qw/void aom_yv12_copy_frame/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc";
add_proto qw/void aom_yv12_copy_y/, "const struct yv12_buffer_config *src_ybc, struct yv12_buffer_config *dst_ybc";
add_proto qw/void aom_yv12_copy_u/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc";
add_proto qw/void aom_yv12_copy_v/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc";
if (aom_config("CONFIG_AV1") eq "yes") {
add_proto qw/void aom_extend_frame_borders/, "struct yv12_buffer_config *ybf";
specialize qw/aom_extend_frame_borders dspr2/;
......
......@@ -228,79 +228,79 @@ static void memcpy_short_addr(uint8_t *dst8, const uint8_t *src8, int num) {
// Copies the source image into the destination image and updates the
// destination's UMV borders.
// Note: The frames are assumed to be identical in size.
void aom_yv12_copy_frame_c(const YV12_BUFFER_CONFIG *src_ybc,
YV12_BUFFER_CONFIG *dst_ybc) {
void aom_yv12_copy_frame_c(const YV12_BUFFER_CONFIG *src_bc,
YV12_BUFFER_CONFIG *dst_bc) {
int row;
const uint8_t *src = src_ybc->y_buffer;
uint8_t *dst = dst_ybc->y_buffer;
const uint8_t *src = src_bc->y_buffer;
uint8_t *dst = dst_bc->y_buffer;
#if 0
/* These assertions are valid in the codec, but the libaom-tester uses
* this code slightly differently.
*/
assert(src_ybc->y_width == dst_ybc->y_width);
assert(src_ybc->y_height == dst_ybc->y_height);
assert(src_bc->y_width == dst_bc->y_width);
assert(src_bc->y_height == dst_bc->y_height);
#endif
#if CONFIG_AOM_HIGHBITDEPTH
if (src_ybc->flags & YV12_FLAG_HIGHBITDEPTH) {
assert(dst_ybc->flags & YV12_FLAG_HIGHBITDEPTH);
for (row = 0; row < src_ybc->y_height; ++row) {
memcpy_short_addr(dst, src, src_ybc->y_width);
src += src_ybc->y_stride;
dst += dst_ybc->y_stride;
if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) {
assert(dst_bc->flags & YV12_FLAG_HIGHBITDEPTH);
for (row = 0; row < src_bc->y_height; ++row) {
memcpy_short_addr(dst, src, src_bc->y_width);
src += src_bc->y_stride;
dst += dst_bc->y_stride;
}
src = src_ybc->u_buffer;
dst = dst_ybc->u_buffer;
src = src_bc->u_buffer;
dst = dst_bc->u_buffer;
for (row = 0; row < src_ybc->uv_height; ++row) {
memcpy_short_addr(dst, src, src_ybc->uv_width);
src += src_ybc->uv_stride;
dst += dst_ybc->uv_stride;
for (row = 0; row < src_bc->uv_height; ++row) {
memcpy_short_addr(dst, src, src_bc->uv_width);
src += src_bc->uv_stride;
dst += dst_bc->uv_stride;
}
src = src_ybc->v_buffer;
dst = dst_ybc->v_buffer;
src = src_bc->v_buffer;
dst = dst_bc->v_buffer;
for (row = 0; row < src_ybc->uv_height; ++row) {
memcpy_short_addr(dst, src, src_ybc->uv_width);
src += src_ybc->uv_stride;
dst += dst_ybc->uv_stride;
for (row = 0; row < src_bc->uv_height; ++row) {
memcpy_short_addr(dst, src, src_bc->uv_width);
src += src_bc->uv_stride;
dst += dst_bc->uv_stride;
}
aom_yv12_extend_frame_borders_c(dst_ybc);
aom_yv12_extend_frame_borders_c(dst_bc);
return;
} else {
assert(!(dst_ybc->flags & YV12_FLAG_HIGHBITDEPTH));
assert(!(dst_bc->flags & YV12_FLAG_HIGHBITDEPTH));
}
#endif
for (row = 0; row < src_ybc->y_height; ++row) {
memcpy(dst, src, src_ybc->y_width);
src += src_ybc->y_stride;
dst += dst_ybc->y_stride;
for (row = 0; row < src_bc->y_height; ++row) {
memcpy(dst, src, src_bc->y_width);
src += src_bc->y_stride;
dst += dst_bc->y_stride;
}
src = src_ybc->u_buffer;
dst = dst_ybc->u_buffer;
src = src_bc->u_buffer;
dst = dst_bc->u_buffer;
for (row = 0; row < src_ybc->uv_height; ++row) {
memcpy(dst, src, src_ybc->uv_width);
src += src_ybc->uv_stride;
dst += dst_ybc->uv_stride;
for (row = 0; row < src_bc->uv_height; ++row) {
memcpy(dst, src, src_bc->uv_width);
src += src_bc->uv_stride;
dst += dst_bc->uv_stride;
}
src = src_ybc->v_buffer;
dst = dst_ybc->v_buffer;
src = src_bc->v_buffer;
dst = dst_bc->v_buffer;
for (row = 0; row < src_ybc->uv_height; ++row) {
memcpy(dst, src, src_ybc->uv_width);
src += src_ybc->uv_stride;
dst += dst_ybc->uv_stride;
for (row = 0; row < src_bc->uv_height; ++row) {
memcpy(dst, src, src_bc->uv_width);
src += src_bc->uv_stride;
dst += dst_bc->uv_stride;
}
aom_yv12_extend_frame_borders_c(dst_ybc);
aom_yv12_extend_frame_borders_c(dst_bc);
}
void aom_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc,
......@@ -320,7 +320,7 @@ void aom_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc,
}
return;
}
#endif
#endif // CONFIG_AOM_HIGHBITDEPTH
for (row = 0; row < src_ybc->y_height; ++row) {
memcpy(dst, src, src_ybc->y_width);
......@@ -328,3 +328,55 @@ void aom_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc,
dst += dst_ybc->y_stride;
}
}
void aom_yv12_copy_u_c(const YV12_BUFFER_CONFIG *src_bc,
YV12_BUFFER_CONFIG *dst_bc) {
int row;
const uint8_t *src = src_bc->u_buffer;
uint8_t *dst = dst_bc->u_buffer;
#if CONFIG_AOM_HIGHBITDEPTH
if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) {
const uint16_t *src16 = CONVERT_TO_SHORTPTR(src);
uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst);
for (row = 0; row < src_bc->uv_height; ++row) {
memcpy(dst16, src16, src_bc->uv_width * sizeof(uint16_t));
src16 += src_bc->uv_stride;
dst16 += dst_bc->uv_stride;
}
return;
}
#endif // CONFIG_AOM_HIGHBITDEPTH
for (row = 0; row < src_bc->uv_height; ++row) {
memcpy(dst, src, src_bc->uv_width);
src += src_bc->uv_stride;
dst += dst_bc->uv_stride;
}
}
void aom_yv12_copy_v_c(const YV12_BUFFER_CONFIG *src_bc,
YV12_BUFFER_CONFIG *dst_bc) {
int row;
const uint8_t *src = src_bc->v_buffer;
uint8_t *dst = dst_bc->v_buffer;
#if CONFIG_AOM_HIGHBITDEPTH
if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) {
const uint16_t *src16 = CONVERT_TO_SHORTPTR(src);
uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst);
for (row = 0; row < src_bc->uv_height; ++row) {
memcpy(dst16, src16, src_bc->uv_width * sizeof(uint16_t));
src16 += src_bc->uv_stride;
dst16 += dst_bc->uv_stride;
}
return;
}
#endif // CONFIG_AOM_HIGHBITDEPTH
for (row = 0; row < src_bc->uv_height; ++row) {
memcpy(dst, src, src_bc->uv_width);
src += src_bc->uv_stride;
dst += dst_bc->uv_stride;
}
}
......@@ -89,7 +89,9 @@ void av1_free_ref_frame_buffers(BufferPool *pool) {
#if CONFIG_LOOP_RESTORATION
void av1_alloc_restoration_buffers(AV1_COMMON *cm) {
av1_alloc_restoration_struct(&cm->rst_info, cm->width, cm->height);
int p;
for (p = 0; p < MAX_MB_PLANE; ++p)
av1_alloc_restoration_struct(&cm->rst_info[p], cm->width, cm->height);
cm->rst_internal.tmpbuf =
(int32_t *)aom_realloc(cm->rst_internal.tmpbuf, RESTORATION_TMPBUF_SIZE);
if (cm->rst_internal.tmpbuf == NULL)
......@@ -98,7 +100,9 @@ void av1_alloc_restoration_buffers(AV1_COMMON *cm) {
}
void av1_free_restoration_buffers(AV1_COMMON *cm) {
av1_free_restoration_struct(&cm->rst_info);
int p;
for (p = 0; p < MAX_MB_PLANE; ++p)
av1_free_restoration_struct(&cm->rst_info[p]);
aom_free(cm->rst_internal.tmpbuf);
cm->rst_internal.tmpbuf = NULL;
}
......
......@@ -306,7 +306,7 @@ typedef struct AV1Common {
loop_filter_info_n lf_info;
#if CONFIG_LOOP_RESTORATION
RestorationInfo rst_info;
RestorationInfo rst_info[MAX_MB_PLANE];
RestorationInternal rst_internal;
#endif // CONFIG_LOOP_RESTORATION
......
This diff is collapsed.
......@@ -233,14 +233,9 @@ void av1_domaintxfmrf_restoration_highbd(uint16_t *dgd, int width, int height,
int32_t *tmpbuf);
#endif // CONFIG_AOM_HIGHBITDEPTH
void decode_xq(int *xqd, int *xq);
void av1_loop_restoration_init(RestorationInternal *rst, RestorationInfo *rsi,
int kf, int width, int height);
void av1_loop_restoration_frame(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm,
RestorationInfo *rsi, int y_only,
RestorationInfo *rsi, int components_pattern,
int partial_frame, YV12_BUFFER_CONFIG *dst);
void av1_loop_restoration_rows(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm,
int start_mi_row, int end_mi_row, int y_only,
YV12_BUFFER_CONFIG *dst);
void av1_loop_restoration_precal();
#ifdef __cplusplus
} // extern "C"
......
......@@ -2294,7 +2294,8 @@ static void setup_segmentation(AV1_COMMON *const cm,
#if CONFIG_LOOP_RESTORATION
static void decode_restoration_mode(AV1_COMMON *cm,
struct aom_read_bit_buffer *rb) {
RestorationInfo *rsi = &cm->rst_info;
int p;
RestorationInfo *rsi = &cm->rst_info[0];
if (aom_rb_read_bit(rb)) {
if (aom_rb_read_bit(rb))
rsi->frame_restoration_type =
......@@ -2305,27 +2306,39 @@ static void decode_restoration_mode(AV1_COMMON *cm,
rsi->frame_restoration_type =
aom_rb_read_bit(rb) ? RESTORE_SWITCHABLE : RESTORE_NONE;
}
for (p = 1; p < MAX_MB_PLANE; ++p) {
cm->rst_info[p].frame_restoration_type =
aom_rb_read_bit(rb) ? RESTORE_WIENER : RESTORE_NONE;
}
}
static void read_wiener_filter(WienerInfo *wiener_info, aom_reader *rb) {
wiener_info->vfilter[0] =
wiener_info->vfilter[0] = wiener_info->vfilter[WIENER_WIN - 1] =
aom_read_literal(rb, WIENER_FILT_TAP0_BITS, ACCT_STR) +
WIENER_FILT_TAP0_MINV;
wiener_info->vfilter[1] =
wiener_info->vfilter[1] = wiener_info->vfilter[WIENER_WIN - 2] =
aom_read_literal(rb, WIENER_FILT_TAP1_BITS, ACCT_STR) +
WIENER_FILT_TAP1_MINV;
wiener_info->vfilter[2] =
wiener_info->vfilter[2] = wiener_info->vfilter[WIENER_WIN - 3] =
aom_read_literal(rb, WIENER_FILT_TAP2_BITS, ACCT_STR) +
WIENER_FILT_TAP2_MINV;
wiener_info->hfilter[0] =
wiener_info->vfilter[WIENER_HALFWIN] =
WIENER_FILT_STEP -
2 * (wiener_info->vfilter[0] + wiener_info->vfilter[1] +
wiener_info->vfilter[2]);
wiener_info->hfilter[0] = wiener_info->hfilter[WIENER_WIN - 1] =
aom_read_literal(rb, WIENER_FILT_TAP0_BITS, ACCT_STR) +
WIENER_FILT_TAP0_MINV;
wiener_info->hfilter[1] =
wiener_info->hfilter[1] = wiener_info->hfilter[WIENER_WIN - 2] =
aom_read_literal(rb, WIENER_FILT_TAP1_BITS, ACCT_STR) +
WIENER_FILT_TAP1_MINV;
wiener_info->hfilter[2] =
wiener_info->hfilter[2] = wiener_info->hfilter[WIENER_WIN - 3] =
aom_read_literal(rb, WIENER_FILT_TAP2_BITS, ACCT_STR) +
WIENER_FILT_TAP2_MINV;
wiener_info->hfilter[WIENER_HALFWIN] =
WIENER_FILT_STEP -
2 * (wiener_info->hfilter[0] + wiener_info->hfilter[1] +
wiener_info->hfilter[2]);
}
static void read_sgrproj_filter(SgrprojInfo *sgrproj_info, aom_reader *rb) {
......@@ -2343,10 +2356,10 @@ static void read_domaintxfmrf_filter(DomaintxfmrfInfo *domaintxfmrf_info,
}
static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
int i;
RestorationInfo *rsi = &cm->rst_info;
int i, p;
const int ntiles =
av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
RestorationInfo *rsi = &cm->rst_info[0];
if (rsi->frame_restoration_type != RESTORE_NONE) {
if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
for (i = 0; i < ntiles; ++i) {
......@@ -2399,6 +2412,19 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
}
}
}
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; ++i) {
rsi->restoration_type[i] = RESTORE_WIENER;
memcpy(&rsi->wiener_info[i], &rsi->wiener_info[0],
sizeof(rsi->wiener_info[0]));
}
}
}
}
#endif // CONFIG_LOOP_RESTORATION
......@@ -4596,8 +4622,10 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
*p_data_end = decode_tiles(pbi, data + first_partition_size, data_end);
}
#if CONFIG_LOOP_RESTORATION
if (cm->rst_info.frame_restoration_type != RESTORE_NONE) {
av1_loop_restoration_frame(new_fb, cm, &cm->rst_info, 0, 0, NULL);
if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
av1_loop_restoration_frame(new_fb, cm, cm->rst_info, 7, 0, NULL);
}
#endif // CONFIG_LOOP_RESTORATION
......
......@@ -3022,8 +3022,9 @@ static void update_coef_probs(AV1_COMP *cpi, aom_writer *w) {
#if CONFIG_LOOP_RESTORATION
static void encode_restoration_mode(AV1_COMMON *cm,
struct aom_write_bit_buffer *wb) {
RestorationInfo *rst = &cm->rst_info;
switch (rst->frame_restoration_type) {
int p;
RestorationInfo *rsi = &cm->rst_info[0];
switch (rsi->frame_restoration_type) {
case RESTORE_NONE:
aom_wb_write_bit(wb, 0);
aom_wb_write_bit(wb, 0);
......@@ -3048,6 +3049,14 @@ static void encode_restoration_mode(AV1_COMMON *cm,
break;
default: assert(0);
}
for (p = 1; p < MAX_MB_PLANE; ++p) {
rsi = &cm->rst_info[p];
switch (rsi->frame_restoration_type) {
case RESTORE_NONE: aom_wb_write_bit(wb, 0); break;
case RESTORE_WIENER: aom_wb_write_bit(wb, 1); break;
default: assert(0);
}
}
}
static void write_wiener_filter(WienerInfo *wiener_info, aom_writer *wb) {
......@@ -3079,8 +3088,8 @@ static void write_domaintxfmrf_filter(DomaintxfmrfInfo *domaintxfmrf_info,
}
static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
int i;
RestorationInfo *rsi = &cm->rst_info;
int i, p;
RestorationInfo *rsi = &cm->rst_info[0];
if (rsi->frame_restoration_type != RESTORE_NONE) {
if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
// RESTORE_SWITCHABLE
......@@ -3121,6 +3130,14 @@ static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
}
}
}
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);
} else if (rsi->frame_restoration_type != RESTORE_NONE) {
assert(0);
}
}
}
#endif // CONFIG_LOOP_RESTORATION
......
......@@ -459,7 +459,8 @@ static void dealloc_compressor_data(AV1_COMP *cpi) {
aom_free_frame_buffer(&cpi->last_frame_db);
aom_free_frame_buffer(&cpi->trial_frame_rst);
aom_free(cpi->extra_rstbuf);
av1_free_restoration_struct(&cpi->rst_search);
for (i = 0; i < MAX_MB_PLANE; ++i)
av1_free_restoration_struct(&cpi->rst_search[i]);
#endif // CONFIG_LOOP_RESTORATION
aom_free_frame_buffer(&cpi->scaled_source);
aom_free_frame_buffer(&cpi->scaled_last_source);
......@@ -712,6 +713,9 @@ static void alloc_raw_frame_buffers(AV1_COMP *cpi) {
}
static void alloc_util_frame_buffers(AV1_COMP *cpi) {
#if CONFIG_LOOP_RESTORATION
int i;
#endif // CONFIG_LOOP_RESTORATION
AV1_COMMON *const cm = &cpi->common;
if (aom_realloc_frame_buffer(&cpi->last_frame_uf, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
......@@ -747,7 +751,8 @@ static void alloc_util_frame_buffers(AV1_COMP *cpi) {
if (!cpi->extra_rstbuf)
aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
"Failed to allocate extra rstbuf for restoration");
av1_alloc_restoration_struct(&cpi->rst_search, cm->width, cm->height);
for (i = 0; i < MAX_MB_PLANE; ++i)
av1_alloc_restoration_struct(&cpi->rst_search[i], cm->width, cm->height);
#endif // CONFIG_LOOP_RESTORATION
if (aom_realloc_frame_buffer(&cpi->scaled_source, cm->width, cm->height,
......@@ -3496,9 +3501,10 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) {
}
#endif
#if CONFIG_LOOP_RESTORATION
if (cm->rst_info.frame_restoration_type != RESTORE_NONE) {
av1_loop_restoration_frame(cm->frame_to_show, cm, &cm->rst_info, 0, 0,
NULL);
if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
av1_loop_restoration_frame(cm->frame_to_show, cm, cm->rst_info, 7, 0, NULL);
}
#endif // CONFIG_LOOP_RESTORATION
aom_extend_frame_inner_borders(cm->frame_to_show);
......
......@@ -404,9 +404,9 @@ typedef struct AV1_COMP {
#if CONFIG_LOOP_RESTORATION
YV12_BUFFER_CONFIG last_frame_db;
YV12_BUFFER_CONFIG trial_frame_rst;
uint8_t *extra_rstbuf; // Extra buffers used in restoration search
RestorationInfo rst_search; // Used for encoder side search
#endif // CONFIG_LOOP_RESTORATION
uint8_t *extra_rstbuf; // Extra buffers used in restoration search
RestorationInfo rst_search[MAX_MB_PLANE]; // Used for encoder side search
#endif // CONFIG_LOOP_RESTORATION
// Ambient reconstruction err target for force key frames
int64_t ambient_err;
......
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