in Extended/libwebp/src/enc/vp8l_enc.c [188:333]
static int AnalyzeEntropy(const uint32_t* argb,
int width, int height, int argb_stride,
int use_palette,
int palette_size, int transform_bits,
EntropyIx* const min_entropy_ix,
int* const red_and_blue_always_zero) {
// Allocate histogram set with cache_bits = 0.
uint32_t* histo;
if (use_palette && palette_size <= 16) {
// In the case of small palettes, we pack 2, 4 or 8 pixels together. In
// practice, small palettes are better than any other transform.
*min_entropy_ix = kPalette;
*red_and_blue_always_zero = 1;
return 1;
}
histo = (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256);
if (histo != NULL) {
int i, x, y;
const uint32_t* prev_row = NULL;
const uint32_t* curr_row = argb;
uint32_t pix_prev = argb[0]; // Skip the first pixel.
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
const uint32_t pix = curr_row[x];
const uint32_t pix_diff = VP8LSubPixels(pix, pix_prev);
pix_prev = pix;
if ((pix_diff == 0) || (prev_row != NULL && pix == prev_row[x])) {
continue;
}
AddSingle(pix,
&histo[kHistoAlpha * 256],
&histo[kHistoRed * 256],
&histo[kHistoGreen * 256],
&histo[kHistoBlue * 256]);
AddSingle(pix_diff,
&histo[kHistoAlphaPred * 256],
&histo[kHistoRedPred * 256],
&histo[kHistoGreenPred * 256],
&histo[kHistoBluePred * 256]);
AddSingleSubGreen(pix,
&histo[kHistoRedSubGreen * 256],
&histo[kHistoBlueSubGreen * 256]);
AddSingleSubGreen(pix_diff,
&histo[kHistoRedPredSubGreen * 256],
&histo[kHistoBluePredSubGreen * 256]);
{
// Approximate the palette by the entropy of the multiplicative hash.
const uint32_t hash = HashPix(pix);
++histo[kHistoPalette * 256 + hash];
}
}
prev_row = curr_row;
curr_row += argb_stride;
}
{
double entropy_comp[kHistoTotal];
double entropy[kNumEntropyIx];
int k;
int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen;
int j;
// Let's add one zero to the predicted histograms. The zeros are removed
// too efficiently by the pix_diff == 0 comparison, at least one of the
// zeros is likely to exist.
++histo[kHistoRedPredSubGreen * 256];
++histo[kHistoBluePredSubGreen * 256];
++histo[kHistoRedPred * 256];
++histo[kHistoGreenPred * 256];
++histo[kHistoBluePred * 256];
++histo[kHistoAlphaPred * 256];
for (j = 0; j < kHistoTotal; ++j) {
entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256);
}
entropy[kDirect] = entropy_comp[kHistoAlpha] +
entropy_comp[kHistoRed] +
entropy_comp[kHistoGreen] +
entropy_comp[kHistoBlue];
entropy[kSpatial] = entropy_comp[kHistoAlphaPred] +
entropy_comp[kHistoRedPred] +
entropy_comp[kHistoGreenPred] +
entropy_comp[kHistoBluePred];
entropy[kSubGreen] = entropy_comp[kHistoAlpha] +
entropy_comp[kHistoRedSubGreen] +
entropy_comp[kHistoGreen] +
entropy_comp[kHistoBlueSubGreen];
entropy[kSpatialSubGreen] = entropy_comp[kHistoAlphaPred] +
entropy_comp[kHistoRedPredSubGreen] +
entropy_comp[kHistoGreenPred] +
entropy_comp[kHistoBluePredSubGreen];
entropy[kPalette] = entropy_comp[kHistoPalette];
// When including transforms, there is an overhead in bits from
// storing them. This overhead is small but matters for small images.
// For spatial, there are 14 transformations.
entropy[kSpatial] += VP8LSubSampleSize(width, transform_bits) *
VP8LSubSampleSize(height, transform_bits) *
VP8LFastLog2(14);
// For color transforms: 24 as only 3 channels are considered in a
// ColorTransformElement.
entropy[kSpatialSubGreen] += VP8LSubSampleSize(width, transform_bits) *
VP8LSubSampleSize(height, transform_bits) *
VP8LFastLog2(24);
// For palettes, add the cost of storing the palette.
// We empirically estimate the cost of a compressed entry as 8 bits.
// The palette is differential-coded when compressed hence a much
// lower cost than sizeof(uint32_t)*8.
entropy[kPalette] += palette_size * 8;
*min_entropy_ix = kDirect;
for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) {
if (entropy[*min_entropy_ix] > entropy[k]) {
*min_entropy_ix = (EntropyIx)k;
}
}
assert((int)*min_entropy_ix <= last_mode_to_analyze);
*red_and_blue_always_zero = 1;
// Let's check if the histogram of the chosen entropy mode has
// non-zero red and blue values. If all are zero, we can later skip
// the cross color optimization.
{
static const uint8_t kHistoPairs[5][2] = {
{ kHistoRed, kHistoBlue },
{ kHistoRedPred, kHistoBluePred },
{ kHistoRedSubGreen, kHistoBlueSubGreen },
{ kHistoRedPredSubGreen, kHistoBluePredSubGreen },
{ kHistoRed, kHistoBlue }
};
const uint32_t* const red_histo =
&histo[256 * kHistoPairs[*min_entropy_ix][0]];
const uint32_t* const blue_histo =
&histo[256 * kHistoPairs[*min_entropy_ix][1]];
for (i = 1; i < 256; ++i) {
if ((red_histo[i] | blue_histo[i]) != 0) {
*red_and_blue_always_zero = 0;
break;
}
}
}
}
WebPSafeFree(histo);
return 1;
} else {
return 0;
}
}