From 2a5c417c686e5464934d938eb1d84142fcf1f54b Mon Sep 17 00:00:00 2001 From: Vincent Rabaud Date: Thu, 14 Jul 2016 19:21:07 +0200 Subject: [PATCH] Apply the RLE heuristic to LZ77. Change-Id: I7317eed7e017ee8981f40fcf1737f97e0e3a238c --- src/enc/backward_references.c | 21 +++++++++++++++++++-- src/enc/backward_references.h | 3 ++- src/enc/vp8l.c | 31 +++++++++++++++++-------------- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/enc/backward_references.c b/src/enc/backward_references.c index 136a24a8..fd82563a 100644 --- a/src/enc/backward_references.c +++ b/src/enc/backward_references.c @@ -242,7 +242,8 @@ 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; @@ -285,7 +286,23 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality, 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) { + // Heuristic: use the comparison with the above line as an initialization. + if (base_position >= (uint32_t)xsize) { + const int 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; + // Skip the for loop if we already have the maximum. + if (best_length == MAX_LENGTH) pos = min_pos - 1; + } + + for (; pos >= min_pos; pos = chain[pos]) { int curr_length; if (--iter < 0) { break; diff --git a/src/enc/backward_references.h b/src/enc/backward_references.h index 0cadb11e..3a19aa76 100644 --- a/src/enc/backward_references.h +++ b/src/enc/backward_references.h @@ -130,7 +130,8 @@ struct VP8LHashChain { int VP8LHashChainInit(VP8LHashChain* const p, int size); // Pre-compute the best matches for argb. 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); void VP8LHashChainClear(VP8LHashChain* const p); // release memory // ----------------------------------------------------------------------------- diff --git a/src/enc/vp8l.c b/src/enc/vp8l.c index c16e2560..75d69de5 100644 --- a/src/enc/vp8l.c +++ b/src/enc/vp8l.c @@ -697,7 +697,7 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[2], int width, int height, - int quality) { + int quality, int low_effort) { int i; int max_tokens = 0; WebPEncodingError err = VP8_ENC_OK; @@ -715,7 +715,8 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, } // Calculate backward references from ARGB image. - if (VP8LHashChainFill(hash_chain, quality, argb, width, height) == 0) { + if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, + low_effort)) { err = VP8_ENC_ERROR_OUT_OF_MEMORY; goto Error; } @@ -819,7 +820,8 @@ static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw, // 'best_refs' is the reference to the best backward refs and points to one // of refs_array[0] or refs_array[1]. // Calculate backward references from ARGB image. - if (VP8LHashChainFill(hash_chain, quality, argb, width, height) == 0) { + if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, + low_effort)) { err = VP8_ENC_ERROR_OUT_OF_MEMORY; goto Error; } @@ -900,7 +902,7 @@ static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw, err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array, VP8LSubSampleSize(width, histogram_bits), VP8LSubSampleSize(height, histogram_bits), - quality); + quality, low_effort); WebPSafeFree(histogram_argb); if (err != VP8_ENC_OK) goto Error; } @@ -991,12 +993,12 @@ static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc, (VP8LHashChain*)&enc->hash_chain_, (VP8LBackwardRefs*)enc->refs_, // cast const away transform_width, transform_height, - quality); + quality, low_effort); } static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, int width, int height, - int quality, + int quality, int low_effort, VP8LBitWriter* const bw) { const int ccolor_transform_bits = enc->transform_bits_; const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); @@ -1012,7 +1014,7 @@ static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, (VP8LHashChain*)&enc->hash_chain_, (VP8LBackwardRefs*)enc->refs_, // cast const away transform_width, transform_height, - quality); + quality, low_effort); } // ----------------------------------------------------------------------------- @@ -1291,7 +1293,7 @@ static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc, } // Save palette_[] to bitstream. -static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, +static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort, VP8LEncoder* const enc) { int i; uint32_t tmp_palette[MAX_PALETTE_SIZE]; @@ -1306,13 +1308,14 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, } tmp_palette[0] = palette[0]; return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, enc->refs_, - palette_size, 1, 20 /* quality */); + palette_size, 1, 20 /* quality */, low_effort); } #ifdef WEBP_EXPERIMENTAL_FEATURES static WebPEncodingError EncodeDeltaPalettePredictorImage( - VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality) { + VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality, + int low_effort) { const WebPPicture* const pic = enc->pic_; const int width = pic->width; const int height = pic->height; @@ -1343,7 +1346,7 @@ static WebPEncodingError EncodeDeltaPalettePredictorImage( err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_, (VP8LBackwardRefs*)enc->refs_, // cast const away transform_width, transform_height, - quality); + quality, low_effort); WebPSafeFree(predictors); return err; } @@ -1433,7 +1436,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, if (enc->use_palette_) { err = AllocateTransformBuffer(enc, width, height); if (err != VP8_ENC_OK) goto Error; - err = EncodeDeltaPalettePredictorImage(bw, enc, quality); + err = EncodeDeltaPalettePredictorImage(bw, enc, quality, low_effort); if (err != VP8_ENC_OK) goto Error; use_delta_palettization = 1; } @@ -1442,7 +1445,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, // Encode palette if (enc->use_palette_) { - err = EncodePalette(bw, enc); + err = EncodePalette(bw, low_effort, enc); if (err != VP8_ENC_OK) goto Error; err = MapImageFromPalette(enc, use_delta_palettization); if (err != VP8_ENC_OK) goto Error; @@ -1469,7 +1472,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, if (enc->use_cross_color_) { err = ApplyCrossColorFilter(enc, enc->current_width_, - height, quality, bw); + height, quality, low_effort, bw); if (err != VP8_ENC_OK) goto Error; } }