
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
382 lines
9.6 KiB
C
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
|