vpx/vp9/common/vp9_palette.c
Julia Robson 84d0da63d0 Palette high bit depth functionality
Changes to allow high bit depth and palette to be enabled at the
same time by using a 16 bit (instead of 8bit) palette when high
bit depth is enabled and modifying related functions accordingly.

Change-Id: I97d30b4d9338d3a51db02c94bc568eba60a8905d
2015-06-22 18:53:34 +01:00

382 lines
9.6 KiB
C

/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "vp9/common/vp9_palette.h"
#if CONFIG_PALETTE
void vp9_insertion_sort(double *data, int n) {
int i, j, k;
double val;
if (n <= 1)
return;
for (i = 1; i < n; i++) {
val = data[i];
j = 0;
while (val > data[j] && j < i)
j++;
if (j == i)
continue;
for (k = i; k > j; k--)
data[k] = data[k - 1];
data[j] = val;
}
}
int vp9_count_colors(const uint8_t *src, int stride, int rows, int cols) {
int n = 0, r, c, i, val_count[256];
uint8_t val;
vpx_memset(val_count, 0, sizeof(val_count));
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
val = src[r * stride + c];
val_count[val]++;
}
}
for (i = 0; i < 256; i++) {
if (val_count[i]) {
n++;
}
}
return n;
}
#if CONFIG_VP9_HIGHBITDEPTH
int vp9_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols,
int bit_depth) {
int n = 0, r, c, i;
uint16_t val;
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
int* val_count = vpx_calloc(1 << bit_depth, sizeof(*val_count));
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
val = src[r * stride + c];
val_count[val]++;
}
}
for (i = 0; i < (1 << bit_depth); i++) {
if (val_count[i]) {
n++;
}
}
vpx_free(val_count);
return n;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_palette_color_insertion(uint16_t *old_colors, int *m, int *count,
const MB_MODE_INFO *mbmi) {
const uint16_t *new_colors = mbmi->palette_literal_colors;
uint16_t val;
#else
void vp9_palette_color_insertion(uint8_t *old_colors, int *m, int *count,
const MB_MODE_INFO *mbmi) {
const uint8_t *new_colors = mbmi->palette_literal_colors;
uint8_t val;
#endif // CONFIG_VP9_HIGHBITDEPTH
int k = *m, n = mbmi->palette_literal_size;
int i, j, l, min_idx = -1;
if (mbmi->palette_indexed_size > 0) {
for (i = 0; i < mbmi->palette_indexed_size; i++)
count[mbmi->palette_indexed_colors[i]] +=
(8 - abs(mbmi->palette_color_delta[i]));
}
i = 0;
while (i < k) {
count[i] -= 1;
i++;
}
if (n <= 0)
return;
for (i = 0; i < n; i++) {
val = new_colors[i];
j = 0;
while (val != old_colors[j] && j < k)
j++;
if (j < k && val == old_colors[j]) {
count[j] += 8;
continue;
}
if (k + 1 > PALETTE_BUF_SIZE) {
min_idx = 0;
for (l = 1; l < k; l++)
if (count[l] < count[min_idx])
min_idx = l;
old_colors[min_idx] = val;
count[min_idx] = 8;
} else {
old_colors[k] = val;
count[k] = 8;
k++;
}
}
*m = k;
}
#if CONFIG_VP9_HIGHBITDEPTH
int vp9_palette_color_lookup(uint16_t *dic, int n, uint16_t val, int bits) {
#else
int vp9_palette_color_lookup(uint8_t *dic, int n, uint8_t val, int bits) {
#endif // CONFIG_VP9_HIGHBITDEPTH
int j, min, arg_min = 0, i = 1;
if (n < 1)
return -1;
min = abs(val - dic[0]);
arg_min = 0;
while (i < n) {
j = abs(val - dic[i]);
if (j < min) {
min = j;
arg_min = i;
}
i++;
}
if (min < (1 << bits))
return arg_min;
else
return -1;
}
int vp9_ceil_log2(int n) {
int i = 1, p = 2;
while (p < n) {
i++;
p = p << 1;
}
return i;
}
static double calc_dist(const double *p1, const double *p2, int dim) {
double dist = 0;
int i = 0;
for (i = 0; i < dim; i++) {
dist = dist + (p1[i] - p2[i]) * (p1[i] - p2[i]);
}
return dist;
}
void vp9_calc_indices(const double *data, const double *centroids, int *indices,
int n, int k, int dim) {
int i, j;
double min_dist, this_dist;
for (i = 0; i < n; i++) {
min_dist = calc_dist(data + i * dim, centroids, dim);
indices[i] = 0;
for (j = 1; j < k; j++) {
this_dist = calc_dist(data + i * dim, centroids + j * dim, dim);
if (this_dist < min_dist) {
min_dist = this_dist;
indices[i] = j;
}
}
}
}
static void calc_centroids(const double *data, double *centroids,
const int *indices, int n, int k, int dim) {
int i, j, index;
int count[256];
srand((unsigned int) data[0]);
vpx_memset(count, 0, sizeof(count[0]) * k);
vpx_memset(centroids, 0, sizeof(centroids[0]) * k * dim);
for (i = 0; i < n; i++) {
index = indices[i];
count[index]++;
for (j = 0; j < dim; j++) {
centroids[index * dim + j] += data[i * dim + j];
}
}
for (i = 0; i < k; i++) {
if (count[i] == 0) {
vpx_memcpy(centroids + i * dim, data + (rand() % n) * dim,
sizeof(centroids[0]) * dim);
} else {
const double norm = 1.0 / count[i];
for (j = 0; j < dim; j++)
centroids[i * dim + j] *= norm;
}
}
}
static double calc_total_dist(const double *data, const double *centroids,
const int *indices, int n, int k, int dim) {
double dist = 0;
int i;
(void) k;
for (i = 0; i < n; i++) {
dist += calc_dist(data + i * dim, centroids + indices[i] * dim, dim);
}
return dist;
}
int vp9_k_means(const double *data, double *centroids, int *indices,
int n, int k, int dim, int max_itr) {
int i = 0;
int *pre_indices;
double pre_total_dist, cur_total_dist;
double pre_centroids[256];
pre_indices = vpx_memalign(16, n * sizeof(indices[0]));
vp9_calc_indices(data, centroids, indices, n, k, dim);
pre_total_dist = calc_total_dist(data, centroids, indices, n, k, dim);
vpx_memcpy(pre_centroids, centroids, sizeof(pre_centroids[0]) * k * dim);
vpx_memcpy(pre_indices, indices, sizeof(pre_indices[0]) * n);
while (i < max_itr) {
calc_centroids(data, centroids, indices, n, k, dim);
vp9_calc_indices(data, centroids, indices, n, k, dim);
cur_total_dist = calc_total_dist(data, centroids, indices, n, k, dim);
if (cur_total_dist > pre_total_dist) {
vpx_memcpy(centroids, pre_centroids, sizeof(pre_centroids[0]) * k * dim);
vpx_memcpy(indices, pre_indices, sizeof(pre_indices[0]) * n);
break;
}
if (!memcmp(centroids, pre_centroids, sizeof(pre_centroids[0]) * k * dim))
break;
vpx_memcpy(pre_centroids, centroids, sizeof(pre_centroids[0]) * k * dim);
vpx_memcpy(pre_indices, indices, sizeof(pre_indices[0]) * n);
pre_total_dist = cur_total_dist;
i++;
}
vpx_free(pre_indices);
return i;
}
void vp9_update_palette_counts(FRAME_COUNTS *counts, const MB_MODE_INFO *mbmi,
BLOCK_SIZE bsize, int palette_ctx) {
int idx = bsize - BLOCK_8X8;
counts->y_palette_enabled[idx][palette_ctx][mbmi->palette_enabled[0]]++;
counts->uv_palette_enabled[mbmi->palette_enabled[0]]
[mbmi->palette_enabled[1]]++;
if (mbmi->palette_enabled[0])
counts->y_palette_size[idx][mbmi->palette_size[0] - 2]++;
if (mbmi->palette_enabled[1])
counts->uv_palette_size[idx][mbmi->palette_size[1] - 2]++;
}
static const int palette_color_context_lookup[PALETTE_COLOR_CONTEXTS] = {
3993, 4235, 4378, 4380, // (3, 0, 0, 0), (3, 2, 0, 0),
// (3, 3, 2, 0), (3, 3, 2, 2),
5720, 6655, 7018, 7040, // (4, 3, 3, 0), (5, 0, 0, 0),
// (5, 3, 0, 0), (5, 3, 2, 0),
7260, 8228, 8250, 8470, // (5, 5, 0, 0), (6, 2, 0, 0),
// (6, 2, 2, 0), (6, 4, 0, 0),
9680, 10648, 10890, 13310 // (7, 3, 0, 0), (8, 0, 0, 0),
// (8, 2, 0, 0), (10, 0, 0, 0)
};
int vp9_get_palette_color_context(const uint8_t *color_map, int cols,
int r, int c, int n, int *color_order) {
int i, j, max, max_idx, temp;
int scores[PALETTE_MAX_SIZE + 10];
int weights[4] = {3, 2, 3, 2};
int color_ctx = 0;
int color_neighbors[4];
assert(n <= PALETTE_MAX_SIZE);
if (c - 1 >= 0)
color_neighbors[0] = color_map[r * cols + c - 1];
else
color_neighbors[0] = -1;
if (c - 1 >= 0 && r - 1 >= 0)
color_neighbors[1] = color_map[(r - 1) * cols + c - 1];
else
color_neighbors[1] = -1;
if (r - 1 >= 0)
color_neighbors[2] = color_map[(r - 1) * cols + c];
else
color_neighbors[2] = -1;
if (r - 1 >= 0 && c + 1 <= cols - 1)
color_neighbors[3] = color_map[(r - 1) * cols + c + 1];
else
color_neighbors[3] = -1;
for (i = 0; i < PALETTE_MAX_SIZE; i++)
color_order[i] = i;
memset(scores, 0, PALETTE_MAX_SIZE * sizeof(scores[0]));
for (i = 0; i < 4; i++) {
if (color_neighbors[i] >= 0)
scores[color_neighbors[i]] += weights[i];
}
for (i = 0; i < 4; i++) {
max = scores[i];
max_idx = i;
j = i + 1;
while (j < n) {
if (scores[j] > max) {
max = scores[j];
max_idx = j;
}
j++;
}
if (max_idx != i) {
temp = scores[i];
scores[i] = scores[max_idx];
scores[max_idx] = temp;
temp = color_order[i];
color_order[i] = color_order[max_idx];
color_order[max_idx] = temp;
}
}
for (i = 0; i < 4; i++)
color_ctx = color_ctx * 11 + scores[i];
for (i = 0; i < PALETTE_COLOR_CONTEXTS; i++)
if (color_ctx == palette_color_context_lookup[i]) {
color_ctx = i;
break;
}
return color_ctx;
}
#endif // CONFIG_PALETTE