mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01:00
Some cosmetics in histogram.c
Change-Id: I5d5872a793759fad593dba88c3f593f72b328b0c
This commit is contained in:
parent
ada6ff77df
commit
41b5c8ff71
@ -195,40 +195,29 @@ double VP8LHistogramEstimateBitsHeader(const VP8LHistogram* const p) {
|
||||
HuffmanCost(&p->distance_[0], DISTANCE_CODES_MAX);
|
||||
}
|
||||
|
||||
static int HistogramBuildImage(int xsize, int ysize,
|
||||
int histobits, int palettebits,
|
||||
static int HistogramBuildImage(int xsize, int histo_bits, int cache_bits,
|
||||
const VP8LBackwardRefs* const backward_refs,
|
||||
VP8LHistogram*** const image_arg,
|
||||
int* const image_size) {
|
||||
int histo_xsize = histobits ? (xsize + (1 << histobits) - 1) >> histobits : 1;
|
||||
int histo_ysize = histobits ? (ysize + (1 << histobits) - 1) >> histobits : 1;
|
||||
VP8LHistogram** const image,
|
||||
int image_size) {
|
||||
int i;
|
||||
const int histo_xsize =
|
||||
histo_bits ? (xsize + (1 << histo_bits) - 1) >> histo_bits : 1;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
VP8LHistogram** image;
|
||||
*image_arg = NULL;
|
||||
*image_size = histo_xsize * histo_ysize;
|
||||
image = (VP8LHistogram**)calloc(*image_size, sizeof(*image));
|
||||
if (image == NULL) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < *image_size; ++i) {
|
||||
for (i = 0; i < image_size; ++i) {
|
||||
image[i] = (VP8LHistogram*)malloc(sizeof(*image[i]));
|
||||
if (!image[i]) {
|
||||
if (image[i] == NULL) {
|
||||
int k;
|
||||
for (k = 0; k < *image_size; ++k) {
|
||||
free(image[k]);
|
||||
}
|
||||
free(image);
|
||||
for (k = 0; k < i; ++k) free(image[k]);
|
||||
return 0;
|
||||
}
|
||||
VP8LHistogramInit(image[i], palettebits);
|
||||
VP8LHistogramInit(image[i], cache_bits);
|
||||
}
|
||||
// x and y trace the position in the image.
|
||||
for (i = 0; i < backward_refs->size; ++i) {
|
||||
const PixOrCopy v = backward_refs->refs[i];
|
||||
const int ix =
|
||||
histobits ? (y >> histobits) * histo_xsize + (x >> histobits) : 0;
|
||||
histo_bits ? (y >> histo_bits) * histo_xsize + (x >> histo_bits) : 0;
|
||||
VP8LHistogramAddSinglePixOrCopy(image[ix], v);
|
||||
x += PixOrCopyLength(&v);
|
||||
while (x >= xsize) {
|
||||
@ -236,83 +225,72 @@ static int HistogramBuildImage(int xsize, int ysize,
|
||||
++y;
|
||||
}
|
||||
}
|
||||
*image_arg = image;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int HistogramCombine(VP8LHistogram** const in, int in_size, int quality,
|
||||
VP8LHistogram*** const out_arg,
|
||||
int* const out_size) {
|
||||
static int HistogramCombine(VP8LHistogram** const in, int in_size,
|
||||
int num_pairs, VP8LHistogram** const out,
|
||||
int* const out_size_arg) {
|
||||
int ok = 0;
|
||||
int i;
|
||||
unsigned int seed = 0;
|
||||
int tries_with_no_success = 0;
|
||||
int inner_iters = 10 + quality / 2;
|
||||
int iter;
|
||||
double* bit_costs = (double*)malloc(in_size * sizeof(*bit_costs));
|
||||
VP8LHistogram** out = (VP8LHistogram**)calloc(in_size, sizeof(*out));
|
||||
*out_arg = out;
|
||||
*out_size = in_size;
|
||||
if (bit_costs == NULL || out == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
// Copy
|
||||
const int outer_iters = in_size * 3;
|
||||
double* const bit_costs = (double*)malloc(in_size * sizeof(*bit_costs));
|
||||
// TODO(urvang): 'bit_cost' should be part of VP8LHistogram.
|
||||
VP8LHistogram* const combo = (VP8LHistogram*)malloc(sizeof(*combo));
|
||||
int out_size = in_size;
|
||||
if (bit_costs == NULL || out == NULL || combo == NULL) goto End;
|
||||
|
||||
// Copy histogram 'in' to 'out'.
|
||||
for (i = 0; i < in_size; ++i) {
|
||||
VP8LHistogram* new_histo = (VP8LHistogram*)malloc(sizeof(*new_histo));
|
||||
if (new_histo == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
*new_histo = *(in[i]);
|
||||
out[i] = new_histo;
|
||||
VP8LHistogram* const temp = (VP8LHistogram*)malloc(sizeof(*temp));
|
||||
if (temp == NULL) goto End;
|
||||
*temp = *(in[i]);
|
||||
out[i] = temp;
|
||||
bit_costs[i] = VP8LHistogramEstimateBits(out[i]);
|
||||
}
|
||||
// Collapse similar histograms.
|
||||
for (iter = 0; iter < in_size * 3 && *out_size >= 2; ++iter) {
|
||||
double best_val = 0;
|
||||
int best_ix0 = 0;
|
||||
int best_ix1 = 0;
|
||||
// Try a few times.
|
||||
int k;
|
||||
for (k = 0; k < inner_iters; ++k) {
|
||||
// Choose two, build a combo out of them.
|
||||
double cost_val;
|
||||
VP8LHistogram* combo;
|
||||
int ix0 = rand_r(&seed) % *out_size;
|
||||
int ix1;
|
||||
int diff = ((k & 7) + 1) % (*out_size - 1);
|
||||
if (diff >= 3) {
|
||||
diff = rand_r(&seed) % (*out_size - 1);
|
||||
}
|
||||
ix1 = (ix0 + diff + 1) % *out_size;
|
||||
if (ix0 == ix1) {
|
||||
|
||||
// Collapse similar histograms in 'out'.
|
||||
for (i = 0; i < outer_iters && out_size >= 2; ++i) {
|
||||
// We pick the best pair to be combined out of 'inner_iters' pairs.
|
||||
double best_cost_diff = 0;
|
||||
int best_idx1 = 0;
|
||||
int best_idx2 = 0;
|
||||
int j;
|
||||
for (j = 0; j < num_pairs; ++j) {
|
||||
double curr_cost_diff;
|
||||
// Choose two histograms at random and try to combine them.
|
||||
const int idx1 = rand_r(&seed) % out_size;
|
||||
const int tmp = ((j & 7) + 1) % (out_size - 1);
|
||||
const int diff = (tmp < 3) ? tmp : rand_r(&seed) % (out_size - 1);
|
||||
const int idx2 = (idx1 + diff + 1) % out_size;
|
||||
if (idx1 == idx2) {
|
||||
continue;
|
||||
}
|
||||
combo = (VP8LHistogram*)malloc(sizeof(*combo));
|
||||
if (combo == NULL) {
|
||||
goto Error;
|
||||
*combo = *out[idx1];
|
||||
VP8LHistogramAdd(combo, out[idx2]);
|
||||
// Calculate cost reduction on combining.
|
||||
curr_cost_diff =
|
||||
VP8LHistogramEstimateBits(combo) - bit_costs[idx1] - bit_costs[idx2];
|
||||
if (best_cost_diff > curr_cost_diff) {
|
||||
best_cost_diff = curr_cost_diff;
|
||||
best_idx1 = idx1;
|
||||
best_idx2 = idx2;
|
||||
}
|
||||
*combo = *out[ix0];
|
||||
VP8LHistogramAdd(combo, out[ix1]);
|
||||
cost_val =
|
||||
VP8LHistogramEstimateBits(combo) - bit_costs[ix0] - bit_costs[ix1];
|
||||
if (best_val > cost_val) {
|
||||
best_val = cost_val;
|
||||
best_ix0 = ix0;
|
||||
best_ix1 = ix1;
|
||||
}
|
||||
free(combo);
|
||||
}
|
||||
if (best_val < 0.0) {
|
||||
VP8LHistogramAdd(out[best_ix0], out[best_ix1]);
|
||||
bit_costs[best_ix0] =
|
||||
best_val + bit_costs[best_ix0] + bit_costs[best_ix1];
|
||||
// Erase (*out)[best_ix1]
|
||||
free(out[best_ix1]);
|
||||
memmove(&out[best_ix1], &out[best_ix1 + 1],
|
||||
(*out_size - best_ix1 - 1) * sizeof(out[0]));
|
||||
memmove(&bit_costs[best_ix1], &bit_costs[best_ix1 + 1],
|
||||
(*out_size - best_ix1 - 1) * sizeof(bit_costs[0]));
|
||||
--(*out_size);
|
||||
|
||||
if (best_cost_diff < 0.0) {
|
||||
// Combine this pair and store the combined histogram at 'best_idx1'.
|
||||
VP8LHistogramAdd(out[best_idx1], out[best_idx2]);
|
||||
bit_costs[best_idx1] =
|
||||
best_cost_diff + bit_costs[best_idx1] + bit_costs[best_idx2];
|
||||
free(out[best_idx2]);
|
||||
memmove(&out[best_idx2], &out[best_idx2 + 1],
|
||||
(out_size - best_idx2 - 1) * sizeof(*out));
|
||||
memmove(&bit_costs[best_idx2], &bit_costs[best_idx2 + 1],
|
||||
(out_size - best_idx2 - 1) * sizeof(*bit_costs));
|
||||
--out_size;
|
||||
tries_with_no_success = 0;
|
||||
}
|
||||
if (++tries_with_no_success >= 50) {
|
||||
@ -320,16 +298,17 @@ static int HistogramCombine(VP8LHistogram** const in, int in_size, int quality,
|
||||
}
|
||||
}
|
||||
ok = 1;
|
||||
Error:
|
||||
End:
|
||||
free(bit_costs);
|
||||
free(combo);
|
||||
if (!ok) {
|
||||
if (out) {
|
||||
int i;
|
||||
for (i = 0; i < *out_size; ++i) {
|
||||
free(out[i]);
|
||||
}
|
||||
if (out != NULL) {
|
||||
for (i = 0; i < out_size; ++i) free(out[i]);
|
||||
free(out);
|
||||
}
|
||||
*out_size_arg = 0;
|
||||
} else {
|
||||
*out_size_arg = out_size;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@ -407,44 +386,46 @@ static int HistogramRefine(VP8LHistogram** const raw, int raw_size,
|
||||
|
||||
int VP8LGetHistImageSymbols(int xsize, int ysize,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int quality, int histogram_bits,
|
||||
int quality, int histo_bits,
|
||||
int cache_bits,
|
||||
VP8LHistogram*** const histogram_image,
|
||||
VP8LHistogram** const histogram_image,
|
||||
int* const histogram_image_size,
|
||||
uint32_t* const histogram_symbols) {
|
||||
// Build histogram image.
|
||||
int ok = 0;
|
||||
int i;
|
||||
int histogram_image_raw_size;
|
||||
VP8LHistogram** histogram_image_raw = NULL;
|
||||
const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1;
|
||||
const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1;
|
||||
const int num_histo_pairs = 10 + quality / 2; // For HistogramCombine().
|
||||
const int histo_image_raw_size = histo_xsize * histo_ysize;
|
||||
VP8LHistogram** const histo_image_raw =
|
||||
(VP8LHistogram**)calloc(histo_image_raw_size, sizeof(*histo_image_raw));
|
||||
if (histo_image_raw == NULL) return 0;
|
||||
|
||||
*histogram_image = NULL;
|
||||
if (!HistogramBuildImage(xsize, ysize, histogram_bits, cache_bits, refs,
|
||||
&histogram_image_raw,
|
||||
&histogram_image_raw_size)) {
|
||||
// Build histogram image.
|
||||
if (!HistogramBuildImage(xsize, histo_bits, cache_bits, refs,
|
||||
histo_image_raw, histo_image_raw_size)) {
|
||||
goto Error;
|
||||
}
|
||||
// Collapse similar histograms.
|
||||
if (!HistogramCombine(histogram_image_raw, histogram_image_raw_size,
|
||||
quality, histogram_image, histogram_image_size)) {
|
||||
if (!HistogramCombine(histo_image_raw, histo_image_raw_size, num_histo_pairs,
|
||||
histogram_image, histogram_image_size)) {
|
||||
goto Error;
|
||||
}
|
||||
// Refine histogram image.
|
||||
for (i = 0; i < histogram_image_raw_size; ++i) {
|
||||
for (i = 0; i < histo_image_raw_size; ++i) {
|
||||
histogram_symbols[i] = -1;
|
||||
}
|
||||
if (!HistogramRefine(histogram_image_raw, histogram_image_raw_size,
|
||||
histogram_symbols,
|
||||
*histogram_image, *histogram_image_size)) {
|
||||
if (!HistogramRefine(histo_image_raw, histo_image_raw_size, histogram_symbols,
|
||||
histogram_image, *histogram_image_size)) {
|
||||
goto Error;
|
||||
}
|
||||
ok = 1;
|
||||
|
||||
Error:
|
||||
if (!ok) {
|
||||
VP8LDeleteHistograms(*histogram_image, *histogram_image_size);
|
||||
VP8LDeleteHistograms(histogram_image, *histogram_image_size);
|
||||
}
|
||||
VP8LDeleteHistograms(histogram_image_raw, histogram_image_raw_size);
|
||||
VP8LDeleteHistograms(histo_image_raw, histo_image_raw_size);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ int VP8LGetHistImageSymbols(int xsize, int ysize,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int quality, int histogram_bits,
|
||||
int cache_bits,
|
||||
VP8LHistogram*** histogram_image,
|
||||
VP8LHistogram** const histogram_image,
|
||||
int* const histogram_image_size,
|
||||
uint32_t* const histogram_symbols);
|
||||
|
||||
|
@ -652,7 +652,6 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
int cache_bits, int histogram_bits) {
|
||||
int i;
|
||||
int ok = 0;
|
||||
int histogram_image_size;
|
||||
int write_histogram_image;
|
||||
int* bit_lengths_sizes = NULL;
|
||||
uint8_t** bit_lengths = NULL;
|
||||
@ -662,12 +661,14 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
const int color_cache_size = use_color_cache ? (1 << cache_bits) : 0;
|
||||
const int histogram_image_xysize = VP8LSubSampleSize(width, histogram_bits) *
|
||||
VP8LSubSampleSize(height, histogram_bits);
|
||||
VP8LHistogram** histogram_image;
|
||||
VP8LHistogram** histogram_image =
|
||||
(VP8LHistogram**)calloc(histogram_image_xysize, sizeof(*histogram_image));
|
||||
int histogram_image_size;
|
||||
VP8LBackwardRefs refs;
|
||||
const size_t histo_size = histogram_image_xysize * sizeof(uint32_t);
|
||||
uint32_t* const histogram_symbols = (uint32_t*)calloc(1, histo_size);
|
||||
|
||||
if (histogram_symbols == NULL) goto Error;
|
||||
if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
|
||||
|
||||
// Calculate backward references from ARGB image.
|
||||
if (!GetBackwardReferences(width, height, argb, quality,
|
||||
@ -678,7 +679,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
// Build histogram image & symbols from backward references.
|
||||
if (!VP8LGetHistImageSymbols(width, height, &refs,
|
||||
quality, histogram_bits, cache_bits,
|
||||
&histogram_image, &histogram_image_size,
|
||||
histogram_image, &histogram_image_size,
|
||||
histogram_symbols)) {
|
||||
goto Error;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user