Index: third_party/libwebp/dec/alpha.c |
diff --git a/third_party/libwebp/dec/alpha.c b/third_party/libwebp/dec/alpha.c |
index 3052ced777ebf3595fac67af9ad279420244fdbc..6e65de90302a14422e7f26076cf49eddeb8d7c39 100644 |
--- a/third_party/libwebp/dec/alpha.c |
+++ b/third_party/libwebp/dec/alpha.c |
@@ -1,4 +1,4 @@ |
-// Copyright 2011 Google Inc. |
+// Copyright 2011 Google Inc. All Rights Reserved. |
// |
// This code is licensed under the same terms as WebM: |
// Software License Agreement: http://www.webmproject.org/license/software/ |
@@ -10,60 +10,131 @@ |
// Author: Skal (pascal.massimino@gmail.com) |
#include <stdlib.h> |
-#include "vp8i.h" |
- |
-#ifdef WEBP_EXPERIMENTAL_FEATURES |
- |
-#include "zlib.h" |
+#include "./vp8i.h" |
+#include "./vp8li.h" |
+#include "../utils/filters.h" |
+#include "../utils/quant_levels.h" |
+#include "../webp/format_constants.h" |
#if defined(__cplusplus) || defined(c_plusplus) |
extern "C" { |
#endif |
+// TODO(skal): move to dsp/ ? |
+static void CopyPlane(const uint8_t* src, int src_stride, |
+ uint8_t* dst, int dst_stride, int width, int height) { |
+ while (height-- > 0) { |
+ memcpy(dst, src, width); |
+ src += src_stride; |
+ dst += dst_stride; |
+ } |
+} |
+ |
+//------------------------------------------------------------------------------ |
+// Decodes the compressed data 'data' of size 'data_size' into the 'output'. |
+// The 'output' buffer should be pre-allocated and must be of the same |
+// dimension 'height'x'stride', as that of the image. |
+// |
+// Returns 1 on successfully decoding the compressed alpha and |
+// 0 if either: |
+// error in bit-stream header (invalid compression mode or filter), or |
+// error returned by appropriate compression method. |
+ |
+static int DecodeAlpha(const uint8_t* data, size_t data_size, |
+ int width, int height, int stride, uint8_t* output) { |
+ uint8_t* decoded_data = NULL; |
+ const size_t decoded_size = height * width; |
+ uint8_t* unfiltered_data = NULL; |
+ WEBP_FILTER_TYPE filter; |
+ int pre_processing; |
+ int rsrv; |
+ int ok = 0; |
+ int method; |
+ |
+ assert(width > 0 && height > 0 && stride >= width); |
+ assert(data != NULL && output != NULL); |
+ |
+ if (data_size <= ALPHA_HEADER_LEN) { |
+ return 0; |
+ } |
+ |
+ method = (data[0] >> 0) & 0x03; |
+ filter = (data[0] >> 2) & 0x03; |
+ pre_processing = (data[0] >> 4) & 0x03; |
+ rsrv = (data[0] >> 6) & 0x03; |
+ if (method < ALPHA_NO_COMPRESSION || |
+ method > ALPHA_LOSSLESS_COMPRESSION || |
+ filter >= WEBP_FILTER_LAST || |
+ pre_processing > ALPHA_PREPROCESSED_LEVELS || |
+ rsrv != 0) { |
+ return 0; |
+ } |
+ |
+ if (method == ALPHA_NO_COMPRESSION) { |
+ ok = (data_size >= decoded_size); |
+ decoded_data = (uint8_t*)data + ALPHA_HEADER_LEN; |
+ } else { |
+ decoded_data = (uint8_t*)malloc(decoded_size); |
+ if (decoded_data == NULL) return 0; |
+ ok = VP8LDecodeAlphaImageStream(width, height, |
+ data + ALPHA_HEADER_LEN, |
+ data_size - ALPHA_HEADER_LEN, |
+ decoded_data); |
+ } |
+ |
+ if (ok) { |
+ WebPFilterFunc unfilter_func = WebPUnfilters[filter]; |
+ if (unfilter_func != NULL) { |
+ unfiltered_data = (uint8_t*)malloc(decoded_size); |
+ if (unfiltered_data == NULL) { |
+ ok = 0; |
+ goto Error; |
+ } |
+ // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode |
+ // and apply filter per image-row. |
+ unfilter_func(decoded_data, width, height, 1, width, unfiltered_data); |
+ // Construct raw_data (height x stride) from alpha data (height x width). |
+ CopyPlane(unfiltered_data, width, output, stride, width, height); |
+ free(unfiltered_data); |
+ } else { |
+ // Construct raw_data (height x stride) from alpha data (height x width). |
+ CopyPlane(decoded_data, width, output, stride, width, height); |
+ } |
+ if (pre_processing == ALPHA_PREPROCESSED_LEVELS) { |
+ ok = DequantizeLevels(decoded_data, width, height); |
+ } |
+ } |
+ |
+ Error: |
+ if (method != ALPHA_NO_COMPRESSION) { |
+ free(decoded_data); |
+ } |
+ return ok; |
+} |
+ |
//------------------------------------------------------------------------------ |
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, |
int row, int num_rows) { |
- uint8_t* output = dec->alpha_plane_; |
const int stride = dec->pic_hdr_.width_; |
- if (row < 0 || row + num_rows > dec->pic_hdr_.height_) { |
- return NULL; // sanity check |
+ |
+ if (row < 0 || num_rows < 0 || row + num_rows > dec->pic_hdr_.height_) { |
+ return NULL; // sanity check. |
} |
- if (row == 0) { |
- // TODO(skal): for now, we just decompress everything during the first call. |
- // Later, we'll decode progressively, but we need to store the |
- // z_stream state. |
- const uint8_t* data = dec->alpha_data_; |
- size_t data_size = dec->alpha_data_size_; |
- const size_t output_size = stride * dec->pic_hdr_.height_; |
- int ret = Z_OK; |
- z_stream strm; |
- |
- memset(&strm, 0, sizeof(strm)); |
- if (inflateInit(&strm) != Z_OK) { |
- return 0; |
- } |
- strm.avail_in = data_size; |
- strm.next_in = (unsigned char*)data; |
- do { |
- strm.avail_out = output_size; |
- strm.next_out = output; |
- ret = inflate(&strm, Z_NO_FLUSH); |
- if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { |
- break; |
- } |
- } while (strm.avail_out == 0); |
- inflateEnd(&strm); |
- if (ret != Z_STREAM_END) { |
- return NULL; // error |
+ if (row == 0) { |
+ // Decode everything during the first call. |
+ if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_, |
+ dec->pic_hdr_.width_, dec->pic_hdr_.height_, stride, |
+ dec->alpha_plane_)) { |
+ return NULL; // Error. |
} |
} |
- return output + row * stride; |
+ |
+ // Return a pointer to the current decoded row. |
+ return dec->alpha_plane_ + row * stride; |
} |
#if defined(__cplusplus) || defined(c_plusplus) |
} // extern "C" |
#endif |
- |
-#endif // WEBP_EXPERIMENTAL_FEATURES |