OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |