• 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 "./backward_references_enc.h"
19 #include "./histogram_enc.h"
20 #include "./vp8i_enc.h"
21 #include "./vp8li_enc.h"
22 #include "../dsp/lossless.h"
23 #include "../dsp/lossless_common.h"
24 #include "../utils/bit_writer_utils.h"
25 #include "../utils/huffman_encode_utils.h"
26 #include "../utils/utils.h"
27 #include "../webp/format_constants.h"
28 
29 #include "./delta_palettization_enc.h"
30 
31 #define PALETTE_KEY_RIGHT_SHIFT   22  // Key for 1K buffer.
32 // Maximum number of histogram images (sub-blocks).
33 #define MAX_HUFF_IMAGE_SIZE       2600
34 
35 // Palette reordering for smaller sum of deltas (and for smaller storage).
36 
PaletteCompareColorsForQsort(const void * p1,const void * p2)37 static int PaletteCompareColorsForQsort(const void* p1, const void* p2) {
38   const uint32_t a = WebPMemToUint32((uint8_t*)p1);
39   const uint32_t b = WebPMemToUint32((uint8_t*)p2);
40   assert(a != b);
41   return (a < b) ? -1 : 1;
42 }
43 
PaletteComponentDistance(uint32_t v)44 static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) {
45   return (v <= 128) ? v : (256 - v);
46 }
47 
48 // Computes a value that is related to the entropy created by the
49 // palette entry diff.
50 //
51 // Note that the last & 0xff is a no-operation in the next statement, but
52 // removed by most compilers and is here only for regularity of the code.
PaletteColorDistance(uint32_t col1,uint32_t col2)53 static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) {
54   const uint32_t diff = VP8LSubPixels(col1, col2);
55   const int kMoreWeightForRGBThanForAlpha = 9;
56   uint32_t score;
57   score =  PaletteComponentDistance((diff >>  0) & 0xff);
58   score += PaletteComponentDistance((diff >>  8) & 0xff);
59   score += PaletteComponentDistance((diff >> 16) & 0xff);
60   score *= kMoreWeightForRGBThanForAlpha;
61   score += PaletteComponentDistance((diff >> 24) & 0xff);
62   return score;
63 }
64 
SwapColor(uint32_t * const col1,uint32_t * const col2)65 static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
66   const uint32_t tmp = *col1;
67   *col1 = *col2;
68   *col2 = tmp;
69 }
70 
GreedyMinimizeDeltas(uint32_t palette[],int num_colors)71 static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
72   // Find greedily always the closest color of the predicted color to minimize
73   // deltas in the palette. This reduces storage needs since the
74   // palette is stored with delta encoding.
75   uint32_t predict = 0x00000000;
76   int i, k;
77   for (i = 0; i < num_colors; ++i) {
78     int best_ix = i;
79     uint32_t best_score = ~0U;
80     for (k = i; k < num_colors; ++k) {
81       const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
82       if (best_score > cur_score) {
83         best_score = cur_score;
84         best_ix = k;
85       }
86     }
87     SwapColor(&palette[best_ix], &palette[i]);
88     predict = palette[i];
89   }
90 }
91 
92 // The palette has been sorted by alpha. This function checks if the other
93 // components of the palette have a monotonic development with regards to
94 // position in the palette. If all have monotonic development, there is
95 // no benefit to re-organize them greedily. A monotonic development
96 // would be spotted in green-only situations (like lossy alpha) or gray-scale
97 // images.
PaletteHasNonMonotonousDeltas(uint32_t palette[],int num_colors)98 static int PaletteHasNonMonotonousDeltas(uint32_t palette[], int num_colors) {
99   uint32_t predict = 0x000000;
100   int i;
101   uint8_t sign_found = 0x00;
102   for (i = 0; i < num_colors; ++i) {
103     const uint32_t diff = VP8LSubPixels(palette[i], predict);
104     const uint8_t rd = (diff >> 16) & 0xff;
105     const uint8_t gd = (diff >>  8) & 0xff;
106     const uint8_t bd = (diff >>  0) & 0xff;
107     if (rd != 0x00) {
108       sign_found |= (rd < 0x80) ? 1 : 2;
109     }
110     if (gd != 0x00) {
111       sign_found |= (gd < 0x80) ? 8 : 16;
112     }
113     if (bd != 0x00) {
114       sign_found |= (bd < 0x80) ? 64 : 128;
115     }
116     predict = palette[i];
117   }
118   return (sign_found & (sign_found << 1)) != 0;  // two consequent signs.
119 }
120 
121 // -----------------------------------------------------------------------------
122 // Palette
123 
124 // If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
125 // creates a palette and returns true, else returns false.
AnalyzeAndCreatePalette(const WebPPicture * const pic,int low_effort,uint32_t palette[MAX_PALETTE_SIZE],int * const palette_size)126 static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
127                                    int low_effort,
128                                    uint32_t palette[MAX_PALETTE_SIZE],
129                                    int* const palette_size) {
130   const int num_colors = WebPGetColorPalette(pic, palette);
131   if (num_colors > MAX_PALETTE_SIZE) return 0;
132   *palette_size = num_colors;
133   qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
134   if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {
135     GreedyMinimizeDeltas(palette, num_colors);
136   }
137   return 1;
138 }
139 
140 // These five modes are evaluated and their respective entropy is computed.
141 typedef enum {
142   kDirect = 0,
143   kSpatial = 1,
144   kSubGreen = 2,
145   kSpatialSubGreen = 3,
146   kPalette = 4,
147   kNumEntropyIx = 5
148 } EntropyIx;
149 
150 typedef enum {
151   kHistoAlpha = 0,
152   kHistoAlphaPred,
153   kHistoGreen,
154   kHistoGreenPred,
155   kHistoRed,
156   kHistoRedPred,
157   kHistoBlue,
158   kHistoBluePred,
159   kHistoRedSubGreen,
160   kHistoRedPredSubGreen,
161   kHistoBlueSubGreen,
162   kHistoBluePredSubGreen,
163   kHistoPalette,
164   kHistoTotal  // Must be last.
165 } HistoIx;
166 
AddSingleSubGreen(int p,uint32_t * const r,uint32_t * const b)167 static void AddSingleSubGreen(int p, uint32_t* const r, uint32_t* const b) {
168   const int green = p >> 8;  // The upper bits are masked away later.
169   ++r[((p >> 16) - green) & 0xff];
170   ++b[((p >>  0) - green) & 0xff];
171 }
172 
AddSingle(uint32_t p,uint32_t * const a,uint32_t * const r,uint32_t * const g,uint32_t * const b)173 static void AddSingle(uint32_t p,
174                       uint32_t* const a, uint32_t* const r,
175                       uint32_t* const g, uint32_t* const b) {
176   ++a[(p >> 24) & 0xff];
177   ++r[(p >> 16) & 0xff];
178   ++g[(p >>  8) & 0xff];
179   ++b[(p >>  0) & 0xff];
180 }
181 
HashPix(uint32_t pix)182 static WEBP_INLINE uint32_t HashPix(uint32_t pix) {
183   // Note that masking with 0xffffffffu is for preventing an
184   // 'unsigned int overflow' warning. Doesn't impact the compiled code.
185   return ((((uint64_t)pix + (pix >> 19)) * 0x39c5fba7ull) & 0xffffffffu) >> 24;
186 }
187 
AnalyzeEntropy(const uint32_t * argb,int width,int height,int argb_stride,int use_palette,EntropyIx * const min_entropy_ix,int * const red_and_blue_always_zero)188 static int AnalyzeEntropy(const uint32_t* argb,
189                           int width, int height, int argb_stride,
190                           int use_palette,
191                           EntropyIx* const min_entropy_ix,
192                           int* const red_and_blue_always_zero) {
193   // Allocate histogram set with cache_bits = 0.
194   uint32_t* const histo =
195       (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256);
196   if (histo != NULL) {
197     int i, x, y;
198     const uint32_t* prev_row = argb;
199     const uint32_t* curr_row = argb + argb_stride;
200     for (y = 1; y < height; ++y) {
201       uint32_t prev_pix = curr_row[0];
202       for (x = 1; x < width; ++x) {
203         const uint32_t pix = curr_row[x];
204         const uint32_t pix_diff = VP8LSubPixels(pix, prev_pix);
205         if ((pix_diff == 0) || (pix == prev_row[x])) continue;
206         prev_pix = pix;
207         AddSingle(pix,
208                   &histo[kHistoAlpha * 256],
209                   &histo[kHistoRed * 256],
210                   &histo[kHistoGreen * 256],
211                   &histo[kHistoBlue * 256]);
212         AddSingle(pix_diff,
213                   &histo[kHistoAlphaPred * 256],
214                   &histo[kHistoRedPred * 256],
215                   &histo[kHistoGreenPred * 256],
216                   &histo[kHistoBluePred * 256]);
217         AddSingleSubGreen(pix,
218                           &histo[kHistoRedSubGreen * 256],
219                           &histo[kHistoBlueSubGreen * 256]);
220         AddSingleSubGreen(pix_diff,
221                           &histo[kHistoRedPredSubGreen * 256],
222                           &histo[kHistoBluePredSubGreen * 256]);
223         {
224           // Approximate the palette by the entropy of the multiplicative hash.
225           const uint32_t hash = HashPix(pix);
226           ++histo[kHistoPalette * 256 + hash];
227         }
228       }
229       prev_row = curr_row;
230       curr_row += argb_stride;
231     }
232     {
233       double entropy_comp[kHistoTotal];
234       double entropy[kNumEntropyIx];
235       int k;
236       int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen;
237       int j;
238       // Let's add one zero to the predicted histograms. The zeros are removed
239       // too efficiently by the pix_diff == 0 comparison, at least one of the
240       // zeros is likely to exist.
241       ++histo[kHistoRedPredSubGreen * 256];
242       ++histo[kHistoBluePredSubGreen * 256];
243       ++histo[kHistoRedPred * 256];
244       ++histo[kHistoGreenPred * 256];
245       ++histo[kHistoBluePred * 256];
246       ++histo[kHistoAlphaPred * 256];
247 
248       for (j = 0; j < kHistoTotal; ++j) {
249         entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256, NULL);
250       }
251       entropy[kDirect] = entropy_comp[kHistoAlpha] +
252           entropy_comp[kHistoRed] +
253           entropy_comp[kHistoGreen] +
254           entropy_comp[kHistoBlue];
255       entropy[kSpatial] = entropy_comp[kHistoAlphaPred] +
256           entropy_comp[kHistoRedPred] +
257           entropy_comp[kHistoGreenPred] +
258           entropy_comp[kHistoBluePred];
259       entropy[kSubGreen] = entropy_comp[kHistoAlpha] +
260           entropy_comp[kHistoRedSubGreen] +
261           entropy_comp[kHistoGreen] +
262           entropy_comp[kHistoBlueSubGreen];
263       entropy[kSpatialSubGreen] = entropy_comp[kHistoAlphaPred] +
264           entropy_comp[kHistoRedPredSubGreen] +
265           entropy_comp[kHistoGreenPred] +
266           entropy_comp[kHistoBluePredSubGreen];
267       // Palette mode seems more efficient in a breakeven case. Bias with 1.0.
268       entropy[kPalette] = entropy_comp[kHistoPalette] - 1.0;
269 
270       *min_entropy_ix = kDirect;
271       for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) {
272         if (entropy[*min_entropy_ix] > entropy[k]) {
273           *min_entropy_ix = (EntropyIx)k;
274         }
275       }
276       *red_and_blue_always_zero = 1;
277       // Let's check if the histogram of the chosen entropy mode has
278       // non-zero red and blue values. If all are zero, we can later skip
279       // the cross color optimization.
280       {
281         static const uint8_t kHistoPairs[5][2] = {
282           { kHistoRed, kHistoBlue },
283           { kHistoRedPred, kHistoBluePred },
284           { kHistoRedSubGreen, kHistoBlueSubGreen },
285           { kHistoRedPredSubGreen, kHistoBluePredSubGreen },
286           { kHistoRed, kHistoBlue }
287         };
288         const uint32_t* const red_histo =
289             &histo[256 * kHistoPairs[*min_entropy_ix][0]];
290         const uint32_t* const blue_histo =
291             &histo[256 * kHistoPairs[*min_entropy_ix][1]];
292         for (i = 1; i < 256; ++i) {
293           if ((red_histo[i] | blue_histo[i]) != 0) {
294             *red_and_blue_always_zero = 0;
295             break;
296           }
297         }
298       }
299     }
300     WebPSafeFree(histo);
301     return 1;
302   } else {
303     return 0;
304   }
305 }
306 
GetHistoBits(int method,int use_palette,int width,int height)307 static int GetHistoBits(int method, int use_palette, int width, int height) {
308   // Make tile size a function of encoding method (Range: 0 to 6).
309   int histo_bits = (use_palette ? 9 : 7) - method;
310   while (1) {
311     const int huff_image_size = VP8LSubSampleSize(width, histo_bits) *
312                                 VP8LSubSampleSize(height, histo_bits);
313     if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
314     ++histo_bits;
315   }
316   return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
317          (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
318 }
319 
GetTransformBits(int method,int histo_bits)320 static int GetTransformBits(int method, int histo_bits) {
321   const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5;
322   const int res =
323       (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits;
324   assert(res <= MAX_TRANSFORM_BITS);
325   return res;
326 }
327 
AnalyzeAndInit(VP8LEncoder * const enc)328 static int AnalyzeAndInit(VP8LEncoder* const enc) {
329   const WebPPicture* const pic = enc->pic_;
330   const int width = pic->width;
331   const int height = pic->height;
332   const int pix_cnt = width * height;
333   const WebPConfig* const config = enc->config_;
334   const int method = config->method;
335   const int low_effort = (config->method == 0);
336   // we round the block size up, so we're guaranteed to have
337   // at max MAX_REFS_BLOCK_PER_IMAGE blocks used:
338   int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1;
339   assert(pic != NULL && pic->argb != NULL);
340 
341   enc->use_cross_color_ = 0;
342   enc->use_predict_ = 0;
343   enc->use_subtract_green_ = 0;
344   enc->use_palette_ =
345       AnalyzeAndCreatePalette(pic, low_effort,
346                               enc->palette_, &enc->palette_size_);
347 
348   // TODO(jyrki): replace the decision to be based on an actual estimate
349   // of entropy, or even spatial variance of entropy.
350   enc->histo_bits_ = GetHistoBits(method, enc->use_palette_,
351                                   pic->width, pic->height);
352   enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_);
353 
354   if (low_effort) {
355     // AnalyzeEntropy is somewhat slow.
356     enc->use_predict_ = !enc->use_palette_;
357     enc->use_subtract_green_ = !enc->use_palette_;
358     enc->use_cross_color_ = 0;
359   } else {
360     int red_and_blue_always_zero;
361     EntropyIx min_entropy_ix;
362     if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride,
363                         enc->use_palette_, &min_entropy_ix,
364                         &red_and_blue_always_zero)) {
365       return 0;
366     }
367     enc->use_palette_ = (min_entropy_ix == kPalette);
368     enc->use_subtract_green_ =
369         (min_entropy_ix == kSubGreen) || (min_entropy_ix == kSpatialSubGreen);
370     enc->use_predict_ =
371         (min_entropy_ix == kSpatial) || (min_entropy_ix == kSpatialSubGreen);
372     enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_;
373   }
374 
375   if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0;
376 
377   // palette-friendly input typically uses less literals
378   //  -> reduce block size a bit
379   if (enc->use_palette_) refs_block_size /= 2;
380   VP8LBackwardRefsInit(&enc->refs_[0], refs_block_size);
381   VP8LBackwardRefsInit(&enc->refs_[1], refs_block_size);
382 
383   return 1;
384 }
385 
386 // Returns false in case of memory error.
GetHuffBitLengthsAndCodes(const VP8LHistogramSet * const histogram_image,HuffmanTreeCode * const huffman_codes)387 static int GetHuffBitLengthsAndCodes(
388     const VP8LHistogramSet* const histogram_image,
389     HuffmanTreeCode* const huffman_codes) {
390   int i, k;
391   int ok = 0;
392   uint64_t total_length_size = 0;
393   uint8_t* mem_buf = NULL;
394   const int histogram_image_size = histogram_image->size;
395   int max_num_symbols = 0;
396   uint8_t* buf_rle = NULL;
397   HuffmanTree* huff_tree = NULL;
398 
399   // Iterate over all histograms and get the aggregate number of codes used.
400   for (i = 0; i < histogram_image_size; ++i) {
401     const VP8LHistogram* const histo = histogram_image->histograms[i];
402     HuffmanTreeCode* const codes = &huffman_codes[5 * i];
403     for (k = 0; k < 5; ++k) {
404       const int num_symbols =
405           (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) :
406           (k == 4) ? NUM_DISTANCE_CODES : 256;
407       codes[k].num_symbols = num_symbols;
408       total_length_size += num_symbols;
409     }
410   }
411 
412   // Allocate and Set Huffman codes.
413   {
414     uint16_t* codes;
415     uint8_t* lengths;
416     mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size,
417                                        sizeof(*lengths) + sizeof(*codes));
418     if (mem_buf == NULL) goto End;
419 
420     codes = (uint16_t*)mem_buf;
421     lengths = (uint8_t*)&codes[total_length_size];
422     for (i = 0; i < 5 * histogram_image_size; ++i) {
423       const int bit_length = huffman_codes[i].num_symbols;
424       huffman_codes[i].codes = codes;
425       huffman_codes[i].code_lengths = lengths;
426       codes += bit_length;
427       lengths += bit_length;
428       if (max_num_symbols < bit_length) {
429         max_num_symbols = bit_length;
430       }
431     }
432   }
433 
434   buf_rle = (uint8_t*)WebPSafeMalloc(1ULL, max_num_symbols);
435   huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * max_num_symbols,
436                                            sizeof(*huff_tree));
437   if (buf_rle == NULL || huff_tree == NULL) goto End;
438 
439   // Create Huffman trees.
440   for (i = 0; i < histogram_image_size; ++i) {
441     HuffmanTreeCode* const codes = &huffman_codes[5 * i];
442     VP8LHistogram* const histo = histogram_image->histograms[i];
443     VP8LCreateHuffmanTree(histo->literal_, 15, buf_rle, huff_tree, codes + 0);
444     VP8LCreateHuffmanTree(histo->red_, 15, buf_rle, huff_tree, codes + 1);
445     VP8LCreateHuffmanTree(histo->blue_, 15, buf_rle, huff_tree, codes + 2);
446     VP8LCreateHuffmanTree(histo->alpha_, 15, buf_rle, huff_tree, codes + 3);
447     VP8LCreateHuffmanTree(histo->distance_, 15, buf_rle, huff_tree, codes + 4);
448   }
449   ok = 1;
450  End:
451   WebPSafeFree(huff_tree);
452   WebPSafeFree(buf_rle);
453   if (!ok) {
454     WebPSafeFree(mem_buf);
455     memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
456   }
457   return ok;
458 }
459 
StoreHuffmanTreeOfHuffmanTreeToBitMask(VP8LBitWriter * const bw,const uint8_t * code_length_bitdepth)460 static void StoreHuffmanTreeOfHuffmanTreeToBitMask(
461     VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) {
462   // RFC 1951 will calm you down if you are worried about this funny sequence.
463   // This sequence is tuned from that, but more weighted for lower symbol count,
464   // and more spiking histograms.
465   static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = {
466     17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
467   };
468   int i;
469   // Throw away trailing zeros:
470   int codes_to_store = CODE_LENGTH_CODES;
471   for (; codes_to_store > 4; --codes_to_store) {
472     if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
473       break;
474     }
475   }
476   VP8LPutBits(bw, codes_to_store - 4, 4);
477   for (i = 0; i < codes_to_store; ++i) {
478     VP8LPutBits(bw, code_length_bitdepth[kStorageOrder[i]], 3);
479   }
480 }
481 
ClearHuffmanTreeIfOnlyOneSymbol(HuffmanTreeCode * const huffman_code)482 static void ClearHuffmanTreeIfOnlyOneSymbol(
483     HuffmanTreeCode* const huffman_code) {
484   int k;
485   int count = 0;
486   for (k = 0; k < huffman_code->num_symbols; ++k) {
487     if (huffman_code->code_lengths[k] != 0) {
488       ++count;
489       if (count > 1) return;
490     }
491   }
492   for (k = 0; k < huffman_code->num_symbols; ++k) {
493     huffman_code->code_lengths[k] = 0;
494     huffman_code->codes[k] = 0;
495   }
496 }
497 
StoreHuffmanTreeToBitMask(VP8LBitWriter * const bw,const HuffmanTreeToken * const tokens,const int num_tokens,const HuffmanTreeCode * const huffman_code)498 static void StoreHuffmanTreeToBitMask(
499     VP8LBitWriter* const bw,
500     const HuffmanTreeToken* const tokens, const int num_tokens,
501     const HuffmanTreeCode* const huffman_code) {
502   int i;
503   for (i = 0; i < num_tokens; ++i) {
504     const int ix = tokens[i].code;
505     const int extra_bits = tokens[i].extra_bits;
506     VP8LPutBits(bw, huffman_code->codes[ix], huffman_code->code_lengths[ix]);
507     switch (ix) {
508       case 16:
509         VP8LPutBits(bw, extra_bits, 2);
510         break;
511       case 17:
512         VP8LPutBits(bw, extra_bits, 3);
513         break;
514       case 18:
515         VP8LPutBits(bw, extra_bits, 7);
516         break;
517     }
518   }
519 }
520 
521 // 'huff_tree' and 'tokens' are pre-alloacted buffers.
StoreFullHuffmanCode(VP8LBitWriter * const bw,HuffmanTree * const huff_tree,HuffmanTreeToken * const tokens,const HuffmanTreeCode * const tree)522 static void StoreFullHuffmanCode(VP8LBitWriter* const bw,
523                                  HuffmanTree* const huff_tree,
524                                  HuffmanTreeToken* const tokens,
525                                  const HuffmanTreeCode* const tree) {
526   uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
527   uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
528   const int max_tokens = tree->num_symbols;
529   int num_tokens;
530   HuffmanTreeCode huffman_code;
531   huffman_code.num_symbols = CODE_LENGTH_CODES;
532   huffman_code.code_lengths = code_length_bitdepth;
533   huffman_code.codes = code_length_bitdepth_symbols;
534 
535   VP8LPutBits(bw, 0, 1);
536   num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens);
537   {
538     uint32_t histogram[CODE_LENGTH_CODES] = { 0 };
539     uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 };
540     int i;
541     for (i = 0; i < num_tokens; ++i) {
542       ++histogram[tokens[i].code];
543     }
544 
545     VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code);
546   }
547 
548   StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
549   ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code);
550   {
551     int trailing_zero_bits = 0;
552     int trimmed_length = num_tokens;
553     int write_trimmed_length;
554     int length;
555     int i = num_tokens;
556     while (i-- > 0) {
557       const int ix = tokens[i].code;
558       if (ix == 0 || ix == 17 || ix == 18) {
559         --trimmed_length;   // discount trailing zeros
560         trailing_zero_bits += code_length_bitdepth[ix];
561         if (ix == 17) {
562           trailing_zero_bits += 3;
563         } else if (ix == 18) {
564           trailing_zero_bits += 7;
565         }
566       } else {
567         break;
568       }
569     }
570     write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
571     length = write_trimmed_length ? trimmed_length : num_tokens;
572     VP8LPutBits(bw, write_trimmed_length, 1);
573     if (write_trimmed_length) {
574       const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
575       const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
576       VP8LPutBits(bw, nbitpairs - 1, 3);
577       assert(trimmed_length >= 2);
578       VP8LPutBits(bw, trimmed_length - 2, nbitpairs * 2);
579     }
580     StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
581   }
582 }
583 
584 // 'huff_tree' and 'tokens' are pre-alloacted buffers.
StoreHuffmanCode(VP8LBitWriter * const bw,HuffmanTree * const huff_tree,HuffmanTreeToken * const tokens,const HuffmanTreeCode * const huffman_code)585 static void StoreHuffmanCode(VP8LBitWriter* const bw,
586                              HuffmanTree* const huff_tree,
587                              HuffmanTreeToken* const tokens,
588                              const HuffmanTreeCode* const huffman_code) {
589   int i;
590   int count = 0;
591   int symbols[2] = { 0, 0 };
592   const int kMaxBits = 8;
593   const int kMaxSymbol = 1 << kMaxBits;
594 
595   // Check whether it's a small tree.
596   for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) {
597     if (huffman_code->code_lengths[i] != 0) {
598       if (count < 2) symbols[count] = i;
599       ++count;
600     }
601   }
602 
603   if (count == 0) {   // emit minimal tree for empty cases
604     // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
605     VP8LPutBits(bw, 0x01, 4);
606   } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
607     VP8LPutBits(bw, 1, 1);  // Small tree marker to encode 1 or 2 symbols.
608     VP8LPutBits(bw, count - 1, 1);
609     if (symbols[0] <= 1) {
610       VP8LPutBits(bw, 0, 1);  // Code bit for small (1 bit) symbol value.
611       VP8LPutBits(bw, symbols[0], 1);
612     } else {
613       VP8LPutBits(bw, 1, 1);
614       VP8LPutBits(bw, symbols[0], 8);
615     }
616     if (count == 2) {
617       VP8LPutBits(bw, symbols[1], 8);
618     }
619   } else {
620     StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code);
621   }
622 }
623 
WriteHuffmanCode(VP8LBitWriter * const bw,const HuffmanTreeCode * const code,int code_index)624 static WEBP_INLINE void WriteHuffmanCode(VP8LBitWriter* const bw,
625                              const HuffmanTreeCode* const code,
626                              int code_index) {
627   const int depth = code->code_lengths[code_index];
628   const int symbol = code->codes[code_index];
629   VP8LPutBits(bw, symbol, depth);
630 }
631 
WriteHuffmanCodeWithExtraBits(VP8LBitWriter * const bw,const HuffmanTreeCode * const code,int code_index,int bits,int n_bits)632 static WEBP_INLINE void WriteHuffmanCodeWithExtraBits(
633     VP8LBitWriter* const bw,
634     const HuffmanTreeCode* const code,
635     int code_index,
636     int bits,
637     int n_bits) {
638   const int depth = code->code_lengths[code_index];
639   const int symbol = code->codes[code_index];
640   VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits);
641 }
642 
StoreImageToBitMask(VP8LBitWriter * const bw,int width,int histo_bits,VP8LBackwardRefs * const refs,const uint16_t * histogram_symbols,const HuffmanTreeCode * const huffman_codes)643 static WebPEncodingError StoreImageToBitMask(
644     VP8LBitWriter* const bw, int width, int histo_bits,
645     VP8LBackwardRefs* const refs,
646     const uint16_t* histogram_symbols,
647     const HuffmanTreeCode* const huffman_codes) {
648   const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
649   const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits);
650   // x and y trace the position in the image.
651   int x = 0;
652   int y = 0;
653   int tile_x = x & tile_mask;
654   int tile_y = y & tile_mask;
655   int histogram_ix = histogram_symbols[0];
656   const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix;
657   VP8LRefsCursor c = VP8LRefsCursorInit(refs);
658   while (VP8LRefsCursorOk(&c)) {
659     const PixOrCopy* const v = c.cur_pos;
660     if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) {
661       tile_x = x & tile_mask;
662       tile_y = y & tile_mask;
663       histogram_ix = histogram_symbols[(y >> histo_bits) * histo_xsize +
664                                        (x >> histo_bits)];
665       codes = huffman_codes + 5 * histogram_ix;
666     }
667     if (PixOrCopyIsLiteral(v)) {
668       static const int order[] = { 1, 2, 0, 3 };
669       int k;
670       for (k = 0; k < 4; ++k) {
671         const int code = PixOrCopyLiteral(v, order[k]);
672         WriteHuffmanCode(bw, codes + k, code);
673       }
674     } else if (PixOrCopyIsCacheIdx(v)) {
675       const int code = PixOrCopyCacheIdx(v);
676       const int literal_ix = 256 + NUM_LENGTH_CODES + code;
677       WriteHuffmanCode(bw, codes, literal_ix);
678     } else {
679       int bits, n_bits;
680       int code;
681 
682       const int distance = PixOrCopyDistance(v);
683       VP8LPrefixEncode(v->len, &code, &n_bits, &bits);
684       WriteHuffmanCodeWithExtraBits(bw, codes, 256 + code, bits, n_bits);
685 
686       // Don't write the distance with the extra bits code since
687       // the distance can be up to 18 bits of extra bits, and the prefix
688       // 15 bits, totaling to 33, and our PutBits only supports up to 32 bits.
689       // TODO(jyrki): optimize this further.
690       VP8LPrefixEncode(distance, &code, &n_bits, &bits);
691       WriteHuffmanCode(bw, codes + 4, code);
692       VP8LPutBits(bw, bits, n_bits);
693     }
694     x += PixOrCopyLength(v);
695     while (x >= width) {
696       x -= width;
697       ++y;
698     }
699     VP8LRefsCursorNext(&c);
700   }
701   return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK;
702 }
703 
704 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
EncodeImageNoHuffman(VP8LBitWriter * const bw,const uint32_t * const argb,VP8LHashChain * const hash_chain,VP8LBackwardRefs refs_array[2],int width,int height,int quality,int low_effort)705 static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
706                                               const uint32_t* const argb,
707                                               VP8LHashChain* const hash_chain,
708                                               VP8LBackwardRefs refs_array[2],
709                                               int width, int height,
710                                               int quality, int low_effort) {
711   int i;
712   int max_tokens = 0;
713   WebPEncodingError err = VP8_ENC_OK;
714   VP8LBackwardRefs* refs;
715   HuffmanTreeToken* tokens = NULL;
716   HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
717   const uint16_t histogram_symbols[1] = { 0 };    // only one tree, one symbol
718   int cache_bits = 0;
719   VP8LHistogramSet* histogram_image = NULL;
720   HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
721         3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
722   if (huff_tree == NULL) {
723     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
724     goto Error;
725   }
726 
727   // Calculate backward references from ARGB image.
728   if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
729                          low_effort)) {
730     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
731     goto Error;
732   }
733   refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, &cache_bits,
734                                    hash_chain, refs_array);
735   if (refs == NULL) {
736     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
737     goto Error;
738   }
739   histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
740   if (histogram_image == NULL) {
741     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
742     goto Error;
743   }
744 
745   // Build histogram image and symbols from backward references.
746   VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);
747 
748   // Create Huffman bit lengths and codes for each histogram image.
749   assert(histogram_image->size == 1);
750   if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
751     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
752     goto Error;
753   }
754 
755   // No color cache, no Huffman image.
756   VP8LPutBits(bw, 0, 1);
757 
758   // Find maximum number of symbols for the huffman tree-set.
759   for (i = 0; i < 5; ++i) {
760     HuffmanTreeCode* const codes = &huffman_codes[i];
761     if (max_tokens < codes->num_symbols) {
762       max_tokens = codes->num_symbols;
763     }
764   }
765 
766   tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
767   if (tokens == NULL) {
768     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
769     goto Error;
770   }
771 
772   // Store Huffman codes.
773   for (i = 0; i < 5; ++i) {
774     HuffmanTreeCode* const codes = &huffman_codes[i];
775     StoreHuffmanCode(bw, huff_tree, tokens, codes);
776     ClearHuffmanTreeIfOnlyOneSymbol(codes);
777   }
778 
779   // Store actual literals.
780   err = StoreImageToBitMask(bw, width, 0, refs, histogram_symbols,
781                             huffman_codes);
782 
783  Error:
784   WebPSafeFree(tokens);
785   WebPSafeFree(huff_tree);
786   VP8LFreeHistogramSet(histogram_image);
787   WebPSafeFree(huffman_codes[0].codes);
788   return err;
789 }
790 
EncodeImageInternal(VP8LBitWriter * const bw,const uint32_t * const argb,VP8LHashChain * const hash_chain,VP8LBackwardRefs refs_array[2],int width,int height,int quality,int low_effort,int use_cache,int * cache_bits,int histogram_bits,size_t init_byte_position,int * const hdr_size,int * const data_size)791 static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw,
792                                              const uint32_t* const argb,
793                                              VP8LHashChain* const hash_chain,
794                                              VP8LBackwardRefs refs_array[2],
795                                              int width, int height, int quality,
796                                              int low_effort,
797                                              int use_cache, int* cache_bits,
798                                              int histogram_bits,
799                                              size_t init_byte_position,
800                                              int* const hdr_size,
801                                              int* const data_size) {
802   WebPEncodingError err = VP8_ENC_OK;
803   const uint32_t histogram_image_xysize =
804       VP8LSubSampleSize(width, histogram_bits) *
805       VP8LSubSampleSize(height, histogram_bits);
806   VP8LHistogramSet* histogram_image = NULL;
807   VP8LHistogramSet* tmp_histos = NULL;
808   int histogram_image_size = 0;
809   size_t bit_array_size = 0;
810   HuffmanTree* huff_tree = NULL;
811   HuffmanTreeToken* tokens = NULL;
812   HuffmanTreeCode* huffman_codes = NULL;
813   VP8LBackwardRefs refs;
814   VP8LBackwardRefs* best_refs;
815   uint16_t* const histogram_symbols =
816       (uint16_t*)WebPSafeMalloc(histogram_image_xysize,
817                                 sizeof(*histogram_symbols));
818   assert(histogram_bits >= MIN_HUFFMAN_BITS);
819   assert(histogram_bits <= MAX_HUFFMAN_BITS);
820   assert(hdr_size != NULL);
821   assert(data_size != NULL);
822 
823   VP8LBackwardRefsInit(&refs, refs_array[0].block_size_);
824   if (histogram_symbols == NULL) {
825     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
826     goto Error;
827   }
828 
829   if (use_cache) {
830     // If the value is different from zero, it has been set during the
831     // palette analysis.
832     if (*cache_bits == 0) *cache_bits = MAX_COLOR_CACHE_BITS;
833   } else {
834     *cache_bits = 0;
835   }
836   // 'best_refs' is the reference to the best backward refs and points to one
837   // of refs_array[0] or refs_array[1].
838   // Calculate backward references from ARGB image.
839   if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
840                          low_effort)) {
841     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
842     goto Error;
843   }
844   best_refs = VP8LGetBackwardReferences(width, height, argb, quality,
845                                         low_effort, cache_bits, hash_chain,
846                                         refs_array);
847   if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) {
848     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
849     goto Error;
850   }
851   histogram_image =
852       VP8LAllocateHistogramSet(histogram_image_xysize, *cache_bits);
853   tmp_histos = VP8LAllocateHistogramSet(2, *cache_bits);
854   if (histogram_image == NULL || tmp_histos == NULL) {
855     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
856     goto Error;
857   }
858 
859   // Build histogram image and symbols from backward references.
860   if (!VP8LGetHistoImageSymbols(width, height, &refs, quality, low_effort,
861                                 histogram_bits, *cache_bits, histogram_image,
862                                 tmp_histos, histogram_symbols)) {
863     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
864     goto Error;
865   }
866   // Create Huffman bit lengths and codes for each histogram image.
867   histogram_image_size = histogram_image->size;
868   bit_array_size = 5 * histogram_image_size;
869   huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
870                                                    sizeof(*huffman_codes));
871   // Note: some histogram_image entries may point to tmp_histos[], so the latter
872   // need to outlive the following call to GetHuffBitLengthsAndCodes().
873   if (huffman_codes == NULL ||
874       !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
875     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
876     goto Error;
877   }
878   // Free combined histograms.
879   VP8LFreeHistogramSet(histogram_image);
880   histogram_image = NULL;
881 
882   // Free scratch histograms.
883   VP8LFreeHistogramSet(tmp_histos);
884   tmp_histos = NULL;
885 
886   // Color Cache parameters.
887   if (*cache_bits > 0) {
888     VP8LPutBits(bw, 1, 1);
889     VP8LPutBits(bw, *cache_bits, 4);
890   } else {
891     VP8LPutBits(bw, 0, 1);
892   }
893 
894   // Huffman image + meta huffman.
895   {
896     const int write_histogram_image = (histogram_image_size > 1);
897     VP8LPutBits(bw, write_histogram_image, 1);
898     if (write_histogram_image) {
899       uint32_t* const histogram_argb =
900           (uint32_t*)WebPSafeMalloc(histogram_image_xysize,
901                                     sizeof(*histogram_argb));
902       int max_index = 0;
903       uint32_t i;
904       if (histogram_argb == NULL) {
905         err = VP8_ENC_ERROR_OUT_OF_MEMORY;
906         goto Error;
907       }
908       for (i = 0; i < histogram_image_xysize; ++i) {
909         const int symbol_index = histogram_symbols[i] & 0xffff;
910         histogram_argb[i] = (symbol_index << 8);
911         if (symbol_index >= max_index) {
912           max_index = symbol_index + 1;
913         }
914       }
915       histogram_image_size = max_index;
916 
917       VP8LPutBits(bw, histogram_bits - 2, 3);
918       err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array,
919                                  VP8LSubSampleSize(width, histogram_bits),
920                                  VP8LSubSampleSize(height, histogram_bits),
921                                  quality, low_effort);
922       WebPSafeFree(histogram_argb);
923       if (err != VP8_ENC_OK) goto Error;
924     }
925   }
926 
927   // Store Huffman codes.
928   {
929     int i;
930     int max_tokens = 0;
931     huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * CODE_LENGTH_CODES,
932                                              sizeof(*huff_tree));
933     if (huff_tree == NULL) {
934       err = VP8_ENC_ERROR_OUT_OF_MEMORY;
935       goto Error;
936     }
937     // Find maximum number of symbols for the huffman tree-set.
938     for (i = 0; i < 5 * histogram_image_size; ++i) {
939       HuffmanTreeCode* const codes = &huffman_codes[i];
940       if (max_tokens < codes->num_symbols) {
941         max_tokens = codes->num_symbols;
942       }
943     }
944     tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens,
945                                                sizeof(*tokens));
946     if (tokens == NULL) {
947       err = VP8_ENC_ERROR_OUT_OF_MEMORY;
948       goto Error;
949     }
950     for (i = 0; i < 5 * histogram_image_size; ++i) {
951       HuffmanTreeCode* const codes = &huffman_codes[i];
952       StoreHuffmanCode(bw, huff_tree, tokens, codes);
953       ClearHuffmanTreeIfOnlyOneSymbol(codes);
954     }
955   }
956 
957   *hdr_size = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
958   // Store actual literals.
959   err = StoreImageToBitMask(bw, width, histogram_bits, &refs,
960                             histogram_symbols, huffman_codes);
961   *data_size =
962         (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size);
963 
964  Error:
965   WebPSafeFree(tokens);
966   WebPSafeFree(huff_tree);
967   VP8LFreeHistogramSet(histogram_image);
968   VP8LFreeHistogramSet(tmp_histos);
969   VP8LBackwardRefsClear(&refs);
970   if (huffman_codes != NULL) {
971     WebPSafeFree(huffman_codes->codes);
972     WebPSafeFree(huffman_codes);
973   }
974   WebPSafeFree(histogram_symbols);
975   return err;
976 }
977 
978 // -----------------------------------------------------------------------------
979 // Transforms
980 
ApplySubtractGreen(VP8LEncoder * const enc,int width,int height,VP8LBitWriter * const bw)981 static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height,
982                                VP8LBitWriter* const bw) {
983   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
984   VP8LPutBits(bw, SUBTRACT_GREEN, 2);
985   VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
986 }
987 
ApplyPredictFilter(const VP8LEncoder * const enc,int width,int height,int quality,int low_effort,int used_subtract_green,VP8LBitWriter * const bw)988 static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
989                                             int width, int height,
990                                             int quality, int low_effort,
991                                             int used_subtract_green,
992                                             VP8LBitWriter* const bw) {
993   const int pred_bits = enc->transform_bits_;
994   const int transform_width = VP8LSubSampleSize(width, pred_bits);
995   const int transform_height = VP8LSubSampleSize(height, pred_bits);
996   // we disable near-lossless quantization if palette is used.
997   const int near_lossless_strength = enc->use_palette_ ? 100
998                                    : enc->config_->near_lossless;
999 
1000   VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
1001                     enc->argb_scratch_, enc->transform_data_,
1002                     near_lossless_strength, enc->config_->exact,
1003                     used_subtract_green);
1004   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1005   VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
1006   assert(pred_bits >= 2);
1007   VP8LPutBits(bw, pred_bits - 2, 3);
1008   return EncodeImageNoHuffman(bw, enc->transform_data_,
1009                               (VP8LHashChain*)&enc->hash_chain_,
1010                               (VP8LBackwardRefs*)enc->refs_,  // cast const away
1011                               transform_width, transform_height,
1012                               quality, low_effort);
1013 }
1014 
ApplyCrossColorFilter(const VP8LEncoder * const enc,int width,int height,int quality,int low_effort,VP8LBitWriter * const bw)1015 static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
1016                                                int width, int height,
1017                                                int quality, int low_effort,
1018                                                VP8LBitWriter* const bw) {
1019   const int ccolor_transform_bits = enc->transform_bits_;
1020   const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
1021   const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
1022 
1023   VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality,
1024                           enc->argb_, enc->transform_data_);
1025   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1026   VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2);
1027   assert(ccolor_transform_bits >= 2);
1028   VP8LPutBits(bw, ccolor_transform_bits - 2, 3);
1029   return EncodeImageNoHuffman(bw, enc->transform_data_,
1030                               (VP8LHashChain*)&enc->hash_chain_,
1031                               (VP8LBackwardRefs*)enc->refs_,  // cast const away
1032                               transform_width, transform_height,
1033                               quality, low_effort);
1034 }
1035 
1036 // -----------------------------------------------------------------------------
1037 
WriteRiffHeader(const WebPPicture * const pic,size_t riff_size,size_t vp8l_size)1038 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
1039                                          size_t riff_size, size_t vp8l_size) {
1040   uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
1041     'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
1042     'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
1043   };
1044   PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
1045   PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
1046   if (!pic->writer(riff, sizeof(riff), pic)) {
1047     return VP8_ENC_ERROR_BAD_WRITE;
1048   }
1049   return VP8_ENC_OK;
1050 }
1051 
WriteImageSize(const WebPPicture * const pic,VP8LBitWriter * const bw)1052 static int WriteImageSize(const WebPPicture* const pic,
1053                           VP8LBitWriter* const bw) {
1054   const int width = pic->width - 1;
1055   const int height = pic->height - 1;
1056   assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
1057 
1058   VP8LPutBits(bw, width, VP8L_IMAGE_SIZE_BITS);
1059   VP8LPutBits(bw, height, VP8L_IMAGE_SIZE_BITS);
1060   return !bw->error_;
1061 }
1062 
WriteRealAlphaAndVersion(VP8LBitWriter * const bw,int has_alpha)1063 static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
1064   VP8LPutBits(bw, has_alpha, 1);
1065   VP8LPutBits(bw, VP8L_VERSION, VP8L_VERSION_BITS);
1066   return !bw->error_;
1067 }
1068 
WriteImage(const WebPPicture * const pic,VP8LBitWriter * const bw,size_t * const coded_size)1069 static WebPEncodingError WriteImage(const WebPPicture* const pic,
1070                                     VP8LBitWriter* const bw,
1071                                     size_t* const coded_size) {
1072   WebPEncodingError err = VP8_ENC_OK;
1073   const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
1074   const size_t webpll_size = VP8LBitWriterNumBytes(bw);
1075   const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
1076   const size_t pad = vp8l_size & 1;
1077   const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
1078 
1079   err = WriteRiffHeader(pic, riff_size, vp8l_size);
1080   if (err != VP8_ENC_OK) goto Error;
1081 
1082   if (!pic->writer(webpll_data, webpll_size, pic)) {
1083     err = VP8_ENC_ERROR_BAD_WRITE;
1084     goto Error;
1085   }
1086 
1087   if (pad) {
1088     const uint8_t pad_byte[1] = { 0 };
1089     if (!pic->writer(pad_byte, 1, pic)) {
1090       err = VP8_ENC_ERROR_BAD_WRITE;
1091       goto Error;
1092     }
1093   }
1094   *coded_size = CHUNK_HEADER_SIZE + riff_size;
1095   return VP8_ENC_OK;
1096 
1097  Error:
1098   return err;
1099 }
1100 
1101 // -----------------------------------------------------------------------------
1102 
ClearTransformBuffer(VP8LEncoder * const enc)1103 static void ClearTransformBuffer(VP8LEncoder* const enc) {
1104   WebPSafeFree(enc->transform_mem_);
1105   enc->transform_mem_ = NULL;
1106   enc->transform_mem_size_ = 0;
1107 }
1108 
1109 // Allocates the memory for argb (W x H) buffer, 2 rows of context for
1110 // prediction and transform data.
1111 // Flags influencing the memory allocated:
1112 //  enc->transform_bits_
1113 //  enc->use_predict_, enc->use_cross_color_
AllocateTransformBuffer(VP8LEncoder * const enc,int width,int height)1114 static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
1115                                                  int width, int height) {
1116   WebPEncodingError err = VP8_ENC_OK;
1117   const uint64_t image_size = width * height;
1118   // VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
1119   // pixel in each, plus 2 regular scanlines of bytes.
1120   // TODO(skal): Clean up by using arithmetic in bytes instead of words.
1121   const uint64_t argb_scratch_size =
1122       enc->use_predict_
1123           ? (width + 1) * 2 +
1124             (width * 2 + sizeof(uint32_t) - 1) / sizeof(uint32_t)
1125           : 0;
1126   const uint64_t transform_data_size =
1127       (enc->use_predict_ || enc->use_cross_color_)
1128           ? VP8LSubSampleSize(width, enc->transform_bits_) *
1129                 VP8LSubSampleSize(height, enc->transform_bits_)
1130           : 0;
1131   const uint64_t max_alignment_in_words =
1132       (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t);
1133   const uint64_t mem_size =
1134       image_size + max_alignment_in_words +
1135       argb_scratch_size + max_alignment_in_words +
1136       transform_data_size;
1137   uint32_t* mem = enc->transform_mem_;
1138   if (mem == NULL || mem_size > enc->transform_mem_size_) {
1139     ClearTransformBuffer(enc);
1140     mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem));
1141     if (mem == NULL) {
1142       err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1143       goto Error;
1144     }
1145     enc->transform_mem_ = mem;
1146     enc->transform_mem_size_ = (size_t)mem_size;
1147   }
1148   enc->argb_ = mem;
1149   mem = (uint32_t*)WEBP_ALIGN(mem + image_size);
1150   enc->argb_scratch_ = mem;
1151   mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size);
1152   enc->transform_data_ = mem;
1153 
1154   enc->current_width_ = width;
1155  Error:
1156   return err;
1157 }
1158 
MakeInputImageCopy(VP8LEncoder * const enc)1159 static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
1160   WebPEncodingError err = VP8_ENC_OK;
1161   const WebPPicture* const picture = enc->pic_;
1162   const int width = picture->width;
1163   const int height = picture->height;
1164   int y;
1165   err = AllocateTransformBuffer(enc, width, height);
1166   if (err != VP8_ENC_OK) return err;
1167   for (y = 0; y < height; ++y) {
1168     memcpy(enc->argb_ + y * width,
1169            picture->argb + y * picture->argb_stride,
1170            width * sizeof(*enc->argb_));
1171   }
1172   assert(enc->current_width_ == width);
1173   return VP8_ENC_OK;
1174 }
1175 
1176 // -----------------------------------------------------------------------------
1177 
SearchColorNoIdx(const uint32_t sorted[],uint32_t color,int hi)1178 static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
1179                                         int hi) {
1180   int low = 0;
1181   if (sorted[low] == color) return low;  // loop invariant: sorted[low] != color
1182   while (1) {
1183     const int mid = (low + hi) >> 1;
1184     if (sorted[mid] == color) {
1185       return mid;
1186     } else if (sorted[mid] < color) {
1187       low = mid;
1188     } else {
1189       hi = mid;
1190     }
1191   }
1192 }
1193 
1194 #define APPLY_PALETTE_GREEDY_MAX 4
1195 
SearchColorGreedy(const uint32_t palette[],int palette_size,uint32_t color)1196 static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[],
1197                                               int palette_size,
1198                                               uint32_t color) {
1199   (void)palette_size;
1200   assert(palette_size < APPLY_PALETTE_GREEDY_MAX);
1201   assert(3 == APPLY_PALETTE_GREEDY_MAX - 1);
1202   if (color == palette[0]) return 0;
1203   if (color == palette[1]) return 1;
1204   if (color == palette[2]) return 2;
1205   return 3;
1206 }
1207 
ApplyPaletteHash0(uint32_t color)1208 static WEBP_INLINE uint32_t ApplyPaletteHash0(uint32_t color) {
1209   // Focus on the green color.
1210   return (color >> 8) & 0xff;
1211 }
1212 
1213 #define PALETTE_INV_SIZE_BITS 11
1214 #define PALETTE_INV_SIZE (1 << PALETTE_INV_SIZE_BITS)
1215 
ApplyPaletteHash1(uint32_t color)1216 static WEBP_INLINE uint32_t ApplyPaletteHash1(uint32_t color) {
1217   // Forget about alpha.
1218   return ((color & 0x00ffffffu) * 4222244071u) >> (32 - PALETTE_INV_SIZE_BITS);
1219 }
1220 
ApplyPaletteHash2(uint32_t color)1221 static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) {
1222   // Forget about alpha.
1223   return (color & 0x00ffffffu) * ((1u << 31) - 1) >>
1224          (32 - PALETTE_INV_SIZE_BITS);
1225 }
1226 
1227 // Sort palette in increasing order and prepare an inverse mapping array.
PrepareMapToPalette(const uint32_t palette[],int num_colors,uint32_t sorted[],uint32_t idx_map[])1228 static void PrepareMapToPalette(const uint32_t palette[], int num_colors,
1229                                 uint32_t sorted[], uint32_t idx_map[]) {
1230   int i;
1231   memcpy(sorted, palette, num_colors * sizeof(*sorted));
1232   qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
1233   for (i = 0; i < num_colors; ++i) {
1234     idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
1235   }
1236 }
1237 
1238 // Use 1 pixel cache for ARGB pixels.
1239 #define APPLY_PALETTE_FOR(COLOR_INDEX) do {         \
1240   uint32_t prev_pix = palette[0];                   \
1241   uint32_t prev_idx = 0;                            \
1242   for (y = 0; y < height; ++y) {                    \
1243     for (x = 0; x < width; ++x) {                   \
1244       const uint32_t pix = src[x];                  \
1245       if (pix != prev_pix) {                        \
1246         prev_idx = COLOR_INDEX;                     \
1247         prev_pix = pix;                             \
1248       }                                             \
1249       tmp_row[x] = prev_idx;                        \
1250     }                                               \
1251     VP8LBundleColorMap(tmp_row, width, xbits, dst); \
1252     src += src_stride;                              \
1253     dst += dst_stride;                              \
1254   }                                                 \
1255 } while (0)
1256 
1257 // Remap argb values in src[] to packed palettes entries in dst[]
1258 // using 'row' as a temporary buffer of size 'width'.
1259 // We assume that all src[] values have a corresponding entry in the palette.
1260 // 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)1261 static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride,
1262                                       uint32_t* dst, uint32_t dst_stride,
1263                                       const uint32_t* palette, int palette_size,
1264                                       int width, int height, int xbits) {
1265   // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be
1266   // made to work in-place.
1267   uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
1268   int x, y;
1269 
1270   if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
1271 
1272   if (palette_size < APPLY_PALETTE_GREEDY_MAX) {
1273     APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix));
1274   } else {
1275     int i, j;
1276     uint16_t buffer[PALETTE_INV_SIZE];
1277     uint32_t (*const hash_functions[])(uint32_t) = {
1278         ApplyPaletteHash0, ApplyPaletteHash1, ApplyPaletteHash2
1279     };
1280 
1281     // Try to find a perfect hash function able to go from a color to an index
1282     // within 1 << PALETTE_INV_SIZE_BITS in order to build a hash map to go
1283     // from color to index in palette.
1284     for (i = 0; i < 3; ++i) {
1285       int use_LUT = 1;
1286       // Set each element in buffer to max uint16_t.
1287       memset(buffer, 0xff, sizeof(buffer));
1288       for (j = 0; j < palette_size; ++j) {
1289         const uint32_t ind = hash_functions[i](palette[j]);
1290         if (buffer[ind] != 0xffffu) {
1291           use_LUT = 0;
1292           break;
1293         } else {
1294           buffer[ind] = j;
1295         }
1296       }
1297       if (use_LUT) break;
1298     }
1299 
1300     if (i == 0) {
1301       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash0(pix)]);
1302     } else if (i == 1) {
1303       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash1(pix)]);
1304     } else if (i == 2) {
1305       APPLY_PALETTE_FOR(buffer[ApplyPaletteHash2(pix)]);
1306     } else {
1307       uint32_t idx_map[MAX_PALETTE_SIZE];
1308       uint32_t palette_sorted[MAX_PALETTE_SIZE];
1309       PrepareMapToPalette(palette, palette_size, palette_sorted, idx_map);
1310       APPLY_PALETTE_FOR(
1311           idx_map[SearchColorNoIdx(palette_sorted, pix, palette_size)]);
1312     }
1313   }
1314   WebPSafeFree(tmp_row);
1315   return VP8_ENC_OK;
1316 }
1317 #undef APPLY_PALETTE_FOR
1318 #undef PALETTE_INV_SIZE_BITS
1319 #undef PALETTE_INV_SIZE
1320 #undef APPLY_PALETTE_GREEDY_MAX
1321 
1322 // Note: Expects "enc->palette_" to be set properly.
MapImageFromPalette(VP8LEncoder * const enc,int in_place)1323 static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc,
1324                                              int in_place) {
1325   WebPEncodingError err = VP8_ENC_OK;
1326   const WebPPicture* const pic = enc->pic_;
1327   const int width = pic->width;
1328   const int height = pic->height;
1329   const uint32_t* const palette = enc->palette_;
1330   const uint32_t* src = in_place ? enc->argb_ : pic->argb;
1331   const int src_stride = in_place ? enc->current_width_ : pic->argb_stride;
1332   const int palette_size = enc->palette_size_;
1333   int xbits;
1334 
1335   // Replace each input pixel by corresponding palette index.
1336   // This is done line by line.
1337   if (palette_size <= 4) {
1338     xbits = (palette_size <= 2) ? 3 : 2;
1339   } else {
1340     xbits = (palette_size <= 16) ? 1 : 0;
1341   }
1342 
1343   err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
1344   if (err != VP8_ENC_OK) return err;
1345 
1346   err = ApplyPalette(src, src_stride,
1347                      enc->argb_, enc->current_width_,
1348                      palette, palette_size, width, height, xbits);
1349   return err;
1350 }
1351 
1352 // Save palette_[] to bitstream.
EncodePalette(VP8LBitWriter * const bw,int low_effort,VP8LEncoder * const enc)1353 static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort,
1354                                        VP8LEncoder* const enc) {
1355   int i;
1356   uint32_t tmp_palette[MAX_PALETTE_SIZE];
1357   const int palette_size = enc->palette_size_;
1358   const uint32_t* const palette = enc->palette_;
1359   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1360   VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2);
1361   assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE);
1362   VP8LPutBits(bw, palette_size - 1, 8);
1363   for (i = palette_size - 1; i >= 1; --i) {
1364     tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
1365   }
1366   tmp_palette[0] = palette[0];
1367   return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, enc->refs_,
1368                               palette_size, 1, 20 /* quality */, low_effort);
1369 }
1370 
1371 #ifdef WEBP_EXPERIMENTAL_FEATURES
1372 
EncodeDeltaPalettePredictorImage(VP8LBitWriter * const bw,VP8LEncoder * const enc,int quality,int low_effort)1373 static WebPEncodingError EncodeDeltaPalettePredictorImage(
1374     VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality,
1375     int low_effort) {
1376   const WebPPicture* const pic = enc->pic_;
1377   const int width = pic->width;
1378   const int height = pic->height;
1379 
1380   const int pred_bits = 5;
1381   const int transform_width = VP8LSubSampleSize(width, pred_bits);
1382   const int transform_height = VP8LSubSampleSize(height, pred_bits);
1383   const int pred = 7;   // default is Predictor7 (Top/Left Average)
1384   const int tiles_per_row = VP8LSubSampleSize(width, pred_bits);
1385   const int tiles_per_col = VP8LSubSampleSize(height, pred_bits);
1386   uint32_t* predictors;
1387   int tile_x, tile_y;
1388   WebPEncodingError err = VP8_ENC_OK;
1389 
1390   predictors = (uint32_t*)WebPSafeMalloc(tiles_per_col * tiles_per_row,
1391                                          sizeof(*predictors));
1392   if (predictors == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
1393 
1394   for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
1395     for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
1396       predictors[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
1397     }
1398   }
1399 
1400   VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1401   VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
1402   VP8LPutBits(bw, pred_bits - 2, 3);
1403   err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_,
1404                              (VP8LBackwardRefs*)enc->refs_,  // cast const away
1405                              transform_width, transform_height,
1406                              quality, low_effort);
1407   WebPSafeFree(predictors);
1408   return err;
1409 }
1410 
1411 #endif // WEBP_EXPERIMENTAL_FEATURES
1412 
1413 // -----------------------------------------------------------------------------
1414 // VP8LEncoder
1415 
VP8LEncoderNew(const WebPConfig * const config,const WebPPicture * const picture)1416 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
1417                                    const WebPPicture* const picture) {
1418   VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc));
1419   if (enc == NULL) {
1420     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1421     return NULL;
1422   }
1423   enc->config_ = config;
1424   enc->pic_ = picture;
1425 
1426   VP8LEncDspInit();
1427 
1428   return enc;
1429 }
1430 
VP8LEncoderDelete(VP8LEncoder * enc)1431 static void VP8LEncoderDelete(VP8LEncoder* enc) {
1432   if (enc != NULL) {
1433     VP8LHashChainClear(&enc->hash_chain_);
1434     VP8LBackwardRefsClear(&enc->refs_[0]);
1435     VP8LBackwardRefsClear(&enc->refs_[1]);
1436     ClearTransformBuffer(enc);
1437     WebPSafeFree(enc);
1438   }
1439 }
1440 
1441 // -----------------------------------------------------------------------------
1442 // Main call
1443 
VP8LEncodeStream(const WebPConfig * const config,const WebPPicture * const picture,VP8LBitWriter * const bw,int use_cache)1444 WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
1445                                    const WebPPicture* const picture,
1446                                    VP8LBitWriter* const bw, int use_cache) {
1447   WebPEncodingError err = VP8_ENC_OK;
1448   const int quality = (int)config->quality;
1449   const int low_effort = (config->method == 0);
1450   const int width = picture->width;
1451   const int height = picture->height;
1452   VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
1453   const size_t byte_position = VP8LBitWriterNumBytes(bw);
1454   int use_near_lossless = 0;
1455   int hdr_size = 0;
1456   int data_size = 0;
1457   int use_delta_palette = 0;
1458 
1459   if (enc == NULL) {
1460     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1461     goto Error;
1462   }
1463 
1464   // ---------------------------------------------------------------------------
1465   // Analyze image (entropy, num_palettes etc)
1466 
1467   if (!AnalyzeAndInit(enc)) {
1468     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1469     goto Error;
1470   }
1471 
1472   // Apply near-lossless preprocessing.
1473   use_near_lossless =
1474       (config->near_lossless < 100) && !enc->use_palette_ && !enc->use_predict_;
1475   if (use_near_lossless) {
1476     if (!VP8ApplyNearLossless(width, height, picture->argb,
1477                               config->near_lossless)) {
1478       err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1479       goto Error;
1480     }
1481   }
1482 
1483 #ifdef WEBP_EXPERIMENTAL_FEATURES
1484   if (config->use_delta_palette) {
1485     enc->use_predict_ = 1;
1486     enc->use_cross_color_ = 0;
1487     enc->use_subtract_green_ = 0;
1488     enc->use_palette_ = 1;
1489     err = MakeInputImageCopy(enc);
1490     if (err != VP8_ENC_OK) goto Error;
1491     err = WebPSearchOptimalDeltaPalette(enc);
1492     if (err != VP8_ENC_OK) goto Error;
1493     if (enc->use_palette_) {
1494       err = AllocateTransformBuffer(enc, width, height);
1495       if (err != VP8_ENC_OK) goto Error;
1496       err = EncodeDeltaPalettePredictorImage(bw, enc, quality, low_effort);
1497       if (err != VP8_ENC_OK) goto Error;
1498       use_delta_palette = 1;
1499     }
1500   }
1501 #endif  // WEBP_EXPERIMENTAL_FEATURES
1502 
1503   // Encode palette
1504   if (enc->use_palette_) {
1505     err = EncodePalette(bw, low_effort, enc);
1506     if (err != VP8_ENC_OK) goto Error;
1507     err = MapImageFromPalette(enc, use_delta_palette);
1508     if (err != VP8_ENC_OK) goto Error;
1509     // If using a color cache, do not have it bigger than the number of colors.
1510     if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
1511       enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1;
1512     }
1513   }
1514   if (!use_delta_palette) {
1515     // In case image is not packed.
1516     if (enc->argb_ == NULL) {
1517       err = MakeInputImageCopy(enc);
1518       if (err != VP8_ENC_OK) goto Error;
1519     }
1520 
1521     // -------------------------------------------------------------------------
1522     // Apply transforms and write transform data.
1523 
1524     if (enc->use_subtract_green_) {
1525       ApplySubtractGreen(enc, enc->current_width_, height, bw);
1526     }
1527 
1528     if (enc->use_predict_) {
1529       err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
1530                                low_effort, enc->use_subtract_green_, bw);
1531       if (err != VP8_ENC_OK) goto Error;
1532     }
1533 
1534     if (enc->use_cross_color_) {
1535       err = ApplyCrossColorFilter(enc, enc->current_width_,
1536                                   height, quality, low_effort, bw);
1537       if (err != VP8_ENC_OK) goto Error;
1538     }
1539   }
1540 
1541   VP8LPutBits(bw, !TRANSFORM_PRESENT, 1);  // No more transforms.
1542 
1543   // ---------------------------------------------------------------------------
1544   // Encode and write the transformed image.
1545   err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
1546                             enc->current_width_, height, quality, low_effort,
1547                             use_cache, &enc->cache_bits_, enc->histo_bits_,
1548                             byte_position, &hdr_size, &data_size);
1549   if (err != VP8_ENC_OK) goto Error;
1550 
1551   if (picture->stats != NULL) {
1552     WebPAuxStats* const stats = picture->stats;
1553     stats->lossless_features = 0;
1554     if (enc->use_predict_) stats->lossless_features |= 1;
1555     if (enc->use_cross_color_) stats->lossless_features |= 2;
1556     if (enc->use_subtract_green_) stats->lossless_features |= 4;
1557     if (enc->use_palette_) stats->lossless_features |= 8;
1558     stats->histogram_bits = enc->histo_bits_;
1559     stats->transform_bits = enc->transform_bits_;
1560     stats->cache_bits = enc->cache_bits_;
1561     stats->palette_size = enc->palette_size_;
1562     stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position);
1563     stats->lossless_hdr_size = hdr_size;
1564     stats->lossless_data_size = data_size;
1565   }
1566 
1567  Error:
1568   VP8LEncoderDelete(enc);
1569   return err;
1570 }
1571 
VP8LEncodeImage(const WebPConfig * const config,const WebPPicture * const picture)1572 int VP8LEncodeImage(const WebPConfig* const config,
1573                     const WebPPicture* const picture) {
1574   int width, height;
1575   int has_alpha;
1576   size_t coded_size;
1577   int percent = 0;
1578   int initial_size;
1579   WebPEncodingError err = VP8_ENC_OK;
1580   VP8LBitWriter bw;
1581 
1582   if (picture == NULL) return 0;
1583 
1584   if (config == NULL || picture->argb == NULL) {
1585     err = VP8_ENC_ERROR_NULL_PARAMETER;
1586     WebPEncodingSetError(picture, err);
1587     return 0;
1588   }
1589 
1590   width = picture->width;
1591   height = picture->height;
1592   // Initialize BitWriter with size corresponding to 16 bpp to photo images and
1593   // 8 bpp for graphical images.
1594   initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
1595       width * height : width * height * 2;
1596   if (!VP8LBitWriterInit(&bw, initial_size)) {
1597     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1598     goto Error;
1599   }
1600 
1601   if (!WebPReportProgress(picture, 1, &percent)) {
1602  UserAbort:
1603     err = VP8_ENC_ERROR_USER_ABORT;
1604     goto Error;
1605   }
1606   // Reset stats (for pure lossless coding)
1607   if (picture->stats != NULL) {
1608     WebPAuxStats* const stats = picture->stats;
1609     memset(stats, 0, sizeof(*stats));
1610     stats->PSNR[0] = 99.f;
1611     stats->PSNR[1] = 99.f;
1612     stats->PSNR[2] = 99.f;
1613     stats->PSNR[3] = 99.f;
1614     stats->PSNR[4] = 99.f;
1615   }
1616 
1617   // Write image size.
1618   if (!WriteImageSize(picture, &bw)) {
1619     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1620     goto Error;
1621   }
1622 
1623   has_alpha = WebPPictureHasTransparency(picture);
1624   // Write the non-trivial Alpha flag and lossless version.
1625   if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
1626     err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1627     goto Error;
1628   }
1629 
1630   if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort;
1631 
1632   // Encode main image stream.
1633   err = VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/);
1634   if (err != VP8_ENC_OK) goto Error;
1635 
1636   // TODO(skal): have a fine-grained progress report in VP8LEncodeStream().
1637   if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort;
1638 
1639   // Finish the RIFF chunk.
1640   err = WriteImage(picture, &bw, &coded_size);
1641   if (err != VP8_ENC_OK) goto Error;
1642 
1643   if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
1644 
1645   // Save size.
1646   if (picture->stats != NULL) {
1647     picture->stats->coded_size += (int)coded_size;
1648     picture->stats->lossless_size = (int)coded_size;
1649   }
1650 
1651   if (picture->extra_info != NULL) {
1652     const int mb_w = (width + 15) >> 4;
1653     const int mb_h = (height + 15) >> 4;
1654     memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
1655   }
1656 
1657  Error:
1658   if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1659   VP8LBitWriterWipeOut(&bw);
1660   if (err != VP8_ENC_OK) {
1661     WebPEncodingSetError(picture, err);
1662     return 0;
1663   }
1664   return 1;
1665 }
1666 
1667 //------------------------------------------------------------------------------
1668