OLD | NEW |
1 // Copyright 2011 Google Inc. | 1 // Copyright 2011 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 // Alpha-plane decompression. | 8 // Alpha-plane decompression. |
9 // | 9 // |
10 // Author: Skal (pascal.massimino@gmail.com) | 10 // Author: Skal (pascal.massimino@gmail.com) |
11 | 11 |
12 #include <stdlib.h> | 12 #include <stdlib.h> |
13 #include "vp8i.h" | 13 #include "./vp8i.h" |
14 | 14 #include "./vp8li.h" |
15 #ifdef WEBP_EXPERIMENTAL_FEATURES | 15 #include "../utils/filters.h" |
16 | 16 #include "../utils/quant_levels.h" |
17 #include "zlib.h" | 17 #include "../webp/format_constants.h" |
18 | 18 |
19 #if defined(__cplusplus) || defined(c_plusplus) | 19 #if defined(__cplusplus) || defined(c_plusplus) |
20 extern "C" { | 20 extern "C" { |
21 #endif | 21 #endif |
22 | 22 |
| 23 // TODO(skal): move to dsp/ ? |
| 24 static void CopyPlane(const uint8_t* src, int src_stride, |
| 25 uint8_t* dst, int dst_stride, int width, int height) { |
| 26 while (height-- > 0) { |
| 27 memcpy(dst, src, width); |
| 28 src += src_stride; |
| 29 dst += dst_stride; |
| 30 } |
| 31 } |
| 32 |
| 33 //------------------------------------------------------------------------------ |
| 34 // Decodes the compressed data 'data' of size 'data_size' into the 'output'. |
| 35 // The 'output' buffer should be pre-allocated and must be of the same |
| 36 // dimension 'height'x'stride', as that of the image. |
| 37 // |
| 38 // Returns 1 on successfully decoding the compressed alpha and |
| 39 // 0 if either: |
| 40 // error in bit-stream header (invalid compression mode or filter), or |
| 41 // error returned by appropriate compression method. |
| 42 |
| 43 static int DecodeAlpha(const uint8_t* data, size_t data_size, |
| 44 int width, int height, int stride, uint8_t* output) { |
| 45 uint8_t* decoded_data = NULL; |
| 46 const size_t decoded_size = height * width; |
| 47 uint8_t* unfiltered_data = NULL; |
| 48 WEBP_FILTER_TYPE filter; |
| 49 int pre_processing; |
| 50 int rsrv; |
| 51 int ok = 0; |
| 52 int method; |
| 53 |
| 54 assert(width > 0 && height > 0 && stride >= width); |
| 55 assert(data != NULL && output != NULL); |
| 56 |
| 57 if (data_size <= ALPHA_HEADER_LEN) { |
| 58 return 0; |
| 59 } |
| 60 |
| 61 method = (data[0] >> 0) & 0x03; |
| 62 filter = (data[0] >> 2) & 0x03; |
| 63 pre_processing = (data[0] >> 4) & 0x03; |
| 64 rsrv = (data[0] >> 6) & 0x03; |
| 65 if (method < ALPHA_NO_COMPRESSION || |
| 66 method > ALPHA_LOSSLESS_COMPRESSION || |
| 67 filter >= WEBP_FILTER_LAST || |
| 68 pre_processing > ALPHA_PREPROCESSED_LEVELS || |
| 69 rsrv != 0) { |
| 70 return 0; |
| 71 } |
| 72 |
| 73 if (method == ALPHA_NO_COMPRESSION) { |
| 74 ok = (data_size >= decoded_size); |
| 75 decoded_data = (uint8_t*)data + ALPHA_HEADER_LEN; |
| 76 } else { |
| 77 decoded_data = (uint8_t*)malloc(decoded_size); |
| 78 if (decoded_data == NULL) return 0; |
| 79 ok = VP8LDecodeAlphaImageStream(width, height, |
| 80 data + ALPHA_HEADER_LEN, |
| 81 data_size - ALPHA_HEADER_LEN, |
| 82 decoded_data); |
| 83 } |
| 84 |
| 85 if (ok) { |
| 86 WebPFilterFunc unfilter_func = WebPUnfilters[filter]; |
| 87 if (unfilter_func != NULL) { |
| 88 unfiltered_data = (uint8_t*)malloc(decoded_size); |
| 89 if (unfiltered_data == NULL) { |
| 90 ok = 0; |
| 91 goto Error; |
| 92 } |
| 93 // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode |
| 94 // and apply filter per image-row. |
| 95 unfilter_func(decoded_data, width, height, 1, width, unfiltered_data); |
| 96 // Construct raw_data (height x stride) from alpha data (height x width). |
| 97 CopyPlane(unfiltered_data, width, output, stride, width, height); |
| 98 free(unfiltered_data); |
| 99 } else { |
| 100 // Construct raw_data (height x stride) from alpha data (height x width). |
| 101 CopyPlane(decoded_data, width, output, stride, width, height); |
| 102 } |
| 103 if (pre_processing == ALPHA_PREPROCESSED_LEVELS) { |
| 104 ok = DequantizeLevels(decoded_data, width, height); |
| 105 } |
| 106 } |
| 107 |
| 108 Error: |
| 109 if (method != ALPHA_NO_COMPRESSION) { |
| 110 free(decoded_data); |
| 111 } |
| 112 return ok; |
| 113 } |
| 114 |
23 //------------------------------------------------------------------------------ | 115 //------------------------------------------------------------------------------ |
24 | 116 |
25 const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, | 117 const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, |
26 int row, int num_rows) { | 118 int row, int num_rows) { |
27 uint8_t* output = dec->alpha_plane_; | |
28 const int stride = dec->pic_hdr_.width_; | 119 const int stride = dec->pic_hdr_.width_; |
29 if (row < 0 || row + num_rows > dec->pic_hdr_.height_) { | 120 |
30 return NULL; // sanity check | 121 if (row < 0 || num_rows < 0 || row + num_rows > dec->pic_hdr_.height_) { |
| 122 return NULL; // sanity check. |
31 } | 123 } |
| 124 |
32 if (row == 0) { | 125 if (row == 0) { |
33 // TODO(skal): for now, we just decompress everything during the first call. | 126 // Decode everything during the first call. |
34 // Later, we'll decode progressively, but we need to store the | 127 if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_, |
35 // z_stream state. | 128 dec->pic_hdr_.width_, dec->pic_hdr_.height_, stride, |
36 const uint8_t* data = dec->alpha_data_; | 129 dec->alpha_plane_)) { |
37 size_t data_size = dec->alpha_data_size_; | 130 return NULL; // Error. |
38 const size_t output_size = stride * dec->pic_hdr_.height_; | |
39 int ret = Z_OK; | |
40 z_stream strm; | |
41 | |
42 memset(&strm, 0, sizeof(strm)); | |
43 if (inflateInit(&strm) != Z_OK) { | |
44 return 0; | |
45 } | |
46 strm.avail_in = data_size; | |
47 strm.next_in = (unsigned char*)data; | |
48 do { | |
49 strm.avail_out = output_size; | |
50 strm.next_out = output; | |
51 ret = inflate(&strm, Z_NO_FLUSH); | |
52 if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { | |
53 break; | |
54 } | |
55 } while (strm.avail_out == 0); | |
56 | |
57 inflateEnd(&strm); | |
58 if (ret != Z_STREAM_END) { | |
59 return NULL; // error | |
60 } | 131 } |
61 } | 132 } |
62 return output + row * stride; | 133 |
| 134 // Return a pointer to the current decoded row. |
| 135 return dec->alpha_plane_ + row * stride; |
63 } | 136 } |
64 | 137 |
65 #if defined(__cplusplus) || defined(c_plusplus) | 138 #if defined(__cplusplus) || defined(c_plusplus) |
66 } // extern "C" | 139 } // extern "C" |
67 #endif | 140 #endif |
68 | |
69 #endif // WEBP_EXPERIMENTAL_FEATURES | |
OLD | NEW |