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

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

Issue 2651883004: libwebp-0.6.0-rc1 (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/libwebp/enc/vp8l.c ('k') | third_party/libwebp/enc/vp8li.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 Google Inc. All Rights Reserved.
2 // 2 //
3 // 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
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
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
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
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
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
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
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
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
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
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
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
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 //------------------------------------------------------------------------------
OLDNEW
« no previous file with comments | « third_party/libwebp/enc/vp8l.c ('k') | third_party/libwebp/enc/vp8li.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698