Coverage Report

Created: 2026-09-14 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebp/src/enc/predictor_enc.c
Line
Count
Source
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
481M
#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
24.1M
static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
38
14.8G
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
458M
                                  uint64_t exp_val) {
48
458M
  const int significant_symbols = 256 >> 4;
49
458M
  const uint64_t exp_decay_factor = 6;  // has a scaling factor of 1/10
50
458M
  uint64_t bits = (weight_0 * counts[0]) << LOG_2_PRECISION_BITS;
51
458M
  int i;
52
458M
  exp_val <<= LOG_2_PRECISION_BITS;
53
7.33G
  for (i = 1; i < significant_symbols; ++i) {
54
6.87G
    bits += DivRound(exp_val * (counts[i] + counts[256 - i]), 100);
55
6.87G
    exp_val = DivRound(exp_decay_factor * exp_val, 10);
56
6.87G
  }
57
458M
  return -DivRound((int64_t)bits, 10);
58
458M
}
59
60
static int64_t PredictionCostSpatialHistogram(
61
    const uint32_t accumulated[HISTO_SIZE], const uint32_t tile[HISTO_SIZE],
62
92.9M
    int mode, int left_mode, int above_mode) {
63
92.9M
  int i;
64
92.9M
  int64_t retval = 0;
65
464M
  for (i = 0; i < 4; ++i) {
66
371M
    const uint64_t kExpValue = 94;
67
371M
    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
371M
    retval += (int64_t)VP8LCombinedShannonEntropy(&tile[i * 256],
72
371M
                                                  &accumulated[i * 256]);
73
371M
  }
74
  // Favor keeping the areas locally similar.
75
92.9M
  if (mode == left_mode) retval -= kSpatialPredictorBias;
76
92.9M
  if (mode == above_mode) retval -= kSpatialPredictorBias;
77
92.9M
  return retval;
78
92.9M
}
79
80
static WEBP_INLINE void UpdateHisto(uint32_t histo_argb[HISTO_SIZE],
81
2.91G
                                    uint32_t argb) {
82
2.91G
  ++histo_argb[0 * 256 + (argb >> 24)];
83
2.91G
  ++histo_argb[1 * 256 + ((argb >> 16) & 0xff)];
84
2.91G
  ++histo_argb[2 * 256 + ((argb >> 8) & 0xff)];
85
2.91G
  ++histo_argb[3 * 256 + (argb & 0xff)];
86
2.91G
}
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
225M
                                     const uint32_t* upper, uint32_t* out) {
94
225M
  if (x_start == 0) {
95
60.5M
    if (y == 0) {
96
      // ARGB_BLACK.
97
2.92M
      VP8LPredictorsSub[0](current, NULL, 1, out);
98
57.6M
    } else {
99
      // Top one.
100
57.6M
      VP8LPredictorsSub[2](current, upper, 1, out);
101
57.6M
    }
102
60.5M
    ++x_start;
103
60.5M
    ++out;
104
60.5M
    --num_pixels;
105
60.5M
  }
106
225M
  if (y == 0) {
107
    // Left one.
108
14.8M
    VP8LPredictorsSub[1](current + x_start, NULL, num_pixels, out);
109
210M
  } else {
110
210M
    VP8LPredictorsSub[mode](current + x_start, upper + x_start, num_pixels,
111
210M
                            out);
112
210M
  }
113
225M
}
114
115
#if (WEBP_NEAR_LOSSLESS == 1)
116
3.96G
static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) {
117
3.96G
  const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24));
118
3.96G
  const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff));
119
3.96G
  const int diff_g = abs((int)((p1 >> 8) & 0xff) - (int)((p2 >> 8) & 0xff));
120
3.96G
  const int diff_b = abs((int)(p1 & 0xff) - (int)(p2 & 0xff));
121
3.96G
  return GetMax(GetMax(diff_a, diff_r), GetMax(diff_g, diff_b));
122
3.96G
}
123
124
static int MaxDiffAroundPixel(uint32_t current, uint32_t up, uint32_t down,
125
992M
                              uint32_t left, uint32_t right) {
126
992M
  const int diff_up = MaxDiffBetweenPixels(current, up);
127
992M
  const int diff_down = MaxDiffBetweenPixels(current, down);
128
992M
  const int diff_left = MaxDiffBetweenPixels(current, left);
129
992M
  const int diff_right = MaxDiffBetweenPixels(current, right);
130
992M
  return GetMax(GetMax(diff_up, diff_down), GetMax(diff_left, diff_right));
131
992M
}
132
133
2.68G
static uint32_t AddGreenToBlueAndRed(uint32_t argb) {
134
2.68G
  const uint32_t green = (argb >> 8) & 0xff;
135
2.68G
  uint32_t red_blue = argb & 0x00ff00ffu;
136
2.68G
  red_blue += (green << 16) | green;
137
2.68G
  red_blue &= 0x00ff00ffu;
138
2.68G
  return (argb & 0xff00ff00u) | red_blue;
139
2.68G
}
140
141
static void MaxDiffsForRow(int width, int stride, const uint32_t* const argb,
142
124M
                           uint8_t* const max_diffs, int used_subtract_green) {
143
124M
  uint32_t current, up, down, left, right;
144
124M
  int x;
145
124M
  if (width <= 2) return;
146
117M
  current = argb[0];
147
117M
  right = argb[1];
148
117M
  if (used_subtract_green) {
149
96.7M
    current = AddGreenToBlueAndRed(current);
150
96.7M
    right = AddGreenToBlueAndRed(right);
151
96.7M
  }
152
  // max_diffs[0] and max_diffs[width - 1] are never used.
153
1.11G
  for (x = 1; x < width - 1; ++x) {
154
992M
    up = argb[-stride + x];
155
992M
    down = argb[stride + x];
156
992M
    left = current;
157
992M
    current = right;
158
992M
    right = argb[x + 1];
159
992M
    if (used_subtract_green) {
160
831M
      up = AddGreenToBlueAndRed(up);
161
831M
      down = AddGreenToBlueAndRed(down);
162
831M
      right = AddGreenToBlueAndRed(right);
163
831M
    }
164
992M
    max_diffs[x] = MaxDiffAroundPixel(current, up, down, left, right);
165
992M
  }
166
117M
}
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
1.41G
                                     uint8_t boundary, int quantization) {
173
1.41G
  const int residual = (value - predict) & 0xff;
174
1.41G
  const int boundary_residual = (boundary - predict) & 0xff;
175
1.41G
  const int lower = residual & ~(quantization - 1);
176
1.41G
  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
1.41G
  const int bias = ((boundary - value) & 0xff) < boundary_residual;
180
1.41G
  if (residual - lower < upper - residual + bias) {
181
    // lower is closer to residual than upper.
182
925M
    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
4.15M
      return lower + (quantization >> 1);
187
4.15M
    }
188
920M
    return lower;
189
925M
  } else {
190
    // upper is closer to residual than lower.
191
491M
    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
5.59M
      return lower + (quantization >> 1);
196
5.59M
    }
197
486M
    return upper & 0xff;
198
491M
  }
199
1.41G
}
200
201
1.64G
static WEBP_INLINE uint8_t NearLosslessDiff(uint8_t a, uint8_t b) {
202
1.64G
  return (uint8_t)((((int)(a) - (int)(b))) & 0xff);
203
1.64G
}
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
541M
                             int used_subtract_green) {
213
541M
  int quantization;
214
541M
  uint8_t new_green = 0;
215
541M
  uint8_t green_diff = 0;
216
541M
  uint8_t a, r, g, b;
217
541M
  if (max_diff <= 2) {
218
93.1M
    return VP8LSubPixels(value, predict);
219
93.1M
  }
220
447M
  quantization = max_quantization;
221
889M
  while (quantization >= max_diff) {
222
441M
    quantization >>= 1;
223
441M
  }
224
447M
  if ((value >> 24) == 0 || (value >> 24) == 0xff) {
225
    // Preserve transparency of fully transparent or fully opaque pixels.
226
374M
    a = NearLosslessDiff((value >> 24) & 0xff, (predict >> 24) & 0xff);
227
374M
  } else {
228
73.5M
    a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization);
229
73.5M
  }
230
447M
  g = NearLosslessComponent((value >> 8) & 0xff, (predict >> 8) & 0xff, 0xff,
231
447M
                            quantization);
232
447M
  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
375M
    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
375M
    green_diff = NearLosslessDiff(new_green, (value >> 8) & 0xff);
240
375M
  }
241
447M
  r = NearLosslessComponent(NearLosslessDiff((value >> 16) & 0xff, green_diff),
242
447M
                            (predict >> 16) & 0xff, 0xff - new_green,
243
447M
                            quantization);
244
447M
  b = NearLosslessComponent(NearLosslessDiff(value & 0xff, green_diff),
245
447M
                            predict & 0xff, 0xff - new_green, quantization);
246
447M
  return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
247
541M
}
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
353M
    int used_subtract_green, uint32_t* const out) {
259
353M
  if (exact) {
260
225M
    PredictBatch(mode, x_start, y, x_end - x_start, current_row, upper_row,
261
225M
                 out);
262
225M
  } else {
263
127M
    const VP8LPredictorFunc pred_func = VP8LPredictors[mode];
264
127M
    int x;
265
1.01G
    for (x = x_start; x < x_end; ++x) {
266
885M
      uint32_t predict;
267
885M
      uint32_t residual;
268
885M
      if (y == 0) {
269
18.1M
        predict = (x == 0) ? ARGB_BLACK : current_row[x - 1];  // Left.
270
867M
      } else if (x == 0) {
271
19.0M
        predict = upper_row[x];  // Top.
272
848M
      } else {
273
848M
        predict = pred_func(&current_row[x - 1], upper_row + x);
274
848M
      }
275
885M
#if (WEBP_NEAR_LOSSLESS == 1)
276
885M
      if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 ||
277
558M
          x == 0 || x == width - 1) {
278
344M
        residual = VP8LSubPixels(current_row[x], predict);
279
540M
      } else {
280
540M
        residual = NearLossless(current_row[x], predict, max_quantization,
281
540M
                                max_diffs[x], used_subtract_green);
282
        // Update the source image.
283
540M
        current_row[x] = VP8LAddPixels(predict, residual);
284
        // x is never 0 here so we do not need to update upper_row like below.
285
540M
      }
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
885M
      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
10.5M
        residual &= kMaskAlpha;
299
        // Update the source image.
300
10.5M
        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
10.5M
        if (x == 0 && y != 0) upper_row[width] = current_row[0];
308
10.5M
      }
309
885M
      out[x - x_start] = residual;
310
885M
    }
311
127M
  }
312
353M
}
313
314
// Accessors to residual histograms.
315
static WEBP_INLINE uint32_t* GetHistoArgb(uint32_t* const all_histos,
316
263M
                                          int subsampling_index, int mode) {
317
263M
  return &all_histos[(subsampling_index * kNumPredModes + mode) * HISTO_SIZE];
318
263M
}
319
320
static WEBP_INLINE const uint32_t* GetHistoArgbConst(
321
99.6M
    const uint32_t* const all_histos, int subsampling_index, int mode) {
322
99.6M
  return &all_histos[subsampling_index * kNumPredModes * HISTO_SIZE +
323
99.6M
                     mode * HISTO_SIZE];
324
99.6M
}
325
326
// Accessors to accumulated residual histogram.
327
static WEBP_INLINE uint32_t* GetAccumulatedHisto(uint32_t* all_accumulated,
328
7.05M
                                                 int subsampling_index) {
329
7.05M
  return &all_accumulated[subsampling_index * HISTO_SIZE];
330
7.05M
}
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
6.64M
                                    uint32_t* const all_pred_histos) {
340
6.64M
  uint32_t* const accumulated_argb =
341
6.64M
      GetAccumulatedHisto(all_accumulated_argb, subsampling_index);
342
6.64M
  uint32_t* const modes = all_modes[subsampling_index];
343
6.64M
  uint32_t* const pred_histos =
344
6.64M
      &all_pred_histos[subsampling_index * kNumPredModes];
345
  // Prediction modes of the left and above neighbor tiles.
346
6.64M
  const int left_mode =
347
6.64M
      (tile_x > 0) ? (modes[tile_y * tiles_per_row + tile_x - 1] >> 8) & 0xff
348
6.64M
                   : 0xff;
349
6.64M
  const int above_mode =
350
6.64M
      (tile_y > 0) ? (modes[(tile_y - 1) * tiles_per_row + tile_x] >> 8) & 0xff
351
6.64M
                   : 0xff;
352
6.64M
  int mode;
353
6.64M
  int64_t best_diff = WEBP_INT64_MAX;
354
6.64M
  uint32_t best_mode = 0;
355
6.64M
  const uint32_t* best_histo =
356
6.64M
      GetHistoArgbConst(all_argb, /*subsampling_index=*/0, best_mode);
357
99.6M
  for (mode = 0; mode < kNumPredModes; ++mode) {
358
92.9M
    const uint32_t* const histo_argb =
359
92.9M
        GetHistoArgbConst(all_argb, subsampling_index, mode);
360
92.9M
    const int64_t cur_diff = PredictionCostSpatialHistogram(
361
92.9M
        accumulated_argb, histo_argb, mode, left_mode, above_mode);
362
363
92.9M
    if (cur_diff < best_diff) {
364
17.7M
      best_histo = histo_argb;
365
17.7M
      best_diff = cur_diff;
366
17.7M
      best_mode = mode;
367
17.7M
    }
368
92.9M
  }
369
  // Update the accumulated histogram.
370
6.64M
  VP8LAddVectorEq(best_histo, accumulated_argb, HISTO_SIZE);
371
6.64M
  modes[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (best_mode << 8);
372
6.64M
  ++pred_histos[best_mode];
373
6.64M
}
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
5.33M
    int max_quantization, int exact, int used_subtract_green) {
385
5.33M
  const int start_x = tile_x << min_bits;
386
5.33M
  const int start_y = tile_y << min_bits;
387
5.33M
  const int tile_size = 1 << min_bits;
388
5.33M
  const int max_y = GetMin(tile_size, height - start_y);
389
5.33M
  const int max_x = GetMin(tile_size, width - start_x);
390
  // Whether there exist columns just outside the tile.
391
5.33M
  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
5.33M
  const int context_start_x = start_x - have_left;
395
5.33M
#if (WEBP_NEAR_LOSSLESS == 1)
396
5.33M
  const int context_width = max_x + have_left + (max_x < width - start_x);
397
5.33M
#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
5.33M
  uint32_t* upper_row = argb_scratch;
402
5.33M
  uint32_t* current_row = upper_row + width + 1;
403
5.33M
  uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1);
404
5.33M
  int mode;
405
  // Need pointers to be able to swap arrays.
406
5.33M
  uint32_t residuals[1 << MAX_TRANSFORM_BITS];
407
5.33M
  assert(max_x <= (1 << MAX_TRANSFORM_BITS));
408
79.9M
  for (mode = 0; mode < kNumPredModes; ++mode) {
409
74.6M
    int relative_y;
410
74.6M
    uint32_t* const histo_argb =
411
74.6M
        GetHistoArgb(all_argb, /*subsampling_index=*/0, mode);
412
74.6M
    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
56.6M
      memcpy(current_row + context_start_x,
418
56.6M
             argb + (start_y - 1) * width + context_start_x,
419
56.6M
             sizeof(*argb) * (max_x + have_left + 1));
420
56.6M
    }
421
409M
    for (relative_y = 0; relative_y < max_y; ++relative_y) {
422
334M
      const int y = start_y + relative_y;
423
334M
      int relative_x;
424
334M
      uint32_t* tmp = upper_row;
425
334M
      upper_row = current_row;
426
334M
      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
334M
      memcpy(current_row + context_start_x, argb + y * width + context_start_x,
432
334M
             sizeof(*argb) * (max_x + have_left + (y + 1 < height)));
433
334M
#if (WEBP_NEAR_LOSSLESS == 1)
434
334M
      if (max_quantization > 1 && y >= 1 && y + 1 < height) {
435
123M
        MaxDiffsForRow(context_width, width, argb + y * width + context_start_x,
436
123M
                       max_diffs + context_start_x, used_subtract_green);
437
123M
      }
438
334M
#endif
439
440
334M
      GetResidual(width, height, upper_row, current_row, max_diffs, mode,
441
334M
                  start_x, start_x + max_x, y, max_quantization, exact,
442
334M
                  used_subtract_green, residuals);
443
2.59G
      for (relative_x = 0; relative_x < max_x; ++relative_x) {
444
2.26G
        UpdateHisto(histo_argb, residuals[relative_x]);
445
2.26G
      }
446
334M
      if (update_up_to_index > 0) {
447
166M
        uint32_t subsampling_index;
448
355M
        for (subsampling_index = 1; subsampling_index <= update_up_to_index;
449
188M
             ++subsampling_index) {
450
188M
          uint32_t* const super_histo =
451
188M
              GetHistoArgb(all_argb, subsampling_index, mode);
452
835M
          for (relative_x = 0; relative_x < max_x; ++relative_x) {
453
647M
            UpdateHisto(super_histo, residuals[relative_x]);
454
647M
          }
455
188M
        }
456
166M
      }
457
334M
    }
458
74.6M
  }
459
5.33M
}
460
461
// Converts pixels of the image to residuals with respect to predictions.
462
// If max_quantization > 1, applies near lossless processing, quantizing
463
// residuals to multiples of quantization levels up to max_quantization
464
// (the actual quantization level depends on smoothness near the given pixel).
465
static void CopyImageWithPrediction(int width, int height, int bits,
466
                                    const uint32_t* const modes,
467
                                    uint32_t* const argb_scratch,
468
                                    uint32_t* const argb, int low_effort,
469
                                    int max_quantization, int exact,
470
247k
                                    int used_subtract_green) {
471
247k
  const int tiles_per_row = VP8LSubSampleSize(width, bits);
472
  // The width of upper_row and current_row is one pixel larger than image width
473
  // to allow the top right pixel to point to the leftmost pixel of the next row
474
  // when at the right edge.
475
247k
  uint32_t* upper_row = argb_scratch;
476
247k
  uint32_t* current_row = upper_row + width + 1;
477
247k
  uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1);
478
247k
#if (WEBP_NEAR_LOSSLESS == 1)
479
247k
  uint8_t* lower_max_diffs = current_max_diffs + width;
480
247k
#endif
481
247k
  int y;
482
483
5.82M
  for (y = 0; y < height; ++y) {
484
5.57M
    int x;
485
5.57M
    uint32_t* const tmp32 = upper_row;
486
5.57M
    upper_row = current_row;
487
5.57M
    current_row = tmp32;
488
5.57M
    memcpy(current_row, argb + y * width,
489
5.57M
           sizeof(*argb) * (width + (y + 1 < height)));
490
491
5.57M
    if (low_effort) {
492
234k
      PredictBatch(kPredLowEffort, 0, y, width, current_row, upper_row,
493
234k
                   argb + y * width);
494
5.34M
    } else {
495
5.34M
#if (WEBP_NEAR_LOSSLESS == 1)
496
5.34M
      if (max_quantization > 1) {
497
        // Compute max_diffs for the lower row now, because that needs the
498
        // contents of argb for the current row, which we will overwrite with
499
        // residuals before proceeding with the next row.
500
1.21M
        uint8_t* const tmp8 = current_max_diffs;
501
1.21M
        current_max_diffs = lower_max_diffs;
502
1.21M
        lower_max_diffs = tmp8;
503
1.21M
        if (y + 2 < height) {
504
1.15M
          MaxDiffsForRow(width, width, argb + (y + 1) * width, lower_max_diffs,
505
1.15M
                         used_subtract_green);
506
1.15M
        }
507
1.21M
      }
508
5.34M
#endif
509
23.7M
      for (x = 0; x < width;) {
510
18.4M
        const int mode =
511
18.4M
            (modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff;
512
18.4M
        int x_end = x + (1 << bits);
513
18.4M
        if (x_end > width) x_end = width;
514
18.4M
        GetResidual(width, height, upper_row, current_row, current_max_diffs,
515
18.4M
                    mode, x, x_end, y, max_quantization, exact,
516
18.4M
                    used_subtract_green, argb + y * width + x);
517
18.4M
        x = x_end;
518
18.4M
      }
519
5.34M
    }
520
5.57M
  }
521
247k
}
522
523
// Checks whether 'image' can be subsampled by finding the biggest power of 2
524
// squares (defined by 'best_bits') of uniform value it is made out of.
525
void VP8LOptimizeSampling(uint32_t* const image, int full_width,
526
                          int full_height, int bits, int max_bits,
527
298k
                          int* best_bits_out) {
528
298k
  int width = VP8LSubSampleSize(full_width, bits);
529
298k
  int height = VP8LSubSampleSize(full_height, bits);
530
298k
  int old_width, x, y, square_size;
531
298k
  int best_bits = bits;
532
298k
  *best_bits_out = bits;
533
  // Check rows first.
534
1.73M
  while (best_bits < max_bits) {
535
1.51M
    const int new_square_size = 1 << (best_bits + 1 - bits);
536
1.51M
    int is_good = 1;
537
1.51M
    square_size = 1 << (best_bits - bits);
538
2.15M
    for (y = 0; y + square_size < height; y += new_square_size) {
539
      // Check the first lines of consecutive line groups.
540
713k
      if (memcmp(&image[y * width], &image[(y + square_size) * width],
541
713k
                 width * sizeof(*image)) != 0) {
542
82.5k
        is_good = 0;
543
82.5k
        break;
544
82.5k
      }
545
713k
    }
546
1.51M
    if (is_good) {
547
1.43M
      ++best_bits;
548
1.43M
    } else {
549
82.5k
      break;
550
82.5k
    }
551
1.51M
  }
552
298k
  if (best_bits == bits) return;
553
554
  // Check columns.
555
346k
  while (best_bits > bits) {
556
326k
    int is_good = 1;
557
326k
    square_size = 1 << (best_bits - bits);
558
1.26M
    for (y = 0; is_good && y < height; ++y) {
559
1.93M
      for (x = 0; is_good && x < width; x += square_size) {
560
999k
        int i;
561
2.21M
        for (i = x + 1; i < GetMin(x + square_size, width); ++i) {
562
1.34M
          if (image[y * width + i] != image[y * width + x]) {
563
127k
            is_good = 0;
564
127k
            break;
565
127k
          }
566
1.34M
        }
567
999k
      }
568
935k
    }
569
326k
    if (is_good) {
570
199k
      break;
571
199k
    }
572
127k
    --best_bits;
573
127k
  }
574
219k
  if (best_bits == bits) return;
575
576
  // Subsample the image.
577
199k
  old_width = width;
578
199k
  square_size = 1 << (best_bits - bits);
579
199k
  width = VP8LSubSampleSize(full_width, best_bits);
580
199k
  height = VP8LSubSampleSize(full_height, best_bits);
581
406k
  for (y = 0; y < height; ++y) {
582
435k
    for (x = 0; x < width; ++x) {
583
227k
      image[y * width + x] = image[square_size * (y * old_width + x)];
584
227k
    }
585
207k
  }
586
199k
  *best_bits_out = best_bits;
587
199k
}
588
589
// Computes the best predictor image.
590
// Finds the best predictors per tile. Once done, finds the best predictor image
591
// sampling.
592
// best_bits is set to 0 in case of error.
593
// The following requires some glossary:
594
// - a tile is a square of side 2^min_bits pixels.
595
// - a super-tile of a tile is a square of side 2^bits pixels with bits in
596
// [min_bits+1, max_bits].
597
// - the max-tile of a tile is the square of 2^max_bits pixels containing it.
598
//   If this max-tile crosses the border of an image, it is cropped.
599
// - tile, super-tiles and max_tile are aligned on powers of 2 in the original
600
//   image.
601
// - coordinates for tile, super-tile, max-tile are respectively named
602
//   tile_x, super_tile_x, max_tile_x at their bit scale.
603
// - in the max-tile, a tile has local coordinates (local_tile_x, local_tile_y).
604
// The tiles are processed in the following zigzag order to complete the
605
// super-tiles as soon as possible:
606
//   1  2|  5  6
607
//   3  4|  7  8
608
// --------------
609
//   9 10| 13 14
610
//  11 12| 15 16
611
// When computing the residuals for a tile, the histogram of the above
612
// super-tile is updated. If this super-tile is finished, its histogram is used
613
// to update the histogram of the next super-tile and so on up to the max-tile.
614
static void GetBestPredictorsAndSubSampling(
615
    int width, int height, const int min_bits, const int max_bits,
616
    uint32_t* const argb_scratch, const uint32_t* const argb,
617
    int max_quantization, int exact, int used_subtract_green,
618
    const WebPPicture* const pic, int percent_range, int* const percent,
619
245k
    uint32_t** const all_modes, int* best_bits, uint32_t** best_mode) {
620
245k
  const uint32_t tiles_per_row = VP8LSubSampleSize(width, min_bits);
621
245k
  const uint32_t tiles_per_col = VP8LSubSampleSize(height, min_bits);
622
245k
  int64_t best_cost;
623
245k
  uint32_t subsampling_index;
624
245k
  const uint32_t max_subsampling_index = max_bits - min_bits;
625
  // Compute the needed memory size for residual histograms, accumulated
626
  // residual histograms and predictor histograms.
627
245k
  const int num_argb = (max_subsampling_index + 1) * kNumPredModes * HISTO_SIZE;
628
245k
  const int num_accumulated_rgb = (max_subsampling_index + 1) * HISTO_SIZE;
629
245k
  const int num_predictors = (max_subsampling_index + 1) * kNumPredModes;
630
245k
  uint32_t* const raw_data = (uint32_t*)WebPSafeCalloc(
631
245k
      num_argb + num_accumulated_rgb + num_predictors, sizeof(uint32_t));
632
245k
  uint32_t* const all_argb = raw_data;
633
245k
  uint32_t* const all_accumulated_argb = all_argb + num_argb;
634
245k
  uint32_t* const all_pred_histos = all_accumulated_argb + num_accumulated_rgb;
635
245k
  const int max_tile_size = 1 << max_subsampling_index;  // in tile size
636
245k
  int percent_start = *percent;
637
  // When using the residuals of a tile for its super-tiles, you can either:
638
  // - use each residual to update the histogram of the super-tile, with a cost
639
  //   of 4 * (1<<n)^2 increment operations (4 for the number of channels, and
640
  //   (1<<n)^2 for the number of pixels in the tile)
641
  // - use the histogram of the tile to update the histogram of the super-tile,
642
  //   with a cost of HISTO_SIZE (1024)
643
  // The first method is therefore faster until n==4. 'update_up_to_index'
644
  // defines the maximum subsampling_index for which the residuals should be
645
  // individually added to the super-tile histogram.
646
245k
  const uint32_t update_up_to_index =
647
245k
      GetMax(GetMin(4, max_bits), min_bits) - min_bits;
648
  // Coordinates in the max-tile in tile units.
649
245k
  uint32_t local_tile_x = 0, local_tile_y = 0;
650
245k
  uint32_t max_tile_x = 0, max_tile_y = 0;
651
245k
  uint32_t tile_x = 0, tile_y = 0;
652
653
245k
  *best_bits = 0;
654
245k
  *best_mode = NULL;
655
245k
  if (raw_data == NULL) {
656
0
    WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
657
0
    return;
658
0
  }
659
660
5.57M
  while (tile_y < tiles_per_col) {
661
5.33M
    ComputeResidualsForTile(width, height, tile_x, tile_y, min_bits,
662
5.33M
                            update_up_to_index, all_argb, argb_scratch, argb,
663
5.33M
                            max_quantization, exact, used_subtract_green);
664
665
    // Update all the super-tiles that are complete.
666
5.33M
    subsampling_index = 0;
667
6.64M
    while (1) {
668
6.64M
      const uint32_t super_tile_x = tile_x >> subsampling_index;
669
6.64M
      const uint32_t super_tile_y = tile_y >> subsampling_index;
670
6.64M
      const uint32_t super_tiles_per_row =
671
6.64M
          VP8LSubSampleSize(width, min_bits + subsampling_index);
672
6.64M
      GetBestPredictorForTile(all_argb, subsampling_index, super_tile_x,
673
6.64M
                              super_tile_y, super_tiles_per_row,
674
6.64M
                              all_accumulated_argb, all_modes, all_pred_histos);
675
6.64M
      if (subsampling_index == max_subsampling_index) break;
676
677
      // Update the following super-tile histogram if it has not been updated
678
      // yet.
679
3.61M
      ++subsampling_index;
680
3.61M
      if (subsampling_index > update_up_to_index &&
681
0
          subsampling_index <= max_subsampling_index) {
682
0
        VP8LAddVectorEq(
683
0
            GetHistoArgbConst(all_argb, subsampling_index - 1, /*mode=*/0),
684
0
            GetHistoArgb(all_argb, subsampling_index, /*mode=*/0),
685
0
            HISTO_SIZE * kNumPredModes);
686
0
      }
687
      // Check whether the super-tile is not complete (if the smallest tile
688
      // is not at the end of a line/column or at the beginning of a super-tile
689
      // of size (1 << subsampling_index)).
690
3.61M
      if (!((tile_x == (tiles_per_row - 1) ||
691
2.56M
             (local_tile_x + 1) % (1 << subsampling_index) == 0) &&
692
2.18M
            (tile_y == (tiles_per_col - 1) ||
693
2.30M
             (local_tile_y + 1) % (1 << subsampling_index) == 0))) {
694
2.30M
        --subsampling_index;
695
        // subsampling_index now is the index of the last finished super-tile.
696
2.30M
        break;
697
2.30M
      }
698
3.61M
    }
699
    // Reset all the histograms belonging to finished tiles.
700
5.33M
    memset(all_argb, 0,
701
5.33M
           HISTO_SIZE * kNumPredModes * (subsampling_index + 1) *
702
5.33M
               sizeof(*all_argb));
703
704
5.33M
    if (subsampling_index == max_subsampling_index) {
705
      // If a new max-tile is started.
706
3.02M
      if (tile_x == (tiles_per_row - 1)) {
707
777k
        max_tile_x = 0;
708
777k
        ++max_tile_y;
709
2.24M
      } else {
710
2.24M
        ++max_tile_x;
711
2.24M
      }
712
3.02M
      local_tile_x = 0;
713
3.02M
      local_tile_y = 0;
714
3.02M
    } else {
715
      // Proceed with the Z traversal.
716
2.30M
      uint32_t coord_x = local_tile_x >> subsampling_index;
717
2.30M
      uint32_t coord_y = local_tile_y >> subsampling_index;
718
2.30M
      if (tile_x == (tiles_per_row - 1) && coord_x % 2 == 0) {
719
348k
        ++coord_y;
720
1.95M
      } else {
721
1.95M
        if (coord_x % 2 == 0) {
722
1.42M
          ++coord_x;
723
1.42M
        } else {
724
          // Z traversal.
725
529k
          ++coord_y;
726
529k
          --coord_x;
727
529k
        }
728
1.95M
      }
729
2.30M
      local_tile_x = coord_x << subsampling_index;
730
2.30M
      local_tile_y = coord_y << subsampling_index;
731
2.30M
    }
732
5.33M
    tile_x = max_tile_x * max_tile_size + local_tile_x;
733
5.33M
    tile_y = max_tile_y * max_tile_size + local_tile_y;
734
735
5.33M
    if (tile_x == 0 &&
736
1.24M
        !WebPReportProgress(
737
1.24M
            pic, percent_start + percent_range * tile_y / tiles_per_col,
738
1.24M
            percent)) {
739
0
      WebPSafeFree(raw_data);
740
0
      return;
741
0
    }
742
5.33M
  }
743
744
  // Figure out the best sampling.
745
245k
  best_cost = WEBP_INT64_MAX;
746
662k
  for (subsampling_index = 0; subsampling_index <= max_subsampling_index;
747
417k
       ++subsampling_index) {
748
417k
    int plane;
749
417k
    const uint32_t* const accumulated =
750
417k
        GetAccumulatedHisto(all_accumulated_argb, subsampling_index);
751
417k
    int64_t cost = VP8LShannonEntropy(
752
417k
        &all_pred_histos[subsampling_index * kNumPredModes], kNumPredModes);
753
2.08M
    for (plane = 0; plane < 4; ++plane) {
754
1.67M
      cost += VP8LShannonEntropy(&accumulated[plane * 256], 256);
755
1.67M
    }
756
417k
    if (cost < best_cost) {
757
299k
      best_cost = cost;
758
299k
      *best_bits = min_bits + subsampling_index;
759
299k
      *best_mode = all_modes[subsampling_index];
760
299k
    }
761
417k
  }
762
763
245k
  WebPSafeFree(raw_data);
764
765
245k
  VP8LOptimizeSampling(*best_mode, width, height, *best_bits,
766
245k
                       MAX_TRANSFORM_BITS, best_bits);
767
245k
}
768
769
// Finds the best predictor for each tile, and converts the image to residuals
770
// with respect to predictions. If near_lossless_quality < 100, applies
771
// near lossless processing, shaving off more bits of residuals for lower
772
// qualities.
773
int VP8LResidualImage(int width, int height, int min_bits, int max_bits,
774
                      int low_effort, uint32_t* const argb,
775
                      uint32_t* const argb_scratch, uint32_t* const image,
776
                      int near_lossless_quality, int exact,
777
                      int used_subtract_green, const WebPPicture* const pic,
778
                      int percent_range, int* const percent,
779
247k
                      int* const best_bits) {
780
247k
  int percent_start = *percent;
781
247k
  const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality);
782
247k
  if (low_effort) {
783
2.64k
    const int tiles_per_row = VP8LSubSampleSize(width, max_bits);
784
2.64k
    const int tiles_per_col = VP8LSubSampleSize(height, max_bits);
785
2.64k
    int i;
786
11.4k
    for (i = 0; i < tiles_per_row * tiles_per_col; ++i) {
787
8.84k
      image[i] = ARGB_BLACK | (kPredLowEffort << 8);
788
8.84k
    }
789
2.64k
    *best_bits = max_bits;
790
245k
  } else {
791
    // Allocate data to try all samplings from min_bits to max_bits.
792
245k
    int bits;
793
245k
    uint32_t sum_num_pixels = 0u;
794
245k
    uint32_t *modes_raw, *best_mode;
795
245k
    uint32_t* modes[MAX_TRANSFORM_BITS + 1];
796
245k
    uint32_t num_pixels[MAX_TRANSFORM_BITS + 1];
797
662k
    for (bits = min_bits; bits <= max_bits; ++bits) {
798
417k
      const int tiles_per_row = VP8LSubSampleSize(width, bits);
799
417k
      const int tiles_per_col = VP8LSubSampleSize(height, bits);
800
417k
      num_pixels[bits] = tiles_per_row * tiles_per_col;
801
417k
      sum_num_pixels += num_pixels[bits];
802
417k
    }
803
245k
    modes_raw = (uint32_t*)WebPSafeMalloc(sum_num_pixels, sizeof(*modes_raw));
804
245k
    if (modes_raw == NULL) {
805
0
      return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
806
0
    }
807
    // Have modes point to the right global memory modes_raw.
808
245k
    modes[min_bits] = modes_raw;
809
417k
    for (bits = min_bits + 1; bits <= max_bits; ++bits) {
810
172k
      modes[bits] = modes[bits - 1] + num_pixels[bits - 1];
811
172k
    }
812
    // Find the best sampling.
813
245k
    GetBestPredictorsAndSubSampling(
814
245k
        width, height, min_bits, max_bits, argb_scratch, argb, max_quantization,
815
245k
        exact, used_subtract_green, pic, percent_range, percent,
816
245k
        &modes[min_bits], best_bits, &best_mode);
817
245k
    if (*best_bits == 0) {
818
0
      WebPSafeFree(modes_raw);
819
0
      return 0;
820
0
    }
821
    // Keep the best predictor image.
822
245k
    memcpy(image, best_mode,
823
245k
           VP8LSubSampleSize(width, *best_bits) *
824
245k
               VP8LSubSampleSize(height, *best_bits) * sizeof(*image));
825
245k
    WebPSafeFree(modes_raw);
826
245k
  }
827
828
247k
  CopyImageWithPrediction(width, height, *best_bits, image, argb_scratch, argb,
829
247k
                          low_effort, max_quantization, exact,
830
247k
                          used_subtract_green);
831
247k
  return WebPReportProgress(pic, percent_start + percent_range, percent);
832
247k
}
833
834
//------------------------------------------------------------------------------
835
// Color transform functions.
836
837
1.89M
static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) {
838
1.89M
  m->green_to_red = 0;
839
1.89M
  m->green_to_blue = 0;
840
1.89M
  m->red_to_blue = 0;
841
1.89M
}
842
843
static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code,
844
1.63M
                                               VP8LMultipliers* const m) {
845
1.63M
  m->green_to_red = (color_code >> 0) & 0xff;
846
1.63M
  m->green_to_blue = (color_code >> 8) & 0xff;
847
1.63M
  m->red_to_blue = (color_code >> 16) & 0xff;
848
1.63M
}
849
850
static WEBP_INLINE uint32_t
851
1.83M
MultipliersToColorCode(const VP8LMultipliers* const m) {
852
1.83M
  return 0xff000000u | ((uint32_t)(m->red_to_blue) << 16) |
853
1.83M
         ((uint32_t)(m->green_to_blue) << 8) | m->green_to_red;
854
1.83M
}
855
856
static int64_t PredictionCostCrossColor(const uint32_t accumulated[256],
857
87.3M
                                        const uint32_t counts[256]) {
858
  // Favor low entropy, locally and globally.
859
  // Favor small absolute values for PredictionCostSpatial
860
87.3M
  static const uint64_t kExpValue = 240;
861
87.3M
  return (int64_t)VP8LCombinedShannonEntropy(counts, accumulated) +
862
87.3M
         PredictionCostBias(counts, 3, kExpValue);
863
87.3M
}
864
865
static int64_t GetPredictionCostCrossColorRed(
866
    const uint32_t* argb, int stride, int tile_width, int tile_height,
867
    VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red,
868
21.0M
    const uint32_t accumulated_red_histo[256]) {
869
21.0M
  uint32_t histo[256] = {0};
870
21.0M
  int64_t cur_diff;
871
872
21.0M
  VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height,
873
21.0M
                                green_to_red, histo);
874
875
21.0M
  cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo);
876
21.0M
  if ((uint8_t)green_to_red == prev_x.green_to_red) {
877
    // favor keeping the areas locally similar
878
1.88M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
879
1.88M
  }
880
21.0M
  if ((uint8_t)green_to_red == prev_y.green_to_red) {
881
    // favor keeping the areas locally similar
882
1.92M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
883
1.92M
  }
884
21.0M
  if (green_to_red == 0) {
885
2.17M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
886
2.17M
  }
887
21.0M
  return cur_diff;
888
21.0M
}
889
890
static void GetBestGreenToRed(const uint32_t* argb, int stride, int tile_width,
891
                              int tile_height, VP8LMultipliers prev_x,
892
                              VP8LMultipliers prev_y, int quality,
893
                              const uint32_t accumulated_red_histo[256],
894
1.83M
                              VP8LMultipliers* const best_tx) {
895
1.83M
  const int kMaxIters = 4 + ((7 * quality) >> 8);  // in range [4..6]
896
1.83M
  int green_to_red_best = 0;
897
1.83M
  int iter, offset;
898
1.83M
  int64_t best_diff = GetPredictionCostCrossColorRed(
899
1.83M
      argb, stride, tile_width, tile_height, prev_x, prev_y, green_to_red_best,
900
1.83M
      accumulated_red_histo);
901
11.4M
  for (iter = 0; iter < kMaxIters; ++iter) {
902
    // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to
903
    // one in color computation. Having initial delta here as 1 is sufficient
904
    // to explore the range of (-2, 2).
905
9.60M
    const int delta = 32 >> iter;
906
    // Try a negative and a positive delta from the best known value.
907
28.8M
    for (offset = -delta; offset <= delta; offset += 2 * delta) {
908
19.2M
      const int green_to_red_cur = offset + green_to_red_best;
909
19.2M
      const int64_t cur_diff = GetPredictionCostCrossColorRed(
910
19.2M
          argb, stride, tile_width, tile_height, prev_x, prev_y,
911
19.2M
          green_to_red_cur, accumulated_red_histo);
912
19.2M
      if (cur_diff < best_diff) {
913
718k
        best_diff = cur_diff;
914
718k
        green_to_red_best = green_to_red_cur;
915
718k
      }
916
19.2M
    }
917
9.60M
  }
918
1.83M
  best_tx->green_to_red = (green_to_red_best & 0xff);
919
1.83M
}
920
921
static int64_t GetPredictionCostCrossColorBlue(
922
    const uint32_t* argb, int stride, int tile_width, int tile_height,
923
    VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_blue,
924
66.2M
    int red_to_blue, const uint32_t accumulated_blue_histo[256]) {
925
66.2M
  uint32_t histo[256] = {0};
926
66.2M
  int64_t cur_diff;
927
928
66.2M
  VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height,
929
66.2M
                                 green_to_blue, red_to_blue, histo);
930
931
66.2M
  cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo);
932
66.2M
  if ((uint8_t)green_to_blue == prev_x.green_to_blue) {
933
    // favor keeping the areas locally similar
934
16.2M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
935
16.2M
  }
936
66.2M
  if ((uint8_t)green_to_blue == prev_y.green_to_blue) {
937
    // favor keeping the areas locally similar
938
16.4M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
939
16.4M
  }
940
66.2M
  if ((uint8_t)red_to_blue == prev_x.red_to_blue) {
941
    // favor keeping the areas locally similar
942
14.3M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
943
14.3M
  }
944
66.2M
  if ((uint8_t)red_to_blue == prev_y.red_to_blue) {
945
    // favor keeping the areas locally similar
946
14.5M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
947
14.5M
  }
948
66.2M
  if (green_to_blue == 0) {
949
17.1M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
950
17.1M
  }
951
66.2M
  if (red_to_blue == 0) {
952
15.4M
    cur_diff -= 3ll << LOG_2_PRECISION_BITS;
953
15.4M
  }
954
66.2M
  return cur_diff;
955
66.2M
}
956
957
72.5M
#define kGreenRedToBlueNumAxis 8
958
1.19M
#define kGreenRedToBlueMaxIters 7
959
static void GetBestGreenRedToBlue(const uint32_t* argb, int stride,
960
                                  int tile_width, int tile_height,
961
                                  VP8LMultipliers prev_x,
962
                                  VP8LMultipliers prev_y, int quality,
963
                                  const uint32_t accumulated_blue_histo[256],
964
1.83M
                                  VP8LMultipliers* const best_tx) {
965
1.83M
  const int8_t offset[kGreenRedToBlueNumAxis][2] = {
966
1.83M
      {0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
967
1.83M
  const int8_t delta_lut[kGreenRedToBlueMaxIters] = {16, 16, 8, 4, 2, 2, 2};
968
  // Only axis aligned diffs for lower quality.
969
1.83M
  const int iters = (quality < 25)   ? 1
970
1.83M
                    : (quality > 50) ? kGreenRedToBlueMaxIters
971
1.42M
                                     : 4;
972
1.83M
  int green_to_blue_best = 0;
973
1.83M
  int red_to_blue_best = 0;
974
1.83M
  int iter;
975
  // Initial value at origin:
976
1.83M
  int64_t best_diff = GetPredictionCostCrossColorBlue(
977
1.83M
      argb, stride, tile_width, tile_height, prev_x, prev_y, green_to_blue_best,
978
1.83M
      red_to_blue_best, accumulated_blue_histo);
979
9.07M
  for (iter = 0; iter < iters; ++iter) {
980
8.05M
    const int delta = delta_lut[iter];
981
8.05M
    int axis;
982
72.5M
    for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) {
983
64.4M
      const int green_to_blue_cur =
984
64.4M
          offset[axis][0] * delta + green_to_blue_best;
985
64.4M
      const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best;
986
64.4M
      const int64_t cur_diff = GetPredictionCostCrossColorBlue(
987
64.4M
          argb, stride, tile_width, tile_height, prev_x, prev_y,
988
64.4M
          green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo);
989
64.4M
      if (cur_diff < best_diff) {
990
1.04M
        best_diff = cur_diff;
991
1.04M
        green_to_blue_best = green_to_blue_cur;
992
1.04M
        red_to_blue_best = red_to_blue_cur;
993
1.04M
      }
994
64.4M
    }
995
8.05M
    if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) {
996
      // Further iterations would not help.
997
817k
      break;  // out of iter-loop.
998
817k
    }
999
8.05M
  }
1000
1.83M
  best_tx->green_to_blue = green_to_blue_best & 0xff;
1001
1.83M
  best_tx->red_to_blue = red_to_blue_best & 0xff;
1002
1.83M
}
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
1.83M
    const uint32_t accumulated_blue_histo[256], const uint32_t* const argb) {
1011
1.83M
  const int max_tile_size = 1 << bits;
1012
1.83M
  const int tile_y_offset = tile_y * max_tile_size;
1013
1.83M
  const int tile_x_offset = tile_x * max_tile_size;
1014
1.83M
  const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize);
1015
1.83M
  const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize);
1016
1.83M
  const int tile_width = all_x_max - tile_x_offset;
1017
1.83M
  const int tile_height = all_y_max - tile_y_offset;
1018
1.83M
  const uint32_t* const tile_argb =
1019
1.83M
      argb + tile_y_offset * xsize + tile_x_offset;
1020
1.83M
  VP8LMultipliers best_tx;
1021
1.83M
  MultipliersClear(&best_tx);
1022
1023
1.83M
  GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height, prev_x, prev_y,
1024
1.83M
                    quality, accumulated_red_histo, &best_tx);
1025
1.83M
  GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height, prev_x,
1026
1.83M
                        prev_y, quality, accumulated_blue_histo, &best_tx);
1027
1.83M
  return best_tx;
1028
1.83M
}
1029
1030
static void CopyTileWithColorTransform(int xsize, int ysize, int tile_x,
1031
                                       int tile_y, int max_tile_size,
1032
                                       VP8LMultipliers color_transform,
1033
1.83M
                                       uint32_t* argb) {
1034
1.83M
  const int xscan = GetMin(max_tile_size, xsize - tile_x);
1035
1.83M
  int yscan = GetMin(max_tile_size, ysize - tile_y);
1036
1.83M
  argb += tile_y * xsize + tile_x;
1037
13.2M
  while (yscan-- > 0) {
1038
11.3M
    VP8LTransformColor(&color_transform, argb, xscan);
1039
11.3M
    argb += xsize;
1040
11.3M
  }
1041
1.83M
}
1042
1043
int VP8LColorSpaceTransform(int width, int height, int bits, int quality,
1044
                            uint32_t* const argb, uint32_t* image,
1045
                            const WebPPicture* const pic, int percent_range,
1046
31.2k
                            int* const percent, int* const best_bits) {
1047
31.2k
  const int max_tile_size = 1 << bits;
1048
31.2k
  const int tile_xsize = VP8LSubSampleSize(width, bits);
1049
31.2k
  const int tile_ysize = VP8LSubSampleSize(height, bits);
1050
31.2k
  int percent_start = *percent;
1051
31.2k
  uint32_t accumulated_red_histo[256] = {0};
1052
31.2k
  uint32_t accumulated_blue_histo[256] = {0};
1053
31.2k
  int tile_x, tile_y;
1054
31.2k
  VP8LMultipliers prev_x, prev_y;
1055
31.2k
  MultipliersClear(&prev_y);
1056
31.2k
  MultipliersClear(&prev_x);
1057
232k
  for (tile_y = 0; tile_y < tile_ysize; ++tile_y) {
1058
2.03M
    for (tile_x = 0; tile_x < tile_xsize; ++tile_x) {
1059
1.83M
      int y;
1060
1.83M
      const int tile_x_offset = tile_x * max_tile_size;
1061
1.83M
      const int tile_y_offset = tile_y * max_tile_size;
1062
1.83M
      const int all_x_max = GetMin(tile_x_offset + max_tile_size, width);
1063
1.83M
      const int all_y_max = GetMin(tile_y_offset + max_tile_size, height);
1064
1.83M
      const int offset = tile_y * tile_xsize + tile_x;
1065
1.83M
      if (tile_y != 0) {
1066
1.63M
        ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y);
1067
1.63M
      }
1068
1.83M
      prev_x = GetBestColorTransformForTile(
1069
1.83M
          tile_x, tile_y, bits, prev_x, prev_y, quality, width, height,
1070
1.83M
          accumulated_red_histo, accumulated_blue_histo, argb);
1071
1.83M
      image[offset] = MultipliersToColorCode(&prev_x);
1072
1.83M
      CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset,
1073
1.83M
                                 max_tile_size, prev_x, argb);
1074
1075
      // Gather accumulated histogram data.
1076
13.2M
      for (y = tile_y_offset; y < all_y_max; ++y) {
1077
11.3M
        int ix = y * width + tile_x_offset;
1078
11.3M
        const int ix_end = ix + all_x_max - tile_x_offset;
1079
103M
        for (; ix < ix_end; ++ix) {
1080
91.9M
          const uint32_t pix = argb[ix];
1081
91.9M
          if (ix >= 2 && pix == argb[ix - 2] && pix == argb[ix - 1]) {
1082
10.0M
            continue;  // repeated pixels are handled by backward references
1083
10.0M
          }
1084
81.9M
          if (ix >= width + 2 && argb[ix - 2] == argb[ix - width - 2] &&
1085
8.11M
              argb[ix - 1] == argb[ix - width - 1] && pix == argb[ix - width]) {
1086
362k
            continue;  // repeated pixels are handled by backward references
1087
362k
          }
1088
81.5M
          ++accumulated_red_histo[(pix >> 16) & 0xff];
1089
81.5M
          ++accumulated_blue_histo[(pix >> 0) & 0xff];
1090
81.5M
        }
1091
11.3M
      }
1092
1.83M
    }
1093
201k
    if (!WebPReportProgress(pic,
1094
201k
                            percent_start + percent_range * tile_y / tile_ysize,
1095
201k
                            percent)) {
1096
0
      return 0;
1097
0
    }
1098
201k
  }
1099
31.2k
  VP8LOptimizeSampling(image, width, height, bits, MAX_TRANSFORM_BITS,
1100
31.2k
                       best_bits);
1101
31.2k
  return 1;
1102
31.2k
}