Compare commits

..

99 Commits

Author SHA1 Message Date
9ce5843dba update ChangeLog
Change-Id: I12c2b718e99087201a57f7ab7cc4c16374e205f6
2021-07-29 15:55:37 -07:00
d9191588ab fuzzer/*: normalize src/ includes
this uses the format introduced to some files in:
cc3577e9 fuzzer/*: use src/ based include paths

Change-Id: I9b5cbeadbb9d54d1e89f474a6e479a5eb3175ed7
(cherry picked from commit c5bc36243a)
2021-07-29 20:15:30 +00:00
53b6f76209 fix indent
after:
277d3074 Fix size_t overflow in  WebPRescalerInit

Change-Id: I9adf7f01f28ddd54305512762e2ed28713282966
(cherry picked from commit d2caaba435)
2021-07-28 20:22:18 +00:00
731246ba3b update ChangeLog
Change-Id: Ia3faaafd42eb96e257415e1cf9c7ceb69f851147
2021-07-26 18:19:56 -07:00
d250f01d95 dsp/*: use WEBP_HAVE_* to determine Init availability
after:
  ece18e55 dsp.h: respect --disable-sse2/sse4.1/neon
WEBP_USE_* will be set when a module is targeting a particular
instruction set, e.g., sse4.1, and not overridden if WEBP_HAVE_SSE41 is
set, as previously this would ignore the case where the instruction set
was disabled via config.h and the HAVE macro was unset.

dsp.h not ensures WEBP_HAVE_* are set when WEBP_USE_* to cover cases
where the files are built without config.h.

Change-Id: Ia1c2dcf4100cc1081d968acb6e085e2a1768ece6
(cherry picked from commit 1fe3162541)
2021-07-26 20:44:58 +00:00
3a4d3ecd40 update NEWS
Bug: webp:521
Change-Id: Ic52942bcbfa8aa8e41b95991c0663698884fa8a8
2021-07-20 18:12:28 -07:00
b2bc809346 bump version to 1.2.1
libwebp{,decoder} - 1.2.1
libwebp libtool - 8.2.1
libwebpdecoder libtool - 4.2.1

mux - 1.2.1
libtool - 3.7.0

demux - 1.2.1
libtool - 2.8.0

Bug: webp:521
Change-Id: I098e3e9df698baa275dea85315b9136e565e9971
2021-07-20 18:12:24 -07:00
e542fc7a8a update AUTHORS
Bug: webp:521
Change-Id: Ie2decd9def1a718a01aa1e381ef8f284d18fe279
2021-07-20 18:12:16 -07:00
e024115490 Merge "libwebp/CMake: Add <BUILD_INTERFACE> to webp incl" into main 2021-07-19 20:40:32 +00:00
edea64442c libwebp/CMake: Add <BUILD_INTERFACE> to webp incl
This way target_link_libraries(my_target PUBLIC webp) is enough,
no need to add include directories explicitly for the public headers
such as src/webp/decode.h. This matches the /usr/include/webp/decode.h
installation folder path prefix (#include "webp/decode.h").
See https://bugs.chromium.org/p/webp/issues/detail?id=532

The target_include_directories() calls for cwebp, dwebp etc. may be
unnecessary now and may be removed in another patch.

Change-Id: I2c85218920ffc35ebec23e0dd239f71e29add23b
2021-07-19 18:46:03 +02:00
ece18e5520 dsp.h: respect --disable-sse2/sse4.1/neon
previously this would be overridden if the instruction set was enabled
via -msse4.1, __aarch64__, etc.

Change-Id: I51e87a7da7589c6093d260b848ab41d89ec7b990
2021-07-17 12:14:38 -07:00
a89a3230c9 wicdec: support alpha from WebP WIC decoder
the container check may not be strictly necessary now that the alpha
check has matured and the library will detect usable alpha, but it's
safer to fix this case first before making larger changes.

Bug: webp:533
Change-Id: I2e1ba42156970d579a52bd183707a037e65fd900
2021-07-16 12:19:33 -07:00
26f4aa0115 Merge "alpha_processing: fix visual studio warnings" into main 2021-07-13 23:42:08 +00:00
8f5946634e alpha_processing: fix visual studio warnings
similar to '* const', __restrict needs to be included in the
declaration to avoid warnings like:
src\dsp\alpha_processing.c(429): warning C4028: formal parameter 1
different from declaration

this change also moves WEBP_RESTRICT to dsp.h to avoid a circular
dependency between it and utils.h which already includes dsp.h

Change-Id: Ib070d358a372e76fae4be5445ab288940b9baac0
2021-07-13 23:41:45 +00:00
46d844e6cf Merge "cpu.cmake: fix compiler flag detection w/3.17.0+" into main 2021-07-09 22:22:56 +00:00
298d26eac2 Merge changes I593adf92,If20675e7,Ifac68eac into main
* changes:
  configure: enable libwebpmux by default
  configure: add informational notices when disabling binaries
  configure: move lib flag checks before binaries
2021-07-08 05:35:24 +00:00
a1e5dae0f0 alpha_processing*: use WEBP_RESTRICT qualifier
this helps both auto-vectorization in the C code and the optimized code
generation

Change-Id: Ide570d6be45125ffef7248bdc40e9eb08f00e832
2021-07-07 15:39:21 -07:00
327ef24fbd cpu.cmake: fix compiler flag detection w/3.17.0+
Between 3.17.0 and 3.18.2 check_cxx_compiler_flag() sets a normal
variable at parent scope while check_cxx_source_compiles() continues to
set an internal cache variable, so we unset both to avoid the failure /
success state persisting between checks.

This was fixed in 3.18.3 [1], but regressed shortly afterward [2];
currently seen with 3.20.0 installed via homebrew.

[1] https://gitlab.kitware.com/cmake/cmake/-/issues/21207
[2]
90dead024c CheckCompilerFlag: unified way to check compiler flags per language

Change-Id: I57282f89b07a9cfd85aca7569380f7d115c0b3cf
2021-07-05 18:16:55 -07:00
f70819de51 configure: enable libwebpmux by default
this will provide the main libraries and their supporting examples by
default if external library requirements (e.g., gif2webp+libgif) are
met.

Bug: webp:501
Change-Id: I593adf9222698e2dc5a2199909949c7fea1273b2
2021-07-03 15:58:09 -07:00
dc7e2b42e7 configure: add informational notices when disabling binaries
this better documents the requirements for some of the examples.

Bug: webp:501
Change-Id: If20675e71ebf2c1d9bb51d65a05fd4e9f339ac5a
2021-07-03 15:58:04 -07:00
9df23dddc2 configure: move lib flag checks before binaries
this ensures the defaults are set properly before testing conditions for
enabling certain binaries. previously anim_diff would need
--enable-libwebpdemux to be explicitly added though it defaults to
enabled.

Bug: webp:501
Change-Id: Ifac68eac7096b39e98d0025e07a37b0be3d32c0a
2021-07-03 15:58:01 -07:00
a2e18f10eb Merge "WebPConfig.config.in: correct WEBP_INCLUDE_DIRS" into main 2021-06-29 18:56:36 +00:00
e1a8d4f3fe Merge "bit_reader_inl_utils: uniformly apply WEBP_RESTRICT" into main 2021-06-28 23:19:21 +00:00
4de35f4383 rescaler.c: fix alignment
Change-Id: Ifc2d0d301280baaa403fcdf8722fce42d28a1853
2021-06-28 11:08:50 +02:00
0f13eec7bf bit_reader_inl_utils: uniformly apply WEBP_RESTRICT
this can help with some aliasing issues with some versions of clang/gcc,
similar to:
3e265136 Add WEBP_RESTRICT & use it in VP8BitReader

Change-Id: I863e53cc9d707c9a4b21373ca743c3089aed012e
2021-06-26 10:53:01 -07:00
277d30749f Fix size_t overflow in WebPRescalerInit
we need to surface potential error up, so lot of signature changes.

Change-Id: I7c11a46c4542564d06417203cd1158754e30a9e4
2021-06-25 14:54:42 -07:00
97adbba513 WebPConfig.config.in: correct WEBP_INCLUDE_DIRS
this should be the full path to the installed headers to be added to the
client code's search path, e.g., /usr/local/include when including
<webp/decode.h>

Bug: webp:509
Change-Id: I756249876d8de421c9a33513221fb635157560ef
2021-06-25 10:49:14 -07:00
b60d460318 advanced_api_fuzzer: add extreme config value coverage
this enables cases that might trigger overflows, but increases the risk
of OOM and timeouts

Bug: chromium:1196850
Change-Id: I317b5109525646731e762faa3c34ed28a27595dc
2021-06-23 18:53:05 -07:00
72fe52f623 anim_encode.c,cosmetics: normalize indent
Change-Id: Iba33a60850ec481b73b7eccb67492e7f1dd3d10e
2021-06-23 15:14:04 -07:00
116d235c30 anim_encode: Fix encoded_frames_[] overflow
Check encoded_frames_ count and call FlushFrames if necessary after
IncreasePreviousDuration. Avoids an overflow in encoded_frames_[] with
-kmax 0 and an assertion failure related to the previous and keyframe
durations when a frame is forced in this way.

Based on patch by tomwei7g <at> gmail

Bug: webp:518
Change-Id: Idef685e6c06a67d48fcdc048265ca0e672a01263
2021-06-23 15:13:43 -07:00
6f445b3e3d CMake: set CMP0072 to NEW
Silences CMake's warning and uses GLVND, which still works for linux

Signed-off-by: Christopher Degawa <ccom@randomderp.com>
Change-Id: Iadd173b41c4fbcdff9fe512f9a7dbf70a6d95bcd
2021-06-21 21:25:28 -05:00
b1cf887f86 define WEBP_RESTRICT for MSVC
__restrict is supported:
https://docs.microsoft.com/en-us/cpp/cpp/extension-restrict?view=msvc-160

+ add a comment and simplify the __restrict__ check, clang defines
__GNUC__

Change-Id: I76d8d3cbd1b730f492c6fc0b2114f1897886b677
2021-06-18 19:30:38 -07:00
3e26513656 Add WEBP_RESTRICT & use it in VP8BitReader
Marking the `VP8BitReader` as `__restrict__` helps the compiler generate
better code avoiding issues related to aliasing (re-loads/stores).

Change-Id: Ib7178f57e27e5f40572efc3e567cdf994ea6d928
2021-06-18 19:28:54 -07:00
f6d2924757 vp8l_dec::ProcessRows: fix int overflow in multiply
use 64-bit math in calculating the offsets as they may exceed 32-bits
when scaling

Bug: chromium:1196850
Change-Id: I6a484fc4dded6f6c4b82346ef145eb69c1477b3c
2021-06-16 10:50:44 -07:00
de3b4ba813 CMake: add WEBP_BUILD_LIBWEBPMUX
Adds an additional option similar to configure's --enable-libwebpmux
to toggle building libwebpmux separate from the binaries

Signed-off-by: Christopher Degawa <ccom@randomderp.com>
Change-Id: I0443b84eea36d86791e2e421a6fc0070879a7bef
2021-06-16 16:55:45 +00:00
7f09d3d132 CMakeLists.txt: rm libwebpmux dep from anim_{diff,dump}
Change-Id: Ic293affca5a3e17afbfcda5e96eb101d005621b8
2021-06-16 04:40:21 +00:00
4edea4a695 Init{RGB,YUV}Rescaler: fix a few more int overflows
promote out_width to size_t before multiplying

src/dec/io_dec.c:301:30: runtime error: signed integer overflow: 2 *
1224167500 cannot be represented in type 'int'
  #0 0x55fd9e8de2bd in InitYUVRescaler src/dec/io_dec.c:301:30
  #1 0x55fd9e8de2bd in CustomSetup src/dec/io_dec.c:571:54

Bug: chromium:1196850
Change-Id: I70d0aac1b5eef163a3f353b721fb9ab561e02040
2021-06-14 12:22:28 -07:00
c9e26bdb35 rescaler_utils: set max valid scaled w/h to INT_MAX/2
this will avoid the potential for some integer overflows in rescaler
calculations

Bug: chromium:1196850
Change-Id: Iaa09f5d6b888b39aaeb2154d470279620362d6eb
2021-06-14 12:22:28 -07:00
28d488e6f1 utils.h: add SizeOverflow()
this normalizes the 'size != (size_t)size' checks in the libraries.

Change-Id: I1e8ccd0d3697266f23911ecf0f7a546f011befde
2021-06-14 12:22:28 -07:00
695bdaa2f6 Export/EmitRescaledRowsRGBA: fix pointer offset int overflow
in Export increment the dst pointer, but in EmitRescaledRowsRGBA use
64-bit math as the number of output lines is variable and may still
overflow when incrementing.

Bug: chromium:1196850
Change-Id: I5c65b875894ee9da0fef1e24d27e507171800c4a
2021-06-14 12:22:21 -07:00
685d073ee1 Init{RGB,YUV}Rescaler: fix int overflows in multiplication
with large sizes the intermediate calculations may exceed 32-bits

src/dec/io_dec.c:491:17: runtime error: signed integer overflow: 3 *
788529152 cannot be represented in type 'int'
  #0 0x557a3ad972b2 in InitRGBRescaler src/dec/io_dec.c:491:17
  #1 0x557a3ad972b2 in CustomSetup src/dec/io_dec.c:563:29

Bug: chromium:1196850
Change-Id: Iaf2e8a6de9481dfea31dcd7fccb2d4eca767bddf
2021-06-10 15:26:44 -07:00
d38bd0dda0 WebPFlipBuffer: fix integer overflow
with large scale values the offset to the end of the buffer may exceed
32-bits range.

src/dec/buffer_dec.c:158:39: runtime error: signed integer overflow: 2 *
1275068416 cannot be represented in type 'int'
  #0 0x56444802bea5 in WebPFlipBuffer src/dec/buffer_dec.c:158:39

Bug: chromium:1196850
Change-Id: I08c8b69ada5d5dd3e9bf2b9006dffa0c5f2103a5
2021-06-10 15:26:34 -07:00
109ff0f100 utils: allow MALLOC_LIMIT to indicate a max
in addition to checking the environment for "MALLOC_LIMIT"; the
environment will still take precedence.
this is in preparation for adding extreme config value coverage to
advanced_api_fuzzer

Bug: chromium:1196850
Change-Id: Ibe22f5e39e030a422fd6e383269bde35252d3fae
2021-06-07 18:59:39 -07:00
a2fce86744 WebPRescalerImportRowExpand_C: promote some vals before multiply
avoids integer overflow in extreme cases:
src/dsp/rescaler.c:45:32: runtime error: signed integer overflow: 129 *
16777215 cannot be represented in type 'int'
    #0 0x556bde3538e3 in WebPRescalerImportRowExpand_C src/dsp/rescaler.c:45:32
    #1 0x556bde357465 in RescalerImportRowExpand_SSE2 src/dsp/rescaler_sse2.c:56:5
    ...

Bug: chromium:1196850
Change-Id: I4f923807f106713e113f3eec62a1d1c346066345
2021-06-07 18:59:33 -07:00
776983d427 AllocateBuffer: fix int multiplication overflow check
after the check using 64-bit math we used a signed integer in the
multiplication. previously unsigned integer max was tested.

fixes cases like:
src/dec/buffer_dec.c:108:16: runtime error: signed integer overflow:
944731466 * 4 cannot be represented in type 'int'
    #0 0x55e56187dc1d in AllocateBuffer src/dec/buffer_dec.c:108:16
    #1 0x55e56187dc1d in WebPAllocateDecBuffer src/dec/buffer_dec.c:216:12
    ...

Bug: chromium:1196850
Change-Id: I6e5b3e5d1d5b50b5c98c39bbf9813a63fedc5ca7
2021-06-07 18:59:24 -07:00
315abbd60b Merge "Revert "Do not use a palette for one color images."" 2021-05-24 18:53:42 +00:00
eae815d0d1 Merge changes Ica3bbf75,I82f82954
* changes:
  cosmetics: remove use of 'sanity' / 'master'
  WebPAnimEncoderNewInternal: remove some unnecessary inits
2021-05-24 18:53:20 +00:00
afbca5a152 Require Emscripten 2.0.18
Change-Id: I04fe7041fcd82d08416c37a6e95c36acb70c39dc
2021-05-24 10:35:36 -07:00
3320416b2e CMakeLists,emscripten: use EXPORTED_RUNTIME_METHODS
rather than EXTRA_EXPORTED_RUNTIME_METHODS. this was deprecated in
2.0.18.

quiets a warning:
emcc: warning: EXTRA_EXPORTED_RUNTIME_METHODS is deprecated, please use
EXPORTED_RUNTIME_METHODS instead [-Wdeprecated]

https://emscripten.org/docs/introducing_emscripten/release_notes.html?highlight=exported_runtime_methods

Change-Id: I3acf22339a64f39a342051841a147744f6af954a
2021-05-21 15:09:04 -07:00
29145ed692 Update README instructions for using Emscripten
- Point to a newer URL
- Use emcmake and emmake (which will set the CMake project file)

Change-Id: I3341b9f8e741436bc5961fbc77586963f3241c7a
2021-05-21 11:47:01 -07:00
1f5791398c cosmetics: remove use of 'sanity' / 'master'
replace with more inclusive terms or remove the comment entirely if the
meaning was already clear.

Bug: webp:507
Change-Id: Ica3bbf751ebf79f6668df6e6209af770248ff4ca
2021-05-21 10:38:40 -07:00
29b6129c78 WebPAnimEncoderNewInternal: remove some unnecessary inits
enc is allocated with WebPSafeCalloc so there's no need to clear the
pointers afterward.
this has the side-effect of removing a non-inclusive term.

Bug: webp:507
Change-Id: I82f82954936638c4c15d33b2d6f0497a6a13571f
2021-05-21 10:31:50 -07:00
b60869a18e Revert "Do not use a palette for one color images."
This reverts commit b6513fbaa8.

This change can produce files that can cause decode failures in some
versions of chrome and safari/ios/macos.

https://chromium-review.googlesource.com/c/chromium/src/+/2876279

The chrome fix will be available in M92. This change can be revisited
after it and the mac updates are more widely deployed.

Bug: b/186640109,b/188702956
Change-Id: I296b8fe88c6c48219e3edf532226c4f972f1605b
2021-05-21 10:26:37 -07:00
6fb4cddc93 demux: move padded size calc post unpadded validation
though the max chunk/payload sizes were checked and would fail the
padded size was being calculated beforehand which could result in a
(harmless) unsigned int overflow warning.

Bug: webp:508
Change-Id: I4fa30ded2b027c1577b03049a2deeb7bf75e5472
2021-05-15 10:59:06 -07:00
05b72d4205 vp8l_enc.c: normalize index types
fixes conversion warnings in visual studio after:
b1674240 Add modified Zeng's method to palette sorting.

src\enc\vp8l_enc.c(296) : warning C4244: '=' : conversion from 'const
uint16_t' to 'uint8_t', possible loss of data
src\enc\vp8l_enc.c(299) : warning C4244: '=' : conversion from 'const
uint16_t' to 'uint8_t', possible loss of data

Change-Id: I981b1ba4912edbbafbd49f1f5b1043bf12266920
2021-04-28 15:09:34 -07:00
b6513fbaa8 Do not use a palette for one color images.
1 color images now always take 30 bytes.

Change-Id: Ifa86bc5320362c659672b3836160353d63576467
2021-04-28 13:14:28 +02:00
98bbe35b51 Fix multi-threading with palettes.
Change-Id: Ifa23378c1f9c489d5963b4928781e104a14eb01a
2021-04-27 16:54:03 +02:00
b1674240f9 Add modified Zeng's method to palette sorting.
Also add palette sorting to crunch configurations.

Change-Id: I010a8bf8f1921279db6e9c7209307d8d19a4d105
2021-04-27 13:11:18 +02:00
88c90c4528 add CONTRIBUTING.md
this contains some of the basics for contributing patches to the
project. over time the instructions from
https://www.webmproject.org/code/contribute/submitting-patches/ can be
added here.

Change-Id: Ib5fcbc818c6feb87654517fdd7118f226c5cccc3
2021-04-23 18:35:44 -07:00
6a9916d734 WebPRescalerInit: add missing int64_t promotion
large values of x_add and y_add may rollover an int causing a later
assertion to fail in WebPRescalerExportRow due to fxy_scale incorrectly
being set to 0.

fixes:
src/dsp/rescaler.c:178: void WebPRescalerExportRow(WebPRescaler *const):
Assertion `wrk->src_height == wrk->dst_height && wrk->x_add == 1'
failed.

Bug: chromium:1196480
Change-Id: I2c00f015d61a1257033d8edb1edd4d060d6878b7
2021-04-23 11:46:45 -07:00
b6cf52d5b8 WebPIoInitFromOptions: treat use_scaling as a bool
this matches the description in WebPDecoderOptions and prevents a
mismatch between the user supplied options and the ones used by io.

Bug: chromium:1196773, chromium:1196775, chromium:1196480
Change-Id: I3603b806884cfc6969b093d06b7980b0cc13199b
2021-04-23 11:46:45 -07:00
3b12b7f4b4 WebPIoInitFromOptions: treat use_cropping as a bool
this matches the description in WebPDecoderOptions and prevents a
mismatch between the user supplied options and the ones used by io.

Bug: chromium:1196480
Change-Id: Id464f999d737078078f9d21afe25b349317f5ab4
2021-04-23 11:46:45 -07:00
595fa13f83 add WebPCheckCropDimensions()
and avoid integer overflow in test of x/width and y/height parameters
against the image width/height

Bug: chromium:1196778, chromium:1196777, chromium:1196480
Change-Id: I7b8f1f4dbebfe073b1ba260b8317979488655dcc
2021-04-23 11:46:45 -07:00
8fdaecb09d Disable cross-color when palette is used.
With palette+predictors, cross-color was forced (because of predictors).
No need for cross-color for palettes as R/B==0.
This saves 10 bytes per image that uses palette+predictors.

Change-Id: If2184d16cdabe1e8498009062284ad3e37ef1342
2021-04-23 17:43:36 +02:00
8933bac212 WebPIoInitFromOptions: respect incoming bypass_filtering val
if bypass_filtering was set to 1 in the user provided options it
shouldn't be reset in the use_scaling pass even if the image satisfies
the scaling requirements.

Change-Id: I036029907886acb63748872d5f8763954a7c607b
2021-04-19 19:02:13 -07:00
7d416ff085 webpdec,cosmetics: match error text to function call
WebPINewDecoder -> WebPIDecode

Change-Id: I5c17486ce2598a5dda687d7bc579daf7630c2133
2021-04-17 15:13:43 -07:00
ec6cfeb51e Fix typo on WebPPictureAlloc() in README
Change-Id: I4435a6a2e53495e475f7f833b7d38b6a29ed73d1
2021-04-15 19:11:49 +02:00
7e58a1a260 *.cmake: add license header
this syncs the files with CMakeLists.txt

Change-Id: I94d45ef61d33ee9e43973b5d4e85fab007941f67
2021-04-12 17:28:15 -07:00
5651a6b2ed cmake: fix .so versioning
libtool uses -version-info current:revision:age, but the library created
is [c-a].a.r.

Change-Id: Icf081e156a818a3cd7579ad5ffe3b518d8532bdb
2021-04-07 13:51:22 -07:00
25ae67b3de xcframeworkbuild.sh: add arm64 simulator target
this fixes simulator builds on an M1

Bug: webp:510
Change-Id: Ia2c81d33d9a85b432b17f22305b110ccc337b809
2021-03-15 15:25:44 -07:00
5d4ee4c3c0 cosmetics: remove use of the term 'dummy'
this is replaced with more inclusive / informative text

Bug: webp:507
Change-Id: Ib77f0c79dd548601bf2bc3169985af4b5edf0a62
2021-03-15 11:39:06 -07:00
01b38ee19a faster CollectColorXXXTransforms_SSE41
3/4% faster overall.

Change-Id: If555c5530238ca0342b8d97b0d708b1bdc888d3f
2021-02-19 20:45:07 +01:00
652aa34424 Merge "Use BitCtz for FastSLog2Slow_C" 2021-02-19 17:39:30 +00:00
0320e1e36f add the missing default BitsCtz() code
Change-Id: Iff3ea946a380837b9dfad58350173b68b45e1347
2021-02-19 17:04:35 +00:00
8886f620c0 Use BitCtz for FastSLog2Slow_C
Change-Id: Icc6068b8934e481e6f17efd30616392e68d504ad
2021-02-19 15:11:42 +01:00
fae416179e faster CombinedShannonEntropy_SSE2
optimized for sparse histograms

Change-Id: I54412f5f8fc53d2598964a5be91f6c54ece3f21b
2021-02-19 13:14:46 +01:00
5bd2704e30 Introduce the BitCtz() function.
* Use a WEBP_HAVE_SLOW_CLZ_CTZ flag when they are slow (LUT-based).

Change-Id: If707c121b8800438be404594a39bb123ef25b0f0
2021-02-19 11:52:05 +01:00
fee642870e Merge "wicdec,icc: treat unsupported op as non-fatal" 2021-02-18 21:28:47 +00:00
33ddb894b1 lossless_sse{2,41}: remove some unneeded includes
Change-Id: Icd2cffd32b39c6bf017eee353ac04a4b6d337a11
2021-02-18 10:54:09 -08:00
b27ea8525a wicdec,icc: treat unsupported op as non-fatal
ICC extraction via GetColorContexts may fail due to the operation not
being supported with e.g., bitmaps.

Bug: webp:506
Change-Id: I587220e688ac90d77c84af21c9e7bc8bf178f3aa
2021-02-18 10:36:13 -08:00
b78494a933 Merge "Fix undefined signed shift." 2021-02-18 16:51:17 +00:00
e79974cd6a Fix undefined signed shift.
Using the fix from SSE2.

Change-Id: Ie53d0163d97322da5a722c3e49f9d5f057ee1d91
2021-02-18 16:56:22 +01:00
a885339448 SSE4.1 versions of BGRA to RGB/BGR color-space conversions
Change-Id: Iacafd2f6402080b02fcbf75831e69c488f447454
2021-02-18 15:32:30 +01:00
a09a647241 SSE4.1 version of TransformColorInverse
Change-Id: I6ba5cb35917eef7a52152c4924eca205b4af7220
2021-02-18 12:42:39 +01:00
401da22bd6 Merge "pngdec: check version before using png_get_chunk_malloc_max" 2021-02-11 00:44:19 +00:00
2690782292 pngdec: check version before using png_get_chunk_malloc_max
png_get_chunk_malloc_max / png_set_chunk_malloc_max were added in 1.4.1.

Bug: webp:505, webp:497
Change-Id: Id4e0643a7734563fec7779f7943ec760da8d276d
2021-02-10 13:41:54 -08:00
06c1e72e71 Code cleanup
* match param names

Change-Id: Ib75197a3c6bcc735049c6724dce6c240684108ae
2021-02-10 22:14:45 +01:00
8f0d41aac0 Merge changes Id135bbf4,I99e59797
* changes:
  cmake: add WEBP_USE_THREAD option
  cmake: don't install binaries from extras/
2021-02-09 21:25:12 +00:00
373eb170f1 gif2webp: don't store loop-count if there's only 1 frame
BUG=webp:504

Change-Id: Iacea11a861096ae950379c872d9840bdbec42a21
2021-02-08 22:00:48 +00:00
759b9d5a06 cmake: add WEBP_USE_THREAD option
this controls the config.h define of the same name and matches the
behavior of configure's --disable-threading

Bug: webp:502
Change-Id: Id135bbf4e6b3c9900e2b4f4f7ab744b3457ce41c
2021-02-05 15:32:41 -08:00
926ce921f3 cmake: don't install binaries from extras/
this matches the behavior of configure

Bug: webp:502
Change-Id: I99e597971636bdc2b9a9465ba13bb24c70ce87c0
2021-02-05 15:30:06 -08:00
9c367bc602 WebPAnimDecoderNewInternal: validate bitstream before alloc
this avoids large allocations with corrupt files due to the canvas size

BUG=oss-fuzz:28658

Change-Id: Idd1957e5447a2dadaef1fadaf68820fcb29f045a
2021-02-05 13:01:27 -08:00
47f64f6edd filters_sse2: import Chromium change
VerticalUnfilter_SSE2 has long been disabled due to a crash in an
Android emulator that hasn't reproduced elsewhere (crbug.com/654974).
this synchronizes the code for now to avoid needing to locally edit the
file on import.

Bug: 1141126
Change-Id: Ib61aeab93caaff1759606566b9e499eaac1576cf
2021-01-30 11:44:07 -08:00
cc3577e9b9 fuzzer/*: use src/ based include paths
this synchronizes the code with chrome, where this format allows the
code to pass buildtools/checkdeps/checkdeps.py

Bug: 1141126
Change-Id: I25361b1a43cd95730814302f02aa16af8fdb5fd2
2021-01-29 20:04:08 -08:00
004d77ffab Merge tag 'v1.2.0'
libwebp-1.2.0

- 12/23/2020: version 1.2.0
  * API changes:
    - libwebp:
      encode.h: add a qmin / qmax range for quality factor (cwebp adds -qrange)
  * lossless encoder improvements
  * SIMD support for Wasm builds
  * add xcframeworkbuild.sh, supports Mac Catalyst builds
  * import fuzzers from oss-fuzz & chromium (#409)
  * webpmux: add an '-set loop <value>' option (#494)
  * toolchain updates and bug fixes (#449, #463, #470, #475, #477, #478, #479,
    #488, #491)

* tag 'v1.2.0':
  update ChangeLog
  Fix check_c_source_compiles with pthread.
  disable CombinedShannonEntropy_SSE2 on x86
  pngdec: raise memory limit if needed
  {ios,xcframework}build.sh: make min version(s) more visible
  animdecoder_fuzzer: fix memory leak
  update gradle to 6.1.1
  update NEWS
  bump version to 1.2.0
  webp/encode.h: restore WEBP_ENCODER_ABI_VERSION to v1.1.0
  update AUTHORS

Bug: webp:484
Change-Id: I8f716a0e0438537e674092c1bfb60d27d738f69f
2021-01-29 19:24:01 -08:00
ceddb5fc8d Fix check_c_source_compiles with pthread.
Also fix the variables: we need to check for PTHREAD_PRIO_INHERIT
and PTHREAD_CREATE_JOINABLE (not PTHREAD_CREATE_UNDETACHED) and
internally use HAVE_PTHREAD_PRIO_INHERIT and PTHREAD_CREATE_JOINABLE
(and not HAVE_PTHREAD_CREATE_JOINABLE).
cmake/config.h.in actually had the right variables.

BUG=webp:498

Change-Id: Ibf6cf854337cea5781a74316024f8ff4960366d7
2021-01-19 23:15:16 +01:00
289757fe1e TiffDec: enforce stricter mem/dimension limit on tiles
Tile can be even larger than image dimensions.

Change-Id: I80518e815bb11d7a07c8189d0493b3cc60e29815
2021-01-12 10:57:27 +01:00
8696147da4 pngdec: raise memory limit if needed
Some PNG input contain chunks larger than libpng's default
memory-alloc limit (8M).
Raise this limit reasonably if it looks like the input bitstream
is larger than libpng's default limit.

BUG=webp:497

Change-Id: I2c9fbed727424042444b82cbf15e0781cefb38dc
2021-01-08 08:48:39 +01:00
8df77fb1b1 animdecoder_fuzzer: fix memory leak
BUG=oss-fuzz:28978

Change-Id: I7b3a495c02b4b03f367d732af5acb02856f8bead
2020-12-26 12:26:41 +01:00
100 changed files with 1478 additions and 737 deletions

View File

@ -11,3 +11,4 @@ Vikas Arora <vikasa@google.com>
Tamar Levy <tamar.levy@intel.com>
<qrczak@google.com> <qrczak>
Hui Su <huisu@google.com>
James Zern <jzern@google.com>

View File

@ -4,8 +4,11 @@ Contributors:
- Charles Munger (clm at google dot com)
- Cheng Yi (cyi at google dot com)
- Christian Duvivier (cduvivier at google dot com)
- Christopher Degawa (ccom at randomderp dot com)
- Clement Courbet (courbet at google dot com)
- Djordje Pesut (djordje dot pesut at imgtec dot com)
- Hui Su (huisu at google dot com)
- Ilya Kurdyukov (jpegqs at gmail dot com)
- Ingvar Stepanyan (rreverser at google dot com)
- James Zern (jzern at google dot com)
- Jan Engelhardt (jengelh at medozas dot de)
@ -45,3 +48,4 @@ Contributors:
- Wan-Teh Chang (wtc at google dot com)
- Yang Zhang (yang dot zhang at arm dot com)
- Yannis Guyon (yguyon at google dot com)
- Zhi An Ng (zhin at chromium dot org)

View File

@ -74,6 +74,7 @@ dsp_dec_srcs := \
src/dsp/lossless_msa.c \
src/dsp/lossless_neon.$(NEON) \
src/dsp/lossless_sse2.c \
src/dsp/lossless_sse41.c \
src/dsp/rescaler.c \
src/dsp/rescaler_mips32.c \
src/dsp/rescaler_mips_dsp_r2.c \

View File

@ -1,14 +1,17 @@
##
## Copyright (c) 2020 Google LLC.
##
## Use of this source code is governed by a BSD-style license
## that can be found in the LICENSE 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.
# Copyright (c) 2020 Google LLC.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE 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.
cmake_minimum_required(VERSION 3.5)
if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW)
endif()
project(WebP C)
# Options for coder / decoder executables.
@ -26,9 +29,11 @@ option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." ON)
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." ON)
option(WEBP_BUILD_VWEBP "Build the vwebp viewer tool." ON)
option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." ON)
option(WEBP_BUILD_LIBWEBPMUX "Build the libwebpmux library." ON)
option(WEBP_BUILD_WEBPMUX "Build the webpmux command line tool." ON)
option(WEBP_BUILD_EXTRAS "Build extras." ON)
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
option(WEBP_USE_THREAD "Enable threading support" ON)
option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
OFF)
@ -50,6 +55,7 @@ if(WEBP_BUILD_WEBP_JS)
set(WEBP_BUILD_WEBPINFO OFF)
set(WEBP_BUILD_WEBPMUX OFF)
set(WEBP_BUILD_EXTRAS OFF)
set(WEBP_USE_THREAD OFF)
if(WEBP_ENABLE_SIMD)
message("wasm2js does not support SIMD, disabling webp.js generation.")
@ -277,10 +283,12 @@ if(XCODE)
libwebp_add_stub_file(webp)
endif()
target_link_libraries(webp ${WEBP_DEP_LIBRARIES})
target_include_directories(webp
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
PUBLIC $<INSTALL_INTERFACE:include>)
target_include_directories(
webp
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include>)
set_target_properties(
webp
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
@ -315,10 +323,10 @@ ${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/demux/libwebpdemux.pc")
# Set the version numbers.
function(parse_version FILE NAME VAR)
macro(set_version FILE TARGET_NAME NAME_IN_MAKEFILE)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/${FILE} SOURCE_FILE)
string(REGEX MATCH
"${NAME}_la_LDFLAGS[^\n]* -version-info [0-9:]+"
"${NAME_IN_MAKEFILE}_la_LDFLAGS[^\n]* -version-info [0-9:]+"
TMP
${SOURCE_FILE})
string(REGEX MATCH
@ -327,29 +335,35 @@ function(parse_version FILE NAME VAR)
${TMP})
string(REGEX
REPLACE ":"
"."
VERSION
" "
LT_VERSION
${TMP})
set(${VAR} "${VERSION}" PARENT_SCOPE)
endfunction()
parse_version(Makefile.am webp WEBP_WEBP_SOVERSION)
set_target_properties(webp
PROPERTIES VERSION
${PACKAGE_VERSION}
SOVERSION
${WEBP_WEBP_SOVERSION})
parse_version(Makefile.am webpdecoder WEBP_DECODER_SOVERSION)
set_target_properties(webpdecoder
PROPERTIES VERSION
${PACKAGE_VERSION}
SOVERSION
${WEBP_DECODER_SOVERSION})
parse_version(demux/Makefile.am webpdemux WEBP_DEMUX_SOVERSION)
set_target_properties(webpdemux
PROPERTIES VERSION
${PACKAGE_VERSION}
SOVERSION
${WEBP_DEMUX_SOVERSION})
# See the libtool docs for more information:
# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
#
# c=<current>, a=<age>, r=<revision>
#
# libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is
# passed to libtool.
#
# We set FULL = [c-a].a.r and MAJOR = [c-a].
separate_arguments(LT_VERSION)
list(GET LT_VERSION 0 LT_CURRENT)
list(GET LT_VERSION 1 LT_REVISION)
list(GET LT_VERSION 2 LT_AGE)
math(EXPR LT_CURRENT_MINUS_AGE "${LT_CURRENT} - ${LT_AGE}")
set_target_properties(
${TARGET_NAME}
PROPERTIES VERSION
${LT_CURRENT_MINUS_AGE}.${LT_AGE}.${LT_REVISION}
SOVERSION
${LT_CURRENT_MINUS_AGE})
endmacro()
set_version(Makefile.am webp webp)
set_version(Makefile.am webpdecoder webpdecoder)
set_version(demux/Makefile.am webpdemux webpdemux)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE)
string(REGEX MATCH
"AC_INIT\\([^\n]*\\[[0-9\\.]+\\]"
@ -377,6 +391,12 @@ foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
${SIMD_COMPILE_FLAG})
endforeach()
if(NOT WEBP_BUILD_LIBWEBPMUX)
set(WEBP_BUILD_GIF2WEBP OFF)
set(WEBP_BUILD_IMG2WEBP OFF)
set(WEBP_BUILD_WEBPMUX OFF)
endif()
if(WEBP_BUILD_GIF2WEBP AND NOT GIF_FOUND)
set(WEBP_BUILD_GIF2WEBP OFF)
endif()
@ -449,19 +469,14 @@ if(WEBP_BUILD_CWEBP)
install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(WEBP_BUILD_GIF2WEBP OR WEBP_BUILD_IMG2WEBP)
if(WEBP_BUILD_LIBWEBPMUX)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "WEBP_MUX_SRCS" "")
add_library(libwebpmux ${WEBP_MUX_SRCS})
target_link_libraries(libwebpmux webp)
target_include_directories(libwebpmux
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
parse_version(mux/Makefile.am webpmux WEBP_MUX_SOVERSION)
set_target_properties(libwebpmux
PROPERTIES VERSION
${PACKAGE_VERSION}
SOVERSION
${WEBP_MUX_SOVERSION})
set_version(mux/Makefile.am libwebpmux webpmux)
set_target_properties(libwebpmux
PROPERTIES PUBLIC_HEADER
"${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
@ -567,7 +582,6 @@ if(WEBP_BUILD_EXTRAS)
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS get_disto RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# webp_quality
add_executable(webp_quality ${WEBP_QUALITY_SRCS} ${WEBP_EXTRAS_SRCS})
@ -575,7 +589,6 @@ if(WEBP_BUILD_EXTRAS)
target_include_directories(webp_quality
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR})
install(TARGETS webp_quality RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# vwebp_sdl
find_package(SDL)
@ -590,7 +603,6 @@ if(WEBP_BUILD_EXTRAS)
${SDL_INCLUDE_DIR})
set(WEBP_HAVE_SDL 1)
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
install(TARGETS vwebp_sdl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
endif()
@ -606,7 +618,7 @@ if(WEBP_BUILD_WEBP_JS)
webp_js
PROPERTIES LINK_FLAGS "-s WASM=0 \
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
-s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
endif()
@ -619,7 +631,7 @@ if(WEBP_BUILD_WEBP_JS)
webp_wasm
PROPERTIES LINK_FLAGS "-s WASM=1 \
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
-s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
@ -637,7 +649,6 @@ if(WEBP_BUILD_ANIM_UTILS)
imageenc
imageioutil
webp
libwebpmux
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
@ -653,7 +664,6 @@ if(WEBP_BUILD_ANIM_UTILS)
imageenc
imageioutil
webp
libwebpmux
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)

29
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,29 @@
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use a [Gerrit](https://www.gerritcodereview.com) instance hosted at
https://chromium-review.googlesource.com for this purpose. See the
[WebM Project page](https://www.webmproject.org/code/contribute/submitting-patches/)
for additional details.
## Community Guidelines
This project follows
[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).

View File

@ -1,10 +1,109 @@
d9191588 fuzzer/*: normalize src/ includes
53b6f762 fix indent
731246ba update ChangeLog (tag: v1.2.1-rc2)
d250f01d dsp/*: use WEBP_HAVE_* to determine Init availability
3a4d3ecd update NEWS
b2bc8093 bump version to 1.2.1
e542fc7a update AUTHORS
e0241154 Merge "libwebp/CMake: Add <BUILD_INTERFACE> to webp incl" into main
edea6444 libwebp/CMake: Add <BUILD_INTERFACE> to webp incl
ece18e55 dsp.h: respect --disable-sse2/sse4.1/neon
a89a3230 wicdec: support alpha from WebP WIC decoder
26f4aa01 Merge "alpha_processing: fix visual studio warnings" into main
8f594663 alpha_processing: fix visual studio warnings
46d844e6 Merge "cpu.cmake: fix compiler flag detection w/3.17.0+" into main
298d26ea Merge changes I593adf92,If20675e7,Ifac68eac into main
a1e5dae0 alpha_processing*: use WEBP_RESTRICT qualifier
327ef24f cpu.cmake: fix compiler flag detection w/3.17.0+
f70819de configure: enable libwebpmux by default
dc7e2b42 configure: add informational notices when disabling binaries
9df23ddd configure: move lib flag checks before binaries
a2e18f10 Merge "WebPConfig.config.in: correct WEBP_INCLUDE_DIRS" into main
e1a8d4f3 Merge "bit_reader_inl_utils: uniformly apply WEBP_RESTRICT" into main
4de35f43 rescaler.c: fix alignment
0f13eec7 bit_reader_inl_utils: uniformly apply WEBP_RESTRICT
277d3074 Fix size_t overflow in WebPRescalerInit
97adbba5 WebPConfig.config.in: correct WEBP_INCLUDE_DIRS
b60d4603 advanced_api_fuzzer: add extreme config value coverage
72fe52f6 anim_encode.c,cosmetics: normalize indent
116d235c anim_encode: Fix encoded_frames_[] overflow
6f445b3e CMake: set CMP0072 to NEW
b1cf887f define WEBP_RESTRICT for MSVC
3e265136 Add WEBP_RESTRICT & use it in VP8BitReader
f6d29247 vp8l_dec::ProcessRows: fix int overflow in multiply
de3b4ba8 CMake: add WEBP_BUILD_LIBWEBPMUX
7f09d3d1 CMakeLists.txt: rm libwebpmux dep from anim_{diff,dump}
4edea4a6 Init{RGB,YUV}Rescaler: fix a few more int overflows
c9e26bdb rescaler_utils: set max valid scaled w/h to INT_MAX/2
28d488e6 utils.h: add SizeOverflow()
695bdaa2 Export/EmitRescaledRowsRGBA: fix pointer offset int overflow
685d073e Init{RGB,YUV}Rescaler: fix int overflows in multiplication
d38bd0dd WebPFlipBuffer: fix integer overflow
109ff0f1 utils: allow MALLOC_LIMIT to indicate a max
a2fce867 WebPRescalerImportRowExpand_C: promote some vals before multiply
776983d4 AllocateBuffer: fix int multiplication overflow check
315abbd6 Merge "Revert "Do not use a palette for one color images.""
eae815d0 Merge changes Ica3bbf75,I82f82954
afbca5a1 Require Emscripten 2.0.18
3320416b CMakeLists,emscripten: use EXPORTED_RUNTIME_METHODS
29145ed6 Update README instructions for using Emscripten
1f579139 cosmetics: remove use of 'sanity' / 'master'
29b6129c WebPAnimEncoderNewInternal: remove some unnecessary inits
b60869a1 Revert "Do not use a palette for one color images."
6fb4cddc demux: move padded size calc post unpadded validation
05b72d42 vp8l_enc.c: normalize index types
b6513fba Do not use a palette for one color images.
98bbe35b Fix multi-threading with palettes.
b1674240 Add modified Zeng's method to palette sorting.
88c90c45 add CONTRIBUTING.md
6a9916d7 WebPRescalerInit: add missing int64_t promotion
b6cf52d5 WebPIoInitFromOptions: treat use_scaling as a bool
3b12b7f4 WebPIoInitFromOptions: treat use_cropping as a bool
595fa13f add WebPCheckCropDimensions()
8fdaecb0 Disable cross-color when palette is used.
8933bac2 WebPIoInitFromOptions: respect incoming bypass_filtering val
7d416ff0 webpdec,cosmetics: match error text to function call
ec6cfeb5 Fix typo on WebPPictureAlloc() in README
7e58a1a2 *.cmake: add license header
5651a6b2 cmake: fix .so versioning
25ae67b3 xcframeworkbuild.sh: add arm64 simulator target
5d4ee4c3 cosmetics: remove use of the term 'dummy'
01b38ee1 faster CollectColorXXXTransforms_SSE41
652aa344 Merge "Use BitCtz for FastSLog2Slow_C"
0320e1e3 add the missing default BitsCtz() code
8886f620 Use BitCtz for FastSLog2Slow_C
fae41617 faster CombinedShannonEntropy_SSE2
5bd2704e Introduce the BitCtz() function.
fee64287 Merge "wicdec,icc: treat unsupported op as non-fatal"
33ddb894 lossless_sse{2,41}: remove some unneeded includes
b27ea852 wicdec,icc: treat unsupported op as non-fatal
b78494a9 Merge "Fix undefined signed shift."
e79974cd Fix undefined signed shift.
a8853394 SSE4.1 versions of BGRA to RGB/BGR color-space conversions
a09a6472 SSE4.1 version of TransformColorInverse
401da22b Merge "pngdec: check version before using png_get_chunk_malloc_max"
26907822 pngdec: check version before using png_get_chunk_malloc_max
06c1e72e Code cleanup
8f0d41aa Merge changes Id135bbf4,I99e59797
373eb170 gif2webp: don't store loop-count if there's only 1 frame
759b9d5a cmake: add WEBP_USE_THREAD option
926ce921 cmake: don't install binaries from extras/
9c367bc6 WebPAnimDecoderNewInternal: validate bitstream before alloc
47f64f6e filters_sse2: import Chromium change
cc3577e9 fuzzer/*: use src/ based include paths
004d77ff Merge tag 'v1.2.0'
fedac6cc update ChangeLog (tag: v1.2.0-rc3, tag: v1.2.0)
170a8712 Fix check_c_source_compiles with pthread.
ceddb5fc Fix check_c_source_compiles with pthread.
85995719 disable CombinedShannonEntropy_SSE2 on x86
289757fe TiffDec: enforce stricter mem/dimension limit on tiles
8af7436f Merge "{ios,xcframework}build.sh: make min version(s) more visible" into 1.2.0
e56c3c5b pngdec: raise memory limit if needed
8696147d pngdec: raise memory limit if needed
13b8e9fe {ios,xcframework}build.sh: make min version(s) more visible
a9225410 animdecoder_fuzzer: fix memory leak
d6c2285d update gradle to 6.1.1
8df77fb1 animdecoder_fuzzer: fix memory leak
52ce6333 update NEWS
28c49820 bump version to 1.2.0
7363dff2 webp/encode.h: restore WEBP_ENCODER_ABI_VERSION to v1.1.0

View File

@ -215,6 +215,7 @@ DSP_DEC_OBJS = \
$(DIROBJ)\dsp\lossless_msa.obj \
$(DIROBJ)\dsp\lossless_neon.obj \
$(DIROBJ)\dsp\lossless_sse2.obj \
$(DIROBJ)\dsp\lossless_sse41.obj \
$(DIROBJ)\dsp\rescaler.obj \
$(DIROBJ)\dsp\rescaler_mips32.obj \
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \

12
NEWS
View File

@ -1,3 +1,15 @@
- 7/20/2021: version 1.2.1
This is a binary compatible release.
* minor lossless encoder improvements and x86 color conversion speed up
* add ARM64 simulator support to xcframeworkbuild.sh (#510)
* further security related hardening in libwebp & examples
(issues: #497, #508, #518)
(chromium: #1196480, #1196773, #1196775, #1196777, #1196778, #1196850)
(oss-fuzz: #28658, #28978)
* toolchain updates and bug fixes (#498, #501, #502, #504, #505, #506, #509,
#533)
* use more inclusive language within the source (#507)
- 12/23/2020: version 1.2.0
* API changes:
- libwebp:

4
README
View File

@ -4,7 +4,7 @@
\__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v1.2.0
\____/____/\_____/_____/____/v1.2.1
Description:
============
@ -619,7 +619,7 @@ The encoding flow looks like:
pic.width = width;
pic.height = height;
// allocated picture of dimension width x height
if (!WebPPictureAllocate(&pic)) {
if (!WebPPictureAlloc(&pic)) {
return 0; // memory error
}
// at this point, 'pic' has been initialized as a container,

View File

@ -1,7 +1,7 @@
 __ __ ____ ____ ____ __ __ _ __ __
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
\ / __/ _ \ __/ / / (_/ /__
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.2.0
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.2.1
Description:

View File

@ -10,26 +10,18 @@ This file describes the compilation of libwebp into a JavaScript decoder
using Emscripten and CMake.
- install the Emscripten SDK following the procedure described at:
https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended
After installation, you should have some global variable positioned to the
location of the SDK. In particular, $EMSCRIPTEN should point to the
location of the SDK. In particular, $EMSDK should point to the
top-level directory containing Emscripten tools.
- make sure the file $EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake is
accessible. This is the toolchain file used by CMake to invoke Emscripten.
If $EMSCRIPTEN is unset search for Emscripten.cmake under $EMSDK and set
$EMSCRIPTEN accordingly, for example:
unix-like environments: export EMSCRIPTEN=$EMSDK/upstream/emscripten
windows: set EMSCRIPTEN=%EMSDK%\upstream\emscripten
- configure the project 'WEBP_JS' with CMake using:
cd webp_js && \
cmake -DWEBP_BUILD_WEBP_JS=ON \
-DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
emcmake cmake -DWEBP_BUILD_WEBP_JS=ON \
../
- compile webp.js using 'make'.
- compile webp.js using 'emmake make'.
- that's it! Upon completion, you should have the webp.js and
webp.wasm files generated.
@ -58,7 +50,7 @@ Web-Assembly (WASM) version:
See webp_js/index_wasm.html for a simple demo page using the WASM version
of the library.
You will need a fairly recent version of Emscripten (at least 1.37.8,
You will need a fairly recent version of Emscripten (at least 2.0.18,
latest-upstream is recommended) and of your WASM-enabled browser to run this
version.

View File

@ -141,6 +141,7 @@ model {
include "lossless_msa.c"
include "lossless_neon.$NEON"
include "lossless_sse2.c"
include "lossless_sse41.c"
include "rescaler.c"
include "rescaler_mips32.c"
include "rescaler_mips_dsp_r2.c"

View File

@ -5,7 +5,7 @@ set(WEBP_VERSION ${WebP_VERSION})
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
set(WebP_INCLUDE_DIRS "webp")
set(WebP_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")

View File

@ -1,3 +1,11 @@
# Copyright (c) 2021 Google LLC.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE 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.
# Check for SIMD extensions.
include(CMakePushCheckState)
@ -117,6 +125,12 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
include(CheckCCompilerFlag)
if(SIMD_COMPILE_FLAG)
# Between 3.17.0 and 3.18.2 check_cxx_compiler_flag() sets a normal
# variable at parent scope while check_cxx_source_compiles() continues
# to set an internal cache variable, so we unset both to avoid the
# failure / success state persisting between checks. See
# https://gitlab.kitware.com/cmake/cmake/-/issues/21207.
unset(HAS_COMPILE_FLAG)
unset(HAS_COMPILE_FLAG CACHE)
check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
if(HAS_COMPILE_FLAG)
@ -134,6 +148,7 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
"warning: argument unused during compilation:"
${COMMON_PATTERNS})
if(NOT FLAG_${SIMD_COMPILE_FLAG})
unset(HAS_COMPILE_FLAG)
unset(HAS_COMPILE_FLAG CACHE)
endif()
endif()

View File

@ -1,3 +1,11 @@
# Copyright (c) 2021 Google LLC.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE 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.
# Generate the config.h to compile with specific intrinsics / libs.
# Check for compiler options.
@ -22,26 +30,25 @@ check_c_source_compiles("
" HAVE_BUILTIN_BSWAP64)
# Check for libraries.
if(NOT WEBP_BUILD_WEBP_JS)
# Disable pThreads for WASM.
if(WEBP_USE_THREAD)
find_package(Threads)
endif()
if(Threads_FOUND)
# work around cmake bug on QNX (https://cmake.org/Bug/view.php?id=11333)
if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
if(Threads_FOUND)
# work around cmake bug on QNX (https://cmake.org/Bug/view.php?id=11333)
if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
endif()
check_c_source_compiles("
#include <pthread.h>
int main (void) {
int attr = PTHREAD_PRIO_INHERIT;
return attr;
}
" FLAG_HAVE_PTHREAD_PRIO_INHERIT)
set(HAVE_PTHREAD_PRIO_INHERIT ${FLAG_HAVE_PTHREAD_PRIO_INHERIT})
list(APPEND WEBP_DEP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
endif()
check_c_source_compiles("
#include <pthread.h>
int main (void) {
int attr = PTHREAD_PRIO_INHERIT;
return attr;
}
" FLAG_HAVE_PTHREAD_PRIO_INHERIT)
set(HAVE_PTHREAD_PRIO_INHERIT ${FLAG_HAVE_PTHREAD_PRIO_INHERIT})
list(APPEND WEBP_DEP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
set(WEBP_USE_THREAD ${Threads_FOUND})
endif()
set(WEBP_USE_THREAD ${Threads_FOUND})
# TODO: this seems unused, check with autotools.
set(LT_OBJDIR ".libs/")

View File

@ -1,4 +1,4 @@
AC_INIT([libwebp], [1.2.0],
AC_INIT([libwebp], [1.2.1],
[https://bugs.chromium.org/p/webp],,
[http://developers.google.com/speed/webp])
AC_CANONICAL_HOST
@ -32,6 +32,40 @@ AC_ARG_ENABLE([everything],
SET_IF_UNSET([enable_libwebpextras], [$enableval])
SET_IF_UNSET([enable_libwebpmux], [$enableval])])
dnl === Check whether libwebpmux should be built
AC_MSG_CHECKING(whether libwebpmux is to be built)
AC_ARG_ENABLE([libwebpmux],
AS_HELP_STRING([--disable-libwebpmux],
[Disable libwebpmux @<:@default=no@:>@]),
[], [enable_libwebpmux=yes])
AC_MSG_RESULT(${enable_libwebpmux-no})
AM_CONDITIONAL([BUILD_MUX], [test "$enable_libwebpmux" = "yes"])
dnl === Check whether libwebpdemux should be built
AC_MSG_CHECKING(whether libwebpdemux is to be built)
AC_ARG_ENABLE([libwebpdemux],
AS_HELP_STRING([--disable-libwebpdemux],
[Disable libwebpdemux @<:@default=no@:>@]),
[], [enable_libwebpdemux=yes])
AC_MSG_RESULT(${enable_libwebpdemux-no})
AM_CONDITIONAL([BUILD_DEMUX], [test "$enable_libwebpdemux" = "yes"])
dnl === Check whether decoder library should be built.
AC_MSG_CHECKING(whether decoder library is to be built)
AC_ARG_ENABLE([libwebpdecoder],
AS_HELP_STRING([--enable-libwebpdecoder],
[Build libwebpdecoder @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpdecoder-no})
AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"])
dnl === Check whether libwebpextras should be built
AC_MSG_CHECKING(whether libwebpextras is to be built)
AC_ARG_ENABLE([libwebpextras],
AS_HELP_STRING([--enable-libwebpextras],
[Build libwebpextras @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpextras-no})
AM_CONDITIONAL([BUILD_EXTRAS], [test "$enable_libwebpextras" = "yes"])
dnl === If --enable-asserts is not defined, define NDEBUG
AC_MSG_CHECKING(whether asserts are enabled)
@ -225,6 +259,9 @@ AS_IF([test "x$enable_neon" != "xno"], [
*android*) AC_CHECK_HEADERS([cpu-features.h]) ;;
esac
;;
aarch64*|arm64*)
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
;;
esac
AC_SUBST([NEON_FLAGS])])
@ -409,6 +446,10 @@ AS_IF([test "x$enable_gl" != "xno"], [
if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then
build_vwebp=yes
else
AC_MSG_NOTICE(
m4_normalize([Not building vwebp.
OpenGL libraries and --enable-libwebpdemux are required.]))
fi
])
AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
@ -468,7 +509,7 @@ AS_IF([test "x$enable_sdl" != "xno"], [
if test x"$sdl_support" = "xyes"; then
build_vwebp_sdl=yes
else
AC_MSG_WARN(Optional SDL library not found)
AC_MSG_NOTICE([Not building vwebp-sdl. SDL library is required.])
fi
])
@ -592,11 +633,17 @@ AS_IF([test "x$enable_gif" != "xno"], [
if test "$gif_support" = "yes" -a \
"$enable_libwebpdemux" = "yes"; then
build_anim_diff=yes
else
AC_MSG_NOTICE(
[Not building anim_diff. libgif and --enable-libwebpdemux are required.])
fi
if test "$gif_support" = "yes" -a \
"$enable_libwebpmux" = "yes"; then
build_gif2webp=yes
else
AC_MSG_NOTICE(
[Not building gif2webp. libgif and --enable-libwebpmux are required.])
fi
])
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_anim_diff}" = "yes"])
@ -604,11 +651,17 @@ AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
if test "$enable_libwebpdemux" = "yes" -a "$enable_libwebpmux" = "yes"; then
build_img2webp=yes
else
AC_MSG_NOTICE(
m4_normalize([Not building img2webp.
--enable-libwebpdemux & --enable-libwebpmux are required.]))
fi
AM_CONDITIONAL([BUILD_IMG2WEBP], [test "${build_img2webp}" = "yes"])
if test "$enable_libwebpmux" = "yes"; then
build_webpinfo=yes
else
AC_MSG_NOTICE([Not building webpinfo. --enable-libwebpdemux is required.])
fi
AM_CONDITIONAL([BUILD_WEBPINFO], [test "${build_webpinfo}" = "yes"])
@ -692,39 +745,6 @@ else
AC_MSG_RESULT([no])
fi
dnl === Check whether libwebpmux should be built
AC_MSG_CHECKING(whether libwebpmux is to be built)
AC_ARG_ENABLE([libwebpmux],
AS_HELP_STRING([--enable-libwebpmux],
[Build libwebpmux @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpmux-no})
AM_CONDITIONAL([BUILD_MUX], [test "$enable_libwebpmux" = "yes"])
dnl === Check whether libwebpdemux should be built
AC_MSG_CHECKING(whether libwebpdemux is to be built)
AC_ARG_ENABLE([libwebpdemux],
AS_HELP_STRING([--disable-libwebpdemux],
[Disable libwebpdemux @<:@default=no@:>@]),
[], [enable_libwebpdemux=yes])
AC_MSG_RESULT(${enable_libwebpdemux-no})
AM_CONDITIONAL([BUILD_DEMUX], [test "$enable_libwebpdemux" = "yes"])
dnl === Check whether decoder library should be built.
AC_MSG_CHECKING(whether decoder library is to be built)
AC_ARG_ENABLE([libwebpdecoder],
AS_HELP_STRING([--enable-libwebpdecoder],
[Build libwebpdecoder @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpdecoder-no})
AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"])
dnl === Check whether libwebpextras should be built
AC_MSG_CHECKING(whether libwebpextras is to be built)
AC_ARG_ENABLE([libwebpextras],
AS_HELP_STRING([--enable-libwebpextras],
[Build libwebpextras @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpextras-no})
AM_CONDITIONAL([BUILD_EXTRAS], [test "$enable_libwebpextras" = "yes"])
dnl =========================
AC_CONFIG_MACRO_DIR([m4])

View File

@ -816,7 +816,7 @@ RIFF/WEBP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[vp8spec]: http://tools.ietf.org/html/rfc6386
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt
[iccspec]: http://www.color.org/icc_specs2.xalter
[metadata]: http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
[rfc 1166]: http://tools.ietf.org/html/rfc1166

View File

@ -465,8 +465,10 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
goto End;
}
if (!loop_compatibility) {
// If there's only one frame, we don't need to handle loop count.
if (frame_number == 1) {
loop_count = 0;
} else if (!loop_compatibility) {
if (!stored_loop_count) {
// if no loop-count element is seen, the default is '1' (loop-once)
// and we need to signal it explicitly in WebP. Note however that

View File

@ -472,11 +472,11 @@ static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
}
static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
int dispose_method, dummy;
int dispose_method, unused;
char plus_minus, blend_method;
const int num_args = sscanf(args, "+%d+%d+%d+%d%c%c+%d", &info->duration,
&info->x_offset, &info->y_offset, &dispose_method,
&plus_minus, &blend_method, &dummy);
&plus_minus, &blend_method, &unused);
switch (num_args) {
case 1:
info->x_offset = info->y_offset = 0; // fall through
@ -495,7 +495,7 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
WarnAboutOddOffset(info);
// Note: The sanity of the following conversion is checked by
// Note: The validity of the following conversion is checked by
// WebPMuxPushFrame().
info->dispose_method = (WebPMuxAnimDispose)dispose_method;

View File

@ -19,7 +19,7 @@
#define XTRA_MAJ_VERSION 1
#define XTRA_MIN_VERSION 2
#define XTRA_REV_VERSION 0
#define XTRA_REV_VERSION 1
//------------------------------------------------------------------------------

View File

@ -155,8 +155,8 @@ int WebPWritePNG(const char* out_file_name, int use_stdout,
}
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp dummy) {
(void)dummy; // remove variable-unused warning
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp unused) {
(void)unused; // remove variable-unused warning
longjmp(png_jmpbuf(png), 1);
}
@ -320,7 +320,7 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
PutLE16(bmp_header + 26, 1); // number of planes
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
PutLE32(bmp_header + 34, 0); // image size (dummy)
PutLE32(bmp_header + 34, 0); // image size (placeholder)
PutLE32(bmp_header + 38, 2400); // x pixels/meter
PutLE32(bmp_header + 42, 2400); // y pixels/meter
PutLE32(bmp_header + 46, 0); // number of palette colors

View File

@ -148,9 +148,11 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
// -----------------------------------------------------------------------------
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
const uint64_t total_size = nmemb * size;
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height) {
const uint64_t total_size = stride * height;
int ok = (total_size == (size_t)total_size);
// check that 'stride' is representable as int:
ok = ok && ((uint64_t)(int)stride == stride);
#if defined(WEBP_MAX_IMAGE_SIZE)
ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE);
#endif

View File

@ -54,8 +54,8 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
//------------------------------------------------------------------------------
// Returns 0 in case of overflow of nmemb * size.
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size);
// Returns 0 in case of overflow, memory over-allocation or excessive dimension.
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height);
#ifdef __cplusplus
} // extern "C"

View File

@ -274,7 +274,7 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
ctx.data = data;
ctx.data_size = data_size;
memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp sanity
memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp safety
dinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;

View File

@ -259,11 +259,14 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
goto End;
}
#if LOCAL_PNG_PREREQ(1,5) || \
(LOCAL_PNG_PREREQ(1,4) && PNG_LIBPNG_VER_RELEASE >= 1)
// If it looks like the bitstream is going to need more memory than libpng's
// internal limit (default: 8M), try to (reasonably) raise it.
if (data_size > png_get_chunk_malloc_max(png) && data_size < (1u << 24)) {
png_set_chunk_malloc_max(png, data_size);
}
#endif
info = png_create_info_struct(png);
if (info == NULL) goto Error;

View File

@ -157,6 +157,7 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
MyData my_data = { data, (toff_t)data_size, 0 };
TIFF* tif;
uint32_t image_width, image_height, tile_width, tile_height;
uint64_t stride;
uint16_t samples_per_px = 0;
uint16_t extra_samples = 0;
uint16_t* extra_samples_ptr = NULL;
@ -194,20 +195,31 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
goto End;
}
if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)image_width * image_height,
sizeof(*raster))) {
stride = (uint64_t)image_width * sizeof(*raster);
if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, image_height)) {
fprintf(stderr, "Error! TIFF image dimension (%d x %d) is too large.\n",
image_width, image_height);
goto End;
}
// According to spec, a tile can be bigger than the image. However it should
// be a multiple of 16 and not way too large, so check that it's not more than
// twice the image size, for dimensions above some arbitrary minimum 32.
if ((TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) &&
tile_width > 32 && tile_width / 2 > image_width) ||
(TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height) &&
tile_height > 32 && tile_height / 2 > image_height)) {
fprintf(stderr, "Error! TIFF tile dimensions are too big.\n");
goto End;
// be a multiple of 16 and not way too large, so check that it's not more
// than twice the image size, for dimensions above some arbitrary minimum
// 32. We also check that they respect WebP's dimension and memory limit.
// Note that a tile can be 6byte/px in some cases. Here we assume
// 4byte/px with sizeof(*raster), to be conservative.
if (TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) &&
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height)) {
if ((tile_width > 32 && tile_width / 2 > image_width) ||
(tile_height > 32 && tile_height / 2 > image_height) ||
ImgIoUtilCheckSizeArgumentsOverflow(
(uint64_t)tile_width * sizeof(*raster), tile_height)) {
fprintf(stderr, "Error! TIFF tile dimension (%d x %d) is too large.\n",
tile_width, tile_height);
goto End;
}
}
if (samples_per_px > 3 && !TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
&extra_samples, &extra_samples_ptr)) {
fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n");
@ -215,15 +227,13 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
}
// _Tiffmalloc uses a signed type for size.
alloc_size =
(int64_t)((uint64_t)image_width * image_height * sizeof(*raster));
alloc_size = (int64_t)(stride * image_height);
if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
raster = (uint32*)_TIFFmalloc((tsize_t)alloc_size);
if (raster != NULL) {
if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster,
ORIENTATION_TOPLEFT, 1)) {
const int stride = image_width * sizeof(*raster);
pic->width = image_width;
pic->height = image_height;
// TIFF data is ABGR
@ -241,8 +251,8 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
}
}
ok = keep_alpha
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, (int)stride)
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, (int)stride);
}
_TIFFfree(raster);
} else {

View File

@ -95,7 +95,7 @@ VP8StatusCode DecodeWebPIncremental(
{
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
if (idec == NULL) {
fprintf(stderr, "Failed during WebPINewDecoder().\n");
fprintf(stderr, "Failed during WebPIDecode().\n");
return VP8_STATUS_OUT_OF_MEMORY;
} else {
status = WebPIUpdate(idec, data, data_size);

View File

@ -134,7 +134,10 @@ static HRESULT ExtractICCP(IWICImagingFactory* const factory,
IWICColorContext** color_contexts;
IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
if (FAILED(hr) || count == 0) return hr;
if (FAILED(hr) || count == 0) {
// Treat unsupported operation as a non-fatal error. See crbug.com/webp/506.
return (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) ? S_OK : hr;
}
color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts));
if (color_contexts == NULL) return E_OUTOFMEMORY;
@ -270,10 +273,15 @@ int ReadPictureWithWIC(const char* const filename,
WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
const WICFormatImporter* importer = NULL;
GUID src_container_format = GUID_NULL_;
// From Windows Kits\10\Include\10.0.19041.0\um\wincodec.h
WEBP_DEFINE_GUID(GUID_ContainerFormatWebp_,
0xe094b0e2, 0x67f2, 0x45b3,
0xb0, 0xea, 0x11, 0x53, 0x37, 0xca, 0x7c, 0xf3);
static const GUID* kAlphaContainers[] = {
&GUID_ContainerFormatBmp,
&GUID_ContainerFormatPng,
&GUID_ContainerFormatTiff,
&GUID_ContainerFormatWebp_,
NULL
};
int has_alpha = 0;

View File

@ -166,6 +166,7 @@ DSP_DEC_OBJS = \
src/dsp/lossless_msa.o \
src/dsp/lossless_neon.o \
src/dsp/lossless_sse2.o \
src/dsp/lossless_sse41.o \
src/dsp/rescaler.o \
src/dsp/rescaler_mips32.o \
src/dsp/rescaler_mips_dsp_r2.o \

View File

@ -36,7 +36,7 @@ libwebp_la_LIBADD += utils/libwebputils.la
# other than the ones listed on the command line, i.e., after linking, it will
# not have unresolved symbols. Some platforms (Windows among them) require all
# symbols in shared libraries to be resolved at library creation.
libwebp_la_LDFLAGS = -no-undefined -version-info 8:1:1
libwebp_la_LDFLAGS = -no-undefined -version-info 8:2:1
libwebpincludedir = $(includedir)/webp
pkgconfig_DATA = libwebp.pc
@ -48,7 +48,7 @@ if BUILD_LIBWEBPDECODER
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:1:1
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:2:1
pkgconfig_DATA += libwebpdecoder.pc
endif

View File

@ -183,7 +183,7 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
assert(dec != NULL && io != NULL);
if (row < 0 || num_rows <= 0 || row + num_rows > height) {
return NULL; // sanity check.
return NULL;
}
if (!dec->is_alpha_decoded_) {

View File

@ -102,7 +102,7 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
int stride;
uint64_t size;
if ((uint64_t)w * kModeBpp[mode] >= (1ull << 32)) {
if ((uint64_t)w * kModeBpp[mode] >= (1ull << 31)) {
return VP8_STATUS_INVALID_PARAM;
}
stride = w * kModeBpp[mode];
@ -117,7 +117,6 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
}
total_size = size + 2 * uv_size + a_size;
// Security/sanity checks
output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
if (output == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
@ -156,11 +155,11 @@ VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
}
if (WebPIsRGBMode(buffer->colorspace)) {
WebPRGBABuffer* const buf = &buffer->u.RGBA;
buf->rgba += (buffer->height - 1) * buf->stride;
buf->rgba += (int64_t)(buffer->height - 1) * buf->stride;
buf->stride = -buf->stride;
} else {
WebPYUVABuffer* const buf = &buffer->u.YUVA;
const int H = buffer->height;
const int64_t H = buffer->height;
buf->y += (H - 1) * buf->y_stride;
buf->y_stride = -buf->y_stride;
buf->u += ((H - 1) >> 1) * buf->u_stride;
@ -188,8 +187,7 @@ VP8StatusCode WebPAllocateDecBuffer(int width, int height,
const int ch = options->crop_height;
const int x = options->crop_left & ~1;
const int y = options->crop_top & ~1;
if (x < 0 || y < 0 || cw <= 0 || ch <= 0 ||
x + cw > width || y + ch > height) {
if (!WebPCheckCropDimensions(width, height, x, y, cw, ch)) {
return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
}
width = cw;

View File

@ -705,7 +705,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
+ cache_size + alpha_size + WEBP_ALIGN_CST;
uint8_t* mem;
if (needed != (size_t)needed) return 0; // check for overflow
if (!CheckSizeOverflow(needed)) return 0; // check for overflow
if (needed > dec->mem_size_) {
WebPSafeFree(dec->mem_);
dec->mem_size_ = 0;

View File

@ -298,46 +298,57 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int uv_out_height = (out_height + 1) >> 1;
const int uv_in_width = (io->mb_w + 1) >> 1;
const int uv_in_height = (io->mb_h + 1) >> 1;
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
// scratch memory for luma rescaler
const size_t work_size = 2 * (size_t)out_width;
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
size_t tmp_size, rescaler_size;
uint64_t total_size;
size_t rescaler_size;
rescaler_t* work;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
total_size = ((uint64_t)work_size + 2 * uv_work_size) * sizeof(*work);
if (has_alpha) {
tmp_size += work_size * sizeof(*work);
total_size += (uint64_t)work_size * sizeof(*work);
}
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
total_size += rescaler_size;
if (!CheckSizeOverflow(total_size)) {
return 0;
}
p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size);
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
if (p->memory == NULL) {
return 0; // memory error
}
work = (rescaler_t*)p->memory;
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size);
scalers = (WebPRescaler*)WEBP_ALIGN(
(const uint8_t*)work + total_size - rescaler_size);
p->scaler_y = &scalers[0];
p->scaler_u = &scalers[1];
p->scaler_v = &scalers[2];
p->scaler_a = has_alpha ? &scalers[3] : NULL;
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
buf->y, out_width, out_height, buf->y_stride, 1,
work);
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
work + work_size);
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
work + work_size + uv_work_size);
if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
buf->y, out_width, out_height, buf->y_stride, 1,
work) ||
!WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
work + work_size) ||
!WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
work + work_size + uv_work_size)) {
return 0;
}
p->emit = EmitRescaledYUV;
if (has_alpha) {
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
buf->a, out_width, out_height, buf->a_stride, 1,
work + work_size + 2 * uv_work_size);
if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
buf->a, out_width, out_height, buf->a_stride, 1,
work + work_size + 2 * uv_work_size)) {
return 0;
}
p->emit_alpha = EmitRescaledAlphaYUV;
WebPInitAlphaProcessing();
}
@ -480,51 +491,58 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int out_height = io->scaled_height;
const int uv_in_width = (io->mb_w + 1) >> 1;
const int uv_in_height = (io->mb_h + 1) >> 1;
const size_t work_size = 2 * out_width; // scratch memory for one rescaler
// scratch memory for one rescaler
const size_t work_size = 2 * (size_t)out_width;
rescaler_t* work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
size_t tmp_size1, tmp_size2, total_size, rescaler_size;
uint64_t tmp_size1, tmp_size2, total_size;
size_t rescaler_size;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
tmp_size1 = 3 * work_size;
tmp_size2 = 3 * out_width;
if (has_alpha) {
tmp_size1 += work_size;
tmp_size2 += out_width;
}
tmp_size1 = (uint64_t)num_rescalers * work_size;
tmp_size2 = (uint64_t)num_rescalers * out_width;
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
total_size += rescaler_size;
if (!CheckSizeOverflow(total_size)) {
return 0;
}
p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size);
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
if (p->memory == NULL) {
return 0; // memory error
}
work = (rescaler_t*)p->memory;
tmp = (uint8_t*)(work + tmp_size1);
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size);
scalers = (WebPRescaler*)WEBP_ALIGN(
(const uint8_t*)work + total_size - rescaler_size);
p->scaler_y = &scalers[0];
p->scaler_u = &scalers[1];
p->scaler_v = &scalers[2];
p->scaler_a = has_alpha ? &scalers[3] : NULL;
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
tmp + 0 * out_width, out_width, out_height, 0, 1,
work + 0 * work_size);
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
tmp + 1 * out_width, out_width, out_height, 0, 1,
work + 1 * work_size);
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
tmp + 2 * out_width, out_width, out_height, 0, 1,
work + 2 * work_size);
if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
tmp + 0 * out_width, out_width, out_height, 0, 1,
work + 0 * work_size) ||
!WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
tmp + 1 * out_width, out_width, out_height, 0, 1,
work + 1 * work_size) ||
!WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
tmp + 2 * out_width, out_width, out_height, 0, 1,
work + 2 * work_size)) {
return 0;
}
p->emit = EmitRescaledRGB;
WebPInitYUV444Converters();
if (has_alpha) {
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
tmp + 3 * out_width, out_width, out_height, 0, 1,
work + 3 * work_size);
if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
tmp + 3 * out_width, out_width, out_height, 0, 1,
work + 3 * work_size)) {
return 0;
}
p->emit_alpha = EmitRescaledAlphaRGB;
if (p->output->colorspace == MODE_RGBA_4444 ||
p->output->colorspace == MODE_rgbA_4444) {

View File

@ -335,7 +335,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
io->scaled_width = io->width;
io->scaled_height = io->height;
io->mb_w = io->width; // sanity check
io->mb_w = io->width; // for soundness
io->mb_h = io->height; // ditto
VP8ResetProba(&dec->proba_);

View File

@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 2
#define DEC_REV_VERSION 0
#define DEC_REV_VERSION 1
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),

View File

@ -559,8 +559,11 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
memory += work_size * sizeof(*work);
scaled_data = (uint32_t*)memory;
WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
out_width, out_height, 0, num_channels, work);
if (!WebPRescalerInit(dec->rescaler, in_width, in_height,
(uint8_t*)scaled_data, out_width, out_height,
0, num_channels, work)) {
return 0;
}
return 1;
}
#endif // WEBP_REDUCE_SIZE
@ -574,13 +577,14 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
int rgba_stride, uint8_t* const rgba) {
uint32_t* const src = (uint32_t*)rescaler->dst;
uint8_t* dst = rgba;
const int dst_width = rescaler->dst_width;
int num_lines_out = 0;
while (WebPRescalerHasPendingOutput(rescaler)) {
uint8_t* const dst = rgba + num_lines_out * rgba_stride;
WebPRescalerExportRow(rescaler);
WebPMultARGBRow(src, dst_width, 1);
VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
dst += rgba_stride;
++num_lines_out;
}
return num_lines_out;
@ -594,8 +598,8 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
int num_lines_in = 0;
int num_lines_out = 0;
while (num_lines_in < mb_h) {
uint8_t* const row_in = in + num_lines_in * in_stride;
uint8_t* const row_out = out + num_lines_out * out_stride;
uint8_t* const row_in = in + (uint64_t)num_lines_in * in_stride;
uint8_t* const row_out = out + (uint64_t)num_lines_out * out_stride;
const int lines_left = mb_h - num_lines_in;
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
int lines_imported;
@ -796,7 +800,8 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
const WebPDecBuffer* const output = dec->output_;
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
const WebPRGBABuffer* const buf = &output->u.RGBA;
uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
uint8_t* const rgba =
buf->rgba + (int64_t)dec->last_out_row_ * buf->stride;
const int num_rows_out =
#if !defined(WEBP_REDUCE_SIZE)
io->use_scaling ?
@ -1514,7 +1519,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
assert(dec->width_ <= final_width);
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
if (dec->pixels_ == NULL) {
dec->argb_cache_ = NULL; // for sanity check
dec->argb_cache_ = NULL; // for soundness
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
return 0;
}
@ -1524,7 +1529,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_;
dec->argb_cache_ = NULL; // for sanity check
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;
@ -1666,7 +1671,6 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
VP8Io* io = NULL;
WebPDecParams* params = NULL;
// Sanity checks.
if (dec == NULL) return 0;
assert(dec->hdr_.huffman_tables_ != NULL);

View File

@ -785,6 +785,13 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
//------------------------------------------------------------------------------
// Cropping and rescaling.
int WebPCheckCropDimensions(int image_width, int image_height,
int x, int y, int w, int h) {
return !(x < 0 || y < 0 || w <= 0 || h <= 0 ||
x >= image_width || w > image_width || w > image_width - x ||
y >= image_height || h > image_height || h > image_height - y);
}
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
const int W = io->width;
@ -792,7 +799,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
int x = 0, y = 0, w = W, h = H;
// Cropping
io->use_cropping = (options != NULL) && (options->use_cropping > 0);
io->use_cropping = (options != NULL) && options->use_cropping;
if (io->use_cropping) {
w = options->crop_width;
h = options->crop_height;
@ -802,7 +809,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
x &= ~1;
y &= ~1;
}
if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
if (!WebPCheckCropDimensions(W, H, x, y, w, h)) {
return 0; // out of frame boundary error
}
}
@ -814,7 +821,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
io->mb_h = h;
// Scaling
io->use_scaling = (options != NULL) && (options->use_scaling > 0);
io->use_scaling = (options != NULL) && options->use_scaling;
if (io->use_scaling) {
int scaled_width = options->scaled_width;
int scaled_height = options->scaled_height;
@ -835,8 +842,8 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
if (io->use_scaling) {
// disable filter (only for large downscaling ratio).
io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
(io->scaled_height < H * 3 / 4);
io->bypass_filtering |= (io->scaled_width < W * 3 / 4) &&
(io->scaled_height < H * 3 / 4);
io->fancy_upsampling = 0;
}
return 1;

View File

@ -77,6 +77,10 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
//------------------------------------------------------------------------------
// Misc utils
// Returns true if crop dimensions are within image bounds.
int WebPCheckCropDimensions(int image_width, int image_height,
int x, int y, int w, int h);
// Initializes VP8Io with custom setup, io and teardown functions. The default
// hooks will use the supplied 'params' as io->opaque handle.
void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);

View File

@ -13,6 +13,6 @@ noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h
libwebpdemux_la_LIBADD = ../libwebp.la
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:7:0
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:8:0
libwebpdemuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpdemux.pc

View File

@ -87,11 +87,19 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
int abi_version) {
WebPAnimDecoderOptions options;
WebPAnimDecoder* dec = NULL;
WebPBitstreamFeatures features;
if (webp_data == NULL ||
WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
return NULL;
}
// Validate the bitstream before doing expensive allocations. The demuxer may
// be more tolerant than the decoder.
if (WebPGetFeatures(webp_data->bytes, webp_data->size, &features) !=
VP8_STATUS_OK) {
return NULL;
}
// Note: calloc() so that the pointer members are initialized to NULL.
dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec == NULL) goto Error;
@ -145,7 +153,7 @@ 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 (size != (size_t)size) return 0;
if (!CheckSizeOverflow(size)) return 0;
memset(buf, 0, (size_t)size);
return 1;
}
@ -166,7 +174,7 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
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 (size != (size_t)size) return 0;
if (!CheckSizeOverflow(size)) return 0;
assert(src != NULL && dst != NULL);
memcpy(dst, src, (size_t)size);
return 1;

View File

@ -25,7 +25,7 @@
#define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 2
#define DMUX_REV_VERSION 0
#define DMUX_REV_VERSION 1
typedef struct {
size_t start_; // start location of the data
@ -221,12 +221,16 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
const size_t chunk_start_offset = mem->start_;
const uint32_t fourcc = ReadLE32(mem);
const uint32_t payload_size = ReadLE32(mem);
const uint32_t payload_size_padded = payload_size + (payload_size & 1);
const size_t payload_available = (payload_size_padded > MemDataSize(mem))
? MemDataSize(mem) : payload_size_padded;
const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available;
uint32_t payload_size_padded;
size_t payload_available;
size_t chunk_size;
if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
payload_size_padded = payload_size + (payload_size & 1);
payload_available = (payload_size_padded > MemDataSize(mem))
? MemDataSize(mem) : payload_size_padded;
chunk_size = CHUNK_HEADER_SIZE + payload_available;
if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR;
if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA;
@ -451,9 +455,11 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
const size_t chunk_start_offset = mem->start_;
const uint32_t fourcc = ReadLE32(mem);
const uint32_t chunk_size = ReadLE32(mem);
const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1);
uint32_t chunk_size_padded;
if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
chunk_size_padded = chunk_size + (chunk_size & 1);
if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR;
switch (fourcc) {

View File

@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,2,0
PRODUCTVERSION 1,0,2,0
FILEVERSION 1,0,2,1
PRODUCTVERSION 1,0,2,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpdemux DLL"
VALUE "FileVersion", "1.2.0"
VALUE "FileVersion", "1.2.1"
VALUE "InternalName", "libwebpdemux.dll"
VALUE "LegalCopyright", "Copyright (C) 2019"
VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "libwebpdemux.dll"
VALUE "ProductName", "WebP Image Demuxer"
VALUE "ProductVersion", "1.2.0"
VALUE "ProductVersion", "1.2.1"
END
END
BLOCK "VarFileInfo"

View File

@ -46,6 +46,7 @@ ENC_SOURCES += ssim.c
libwebpdspdecode_sse41_la_SOURCES =
libwebpdspdecode_sse41_la_SOURCES += alpha_processing_sse41.c
libwebpdspdecode_sse41_la_SOURCES += dec_sse41.c
libwebpdspdecode_sse41_la_SOURCES += lossless_sse41.c
libwebpdspdecode_sse41_la_SOURCES += upsampling_sse41.c
libwebpdspdecode_sse41_la_SOURCES += yuv_sse41.c
libwebpdspdecode_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)

View File

@ -157,7 +157,8 @@ void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) {
}
}
void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse) {
int x;
for (x = 0; x < width; ++x) {
@ -178,7 +179,8 @@ void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
#undef MFIX
void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr,
const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse);
//------------------------------------------------------------------------------
@ -193,8 +195,8 @@ void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
}
}
void WebPMultRows(uint8_t* ptr, int stride,
const uint8_t* alpha, int alpha_stride,
void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride,
const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
int width, int num_rows, int inverse) {
int n;
for (n = 0; n < num_rows; ++n) {
@ -290,9 +292,9 @@ static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444,
}
#if !WEBP_NEON_OMIT_C_CODE
static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
static int DispatchAlpha_C(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
int width, int height,
uint8_t* dst, int dst_stride) {
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
uint32_t alpha_mask = 0xff;
int i, j;
@ -309,9 +311,10 @@ static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
return (alpha_mask != 0xff);
}
static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
int width, int height,
uint32_t* dst, int dst_stride) {
static void DispatchAlphaToGreen_C(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint32_t* WEBP_RESTRICT dst,
int dst_stride) {
int i, j;
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
@ -322,9 +325,9 @@ static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
}
}
static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
static int ExtractAlpha_C(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
int width, int height,
uint8_t* alpha, int alpha_stride) {
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
uint8_t alpha_mask = 0xff;
int i, j;
@ -340,7 +343,8 @@ static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
return (alpha_mask == 0xff);
}
static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) {
static void ExtractGreen_C(const uint32_t* WEBP_RESTRICT argb,
uint8_t* WEBP_RESTRICT alpha, int size) {
int i;
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
}
@ -372,8 +376,11 @@ static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
}
#ifdef WORDS_BIGENDIAN
static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
const uint8_t* b, int len, uint32_t* out) {
static void PackARGB_C(const uint8_t* WEBP_RESTRICT a,
const uint8_t* WEBP_RESTRICT r,
const uint8_t* WEBP_RESTRICT g,
const uint8_t* WEBP_RESTRICT b,
int len, uint32_t* WEBP_RESTRICT out) {
int i;
for (i = 0; i < len; ++i) {
out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
@ -381,8 +388,10 @@ static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
}
#endif
static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
int len, int step, uint32_t* out) {
static void PackRGB_C(const uint8_t* WEBP_RESTRICT r,
const uint8_t* WEBP_RESTRICT g,
const uint8_t* WEBP_RESTRICT b,
int len, int step, uint32_t* WEBP_RESTRICT out) {
int i, offset = 0;
for (i = 0; i < len; ++i) {
out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
@ -392,16 +401,22 @@ static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
uint8_t* WEBP_RESTRICT, int);
void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT, int, int, int,
uint32_t* WEBP_RESTRICT, int);
int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
uint8_t* WEBP_RESTRICT, int);
void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb,
uint8_t* WEBP_RESTRICT alpha, int size);
#ifdef WORDS_BIGENDIAN
void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
const uint8_t* b, int, uint32_t*);
#endif
void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
int len, int step, uint32_t* out);
void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r,
const uint8_t* WEBP_RESTRICT g,
const uint8_t* WEBP_RESTRICT b,
int len, int step, uint32_t* WEBP_RESTRICT out);
int (*WebPHasAlpha8b)(const uint8_t* src, int length);
int (*WebPHasAlpha32b)(const uint8_t* src, int length);
@ -438,10 +453,10 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitAlphaProcessingSSE2();
#if defined(WEBP_USE_SSE41)
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitAlphaProcessingSSE41();
}
@ -455,7 +470,7 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
#endif
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitAlphaProcessingNEON();

View File

@ -80,9 +80,9 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
//------------------------------------------------------------------------------
static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
int width, int height,
uint8_t* dst, int dst_stride) {
static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
uint32_t alpha_mask = 0xffffffffu;
uint8x8_t mask8 = vdup_n_u8(0xff);
uint32_t tmp[2];
@ -112,9 +112,10 @@ static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
return (alpha_mask != 0xffffffffu);
}
static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
int width, int height,
uint32_t* dst, int dst_stride) {
static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint32_t* WEBP_RESTRICT dst,
int dst_stride) {
int i, j;
uint8x8x4_t greens; // leave A/R/B channels zero'd.
greens.val[0] = vdup_n_u8(0);
@ -131,9 +132,9 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
}
}
static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
int width, int height,
uint8_t* alpha, int alpha_stride) {
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
uint32_t alpha_mask = 0xffffffffu;
uint8x8_t mask8 = vdup_n_u8(0xff);
uint32_t tmp[2];
@ -161,8 +162,8 @@ static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
return (alpha_mask == 0xffffffffu);
}
static void ExtractGreen_NEON(const uint32_t* argb,
uint8_t* alpha, int size) {
static void ExtractGreen_NEON(const uint32_t* WEBP_RESTRICT argb,
uint8_t* WEBP_RESTRICT alpha, int size) {
int i;
for (i = 0; i + 16 <= size; i += 16) {
const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));

View File

@ -18,9 +18,9 @@
//------------------------------------------------------------------------------
static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
int width, int height,
uint8_t* dst, int dst_stride) {
static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
@ -72,9 +72,10 @@ static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
return (alpha_and != 0xff);
}
static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
int width, int height,
uint32_t* dst, int dst_stride) {
static void DispatchAlphaToGreen_SSE2(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint32_t* WEBP_RESTRICT dst,
int dst_stride) {
int i, j;
const __m128i zero = _mm_setzero_si128();
const int limit = width & ~15;
@ -98,9 +99,9 @@ static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
}
}
static int ExtractAlpha_SSE2(const uint8_t* argb, int argb_stride,
static int ExtractAlpha_SSE2(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
int width, int height,
uint8_t* alpha, int alpha_stride) {
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
@ -317,7 +318,8 @@ static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) {
if (width > 0) WebPMultARGBRow_C(ptr + x, width, inverse);
}
static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
static void MultRow_SSE2(uint8_t* WEBP_RESTRICT const ptr,
const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse) {
int x = 0;
if (!inverse) {

View File

@ -19,9 +19,9 @@
//------------------------------------------------------------------------------
static int ExtractAlpha_SSE41(const uint8_t* argb, int argb_stride,
int width, int height,
uint8_t* alpha, int alpha_stride) {
static int ExtractAlpha_SSE41(const uint8_t* WEBP_RESTRICT argb,
int argb_stride, int width, int height,
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;

View File

@ -395,12 +395,12 @@ WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) {
VP8EncDspCostInitMIPSdspR2();
}
#endif
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8EncDspCostInitSSE2();
}
#endif
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (VP8GetCPUInfo(kNEON)) {
VP8EncDspCostInitNEON();
}

View File

@ -189,17 +189,17 @@ VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
// Use compile flags as an indicator of SIMD support instead of a runtime check.
static int wasmCPUInfo(CPUFeature feature) {
switch (feature) {
#ifdef WEBP_USE_SSE2
#ifdef WEBP_HAVE_SSE2
case kSSE2:
return 1;
#endif
#ifdef WEBP_USE_SSE41
#ifdef WEBP_HAVE_SSE41
case kSSE3:
case kSlowSSSE3:
case kSSE4_1:
return 1;
#endif
#ifdef WEBP_USE_NEON
#ifdef WEBP_HAVE_NEON
case kNEON:
return 1;
#endif
@ -209,9 +209,10 @@ static int wasmCPUInfo(CPUFeature feature) {
return 0;
}
VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo;
#elif defined(WEBP_USE_NEON)
// define a dummy function to enable turning off NEON at runtime by setting
// VP8DecGetCPUInfo = NULL
#elif defined(WEBP_HAVE_NEON)
// In most cases this function doesn't check for NEON support (it's assumed by
// the configuration), but enables turning off NEON at runtime, for testing
// purposes, by setting VP8DecGetCPUInfo = NULL.
static int armCPUInfo(CPUFeature feature) {
if (feature != kNEON) return 0;
#if defined(__linux__) && defined(WEBP_HAVE_NEON_RTCD)

View File

@ -807,10 +807,10 @@ WEBP_DSP_INIT_FUNC(VP8DspInit) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8DspInitSSE2();
#if defined(WEBP_USE_SSE41)
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
VP8DspInitSSE41();
}
@ -834,7 +834,7 @@ WEBP_DSP_INIT_FUNC(VP8DspInit) {
#endif
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8DspInitNEON();

View File

@ -26,6 +26,23 @@ extern "C" {
#define BPS 32 // this is the common stride for enc/dec
//------------------------------------------------------------------------------
// WEBP_RESTRICT
// Declares a pointer with the restrict type qualifier if available.
// This allows code to hint to the compiler that only this pointer references a
// particular object or memory region within the scope of the block in which it
// is declared. This may allow for improved optimizations due to the lack of
// pointer aliasing. See also:
// https://en.cppreference.com/w/c/language/restrict
#if defined(__GNUC__)
#define WEBP_RESTRICT __restrict__
#elif defined(_MSC_VER)
#define WEBP_RESTRICT __restrict
#else
#define WEBP_RESTRICT
#endif
//------------------------------------------------------------------------------
// CPU detection
@ -67,21 +84,31 @@ extern "C" {
// files without intrinsics, allowing the corresponding Init() to be called.
// Files containing intrinsics will need to be built targeting the instruction
// set so should succeed on one of the earlier tests.
#if defined(__SSE2__) || defined(WEBP_MSC_SSE2) || defined(WEBP_HAVE_SSE2)
#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
#define WEBP_USE_SSE2
#endif
#if defined(__SSE4_1__) || defined(WEBP_MSC_SSE41) || defined(WEBP_HAVE_SSE41)
#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
#define WEBP_HAVE_SSE2
#endif
#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
#define WEBP_USE_SSE41
#endif
#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
#define WEBP_HAVE_SSE41
#endif
#undef WEBP_MSC_SSE41
#undef WEBP_MSC_SSE2
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
// inline assembly would need to be modified for use with Native Client.
#if (defined(__ARM_NEON__) || \
defined(__aarch64__) || defined(WEBP_HAVE_NEON)) && \
#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
!defined(__native_client__)
#define WEBP_USE_NEON
#endif
@ -97,6 +124,10 @@ extern "C" {
#define WEBP_USE_INTRINSICS
#endif
#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
#define WEBP_HAVE_NEON
#endif
#if defined(__mips__) && !defined(__mips64) && \
defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
#define WEBP_USE_MIPS32
@ -116,7 +147,7 @@ extern "C" {
#define WEBP_DSP_OMIT_C_CODE 1
#endif
#if (defined(__aarch64__) || defined(__ARM_NEON__)) && WEBP_DSP_OMIT_C_CODE
#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
#define WEBP_NEON_OMIT_C_CODE 1
#else
#define WEBP_NEON_OMIT_C_CODE 0
@ -578,26 +609,29 @@ extern void (*WebPApplyAlphaMultiply4444)(
// Dispatch the values from alpha[] plane to the ARGB destination 'dst'.
// Returns true if alpha[] plane has non-trivial values different from 0xff.
extern int (*WebPDispatchAlpha)(const uint8_t* alpha, int alpha_stride,
int width, int height,
uint8_t* dst, int dst_stride);
extern int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint8_t* WEBP_RESTRICT dst, int dst_stride);
// Transfer packed 8b alpha[] values to green channel in dst[], zero'ing the
// A/R/B values. 'dst_stride' is the stride for dst[] in uint32_t units.
extern void (*WebPDispatchAlphaToGreen)(const uint8_t* alpha, int alpha_stride,
int width, int height,
uint32_t* dst, int dst_stride);
extern void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint32_t* WEBP_RESTRICT dst,
int dst_stride);
// Extract the alpha values from 32b values in argb[] and pack them into alpha[]
// (this is the opposite of WebPDispatchAlpha).
// Returns true if there's only trivial 0xff alpha values.
extern int (*WebPExtractAlpha)(const uint8_t* argb, int argb_stride,
int width, int height,
uint8_t* alpha, int alpha_stride);
extern int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT argb,
int argb_stride, int width, int height,
uint8_t* WEBP_RESTRICT alpha,
int alpha_stride);
// Extract the green values from 32b values in argb[] and pack them into alpha[]
// (this is the opposite of WebPDispatchAlphaToGreen).
extern void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
extern void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb,
uint8_t* WEBP_RESTRICT alpha, int size);
// Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B).
// Un-Multiply operation transforms x into x * 255 / A.
@ -610,29 +644,35 @@ void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
int inverse);
// Same for a row of single values, with side alpha values.
extern void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
extern void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr,
const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse);
// Same a WebPMultRow(), but for several 'num_rows' rows.
void WebPMultRows(uint8_t* ptr, int stride,
const uint8_t* alpha, int alpha_stride,
void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride,
const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
int width, int num_rows, int inverse);
// Plain-C versions, used as fallback by some implementations.
void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse);
void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse);
#ifdef WORDS_BIGENDIAN
// ARGB packing function: a/r/g/b input is rgba or bgra order.
extern void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r,
const uint8_t* g, const uint8_t* b, int len,
uint32_t* out);
extern void (*WebPPackARGB)(const uint8_t* WEBP_RESTRICT a,
const uint8_t* WEBP_RESTRICT r,
const uint8_t* WEBP_RESTRICT g,
const uint8_t* WEBP_RESTRICT b,
int len, uint32_t* WEBP_RESTRICT out);
#endif
// RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order.
extern void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
int len, int step, uint32_t* out);
extern void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r,
const uint8_t* WEBP_RESTRICT g,
const uint8_t* WEBP_RESTRICT b,
int len, int step, uint32_t* WEBP_RESTRICT out);
// This function returns true if src[i] contains a value different from 0xff.
extern int (*WebPHasAlpha8b)(const uint8_t* src, int length);

View File

@ -773,10 +773,10 @@ WEBP_DSP_INIT_FUNC(VP8EncDspInit) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8EncDspInitSSE2();
#if defined(WEBP_USE_SSE41)
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
VP8EncDspInitSSE41();
}
@ -800,7 +800,7 @@ WEBP_DSP_INIT_FUNC(VP8EncDspInit) {
#endif
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8EncDspInitNEON();

View File

@ -254,7 +254,7 @@ WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
#endif
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8FiltersInitSSE2();
}
@ -271,7 +271,7 @@ WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
#endif
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8FiltersInitNEON();

View File

@ -320,7 +320,12 @@ extern void VP8FiltersInitSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) {
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_SSE2;
#if defined(CHROMIUM)
// TODO(crbug.com/654974)
(void)VerticalUnfilter_SSE2;
#else
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_SSE2;
#endif
WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_SSE2;
WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_SSE2;

View File

@ -575,6 +575,7 @@ VP8LMapARGBFunc VP8LMapColor32b;
VP8LMapAlphaFunc VP8LMapColor8b;
extern void VP8LDspInitSSE2(void);
extern void VP8LDspInitSSE41(void);
extern void VP8LDspInitNEON(void);
extern void VP8LDspInitMIPSdspR2(void);
extern void VP8LDspInitMSA(void);
@ -621,9 +622,14 @@ WEBP_DSP_INIT_FUNC(VP8LDspInit) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8LDspInitSSE2();
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
VP8LDspInitSSE41();
}
#endif
}
#endif
#if defined(WEBP_USE_MIPS_DSP_R2)
@ -638,7 +644,7 @@ WEBP_DSP_INIT_FUNC(VP8LDspInit) {
#endif
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8LDspInitNEON();

View File

@ -329,6 +329,15 @@ const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX] = {
static float FastSLog2Slow_C(uint32_t v) {
assert(v >= LOG_LOOKUP_IDX_MAX);
if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ)
// use clz if available
const int log_cnt = BitsLog2Floor(v) - 7;
const uint32_t y = 1 << log_cnt;
int correction = 0;
const float v_f = (float)v;
const uint32_t orig_v = v;
v >>= log_cnt;
#else
int log_cnt = 0;
uint32_t y = 1;
int correction = 0;
@ -339,6 +348,7 @@ static float FastSLog2Slow_C(uint32_t v) {
v = v >> 1;
y = y << 1;
} while (v >= LOG_LOOKUP_IDX_MAX);
#endif
// vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256
// Xf = floor(Xf) * (1 + (v % y) / v)
// log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v)
@ -355,6 +365,14 @@ static float FastSLog2Slow_C(uint32_t v) {
static float FastLog2Slow_C(uint32_t v) {
assert(v >= LOG_LOOKUP_IDX_MAX);
if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ)
// use clz if available
const int log_cnt = BitsLog2Floor(v) - 7;
const uint32_t y = 1 << log_cnt;
const uint32_t orig_v = v;
double log_2;
v >>= log_cnt;
#else
int log_cnt = 0;
uint32_t y = 1;
const uint32_t orig_v = v;
@ -364,6 +382,7 @@ static float FastLog2Slow_C(uint32_t v) {
v = v >> 1;
y = y << 1;
} while (v >= LOG_LOOKUP_IDX_MAX);
#endif
log_2 = kLog2Table[v] + log_cnt;
if (orig_v >= APPROX_LOG_MAX) {
// Since the division is still expensive, add this correction factor only
@ -843,10 +862,10 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8LEncDspInitSSE2();
#if defined(WEBP_USE_SSE41)
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
VP8LEncDspInitSSE41();
}
@ -870,7 +889,7 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
#endif
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8LEncDspInitNEON();

View File

@ -232,79 +232,55 @@ static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
//------------------------------------------------------------------------------
// Entropy
// Checks whether the X or Y contribution is worth computing and adding.
// Used in loop unrolling.
#define ANALYZE_X_OR_Y(x_or_y, j) \
do { \
if ((x_or_y)[i + (j)] != 0) retval -= VP8LFastSLog2((x_or_y)[i + (j)]); \
} while (0)
// TODO(https://crbug.com/webp/499): this function produces different results
// from the C code due to use of double/float resulting in output differences
// when compared to -noasm.
#if !(defined(WEBP_HAVE_SLOW_CLZ_CTZ) || defined(__i386__) || defined(_M_IX86))
// Checks whether the X + Y contribution is worth computing and adding.
// Used in loop unrolling.
#define ANALYZE_XY(j) \
do { \
if (tmp[j] != 0) { \
retval -= VP8LFastSLog2(tmp[j]); \
ANALYZE_X_OR_Y(X, j); \
} \
} while (0)
#if !(defined(__i386__) || defined(_M_IX86))
static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) {
int i;
double retval = 0.;
int sumX, sumXY;
int32_t tmp[4];
__m128i zero = _mm_setzero_si128();
// Sums up X + Y, 4 ints at a time (and will merge it at the end for sumXY).
__m128i sumXY_128 = zero;
__m128i sumX_128 = zero;
int sumX = 0, sumXY = 0;
const __m128i zero = _mm_setzero_si128();
for (i = 0; i < 256; i += 4) {
const __m128i x = _mm_loadu_si128((const __m128i*)(X + i));
const __m128i y = _mm_loadu_si128((const __m128i*)(Y + i));
// Check if any X is non-zero: this actually provides a speedup as X is
// usually sparse.
if (_mm_movemask_epi8(_mm_cmpeq_epi32(x, zero)) != 0xFFFF) {
const __m128i xy_128 = _mm_add_epi32(x, y);
sumXY_128 = _mm_add_epi32(sumXY_128, xy_128);
sumX_128 = _mm_add_epi32(sumX_128, x);
// Analyze the different X + Y.
_mm_storeu_si128((__m128i*)tmp, xy_128);
ANALYZE_XY(0);
ANALYZE_XY(1);
ANALYZE_XY(2);
ANALYZE_XY(3);
} else {
// X is fully 0, so only deal with Y.
sumXY_128 = _mm_add_epi32(sumXY_128, y);
ANALYZE_X_OR_Y(Y, 0);
ANALYZE_X_OR_Y(Y, 1);
ANALYZE_X_OR_Y(Y, 2);
ANALYZE_X_OR_Y(Y, 3);
for (i = 0; i < 256; i += 16) {
const __m128i x0 = _mm_loadu_si128((const __m128i*)(X + i + 0));
const __m128i y0 = _mm_loadu_si128((const __m128i*)(Y + i + 0));
const __m128i x1 = _mm_loadu_si128((const __m128i*)(X + i + 4));
const __m128i y1 = _mm_loadu_si128((const __m128i*)(Y + i + 4));
const __m128i x2 = _mm_loadu_si128((const __m128i*)(X + i + 8));
const __m128i y2 = _mm_loadu_si128((const __m128i*)(Y + i + 8));
const __m128i x3 = _mm_loadu_si128((const __m128i*)(X + i + 12));
const __m128i y3 = _mm_loadu_si128((const __m128i*)(Y + i + 12));
const __m128i x4 = _mm_packs_epi16(_mm_packs_epi32(x0, x1),
_mm_packs_epi32(x2, x3));
const __m128i y4 = _mm_packs_epi16(_mm_packs_epi32(y0, y1),
_mm_packs_epi32(y2, y3));
const int32_t mx = _mm_movemask_epi8(_mm_cmpgt_epi8(x4, zero));
int32_t my = _mm_movemask_epi8(_mm_cmpgt_epi8(y4, zero)) | mx;
while (my) {
const int32_t j = BitsCtz(my);
int xy;
if ((mx >> j) & 1) {
const int x = X[i + j];
sumXY += x;
retval -= VP8LFastSLog2(x);
}
xy = X[i + j] + Y[i + j];
sumX += xy;
retval -= VP8LFastSLog2(xy);
my &= my - 1;
}
}
// Sum up sumX_128 to get sumX.
_mm_storeu_si128((__m128i*)tmp, sumX_128);
sumX = tmp[3] + tmp[2] + tmp[1] + tmp[0];
// Sum up sumXY_128 to get sumXY.
_mm_storeu_si128((__m128i*)tmp, sumXY_128);
sumXY = tmp[3] + tmp[2] + tmp[1] + tmp[0];
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
return (float)retval;
}
#endif // !(defined(__i386__) || defined(_M_IX86))
#undef ANALYZE_X_OR_Y
#undef ANALYZE_XY
#else
#define DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC // won't be faster
#endif
//------------------------------------------------------------------------------
@ -662,10 +638,7 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) {
VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE2;
VP8LAddVector = AddVector_SSE2;
VP8LAddVectorEq = AddVectorEq_SSE2;
// TODO(https://crbug.com/webp/499): this function produces different results
// from the C code due to use of double/float resulting in output differences
// when compared to -noasm.
#if !(defined(__i386__) || defined(_M_IX86))
#if !defined(DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC)
VP8LCombinedShannonEntropy = CombinedShannonEntropy_SSE2;
#endif
VP8LVectorMismatch = VectorMismatch_SSE2;

View File

@ -44,46 +44,47 @@ static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data,
//------------------------------------------------------------------------------
// Color Transform
#define SPAN 8
#define MK_CST_16(HI, LO) \
_mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff)))
static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride,
int tile_width, int tile_height,
int green_to_blue, int red_to_blue,
int histo[]) {
const __m128i mults_r = _mm_set1_epi16(CST_5b(red_to_blue));
const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_blue));
const __m128i mask_g = _mm_set1_epi16((short)0xff00); // green mask
const __m128i mask_gb = _mm_set1_epi32(0xffff); // green/blue mask
const __m128i mask_b = _mm_set1_epi16(0x00ff); // blue mask
const __m128i shuffler_lo = _mm_setr_epi8(-1, 2, -1, 6, -1, 10, -1, 14, -1,
-1, -1, -1, -1, -1, -1, -1);
const __m128i shuffler_hi = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1,
2, -1, 6, -1, 10, -1, 14);
int y;
for (y = 0; y < tile_height; ++y) {
const uint32_t* const src = argb + y * stride;
int i, x;
for (x = 0; x + SPAN <= tile_width; x += SPAN) {
uint16_t values[SPAN];
const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]);
const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]);
const __m128i r0 = _mm_shuffle_epi8(in0, shuffler_lo);
const __m128i r1 = _mm_shuffle_epi8(in1, shuffler_hi);
const __m128i r = _mm_or_si128(r0, r1); // r 0
const __m128i gb0 = _mm_and_si128(in0, mask_gb);
const __m128i gb1 = _mm_and_si128(in1, mask_gb);
const __m128i gb = _mm_packus_epi32(gb0, gb1); // g b
const __m128i g = _mm_and_si128(gb, mask_g); // g 0
const __m128i A = _mm_mulhi_epi16(r, mults_r); // x dbr
const __m128i B = _mm_mulhi_epi16(g, mults_g); // x dbg
const __m128i C = _mm_sub_epi8(gb, B); // x b'
const __m128i D = _mm_sub_epi8(C, A); // x b''
const __m128i E = _mm_and_si128(D, mask_b); // 0 b''
_mm_storeu_si128((__m128i*)values, E);
for (i = 0; i < SPAN; ++i) ++histo[values[i]];
const __m128i mult =
MK_CST_16(CST_5b(red_to_blue) + 256,CST_5b(green_to_blue));
const __m128i perm =
_mm_setr_epi8(-1, 1, -1, 2, -1, 5, -1, 6, -1, 9, -1, 10, -1, 13, -1, 14);
if (tile_width >= 4) {
int y;
for (y = 0; y < tile_height; ++y) {
const uint32_t* const src = argb + y * stride;
const __m128i A1 = _mm_loadu_si128((const __m128i*)src);
const __m128i B1 = _mm_shuffle_epi8(A1, perm);
const __m128i C1 = _mm_mulhi_epi16(B1, mult);
const __m128i D1 = _mm_sub_epi16(A1, C1);
__m128i E = _mm_add_epi16(_mm_srli_epi32(D1, 16), D1);
int x;
for (x = 4; x + 4 <= tile_width; x += 4) {
const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x));
__m128i B2, C2, D2;
++histo[_mm_extract_epi8(E, 0)];
B2 = _mm_shuffle_epi8(A2, perm);
++histo[_mm_extract_epi8(E, 4)];
C2 = _mm_mulhi_epi16(B2, mult);
++histo[_mm_extract_epi8(E, 8)];
D2 = _mm_sub_epi16(A2, C2);
++histo[_mm_extract_epi8(E, 12)];
E = _mm_add_epi16(_mm_srli_epi32(D2, 16), D2);
}
++histo[_mm_extract_epi8(E, 0)];
++histo[_mm_extract_epi8(E, 4)];
++histo[_mm_extract_epi8(E, 8)];
++histo[_mm_extract_epi8(E, 12)];
}
}
{
const int left_over = tile_width & (SPAN - 1);
const int left_over = tile_width & 3;
if (left_over > 0) {
VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride,
left_over, tile_height,
@ -95,33 +96,37 @@ static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride,
static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride,
int tile_width, int tile_height,
int green_to_red, int histo[]) {
const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_red));
const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask
const __m128i mask = _mm_set1_epi16(0xff);
int y;
for (y = 0; y < tile_height; ++y) {
const uint32_t* const src = argb + y * stride;
int i, x;
for (x = 0; x + SPAN <= tile_width; x += SPAN) {
uint16_t values[SPAN];
const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]);
const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]);
const __m128i g0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0
const __m128i g1 = _mm_and_si128(in1, mask_g);
const __m128i g = _mm_packus_epi32(g0, g1); // g 0
const __m128i A0 = _mm_srli_epi32(in0, 16); // 0 0 | x r
const __m128i A1 = _mm_srli_epi32(in1, 16);
const __m128i A = _mm_packus_epi32(A0, A1); // x r
const __m128i B = _mm_mulhi_epi16(g, mults_g); // x dr
const __m128i C = _mm_sub_epi8(A, B); // x r'
const __m128i D = _mm_and_si128(C, mask); // 0 r'
_mm_storeu_si128((__m128i*)values, D);
for (i = 0; i < SPAN; ++i) ++histo[values[i]];
const __m128i mult = MK_CST_16(0, CST_5b(green_to_red));
const __m128i mask_g = _mm_set1_epi32(0x0000ff00);
if (tile_width >= 4) {
int y;
for (y = 0; y < tile_height; ++y) {
const uint32_t* const src = argb + y * stride;
const __m128i A1 = _mm_loadu_si128((const __m128i*)src);
const __m128i B1 = _mm_and_si128(A1, mask_g);
const __m128i C1 = _mm_madd_epi16(B1, mult);
__m128i D = _mm_sub_epi16(A1, C1);
int x;
for (x = 4; x + 4 <= tile_width; x += 4) {
const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x));
__m128i B2, C2;
++histo[_mm_extract_epi8(D, 2)];
B2 = _mm_and_si128(A2, mask_g);
++histo[_mm_extract_epi8(D, 6)];
C2 = _mm_madd_epi16(B2, mult);
++histo[_mm_extract_epi8(D, 10)];
++histo[_mm_extract_epi8(D, 14)];
D = _mm_sub_epi16(A2, C2);
}
++histo[_mm_extract_epi8(D, 2)];
++histo[_mm_extract_epi8(D, 6)];
++histo[_mm_extract_epi8(D, 10)];
++histo[_mm_extract_epi8(D, 14)];
}
}
{
const int left_over = tile_width & (SPAN - 1);
const int left_over = tile_width & 3;
if (left_over > 0) {
VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride,
left_over, tile_height, green_to_red,
@ -130,6 +135,8 @@ static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride,
}
}
#undef MK_CST_16
//------------------------------------------------------------------------------
// Entry point

View File

@ -18,7 +18,6 @@
#include "src/dsp/common_sse2.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
#include <assert.h>
#include <emmintrin.h>
//------------------------------------------------------------------------------

132
src/dsp/lossless_sse41.c Normal file
View File

@ -0,0 +1,132 @@
// Copyright 2021 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.
// -----------------------------------------------------------------------------
//
// SSE41 variant of methods for lossless decoder
#include "src/dsp/dsp.h"
#if defined(WEBP_USE_SSE41)
#include "src/dsp/common_sse41.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
//------------------------------------------------------------------------------
// Color-space conversion functions
static void TransformColorInverse_SSE41(const VP8LMultipliers* const m,
const uint32_t* const src,
int num_pixels, uint32_t* dst) {
// sign-extended multiplying constants, pre-shifted by 5.
#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend
const __m128i mults_rb = _mm_set1_epi32((uint32_t)CST(green_to_red_) << 16 |
(CST(green_to_blue_) & 0xffff));
const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue_));
#undef CST
const __m128i mask_ag = _mm_set1_epi32(0xff00ff00);
const __m128i perm1 = _mm_setr_epi8(-1, 1, -1, 1, -1, 5, -1, 5,
-1, 9, -1, 9, -1, 13, -1, 13);
const __m128i perm2 = _mm_setr_epi8(-1, 2, -1, -1, -1, 6, -1, -1,
-1, 10, -1, -1, -1, 14, -1, -1);
int i;
for (i = 0; i + 4 <= num_pixels; i += 4) {
const __m128i A = _mm_loadu_si128((const __m128i*)(src + i));
const __m128i B = _mm_shuffle_epi8(A, perm1); // argb -> g0g0
const __m128i C = _mm_mulhi_epi16(B, mults_rb);
const __m128i D = _mm_add_epi8(A, C);
const __m128i E = _mm_shuffle_epi8(D, perm2);
const __m128i F = _mm_mulhi_epi16(E, mults_b2);
const __m128i G = _mm_add_epi8(D, F);
const __m128i out = _mm_blendv_epi8(G, A, mask_ag);
_mm_storeu_si128((__m128i*)&dst[i], out);
}
// Fall-back to C-version for left-overs.
if (i != num_pixels) {
VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i);
}
}
//------------------------------------------------------------------------------
#define ARGB_TO_RGB_SSE41 do { \
while (num_pixels >= 16) { \
const __m128i in0 = _mm_loadu_si128(in + 0); \
const __m128i in1 = _mm_loadu_si128(in + 1); \
const __m128i in2 = _mm_loadu_si128(in + 2); \
const __m128i in3 = _mm_loadu_si128(in + 3); \
const __m128i a0 = _mm_shuffle_epi8(in0, perm0); \
const __m128i a1 = _mm_shuffle_epi8(in1, perm1); \
const __m128i a2 = _mm_shuffle_epi8(in2, perm2); \
const __m128i a3 = _mm_shuffle_epi8(in3, perm3); \
const __m128i b0 = _mm_blend_epi16(a0, a1, 0xc0); \
const __m128i b1 = _mm_blend_epi16(a1, a2, 0xf0); \
const __m128i b2 = _mm_blend_epi16(a2, a3, 0xfc); \
_mm_storeu_si128(out + 0, b0); \
_mm_storeu_si128(out + 1, b1); \
_mm_storeu_si128(out + 2, b2); \
in += 4; \
out += 3; \
num_pixels -= 16; \
} \
} while (0)
static void ConvertBGRAToRGB_SSE41(const uint32_t* src, int num_pixels,
uint8_t* dst) {
const __m128i* in = (const __m128i*)src;
__m128i* out = (__m128i*)dst;
const __m128i perm0 = _mm_setr_epi8(2, 1, 0, 6, 5, 4, 10, 9,
8, 14, 13, 12, -1, -1, -1, -1);
const __m128i perm1 = _mm_shuffle_epi32(perm0, 0x39);
const __m128i perm2 = _mm_shuffle_epi32(perm0, 0x4e);
const __m128i perm3 = _mm_shuffle_epi32(perm0, 0x93);
ARGB_TO_RGB_SSE41;
// left-overs
if (num_pixels > 0) {
VP8LConvertBGRAToRGB_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
}
}
static void ConvertBGRAToBGR_SSE41(const uint32_t* src,
int num_pixels, uint8_t* dst) {
const __m128i* in = (const __m128i*)src;
__m128i* out = (__m128i*)dst;
const __m128i perm0 = _mm_setr_epi8(0, 1, 2, 4, 5, 6, 8, 9, 10,
12, 13, 14, -1, -1, -1, -1);
const __m128i perm1 = _mm_shuffle_epi32(perm0, 0x39);
const __m128i perm2 = _mm_shuffle_epi32(perm0, 0x4e);
const __m128i perm3 = _mm_shuffle_epi32(perm0, 0x93);
ARGB_TO_RGB_SSE41;
// left-overs
if (num_pixels > 0) {
VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
}
}
#undef ARGB_TO_RGB_SSE41
//------------------------------------------------------------------------------
// Entry point
extern void VP8LDspInitSSE41(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE41(void) {
VP8LTransformColorInverse = TransformColorInverse_SSE41;
VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE41;
VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE41;
}
#else // !WEBP_USE_SSE41
WEBP_DSP_INIT_STUB(VP8LDspInitSSE41)
#endif // WEBP_USE_SSE41

View File

@ -38,8 +38,9 @@ void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
int x_out = channel;
// simple bilinear interpolation
int accum = wrk->x_add;
int left = src[x_in];
int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
rescaler_t left = (rescaler_t)src[x_in];
rescaler_t right =
(wrk->src_width > 1) ? (rescaler_t)src[x_in + x_stride] : left;
x_in += x_stride;
while (1) {
wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
@ -50,7 +51,7 @@ void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
left = right;
x_in += x_stride;
assert(x_in < wrk->src_width * x_stride);
right = src[x_in];
right = (rescaler_t)src[x_in];
accum += wrk->x_add;
}
}
@ -213,7 +214,7 @@ WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPRescalerDspInitSSE2();
}
@ -235,7 +236,7 @@ WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
#endif
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPRescalerDspInitNEON();

View File

@ -150,7 +150,7 @@ WEBP_DSP_INIT_FUNC(VP8SSIMDspInit) {
#endif
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8SSIMDspInitSSE2();
}

View File

@ -233,12 +233,12 @@ WEBP_DSP_INIT_FUNC(WebPInitYUV444Converters) {
WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444_C;
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitYUV444ConvertersSSE2();
}
#endif
#if defined(WEBP_USE_SSE41)
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitYUV444ConvertersSSE41();
}
@ -278,12 +278,12 @@ WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitUpsamplersSSE2();
}
#endif
#if defined(WEBP_USE_SSE41)
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitUpsamplersSSE41();
}
@ -300,7 +300,7 @@ WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) {
#endif
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitUpsamplersNEON();

View File

@ -90,16 +90,16 @@ WEBP_DSP_INIT_FUNC(WebPInitSamplers) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitSamplersSSE2();
}
#endif // WEBP_USE_SSE2
#if defined(WEBP_USE_SSE41)
#endif // WEBP_HAVE_SSE2
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitSamplersSSE41();
}
#endif // WEBP_USE_SSE41
#endif // WEBP_HAVE_SSE41
#if defined(WEBP_USE_MIPS32)
if (VP8GetCPUInfo(kMIPS32)) {
WebPInitSamplersMIPS32();
@ -276,26 +276,26 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
#endif
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitConvertARGBToYUVSSE2();
WebPInitSharpYUVSSE2();
}
#endif // WEBP_USE_SSE2
#if defined(WEBP_USE_SSE41)
#endif // WEBP_HAVE_SSE2
#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitConvertARGBToYUVSSE41();
}
#endif // WEBP_USE_SSE41
#endif // WEBP_HAVE_SSE41
}
#if defined(WEBP_USE_NEON)
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitConvertARGBToYUVNEON();
WebPInitSharpYUVNEON();
}
#endif // WEBP_USE_NEON
#endif // WEBP_HAVE_NEON
assert(WebPConvertARGBToY != NULL);
assert(WebPConvertARGBToUV != NULL);

View File

@ -303,7 +303,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
int ok = 1;
const int reduce_levels = (quality < 100);
// quick sanity checks
// quick correctness checks
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
assert(enc != NULL && pic != NULL && pic->a != NULL);
assert(output != NULL && output_size != NULL);
@ -361,7 +361,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
//------------------------------------------------------------------------------
// Main calls
static int CompressAlphaJob(void* arg1, void* dummy) {
static int CompressAlphaJob(void* arg1, void* unused) {
VP8Encoder* const enc = (VP8Encoder*)arg1;
const WebPConfig* config = enc->config_;
uint8_t* alpha_data = NULL;
@ -375,13 +375,13 @@ static int CompressAlphaJob(void* arg1, void* dummy) {
filter, effort_level, &alpha_data, &alpha_size)) {
return 0;
}
if (alpha_size != (uint32_t)alpha_size) { // Sanity check.
if (alpha_size != (uint32_t)alpha_size) { // Soundness check.
WebPSafeFree(alpha_data);
return 0;
}
enc->alpha_data_size_ = (uint32_t)alpha_size;
enc->alpha_data_ = alpha_data;
(void)dummy;
(void)unused;
return 1;
}

View File

@ -1171,13 +1171,15 @@ static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) {
int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int quality, int low_effort,
int histo_bits, int cache_bits,
int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols) {
int ok = 0;
const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1;
const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1;
const int histo_xsize =
histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1;
const int histo_ysize =
histogram_bits ? VP8LSubSampleSize(ysize, histogram_bits) : 1;
const int image_histo_raw_size = histo_xsize * histo_ysize;
VP8LHistogramSet* const orig_histo =
VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits);
@ -1193,7 +1195,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
if (orig_histo == NULL || map_tmp == NULL) goto Error;
// Construct the histograms from backward references.
HistogramBuild(xsize, histo_bits, refs, orig_histo);
HistogramBuild(xsize, histogram_bits, refs, orig_histo);
// Copies the histograms and computes its bit_cost.
// histogram_symbols is optimized
HistogramCopyAndAnalyze(orig_histo, image_histo, &num_used,

View File

@ -64,8 +64,8 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
const VP8LBackwardRefs* const refs,
int palette_code_bits);
// Return the size of the histogram for a given palette_code_bits.
int VP8LGetHistogramSize(int palette_code_bits);
// Return the size of the histogram for a given cache_bits.
int VP8LGetHistogramSize(int cache_bits);
// Set the palette_code_bits and reset the stats.
// If init_arrays is true, the arrays are also filled with 0's.
@ -110,7 +110,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int quality, int low_effort,
int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_in,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols);

View File

@ -164,22 +164,25 @@ int WebPPictureCrop(WebPPicture* pic,
//------------------------------------------------------------------------------
// Simple picture rescaler
static void RescalePlane(const uint8_t* src,
int src_width, int src_height, int src_stride,
uint8_t* dst,
int dst_width, int dst_height, int dst_stride,
rescaler_t* const work,
int num_channels) {
static int RescalePlane(const uint8_t* src,
int src_width, int src_height, int src_stride,
uint8_t* dst,
int dst_width, int dst_height, int dst_stride,
rescaler_t* const work,
int num_channels) {
WebPRescaler rescaler;
int y = 0;
WebPRescalerInit(&rescaler, src_width, src_height,
dst, dst_width, dst_height, dst_stride,
num_channels, work);
if (!WebPRescalerInit(&rescaler, src_width, src_height,
dst, dst_width, dst_height, dst_stride,
num_channels, work)) {
return 0;
}
while (y < src_height) {
y += WebPRescalerImport(&rescaler, src_height - y,
src + y * src_stride, src_stride);
WebPRescalerExport(&rescaler);
}
return 1;
}
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
@ -222,25 +225,28 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
// If present, we need to rescale alpha first (for AlphaMultiplyY).
if (pic->a != NULL) {
WebPInitAlphaProcessing();
RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
tmp.a, width, height, tmp.a_stride, work, 1);
if (!RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
tmp.a, width, height, tmp.a_stride, work, 1)) {
return 0;
}
}
// We take transparency into account on the luma plane only. That's not
// totally exact blending, but still is a good approximation.
AlphaMultiplyY(pic, 0);
RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
tmp.y, width, height, tmp.y_stride, work, 1);
if (!RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
tmp.y, width, height, tmp.y_stride, work, 1) ||
!RescalePlane(pic->u,
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
tmp.u,
HALVE(width), HALVE(height), tmp.uv_stride, work, 1) ||
!RescalePlane(pic->v,
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
tmp.v,
HALVE(width), HALVE(height), tmp.uv_stride, work, 1)) {
return 0;
}
AlphaMultiplyY(&tmp, 1);
RescalePlane(pic->u,
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
tmp.u,
HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
RescalePlane(pic->v,
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
tmp.v,
HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
} else {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
if (work == NULL) {
@ -252,11 +258,12 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
// the premultiplication afterward (while preserving the alpha channel).
WebPInitAlphaProcessing();
AlphaMultiplyARGB(pic, 0);
RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
pic->argb_stride * 4,
(uint8_t*)tmp.argb, width, height,
tmp.argb_stride * 4,
work, 4);
if (!RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
pic->argb_stride * 4,
(uint8_t*)tmp.argb, width, height,
tmp.argb_stride * 4, work, 4)) {
return 0;
}
AlphaMultiplyARGB(&tmp, 1);
}
WebPPictureFree(pic);

View File

@ -349,7 +349,7 @@ int VP8EncWrite(VP8Encoder* const enc) {
(enc->alpha_data_size_ & 1);
riff_size += CHUNK_HEADER_SIZE + padded_alpha_size;
}
// Sanity check.
// RIFF size should fit in 32-bits.
if (riff_size > 0xfffffffeU) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG);
}

View File

@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 2
#define ENC_REV_VERSION 0
#define ENC_REV_VERSION 1
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
@ -286,8 +286,7 @@ int VP8IteratorNext(VP8EncIterator* const it);
// save the yuv_out_ boundary values to top_/left_ arrays for next iterations.
void VP8IteratorSaveBoundary(VP8EncIterator* const it);
// Report progression based on macroblock rows. Return 0 for user-abort request.
int VP8IteratorProgress(const VP8EncIterator* const it,
int final_delta_percent);
int VP8IteratorProgress(const VP8EncIterator* const it, int delta);
// Intra4x4 iterations
void VP8IteratorStartI4(VP8EncIterator* const it);
// returns true if not done.

View File

@ -65,25 +65,22 @@ static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
*col2 = tmp;
}
static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
// 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.
uint32_t predict = 0x00000000;
int i, k;
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;
}
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;
}
SwapColor(&palette[best_ix], &palette[i]);
predict = palette[i];
}
assert(0);
return 0;
}
// The palette has been sorted by alpha. This function checks if the other
@ -92,7 +89,8 @@ static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
// 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(uint32_t palette[], int num_colors) {
static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
int num_colors) {
uint32_t predict = 0x000000;
int i;
uint8_t sign_found = 0x00;
@ -115,28 +113,215 @@ static int PaletteHasNonMonotonousDeltas(uint32_t palette[], int num_colors) {
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 WebPEncodingError 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 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 VP8_ENC_OK;
}
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 WebPEncodingError 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 VP8_ENC_OK;
// Build the co-occurrence matrix.
cooccurrence =
(uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
if (cooccurrence == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
if (CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence) !=
VP8_ENC_OK) {
WebPSafeFree(cooccurrence);
return VP8_ENC_ERROR_OUT_OF_MEMORY;
}
// 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 VP8_ENC_OK;
}
// -----------------------------------------------------------------------------
// Palette
// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
// creates a palette and returns true, else returns false.
static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
int low_effort,
uint32_t palette[MAX_PALETTE_SIZE],
int* const palette_size) {
const int num_colors = WebPGetColorPalette(pic, palette);
if (num_colors > MAX_PALETTE_SIZE) {
*palette_size = 0;
return 0;
}
*palette_size = num_colors;
qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {
GreedyMinimizeDeltas(palette, num_colors);
}
return 1;
}
// These five modes are evaluated and their respective entropy is computed.
typedef enum {
kDirect = 0,
@ -148,6 +333,13 @@ typedef enum {
kNumEntropyIx = 6
} EntropyIx;
typedef enum {
kSortedDefault = 0,
kMinimizeDelta = 1,
kModifiedZeng = 2,
kUnusedPalette = 3,
} PaletteSorting;
typedef enum {
kHistoAlpha = 0,
kHistoAlphaPred,
@ -362,11 +554,14 @@ typedef struct {
} CrunchSubConfig;
typedef struct {
int entropy_idx_;
PaletteSorting palette_sorting_type_;
CrunchSubConfig sub_configs_[CRUNCH_SUBCONFIGS_MAX];
int sub_configs_size_;
} CrunchConfig;
#define CRUNCH_CONFIGS_MAX kNumEntropyIx
// +2 because we add a palette sorting configuration for kPalette and
// kPaletteAndSpatial.
#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2)
static int EncoderAnalyze(VP8LEncoder* const enc,
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],
@ -386,9 +581,15 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
int do_no_cache = 0;
assert(pic != NULL && pic->argb != NULL);
use_palette =
AnalyzeAndCreatePalette(pic, low_effort,
enc->palette_, &enc->palette_size_);
// Check whether a palette is possible.
enc->palette_size_ = WebPGetColorPalette(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.
enc->histo_bits_ = GetHistoBits(method, use_palette,
@ -398,6 +599,8 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
if (low_effort) {
// AnalyzeEntropy is somewhat slow.
crunch_configs[0].entropy_idx_ = use_palette ? kPalette : kSpatialSubGreen;
crunch_configs[0].palette_sorting_type_ =
use_palette ? kSortedDefault : kUnusedPalette;
n_lz77s = 1;
*crunch_configs_size = 1;
} else {
@ -418,13 +621,28 @@ 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;
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;
} else {
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
kUnusedPalette;
}
++*crunch_configs_size;
}
}
} else {
// Only choose the guessed best transform.
*crunch_configs_size = 1;
crunch_configs[0].entropy_idx_ = min_entropy_ix;
crunch_configs[0].palette_sorting_type_ =
use_palette ? kMinimizeDelta : kUnusedPalette;
if (config->quality >= 75 && method == 5) {
// Test with and without color cache.
do_no_cache = 1;
@ -432,6 +650,7 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
if (min_entropy_ix == kPalette) {
*crunch_configs_size = 2;
crunch_configs[1].entropy_idx_ = kPaletteAndSpatial;
crunch_configs[1].palette_sorting_type_ = kMinimizeDelta;
}
}
}
@ -1283,22 +1502,6 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
// -----------------------------------------------------------------------------
static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
int hi) {
int low = 0;
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;
}
}
}
#define APPLY_PALETTE_GREEDY_MAX 4
static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[],
@ -1333,17 +1536,6 @@ static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) {
(32 - PALETTE_INV_SIZE_BITS);
}
// Sort palette in increasing order and prepare an inverse mapping array.
static void PrepareMapToPalette(const uint32_t palette[], int num_colors,
uint32_t sorted[], uint32_t idx_map[]) {
int 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;
}
}
// Use 1 pixel cache for ARGB pixels.
#define APPLY_PALETTE_FOR(COLOR_INDEX) do { \
uint32_t prev_pix = palette[0]; \
@ -1571,7 +1763,8 @@ static int EncodeStreamHook(void* input, void* data2) {
enc->use_predict_ = (entropy_idx == kSpatial) ||
(entropy_idx == kSpatialSubGreen) ||
(entropy_idx == kPaletteAndSpatial);
if (low_effort) {
// When using a palette, R/B==0, hence no need to test for cross-color.
if (low_effort || enc->use_palette_) {
enc->use_cross_color_ = 0;
} else {
enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_;
@ -1603,6 +1796,19 @@ 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);
err = PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
enc->palette_size_, enc->palette_);
if (err != VP8_ENC_OK) goto Error;
}
err = EncodePalette(bw, low_effort, enc);
if (err != VP8_ENC_OK) goto Error;
err = MapImageFromPalette(enc, use_delta_palette);
@ -1767,6 +1973,8 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
enc_side->palette_size_ = enc_main->palette_size_;
memcpy(enc_side->palette_, enc_main->palette_,
sizeof(enc_main->palette_));
memcpy(enc_side->palette_sorted_, enc_main->palette_sorted_,
sizeof(enc_main->palette_sorted_));
param->enc_ = enc_side;
}
// Create the workers.

View File

@ -69,6 +69,8 @@ typedef struct {
int use_palette_;
int palette_size_;
uint32_t palette_[MAX_PALETTE_SIZE];
// Sorted version of palette_ for cache purposes.
uint32_t palette_sorted_[MAX_PALETTE_SIZE];
// Some 'scratch' (potentially large) objects.
struct VP8LBackwardRefs refs_[4]; // Backward Refs array for temporaries.

View File

@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,2,0
PRODUCTVERSION 1,0,2,0
FILEVERSION 1,0,2,1
PRODUCTVERSION 1,0,2,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebp DLL"
VALUE "FileVersion", "1.2.0"
VALUE "FileVersion", "1.2.1"
VALUE "InternalName", "libwebp.dll"
VALUE "LegalCopyright", "Copyright (C) 2019"
VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "libwebp.dll"
VALUE "ProductName", "WebP Image Codec"
VALUE "ProductVersion", "1.2.0"
VALUE "ProductVersion", "1.2.1"
END
END
BLOCK "VarFileInfo"

View File

@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,2,0
PRODUCTVERSION 1,0,2,0
FILEVERSION 1,0,2,1
PRODUCTVERSION 1,0,2,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpdecoder DLL"
VALUE "FileVersion", "1.2.0"
VALUE "FileVersion", "1.2.1"
VALUE "InternalName", "libwebpdecoder.dll"
VALUE "LegalCopyright", "Copyright (C) 2019"
VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "libwebpdecoder.dll"
VALUE "ProductName", "WebP Image Decoder"
VALUE "ProductVersion", "1.2.0"
VALUE "ProductVersion", "1.2.1"
END
END
BLOCK "VarFileInfo"

View File

@ -17,6 +17,6 @@ noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h
libwebpmux_la_LIBADD = ../libwebp.la
libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:6:0 -lm
libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:7:0 -lm
libwebpmuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpmux.pc

View File

@ -248,9 +248,6 @@ WebPAnimEncoder* WebPAnimEncoderNewInternal(
enc = (WebPAnimEncoder*)WebPSafeCalloc(1, sizeof(*enc));
if (enc == NULL) return NULL;
// sanity inits, so we can call WebPAnimEncoderDelete():
enc->encoded_frames_ = NULL;
enc->mux_ = NULL;
MarkNoError(enc);
// Dimensions and options.
@ -421,7 +418,7 @@ static void MinimizeChangeRectangle(const WebPPicture* const src,
const int max_allowed_diff_lossy = QualityToMaxDiff(quality);
const int max_allowed_diff = is_lossless ? 0 : max_allowed_diff_lossy;
// Sanity checks.
// Assumption/correctness checks.
assert(src->width == dst->width && src->height == dst->height);
assert(rect->x_offset_ + rect->width_ <= dst->width);
assert(rect->y_offset_ + rect->height_ <= dst->height);
@ -949,7 +946,8 @@ static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) {
int new_duration;
assert(enc->count_ >= 1);
assert(prev_enc_frame->sub_frame_.duration ==
assert(!prev_enc_frame->is_key_frame_ ||
prev_enc_frame->sub_frame_.duration ==
prev_enc_frame->key_frame_.duration);
assert(prev_enc_frame->sub_frame_.duration ==
(prev_enc_frame->sub_frame_.duration & (MAX_DURATION - 1)));
@ -966,7 +964,7 @@ static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) {
0x10, 0x88, 0x88, 0x08
};
const WebPData lossless_1x1 = {
lossless_1x1_bytes, sizeof(lossless_1x1_bytes)
lossless_1x1_bytes, sizeof(lossless_1x1_bytes)
};
const uint8_t lossy_1x1_bytes[] = {
0x52, 0x49, 0x46, 0x46, 0x40, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
@ -1358,6 +1356,12 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
if (!IncreasePreviousDuration(enc, (int)prev_frame_duration)) {
return 0;
}
// IncreasePreviousDuration() may add a frame to avoid exceeding
// MAX_DURATION which could cause CacheFrame() to over read encoded_frames_
// before the next flush.
if (enc->count_ == enc->size_ && !FlushFrames(enc)) {
return 0;
}
} else {
enc->first_timestamp_ = timestamp;
}

View File

@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,2,0
PRODUCTVERSION 1,0,2,0
FILEVERSION 1,0,2,1
PRODUCTVERSION 1,0,2,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpmux DLL"
VALUE "FileVersion", "1.2.0"
VALUE "FileVersion", "1.2.1"
VALUE "InternalName", "libwebpmux.dll"
VALUE "LegalCopyright", "Copyright (C) 2019"
VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "libwebpmux.dll"
VALUE "ProductName", "WebP Image Muxer"
VALUE "ProductVersion", "1.2.0"
VALUE "ProductVersion", "1.2.1"
END
END
BLOCK "VarFileInfo"

View File

@ -235,7 +235,6 @@ WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream,
WebPMuxImage wpi;
WebPMuxError err;
// Sanity checks.
if (mux == NULL || bitstream == NULL || bitstream->bytes == NULL ||
bitstream->size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT;
@ -267,7 +266,6 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info,
WebPMuxImage wpi;
WebPMuxError err;
// Sanity checks.
if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT;
if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT;

View File

@ -29,7 +29,7 @@ extern "C" {
#define MUX_MAJ_VERSION 1
#define MUX_MIN_VERSION 2
#define MUX_REV_VERSION 0
#define MUX_REV_VERSION 1
// Chunk object.
typedef struct WebPChunk WebPChunk;

View File

@ -56,7 +56,7 @@ static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk,
uint32_t chunk_size;
WebPData chunk_data;
// Sanity checks.
// Correctness checks.
if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
chunk_size = GetLE32(data + TAG_SIZE);
if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA;
@ -186,7 +186,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
WebPChunk** chunk_list_ends[WEBP_CHUNK_NIL + 1] = { NULL };
ChunkInit(&chunk);
// Sanity checks.
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) {
return NULL; // version mismatch
}
@ -481,7 +480,6 @@ WebPMuxError WebPMuxGetFrame(
WebPMuxError err;
WebPMuxImage* wpi;
// Sanity checks.
if (mux == NULL || frame == NULL) {
return WEBP_MUX_INVALID_ARGUMENT;
}

View File

@ -55,7 +55,7 @@ void VP8LoadFinalBytes(VP8BitReader* const br);
// makes sure br->value_ has at least BITS bits worth of data
static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE
void VP8LoadNewBytes(VP8BitReader* const br) {
void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) {
assert(br != NULL && br->buf_ != NULL);
// Read 'BITS' bits at a time if possible.
if (br->buf_ < br->buf_max_) {
@ -104,7 +104,7 @@ void VP8LoadNewBytes(VP8BitReader* const br) {
}
// Read a bit with proba 'prob'. Speed-critical function!
static WEBP_INLINE int VP8GetBit(VP8BitReader* const br,
static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br,
int prob, const char label[]) {
// Don't move this declaration! It makes a big speed difference to store
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
@ -137,7 +137,8 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* const br,
// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
int VP8GetSigned(VP8BitReader* const br, int v, const char label[]) {
int VP8GetSigned(VP8BitReader* WEBP_RESTRICT const br, int v,
const char label[]) {
if (br->bits_ < 0) {
VP8LoadNewBytes(br);
}
@ -155,7 +156,7 @@ int VP8GetSigned(VP8BitReader* const br, int v, const char label[]) {
}
}
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br,
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* WEBP_RESTRICT const br,
int prob, const char label[]) {
// Don't move this declaration! It makes a big speed difference to store
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't

View File

@ -278,7 +278,7 @@ void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) {
// If needed, make some room by flushing some bits out.
if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
if (extra_size != (size_t)extra_size ||
if (!CheckSizeOverflow(extra_size) ||
!VP8LBitWriterResize(bw, (size_t)extra_size)) {
bw->cur_ = bw->buf_;
bw->error_ = 1;
@ -314,7 +314,7 @@ void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) {
while (used >= VP8L_WRITER_BITS) {
if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
if (extra_size != (size_t)extra_size ||
if (!CheckSizeOverflow(extra_size) ||
!VP8LBitWriterResize(bw, (size_t)extra_size)) {
bw->cur_ = bw->buf_;
bw->error_ = 1;

View File

@ -20,22 +20,22 @@
//------------------------------------------------------------------------------
// VP8LColorCache.
int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) {
int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits) {
const int hash_size = 1 << hash_bits;
assert(cc != NULL);
assert(color_cache != NULL);
assert(hash_bits > 0);
cc->colors_ = (uint32_t*)WebPSafeCalloc((uint64_t)hash_size,
sizeof(*cc->colors_));
if (cc->colors_ == NULL) return 0;
cc->hash_shift_ = 32 - hash_bits;
cc->hash_bits_ = hash_bits;
color_cache->colors_ = (uint32_t*)WebPSafeCalloc(
(uint64_t)hash_size, sizeof(*color_cache->colors_));
if (color_cache->colors_ == NULL) return 0;
color_cache->hash_shift_ = 32 - hash_bits;
color_cache->hash_bits_ = hash_bits;
return 1;
}
void VP8LColorCacheClear(VP8LColorCache* const cc) {
if (cc != NULL) {
WebPSafeFree(cc->colors_);
cc->colors_ = NULL;
void VP8LColorCacheClear(VP8LColorCache* const color_cache) {
if (color_cache != NULL) {
WebPSafeFree(color_cache->colors_);
color_cache->colors_ = NULL;
}
}

View File

@ -404,8 +404,7 @@ static void ConvertBitDepthsToSymbols(HuffmanTreeCode* const tree) {
// Main entry point
void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
uint8_t* const buf_rle,
HuffmanTree* const huff_tree,
uint8_t* const buf_rle, HuffmanTree* const huff_tree,
HuffmanTreeCode* const huff_code) {
const int num_symbols = huff_code->num_symbols;
memset(buf_rle, 0, num_symbols * sizeof(*buf_rle));

View File

@ -51,7 +51,7 @@ int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree,
// huffman code tree.
void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
uint8_t* const buf_rle, HuffmanTree* const huff_tree,
HuffmanTreeCode* const tree);
HuffmanTreeCode* const huff_code);
#ifdef __cplusplus
}

View File

@ -12,66 +12,74 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "src/dsp/dsp.h"
#include "src/utils/rescaler_utils.h"
#include "src/utils/utils.h"
//------------------------------------------------------------------------------
void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
uint8_t* const dst,
int dst_width, int dst_height, int dst_stride,
int num_channels, rescaler_t* const work) {
int WebPRescalerInit(WebPRescaler* const rescaler,
int src_width, int src_height,
uint8_t* const dst,
int dst_width, int dst_height, int dst_stride,
int num_channels, rescaler_t* const work) {
const int x_add = src_width, x_sub = dst_width;
const int y_add = src_height, y_sub = dst_height;
wrk->x_expand = (src_width < dst_width);
wrk->y_expand = (src_height < dst_height);
wrk->src_width = src_width;
wrk->src_height = src_height;
wrk->dst_width = dst_width;
wrk->dst_height = dst_height;
wrk->src_y = 0;
wrk->dst_y = 0;
wrk->dst = dst;
wrk->dst_stride = dst_stride;
wrk->num_channels = num_channels;
const uint64_t total_size = 2ull * dst_width * num_channels * sizeof(*work);
if (!CheckSizeOverflow(total_size)) return 0;
rescaler->x_expand = (src_width < dst_width);
rescaler->y_expand = (src_height < dst_height);
rescaler->src_width = src_width;
rescaler->src_height = src_height;
rescaler->dst_width = dst_width;
rescaler->dst_height = dst_height;
rescaler->src_y = 0;
rescaler->dst_y = 0;
rescaler->dst = dst;
rescaler->dst_stride = dst_stride;
rescaler->num_channels = num_channels;
// for 'x_expand', we use bilinear interpolation
wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add;
wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
if (!wrk->x_expand) { // fx_scale is not used otherwise
wrk->fx_scale = WEBP_RESCALER_FRAC(1, wrk->x_sub);
rescaler->x_add = rescaler->x_expand ? (x_sub - 1) : x_add;
rescaler->x_sub = rescaler->x_expand ? (x_add - 1) : x_sub;
if (!rescaler->x_expand) { // fx_scale is not used otherwise
rescaler->fx_scale = WEBP_RESCALER_FRAC(1, rescaler->x_sub);
}
// vertical scaling parameters
wrk->y_add = wrk->y_expand ? y_add - 1 : y_add;
wrk->y_sub = wrk->y_expand ? y_sub - 1 : y_sub;
wrk->y_accum = wrk->y_expand ? wrk->y_sub : wrk->y_add;
if (!wrk->y_expand) {
rescaler->y_add = rescaler->y_expand ? y_add - 1 : y_add;
rescaler->y_sub = rescaler->y_expand ? y_sub - 1 : y_sub;
rescaler->y_accum = rescaler->y_expand ? rescaler->y_sub : rescaler->y_add;
if (!rescaler->y_expand) {
// This is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast.
// Its value is <= WEBP_RESCALER_ONE, because dst_height <= wrk->y_add, and
// wrk->x_add >= 1;
const uint64_t ratio =
(uint64_t)dst_height * WEBP_RESCALER_ONE / (wrk->x_add * wrk->y_add);
// Its value is <= WEBP_RESCALER_ONE, because dst_height <= rescaler->y_add
// and rescaler->x_add >= 1;
const uint64_t num = (uint64_t)dst_height * WEBP_RESCALER_ONE;
const uint64_t den = (uint64_t)rescaler->x_add * rescaler->y_add;
const uint64_t ratio = num / den;
if (ratio != (uint32_t)ratio) {
// When ratio == WEBP_RESCALER_ONE, we can't represent the ratio with the
// current fixed-point precision. This happens when src_height ==
// wrk->y_add (which == src_height), and wrk->x_add == 1.
// rescaler->y_add (which == src_height), and rescaler->x_add == 1.
// => We special-case fxy_scale = 0, in WebPRescalerExportRow().
wrk->fxy_scale = 0;
rescaler->fxy_scale = 0;
} else {
wrk->fxy_scale = (uint32_t)ratio;
rescaler->fxy_scale = (uint32_t)ratio;
}
wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->y_sub);
rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->y_sub);
} else {
wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->x_add);
// wrk->fxy_scale is unused here.
rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->x_add);
// rescaler->fxy_scale is unused here.
}
wrk->irow = work;
wrk->frow = work + num_channels * dst_width;
memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
rescaler->irow = work;
rescaler->frow = work + num_channels * dst_width;
memset(work, 0, (size_t)total_size);
WebPRescalerDspInit();
return 1;
}
int WebPRescalerGetScaledDimensions(int src_width, int src_height,
@ -82,6 +90,7 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
{
int width = *scaled_width;
int height = *scaled_height;
const int max_size = INT_MAX / 2;
// if width is unspecified, scale original proportionally to height ratio.
if (width == 0 && src_height > 0) {
@ -94,7 +103,7 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
(int)(((uint64_t)src_height * width + src_width - 1) / src_width);
}
// Check if the overall dimensions still make sense.
if (width <= 0 || height <= 0) {
if (width <= 0 || height <= 0 || width > max_size || height > max_size) {
return 0;
}
@ -107,31 +116,34 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
//------------------------------------------------------------------------------
// all-in-one calls
int WebPRescaleNeededLines(const WebPRescaler* const wrk, int max_num_lines) {
const int num_lines = (wrk->y_accum + wrk->y_sub - 1) / wrk->y_sub;
int WebPRescaleNeededLines(const WebPRescaler* const rescaler,
int max_num_lines) {
const int num_lines =
(rescaler->y_accum + rescaler->y_sub - 1) / rescaler->y_sub;
return (num_lines > max_num_lines) ? max_num_lines : num_lines;
}
int WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
int WebPRescalerImport(WebPRescaler* const rescaler, int num_lines,
const uint8_t* src, int src_stride) {
int total_imported = 0;
while (total_imported < num_lines && !WebPRescalerHasPendingOutput(wrk)) {
if (wrk->y_expand) {
rescaler_t* const tmp = wrk->irow;
wrk->irow = wrk->frow;
wrk->frow = tmp;
while (total_imported < num_lines &&
!WebPRescalerHasPendingOutput(rescaler)) {
if (rescaler->y_expand) {
rescaler_t* const tmp = rescaler->irow;
rescaler->irow = rescaler->frow;
rescaler->frow = tmp;
}
WebPRescalerImportRow(wrk, src);
if (!wrk->y_expand) { // Accumulate the contribution of the new row.
WebPRescalerImportRow(rescaler, src);
if (!rescaler->y_expand) { // Accumulate the contribution of the new row.
int x;
for (x = 0; x < wrk->num_channels * wrk->dst_width; ++x) {
wrk->irow[x] += wrk->frow[x];
for (x = 0; x < rescaler->num_channels * rescaler->dst_width; ++x) {
rescaler->irow[x] += rescaler->frow[x];
}
}
++wrk->src_y;
++rescaler->src_y;
src += src_stride;
++total_imported;
wrk->y_accum -= wrk->y_sub;
rescaler->y_accum -= rescaler->y_sub;
}
return total_imported;
}

View File

@ -47,12 +47,13 @@ struct WebPRescaler {
};
// Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
void WebPRescalerInit(WebPRescaler* const rescaler,
int src_width, int src_height,
uint8_t* const dst,
int dst_width, int dst_height, int dst_stride,
int num_channels,
rescaler_t* const work);
// Returns false in case of error.
int WebPRescalerInit(WebPRescaler* const rescaler,
int src_width, int src_height,
uint8_t* const dst,
int dst_width, int dst_height, int dst_stride,
int num_channels,
rescaler_t* const work);
// If either 'scaled_width' or 'scaled_height' (but not both) is 0 the value
// will be calculated preserving the aspect ratio, otherwise the values are

View File

@ -101,6 +101,9 @@ static void Increment(int* const v) {
#if defined(MALLOC_LIMIT)
{
const char* const malloc_limit_str = getenv("MALLOC_LIMIT");
#if MALLOC_LIMIT > 1
mem_limit = (size_t)MALLOC_LIMIT;
#endif
if (malloc_limit_str != NULL) {
mem_limit = atoi(malloc_limit_str);
}
@ -169,16 +172,16 @@ static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
const uint64_t total_size = nmemb * size;
if (nmemb == 0) return 1;
if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0;
if (total_size != (size_t)total_size) return 0;
if (!CheckSizeOverflow(total_size)) return 0;
#if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT)
if (countdown_to_fail > 0 && --countdown_to_fail == 0) {
return 0; // fake fail!
}
#endif
#if defined(MALLOC_LIMIT)
#if defined(PRINT_MEM_INFO) && defined(MALLOC_LIMIT)
if (mem_limit > 0) {
const uint64_t new_total_mem = (uint64_t)total_mem + total_size;
if (new_total_mem != (size_t)new_total_mem ||
if (!CheckSizeOverflow(new_total_mem) ||
new_total_mem > mem_limit) {
return 0; // fake fail!
}

View File

@ -42,6 +42,10 @@ extern "C" {
#endif
#endif // WEBP_MAX_ALLOCABLE_MEMORY
static WEBP_INLINE int CheckSizeOverflow(uint64_t size) {
return size == (size_t)size;
}
// size-checking safe malloc/calloc: verify that the requested size is not too
// large, or return NULL. You don't need to call these for constructs like
// malloc(sizeof(foo)), but only if there's picture-dependent size involved
@ -107,24 +111,33 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
PutLE16(data + 2, (int)(val >> 16));
}
// Returns (int)floor(log2(n)). n must be > 0.
// use GNU builtins where available.
#if defined(__GNUC__) && \
((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
// Returns (int)floor(log2(n)). n must be > 0.
static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
return 31 ^ __builtin_clz(n);
}
// counts the number of trailing zero
static WEBP_INLINE int BitsCtz(uint32_t n) { return __builtin_ctz(n); }
#elif defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#include <intrin.h>
#pragma intrinsic(_BitScanReverse)
#pragma intrinsic(_BitScanForward)
static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
unsigned long first_set_bit;
unsigned long first_set_bit; // NOLINT (runtime/int)
_BitScanReverse(&first_set_bit, n);
return first_set_bit;
}
#else // default: use the C-version.
static WEBP_INLINE int BitsCtz(uint32_t n) {
unsigned long first_set_bit; // NOLINT (runtime/int)
_BitScanForward(&first_set_bit, n);
return first_set_bit;
}
#else // default: use the (slow) C-version.
#define WEBP_HAVE_SLOW_CLZ_CTZ // signal that the Clz/Ctz function are slow
// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either
// based on table or not. Can be used as fallback if clz() is not available.
#define WEBP_NEED_LOG_TABLE_8BIT
@ -139,6 +152,15 @@ static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
}
static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); }
static WEBP_INLINE int BitsCtz(uint32_t n) {
int i;
for (i = 0; i < 32; ++i, n >>= 1) {
if (n & 1) return i;
}
return 32;
}
#endif
//------------------------------------------------------------------------------

View File

@ -2764,7 +2764,7 @@ SWIG_Python_DestroyModule(void *vptr)
SWIGRUNTIME void
SWIG_Python_SetModule(swig_module_info *swig_module) {
#if PY_VERSION_HEX >= 0x03000000
/* Add a dummy module object into sys.modules */
/* Add a placeholder module object into sys.modules */
PyObject *module = PyImport_AddModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION);
#else
static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} }; /* Sentinel */

View File

@ -14,10 +14,13 @@
//
////////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include "./fuzz_utils.h"
#include "webp/decode.h"
#include "src/webp/decode.h"
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
int i;
WebPDecoderConfig config;
if (!WebPInitDecoderConfig(&config)) return 0;
if (WebPGetFeatures(data, size, &config.input) != VP8_STATUS_OK) return 0;
@ -59,39 +62,53 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
config.output.colorspace = (WEBP_CSP_MODE)(value % MODE_LAST);
#endif // WEBP_REDUCE_CSP
if (size % 3) {
// Decodes incrementally in chunks of increasing size.
WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
if (!idec) return 0;
VP8StatusCode status;
if (size & 8) {
size_t available_size = value + 1;
while (1) {
if (available_size > size) available_size = size;
status = WebPIUpdate(idec, data, available_size);
if (status != VP8_STATUS_SUSPENDED || available_size == size) break;
available_size *= 2;
}
} else {
// WebPIAppend expects new data and its size with each call.
// Implemented here by simply advancing the pointer into data.
const uint8_t* new_data = data;
size_t new_size = value + 1;
while (1) {
if (new_data + new_size > data + size) {
new_size = data + size - new_data;
}
status = WebPIAppend(idec, new_data, new_size);
if (status != VP8_STATUS_SUSPENDED || new_size == 0) break;
new_data += new_size;
new_size *= 2;
for (i = 0; i < 2; ++i) {
if (i == 1) {
// Use the bitstream data to generate extreme ranges for the options. An
// alternative approach would be to use a custom corpus containing webp
// files prepended with sizeof(config.options) zeroes to allow the fuzzer
// to modify these independently.
const int data_offset = 50;
if (size > data_offset + sizeof(config.options)) {
memcpy(&config.options, data + data_offset, sizeof(config.options));
} else {
break;
}
}
WebPIDelete(idec);
} else {
WebPDecode(data, size, &config);
}
if (size % 3) {
// Decodes incrementally in chunks of increasing size.
WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
if (!idec) return 0;
VP8StatusCode status;
if (size & 8) {
size_t available_size = value + 1;
while (1) {
if (available_size > size) available_size = size;
status = WebPIUpdate(idec, data, available_size);
if (status != VP8_STATUS_SUSPENDED || available_size == size) break;
available_size *= 2;
}
} else {
// WebPIAppend expects new data and its size with each call.
// Implemented here by simply advancing the pointer into data.
const uint8_t* new_data = data;
size_t new_size = value + 1;
while (1) {
if (new_data + new_size > data + size) {
new_size = data + size - new_data;
}
status = WebPIAppend(idec, new_data, new_size);
if (status != VP8_STATUS_SUSPENDED || new_size == 0) break;
new_data += new_size;
new_size *= 2;
}
}
WebPIDelete(idec);
} else {
WebPDecode(data, size, &config);
}
WebPFreeDecBuffer(&config.output);
WebPFreeDecBuffer(&config.output);
}
return 0;
}

View File

@ -15,9 +15,9 @@
////////////////////////////////////////////////////////////////////////////////
#include "./fuzz_utils.h"
#include "webp/decode.h"
#include "webp/demux.h"
#include "webp/mux_types.h"
#include "src/webp/decode.h"
#include "src/webp/demux.h"
#include "src/webp/mux_types.h"
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
WebPData webp_data;

View File

@ -16,7 +16,7 @@
#include "examples/anim_util.h"
#include "imageio/imageio_util.h"
#include "webp/demux.h"
#include "src/webp/demux.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// WebPAnimDecoderGetInfo() is too late to check the canvas size as

View File

@ -18,8 +18,8 @@
#include <stdlib.h>
#include "./fuzz_utils.h"
#include "webp/encode.h"
#include "webp/mux.h"
#include "src/webp/encode.h"
#include "src/webp/mux.h"
namespace {

View File

@ -18,8 +18,8 @@
#include <stdlib.h>
#include "./fuzz_utils.h"
#include "webp/decode.h"
#include "webp/encode.h"
#include "src/webp/decode.h"
#include "src/webp/encode.h"
namespace {

View File

@ -23,8 +23,8 @@
#include "./img_alpha.h"
#include "./img_grid.h"
#include "./img_peak.h"
#include "dsp/dsp.h"
#include "webp/encode.h"
#include "src/dsp/dsp.h"
#include "src/webp/encode.h"
//------------------------------------------------------------------------------
// Arbitrary limits to prevent OOM, timeout, or slow execution.

View File

@ -15,8 +15,8 @@
////////////////////////////////////////////////////////////////////////////////
#include "./fuzz_utils.h"
#include "webp/demux.h"
#include "webp/mux.h"
#include "src/webp/demux.h"
#include "src/webp/mux.h"
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
WebPData webp_data;

View File

@ -15,7 +15,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "./fuzz_utils.h"
#include "webp/decode.h"
#include "src/webp/decode.h"
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
int w, h;

View File

@ -48,6 +48,7 @@ PLATFORMS[$MACOS_CATALYST]="MacOSX-Catalyst-x86_64"
if [[ "${XCODE%%.*}" -ge 12 ]]; then
PLATFORMS[$MACOS]+=" MacOSX-arm64"
PLATFORMS[$MACOS_CATALYST]+=" MacOSX-Catalyst-arm64"
PLATFORMS[$IOS_SIMULATOR]+=" iPhoneSimulator-arm64"
elif [[ "${XCODE%%.*}" -eq 11 ]]; then
cat << EOF
WARNING: Xcode 12.0 or higher is required to build targets for
@ -140,7 +141,9 @@ for (( i = 0; i < $NUM_PLATFORMS; ++i )); do
CFLAGS="-pipe -isysroot ${SDKROOT} -O3 -DNDEBUG"
case "${PLATFORM}" in
iPhone*)
CFLAGS+=" -miphoneos-version-min=${IOS_MIN_VERSION} -fembed-bitcode"
CFLAGS+=" -fembed-bitcode"
CFLAGS+=" -target ${ARCH}-apple-ios${IOS_MIN_VERSION}"
[[ "${PLATFORM}" == *Simulator* ]] && CFLAGS+="-simulator"
;;
MacOSX-Catalyst*)
CFLAGS+=" -target"