Palette: Don't store tokens for pixels outside image boundary.

If part of a block falls outside right and/or bottom image boundary,
then only store tokens for the part of it within the boundary.

Also, consider only the part of the block within the boundary when
calculating the number of colors in the image, deciding the base
colors for palette, RD calculation etc.

The part of color map corresponding to pixels outside the image
boundary is padded with color indices copied from same row/column.
This behavior is similar to how pixels outside the boundary are padded.

For screen_content set, this is improves compression performance by
0.038 overall. One clip, in particular, has a significant gain of 0.8.

Change-Id: I745ca032f313c5041aacc98c03ae4bfc33d840de
This commit is contained in:
Urvang Joshi 2017-01-10 13:22:09 -08:00
Родитель e1c0929f51
Коммит 56ba91bbe4
8 изменённых файлов: 125 добавлений и 54 удалений

Просмотреть файл

@ -1073,6 +1073,34 @@ static INLINE int is_neighbor_overlappable(const MB_MODE_INFO *mbmi) {
#endif // CONFIG_MOTION_VAR
#endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
// Returns sub-sampled dimensions of the given block.
// The output values for 'rows_within_bounds' and 'cols_within_bounds' will
// differ from 'height' and 'width' when part of the block is outside the right
// and/or bottom image boundary.
static INLINE void av1_get_block_dimensions(BLOCK_SIZE bsize, int plane,
const MACROBLOCKD *xd, int *width,
int *height,
int *rows_within_bounds,
int *cols_within_bounds) {
const int block_height = block_size_high[bsize];
const int block_width = block_size_wide[bsize];
const int block_rows = (xd->mb_to_bottom_edge >= 0)
? block_height
: (xd->mb_to_bottom_edge >> 3) + block_height;
const int block_cols = (xd->mb_to_right_edge >= 0)
? block_width
: (xd->mb_to_right_edge >> 3) + block_width;
const struct macroblockd_plane *const pd = &xd->plane[plane];
assert(IMPLIES(plane == PLANE_TYPE_Y, pd->subsampling_x == 0));
assert(IMPLIES(plane == PLANE_TYPE_Y, pd->subsampling_y == 0));
assert(block_width >= block_cols);
assert(block_height >= block_rows);
if (width) *width = block_width >> pd->subsampling_x;
if (height) *height = block_height >> pd->subsampling_y;
if (rows_within_bounds) *rows_within_bounds = block_rows >> pd->subsampling_y;
if (cols_within_bounds) *cols_within_bounds = block_cols >> pd->subsampling_x;
}
#ifdef __cplusplus
} // extern "C"
#endif

Просмотреть файл

@ -1266,9 +1266,9 @@ static const aom_prob
#endif // CONFIG_LOOP_RESTORATION
#if CONFIG_PALETTE
int av1_get_palette_color_context(const uint8_t *color_map, int cols, int r,
int c, int n, uint8_t *color_order,
int *color_idx) {
int av1_get_palette_color_context(const uint8_t *color_map, int width,
int stride, int r, int c, int palette_size,
uint8_t *color_order, int *color_idx) {
int i;
// The +10 below should not be needed. But we get a warning "array subscript
// is above array bounds [-Werror=array-bounds]" without it, possibly due to
@ -1279,15 +1279,15 @@ int av1_get_palette_color_context(const uint8_t *color_map, int cols, int r,
int color_ctx;
int color_neighbors[4];
int inverse_color_order[PALETTE_MAX_SIZE];
assert(n <= PALETTE_MAX_SIZE);
assert(palette_size <= PALETTE_MAX_SIZE);
// Get color indices of neighbors.
color_neighbors[0] = (c - 1 >= 0) ? color_map[r * cols + c - 1] : -1;
color_neighbors[0] = (c - 1 >= 0) ? color_map[r * stride + c - 1] : -1;
color_neighbors[1] =
(c - 1 >= 0 && r - 1 >= 0) ? color_map[(r - 1) * cols + c - 1] : -1;
color_neighbors[2] = (r - 1 >= 0) ? color_map[(r - 1) * cols + c] : -1;
color_neighbors[3] = (r - 1 >= 0 && c + 1 <= cols - 1)
? color_map[(r - 1) * cols + c + 1]
(c - 1 >= 0 && r - 1 >= 0) ? color_map[(r - 1) * stride + c - 1] : -1;
color_neighbors[2] = (r - 1 >= 0) ? color_map[(r - 1) * stride + c] : -1;
color_neighbors[3] = (r - 1 >= 0 && c + 1 <= width - 1)
? color_map[(r - 1) * stride + c + 1]
: -1;
for (i = 0; i < PALETTE_MAX_SIZE; ++i) {
@ -1306,7 +1306,7 @@ int av1_get_palette_color_context(const uint8_t *color_map, int cols, int r,
int max = scores[i];
int max_idx = i;
int j;
for (j = i + 1; j < n; ++j) {
for (j = i + 1; j < palette_size; ++j) {
if (scores[j] > max) {
max = scores[j];
max_idx = j;
@ -1343,7 +1343,7 @@ int av1_get_palette_color_context(const uint8_t *color_map, int cols, int r,
}
if (color_idx != NULL) {
*color_idx = inverse_color_order[color_map[r * cols + c]];
*color_idx = inverse_color_order[color_map[r * stride + c]];
}
return color_ctx;
}

Просмотреть файл

@ -436,9 +436,12 @@ static INLINE int av1_ceil_log2(int n) {
}
#if CONFIG_PALETTE
int av1_get_palette_color_context(const uint8_t *color_map, int cols, int r,
int c, int n, uint8_t *color_order,
int *color_idx);
// Returns the context for palette color index at row 'r' and column 'c',
// along with the 'color_order' of neighbors and the 'color_idx'.
// The 'color_map' is a 2D array with the given 'width' and 'stride'.
int av1_get_palette_color_context(const uint8_t *color_map, int width,
int stride, int r, int c, int palette_size,
uint8_t *color_order, int *color_idx);
#endif // CONFIG_PALETTE
#ifdef __cplusplus

Просмотреть файл

@ -1925,7 +1925,7 @@ static void predict_square_intra_block(const MACROBLOCKD *xd, int wpx, int hpx,
const int bs = tx_size_wide[tx_size];
const int stride = wpx;
int r, c;
uint8_t *map = NULL;
const uint8_t *const map = xd->plane[plane != 0].color_index_map;
#if CONFIG_AOM_HIGHBITDEPTH
uint16_t *palette = xd->mi[0]->mbmi.palette_mode_info.palette_colors +
plane * PALETTE_MAX_SIZE;
@ -1934,8 +1934,6 @@ static void predict_square_intra_block(const MACROBLOCKD *xd, int wpx, int hpx,
plane * PALETTE_MAX_SIZE;
#endif // CONFIG_AOM_HIGHBITDEPTH
map = xd->plane[plane != 0].color_index_map;
#if CONFIG_AOM_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst);

Просмотреть файл

@ -314,28 +314,35 @@ void av1_decode_palette_tokens(MACROBLOCKD *const xd, int plane,
aom_reader *r) {
const MODE_INFO *const mi = xd->mi[0];
const MB_MODE_INFO *const mbmi = &mi->mbmi;
const BLOCK_SIZE bsize = mbmi->sb_type;
const int rows =
(block_size_high[bsize]) >> (xd->plane[plane != 0].subsampling_y);
const int cols =
(block_size_wide[bsize]) >> (xd->plane[plane != 0].subsampling_x);
uint8_t color_order[PALETTE_MAX_SIZE];
const int n = mbmi->palette_mode_info.palette_size[plane != 0];
const int n = mbmi->palette_mode_info.palette_size[plane];
int i, j;
uint8_t *color_map = xd->plane[plane != 0].color_index_map;
uint8_t *const color_map = xd->plane[plane].color_index_map;
const aom_prob(*const prob)[PALETTE_COLOR_CONTEXTS][PALETTE_COLORS - 1] =
plane ? av1_default_palette_uv_color_prob
: av1_default_palette_y_color_prob;
int plane_block_width, plane_block_height, rows, cols;
av1_get_block_dimensions(mbmi->sb_type, plane, xd, &plane_block_width,
&plane_block_height, &rows, &cols);
assert(plane == 0 || plane == 1);
for (i = 0; i < rows; ++i) {
for (j = (i == 0 ? 1 : 0); j < cols; ++j) {
const int color_ctx = av1_get_palette_color_context(color_map, cols, i, j,
n, color_order, NULL);
const int color_ctx = av1_get_palette_color_context(
color_map, plane_block_width, cols, i, j, n, color_order, NULL);
const int color_idx = aom_read_tree(r, av1_palette_color_tree[n - 2],
prob[n - 2][color_ctx], ACCT_STR);
assert(color_idx >= 0 && color_idx < n);
color_map[i * cols + j] = color_order[color_idx];
color_map[i * plane_block_width + j] = color_order[color_idx];
}
memset(color_map + i * plane_block_width + cols,
color_map[i * plane_block_width + cols - 1],
(plane_block_width - cols)); // Copy last column to extra columns.
}
// Copy last row to extra rows.
for (i = rows; i < plane_block_height; ++i) {
memcpy(color_map + i * plane_block_width,
color_map + (rows - 1) * plane_block_width, plane_block_width);
}
}
#endif // CONFIG_PALETTE

Просмотреть файл

@ -1938,14 +1938,14 @@ static void write_tokens_b(AV1_COMP *cpi, const TileInfo *const tile,
#if !CONFIG_PVQ
#if CONFIG_PALETTE
for (plane = 0; plane <= 1; ++plane) {
if (m->mbmi.palette_mode_info.palette_size[plane] > 0) {
const int rows =
block_size_high[m->mbmi.sb_type] >> (xd->plane[plane].subsampling_y);
const int cols =
block_size_wide[m->mbmi.sb_type] >> (xd->plane[plane].subsampling_x);
const uint8_t palette_size_plane =
m->mbmi.palette_mode_info.palette_size[plane];
if (palette_size_plane > 0) {
int rows, cols;
av1_get_block_dimensions(m->mbmi.sb_type, plane, xd, NULL, NULL, &rows,
&cols);
assert(*tok < tok_end);
pack_palette_tokens(w, tok, m->mbmi.palette_mode_info.palette_size[plane],
rows * cols - 1);
pack_palette_tokens(w, tok, palette_size_plane, rows * cols - 1);
assert(*tok < tok_end + m->mbmi.skip);
}
}

Просмотреть файл

@ -2270,6 +2270,30 @@ static int64_t intra_model_yrd(const AV1_COMP *const cpi, MACROBLOCK *const x,
}
#if CONFIG_PALETTE
// Extends 'color_map' array from 'orig_width x orig_height' to 'new_width x
// new_height'. Extra rows and columns are filled in by copying last valid
// row/column.
static void extend_palette_color_map(uint8_t *const color_map, int orig_width,
int orig_height, int new_width,
int new_height) {
int j;
assert(new_width >= orig_width);
assert(new_height >= orig_height);
if (new_width == orig_width && new_height == orig_height) return;
for (j = orig_height - 1; j >= 0; --j) {
memmove(color_map + j * new_width, color_map + j * orig_width, orig_width);
// Copy last column to extra columns.
memset(color_map + j * new_width + orig_width,
color_map[j * new_width + orig_width - 1], new_width - orig_width);
}
// Copy last row to extra rows.
for (j = orig_height; j < new_height; ++j) {
memcpy(color_map + j * new_width, color_map + (orig_height - 1) * new_width,
new_width);
}
}
static int rd_pick_palette_intra_sby(const AV1_COMP *const cpi, MACROBLOCK *x,
BLOCK_SIZE bsize, int palette_ctx,
int dc_mode_cost, MB_MODE_INFO *best_mbmi,
@ -2281,12 +2305,13 @@ static int rd_pick_palette_intra_sby(const AV1_COMP *const cpi, MACROBLOCK *x,
MACROBLOCKD *const xd = &x->e_mbd;
MODE_INFO *const mic = xd->mi[0];
MB_MODE_INFO *const mbmi = &mic->mbmi;
const int rows = block_size_high[bsize];
const int cols = block_size_wide[bsize];
int this_rate, colors, n;
const int src_stride = x->plane[0].src.stride;
const uint8_t *const src = x->plane[0].src.buf;
uint8_t *const color_map = xd->plane[0].color_index_map;
int block_width, block_height, rows, cols;
av1_get_block_dimensions(bsize, 0, xd, &block_width, &block_height, &rows,
&cols);
assert(cpi->common.allow_screen_content_tools);
@ -2373,6 +2398,8 @@ static int rd_pick_palette_intra_sby(const AV1_COMP *const cpi, MACROBLOCK *x,
pmi->palette_size[0] = k;
av1_calc_indices(data, centroids, color_map, rows * cols, k, 1);
extend_palette_color_map(color_map, cols, rows, block_width,
block_height);
palette_mode_cost =
dc_mode_cost + cpi->common.bit_depth * k * av1_cost_bit(128, 0) +
cpi->palette_y_size_cost[bsize - BLOCK_8X8][k - 2] +
@ -2384,7 +2411,7 @@ static int rd_pick_palette_intra_sby(const AV1_COMP *const cpi, MACROBLOCK *x,
for (j = (i == 0 ? 1 : 0); j < cols; ++j) {
int color_idx;
const int color_ctx = av1_get_palette_color_context(
color_map, cols, i, j, k, color_order, &color_idx);
color_map, cols, block_width, i, j, k, color_order, &color_idx);
assert(color_idx >= 0 && color_idx < k);
palette_mode_cost +=
cpi->palette_y_color_cost[k - 2][color_ctx][color_idx];
@ -2405,7 +2432,7 @@ static int rd_pick_palette_intra_sby(const AV1_COMP *const cpi, MACROBLOCK *x,
if (this_rd < *best_rd) {
*best_rd = this_rd;
memcpy(best_palette_color_map, color_map,
rows * cols * sizeof(color_map[0]));
block_width * block_height * sizeof(color_map[0]));
*best_mbmi = *mbmi;
rate_overhead = this_rate - tokenonly_rd_stats.rate;
if (rate) *rate = this_rate;
@ -4339,8 +4366,6 @@ static void rd_pick_palette_intra_sbuv(
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
const BLOCK_SIZE bsize = mbmi->sb_type;
const int rows = block_size_high[bsize] >> (xd->plane[1].subsampling_y);
const int cols = block_size_wide[bsize] >> (xd->plane[1].subsampling_x);
int this_rate;
int64_t this_rd;
int colors_u, colors_v, colors;
@ -4349,7 +4374,9 @@ static void rd_pick_palette_intra_sbuv(
const uint8_t *const src_v = x->plane[2].src.buf;
uint8_t *const color_map = xd->plane[1].color_index_map;
RD_STATS tokenonly_rd_stats;
int plane_block_width, plane_block_height, rows, cols;
av1_get_block_dimensions(bsize, 1, xd, &plane_block_width,
&plane_block_height, &rows, &cols);
if (rows * cols > PALETTE_MAX_BLOCK_SIZE) return;
#if CONFIG_FILTER_INTRA
@ -4437,6 +4464,8 @@ static void rd_pick_palette_intra_sbuv(
centroids[i * 2 + 1] = lb_v + (2 * i + 1) * (ub_v - lb_v) / n / 2;
}
av1_k_means(data, centroids, color_map, rows * cols, n, 2, max_itr);
extend_palette_color_map(color_map, cols, rows, plane_block_width,
plane_block_height);
pmi->palette_size[1] = n;
for (i = 1; i < 3; ++i) {
for (j = 0; j < n; ++j) {
@ -4464,8 +4493,9 @@ static void rd_pick_palette_intra_sbuv(
for (i = 0; i < rows; ++i) {
for (j = (i == 0 ? 1 : 0); j < cols; ++j) {
int color_idx;
const int color_ctx = av1_get_palette_color_context(
color_map, cols, i, j, n, color_order, &color_idx);
const int color_ctx =
av1_get_palette_color_context(color_map, cols, plane_block_width,
i, j, n, color_order, &color_idx);
assert(color_idx >= 0 && color_idx < n);
this_rate += cpi->palette_uv_color_cost[n - 2][color_ctx][color_idx];
}
@ -4476,7 +4506,8 @@ static void rd_pick_palette_intra_sbuv(
*best_rd = this_rd;
*palette_mode_info = *pmi;
memcpy(best_palette_color_map, color_map,
rows * cols * sizeof(best_palette_color_map[0]));
plane_block_width * plane_block_height *
sizeof(best_palette_color_map[0]));
*mode_selected = DC_PRED;
*rate = this_rate;
*distortion = tokenonly_rd_stats.dist;
@ -9039,8 +9070,6 @@ static void restore_uv_color_map(const AV1_COMP *const cpi, MACROBLOCK *x) {
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
const BLOCK_SIZE bsize = mbmi->sb_type;
const int rows = block_size_high[bsize] >> (xd->plane[1].subsampling_y);
const int cols = block_size_wide[bsize] >> (xd->plane[1].subsampling_x);
int src_stride = x->plane[1].src.stride;
const uint8_t *const src_u = x->plane[1].src.buf;
const uint8_t *const src_v = x->plane[2].src.buf;
@ -9052,6 +9081,9 @@ static void restore_uv_color_map(const AV1_COMP *const cpi, MACROBLOCK *x) {
const uint16_t *const src_u16 = CONVERT_TO_SHORTPTR(src_u);
const uint16_t *const src_v16 = CONVERT_TO_SHORTPTR(src_v);
#endif // CONFIG_AOM_HIGHBITDEPTH
int plane_block_width, plane_block_height, rows, cols;
av1_get_block_dimensions(bsize, 1, xd, &plane_block_width,
&plane_block_height, &rows, &cols);
(void)cpi;
for (r = 0; r < rows; ++r) {
@ -9078,6 +9110,8 @@ static void restore_uv_color_map(const AV1_COMP *const cpi, MACROBLOCK *x) {
av1_calc_indices(data, centroids, color_map, rows * cols,
pmi->palette_size[1], 2);
extend_palette_color_map(color_map, cols, rows, plane_block_width,
plane_block_height);
}
#endif // CONFIG_PALETTE

Просмотреть файл

@ -391,25 +391,26 @@ void av1_tokenize_palette_sb(const AV1_COMP *cpi,
const MACROBLOCK *const x = &td->mb;
const MACROBLOCKD *const xd = &x->e_mbd;
const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
const uint8_t *const color_map = xd->plane[plane != 0].color_index_map;
const uint8_t *const color_map = xd->plane[plane].color_index_map;
const PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
const int n = pmi->palette_size[plane != 0];
const int n = pmi->palette_size[plane];
int i, j;
int this_rate = 0;
uint8_t color_order[PALETTE_MAX_SIZE];
const int rows =
block_size_high[bsize] >> (xd->plane[plane != 0].subsampling_y);
const int cols =
block_size_wide[bsize] >> (xd->plane[plane != 0].subsampling_x);
const aom_prob(*const probs)[PALETTE_COLOR_CONTEXTS][PALETTE_COLORS - 1] =
plane == 0 ? av1_default_palette_y_color_prob
: av1_default_palette_uv_color_prob;
int plane_block_width, rows, cols;
av1_get_block_dimensions(bsize, plane, xd, &plane_block_width, NULL, &rows,
&cols);
assert(plane == 0 || plane == 1);
for (i = 0; i < rows; ++i) {
for (j = (i == 0 ? 1 : 0); j < cols; ++j) {
int color_new_idx;
const int color_ctx = av1_get_palette_color_context(
color_map, cols, i, j, n, color_order, &color_new_idx);
const int color_ctx =
av1_get_palette_color_context(color_map, cols, plane_block_width, i,
j, n, color_order, &color_new_idx);
assert(color_new_idx >= 0 && color_new_idx < n);
if (dry_run == DRY_RUN_COSTCOEFFS)
this_rate += cpi->palette_y_color_cost[n - 2][color_ctx][color_new_idx];