From 76c7800ea8b44fcefdeffadabd298ffd135d1d2f Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Thu, 2 Nov 2017 17:26:35 +0000 Subject: [PATCH] Allow horzonly superres and striped loop restoration We do this by upscaling the deblocked output as we save it into the RestorationStripeBoundaries line buffers. (See save_boundary_lines in restoration.c for the details) The upscaling is done by calling av1_convolve_horiz_rs, which reads off the edge of the frame and, of course, across tile boundaries. This means we need to extend the frame borders before saving boundary lines (hence the changes to decodeframe.c and encoder.c) Change-Id: Ia096846898b20afe4737433d772f7277d4f71724 --- av1/common/resize.c | 26 +++++++------- av1/common/resize.h | 13 +++++++ av1/common/restoration.c | 72 ++++++++++++++++++++++++--------------- av1/decoder/decodeframe.c | 3 ++ av1/encoder/encoder.c | 3 ++ 5 files changed, 78 insertions(+), 39 deletions(-) diff --git a/av1/common/resize.c b/av1/common/resize.c index 41a578bfa..61688d2dd 100644 --- a/av1/common/resize.c +++ b/av1/common/resize.c @@ -215,7 +215,7 @@ static const InterpKernel filteredinterp_filters1000[(1 << RS_SUBPEL_BITS)] = { #define UPSCALE_NORMATIVE_TAPS 6 #endif // CONFIG_HORZONLY_FRAME_SUPERRES -static const int16_t filter_normative[( +const int16_t av1_resize_filter_normative[( 1 << RS_SUBPEL_BITS)][UPSCALE_NORMATIVE_TAPS] = { #if UPSCALE_NORMATIVE_TAPS == 2 { 128, 0 }, { 126, 2 }, { 124, 4 }, { 122, 6 }, { 120, 8 }, { 118, 10 }, @@ -438,7 +438,7 @@ static void interpolate(const uint8_t *const input, int in_length, #define UPSCALE_PROC_UNIT 0 // Source step (roughly), 0: do not use #define UPSCALE_PROC_UNIT_SCALE (UPSCALE_PROC_UNIT / SCALE_NUMERATOR) -static int32_t get_upscale_convolve_step(int in_length, int out_length) { +int32_t av1_get_upscale_convolve_step(int in_length, int out_length) { return ((in_length << RS_SCALE_SUBPEL_BITS) + out_length / 2) / out_length; } @@ -461,7 +461,8 @@ static void interpolate_normative_core(const uint8_t *const src, int in_length, int interp_taps) { (void)superres_denom; assert(in_length < out_length); - const int32_t x_step_qn = get_upscale_convolve_step(in_length, out_length); + const int32_t x_step_qn = + av1_get_upscale_convolve_step(in_length, out_length); const int32_t x0_qn = get_upscale_convolve_x0(in_length, out_length, x_step_qn); // Note since we are upscaling, the first output sample is located before @@ -498,7 +499,7 @@ static void interpolate_normative(const uint8_t *const input, int in_length, intbuf[in_length + k] = intbuf[in_length - 1]; } interpolate_normative_core(intbuf, in_length, output, out_length, - superres_denom, &filter_normative[0][0], + superres_denom, &av1_resize_filter_normative[0][0], UPSCALE_NORMATIVE_TAPS); aom_free(intbuf_alloc); } @@ -731,10 +732,10 @@ static void upscale_normative_plane(const uint8_t *const input, int height, (void)height2; (void)superres_denom; assert(height2 == height); - const int32_t x_step_qn = get_upscale_convolve_step(width, width2); + const int32_t x_step_qn = av1_get_upscale_convolve_step(width, width2); const int32_t x0_qn = get_upscale_convolve_x0(width, width2, x_step_qn); av1_convolve_horiz_rs(input - 1, in_stride, output, out_stride, width2, - height2, &filter_normative[0][0], + height2, &av1_resize_filter_normative[0][0], UPSCALE_NORMATIVE_TAPS, x0_qn, x_step_qn); #else uint8_t *intbuf = (uint8_t *)aom_malloc(sizeof(uint8_t) * width2 * height); @@ -861,7 +862,8 @@ static void highbd_interpolate_normative_core(const uint16_t *const src, int interp_taps) { (void)superres_denom; assert(in_length < out_length); - const int32_t x_step_qn = get_upscale_convolve_step(in_length, out_length); + const int32_t x_step_qn = + av1_get_upscale_convolve_step(in_length, out_length); const int32_t x0_qn = get_upscale_convolve_x0(in_length, out_length, x_step_qn); // Note since we are upscaling, the first output sample is located before @@ -898,9 +900,9 @@ static void highbd_interpolate_normative(const uint16_t *const input, intbuf[-k - 1] = intbuf[0]; intbuf[in_length + k] = intbuf[in_length - 1]; } - highbd_interpolate_normative_core(intbuf, in_length, output, out_length, - superres_denom, bd, &filter_normative[0][0], - UPSCALE_NORMATIVE_TAPS); + highbd_interpolate_normative_core( + intbuf, in_length, output, out_length, superres_denom, bd, + &av1_resize_filter_normative[0][0], UPSCALE_NORMATIVE_TAPS); aom_free(intbuf_alloc); } #endif // !CONFIG_HORZONLY_FRAME_SUPERRES @@ -1117,11 +1119,11 @@ static void highbd_upscale_normative_plane(const uint8_t *const input, (void)height2; (void)superres_denom; assert(height2 == height); - const int32_t x_step_qn = get_upscale_convolve_step(width, width2); + const int32_t x_step_qn = av1_get_upscale_convolve_step(width, width2); const int32_t x0_qn = get_upscale_convolve_x0(width, width2, x_step_qn); av1_highbd_convolve_horiz_rs(CONVERT_TO_SHORTPTR(input - 1), in_stride, CONVERT_TO_SHORTPTR(output), out_stride, width2, - height2, &filter_normative[0][0], + height2, &av1_resize_filter_normative[0][0], UPSCALE_NORMATIVE_TAPS, x0_qn, x_step_qn, bd); #else uint16_t *intbuf = (uint16_t *)aom_malloc(sizeof(uint16_t) * width2 * height); diff --git a/av1/common/resize.h b/av1/common/resize.h index a24b9752a..b4ccf2850 100644 --- a/av1/common/resize.h +++ b/av1/common/resize.h @@ -110,6 +110,19 @@ static INLINE int av1_superres_unscaled(const AV1_COMMON *cm) { } #endif // CONFIG_FRAME_SUPERRES +#if CONFIG_FRAME_SUPERRES && CONFIG_LOOP_RESTORATION +#if CONFIG_HORZONLY_FRAME_SUPERRES +#define UPSCALE_NORMATIVE_TAPS 8 +#else +#define UPSCALE_NORMATIVE_TAPS 6 +#endif // CONFIG_HORZONLY_FRAME_SUPERRES + +extern const int16_t av1_resize_filter_normative[1 << RS_SUBPEL_BITS] + [UPSCALE_NORMATIVE_TAPS]; + +int32_t av1_get_upscale_convolve_step(int in_length, int out_length); +#endif + #ifdef __cplusplus } // extern "C" #endif diff --git a/av1/common/restoration.c b/av1/common/restoration.c index 0cbf3301d..ed2c2d954 100644 --- a/av1/common/restoration.c +++ b/av1/common/restoration.c @@ -1672,29 +1672,29 @@ int av1_loop_restoration_corners_in_sb(const struct AV1Common *cm, int plane, } #if CONFIG_STRIPED_LOOP_RESTORATION +static void memset16(uint16_t *arr, uint16_t val, int nelts) { + for (int i = 0; i < nelts; ++i) arr[i] = val; +} // Extend to left and right -static void extend_line(uint8_t *buf, int width, int extend, - int use_highbitdepth) { - int i; - if (use_highbitdepth) { - uint16_t val, *buf16 = (uint16_t *)buf; - val = buf16[0]; - for (i = 0; i < extend; i++) buf16[-1 - i] = val; - val = buf16[width - 1]; - for (i = 0; i < extend; i++) buf16[width + i] = val; - } else { - uint8_t val; - val = buf[0]; - for (i = 0; i < extend; i++) buf[-1 - i] = val; - val = buf[width - 1]; - for (i = 0; i < extend; i++) buf[width + i] = val; +static void extend_lines(uint8_t *buf, int width, int height, int stride, + int extend, int use_highbitdepth) { + for (int i = 0; i < height; ++i) { + if (use_highbitdepth) { + uint16_t *buf16 = (uint16_t *)buf; + memset16(buf16 - extend, buf16[0], extend); + memset16(buf16 + width, buf16[width - 1], extend); + } else { + memset(buf - extend, buf[0], extend); + memset(buf + width, buf[width - 1], extend); + } + buf += stride; } } -static void save_boundary_lines(const YV12_BUFFER_CONFIG *frame, int plane, - int row, int stripe, int use_highbd, - int is_above, +static void save_boundary_lines(const YV12_BUFFER_CONFIG *frame, + const AV1_COMMON *cm, int plane, int row, + int stripe, int use_highbd, int is_above, RestorationStripeBoundaries *boundaries) { const int is_uv = plane > 0; const int src_width = frame->crop_widths[is_uv]; @@ -1709,16 +1709,34 @@ static void save_boundary_lines(const YV12_BUFFER_CONFIG *frame, int plane, const int bdry_stride = boundaries->stripe_boundary_stride << use_highbd; uint8_t *bdry_rows = bdry_start + RESTORATION_CTX_VERT * stripe * bdry_stride; + const int lines_to_save = AOMMIN(RESTORATION_CTX_VERT, src_height - row); +#if CONFIG_FRAME_SUPERRES + const int ss_x = is_uv && cm->subsampling_x; + const int upscaled_width = (cm->superres_upscaled_width + ss_x) >> ss_x; + const int step = av1_get_upscale_convolve_step(src_width, upscaled_width); +#if CONFIG_HIGHBITDEPTH + if (use_highbd) + av1_highbd_convolve_horiz_rs( + (uint16_t *)src_rows, src_stride >> 1, (uint16_t *)bdry_rows, + bdry_stride >> 1, upscaled_width, lines_to_save, + &av1_resize_filter_normative[0][0], UPSCALE_NORMATIVE_TAPS, 0, step, + cm->bit_depth); + else +#endif // CONFIG_HIGHBITDEPTH + av1_convolve_horiz_rs(src_rows, src_stride, bdry_rows, bdry_stride, + upscaled_width, lines_to_save, + &av1_resize_filter_normative[0][0], + UPSCALE_NORMATIVE_TAPS, 0, step); +#else + (void)cm; + const int upscaled_width = src_width; const int line_bytes = src_width << use_highbd; - - for (int i = 0; i < RESTORATION_CTX_VERT; i++) { - const int y = row + i; - if (y >= src_height) return; - + for (int i = 0; i < lines_to_save; i++) { memcpy(bdry_rows + i * bdry_stride, src_rows + i * src_stride, line_bytes); - extend_line(bdry_rows + i * bdry_stride, src_width, RESTORATION_EXTRA_HORZ, - use_highbd); } +#endif // CONFIG_FRAME_SUPERRES + extend_lines(bdry_rows, upscaled_width, lines_to_save, bdry_stride, + RESTORATION_EXTRA_HORZ, use_highbd); } static void save_tile_row_boundary_lines(const YV12_BUFFER_CONFIG *frame, @@ -1748,11 +1766,11 @@ static void save_tile_row_boundary_lines(const YV12_BUFFER_CONFIG *frame, if (frame_stripe > 0) { // Save RESTORATION_CTX_VERT lines above the stripe if frame_stripe > 0 - save_boundary_lines(frame, plane, y0 - RESTORATION_CTX_VERT, + save_boundary_lines(frame, cm, plane, y0 - RESTORATION_CTX_VERT, frame_stripe - 1, use_highbd, 1, boundaries); } // Always save RESTORATION_CTX_VERT lines below the LR stripe - save_boundary_lines(frame, plane, y1, frame_stripe, use_highbd, 0, + save_boundary_lines(frame, cm, plane, y1, frame_stripe, use_highbd, 0, boundaries); } } diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 53cb21b96..0b124b33c 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c @@ -3842,6 +3842,9 @@ void av1_decode_tg_tiles_and_wrapup(AV1Decoder *pbi, const uint8_t *data, 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) { +#if CONFIG_FRAME_SUPERRES && CONFIG_HORZONLY_FRAME_SUPERRES + aom_extend_frame_borders(&pbi->cur_buf->buf); +#endif av1_loop_restoration_save_boundary_lines(&pbi->cur_buf->buf, cm); } #endif diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 7f23a3b27..8a2d9e20c 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c @@ -4628,6 +4628,9 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { #endif // CONFIG_INTRABC #if CONFIG_STRIPED_LOOP_RESTORATION +#if CONFIG_FRAME_SUPERRES && CONFIG_HORZONLY_FRAME_SUPERRES + aom_extend_frame_borders(cm->frame_to_show); +#endif av1_loop_restoration_save_boundary_lines(cm->frame_to_show, cm); #endif -- GitLab