OLD | NEW |
1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
4 // that can be found in the COPYING file in the root of the source | 4 // that can be found in the COPYING file in the root of the source |
5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
9 // | 9 // |
10 // main entry for the lossless encoder. | 10 // main entry for the lossless encoder. |
11 // | 11 // |
12 // Author: Vikas Arora (vikaas.arora@gmail.com) | 12 // Author: Vikas Arora (vikaas.arora@gmail.com) |
13 // | 13 // |
14 | 14 |
15 #include <assert.h> | 15 #include <assert.h> |
16 #include <stdio.h> | 16 #include <stdio.h> |
17 #include <stdlib.h> | 17 #include <stdlib.h> |
18 | 18 |
19 #include "./backward_references.h" | 19 #include "./backward_references.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 #if defined(__cplusplus) || defined(c_plusplus) | |
29 extern "C" { | |
30 #endif | |
31 | |
32 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. | 28 #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. |
33 #define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024) | 29 #define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024) |
34 #define MAX_COLORS_FOR_GRAPH 64 | 30 #define MAX_COLORS_FOR_GRAPH 64 |
35 | 31 |
36 // ----------------------------------------------------------------------------- | 32 // ----------------------------------------------------------------------------- |
37 // Palette | 33 // Palette |
38 | 34 |
39 static int CompareColors(const void* p1, const void* p2) { | 35 static int CompareColors(const void* p1, const void* p2) { |
40 const uint32_t a = *(const uint32_t*)p1; | 36 const uint32_t a = *(const uint32_t*)p1; |
41 const uint32_t b = *(const uint32_t*)p2; | 37 const uint32_t b = *(const uint32_t*)p2; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 enc->use_predict_ = 1; | 157 enc->use_predict_ = 1; |
162 enc->use_cross_color_ = 1; | 158 enc->use_cross_color_ = 1; |
163 } else { | 159 } else { |
164 double non_pred_entropy, pred_entropy; | 160 double non_pred_entropy, pred_entropy; |
165 if (!AnalyzeEntropy(pic->argb, pic->width, pic->height, pic->argb_stride, | 161 if (!AnalyzeEntropy(pic->argb, pic->width, pic->height, pic->argb_stride, |
166 &non_pred_entropy, &pred_entropy)) { | 162 &non_pred_entropy, &pred_entropy)) { |
167 return 0; | 163 return 0; |
168 } | 164 } |
169 if (pred_entropy < 0.95 * non_pred_entropy) { | 165 if (pred_entropy < 0.95 * non_pred_entropy) { |
170 enc->use_predict_ = 1; | 166 enc->use_predict_ = 1; |
171 // TODO(vikasa): Observed some correlation of cross_color transform with | |
172 // predict. Need to investigate this further and add separate heuristic | |
173 // for setting use_cross_color flag. | |
174 enc->use_cross_color_ = 1; | 167 enc->use_cross_color_ = 1; |
175 } | 168 } |
176 } | 169 } |
177 } | 170 } |
178 | 171 |
179 return 1; | 172 return 1; |
180 } | 173 } |
181 | 174 |
182 static int GetHuffBitLengthsAndCodes( | 175 static int GetHuffBitLengthsAndCodes( |
183 const VP8LHistogramSet* const histogram_image, | 176 const VP8LHistogramSet* const histogram_image, |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 static const int order[] = { 1, 2, 0, 3 }; | 437 static const int order[] = { 1, 2, 0, 3 }; |
445 int k; | 438 int k; |
446 for (k = 0; k < 4; ++k) { | 439 for (k = 0; k < 4; ++k) { |
447 const int code = PixOrCopyLiteral(v, order[k]); | 440 const int code = PixOrCopyLiteral(v, order[k]); |
448 WriteHuffmanCode(bw, codes + k, code); | 441 WriteHuffmanCode(bw, codes + k, code); |
449 } | 442 } |
450 } else { | 443 } else { |
451 int bits, n_bits; | 444 int bits, n_bits; |
452 int code, distance; | 445 int code, distance; |
453 | 446 |
454 PrefixEncode(v->len, &code, &n_bits, &bits); | 447 VP8LPrefixEncode(v->len, &code, &n_bits, &bits); |
455 WriteHuffmanCode(bw, codes, 256 + code); | 448 WriteHuffmanCode(bw, codes, 256 + code); |
456 VP8LWriteBits(bw, n_bits, bits); | 449 VP8LWriteBits(bw, n_bits, bits); |
457 | 450 |
458 distance = PixOrCopyDistance(v); | 451 distance = PixOrCopyDistance(v); |
459 PrefixEncode(distance, &code, &n_bits, &bits); | 452 VP8LPrefixEncode(distance, &code, &n_bits, &bits); |
460 WriteHuffmanCode(bw, codes + 4, code); | 453 WriteHuffmanCode(bw, codes + 4, code); |
461 VP8LWriteBits(bw, n_bits, bits); | 454 VP8LWriteBits(bw, n_bits, bits); |
462 } | 455 } |
463 x += PixOrCopyLength(v); | 456 x += PixOrCopyLength(v); |
464 while (x >= width) { | 457 while (x >= width) { |
465 x -= width; | 458 x -= width; |
466 ++y; | 459 ++y; |
467 } | 460 } |
468 } | 461 } |
469 } | 462 } |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 } | 688 } |
696 return 1; | 689 return 1; |
697 } | 690 } |
698 | 691 |
699 static int ApplyCrossColorFilter(const VP8LEncoder* const enc, | 692 static int ApplyCrossColorFilter(const VP8LEncoder* const enc, |
700 int width, int height, int quality, | 693 int width, int height, int quality, |
701 VP8LBitWriter* const bw) { | 694 VP8LBitWriter* const bw) { |
702 const int ccolor_transform_bits = enc->transform_bits_; | 695 const int ccolor_transform_bits = enc->transform_bits_; |
703 const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); | 696 const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); |
704 const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); | 697 const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); |
705 const int step = (quality == 0) ? 32 : 8; | 698 const int step = (quality < 25) ? 32 : (quality > 50) ? 8 : 16; |
706 | 699 |
707 VP8LColorSpaceTransform(width, height, ccolor_transform_bits, step, | 700 VP8LColorSpaceTransform(width, height, ccolor_transform_bits, step, |
708 enc->argb_, enc->transform_data_); | 701 enc->argb_, enc->transform_data_); |
709 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); | 702 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); |
710 VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM); | 703 VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM); |
711 assert(ccolor_transform_bits >= 2); | 704 assert(ccolor_transform_bits >= 2); |
712 VP8LWriteBits(bw, 3, ccolor_transform_bits - 2); | 705 VP8LWriteBits(bw, 3, ccolor_transform_bits - 2); |
713 if (!EncodeImageNoHuffman(bw, enc->transform_data_, | 706 if (!EncodeImageNoHuffman(bw, enc->transform_data_, |
714 transform_width, transform_height, quality)) { | 707 transform_width, transform_height, quality)) { |
715 return 0; | 708 return 0; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 int i, x, y; | 813 int i, x, y; |
821 int use_LUT = 1; | 814 int use_LUT = 1; |
822 for (i = 0; i < palette_size; ++i) { | 815 for (i = 0; i < palette_size; ++i) { |
823 if ((palette[i] & 0xffff00ffu) != 0) { | 816 if ((palette[i] & 0xffff00ffu) != 0) { |
824 use_LUT = 0; | 817 use_LUT = 0; |
825 break; | 818 break; |
826 } | 819 } |
827 } | 820 } |
828 | 821 |
829 if (use_LUT) { | 822 if (use_LUT) { |
830 int inv_palette[MAX_PALETTE_SIZE] = { 0 }; | 823 uint8_t inv_palette[MAX_PALETTE_SIZE] = { 0 }; |
831 for (i = 0; i < palette_size; ++i) { | 824 for (i = 0; i < palette_size; ++i) { |
832 const int color = (palette[i] >> 8) & 0xff; | 825 const int color = (palette[i] >> 8) & 0xff; |
833 inv_palette[color] = i; | 826 inv_palette[color] = i; |
834 } | 827 } |
835 for (y = 0; y < height; ++y) { | 828 for (y = 0; y < height; ++y) { |
836 for (x = 0; x < width; ++x) { | 829 for (x = 0; x < width; ++x) { |
837 const int color = (src[x] >> 8) & 0xff; | 830 const int color = (src[x] >> 8) & 0xff; |
838 row[x] = inv_palette[color]; | 831 row[x] = inv_palette[color]; |
839 } | 832 } |
840 VP8LBundleColorMap(row, width, xbits, dst); | 833 VP8LBundleColorMap(row, width, xbits, dst); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
888 if (palette_size <= 4) { | 881 if (palette_size <= 4) { |
889 xbits = (palette_size <= 2) ? 3 : 2; | 882 xbits = (palette_size <= 2) ? 3 : 2; |
890 } else { | 883 } else { |
891 xbits = (palette_size <= 16) ? 1 : 0; | 884 xbits = (palette_size <= 16) ? 1 : 0; |
892 } | 885 } |
893 | 886 |
894 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height); | 887 err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height); |
895 if (err != VP8_ENC_OK) goto Error; | 888 if (err != VP8_ENC_OK) goto Error; |
896 dst = enc->argb_; | 889 dst = enc->argb_; |
897 | 890 |
898 row = WebPSafeMalloc((uint64_t)width, sizeof(*row)); | 891 row = (uint8_t*)WebPSafeMalloc((uint64_t)width, sizeof(*row)); |
899 if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; | 892 if (row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; |
900 | 893 |
901 ApplyPalette(src, dst, pic->argb_stride, enc->current_width_, | 894 ApplyPalette(src, dst, pic->argb_stride, enc->current_width_, |
902 palette, palette_size, width, height, xbits, row); | 895 palette, palette_size, width, height, xbits, row); |
903 | 896 |
904 // Save palette to bitstream. | 897 // Save palette to bitstream. |
905 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); | 898 VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); |
906 VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM); | 899 VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM); |
907 assert(palette_size >= 1); | 900 assert(palette_size >= 1); |
908 VP8LWriteBits(bw, 8, palette_size - 1); | 901 VP8LWriteBits(bw, 8, palette_size - 1); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
952 | 945 |
953 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, | 946 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, |
954 const WebPPicture* const picture) { | 947 const WebPPicture* const picture) { |
955 VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc)); | 948 VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc)); |
956 if (enc == NULL) { | 949 if (enc == NULL) { |
957 WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); | 950 WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); |
958 return NULL; | 951 return NULL; |
959 } | 952 } |
960 enc->config_ = config; | 953 enc->config_ = config; |
961 enc->pic_ = picture; | 954 enc->pic_ = picture; |
| 955 |
| 956 VP8LDspInit(); |
| 957 |
962 return enc; | 958 return enc; |
963 } | 959 } |
964 | 960 |
965 static void VP8LEncoderDelete(VP8LEncoder* enc) { | 961 static void VP8LEncoderDelete(VP8LEncoder* enc) { |
966 free(enc->argb_); | 962 free(enc->argb_); |
967 free(enc); | 963 free(enc); |
968 } | 964 } |
969 | 965 |
970 // ----------------------------------------------------------------------------- | 966 // ----------------------------------------------------------------------------- |
971 // Main call | 967 // Main call |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1163 VP8LBitWriterDestroy(&bw); | 1159 VP8LBitWriterDestroy(&bw); |
1164 if (err != VP8_ENC_OK) { | 1160 if (err != VP8_ENC_OK) { |
1165 WebPEncodingSetError(picture, err); | 1161 WebPEncodingSetError(picture, err); |
1166 return 0; | 1162 return 0; |
1167 } | 1163 } |
1168 return 1; | 1164 return 1; |
1169 } | 1165 } |
1170 | 1166 |
1171 //------------------------------------------------------------------------------ | 1167 //------------------------------------------------------------------------------ |
1172 | 1168 |
1173 #if defined(__cplusplus) || defined(c_plusplus) | |
1174 } // extern "C" | |
1175 #endif | |
OLD | NEW |