summaryrefslogtreecommitdiff
path: root/media/libwebp/dec
diff options
context:
space:
mode:
Diffstat (limited to 'media/libwebp/dec')
-rw-r--r--media/libwebp/dec/alphai_dec.h2
-rw-r--r--media/libwebp/dec/common_dec.h2
-rw-r--r--media/libwebp/dec/frame_dec.c9
-rw-r--r--media/libwebp/dec/idec_dec.c19
-rw-r--r--media/libwebp/dec/vp8_dec.h2
-rw-r--r--media/libwebp/dec/vp8i_dec.h4
-rw-r--r--media/libwebp/dec/vp8l_dec.c205
-rw-r--r--media/libwebp/dec/vp8li_dec.h2
-rw-r--r--media/libwebp/dec/webpi_dec.h2
9 files changed, 137 insertions, 110 deletions
diff --git a/media/libwebp/dec/alphai_dec.h b/media/libwebp/dec/alphai_dec.h
index 3b40691b5..d2a404dc5 100644
--- a/media/libwebp/dec/alphai_dec.h
+++ b/media/libwebp/dec/alphai_dec.h
@@ -51,4 +51,4 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
} // extern "C"
#endif
-#endif /* WEBP_DEC_ALPHAI_DEC_H_ */
+#endif // WEBP_DEC_ALPHAI_DEC_H_
diff --git a/media/libwebp/dec/common_dec.h b/media/libwebp/dec/common_dec.h
index 9995f1a51..b158550a8 100644
--- a/media/libwebp/dec/common_dec.h
+++ b/media/libwebp/dec/common_dec.h
@@ -51,4 +51,4 @@ enum { MB_FEATURE_TREE_PROBS = 3,
NUM_PROBAS = 11
};
-#endif // WEBP_DEC_COMMON_DEC_H_
+#endif // WEBP_DEC_COMMON_DEC_H_
diff --git a/media/libwebp/dec/frame_dec.c b/media/libwebp/dec/frame_dec.c
index 57e4d9669..3d1d66274 100644
--- a/media/libwebp/dec/frame_dec.c
+++ b/media/libwebp/dec/frame_dec.c
@@ -338,7 +338,6 @@ void VP8InitDithering(const WebPDecoderOptions* const options,
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
VP8QuantMatrix* const dqm = &dec->dqm_[s];
if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) {
- // TODO(skal): should we specially dither more for uv_quant_ < 0?
const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_;
dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3;
}
@@ -669,15 +668,9 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
(void)height;
assert(headers == NULL || !headers->is_lossless);
#if defined(WEBP_USE_THREAD)
- if (width < MIN_WIDTH_FOR_THREADS) return 0;
- // TODO(skal): tune the heuristic further
-#if 0
- if (height < 2 * width) return 2;
+ if (width >= MIN_WIDTH_FOR_THREADS) return 2;
#endif
- return 2;
-#else // !WEBP_USE_THREAD
return 0;
-#endif
}
#undef MT_CACHE_LINES
diff --git a/media/libwebp/dec/idec_dec.c b/media/libwebp/dec/idec_dec.c
index c9506bc83..ee0d33eac 100644
--- a/media/libwebp/dec/idec_dec.c
+++ b/media/libwebp/dec/idec_dec.c
@@ -140,10 +140,9 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
if (NeedCompressedAlpha(idec)) {
ALPHDecoder* const alph_dec = dec->alph_dec_;
dec->alpha_data_ += offset;
- if (alph_dec != NULL) {
+ if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) {
if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) {
VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_;
- assert(alph_vp8l_dec != NULL);
assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN);
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_,
dec->alpha_data_ + ALPHA_HEADER_LEN,
@@ -449,7 +448,10 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8Io* const io = &idec->io_;
- assert(dec->ready_);
+ // Make sure partition #0 has been read before, to set dec to ready_.
+ if (!dec->ready_) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
if (idec->last_mb_y_ != dec->mb_y_) {
if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
@@ -471,6 +473,12 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
+ // Synchronize the threads.
+ if (dec->mt_method_ > 0) {
+ if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+ }
RestoreContext(&context, dec, token_br);
return VP8_STATUS_SUSPENDED;
}
@@ -489,6 +497,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
}
// Synchronize the thread and check for errors.
if (!VP8ExitCritical(dec, io)) {
+ idec->state_ = STATE_ERROR; // prevent re-entry in IDecError
return IDecError(idec, VP8_STATUS_USER_ABORT);
}
dec->ready_ = 0;
@@ -569,6 +578,10 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
status = DecodePartition0(idec);
}
if (idec->state_ == STATE_VP8_DATA) {
+ const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
+ if (dec == NULL) {
+ return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
+ }
status = DecodeRemaining(idec);
}
if (idec->state_ == STATE_VP8L_HEADER) {
diff --git a/media/libwebp/dec/vp8_dec.h b/media/libwebp/dec/vp8_dec.h
index 7b4941d65..03f4415fb 100644
--- a/media/libwebp/dec/vp8_dec.h
+++ b/media/libwebp/dec/vp8_dec.h
@@ -182,4 +182,4 @@ WEBP_EXTERN int VP8LGetInfo(
} // extern "C"
#endif
-#endif /* WEBP_DEC_VP8_DEC_H_ */
+#endif // WEBP_DEC_VP8_DEC_H_
diff --git a/media/libwebp/dec/vp8i_dec.h b/media/libwebp/dec/vp8i_dec.h
index d0ef67b91..fabee44a0 100644
--- a/media/libwebp/dec/vp8i_dec.h
+++ b/media/libwebp/dec/vp8i_dec.h
@@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 0
-#define DEC_REV_VERSION 0
+#define DEC_REV_VERSION 2
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
@@ -316,4 +316,4 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
} // extern "C"
#endif
-#endif /* WEBP_DEC_VP8I_DEC_H_ */
+#endif // WEBP_DEC_VP8I_DEC_H_
diff --git a/media/libwebp/dec/vp8l_dec.c b/media/libwebp/dec/vp8l_dec.c
index 3d303fb22..0502cb9a5 100644
--- a/media/libwebp/dec/vp8l_dec.c
+++ b/media/libwebp/dec/vp8l_dec.c
@@ -359,17 +359,22 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int color_cache_bits, int allow_recursion) {
int i, j;
VP8LBitReader* const br = &dec->br_;
- VP8LBitReader br_tmp;
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL;
+ // When reading htrees, some might be unused, as the format allows it.
+ // We will still read them but put them in this htree_group_bogus.
+ HTreeGroup htree_group_bogus;
HuffmanCode* huffman_tables = NULL;
+ HuffmanCode* huffman_tables_bogus = NULL;
HuffmanCode* next = NULL;
int num_htree_groups = 1;
- int num_htree_groups_limit = 1;
+ int num_htree_groups_max = 1;
int max_alphabet_size = 0;
int* code_lengths = NULL;
const int table_size = kTableSize[color_cache_bits];
+ int* mapping = NULL;
+ int ok = 0;
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
@@ -386,21 +391,41 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
// The huffman data is stored in red and green bytes.
const int group = (huffman_image[i] >> 8) & 0xffff;
huffman_image[i] = group;
- if (group >= num_htree_groups) {
- num_htree_groups = group + 1;
+ if (group >= num_htree_groups_max) {
+ num_htree_groups_max = group + 1;
}
}
- // Check the validity of num_htree_groups. If it seems too big, use a
+ // Check the validity of num_htree_groups_max. If it seems too big, use a
// smaller value for later. This will prevent big memory allocations to end
// up with a bad bitstream anyway.
- // The value of 1000 is totally arbitrary. We know that num_htree_groups
+ // The value of 1000 is totally arbitrary. We know that num_htree_groups_max
// is smaller than (1 << 16) and should be smaller than the number of pixels
// (though the format allows it to be bigger).
- if (num_htree_groups > 1000 || num_htree_groups > xsize * ysize) {
- num_htree_groups_limit = (xsize * ysize > 1000) ? 1000 : xsize * ysize;
- br_tmp = dec->br_;
+ if (num_htree_groups_max > 1000 || num_htree_groups_max > xsize * ysize) {
+ // Create a mapping from the used indices to the minimal set of used
+ // values [0, num_htree_groups)
+ mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
+ if (mapping == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ goto Error;
+ }
+ // -1 means a value is unmapped, and therefore unused in the Huffman
+ // image.
+ memset(mapping, 0xff, num_htree_groups_max * sizeof(*mapping));
+ for (num_htree_groups = 0, i = 0; i < huffman_pixs; ++i) {
+ // Get the current mapping for the group and remap the Huffman image.
+ int* const mapped_group = &mapping[huffman_image[i]];
+ if (*mapped_group == -1) *mapped_group = num_htree_groups++;
+ huffman_image[i] = *mapped_group;
+ }
+ huffman_tables_bogus = (HuffmanCode*)WebPSafeMalloc(
+ table_size, sizeof(*huffman_tables_bogus));
+ if (huffman_tables_bogus == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ goto Error;
+ }
} else {
- num_htree_groups_limit = num_htree_groups;
+ num_htree_groups = num_htree_groups_max;
}
}
@@ -419,99 +444,91 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
sizeof(*code_lengths));
- // If num_htree_groups_tmp == num_htree_groups, the following loop is executed
- // once.
- // If num_htree_groups_tmp != num_htree_groups, we execute the loop the first
- // time with little memory allocation in the hope that there is a bitstream
- // error. If after num_htree_groups_tmp iterations, no error appears,
- // num_htree_groups is probably the right value so try it out.
- do {
- huffman_tables = (HuffmanCode*)WebPSafeMalloc(
- num_htree_groups_limit * table_size, sizeof(*huffman_tables));
- htree_groups = VP8LHtreeGroupsNew(num_htree_groups_limit);
-
- if (htree_groups == NULL || code_lengths == NULL ||
- huffman_tables == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- goto Error;
- }
+ huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
+ sizeof(*huffman_tables));
+ htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
- next = huffman_tables;
- for (i = 0; i < num_htree_groups_limit; ++i) {
- HTreeGroup* const htree_group = &htree_groups[i];
- HuffmanCode** const htrees = htree_group->htrees;
- int size;
- int total_size = 0;
- int is_trivial_literal = 1;
- int max_bits = 0;
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- int alphabet_size = kAlphabetSize[j];
- htrees[j] = next;
- if (j == 0 && color_cache_bits > 0) {
- alphabet_size += 1 << color_cache_bits;
- }
- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
- if (size == 0) {
- goto Error;
- }
- if (is_trivial_literal && kLiteralMap[j] == 1) {
- is_trivial_literal = (next->bits == 0);
- }
- total_size += next->bits;
- next += size;
- if (j <= ALPHA) {
- int local_max_bits = code_lengths[0];
- int k;
- for (k = 1; k < alphabet_size; ++k) {
- if (code_lengths[k] > local_max_bits) {
- local_max_bits = code_lengths[k];
- }
- }
- max_bits += local_max_bits;
- }
+ if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ next = huffman_tables;
+ for (i = 0; i < num_htree_groups_max; ++i) {
+ // If the index "i" is unused in the Huffman image, read the coefficients
+ // but store them to a bogus htree_group.
+ const int is_bogus = (mapping != NULL && mapping[i] == -1);
+ HTreeGroup* const htree_group =
+ is_bogus ? &htree_group_bogus :
+ &htree_groups[(mapping == NULL) ? i : mapping[i]];
+ HuffmanCode** const htrees = htree_group->htrees;
+ HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next;
+ int size;
+ int total_size = 0;
+ int is_trivial_literal = 1;
+ int max_bits = 0;
+ for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
+ int alphabet_size = kAlphabetSize[j];
+ htrees[j] = huffman_tables_i;
+ if (j == 0 && color_cache_bits > 0) {
+ alphabet_size += 1 << color_cache_bits;
}
- htree_group->is_trivial_literal = is_trivial_literal;
- htree_group->is_trivial_code = 0;
- if (is_trivial_literal) {
- const int red = htrees[RED][0].value;
- const int blue = htrees[BLUE][0].value;
- const int alpha = htrees[ALPHA][0].value;
- htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
- if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
- htree_group->is_trivial_code = 1;
- htree_group->literal_arb |= htrees[GREEN][0].value << 8;
+ size =
+ ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i);
+ if (size == 0) {
+ goto Error;
+ }
+ if (is_trivial_literal && kLiteralMap[j] == 1) {
+ is_trivial_literal = (huffman_tables_i->bits == 0);
+ }
+ total_size += huffman_tables_i->bits;
+ huffman_tables_i += size;
+ if (j <= ALPHA) {
+ int local_max_bits = code_lengths[0];
+ int k;
+ for (k = 1; k < alphabet_size; ++k) {
+ if (code_lengths[k] > local_max_bits) {
+ local_max_bits = code_lengths[k];
+ }
}
+ max_bits += local_max_bits;
}
- htree_group->use_packed_table =
- !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
- if (htree_group->use_packed_table) BuildPackedTable(htree_group);
}
- // If we have survived up to here, num_htree_groups might actually be
- // that big so restart with a proper allocation.
- if (num_htree_groups != num_htree_groups_limit) {
- num_htree_groups_limit = num_htree_groups;
- WebPSafeFree(huffman_tables);
- VP8LHtreeGroupsFree(htree_groups);
- huffman_tables = NULL;
- htree_groups = NULL;
- dec->br_ = br_tmp;
+ if (!is_bogus) next = huffman_tables_i;
+ htree_group->is_trivial_literal = is_trivial_literal;
+ htree_group->is_trivial_code = 0;
+ if (is_trivial_literal) {
+ const int red = htrees[RED][0].value;
+ const int blue = htrees[BLUE][0].value;
+ const int alpha = htrees[ALPHA][0].value;
+ htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
+ if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
+ htree_group->is_trivial_code = 1;
+ htree_group->literal_arb |= htrees[GREEN][0].value << 8;
+ }
}
- } while (i != num_htree_groups);
- WebPSafeFree(code_lengths);
+ htree_group->use_packed_table =
+ !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
+ if (htree_group->use_packed_table) BuildPackedTable(htree_group);
+ }
+ ok = 1;
- // All OK. Finalize pointers and return.
+ // All OK. Finalize pointers.
hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups;
hdr->huffman_tables_ = huffman_tables;
- return 1;
Error:
WebPSafeFree(code_lengths);
- WebPSafeFree(huffman_image);
- WebPSafeFree(huffman_tables);
- VP8LHtreeGroupsFree(htree_groups);
- return 0;
+ WebPSafeFree(huffman_tables_bogus);
+ WebPSafeFree(mapping);
+ if (!ok) {
+ WebPSafeFree(huffman_image);
+ WebPSafeFree(huffman_tables);
+ VP8LHtreeGroupsFree(htree_groups);
+ }
+ return ok;
}
//------------------------------------------------------------------------------
@@ -916,7 +933,11 @@ static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) {
#endif
break;
case 2:
+#if !defined(WORDS_BIGENDIAN)
memcpy(&pattern, src, sizeof(uint16_t));
+#else
+ pattern = ((uint32_t)src[0] << 8) | src[1];
+#endif
#if defined(__arm__) || defined(_M_ARM)
pattern |= pattern << 16;
#elif defined(WEBP_USE_MIPS_DSP_R2)
@@ -1555,7 +1576,6 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
if (dec == NULL) return 0;
assert(alph_dec != NULL);
- alph_dec->vp8l_dec_ = dec;
dec->width_ = alph_dec->width_;
dec->height_ = alph_dec->height_;
@@ -1587,11 +1607,12 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
if (!ok) goto Err;
+ // Only set here, once we are sure it is valid (to avoid thread races).
+ alph_dec->vp8l_dec_ = dec;
return 1;
Err:
- VP8LDelete(alph_dec->vp8l_dec_);
- alph_dec->vp8l_dec_ = NULL;
+ VP8LDelete(dec);
return 0;
}
diff --git a/media/libwebp/dec/vp8li_dec.h b/media/libwebp/dec/vp8li_dec.h
index ed89a02a9..2b9c95a44 100644
--- a/media/libwebp/dec/vp8li_dec.h
+++ b/media/libwebp/dec/vp8li_dec.h
@@ -132,4 +132,4 @@ void VP8LDelete(VP8LDecoder* const dec);
} // extern "C"
#endif
-#endif /* WEBP_DEC_VP8LI_DEC_H_ */
+#endif // WEBP_DEC_VP8LI_DEC_H_
diff --git a/media/libwebp/dec/webpi_dec.h b/media/libwebp/dec/webpi_dec.h
index d0a045e70..83d7444e5 100644
--- a/media/libwebp/dec/webpi_dec.h
+++ b/media/libwebp/dec/webpi_dec.h
@@ -130,4 +130,4 @@ int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
} // extern "C"
#endif
-#endif /* WEBP_DEC_WEBPI_DEC_H_ */
+#endif // WEBP_DEC_WEBPI_DEC_H_