| 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 |