summaryrefslogtreecommitdiffstats
path: root/media/libwebp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
commit8dd16259287f58f9273002717ec4d27e97127719 (patch)
tree3863e62a53829a84037444beab3abd4ed9dfc7d0 /media/libwebp
parentReleasing progress-linux version 126.0.1-1~progress7.99u1. (diff)
downloadfirefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz
firefox-8dd16259287f58f9273002717ec4d27e97127719.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'media/libwebp')
-rw-r--r--media/libwebp/AUTHORS7
-rw-r--r--media/libwebp/NEWS15
-rw-r--r--media/libwebp/README.md2
-rw-r--r--media/libwebp/moz.yaml2
-rw-r--r--media/libwebp/sharpyuv/sharpyuv.c163
-rw-r--r--media/libwebp/sharpyuv/sharpyuv.h85
-rw-r--r--media/libwebp/sharpyuv/sharpyuv_dsp.c4
-rw-r--r--media/libwebp/sharpyuv/sharpyuv_gamma.c310
-rw-r--r--media/libwebp/sharpyuv/sharpyuv_gamma.h11
-rw-r--r--media/libwebp/src/dec/alpha_dec.c61
-rw-r--r--media/libwebp/src/dec/buffer_dec.c2
-rw-r--r--media/libwebp/src/dec/idec_dec.c50
-rw-r--r--media/libwebp/src/dec/vp8_dec.c20
-rw-r--r--media/libwebp/src/dec/vp8_dec.h17
-rw-r--r--media/libwebp/src/dec/vp8i_dec.h15
-rw-r--r--media/libwebp/src/dec/vp8l_dec.c153
-rw-r--r--media/libwebp/src/dec/vp8li_dec.h28
-rw-r--r--media/libwebp/src/dec/webp_dec.c48
-rw-r--r--media/libwebp/src/dec/webpi_dec.h6
-rw-r--r--media/libwebp/src/demux/demux.c4
-rw-r--r--media/libwebp/src/dsp/alpha_processing_sse2.c41
-rw-r--r--media/libwebp/src/dsp/dec.c25
-rw-r--r--media/libwebp/src/dsp/dec_mips32.c56
-rw-r--r--media/libwebp/src/dsp/dec_mips_dsp_r2.c16
-rw-r--r--media/libwebp/src/dsp/dec_msa.c10
-rw-r--r--media/libwebp/src/dsp/dec_neon.c17
-rw-r--r--media/libwebp/src/dsp/dec_sse2.c34
-rw-r--r--media/libwebp/src/dsp/dsp.h5
-rw-r--r--media/libwebp/src/dsp/enc.c21
-rw-r--r--media/libwebp/src/dsp/enc_mips32.c20
-rw-r--r--media/libwebp/src/dsp/enc_mips_dsp_r2.c4
-rw-r--r--media/libwebp/src/dsp/enc_neon.c5
-rw-r--r--media/libwebp/src/dsp/filters.c35
-rw-r--r--media/libwebp/src/dsp/filters_mips_dsp_r2.c26
-rw-r--r--media/libwebp/src/dsp/filters_msa.c22
-rw-r--r--media/libwebp/src/dsp/filters_neon.c26
-rw-r--r--media/libwebp/src/dsp/filters_sse2.c26
-rw-r--r--media/libwebp/src/dsp/lossless.h6
-rw-r--r--media/libwebp/src/dsp/lossless_common.h6
-rw-r--r--media/libwebp/src/dsp/lossless_enc.c23
-rw-r--r--media/libwebp/src/dsp/lossless_enc_mips32.c14
-rw-r--r--media/libwebp/src/dsp/lossless_enc_sse41.c54
-rw-r--r--media/libwebp/src/dsp/lossless_neon.c6
-rw-r--r--media/libwebp/src/dsp/mips_macro.h42
-rw-r--r--media/libwebp/src/dsp/msa_macro.h32
-rw-r--r--media/libwebp/src/dsp/quant.h3
-rw-r--r--media/libwebp/src/dsp/rescaler_neon.c2
-rw-r--r--media/libwebp/src/dsp/upsampling_sse2.c12
-rw-r--r--media/libwebp/src/dsp/upsampling_sse41.c8
-rw-r--r--media/libwebp/src/enc/alpha_enc.c11
-rw-r--r--media/libwebp/src/enc/frame_enc.c4
-rw-r--r--media/libwebp/src/enc/histogram_enc.c36
-rw-r--r--media/libwebp/src/enc/picture_enc.c2
-rw-r--r--media/libwebp/src/enc/vp8i_enc.h4
-rw-r--r--media/libwebp/src/enc/vp8l_enc.c389
-rw-r--r--media/libwebp/src/enc/vp8li_enc.h4
-rw-r--r--media/libwebp/src/utils/huffman_utils.c5
-rw-r--r--media/libwebp/src/utils/huffman_utils.h11
-rw-r--r--media/libwebp/src/utils/moz.build1
-rw-r--r--media/libwebp/src/utils/palette.c402
-rw-r--r--media/libwebp/src/utils/palette.h60
-rw-r--r--media/libwebp/src/utils/utils.c66
-rw-r--r--media/libwebp/src/utils/utils.h3
-rw-r--r--media/libwebp/src/webp/decode.h114
-rw-r--r--media/libwebp/src/webp/demux.h46
-rw-r--r--media/libwebp/src/webp/encode.h83
-rw-r--r--media/libwebp/src/webp/mux.h91
-rw-r--r--media/libwebp/src/webp/mux_types.h3
-rw-r--r--media/libwebp/src/webp/types.h37
69 files changed, 1893 insertions, 1079 deletions
diff --git a/media/libwebp/AUTHORS b/media/libwebp/AUTHORS
index 8359b20da9..4cbe976608 100644
--- a/media/libwebp/AUTHORS
+++ b/media/libwebp/AUTHORS
@@ -2,6 +2,8 @@ Contributors:
- Aidan O'Loan (aidanol at gmail dot com)
- Alan Browning (browning at google dot com)
- Alexandru Ardelean (ardeleanalex at gmail dot com)
+- Anuraag Agrawal (anuraaga at gmail dot com)
+- Arthur Eubanks (aeubanks at google dot com)
- Brian Ledger (brianpl at google dot com)
- Charles Munger (clm at google dot com)
- Cheng Yi (cyi at google dot com)
@@ -19,6 +21,8 @@ Contributors:
- Jehan (jehan at girinstud dot io)
- Jeremy Maitin-Shepard (jbms at google dot com)
- Johann Koenig (johann dot koenig at duck dot com)
+- Jonathan Grant (jgrantinfotech at gmail dot com)
+- Jonliu1993 (13720414433 at 163 dot com)
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
- Jyrki Alakuijala (jyrki at google dot com)
- Konstantin Ivlev (tomskside at gmail dot com)
@@ -28,13 +32,16 @@ Contributors:
- Marcin Kowalczyk (qrczak at google dot com)
- Martin Olsson (mnemo at minimum dot se)
- Maryla Ustarroz-Calonge (maryla at google dot com)
+- Masahiro Hanada (hanada at atmark-techno dot com)
- Mikołaj Zalewski (mikolajz at google dot com)
- Mislav Bradac (mislavm at google dot com)
+- natewood (natewood at fb dot com)
- Nico Weber (thakis at chromium dot org)
- Noel Chromium (noel at chromium dot org)
- Nozomi Isozaki (nontan at pixiv dot co dot jp)
- Oliver Wolff (oliver dot wolff at qt dot io)
- Owen Rodley (orodley at google dot com)
+- Ozkan Sezer (sezeroz at gmail dot com)
- Parag Salasakar (img dot mips1 at gmail dot com)
- Pascal Massimino (pascal dot massimino at gmail dot com)
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
diff --git a/media/libwebp/NEWS b/media/libwebp/NEWS
index 47f8451482..8e40d8ead0 100644
--- a/media/libwebp/NEWS
+++ b/media/libwebp/NEWS
@@ -1,3 +1,18 @@
+- 4/12/2024: version 1.4.0
+ This is a binary compatible release.
+ * API changes:
+ - libwebpmux: WebPAnimEncoderSetChunk, WebPAnimEncoderGetChunk,
+ WebPAnimEncoderDeleteChunk
+ - libsharpyuv: SharpYuvOptionsInit, SharpYuvConvertWithOptions
+ - extras: SharpYuvEstimate420Risk
+ * further security related hardening in libwebp & examples
+ * some minor optimizations in the lossless encoder
+ * added WEBP_NODISCARD to report unused result warnings; enable with
+ -DWEBP_ENABLE_NODISCARD=1
+ * improvements and corrections in webp-container-spec.txt and
+ webp-lossless-bitstream-spec.txt (#611)
+ * miscellaneous warning, bug & build fixes (#615, #619, #632, #635)
+
- 9/13/2023: version 1.3.2
This is a binary compatible release.
* security fix for lossless decoder (chromium: #1479274, CVE-2023-4863)
diff --git a/media/libwebp/README.md b/media/libwebp/README.md
index a9f2c0e12b..ffffa538a8 100644
--- a/media/libwebp/README.md
+++ b/media/libwebp/README.md
@@ -7,7 +7,7 @@
\__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__
- \____/____/\_____/_____/____/v1.3.2
+ \____/____/\_____/_____/____/v1.4.0
```
WebP codec is a library to encode and decode images in WebP format. This package
diff --git a/media/libwebp/moz.yaml b/media/libwebp/moz.yaml
index f387be32ca..13467a63b9 100644
--- a/media/libwebp/moz.yaml
+++ b/media/libwebp/moz.yaml
@@ -11,7 +11,7 @@ origin:
url: "https://chromium.googlesource.com/webm/libwebp"
license: BSD-3-Clause
- release: v1.3.2 (2023-09-13T22:11:07Z).
+ release: v1.4.0 (2024-04-12T13:48:48-07:00).
revision: "v1.3.0"
diff --git a/media/libwebp/sharpyuv/sharpyuv.c b/media/libwebp/sharpyuv/sharpyuv.c
index a074564888..7cbf668fbb 100644
--- a/media/libwebp/sharpyuv/sharpyuv.c
+++ b/media/libwebp/sharpyuv/sharpyuv.c
@@ -75,41 +75,48 @@ static int RGBToGray(int64_t r, int64_t g, int64_t b) {
}
static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
- int rgb_bit_depth) {
+ int rgb_bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
- const uint32_t A = SharpYuvGammaToLinear(a, bit_depth);
- const uint32_t B = SharpYuvGammaToLinear(b, bit_depth);
- const uint32_t C = SharpYuvGammaToLinear(c, bit_depth);
- const uint32_t D = SharpYuvGammaToLinear(d, bit_depth);
- return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth);
+ const uint32_t A = SharpYuvGammaToLinear(a, bit_depth, transfer_type);
+ const uint32_t B = SharpYuvGammaToLinear(b, bit_depth, transfer_type);
+ const uint32_t C = SharpYuvGammaToLinear(c, bit_depth, transfer_type);
+ const uint32_t D = SharpYuvGammaToLinear(d, bit_depth, transfer_type);
+ return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth,
+ transfer_type);
}
static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
- int rgb_bit_depth) {
+ int rgb_bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
- int i;
- for (i = 0; i < w; ++i) {
- const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth);
- const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth);
- const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth);
+ int i = 0;
+ do {
+ const uint32_t R =
+ SharpYuvGammaToLinear(src[0 * w + i], bit_depth, transfer_type);
+ const uint32_t G =
+ SharpYuvGammaToLinear(src[1 * w + i], bit_depth, transfer_type);
+ const uint32_t B =
+ SharpYuvGammaToLinear(src[2 * w + i], bit_depth, transfer_type);
const uint32_t Y = RGBToGray(R, G, B);
- dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth);
- }
+ dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth, transfer_type);
+ } while (++i < w);
}
static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
- fixed_t* dst, int uv_w, int rgb_bit_depth) {
- int i;
- for (i = 0; i < uv_w; ++i) {
+ fixed_t* dst, int uv_w, int rgb_bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
+ int i = 0;
+ do {
const int r =
ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0],
- src2[0 * uv_w + 1], rgb_bit_depth);
+ src2[0 * uv_w + 1], rgb_bit_depth, transfer_type);
const int g =
ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0],
- src2[2 * uv_w + 1], rgb_bit_depth);
+ src2[2 * uv_w + 1], rgb_bit_depth, transfer_type);
const int b =
ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0],
- src2[4 * uv_w + 1], rgb_bit_depth);
+ src2[4 * uv_w + 1], rgb_bit_depth, transfer_type);
const int W = RGBToGray(r, g, b);
dst[0 * uv_w] = (fixed_t)(r - W);
dst[1 * uv_w] = (fixed_t)(g - W);
@@ -117,15 +124,15 @@ static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
dst += 1;
src1 += 2;
src2 += 2;
- }
+ } while (++i < uv_w);
}
static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
- int i;
+ int i = 0;
assert(w > 0);
- for (i = 0; i < w; ++i) {
+ do {
y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
- }
+ } while (++i < w);
}
//------------------------------------------------------------------------------
@@ -151,9 +158,9 @@ static void ImportOneRow(const uint8_t* const r_ptr,
// Convert the rgb_step from a number of bytes to a number of uint8_t or
// uint16_t values depending the bit depth.
const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step;
- int i;
+ int i = 0;
const int w = (pic_width + 1) & ~1;
- for (i = 0; i < pic_width; ++i) {
+ do {
const int off = i * step;
const int shift = GetPrecisionShift(rgb_bit_depth);
if (rgb_bit_depth == 8) {
@@ -165,7 +172,7 @@ static void ImportOneRow(const uint8_t* const r_ptr,
dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift);
dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift);
}
- }
+ } while (++i < pic_width);
if (pic_width & 1) { // replicate rightmost pixel
dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
@@ -233,8 +240,11 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
const int sfix = GetPrecisionShift(rgb_bit_depth);
const int yuv_max = (1 << yuv_bit_depth) - 1;
- for (best_uv = best_uv_base, j = 0; j < height; ++j) {
- for (i = 0; i < width; ++i) {
+ best_uv = best_uv_base;
+ j = 0;
+ do {
+ i = 0;
+ do {
const int off = (i >> 1);
const int W = best_y[i];
const int r = best_uv[off + 0 * uv_w] + W;
@@ -246,19 +256,22 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
} else {
((uint16_t*)y_ptr)[i] = clip(y, yuv_max);
}
- }
+ } while (++i < width);
best_y += w;
best_uv += (j & 1) * 3 * uv_w;
y_ptr += y_stride;
- }
- for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
- for (i = 0; i < uv_w; ++i) {
- const int off = i;
+ } while (++j < height);
+
+ best_uv = best_uv_base;
+ j = 0;
+ do {
+ i = 0;
+ do {
// Note r, g and b values here are off by W, but a constant offset on all
// 3 components doesn't change the value of u and v with a YCbCr matrix.
- const int r = best_uv[off + 0 * uv_w];
- const int g = best_uv[off + 1 * uv_w];
- const int b = best_uv[off + 2 * uv_w];
+ const int r = best_uv[i + 0 * uv_w];
+ const int g = best_uv[i + 1 * uv_w];
+ const int b = best_uv[i + 2 * uv_w];
const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix);
const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix);
if (yuv_bit_depth <= 8) {
@@ -268,11 +281,11 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
((uint16_t*)u_ptr)[i] = clip(u, yuv_max);
((uint16_t*)v_ptr)[i] = clip(v, yuv_max);
}
- }
+ } while (++i < uv_w);
best_uv += 3 * uv_w;
u_ptr += u_stride;
v_ptr += v_stride;
- }
+ } while (++j < uv_h);
return 1;
}
@@ -285,7 +298,7 @@ static void* SafeMalloc(uint64_t nmemb, size_t size) {
return malloc((size_t)total_size);
}
-#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T)))
+#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((uint64_t)(W) * (H), sizeof(T)))
static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
const uint8_t* b_ptr, int rgb_step, int rgb_stride,
@@ -293,12 +306,14 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
uint8_t* u_ptr, int u_stride, uint8_t* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int height,
- const SharpYuvConversionMatrix* yuv_matrix) {
+ const SharpYuvConversionMatrix* yuv_matrix,
+ SharpYuvTransferFunctionType transfer_type) {
// we expand the right/bottom border if needed
const int w = (width + 1) & ~1;
const int h = (height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
+ const int y_bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
uint64_t prev_diff_y_sum = ~0;
int j, iter;
@@ -346,9 +361,9 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
StoreGray(src1, best_y + 0, w);
StoreGray(src2, best_y + w, w);
- UpdateW(src1, target_y, w, rgb_bit_depth);
- UpdateW(src2, target_y + w, w, rgb_bit_depth);
- UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth);
+ UpdateW(src1, target_y, w, rgb_bit_depth, transfer_type);
+ UpdateW(src2, target_y + w, w, rgb_bit_depth, transfer_type);
+ UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth, transfer_type);
memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
best_y += 2 * w;
best_uv += 3 * uv_w;
@@ -369,7 +384,8 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
best_uv = best_uv_base;
target_y = target_y_base;
target_uv = target_uv_base;
- for (j = 0; j < h; j += 2) {
+ j = 0;
+ do {
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
{
@@ -380,21 +396,21 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
cur_uv = next_uv;
}
- UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth);
- UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth);
- UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth);
+ UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth, transfer_type);
+ UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth, transfer_type);
+ UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth, transfer_type);
// update two rows of Y and one row of RGB
diff_y_sum +=
- SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w,
- rgb_bit_depth + GetPrecisionShift(rgb_bit_depth));
+ SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w, y_bit_depth);
SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
- }
+ j += 2;
+ } while (j < h);
// test exit condition
if (iter > 0) {
if (diff_y_sum < diff_y_threshold) break;
@@ -418,6 +434,7 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
free(tmp_buffer);
return ok;
}
+
#undef SAFE_ALLOC
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
@@ -462,12 +479,42 @@ void SharpYuvInit(VP8CPUInfo cpu_info_func) {
UNLOCK_ACCESS_AND_RETURN;
}
-int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
- const void* b_ptr, int rgb_step, int rgb_stride,
- int rgb_bit_depth, void* y_ptr, int y_stride,
- void* u_ptr, int u_stride, void* v_ptr,
- int v_stride, int yuv_bit_depth, int width,
+int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr,
+ int rgb_step, int rgb_stride, int rgb_bit_depth,
+ void* y_ptr, int y_stride, void* u_ptr, int u_stride,
+ void* v_ptr, int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvConversionMatrix* yuv_matrix) {
+ SharpYuvOptions options;
+ options.yuv_matrix = yuv_matrix;
+ options.transfer_type = kSharpYuvTransferFunctionSrgb;
+ return SharpYuvConvertWithOptions(
+ r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride, rgb_bit_depth, y_ptr, y_stride,
+ u_ptr, u_stride, v_ptr, v_stride, yuv_bit_depth, width, height, &options);
+}
+
+int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix* yuv_matrix,
+ SharpYuvOptions* options, int version) {
+ const int major = (version >> 24);
+ const int minor = (version >> 16) & 0xff;
+ if (options == NULL || yuv_matrix == NULL ||
+ (major == SHARPYUV_VERSION_MAJOR && major == 0 &&
+ minor != SHARPYUV_VERSION_MINOR) ||
+ (major != SHARPYUV_VERSION_MAJOR)) {
+ return 0;
+ }
+ options->yuv_matrix = yuv_matrix;
+ options->transfer_type = kSharpYuvTransferFunctionSrgb;
+ return 1;
+}
+
+int SharpYuvConvertWithOptions(const void* r_ptr, const void* g_ptr,
+ const void* b_ptr, int rgb_step, int rgb_stride,
+ int rgb_bit_depth, void* y_ptr, int y_stride,
+ void* u_ptr, int u_stride, void* v_ptr,
+ int v_stride, int yuv_bit_depth, int width,
+ int height, const SharpYuvOptions* options) {
+ const SharpYuvConversionMatrix* yuv_matrix = options->yuv_matrix;
+ SharpYuvTransferFunctionType transfer_type = options->transfer_type;
SharpYuvConversionMatrix scaled_matrix;
const int rgb_max = (1 << rgb_bit_depth) - 1;
const int rgb_round = 1 << (rgb_bit_depth - 1);
@@ -486,7 +533,7 @@ int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) {
return 0;
}
- if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) {
+ if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride % 2 != 0)) {
// Step/stride should be even for uint16_t buffers.
return 0;
}
@@ -521,7 +568,7 @@ int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride,
rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride,
v_ptr, v_stride, yuv_bit_depth, width, height,
- &scaled_matrix);
+ &scaled_matrix, transfer_type);
}
//------------------------------------------------------------------------------
diff --git a/media/libwebp/sharpyuv/sharpyuv.h b/media/libwebp/sharpyuv/sharpyuv.h
index 7b9904d6f9..fe95891599 100644
--- a/media/libwebp/sharpyuv/sharpyuv.h
+++ b/media/libwebp/sharpyuv/sharpyuv.h
@@ -22,22 +22,37 @@ extern "C" {
#else
// This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds.
-#if defined(__GNUC__) && __GNUC__ >= 4
-#define SHARPYUV_EXTERN extern __attribute__((visibility("default")))
-#else
-#if defined(_MSC_VER) && defined(WEBP_DLL)
+#if defined(_WIN32) && defined(WEBP_DLL)
#define SHARPYUV_EXTERN __declspec(dllexport)
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define SHARPYUV_EXTERN extern __attribute__((visibility("default")))
#else
#define SHARPYUV_EXTERN extern
-#endif /* _MSC_VER && WEBP_DLL */
-#endif /* __GNUC__ >= 4 */
+#endif /* defined(_WIN32) && defined(WEBP_DLL) */
#endif /* WEBP_EXTERN */
#endif /* SHARPYUV_EXTERN */
+#ifndef SHARPYUV_INLINE
+#ifdef WEBP_INLINE
+#define SHARPYUV_INLINE WEBP_INLINE
+#else
+#ifndef _MSC_VER
+#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
+#define SHARPYUV_INLINE inline
+#else
+#define SHARPYUV_INLINE
+#endif
+#else
+#define SHARPYUV_INLINE __forceinline
+#endif /* _MSC_VER */
+#endif /* WEBP_INLINE */
+#endif /* SHARPYUV_INLINE */
+
// SharpYUV API version following the convention from semver.org
#define SHARPYUV_VERSION_MAJOR 0
-#define SHARPYUV_VERSION_MINOR 2
-#define SHARPYUV_VERSION_PATCH 1
+#define SHARPYUV_VERSION_MINOR 4
+#define SHARPYUV_VERSION_PATCH 0
// Version as a uint32_t. The major number is the high 8 bits.
// The minor number is the middle 8 bits. The patch number is the low 16 bits.
#define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \
@@ -61,6 +76,33 @@ typedef struct {
int rgb_to_v[4];
} SharpYuvConversionMatrix;
+typedef struct SharpYuvOptions SharpYuvOptions;
+
+// Enums for transfer functions, as defined in H.273,
+// https://www.itu.int/rec/T-REC-H.273-202107-I/en
+typedef enum SharpYuvTransferFunctionType {
+ // 0 is reserved
+ kSharpYuvTransferFunctionBt709 = 1,
+ // 2 is unspecified
+ // 3 is reserved
+ kSharpYuvTransferFunctionBt470M = 4,
+ kSharpYuvTransferFunctionBt470Bg = 5,
+ kSharpYuvTransferFunctionBt601 = 6,
+ kSharpYuvTransferFunctionSmpte240 = 7,
+ kSharpYuvTransferFunctionLinear = 8,
+ kSharpYuvTransferFunctionLog100 = 9,
+ kSharpYuvTransferFunctionLog100_Sqrt10 = 10,
+ kSharpYuvTransferFunctionIec61966 = 11,
+ kSharpYuvTransferFunctionBt1361 = 12,
+ kSharpYuvTransferFunctionSrgb = 13,
+ kSharpYuvTransferFunctionBt2020_10Bit = 14,
+ kSharpYuvTransferFunctionBt2020_12Bit = 15,
+ kSharpYuvTransferFunctionSmpte2084 = 16, // PQ
+ kSharpYuvTransferFunctionSmpte428 = 17,
+ kSharpYuvTransferFunctionHlg = 18,
+ kSharpYuvTransferFunctionNum
+} SharpYuvTransferFunctionType;
+
// Converts RGB to YUV420 using a downsampling algorithm that minimizes
// artefacts caused by chroma subsampling.
// This is slower than standard downsampling (averaging of 4 UV values).
@@ -85,6 +127,8 @@ typedef struct {
// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they
// should be multiples of 2.
// width, height: width and height of the image in pixels
+// This function calls SharpYuvConvertWithOptions with a default transfer
+// function of kSharpYuvTransferFunctionSrgb.
SHARPYUV_EXTERN int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
const void* b_ptr, int rgb_step,
int rgb_stride, int rgb_bit_depth,
@@ -93,6 +137,31 @@ SHARPYUV_EXTERN int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
int yuv_bit_depth, int width, int height,
const SharpYuvConversionMatrix* yuv_matrix);
+struct SharpYuvOptions {
+ // This matrix cannot be NULL and can be initialized by
+ // SharpYuvComputeConversionMatrix.
+ const SharpYuvConversionMatrix* yuv_matrix;
+ SharpYuvTransferFunctionType transfer_type;
+};
+
+// Internal, version-checked, entry point
+SHARPYUV_EXTERN int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix*,
+ SharpYuvOptions*, int);
+
+// Should always be called, to initialize a fresh SharpYuvOptions
+// structure before modification. SharpYuvOptionsInit() must have succeeded
+// before using the 'options' object.
+static SHARPYUV_INLINE int SharpYuvOptionsInit(
+ const SharpYuvConversionMatrix* yuv_matrix, SharpYuvOptions* options) {
+ return SharpYuvOptionsInitInternal(yuv_matrix, options, SHARPYUV_VERSION);
+}
+
+SHARPYUV_EXTERN int SharpYuvConvertWithOptions(
+ const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step,
+ int rgb_stride, int rgb_bit_depth, void* y_ptr, int y_stride, void* u_ptr,
+ int u_stride, void* v_ptr, int v_stride, int yuv_bit_depth, int width,
+ int height, const SharpYuvOptions* options);
+
// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
// support (it's rarely used in practice, especially for images).
diff --git a/media/libwebp/sharpyuv/sharpyuv_dsp.c b/media/libwebp/sharpyuv/sharpyuv_dsp.c
index 0da3efc0b8..94a40ec686 100644
--- a/media/libwebp/sharpyuv/sharpyuv_dsp.c
+++ b/media/libwebp/sharpyuv/sharpyuv_dsp.c
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include "sharpyuv/sharpyuv_cpu.h"
+#include "src/webp/types.h"
//-----------------------------------------------------------------------------
@@ -69,8 +70,7 @@ uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst,
int len);
void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out,
- int bit_depth);
+ const uint16_t* best_y, uint16_t* out, int bit_depth);
extern VP8CPUInfo SharpYuvGetCPUInfo;
extern void InitSharpYuvSSE2(void);
diff --git a/media/libwebp/sharpyuv/sharpyuv_gamma.c b/media/libwebp/sharpyuv/sharpyuv_gamma.c
index 20ab2da6bc..09028428ac 100644
--- a/media/libwebp/sharpyuv/sharpyuv_gamma.c
+++ b/media/libwebp/sharpyuv/sharpyuv_gamma.c
@@ -12,6 +12,7 @@
#include "sharpyuv/sharpyuv_gamma.h"
#include <assert.h>
+#include <float.h>
#include <math.h>
#include "src/webp/types.h"
@@ -97,7 +98,7 @@ static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab,
return result;
}
-uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
+static uint32_t ToLinearSrgb(uint16_t v, int bit_depth) {
const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth;
if (shift > 0) {
return kGammaToLinearTabS[v << shift];
@@ -105,9 +106,314 @@ uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0);
}
-uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth) {
+static uint16_t FromLinearSrgb(uint32_t value, int bit_depth) {
return FixedPointInterpolation(
value, kLinearToGammaTabS,
(GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS),
bit_depth - GAMMA_TO_LINEAR_BITS);
}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define CLAMP(x, low, high) \
+ (((x) < (low)) ? (low) : (((high) < (x)) ? (high) : (x)))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+static WEBP_INLINE float Roundf(float x) {
+ if (x < 0)
+ return (float)ceil((double)(x - 0.5f));
+ else
+ return (float)floor((double)(x + 0.5f));
+}
+
+static WEBP_INLINE float Powf(float base, float exp) {
+ return (float)pow((double)base, (double)exp);
+}
+
+static WEBP_INLINE float Log10f(float x) { return (float)log10((double)x); }
+
+static float ToLinear709(float gamma) {
+ if (gamma < 0.f) {
+ return 0.f;
+ } else if (gamma < 4.5f * 0.018053968510807f) {
+ return gamma / 4.5f;
+ } else if (gamma < 1.f) {
+ return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
+ }
+ return 1.f;
+}
+
+static float FromLinear709(float linear) {
+ if (linear < 0.f) {
+ return 0.f;
+ } else if (linear < 0.018053968510807f) {
+ return linear * 4.5f;
+ } else if (linear < 1.f) {
+ return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
+ }
+ return 1.f;
+}
+
+static float ToLinear470M(float gamma) {
+ return Powf(CLAMP(gamma, 0.f, 1.f), 2.2f);
+}
+
+static float FromLinear470M(float linear) {
+ return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.2f);
+}
+
+static float ToLinear470Bg(float gamma) {
+ return Powf(CLAMP(gamma, 0.f, 1.f), 2.8f);
+}
+
+static float FromLinear470Bg(float linear) {
+ return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.8f);
+}
+
+static float ToLinearSmpte240(float gamma) {
+ if (gamma < 0.f) {
+ return 0.f;
+ } else if (gamma < 4.f * 0.022821585529445f) {
+ return gamma / 4.f;
+ } else if (gamma < 1.f) {
+ return Powf((gamma + 0.111572195921731f) / 1.111572195921731f, 1.f / 0.45f);
+ }
+ return 1.f;
+}
+
+static float FromLinearSmpte240(float linear) {
+ if (linear < 0.f) {
+ return 0.f;
+ } else if (linear < 0.022821585529445f) {
+ return linear * 4.f;
+ } else if (linear < 1.f) {
+ return 1.111572195921731f * Powf(linear, 0.45f) - 0.111572195921731f;
+ }
+ return 1.f;
+}
+
+static float ToLinearLog100(float gamma) {
+ // The function is non-bijective so choose the middle of [0, 0.01].
+ const float mid_interval = 0.01f / 2.f;
+ return (gamma <= 0.0f) ? mid_interval
+ : Powf(10.0f, 2.f * (MIN(gamma, 1.f) - 1.0f));
+}
+
+static float FromLinearLog100(float linear) {
+ return (linear < 0.01f) ? 0.0f : 1.0f + Log10f(MIN(linear, 1.f)) / 2.0f;
+}
+
+static float ToLinearLog100Sqrt10(float gamma) {
+ // The function is non-bijective so choose the middle of [0, 0.00316227766f[.
+ const float mid_interval = 0.00316227766f / 2.f;
+ return (gamma <= 0.0f) ? mid_interval
+ : Powf(10.0f, 2.5f * (MIN(gamma, 1.f) - 1.0f));
+}
+
+static float FromLinearLog100Sqrt10(float linear) {
+ return (linear < 0.00316227766f) ? 0.0f
+ : 1.0f + Log10f(MIN(linear, 1.f)) / 2.5f;
+}
+
+static float ToLinearIec61966(float gamma) {
+ if (gamma <= -4.5f * 0.018053968510807f) {
+ return Powf((-gamma + 0.09929682680944f) / -1.09929682680944f, 1.f / 0.45f);
+ } else if (gamma < 4.5f * 0.018053968510807f) {
+ return gamma / 4.5f;
+ }
+ return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
+}
+
+static float FromLinearIec61966(float linear) {
+ if (linear <= -0.018053968510807f) {
+ return -1.09929682680944f * Powf(-linear, 0.45f) + 0.09929682680944f;
+ } else if (linear < 0.018053968510807f) {
+ return linear * 4.5f;
+ }
+ return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
+}
+
+static float ToLinearBt1361(float gamma) {
+ if (gamma < -0.25f) {
+ return -0.25f;
+ } else if (gamma < 0.f) {
+ return Powf((gamma - 0.02482420670236f) / -0.27482420670236f, 1.f / 0.45f) /
+ -4.f;
+ } else if (gamma < 4.5f * 0.018053968510807f) {
+ return gamma / 4.5f;
+ } else if (gamma < 1.f) {
+ return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
+ }
+ return 1.f;
+}
+
+static float FromLinearBt1361(float linear) {
+ if (linear < -0.25f) {
+ return -0.25f;
+ } else if (linear < 0.f) {
+ return -0.27482420670236f * Powf(-4.f * linear, 0.45f) + 0.02482420670236f;
+ } else if (linear < 0.018053968510807f) {
+ return linear * 4.5f;
+ } else if (linear < 1.f) {
+ return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
+ }
+ return 1.f;
+}
+
+static float ToLinearPq(float gamma) {
+ if (gamma > 0.f) {
+ const float pow_gamma = Powf(gamma, 32.f / 2523.f);
+ const float num = MAX(pow_gamma - 107.f / 128.f, 0.0f);
+ const float den = MAX(2413.f / 128.f - 2392.f / 128.f * pow_gamma, FLT_MIN);
+ return Powf(num / den, 4096.f / 653.f);
+ }
+ return 0.f;
+}
+
+static float FromLinearPq(float linear) {
+ if (linear > 0.f) {
+ const float pow_linear = Powf(linear, 653.f / 4096.f);
+ const float num = 107.f / 128.f + 2413.f / 128.f * pow_linear;
+ const float den = 1.0f + 2392.f / 128.f * pow_linear;
+ return Powf(num / den, 2523.f / 32.f);
+ }
+ return 0.f;
+}
+
+static float ToLinearSmpte428(float gamma) {
+ return Powf(MAX(gamma, 0.f), 2.6f) / 0.91655527974030934f;
+}
+
+static float FromLinearSmpte428(float linear) {
+ return Powf(0.91655527974030934f * MAX(linear, 0.f), 1.f / 2.6f);
+}
+
+// Conversion in BT.2100 requires RGB info. Simplify to gamma correction here.
+static float ToLinearHlg(float gamma) {
+ if (gamma < 0.f) {
+ return 0.f;
+ } else if (gamma <= 0.5f) {
+ return Powf((gamma * gamma) * (1.f / 3.f), 1.2f);
+ }
+ return Powf((expf((gamma - 0.55991073f) / 0.17883277f) + 0.28466892f) / 12.0f,
+ 1.2f);
+}
+
+static float FromLinearHlg(float linear) {
+ linear = Powf(linear, 1.f / 1.2f);
+ if (linear < 0.f) {
+ return 0.f;
+ } else if (linear <= (1.f / 12.f)) {
+ return sqrtf(3.f * linear);
+ }
+ return 0.17883277f * logf(12.f * linear - 0.28466892f) + 0.55991073f;
+}
+
+uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
+ float v_float, linear;
+ if (transfer_type == kSharpYuvTransferFunctionSrgb) {
+ return ToLinearSrgb(v, bit_depth);
+ }
+ v_float = (float)v / ((1 << bit_depth) - 1);
+ switch (transfer_type) {
+ case kSharpYuvTransferFunctionBt709:
+ case kSharpYuvTransferFunctionBt601:
+ case kSharpYuvTransferFunctionBt2020_10Bit:
+ case kSharpYuvTransferFunctionBt2020_12Bit:
+ linear = ToLinear709(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt470M:
+ linear = ToLinear470M(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt470Bg:
+ linear = ToLinear470Bg(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte240:
+ linear = ToLinearSmpte240(v_float);
+ break;
+ case kSharpYuvTransferFunctionLinear:
+ return v;
+ case kSharpYuvTransferFunctionLog100:
+ linear = ToLinearLog100(v_float);
+ break;
+ case kSharpYuvTransferFunctionLog100_Sqrt10:
+ linear = ToLinearLog100Sqrt10(v_float);
+ break;
+ case kSharpYuvTransferFunctionIec61966:
+ linear = ToLinearIec61966(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt1361:
+ linear = ToLinearBt1361(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte2084:
+ linear = ToLinearPq(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte428:
+ linear = ToLinearSmpte428(v_float);
+ break;
+ case kSharpYuvTransferFunctionHlg:
+ linear = ToLinearHlg(v_float);
+ break;
+ default:
+ assert(0);
+ linear = 0;
+ break;
+ }
+ return (uint32_t)Roundf(linear * ((1 << 16) - 1));
+}
+
+uint16_t SharpYuvLinearToGamma(uint32_t v, int bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
+ float v_float, linear;
+ if (transfer_type == kSharpYuvTransferFunctionSrgb) {
+ return FromLinearSrgb(v, bit_depth);
+ }
+ v_float = (float)v / ((1 << 16) - 1);
+ switch (transfer_type) {
+ case kSharpYuvTransferFunctionBt709:
+ case kSharpYuvTransferFunctionBt601:
+ case kSharpYuvTransferFunctionBt2020_10Bit:
+ case kSharpYuvTransferFunctionBt2020_12Bit:
+ linear = FromLinear709(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt470M:
+ linear = FromLinear470M(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt470Bg:
+ linear = FromLinear470Bg(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte240:
+ linear = FromLinearSmpte240(v_float);
+ break;
+ case kSharpYuvTransferFunctionLinear:
+ return v;
+ case kSharpYuvTransferFunctionLog100:
+ linear = FromLinearLog100(v_float);
+ break;
+ case kSharpYuvTransferFunctionLog100_Sqrt10:
+ linear = FromLinearLog100Sqrt10(v_float);
+ break;
+ case kSharpYuvTransferFunctionIec61966:
+ linear = FromLinearIec61966(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt1361:
+ linear = FromLinearBt1361(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte2084:
+ linear = FromLinearPq(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte428:
+ linear = FromLinearSmpte428(v_float);
+ break;
+ case kSharpYuvTransferFunctionHlg:
+ linear = FromLinearHlg(v_float);
+ break;
+ default:
+ assert(0);
+ linear = 0;
+ break;
+ }
+ return (uint16_t)Roundf(linear * ((1 << bit_depth) - 1));
+}
diff --git a/media/libwebp/sharpyuv/sharpyuv_gamma.h b/media/libwebp/sharpyuv/sharpyuv_gamma.h
index d13aff59e1..b8ba7e9870 100644
--- a/media/libwebp/sharpyuv/sharpyuv_gamma.h
+++ b/media/libwebp/sharpyuv/sharpyuv_gamma.h
@@ -12,6 +12,7 @@
#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
+#include "sharpyuv/sharpyuv.h"
#include "src/webp/types.h"
#ifdef __cplusplus
@@ -22,11 +23,13 @@ extern "C" {
// SharpYuvGammaToLinear or SharpYuvLinearToGamma.
void SharpYuvInitGammaTables(void);
-// Converts a gamma color value on 'bit_depth' bits to a 16 bit linear value.
-uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth);
+// Converts a 'bit_depth'-bit gamma color value to a 16-bit linear value.
+uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth,
+ SharpYuvTransferFunctionType transfer_type);
-// Converts a 16 bit linear color value to a gamma value on 'bit_depth' bits.
-uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth);
+// Converts a 16-bit linear color value to a 'bit_depth'-bit gamma value.
+uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth,
+ SharpYuvTransferFunctionType transfer_type);
#ifdef __cplusplus
} // extern "C"
diff --git a/media/libwebp/src/dec/alpha_dec.c b/media/libwebp/src/dec/alpha_dec.c
index 0b93a30b32..b6c874fb84 100644
--- a/media/libwebp/src/dec/alpha_dec.c
+++ b/media/libwebp/src/dec/alpha_dec.c
@@ -13,18 +13,20 @@
#include <stdlib.h>
#include "src/dec/alphai_dec.h"
+#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
#include "src/dsp/dsp.h"
#include "src/utils/quant_levels_dec_utils.h"
#include "src/utils/utils.h"
#include "src/webp/format_constants.h"
+#include "src/webp/types.h"
//------------------------------------------------------------------------------
// ALPHDecoder object.
// Allocates a new alpha decoder instance.
-static ALPHDecoder* ALPHNew(void) {
+WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
return dec;
}
@@ -45,9 +47,9 @@ static void ALPHDelete(ALPHDecoder* const dec) {
// header for alpha data stored using lossless compression.
// Returns false in case of error in alpha header (data too short, invalid
// compression method or filter, error in lossless header data etc).
-static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
- size_t data_size, const VP8Io* const src_io,
- uint8_t* output) {
+WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
+ size_t data_size, const VP8Io* const src_io,
+ uint8_t* output) {
int ok = 0;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
@@ -79,7 +81,9 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
}
// Copy the necessary parameters from src_io to io
- VP8InitIo(io);
+ if (!VP8InitIo(io)) {
+ return 0;
+ }
WebPInitCustomIo(NULL, io);
io->opaque = dec;
io->width = src_io->width;
@@ -107,7 +111,8 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
// starting from row number 'row'. It assumes that rows up to (row - 1) have
// already been decoded.
// Returns false in case of bitstream error.
-static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
+WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,
+ int num_rows) {
ALPHDecoder* const alph_dec = dec->alph_dec_;
const int width = alph_dec->width_;
const int height = alph_dec->io_.crop_bottom;
@@ -117,21 +122,12 @@ static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width;
uint8_t* dst = dec->alpha_plane_ + row * width;
assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]);
- if (alph_dec->filter_ != WEBP_FILTER_NONE) {
- assert(WebPUnfilters[alph_dec->filter_] != NULL);
- for (y = 0; y < num_rows; ++y) {
- WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);
- prev_line = dst;
- dst += width;
- deltas += width;
- }
- } else {
- for (y = 0; y < num_rows; ++y) {
- memcpy(dst, deltas, width * sizeof(*dst));
- prev_line = dst;
- dst += width;
- deltas += width;
- }
+ assert(WebPUnfilters[alph_dec->filter_] != NULL);
+ for (y = 0; y < num_rows; ++y) {
+ WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);
+ prev_line = dst;
+ dst += width;
+ deltas += width;
}
dec->alpha_prev_line_ = prev_line;
} else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
@@ -147,7 +143,8 @@ static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
return 1;
}
-static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
+WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,
+ const VP8Io* const io) {
const int stride = io->width;
const int height = io->crop_bottom;
const uint64_t alpha_size = (uint64_t)stride * height;
@@ -155,7 +152,8 @@ static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
dec->alpha_plane_mem_ =
(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_));
if (dec->alpha_plane_mem_ == NULL) {
- return 0;
+ return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
+ "Alpha decoder initialization failed.");
}
dec->alpha_plane_ = dec->alpha_plane_mem_;
dec->alpha_prev_line_ = NULL;
@@ -174,9 +172,9 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
//------------------------------------------------------------------------------
// Main entry point.
-const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
- const VP8Io* const io,
- int row, int num_rows) {
+WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
+ const VP8Io* const io,
+ int row, int num_rows) {
const int width = io->width;
const int height = io->crop_bottom;
@@ -189,10 +187,19 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
if (!dec->is_alpha_decoded_) {
if (dec->alph_dec_ == NULL) { // Initialize decoder.
dec->alph_dec_ = ALPHNew();
- if (dec->alph_dec_ == NULL) return NULL;
+ if (dec->alph_dec_ == NULL) {
+ VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
+ "Alpha decoder initialization failed.");
+ return NULL;
+ }
if (!AllocateAlphaPlane(dec, io)) goto Error;
if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
io, dec->alpha_plane_)) {
+ VP8LDecoder* const vp8l_dec = dec->alph_dec_->vp8l_dec_;
+ VP8SetError(dec,
+ (vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY
+ : vp8l_dec->status_,
+ "Alpha decoder initialization failed.");
goto Error;
}
// if we allowed use of alpha dithering, check whether it's needed at all
diff --git a/media/libwebp/src/dec/buffer_dec.c b/media/libwebp/src/dec/buffer_dec.c
index 4786cf0ddb..11ce76f19e 100644
--- a/media/libwebp/src/dec/buffer_dec.c
+++ b/media/libwebp/src/dec/buffer_dec.c
@@ -75,7 +75,7 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
const int stride = abs(buf->stride);
const uint64_t size =
- MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
+ MIN_BUFFER_SIZE((uint64_t)width * kModeBpp[mode], height, stride);
ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL);
diff --git a/media/libwebp/src/dec/idec_dec.c b/media/libwebp/src/dec/idec_dec.c
index 9035df5659..ad042a1ffc 100644
--- a/media/libwebp/src/dec/idec_dec.c
+++ b/media/libwebp/src/dec/idec_dec.c
@@ -17,8 +17,10 @@
#include "src/dec/alphai_dec.h"
#include "src/dec/webpi_dec.h"
+#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/utils/utils.h"
+#include "src/webp/decode.h"
// In append mode, buffer allocations increase as multiples of this value.
// Needs to be a power of 2.
@@ -161,8 +163,9 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
// Appends data to the end of MemBuffer->buf_. It expands the allocated memory
// size if required and also updates VP8BitReader's if new memory is allocated.
-static int AppendToMemBuffer(WebPIDecoder* const idec,
- const uint8_t* const data, size_t data_size) {
+WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec,
+ const uint8_t* const data,
+ size_t data_size) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
MemBuffer* const mem = &idec->mem_;
const int need_compressed_alpha = NeedCompressedAlpha(idec);
@@ -203,8 +206,9 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
return 1;
}
-static int RemapMemBuffer(WebPIDecoder* const idec,
- const uint8_t* const data, size_t data_size) {
+WEBP_NODISCARD static int RemapMemBuffer(WebPIDecoder* const idec,
+ const uint8_t* const data,
+ size_t data_size) {
MemBuffer* const mem = &idec->mem_;
const uint8_t* const old_buf = mem->buf_;
const uint8_t* const old_start =
@@ -237,7 +241,8 @@ static void ClearMemBuffer(MemBuffer* const mem) {
}
}
-static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
+WEBP_NODISCARD static int CheckMemBufferMode(MemBuffer* const mem,
+ MemBufferMode expected) {
if (mem->mode_ == MEM_MODE_NONE) {
mem->mode_ = expected; // switch to the expected mode
} else if (mem->mode_ != expected) {
@@ -248,7 +253,7 @@ static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
}
// To be called last.
-static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
+WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
const WebPDecoderOptions* const options = idec->params_.options;
WebPDecBuffer* const output = idec->params_.output;
@@ -258,8 +263,10 @@ static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
if (status != VP8_STATUS_OK) return status;
}
if (idec->final_output_ != NULL) {
- WebPCopyDecBufferPixels(output, idec->final_output_); // do the slow-copy
+ const VP8StatusCode status = WebPCopyDecBufferPixels(
+ output, idec->final_output_); // do the slow-copy
WebPFreeDecBuffer(&idec->output_);
+ if (status != VP8_STATUS_OK) return status;
*output = *idec->final_output_;
idec->final_output_ = NULL;
}
@@ -288,7 +295,7 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) {
// Synchronize the thread, clean-up and check for errors.
- VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
+ (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
}
idec->state_ = STATE_ERROR;
return error;
@@ -329,6 +336,7 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
if (dec == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
}
+ dec->incremental_ = 1;
idec->dec_ = dec;
dec->alpha_data_ = headers.alpha_data;
dec->alpha_data_size_ = headers.alpha_data_size;
@@ -601,8 +609,9 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
//------------------------------------------------------------------------------
// Internal constructor
-static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer,
- const WebPBitstreamFeatures* const features) {
+WEBP_NODISCARD static WebPIDecoder* NewDecoder(
+ WebPDecBuffer* const output_buffer,
+ const WebPBitstreamFeatures* const features) {
WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
if (idec == NULL) {
return NULL;
@@ -614,8 +623,10 @@ static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer,
idec->last_mb_y_ = -1;
InitMemBuffer(&idec->mem_);
- WebPInitDecBuffer(&idec->output_);
- VP8InitIo(&idec->io_);
+ if (!WebPInitDecBuffer(&idec->output_) || !VP8InitIo(&idec->io_)) {
+ WebPSafeFree(idec);
+ return NULL;
+ }
WebPResetDecParams(&idec->params_);
if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) {
@@ -674,7 +685,8 @@ void WebPIDelete(WebPIDecoder* idec) {
if (!idec->is_lossless_) {
if (idec->state_ == STATE_VP8_DATA) {
// Synchronize the thread, clean-up and check for errors.
- VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
+ // TODO(vrabaud) do we care about the return result?
+ (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
}
VP8Delete((VP8Decoder*)idec->dec_);
} else {
@@ -851,8 +863,8 @@ const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
return src;
}
-uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
- int* width, int* height, int* stride) {
+WEBP_NODISCARD uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
+ int* width, int* height, int* stride) {
const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (src == NULL) return NULL;
if (src->colorspace >= MODE_YUV) {
@@ -867,10 +879,10 @@ uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
return src->u.RGBA.rgba;
}
-uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
- uint8_t** u, uint8_t** v, uint8_t** a,
- int* width, int* height,
- int* stride, int* uv_stride, int* a_stride) {
+WEBP_NODISCARD uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
+ uint8_t** u, uint8_t** v, uint8_t** a,
+ int* width, int* height, int* stride,
+ int* uv_stride, int* a_stride) {
const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (src == NULL) return NULL;
if (src->colorspace < MODE_YUV) {
diff --git a/media/libwebp/src/dec/vp8_dec.c b/media/libwebp/src/dec/vp8_dec.c
index 20b92e84c4..2ee8900605 100644
--- a/media/libwebp/src/dec/vp8_dec.c
+++ b/media/libwebp/src/dec/vp8_dec.c
@@ -86,6 +86,8 @@ void VP8Delete(VP8Decoder* const dec) {
int VP8SetError(VP8Decoder* const dec,
VP8StatusCode error, const char* const msg) {
+ // VP8_STATUS_SUSPENDED is only meaningful in incremental decoding.
+ assert(dec->incremental_ || error != VP8_STATUS_SUSPENDED);
// The oldest error reported takes precedence over the new one.
if (dec->status_ == VP8_STATUS_OK) {
dec->status_ = error;
@@ -190,12 +192,12 @@ static int ParseSegmentHeader(VP8BitReader* br,
}
// Paragraph 9.5
-// This function returns VP8_STATUS_SUSPENDED if we don't have all the
-// necessary data in 'buf'.
-// This case is not necessarily an error (for incremental decoding).
-// Still, no bitreader is ever initialized to make it possible to read
-// unavailable memory.
-// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA
+// If we don't have all the necessary data in 'buf', this function returns
+// VP8_STATUS_SUSPENDED in incremental decoding, VP8_STATUS_NOT_ENOUGH_DATA
+// otherwise.
+// In incremental decoding, this case is not necessarily an error. Still, no
+// bitreader is ever initialized to make it possible to read unavailable memory.
+// If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA
// is returned, and this is an unrecoverable error.
// If the partitions were positioned ok, VP8_STATUS_OK is returned.
static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
@@ -225,8 +227,10 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
sz += 3;
}
VP8InitBitReader(dec->parts_ + last_part, part_start, size_left);
- return (part_start < buf_end) ? VP8_STATUS_OK :
- VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data
+ if (part_start < buf_end) return VP8_STATUS_OK;
+ return dec->incremental_
+ ? VP8_STATUS_SUSPENDED // Init is ok, but there's not enough data
+ : VP8_STATUS_NOT_ENOUGH_DATA;
}
// Paragraph 9.4
diff --git a/media/libwebp/src/dec/vp8_dec.h b/media/libwebp/src/dec/vp8_dec.h
index a05405df72..91fe104093 100644
--- a/media/libwebp/src/dec/vp8_dec.h
+++ b/media/libwebp/src/dec/vp8_dec.h
@@ -15,6 +15,7 @@
#define WEBP_DEC_VP8_DEC_H_
#include "src/webp/decode.h"
+#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@@ -108,16 +109,14 @@ struct VP8Io {
};
// Internal, version-checked, entry point
-int VP8InitIoInternal(VP8Io* const, int);
+WEBP_NODISCARD int VP8InitIoInternal(VP8Io* const, int);
// Set the custom IO function pointers and user-data. The setter for IO hooks
// should be called before initiating incremental decoding. Returns true if
// WebPIDecoder object is successfully modified, false otherwise.
-int WebPISetIOHooks(WebPIDecoder* const idec,
- VP8IoPutHook put,
- VP8IoSetupHook setup,
- VP8IoTeardownHook teardown,
- void* user_data);
+WEBP_NODISCARD int WebPISetIOHooks(WebPIDecoder* const idec, VP8IoPutHook put,
+ VP8IoSetupHook setup,
+ VP8IoTeardownHook teardown, void* user_data);
// Main decoding object. This is an opaque structure.
typedef struct VP8Decoder VP8Decoder;
@@ -128,17 +127,17 @@ VP8Decoder* VP8New(void);
// Must be called to make sure 'io' is initialized properly.
// Returns false in case of version mismatch. Upon such failure, no other
// decoding function should be called (VP8Decode, VP8GetHeaders, ...)
-static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
+WEBP_NODISCARD static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
}
// Decode the VP8 frame header. Returns true if ok.
// Note: 'io->data' must be pointing to the start of the VP8 frame header.
-int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
// Returns false in case of error.
-int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
// Return current status of the decoder:
VP8StatusCode VP8Status(VP8Decoder* const dec);
diff --git a/media/libwebp/src/dec/vp8i_dec.h b/media/libwebp/src/dec/vp8i_dec.h
index 7929fd7506..cb21d475ae 100644
--- a/media/libwebp/src/dec/vp8i_dec.h
+++ b/media/libwebp/src/dec/vp8i_dec.h
@@ -21,6 +21,7 @@
#include "src/utils/random_utils.h"
#include "src/utils/thread_utils.h"
#include "src/dsp/dsp.h"
+#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@@ -31,8 +32,8 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
-#define DEC_MIN_VERSION 3
-#define DEC_REV_VERSION 2
+#define DEC_MIN_VERSION 4
+#define DEC_REV_VERSION 0
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
@@ -186,6 +187,7 @@ struct VP8Decoder {
// Main data source
VP8BitReader br_;
+ int incremental_; // if true, incremental decoding is expected
// headers
VP8FrameHeader frm_hdr_;
@@ -281,7 +283,7 @@ int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec);
void VP8ParseQuant(VP8Decoder* const dec);
// in frame.c
-int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
// Call io->setup() and finish setting up scan parameters.
// After this call returns, one must always call VP8ExitCritical() with the
// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK
@@ -289,7 +291,7 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
// Must always be called in pair with VP8EnterCritical().
// Returns false in case of error.
-int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
// Return the multi-threading method to use (0=off), depending
// on options and bitstream size. Only for lossy decoding.
int VP8GetThreadMethod(const WebPDecoderOptions* const options,
@@ -299,11 +301,12 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
void VP8InitDithering(const WebPDecoderOptions* const options,
VP8Decoder* const dec);
// Process the last decoded row (filtering + output).
-int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
// To be called at the start of a new scanline, to initialize predictors.
void VP8InitScanline(VP8Decoder* const dec);
// Decode one macroblock. Returns false if there is not enough data.
-int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br);
+WEBP_NODISCARD int VP8DecodeMB(VP8Decoder* const dec,
+ VP8BitReader* const token_br);
// in alpha.c
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
diff --git a/media/libwebp/src/dec/vp8l_dec.c b/media/libwebp/src/dec/vp8l_dec.c
index 1a6c0a8980..11c00ea964 100644
--- a/media/libwebp/src/dec/vp8l_dec.c
+++ b/media/libwebp/src/dec/vp8l_dec.c
@@ -12,6 +12,7 @@
// Authors: Vikas Arora (vikaas.arora@gmail.com)
// Jyrki Alakuijala (jyrki@google.com)
+#include <assert.h>
#include <stdlib.h>
#include "src/dec/alphai_dec.h"
@@ -101,6 +102,14 @@ static const uint16_t kTableSize[12] = {
FIXED_TABLE_SIZE + 2704
};
+static int VP8LSetError(VP8LDecoder* const dec, VP8StatusCode error) {
+ // The oldest error reported takes precedence over the new one.
+ if (dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED) {
+ dec->status_ = error;
+ }
+ return 0;
+}
+
static int DecodeImageStream(int xsize, int ysize,
int is_level0,
VP8LDecoder* const dec,
@@ -301,7 +310,7 @@ static int ReadHuffmanCodeLengths(
End:
VP8LHuffmanTablesDeallocate(&tables);
- if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ if (!ok) return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
return ok;
}
@@ -333,10 +342,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
int i;
int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
const int num_codes = VP8LReadBits(br, 4) + 4;
- if (num_codes > NUM_CODE_LENGTH_CODES) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
- }
+ assert(num_codes <= NUM_CODE_LENGTH_CODES);
for (i = 0; i < num_codes; ++i) {
code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
@@ -351,15 +357,14 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
code_lengths, alphabet_size);
}
if (!ok || size == 0) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
}
return size;
}
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int color_cache_bits, int allow_recursion) {
- int i, j;
+ int i;
VP8LBitReader* const br = &dec->br_;
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
@@ -367,9 +372,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
HuffmanTables* huffman_tables = &hdr->huffman_tables_;
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;
@@ -383,7 +385,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
const int huffman_pixs = huffman_xsize * huffman_ysize;
- if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
+ if (!DecodeImageStream(huffman_xsize, huffman_ysize, /*is_level0=*/0, dec,
&huffman_image)) {
goto Error;
}
@@ -407,7 +409,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
// values [0, num_htree_groups)
mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
if (mapping == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Error;
}
// -1 means a value is unmapped, and therefore unused in the Huffman
@@ -426,25 +428,52 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
if (br->eos_) goto Error;
- // Find maximum alphabet size for the htree group.
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- int alphabet_size = kAlphabetSize[j];
- if (j == 0 && color_cache_bits > 0) {
- alphabet_size += 1 << color_cache_bits;
- }
- if (max_alphabet_size < alphabet_size) {
- max_alphabet_size = alphabet_size;
- }
+ if (!ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups,
+ num_htree_groups_max, mapping, dec,
+ huffman_tables, &htree_groups)) {
+ goto Error;
}
+ ok = 1;
- code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
- sizeof(*code_lengths));
- htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+ // All OK. Finalize pointers.
+ hdr->huffman_image_ = huffman_image;
+ hdr->num_htree_groups_ = num_htree_groups;
+ hdr->htree_groups_ = htree_groups;
- if (htree_groups == NULL || code_lengths == NULL ||
+ Error:
+ WebPSafeFree(mapping);
+ if (!ok) {
+ WebPSafeFree(huffman_image);
+ VP8LHuffmanTablesDeallocate(huffman_tables);
+ VP8LHtreeGroupsFree(htree_groups);
+ }
+ return ok;
+}
+
+int ReadHuffmanCodesHelper(int color_cache_bits, int num_htree_groups,
+ int num_htree_groups_max, const int* const mapping,
+ VP8LDecoder* const dec,
+ HuffmanTables* const huffman_tables,
+ HTreeGroup** const htree_groups) {
+ int i, j, ok = 0;
+ const int max_alphabet_size =
+ kAlphabetSize[0] + ((color_cache_bits > 0) ? 1 << color_cache_bits : 0);
+ const int table_size = kTableSize[color_cache_bits];
+ int* code_lengths = NULL;
+
+ if ((mapping == NULL && num_htree_groups != num_htree_groups_max) ||
+ num_htree_groups > num_htree_groups_max) {
+ goto Error;
+ }
+
+ code_lengths =
+ (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, sizeof(*code_lengths));
+ *htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+
+ if (*htree_groups == NULL || code_lengths == NULL ||
!VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
huffman_tables)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Error;
}
@@ -464,7 +493,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
} else {
HTreeGroup* const htree_group =
- &htree_groups[(mapping == NULL) ? i : mapping[i]];
+ &(*htree_groups)[(mapping == NULL) ? i : mapping[i]];
HuffmanCode** const htrees = htree_group->htrees;
int size;
int total_size = 0;
@@ -516,18 +545,12 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
ok = 1;
- // All OK. Finalize pointers.
- hdr->huffman_image_ = huffman_image;
- hdr->num_htree_groups_ = num_htree_groups;
- hdr->htree_groups_ = htree_groups;
-
Error:
WebPSafeFree(code_lengths);
- WebPSafeFree(mapping);
if (!ok) {
- WebPSafeFree(huffman_image);
VP8LHuffmanTablesDeallocate(huffman_tables);
- VP8LHtreeGroupsFree(htree_groups);
+ VP8LHtreeGroupsFree(*htree_groups);
+ *htree_groups = NULL;
}
return ok;
}
@@ -551,8 +574,7 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
scaled_data_size * sizeof(*scaled_data);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
if (memory == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
assert(dec->rescaler_memory == NULL);
dec->rescaler_memory = memory;
@@ -1086,12 +1108,10 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
End:
br->eos_ = VP8LIsEndOfStream(br);
if (!ok || (br->eos_ && pos < end)) {
- ok = 0;
- dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
- : VP8_STATUS_BITSTREAM_ERROR;
- } else {
- dec->last_pixel_ = pos;
+ return VP8LSetError(
+ dec, br->eos_ ? VP8_STATUS_SUSPENDED : VP8_STATUS_BITSTREAM_ERROR);
}
+ dec->last_pixel_ = pos;
return ok;
}
@@ -1269,8 +1289,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
return 1;
Error:
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
}
// -----------------------------------------------------------------------------
@@ -1337,7 +1356,7 @@ static int ReadTransform(int* const xsize, int const* ysize,
transform->bits_),
VP8LSubSampleSize(transform->ysize_,
transform->bits_),
- 0, dec, &transform->data_);
+ /*is_level0=*/0, dec, &transform->data_);
break;
case COLOR_INDEXING_TRANSFORM: {
const int num_colors = VP8LReadBits(br, 8) + 1;
@@ -1347,8 +1366,11 @@ static int ReadTransform(int* const xsize, int const* ysize,
: 3;
*xsize = VP8LSubSampleSize(transform->xsize_, bits);
transform->bits_ = bits;
- ok = DecodeImageStream(num_colors, 1, 0, dec, &transform->data_);
- ok = ok && ExpandColorMap(num_colors, transform);
+ ok = DecodeImageStream(num_colors, /*ysize=*/1, /*is_level0=*/0, dec,
+ &transform->data_);
+ if (ok && !ExpandColorMap(num_colors, transform)) {
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
+ }
break;
}
case SUBTRACT_GREEN_TRANSFORM:
@@ -1454,7 +1476,7 @@ static int DecodeImageStream(int xsize, int ysize,
color_cache_bits = VP8LReadBits(br, 4);
ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS);
if (!ok) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto End;
}
}
@@ -1463,7 +1485,7 @@ static int DecodeImageStream(int xsize, int ysize,
ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize,
color_cache_bits, is_level0);
if (!ok) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto End;
}
@@ -1471,8 +1493,7 @@ static int DecodeImageStream(int xsize, int ysize,
if (color_cache_bits > 0) {
hdr->color_cache_size_ = 1 << color_cache_bits;
if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- ok = 0;
+ ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto End;
}
} else {
@@ -1489,8 +1510,7 @@ static int DecodeImageStream(int xsize, int ysize,
const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize;
data = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*data));
if (data == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- ok = 0;
+ ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto End;
}
}
@@ -1535,8 +1555,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
if (dec->pixels_ == NULL) {
dec->argb_cache_ = NULL; // for soundness
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels;
return 1;
@@ -1547,8 +1566,7 @@ static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
dec->argb_cache_ = NULL; // for soundness
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
if (dec->pixels_ == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
return 1;
}
@@ -1603,7 +1621,8 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
dec->status_ = VP8_STATUS_OK;
VP8LInitBitReader(&dec->br_, data, data_size);
- if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, 1, dec, NULL)) {
+ if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, /*is_level0=*/1,
+ dec, /*decoded_data=*/NULL)) {
goto Err;
}
@@ -1658,22 +1677,24 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
if (dec == NULL) return 0;
if (io == NULL) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
}
dec->io_ = io;
dec->status_ = VP8_STATUS_OK;
VP8LInitBitReader(&dec->br_, io->data, io->data_size);
if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto Error;
}
dec->state_ = READ_DIM;
io->width = width;
io->height = height;
- if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error;
+ if (!DecodeImageStream(width, height, /*is_level0=*/1, dec,
+ /*decoded_data=*/NULL)) {
+ goto Error;
+ }
return 1;
Error:
@@ -1703,7 +1724,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
assert(dec->output_ != NULL);
if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
+ VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
goto Err;
}
@@ -1713,7 +1734,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
#else
if (io->use_scaling) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
+ VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
goto Err;
}
#endif
@@ -1731,7 +1752,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
dec->hdr_.saved_color_cache_.colors_ == NULL) {
if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_,
dec->hdr_.color_cache_.hash_bits_)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Err;
}
}
diff --git a/media/libwebp/src/dec/vp8li_dec.h b/media/libwebp/src/dec/vp8li_dec.h
index 32540a4b88..9a13bcc98d 100644
--- a/media/libwebp/src/dec/vp8li_dec.h
+++ b/media/libwebp/src/dec/vp8li_dec.h
@@ -20,6 +20,7 @@
#include "src/utils/bit_reader_utils.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/huffman_utils.h"
+#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@@ -99,25 +100,26 @@ struct ALPHDecoder; // Defined in dec/alphai.h.
// Decodes image header for alpha data stored using lossless compression.
// Returns false in case of error.
-int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
- const uint8_t* const data, size_t data_size);
+WEBP_NODISCARD int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
+ const uint8_t* const data,
+ size_t data_size);
// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
// already decoded in previous call(s), it will resume decoding from where it
// was paused.
// Returns false in case of bitstream error.
-int VP8LDecodeAlphaImageStream(struct ALPHDecoder* const alph_dec,
- int last_row);
+WEBP_NODISCARD int VP8LDecodeAlphaImageStream(
+ struct ALPHDecoder* const alph_dec, int last_row);
// Allocates and initialize a new lossless decoder instance.
-VP8LDecoder* VP8LNew(void);
+WEBP_NODISCARD VP8LDecoder* VP8LNew(void);
// Decodes the image header. Returns false in case of error.
-int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
// Decodes an image. It's required to decode the lossless header before calling
// this function. Returns false in case of error, with updated dec->status_.
-int VP8LDecodeImage(VP8LDecoder* const dec);
+WEBP_NODISCARD int VP8LDecodeImage(VP8LDecoder* const dec);
// Resets the decoder in its initial state, reclaiming memory.
// Preserves the dec->status_ value.
@@ -126,6 +128,18 @@ void VP8LClear(VP8LDecoder* const dec);
// Clears and deallocate a lossless decoder instance.
void VP8LDelete(VP8LDecoder* const dec);
+// Helper function for reading the different Huffman codes and storing them in
+// 'huffman_tables' and 'htree_groups'.
+// If mapping is NULL 'num_htree_groups_max' must equal 'num_htree_groups'.
+// If it is not NULL, it maps 'num_htree_groups_max' indices to the
+// 'num_htree_groups' groups. If 'num_htree_groups_max' > 'num_htree_groups',
+// some of those indices map to -1. This is used for non-balanced codes to
+// limit memory usage.
+WEBP_NODISCARD int ReadHuffmanCodesHelper(
+ int color_cache_bits, int num_htree_groups, int num_htree_groups_max,
+ const int* const mapping, VP8LDecoder* const dec,
+ HuffmanTables* const huffman_tables, HTreeGroup** const htree_groups);
+
//------------------------------------------------------------------------------
#ifdef __cplusplus
diff --git a/media/libwebp/src/dec/webp_dec.c b/media/libwebp/src/dec/webp_dec.c
index f557868b99..49ef205c8b 100644
--- a/media/libwebp/src/dec/webp_dec.c
+++ b/media/libwebp/src/dec/webp_dec.c
@@ -13,11 +13,14 @@
#include <stdlib.h>
+#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
#include "src/dec/webpi_dec.h"
#include "src/utils/utils.h"
#include "src/webp/mux_types.h" // ALPHA_FLAG
+#include "src/webp/decode.h"
+#include "src/webp/types.h"
//------------------------------------------------------------------------------
// RIFF layout is:
@@ -444,8 +447,9 @@ void WebPResetDecParams(WebPDecParams* const params) {
// "Into" decoding variants
// Main flow
-static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
- WebPDecParams* const params) {
+WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
+ size_t data_size,
+ WebPDecParams* const params) {
VP8StatusCode status;
VP8Io io;
WebPHeaderStructure headers;
@@ -459,7 +463,9 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
}
assert(params != NULL);
- VP8InitIo(&io);
+ if (!VP8InitIo(&io)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
io.data = headers.data + headers.offset;
io.data_size = headers.data_size - headers.offset;
WebPInitCustomIo(params, &io); // Plug the I/O functions.
@@ -523,17 +529,16 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
}
// Helpers
-static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
- const uint8_t* const data,
- size_t data_size,
- uint8_t* const rgba,
- int stride, size_t size) {
+WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
+ const uint8_t* const data,
+ size_t data_size,
+ uint8_t* const rgba,
+ int stride, size_t size) {
WebPDecParams params;
WebPDecBuffer buf;
- if (rgba == NULL) {
+ if (rgba == NULL || !WebPInitDecBuffer(&buf)) {
return NULL;
}
- WebPInitDecBuffer(&buf);
WebPResetDecParams(&params);
params.output = &buf;
buf.colorspace = colorspace;
@@ -578,8 +583,7 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
uint8_t* v, size_t v_size, int v_stride) {
WebPDecParams params;
WebPDecBuffer output;
- if (luma == NULL) return NULL;
- WebPInitDecBuffer(&output);
+ if (luma == NULL || !WebPInitDecBuffer(&output)) return NULL;
WebPResetDecParams(&params);
params.output = &output;
output.colorspace = MODE_YUV;
@@ -601,13 +605,17 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
//------------------------------------------------------------------------------
-static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data,
- size_t data_size, int* const width, int* const height,
- WebPDecBuffer* const keep_info) {
+WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode,
+ const uint8_t* const data,
+ size_t data_size, int* const width,
+ int* const height,
+ WebPDecBuffer* const keep_info) {
WebPDecParams params;
WebPDecBuffer output;
- WebPInitDecBuffer(&output);
+ if (!WebPInitDecBuffer(&output)) {
+ return NULL;
+ }
WebPResetDecParams(&params);
params.output = &output;
output.colorspace = mode;
@@ -733,7 +741,9 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
}
memset(config, 0, sizeof(*config));
DefaultFeatures(&config->input);
- WebPInitDecBuffer(&config->output);
+ if (!WebPInitDecBuffer(&config->output)) {
+ return 0;
+ }
return 1;
}
@@ -772,7 +782,9 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
if (WebPAvoidSlowMemory(params.output, &config->input)) {
// decoding to slow memory: use a temporary in-mem buffer to decode into.
WebPDecBuffer in_mem_buffer;
- WebPInitDecBuffer(&in_mem_buffer);
+ if (!WebPInitDecBuffer(&in_mem_buffer)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
in_mem_buffer.colorspace = config->output.colorspace;
in_mem_buffer.width = config->input.width;
in_mem_buffer.height = config->input.height;
diff --git a/media/libwebp/src/dec/webpi_dec.h b/media/libwebp/src/dec/webpi_dec.h
index 3b97388c71..77bf5264b7 100644
--- a/media/libwebp/src/dec/webpi_dec.h
+++ b/media/libwebp/src/dec/webpi_dec.h
@@ -20,6 +20,7 @@ extern "C" {
#include "src/utils/rescaler_utils.h"
#include "src/dec/vp8_dec.h"
+#include "src/webp/decode.h"
//------------------------------------------------------------------------------
// WebPDecParams: Decoding output parameters. Transient internal object.
@@ -87,8 +88,9 @@ void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers
// to the *compressed* format, not the output one.
-int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
- VP8Io* const io, WEBP_CSP_MODE src_colorspace);
+WEBP_NODISCARD int WebPIoInitFromOptions(
+ const WebPDecoderOptions* const options, VP8Io* const io,
+ WEBP_CSP_MODE src_colorspace);
//------------------------------------------------------------------------------
// Internal functions regarding WebPDecBuffer memory (in buffer.c).
diff --git a/media/libwebp/src/demux/demux.c b/media/libwebp/src/demux/demux.c
index 4b0d3f59e9..d01c6a7464 100644
--- a/media/libwebp/src/demux/demux.c
+++ b/media/libwebp/src/demux/demux.c
@@ -24,8 +24,8 @@
#include "src/webp/format_constants.h"
#define DMUX_MAJ_VERSION 1
-#define DMUX_MIN_VERSION 3
-#define DMUX_REV_VERSION 2
+#define DMUX_MIN_VERSION 4
+#define DMUX_REV_VERSION 0
typedef struct {
size_t start_; // start location of the data
diff --git a/media/libwebp/src/dsp/alpha_processing_sse2.c b/media/libwebp/src/dsp/alpha_processing_sse2.c
index f0843d0feb..aa0cc2848a 100644
--- a/media/libwebp/src/dsp/alpha_processing_sse2.c
+++ b/media/libwebp/src/dsp/alpha_processing_sse2.c
@@ -144,6 +144,46 @@ static int ExtractAlpha_SSE2(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
return (alpha_and == 0xff);
}
+static void ExtractGreen_SSE2(const uint32_t* WEBP_RESTRICT argb,
+ uint8_t* WEBP_RESTRICT alpha, int size) {
+ int i;
+ const __m128i mask = _mm_set1_epi32(0xff);
+ const __m128i* src = (const __m128i*)argb;
+
+ for (i = 0; i + 16 <= size; i += 16, src += 4) {
+ const __m128i a0 = _mm_loadu_si128(src + 0);
+ const __m128i a1 = _mm_loadu_si128(src + 1);
+ const __m128i a2 = _mm_loadu_si128(src + 2);
+ const __m128i a3 = _mm_loadu_si128(src + 3);
+ const __m128i b0 = _mm_srli_epi32(a0, 8);
+ const __m128i b1 = _mm_srli_epi32(a1, 8);
+ const __m128i b2 = _mm_srli_epi32(a2, 8);
+ const __m128i b3 = _mm_srli_epi32(a3, 8);
+ const __m128i c0 = _mm_and_si128(b0, mask);
+ const __m128i c1 = _mm_and_si128(b1, mask);
+ const __m128i c2 = _mm_and_si128(b2, mask);
+ const __m128i c3 = _mm_and_si128(b3, mask);
+ const __m128i d0 = _mm_packs_epi32(c0, c1);
+ const __m128i d1 = _mm_packs_epi32(c2, c3);
+ const __m128i e = _mm_packus_epi16(d0, d1);
+ // store
+ _mm_storeu_si128((__m128i*)&alpha[i], e);
+ }
+ if (i + 8 <= size) {
+ const __m128i a0 = _mm_loadu_si128(src + 0);
+ const __m128i a1 = _mm_loadu_si128(src + 1);
+ const __m128i b0 = _mm_srli_epi32(a0, 8);
+ const __m128i b1 = _mm_srli_epi32(a1, 8);
+ const __m128i c0 = _mm_and_si128(b0, mask);
+ const __m128i c1 = _mm_and_si128(b1, mask);
+ const __m128i d = _mm_packs_epi32(c0, c1);
+ const __m128i e = _mm_packus_epi16(d, d);
+ _mm_storel_epi64((__m128i*)&alpha[i], e);
+ i += 8;
+ }
+ for (; i < size; ++i) alpha[i] = argb[i] >> 8;
+}
+
//------------------------------------------------------------------------------
// Non-dither premultiplied modes
@@ -354,6 +394,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) {
WebPDispatchAlpha = DispatchAlpha_SSE2;
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_SSE2;
WebPExtractAlpha = ExtractAlpha_SSE2;
+ WebPExtractGreen = ExtractGreen_SSE2;
WebPHasAlpha8b = HasAlpha8b_SSE2;
WebPHasAlpha32b = HasAlpha32b_SSE2;
diff --git a/media/libwebp/src/dsp/dec.c b/media/libwebp/src/dsp/dec.c
index 33d8df8a62..451d649d58 100644
--- a/media/libwebp/src/dsp/dec.c
+++ b/media/libwebp/src/dsp/dec.c
@@ -37,9 +37,6 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
STORE(3, y, DC - (d)); \
} while (0)
-#define MUL1(a) ((((a) * 20091) >> 16) + (a))
-#define MUL2(a) (((a) * 35468) >> 16)
-
#if !WEBP_NEON_OMIT_C_CODE
static void TransformOne_C(const int16_t* in, uint8_t* dst) {
int C[4 * 4], *tmp;
@@ -48,8 +45,10 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
for (i = 0; i < 4; ++i) { // vertical pass
const int a = in[0] + in[8]; // [-4096, 4094]
const int b = in[0] - in[8]; // [-4095, 4095]
- const int c = MUL2(in[4]) - MUL1(in[12]); // [-3783, 3783]
- const int d = MUL1(in[4]) + MUL2(in[12]); // [-3785, 3781]
+ const int c = WEBP_TRANSFORM_AC3_MUL2(in[4]) -
+ WEBP_TRANSFORM_AC3_MUL1(in[12]); // [-3783, 3783]
+ const int d = WEBP_TRANSFORM_AC3_MUL1(in[4]) +
+ WEBP_TRANSFORM_AC3_MUL2(in[12]); // [-3785, 3781]
tmp[0] = a + d; // [-7881, 7875]
tmp[1] = b + c; // [-7878, 7878]
tmp[2] = b - c; // [-7878, 7878]
@@ -69,8 +68,10 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
const int dc = tmp[0] + 4;
const int a = dc + tmp[8];
const int b = dc - tmp[8];
- const int c = MUL2(tmp[4]) - MUL1(tmp[12]);
- const int d = MUL1(tmp[4]) + MUL2(tmp[12]);
+ const int c =
+ WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]);
+ const int d =
+ WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]);
STORE(0, 0, a + d);
STORE(1, 0, b + c);
STORE(2, 0, b - c);
@@ -83,17 +84,15 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
// Simplified transform when only in[0], in[1] and in[4] are non-zero
static void TransformAC3_C(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4;
- const int c4 = MUL2(in[4]);
- const int d4 = MUL1(in[4]);
- const int c1 = MUL2(in[1]);
- const int d1 = MUL1(in[1]);
+ const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
+ const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
+ const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
STORE2(0, a + d4, d1, c1);
STORE2(1, a + c4, d1, c1);
STORE2(2, a - c4, d1, c1);
STORE2(3, a - d4, d1, c1);
}
-#undef MUL1
-#undef MUL2
#undef STORE2
static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) {
diff --git a/media/libwebp/src/dsp/dec_mips32.c b/media/libwebp/src/dsp/dec_mips32.c
index e4e70966d2..f0e7de4ac4 100644
--- a/media/libwebp/src/dsp/dec_mips32.c
+++ b/media/libwebp/src/dsp/dec_mips32.c
@@ -18,8 +18,8 @@
#include "src/dsp/mips_macro.h"
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
+static const int kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int kC2 = WEBP_TRANSFORM_AC3_C2;
static WEBP_INLINE int abs_mips32(int x) {
const int sign = x >> 31;
@@ -219,7 +219,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
int temp0, temp1, temp2, temp3, temp4;
int temp5, temp6, temp7, temp8, temp9;
int temp10, temp11, temp12, temp13, temp14;
- int temp15, temp16, temp17, temp18;
+ int temp15, temp16, temp17, temp18, temp19;
int16_t* p_in = (int16_t*)in;
// loops unrolled and merged to avoid usage of tmp buffer
@@ -233,16 +233,14 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp16], %[temp0], %[temp8] \n\t"
"subu %[temp0], %[temp0], %[temp8] \n\t"
"mul %[temp8], %[temp4], %[kC2] \n\t"
- "mul %[temp17], %[temp12], %[kC1] \n\t"
- "mul %[temp4], %[temp4], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp12)
+ MUL_SHIFT_C1_IO(temp4, temp19)
"mul %[temp12], %[temp12], %[kC2] \n\t"
"lh %[temp1], 2(%[in]) \n\t"
"lh %[temp5], 10(%[in]) \n\t"
"lh %[temp9], 18(%[in]) \n\t"
"lh %[temp13], 26(%[in]) \n\t"
"sra %[temp8], %[temp8], 16 \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
- "sra %[temp4], %[temp4], 16 \n\t"
"sra %[temp12], %[temp12], 16 \n\t"
"lh %[temp2], 4(%[in]) \n\t"
"lh %[temp6], 12(%[in]) \n\t"
@@ -261,49 +259,43 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp12], %[temp0], %[temp17] \n\t"
"subu %[temp0], %[temp0], %[temp17] \n\t"
"mul %[temp9], %[temp5], %[kC2] \n\t"
- "mul %[temp17], %[temp13], %[kC1] \n\t"
- "mul %[temp5], %[temp5], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp13)
+ MUL_SHIFT_C1_IO(temp5, temp19)
"mul %[temp13], %[temp13], %[kC2] \n\t"
"sra %[temp9], %[temp9], 16 \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
"subu %[temp17], %[temp9], %[temp17] \n\t"
- "sra %[temp5], %[temp5], 16 \n\t"
"sra %[temp13], %[temp13], 16 \n\t"
"addu %[temp5], %[temp5], %[temp13] \n\t"
"addu %[temp13], %[temp1], %[temp17] \n\t"
"subu %[temp1], %[temp1], %[temp17] \n\t"
- "mul %[temp17], %[temp14], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp14)
"mul %[temp14], %[temp14], %[kC2] \n\t"
"addu %[temp9], %[temp16], %[temp5] \n\t"
"subu %[temp5], %[temp16], %[temp5] \n\t"
"addu %[temp16], %[temp2], %[temp10] \n\t"
"subu %[temp2], %[temp2], %[temp10] \n\t"
"mul %[temp10], %[temp6], %[kC2] \n\t"
- "mul %[temp6], %[temp6], %[kC1] \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
+ MUL_SHIFT_C1_IO(temp6, temp19)
"sra %[temp14], %[temp14], 16 \n\t"
"sra %[temp10], %[temp10], 16 \n\t"
- "sra %[temp6], %[temp6], 16 \n\t"
"subu %[temp17], %[temp10], %[temp17] \n\t"
"addu %[temp6], %[temp6], %[temp14] \n\t"
"addu %[temp10], %[temp16], %[temp6] \n\t"
"subu %[temp6], %[temp16], %[temp6] \n\t"
"addu %[temp14], %[temp2], %[temp17] \n\t"
"subu %[temp2], %[temp2], %[temp17] \n\t"
- "mul %[temp17], %[temp15], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp15)
"mul %[temp15], %[temp15], %[kC2] \n\t"
"addu %[temp16], %[temp3], %[temp11] \n\t"
"subu %[temp3], %[temp3], %[temp11] \n\t"
"mul %[temp11], %[temp7], %[kC2] \n\t"
- "mul %[temp7], %[temp7], %[kC1] \n\t"
+ MUL_SHIFT_C1_IO(temp7, temp19)
"addiu %[temp8], %[temp8], 4 \n\t"
"addiu %[temp12], %[temp12], 4 \n\t"
"addiu %[temp0], %[temp0], 4 \n\t"
"addiu %[temp4], %[temp4], 4 \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
"sra %[temp15], %[temp15], 16 \n\t"
"sra %[temp11], %[temp11], 16 \n\t"
- "sra %[temp7], %[temp7], 16 \n\t"
"subu %[temp17], %[temp11], %[temp17] \n\t"
"addu %[temp7], %[temp7], %[temp15] \n\t"
"addu %[temp15], %[temp3], %[temp17] \n\t"
@@ -313,48 +305,40 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp16], %[temp8], %[temp10] \n\t"
"subu %[temp8], %[temp8], %[temp10] \n\t"
"mul %[temp10], %[temp9], %[kC2] \n\t"
- "mul %[temp17], %[temp11], %[kC1] \n\t"
- "mul %[temp9], %[temp9], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp11)
+ MUL_SHIFT_C1_IO(temp9, temp19)
"mul %[temp11], %[temp11], %[kC2] \n\t"
"sra %[temp10], %[temp10], 16 \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
- "sra %[temp9], %[temp9], 16 \n\t"
"sra %[temp11], %[temp11], 16 \n\t"
"subu %[temp17], %[temp10], %[temp17] \n\t"
"addu %[temp11], %[temp9], %[temp11] \n\t"
"addu %[temp10], %[temp12], %[temp14] \n\t"
"subu %[temp12], %[temp12], %[temp14] \n\t"
"mul %[temp14], %[temp13], %[kC2] \n\t"
- "mul %[temp9], %[temp15], %[kC1] \n\t"
- "mul %[temp13], %[temp13], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp9, temp15)
+ MUL_SHIFT_C1_IO(temp13, temp19)
"mul %[temp15], %[temp15], %[kC2] \n\t"
"sra %[temp14], %[temp14], 16 \n\t"
- "sra %[temp9], %[temp9], 16 \n\t"
- "sra %[temp13], %[temp13], 16 \n\t"
"sra %[temp15], %[temp15], 16 \n\t"
"subu %[temp9], %[temp14], %[temp9] \n\t"
"addu %[temp15], %[temp13], %[temp15] \n\t"
"addu %[temp14], %[temp0], %[temp2] \n\t"
"subu %[temp0], %[temp0], %[temp2] \n\t"
"mul %[temp2], %[temp1], %[kC2] \n\t"
- "mul %[temp13], %[temp3], %[kC1] \n\t"
- "mul %[temp1], %[temp1], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp13, temp3)
+ MUL_SHIFT_C1_IO(temp1, temp19)
"mul %[temp3], %[temp3], %[kC2] \n\t"
"sra %[temp2], %[temp2], 16 \n\t"
- "sra %[temp13], %[temp13], 16 \n\t"
- "sra %[temp1], %[temp1], 16 \n\t"
"sra %[temp3], %[temp3], 16 \n\t"
"subu %[temp13], %[temp2], %[temp13] \n\t"
"addu %[temp3], %[temp1], %[temp3] \n\t"
"addu %[temp2], %[temp4], %[temp6] \n\t"
"subu %[temp4], %[temp4], %[temp6] \n\t"
"mul %[temp6], %[temp5], %[kC2] \n\t"
- "mul %[temp1], %[temp7], %[kC1] \n\t"
- "mul %[temp5], %[temp5], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp1, temp7)
+ MUL_SHIFT_C1_IO(temp5, temp19)
"mul %[temp7], %[temp7], %[kC2] \n\t"
"sra %[temp6], %[temp6], 16 \n\t"
- "sra %[temp1], %[temp1], 16 \n\t"
- "sra %[temp5], %[temp5], 16 \n\t"
"sra %[temp7], %[temp7], 16 \n\t"
"subu %[temp1], %[temp6], %[temp1] \n\t"
"addu %[temp7], %[temp5], %[temp7] \n\t"
@@ -542,7 +526,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
[temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
[temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
[temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
- [temp18]"=&r"(temp18)
+ [temp18]"=&r"(temp18), [temp19]"=&r"(temp19)
: [in]"r"(p_in), [kC1]"r"(kC1), [kC2]"r"(kC2), [dst]"r"(dst)
: "memory", "hi", "lo"
);
diff --git a/media/libwebp/src/dsp/dec_mips_dsp_r2.c b/media/libwebp/src/dsp/dec_mips_dsp_r2.c
index b0936bc46e..0ba706a2ef 100644
--- a/media/libwebp/src/dsp/dec_mips_dsp_r2.c
+++ b/media/libwebp/src/dsp/dec_mips_dsp_r2.c
@@ -18,10 +18,8 @@
#include "src/dsp/mips_macro.h"
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
-
-#define MUL(a, b) (((a) * (b)) >> 16)
+static const int kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int kC2 = WEBP_TRANSFORM_AC3_C2;
static void TransformDC(const int16_t* in, uint8_t* dst) {
int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10;
@@ -49,10 +47,10 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
static void TransformAC3(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4;
- int c4 = MUL(in[4], kC2);
- const int d4 = MUL(in[4], kC1);
- const int c1 = MUL(in[1], kC2);
- const int d1 = MUL(in[1], kC1);
+ int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
+ const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
+ const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18;
@@ -479,8 +477,6 @@ static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
}
-#undef MUL
-
//------------------------------------------------------------------------------
// Simple In-loop filtering (Paragraph 15.2)
diff --git a/media/libwebp/src/dsp/dec_msa.c b/media/libwebp/src/dsp/dec_msa.c
index 8090622b7b..58d1730192 100644
--- a/media/libwebp/src/dsp/dec_msa.c
+++ b/media/libwebp/src/dsp/dec_msa.c
@@ -37,8 +37,6 @@
d1_m = d_tmp1_m + d_tmp2_m; \
BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \
}
-#define MULT1(a) ((((a) * 20091) >> 16) + (a))
-#define MULT2(a) (((a) * 35468) >> 16)
static void TransformOne(const int16_t* in, uint8_t* dst) {
v8i16 input0, input1;
@@ -124,10 +122,10 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
static void TransformAC3(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4;
- const int c4 = MULT2(in[4]);
- const int d4 = MULT1(in[4]);
- const int in2 = MULT2(in[1]);
- const int in3 = MULT1(in[1]);
+ const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
+ const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
+ const int in2 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int in3 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
v4i32 tmp0 = { 0 };
v4i32 out0 = __msa_fill_w(a + d4);
v4i32 out1 = __msa_fill_w(a + c4);
diff --git a/media/libwebp/src/dsp/dec_neon.c b/media/libwebp/src/dsp/dec_neon.c
index 22784cf15a..83b3a1f970 100644
--- a/media/libwebp/src/dsp/dec_neon.c
+++ b/media/libwebp/src/dsp/dec_neon.c
@@ -1000,8 +1000,9 @@ static void HFilter8i_NEON(uint8_t* u, uint8_t* v, int stride,
// libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the
// same issue with kC1 and vqdmulh that we work around by down shifting kC2
-static const int16_t kC1 = 20091;
-static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
+static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int16_t kC2 =
+ WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above.
#if defined(WEBP_USE_INTRINSICS)
static WEBP_INLINE void Transpose8x2_NEON(const int16x8_t in0,
@@ -1255,15 +1256,12 @@ static void TransformWHT_NEON(const int16_t* in, int16_t* out) {
//------------------------------------------------------------------------------
-#define MUL(a, b) (((a) * (b)) >> 16)
static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) {
- static const int kC1_full = 20091 + (1 << 16);
- static const int kC2_full = 35468;
const int16x4_t A = vld1_dup_s16(in);
- const int16x4_t c4 = vdup_n_s16(MUL(in[4], kC2_full));
- const int16x4_t d4 = vdup_n_s16(MUL(in[4], kC1_full));
- const int c1 = MUL(in[1], kC2_full);
- const int d1 = MUL(in[1], kC1_full);
+ const int16x4_t c4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL2(in[4]));
+ const int16x4_t d4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL1(in[4]));
+ const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
const uint64_t cd = (uint64_t)( d1 & 0xffff) << 0 |
(uint64_t)( c1 & 0xffff) << 16 |
(uint64_t)(-c1 & 0xffff) << 32 |
@@ -1274,7 +1272,6 @@ static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) {
const int16x8_t m2_m3 = vcombine_s16(vqsub_s16(B, c4), vqsub_s16(B, d4));
Add4x4_NEON(m0_m1, m2_m3, dst);
}
-#undef MUL
//------------------------------------------------------------------------------
// 4x4
diff --git a/media/libwebp/src/dsp/dec_sse2.c b/media/libwebp/src/dsp/dec_sse2.c
index 01e6bcb636..ff3a28555b 100644
--- a/media/libwebp/src/dsp/dec_sse2.c
+++ b/media/libwebp/src/dsp/dec_sse2.c
@@ -196,15 +196,13 @@ static void Transform_SSE2(const int16_t* in, uint8_t* dst, int do_two) {
}
#if (USE_TRANSFORM_AC3 == 1)
-#define MUL(a, b) (((a) * (b)) >> 16)
+
static void TransformAC3(const int16_t* in, uint8_t* dst) {
- static const int kC1 = 20091 + (1 << 16);
- static const int kC2 = 35468;
const __m128i A = _mm_set1_epi16(in[0] + 4);
- const __m128i c4 = _mm_set1_epi16(MUL(in[4], kC2));
- const __m128i d4 = _mm_set1_epi16(MUL(in[4], kC1));
- const int c1 = MUL(in[1], kC2);
- const int d1 = MUL(in[1], kC1);
+ const __m128i c4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL2(in[4]));
+ const __m128i d4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL1(in[4]));
+ const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
const __m128i CD = _mm_set_epi16(0, 0, 0, 0, -d1, -c1, c1, d1);
const __m128i B = _mm_adds_epi16(A, CD);
const __m128i m0 = _mm_adds_epi16(B, d4);
@@ -238,7 +236,7 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2));
WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3));
}
-#undef MUL
+
#endif // USE_TRANSFORM_AC3
//------------------------------------------------------------------------------
@@ -259,15 +257,15 @@ static WEBP_INLINE void SignedShift8b_SSE2(__m128i* const x) {
*x = _mm_packs_epi16(lo_1, hi_1);
}
-#define FLIP_SIGN_BIT2(a, b) { \
+#define FLIP_SIGN_BIT2(a, b) do { \
(a) = _mm_xor_si128(a, sign_bit); \
(b) = _mm_xor_si128(b, sign_bit); \
-}
+} while (0)
-#define FLIP_SIGN_BIT4(a, b, c, d) { \
+#define FLIP_SIGN_BIT4(a, b, c, d) do { \
FLIP_SIGN_BIT2(a, b); \
FLIP_SIGN_BIT2(c, d); \
-}
+} while (0)
// input/output is uint8_t
static WEBP_INLINE void GetNotHEV_SSE2(const __m128i* const p1,
@@ -645,12 +643,12 @@ static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
(m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \
} while (0)
-#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \
+#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) do { \
(e1) = _mm_loadu_si128((__m128i*)&(p)[0 * (stride)]); \
(e2) = _mm_loadu_si128((__m128i*)&(p)[1 * (stride)]); \
(e3) = _mm_loadu_si128((__m128i*)&(p)[2 * (stride)]); \
(e4) = _mm_loadu_si128((__m128i*)&(p)[3 * (stride)]); \
-}
+} while (0)
#define LOADUV_H_EDGE(p, u, v, stride) do { \
const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
@@ -658,18 +656,18 @@ static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
(p) = _mm_unpacklo_epi64(U, V); \
} while (0)
-#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \
+#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) do { \
LOADUV_H_EDGE(e1, u, v, 0 * (stride)); \
LOADUV_H_EDGE(e2, u, v, 1 * (stride)); \
LOADUV_H_EDGE(e3, u, v, 2 * (stride)); \
LOADUV_H_EDGE(e4, u, v, 3 * (stride)); \
-}
+} while (0)
-#define STOREUV(p, u, v, stride) { \
+#define STOREUV(p, u, v, stride) do { \
_mm_storel_epi64((__m128i*)&(u)[(stride)], p); \
(p) = _mm_srli_si128(p, 8); \
_mm_storel_epi64((__m128i*)&(v)[(stride)], p); \
-}
+} while (0)
static WEBP_INLINE void ComplexMask_SSE2(const __m128i* const p1,
const __m128i* const p0,
diff --git a/media/libwebp/src/dsp/dsp.h b/media/libwebp/src/dsp/dsp.h
index d2000b8efc..23bc296514 100644
--- a/media/libwebp/src/dsp/dsp.h
+++ b/media/libwebp/src/dsp/dsp.h
@@ -203,6 +203,11 @@ extern VP8DecIdct VP8TransformDC;
extern VP8DecIdct VP8TransformDCUV;
extern VP8WHT VP8TransformWHT;
+#define WEBP_TRANSFORM_AC3_C1 20091
+#define WEBP_TRANSFORM_AC3_C2 35468
+#define WEBP_TRANSFORM_AC3_MUL1(a) ((((a) * WEBP_TRANSFORM_AC3_C1) >> 16) + (a))
+#define WEBP_TRANSFORM_AC3_MUL2(a) (((a) * WEBP_TRANSFORM_AC3_C2) >> 16)
+
// *dst is the destination block, with stride BPS. Boundary samples are
// assumed accessible when needed.
typedef void (*VP8PredFunc)(uint8_t* dst);
diff --git a/media/libwebp/src/dsp/enc.c b/media/libwebp/src/dsp/enc.c
index 2ba97ba8d6..395ad05b0b 100644
--- a/media/libwebp/src/dsp/enc.c
+++ b/media/libwebp/src/dsp/enc.c
@@ -109,10 +109,6 @@ static WEBP_TSAN_IGNORE_FUNCTION void InitTables(void) {
#define STORE(x, y, v) \
dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3))
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
-#define MUL(a, b) (((a) * (b)) >> 16)
-
static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
uint8_t* dst) {
int C[4 * 4], *tmp;
@@ -121,8 +117,10 @@ static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
for (i = 0; i < 4; ++i) { // vertical pass
const int a = in[0] + in[8];
const int b = in[0] - in[8];
- const int c = MUL(in[4], kC2) - MUL(in[12], kC1);
- const int d = MUL(in[4], kC1) + MUL(in[12], kC2);
+ const int c =
+ WEBP_TRANSFORM_AC3_MUL2(in[4]) - WEBP_TRANSFORM_AC3_MUL1(in[12]);
+ const int d =
+ WEBP_TRANSFORM_AC3_MUL1(in[4]) + WEBP_TRANSFORM_AC3_MUL2(in[12]);
tmp[0] = a + d;
tmp[1] = b + c;
tmp[2] = b - c;
@@ -134,10 +132,12 @@ static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
tmp = C;
for (i = 0; i < 4; ++i) { // horizontal pass
const int dc = tmp[0] + 4;
- const int a = dc + tmp[8];
- const int b = dc - tmp[8];
- const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1);
- const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2);
+ const int a = dc + tmp[8];
+ const int b = dc - tmp[8];
+ const int c =
+ WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]);
+ const int d =
+ WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]);
STORE(0, i, a + d);
STORE(1, i, b + c);
STORE(2, i, b - c);
@@ -222,7 +222,6 @@ static void FTransformWHT_C(const int16_t* in, int16_t* out) {
}
#endif // !WEBP_NEON_OMIT_C_CODE
-#undef MUL
#undef STORE
//------------------------------------------------------------------------------
diff --git a/media/libwebp/src/dsp/enc_mips32.c b/media/libwebp/src/dsp/enc_mips32.c
index 618f0fc0ee..50518a5f1a 100644
--- a/media/libwebp/src/dsp/enc_mips32.c
+++ b/media/libwebp/src/dsp/enc_mips32.c
@@ -21,8 +21,8 @@
#include "src/enc/vp8i_enc.h"
#include "src/enc/cost_enc.h"
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
+static const int kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int kC2 = WEBP_TRANSFORM_AC3_C2;
// macro for one vertical pass in ITransformOne
// MUL macro inlined
@@ -30,7 +30,7 @@ static const int kC2 = 35468;
// A..D - offsets in bytes to load from in buffer
// TEMP0..TEMP3 - registers for corresponding tmp elements
// TEMP4..TEMP5 - temporary registers
-#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \
+#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \
"lh %[temp16], " #A "(%[temp20]) \n\t" \
"lh %[temp18], " #B "(%[temp20]) \n\t" \
"lh %[temp17], " #C "(%[temp20]) \n\t" \
@@ -38,12 +38,10 @@ static const int kC2 = 35468;
"addu %[" #TEMP4 "], %[temp16], %[temp18] \n\t" \
"subu %[temp16], %[temp16], %[temp18] \n\t" \
"mul %[" #TEMP0 "], %[temp17], %[kC2] \n\t" \
- "mul %[temp18], %[temp19], %[kC1] \n\t" \
- "mul %[temp17], %[temp17], %[kC1] \n\t" \
+ MUL_SHIFT_C1_IO(temp17, temp18) \
+ MUL_SHIFT_C1(temp18, temp19) \
"mul %[temp19], %[temp19], %[kC2] \n\t" \
"sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\n" \
- "sra %[temp18], %[temp18], 16 \n\n" \
- "sra %[temp17], %[temp17], 16 \n\n" \
"sra %[temp19], %[temp19], 16 \n\n" \
"subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp18] \n\t" \
"addu %[" #TEMP3 "], %[temp17], %[temp19] \n\t" \
@@ -58,17 +56,15 @@ static const int kC2 = 35468;
// temp0..temp15 holds tmp[0]..tmp[15]
// A - offset in bytes to load from ref and store to dst buffer
// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements
-#define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \
+#define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \
"addiu %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \
"addu %[temp16], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"subu %[temp17], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"mul %[" #TEMP0 "], %[" #TEMP4 "], %[kC2] \n\t" \
- "mul %[" #TEMP8 "], %[" #TEMP12 "], %[kC1] \n\t" \
- "mul %[" #TEMP4 "], %[" #TEMP4 "], %[kC1] \n\t" \
+ MUL_SHIFT_C1_IO(TEMP4, TEMP8) \
+ MUL_SHIFT_C1(TEMP8, TEMP12) \
"mul %[" #TEMP12 "], %[" #TEMP12 "], %[kC2] \n\t" \
"sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \
- "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \
- "sra %[" #TEMP4 "], %[" #TEMP4 "], 16 \n\t" \
"sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \
"subu %[temp18], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"addu %[temp19], %[" #TEMP4 "], %[" #TEMP12 "] \n\t" \
diff --git a/media/libwebp/src/dsp/enc_mips_dsp_r2.c b/media/libwebp/src/dsp/enc_mips_dsp_r2.c
index 9ddd895086..e1431f3bef 100644
--- a/media/libwebp/src/dsp/enc_mips_dsp_r2.c
+++ b/media/libwebp/src/dsp/enc_mips_dsp_r2.c
@@ -20,8 +20,8 @@
#include "src/enc/cost_enc.h"
#include "src/enc/vp8i_enc.h"
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
+static const int kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int kC2 = WEBP_TRANSFORM_AC3_C2;
// O - output
// I - input (macro doesn't change it)
diff --git a/media/libwebp/src/dsp/enc_neon.c b/media/libwebp/src/dsp/enc_neon.c
index 714800367b..6f641c9a76 100644
--- a/media/libwebp/src/dsp/enc_neon.c
+++ b/media/libwebp/src/dsp/enc_neon.c
@@ -27,8 +27,9 @@
// This code is pretty much the same as TransformOne in the dec_neon.c, except
// for subtraction to *ref. See the comments there for algorithmic explanations.
-static const int16_t kC1 = 20091;
-static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
+static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int16_t kC2 =
+ WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above.
// This code works but is *slower* than the inlined-asm version below
// (with gcc-4.6). So we disable it for now. Later, it'll be conditional to
diff --git a/media/libwebp/src/dsp/filters.c b/media/libwebp/src/dsp/filters.c
index 85eee5098f..c9232ff16a 100644
--- a/media/libwebp/src/dsp/filters.c
+++ b/media/libwebp/src/dsp/filters.c
@@ -19,14 +19,16 @@
//------------------------------------------------------------------------------
// 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.
+#define DCHECK(in, out) \
+ do { \
+ 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. */ \
+ } while (0)
#if !WEBP_NEON_OMIT_C_CODE
static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred,
@@ -49,7 +51,7 @@ static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = inverse ? out : in;
@@ -86,7 +88,7 @@ static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = inverse ? out : in;
@@ -131,7 +133,7 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = inverse ? out : in;
@@ -165,7 +167,7 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
}
#endif // !WEBP_NEON_OMIT_C_CODE
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
@@ -189,6 +191,12 @@ static void GradientFilter_C(const uint8_t* data, int width, int height,
//------------------------------------------------------------------------------
+static void NoneUnfilter_C(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
+ (void)prev;
+ if (out != in) memcpy(out, in, width * sizeof(*out));
+}
+
static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in,
uint8_t* out, int width) {
uint8_t pred = (prev == NULL) ? 0 : prev[0];
@@ -240,7 +248,7 @@ extern void VP8FiltersInitNEON(void);
extern void VP8FiltersInitSSE2(void);
WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
- WebPUnfilters[WEBP_FILTER_NONE] = NULL;
+ WebPUnfilters[WEBP_FILTER_NONE] = NoneUnfilter_C;
#if !WEBP_NEON_OMIT_C_CODE
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_C;
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_C;
@@ -279,6 +287,7 @@ WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
}
#endif
+ assert(WebPUnfilters[WEBP_FILTER_NONE] != NULL);
assert(WebPUnfilters[WEBP_FILTER_HORIZONTAL] != NULL);
assert(WebPUnfilters[WEBP_FILTER_VERTICAL] != NULL);
assert(WebPUnfilters[WEBP_FILTER_GRADIENT] != NULL);
diff --git a/media/libwebp/src/dsp/filters_mips_dsp_r2.c b/media/libwebp/src/dsp/filters_mips_dsp_r2.c
index 9382b12823..eca866f578 100644
--- a/media/libwebp/src/dsp/filters_mips_dsp_r2.c
+++ b/media/libwebp/src/dsp/filters_mips_dsp_r2.c
@@ -24,14 +24,16 @@
//------------------------------------------------------------------------------
// 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.
+#define DCHECK(in, out) \
+ do { \
+ 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. */ \
+ } while (0)
#define DO_PREDICT_LINE(SRC, DST, LENGTH, INVERSE) do { \
const uint8_t* psrc = (uint8_t*)(SRC); \
@@ -200,7 +202,7 @@ static WEBP_INLINE void DoHorizontalFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = in;
@@ -248,7 +250,7 @@ static WEBP_INLINE void DoVerticalFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = in;
@@ -316,7 +318,7 @@ static void DoGradientFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = in;
@@ -378,7 +380,7 @@ static void GradientUnfilter_MIPSdspR2(const uint8_t* prev, const uint8_t* in,
#undef DO_PREDICT_LINE_VERTICAL
#undef PREDICT_LINE_ONE_PASS
#undef DO_PREDICT_LINE
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
// Entry point
diff --git a/media/libwebp/src/dsp/filters_msa.c b/media/libwebp/src/dsp/filters_msa.c
index 14c437d141..33a1b20b70 100644
--- a/media/libwebp/src/dsp/filters_msa.c
+++ b/media/libwebp/src/dsp/filters_msa.c
@@ -56,12 +56,14 @@ static WEBP_INLINE void PredictLineInverse0(const uint8_t* src,
//------------------------------------------------------------------------------
// Helpful macro.
-#define SANITY_CHECK(in, out) \
- assert(in != NULL); \
- assert(out != NULL); \
- assert(width > 0); \
- assert(height > 0); \
- assert(stride >= width);
+#define DCHECK(in, out) \
+ do { \
+ assert(in != NULL); \
+ assert(out != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ } while (0)
//------------------------------------------------------------------------------
// Horrizontal filter
@@ -72,7 +74,7 @@ static void HorizontalFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* in = data;
uint8_t* out = filtered_data;
int row = 1;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
// Leftmost pixel is the same as input for topmost scanline.
out[0] = in[0];
@@ -135,7 +137,7 @@ static void GradientFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* preds = data;
uint8_t* out = filtered_data;
int row = 1;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
// left prediction for top scan-line
out[0] = in[0];
@@ -163,7 +165,7 @@ static void VerticalFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* preds = data;
uint8_t* out = filtered_data;
int row = 1;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
// Very first top-left pixel is copied.
out[0] = in[0];
@@ -182,7 +184,7 @@ static void VerticalFilter_MSA(const uint8_t* data, int width, int height,
}
}
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
// Entry point
diff --git a/media/libwebp/src/dsp/filters_neon.c b/media/libwebp/src/dsp/filters_neon.c
index 3e6a578ea7..b49e515af1 100644
--- a/media/libwebp/src/dsp/filters_neon.c
+++ b/media/libwebp/src/dsp/filters_neon.c
@@ -21,14 +21,16 @@
//------------------------------------------------------------------------------
// Helpful macros.
-# 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.
+#define DCHECK(in, out) \
+ do { \
+ 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. */ \
+ } while (0)
// load eight u8 and widen to s16
#define U8_TO_S16(A) vreinterpretq_s16_u16(vmovl_u8(A))
@@ -71,7 +73,7 @@ static WEBP_INLINE void DoHorizontalFilter_NEON(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -110,7 +112,7 @@ static WEBP_INLINE void DoVerticalFilter_NEON(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -172,7 +174,7 @@ static WEBP_INLINE void DoGradientFilter_NEON(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -201,7 +203,7 @@ static void GradientFilter_NEON(const uint8_t* data, int width, int height,
filtered_data);
}
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
// Inverse transforms
diff --git a/media/libwebp/src/dsp/filters_sse2.c b/media/libwebp/src/dsp/filters_sse2.c
index 5c33ec15e2..bb4b5d5874 100644
--- a/media/libwebp/src/dsp/filters_sse2.c
+++ b/media/libwebp/src/dsp/filters_sse2.c
@@ -23,14 +23,16 @@
//------------------------------------------------------------------------------
// 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.
+#define DCHECK(in, out) \
+ do { \
+ 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. */ \
+ } while (0)
static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred,
uint8_t* dst, int length) {
@@ -78,7 +80,7 @@ static WEBP_INLINE void DoHorizontalFilter_SSE2(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -111,7 +113,7 @@ static WEBP_INLINE void DoVerticalFilter_SSE2(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -174,7 +176,7 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -197,7 +199,7 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
}
}
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
diff --git a/media/libwebp/src/dsp/lossless.h b/media/libwebp/src/dsp/lossless.h
index de60d95d0b..0bf10a1a3d 100644
--- a/media/libwebp/src/dsp/lossless.h
+++ b/media/libwebp/src/dsp/lossless.h
@@ -182,9 +182,9 @@ extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16];
// -----------------------------------------------------------------------------
// Huffman-cost related functions.
-typedef float (*VP8LCostFunc)(const uint32_t* population, int length);
-typedef float (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
- int length);
+typedef uint32_t (*VP8LCostFunc)(const uint32_t* population, int length);
+typedef uint32_t (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
+ int length);
typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256],
const int Y[256]);
diff --git a/media/libwebp/src/dsp/lossless_common.h b/media/libwebp/src/dsp/lossless_common.h
index 6a2f736b5e..d6139b2b57 100644
--- a/media/libwebp/src/dsp/lossless_common.h
+++ b/media/libwebp/src/dsp/lossless_common.h
@@ -16,9 +16,9 @@
#ifndef WEBP_DSP_LOSSLESS_COMMON_H_
#define WEBP_DSP_LOSSLESS_COMMON_H_
-#include "src/webp/types.h"
-
+#include "src/dsp/cpu.h"
#include "src/utils/utils.h"
+#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@@ -166,7 +166,7 @@ uint32_t VP8LSubPixels(uint32_t a, uint32_t b) {
}
//------------------------------------------------------------------------------
-// Transform-related functions use din both encoding and decoding.
+// Transform-related functions used in both encoding and decoding.
// Macros used to create a batch predictor that iteratively uses a
// one-pixel predictor.
diff --git a/media/libwebp/src/dsp/lossless_enc.c b/media/libwebp/src/dsp/lossless_enc.c
index cde1280617..997d56c2ad 100644
--- a/media/libwebp/src/dsp/lossless_enc.c
+++ b/media/libwebp/src/dsp/lossless_enc.c
@@ -636,20 +636,25 @@ void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits,
//------------------------------------------------------------------------------
-static float ExtraCost_C(const uint32_t* population, int length) {
+static uint32_t ExtraCost_C(const uint32_t* population, int length) {
int i;
- float cost = 0.f;
- for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
+ uint32_t cost = population[4] + population[5];
+ assert(length % 2 == 0);
+ for (i = 2; i < length / 2 - 1; ++i) {
+ cost += i * (population[2 * i + 2] + population[2 * i + 3]);
+ }
return cost;
}
-static float ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
- int length) {
+static uint32_t ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
+ int length) {
int i;
- float cost = 0.f;
- for (i = 2; i < length - 2; ++i) {
- const int xy = X[i + 2] + Y[i + 2];
- cost += (i >> 1) * xy;
+ uint32_t cost = X[4] + Y[4] + X[5] + Y[5];
+ assert(length % 2 == 0);
+ for (i = 2; i < length / 2 - 1; ++i) {
+ const int xy0 = X[2 * i + 2] + Y[2 * i + 2];
+ const int xy1 = X[2 * i + 3] + Y[2 * i + 3];
+ cost += i * (xy0 + xy1);
}
return cost;
}
diff --git a/media/libwebp/src/dsp/lossless_enc_mips32.c b/media/libwebp/src/dsp/lossless_enc_mips32.c
index 639f786631..e10f12da9d 100644
--- a/media/libwebp/src/dsp/lossless_enc_mips32.c
+++ b/media/libwebp/src/dsp/lossless_enc_mips32.c
@@ -103,8 +103,8 @@ static float FastLog2Slow_MIPS32(uint32_t v) {
// cost += i * *(pop + 1);
// pop += 2;
// }
-// return (float)cost;
-static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
+// return cost;
+static uint32_t ExtraCost_MIPS32(const uint32_t* const population, int length) {
int i, temp0, temp1;
const uint32_t* pop = &population[4];
const uint32_t* const LoopEnd = &population[length];
@@ -130,7 +130,7 @@ static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
: "memory", "hi", "lo"
);
- return (float)((int64_t)temp0 << 32 | temp1);
+ return ((int64_t)temp0 << 32 | temp1);
}
// C version of this function:
@@ -148,9 +148,9 @@ static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
// pX += 2;
// pY += 2;
// }
-// return (float)cost;
-static float ExtraCostCombined_MIPS32(const uint32_t* const X,
- const uint32_t* const Y, int length) {
+// return cost;
+static uint32_t ExtraCostCombined_MIPS32(const uint32_t* const X,
+ const uint32_t* const Y, int length) {
int i, temp0, temp1, temp2, temp3;
const uint32_t* pX = &X[4];
const uint32_t* pY = &Y[4];
@@ -183,7 +183,7 @@ static float ExtraCostCombined_MIPS32(const uint32_t* const X,
: "memory", "hi", "lo"
);
- return (float)((int64_t)temp0 << 32 | temp1);
+ return ((int64_t)temp0 << 32 | temp1);
}
#define HUFFMAN_COST_PASS \
diff --git a/media/libwebp/src/dsp/lossless_enc_sse41.c b/media/libwebp/src/dsp/lossless_enc_sse41.c
index ad358a6f25..7ab83c2604 100644
--- a/media/libwebp/src/dsp/lossless_enc_sse41.c
+++ b/media/libwebp/src/dsp/lossless_enc_sse41.c
@@ -18,8 +18,53 @@
#include <smmintrin.h>
#include "src/dsp/lossless.h"
-// For sign-extended multiplying constants, pre-shifted by 5:
-#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5)
+//------------------------------------------------------------------------------
+// Cost operations.
+
+static WEBP_INLINE uint32_t HorizontalSum_SSE41(__m128i cost) {
+ cost = _mm_add_epi32(cost, _mm_srli_si128(cost, 8));
+ cost = _mm_add_epi32(cost, _mm_srli_si128(cost, 4));
+ return _mm_cvtsi128_si32(cost);
+}
+
+static uint32_t ExtraCost_SSE41(const uint32_t* const a, int length) {
+ int i;
+ __m128i cost = _mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]);
+ assert(length % 8 == 0);
+
+ for (i = 8; i + 8 <= length; i += 8) {
+ const int j = (i - 2) >> 1;
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]);
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
+ const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j);
+ const __m128i a2 = _mm_hadd_epi32(a0, a1);
+ const __m128i mul = _mm_mullo_epi32(a2, w);
+ cost = _mm_add_epi32(mul, cost);
+ }
+ return HorizontalSum_SSE41(cost);
+}
+
+static uint32_t ExtraCostCombined_SSE41(const uint32_t* const a,
+ const uint32_t* const b, int length) {
+ int i;
+ __m128i cost = _mm_add_epi32(_mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]),
+ _mm_set_epi32(2 * b[7], 2 * b[6], b[5], b[4]));
+ assert(length % 8 == 0);
+
+ for (i = 8; i + 8 <= length; i += 8) {
+ const int j = (i - 2) >> 1;
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]);
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
+ const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[i]);
+ const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[i + 4]);
+ const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j);
+ const __m128i a2 = _mm_hadd_epi32(a0, a1);
+ const __m128i b2 = _mm_hadd_epi32(b0, b1);
+ const __m128i mul = _mm_mullo_epi32(_mm_add_epi32(a2, b2), w);
+ cost = _mm_add_epi32(mul, cost);
+ }
+ return HorizontalSum_SSE41(cost);
+}
//------------------------------------------------------------------------------
// Subtract-Green Transform
@@ -44,6 +89,9 @@ static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data,
//------------------------------------------------------------------------------
// Color Transform
+// For sign-extended multiplying constants, pre-shifted by 5:
+#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5)
+
#define MK_CST_16(HI, LO) \
_mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff)))
@@ -143,6 +191,8 @@ static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride,
extern void VP8LEncDspInitSSE41(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE41(void) {
+ VP8LExtraCost = ExtraCost_SSE41;
+ VP8LExtraCostCombined = ExtraCostCombined_SSE41;
VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_SSE41;
VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE41;
VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE41;
diff --git a/media/libwebp/src/dsp/lossless_neon.c b/media/libwebp/src/dsp/lossless_neon.c
index ddc9b61711..e9960db38a 100644
--- a/media/libwebp/src/dsp/lossless_neon.c
+++ b/media/libwebp/src/dsp/lossless_neon.c
@@ -146,9 +146,9 @@ static void ConvertBGRAToRGB_NEON(const uint32_t* src,
#define LOAD_U32P_AS_U8(IN) vreinterpret_u8_u32(vld1_u32((IN)))
#define LOADQ_U32_AS_U8(IN) vreinterpretq_u8_u32(vdupq_n_u32((IN)))
#define LOADQ_U32P_AS_U8(IN) vreinterpretq_u8_u32(vld1q_u32((IN)))
-#define GET_U8_AS_U32(IN) vget_lane_u32(vreinterpret_u32_u8((IN)), 0);
-#define GETQ_U8_AS_U32(IN) vgetq_lane_u32(vreinterpretq_u32_u8((IN)), 0);
-#define STOREQ_U8_AS_U32P(OUT, IN) vst1q_u32((OUT), vreinterpretq_u32_u8((IN)));
+#define GET_U8_AS_U32(IN) vget_lane_u32(vreinterpret_u32_u8((IN)), 0)
+#define GETQ_U8_AS_U32(IN) vgetq_lane_u32(vreinterpretq_u32_u8((IN)), 0)
+#define STOREQ_U8_AS_U32P(OUT, IN) vst1q_u32((OUT), vreinterpretq_u32_u8((IN)))
#define ROTATE32_LEFT(L) vextq_u8((L), (L), 12) // D|C|B|A -> C|B|A|D
static WEBP_INLINE uint8x8_t Average2_u8_NEON(uint32_t a0, uint32_t a1) {
diff --git a/media/libwebp/src/dsp/mips_macro.h b/media/libwebp/src/dsp/mips_macro.h
index 44aba9b71d..e810d3d382 100644
--- a/media/libwebp/src/dsp/mips_macro.h
+++ b/media/libwebp/src/dsp/mips_macro.h
@@ -45,28 +45,38 @@
"ulw %[" #O2 "], " #I3 "+" XSTR(I9) "*" #I7 "(%[" #I0 "]) \n\t" \
"ulw %[" #O3 "], " #I4 "+" XSTR(I9) "*" #I8 "(%[" #I0 "]) \n\t"
+
+// O - output
+// I - input (macro doesn't change it so it should be different from I)
+#define MUL_SHIFT_C1(O, I) \
+ "mul %[" #O "], %[" #I "], %[kC1] \n\t" \
+ "sra %[" #O "], %[" #O "], 16 \n\t" \
+ "addu %[" #O "], %[" #O "], %[" #I "] \n\t"
+#define MUL_SHIFT_C2(O, I) \
+ "mul %[" #O "], %[" #I "], %[kC2] \n\t" \
+ "sra %[" #O "], %[" #O "], 16 \n\t"
+
+// Same as #define MUL_SHIFT_C1 but I and O are the same. It stores the
+// intermediary result in TMP.
+#define MUL_SHIFT_C1_IO(IO, TMP) \
+ "mul %[" #TMP "], %[" #IO "], %[kC1] \n\t" \
+ "sra %[" #TMP "], %[" #TMP "], 16 \n\t" \
+ "addu %[" #IO "], %[" #TMP "], %[" #IO "] \n\t"
+
// O - output
// IO - input/output
// I - input (macro doesn't change it)
#define MUL_SHIFT_SUM(O0, O1, O2, O3, O4, O5, O6, O7, \
IO0, IO1, IO2, IO3, \
I0, I1, I2, I3, I4, I5, I6, I7) \
- "mul %[" #O0 "], %[" #I0 "], %[kC2] \n\t" \
- "mul %[" #O1 "], %[" #I0 "], %[kC1] \n\t" \
- "mul %[" #O2 "], %[" #I1 "], %[kC2] \n\t" \
- "mul %[" #O3 "], %[" #I1 "], %[kC1] \n\t" \
- "mul %[" #O4 "], %[" #I2 "], %[kC2] \n\t" \
- "mul %[" #O5 "], %[" #I2 "], %[kC1] \n\t" \
- "mul %[" #O6 "], %[" #I3 "], %[kC2] \n\t" \
- "mul %[" #O7 "], %[" #I3 "], %[kC1] \n\t" \
- "sra %[" #O0 "], %[" #O0 "], 16 \n\t" \
- "sra %[" #O1 "], %[" #O1 "], 16 \n\t" \
- "sra %[" #O2 "], %[" #O2 "], 16 \n\t" \
- "sra %[" #O3 "], %[" #O3 "], 16 \n\t" \
- "sra %[" #O4 "], %[" #O4 "], 16 \n\t" \
- "sra %[" #O5 "], %[" #O5 "], 16 \n\t" \
- "sra %[" #O6 "], %[" #O6 "], 16 \n\t" \
- "sra %[" #O7 "], %[" #O7 "], 16 \n\t" \
+ MUL_SHIFT_C2(O0, I0) \
+ MUL_SHIFT_C1(O1, I0) \
+ MUL_SHIFT_C2(O2, I1) \
+ MUL_SHIFT_C1(O3, I1) \
+ MUL_SHIFT_C2(O4, I2) \
+ MUL_SHIFT_C1(O5, I2) \
+ MUL_SHIFT_C2(O6, I3) \
+ MUL_SHIFT_C1(O7, I3) \
"addu %[" #IO0 "], %[" #IO0 "], %[" #I4 "] \n\t" \
"addu %[" #IO1 "], %[" #IO1 "], %[" #I5 "] \n\t" \
"subu %[" #IO2 "], %[" #IO2 "], %[" #I6 "] \n\t" \
diff --git a/media/libwebp/src/dsp/msa_macro.h b/media/libwebp/src/dsp/msa_macro.h
index 51f6c643ab..90adbbc319 100644
--- a/media/libwebp/src/dsp/msa_macro.h
+++ b/media/libwebp/src/dsp/msa_macro.h
@@ -73,27 +73,25 @@
#define ST_UW(...) ST_W(v4u32, __VA_ARGS__)
#define ST_SW(...) ST_W(v4i32, __VA_ARGS__)
-#define MSA_LOAD_FUNC(TYPE, INSTR, FUNC_NAME) \
- static inline TYPE FUNC_NAME(const void* const psrc) { \
- const uint8_t* const psrc_m = (const uint8_t*)psrc; \
- TYPE val_m; \
- asm volatile ( \
- "" #INSTR " %[val_m], %[psrc_m] \n\t" \
- : [val_m] "=r" (val_m) \
- : [psrc_m] "m" (*psrc_m)); \
- return val_m; \
+#define MSA_LOAD_FUNC(TYPE, INSTR, FUNC_NAME) \
+ static inline TYPE FUNC_NAME(const void* const psrc) { \
+ const uint8_t* const psrc_m = (const uint8_t*)psrc; \
+ TYPE val_m; \
+ __asm__ volatile("" #INSTR " %[val_m], %[psrc_m] \n\t" \
+ : [val_m] "=r"(val_m) \
+ : [psrc_m] "m"(*psrc_m)); \
+ return val_m; \
}
#define MSA_LOAD(psrc, FUNC_NAME) FUNC_NAME(psrc)
-#define MSA_STORE_FUNC(TYPE, INSTR, FUNC_NAME) \
- static inline void FUNC_NAME(TYPE val, void* const pdst) { \
- uint8_t* const pdst_m = (uint8_t*)pdst; \
- TYPE val_m = val; \
- asm volatile ( \
- " " #INSTR " %[val_m], %[pdst_m] \n\t" \
- : [pdst_m] "=m" (*pdst_m) \
- : [val_m] "r" (val_m)); \
+#define MSA_STORE_FUNC(TYPE, INSTR, FUNC_NAME) \
+ static inline void FUNC_NAME(TYPE val, void* const pdst) { \
+ uint8_t* const pdst_m = (uint8_t*)pdst; \
+ TYPE val_m = val; \
+ __asm__ volatile(" " #INSTR " %[val_m], %[pdst_m] \n\t" \
+ : [pdst_m] "=m"(*pdst_m) \
+ : [val_m] "r"(val_m)); \
}
#define MSA_STORE(val, pdst, FUNC_NAME) FUNC_NAME(val, pdst)
diff --git a/media/libwebp/src/dsp/quant.h b/media/libwebp/src/dsp/quant.h
index bf7734cb11..dcbc11c77c 100644
--- a/media/libwebp/src/dsp/quant.h
+++ b/media/libwebp/src/dsp/quant.h
@@ -36,8 +36,9 @@ static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
int thresh) {
const int16x8_t tst_ones = vdupq_n_s16(-1);
uint32x4_t sum = vdupq_n_u32(0);
+ int i;
- for (int i = 0; i < num_blocks; ++i) {
+ for (i = 0; i < num_blocks; ++i) {
// Set DC to zero.
const int16x8_t a_0 = vsetq_lane_s16(0, vld1q_s16(levels), 0);
const int16x8_t a_1 = vld1q_s16(levels + 8);
diff --git a/media/libwebp/src/dsp/rescaler_neon.c b/media/libwebp/src/dsp/rescaler_neon.c
index b976a852cf..957a92dbc9 100644
--- a/media/libwebp/src/dsp/rescaler_neon.c
+++ b/media/libwebp/src/dsp/rescaler_neon.c
@@ -32,7 +32,7 @@
#define STORE_32x8(SRC0, SRC1, DST) do { \
vst1q_u32((DST) + 0, SRC0); \
vst1q_u32((DST) + 4, SRC1); \
-} while (0);
+} while (0)
#if (WEBP_RESCALER_RFIX == 32)
#define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1))
diff --git a/media/libwebp/src/dsp/upsampling_sse2.c b/media/libwebp/src/dsp/upsampling_sse2.c
index 08b6d0b1cf..77b4f7221e 100644
--- a/media/libwebp/src/dsp/upsampling_sse2.c
+++ b/media/libwebp/src/dsp/upsampling_sse2.c
@@ -58,7 +58,7 @@
} while (0)
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
-#define UPSAMPLE_32PIXELS(r1, r2, out) { \
+#define UPSAMPLE_32PIXELS(r1, r2, out) do { \
const __m128i one = _mm_set1_epi8(1); \
const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
@@ -85,7 +85,7 @@
/* pack the alternate pixels */ \
PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
-}
+} while (0)
// Turn the macro into a function for reducing code-size when non-critical
static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[],
@@ -229,11 +229,11 @@ static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
} \
}
-YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4);
-YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4);
+YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4)
+YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4)
#if !defined(WEBP_REDUCE_CSP)
-YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3);
-YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3);
+YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3)
+YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3)
YUV444_FUNC(Yuv444ToArgb_SSE2, VP8YuvToArgb32_SSE2, WebPYuv444ToArgb_C, 4)
YUV444_FUNC(Yuv444ToRgba4444_SSE2, VP8YuvToRgba444432_SSE2, \
WebPYuv444ToRgba4444_C, 2)
diff --git a/media/libwebp/src/dsp/upsampling_sse41.c b/media/libwebp/src/dsp/upsampling_sse41.c
index 648d456027..e38c88d5e6 100644
--- a/media/libwebp/src/dsp/upsampling_sse41.c
+++ b/media/libwebp/src/dsp/upsampling_sse41.c
@@ -60,7 +60,7 @@
} while (0)
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
-#define UPSAMPLE_32PIXELS(r1, r2, out) { \
+#define UPSAMPLE_32PIXELS(r1, r2, out) do { \
const __m128i one = _mm_set1_epi8(1); \
const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
@@ -87,7 +87,7 @@
/* pack the alternate pixels */ \
PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
-}
+} while (0)
// Turn the macro into a function for reducing code-size when non-critical
static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[],
@@ -217,8 +217,8 @@ static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
}
#if !defined(WEBP_REDUCE_CSP)
-YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3);
-YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3);
+YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3)
+YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3)
#endif // WEBP_REDUCE_CSP
WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE41(void) {
diff --git a/media/libwebp/src/enc/alpha_enc.c b/media/libwebp/src/enc/alpha_enc.c
index 26f003485a..c11a261c8a 100644
--- a/media/libwebp/src/enc/alpha_enc.c
+++ b/media/libwebp/src/enc/alpha_enc.c
@@ -20,6 +20,7 @@
#include "src/utils/filters_utils.h"
#include "src/utils/quant_levels_utils.h"
#include "src/utils/utils.h"
+#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
// -----------------------------------------------------------------------------
@@ -55,7 +56,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
WebPConfig config;
WebPPicture picture;
- WebPPictureInit(&picture);
+ if (!WebPPictureInit(&picture)) return 0;
picture.width = width;
picture.height = height;
picture.use_argb = 1;
@@ -66,7 +67,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
WebPDispatchAlphaToGreen(data, width, picture.width, picture.height,
picture.argb, picture.argb_stride);
- WebPConfigInit(&config);
+ if (!WebPConfigInit(&config)) return 0;
config.lossless = 1;
// Enable exact, or it would alter RGB values of transparent alpha, which is
// normally OK but not here since we are not encoding the input image but an
@@ -83,11 +84,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
(use_quality_100 && effort_level == 6) ? 100 : 8.f * effort_level;
assert(config.quality >= 0 && config.quality <= 100.f);
- // TODO(urvang): Temporary fix to avoid generating images that trigger
- // a decoder bug related to alpha with color cache.
- // See: https://code.google.com/p/webp/issues/detail?id=239
- // Need to re-enable this later.
- ok = VP8LEncodeStream(&config, &picture, bw, /*use_cache=*/0);
+ ok = VP8LEncodeStream(&config, &picture, bw);
WebPPictureFree(&picture);
ok = ok && !bw->error_;
if (!ok) {
diff --git a/media/libwebp/src/enc/frame_enc.c b/media/libwebp/src/enc/frame_enc.c
index 9a98dc1f3e..01860ca757 100644
--- a/media/libwebp/src/enc/frame_enc.c
+++ b/media/libwebp/src/enc/frame_enc.c
@@ -578,7 +578,7 @@ static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt,
uint64_t size = 0;
uint64_t size_p0 = 0;
uint64_t distortion = 0;
- const uint64_t pixel_count = nb_mbs * 384;
+ const uint64_t pixel_count = (uint64_t)nb_mbs * 384;
VP8IteratorInit(enc, &it);
SetLoopParams(enc, s->q);
@@ -789,7 +789,7 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
VP8EncIterator it;
VP8EncProba* const proba = &enc->proba_;
const VP8RDLevel rd_opt = enc->rd_opt_level_;
- const uint64_t pixel_count = enc->mb_w_ * enc->mb_h_ * 384;
+ const uint64_t pixel_count = (uint64_t)enc->mb_w_ * enc->mb_h_ * 384;
PassStats stats;
int ok;
diff --git a/media/libwebp/src/enc/histogram_enc.c b/media/libwebp/src/enc/histogram_enc.c
index 8418def2e1..3ca67b3ad0 100644
--- a/media/libwebp/src/enc/histogram_enc.c
+++ b/media/libwebp/src/enc/histogram_enc.c
@@ -358,15 +358,17 @@ static WEBP_INLINE float GetCombinedEntropy(const uint32_t* const X,
// Estimates the Entropy + Huffman + other block overhead size cost.
float VP8LHistogramEstimateBits(VP8LHistogram* const p) {
- return
- 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);
+ return 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]) +
+ (float)VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES,
+ NUM_LENGTH_CODES) +
+ (float)VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES);
}
// -----------------------------------------------------------------------------
@@ -381,9 +383,9 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
*cost += GetCombinedEntropy(a->literal_, b->literal_,
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);
+ *cost += (float)VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES,
+ b->literal_ + NUM_LITERAL_CODES,
+ NUM_LENGTH_CODES);
if (*cost > cost_threshold) return 0;
if (a->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM &&
@@ -417,8 +419,8 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
*cost +=
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);
+ *cost += (float)VP8LExtraCostCombined(a->distance_, b->distance_,
+ NUM_DISTANCE_CODES);
if (*cost > cost_threshold) return 0;
return 1;
@@ -506,11 +508,11 @@ static void UpdateHistogramCost(VP8LHistogram* const h) {
PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]);
const float distance_cost =
PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) +
- VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
+ (float)VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_);
h->literal_cost_ =
PopulationCost(h->literal_, num_codes, NULL, &h->is_used_[0]) +
- VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES);
+ (float)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_ =
@@ -1179,7 +1181,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
int entropy_combine;
uint16_t* const map_tmp =
- WebPSafeMalloc(2 * image_histo_raw_size, sizeof(map_tmp));
+ WebPSafeMalloc(2 * image_histo_raw_size, sizeof(*map_tmp));
uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size;
int num_used = image_histo_raw_size;
if (orig_histo == NULL || map_tmp == NULL) {
diff --git a/media/libwebp/src/enc/picture_enc.c b/media/libwebp/src/enc/picture_enc.c
index 3af6383d38..5a2703541f 100644
--- a/media/libwebp/src/enc/picture_enc.c
+++ b/media/libwebp/src/enc/picture_enc.c
@@ -12,10 +12,10 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
+#include <limits.h>
#include <stdlib.h>
#include "src/enc/vp8i_enc.h"
-#include "src/dsp/dsp.h"
#include "src/utils/utils.h"
//------------------------------------------------------------------------------
diff --git a/media/libwebp/src/enc/vp8i_enc.h b/media/libwebp/src/enc/vp8i_enc.h
index 0864fbf1f5..00ff1be795 100644
--- a/media/libwebp/src/enc/vp8i_enc.h
+++ b/media/libwebp/src/enc/vp8i_enc.h
@@ -31,8 +31,8 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
-#define ENC_MIN_VERSION 3
-#define ENC_REV_VERSION 2
+#define ENC_MIN_VERSION 4
+#define ENC_REV_VERSION 0
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
diff --git a/media/libwebp/src/enc/vp8l_enc.c b/media/libwebp/src/enc/vp8l_enc.c
index 3a8ec3dd1e..40eafa4169 100644
--- a/media/libwebp/src/enc/vp8l_enc.c
+++ b/media/libwebp/src/enc/vp8l_enc.c
@@ -23,6 +23,7 @@
#include "src/enc/vp8li_enc.h"
#include "src/utils/bit_writer_utils.h"
#include "src/utils/huffman_encode_utils.h"
+#include "src/utils/palette.h"
#include "src/utils/utils.h"
#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
@@ -30,298 +31,6 @@
// Maximum number of histogram images (sub-blocks).
#define MAX_HUFF_IMAGE_SIZE 2600
-// Palette reordering for smaller sum of deltas (and for smaller storage).
-
-static int PaletteCompareColorsForQsort(const void* p1, const void* p2) {
- const uint32_t a = WebPMemToUint32((uint8_t*)p1);
- const uint32_t b = WebPMemToUint32((uint8_t*)p2);
- assert(a != b);
- return (a < b) ? -1 : 1;
-}
-
-static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) {
- return (v <= 128) ? v : (256 - v);
-}
-
-// Computes a value that is related to the entropy created by the
-// palette entry diff.
-//
-// Note that the last & 0xff is a no-operation in the next statement, but
-// removed by most compilers and is here only for regularity of the code.
-static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) {
- const uint32_t diff = VP8LSubPixels(col1, col2);
- const int kMoreWeightForRGBThanForAlpha = 9;
- uint32_t score;
- score = PaletteComponentDistance((diff >> 0) & 0xff);
- score += PaletteComponentDistance((diff >> 8) & 0xff);
- score += PaletteComponentDistance((diff >> 16) & 0xff);
- score *= kMoreWeightForRGBThanForAlpha;
- score += PaletteComponentDistance((diff >> 24) & 0xff);
- return score;
-}
-
-static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
- const uint32_t tmp = *col1;
- *col1 = *col2;
- *col2 = tmp;
-}
-
-static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
- int num_colors) {
- int low = 0, hi = num_colors;
- if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
- while (1) {
- const int mid = (low + hi) >> 1;
- if (sorted[mid] == color) {
- return mid;
- } else if (sorted[mid] < color) {
- low = mid;
- } else {
- hi = mid;
- }
- }
- assert(0);
- return 0;
-}
-
-// The palette has been sorted by alpha. This function checks if the other
-// components of the palette have a monotonic development with regards to
-// position in the palette. If all have monotonic development, there is
-// no benefit to re-organize them greedily. A monotonic development
-// would be spotted in green-only situations (like lossy alpha) or gray-scale
-// images.
-static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
- int num_colors) {
- uint32_t predict = 0x000000;
- int i;
- uint8_t sign_found = 0x00;
- for (i = 0; i < num_colors; ++i) {
- const uint32_t diff = VP8LSubPixels(palette[i], predict);
- const uint8_t rd = (diff >> 16) & 0xff;
- const uint8_t gd = (diff >> 8) & 0xff;
- const uint8_t bd = (diff >> 0) & 0xff;
- if (rd != 0x00) {
- sign_found |= (rd < 0x80) ? 1 : 2;
- }
- if (gd != 0x00) {
- sign_found |= (gd < 0x80) ? 8 : 16;
- }
- if (bd != 0x00) {
- sign_found |= (bd < 0x80) ? 64 : 128;
- }
- predict = palette[i];
- }
- return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
-}
-
-static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
- int num_colors, uint32_t* const palette) {
- uint32_t predict = 0x00000000;
- int i, k;
- memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
- if (!PaletteHasNonMonotonousDeltas(palette_sorted, num_colors)) return;
- // Find greedily always the closest color of the predicted color to minimize
- // deltas in the palette. This reduces storage needs since the
- // palette is stored with delta encoding.
- for (i = 0; i < num_colors; ++i) {
- int best_ix = i;
- uint32_t best_score = ~0U;
- for (k = i; k < num_colors; ++k) {
- const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
- if (best_score > cur_score) {
- best_score = cur_score;
- best_ix = k;
- }
- }
- SwapColor(&palette[best_ix], &palette[i]);
- predict = palette[i];
- }
-}
-
-// Sort palette in increasing order and prepare an inverse mapping array.
-static void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
- uint32_t sorted[], uint32_t idx_map[]) {
- uint32_t i;
- memcpy(sorted, palette, num_colors * sizeof(*sorted));
- qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
- for (i = 0; i < num_colors; ++i) {
- idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
- }
-}
-
-// -----------------------------------------------------------------------------
-// Modified Zeng method from "A Survey on Palette Reordering
-// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
-// Pinho and Antonio J. R. Neves.
-
-// Finds the biggest cooccurrence in the matrix.
-static void CoOccurrenceFindMax(const uint32_t* const cooccurrence,
- uint32_t num_colors, uint8_t* const c1,
- uint8_t* const c2) {
- // Find the index that is most frequently located adjacent to other
- // (different) indexes.
- uint32_t best_sum = 0u;
- uint32_t i, j, best_cooccurrence;
- *c1 = 0u;
- for (i = 0; i < num_colors; ++i) {
- uint32_t sum = 0;
- for (j = 0; j < num_colors; ++j) sum += cooccurrence[i * num_colors + j];
- if (sum > best_sum) {
- best_sum = sum;
- *c1 = i;
- }
- }
- // Find the index that is most frequently found adjacent to *c1.
- *c2 = 0u;
- best_cooccurrence = 0u;
- for (i = 0; i < num_colors; ++i) {
- if (cooccurrence[*c1 * num_colors + i] > best_cooccurrence) {
- best_cooccurrence = cooccurrence[*c1 * num_colors + i];
- *c2 = i;
- }
- }
- assert(*c1 != *c2);
-}
-
-// Builds the cooccurrence matrix
-static int CoOccurrenceBuild(const WebPPicture* const pic,
- const uint32_t* const palette, uint32_t num_colors,
- uint32_t* cooccurrence) {
- uint32_t *lines, *line_top, *line_current, *line_tmp;
- int x, y;
- const uint32_t* src = pic->argb;
- uint32_t prev_pix = ~src[0];
- uint32_t prev_idx = 0u;
- uint32_t idx_map[MAX_PALETTE_SIZE] = {0};
- uint32_t palette_sorted[MAX_PALETTE_SIZE];
- lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines));
- if (lines == NULL) {
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- }
- line_top = &lines[0];
- line_current = &lines[pic->width];
- PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map);
- for (y = 0; y < pic->height; ++y) {
- for (x = 0; x < pic->width; ++x) {
- const uint32_t pix = src[x];
- if (pix != prev_pix) {
- prev_idx = idx_map[SearchColorNoIdx(palette_sorted, pix, num_colors)];
- prev_pix = pix;
- }
- line_current[x] = prev_idx;
- // 4-connectivity is what works best as mentioned in "On the relation
- // between Memon's and the modified Zeng's palette reordering methods".
- if (x > 0 && prev_idx != line_current[x - 1]) {
- const uint32_t left_idx = line_current[x - 1];
- ++cooccurrence[prev_idx * num_colors + left_idx];
- ++cooccurrence[left_idx * num_colors + prev_idx];
- }
- if (y > 0 && prev_idx != line_top[x]) {
- const uint32_t top_idx = line_top[x];
- ++cooccurrence[prev_idx * num_colors + top_idx];
- ++cooccurrence[top_idx * num_colors + prev_idx];
- }
- }
- line_tmp = line_top;
- line_top = line_current;
- line_current = line_tmp;
- src += pic->argb_stride;
- }
- WebPSafeFree(lines);
- return 1;
-}
-
-struct Sum {
- uint8_t index;
- uint32_t sum;
-};
-
-// Implements the modified Zeng method from "A Survey on Palette Reordering
-// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
-// Pinho and Antonio J. R. Neves.
-static int PaletteSortModifiedZeng(
- const WebPPicture* const pic, const uint32_t* const palette_sorted,
- uint32_t num_colors, uint32_t* const palette) {
- uint32_t i, j, ind;
- uint8_t remapping[MAX_PALETTE_SIZE];
- uint32_t* cooccurrence;
- struct Sum sums[MAX_PALETTE_SIZE];
- uint32_t first, last;
- uint32_t num_sums;
- // TODO(vrabaud) check whether one color images should use palette or not.
- if (num_colors <= 1) return 1;
- // Build the co-occurrence matrix.
- cooccurrence =
- (uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
- if (cooccurrence == NULL) {
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- }
- if (!CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence)) {
- WebPSafeFree(cooccurrence);
- return 0;
- }
-
- // Initialize the mapping list with the two best indices.
- CoOccurrenceFindMax(cooccurrence, num_colors, &remapping[0], &remapping[1]);
-
- // We need to append and prepend to the list of remapping. To this end, we
- // actually define the next start/end of the list as indices in a vector (with
- // a wrap around when the end is reached).
- first = 0;
- last = 1;
- num_sums = num_colors - 2; // -2 because we know the first two values
- if (num_sums > 0) {
- // Initialize the sums with the first two remappings and find the best one
- struct Sum* best_sum = &sums[0];
- best_sum->index = 0u;
- best_sum->sum = 0u;
- for (i = 0, j = 0; i < num_colors; ++i) {
- if (i == remapping[0] || i == remapping[1]) continue;
- sums[j].index = i;
- sums[j].sum = cooccurrence[i * num_colors + remapping[0]] +
- cooccurrence[i * num_colors + remapping[1]];
- if (sums[j].sum > best_sum->sum) best_sum = &sums[j];
- ++j;
- }
-
- while (num_sums > 0) {
- const uint8_t best_index = best_sum->index;
- // Compute delta to know if we need to prepend or append the best index.
- int32_t delta = 0;
- const int32_t n = num_colors - num_sums;
- for (ind = first, j = 0; (ind + j) % num_colors != last + 1; ++j) {
- const uint16_t l_j = remapping[(ind + j) % num_colors];
- delta += (n - 1 - 2 * (int32_t)j) *
- (int32_t)cooccurrence[best_index * num_colors + l_j];
- }
- if (delta > 0) {
- first = (first == 0) ? num_colors - 1 : first - 1;
- remapping[first] = best_index;
- } else {
- ++last;
- remapping[last] = best_index;
- }
- // Remove best_sum from sums.
- *best_sum = sums[num_sums - 1];
- --num_sums;
- // Update all the sums and find the best one.
- best_sum = &sums[0];
- for (i = 0; i < num_sums; ++i) {
- sums[i].sum += cooccurrence[best_index * num_colors + sums[i].index];
- if (sums[i].sum > best_sum->sum) best_sum = &sums[i];
- }
- }
- }
- assert((last + 1) % num_colors == first);
- WebPSafeFree(cooccurrence);
-
- // Re-map the palette.
- for (i = 0; i < num_colors; ++i) {
- palette[i] = palette_sorted[remapping[(first + i) % num_colors]];
- }
- return 1;
-}
-
// -----------------------------------------------------------------------------
// Palette
@@ -337,13 +46,6 @@ typedef enum {
} EntropyIx;
typedef enum {
- kSortedDefault = 0,
- kMinimizeDelta = 1,
- kModifiedZeng = 2,
- kUnusedPalette = 3,
-} PaletteSorting;
-
-typedef enum {
kHistoAlpha = 0,
kHistoAlphaPred,
kHistoGreen,
@@ -565,7 +267,7 @@ typedef struct {
// +2 because we add a palette sorting configuration for kPalette and
// kPaletteAndSpatial.
-#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2)
+#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2 * kPaletteSortingNum)
static int EncoderAnalyze(VP8LEncoder* const enc,
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],
@@ -586,13 +288,10 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
assert(pic != NULL && pic->argb != NULL);
// Check whether a palette is possible.
- enc->palette_size_ = WebPGetColorPalette(pic, enc->palette_sorted_);
+ enc->palette_size_ = GetColorPalette(pic, enc->palette_sorted_);
use_palette = (enc->palette_size_ <= MAX_PALETTE_SIZE);
if (!use_palette) {
enc->palette_size_ = 0;
- } else {
- qsort(enc->palette_sorted_, enc->palette_size_,
- sizeof(*enc->palette_sorted_), PaletteCompareColorsForQsort);
}
// Empirical bit sizes.
@@ -625,20 +324,29 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
// a palette.
if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) {
assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX);
- crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) {
- crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
- kMinimizeDelta;
- ++*crunch_configs_size;
- // Also add modified Zeng's method.
- crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
- crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
- kModifiedZeng;
+ int sorting_method;
+ for (sorting_method = 0; sorting_method < kPaletteSortingNum;
+ ++sorting_method) {
+ const PaletteSorting typed_sorting_method =
+ (PaletteSorting)sorting_method;
+ // TODO(vrabaud) kSortedDefault should be tested. It is omitted
+ // for now for backward compatibility.
+ if (typed_sorting_method == kUnusedPalette ||
+ typed_sorting_method == kSortedDefault) {
+ continue;
+ }
+ crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
+ crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
+ typed_sorting_method;
+ ++*crunch_configs_size;
+ }
} else {
+ crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
kUnusedPalette;
+ ++*crunch_configs_size;
}
- ++*crunch_configs_size;
}
}
} else {
@@ -1112,10 +820,10 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
static int EncodeImageInternal(
VP8LBitWriter* const bw, const uint32_t* const argb,
VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width,
- int height, int quality, int low_effort, int use_cache,
- const CrunchConfig* const config, int* cache_bits, int histogram_bits,
- size_t init_byte_position, int* const hdr_size, int* const data_size,
- const WebPPicture* const pic, int percent_range, int* const percent) {
+ int height, int quality, int low_effort, const CrunchConfig* const config,
+ int* cache_bits, int histogram_bits, size_t init_byte_position,
+ int* const hdr_size, int* const data_size, const WebPPicture* const pic,
+ int percent_range, int* const percent) {
const uint32_t histogram_image_xysize =
VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits);
@@ -1163,13 +871,9 @@ static int EncodeImageInternal(
percent_start += percent_range;
remaining_percent -= percent_range;
- if (use_cache) {
- // If the value is different from zero, it has been set during the
- // palette analysis.
- cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits;
- } else {
- cache_bits_init = 0;
- }
+ // If the value is different from zero, it has been set during the palette
+ // analysis.
+ cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits;
// If several iterations will happen, clone into bw_best.
if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) &&
!VP8LBitWriterClone(bw, &bw_best)) {
@@ -1485,7 +1189,7 @@ static void ClearTransformBuffer(VP8LEncoder* const enc) {
// enc->use_predict_, enc->use_cross_color_
static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
int height) {
- const uint64_t image_size = width * height;
+ const uint64_t image_size = (uint64_t)width * height;
// VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
// pixel in each, plus 2 regular scanlines of bytes.
// TODO(skal): Clean up by using arithmetic in bytes instead of words.
@@ -1495,7 +1199,7 @@ static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
: 0;
const uint64_t transform_data_size =
(enc->use_predict_ || enc->use_cross_color_)
- ? VP8LSubSampleSize(width, enc->transform_bits_) *
+ ? (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) *
VP8LSubSampleSize(height, enc->transform_bits_)
: 0;
const uint64_t max_alignment_in_words =
@@ -1758,7 +1462,6 @@ typedef struct {
const WebPPicture* picture_;
VP8LBitWriter* bw_;
VP8LEncoder* enc_;
- int use_cache_;
CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX];
int num_crunch_configs_;
int red_and_blue_always_zero_;
@@ -1771,7 +1474,6 @@ static int EncodeStreamHook(void* input, void* data2) {
const WebPPicture* const picture = params->picture_;
VP8LBitWriter* const bw = params->bw_;
VP8LEncoder* const enc = params->enc_;
- const int use_cache = params->use_cache_;
const CrunchConfig* const crunch_configs = params->crunch_configs_;
const int num_crunch_configs = params->num_crunch_configs_;
const int red_and_blue_always_zero = params->red_and_blue_always_zero_;
@@ -1845,19 +1547,11 @@ static int EncodeStreamHook(void* input, void* data2) {
// Encode palette
if (enc->use_palette_) {
- if (crunch_configs[idx].palette_sorting_type_ == kSortedDefault) {
- // Nothing to do, we have already sorted the palette.
- memcpy(enc->palette_, enc->palette_sorted_,
- enc->palette_size_ * sizeof(*enc->palette_));
- } else if (crunch_configs[idx].palette_sorting_type_ == kMinimizeDelta) {
- PaletteSortMinimizeDeltas(enc->palette_sorted_, enc->palette_size_,
- enc->palette_);
- } else {
- assert(crunch_configs[idx].palette_sorting_type_ == kModifiedZeng);
- if (!PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
- enc->palette_size_, enc->palette_)) {
- goto Error;
- }
+ if (!PaletteSort(crunch_configs[idx].palette_sorting_type_, enc->pic_,
+ enc->palette_sorted_, enc->palette_size_,
+ enc->palette_)) {
+ WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
}
percent_range = remaining_percent / 4;
if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) {
@@ -1867,7 +1561,7 @@ static int EncodeStreamHook(void* input, void* data2) {
if (!MapImageFromPalette(enc, use_delta_palette)) goto Error;
// If using a color cache, do not have it bigger than the number of
// colors.
- if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
+ if (enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1;
}
}
@@ -1911,7 +1605,7 @@ static int EncodeStreamHook(void* input, void* data2) {
// Encode and write the transformed image.
if (!EncodeImageInternal(
bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_,
- height, quality, low_effort, use_cache, &crunch_configs[idx],
+ height, quality, low_effort, &crunch_configs[idx],
&enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size,
&data_size, picture, remaining_percent, &percent)) {
goto Error;
@@ -1953,7 +1647,7 @@ static int EncodeStreamHook(void* input, void* data2) {
int VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture,
- VP8LBitWriter* const bw_main, int use_cache) {
+ VP8LBitWriter* const bw_main) {
VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture);
VP8LEncoder* enc_side = NULL;
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX];
@@ -1975,7 +1669,9 @@ int VP8LEncodeStream(const WebPConfig* const config,
}
// Avoid "garbage value" error from Clang's static analysis tool.
- WebPPictureInit(&picture_side);
+ if (!WebPPictureInit(&picture_side)) {
+ goto Error;
+ }
// Analyze image (entropy, num_palettes etc)
if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
@@ -2010,7 +1706,6 @@ int VP8LEncodeStream(const WebPConfig* const config,
StreamEncodeContext* const param =
(idx == 0) ? &params_main : &params_side;
param->config_ = config;
- param->use_cache_ = use_cache;
param->red_and_blue_always_zero_ = red_and_blue_always_zero;
if (idx == 0) {
param->picture_ = picture;
@@ -2164,7 +1859,7 @@ int VP8LEncodeImage(const WebPConfig* const config,
if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort;
// Encode main image stream.
- if (!VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/)) goto Error;
+ if (!VP8LEncodeStream(config, picture, &bw)) goto Error;
if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort;
diff --git a/media/libwebp/src/enc/vp8li_enc.h b/media/libwebp/src/enc/vp8li_enc.h
index 3d35e1612d..c5b60dcb39 100644
--- a/media/libwebp/src/enc/vp8li_enc.h
+++ b/media/libwebp/src/enc/vp8li_enc.h
@@ -88,11 +88,9 @@ int VP8LEncodeImage(const WebPConfig* const config,
const WebPPicture* const picture);
// Encodes the main image stream using the supplied bit writer.
-// If 'use_cache' is false, disables the use of color cache.
// Returns false in case of error (stored in picture->error_code).
int VP8LEncodeStream(const WebPConfig* const config,
- const WebPPicture* const picture, VP8LBitWriter* const bw,
- int use_cache);
+ const WebPPicture* const picture, VP8LBitWriter* const bw);
#if (WEBP_NEAR_LOSSLESS == 1)
// in near_lossless.c
diff --git a/media/libwebp/src/utils/huffman_utils.c b/media/libwebp/src/utils/huffman_utils.c
index cf73abd437..16f9faaa9a 100644
--- a/media/libwebp/src/utils/huffman_utils.c
+++ b/media/libwebp/src/utils/huffman_utils.c
@@ -122,6 +122,9 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
const int symbol_code_length = code_lengths[symbol];
if (code_lengths[symbol] > 0) {
if (sorted != NULL) {
+ if(offset[symbol_code_length] >= code_lengths_size) {
+ return 0;
+ }
sorted[offset[symbol_code_length]++] = symbol;
} else {
offset[symbol_code_length]++;
@@ -267,11 +270,11 @@ int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
// Have 'segment' point to the first segment for now, 'root'.
HuffmanTablesSegment* const root = &huffman_tables->root;
huffman_tables->curr_segment = root;
+ root->next = NULL;
// Allocate root.
root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
if (root->start == NULL) return 0;
root->curr_table = root->start;
- root->next = NULL;
root->size = size;
return 1;
}
diff --git a/media/libwebp/src/utils/huffman_utils.h b/media/libwebp/src/utils/huffman_utils.h
index 98415c5328..d511dc052c 100644
--- a/media/libwebp/src/utils/huffman_utils.h
+++ b/media/libwebp/src/utils/huffman_utils.h
@@ -63,7 +63,8 @@ typedef struct HuffmanTables {
// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
// memory allocation error, 1 otherwise.
-int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables);
+WEBP_NODISCARD int VP8LHuffmanTablesAllocate(int size,
+ HuffmanTables* huffman_tables);
void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
#define HUFFMAN_PACKED_BITS 6
@@ -91,7 +92,7 @@ struct HTreeGroup {
};
// Creates the instance of HTreeGroup with specified number of tree-groups.
-HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups);
+WEBP_NODISCARD HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups);
// Releases the memory allocated for HTreeGroup.
void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
@@ -101,8 +102,10 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
// the huffman table.
// Returns built table size or 0 in case of error (invalid tree or
// memory error).
-int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
- const int code_lengths[], int code_lengths_size);
+WEBP_NODISCARD int VP8LBuildHuffmanTable(HuffmanTables* const root_table,
+ int root_bits,
+ const int code_lengths[],
+ int code_lengths_size);
#ifdef __cplusplus
} // extern "C"
diff --git a/media/libwebp/src/utils/moz.build b/media/libwebp/src/utils/moz.build
index b4a01a8ada..2594c2493a 100644
--- a/media/libwebp/src/utils/moz.build
+++ b/media/libwebp/src/utils/moz.build
@@ -11,6 +11,7 @@ SOURCES += [
'filters_utils.c',
'huffman_encode_utils.c',
'huffman_utils.c',
+ 'palette.c',
'quant_levels_dec_utils.c',
'quant_levels_utils.c',
'random_utils.c',
diff --git a/media/libwebp/src/utils/palette.c b/media/libwebp/src/utils/palette.c
new file mode 100644
index 0000000000..515da21019
--- /dev/null
+++ b/media/libwebp/src/utils/palette.c
@@ -0,0 +1,402 @@
+// Copyright 2023 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.
+// -----------------------------------------------------------------------------
+//
+// Utilities for palette analysis.
+//
+// Author: Vincent Rabaud (vrabaud@google.com)
+
+#include "src/utils/palette.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "src/dsp/lossless_common.h"
+#include "src/utils/color_cache_utils.h"
+#include "src/utils/utils.h"
+#include "src/webp/encode.h"
+#include "src/webp/format_constants.h"
+
+// -----------------------------------------------------------------------------
+
+// Palette reordering for smaller sum of deltas (and for smaller storage).
+
+static int PaletteCompareColorsForQsort(const void* p1, const void* p2) {
+ const uint32_t a = WebPMemToUint32((uint8_t*)p1);
+ const uint32_t b = WebPMemToUint32((uint8_t*)p2);
+ assert(a != b);
+ return (a < b) ? -1 : 1;
+}
+
+static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) {
+ return (v <= 128) ? v : (256 - v);
+}
+
+// Computes a value that is related to the entropy created by the
+// palette entry diff.
+//
+// Note that the last & 0xff is a no-operation in the next statement, but
+// removed by most compilers and is here only for regularity of the code.
+static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) {
+ const uint32_t diff = VP8LSubPixels(col1, col2);
+ const int kMoreWeightForRGBThanForAlpha = 9;
+ uint32_t score;
+ score = PaletteComponentDistance((diff >> 0) & 0xff);
+ score += PaletteComponentDistance((diff >> 8) & 0xff);
+ score += PaletteComponentDistance((diff >> 16) & 0xff);
+ score *= kMoreWeightForRGBThanForAlpha;
+ score += PaletteComponentDistance((diff >> 24) & 0xff);
+ return score;
+}
+
+static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
+ const uint32_t tmp = *col1;
+ *col1 = *col2;
+ *col2 = tmp;
+}
+
+int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, int num_colors) {
+ int low = 0, hi = num_colors;
+ if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
+ while (1) {
+ const int mid = (low + hi) >> 1;
+ if (sorted[mid] == color) {
+ return mid;
+ } else if (sorted[mid] < color) {
+ low = mid;
+ } else {
+ hi = mid;
+ }
+ }
+ assert(0);
+ return 0;
+}
+
+void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
+ uint32_t sorted[], uint32_t idx_map[]) {
+ uint32_t i;
+ memcpy(sorted, palette, num_colors * sizeof(*sorted));
+ qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
+ for (i = 0; i < num_colors; ++i) {
+ idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+#define COLOR_HASH_SIZE (MAX_PALETTE_SIZE * 4)
+#define COLOR_HASH_RIGHT_SHIFT 22 // 32 - log2(COLOR_HASH_SIZE).
+
+int GetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
+ int i;
+ int x, y;
+ int num_colors = 0;
+ uint8_t in_use[COLOR_HASH_SIZE] = {0};
+ uint32_t colors[COLOR_HASH_SIZE] = {0};
+ const uint32_t* argb = pic->argb;
+ const int width = pic->width;
+ const int height = pic->height;
+ uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
+ assert(pic != NULL);
+ assert(pic->use_argb);
+
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ int key;
+ if (argb[x] == last_pix) {
+ continue;
+ }
+ last_pix = argb[x];
+ key = VP8LHashPix(last_pix, COLOR_HASH_RIGHT_SHIFT);
+ while (1) {
+ if (!in_use[key]) {
+ colors[key] = last_pix;
+ in_use[key] = 1;
+ ++num_colors;
+ if (num_colors > MAX_PALETTE_SIZE) {
+ return MAX_PALETTE_SIZE + 1; // Exact count not needed.
+ }
+ break;
+ } else if (colors[key] == last_pix) {
+ break; // The color is already there.
+ } else {
+ // Some other color sits here, so do linear conflict resolution.
+ ++key;
+ key &= (COLOR_HASH_SIZE - 1); // Key mask.
+ }
+ }
+ }
+ argb += pic->argb_stride;
+ }
+
+ if (palette != NULL) { // Fill the colors into palette.
+ num_colors = 0;
+ for (i = 0; i < COLOR_HASH_SIZE; ++i) {
+ if (in_use[i]) {
+ palette[num_colors] = colors[i];
+ ++num_colors;
+ }
+ }
+ qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
+ }
+ return num_colors;
+}
+
+#undef COLOR_HASH_SIZE
+#undef COLOR_HASH_RIGHT_SHIFT
+
+// -----------------------------------------------------------------------------
+
+// The palette has been sorted by alpha. This function checks if the other
+// components of the palette have a monotonic development with regards to
+// position in the palette. If all have monotonic development, there is
+// no benefit to re-organize them greedily. A monotonic development
+// would be spotted in green-only situations (like lossy alpha) or gray-scale
+// images.
+static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
+ int num_colors) {
+ uint32_t predict = 0x000000;
+ int i;
+ uint8_t sign_found = 0x00;
+ for (i = 0; i < num_colors; ++i) {
+ const uint32_t diff = VP8LSubPixels(palette[i], predict);
+ const uint8_t rd = (diff >> 16) & 0xff;
+ const uint8_t gd = (diff >> 8) & 0xff;
+ const uint8_t bd = (diff >> 0) & 0xff;
+ if (rd != 0x00) {
+ sign_found |= (rd < 0x80) ? 1 : 2;
+ }
+ if (gd != 0x00) {
+ sign_found |= (gd < 0x80) ? 8 : 16;
+ }
+ if (bd != 0x00) {
+ sign_found |= (bd < 0x80) ? 64 : 128;
+ }
+ predict = palette[i];
+ }
+ return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
+}
+
+static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
+ int num_colors, uint32_t* const palette) {
+ uint32_t predict = 0x00000000;
+ int i, k;
+ memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
+ if (!PaletteHasNonMonotonousDeltas(palette_sorted, num_colors)) return;
+ // Find greedily always the closest color of the predicted color to minimize
+ // deltas in the palette. This reduces storage needs since the
+ // palette is stored with delta encoding.
+ for (i = 0; i < num_colors; ++i) {
+ int best_ix = i;
+ uint32_t best_score = ~0U;
+ for (k = i; k < num_colors; ++k) {
+ const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
+ if (best_score > cur_score) {
+ best_score = cur_score;
+ best_ix = k;
+ }
+ }
+ SwapColor(&palette[best_ix], &palette[i]);
+ predict = palette[i];
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Modified Zeng method from "A Survey on Palette Reordering
+// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
+// Pinho and Antonio J. R. Neves.
+
+// Finds the biggest cooccurrence in the matrix.
+static void CoOccurrenceFindMax(const uint32_t* const cooccurrence,
+ uint32_t num_colors, uint8_t* const c1,
+ uint8_t* const c2) {
+ // Find the index that is most frequently located adjacent to other
+ // (different) indexes.
+ uint32_t best_sum = 0u;
+ uint32_t i, j, best_cooccurrence;
+ *c1 = 0u;
+ for (i = 0; i < num_colors; ++i) {
+ uint32_t sum = 0;
+ for (j = 0; j < num_colors; ++j) sum += cooccurrence[i * num_colors + j];
+ if (sum > best_sum) {
+ best_sum = sum;
+ *c1 = i;
+ }
+ }
+ // Find the index that is most frequently found adjacent to *c1.
+ *c2 = 0u;
+ best_cooccurrence = 0u;
+ for (i = 0; i < num_colors; ++i) {
+ if (cooccurrence[*c1 * num_colors + i] > best_cooccurrence) {
+ best_cooccurrence = cooccurrence[*c1 * num_colors + i];
+ *c2 = i;
+ }
+ }
+ assert(*c1 != *c2);
+}
+
+// Builds the cooccurrence matrix
+static int CoOccurrenceBuild(const WebPPicture* const pic,
+ const uint32_t* const palette, uint32_t num_colors,
+ uint32_t* cooccurrence) {
+ uint32_t *lines, *line_top, *line_current, *line_tmp;
+ int x, y;
+ const uint32_t* src = pic->argb;
+ uint32_t prev_pix = ~src[0];
+ uint32_t prev_idx = 0u;
+ uint32_t idx_map[MAX_PALETTE_SIZE] = {0};
+ uint32_t palette_sorted[MAX_PALETTE_SIZE];
+ lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines));
+ if (lines == NULL) {
+ return 0;
+ }
+ line_top = &lines[0];
+ line_current = &lines[pic->width];
+ PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map);
+ for (y = 0; y < pic->height; ++y) {
+ for (x = 0; x < pic->width; ++x) {
+ const uint32_t pix = src[x];
+ if (pix != prev_pix) {
+ prev_idx = idx_map[SearchColorNoIdx(palette_sorted, pix, num_colors)];
+ prev_pix = pix;
+ }
+ line_current[x] = prev_idx;
+ // 4-connectivity is what works best as mentioned in "On the relation
+ // between Memon's and the modified Zeng's palette reordering methods".
+ if (x > 0 && prev_idx != line_current[x - 1]) {
+ const uint32_t left_idx = line_current[x - 1];
+ ++cooccurrence[prev_idx * num_colors + left_idx];
+ ++cooccurrence[left_idx * num_colors + prev_idx];
+ }
+ if (y > 0 && prev_idx != line_top[x]) {
+ const uint32_t top_idx = line_top[x];
+ ++cooccurrence[prev_idx * num_colors + top_idx];
+ ++cooccurrence[top_idx * num_colors + prev_idx];
+ }
+ }
+ line_tmp = line_top;
+ line_top = line_current;
+ line_current = line_tmp;
+ src += pic->argb_stride;
+ }
+ WebPSafeFree(lines);
+ return 1;
+}
+
+struct Sum {
+ uint8_t index;
+ uint32_t sum;
+};
+
+static int PaletteSortModifiedZeng(const WebPPicture* const pic,
+ const uint32_t* const palette_in,
+ uint32_t num_colors,
+ uint32_t* const palette) {
+ uint32_t i, j, ind;
+ uint8_t remapping[MAX_PALETTE_SIZE];
+ uint32_t* cooccurrence;
+ struct Sum sums[MAX_PALETTE_SIZE];
+ uint32_t first, last;
+ uint32_t num_sums;
+ // TODO(vrabaud) check whether one color images should use palette or not.
+ if (num_colors <= 1) return 1;
+ // Build the co-occurrence matrix.
+ cooccurrence =
+ (uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
+ if (cooccurrence == NULL) {
+ return 0;
+ }
+ if (!CoOccurrenceBuild(pic, palette_in, num_colors, cooccurrence)) {
+ WebPSafeFree(cooccurrence);
+ return 0;
+ }
+
+ // Initialize the mapping list with the two best indices.
+ CoOccurrenceFindMax(cooccurrence, num_colors, &remapping[0], &remapping[1]);
+
+ // We need to append and prepend to the list of remapping. To this end, we
+ // actually define the next start/end of the list as indices in a vector (with
+ // a wrap around when the end is reached).
+ first = 0;
+ last = 1;
+ num_sums = num_colors - 2; // -2 because we know the first two values
+ if (num_sums > 0) {
+ // Initialize the sums with the first two remappings and find the best one
+ struct Sum* best_sum = &sums[0];
+ best_sum->index = 0u;
+ best_sum->sum = 0u;
+ for (i = 0, j = 0; i < num_colors; ++i) {
+ if (i == remapping[0] || i == remapping[1]) continue;
+ sums[j].index = i;
+ sums[j].sum = cooccurrence[i * num_colors + remapping[0]] +
+ cooccurrence[i * num_colors + remapping[1]];
+ if (sums[j].sum > best_sum->sum) best_sum = &sums[j];
+ ++j;
+ }
+
+ while (num_sums > 0) {
+ const uint8_t best_index = best_sum->index;
+ // Compute delta to know if we need to prepend or append the best index.
+ int32_t delta = 0;
+ const int32_t n = num_colors - num_sums;
+ for (ind = first, j = 0; (ind + j) % num_colors != last + 1; ++j) {
+ const uint16_t l_j = remapping[(ind + j) % num_colors];
+ delta += (n - 1 - 2 * (int32_t)j) *
+ (int32_t)cooccurrence[best_index * num_colors + l_j];
+ }
+ if (delta > 0) {
+ first = (first == 0) ? num_colors - 1 : first - 1;
+ remapping[first] = best_index;
+ } else {
+ ++last;
+ remapping[last] = best_index;
+ }
+ // Remove best_sum from sums.
+ *best_sum = sums[num_sums - 1];
+ --num_sums;
+ // Update all the sums and find the best one.
+ best_sum = &sums[0];
+ for (i = 0; i < num_sums; ++i) {
+ sums[i].sum += cooccurrence[best_index * num_colors + sums[i].index];
+ if (sums[i].sum > best_sum->sum) best_sum = &sums[i];
+ }
+ }
+ }
+ assert((last + 1) % num_colors == first);
+ WebPSafeFree(cooccurrence);
+
+ // Re-map the palette.
+ for (i = 0; i < num_colors; ++i) {
+ palette[i] = palette_in[remapping[(first + i) % num_colors]];
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic,
+ const uint32_t* const palette_sorted, uint32_t num_colors,
+ uint32_t* const palette) {
+ switch (method) {
+ case kSortedDefault:
+ // Nothing to do, we have already sorted the palette.
+ memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
+ return 1;
+ case kMinimizeDelta:
+ PaletteSortMinimizeDeltas(palette_sorted, num_colors, palette);
+ return 1;
+ case kModifiedZeng:
+ return PaletteSortModifiedZeng(pic, palette_sorted, num_colors, palette);
+ case kUnusedPalette:
+ case kPaletteSortingNum:
+ break;
+ }
+
+ assert(0);
+ return 0;
+}
diff --git a/media/libwebp/src/utils/palette.h b/media/libwebp/src/utils/palette.h
new file mode 100644
index 0000000000..34479e463f
--- /dev/null
+++ b/media/libwebp/src/utils/palette.h
@@ -0,0 +1,60 @@
+// Copyright 2023 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.
+// -----------------------------------------------------------------------------
+//
+// Utilities for palette analysis.
+//
+// Author: Vincent Rabaud (vrabaud@google.com)
+
+#ifndef WEBP_UTILS_PALETTE_H_
+#define WEBP_UTILS_PALETTE_H_
+
+#include "src/webp/types.h"
+
+struct WebPPicture;
+
+// The different ways a palette can be sorted.
+typedef enum PaletteSorting {
+ kSortedDefault = 0,
+ // Sorts by minimizing L1 deltas between consecutive colors, giving more
+ // weight to RGB colors.
+ kMinimizeDelta = 1,
+ // Implements the modified Zeng method from "A Survey on Palette Reordering
+ // Methods for Improving the Compression of Color-Indexed Images" by Armando
+ // J. Pinho and Antonio J. R. Neves.
+ kModifiedZeng = 2,
+ kUnusedPalette = 3,
+ kPaletteSortingNum = 4
+} PaletteSorting;
+
+// Returns the index of 'color' in the sorted palette 'sorted' of size
+// 'num_colors'.
+int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, int num_colors);
+
+// Sort palette in increasing order and prepare an inverse mapping array.
+void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
+ uint32_t sorted[], uint32_t idx_map[]);
+
+// Returns count of unique colors in 'pic', assuming pic->use_argb is true.
+// If the unique color count is more than MAX_PALETTE_SIZE, returns
+// MAX_PALETTE_SIZE+1.
+// If 'palette' is not NULL and the number of unique colors is less than or
+// equal to MAX_PALETTE_SIZE, also outputs the actual unique colors into
+// 'palette' in a sorted order. Note: 'palette' is assumed to be an array
+// already allocated with at least MAX_PALETTE_SIZE elements.
+int GetColorPalette(const struct WebPPicture* const pic,
+ uint32_t* const palette);
+
+// Sorts the palette according to the criterion defined by 'method'.
+// 'palette_sorted' is the input palette sorted lexicographically, as done in
+// PrepareMapToPalette. Returns 0 on memory allocation error.
+int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic,
+ const uint32_t* const palette_sorted, uint32_t num_colors,
+ uint32_t* const palette);
+
+#endif // WEBP_UTILS_PALETTE_H_
diff --git a/media/libwebp/src/utils/utils.c b/media/libwebp/src/utils/utils.c
index a7c3a70fef..408ce88f67 100644
--- a/media/libwebp/src/utils/utils.c
+++ b/media/libwebp/src/utils/utils.c
@@ -11,13 +11,13 @@
//
// Author: Skal (pascal.massimino@gmail.com)
+#include "src/utils/utils.h"
+
#include <stdlib.h>
#include <string.h> // for memcpy()
-#include "src/webp/decode.h"
+
+#include "src/utils/palette.h"
#include "src/webp/encode.h"
-#include "src/webp/format_constants.h" // for MAX_PALETTE_SIZE
-#include "src/utils/color_cache_utils.h"
-#include "src/utils/utils.h"
// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,
@@ -252,66 +252,10 @@ void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) {
//------------------------------------------------------------------------------
-#define COLOR_HASH_SIZE (MAX_PALETTE_SIZE * 4)
-#define COLOR_HASH_RIGHT_SHIFT 22 // 32 - log2(COLOR_HASH_SIZE).
-
int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
- int i;
- int x, y;
- int num_colors = 0;
- uint8_t in_use[COLOR_HASH_SIZE] = { 0 };
- uint32_t colors[COLOR_HASH_SIZE];
- const uint32_t* argb = pic->argb;
- const int width = pic->width;
- const int height = pic->height;
- uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
- assert(pic != NULL);
- assert(pic->use_argb);
-
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- int key;
- if (argb[x] == last_pix) {
- continue;
- }
- last_pix = argb[x];
- key = VP8LHashPix(last_pix, COLOR_HASH_RIGHT_SHIFT);
- while (1) {
- if (!in_use[key]) {
- colors[key] = last_pix;
- in_use[key] = 1;
- ++num_colors;
- if (num_colors > MAX_PALETTE_SIZE) {
- return MAX_PALETTE_SIZE + 1; // Exact count not needed.
- }
- break;
- } else if (colors[key] == last_pix) {
- break; // The color is already there.
- } else {
- // Some other color sits here, so do linear conflict resolution.
- ++key;
- key &= (COLOR_HASH_SIZE - 1); // Key mask.
- }
- }
- }
- argb += pic->argb_stride;
- }
-
- if (palette != NULL) { // Fill the colors into palette.
- num_colors = 0;
- for (i = 0; i < COLOR_HASH_SIZE; ++i) {
- if (in_use[i]) {
- palette[num_colors] = colors[i];
- ++num_colors;
- }
- }
- }
- return num_colors;
+ return GetColorPalette(pic, palette);
}
-#undef COLOR_HASH_SIZE
-#undef COLOR_HASH_RIGHT_SHIFT
-
//------------------------------------------------------------------------------
#if defined(WEBP_NEED_LOG_TABLE_8BIT)
diff --git a/media/libwebp/src/utils/utils.h b/media/libwebp/src/utils/utils.h
index c5ee873357..b2241fbf9b 100644
--- a/media/libwebp/src/utils/utils.h
+++ b/media/libwebp/src/utils/utils.h
@@ -20,9 +20,7 @@
#endif
#include <assert.h>
-#include <limits.h>
-#include "src/dsp/dsp.h"
#include "src/webp/types.h"
#ifdef __cplusplus
@@ -198,6 +196,7 @@ WEBP_EXTERN void WebPCopyPixels(const struct WebPPicture* const src,
// MAX_PALETTE_SIZE, also outputs the actual unique colors into 'palette'.
// Note: 'palette' is assumed to be an array already allocated with at least
// MAX_PALETTE_SIZE elements.
+// TODO(vrabaud) remove whenever we can break the ABI.
WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic,
uint32_t* const palette);
diff --git a/media/libwebp/src/webp/decode.h b/media/libwebp/src/webp/decode.h
index 0177b12089..d6895f5c55 100644
--- a/media/libwebp/src/webp/decode.h
+++ b/media/libwebp/src/webp/decode.h
@@ -48,34 +48,33 @@ WEBP_EXTERN int WebPGetDecoderVersion(void);
// RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
-WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
// with the dimensions in *width and *height. The ordering of samples in
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
// The returned pointer should be deleted calling WebPFree().
// Returns NULL in case of error.
-WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
// If the bitstream contains transparency, it is ignored.
-WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
// returned is the Y samples buffer. Upon return, *u and *v will point to
@@ -87,10 +86,9 @@ WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
// 'width' and 'height' may be NULL, the other pointers must not be.
// Returns NULL in case of error.
// (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr
-WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
- int* width, int* height,
- uint8_t** u, uint8_t** v,
- int* stride, int* uv_stride);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(
+ const uint8_t* data, size_t data_size, int* width, int* height,
+ uint8_t** u, uint8_t** v, int* stride, int* uv_stride);
// These five functions are variants of the above ones, that decode the image
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
@@ -100,22 +98,22 @@ WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
// The parameter 'output_stride' specifies the distance (in bytes)
// between scanlines. Hence, output_buffer_size is expected to be at least
// output_stride x picture-height.
-WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
// RGB and BGR variants. Here too the transparency information, if present,
// will be dropped and ignored.
-WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
@@ -126,7 +124,7 @@ WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
// 'u_size' and 'v_size' respectively.
// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
// during decoding (or because some buffers were found to be too small).
-WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
const uint8_t* data, size_t data_size,
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
@@ -217,11 +215,11 @@ struct WebPDecBuffer {
};
// Internal, version-checked, entry point
-WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int);
+WEBP_NODISCARD WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int);
// Initialize the structure as empty. Must be called before any other use.
// Returns false in case of version mismatch
-static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
+WEBP_NODISCARD static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
return WebPInitDecBufferInternal(buffer, WEBP_DECODER_ABI_VERSION);
}
@@ -232,7 +230,7 @@ WEBP_EXTERN void WebPFreeDecBuffer(WebPDecBuffer* buffer);
//------------------------------------------------------------------------------
// Enumeration of the status codes
-typedef enum VP8StatusCode {
+typedef enum WEBP_NODISCARD VP8StatusCode {
VP8_STATUS_OK = 0,
VP8_STATUS_OUT_OF_MEMORY,
VP8_STATUS_INVALID_PARAM,
@@ -251,23 +249,24 @@ typedef enum VP8StatusCode {
// WebPIDecoder object. This object can be left in a SUSPENDED state if the
// picture is only partially decoded, pending additional input.
// Code example:
-//
-// WebPInitDecBuffer(&output_buffer);
-// output_buffer.colorspace = mode;
-// ...
-// WebPIDecoder* idec = WebPINewDecoder(&output_buffer);
-// while (additional_data_is_available) {
-// // ... (get additional data in some new_data[] buffer)
-// status = WebPIAppend(idec, new_data, new_data_size);
-// if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
-// break; // an error occurred.
-// }
-//
-// // The above call decodes the current available buffer.
-// // Part of the image can now be refreshed by calling
-// // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
-// }
-// WebPIDelete(idec);
+/*
+ WebPInitDecBuffer(&output_buffer);
+ output_buffer.colorspace = mode;
+ ...
+ WebPIDecoder* idec = WebPINewDecoder(&output_buffer);
+ while (additional_data_is_available) {
+ // ... (get additional data in some new_data[] buffer)
+ status = WebPIAppend(idec, new_data, new_data_size);
+ if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
+ break; // an error occurred.
+ }
+
+ // The above call decodes the current available buffer.
+ // Part of the image can now be refreshed by calling
+ // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
+ }
+ WebPIDelete(idec);
+*/
// Creates a new incremental decoder with the supplied buffer parameter.
// This output_buffer can be passed NULL, in which case a default output buffer
@@ -281,7 +280,8 @@ typedef enum VP8StatusCode {
// within valid bounds.
// All other fields of WebPDecBuffer MUST remain constant between calls.
// Returns NULL if the allocation failed.
-WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer);
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewDecoder(
+ WebPDecBuffer* output_buffer);
// This function allocates and initializes an incremental-decoder object, which
// will output the RGB/A samples specified by 'csp' into a preallocated
@@ -293,7 +293,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer);
// colorspace 'csp' is taken into account for allocating this buffer. All other
// parameters are ignored.
// Returns NULL if the allocation failed, or if some parameters are invalid.
-WEBP_EXTERN WebPIDecoder* WebPINewRGB(
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(
WEBP_CSP_MODE csp,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
@@ -308,7 +308,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewRGB(
// In this case, the output buffer will be automatically allocated (using
// MODE_YUVA) when decoding starts. All parameters are then ignored.
// Returns NULL if the allocation failed or if a parameter is invalid.
-WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride,
@@ -316,7 +316,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
// Deprecated version of the above, without the alpha plane.
// Kept for backward compatibility.
-WEBP_EXTERN WebPIDecoder* WebPINewYUV(
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUV(
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride);
@@ -346,21 +346,21 @@ WEBP_EXTERN VP8StatusCode WebPIUpdate(
// (*last_y, *width etc.) can be NULL if corresponding information is not
// needed. The values in these pointers are only valid on successful (non-NULL)
// return.
-WEBP_EXTERN uint8_t* WebPIDecGetRGB(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPIDecGetRGB(
const WebPIDecoder* idec, int* last_y,
int* width, int* height, int* stride);
// Same as above function to get a YUVA image. Returns pointer to the luma
// plane or NULL in case of error. If there is no alpha information
// the alpha pointer '*a' will be returned NULL.
-WEBP_EXTERN uint8_t* WebPIDecGetYUVA(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPIDecGetYUVA(
const WebPIDecoder* idec, int* last_y,
uint8_t** u, uint8_t** v, uint8_t** a,
int* width, int* height, int* stride, int* uv_stride, int* a_stride);
// Deprecated alpha-less version of WebPIDecGetYUVA(): it will ignore the
// alpha information (if present). Kept for backward compatibility.
-static WEBP_INLINE uint8_t* WebPIDecGetYUV(
+WEBP_NODISCARD static WEBP_INLINE uint8_t* WebPIDecGetYUV(
const WebPIDecoder* idec, int* last_y, uint8_t** u, uint8_t** v,
int* width, int* height, int* stride, int* uv_stride) {
return WebPIDecGetYUVA(idec, last_y, u, v, NULL, width, height,
@@ -373,7 +373,7 @@ static WEBP_INLINE uint8_t* WebPIDecGetYUV(
// Returns NULL in case the incremental decoder object is in an invalid state.
// Otherwise returns the pointer to the internal representation. This structure
// is read-only, tied to WebPIDecoder's lifespan and should not be modified.
-WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
+WEBP_NODISCARD WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
const WebPIDecoder* idec, int* left, int* top, int* width, int* height);
//------------------------------------------------------------------------------
@@ -389,7 +389,7 @@ WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);
// C) Adjust 'config', if needed
- config.no_fancy_upsampling = 1;
+ config.options.no_fancy_upsampling = 1;
config.output.colorspace = MODE_BGRA;
// etc.
@@ -468,12 +468,14 @@ struct WebPDecoderConfig {
};
// Internal, version-checked, entry point
-WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
+WEBP_NODISCARD WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*,
+ int);
// Initialize the configuration as empty. This function must always be
// called first, unless WebPGetFeatures() is to be called.
// Returns false in case of mismatched version.
-static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
+WEBP_NODISCARD static WEBP_INLINE int WebPInitDecoderConfig(
+ WebPDecoderConfig* config) {
return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION);
}
@@ -488,8 +490,8 @@ static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
// The return WebPIDecoder object must always be deleted calling WebPIDelete().
// Returns NULL in case of error (and config->status will then reflect
// the error condition, if available).
-WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
- WebPDecoderConfig* config);
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(
+ const uint8_t* data, size_t data_size, WebPDecoderConfig* config);
// Non-incremental version. This version decodes the full data at once, taking
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
diff --git a/media/libwebp/src/webp/demux.h b/media/libwebp/src/webp/demux.h
index 846eeb15a9..8d246550ca 100644
--- a/media/libwebp/src/webp/demux.h
+++ b/media/libwebp/src/webp/demux.h
@@ -50,6 +50,7 @@
#include "./decode.h" // for WEBP_CSP_MODE
#include "./mux_types.h"
+#include "./types.h"
#ifdef __cplusplus
extern "C" {
@@ -85,13 +86,13 @@ typedef enum WebPDemuxState {
} WebPDemuxState;
// Internal, version-checked, entry point
-WEBP_EXTERN WebPDemuxer* WebPDemuxInternal(
+WEBP_NODISCARD WEBP_EXTERN WebPDemuxer* WebPDemuxInternal(
const WebPData*, int, WebPDemuxState*, int);
// Parses the full WebP file given by 'data'. For single images the WebP file
// header alone or the file header and the chunk header may be absent.
// Returns a WebPDemuxer object on successful parse, NULL otherwise.
-static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
+WEBP_NODISCARD static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION);
}
@@ -103,7 +104,7 @@ static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
// If this data is volatile, the demuxer object should be deleted (by calling
// WebPDemuxDelete()) and WebPDemuxPartial() called again on the new data.
// This is usually an inexpensive operation.
-static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
+WEBP_NODISCARD static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
const WebPData* data, WebPDemuxState* state) {
return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION);
}
@@ -164,14 +165,14 @@ struct WebPIterator {
// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
// NOTE: 'dmux' must persist for the lifetime of 'iter'.
-WEBP_EXTERN int WebPDemuxGetFrame(
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxGetFrame(
const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
// previous ('iter->frame_num' - 1) frame. These functions do not loop.
// Returns true on success, false otherwise.
-WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter);
-WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter);
// Releases any memory associated with 'iter'.
// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same
@@ -202,15 +203,16 @@ struct WebPChunkIterator {
// payloads are accessed through WebPDemuxGetFrame() and related functions.
// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
// NOTE: 'dmux' must persist for the lifetime of the iterator.
-WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux,
- const char fourcc[4], int chunk_number,
- WebPChunkIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux,
+ const char fourcc[4],
+ int chunk_number,
+ WebPChunkIterator* iter);
// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
// ('iter->chunk_num' - 1) chunk. These functions do not loop.
// Returns true on success, false otherwise.
-WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter);
-WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter);
// Releases any memory associated with 'iter'.
// Must be called before destroying the associated WebPDemuxer with
@@ -257,21 +259,21 @@ struct WebPAnimDecoderOptions {
};
// Internal, version-checked, entry point.
-WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal(
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal(
WebPAnimDecoderOptions*, int);
// Should always be called, to initialize a fresh WebPAnimDecoderOptions
// structure before modification. Returns false in case of version mismatch.
// WebPAnimDecoderOptionsInit() must have succeeded before using the
// 'dec_options' object.
-static WEBP_INLINE int WebPAnimDecoderOptionsInit(
+WEBP_NODISCARD static WEBP_INLINE int WebPAnimDecoderOptionsInit(
WebPAnimDecoderOptions* dec_options) {
return WebPAnimDecoderOptionsInitInternal(dec_options,
WEBP_DEMUX_ABI_VERSION);
}
// Internal, version-checked, entry point.
-WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
+WEBP_NODISCARD WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
const WebPData*, const WebPAnimDecoderOptions*, int);
// Creates and initializes a WebPAnimDecoder object.
@@ -284,7 +286,7 @@ WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
// Returns:
// A pointer to the newly created WebPAnimDecoder object, or NULL in case of
// parsing error, invalid option or memory error.
-static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew(
+WEBP_NODISCARD static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew(
const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options) {
return WebPAnimDecoderNewInternal(webp_data, dec_options,
WEBP_DEMUX_ABI_VERSION);
@@ -306,8 +308,8 @@ struct WebPAnimInfo {
// info - (out) global information fetched from the animation.
// Returns:
// True on success.
-WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
- WebPAnimInfo* info);
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderGetInfo(
+ const WebPAnimDecoder* dec, WebPAnimInfo* info);
// Fetch the next frame from 'dec' based on options supplied to
// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size
@@ -321,8 +323,9 @@ WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
// Returns:
// False if any of the arguments are NULL, or if there is a parsing or
// decoding error, or if there are no more frames. Otherwise, returns true.
-WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
- uint8_t** buf, int* timestamp);
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
+ uint8_t** buf,
+ int* timestamp);
// Check if there are more frames left to decode.
// Parameters:
@@ -330,7 +333,8 @@ WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
// Returns:
// True if 'dec' is not NULL and some frames are yet to be decoded.
// Otherwise, returns false.
-WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(
+ const WebPAnimDecoder* dec);
// Resets the WebPAnimDecoder object, so that next call to
// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be
@@ -348,7 +352,7 @@ WEBP_EXTERN void WebPAnimDecoderReset(WebPAnimDecoder* dec);
//
// Parameters:
// dec - (in) decoder instance from which the demuxer object is to be fetched.
-WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer(
+WEBP_NODISCARD WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer(
const WebPAnimDecoder* dec);
// Deletes the WebPAnimDecoder object.
diff --git a/media/libwebp/src/webp/encode.h b/media/libwebp/src/webp/encode.h
index 56b68e2f10..f3d59297c8 100644
--- a/media/libwebp/src/webp/encode.h
+++ b/media/libwebp/src/webp/encode.h
@@ -164,13 +164,14 @@ typedef enum WebPPreset {
} WebPPreset;
// Internal, version-checked, entry point
-WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int);
+WEBP_NODISCARD WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset,
+ float, int);
// Should always be called, to initialize a fresh WebPConfig structure before
// modification. Returns false in case of version mismatch. WebPConfigInit()
// must have succeeded before using the 'config' object.
// Note that the default values are lossless=0 and quality=75.
-static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
+WEBP_NODISCARD static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f,
WEBP_ENCODER_ABI_VERSION);
}
@@ -179,8 +180,9 @@ static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
// set of parameters (referred to by 'preset') and a given quality factor.
// This function can be called as a replacement to WebPConfigInit(). Will
// return false in case of error.
-static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
- WebPPreset preset, float quality) {
+WEBP_NODISCARD static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
+ WebPPreset preset,
+ float quality) {
return WebPConfigInitInternal(config, preset, quality,
WEBP_ENCODER_ABI_VERSION);
}
@@ -191,11 +193,12 @@ static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
// speed and final compressed size.
// This function will overwrite several fields from config: 'method', 'quality'
// and 'lossless'. Returns false in case of parameter error.
-WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config, int level);
+WEBP_NODISCARD WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config,
+ int level);
// Returns true if 'config' is non-NULL and all configuration parameters are
// within their valid ranges.
-WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config);
+WEBP_NODISCARD WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config);
//------------------------------------------------------------------------------
// Input / Output
@@ -255,8 +258,8 @@ WEBP_EXTERN void WebPMemoryWriterClear(WebPMemoryWriter* writer);
// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
// completion, writer.mem and writer.size will hold the coded data.
// writer.mem must be freed by calling WebPMemoryWriterClear.
-WEBP_EXTERN int WebPMemoryWrite(const uint8_t* data, size_t data_size,
- const WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPMemoryWrite(
+ const uint8_t* data, size_t data_size, const WebPPicture* picture);
// Progress hook, called from time to time to report progress. It can return
// false to request an abort of the encoding process, or true otherwise if
@@ -364,13 +367,13 @@ struct WebPPicture {
};
// Internal, version-checked, entry point
-WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int);
// Should always be called, to initialize the structure. Returns false in case
// of version mismatch. WebPPictureInit() must have succeeded before using the
// 'picture' object.
// Note that, by default, use_argb is false and colorspace is WEBP_YUV420.
-static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
+WEBP_NODISCARD static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION);
}
@@ -381,7 +384,7 @@ static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
// Allocate y/u/v buffers as per colorspace/width/height specification.
// Note! This function will free the previous buffer if needed.
// Returns false in case of memory error.
-WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture);
// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
// Note that this function does _not_ free the memory used by the 'picture'
@@ -394,7 +397,8 @@ WEBP_EXTERN void WebPPictureFree(WebPPicture* picture);
// will fully own the copied pixels (this is not a view). The 'dst' picture need
// not be initialized as its content is overwritten.
// Returns false in case of memory allocation error.
-WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src,
+ WebPPicture* dst);
// Compute the single distortion for packed planes of samples.
// 'src' will be compared to 'ref', and the raw distortion stored into
@@ -403,19 +407,18 @@ WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
// 'x_step' is the horizontal stride (in bytes) between samples.
// 'src/ref_stride' is the byte distance between rows.
// Returns false in case of error (bad parameter, memory allocation error, ...).
-WEBP_EXTERN int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
- const uint8_t* ref, size_t ref_stride,
- int width, int height,
- size_t x_step,
- int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
- float* distortion, float* result);
+WEBP_NODISCARD WEBP_EXTERN int WebPPlaneDistortion(
+ const uint8_t* src, size_t src_stride,
+ const uint8_t* ref, size_t ref_stride, int width, int height, size_t x_step,
+ int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
+ float* distortion, float* result);
// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results
// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is
// always performed using ARGB samples. Hence if the input is YUV(A), the
// picture will be internally converted to ARGB (just for the measurement).
// Warning: this function is rather CPU-intensive.
-WEBP_EXTERN int WebPPictureDistortion(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureDistortion(
const WebPPicture* src, const WebPPicture* ref,
int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
float result[5]);
@@ -428,8 +431,8 @@ WEBP_EXTERN int WebPPictureDistortion(
// must be fully be comprised inside the 'src' source picture. If the source
// picture uses the YUV420 colorspace, the top and left coordinates will be
// snapped to even values.
-WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
- int left, int top, int width, int height);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureCrop(
+ WebPPicture* picture, int left, int top, int width, int height);
// Extracts a view from 'src' picture into 'dst'. The rectangle for the view
// is defined by the top-left corner pixel coordinates (left, top) as well
@@ -442,9 +445,9 @@ WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
// with WebPPictureInit() if it is different from 'src', since its content will
// be overwritten.
// Returns false in case of invalid parameters.
-WEBP_EXTERN int WebPPictureView(const WebPPicture* src,
- int left, int top, int width, int height,
- WebPPicture* dst);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureView(
+ const WebPPicture* src, int left, int top, int width, int height,
+ WebPPicture* dst);
// Returns true if the 'picture' is actually a view and therefore does
// not own the memory for pixels.
@@ -455,29 +458,30 @@ WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture);
// dimension will be calculated preserving the aspect ratio.
// No gamma correction is applied.
// Returns false in case of error (invalid parameter or insufficient memory).
-WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture, int width, int height);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture,
+ int width, int height);
// Colorspace conversion function to import RGB samples.
// Previous buffer will be free'd, if any.
// *rgb buffer should have a size of at least height * rgb_stride.
// Returns false in case of memory error.
-WEBP_EXTERN int WebPPictureImportRGB(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGB(
WebPPicture* picture, const uint8_t* rgb, int rgb_stride);
// Same, but for RGBA buffer.
-WEBP_EXTERN int WebPPictureImportRGBA(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGBA(
WebPPicture* picture, const uint8_t* rgba, int rgba_stride);
// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format
// input buffer ignoring the alpha channel. Avoids needing to copy the data
// to a temporary 24-bit RGB buffer to import the RGB only.
-WEBP_EXTERN int WebPPictureImportRGBX(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGBX(
WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride);
// Variants of the above, but taking BGR(A|X) input.
-WEBP_EXTERN int WebPPictureImportBGR(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGR(
WebPPicture* picture, const uint8_t* bgr, int bgr_stride);
-WEBP_EXTERN int WebPPictureImportBGRA(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGRA(
WebPPicture* picture, const uint8_t* bgra, int bgra_stride);
-WEBP_EXTERN int WebPPictureImportBGRX(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGRX(
WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
// Converts picture->argb data to the YUV420A format. The 'colorspace'
@@ -486,24 +490,24 @@ WEBP_EXTERN int WebPPictureImportBGRX(
// non-opaque transparent values is detected, and 'colorspace' will be
// adjusted accordingly. Note that this method is lossy.
// Returns false in case of error.
-WEBP_EXTERN int WebPPictureARGBToYUVA(WebPPicture* picture,
- WebPEncCSP /*colorspace = WEBP_YUV420*/);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureARGBToYUVA(
+ WebPPicture* picture, WebPEncCSP /*colorspace = WEBP_YUV420*/);
// Same as WebPPictureARGBToYUVA(), but the conversion is done using
// pseudo-random dithering with a strength 'dithering' between
// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful
// for photographic picture.
-WEBP_EXTERN int WebPPictureARGBToYUVADithered(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureARGBToYUVADithered(
WebPPicture* picture, WebPEncCSP colorspace, float dithering);
-// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion.
+// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion
// Downsampling is handled with extra care in case of color clipping. This
// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better
// and sharper YUV representation.
// Returns false in case of error.
-WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture);
// kept for backward compatibility:
-WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Converts picture->yuv to picture->argb and sets picture->use_argb to true.
// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to
@@ -511,7 +515,7 @@ WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Note that the use of this colorspace is discouraged if one has access to the
// raw ARGB samples, since using YUV420 is comparatively lossy.
// Returns false in case of error.
-WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture);
// Helper function: given a width x height plane of RGBA or YUV(A) samples
// clean-up or smoothen the YUV or RGB samples under fully transparent area,
@@ -541,7 +545,8 @@ WEBP_EXTERN void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb);
// the former for lossy encoding, and the latter for lossless encoding
// (when config.lossless is true). Automatic conversion from one format to
// another is provided but they both incur some loss.
-WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPEncode(const WebPConfig* config,
+ WebPPicture* picture);
//------------------------------------------------------------------------------
diff --git a/media/libwebp/src/webp/mux.h b/media/libwebp/src/webp/mux.h
index 7d27489a40..8fb067e435 100644
--- a/media/libwebp/src/webp/mux.h
+++ b/media/libwebp/src/webp/mux.h
@@ -16,12 +16,13 @@
#define WEBP_WEBP_MUX_H_
#include "./mux_types.h"
+#include "./types.h"
#ifdef __cplusplus
extern "C" {
#endif
-#define WEBP_MUX_ABI_VERSION 0x0108 // MAJOR(8b) + MINOR(8b)
+#define WEBP_MUX_ABI_VERSION 0x0109 // MAJOR(8b) + MINOR(8b)
//------------------------------------------------------------------------------
// Mux API
@@ -70,7 +71,7 @@ typedef struct WebPMuxAnimParams WebPMuxAnimParams;
typedef struct WebPAnimEncoderOptions WebPAnimEncoderOptions;
// Error codes
-typedef enum WebPMuxError {
+typedef enum WEBP_NODISCARD WebPMuxError {
WEBP_MUX_OK = 1,
WEBP_MUX_NOT_FOUND = 0,
WEBP_MUX_INVALID_ARGUMENT = -1,
@@ -104,13 +105,13 @@ WEBP_EXTERN int WebPGetMuxVersion(void);
// Life of a Mux object
// Internal, version-checked, entry point
-WEBP_EXTERN WebPMux* WebPNewInternal(int);
+WEBP_NODISCARD WEBP_EXTERN WebPMux* WebPNewInternal(int);
// Creates an empty mux object.
// Returns:
// A pointer to the newly created empty mux object.
// Or NULL in case of memory error.
-static WEBP_INLINE WebPMux* WebPMuxNew(void) {
+WEBP_NODISCARD static WEBP_INLINE WebPMux* WebPMuxNew(void) {
return WebPNewInternal(WEBP_MUX_ABI_VERSION);
}
@@ -123,18 +124,21 @@ WEBP_EXTERN void WebPMuxDelete(WebPMux* mux);
// Mux creation.
// Internal, version-checked, entry point
-WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int, int);
+WEBP_NODISCARD WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int,
+ int);
// Creates a mux object from raw data given in WebP RIFF format.
// Parameters:
// bitstream - (in) the bitstream data in WebP RIFF format
// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist for the lifetime of the
+// mux object.
// Returns:
// A pointer to the mux object created from given data - on success.
// NULL - In case of invalid data or memory error.
-static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
- int copy_data) {
+WEBP_NODISCARD static WEBP_INLINE WebPMux* WebPMuxCreate(
+ const WebPData* bitstream, int copy_data) {
return WebPMuxCreateInternal(bitstream, copy_data, WEBP_MUX_ABI_VERSION);
}
@@ -154,7 +158,9 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
// e.g., "ICCP", "XMP ", "EXIF" etc.
// chunk_data - (in) the chunk data to be added
// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist until a call to
+// WebPMuxAssemble() is made.
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL
// or if fourcc corresponds to an image chunk.
@@ -217,7 +223,9 @@ struct WebPMuxFrameInfo {
// bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image
// WebP file (non-animated)
// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist until a call to
+// WebPMuxAssemble() is made.
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
@@ -235,7 +243,9 @@ WEBP_EXTERN WebPMuxError WebPMuxSetImage(
// mux - (in/out) object to which the frame is to be added
// frame - (in) frame data.
// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist until a call to
+// WebPMuxAssemble() is made.
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL
// or if content of 'frame' is invalid.
@@ -449,7 +459,7 @@ WEBP_EXTERN int WebPAnimEncoderOptionsInitInternal(
// structure before modification. Returns false in case of version mismatch.
// WebPAnimEncoderOptionsInit() must have succeeded before using the
// 'enc_options' object.
-static WEBP_INLINE int WebPAnimEncoderOptionsInit(
+WEBP_NODISCARD static WEBP_INLINE int WebPAnimEncoderOptionsInit(
WebPAnimEncoderOptions* enc_options) {
return WebPAnimEncoderOptionsInitInternal(enc_options, WEBP_MUX_ABI_VERSION);
}
@@ -490,7 +500,7 @@ static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew(
// Returns:
// On error, returns false and frame->error_code is set appropriately.
// Otherwise, returns true.
-WEBP_EXTERN int WebPAnimEncoderAdd(
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimEncoderAdd(
WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms,
const struct WebPConfig* config);
@@ -503,8 +513,8 @@ WEBP_EXTERN int WebPAnimEncoderAdd(
// webp_data - (out) generated WebP bitstream.
// Returns:
// True on success.
-WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
- WebPData* webp_data);
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
+ WebPData* webp_data);
// Get error string corresponding to the most recent call using 'enc'. The
// returned string is owned by 'enc' and is valid only until the next call to
@@ -522,6 +532,57 @@ WEBP_EXTERN const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc);
WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
//------------------------------------------------------------------------------
+// Non-image chunks.
+
+// Note: Only non-image related chunks should be managed through chunk APIs.
+// (Image related chunks are: "ANMF", "VP8 ", "VP8L" and "ALPH").
+
+// Adds a chunk with id 'fourcc' and data 'chunk_data' in the enc object.
+// Any existing chunk(s) with the same id will be removed.
+// Parameters:
+// enc - (in/out) object to which the chunk is to be added
+// fourcc - (in) a character array containing the fourcc of the given chunk;
+// e.g., "ICCP", "XMP ", "EXIF", etc.
+// chunk_data - (in) the chunk data to be added
+// copy_data - (in) value 1 indicates given data WILL be copied to the enc
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist until a call to
+// WebPAnimEncoderAssemble() is made.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if enc, fourcc or chunk_data is NULL.
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN WebPMuxError WebPAnimEncoderSetChunk(
+ WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data,
+ int copy_data);
+
+// Gets a reference to the data of the chunk with id 'fourcc' in the enc object.
+// The caller should NOT free the returned data.
+// Parameters:
+// enc - (in) object from which the chunk data is to be fetched
+// fourcc - (in) a character array containing the fourcc of the chunk;
+// e.g., "ICCP", "XMP ", "EXIF", etc.
+// chunk_data - (out) returned chunk data
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if enc, fourcc or chunk_data is NULL.
+// WEBP_MUX_NOT_FOUND - If enc does not contain a chunk with the given id.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN WebPMuxError WebPAnimEncoderGetChunk(
+ const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data);
+
+// Deletes the chunk with the given 'fourcc' from the enc object.
+// Parameters:
+// enc - (in/out) object from which the chunk is to be deleted
+// fourcc - (in) a character array containing the fourcc of the chunk;
+// e.g., "ICCP", "XMP ", "EXIF", etc.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if enc or fourcc is NULL.
+// WEBP_MUX_NOT_FOUND - If enc does not contain a chunk with the given fourcc.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN WebPMuxError WebPAnimEncoderDeleteChunk(
+ WebPAnimEncoder* enc, const char fourcc[4]);
+
+//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
diff --git a/media/libwebp/src/webp/mux_types.h b/media/libwebp/src/webp/mux_types.h
index 2fe8195839..c585d2082f 100644
--- a/media/libwebp/src/webp/mux_types.h
+++ b/media/libwebp/src/webp/mux_types.h
@@ -79,7 +79,8 @@ static WEBP_INLINE void WebPDataClear(WebPData* webp_data) {
// Allocates necessary storage for 'dst' and copies the contents of 'src'.
// Returns true on success.
-static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) {
+WEBP_NODISCARD static WEBP_INLINE int WebPDataCopy(const WebPData* src,
+ WebPData* dst) {
if (src == NULL || dst == NULL) return 0;
WebPDataInit(dst);
if (src->bytes != NULL && src->size != 0) {
diff --git a/media/libwebp/src/webp/types.h b/media/libwebp/src/webp/types.h
index f255432e41..9c17edec45 100644
--- a/media/libwebp/src/webp/types.h
+++ b/media/libwebp/src/webp/types.h
@@ -36,18 +36,39 @@ typedef long long int int64_t;
#define WEBP_INLINE __forceinline
#endif /* _MSC_VER */
+#ifndef WEBP_NODISCARD
+#if defined(WEBP_ENABLE_NODISCARD) && WEBP_ENABLE_NODISCARD
+#if (defined(__cplusplus) && __cplusplus >= 201700L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define WEBP_NODISCARD [[nodiscard]]
+#else
+// gcc's __has_attribute does not work for enums.
+#if defined(__clang__) && defined(__has_attribute)
+#if __has_attribute(warn_unused_result)
+#define WEBP_NODISCARD __attribute__((warn_unused_result))
+#else
+#define WEBP_NODISCARD
+#endif /* __has_attribute(warn_unused_result) */
+#else
+#define WEBP_NODISCARD
+#endif /* defined(__clang__) && defined(__has_attribute) */
+#endif /* (defined(__cplusplus) && __cplusplus >= 201700L) ||
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) */
+#else
+#define WEBP_NODISCARD
+#endif /* defined(WEBP_ENABLE_NODISCARD) && WEBP_ENABLE_NODISCARD */
+#endif /* WEBP_NODISCARD */
+
#ifndef WEBP_EXTERN
// This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds.
-# if defined(__GNUC__) && __GNUC__ >= 4
+# if defined(_WIN32) && defined(WEBP_DLL)
+# define WEBP_EXTERN __declspec(dllexport)
+# elif defined(__GNUC__) && __GNUC__ >= 4
# define WEBP_EXTERN extern __attribute__ ((visibility ("default")))
# else
-# if defined(_MSC_VER) && defined(WEBP_DLL)
-# define WEBP_EXTERN __declspec(dllexport)
-# else
-# define WEBP_EXTERN extern
-# endif
-# endif /* __GNUC__ >= 4 */
+# define WEBP_EXTERN extern
+# endif /* defined(_WIN32) && defined(WEBP_DLL) */
#endif /* WEBP_EXTERN */
// Macro to check ABI compatibility (same major revision number)
@@ -60,7 +81,7 @@ extern "C" {
// Allocates 'size' bytes of memory. Returns NULL upon error. Memory
// must be deallocated by calling WebPFree(). This function is made available
// by the core 'libwebp' library.
-WEBP_EXTERN void* WebPMalloc(size_t size);
+WEBP_NODISCARD WEBP_EXTERN void* WebPMalloc(size_t size);
// Releases memory returned by the WebPDecode*() functions (from decode.h).
WEBP_EXTERN void WebPFree(void* ptr);