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