Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // This code is licensed under the same terms as WebM: | 3 // This code is licensed under the same terms as WebM: |
| 4 // Software License Agreement: http://www.webmproject.org/license/software/ | 4 // Software License Agreement: http://www.webmproject.org/license/software/ |
| 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ | 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ |
| 6 // ----------------------------------------------------------------------------- | 6 // ----------------------------------------------------------------------------- |
| 7 // | 7 // |
| 8 // main entry for the decoder | 8 // main entry for the decoder |
| 9 // | 9 // |
| 10 // Authors: Vikas Arora (vikaas.arora@gmail.com) | 10 // Authors: Vikas Arora (vikaas.arora@gmail.com) |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 142 const int yoffset = dist_code >> 4; | 142 const int yoffset = dist_code >> 4; |
| 143 const int xoffset = 8 - (dist_code & 0xf); | 143 const int xoffset = 8 - (dist_code & 0xf); |
| 144 const int dist = yoffset * xsize + xoffset; | 144 const int dist = yoffset * xsize + xoffset; |
| 145 return (dist >= 1) ? dist : 1; | 145 return (dist >= 1) ? dist : 1; |
| 146 } | 146 } |
| 147 } | 147 } |
| 148 | 148 |
| 149 //------------------------------------------------------------------------------ | 149 //------------------------------------------------------------------------------ |
| 150 // Decodes the next Huffman code from bit-stream. | 150 // Decodes the next Huffman code from bit-stream. |
| 151 // FillBitWindow(br) needs to be called at minimum every second call | 151 // FillBitWindow(br) needs to be called at minimum every second call |
| 152 // to ReadSymbolUnsafe. | 152 // to ReadSymbol, in order to pre-fetch enough bits. |
| 153 static int ReadSymbolUnsafe(const HuffmanTree* tree, VP8LBitReader* const br) { | 153 static WEBP_INLINE int ReadSymbol(const HuffmanTree* tree, |
| 154 VP8LBitReader* const br) { | |
| 154 const HuffmanTreeNode* node = tree->root_; | 155 const HuffmanTreeNode* node = tree->root_; |
| 156 int num_bits = 0; | |
| 157 uint32_t bits = VP8LPrefetchBits(br); | |
| 155 assert(node != NULL); | 158 assert(node != NULL); |
| 156 while (!HuffmanTreeNodeIsLeaf(node)) { | 159 while (!HuffmanTreeNodeIsLeaf(node)) { |
| 157 node = HuffmanTreeNextNode(node, VP8LReadOneBitUnsafe(br)); | 160 node = HuffmanTreeNextNode(node, bits & 1); |
| 161 bits >>= 1; | |
| 162 ++num_bits; | |
| 158 } | 163 } |
| 164 VP8LDiscardBits(br, num_bits); | |
| 159 return node->symbol_; | 165 return node->symbol_; |
| 160 } | 166 } |
| 161 | 167 |
| 162 static WEBP_INLINE int ReadSymbol(const HuffmanTree* tree, | |
| 163 VP8LBitReader* const br) { | |
| 164 const int read_safe = (br->pos_ + 8 > br->len_); | |
| 165 if (!read_safe) { | |
| 166 return ReadSymbolUnsafe(tree, br); | |
| 167 } else { | |
| 168 const HuffmanTreeNode* node = tree->root_; | |
| 169 assert(node != NULL); | |
| 170 while (!HuffmanTreeNodeIsLeaf(node)) { | |
| 171 node = HuffmanTreeNextNode(node, VP8LReadOneBit(br)); | |
| 172 } | |
| 173 return node->symbol_; | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 static int ReadHuffmanCodeLengths( | 168 static int ReadHuffmanCodeLengths( |
| 178 VP8LDecoder* const dec, const int* const code_length_code_lengths, | 169 VP8LDecoder* const dec, const int* const code_length_code_lengths, |
| 179 int num_symbols, int* const code_lengths) { | 170 int num_symbols, int* const code_lengths) { |
| 180 int ok = 0; | 171 int ok = 0; |
| 181 VP8LBitReader* const br = &dec->br_; | 172 VP8LBitReader* const br = &dec->br_; |
| 182 int symbol; | 173 int symbol; |
| 183 int max_symbol; | 174 int max_symbol; |
| 184 int prev_code_len = DEFAULT_CODE_LENGTH; | 175 int prev_code_len = DEFAULT_CODE_LENGTH; |
| 185 HuffmanTree tree; | 176 HuffmanTree tree; |
| 186 | 177 |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision); | 311 const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision); |
| 321 const int huffman_pixs = huffman_xsize * huffman_ysize; | 312 const int huffman_pixs = huffman_xsize * huffman_ysize; |
| 322 if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec, | 313 if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec, |
| 323 &huffman_image)) { | 314 &huffman_image)) { |
| 324 dec->status_ = VP8_STATUS_BITSTREAM_ERROR; | 315 dec->status_ = VP8_STATUS_BITSTREAM_ERROR; |
| 325 goto Error; | 316 goto Error; |
| 326 } | 317 } |
| 327 hdr->huffman_subsample_bits_ = huffman_precision; | 318 hdr->huffman_subsample_bits_ = huffman_precision; |
| 328 for (i = 0; i < huffman_pixs; ++i) { | 319 for (i = 0; i < huffman_pixs; ++i) { |
| 329 // The huffman data is stored in red and green bytes. | 320 // The huffman data is stored in red and green bytes. |
| 330 const int index = (huffman_image[i] >> 8) & 0xffff; | 321 const int group = (huffman_image[i] >> 8) & 0xffff; |
| 331 huffman_image[i] = index; | 322 huffman_image[i] = group; |
| 332 if (index >= num_htree_groups) { | 323 if (group >= num_htree_groups) { |
| 333 num_htree_groups = index + 1; | 324 num_htree_groups = group + 1; |
| 334 } | 325 } |
| 335 } | 326 } |
| 336 } | 327 } |
| 337 | 328 |
| 338 if (br->error_) goto Error; | 329 if (br->error_) goto Error; |
| 339 | 330 |
| 340 assert(num_htree_groups <= 0x10000); | 331 assert(num_htree_groups <= 0x10000); |
| 341 htree_groups = | 332 htree_groups = |
| 342 (HTreeGroup*)WebPSafeCalloc((uint64_t)num_htree_groups, | 333 (HTreeGroup*)WebPSafeCalloc((uint64_t)num_htree_groups, |
| 343 sizeof(*htree_groups)); | 334 sizeof(*htree_groups)); |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 608 hdr->huffman_subsample_bits_, x, y); | 599 hdr->huffman_subsample_bits_, x, y); |
| 609 assert(meta_index < hdr->num_htree_groups_); | 600 assert(meta_index < hdr->num_htree_groups_); |
| 610 return hdr->htree_groups_ + meta_index; | 601 return hdr->htree_groups_ + meta_index; |
| 611 } | 602 } |
| 612 | 603 |
| 613 //------------------------------------------------------------------------------ | 604 //------------------------------------------------------------------------------ |
| 614 // Main loop, with custom row-processing function | 605 // Main loop, with custom row-processing function |
| 615 | 606 |
| 616 typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row); | 607 typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row); |
| 617 | 608 |
| 618 static void ApplyTransforms(VP8LDecoder* const dec, int num_rows, | 609 static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows, |
| 619 const uint32_t* const rows) { | 610 const uint32_t* const rows) { |
| 620 int n = dec->next_transform_; | 611 int n = dec->next_transform_; |
| 621 const int cache_pixs = dec->width_ * num_rows; | 612 const int cache_pixs = dec->width_ * num_rows; |
| 622 uint32_t* rows_data = dec->argb_cache_; | |
| 623 const int start_row = dec->last_row_; | 613 const int start_row = dec->last_row_; |
| 624 const int end_row = start_row + num_rows; | 614 const int end_row = start_row + num_rows; |
| 615 const uint32_t* rows_in = rows; | |
| 616 uint32_t* const rows_out = dec->argb_cache_; | |
| 625 | 617 |
| 626 // Inverse transforms. | 618 // Inverse transforms. |
| 627 // TODO: most transforms only need to operate on the cropped region only. | 619 // TODO: most transforms only need to operate on the cropped region only. |
| 628 memcpy(rows_data, rows, cache_pixs * sizeof(*rows_data)); | 620 memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out)); |
| 629 while (n-- > 0) { | 621 while (n-- > 0) { |
| 630 VP8LTransform* const transform = &dec->transforms_[n]; | 622 VP8LTransform* const transform = &dec->transforms_[n]; |
| 631 VP8LInverseTransform(transform, start_row, end_row, rows, rows_data); | 623 VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); |
| 624 rows_in = rows_out; | |
| 632 } | 625 } |
| 633 } | 626 } |
| 634 | 627 |
| 635 // Processes (transforms, scales & color-converts) the rows decoded after the | 628 // Processes (transforms, scales & color-converts) the rows decoded after the |
| 636 // last call. | 629 // last call. |
| 637 static void ProcessRows(VP8LDecoder* const dec, int row) { | 630 static void ProcessRows(VP8LDecoder* const dec, int row) { |
| 638 const uint32_t* const rows = dec->argb_ + dec->width_ * dec->last_row_; | 631 const uint32_t* const rows = dec->argb_ + dec->width_ * dec->last_row_; |
| 639 const int num_rows = row - dec->last_row_; | 632 const int num_rows = row - dec->last_row_; |
| 640 | 633 |
| 641 if (num_rows <= 0) return; // Nothing to be done. | 634 if (num_rows <= 0) return; // Nothing to be done. |
| 642 ApplyTransforms(dec, num_rows, rows); | 635 ApplyInverseTransforms(dec, num_rows, rows); |
| 643 | 636 |
| 644 // Emit output. | 637 // Emit output. |
| 645 { | 638 { |
| 646 VP8Io* const io = dec->io_; | 639 VP8Io* const io = dec->io_; |
| 647 const uint32_t* rows_data = dec->argb_cache_; | 640 const uint32_t* rows_data = dec->argb_cache_; |
| 648 if (!SetCropWindow(io, dec->last_row_, row, &rows_data, io->width)) { | 641 if (!SetCropWindow(io, dec->last_row_, row, &rows_data, io->width)) { |
| 649 // Nothing to output (this time). | 642 // Nothing to output (this time). |
| 650 } else { | 643 } else { |
| 651 const WebPDecBuffer* const output = dec->output_; | 644 const WebPDecBuffer* const output = dec->output_; |
| 652 const int in_stride = io->width * sizeof(*rows_data); | 645 const int in_stride = io->width * sizeof(*rows_data); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 790 } | 783 } |
| 791 | 784 |
| 792 // ----------------------------------------------------------------------------- | 785 // ----------------------------------------------------------------------------- |
| 793 // VP8LTransform | 786 // VP8LTransform |
| 794 | 787 |
| 795 static void ClearTransform(VP8LTransform* const transform) { | 788 static void ClearTransform(VP8LTransform* const transform) { |
| 796 free(transform->data_); | 789 free(transform->data_); |
| 797 transform->data_ = NULL; | 790 transform->data_ = NULL; |
| 798 } | 791 } |
| 799 | 792 |
| 800 static void ApplyInverseTransforms(VP8LDecoder* const dec, int start_idx, | |
| 801 uint32_t* const decoded_data) { | |
| 802 int n = dec->next_transform_; | |
| 803 assert(start_idx >= 0); | |
| 804 while (n-- > start_idx) { | |
| 805 VP8LTransform* const transform = &dec->transforms_[n]; | |
| 806 VP8LInverseTransform(transform, 0, transform->ysize_, | |
| 807 decoded_data, decoded_data); | |
| 808 ClearTransform(transform); | |
| 809 } | |
| 810 dec->next_transform_ = start_idx; | |
| 811 } | |
| 812 | |
| 813 // For security reason, we need to remap the color map to span | 793 // For security reason, we need to remap the color map to span |
| 814 // the total possible bundled values, and not just the num_colors. | 794 // the total possible bundled values, and not just the num_colors. |
| 815 static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { | 795 static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { |
| 816 int i; | 796 int i; |
| 817 const int final_num_colors = 1 << (8 >> transform->bits_); | 797 const int final_num_colors = 1 << (8 >> transform->bits_); |
| 818 uint32_t* const new_color_map = | 798 uint32_t* const new_color_map = |
| 819 (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors, | 799 (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors, |
| 820 sizeof(*new_color_map)); | 800 sizeof(*new_color_map)); |
| 821 if (new_color_map == NULL) { | 801 if (new_color_map == NULL) { |
| 822 return 0; | 802 return 0; |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 956 | 936 |
| 957 static int DecodeImageStream(int xsize, int ysize, | 937 static int DecodeImageStream(int xsize, int ysize, |
| 958 int is_level0, | 938 int is_level0, |
| 959 VP8LDecoder* const dec, | 939 VP8LDecoder* const dec, |
| 960 uint32_t** const decoded_data) { | 940 uint32_t** const decoded_data) { |
| 961 int ok = 1; | 941 int ok = 1; |
| 962 int transform_xsize = xsize; | 942 int transform_xsize = xsize; |
| 963 int transform_ysize = ysize; | 943 int transform_ysize = ysize; |
| 964 VP8LBitReader* const br = &dec->br_; | 944 VP8LBitReader* const br = &dec->br_; |
| 965 VP8LMetadata* const hdr = &dec->hdr_; | 945 VP8LMetadata* const hdr = &dec->hdr_; |
| 966 uint32_t* data = NULL; | 946 uint32_t* data = NULL; |
|
fbarchard
2013/03/22 18:56:44
shouldnt we be using uint32* etc?
jzern
2013/03/22 19:10:36
no. we use posix types in this (C) project
| |
| 967 const int transform_start_idx = dec->next_transform_; | |
| 968 int color_cache_bits = 0; | 947 int color_cache_bits = 0; |
| 969 | 948 |
| 970 // Read the transforms (may recurse). | 949 // Read the transforms (may recurse). |
| 971 if (is_level0) { | 950 if (is_level0) { |
| 972 while (ok && VP8LReadBits(br, 1)) { | 951 while (ok && VP8LReadBits(br, 1)) { |
| 973 ok = ReadTransform(&transform_xsize, &transform_ysize, dec); | 952 ok = ReadTransform(&transform_xsize, &transform_ysize, dec); |
| 974 } | 953 } |
| 975 } | 954 } |
| 976 | 955 |
| 977 // Color cache | 956 // Color cache |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1017 dec->status_ = VP8_STATUS_OUT_OF_MEMORY; | 996 dec->status_ = VP8_STATUS_OUT_OF_MEMORY; |
| 1018 ok = 0; | 997 ok = 0; |
| 1019 goto End; | 998 goto End; |
| 1020 } | 999 } |
| 1021 } | 1000 } |
| 1022 | 1001 |
| 1023 // Use the Huffman trees to decode the LZ77 encoded data. | 1002 // Use the Huffman trees to decode the LZ77 encoded data. |
| 1024 ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, NULL); | 1003 ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, NULL); |
| 1025 ok = ok && !br->error_; | 1004 ok = ok && !br->error_; |
| 1026 | 1005 |
| 1027 // Apply transforms on the decoded data. | |
| 1028 if (ok) ApplyInverseTransforms(dec, transform_start_idx, data); | |
| 1029 | |
| 1030 End: | 1006 End: |
| 1031 | 1007 |
| 1032 if (!ok) { | 1008 if (!ok) { |
| 1033 free(data); | 1009 free(data); |
| 1034 ClearMetadata(hdr); | 1010 ClearMetadata(hdr); |
| 1035 // If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the | 1011 // If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the |
| 1036 // status appropriately. | 1012 // status appropriately. |
| 1037 if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && dec->br_.eos_) { | 1013 if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && dec->br_.eos_) { |
| 1038 dec->status_ = VP8_STATUS_SUSPENDED; | 1014 dec->status_ = VP8_STATUS_SUSPENDED; |
| 1039 } | 1015 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1076 } | 1052 } |
| 1077 | 1053 |
| 1078 //------------------------------------------------------------------------------ | 1054 //------------------------------------------------------------------------------ |
| 1079 // Special row-processing that only stores the alpha data. | 1055 // Special row-processing that only stores the alpha data. |
| 1080 | 1056 |
| 1081 static void ExtractAlphaRows(VP8LDecoder* const dec, int row) { | 1057 static void ExtractAlphaRows(VP8LDecoder* const dec, int row) { |
| 1082 const int num_rows = row - dec->last_row_; | 1058 const int num_rows = row - dec->last_row_; |
| 1083 const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_; | 1059 const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_; |
| 1084 | 1060 |
| 1085 if (num_rows <= 0) return; // Nothing to be done. | 1061 if (num_rows <= 0) return; // Nothing to be done. |
| 1086 ApplyTransforms(dec, num_rows, in); | 1062 ApplyInverseTransforms(dec, num_rows, in); |
| 1087 | 1063 |
| 1088 // Extract alpha (which is stored in the green plane). | 1064 // Extract alpha (which is stored in the green plane). |
| 1089 { | 1065 { |
| 1090 const int width = dec->io_->width; // the final width (!= dec->width_) | 1066 const int width = dec->io_->width; // the final width (!= dec->width_) |
| 1091 const int cache_pixs = width * num_rows; | 1067 const int cache_pixs = width * num_rows; |
| 1092 uint8_t* const dst = (uint8_t*)dec->io_->opaque + width * dec->last_row_; | 1068 uint8_t* const dst = (uint8_t*)dec->io_->opaque + width * dec->last_row_; |
| 1093 const uint32_t* const src = dec->argb_cache_; | 1069 const uint32_t* const src = dec->argb_cache_; |
| 1094 int i; | 1070 int i; |
| 1095 for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff; | 1071 for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff; |
| 1096 } | 1072 } |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1206 VP8LClear(dec); | 1182 VP8LClear(dec); |
| 1207 assert(dec->status_ != VP8_STATUS_OK); | 1183 assert(dec->status_ != VP8_STATUS_OK); |
| 1208 return 0; | 1184 return 0; |
| 1209 } | 1185 } |
| 1210 | 1186 |
| 1211 //------------------------------------------------------------------------------ | 1187 //------------------------------------------------------------------------------ |
| 1212 | 1188 |
| 1213 #if defined(__cplusplus) || defined(c_plusplus) | 1189 #if defined(__cplusplus) || defined(c_plusplus) |
| 1214 } // extern "C" | 1190 } // extern "C" |
| 1215 #endif | 1191 #endif |
| OLD | NEW |