predictor_enc.c (46398B)
1 // Copyright 2016 Google Inc. All Rights Reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the COPYING file in the root of the source 5 // tree. An additional intellectual property rights grant can be found 6 // in the file PATENTS. All contributing project authors may 7 // be found in the AUTHORS file in the root of the source tree. 8 // ----------------------------------------------------------------------------- 9 // 10 // Image transform methods for lossless encoder. 11 // 12 // Authors: Vikas Arora (vikaas.arora@gmail.com) 13 // Jyrki Alakuijala (jyrki@google.com) 14 // Urvang Joshi (urvang@google.com) 15 // Vincent Rabaud (vrabaud@google.com) 16 17 #include <assert.h> 18 #include <stdlib.h> 19 #include <string.h> 20 21 #include "src/dsp/lossless.h" 22 #include "src/dsp/lossless_common.h" 23 #include "src/enc/vp8i_enc.h" 24 #include "src/enc/vp8li_enc.h" 25 #include "src/utils/utils.h" 26 #include "src/webp/encode.h" 27 #include "src/webp/format_constants.h" 28 #include "src/webp/types.h" 29 30 #define HISTO_SIZE (4 * 256) 31 static const int64_t kSpatialPredictorBias = 15ll << LOG_2_PRECISION_BITS; 32 static const int kPredLowEffort = 11; 33 static const uint32_t kMaskAlpha = 0xff000000; 34 static const int kNumPredModes = 14; 35 36 // Mostly used to reduce code size + readability 37 static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; } 38 static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; } 39 40 //------------------------------------------------------------------------------ 41 // Methods to calculate Entropy (Shannon). 42 43 // Compute a bias for prediction entropy using a global heuristic to favor 44 // values closer to 0. Hence the final negative sign. 45 // 'exp_val' has a scaling factor of 1/100. 46 static int64_t PredictionCostBias(const uint32_t counts[256], uint64_t weight_0, 47 uint64_t exp_val) { 48 const int significant_symbols = 256 >> 4; 49 const uint64_t exp_decay_factor = 6; // has a scaling factor of 1/10 50 uint64_t bits = (weight_0 * counts[0]) << LOG_2_PRECISION_BITS; 51 int i; 52 exp_val <<= LOG_2_PRECISION_BITS; 53 for (i = 1; i < significant_symbols; ++i) { 54 bits += DivRound(exp_val * (counts[i] + counts[256 - i]), 100); 55 exp_val = DivRound(exp_decay_factor * exp_val, 10); 56 } 57 return -DivRound((int64_t)bits, 10); 58 } 59 60 static int64_t PredictionCostSpatialHistogram( 61 const uint32_t accumulated[HISTO_SIZE], const uint32_t tile[HISTO_SIZE], 62 int mode, int left_mode, int above_mode) { 63 int i; 64 int64_t retval = 0; 65 for (i = 0; i < 4; ++i) { 66 const uint64_t kExpValue = 94; 67 retval += PredictionCostBias(&tile[i * 256], 1, kExpValue); 68 // Compute the new cost if 'tile' is added to 'accumulate' but also add the 69 // cost of the current histogram to guide the spatial predictor selection. 70 // Basically, favor low entropy, locally and globally. 71 retval += (int64_t)VP8LCombinedShannonEntropy(&tile[i * 256], 72 &accumulated[i * 256]); 73 } 74 // Favor keeping the areas locally similar. 75 if (mode == left_mode) retval -= kSpatialPredictorBias; 76 if (mode == above_mode) retval -= kSpatialPredictorBias; 77 return retval; 78 } 79 80 static WEBP_INLINE void UpdateHisto(uint32_t histo_argb[HISTO_SIZE], 81 uint32_t argb) { 82 ++histo_argb[0 * 256 + (argb >> 24)]; 83 ++histo_argb[1 * 256 + ((argb >> 16) & 0xff)]; 84 ++histo_argb[2 * 256 + ((argb >> 8) & 0xff)]; 85 ++histo_argb[3 * 256 + (argb & 0xff)]; 86 } 87 88 //------------------------------------------------------------------------------ 89 // Spatial transform functions. 90 91 static WEBP_INLINE void PredictBatch(int mode, int x_start, int y, 92 int num_pixels, const uint32_t* current, 93 const uint32_t* upper, uint32_t* out) { 94 if (x_start == 0) { 95 if (y == 0) { 96 // ARGB_BLACK. 97 VP8LPredictorsSub[0](current, NULL, 1, out); 98 } else { 99 // Top one. 100 VP8LPredictorsSub[2](current, upper, 1, out); 101 } 102 ++x_start; 103 ++out; 104 --num_pixels; 105 } 106 if (y == 0) { 107 // Left one. 108 VP8LPredictorsSub[1](current + x_start, NULL, num_pixels, out); 109 } else { 110 VP8LPredictorsSub[mode](current + x_start, upper + x_start, num_pixels, 111 out); 112 } 113 } 114 115 #if (WEBP_NEAR_LOSSLESS == 1) 116 static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) { 117 const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24)); 118 const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff)); 119 const int diff_g = abs((int)((p1 >> 8) & 0xff) - (int)((p2 >> 8) & 0xff)); 120 const int diff_b = abs((int)(p1 & 0xff) - (int)(p2 & 0xff)); 121 return GetMax(GetMax(diff_a, diff_r), GetMax(diff_g, diff_b)); 122 } 123 124 static int MaxDiffAroundPixel(uint32_t current, uint32_t up, uint32_t down, 125 uint32_t left, uint32_t right) { 126 const int diff_up = MaxDiffBetweenPixels(current, up); 127 const int diff_down = MaxDiffBetweenPixels(current, down); 128 const int diff_left = MaxDiffBetweenPixels(current, left); 129 const int diff_right = MaxDiffBetweenPixels(current, right); 130 return GetMax(GetMax(diff_up, diff_down), GetMax(diff_left, diff_right)); 131 } 132 133 static uint32_t AddGreenToBlueAndRed(uint32_t argb) { 134 const uint32_t green = (argb >> 8) & 0xff; 135 uint32_t red_blue = argb & 0x00ff00ffu; 136 red_blue += (green << 16) | green; 137 red_blue &= 0x00ff00ffu; 138 return (argb & 0xff00ff00u) | red_blue; 139 } 140 141 static void MaxDiffsForRow(int width, int stride, const uint32_t* const argb, 142 uint8_t* const max_diffs, int used_subtract_green) { 143 uint32_t current, up, down, left, right; 144 int x; 145 if (width <= 2) return; 146 current = argb[0]; 147 right = argb[1]; 148 if (used_subtract_green) { 149 current = AddGreenToBlueAndRed(current); 150 right = AddGreenToBlueAndRed(right); 151 } 152 // max_diffs[0] and max_diffs[width - 1] are never used. 153 for (x = 1; x < width - 1; ++x) { 154 up = argb[-stride + x]; 155 down = argb[stride + x]; 156 left = current; 157 current = right; 158 right = argb[x + 1]; 159 if (used_subtract_green) { 160 up = AddGreenToBlueAndRed(up); 161 down = AddGreenToBlueAndRed(down); 162 right = AddGreenToBlueAndRed(right); 163 } 164 max_diffs[x] = MaxDiffAroundPixel(current, up, down, left, right); 165 } 166 } 167 168 // Quantize the difference between the actual component value and its prediction 169 // to a multiple of quantization, working modulo 256, taking care not to cross 170 // a boundary (inclusive upper limit). 171 static uint8_t NearLosslessComponent(uint8_t value, uint8_t predict, 172 uint8_t boundary, int quantization) { 173 const int residual = (value - predict) & 0xff; 174 const int boundary_residual = (boundary - predict) & 0xff; 175 const int lower = residual & ~(quantization - 1); 176 const int upper = lower + quantization; 177 // Resolve ties towards a value closer to the prediction (i.e. towards lower 178 // if value comes after prediction and towards upper otherwise). 179 const int bias = ((boundary - value) & 0xff) < boundary_residual; 180 if (residual - lower < upper - residual + bias) { 181 // lower is closer to residual than upper. 182 if (residual > boundary_residual && lower <= boundary_residual) { 183 // Halve quantization step to avoid crossing boundary. This midpoint is 184 // on the same side of boundary as residual because midpoint >= residual 185 // (since lower is closer than upper) and residual is above the boundary. 186 return lower + (quantization >> 1); 187 } 188 return lower; 189 } else { 190 // upper is closer to residual than lower. 191 if (residual <= boundary_residual && upper > boundary_residual) { 192 // Halve quantization step to avoid crossing boundary. This midpoint is 193 // on the same side of boundary as residual because midpoint <= residual 194 // (since upper is closer than lower) and residual is below the boundary. 195 return lower + (quantization >> 1); 196 } 197 return upper & 0xff; 198 } 199 } 200 201 static WEBP_INLINE uint8_t NearLosslessDiff(uint8_t a, uint8_t b) { 202 return (uint8_t)((((int)(a) - (int)(b))) & 0xff); 203 } 204 205 // Quantize every component of the difference between the actual pixel value and 206 // its prediction to a multiple of a quantization (a power of 2, not larger than 207 // max_quantization which is a power of 2, smaller than max_diff). Take care if 208 // value and predict have undergone subtract green, which means that red and 209 // blue are represented as offsets from green. 210 static uint32_t NearLossless(uint32_t value, uint32_t predict, 211 int max_quantization, int max_diff, 212 int used_subtract_green) { 213 int quantization; 214 uint8_t new_green = 0; 215 uint8_t green_diff = 0; 216 uint8_t a, r, g, b; 217 if (max_diff <= 2) { 218 return VP8LSubPixels(value, predict); 219 } 220 quantization = max_quantization; 221 while (quantization >= max_diff) { 222 quantization >>= 1; 223 } 224 if ((value >> 24) == 0 || (value >> 24) == 0xff) { 225 // Preserve transparency of fully transparent or fully opaque pixels. 226 a = NearLosslessDiff((value >> 24) & 0xff, (predict >> 24) & 0xff); 227 } else { 228 a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization); 229 } 230 g = NearLosslessComponent((value >> 8) & 0xff, (predict >> 8) & 0xff, 0xff, 231 quantization); 232 if (used_subtract_green) { 233 // The green offset will be added to red and blue components during decoding 234 // to obtain the actual red and blue values. 235 new_green = ((predict >> 8) + g) & 0xff; 236 // The amount by which green has been adjusted during quantization. It is 237 // subtracted from red and blue for compensation, to avoid accumulating two 238 // quantization errors in them. 239 green_diff = NearLosslessDiff(new_green, (value >> 8) & 0xff); 240 } 241 r = NearLosslessComponent(NearLosslessDiff((value >> 16) & 0xff, green_diff), 242 (predict >> 16) & 0xff, 0xff - new_green, 243 quantization); 244 b = NearLosslessComponent(NearLosslessDiff(value & 0xff, green_diff), 245 predict & 0xff, 0xff - new_green, quantization); 246 return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; 247 } 248 #endif // (WEBP_NEAR_LOSSLESS == 1) 249 250 // Stores the difference between the pixel and its prediction in "out". 251 // In case of a lossy encoding, updates the source image to avoid propagating 252 // the deviation further to pixels which depend on the current pixel for their 253 // predictions. 254 static WEBP_INLINE void GetResidual( 255 int width, int height, uint32_t* const upper_row, 256 uint32_t* const current_row, const uint8_t* const max_diffs, int mode, 257 int x_start, int x_end, int y, int max_quantization, int exact, 258 int used_subtract_green, uint32_t* const out) { 259 if (exact) { 260 PredictBatch(mode, x_start, y, x_end - x_start, current_row, upper_row, 261 out); 262 } else { 263 const VP8LPredictorFunc pred_func = VP8LPredictors[mode]; 264 int x; 265 for (x = x_start; x < x_end; ++x) { 266 uint32_t predict; 267 uint32_t residual; 268 if (y == 0) { 269 predict = (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left. 270 } else if (x == 0) { 271 predict = upper_row[x]; // Top. 272 } else { 273 predict = pred_func(¤t_row[x - 1], upper_row + x); 274 } 275 #if (WEBP_NEAR_LOSSLESS == 1) 276 if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 || 277 x == 0 || x == width - 1) { 278 residual = VP8LSubPixels(current_row[x], predict); 279 } else { 280 residual = NearLossless(current_row[x], predict, max_quantization, 281 max_diffs[x], used_subtract_green); 282 // Update the source image. 283 current_row[x] = VP8LAddPixels(predict, residual); 284 // x is never 0 here so we do not need to update upper_row like below. 285 } 286 #else 287 (void)max_diffs; 288 (void)height; 289 (void)max_quantization; 290 (void)used_subtract_green; 291 residual = VP8LSubPixels(current_row[x], predict); 292 #endif 293 if ((current_row[x] & kMaskAlpha) == 0) { 294 // If alpha is 0, cleanup RGB. We can choose the RGB values of the 295 // residual for best compression. The prediction of alpha itself can be 296 // non-zero and must be kept though. We choose RGB of the residual to be 297 // 0. 298 residual &= kMaskAlpha; 299 // Update the source image. 300 current_row[x] = predict & ~kMaskAlpha; 301 // The prediction for the rightmost pixel in a row uses the leftmost 302 // pixel 303 // in that row as its top-right context pixel. Hence if we change the 304 // leftmost pixel of current_row, the corresponding change must be 305 // applied 306 // to upper_row as well where top-right context is being read from. 307 if (x == 0 && y != 0) upper_row[width] = current_row[0]; 308 } 309 out[x - x_start] = residual; 310 } 311 } 312 } 313 314 // Accessors to residual histograms. 315 static WEBP_INLINE uint32_t* GetHistoArgb(uint32_t* const all_histos, 316 int subsampling_index, int mode) { 317 return &all_histos[(subsampling_index * kNumPredModes + mode) * HISTO_SIZE]; 318 } 319 320 static WEBP_INLINE const uint32_t* GetHistoArgbConst( 321 const uint32_t* const all_histos, int subsampling_index, int mode) { 322 return &all_histos[subsampling_index * kNumPredModes * HISTO_SIZE + 323 mode * HISTO_SIZE]; 324 } 325 326 // Accessors to accumulated residual histogram. 327 static WEBP_INLINE uint32_t* GetAccumulatedHisto(uint32_t* all_accumulated, 328 int subsampling_index) { 329 return &all_accumulated[subsampling_index * HISTO_SIZE]; 330 } 331 332 // Find and store the best predictor for a tile at subsampling 333 // 'subsampling_index'. 334 static void GetBestPredictorForTile(const uint32_t* const all_argb, 335 int subsampling_index, int tile_x, 336 int tile_y, int tiles_per_row, 337 uint32_t* all_accumulated_argb, 338 uint32_t** const all_modes, 339 uint32_t* const all_pred_histos) { 340 uint32_t* const accumulated_argb = 341 GetAccumulatedHisto(all_accumulated_argb, subsampling_index); 342 uint32_t* const modes = all_modes[subsampling_index]; 343 uint32_t* const pred_histos = 344 &all_pred_histos[subsampling_index * kNumPredModes]; 345 // Prediction modes of the left and above neighbor tiles. 346 const int left_mode = 347 (tile_x > 0) ? (modes[tile_y * tiles_per_row + tile_x - 1] >> 8) & 0xff 348 : 0xff; 349 const int above_mode = 350 (tile_y > 0) ? (modes[(tile_y - 1) * tiles_per_row + tile_x] >> 8) & 0xff 351 : 0xff; 352 int mode; 353 int64_t best_diff = WEBP_INT64_MAX; 354 uint32_t best_mode = 0; 355 const uint32_t* best_histo = 356 GetHistoArgbConst(all_argb, /*subsampling_index=*/0, best_mode); 357 for (mode = 0; mode < kNumPredModes; ++mode) { 358 const uint32_t* const histo_argb = 359 GetHistoArgbConst(all_argb, subsampling_index, mode); 360 const int64_t cur_diff = PredictionCostSpatialHistogram( 361 accumulated_argb, histo_argb, mode, left_mode, above_mode); 362 363 if (cur_diff < best_diff) { 364 best_histo = histo_argb; 365 best_diff = cur_diff; 366 best_mode = mode; 367 } 368 } 369 // Update the accumulated histogram. 370 VP8LAddVectorEq(best_histo, accumulated_argb, HISTO_SIZE); 371 modes[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (best_mode << 8); 372 ++pred_histos[best_mode]; 373 } 374 375 // Computes the residuals for the different predictors. 376 // If max_quantization > 1, assumes that near lossless processing will be 377 // applied, quantizing residuals to multiples of quantization levels up to 378 // max_quantization (the actual quantization level depends on smoothness near 379 // the given pixel). 380 static void ComputeResidualsForTile( 381 int width, int height, int tile_x, int tile_y, int min_bits, 382 uint32_t update_up_to_index, uint32_t* const all_argb, 383 uint32_t* const argb_scratch, const uint32_t* const argb, 384 int max_quantization, int exact, int used_subtract_green) { 385 const int start_x = tile_x << min_bits; 386 const int start_y = tile_y << min_bits; 387 const int tile_size = 1 << min_bits; 388 const int max_y = GetMin(tile_size, height - start_y); 389 const int max_x = GetMin(tile_size, width - start_x); 390 // Whether there exist columns just outside the tile. 391 const int have_left = (start_x > 0); 392 // Position and size of the strip covering the tile and adjacent columns if 393 // they exist. 394 const int context_start_x = start_x - have_left; 395 #if (WEBP_NEAR_LOSSLESS == 1) 396 const int context_width = max_x + have_left + (max_x < width - start_x); 397 #endif 398 // The width of upper_row and current_row is one pixel larger than image width 399 // to allow the top right pixel to point to the leftmost pixel of the next row 400 // when at the right edge. 401 uint32_t* upper_row = argb_scratch; 402 uint32_t* current_row = upper_row + width + 1; 403 uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1); 404 int mode; 405 // Need pointers to be able to swap arrays. 406 uint32_t residuals[1 << MAX_TRANSFORM_BITS]; 407 assert(max_x <= (1 << MAX_TRANSFORM_BITS)); 408 for (mode = 0; mode < kNumPredModes; ++mode) { 409 int relative_y; 410 uint32_t* const histo_argb = 411 GetHistoArgb(all_argb, /*subsampling_index=*/0, mode); 412 if (start_y > 0) { 413 // Read the row above the tile which will become the first upper_row. 414 // Include a pixel to the left if it exists; include a pixel to the right 415 // in all cases (wrapping to the leftmost pixel of the next row if it does 416 // not exist). 417 memcpy(current_row + context_start_x, 418 argb + (start_y - 1) * width + context_start_x, 419 sizeof(*argb) * (max_x + have_left + 1)); 420 } 421 for (relative_y = 0; relative_y < max_y; ++relative_y) { 422 const int y = start_y + relative_y; 423 int relative_x; 424 uint32_t* tmp = upper_row; 425 upper_row = current_row; 426 current_row = tmp; 427 // Read current_row. Include a pixel to the left if it exists; include a 428 // pixel to the right in all cases except at the bottom right corner of 429 // the image (wrapping to the leftmost pixel of the next row if it does 430 // not exist in the current row). 431 memcpy(current_row + context_start_x, 432 argb + y * width + context_start_x, 433 sizeof(*argb) * (max_x + have_left + (y + 1 < height))); 434 #if (WEBP_NEAR_LOSSLESS == 1) 435 if (max_quantization > 1 && y >= 1 && y + 1 < height) { 436 MaxDiffsForRow(context_width, width, argb + y * width + context_start_x, 437 max_diffs + context_start_x, used_subtract_green); 438 } 439 #endif 440 441 GetResidual(width, height, upper_row, current_row, max_diffs, mode, 442 start_x, start_x + max_x, y, max_quantization, exact, 443 used_subtract_green, residuals); 444 for (relative_x = 0; relative_x < max_x; ++relative_x) { 445 UpdateHisto(histo_argb, residuals[relative_x]); 446 } 447 if (update_up_to_index > 0) { 448 uint32_t subsampling_index; 449 for (subsampling_index = 1; subsampling_index <= update_up_to_index; 450 ++subsampling_index) { 451 uint32_t* const super_histo = 452 GetHistoArgb(all_argb, subsampling_index, mode); 453 for (relative_x = 0; relative_x < max_x; ++relative_x) { 454 UpdateHisto(super_histo, residuals[relative_x]); 455 } 456 } 457 } 458 } 459 } 460 } 461 462 // Converts pixels of the image to residuals with respect to predictions. 463 // If max_quantization > 1, applies near lossless processing, quantizing 464 // residuals to multiples of quantization levels up to max_quantization 465 // (the actual quantization level depends on smoothness near the given pixel). 466 static void CopyImageWithPrediction(int width, int height, int bits, 467 const uint32_t* const modes, 468 uint32_t* const argb_scratch, 469 uint32_t* const argb, int low_effort, 470 int max_quantization, int exact, 471 int used_subtract_green) { 472 const int tiles_per_row = VP8LSubSampleSize(width, bits); 473 // The width of upper_row and current_row is one pixel larger than image width 474 // to allow the top right pixel to point to the leftmost pixel of the next row 475 // when at the right edge. 476 uint32_t* upper_row = argb_scratch; 477 uint32_t* current_row = upper_row + width + 1; 478 uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1); 479 #if (WEBP_NEAR_LOSSLESS == 1) 480 uint8_t* lower_max_diffs = current_max_diffs + width; 481 #endif 482 int y; 483 484 for (y = 0; y < height; ++y) { 485 int x; 486 uint32_t* const tmp32 = upper_row; 487 upper_row = current_row; 488 current_row = tmp32; 489 memcpy(current_row, argb + y * width, 490 sizeof(*argb) * (width + (y + 1 < height))); 491 492 if (low_effort) { 493 PredictBatch(kPredLowEffort, 0, y, width, current_row, upper_row, 494 argb + y * width); 495 } else { 496 #if (WEBP_NEAR_LOSSLESS == 1) 497 if (max_quantization > 1) { 498 // Compute max_diffs for the lower row now, because that needs the 499 // contents of argb for the current row, which we will overwrite with 500 // residuals before proceeding with the next row. 501 uint8_t* const tmp8 = current_max_diffs; 502 current_max_diffs = lower_max_diffs; 503 lower_max_diffs = tmp8; 504 if (y + 2 < height) { 505 MaxDiffsForRow(width, width, argb + (y + 1) * width, lower_max_diffs, 506 used_subtract_green); 507 } 508 } 509 #endif 510 for (x = 0; x < width;) { 511 const int mode = 512 (modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff; 513 int x_end = x + (1 << bits); 514 if (x_end > width) x_end = width; 515 GetResidual(width, height, upper_row, current_row, current_max_diffs, 516 mode, x, x_end, y, max_quantization, exact, 517 used_subtract_green, argb + y * width + x); 518 x = x_end; 519 } 520 } 521 } 522 } 523 524 // Checks whether 'image' can be subsampled by finding the biggest power of 2 525 // squares (defined by 'best_bits') of uniform value it is made out of. 526 void VP8LOptimizeSampling(uint32_t* const image, int full_width, 527 int full_height, int bits, int max_bits, 528 int* best_bits_out) { 529 int width = VP8LSubSampleSize(full_width, bits); 530 int height = VP8LSubSampleSize(full_height, bits); 531 int old_width, x, y, square_size; 532 int best_bits = bits; 533 *best_bits_out = bits; 534 // Check rows first. 535 while (best_bits < max_bits) { 536 const int new_square_size = 1 << (best_bits + 1 - bits); 537 int is_good = 1; 538 square_size = 1 << (best_bits - bits); 539 for (y = 0; y + square_size < height; y += new_square_size) { 540 // Check the first lines of consecutive line groups. 541 if (memcmp(&image[y * width], &image[(y + square_size) * width], 542 width * sizeof(*image)) != 0) { 543 is_good = 0; 544 break; 545 } 546 } 547 if (is_good) { 548 ++best_bits; 549 } else { 550 break; 551 } 552 } 553 if (best_bits == bits) return; 554 555 // Check columns. 556 while (best_bits > bits) { 557 int is_good = 1; 558 square_size = 1 << (best_bits - bits); 559 for (y = 0; is_good && y < height; ++y) { 560 for (x = 0; is_good && x < width; x += square_size) { 561 int i; 562 for (i = x + 1; i < GetMin(x + square_size, width); ++i) { 563 if (image[y * width + i] != image[y * width + x]) { 564 is_good = 0; 565 break; 566 } 567 } 568 } 569 } 570 if (is_good) { 571 break; 572 } 573 --best_bits; 574 } 575 if (best_bits == bits) return; 576 577 // Subsample the image. 578 old_width = width; 579 square_size = 1 << (best_bits - bits); 580 width = VP8LSubSampleSize(full_width, best_bits); 581 height = VP8LSubSampleSize(full_height, best_bits); 582 for (y = 0; y < height; ++y) { 583 for (x = 0; x < width; ++x) { 584 image[y * width + x] = image[square_size * (y * old_width + x)]; 585 } 586 } 587 *best_bits_out = best_bits; 588 } 589 590 // Computes the best predictor image. 591 // Finds the best predictors per tile. Once done, finds the best predictor image 592 // sampling. 593 // best_bits is set to 0 in case of error. 594 // The following requires some glossary: 595 // - a tile is a square of side 2^min_bits pixels. 596 // - a super-tile of a tile is a square of side 2^bits pixels with bits in 597 // [min_bits+1, max_bits]. 598 // - the max-tile of a tile is the square of 2^max_bits pixels containing it. 599 // If this max-tile crosses the border of an image, it is cropped. 600 // - tile, super-tiles and max_tile are aligned on powers of 2 in the original 601 // image. 602 // - coordinates for tile, super-tile, max-tile are respectively named 603 // tile_x, super_tile_x, max_tile_x at their bit scale. 604 // - in the max-tile, a tile has local coordinates (local_tile_x, local_tile_y). 605 // The tiles are processed in the following zigzag order to complete the 606 // super-tiles as soon as possible: 607 // 1 2| 5 6 608 // 3 4| 7 8 609 // -------------- 610 // 9 10| 13 14 611 // 11 12| 15 16 612 // When computing the residuals for a tile, the histogram of the above 613 // super-tile is updated. If this super-tile is finished, its histogram is used 614 // to update the histogram of the next super-tile and so on up to the max-tile. 615 static void GetBestPredictorsAndSubSampling( 616 int width, int height, const int min_bits, const int max_bits, 617 uint32_t* const argb_scratch, const uint32_t* const argb, 618 int max_quantization, int exact, int used_subtract_green, 619 const WebPPicture* const pic, int percent_range, int* const percent, 620 uint32_t** const all_modes, int* best_bits, uint32_t** best_mode) { 621 const uint32_t tiles_per_row = VP8LSubSampleSize(width, min_bits); 622 const uint32_t tiles_per_col = VP8LSubSampleSize(height, min_bits); 623 int64_t best_cost; 624 uint32_t subsampling_index; 625 const uint32_t max_subsampling_index = max_bits - min_bits; 626 // Compute the needed memory size for residual histograms, accumulated 627 // residual histograms and predictor histograms. 628 const int num_argb = (max_subsampling_index + 1) * kNumPredModes * HISTO_SIZE; 629 const int num_accumulated_rgb = (max_subsampling_index + 1) * HISTO_SIZE; 630 const int num_predictors = (max_subsampling_index + 1) * kNumPredModes; 631 uint32_t* const raw_data = (uint32_t*)WebPSafeCalloc( 632 num_argb + num_accumulated_rgb + num_predictors, sizeof(uint32_t)); 633 uint32_t* const all_argb = raw_data; 634 uint32_t* const all_accumulated_argb = all_argb + num_argb; 635 uint32_t* const all_pred_histos = all_accumulated_argb + num_accumulated_rgb; 636 const int max_tile_size = 1 << max_subsampling_index; // in tile size 637 int percent_start = *percent; 638 // When using the residuals of a tile for its super-tiles, you can either: 639 // - use each residual to update the histogram of the super-tile, with a cost 640 // of 4 * (1<<n)^2 increment operations (4 for the number of channels, and 641 // (1<<n)^2 for the number of pixels in the tile) 642 // - use the histogram of the tile to update the histogram of the super-tile, 643 // with a cost of HISTO_SIZE (1024) 644 // The first method is therefore faster until n==4. 'update_up_to_index' 645 // defines the maximum subsampling_index for which the residuals should be 646 // individually added to the super-tile histogram. 647 const uint32_t update_up_to_index = 648 GetMax(GetMin(4, max_bits), min_bits) - min_bits; 649 // Coordinates in the max-tile in tile units. 650 uint32_t local_tile_x = 0, local_tile_y = 0; 651 uint32_t max_tile_x = 0, max_tile_y = 0; 652 uint32_t tile_x = 0, tile_y = 0; 653 654 *best_bits = 0; 655 *best_mode = NULL; 656 if (raw_data == NULL) return; 657 658 while (tile_y < tiles_per_col) { 659 ComputeResidualsForTile(width, height, tile_x, tile_y, min_bits, 660 update_up_to_index, all_argb, argb_scratch, argb, 661 max_quantization, exact, used_subtract_green); 662 663 // Update all the super-tiles that are complete. 664 subsampling_index = 0; 665 while (1) { 666 const uint32_t super_tile_x = tile_x >> subsampling_index; 667 const uint32_t super_tile_y = tile_y >> subsampling_index; 668 const uint32_t super_tiles_per_row = 669 VP8LSubSampleSize(width, min_bits + subsampling_index); 670 GetBestPredictorForTile(all_argb, subsampling_index, super_tile_x, 671 super_tile_y, super_tiles_per_row, 672 all_accumulated_argb, all_modes, all_pred_histos); 673 if (subsampling_index == max_subsampling_index) break; 674 675 // Update the following super-tile histogram if it has not been updated 676 // yet. 677 ++subsampling_index; 678 if (subsampling_index > update_up_to_index && 679 subsampling_index <= max_subsampling_index) { 680 VP8LAddVectorEq( 681 GetHistoArgbConst(all_argb, subsampling_index - 1, /*mode=*/0), 682 GetHistoArgb(all_argb, subsampling_index, /*mode=*/0), 683 HISTO_SIZE * kNumPredModes); 684 } 685 // Check whether the super-tile is not complete (if the smallest tile 686 // is not at the end of a line/column or at the beginning of a super-tile 687 // of size (1 << subsampling_index)). 688 if (!((tile_x == (tiles_per_row - 1) || 689 (local_tile_x + 1) % (1 << subsampling_index) == 0) && 690 (tile_y == (tiles_per_col - 1) || 691 (local_tile_y + 1) % (1 << subsampling_index) == 0))) { 692 --subsampling_index; 693 // subsampling_index now is the index of the last finished super-tile. 694 break; 695 } 696 } 697 // Reset all the histograms belonging to finished tiles. 698 memset(all_argb, 0, 699 HISTO_SIZE * kNumPredModes * (subsampling_index + 1) * 700 sizeof(*all_argb)); 701 702 if (subsampling_index == max_subsampling_index) { 703 // If a new max-tile is started. 704 if (tile_x == (tiles_per_row - 1)) { 705 max_tile_x = 0; 706 ++max_tile_y; 707 } else { 708 ++max_tile_x; 709 } 710 local_tile_x = 0; 711 local_tile_y = 0; 712 } else { 713 // Proceed with the Z traversal. 714 uint32_t coord_x = local_tile_x >> subsampling_index; 715 uint32_t coord_y = local_tile_y >> subsampling_index; 716 if (tile_x == (tiles_per_row - 1) && coord_x % 2 == 0) { 717 ++coord_y; 718 } else { 719 if (coord_x % 2 == 0) { 720 ++coord_x; 721 } else { 722 // Z traversal. 723 ++coord_y; 724 --coord_x; 725 } 726 } 727 local_tile_x = coord_x << subsampling_index; 728 local_tile_y = coord_y << subsampling_index; 729 } 730 tile_x = max_tile_x * max_tile_size + local_tile_x; 731 tile_y = max_tile_y * max_tile_size + local_tile_y; 732 733 if (tile_x == 0 && 734 !WebPReportProgress( 735 pic, percent_start + percent_range * tile_y / tiles_per_col, 736 percent)) { 737 WebPSafeFree(raw_data); 738 return; 739 } 740 } 741 742 // Figure out the best sampling. 743 best_cost = WEBP_INT64_MAX; 744 for (subsampling_index = 0; subsampling_index <= max_subsampling_index; 745 ++subsampling_index) { 746 int plane; 747 const uint32_t* const accumulated = 748 GetAccumulatedHisto(all_accumulated_argb, subsampling_index); 749 int64_t cost = VP8LShannonEntropy( 750 &all_pred_histos[subsampling_index * kNumPredModes], kNumPredModes); 751 for (plane = 0; plane < 4; ++plane) { 752 cost += VP8LShannonEntropy(&accumulated[plane * 256], 256); 753 } 754 if (cost < best_cost) { 755 best_cost = cost; 756 *best_bits = min_bits + subsampling_index; 757 *best_mode = all_modes[subsampling_index]; 758 } 759 } 760 761 WebPSafeFree(raw_data); 762 763 VP8LOptimizeSampling(*best_mode, width, height, *best_bits, 764 MAX_TRANSFORM_BITS, best_bits); 765 } 766 767 // Finds the best predictor for each tile, and converts the image to residuals 768 // with respect to predictions. If near_lossless_quality < 100, applies 769 // near lossless processing, shaving off more bits of residuals for lower 770 // qualities. 771 int VP8LResidualImage(int width, int height, int min_bits, int max_bits, 772 int low_effort, uint32_t* const argb, 773 uint32_t* const argb_scratch, uint32_t* const image, 774 int near_lossless_quality, int exact, 775 int used_subtract_green, const WebPPicture* const pic, 776 int percent_range, int* const percent, 777 int* const best_bits) { 778 int percent_start = *percent; 779 const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality); 780 if (low_effort) { 781 const int tiles_per_row = VP8LSubSampleSize(width, max_bits); 782 const int tiles_per_col = VP8LSubSampleSize(height, max_bits); 783 int i; 784 for (i = 0; i < tiles_per_row * tiles_per_col; ++i) { 785 image[i] = ARGB_BLACK | (kPredLowEffort << 8); 786 } 787 *best_bits = max_bits; 788 } else { 789 // Allocate data to try all samplings from min_bits to max_bits. 790 int bits; 791 uint32_t sum_num_pixels = 0u; 792 uint32_t *modes_raw, *best_mode; 793 uint32_t* modes[MAX_TRANSFORM_BITS + 1]; 794 uint32_t num_pixels[MAX_TRANSFORM_BITS + 1]; 795 for (bits = min_bits; bits <= max_bits; ++bits) { 796 const int tiles_per_row = VP8LSubSampleSize(width, bits); 797 const int tiles_per_col = VP8LSubSampleSize(height, bits); 798 num_pixels[bits] = tiles_per_row * tiles_per_col; 799 sum_num_pixels += num_pixels[bits]; 800 } 801 modes_raw = (uint32_t*)WebPSafeMalloc(sum_num_pixels, sizeof(*modes_raw)); 802 if (modes_raw == NULL) return 0; 803 // Have modes point to the right global memory modes_raw. 804 modes[min_bits] = modes_raw; 805 for (bits = min_bits + 1; bits <= max_bits; ++bits) { 806 modes[bits] = modes[bits - 1] + num_pixels[bits - 1]; 807 } 808 // Find the best sampling. 809 GetBestPredictorsAndSubSampling( 810 width, height, min_bits, max_bits, argb_scratch, argb, max_quantization, 811 exact, used_subtract_green, pic, percent_range, percent, 812 &modes[min_bits], best_bits, &best_mode); 813 if (*best_bits == 0) { 814 WebPSafeFree(modes_raw); 815 return 0; 816 } 817 // Keep the best predictor image. 818 memcpy(image, best_mode, 819 VP8LSubSampleSize(width, *best_bits) * 820 VP8LSubSampleSize(height, *best_bits) * sizeof(*image)); 821 WebPSafeFree(modes_raw); 822 } 823 824 CopyImageWithPrediction(width, height, *best_bits, image, argb_scratch, argb, 825 low_effort, max_quantization, exact, 826 used_subtract_green); 827 return WebPReportProgress(pic, percent_start + percent_range, percent); 828 } 829 830 //------------------------------------------------------------------------------ 831 // Color transform functions. 832 833 static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) { 834 m->green_to_red = 0; 835 m->green_to_blue = 0; 836 m->red_to_blue = 0; 837 } 838 839 static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, 840 VP8LMultipliers* const m) { 841 m->green_to_red = (color_code >> 0) & 0xff; 842 m->green_to_blue = (color_code >> 8) & 0xff; 843 m->red_to_blue = (color_code >> 16) & 0xff; 844 } 845 846 static WEBP_INLINE uint32_t MultipliersToColorCode( 847 const VP8LMultipliers* const m) { 848 return 0xff000000u | 849 ((uint32_t)(m->red_to_blue) << 16) | 850 ((uint32_t)(m->green_to_blue) << 8) | 851 m->green_to_red; 852 } 853 854 static int64_t PredictionCostCrossColor(const uint32_t accumulated[256], 855 const uint32_t counts[256]) { 856 // Favor low entropy, locally and globally. 857 // Favor small absolute values for PredictionCostSpatial 858 static const uint64_t kExpValue = 240; 859 return (int64_t)VP8LCombinedShannonEntropy(counts, accumulated) + 860 PredictionCostBias(counts, 3, kExpValue); 861 } 862 863 static int64_t GetPredictionCostCrossColorRed( 864 const uint32_t* argb, int stride, int tile_width, int tile_height, 865 VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red, 866 const uint32_t accumulated_red_histo[256]) { 867 uint32_t histo[256] = { 0 }; 868 int64_t cur_diff; 869 870 VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height, 871 green_to_red, histo); 872 873 cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo); 874 if ((uint8_t)green_to_red == prev_x.green_to_red) { 875 // favor keeping the areas locally similar 876 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 877 } 878 if ((uint8_t)green_to_red == prev_y.green_to_red) { 879 // favor keeping the areas locally similar 880 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 881 } 882 if (green_to_red == 0) { 883 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 884 } 885 return cur_diff; 886 } 887 888 static void GetBestGreenToRed(const uint32_t* argb, int stride, int tile_width, 889 int tile_height, VP8LMultipliers prev_x, 890 VP8LMultipliers prev_y, int quality, 891 const uint32_t accumulated_red_histo[256], 892 VP8LMultipliers* const best_tx) { 893 const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6] 894 int green_to_red_best = 0; 895 int iter, offset; 896 int64_t best_diff = GetPredictionCostCrossColorRed( 897 argb, stride, tile_width, tile_height, prev_x, prev_y, green_to_red_best, 898 accumulated_red_histo); 899 for (iter = 0; iter < kMaxIters; ++iter) { 900 // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to 901 // one in color computation. Having initial delta here as 1 is sufficient 902 // to explore the range of (-2, 2). 903 const int delta = 32 >> iter; 904 // Try a negative and a positive delta from the best known value. 905 for (offset = -delta; offset <= delta; offset += 2 * delta) { 906 const int green_to_red_cur = offset + green_to_red_best; 907 const int64_t cur_diff = GetPredictionCostCrossColorRed( 908 argb, stride, tile_width, tile_height, prev_x, prev_y, 909 green_to_red_cur, accumulated_red_histo); 910 if (cur_diff < best_diff) { 911 best_diff = cur_diff; 912 green_to_red_best = green_to_red_cur; 913 } 914 } 915 } 916 best_tx->green_to_red = (green_to_red_best & 0xff); 917 } 918 919 static int64_t GetPredictionCostCrossColorBlue( 920 const uint32_t* argb, int stride, int tile_width, int tile_height, 921 VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_blue, 922 int red_to_blue, const uint32_t accumulated_blue_histo[256]) { 923 uint32_t histo[256] = { 0 }; 924 int64_t cur_diff; 925 926 VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height, 927 green_to_blue, red_to_blue, histo); 928 929 cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo); 930 if ((uint8_t)green_to_blue == prev_x.green_to_blue) { 931 // favor keeping the areas locally similar 932 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 933 } 934 if ((uint8_t)green_to_blue == prev_y.green_to_blue) { 935 // favor keeping the areas locally similar 936 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 937 } 938 if ((uint8_t)red_to_blue == prev_x.red_to_blue) { 939 // favor keeping the areas locally similar 940 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 941 } 942 if ((uint8_t)red_to_blue == prev_y.red_to_blue) { 943 // favor keeping the areas locally similar 944 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 945 } 946 if (green_to_blue == 0) { 947 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 948 } 949 if (red_to_blue == 0) { 950 cur_diff -= 3ll << LOG_2_PRECISION_BITS; 951 } 952 return cur_diff; 953 } 954 955 #define kGreenRedToBlueNumAxis 8 956 #define kGreenRedToBlueMaxIters 7 957 static void GetBestGreenRedToBlue(const uint32_t* argb, int stride, 958 int tile_width, int tile_height, 959 VP8LMultipliers prev_x, 960 VP8LMultipliers prev_y, int quality, 961 const uint32_t accumulated_blue_histo[256], 962 VP8LMultipliers* const best_tx) { 963 const int8_t offset[kGreenRedToBlueNumAxis][2] = 964 {{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}}; 965 const int8_t delta_lut[kGreenRedToBlueMaxIters] = { 16, 16, 8, 4, 2, 2, 2 }; 966 const int iters = 967 (quality < 25) ? 1 : (quality > 50) ? kGreenRedToBlueMaxIters : 4; 968 int green_to_blue_best = 0; 969 int red_to_blue_best = 0; 970 int iter; 971 // Initial value at origin: 972 int64_t best_diff = GetPredictionCostCrossColorBlue( 973 argb, stride, tile_width, tile_height, prev_x, prev_y, green_to_blue_best, 974 red_to_blue_best, accumulated_blue_histo); 975 for (iter = 0; iter < iters; ++iter) { 976 const int delta = delta_lut[iter]; 977 int axis; 978 for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) { 979 const int green_to_blue_cur = 980 offset[axis][0] * delta + green_to_blue_best; 981 const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best; 982 const int64_t cur_diff = GetPredictionCostCrossColorBlue( 983 argb, stride, tile_width, tile_height, prev_x, prev_y, 984 green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo); 985 if (cur_diff < best_diff) { 986 best_diff = cur_diff; 987 green_to_blue_best = green_to_blue_cur; 988 red_to_blue_best = red_to_blue_cur; 989 } 990 if (quality < 25 && iter == 4) { 991 // Only axis aligned diffs for lower quality. 992 break; // next iter. 993 } 994 } 995 if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) { 996 // Further iterations would not help. 997 break; // out of iter-loop. 998 } 999 } 1000 best_tx->green_to_blue = green_to_blue_best & 0xff; 1001 best_tx->red_to_blue = red_to_blue_best & 0xff; 1002 } 1003 #undef kGreenRedToBlueMaxIters 1004 #undef kGreenRedToBlueNumAxis 1005 1006 static VP8LMultipliers GetBestColorTransformForTile( 1007 int tile_x, int tile_y, int bits, VP8LMultipliers prev_x, 1008 VP8LMultipliers prev_y, int quality, int xsize, int ysize, 1009 const uint32_t accumulated_red_histo[256], 1010 const uint32_t accumulated_blue_histo[256], const uint32_t* const argb) { 1011 const int max_tile_size = 1 << bits; 1012 const int tile_y_offset = tile_y * max_tile_size; 1013 const int tile_x_offset = tile_x * max_tile_size; 1014 const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize); 1015 const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize); 1016 const int tile_width = all_x_max - tile_x_offset; 1017 const int tile_height = all_y_max - tile_y_offset; 1018 const uint32_t* const tile_argb = argb + tile_y_offset * xsize 1019 + tile_x_offset; 1020 VP8LMultipliers best_tx; 1021 MultipliersClear(&best_tx); 1022 1023 GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height, 1024 prev_x, prev_y, quality, accumulated_red_histo, &best_tx); 1025 GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height, 1026 prev_x, prev_y, quality, accumulated_blue_histo, 1027 &best_tx); 1028 return best_tx; 1029 } 1030 1031 static void CopyTileWithColorTransform(int xsize, int ysize, 1032 int tile_x, int tile_y, 1033 int max_tile_size, 1034 VP8LMultipliers color_transform, 1035 uint32_t* argb) { 1036 const int xscan = GetMin(max_tile_size, xsize - tile_x); 1037 int yscan = GetMin(max_tile_size, ysize - tile_y); 1038 argb += tile_y * xsize + tile_x; 1039 while (yscan-- > 0) { 1040 VP8LTransformColor(&color_transform, argb, xscan); 1041 argb += xsize; 1042 } 1043 } 1044 1045 int VP8LColorSpaceTransform(int width, int height, int bits, int quality, 1046 uint32_t* const argb, uint32_t* image, 1047 const WebPPicture* const pic, int percent_range, 1048 int* const percent, int* const best_bits) { 1049 const int max_tile_size = 1 << bits; 1050 const int tile_xsize = VP8LSubSampleSize(width, bits); 1051 const int tile_ysize = VP8LSubSampleSize(height, bits); 1052 int percent_start = *percent; 1053 uint32_t accumulated_red_histo[256] = { 0 }; 1054 uint32_t accumulated_blue_histo[256] = { 0 }; 1055 int tile_x, tile_y; 1056 VP8LMultipliers prev_x, prev_y; 1057 MultipliersClear(&prev_y); 1058 MultipliersClear(&prev_x); 1059 for (tile_y = 0; tile_y < tile_ysize; ++tile_y) { 1060 for (tile_x = 0; tile_x < tile_xsize; ++tile_x) { 1061 int y; 1062 const int tile_x_offset = tile_x * max_tile_size; 1063 const int tile_y_offset = tile_y * max_tile_size; 1064 const int all_x_max = GetMin(tile_x_offset + max_tile_size, width); 1065 const int all_y_max = GetMin(tile_y_offset + max_tile_size, height); 1066 const int offset = tile_y * tile_xsize + tile_x; 1067 if (tile_y != 0) { 1068 ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y); 1069 } 1070 prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits, 1071 prev_x, prev_y, 1072 quality, width, height, 1073 accumulated_red_histo, 1074 accumulated_blue_histo, 1075 argb); 1076 image[offset] = MultipliersToColorCode(&prev_x); 1077 CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset, 1078 max_tile_size, prev_x, argb); 1079 1080 // Gather accumulated histogram data. 1081 for (y = tile_y_offset; y < all_y_max; ++y) { 1082 int ix = y * width + tile_x_offset; 1083 const int ix_end = ix + all_x_max - tile_x_offset; 1084 for (; ix < ix_end; ++ix) { 1085 const uint32_t pix = argb[ix]; 1086 if (ix >= 2 && 1087 pix == argb[ix - 2] && 1088 pix == argb[ix - 1]) { 1089 continue; // repeated pixels are handled by backward references 1090 } 1091 if (ix >= width + 2 && 1092 argb[ix - 2] == argb[ix - width - 2] && 1093 argb[ix - 1] == argb[ix - width - 1] && 1094 pix == argb[ix - width]) { 1095 continue; // repeated pixels are handled by backward references 1096 } 1097 ++accumulated_red_histo[(pix >> 16) & 0xff]; 1098 ++accumulated_blue_histo[(pix >> 0) & 0xff]; 1099 } 1100 } 1101 } 1102 if (!WebPReportProgress( 1103 pic, percent_start + percent_range * tile_y / tile_ysize, 1104 percent)) { 1105 return 0; 1106 } 1107 } 1108 VP8LOptimizeSampling(image, width, height, bits, MAX_TRANSFORM_BITS, 1109 best_bits); 1110 return 1; 1111 }