Commit 33567b21 authored by hui su's avatar hui su Committed by Hui Su

Palette: use color cache to compress base colors

Get a list of palette base colors that are used in the above and
left blocks, referred to as "color cache". For each cache color,
signal if it is present in current block's palette, so that we
don't need to transmit their raw values.

When palette-delta-encoding is enabled, compression is improved
by 2% on keyframe and 1% overall for the screen_content testset.

Change-Id: I4cb027f1904aa9d0ab1c8f00ea9ee34bf5f16234
parent d1fb415f
......@@ -153,6 +153,53 @@ int av1_get_pred_context_intra_interp(const MACROBLOCKD *xd) {
#endif // CONFIG_INTRA_INTERP
#endif // CONFIG_EXT_INTRA
#if CONFIG_PALETTE && CONFIG_PALETTE_DELTA_ENCODING
int av1_get_palette_cache(const MODE_INFO *above_mi, const MODE_INFO *left_mi,
int plane, uint16_t *cache) {
int above_n = 0, left_n = 0;
if (above_mi)
above_n = above_mi->mbmi.palette_mode_info.palette_size[plane != 0];
if (left_mi)
left_n = left_mi->mbmi.palette_mode_info.palette_size[plane != 0];
if (above_n == 0 && left_n == 0) return 0;
int above_idx = plane * PALETTE_MAX_SIZE;
int left_idx = plane * PALETTE_MAX_SIZE;
int n = 0;
#if CONFIG_HIGHBITDEPTH
const uint16_t *above_colors =
above_mi->mbmi.palette_mode_info.palette_colors;
const uint16_t *left_colors = left_mi->mbmi.palette_mode_info.palette_colors;
#else
const uint8_t *above_colors = above_mi->mbmi.palette_mode_info.palette_colors;
const uint8_t *left_colors = left_mi->mbmi.palette_mode_info.palette_colors;
#endif // CONFIG_HIGHBITDEPTH
// Merge the sorted lists of base colors from above and left to get
// combined sorted color cache.
while (above_n > 0 && left_n > 0) {
uint16_t v_above = above_colors[above_idx];
uint16_t v_left = left_colors[left_idx];
if (v_left < v_above) {
if (n == 0 || v_left != cache[n - 1]) cache[n++] = v_left;
++left_idx, --left_n;
} else {
if (n == 0 || v_above != cache[n - 1]) cache[n++] = v_above;
++above_idx, --above_n;
if (v_left == v_above) ++left_idx, --left_n;
}
}
while (above_n-- > 0) {
uint16_t val = above_colors[above_idx++];
if (n == 0 || val != cache[n - 1]) cache[n++] = val;
}
while (left_n-- > 0) {
uint16_t val = left_colors[left_idx++];
if (n == 0 || val != cache[n - 1]) cache[n++] = val;
}
assert(n <= 2 * PALETTE_MAX_SIZE);
return n;
}
#endif // CONFIG_PALETTE && CONFIG_PALETTE_DELTA_ENCODING
// The mode info data structure has a one element border above and to the
// left of the entries corresponding to real macroblocks.
// The prediction flags in these dummy entries are initialized to 0.
......
......@@ -79,6 +79,15 @@ int av1_get_pred_context_intra_interp(const MACROBLOCKD *xd);
#endif // CONFIG_INTRA_INTERP
#endif // CONFIG_EXT_INTRA
#if CONFIG_PALETTE && CONFIG_PALETTE_DELTA_ENCODING
// Get a list of palette base colors that are used in the above and left blocks,
// referred to as "color cache". The return value is the number of colors in the
// cache (<= 2 * PALETTE_MAX_SIZE). The color values are stored in "cache"
// in ascending order.
int av1_get_palette_cache(const MODE_INFO *above_mi, const MODE_INFO *left_mi,
int plane, uint16_t *cache);
#endif // CONFIG_PALETTE && CONFIG_PALETTE_DELTA_ENCODING
int av1_get_intra_inter_context(const MACROBLOCKD *xd);
static INLINE aom_prob av1_get_intra_inter_prob(const AV1_COMMON *cm,
......
......@@ -645,6 +645,110 @@ static int read_skip(AV1_COMMON *cm, const MACROBLOCKD *xd, int segment_id,
}
#if CONFIG_PALETTE
#if CONFIG_PALETTE_DELTA_ENCODING
#if CONFIG_HIGHBITDEPTH
static int uint16_compare(const void *a, const void *b) {
const uint16 va = *(const uint16 *)a;
const uint16 vb = *(const uint16 *)b;
return va - vb;
}
#else
static int uint8_compare(const void *a, const void *b) {
const uint8_t va = *(const uint8_t *)a;
const uint8_t vb = *(const uint8_t *)b;
return va - vb;
}
#endif // CONFIG_HIGHBITDEPTH
static void read_palette_colors_y(MACROBLOCKD *const xd, int bit_depth,
PALETTE_MODE_INFO *const pmi, aom_reader *r) {
uint16_t color_cache[2 * PALETTE_MAX_SIZE];
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
const int n_cache = av1_get_palette_cache(above_mi, left_mi, 0, color_cache);
const int n = pmi->palette_size[0];
int idx = 0;
for (int i = 0; i < n_cache && idx < n; ++i)
if (aom_read_bit(r, ACCT_STR)) pmi->palette_colors[idx++] = color_cache[i];
if (idx < n) {
pmi->palette_colors[idx++] = aom_read_literal(r, bit_depth, ACCT_STR);
if (idx < n) {
const int min_bits = bit_depth - 3;
int bits = min_bits + aom_read_literal(r, 2, ACCT_STR);
int range = (1 << bit_depth) - pmi->palette_colors[idx - 1] - 1;
for (; idx < n; ++idx) {
const int delta = aom_read_literal(r, bits, ACCT_STR) + 1;
pmi->palette_colors[idx] = pmi->palette_colors[idx - 1] + delta;
range -= delta;
bits = AOMMIN(bits, av1_ceil_log2(range));
}
}
}
#if CONFIG_HIGHBITDEPTH
qsort(pmi->palette_colors, n, sizeof(pmi->palette_colors[0]), uint16_compare);
#else
qsort(pmi->palette_colors, n, sizeof(pmi->palette_colors[0]), uint8_compare);
#endif // CONFIG_HIGHBITDEPTH
}
static void read_palette_colors_uv(MACROBLOCKD *const xd, int bit_depth,
PALETTE_MODE_INFO *const pmi,
aom_reader *r) {
const int n = pmi->palette_size[1];
// U channel colors.
uint16_t color_cache[2 * PALETTE_MAX_SIZE];
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
const int n_cache = av1_get_palette_cache(above_mi, left_mi, 1, color_cache);
int idx = PALETTE_MAX_SIZE;
for (int i = 0; i < n_cache && idx < PALETTE_MAX_SIZE + n; ++i)
if (aom_read_bit(r, ACCT_STR)) pmi->palette_colors[idx++] = color_cache[i];
if (idx < PALETTE_MAX_SIZE + n) {
pmi->palette_colors[idx++] = aom_read_literal(r, bit_depth, ACCT_STR);
if (idx < PALETTE_MAX_SIZE + n) {
const int min_bits = bit_depth - 3;
int bits = min_bits + aom_read_literal(r, 2, ACCT_STR);
int range = (1 << bit_depth) - pmi->palette_colors[idx - 1];
for (; idx < PALETTE_MAX_SIZE + n; ++idx) {
const int delta = aom_read_literal(r, bits, ACCT_STR);
pmi->palette_colors[idx] = pmi->palette_colors[idx - 1] + delta;
range -= delta;
bits = AOMMIN(bits, av1_ceil_log2(range));
}
}
}
#if CONFIG_HIGHBITDEPTH
qsort(pmi->palette_colors + PALETTE_MAX_SIZE, n,
sizeof(pmi->palette_colors[0]), uint16_compare);
#else
qsort(pmi->palette_colors + PALETTE_MAX_SIZE, n,
sizeof(pmi->palette_colors[0]), uint8_compare);
#endif // CONFIG_HIGHBITDEPTH
// V channel colors.
if (aom_read_bit(r, ACCT_STR)) { // Delta encoding.
const int min_bits_v = bit_depth - 4;
const int max_val = 1 << bit_depth;
int bits = min_bits_v + aom_read_literal(r, 2, ACCT_STR);
pmi->palette_colors[2 * PALETTE_MAX_SIZE] =
aom_read_literal(r, bit_depth, ACCT_STR);
for (int i = 1; i < n; ++i) {
int delta = aom_read_literal(r, bits, ACCT_STR);
if (delta && aom_read_bit(r, ACCT_STR)) delta = -delta;
int val = (int)pmi->palette_colors[2 * PALETTE_MAX_SIZE + i - 1] + delta;
if (val < 0) val += max_val;
if (val >= max_val) val -= max_val;
pmi->palette_colors[2 * PALETTE_MAX_SIZE + i] = val;
}
} else {
for (int i = 0; i < n; ++i) {
pmi->palette_colors[2 * PALETTE_MAX_SIZE + i] =
aom_read_literal(r, bit_depth, ACCT_STR);
}
}
}
#endif // CONFIG_PALETTE_DELTA_ENCODING
static void read_palette_mode_info(AV1_COMMON *const cm, MACROBLOCKD *const xd,
aom_reader *r) {
MODE_INFO *const mi = xd->mi[0];
......@@ -652,7 +756,7 @@ static void read_palette_mode_info(AV1_COMMON *const cm, MACROBLOCKD *const xd,
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
const BLOCK_SIZE bsize = mbmi->sb_type;
int i, n;
int n;
PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
if (mbmi->mode == DC_PRED) {
......@@ -673,16 +777,9 @@ static void read_palette_mode_info(AV1_COMMON *const cm, MACROBLOCKD *const xd,
2;
n = pmi->palette_size[0];
#if CONFIG_PALETTE_DELTA_ENCODING
const int min_bits = cm->bit_depth - 3;
int bits = min_bits + aom_read_literal(r, 2, ACCT_STR);
pmi->palette_colors[0] = aom_read_literal(r, cm->bit_depth, ACCT_STR);
for (i = 1; i < n; ++i) {
pmi->palette_colors[i] = pmi->palette_colors[i - 1] +
aom_read_literal(r, bits, ACCT_STR) + 1;
bits = AOMMIN(
bits, av1_ceil_log2((1 << cm->bit_depth) - pmi->palette_colors[i]));
}
read_palette_colors_y(xd, cm->bit_depth, pmi, r);
#else
int i;
for (i = 0; i < n; ++i)
pmi->palette_colors[i] = aom_read_literal(r, cm->bit_depth, ACCT_STR);
#endif // CONFIG_PALETTE_DELTA_ENCODING
......@@ -702,42 +799,9 @@ static void read_palette_mode_info(AV1_COMMON *const cm, MACROBLOCKD *const xd,
2;
n = pmi->palette_size[1];
#if CONFIG_PALETTE_DELTA_ENCODING
// U channel colors.
const int min_bits_u = cm->bit_depth - 3;
int bits = min_bits_u + aom_read_literal(r, 2, ACCT_STR);
pmi->palette_colors[PALETTE_MAX_SIZE] =
aom_read_literal(r, cm->bit_depth, ACCT_STR);
for (i = 1; i < n; ++i) {
pmi->palette_colors[PALETTE_MAX_SIZE + i] =
pmi->palette_colors[PALETTE_MAX_SIZE + i - 1] +
aom_read_literal(r, bits, ACCT_STR);
bits = AOMMIN(bits,
av1_ceil_log2(1 + (1 << cm->bit_depth) -
pmi->palette_colors[PALETTE_MAX_SIZE + i]));
}
// V channel colors.
if (aom_read_bit(r, ACCT_STR)) { // Delta encoding.
const int min_bits_v = cm->bit_depth - 4;
const int max_val = 1 << cm->bit_depth;
bits = min_bits_v + aom_read_literal(r, 2, ACCT_STR);
pmi->palette_colors[2 * PALETTE_MAX_SIZE] =
aom_read_literal(r, cm->bit_depth, ACCT_STR);
for (i = 1; i < n; ++i) {
int delta = aom_read_literal(r, bits, ACCT_STR);
if (delta && aom_read_bit(r, ACCT_STR)) delta = -delta;
int val =
(int)pmi->palette_colors[2 * PALETTE_MAX_SIZE + i - 1] + delta;
if (val < 0) val += max_val;
if (val >= max_val) val -= max_val;
pmi->palette_colors[2 * PALETTE_MAX_SIZE + i] = val;
}
} else {
for (i = 0; i < n; ++i) {
pmi->palette_colors[2 * PALETTE_MAX_SIZE + i] =
aom_read_literal(r, cm->bit_depth, ACCT_STR);
}
}
read_palette_colors_uv(xd, cm->bit_depth, pmi, r);
#else
int i;
for (i = 0; i < n; ++i) {
pmi->palette_colors[PALETTE_MAX_SIZE + i] =
aom_read_literal(r, cm->bit_depth, ACCT_STR);
......
......@@ -1421,30 +1421,67 @@ static void write_mb_interp_filter(AV1_COMP *cpi, const MACROBLOCKD *xd,
#if CONFIG_PALETTE
#if CONFIG_PALETTE_DELTA_ENCODING
// Write luma palette color values with delta encoding. Write the first value as
// literal, and the deltas between each value and the previous one. The luma
// palette is sorted so each delta is larger than 0.
static void write_palette_colors_y(const PALETTE_MODE_INFO *const pmi,
int bit_depth, aom_writer *w) {
const int n = pmi->palette_size[0];
int min_bits, i;
int bits = av1_get_palette_delta_bits_y(pmi, bit_depth, &min_bits);
// Transmit color values with delta encoding. Write the first value as
// literal, and the deltas between each value and the previous one. "min_val" is
// the smallest possible value of the deltas.
static void delta_encode_palette_colors(const int *colors, int num,
int bit_depth, int min_val,
aom_writer *w) {
if (num <= 0) return;
aom_write_literal(w, colors[0], bit_depth);
if (num == 1) return;
int max_delta = 0;
int deltas[PALETTE_MAX_SIZE];
memset(deltas, 0, sizeof(deltas));
for (int i = 1; i < num; ++i) {
const int delta = colors[i] - colors[i - 1];
deltas[i - 1] = delta;
assert(delta >= min_val);
if (delta > max_delta) max_delta = delta;
}
const int min_bits = bit_depth - 3;
int bits = AOMMAX(av1_ceil_log2(max_delta + 1 - min_val), min_bits);
int range = (1 << bit_depth) - colors[0] - min_val;
aom_write_literal(w, bits - min_bits, 2);
aom_write_literal(w, pmi->palette_colors[0], bit_depth);
for (i = 1; i < n; ++i) {
aom_write_literal(
w, pmi->palette_colors[i] - pmi->palette_colors[i - 1] - 1, bits);
bits =
AOMMIN(bits, av1_ceil_log2((1 << bit_depth) - pmi->palette_colors[i]));
for (int i = 0; i < num - 1; ++i) {
aom_write_literal(w, deltas[i] - min_val, bits);
range -= deltas[i];
bits = AOMMIN(bits, av1_ceil_log2(range));
}
}
// Write chroma palette color values. Use delta encoding for u channel as its
// palette is sorted. For v channel, either use delta encoding or transmit
// raw values directly, whichever costs less.
static void write_palette_colors_uv(const PALETTE_MODE_INFO *const pmi,
// Transmit luma palette color values. First signal if each color in the color
// cache is used. Those colors that are not in the cache are transmitted with
// delta encoding.
static void write_palette_colors_y(const MACROBLOCKD *const xd,
const PALETTE_MODE_INFO *const pmi,
int bit_depth, aom_writer *w) {
const int n = pmi->palette_size[0];
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
uint16_t color_cache[2 * PALETTE_MAX_SIZE];
const int n_cache = av1_get_palette_cache(above_mi, left_mi, 0, color_cache);
int out_cache_colors[PALETTE_MAX_SIZE];
uint8_t cache_color_found[2 * PALETTE_MAX_SIZE];
const int n_out_cache =
av1_index_color_cache(color_cache, n_cache, pmi->palette_colors, n,
cache_color_found, out_cache_colors);
int n_in_cache = 0;
for (int i = 0; i < n_cache && n_in_cache < n; ++i) {
const int found = cache_color_found[i];
aom_write_bit(w, found);
n_in_cache += found;
}
assert(n_in_cache + n_out_cache == n);
delta_encode_palette_colors(out_cache_colors, n_out_cache, bit_depth, 1, w);
}
// Write chroma palette color values. U channel is handled similarly to the luma
// channel. For v channel, either use delta encoding or transmit raw values
// directly, whichever costs less.
static void write_palette_colors_uv(const MACROBLOCKD *const xd,
const PALETTE_MODE_INFO *const pmi,
int bit_depth, aom_writer *w) {
int i;
const int n = pmi->palette_size[1];
#if CONFIG_HIGHBITDEPTH
const uint16_t *colors_u = pmi->palette_colors + PALETTE_MAX_SIZE;
......@@ -1454,15 +1491,23 @@ static void write_palette_colors_uv(const PALETTE_MODE_INFO *const pmi,
const uint8_t *colors_v = pmi->palette_colors + 2 * PALETTE_MAX_SIZE;
#endif // CONFIG_HIGHBITDEPTH
// U channel colors.
int min_bits_u = 0;
int bits_u = av1_get_palette_delta_bits_u(pmi, bit_depth, &min_bits_u);
aom_write_literal(w, bits_u - min_bits_u, 2);
aom_write_literal(w, colors_u[0], bit_depth);
for (i = 1; i < n; ++i) {
aom_write_literal(w, colors_u[i] - colors_u[i - 1], bits_u);
bits_u = AOMMIN(bits_u, av1_ceil_log2(1 + (1 << bit_depth) - colors_u[i]));
}
// V channel colors.
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
uint16_t color_cache[2 * PALETTE_MAX_SIZE];
const int n_cache = av1_get_palette_cache(above_mi, left_mi, 1, color_cache);
int out_cache_colors[PALETTE_MAX_SIZE];
uint8_t cache_color_found[2 * PALETTE_MAX_SIZE];
const int n_out_cache = av1_index_color_cache(
color_cache, n_cache, colors_u, n, cache_color_found, out_cache_colors);
int n_in_cache = 0;
for (int i = 0; i < n_cache && n_in_cache < n; ++i) {
const int found = cache_color_found[i];
aom_write_bit(w, found);
n_in_cache += found;
}
delta_encode_palette_colors(out_cache_colors, n_out_cache, bit_depth, 0, w);
// V channel colors. Don't use color cache as the colors are not sorted.
const int max_val = 1 << bit_depth;
int zero_count = 0, min_bits_v = 0;
int bits_v =
......@@ -1474,7 +1519,7 @@ static void write_palette_colors_uv(const PALETTE_MODE_INFO *const pmi,
aom_write_bit(w, 1);
aom_write_literal(w, bits_v - min_bits_v, 2);
aom_write_literal(w, colors_v[0], bit_depth);
for (i = 1; i < n; ++i) {
for (int i = 1; i < n; ++i) {
if (colors_v[i] == colors_v[i - 1]) { // No need to signal sign bit.
aom_write_literal(w, 0, bits_v);
continue;
......@@ -1491,7 +1536,7 @@ static void write_palette_colors_uv(const PALETTE_MODE_INFO *const pmi,
}
} else { // Transmit raw values.
aom_write_bit(w, 0);
for (i = 0; i < n; ++i) aom_write_literal(w, colors_v[i], bit_depth);
for (int i = 0; i < n; ++i) aom_write_literal(w, colors_v[i], bit_depth);
}
}
#endif // CONFIG_PALETTE_DELTA_ENCODING
......@@ -1521,7 +1566,7 @@ static void write_palette_mode_info(const AV1_COMMON *cm, const MACROBLOCKD *xd,
av1_default_palette_y_size_prob[bsize - BLOCK_8X8],
&palette_size_encodings[n - PALETTE_MIN_SIZE]);
#if CONFIG_PALETTE_DELTA_ENCODING
write_palette_colors_y(pmi, cm->bit_depth, w);
write_palette_colors_y(xd, pmi, cm->bit_depth, w);
#else
int i;
for (i = 0; i < n; ++i)
......@@ -1540,7 +1585,7 @@ static void write_palette_mode_info(const AV1_COMMON *cm, const MACROBLOCKD *xd,
av1_default_palette_uv_size_prob[bsize - BLOCK_8X8],
&palette_size_encodings[n - PALETTE_MIN_SIZE]);
#if CONFIG_PALETTE_DELTA_ENCODING
write_palette_colors_uv(pmi, cm->bit_depth, w);
write_palette_colors_uv(xd, pmi, cm->bit_depth, w);
#else
int i;
for (i = 0; i < n; ++i) {
......
......@@ -167,31 +167,62 @@ int av1_count_colors(const uint8_t *src, int stride, int rows, int cols) {
}
#if CONFIG_PALETTE_DELTA_ENCODING
int av1_get_palette_delta_bits_y(const PALETTE_MODE_INFO *const pmi,
int bit_depth, int *min_bits) {
const int n = pmi->palette_size[0];
int max_d = 0, i;
*min_bits = bit_depth - 3;
for (i = 1; i < n; ++i) {
const int delta = pmi->palette_colors[i] - pmi->palette_colors[i - 1];
assert(delta > 0);
if (delta > max_d) max_d = delta;
static int delta_encode_cost(const int *colors, int num, int bit_depth,
int min_val) {
if (num <= 0) return 0;
int bits_cost = bit_depth;
if (num == 1) return bits_cost;
bits_cost += 2;
int max_delta = 0;
int deltas[PALETTE_MAX_SIZE];
const int min_bits = bit_depth - 3;
for (int i = 1; i < num; ++i) {
const int delta = colors[i] - colors[i - 1];
deltas[i - 1] = delta;
assert(delta >= min_val);
if (delta > max_delta) max_delta = delta;
}
int bits_per_delta = AOMMAX(av1_ceil_log2(max_delta + 1 - min_val), min_bits);
int range = (1 << bit_depth) - colors[0] - min_val;
for (int i = 0; i < num - 1; ++i) {
bits_cost += bits_per_delta;
range -= deltas[i];
bits_per_delta = AOMMIN(bits_per_delta, av1_ceil_log2(range));
}
return AOMMAX(av1_ceil_log2(max_d), *min_bits);
return bits_cost;
}
int av1_get_palette_delta_bits_u(const PALETTE_MODE_INFO *const pmi,
int bit_depth, int *min_bits) {
const int n = pmi->palette_size[1];
int max_d = 0, i;
*min_bits = bit_depth - 3;
for (i = 1; i < n; ++i) {
const int delta = pmi->palette_colors[PALETTE_MAX_SIZE + i] -
pmi->palette_colors[PALETTE_MAX_SIZE + i - 1];
assert(delta >= 0);
if (delta > max_d) max_d = delta;
int av1_index_color_cache(uint16_t *color_cache, int n_cache,
const void *colors, int n_colors,
uint8_t *cache_color_found, int *out_cache_colors) {
#if CONFIG_HIGHBITDEPTH
const uint16_t *colors_in = (const uint16 *)colors;
#else
const uint8_t *colors_in = (const uint8_t *)colors;
#endif // CONFIG_HIGHBITDEPTH
if (n_cache <= 0) {
for (int i = 0; i < n_colors; ++i) out_cache_colors[i] = colors_in[i];
return n_colors;
}
return AOMMAX(av1_ceil_log2(max_d + 1), *min_bits);
memset(cache_color_found, 0, n_cache * sizeof(*cache_color_found));
int n_in_cache = 0;
int in_cache_flags[PALETTE_MAX_SIZE];
memset(in_cache_flags, 0, sizeof(in_cache_flags));
for (int i = 0; i < n_cache && n_in_cache < n_colors; ++i) {
for (int j = 0; j < n_colors; ++j) {
if (colors_in[j] == color_cache[i]) {
in_cache_flags[j] = 1;
cache_color_found[i] = 1;
++n_in_cache;
break;
}
}
}
int j = 0;
for (int i = 0; i < n_colors; ++i)
if (!in_cache_flags[i]) out_cache_colors[j++] = colors_in[i];
assert(j == n_colors - n_in_cache);
return j;
}
int av1_get_palette_delta_bits_v(const PALETTE_MODE_INFO *const pmi,
......@@ -199,10 +230,10 @@ int av1_get_palette_delta_bits_v(const PALETTE_MODE_INFO *const pmi,
int *min_bits) {
const int n = pmi->palette_size[1];
const int max_val = 1 << bit_depth;
int max_d = 0, i;
int max_d = 0;
*min_bits = bit_depth - 4;
*zero_count = 0;
for (i = 1; i < n; ++i) {
for (int i = 1; i < n; ++i) {
const int delta = pmi->palette_colors[2 * PALETTE_MAX_SIZE + i] -
pmi->palette_colors[2 * PALETTE_MAX_SIZE + i - 1];
const int v = abs(delta);
......@@ -215,26 +246,42 @@ int av1_get_palette_delta_bits_v(const PALETTE_MODE_INFO *const pmi,
#endif // CONFIG_PALETTE_DELTA_ENCODING
int av1_palette_color_cost_y(const PALETTE_MODE_INFO *const pmi,
#if CONFIG_PALETTE_DELTA_ENCODING
uint16_t *color_cache, int n_cache,
#endif // CONFIG_PALETTE_DELTA_ENCODING
int bit_depth) {
const int n = pmi->palette_size[0];
#if CONFIG_PALETTE_DELTA_ENCODING
int min_bits = 0;
const int bits = av1_get_palette_delta_bits_y(pmi, bit_depth, &min_bits);
return av1_cost_bit(128, 0) * (2 + bit_depth + bits * (n - 1));
int out_cache_colors[PALETTE_MAX_SIZE];
uint8_t cache_color_found[2 * PALETTE_MAX_SIZE];
const int n_out_cache =
av1_index_color_cache(color_cache, n_cache, pmi->palette_colors, n,
cache_color_found, out_cache_colors);
const int total_bits =
n_cache + delta_encode_cost(out_cache_colors, n_out_cache, bit_depth, 1);
return total_bits * av1_cost_bit(128, 0);
#else
return bit_depth * n * av1_cost_bit(128, 0);
#endif // CONFIG_PALETTE_DELTA_ENCODING
}
int av1_palette_color_cost_uv(const PALETTE_MODE_INFO *const pmi,
#if CONFIG_PALETTE_DELTA_ENCODING
uint16_t *color_cache, int n_cache,
#endif // CONFIG_PALETTE_DELTA_ENCODING
int bit_depth) {
const int n = pmi->palette_size[1];
#if CONFIG_PALETTE_DELTA_ENCODING
int cost = 0;
int total_bits = 0;
// U channel palette color cost.
int min_bits_u = 0;
const int bits_u = av1_get_palette_delta_bits_u(pmi, bit_depth, &min_bits_u);
cost += av1_cost_bit(128, 0) * (2 + bit_depth + bits_u * (n - 1));
int out_cache_colors[PALETTE_MAX_SIZE];
uint8_t cache_color_found[2 * PALETTE_MAX_SIZE];
const int n_out_cache = av1_index_color_cache(
color_cache, n_cache, pmi->palette_colors + PALETTE_MAX_SIZE, n,
cache_color_found, out_cache_colors);
total_bits +=
n_cache + delta_encode_cost(out_cache_colors, n_out_cache, bit_depth, 0);
// V channel palette color cost.
int zero_count = 0, min_bits_v = 0;
const int bits_v =
......@@ -242,8 +289,8 @@ int av1_palette_color_cost_uv(const PALETTE_MODE_INFO *const pmi,
const int bits_using_delta =
2 + bit_depth + (bits_v + 1) * (n - 1) - zero_count;
const int bits_using_raw = bit_depth * n;
cost += av1_cost_bit(128, 0) * (1 + AOMMIN(bits_using_delta, bits_using_raw));
return cost;
total_bits += 1 + AOMMIN(bits_using_delta, bits_using_raw);
return total_bits * av1_cost_bit(128, 0);
#else
return 2 * bit_depth * n * av1_cost_bit(128, 0);
#endif // CONFIG_PALETTE_DELTA_ENCODING
......
......@@ -45,13 +45,12 @@ int av1_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols,
#endif // CONFIG_HIGHBITDEPTH
#if CONFIG_PALETTE_DELTA_ENCODING
// Return the number of bits used to transmit each luma palette color delta.
int av1_get_palette_delta_bits_y(const PALETTE_MODE_INFO *const pmi,
int bit_depth, int *min_bits);
// Return the number of bits used to transmit each U palette color delta.
int av1_get_palette_delta_bits_u(const PALETTE_MODE_INFO *const pmi,
int bit_depth, int *min_bits);
// Given a color cache and a set of base colors, find if each cache color is
// present in the base colors, record the binary results in "cache_color_found".
// Record the colors that are not in the color cache in "out_cache_colors".
int av1_index_color_cache(uint16_t *color_cache, int n_cache,
const void *colors, int n_colors,
uint8_t *cache_color_found, int *out_cache_colors);
// Return the number of bits used to transmit each v palette color delta;
// assign zero_count with the number of deltas being 0.
......@@ -60,10 +59,17 @@ int av1_get_palette_delta_bits_v(const PALETTE_MODE_INFO *const pmi,
#endif // CONFIG_PALETTE_DELTA_ENCODING
// Return the rate cost for transmitting luma palette color values.
int av1_palette_color_cost_y(const PALETTE_MODE_INFO *const pmi, int bit_depth);
int av1_palette_color_cost_y(const PALETTE_MODE_INFO *const pmi,
#if CONFIG_PALETTE_DELTA_ENCODING
uint16_t *color_cache, int n_cache,
#endif // CONFIG_PALETTE_DELTA_ENCODING
int bit_depth);
// Return the rate cost for transmitting chroma palette color values.
int av1_palette_color_cost_uv(const PALETTE_MODE_INFO *const pmi,
#if CONFIG_PALETTE_DELTA_ENCODING
uint16_t *color_cache, int n_cache,
#endif // CONFIG_PALETTE_DELTA_ENCODING
int bit_depth);
#ifdef __cplusplus
......
......@@ -2429,6 +2429,28 @@ static void extend_palette_color_map(uint8_t *const color_map, int orig_width,
}
}
#if CONFIG_PALETTE_DELTA_ENCODING
// Bias toward using colors in the cache.
// TODO(huisu): Try other schemes to improve compression.
static void optimize_palette_colors(uint16_t *color_cache, int n_cache,