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