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 |