| Index: third_party/libwebp/enc/backward_references_enc.c
|
| diff --git a/third_party/libwebp/enc/backward_references.c b/third_party/libwebp/enc/backward_references_enc.c
|
| similarity index 87%
|
| rename from third_party/libwebp/enc/backward_references.c
|
| rename to third_party/libwebp/enc/backward_references_enc.c
|
| index 136a24a8c31c810bd8b1b228f07ad2c9681de364..7c0559ff1e146dc9c1604dd4ac7a94b959e9abb5 100644
|
| --- a/third_party/libwebp/enc/backward_references.c
|
| +++ b/third_party/libwebp/enc/backward_references_enc.c
|
| @@ -13,11 +13,12 @@
|
| #include <assert.h>
|
| #include <math.h>
|
|
|
| -#include "./backward_references.h"
|
| -#include "./histogram.h"
|
| +#include "./backward_references_enc.h"
|
| +#include "./histogram_enc.h"
|
| #include "../dsp/lossless.h"
|
| +#include "../dsp/lossless_common.h"
|
| #include "../dsp/dsp.h"
|
| -#include "../utils/color_cache.h"
|
| +#include "../utils/color_cache_utils.h"
|
| #include "../utils/utils.h"
|
|
|
| #define VALUES_IN_BYTE 256
|
| @@ -30,8 +31,9 @@
|
| #define WINDOW_SIZE_BITS 20
|
| #define WINDOW_SIZE ((1 << WINDOW_SIZE_BITS) - 120)
|
|
|
| -// Bounds for the match length.
|
| -#define MIN_LENGTH 2
|
| +// Minimum number of pixels for which it is cheaper to encode a
|
| +// distance + length instead of each pixel as a literal.
|
| +#define MIN_LENGTH 4
|
| // If you change this, you need MAX_LENGTH_BITS + WINDOW_SIZE_BITS <= 32 as it
|
| // is used in VP8LHashChain.
|
| #define MAX_LENGTH_BITS 12
|
| @@ -211,13 +213,13 @@ void VP8LHashChainClear(VP8LHashChain* const p) {
|
|
|
| // -----------------------------------------------------------------------------
|
|
|
| -#define HASH_MULTIPLIER_HI (0xc6a4a793U)
|
| -#define HASH_MULTIPLIER_LO (0x5bd1e996U)
|
| +#define HASH_MULTIPLIER_HI (0xc6a4a793ULL)
|
| +#define HASH_MULTIPLIER_LO (0x5bd1e996ULL)
|
|
|
| static WEBP_INLINE uint32_t GetPixPairHash64(const uint32_t* const argb) {
|
| uint32_t key;
|
| - key = argb[1] * HASH_MULTIPLIER_HI;
|
| - key += argb[0] * HASH_MULTIPLIER_LO;
|
| + key = (argb[1] * HASH_MULTIPLIER_HI) & 0xffffffffu;
|
| + key += (argb[0] * HASH_MULTIPLIER_LO) & 0xffffffffu;
|
| key = key >> (32 - HASH_BITS);
|
| return key;
|
| }
|
| @@ -242,19 +244,26 @@ static WEBP_INLINE int MaxFindCopyLength(int len) {
|
| }
|
|
|
| int VP8LHashChainFill(VP8LHashChain* const p, int quality,
|
| - const uint32_t* const argb, int xsize, int ysize) {
|
| + const uint32_t* const argb, int xsize, int ysize,
|
| + int low_effort) {
|
| const int size = xsize * ysize;
|
| const int iter_max = GetMaxItersForQuality(quality);
|
| - const int iter_min = iter_max - quality / 10;
|
| const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize);
|
| int pos;
|
| + int argb_comp;
|
| uint32_t base_position;
|
| int32_t* hash_to_first_index;
|
| // Temporarily use the p->offset_length_ as a hash chain.
|
| int32_t* chain = (int32_t*)p->offset_length_;
|
| + assert(size > 0);
|
| assert(p->size_ != 0);
|
| assert(p->offset_length_ != NULL);
|
|
|
| + if (size <= 2) {
|
| + p->offset_length_[0] = p->offset_length_[size - 1] = 0;
|
| + return 1;
|
| + }
|
| +
|
| hash_to_first_index =
|
| (int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index));
|
| if (hash_to_first_index == NULL) return 0;
|
| @@ -262,48 +271,111 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
|
| // Set the int32_t array to -1.
|
| memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index));
|
| // Fill the chain linking pixels with the same hash.
|
| - for (pos = 0; pos < size - 1; ++pos) {
|
| - const uint32_t hash_code = GetPixPairHash64(argb + pos);
|
| - chain[pos] = hash_to_first_index[hash_code];
|
| - hash_to_first_index[hash_code] = pos;
|
| + argb_comp = (argb[0] == argb[1]);
|
| + for (pos = 0; pos < size - 2;) {
|
| + uint32_t hash_code;
|
| + const int argb_comp_next = (argb[pos + 1] == argb[pos + 2]);
|
| + if (argb_comp && argb_comp_next) {
|
| + // Consecutive pixels with the same color will share the same hash.
|
| + // We therefore use a different hash: the color and its repetition
|
| + // length.
|
| + uint32_t tmp[2];
|
| + uint32_t len = 1;
|
| + tmp[0] = argb[pos];
|
| + // Figure out how far the pixels are the same.
|
| + // The last pixel has a different 64 bit hash, as its next pixel does
|
| + // not have the same color, so we just need to get to the last pixel equal
|
| + // to its follower.
|
| + while (pos + (int)len + 2 < size && argb[pos + len + 2] == argb[pos]) {
|
| + ++len;
|
| + }
|
| + if (len > MAX_LENGTH) {
|
| + // Skip the pixels that match for distance=1 and length>MAX_LENGTH
|
| + // because they are linked to their predecessor and we automatically
|
| + // check that in the main for loop below. Skipping means setting no
|
| + // predecessor in the chain, hence -1.
|
| + memset(chain + pos, 0xff, (len - MAX_LENGTH) * sizeof(*chain));
|
| + pos += len - MAX_LENGTH;
|
| + len = MAX_LENGTH;
|
| + }
|
| + // Process the rest of the hash chain.
|
| + while (len) {
|
| + tmp[1] = len--;
|
| + hash_code = GetPixPairHash64(tmp);
|
| + chain[pos] = hash_to_first_index[hash_code];
|
| + hash_to_first_index[hash_code] = pos++;
|
| + }
|
| + argb_comp = 0;
|
| + } else {
|
| + // Just move one pixel forward.
|
| + hash_code = GetPixPairHash64(argb + pos);
|
| + chain[pos] = hash_to_first_index[hash_code];
|
| + hash_to_first_index[hash_code] = pos++;
|
| + argb_comp = argb_comp_next;
|
| + }
|
| }
|
| + // Process the penultimate pixel.
|
| + chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)];
|
| +
|
| WebPSafeFree(hash_to_first_index);
|
|
|
| // Find the best match interval at each pixel, defined by an offset to the
|
| // pixel and a length. The right-most pixel cannot match anything to the right
|
| // (hence a best length of 0) and the left-most pixel nothing to the left
|
| // (hence an offset of 0).
|
| + assert(size > 2);
|
| p->offset_length_[0] = p->offset_length_[size - 1] = 0;
|
| - for (base_position = size - 2 < 0 ? 0 : size - 2; base_position > 0;) {
|
| + for (base_position = size - 2; base_position > 0;) {
|
| const int max_len = MaxFindCopyLength(size - 1 - base_position);
|
| const uint32_t* const argb_start = argb + base_position;
|
| int iter = iter_max;
|
| int best_length = 0;
|
| uint32_t best_distance = 0;
|
| + uint32_t best_argb;
|
| const int min_pos =
|
| (base_position > window_size) ? base_position - window_size : 0;
|
| const int length_max = (max_len < 256) ? max_len : 256;
|
| uint32_t max_base_position;
|
|
|
| - for (pos = chain[base_position]; pos >= min_pos; pos = chain[pos]) {
|
| + pos = chain[base_position];
|
| + if (!low_effort) {
|
| int curr_length;
|
| - if (--iter < 0) {
|
| - break;
|
| + // Heuristic: use the comparison with the above line as an initialization.
|
| + if (base_position >= (uint32_t)xsize) {
|
| + curr_length = FindMatchLength(argb_start - xsize, argb_start,
|
| + best_length, max_len);
|
| + if (curr_length > best_length) {
|
| + best_length = curr_length;
|
| + best_distance = xsize;
|
| + }
|
| + --iter;
|
| + }
|
| + // Heuristic: compare to the previous pixel.
|
| + curr_length =
|
| + FindMatchLength(argb_start - 1, argb_start, best_length, max_len);
|
| + if (curr_length > best_length) {
|
| + best_length = curr_length;
|
| + best_distance = 1;
|
| }
|
| + --iter;
|
| + // Skip the for loop if we already have the maximum.
|
| + if (best_length == MAX_LENGTH) pos = min_pos - 1;
|
| + }
|
| + best_argb = argb_start[best_length];
|
| +
|
| + for (; pos >= min_pos && --iter; pos = chain[pos]) {
|
| + int curr_length;
|
| assert(base_position > (uint32_t)pos);
|
|
|
| - curr_length =
|
| - FindMatchLength(argb + pos, argb_start, best_length, max_len);
|
| + if (argb[pos + best_length] != best_argb) continue;
|
| +
|
| + curr_length = VP8LVectorMismatch(argb + pos, argb_start, max_len);
|
| if (best_length < curr_length) {
|
| best_length = curr_length;
|
| best_distance = base_position - pos;
|
| - // Stop if we have reached the maximum length. Otherwise, make sure
|
| - // we have executed a minimum number of iterations depending on the
|
| - // quality.
|
| - if ((best_length == MAX_LENGTH) ||
|
| - (curr_length >= length_max && iter < iter_min)) {
|
| - break;
|
| - }
|
| + best_argb = argb_start[best_length];
|
| + // Stop if we have reached a good enough length.
|
| + if (best_length >= length_max) break;
|
| }
|
| }
|
| // We have the best match but in case the two intervals continue matching
|
| @@ -392,17 +464,16 @@ static int BackwardReferencesRle(int xsize, int ysize,
|
| i = 1;
|
| while (i < pix_count) {
|
| const int max_len = MaxFindCopyLength(pix_count - i);
|
| - const int kMinLength = 4;
|
| const int rle_len = FindMatchLength(argb + i, argb + i - 1, 0, max_len);
|
| const int prev_row_len = (i < xsize) ? 0 :
|
| FindMatchLength(argb + i, argb + i - xsize, 0, max_len);
|
| - if (rle_len >= prev_row_len && rle_len >= kMinLength) {
|
| + if (rle_len >= prev_row_len && rle_len >= MIN_LENGTH) {
|
| BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, rle_len));
|
| // We don't need to update the color cache here since it is always the
|
| // same pixel being copied, and that does not change the color cache
|
| // state.
|
| i += rle_len;
|
| - } else if (prev_row_len >= kMinLength) {
|
| + } else if (prev_row_len >= MIN_LENGTH) {
|
| BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(xsize, prev_row_len));
|
| if (use_color_cache) {
|
| for (k = 0; k < prev_row_len; ++k) {
|
| @@ -442,7 +513,7 @@ static int BackwardReferencesLz77(int xsize, int ysize,
|
| int len = 0;
|
| int j;
|
| HashChainFindCopy(hash_chain, i, &offset, &len);
|
| - if (len > MIN_LENGTH + 1) {
|
| + if (len >= MIN_LENGTH) {
|
| const int len_ini = len;
|
| int max_reach = 0;
|
| assert(i + len < pix_count);
|
| @@ -457,7 +528,7 @@ static int BackwardReferencesLz77(int xsize, int ysize,
|
| for (j = i_last_check + 1; j <= i + len_ini; ++j) {
|
| const int len_j = HashChainFindLength(hash_chain, j);
|
| const int reach =
|
| - j + (len_j > MIN_LENGTH + 1 ? len_j : 1); // 1 for single literal.
|
| + j + (len_j >= MIN_LENGTH ? len_j : 1); // 1 for single literal.
|
| if (reach > max_reach) {
|
| len = j - i;
|
| max_reach = reach;
|
| @@ -581,9 +652,10 @@ static void AddSingleLiteralWithCostModel(const uint32_t* const argb,
|
| uint16_t* const dist_array) {
|
| double cost_val = prev_cost;
|
| const uint32_t color = argb[0];
|
| - if (use_color_cache && VP8LColorCacheContains(hashers, color)) {
|
| + const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1;
|
| + if (ix >= 0) {
|
| + // use_color_cache is true and hashers contains color
|
| const double mul0 = 0.68;
|
| - const int ix = VP8LColorCacheGetIndex(hashers, color);
|
| cost_val += GetCacheCost(cost_model, ix) * mul0;
|
| } else {
|
| const double mul1 = 0.82;
|
| @@ -1215,7 +1287,8 @@ static int BackwardReferencesHashChainDistanceOnly(
|
| int offset = 0, len = 0;
|
| double prev_cost = cost_manager->costs_[i - 1];
|
| HashChainFindCopy(hash_chain, i, &offset, &len);
|
| - if (len >= MIN_LENGTH) {
|
| + if (len >= 2) {
|
| + // If we are dealing with a non-literal.
|
| const int code = DistanceToPlaneCode(xsize, offset);
|
| const double offset_cost = GetDistanceCost(cost_model, code);
|
| const int first_i = i;
|
| @@ -1304,20 +1377,17 @@ static int BackwardReferencesHashChainDistanceOnly(
|
| }
|
| goto next_symbol;
|
| }
|
| - if (len > MIN_LENGTH) {
|
| - int code_min_length;
|
| - double cost_total;
|
| - offset = HashChainFindOffset(hash_chain, i);
|
| - code_min_length = DistanceToPlaneCode(xsize, offset);
|
| - cost_total = prev_cost +
|
| - GetDistanceCost(cost_model, code_min_length) +
|
| - GetLengthCost(cost_model, 1);
|
| + if (len > 2) {
|
| + // Also try the smallest interval possible (size 2).
|
| + double cost_total =
|
| + prev_cost + offset_cost + GetLengthCost(cost_model, 1);
|
| if (cost_manager->costs_[i + 1] > cost_total) {
|
| cost_manager->costs_[i + 1] = (float)cost_total;
|
| dist_array[i + 1] = 2;
|
| }
|
| }
|
| - } else { // len < MIN_LENGTH
|
| + } else {
|
| + // The pixel is added as a single literal so just update the costs.
|
| UpdateCostPerIndex(cost_manager, i + 1);
|
| }
|
|
|
| @@ -1393,9 +1463,11 @@ static int BackwardReferencesHashChainFollowChosenPath(
|
| i += len;
|
| } else {
|
| PixOrCopy v;
|
| - if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
|
| + const int idx =
|
| + use_color_cache ? VP8LColorCacheContains(&hashers, argb[i]) : -1;
|
| + if (idx >= 0) {
|
| + // use_color_cache is true and hashers contains argb[i]
|
| // push pixel as a color cache index
|
| - const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]);
|
| v = PixOrCopyCreateCacheIdx(idx);
|
| } else {
|
| if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
|
| @@ -1454,63 +1526,89 @@ static void BackwardReferences2DLocality(int xsize,
|
| }
|
| }
|
|
|
| -// Returns entropy for the given cache bits.
|
| -static double ComputeCacheEntropy(const uint32_t* argb,
|
| - const VP8LBackwardRefs* const refs,
|
| - int cache_bits) {
|
| - const int use_color_cache = (cache_bits > 0);
|
| - int cc_init = 0;
|
| - double entropy = MAX_ENTROPY;
|
| - const double kSmallPenaltyForLargeCache = 4.0;
|
| - VP8LColorCache hashers;
|
| +// Computes the entropies for a color cache size (in bits) between 0 (unused)
|
| +// and cache_bits_max (inclusive).
|
| +// Returns 1 on success, 0 in case of allocation error.
|
| +static int ComputeCacheEntropies(const uint32_t* argb,
|
| + const VP8LBackwardRefs* const refs,
|
| + int cache_bits_max, double entropies[]) {
|
| + int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 };
|
| + VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1];
|
| VP8LRefsCursor c = VP8LRefsCursorInit(refs);
|
| - VP8LHistogram* histo = VP8LAllocateHistogram(cache_bits);
|
| - if (histo == NULL) goto Error;
|
| + VP8LHistogram* histos[MAX_COLOR_CACHE_BITS + 1] = { NULL };
|
| + int ok = 0;
|
| + int i;
|
|
|
| - if (use_color_cache) {
|
| - cc_init = VP8LColorCacheInit(&hashers, cache_bits);
|
| - if (!cc_init) goto Error;
|
| + for (i = 0; i <= cache_bits_max; ++i) {
|
| + histos[i] = VP8LAllocateHistogram(i);
|
| + if (histos[i] == NULL) goto Error;
|
| + if (i == 0) continue;
|
| + cc_init[i] = VP8LColorCacheInit(&hashers[i], i);
|
| + if (!cc_init[i]) goto Error;
|
| }
|
| - if (!use_color_cache) {
|
| - while (VP8LRefsCursorOk(&c)) {
|
| - VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos);
|
| - VP8LRefsCursorNext(&c);
|
| - }
|
| - } else {
|
| +
|
| + assert(cache_bits_max >= 0);
|
| + // Do not use the color cache for cache_bits=0.
|
| + while (VP8LRefsCursorOk(&c)) {
|
| + VP8LHistogramAddSinglePixOrCopy(histos[0], c.cur_pos);
|
| + VP8LRefsCursorNext(&c);
|
| + }
|
| + if (cache_bits_max > 0) {
|
| + c = VP8LRefsCursorInit(refs);
|
| while (VP8LRefsCursorOk(&c)) {
|
| const PixOrCopy* const v = c.cur_pos;
|
| if (PixOrCopyIsLiteral(v)) {
|
| const uint32_t pix = *argb++;
|
| - const uint32_t key = VP8LColorCacheGetIndex(&hashers, pix);
|
| - if (VP8LColorCacheLookup(&hashers, key) == pix) {
|
| - ++histo->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key];
|
| - } else {
|
| - VP8LColorCacheSet(&hashers, key, pix);
|
| - ++histo->blue_[pix & 0xff];
|
| - ++histo->literal_[(pix >> 8) & 0xff];
|
| - ++histo->red_[(pix >> 16) & 0xff];
|
| - ++histo->alpha_[pix >> 24];
|
| + // The keys of the caches can be derived from the longest one.
|
| + int key = HashPix(pix, 32 - cache_bits_max);
|
| + 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_[pix & 0xff];
|
| + ++histos[i]->literal_[(pix >> 8) & 0xff];
|
| + ++histos[i]->red_[(pix >> 16) & 0xff];
|
| + ++histos[i]->alpha_[pix >> 24];
|
| + }
|
| }
|
| } else {
|
| + // Update the histograms for distance/length.
|
| int len = PixOrCopyLength(v);
|
| - int code, extra_bits;
|
| - VP8LPrefixEncodeBits(len, &code, &extra_bits);
|
| - ++histo->literal_[NUM_LITERAL_CODES + code];
|
| - VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits);
|
| - ++histo->distance_[code];
|
| + int code_dist, code_len, extra_bits;
|
| + uint32_t argb_prev = *argb ^ 0xffffffffu;
|
| + VP8LPrefixEncodeBits(len, &code_len, &extra_bits);
|
| + VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code_dist, &extra_bits);
|
| + for (i = 1; i <= cache_bits_max; ++i) {
|
| + ++histos[i]->literal_[NUM_LITERAL_CODES + code_len];
|
| + ++histos[i]->distance_[code_dist];
|
| + }
|
| + // Update the colors caches.
|
| do {
|
| - VP8LColorCacheInsert(&hashers, *argb++);
|
| - } while(--len != 0);
|
| + if (*argb != argb_prev) {
|
| + // Efficiency: insert only if the color changes.
|
| + int key = HashPix(*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);
|
| }
|
| }
|
| - entropy = VP8LHistogramEstimateBits(histo) +
|
| - kSmallPenaltyForLargeCache * cache_bits;
|
| - Error:
|
| - if (cc_init) VP8LColorCacheClear(&hashers);
|
| - VP8LFreeHistogram(histo);
|
| - return entropy;
|
| + for (i = 0; i <= cache_bits_max; ++i) {
|
| + entropies[i] = VP8LHistogramEstimateBits(histos[i]);
|
| + }
|
| + ok = 1;
|
| +Error:
|
| + for (i = 0; i <= cache_bits_max; ++i) {
|
| + if (cc_init[i]) VP8LColorCacheClear(&hashers[i]);
|
| + VP8LFreeHistogram(histos[i]);
|
| + }
|
| + return ok;
|
| }
|
|
|
| // Evaluate optimal cache bits for the local color cache.
|
| @@ -1524,13 +1622,10 @@ static int CalculateBestCacheSize(const uint32_t* const argb,
|
| VP8LBackwardRefs* const refs,
|
| int* const lz77_computed,
|
| int* const best_cache_bits) {
|
| - int eval_low = 1;
|
| - int eval_high = 1;
|
| - double entropy_low = MAX_ENTROPY;
|
| - double entropy_high = MAX_ENTROPY;
|
| - const double cost_mul = 5e-4;
|
| - int cache_bits_low = 0;
|
| + int i;
|
| int cache_bits_high = (quality <= 25) ? 0 : *best_cache_bits;
|
| + double entropy_min = MAX_ENTROPY;
|
| + double entropies[MAX_COLOR_CACHE_BITS + 1];
|
|
|
| assert(cache_bits_high <= MAX_COLOR_CACHE_BITS);
|
|
|
| @@ -1540,34 +1635,23 @@ static int CalculateBestCacheSize(const uint32_t* const argb,
|
| // Local color cache is disabled.
|
| return 1;
|
| }
|
| - if (!BackwardReferencesLz77(xsize, ysize, argb, cache_bits_low, hash_chain,
|
| - refs)) {
|
| + // Compute LZ77 with no cache (0 bits), as the ideal LZ77 with a color cache
|
| + // is not that different in practice.
|
| + if (!BackwardReferencesLz77(xsize, ysize, argb, 0, hash_chain, refs)) {
|
| return 0;
|
| }
|
| - // Do a binary search to find the optimal entropy for cache_bits.
|
| - while (eval_low || eval_high) {
|
| - if (eval_low) {
|
| - entropy_low = ComputeCacheEntropy(argb, refs, cache_bits_low);
|
| - entropy_low += entropy_low * cache_bits_low * cost_mul;
|
| - eval_low = 0;
|
| - }
|
| - if (eval_high) {
|
| - entropy_high = ComputeCacheEntropy(argb, refs, cache_bits_high);
|
| - entropy_high += entropy_high * cache_bits_high * cost_mul;
|
| - eval_high = 0;
|
| - }
|
| - if (entropy_high < entropy_low) {
|
| - const int prev_cache_bits_low = cache_bits_low;
|
| - *best_cache_bits = cache_bits_high;
|
| - cache_bits_low = (cache_bits_low + cache_bits_high) / 2;
|
| - if (cache_bits_low != prev_cache_bits_low) eval_low = 1;
|
| - } else {
|
| - *best_cache_bits = cache_bits_low;
|
| - cache_bits_high = (cache_bits_low + cache_bits_high) / 2;
|
| - if (cache_bits_high != cache_bits_low) eval_high = 1;
|
| + // 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.
|
| + if (!ComputeCacheEntropies(argb, refs, cache_bits_high, entropies)) {
|
| + return 0;
|
| + }
|
| + for (i = 0; i <= cache_bits_high; ++i) {
|
| + if (i == 0 || entropies[i] < entropy_min) {
|
| + entropy_min = entropies[i];
|
| + *best_cache_bits = i;
|
| }
|
| }
|
| - *lz77_computed = 1;
|
| return 1;
|
| }
|
|
|
| @@ -1584,8 +1668,9 @@ static int BackwardRefsWithLocalCache(const uint32_t* const argb,
|
| PixOrCopy* const v = c.cur_pos;
|
| if (PixOrCopyIsLiteral(v)) {
|
| const uint32_t argb_literal = v->argb_or_distance;
|
| - if (VP8LColorCacheContains(&hashers, argb_literal)) {
|
| - const int ix = VP8LColorCacheGetIndex(&hashers, argb_literal);
|
| + const int ix = VP8LColorCacheContains(&hashers, argb_literal);
|
| + if (ix >= 0) {
|
| + // hashers contains argb_literal
|
| *v = PixOrCopyCreateCacheIdx(ix);
|
| } else {
|
| VP8LColorCacheInsert(&hashers, argb_literal);
|
|
|