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