Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(241)

Side by Side Diff: third_party/libwebp/enc/vp8l.c

Issue 12942006: libwebp: update snapshot to v0.3.0-rc6 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/libwebp/enc/vp8enci.h ('k') | third_party/libwebp/enc/webpenc.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 Google Inc. All Rights Reserved.
2 // 2 //
3 // This code is licensed under the same terms as WebM: 3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/ 4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // ----------------------------------------------------------------------------- 6 // -----------------------------------------------------------------------------
7 // 7 //
8 // main entry for the lossless encoder. 8 // main entry for the lossless encoder.
9 // 9 //
10 // Author: Vikas Arora (vikaas.arora@gmail.com) 10 // Author: Vikas Arora (vikaas.arora@gmail.com)
(...skipping 11 matching lines...) Expand all
22 #include "../utils/huffman_encode.h" 22 #include "../utils/huffman_encode.h"
23 #include "../utils/utils.h" 23 #include "../utils/utils.h"
24 #include "../webp/format_constants.h" 24 #include "../webp/format_constants.h"
25 25
26 #if defined(__cplusplus) || defined(c_plusplus) 26 #if defined(__cplusplus) || defined(c_plusplus)
27 extern "C" { 27 extern "C" {
28 #endif 28 #endif
29 29
30 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. 30 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
31 #define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024) 31 #define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024)
32 #define MAX_COLORS_FOR_GRAPH 64
32 33
33 // ----------------------------------------------------------------------------- 34 // -----------------------------------------------------------------------------
34 // Palette 35 // Palette
35 36
36 static int CompareColors(const void* p1, const void* p2) { 37 static int CompareColors(const void* p1, const void* p2) {
37 const uint32_t a = *(const uint32_t*)p1; 38 const uint32_t a = *(const uint32_t*)p1;
38 const uint32_t b = *(const uint32_t*)p2; 39 const uint32_t b = *(const uint32_t*)p2;
39 return (a < b) ? -1 : (a > b) ? 1 : 0; 40 assert(a != b);
41 return (a < b) ? -1 : 1;
40 } 42 }
41 43
42 // If number of colors in the image is less than or equal to MAX_PALETTE_SIZE, 44 // If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
43 // creates a palette and returns true, else returns false. 45 // creates a palette and returns true, else returns false.
44 static int AnalyzeAndCreatePalette(const WebPPicture* const pic, 46 static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
45 uint32_t palette[MAX_PALETTE_SIZE], 47 uint32_t palette[MAX_PALETTE_SIZE],
46 int* const palette_size) { 48 int* const palette_size) {
47 int i, x, y, key; 49 int i, x, y, key;
48 int num_colors = 0; 50 int num_colors = 0;
49 uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 }; 51 uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 palette[num_colors] = colors[i]; 93 palette[num_colors] = colors[i];
92 ++num_colors; 94 ++num_colors;
93 } 95 }
94 } 96 }
95 97
96 qsort(palette, num_colors, sizeof(*palette), CompareColors); 98 qsort(palette, num_colors, sizeof(*palette), CompareColors);
97 *palette_size = num_colors; 99 *palette_size = num_colors;
98 return 1; 100 return 1;
99 } 101 }
100 102
101 static int AnalyzeEntropy(const WebPPicture* const pic, 103 static int AnalyzeEntropy(const uint32_t* argb,
104 int width, int height, int argb_stride,
102 double* const nonpredicted_bits, 105 double* const nonpredicted_bits,
103 double* const predicted_bits) { 106 double* const predicted_bits) {
104 int x, y; 107 int x, y;
105 const uint32_t* argb = pic->argb;
106 const uint32_t* last_line = NULL; 108 const uint32_t* last_line = NULL;
107 uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0 109 uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0
108 110
109 VP8LHistogram* nonpredicted = NULL; 111 VP8LHistogram* nonpredicted = NULL;
110 VP8LHistogram* predicted = 112 VP8LHistogram* predicted =
111 (VP8LHistogram*)malloc(2 * sizeof(*predicted)); 113 (VP8LHistogram*)malloc(2 * sizeof(*predicted));
112 if (predicted == NULL) return 0; 114 if (predicted == NULL) return 0;
113 nonpredicted = predicted + 1; 115 nonpredicted = predicted + 1;
114 116
115 VP8LHistogramInit(predicted, 0); 117 VP8LHistogramInit(predicted, 0);
116 VP8LHistogramInit(nonpredicted, 0); 118 VP8LHistogramInit(nonpredicted, 0);
117 for (y = 0; y < pic->height; ++y) { 119 for (y = 0; y < height; ++y) {
118 for (x = 0; x < pic->width; ++x) { 120 for (x = 0; x < width; ++x) {
119 const uint32_t pix = argb[x]; 121 const uint32_t pix = argb[x];
120 const uint32_t pix_diff = VP8LSubPixels(pix, last_pix); 122 const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
121 if (pix_diff == 0) continue; 123 if (pix_diff == 0) continue;
122 if (last_line != NULL && pix == last_line[x]) { 124 if (last_line != NULL && pix == last_line[x]) {
123 continue; 125 continue;
124 } 126 }
125 last_pix = pix; 127 last_pix = pix;
126 { 128 {
127 const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix); 129 const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
128 const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff); 130 const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
129 VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token); 131 VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token);
130 VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token); 132 VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token);
131 } 133 }
132 } 134 }
133 last_line = argb; 135 last_line = argb;
134 argb += pic->argb_stride; 136 argb += argb_stride;
135 } 137 }
136 *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted); 138 *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
137 *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted); 139 *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
138 free(predicted); 140 free(predicted);
139 return 1; 141 return 1;
140 } 142 }
141 143
142 static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) { 144 static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) {
143 const WebPPicture* const pic = enc->pic_; 145 const WebPPicture* const pic = enc->pic_;
144 assert(pic != NULL && pic->argb != NULL); 146 assert(pic != NULL && pic->argb != NULL);
145 147
146 enc->use_palette_ = (image_hint == WEBP_HINT_GRAPH) ? 0 : 148 enc->use_palette_ =
147 AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_); 149 AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_);
150
151 if (image_hint == WEBP_HINT_GRAPH) {
152 if (enc->use_palette_ && enc->palette_size_ < MAX_COLORS_FOR_GRAPH) {
153 enc->use_palette_ = 0;
154 }
155 }
156
148 if (!enc->use_palette_) { 157 if (!enc->use_palette_) {
149 if (image_hint == WEBP_HINT_DEFAULT) { 158 if (image_hint == WEBP_HINT_PHOTO) {
159 enc->use_predict_ = 1;
160 enc->use_cross_color_ = 1;
161 } else {
150 double non_pred_entropy, pred_entropy; 162 double non_pred_entropy, pred_entropy;
151 if (!AnalyzeEntropy(pic, &non_pred_entropy, &pred_entropy)) { 163 if (!AnalyzeEntropy(pic->argb, pic->width, pic->height, pic->argb_stride,
164 &non_pred_entropy, &pred_entropy)) {
152 return 0; 165 return 0;
153 } 166 }
154
155 if (pred_entropy < 0.95 * non_pred_entropy) { 167 if (pred_entropy < 0.95 * non_pred_entropy) {
156 enc->use_predict_ = 1; 168 enc->use_predict_ = 1;
169 // TODO(vikasa): Observed some correlation of cross_color transform with
170 // predict. Need to investigate this further and add separate heuristic
171 // for setting use_cross_color flag.
157 enc->use_cross_color_ = 1; 172 enc->use_cross_color_ = 1;
158 } 173 }
159 } else if (image_hint == WEBP_HINT_PHOTO) {
160 enc->use_predict_ = 1;
161 enc->use_cross_color_ = 1;
162 } 174 }
163 } 175 }
176
164 return 1; 177 return 1;
165 } 178 }
166 179
167 static int GetHuffBitLengthsAndCodes( 180 static int GetHuffBitLengthsAndCodes(
168 const VP8LHistogramSet* const histogram_image, 181 const VP8LHistogramSet* const histogram_image,
169 HuffmanTreeCode* const huffman_codes) { 182 HuffmanTreeCode* const huffman_codes) {
170 int i, k; 183 int i, k;
171 int ok = 1; 184 int ok = 1;
172 uint64_t total_length_size = 0; 185 uint64_t total_length_size = 0;
173 uint8_t* mem_buf = NULL; 186 uint8_t* mem_buf = NULL;
(...skipping 27 matching lines...) Expand all
201 for (i = 0; i < 5 * histogram_image_size; ++i) { 214 for (i = 0; i < 5 * histogram_image_size; ++i) {
202 const int bit_length = huffman_codes[i].num_symbols; 215 const int bit_length = huffman_codes[i].num_symbols;
203 huffman_codes[i].codes = codes; 216 huffman_codes[i].codes = codes;
204 huffman_codes[i].code_lengths = lengths; 217 huffman_codes[i].code_lengths = lengths;
205 codes += bit_length; 218 codes += bit_length;
206 lengths += bit_length; 219 lengths += bit_length;
207 } 220 }
208 } 221 }
209 222
210 // Create Huffman trees. 223 // Create Huffman trees.
211 for (i = 0; i < histogram_image_size; ++i) { 224 for (i = 0; ok && (i < histogram_image_size); ++i) {
212 HuffmanTreeCode* const codes = &huffman_codes[5 * i]; 225 HuffmanTreeCode* const codes = &huffman_codes[5 * i];
213 VP8LHistogram* const histo = histogram_image->histograms[i]; 226 VP8LHistogram* const histo = histogram_image->histograms[i];
214 ok = ok && VP8LCreateHuffmanTree(histo->literal_, 15, codes + 0); 227 ok = ok && VP8LCreateHuffmanTree(histo->literal_, 15, codes + 0);
215 ok = ok && VP8LCreateHuffmanTree(histo->red_, 15, codes + 1); 228 ok = ok && VP8LCreateHuffmanTree(histo->red_, 15, codes + 1);
216 ok = ok && VP8LCreateHuffmanTree(histo->blue_, 15, codes + 2); 229 ok = ok && VP8LCreateHuffmanTree(histo->blue_, 15, codes + 2);
217 ok = ok && VP8LCreateHuffmanTree(histo->alpha_, 15, codes + 3); 230 ok = ok && VP8LCreateHuffmanTree(histo->alpha_, 15, codes + 3);
218 ok = ok && VP8LCreateHuffmanTree(histo->distance_, 15, codes + 4); 231 ok = ok && VP8LCreateHuffmanTree(histo->distance_, 15, codes + 4);
219 } 232 }
220 233
221 End: 234 End:
222 if (!ok) free(mem_buf); 235 if (!ok) {
236 free(mem_buf);
237 // If one VP8LCreateHuffmanTree() above fails, we need to clean up behind.
238 memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
239 }
223 return ok; 240 return ok;
224 } 241 }
225 242
226 static void StoreHuffmanTreeOfHuffmanTreeToBitMask( 243 static void StoreHuffmanTreeOfHuffmanTreeToBitMask(
227 VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) { 244 VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) {
228 // RFC 1951 will calm you down if you are worried about this funny sequence. 245 // RFC 1951 will calm you down if you are worried about this funny sequence.
229 // This sequence is tuned from that, but more weighted for lower symbol count, 246 // This sequence is tuned from that, but more weighted for lower symbol count,
230 // and more spiking histograms. 247 // and more spiking histograms.
231 static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = { 248 static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = {
232 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 249 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 if (count == 2) { 404 if (count == 2) {
388 VP8LWriteBits(bw, 8, symbols[1]); 405 VP8LWriteBits(bw, 8, symbols[1]);
389 } 406 }
390 return 1; 407 return 1;
391 } else { 408 } else {
392 return StoreFullHuffmanCode(bw, huffman_code); 409 return StoreFullHuffmanCode(bw, huffman_code);
393 } 410 }
394 } 411 }
395 412
396 static void WriteHuffmanCode(VP8LBitWriter* const bw, 413 static void WriteHuffmanCode(VP8LBitWriter* const bw,
397 const HuffmanTreeCode* const code, int index) { 414 const HuffmanTreeCode* const code,
398 const int depth = code->code_lengths[index]; 415 int code_index) {
399 const int symbol = code->codes[index]; 416 const int depth = code->code_lengths[code_index];
417 const int symbol = code->codes[code_index];
400 VP8LWriteBits(bw, depth, symbol); 418 VP8LWriteBits(bw, depth, symbol);
401 } 419 }
402 420
403 static void StoreImageToBitMask( 421 static void StoreImageToBitMask(
404 VP8LBitWriter* const bw, int width, int histo_bits, 422 VP8LBitWriter* const bw, int width, int histo_bits,
405 const VP8LBackwardRefs* const refs, 423 const VP8LBackwardRefs* const refs,
406 const uint16_t* histogram_symbols, 424 const uint16_t* histogram_symbols,
407 const HuffmanTreeCode* const huffman_codes) { 425 const HuffmanTreeCode* const huffman_codes) {
408 // x and y trace the position in the image. 426 // x and y trace the position in the image.
409 int x = 0; 427 int x = 0;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 VP8LAllocateHistogramSet(histogram_image_xysize, 0); 528 VP8LAllocateHistogramSet(histogram_image_xysize, 0);
511 int histogram_image_size = 0; 529 int histogram_image_size = 0;
512 size_t bit_array_size = 0; 530 size_t bit_array_size = 0;
513 HuffmanTreeCode* huffman_codes = NULL; 531 HuffmanTreeCode* huffman_codes = NULL;
514 VP8LBackwardRefs refs; 532 VP8LBackwardRefs refs;
515 uint16_t* const histogram_symbols = 533 uint16_t* const histogram_symbols =
516 (uint16_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize, 534 (uint16_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
517 sizeof(*histogram_symbols)); 535 sizeof(*histogram_symbols));
518 assert(histogram_bits >= MIN_HUFFMAN_BITS); 536 assert(histogram_bits >= MIN_HUFFMAN_BITS);
519 assert(histogram_bits <= MAX_HUFFMAN_BITS); 537 assert(histogram_bits <= MAX_HUFFMAN_BITS);
520 if (histogram_image == NULL || histogram_symbols == NULL) goto Error; 538
539 if (histogram_image == NULL || histogram_symbols == NULL) {
540 free(histogram_image);
541 free(histogram_symbols);
542 return 0;
543 }
521 544
522 // Calculate backward references from ARGB image. 545 // Calculate backward references from ARGB image.
523 if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits, 546 if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits,
524 use_2d_locality, &refs)) { 547 use_2d_locality, &refs)) {
525 goto Error; 548 goto Error;
526 } 549 }
527 // Build histogram image and symbols from backward references. 550 // Build histogram image and symbols from backward references.
528 if (!VP8LGetHistoImageSymbols(width, height, &refs, 551 if (!VP8LGetHistoImageSymbols(width, height, &refs,
529 quality, histogram_bits, cache_bits, 552 quality, histogram_bits, cache_bits,
530 histogram_image, 553 histogram_image,
531 histogram_symbols)) { 554 histogram_symbols)) {
532 goto Error; 555 goto Error;
533 } 556 }
534 // Create Huffman bit lengths and codes for each histogram image. 557 // Create Huffman bit lengths and codes for each histogram image.
535 histogram_image_size = histogram_image->size; 558 histogram_image_size = histogram_image->size;
536 bit_array_size = 5 * histogram_image_size; 559 bit_array_size = 5 * histogram_image_size;
537 huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size, 560 huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
538 sizeof(*huffman_codes)); 561 sizeof(*huffman_codes));
539 if (huffman_codes == NULL || 562 if (huffman_codes == NULL ||
540 !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { 563 !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
541 goto Error; 564 goto Error;
542 } 565 }
566 // Free combined histograms.
567 free(histogram_image);
568 histogram_image = NULL;
543 569
544 // Color Cache parameters. 570 // Color Cache parameters.
545 VP8LWriteBits(bw, 1, use_color_cache); 571 VP8LWriteBits(bw, 1, use_color_cache);
546 if (use_color_cache) { 572 if (use_color_cache) {
547 VP8LWriteBits(bw, 4, cache_bits); 573 VP8LWriteBits(bw, 4, cache_bits);
548 } 574 }
549 575
550 // Huffman image + meta huffman. 576 // Huffman image + meta huffman.
551 { 577 {
552 const int write_histogram_image = (histogram_image_size > 1); 578 const int write_histogram_image = (histogram_image_size > 1);
553 VP8LWriteBits(bw, 1, write_histogram_image); 579 VP8LWriteBits(bw, 1, write_histogram_image);
554 if (write_histogram_image) { 580 if (write_histogram_image) {
555 uint32_t* const histogram_argb = 581 uint32_t* const histogram_argb =
556 (uint32_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize, 582 (uint32_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
557 sizeof(*histogram_argb)); 583 sizeof(*histogram_argb));
558 int max_index = 0; 584 int max_index = 0;
559 uint32_t i; 585 uint32_t i;
560 if (histogram_argb == NULL) goto Error; 586 if (histogram_argb == NULL) goto Error;
561 for (i = 0; i < histogram_image_xysize; ++i) { 587 for (i = 0; i < histogram_image_xysize; ++i) {
562 const int index = histogram_symbols[i] & 0xffff; 588 const int symbol_index = histogram_symbols[i] & 0xffff;
563 histogram_argb[i] = 0xff000000 | (index << 8); 589 histogram_argb[i] = 0xff000000 | (symbol_index << 8);
564 if (index >= max_index) { 590 if (symbol_index >= max_index) {
565 max_index = index + 1; 591 max_index = symbol_index + 1;
566 } 592 }
567 } 593 }
568 histogram_image_size = max_index; 594 histogram_image_size = max_index;
569 595
570 VP8LWriteBits(bw, 3, histogram_bits - 2); 596 VP8LWriteBits(bw, 3, histogram_bits - 2);
571 ok = EncodeImageNoHuffman(bw, histogram_argb, 597 ok = EncodeImageNoHuffman(bw, histogram_argb,
572 VP8LSubSampleSize(width, histogram_bits), 598 VP8LSubSampleSize(width, histogram_bits),
573 VP8LSubSampleSize(height, histogram_bits), 599 VP8LSubSampleSize(height, histogram_bits),
574 quality); 600 quality);
575 free(histogram_argb); 601 free(histogram_argb);
576 if (!ok) goto Error; 602 if (!ok) goto Error;
577 } 603 }
578 } 604 }
579 605
580 // Store Huffman codes. 606 // Store Huffman codes.
581 { 607 {
582 int i; 608 int i;
583 for (i = 0; i < 5 * histogram_image_size; ++i) { 609 for (i = 0; i < 5 * histogram_image_size; ++i) {
584 HuffmanTreeCode* const codes = &huffman_codes[i]; 610 HuffmanTreeCode* const codes = &huffman_codes[i];
585 if (!StoreHuffmanCode(bw, codes)) goto Error; 611 if (!StoreHuffmanCode(bw, codes)) goto Error;
586 ClearHuffmanTreeIfOnlyOneSymbol(codes); 612 ClearHuffmanTreeIfOnlyOneSymbol(codes);
587 } 613 }
588 } 614 }
589 // Free combined histograms.
590 free(histogram_image);
591 histogram_image = NULL;
592 615
593 // Store actual literals. 616 // Store actual literals.
594 StoreImageToBitMask(bw, width, histogram_bits, &refs, 617 StoreImageToBitMask(bw, width, histogram_bits, &refs,
595 histogram_symbols, huffman_codes); 618 histogram_symbols, huffman_codes);
596 ok = 1; 619 ok = 1;
597 620
598 Error: 621 Error:
599 if (!ok) free(histogram_image); 622 free(histogram_image);
600 623
601 VP8LClearBackwardRefs(&refs); 624 VP8LClearBackwardRefs(&refs);
602 if (huffman_codes != NULL) { 625 if (huffman_codes != NULL) {
603 free(huffman_codes->codes); 626 free(huffman_codes->codes);
604 free(huffman_codes); 627 free(huffman_codes);
605 } 628 }
606 free(histogram_symbols); 629 free(histogram_symbols);
607 return ok; 630 return ok;
608 } 631 }
609 632
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 VP8LWriteBits(bw, 3, ccolor_transform_bits - 2); 710 VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
688 if (!EncodeImageNoHuffman(bw, enc->transform_data_, 711 if (!EncodeImageNoHuffman(bw, enc->transform_data_,
689 transform_width, transform_height, quality)) { 712 transform_width, transform_height, quality)) {
690 return 0; 713 return 0;
691 } 714 }
692 return 1; 715 return 1;
693 } 716 }
694 717
695 // ----------------------------------------------------------------------------- 718 // -----------------------------------------------------------------------------
696 719
697 static void PutLE32(uint8_t* const data, uint32_t val) {
698 data[0] = (val >> 0) & 0xff;
699 data[1] = (val >> 8) & 0xff;
700 data[2] = (val >> 16) & 0xff;
701 data[3] = (val >> 24) & 0xff;
702 }
703
704 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic, 720 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
705 size_t riff_size, size_t vp8l_size) { 721 size_t riff_size, size_t vp8l_size) {
706 uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { 722 uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
707 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', 723 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
708 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, 724 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
709 }; 725 };
710 PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); 726 PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
711 PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size); 727 PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
712 if (!pic->writer(riff, sizeof(riff), pic)) { 728 if (!pic->writer(riff, sizeof(riff), pic)) {
713 return VP8_ENC_ERROR_BAD_WRITE; 729 return VP8_ENC_ERROR_BAD_WRITE;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
788 mem += image_size; 804 mem += image_size;
789 enc->argb_scratch_ = mem; 805 enc->argb_scratch_ = mem;
790 mem += argb_scratch_size; 806 mem += argb_scratch_size;
791 enc->transform_data_ = mem; 807 enc->transform_data_ = mem;
792 enc->current_width_ = width; 808 enc->current_width_ = width;
793 809
794 Error: 810 Error:
795 return err; 811 return err;
796 } 812 }
797 813
798 // Bundles multiple (2, 4 or 8) pixels into a single pixel. 814 // Bundles multiple (1, 2, 4 or 8) pixels into a single pixel.
799 // Returns the new xsize. 815 static void BundleColorMap(const uint8_t* const row, int width,
800 static void BundleColorMap(const WebPPicture* const pic, 816 int xbits, uint32_t* const dst) {
801 int xbits, uint32_t* bundled_argb, int xs) { 817 int x;
802 int y; 818 if (xbits > 0) {
803 const int bit_depth = 1 << (3 - xbits); 819 const int bit_depth = 1 << (3 - xbits);
804 uint32_t code = 0; 820 const int mask = (1 << xbits) - 1;
805 const uint32_t* argb = pic->argb; 821 uint32_t code = 0xff000000;
806 const int width = pic->width;
807 const int height = pic->height;
808
809 for (y = 0; y < height; ++y) {
810 int x;
811 for (x = 0; x < width; ++x) { 822 for (x = 0; x < width; ++x) {
812 const int mask = (1 << xbits) - 1;
813 const int xsub = x & mask; 823 const int xsub = x & mask;
814 if (xsub == 0) { 824 if (xsub == 0) {
815 code = 0; 825 code = 0xff000000;
816 } 826 }
817 // TODO(vikasa): simplify the bundling logic. 827 code |= row[x] << (8 + bit_depth * xsub);
818 code |= (argb[x] & 0xff00) << (bit_depth * xsub); 828 dst[x >> xbits] = code;
819 bundled_argb[y * xs + (x >> xbits)] = 0xff000000 | code;
820 } 829 }
821 argb += pic->argb_stride; 830 } else {
831 for (x = 0; x < width; ++x) dst[x] = 0xff000000 | (row[x] << 8);
822 } 832 }
823 } 833 }
824 834
825 // Note: Expects "enc->palette_" to be set properly. 835 // Note: Expects "enc->palette_" to be set properly.
826 // Also, "enc->palette_" will be modified after this call and should not be used 836 // Also, "enc->palette_" will be modified after this call and should not be used
827 // later. 837 // later.
828 static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw, 838 static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
829 VP8LEncoder* const enc, int quality) { 839 VP8LEncoder* const enc, int quality) {
830 WebPEncodingError err = VP8_ENC_OK; 840 WebPEncodingError err = VP8_ENC_OK;
831 int i, x, y; 841 int i, x, y;
832 const WebPPicture* const pic = enc->pic_; 842 const WebPPicture* const pic = enc->pic_;
833 uint32_t* argb = pic->argb; 843 uint32_t* src = pic->argb;
844 uint32_t* dst;
834 const int width = pic->width; 845 const int width = pic->width;
835 const int height = pic->height; 846 const int height = pic->height;
836 uint32_t* const palette = enc->palette_; 847 uint32_t* const palette = enc->palette_;
837 const int palette_size = enc->palette_size_; 848 const int palette_size = enc->palette_size_;
849 uint8_t* row = NULL;
850 int xbits;
838 851
839 // Replace each input pixel by corresponding palette index. 852 // Replace each input pixel by corresponding palette index.
853 // This is done line by line.
854 if (palette_size <= 4) {
855 xbits = (palette_size <= 2) ? 3 : 2;
856 } else {
857 xbits = (palette_size <= 16) ? 1 : 0;
858 }
859
860 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
861 if (err != VP8_ENC_OK) goto Error;
862 dst = enc->argb_;
863
864 row = WebPSafeMalloc((uint64_t)width, sizeof(*row));
865 if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
866
840 for (y = 0; y < height; ++y) { 867 for (y = 0; y < height; ++y) {
841 for (x = 0; x < width; ++x) { 868 for (x = 0; x < width; ++x) {
842 const uint32_t pix = argb[x]; 869 const uint32_t pix = src[x];
843 for (i = 0; i < palette_size; ++i) { 870 for (i = 0; i < palette_size; ++i) {
844 if (pix == palette[i]) { 871 if (pix == palette[i]) {
845 argb[x] = 0xff000000u | (i << 8); 872 row[x] = i;
846 break; 873 break;
847 } 874 }
848 } 875 }
849 } 876 }
850 argb += pic->argb_stride; 877 BundleColorMap(row, width, xbits, dst);
878 src += pic->argb_stride;
879 dst += enc->current_width_;
851 } 880 }
852 881
853 // Save palette to bitstream. 882 // Save palette to bitstream.
854 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); 883 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
855 VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM); 884 VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM);
856 assert(palette_size >= 1); 885 assert(palette_size >= 1);
857 VP8LWriteBits(bw, 8, palette_size - 1); 886 VP8LWriteBits(bw, 8, palette_size - 1);
858 for (i = palette_size - 1; i >= 1; --i) { 887 for (i = palette_size - 1; i >= 1; --i) {
859 palette[i] = VP8LSubPixels(palette[i], palette[i - 1]); 888 palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
860 } 889 }
861 if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) { 890 if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) {
862 err = VP8_ENC_ERROR_INVALID_CONFIGURATION; 891 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
863 goto Error; 892 goto Error;
864 } 893 }
865 894
866 if (palette_size <= 16) {
867 // Image can be packed (multiple pixels per uint32_t).
868 int xbits = 1;
869 if (palette_size <= 2) {
870 xbits = 3;
871 } else if (palette_size <= 4) {
872 xbits = 2;
873 }
874 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
875 if (err != VP8_ENC_OK) goto Error;
876 BundleColorMap(pic, xbits, enc->argb_, enc->current_width_);
877 }
878
879 Error: 895 Error:
896 free(row);
880 return err; 897 return err;
881 } 898 }
882 899
883 // ----------------------------------------------------------------------------- 900 // -----------------------------------------------------------------------------
884 901
885 static int GetHistoBits(const WebPConfig* const config, 902 static int GetHistoBits(const WebPConfig* const config,
886 const WebPPicture* const pic) { 903 const WebPPicture* const pic) {
887 const int width = pic->width; 904 const int width = pic->width;
888 const int height = pic->height; 905 const int height = pic->height;
889 const size_t hist_size = sizeof(VP8LHistogram); 906 const uint64_t hist_size = sizeof(VP8LHistogram);
890 // Make tile size a function of encoding method (Range: 0 to 6). 907 // Make tile size a function of encoding method (Range: 0 to 6).
891 int histo_bits = 7 - config->method; 908 int histo_bits = 7 - config->method;
892 while (1) { 909 while (1) {
893 const size_t huff_image_size = VP8LSubSampleSize(width, histo_bits) * 910 const uint64_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
894 VP8LSubSampleSize(height, histo_bits) * 911 VP8LSubSampleSize(height, histo_bits) *
895 hist_size; 912 hist_size;
896 if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break; 913 if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
897 ++histo_bits; 914 ++histo_bits;
898 } 915 }
899 return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS : 916 return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
900 (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits; 917 (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
901 } 918 }
902 919
903 static void InitEncParams(VP8LEncoder* const enc) { 920 static void InitEncParams(VP8LEncoder* const enc) {
904 const WebPConfig* const config = enc->config_; 921 const WebPConfig* const config = enc->config_;
905 const WebPPicture* const picture = enc->pic_; 922 const WebPPicture* const picture = enc->pic_;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
954 // Analyze image (entropy, num_palettes etc) 971 // Analyze image (entropy, num_palettes etc)
955 972
956 if (!VP8LEncAnalyze(enc, config->image_hint)) { 973 if (!VP8LEncAnalyze(enc, config->image_hint)) {
957 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 974 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
958 goto Error; 975 goto Error;
959 } 976 }
960 977
961 if (enc->use_palette_) { 978 if (enc->use_palette_) {
962 err = ApplyPalette(bw, enc, quality); 979 err = ApplyPalette(bw, enc, quality);
963 if (err != VP8_ENC_OK) goto Error; 980 if (err != VP8_ENC_OK) goto Error;
981 // Color cache is disabled for palette.
964 enc->cache_bits_ = 0; 982 enc->cache_bits_ = 0;
965 } 983 }
966 984
967 // In case image is not packed. 985 // In case image is not packed.
968 if (enc->argb_ == NULL) { 986 if (enc->argb_ == NULL) {
969 int y; 987 int y;
970 err = AllocateTransformBuffer(enc, width, height); 988 err = AllocateTransformBuffer(enc, width, height);
971 if (err != VP8_ENC_OK) goto Error; 989 if (err != VP8_ENC_OK) goto Error;
972 for (y = 0; y < height; ++y) { 990 for (y = 0; y < height; ++y) {
973 memcpy(enc->argb_ + y * width, 991 memcpy(enc->argb_ + y * width,
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
1128 return 0; 1146 return 0;
1129 } 1147 }
1130 return 1; 1148 return 1;
1131 } 1149 }
1132 1150
1133 //------------------------------------------------------------------------------ 1151 //------------------------------------------------------------------------------
1134 1152
1135 #if defined(__cplusplus) || defined(c_plusplus) 1153 #if defined(__cplusplus) || defined(c_plusplus)
1136 } // extern "C" 1154 } // extern "C"
1137 #endif 1155 #endif
OLDNEW
« no previous file with comments | « third_party/libwebp/enc/vp8enci.h ('k') | third_party/libwebp/enc/webpenc.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698