summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/utils
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2016-03-09 10:22:13 +0100
committerLiang Qi <liang.qi@theqtcompany.com>2016-03-11 20:05:19 +0000
commitb114e552211456fbde3ff6ca2da21cbc8d1e90e2 (patch)
tree9c033ea7bcc9cc7314eaa8aff57356b2ae301257 /src/3rdparty/libwebp/src/utils
parent1d4f24820c0fff474d524e006d715e13e409a4b8 (diff)
libwebp: update to 0.5.0
This commit imports libwebp 0.5.0, including AUTHORS, COPYING, ChangeLog, NEWS, PATENTS, README and src directories. In src, only includes header and source files. The patches required to build it in Qt will follow in separate commit(s). Change-Id: I96b4961ba63c75cc7fbab158c36a0f403f254c14 Reviewed-by: aavit <eirik.aavitsland@theqtcompany.com>
Diffstat (limited to 'src/3rdparty/libwebp/src/utils')
-rw-r--r--src/3rdparty/libwebp/src/utils/bit_reader.c42
-rw-r--r--src/3rdparty/libwebp/src/utils/bit_reader.h19
-rw-r--r--src/3rdparty/libwebp/src/utils/bit_reader_inl.h4
-rw-r--r--src/3rdparty/libwebp/src/utils/bit_writer.c64
-rw-r--r--src/3rdparty/libwebp/src/utils/bit_writer.h37
-rw-r--r--src/3rdparty/libwebp/src/utils/color_cache.c10
-rw-r--r--src/3rdparty/libwebp/src/utils/color_cache.h16
-rw-r--r--src/3rdparty/libwebp/src/utils/filters.c204
-rw-r--r--src/3rdparty/libwebp/src/utils/filters.h33
-rw-r--r--src/3rdparty/libwebp/src/utils/huffman.c392
-rw-r--r--src/3rdparty/libwebp/src/utils/huffman.h110
-rw-r--r--src/3rdparty/libwebp/src/utils/huffman_encode.h5
-rw-r--r--src/3rdparty/libwebp/src/utils/rescaler.c492
-rw-r--r--src/3rdparty/libwebp/src/utils/rescaler.h22
-rw-r--r--src/3rdparty/libwebp/src/utils/thread.c49
-rw-r--r--src/3rdparty/libwebp/src/utils/thread.h2
-rw-r--r--src/3rdparty/libwebp/src/utils/utils.c30
-rw-r--r--src/3rdparty/libwebp/src/utils/utils.h47
18 files changed, 503 insertions, 1075 deletions
diff --git a/src/3rdparty/libwebp/src/utils/bit_reader.c b/src/3rdparty/libwebp/src/utils/bit_reader.c
index 64503e6..45198e1 100644
--- a/src/3rdparty/libwebp/src/utils/bit_reader.c
+++ b/src/3rdparty/libwebp/src/utils/bit_reader.c
@@ -20,17 +20,26 @@
//------------------------------------------------------------------------------
// VP8BitReader
+void VP8BitReaderSetBuffer(VP8BitReader* const br,
+ const uint8_t* const start,
+ size_t size) {
+ br->buf_ = start;
+ br->buf_end_ = start + size;
+ br->buf_max_ =
+ (size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1
+ : start;
+}
+
void VP8InitBitReader(VP8BitReader* const br,
- const uint8_t* const start, const uint8_t* const end) {
+ const uint8_t* const start, size_t size) {
assert(br != NULL);
assert(start != NULL);
- assert(start <= end);
+ assert(size < (1u << 31)); // limit ensured by format and upstream checks
br->range_ = 255 - 1;
- br->buf_ = start;
- br->buf_end_ = end;
br->value_ = 0;
br->bits_ = -8; // to load the very first 8bits
br->eof_ = 0;
+ VP8BitReaderSetBuffer(br, start, size);
VP8LoadNewBytes(br);
}
@@ -38,6 +47,7 @@ void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
if (br->buf_ != NULL) {
br->buf_ += offset;
br->buf_end_ += offset;
+ br->buf_max_ += offset;
}
}
@@ -54,7 +64,7 @@ const uint8_t kVP8Log2Range[128] = {
};
// range = ((range - 1) << kVP8Log2Range[range]) + 1
-const range_t kVP8NewRange[128] = {
+const uint8_t kVP8NewRange[128] = {
127, 127, 191, 127, 159, 191, 223, 127,
143, 159, 175, 191, 207, 223, 239, 127,
135, 143, 151, 159, 167, 175, 183, 191,
@@ -83,6 +93,8 @@ void VP8LoadFinalBytes(VP8BitReader* const br) {
br->value_ <<= 8;
br->bits_ += 8;
br->eof_ = 1;
+ } else {
+ br->bits_ = 0; // This is to avoid undefined behaviour with shifts.
}
}
@@ -136,7 +148,6 @@ void VP8LInitBitReader(VP8LBitReader* const br, const uint8_t* const start,
br->val_ = 0;
br->bit_pos_ = 0;
br->eos_ = 0;
- br->error_ = 0;
if (length > sizeof(br->val_)) {
length = sizeof(br->val_);
@@ -157,8 +168,12 @@ void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
br->buf_ = buf;
br->len_ = len;
// pos_ > len_ should be considered a param error.
- br->error_ = (br->pos_ > br->len_);
- br->eos_ = br->error_ || VP8LIsEndOfStream(br);
+ br->eos_ = (br->pos_ > br->len_) || VP8LIsEndOfStream(br);
+}
+
+static void VP8LSetEndOfStream(VP8LBitReader* const br) {
+ br->eos_ = 1;
+ br->bit_pos_ = 0; // To avoid undefined behaviour with shifts.
}
// If not at EOS, reload up to VP8L_LBITS byte-by-byte
@@ -169,7 +184,9 @@ static void ShiftBytes(VP8LBitReader* const br) {
++br->pos_;
br->bit_pos_ -= 8;
}
- br->eos_ = VP8LIsEndOfStream(br);
+ if (VP8LIsEndOfStream(br)) {
+ VP8LSetEndOfStream(br);
+ }
}
void VP8LDoFillBitWindow(VP8LBitReader* const br) {
@@ -182,7 +199,7 @@ void VP8LDoFillBitWindow(VP8LBitReader* const br) {
br->bit_pos_ -= VP8L_WBITS;
// The expression below needs a little-endian arch to work correctly.
// This gives a large speedup for decoding speed.
- br->val_ |= (vp8l_val_t)*(const uint32_t*)(br->buf_ + br->pos_) <<
+ br->val_ |= (vp8l_val_t)WebPMemToUint32(br->buf_ + br->pos_) <<
(VP8L_LBITS - VP8L_WBITS);
br->pos_ += VP8L_LOG8_WBITS;
return;
@@ -195,14 +212,13 @@ uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) {
assert(n_bits >= 0);
// Flag an error if end_of_stream or n_bits is more than allowed limit.
if (!br->eos_ && n_bits <= VP8L_MAX_NUM_BIT_READ) {
- const uint32_t val =
- (uint32_t)(br->val_ >> br->bit_pos_) & kBitMask[n_bits];
+ const uint32_t val = VP8LPrefetchBits(br) & kBitMask[n_bits];
const int new_bits = br->bit_pos_ + n_bits;
br->bit_pos_ = new_bits;
ShiftBytes(br);
return val;
} else {
- br->error_ = 1;
+ VP8LSetEndOfStream(br);
return 0;
}
}
diff --git a/src/3rdparty/libwebp/src/utils/bit_reader.h b/src/3rdparty/libwebp/src/utils/bit_reader.h
index f569734..ec3426c 100644
--- a/src/3rdparty/libwebp/src/utils/bit_reader.h
+++ b/src/3rdparty/libwebp/src/utils/bit_reader.h
@@ -43,10 +43,12 @@ extern "C" {
#define BITS 56
#elif defined(__arm__) || defined(_M_ARM) // ARM
#define BITS 24
+#elif defined(__aarch64__) // ARM 64bit
+#define BITS 56
#elif defined(__mips__) // MIPS
#define BITS 24
#else // reasonable default
-#define BITS 24 // TODO(skal): test aarch64 and find the proper BITS value.
+#define BITS 24
#endif
//------------------------------------------------------------------------------
@@ -74,12 +76,16 @@ struct VP8BitReader {
// read buffer
const uint8_t* buf_; // next byte to be read
const uint8_t* buf_end_; // end of read buffer
+ const uint8_t* buf_max_; // max packed-read position on buffer
int eof_; // true if input is exhausted
};
// Initialize the bit reader and the boolean decoder.
void VP8InitBitReader(VP8BitReader* const br,
- const uint8_t* const start, const uint8_t* const end);
+ const uint8_t* const start, size_t size);
+// Sets the working read buffer.
+void VP8BitReaderSetBuffer(VP8BitReader* const br,
+ const uint8_t* const start, size_t size);
// Update internal pointers to displace the byte buffer by the
// relative offset 'offset'.
@@ -107,7 +113,7 @@ int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits);
// maximum number of bits (inclusive) the bit-reader can handle:
#define VP8L_MAX_NUM_BIT_READ 24
-#define VP8L_LBITS 64 // Number of bits prefetched.
+#define VP8L_LBITS 64 // Number of bits prefetched (= bit-size of vp8l_val_t).
#define VP8L_WBITS 32 // Minimum number of bytes ready after VP8LFillBitWindow.
typedef uint64_t vp8l_val_t; // right now, this bit-reader can only use 64bit.
@@ -118,8 +124,7 @@ typedef struct {
size_t len_; // buffer length
size_t pos_; // byte position in buf_
int bit_pos_; // current bit-reading position in val_
- int eos_; // bitstream is finished
- int error_; // an error occurred (buffer overflow attempt...)
+ int eos_; // true if a bit was read past the end of buffer
} VP8LBitReader;
void VP8LInitBitReader(VP8LBitReader* const br,
@@ -138,14 +143,14 @@ uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits);
// Return the prefetched bits, so they can be looked up.
static WEBP_INLINE uint32_t VP8LPrefetchBits(VP8LBitReader* const br) {
- return (uint32_t)(br->val_ >> br->bit_pos_);
+ return (uint32_t)(br->val_ >> (br->bit_pos_ & (VP8L_LBITS - 1)));
}
// Returns true if there was an attempt at reading bit past the end of
// the buffer. Doesn't set br->eos_ flag.
static WEBP_INLINE int VP8LIsEndOfStream(const VP8LBitReader* const br) {
assert(br->pos_ <= br->len_);
- return (br->pos_ == br->len_) && (br->bit_pos_ > VP8L_LBITS);
+ return br->eos_ || ((br->pos_ == br->len_) && (br->bit_pos_ > VP8L_LBITS));
}
// For jumping over a number of bits in the bit stream when accessed with
diff --git a/src/3rdparty/libwebp/src/utils/bit_reader_inl.h b/src/3rdparty/libwebp/src/utils/bit_reader_inl.h
index 81427c6..3721570 100644
--- a/src/3rdparty/libwebp/src/utils/bit_reader_inl.h
+++ b/src/3rdparty/libwebp/src/utils/bit_reader_inl.h
@@ -46,7 +46,7 @@ typedef uint8_t lbit_t;
#endif
extern const uint8_t kVP8Log2Range[128];
-extern const range_t kVP8NewRange[128];
+extern const uint8_t kVP8NewRange[128];
// special case for the tail byte-reading
void VP8LoadFinalBytes(VP8BitReader* const br);
@@ -58,7 +58,7 @@ void VP8LoadFinalBytes(VP8BitReader* const br);
static WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* const br) {
assert(br != NULL && br->buf_ != NULL);
// Read 'BITS' bits at a time if possible.
- if (br->buf_ + sizeof(lbit_t) <= br->buf_end_) {
+ if (br->buf_ < br->buf_max_) {
// convert memory type to register type (with some zero'ing!)
bit_t bits;
#if defined(WEBP_FORCE_ALIGNED)
diff --git a/src/3rdparty/libwebp/src/utils/bit_writer.c b/src/3rdparty/libwebp/src/utils/bit_writer.c
index 9875ca6..0644286 100644
--- a/src/3rdparty/libwebp/src/utils/bit_writer.c
+++ b/src/3rdparty/libwebp/src/utils/bit_writer.c
@@ -140,19 +140,20 @@ int VP8PutBitUniform(VP8BitWriter* const bw, int bit) {
return bit;
}
-void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits) {
- int mask;
- for (mask = 1 << (nb_bits - 1); mask; mask >>= 1)
+void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits) {
+ uint32_t mask;
+ assert(nb_bits > 0 && nb_bits < 32);
+ for (mask = 1u << (nb_bits - 1); mask; mask >>= 1)
VP8PutBitUniform(bw, value & mask);
}
-void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits) {
+void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits) {
if (!VP8PutBitUniform(bw, value != 0))
return;
if (value < 0) {
- VP8PutValue(bw, ((-value) << 1) | 1, nb_bits + 1);
+ VP8PutBits(bw, ((-value) << 1) | 1, nb_bits + 1);
} else {
- VP8PutValue(bw, value << 1, nb_bits + 1);
+ VP8PutBits(bw, value << 1, nb_bits + 1);
}
}
@@ -171,7 +172,7 @@ int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size) {
}
uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) {
- VP8PutValue(bw, 0, 9 - bw->nb_bits_);
+ VP8PutBits(bw, 0, 9 - bw->nb_bits_);
bw->nb_bits_ = 0; // pad with zeroes
Flush(bw);
return bw->buf_;
@@ -201,10 +202,6 @@ void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
// when extra space is needed.
#define MIN_EXTRA_SIZE (32768ULL)
-#define VP8L_WRITER_BYTES ((int)sizeof(vp8l_wtype_t))
-#define VP8L_WRITER_BITS (VP8L_WRITER_BYTES * 8)
-#define VP8L_WRITER_MAX_BITS (8 * (int)sizeof(vp8l_atype_t))
-
// Returns 1 on success.
static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
uint8_t* allocated_buf;
@@ -242,33 +239,49 @@ int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) {
return VP8LBitWriterResize(bw, expected_size);
}
-void VP8LBitWriterDestroy(VP8LBitWriter* const bw) {
+void VP8LBitWriterWipeOut(VP8LBitWriter* const bw) {
if (bw != NULL) {
WebPSafeFree(bw->buf_);
memset(bw, 0, sizeof(*bw));
}
}
-void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits) {
+void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) {
+ // If needed, make some room by flushing some bits out.
+ if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
+ const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
+ if (extra_size != (size_t)extra_size ||
+ !VP8LBitWriterResize(bw, (size_t)extra_size)) {
+ bw->cur_ = bw->buf_;
+ bw->error_ = 1;
+ return;
+ }
+ }
+ *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)bw->bits_);
+ bw->cur_ += VP8L_WRITER_BYTES;
+ bw->bits_ >>= VP8L_WRITER_BITS;
+ bw->used_ -= VP8L_WRITER_BITS;
+}
+
+void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) {
assert(n_bits <= 32);
// That's the max we can handle:
- assert(bw->used_ + n_bits <= 2 * VP8L_WRITER_MAX_BITS);
+ assert(sizeof(vp8l_wtype_t) == 2);
if (n_bits > 0) {
- // Local field copy.
vp8l_atype_t lbits = bw->bits_;
int used = bw->used_;
// Special case of overflow handling for 32bit accumulator (2-steps flush).
- if (VP8L_WRITER_BITS == 16) {
- if (used + n_bits >= VP8L_WRITER_MAX_BITS) {
- // Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below.
- const int shift = VP8L_WRITER_MAX_BITS - used;
- lbits |= (vp8l_atype_t)bits << used;
- used = VP8L_WRITER_MAX_BITS;
- n_bits -= shift;
- bits >>= shift;
- assert(n_bits <= VP8L_WRITER_MAX_BITS);
- }
+#if VP8L_WRITER_BITS == 16
+ if (used + n_bits >= VP8L_WRITER_MAX_BITS) {
+ // Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below.
+ const int shift = VP8L_WRITER_MAX_BITS - used;
+ lbits |= (vp8l_atype_t)bits << used;
+ used = VP8L_WRITER_MAX_BITS;
+ n_bits -= shift;
+ bits >>= shift;
+ assert(n_bits <= VP8L_WRITER_MAX_BITS);
}
+#endif
// If needed, make some room by flushing some bits out.
while (used >= VP8L_WRITER_BITS) {
if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
@@ -285,7 +298,6 @@ void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits) {
lbits >>= VP8L_WRITER_BITS;
used -= VP8L_WRITER_BITS;
}
- // Eventually, insert new bits.
bw->bits_ = lbits | ((vp8l_atype_t)bits << used);
bw->used_ = used + n_bits;
}
diff --git a/src/3rdparty/libwebp/src/utils/bit_writer.h b/src/3rdparty/libwebp/src/utils/bit_writer.h
index c80d22a..ef360d1 100644
--- a/src/3rdparty/libwebp/src/utils/bit_writer.h
+++ b/src/3rdparty/libwebp/src/utils/bit_writer.h
@@ -45,8 +45,8 @@ void VP8BitWriterWipeOut(VP8BitWriter* const bw);
int VP8PutBit(VP8BitWriter* const bw, int bit, int prob);
int VP8PutBitUniform(VP8BitWriter* const bw, int bit);
-void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits);
-void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits);
+void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits);
+void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits);
// Appends some bytes to the internal buffer. Data is copied.
int VP8BitWriterAppend(VP8BitWriter* const bw,
@@ -73,10 +73,16 @@ static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) {
typedef uint64_t vp8l_atype_t; // accumulator type
typedef uint32_t vp8l_wtype_t; // writing type
#define WSWAP HToLE32
+#define VP8L_WRITER_BYTES 4 // sizeof(vp8l_wtype_t)
+#define VP8L_WRITER_BITS 32 // 8 * sizeof(vp8l_wtype_t)
+#define VP8L_WRITER_MAX_BITS 64 // 8 * sizeof(vp8l_atype_t)
#else
typedef uint32_t vp8l_atype_t;
typedef uint16_t vp8l_wtype_t;
#define WSWAP HToLE16
+#define VP8L_WRITER_BYTES 2
+#define VP8L_WRITER_BITS 16
+#define VP8L_WRITER_MAX_BITS 32
#endif
typedef struct {
@@ -97,19 +103,38 @@ static WEBP_INLINE size_t VP8LBitWriterNumBytes(VP8LBitWriter* const bw) {
return (bw->cur_ - bw->buf_) + ((bw->used_ + 7) >> 3);
}
+// Returns false in case of memory allocation error.
+int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size);
+// Finalize the bitstream coding. Returns a pointer to the internal buffer.
uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw);
+// Release any pending memory and zeroes the object.
+void VP8LBitWriterWipeOut(VP8LBitWriter* const bw);
-// Returns 0 in case of memory allocation error.
-int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size);
+// Internal function for VP8LPutBits flushing 32 bits from the written state.
+void VP8LPutBitsFlushBits(VP8LBitWriter* const bw);
-void VP8LBitWriterDestroy(VP8LBitWriter* const bw);
+// PutBits internal function used in the 16 bit vp8l_wtype_t case.
+void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits);
// This function writes bits into bytes in increasing addresses (little endian),
// and within a byte least-significant-bit first.
// This function can write up to 32 bits in one go, but VP8LBitReader can only
// read 24 bits max (VP8L_MAX_NUM_BIT_READ).
// VP8LBitWriter's error_ flag is set in case of memory allocation error.
-void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits);
+static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw,
+ uint32_t bits, int n_bits) {
+ if (sizeof(vp8l_wtype_t) == 4) {
+ if (n_bits > 0) {
+ if (bw->used_ >= 32) {
+ VP8LPutBitsFlushBits(bw);
+ }
+ bw->bits_ |= (vp8l_atype_t)bits << bw->used_;
+ bw->used_ += n_bits;
+ }
+ } else {
+ VP8LPutBitsInternal(bw, bits, n_bits);
+ }
+}
//------------------------------------------------------------------------------
diff --git a/src/3rdparty/libwebp/src/utils/color_cache.c b/src/3rdparty/libwebp/src/utils/color_cache.c
index 8a88f08..f9ff4b5 100644
--- a/src/3rdparty/libwebp/src/utils/color_cache.c
+++ b/src/3rdparty/libwebp/src/utils/color_cache.c
@@ -13,6 +13,7 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include "./color_cache.h"
#include "../utils/utils.h"
@@ -27,6 +28,7 @@ int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) {
sizeof(*cc->colors_));
if (cc->colors_ == NULL) return 0;
cc->hash_shift_ = 32 - hash_bits;
+ cc->hash_bits_ = hash_bits;
return 1;
}
@@ -37,3 +39,11 @@ void VP8LColorCacheClear(VP8LColorCache* const cc) {
}
}
+void VP8LColorCacheCopy(const VP8LColorCache* const src,
+ VP8LColorCache* const dst) {
+ assert(src != NULL);
+ assert(dst != NULL);
+ assert(src->hash_bits_ == dst->hash_bits_);
+ memcpy(dst->colors_, src->colors_,
+ ((size_t)1u << dst->hash_bits_) * sizeof(*dst->colors_));
+}
diff --git a/src/3rdparty/libwebp/src/utils/color_cache.h b/src/3rdparty/libwebp/src/utils/color_cache.h
index 0f824ed..a9a9f64 100644
--- a/src/3rdparty/libwebp/src/utils/color_cache.h
+++ b/src/3rdparty/libwebp/src/utils/color_cache.h
@@ -24,17 +24,24 @@ extern "C" {
// Main color cache struct.
typedef struct {
uint32_t *colors_; // color entries
- int hash_shift_; // Hash shift: 32 - hash_bits.
+ int hash_shift_; // Hash shift: 32 - hash_bits_.
+ int hash_bits_;
} VP8LColorCache;
static const uint32_t kHashMul = 0x1e35a7bd;
static WEBP_INLINE uint32_t VP8LColorCacheLookup(
const VP8LColorCache* const cc, uint32_t key) {
- assert(key <= (~0U >> cc->hash_shift_));
+ assert((key >> cc->hash_bits_) == 0u);
return cc->colors_[key];
}
+static WEBP_INLINE void VP8LColorCacheSet(const VP8LColorCache* const cc,
+ uint32_t key, uint32_t argb) {
+ assert((key >> cc->hash_bits_) == 0u);
+ cc->colors_[key] = argb;
+}
+
static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc,
uint32_t argb) {
const uint32_t key = (kHashMul * argb) >> cc->hash_shift_;
@@ -49,7 +56,7 @@ static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc,
static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc,
uint32_t argb) {
const uint32_t key = (kHashMul * argb) >> cc->hash_shift_;
- return cc->colors_[key] == argb;
+ return (cc->colors_[key] == argb);
}
//------------------------------------------------------------------------------
@@ -58,6 +65,9 @@ static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc,
// Returns false in case of memory error.
int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits);
+void VP8LColorCacheCopy(const VP8LColorCache* const src,
+ VP8LColorCache* const dst);
+
// Delete the memory associated to color cache.
void VP8LColorCacheClear(VP8LColorCache* const color_cache);
diff --git a/src/3rdparty/libwebp/src/utils/filters.c b/src/3rdparty/libwebp/src/utils/filters.c
index 2d15bd0..15543b1 100644
--- a/src/3rdparty/libwebp/src/utils/filters.c
+++ b/src/3rdparty/libwebp/src/utils/filters.c
@@ -7,200 +7,27 @@
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// Spatial prediction using various filters
+// filter estimation
//
// Author: Urvang (urvang@google.com)
#include "./filters.h"
-#include <assert.h>
#include <stdlib.h>
#include <string.h>
-//------------------------------------------------------------------------------
-// Helpful macro.
-
-# define SANITY_CHECK(in, out) \
- assert(in != NULL); \
- assert(out != NULL); \
- assert(width > 0); \
- assert(height > 0); \
- assert(stride >= width); \
- assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
- (void)height; // Silence unused warning.
-
-static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
- uint8_t* dst, int length, int inverse) {
- int i;
- if (inverse) {
- for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
- } else {
- for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i];
- }
-}
-
-//------------------------------------------------------------------------------
-// Horizontal filter.
-
-static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows,
- int inverse, uint8_t* out) {
- const uint8_t* preds;
- const size_t start_offset = row * stride;
- const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
- in += start_offset;
- out += start_offset;
- preds = inverse ? out : in;
-
- if (row == 0) {
- // Leftmost pixel is the same as input for topmost scanline.
- out[0] = in[0];
- PredictLine(in + 1, preds, out + 1, width - 1, inverse);
- row = 1;
- preds += stride;
- in += stride;
- out += stride;
- }
-
- // Filter line-by-line.
- while (row < last_row) {
- // Leftmost pixel is predicted from above.
- PredictLine(in, preds - stride, out, 1, inverse);
- PredictLine(in + 1, preds, out + 1, width - 1, inverse);
- ++row;
- preds += stride;
- in += stride;
- out += stride;
- }
-}
-
-static void HorizontalFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data);
-}
-
-static void HorizontalUnfilter(int width, int height, int stride, int row,
- int num_rows, uint8_t* data) {
- DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data);
-}
-
-//------------------------------------------------------------------------------
-// Vertical filter.
-
-static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows,
- int inverse, uint8_t* out) {
- const uint8_t* preds;
- const size_t start_offset = row * stride;
- const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
- in += start_offset;
- out += start_offset;
- preds = inverse ? out : in;
-
- if (row == 0) {
- // Very first top-left pixel is copied.
- out[0] = in[0];
- // Rest of top scan-line is left-predicted.
- PredictLine(in + 1, preds, out + 1, width - 1, inverse);
- row = 1;
- in += stride;
- out += stride;
- } else {
- // We are starting from in-between. Make sure 'preds' points to prev row.
- preds -= stride;
- }
-
- // Filter line-by-line.
- while (row < last_row) {
- PredictLine(in, preds, out, width, inverse);
- ++row;
- preds += stride;
- in += stride;
- out += stride;
- }
-}
-
-static void VerticalFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data);
-}
-
-static void VerticalUnfilter(int width, int height, int stride, int row,
- int num_rows, uint8_t* data) {
- DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data);
-}
+// -----------------------------------------------------------------------------
+// Quick estimate of a potentially interesting filter mode to try.
-//------------------------------------------------------------------------------
-// Gradient filter.
+#define SMAX 16
+#define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX)
static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
const int g = a + b - c;
return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
}
-static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows,
- int inverse, uint8_t* out) {
- const uint8_t* preds;
- const size_t start_offset = row * stride;
- const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
- in += start_offset;
- out += start_offset;
- preds = inverse ? out : in;
-
- // left prediction for top scan-line
- if (row == 0) {
- out[0] = in[0];
- PredictLine(in + 1, preds, out + 1, width - 1, inverse);
- row = 1;
- preds += stride;
- in += stride;
- out += stride;
- }
-
- // Filter line-by-line.
- while (row < last_row) {
- int w;
- // leftmost pixel: predict from above.
- PredictLine(in, preds - stride, out, 1, inverse);
- for (w = 1; w < width; ++w) {
- const int pred = GradientPredictor(preds[w - 1],
- preds[w - stride],
- preds[w - stride - 1]);
- out[w] = in[w] + (inverse ? pred : -pred);
- }
- ++row;
- preds += stride;
- in += stride;
- out += stride;
- }
-}
-
-static void GradientFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data);
-}
-
-static void GradientUnfilter(int width, int height, int stride, int row,
- int num_rows, uint8_t* data) {
- DoGradientFilter(data, width, height, stride, row, num_rows, 1, data);
-}
-
-#undef SANITY_CHECK
-
-// -----------------------------------------------------------------------------
-// Quick estimate of a potentially interesting filter mode to try.
-
-#define SMAX 16
-#define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX)
-
-WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
- int width, int height, int stride) {
+WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
+ int width, int height, int stride) {
int i, j;
int bins[WEBP_FILTER_LAST][SMAX];
memset(bins, 0, sizeof(bins));
@@ -247,20 +74,3 @@ WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
#undef SDIFF
//------------------------------------------------------------------------------
-
-const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = {
- NULL, // WEBP_FILTER_NONE
- HorizontalFilter, // WEBP_FILTER_HORIZONTAL
- VerticalFilter, // WEBP_FILTER_VERTICAL
- GradientFilter // WEBP_FILTER_GRADIENT
-};
-
-const WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST] = {
- NULL, // WEBP_FILTER_NONE
- HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL
- VerticalUnfilter, // WEBP_FILTER_VERTICAL
- GradientUnfilter // WEBP_FILTER_GRADIENT
-};
-
-//------------------------------------------------------------------------------
-
diff --git a/src/3rdparty/libwebp/src/utils/filters.h b/src/3rdparty/libwebp/src/utils/filters.h
index dde39cb..088b132 100644
--- a/src/3rdparty/libwebp/src/utils/filters.h
+++ b/src/3rdparty/libwebp/src/utils/filters.h
@@ -15,42 +15,15 @@
#define WEBP_UTILS_FILTERS_H_
#include "../webp/types.h"
+#include "../dsp/dsp.h"
#ifdef __cplusplus
extern "C" {
#endif
-// Filters.
-typedef enum {
- WEBP_FILTER_NONE = 0,
- WEBP_FILTER_HORIZONTAL,
- WEBP_FILTER_VERTICAL,
- WEBP_FILTER_GRADIENT,
- WEBP_FILTER_LAST = WEBP_FILTER_GRADIENT + 1, // end marker
- WEBP_FILTER_BEST,
- WEBP_FILTER_FAST
-} WEBP_FILTER_TYPE;
-
-typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height,
- int stride, uint8_t* out);
-typedef void (*WebPUnfilterFunc)(int width, int height, int stride,
- int row, int num_rows, uint8_t* data);
-
-// Filter the given data using the given predictor.
-// 'in' corresponds to a 2-dimensional pixel array of size (stride * height)
-// in raster order.
-// 'stride' is number of bytes per scan line (with possible padding).
-// 'out' should be pre-allocated.
-extern const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
-
-// In-place reconstruct the original data from the given filtered data.
-// The reconstruction will be done for 'num_rows' rows starting from 'row'
-// (assuming rows upto 'row - 1' are already reconstructed).
-extern const WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
-
// Fast estimate of a potentially good filter.
-WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
- int width, int height, int stride);
+WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
+ int width, int height, int stride);
#ifdef __cplusplus
} // extern "C"
diff --git a/src/3rdparty/libwebp/src/utils/huffman.c b/src/3rdparty/libwebp/src/utils/huffman.c
index c4c16d9..d57376a 100644
--- a/src/3rdparty/libwebp/src/utils/huffman.c
+++ b/src/3rdparty/libwebp/src/utils/huffman.c
@@ -18,302 +18,188 @@
#include "../utils/utils.h"
#include "../webp/format_constants.h"
-// Uncomment the following to use look-up table for ReverseBits()
-// (might be faster on some platform)
-// #define USE_LUT_REVERSE_BITS
-
// Huffman data read via DecodeImageStream is represented in two (red and green)
// bytes.
#define MAX_HTREE_GROUPS 0x10000
-#define NON_EXISTENT_SYMBOL (-1)
-
-static void TreeNodeInit(HuffmanTreeNode* const node) {
- node->children_ = -1; // means: 'unassigned so far'
-}
-
-static int NodeIsEmpty(const HuffmanTreeNode* const node) {
- return (node->children_ < 0);
-}
-
-static int IsFull(const HuffmanTree* const tree) {
- return (tree->num_nodes_ == tree->max_nodes_);
-}
-
-static void AssignChildren(HuffmanTree* const tree,
- HuffmanTreeNode* const node) {
- HuffmanTreeNode* const children = tree->root_ + tree->num_nodes_;
- node->children_ = (int)(children - node);
- assert(children - node == (int)(children - node));
- tree->num_nodes_ += 2;
- TreeNodeInit(children + 0);
- TreeNodeInit(children + 1);
-}
-
-// A Huffman tree is a full binary tree; and in a full binary tree with L
-// leaves, the total number of nodes N = 2 * L - 1.
-static int HuffmanTreeMaxNodes(int num_leaves) {
- return (2 * num_leaves - 1);
-}
-
-static int HuffmanTreeAllocate(HuffmanTree* const tree, int num_nodes) {
- assert(tree != NULL);
- tree->root_ =
- (HuffmanTreeNode*)WebPSafeMalloc(num_nodes, sizeof(*tree->root_));
- return (tree->root_ != NULL);
-}
-
-static int TreeInit(HuffmanTree* const tree, int num_leaves) {
- assert(tree != NULL);
- if (num_leaves == 0) return 0;
- tree->max_nodes_ = HuffmanTreeMaxNodes(num_leaves);
- assert(tree->max_nodes_ < (1 << 16)); // limit for the lut_jump_ table
- if (!HuffmanTreeAllocate(tree, tree->max_nodes_)) return 0;
- TreeNodeInit(tree->root_); // Initialize root.
- tree->num_nodes_ = 1;
- memset(tree->lut_bits_, 255, sizeof(tree->lut_bits_));
- memset(tree->lut_jump_, 0, sizeof(tree->lut_jump_));
- return 1;
-}
-
-void VP8LHuffmanTreeFree(HuffmanTree* const tree) {
- if (tree != NULL) {
- WebPSafeFree(tree->root_);
- tree->root_ = NULL;
- tree->max_nodes_ = 0;
- tree->num_nodes_ = 0;
- }
-}
HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups) {
HTreeGroup* const htree_groups =
- (HTreeGroup*)WebPSafeCalloc(num_htree_groups, sizeof(*htree_groups));
- assert(num_htree_groups <= MAX_HTREE_GROUPS);
+ (HTreeGroup*)WebPSafeMalloc(num_htree_groups, sizeof(*htree_groups));
if (htree_groups == NULL) {
return NULL;
}
+ assert(num_htree_groups <= MAX_HTREE_GROUPS);
return htree_groups;
}
-void VP8LHtreeGroupsFree(HTreeGroup* htree_groups, int num_htree_groups) {
+void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups) {
if (htree_groups != NULL) {
- int i, j;
- for (i = 0; i < num_htree_groups; ++i) {
- HuffmanTree* const htrees = htree_groups[i].htrees_;
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- VP8LHuffmanTreeFree(&htrees[j]);
- }
- }
WebPSafeFree(htree_groups);
}
}
-int VP8LHuffmanCodeLengthsToCodes(
- const int* const code_lengths, int code_lengths_size,
- int* const huff_codes) {
- int symbol;
- int code_len;
- int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
- int curr_code;
- int next_codes[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
- int max_code_length = 0;
-
- assert(code_lengths != NULL);
- assert(code_lengths_size > 0);
- assert(huff_codes != NULL);
-
- // Calculate max code length.
- for (symbol = 0; symbol < code_lengths_size; ++symbol) {
- if (code_lengths[symbol] > max_code_length) {
- max_code_length = code_lengths[symbol];
- }
- }
- if (max_code_length > MAX_ALLOWED_CODE_LENGTH) return 0;
-
- // Calculate code length histogram.
- for (symbol = 0; symbol < code_lengths_size; ++symbol) {
- ++code_length_hist[code_lengths[symbol]];
+// Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the
+// bit-wise reversal of the len least significant bits of key.
+static WEBP_INLINE uint32_t GetNextKey(uint32_t key, int len) {
+ uint32_t step = 1 << (len - 1);
+ while (key & step) {
+ step >>= 1;
}
- code_length_hist[0] = 0;
-
- // Calculate the initial values of 'next_codes' for each code length.
- // next_codes[code_len] denotes the code to be assigned to the next symbol
- // of code length 'code_len'.
- curr_code = 0;
- next_codes[0] = -1; // Unused, as code length = 0 implies code doesn't exist.
- for (code_len = 1; code_len <= max_code_length; ++code_len) {
- curr_code = (curr_code + code_length_hist[code_len - 1]) << 1;
- next_codes[code_len] = curr_code;
+ return (key & (step - 1)) + step;
+}
+
+// Stores code in table[0], table[step], table[2*step], ..., table[end].
+// Assumes that end is an integer multiple of step.
+static WEBP_INLINE void ReplicateValue(HuffmanCode* table,
+ int step, int end,
+ HuffmanCode code) {
+ assert(end % step == 0);
+ do {
+ end -= step;
+ table[end] = code;
+ } while (end > 0);
+}
+
+// Returns the table width of the next 2nd level table. count is the histogram
+// of bit lengths for the remaining symbols, len is the code length of the next
+// processed symbol
+static WEBP_INLINE int NextTableBitSize(const int* const count,
+ int len, int root_bits) {
+ int left = 1 << (len - root_bits);
+ while (len < MAX_ALLOWED_CODE_LENGTH) {
+ left -= count[len];
+ if (left <= 0) break;
+ ++len;
+ left <<= 1;
}
+ return len - root_bits;
+}
+
+int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+ const int code_lengths[], int code_lengths_size) {
+ HuffmanCode* table = root_table; // next available space in table
+ int total_size = 1 << root_bits; // total size root table + 2nd level table
+ int* sorted = NULL; // symbols sorted by code length
+ int len; // current code length
+ int symbol; // symbol index in original or sorted table
+ // number of codes of each length:
+ int count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
+ // offsets in sorted table for each length:
+ int offset[MAX_ALLOWED_CODE_LENGTH + 1];
+
+ assert(code_lengths_size != 0);
+ assert(code_lengths != NULL);
+ assert(root_table != NULL);
+ assert(root_bits > 0);
- // Get symbols.
+ // Build histogram of code lengths.
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
- if (code_lengths[symbol] > 0) {
- huff_codes[symbol] = next_codes[code_lengths[symbol]]++;
- } else {
- huff_codes[symbol] = NON_EXISTENT_SYMBOL;
+ if (code_lengths[symbol] > MAX_ALLOWED_CODE_LENGTH) {
+ return 0;
}
+ ++count[code_lengths[symbol]];
}
- return 1;
-}
-
-#ifndef USE_LUT_REVERSE_BITS
-static int ReverseBitsShort(int bits, int num_bits) {
- int retval = 0;
- int i;
- assert(num_bits <= 8); // Not a hard requirement, just for coherency.
- for (i = 0; i < num_bits; ++i) {
- retval <<= 1;
- retval |= bits & 1;
- bits >>= 1;
+ // Error, all code lengths are zeros.
+ if (count[0] == code_lengths_size) {
+ return 0;
}
- return retval;
-}
-
-#else
-
-static const uint8_t kReversedBits[16] = { // Pre-reversed 4-bit values.
- 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
- 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
-};
-static int ReverseBitsShort(int bits, int num_bits) {
- const uint8_t v = (kReversedBits[bits & 0xf] << 4) | kReversedBits[bits >> 4];
- assert(num_bits <= 8);
- return v >> (8 - num_bits);
-}
-
-#endif
-
-static int TreeAddSymbol(HuffmanTree* const tree,
- int symbol, int code, int code_length) {
- int step = HUFF_LUT_BITS;
- int base_code;
- HuffmanTreeNode* node = tree->root_;
- const HuffmanTreeNode* const max_node = tree->root_ + tree->max_nodes_;
- assert(symbol == (int16_t)symbol);
- if (code_length <= HUFF_LUT_BITS) {
- int i;
- base_code = ReverseBitsShort(code, code_length);
- for (i = 0; i < (1 << (HUFF_LUT_BITS - code_length)); ++i) {
- const int idx = base_code | (i << code_length);
- tree->lut_symbol_[idx] = (int16_t)symbol;
- tree->lut_bits_[idx] = code_length;
- }
- } else {
- base_code = ReverseBitsShort((code >> (code_length - HUFF_LUT_BITS)),
- HUFF_LUT_BITS);
- }
- while (code_length-- > 0) {
- if (node >= max_node) {
+ // Generate offsets into sorted symbol table by code length.
+ offset[1] = 0;
+ for (len = 1; len < MAX_ALLOWED_CODE_LENGTH; ++len) {
+ if (count[len] > (1 << len)) {
return 0;
}
- if (NodeIsEmpty(node)) {
- if (IsFull(tree)) return 0; // error: too many symbols.
- AssignChildren(tree, node);
- } else if (!HuffmanTreeNodeIsNotLeaf(node)) {
- return 0; // leaf is already occupied.
- }
- node += node->children_ + ((code >> code_length) & 1);
- if (--step == 0) {
- tree->lut_jump_[base_code] = (int16_t)(node - tree->root_);
- }
- }
- if (NodeIsEmpty(node)) {
- node->children_ = 0; // turn newly created node into a leaf.
- } else if (HuffmanTreeNodeIsNotLeaf(node)) {
- return 0; // trying to assign a symbol to already used code.
+ offset[len + 1] = offset[len] + count[len];
}
- node->symbol_ = symbol; // Add symbol in this node.
- return 1;
-}
-
-int VP8LHuffmanTreeBuildImplicit(HuffmanTree* const tree,
- const int* const code_lengths,
- int* const codes,
- int code_lengths_size) {
- int symbol;
- int num_symbols = 0;
- int root_symbol = 0;
- assert(tree != NULL);
- assert(code_lengths != NULL);
+ sorted = (int*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
+ if (sorted == NULL) {
+ return 0;
+ }
- // Find out number of symbols and the root symbol.
+ // Sort symbols by length, by symbol order within each length.
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
+ const int symbol_code_length = code_lengths[symbol];
if (code_lengths[symbol] > 0) {
- // Note: code length = 0 indicates non-existent symbol.
- ++num_symbols;
- root_symbol = symbol;
+ sorted[offset[symbol_code_length]++] = symbol;
}
}
- // Initialize the tree. Will fail for num_symbols = 0
- if (!TreeInit(tree, num_symbols)) return 0;
-
- // Build tree.
- if (num_symbols == 1) { // Trivial case.
- const int max_symbol = code_lengths_size;
- if (root_symbol < 0 || root_symbol >= max_symbol) {
- VP8LHuffmanTreeFree(tree);
- return 0;
- }
- return TreeAddSymbol(tree, root_symbol, 0, 0);
- } else { // Normal case.
- int ok = 0;
- memset(codes, 0, code_lengths_size * sizeof(*codes));
+ // Special case code with only one value.
+ if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) {
+ HuffmanCode code;
+ code.bits = 0;
+ code.value = (uint16_t)sorted[0];
+ ReplicateValue(table, 1, total_size, code);
+ WebPSafeFree(sorted);
+ return total_size;
+ }
- if (!VP8LHuffmanCodeLengthsToCodes(code_lengths, code_lengths_size,
- codes)) {
- goto End;
+ {
+ int step; // step size to replicate values in current table
+ uint32_t low = -1; // low bits for current root entry
+ uint32_t mask = total_size - 1; // mask for low bits
+ uint32_t key = 0; // reversed prefix code
+ int num_nodes = 1; // number of Huffman tree nodes
+ int num_open = 1; // number of open branches in current tree level
+ int table_bits = root_bits; // key length of current table
+ int table_size = 1 << table_bits; // size of current table
+ symbol = 0;
+ // Fill in root table.
+ for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) {
+ num_open <<= 1;
+ num_nodes += num_open;
+ num_open -= count[len];
+ if (num_open < 0) {
+ WebPSafeFree(sorted);
+ return 0;
+ }
+ for (; count[len] > 0; --count[len]) {
+ HuffmanCode code;
+ code.bits = (uint8_t)len;
+ code.value = (uint16_t)sorted[symbol++];
+ ReplicateValue(&table[key], step, table_size, code);
+ key = GetNextKey(key, len);
+ }
}
- // Add symbols one-by-one.
- for (symbol = 0; symbol < code_lengths_size; ++symbol) {
- if (code_lengths[symbol] > 0) {
- if (!TreeAddSymbol(tree, symbol, codes[symbol],
- code_lengths[symbol])) {
- goto End;
+ // Fill in 2nd level tables and add pointers to root table.
+ for (len = root_bits + 1, step = 2; len <= MAX_ALLOWED_CODE_LENGTH;
+ ++len, step <<= 1) {
+ num_open <<= 1;
+ num_nodes += num_open;
+ num_open -= count[len];
+ if (num_open < 0) {
+ WebPSafeFree(sorted);
+ return 0;
+ }
+ for (; count[len] > 0; --count[len]) {
+ HuffmanCode code;
+ if ((key & mask) != low) {
+ table += table_size;
+ table_bits = NextTableBitSize(count, len, root_bits);
+ table_size = 1 << table_bits;
+ total_size += table_size;
+ low = key & mask;
+ root_table[low].bits = (uint8_t)(table_bits + root_bits);
+ root_table[low].value = (uint16_t)((table - root_table) - low);
}
+ code.bits = (uint8_t)(len - root_bits);
+ code.value = (uint16_t)sorted[symbol++];
+ ReplicateValue(&table[key >> root_bits], step, table_size, code);
+ key = GetNextKey(key, len);
}
}
- ok = 1;
- End:
- ok = ok && IsFull(tree);
- if (!ok) VP8LHuffmanTreeFree(tree);
- return ok;
- }
-}
-
-int VP8LHuffmanTreeBuildExplicit(HuffmanTree* const tree,
- const int* const code_lengths,
- const int* const codes,
- const int* const symbols, int max_symbol,
- int num_symbols) {
- int ok = 0;
- int i;
- assert(tree != NULL);
- assert(code_lengths != NULL);
- assert(codes != NULL);
- assert(symbols != NULL);
-
- // Initialize the tree. Will fail if num_symbols = 0.
- if (!TreeInit(tree, num_symbols)) return 0;
- // Add symbols one-by-one.
- for (i = 0; i < num_symbols; ++i) {
- if (codes[i] != NON_EXISTENT_SYMBOL) {
- if (symbols[i] < 0 || symbols[i] >= max_symbol) {
- goto End;
- }
- if (!TreeAddSymbol(tree, symbols[i], codes[i], code_lengths[i])) {
- goto End;
- }
+ // Check if tree is full.
+ if (num_nodes != 2 * offset[MAX_ALLOWED_CODE_LENGTH] - 1) {
+ WebPSafeFree(sorted);
+ return 0;
}
}
- ok = 1;
- End:
- ok = ok && IsFull(tree);
- if (!ok) VP8LHuffmanTreeFree(tree);
- return ok;
+
+ WebPSafeFree(sorted);
+ return total_size;
}
diff --git a/src/3rdparty/libwebp/src/utils/huffman.h b/src/3rdparty/libwebp/src/utils/huffman.h
index 624bc17..c6dd6aa 100644
--- a/src/3rdparty/libwebp/src/utils/huffman.h
+++ b/src/3rdparty/libwebp/src/utils/huffman.h
@@ -22,78 +22,64 @@
extern "C" {
#endif
-// A node of a Huffman tree.
-typedef struct {
- int symbol_;
- int children_; // delta offset to both children (contiguous) or 0 if leaf.
-} HuffmanTreeNode;
+#define HUFFMAN_TABLE_BITS 8
+#define HUFFMAN_TABLE_MASK ((1 << HUFFMAN_TABLE_BITS) - 1)
+
+#define LENGTHS_TABLE_BITS 7
+#define LENGTHS_TABLE_MASK ((1 << LENGTHS_TABLE_BITS) - 1)
-// Huffman Tree.
-#define HUFF_LUT_BITS 7
-#define HUFF_LUT (1U << HUFF_LUT_BITS)
-typedef struct HuffmanTree HuffmanTree;
-struct HuffmanTree {
- // Fast lookup for short bit lengths.
- uint8_t lut_bits_[HUFF_LUT];
- int16_t lut_symbol_[HUFF_LUT];
- int16_t lut_jump_[HUFF_LUT];
- // Complete tree for lookups.
- HuffmanTreeNode* root_; // all the nodes, starting at root.
- int max_nodes_; // max number of nodes
- int num_nodes_; // number of currently occupied nodes
-};
-// Huffman Tree group.
+// Huffman lookup table entry
+typedef struct {
+ uint8_t bits; // number of bits used for this symbol
+ uint16_t value; // symbol value or table offset
+} HuffmanCode;
+
+// long version for holding 32b values
+typedef struct {
+ int bits; // number of bits used for this symbol,
+ // or an impossible value if not a literal code.
+ uint32_t value; // 32b packed ARGB value if literal,
+ // or non-literal symbol otherwise
+} HuffmanCode32;
+
+#define HUFFMAN_PACKED_BITS 6
+#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
+
+// Huffman table group.
+// Includes special handling for the following cases:
+// - is_trivial_literal: one common literal base for RED/BLUE/ALPHA (not GREEN)
+// - is_trivial_code: only 1 code (no bit is read from bitstream)
+// - use_packed_table: few enough literal symbols, so all the bit codes
+// can fit into a small look-up table packed_table[]
+// The common literal base, if applicable, is stored in 'literal_arb'.
typedef struct HTreeGroup HTreeGroup;
struct HTreeGroup {
- HuffmanTree htrees_[HUFFMAN_CODES_PER_META_CODE];
+ HuffmanCode* htrees[HUFFMAN_CODES_PER_META_CODE];
+ int is_trivial_literal; // True, if huffman trees for Red, Blue & Alpha
+ // Symbols are trivial (have a single code).
+ uint32_t literal_arb; // If is_trivial_literal is true, this is the
+ // ARGB value of the pixel, with Green channel
+ // being set to zero.
+ int is_trivial_code; // true if is_trivial_literal with only one code
+ int use_packed_table; // use packed table below for short literal code
+ // table mapping input bits to a packed values, or escape case to literal code
+ HuffmanCode32 packed_table[HUFFMAN_PACKED_TABLE_SIZE];
};
-// Returns true if the given node is not a leaf of the Huffman tree.
-static WEBP_INLINE int HuffmanTreeNodeIsNotLeaf(
- const HuffmanTreeNode* const node) {
- return node->children_;
-}
-
-// Go down one level. Most critical function. 'right_child' must be 0 or 1.
-static WEBP_INLINE const HuffmanTreeNode* HuffmanTreeNextNode(
- const HuffmanTreeNode* node, int right_child) {
- return node + node->children_ + right_child;
-}
-
-// Releases the nodes of the Huffman tree.
-// Note: It does NOT free 'tree' itself.
-void VP8LHuffmanTreeFree(HuffmanTree* const tree);
-
// Creates the instance of HTreeGroup with specified number of tree-groups.
HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups);
// Releases the memory allocated for HTreeGroup.
-void VP8LHtreeGroupsFree(HTreeGroup* htree_groups, int num_htree_groups);
-
-// Builds Huffman tree assuming code lengths are implicitly in symbol order.
-// The 'huff_codes' and 'code_lengths' are pre-allocated temporary memory
-// buffers, used for creating the huffman tree.
-// Returns false in case of error (invalid tree or memory error).
-int VP8LHuffmanTreeBuildImplicit(HuffmanTree* const tree,
- const int* const code_lengths,
- int* const huff_codes,
- int code_lengths_size);
-
-// Build a Huffman tree with explicitly given lists of code lengths, codes
-// and symbols. Verifies that all symbols added are smaller than max_symbol.
-// Returns false in case of an invalid symbol, invalid tree or memory error.
-int VP8LHuffmanTreeBuildExplicit(HuffmanTree* const tree,
- const int* const code_lengths,
- const int* const codes,
- const int* const symbols, int max_symbol,
- int num_symbols);
-
-// Utility: converts Huffman code lengths to corresponding Huffman codes.
-// 'huff_codes' should be pre-allocated.
-// Returns false in case of error (memory allocation, invalid codes).
-int VP8LHuffmanCodeLengthsToCodes(const int* const code_lengths,
- int code_lengths_size, int* const huff_codes);
+void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
+
+// Builds Huffman lookup table assuming code lengths are in symbol order.
+// The 'code_lengths' is pre-allocated temporary memory buffer used for creating
+// the huffman table.
+// Returns built table size or 0 in case of error (invalid tree or
+// memory error).
+int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+ const int code_lengths[], int code_lengths_size);
#ifdef __cplusplus
} // extern "C"
diff --git a/src/3rdparty/libwebp/src/utils/huffman_encode.h b/src/3rdparty/libwebp/src/utils/huffman_encode.h
index 91aa18f..a157165 100644
--- a/src/3rdparty/libwebp/src/utils/huffman_encode.h
+++ b/src/3rdparty/libwebp/src/utils/huffman_encode.h
@@ -34,10 +34,9 @@ typedef struct {
} HuffmanTreeCode;
// Struct to represent the Huffman tree.
-// TODO(vikasa): Add comment for the fields of the Struct.
typedef struct {
- uint32_t total_count_;
- int value_;
+ uint32_t total_count_; // Symbol frequency.
+ int value_; // Symbol value.
int pool_index_left_; // Index for the left sub-tree.
int pool_index_right_; // Index for the right sub-tree.
} HuffmanTree;
diff --git a/src/3rdparty/libwebp/src/utils/rescaler.c b/src/3rdparty/libwebp/src/utils/rescaler.c
index 3a43229..00c9300 100644
--- a/src/3rdparty/libwebp/src/utils/rescaler.c
+++ b/src/3rdparty/libwebp/src/utils/rescaler.c
@@ -14,451 +14,8 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "./rescaler.h"
#include "../dsp/dsp.h"
-
-//------------------------------------------------------------------------------
-// Implementations of critical functions ImportRow / ExportRow
-
-// Import a row of data and save its contribution in the rescaler.
-// 'channel' denotes the channel number to be imported. 'Expand' corresponds to
-// the wrk->x_expand case. Otherwise, 'Shrink' is to be used.
-typedef void (*WebPRescalerImportRowFunc)(WebPRescaler* const wrk,
- const uint8_t* src);
-static WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
-static WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
-
-// Export one row (starting at x_out position) from rescaler.
-// 'Expand' corresponds to the wrk->y_expand case.
-// Otherwise 'Shrink' is to be used
-typedef void (*WebPRescalerExportRowFunc)(WebPRescaler* const wrk);
-static WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
-static WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
-
-#define WEBP_RESCALER_RFIX 32 // fixed-point precision for multiplies
-#define WEBP_RESCALER_ONE (1ull << WEBP_RESCALER_RFIX)
-#define WEBP_RESCALER_FRAC(x, y) \
- ((uint32_t)(((uint64_t)(x) << WEBP_RESCALER_RFIX) / (y)))
-#define ROUNDER (WEBP_RESCALER_ONE >> 1)
-#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
-
-static void ImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) {
- const int x_stride = wrk->num_channels;
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- int channel;
- assert(!WebPRescalerInputDone(wrk));
- assert(wrk->x_expand);
- for (channel = 0; channel < x_stride; ++channel) {
- int x_in = channel;
- int x_out = channel;
- // simple bilinear interpolation
- int accum = wrk->x_add;
- int left = src[x_in];
- int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
- x_in += x_stride;
- while (1) {
- wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
- x_out += x_stride;
- if (x_out >= x_out_max) break;
- accum -= wrk->x_sub;
- if (accum < 0) {
- left = right;
- x_in += x_stride;
- assert(x_in < wrk->src_width * x_stride);
- right = src[x_in];
- accum += wrk->x_add;
- }
- }
- assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
- }
-}
-
-static void ImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) {
- const int x_stride = wrk->num_channels;
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- int channel;
- assert(!WebPRescalerInputDone(wrk));
- assert(!wrk->x_expand);
- for (channel = 0; channel < x_stride; ++channel) {
- int x_in = channel;
- int x_out = channel;
- uint32_t sum = 0;
- int accum = 0;
- while (x_out < x_out_max) {
- uint32_t base = 0;
- accum += wrk->x_add;
- while (accum > 0) {
- accum -= wrk->x_sub;
- assert(x_in < wrk->src_width * x_stride);
- base = src[x_in];
- sum += base;
- x_in += x_stride;
- }
- { // Emit next horizontal pixel.
- const rescaler_t frac = base * (-accum);
- wrk->frow[x_out] = sum * wrk->x_sub - frac;
- // fresh fractional start for next pixel
- sum = (int)MULT_FIX(frac, wrk->fx_scale);
- }
- x_out += x_stride;
- }
- assert(accum == 0);
- }
-}
-
-//------------------------------------------------------------------------------
-// Row export
-
-static void ExportRowExpandC(WebPRescaler* const wrk) {
- int x_out;
- uint8_t* const dst = wrk->dst;
- rescaler_t* const irow = wrk->irow;
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- const rescaler_t* const frow = wrk->frow;
- assert(!WebPRescalerOutputDone(wrk));
- assert(wrk->y_accum <= 0);
- assert(wrk->y_expand);
- assert(wrk->y_sub != 0);
- if (wrk->y_accum == 0) {
- for (x_out = 0; x_out < x_out_max; ++x_out) {
- const uint32_t J = frow[x_out];
- const int v = (int)MULT_FIX(J, wrk->fy_scale);
- assert(v >= 0 && v <= 255);
- dst[x_out] = v;
- }
- } else {
- const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
- const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
- for (x_out = 0; x_out < x_out_max; ++x_out) {
- const uint64_t I = (uint64_t)A * frow[x_out]
- + (uint64_t)B * irow[x_out];
- const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
- const int v = (int)MULT_FIX(J, wrk->fy_scale);
- assert(v >= 0 && v <= 255);
- dst[x_out] = v;
- }
- }
-}
-
-static void ExportRowShrinkC(WebPRescaler* const wrk) {
- int x_out;
- uint8_t* const dst = wrk->dst;
- rescaler_t* const irow = wrk->irow;
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- const rescaler_t* const frow = wrk->frow;
- const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
- assert(!WebPRescalerOutputDone(wrk));
- assert(wrk->y_accum <= 0);
- assert(!wrk->y_expand);
- 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);
- assert(v >= 0 && v <= 255);
- dst[x_out] = v;
- irow[x_out] = frac; // new fractional start
- }
- } else {
- for (x_out = 0; x_out < x_out_max; ++x_out) {
- const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
- assert(v >= 0 && v <= 255);
- dst[x_out] = v;
- irow[x_out] = 0;
- }
- }
-}
-
-//------------------------------------------------------------------------------
-// Main entry calls
-
-void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
- assert(!WebPRescalerInputDone(wrk));
- if (!wrk->x_expand) {
- WebPRescalerImportRowShrink(wrk, src);
- } else {
- WebPRescalerImportRowExpand(wrk, src);
- }
-}
-
-void WebPRescalerExportRow(WebPRescaler* const wrk) {
- if (wrk->y_accum <= 0) {
- assert(!WebPRescalerOutputDone(wrk));
- if (wrk->y_expand) {
- WebPRescalerExportRowExpand(wrk);
- } else if (wrk->fxy_scale) {
- WebPRescalerExportRowShrink(wrk);
- } else { // very special case for src = dst = 1x1
- int i;
- assert(wrk->src_width == 1 && wrk->dst_width <= 2);
- assert(wrk->src_height == 1 && wrk->dst_height == 1);
- for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
- wrk->dst[i] = wrk->irow[i];
- wrk->irow[i] = 0;
- }
- }
- wrk->y_accum += wrk->y_add;
- wrk->dst += wrk->dst_stride;
- ++wrk->dst_y;
- }
-}
-
-//------------------------------------------------------------------------------
-// MIPS version
-
-#if defined(WEBP_USE_MIPS32)
-
-static void ImportRowShrinkMIPS(WebPRescaler* const wrk, const uint8_t* src) {
- const int x_stride = wrk->num_channels;
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- const int fx_scale = wrk->fx_scale;
- const int x_add = wrk->x_add;
- const int x_sub = wrk->x_sub;
- const int x_stride1 = x_stride << 2;
- int channel;
- assert(!wrk->x_expand);
- assert(!WebPRescalerInputDone(wrk));
-
- for (channel = 0; channel < x_stride; ++channel) {
- const uint8_t* src1 = src + channel;
- rescaler_t* frow = wrk->frow + channel;
- int temp1, temp2, temp3;
- int base, frac, sum;
- int accum, accum1;
- int loop_c = x_out_max - channel;
-
- __asm__ volatile (
- "li %[temp1], 0x8000 \n\t"
- "li %[temp2], 0x10000 \n\t"
- "li %[sum], 0 \n\t"
- "li %[accum], 0 \n\t"
- "1: \n\t"
- "addu %[accum], %[accum], %[x_add] \n\t"
- "li %[base], 0 \n\t"
- "blez %[accum], 3f \n\t"
- "2: \n\t"
- "lbu %[base], 0(%[src1]) \n\t"
- "subu %[accum], %[accum], %[x_sub] \n\t"
- "addu %[src1], %[src1], %[x_stride] \n\t"
- "addu %[sum], %[sum], %[base] \n\t"
- "bgtz %[accum], 2b \n\t"
- "3: \n\t"
- "negu %[accum1], %[accum] \n\t"
- "mul %[frac], %[base], %[accum1] \n\t"
- "mul %[temp3], %[sum], %[x_sub] \n\t"
- "subu %[loop_c], %[loop_c], %[x_stride] \n\t"
- "mult %[temp1], %[temp2] \n\t"
- "maddu %[frac], %[fx_scale] \n\t"
- "mfhi %[sum] \n\t"
- "subu %[temp3], %[temp3], %[frac] \n\t"
- "sw %[temp3], 0(%[frow]) \n\t"
- "addu %[frow], %[frow], %[x_stride1] \n\t"
- "bgtz %[loop_c], 1b \n\t"
- : [accum]"=&r"(accum), [src1]"+r"(src1), [temp3]"=&r"(temp3),
- [sum]"=&r"(sum), [base]"=&r"(base), [frac]"=&r"(frac),
- [frow]"+r"(frow), [accum1]"=&r"(accum1),
- [temp2]"=&r"(temp2), [temp1]"=&r"(temp1)
- : [x_stride]"r"(x_stride), [fx_scale]"r"(fx_scale),
- [x_sub]"r"(x_sub), [x_add]"r"(x_add),
- [loop_c]"r"(loop_c), [x_stride1]"r"(x_stride1)
- : "memory", "hi", "lo"
- );
- assert(accum == 0);
- }
-}
-
-static void ImportRowExpandMIPS(WebPRescaler* const wrk, const uint8_t* src) {
- const int x_stride = wrk->num_channels;
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- const int x_add = wrk->x_add;
- const int x_sub = wrk->x_sub;
- const int src_width = wrk->src_width;
- const int x_stride1 = x_stride << 2;
- int channel;
- assert(wrk->x_expand);
- assert(!WebPRescalerInputDone(wrk));
-
- for (channel = 0; channel < x_stride; ++channel) {
- const uint8_t* src1 = src + channel;
- rescaler_t* frow = wrk->frow + channel;
- int temp1, temp2, temp3, temp4;
- int frac;
- int accum;
- int x_out = channel;
-
- __asm__ volatile (
- "addiu %[temp3], %[src_width], -1 \n\t"
- "lbu %[temp2], 0(%[src1]) \n\t"
- "addu %[src1], %[src1], %[x_stride] \n\t"
- "bgtz %[temp3], 0f \n\t"
- "addiu %[temp1], %[temp2], 0 \n\t"
- "b 3f \n\t"
- "0: \n\t"
- "lbu %[temp1], 0(%[src1]) \n\t"
- "3: \n\t"
- "addiu %[accum], %[x_add], 0 \n\t"
- "1: \n\t"
- "subu %[temp3], %[temp2], %[temp1] \n\t"
- "mul %[temp3], %[temp3], %[accum] \n\t"
- "mul %[temp4], %[temp1], %[x_add] \n\t"
- "addu %[temp3], %[temp4], %[temp3] \n\t"
- "sw %[temp3], 0(%[frow]) \n\t"
- "addu %[frow], %[frow], %[x_stride1] \n\t"
- "addu %[x_out], %[x_out], %[x_stride] \n\t"
- "subu %[temp3], %[x_out], %[x_out_max] \n\t"
- "bgez %[temp3], 2f \n\t"
- "subu %[accum], %[accum], %[x_sub] \n\t"
- "bgez %[accum], 4f \n\t"
- "addiu %[temp2], %[temp1], 0 \n\t"
- "addu %[src1], %[src1], %[x_stride] \n\t"
- "lbu %[temp1], 0(%[src1]) \n\t"
- "addu %[accum], %[accum], %[x_add] \n\t"
- "4: \n\t"
- "b 1b \n\t"
- "2: \n\t"
- : [src1]"+r"(src1), [accum]"=&r"(accum), [temp1]"=&r"(temp1),
- [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4),
- [x_out]"+r"(x_out), [frac]"=&r"(frac), [frow]"+r"(frow)
- : [x_stride]"r"(x_stride), [x_add]"r"(x_add), [x_sub]"r"(x_sub),
- [x_stride1]"r"(x_stride1), [src_width]"r"(src_width),
- [x_out_max]"r"(x_out_max)
- : "memory", "hi", "lo"
- );
- assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
- }
-}
-
-//------------------------------------------------------------------------------
-// Row export
-
-static void ExportRowExpandMIPS(WebPRescaler* const wrk) {
- uint8_t* dst = wrk->dst;
- rescaler_t* irow = wrk->irow;
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- const rescaler_t* frow = wrk->frow;
- int temp0, temp1, temp3, temp4, temp5, loop_end;
- const int temp2 = (int)wrk->fy_scale;
- const int temp6 = x_out_max << 2;
- assert(!WebPRescalerOutputDone(wrk));
- assert(wrk->y_accum <= 0);
- assert(wrk->y_expand);
- assert(wrk->y_sub != 0);
- if (wrk->y_accum == 0) {
- __asm__ volatile (
- "li %[temp3], 0x10000 \n\t"
- "li %[temp4], 0x8000 \n\t"
- "addu %[loop_end], %[frow], %[temp6] \n\t"
- "1: \n\t"
- "lw %[temp0], 0(%[frow]) \n\t"
- "addiu %[dst], %[dst], 1 \n\t"
- "addiu %[frow], %[frow], 4 \n\t"
- "mult %[temp3], %[temp4] \n\t"
- "maddu %[temp0], %[temp2] \n\t"
- "mfhi %[temp5] \n\t"
- "sb %[temp5], -1(%[dst]) \n\t"
- "bne %[frow], %[loop_end], 1b \n\t"
- : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
- [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
- [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
- : [temp2]"r"(temp2), [temp6]"r"(temp6)
- : "memory", "hi", "lo"
- );
- } else {
- const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
- const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
- __asm__ volatile (
- "li %[temp3], 0x10000 \n\t"
- "li %[temp4], 0x8000 \n\t"
- "addu %[loop_end], %[frow], %[temp6] \n\t"
- "1: \n\t"
- "lw %[temp0], 0(%[frow]) \n\t"
- "lw %[temp1], 0(%[irow]) \n\t"
- "addiu %[dst], %[dst], 1 \n\t"
- "mult %[temp3], %[temp4] \n\t"
- "maddu %[A], %[temp0] \n\t"
- "maddu %[B], %[temp1] \n\t"
- "addiu %[frow], %[frow], 4 \n\t"
- "addiu %[irow], %[irow], 4 \n\t"
- "mfhi %[temp5] \n\t"
- "mult %[temp3], %[temp4] \n\t"
- "maddu %[temp5], %[temp2] \n\t"
- "mfhi %[temp5] \n\t"
- "sb %[temp5], -1(%[dst]) \n\t"
- "bne %[frow], %[loop_end], 1b \n\t"
- : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
- [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
- [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
- : [temp2]"r"(temp2), [temp6]"r"(temp6), [A]"r"(A), [B]"r"(B)
- : "memory", "hi", "lo"
- );
- }
-}
-
-static void ExportRowShrinkMIPS(WebPRescaler* const wrk) {
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- uint8_t* dst = wrk->dst;
- rescaler_t* irow = wrk->irow;
- const rescaler_t* frow = wrk->frow;
- const int yscale = wrk->fy_scale * (-wrk->y_accum);
- int temp0, temp1, temp3, temp4, temp5, loop_end;
- const int temp2 = (int)wrk->fxy_scale;
- const int temp6 = x_out_max << 2;
-
- assert(!WebPRescalerOutputDone(wrk));
- assert(wrk->y_accum <= 0);
- assert(!wrk->y_expand);
- assert(wrk->fxy_scale != 0);
- if (yscale) {
- __asm__ volatile (
- "li %[temp3], 0x10000 \n\t"
- "li %[temp4], 0x8000 \n\t"
- "addu %[loop_end], %[frow], %[temp6] \n\t"
- "1: \n\t"
- "lw %[temp0], 0(%[frow]) \n\t"
- "mult %[temp3], %[temp4] \n\t"
- "addiu %[frow], %[frow], 4 \n\t"
- "maddu %[temp0], %[yscale] \n\t"
- "mfhi %[temp1] \n\t"
- "lw %[temp0], 0(%[irow]) \n\t"
- "addiu %[dst], %[dst], 1 \n\t"
- "addiu %[irow], %[irow], 4 \n\t"
- "subu %[temp0], %[temp0], %[temp1] \n\t"
- "mult %[temp3], %[temp4] \n\t"
- "maddu %[temp0], %[temp2] \n\t"
- "mfhi %[temp5] \n\t"
- "sw %[temp1], -4(%[irow]) \n\t"
- "sb %[temp5], -1(%[dst]) \n\t"
- "bne %[frow], %[loop_end], 1b \n\t"
- : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
- [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
- [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
- : [temp2]"r"(temp2), [yscale]"r"(yscale), [temp6]"r"(temp6)
- : "memory", "hi", "lo"
- );
- } else {
- __asm__ volatile (
- "li %[temp3], 0x10000 \n\t"
- "li %[temp4], 0x8000 \n\t"
- "addu %[loop_end], %[irow], %[temp6] \n\t"
- "1: \n\t"
- "lw %[temp0], 0(%[irow]) \n\t"
- "addiu %[dst], %[dst], 1 \n\t"
- "addiu %[irow], %[irow], 4 \n\t"
- "mult %[temp3], %[temp4] \n\t"
- "maddu %[temp0], %[temp2] \n\t"
- "mfhi %[temp5] \n\t"
- "sw $zero, -4(%[irow]) \n\t"
- "sb %[temp5], -1(%[dst]) \n\t"
- "bne %[irow], %[loop_end], 1b \n\t"
- : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
- [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow),
- [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
- : [temp2]"r"(temp2), [temp6]"r"(temp6)
- : "memory", "hi", "lo"
- );
- }
-}
-
-#endif // WEBP_USE_MIPS32
+#include "./rescaler.h"
//------------------------------------------------------------------------------
@@ -510,30 +67,37 @@ void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
wrk->frow = work + num_channels * dst_width;
memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
- if (WebPRescalerImportRowExpand == NULL) {
- WebPRescalerImportRowExpand = ImportRowExpandC;
- WebPRescalerImportRowShrink = ImportRowShrinkC;
- WebPRescalerExportRowExpand = ExportRowExpandC;
- WebPRescalerExportRowShrink = ExportRowShrinkC;
- if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_MIPS32)
- if (VP8GetCPUInfo(kMIPS32)) {
- WebPRescalerImportRowExpand = ImportRowExpandMIPS;
- WebPRescalerImportRowShrink = ImportRowShrinkMIPS;
- WebPRescalerExportRowExpand = ExportRowExpandMIPS;
- WebPRescalerExportRowShrink = ExportRowShrinkMIPS;
- }
-#endif
+ WebPRescalerDspInit();
+}
+
+int WebPRescalerGetScaledDimensions(int src_width, int src_height,
+ int* const scaled_width,
+ int* const scaled_height) {
+ assert(scaled_width != NULL);
+ assert(scaled_height != NULL);
+ {
+ int width = *scaled_width;
+ int height = *scaled_height;
+
+ // if width is unspecified, scale original proportionally to height ratio.
+ if (width == 0) {
+ width = (src_width * height + src_height / 2) / src_height;
}
+ // if height is unspecified, scale original proportionally to width ratio.
+ if (height == 0) {
+ height = (src_height * width + src_width / 2) / src_width;
+ }
+ // Check if the overall dimensions still make sense.
+ if (width <= 0 || height <= 0) {
+ return 0;
+ }
+
+ *scaled_width = width;
+ *scaled_height = height;
+ return 1;
}
}
-#undef MULT_FIX
-#undef WEBP_RESCALER_RFIX
-#undef WEBP_RESCALER_ONE
-#undef WEBP_RESCALER_FRAC
-#undef ROUNDER
-
//------------------------------------------------------------------------------
// all-in-one calls
diff --git a/src/3rdparty/libwebp/src/utils/rescaler.h b/src/3rdparty/libwebp/src/utils/rescaler.h
index 8244cfe..98b01a7 100644
--- a/src/3rdparty/libwebp/src/utils/rescaler.h
+++ b/src/3rdparty/libwebp/src/utils/rescaler.h
@@ -20,9 +20,15 @@ extern "C" {
#include "../webp/types.h"
+#define WEBP_RESCALER_RFIX 32 // fixed-point precision for multiplies
+#define WEBP_RESCALER_ONE (1ull << WEBP_RESCALER_RFIX)
+#define WEBP_RESCALER_FRAC(x, y) \
+ ((uint32_t)(((uint64_t)(x) << WEBP_RESCALER_RFIX) / (y)))
+
// Structure used for on-the-fly rescaling
typedef uint32_t rescaler_t; // type for side-buffer
-typedef struct {
+typedef struct WebPRescaler WebPRescaler;
+struct WebPRescaler {
int x_expand; // true if we're expanding in the x direction
int y_expand; // true if we're expanding in the y direction
int num_channels; // bytes to jump between pixels
@@ -38,7 +44,7 @@ typedef struct {
uint8_t* dst;
int dst_stride;
rescaler_t* irow, *frow; // work buffer
-} WebPRescaler;
+};
// Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
void WebPRescalerInit(WebPRescaler* const rescaler,
@@ -48,6 +54,14 @@ void WebPRescalerInit(WebPRescaler* const rescaler,
int num_channels,
rescaler_t* const work);
+// If either 'scaled_width' or 'scaled_height' (but not both) is 0 the value
+// will be calculated preserving the aspect ratio, otherwise the values are
+// left unmodified. Returns true on success, false if either value is 0 after
+// performing the scaling calculation.
+int WebPRescalerGetScaledDimensions(int src_width, int src_height,
+ int* const scaled_width,
+ int* const scaled_height);
+
// Returns the number of input lines needed next to produce one output line,
// considering that the maximum available input lines are 'max_num_lines'.
int WebPRescaleNeededLines(const WebPRescaler* const rescaler,
@@ -60,10 +74,6 @@ int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows,
// Export as many rows as possible. Return the numbers of rows written.
int WebPRescalerExport(WebPRescaler* const rescaler);
-void WebPRescalerImportRow(WebPRescaler* const wrk,
- const uint8_t* src);
-// Export one row (starting at x_out position) from rescaler.
-void WebPRescalerExportRow(WebPRescaler* const wrk);
// Return true if input is finished
static WEBP_INLINE
diff --git a/src/3rdparty/libwebp/src/utils/thread.c b/src/3rdparty/libwebp/src/utils/thread.c
index 264210b..93f7622 100644
--- a/src/3rdparty/libwebp/src/utils/thread.c
+++ b/src/3rdparty/libwebp/src/utils/thread.c
@@ -23,11 +23,26 @@
#include <windows.h>
typedef HANDLE pthread_t;
typedef CRITICAL_SECTION pthread_mutex_t;
+
+#if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater
+#define USE_WINDOWS_CONDITION_VARIABLE
+typedef CONDITION_VARIABLE pthread_cond_t;
+#else
typedef struct {
HANDLE waiting_sem_;
HANDLE received_sem_;
HANDLE signal_event_;
} pthread_cond_t;
+#endif // _WIN32_WINNT >= 0x600
+
+#ifndef WINAPI_FAMILY_PARTITION
+#define WINAPI_PARTITION_DESKTOP 1
+#define WINAPI_FAMILY_PARTITION(x) x
+#endif
+
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#define USE_CREATE_THREAD
+#endif
#else // !_WIN32
@@ -52,15 +67,29 @@ struct WebPWorkerImpl {
#define THREADFN unsigned int __stdcall
#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val)
+#if _WIN32_WINNT >= 0x0501 // Windows XP or greater
+#define WaitForSingleObject(obj, timeout) \
+ WaitForSingleObjectEx(obj, timeout, FALSE /*bAlertable*/)
+#endif
+
static int pthread_create(pthread_t* const thread, const void* attr,
unsigned int (__stdcall *start)(void*), void* arg) {
(void)attr;
+#ifdef USE_CREATE_THREAD
+ *thread = CreateThread(NULL, /* lpThreadAttributes */
+ 0, /* dwStackSize */
+ start,
+ arg,
+ 0, /* dwStackSize */
+ NULL); /* lpThreadId */
+#else
*thread = (pthread_t)_beginthreadex(NULL, /* void *security */
0, /* unsigned stack_size */
start,
arg,
0, /* unsigned initflag */
NULL); /* unsigned *thrdaddr */
+#endif
if (*thread == NULL) return 1;
SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
return 0;
@@ -75,7 +104,11 @@ static int pthread_join(pthread_t thread, void** value_ptr) {
// Mutex
static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) {
(void)mutexattr;
+#if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater
+ InitializeCriticalSectionEx(mutex, 0 /*dwSpinCount*/, 0 /*Flags*/);
+#else
InitializeCriticalSection(mutex);
+#endif
return 0;
}
@@ -97,14 +130,21 @@ static int pthread_mutex_destroy(pthread_mutex_t* const mutex) {
// Condition
static int pthread_cond_destroy(pthread_cond_t* const condition) {
int ok = 1;
+#ifdef USE_WINDOWS_CONDITION_VARIABLE
+ (void)condition;
+#else
ok &= (CloseHandle(condition->waiting_sem_) != 0);
ok &= (CloseHandle(condition->received_sem_) != 0);
ok &= (CloseHandle(condition->signal_event_) != 0);
+#endif
return !ok;
}
static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) {
(void)cond_attr;
+#ifdef USE_WINDOWS_CONDITION_VARIABLE
+ InitializeConditionVariable(condition);
+#else
condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
@@ -114,11 +154,15 @@ static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) {
pthread_cond_destroy(condition);
return 1;
}
+#endif
return 0;
}
static int pthread_cond_signal(pthread_cond_t* const condition) {
int ok = 1;
+#ifdef USE_WINDOWS_CONDITION_VARIABLE
+ WakeConditionVariable(condition);
+#else
if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) {
// a thread is waiting in pthread_cond_wait: allow it to be notified
ok = SetEvent(condition->signal_event_);
@@ -127,12 +171,16 @@ static int pthread_cond_signal(pthread_cond_t* const condition) {
ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) !=
WAIT_OBJECT_0);
}
+#endif
return !ok;
}
static int pthread_cond_wait(pthread_cond_t* const condition,
pthread_mutex_t* const mutex) {
int ok;
+#ifdef USE_WINDOWS_CONDITION_VARIABLE
+ ok = SleepConditionVariableCS(condition, mutex, INFINITE);
+#else
// note that there is a consumer available so the signal isn't dropped in
// pthread_cond_signal
if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL))
@@ -143,6 +191,7 @@ static int pthread_cond_wait(pthread_cond_t* const condition,
WAIT_OBJECT_0);
ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL);
pthread_mutex_lock(mutex);
+#endif
return !ok;
}
diff --git a/src/3rdparty/libwebp/src/utils/thread.h b/src/3rdparty/libwebp/src/utils/thread.h
index 7bd451b..8408311 100644
--- a/src/3rdparty/libwebp/src/utils/thread.h
+++ b/src/3rdparty/libwebp/src/utils/thread.h
@@ -79,7 +79,7 @@ typedef struct {
// is safe to free the corresponding memory after this call. This function is
// not thread-safe. Return false in case of invalid pointer or methods.
WEBP_EXTERN(int) WebPSetWorkerInterface(
- const WebPWorkerInterface* const interface);
+ const WebPWorkerInterface* const winterface);
// Retrieve the currently set thread worker interface.
WEBP_EXTERN(const WebPWorkerInterface*) WebPGetWorkerInterface(void);
diff --git a/src/3rdparty/libwebp/src/utils/utils.c b/src/3rdparty/libwebp/src/utils/utils.c
index 8ff7f12..d8e3093 100644
--- a/src/3rdparty/libwebp/src/utils/utils.c
+++ b/src/3rdparty/libwebp/src/utils/utils.c
@@ -12,6 +12,9 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
+#include <string.h> // for memcpy()
+#include "../webp/decode.h"
+#include "../webp/encode.h"
#include "./utils.h"
// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
@@ -47,7 +50,6 @@
#if defined(PRINT_MEM_INFO)
#include <stdio.h>
-#include <stdlib.h> // for abort()
static int num_malloc_calls = 0;
static int num_calloc_calls = 0;
@@ -208,4 +210,30 @@ void WebPSafeFree(void* const ptr) {
free(ptr);
}
+// Public API function.
+void WebPFree(void* ptr) {
+ free(ptr);
+}
+
+//------------------------------------------------------------------------------
+
+void WebPCopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride, int width, int height) {
+ assert(src != NULL && dst != NULL);
+ assert(src_stride >= width && dst_stride >= width);
+ while (height-- > 0) {
+ memcpy(dst, src, width);
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) {
+ assert(src != NULL && dst != NULL);
+ assert(src->width == dst->width && src->height == dst->height);
+ assert(src->use_argb && dst->use_argb);
+ WebPCopyPlane((uint8_t*)src->argb, 4 * src->argb_stride, (uint8_t*)dst->argb,
+ 4 * dst->argb_stride, 4 * src->width, src->height);
+}
+
//------------------------------------------------------------------------------
diff --git a/src/3rdparty/libwebp/src/utils/utils.h b/src/3rdparty/libwebp/src/utils/utils.h
index 0bbbcab..f506d66 100644
--- a/src/3rdparty/libwebp/src/utils/utils.h
+++ b/src/3rdparty/libwebp/src/utils/utils.h
@@ -15,6 +15,10 @@
#ifndef WEBP_UTILS_UTILS_H_
#define WEBP_UTILS_UTILS_H_
+#ifdef HAVE_CONFIG_H
+#include "../webp/config.h"
+#endif
+
#include <assert.h>
#include "../webp/types.h"
@@ -44,6 +48,32 @@ WEBP_EXTERN(void*) WebPSafeCalloc(uint64_t nmemb, size_t size);
WEBP_EXTERN(void) WebPSafeFree(void* const ptr);
//------------------------------------------------------------------------------
+// Alignment
+
+#define WEBP_ALIGN_CST 31
+#define WEBP_ALIGN(PTR) ((uintptr_t)((PTR) + WEBP_ALIGN_CST) & ~WEBP_ALIGN_CST)
+
+#if defined(WEBP_FORCE_ALIGNED)
+#include <string.h>
+// memcpy() is the safe way of moving potentially unaligned 32b memory.
+static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) {
+ uint32_t A;
+ memcpy(&A, (const int*)ptr, sizeof(A));
+ return A;
+}
+static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) {
+ memcpy(ptr, &val, sizeof(val));
+}
+#else
+static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) {
+ return *(const uint32_t*)ptr;
+}
+static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) {
+ *(uint32_t*)ptr = val;
+}
+#endif
+
+//------------------------------------------------------------------------------
// Reading/writing data.
// Read 16, 24 or 32 bits stored in little-endian order.
@@ -56,7 +86,7 @@ static WEBP_INLINE int GetLE24(const uint8_t* const data) {
}
static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) {
- return (uint32_t)GetLE16(data) | (GetLE16(data + 2) << 16);
+ return GetLE16(data) | ((uint32_t)GetLE16(data + 2) << 16);
}
// Store 16, 24 or 32 bits in little-endian order.
@@ -113,6 +143,21 @@ static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
#endif
//------------------------------------------------------------------------------
+// Pixel copying.
+
+struct WebPPicture;
+
+// Copy width x height pixels from 'src' to 'dst' honoring the strides.
+WEBP_EXTERN(void) WebPCopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride,
+ int width, int height);
+
+// Copy ARGB pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are
+// assumed to be already allocated and using ARGB data.
+WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src,
+ struct WebPPicture* const dst);
+
+//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"