Some cosmetics in histogram.c

Change-Id: I5d5872a793759fad593dba88c3f593f72b328b0c
This commit is contained in:
Urvang Joshi 2012-04-27 19:37:50 +00:00 committed by James Zern
parent ada6ff77df
commit 41b5c8ff71
3 changed files with 94 additions and 112 deletions

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;
} }