diff options
Diffstat (limited to 'thirdparty')
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; } |