From 9814ddb6014299f14c67d29e56476009ddfffabf Mon Sep 17 00:00:00 2001 From: Vikas Arora Date: Mon, 26 Jan 2015 13:18:17 -0800 Subject: [PATCH] Remove the post-transform near-lossless heuristic. Remove the post-transform (prediction, subtract green & cross-color) near-lossless heuristic, that's not ready yet and produces unacceptable visual (banding) artifacts. Change-Id: I9b606a790ce0344c588f2ef83a09c57ac19c2fc1 --- src/enc/near_lossless.c | 110 +--------------------------------------- src/enc/vp8l.c | 45 +++------------- 2 files changed, 9 insertions(+), 146 deletions(-) diff --git a/src/enc/near_lossless.c b/src/enc/near_lossless.c index e6dd8535..98408ee0 100644 --- a/src/enc/near_lossless.c +++ b/src/enc/near_lossless.c @@ -58,23 +58,6 @@ static int FindClosestDiscretized(int a, int bits, int min, int max) { return best_val; } -// Discretizes value (actual - predicted) in the way that actual pixel value -// stays within error bounds. -static WEBP_INLINE uint32_t DiscretizedResidual(uint32_t actual, - uint32_t predicted, - int limit_bits) { - const uint32_t res = (actual - predicted) & 0xff; - uint32_t min, max; - if (actual < predicted) { - min = 256 - predicted; - max = 255; - } else { - min = 0; - max = 255 - predicted; - } - return FindClosestDiscretized(res, limit_bits, min, max); -} - // Applies FindClosestDiscretized to all channels of pixel. static uint32_t ClosestDiscretizedArgb(uint32_t a, int bits, uint32_t min, uint32_t max) { @@ -139,7 +122,7 @@ static int QualityToLimitBits(int quality) { } #endif // WEBP_EXPERIMENTAL_FEATURES -// TODO(akramarz): optimize memory to O(xsize) +// TODO(vikasa): optimize memory to O(xsize) int VP8ApplyNearLossless(int xsize, int ysize, uint32_t* argb, int quality) { #ifndef WEBP_EXPERIMENTAL_FEATURES (void)xsize; @@ -166,94 +149,3 @@ int VP8ApplyNearLossless(int xsize, int ysize, uint32_t* argb, int quality) { #endif // WEBP_EXPERIMENTAL_FEATURES return 1; } - -#ifdef WEBP_EXPERIMENTAL_FEATURES - -// In-place sum of each component with mod 256. -// This probably should go somewhere else (lossless.h?). This is just copy-paste -// from lossless.c. -static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) { - const uint32_t alpha_and_green = (*a & 0xff00ff00u) + (b & 0xff00ff00u); - const uint32_t red_and_blue = (*a & 0x00ff00ffu) + (b & 0x00ff00ffu); - *a = (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); -} - -void VP8ApplyNearLosslessPredict(int xsize, int ysize, int pred_bits, - const uint32_t* argb_orig, - uint32_t* argb, uint32_t* argb_scratch, - const uint32_t* const transform_data, - int quality, int subtract_green) { - const int tiles_per_row = VP8LSubSampleSize(xsize, pred_bits); - uint32_t* const upper_row = argb_scratch; - const int limit_bits = QualityToLimitBits(quality); - - int y; - for (y = 0; y < ysize; ++y) { - int x; - uint32_t curr_pix = 0, prev_pix = 0; - for (x = 0; x < xsize; ++x) { - const int tile_idx = (y >> pred_bits) * tiles_per_row + (x >> pred_bits); - const int pred = (transform_data[tile_idx] >> 8) & 0xf; - const VP8LPredictorFunc pred_func = VP8LPredictors[pred]; - uint32_t predict, rb_shift = 0, delta_g = 0; - if (y == 0) { - predict = (x == 0) ? ARGB_BLACK : prev_pix; // Left. - } else if (x == 0) { - predict = upper_row[x]; // Top. - } else { - predict = pred_func(prev_pix, upper_row + x); - } - - // Discretize all residuals keeping the original pixel values in error - // bounds. - curr_pix = argb_orig[x]; - { - const uint32_t a = curr_pix >> 24; - const uint32_t a_pred = predict >> 24; - const uint32_t a_res = DiscretizedResidual(a, a_pred, limit_bits); - curr_pix = (curr_pix & 0x00ffffff) | a_res << 24; - } - - { - const uint32_t g = (curr_pix >> 8) & 0xff; - const uint32_t g_pred = (predict >> 8) & 0xff; - const uint32_t g_res = DiscretizedResidual(g, g_pred, limit_bits); - // In case subtract-green transform is used, we need to shift - // red and blue later. - if (subtract_green) { - delta_g = (g_pred + g_res - g) & 0xff; - rb_shift = g; - } - curr_pix = (curr_pix & 0xffff00ff) | (g_res << 8); - } - - { - const uint32_t r = ((curr_pix >> 16) + rb_shift) & 0xff; - const uint32_t r_pred = ((predict >> 16) + rb_shift + delta_g) & 0xff; - const uint32_t r_res = DiscretizedResidual(r, r_pred, limit_bits); - curr_pix = (curr_pix & 0xff00ffff) | (r_res << 16); - } - - { - const uint32_t b = (curr_pix + rb_shift) & 0xff; - const uint32_t b_pred = (predict + rb_shift + delta_g) & 0xff; - const uint32_t b_res = DiscretizedResidual(b, b_pred, limit_bits); - curr_pix = (curr_pix & 0xffffff00) | b_res; - } - - // Change pixel value. - argb[x] = curr_pix; - curr_pix = predict; - AddPixelsEq(&curr_pix, argb[x]); - // Copy previous pixel to upper row. - if(x > 0) { - upper_row[x - 1] = prev_pix; - } - prev_pix = curr_pix; - } - argb += xsize; - argb_orig += xsize; - upper_row[xsize - 1] = curr_pix; - } -} -#endif // WEBP_EXPERIMENTAL_FEATURES diff --git a/src/enc/vp8l.c b/src/enc/vp8l.c index 172caf10..c62c9b14 100644 --- a/src/enc/vp8l.c +++ b/src/enc/vp8l.c @@ -1240,12 +1240,14 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, goto Error; } - // If no prediction transform just apply near-lossless preprocessing. + // Apply near-lossless preprocessing. use_near_lossless = !enc->use_palette_ && config->near_lossless; - if (!enc->use_predict_ && use_near_lossless && - !VP8ApplyNearLossless(width, height, picture->argb, - config->near_lossless)) { - goto Error; + if (use_near_lossless) { + if (!VP8ApplyNearLossless(width, height, picture->argb, + config->near_lossless)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } } if (enc->use_palette_) { @@ -1275,40 +1277,9 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, } if (enc->use_predict_) { - uint32_t* copy_buffer = NULL; -#ifdef WEBP_EXPERIMENTAL_FEATURES - if (use_near_lossless) { - // Copy image to temporary buffer. - int y; - copy_buffer = WebPSafeMalloc(height * enc->current_width_, - sizeof(*copy_buffer)); - if (copy_buffer == NULL) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; - goto Error; - } - for (y = 0; y < height; ++y) { - memcpy(copy_buffer + y * enc->current_width_, - enc->argb_ + y * enc->current_width_, - enc->current_width_ * sizeof(*enc->argb_)); - } - } -#endif // WEBP_EXPERIMENTAL_FEATURES err = ApplyPredictFilter(enc, enc->current_width_, height, quality, low_effort, bw); - if (err != VP8_ENC_OK) { - WebPSafeFree(copy_buffer); - goto Error; - } -#ifdef WEBP_EXPERIMENTAL_FEATURES - if (use_near_lossless) { - VP8ApplyNearLosslessPredict(enc->current_width_, height, - enc->transform_bits_, copy_buffer, enc->argb_, - enc->argb_scratch_, enc->transform_data_, - config->near_lossless, - enc->use_subtract_green_); - WebPSafeFree(copy_buffer); - } -#endif // WEBP_EXPERIMENTAL_FEATURES + if (err != VP8_ENC_OK) goto Error; } if (enc->use_cross_color_) {