• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 // main entry for the lossless encoder.
11 //
12 // Author: Vikas Arora (vikaas.arora@gmail.com)
13 //
14 
15 #include <assert.h>
16 #include <stdlib.h>
17 
18 #include "src/dsp/lossless.h"
19 #include "src/dsp/lossless_common.h"
20 #include "src/enc/backward_references_enc.h"
21 #include "src/enc/histogram_enc.h"
22 #include "src/enc/vp8i_enc.h"
23 #include "src/enc/vp8li_enc.h"
24 #include "src/utils/bit_writer_utils.h"
25 #include "src/utils/huffman_encode_utils.h"
26 #include "src/utils/palette.h"
27 #include "src/utils/utils.h"
28 #include "src/webp/encode.h"
29 #include "src/webp/format_constants.h"
30 
31 // Maximum number of histogram images (sub-blocks).
32 #define MAX_HUFF_IMAGE_SIZE       2600
33 #define MAX_HUFFMAN_BITS (MIN_HUFFMAN_BITS + (1 << NUM_HUFFMAN_BITS) - 1)
34 // Empirical value for which it becomes too computationally expensive to
35 // compute the best predictor image.
36 #define MAX_PREDICTOR_IMAGE_SIZE (1 << 14)
37 
38 // -----------------------------------------------------------------------------
39 // Palette
40 
41 // These five modes are evaluated and their respective entropy is computed.
42 typedef enum {
43   kDirect = 0,
44   kSpatial = 1,
45   kSubGreen = 2,
46   kSpatialSubGreen = 3,
47   kPalette = 4,
48   kPaletteAndSpatial = 5,
49   kNumEntropyIx = 6
50 } EntropyIx;
51 
52 typedef enum {
53   kHistoAlpha = 0,
54   kHistoAlphaPred,
55   kHistoGreen,
56   kHistoGreenPred,
57   kHistoRed,
58   kHistoRedPred,
59   kHistoBlue,
60   kHistoBluePred,
61   kHistoRedSubGreen,
62   kHistoRedPredSubGreen,
63   kHistoBlueSubGreen,
64   kHistoBluePredSubGreen,
65   kHistoPalette,
66   kHistoTotal  // Must be last.
67 } HistoIx;
68 
AddSingleSubGreen(uint32_t p,uint32_t * const r,uint32_t * const b)69 static void AddSingleSubGreen(uint32_t p,
70                               uint32_t* const r, uint32_t* const b) {
71   const int green = (int)p >> 8;  // The upper bits are masked away later.
72   ++r[(((int)p >> 16) - green) & 0xff];
73   ++b[(((int)p >>  0) - green) & 0xff];
74 }
75 
AddSingle(uint32_t p,uint32_t * const a,uint32_t * const r,uint32_t * const g,uint32_t * const b)76 static void AddSingle(uint32_t p,
77                       uint32_t* const a, uint32_t* const r,
78                       uint32_t* const g, uint32_t* const b) {
79   ++a[(p >> 24) & 0xff];
80   ++r[(p >> 16) & 0xff];
81   ++g[(p >>  8) & 0xff];
82   ++b[(p >>  0) & 0xff];
83 }
84 
HashPix(uint32_t pix)85 static WEBP_INLINE uint32_t HashPix(uint32_t pix) {
86   // Note that masking with 0xffffffffu is for preventing an
87   // 'unsigned int overflow' warning. Doesn't impact the compiled code.
88   return ((((uint64_t)pix + (pix >> 19)) * 0x39c5fba7ull) & 0xffffffffu) >> 24;
89 }
90 
AnalyzeEntropy(const uint32_t * argb,int width,int height,int argb_stride,int use_palette,int palette_size,int transform_bits,EntropyIx * const min_entropy_ix,int * const red_and_blue_always_zero)91 static int AnalyzeEntropy(const uint32_t* argb,
92                           int width, int height, int argb_stride,
93                           int use_palette,
94                           int palette_size, int transform_bits,
95                           EntropyIx* const min_entropy_ix,
96                           int* const red_and_blue_always_zero) {
97   // Allocate histogram set with cache_bits = 0.
98   uint32_t* histo;
99 
100   if (use_palette && palette_size <= 16) {
101     // In the case of small palettes, we pack 2, 4 or 8 pixels together. In
102     // practice, small palettes are better than any other transform.
103     *min_entropy_ix = kPalette;
104     *red_and_blue_always_zero = 1;
105     return 1;
106   }
107   histo = (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256);
108   if (histo != NULL) {
109     int i, x, y;
110     const uint32_t* prev_row = NULL;
111     const uint32_t* curr_row = argb;
112     uint32_t pix_prev = argb[0];  // Skip the first pixel.
113     for (y = 0; y < height; ++y) {
114       for (x = 0; x < width; ++x) {
115         const uint32_t pix = curr_row[x];
116         const uint32_t pix_diff = VP8LSubPixels(pix, pix_prev);
117         pix_prev = pix;
118         if ((pix_diff == 0) || (prev_row != NULL && pix == prev_row[x])) {
119           continue;
120         }
121         AddSingle(pix,
122                   &histo[kHistoAlpha * 256],
123                   &histo[kHistoRed * 256],
124                   &histo[kHistoGreen * 256],
125                   &histo[kHistoBlue * 256]);
126         AddSingle(pix_diff,
127                   &histo[kHistoAlphaPred * 256],
128                   &histo[kHistoRedPred * 256],
129                   &histo[kHistoGreenPred * 256],
130                   &histo[kHistoBluePred * 256]);
131         AddSingleSubGreen(pix,
132                           &histo[kHistoRedSubGreen * 256],
133                           &histo[kHistoBlueSubGreen * 256]);
134         AddSingleSubGreen(pix_diff,
135                           &histo[kHistoRedPredSubGreen * 256],
136                           &histo[kHistoBluePredSubGreen * 256]);
137         {
138           // Approximate the palette by the entropy of the multiplicative hash.
139           const uint32_t hash = HashPix(pix);
140           ++histo[kHistoPalette * 256 + hash];
141         }
142       }
143       prev_row = curr_row;
144       curr_row += argb_stride;
145     }
146     {
147       uint64_t entropy_comp[kHistoTotal];
148       uint64_t entropy[kNumEntropyIx];
149       int k;
150       int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen;
151       int j;
152       // Let's add one zero to the predicted histograms. The zeros are removed
153       // too efficiently by the pix_diff == 0 comparison, at least one of the
154       // zeros is likely to exist.
155       ++histo[kHistoRedPredSubGreen * 256];
156       ++histo[kHistoBluePredSubGreen * 256];
157       ++histo[kHistoRedPred * 256];
158       ++histo[kHistoGreenPred * 256];
159       ++histo[kHistoBluePred * 256];
160       ++histo[kHistoAlphaPred * 256];
161 
162       for (j = 0; j < kHistoTotal; ++j) {
163         entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256);
164       }
165       entropy[kDirect] = entropy_comp[kHistoAlpha] +
166           entropy_comp[kHistoRed] +
167           entropy_comp[kHistoGreen] +
168           entropy_comp[kHistoBlue];
169       entropy[kSpatial] = entropy_comp[kHistoAlphaPred] +
170           entropy_comp[kHistoRedPred] +
171           entropy_comp[kHistoGreenPred] +
172           entropy_comp[kHistoBluePred];
173       entropy[kSubGreen] = entropy_comp[kHistoAlpha] +
174           entropy_comp[kHistoRedSubGreen] +
175           entropy_comp[kHistoGreen] +
176           entropy_comp[kHistoBlueSubGreen];
177       entropy[kSpatialSubGreen] = entropy_comp[kHistoAlphaPred] +
178           entropy_comp[kHistoRedPredSubGreen] +
179           entropy_comp[kHistoGreenPred] +
180           entropy_comp[kHistoBluePredSubGreen];
181       entropy[kPalette] = entropy_comp[kHistoPalette];
182 
183       // When including transforms, there is an overhead in bits from
184       // storing them. This overhead is small but matters for small images.
185       // For spatial, there are 14 transformations.
186       entropy[kSpatial] += (uint64_t)VP8LSubSampleSize(width, transform_bits) *
187                            VP8LSubSampleSize(height, transform_bits) *
188                            VP8LFastLog2(14);
189       // For color transforms: 24 as only 3 channels are considered in a
190       // ColorTransformElement.
191       entropy[kSpatialSubGreen] +=
192           (uint64_t)VP8LSubSampleSize(width, transform_bits) *
193           VP8LSubSampleSize(height, transform_bits) * VP8LFastLog2(24);
194       // For palettes, add the cost of storing the palette.
195       // We empirically estimate the cost of a compressed entry as 8 bits.
196       // The palette is differential-coded when compressed hence a much
197       // lower cost than sizeof(uint32_t)*8.
198       entropy[kPalette] += (palette_size * 8ull) << LOG_2_PRECISION_BITS;
199 
200       *min_entropy_ix = kDirect;
201       for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) {
202         if (entropy[*min_entropy_ix] > entropy[k]) {
203           *min_entropy_ix = (EntropyIx)k;
204         }
205       }
206       assert((int)*min_entropy_ix <= last_mode_to_analyze);
207       *red_and_blue_always_zero = 1;
208       // Let's check if the histogram of the chosen entropy mode has
209       // non-zero red and blue values. If all are zero, we can later skip
210       // the cross color optimization.
211       {
212         static const uint8_t kHistoPairs[5][2] = {
213           { kHistoRed, kHistoBlue },
214           { kHistoRedPred, kHistoBluePred },
215           { kHistoRedSubGreen, kHistoBlueSubGreen },
216           { kHistoRedPredSubGreen, kHistoBluePredSubGreen },
217           { kHistoRed, kHistoBlue }
218         };
219         const uint32_t* const red_histo =
220             &histo[256 * kHistoPairs[*min_entropy_ix][0]];
221         const uint32_t* const blue_histo =
222             &histo[256 * kHistoPairs[*min_entropy_ix][1]];
223         for (i = 1; i < 256; ++i) {
224           if ((red_histo[i] | blue_histo[i]) != 0) {
225             *red_and_blue_always_zero = 0;
226             break;
227           }
228         }
229       }
230     }
231     WebPSafeFree(histo);
232     return 1;
233   } else {
234     return 0;
235   }
236 }
237 
238 // Clamp histogram and transform bits.
ClampBits(int width,int height,int bits,int min_bits,int max_bits,int image_size_max)239 static int ClampBits(int width, int height, int bits, int min_bits,
240                      int max_bits, int image_size_max) {
241   int image_size;
242   bits = (bits < min_bits) ? min_bits : (bits > max_bits) ? max_bits : bits;
243   image_size = VP8LSubSampleSize(width, bits) * VP8LSubSampleSize(height, bits);
244   while (bits < max_bits && image_size > image_size_max) {
245     ++bits;
246     image_size =
247         VP8LSubSampleSize(width, bits) * VP8LSubSampleSize(height, bits);
248   }
249   // In case the bits reduce the image too much, choose the smallest value
250   // setting the histogram image size to 1.
251   while (bits > min_bits && image_size == 1) {
252     image_size = VP8LSubSampleSize(width, bits - 1) *
253                  VP8LSubSampleSize(height, bits - 1);
254     if (image_size != 1) break;
255     --bits;
256   }
257   return bits;
258 }
259 
GetHistoBits(int method,int use_palette,int width,int height)260 static int GetHistoBits(int method, int use_palette, int width, int height) {
261   // Make tile size a function of encoding method (Range: 0 to 6).
262   const int histo_bits = (use_palette ? 9 : 7) - method;
263   return ClampBits(width, height, histo_bits, MIN_HUFFMAN_BITS,
264                    MAX_HUFFMAN_BITS, MAX_HUFF_IMAGE_SIZE);
265 }
266 
GetTransformBits(int method,int histo_bits)267 static int GetTransformBits(int method, int histo_bits) {
268   const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5;
269   const int res =
270       (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits;
271   assert(res <= MAX_TRANSFORM_BITS);
272   return res;
273 }
274 
275 // Set of parameters to be used in each iteration of the cruncher.
276 #define CRUNCH_SUBCONFIGS_MAX 2
277 typedef struct {
278   int lz77_;
279   int do_no_cache_;
280 } CrunchSubConfig;
281 typedef struct {
282   int entropy_idx_;
283   PaletteSorting palette_sorting_type_;
284   CrunchSubConfig sub_configs_[CRUNCH_SUBCONFIGS_MAX];
285   int sub_configs_size_;
286 } CrunchConfig;
287 
288 // +2 because we add a palette sorting configuration for kPalette and
289 // kPaletteAndSpatial.
290 #define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2 * kPaletteSortingNum)
291 
EncoderAnalyze(VP8LEncoder * const enc,CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],int * const crunch_configs_size,int * const red_and_blue_always_zero)292 static int EncoderAnalyze(VP8LEncoder* const enc,
293                           CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],
294                           int* const crunch_configs_size,
295                           int* const red_and_blue_always_zero) {
296   const WebPPicture* const pic = enc->pic_;
297   const int width = pic->width;
298   const int height = pic->height;
299   const WebPConfig* const config = enc->config_;
300   const int method = config->method;
301   const int low_effort = (config->method == 0);
302   int i;
303   int use_palette, transform_bits;
304   int n_lz77s;
305   // If set to 0, analyze the cache with the computed cache value. If 1, also
306   // analyze with no-cache.
307   int do_no_cache = 0;
308   assert(pic != NULL && pic->argb != NULL);
309 
310   // Check whether a palette is possible.
311   enc->palette_size_ = GetColorPalette(pic, enc->palette_sorted_);
312   use_palette = (enc->palette_size_ <= MAX_PALETTE_SIZE);
313   if (!use_palette) {
314     enc->palette_size_ = 0;
315   }
316 
317   // Empirical bit sizes.
318   enc->histo_bits_ = GetHistoBits(method, use_palette,
319                                   pic->width, pic->height);
320   transform_bits = GetTransformBits(method, enc->histo_bits_);
321   enc->predictor_transform_bits_ = transform_bits;
322   enc->cross_color_transform_bits_ = transform_bits;
323 
324   if (low_effort) {
325     // AnalyzeEntropy is somewhat slow.
326     crunch_configs[0].entropy_idx_ = use_palette ? kPalette : kSpatialSubGreen;
327     crunch_configs[0].palette_sorting_type_ =
328         use_palette ? kSortedDefault : kUnusedPalette;
329     n_lz77s = 1;
330     *crunch_configs_size = 1;
331   } else {
332     EntropyIx min_entropy_ix;
333     // Try out multiple LZ77 on images with few colors.
334     n_lz77s = (enc->palette_size_ > 0 && enc->palette_size_ <= 16) ? 2 : 1;
335     if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, use_palette,
336                         enc->palette_size_, transform_bits, &min_entropy_ix,
337                         red_and_blue_always_zero)) {
338       return 0;
339     }
340     if (method == 6 && config->quality == 100) {
341       do_no_cache = 1;
342       // Go brute force on all transforms.
343       *crunch_configs_size = 0;
344       for (i = 0; i < kNumEntropyIx; ++i) {
345         // We can only apply kPalette or kPaletteAndSpatial if we can indeed use
346         // a palette.
347         if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) {
348           assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX);
349           if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) {
350             int sorting_method;
351             for (sorting_method = 0; sorting_method < kPaletteSortingNum;
352                  ++sorting_method) {
353               const PaletteSorting typed_sorting_method =
354                   (PaletteSorting)sorting_method;
355               // TODO(vrabaud) kSortedDefault should be tested. It is omitted
356               // for now for backward compatibility.
357               if (typed_sorting_method == kUnusedPalette ||
358                   typed_sorting_method == kSortedDefault) {
359                 continue;
360               }
361               crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
362               crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
363                   typed_sorting_method;
364               ++*crunch_configs_size;
365             }
366           } else {
367             crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
368             crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
369                 kUnusedPalette;
370             ++*crunch_configs_size;
371           }
372         }
373       }
374     } else {
375       // Only choose the guessed best transform.
376       *crunch_configs_size = 1;
377       crunch_configs[0].entropy_idx_ = min_entropy_ix;
378       crunch_configs[0].palette_sorting_type_ =
379           use_palette ? kMinimizeDelta : kUnusedPalette;
380       if (config->quality >= 75 && method == 5) {
381         // Test with and without color cache.
382         do_no_cache = 1;
383         // If we have a palette, also check in combination with spatial.
384         if (min_entropy_ix == kPalette) {
385           *crunch_configs_size = 2;
386           crunch_configs[1].entropy_idx_ = kPaletteAndSpatial;
387           crunch_configs[1].palette_sorting_type_ = kMinimizeDelta;
388         }
389       }
390     }
391   }
392   // Fill in the different LZ77s.
393   assert(n_lz77s <= CRUNCH_SUBCONFIGS_MAX);
394   for (i = 0; i < *crunch_configs_size; ++i) {
395     int j;
396     for (j = 0; j < n_lz77s; ++j) {
397       assert(j < CRUNCH_SUBCONFIGS_MAX);
398       crunch_configs[i].sub_configs_[j].lz77_ =
399           (j == 0) ? kLZ77Standard | kLZ77RLE : kLZ77Box;
400       crunch_configs[i].sub_configs_[j].do_no_cache_ = do_no_cache;
401     }
402     crunch_configs[i].sub_configs_size_ = n_lz77s;
403   }
404   return 1;
405 }
406 
EncoderInit(VP8LEncoder * const enc)407 static int EncoderInit(VP8LEncoder* const enc) {
408   const WebPPicture* const pic = enc->pic_;
409   const int width = pic->width;
410   const int height = pic->height;
411   const int pix_cnt = width * height;
412   // we round the block size up, so we're guaranteed to have
413   // at most MAX_REFS_BLOCK_PER_IMAGE blocks used:
414   const int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1;
415   int i;
416   if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0;
417 
418   for (i = 0; i < 4; ++i) VP8LBackwardRefsInit(&enc->refs_[i], refs_block_size);
419 
420   return 1;
421 }
422 
423 // Returns false in case of memory error.
GetHuffBitLengthsAndCodes(const VP8LHistogramSet * const histogram_image,HuffmanTreeCode * const huffman_codes)424 static int GetHuffBitLengthsAndCodes(
425     const VP8LHistogramSet* const histogram_image,
426     HuffmanTreeCode* const huffman_codes) {
427   int i, k;
428   int ok = 0;
429   uint64_t total_length_size = 0;
430   uint8_t* mem_buf = NULL;
431   const int histogram_image_size = histogram_image->size;
432   int max_num_symbols = 0;
433   uint8_t* buf_rle = NULL;
434   HuffmanTree* huff_tree = NULL;
435 
436   // Iterate over all histograms and get the aggregate number of codes used.
437   for (i = 0; i < histogram_image_size; ++i) {
438     const VP8LHistogram* const histo = histogram_image->histograms[i];
439     HuffmanTreeCode* const codes = &huffman_codes[5 * i];
440     assert(histo != NULL);
441     for (k = 0; k < 5; ++k) {
442       const int num_symbols =
443           (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) :
444           (k == 4) ? NUM_DISTANCE_CODES : 256;
445       codes[k].num_symbols = num_symbols;
446       total_length_size += num_symbols;
447     }
448   }
449 
450   // Allocate and Set Huffman codes.
451   {
452     uint16_t* codes;
453     uint8_t* lengths;
454     mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size,
455                                        sizeof(*lengths) + sizeof(*codes));
456     if (mem_buf == NULL) goto End;
457 
458     codes = (uint16_t*)mem_buf;
459     lengths = (uint8_t*)&codes[total_length_size];
460     for (i = 0; i < 5 * histogram_image_size; ++i) {
461       const int bit_length = huffman_codes[i].num_symbols;
462       huffman_codes[i].codes = codes;
463       huffman_codes[i].code_lengths = lengths;
464       codes += bit_length;
465       lengths += bit_length;
466       if (max_num_symbols < bit_length) {
467         max_num_symbols = bit_length;
468       }
469     }
470   }
471 
472   buf_rle = (uint8_t*)WebPSafeMalloc(1ULL, max_num_symbols);
473   huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * max_num_symbols,
474                                            sizeof(*huff_tree));
475   if (buf_rle == NULL || huff_tree == NULL) goto End;
476 
477   // Create Huffman trees.
478   for (i = 0; i < histogram_image_size; ++i) {
479     HuffmanTreeCode* const codes = &huffman_codes[5 * i];
480     VP8LHistogram* const histo = histogram_image->histograms[i];
481     VP8LCreateHuffmanTree(histo->literal_, 15, buf_rle, huff_tree, codes + 0);
482     VP8LCreateHuffmanTree(histo->red_, 15, buf_rle, huff_tree, codes + 1);
483     VP8LCreateHuffmanTree(histo->blue_, 15, buf_rle, huff_tree, codes + 2);
484     VP8LCreateHuffmanTree(histo->alpha_, 15, buf_rle, huff_tree, codes + 3);
485     VP8LCreateHuffmanTree(histo->distance_, 15, buf_rle, huff_tree, codes + 4);
486   }
487   ok = 1;
488  End:
489   WebPSafeFree(huff_tree);
490   WebPSafeFree(buf_rle);
491   if (!ok) {
492     WebPSafeFree(mem_buf);
493     memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
494   }
495   return ok;
496 }
497 
StoreHuffmanTreeOfHuffmanTreeToBitMask(VP8LBitWriter * const bw,const uint8_t * code_length_bitdepth)498 static void StoreHuffmanTreeOfHuffmanTreeToBitMask(
499     VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) {
500   // RFC 1951 will calm you down if you are worried about this funny sequence.
501   // This sequence is tuned from that, but more weighted for lower symbol count,
502   // and more spiking histograms.
503   static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = {
504     17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
505   };
506   int i;
507   // Throw away trailing zeros:
508   int codes_to_store = CODE_LENGTH_CODES;
509   for (; codes_to_store > 4; --codes_to_store) {
510     if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
511       break;
512     }
513   }
514   VP8LPutBits(bw, codes_to_store - 4, 4);
515   for (i = 0; i < codes_to_store; ++i) {
516     VP8LPutBits(bw, code_length_bitdepth[kStorageOrder[i]], 3);
517   }
518 }
519 
ClearHuffmanTreeIfOnlyOneSymbol(HuffmanTreeCode * const huffman_code)520 static void ClearHuffmanTreeIfOnlyOneSymbol(
521     HuffmanTreeCode* const huffman_code) {
522   int k;
523   int count = 0;
524   for (k = 0; k < huffman_code->num_symbols; ++k) {
525     if (huffman_code->code_lengths[k] != 0) {
526       ++count;
527       if (count > 1) return;
528     }
529   }
530   for (k = 0; k < huffman_code->num_symbols; ++k) {
531     huffman_code->code_lengths[k] = 0;
532     huffman_code->codes[k] = 0;
533   }
534 }
535 
StoreHuffmanTreeToBitMask(VP8LBitWriter * const bw,const HuffmanTreeToken * const tokens,const int num_tokens,const HuffmanTreeCode * const huffman_code)536 static void StoreHuffmanTreeToBitMask(
537     VP8LBitWriter* const bw,
538     const HuffmanTreeToken* const tokens, const int num_tokens,
539     const HuffmanTreeCode* const huffman_code) {
540   int i;
541   for (i = 0; i < num_tokens; ++i) {
542     const int ix = tokens[i].code;
543     const int extra_bits = tokens[i].extra_bits;
544     VP8LPutBits(bw, huffman_code->codes[ix], huffman_code->code_lengths[ix]);
545     switch (ix) {
546       case 16:
547         VP8LPutBits(bw, extra_bits, 2);
548         break;
549       case 17:
550         VP8LPutBits(bw, extra_bits, 3);
551         break;
552       case 18:
553         VP8LPutBits(bw, extra_bits, 7);
554         break;
555     }
556   }
557 }
558 
559 // 'huff_tree' and 'tokens' are pre-alloacted buffers.
StoreFullHuffmanCode(VP8LBitWriter * const bw,HuffmanTree * const huff_tree,HuffmanTreeToken * const tokens,const HuffmanTreeCode * const tree)560 static void StoreFullHuffmanCode(VP8LBitWriter* const bw,
561                                  HuffmanTree* const huff_tree,
562                                  HuffmanTreeToken* const tokens,
563                                  const HuffmanTreeCode* const tree) {
564   uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
565   uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
566   const int max_tokens = tree->num_symbols;
567   int num_tokens;
568   HuffmanTreeCode huffman_code;
569   huffman_code.num_symbols = CODE_LENGTH_CODES;
570   huffman_code.code_lengths = code_length_bitdepth;
571   huffman_code.codes = code_length_bitdepth_symbols;
572 
573   VP8LPutBits(bw, 0, 1);
574   num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens);
575   {
576     uint32_t histogram[CODE_LENGTH_CODES] = { 0 };
577     uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 };
578     int i;
579     for (i = 0; i < num_tokens; ++i) {
580       ++histogram[tokens[i].code];
581     }
582 
583     VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code);
584   }
585 
586   StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
587   ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code);
588   {
589     int trailing_zero_bits = 0;
590     int trimmed_length = num_tokens;
591     int write_trimmed_length;
592     int length;
593     int i = num_tokens;
594     while (i-- > 0) {
595       const int ix = tokens[i].code;
596       if (ix == 0 || ix == 17 || ix == 18) {
597         --trimmed_length;   // discount trailing zeros
598         trailing_zero_bits += code_length_bitdepth[ix];
599         if (ix == 17) {
600           trailing_zero_bits += 3;
601         } else if (ix == 18) {
602           trailing_zero_bits += 7;
603         }
604       } else {
605         break;
606       }
607     }
608     write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
609     length = write_trimmed_length ? trimmed_length : num_tokens;
610     VP8LPutBits(bw, write_trimmed_length, 1);
611     if (write_trimmed_length) {
612       if (trimmed_length == 2) {
613         VP8LPutBits(bw, 0, 3 + 2);     // nbitpairs=1, trimmed_length=2
614       } else {
615         const int nbits = BitsLog2Floor(trimmed_length - 2);
616         const int nbitpairs = nbits / 2 + 1;
617         assert(trimmed_length > 2);
618         assert(nbitpairs - 1 < 8);
619         VP8LPutBits(bw, nbitpairs - 1, 3);
620         VP8LPutBits(bw, trimmed_length - 2, nbitpairs * 2);
621       }
622     }
623     StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
624   }
625 }
626 
627 // 'huff_tree' and 'tokens' are pre-alloacted buffers.
StoreHuffmanCode(VP8LBitWriter * const bw,HuffmanTree * const huff_tree,HuffmanTreeToken * const tokens,const HuffmanTreeCode * const huffman_code)628 static void StoreHuffmanCode(VP8LBitWriter* const bw,
629                              HuffmanTree* const huff_tree,
630                              HuffmanTreeToken* const tokens,
631                              const HuffmanTreeCode* const huffman_code) {
632   int i;
633   int count = 0;
634   int symbols[2] = { 0, 0 };
635   const int kMaxBits = 8;
636   const int kMaxSymbol = 1 << kMaxBits;
637 
638   // Check whether it's a small tree.
639   for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) {
640     if (huffman_code->code_lengths[i] != 0) {
641       if (count < 2) symbols[count] = i;
642       ++count;
643     }
644   }
645 
646   if (count == 0) {   // emit minimal tree for empty cases
647     // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
648     VP8LPutBits(bw, 0x01, 4);
649   } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
650     VP8LPutBits(bw, 1, 1);  // Small tree marker to encode 1 or 2 symbols.
651     VP8LPutBits(bw, count - 1, 1);
652     if (symbols[0] <= 1) {
653       VP8LPutBits(bw, 0, 1);  // Code bit for small (1 bit) symbol value.
654       VP8LPutBits(bw, symbols[0], 1);
655     } else {
656       VP8LPutBits(bw, 1, 1);
657       VP8LPutBits(bw, symbols[0], 8);
658     }
659     if (count == 2) {
660       VP8LPutBits(bw, symbols[1], 8);
661     }
662   } else {
663     StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code);
664   }
665 }
666 
WriteHuffmanCode(VP8LBitWriter * const bw,const HuffmanTreeCode * const code,int code_index)667 static WEBP_INLINE void WriteHuffmanCode(VP8LBitWriter* const bw,
668                              const HuffmanTreeCode* const code,
669                              int code_index) {
670   const int depth = code->code_lengths[code_index];
671   const int symbol = code->codes[code_index];
672   VP8LPutBits(bw, symbol, depth);
673 }
674 
WriteHuffmanCodeWithExtraBits(VP8LBitWriter * const bw,const HuffmanTreeCode * const code,int code_index,int bits,int n_bits)675 static WEBP_INLINE void WriteHuffmanCodeWithExtraBits(
676     VP8LBitWriter* const bw,
677     const HuffmanTreeCode* const code,
678     int code_index,
679     int bits,
680     int n_bits) {
681   const int depth = code->code_lengths[code_index];
682   const int symbol = code->codes[code_index];
683   VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits);
684 }
685 
StoreImageToBitMask(VP8LBitWriter * const bw,int width,int histo_bits,const VP8LBackwardRefs * const refs,const uint32_t * histogram_symbols,const HuffmanTreeCode * const huffman_codes,const WebPPicture * const pic)686 static int StoreImageToBitMask(VP8LBitWriter* const bw, int width,
687                                int histo_bits,
688                                const VP8LBackwardRefs* const refs,
689                                const uint32_t* histogram_symbols,
690                                const HuffmanTreeCode* const huffman_codes,
691                                const WebPPicture* const pic) {
692   const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
693   const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits);
694   // x and y trace the position in the image.
695   int x = 0;
696   int y = 0;
697   int tile_x = x & tile_mask;
698   int tile_y = y & tile_mask;
699   int histogram_ix = (histogram_symbols[0] >> 8) & 0xffff;
700   const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix;
701   VP8LRefsCursor c = VP8LRefsCursorInit(refs);
702   while (VP8LRefsCursorOk(&c)) {
703     const PixOrCopy* const v = c.cur_pos;
704     if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) {
705       tile_x = x & tile_mask;
706       tile_y = y & tile_mask;
707       histogram_ix = (histogram_symbols[(y >> histo_bits) * histo_xsize +
708                                         (x >> histo_bits)] >>
709                       8) &
710                      0xffff;
711       codes = huffman_codes + 5 * histogram_ix;
712     }
713     if (PixOrCopyIsLiteral(v)) {
714       static const uint8_t order[] = { 1, 2, 0, 3 };
715       int k;
716       for (k = 0; k < 4; ++k) {
717         const int code = PixOrCopyLiteral(v, order[k]);
718         WriteHuffmanCode(bw, codes + k, code);
719       }
720     } else if (PixOrCopyIsCacheIdx(v)) {
721       const int code = PixOrCopyCacheIdx(v);
722       const int literal_ix = 256 + NUM_LENGTH_CODES + code;
723       WriteHuffmanCode(bw, codes, literal_ix);
724     } else {
725       int bits, n_bits;
726       int code;
727 
728       const int distance = PixOrCopyDistance(v);
729       VP8LPrefixEncode(v->len, &code, &n_bits, &bits);
730       WriteHuffmanCodeWithExtraBits(bw, codes, 256 + code, bits, n_bits);
731 
732       // Don't write the distance with the extra bits code since
733       // the distance can be up to 18 bits of extra bits, and the prefix
734       // 15 bits, totaling to 33, and our PutBits only supports up to 32 bits.
735       VP8LPrefixEncode(distance, &code, &n_bits, &bits);
736       WriteHuffmanCode(bw, codes + 4, code);
737       VP8LPutBits(bw, bits, n_bits);
738     }
739     x += PixOrCopyLength(v);
740     while (x >= width) {
741       x -= width;
742       ++y;
743     }
744     VP8LRefsCursorNext(&c);
745   }
746   if (bw->error_) {
747     return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
748   }
749   return 1;
750 }
751 
752 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31.
753 // pic and percent are for progress.
EncodeImageNoHuffman(VP8LBitWriter * const bw,const uint32_t * const argb,VP8LHashChain * const hash_chain,VP8LBackwardRefs * const refs_array,int width,int height,int quality,int low_effort,const WebPPicture * const pic,int percent_range,int * const percent)754 static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
755                                 const uint32_t* const argb,
756                                 VP8LHashChain* const hash_chain,
757                                 VP8LBackwardRefs* const refs_array, int width,
758                                 int height, int quality, int low_effort,
759                                 const WebPPicture* const pic, int percent_range,
760                                 int* const percent) {
761   int i;
762   int max_tokens = 0;
763   VP8LBackwardRefs* refs;
764   HuffmanTreeToken* tokens = NULL;
765   HuffmanTreeCode huffman_codes[5] = {{0, NULL, NULL}};
766   const uint32_t histogram_symbols[1] = {0};  // only one tree, one symbol
767   int cache_bits = 0;
768   VP8LHistogramSet* histogram_image = NULL;
769   HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
770       3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
771   if (huff_tree == NULL) {
772     WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
773     goto Error;
774   }
775 
776   // Calculate backward references from ARGB image.
777   if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, low_effort,
778                          pic, percent_range / 2, percent)) {
779     goto Error;
780   }
781   if (!VP8LGetBackwardReferences(width, height, argb, quality, /*low_effort=*/0,
782                                  kLZ77Standard | kLZ77RLE, cache_bits,
783                                  /*do_no_cache=*/0, hash_chain, refs_array,
784                                  &cache_bits, pic,
785                                  percent_range - percent_range / 2, percent)) {
786     goto Error;
787   }
788   refs = &refs_array[0];
789   histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
790   if (histogram_image == NULL) {
791     WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
792     goto Error;
793   }
794   VP8LHistogramSetClear(histogram_image);
795 
796   // Build histogram image and symbols from backward references.
797   VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);
798 
799   // Create Huffman bit lengths and codes for each histogram image.
800   assert(histogram_image->size == 1);
801   if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
802     WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
803     goto Error;
804   }
805 
806   // No color cache, no Huffman image.
807   VP8LPutBits(bw, 0, 1);
808 
809   // Find maximum number of symbols for the huffman tree-set.
810   for (i = 0; i < 5; ++i) {
811     HuffmanTreeCode* const codes = &huffman_codes[i];
812     if (max_tokens < codes->num_symbols) {
813       max_tokens = codes->num_symbols;
814     }
815   }
816 
817   tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
818   if (tokens == NULL) {
819     WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
820     goto Error;
821   }
822 
823   // Store Huffman codes.
824   for (i = 0; i < 5; ++i) {
825     HuffmanTreeCode* const codes = &huffman_codes[i];
826     StoreHuffmanCode(bw, huff_tree, tokens, codes);
827     ClearHuffmanTreeIfOnlyOneSymbol(codes);
828   }
829 
830   // Store actual literals.
831   if (!StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, huffman_codes,
832                            pic)) {
833     goto Error;
834   }
835 
836  Error:
837   WebPSafeFree(tokens);
838   WebPSafeFree(huff_tree);
839   VP8LFreeHistogramSet(histogram_image);
840   WebPSafeFree(huffman_codes[0].codes);
841   return (pic->error_code == VP8_ENC_OK);
842 }
843 
844 // pic and percent are for progress.
EncodeImageInternal(VP8LBitWriter * const bw,const uint32_t * const argb,VP8LHashChain * const hash_chain,VP8LBackwardRefs refs_array[4],int width,int height,int quality,int low_effort,const CrunchConfig * const config,int * cache_bits,int histogram_bits_in,size_t init_byte_position,int * const hdr_size,int * const data_size,const WebPPicture * const pic,int percent_range,int * const percent)845 static int EncodeImageInternal(
846     VP8LBitWriter* const bw, const uint32_t* const argb,
847     VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width,
848     int height, int quality, int low_effort, const CrunchConfig* const config,
849     int* cache_bits, int histogram_bits_in, size_t init_byte_position,
850     int* const hdr_size, int* const data_size, const WebPPicture* const pic,
851     int percent_range, int* const percent) {
852   const uint32_t histogram_image_xysize =
853       VP8LSubSampleSize(width, histogram_bits_in) *
854       VP8LSubSampleSize(height, histogram_bits_in);
855   int remaining_percent = percent_range;
856   int percent_start = *percent;
857   VP8LHistogramSet* histogram_image = NULL;
858   VP8LHistogram* tmp_histo = NULL;
859   uint32_t i, histogram_image_size = 0;
860   size_t bit_array_size = 0;
861   HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
862       3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
863   HuffmanTreeToken* tokens = NULL;
864   HuffmanTreeCode* huffman_codes = NULL;
865   uint32_t* const histogram_argb = (uint32_t*)WebPSafeMalloc(
866       histogram_image_xysize, sizeof(*histogram_argb));
867   int sub_configs_idx;
868   int cache_bits_init, write_histogram_image;
869   VP8LBitWriter bw_init = *bw, bw_best;
870   int hdr_size_tmp;
871   VP8LHashChain hash_chain_histogram;  // histogram image hash chain
872   size_t bw_size_best = ~(size_t)0;
873   assert(histogram_bits_in >= MIN_HUFFMAN_BITS);
874   assert(histogram_bits_in <= MAX_HUFFMAN_BITS);
875   assert(hdr_size != NULL);
876   assert(data_size != NULL);
877 
878   memset(&hash_chain_histogram, 0, sizeof(hash_chain_histogram));
879   if (!VP8LBitWriterInit(&bw_best, 0)) {
880     WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
881     goto Error;
882   }
883 
884   // Make sure we can allocate the different objects.
885   if (huff_tree == NULL || histogram_argb == NULL ||
886       !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize)) {
887     WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
888     goto Error;
889   }
890 
891   percent_range = remaining_percent / 5;
892   if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
893                          low_effort, pic, percent_range, percent)) {
894     goto Error;
895   }
896   percent_start += percent_range;
897   remaining_percent -= percent_range;
898 
899   // If the value is different from zero, it has been set during the palette
900   // analysis.
901   cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits;
902   // If several iterations will happen, clone into bw_best.
903   if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) &&
904       !VP8LBitWriterClone(bw, &bw_best)) {
905     WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
906     goto Error;
907   }
908 
909   for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size_;
910        ++sub_configs_idx) {
911     const CrunchSubConfig* const sub_config =
912         &config->sub_configs_[sub_configs_idx];
913     int cache_bits_best, i_cache;
914     int i_remaining_percent = remaining_percent / config->sub_configs_size_;
915     int i_percent_range = i_remaining_percent / 4;
916     i_remaining_percent -= i_percent_range;
917 
918     if (!VP8LGetBackwardReferences(
919             width, height, argb, quality, low_effort, sub_config->lz77_,
920             cache_bits_init, sub_config->do_no_cache_, hash_chain,
921             &refs_array[0], &cache_bits_best, pic, i_percent_range, percent)) {
922       goto Error;
923     }
924 
925     for (i_cache = 0; i_cache < (sub_config->do_no_cache_ ? 2 : 1); ++i_cache) {
926       const int cache_bits_tmp = (i_cache == 0) ? cache_bits_best : 0;
927       int histogram_bits = histogram_bits_in;
928       // Speed-up: no need to study the no-cache case if it was already studied
929       // in i_cache == 0.
930       if (i_cache == 1 && cache_bits_best == 0) break;
931 
932       // Reset the bit writer for this iteration.
933       VP8LBitWriterReset(&bw_init, bw);
934 
935       // Build histogram image and symbols from backward references.
936       histogram_image =
937           VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits_tmp);
938       tmp_histo = VP8LAllocateHistogram(cache_bits_tmp);
939       if (histogram_image == NULL || tmp_histo == NULL) {
940         WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
941         goto Error;
942       }
943 
944       i_percent_range = i_remaining_percent / 3;
945       i_remaining_percent -= i_percent_range;
946       if (!VP8LGetHistoImageSymbols(
947               width, height, &refs_array[i_cache], quality, low_effort,
948               histogram_bits, cache_bits_tmp, histogram_image, tmp_histo,
949               histogram_argb, pic, i_percent_range, percent)) {
950         goto Error;
951       }
952       // Create Huffman bit lengths and codes for each histogram image.
953       histogram_image_size = histogram_image->size;
954       bit_array_size = 5 * histogram_image_size;
955       huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
956                                                        sizeof(*huffman_codes));
957       // Note: some histogram_image entries may point to tmp_histos[], so the
958       // latter need to outlive the following call to
959       // GetHuffBitLengthsAndCodes().
960       if (huffman_codes == NULL ||
961           !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
962         WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
963         goto Error;
964       }
965       // Free combined histograms.
966       VP8LFreeHistogramSet(histogram_image);
967       histogram_image = NULL;
968 
969       // Free scratch histograms.
970       VP8LFreeHistogram(tmp_histo);
971       tmp_histo = NULL;
972 
973       // Color Cache parameters.
974       if (cache_bits_tmp > 0) {
975         VP8LPutBits(bw, 1, 1);
976         VP8LPutBits(bw, cache_bits_tmp, 4);
977       } else {
978         VP8LPutBits(bw, 0, 1);
979       }
980 
981       // Huffman image + meta huffman.
982       histogram_image_size = 0;
983       for (i = 0; i < histogram_image_xysize; ++i) {
984         if (histogram_argb[i] >= histogram_image_size) {
985           histogram_image_size = histogram_argb[i] + 1;
986         }
987         histogram_argb[i] <<= 8;
988       }
989 
990       write_histogram_image = (histogram_image_size > 1);
991       VP8LPutBits(bw, write_histogram_image, 1);
992       if (write_histogram_image) {
993         VP8LOptimizeSampling(histogram_argb, width, height, histogram_bits_in,
994                              MAX_HUFFMAN_BITS, &histogram_bits);
995         VP8LPutBits(bw, histogram_bits - 2, 3);
996         i_percent_range = i_remaining_percent / 2;
997         i_remaining_percent -= i_percent_range;
998         if (!EncodeImageNoHuffman(
999                 bw, histogram_argb, &hash_chain_histogram, &refs_array[2],
1000                 VP8LSubSampleSize(width, histogram_bits),
1001                 VP8LSubSampleSize(height, histogram_bits), quality, low_effort,
1002                 pic, i_percent_range, percent)) {
1003           goto Error;
1004         }
1005       }
1006 
1007       // Store Huffman codes.
1008       {
1009         int max_tokens = 0;
1010         // Find maximum number of symbols for the huffman tree-set.
1011         for (i = 0; i < 5 * histogram_image_size; ++i) {
1012           HuffmanTreeCode* const codes = &huffman_codes[i];
1013           if (max_tokens < codes->num_symbols) {
1014             max_tokens = codes->num_symbols;
1015           }
1016         }
1017         tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
1018         if (tokens == NULL) {
1019           WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
1020           goto Error;
1021         }
1022         for (i = 0; i < 5 * histogram_image_size; ++i) {
1023           HuffmanTreeCode* const codes = &huffman_codes[i];
1024           StoreHuffmanCode(bw, huff_tree, tokens, codes);
1025           ClearHuffmanTreeIfOnlyOneSymbol(codes);
1026         }
1027       }
1028       // Store actual literals.
1029       hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
1030       if (!StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache],
1031                                histogram_argb, huffman_codes, pic)) {
1032         goto Error;
1033       }
1034       // Keep track of the smallest image so far.
1035       if (VP8LBitWriterNumBytes(bw) < bw_size_best) {
1036         bw_size_best = VP8LBitWriterNumBytes(bw);
1037         *cache_bits = cache_bits_tmp;
1038         *hdr_size = hdr_size_tmp;
1039         *data_size =
1040             (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size);
1041         VP8LBitWriterSwap(bw, &bw_best);
1042       }
1043       WebPSafeFree(tokens);
1044       tokens = NULL;
1045       if (huffman_codes != NULL) {
1046         WebPSafeFree(huffman_codes->codes);
1047         WebPSafeFree(huffman_codes);
1048         huffman_codes = NULL;
1049       }
1050     }
1051   }
1052   VP8LBitWriterSwap(bw, &bw_best);
1053 
1054   if (!WebPReportProgress(pic, percent_start + remaining_percent, percent)) {
1055     goto Error;
1056   }
1057 
1058  Error:
1059   WebPSafeFree(tokens);
1060   WebPSafeFree(huff_tree);
1061   VP8LFreeHistogramSet(histogram_image);
1062   VP8LFreeHistogram(tmp_histo);
1063   VP8LHashChainClear(&hash_chain_histogram);
1064   if (huffman_codes != NULL) {
1065     WebPSafeFree(huffman_codes->codes);
1066     WebPSafeFree(huffman_codes);
1067   }
1068   WebPSafeFree(histogram_argb);
1069   VP8LBitWriterWipeOut(&bw_best);
1070   return (pic->error_code == VP8_ENC_OK);
1071 }
1072 
1073 // -----------------------------------------------------------------------------
1074 // Transforms
1075 
ApplySubtractGreen(VP8LEncoder * const enc,int width,int height,VP8LBitWriter * const bw)1076 static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height,
1077                                VP8LBitWriter* const bw) {
1078   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1079   VP8LPutBits(bw, SUBTRACT_GREEN_TRANSFORM, 2);
1080   VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
1081 }
1082 
ApplyPredictFilter(VP8LEncoder * const enc,int width,int height,int quality,int low_effort,int used_subtract_green,VP8LBitWriter * const bw,int percent_range,int * const percent)1083 static int ApplyPredictFilter(VP8LEncoder* const enc, int width, int height,
1084                               int quality, int low_effort,
1085                               int used_subtract_green, VP8LBitWriter* const bw,
1086                               int percent_range, int* const percent) {
1087   int best_bits;
1088   const int near_lossless_strength =
1089       enc->use_palette_ ? 100 : enc->config_->near_lossless;
1090   const int max_bits = ClampBits(width, height, enc->predictor_transform_bits_,
1091                                  MIN_TRANSFORM_BITS, MAX_TRANSFORM_BITS,
1092                                  MAX_PREDICTOR_IMAGE_SIZE);
1093   const int min_bits = ClampBits(
1094       width, height,
1095       max_bits - 2 * (enc->config_->method > 4 ? enc->config_->method - 4 : 0),
1096       MIN_TRANSFORM_BITS, MAX_TRANSFORM_BITS, MAX_PREDICTOR_IMAGE_SIZE);
1097 
1098   if (!VP8LResidualImage(width, height, min_bits, max_bits, low_effort,
1099                          enc->argb_, enc->argb_scratch_, enc->transform_data_,
1100                          near_lossless_strength, enc->config_->exact,
1101                          used_subtract_green, enc->pic_, percent_range / 2,
1102                          percent, &best_bits)) {
1103     return 0;
1104   }
1105   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1106   VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
1107   assert(best_bits >= MIN_TRANSFORM_BITS && best_bits <= MAX_TRANSFORM_BITS);
1108   VP8LPutBits(bw, best_bits - MIN_TRANSFORM_BITS, NUM_TRANSFORM_BITS);
1109   enc->predictor_transform_bits_ = best_bits;
1110   return EncodeImageNoHuffman(
1111       bw, enc->transform_data_, &enc->hash_chain_, &enc->refs_[0],
1112       VP8LSubSampleSize(width, best_bits), VP8LSubSampleSize(height, best_bits),
1113       quality, low_effort, enc->pic_, percent_range - percent_range / 2,
1114       percent);
1115 }
1116 
ApplyCrossColorFilter(VP8LEncoder * const enc,int width,int height,int quality,int low_effort,VP8LBitWriter * const bw,int percent_range,int * const percent)1117 static int ApplyCrossColorFilter(VP8LEncoder* const enc, int width, int height,
1118                                  int quality, int low_effort,
1119                                  VP8LBitWriter* const bw, int percent_range,
1120                                  int* const percent) {
1121   const int min_bits = enc->cross_color_transform_bits_;
1122   int best_bits;
1123 
1124   if (!VP8LColorSpaceTransform(width, height, min_bits, quality, enc->argb_,
1125                                enc->transform_data_, enc->pic_,
1126                                percent_range / 2, percent, &best_bits)) {
1127     return 0;
1128   }
1129   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1130   VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2);
1131   assert(best_bits >= MIN_TRANSFORM_BITS && best_bits <= MAX_TRANSFORM_BITS);
1132   VP8LPutBits(bw, best_bits - MIN_TRANSFORM_BITS, NUM_TRANSFORM_BITS);
1133   enc->cross_color_transform_bits_ = best_bits;
1134   return EncodeImageNoHuffman(
1135       bw, enc->transform_data_, &enc->hash_chain_, &enc->refs_[0],
1136       VP8LSubSampleSize(width, best_bits), VP8LSubSampleSize(height, best_bits),
1137       quality, low_effort, enc->pic_, percent_range - percent_range / 2,
1138       percent);
1139 }
1140 
1141 // -----------------------------------------------------------------------------
1142 
WriteRiffHeader(const WebPPicture * const pic,size_t riff_size,size_t vp8l_size)1143 static int WriteRiffHeader(const WebPPicture* const pic, size_t riff_size,
1144                            size_t vp8l_size) {
1145   uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
1146     'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
1147     'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
1148   };
1149   PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
1150   PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
1151   return pic->writer(riff, sizeof(riff), pic);
1152 }
1153 
WriteImageSize(const WebPPicture * const pic,VP8LBitWriter * const bw)1154 static int WriteImageSize(const WebPPicture* const pic,
1155                           VP8LBitWriter* const bw) {
1156   const int width = pic->width - 1;
1157   const int height = pic->height - 1;
1158   assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
1159 
1160   VP8LPutBits(bw, width, VP8L_IMAGE_SIZE_BITS);
1161   VP8LPutBits(bw, height, VP8L_IMAGE_SIZE_BITS);
1162   return !bw->error_;
1163 }
1164 
WriteRealAlphaAndVersion(VP8LBitWriter * const bw,int has_alpha)1165 static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
1166   VP8LPutBits(bw, has_alpha, 1);
1167   VP8LPutBits(bw, VP8L_VERSION, VP8L_VERSION_BITS);
1168   return !bw->error_;
1169 }
1170 
WriteImage(const WebPPicture * const pic,VP8LBitWriter * const bw,size_t * const coded_size)1171 static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw,
1172                       size_t* const coded_size) {
1173   const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
1174   const size_t webpll_size = VP8LBitWriterNumBytes(bw);
1175   const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
1176   const size_t pad = vp8l_size & 1;
1177   const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
1178   *coded_size = 0;
1179 
1180   if (bw->error_) {
1181     return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
1182   }
1183 
1184   if (!WriteRiffHeader(pic, riff_size, vp8l_size) ||
1185       !pic->writer(webpll_data, webpll_size, pic)) {
1186     return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
1187   }
1188 
1189   if (pad) {
1190     const uint8_t pad_byte[1] = { 0 };
1191     if (!pic->writer(pad_byte, 1, pic)) {
1192       return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
1193     }
1194   }
1195   *coded_size = CHUNK_HEADER_SIZE + riff_size;
1196   return 1;
1197 }
1198 
1199 // -----------------------------------------------------------------------------
1200 
ClearTransformBuffer(VP8LEncoder * const enc)1201 static void ClearTransformBuffer(VP8LEncoder* const enc) {
1202   WebPSafeFree(enc->transform_mem_);
1203   enc->transform_mem_ = NULL;
1204   enc->transform_mem_size_ = 0;
1205 }
1206 
1207 // Allocates the memory for argb (W x H) buffer, 2 rows of context for
1208 // prediction and transform data.
1209 // Flags influencing the memory allocated:
1210 //  enc->transform_bits_
1211 //  enc->use_predict_, enc->use_cross_color_
AllocateTransformBuffer(VP8LEncoder * const enc,int width,int height)1212 static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
1213                                    int height) {
1214   const uint64_t image_size = (uint64_t)width * height;
1215   // VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
1216   // pixel in each, plus 2 regular scanlines of bytes.
1217   // TODO(skal): Clean up by using arithmetic in bytes instead of words.
1218   const uint64_t argb_scratch_size =
1219       enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) /
1220                                                 sizeof(uint32_t)
1221                         : 0;
1222   const uint64_t transform_data_size =
1223       (enc->use_predict_ || enc->use_cross_color_)
1224           ? (uint64_t)VP8LSubSampleSize(width, MIN_TRANSFORM_BITS) *
1225                 VP8LSubSampleSize(height, MIN_TRANSFORM_BITS)
1226           : 0;
1227   const uint64_t max_alignment_in_words =
1228       (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t);
1229   const uint64_t mem_size = image_size + max_alignment_in_words +
1230                             argb_scratch_size + max_alignment_in_words +
1231                             transform_data_size;
1232   uint32_t* mem = enc->transform_mem_;
1233   if (mem == NULL || mem_size > enc->transform_mem_size_) {
1234     ClearTransformBuffer(enc);
1235     mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem));
1236     if (mem == NULL) {
1237       return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
1238     }
1239     enc->transform_mem_ = mem;
1240     enc->transform_mem_size_ = (size_t)mem_size;
1241     enc->argb_content_ = kEncoderNone;
1242   }
1243   enc->argb_ = mem;
1244   mem = (uint32_t*)WEBP_ALIGN(mem + image_size);
1245   enc->argb_scratch_ = mem;
1246   mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size);
1247   enc->transform_data_ = mem;
1248 
1249   enc->current_width_ = width;
1250   return 1;
1251 }
1252 
MakeInputImageCopy(VP8LEncoder * const enc)1253 static int MakeInputImageCopy(VP8LEncoder* const enc) {
1254   const WebPPicture* const picture = enc->pic_;
1255   const int width = picture->width;
1256   const int height = picture->height;
1257 
1258   if (!AllocateTransformBuffer(enc, width, height)) return 0;
1259   if (enc->argb_content_ == kEncoderARGB) return 1;
1260 
1261   {
1262     uint32_t* dst = enc->argb_;
1263     const uint32_t* src = picture->argb;
1264     int y;
1265     for (y = 0; y < height; ++y) {
1266       memcpy(dst, src, width * sizeof(*dst));
1267       dst += width;
1268       src += picture->argb_stride;
1269     }
1270   }
1271   enc->argb_content_ = kEncoderARGB;
1272   assert(enc->current_width_ == width);
1273   return 1;
1274 }
1275 
1276 // -----------------------------------------------------------------------------
1277 
1278 #define APPLY_PALETTE_GREEDY_MAX 4
1279 
SearchColorGreedy(const uint32_t palette[],int palette_size,uint32_t color)1280 static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[],
1281                                               int palette_size,
1282                                               uint32_t color) {
1283   (void)palette_size;
1284   assert(palette_size < APPLY_PALETTE_GREEDY_MAX);
1285   assert(3 == APPLY_PALETTE_GREEDY_MAX - 1);
1286   if (color == palette[0]) return 0;
1287   if (color == palette[1]) return 1;
1288   if (color == palette[2]) return 2;
1289   return 3;
1290 }
1291 
ApplyPaletteHash0(uint32_t color)1292 static WEBP_INLINE uint32_t ApplyPaletteHash0(uint32_t color) {
1293   // Focus on the green color.
1294   return (color >> 8) & 0xff;
1295 }
1296 
1297 #define PALETTE_INV_SIZE_BITS 11
1298 #define PALETTE_INV_SIZE (1 << PALETTE_INV_SIZE_BITS)
1299 
ApplyPaletteHash1(uint32_t color)1300 static WEBP_INLINE uint32_t ApplyPaletteHash1(uint32_t color) {
1301   // Forget about alpha.
1302   return ((uint32_t)((color & 0x00ffffffu) * 4222244071ull)) >>
1303          (32 - PALETTE_INV_SIZE_BITS);
1304 }
1305 
ApplyPaletteHash2(uint32_t color)1306 static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) {
1307   // Forget about alpha.
1308   return ((uint32_t)((color & 0x00ffffffu) * ((1ull << 31) - 1))) >>
1309          (32 - PALETTE_INV_SIZE_BITS);
1310 }
1311 
1312 // Use 1 pixel cache for ARGB pixels.
1313 #define APPLY_PALETTE_FOR(COLOR_INDEX) do {         \
1314   uint32_t prev_pix = palette[0];                   \
1315   uint32_t prev_idx = 0;                            \
1316   for (y = 0; y < height; ++y) {                    \
1317     for (x = 0; x < width; ++x) {                   \
1318       const uint32_t pix = src[x];                  \
1319       if (pix != prev_pix) {                        \
1320         prev_idx = COLOR_INDEX;                     \
1321         prev_pix = pix;                             \
1322       }                                             \
1323       tmp_row[x] = prev_idx;                        \
1324     }                                               \
1325     VP8LBundleColorMap(tmp_row, width, xbits, dst); \
1326     src += src_stride;                              \
1327     dst += dst_stride;                              \
1328   }                                                 \
1329 } while (0)
1330 
1331 // Remap argb values in src[] to packed palettes entries in dst[]
1332 // using 'row' as a temporary buffer of size 'width'.
1333 // We assume that all src[] values have a corresponding entry in the palette.
1334 // Note: src[] can be the same as dst[]
ApplyPalette(const uint32_t * src,uint32_t src_stride,uint32_t * dst,uint32_t dst_stride,const uint32_t * palette,int palette_size,int width,int height,int xbits,const WebPPicture * const pic)1335 static int ApplyPalette(const uint32_t* src, uint32_t src_stride, uint32_t* dst,
1336                         uint32_t dst_stride, const uint32_t* palette,
1337                         int palette_size, int width, int height, int xbits,
1338                         const WebPPicture* const pic) {
1339   // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be
1340   // made to work in-place.
1341   uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
1342   int x, y;
1343 
1344   if (tmp_row == NULL) {
1345     return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
1346   }
1347 
1348   if (palette_size < APPLY_PALETTE_GREEDY_MAX) {
1349     APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix));
1350   } else {
1351     int i, j;
1352     uint16_t buffer[PALETTE_INV_SIZE];
1353     uint32_t (*const hash_functions[])(uint32_t) = {
1354         ApplyPaletteHash0, ApplyPaletteHash1, ApplyPaletteHash2
1355     };
1356 
1357     // Try to find a perfect hash function able to go from a color to an index
1358     // within 1 << PALETTE_INV_SIZE_BITS in order to build a hash map to go
1359     // from color to index in palette.
1360     for (i = 0; i < 3; ++i) {
1361       int use_LUT = 1;
1362       // Set each element in buffer to max uint16_t.
1363       memset(buffer, 0xff, sizeof(buffer));
1364       for (j = 0; j < palette_size; ++j) {
1365         const uint32_t ind = hash_functions[i](palette[j]);
1366         if (buffer[ind] != 0xffffu) {
1367           use_LUT = 0;
1368           break;
1369         } else {
1370           buffer[ind] = j;
1371         }
1372       }
1373       if (use_LUT) break;
1374     }
1375 
1376     if (i == 0) {
1377       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash0(pix)]);
1378     } else if (i == 1) {
1379       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash1(pix)]);
1380     } else if (i == 2) {
1381       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash2(pix)]);
1382     } else {
1383       uint32_t idx_map[MAX_PALETTE_SIZE];
1384       uint32_t palette_sorted[MAX_PALETTE_SIZE];
1385       PrepareMapToPalette(palette, palette_size, palette_sorted, idx_map);
1386       APPLY_PALETTE_FOR(
1387           idx_map[SearchColorNoIdx(palette_sorted, pix, palette_size)]);
1388     }
1389   }
1390   WebPSafeFree(tmp_row);
1391   return 1;
1392 }
1393 #undef APPLY_PALETTE_FOR
1394 #undef PALETTE_INV_SIZE_BITS
1395 #undef PALETTE_INV_SIZE
1396 #undef APPLY_PALETTE_GREEDY_MAX
1397 
1398 // Note: Expects "enc->palette_" to be set properly.
MapImageFromPalette(VP8LEncoder * const enc)1399 static int MapImageFromPalette(VP8LEncoder* const enc) {
1400   const WebPPicture* const pic = enc->pic_;
1401   const int width = pic->width;
1402   const int height = pic->height;
1403   const uint32_t* const palette = enc->palette_;
1404   const int palette_size = enc->palette_size_;
1405   int xbits;
1406 
1407   // Replace each input pixel by corresponding palette index.
1408   // This is done line by line.
1409   if (palette_size <= 4) {
1410     xbits = (palette_size <= 2) ? 3 : 2;
1411   } else {
1412     xbits = (palette_size <= 16) ? 1 : 0;
1413   }
1414 
1415   if (!AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height)) {
1416     return 0;
1417   }
1418   if (!ApplyPalette(pic->argb, pic->argb_stride, enc->argb_,
1419                     enc->current_width_, palette, palette_size, width, height,
1420                     xbits, pic)) {
1421     return 0;
1422   }
1423   enc->argb_content_ = kEncoderPalette;
1424   return 1;
1425 }
1426 
1427 // Save palette_[] to bitstream.
EncodePalette(VP8LBitWriter * const bw,int low_effort,VP8LEncoder * const enc,int percent_range,int * const percent)1428 static int EncodePalette(VP8LBitWriter* const bw, int low_effort,
1429                          VP8LEncoder* const enc, int percent_range,
1430                          int* const percent) {
1431   int i;
1432   uint32_t tmp_palette[MAX_PALETTE_SIZE];
1433   const int palette_size = enc->palette_size_;
1434   const uint32_t* const palette = enc->palette_;
1435   // If the last element is 0, do not store it and count on automatic palette
1436   // 0-filling. This can only happen if there is no pixel packing, hence if
1437   // there are strictly more than 16 colors (after 0 is removed).
1438   const uint32_t encoded_palette_size =
1439       (enc->palette_[palette_size - 1] == 0 && palette_size > 17)
1440           ? palette_size - 1
1441           : palette_size;
1442   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1443   VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2);
1444   assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE);
1445   VP8LPutBits(bw, encoded_palette_size - 1, 8);
1446   for (i = encoded_palette_size - 1; i >= 1; --i) {
1447     tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
1448   }
1449   tmp_palette[0] = palette[0];
1450   return EncodeImageNoHuffman(
1451       bw, tmp_palette, &enc->hash_chain_, &enc->refs_[0], encoded_palette_size,
1452       1, /*quality=*/20, low_effort, enc->pic_, percent_range, percent);
1453 }
1454 
1455 // -----------------------------------------------------------------------------
1456 // VP8LEncoder
1457 
VP8LEncoderNew(const WebPConfig * const config,const WebPPicture * const picture)1458 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
1459                                    const WebPPicture* const picture) {
1460   VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc));
1461   if (enc == NULL) {
1462     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1463     return NULL;
1464   }
1465   enc->config_ = config;
1466   enc->pic_ = picture;
1467   enc->argb_content_ = kEncoderNone;
1468 
1469   VP8LEncDspInit();
1470 
1471   return enc;
1472 }
1473 
VP8LEncoderDelete(VP8LEncoder * enc)1474 static void VP8LEncoderDelete(VP8LEncoder* enc) {
1475   if (enc != NULL) {
1476     int i;
1477     VP8LHashChainClear(&enc->hash_chain_);
1478     for (i = 0; i < 4; ++i) VP8LBackwardRefsClear(&enc->refs_[i]);
1479     ClearTransformBuffer(enc);
1480     WebPSafeFree(enc);
1481   }
1482 }
1483 
1484 // -----------------------------------------------------------------------------
1485 // Main call
1486 
1487 typedef struct {
1488   const WebPConfig* config_;
1489   const WebPPicture* picture_;
1490   VP8LBitWriter* bw_;
1491   VP8LEncoder* enc_;
1492   CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX];
1493   int num_crunch_configs_;
1494   int red_and_blue_always_zero_;
1495   WebPAuxStats* stats_;
1496 } StreamEncodeContext;
1497 
EncodeStreamHook(void * input,void * data2)1498 static int EncodeStreamHook(void* input, void* data2) {
1499   StreamEncodeContext* const params = (StreamEncodeContext*)input;
1500   const WebPConfig* const config = params->config_;
1501   const WebPPicture* const picture = params->picture_;
1502   VP8LBitWriter* const bw = params->bw_;
1503   VP8LEncoder* const enc = params->enc_;
1504   const CrunchConfig* const crunch_configs = params->crunch_configs_;
1505   const int num_crunch_configs = params->num_crunch_configs_;
1506   const int red_and_blue_always_zero = params->red_and_blue_always_zero_;
1507 #if !defined(WEBP_DISABLE_STATS)
1508   WebPAuxStats* const stats = params->stats_;
1509 #endif
1510   const int quality = (int)config->quality;
1511   const int low_effort = (config->method == 0);
1512 #if (WEBP_NEAR_LOSSLESS == 1)
1513   const int width = picture->width;
1514 #endif
1515   const int height = picture->height;
1516   const size_t byte_position = VP8LBitWriterNumBytes(bw);
1517   int percent = 2;  // for WebPProgressHook
1518 #if (WEBP_NEAR_LOSSLESS == 1)
1519   int use_near_lossless = 0;
1520 #endif
1521   int hdr_size = 0;
1522   int data_size = 0;
1523   int idx;
1524   size_t best_size = ~(size_t)0;
1525   VP8LBitWriter bw_init = *bw, bw_best;
1526   (void)data2;
1527 
1528   if (!VP8LBitWriterInit(&bw_best, 0) ||
1529       (num_crunch_configs > 1 && !VP8LBitWriterClone(bw, &bw_best))) {
1530     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1531     goto Error;
1532   }
1533 
1534   for (idx = 0; idx < num_crunch_configs; ++idx) {
1535     const int entropy_idx = crunch_configs[idx].entropy_idx_;
1536     int remaining_percent = 97 / num_crunch_configs, percent_range;
1537     enc->use_palette_ =
1538         (entropy_idx == kPalette) || (entropy_idx == kPaletteAndSpatial);
1539     enc->use_subtract_green_ =
1540         (entropy_idx == kSubGreen) || (entropy_idx == kSpatialSubGreen);
1541     enc->use_predict_ = (entropy_idx == kSpatial) ||
1542                         (entropy_idx == kSpatialSubGreen) ||
1543                         (entropy_idx == kPaletteAndSpatial);
1544     // When using a palette, R/B==0, hence no need to test for cross-color.
1545     if (low_effort || enc->use_palette_) {
1546       enc->use_cross_color_ = 0;
1547     } else {
1548       enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_;
1549     }
1550     // Reset any parameter in the encoder that is set in the previous iteration.
1551     enc->cache_bits_ = 0;
1552     VP8LBackwardRefsClear(&enc->refs_[0]);
1553     VP8LBackwardRefsClear(&enc->refs_[1]);
1554 
1555 #if (WEBP_NEAR_LOSSLESS == 1)
1556     // Apply near-lossless preprocessing.
1557     use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ &&
1558                         !enc->use_predict_;
1559     if (use_near_lossless) {
1560       if (!AllocateTransformBuffer(enc, width, height)) goto Error;
1561       if ((enc->argb_content_ != kEncoderNearLossless) &&
1562           !VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) {
1563         WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1564         goto Error;
1565       }
1566       enc->argb_content_ = kEncoderNearLossless;
1567     } else {
1568       enc->argb_content_ = kEncoderNone;
1569     }
1570 #else
1571     enc->argb_content_ = kEncoderNone;
1572 #endif
1573 
1574     // Encode palette
1575     if (enc->use_palette_) {
1576       if (!PaletteSort(crunch_configs[idx].palette_sorting_type_, enc->pic_,
1577                        enc->palette_sorted_, enc->palette_size_,
1578                        enc->palette_)) {
1579         WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
1580         goto Error;
1581       }
1582       percent_range = remaining_percent / 4;
1583       if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) {
1584         goto Error;
1585       }
1586       remaining_percent -= percent_range;
1587       if (!MapImageFromPalette(enc)) goto Error;
1588       // If using a color cache, do not have it bigger than the number of
1589       // colors.
1590       if (enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
1591         enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1;
1592       }
1593     }
1594     // In case image is not packed.
1595     if (enc->argb_content_ != kEncoderNearLossless &&
1596         enc->argb_content_ != kEncoderPalette) {
1597       if (!MakeInputImageCopy(enc)) goto Error;
1598     }
1599 
1600     // -------------------------------------------------------------------------
1601     // Apply transforms and write transform data.
1602 
1603     if (enc->use_subtract_green_) {
1604       ApplySubtractGreen(enc, enc->current_width_, height, bw);
1605     }
1606 
1607     if (enc->use_predict_) {
1608       percent_range = remaining_percent / 3;
1609       if (!ApplyPredictFilter(enc, enc->current_width_, height, quality,
1610                               low_effort, enc->use_subtract_green_, bw,
1611                               percent_range, &percent)) {
1612         goto Error;
1613       }
1614       remaining_percent -= percent_range;
1615     }
1616 
1617     if (enc->use_cross_color_) {
1618       percent_range = remaining_percent / 2;
1619       if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality,
1620                                  low_effort, bw, percent_range, &percent)) {
1621         goto Error;
1622       }
1623       remaining_percent -= percent_range;
1624     }
1625 
1626     VP8LPutBits(bw, !TRANSFORM_PRESENT, 1);  // No more transforms.
1627 
1628     // -------------------------------------------------------------------------
1629     // Encode and write the transformed image.
1630     if (!EncodeImageInternal(
1631             bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_,
1632             height, quality, low_effort, &crunch_configs[idx],
1633             &enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size,
1634             &data_size, picture, remaining_percent, &percent)) {
1635       goto Error;
1636     }
1637 
1638     // If we are better than what we already have.
1639     if (VP8LBitWriterNumBytes(bw) < best_size) {
1640       best_size = VP8LBitWriterNumBytes(bw);
1641       // Store the BitWriter.
1642       VP8LBitWriterSwap(bw, &bw_best);
1643 #if !defined(WEBP_DISABLE_STATS)
1644       // Update the stats.
1645       if (stats != NULL) {
1646         stats->lossless_features = 0;
1647         if (enc->use_predict_) stats->lossless_features |= 1;
1648         if (enc->use_cross_color_) stats->lossless_features |= 2;
1649         if (enc->use_subtract_green_) stats->lossless_features |= 4;
1650         if (enc->use_palette_) stats->lossless_features |= 8;
1651         stats->histogram_bits = enc->histo_bits_;
1652         stats->transform_bits = enc->predictor_transform_bits_;
1653         stats->cross_color_transform_bits = enc->cross_color_transform_bits_;
1654         stats->cache_bits = enc->cache_bits_;
1655         stats->palette_size = enc->palette_size_;
1656         stats->lossless_size = (int)(best_size - byte_position);
1657         stats->lossless_hdr_size = hdr_size;
1658         stats->lossless_data_size = data_size;
1659       }
1660 #endif
1661     }
1662     // Reset the bit writer for the following iteration if any.
1663     if (num_crunch_configs > 1) VP8LBitWriterReset(&bw_init, bw);
1664   }
1665   VP8LBitWriterSwap(&bw_best, bw);
1666 
1667  Error:
1668   VP8LBitWriterWipeOut(&bw_best);
1669   // The hook should return false in case of error.
1670   return (params->picture_->error_code == VP8_ENC_OK);
1671 }
1672 
VP8LEncodeStream(const WebPConfig * const config,const WebPPicture * const picture,VP8LBitWriter * const bw_main)1673 int VP8LEncodeStream(const WebPConfig* const config,
1674                      const WebPPicture* const picture,
1675                      VP8LBitWriter* const bw_main) {
1676   VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture);
1677   VP8LEncoder* enc_side = NULL;
1678   CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX];
1679   int num_crunch_configs_main, num_crunch_configs_side = 0;
1680   int idx;
1681   int red_and_blue_always_zero = 0;
1682   WebPWorker worker_main, worker_side;
1683   StreamEncodeContext params_main, params_side;
1684   // The main thread uses picture->stats, the side thread uses stats_side.
1685   WebPAuxStats stats_side;
1686   VP8LBitWriter bw_side;
1687   WebPPicture picture_side;
1688   const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface();
1689   int ok_main;
1690 
1691   if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) {
1692     VP8LEncoderDelete(enc_main);
1693     return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1694   }
1695 
1696   // Avoid "garbage value" error from Clang's static analysis tool.
1697   if (!WebPPictureInit(&picture_side)) {
1698     goto Error;
1699   }
1700 
1701   // Analyze image (entropy, num_palettes etc)
1702   if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
1703                       &red_and_blue_always_zero) ||
1704       !EncoderInit(enc_main)) {
1705     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1706     goto Error;
1707   }
1708 
1709   // Split the configs between the main and side threads (if any).
1710   if (config->thread_level > 0) {
1711     num_crunch_configs_side = num_crunch_configs_main / 2;
1712     for (idx = 0; idx < num_crunch_configs_side; ++idx) {
1713       params_side.crunch_configs_[idx] =
1714           crunch_configs[num_crunch_configs_main - num_crunch_configs_side +
1715                          idx];
1716     }
1717     params_side.num_crunch_configs_ = num_crunch_configs_side;
1718   }
1719   num_crunch_configs_main -= num_crunch_configs_side;
1720   for (idx = 0; idx < num_crunch_configs_main; ++idx) {
1721     params_main.crunch_configs_[idx] = crunch_configs[idx];
1722   }
1723   params_main.num_crunch_configs_ = num_crunch_configs_main;
1724 
1725   // Fill in the parameters for the thread workers.
1726   {
1727     const int params_size = (num_crunch_configs_side > 0) ? 2 : 1;
1728     for (idx = 0; idx < params_size; ++idx) {
1729       // Create the parameters for each worker.
1730       WebPWorker* const worker = (idx == 0) ? &worker_main : &worker_side;
1731       StreamEncodeContext* const param =
1732           (idx == 0) ? &params_main : &params_side;
1733       param->config_ = config;
1734       param->red_and_blue_always_zero_ = red_and_blue_always_zero;
1735       if (idx == 0) {
1736         param->picture_ = picture;
1737         param->stats_ = picture->stats;
1738         param->bw_ = bw_main;
1739         param->enc_ = enc_main;
1740       } else {
1741         // Create a side picture (error_code is not thread-safe).
1742         if (!WebPPictureView(picture, /*left=*/0, /*top=*/0, picture->width,
1743                              picture->height, &picture_side)) {
1744           assert(0);
1745         }
1746         picture_side.progress_hook = NULL;  // Progress hook is not thread-safe.
1747         param->picture_ = &picture_side;  // No need to free a view afterwards.
1748         param->stats_ = (picture->stats == NULL) ? NULL : &stats_side;
1749         // Create a side bit writer.
1750         if (!VP8LBitWriterClone(bw_main, &bw_side)) {
1751           WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1752           goto Error;
1753         }
1754         param->bw_ = &bw_side;
1755         // Create a side encoder.
1756         enc_side = VP8LEncoderNew(config, &picture_side);
1757         if (enc_side == NULL || !EncoderInit(enc_side)) {
1758           WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1759           goto Error;
1760         }
1761         // Copy the values that were computed for the main encoder.
1762         enc_side->histo_bits_ = enc_main->histo_bits_;
1763         enc_side->predictor_transform_bits_ =
1764             enc_main->predictor_transform_bits_;
1765         enc_side->cross_color_transform_bits_ =
1766             enc_main->cross_color_transform_bits_;
1767         enc_side->palette_size_ = enc_main->palette_size_;
1768         memcpy(enc_side->palette_, enc_main->palette_,
1769                sizeof(enc_main->palette_));
1770         memcpy(enc_side->palette_sorted_, enc_main->palette_sorted_,
1771                sizeof(enc_main->palette_sorted_));
1772         param->enc_ = enc_side;
1773       }
1774       // Create the workers.
1775       worker_interface->Init(worker);
1776       worker->data1 = param;
1777       worker->data2 = NULL;
1778       worker->hook = EncodeStreamHook;
1779     }
1780   }
1781 
1782   // Start the second thread if needed.
1783   if (num_crunch_configs_side != 0) {
1784     if (!worker_interface->Reset(&worker_side)) {
1785       WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1786       goto Error;
1787     }
1788 #if !defined(WEBP_DISABLE_STATS)
1789     // This line is here and not in the param initialization above to remove a
1790     // Clang static analyzer warning.
1791     if (picture->stats != NULL) {
1792       memcpy(&stats_side, picture->stats, sizeof(stats_side));
1793     }
1794 #endif
1795     worker_interface->Launch(&worker_side);
1796   }
1797   // Execute the main thread.
1798   worker_interface->Execute(&worker_main);
1799   ok_main = worker_interface->Sync(&worker_main);
1800   worker_interface->End(&worker_main);
1801   if (num_crunch_configs_side != 0) {
1802     // Wait for the second thread.
1803     const int ok_side = worker_interface->Sync(&worker_side);
1804     worker_interface->End(&worker_side);
1805     if (!ok_main || !ok_side) {
1806       if (picture->error_code == VP8_ENC_OK) {
1807         assert(picture_side.error_code != VP8_ENC_OK);
1808         WebPEncodingSetError(picture, picture_side.error_code);
1809       }
1810       goto Error;
1811     }
1812     if (VP8LBitWriterNumBytes(&bw_side) < VP8LBitWriterNumBytes(bw_main)) {
1813       VP8LBitWriterSwap(bw_main, &bw_side);
1814 #if !defined(WEBP_DISABLE_STATS)
1815       if (picture->stats != NULL) {
1816         memcpy(picture->stats, &stats_side, sizeof(*picture->stats));
1817       }
1818 #endif
1819     }
1820   }
1821 
1822  Error:
1823   VP8LBitWriterWipeOut(&bw_side);
1824   VP8LEncoderDelete(enc_main);
1825   VP8LEncoderDelete(enc_side);
1826   return (picture->error_code == VP8_ENC_OK);
1827 }
1828 
1829 #undef CRUNCH_CONFIGS_MAX
1830 #undef CRUNCH_SUBCONFIGS_MAX
1831 
VP8LEncodeImage(const WebPConfig * const config,const WebPPicture * const picture)1832 int VP8LEncodeImage(const WebPConfig* const config,
1833                     const WebPPicture* const picture) {
1834   int width, height;
1835   int has_alpha;
1836   size_t coded_size;
1837   int percent = 0;
1838   int initial_size;
1839   VP8LBitWriter bw;
1840 
1841   if (picture == NULL) return 0;
1842 
1843   if (config == NULL || picture->argb == NULL) {
1844     return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
1845   }
1846 
1847   width = picture->width;
1848   height = picture->height;
1849   // Initialize BitWriter with size corresponding to 16 bpp to photo images and
1850   // 8 bpp for graphical images.
1851   initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
1852       width * height : width * height * 2;
1853   if (!VP8LBitWriterInit(&bw, initial_size)) {
1854     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1855     goto Error;
1856   }
1857 
1858   if (!WebPReportProgress(picture, 1, &percent)) {
1859  UserAbort:
1860     WebPEncodingSetError(picture, VP8_ENC_ERROR_USER_ABORT);
1861     goto Error;
1862   }
1863   // Reset stats (for pure lossless coding)
1864   if (picture->stats != NULL) {
1865     WebPAuxStats* const stats = picture->stats;
1866     memset(stats, 0, sizeof(*stats));
1867     stats->PSNR[0] = 99.f;
1868     stats->PSNR[1] = 99.f;
1869     stats->PSNR[2] = 99.f;
1870     stats->PSNR[3] = 99.f;
1871     stats->PSNR[4] = 99.f;
1872   }
1873 
1874   // Write image size.
1875   if (!WriteImageSize(picture, &bw)) {
1876     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1877     goto Error;
1878   }
1879 
1880   has_alpha = WebPPictureHasTransparency(picture);
1881   // Write the non-trivial Alpha flag and lossless version.
1882   if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
1883     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1884     goto Error;
1885   }
1886 
1887   if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort;
1888 
1889   // Encode main image stream.
1890   if (!VP8LEncodeStream(config, picture, &bw)) goto Error;
1891 
1892   if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort;
1893 
1894   // Finish the RIFF chunk.
1895   if (!WriteImage(picture, &bw, &coded_size)) goto Error;
1896 
1897   if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
1898 
1899 #if !defined(WEBP_DISABLE_STATS)
1900   // Save size.
1901   if (picture->stats != NULL) {
1902     picture->stats->coded_size += (int)coded_size;
1903     picture->stats->lossless_size = (int)coded_size;
1904   }
1905 #endif
1906 
1907   if (picture->extra_info != NULL) {
1908     const int mb_w = (width + 15) >> 4;
1909     const int mb_h = (height + 15) >> 4;
1910     memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
1911   }
1912 
1913  Error:
1914   if (bw.error_) {
1915     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1916   }
1917   VP8LBitWriterWipeOut(&bw);
1918   return (picture->error_code == VP8_ENC_OK);
1919 }
1920 
1921 //------------------------------------------------------------------------------
1922