| 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 // Use of this source code is governed by a BSD-style license |
| 4 // Software License Agreement: http://www.webmproject.org/license/software/ | 4 // that can be found in the COPYING file in the root of the source |
| 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. |
| 6 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
| 7 // | 9 // |
| 8 // main entry for the decoder | 10 // main entry for the decoder |
| 9 // | 11 // |
| 10 // Authors: Vikas Arora (vikaas.arora@gmail.com) | 12 // Authors: Vikas Arora (vikaas.arora@gmail.com) |
| 11 // Jyrki Alakuijala (jyrki@google.com) | 13 // Jyrki Alakuijala (jyrki@google.com) |
| 12 | 14 |
| 13 #include <stdio.h> | 15 #include <stdio.h> |
| 14 #include <stdlib.h> | 16 #include <stdlib.h> |
| 15 #include "./vp8li.h" | 17 #include "./vp8li.h" |
| (...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 // Inverse transforms. | 620 // Inverse transforms. |
| 619 // TODO: most transforms only need to operate on the cropped region only. | 621 // TODO: most transforms only need to operate on the cropped region only. |
| 620 memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out)); | 622 memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out)); |
| 621 while (n-- > 0) { | 623 while (n-- > 0) { |
| 622 VP8LTransform* const transform = &dec->transforms_[n]; | 624 VP8LTransform* const transform = &dec->transforms_[n]; |
| 623 VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); | 625 VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); |
| 624 rows_in = rows_out; | 626 rows_in = rows_out; |
| 625 } | 627 } |
| 626 } | 628 } |
| 627 | 629 |
| 630 // Special method for paletted alpha data. |
| 631 static void ApplyInverseTransformsAlpha(VP8LDecoder* const dec, int num_rows, |
| 632 const uint8_t* const rows) { |
| 633 const int start_row = dec->last_row_; |
| 634 const int end_row = start_row + num_rows; |
| 635 const uint8_t* rows_in = rows; |
| 636 uint8_t* rows_out = (uint8_t*)dec->io_->opaque + dec->io_->width * start_row; |
| 637 VP8LTransform* const transform = &dec->transforms_[0]; |
| 638 assert(dec->next_transform_ == 1); |
| 639 assert(transform->type_ == COLOR_INDEXING_TRANSFORM); |
| 640 VP8LColorIndexInverseTransformAlpha(transform, start_row, end_row, rows_in, |
| 641 rows_out); |
| 642 } |
| 643 |
| 628 // Processes (transforms, scales & color-converts) the rows decoded after the | 644 // Processes (transforms, scales & color-converts) the rows decoded after the |
| 629 // last call. | 645 // last call. |
| 630 static void ProcessRows(VP8LDecoder* const dec, int row) { | 646 static void ProcessRows(VP8LDecoder* const dec, int row) { |
| 631 const uint32_t* const rows = dec->argb_ + dec->width_ * dec->last_row_; | 647 const uint32_t* const rows = dec->pixels_ + dec->width_ * dec->last_row_; |
| 632 const int num_rows = row - dec->last_row_; | 648 const int num_rows = row - dec->last_row_; |
| 633 | 649 |
| 634 if (num_rows <= 0) return; // Nothing to be done. | 650 if (num_rows <= 0) return; // Nothing to be done. |
| 635 ApplyInverseTransforms(dec, num_rows, rows); | 651 ApplyInverseTransforms(dec, num_rows, rows); |
| 636 | 652 |
| 637 // Emit output. | 653 // Emit output. |
| 638 { | 654 { |
| 639 VP8Io* const io = dec->io_; | 655 VP8Io* const io = dec->io_; |
| 640 const uint32_t* rows_data = dec->argb_cache_; | 656 const uint32_t* rows_data = dec->argb_cache_; |
| 641 if (!SetCropWindow(io, dec->last_row_, row, &rows_data, io->width)) { | 657 if (!SetCropWindow(io, dec->last_row_, row, &rows_data, io->width)) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 660 } | 676 } |
| 661 assert(dec->last_out_row_ <= output->height); | 677 assert(dec->last_out_row_ <= output->height); |
| 662 } | 678 } |
| 663 } | 679 } |
| 664 | 680 |
| 665 // Update 'last_row_'. | 681 // Update 'last_row_'. |
| 666 dec->last_row_ = row; | 682 dec->last_row_ = row; |
| 667 assert(dec->last_row_ <= dec->height_); | 683 assert(dec->last_row_ <= dec->height_); |
| 668 } | 684 } |
| 669 | 685 |
| 670 static int DecodeImageData(VP8LDecoder* const dec, | 686 #define DECODE_DATA_FUNC(FUNC_NAME, TYPE, STORE_PIXEL) \ |
| 671 uint32_t* const data, int width, int height, | 687 static int FUNC_NAME(VP8LDecoder* const dec, TYPE* const data, int width, \ |
| 672 ProcessRowsFunc process_func) { | 688 int height, ProcessRowsFunc process_func) { \ |
| 673 int ok = 1; | 689 int ok = 1; \ |
| 674 int col = 0, row = 0; | 690 int col = 0, row = 0; \ |
| 675 VP8LBitReader* const br = &dec->br_; | 691 VP8LBitReader* const br = &dec->br_; \ |
| 676 VP8LMetadata* const hdr = &dec->hdr_; | 692 VP8LMetadata* const hdr = &dec->hdr_; \ |
| 677 HTreeGroup* htree_group = hdr->htree_groups_; | 693 HTreeGroup* htree_group = hdr->htree_groups_; \ |
| 678 uint32_t* src = data; | 694 TYPE* src = data; \ |
| 679 uint32_t* last_cached = data; | 695 TYPE* last_cached = data; \ |
| 680 uint32_t* const src_end = data + width * height; | 696 TYPE* const src_end = data + width * height; \ |
| 681 const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; | 697 const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; \ |
| 682 const int color_cache_limit = len_code_limit + hdr->color_cache_size_; | 698 const int color_cache_limit = len_code_limit + hdr->color_cache_size_; \ |
| 683 VP8LColorCache* const color_cache = | 699 VP8LColorCache* const color_cache = \ |
| 684 (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL; | 700 (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL; \ |
| 685 const int mask = hdr->huffman_mask_; | 701 const int mask = hdr->huffman_mask_; \ |
| 702 assert(htree_group != NULL); \ |
| 703 while (!br->eos_ && src < src_end) { \ |
| 704 int code; \ |
| 705 /* Only update when changing tile. Note we could use this test: */ \ |
| 706 /* if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed */ \ |
| 707 /* but that's actually slower and needs storing the previous col/row. */ \ |
| 708 if ((col & mask) == 0) { \ |
| 709 htree_group = GetHtreeGroupForPos(hdr, col, row); \ |
| 710 } \ |
| 711 VP8LFillBitWindow(br); \ |
| 712 code = ReadSymbol(&htree_group->htrees_[GREEN], br); \ |
| 713 if (code < NUM_LITERAL_CODES) { /* Literal*/ \ |
| 714 int red, green, blue, alpha; \ |
| 715 red = ReadSymbol(&htree_group->htrees_[RED], br); \ |
| 716 green = code; \ |
| 717 VP8LFillBitWindow(br); \ |
| 718 blue = ReadSymbol(&htree_group->htrees_[BLUE], br); \ |
| 719 alpha = ReadSymbol(&htree_group->htrees_[ALPHA], br); \ |
| 720 *src = STORE_PIXEL(alpha, red, green, blue); \ |
| 721 AdvanceByOne: \ |
| 722 ++src; \ |
| 723 ++col; \ |
| 724 if (col >= width) { \ |
| 725 col = 0; \ |
| 726 ++row; \ |
| 727 if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) { \ |
| 728 process_func(dec, row); \ |
| 729 } \ |
| 730 if (color_cache != NULL) { \ |
| 731 while (last_cached < src) { \ |
| 732 VP8LColorCacheInsert(color_cache, *last_cached++); \ |
| 733 } \ |
| 734 } \ |
| 735 } \ |
| 736 } else if (code < len_code_limit) { /* Backward reference */ \ |
| 737 int dist_code, dist; \ |
| 738 const int length_sym = code - NUM_LITERAL_CODES; \ |
| 739 const int length = GetCopyLength(length_sym, br); \ |
| 740 const int dist_symbol = ReadSymbol(&htree_group->htrees_[DIST], br); \ |
| 741 VP8LFillBitWindow(br); \ |
| 742 dist_code = GetCopyDistance(dist_symbol, br); \ |
| 743 dist = PlaneCodeToDistance(width, dist_code); \ |
| 744 if (src - data < dist || src_end - src < length) { \ |
| 745 ok = 0; \ |
| 746 goto End; \ |
| 747 } \ |
| 748 { \ |
| 749 int i; \ |
| 750 for (i = 0; i < length; ++i) src[i] = src[i - dist]; \ |
| 751 src += length; \ |
| 752 } \ |
| 753 col += length; \ |
| 754 while (col >= width) { \ |
| 755 col -= width; \ |
| 756 ++row; \ |
| 757 if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) { \ |
| 758 process_func(dec, row); \ |
| 759 } \ |
| 760 } \ |
| 761 if (src < src_end) { \ |
| 762 htree_group = GetHtreeGroupForPos(hdr, col, row); \ |
| 763 if (color_cache != NULL) { \ |
| 764 while (last_cached < src) { \ |
| 765 VP8LColorCacheInsert(color_cache, *last_cached++); \ |
| 766 } \ |
| 767 } \ |
| 768 } \ |
| 769 } else if (code < color_cache_limit) { /* Color cache */ \ |
| 770 const int key = code - len_code_limit; \ |
| 771 assert(color_cache != NULL); \ |
| 772 while (last_cached < src) { \ |
| 773 VP8LColorCacheInsert(color_cache, *last_cached++); \ |
| 774 } \ |
| 775 *src = VP8LColorCacheLookup(color_cache, key); \ |
| 776 goto AdvanceByOne; \ |
| 777 } else { /* Not reached */ \ |
| 778 ok = 0; \ |
| 779 goto End; \ |
| 780 } \ |
| 781 ok = !br->error_; \ |
| 782 if (!ok) goto End; \ |
| 783 } \ |
| 784 /* Process the remaining rows corresponding to last row-block. */ \ |
| 785 if (process_func != NULL) process_func(dec, row); \ |
| 786 End: \ |
| 787 if (br->error_ || !ok || (br->eos_ && src < src_end)) { \ |
| 788 ok = 0; \ |
| 789 dec->status_ = \ |
| 790 (!br->eos_) ? VP8_STATUS_BITSTREAM_ERROR : VP8_STATUS_SUSPENDED; \ |
| 791 } else if (src == src_end) { \ |
| 792 dec->state_ = READ_DATA; \ |
| 793 } \ |
| 794 return ok; \ |
| 795 } |
| 686 | 796 |
| 687 assert(htree_group != NULL); | 797 static WEBP_INLINE uint32_t GetARGBPixel(int alpha, int red, int green, |
| 798 int blue) { |
| 799 return (alpha << 24) | (red << 16) | (green << 8) | blue; |
| 800 } |
| 688 | 801 |
| 689 while (!br->eos_ && src < src_end) { | 802 static WEBP_INLINE uint8_t GetAlphaPixel(int alpha, int red, int green, |
| 690 int code; | 803 int blue) { |
| 691 // Only update when changing tile. Note we could use the following test: | 804 (void)alpha; |
| 692 // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed | 805 (void)red; |
| 693 // but that's actually slower and requires storing the previous col/row | 806 (void)blue; |
| 694 if ((col & mask) == 0) { | 807 return green; // Alpha value is stored in green channel. |
| 695 htree_group = GetHtreeGroupForPos(hdr, col, row); | 808 } |
| 696 } | |
| 697 VP8LFillBitWindow(br); | |
| 698 code = ReadSymbol(&htree_group->htrees_[GREEN], br); | |
| 699 if (code < NUM_LITERAL_CODES) { // Literal. | |
| 700 int red, green, blue, alpha; | |
| 701 red = ReadSymbol(&htree_group->htrees_[RED], br); | |
| 702 green = code; | |
| 703 VP8LFillBitWindow(br); | |
| 704 blue = ReadSymbol(&htree_group->htrees_[BLUE], br); | |
| 705 alpha = ReadSymbol(&htree_group->htrees_[ALPHA], br); | |
| 706 *src = (alpha << 24) + (red << 16) + (green << 8) + blue; | |
| 707 AdvanceByOne: | |
| 708 ++src; | |
| 709 ++col; | |
| 710 if (col >= width) { | |
| 711 col = 0; | |
| 712 ++row; | |
| 713 if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) { | |
| 714 process_func(dec, row); | |
| 715 } | |
| 716 if (color_cache != NULL) { | |
| 717 while (last_cached < src) { | |
| 718 VP8LColorCacheInsert(color_cache, *last_cached++); | |
| 719 } | |
| 720 } | |
| 721 } | |
| 722 } else if (code < len_code_limit) { // Backward reference | |
| 723 int dist_code, dist; | |
| 724 const int length_sym = code - NUM_LITERAL_CODES; | |
| 725 const int length = GetCopyLength(length_sym, br); | |
| 726 const int dist_symbol = ReadSymbol(&htree_group->htrees_[DIST], br); | |
| 727 VP8LFillBitWindow(br); | |
| 728 dist_code = GetCopyDistance(dist_symbol, br); | |
| 729 dist = PlaneCodeToDistance(width, dist_code); | |
| 730 if (src - data < dist || src_end - src < length) { | |
| 731 ok = 0; | |
| 732 goto End; | |
| 733 } | |
| 734 { | |
| 735 int i; | |
| 736 for (i = 0; i < length; ++i) src[i] = src[i - dist]; | |
| 737 src += length; | |
| 738 } | |
| 739 col += length; | |
| 740 while (col >= width) { | |
| 741 col -= width; | |
| 742 ++row; | |
| 743 if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) { | |
| 744 process_func(dec, row); | |
| 745 } | |
| 746 } | |
| 747 if (src < src_end) { | |
| 748 htree_group = GetHtreeGroupForPos(hdr, col, row); | |
| 749 if (color_cache != NULL) { | |
| 750 while (last_cached < src) { | |
| 751 VP8LColorCacheInsert(color_cache, *last_cached++); | |
| 752 } | |
| 753 } | |
| 754 } | |
| 755 } else if (code < color_cache_limit) { // Color cache. | |
| 756 const int key = code - len_code_limit; | |
| 757 assert(color_cache != NULL); | |
| 758 while (last_cached < src) { | |
| 759 VP8LColorCacheInsert(color_cache, *last_cached++); | |
| 760 } | |
| 761 *src = VP8LColorCacheLookup(color_cache, key); | |
| 762 goto AdvanceByOne; | |
| 763 } else { // Not reached. | |
| 764 ok = 0; | |
| 765 goto End; | |
| 766 } | |
| 767 ok = !br->error_; | |
| 768 if (!ok) goto End; | |
| 769 } | |
| 770 // Process the remaining rows corresponding to last row-block. | |
| 771 if (process_func != NULL) process_func(dec, row); | |
| 772 | 809 |
| 773 End: | 810 DECODE_DATA_FUNC(DecodeImageData, uint32_t, GetARGBPixel) |
| 774 if (br->error_ || !ok || (br->eos_ && src < src_end)) { | 811 DECODE_DATA_FUNC(DecodeAlphaData, uint8_t, GetAlphaPixel) |
| 775 ok = 0; | |
| 776 dec->status_ = (!br->eos_) ? | |
| 777 VP8_STATUS_BITSTREAM_ERROR : VP8_STATUS_SUSPENDED; | |
| 778 } else if (src == src_end) { | |
| 779 dec->state_ = READ_DATA; | |
| 780 } | |
| 781 | 812 |
| 782 return ok; | 813 #undef DECODE_DATA_FUNC |
| 783 } | |
| 784 | 814 |
| 785 // ----------------------------------------------------------------------------- | 815 // ----------------------------------------------------------------------------- |
| 786 // VP8LTransform | 816 // VP8LTransform |
| 787 | 817 |
| 788 static void ClearTransform(VP8LTransform* const transform) { | 818 static void ClearTransform(VP8LTransform* const transform) { |
| 789 free(transform->data_); | 819 free(transform->data_); |
| 790 transform->data_ = NULL; | 820 transform->data_ = NULL; |
| 791 } | 821 } |
| 792 | 822 |
| 793 // For security reason, we need to remap the color map to span | 823 // For security reason, we need to remap the color map to span |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 896 dec->action_ = READ_DIM; | 926 dec->action_ = READ_DIM; |
| 897 dec->state_ = READ_DIM; | 927 dec->state_ = READ_DIM; |
| 898 return dec; | 928 return dec; |
| 899 } | 929 } |
| 900 | 930 |
| 901 void VP8LClear(VP8LDecoder* const dec) { | 931 void VP8LClear(VP8LDecoder* const dec) { |
| 902 int i; | 932 int i; |
| 903 if (dec == NULL) return; | 933 if (dec == NULL) return; |
| 904 ClearMetadata(&dec->hdr_); | 934 ClearMetadata(&dec->hdr_); |
| 905 | 935 |
| 906 free(dec->argb_); | 936 free(dec->pixels_); |
| 907 dec->argb_ = NULL; | 937 dec->pixels_ = NULL; |
| 908 for (i = 0; i < dec->next_transform_; ++i) { | 938 for (i = 0; i < dec->next_transform_; ++i) { |
| 909 ClearTransform(&dec->transforms_[i]); | 939 ClearTransform(&dec->transforms_[i]); |
| 910 } | 940 } |
| 911 dec->next_transform_ = 0; | 941 dec->next_transform_ = 0; |
| 912 dec->transforms_seen_ = 0; | 942 dec->transforms_seen_ = 0; |
| 913 | 943 |
| 914 free(dec->rescaler_memory); | 944 free(dec->rescaler_memory); |
| 915 dec->rescaler_memory = NULL; | 945 dec->rescaler_memory = NULL; |
| 916 | 946 |
| 917 dec->output_ = NULL; // leave no trace behind | 947 dec->output_ = NULL; // leave no trace behind |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1021 // (that is: not the transforms), we shouldn't have allocated anything. | 1051 // (that is: not the transforms), we shouldn't have allocated anything. |
| 1022 assert(data == NULL); | 1052 assert(data == NULL); |
| 1023 assert(is_level0); | 1053 assert(is_level0); |
| 1024 } | 1054 } |
| 1025 if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind. | 1055 if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind. |
| 1026 } | 1056 } |
| 1027 return ok; | 1057 return ok; |
| 1028 } | 1058 } |
| 1029 | 1059 |
| 1030 //------------------------------------------------------------------------------ | 1060 //------------------------------------------------------------------------------ |
| 1031 // Allocate dec->argb_ and dec->argb_cache_ using dec->width_ and dec->height_ | 1061 // Allocate internal buffers dec->pixels_ and dec->argb_cache_. |
| 1032 | 1062 static int AllocateInternalBuffers(VP8LDecoder* const dec, int final_width, |
| 1033 static int AllocateARGBBuffers(VP8LDecoder* const dec, int final_width) { | 1063 size_t bytes_per_pixel) { |
| 1064 const int argb_cache_needed = (bytes_per_pixel == sizeof(uint32_t)); |
| 1034 const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_; | 1065 const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_; |
| 1035 // Scratch buffer corresponding to top-prediction row for transforming the | 1066 // Scratch buffer corresponding to top-prediction row for transforming the |
| 1036 // first row in the row-blocks. | 1067 // first row in the row-blocks. Not needed for paletted alpha. |
| 1037 const uint64_t cache_top_pixels = final_width; | 1068 const uint64_t cache_top_pixels = |
| 1038 // Scratch buffer for temporary BGRA storage. | 1069 argb_cache_needed ? (uint16_t)final_width : 0ULL; |
| 1039 const uint64_t cache_pixels = (uint64_t)final_width * NUM_ARGB_CACHE_ROWS; | 1070 // Scratch buffer for temporary BGRA storage. Not needed for paletted alpha. |
| 1071 const uint64_t cache_pixels = |
| 1072 argb_cache_needed ? (uint64_t)final_width * NUM_ARGB_CACHE_ROWS : 0ULL; |
| 1040 const uint64_t total_num_pixels = | 1073 const uint64_t total_num_pixels = |
| 1041 num_pixels + cache_top_pixels + cache_pixels; | 1074 num_pixels + cache_top_pixels + cache_pixels; |
| 1042 | 1075 |
| 1043 assert(dec->width_ <= final_width); | 1076 assert(dec->width_ <= final_width); |
| 1044 dec->argb_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(*dec->argb_)); | 1077 dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, bytes_per_pixel); |
| 1045 if (dec->argb_ == NULL) { | 1078 if (dec->pixels_ == NULL) { |
| 1046 dec->argb_cache_ = NULL; // for sanity check | 1079 dec->argb_cache_ = NULL; // for sanity check |
| 1047 dec->status_ = VP8_STATUS_OUT_OF_MEMORY; | 1080 dec->status_ = VP8_STATUS_OUT_OF_MEMORY; |
| 1048 return 0; | 1081 return 0; |
| 1049 } | 1082 } |
| 1050 dec->argb_cache_ = dec->argb_ + num_pixels + cache_top_pixels; | 1083 dec->argb_cache_ = |
| 1084 argb_cache_needed ? dec->pixels_ + num_pixels + cache_top_pixels : NULL; |
| 1051 return 1; | 1085 return 1; |
| 1052 } | 1086 } |
| 1053 | 1087 |
| 1054 //------------------------------------------------------------------------------ | 1088 //------------------------------------------------------------------------------ |
| 1089 |
| 1055 // Special row-processing that only stores the alpha data. | 1090 // Special row-processing that only stores the alpha data. |
| 1056 | |
| 1057 static void ExtractAlphaRows(VP8LDecoder* const dec, int row) { | 1091 static void ExtractAlphaRows(VP8LDecoder* const dec, int row) { |
| 1058 const int num_rows = row - dec->last_row_; | 1092 const int num_rows = row - dec->last_row_; |
| 1059 const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_; | 1093 const uint32_t* const in = dec->pixels_ + dec->width_ * dec->last_row_; |
| 1060 | 1094 |
| 1061 if (num_rows <= 0) return; // Nothing to be done. | 1095 if (num_rows <= 0) return; // Nothing to be done. |
| 1062 ApplyInverseTransforms(dec, num_rows, in); | 1096 ApplyInverseTransforms(dec, num_rows, in); |
| 1063 | 1097 |
| 1064 // Extract alpha (which is stored in the green plane). | 1098 // Extract alpha (which is stored in the green plane). |
| 1065 { | 1099 { |
| 1066 const int width = dec->io_->width; // the final width (!= dec->width_) | 1100 const int width = dec->io_->width; // the final width (!= dec->width_) |
| 1067 const int cache_pixs = width * num_rows; | 1101 const int cache_pixs = width * num_rows; |
| 1068 uint8_t* const dst = (uint8_t*)dec->io_->opaque + width * dec->last_row_; | 1102 uint8_t* const dst = (uint8_t*)dec->io_->opaque + width * dec->last_row_; |
| 1069 const uint32_t* const src = dec->argb_cache_; | 1103 const uint32_t* const src = dec->argb_cache_; |
| 1070 int i; | 1104 int i; |
| 1071 for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff; | 1105 for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff; |
| 1072 } | 1106 } |
| 1073 | |
| 1074 dec->last_row_ = dec->last_out_row_ = row; | 1107 dec->last_row_ = dec->last_out_row_ = row; |
| 1075 } | 1108 } |
| 1076 | 1109 |
| 1110 // Row-processing for the special case when alpha data contains only one |
| 1111 // transform: color indexing. |
| 1112 static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int row) { |
| 1113 const int num_rows = row - dec->last_row_; |
| 1114 const uint8_t* const in = |
| 1115 (uint8_t*)dec->pixels_ + dec->width_ * dec->last_row_; |
| 1116 if (num_rows <= 0) return; // Nothing to be done. |
| 1117 ApplyInverseTransformsAlpha(dec, num_rows, in); |
| 1118 dec->last_row_ = dec->last_out_row_ = row; |
| 1119 } |
| 1120 |
| 1077 int VP8LDecodeAlphaImageStream(int width, int height, const uint8_t* const data, | 1121 int VP8LDecodeAlphaImageStream(int width, int height, const uint8_t* const data, |
| 1078 size_t data_size, uint8_t* const output) { | 1122 size_t data_size, uint8_t* const output) { |
| 1079 VP8Io io; | 1123 VP8Io io; |
| 1080 int ok = 0; | 1124 int ok = 0; |
| 1081 VP8LDecoder* const dec = VP8LNew(); | 1125 VP8LDecoder* const dec = VP8LNew(); |
| 1126 size_t bytes_per_pixel = sizeof(uint32_t); // Default: BGRA mode. |
| 1082 if (dec == NULL) return 0; | 1127 if (dec == NULL) return 0; |
| 1083 | 1128 |
| 1084 dec->width_ = width; | 1129 dec->width_ = width; |
| 1085 dec->height_ = height; | 1130 dec->height_ = height; |
| 1086 dec->io_ = &io; | 1131 dec->io_ = &io; |
| 1087 | 1132 |
| 1088 VP8InitIo(&io); | 1133 VP8InitIo(&io); |
| 1089 WebPInitCustomIo(NULL, &io); // Just a sanity Init. io won't be used. | 1134 WebPInitCustomIo(NULL, &io); // Just a sanity Init. io won't be used. |
| 1090 io.opaque = output; | 1135 io.opaque = output; |
| 1091 io.width = width; | 1136 io.width = width; |
| 1092 io.height = height; | 1137 io.height = height; |
| 1093 | 1138 |
| 1094 dec->status_ = VP8_STATUS_OK; | 1139 dec->status_ = VP8_STATUS_OK; |
| 1095 VP8LInitBitReader(&dec->br_, data, data_size); | 1140 VP8LInitBitReader(&dec->br_, data, data_size); |
| 1096 | 1141 |
| 1097 dec->action_ = READ_HDR; | 1142 dec->action_ = READ_HDR; |
| 1098 if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Err; | 1143 if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Err; |
| 1099 | 1144 |
| 1100 // Allocate output (note that dec->width_ may have changed here). | 1145 // Special case: if alpha data uses only the color indexing transform and |
| 1101 if (!AllocateARGBBuffers(dec, width)) goto Err; | 1146 // doesn't use color cache (a frequent case), we will use DecodeAlphaData() |
| 1147 // method that only needs allocation of 1 byte per pixel (alpha channel). |
| 1148 if (dec->next_transform_ == 1 && |
| 1149 dec->transforms_[0].type_ == COLOR_INDEXING_TRANSFORM && |
| 1150 dec->hdr_.color_cache_size_ == 0) { |
| 1151 bytes_per_pixel = sizeof(uint8_t); |
| 1152 } |
| 1153 |
| 1154 // Allocate internal buffers (note that dec->width_ may have changed here). |
| 1155 if (!AllocateInternalBuffers(dec, width, bytes_per_pixel)) goto Err; |
| 1102 | 1156 |
| 1103 // Decode (with special row processing). | 1157 // Decode (with special row processing). |
| 1104 dec->action_ = READ_DATA; | 1158 dec->action_ = READ_DATA; |
| 1105 ok = DecodeImageData(dec, dec->argb_, dec->width_, dec->height_, | 1159 ok = (bytes_per_pixel == sizeof(uint8_t)) ? |
| 1106 ExtractAlphaRows); | 1160 DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_, |
| 1161 ExtractPalettedAlphaRows) : |
| 1162 DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_, |
| 1163 ExtractAlphaRows); |
| 1107 | 1164 |
| 1108 Err: | 1165 Err: |
| 1109 VP8LDelete(dec); | 1166 VP8LDelete(dec); |
| 1110 return ok; | 1167 return ok; |
| 1111 } | 1168 } |
| 1112 | 1169 |
| 1113 //------------------------------------------------------------------------------ | 1170 //------------------------------------------------------------------------------ |
| 1114 | 1171 |
| 1115 int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) { | 1172 int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) { |
| 1116 int width, height, has_alpha; | 1173 int width, height, has_alpha; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1136 if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error; | 1193 if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error; |
| 1137 return 1; | 1194 return 1; |
| 1138 | 1195 |
| 1139 Error: | 1196 Error: |
| 1140 VP8LClear(dec); | 1197 VP8LClear(dec); |
| 1141 assert(dec->status_ != VP8_STATUS_OK); | 1198 assert(dec->status_ != VP8_STATUS_OK); |
| 1142 return 0; | 1199 return 0; |
| 1143 } | 1200 } |
| 1144 | 1201 |
| 1145 int VP8LDecodeImage(VP8LDecoder* const dec) { | 1202 int VP8LDecodeImage(VP8LDecoder* const dec) { |
| 1203 const size_t bytes_per_pixel = sizeof(uint32_t); |
| 1146 VP8Io* io = NULL; | 1204 VP8Io* io = NULL; |
| 1147 WebPDecParams* params = NULL; | 1205 WebPDecParams* params = NULL; |
| 1148 | 1206 |
| 1149 // Sanity checks. | 1207 // Sanity checks. |
| 1150 if (dec == NULL) return 0; | 1208 if (dec == NULL) return 0; |
| 1151 | 1209 |
| 1152 io = dec->io_; | 1210 io = dec->io_; |
| 1153 assert(io != NULL); | 1211 assert(io != NULL); |
| 1154 params = (WebPDecParams*)io->opaque; | 1212 params = (WebPDecParams*)io->opaque; |
| 1155 assert(params != NULL); | 1213 assert(params != NULL); |
| 1156 dec->output_ = params->output; | 1214 dec->output_ = params->output; |
| 1157 assert(dec->output_ != NULL); | 1215 assert(dec->output_ != NULL); |
| 1158 | 1216 |
| 1159 // Initialization. | 1217 // Initialization. |
| 1160 if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) { | 1218 if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) { |
| 1161 dec->status_ = VP8_STATUS_INVALID_PARAM; | 1219 dec->status_ = VP8_STATUS_INVALID_PARAM; |
| 1162 goto Err; | 1220 goto Err; |
| 1163 } | 1221 } |
| 1164 | 1222 |
| 1165 if (!AllocateARGBBuffers(dec, io->width)) goto Err; | 1223 if (!AllocateInternalBuffers(dec, io->width, bytes_per_pixel)) goto Err; |
| 1166 | 1224 |
| 1167 if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err; | 1225 if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err; |
| 1168 | 1226 |
| 1169 // Decode. | 1227 // Decode. |
| 1170 dec->action_ = READ_DATA; | 1228 dec->action_ = READ_DATA; |
| 1171 if (!DecodeImageData(dec, dec->argb_, dec->width_, dec->height_, | 1229 if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_, |
| 1172 ProcessRows)) { | 1230 ProcessRows)) { |
| 1173 goto Err; | 1231 goto Err; |
| 1174 } | 1232 } |
| 1175 | 1233 |
| 1176 // Cleanup. | 1234 // Cleanup. |
| 1177 params->last_y = dec->last_out_row_; | 1235 params->last_y = dec->last_out_row_; |
| 1178 VP8LClear(dec); | 1236 VP8LClear(dec); |
| 1179 return 1; | 1237 return 1; |
| 1180 | 1238 |
| 1181 Err: | 1239 Err: |
| 1182 VP8LClear(dec); | 1240 VP8LClear(dec); |
| 1183 assert(dec->status_ != VP8_STATUS_OK); | 1241 assert(dec->status_ != VP8_STATUS_OK); |
| 1184 return 0; | 1242 return 0; |
| 1185 } | 1243 } |
| 1186 | 1244 |
| 1187 //------------------------------------------------------------------------------ | 1245 //------------------------------------------------------------------------------ |
| 1188 | 1246 |
| 1189 #if defined(__cplusplus) || defined(c_plusplus) | 1247 #if defined(__cplusplus) || defined(c_plusplus) |
| 1190 } // extern "C" | 1248 } // extern "C" |
| 1191 #endif | 1249 #endif |
| OLD | NEW |