Commit c0cea7f3 authored by Rupert Swarbrick's avatar Rupert Swarbrick Committed by Debargha Mukherjee

Refactor iteration over neighbours for OBMC

There are six pieces of code in reconinter.c and two in rdopt.c which
iterate over the blocks along the top or left edge of the current
block for OBMC. Before this patch, each bit of code has its own
implementation of the iteration, which is reasonably finicky to get

This patch factors out that logic into a pair of helpers
(foreach_overlappable_nb_above and foreach_overlappable_nb_left). The
functions take a "fun" parameter, which contains the loop body. Note
that the iteration is too complicated for us to be able to define a
macro that could be used like

  FOREACH_NB_ABOVE(rel_pos, nb_size, nb_mi) { ... }

While C's syntax doesn't seem to let you do that, once the compiler's
optimisation pass is done inlining everything, the results are
essentially the same.

The iteration logic is also slightly generalised: the old code checked
whether a block was shorter or narrower than 8 pixels by comparing a
block size with BLOCK_8X8. This doesn't work when you have a 4x16 or
16x4 block because e.g. BLOCK_16X4 is not less than BLOCK_8X8. This
generalisation is (unsurprisingly) needed in order to to support 16x4
or 4x16 blocks.

This patch doesn't address the CONFIG_NCOBMC functions in reconinter.c
that do prediction from right and bottom edges.

This patch shouldn't affect the generated bitstream in any way: the
code is supposed to be equivalent.

Change-Id: I9e5a116b012c18645604a7d98fb98be99697d363
parent bdb7e9cd
......@@ -118,6 +118,10 @@ AV1_COMMON_SRCS-yes += common/cfl.h
AV1_COMMON_SRCS-yes += common/cfl.c
ifeq ($(CONFIG_MOTION_VAR),yes)
AV1_COMMON_SRCS-yes += common/obmc.h
ifeq ($(CONFIG_PVQ),yes)
# PVQ from daala
AV1_COMMON_SRCS-yes += common/pvq.c
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at
#ifndef AV1_COMMON_OBMC_H_
#define AV1_COMMON_OBMC_H_
typedef void (*overlappable_nb_visitor_t)(MACROBLOCKD *xd, int rel_mi_pos,
uint8_t nb_mi_size, MODE_INFO *nb_mi,
void *fun_ctxt);
static INLINE void foreach_overlappable_nb_above(const AV1_COMMON *cm,
MACROBLOCKD *xd, int mi_col,
int nb_max,
overlappable_nb_visitor_t fun,
void *fun_ctxt) {
if (!xd->up_available) return;
int nb_count = 0;
// prev_row_mi points into the mi array, starting at the beginning of the
// previous row.
MODE_INFO **prev_row_mi = xd->mi - mi_col - 1 * xd->mi_stride;
const int end_col = AOMMIN(mi_col + xd->n8_w, cm->mi_cols);
uint8_t mi_step;
for (int above_mi_col = mi_col; above_mi_col < end_col && nb_count < nb_max;
above_mi_col += mi_step) {
MODE_INFO **above_mi = prev_row_mi + above_mi_col;
mi_step = mi_size_wide[above_mi[0]->mbmi.sb_type];
// If we're considering a block with width 4, it should be treated as
// half of a pair of blocks with chroma information in the second. Move
// above_mi_col back to the start of the pair if needed, set above_mbmi
// to point at the block with chroma information, and set mi_step to 2 to
// step over the entire pair at the end of the iteration.
if (mi_step == 1) {
above_mi_col &= ~1;
above_mi = prev_row_mi + above_mi_col + 1;
mi_step = 2;
MB_MODE_INFO *above_mbmi = &above_mi[0]->mbmi;
if (is_neighbor_overlappable(above_mbmi)) {
fun(xd, above_mi_col - mi_col, AOMMIN(xd->n8_w, mi_step), *above_mi,
static INLINE void foreach_overlappable_nb_left(const AV1_COMMON *cm,
MACROBLOCKD *xd, int mi_row,
int nb_max,
overlappable_nb_visitor_t fun,
void *fun_ctxt) {
if (!xd->left_available) return;
int nb_count = 0;
// prev_col_mi points into the mi array, starting at the top of the
// previous column
MODE_INFO **prev_col_mi = xd->mi - 1 - mi_row * xd->mi_stride;
const int end_row = AOMMIN(mi_row + xd->n8_h, cm->mi_rows);
uint8_t mi_step;
for (int left_mi_row = mi_row; left_mi_row < end_row && nb_count < nb_max;
left_mi_row += mi_step) {
MODE_INFO **left_mi = prev_col_mi + left_mi_row * xd->mi_stride;
mi_step = mi_size_high[left_mi[0]->mbmi.sb_type];
if (mi_step == 1) {
left_mi_row &= ~1;
left_mi = prev_col_mi + (left_mi_row + 1) * xd->mi_stride;
mi_step = 2;
MB_MODE_INFO *left_mbmi = &left_mi[0]->mbmi;
if (is_neighbor_overlappable(left_mbmi)) {
fun(xd, left_mi_row - mi_row, AOMMIN(xd->n8_h, mi_step), *left_mi,
#endif // AV1_COMMON_OBMC_H_
This diff is collapsed.
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