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

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

Issue 2149863002: libwebp: update to v0.5.1 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 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/vp8enci.h ('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.
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 119
120 // ----------------------------------------------------------------------------- 120 // -----------------------------------------------------------------------------
121 // Palette 121 // Palette
122 122
123 // If number of colors in the image is less than or equal to MAX_PALETTE_SIZE, 123 // If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
124 // creates a palette and returns true, else returns false. 124 // creates a palette and returns true, else returns false.
125 static int AnalyzeAndCreatePalette(const WebPPicture* const pic, 125 static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
126 int low_effort, 126 int low_effort,
127 uint32_t palette[MAX_PALETTE_SIZE], 127 uint32_t palette[MAX_PALETTE_SIZE],
128 int* const palette_size) { 128 int* const palette_size) {
129 int i, x, y, key; 129 const int num_colors = WebPGetColorPalette(pic, palette);
130 int num_colors = 0; 130 if (num_colors > MAX_PALETTE_SIZE) return 0;
131 uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
132 uint32_t colors[MAX_PALETTE_SIZE * 4];
133 static const uint32_t kHashMul = 0x1e35a7bd;
134 const uint32_t* argb = pic->argb;
135 const int width = pic->width;
136 const int height = pic->height;
137 uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
138
139 for (y = 0; y < height; ++y) {
140 for (x = 0; x < width; ++x) {
141 if (argb[x] == last_pix) {
142 continue;
143 }
144 last_pix = argb[x];
145 key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT;
146 while (1) {
147 if (!in_use[key]) {
148 colors[key] = last_pix;
149 in_use[key] = 1;
150 ++num_colors;
151 if (num_colors > MAX_PALETTE_SIZE) {
152 return 0;
153 }
154 break;
155 } else if (colors[key] == last_pix) {
156 // The color is already there.
157 break;
158 } else {
159 // Some other color sits there.
160 // Do linear conflict resolution.
161 ++key;
162 key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer.
163 }
164 }
165 }
166 argb += pic->argb_stride;
167 }
168
169 // TODO(skal): could we reuse in_use[] to speed up EncodePalette()?
170 num_colors = 0;
171 for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
172 if (in_use[i]) {
173 palette[num_colors] = colors[i];
174 ++num_colors;
175 }
176 }
177 *palette_size = num_colors; 131 *palette_size = num_colors;
178 qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort); 132 qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
179 if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) { 133 if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {
180 GreedyMinimizeDeltas(palette, num_colors); 134 GreedyMinimizeDeltas(palette, num_colors);
181 } 135 }
182 return 1; 136 return 1;
183 } 137 }
184 138
185 // These five modes are evaluated and their respective entropy is computed. 139 // These five modes are evaluated and their respective entropy is computed.
186 typedef enum { 140 typedef enum {
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 const uint32_t* const blue_histo = 283 const uint32_t* const blue_histo =
330 &histo[256 * kHistoPairs[*min_entropy_ix][1]]; 284 &histo[256 * kHistoPairs[*min_entropy_ix][1]];
331 for (i = 1; i < 256; ++i) { 285 for (i = 1; i < 256; ++i) {
332 if ((red_histo[i] | blue_histo[i]) != 0) { 286 if ((red_histo[i] | blue_histo[i]) != 0) {
333 *red_and_blue_always_zero = 0; 287 *red_and_blue_always_zero = 0;
334 break; 288 break;
335 } 289 }
336 } 290 }
337 } 291 }
338 } 292 }
339 free(histo); 293 WebPSafeFree(histo);
340 return 1; 294 return 1;
341 } else { 295 } else {
342 return 0; 296 return 0;
343 } 297 }
344 } 298 }
345 299
346 static int GetHistoBits(int method, int use_palette, int width, int height) { 300 static int GetHistoBits(int method, int use_palette, int width, int height) {
347 // Make tile size a function of encoding method (Range: 0 to 6). 301 // Make tile size a function of encoding method (Range: 0 to 6).
348 int histo_bits = (use_palette ? 9 : 7) - method; 302 int histo_bits = (use_palette ? 9 : 7) - method;
349 while (1) { 303 while (1) {
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
754 int cache_bits = 0; 708 int cache_bits = 0;
755 VP8LHistogramSet* histogram_image = NULL; 709 VP8LHistogramSet* histogram_image = NULL;
756 HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( 710 HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
757 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); 711 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
758 if (huff_tree == NULL) { 712 if (huff_tree == NULL) {
759 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 713 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
760 goto Error; 714 goto Error;
761 } 715 }
762 716
763 // Calculate backward references from ARGB image. 717 // Calculate backward references from ARGB image.
718 if (VP8LHashChainFill(hash_chain, quality, argb, width, height) == 0) {
719 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
720 goto Error;
721 }
764 refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, &cache_bits, 722 refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, &cache_bits,
765 hash_chain, refs_array); 723 hash_chain, refs_array);
766 if (refs == NULL) { 724 if (refs == NULL) {
767 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 725 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
768 goto Error; 726 goto Error;
769 } 727 }
770 histogram_image = VP8LAllocateHistogramSet(1, cache_bits); 728 histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
771 if (histogram_image == NULL) { 729 if (histogram_image == NULL) {
772 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 730 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
773 goto Error; 731 goto Error;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
817 VP8LFreeHistogramSet(histogram_image); 775 VP8LFreeHistogramSet(histogram_image);
818 WebPSafeFree(huffman_codes[0].codes); 776 WebPSafeFree(huffman_codes[0].codes);
819 return err; 777 return err;
820 } 778 }
821 779
822 static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw, 780 static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw,
823 const uint32_t* const argb, 781 const uint32_t* const argb,
824 VP8LHashChain* const hash_chain, 782 VP8LHashChain* const hash_chain,
825 VP8LBackwardRefs refs_array[2], 783 VP8LBackwardRefs refs_array[2],
826 int width, int height, int quality, 784 int width, int height, int quality,
827 int low_effort, int* cache_bits, 785 int low_effort,
786 int use_cache, int* cache_bits,
828 int histogram_bits, 787 int histogram_bits,
829 size_t init_byte_position, 788 size_t init_byte_position,
830 int* const hdr_size, 789 int* const hdr_size,
831 int* const data_size) { 790 int* const data_size) {
832 WebPEncodingError err = VP8_ENC_OK; 791 WebPEncodingError err = VP8_ENC_OK;
833 const uint32_t histogram_image_xysize = 792 const uint32_t histogram_image_xysize =
834 VP8LSubSampleSize(width, histogram_bits) * 793 VP8LSubSampleSize(width, histogram_bits) *
835 VP8LSubSampleSize(height, histogram_bits); 794 VP8LSubSampleSize(height, histogram_bits);
836 VP8LHistogramSet* histogram_image = NULL; 795 VP8LHistogramSet* histogram_image = NULL;
837 VP8LHistogramSet* tmp_histos = NULL; 796 VP8LHistogramSet* tmp_histos = NULL;
(...skipping 11 matching lines...) Expand all
849 assert(histogram_bits <= MAX_HUFFMAN_BITS); 808 assert(histogram_bits <= MAX_HUFFMAN_BITS);
850 assert(hdr_size != NULL); 809 assert(hdr_size != NULL);
851 assert(data_size != NULL); 810 assert(data_size != NULL);
852 811
853 VP8LBackwardRefsInit(&refs, refs_array[0].block_size_); 812 VP8LBackwardRefsInit(&refs, refs_array[0].block_size_);
854 if (histogram_symbols == NULL) { 813 if (histogram_symbols == NULL) {
855 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 814 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
856 goto Error; 815 goto Error;
857 } 816 }
858 817
859 *cache_bits = MAX_COLOR_CACHE_BITS; 818 *cache_bits = use_cache ? MAX_COLOR_CACHE_BITS : 0;
860 // 'best_refs' is the reference to the best backward refs and points to one 819 // 'best_refs' is the reference to the best backward refs and points to one
861 // of refs_array[0] or refs_array[1]. 820 // of refs_array[0] or refs_array[1].
862 // Calculate backward references from ARGB image. 821 // Calculate backward references from ARGB image.
822 if (VP8LHashChainFill(hash_chain, quality, argb, width, height) == 0) {
823 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
824 goto Error;
825 }
863 best_refs = VP8LGetBackwardReferences(width, height, argb, quality, 826 best_refs = VP8LGetBackwardReferences(width, height, argb, quality,
864 low_effort, cache_bits, hash_chain, 827 low_effort, cache_bits, hash_chain,
865 refs_array); 828 refs_array);
866 if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) { 829 if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) {
867 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 830 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
868 goto Error; 831 goto Error;
869 } 832 }
870 histogram_image = 833 histogram_image =
871 VP8LAllocateHistogramSet(histogram_image_xysize, *cache_bits); 834 VP8LAllocateHistogramSet(histogram_image_xysize, *cache_bits);
872 tmp_histos = VP8LAllocateHistogramSet(2, *cache_bits); 835 tmp_histos = VP8LAllocateHistogramSet(2, *cache_bits);
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
1000 static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height, 963 static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height,
1001 VP8LBitWriter* const bw) { 964 VP8LBitWriter* const bw) {
1002 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); 965 VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1003 VP8LPutBits(bw, SUBTRACT_GREEN, 2); 966 VP8LPutBits(bw, SUBTRACT_GREEN, 2);
1004 VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height); 967 VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
1005 } 968 }
1006 969
1007 static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc, 970 static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
1008 int width, int height, 971 int width, int height,
1009 int quality, int low_effort, 972 int quality, int low_effort,
973 int used_subtract_green,
1010 VP8LBitWriter* const bw) { 974 VP8LBitWriter* const bw) {
1011 const int pred_bits = enc->transform_bits_; 975 const int pred_bits = enc->transform_bits_;
1012 const int transform_width = VP8LSubSampleSize(width, pred_bits); 976 const int transform_width = VP8LSubSampleSize(width, pred_bits);
1013 const int transform_height = VP8LSubSampleSize(height, pred_bits); 977 const int transform_height = VP8LSubSampleSize(height, pred_bits);
978 // we disable near-lossless quantization if palette is used.
979 const int near_lossless_strength = enc->use_palette_ ? 100
980 : enc->config_->near_lossless;
1014 981
1015 VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_, 982 VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
1016 enc->argb_scratch_, enc->transform_data_, 983 enc->argb_scratch_, enc->transform_data_,
1017 enc->config_->exact); 984 near_lossless_strength, enc->config_->exact,
985 used_subtract_green);
1018 VP8LPutBits(bw, TRANSFORM_PRESENT, 1); 986 VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1019 VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); 987 VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
1020 assert(pred_bits >= 2); 988 assert(pred_bits >= 2);
1021 VP8LPutBits(bw, pred_bits - 2, 3); 989 VP8LPutBits(bw, pred_bits - 2, 3);
1022 return EncodeImageNoHuffman(bw, enc->transform_data_, 990 return EncodeImageNoHuffman(bw, enc->transform_data_,
1023 (VP8LHashChain*)&enc->hash_chain_, 991 (VP8LHashChain*)&enc->hash_chain_,
1024 (VP8LBackwardRefs*)enc->refs_, // cast const away 992 (VP8LBackwardRefs*)enc->refs_, // cast const away
1025 transform_width, transform_height, 993 transform_width, transform_height,
1026 quality); 994 quality);
1027 } 995 }
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
1107 } 1075 }
1108 *coded_size = CHUNK_HEADER_SIZE + riff_size; 1076 *coded_size = CHUNK_HEADER_SIZE + riff_size;
1109 return VP8_ENC_OK; 1077 return VP8_ENC_OK;
1110 1078
1111 Error: 1079 Error:
1112 return err; 1080 return err;
1113 } 1081 }
1114 1082
1115 // ----------------------------------------------------------------------------- 1083 // -----------------------------------------------------------------------------
1116 1084
1085 static void ClearTransformBuffer(VP8LEncoder* const enc) {
1086 WebPSafeFree(enc->transform_mem_);
1087 enc->transform_mem_ = NULL;
1088 enc->transform_mem_size_ = 0;
1089 }
1090
1117 // Allocates the memory for argb (W x H) buffer, 2 rows of context for 1091 // Allocates the memory for argb (W x H) buffer, 2 rows of context for
1118 // prediction and transform data. 1092 // prediction and transform data.
1119 // Flags influencing the memory allocated: 1093 // Flags influencing the memory allocated:
1120 // enc->transform_bits_ 1094 // enc->transform_bits_
1121 // enc->use_predict_, enc->use_cross_color_ 1095 // enc->use_predict_, enc->use_cross_color_
1122 static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, 1096 static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
1123 int width, int height) { 1097 int width, int height) {
1124 WebPEncodingError err = VP8_ENC_OK; 1098 WebPEncodingError err = VP8_ENC_OK;
1125 if (enc->argb_ == NULL) { 1099 const uint64_t image_size = width * height;
1126 const int tile_size = 1 << enc->transform_bits_; 1100 // VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
1127 const uint64_t image_size = width * height; 1101 // pixel in each, plus 2 regular scanlines of bytes.
1128 // Ensure enough size for tiles, as well as for two scanlines and two 1102 // TODO(skal): Clean up by using arithmetic in bytes instead of words.
1129 // extra pixels for CopyImageWithPrediction. 1103 const uint64_t argb_scratch_size =
1130 const uint64_t argb_scratch_size = 1104 enc->use_predict_
1131 enc->use_predict_ ? tile_size * width + width + 2 : 0; 1105 ? (width + 1) * 2 +
1132 const int transform_data_size = 1106 (width * 2 + sizeof(uint32_t) - 1) / sizeof(uint32_t)
1133 (enc->use_predict_ || enc->use_cross_color_) 1107 : 0;
1134 ? VP8LSubSampleSize(width, enc->transform_bits_) * 1108 const uint64_t transform_data_size =
1135 VP8LSubSampleSize(height, enc->transform_bits_) 1109 (enc->use_predict_ || enc->use_cross_color_)
1136 : 0; 1110 ? VP8LSubSampleSize(width, enc->transform_bits_) *
1137 const uint64_t total_size = 1111 VP8LSubSampleSize(height, enc->transform_bits_)
1138 image_size + WEBP_ALIGN_CST + 1112 : 0;
1139 argb_scratch_size + WEBP_ALIGN_CST + 1113 const uint64_t max_alignment_in_words =
1140 (uint64_t)transform_data_size; 1114 (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t);
1141 uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem)); 1115 const uint64_t mem_size =
1116 image_size + max_alignment_in_words +
1117 argb_scratch_size + max_alignment_in_words +
1118 transform_data_size;
1119 uint32_t* mem = enc->transform_mem_;
1120 if (mem == NULL || mem_size > enc->transform_mem_size_) {
1121 ClearTransformBuffer(enc);
1122 mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem));
1142 if (mem == NULL) { 1123 if (mem == NULL) {
1143 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1124 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1144 goto Error; 1125 goto Error;
1145 } 1126 }
1146 enc->argb_ = mem; 1127 enc->transform_mem_ = mem;
1147 mem = (uint32_t*)WEBP_ALIGN(mem + image_size); 1128 enc->transform_mem_size_ = (size_t)mem_size;
1148 enc->argb_scratch_ = mem;
1149 mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size);
1150 enc->transform_data_ = mem;
1151 enc->current_width_ = width;
1152 } 1129 }
1130 enc->argb_ = mem;
1131 mem = (uint32_t*)WEBP_ALIGN(mem + image_size);
1132 enc->argb_scratch_ = mem;
1133 mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size);
1134 enc->transform_data_ = mem;
1135
1136 enc->current_width_ = width;
1153 Error: 1137 Error:
1154 return err; 1138 return err;
1155 } 1139 }
1156 1140
1157 static void ClearTransformBuffer(VP8LEncoder* const enc) {
1158 WebPSafeFree(enc->argb_);
1159 enc->argb_ = NULL;
1160 }
1161
1162 static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) { 1141 static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
1163 WebPEncodingError err = VP8_ENC_OK; 1142 WebPEncodingError err = VP8_ENC_OK;
1164 const WebPPicture* const picture = enc->pic_; 1143 const WebPPicture* const picture = enc->pic_;
1165 const int width = picture->width; 1144 const int width = picture->width;
1166 const int height = picture->height; 1145 const int height = picture->height;
1167 int y; 1146 int y;
1168 err = AllocateTransformBuffer(enc, width, height); 1147 err = AllocateTransformBuffer(enc, width, height);
1169 if (err != VP8_ENC_OK) return err; 1148 if (err != VP8_ENC_OK) return err;
1170 for (y = 0; y < height; ++y) { 1149 for (y = 0; y < height; ++y) {
1171 memcpy(enc->argb_ + y * width, 1150 memcpy(enc->argb_ + y * width,
1172 picture->argb + y * picture->argb_stride, 1151 picture->argb + y * picture->argb_stride,
1173 width * sizeof(*enc->argb_)); 1152 width * sizeof(*enc->argb_));
1174 } 1153 }
1175 assert(enc->current_width_ == width); 1154 assert(enc->current_width_ == width);
1176 return VP8_ENC_OK; 1155 return VP8_ENC_OK;
1177 } 1156 }
1178 1157
1179 // ----------------------------------------------------------------------------- 1158 // -----------------------------------------------------------------------------
1180 1159
1181 static void MapToPalette(const uint32_t palette[], int num_colors, 1160 static int SearchColor(const uint32_t sorted[], uint32_t color, int hi) {
1161 int low = 0;
1162 if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
1163 while (1) {
1164 const int mid = (low + hi) >> 1;
1165 if (sorted[mid] == color) {
1166 return mid;
1167 } else if (sorted[mid] < color) {
1168 low = mid;
1169 } else {
1170 hi = mid;
1171 }
1172 }
1173 }
1174
1175 // Sort palette in increasing order and prepare an inverse mapping array.
1176 static void PrepareMapToPalette(const uint32_t palette[], int num_colors,
1177 uint32_t sorted[], int idx_map[]) {
1178 int i;
1179 memcpy(sorted, palette, num_colors * sizeof(*sorted));
1180 qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
1181 for (i = 0; i < num_colors; ++i) {
1182 idx_map[SearchColor(sorted, palette[i], num_colors)] = i;
1183 }
1184 }
1185
1186 static void MapToPalette(const uint32_t sorted_palette[], int num_colors,
1182 uint32_t* const last_pix, int* const last_idx, 1187 uint32_t* const last_pix, int* const last_idx,
1188 const int idx_map[],
1183 const uint32_t* src, uint8_t* dst, int width) { 1189 const uint32_t* src, uint8_t* dst, int width) {
1184 int x; 1190 int x;
1185 int prev_idx = *last_idx; 1191 int prev_idx = *last_idx;
1186 uint32_t prev_pix = *last_pix; 1192 uint32_t prev_pix = *last_pix;
1187 for (x = 0; x < width; ++x) { 1193 for (x = 0; x < width; ++x) {
1188 const uint32_t pix = src[x]; 1194 const uint32_t pix = src[x];
1189 if (pix != prev_pix) { 1195 if (pix != prev_pix) {
1190 int i; 1196 prev_idx = idx_map[SearchColor(sorted_palette, pix, num_colors)];
1191 for (i = 0; i < num_colors; ++i) { 1197 prev_pix = pix;
1192 if (pix == palette[i]) {
1193 prev_idx = i;
1194 prev_pix = pix;
1195 break;
1196 }
1197 }
1198 } 1198 }
1199 dst[x] = prev_idx; 1199 dst[x] = prev_idx;
1200 } 1200 }
1201 *last_idx = prev_idx; 1201 *last_idx = prev_idx;
1202 *last_pix = prev_pix; 1202 *last_pix = prev_pix;
1203 } 1203 }
1204 1204
1205 // Remap argb values in src[] to packed palettes entries in dst[] 1205 // Remap argb values in src[] to packed palettes entries in dst[]
1206 // using 'row' as a temporary buffer of size 'width'. 1206 // using 'row' as a temporary buffer of size 'width'.
1207 // We assume that all src[] values have a corresponding entry in the palette. 1207 // We assume that all src[] values have a corresponding entry in the palette.
(...skipping 26 matching lines...) Expand all
1234 for (x = 0; x < width; ++x) { 1234 for (x = 0; x < width; ++x) {
1235 const int color = (src[x] >> 8) & 0xff; 1235 const int color = (src[x] >> 8) & 0xff;
1236 tmp_row[x] = inv_palette[color]; 1236 tmp_row[x] = inv_palette[color];
1237 } 1237 }
1238 VP8LBundleColorMap(tmp_row, width, xbits, dst); 1238 VP8LBundleColorMap(tmp_row, width, xbits, dst);
1239 src += src_stride; 1239 src += src_stride;
1240 dst += dst_stride; 1240 dst += dst_stride;
1241 } 1241 }
1242 } else { 1242 } else {
1243 // Use 1 pixel cache for ARGB pixels. 1243 // Use 1 pixel cache for ARGB pixels.
1244 uint32_t last_pix = palette[0]; 1244 uint32_t last_pix;
1245 int last_idx = 0; 1245 int last_idx;
1246 uint32_t sorted[MAX_PALETTE_SIZE];
1247 int idx_map[MAX_PALETTE_SIZE];
1248 PrepareMapToPalette(palette, palette_size, sorted, idx_map);
1249 last_pix = palette[0];
1250 last_idx = 0;
1246 for (y = 0; y < height; ++y) { 1251 for (y = 0; y < height; ++y) {
1247 MapToPalette(palette, palette_size, &last_pix, &last_idx, 1252 MapToPalette(sorted, palette_size, &last_pix, &last_idx,
1248 src, tmp_row, width); 1253 idx_map, src, tmp_row, width);
1249 VP8LBundleColorMap(tmp_row, width, xbits, dst); 1254 VP8LBundleColorMap(tmp_row, width, xbits, dst);
1250 src += src_stride; 1255 src += src_stride;
1251 dst += dst_stride; 1256 dst += dst_stride;
1252 } 1257 }
1253 } 1258 }
1254 WebPSafeFree(tmp_row); 1259 WebPSafeFree(tmp_row);
1255 return VP8_ENC_OK; 1260 return VP8_ENC_OK;
1256 } 1261 }
1257 1262
1258 // Note: Expects "enc->palette_" to be set properly. 1263 // Note: Expects "enc->palette_" to be set properly.
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
1371 ClearTransformBuffer(enc); 1376 ClearTransformBuffer(enc);
1372 WebPSafeFree(enc); 1377 WebPSafeFree(enc);
1373 } 1378 }
1374 } 1379 }
1375 1380
1376 // ----------------------------------------------------------------------------- 1381 // -----------------------------------------------------------------------------
1377 // Main call 1382 // Main call
1378 1383
1379 WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, 1384 WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
1380 const WebPPicture* const picture, 1385 const WebPPicture* const picture,
1381 VP8LBitWriter* const bw) { 1386 VP8LBitWriter* const bw, int use_cache) {
1382 WebPEncodingError err = VP8_ENC_OK; 1387 WebPEncodingError err = VP8_ENC_OK;
1383 const int quality = (int)config->quality; 1388 const int quality = (int)config->quality;
1384 const int low_effort = (config->method == 0); 1389 const int low_effort = (config->method == 0);
1385 const int width = picture->width; 1390 const int width = picture->width;
1386 const int height = picture->height; 1391 const int height = picture->height;
1387 VP8LEncoder* const enc = VP8LEncoderNew(config, picture); 1392 VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
1388 const size_t byte_position = VP8LBitWriterNumBytes(bw); 1393 const size_t byte_position = VP8LBitWriterNumBytes(bw);
1389 int use_near_lossless = 0; 1394 int use_near_lossless = 0;
1390 int hdr_size = 0; 1395 int hdr_size = 0;
1391 int data_size = 0; 1396 int data_size = 0;
1392 int use_delta_palettization = 0; 1397 int use_delta_palettization = 0;
1393 1398
1394 if (enc == NULL) { 1399 if (enc == NULL) {
1395 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1400 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1396 goto Error; 1401 goto Error;
1397 } 1402 }
1398 1403
1399 // --------------------------------------------------------------------------- 1404 // ---------------------------------------------------------------------------
1400 // Analyze image (entropy, num_palettes etc) 1405 // Analyze image (entropy, num_palettes etc)
1401 1406
1402 if (!AnalyzeAndInit(enc)) { 1407 if (!AnalyzeAndInit(enc)) {
1403 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1408 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1404 goto Error; 1409 goto Error;
1405 } 1410 }
1406 1411
1407 // Apply near-lossless preprocessing. 1412 // Apply near-lossless preprocessing.
1408 use_near_lossless = !enc->use_palette_ && (config->near_lossless < 100); 1413 use_near_lossless =
1414 (config->near_lossless < 100) && !enc->use_palette_ && !enc->use_predict_;
1409 if (use_near_lossless) { 1415 if (use_near_lossless) {
1410 if (!VP8ApplyNearLossless(width, height, picture->argb, 1416 if (!VP8ApplyNearLossless(width, height, picture->argb,
1411 config->near_lossless)) { 1417 config->near_lossless)) {
1412 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1418 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1413 goto Error; 1419 goto Error;
1414 } 1420 }
1415 } 1421 }
1416 1422
1417 #ifdef WEBP_EXPERIMENTAL_FEATURES 1423 #ifdef WEBP_EXPERIMENTAL_FEATURES
1418 if (config->delta_palettization) { 1424 if (config->delta_palettization) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1450 1456
1451 // ------------------------------------------------------------------------- 1457 // -------------------------------------------------------------------------
1452 // Apply transforms and write transform data. 1458 // Apply transforms and write transform data.
1453 1459
1454 if (enc->use_subtract_green_) { 1460 if (enc->use_subtract_green_) {
1455 ApplySubtractGreen(enc, enc->current_width_, height, bw); 1461 ApplySubtractGreen(enc, enc->current_width_, height, bw);
1456 } 1462 }
1457 1463
1458 if (enc->use_predict_) { 1464 if (enc->use_predict_) {
1459 err = ApplyPredictFilter(enc, enc->current_width_, height, quality, 1465 err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
1460 low_effort, bw); 1466 low_effort, enc->use_subtract_green_, bw);
1461 if (err != VP8_ENC_OK) goto Error; 1467 if (err != VP8_ENC_OK) goto Error;
1462 } 1468 }
1463 1469
1464 if (enc->use_cross_color_) { 1470 if (enc->use_cross_color_) {
1465 err = ApplyCrossColorFilter(enc, enc->current_width_, 1471 err = ApplyCrossColorFilter(enc, enc->current_width_,
1466 height, quality, bw); 1472 height, quality, bw);
1467 if (err != VP8_ENC_OK) goto Error; 1473 if (err != VP8_ENC_OK) goto Error;
1468 } 1474 }
1469 } 1475 }
1470 1476
1471 VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms. 1477 VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms.
1472 1478
1473 // --------------------------------------------------------------------------- 1479 // ---------------------------------------------------------------------------
1474 // Encode and write the transformed image. 1480 // Encode and write the transformed image.
1475 err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_, 1481 err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
1476 enc->current_width_, height, quality, low_effort, 1482 enc->current_width_, height, quality, low_effort,
1477 &enc->cache_bits_, enc->histo_bits_, byte_position, 1483 use_cache, &enc->cache_bits_, enc->histo_bits_,
1478 &hdr_size, &data_size); 1484 byte_position, &hdr_size, &data_size);
1479 if (err != VP8_ENC_OK) goto Error; 1485 if (err != VP8_ENC_OK) goto Error;
1480 1486
1481 if (picture->stats != NULL) { 1487 if (picture->stats != NULL) {
1482 WebPAuxStats* const stats = picture->stats; 1488 WebPAuxStats* const stats = picture->stats;
1483 stats->lossless_features = 0; 1489 stats->lossless_features = 0;
1484 if (enc->use_predict_) stats->lossless_features |= 1; 1490 if (enc->use_predict_) stats->lossless_features |= 1;
1485 if (enc->use_cross_color_) stats->lossless_features |= 2; 1491 if (enc->use_cross_color_) stats->lossless_features |= 2;
1486 if (enc->use_subtract_green_) stats->lossless_features |= 4; 1492 if (enc->use_subtract_green_) stats->lossless_features |= 4;
1487 if (enc->use_palette_) stats->lossless_features |= 8; 1493 if (enc->use_palette_) stats->lossless_features |= 8;
1488 stats->histogram_bits = enc->histo_bits_; 1494 stats->histogram_bits = enc->histo_bits_;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1553 has_alpha = WebPPictureHasTransparency(picture); 1559 has_alpha = WebPPictureHasTransparency(picture);
1554 // Write the non-trivial Alpha flag and lossless version. 1560 // Write the non-trivial Alpha flag and lossless version.
1555 if (!WriteRealAlphaAndVersion(&bw, has_alpha)) { 1561 if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
1556 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1562 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1557 goto Error; 1563 goto Error;
1558 } 1564 }
1559 1565
1560 if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort; 1566 if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort;
1561 1567
1562 // Encode main image stream. 1568 // Encode main image stream.
1563 err = VP8LEncodeStream(config, picture, &bw); 1569 err = VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/);
1564 if (err != VP8_ENC_OK) goto Error; 1570 if (err != VP8_ENC_OK) goto Error;
1565 1571
1566 // TODO(skal): have a fine-grained progress report in VP8LEncodeStream(). 1572 // TODO(skal): have a fine-grained progress report in VP8LEncodeStream().
1567 if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort; 1573 if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort;
1568 1574
1569 // Finish the RIFF chunk. 1575 // Finish the RIFF chunk.
1570 err = WriteImage(picture, &bw, &coded_size); 1576 err = WriteImage(picture, &bw, &coded_size);
1571 if (err != VP8_ENC_OK) goto Error; 1577 if (err != VP8_ENC_OK) goto Error;
1572 1578
1573 if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort; 1579 if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
(...skipping 14 matching lines...) Expand all
1588 if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1594 if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1589 VP8LBitWriterWipeOut(&bw); 1595 VP8LBitWriterWipeOut(&bw);
1590 if (err != VP8_ENC_OK) { 1596 if (err != VP8_ENC_OK) {
1591 WebPEncodingSetError(picture, err); 1597 WebPEncodingSetError(picture, err);
1592 return 0; 1598 return 0;
1593 } 1599 }
1594 return 1; 1600 return 1;
1595 } 1601 }
1596 1602
1597 //------------------------------------------------------------------------------ 1603 //------------------------------------------------------------------------------
OLDNEW
« no previous file with comments | « third_party/libwebp/enc/vp8enci.h ('k') | third_party/libwebp/enc/vp8li.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698