Commit 76c7800e authored by Rupert Swarbrick's avatar Rupert Swarbrick

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
parent e2692c5c
......@@ -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);
......
......@@ -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
......
......@@ -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);
}
}
......
......@@ -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
......
......@@ -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
......
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