summaryrefslogtreecommitdiff
path: root/thirdparty
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty')
-rw-r--r--thirdparty/README.md4
-rw-r--r--thirdparty/libwebp/src/dec/alphai_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/buffer_dec.c3
-rw-r--r--thirdparty/libwebp/src/dec/common_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/frame_dec.c9
-rw-r--r--thirdparty/libwebp/src/dec/idec_dec.c25
-rw-r--r--thirdparty/libwebp/src/dec/vp8_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/vp8i_dec.h4
-rw-r--r--thirdparty/libwebp/src/dec/vp8l_dec.c103
-rw-r--r--thirdparty/libwebp/src/dec/vp8li_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/webpi_dec.h2
-rw-r--r--thirdparty/libwebp/src/demux/demux.c2
-rw-r--r--thirdparty/libwebp/src/dsp/dsp.h6
-rw-r--r--thirdparty/libwebp/src/dsp/enc.c6
-rw-r--r--thirdparty/libwebp/src/dsp/enc_avx2.c21
-rw-r--r--thirdparty/libwebp/src/dsp/lossless.c2
-rw-r--r--thirdparty/libwebp/src/dsp/lossless.h14
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc.c86
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc_mips32.c79
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc_sse2.c44
-rw-r--r--thirdparty/libwebp/src/dsp/msa_macro.h2
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler.c4
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_mips32.c4
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c10
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_msa.c7
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_neon.c18
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler_sse2.c35
-rw-r--r--thirdparty/libwebp/src/dsp/yuv.h2
-rw-r--r--thirdparty/libwebp/src/enc/analysis_enc.c2
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_cost_enc.c2
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_enc.c1
-rw-r--r--thirdparty/libwebp/src/enc/cost_enc.h2
-rw-r--r--thirdparty/libwebp/src/enc/delta_palettization_enc.c455
-rw-r--r--thirdparty/libwebp/src/enc/delta_palettization_enc.h25
-rw-r--r--thirdparty/libwebp/src/enc/histogram_enc.c196
-rw-r--r--thirdparty/libwebp/src/enc/histogram_enc.h10
-rw-r--r--thirdparty/libwebp/src/enc/iterator_enc.c2
-rw-r--r--thirdparty/libwebp/src/enc/picture_tools_enc.c41
-rw-r--r--thirdparty/libwebp/src/enc/vp8i_enc.h6
-rw-r--r--thirdparty/libwebp/src/enc/vp8l_enc.c17
-rw-r--r--thirdparty/libwebp/src/enc/vp8li_enc.h2
-rw-r--r--thirdparty/libwebp/src/mux/animi.h2
-rw-r--r--thirdparty/libwebp/src/mux/muxedit.c18
-rw-r--r--thirdparty/libwebp/src/mux/muxi.h18
-rw-r--r--thirdparty/libwebp/src/mux/muxinternal.c53
-rw-r--r--thirdparty/libwebp/src/mux/muxread.c61
-rw-r--r--thirdparty/libwebp/src/utils/bit_reader_inl_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/bit_reader_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/bit_writer_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/filters_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/quant_levels_dec_utils.c8
-rw-r--r--thirdparty/libwebp/src/utils/quant_levels_dec_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/quant_levels_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/random_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/rescaler_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/thread_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/utils.h2
-rw-r--r--thirdparty/libwebp/src/webp/decode.h2
-rw-r--r--thirdparty/libwebp/src/webp/demux.h2
-rw-r--r--thirdparty/libwebp/src/webp/encode.h2
-rw-r--r--thirdparty/libwebp/src/webp/format_constants.h2
-rw-r--r--thirdparty/libwebp/src/webp/mux.h2
-rw-r--r--thirdparty/libwebp/src/webp/mux_types.h2
-rw-r--r--thirdparty/libwebp/src/webp/types.h2
-rw-r--r--thirdparty/tinyexr/tinyexr.h253
65 files changed, 761 insertions, 947 deletions
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 55b693af96..e63e1fc109 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -233,7 +233,7 @@ Godot-made change marked with `// -- GODOT --` comments.
## libwebp
- Upstream: https://chromium.googlesource.com/webm/libwebp/
-- Version: 1.0.0
+- Version: 1.0.1
- License: BSD-3-Clause
Files extracted from upstream source:
@@ -503,7 +503,7 @@ changes are marked with `// -- GODOT --` comments.
## tinyexr
- Upstream: https://github.com/syoyo/tinyexr
-- Version: git (2d5375f, 2018)
+- Version: git (5ae30aa, 2018)
- License: BSD-3-Clause
Files extracted from upstream source:
diff --git a/thirdparty/libwebp/src/dec/alphai_dec.h b/thirdparty/libwebp/src/dec/alphai_dec.h
index e0fa281a55..a64104abeb 100644
--- a/thirdparty/libwebp/src/dec/alphai_dec.h
+++ b/thirdparty/libwebp/src/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/thirdparty/libwebp/src/dec/buffer_dec.c b/thirdparty/libwebp/src/dec/buffer_dec.c
index 75eb3c40b4..3cd94eb4d9 100644
--- a/thirdparty/libwebp/src/dec/buffer_dec.c
+++ b/thirdparty/libwebp/src/dec/buffer_dec.c
@@ -74,7 +74,8 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
} else { // RGB checks
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
const int stride = abs(buf->stride);
- const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
+ const uint64_t size =
+ MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL);
diff --git a/thirdparty/libwebp/src/dec/common_dec.h b/thirdparty/libwebp/src/dec/common_dec.h
index 9995f1a51a..b158550a80 100644
--- a/thirdparty/libwebp/src/dec/common_dec.h
+++ b/thirdparty/libwebp/src/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/thirdparty/libwebp/src/dec/frame_dec.c b/thirdparty/libwebp/src/dec/frame_dec.c
index a9d5430d00..bda9e1a6f6 100644
--- a/thirdparty/libwebp/src/dec/frame_dec.c
+++ b/thirdparty/libwebp/src/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/thirdparty/libwebp/src/dec/idec_dec.c b/thirdparty/libwebp/src/dec/idec_dec.c
index a371ed7500..9bc9166808 100644
--- a/thirdparty/libwebp/src/dec/idec_dec.c
+++ b/thirdparty/libwebp/src/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,
@@ -283,10 +282,8 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) {
- VP8Io* const io = &idec->io_;
- if (io->teardown != NULL) {
- io->teardown(io);
- }
+ // Synchronize the thread, clean-up and check for errors.
+ VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
}
idec->state_ = STATE_ERROR;
return error;
@@ -451,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)) {
@@ -473,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;
}
@@ -491,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;
@@ -571,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/thirdparty/libwebp/src/dec/vp8_dec.h b/thirdparty/libwebp/src/dec/vp8_dec.h
index ca85b340cf..a05405df72 100644
--- a/thirdparty/libwebp/src/dec/vp8_dec.h
+++ b/thirdparty/libwebp/src/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/thirdparty/libwebp/src/dec/vp8i_dec.h b/thirdparty/libwebp/src/dec/vp8i_dec.h
index c929933e1c..e5e89df57d 100644
--- a/thirdparty/libwebp/src/dec/vp8i_dec.h
+++ b/thirdparty/libwebp/src/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 1
// 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/thirdparty/libwebp/src/dec/vp8l_dec.c b/thirdparty/libwebp/src/dec/vp8l_dec.c
index 0570f53a77..333bb3e80d 100644
--- a/thirdparty/libwebp/src/dec/vp8l_dec.c
+++ b/thirdparty/libwebp/src/dec/vp8l_dec.c
@@ -362,12 +362,19 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
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_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.
@@ -384,9 +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_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_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_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 = num_htree_groups_max;
}
}
@@ -403,11 +442,11 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
}
+ code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
+ sizeof(*code_lengths));
huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
sizeof(*huffman_tables));
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
- code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
- sizeof(*code_lengths));
if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
@@ -415,28 +454,35 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
next = huffman_tables;
- for (i = 0; i < num_htree_groups; ++i) {
- HTreeGroup* const htree_group = &htree_groups[i];
+ 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] = next;
+ htrees[j] = huffman_tables_i;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += 1 << color_cache_bits;
}
- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
+ 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 = (next->bits == 0);
+ is_trivial_literal = (huffman_tables_i->bits == 0);
}
- total_size += next->bits;
- next += size;
+ total_size += huffman_tables_i->bits;
+ huffman_tables_i += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
@@ -448,38 +494,41 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
max_bits += local_max_bits;
}
}
+ 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;
+ 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;
}
}
- htree_group->use_packed_table = !htree_group->is_trivial_code &&
- (max_bits < HUFFMAN_PACKED_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);
}
- WebPSafeFree(code_lengths);
+ 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;
}
//------------------------------------------------------------------------------
@@ -884,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)
@@ -1523,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_;
@@ -1555,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/thirdparty/libwebp/src/dec/vp8li_dec.h b/thirdparty/libwebp/src/dec/vp8li_dec.h
index 8e500cf9ff..0a4d613f99 100644
--- a/thirdparty/libwebp/src/dec/vp8li_dec.h
+++ b/thirdparty/libwebp/src/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/thirdparty/libwebp/src/dec/webpi_dec.h b/thirdparty/libwebp/src/dec/webpi_dec.h
index c378ba6fc3..24baff5d27 100644
--- a/thirdparty/libwebp/src/dec/webpi_dec.h
+++ b/thirdparty/libwebp/src/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_
diff --git a/thirdparty/libwebp/src/demux/demux.c b/thirdparty/libwebp/src/demux/demux.c
index 684215e3de..a69c65b7cf 100644
--- a/thirdparty/libwebp/src/demux/demux.c
+++ b/thirdparty/libwebp/src/demux/demux.c
@@ -25,7 +25,7 @@
#define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 0
-#define DMUX_REV_VERSION 0
+#define DMUX_REV_VERSION 1
typedef struct {
size_t start_; // start location of the data
diff --git a/thirdparty/libwebp/src/dsp/dsp.h b/thirdparty/libwebp/src/dsp/dsp.h
index 4ab77a5130..fafc2d05d3 100644
--- a/thirdparty/libwebp/src/dsp/dsp.h
+++ b/thirdparty/libwebp/src/dsp/dsp.h
@@ -76,10 +76,6 @@ extern "C" {
#define WEBP_USE_SSE41
#endif
-#if defined(__AVX2__) || defined(WEBP_HAVE_AVX2)
-#define WEBP_USE_AVX2
-#endif
-
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
// inline assembly would need to be modified for use with Native Client.
#if (defined(__ARM_NEON__) || \
@@ -679,4 +675,4 @@ void VP8FiltersInit(void);
} // extern "C"
#endif
-#endif /* WEBP_DSP_DSP_H_ */
+#endif // WEBP_DSP_DSP_H_
diff --git a/thirdparty/libwebp/src/dsp/enc.c b/thirdparty/libwebp/src/dsp/enc.c
index fa23b40a30..2fddbc4c52 100644
--- a/thirdparty/libwebp/src/dsp/enc.c
+++ b/thirdparty/libwebp/src/dsp/enc.c
@@ -734,7 +734,6 @@ VP8BlockCopy VP8Copy16x8;
extern void VP8EncDspInitSSE2(void);
extern void VP8EncDspInitSSE41(void);
-extern void VP8EncDspInitAVX2(void);
extern void VP8EncDspInitNEON(void);
extern void VP8EncDspInitMIPS32(void);
extern void VP8EncDspInitMIPSdspR2(void);
@@ -784,11 +783,6 @@ WEBP_DSP_INIT_FUNC(VP8EncDspInit) {
#endif
}
#endif
-#if defined(WEBP_USE_AVX2)
- if (VP8GetCPUInfo(kAVX2)) {
- VP8EncDspInitAVX2();
- }
-#endif
#if defined(WEBP_USE_MIPS32)
if (VP8GetCPUInfo(kMIPS32)) {
VP8EncDspInitMIPS32();
diff --git a/thirdparty/libwebp/src/dsp/enc_avx2.c b/thirdparty/libwebp/src/dsp/enc_avx2.c
deleted file mode 100644
index 8bc5798fee..0000000000
--- a/thirdparty/libwebp/src/dsp/enc_avx2.c
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the COPYING file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-// -----------------------------------------------------------------------------
-//
-// AVX2 version of speed-critical encoding functions.
-
-#include "src/dsp/dsp.h"
-
-#if defined(WEBP_USE_AVX2)
-
-#endif // WEBP_USE_AVX2
-
-//------------------------------------------------------------------------------
-// Entry point
-
-WEBP_DSP_INIT_STUB(VP8EncDspInitAVX2)
diff --git a/thirdparty/libwebp/src/dsp/lossless.c b/thirdparty/libwebp/src/dsp/lossless.c
index f9b3c182d3..d21aa6a0a0 100644
--- a/thirdparty/libwebp/src/dsp/lossless.c
+++ b/thirdparty/libwebp/src/dsp/lossless.c
@@ -23,8 +23,6 @@
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
-#define MAX_DIFF_COST (1e30f)
-
//------------------------------------------------------------------------------
// Image transforms.
diff --git a/thirdparty/libwebp/src/dsp/lossless.h b/thirdparty/libwebp/src/dsp/lossless.h
index b2bbdfc93c..f709cc86b2 100644
--- a/thirdparty/libwebp/src/dsp/lossless.h
+++ b/thirdparty/libwebp/src/dsp/lossless.h
@@ -163,7 +163,7 @@ extern VP8LCostCombinedFunc VP8LExtraCostCombined;
extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy;
typedef struct { // small struct to hold counters
- int counts[2]; // index: 0=zero steak, 1=non-zero streak
+ int counts[2]; // index: 0=zero streak, 1=non-zero streak
int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3]
} VP8LStreaks;
@@ -194,10 +194,14 @@ extern VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined;
void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n,
VP8LBitEntropy* const entropy);
-typedef void (*VP8LHistogramAddFunc)(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out);
-extern VP8LHistogramAddFunc VP8LHistogramAdd;
+typedef void (*VP8LAddVectorFunc)(const uint32_t* a, const uint32_t* b,
+ uint32_t* out, int size);
+extern VP8LAddVectorFunc VP8LAddVector;
+typedef void (*VP8LAddVectorEqFunc)(const uint32_t* a, uint32_t* out, int size);
+extern VP8LAddVectorEqFunc VP8LAddVectorEq;
+void VP8LHistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out);
// -----------------------------------------------------------------------------
// PrefixEncode()
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc.c b/thirdparty/libwebp/src/dsp/lossless_enc.c
index d608326fef..1408fbf580 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc.c
@@ -632,38 +632,67 @@ static double ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
//------------------------------------------------------------------------------
-static void HistogramAdd_C(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out) {
+static void AddVector_C(const uint32_t* a, const uint32_t* b, uint32_t* out,
+ int size) {
+ int i;
+ for (i = 0; i < size; ++i) out[i] = a[i] + b[i];
+}
+
+static void AddVectorEq_C(const uint32_t* a, uint32_t* out, int size) {
+ int i;
+ for (i = 0; i < size; ++i) out[i] += a[i];
+}
+
+#define ADD(X, ARG, LEN) do { \
+ if (a->is_used_[X]) { \
+ if (b->is_used_[X]) { \
+ VP8LAddVector(a->ARG, b->ARG, out->ARG, (LEN)); \
+ } else { \
+ memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \
+ } \
+ } else if (b->is_used_[X]) { \
+ memcpy(&out->ARG[0], &b->ARG[0], (LEN) * sizeof(out->ARG[0])); \
+ } else { \
+ memset(&out->ARG[0], 0, (LEN) * sizeof(out->ARG[0])); \
+ } \
+} while (0)
+
+#define ADD_EQ(X, ARG, LEN) do { \
+ if (a->is_used_[X]) { \
+ if (out->is_used_[X]) { \
+ VP8LAddVectorEq(a->ARG, out->ARG, (LEN)); \
+ } else { \
+ memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \
+ } \
+ } \
+} while (0)
+
+void VP8LHistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b, VP8LHistogram* const out) {
int i;
const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_);
assert(a->palette_code_bits_ == b->palette_code_bits_);
+
if (b != out) {
- for (i = 0; i < literal_size; ++i) {
- out->literal_[i] = a->literal_[i] + b->literal_[i];
- }
- for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
- out->distance_[i] = a->distance_[i] + b->distance_[i];
- }
- for (i = 0; i < NUM_LITERAL_CODES; ++i) {
- out->red_[i] = a->red_[i] + b->red_[i];
- out->blue_[i] = a->blue_[i] + b->blue_[i];
- out->alpha_[i] = a->alpha_[i] + b->alpha_[i];
+ ADD(0, literal_, literal_size);
+ ADD(1, red_, NUM_LITERAL_CODES);
+ ADD(2, blue_, NUM_LITERAL_CODES);
+ ADD(3, alpha_, NUM_LITERAL_CODES);
+ ADD(4, distance_, NUM_DISTANCE_CODES);
+ for (i = 0; i < 5; ++i) {
+ out->is_used_[i] = (a->is_used_[i] | b->is_used_[i]);
}
} else {
- for (i = 0; i < literal_size; ++i) {
- out->literal_[i] += a->literal_[i];
- }
- for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
- out->distance_[i] += a->distance_[i];
- }
- for (i = 0; i < NUM_LITERAL_CODES; ++i) {
- out->red_[i] += a->red_[i];
- out->blue_[i] += a->blue_[i];
- out->alpha_[i] += a->alpha_[i];
- }
+ ADD_EQ(0, literal_, literal_size);
+ ADD_EQ(1, red_, NUM_LITERAL_CODES);
+ ADD_EQ(2, blue_, NUM_LITERAL_CODES);
+ ADD_EQ(3, alpha_, NUM_LITERAL_CODES);
+ ADD_EQ(4, distance_, NUM_DISTANCE_CODES);
+ for (i = 0; i < 5; ++i) out->is_used_[i] |= a->is_used_[i];
}
}
+#undef ADD
+#undef ADD_EQ
//------------------------------------------------------------------------------
// Image transforms.
@@ -848,7 +877,8 @@ VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy;
VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined;
VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined;
-VP8LHistogramAddFunc VP8LHistogramAdd;
+VP8LAddVectorFunc VP8LAddVector;
+VP8LAddVectorEqFunc VP8LAddVectorEq;
VP8LVectorMismatchFunc VP8LVectorMismatch;
VP8LBundleColorMapFunc VP8LBundleColorMap;
@@ -885,7 +915,8 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
VP8LGetEntropyUnrefined = GetEntropyUnrefined_C;
VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_C;
- VP8LHistogramAdd = HistogramAdd_C;
+ VP8LAddVector = AddVector_C;
+ VP8LAddVectorEq = AddVectorEq_C;
VP8LVectorMismatch = VectorMismatch_C;
VP8LBundleColorMap = VP8LBundleColorMap_C;
@@ -971,7 +1002,8 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
assert(VP8LCombinedShannonEntropy != NULL);
assert(VP8LGetEntropyUnrefined != NULL);
assert(VP8LGetCombinedEntropyUnrefined != NULL);
- assert(VP8LHistogramAdd != NULL);
+ assert(VP8LAddVector != NULL);
+ assert(VP8LAddVectorEq != NULL);
assert(VP8LVectorMismatch != NULL);
assert(VP8LBundleColorMap != NULL);
assert(VP8LPredictorsSub[0] != NULL);
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c b/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
index e7b58f4e8c..0412a093cf 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
@@ -344,65 +344,29 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[],
ASM_END_COMMON_0 \
ASM_END_COMMON_1
-#define ADD_VECTOR(A, B, OUT, SIZE, EXTRA_SIZE) do { \
- const uint32_t* pa = (const uint32_t*)(A); \
- const uint32_t* pb = (const uint32_t*)(B); \
- uint32_t* pout = (uint32_t*)(OUT); \
- const uint32_t* const LoopEnd = pa + (SIZE); \
- assert((SIZE) % 4 == 0); \
- ASM_START \
- ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) \
- ASM_END_0 \
- if ((EXTRA_SIZE) > 0) { \
- const int last = (EXTRA_SIZE); \
- int i; \
- for (i = 0; i < last; ++i) pout[i] = pa[i] + pb[i]; \
- } \
-} while (0)
-
-#define ADD_VECTOR_EQ(A, OUT, SIZE, EXTRA_SIZE) do { \
- const uint32_t* pa = (const uint32_t*)(A); \
- uint32_t* pout = (uint32_t*)(OUT); \
- const uint32_t* const LoopEnd = pa + (SIZE); \
- assert((SIZE) % 4 == 0); \
- ASM_START \
- ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) \
- ASM_END_1 \
- if ((EXTRA_SIZE) > 0) { \
- const int last = (EXTRA_SIZE); \
- int i; \
- for (i = 0; i < last; ++i) pout[i] += pa[i]; \
- } \
-} while (0)
-
-static void HistogramAdd_MIPS32(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out) {
+static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb,
+ uint32_t* pout, int size) {
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
- const int extra_cache_size = VP8LHistogramNumCodes(a->palette_code_bits_)
- - (NUM_LITERAL_CODES + NUM_LENGTH_CODES);
- assert(a->palette_code_bits_ == b->palette_code_bits_);
-
- if (b != out) {
- ADD_VECTOR(a->literal_, b->literal_, out->literal_,
- NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
- ADD_VECTOR(a->distance_, b->distance_, out->distance_,
- NUM_DISTANCE_CODES, 0);
- ADD_VECTOR(a->red_, b->red_, out->red_, NUM_LITERAL_CODES, 0);
- ADD_VECTOR(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES, 0);
- ADD_VECTOR(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
- } else {
- ADD_VECTOR_EQ(a->literal_, out->literal_,
- NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
- ADD_VECTOR_EQ(a->distance_, out->distance_, NUM_DISTANCE_CODES, 0);
- ADD_VECTOR_EQ(a->red_, out->red_, NUM_LITERAL_CODES, 0);
- ADD_VECTOR_EQ(a->blue_, out->blue_, NUM_LITERAL_CODES, 0);
- ADD_VECTOR_EQ(a->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
- }
+ const uint32_t end = ((size) / 4) * 4;
+ const uint32_t* const LoopEnd = pa + end;
+ int i;
+ ASM_START
+ ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout)
+ ASM_END_0
+ for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i];
+}
+
+static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) {
+ uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ const uint32_t end = ((size) / 4) * 4;
+ const uint32_t* const LoopEnd = pa + end;
+ int i;
+ ASM_START
+ ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout)
+ ASM_END_1
+ for (i = end; i < size; ++i) pout[i] += pa[i];
}
-#undef ADD_VECTOR_EQ
-#undef ADD_VECTOR
#undef ASM_END_1
#undef ASM_END_0
#undef ASM_END_COMMON_1
@@ -422,7 +386,8 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPS32(void) {
VP8LExtraCostCombined = ExtraCostCombined_MIPS32;
VP8LGetEntropyUnrefined = GetEntropyUnrefined_MIPS32;
VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_MIPS32;
- VP8LHistogramAdd = HistogramAdd_MIPS32;
+ VP8LAddVector = AddVector_MIPS32;
+ VP8LAddVectorEq = AddVectorEq_MIPS32;
}
#else // !WEBP_USE_MIPS32
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
index f84a9909e1..36478c4912 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
@@ -170,12 +170,13 @@ static void CollectColorRedTransforms_SSE2(const uint32_t* argb, int stride,
//------------------------------------------------------------------------------
+// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But
+// that's ok since the histogram values are less than 1<<28 (max picture size).
#define LINE_SIZE 16 // 8 or 16
static void AddVector_SSE2(const uint32_t* a, const uint32_t* b, uint32_t* out,
int size) {
int i;
- assert(size % LINE_SIZE == 0);
- for (i = 0; i < size; i += LINE_SIZE) {
+ for (i = 0; i + LINE_SIZE <= size; i += LINE_SIZE) {
const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]);
const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
#if (LINE_SIZE == 16)
@@ -195,12 +196,14 @@ static void AddVector_SSE2(const uint32_t* a, const uint32_t* b, uint32_t* out,
_mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3));
#endif
}
+ for (; i < size; ++i) {
+ out[i] = a[i] + b[i];
+ }
}
static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
int i;
- assert(size % LINE_SIZE == 0);
- for (i = 0; i < size; i += LINE_SIZE) {
+ for (i = 0; i + LINE_SIZE <= size; i += LINE_SIZE) {
const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]);
const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
#if (LINE_SIZE == 16)
@@ -220,35 +223,11 @@ static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
_mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3));
#endif
}
-}
-#undef LINE_SIZE
-
-// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But
-// that's ok since the histogram values are less than 1<<28 (max picture size).
-static void HistogramAdd_SSE2(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out) {
- int i;
- const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_);
- assert(a->palette_code_bits_ == b->palette_code_bits_);
- if (b != out) {
- AddVector_SSE2(a->literal_, b->literal_, out->literal_, NUM_LITERAL_CODES);
- AddVector_SSE2(a->red_, b->red_, out->red_, NUM_LITERAL_CODES);
- AddVector_SSE2(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES);
- AddVector_SSE2(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES);
- } else {
- AddVectorEq_SSE2(a->literal_, out->literal_, NUM_LITERAL_CODES);
- AddVectorEq_SSE2(a->red_, out->red_, NUM_LITERAL_CODES);
- AddVectorEq_SSE2(a->blue_, out->blue_, NUM_LITERAL_CODES);
- AddVectorEq_SSE2(a->alpha_, out->alpha_, NUM_LITERAL_CODES);
- }
- for (i = NUM_LITERAL_CODES; i < literal_size; ++i) {
- out->literal_[i] = a->literal_[i] + b->literal_[i];
- }
- for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
- out->distance_[i] = a->distance_[i] + b->distance_[i];
+ for (; i < size; ++i) {
+ out[i] += a[i];
}
}
+#undef LINE_SIZE
//------------------------------------------------------------------------------
// Entropy
@@ -675,7 +654,8 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) {
VP8LTransformColor = TransformColor_SSE2;
VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE2;
VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE2;
- VP8LHistogramAdd = HistogramAdd_SSE2;
+ VP8LAddVector = AddVector_SSE2;
+ VP8LAddVectorEq = AddVectorEq_SSE2;
VP8LCombinedShannonEntropy = CombinedShannonEntropy_SSE2;
VP8LVectorMismatch = VectorMismatch_SSE2;
VP8LBundleColorMap = BundleColorMap_SSE2;
diff --git a/thirdparty/libwebp/src/dsp/msa_macro.h b/thirdparty/libwebp/src/dsp/msa_macro.h
index dfacda6ccd..de026a1d9e 100644
--- a/thirdparty/libwebp/src/dsp/msa_macro.h
+++ b/thirdparty/libwebp/src/dsp/msa_macro.h
@@ -1389,4 +1389,4 @@ static WEBP_INLINE uint32_t func_hadd_uh_u32(v8u16 in) {
} while (0)
#define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__)
-#endif /* WEBP_DSP_MSA_MACRO_H_ */
+#endif // WEBP_DSP_MSA_MACRO_H_
diff --git a/thirdparty/libwebp/src/dsp/rescaler.c b/thirdparty/libwebp/src/dsp/rescaler.c
index f307d35056..753f84fcf4 100644
--- a/thirdparty/libwebp/src/dsp/rescaler.c
+++ b/thirdparty/libwebp/src/dsp/rescaler.c
@@ -21,6 +21,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
//------------------------------------------------------------------------------
// Row import
@@ -138,7 +139,7 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
if (yscale) {
for (x_out = 0; x_out < x_out_max; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
- const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
dst[x_out] = v;
irow[x_out] = frac; // new fractional start
@@ -153,6 +154,7 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
}
}
+#undef MULT_FIX_FLOOR
#undef MULT_FIX
#undef ROUNDER
diff --git a/thirdparty/libwebp/src/dsp/rescaler_mips32.c b/thirdparty/libwebp/src/dsp/rescaler_mips32.c
index 542f7e5970..61f63c616c 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_mips32.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_mips32.c
@@ -209,6 +209,7 @@ static void ExportRowExpand_MIPS32(WebPRescaler* const wrk) {
}
}
+#if 0 // disabled for now. TODO(skal): make match the C-code
static void ExportRowShrink_MIPS32(WebPRescaler* const wrk) {
const int x_out_max = wrk->dst_width * wrk->num_channels;
uint8_t* dst = wrk->dst;
@@ -273,6 +274,7 @@ static void ExportRowShrink_MIPS32(WebPRescaler* const wrk) {
);
}
}
+#endif // 0
//------------------------------------------------------------------------------
// Entry point
@@ -283,7 +285,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPS32(void) {
WebPRescalerImportRowExpand = ImportRowExpand_MIPS32;
WebPRescalerImportRowShrink = ImportRowShrink_MIPS32;
WebPRescalerExportRowExpand = ExportRowExpand_MIPS32;
- WebPRescalerExportRowShrink = ExportRowShrink_MIPS32;
+// WebPRescalerExportRowShrink = ExportRowShrink_MIPS32;
}
#else // !WEBP_USE_MIPS32
diff --git a/thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c b/thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c
index b78aac15e6..ce9e64862e 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c
@@ -20,10 +20,12 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
//------------------------------------------------------------------------------
// Row export
+#if 0 // disabled for now. TODO(skal): make match the C-code
static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
int i;
const int x_out_max = wrk->dst_width * wrk->num_channels;
@@ -106,7 +108,7 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
}
for (i = 0; i < (x_out_max & 0x3); ++i) {
const uint32_t frac = (uint32_t)MULT_FIX(*frow++, yscale);
- const int v = (int)MULT_FIX(*irow - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(*irow - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
*dst++ = v;
*irow++ = frac; // new fractional start
@@ -154,13 +156,14 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
);
}
for (i = 0; i < (x_out_max & 0x3); ++i) {
- const int v = (int)MULT_FIX(*irow, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
*dst++ = v;
*irow++ = 0;
}
}
}
+#endif // 0
static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
int i;
@@ -294,6 +297,7 @@ static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
}
}
+#undef MULT_FIX_FLOOR
#undef MULT_FIX
#undef ROUNDER
@@ -304,7 +308,7 @@ extern void WebPRescalerDspInitMIPSdspR2(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPSdspR2(void) {
WebPRescalerExportRowExpand = ExportRowExpand_MIPSdspR2;
- WebPRescalerExportRowShrink = ExportRowShrink_MIPSdspR2;
+// WebPRescalerExportRowShrink = ExportRowShrink_MIPSdspR2;
}
#else // !WEBP_USE_MIPS_DSP_R2
diff --git a/thirdparty/libwebp/src/dsp/rescaler_msa.c b/thirdparty/libwebp/src/dsp/rescaler_msa.c
index f3bc99f1cd..c559254836 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_msa.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_msa.c
@@ -22,6 +22,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
#define CALC_MULT_FIX_16(in0, in1, in2, in3, scale, shift, dst) do { \
v4u32 tmp0, tmp1, tmp2, tmp3; \
@@ -262,6 +263,7 @@ static void RescalerExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
}
}
+#if 0 // disabled for now. TODO(skal): make match the C-code
static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
uint8_t* dst, int length,
const uint32_t yscale,
@@ -341,7 +343,7 @@ static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
}
for (x_out = 0; x_out < length; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
- const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
dst[x_out] = v;
irow[x_out] = frac;
@@ -426,6 +428,7 @@ static void RescalerExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
ExportRowShrink_1(irow, dst, x_out_max, wrk);
}
}
+#endif // 0
//------------------------------------------------------------------------------
// Entry point
@@ -434,7 +437,7 @@ extern void WebPRescalerDspInitMSA(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMSA(void) {
WebPRescalerExportRowExpand = RescalerExportRowExpand_MIPSdspR2;
- WebPRescalerExportRowShrink = RescalerExportRowShrink_MIPSdspR2;
+// WebPRescalerExportRowShrink = RescalerExportRowShrink_MIPSdspR2;
}
#else // !WEBP_USE_MSA
diff --git a/thirdparty/libwebp/src/dsp/rescaler_neon.c b/thirdparty/libwebp/src/dsp/rescaler_neon.c
index 3eff9fbaf4..a553f06f79 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_neon.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_neon.c
@@ -22,6 +22,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR_C(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
#define LOAD_32x4(SRC, DST) const uint32x4_t DST = vld1q_u32((SRC))
#define LOAD_32x8(SRC, DST0, DST1) \
@@ -35,8 +36,11 @@
#if (WEBP_RESCALER_RFIX == 32)
#define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1))
-#define MULT_FIX(A, B) /* note: B is actualy scale>>1. See MAKE_HALF_CST */ \
+// note: B is actualy scale>>1. See MAKE_HALF_CST
+#define MULT_FIX(A, B) \
vreinterpretq_u32_s32(vqrdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
+#define MULT_FIX_FLOOR(A, B) \
+ vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
#else
#error "MULT_FIX/WEBP_RESCALER_RFIX need some more work"
#endif
@@ -135,8 +139,8 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
const uint32x4_t A1 = MULT_FIX(in1, yscale_half);
const uint32x4_t B0 = vqsubq_u32(in2, A0);
const uint32x4_t B1 = vqsubq_u32(in3, A1);
- const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half);
- const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half);
+ const uint32x4_t C0 = MULT_FIX_FLOOR(B0, fxy_scale_half);
+ const uint32x4_t C1 = MULT_FIX_FLOOR(B1, fxy_scale_half);
const uint16x4_t D0 = vmovn_u32(C0);
const uint16x4_t D1 = vmovn_u32(C1);
const uint8x8_t E = vmovn_u16(vcombine_u16(D0, D1));
@@ -145,7 +149,7 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
}
for (; x_out < x_out_max; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX_C(frow[x_out], yscale);
- const int v = (int)MULT_FIX_C(irow[x_out] - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR_C(irow[x_out] - frac, fxy_scale);
assert(v >= 0 && v <= 255);
dst[x_out] = v;
irow[x_out] = frac; // new fractional start
@@ -170,6 +174,12 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
}
}
+#undef MULT_FIX_FLOOR_C
+#undef MULT_FIX_C
+#undef MULT_FIX_FLOOR
+#undef MULT_FIX
+#undef ROUNDER
+
//------------------------------------------------------------------------------
extern void WebPRescalerDspInitNEON(void);
diff --git a/thirdparty/libwebp/src/dsp/rescaler_sse2.c b/thirdparty/libwebp/src/dsp/rescaler_sse2.c
index 64c50deab5..f7461a452c 100644
--- a/thirdparty/libwebp/src/dsp/rescaler_sse2.c
+++ b/thirdparty/libwebp/src/dsp/rescaler_sse2.c
@@ -25,6 +25,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
// input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0
static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) {
@@ -224,6 +225,35 @@ static WEBP_INLINE void ProcessRow_SSE2(const __m128i* const A0,
_mm_storel_epi64((__m128i*)dst, G);
}
+static WEBP_INLINE void ProcessRow_Floor_SSE2(const __m128i* const A0,
+ const __m128i* const A1,
+ const __m128i* const A2,
+ const __m128i* const A3,
+ const __m128i* const mult,
+ uint8_t* const dst) {
+ const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
+ const __m128i B0 = _mm_mul_epu32(*A0, *mult);
+ const __m128i B1 = _mm_mul_epu32(*A1, *mult);
+ const __m128i B2 = _mm_mul_epu32(*A2, *mult);
+ const __m128i B3 = _mm_mul_epu32(*A3, *mult);
+ const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX);
+ const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
+#if (WEBP_RESCALER_RFIX < 32)
+ const __m128i D2 =
+ _mm_and_si128(_mm_slli_epi64(B2, 32 - WEBP_RESCALER_RFIX), mask);
+ const __m128i D3 =
+ _mm_and_si128(_mm_slli_epi64(B3, 32 - WEBP_RESCALER_RFIX), mask);
+#else
+ const __m128i D2 = _mm_and_si128(B2, mask);
+ const __m128i D3 = _mm_and_si128(B3, mask);
+#endif
+ const __m128i E0 = _mm_or_si128(D0, D2);
+ const __m128i E1 = _mm_or_si128(D1, D3);
+ const __m128i F = _mm_packs_epi32(E0, E1);
+ const __m128i G = _mm_packus_epi16(F, F);
+ _mm_storel_epi64((__m128i*)dst, G);
+}
+
static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
int x_out;
uint8_t* const dst = wrk->dst;
@@ -322,12 +352,12 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
const __m128i G1 = _mm_or_si128(D1, F3);
_mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
_mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
- ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
+ ProcessRow_Floor_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
}
}
for (; x_out < x_out_max; ++x_out) {
const uint32_t frac = (int)MULT_FIX(frow[x_out], yscale);
- const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255);
dst[x_out] = v;
irow[x_out] = frac; // new fractional start
@@ -352,6 +382,7 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
}
}
+#undef MULT_FIX_FLOOR
#undef MULT_FIX
#undef ROUNDER
diff --git a/thirdparty/libwebp/src/dsp/yuv.h b/thirdparty/libwebp/src/dsp/yuv.h
index eb787270d2..c12be1d094 100644
--- a/thirdparty/libwebp/src/dsp/yuv.h
+++ b/thirdparty/libwebp/src/dsp/yuv.h
@@ -207,4 +207,4 @@ static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
} // extern "C"
#endif
-#endif /* WEBP_DSP_YUV_H_ */
+#endif // WEBP_DSP_YUV_H_
diff --git a/thirdparty/libwebp/src/enc/analysis_enc.c b/thirdparty/libwebp/src/enc/analysis_enc.c
index a47ff7d4e8..687757ae03 100644
--- a/thirdparty/libwebp/src/enc/analysis_enc.c
+++ b/thirdparty/libwebp/src/enc/analysis_enc.c
@@ -458,7 +458,7 @@ static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
dst->uv_alpha += src->uv_alpha;
}
-// initialize the job struct with some TODOs
+// initialize the job struct with some tasks to perform
static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
int start_row, int end_row) {
WebPGetWorkerInterface()->Init(&job->worker);
diff --git a/thirdparty/libwebp/src/enc/backward_references_cost_enc.c b/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
index 7175496c7f..516abd73eb 100644
--- a/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
+++ b/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
@@ -67,7 +67,7 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
// The following code is similar to VP8LHistogramCreate but converts the
// distance to plane code.
- VP8LHistogramInit(histo, cache_bits);
+ VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 1);
while (VP8LRefsCursorOk(&c)) {
VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode,
xsize);
diff --git a/thirdparty/libwebp/src/enc/backward_references_enc.c b/thirdparty/libwebp/src/enc/backward_references_enc.c
index 39230188b9..3ab7b0ac7d 100644
--- a/thirdparty/libwebp/src/enc/backward_references_enc.c
+++ b/thirdparty/libwebp/src/enc/backward_references_enc.c
@@ -715,6 +715,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
for (i = 0; i <= cache_bits_max; ++i) {
histos[i] = VP8LAllocateHistogram(i);
if (histos[i] == NULL) goto Error;
+ VP8LHistogramInit(histos[i], i, /*init_arrays=*/ 1);
if (i == 0) continue;
cc_init[i] = VP8LColorCacheInit(&hashers[i], i);
if (!cc_init[i]) goto Error;
diff --git a/thirdparty/libwebp/src/enc/cost_enc.h b/thirdparty/libwebp/src/enc/cost_enc.h
index bdce1e6a3b..a4b177b342 100644
--- a/thirdparty/libwebp/src/enc/cost_enc.h
+++ b/thirdparty/libwebp/src/enc/cost_enc.h
@@ -79,4 +79,4 @@ extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
} // extern "C"
#endif
-#endif /* WEBP_ENC_COST_ENC_H_ */
+#endif // WEBP_ENC_COST_ENC_H_
diff --git a/thirdparty/libwebp/src/enc/delta_palettization_enc.c b/thirdparty/libwebp/src/enc/delta_palettization_enc.c
deleted file mode 100644
index a61c8e6c93..0000000000
--- a/thirdparty/libwebp/src/enc/delta_palettization_enc.c
+++ /dev/null
@@ -1,455 +0,0 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the COPYING file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-// -----------------------------------------------------------------------------
-//
-// Author: Mislav Bradac (mislavm@google.com)
-//
-
-#include "src/enc/delta_palettization_enc.h"
-
-#ifdef WEBP_EXPERIMENTAL_FEATURES
-#include "src/webp/types.h"
-#include "src/dsp/lossless.h"
-
-#define MK_COL(r, g, b) (((r) << 16) + ((g) << 8) + (b))
-
-// Format allows palette up to 256 entries, but more palette entries produce
-// bigger entropy. In the future it will probably be useful to add more entries
-// that are far from the origin of the palette or choose remaining entries
-// dynamically.
-#define DELTA_PALETTE_SIZE 226
-
-// Palette used for delta_palettization. Entries are roughly sorted by distance
-// of their signed equivalents from the origin.
-static const uint32_t kDeltaPalette[DELTA_PALETTE_SIZE] = {
- MK_COL(0u, 0u, 0u),
- MK_COL(255u, 255u, 255u),
- MK_COL(1u, 1u, 1u),
- MK_COL(254u, 254u, 254u),
- MK_COL(2u, 2u, 2u),
- MK_COL(4u, 4u, 4u),
- MK_COL(252u, 252u, 252u),
- MK_COL(250u, 0u, 0u),
- MK_COL(0u, 250u, 0u),
- MK_COL(0u, 0u, 250u),
- MK_COL(6u, 0u, 0u),
- MK_COL(0u, 6u, 0u),
- MK_COL(0u, 0u, 6u),
- MK_COL(0u, 0u, 248u),
- MK_COL(0u, 0u, 8u),
- MK_COL(0u, 248u, 0u),
- MK_COL(0u, 248u, 248u),
- MK_COL(0u, 248u, 8u),
- MK_COL(0u, 8u, 0u),
- MK_COL(0u, 8u, 248u),
- MK_COL(0u, 8u, 8u),
- MK_COL(8u, 8u, 8u),
- MK_COL(248u, 0u, 0u),
- MK_COL(248u, 0u, 248u),
- MK_COL(248u, 0u, 8u),
- MK_COL(248u, 248u, 0u),
- MK_COL(248u, 8u, 0u),
- MK_COL(8u, 0u, 0u),
- MK_COL(8u, 0u, 248u),
- MK_COL(8u, 0u, 8u),
- MK_COL(8u, 248u, 0u),
- MK_COL(8u, 8u, 0u),
- MK_COL(23u, 23u, 23u),
- MK_COL(13u, 13u, 13u),
- MK_COL(232u, 232u, 232u),
- MK_COL(244u, 244u, 244u),
- MK_COL(245u, 245u, 250u),
- MK_COL(50u, 50u, 50u),
- MK_COL(204u, 204u, 204u),
- MK_COL(236u, 236u, 236u),
- MK_COL(16u, 16u, 16u),
- MK_COL(240u, 16u, 16u),
- MK_COL(16u, 240u, 16u),
- MK_COL(240u, 240u, 16u),
- MK_COL(16u, 16u, 240u),
- MK_COL(240u, 16u, 240u),
- MK_COL(16u, 240u, 240u),
- MK_COL(240u, 240u, 240u),
- MK_COL(0u, 0u, 232u),
- MK_COL(0u, 232u, 0u),
- MK_COL(232u, 0u, 0u),
- MK_COL(0u, 0u, 24u),
- MK_COL(0u, 24u, 0u),
- MK_COL(24u, 0u, 0u),
- MK_COL(32u, 32u, 32u),
- MK_COL(224u, 32u, 32u),
- MK_COL(32u, 224u, 32u),
- MK_COL(224u, 224u, 32u),
- MK_COL(32u, 32u, 224u),
- MK_COL(224u, 32u, 224u),
- MK_COL(32u, 224u, 224u),
- MK_COL(224u, 224u, 224u),
- MK_COL(0u, 0u, 176u),
- MK_COL(0u, 0u, 80u),
- MK_COL(0u, 176u, 0u),
- MK_COL(0u, 176u, 176u),
- MK_COL(0u, 176u, 80u),
- MK_COL(0u, 80u, 0u),
- MK_COL(0u, 80u, 176u),
- MK_COL(0u, 80u, 80u),
- MK_COL(176u, 0u, 0u),
- MK_COL(176u, 0u, 176u),
- MK_COL(176u, 0u, 80u),
- MK_COL(176u, 176u, 0u),
- MK_COL(176u, 80u, 0u),
- MK_COL(80u, 0u, 0u),
- MK_COL(80u, 0u, 176u),
- MK_COL(80u, 0u, 80u),
- MK_COL(80u, 176u, 0u),
- MK_COL(80u, 80u, 0u),
- MK_COL(0u, 0u, 152u),
- MK_COL(0u, 0u, 104u),
- MK_COL(0u, 152u, 0u),
- MK_COL(0u, 152u, 152u),
- MK_COL(0u, 152u, 104u),
- MK_COL(0u, 104u, 0u),
- MK_COL(0u, 104u, 152u),
- MK_COL(0u, 104u, 104u),
- MK_COL(152u, 0u, 0u),
- MK_COL(152u, 0u, 152u),
- MK_COL(152u, 0u, 104u),
- MK_COL(152u, 152u, 0u),
- MK_COL(152u, 104u, 0u),
- MK_COL(104u, 0u, 0u),
- MK_COL(104u, 0u, 152u),
- MK_COL(104u, 0u, 104u),
- MK_COL(104u, 152u, 0u),
- MK_COL(104u, 104u, 0u),
- MK_COL(216u, 216u, 216u),
- MK_COL(216u, 216u, 40u),
- MK_COL(216u, 216u, 176u),
- MK_COL(216u, 216u, 80u),
- MK_COL(216u, 40u, 216u),
- MK_COL(216u, 40u, 40u),
- MK_COL(216u, 40u, 176u),
- MK_COL(216u, 40u, 80u),
- MK_COL(216u, 176u, 216u),
- MK_COL(216u, 176u, 40u),
- MK_COL(216u, 176u, 176u),
- MK_COL(216u, 176u, 80u),
- MK_COL(216u, 80u, 216u),
- MK_COL(216u, 80u, 40u),
- MK_COL(216u, 80u, 176u),
- MK_COL(216u, 80u, 80u),
- MK_COL(40u, 216u, 216u),
- MK_COL(40u, 216u, 40u),
- MK_COL(40u, 216u, 176u),
- MK_COL(40u, 216u, 80u),
- MK_COL(40u, 40u, 216u),
- MK_COL(40u, 40u, 40u),
- MK_COL(40u, 40u, 176u),
- MK_COL(40u, 40u, 80u),
- MK_COL(40u, 176u, 216u),
- MK_COL(40u, 176u, 40u),
- MK_COL(40u, 176u, 176u),
- MK_COL(40u, 176u, 80u),
- MK_COL(40u, 80u, 216u),
- MK_COL(40u, 80u, 40u),
- MK_COL(40u, 80u, 176u),
- MK_COL(40u, 80u, 80u),
- MK_COL(80u, 216u, 216u),
- MK_COL(80u, 216u, 40u),
- MK_COL(80u, 216u, 176u),
- MK_COL(80u, 216u, 80u),
- MK_COL(80u, 40u, 216u),
- MK_COL(80u, 40u, 40u),
- MK_COL(80u, 40u, 176u),
- MK_COL(80u, 40u, 80u),
- MK_COL(80u, 176u, 216u),
- MK_COL(80u, 176u, 40u),
- MK_COL(80u, 176u, 176u),
- MK_COL(80u, 176u, 80u),
- MK_COL(80u, 80u, 216u),
- MK_COL(80u, 80u, 40u),
- MK_COL(80u, 80u, 176u),
- MK_COL(80u, 80u, 80u),
- MK_COL(0u, 0u, 192u),
- MK_COL(0u, 0u, 64u),
- MK_COL(0u, 0u, 128u),
- MK_COL(0u, 192u, 0u),
- MK_COL(0u, 192u, 192u),
- MK_COL(0u, 192u, 64u),
- MK_COL(0u, 192u, 128u),
- MK_COL(0u, 64u, 0u),
- MK_COL(0u, 64u, 192u),
- MK_COL(0u, 64u, 64u),
- MK_COL(0u, 64u, 128u),
- MK_COL(0u, 128u, 0u),
- MK_COL(0u, 128u, 192u),
- MK_COL(0u, 128u, 64u),
- MK_COL(0u, 128u, 128u),
- MK_COL(176u, 216u, 216u),
- MK_COL(176u, 216u, 40u),
- MK_COL(176u, 216u, 176u),
- MK_COL(176u, 216u, 80u),
- MK_COL(176u, 40u, 216u),
- MK_COL(176u, 40u, 40u),
- MK_COL(176u, 40u, 176u),
- MK_COL(176u, 40u, 80u),
- MK_COL(176u, 176u, 216u),
- MK_COL(176u, 176u, 40u),
- MK_COL(176u, 176u, 176u),
- MK_COL(176u, 176u, 80u),
- MK_COL(176u, 80u, 216u),
- MK_COL(176u, 80u, 40u),
- MK_COL(176u, 80u, 176u),
- MK_COL(176u, 80u, 80u),
- MK_COL(192u, 0u, 0u),
- MK_COL(192u, 0u, 192u),
- MK_COL(192u, 0u, 64u),
- MK_COL(192u, 0u, 128u),
- MK_COL(192u, 192u, 0u),
- MK_COL(192u, 192u, 192u),
- MK_COL(192u, 192u, 64u),
- MK_COL(192u, 192u, 128u),
- MK_COL(192u, 64u, 0u),
- MK_COL(192u, 64u, 192u),
- MK_COL(192u, 64u, 64u),
- MK_COL(192u, 64u, 128u),
- MK_COL(192u, 128u, 0u),
- MK_COL(192u, 128u, 192u),
- MK_COL(192u, 128u, 64u),
- MK_COL(192u, 128u, 128u),
- MK_COL(64u, 0u, 0u),
- MK_COL(64u, 0u, 192u),
- MK_COL(64u, 0u, 64u),
- MK_COL(64u, 0u, 128u),
- MK_COL(64u, 192u, 0u),
- MK_COL(64u, 192u, 192u),
- MK_COL(64u, 192u, 64u),
- MK_COL(64u, 192u, 128u),
- MK_COL(64u, 64u, 0u),
- MK_COL(64u, 64u, 192u),
- MK_COL(64u, 64u, 64u),
- MK_COL(64u, 64u, 128u),
- MK_COL(64u, 128u, 0u),
- MK_COL(64u, 128u, 192u),
- MK_COL(64u, 128u, 64u),
- MK_COL(64u, 128u, 128u),
- MK_COL(128u, 0u, 0u),
- MK_COL(128u, 0u, 192u),
- MK_COL(128u, 0u, 64u),
- MK_COL(128u, 0u, 128u),
- MK_COL(128u, 192u, 0u),
- MK_COL(128u, 192u, 192u),
- MK_COL(128u, 192u, 64u),
- MK_COL(128u, 192u, 128u),
- MK_COL(128u, 64u, 0u),
- MK_COL(128u, 64u, 192u),
- MK_COL(128u, 64u, 64u),
- MK_COL(128u, 64u, 128u),
- MK_COL(128u, 128u, 0u),
- MK_COL(128u, 128u, 192u),
- MK_COL(128u, 128u, 64u),
- MK_COL(128u, 128u, 128u),
-};
-
-#undef MK_COL
-
-//------------------------------------------------------------------------------
-// TODO(skal): move the functions to dsp/lossless.c when the correct
-// granularity is found. For now, we'll just copy-paste some useful bits
-// here instead.
-
-// In-place sum of each component with mod 256.
-static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) {
- const uint32_t alpha_and_green = (*a & 0xff00ff00u) + (b & 0xff00ff00u);
- const uint32_t red_and_blue = (*a & 0x00ff00ffu) + (b & 0x00ff00ffu);
- *a = (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu);
-}
-
-static WEBP_INLINE uint32_t Clip255(uint32_t a) {
- if (a < 256) {
- return a;
- }
- // return 0, when a is a negative integer.
- // return 255, when a is positive.
- return ~a >> 24;
-}
-
-// Delta palettization functions.
-static WEBP_INLINE int Square(int x) {
- return x * x;
-}
-
-static WEBP_INLINE uint32_t Intensity(uint32_t a) {
- return
- 30 * ((a >> 16) & 0xff) +
- 59 * ((a >> 8) & 0xff) +
- 11 * ((a >> 0) & 0xff);
-}
-
-static uint32_t CalcDist(uint32_t predicted_value, uint32_t actual_value,
- uint32_t palette_entry) {
- int i;
- uint32_t distance = 0;
- AddPixelsEq(&predicted_value, palette_entry);
- for (i = 0; i < 32; i += 8) {
- const int32_t av = (actual_value >> i) & 0xff;
- const int32_t pv = (predicted_value >> i) & 0xff;
- distance += Square(pv - av);
- }
- // We sum square of intensity difference with factor 10, but because Intensity
- // returns 100 times real intensity we need to multiply differences of colors
- // by 1000.
- distance *= 1000u;
- distance += Square(Intensity(predicted_value)
- - Intensity(actual_value));
- return distance;
-}
-
-static uint32_t Predict(int x, int y, uint32_t* image) {
- const uint32_t t = (y == 0) ? ARGB_BLACK : image[x];
- const uint32_t l = (x == 0) ? ARGB_BLACK : image[x - 1];
- const uint32_t p =
- (((((t >> 24) & 0xff) + ((l >> 24) & 0xff)) / 2) << 24) +
- (((((t >> 16) & 0xff) + ((l >> 16) & 0xff)) / 2) << 16) +
- (((((t >> 8) & 0xff) + ((l >> 8) & 0xff)) / 2) << 8) +
- (((((t >> 0) & 0xff) + ((l >> 0) & 0xff)) / 2) << 0);
- if (x == 0 && y == 0) return ARGB_BLACK;
- if (x == 0) return t;
- if (y == 0) return l;
- return p;
-}
-
-static WEBP_INLINE int AddSubtractComponentFullWithCoefficient(
- int a, int b, int c) {
- return Clip255(a + ((b - c) >> 2));
-}
-
-static WEBP_INLINE uint32_t ClampedAddSubtractFullWithCoefficient(
- uint32_t c0, uint32_t c1, uint32_t c2) {
- const int a = AddSubtractComponentFullWithCoefficient(
- c0 >> 24, c1 >> 24, c2 >> 24);
- const int r = AddSubtractComponentFullWithCoefficient((c0 >> 16) & 0xff,
- (c1 >> 16) & 0xff,
- (c2 >> 16) & 0xff);
- const int g = AddSubtractComponentFullWithCoefficient((c0 >> 8) & 0xff,
- (c1 >> 8) & 0xff,
- (c2 >> 8) & 0xff);
- const int b = AddSubtractComponentFullWithCoefficient(
- c0 & 0xff, c1 & 0xff, c2 & 0xff);
- return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
-}
-
-//------------------------------------------------------------------------------
-
-// Find palette entry with minimum error from difference of actual pixel value
-// and predicted pixel value. Propagate error of pixel to its top and left pixel
-// in src array. Write predicted_value + palette_entry to new_image. Return
-// index of best palette entry.
-static int FindBestPaletteEntry(uint32_t src, uint32_t predicted_value,
- const uint32_t palette[], int palette_size) {
- int i;
- int idx = 0;
- uint32_t best_distance = CalcDist(predicted_value, src, palette[0]);
- for (i = 1; i < palette_size; ++i) {
- const uint32_t distance = CalcDist(predicted_value, src, palette[i]);
- if (distance < best_distance) {
- best_distance = distance;
- idx = i;
- }
- }
- return idx;
-}
-
-static void ApplyBestPaletteEntry(int x, int y,
- uint32_t new_value, uint32_t palette_value,
- uint32_t* src, int src_stride,
- uint32_t* new_image) {
- AddPixelsEq(&new_value, palette_value);
- if (x > 0) {
- src[x - 1] = ClampedAddSubtractFullWithCoefficient(src[x - 1],
- new_value, src[x]);
- }
- if (y > 0) {
- src[x - src_stride] =
- ClampedAddSubtractFullWithCoefficient(src[x - src_stride],
- new_value, src[x]);
- }
- new_image[x] = new_value;
-}
-
-//------------------------------------------------------------------------------
-// Main entry point
-
-static WebPEncodingError ApplyDeltaPalette(uint32_t* src, uint32_t* dst,
- uint32_t src_stride,
- uint32_t dst_stride,
- const uint32_t* palette,
- int palette_size,
- int width, int height,
- int num_passes) {
- int x, y;
- WebPEncodingError err = VP8_ENC_OK;
- uint32_t* new_image = (uint32_t*)WebPSafeMalloc(width, sizeof(*new_image));
- uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
- if (new_image == NULL || tmp_row == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
-
- while (num_passes--) {
- uint32_t* cur_src = src;
- uint32_t* cur_dst = dst;
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const uint32_t predicted_value = Predict(x, y, new_image);
- tmp_row[x] = FindBestPaletteEntry(cur_src[x], predicted_value,
- palette, palette_size);
- ApplyBestPaletteEntry(x, y, predicted_value, palette[tmp_row[x]],
- cur_src, src_stride, new_image);
- }
- for (x = 0; x < width; ++x) {
- cur_dst[x] = palette[tmp_row[x]];
- }
- cur_src += src_stride;
- cur_dst += dst_stride;
- }
- }
- Error:
- WebPSafeFree(new_image);
- WebPSafeFree(tmp_row);
- return err;
-}
-
-// replaces enc->argb_ by a palettizable approximation of it,
-// and generates optimal enc->palette_[]
-WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc) {
- const WebPPicture* const pic = enc->pic_;
- uint32_t* src = pic->argb;
- uint32_t* dst = enc->argb_;
- const int width = pic->width;
- const int height = pic->height;
-
- WebPEncodingError err = VP8_ENC_OK;
- memcpy(enc->palette_, kDeltaPalette, sizeof(kDeltaPalette));
- enc->palette_[DELTA_PALETTE_SIZE - 1] = src[0] - 0xff000000u;
- enc->palette_size_ = DELTA_PALETTE_SIZE;
- err = ApplyDeltaPalette(src, dst, pic->argb_stride, enc->current_width_,
- enc->palette_, enc->palette_size_,
- width, height, 2);
- if (err != VP8_ENC_OK) goto Error;
-
- Error:
- return err;
-}
-
-#else // !WEBP_EXPERIMENTAL_FEATURES
-
-WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc) {
- (void)enc;
- return VP8_ENC_ERROR_INVALID_CONFIGURATION;
-}
-
-#endif // WEBP_EXPERIMENTAL_FEATURES
diff --git a/thirdparty/libwebp/src/enc/delta_palettization_enc.h b/thirdparty/libwebp/src/enc/delta_palettization_enc.h
deleted file mode 100644
index b15e2cd487..0000000000
--- a/thirdparty/libwebp/src/enc/delta_palettization_enc.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the COPYING file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-// -----------------------------------------------------------------------------
-//
-// Author: Mislav Bradac (mislavm@google.com)
-//
-
-#ifndef WEBP_ENC_DELTA_PALETTIZATION_ENC_H_
-#define WEBP_ENC_DELTA_PALETTIZATION_ENC_H_
-
-#include "src/webp/encode.h"
-#include "src/enc/vp8li_enc.h"
-
-// Replaces enc->argb_[] input by a palettizable approximation of it,
-// and generates optimal enc->palette_[].
-// This function can revert enc->use_palette_ / enc->use_predict_ flag
-// if delta-palettization is not producing expected saving.
-WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc);
-
-#endif // WEBP_ENC_DELTA_PALETTIZATION_ENC_H_
diff --git a/thirdparty/libwebp/src/enc/histogram_enc.c b/thirdparty/libwebp/src/enc/histogram_enc.c
index 9fdbc627a1..4e49e0a201 100644
--- a/thirdparty/libwebp/src/enc/histogram_enc.c
+++ b/thirdparty/libwebp/src/enc/histogram_enc.c
@@ -51,10 +51,12 @@ static void HistogramCopy(const VP8LHistogram* const src,
VP8LHistogram* const dst) {
uint32_t* const dst_literal = dst->literal_;
const int dst_cache_bits = dst->palette_code_bits_;
+ const int literal_size = VP8LHistogramNumCodes(dst_cache_bits);
const int histo_size = VP8LGetHistogramSize(dst_cache_bits);
assert(src->palette_code_bits_ == dst_cache_bits);
memcpy(dst, src, histo_size);
dst->literal_ = dst_literal;
+ memcpy(dst->literal_, src->literal_, literal_size * sizeof(*dst->literal_));
}
int VP8LGetHistogramSize(int cache_bits) {
@@ -91,9 +93,19 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
VP8LHistogramStoreRefs(refs, p);
}
-void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) {
+void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
+ int init_arrays) {
p->palette_code_bits_ = palette_code_bits;
- HistogramClear(p);
+ if (init_arrays) {
+ HistogramClear(p);
+ } else {
+ p->trivial_symbol_ = 0;
+ p->bit_cost_ = 0.;
+ p->literal_cost_ = 0.;
+ p->red_cost_ = 0.;
+ p->blue_cost_ = 0.;
+ memset(p->is_used_, 0, sizeof(p->is_used_));
+ }
}
VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
@@ -104,37 +116,70 @@ VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
histo = (VP8LHistogram*)memory;
// literal_ won't necessary be aligned.
histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
- VP8LHistogramInit(histo, cache_bits);
+ VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0);
return histo;
}
+// Resets the pointers of the histograms to point to the bit buffer in the set.
+static void HistogramSetResetPointers(VP8LHistogramSet* const set,
+ int cache_bits) {
+ int i;
+ const int histo_size = VP8LGetHistogramSize(cache_bits);
+ uint8_t* memory = (uint8_t*) (set->histograms);
+ memory += set->max_size * sizeof(*set->histograms);
+ for (i = 0; i < set->max_size; ++i) {
+ memory = (uint8_t*) WEBP_ALIGN(memory);
+ set->histograms[i] = (VP8LHistogram*) memory;
+ // literal_ won't necessary be aligned.
+ set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
+ memory += histo_size;
+ }
+}
+
+// Returns the total size of the VP8LHistogramSet.
+static size_t HistogramSetTotalSize(int size, int cache_bits) {
+ const int histo_size = VP8LGetHistogramSize(cache_bits);
+ return (sizeof(VP8LHistogramSet) + size * (sizeof(VP8LHistogram*) +
+ histo_size + WEBP_ALIGN_CST));
+}
+
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
int i;
VP8LHistogramSet* set;
- const int histo_size = VP8LGetHistogramSize(cache_bits);
- const size_t total_size =
- sizeof(*set) + size * (sizeof(*set->histograms) +
- histo_size + WEBP_ALIGN_CST);
+ const size_t total_size = HistogramSetTotalSize(size, cache_bits);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
if (memory == NULL) return NULL;
set = (VP8LHistogramSet*)memory;
memory += sizeof(*set);
set->histograms = (VP8LHistogram**)memory;
- memory += size * sizeof(*set->histograms);
set->max_size = size;
set->size = size;
+ HistogramSetResetPointers(set, cache_bits);
for (i = 0; i < size; ++i) {
- memory = (uint8_t*)WEBP_ALIGN(memory);
- set->histograms[i] = (VP8LHistogram*)memory;
- // literal_ won't necessary be aligned.
- set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
- VP8LHistogramInit(set->histograms[i], cache_bits);
- memory += histo_size;
+ VP8LHistogramInit(set->histograms[i], cache_bits, /*init_arrays=*/ 0);
}
return set;
}
+void VP8LHistogramSetClear(VP8LHistogramSet* const set) {
+ int i;
+ const int cache_bits = set->histograms[0]->palette_code_bits_;
+ const int size = set->size;
+ const size_t total_size = HistogramSetTotalSize(size, cache_bits);
+ uint8_t* memory = (uint8_t*)set;
+
+ memset(memory, 0, total_size);
+ memory += sizeof(*set);
+ set->histograms = (VP8LHistogram**)memory;
+ set->max_size = size;
+ set->size = size;
+ HistogramSetResetPointers(set, cache_bits);
+ for (i = 0; i < size; ++i) {
+ set->histograms[i]->palette_code_bits_ = cache_bits;
+ }
+}
+
// -----------------------------------------------------------------------------
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
@@ -237,7 +282,8 @@ static double FinalHuffmanCost(const VP8LStreaks* const stats) {
// Get the symbol entropy for the distribution 'population'.
// Set 'trivial_sym', if there's only one symbol present in the distribution.
static double PopulationCost(const uint32_t* const population, int length,
- uint32_t* const trivial_sym) {
+ uint32_t* const trivial_sym,
+ uint8_t* const is_used) {
VP8LBitEntropy bit_entropy;
VP8LStreaks stats;
VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats);
@@ -245,6 +291,8 @@ static double PopulationCost(const uint32_t* const population, int length,
*trivial_sym = (bit_entropy.nonzeros == 1) ? bit_entropy.nonzero_code
: VP8L_NON_TRIVIAL_SYM;
}
+ // The histogram is used if there is at least one non-zero streak.
+ *is_used = (stats.streaks[1][0] != 0 || stats.streaks[1][1] != 0);
return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats);
}
@@ -253,7 +301,9 @@ static double PopulationCost(const uint32_t* const population, int length,
// non-zero: both the zero-th one, or both the last one.
static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
const uint32_t* const Y,
- int length, int trivial_at_end) {
+ int length, int is_X_used,
+ int is_Y_used,
+ int trivial_at_end) {
VP8LStreaks stats;
if (trivial_at_end) {
// This configuration is due to palettization that transforms an indexed
@@ -262,28 +312,43 @@ static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
// Only FinalHuffmanCost needs to be evaluated.
memset(&stats, 0, sizeof(stats));
// Deal with the non-zero value at index 0 or length-1.
- stats.streaks[1][0] += 1;
+ stats.streaks[1][0] = 1;
// Deal with the following/previous zero streak.
- stats.counts[0] += 1;
- stats.streaks[0][1] += length - 1;
+ stats.counts[0] = 1;
+ stats.streaks[0][1] = length - 1;
return FinalHuffmanCost(&stats);
} else {
VP8LBitEntropy bit_entropy;
- VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats);
+ if (is_X_used) {
+ if (is_Y_used) {
+ VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats);
+ } else {
+ VP8LGetEntropyUnrefined(X, length, &bit_entropy, &stats);
+ }
+ } else {
+ if (is_Y_used) {
+ VP8LGetEntropyUnrefined(Y, length, &bit_entropy, &stats);
+ } else {
+ memset(&stats, 0, sizeof(stats));
+ stats.counts[0] = 1;
+ stats.streaks[0][length > 3] = length;
+ VP8LBitEntropyInit(&bit_entropy);
+ }
+ }
return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats);
}
}
// Estimates the Entropy + Huffman + other block overhead size cost.
-double VP8LHistogramEstimateBits(const VP8LHistogram* const p) {
+double VP8LHistogramEstimateBits(VP8LHistogram* const p) {
return
- PopulationCost(
- p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_), NULL)
- + PopulationCost(p->red_, NUM_LITERAL_CODES, NULL)
- + PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL)
- + PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL)
- + PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL)
+ PopulationCost(p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_),
+ NULL, &p->is_used_[0])
+ + PopulationCost(p->red_, NUM_LITERAL_CODES, NULL, &p->is_used_[1])
+ + PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL, &p->is_used_[2])
+ + PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL, &p->is_used_[3])
+ + PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL, &p->is_used_[4])
+ VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES)
+ VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES);
}
@@ -299,7 +364,8 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
int trivial_at_end = 0;
assert(a->palette_code_bits_ == b->palette_code_bits_);
*cost += GetCombinedEntropy(a->literal_, b->literal_,
- VP8LHistogramNumCodes(palette_code_bits), 0);
+ VP8LHistogramNumCodes(palette_code_bits),
+ a->is_used_[0], b->is_used_[0], 0);
*cost += VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES,
b->literal_ + NUM_LITERAL_CODES,
NUM_LENGTH_CODES);
@@ -319,19 +385,23 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
}
*cost +=
- GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES, trivial_at_end);
+ GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES, a->is_used_[1],
+ b->is_used_[1], trivial_at_end);
if (*cost > cost_threshold) return 0;
*cost +=
- GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES, trivial_at_end);
+ GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES, a->is_used_[2],
+ b->is_used_[2], trivial_at_end);
if (*cost > cost_threshold) return 0;
- *cost += GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES,
- trivial_at_end);
+ *cost +=
+ GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES,
+ a->is_used_[3], b->is_used_[3], trivial_at_end);
if (*cost > cost_threshold) return 0;
*cost +=
- GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES, 0);
+ GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES,
+ a->is_used_[4], b->is_used_[4], 0);
*cost +=
VP8LExtraCostCombined(a->distance_, b->distance_, NUM_DISTANCE_CODES);
if (*cost > cost_threshold) return 0;
@@ -419,16 +489,19 @@ static void UpdateDominantCostRange(
static void UpdateHistogramCost(VP8LHistogram* const h) {
uint32_t alpha_sym, red_sym, blue_sym;
const double alpha_cost =
- PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym);
+ PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym,
+ &h->is_used_[3]);
const double distance_cost =
- PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL) +
+ PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) +
VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_);
- h->literal_cost_ = PopulationCost(h->literal_, num_codes, NULL) +
- VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES,
- NUM_LENGTH_CODES);
- h->red_cost_ = PopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym);
- h->blue_cost_ = PopulationCost(h->blue_, NUM_LITERAL_CODES, &blue_sym);
+ h->literal_cost_ =
+ PopulationCost(h->literal_, num_codes, NULL, &h->is_used_[0]) +
+ VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES);
+ h->red_cost_ =
+ PopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym, &h->is_used_[1]);
+ h->blue_cost_ =
+ PopulationCost(h->blue_, NUM_LITERAL_CODES, &blue_sym, &h->is_used_[2]);
h->bit_cost_ = h->literal_cost_ + h->red_cost_ + h->blue_cost_ +
alpha_cost + distance_cost;
if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) {
@@ -473,6 +546,7 @@ static void HistogramBuild(
VP8LHistogram** const histograms = image_histo->histograms;
VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs);
assert(histo_bits > 0);
+ VP8LHistogramSetClear(image_histo);
while (VP8LRefsCursorOk(&c)) {
const PixOrCopy* const v = c.cur_pos;
const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
@@ -493,11 +567,19 @@ static void HistogramCopyAndAnalyze(
const int histo_size = orig_histo->size;
VP8LHistogram** const orig_histograms = orig_histo->histograms;
VP8LHistogram** const histograms = image_histo->histograms;
+ image_histo->size = 0;
for (i = 0; i < histo_size; ++i) {
VP8LHistogram* const histo = orig_histograms[i];
UpdateHistogramCost(histo);
+
+ // Skip the histogram if it is completely empty, which can happen for tiles
+ // with no information (when they are skipped because of LZ77).
+ if (!histo->is_used_[0] && !histo->is_used_[1] && !histo->is_used_[2]
+ && !histo->is_used_[3] && !histo->is_used_[4]) {
+ continue;
+ }
// Copy histograms from orig_histo[] to image_histo[].
- HistogramCopy(histo, histograms[i]);
+ HistogramCopy(histo, histograms[image_histo->size++]);
}
}
@@ -674,6 +756,18 @@ static void HistoQueueUpdateHead(HistoQueue* const histo_queue,
}
}
+// Update the cost diff and combo of a pair of histograms. This needs to be
+// called when the the histograms have been merged with a third one.
+static void HistoQueueUpdatePair(const VP8LHistogram* const h1,
+ const VP8LHistogram* const h2,
+ double threshold,
+ HistogramPair* const pair) {
+ const double sum_cost = h1->bit_cost_ + h2->bit_cost_;
+ pair->cost_combo = 0.;
+ GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair->cost_combo);
+ pair->cost_diff = pair->cost_combo - sum_cost;
+}
+
// Create a pair from indices "idx1" and "idx2" provided its cost
// is inferior to "threshold", a negative entropy.
// It returns the cost of the pair, or 0. if it superior to threshold.
@@ -683,7 +777,6 @@ static double HistoQueuePush(HistoQueue* const histo_queue,
const VP8LHistogram* h1;
const VP8LHistogram* h2;
HistogramPair pair;
- double sum_cost;
assert(threshold <= 0.);
if (idx1 > idx2) {
@@ -695,10 +788,8 @@ static double HistoQueuePush(HistoQueue* const histo_queue,
pair.idx2 = idx2;
h1 = histograms[idx1];
h2 = histograms[idx2];
- sum_cost = h1->bit_cost_ + h2->bit_cost_;
- pair.cost_combo = 0.;
- GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair.cost_combo);
- pair.cost_diff = pair.cost_combo - sum_cost;
+
+ HistoQueueUpdatePair(h1, h2, threshold, &pair);
// Do not even consider the pair if it does not improve the entropy.
if (pair.cost_diff >= threshold) return 0.;
@@ -891,8 +982,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
}
if (do_eval) {
// Re-evaluate the cost of an updated pair.
- GetCombinedHistogramEntropy(histograms[p->idx1], histograms[p->idx2], 0,
- &p->cost_diff);
+ HistoQueueUpdatePair(histograms[p->idx1], histograms[p->idx2], 0., p);
if (p->cost_diff >= 0.) {
HistoQueuePopPair(&histo_queue, p);
continue;
@@ -987,8 +1077,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
// histograms of small sizes (as bin_map will be very sparse) and
// maximum quality q==100 (to preserve the compression gains at that level).
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
- const int entropy_combine =
- (orig_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
+ int entropy_combine;
if (orig_histo == NULL) goto Error;
@@ -996,15 +1085,16 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
HistogramBuild(xsize, histo_bits, refs, orig_histo);
// Copies the histograms and computes its bit_cost.
HistogramCopyAndAnalyze(orig_histo, image_histo);
-
+ entropy_combine =
+ (image_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
if (entropy_combine) {
- const int bin_map_size = orig_histo->size;
+ const int bin_map_size = image_histo->size;
// Reuse histogram_symbols storage. By definition, it's guaranteed to be ok.
uint16_t* const bin_map = histogram_symbols;
const double combine_cost_factor =
GetCombineCostFactor(image_histo_raw_size, quality);
- HistogramAnalyzeEntropyBin(orig_histo, bin_map, low_effort);
+ HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort);
// Collapse histograms with similar entropy.
HistogramCombineEntropyBin(image_histo, tmp_histo, bin_map, bin_map_size,
entropy_combine_num_bins, combine_cost_factor,
diff --git a/thirdparty/libwebp/src/enc/histogram_enc.h b/thirdparty/libwebp/src/enc/histogram_enc.h
index e8c4c83f6f..54c2d21783 100644
--- a/thirdparty/libwebp/src/enc/histogram_enc.h
+++ b/thirdparty/libwebp/src/enc/histogram_enc.h
@@ -44,6 +44,7 @@ typedef struct {
double literal_cost_; // Cached values of dominant entropy costs:
double red_cost_; // literal, red & blue.
double blue_cost_;
+ uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance
} VP8LHistogram;
// Collection of histograms with fixed capacity, allocated as one
@@ -67,7 +68,9 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
int VP8LGetHistogramSize(int palette_code_bits);
// Set the palette_code_bits and reset the stats.
-void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
+// If init_arrays is true, the arrays are also filled with 0's.
+void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
+ int init_arrays);
// Collect all the references into a histogram (without reset)
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
@@ -83,6 +86,9 @@ void VP8LFreeHistogramSet(VP8LHistogramSet* const histo);
// using 'cache_bits'. Return NULL in case of memory error.
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
+// Set the histograms in set to 0.
+void VP8LHistogramSetClear(VP8LHistogramSet* const set);
+
// Allocate and initialize histogram object with specified 'cache_bits'.
// Returns NULL in case of memory error.
// Special case of VP8LAllocateHistogramSet, with size equals 1.
@@ -113,7 +119,7 @@ double VP8LBitsEntropy(const uint32_t* const array, int n);
// Estimate how many bits the combined entropy of literals and distance
// approximately maps to.
-double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
+double VP8LHistogramEstimateBits(VP8LHistogram* const p);
#ifdef __cplusplus
}
diff --git a/thirdparty/libwebp/src/enc/iterator_enc.c b/thirdparty/libwebp/src/enc/iterator_enc.c
index 7c47d51272..29f91d8315 100644
--- a/thirdparty/libwebp/src/enc/iterator_enc.c
+++ b/thirdparty/libwebp/src/enc/iterator_enc.c
@@ -128,7 +128,7 @@ static void ImportLine(const uint8_t* src, int src_stride,
for (; i < total_len; ++i) dst[i] = dst[len - 1];
}
-void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32) {
+void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32) {
const VP8Encoder* const enc = it->enc_;
const int x = it->x_, y = it->y_;
const WebPPicture* const pic = enc->pic_;
diff --git a/thirdparty/libwebp/src/enc/picture_tools_enc.c b/thirdparty/libwebp/src/enc/picture_tools_enc.c
index be292d4391..d0e8a495da 100644
--- a/thirdparty/libwebp/src/enc/picture_tools_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_tools_enc.c
@@ -16,10 +16,6 @@
#include "src/enc/vp8i_enc.h"
#include "src/dsp/yuv.h"
-static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) {
- return (0xff000000u | (r << 16) | (g << 8) | b);
-}
-
//------------------------------------------------------------------------------
// Helper: clean up fully transparent area to help compressibility.
@@ -195,6 +191,10 @@ void WebPCleanupTransparentAreaLossless(WebPPicture* const pic) {
#define BLEND_10BIT(V0, V1, ALPHA) \
((((V0) * (1020 - (ALPHA)) + (V1) * (ALPHA)) * 0x101 + 1024) >> 18)
+static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) {
+ return (0xff000000u | (r << 16) | (g << 8) | b);
+}
+
void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
const int red = (background_rgb >> 16) & 0xff;
const int green = (background_rgb >> 8) & 0xff;
@@ -208,39 +208,44 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT;
- if (!has_alpha || pic->a == NULL) return; // nothing to do
+ uint8_t* y_ptr = pic->y;
+ uint8_t* u_ptr = pic->u;
+ uint8_t* v_ptr = pic->v;
+ uint8_t* a_ptr = pic->a;
+ if (!has_alpha || a_ptr == NULL) return; // nothing to do
for (y = 0; y < pic->height; ++y) {
// Luma blending
- uint8_t* const y_ptr = pic->y + y * pic->y_stride;
- uint8_t* const a_ptr = pic->a + y * pic->a_stride;
for (x = 0; x < pic->width; ++x) {
- const int alpha = a_ptr[x];
+ const uint8_t alpha = a_ptr[x];
if (alpha < 0xff) {
- y_ptr[x] = BLEND(Y0, y_ptr[x], a_ptr[x]);
+ y_ptr[x] = BLEND(Y0, y_ptr[x], alpha);
}
}
// Chroma blending every even line
if ((y & 1) == 0) {
- uint8_t* const u = pic->u + (y >> 1) * pic->uv_stride;
- uint8_t* const v = pic->v + (y >> 1) * pic->uv_stride;
uint8_t* const a_ptr2 =
(y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride;
for (x = 0; x < uv_width; ++x) {
// Average four alpha values into a single blending weight.
// TODO(skal): might lead to visible contouring. Can we do better?
- const int alpha =
+ const uint32_t alpha =
a_ptr[2 * x + 0] + a_ptr[2 * x + 1] +
a_ptr2[2 * x + 0] + a_ptr2[2 * x + 1];
- u[x] = BLEND_10BIT(U0, u[x], alpha);
- v[x] = BLEND_10BIT(V0, v[x], alpha);
+ u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
+ v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
if (pic->width & 1) { // rightmost pixel
- const int alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
- u[x] = BLEND_10BIT(U0, u[x], alpha);
- v[x] = BLEND_10BIT(V0, v[x], alpha);
+ const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
+ u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
+ v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
+ } else {
+ u_ptr += pic->uv_stride;
+ v_ptr += pic->uv_stride;
}
- memset(a_ptr, 0xff, pic->width);
+ memset(a_ptr, 0xff, pic->width); // reset alpha value to opaque
+ a_ptr += pic->a_stride;
+ y_ptr += pic->y_stride;
}
} else {
uint32_t* argb = pic->argb;
diff --git a/thirdparty/libwebp/src/enc/vp8i_enc.h b/thirdparty/libwebp/src/enc/vp8i_enc.h
index 624e8f8e66..92439febb8 100644
--- a/thirdparty/libwebp/src/enc/vp8i_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8i_enc.h
@@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 0
-#define ENC_REV_VERSION 0
+#define ENC_REV_VERSION 1
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
@@ -278,7 +278,7 @@ int VP8IteratorIsDone(const VP8EncIterator* const it);
// Import uncompressed samples from source.
// If tmp_32 is not NULL, import boundary samples too.
// tmp_32 is a 32-bytes scratch buffer that must be aligned in memory.
-void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32);
+void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32);
// export decimated samples
void VP8IteratorExport(const VP8EncIterator* const it);
// go to next macroblock. Returns false if not finished.
@@ -515,4 +515,4 @@ void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
} // extern "C"
#endif
-#endif /* WEBP_ENC_VP8I_ENC_H_ */
+#endif // WEBP_ENC_VP8I_ENC_H_
diff --git a/thirdparty/libwebp/src/enc/vp8l_enc.c b/thirdparty/libwebp/src/enc/vp8l_enc.c
index a89184eb08..2713edcd95 100644
--- a/thirdparty/libwebp/src/enc/vp8l_enc.c
+++ b/thirdparty/libwebp/src/enc/vp8l_enc.c
@@ -809,6 +809,7 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
+ VP8LHistogramSetClear(histogram_image);
// Build histogram image and symbols from backward references.
VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);
@@ -1248,14 +1249,20 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
const WebPPicture* const picture = enc->pic_;
const int width = picture->width;
const int height = picture->height;
- int y;
+
err = AllocateTransformBuffer(enc, width, height);
if (err != VP8_ENC_OK) return err;
if (enc->argb_content_ == kEncoderARGB) return VP8_ENC_OK;
- for (y = 0; y < height; ++y) {
- memcpy(enc->argb_ + y * width,
- picture->argb + y * picture->argb_stride,
- width * sizeof(*enc->argb_));
+
+ {
+ uint32_t* dst = enc->argb_;
+ const uint32_t* src = picture->argb;
+ int y;
+ for (y = 0; y < height; ++y) {
+ memcpy(dst, src, width * sizeof(*dst));
+ dst += width;
+ src += picture->argb_stride;
+ }
}
enc->argb_content_ = kEncoderARGB;
assert(enc->current_width_ == width);
diff --git a/thirdparty/libwebp/src/enc/vp8li_enc.h b/thirdparty/libwebp/src/enc/vp8li_enc.h
index 298a4a0014..d2d0fc509c 100644
--- a/thirdparty/libwebp/src/enc/vp8li_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8li_enc.h
@@ -115,4 +115,4 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
} // extern "C"
#endif
-#endif /* WEBP_ENC_VP8LI_ENC_H_ */
+#endif // WEBP_ENC_VP8LI_ENC_H_
diff --git a/thirdparty/libwebp/src/mux/animi.h b/thirdparty/libwebp/src/mux/animi.h
index 88899532aa..34c45ba4da 100644
--- a/thirdparty/libwebp/src/mux/animi.h
+++ b/thirdparty/libwebp/src/mux/animi.h
@@ -40,4 +40,4 @@ int WebPAnimEncoderRefineRect(
} // extern "C"
#endif
-#endif /* WEBP_MUX_ANIMI_H_ */
+#endif // WEBP_MUX_ANIMI_H_
diff --git a/thirdparty/libwebp/src/mux/muxedit.c b/thirdparty/libwebp/src/mux/muxedit.c
index 7a027b3cb4..ccf14b2a0c 100644
--- a/thirdparty/libwebp/src/mux/muxedit.c
+++ b/thirdparty/libwebp/src/mux/muxedit.c
@@ -69,12 +69,12 @@ void WebPMuxDelete(WebPMux* mux) {
if (idx == (INDEX)) { \
err = ChunkAssignData(&chunk, data, copy_data, tag); \
if (err == WEBP_MUX_OK) { \
- err = ChunkSetNth(&chunk, (LIST), nth); \
+ err = ChunkSetHead(&chunk, (LIST)); \
} \
return err; \
}
-static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, uint32_t nth,
+static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag,
const WebPData* const data, int copy_data) {
WebPChunk chunk;
WebPMuxError err = WEBP_MUX_NOT_FOUND;
@@ -190,7 +190,7 @@ WebPMuxError WebPMuxSetChunk(WebPMux* mux, const char fourcc[4],
if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
// Add the given chunk.
- return MuxSet(mux, tag, 1, chunk_data, copy_data);
+ return MuxSet(mux, tag, chunk_data, copy_data);
}
// Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'.
@@ -202,7 +202,7 @@ static WebPMuxError AddDataToChunkList(
ChunkInit(&chunk);
err = ChunkAssignData(&chunk, data, copy_data, tag);
if (err != WEBP_MUX_OK) goto Err;
- err = ChunkSetNth(&chunk, chunk_list, 1);
+ err = ChunkSetHead(&chunk, chunk_list);
if (err != WEBP_MUX_OK) goto Err;
return WEBP_MUX_OK;
Err:
@@ -266,14 +266,14 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info,
int copy_data) {
WebPMuxImage wpi;
WebPMuxError err;
- const WebPData* const bitstream = &info->bitstream;
// Sanity checks.
if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT;
if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT;
- if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) {
+ if (info->bitstream.bytes == NULL ||
+ info->bitstream.size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT;
}
@@ -287,7 +287,7 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info,
}
MuxImageInit(&wpi);
- err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi);
+ err = SetAlphaAndImageChunks(&info->bitstream, copy_data, &wpi);
if (err != WEBP_MUX_OK) goto Err;
assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful.
@@ -342,7 +342,7 @@ WebPMuxError WebPMuxSetAnimationParams(WebPMux* mux,
// Set the animation parameters.
PutLE32(data, params->bgcolor);
PutLE16(data + 4, params->loop_count);
- return MuxSet(mux, kChunks[IDX_ANIM].tag, 1, &anim, 1);
+ return MuxSet(mux, kChunks[IDX_ANIM].tag, &anim, 1);
}
WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux,
@@ -540,7 +540,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
PutLE24(data + 4, width - 1); // canvas width.
PutLE24(data + 7, height - 1); // canvas height.
- return MuxSet(mux, kChunks[IDX_VP8X].tag, 1, &vp8x, 1);
+ return MuxSet(mux, kChunks[IDX_VP8X].tag, &vp8x, 1);
}
// Cleans up 'mux' by removing any unnecessary chunks.
diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h
index 6b57eea30f..df9f74c63c 100644
--- a/thirdparty/libwebp/src/mux/muxi.h
+++ b/thirdparty/libwebp/src/mux/muxi.h
@@ -14,6 +14,7 @@
#ifndef WEBP_MUX_MUXI_H_
#define WEBP_MUX_MUXI_H_
+#include <assert.h>
#include <stdlib.h>
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
@@ -28,7 +29,7 @@ extern "C" {
#define MUX_MAJ_VERSION 1
#define MUX_MIN_VERSION 0
-#define MUX_REV_VERSION 0
+#define MUX_REV_VERSION 1
// Chunk object.
typedef struct WebPChunk WebPChunk;
@@ -126,11 +127,14 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag);
WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
int copy_data, uint32_t tag);
-// Sets 'chunk' at nth position in the 'chunk_list'.
-// nth = 0 has the special meaning "last of the list".
+// Sets 'chunk' as the only element in 'chunk_list' if it is empty.
// On success ownership is transferred from 'chunk' to the 'chunk_list'.
-WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
- uint32_t nth);
+WebPMuxError ChunkSetHead(WebPChunk* const chunk, WebPChunk** const chunk_list);
+// Sets 'chunk' at last position in the 'chunk_list'.
+// On success ownership is transferred from 'chunk' to the 'chunk_list'.
+// *chunk_list also points towards the last valid element of the initial
+// *chunk_list.
+WebPMuxError ChunkAppend(WebPChunk* const chunk, WebPChunk*** const chunk_list);
// Releases chunk and returns chunk->next_.
WebPChunk* ChunkRelease(WebPChunk* const chunk);
@@ -143,13 +147,13 @@ void ChunkListDelete(WebPChunk** const chunk_list);
// Returns size of the chunk including chunk header and padding byte (if any).
static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) {
+ assert(chunk_size <= MAX_CHUNK_PAYLOAD);
return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U);
}
// Size of a chunk including header and padding.
static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) {
const size_t data_size = chunk->data_.size;
- assert(data_size < MAX_CHUNK_PAYLOAD);
return SizeWithPadding(data_size);
}
@@ -227,4 +231,4 @@ WebPMuxError MuxValidate(const WebPMux* const mux);
} // extern "C"
#endif
-#endif /* WEBP_MUX_MUXI_H_ */
+#endif // WEBP_MUX_MUXI_H_
diff --git a/thirdparty/libwebp/src/mux/muxinternal.c b/thirdparty/libwebp/src/mux/muxinternal.c
index 1473f100e5..b9ee6717d3 100644
--- a/thirdparty/libwebp/src/mux/muxinternal.c
+++ b/thirdparty/libwebp/src/mux/muxinternal.c
@@ -111,27 +111,6 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) {
return ((nth > 0) && (iter > 0)) ? NULL : first;
}
-// Outputs a pointer to 'prev_chunk->next_',
-// where 'prev_chunk' is the pointer to the chunk at position (nth - 1).
-// Returns true if nth chunk was found.
-static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth,
- WebPChunk*** const location) {
- uint32_t count = 0;
- assert(chunk_list != NULL);
- *location = chunk_list;
-
- while (*chunk_list != NULL) {
- WebPChunk* const cur_chunk = *chunk_list;
- ++count;
- if (count == nth) return 1; // Found.
- chunk_list = &cur_chunk->next_;
- *location = chunk_list;
- }
-
- // *chunk_list is ok to be NULL if adding at last location.
- return (nth == 0 || (count == nth - 1)) ? 1 : 0;
-}
-
//------------------------------------------------------------------------------
// Chunk writer methods.
@@ -156,11 +135,12 @@ WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
return WEBP_MUX_OK;
}
-WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
- uint32_t nth) {
+WebPMuxError ChunkSetHead(WebPChunk* const chunk,
+ WebPChunk** const chunk_list) {
WebPChunk* new_chunk;
- if (!ChunkSearchListToSet(chunk_list, nth, &chunk_list)) {
+ assert(chunk_list != NULL);
+ if (*chunk_list != NULL) {
return WEBP_MUX_NOT_FOUND;
}
@@ -168,11 +148,26 @@ WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR;
*new_chunk = *chunk;
chunk->owner_ = 0;
- new_chunk->next_ = *chunk_list;
+ new_chunk->next_ = NULL;
*chunk_list = new_chunk;
return WEBP_MUX_OK;
}
+WebPMuxError ChunkAppend(WebPChunk* const chunk,
+ WebPChunk*** const chunk_list) {
+ assert(chunk_list != NULL && *chunk_list != NULL);
+
+ if (**chunk_list == NULL) {
+ ChunkSetHead(chunk, *chunk_list);
+ } else {
+ WebPChunk* last_chunk = **chunk_list;
+ while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_;
+ ChunkSetHead(chunk, &last_chunk->next_);
+ *chunk_list = &last_chunk->next_;
+ }
+ return WEBP_MUX_OK;
+}
+
//------------------------------------------------------------------------------
// Chunk deletion method(s).
@@ -232,9 +227,11 @@ void MuxImageInit(WebPMuxImage* const wpi) {
WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) {
WebPMuxImage* next;
if (wpi == NULL) return NULL;
- ChunkDelete(wpi->header_);
- ChunkDelete(wpi->alpha_);
- ChunkDelete(wpi->img_);
+ // There should be at most one chunk of header_, alpha_, img_ but we call
+ // ChunkListDelete to be safe
+ ChunkListDelete(&wpi->header_);
+ ChunkListDelete(&wpi->alpha_);
+ ChunkListDelete(&wpi->img_);
ChunkListDelete(&wpi->unknown_);
next = wpi->next_;
diff --git a/thirdparty/libwebp/src/mux/muxread.c b/thirdparty/libwebp/src/mux/muxread.c
index 0b55286862..268f6acb53 100644
--- a/thirdparty/libwebp/src/mux/muxread.c
+++ b/thirdparty/libwebp/src/mux/muxread.c
@@ -59,6 +59,7 @@ static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk,
// Sanity checks.
if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
chunk_size = GetLE32(data + TAG_SIZE);
+ if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA;
{
const size_t chunk_disk_size = SizeWithPadding(chunk_size);
@@ -102,6 +103,7 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
const uint8_t* const last = bytes + size;
WebPChunk subchunk;
size_t subchunk_size;
+ WebPChunk** unknown_chunk_list = &wpi->unknown_;
ChunkInit(&subchunk);
assert(chunk->tag_ == kChunks[IDX_ANMF].tag);
@@ -116,7 +118,7 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
if (size < hdr_size) goto Fail;
ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_);
}
- ChunkSetNth(&subchunk, &wpi->header_, 1);
+ ChunkSetHead(&subchunk, &wpi->header_);
wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks.
// Rest of the chunks.
@@ -133,18 +135,23 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
switch (ChunkGetIdFromTag(subchunk.tag_)) {
case WEBP_CHUNK_ALPHA:
if (wpi->alpha_ != NULL) goto Fail; // Consecutive ALPH chunks.
- if (ChunkSetNth(&subchunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Fail;
+ if (ChunkSetHead(&subchunk, &wpi->alpha_) != WEBP_MUX_OK) goto Fail;
wpi->is_partial_ = 1; // Waiting for a VP8 chunk.
break;
case WEBP_CHUNK_IMAGE:
- if (ChunkSetNth(&subchunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Fail;
+ if (wpi->img_ != NULL) goto Fail; // Only 1 image chunk allowed.
+ if (ChunkSetHead(&subchunk, &wpi->img_) != WEBP_MUX_OK) goto Fail;
if (!MuxImageFinalize(wpi)) goto Fail;
wpi->is_partial_ = 0; // wpi is completely filled.
break;
case WEBP_CHUNK_UNKNOWN:
- if (wpi->is_partial_) goto Fail; // Encountered an unknown chunk
- // before some image chunks.
- if (ChunkSetNth(&subchunk, &wpi->unknown_, 0) != WEBP_MUX_OK) goto Fail;
+ if (wpi->is_partial_) {
+ goto Fail; // Encountered an unknown chunk
+ // before some image chunks.
+ }
+ if (ChunkAppend(&subchunk, &unknown_chunk_list) != WEBP_MUX_OK) {
+ goto Fail;
+ }
break;
default:
goto Fail;
@@ -175,6 +182,9 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
const uint8_t* data;
size_t size;
WebPChunk chunk;
+ // Stores the end of the chunk lists so that it is faster to append data to
+ // their ends.
+ WebPChunk** chunk_list_ends[WEBP_CHUNK_NIL + 1] = { NULL };
ChunkInit(&chunk);
// Sanity checks.
@@ -187,7 +197,7 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
size = bitstream->size;
if (data == NULL) return NULL;
- if (size < RIFF_HEADER_SIZE) return NULL;
+ if (size < RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE) return NULL;
if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') ||
GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) {
return NULL;
@@ -196,8 +206,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
mux = WebPMuxNew();
if (mux == NULL) return NULL;
- if (size < RIFF_HEADER_SIZE + TAG_SIZE) goto Err;
-
tag = GetLE32(data + RIFF_HEADER_SIZE);
if (tag != kChunks[IDX_VP8].tag &&
tag != kChunks[IDX_VP8L].tag &&
@@ -205,13 +213,17 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
goto Err; // First chunk should be VP8, VP8L or VP8X.
}
- riff_size = SizeWithPadding(GetLE32(data + TAG_SIZE));
- if (riff_size > MAX_CHUNK_PAYLOAD || riff_size > size) {
- goto Err;
- } else {
- if (riff_size < size) { // Redundant data after last chunk.
- size = riff_size; // To make sure we don't read any data beyond mux_size.
- }
+ riff_size = GetLE32(data + TAG_SIZE);
+ if (riff_size > MAX_CHUNK_PAYLOAD) goto Err;
+
+ // Note this padding is historical and differs from demux.c which does not
+ // pad the file size.
+ riff_size = SizeWithPadding(riff_size);
+ if (riff_size < CHUNK_HEADER_SIZE) goto Err;
+ if (riff_size > size) goto Err;
+ // There's no point in reading past the end of the RIFF chunk.
+ if (size > riff_size + CHUNK_HEADER_SIZE) {
+ size = riff_size + CHUNK_HEADER_SIZE;
}
end = data + size;
@@ -226,7 +238,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
while (data != end) {
size_t data_size;
WebPChunkId id;
- WebPChunk** chunk_list;
if (ChunkVerifyAndAssign(&chunk, data, size, riff_size,
copy_data) != WEBP_MUX_OK) {
goto Err;
@@ -236,11 +247,11 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
switch (id) {
case WEBP_CHUNK_ALPHA:
if (wpi->alpha_ != NULL) goto Err; // Consecutive ALPH chunks.
- if (ChunkSetNth(&chunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Err;
+ if (ChunkSetHead(&chunk, &wpi->alpha_) != WEBP_MUX_OK) goto Err;
wpi->is_partial_ = 1; // Waiting for a VP8 chunk.
break;
case WEBP_CHUNK_IMAGE:
- if (ChunkSetNth(&chunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Err;
+ if (ChunkSetHead(&chunk, &wpi->img_) != WEBP_MUX_OK) goto Err;
if (!MuxImageFinalize(wpi)) goto Err;
wpi->is_partial_ = 0; // wpi is completely filled.
PushImage:
@@ -257,9 +268,13 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
default: // A non-image chunk.
if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
// getting all chunks of an image.
- chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk.
- if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
+ if (chunk_list_ends[id] == NULL) {
+ chunk_list_ends[id] =
+ MuxGetChunkListFromId(mux, id); // List to add this chunk.
+ }
+ if (ChunkAppend(&chunk, &chunk_list_ends[id]) != WEBP_MUX_OK) goto Err;
if (id == WEBP_CHUNK_VP8X) { // grab global specs
+ if (data_size < CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE) goto Err;
mux->canvas_width_ = GetLE24(data + 12) + 1;
mux->canvas_height_ = GetLE24(data + 15) + 1;
}
@@ -385,6 +400,10 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi,
uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
+ // There should be at most one alpha_ chunk and exactly one img_ chunk.
+ assert(wpi->alpha_ == NULL || wpi->alpha_->next_ == NULL);
+ assert(wpi->img_ != NULL && wpi->img_->next_ == NULL);
+
// Main RIFF header.
dst = MuxEmitRiffHeader(data, size);
diff --git a/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h b/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
index 2ccc6ed326..7e607f370a 100644
--- a/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
+++ b/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
@@ -187,4 +187,4 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
} // extern "C"
#endif
-#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_
+#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/bit_reader_utils.h b/thirdparty/libwebp/src/utils/bit_reader_utils.h
index 04f9804409..de810d402a 100644
--- a/thirdparty/libwebp/src/utils/bit_reader_utils.h
+++ b/thirdparty/libwebp/src/utils/bit_reader_utils.h
@@ -182,4 +182,4 @@ static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_BIT_READER_UTILS_H_ */
+#endif // WEBP_UTILS_BIT_READER_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/bit_writer_utils.h b/thirdparty/libwebp/src/utils/bit_writer_utils.h
index 2cf5976fe3..b9d5102a5a 100644
--- a/thirdparty/libwebp/src/utils/bit_writer_utils.h
+++ b/thirdparty/libwebp/src/utils/bit_writer_utils.h
@@ -151,4 +151,4 @@ static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_BIT_WRITER_UTILS_H_ */
+#endif // WEBP_UTILS_BIT_WRITER_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/filters_utils.h b/thirdparty/libwebp/src/utils/filters_utils.h
index 410f2fcdf2..61da66e212 100644
--- a/thirdparty/libwebp/src/utils/filters_utils.h
+++ b/thirdparty/libwebp/src/utils/filters_utils.h
@@ -29,4 +29,4 @@ WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_FILTERS_UTILS_H_ */
+#endif // WEBP_UTILS_FILTERS_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/quant_levels_dec_utils.c b/thirdparty/libwebp/src/utils/quant_levels_dec_utils.c
index 3818a78b93..f65b6cdbb6 100644
--- a/thirdparty/libwebp/src/utils/quant_levels_dec_utils.c
+++ b/thirdparty/libwebp/src/utils/quant_levels_dec_utils.c
@@ -261,9 +261,15 @@ static void CleanupParams(SmoothParams* const p) {
int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
int strength) {
- const int radius = 4 * strength / 100;
+ int radius = 4 * strength / 100;
+
if (strength < 0 || strength > 100) return 0;
if (data == NULL || width <= 0 || height <= 0) return 0; // bad params
+
+ // limit the filter size to not exceed the image dimensions
+ if (2 * radius + 1 > width) radius = (width - 1) >> 1;
+ if (2 * radius + 1 > height) radius = (height - 1) >> 1;
+
if (radius > 0) {
SmoothParams p;
memset(&p, 0, sizeof(p));
diff --git a/thirdparty/libwebp/src/utils/quant_levels_dec_utils.h b/thirdparty/libwebp/src/utils/quant_levels_dec_utils.h
index f822107a72..327f19f336 100644
--- a/thirdparty/libwebp/src/utils/quant_levels_dec_utils.h
+++ b/thirdparty/libwebp/src/utils/quant_levels_dec_utils.h
@@ -32,4 +32,4 @@ int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ */
+#endif // WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/quant_levels_utils.h b/thirdparty/libwebp/src/utils/quant_levels_utils.h
index 75df2ba6a4..9ee3ea0075 100644
--- a/thirdparty/libwebp/src/utils/quant_levels_utils.h
+++ b/thirdparty/libwebp/src/utils/quant_levels_utils.h
@@ -33,4 +33,4 @@ int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_QUANT_LEVELS_UTILS_H_ */
+#endif // WEBP_UTILS_QUANT_LEVELS_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/random_utils.h b/thirdparty/libwebp/src/utils/random_utils.h
index 6d36c667e7..a5006f84f7 100644
--- a/thirdparty/libwebp/src/utils/random_utils.h
+++ b/thirdparty/libwebp/src/utils/random_utils.h
@@ -60,4 +60,4 @@ static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_RANDOM_UTILS_H_ */
+#endif // WEBP_UTILS_RANDOM_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/rescaler_utils.h b/thirdparty/libwebp/src/utils/rescaler_utils.h
index 8890e6fa13..ca41e42c4a 100644
--- a/thirdparty/libwebp/src/utils/rescaler_utils.h
+++ b/thirdparty/libwebp/src/utils/rescaler_utils.h
@@ -98,4 +98,4 @@ int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_RESCALER_UTILS_H_ */
+#endif // WEBP_UTILS_RESCALER_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/thread_utils.h b/thirdparty/libwebp/src/utils/thread_utils.h
index c8ae6c9033..29ad49f74b 100644
--- a/thirdparty/libwebp/src/utils/thread_utils.h
+++ b/thirdparty/libwebp/src/utils/thread_utils.h
@@ -87,4 +87,4 @@ WEBP_EXTERN const WebPWorkerInterface* WebPGetWorkerInterface(void);
} // extern "C"
#endif
-#endif /* WEBP_UTILS_THREAD_UTILS_H_ */
+#endif // WEBP_UTILS_THREAD_UTILS_H_
diff --git a/thirdparty/libwebp/src/utils/utils.h b/thirdparty/libwebp/src/utils/utils.h
index 52921bf24e..da97b5d38f 100644
--- a/thirdparty/libwebp/src/utils/utils.h
+++ b/thirdparty/libwebp/src/utils/utils.h
@@ -175,4 +175,4 @@ WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_UTILS_H_ */
+#endif // WEBP_UTILS_UTILS_H_
diff --git a/thirdparty/libwebp/src/webp/decode.h b/thirdparty/libwebp/src/webp/decode.h
index 2165e96c95..95d31e7619 100644
--- a/thirdparty/libwebp/src/webp/decode.h
+++ b/thirdparty/libwebp/src/webp/decode.h
@@ -491,4 +491,4 @@ WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
} // extern "C"
#endif
-#endif /* WEBP_WEBP_DECODE_H_ */
+#endif // WEBP_WEBP_DECODE_H_
diff --git a/thirdparty/libwebp/src/webp/demux.h b/thirdparty/libwebp/src/webp/demux.h
index 555d641338..846eeb15a9 100644
--- a/thirdparty/libwebp/src/webp/demux.h
+++ b/thirdparty/libwebp/src/webp/demux.h
@@ -360,4 +360,4 @@ WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec);
} // extern "C"
#endif
-#endif /* WEBP_WEBP_DEMUX_H_ */
+#endif // WEBP_WEBP_DEMUX_H_
diff --git a/thirdparty/libwebp/src/webp/encode.h b/thirdparty/libwebp/src/webp/encode.h
index 7ec3543dc2..549cf07730 100644
--- a/thirdparty/libwebp/src/webp/encode.h
+++ b/thirdparty/libwebp/src/webp/encode.h
@@ -542,4 +542,4 @@ WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
} // extern "C"
#endif
-#endif /* WEBP_WEBP_ENCODE_H_ */
+#endif // WEBP_WEBP_ENCODE_H_
diff --git a/thirdparty/libwebp/src/webp/format_constants.h b/thirdparty/libwebp/src/webp/format_constants.h
index 329fc8a3b0..eca6981a47 100644
--- a/thirdparty/libwebp/src/webp/format_constants.h
+++ b/thirdparty/libwebp/src/webp/format_constants.h
@@ -84,4 +84,4 @@ typedef enum {
// overflow a uint32_t.
#define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1)
-#endif /* WEBP_WEBP_FORMAT_CONSTANTS_H_ */
+#endif // WEBP_WEBP_FORMAT_CONSTANTS_H_
diff --git a/thirdparty/libwebp/src/webp/mux.h b/thirdparty/libwebp/src/webp/mux.h
index 28bb4a41c9..66096a92e0 100644
--- a/thirdparty/libwebp/src/webp/mux.h
+++ b/thirdparty/libwebp/src/webp/mux.h
@@ -527,4 +527,4 @@ WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
} // extern "C"
#endif
-#endif /* WEBP_WEBP_MUX_H_ */
+#endif // WEBP_WEBP_MUX_H_
diff --git a/thirdparty/libwebp/src/webp/mux_types.h b/thirdparty/libwebp/src/webp/mux_types.h
index b37e2c67aa..ceea77dfc6 100644
--- a/thirdparty/libwebp/src/webp/mux_types.h
+++ b/thirdparty/libwebp/src/webp/mux_types.h
@@ -95,4 +95,4 @@ static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) {
} // extern "C"
#endif
-#endif /* WEBP_WEBP_MUX_TYPES_H_ */
+#endif // WEBP_WEBP_MUX_TYPES_H_
diff --git a/thirdparty/libwebp/src/webp/types.h b/thirdparty/libwebp/src/webp/types.h
index 989a763f0d..0ce2622e41 100644
--- a/thirdparty/libwebp/src/webp/types.h
+++ b/thirdparty/libwebp/src/webp/types.h
@@ -49,4 +49,4 @@ typedef long long int int64_t;
// Macro to check ABI compatibility (same major revision number)
#define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8))
-#endif /* WEBP_WEBP_TYPES_H_ */
+#endif // WEBP_WEBP_TYPES_H_
diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h
index 990c8ee142..b3a7ee00c2 100644
--- a/thirdparty/tinyexr/tinyexr.h
+++ b/thirdparty/tinyexr/tinyexr.h
@@ -116,6 +116,8 @@ extern "C" {
#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-7)
#define TINYEXR_ERROR_INVALID_HEADER (-8)
#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-9)
+#define TINYEXR_ERROR_CANT_WRITE_FILE (-10)
+#define TINYEXR_ERROR_SERIALZATION_FAILED (-11)
// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
@@ -279,9 +281,12 @@ extern int LoadEXR(float **out_rgba, int *width, int *height,
// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
// value.
// Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
+// Use ZIP compression by default.
+// Returns negative value and may set error string in `err` when there's an
+// error
extern int SaveEXR(const float *data, const int width, const int height,
const int components, const int save_as_fp16,
- const char *filename);
+ const char *filename, const char **err);
// Initialize EXRHeader struct
extern void InitEXRHeader(EXRHeader *exr_header);
@@ -400,9 +405,9 @@ extern int SaveEXRImageToFile(const EXRImage *image,
// Saves multi-channel, single-frame OpenEXR image to a memory.
// Image is compressed using EXRImage.compression value.
-// Return the number of bytes if succes.
-// Returns negative value and may set error string in `err` when there's an
-// error
+// Return the number of bytes if success.
+// Return zero and will set error string in `err` when there's an
+// error.
// When there was an error message, Application must free `err` with
// FreeEXRErrorMessage()
extern size_t SaveEXRImageToMemory(const EXRImage *image,
@@ -524,15 +529,23 @@ namespace miniz {
#if __has_warning("-Wcomma")
#pragma clang diagnostic ignored "-Wcomma"
#endif
+
#if __has_warning("-Wmacro-redefined")
#pragma clang diagnostic ignored "-Wmacro-redefined"
#endif
+
#if __has_warning("-Wcast-qual")
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
+
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
+
+#if __has_warning("-Wtautological-constant-compare")
+#pragma clang diagnostic ignored "-Wtautological-constant-compare"
+#endif
+
#endif
/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
@@ -2518,10 +2531,10 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r,
tinfl_status status = TINFL_STATUS_FAILED;
mz_uint32 num_bits, dist, counter, num_extra;
tinfl_bit_buf_t bit_buf;
- const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
- pIn_buf_next + *pIn_buf_size;
- mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
- pOut_buf_next + *pOut_buf_size;
+ const mz_uint8 *pIn_buf_cur = pIn_buf_next,
+ *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
+ mz_uint8 *pOut_buf_cur = pOut_buf_next,
+ *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
size_t out_buf_size_mask =
(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
? (size_t)-1
@@ -2938,9 +2951,8 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
tinfl_status status = tinfl_decompress(
&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
(mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
- &dst_buf_size,
- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+ &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
+ TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
MZ_FREE(pBuf);
*pOut_len = 0;
@@ -2993,8 +3005,9 @@ int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
tinfl_status status =
tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
&in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
- (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
+ (flags &
+ ~(TINFL_FLAG_HAS_MORE_INPUT |
+ TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
in_buf_ofs += in_buf_size;
if ((dst_buf_size) &&
(!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
@@ -3119,9 +3132,7 @@ static const mz_uint8 s_tdefl_large_dist_extra[128] = {
// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
// values.
-typedef struct {
- mz_uint16 m_key, m_sym_index;
-} tdefl_sym_freq;
+typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq;
static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
tdefl_sym_freq *pSyms0,
tdefl_sym_freq *pSyms1) {
@@ -5265,10 +5276,9 @@ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
pStat->m_comment_size = n;
- memcpy(pStat->m_comment,
- p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
- MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
+ memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
+ MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
+ MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
n);
pStat->m_comment[n] = '\0';
@@ -10087,9 +10097,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
unsigned short *outLine =
reinterpret_cast<unsigned short *>(out_images[c]);
if (line_order == 0) {
- outLine += (y + v) * x_stride;
+ outLine += (size_t(y) + v) * size_t(x_stride);
} else {
- outLine += (height - 1 - (y + v)) * x_stride;
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
}
for (int u = 0; u < width; u++) {
@@ -10105,9 +10116,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
} else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
float *outLine = reinterpret_cast<float *>(out_images[c]);
if (line_order == 0) {
- outLine += (y + v) * x_stride;
+ outLine += (size_t(y) + v) * size_t(x_stride);
} else {
- outLine += (height - 1 - (y + v)) * x_stride;
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
}
if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
@@ -10140,9 +10152,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
float *outLine = reinterpret_cast<float *>(out_images[c]);
if (line_order == 0) {
- outLine += (y + v) * x_stride;
+ outLine += (size_t(y) + v) * size_t(x_stride);
} else {
- outLine += (height - 1 - (y + v)) * x_stride;
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
}
if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
@@ -10167,9 +10180,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
unsigned int *outLine =
reinterpret_cast<unsigned int *>(out_images[c]);
if (line_order == 0) {
- outLine += (y + v) * x_stride;
+ outLine += (size_t(y) + v) * size_t(x_stride);
} else {
- outLine += (height - 1 - (y + v)) * x_stride;
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
}
for (int u = 0; u < width; u++) {
@@ -11133,21 +11147,53 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
}
}
- if ((idxA == 0) && (idxR == -1) && (idxG == -1) && (idxB == -1)) {
- // Alpha channel only.
+ if (exr_header.num_channels == 1) {
+ // Grayscale channel only.
- if (exr_header.tiled) {
- // todo.implement this
- }
(*out_rgba) = reinterpret_cast<float *>(
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
- for (int i = 0; i < exr_image.width * exr_image.height; i++) {
- const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
- (*out_rgba)[4 * i + 0] = val;
- (*out_rgba)[4 * i + 1] = val;
- (*out_rgba)[4 * i + 2] = val;
- (*out_rgba)[4 * i + 3] = val;
+
+ if (exr_header.tiled) {
+ // todo.implement this
+
+ for (int it = 0; it < exr_image.num_tiles; it++) {
+ for (int j = 0; j < exr_header.tile_size_y; j++) {
+ for (int i = 0; i < exr_header.tile_size_x; i++) {
+ const int ii =
+ exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
+ const int jj =
+ exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
+ const int idx = ii + jj * exr_image.width;
+
+ // out of region check.
+ if (ii >= exr_image.width) {
+ continue;
+ }
+ if (jj >= exr_image.height) {
+ continue;
+ }
+ const int srcIdx = i + j * exr_header.tile_size_x;
+ unsigned char **src = exr_image.tiles[it].images;
+ (*out_rgba)[4 * idx + 0] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 1] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 2] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 3] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) {
+ const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
+ (*out_rgba)[4 * i + 0] = val;
+ (*out_rgba)[4 * i + 1] = val;
+ (*out_rgba)[4 * i + 2] = val;
+ (*out_rgba)[4 * i + 3] = val;
+ }
}
} else {
// Assume RGB(A)
@@ -11179,7 +11225,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
static_cast<size_t>(exr_image.height)));
if (exr_header.tiled) {
for (int it = 0; it < exr_image.num_tiles; it++) {
- for (int j = 0; j < exr_header.tile_size_y; j++)
+ for (int j = 0; j < exr_header.tile_size_y; j++) {
for (int i = 0; i < exr_header.tile_size_x; i++) {
const int ii =
exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
@@ -11209,6 +11255,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
(*out_rgba)[4 * idx + 3] = 1.0;
}
}
+ }
}
} else {
for (int i = 0; i < exr_image.width * exr_image.height; i++) {
@@ -11356,18 +11403,53 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
- for (int i = 0; i < exr_image.width * exr_image.height; i++) {
- (*out_rgba)[4 * i + 0] =
- reinterpret_cast<float **>(exr_image.images)[idxR][i];
- (*out_rgba)[4 * i + 1] =
- reinterpret_cast<float **>(exr_image.images)[idxG][i];
- (*out_rgba)[4 * i + 2] =
- reinterpret_cast<float **>(exr_image.images)[idxB][i];
- if (idxA != -1) {
- (*out_rgba)[4 * i + 3] =
- reinterpret_cast<float **>(exr_image.images)[idxA][i];
- } else {
- (*out_rgba)[4 * i + 3] = 1.0;
+ if (exr_header.tiled) {
+ for (int it = 0; it < exr_image.num_tiles; it++) {
+ for (int j = 0; j < exr_header.tile_size_y; j++)
+ for (int i = 0; i < exr_header.tile_size_x; i++) {
+ const int ii =
+ exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
+ const int jj =
+ exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
+ const int idx = ii + jj * exr_image.width;
+
+ // out of region check.
+ if (ii >= exr_image.width) {
+ continue;
+ }
+ if (jj >= exr_image.height) {
+ continue;
+ }
+ const int srcIdx = i + j * exr_header.tile_size_x;
+ unsigned char **src = exr_image.tiles[it].images;
+ (*out_rgba)[4 * idx + 0] =
+ reinterpret_cast<float **>(src)[idxR][srcIdx];
+ (*out_rgba)[4 * idx + 1] =
+ reinterpret_cast<float **>(src)[idxG][srcIdx];
+ (*out_rgba)[4 * idx + 2] =
+ reinterpret_cast<float **>(src)[idxB][srcIdx];
+ if (idxA != -1) {
+ (*out_rgba)[4 * idx + 3] =
+ reinterpret_cast<float **>(src)[idxA][srcIdx];
+ } else {
+ (*out_rgba)[4 * idx + 3] = 1.0;
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) {
+ (*out_rgba)[4 * i + 0] =
+ reinterpret_cast<float **>(exr_image.images)[idxR][i];
+ (*out_rgba)[4 * i + 1] =
+ reinterpret_cast<float **>(exr_image.images)[idxG][i];
+ (*out_rgba)[4 * i + 2] =
+ reinterpret_cast<float **>(exr_image.images)[idxB][i];
+ if (idxA != -1) {
+ (*out_rgba)[4 * i + 3] =
+ reinterpret_cast<float **>(exr_image.images)[idxA][i];
+ } else {
+ (*out_rgba)[4 * i + 3] = 1.0;
+ }
}
}
@@ -11452,7 +11534,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
if (exr_image == NULL || memory_out == NULL ||
exr_header->compression_type < 0) {
tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err);
- return 0; // @fixme
+ return 0;
}
#if !TINYEXR_USE_PIZ
@@ -11623,8 +11705,6 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
sizeof(
tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable)
- std::vector<unsigned char> data;
-
std::vector<std::vector<unsigned char> > data_list(
static_cast<size_t>(num_blocks));
std::vector<size_t> channel_offset_list(
@@ -11863,9 +11943,9 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
} else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
#if TINYEXR_USE_PIZ
unsigned int bufLen =
- 1024 + static_cast<unsigned int>(
- 1.2 * static_cast<unsigned int>(
- buf.size())); // @fixme { compute good bound. }
+ 8192 + static_cast<unsigned int>(
+ 2 * static_cast<unsigned int>(
+ buf.size())); // @fixme { compute good bound. }
std::vector<unsigned char> block(bufLen);
unsigned int outSize = static_cast<unsigned int>(block.size());
@@ -11924,13 +12004,12 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
} // omp parallel
for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
- data.insert(data.end(), data_list[i].begin(), data_list[i].end());
-
offsets[i] = offset;
tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i]));
offset += data_list[i].size();
}
+ size_t totalSize = static_cast<size_t>(offset);
{
memory.insert(
memory.end(), reinterpret_cast<unsigned char *>(&offsets.at(0)),
@@ -11938,14 +12017,21 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks));
}
- { memory.insert(memory.end(), data.begin(), data.end()); }
-
- assert(memory.size() > 0);
+ if ( memory.size() == 0 ) {
+ tinyexr::SetErrorMessage("Output memory size is zero", err);
+ return 0;
+ }
- (*memory_out) = static_cast<unsigned char *>(malloc(memory.size()));
+ (*memory_out) = static_cast<unsigned char *>(malloc(totalSize));
memcpy((*memory_out), &memory.at(0), memory.size());
+ unsigned char *memory_ptr = *memory_out + memory.size();
- return memory.size(); // OK
+ for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
+ memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size());
+ memory_ptr += data_list[i].size();
+ }
+
+ return totalSize; // OK
}
int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
@@ -11960,7 +12046,7 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
err);
- return 0;
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
}
#endif
@@ -11968,7 +12054,7 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
err);
- return 0;
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
}
#endif
@@ -11980,19 +12066,28 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
#endif
if (!fp) {
tinyexr::SetErrorMessage("Cannot write a file", err);
- return TINYEXR_ERROR_CANT_OPEN_FILE;
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
}
unsigned char *mem = NULL;
size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err);
+ if (mem_size == 0) {
+ return TINYEXR_ERROR_SERIALZATION_FAILED;
+ }
+ size_t written_size = 0;
if ((mem_size > 0) && mem) {
- fwrite(mem, 1, mem_size, fp);
+ written_size = fwrite(mem, 1, mem_size, fp);
}
free(mem);
fclose(fp);
+ if (written_size != mem_size) {
+ tinyexr::SetErrorMessage("Cannot write a file", err);
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
+ }
+
return TINYEXR_SUCCESS;
}
@@ -12861,20 +12956,27 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
}
int SaveEXR(const float *data, int width, int height, int components,
- const int save_as_fp16, const char *outfilename) {
+ const int save_as_fp16, const char *outfilename, const char **err) {
if ((components == 1) || components == 3 || components == 4) {
// OK
} else {
+ std::stringstream ss;
+ ss << "Unsupported component value : " << components << std::endl;
+
+ tinyexr::SetErrorMessage(ss.str(), err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
- // Assume at least 16x16 pixels.
- if (width < 16) return TINYEXR_ERROR_INVALID_ARGUMENT;
- if (height < 16) return TINYEXR_ERROR_INVALID_ARGUMENT;
-
EXRHeader header;
InitEXRHeader(&header);
+ if ((width < 16) && (height < 16)) {
+ // No compression for small image.
+ header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE;
+ } else {
+ header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP;
+ }
+
EXRImage image;
InitEXRImage(&image);
@@ -12980,8 +13082,7 @@ int SaveEXR(const float *data, int width, int height, int components,
}
}
- const char *err;
- int ret = SaveEXRImageToFile(&image, &header, outfilename, &err);
+ int ret = SaveEXRImageToFile(&image, &header, outfilename, err);
if (ret != TINYEXR_SUCCESS) {
return ret;
}