1 // Copyright 2012 Google Inc. All Rights Reserved.
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 // -----------------------------------------------------------------------------
10 // main entry for the lossless encoder.
12 // Author: Vikas Arora (vikaas.arora@gmail.com)
19 #include "./backward_references.h"
20 #include "./vp8enci.h"
22 #include "../dsp/lossless.h"
23 #include "../utils/bit_writer.h"
24 #include "../utils/huffman_encode.h"
25 #include "../utils/utils.h"
26 #include "../webp/format_constants.h"
28 #if defined(__cplusplus) || defined(c_plusplus)
32 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
33 #define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024)
34 #define MAX_COLORS_FOR_GRAPH 64
36 // -----------------------------------------------------------------------------
39 static int CompareColors(const void* p1, const void* p2) {
40 const uint32_t a = *(const uint32_t*)p1;
41 const uint32_t b = *(const uint32_t*)p2;
43 return (a < b) ? -1 : 1;
46 // If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
47 // creates a palette and returns true, else returns false.
48 static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
49 uint32_t palette[MAX_PALETTE_SIZE],
50 int* const palette_size) {
53 uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
54 uint32_t colors[MAX_PALETTE_SIZE * 4];
55 static const uint32_t kHashMul = 0x1e35a7bd;
56 const uint32_t* argb = pic->argb;
57 const int width = pic->width;
58 const int height = pic->height;
59 uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
61 for (y = 0; y < height; ++y) {
62 for (x = 0; x < width; ++x) {
63 if (argb[x] == last_pix) {
67 key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT;
70 colors[key] = last_pix;
73 if (num_colors > MAX_PALETTE_SIZE) {
77 } else if (colors[key] == last_pix) {
78 // The color is already there.
81 // Some other color sits there.
82 // Do linear conflict resolution.
84 key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer.
88 argb += pic->argb_stride;
91 // TODO(skal): could we reuse in_use[] to speed up EncodePalette()?
93 for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
95 palette[num_colors] = colors[i];
100 qsort(palette, num_colors, sizeof(*palette), CompareColors);
101 *palette_size = num_colors;
105 static int AnalyzeEntropy(const uint32_t* argb,
106 int width, int height, int argb_stride,
107 double* const nonpredicted_bits,
108 double* const predicted_bits) {
110 const uint32_t* last_line = NULL;
111 uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0
113 VP8LHistogram* nonpredicted = NULL;
114 VP8LHistogram* predicted =
115 (VP8LHistogram*)malloc(2 * sizeof(*predicted));
116 if (predicted == NULL) return 0;
117 nonpredicted = predicted + 1;
119 VP8LHistogramInit(predicted, 0);
120 VP8LHistogramInit(nonpredicted, 0);
121 for (y = 0; y < height; ++y) {
122 for (x = 0; x < width; ++x) {
123 const uint32_t pix = argb[x];
124 const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
125 if (pix_diff == 0) continue;
126 if (last_line != NULL && pix == last_line[x]) {
131 const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
132 const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
133 VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token);
134 VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token);
140 *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
141 *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
146 static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) {
147 const WebPPicture* const pic = enc->pic_;
148 assert(pic != NULL && pic->argb != NULL);
151 AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_);
153 if (image_hint == WEBP_HINT_GRAPH) {
154 if (enc->use_palette_ && enc->palette_size_ < MAX_COLORS_FOR_GRAPH) {
155 enc->use_palette_ = 0;
159 if (!enc->use_palette_) {
160 if (image_hint == WEBP_HINT_PHOTO) {
161 enc->use_predict_ = 1;
162 enc->use_cross_color_ = 1;
164 double non_pred_entropy, pred_entropy;
165 if (!AnalyzeEntropy(pic->argb, pic->width, pic->height, pic->argb_stride,
166 &non_pred_entropy, &pred_entropy)) {
169 if (pred_entropy < 0.95 * non_pred_entropy) {
170 enc->use_predict_ = 1;
171 // TODO(vikasa): Observed some correlation of cross_color transform with
172 // predict. Need to investigate this further and add separate heuristic
173 // for setting use_cross_color flag.
174 enc->use_cross_color_ = 1;
182 static int GetHuffBitLengthsAndCodes(
183 const VP8LHistogramSet* const histogram_image,
184 HuffmanTreeCode* const huffman_codes) {
187 uint64_t total_length_size = 0;
188 uint8_t* mem_buf = NULL;
189 const int histogram_image_size = histogram_image->size;
191 // Iterate over all histograms and get the aggregate number of codes used.
192 for (i = 0; i < histogram_image_size; ++i) {
193 const VP8LHistogram* const histo = histogram_image->histograms[i];
194 HuffmanTreeCode* const codes = &huffman_codes[5 * i];
195 for (k = 0; k < 5; ++k) {
196 const int num_symbols = (k == 0) ? VP8LHistogramNumCodes(histo)
197 : (k == 4) ? NUM_DISTANCE_CODES
199 codes[k].num_symbols = num_symbols;
200 total_length_size += num_symbols;
204 // Allocate and Set Huffman codes.
208 mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size,
209 sizeof(*lengths) + sizeof(*codes));
210 if (mem_buf == NULL) {
214 codes = (uint16_t*)mem_buf;
215 lengths = (uint8_t*)&codes[total_length_size];
216 for (i = 0; i < 5 * histogram_image_size; ++i) {
217 const int bit_length = huffman_codes[i].num_symbols;
218 huffman_codes[i].codes = codes;
219 huffman_codes[i].code_lengths = lengths;
221 lengths += bit_length;
225 // Create Huffman trees.
226 for (i = 0; ok && (i < histogram_image_size); ++i) {
227 HuffmanTreeCode* const codes = &huffman_codes[5 * i];
228 VP8LHistogram* const histo = histogram_image->histograms[i];
229 ok = ok && VP8LCreateHuffmanTree(histo->literal_, 15, codes + 0);
230 ok = ok && VP8LCreateHuffmanTree(histo->red_, 15, codes + 1);
231 ok = ok && VP8LCreateHuffmanTree(histo->blue_, 15, codes + 2);
232 ok = ok && VP8LCreateHuffmanTree(histo->alpha_, 15, codes + 3);
233 ok = ok && VP8LCreateHuffmanTree(histo->distance_, 15, codes + 4);
239 // If one VP8LCreateHuffmanTree() above fails, we need to clean up behind.
240 memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
245 static void StoreHuffmanTreeOfHuffmanTreeToBitMask(
246 VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) {
247 // RFC 1951 will calm you down if you are worried about this funny sequence.
248 // This sequence is tuned from that, but more weighted for lower symbol count,
249 // and more spiking histograms.
250 static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = {
251 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
254 // Throw away trailing zeros:
255 int codes_to_store = CODE_LENGTH_CODES;
256 for (; codes_to_store > 4; --codes_to_store) {
257 if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
261 VP8LWriteBits(bw, 4, codes_to_store - 4);
262 for (i = 0; i < codes_to_store; ++i) {
263 VP8LWriteBits(bw, 3, code_length_bitdepth[kStorageOrder[i]]);
267 static void ClearHuffmanTreeIfOnlyOneSymbol(
268 HuffmanTreeCode* const huffman_code) {
271 for (k = 0; k < huffman_code->num_symbols; ++k) {
272 if (huffman_code->code_lengths[k] != 0) {
274 if (count > 1) return;
277 for (k = 0; k < huffman_code->num_symbols; ++k) {
278 huffman_code->code_lengths[k] = 0;
279 huffman_code->codes[k] = 0;
283 static void StoreHuffmanTreeToBitMask(
284 VP8LBitWriter* const bw,
285 const HuffmanTreeToken* const tokens, const int num_tokens,
286 const HuffmanTreeCode* const huffman_code) {
288 for (i = 0; i < num_tokens; ++i) {
289 const int ix = tokens[i].code;
290 const int extra_bits = tokens[i].extra_bits;
291 VP8LWriteBits(bw, huffman_code->code_lengths[ix], huffman_code->codes[ix]);
294 VP8LWriteBits(bw, 2, extra_bits);
297 VP8LWriteBits(bw, 3, extra_bits);
300 VP8LWriteBits(bw, 7, extra_bits);
306 static int StoreFullHuffmanCode(VP8LBitWriter* const bw,
307 const HuffmanTreeCode* const tree) {
309 uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
310 uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
311 const int max_tokens = tree->num_symbols;
313 HuffmanTreeCode huffman_code;
314 HuffmanTreeToken* const tokens =
315 (HuffmanTreeToken*)WebPSafeMalloc((uint64_t)max_tokens, sizeof(*tokens));
316 if (tokens == NULL) return 0;
318 huffman_code.num_symbols = CODE_LENGTH_CODES;
319 huffman_code.code_lengths = code_length_bitdepth;
320 huffman_code.codes = code_length_bitdepth_symbols;
322 VP8LWriteBits(bw, 1, 0);
323 num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens);
325 int histogram[CODE_LENGTH_CODES] = { 0 };
327 for (i = 0; i < num_tokens; ++i) {
328 ++histogram[tokens[i].code];
331 if (!VP8LCreateHuffmanTree(histogram, 7, &huffman_code)) {
336 StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
337 ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code);
339 int trailing_zero_bits = 0;
340 int trimmed_length = num_tokens;
341 int write_trimmed_length;
345 const int ix = tokens[i].code;
346 if (ix == 0 || ix == 17 || ix == 18) {
347 --trimmed_length; // discount trailing zeros
348 trailing_zero_bits += code_length_bitdepth[ix];
350 trailing_zero_bits += 3;
351 } else if (ix == 18) {
352 trailing_zero_bits += 7;
358 write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
359 length = write_trimmed_length ? trimmed_length : num_tokens;
360 VP8LWriteBits(bw, 1, write_trimmed_length);
361 if (write_trimmed_length) {
362 const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
363 const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
364 VP8LWriteBits(bw, 3, nbitpairs - 1);
365 assert(trimmed_length >= 2);
366 VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2);
368 StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
376 static int StoreHuffmanCode(VP8LBitWriter* const bw,
377 const HuffmanTreeCode* const huffman_code) {
380 int symbols[2] = { 0, 0 };
381 const int kMaxBits = 8;
382 const int kMaxSymbol = 1 << kMaxBits;
384 // Check whether it's a small tree.
385 for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) {
386 if (huffman_code->code_lengths[i] != 0) {
387 if (count < 2) symbols[count] = i;
392 if (count == 0) { // emit minimal tree for empty cases
393 // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
394 VP8LWriteBits(bw, 4, 0x01);
396 } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
397 VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols.
398 VP8LWriteBits(bw, 1, count - 1);
399 if (symbols[0] <= 1) {
400 VP8LWriteBits(bw, 1, 0); // Code bit for small (1 bit) symbol value.
401 VP8LWriteBits(bw, 1, symbols[0]);
403 VP8LWriteBits(bw, 1, 1);
404 VP8LWriteBits(bw, 8, symbols[0]);
407 VP8LWriteBits(bw, 8, symbols[1]);
411 return StoreFullHuffmanCode(bw, huffman_code);
415 static void WriteHuffmanCode(VP8LBitWriter* const bw,
416 const HuffmanTreeCode* const code,
418 const int depth = code->code_lengths[code_index];
419 const int symbol = code->codes[code_index];
420 VP8LWriteBits(bw, depth, symbol);
423 static void StoreImageToBitMask(
424 VP8LBitWriter* const bw, int width, int histo_bits,
425 const VP8LBackwardRefs* const refs,
426 const uint16_t* histogram_symbols,
427 const HuffmanTreeCode* const huffman_codes) {
428 // x and y trace the position in the image.
431 const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
433 for (i = 0; i < refs->size; ++i) {
434 const PixOrCopy* const v = &refs->refs[i];
435 const int histogram_ix = histogram_symbols[histo_bits ?
436 (y >> histo_bits) * histo_xsize +
437 (x >> histo_bits) : 0];
438 const HuffmanTreeCode* const codes = huffman_codes + 5 * histogram_ix;
439 if (PixOrCopyIsCacheIdx(v)) {
440 const int code = PixOrCopyCacheIdx(v);
441 const int literal_ix = 256 + NUM_LENGTH_CODES + code;
442 WriteHuffmanCode(bw, codes, literal_ix);
443 } else if (PixOrCopyIsLiteral(v)) {
444 static const int order[] = { 1, 2, 0, 3 };
446 for (k = 0; k < 4; ++k) {
447 const int code = PixOrCopyLiteral(v, order[k]);
448 WriteHuffmanCode(bw, codes + k, code);
454 PrefixEncode(v->len, &code, &n_bits, &bits);
455 WriteHuffmanCode(bw, codes, 256 + code);
456 VP8LWriteBits(bw, n_bits, bits);
458 distance = PixOrCopyDistance(v);
459 PrefixEncode(distance, &code, &n_bits, &bits);
460 WriteHuffmanCode(bw, codes + 4, code);
461 VP8LWriteBits(bw, n_bits, bits);
463 x += PixOrCopyLength(v);
471 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
472 static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
473 const uint32_t* const argb,
474 int width, int height, int quality) {
477 VP8LBackwardRefs refs;
478 HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
479 const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol
480 VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0);
481 if (histogram_image == NULL) return 0;
483 // Calculate backward references from ARGB image.
484 if (!VP8LGetBackwardReferences(width, height, argb, quality, 0, 1, &refs)) {
487 // Build histogram image and symbols from backward references.
488 VP8LHistogramStoreRefs(&refs, histogram_image->histograms[0]);
490 // Create Huffman bit lengths and codes for each histogram image.
491 assert(histogram_image->size == 1);
492 if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
496 // No color cache, no Huffman image.
497 VP8LWriteBits(bw, 1, 0);
499 // Store Huffman codes.
500 for (i = 0; i < 5; ++i) {
501 HuffmanTreeCode* const codes = &huffman_codes[i];
502 if (!StoreHuffmanCode(bw, codes)) {
505 ClearHuffmanTreeIfOnlyOneSymbol(codes);
508 // Store actual literals.
509 StoreImageToBitMask(bw, width, 0, &refs, histogram_symbols, huffman_codes);
513 free(histogram_image);
514 VP8LClearBackwardRefs(&refs);
515 free(huffman_codes[0].codes);
519 static int EncodeImageInternal(VP8LBitWriter* const bw,
520 const uint32_t* const argb,
521 int width, int height, int quality,
522 int cache_bits, int histogram_bits) {
524 const int use_2d_locality = 1;
525 const int use_color_cache = (cache_bits > 0);
526 const uint32_t histogram_image_xysize =
527 VP8LSubSampleSize(width, histogram_bits) *
528 VP8LSubSampleSize(height, histogram_bits);
529 VP8LHistogramSet* histogram_image =
530 VP8LAllocateHistogramSet(histogram_image_xysize, 0);
531 int histogram_image_size = 0;
532 size_t bit_array_size = 0;
533 HuffmanTreeCode* huffman_codes = NULL;
534 VP8LBackwardRefs refs;
535 uint16_t* const histogram_symbols =
536 (uint16_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
537 sizeof(*histogram_symbols));
538 assert(histogram_bits >= MIN_HUFFMAN_BITS);
539 assert(histogram_bits <= MAX_HUFFMAN_BITS);
541 if (histogram_image == NULL || histogram_symbols == NULL) {
542 free(histogram_image);
543 free(histogram_symbols);
547 // Calculate backward references from ARGB image.
548 if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits,
549 use_2d_locality, &refs)) {
552 // Build histogram image and symbols from backward references.
553 if (!VP8LGetHistoImageSymbols(width, height, &refs,
554 quality, histogram_bits, cache_bits,
556 histogram_symbols)) {
559 // Create Huffman bit lengths and codes for each histogram image.
560 histogram_image_size = histogram_image->size;
561 bit_array_size = 5 * histogram_image_size;
562 huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
563 sizeof(*huffman_codes));
564 if (huffman_codes == NULL ||
565 !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
568 // Free combined histograms.
569 free(histogram_image);
570 histogram_image = NULL;
572 // Color Cache parameters.
573 VP8LWriteBits(bw, 1, use_color_cache);
574 if (use_color_cache) {
575 VP8LWriteBits(bw, 4, cache_bits);
578 // Huffman image + meta huffman.
580 const int write_histogram_image = (histogram_image_size > 1);
581 VP8LWriteBits(bw, 1, write_histogram_image);
582 if (write_histogram_image) {
583 uint32_t* const histogram_argb =
584 (uint32_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
585 sizeof(*histogram_argb));
588 if (histogram_argb == NULL) goto Error;
589 for (i = 0; i < histogram_image_xysize; ++i) {
590 const int symbol_index = histogram_symbols[i] & 0xffff;
591 histogram_argb[i] = 0xff000000 | (symbol_index << 8);
592 if (symbol_index >= max_index) {
593 max_index = symbol_index + 1;
596 histogram_image_size = max_index;
598 VP8LWriteBits(bw, 3, histogram_bits - 2);
599 ok = EncodeImageNoHuffman(bw, histogram_argb,
600 VP8LSubSampleSize(width, histogram_bits),
601 VP8LSubSampleSize(height, histogram_bits),
603 free(histogram_argb);
608 // Store Huffman codes.
611 for (i = 0; i < 5 * histogram_image_size; ++i) {
612 HuffmanTreeCode* const codes = &huffman_codes[i];
613 if (!StoreHuffmanCode(bw, codes)) goto Error;
614 ClearHuffmanTreeIfOnlyOneSymbol(codes);
618 // Store actual literals.
619 StoreImageToBitMask(bw, width, histogram_bits, &refs,
620 histogram_symbols, huffman_codes);
624 free(histogram_image);
626 VP8LClearBackwardRefs(&refs);
627 if (huffman_codes != NULL) {
628 free(huffman_codes->codes);
631 free(histogram_symbols);
635 // -----------------------------------------------------------------------------
638 // Check if it would be a good idea to subtract green from red and blue. We
639 // only impact entropy in red/blue components, don't bother to look at others.
640 static int EvalAndApplySubtractGreen(VP8LEncoder* const enc,
641 int width, int height,
642 VP8LBitWriter* const bw) {
643 if (!enc->use_palette_) {
645 const uint32_t* const argb = enc->argb_;
646 double bit_cost_before, bit_cost_after;
647 VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
648 if (histo == NULL) return 0;
650 VP8LHistogramInit(histo, 1);
651 for (i = 0; i < width * height; ++i) {
652 const uint32_t c = argb[i];
653 ++histo->red_[(c >> 16) & 0xff];
654 ++histo->blue_[(c >> 0) & 0xff];
656 bit_cost_before = VP8LHistogramEstimateBits(histo);
658 VP8LHistogramInit(histo, 1);
659 for (i = 0; i < width * height; ++i) {
660 const uint32_t c = argb[i];
661 const int green = (c >> 8) & 0xff;
662 ++histo->red_[((c >> 16) - green) & 0xff];
663 ++histo->blue_[((c >> 0) - green) & 0xff];
665 bit_cost_after = VP8LHistogramEstimateBits(histo);
668 // Check if subtracting green yields low entropy.
669 enc->use_subtract_green_ = (bit_cost_after < bit_cost_before);
670 if (enc->use_subtract_green_) {
671 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
672 VP8LWriteBits(bw, 2, SUBTRACT_GREEN);
673 VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
679 static int ApplyPredictFilter(const VP8LEncoder* const enc,
680 int width, int height, int quality,
681 VP8LBitWriter* const bw) {
682 const int pred_bits = enc->transform_bits_;
683 const int transform_width = VP8LSubSampleSize(width, pred_bits);
684 const int transform_height = VP8LSubSampleSize(height, pred_bits);
686 VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->argb_scratch_,
687 enc->transform_data_);
688 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
689 VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
690 assert(pred_bits >= 2);
691 VP8LWriteBits(bw, 3, pred_bits - 2);
692 if (!EncodeImageNoHuffman(bw, enc->transform_data_,
693 transform_width, transform_height, quality)) {
699 static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
700 int width, int height, int quality,
701 VP8LBitWriter* const bw) {
702 const int ccolor_transform_bits = enc->transform_bits_;
703 const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
704 const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
705 const int step = (quality == 0) ? 32 : 8;
707 VP8LColorSpaceTransform(width, height, ccolor_transform_bits, step,
708 enc->argb_, enc->transform_data_);
709 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
710 VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
711 assert(ccolor_transform_bits >= 2);
712 VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
713 if (!EncodeImageNoHuffman(bw, enc->transform_data_,
714 transform_width, transform_height, quality)) {
720 // -----------------------------------------------------------------------------
722 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
723 size_t riff_size, size_t vp8l_size) {
724 uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
725 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
726 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
728 PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
729 PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
730 if (!pic->writer(riff, sizeof(riff), pic)) {
731 return VP8_ENC_ERROR_BAD_WRITE;
736 static int WriteImageSize(const WebPPicture* const pic,
737 VP8LBitWriter* const bw) {
738 const int width = pic->width - 1;
739 const int height = pic->height - 1;
740 assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
742 VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, width);
743 VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, height);
747 static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
748 VP8LWriteBits(bw, 1, has_alpha);
749 VP8LWriteBits(bw, VP8L_VERSION_BITS, VP8L_VERSION);
753 static WebPEncodingError WriteImage(const WebPPicture* const pic,
754 VP8LBitWriter* const bw,
755 size_t* const coded_size) {
756 WebPEncodingError err = VP8_ENC_OK;
757 const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
758 const size_t webpll_size = VP8LBitWriterNumBytes(bw);
759 const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
760 const size_t pad = vp8l_size & 1;
761 const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
763 err = WriteRiffHeader(pic, riff_size, vp8l_size);
764 if (err != VP8_ENC_OK) goto Error;
766 if (!pic->writer(webpll_data, webpll_size, pic)) {
767 err = VP8_ENC_ERROR_BAD_WRITE;
772 const uint8_t pad_byte[1] = { 0 };
773 if (!pic->writer(pad_byte, 1, pic)) {
774 err = VP8_ENC_ERROR_BAD_WRITE;
778 *coded_size = CHUNK_HEADER_SIZE + riff_size;
785 // -----------------------------------------------------------------------------
787 // Allocates the memory for argb (W x H) buffer, 2 rows of context for
788 // prediction and transform data.
789 static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
790 int width, int height) {
791 WebPEncodingError err = VP8_ENC_OK;
792 const int tile_size = 1 << enc->transform_bits_;
793 const uint64_t image_size = width * height;
794 const uint64_t argb_scratch_size = tile_size * width + width;
795 const uint64_t transform_data_size =
796 (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) *
797 (uint64_t)VP8LSubSampleSize(height, enc->transform_bits_);
798 const uint64_t total_size =
799 image_size + argb_scratch_size + transform_data_size;
800 uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem));
802 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
807 enc->argb_scratch_ = mem;
808 mem += argb_scratch_size;
809 enc->transform_data_ = mem;
810 enc->current_width_ = width;
816 static void ApplyPalette(uint32_t* src, uint32_t* dst,
817 uint32_t src_stride, uint32_t dst_stride,
818 const uint32_t* palette, int palette_size,
819 int width, int height, int xbits, uint8_t* row) {
822 for (i = 0; i < palette_size; ++i) {
823 if ((palette[i] & 0xffff00ffu) != 0) {
830 int inv_palette[MAX_PALETTE_SIZE] = { 0 };
831 for (i = 0; i < palette_size; ++i) {
832 const int color = (palette[i] >> 8) & 0xff;
833 inv_palette[color] = i;
835 for (y = 0; y < height; ++y) {
836 for (x = 0; x < width; ++x) {
837 const int color = (src[x] >> 8) & 0xff;
838 row[x] = inv_palette[color];
840 VP8LBundleColorMap(row, width, xbits, dst);
845 // Use 1 pixel cache for ARGB pixels.
846 uint32_t last_pix = palette[0];
848 for (y = 0; y < height; ++y) {
849 for (x = 0; x < width; ++x) {
850 const uint32_t pix = src[x];
851 if (pix != last_pix) {
852 for (i = 0; i < palette_size; ++i) {
853 if (pix == palette[i]) {
862 VP8LBundleColorMap(row, width, xbits, dst);
869 // Note: Expects "enc->palette_" to be set properly.
870 // Also, "enc->palette_" will be modified after this call and should not be used
872 static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
873 VP8LEncoder* const enc, int quality) {
874 WebPEncodingError err = VP8_ENC_OK;
876 const WebPPicture* const pic = enc->pic_;
877 uint32_t* src = pic->argb;
879 const int width = pic->width;
880 const int height = pic->height;
881 uint32_t* const palette = enc->palette_;
882 const int palette_size = enc->palette_size_;
886 // Replace each input pixel by corresponding palette index.
887 // This is done line by line.
888 if (palette_size <= 4) {
889 xbits = (palette_size <= 2) ? 3 : 2;
891 xbits = (palette_size <= 16) ? 1 : 0;
894 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
895 if (err != VP8_ENC_OK) goto Error;
898 row = WebPSafeMalloc((uint64_t)width, sizeof(*row));
899 if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
901 ApplyPalette(src, dst, pic->argb_stride, enc->current_width_,
902 palette, palette_size, width, height, xbits, row);
904 // Save palette to bitstream.
905 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
906 VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM);
907 assert(palette_size >= 1);
908 VP8LWriteBits(bw, 8, palette_size - 1);
909 for (i = palette_size - 1; i >= 1; --i) {
910 palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
912 if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) {
913 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
922 // -----------------------------------------------------------------------------
924 static int GetHistoBits(int method, int use_palette, int width, int height) {
925 const uint64_t hist_size = sizeof(VP8LHistogram);
926 // Make tile size a function of encoding method (Range: 0 to 6).
927 int histo_bits = (use_palette ? 9 : 7) - method;
929 const uint64_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
930 VP8LSubSampleSize(height, histo_bits) *
932 if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
935 return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
936 (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
939 static void FinishEncParams(VP8LEncoder* const enc) {
940 const WebPConfig* const config = enc->config_;
941 const WebPPicture* const pic = enc->pic_;
942 const int method = config->method;
943 const float quality = config->quality;
944 const int use_palette = enc->use_palette_;
945 enc->transform_bits_ = (method < 4) ? 5 : (method > 4) ? 3 : 4;
946 enc->histo_bits_ = GetHistoBits(method, use_palette, pic->width, pic->height);
947 enc->cache_bits_ = (quality <= 25.f) ? 0 : 7;
950 // -----------------------------------------------------------------------------
953 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
954 const WebPPicture* const picture) {
955 VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc));
957 WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
960 enc->config_ = config;
965 static void VP8LEncoderDelete(VP8LEncoder* enc) {
970 // -----------------------------------------------------------------------------
973 WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
974 const WebPPicture* const picture,
975 VP8LBitWriter* const bw) {
976 WebPEncodingError err = VP8_ENC_OK;
977 const int quality = (int)config->quality;
978 const int width = picture->width;
979 const int height = picture->height;
980 VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
981 const size_t byte_position = VP8LBitWriterNumBytes(bw);
984 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
988 // ---------------------------------------------------------------------------
989 // Analyze image (entropy, num_palettes etc)
991 if (!VP8LEncAnalyze(enc, config->image_hint)) {
992 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
996 FinishEncParams(enc);
998 if (enc->use_palette_) {
999 err = EncodePalette(bw, enc, quality);
1000 if (err != VP8_ENC_OK) goto Error;
1001 // Color cache is disabled for palette.
1002 enc->cache_bits_ = 0;
1005 // In case image is not packed.
1006 if (enc->argb_ == NULL) {
1008 err = AllocateTransformBuffer(enc, width, height);
1009 if (err != VP8_ENC_OK) goto Error;
1010 for (y = 0; y < height; ++y) {
1011 memcpy(enc->argb_ + y * width,
1012 picture->argb + y * picture->argb_stride,
1013 width * sizeof(*enc->argb_));
1015 enc->current_width_ = width;
1018 // ---------------------------------------------------------------------------
1019 // Apply transforms and write transform data.
1021 if (!EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw)) {
1022 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1026 if (enc->use_predict_) {
1027 if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, bw)) {
1028 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
1033 if (enc->use_cross_color_) {
1034 if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw)) {
1035 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
1040 VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms.
1042 // ---------------------------------------------------------------------------
1043 // Estimate the color cache size.
1045 if (enc->cache_bits_ > 0) {
1046 if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_,
1047 height, &enc->cache_bits_)) {
1048 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
1053 // ---------------------------------------------------------------------------
1054 // Encode and write the transformed image.
1056 if (!EncodeImageInternal(bw, enc->argb_, enc->current_width_, height,
1057 quality, enc->cache_bits_, enc->histo_bits_)) {
1058 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1062 if (picture->stats != NULL) {
1063 WebPAuxStats* const stats = picture->stats;
1064 stats->lossless_features = 0;
1065 if (enc->use_predict_) stats->lossless_features |= 1;
1066 if (enc->use_cross_color_) stats->lossless_features |= 2;
1067 if (enc->use_subtract_green_) stats->lossless_features |= 4;
1068 if (enc->use_palette_) stats->lossless_features |= 8;
1069 stats->histogram_bits = enc->histo_bits_;
1070 stats->transform_bits = enc->transform_bits_;
1071 stats->cache_bits = enc->cache_bits_;
1072 stats->palette_size = enc->palette_size_;
1073 stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position);
1077 VP8LEncoderDelete(enc);
1081 int VP8LEncodeImage(const WebPConfig* const config,
1082 const WebPPicture* const picture) {
1087 WebPEncodingError err = VP8_ENC_OK;
1090 if (picture == NULL) return 0;
1092 if (config == NULL || picture->argb == NULL) {
1093 err = VP8_ENC_ERROR_NULL_PARAMETER;
1094 WebPEncodingSetError(picture, err);
1098 width = picture->width;
1099 height = picture->height;
1100 if (!VP8LBitWriterInit(&bw, (width * height) >> 1)) {
1101 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1105 if (!WebPReportProgress(picture, 1, &percent)) {
1107 err = VP8_ENC_ERROR_USER_ABORT;
1110 // Reset stats (for pure lossless coding)
1111 if (picture->stats != NULL) {
1112 WebPAuxStats* const stats = picture->stats;
1113 memset(stats, 0, sizeof(*stats));
1114 stats->PSNR[0] = 99.f;
1115 stats->PSNR[1] = 99.f;
1116 stats->PSNR[2] = 99.f;
1117 stats->PSNR[3] = 99.f;
1118 stats->PSNR[4] = 99.f;
1121 // Write image size.
1122 if (!WriteImageSize(picture, &bw)) {
1123 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1127 has_alpha = WebPPictureHasTransparency(picture);
1128 // Write the non-trivial Alpha flag and lossless version.
1129 if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
1130 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1134 if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort;
1136 // Encode main image stream.
1137 err = VP8LEncodeStream(config, picture, &bw);
1138 if (err != VP8_ENC_OK) goto Error;
1140 // TODO(skal): have a fine-grained progress report in VP8LEncodeStream().
1141 if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort;
1143 // Finish the RIFF chunk.
1144 err = WriteImage(picture, &bw, &coded_size);
1145 if (err != VP8_ENC_OK) goto Error;
1147 if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
1150 if (picture->stats != NULL) {
1151 picture->stats->coded_size += (int)coded_size;
1152 picture->stats->lossless_size = (int)coded_size;
1155 if (picture->extra_info != NULL) {
1156 const int mb_w = (width + 15) >> 4;
1157 const int mb_h = (height + 15) >> 4;
1158 memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
1162 if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1163 VP8LBitWriterDestroy(&bw);
1164 if (err != VP8_ENC_OK) {
1165 WebPEncodingSetError(picture, err);
1171 //------------------------------------------------------------------------------
1173 #if defined(__cplusplus) || defined(c_plusplus)