Implement on the fly padding in decoder Calculate the amount of padding required for motion compensation in the decoder and pad the reference frame(s) accordingly. Change-Id: I0819f13e0c9aa8d3b790d49f0fc08684a535b830
diff --git a/av1/common/reconinter.c b/av1/common/reconinter.c index 63481eb..108eb1f 100644 --- a/av1/common/reconinter.c +++ b/av1/common/reconinter.c
@@ -32,23 +32,26 @@ // This function will determine whether or not to create a warped // prediction. -static INLINE int allow_warp(const MB_MODE_INFO *const mbmi, - const WarpTypesAllowed *const warp_types, - const WarpedMotionParams *const gm_params, - int build_for_obmc, int x_scale, int y_scale, - WarpedMotionParams *final_warp_params) { +int av1_allow_warp(const MB_MODE_INFO *const mbmi, + const WarpTypesAllowed *const warp_types, + const WarpedMotionParams *const gm_params, + int build_for_obmc, int x_scale, int y_scale, + WarpedMotionParams *final_warp_params) { if (x_scale != SCALE_SUBPEL_SHIFTS || y_scale != SCALE_SUBPEL_SHIFTS) return 0; - *final_warp_params = default_warp_params; + if (final_warp_params != NULL) *final_warp_params = default_warp_params; if (build_for_obmc) return 0; if (warp_types->local_warp_allowed && !mbmi->wm_params[0].invalid) { - memcpy(final_warp_params, &mbmi->wm_params[0], sizeof(*final_warp_params)); + if (final_warp_params != NULL) + memcpy(final_warp_params, &mbmi->wm_params[0], + sizeof(*final_warp_params)); return 1; } else if (warp_types->global_warp_allowed && !gm_params->invalid) { - memcpy(final_warp_params, gm_params, sizeof(*final_warp_params)); + if (final_warp_params != NULL) + memcpy(final_warp_params, gm_params, sizeof(*final_warp_params)); return 1; } @@ -73,8 +76,8 @@ WarpedMotionParams final_warp_params; const int do_warp = (w >= 8 && h >= 8 && - allow_warp(mi, warp_types, &xd->global_motion[mi->ref_frame[ref]], - build_for_obmc, xs, ys, &final_warp_params)); + av1_allow_warp(mi, warp_types, &xd->global_motion[mi->ref_frame[ref]], + build_for_obmc, xs, ys, &final_warp_params)); if (do_warp && xd->cur_frame_force_integer_mv == 0) { const struct macroblockd_plane *const pd = &xd->plane[plane]; const struct buf_2d *const pre_buf = &pd->pre[ref];
diff --git a/av1/common/reconinter.h b/av1/common/reconinter.h index 2bae318..73d8dea 100644 --- a/av1/common/reconinter.h +++ b/av1/common/reconinter.h
@@ -453,6 +453,12 @@ int order_idx, int *fwd_offset, int *bck_offset, int *use_jnt_comp_avg, int is_compound); +int av1_allow_warp(const MB_MODE_INFO *const mbmi, + const WarpTypesAllowed *const warp_types, + const WarpedMotionParams *const gm_params, + int build_for_obmc, int x_scale, int y_scale, + WarpedMotionParams *final_warp_params); + #ifdef __cplusplus } // extern "C" #endif
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 93b62c53..172ac7e 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c
@@ -335,11 +335,135 @@ aom_merge_corrupted_flag(&xd->corrupted, reader_corrupted_flag); } +typedef struct PadBlock { + int x0; + int x1; + int y0; + int y1; +} PadBlock; + +static void highbd_build_mc_border(const uint8_t *src8, uint8_t *dst8, + int stride, int x, int y, int b_w, int b_h, + int w, int h) { + // Get a pointer to the start of the real data for this row. + const uint16_t *src = CONVERT_TO_SHORTPTR(src8); + uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); + const uint16_t *ref_row = src - x - y * stride; + + if (y >= h) + ref_row += (h - 1) * stride; + else if (y > 0) + ref_row += y * stride; + + do { + int right = 0, copy; + int left = x < 0 ? -x : 0; + + if (left > b_w) left = b_w; + + if (x + b_w > w) right = x + b_w - w; + + if (right > b_w) right = b_w; + + copy = b_w - left - right; + + if (left) aom_memset16(dst, ref_row[0], left); + + if (copy) memcpy(dst + left, ref_row + x + left, copy * sizeof(uint16_t)); + + if (right) aom_memset16(dst + left + copy, ref_row[w - 1], right); + + dst += stride; + ++y; + + if (y > 0 && y < h) ref_row += stride; + } while (--b_h); +} + +static void build_mc_border(const uint8_t *src, uint8_t *dst, int stride, int x, + int y, int b_w, int b_h, int w, int h) { + // Get a pointer to the start of the real data for this row. + const uint8_t *ref_row = src - x - y * stride; + + if (y >= h) + ref_row += (h - 1) * stride; + else if (y > 0) + ref_row += y * stride; + + do { + int right = 0, copy; + int left = x < 0 ? -x : 0; + + if (left > b_w) left = b_w; + + if (x + b_w > w) right = x + b_w - w; + + if (right > b_w) right = b_w; + + copy = b_w - left - right; + + if (left) memset(dst, ref_row[0], left); + if (copy) memcpy(dst + left, ref_row + x + left, copy); + if (right) memset(dst + left + copy, ref_row[w - 1], right); + + dst += stride; + ++y; + + if (y > 0 && y < h) ref_row += stride; + } while (--b_h); +} + +static INLINE void extend_mc_borders(MACROBLOCKD *xd, + const struct scale_factors *const sf, + struct buf_2d *const pre_buf, + MV32 scaled_mv, PadBlock block, + int subpel_x_mv, int subpel_y_mv, + int do_warp) { + const int is_scaled = av1_is_scaled(sf); + // Get reference width and height. + int frame_width = pre_buf->width; + int frame_height = pre_buf->height; + + // Do border extension if there is motion or + // width/height is not a multiple of 8 pixels. + if ((!do_warp) && (is_scaled || scaled_mv.col || scaled_mv.row || + (frame_width & 0x7) || (frame_height & 0x7))) { + if (subpel_x_mv || (sf->x_step_q4 != SUBPEL_SHIFTS)) { + block.x0 -= AOM_INTERP_EXTEND - 1; + block.x1 += AOM_INTERP_EXTEND; + } + + if (subpel_y_mv || (sf->y_step_q4 != SUBPEL_SHIFTS)) { + block.y0 -= AOM_INTERP_EXTEND - 1; + block.y1 += AOM_INTERP_EXTEND; + } + + // Skip border extension if block is inside the frame. + if (block.x0 < 0 || block.x1 > frame_width - 1 || block.y0 < 0 || + block.y1 > frame_height - 1) { + // Get reference block pointer. + uint8_t *buf_ptr = pre_buf->buf0 + block.y0 * pre_buf->stride + block.x0; + int buf_stride = pre_buf->stride; + + // Extend the border. + if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) + highbd_build_mc_border(buf_ptr, buf_ptr, buf_stride, block.x0, block.y0, + block.x1 - block.x0, block.y1 - block.y0, + frame_width, frame_height); + else + build_mc_border(buf_ptr, buf_ptr, buf_stride, block.x0, block.y0, + block.x1 - block.x0, block.y1 - block.y0, frame_width, + frame_height); + } + } +} + static INLINE void dec_calc_subpel_params( MACROBLOCKD *xd, const struct scale_factors *const sf, const MV mv, int plane, const int pre_x, const int pre_y, int x, int y, struct buf_2d *const pre_buf, uint8_t **pre, SubpelParams *subpel_params, - int bw, int bh) { + PadBlock *block, int bw, int bh, int mi_x, int mi_y, MV32 *scaled_mv, + int *subpel_x_mv, int *subpel_y_mv) { struct macroblockd_plane *const pd = &xd->plane[plane]; const int is_scaled = av1_is_scaled(sf); if (is_scaled) { @@ -368,14 +492,54 @@ subpel_params->subpel_y = pos_y & SCALE_SUBPEL_MASK; subpel_params->xs = sf->x_step_q4; subpel_params->ys = sf->y_step_q4; + + // Get block position in the scaled reference frame. + MV temp_mv; + temp_mv = clamp_mv_to_umv_border_sb(xd, &mv, bw, bh, pd->subsampling_x, + pd->subsampling_y); + *scaled_mv = av1_scale_mv(&temp_mv, (mi_x + x), (mi_y + y), sf); + scaled_mv->row += SCALE_EXTRA_OFF; + scaled_mv->col += SCALE_EXTRA_OFF; + + // Get reference block top left coordinate. + block->x0 = pos_x >> SCALE_SUBPEL_BITS; + block->y0 = pos_y >> SCALE_SUBPEL_BITS; + + // Get reference block bottom right coordinate. + block->x1 = + ((pos_x + (bw - 1) * subpel_params->xs) >> SCALE_SUBPEL_BITS) + 1; + block->y1 = + ((pos_y + (bh - 1) * subpel_params->ys) >> SCALE_SUBPEL_BITS) + 1; + + *subpel_x_mv = scaled_mv->col & SCALE_SUBPEL_MASK; + *subpel_y_mv = scaled_mv->row & SCALE_SUBPEL_MASK; } else { + // Get block position in current frame. + int pos_x = (pre_x + x) << SUBPEL_BITS; + int pos_y = (pre_y + y) << SUBPEL_BITS; + const MV mv_q4 = clamp_mv_to_umv_border_sb( xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y); subpel_params->xs = subpel_params->ys = SCALE_SUBPEL_SHIFTS; + scaled_mv->row = mv_q4.row; + scaled_mv->col = mv_q4.col; subpel_params->subpel_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS; subpel_params->subpel_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS; *pre = pre_buf->buf + (y + (mv_q4.row >> SUBPEL_BITS)) * pre_buf->stride + (x + (mv_q4.col >> SUBPEL_BITS)); + + // Get reference block top left coordinate. + pos_x += scaled_mv->col; + pos_y += scaled_mv->row; + block->x0 = pos_x >> SUBPEL_BITS; + block->y0 = pos_y >> SUBPEL_BITS; + + // Get reference block bottom right coordinate. + block->x1 = (pos_x >> SUBPEL_BITS) + (bw - 1) + 1; + block->y1 = (pos_y >> SUBPEL_BITS) + (bh - 1) + 1; + + *subpel_x_mv = scaled_mv->col & SUBPEL_MASK; + *subpel_y_mv = scaled_mv->row & SUBPEL_MASK; } } @@ -473,12 +637,19 @@ uint8_t *pre; SubpelParams subpel_params; + MV32 scaled_mv; + PadBlock block; + int subpel_x_mv, subpel_y_mv; WarpTypesAllowed warp_types; warp_types.global_warp_allowed = is_global[ref]; warp_types.local_warp_allowed = this_mbmi->motion_mode == WARPED_CAUSAL; dec_calc_subpel_params(xd, sf, mv, plane, pre_x, pre_y, x, y, pre_buf, - &pre, &subpel_params, bw, bh); + &pre, &subpel_params, &block, bw, bh, mi_x, mi_y, + &scaled_mv, &subpel_x_mv, &subpel_y_mv); + + extend_mc_borders(xd, sf, pre_buf, scaled_mv, block, subpel_x_mv, + subpel_y_mv, 0); conv_params.ref = ref; conv_params.do_average = ref; @@ -516,8 +687,27 @@ struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; const MV mv = mi->mv[ref].as_mv; + MV32 scaled_mv; + PadBlock block; + int subpel_x_mv, subpel_y_mv; + dec_calc_subpel_params(xd, sf, mv, plane, pre_x, pre_y, 0, 0, pre_buf, - &pre[ref], &subpel_params[ref], bw, bh); + &pre[ref], &subpel_params[ref], &block, bw, bh, + mi_x, mi_y, &scaled_mv, &subpel_x_mv, + &subpel_y_mv); + + WarpTypesAllowed warp_types; + warp_types.global_warp_allowed = is_global[ref]; + warp_types.local_warp_allowed = mi->motion_mode == WARPED_CAUSAL; + int do_warp = (bw >= 8 && bh >= 8 && + av1_allow_warp(mi, &warp_types, + &xd->global_motion[mi->ref_frame[ref]], + build_for_obmc, subpel_params[ref].xs, + subpel_params[ref].ys, NULL)); + do_warp = (do_warp && xd->cur_frame_force_integer_mv == 0); + + extend_mc_borders(xd, sf, pre_buf, scaled_mv, block, subpel_x_mv, + subpel_y_mv, do_warp); } ConvolveParams conv_params = get_conv_params_no_round(
diff --git a/av1/decoder/decoder.c b/av1/decoder/decoder.c index 33bfb8c..d676bce 100644 --- a/av1/decoder/decoder.c +++ b/av1/decoder/decoder.c
@@ -290,15 +290,6 @@ unlock_buffer_pool(pool); cm->frame_to_show = get_frame_new_buffer(cm); - - // For now, we only extend the frame borders when the whole frame is - // decoded. Later, if needed, extend the border for the decoded tile on the - // frame border. - if (pbi->dec_tile_row == -1 && pbi->dec_tile_col == -1) - // TODO(debargha): Fix encoder side mv range, so that we can use the - // inner border extension. As of now use the larger extension. - // aom_extend_frame_inner_borders(cm->frame_to_show, av1_num_planes(cm)); - aom_extend_frame_borders(cm->frame_to_show, av1_num_planes(cm)); } pbi->hold_ref_buf = 0;