mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
Merge "rewrite the bin_map clustering to use less memory"
This commit is contained in:
commit
a977b4b513
@ -450,33 +450,23 @@ static void HistogramCopyAndAnalyze(
|
|||||||
// Partition histograms to different entropy bins for three dominant (literal,
|
// Partition histograms to different entropy bins for three dominant (literal,
|
||||||
// red and blue) symbol costs and compute the histogram aggregate bit_cost.
|
// red and blue) symbol costs and compute the histogram aggregate bit_cost.
|
||||||
static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
|
static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
|
||||||
int16_t* const bin_map, int low_effort) {
|
uint16_t* const bin_map,
|
||||||
|
int low_effort) {
|
||||||
int i;
|
int i;
|
||||||
VP8LHistogram** const histograms = image_histo->histograms;
|
VP8LHistogram** const histograms = image_histo->histograms;
|
||||||
const int histo_size = image_histo->size;
|
const int histo_size = image_histo->size;
|
||||||
const int bin_depth = histo_size + 1;
|
|
||||||
DominantCostRange cost_range;
|
DominantCostRange cost_range;
|
||||||
DominantCostRangeInit(&cost_range);
|
DominantCostRangeInit(&cost_range);
|
||||||
|
|
||||||
// Analyze the dominant (literal, red and blue) entropy costs.
|
// Analyze the dominant (literal, red and blue) entropy costs.
|
||||||
for (i = 0; i < histo_size; ++i) {
|
for (i = 0; i < histo_size; ++i) {
|
||||||
VP8LHistogram* const histo = histograms[i];
|
UpdateDominantCostRange(histograms[i], &cost_range);
|
||||||
UpdateDominantCostRange(histo, &cost_range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bin-hash histograms on three of the dominant (literal, red and blue)
|
// bin-hash histograms on three of the dominant (literal, red and blue)
|
||||||
// symbol costs.
|
// symbol costs and store the resulting bin_id for each histogram.
|
||||||
for (i = 0; i < histo_size; ++i) {
|
for (i = 0; i < histo_size; ++i) {
|
||||||
const VP8LHistogram* const histo = histograms[i];
|
bin_map[i] = GetHistoBinIndex(histograms[i], &cost_range, low_effort);
|
||||||
const int bin_id = GetHistoBinIndex(histo, &cost_range, low_effort);
|
|
||||||
const int bin_offset = bin_id * bin_depth;
|
|
||||||
// bin_map[n][0] for every bin 'n' maintains the counter for the number of
|
|
||||||
// histograms in that bin.
|
|
||||||
// Get and increment the num_histos in that bin.
|
|
||||||
const int num_histos = ++bin_map[bin_offset];
|
|
||||||
assert(bin_offset + num_histos < bin_depth * BIN_SIZE);
|
|
||||||
// Add histogram i'th index at num_histos (last) position in the bin_map.
|
|
||||||
bin_map[bin_offset + num_histos] = i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,19 +490,21 @@ static void HistogramCompactBins(VP8LHistogramSet* const image_histo) {
|
|||||||
static VP8LHistogram* HistogramCombineEntropyBin(
|
static VP8LHistogram* HistogramCombineEntropyBin(
|
||||||
VP8LHistogramSet* const image_histo,
|
VP8LHistogramSet* const image_histo,
|
||||||
VP8LHistogram* cur_combo,
|
VP8LHistogram* cur_combo,
|
||||||
int16_t* const bin_map, int bin_depth, int num_bins,
|
uint16_t* const bin_map, int bin_map_size, int num_bins,
|
||||||
double combine_cost_factor, int low_effort) {
|
double combine_cost_factor, int low_effort) {
|
||||||
int bin_id;
|
|
||||||
VP8LHistogram** const histograms = image_histo->histograms;
|
VP8LHistogram** const histograms = image_histo->histograms;
|
||||||
|
int bin_id;
|
||||||
|
|
||||||
for (bin_id = 0; bin_id < num_bins; ++bin_id) {
|
for (bin_id = 0; bin_id < num_bins; ++bin_id) {
|
||||||
const int bin_offset = bin_id * bin_depth;
|
|
||||||
const int num_histos = bin_map[bin_offset];
|
|
||||||
const int idx1 = bin_map[bin_offset + 1];
|
|
||||||
int num_combine_failures = 0;
|
int num_combine_failures = 0;
|
||||||
int n;
|
int idx1, idx2;
|
||||||
for (n = 2; n <= num_histos; ++n) {
|
for (idx1 = 0; idx1 < bin_map_size; ++idx1) {
|
||||||
const int idx2 = bin_map[bin_offset + n];
|
if (bin_map[idx1] == bin_id) break;
|
||||||
|
}
|
||||||
|
if (idx1 == bin_map_size) continue; // no histo with this bin_id
|
||||||
|
for (idx2 = idx1 + 1; idx2 < bin_map_size; ++idx2) {
|
||||||
|
if (bin_map[idx2] != bin_id) continue;
|
||||||
|
// try to merge #idx2 into #idx1 (both share the same bin_id)
|
||||||
if (low_effort) {
|
if (low_effort) {
|
||||||
// Merge all histograms with the same bin index, irrespective of cost of
|
// Merge all histograms with the same bin index, irrespective of cost of
|
||||||
// the merged histograms.
|
// the merged histograms.
|
||||||
@ -870,30 +862,17 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
|||||||
const int image_histo_raw_size = histo_xsize * histo_ysize;
|
const int image_histo_raw_size = histo_xsize * histo_ysize;
|
||||||
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
|
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
|
||||||
|
|
||||||
// The bin_map for every bin follows following semantics:
|
|
||||||
// bin_map[n][0] = num_histo; // The number of histograms in that bin.
|
|
||||||
// bin_map[n][1] = index of first histogram in that bin;
|
|
||||||
// bin_map[n][num_histo] = index of last histogram in that bin;
|
|
||||||
// bin_map[n][num_histo + 1] ... bin_map[n][bin_depth - 1] = unused indices.
|
|
||||||
const int bin_depth = image_histo_raw_size + 1;
|
|
||||||
int16_t* bin_map = NULL;
|
|
||||||
VP8LHistogramSet* const orig_histo =
|
VP8LHistogramSet* const orig_histo =
|
||||||
VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits);
|
VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits);
|
||||||
VP8LHistogram* cur_combo;
|
VP8LHistogram* cur_combo;
|
||||||
|
// Don't attempt linear bin-partition heuristic for
|
||||||
|
// histograms of small sizes (as bin_map will be very sparse) and
|
||||||
|
// maximum quality q==100 (to preserve the compression gains at that level).
|
||||||
const int entropy_combine =
|
const int entropy_combine =
|
||||||
(orig_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
|
(orig_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
|
||||||
|
|
||||||
if (orig_histo == NULL) goto Error;
|
if (orig_histo == NULL) goto Error;
|
||||||
|
|
||||||
// Don't attempt linear bin-partition heuristic for:
|
|
||||||
// histograms of small sizes, as bin_map will be very sparse and;
|
|
||||||
// Maximum quality (q==100), to preserve the compression gains at that level.
|
|
||||||
if (entropy_combine) {
|
|
||||||
const int bin_map_size = bin_depth * entropy_combine_num_bins;
|
|
||||||
bin_map = (int16_t*)WebPSafeCalloc(bin_map_size, sizeof(*bin_map));
|
|
||||||
if (bin_map == NULL) goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the histograms from backward references.
|
// Construct the histograms from backward references.
|
||||||
HistogramBuild(xsize, histo_bits, refs, orig_histo);
|
HistogramBuild(xsize, histo_bits, refs, orig_histo);
|
||||||
// Copies the histograms and computes its bit_cost.
|
// Copies the histograms and computes its bit_cost.
|
||||||
@ -901,13 +880,20 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
|||||||
|
|
||||||
cur_combo = tmp_histos->histograms[1]; // pick up working slot
|
cur_combo = tmp_histos->histograms[1]; // pick up working slot
|
||||||
if (entropy_combine) {
|
if (entropy_combine) {
|
||||||
|
const int bin_map_size = orig_histo->size;
|
||||||
const double combine_cost_factor =
|
const double combine_cost_factor =
|
||||||
GetCombineCostFactor(image_histo_raw_size, quality);
|
GetCombineCostFactor(image_histo_raw_size, quality);
|
||||||
|
uint16_t* const bin_map =
|
||||||
|
(uint16_t*)WebPSafeCalloc(bin_map_size, sizeof(*bin_map));
|
||||||
|
if (bin_map == NULL) goto Error;
|
||||||
|
|
||||||
HistogramAnalyzeEntropyBin(orig_histo, bin_map, low_effort);
|
HistogramAnalyzeEntropyBin(orig_histo, bin_map, low_effort);
|
||||||
// Collapse histograms with similar entropy.
|
// Collapse histograms with similar entropy.
|
||||||
cur_combo = HistogramCombineEntropyBin(image_histo, cur_combo, bin_map,
|
cur_combo = HistogramCombineEntropyBin(image_histo, cur_combo,
|
||||||
bin_depth, entropy_combine_num_bins,
|
bin_map, bin_map_size,
|
||||||
|
entropy_combine_num_bins,
|
||||||
combine_cost_factor, low_effort);
|
combine_cost_factor, low_effort);
|
||||||
|
WebPSafeFree(bin_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't combine the histograms using stochastic and greedy heuristics for
|
// Don't combine the histograms using stochastic and greedy heuristics for
|
||||||
@ -931,7 +917,6 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
|||||||
ok = 1;
|
ok = 1;
|
||||||
|
|
||||||
Error:
|
Error:
|
||||||
WebPSafeFree(bin_map);
|
|
||||||
VP8LFreeHistogramSet(orig_histo);
|
VP8LFreeHistogramSet(orig_histo);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user