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

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

Issue 10832153: libwebp: update snapshot to v0.2.0-rc1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // -----------------------------------------------------------------------------
7 //
8 // main entry for the lossless encoder.
9 //
10 // Author: Vikas Arora (vikaas.arora@gmail.com)
11 //
12
13 #include <assert.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 #include "./backward_references.h"
18 #include "./vp8enci.h"
19 #include "./vp8li.h"
20 #include "../dsp/lossless.h"
21 #include "../utils/bit_writer.h"
22 #include "../utils/huffman_encode.h"
23 #include "../utils/utils.h"
24 #include "../webp/format_constants.h"
25
26 #if defined(__cplusplus) || defined(c_plusplus)
27 extern "C" {
28 #endif
29
30 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
31 #define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024)
32
33 // -----------------------------------------------------------------------------
34 // Palette
35
36 static int CompareColors(const void* p1, const void* p2) {
37 const uint32_t a = *(const uint32_t*)p1;
38 const uint32_t b = *(const uint32_t*)p2;
39 return (a < b) ? -1 : (a > b) ? 1 : 0;
40 }
41
42 // 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.
44 static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
45 uint32_t palette[MAX_PALETTE_SIZE],
46 int* const palette_size) {
47 int i, x, y, key;
48 int num_colors = 0;
49 uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
50 uint32_t colors[MAX_PALETTE_SIZE * 4];
51 static const uint32_t kHashMul = 0x1e35a7bd;
52 const uint32_t* argb = pic->argb;
53 const int width = pic->width;
54 const int height = pic->height;
55 uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
56
57 for (y = 0; y < height; ++y) {
58 for (x = 0; x < width; ++x) {
59 if (argb[x] == last_pix) {
60 continue;
61 }
62 last_pix = argb[x];
63 key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT;
64 while (1) {
65 if (!in_use[key]) {
66 colors[key] = last_pix;
67 in_use[key] = 1;
68 ++num_colors;
69 if (num_colors > MAX_PALETTE_SIZE) {
70 return 0;
71 }
72 break;
73 } else if (colors[key] == last_pix) {
74 // The color is already there.
75 break;
76 } else {
77 // Some other color sits there.
78 // Do linear conflict resolution.
79 ++key;
80 key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer.
81 }
82 }
83 }
84 argb += pic->argb_stride;
85 }
86
87 // TODO(skal): could we reuse in_use[] to speed up ApplyPalette()?
88 num_colors = 0;
89 for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
90 if (in_use[i]) {
91 palette[num_colors] = colors[i];
92 ++num_colors;
93 }
94 }
95
96 qsort(palette, num_colors, sizeof(*palette), CompareColors);
97 *palette_size = num_colors;
98 return 1;
99 }
100
101 static int AnalyzeEntropy(const WebPPicture* const pic,
102 double* const nonpredicted_bits,
103 double* const predicted_bits) {
104 int x, y;
105 const uint32_t* argb = pic->argb;
106 const uint32_t* last_line = NULL;
107 uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0
108
109 VP8LHistogram* nonpredicted = NULL;
110 VP8LHistogram* predicted =
111 (VP8LHistogram*)malloc(2 * sizeof(*predicted));
112 if (predicted == NULL) return 0;
113 nonpredicted = predicted + 1;
114
115 VP8LHistogramInit(predicted, 0);
116 VP8LHistogramInit(nonpredicted, 0);
117 for (y = 0; y < pic->height; ++y) {
118 for (x = 0; x < pic->width; ++x) {
119 const uint32_t pix = argb[x];
120 const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
121 if (pix_diff == 0) continue;
122 if (last_line != NULL && pix == last_line[x]) {
123 continue;
124 }
125 last_pix = pix;
126 {
127 const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
128 const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
129 VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token);
130 VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token);
131 }
132 }
133 last_line = argb;
134 argb += pic->argb_stride;
135 }
136 *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
137 *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
138 free(predicted);
139 return 1;
140 }
141
142 static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) {
143 const WebPPicture* const pic = enc->pic_;
144 assert(pic != NULL && pic->argb != NULL);
145
146 enc->use_palette_ = (image_hint == WEBP_HINT_GRAPH) ? 0 :
147 AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_);
148 if (!enc->use_palette_) {
149 if (image_hint == WEBP_HINT_DEFAULT) {
150 double non_pred_entropy, pred_entropy;
151 if (!AnalyzeEntropy(pic, &non_pred_entropy, &pred_entropy)) {
152 return 0;
153 }
154
155 if (pred_entropy < 0.95 * non_pred_entropy) {
156 enc->use_predict_ = 1;
157 enc->use_cross_color_ = 1;
158 }
159 } else if (image_hint == WEBP_HINT_PHOTO) {
160 enc->use_predict_ = 1;
161 enc->use_cross_color_ = 1;
162 }
163 }
164 return 1;
165 }
166
167 static int GetHuffBitLengthsAndCodes(
168 const VP8LHistogramSet* const histogram_image,
169 HuffmanTreeCode* const huffman_codes) {
170 int i, k;
171 int ok = 1;
172 uint64_t total_length_size = 0;
173 uint8_t* mem_buf = NULL;
174 const int histogram_image_size = histogram_image->size;
175
176 // Iterate over all histograms and get the aggregate number of codes used.
177 for (i = 0; i < histogram_image_size; ++i) {
178 const VP8LHistogram* const histo = histogram_image->histograms[i];
179 HuffmanTreeCode* const codes = &huffman_codes[5 * i];
180 for (k = 0; k < 5; ++k) {
181 const int num_symbols = (k == 0) ? VP8LHistogramNumCodes(histo)
182 : (k == 4) ? NUM_DISTANCE_CODES
183 : 256;
184 codes[k].num_symbols = num_symbols;
185 total_length_size += num_symbols;
186 }
187 }
188
189 // Allocate and Set Huffman codes.
190 {
191 uint16_t* codes;
192 uint8_t* lengths;
193 mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size,
194 sizeof(*lengths) + sizeof(*codes));
195 if (mem_buf == NULL) {
196 ok = 0;
197 goto End;
198 }
199 codes = (uint16_t*)mem_buf;
200 lengths = (uint8_t*)&codes[total_length_size];
201 for (i = 0; i < 5 * histogram_image_size; ++i) {
202 const int bit_length = huffman_codes[i].num_symbols;
203 huffman_codes[i].codes = codes;
204 huffman_codes[i].code_lengths = lengths;
205 codes += bit_length;
206 lengths += bit_length;
207 }
208 }
209
210 // Create Huffman trees.
211 for (i = 0; i < histogram_image_size; ++i) {
212 HuffmanTreeCode* const codes = &huffman_codes[5 * i];
213 VP8LHistogram* const histo = histogram_image->histograms[i];
214 ok = ok && VP8LCreateHuffmanTree(histo->literal_, 15, codes + 0);
215 ok = ok && VP8LCreateHuffmanTree(histo->red_, 15, codes + 1);
216 ok = ok && VP8LCreateHuffmanTree(histo->blue_, 15, codes + 2);
217 ok = ok && VP8LCreateHuffmanTree(histo->alpha_, 15, codes + 3);
218 ok = ok && VP8LCreateHuffmanTree(histo->distance_, 15, codes + 4);
219 }
220
221 End:
222 if (!ok) free(mem_buf);
223 return ok;
224 }
225
226 static void StoreHuffmanTreeOfHuffmanTreeToBitMask(
227 VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) {
228 // RFC 1951 will calm you down if you are worried about this funny sequence.
229 // This sequence is tuned from that, but more weighted for lower symbol count,
230 // and more spiking histograms.
231 static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = {
232 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
233 };
234 int i;
235 // Throw away trailing zeros:
236 int codes_to_store = CODE_LENGTH_CODES;
237 for (; codes_to_store > 4; --codes_to_store) {
238 if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
239 break;
240 }
241 }
242 VP8LWriteBits(bw, 4, codes_to_store - 4);
243 for (i = 0; i < codes_to_store; ++i) {
244 VP8LWriteBits(bw, 3, code_length_bitdepth[kStorageOrder[i]]);
245 }
246 }
247
248 static void ClearHuffmanTreeIfOnlyOneSymbol(
249 HuffmanTreeCode* const huffman_code) {
250 int k;
251 int count = 0;
252 for (k = 0; k < huffman_code->num_symbols; ++k) {
253 if (huffman_code->code_lengths[k] != 0) {
254 ++count;
255 if (count > 1) return;
256 }
257 }
258 for (k = 0; k < huffman_code->num_symbols; ++k) {
259 huffman_code->code_lengths[k] = 0;
260 huffman_code->codes[k] = 0;
261 }
262 }
263
264 static void StoreHuffmanTreeToBitMask(
265 VP8LBitWriter* const bw,
266 const HuffmanTreeToken* const tokens, const int num_tokens,
267 const HuffmanTreeCode* const huffman_code) {
268 int i;
269 for (i = 0; i < num_tokens; ++i) {
270 const int ix = tokens[i].code;
271 const int extra_bits = tokens[i].extra_bits;
272 VP8LWriteBits(bw, huffman_code->code_lengths[ix], huffman_code->codes[ix]);
273 switch (ix) {
274 case 16:
275 VP8LWriteBits(bw, 2, extra_bits);
276 break;
277 case 17:
278 VP8LWriteBits(bw, 3, extra_bits);
279 break;
280 case 18:
281 VP8LWriteBits(bw, 7, extra_bits);
282 break;
283 }
284 }
285 }
286
287 static int StoreFullHuffmanCode(VP8LBitWriter* const bw,
288 const HuffmanTreeCode* const tree) {
289 int ok = 0;
290 uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
291 uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
292 const int max_tokens = tree->num_symbols;
293 int num_tokens;
294 HuffmanTreeCode huffman_code;
295 HuffmanTreeToken* const tokens =
296 (HuffmanTreeToken*)WebPSafeMalloc((uint64_t)max_tokens, sizeof(*tokens));
297 if (tokens == NULL) return 0;
298
299 huffman_code.num_symbols = CODE_LENGTH_CODES;
300 huffman_code.code_lengths = code_length_bitdepth;
301 huffman_code.codes = code_length_bitdepth_symbols;
302
303 VP8LWriteBits(bw, 1, 0);
304 num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens);
305 {
306 int histogram[CODE_LENGTH_CODES] = { 0 };
307 int i;
308 for (i = 0; i < num_tokens; ++i) {
309 ++histogram[tokens[i].code];
310 }
311
312 if (!VP8LCreateHuffmanTree(histogram, 7, &huffman_code)) {
313 goto End;
314 }
315 }
316
317 StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
318 ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code);
319 {
320 int trailing_zero_bits = 0;
321 int trimmed_length = num_tokens;
322 int write_trimmed_length;
323 int length;
324 int i = num_tokens;
325 while (i-- > 0) {
326 const int ix = tokens[i].code;
327 if (ix == 0 || ix == 17 || ix == 18) {
328 --trimmed_length; // discount trailing zeros
329 trailing_zero_bits += code_length_bitdepth[ix];
330 if (ix == 17) {
331 trailing_zero_bits += 3;
332 } else if (ix == 18) {
333 trailing_zero_bits += 7;
334 }
335 } else {
336 break;
337 }
338 }
339 write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
340 length = write_trimmed_length ? trimmed_length : num_tokens;
341 VP8LWriteBits(bw, 1, write_trimmed_length);
342 if (write_trimmed_length) {
343 const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
344 const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
345 VP8LWriteBits(bw, 3, nbitpairs - 1);
346 assert(trimmed_length >= 2);
347 VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2);
348 }
349 StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
350 }
351 ok = 1;
352 End:
353 free(tokens);
354 return ok;
355 }
356
357 static int StoreHuffmanCode(VP8LBitWriter* const bw,
358 const HuffmanTreeCode* const huffman_code) {
359 int i;
360 int count = 0;
361 int symbols[2] = { 0, 0 };
362 const int kMaxBits = 8;
363 const int kMaxSymbol = 1 << kMaxBits;
364
365 // Check whether it's a small tree.
366 for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) {
367 if (huffman_code->code_lengths[i] != 0) {
368 if (count < 2) symbols[count] = i;
369 ++count;
370 }
371 }
372
373 if (count == 0) { // emit minimal tree for empty cases
374 // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
375 VP8LWriteBits(bw, 4, 0x01);
376 return 1;
377 } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
378 VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols.
379 VP8LWriteBits(bw, 1, count - 1);
380 if (symbols[0] <= 1) {
381 VP8LWriteBits(bw, 1, 0); // Code bit for small (1 bit) symbol value.
382 VP8LWriteBits(bw, 1, symbols[0]);
383 } else {
384 VP8LWriteBits(bw, 1, 1);
385 VP8LWriteBits(bw, 8, symbols[0]);
386 }
387 if (count == 2) {
388 VP8LWriteBits(bw, 8, symbols[1]);
389 }
390 return 1;
391 } else {
392 return StoreFullHuffmanCode(bw, huffman_code);
393 }
394 }
395
396 static void WriteHuffmanCode(VP8LBitWriter* const bw,
397 const HuffmanTreeCode* const code, int index) {
398 const int depth = code->code_lengths[index];
399 const int symbol = code->codes[index];
400 VP8LWriteBits(bw, depth, symbol);
401 }
402
403 static void StoreImageToBitMask(
404 VP8LBitWriter* const bw, int width, int histo_bits,
405 const VP8LBackwardRefs* const refs,
406 const uint16_t* histogram_symbols,
407 const HuffmanTreeCode* const huffman_codes) {
408 // x and y trace the position in the image.
409 int x = 0;
410 int y = 0;
411 const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
412 int i;
413 for (i = 0; i < refs->size; ++i) {
414 const PixOrCopy* const v = &refs->refs[i];
415 const int histogram_ix = histogram_symbols[histo_bits ?
416 (y >> histo_bits) * histo_xsize +
417 (x >> histo_bits) : 0];
418 const HuffmanTreeCode* const codes = huffman_codes + 5 * histogram_ix;
419 if (PixOrCopyIsCacheIdx(v)) {
420 const int code = PixOrCopyCacheIdx(v);
421 const int literal_ix = 256 + NUM_LENGTH_CODES + code;
422 WriteHuffmanCode(bw, codes, literal_ix);
423 } else if (PixOrCopyIsLiteral(v)) {
424 static const int order[] = { 1, 2, 0, 3 };
425 int k;
426 for (k = 0; k < 4; ++k) {
427 const int code = PixOrCopyLiteral(v, order[k]);
428 WriteHuffmanCode(bw, codes + k, code);
429 }
430 } else {
431 int bits, n_bits;
432 int code, distance;
433
434 PrefixEncode(v->len, &code, &n_bits, &bits);
435 WriteHuffmanCode(bw, codes, 256 + code);
436 VP8LWriteBits(bw, n_bits, bits);
437
438 distance = PixOrCopyDistance(v);
439 PrefixEncode(distance, &code, &n_bits, &bits);
440 WriteHuffmanCode(bw, codes + 4, code);
441 VP8LWriteBits(bw, n_bits, bits);
442 }
443 x += PixOrCopyLength(v);
444 while (x >= width) {
445 x -= width;
446 ++y;
447 }
448 }
449 }
450
451 // Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
452 static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
453 const uint32_t* const argb,
454 int width, int height, int quality) {
455 int i;
456 int ok = 0;
457 VP8LBackwardRefs refs;
458 HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
459 const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol
460 VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0);
461 if (histogram_image == NULL) return 0;
462
463 // Calculate backward references from ARGB image.
464 if (!VP8LGetBackwardReferences(width, height, argb, quality, 0, 1, &refs)) {
465 goto Error;
466 }
467 // Build histogram image and symbols from backward references.
468 VP8LHistogramStoreRefs(&refs, histogram_image->histograms[0]);
469
470 // Create Huffman bit lengths and codes for each histogram image.
471 assert(histogram_image->size == 1);
472 if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
473 goto Error;
474 }
475
476 // No color cache, no Huffman image.
477 VP8LWriteBits(bw, 1, 0);
478
479 // Store Huffman codes.
480 for (i = 0; i < 5; ++i) {
481 HuffmanTreeCode* const codes = &huffman_codes[i];
482 if (!StoreHuffmanCode(bw, codes)) {
483 goto Error;
484 }
485 ClearHuffmanTreeIfOnlyOneSymbol(codes);
486 }
487
488 // Store actual literals.
489 StoreImageToBitMask(bw, width, 0, &refs, histogram_symbols, huffman_codes);
490 ok = 1;
491
492 Error:
493 free(histogram_image);
494 VP8LClearBackwardRefs(&refs);
495 free(huffman_codes[0].codes);
496 return ok;
497 }
498
499 static int EncodeImageInternal(VP8LBitWriter* const bw,
500 const uint32_t* const argb,
501 int width, int height, int quality,
502 int cache_bits, int histogram_bits) {
503 int ok = 0;
504 const int use_2d_locality = 1;
505 const int use_color_cache = (cache_bits > 0);
506 const uint32_t histogram_image_xysize =
507 VP8LSubSampleSize(width, histogram_bits) *
508 VP8LSubSampleSize(height, histogram_bits);
509 VP8LHistogramSet* histogram_image =
510 VP8LAllocateHistogramSet(histogram_image_xysize, 0);
511 int histogram_image_size = 0;
512 size_t bit_array_size = 0;
513 HuffmanTreeCode* huffman_codes = NULL;
514 VP8LBackwardRefs refs;
515 uint16_t* const histogram_symbols =
516 (uint16_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
517 sizeof(*histogram_symbols));
518 assert(histogram_bits >= MIN_HUFFMAN_BITS);
519 assert(histogram_bits <= MAX_HUFFMAN_BITS);
520 if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
521
522 // Calculate backward references from ARGB image.
523 if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits,
524 use_2d_locality, &refs)) {
525 goto Error;
526 }
527 // Build histogram image and symbols from backward references.
528 if (!VP8LGetHistoImageSymbols(width, height, &refs,
529 quality, histogram_bits, cache_bits,
530 histogram_image,
531 histogram_symbols)) {
532 goto Error;
533 }
534 // Create Huffman bit lengths and codes for each histogram image.
535 histogram_image_size = histogram_image->size;
536 bit_array_size = 5 * histogram_image_size;
537 huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
538 sizeof(*huffman_codes));
539 if (huffman_codes == NULL ||
540 !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
541 goto Error;
542 }
543
544 // Color Cache parameters.
545 VP8LWriteBits(bw, 1, use_color_cache);
546 if (use_color_cache) {
547 VP8LWriteBits(bw, 4, cache_bits);
548 }
549
550 // Huffman image + meta huffman.
551 {
552 const int write_histogram_image = (histogram_image_size > 1);
553 VP8LWriteBits(bw, 1, write_histogram_image);
554 if (write_histogram_image) {
555 uint32_t* const histogram_argb =
556 (uint32_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
557 sizeof(*histogram_argb));
558 int max_index = 0;
559 uint32_t i;
560 if (histogram_argb == NULL) goto Error;
561 for (i = 0; i < histogram_image_xysize; ++i) {
562 const int index = histogram_symbols[i] & 0xffff;
563 histogram_argb[i] = 0xff000000 | (index << 8);
564 if (index >= max_index) {
565 max_index = index + 1;
566 }
567 }
568 histogram_image_size = max_index;
569
570 VP8LWriteBits(bw, 3, histogram_bits - 2);
571 ok = EncodeImageNoHuffman(bw, histogram_argb,
572 VP8LSubSampleSize(width, histogram_bits),
573 VP8LSubSampleSize(height, histogram_bits),
574 quality);
575 free(histogram_argb);
576 if (!ok) goto Error;
577 }
578 }
579
580 // Store Huffman codes.
581 {
582 int i;
583 for (i = 0; i < 5 * histogram_image_size; ++i) {
584 HuffmanTreeCode* const codes = &huffman_codes[i];
585 if (!StoreHuffmanCode(bw, codes)) goto Error;
586 ClearHuffmanTreeIfOnlyOneSymbol(codes);
587 }
588 }
589 // Free combined histograms.
590 free(histogram_image);
591 histogram_image = NULL;
592
593 // Store actual literals.
594 StoreImageToBitMask(bw, width, histogram_bits, &refs,
595 histogram_symbols, huffman_codes);
596 ok = 1;
597
598 Error:
599 if (!ok) free(histogram_image);
600
601 VP8LClearBackwardRefs(&refs);
602 if (huffman_codes != NULL) {
603 free(huffman_codes->codes);
604 free(huffman_codes);
605 }
606 free(histogram_symbols);
607 return ok;
608 }
609
610 // -----------------------------------------------------------------------------
611 // Transforms
612
613 // Check if it would be a good idea to subtract green from red and blue. We
614 // only impact entropy in red/blue components, don't bother to look at others.
615 static int EvalAndApplySubtractGreen(VP8LEncoder* const enc,
616 int width, int height,
617 VP8LBitWriter* const bw) {
618 if (!enc->use_palette_) {
619 int i;
620 const uint32_t* const argb = enc->argb_;
621 double bit_cost_before, bit_cost_after;
622 VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
623 if (histo == NULL) return 0;
624
625 VP8LHistogramInit(histo, 1);
626 for (i = 0; i < width * height; ++i) {
627 const uint32_t c = argb[i];
628 ++histo->red_[(c >> 16) & 0xff];
629 ++histo->blue_[(c >> 0) & 0xff];
630 }
631 bit_cost_before = VP8LHistogramEstimateBits(histo);
632
633 VP8LHistogramInit(histo, 1);
634 for (i = 0; i < width * height; ++i) {
635 const uint32_t c = argb[i];
636 const int green = (c >> 8) & 0xff;
637 ++histo->red_[((c >> 16) - green) & 0xff];
638 ++histo->blue_[((c >> 0) - green) & 0xff];
639 }
640 bit_cost_after = VP8LHistogramEstimateBits(histo);
641 free(histo);
642
643 // Check if subtracting green yields low entropy.
644 enc->use_subtract_green_ = (bit_cost_after < bit_cost_before);
645 if (enc->use_subtract_green_) {
646 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
647 VP8LWriteBits(bw, 2, SUBTRACT_GREEN);
648 VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
649 }
650 }
651 return 1;
652 }
653
654 static int ApplyPredictFilter(const VP8LEncoder* const enc,
655 int width, int height, int quality,
656 VP8LBitWriter* const bw) {
657 const int pred_bits = enc->transform_bits_;
658 const int transform_width = VP8LSubSampleSize(width, pred_bits);
659 const int transform_height = VP8LSubSampleSize(height, pred_bits);
660
661 VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->argb_scratch_,
662 enc->transform_data_);
663 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
664 VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
665 assert(pred_bits >= 2);
666 VP8LWriteBits(bw, 3, pred_bits - 2);
667 if (!EncodeImageNoHuffman(bw, enc->transform_data_,
668 transform_width, transform_height, quality)) {
669 return 0;
670 }
671 return 1;
672 }
673
674 static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
675 int width, int height, int quality,
676 VP8LBitWriter* const bw) {
677 const int ccolor_transform_bits = enc->transform_bits_;
678 const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
679 const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
680 const int step = (quality == 0) ? 32 : 8;
681
682 VP8LColorSpaceTransform(width, height, ccolor_transform_bits, step,
683 enc->argb_, enc->transform_data_);
684 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
685 VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
686 assert(ccolor_transform_bits >= 2);
687 VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
688 if (!EncodeImageNoHuffman(bw, enc->transform_data_,
689 transform_width, transform_height, quality)) {
690 return 0;
691 }
692 return 1;
693 }
694
695 // -----------------------------------------------------------------------------
696
697 static void PutLE32(uint8_t* const data, uint32_t val) {
698 data[0] = (val >> 0) & 0xff;
699 data[1] = (val >> 8) & 0xff;
700 data[2] = (val >> 16) & 0xff;
701 data[3] = (val >> 24) & 0xff;
702 }
703
704 static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
705 size_t riff_size, size_t vp8l_size) {
706 uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
707 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
708 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
709 };
710 PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
711 PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
712 if (!pic->writer(riff, sizeof(riff), pic)) {
713 return VP8_ENC_ERROR_BAD_WRITE;
714 }
715 return VP8_ENC_OK;
716 }
717
718 static int WriteImageSize(const WebPPicture* const pic,
719 VP8LBitWriter* const bw) {
720 const int width = pic->width - 1;
721 const int height = pic->height - 1;
722 assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
723
724 VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, width);
725 VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, height);
726 return !bw->error_;
727 }
728
729 static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
730 VP8LWriteBits(bw, 1, has_alpha);
731 VP8LWriteBits(bw, VP8L_VERSION_BITS, VP8L_VERSION);
732 return !bw->error_;
733 }
734
735 static WebPEncodingError WriteImage(const WebPPicture* const pic,
736 VP8LBitWriter* const bw,
737 size_t* const coded_size) {
738 WebPEncodingError err = VP8_ENC_OK;
739 const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
740 const size_t webpll_size = VP8LBitWriterNumBytes(bw);
741 const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
742 const size_t pad = vp8l_size & 1;
743 const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
744
745 err = WriteRiffHeader(pic, riff_size, vp8l_size);
746 if (err != VP8_ENC_OK) goto Error;
747
748 if (!pic->writer(webpll_data, webpll_size, pic)) {
749 err = VP8_ENC_ERROR_BAD_WRITE;
750 goto Error;
751 }
752
753 if (pad) {
754 const uint8_t pad_byte[1] = { 0 };
755 if (!pic->writer(pad_byte, 1, pic)) {
756 err = VP8_ENC_ERROR_BAD_WRITE;
757 goto Error;
758 }
759 }
760 *coded_size = CHUNK_HEADER_SIZE + riff_size;
761 return VP8_ENC_OK;
762
763 Error:
764 return err;
765 }
766
767 // -----------------------------------------------------------------------------
768
769 // Allocates the memory for argb (W x H) buffer, 2 rows of context for
770 // prediction and transform data.
771 static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
772 int width, int height) {
773 WebPEncodingError err = VP8_ENC_OK;
774 const int tile_size = 1 << enc->transform_bits_;
775 const uint64_t image_size = width * height;
776 const uint64_t argb_scratch_size = tile_size * width + width;
777 const uint64_t transform_data_size =
778 (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) *
779 (uint64_t)VP8LSubSampleSize(height, enc->transform_bits_);
780 const uint64_t total_size =
781 image_size + argb_scratch_size + transform_data_size;
782 uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem));
783 if (mem == NULL) {
784 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
785 goto Error;
786 }
787 enc->argb_ = mem;
788 mem += image_size;
789 enc->argb_scratch_ = mem;
790 mem += argb_scratch_size;
791 enc->transform_data_ = mem;
792 enc->current_width_ = width;
793
794 Error:
795 return err;
796 }
797
798 // Bundles multiple (2, 4 or 8) pixels into a single pixel.
799 // Returns the new xsize.
800 static void BundleColorMap(const WebPPicture* const pic,
801 int xbits, uint32_t* bundled_argb, int xs) {
802 int y;
803 const int bit_depth = 1 << (3 - xbits);
804 uint32_t code = 0;
805 const uint32_t* argb = pic->argb;
806 const int width = pic->width;
807 const int height = pic->height;
808
809 for (y = 0; y < height; ++y) {
810 int x;
811 for (x = 0; x < width; ++x) {
812 const int mask = (1 << xbits) - 1;
813 const int xsub = x & mask;
814 if (xsub == 0) {
815 code = 0;
816 }
817 // TODO(vikasa): simplify the bundling logic.
818 code |= (argb[x] & 0xff00) << (bit_depth * xsub);
819 bundled_argb[y * xs + (x >> xbits)] = 0xff000000 | code;
820 }
821 argb += pic->argb_stride;
822 }
823 }
824
825 // Note: Expects "enc->palette_" to be set properly.
826 // Also, "enc->palette_" will be modified after this call and should not be used
827 // later.
828 static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
829 VP8LEncoder* const enc, int quality) {
830 WebPEncodingError err = VP8_ENC_OK;
831 int i, x, y;
832 const WebPPicture* const pic = enc->pic_;
833 uint32_t* argb = pic->argb;
834 const int width = pic->width;
835 const int height = pic->height;
836 uint32_t* const palette = enc->palette_;
837 const int palette_size = enc->palette_size_;
838
839 // Replace each input pixel by corresponding palette index.
840 for (y = 0; y < height; ++y) {
841 for (x = 0; x < width; ++x) {
842 const uint32_t pix = argb[x];
843 for (i = 0; i < palette_size; ++i) {
844 if (pix == palette[i]) {
845 argb[x] = 0xff000000u | (i << 8);
846 break;
847 }
848 }
849 }
850 argb += pic->argb_stride;
851 }
852
853 // Save palette to bitstream.
854 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
855 VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM);
856 assert(palette_size >= 1);
857 VP8LWriteBits(bw, 8, palette_size - 1);
858 for (i = palette_size - 1; i >= 1; --i) {
859 palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
860 }
861 if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) {
862 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
863 goto Error;
864 }
865
866 if (palette_size <= 16) {
867 // Image can be packed (multiple pixels per uint32_t).
868 int xbits = 1;
869 if (palette_size <= 2) {
870 xbits = 3;
871 } else if (palette_size <= 4) {
872 xbits = 2;
873 }
874 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
875 if (err != VP8_ENC_OK) goto Error;
876 BundleColorMap(pic, xbits, enc->argb_, enc->current_width_);
877 }
878
879 Error:
880 return err;
881 }
882
883 // -----------------------------------------------------------------------------
884
885 static int GetHistoBits(const WebPConfig* const config,
886 const WebPPicture* const pic) {
887 const int width = pic->width;
888 const int height = pic->height;
889 const size_t hist_size = sizeof(VP8LHistogram);
890 // Make tile size a function of encoding method (Range: 0 to 6).
891 int histo_bits = 7 - config->method;
892 while (1) {
893 const size_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
894 VP8LSubSampleSize(height, histo_bits) *
895 hist_size;
896 if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
897 ++histo_bits;
898 }
899 return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
900 (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
901 }
902
903 static void InitEncParams(VP8LEncoder* const enc) {
904 const WebPConfig* const config = enc->config_;
905 const WebPPicture* const picture = enc->pic_;
906 const int method = config->method;
907 const float quality = config->quality;
908 enc->transform_bits_ = (method < 4) ? 5 : (method > 4) ? 3 : 4;
909 enc->histo_bits_ = GetHistoBits(config, picture);
910 enc->cache_bits_ = (quality <= 25.f) ? 0 : 7;
911 }
912
913 // -----------------------------------------------------------------------------
914 // VP8LEncoder
915
916 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
917 const WebPPicture* const picture) {
918 VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc));
919 if (enc == NULL) {
920 WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
921 return NULL;
922 }
923 enc->config_ = config;
924 enc->pic_ = picture;
925 return enc;
926 }
927
928 static void VP8LEncoderDelete(VP8LEncoder* enc) {
929 free(enc->argb_);
930 free(enc);
931 }
932
933 // -----------------------------------------------------------------------------
934 // Main call
935
936 WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
937 const WebPPicture* const picture,
938 VP8LBitWriter* const bw) {
939 WebPEncodingError err = VP8_ENC_OK;
940 const int quality = (int)config->quality;
941 const int width = picture->width;
942 const int height = picture->height;
943 VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
944 const size_t byte_position = VP8LBitWriterNumBytes(bw);
945
946 if (enc == NULL) {
947 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
948 goto Error;
949 }
950
951 InitEncParams(enc);
952
953 // ---------------------------------------------------------------------------
954 // Analyze image (entropy, num_palettes etc)
955
956 if (!VP8LEncAnalyze(enc, config->image_hint)) {
957 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
958 goto Error;
959 }
960
961 if (enc->use_palette_) {
962 err = ApplyPalette(bw, enc, quality);
963 if (err != VP8_ENC_OK) goto Error;
964 enc->cache_bits_ = 0;
965 }
966
967 // In case image is not packed.
968 if (enc->argb_ == NULL) {
969 int y;
970 err = AllocateTransformBuffer(enc, width, height);
971 if (err != VP8_ENC_OK) goto Error;
972 for (y = 0; y < height; ++y) {
973 memcpy(enc->argb_ + y * width,
974 picture->argb + y * picture->argb_stride,
975 width * sizeof(*enc->argb_));
976 }
977 enc->current_width_ = width;
978 }
979
980 // ---------------------------------------------------------------------------
981 // Apply transforms and write transform data.
982
983 if (!EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw)) {
984 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
985 goto Error;
986 }
987
988 if (enc->use_predict_) {
989 if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, bw)) {
990 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
991 goto Error;
992 }
993 }
994
995 if (enc->use_cross_color_) {
996 if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw)) {
997 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
998 goto Error;
999 }
1000 }
1001
1002 VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms.
1003
1004 // ---------------------------------------------------------------------------
1005 // Estimate the color cache size.
1006
1007 if (enc->cache_bits_ > 0) {
1008 if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_,
1009 height, &enc->cache_bits_)) {
1010 err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
1011 goto Error;
1012 }
1013 }
1014
1015 // ---------------------------------------------------------------------------
1016 // Encode and write the transformed image.
1017
1018 if (!EncodeImageInternal(bw, enc->argb_, enc->current_width_, height,
1019 quality, enc->cache_bits_, enc->histo_bits_)) {
1020 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1021 goto Error;
1022 }
1023
1024 if (picture->stats != NULL) {
1025 WebPAuxStats* const stats = picture->stats;
1026 stats->lossless_features = 0;
1027 if (enc->use_predict_) stats->lossless_features |= 1;
1028 if (enc->use_cross_color_) stats->lossless_features |= 2;
1029 if (enc->use_subtract_green_) stats->lossless_features |= 4;
1030 if (enc->use_palette_) stats->lossless_features |= 8;
1031 stats->histogram_bits = enc->histo_bits_;
1032 stats->transform_bits = enc->transform_bits_;
1033 stats->cache_bits = enc->cache_bits_;
1034 stats->palette_size = enc->palette_size_;
1035 stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position);
1036 }
1037
1038 Error:
1039 VP8LEncoderDelete(enc);
1040 return err;
1041 }
1042
1043 int VP8LEncodeImage(const WebPConfig* const config,
1044 const WebPPicture* const picture) {
1045 int width, height;
1046 int has_alpha;
1047 size_t coded_size;
1048 int percent = 0;
1049 WebPEncodingError err = VP8_ENC_OK;
1050 VP8LBitWriter bw;
1051
1052 if (picture == NULL) return 0;
1053
1054 if (config == NULL || picture->argb == NULL) {
1055 err = VP8_ENC_ERROR_NULL_PARAMETER;
1056 WebPEncodingSetError(picture, err);
1057 return 0;
1058 }
1059
1060 width = picture->width;
1061 height = picture->height;
1062 if (!VP8LBitWriterInit(&bw, (width * height) >> 1)) {
1063 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1064 goto Error;
1065 }
1066
1067 if (!WebPReportProgress(picture, 1, &percent)) {
1068 UserAbort:
1069 err = VP8_ENC_ERROR_USER_ABORT;
1070 goto Error;
1071 }
1072 // Reset stats (for pure lossless coding)
1073 if (picture->stats != NULL) {
1074 WebPAuxStats* const stats = picture->stats;
1075 memset(stats, 0, sizeof(*stats));
1076 stats->PSNR[0] = 99.f;
1077 stats->PSNR[1] = 99.f;
1078 stats->PSNR[2] = 99.f;
1079 stats->PSNR[3] = 99.f;
1080 stats->PSNR[4] = 99.f;
1081 }
1082
1083 // Write image size.
1084 if (!WriteImageSize(picture, &bw)) {
1085 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1086 goto Error;
1087 }
1088
1089 has_alpha = WebPPictureHasTransparency(picture);
1090 // Write the non-trivial Alpha flag and lossless version.
1091 if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
1092 err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1093 goto Error;
1094 }
1095
1096 if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort;
1097
1098 // Encode main image stream.
1099 err = VP8LEncodeStream(config, picture, &bw);
1100 if (err != VP8_ENC_OK) goto Error;
1101
1102 // TODO(skal): have a fine-grained progress report in VP8LEncodeStream().
1103 if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort;
1104
1105 // Finish the RIFF chunk.
1106 err = WriteImage(picture, &bw, &coded_size);
1107 if (err != VP8_ENC_OK) goto Error;
1108
1109 if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
1110
1111 // Save size.
1112 if (picture->stats != NULL) {
1113 picture->stats->coded_size += (int)coded_size;
1114 picture->stats->lossless_size = (int)coded_size;
1115 }
1116
1117 if (picture->extra_info != NULL) {
1118 const int mb_w = (width + 15) >> 4;
1119 const int mb_h = (height + 15) >> 4;
1120 memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
1121 }
1122
1123 Error:
1124 if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
1125 VP8LBitWriterDestroy(&bw);
1126 if (err != VP8_ENC_OK) {
1127 WebPEncodingSetError(picture, err);
1128 return 0;
1129 }
1130 return 1;
1131 }
1132
1133 //------------------------------------------------------------------------------
1134
1135 #if defined(__cplusplus) || defined(c_plusplus)
1136 } // extern "C"
1137 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698