lossless: Less code for the entropy selection

Tested:
	1000 png corpus gives same results

Change-Id: Ief5ea7727290743b9bd893b08af7aa7951f556cb
This commit is contained in:
Jyrki Alakuijala 2015-06-11 11:08:50 +00:00 committed by James Zern
parent 16ab951abf
commit 84326e4ab0

View File

@ -198,27 +198,26 @@ static void AddSinglePixSubtractGreen(VP8LHistogram* const histo,
++histo->blue_[(PixOrCopyLiteral(v, 0) - green) & 0xff]; ++histo->blue_[(PixOrCopyLiteral(v, 0) - green) & 0xff];
} }
// These five modes are evaluated and their respective entropy is computed.
typedef enum {
kDirect = 0,
kSpatial = 1,
kSubGreen = 2,
kSpatialSubGreen = 3,
kPalette = 4,
kNumEntropyIx = 5,
} EntropyIx;
static int AnalyzeEntropy(const uint32_t* argb, static int AnalyzeEntropy(const uint32_t* argb,
int width, int height, int argb_stride, int width, int height, int argb_stride,
double* const nonpredicted_bits, double entropy[kNumEntropyIx]) {
double* const predicted_bits,
double* const predicted_sub_green_bits,
double* const nonpredicted_sub_green_bits,
double* const palette_bits) {
// Allocate histogram set with cache_bits = 0. // Allocate histogram set with cache_bits = 0.
VP8LHistogramSet* const histo_set = VP8LAllocateHistogramSet(5, 0); VP8LHistogramSet* const histo_set = VP8LAllocateHistogramSet(5, 0);
assert(nonpredicted_bits != NULL);
assert(predicted_bits != NULL);
if (histo_set != NULL) { if (histo_set != NULL) {
int x, y; int i, x, y;
const uint32_t* prev_row = argb; const uint32_t* prev_row = argb;
const uint32_t* curr_row = argb + argb_stride; const uint32_t* curr_row = argb + argb_stride;
VP8LHistogram* const histo_non_pred = histo_set->histograms[0]; VP8LHistogram* const * const histo = &histo_set->histograms[0];
VP8LHistogram* const histo_pred = histo_set->histograms[1];
VP8LHistogram* const histo_pred_subgreen = histo_set->histograms[2];
VP8LHistogram* const histo_subgreen = histo_set->histograms[3];
VP8LHistogram* const histo_palette = histo_set->histograms[4];
for (y = 1; y < height; ++y) { for (y = 1; y < height; ++y) {
uint32_t prev_pix = curr_row[0]; uint32_t prev_pix = curr_row[0];
for (x = 1; x < width; ++x) { for (x = 1; x < width; ++x) {
@ -229,27 +228,23 @@ static int AnalyzeEntropy(const uint32_t* argb,
{ {
const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix); const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff); const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
VP8LHistogramAddSinglePixOrCopy(histo_non_pred, &pix_token); VP8LHistogramAddSinglePixOrCopy(histo[kDirect], &pix_token);
VP8LHistogramAddSinglePixOrCopy(histo_pred, &pix_diff_token); VP8LHistogramAddSinglePixOrCopy(histo[kSpatial], &pix_diff_token);
AddSinglePixSubtractGreen(histo_subgreen, &pix_token); AddSinglePixSubtractGreen(histo[kSubGreen], &pix_token);
AddSinglePixSubtractGreen(histo_pred_subgreen, &pix_diff_token); AddSinglePixSubtractGreen(histo[kSpatialSubGreen], &pix_diff_token);
} }
{ {
// Approximate the palette by the entropy of the multiplicative hash. // Approximate the palette by the entropy of the multiplicative hash.
const int hash = ((pix + (pix >> 19)) * 0x39c5fba7) >> 24; const int hash = ((pix + (pix >> 19)) * 0x39c5fba7) >> 24;
++histo_palette->red_[hash & 0xff]; ++histo[kPalette]->red_[hash & 0xff];
} }
} }
prev_row = curr_row; prev_row = curr_row;
curr_row += argb_stride; curr_row += argb_stride;
} }
*nonpredicted_bits = VP8LHistogramEstimateBitsBulk(histo_non_pred); for (i = 0; i < kNumEntropyIx; ++i) {
*predicted_bits = VP8LHistogramEstimateBitsBulk(histo_pred); entropy[i] = VP8LHistogramEstimateBitsBulk(histo[i]);
*predicted_sub_green_bits = }
VP8LHistogramEstimateBitsBulk(histo_pred_subgreen);
*nonpredicted_sub_green_bits =
VP8LHistogramEstimateBitsBulk(histo_subgreen);
*palette_bits = VP8LHistogramEstimateBitsBulk(histo_palette);
VP8LFreeHistogramSet(histo_set); VP8LFreeHistogramSet(histo_set);
return 1; return 1;
} else { } else {
@ -286,11 +281,6 @@ static int AnalyzeAndInit(VP8LEncoder* const enc) {
// we round the block size up, so we're guaranteed to have // we round the block size up, so we're guaranteed to have
// at max MAX_REFS_BLOCK_PER_IMAGE blocks used: // at max MAX_REFS_BLOCK_PER_IMAGE blocks used:
int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1; int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1;
double non_pred_entropy = 0.;
double non_pred_subtract_green_entropy = 0.;
double pred_entropy = 0.;
double pred_subtract_green_entropy = 0.;
double palette_entropy = 0.;
assert(pic != NULL && pic->argb != NULL); assert(pic != NULL && pic->argb != NULL);
enc->use_cross_color_ = 0; enc->use_cross_color_ = 0;
@ -305,49 +295,26 @@ static int AnalyzeAndInit(VP8LEncoder* const enc) {
enc->use_subtract_green_ = !enc->use_palette_; enc->use_subtract_green_ = !enc->use_palette_;
enc->use_cross_color_ = 0; enc->use_cross_color_ = 0;
} else { } else {
double entropy[kNumEntropyIx];
EntropyIx min_entropy_ix = kDirect;
EntropyIx i = kDirect;
EntropyIx last_mode_to_analyze;
if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride,
&non_pred_entropy, &pred_entropy, &entropy[0])) {
&pred_subtract_green_entropy,
&non_pred_subtract_green_entropy,
&palette_entropy)) {
return 0; return 0;
} }
palette_entropy -= 10.; // Small bias in favor of using the palette. entropy[kPalette] -= 10.; // Small bias in favor of using the palette.
last_mode_to_analyze = enc->use_palette_ ? kPalette : kSpatialSubGreen;
if (enc->use_palette_) { for (i = 1; i <= last_mode_to_analyze; ++i) {
// Check if avoiding the palette coding likely improves compression. if (entropy[min_entropy_ix] > entropy[i]) {
if (palette_entropy >= non_pred_entropy || min_entropy_ix = i;
palette_entropy >= non_pred_subtract_green_entropy ||
palette_entropy >= pred_entropy ||
palette_entropy >= pred_subtract_green_entropy) {
enc->use_palette_ = 0;
}
}
// TODO(jyrki): make this more clear.
if (!enc->use_palette_) {
// Choose the smallest of four options.
if (non_pred_entropy < non_pred_subtract_green_entropy &&
non_pred_entropy < pred_entropy &&
non_pred_entropy < pred_subtract_green_entropy) {
enc->use_subtract_green_ = 0;
enc->use_predict_ = 0;
enc->use_cross_color_ = 0;
} else if (pred_entropy < non_pred_subtract_green_entropy &&
pred_entropy < pred_subtract_green_entropy) {
enc->use_subtract_green_ = 0;
enc->use_predict_ = 1;
enc->use_cross_color_ = 1;
} else if (non_pred_subtract_green_entropy <
pred_subtract_green_entropy) {
enc->use_subtract_green_ = 1;
enc->use_predict_ = 0;
enc->use_cross_color_ = 0;
} else {
enc->use_subtract_green_ = 1;
enc->use_predict_ = 1;
enc->use_cross_color_ = 1;
} }
} }
enc->use_palette_ = (min_entropy_ix == kPalette);
enc->use_subtract_green_ =
(min_entropy_ix == kSubGreen) || (min_entropy_ix == kSpatialSubGreen);
enc->use_cross_color_ = enc->use_predict_ =
(min_entropy_ix == kSpatial) || (min_entropy_ix == kSpatialSubGreen);
} }
// Evaluate histogram bits based on the original value of use_palette flag. // Evaluate histogram bits based on the original value of use_palette flag.
enc->histo_bits_ = GetHistoBits(method, enc->use_palette_, pic->width, enc->histo_bits_ = GetHistoBits(method, enc->use_palette_, pic->width,