| OLD | NEW |
| 1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
| 4 // that can be found in the COPYING file in the root of the source | 4 // that can be found in the COPYING file in the root of the source |
| 5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
| 8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
| 9 // | 9 // |
| 10 // main entry for the lossless encoder. | 10 // main entry for the lossless encoder. |
| 11 // | 11 // |
| 12 // Author: Vikas Arora (vikaas.arora@gmail.com) | 12 // Author: Vikas Arora (vikaas.arora@gmail.com) |
| 13 // | 13 // |
| 14 | 14 |
| 15 #include <assert.h> | 15 #include <assert.h> |
| 16 #include <stdlib.h> | 16 #include <stdlib.h> |
| 17 | 17 |
| 18 #include "./backward_references.h" | 18 #include "./backward_references_enc.h" |
| 19 #include "./histogram.h" | 19 #include "./histogram_enc.h" |
| 20 #include "./vp8enci.h" | 20 #include "./vp8i_enc.h" |
| 21 #include "./vp8li.h" | 21 #include "./vp8li_enc.h" |
| 22 #include "../dsp/lossless.h" | 22 #include "../dsp/lossless.h" |
| 23 #include "../utils/bit_writer.h" | 23 #include "../dsp/lossless_common.h" |
| 24 #include "../utils/huffman_encode.h" | 24 #include "../utils/bit_writer_utils.h" |
| 25 #include "../utils/huffman_encode_utils.h" |
| 25 #include "../utils/utils.h" | 26 #include "../utils/utils.h" |
| 26 #include "../webp/format_constants.h" | 27 #include "../webp/format_constants.h" |
| 27 | 28 |
| 28 #include "./delta_palettization.h" | 29 #include "./delta_palettization_enc.h" |
| 29 | 30 |
| 30 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. | 31 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. |
| 31 // Maximum number of histogram images (sub-blocks). | 32 // Maximum number of histogram images (sub-blocks). |
| 32 #define MAX_HUFF_IMAGE_SIZE 2600 | 33 #define MAX_HUFF_IMAGE_SIZE 2600 |
| 33 | 34 |
| 34 // Palette reordering for smaller sum of deltas (and for smaller storage). | 35 // Palette reordering for smaller sum of deltas (and for smaller storage). |
| 35 | 36 |
| 36 static int PaletteCompareColorsForQsort(const void* p1, const void* p2) { | 37 static int PaletteCompareColorsForQsort(const void* p1, const void* p2) { |
| 37 const uint32_t a = WebPMemToUint32((uint8_t*)p1); | 38 const uint32_t a = WebPMemToUint32((uint8_t*)p1); |
| 38 const uint32_t b = WebPMemToUint32((uint8_t*)p2); | 39 const uint32_t b = WebPMemToUint32((uint8_t*)p2); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 kHistoBlue, | 157 kHistoBlue, |
| 157 kHistoBluePred, | 158 kHistoBluePred, |
| 158 kHistoRedSubGreen, | 159 kHistoRedSubGreen, |
| 159 kHistoRedPredSubGreen, | 160 kHistoRedPredSubGreen, |
| 160 kHistoBlueSubGreen, | 161 kHistoBlueSubGreen, |
| 161 kHistoBluePredSubGreen, | 162 kHistoBluePredSubGreen, |
| 162 kHistoPalette, | 163 kHistoPalette, |
| 163 kHistoTotal // Must be last. | 164 kHistoTotal // Must be last. |
| 164 } HistoIx; | 165 } HistoIx; |
| 165 | 166 |
| 166 static void AddSingleSubGreen(uint32_t p, uint32_t* r, uint32_t* b) { | 167 static void AddSingleSubGreen(int p, uint32_t* const r, uint32_t* const b) { |
| 167 const uint32_t green = p >> 8; // The upper bits are masked away later. | 168 const int green = p >> 8; // The upper bits are masked away later. |
| 168 ++r[((p >> 16) - green) & 0xff]; | 169 ++r[((p >> 16) - green) & 0xff]; |
| 169 ++b[(p - green) & 0xff]; | 170 ++b[((p >> 0) - green) & 0xff]; |
| 170 } | 171 } |
| 171 | 172 |
| 172 static void AddSingle(uint32_t p, | 173 static void AddSingle(uint32_t p, |
| 173 uint32_t* a, uint32_t* r, uint32_t* g, uint32_t* b) { | 174 uint32_t* const a, uint32_t* const r, |
| 174 ++a[p >> 24]; | 175 uint32_t* const g, uint32_t* const b) { |
| 176 ++a[(p >> 24) & 0xff]; |
| 175 ++r[(p >> 16) & 0xff]; | 177 ++r[(p >> 16) & 0xff]; |
| 176 ++g[(p >> 8) & 0xff]; | 178 ++g[(p >> 8) & 0xff]; |
| 177 ++b[(p & 0xff)]; | 179 ++b[(p >> 0) & 0xff]; |
| 180 } |
| 181 |
| 182 static WEBP_INLINE uint32_t HashPix(uint32_t pix) { |
| 183 // Note that masking with 0xffffffffu is for preventing an |
| 184 // 'unsigned int overflow' warning. Doesn't impact the compiled code. |
| 185 return ((((uint64_t)pix + (pix >> 19)) * 0x39c5fba7ull) & 0xffffffffu) >> 24; |
| 178 } | 186 } |
| 179 | 187 |
| 180 static int AnalyzeEntropy(const uint32_t* argb, | 188 static int AnalyzeEntropy(const uint32_t* argb, |
| 181 int width, int height, int argb_stride, | 189 int width, int height, int argb_stride, |
| 182 int use_palette, | 190 int use_palette, |
| 183 EntropyIx* const min_entropy_ix, | 191 EntropyIx* const min_entropy_ix, |
| 184 int* const red_and_blue_always_zero) { | 192 int* const red_and_blue_always_zero) { |
| 185 // Allocate histogram set with cache_bits = 0. | 193 // Allocate histogram set with cache_bits = 0. |
| 186 uint32_t* const histo = | 194 uint32_t* const histo = |
| 187 (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256); | 195 (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 207 &histo[kHistoGreenPred * 256], | 215 &histo[kHistoGreenPred * 256], |
| 208 &histo[kHistoBluePred * 256]); | 216 &histo[kHistoBluePred * 256]); |
| 209 AddSingleSubGreen(pix, | 217 AddSingleSubGreen(pix, |
| 210 &histo[kHistoRedSubGreen * 256], | 218 &histo[kHistoRedSubGreen * 256], |
| 211 &histo[kHistoBlueSubGreen * 256]); | 219 &histo[kHistoBlueSubGreen * 256]); |
| 212 AddSingleSubGreen(pix_diff, | 220 AddSingleSubGreen(pix_diff, |
| 213 &histo[kHistoRedPredSubGreen * 256], | 221 &histo[kHistoRedPredSubGreen * 256], |
| 214 &histo[kHistoBluePredSubGreen * 256]); | 222 &histo[kHistoBluePredSubGreen * 256]); |
| 215 { | 223 { |
| 216 // Approximate the palette by the entropy of the multiplicative hash. | 224 // Approximate the palette by the entropy of the multiplicative hash. |
| 217 const int hash = ((pix + (pix >> 19)) * 0x39c5fba7) >> 24; | 225 const uint32_t hash = HashPix(pix); |
| 218 ++histo[kHistoPalette * 256 + (hash & 0xff)]; | 226 ++histo[kHistoPalette * 256 + hash]; |
| 219 } | 227 } |
| 220 } | 228 } |
| 221 prev_row = curr_row; | 229 prev_row = curr_row; |
| 222 curr_row += argb_stride; | 230 curr_row += argb_stride; |
| 223 } | 231 } |
| 224 { | 232 { |
| 225 double entropy_comp[kHistoTotal]; | 233 double entropy_comp[kHistoTotal]; |
| 226 double entropy[kNumEntropyIx]; | 234 double entropy[kNumEntropyIx]; |
| 227 int k; | 235 int k; |
| 228 int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen; | 236 int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 VP8LSubSampleSize(height, histo_bits); | 312 VP8LSubSampleSize(height, histo_bits); |
| 305 if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break; | 313 if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break; |
| 306 ++histo_bits; | 314 ++histo_bits; |
| 307 } | 315 } |
| 308 return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS : | 316 return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS : |
| 309 (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits; | 317 (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits; |
| 310 } | 318 } |
| 311 | 319 |
| 312 static int GetTransformBits(int method, int histo_bits) { | 320 static int GetTransformBits(int method, int histo_bits) { |
| 313 const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5; | 321 const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5; |
| 314 return (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits; | 322 const int res = |
| 323 (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits; |
| 324 assert(res <= MAX_TRANSFORM_BITS); |
| 325 return res; |
| 315 } | 326 } |
| 316 | 327 |
| 317 static int AnalyzeAndInit(VP8LEncoder* const enc) { | 328 static int AnalyzeAndInit(VP8LEncoder* const enc) { |
| 318 const WebPPicture* const pic = enc->pic_; | 329 const WebPPicture* const pic = enc->pic_; |
| 319 const int width = pic->width; | 330 const int width = pic->width; |
| 320 const int height = pic->height; | 331 const int height = pic->height; |
| 321 const int pix_cnt = width * height; | 332 const int pix_cnt = width * height; |
| 322 const WebPConfig* const config = enc->config_; | 333 const WebPConfig* const config = enc->config_; |
| 323 const int method = config->method; | 334 const int method = config->method; |
| 324 const int low_effort = (config->method == 0); | 335 const int low_effort = (config->method == 0); |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 } | 700 } |
| 690 return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK; | 701 return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK; |
| 691 } | 702 } |
| 692 | 703 |
| 693 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31 | 704 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31 |
| 694 static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, | 705 static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, |
| 695 const uint32_t* const argb, | 706 const uint32_t* const argb, |
| 696 VP8LHashChain* const hash_chain, | 707 VP8LHashChain* const hash_chain, |
| 697 VP8LBackwardRefs refs_array[2], | 708 VP8LBackwardRefs refs_array[2], |
| 698 int width, int height, | 709 int width, int height, |
| 699 int quality) { | 710 int quality, int low_effort) { |
| 700 int i; | 711 int i; |
| 701 int max_tokens = 0; | 712 int max_tokens = 0; |
| 702 WebPEncodingError err = VP8_ENC_OK; | 713 WebPEncodingError err = VP8_ENC_OK; |
| 703 VP8LBackwardRefs* refs; | 714 VP8LBackwardRefs* refs; |
| 704 HuffmanTreeToken* tokens = NULL; | 715 HuffmanTreeToken* tokens = NULL; |
| 705 HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } }; | 716 HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } }; |
| 706 const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol | 717 const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol |
| 707 int cache_bits = 0; | 718 int cache_bits = 0; |
| 708 VP8LHistogramSet* histogram_image = NULL; | 719 VP8LHistogramSet* histogram_image = NULL; |
| 709 HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( | 720 HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( |
| 710 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); | 721 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); |
| 711 if (huff_tree == NULL) { | 722 if (huff_tree == NULL) { |
| 712 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 723 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 713 goto Error; | 724 goto Error; |
| 714 } | 725 } |
| 715 | 726 |
| 716 // Calculate backward references from ARGB image. | 727 // Calculate backward references from ARGB image. |
| 717 if (VP8LHashChainFill(hash_chain, quality, argb, width, height) == 0) { | 728 if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, |
| 729 low_effort)) { |
| 718 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 730 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 719 goto Error; | 731 goto Error; |
| 720 } | 732 } |
| 721 refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, &cache_bits, | 733 refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, &cache_bits, |
| 722 hash_chain, refs_array); | 734 hash_chain, refs_array); |
| 723 if (refs == NULL) { | 735 if (refs == NULL) { |
| 724 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 736 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 725 goto Error; | 737 goto Error; |
| 726 } | 738 } |
| 727 histogram_image = VP8LAllocateHistogramSet(1, cache_bits); | 739 histogram_image = VP8LAllocateHistogramSet(1, cache_bits); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 assert(histogram_bits <= MAX_HUFFMAN_BITS); | 819 assert(histogram_bits <= MAX_HUFFMAN_BITS); |
| 808 assert(hdr_size != NULL); | 820 assert(hdr_size != NULL); |
| 809 assert(data_size != NULL); | 821 assert(data_size != NULL); |
| 810 | 822 |
| 811 VP8LBackwardRefsInit(&refs, refs_array[0].block_size_); | 823 VP8LBackwardRefsInit(&refs, refs_array[0].block_size_); |
| 812 if (histogram_symbols == NULL) { | 824 if (histogram_symbols == NULL) { |
| 813 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 825 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 814 goto Error; | 826 goto Error; |
| 815 } | 827 } |
| 816 | 828 |
| 817 *cache_bits = use_cache ? MAX_COLOR_CACHE_BITS : 0; | 829 if (use_cache) { |
| 830 // If the value is different from zero, it has been set during the |
| 831 // palette analysis. |
| 832 if (*cache_bits == 0) *cache_bits = MAX_COLOR_CACHE_BITS; |
| 833 } else { |
| 834 *cache_bits = 0; |
| 835 } |
| 818 // 'best_refs' is the reference to the best backward refs and points to one | 836 // 'best_refs' is the reference to the best backward refs and points to one |
| 819 // of refs_array[0] or refs_array[1]. | 837 // of refs_array[0] or refs_array[1]. |
| 820 // Calculate backward references from ARGB image. | 838 // Calculate backward references from ARGB image. |
| 821 if (VP8LHashChainFill(hash_chain, quality, argb, width, height) == 0) { | 839 if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, |
| 840 low_effort)) { |
| 822 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 841 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 823 goto Error; | 842 goto Error; |
| 824 } | 843 } |
| 825 best_refs = VP8LGetBackwardReferences(width, height, argb, quality, | 844 best_refs = VP8LGetBackwardReferences(width, height, argb, quality, |
| 826 low_effort, cache_bits, hash_chain, | 845 low_effort, cache_bits, hash_chain, |
| 827 refs_array); | 846 refs_array); |
| 828 if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) { | 847 if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) { |
| 829 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 848 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 830 goto Error; | 849 goto Error; |
| 831 } | 850 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 if (symbol_index >= max_index) { | 911 if (symbol_index >= max_index) { |
| 893 max_index = symbol_index + 1; | 912 max_index = symbol_index + 1; |
| 894 } | 913 } |
| 895 } | 914 } |
| 896 histogram_image_size = max_index; | 915 histogram_image_size = max_index; |
| 897 | 916 |
| 898 VP8LPutBits(bw, histogram_bits - 2, 3); | 917 VP8LPutBits(bw, histogram_bits - 2, 3); |
| 899 err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array, | 918 err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array, |
| 900 VP8LSubSampleSize(width, histogram_bits), | 919 VP8LSubSampleSize(width, histogram_bits), |
| 901 VP8LSubSampleSize(height, histogram_bits), | 920 VP8LSubSampleSize(height, histogram_bits), |
| 902 quality); | 921 quality, low_effort); |
| 903 WebPSafeFree(histogram_argb); | 922 WebPSafeFree(histogram_argb); |
| 904 if (err != VP8_ENC_OK) goto Error; | 923 if (err != VP8_ENC_OK) goto Error; |
| 905 } | 924 } |
| 906 } | 925 } |
| 907 | 926 |
| 908 // Store Huffman codes. | 927 // Store Huffman codes. |
| 909 { | 928 { |
| 910 int i; | 929 int i; |
| 911 int max_tokens = 0; | 930 int max_tokens = 0; |
| 912 huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * CODE_LENGTH_CODES, | 931 huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * CODE_LENGTH_CODES, |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 983 near_lossless_strength, enc->config_->exact, | 1002 near_lossless_strength, enc->config_->exact, |
| 984 used_subtract_green); | 1003 used_subtract_green); |
| 985 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); | 1004 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); |
| 986 VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); | 1005 VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); |
| 987 assert(pred_bits >= 2); | 1006 assert(pred_bits >= 2); |
| 988 VP8LPutBits(bw, pred_bits - 2, 3); | 1007 VP8LPutBits(bw, pred_bits - 2, 3); |
| 989 return EncodeImageNoHuffman(bw, enc->transform_data_, | 1008 return EncodeImageNoHuffman(bw, enc->transform_data_, |
| 990 (VP8LHashChain*)&enc->hash_chain_, | 1009 (VP8LHashChain*)&enc->hash_chain_, |
| 991 (VP8LBackwardRefs*)enc->refs_, // cast const away | 1010 (VP8LBackwardRefs*)enc->refs_, // cast const away |
| 992 transform_width, transform_height, | 1011 transform_width, transform_height, |
| 993 quality); | 1012 quality, low_effort); |
| 994 } | 1013 } |
| 995 | 1014 |
| 996 static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, | 1015 static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, |
| 997 int width, int height, | 1016 int width, int height, |
| 998 int quality, | 1017 int quality, int low_effort, |
| 999 VP8LBitWriter* const bw) { | 1018 VP8LBitWriter* const bw) { |
| 1000 const int ccolor_transform_bits = enc->transform_bits_; | 1019 const int ccolor_transform_bits = enc->transform_bits_; |
| 1001 const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); | 1020 const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); |
| 1002 const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); | 1021 const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); |
| 1003 | 1022 |
| 1004 VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality, | 1023 VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality, |
| 1005 enc->argb_, enc->transform_data_); | 1024 enc->argb_, enc->transform_data_); |
| 1006 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); | 1025 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); |
| 1007 VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2); | 1026 VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2); |
| 1008 assert(ccolor_transform_bits >= 2); | 1027 assert(ccolor_transform_bits >= 2); |
| 1009 VP8LPutBits(bw, ccolor_transform_bits - 2, 3); | 1028 VP8LPutBits(bw, ccolor_transform_bits - 2, 3); |
| 1010 return EncodeImageNoHuffman(bw, enc->transform_data_, | 1029 return EncodeImageNoHuffman(bw, enc->transform_data_, |
| 1011 (VP8LHashChain*)&enc->hash_chain_, | 1030 (VP8LHashChain*)&enc->hash_chain_, |
| 1012 (VP8LBackwardRefs*)enc->refs_, // cast const away | 1031 (VP8LBackwardRefs*)enc->refs_, // cast const away |
| 1013 transform_width, transform_height, | 1032 transform_width, transform_height, |
| 1014 quality); | 1033 quality, low_effort); |
| 1015 } | 1034 } |
| 1016 | 1035 |
| 1017 // ----------------------------------------------------------------------------- | 1036 // ----------------------------------------------------------------------------- |
| 1018 | 1037 |
| 1019 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic, | 1038 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic, |
| 1020 size_t riff_size, size_t vp8l_size) { | 1039 size_t riff_size, size_t vp8l_size) { |
| 1021 uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { | 1040 uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { |
| 1022 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', | 1041 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', |
| 1023 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, | 1042 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, |
| 1024 }; | 1043 }; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1149 memcpy(enc->argb_ + y * width, | 1168 memcpy(enc->argb_ + y * width, |
| 1150 picture->argb + y * picture->argb_stride, | 1169 picture->argb + y * picture->argb_stride, |
| 1151 width * sizeof(*enc->argb_)); | 1170 width * sizeof(*enc->argb_)); |
| 1152 } | 1171 } |
| 1153 assert(enc->current_width_ == width); | 1172 assert(enc->current_width_ == width); |
| 1154 return VP8_ENC_OK; | 1173 return VP8_ENC_OK; |
| 1155 } | 1174 } |
| 1156 | 1175 |
| 1157 // ----------------------------------------------------------------------------- | 1176 // ----------------------------------------------------------------------------- |
| 1158 | 1177 |
| 1159 static int SearchColor(const uint32_t sorted[], uint32_t color, int hi) { | 1178 static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, |
| 1179 int hi) { |
| 1160 int low = 0; | 1180 int low = 0; |
| 1161 if (sorted[low] == color) return low; // loop invariant: sorted[low] != color | 1181 if (sorted[low] == color) return low; // loop invariant: sorted[low] != color |
| 1162 while (1) { | 1182 while (1) { |
| 1163 const int mid = (low + hi) >> 1; | 1183 const int mid = (low + hi) >> 1; |
| 1164 if (sorted[mid] == color) { | 1184 if (sorted[mid] == color) { |
| 1165 return mid; | 1185 return mid; |
| 1166 } else if (sorted[mid] < color) { | 1186 } else if (sorted[mid] < color) { |
| 1167 low = mid; | 1187 low = mid; |
| 1168 } else { | 1188 } else { |
| 1169 hi = mid; | 1189 hi = mid; |
| 1170 } | 1190 } |
| 1171 } | 1191 } |
| 1172 } | 1192 } |
| 1173 | 1193 |
| 1194 #define APPLY_PALETTE_GREEDY_MAX 4 |
| 1195 |
| 1196 static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[], |
| 1197 int palette_size, |
| 1198 uint32_t color) { |
| 1199 (void)palette_size; |
| 1200 assert(palette_size < APPLY_PALETTE_GREEDY_MAX); |
| 1201 assert(3 == APPLY_PALETTE_GREEDY_MAX - 1); |
| 1202 if (color == palette[0]) return 0; |
| 1203 if (color == palette[1]) return 1; |
| 1204 if (color == palette[2]) return 2; |
| 1205 return 3; |
| 1206 } |
| 1207 |
| 1208 static WEBP_INLINE uint32_t ApplyPaletteHash0(uint32_t color) { |
| 1209 // Focus on the green color. |
| 1210 return (color >> 8) & 0xff; |
| 1211 } |
| 1212 |
| 1213 #define PALETTE_INV_SIZE_BITS 11 |
| 1214 #define PALETTE_INV_SIZE (1 << PALETTE_INV_SIZE_BITS) |
| 1215 |
| 1216 static WEBP_INLINE uint32_t ApplyPaletteHash1(uint32_t color) { |
| 1217 // Forget about alpha. |
| 1218 return ((color & 0x00ffffffu) * 4222244071u) >> (32 - PALETTE_INV_SIZE_BITS); |
| 1219 } |
| 1220 |
| 1221 static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) { |
| 1222 // Forget about alpha. |
| 1223 return (color & 0x00ffffffu) * ((1u << 31) - 1) >> |
| 1224 (32 - PALETTE_INV_SIZE_BITS); |
| 1225 } |
| 1226 |
| 1174 // Sort palette in increasing order and prepare an inverse mapping array. | 1227 // Sort palette in increasing order and prepare an inverse mapping array. |
| 1175 static void PrepareMapToPalette(const uint32_t palette[], int num_colors, | 1228 static void PrepareMapToPalette(const uint32_t palette[], int num_colors, |
| 1176 uint32_t sorted[], int idx_map[]) { | 1229 uint32_t sorted[], uint32_t idx_map[]) { |
| 1177 int i; | 1230 int i; |
| 1178 memcpy(sorted, palette, num_colors * sizeof(*sorted)); | 1231 memcpy(sorted, palette, num_colors * sizeof(*sorted)); |
| 1179 qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort); | 1232 qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort); |
| 1180 for (i = 0; i < num_colors; ++i) { | 1233 for (i = 0; i < num_colors; ++i) { |
| 1181 idx_map[SearchColor(sorted, palette[i], num_colors)] = i; | 1234 idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i; |
| 1182 } | 1235 } |
| 1183 } | 1236 } |
| 1184 | 1237 |
| 1185 static void MapToPalette(const uint32_t sorted_palette[], int num_colors, | 1238 // Use 1 pixel cache for ARGB pixels. |
| 1186 uint32_t* const last_pix, int* const last_idx, | 1239 #define APPLY_PALETTE_FOR(COLOR_INDEX) do { \ |
| 1187 const int idx_map[], | 1240 uint32_t prev_pix = palette[0]; \ |
| 1188 const uint32_t* src, uint8_t* dst, int width) { | 1241 uint32_t prev_idx = 0; \ |
| 1189 int x; | 1242 for (y = 0; y < height; ++y) { \ |
| 1190 int prev_idx = *last_idx; | 1243 for (x = 0; x < width; ++x) { \ |
| 1191 uint32_t prev_pix = *last_pix; | 1244 const uint32_t pix = src[x]; \ |
| 1192 for (x = 0; x < width; ++x) { | 1245 if (pix != prev_pix) { \ |
| 1193 const uint32_t pix = src[x]; | 1246 prev_idx = COLOR_INDEX; \ |
| 1194 if (pix != prev_pix) { | 1247 prev_pix = pix; \ |
| 1195 prev_idx = idx_map[SearchColor(sorted_palette, pix, num_colors)]; | 1248 } \ |
| 1196 prev_pix = pix; | 1249 tmp_row[x] = prev_idx; \ |
| 1197 } | 1250 } \ |
| 1198 dst[x] = prev_idx; | 1251 VP8LBundleColorMap(tmp_row, width, xbits, dst); \ |
| 1199 } | 1252 src += src_stride; \ |
| 1200 *last_idx = prev_idx; | 1253 dst += dst_stride; \ |
| 1201 *last_pix = prev_pix; | 1254 } \ |
| 1202 } | 1255 } while (0) |
| 1203 | 1256 |
| 1204 // Remap argb values in src[] to packed palettes entries in dst[] | 1257 // Remap argb values in src[] to packed palettes entries in dst[] |
| 1205 // using 'row' as a temporary buffer of size 'width'. | 1258 // using 'row' as a temporary buffer of size 'width'. |
| 1206 // We assume that all src[] values have a corresponding entry in the palette. | 1259 // We assume that all src[] values have a corresponding entry in the palette. |
| 1207 // Note: src[] can be the same as dst[] | 1260 // Note: src[] can be the same as dst[] |
| 1208 static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride, | 1261 static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride, |
| 1209 uint32_t* dst, uint32_t dst_stride, | 1262 uint32_t* dst, uint32_t dst_stride, |
| 1210 const uint32_t* palette, int palette_size, | 1263 const uint32_t* palette, int palette_size, |
| 1211 int width, int height, int xbits) { | 1264 int width, int height, int xbits) { |
| 1212 // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be | 1265 // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be |
| 1213 // made to work in-place. | 1266 // made to work in-place. |
| 1214 uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row)); | 1267 uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row)); |
| 1215 int i, x, y; | 1268 int x, y; |
| 1216 int use_LUT = 1; | |
| 1217 | 1269 |
| 1218 if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; | 1270 if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 1219 for (i = 0; i < palette_size; ++i) { | 1271 |
| 1220 if ((palette[i] & 0xffff00ffu) != 0) { | 1272 if (palette_size < APPLY_PALETTE_GREEDY_MAX) { |
| 1221 use_LUT = 0; | 1273 APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix)); |
| 1222 break; | 1274 } else { |
| 1275 int i, j; |
| 1276 uint16_t buffer[PALETTE_INV_SIZE]; |
| 1277 uint32_t (*const hash_functions[])(uint32_t) = { |
| 1278 ApplyPaletteHash0, ApplyPaletteHash1, ApplyPaletteHash2 |
| 1279 }; |
| 1280 |
| 1281 // Try to find a perfect hash function able to go from a color to an index |
| 1282 // within 1 << PALETTE_INV_SIZE_BITS in order to build a hash map to go |
| 1283 // from color to index in palette. |
| 1284 for (i = 0; i < 3; ++i) { |
| 1285 int use_LUT = 1; |
| 1286 // Set each element in buffer to max uint16_t. |
| 1287 memset(buffer, 0xff, sizeof(buffer)); |
| 1288 for (j = 0; j < palette_size; ++j) { |
| 1289 const uint32_t ind = hash_functions[i](palette[j]); |
| 1290 if (buffer[ind] != 0xffffu) { |
| 1291 use_LUT = 0; |
| 1292 break; |
| 1293 } else { |
| 1294 buffer[ind] = j; |
| 1295 } |
| 1296 } |
| 1297 if (use_LUT) break; |
| 1223 } | 1298 } |
| 1224 } | |
| 1225 | 1299 |
| 1226 if (use_LUT) { | 1300 if (i == 0) { |
| 1227 uint8_t inv_palette[MAX_PALETTE_SIZE] = { 0 }; | 1301 APPLY_PALETTE_FOR(buffer[ApplyPaletteHash0(pix)]); |
| 1228 for (i = 0; i < palette_size; ++i) { | 1302 } else if (i == 1) { |
| 1229 const int color = (palette[i] >> 8) & 0xff; | 1303 APPLY_PALETTE_FOR(buffer[ApplyPaletteHash1(pix)]); |
| 1230 inv_palette[color] = i; | 1304 } else if (i == 2) { |
| 1231 } | 1305 APPLY_PALETTE_FOR(buffer[ApplyPaletteHash2(pix)]); |
| 1232 for (y = 0; y < height; ++y) { | 1306 } else { |
| 1233 for (x = 0; x < width; ++x) { | 1307 uint32_t idx_map[MAX_PALETTE_SIZE]; |
| 1234 const int color = (src[x] >> 8) & 0xff; | 1308 uint32_t palette_sorted[MAX_PALETTE_SIZE]; |
| 1235 tmp_row[x] = inv_palette[color]; | 1309 PrepareMapToPalette(palette, palette_size, palette_sorted, idx_map); |
| 1236 } | 1310 APPLY_PALETTE_FOR( |
| 1237 VP8LBundleColorMap(tmp_row, width, xbits, dst); | 1311 idx_map[SearchColorNoIdx(palette_sorted, pix, palette_size)]); |
| 1238 src += src_stride; | |
| 1239 dst += dst_stride; | |
| 1240 } | |
| 1241 } else { | |
| 1242 // Use 1 pixel cache for ARGB pixels. | |
| 1243 uint32_t last_pix; | |
| 1244 int last_idx; | |
| 1245 uint32_t sorted[MAX_PALETTE_SIZE]; | |
| 1246 int idx_map[MAX_PALETTE_SIZE]; | |
| 1247 PrepareMapToPalette(palette, palette_size, sorted, idx_map); | |
| 1248 last_pix = palette[0]; | |
| 1249 last_idx = 0; | |
| 1250 for (y = 0; y < height; ++y) { | |
| 1251 MapToPalette(sorted, palette_size, &last_pix, &last_idx, | |
| 1252 idx_map, src, tmp_row, width); | |
| 1253 VP8LBundleColorMap(tmp_row, width, xbits, dst); | |
| 1254 src += src_stride; | |
| 1255 dst += dst_stride; | |
| 1256 } | 1312 } |
| 1257 } | 1313 } |
| 1258 WebPSafeFree(tmp_row); | 1314 WebPSafeFree(tmp_row); |
| 1259 return VP8_ENC_OK; | 1315 return VP8_ENC_OK; |
| 1260 } | 1316 } |
| 1317 #undef APPLY_PALETTE_FOR |
| 1318 #undef PALETTE_INV_SIZE_BITS |
| 1319 #undef PALETTE_INV_SIZE |
| 1320 #undef APPLY_PALETTE_GREEDY_MAX |
| 1261 | 1321 |
| 1262 // Note: Expects "enc->palette_" to be set properly. | 1322 // Note: Expects "enc->palette_" to be set properly. |
| 1263 static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc, | 1323 static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc, |
| 1264 int in_place) { | 1324 int in_place) { |
| 1265 WebPEncodingError err = VP8_ENC_OK; | 1325 WebPEncodingError err = VP8_ENC_OK; |
| 1266 const WebPPicture* const pic = enc->pic_; | 1326 const WebPPicture* const pic = enc->pic_; |
| 1267 const int width = pic->width; | 1327 const int width = pic->width; |
| 1268 const int height = pic->height; | 1328 const int height = pic->height; |
| 1269 const uint32_t* const palette = enc->palette_; | 1329 const uint32_t* const palette = enc->palette_; |
| 1270 const uint32_t* src = in_place ? enc->argb_ : pic->argb; | 1330 const uint32_t* src = in_place ? enc->argb_ : pic->argb; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1283 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height); | 1343 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height); |
| 1284 if (err != VP8_ENC_OK) return err; | 1344 if (err != VP8_ENC_OK) return err; |
| 1285 | 1345 |
| 1286 err = ApplyPalette(src, src_stride, | 1346 err = ApplyPalette(src, src_stride, |
| 1287 enc->argb_, enc->current_width_, | 1347 enc->argb_, enc->current_width_, |
| 1288 palette, palette_size, width, height, xbits); | 1348 palette, palette_size, width, height, xbits); |
| 1289 return err; | 1349 return err; |
| 1290 } | 1350 } |
| 1291 | 1351 |
| 1292 // Save palette_[] to bitstream. | 1352 // Save palette_[] to bitstream. |
| 1293 static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, | 1353 static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort, |
| 1294 VP8LEncoder* const enc) { | 1354 VP8LEncoder* const enc) { |
| 1295 int i; | 1355 int i; |
| 1296 uint32_t tmp_palette[MAX_PALETTE_SIZE]; | 1356 uint32_t tmp_palette[MAX_PALETTE_SIZE]; |
| 1297 const int palette_size = enc->palette_size_; | 1357 const int palette_size = enc->palette_size_; |
| 1298 const uint32_t* const palette = enc->palette_; | 1358 const uint32_t* const palette = enc->palette_; |
| 1299 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); | 1359 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); |
| 1300 VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2); | 1360 VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2); |
| 1301 assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE); | 1361 assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE); |
| 1302 VP8LPutBits(bw, palette_size - 1, 8); | 1362 VP8LPutBits(bw, palette_size - 1, 8); |
| 1303 for (i = palette_size - 1; i >= 1; --i) { | 1363 for (i = palette_size - 1; i >= 1; --i) { |
| 1304 tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]); | 1364 tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]); |
| 1305 } | 1365 } |
| 1306 tmp_palette[0] = palette[0]; | 1366 tmp_palette[0] = palette[0]; |
| 1307 return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, enc->refs_, | 1367 return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, enc->refs_, |
| 1308 palette_size, 1, 20 /* quality */); | 1368 palette_size, 1, 20 /* quality */, low_effort); |
| 1309 } | 1369 } |
| 1310 | 1370 |
| 1311 #ifdef WEBP_EXPERIMENTAL_FEATURES | 1371 #ifdef WEBP_EXPERIMENTAL_FEATURES |
| 1312 | 1372 |
| 1313 static WebPEncodingError EncodeDeltaPalettePredictorImage( | 1373 static WebPEncodingError EncodeDeltaPalettePredictorImage( |
| 1314 VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality) { | 1374 VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality, |
| 1375 int low_effort) { |
| 1315 const WebPPicture* const pic = enc->pic_; | 1376 const WebPPicture* const pic = enc->pic_; |
| 1316 const int width = pic->width; | 1377 const int width = pic->width; |
| 1317 const int height = pic->height; | 1378 const int height = pic->height; |
| 1318 | 1379 |
| 1319 const int pred_bits = 5; | 1380 const int pred_bits = 5; |
| 1320 const int transform_width = VP8LSubSampleSize(width, pred_bits); | 1381 const int transform_width = VP8LSubSampleSize(width, pred_bits); |
| 1321 const int transform_height = VP8LSubSampleSize(height, pred_bits); | 1382 const int transform_height = VP8LSubSampleSize(height, pred_bits); |
| 1322 const int pred = 7; // default is Predictor7 (Top/Left Average) | 1383 const int pred = 7; // default is Predictor7 (Top/Left Average) |
| 1323 const int tiles_per_row = VP8LSubSampleSize(width, pred_bits); | 1384 const int tiles_per_row = VP8LSubSampleSize(width, pred_bits); |
| 1324 const int tiles_per_col = VP8LSubSampleSize(height, pred_bits); | 1385 const int tiles_per_col = VP8LSubSampleSize(height, pred_bits); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1335 predictors[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8); | 1396 predictors[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8); |
| 1336 } | 1397 } |
| 1337 } | 1398 } |
| 1338 | 1399 |
| 1339 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); | 1400 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); |
| 1340 VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); | 1401 VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); |
| 1341 VP8LPutBits(bw, pred_bits - 2, 3); | 1402 VP8LPutBits(bw, pred_bits - 2, 3); |
| 1342 err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_, | 1403 err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_, |
| 1343 (VP8LBackwardRefs*)enc->refs_, // cast const away | 1404 (VP8LBackwardRefs*)enc->refs_, // cast const away |
| 1344 transform_width, transform_height, | 1405 transform_width, transform_height, |
| 1345 quality); | 1406 quality, low_effort); |
| 1346 WebPSafeFree(predictors); | 1407 WebPSafeFree(predictors); |
| 1347 return err; | 1408 return err; |
| 1348 } | 1409 } |
| 1349 | 1410 |
| 1350 #endif // WEBP_EXPERIMENTAL_FEATURES | 1411 #endif // WEBP_EXPERIMENTAL_FEATURES |
| 1351 | 1412 |
| 1352 // ----------------------------------------------------------------------------- | 1413 // ----------------------------------------------------------------------------- |
| 1353 // VP8LEncoder | 1414 // VP8LEncoder |
| 1354 | 1415 |
| 1355 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, | 1416 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1386 WebPEncodingError err = VP8_ENC_OK; | 1447 WebPEncodingError err = VP8_ENC_OK; |
| 1387 const int quality = (int)config->quality; | 1448 const int quality = (int)config->quality; |
| 1388 const int low_effort = (config->method == 0); | 1449 const int low_effort = (config->method == 0); |
| 1389 const int width = picture->width; | 1450 const int width = picture->width; |
| 1390 const int height = picture->height; | 1451 const int height = picture->height; |
| 1391 VP8LEncoder* const enc = VP8LEncoderNew(config, picture); | 1452 VP8LEncoder* const enc = VP8LEncoderNew(config, picture); |
| 1392 const size_t byte_position = VP8LBitWriterNumBytes(bw); | 1453 const size_t byte_position = VP8LBitWriterNumBytes(bw); |
| 1393 int use_near_lossless = 0; | 1454 int use_near_lossless = 0; |
| 1394 int hdr_size = 0; | 1455 int hdr_size = 0; |
| 1395 int data_size = 0; | 1456 int data_size = 0; |
| 1396 int use_delta_palettization = 0; | 1457 int use_delta_palette = 0; |
| 1397 | 1458 |
| 1398 if (enc == NULL) { | 1459 if (enc == NULL) { |
| 1399 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 1460 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 1400 goto Error; | 1461 goto Error; |
| 1401 } | 1462 } |
| 1402 | 1463 |
| 1403 // --------------------------------------------------------------------------- | 1464 // --------------------------------------------------------------------------- |
| 1404 // Analyze image (entropy, num_palettes etc) | 1465 // Analyze image (entropy, num_palettes etc) |
| 1405 | 1466 |
| 1406 if (!AnalyzeAndInit(enc)) { | 1467 if (!AnalyzeAndInit(enc)) { |
| 1407 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 1468 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 1408 goto Error; | 1469 goto Error; |
| 1409 } | 1470 } |
| 1410 | 1471 |
| 1411 // Apply near-lossless preprocessing. | 1472 // Apply near-lossless preprocessing. |
| 1412 use_near_lossless = | 1473 use_near_lossless = |
| 1413 (config->near_lossless < 100) && !enc->use_palette_ && !enc->use_predict_; | 1474 (config->near_lossless < 100) && !enc->use_palette_ && !enc->use_predict_; |
| 1414 if (use_near_lossless) { | 1475 if (use_near_lossless) { |
| 1415 if (!VP8ApplyNearLossless(width, height, picture->argb, | 1476 if (!VP8ApplyNearLossless(width, height, picture->argb, |
| 1416 config->near_lossless)) { | 1477 config->near_lossless)) { |
| 1417 err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 1478 err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 1418 goto Error; | 1479 goto Error; |
| 1419 } | 1480 } |
| 1420 } | 1481 } |
| 1421 | 1482 |
| 1422 #ifdef WEBP_EXPERIMENTAL_FEATURES | 1483 #ifdef WEBP_EXPERIMENTAL_FEATURES |
| 1423 if (config->delta_palettization) { | 1484 if (config->use_delta_palette) { |
| 1424 enc->use_predict_ = 1; | 1485 enc->use_predict_ = 1; |
| 1425 enc->use_cross_color_ = 0; | 1486 enc->use_cross_color_ = 0; |
| 1426 enc->use_subtract_green_ = 0; | 1487 enc->use_subtract_green_ = 0; |
| 1427 enc->use_palette_ = 1; | 1488 enc->use_palette_ = 1; |
| 1428 err = MakeInputImageCopy(enc); | 1489 err = MakeInputImageCopy(enc); |
| 1429 if (err != VP8_ENC_OK) goto Error; | 1490 if (err != VP8_ENC_OK) goto Error; |
| 1430 err = WebPSearchOptimalDeltaPalette(enc); | 1491 err = WebPSearchOptimalDeltaPalette(enc); |
| 1431 if (err != VP8_ENC_OK) goto Error; | 1492 if (err != VP8_ENC_OK) goto Error; |
| 1432 if (enc->use_palette_) { | 1493 if (enc->use_palette_) { |
| 1433 err = AllocateTransformBuffer(enc, width, height); | 1494 err = AllocateTransformBuffer(enc, width, height); |
| 1434 if (err != VP8_ENC_OK) goto Error; | 1495 if (err != VP8_ENC_OK) goto Error; |
| 1435 err = EncodeDeltaPalettePredictorImage(bw, enc, quality); | 1496 err = EncodeDeltaPalettePredictorImage(bw, enc, quality, low_effort); |
| 1436 if (err != VP8_ENC_OK) goto Error; | 1497 if (err != VP8_ENC_OK) goto Error; |
| 1437 use_delta_palettization = 1; | 1498 use_delta_palette = 1; |
| 1438 } | 1499 } |
| 1439 } | 1500 } |
| 1440 #endif // WEBP_EXPERIMENTAL_FEATURES | 1501 #endif // WEBP_EXPERIMENTAL_FEATURES |
| 1441 | 1502 |
| 1442 // Encode palette | 1503 // Encode palette |
| 1443 if (enc->use_palette_) { | 1504 if (enc->use_palette_) { |
| 1444 err = EncodePalette(bw, enc); | 1505 err = EncodePalette(bw, low_effort, enc); |
| 1445 if (err != VP8_ENC_OK) goto Error; | 1506 if (err != VP8_ENC_OK) goto Error; |
| 1446 err = MapImageFromPalette(enc, use_delta_palettization); | 1507 err = MapImageFromPalette(enc, use_delta_palette); |
| 1447 if (err != VP8_ENC_OK) goto Error; | 1508 if (err != VP8_ENC_OK) goto Error; |
| 1509 // If using a color cache, do not have it bigger than the number of colors. |
| 1510 if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { |
| 1511 enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1; |
| 1512 } |
| 1448 } | 1513 } |
| 1449 if (!use_delta_palettization) { | 1514 if (!use_delta_palette) { |
| 1450 // In case image is not packed. | 1515 // In case image is not packed. |
| 1451 if (enc->argb_ == NULL) { | 1516 if (enc->argb_ == NULL) { |
| 1452 err = MakeInputImageCopy(enc); | 1517 err = MakeInputImageCopy(enc); |
| 1453 if (err != VP8_ENC_OK) goto Error; | 1518 if (err != VP8_ENC_OK) goto Error; |
| 1454 } | 1519 } |
| 1455 | 1520 |
| 1456 // ------------------------------------------------------------------------- | 1521 // ------------------------------------------------------------------------- |
| 1457 // Apply transforms and write transform data. | 1522 // Apply transforms and write transform data. |
| 1458 | 1523 |
| 1459 if (enc->use_subtract_green_) { | 1524 if (enc->use_subtract_green_) { |
| 1460 ApplySubtractGreen(enc, enc->current_width_, height, bw); | 1525 ApplySubtractGreen(enc, enc->current_width_, height, bw); |
| 1461 } | 1526 } |
| 1462 | 1527 |
| 1463 if (enc->use_predict_) { | 1528 if (enc->use_predict_) { |
| 1464 err = ApplyPredictFilter(enc, enc->current_width_, height, quality, | 1529 err = ApplyPredictFilter(enc, enc->current_width_, height, quality, |
| 1465 low_effort, enc->use_subtract_green_, bw); | 1530 low_effort, enc->use_subtract_green_, bw); |
| 1466 if (err != VP8_ENC_OK) goto Error; | 1531 if (err != VP8_ENC_OK) goto Error; |
| 1467 } | 1532 } |
| 1468 | 1533 |
| 1469 if (enc->use_cross_color_) { | 1534 if (enc->use_cross_color_) { |
| 1470 err = ApplyCrossColorFilter(enc, enc->current_width_, | 1535 err = ApplyCrossColorFilter(enc, enc->current_width_, |
| 1471 height, quality, bw); | 1536 height, quality, low_effort, bw); |
| 1472 if (err != VP8_ENC_OK) goto Error; | 1537 if (err != VP8_ENC_OK) goto Error; |
| 1473 } | 1538 } |
| 1474 } | 1539 } |
| 1475 | 1540 |
| 1476 VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms. | 1541 VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms. |
| 1477 | 1542 |
| 1478 // --------------------------------------------------------------------------- | 1543 // --------------------------------------------------------------------------- |
| 1479 // Encode and write the transformed image. | 1544 // Encode and write the transformed image. |
| 1480 err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_, | 1545 err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_, |
| 1481 enc->current_width_, height, quality, low_effort, | 1546 enc->current_width_, height, quality, low_effort, |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1593 if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY; | 1658 if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY; |
| 1594 VP8LBitWriterWipeOut(&bw); | 1659 VP8LBitWriterWipeOut(&bw); |
| 1595 if (err != VP8_ENC_OK) { | 1660 if (err != VP8_ENC_OK) { |
| 1596 WebPEncodingSetError(picture, err); | 1661 WebPEncodingSetError(picture, err); |
| 1597 return 0; | 1662 return 0; |
| 1598 } | 1663 } |
| 1599 return 1; | 1664 return 1; |
| 1600 } | 1665 } |
| 1601 | 1666 |
| 1602 //------------------------------------------------------------------------------ | 1667 //------------------------------------------------------------------------------ |
| OLD | NEW |