in Extended/libwebp/src/enc/backward_references_enc.c [695:792]
static int CalculateBestCacheSize(const uint32_t* argb, int quality,
const VP8LBackwardRefs* const refs,
int* const best_cache_bits) {
int i;
const int cache_bits_max = (quality <= 25) ? 0 : *best_cache_bits;
double entropy_min = MAX_ENTROPY;
int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 };
VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1];
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
VP8LHistogram* histos[MAX_COLOR_CACHE_BITS + 1] = { NULL };
int ok = 0;
assert(cache_bits_max >= 0 && cache_bits_max <= MAX_COLOR_CACHE_BITS);
if (cache_bits_max == 0) {
*best_cache_bits = 0;
// Local color cache is disabled.
return 1;
}
// Allocate data.
for (i = 0; i <= cache_bits_max; ++i) {
histos[i] = VP8LAllocateHistogram(i);
if (histos[i] == NULL) goto Error;
VP8LHistogramInit(histos[i], i, /*init_arrays=*/ 1);
if (i == 0) continue;
cc_init[i] = VP8LColorCacheInit(&hashers[i], i);
if (!cc_init[i]) goto Error;
}
// Find the cache_bits giving the lowest entropy. The search is done in a
// brute-force way as the function (entropy w.r.t cache_bits) can be
// anything in practice.
while (VP8LRefsCursorOk(&c)) {
const PixOrCopy* const v = c.cur_pos;
if (PixOrCopyIsLiteral(v)) {
const uint32_t pix = *argb++;
const uint32_t a = (pix >> 24) & 0xff;
const uint32_t r = (pix >> 16) & 0xff;
const uint32_t g = (pix >> 8) & 0xff;
const uint32_t b = (pix >> 0) & 0xff;
// The keys of the caches can be derived from the longest one.
int key = VP8LHashPix(pix, 32 - cache_bits_max);
// Do not use the color cache for cache_bits = 0.
++histos[0]->blue_[b];
++histos[0]->literal_[g];
++histos[0]->red_[r];
++histos[0]->alpha_[a];
// Deal with cache_bits > 0.
for (i = cache_bits_max; i >= 1; --i, key >>= 1) {
if (VP8LColorCacheLookup(&hashers[i], key) == pix) {
++histos[i]->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key];
} else {
VP8LColorCacheSet(&hashers[i], key, pix);
++histos[i]->blue_[b];
++histos[i]->literal_[g];
++histos[i]->red_[r];
++histos[i]->alpha_[a];
}
}
} else {
// We should compute the contribution of the (distance,length)
// histograms but those are the same independently from the cache size.
// As those constant contributions are in the end added to the other
// histogram contributions, we can safely ignore them.
int len = PixOrCopyLength(v);
uint32_t argb_prev = *argb ^ 0xffffffffu;
// Update the color caches.
do {
if (*argb != argb_prev) {
// Efficiency: insert only if the color changes.
int key = VP8LHashPix(*argb, 32 - cache_bits_max);
for (i = cache_bits_max; i >= 1; --i, key >>= 1) {
hashers[i].colors_[key] = *argb;
}
argb_prev = *argb;
}
argb++;
} while (--len != 0);
}
VP8LRefsCursorNext(&c);
}
for (i = 0; i <= cache_bits_max; ++i) {
const double entropy = VP8LHistogramEstimateBits(histos[i]);
if (i == 0 || entropy < entropy_min) {
entropy_min = entropy;
*best_cache_bits = i;
}
}
ok = 1;
Error:
for (i = 0; i <= cache_bits_max; ++i) {
if (cc_init[i]) VP8LColorCacheClear(&hashers[i]);
VP8LFreeHistogram(histos[i]);
}
return ok;
}