Browse Source

libwebp: Update to 1.4.0

https://chromium.googlesource.com/webm/libwebp/+/refs/tags/v1.4.0/NEWS
Rémi Verschelde 1 year ago
parent
commit
09bd34df93
74 changed files with 1964 additions and 1127 deletions
  1. 1 0
      modules/webp/SCsub
  2. 1 1
      thirdparty/README.md
  3. 7 0
      thirdparty/libwebp/AUTHORS
  4. 0 0
      thirdparty/libwebp/patches/godot-node-debug-fix.patch
  5. 105 58
      thirdparty/libwebp/sharpyuv/sharpyuv.c
  6. 77 8
      thirdparty/libwebp/sharpyuv/sharpyuv.h
  7. 2 2
      thirdparty/libwebp/sharpyuv/sharpyuv_dsp.c
  8. 308 2
      thirdparty/libwebp/sharpyuv/sharpyuv_gamma.c
  9. 7 4
      thirdparty/libwebp/sharpyuv/sharpyuv_gamma.h
  10. 34 27
      thirdparty/libwebp/src/dec/alpha_dec.c
  11. 1 1
      thirdparty/libwebp/src/dec/buffer_dec.c
  12. 31 19
      thirdparty/libwebp/src/dec/idec_dec.c
  13. 12 8
      thirdparty/libwebp/src/dec/vp8_dec.c
  14. 8 9
      thirdparty/libwebp/src/dec/vp8_dec.h
  15. 9 6
      thirdparty/libwebp/src/dec/vp8i_dec.h
  16. 100 68
      thirdparty/libwebp/src/dec/vp8l_dec.c
  17. 21 7
      thirdparty/libwebp/src/dec/vp8li_dec.h
  18. 30 18
      thirdparty/libwebp/src/dec/webp_dec.c
  19. 4 2
      thirdparty/libwebp/src/dec/webpi_dec.h
  20. 14 8
      thirdparty/libwebp/src/demux/anim_decode.c
  21. 2 2
      thirdparty/libwebp/src/demux/demux.c
  22. 41 0
      thirdparty/libwebp/src/dsp/alpha_processing_sse2.c
  23. 0 12
      thirdparty/libwebp/src/dsp/cpu.c
  24. 12 13
      thirdparty/libwebp/src/dsp/dec.c
  25. 20 36
      thirdparty/libwebp/src/dsp/dec_mips32.c
  26. 6 10
      thirdparty/libwebp/src/dsp/dec_mips_dsp_r2.c
  27. 4 6
      thirdparty/libwebp/src/dsp/dec_msa.c
  28. 7 10
      thirdparty/libwebp/src/dsp/dec_neon.c
  29. 16 18
      thirdparty/libwebp/src/dsp/dec_sse2.c
  30. 5 0
      thirdparty/libwebp/src/dsp/dsp.h
  31. 10 11
      thirdparty/libwebp/src/dsp/enc.c
  32. 8 12
      thirdparty/libwebp/src/dsp/enc_mips32.c
  33. 2 2
      thirdparty/libwebp/src/dsp/enc_mips_dsp_r2.c
  34. 3 2
      thirdparty/libwebp/src/dsp/enc_neon.c
  35. 22 13
      thirdparty/libwebp/src/dsp/filters.c
  36. 14 12
      thirdparty/libwebp/src/dsp/filters_mips_dsp_r2.c
  37. 12 10
      thirdparty/libwebp/src/dsp/filters_msa.c
  38. 14 12
      thirdparty/libwebp/src/dsp/filters_neon.c
  39. 14 12
      thirdparty/libwebp/src/dsp/filters_sse2.c
  40. 3 3
      thirdparty/libwebp/src/dsp/lossless.h
  41. 3 3
      thirdparty/libwebp/src/dsp/lossless_common.h
  42. 14 9
      thirdparty/libwebp/src/dsp/lossless_enc.c
  43. 7 7
      thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
  44. 52 2
      thirdparty/libwebp/src/dsp/lossless_enc_sse41.c
  45. 3 3
      thirdparty/libwebp/src/dsp/lossless_neon.c
  46. 26 16
      thirdparty/libwebp/src/dsp/mips_macro.h
  47. 15 17
      thirdparty/libwebp/src/dsp/msa_macro.h
  48. 2 1
      thirdparty/libwebp/src/dsp/quant.h
  49. 1 1
      thirdparty/libwebp/src/dsp/rescaler_neon.c
  50. 6 6
      thirdparty/libwebp/src/dsp/upsampling_sse2.c
  51. 4 4
      thirdparty/libwebp/src/dsp/upsampling_sse41.c
  52. 4 7
      thirdparty/libwebp/src/enc/alpha_enc.c
  53. 2 2
      thirdparty/libwebp/src/enc/frame_enc.c
  54. 19 17
      thirdparty/libwebp/src/enc/histogram_enc.c
  55. 1 1
      thirdparty/libwebp/src/enc/picture_enc.c
  56. 2 2
      thirdparty/libwebp/src/enc/vp8i_enc.h
  57. 42 347
      thirdparty/libwebp/src/enc/vp8l_enc.c
  58. 1 3
      thirdparty/libwebp/src/enc/vp8li_enc.h
  59. 34 8
      thirdparty/libwebp/src/mux/anim_encode.c
  60. 11 8
      thirdparty/libwebp/src/mux/muxedit.c
  61. 2 2
      thirdparty/libwebp/src/mux/muxi.h
  62. 13 9
      thirdparty/libwebp/src/mux/muxread.c
  63. 4 1
      thirdparty/libwebp/src/utils/huffman_utils.c
  64. 7 4
      thirdparty/libwebp/src/utils/huffman_utils.h
  65. 402 0
      thirdparty/libwebp/src/utils/palette.c
  66. 60 0
      thirdparty/libwebp/src/utils/palette.h
  67. 5 61
      thirdparty/libwebp/src/utils/utils.c
  68. 1 2
      thirdparty/libwebp/src/utils/utils.h
  69. 58 56
      thirdparty/libwebp/src/webp/decode.h
  70. 25 21
      thirdparty/libwebp/src/webp/demux.h
  71. 44 39
      thirdparty/libwebp/src/webp/encode.h
  72. 76 15
      thirdparty/libwebp/src/webp/mux.h
  73. 2 1
      thirdparty/libwebp/src/webp/mux_types.h
  74. 29 8
      thirdparty/libwebp/src/webp/types.h

+ 1 - 0
modules/webp/SCsub

@@ -128,6 +128,7 @@ if env["builtin_libwebp"]:
         "src/utils/filters_utils.c",
         "src/utils/huffman_encode_utils.c",
         "src/utils/huffman_utils.c",
+        "src/utils/palette.c",
         "src/utils/quant_levels_dec_utils.c",
         "src/utils/quant_levels_utils.c",
         "src/utils/random_utils.c",

+ 1 - 1
thirdparty/README.md

@@ -517,7 +517,7 @@ Files extracted from upstream source:
 ## libwebp
 
 - Upstream: https://chromium.googlesource.com/webm/libwebp/
-- Version: 1.3.2 (ca332209cb5567c9b249c86788cb2dbf8847e760, 2023)
+- Version: 1.4.0 (845d5476a866141ba35ac133f856fa62f0b7445f, 2024)
 - License: BSD-3-Clause
 
 Files extracted from upstream source:

+ 7 - 0
thirdparty/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)

+ 0 - 0
thirdparty/libwebp/godot-node-debug-fix.patch → thirdparty/libwebp/patches/godot-node-debug-fix.patch


+ 105 - 58
thirdparty/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);
 }
 
 //------------------------------------------------------------------------------

+ 77 - 8
thirdparty/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).
 

+ 2 - 2
thirdparty/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);

+ 308 - 2
thirdparty/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));
+}

+ 7 - 4
thirdparty/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"

+ 34 - 27
thirdparty/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

+ 1 - 1
thirdparty/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);

+ 31 - 19
thirdparty/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) {

+ 12 - 8
thirdparty/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

+ 8 - 9
thirdparty/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);

+ 9 - 6
thirdparty/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,

+ 100 - 68
thirdparty/libwebp/src/dec/vp8l_dec.c

@@ -12,6 +12,7 @@
 // Authors: Vikas Arora ([email protected])
 //          Jyrki Alakuijala ([email protected])
 
+#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;
 }
 
@@ -1241,9 +1261,20 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
   }
 
   br->eos_ = VP8LIsEndOfStream(br);
-  if (dec->incremental_ && br->eos_ && src < src_end) {
+  // In incremental decoding:
+  // br->eos_ && src < src_last: if 'br' reached the end of the buffer and
+  // 'src_last' has not been reached yet, there is not enough data. 'dec' has to
+  // be reset until there is more data.
+  // !br->eos_ && src < src_last: this cannot happen as either the buffer is
+  // fully read, either enough has been read to reach 'src_last'.
+  // src >= src_last: 'src_last' is reached, all is fine. 'src' can actually go
+  // beyond 'src_last' in case the image is cropped and an LZ77 goes further.
+  // The buffer might have been enough or there is some left. 'br->eos_' does
+  // not matter.
+  assert(!dec->incremental_ || (br->eos_ && src < src_last) || src >= src_last);
+  if (dec->incremental_ && br->eos_ && src < src_last) {
     RestoreState(dec);
-  } else if (!br->eos_) {
+  } else if ((dec->incremental_ && src >= src_last) || !br->eos_) {
     // Process the remaining rows corresponding to last row-block.
     if (process_func != NULL) {
       process_func(dec, row > last_row ? last_row : row);
@@ -1258,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);
 }
 
 // -----------------------------------------------------------------------------
@@ -1326,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;
@@ -1336,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:
@@ -1443,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;
     }
   }
@@ -1452,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;
   }
 
@@ -1460,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 {
@@ -1478,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;
     }
   }
@@ -1524,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;
@@ -1536,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;
 }
@@ -1592,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;
   }
 
@@ -1647,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:
@@ -1692,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;
     }
 
@@ -1702,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
@@ -1720,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;
         }
       }

+ 21 - 7
thirdparty/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

+ 30 - 18
thirdparty/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;

+ 4 - 2
thirdparty/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).

+ 14 - 8
thirdparty/libwebp/src/demux/anim_decode.c

@@ -20,6 +20,7 @@
 #include "src/utils/utils.h"
 #include "src/webp/decode.h"
 #include "src/webp/demux.h"
+#include "src/webp/types.h"
 
 #define NUM_CHANNELS 4
 
@@ -68,8 +69,9 @@ int WebPAnimDecoderOptionsInitInternal(WebPAnimDecoderOptions* dec_options,
   return 1;
 }
 
-static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
-                               WebPAnimDecoder* const dec) {
+WEBP_NODISCARD static int ApplyDecoderOptions(
+    const WebPAnimDecoderOptions* const dec_options,
+    WebPAnimDecoder* const dec) {
   WEBP_CSP_MODE mode;
   WebPDecoderConfig* config = &dec->config_;
   assert(dec_options != NULL);
@@ -82,7 +84,9 @@ static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
   dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA)
                          ? &BlendPixelRowNonPremult
                          : &BlendPixelRowPremult;
-  WebPInitDecoderConfig(config);
+  if (!WebPInitDecoderConfig(config)) {
+    return 0;
+  }
   config->output.colorspace = mode;
   config->output.is_external_memory = 1;
   config->options.use_threads = dec_options->use_threads;
@@ -157,8 +161,8 @@ static int IsFullFrame(int width, int height, int canvas_width,
 }
 
 // Clear the canvas to transparent.
-static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
-                          uint32_t canvas_height) {
+WEBP_NODISCARD static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
+                                         uint32_t canvas_height) {
   const uint64_t size =
       (uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
   if (!CheckSizeOverflow(size)) return 0;
@@ -179,8 +183,8 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
 }
 
 // Copy width * height pixels from 'src' to 'dst'.
-static int CopyCanvas(const uint8_t* src, uint8_t* dst,
-                      uint32_t width, uint32_t height) {
+WEBP_NODISCARD static int CopyCanvas(const uint8_t* src, uint8_t* dst,
+                                     uint32_t width, uint32_t height) {
   const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
   if (!CheckSizeOverflow(size)) return 0;
   assert(src != NULL && dst != NULL);
@@ -424,7 +428,9 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
   WebPDemuxReleaseIterator(&dec->prev_iter_);
   dec->prev_iter_ = iter;
   dec->prev_frame_was_keyframe_ = is_key_frame;
-  CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height);
+  if (!CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height)) {
+    goto Error;
+  }
   if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
     ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS,
                       dec->prev_iter_.x_offset, dec->prev_iter_.y_offset,

+ 2 - 2
thirdparty/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

+ 41 - 0
thirdparty/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;

+ 0 - 12
thirdparty/libwebp/src/dsp/cpu.c

@@ -36,18 +36,6 @@ static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
     : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
     : "a"(info_type), "c"(0));
 }
-#elif defined(__x86_64__) && \
-      (defined(__code_model_medium__) || defined(__code_model_large__)) && \
-      defined(__PIC__)
-static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
-  __asm__ volatile (
-    "xchg{q}\t{%%rbx}, %q1\n"
-    "cpuid\n"
-    "xchg{q}\t{%%rbx}, %q1\n"
-    : "=a"(cpu_info[0]), "=&r"(cpu_info[1]), "=c"(cpu_info[2]),
-      "=d"(cpu_info[3])
-    : "a"(info_type), "c"(0));
-}
 #elif defined(__i386__) || defined(__x86_64__)
 static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
   __asm__ volatile (

+ 12 - 13
thirdparty/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) {

+ 20 - 36
thirdparty/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"
   );

+ 6 - 10
thirdparty/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)
 

+ 4 - 6
thirdparty/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);

+ 7 - 10
thirdparty/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

+ 16 - 18
thirdparty/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,

+ 5 - 0
thirdparty/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);

+ 10 - 11
thirdparty/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
 
 //------------------------------------------------------------------------------

+ 8 - 12
thirdparty/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"          \

+ 2 - 2
thirdparty/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)

+ 3 - 2
thirdparty/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

+ 22 - 13
thirdparty/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);

+ 14 - 12
thirdparty/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

+ 12 - 10
thirdparty/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

+ 14 - 12
thirdparty/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

+ 14 - 12
thirdparty/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
 
 //------------------------------------------------------------------------------
 

+ 3 - 3
thirdparty/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]);
 

+ 3 - 3
thirdparty/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.

+ 14 - 9
thirdparty/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;
 }

+ 7 - 7
thirdparty/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                                 \

+ 52 - 2
thirdparty/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;

+ 3 - 3
thirdparty/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) {

+ 26 - 16
thirdparty/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"            \

+ 15 - 17
thirdparty/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)

+ 2 - 1
thirdparty/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);

+ 1 - 1
thirdparty/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))

+ 6 - 6
thirdparty/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)

+ 4 - 4
thirdparty/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) {

+ 4 - 7
thirdparty/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) {

+ 2 - 2
thirdparty/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;
 

+ 19 - 17
thirdparty/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) {

+ 1 - 1
thirdparty/libwebp/src/enc/picture_enc.c

@@ -12,10 +12,10 @@
 // Author: Skal ([email protected])
 
 #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"
 
 //------------------------------------------------------------------------------

+ 2 - 2
thirdparty/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

+ 42 - 347
thirdparty/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
 
@@ -336,13 +45,6 @@ typedef enum {
   kNumEntropyIx = 6
 } EntropyIx;
 
-typedef enum {
-  kSortedDefault = 0,
-  kMinimizeDelta = 1,
-  kModifiedZeng = 2,
-  kUnusedPalette = 3,
-} PaletteSorting;
-
 typedef enum {
   kHistoAlpha = 0,
   kHistoAlphaPred,
@@ -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;
 

+ 1 - 3
thirdparty/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

+ 34 - 8
thirdparty/libwebp/src/mux/anim_encode.c

@@ -22,6 +22,7 @@
 #include "src/webp/encode.h"
 #include "src/webp/format_constants.h"
 #include "src/webp/mux.h"
+#include "src/webp/types.h"
 
 #if defined(_MSC_VER) && _MSC_VER < 1900
 #define snprintf _snprintf
@@ -593,16 +594,17 @@ int WebPAnimEncoderRefineRect(
     int is_lossless, float quality, int* const x_offset, int* const y_offset,
     int* const width, int* const height) {
   FrameRectangle rect;
-  const int right = clip(*x_offset + *width, 0, curr_canvas->width);
-  const int left = clip(*x_offset, 0, curr_canvas->width - 1);
-  const int bottom = clip(*y_offset + *height, 0, curr_canvas->height);
-  const int top = clip(*y_offset, 0, curr_canvas->height - 1);
+  int right, left, bottom, top;
   if (prev_canvas == NULL || curr_canvas == NULL ||
       prev_canvas->width != curr_canvas->width ||
       prev_canvas->height != curr_canvas->height ||
       !prev_canvas->use_argb || !curr_canvas->use_argb) {
     return 0;
   }
+  right = clip(*x_offset + *width, 0, curr_canvas->width);
+  left = clip(*x_offset, 0, curr_canvas->width - 1);
+  bottom = clip(*y_offset + *height, 0, curr_canvas->height);
+  top = clip(*y_offset, 0, curr_canvas->height - 1);
   rect.x_offset_ = left;
   rect.y_offset_ = top;
   rect.width_ = clip(right - left, 0, curr_canvas->width - rect.x_offset_);
@@ -1397,7 +1399,10 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
     }
     config = *encoder_config;
   } else {
-    WebPConfigInit(&config);
+    if (!WebPConfigInit(&config)) {
+      MarkError(enc, "Cannot Init config");
+      return 0;
+    }
     config.lossless = 1;
   }
   assert(enc->curr_canvas_ == NULL);
@@ -1418,12 +1423,14 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
 // -----------------------------------------------------------------------------
 // Bitstream assembly.
 
-static int DecodeFrameOntoCanvas(const WebPMuxFrameInfo* const frame,
-                                 WebPPicture* const canvas) {
+WEBP_NODISCARD static int DecodeFrameOntoCanvas(
+    const WebPMuxFrameInfo* const frame, WebPPicture* const canvas) {
   const WebPData* const image = &frame->bitstream;
   WebPPicture sub_image;
   WebPDecoderConfig config;
-  WebPInitDecoderConfig(&config);
+  if (!WebPInitDecoderConfig(&config)) {
+    return 0;
+  }
   WebPUtilClearPic(canvas, NULL);
   if (WebPGetFeatures(image->bytes, image->size, &config.input) !=
       VP8_STATUS_OK) {
@@ -1582,4 +1589,23 @@ const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc) {
   return enc->error_str_;
 }
 
+WebPMuxError WebPAnimEncoderSetChunk(
+    WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data,
+    int copy_data) {
+  if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+  return WebPMuxSetChunk(enc->mux_, fourcc, chunk_data, copy_data);
+}
+
+WebPMuxError WebPAnimEncoderGetChunk(
+    const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data) {
+  if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+  return WebPMuxGetChunk(enc->mux_, fourcc, chunk_data);
+}
+
+WebPMuxError WebPAnimEncoderDeleteChunk(
+    WebPAnimEncoder* enc, const char fourcc[4]) {
+  if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+  return WebPMuxDeleteChunk(enc->mux_, fourcc);
+}
+
 // -----------------------------------------------------------------------------

+ 11 - 8
thirdparty/libwebp/src/mux/muxedit.c

@@ -66,14 +66,16 @@ void WebPMuxDelete(WebPMux* mux) {
 
 // Handy MACRO, makes MuxSet() very symmetric to MuxGet().
 #define SWITCH_ID_LIST(INDEX, LIST)                                            \
-  if (idx == (INDEX)) {                                                        \
-    err = ChunkAssignData(&chunk, data, copy_data, tag);                       \
-    if (err == WEBP_MUX_OK) {                                                  \
-      err = ChunkSetHead(&chunk, (LIST));                                      \
-      if (err != WEBP_MUX_OK) ChunkRelease(&chunk);                            \
+  do {                                                                         \
+    if (idx == (INDEX)) {                                                      \
+      err = ChunkAssignData(&chunk, data, copy_data, tag);                     \
+      if (err == WEBP_MUX_OK) {                                                \
+        err = ChunkSetHead(&chunk, (LIST));                                    \
+        if (err != WEBP_MUX_OK) ChunkRelease(&chunk);                          \
+      }                                                                        \
+      return err;                                                              \
     }                                                                          \
-    return err;                                                                \
-  }
+  } while (0)
 
 static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag,
                            const WebPData* const data, int copy_data) {
@@ -555,7 +557,8 @@ static WebPMuxError MuxCleanup(WebPMux* const mux) {
   if (num_frames == 1) {
     WebPMuxImage* frame = NULL;
     err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame);
-    assert(err == WEBP_MUX_OK);  // We know that one frame does exist.
+    if (err != WEBP_MUX_OK) return err;
+    // We know that one frame does exist.
     assert(frame != NULL);
     if (frame->header_ != NULL &&
         ((mux->canvas_width_ == 0 && mux->canvas_height_ == 0) ||

+ 2 - 2
thirdparty/libwebp/src/mux/muxi.h

@@ -28,8 +28,8 @@ extern "C" {
 // Defines and constants.
 
 #define MUX_MAJ_VERSION 1
-#define MUX_MIN_VERSION 3
-#define MUX_REV_VERSION 2
+#define MUX_MIN_VERSION 4
+#define MUX_REV_VERSION 0
 
 // Chunk object.
 typedef struct WebPChunk WebPChunk;

+ 13 - 9
thirdparty/libwebp/src/mux/muxread.c

@@ -21,20 +21,23 @@
 
 // Handy MACRO.
 #define SWITCH_ID_LIST(INDEX, LIST)                                           \
-  if (idx == (INDEX)) {                                                       \
-    const WebPChunk* const chunk = ChunkSearchList((LIST), nth,               \
-                                                   kChunks[(INDEX)].tag);     \
-    if (chunk) {                                                              \
-      *data = chunk->data_;                                                   \
-      return WEBP_MUX_OK;                                                     \
-    } else {                                                                  \
-      return WEBP_MUX_NOT_FOUND;                                              \
+  do {                                                                        \
+    if (idx == (INDEX)) {                                                     \
+      const WebPChunk* const chunk = ChunkSearchList((LIST), nth,             \
+                                                     kChunks[(INDEX)].tag);   \
+      if (chunk) {                                                            \
+        *data = chunk->data_;                                                 \
+        return WEBP_MUX_OK;                                                   \
+      } else {                                                                \
+        return WEBP_MUX_NOT_FOUND;                                            \
+      }                                                                       \
     }                                                                         \
-  }
+  } while (0)
 
 static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
                            uint32_t nth, WebPData* const data) {
   assert(mux != NULL);
+  assert(idx != IDX_LAST_CHUNK);
   assert(!IsWPI(kChunks[idx].id));
   WebPDataInit(data);
 
@@ -429,6 +432,7 @@ WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4],
     return WEBP_MUX_INVALID_ARGUMENT;
   }
   idx = ChunkGetIndexFromFourCC(fourcc);
+  assert(idx != IDX_LAST_CHUNK);
   if (IsWPI(kChunks[idx].id)) {     // An image chunk.
     return WEBP_MUX_INVALID_ARGUMENT;
   } else if (idx != IDX_UNKNOWN) {  // A known chunk type.

+ 4 - 1
thirdparty/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;
 }

+ 7 - 4
thirdparty/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"

+ 402 - 0
thirdparty/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 ([email protected])
+
+#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;
+}

+ 60 - 0
thirdparty/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 ([email protected])
+
+#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_

+ 5 - 61
thirdparty/libwebp/src/utils/utils.c

@@ -11,13 +11,13 @@
 //
 // Author: Skal ([email protected])
 
+#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)

+ 1 - 2
thirdparty/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);
 

+ 58 - 56
thirdparty/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

+ 25 - 21
thirdparty/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.

+ 44 - 39
thirdparty/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);
 
 //------------------------------------------------------------------------------
 

+ 76 - 15
thirdparty/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
@@ -521,6 +531,57 @@ WEBP_EXTERN const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc);
 //   enc - (in/out) object to be deleted
 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

+ 2 - 1
thirdparty/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) {

+ 29 - 8
thirdparty/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);