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
diff --git a/av1/common/resize.c b/av1/common/resize.c index 41a578b..61688d2 100644 --- a/av1/common/resize.c +++ b/av1/common/resize.c
@@ -215,7 +215,7 @@ #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 @@ #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 @@ 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 @@ 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 @@ (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 @@ 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 @@ 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 @@ (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 a24b975..b4ccf28 100644 --- a/av1/common/resize.h +++ b/av1/common/resize.h
@@ -110,6 +110,19 @@ } #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 0cbf330..ed2c2d9 100644 --- a/av1/common/restoration.c +++ b/av1/common/restoration.c
@@ -1672,29 +1672,29 @@ } #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 @@ 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 @@ 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 53cb21b..0b124b3 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c
@@ -3842,6 +3842,9 @@ 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 7f23a3b..8a2d9e2 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -4628,6 +4628,9 @@ #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