mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-28 14:38:21 +01:00
Optimize cache estimate logic.
Optimize 'VP8LCalculateEstimateForCacheSize' for lower quality ranges (Q < 50). The entropy is generally lower for higher cache_bits, so start searching from higher cache_bits and settle for a local minima, instead of evaluating all values. This speeds up the lossless encoding at lower qualities by 10-15%. Change-Id: I33c1e958515a2549f2e6f64b1aab3f128660dcec
This commit is contained in:
parent
7fb6095b03
commit
a7d2ee39be
@ -815,24 +815,27 @@ int VP8LGetBackwardReferences(int width, int height,
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns 1 on success.
|
// Returns entropy for the given cache bits.
|
||||||
static int ComputeCacheHistogram(const uint32_t* const argb,
|
static double ComputeCacheEntropy(const uint32_t* const argb,
|
||||||
int xsize, int ysize,
|
int xsize, int ysize,
|
||||||
const VP8LBackwardRefs* const refs,
|
const VP8LBackwardRefs* const refs,
|
||||||
int cache_bits,
|
int cache_bits) {
|
||||||
VP8LHistogram* const histo) {
|
|
||||||
int pixel_index = 0;
|
int pixel_index = 0;
|
||||||
int i;
|
int i;
|
||||||
uint32_t k;
|
uint32_t k;
|
||||||
VP8LColorCache hashers;
|
|
||||||
const int use_color_cache = (cache_bits > 0);
|
const int use_color_cache = (cache_bits > 0);
|
||||||
int cc_init = 0;
|
int cc_init = 0;
|
||||||
|
double entropy;
|
||||||
|
const double kSmallPenaltyForLargeCache = 4.0;
|
||||||
|
VP8LColorCache hashers;
|
||||||
|
VP8LHistogram histo;
|
||||||
|
|
||||||
if (use_color_cache) {
|
if (use_color_cache) {
|
||||||
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
|
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
|
||||||
if (!cc_init) return 0;
|
if (!cc_init) return 1e99;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VP8LHistogramInit(&histo, cache_bits);
|
||||||
for (i = 0; i < refs->size; ++i) {
|
for (i = 0; i < refs->size; ++i) {
|
||||||
const PixOrCopy* const v = &refs->refs[i];
|
const PixOrCopy* const v = &refs->refs[i];
|
||||||
if (PixOrCopyIsLiteral(v)) {
|
if (PixOrCopyIsLiteral(v)) {
|
||||||
@ -841,12 +844,12 @@ static int ComputeCacheHistogram(const uint32_t* const argb,
|
|||||||
// push pixel as a cache index
|
// push pixel as a cache index
|
||||||
const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]);
|
const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]);
|
||||||
const PixOrCopy token = PixOrCopyCreateCacheIdx(ix);
|
const PixOrCopy token = PixOrCopyCreateCacheIdx(ix);
|
||||||
VP8LHistogramAddSinglePixOrCopy(histo, &token);
|
VP8LHistogramAddSinglePixOrCopy(&histo, &token);
|
||||||
} else {
|
} else {
|
||||||
VP8LHistogramAddSinglePixOrCopy(histo, v);
|
VP8LHistogramAddSinglePixOrCopy(&histo, v);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VP8LHistogramAddSinglePixOrCopy(histo, v);
|
VP8LHistogramAddSinglePixOrCopy(&histo, v);
|
||||||
}
|
}
|
||||||
if (use_color_cache) {
|
if (use_color_cache) {
|
||||||
for (k = 0; k < PixOrCopyLength(v); ++k) {
|
for (k = 0; k < PixOrCopyLength(v); ++k) {
|
||||||
@ -858,34 +861,38 @@ static int ComputeCacheHistogram(const uint32_t* const argb,
|
|||||||
assert(pixel_index == xsize * ysize);
|
assert(pixel_index == xsize * ysize);
|
||||||
(void)xsize; // xsize is not used in non-debug compilations otherwise.
|
(void)xsize; // xsize is not used in non-debug compilations otherwise.
|
||||||
(void)ysize; // ysize is not used in non-debug compilations otherwise.
|
(void)ysize; // ysize is not used in non-debug compilations otherwise.
|
||||||
|
entropy = VP8LHistogramEstimateBits(&histo) +
|
||||||
|
kSmallPenaltyForLargeCache * cache_bits;
|
||||||
if (cc_init) VP8LColorCacheClear(&hashers);
|
if (cc_init) VP8LColorCacheClear(&hashers);
|
||||||
return 1;
|
return entropy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns how many bits are to be used for a color cache.
|
// Returns how many bits are to be used for a color cache.
|
||||||
int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
|
int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
|
||||||
int xsize, int ysize,
|
int xsize, int ysize, int quality,
|
||||||
int* const best_cache_bits) {
|
int* const best_cache_bits) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
int cache_bits;
|
int cache_bits;
|
||||||
|
// Number of tries to get optimal cache-bits after finding a local minima.
|
||||||
|
const int max_tries_after_min = 3 + (quality >> 4);
|
||||||
|
int num_tries_after_min = 0;
|
||||||
double lowest_entropy = 1e99;
|
double lowest_entropy = 1e99;
|
||||||
VP8LBackwardRefs refs;
|
VP8LBackwardRefs refs;
|
||||||
static const double kSmallPenaltyForLargeCache = 4.0;
|
|
||||||
static const int quality = 30;
|
|
||||||
if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize) ||
|
if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize) ||
|
||||||
!BackwardReferencesHashChain(xsize, ysize, argb, 0, quality, &refs)) {
|
!BackwardReferencesHashChain(xsize, ysize, argb, 0, quality, &refs)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
for (cache_bits = 0; cache_bits <= MAX_COLOR_CACHE_BITS; ++cache_bits) {
|
// The entropy is generally lower for higher cache_bits. Start searching from
|
||||||
double cur_entropy;
|
// the highest value and settle for a local minima.
|
||||||
VP8LHistogram histo;
|
for (cache_bits = MAX_COLOR_CACHE_BITS;
|
||||||
VP8LHistogramInit(&histo, cache_bits);
|
cache_bits >= 0 && num_tries_after_min < max_tries_after_min;
|
||||||
ComputeCacheHistogram(argb, xsize, ysize, &refs, cache_bits, &histo);
|
--cache_bits, ++num_tries_after_min) {
|
||||||
cur_entropy = VP8LHistogramEstimateBits(&histo) +
|
const double cur_entropy = ComputeCacheEntropy(argb, xsize, ysize,
|
||||||
kSmallPenaltyForLargeCache * cache_bits;
|
&refs, cache_bits);
|
||||||
if (cache_bits == 0 || cur_entropy < lowest_entropy) {
|
if (cur_entropy < lowest_entropy) {
|
||||||
*best_cache_bits = cache_bits;
|
*best_cache_bits = cache_bits;
|
||||||
lowest_entropy = cur_entropy;
|
lowest_entropy = cur_entropy;
|
||||||
|
num_tries_after_min = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ok = 1;
|
ok = 1;
|
||||||
|
@ -142,7 +142,7 @@ int VP8LGetBackwardReferences(int width, int height,
|
|||||||
|
|
||||||
// Produce an estimate for a good color cache size for the image.
|
// Produce an estimate for a good color cache size for the image.
|
||||||
int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
|
int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
|
||||||
int xsize, int ysize,
|
int xsize, int ysize, int quality,
|
||||||
int* const best_cache_bits);
|
int* const best_cache_bits);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -1042,7 +1042,8 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
|||||||
|
|
||||||
if (enc->cache_bits_ > 0) {
|
if (enc->cache_bits_ > 0) {
|
||||||
if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_,
|
if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_,
|
||||||
height, &enc->cache_bits_)) {
|
height, quality,
|
||||||
|
&enc->cache_bits_)) {
|
||||||
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user