Index: third_party/libwebp/dec/vp8.c |
diff --git a/third_party/libwebp/dec/vp8.c b/third_party/libwebp/dec/vp8.c |
index 89b669aabad992cb178fa993d73aea6faa5d0b85..b0ccfa2a06d1ed73977324450b51bda12772b91d 100644 |
--- a/third_party/libwebp/dec/vp8.c |
+++ b/third_party/libwebp/dec/vp8.c |
@@ -1,4 +1,4 @@ |
-// Copyright 2010 Google Inc. |
+// Copyright 2010 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,8 +10,11 @@ |
// Author: Skal (pascal.massimino@gmail.com) |
#include <stdlib.h> |
-#include "vp8i.h" |
-#include "webpi.h" |
+ |
+#include "./vp8i.h" |
+#include "./vp8li.h" |
+#include "./webpi.h" |
+#include "../utils/bit_reader.h" |
#if defined(__cplusplus) || defined(c_plusplus) |
extern "C" { |
@@ -32,17 +35,18 @@ static void SetOk(VP8Decoder* const dec) { |
} |
int VP8InitIoInternal(VP8Io* const io, int version) { |
- if (version != WEBP_DECODER_ABI_VERSION) |
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { |
return 0; // mismatch error |
- if (io) { |
+ } |
+ if (io != NULL) { |
memset(io, 0, sizeof(*io)); |
} |
return 1; |
} |
VP8Decoder* VP8New(void) { |
- VP8Decoder* dec = (VP8Decoder*)calloc(1, sizeof(VP8Decoder)); |
- if (dec) { |
+ VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(*dec)); |
+ if (dec != NULL) { |
SetOk(dec); |
WebPWorkerInit(&dec->worker_); |
dec->ready_ = 0; |
@@ -57,35 +61,46 @@ VP8StatusCode VP8Status(VP8Decoder* const dec) { |
} |
const char* VP8StatusMessage(VP8Decoder* const dec) { |
- if (!dec) return "no object"; |
+ if (dec == NULL) return "no object"; |
if (!dec->error_msg_) return "OK"; |
return dec->error_msg_; |
} |
void VP8Delete(VP8Decoder* const dec) { |
- if (dec) { |
+ if (dec != NULL) { |
VP8Clear(dec); |
free(dec); |
} |
} |
int VP8SetError(VP8Decoder* const dec, |
- VP8StatusCode error, const char * const msg) { |
- dec->status_ = error; |
- dec->error_msg_ = msg; |
- dec->ready_ = 0; |
+ VP8StatusCode error, const char* const msg) { |
+ // TODO This check would be unnecessary if alpha decompression was separated |
+ // from VP8ProcessRow/FinishRow. This avoids setting 'dec->status_' to |
+ // something other than VP8_STATUS_BITSTREAM_ERROR on alpha decompression |
+ // failure. |
+ if (dec->status_ == VP8_STATUS_OK) { |
+ dec->status_ = error; |
+ dec->error_msg_ = msg; |
+ dec->ready_ = 0; |
+ } |
return 0; |
} |
//------------------------------------------------------------------------------ |
-int VP8GetInfo(const uint8_t* data, uint32_t data_size, uint32_t chunk_size, |
- int* width, int* height, int* has_alpha) { |
- if (data_size < 10) { |
+int VP8CheckSignature(const uint8_t* const data, size_t data_size) { |
+ return (data_size >= 3 && |
+ data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a); |
+} |
+ |
+int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size, |
+ int* const width, int* const height) { |
+ if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) { |
return 0; // not enough data |
} |
// check signature |
- if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a) { |
+ if (!VP8CheckSignature(data + 3, data_size - 3)) { |
return 0; // Wrong signature. |
} else { |
const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16); |
@@ -93,14 +108,6 @@ int VP8GetInfo(const uint8_t* data, uint32_t data_size, uint32_t chunk_size, |
const int w = ((data[7] << 8) | data[6]) & 0x3fff; |
const int h = ((data[9] << 8) | data[8]) & 0x3fff; |
- if (has_alpha) { |
-#ifdef WEBP_EXPERIMENTAL_FEATURES |
- if (data_size < 11) return 0; |
- *has_alpha = !!(data[10] & 0x80); // the colorspace_ bit |
-#else |
- *has_alpha = 0; |
-#endif |
- } |
if (!key_frame) { // Not a keyframe. |
return 0; |
} |
@@ -130,7 +137,7 @@ int VP8GetInfo(const uint8_t* data, uint32_t data_size, uint32_t chunk_size, |
// Header parsing |
static void ResetSegmentHeader(VP8SegmentHeader* const hdr) { |
- assert(hdr); |
+ assert(hdr != NULL); |
hdr->use_segment_ = 0; |
hdr->update_map_ = 0; |
hdr->absolute_delta_ = 1; |
@@ -141,8 +148,8 @@ static void ResetSegmentHeader(VP8SegmentHeader* const hdr) { |
// Paragraph 9.3 |
static int ParseSegmentHeader(VP8BitReader* br, |
VP8SegmentHeader* hdr, VP8Proba* proba) { |
- assert(br); |
- assert(hdr); |
+ assert(br != NULL); |
+ assert(hdr != NULL); |
hdr->use_segment_ = VP8Get(br); |
if (hdr->use_segment_) { |
hdr->update_map_ = VP8Get(br); |
@@ -178,7 +185,7 @@ static int ParseSegmentHeader(VP8BitReader* br, |
// is returned, and this is an unrecoverable error. |
// If the partitions were positioned ok, VP8_STATUS_OK is returned. |
static VP8StatusCode ParsePartitions(VP8Decoder* const dec, |
- const uint8_t* buf, uint32_t size) { |
+ const uint8_t* buf, size_t size) { |
VP8BitReader* const br = &dec->br_; |
const uint8_t* sz = buf; |
const uint8_t* buf_end = buf + size; |
@@ -249,13 +256,12 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) { |
// Topmost call |
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { |
const uint8_t* buf; |
- uint32_t buf_size; |
- uint32_t vp8_chunk_size; |
- uint32_t bytes_skipped; |
+ size_t buf_size; |
VP8FrameHeader* frm_hdr; |
VP8PictureHeader* pic_hdr; |
VP8BitReader* br; |
VP8StatusCode status; |
+ WebPHeaderStructure headers; |
if (dec == NULL) { |
return 0; |
@@ -266,16 +272,32 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { |
"null VP8Io passed to VP8GetHeaders()"); |
} |
- buf = io->data; |
- buf_size = io->data_size; |
- |
// Process Pre-VP8 chunks. |
- status = WebPParseHeaders(&buf, &buf_size, &vp8_chunk_size, &bytes_skipped); |
+ headers.data = io->data; |
+ headers.data_size = io->data_size; |
+ status = WebPParseHeaders(&headers); |
if (status != VP8_STATUS_OK) { |
return VP8SetError(dec, status, "Incorrect/incomplete header."); |
} |
+ if (headers.is_lossless) { |
+ return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, |
+ "Unexpected lossless format encountered."); |
+ } |
+ |
+ if (dec->alpha_data_ == NULL) { |
+ assert(dec->alpha_data_size_ == 0); |
+ // We have NOT set alpha data yet. Set it now. |
+ // (This is to ensure that dec->alpha_data_ is NOT reset to NULL if |
+ // WebPParseHeaders() is called more than once, as in incremental decoding |
+ // case.) |
+ dec->alpha_data_ = headers.alpha_data; |
+ dec->alpha_data_size_ = headers.alpha_data_size; |
+ } |
// Process the VP8 frame header. |
+ buf = headers.data + headers.offset; |
+ buf_size = headers.data_size - headers.offset; |
+ assert(headers.data_size >= headers.offset); // WebPParseHeaders' guarantee |
if (buf_size < 4) { |
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, |
"Truncated header."); |
@@ -306,7 +328,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { |
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, |
"cannot parse picture header"); |
} |
- if (buf[0] != 0x9d || buf[1] != 0x01 || buf[2] != 0x2a) { |
+ if (!VP8CheckSignature(buf, buf_size)) { |
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, |
"Bad code word"); |
} |
@@ -343,9 +365,6 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { |
"bad partition length"); |
} |
- dec->alpha_data_ = NULL; |
- dec->alpha_data_size_ = 0; |
- |
br = &dec->br_; |
VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_); |
buf += frm_hdr->partition_length_; |
@@ -419,17 +438,9 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { |
if (frm_hdr->partition_length_ < kTrailerSize || |
ext_buf[kTrailerSize - 1] != kTrailerMarker) { |
- Error: |
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, |
"RIFF: Inconsistent extra information."); |
} |
- // Alpha |
- size = (ext_buf[4] << 0) | (ext_buf[5] << 8) | (ext_buf[6] << 16); |
- if (frm_hdr->partition_length_ < size + kTrailerSize) { |
- goto Error; |
- } |
- dec->alpha_data_ = (size > 0) ? ext_buf - size : NULL; |
- dec->alpha_data_size_ = size; |
// Layer |
size = (ext_buf[0] << 0) | (ext_buf[1] << 8) | (ext_buf[2] << 16); |
@@ -467,8 +478,9 @@ typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting |
// Returns the position of the last non-zero coeff plus one |
// (and 0 if there's no coeff at all) |
static int GetCoeffs(VP8BitReader* const br, ProbaArray prob, |
- int ctx, const uint16_t dq[2], int n, int16_t* out) { |
- const uint8_t* p = prob[kBands[n]][ctx]; |
+ int ctx, const quant_t dq, int n, int16_t* out) { |
+ // n is either 0 or 1 here. kBands[n] is not necessary for extracting '*p'. |
+ const uint8_t* p = prob[n][ctx]; |
if (!VP8GetBit(br, p[0])) { // first EOB is more a 'CBP' bit. |
return 0; |
} |
@@ -749,7 +761,7 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) { |
} |
dec->ready_ = 0; |
- return 1; |
+ return ok; |
} |
void VP8Clear(VP8Decoder* const dec) { |