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

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

Issue 1546003002: libwebp: update to 0.5.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase around clang-cl fix Created 4 years, 12 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
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 <stdio.h>
17 #include <stdlib.h> 16 #include <stdlib.h>
18 17
19 #include "./backward_references.h" 18 #include "./backward_references.h"
19 #include "./histogram.h"
20 #include "./vp8enci.h" 20 #include "./vp8enci.h"
21 #include "./vp8li.h" 21 #include "./vp8li.h"
22 #include "../dsp/lossless.h" 22 #include "../dsp/lossless.h"
23 #include "../utils/bit_writer.h" 23 #include "../utils/bit_writer.h"
24 #include "../utils/huffman_encode.h" 24 #include "../utils/huffman_encode.h"
25 #include "../utils/utils.h" 25 #include "../utils/utils.h"
26 #include "../webp/format_constants.h" 26 #include "../webp/format_constants.h"
27 27
28 #include "./delta_palettization.h"
29
28 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. 30 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
29 #define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024) 31 // Maximum number of histogram images (sub-blocks).
30 #define MAX_COLORS_FOR_GRAPH 64 32 #define MAX_HUFF_IMAGE_SIZE 2600
33
34 // Palette reordering for smaller sum of deltas (and for smaller storage).
35
36 static int PaletteCompareColorsForQsort(const void* p1, const void* p2) {
37 const uint32_t a = WebPMemToUint32(p1);
38 const uint32_t b = WebPMemToUint32(p2);
39 assert(a != b);
40 return (a < b) ? -1 : 1;
41 }
42
43 static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) {
44 return (v <= 128) ? v : (256 - v);
45 }
46
47 // Computes a value that is related to the entropy created by the
48 // palette entry diff.
49 //
50 // Note that the last & 0xff is a no-operation in the next statement, but
51 // removed by most compilers and is here only for regularity of the code.
52 static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) {
53 const uint32_t diff = VP8LSubPixels(col1, col2);
54 const int kMoreWeightForRGBThanForAlpha = 9;
55 uint32_t score;
56 score = PaletteComponentDistance((diff >> 0) & 0xff);
57 score += PaletteComponentDistance((diff >> 8) & 0xff);
58 score += PaletteComponentDistance((diff >> 16) & 0xff);
59 score *= kMoreWeightForRGBThanForAlpha;
60 score += PaletteComponentDistance((diff >> 24) & 0xff);
61 return score;
62 }
63
64 static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
65 const uint32_t tmp = *col1;
66 *col1 = *col2;
67 *col2 = tmp;
68 }
69
70 static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
71 // Find greedily always the closest color of the predicted color to minimize
72 // deltas in the palette. This reduces storage needs since the
73 // palette is stored with delta encoding.
74 uint32_t predict = 0x00000000;
75 int i, k;
76 for (i = 0; i < num_colors; ++i) {
77 int best_ix = i;
78 uint32_t best_score = ~0U;
79 for (k = i; k < num_colors; ++k) {
80 const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
81 if (best_score > cur_score) {
82 best_score = cur_score;
83 best_ix = k;
84 }
85 }
86 SwapColor(&palette[best_ix], &palette[i]);
87 predict = palette[i];
88 }
89 }
90
91 // The palette has been sorted by alpha. This function checks if the other
92 // components of the palette have a monotonic development with regards to
93 // position in the palette. If all have monotonic development, there is
94 // no benefit to re-organize them greedily. A monotonic development
95 // would be spotted in green-only situations (like lossy alpha) or gray-scale
96 // images.
97 static int PaletteHasNonMonotonousDeltas(uint32_t palette[], int num_colors) {
98 uint32_t predict = 0x000000;
99 int i;
100 uint8_t sign_found = 0x00;
101 for (i = 0; i < num_colors; ++i) {
102 const uint32_t diff = VP8LSubPixels(palette[i], predict);
103 const uint8_t rd = (diff >> 16) & 0xff;
104 const uint8_t gd = (diff >> 8) & 0xff;
105 const uint8_t bd = (diff >> 0) & 0xff;
106 if (rd != 0x00) {
107 sign_found |= (rd < 0x80) ? 1 : 2;
108 }
109 if (gd != 0x00) {
110 sign_found |= (gd < 0x80) ? 8 : 16;
111 }
112 if (bd != 0x00) {
113 sign_found |= (bd < 0x80) ? 64 : 128;
114 }
115 predict = palette[i];
116 }
117 return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
118 }
31 119
32 // ----------------------------------------------------------------------------- 120 // -----------------------------------------------------------------------------
33 // Palette 121 // Palette
34 122
35 static int CompareColors(const void* p1, const void* p2) {
36 const uint32_t a = *(const uint32_t*)p1;
37 const uint32_t b = *(const uint32_t*)p2;
38 assert(a != b);
39 return (a < b) ? -1 : 1;
40 }
41
42 // 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,
43 // creates a palette and returns true, else returns false. 124 // creates a palette and returns true, else returns false.
44 static int AnalyzeAndCreatePalette(const WebPPicture* const pic, 125 static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
126 int low_effort,
45 uint32_t palette[MAX_PALETTE_SIZE], 127 uint32_t palette[MAX_PALETTE_SIZE],
46 int* const palette_size) { 128 int* const palette_size) {
47 int i, x, y, key; 129 int i, x, y, key;
48 int num_colors = 0; 130 int num_colors = 0;
49 uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 }; 131 uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
50 uint32_t colors[MAX_PALETTE_SIZE * 4]; 132 uint32_t colors[MAX_PALETTE_SIZE * 4];
51 static const uint32_t kHashMul = 0x1e35a7bd; 133 static const uint32_t kHashMul = 0x1e35a7bd;
52 const uint32_t* argb = pic->argb; 134 const uint32_t* argb = pic->argb;
53 const int width = pic->width; 135 const int width = pic->width;
54 const int height = pic->height; 136 const int height = pic->height;
(...skipping 30 matching lines...) Expand all
85 } 167 }
86 168
87 // TODO(skal): could we reuse in_use[] to speed up EncodePalette()? 169 // TODO(skal): could we reuse in_use[] to speed up EncodePalette()?
88 num_colors = 0; 170 num_colors = 0;
89 for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) { 171 for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
90 if (in_use[i]) { 172 if (in_use[i]) {
91 palette[num_colors] = colors[i]; 173 palette[num_colors] = colors[i];
92 ++num_colors; 174 ++num_colors;
93 } 175 }
94 } 176 }
95
96 qsort(palette, num_colors, sizeof(*palette), CompareColors);
97 *palette_size = num_colors; 177 *palette_size = num_colors;
178 qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
179 if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {
180 GreedyMinimizeDeltas(palette, num_colors);
181 }
98 return 1; 182 return 1;
99 } 183 }
100 184
185 // These five modes are evaluated and their respective entropy is computed.
186 typedef enum {
187 kDirect = 0,
188 kSpatial = 1,
189 kSubGreen = 2,
190 kSpatialSubGreen = 3,
191 kPalette = 4,
192 kNumEntropyIx = 5
193 } EntropyIx;
194
195 typedef enum {
196 kHistoAlpha = 0,
197 kHistoAlphaPred,
198 kHistoGreen,
199 kHistoGreenPred,
200 kHistoRed,
201 kHistoRedPred,
202 kHistoBlue,
203 kHistoBluePred,
204 kHistoRedSubGreen,
205 kHistoRedPredSubGreen,
206 kHistoBlueSubGreen,
207 kHistoBluePredSubGreen,
208 kHistoPalette,
209 kHistoTotal // Must be last.
210 } HistoIx;
211
212 static void AddSingleSubGreen(uint32_t p, uint32_t* r, uint32_t* b) {
213 const uint32_t green = p >> 8; // The upper bits are masked away later.
214 ++r[((p >> 16) - green) & 0xff];
215 ++b[(p - green) & 0xff];
216 }
217
218 static void AddSingle(uint32_t p,
219 uint32_t* a, uint32_t* r, uint32_t* g, uint32_t* b) {
220 ++a[p >> 24];
221 ++r[(p >> 16) & 0xff];
222 ++g[(p >> 8) & 0xff];
223 ++b[(p & 0xff)];
224 }
225
101 static int AnalyzeEntropy(const uint32_t* argb, 226 static int AnalyzeEntropy(const uint32_t* argb,
102 int width, int height, int argb_stride, 227 int width, int height, int argb_stride,
103 double* const nonpredicted_bits, 228 int use_palette,
104 double* const predicted_bits) { 229 EntropyIx* const min_entropy_ix,
105 int x, y; 230 int* const red_and_blue_always_zero) {
106 const uint32_t* last_line = NULL; 231 // Allocate histogram set with cache_bits = 0.
107 uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0 232 uint32_t* const histo =
108 233 (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256);
109 VP8LHistogramSet* const histo_set = VP8LAllocateHistogramSet(2, 0); 234 if (histo != NULL) {
110 if (histo_set == NULL) return 0; 235 int i, x, y;
111 236 const uint32_t* prev_row = argb;
112 for (y = 0; y < height; ++y) { 237 const uint32_t* curr_row = argb + argb_stride;
113 for (x = 0; x < width; ++x) { 238 for (y = 1; y < height; ++y) {
114 const uint32_t pix = argb[x]; 239 uint32_t prev_pix = curr_row[0];
115 const uint32_t pix_diff = VP8LSubPixels(pix, last_pix); 240 for (x = 1; x < width; ++x) {
116 if (pix_diff == 0) continue; 241 const uint32_t pix = curr_row[x];
117 if (last_line != NULL && pix == last_line[x]) { 242 const uint32_t pix_diff = VP8LSubPixels(pix, prev_pix);
118 continue; 243 if ((pix_diff == 0) || (pix == prev_row[x])) continue;
119 } 244 prev_pix = pix;
120 last_pix = pix; 245 AddSingle(pix,
246 &histo[kHistoAlpha * 256],
247 &histo[kHistoRed * 256],
248 &histo[kHistoGreen * 256],
249 &histo[kHistoBlue * 256]);
250 AddSingle(pix_diff,
251 &histo[kHistoAlphaPred * 256],
252 &histo[kHistoRedPred * 256],
253 &histo[kHistoGreenPred * 256],
254 &histo[kHistoBluePred * 256]);
255 AddSingleSubGreen(pix,
256 &histo[kHistoRedSubGreen * 256],
257 &histo[kHistoBlueSubGreen * 256]);
258 AddSingleSubGreen(pix_diff,
259 &histo[kHistoRedPredSubGreen * 256],
260 &histo[kHistoBluePredSubGreen * 256]);
261 {
262 // Approximate the palette by the entropy of the multiplicative hash.
263 const int hash = ((pix + (pix >> 19)) * 0x39c5fba7) >> 24;
264 ++histo[kHistoPalette * 256 + (hash & 0xff)];
265 }
266 }
267 prev_row = curr_row;
268 curr_row += argb_stride;
269 }
270 {
271 double entropy_comp[kHistoTotal];
272 double entropy[kNumEntropyIx];
273 EntropyIx k;
274 EntropyIx last_mode_to_analyze =
275 use_palette ? kPalette : kSpatialSubGreen;
276 int j;
277 // Let's add one zero to the predicted histograms. The zeros are removed
278 // too efficiently by the pix_diff == 0 comparison, at least one of the
279 // zeros is likely to exist.
280 ++histo[kHistoRedPredSubGreen * 256];
281 ++histo[kHistoBluePredSubGreen * 256];
282 ++histo[kHistoRedPred * 256];
283 ++histo[kHistoGreenPred * 256];
284 ++histo[kHistoBluePred * 256];
285 ++histo[kHistoAlphaPred * 256];
286
287 for (j = 0; j < kHistoTotal; ++j) {
288 entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256, NULL);
289 }
290 entropy[kDirect] = entropy_comp[kHistoAlpha] +
291 entropy_comp[kHistoRed] +
292 entropy_comp[kHistoGreen] +
293 entropy_comp[kHistoBlue];
294 entropy[kSpatial] = entropy_comp[kHistoAlphaPred] +
295 entropy_comp[kHistoRedPred] +
296 entropy_comp[kHistoGreenPred] +
297 entropy_comp[kHistoBluePred];
298 entropy[kSubGreen] = entropy_comp[kHistoAlpha] +
299 entropy_comp[kHistoRedSubGreen] +
300 entropy_comp[kHistoGreen] +
301 entropy_comp[kHistoBlueSubGreen];
302 entropy[kSpatialSubGreen] = entropy_comp[kHistoAlphaPred] +
303 entropy_comp[kHistoRedPredSubGreen] +
304 entropy_comp[kHistoGreenPred] +
305 entropy_comp[kHistoBluePredSubGreen];
306 // Palette mode seems more efficient in a breakeven case. Bias with 1.0.
307 entropy[kPalette] = entropy_comp[kHistoPalette] - 1.0;
308
309 *min_entropy_ix = kDirect;
310 for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) {
311 if (entropy[*min_entropy_ix] > entropy[k]) {
312 *min_entropy_ix = k;
313 }
314 }
315 *red_and_blue_always_zero = 1;
316 // Let's check if the histogram of the chosen entropy mode has
317 // non-zero red and blue values. If all are zero, we can later skip
318 // the cross color optimization.
121 { 319 {
122 const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix); 320 static const uint8_t kHistoPairs[5][2] = {
123 const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff); 321 { kHistoRed, kHistoBlue },
124 VP8LHistogramAddSinglePixOrCopy(histo_set->histograms[0], &pix_token); 322 { kHistoRedPred, kHistoBluePred },
125 VP8LHistogramAddSinglePixOrCopy(histo_set->histograms[1], 323 { kHistoRedSubGreen, kHistoBlueSubGreen },
126 &pix_diff_token); 324 { kHistoRedPredSubGreen, kHistoBluePredSubGreen },
127 } 325 { kHistoRed, kHistoBlue }
128 } 326 };
129 last_line = argb; 327 const uint32_t* const red_histo =
130 argb += argb_stride; 328 &histo[256 * kHistoPairs[*min_entropy_ix][0]];
131 } 329 const uint32_t* const blue_histo =
132 *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(histo_set->histograms[0]); 330 &histo[256 * kHistoPairs[*min_entropy_ix][1]];
133 *predicted_bits = VP8LHistogramEstimateBitsBulk(histo_set->histograms[1]); 331 for (i = 1; i < 256; ++i) {
134 VP8LFreeHistogramSet(histo_set); 332 if ((red_histo[i] | blue_histo[i]) != 0) {
135 return 1; 333 *red_and_blue_always_zero = 0;
136 } 334 break;
137 335 }
138 static int AnalyzeAndInit(VP8LEncoder* const enc, WebPImageHint image_hint) { 336 }
337 }
338 }
339 free(histo);
340 return 1;
341 } else {
342 return 0;
343 }
344 }
345
346 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).
348 int histo_bits = (use_palette ? 9 : 7) - method;
349 while (1) {
350 const int huff_image_size = VP8LSubSampleSize(width, histo_bits) *
351 VP8LSubSampleSize(height, histo_bits);
352 if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
353 ++histo_bits;
354 }
355 return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
356 (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
357 }
358
359 static int GetTransformBits(int method, int histo_bits) {
360 const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5;
361 return (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits;
362 }
363
364 static int AnalyzeAndInit(VP8LEncoder* const enc) {
139 const WebPPicture* const pic = enc->pic_; 365 const WebPPicture* const pic = enc->pic_;
140 const int width = pic->width; 366 const int width = pic->width;
141 const int height = pic->height; 367 const int height = pic->height;
142 const int pix_cnt = width * height; 368 const int pix_cnt = width * height;
369 const WebPConfig* const config = enc->config_;
370 const int method = config->method;
371 const int low_effort = (config->method == 0);
143 // we round the block size up, so we're guaranteed to have 372 // we round the block size up, so we're guaranteed to have
144 // at max MAX_REFS_BLOCK_PER_IMAGE blocks used: 373 // at max MAX_REFS_BLOCK_PER_IMAGE blocks used:
145 int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1; 374 int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1;
146 assert(pic != NULL && pic->argb != NULL); 375 assert(pic != NULL && pic->argb != NULL);
147 376
377 enc->use_cross_color_ = 0;
378 enc->use_predict_ = 0;
379 enc->use_subtract_green_ = 0;
148 enc->use_palette_ = 380 enc->use_palette_ =
149 AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_); 381 AnalyzeAndCreatePalette(pic, low_effort,
150 382 enc->palette_, &enc->palette_size_);
151 if (image_hint == WEBP_HINT_GRAPH) { 383
152 if (enc->use_palette_ && enc->palette_size_ < MAX_COLORS_FOR_GRAPH) { 384 // TODO(jyrki): replace the decision to be based on an actual estimate
153 enc->use_palette_ = 0; 385 // of entropy, or even spatial variance of entropy.
154 } 386 enc->histo_bits_ = GetHistoBits(method, enc->use_palette_,
155 } 387 pic->width, pic->height);
156 388 enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_);
157 if (!enc->use_palette_) { 389
158 if (image_hint == WEBP_HINT_PHOTO) { 390 if (low_effort) {
159 enc->use_predict_ = 1; 391 // AnalyzeEntropy is somewhat slow.
160 enc->use_cross_color_ = 1; 392 enc->use_predict_ = !enc->use_palette_;
161 } else { 393 enc->use_subtract_green_ = !enc->use_palette_;
162 double non_pred_entropy, pred_entropy; 394 enc->use_cross_color_ = 0;
163 if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, 395 } else {
164 &non_pred_entropy, &pred_entropy)) { 396 int red_and_blue_always_zero;
165 return 0; 397 EntropyIx min_entropy_ix;
166 } 398 if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride,
167 if (pred_entropy < 0.95 * non_pred_entropy) { 399 enc->use_palette_, &min_entropy_ix,
168 enc->use_predict_ = 1; 400 &red_and_blue_always_zero)) {
169 enc->use_cross_color_ = 1; 401 return 0;
170 } 402 }
171 } 403 enc->use_palette_ = (min_entropy_ix == kPalette);
172 } 404 enc->use_subtract_green_ =
405 (min_entropy_ix == kSubGreen) || (min_entropy_ix == kSpatialSubGreen);
406 enc->use_predict_ =
407 (min_entropy_ix == kSpatial) || (min_entropy_ix == kSpatialSubGreen);
408 enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_;
409 }
410
173 if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0; 411 if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0;
174 412
175 // palette-friendly input typically uses less literals 413 // palette-friendly input typically uses less literals
176 // -> reduce block size a bit 414 // -> reduce block size a bit
177 if (enc->use_palette_) refs_block_size /= 2; 415 if (enc->use_palette_) refs_block_size /= 2;
178 VP8LBackwardRefsInit(&enc->refs_[0], refs_block_size); 416 VP8LBackwardRefsInit(&enc->refs_[0], refs_block_size);
179 VP8LBackwardRefsInit(&enc->refs_[1], refs_block_size); 417 VP8LBackwardRefsInit(&enc->refs_[1], refs_block_size);
180 418
181 return 1; 419 return 1;
182 } 420 }
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 502 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
265 }; 503 };
266 int i; 504 int i;
267 // Throw away trailing zeros: 505 // Throw away trailing zeros:
268 int codes_to_store = CODE_LENGTH_CODES; 506 int codes_to_store = CODE_LENGTH_CODES;
269 for (; codes_to_store > 4; --codes_to_store) { 507 for (; codes_to_store > 4; --codes_to_store) {
270 if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) { 508 if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
271 break; 509 break;
272 } 510 }
273 } 511 }
274 VP8LWriteBits(bw, 4, codes_to_store - 4); 512 VP8LPutBits(bw, codes_to_store - 4, 4);
275 for (i = 0; i < codes_to_store; ++i) { 513 for (i = 0; i < codes_to_store; ++i) {
276 VP8LWriteBits(bw, 3, code_length_bitdepth[kStorageOrder[i]]); 514 VP8LPutBits(bw, code_length_bitdepth[kStorageOrder[i]], 3);
277 } 515 }
278 } 516 }
279 517
280 static void ClearHuffmanTreeIfOnlyOneSymbol( 518 static void ClearHuffmanTreeIfOnlyOneSymbol(
281 HuffmanTreeCode* const huffman_code) { 519 HuffmanTreeCode* const huffman_code) {
282 int k; 520 int k;
283 int count = 0; 521 int count = 0;
284 for (k = 0; k < huffman_code->num_symbols; ++k) { 522 for (k = 0; k < huffman_code->num_symbols; ++k) {
285 if (huffman_code->code_lengths[k] != 0) { 523 if (huffman_code->code_lengths[k] != 0) {
286 ++count; 524 ++count;
287 if (count > 1) return; 525 if (count > 1) return;
288 } 526 }
289 } 527 }
290 for (k = 0; k < huffman_code->num_symbols; ++k) { 528 for (k = 0; k < huffman_code->num_symbols; ++k) {
291 huffman_code->code_lengths[k] = 0; 529 huffman_code->code_lengths[k] = 0;
292 huffman_code->codes[k] = 0; 530 huffman_code->codes[k] = 0;
293 } 531 }
294 } 532 }
295 533
296 static void StoreHuffmanTreeToBitMask( 534 static void StoreHuffmanTreeToBitMask(
297 VP8LBitWriter* const bw, 535 VP8LBitWriter* const bw,
298 const HuffmanTreeToken* const tokens, const int num_tokens, 536 const HuffmanTreeToken* const tokens, const int num_tokens,
299 const HuffmanTreeCode* const huffman_code) { 537 const HuffmanTreeCode* const huffman_code) {
300 int i; 538 int i;
301 for (i = 0; i < num_tokens; ++i) { 539 for (i = 0; i < num_tokens; ++i) {
302 const int ix = tokens[i].code; 540 const int ix = tokens[i].code;
303 const int extra_bits = tokens[i].extra_bits; 541 const int extra_bits = tokens[i].extra_bits;
304 VP8LWriteBits(bw, huffman_code->code_lengths[ix], huffman_code->codes[ix]); 542 VP8LPutBits(bw, huffman_code->codes[ix], huffman_code->code_lengths[ix]);
305 switch (ix) { 543 switch (ix) {
306 case 16: 544 case 16:
307 VP8LWriteBits(bw, 2, extra_bits); 545 VP8LPutBits(bw, extra_bits, 2);
308 break; 546 break;
309 case 17: 547 case 17:
310 VP8LWriteBits(bw, 3, extra_bits); 548 VP8LPutBits(bw, extra_bits, 3);
311 break; 549 break;
312 case 18: 550 case 18:
313 VP8LWriteBits(bw, 7, extra_bits); 551 VP8LPutBits(bw, extra_bits, 7);
314 break; 552 break;
315 } 553 }
316 } 554 }
317 } 555 }
318 556
319 // 'huff_tree' and 'tokens' are pre-alloacted buffers. 557 // 'huff_tree' and 'tokens' are pre-alloacted buffers.
320 static void StoreFullHuffmanCode(VP8LBitWriter* const bw, 558 static void StoreFullHuffmanCode(VP8LBitWriter* const bw,
321 HuffmanTree* const huff_tree, 559 HuffmanTree* const huff_tree,
322 HuffmanTreeToken* const tokens, 560 HuffmanTreeToken* const tokens,
323 const HuffmanTreeCode* const tree) { 561 const HuffmanTreeCode* const tree) {
324 uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 }; 562 uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
325 uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 }; 563 uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
326 const int max_tokens = tree->num_symbols; 564 const int max_tokens = tree->num_symbols;
327 int num_tokens; 565 int num_tokens;
328 HuffmanTreeCode huffman_code; 566 HuffmanTreeCode huffman_code;
329 huffman_code.num_symbols = CODE_LENGTH_CODES; 567 huffman_code.num_symbols = CODE_LENGTH_CODES;
330 huffman_code.code_lengths = code_length_bitdepth; 568 huffman_code.code_lengths = code_length_bitdepth;
331 huffman_code.codes = code_length_bitdepth_symbols; 569 huffman_code.codes = code_length_bitdepth_symbols;
332 570
333 VP8LWriteBits(bw, 1, 0); 571 VP8LPutBits(bw, 0, 1);
334 num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens); 572 num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens);
335 { 573 {
336 uint32_t histogram[CODE_LENGTH_CODES] = { 0 }; 574 uint32_t histogram[CODE_LENGTH_CODES] = { 0 };
337 uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 }; 575 uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 };
338 int i; 576 int i;
339 for (i = 0; i < num_tokens; ++i) { 577 for (i = 0; i < num_tokens; ++i) {
340 ++histogram[tokens[i].code]; 578 ++histogram[tokens[i].code];
341 } 579 }
342 580
343 VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code); 581 VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code);
(...skipping 16 matching lines...) Expand all
360 trailing_zero_bits += 3; 598 trailing_zero_bits += 3;
361 } else if (ix == 18) { 599 } else if (ix == 18) {
362 trailing_zero_bits += 7; 600 trailing_zero_bits += 7;
363 } 601 }
364 } else { 602 } else {
365 break; 603 break;
366 } 604 }
367 } 605 }
368 write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12); 606 write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
369 length = write_trimmed_length ? trimmed_length : num_tokens; 607 length = write_trimmed_length ? trimmed_length : num_tokens;
370 VP8LWriteBits(bw, 1, write_trimmed_length); 608 VP8LPutBits(bw, write_trimmed_length, 1);
371 if (write_trimmed_length) { 609 if (write_trimmed_length) {
372 const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1); 610 const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
373 const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2; 611 const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
374 VP8LWriteBits(bw, 3, nbitpairs - 1); 612 VP8LPutBits(bw, nbitpairs - 1, 3);
375 assert(trimmed_length >= 2); 613 assert(trimmed_length >= 2);
376 VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2); 614 VP8LPutBits(bw, trimmed_length - 2, nbitpairs * 2);
377 } 615 }
378 StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code); 616 StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
379 } 617 }
380 } 618 }
381 619
382 // 'huff_tree' and 'tokens' are pre-alloacted buffers. 620 // 'huff_tree' and 'tokens' are pre-alloacted buffers.
383 static void StoreHuffmanCode(VP8LBitWriter* const bw, 621 static void StoreHuffmanCode(VP8LBitWriter* const bw,
384 HuffmanTree* const huff_tree, 622 HuffmanTree* const huff_tree,
385 HuffmanTreeToken* const tokens, 623 HuffmanTreeToken* const tokens,
386 const HuffmanTreeCode* const huffman_code) { 624 const HuffmanTreeCode* const huffman_code) {
387 int i; 625 int i;
388 int count = 0; 626 int count = 0;
389 int symbols[2] = { 0, 0 }; 627 int symbols[2] = { 0, 0 };
390 const int kMaxBits = 8; 628 const int kMaxBits = 8;
391 const int kMaxSymbol = 1 << kMaxBits; 629 const int kMaxSymbol = 1 << kMaxBits;
392 630
393 // Check whether it's a small tree. 631 // Check whether it's a small tree.
394 for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) { 632 for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) {
395 if (huffman_code->code_lengths[i] != 0) { 633 if (huffman_code->code_lengths[i] != 0) {
396 if (count < 2) symbols[count] = i; 634 if (count < 2) symbols[count] = i;
397 ++count; 635 ++count;
398 } 636 }
399 } 637 }
400 638
401 if (count == 0) { // emit minimal tree for empty cases 639 if (count == 0) { // emit minimal tree for empty cases
402 // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0 640 // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
403 VP8LWriteBits(bw, 4, 0x01); 641 VP8LPutBits(bw, 0x01, 4);
404 } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) { 642 } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
405 VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols. 643 VP8LPutBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols.
406 VP8LWriteBits(bw, 1, count - 1); 644 VP8LPutBits(bw, count - 1, 1);
407 if (symbols[0] <= 1) { 645 if (symbols[0] <= 1) {
408 VP8LWriteBits(bw, 1, 0); // Code bit for small (1 bit) symbol value. 646 VP8LPutBits(bw, 0, 1); // Code bit for small (1 bit) symbol value.
409 VP8LWriteBits(bw, 1, symbols[0]); 647 VP8LPutBits(bw, symbols[0], 1);
410 } else { 648 } else {
411 VP8LWriteBits(bw, 1, 1); 649 VP8LPutBits(bw, 1, 1);
412 VP8LWriteBits(bw, 8, symbols[0]); 650 VP8LPutBits(bw, symbols[0], 8);
413 } 651 }
414 if (count == 2) { 652 if (count == 2) {
415 VP8LWriteBits(bw, 8, symbols[1]); 653 VP8LPutBits(bw, symbols[1], 8);
416 } 654 }
417 } else { 655 } else {
418 StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code); 656 StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code);
419 } 657 }
420 } 658 }
421 659
422 static void WriteHuffmanCode(VP8LBitWriter* const bw, 660 static WEBP_INLINE void WriteHuffmanCode(VP8LBitWriter* const bw,
423 const HuffmanTreeCode* const code, 661 const HuffmanTreeCode* const code,
424 int code_index) { 662 int code_index) {
425 const int depth = code->code_lengths[code_index]; 663 const int depth = code->code_lengths[code_index];
426 const int symbol = code->codes[code_index]; 664 const int symbol = code->codes[code_index];
427 VP8LWriteBits(bw, depth, symbol); 665 VP8LPutBits(bw, symbol, depth);
666 }
667
668 static WEBP_INLINE void WriteHuffmanCodeWithExtraBits(
669 VP8LBitWriter* const bw,
670 const HuffmanTreeCode* const code,
671 int code_index,
672 int bits,
673 int n_bits) {
674 const int depth = code->code_lengths[code_index];
675 const int symbol = code->codes[code_index];
676 VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits);
428 } 677 }
429 678
430 static WebPEncodingError StoreImageToBitMask( 679 static WebPEncodingError StoreImageToBitMask(
431 VP8LBitWriter* const bw, int width, int histo_bits, 680 VP8LBitWriter* const bw, int width, int histo_bits,
432 VP8LBackwardRefs* const refs, 681 VP8LBackwardRefs* const refs,
433 const uint16_t* histogram_symbols, 682 const uint16_t* histogram_symbols,
434 const HuffmanTreeCode* const huffman_codes) { 683 const HuffmanTreeCode* const huffman_codes) {
684 const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
685 const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits);
435 // x and y trace the position in the image. 686 // x and y trace the position in the image.
436 int x = 0; 687 int x = 0;
437 int y = 0; 688 int y = 0;
438 const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1; 689 int tile_x = x & tile_mask;
690 int tile_y = y & tile_mask;
691 int histogram_ix = histogram_symbols[0];
692 const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix;
439 VP8LRefsCursor c = VP8LRefsCursorInit(refs); 693 VP8LRefsCursor c = VP8LRefsCursorInit(refs);
440 while (VP8LRefsCursorOk(&c)) { 694 while (VP8LRefsCursorOk(&c)) {
441 const PixOrCopy* const v = c.cur_pos; 695 const PixOrCopy* const v = c.cur_pos;
442 const int histogram_ix = histogram_symbols[histo_bits ? 696 if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) {
443 (y >> histo_bits) * histo_xsize + 697 tile_x = x & tile_mask;
444 (x >> histo_bits) : 0]; 698 tile_y = y & tile_mask;
445 const HuffmanTreeCode* const codes = huffman_codes + 5 * histogram_ix; 699 histogram_ix = histogram_symbols[(y >> histo_bits) * histo_xsize +
446 if (PixOrCopyIsCacheIdx(v)) { 700 (x >> histo_bits)];
447 const int code = PixOrCopyCacheIdx(v); 701 codes = huffman_codes + 5 * histogram_ix;
448 const int literal_ix = 256 + NUM_LENGTH_CODES + code; 702 }
449 WriteHuffmanCode(bw, codes, literal_ix); 703 if (PixOrCopyIsLiteral(v)) {
450 } else if (PixOrCopyIsLiteral(v)) {
451 static const int order[] = { 1, 2, 0, 3 }; 704 static const int order[] = { 1, 2, 0, 3 };
452 int k; 705 int k;
453 for (k = 0; k < 4; ++k) { 706 for (k = 0; k < 4; ++k) {
454 const int code = PixOrCopyLiteral(v, order[k]); 707 const int code = PixOrCopyLiteral(v, order[k]);
455 WriteHuffmanCode(bw, codes + k, code); 708 WriteHuffmanCode(bw, codes + k, code);
456 } 709 }
710 } else if (PixOrCopyIsCacheIdx(v)) {
711 const int code = PixOrCopyCacheIdx(v);
712 const int literal_ix = 256 + NUM_LENGTH_CODES + code;
713 WriteHuffmanCode(bw, codes, literal_ix);
457 } else { 714 } else {
458 int bits, n_bits; 715 int bits, n_bits;
459 int code, distance; 716 int code;
460 717
718 const int distance = PixOrCopyDistance(v);
461 VP8LPrefixEncode(v->len, &code, &n_bits, &bits); 719 VP8LPrefixEncode(v->len, &code, &n_bits, &bits);
462 WriteHuffmanCode(bw, codes, 256 + code); 720 WriteHuffmanCodeWithExtraBits(bw, codes, 256 + code, bits, n_bits);
463 VP8LWriteBits(bw, n_bits, bits);
464 721
465 distance = PixOrCopyDistance(v); 722 // Don't write the distance with the extra bits code since
723 // the distance can be up to 18 bits of extra bits, and the prefix
724 // 15 bits, totaling to 33, and our PutBits only supports up to 32 bits.
725 // TODO(jyrki): optimize this further.
466 VP8LPrefixEncode(distance, &code, &n_bits, &bits); 726 VP8LPrefixEncode(distance, &code, &n_bits, &bits);
467 WriteHuffmanCode(bw, codes + 4, code); 727 WriteHuffmanCode(bw, codes + 4, code);
468 VP8LWriteBits(bw, n_bits, bits); 728 VP8LPutBits(bw, bits, n_bits);
469 } 729 }
470 x += PixOrCopyLength(v); 730 x += PixOrCopyLength(v);
471 while (x >= width) { 731 while (x >= width) {
472 x -= width; 732 x -= width;
473 ++y; 733 ++y;
474 } 734 }
475 VP8LRefsCursorNext(&c); 735 VP8LRefsCursorNext(&c);
476 } 736 }
477 return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK; 737 return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK;
478 } 738 }
479 739
480 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31 740 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
481 static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, 741 static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
482 const uint32_t* const argb, 742 const uint32_t* const argb,
483 VP8LHashChain* const hash_chain, 743 VP8LHashChain* const hash_chain,
484 VP8LBackwardRefs refs_array[2], 744 VP8LBackwardRefs refs_array[2],
485 int width, int height, 745 int width, int height,
486 int quality) { 746 int quality) {
487 int i; 747 int i;
488 int max_tokens = 0; 748 int max_tokens = 0;
489 WebPEncodingError err = VP8_ENC_OK; 749 WebPEncodingError err = VP8_ENC_OK;
490 VP8LBackwardRefs* refs; 750 VP8LBackwardRefs* refs;
491 HuffmanTreeToken* tokens = NULL; 751 HuffmanTreeToken* tokens = NULL;
492 HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } }; 752 HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
493 const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol 753 const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol
494 VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0); 754 int cache_bits = 0;
755 VP8LHistogramSet* histogram_image = NULL;
495 HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( 756 HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
496 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); 757 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
497 if (histogram_image == NULL || huff_tree == NULL) { 758 if (huff_tree == NULL) {
498 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 759 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
499 goto Error; 760 goto Error;
500 } 761 }
501 762
502 // Calculate backward references from ARGB image. 763 // Calculate backward references from ARGB image.
503 refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, 1, 764 refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, &cache_bits,
504 hash_chain, refs_array); 765 hash_chain, refs_array);
505 if (refs == NULL) { 766 if (refs == NULL) {
506 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 767 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
507 goto Error; 768 goto Error;
508 } 769 }
770 histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
771 if (histogram_image == NULL) {
772 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
773 goto Error;
774 }
775
509 // Build histogram image and symbols from backward references. 776 // Build histogram image and symbols from backward references.
510 VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]); 777 VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);
511 778
512 // Create Huffman bit lengths and codes for each histogram image. 779 // Create Huffman bit lengths and codes for each histogram image.
513 assert(histogram_image->size == 1); 780 assert(histogram_image->size == 1);
514 if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { 781 if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
515 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 782 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
516 goto Error; 783 goto Error;
517 } 784 }
518 785
519 // No color cache, no Huffman image. 786 // No color cache, no Huffman image.
520 VP8LWriteBits(bw, 1, 0); 787 VP8LPutBits(bw, 0, 1);
521 788
522 // Find maximum number of symbols for the huffman tree-set. 789 // Find maximum number of symbols for the huffman tree-set.
523 for (i = 0; i < 5; ++i) { 790 for (i = 0; i < 5; ++i) {
524 HuffmanTreeCode* const codes = &huffman_codes[i]; 791 HuffmanTreeCode* const codes = &huffman_codes[i];
525 if (max_tokens < codes->num_symbols) { 792 if (max_tokens < codes->num_symbols) {
526 max_tokens = codes->num_symbols; 793 max_tokens = codes->num_symbols;
527 } 794 }
528 } 795 }
529 796
530 tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens)); 797 tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
(...skipping 19 matching lines...) Expand all
550 VP8LFreeHistogramSet(histogram_image); 817 VP8LFreeHistogramSet(histogram_image);
551 WebPSafeFree(huffman_codes[0].codes); 818 WebPSafeFree(huffman_codes[0].codes);
552 return err; 819 return err;
553 } 820 }
554 821
555 static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw, 822 static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw,
556 const uint32_t* const argb, 823 const uint32_t* const argb,
557 VP8LHashChain* const hash_chain, 824 VP8LHashChain* const hash_chain,
558 VP8LBackwardRefs refs_array[2], 825 VP8LBackwardRefs refs_array[2],
559 int width, int height, int quality, 826 int width, int height, int quality,
560 int cache_bits, 827 int low_effort, int* cache_bits,
561 int histogram_bits) { 828 int histogram_bits,
829 size_t init_byte_position,
830 int* const hdr_size,
831 int* const data_size) {
562 WebPEncodingError err = VP8_ENC_OK; 832 WebPEncodingError err = VP8_ENC_OK;
563 const int use_2d_locality = 1;
564 const int use_color_cache = (cache_bits > 0);
565 const uint32_t histogram_image_xysize = 833 const uint32_t histogram_image_xysize =
566 VP8LSubSampleSize(width, histogram_bits) * 834 VP8LSubSampleSize(width, histogram_bits) *
567 VP8LSubSampleSize(height, histogram_bits); 835 VP8LSubSampleSize(height, histogram_bits);
568 VP8LHistogramSet* histogram_image = 836 VP8LHistogramSet* histogram_image = NULL;
569 VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits); 837 VP8LHistogramSet* tmp_histos = NULL;
570 int histogram_image_size = 0; 838 int histogram_image_size = 0;
571 size_t bit_array_size = 0; 839 size_t bit_array_size = 0;
572 HuffmanTree* huff_tree = NULL; 840 HuffmanTree* huff_tree = NULL;
573 HuffmanTreeToken* tokens = NULL; 841 HuffmanTreeToken* tokens = NULL;
574 HuffmanTreeCode* huffman_codes = NULL; 842 HuffmanTreeCode* huffman_codes = NULL;
575 VP8LBackwardRefs refs; 843 VP8LBackwardRefs refs;
576 VP8LBackwardRefs* best_refs; 844 VP8LBackwardRefs* best_refs;
577 uint16_t* const histogram_symbols = 845 uint16_t* const histogram_symbols =
578 (uint16_t*)WebPSafeMalloc(histogram_image_xysize, 846 (uint16_t*)WebPSafeMalloc(histogram_image_xysize,
579 sizeof(*histogram_symbols)); 847 sizeof(*histogram_symbols));
580 assert(histogram_bits >= MIN_HUFFMAN_BITS); 848 assert(histogram_bits >= MIN_HUFFMAN_BITS);
581 assert(histogram_bits <= MAX_HUFFMAN_BITS); 849 assert(histogram_bits <= MAX_HUFFMAN_BITS);
850 assert(hdr_size != NULL);
851 assert(data_size != NULL);
582 852
583 VP8LBackwardRefsInit(&refs, refs_array[0].block_size_); 853 VP8LBackwardRefsInit(&refs, refs_array[0].block_size_);
584 if (histogram_image == NULL || histogram_symbols == NULL) { 854 if (histogram_symbols == NULL) {
585 VP8LFreeHistogramSet(histogram_image); 855 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
586 WebPSafeFree(histogram_symbols); 856 goto Error;
587 return 0;
588 } 857 }
589 858
859 *cache_bits = MAX_COLOR_CACHE_BITS;
590 // 'best_refs' is the reference to the best backward refs and points to one 860 // 'best_refs' is the reference to the best backward refs and points to one
591 // of refs_array[0] or refs_array[1]. 861 // of refs_array[0] or refs_array[1].
592 // Calculate backward references from ARGB image. 862 // Calculate backward references from ARGB image.
593 best_refs = VP8LGetBackwardReferences(width, height, argb, quality, 863 best_refs = VP8LGetBackwardReferences(width, height, argb, quality,
594 cache_bits, use_2d_locality, 864 low_effort, cache_bits, hash_chain,
595 hash_chain, refs_array); 865 refs_array);
596 if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) { 866 if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) {
867 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
597 goto Error; 868 goto Error;
598 } 869 }
870 histogram_image =
871 VP8LAllocateHistogramSet(histogram_image_xysize, *cache_bits);
872 tmp_histos = VP8LAllocateHistogramSet(2, *cache_bits);
873 if (histogram_image == NULL || tmp_histos == NULL) {
874 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
875 goto Error;
876 }
877
599 // Build histogram image and symbols from backward references. 878 // Build histogram image and symbols from backward references.
600 if (!VP8LGetHistoImageSymbols(width, height, &refs, 879 if (!VP8LGetHistoImageSymbols(width, height, &refs, quality, low_effort,
601 quality, histogram_bits, cache_bits, 880 histogram_bits, *cache_bits, histogram_image,
602 histogram_image, 881 tmp_histos, histogram_symbols)) {
603 histogram_symbols)) { 882 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
604 goto Error; 883 goto Error;
605 } 884 }
606 // Create Huffman bit lengths and codes for each histogram image. 885 // Create Huffman bit lengths and codes for each histogram image.
607 histogram_image_size = histogram_image->size; 886 histogram_image_size = histogram_image->size;
608 bit_array_size = 5 * histogram_image_size; 887 bit_array_size = 5 * histogram_image_size;
609 huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size, 888 huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
610 sizeof(*huffman_codes)); 889 sizeof(*huffman_codes));
890 // Note: some histogram_image entries may point to tmp_histos[], so the latter
891 // need to outlive the following call to GetHuffBitLengthsAndCodes().
611 if (huffman_codes == NULL || 892 if (huffman_codes == NULL ||
612 !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { 893 !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
894 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
613 goto Error; 895 goto Error;
614 } 896 }
615 // Free combined histograms. 897 // Free combined histograms.
616 VP8LFreeHistogramSet(histogram_image); 898 VP8LFreeHistogramSet(histogram_image);
617 histogram_image = NULL; 899 histogram_image = NULL;
618 900
901 // Free scratch histograms.
902 VP8LFreeHistogramSet(tmp_histos);
903 tmp_histos = NULL;
904
619 // Color Cache parameters. 905 // Color Cache parameters.
620 VP8LWriteBits(bw, 1, use_color_cache); 906 if (*cache_bits > 0) {
621 if (use_color_cache) { 907 VP8LPutBits(bw, 1, 1);
622 VP8LWriteBits(bw, 4, cache_bits); 908 VP8LPutBits(bw, *cache_bits, 4);
909 } else {
910 VP8LPutBits(bw, 0, 1);
623 } 911 }
624 912
625 // Huffman image + meta huffman. 913 // Huffman image + meta huffman.
626 { 914 {
627 const int write_histogram_image = (histogram_image_size > 1); 915 const int write_histogram_image = (histogram_image_size > 1);
628 VP8LWriteBits(bw, 1, write_histogram_image); 916 VP8LPutBits(bw, write_histogram_image, 1);
629 if (write_histogram_image) { 917 if (write_histogram_image) {
630 uint32_t* const histogram_argb = 918 uint32_t* const histogram_argb =
631 (uint32_t*)WebPSafeMalloc(histogram_image_xysize, 919 (uint32_t*)WebPSafeMalloc(histogram_image_xysize,
632 sizeof(*histogram_argb)); 920 sizeof(*histogram_argb));
633 int max_index = 0; 921 int max_index = 0;
634 uint32_t i; 922 uint32_t i;
635 if (histogram_argb == NULL) goto Error; 923 if (histogram_argb == NULL) {
924 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
925 goto Error;
926 }
636 for (i = 0; i < histogram_image_xysize; ++i) { 927 for (i = 0; i < histogram_image_xysize; ++i) {
637 const int symbol_index = histogram_symbols[i] & 0xffff; 928 const int symbol_index = histogram_symbols[i] & 0xffff;
638 histogram_argb[i] = 0xff000000 | (symbol_index << 8); 929 histogram_argb[i] = (symbol_index << 8);
639 if (symbol_index >= max_index) { 930 if (symbol_index >= max_index) {
640 max_index = symbol_index + 1; 931 max_index = symbol_index + 1;
641 } 932 }
642 } 933 }
643 histogram_image_size = max_index; 934 histogram_image_size = max_index;
644 935
645 VP8LWriteBits(bw, 3, histogram_bits - 2); 936 VP8LPutBits(bw, histogram_bits - 2, 3);
646 err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array, 937 err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array,
647 VP8LSubSampleSize(width, histogram_bits), 938 VP8LSubSampleSize(width, histogram_bits),
648 VP8LSubSampleSize(height, histogram_bits), 939 VP8LSubSampleSize(height, histogram_bits),
649 quality); 940 quality);
650 WebPSafeFree(histogram_argb); 941 WebPSafeFree(histogram_argb);
651 if (err != VP8_ENC_OK) goto Error; 942 if (err != VP8_ENC_OK) goto Error;
652 } 943 }
653 } 944 }
654 945
655 // Store Huffman codes. 946 // Store Huffman codes.
656 { 947 {
657 int i; 948 int i;
658 int max_tokens = 0; 949 int max_tokens = 0;
659 huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * CODE_LENGTH_CODES, 950 huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * CODE_LENGTH_CODES,
660 sizeof(*huff_tree)); 951 sizeof(*huff_tree));
661 if (huff_tree == NULL) goto Error; 952 if (huff_tree == NULL) {
953 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
954 goto Error;
955 }
662 // Find maximum number of symbols for the huffman tree-set. 956 // Find maximum number of symbols for the huffman tree-set.
663 for (i = 0; i < 5 * histogram_image_size; ++i) { 957 for (i = 0; i < 5 * histogram_image_size; ++i) {
664 HuffmanTreeCode* const codes = &huffman_codes[i]; 958 HuffmanTreeCode* const codes = &huffman_codes[i];
665 if (max_tokens < codes->num_symbols) { 959 if (max_tokens < codes->num_symbols) {
666 max_tokens = codes->num_symbols; 960 max_tokens = codes->num_symbols;
667 } 961 }
668 } 962 }
669 tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, 963 tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens,
670 sizeof(*tokens)); 964 sizeof(*tokens));
671 if (tokens == NULL) goto Error; 965 if (tokens == NULL) {
966 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
967 goto Error;
968 }
672 for (i = 0; i < 5 * histogram_image_size; ++i) { 969 for (i = 0; i < 5 * histogram_image_size; ++i) {
673 HuffmanTreeCode* const codes = &huffman_codes[i]; 970 HuffmanTreeCode* const codes = &huffman_codes[i];
674 StoreHuffmanCode(bw, huff_tree, tokens, codes); 971 StoreHuffmanCode(bw, huff_tree, tokens, codes);
675 ClearHuffmanTreeIfOnlyOneSymbol(codes); 972 ClearHuffmanTreeIfOnlyOneSymbol(codes);
676 } 973 }
677 } 974 }
678 975
976 *hdr_size = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
679 // Store actual literals. 977 // Store actual literals.
680 err = StoreImageToBitMask(bw, width, histogram_bits, &refs, 978 err = StoreImageToBitMask(bw, width, histogram_bits, &refs,
681 histogram_symbols, huffman_codes); 979 histogram_symbols, huffman_codes);
980 *data_size =
981 (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size);
682 982
683 Error: 983 Error:
684 WebPSafeFree(tokens); 984 WebPSafeFree(tokens);
685 WebPSafeFree(huff_tree); 985 WebPSafeFree(huff_tree);
686 VP8LFreeHistogramSet(histogram_image); 986 VP8LFreeHistogramSet(histogram_image);
987 VP8LFreeHistogramSet(tmp_histos);
687 VP8LBackwardRefsClear(&refs); 988 VP8LBackwardRefsClear(&refs);
688 if (huffman_codes != NULL) { 989 if (huffman_codes != NULL) {
689 WebPSafeFree(huffman_codes->codes); 990 WebPSafeFree(huffman_codes->codes);
690 WebPSafeFree(huffman_codes); 991 WebPSafeFree(huffman_codes);
691 } 992 }
692 WebPSafeFree(histogram_symbols); 993 WebPSafeFree(histogram_symbols);
693 return err; 994 return err;
694 } 995 }
695 996
696 // ----------------------------------------------------------------------------- 997 // -----------------------------------------------------------------------------
697 // Transforms 998 // Transforms
698 999
699 // Check if it would be a good idea to subtract green from red and blue. We 1000 static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height,
700 // only impact entropy in red/blue components, don't bother to look at others. 1001 VP8LBitWriter* const bw) {
701 static WebPEncodingError EvalAndApplySubtractGreen(VP8LEncoder* const enc, 1002 VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
702 int width, int height, 1003 VP8LPutBits(bw, SUBTRACT_GREEN, 2);
703 VP8LBitWriter* const bw) { 1004 VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
704 if (!enc->use_palette_) {
705 int i;
706 const uint32_t* const argb = enc->argb_;
707 double bit_cost_before, bit_cost_after;
708 // Allocate histogram with cache_bits = 1.
709 VP8LHistogram* const histo = VP8LAllocateHistogram(1);
710 if (histo == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
711 for (i = 0; i < width * height; ++i) {
712 const uint32_t c = argb[i];
713 ++histo->red_[(c >> 16) & 0xff];
714 ++histo->blue_[(c >> 0) & 0xff];
715 }
716 bit_cost_before = VP8LHistogramEstimateBits(histo);
717
718 VP8LHistogramInit(histo, 1);
719 for (i = 0; i < width * height; ++i) {
720 const uint32_t c = argb[i];
721 const int green = (c >> 8) & 0xff;
722 ++histo->red_[((c >> 16) - green) & 0xff];
723 ++histo->blue_[((c >> 0) - green) & 0xff];
724 }
725 bit_cost_after = VP8LHistogramEstimateBits(histo);
726 VP8LFreeHistogram(histo);
727
728 // Check if subtracting green yields low entropy.
729 enc->use_subtract_green_ = (bit_cost_after < bit_cost_before);
730 if (enc->use_subtract_green_) {
731 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
732 VP8LWriteBits(bw, 2, SUBTRACT_GREEN);
733 VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
734 }
735 }
736 return VP8_ENC_OK;
737 } 1005 }
738 1006
739 static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc, 1007 static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
740 int width, int height, int quality, 1008 int width, int height,
1009 int quality, int low_effort,
741 VP8LBitWriter* const bw) { 1010 VP8LBitWriter* const bw) {
742 const int pred_bits = enc->transform_bits_; 1011 const int pred_bits = enc->transform_bits_;
743 const int transform_width = VP8LSubSampleSize(width, pred_bits); 1012 const int transform_width = VP8LSubSampleSize(width, pred_bits);
744 const int transform_height = VP8LSubSampleSize(height, pred_bits); 1013 const int transform_height = VP8LSubSampleSize(height, pred_bits);
745 1014
746 VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->argb_scratch_, 1015 VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
747 enc->transform_data_); 1016 enc->argb_scratch_, enc->transform_data_,
748 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); 1017 enc->config_->exact);
749 VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM); 1018 VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1019 VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
750 assert(pred_bits >= 2); 1020 assert(pred_bits >= 2);
751 VP8LWriteBits(bw, 3, pred_bits - 2); 1021 VP8LPutBits(bw, pred_bits - 2, 3);
752 return EncodeImageNoHuffman(bw, enc->transform_data_, 1022 return EncodeImageNoHuffman(bw, enc->transform_data_,
753 (VP8LHashChain*)&enc->hash_chain_, 1023 (VP8LHashChain*)&enc->hash_chain_,
754 (VP8LBackwardRefs*)enc->refs_, // cast const away 1024 (VP8LBackwardRefs*)enc->refs_, // cast const away
755 transform_width, transform_height, 1025 transform_width, transform_height,
756 quality); 1026 quality);
757 } 1027 }
758 1028
759 static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, 1029 static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
760 int width, int height, 1030 int width, int height,
761 int quality, 1031 int quality,
762 VP8LBitWriter* const bw) { 1032 VP8LBitWriter* const bw) {
763 const int ccolor_transform_bits = enc->transform_bits_; 1033 const int ccolor_transform_bits = enc->transform_bits_;
764 const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); 1034 const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
765 const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); 1035 const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
766 1036
767 VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality, 1037 VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality,
768 enc->argb_, enc->transform_data_); 1038 enc->argb_, enc->transform_data_);
769 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); 1039 VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
770 VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM); 1040 VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2);
771 assert(ccolor_transform_bits >= 2); 1041 assert(ccolor_transform_bits >= 2);
772 VP8LWriteBits(bw, 3, ccolor_transform_bits - 2); 1042 VP8LPutBits(bw, ccolor_transform_bits - 2, 3);
773 return EncodeImageNoHuffman(bw, enc->transform_data_, 1043 return EncodeImageNoHuffman(bw, enc->transform_data_,
774 (VP8LHashChain*)&enc->hash_chain_, 1044 (VP8LHashChain*)&enc->hash_chain_,
775 (VP8LBackwardRefs*)enc->refs_, // cast const away 1045 (VP8LBackwardRefs*)enc->refs_, // cast const away
776 transform_width, transform_height, 1046 transform_width, transform_height,
777 quality); 1047 quality);
778 } 1048 }
779 1049
780 // ----------------------------------------------------------------------------- 1050 // -----------------------------------------------------------------------------
781 1051
782 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic, 1052 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
783 size_t riff_size, size_t vp8l_size) { 1053 size_t riff_size, size_t vp8l_size) {
784 uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { 1054 uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
785 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', 1055 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
786 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, 1056 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
787 }; 1057 };
788 PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); 1058 PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
789 PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size); 1059 PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
790 if (!pic->writer(riff, sizeof(riff), pic)) { 1060 if (!pic->writer(riff, sizeof(riff), pic)) {
791 return VP8_ENC_ERROR_BAD_WRITE; 1061 return VP8_ENC_ERROR_BAD_WRITE;
792 } 1062 }
793 return VP8_ENC_OK; 1063 return VP8_ENC_OK;
794 } 1064 }
795 1065
796 static int WriteImageSize(const WebPPicture* const pic, 1066 static int WriteImageSize(const WebPPicture* const pic,
797 VP8LBitWriter* const bw) { 1067 VP8LBitWriter* const bw) {
798 const int width = pic->width - 1; 1068 const int width = pic->width - 1;
799 const int height = pic->height - 1; 1069 const int height = pic->height - 1;
800 assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION); 1070 assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
801 1071
802 VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, width); 1072 VP8LPutBits(bw, width, VP8L_IMAGE_SIZE_BITS);
803 VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, height); 1073 VP8LPutBits(bw, height, VP8L_IMAGE_SIZE_BITS);
804 return !bw->error_; 1074 return !bw->error_;
805 } 1075 }
806 1076
807 static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) { 1077 static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
808 VP8LWriteBits(bw, 1, has_alpha); 1078 VP8LPutBits(bw, has_alpha, 1);
809 VP8LWriteBits(bw, VP8L_VERSION_BITS, VP8L_VERSION); 1079 VP8LPutBits(bw, VP8L_VERSION, VP8L_VERSION_BITS);
810 return !bw->error_; 1080 return !bw->error_;
811 } 1081 }
812 1082
813 static WebPEncodingError WriteImage(const WebPPicture* const pic, 1083 static WebPEncodingError WriteImage(const WebPPicture* const pic,
814 VP8LBitWriter* const bw, 1084 VP8LBitWriter* const bw,
815 size_t* const coded_size) { 1085 size_t* const coded_size) {
816 WebPEncodingError err = VP8_ENC_OK; 1086 WebPEncodingError err = VP8_ENC_OK;
817 const uint8_t* const webpll_data = VP8LBitWriterFinish(bw); 1087 const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
818 const size_t webpll_size = VP8LBitWriterNumBytes(bw); 1088 const size_t webpll_size = VP8LBitWriterNumBytes(bw);
819 const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size; 1089 const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
(...skipping 19 matching lines...) Expand all
839 return VP8_ENC_OK; 1109 return VP8_ENC_OK;
840 1110
841 Error: 1111 Error:
842 return err; 1112 return err;
843 } 1113 }
844 1114
845 // ----------------------------------------------------------------------------- 1115 // -----------------------------------------------------------------------------
846 1116
847 // Allocates the memory for argb (W x H) buffer, 2 rows of context for 1117 // Allocates the memory for argb (W x H) buffer, 2 rows of context for
848 // prediction and transform data. 1118 // prediction and transform data.
1119 // Flags influencing the memory allocated:
1120 // enc->transform_bits_
1121 // enc->use_predict_, enc->use_cross_color_
849 static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, 1122 static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
850 int width, int height) { 1123 int width, int height) {
851 WebPEncodingError err = VP8_ENC_OK; 1124 WebPEncodingError err = VP8_ENC_OK;
852 const int tile_size = 1 << enc->transform_bits_; 1125 if (enc->argb_ == NULL) {
853 const uint64_t image_size = width * height; 1126 const int tile_size = 1 << enc->transform_bits_;
854 const uint64_t argb_scratch_size = tile_size * width + width; 1127 const uint64_t image_size = width * height;
855 const int transform_data_size = 1128 // Ensure enough size for tiles, as well as for two scanlines and two
856 VP8LSubSampleSize(width, enc->transform_bits_) * 1129 // extra pixels for CopyImageWithPrediction.
857 VP8LSubSampleSize(height, enc->transform_bits_); 1130 const uint64_t argb_scratch_size =
858 const uint64_t total_size = 1131 enc->use_predict_ ? tile_size * width + width + 2 : 0;
859 image_size + argb_scratch_size + (uint64_t)transform_data_size; 1132 const int transform_data_size =
860 uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem)); 1133 (enc->use_predict_ || enc->use_cross_color_)
861 if (mem == NULL) { 1134 ? VP8LSubSampleSize(width, enc->transform_bits_) *
862 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1135 VP8LSubSampleSize(height, enc->transform_bits_)
863 goto Error; 1136 : 0;
1137 const uint64_t total_size =
1138 image_size + WEBP_ALIGN_CST +
1139 argb_scratch_size + WEBP_ALIGN_CST +
1140 (uint64_t)transform_data_size;
1141 uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem));
1142 if (mem == NULL) {
1143 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1144 goto Error;
1145 }
1146 enc->argb_ = mem;
1147 mem = (uint32_t*)WEBP_ALIGN(mem + image_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;
864 } 1152 }
865 enc->argb_ = mem;
866 mem += image_size;
867 enc->argb_scratch_ = mem;
868 mem += argb_scratch_size;
869 enc->transform_data_ = mem;
870 enc->current_width_ = width;
871
872 Error: 1153 Error:
873 return err; 1154 return err;
874 } 1155 }
875 1156
876 static void ApplyPalette(uint32_t* src, uint32_t* dst, 1157 static void ClearTransformBuffer(VP8LEncoder* const enc) {
877 uint32_t src_stride, uint32_t dst_stride, 1158 WebPSafeFree(enc->argb_);
878 const uint32_t* palette, int palette_size, 1159 enc->argb_ = NULL;
879 int width, int height, int xbits, uint8_t* row) { 1160 }
1161
1162 static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
1163 WebPEncodingError err = VP8_ENC_OK;
1164 const WebPPicture* const picture = enc->pic_;
1165 const int width = picture->width;
1166 const int height = picture->height;
1167 int y;
1168 err = AllocateTransformBuffer(enc, width, height);
1169 if (err != VP8_ENC_OK) return err;
1170 for (y = 0; y < height; ++y) {
1171 memcpy(enc->argb_ + y * width,
1172 picture->argb + y * picture->argb_stride,
1173 width * sizeof(*enc->argb_));
1174 }
1175 assert(enc->current_width_ == width);
1176 return VP8_ENC_OK;
1177 }
1178
1179 // -----------------------------------------------------------------------------
1180
1181 static void MapToPalette(const uint32_t palette[], int num_colors,
1182 uint32_t* const last_pix, int* const last_idx,
1183 const uint32_t* src, uint8_t* dst, int width) {
1184 int x;
1185 int prev_idx = *last_idx;
1186 uint32_t prev_pix = *last_pix;
1187 for (x = 0; x < width; ++x) {
1188 const uint32_t pix = src[x];
1189 if (pix != prev_pix) {
1190 int i;
1191 for (i = 0; i < num_colors; ++i) {
1192 if (pix == palette[i]) {
1193 prev_idx = i;
1194 prev_pix = pix;
1195 break;
1196 }
1197 }
1198 }
1199 dst[x] = prev_idx;
1200 }
1201 *last_idx = prev_idx;
1202 *last_pix = prev_pix;
1203 }
1204
1205 // Remap argb values in src[] to packed palettes entries in dst[]
1206 // using 'row' as a temporary buffer of size 'width'.
1207 // We assume that all src[] values have a corresponding entry in the palette.
1208 // Note: src[] can be the same as dst[]
1209 static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride,
1210 uint32_t* dst, uint32_t dst_stride,
1211 const uint32_t* palette, int palette_size,
1212 int width, int height, int xbits) {
1213 // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be
1214 // made to work in-place.
1215 uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
880 int i, x, y; 1216 int i, x, y;
881 int use_LUT = 1; 1217 int use_LUT = 1;
1218
1219 if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
882 for (i = 0; i < palette_size; ++i) { 1220 for (i = 0; i < palette_size; ++i) {
883 if ((palette[i] & 0xffff00ffu) != 0) { 1221 if ((palette[i] & 0xffff00ffu) != 0) {
884 use_LUT = 0; 1222 use_LUT = 0;
885 break; 1223 break;
886 } 1224 }
887 } 1225 }
888 1226
889 if (use_LUT) { 1227 if (use_LUT) {
890 uint8_t inv_palette[MAX_PALETTE_SIZE] = { 0 }; 1228 uint8_t inv_palette[MAX_PALETTE_SIZE] = { 0 };
891 for (i = 0; i < palette_size; ++i) { 1229 for (i = 0; i < palette_size; ++i) {
892 const int color = (palette[i] >> 8) & 0xff; 1230 const int color = (palette[i] >> 8) & 0xff;
893 inv_palette[color] = i; 1231 inv_palette[color] = i;
894 } 1232 }
895 for (y = 0; y < height; ++y) { 1233 for (y = 0; y < height; ++y) {
896 for (x = 0; x < width; ++x) { 1234 for (x = 0; x < width; ++x) {
897 const int color = (src[x] >> 8) & 0xff; 1235 const int color = (src[x] >> 8) & 0xff;
898 row[x] = inv_palette[color]; 1236 tmp_row[x] = inv_palette[color];
899 } 1237 }
900 VP8LBundleColorMap(row, width, xbits, dst); 1238 VP8LBundleColorMap(tmp_row, width, xbits, dst);
901 src += src_stride; 1239 src += src_stride;
902 dst += dst_stride; 1240 dst += dst_stride;
903 } 1241 }
904 } else { 1242 } else {
905 // Use 1 pixel cache for ARGB pixels. 1243 // Use 1 pixel cache for ARGB pixels.
906 uint32_t last_pix = palette[0]; 1244 uint32_t last_pix = palette[0];
907 int last_idx = 0; 1245 int last_idx = 0;
908 for (y = 0; y < height; ++y) { 1246 for (y = 0; y < height; ++y) {
909 for (x = 0; x < width; ++x) { 1247 MapToPalette(palette, palette_size, &last_pix, &last_idx,
910 const uint32_t pix = src[x]; 1248 src, tmp_row, width);
911 if (pix != last_pix) { 1249 VP8LBundleColorMap(tmp_row, width, xbits, dst);
912 for (i = 0; i < palette_size; ++i) {
913 if (pix == palette[i]) {
914 last_idx = i;
915 last_pix = pix;
916 break;
917 }
918 }
919 }
920 row[x] = last_idx;
921 }
922 VP8LBundleColorMap(row, width, xbits, dst);
923 src += src_stride; 1250 src += src_stride;
924 dst += dst_stride; 1251 dst += dst_stride;
925 } 1252 }
926 } 1253 }
1254 WebPSafeFree(tmp_row);
1255 return VP8_ENC_OK;
927 } 1256 }
928 1257
929 // Note: Expects "enc->palette_" to be set properly. 1258 // Note: Expects "enc->palette_" to be set properly.
930 // Also, "enc->palette_" will be modified after this call and should not be used 1259 static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc,
931 // later. 1260 int in_place) {
932 static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
933 VP8LEncoder* const enc, int quality) {
934 WebPEncodingError err = VP8_ENC_OK; 1261 WebPEncodingError err = VP8_ENC_OK;
935 int i;
936 const WebPPicture* const pic = enc->pic_; 1262 const WebPPicture* const pic = enc->pic_;
937 uint32_t* src = pic->argb;
938 uint32_t* dst;
939 const int width = pic->width; 1263 const int width = pic->width;
940 const int height = pic->height; 1264 const int height = pic->height;
941 uint32_t* const palette = enc->palette_; 1265 const uint32_t* const palette = enc->palette_;
1266 const uint32_t* src = in_place ? enc->argb_ : pic->argb;
1267 const int src_stride = in_place ? enc->current_width_ : pic->argb_stride;
942 const int palette_size = enc->palette_size_; 1268 const int palette_size = enc->palette_size_;
943 uint8_t* row = NULL;
944 int xbits; 1269 int xbits;
945 1270
946 // Replace each input pixel by corresponding palette index. 1271 // Replace each input pixel by corresponding palette index.
947 // This is done line by line. 1272 // This is done line by line.
948 if (palette_size <= 4) { 1273 if (palette_size <= 4) {
949 xbits = (palette_size <= 2) ? 3 : 2; 1274 xbits = (palette_size <= 2) ? 3 : 2;
950 } else { 1275 } else {
951 xbits = (palette_size <= 16) ? 1 : 0; 1276 xbits = (palette_size <= 16) ? 1 : 0;
952 } 1277 }
953 1278
954 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height); 1279 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
955 if (err != VP8_ENC_OK) goto Error; 1280 if (err != VP8_ENC_OK) return err;
956 dst = enc->argb_;
957 1281
958 row = (uint8_t*)WebPSafeMalloc(width, sizeof(*row)); 1282 err = ApplyPalette(src, src_stride,
959 if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; 1283 enc->argb_, enc->current_width_,
960 1284 palette, palette_size, width, height, xbits);
961 ApplyPalette(src, dst, pic->argb_stride, enc->current_width_,
962 palette, palette_size, width, height, xbits, row);
963
964 // Save palette to bitstream.
965 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
966 VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM);
967 assert(palette_size >= 1);
968 VP8LWriteBits(bw, 8, palette_size - 1);
969 for (i = palette_size - 1; i >= 1; --i) {
970 palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
971 }
972 err = EncodeImageNoHuffman(bw, palette, &enc->hash_chain_, enc->refs_,
973 palette_size, 1, quality);
974
975 Error:
976 WebPSafeFree(row);
977 return err; 1285 return err;
978 } 1286 }
979 1287
980 // ----------------------------------------------------------------------------- 1288 // Save palette_[] to bitstream.
981 1289 static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
982 static int GetHistoBits(int method, int use_palette, int width, int height) { 1290 VP8LEncoder* const enc) {
983 const int hist_size = VP8LGetHistogramSize(MAX_COLOR_CACHE_BITS); 1291 int i;
984 // Make tile size a function of encoding method (Range: 0 to 6). 1292 uint32_t tmp_palette[MAX_PALETTE_SIZE];
985 int histo_bits = (use_palette ? 9 : 7) - method; 1293 const int palette_size = enc->palette_size_;
986 while (1) { 1294 const uint32_t* const palette = enc->palette_;
987 const int huff_image_size = VP8LSubSampleSize(width, histo_bits) * 1295 VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
988 VP8LSubSampleSize(height, histo_bits); 1296 VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2);
989 if ((uint64_t)huff_image_size * hist_size <= MAX_HUFF_IMAGE_SIZE) break; 1297 assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE);
990 ++histo_bits; 1298 VP8LPutBits(bw, palette_size - 1, 8);
1299 for (i = palette_size - 1; i >= 1; --i) {
1300 tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
991 } 1301 }
992 return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS : 1302 tmp_palette[0] = palette[0];
993 (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits; 1303 return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, enc->refs_,
1304 palette_size, 1, 20 /* quality */);
994 } 1305 }
995 1306
996 static int GetTransformBits(int method, int histo_bits) { 1307 #ifdef WEBP_EXPERIMENTAL_FEATURES
997 const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5; 1308
998 return (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits; 1309 static WebPEncodingError EncodeDeltaPalettePredictorImage(
1310 VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality) {
1311 const WebPPicture* const pic = enc->pic_;
1312 const int width = pic->width;
1313 const int height = pic->height;
1314
1315 const int pred_bits = 5;
1316 const int transform_width = VP8LSubSampleSize(width, pred_bits);
1317 const int transform_height = VP8LSubSampleSize(height, pred_bits);
1318 const int pred = 7; // default is Predictor7 (Top/Left Average)
1319 const int tiles_per_row = VP8LSubSampleSize(width, pred_bits);
1320 const int tiles_per_col = VP8LSubSampleSize(height, pred_bits);
1321 uint32_t* predictors;
1322 int tile_x, tile_y;
1323 WebPEncodingError err = VP8_ENC_OK;
1324
1325 predictors = (uint32_t*)WebPSafeMalloc(tiles_per_col * tiles_per_row,
1326 sizeof(*predictors));
1327 if (predictors == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
1328
1329 for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
1330 for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
1331 predictors[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
1332 }
1333 }
1334
1335 VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
1336 VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
1337 VP8LPutBits(bw, pred_bits - 2, 3);
1338 err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_,
1339 (VP8LBackwardRefs*)enc->refs_, // cast const away
1340 transform_width, transform_height,
1341 quality);
1342 WebPSafeFree(predictors);
1343 return err;
999 } 1344 }
1000 1345
1001 static int GetCacheBits(float quality) { 1346 #endif // WEBP_EXPERIMENTAL_FEATURES
1002 return (quality <= 25.f) ? 0 : 7;
1003 }
1004
1005 static void FinishEncParams(VP8LEncoder* const enc) {
1006 const WebPConfig* const config = enc->config_;
1007 const WebPPicture* const pic = enc->pic_;
1008 const int method = config->method;
1009 const float quality = config->quality;
1010 const int use_palette = enc->use_palette_;
1011 enc->histo_bits_ = GetHistoBits(method, use_palette, pic->width, pic->height);
1012 enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_);
1013 enc->cache_bits_ = GetCacheBits(quality);
1014 }
1015 1347
1016 // ----------------------------------------------------------------------------- 1348 // -----------------------------------------------------------------------------
1017 // VP8LEncoder 1349 // VP8LEncoder
1018 1350
1019 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, 1351 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
1020 const WebPPicture* const picture) { 1352 const WebPPicture* const picture) {
1021 VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc)); 1353 VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc));
1022 if (enc == NULL) { 1354 if (enc == NULL) {
1023 WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); 1355 WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
1024 return NULL; 1356 return NULL;
1025 } 1357 }
1026 enc->config_ = config; 1358 enc->config_ = config;
1027 enc->pic_ = picture; 1359 enc->pic_ = picture;
1028 1360
1029 VP8LDspInit(); 1361 VP8LEncDspInit();
1030 1362
1031 return enc; 1363 return enc;
1032 } 1364 }
1033 1365
1034 static void VP8LEncoderDelete(VP8LEncoder* enc) { 1366 static void VP8LEncoderDelete(VP8LEncoder* enc) {
1035 if (enc != NULL) { 1367 if (enc != NULL) {
1036 VP8LHashChainClear(&enc->hash_chain_); 1368 VP8LHashChainClear(&enc->hash_chain_);
1037 VP8LBackwardRefsClear(&enc->refs_[0]); 1369 VP8LBackwardRefsClear(&enc->refs_[0]);
1038 VP8LBackwardRefsClear(&enc->refs_[1]); 1370 VP8LBackwardRefsClear(&enc->refs_[1]);
1039 WebPSafeFree(enc->argb_); 1371 ClearTransformBuffer(enc);
1040 WebPSafeFree(enc); 1372 WebPSafeFree(enc);
1041 } 1373 }
1042 } 1374 }
1043 1375
1044 // ----------------------------------------------------------------------------- 1376 // -----------------------------------------------------------------------------
1045 // Main call 1377 // Main call
1046 1378
1047 WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, 1379 WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
1048 const WebPPicture* const picture, 1380 const WebPPicture* const picture,
1049 VP8LBitWriter* const bw) { 1381 VP8LBitWriter* const bw) {
1050 WebPEncodingError err = VP8_ENC_OK; 1382 WebPEncodingError err = VP8_ENC_OK;
1051 const int quality = (int)config->quality; 1383 const int quality = (int)config->quality;
1384 const int low_effort = (config->method == 0);
1052 const int width = picture->width; 1385 const int width = picture->width;
1053 const int height = picture->height; 1386 const int height = picture->height;
1054 VP8LEncoder* const enc = VP8LEncoderNew(config, picture); 1387 VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
1055 const size_t byte_position = VP8LBitWriterNumBytes(bw); 1388 const size_t byte_position = VP8LBitWriterNumBytes(bw);
1389 int use_near_lossless = 0;
1390 int hdr_size = 0;
1391 int data_size = 0;
1392 int use_delta_palettization = 0;
1056 1393
1057 if (enc == NULL) { 1394 if (enc == NULL) {
1058 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1395 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1059 goto Error; 1396 goto Error;
1060 } 1397 }
1061 1398
1062 // --------------------------------------------------------------------------- 1399 // ---------------------------------------------------------------------------
1063 // Analyze image (entropy, num_palettes etc) 1400 // Analyze image (entropy, num_palettes etc)
1064 1401
1065 if (!AnalyzeAndInit(enc, config->image_hint)) { 1402 if (!AnalyzeAndInit(enc)) {
1066 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1403 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1067 goto Error; 1404 goto Error;
1068 } 1405 }
1069 1406
1070 FinishEncParams(enc); 1407 // Apply near-lossless preprocessing.
1071 1408 use_near_lossless = !enc->use_palette_ && (config->near_lossless < 100);
1072 if (enc->use_palette_) { 1409 if (use_near_lossless) {
1073 err = EncodePalette(bw, enc, quality); 1410 if (!VP8ApplyNearLossless(width, height, picture->argb,
1074 if (err != VP8_ENC_OK) goto Error; 1411 config->near_lossless)) {
1075 // Color cache is disabled for palette.
1076 enc->cache_bits_ = 0;
1077 }
1078
1079 // In case image is not packed.
1080 if (enc->argb_ == NULL) {
1081 int y;
1082 err = AllocateTransformBuffer(enc, width, height);
1083 if (err != VP8_ENC_OK) goto Error;
1084 assert(enc->argb_ != NULL);
1085 for (y = 0; y < height; ++y) {
1086 memcpy(enc->argb_ + y * width,
1087 picture->argb + y * picture->argb_stride,
1088 width * sizeof(*enc->argb_));
1089 }
1090 enc->current_width_ = width;
1091 }
1092
1093 // ---------------------------------------------------------------------------
1094 // Apply transforms and write transform data.
1095
1096 err = EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw);
1097 if (err != VP8_ENC_OK) goto Error;
1098
1099 if (enc->use_predict_) {
1100 err = ApplyPredictFilter(enc, enc->current_width_, height, quality, bw);
1101 if (err != VP8_ENC_OK) goto Error;
1102 }
1103
1104 if (enc->use_cross_color_) {
1105 err = ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw);
1106 if (err != VP8_ENC_OK) goto Error;
1107 }
1108
1109 VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms.
1110
1111 // ---------------------------------------------------------------------------
1112 // Estimate the color cache size.
1113
1114 if (enc->cache_bits_ > 0) {
1115 if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_,
1116 height, quality, &enc->hash_chain_,
1117 &enc->refs_[0], &enc->cache_bits_)) {
1118 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1412 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1119 goto Error; 1413 goto Error;
1120 } 1414 }
1121 } 1415 }
1122 1416
1417 #ifdef WEBP_EXPERIMENTAL_FEATURES
1418 if (config->delta_palettization) {
1419 enc->use_predict_ = 1;
1420 enc->use_cross_color_ = 0;
1421 enc->use_subtract_green_ = 0;
1422 enc->use_palette_ = 1;
1423 err = MakeInputImageCopy(enc);
1424 if (err != VP8_ENC_OK) goto Error;
1425 err = WebPSearchOptimalDeltaPalette(enc);
1426 if (err != VP8_ENC_OK) goto Error;
1427 if (enc->use_palette_) {
1428 err = AllocateTransformBuffer(enc, width, height);
1429 if (err != VP8_ENC_OK) goto Error;
1430 err = EncodeDeltaPalettePredictorImage(bw, enc, quality);
1431 if (err != VP8_ENC_OK) goto Error;
1432 use_delta_palettization = 1;
1433 }
1434 }
1435 #endif // WEBP_EXPERIMENTAL_FEATURES
1436
1437 // Encode palette
1438 if (enc->use_palette_) {
1439 err = EncodePalette(bw, enc);
1440 if (err != VP8_ENC_OK) goto Error;
1441 err = MapImageFromPalette(enc, use_delta_palettization);
1442 if (err != VP8_ENC_OK) goto Error;
1443 }
1444 if (!use_delta_palettization) {
1445 // In case image is not packed.
1446 if (enc->argb_ == NULL) {
1447 err = MakeInputImageCopy(enc);
1448 if (err != VP8_ENC_OK) goto Error;
1449 }
1450
1451 // -------------------------------------------------------------------------
1452 // Apply transforms and write transform data.
1453
1454 if (enc->use_subtract_green_) {
1455 ApplySubtractGreen(enc, enc->current_width_, height, bw);
1456 }
1457
1458 if (enc->use_predict_) {
1459 err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
1460 low_effort, bw);
1461 if (err != VP8_ENC_OK) goto Error;
1462 }
1463
1464 if (enc->use_cross_color_) {
1465 err = ApplyCrossColorFilter(enc, enc->current_width_,
1466 height, quality, bw);
1467 if (err != VP8_ENC_OK) goto Error;
1468 }
1469 }
1470
1471 VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms.
1472
1123 // --------------------------------------------------------------------------- 1473 // ---------------------------------------------------------------------------
1124 // Encode and write the transformed image. 1474 // Encode and write the transformed image.
1125
1126 err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_, 1475 err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
1127 enc->current_width_, height, quality, 1476 enc->current_width_, height, quality, low_effort,
1128 enc->cache_bits_, enc->histo_bits_); 1477 &enc->cache_bits_, enc->histo_bits_, byte_position,
1478 &hdr_size, &data_size);
1129 if (err != VP8_ENC_OK) goto Error; 1479 if (err != VP8_ENC_OK) goto Error;
1130 1480
1131 if (picture->stats != NULL) { 1481 if (picture->stats != NULL) {
1132 WebPAuxStats* const stats = picture->stats; 1482 WebPAuxStats* const stats = picture->stats;
1133 stats->lossless_features = 0; 1483 stats->lossless_features = 0;
1134 if (enc->use_predict_) stats->lossless_features |= 1; 1484 if (enc->use_predict_) stats->lossless_features |= 1;
1135 if (enc->use_cross_color_) stats->lossless_features |= 2; 1485 if (enc->use_cross_color_) stats->lossless_features |= 2;
1136 if (enc->use_subtract_green_) stats->lossless_features |= 4; 1486 if (enc->use_subtract_green_) stats->lossless_features |= 4;
1137 if (enc->use_palette_) stats->lossless_features |= 8; 1487 if (enc->use_palette_) stats->lossless_features |= 8;
1138 stats->histogram_bits = enc->histo_bits_; 1488 stats->histogram_bits = enc->histo_bits_;
1139 stats->transform_bits = enc->transform_bits_; 1489 stats->transform_bits = enc->transform_bits_;
1140 stats->cache_bits = enc->cache_bits_; 1490 stats->cache_bits = enc->cache_bits_;
1141 stats->palette_size = enc->palette_size_; 1491 stats->palette_size = enc->palette_size_;
1142 stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position); 1492 stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position);
1493 stats->lossless_hdr_size = hdr_size;
1494 stats->lossless_data_size = data_size;
1143 } 1495 }
1144 1496
1145 Error: 1497 Error:
1146 VP8LEncoderDelete(enc); 1498 VP8LEncoderDelete(enc);
1147 return err; 1499 return err;
1148 } 1500 }
1149 1501
1150 int VP8LEncodeImage(const WebPConfig* const config, 1502 int VP8LEncodeImage(const WebPConfig* const config,
1151 const WebPPicture* const picture) { 1503 const WebPPicture* const picture) {
1152 int width, height; 1504 int width, height;
(...skipping 10 matching lines...) Expand all
1163 err = VP8_ENC_ERROR_NULL_PARAMETER; 1515 err = VP8_ENC_ERROR_NULL_PARAMETER;
1164 WebPEncodingSetError(picture, err); 1516 WebPEncodingSetError(picture, err);
1165 return 0; 1517 return 0;
1166 } 1518 }
1167 1519
1168 width = picture->width; 1520 width = picture->width;
1169 height = picture->height; 1521 height = picture->height;
1170 // Initialize BitWriter with size corresponding to 16 bpp to photo images and 1522 // Initialize BitWriter with size corresponding to 16 bpp to photo images and
1171 // 8 bpp for graphical images. 1523 // 8 bpp for graphical images.
1172 initial_size = (config->image_hint == WEBP_HINT_GRAPH) ? 1524 initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
1173 width * height : width * height * 2; 1525 width * height : width * height * 2;
1174 if (!VP8LBitWriterInit(&bw, initial_size)) { 1526 if (!VP8LBitWriterInit(&bw, initial_size)) {
1175 err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1527 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1176 goto Error; 1528 goto Error;
1177 } 1529 }
1178 1530
1179 if (!WebPReportProgress(picture, 1, &percent)) { 1531 if (!WebPReportProgress(picture, 1, &percent)) {
1180 UserAbort: 1532 UserAbort:
1181 err = VP8_ENC_ERROR_USER_ABORT; 1533 err = VP8_ENC_ERROR_USER_ABORT;
1182 goto Error; 1534 goto Error;
1183 } 1535 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1227 } 1579 }
1228 1580
1229 if (picture->extra_info != NULL) { 1581 if (picture->extra_info != NULL) {
1230 const int mb_w = (width + 15) >> 4; 1582 const int mb_w = (width + 15) >> 4;
1231 const int mb_h = (height + 15) >> 4; 1583 const int mb_h = (height + 15) >> 4;
1232 memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info)); 1584 memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
1233 } 1585 }
1234 1586
1235 Error: 1587 Error:
1236 if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY; 1588 if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1237 VP8LBitWriterDestroy(&bw); 1589 VP8LBitWriterWipeOut(&bw);
1238 if (err != VP8_ENC_OK) { 1590 if (err != VP8_ENC_OK) {
1239 WebPEncodingSetError(picture, err); 1591 WebPEncodingSetError(picture, err);
1240 return 0; 1592 return 0;
1241 } 1593 }
1242 return 1; 1594 return 1;
1243 } 1595 }
1244 1596
1245 //------------------------------------------------------------------------------ 1597 //------------------------------------------------------------------------------
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698