Compare commits

...

541 Commits
v1.2.4 ... main

Author SHA1 Message Date
James Zern
ad52d5fc7e dec/dsp/enc/utils,cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

This is the final change in this set. It is rather large due to the
shared dependencies between dec/enc.

Change-Id: I89de06b5653ae0bb627f904fa6060334831f7e3b
2025-04-16 13:23:42 -07:00
James Zern
ed7cd6a7f3 utils.c,cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

Change-Id: Ie2f82401e1ba28bd0575b6bb82d12ed55c71718f
2025-04-16 11:47:46 -07:00
James Zern
3a23b0f008 random_utils.[hc],cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

Change-Id: Ib58d676fa79c5a4a95c676a98b62b548097f3c48
2025-04-16 11:47:46 -07:00
James Zern
a99d0e6f04 quant_levels_dec_utils.c,cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

Change-Id: Ia4ce0fd0095f76f7edbc0fc6fe7f625e0d8bc6df
2025-04-16 11:47:46 -07:00
James Zern
1ed4654dc0 huffman_encode_utils.[hc],cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

Change-Id: Ice1edbbd98172a916be6b6d3cdaff80fe05a6e37
2025-04-16 11:47:46 -07:00
James Zern
f0689e48cb config_enc.c,cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

Change-Id: I23878bca2e14a898266704f3fec65d40f58fd0b2
2025-04-16 11:47:45 -07:00
James Zern
24262266d0 mux,cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

Change-Id: I9774ed6182ee4d872551aea56390fc0662cf0925
2025-04-16 11:47:41 -07:00
James Zern
3f54b1aa12 demux,cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

Change-Id: Ida41ca82445800552573ff5ebbde743cf8fa6eff
2025-04-15 19:27:17 -07:00
James Zern
295804e4b9 examples,cosmetics: rm struct member '_' suffix
This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

Change-Id: If6a77a316e36a6d87abaa69692a34374ba6aed4f
2025-04-15 12:07:42 -07:00
Vincent Rabaud
5225592f6b Refactor VP8LHistogram to hide initializations from the user.
This will make it easier to update some future statistics

Change-Id: I3a3ec64d3c9c53ebcf491007e3a4d916e122c87f
2025-04-11 16:16:37 +02:00
Vincent Rabaud
00338240c1 Remove some computations in histogram clustering
- move the bin_id to the Histogram
- do not consider empty histograms

The speed-ups are negligible as linear algorithms in uint16_t are
removed, while the whole code is still O(N^2) in histograms.

Change-Id: Ie9c4831f0f3c64af9d9710a1dc2d817ba165389e
2025-04-11 08:55:24 +02:00
Vincent Rabaud
44f91b0ddd Speed DispatchAlpha_SSE2 up
On some dataset, this was taking 2.5%. 2% when switching to
_mm_maskmoveu_si128. 1.7% when using _mm_loadu_si128

Confirmed by IACA: going from throughput of 4.26 to 3.5 and then
to 6.26 for twice the input.

Change-Id: I409f901aaad9d39bf55a1aac28cc25f126876b01
2025-04-10 11:53:19 +02:00
Vincent Rabaud
ee8e8c620f Fix member naming for VP8LHistogram
clang-tidy keeps complaining and that typedef will evolve in the
future

Change-Id: I734f2ae7dc0f4deac0dd391ae9f4b38c45507651
2025-04-10 09:54:57 +02:00
Vincent Rabaud
a1ad3f1e37 Merge "Remove now unused ExtraCostCombined" into main 2025-04-01 00:28:47 -07:00
Vincent Rabaud
321561b41f Remove now unused ExtraCostCombined
Change-Id: Ic9d1ccf5b10fed67f836aa19fa0f84238acbf4c1
2025-03-29 23:34:20 +01:00
James Zern
e0ae21d231 WebPMemoryWriterClear: use WebPMemoryWriterInit
Removes some common code between the two functions.

Change-Id: If9f42e580e34dad63f3806750d9d7571941026b5
2025-03-28 12:37:24 -07:00
Vincent Rabaud
a4183d94c7 Remove the computation of ExtraCost when comparing histograms
Entropy clustering merges symbol histograms to reduce the overall
entropy. The cost of 2 added histograms is compared to the 2 costs
of the individual histograms and if it is smaller, a merge is done.

Except for some symbols (distance and length), the computed cost is
 the real final cost based on the histogram, and some constant cost
(independent from the probabilities of the symbols and hence the
merge) because the symbol is encode as Golomb.

This constant cost is useless and can be removed.

Change-Id: I6271e8c0e4111cdeff544cbdb7dec3c67be5309c
2025-03-28 15:00:41 +01:00
Vincent Rabaud
f2b3f52733 Get AVX2 into WebP lossless
Change-Id: Ifad3102c9f899a46401985515cd98f3f7a21887f
2025-03-28 11:44:03 +01:00
Vincent Rabaud
7c70ff7a3b Clean dsp/lossless includes
Change-Id: I47a405a9c402095b440404fe57ac08b5293ea71b
2025-03-25 12:38:00 +01:00
Vincent Rabaud
9dd5ae819b Use the full register in PredictorSub13_SSE2
No more than 15 registers are used at a time

Change-Id: I40f77d9df8500e5e0d52ff6b206d765e8be62ae1
2025-03-25 11:07:15 +01:00
James Zern
613be8fc61 Makefile.vc: add /MP to CFLAGS
This speeds up the batch rules by compiling source files in parallel.

Change-Id: If5076e9c245d82df957b05711a74e2569f4ba086
2025-03-17 16:33:51 -07:00
James Zern
1d86819f49 Merge changes I1437390a,I10a20de5,I1ac777d1 into main
* changes:
  pngdec.c: add support for 'eXIf' tag
  pngdec.c: support ImageMagick app1 exif text data
  pngdec.c: add missing #ifdef for png_get_iCCP
2025-03-06 14:00:07 -08:00
James Zern
743a5f092d enc_neon: enable vld1q_u8_x4 for clang & msvc
This restores the use of the function after
980b708e enc_neon: fix build w/aarch64 gcc < 9.4.0

The intrinsic was added to llvm for aarch64 in:
5e4ce1ae9dad Implement the newly added AArch64 ACLE functions for
             ld1/st1 with 2/3/4 vectors. The functions are like:
             vst1_s8_x2 ...
llvmorg-3.4.0-rc1~101
https://github.com/llvm/llvm-project/commit/5e4ce1ae9dad

Visual Studio 2019 and 2022 also support the function (2017 is still
disabled for this path due to it relying on arm64_neon.h).

Change-Id: I6ff10e22deb3968a48738a4458d2d3d55410b5ec
2025-03-05 16:56:20 -08:00
James Zern
565da14882 pngdec.c: add support for 'eXIf' tag
Test file created with exiftool 12.76:

```
exiftool test_app1_exif.png -exif:all \
  -exif:DocumentName=test_multi_exif.png -o test_multi_exif.png
```

Bug: webp:398066379
Change-Id: I1437390a70f5708421683eb69c588624bb376baa
2025-03-05 13:54:09 -08:00
James Zern
319860e919 pngdec.c: support ImageMagick app1 exif text data
Test file created with ImageMagick 6.9.13-12:

```
convert test_exif.png test_app1_exif.png
```

Bug: webp:398066379
Change-Id: I10a20de5699fabb0906045994d7d1f4b9e951973
2025-03-05 13:54:07 -08:00
James Zern
815fc1e110 pngdec.c: add missing #ifdef for png_get_iCCP
png_get_iCCP is an optional part of the API. Protect its usage with
PNG_iCCP_SUPPORTED.

Change-Id: I1ac777d1c2a200bb3e1303b3d095cc0d67633bd4
2025-03-05 13:54:04 -08:00
James Zern
980b708e2c enc_neon: fix build w/aarch64 gcc < 9.4.0
vld1q_u8_x4 was added for aarch64 in the gcc 9.4.0 release:
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/ChangeLog;h=7558c0a369ea8c74a2b9369049a2d1cc187dc050;hb=13c83c4cc679ad5383ed57f359e53e8d518b7842#l2100

fixes:
src/dsp/enc_neon.c: In function 'Intra4Preds_NEON':
src/dsp/enc_neon.c:974:37: warning: implicit declaration of function
  'vld1q_u8_x4'; did you mean 'vld1q_u8_x2'?
  [-Wimplicit-function-declaration]

Bug: webp:398288323
Change-Id: Ic6e408065a375c945cc8691bd16a9f5d5642cfa2
2025-02-27 19:07:50 -08:00
James Zern
73b728cbb9 cmake: bump minimum version to 3.16
This matches the current support matrix (from 2024-12-17) [1] and quiets
a warning from recent (3.31.5) versions of cmake:

CMake Deprecation Warning at CMakeLists.txt:12 (cmake_minimum_required):
  Compatibility with CMake < 3.10 will be removed from a future version
  of CMake.

Explicit setting of CMP0072 is also removed; it was added in 3.11.

[1]: https://github.com/google/oss-policies-info/blob/main/foundational-cxx-support-matrix.md

Bug: webp:397130631
Change-Id: Ic844dadf983a82674990edbddbfc54329df12eb7
Fixed: webp:397130631
2025-02-20 12:32:08 -08:00
Vincent Rabaud
6a22b6709c Add a function to validate a WebPDecoderConfig
This echoes WebPValidateConfig for encoding.

Change-Id: Ib404d55c7af4d0755644879ec491e3998e6b5e8d
2025-01-30 10:10:08 +01:00
Vincent Rabaud
7ed2b10ef0 Use consistently signed stride types.
The stride can be negative when asked for a flipped image.

Change-Id: I049e8027c769186274a6a3049949f3fcaae7d2e9
2025-01-30 00:12:28 +01:00
Vincent Rabaud
654bfb040c Avoid nullptr arithmetic in VP8BitReaderSetBuffer
When start is nullptr, the IO is not used afterwards
anyway, so there is not risk.

Change-Id: I0a828aec85c6e228e95dfed4a40d348275a7c577
2025-01-30 00:12:15 +01:00
Vincent Rabaud
f8f2410710 Fix potential "divide by zero" in examples found by coverity
Change-Id: Ic41f9cb2ac24450986cd061db718953276eee080
2025-01-16 18:02:41 +01:00
James Zern
2af6c034ac libwebp-1.5.0
- 12/19/2024 version 1.5.0
   This is a binary compatible release.
   API changes:
     - `cross_color_transform_bits` added to WebPAuxStats
   * minor lossless encoder speed and compression improvements
   * lossless encoding does not use floats anymore
   * additional Arm optimizations for lossy & lossless + general code generation
     improvements
   * improvements to WASM performance (#643)
   * improvements and corrections in webp-container-spec.txt and
     webp-lossless-bitstream-spec.txt (#646, #355607636)
   * further security related hardening and increased fuzzing coverage w/fuzztest
     (oss-fuzz: #382816119, #70112, #70102, #69873, #69825, #69508, #69208)
   * miscellaneous warning, bug & build fixes (#499, #562, #381372617,
     #381109771, #42340561, #375011696, #372109644, chromium: #334120888)
   Tool updates:
     * gif2webp: add -sharp_yuv & -near_lossless
     * img2webp: add -exact & -noexact
     * exit codes normalized; running an example program with no
       arguments will output its help and exit with an error (#42340557,
       #381372617)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEaw5rcJdt4wPt8vYB+cPWvbgjK10FAmdk0soACgkQ+cPWvbgj
 K11UhhAAl5LtmIDz5uQE5ZlAADpIAuAC5nIikQUVY9up4RqAaw734atTh5JRzbpL
 QoQvAUPQ6YBdiH2GSF47THGHHQZfsV+f3yb0MICI3l6NOBJhHHFmG2Dt3IVVmO1l
 LZGM1CxaSZP7gpvSa/eNwvXEWxLezith7I3fyY0oIEf+JKdWan7uyeUPvc+iFrpo
 xTSpcAdWbHKGaC6zvH5gPJPlW64D2MZ31To+26s44uSgwpB6JrICXpxwn51cOClc
 1YzGJZ/aTQBphwY0W2yYFa5rBs6VxhCGHJAY5dSTmkeMUiQpIz0kugkKmyfVBmfN
 2tLC1suE0WgXzHUVwlZdorM5EIjXK0Orht/Fn5EphjmUXPr+2S+ENwiOnI2HPrEB
 Fn3Cy64uOHsuW58JVm+yUeNtPqB8uXunzQrteO7nd5aKXNxgth83QJwzv0T80tMI
 NltAfse+QPrbwA/GS250hh+8WfFzOr8i9W/3V0OYZXqLD/ooJA2hxy3gAU6Zr2qa
 GowRvbCZs18w1ormXoDEC3tBnBBPi8ktRfYd2wGHRl0VUFo1Ntyj+tr8NOuylpxO
 hE3WFn/Ao6Xs3WRSx1LppbPvWnH+j2UAm0QCeAcUN2A766XpKyupGDAg09fZUZe6
 korrahZni3I0uOpqyZX0W2FmCQYIIRHTwcCNLD/yTqlqhyiQtDg=
 =HZLr
 -----END PGP SIGNATURE-----

Merge tag 'v1.5.0'

libwebp-1.5.0

- 12/19/2024 version 1.5.0
  This is a binary compatible release.
  API changes:
    - `cross_color_transform_bits` added to WebPAuxStats
  * minor lossless encoder speed and compression improvements
  * lossless encoding does not use floats anymore
  * additional Arm optimizations for lossy & lossless + general code generation
    improvements
  * improvements to WASM performance (#643)
  * improvements and corrections in webp-container-spec.txt and
    webp-lossless-bitstream-spec.txt (#646, #355607636)
  * further security related hardening and increased fuzzing coverage w/fuzztest
    (oss-fuzz: #382816119, #70112, #70102, #69873, #69825, #69508, #69208)
  * miscellaneous warning, bug & build fixes (#499, #562, #381372617,
    #381109771, #42340561, #375011696, #372109644, chromium: #334120888)
  Tool updates:
    * gif2webp: add -sharp_yuv & -near_lossless
    * img2webp: add -exact & -noexact
    * exit codes normalized; running an example program with no
      arguments will output its help and exit with an error (#42340557,
      #381372617)

Bug: b:336795049,webp:380121350

* tag 'v1.5.0':
  update ChangeLog
  update NEWS
  tests/fuzzer/*: add missing <string_view> include
  fuzz_utils.cc: fix build error w/WEBP_REDUCE_SIZE
  mux_demux_api_fuzzer.cc: fix -Wshadow warning
  update ChangeLog
  update NEWS
  bump version to 1.5.0
  update AUTHORS

Change-Id: I076b197fac29230bc61bc5f06e950d83d058a737
2024-12-19 18:19:10 -08:00
James Zern
a4d7a71533 update ChangeLog
Bug: b:336795049,webp:380121350
Change-Id: I011bf6c44f89e475f58c6e96f5b68c6ed75a1e22
2024-12-19 17:17:50 -08:00
James Zern
c3d85ce4cf update NEWS
Bug: b:336795049,webp:380121350
Change-Id: Icb6f2f046647591a318f12853f265b2115060488
2024-12-19 12:32:05 -08:00
devtools-clrobot@google.com
ad14e811cf tests/fuzzer/*: add missing <string_view> include
Bug: webp:380121350
Change-Id: Ie0910165600317ed8c94305f0a793282e02e1c99
2024-12-19 12:31:52 -08:00
James Zern
74cd026edb fuzz_utils.cc: fix build error w/WEBP_REDUCE_SIZE
Correct (void) variable names.

Bug: webp:380121350
Change-Id: I3ce8a4d34f60f9ec0a467fcb5958b0b7a2edabc9
2024-12-17 09:58:20 -08:00
James Zern
a027aa93de mux_demux_api_fuzzer.cc: fix -Wshadow warning
`bool mux` -> `use_mux_api` to avoid conflicting with WebPMux variable.

Bug: webp:380121350
Change-Id: Ie3f8176efc296fae804c36ee0b27bf8e3034c6e8
2024-12-17 09:57:47 -08:00
James Zern
25e17c686f update ChangeLog
Bug: b:336795049,webp:380121350
Change-Id: I0ae2d1d3a812b6bc9c4cd889eae03308e344190b
2024-12-13 12:25:59 -08:00
James Zern
aa2684fccc update NEWS
Bug: b:336795049,webp:380121350
Change-Id: Ieb2c7961f6eef39813399855027d007e88ca7891
2024-12-13 09:27:03 -08:00
James Zern
369238461b bump version to 1.5.0
libwebp{,decoder} - 1.5.0
libwebp libtool - 8.10.1
libwebpdecoder libtool - 4.10.1

mux - 1.5.0
libtool - 4.1.1

demux - 1.5.0
libtool - 2.16.0

sharpyuv - 0.4.1
libtool - 1.1.1

Bug: b:336795049,webp:380121350
Change-Id: I53bdac2b0bd5ce30addf10e16776a16a07910e45
2024-12-12 17:43:51 -08:00
James Zern
ceea8ff6b3 update AUTHORS
Bug: b:336795049,webp:380121350
Change-Id: I45a2aff8d9f04d996e3391d111d18d0872f45b41
2024-12-12 17:43:41 -08:00
James Zern
e4f7a9f0c7 img2webp: add a warning for unused options
This may help prevent confusion when placing frame options after the
target frame.

Note for compatibility this isn't fatal, but the behavior may change in
the future.

Bug: webp:381372617
Change-Id: I9f3b51e60ff650ccc6fd29b8f5f607c3771a8a55
2024-12-10 17:32:54 -08:00
Vincent Rabaud
1b4c967fbb Merge "Properly check the data size against the end of the RIFF chunk" into main 2024-12-10 08:10:16 +00:00
Vincent Rabaud
9e5ecfaf00 Properly check the data size against the end of the RIFF chunk
Bug: oss-fuzz:382816119

Change-Id: I629870246d8f1bd7c6cb0d66e89018600cecee3a
2024-12-10 09:09:08 +01:00
James Zern
da0d9c7d4e examples: exit w/failure w/no args
cwebp, gif2webp, img2webp, vwebp and webpinfo are modified in this
change to align with the other examples. When given no arguments, the
examples print their help output and exit with failure.

Bug: webp:42340557, webp:381372617
Change-Id: Ifed4eb79e98233f7aa780c42e489636d0cf4a035
2024-12-06 14:53:06 -08:00
James Zern
fcff86c71b {gif,img}2webp: sync -m help w/cwebp
These were both missing the mention of the default value (4).

Bug: webm:381109771
Change-Id: Ibb0d822310af443c5ff5219fc0334008de0a0c60
2024-11-26 13:08:29 -08:00
James Zern
b76c4a8416 man/img2webp.1: sync -m text w/cwebp.1 & gif2webp.1
Bug: webp:381109771
Change-Id: I3df400305255ba74a913601cf7aa04f392814370
2024-11-26 13:03:20 -08:00
James Zern
306335198d muxread: fix reading of buffers > riff size
After:
  2c70ad76 muxread,CreateInternal: fix riff size checks (cl/200674839)

`SizeWithPadding()` adds `CHUNK_HEADER_SIZE` (plus additional 1 byte
padding if needed). A later check included `CHUNK_HEADER_SIZE` before
capping the value of the size passed to `WebPMuxCreateInternal()`,
missing cases with a small amount of extra data after the RIFF chunk
(like a newline when the file is opened and saved in a text editor) and
setting size to an incorrect value, so larger sizes would also fail.

Another check of `riff_size < CHUNK_HEADER_SIZE` after the call to
`SizeWithPadding()` is removed because 1) it could not fail given
`SizeWithPadding()` adds `CHUNK_HEADER_SIZE` to the value; and 2) it is
redundant as `size < RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE` is checked
earlier in the function.

Bug: webp:42340561
Change-Id: I58dc4f071b27c2841001b4012aabdb1869f64f97
2024-11-22 12:40:34 -08:00
James Zern
4c85d860ea yuv.h: update RGB<->YUV coefficients in comment
The values for the R/G/B floating point formulas resembled
https://fourcc.org/fccyvrgb.php and Video Demystified, but the fixed
point values are more closely aligned to rounded values from
https://en.wikipedia.org/wiki/YCbCr and BT.601.

The R/G/B formulas with the values prior to this change are added to
sharpyuv_csp.c as they align with the fixed values. The origin of those
coefficients is unclear. For consistency between library versions we'll
leave them as is.

Bug: webp:375011696
Change-Id: Id3f2a57530eee700cc52a899b32b25b5c015e89b
2024-11-21 16:21:45 -08:00
James Zern
0ab789e067 Merge changes I6dfedfd5,I2376e2dc into main
* changes:
  rework AddVectorEq_SSE2
  rework AddVector_SSE2
2024-11-15 02:58:10 +00:00
James Zern
0323645066 {ios,xcframework}build.sh: fix compilation w/Xcode 16
Don't use `-fembed-bitcode`, fixes:
ld: warning: -bitcode_bundle is no longer supported and will be ignored
ld: -mllvm and -bitcode_bundle (Xcode setting ENABLE_BITCODE=YES) cannot
    be used together

Change-Id: I4ead0fc71da39bb5ec92c1f5ba467b95ad8b7461
2024-11-14 20:26:57 +00:00
James Zern
61e2cfdadd rework AddVectorEq_SSE2
Take advantage of the known sizes used by VP8LHistogramAdd() and
remove loop for the remainder. The loop was being auto-vectorized making
the code larger and slower than the vectorized C code.

For larger sizes the new code is ~3-4.5% faster than the old code with
about the same improvement against the vectorized C code. For the
minimal size (40), the new code is ~30% faster than the C and old SSE2
code.

The LINE_SIZE==8 option is removed with this change. It had been set
to 16 for its entire life and clang-16 was unrolling the LINE_SIZE==8
case by 2 in any case; they both profile similarly.

Change-Id: I6dfedfd57474f44d15e2ce510a48e5252221077a
2024-11-14 12:21:39 -08:00
James Zern
7bda3deb89 rework AddVector_SSE2
Take advantage of the known sizes used by VP8LHistogramAdd() and remove
loop for the remainder. The loop was being auto-vectorized making the
code larger and slower than the vectorized C code.

For larger sizes the new code is ~4-7% faster than the old code with
about the same improvement against the vectorized C code. For the
minimal size (40), the new code is ~30% faster than the C and old SSE2
code.

The LINE_SIZE==8 option is removed with this change. It had been set to
16 for its entire life and clang-16 was unrolling the LINE_SIZE==8 case
by 2 in any case; they both profile similarly.

Change-Id: I2376e2dca3bffa38477b4a432f4c533419e3be0e
2024-11-14 12:21:33 -08:00
Maryla
2ddaaf0aa5 Fix variable names in SharpYuvComputeConversionMatrix
Change-Id: Ia07e71aae42396100a4f50dc104e828239522d77
2024-11-07 09:37:40 +01:00
James Zern
a3ba6f19e9 Makefile.vc: fix gif2webp link error
Add missing dependency on libsharpyuv.

needed after:
f999d94f gif2webp: add -sharp_yuv/-near_lossless

Change-Id: I8bdd5c0fd4622f9c8ec6ffdf4ac11399f86350da
2024-11-06 10:14:05 -08:00
James Zern
f999d94f4a gif2webp: add -sharp_yuv/-near_lossless
This change is the same as the one that introduced the options to
img2webp:
0825faa4 img2webp: add -sharp_yuv/-near_lossless

Change-Id: Id380d159299c38dd6440f833d487e00c0976afec
2024-11-04 12:29:24 -08:00
James Zern
dfdcb7f95c Merge "lossless.h: fix function declaration mismatches" into main 2024-10-09 22:30:49 +00:00
James Zern
78ed683978 fix overread in Intra4Preds_NEON
Extend VP8EncIterator::i4_boundary_ by 3 bytes to avoid Intra4Preds_NEON
reading deeper into the struct (likely padding) when top is positioned
at offset 29. This data is memset with MSan to prevent a warning due to
its incorrect modeling of tbl instructions.

Prior to:
  169dfbf9 disable Intra4Preds_NEON
there was a mismatch in the preprocessor checks for enabling the
function in NEON and removing the C version; NEON used `BPS == 32` while
the C code was removed unconditionally when building for aarch64. This
patch also normalizes those checks to look for `BPS == 32` and `BPS !=
32` as appropriate.

Bug: b:366668849,webp:372109644
Change-Id: Ic9e6ad4b2d844cb446decd63aec0b2676a89c8d0
2024-10-08 16:55:12 -07:00
James Zern
d516a68e54 lossless.h: fix function declaration mismatches
These appear as warnings under VS15 (16 and 17 are silent) and were
missed in:
a32b436b dsp/lossless*: use WEBP_RESTRICT qualifier

Change-Id: Ia7cffafc166f2da93b51714363558798cda71b67
2024-10-08 13:41:16 -07:00
Maryla Ustarroz-Calonge
874069042e Merge "Improve documentation of SharpYuvConversionMatrix." into main 2024-10-04 11:59:25 +00:00
James Zern
fdb229ea3a Merge changes I07a7e36a,Ib29980f7,I2316122d,I2356e314,I32b53dd3, ... into main
* changes:
  dsp/yuv*: use WEBP_RESTRICT qualifier
  dsp/upsampling*: use WEBP_RESTRICT qualifier
  dsp/rescaler*: use WEBP_RESTRICT qualifier
  dsp/lossless*: use WEBP_RESTRICT qualifier
  dsp/filters*: use WEBP_RESTRICT qualifier
  dsp/enc*: use WEBP_RESTRICT qualifier
  dsp/dec*: use WEBP_RESTRICT qualifier
  dsp/cost*: use WEBP_RESTRICT qualifier
2024-10-03 17:01:02 +00:00
Maryla
0c3cd9cc2c Improve documentation of SharpYuvConversionMatrix.
Change-Id: I39898bf53db759b68c86c9005c11ded20de4eb3e
2024-10-03 10:35:58 +02:00
James Zern
169dfbf931 disable Intra4Preds_NEON
The load of the `top` parameter may over read causing MSan errors:

==7373==WARNING: MemorySanitizer: use-of-uninitialized-value
  #0 0xfff891d52ad4 in Intra4Preds_NEON src/dsp/enc_neon.c:1003:12
  #1 0xfff892d87618 in MakeIntra4Preds src/enc/quant_enc.c:484:3

Bug: b:366668849
Change-Id: I29cf3b2f402ee79ea93c1ee2a4fdd95083aeed68
2024-10-02 15:42:19 -07:00
James Zern
2dd5eb9862 dsp/yuv*: use WEBP_RESTRICT qualifier
Better vectorization in the C code, fewer instructions / comparisons in
NEON, and fewer reloads in SSE2/SSE4 w/ndk r27/gcc-13/clang-16.

This only affects non-vector pointers; any vector pointers are left as a
follow up.

Change-Id: I07a7e36a2dce8632c71c0fbbeef94dc51453eaf7
2024-10-02 14:55:15 -07:00
James Zern
23bbafbeb8 dsp/upsampling*: use WEBP_RESTRICT qualifier
Better vectorization in the C code, fewer instructions in NEON, and some
code reordering / better register usage in SSE2/SSE4 w/ndk
r27/gcc-13/clang-16.

This only affects non-vector pointers; any vector pointers are left as a
follow up.

Change-Id: Ib29980f778ad3dbb952178ad8dee39b8673c4ff8
2024-10-02 14:55:15 -07:00
James Zern
35915b389e dsp/rescaler*: use WEBP_RESTRICT qualifier
Some improvement in the C code. No changes in NEON or SSE2 w/ndk
r27/gcc-13/clang-16.

This only affects non-vector pointers; any vector pointers are left as a
follow up.

Change-Id: I2316122db893f48f0afda90a147c83cac7f07526
2024-10-02 14:55:14 -07:00
James Zern
a32b436bd5 dsp/lossless*: use WEBP_RESTRICT qualifier
lossless_enc: better vectorization, most benefits seen in AddVector/Eq
              w/ndk r27/gcc-13/clang-16
lossless: minor reordering and some improvement to PredictorAdd5_SSE2
          w/gcc-13

This only affects non-vector pointers; any vector pointers are left as a
follow up.

Change-Id: I2356e314f391ee2f2c71f00bc6ee10097d3881e7
2024-10-02 14:55:14 -07:00
James Zern
04d4b4f387 dsp/filters*: use WEBP_RESTRICT qualifier
Better stack/register usage in SSE2/NEON code and improved vectorization
of the C code with ndk r27/gcc-13/clang-16.

This only affects non-vector pointers; any vector pointers are left as a
follow up.

Change-Id: I32b53dd38bfc7e2231d875409e7dfda7c513cfb6
2024-10-02 14:55:14 -07:00
James Zern
b1cb37e659 dsp/enc*: use WEBP_RESTRICT qualifier
This allows for better vectorization of the C code, inlining of
TrueMotion_SSE2, better load usage in aarch64 and other minor
reordering with ndk r27/gcc-13/clang-16.

This only affects non-vector pointers; any vector pointers are left as a
follow up.

Change-Id: I07e9944d5c0aa5a079b22883ac5a2d649695e4a0
2024-10-02 14:55:14 -07:00
James Zern
201894ef24 dsp/dec*: use WEBP_RESTRICT qualifier
A minor improvement for arm targets with ndk r27/gcc-13 in H/VFilter8 (a
couple fewer moves w/aarch64) and much better vectorization of
DitherCombine8x8_C in most targets.

This only affects non-vector pointers; any vector pointers are left as a
follow up.

Change-Id: I03e73e6d6404261bb8408a9ae76a4b6ef142f8f0
2024-10-02 14:55:14 -07:00
James Zern
02eac8a741 dsp/cost*: use WEBP_RESTRICT qualifier
on SetResidualCoeffs_*. This results in some minor code reordering when
targeting arvm7 with ndk r27 and other recent versions of clang. No
changes in the x86 compilations with clang-16 / gcc-13.

This only affects non-vector pointers; any vector pointers are left as a
follow up.

Change-Id: I7c3554ece848fafbc5ac9c4944f1dc85129f6fd8
2024-10-02 14:55:14 -07:00
James Zern
84b118c9c3 Merge "webp-container-spec: normalize notes & unknown chunk link" into main 2024-09-30 18:16:05 +00:00
James Zern
052cf42f1a webp-container-spec: normalize notes & unknown chunk link
- use plural 'Notes' in the description of 'Background Color' to match
  the formatting of the notes describing 'Disposal method';
- fix one unknown chunks link to contain both words to match others

+ add a couple of missing commas

These changes are based on editor changes in AUTH48:
https://datatracker.ietf.org/doc/draft-zern-webp/

Change-Id: Ibbed0459d42944099e295f492dc21bde4e107658
2024-09-27 11:07:10 -07:00
Vincent Rabaud
220ee52967 Search for best predictor transform bits
This is useful in cruncher mode.

Change-Id: I8586bdbf464daf85db381ab77a18bf63dd48f323
2024-09-24 10:44:22 +02:00
Vincent Rabaud
7861947813 Try to reduce the sampling for the entropy image
This offers minor compression improvements.

Change-Id: I4b3b1bb11ee83273c0e4c9f47e53b21cf7cd5f76
2024-09-24 10:28:43 +02:00
James Zern
14f09ab75b webp-container-spec: reorder chunk size - N text
Use 'Chunk Size bytes - N' to avoid singular/plural confusion in the
case of 'Chunk Size - 1 bytes' case.

These changes are based on editor comments in AUTH48:
https://datatracker.ietf.org/doc/draft-zern-webp/

Change-Id: I898113033fd53d744fe9289f971887b8cfe278b9
2024-09-19 11:54:42 -07:00
Vincent Rabaud
a78c5356ba Remove a useless malloc for entropy image
histogram_symbols is converted to uint32_t and <<8 into
histogram_argb.
Using a uint32_t buffer from the start prevents copying and
converting the data.

Change-Id: I245003a6a0f048c31519afa25a600d4479e762e3
2024-09-18 22:38:11 +02:00
Vincent Rabaud
bc49176355 Merge "Refactor predictor finding" into main 2024-09-18 08:38:57 +00:00
James Zern
34f9223829 man/{cwebp,img2webp}.1: rm 'if needed' from -sharp_yuv
The wording might have implied that the library would optionally use
sharpyuv, though this option forces its use. The riskiness score
computed by SharpYuvEstimate420Risk() (extras/extras.c) is not used by
the library.

Change-Id: I56ea3262d7985215570809a4a629a2a7760e936a
2024-09-17 11:03:04 -07:00
Vincent Rabaud
367ca938f1 Refactor predictor finding
This is useful for a forward change that will improve compression.
It splits the residual computation and the best predictor
selection.

The only downside is that more memory is allocated: we had 2
histograms before, we now have 14, but this is necessary for the
later change. Still, this is nothing compared to what is done
later in the pipeline in HistogramSetTotalSize where the number of
histograms created is the number of pixels in the subsampled image.

Change-Id: If03501a26f00462dd1809daa6e9314abd180945d
2024-09-17 09:49:43 +02:00
James Zern
a582b53b74 webp-lossless-bitstream-spec: clarify some text
These changes are based on editor comments in AUTH48:
https://datatracker.ietf.org/doc/draft-zern-webp/

Change-Id: I21f18bce43fde0e396b2cbc935d0ff90448f96c4
2024-09-10 18:04:24 -07:00
James Zern
0fd25d8406 Merge "anim_encode.c: fix function ref in comment" into main 2024-09-10 18:53:23 +00:00
James Zern
f888291359 anim_encode.c: fix function ref in comment
WebPCleanupTransparentAreaLossless() was renamed to
WebPReplaceTransparentPixels() in:
55a080e5 Add WebPReplaceTransparentPixels() in dsp

Change-Id: I91e32574e6add2748c0655146f100eb2b40498b2
2024-09-09 19:28:12 -07:00
James Zern
40e4ca60ea specs_generation.md: update kramdown command line
coderay was extracted from the core and the options removed in 2.0.0.
See:
49e1b12f52

Change-Id: I5191dcec296ba4bcde5f0bcbc46d1e1135d40ec2
2024-09-06 15:32:26 -07:00
James Zern
57883c78ed img2webp: add -exact/-noexact per-frame options
Bug: b:363409354
Change-Id: I4e7282ed2df091dbef6d79743be1c8c868c0d44a
2024-09-03 18:58:13 -07:00
James Zern
1c8eba978b img2webp,cosmetics: add missing '.' spacers to help
Change-Id: I98e853a8caa091c182d41ea9d95499021c8deb3a
2024-09-03 18:27:45 -07:00
Vincent Rabaud
2e81017c7a Convert predictor_enc.c to fixed point
Also remove the last float in histogram_enc.c

Change-Id: I6f647a5fc6dd34a19292820817472b4462c94f49
2024-08-30 09:22:48 +02:00
Vincent Rabaud
94de6c7fed Merge "Fix fuzztest link errors w/-DBUILD_SHARED_LIBS=1" into main 2024-08-30 07:15:24 +00:00
Vincent Rabaud
51d9832a36 Fix fuzztest link errors w/-DBUILD_SHARED_LIBS=1
Change-Id: I089a59baa3275f7a62483da0bc1d5269e51af74e
2024-08-28 11:39:11 +02:00
Vincent Rabaud
7bcb36b884 Merge "Fix static overflow warning." into main 2024-08-28 09:17:08 +00:00
Vincent Rabaud
8e0cc14c3e Fix static overflow warning.
In practice, this can never happen because:
- 'streak' is at most as long as a histogram
- 'count' counts the number of streaks

'streak' and 'count' are therefore at most as big as the histogram
length which is at most the max of VP8LHistogramNumCodes,
which is 256+24+(1<<10).

Change-Id: I31c8834543479c8a9260732313ea26b045519515
2024-08-28 10:23:54 +02:00
James Zern
cea684626d README.md: add security report note
The default template for https://issues.webmproject.org/ is a public bug
report. Security issues can be reported securely using the 'Security
report' template.

Change-Id: Id489253c0def8a4d6d26327ea93ef4c796703ff1
2024-08-26 18:34:04 -07:00
James Zern
615e58744f Merge "make VP8LPredictor[01]_C() static" into main 2024-08-22 17:35:52 +00:00
James Zern
233e86b91f Merge changes Ie43dc5ef,I94cd8bab into main
* changes:
  Do*Filter_*: remove row & num_rows parameters
  Do*Filter_C: remove dead 'inverse' code paths
2024-08-19 18:51:06 +00:00
James Zern
1a29fd2fc3 make VP8LPredictor[01]_C() static
Only predictors 2-13 are reused in lossless_enc.c.

Change-Id: Ia3a7342fccfb44b9ad5297f48d6be2d96af68ec8
2024-08-16 10:58:45 -07:00
James Zern
dd9d3770d7 Do*Filter_*: remove row & num_rows parameters
The row parameter became a constant in:
2102ccd update the Unfilter API in dsp to process one row independently

num_rows is always equal to height.

Change-Id: Ie43dc5ef222e442ce8c92766da0b9824ccbca236
2024-08-12 19:36:31 -07:00
James Zern
ab451a495c Do*Filter_C: remove dead 'inverse' code paths
The inverse parameter became a constant in:
2102ccd update the Unfilter API in dsp to process one row independently

The row parameter to these functions is in a similar state; it will be
removed in a follow up.

Change-Id: I94cd8babe0e42474ff794ba5fa29dd48039de5f8
2024-08-08 18:13:48 -07:00
James Zern
f9a480f7c3 {TrueMotion,TM16}_NEON: remove zero extension
Replace vmovl_u8 -> s16 + signed vaddq with unsigned vaddw.
No change in assembly with clang-16 (armv7 & aarch64) and gcc-13
(aarch64). armv7 gcc-13 had kept the vmovl instructions, those are now
gone.

Change-Id: Ibb4fbdd5680d3e9dd06933c100528a6f363de472
2024-08-07 16:43:14 -07:00
James Zern
04834acae7 Merge changes I25c30a9e,I0a192fc6,I4cf89575 into main
* changes:
  WASM: Enable VP8L_USE_FAST_LOAD
  WASM: don't use USE_GENERIC_TREE
  WASM: Enable 64-bit BITS caching
2024-08-01 18:36:34 +00:00
James Zern
39a602afe6 webp-lossless-bitstream-spec: normalize predictor transform ref
Replace the only use of 'prediction transform' with 'predictor
transform' which is used throughout the text.

Spotted by thakis@.

Bug: webp:355607636
Change-Id: Ic4e1f08e2ff94da82824cee24c86a4fa42c7ec28
2024-07-29 19:22:33 -07:00
James Zern
f28c837dc1 Merge "webp-container-spec: align anim pseudocode w/prose" into main 2024-07-29 17:17:16 +00:00
Vincent Rabaud
74be8e22d9 Fix implicit conversion issues
Change-Id: If2cc8a137371ef365cf4a9c55f1b6ab131fba564
2024-07-25 22:30:15 +02:00
Vincent Rabaud
0c01db7c3c Merge "Increase the transform bits if possible." into main 2024-07-19 22:44:13 +00:00
Vincent Rabaud
f2d6dc1eef Increase the transform bits if possible.
This brings minor size improvements because repetitive values in
the transform images are easily explainable through LZ77. Still,
it makes an upcoming pull request a bit more stable.

This is a rollforward of
7ec51c591608333fd5e6fdddbee16e1d65bef3db
ee26766a89a149afe5f73fdcb8f2493ec808f2b7

Change-Id: I254ab3ccd5053344f89099280e8d994ecd55aee0
2024-07-19 23:22:27 +02:00
James Zern
caa19e5b3a update link to issue tracker
https://bugs.chromium.org/p/webp ->
https://issues.webmproject.org

Change-Id: I45324210d4e9351238da127efd04b22627548545
2024-07-18 16:49:45 -07:00
James Zern
c9dd9bd40b webp-container-spec: align anim pseudocode w/prose
- add missing 'or application-defined color' when creating the canvas
- reference 'dispose_method' before rendering image

Bug: webp:646
Change-Id: I25734d1912644f0aa6c87e14b80ed8cd9b180056
2024-07-16 15:42:07 -07:00
wrv
8a7c8dc662 WASM: Enable VP8L_USE_FAST_LOAD
It is 2-5% faster to use VP8L fast load on WASM

Bug: webp:643
Change-Id: I25c30a9e6bcfc7cadd640122579eeebcb37e6fc0
2024-07-15 14:41:36 -05:00
wrv
f0c53cd966 WASM: don't use USE_GENERIC_TREE
It is 2-4% faster to use hard-coded tree on WASM

Bug: webp:643
Change-Id: I0a192fc6af210c79814a81084cd1f199714bf46c
2024-07-15 14:41:14 -05:00
wrv
eef903d04a WASM: Enable 64-bit BITS caching
Bug: webp:643
Change-Id: I4cf89575e0ebcfeaf9d84be8e188863657893a07
2024-07-15 14:40:45 -05:00
James Zern
6296cc8d0d iterator_enc: make VP8IteratorReset() static
This function is unused outside of iterator_enc.c.

Change-Id: I0f1ecedeb9ed4d9f51d0135f04b8ef00424f24cc
2024-07-12 15:23:10 -07:00
James Zern
fbd93896a6 histogram_enc: make VP8LGetHistogramSize static
This function is unused outside of histogram_enc.c.

Change-Id: I527f54408383d0bc9d04878ca397a3d044b350de
2024-07-12 15:23:10 -07:00
James Zern
cc7ff5459a cost_enc: make VP8CalculateLevelCosts[] static
This table is unused outside of cost_enc.c.

Change-Id: I0aa46554b8470fb09a7ffeae0e98d2356b40b671
2024-07-12 15:23:10 -07:00
James Zern
4e2828bae8 vp8l_dec: make VP8LClear() static
This function is unused outside of vp8l_dec.c.

Change-Id: I16733a44ea024ca9601c098641a3cd464bed2b53
2024-07-12 15:22:20 -07:00
James Zern
d742b24a88 Intra16Preds_NEON: fix truemotion saturation
This needs to be done with signed saturation as the sum may be negative.

fixes mismatch with C code after:
3bfb05e3 Add AArch64 Neon implementation of Intra16Preds

Change-Id: I017e939d7155cc3489ceb76fc8ad50ac9917f23d
2024-07-11 13:37:06 -07:00
James Zern
c7bb4cb585 Intra4Preds_NEON: fix truemotion saturation
This needs to be done with signed saturation as the sum may be negative.

fixes mismatch with C code after:
baa93808 Add AArch64 Neon implementation of Intra4Preds

Change-Id: I190c3d7f78cfd2c7ae83fb7059de41e307abda36
2024-07-11 13:37:06 -07:00
Vincent Rabaud
952a989b1b Merge "Remove TODO now that log is using fixed point." into main 2024-07-11 20:11:37 +00:00
Vincent Rabaud
dde11574b0 Remove TODO now that log is using fixed point.
Bug: webp:499

Change-Id: I39ab340ec6b5932db7535c6b7f31843c28de8415
2024-07-11 20:11:03 +00:00
Vincent Rabaud
a1ca153d51 Fix hidden myerr in my_error_exit
Change-Id: I0e3660eff2f6a20446b6fcd2925312757fda424c
2024-07-11 15:59:57 +02:00
James Zern
3bd9420289 Merge changes Iff6e47ed,I24c67cd5,Id781e761 into main
* changes:
  Use QuantizeBlock_NEON for VP8EncQuantizeBlockWHT on Arm
  Add AArch64 Neon implementation of Intra16Preds
  Add AArch64 Neon implementation of Intra4Preds
2024-07-11 02:04:42 +00:00
Vincent Rabaud
d27d246e42 Merge "Convert VP8LFastSLog2 to fixed point" into main 2024-07-10 21:52:39 +00:00
Vincent Rabaud
4838611f91 Disable msg_code use in fuzzing mode
bug:oss-fuzz:70102
bug:oss-fuzz:70112
Change-Id: I519c991c784bccb4bbaec622281f81015ab479a4
2024-07-10 22:55:21 +02:00
Istvan Stefan
314a142a34 Use QuantizeBlock_NEON for VP8EncQuantizeBlockWHT on Arm
Use the Neon implementation instead of falling back to
QuantizeBlock_C.

Change-Id: Iff6e47eda353cbaa9766f75040fa63aa34607816
2024-07-10 14:48:38 +01:00
Istvan Stefan
3bfb05e38c Add AArch64 Neon implementation of Intra16Preds
Add a Neon implementation of Intra16Preds for use on 64-bit Arm
platforms. (This implementation cannot be used on 32-bit Arm
platforms as it makes use of a number of AArch64-only Neon
instructions.)

Change-Id: I24c67cd54b66307e3924fd332c2795fd7422f082
2024-07-10 14:48:38 +01:00
Istvan Stefan
baa93808d9 Add AArch64 Neon implementation of Intra4Preds
Add Neon implementation of Intra4Preds for use on 64-bit Arm
platforms. (The same implementation cannot be used for 32-bit Arm
platforms as it uses a number of AArch64-only Neon instructions.)

Change-Id: Id781e7614f4e8e876dfeecd95cfc85e04611d8c6
2024-07-10 14:48:26 +01:00
Vincent Rabaud
41a5e582c2 Fix errors when compiling code as C++
Change-Id: Iba94e24e764038640f39d61fb2bc9cfb3434cc8f
2024-07-10 10:30:48 +02:00
Vincent Rabaud
fb444b692b Convert VP8LFastSLog2 to fixed point
Speedups: 1% with '-lossless', 2% with '-lossless -q 100 -m6'

Change-Id: I1d79ea8e3e9e4bac7bcea4d7cbcc1bd56273988e
2024-07-09 16:42:21 +02:00
Vincent Rabaud
c1c89f5189 Fix WEBP_NODISCARD comment and C++ version
Change-Id: I8b94974a46b7ac7d9bce179a48655ba8d9700edf
2024-07-09 14:24:00 +02:00
Vincent Rabaud
66408c2c7c Switch the histogram_enc.h API to fixed point
Speedups: 4% with '-lossless', 8% with '-lossless -q 100 -m6'

Change-Id: I8f1c244b290d48132c1edc6a1c9fc3f79fef68ec
2024-07-09 13:39:45 +02:00
Vincent Rabaud
ac1e410ded Remove leftover tiff dep
Change-Id: I880ee0f8d0b80fb0f0e476baaf91fe545195c029
2024-07-05 13:39:23 +02:00
Vincent Rabaud
b78d39571f Disable TIFF on fuzztest.
oss-fuzz does not support dynamic libraries so we stick to
static. But libtiff.a has undefined symbols on Ubuntu, so we
have to disable TIFF.

Change-Id: Ibd1932f5780a0af51b6b398ae6415eed8685a0be
2024-07-05 11:26:12 +02:00
Vincent Rabaud
cff21a7d87 Do not build statically on oss-fuzz.
This is to get TIFF support for imageio.

Change-Id: I3c9aea4b72661926568dc777644b7a9ddd499726
2024-07-04 15:44:12 +02:00
Vincent Rabaud
6853a8e5ac Merge "Move more internal fuzzers to public." into main 2024-07-02 13:47:01 +00:00
Vincent Rabaud
9bc09db4b8 Merge "Convert VP8LFastLog2 to fixed point" into main 2024-07-02 09:48:16 +00:00
Vincent Rabaud
0a9f1c19f8 Convert VP8LFastLog2 to fixed point
The lossless encoding speed-ups are:
- up to 1% with default parameters
- up to 4% in cruncher mode: -q 100 -m 6

Change-Id: Id92d4bad0b0a2c28c8aa9ff5280eea5717017f30
2024-07-02 10:29:38 +02:00
Vincent Rabaud
db0cb9c27e Move more internal fuzzers to public.
Change-Id: Idde75f374264666e4c54a17b1606464ad5d00d9c
2024-06-28 16:59:18 +02:00
James Zern
ff2b5b15ae Merge "advanced_api_fuzzer.cc: use crop dims in OOM check" into main 2024-06-26 18:30:07 +00:00
Vincent Rabaud
c4af79d053 Put 0 at the end of a palette and do not store it.
This only applies to kSortedDefault and kMinimizeDelta.

Change-Id: I9d4178406ed2ef91c5c55f0a1919cfc6605fedf9
2024-06-25 14:46:05 +02:00
Vincent Rabaud
0ec80aef3d Delete last references to delta palettization
Change-Id: I1f931d3aa587d2ae82895ae7c7f4c94fb82fbfb1
2024-06-25 10:53:43 +02:00
James Zern
96d79f8481 advanced_api_fuzzer.cc: use crop dims in OOM check
Apply crop dimensions before calculating scaled width/height to ensure
the check against fuzz_utils::kFuzzPxLimit will use the same dimensions
as the decoder.

Bug: oss-fuzz:69873
Change-Id: Icd0862eadf8575135b6d53376acc79d14733a0e5
2024-06-24 16:35:06 -07:00
Vincent Rabaud
c35c7e0240 Fix huffman fuzzer to not leak.
That was obviously intentional to see if the new fuzzer was
working :)

Bug: oss-fuzz=69825
Change-Id: Ie9465bb6225999fd792b712cc585ca3ee1ec528a
2024-06-24 10:13:16 +02:00
Vincent Rabaud
f2fe8decce Bump fuzztest dependency.
Also do not restrict the oss-fuzz script to libfuzzer:
this allows new fuzzer engines to try the script as is.
The libfuzzer restriction is done upstream anyway.

Bug: oss-fuzz:69508
Change-Id: I15685bc7193bef3b9ccb0e0a30a6262e7bfb6fb9
2024-06-21 18:27:37 +02:00
Vincent Rabaud
9ce982fdf2 Fix fuzz tests to work on oss-fuzz
- the tests now build/run/check_build with libfuzzer on oss-fuzz
- centipede is removed as it builds/runs but do not check_build
(timeout due to arguments not parsed correctly)

Bug: oss-fuzz:69508

Change-Id: Id063565fc4cce02fc5e36c7d8499d6de9ff54345
2024-06-20 15:09:57 +02:00
Vincent Rabaud
3ba8af1a33 Do not escape quotes anymore in build.sh
cat is used now, not an echo of a "".

Change-Id: I36036ff2110f94a99bf1581c6c0d30326161314b
2024-06-11 13:35:44 +02:00
Vincent Rabaud
ea0e121b6a Allow centipede to be used as a fuzzing engine.
fuzztest is compatible with libfuzzer in compatibility mode, and
fully compatible with centipede by default.

Change-Id: I0c8e636df642dede16d394d678008c5e064094b3
2024-06-10 18:13:37 +02:00
James Zern
27731afd47 make VP8I4ModeOffsets & VP8MakeIntra4Preds static
These are unused outside of quant_enc.c.

Change-Id: I2c5cd0df28c25f279cd05667b327fea14f3fa50e
2024-06-06 19:07:48 -07:00
James Zern
ddd6245eb7 oss-fuzz/build.sh: use heredoc for script creation
Rather than a quoted multi-line echo.

Change-Id: Ib51fa5693f2946e2bc991dc66a6b3449e6ee61c0
2024-06-06 10:31:33 -07:00
James Zern
50074930e3 oss-fuzz/build.sh,cosmetics: fix indent
Change-Id: I1b9ddb5a531fc829fc7374ecefe31a38ac27e02c
2024-06-06 10:28:13 -07:00
Vincent Rabaud
20e92f7d40 Limit the possible fuzz engines.
Change-Id: I8f2fd84bc7175e4e74c4fb418fcc4f5549018ac3
2024-06-06 13:21:09 +02:00
Vincent Rabaud
4f200de591 Switch public fuzz tests to fuzztest.
Change-Id: I75afb65058690585bbf2671c27d6a99a87bcaab7
2024-06-05 14:08:27 +02:00
wrv
64186bb36c Add huffman_fuzzer to .gitignore
Change-Id: I1ec33a29beb1a9111e57c85ef67e4c4616908c56
2024-06-01 10:21:54 -05:00
Vincent Rabaud
0905f61c85 Move build script from oss-fuzz repo to here.
This requires a change in the oss-fuzz repo similar to
https://github.com/AOMediaCodec/libavif/blob/main/tests/oss-fuzz/build.sh

Change-Id: I7bcdb52dcec7e6edd926aea93988cd758ef9a854
2024-05-31 22:02:17 +02:00
wrv
e86787586b Fix link to Javascript documentation
Change-Id: Ia65d307570a3dff1fc6894abb42dfaaaaa74f086
2024-05-30 17:06:57 -05:00
wrv
5e5b8f0c95 Fix SSE2 Transform_AC3 function name
Change-Id: I5fda3221612beafc3548d2abfa7c1e3f686aaaf0
2024-05-29 21:41:14 -05:00
James Zern
45129ee027 Revert "Check all the rows."
This reverts commit ee26766a89a149afe5f73fdcb8f2493ec808f2b7.

This change also reverts the parent.

Revert "Increase the transform bits if possible."

This reverts commit 7ec51c591608333fd5e6fdddbee16e1d65bef3db.

These changes result in non-lossless encodes.

Bug: oss-fuzz:69231, oss-fuzz:69109, oss-fuzz:69208
Bug: b:341475869, b:342743143
Change-Id: Ia28f558992e0aa6f024af1ff66da52e0a5e26fa3
2024-05-25 11:00:32 -07:00
Vincent Rabaud
ee26766a89 Check all the rows.
A 3 by 1 image would not have its 1st and 3rd lines compared at
the second iteration.

BUG=oss-fuzz:69208

Change-Id: I9213e73995d31907f358310a0b7d5ebb21c1f8b2
2024-05-24 23:11:20 +02:00
Vincent Rabaud
7ec51c5916 Increase the transform bits if possible.
This brings minor size improvements because repetitive values in
the transform images are easily explainable through LZ77. Still,
it makes an upcoming pull request a bit more stable.

This is 971a03d8204c3ab1e12db8ae68ba6f919c615ade with a fix to
not forget to analyze the end of the line.
A const has also been added to match VP8LColorSpaceTransform's
signature.

Change-Id: Iae03216fef298c7abc96a766f8a799552b05ade5
2024-05-23 14:04:34 +02:00
James Zern
3cd16fd3e2 Revert "Increase the transform bits if possible."
This reverts commit 971a03d8204c3ab1e12db8ae68ba6f919c615ade.

Reason for revert:
This creates non-lossless encodes.

Original change's description:
> Increase the transform bits if possible.
>
> This brings minor size improvements because repetitive values in
> the transform images are easily explainable through LZ77. Still,
> it makes an upcoming pull request a bit more stable.
>
> Change-Id: I1c7135675cb59b5e27ca960738d74465f10d0deb

Bug: oss-fuzz:69109, b:341475869
Change-Id: I3b9f21a5498735eb3681e62fb35bf9f9c2ed4f9f
2024-05-20 22:25:57 +00:00
Vincent Rabaud
971a03d820 Increase the transform bits if possible.
This brings minor size improvements because repetitive values in
the transform images are easily explainable through LZ77. Still,
it makes an upcoming pull request a bit more stable.

Change-Id: I1c7135675cb59b5e27ca960738d74465f10d0deb
2024-05-17 15:19:03 +02:00
Vincent Rabaud
1bf198a22b Allow transform_bits to be different during encoding.
The spec allows it but it is currently forced to the same value for simplicity.

Change-Id: I26197dbf3342f7a72115cc7f7805c154313a2afb
2024-05-13 16:56:19 +02:00
Vincent Rabaud
1e462ca80e Define MAX_TRANSFORM_BITS according to the specification.
Change-Id: I0d575aa84e143bea56b55deb8f42b44e13dd5f1e
2024-05-07 09:16:02 +02:00
Vincent Rabaud
64d1ec23ac Use (MIN/NUM)_(TRANSFORM/HUFFMAN)_BITS where appropriate
Change-Id: I849ff8864f7abcc723dfe2b7ee0f290c8ee89c3f
2024-05-06 22:46:44 +02:00
Vincent Rabaud
a90160e11a Refactor histograms in predictors.
Replace the 2d histograms with uint32_t 1d versions (to avoid
pointer casting and to use the optimized VP8LAddVectorEq).

Change-Id: I90b0fe98390b49e3fd03e3484289571cf7ae6eca
2024-05-03 22:09:38 +02:00
Vincent Rabaud
a7aa7525b8 Fix some function declarations
- fix some function declarations to match the implementation
- fix some consts

Change-Id: I8c89f49ec68d3dd1db7f8ee5cac73777f52d2576
2024-05-03 20:10:46 +02:00
James Zern
68ff4e1efe Merge "jpegdec: add a hint for EOF/READ errors" into main 2024-05-02 20:53:54 +00:00
James Zern
79e7968ad0 jpegdec: add a hint for EOF/READ errors
`jpegtran -copy all` may be able to process the file into something
libjpeg can read.

Bug: webp:562
Change-Id: I27a8a7a841c1d8d54f47c7c52e289d9d8c549220
2024-05-01 12:32:47 -07:00
James Zern
d33455cd31 man/*: s/BUGS/REPORTING BUGS/
BUGS is described by the man-pages man page as:
A list of limitations, known defects or inconveniences, and other
questionable activities.

Change-Id: I2781d48d7a01c173fd24ac0b60af1a84aec31c3b
2024-05-01 10:39:00 -07:00
James Zern
a67ff735a2 normalize example exit status
Use EXIT_SUCCESS / EXIT_FAILURE in most cases as more granularity isn't
useful. For anim_diff, use 0 (success), 1 (image difference) and 2
(error) to align it with other diff utilities (diff, etc.).

Bug: webp:637
Change-Id: I52925de8622a5a4d2141883279d69a1d95ef9b12
2024-05-01 10:38:44 -07:00
James Zern
edc289092a upsampling_{neon,sse41}: fix int sanitizer warning
fixes warnings of the form:
/src/dsp/upsampling_sse41.c:170:1: runtime error: implicit conversion
  from type 'int' of value -16 (32-bit, signed) to type 'uintptr_t' (aka
  'unsigned long') changed the value to 18446744073709551600 (64-bit,
  unsigned)

this is the same change as was done previously in upsampling_sse2.c:
2ee786c7 upsampling_sse2.c: clear int sanitizer warnings

Change-Id: I36064d837ad1a7a118918c16a5551fc732dec2ff
2024-04-30 13:06:09 -07:00
James Zern
3cada4cef4 ImgIoUtilReadFile: check ftell() return
This avoids attempting to allocate 0 bytes if the call fails. (An
additional byte is added to the result to allow a '\0' to be appended.)

Bug: chromium:334120888
Change-Id: Ifcb8ff7744c567cbd08051aa04cc66acf936078d
2024-04-19 12:50:01 -07:00
James Zern
dc9505855e libwebp-1.4.0
- 4/12/2024: version 1.4.0
   This is a binary compatible release.
   * API changes:
     - libwebpmux: WebPAnimEncoderSetChunk, WebPAnimEncoderGetChunk,
                   WebPAnimEncoderDeleteChunk
     - libsharpyuv: SharpYuvOptionsInit, SharpYuvConvertWithOptions
     - extras: SharpYuvEstimate420Risk
   * further security related hardening in libwebp & examples
   * some minor optimizations in the lossless encoder
   * added WEBP_NODISCARD to report unused result warnings; enable with
     -DWEBP_ENABLE_NODISCARD=1
   * improvements and corrections in webp-container-spec.txt and
     webp-lossless-bitstream-spec.txt (#611)
   * miscellaneous warning, bug & build fixes (#615, #619, #632, #635)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEaw5rcJdt4wPt8vYB+cPWvbgjK10FAmYZ5dsACgkQ+cPWvbgj
 K11+Lg//cTnfLXYUZYI3coork1BG6E+r3bCvF6oncgdyOpQGM/7dExsPM43dBHBp
 uMHqapnxECSaga3g05+13R0ouhS72j3cuWBVkwmhrad7nxX7SGrCHIhaauJEAuyh
 ZX/MuMWVynAw9aq4UyCSLEfJ8bzRn/BmBb87zY8yBQP5fxUjGZ/hzRw4+pEoy9XU
 FA6QHv28agiswM111iOwIHQcAsKlUKy7SyULjFV40Q+wkF3tWTkOA9ecnsjXdDAU
 q3x06lZ4StvjyD7xwoxLL7E+sUAl0DcTluP1IMfmhzXOIl80OR0ec5qzGthaHSQZ
 ReDd9F0YqrEQOj371KkBg1d+VyBmwQoqh6vzKiEfqcm+wSDEd5WoOk7FmDbUlwmx
 EyRWrlxrmF7MsvjPYfQxxYfMcojewoVFFm43xgGO7pYg1b8yGEZ69So/3NWBqv6x
 ANXJCIcLHikz2u+v4n5A6eg6mFSW3pdPq8HpELTmefveXfIAGoA/6zcACqfNN+sO
 bt4lh7fUHTTFJmW5EJYkZmY725eY0nH7IQc0Jpc0iKMgtISTg2bxGHFeCB+GUTd0
 BCKBCCeIHIP7n7HnFGfGkNeas70QkN5lG5kDSLw4KR0TT1/We2MVZEsWeFPhQeYq
 myrMjhSOBn2sPKtknCL9WilQtBdLDPFBUIB3yHVXcP+HGCs8d/w=
 =+gXF
 -----END PGP SIGNATURE-----

Merge tag 'v1.4.0'

libwebp-1.4.0

- 4/12/2024: version 1.4.0
  This is a binary compatible release.
  * API changes:
    - libwebpmux: WebPAnimEncoderSetChunk, WebPAnimEncoderGetChunk,
                  WebPAnimEncoderDeleteChunk
    - libsharpyuv: SharpYuvOptionsInit, SharpYuvConvertWithOptions
    - extras: SharpYuvEstimate420Risk
  * further security related hardening in libwebp & examples
  * some minor optimizations in the lossless encoder
  * added WEBP_NODISCARD to report unused result warnings; enable with
    -DWEBP_ENABLE_NODISCARD=1
  * improvements and corrections in webp-container-spec.txt and
    webp-lossless-bitstream-spec.txt (#611)
  * miscellaneous warning, bug & build fixes (#615, #619, #632, #635)

Bug: webp:627

* tag 'v1.4.0':
  update ChangeLog
  update NEWS
  provide a way to opt-out/override WEBP_NODISCARD
  update ChangeLog
  NEWS: fix date
  vwebp: fix window title when options are given
  update NEWS
  bump version to 1.4.0
  update AUTHORS

Change-Id: Ib09dee63d968b50166c9177f571d68082e50ca76
2024-04-12 19:05:47 -07:00
James Zern
845d5476a8 update ChangeLog
Bug: webp:627
Change-Id: I67a011b62087a8ad64df3b5eb0a1c051adeea60f
2024-04-12 13:48:48 -07:00
James Zern
8a6a55bba8 update NEWS
add a note about WEBP_NODISCARD / WEBP_ENABLE_NODISCARD

Bug: webp:627
Change-Id: I018848eaef33dd47b922d6c95fc2842248cc02df
2024-04-12 12:34:22 -07:00
James Zern
cf7c5a5de8 provide a way to opt-out/override WEBP_NODISCARD
Bug: webp:627
Change-Id: I95ef89f37e5b7bf0f806bcfc6a295f5168b1bf67
2024-04-11 12:34:46 -07:00
James Zern
cc34288aa3 update ChangeLog
Bug: webm:627
Change-Id: I63243ecb39aa73a04d06426828e10d3e419922f6
2024-04-02 18:25:23 -07:00
James Zern
f13c08868a NEWS: fix date
Bug: webp:627
Change-Id: Ia3c620c2a0857e32ed9d85f08a0ef3caeddf6796
2024-04-02 17:41:32 -07:00
James Zern
7455595072 Merge "vwebp: fix window title when options are given" into 1.4.0 2024-04-02 16:56:08 +00:00
James Zern
d781646c29 vwebp: fix window title when options are given
Options can precede the file name. This still won't be correct for
Unicode file names, but an approximation will be displayed (with '?'s)
rather than the first character if kParams.file_name were used.
glutCreateWindow() looks like it will prohibit correcting this as it
expects an ASCII string.

Change-Id: I96986a178a0bbce6971d2ac415222d4a456ce1a3
2024-04-01 19:34:17 -07:00
James Zern
c2e394de91 update NEWS
Bug: webp:627
Change-Id: I7deea5d982ea9967c4be6b945452b9361e02eb85
2024-04-01 15:46:40 -07:00
James Zern
f6d15cb747 bump version to 1.4.0
libwebp{,decoder} - 1.4.0
libwebp libtool - 8.9.1
libwebpdecoder libtool - 4.9.1

mux - 1.4.0
libtool - 4.0.1

demux - 1.4.0
libtool - 2.15.0

sharpyuv - 0.4.0
libtool - 1.0.1

Bug: webp:627
Change-Id: I9a61d83ee92809de1c2501d1b4fb68aa38f98850
2024-04-01 15:37:40 -07:00
James Zern
57c388b8ff update AUTHORS
Bug: webp:627
Change-Id: I517fdc5201a8a44f1cdc64ef16f68e0ed9677937
2024-04-01 15:37:40 -07:00
James Zern
b3d1b2cbf7 Merge changes I26f4aa22,I83386b6c,I320ed1a2 into main
* changes:
  webp_js/*.html: fix canvas mapping
  cmake,wasm: simplify SDL2 related flags
  cmake: fix vwebp_sdl compile w/libsdl-org release
2024-04-01 20:19:51 +00:00
James Zern
07216886a7 webp-container-spec: fix VP8 chunk ref ('VP8'->'VP8 ')
Change-Id: Iad8317660c6be7c8044421d7517c95c5034609d7
2024-03-29 19:28:52 -07:00
James Zern
f88666eb47 webp_js/*.html: fix canvas mapping
after:
24d7f9cb Switch code to SDL2.

fixes:
webp_wasm.js:1 Uncaught TypeError: Cannot read properties of null
    (reading 'addEventListener')
    at Object.registerOrRemoveHandler (webp_wasm.js:1:101330)
    at registerMouseEventCallback (webp_wasm.js:1:154227)
    at _emscripten_set_mousemove_callback_on_thread (webp_wasm.js:1:155015)
    ...

The SDL2 port forces the canvas id to '#canvas':
324df6865a/src/video/emscripten/SDL_emscriptenvideo.c (L210)

This change maps '#output_canvas' to this entry in specialHTMLTargets[]:
https://emscripten.org/docs/api_reference/html5.h.html

https://github.com/libsdl-org/SDL/issues/5260 &
https://github.com/emscripten-ports/SDL2/issues/130 may also be related.

Change-Id: I26f4aa22b9d68b0fc45b83edfe6fe074b59a82a7
Test: emscripten 3.1.16
2024-03-29 12:53:05 -07:00
James Zern
e2c8f233ef cmake,wasm: simplify SDL2 related flags
Use the result of find_package(SDL2); the cmake module is available
prior to downloading the port. Previously the result of this call was
ignored. This also updates the flags to use the results of
SDL2_LIBRARIES which may be more future proof than specifying them
manually.

SDL2_INCLUDE_DIRS do not appear to be necessary with -sUSE_SDL2.

Based in part on:
d0b3e8efe3/ports/libwebp/0008-sdl.patch

Bug: b:301040580
Change-Id: I83386b6c3d9628e3f0d9d17f20d47338d0db044a
2024-03-28 19:23:51 -07:00
James Zern
d537cd3704 cmake: fix vwebp_sdl compile w/libsdl-org release
Prebuilt SDL2 releases from https://github.com/libsdl-org/SDL/releases
provide include/SDL.h. Test for this and set WEBP_HAVE_JUST_SDL_H
accordingly.

This was inspired by:
d0b3e8efe3/ports/libwebp/0008-sdl.patch

Bug: b:301040580
Change-Id: I320ed1a23352fc4035d491399fdba184dc927554
Test: cmake .. -DCMAKE_PREFIX_PATH=<path-to-sdl2>/cmake
2024-03-28 14:11:46 -07:00
James Zern
6c484cbf92 CMakeLists.txt: add missing WEBP_BUILD_EXTRAS check
And include directories to imageenc/imagedec. This fixes the build with
`-DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF
-DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF
-DWEBP_BUILD_IMG2WEBP=OFF -DWEBP_BUILD_LIBWEBPMUX=OFF
-DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF
-DWEBP_BUILD_WEBPMUX=OFF` and image dependencies outside of default
include locations (e.g., /usr/include).

Patch from:
d0b3e8efe3/ports/libwebp/0010-fix_build.patch

Bug: b:301040580
Change-Id: I2b9ad81dfe52316b102ca46ab8c60c42de3c0000
2024-03-27 18:55:20 -07:00
James Zern
7b0bc2352b man/cwebp.1: add more detail to -partition_limit
-m and -q can also affect the encoder's ability to satisfy the
partition limit.

Bug: webp:634
Change-Id: I89ea2b037c0cf1e109c251f45c09378ce501862b
2024-03-26 13:00:35 -07:00
James Zern
3c0011bbd1 WebPMuxGetChunk: add an assert
assert idx != IDX_LAST_CHUNK to quiet a static analysis warning
(reported by Coverity):
  overrun-local: Overrunning array kChunks of 11 12-byte elements at
    element index 11 (byte offset 143) using index idx (which evaluates
    to 11).

Change-Id: I85ae159e338d5670c007f76277ffe94e7a1dcafc
2024-03-21 18:32:55 -07:00
James Zern
955a3d14ae Merge "muxread,MuxGet: add an assert" into main 2024-03-22 01:01:04 +00:00
James Zern
00abc0007c muxread,MuxGet: add an assert
assert idx != IDX_LAST_CHUNK to quiet a static analysis warning
(reported by Coverity):
  Indexing array kChunks of size 11 with idx.

Change-Id: I5e54b5c09d23c26abbd1a7919b6f828b35fe4f75
2024-03-20 12:36:37 -07:00
Vincent Rabaud
40e85a0b56 Have the window title reflect the filename.
This is from https://github.com/webmproject/libwebp/pull/3

Change-Id: Ia54f9b6a2ac0d078e931c088694924ed914c18fd
2024-03-20 14:33:54 +01:00
James Zern
1bf46358c4 man/cwebp.1: clarify -pass > 1 behavior w/o -size/-psnr
A PSNR value of 40dB will be used in this case.

Bug: webp:635
Change-Id: I74964a08a1f0a6b92ecfa482753a171ce6f3ae18
2024-03-14 19:34:39 -07:00
James Zern
eba03acb05 webp-container-spec: replace 'above' with 'earlier'
https://developers.google.com/style/word-list#above

Change-Id: Ib20395c00289d0e37f532b383dec0bf14d4bec73
2024-03-12 16:22:31 -07:00
James Zern
a16d30cb57 webp-container-spec: clarify chunk order requirements
based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_robert-wilton

Change-Id: If2cd956b607c51b714e82e8eee7a1c4375c3c632
2024-03-11 14:01:40 -07:00
James Zern
8a7e911231 Merge "CMakeLists.txt: apply cmake-format" into main 2024-03-07 19:21:20 +00:00
Vincent Rabaud
7fac6c1bf2 Merge "Copy C code to not have multiplication overflow" into main 2024-03-07 12:14:57 +00:00
Vincent Rabaud
e2922e4390 Merge "Check for the presence of the ANDROID_ABI variable" into main 2024-03-07 08:54:42 +00:00
Vincent Rabaud
501d9274a7 Copy C code to not have multiplication overflow
Change-Id: I9375170ce1217921a334c5b93dc3e0084f976688
2024-03-07 09:22:20 +01:00
James Zern
fba7d62ee5 CMakeLists.txt: apply cmake-format
Change-Id: I23b848d6936e5dd3b6a56f1e3218da5ed6f2539b
2024-03-06 15:56:36 -08:00
James Zern
661c1b6641 Merge "windows exports: use dllexport attribute, instead of visibility." into main 2024-03-06 23:54:57 +00:00
Ozkan Sezer
8487860a8c windows exports: use dllexport attribute, instead of visibility.
With older toolchains, at the least, visibility attributes don't
work and all symbols are exported along with lots of unsupported
warnings.

Change-Id: I6ffe220b7589a6bda00f42c17ead35592de7cc5a
2024-03-07 01:14:37 +03:00
James Zern
8ea678b990 webp/mux.h: data lifetime note w/copy_data=0
The data mostly must persist until a call to Assemble() is made. If the
data is discarded and subsequent calls are made the behavior is
undefined.

Change-Id: I64b39034ae4663e9ca25b85040b6068d09dfac04
2024-03-06 11:11:24 -08:00
Vincent Rabaud
79e05c7f9f Check for the presence of the ANDROID_ABI variable
BUG=webp:632

Change-Id: I8169be37d7b739b206ffb6555d58ff79a34c3605
2024-03-06 14:50:30 +01:00
natewood
45f995a37e Expose functions for managing non-image chunks on WebPAnimEncoder
Change-Id: Ie6376267eee6df3517417b6cadafcdf6112bd854
2024-02-27 16:55:24 -08:00
James Zern
1fb9f3dcf1 gifdec: fix ErrorGIFNotAvailable() declaration
A void parameter list should be (void), not (). Fixes a
-Wstrict-prototypes warning.

Change-Id: I180efbf7c58956695359320072cce1171d79e377
2024-02-22 13:58:19 -08:00
James Zern
4723db65bc cosmetics: s/SANITY_CHECK/DCHECK/
'sanity' is not an inclusive term. This is a debug check so DCHECK
better shows the intent.

https://source.android.com/docs/setup/contribute/respectful-code

Change-Id: I4cdad3ef9ddf0404d26e46b8430e3ad1d715c5b2
2024-02-16 11:57:16 -08:00
James Zern
f4b9bc9ea1 clear -Wextra-semi-stmt warnings
This is available with clang. Clears warnings of the form:
  warning: empty expression statement has no effect; remove unnecessary
    ';' to silence this warning [-Wextra-semi-stmt]

As a side-effect it also clear a few -Wpedantic warnings with gcc:
  warning: ISO C does not allow extra ';' outside of a function
    [-Wpedantic]

Change-Id: I9295c767aad475c68b1fbbdff855b0d6650a25f5
2024-02-15 18:55:22 -08:00
Yannis Guyon
713982b883 Limit animdecoder_fuzzer to 320MB
Change-Id: Ic139ea870b98c58a2ecf46e81844f647fa0d2aba
2024-02-15 10:16:54 +00:00
Ozkan Sezer
cbe825e4cc cmake: fix sharpyuv simd files' build
Without this, when targeting x86, the compiler may not enable sse2
by default without -msse2 switch and therefore leaves WEBP_USE_SSE2
undefined and the SSE2 procedure won't be built.

Change-Id: If983df5cd12c962cf153094468fb549ec3f2c89b
2024-02-10 00:58:20 +03:00
James Zern
f99305e9e5 Makefile.vc: add ARM64 support
This enables the executables and the correct flags, it's a full desktop
platform. This is different from the old Windows mobile ARM target.

Change-Id: I610d1579e5dac7b0a6a50ab9194a5f1fef2fc907
2024-01-31 14:12:03 -08:00
James Zern
5efd6300dc mv SharpYuvEstimate420Risk to extras/
There's no need for this in libsharpyuv currently. This avoids an ABI
bump and library size increase.

Change-Id: I3e4c79052fdb4d628a2d36491547233dd0b6dc34
2024-01-12 15:25:27 -08:00
James Zern
e78e924f84 Makefile.vc: add sharpyuv_risk_table.obj
missed in:
d7a0506d Add YUV420 riskiness metric.

Change-Id: I5c3cfeaf6757792ac97902f587e04bf95fd4c5a1
2023-12-21 15:43:17 -08:00
Maryla
d7a0506dcc Add YUV420 riskiness metric.
Basic version for 8 bit only and C only (no simd).

Hidden behind a compile flag because the precompiled table is
fairly large (114kiB) and more than triples the size of the library.

Change-Id: I165c78e863df6a17b32f578bdbffe3adda9ac1d0
2023-12-05 10:17:15 +01:00
Vincent Rabaud
89c5b91746 Merge "BuildHuffmanTable check sorted[] array bounds before writing" into main 2023-11-22 15:45:18 +00:00
Vincent Rabaud
34c8074915 Remove alpha encoding pessimization.
This was created to have outputs readable with libwebp 0.4.x
Jelly-Bean and Kit-Kat are not supported anymore:
https://android-developers.googleblog.com/2021/07/google-play-services-discontinuing-jelly-bean.html
https://android-developers.googleblog.com/2023/07/google-play-services-discontinuing-updates-for-kitkat.html

Change-Id: I0b9ff3091412ce12eb50da301d7dacace9b54cc3
2023-11-14 14:18:12 +01:00
Vincent Rabaud
13d9c30b2b Add a WEBP_NODISCARD
Change-Id: Ice66f2aa6358474d728fb19c571edc86ed139a49
2023-11-10 13:57:07 +01:00
Vincent Rabaud
24d7f9cb6e Switch code to SDL2.
Also simplify wasm html (now that it is suppported by all browsers).

Change-Id: I352b08594b93d3dd7d44832d4328b3546ccc1b90
2023-10-28 23:36:35 +02:00
Jonathan Grant
0b56dedc98 BuildHuffmanTable check sorted[] array bounds before writing
Change-Id: I6a83f414e86311121451e9da26004dfc3ac9b21f
2023-10-27 00:17:27 +01:00
James Zern
a429c0de64 sharpyuv: convert some for() to do/while
With loops that don't use an immediate value in the conditional, this
can produce fewer tests.

Change-Id: I75401c51f7f7653be2f8c04d5f3c4ce04aefc3fc
2023-10-25 12:25:16 -07:00
James Zern
f0cd786125 DoSharpArgbToYuv: remove constant from loop
pre-calculating rgb_bit_depth + GetPrecisionShift(rgb_bit_depth)
produces better assembly with clang.

Change-Id: Ic4c3a620c1634fb5ea7001fa709d28c547769f79
2023-10-25 12:25:12 -07:00
James Zern
339231cc37 SharpYuvConvertWithOptions,cosmetics: fix formatting
Change-Id: Ieffe5877c6d715d168b0e9526d8fa1a946860771
2023-10-25 12:25:08 -07:00
Arthur Eubanks
307071f144 Remove medium/large code model-specific inline asm
Initially added to workaround gcc implementation issues that clang
does not have. (gcc hardcodes rbx as the PIC register, clang uses a
virtual register)

Change-Id: I1a3277abf02b1ff437b4aea4d28f4cb1c0176b80
2023-10-24 09:48:12 +02:00
Maryla
deadc339d5 Fix transfer functions where toGamma and toLinear are swapped.
Change-Id: I2f7ef84d227009181dad1c17883741bd98bf92b6
2023-10-12 16:57:32 +02:00
Maryla Ustarroz-Calonge
e7b78d4375 Merge "Fix bug in FromLinearLog100." into main 2023-10-12 08:28:34 +00:00
James Zern
15a1309efc Merge "webp-lossless-bitstream-spec: delete extra blank line" into main 2023-10-11 18:31:37 +00:00
Maryla
54ca975245 Fix bug in FromLinearLog100.
Change-Id: Iddfa7d16fe44e375a93deae9636eadc8bef42767
2023-10-11 15:08:24 +02:00
Vincent Rabaud
d2cb2d8cfc Dereference after NULL check.
Change-Id: Ia592affff075b2e00c150b89febcf676c7dcbbd2
2023-10-11 14:21:54 +02:00
James Zern
e9d5010718 webp-lossless-bitstream-spec: delete extra blank line
This clears a lint warning.

Change-Id: I87926cb6e2448332d7bbf7a3fe064e7aaf791a72
2023-10-10 15:55:16 -07:00
James Zern
786579711f Merge changes Ief442c90,Ie6e9c9a5 into main
* changes:
  webp-lossless-bitstream-spec: update variable names
  webp-lossless-bitstream-spec: simplify abstract
2023-10-10 18:16:58 +00:00
James Zern
e30a588456 webp-lossless-bitstream-spec: update variable names
This syncs the document with the draft RFC.

block_xsize -> transform_width
i -> distance_code
x/ysize -> image_width/height

Change-Id: Ief442c90157e82c518e8cb175a522c519b16ac69
2023-10-09 21:24:01 -07:00
James Zern
09ca136801 Merge "webp-container-spec: change assert to MUST be TRUE" into main 2023-10-10 00:26:53 +00:00
James Zern
38cb4fc0ea iosbuild,xcframeworkbuild: add SharpYuv framework
Provides the missing symbols in WebP.framework & WebP.xcframework:
Undefined symbols for architecture arm64:
  "_SharpYuvConvert", referenced from:
      _ImportYUVAFromRGBA in libwebp.a(libwebpencode_la-picture_csp_enc.o)
  "_SharpYuvGetConversionMatrix", referenced from:
      _ImportYUVAFromRGBA in libwebp.a(libwebpencode_la-picture_csp_enc.o)
  "_SharpYuvInit", referenced from:
      _ImportYUVAFromRGBA in libwebp.a(libwebpencode_la-picture_csp_enc.o)

This was missed in:
  c3d0c2d7 fix ios build scripts after sharpyuv dep added

Bug: webp:623
Change-Id: I1c4582ec2cee801b52867674d553900d6028bea8
Fixed: webp:623
2023-10-06 18:41:03 -07:00
James Zern
40afa9269b webp-lossless-bitstream-spec: simplify abstract
This syncs the document with the draft RFC.

Change-Id: Ie6e9c9a50527378cb1b24e2c130a0a09855fe96e
2023-10-06 11:46:24 -07:00
James Zern
9db21143d0 webp-container-spec: change assert to MUST be TRUE
in the 'Canvas Assembly from Frames' section. This matches the format in
the RFC draft; assert was not defined

Change-Id: Ib943b42f75fd1b4c281848f14e0626df9c868f59
2023-10-06 11:33:23 -07:00
Anuraag Agrawal
cdbf88aed2 Fix typo in API docs for incremental decoding
Change-Id: I410450a9d2c5192086da9fceaeaabefb7b0f5e57
2023-10-02 10:51:49 +02:00
Vincent Rabaud
05c469843c Reformat vcpkg build instructions.
Change-Id: I2ca7bd2feb85103c2377cc48daf3453dc5d859e4
2023-09-20 13:03:30 +02:00
Vincent Rabaud
8534f53960 Merge "Never send VP8_STATUS_SUSPENDED back in non-incremental." into main 2023-09-19 09:23:01 +00:00
Vincent Rabaud
35e197bdb7 Never send VP8_STATUS_SUSPENDED back in non-incremental.
Add the incremental_ member to the internal VP8Decoder,
to mimic VP8LDecoder

Change-Id: I34842e473bb566f51c18fe42afda63e66c0185b6
2023-09-19 10:28:02 +02:00
Jonliu1993
61441425fe Add vcpkg installation instructions
Change-Id: Id6396a9c31cb47bb7b1d743da7d5554505cd81a8
2023-09-15 13:59:30 +02:00
Masahiro Hanada
dce8397fec Fix next is invalid pointer when WebPSafeMalloc fails
When WebPSafeMalloc fails on VP8LHuffmanTablesAllocate,
next is not initialized to NULL.
VP8LHuffmanTablesDeallocate uses next to know the following nodes.
A patch fixes this issue.

Change-Id: I144ae84cd97e5bca227018ef1afa95361267902c
2023-09-15 13:59:30 +02:00
Frank
57c58105f3 Cmake: wrong public macro WEBP_INCLUDE_DIRS
Change-Id: I2220e5a094fe7ca6274e654bcedb6cca194663eb
2023-09-15 13:59:30 +02:00
Vincent Rabaud
c1ffd9ac75 Merge "vp8l_enc: fix non-C90 code" into main 2023-09-15 06:45:52 +00:00
Vincent Rabaud
a3965948e0 Merge changes If628bb93,Ic79f6309,I45f0db23 into main
* changes:
  Update lossless spec for two simple codes.
  Fix non-C90 code.
  Fix static analyzer warnings.
2023-09-15 06:44:42 +00:00
James Zern
f80e9b7e4c vp8l_enc: fix non-C90 code
Change-Id: I14b5288c1b9392dcb64db09b9852f1d7d47b3200
2023-09-14 16:21:04 -07:00
Vincent Rabaud
accd141da3 Update lossless spec for two simple codes.
Bug: webp:611
Change-Id: If628bb9332ebca6dd11b3561c3458e0f43ed54a3
2023-09-14 22:43:45 +02:00
Vincent Rabaud
ac17ffffcb Fix non-C90 code.
Thank you OpenCV: https://github.com/opencv/opencv/blob/
1e54e5657927996e86b155d89f51c7b5a73461d2/3rdparty/libwebp/
CMakeLists.txt#L24

Change-Id: Ic79f6309951f96c380e44b3167c1a36aae6d8903
2023-09-14 22:43:45 +02:00
Vincent Rabaud
433c7dca11 Fix static analyzer warnings.
Change-Id: I45f0db2310b1188809963af93240e3d438f807b8
2023-09-14 22:43:45 +02:00
James Zern
5fac76cf8d libwebp-1.3.2
- 9/13/2023: version 1.3.2
   This is a binary compatible release.
   * security fix for lossless decoder (chromium: #1479274, CVE-2023-4863)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEaw5rcJdt4wPt8vYB+cPWvbgjK10FAmUCZrcACgkQ+cPWvbgj
 K12xQBAAoR6PIMHsttDUvgrCmgM19HbDVYmN3fK1VSL2yhT2Nj71hloIBQ46j+pJ
 aLyOhLX92yvvDEORDvm12LO7e7VwbPxc66Lwh5q0AjgsliMD1sR0yFJHVnZTOrJ/
 ndF0G1dNkrwYYYLWPIDtxrfr2eyB0+el8zjUCkWuKn5WSeaiV3FNfjHmNjQsgf1K
 dyy4DHcmZb5N2eJ6OvsiGvp7JwOjTpoHmYB2TbqfzqbV3Wq/aWgLsuGffpcNiEgP
 i/GCTapAFTdYW7StqXUGWML0IV3E3CrcBYjlWJqR499/DTfX1jrNcyWbuR0iaM9e
 yKlYS4PeylB6xdyEGVNM+8j3Trt3YYxvTGO/ydh9D4CtjaJPzlLfs2646AaV6TFW
 34t9mUDm1ZqQP8yJNqpSF00iwH0LA5/dKTd9Xr/MSifB/nvF3aqQjEDHLeTgD6pS
 D0Kf6OkhBtRuDbw7bTMwTGOZ5Z/VLG9JFni9JPt/KylBANUXQAI8vn0jjZRmpAki
 ketic0AgoDtH1TmPA+AzbiPWxKuFHfH3CpoECsgbpJjuMjbJ7EuXDfiG6cUIqTrD
 Lk+r1jgkCTWikB0KnGxDaNnDx+U0iatH4XfuAqp0o3pEHdgH0p4Gk3Kb8oraSZNv
 Y9AM9TaUaGPZxdyXfyR8glvHSu3li15DF1l1Ewml9qSxuqs/4Ls=
 =Rv7k
 -----END PGP SIGNATURE-----

Merge tag 'v1.3.2'

libwebp-1.3.2

- 9/13/2023: version 1.3.2
  This is a binary compatible release.
  * security fix for lossless decoder (chromium: #1479274, CVE-2023-4863)

* tag 'v1.3.2':
  update ChangeLog
  update NEWS
  bump version to 1.3.2
  Fix OOB write in BuildHuffmanTable.

Bug: webp:620
Change-Id: I094a4fe6ab4f3f8ada6fb662ba9cc6ec0f3bdd87
2023-09-13 19:08:16 -07:00
James Zern
ca332209cb update ChangeLog
Bug: webp:620
Change-Id: I5703f222de7262736339dbfd6ba82f2039dfc850
2023-09-13 15:11:07 -07:00
James Zern
1ace578c91 update NEWS
Bug: webp:620
Change-Id: I393c58cc23ccf98fa3c5d1568f0689a36e64575b
2023-09-13 13:33:58 -07:00
James Zern
63234c4296 bump version to 1.3.2
libwebp{,decoder} - 1.3.2
libwebp libtool - 8.8.1
libwebpdecoder libtool - 4.8.1

mux - 1.3.2
libtool - 3.13.0

demux - 1.3.2
libtool - 2.14.0

sharpyuv - 0.2.1 (no change)
libtool - 0.1.0 (no change)

Bug: webp:620
Change-Id: I9a61d83ee92809de1c2501d1b4fb68aa38f98850
2023-09-13 13:24:49 -07:00
Vincent Rabaud
a35ea50de4 Add a fuzzer for ReadHuffmanCodes
Change-Id: If8c30aaa87c34007ae455a03daa7b3c0f22fc8c3
2023-09-12 23:41:29 +02:00
Vincent Rabaud
95ea5226c8 Fix invalid incremental decoding check.
The first condition is only necessary if we have not read enough
(enough being defined by src_last, not src_end which is the end
of the image).
The second condition now fits the comment below: "if not
incremental, and we are past the end of buffer".

BUG=oss-fuzz:62136

Change-Id: I0700f67c62db8e1c02c2e429a069a71e606a5e4f
2023-09-12 09:22:53 +02:00
Vincent Rabaud
2af26267cd Fix OOB write in BuildHuffmanTable.
First, BuildHuffmanTable is called to check if the data is valid.
If it is and the table is not big enough, more memory is allocated.

This will make sure that valid (but unoptimized because of unbalanced
codes) streams are still decodable.

Bug: chromium:1479274
Change-Id: I31c36dbf3aa78d35ecf38706b50464fd3d375741
(cherry picked from commit 902bc9190331343b2017211debcec8d2ab87e17a)
2023-09-07 15:14:39 -07:00
Vincent Rabaud
902bc91903 Fix OOB write in BuildHuffmanTable.
First, BuildHuffmanTable is called to check if the data is valid.
If it is and the table is not big enough, more memory is allocated.

This will make sure that valid (but unoptimized because of unbalanced
codes) streams are still decodable.

Bug: chromium:1479274
Change-Id: I31c36dbf3aa78d35ecf38706b50464fd3d375741
2023-09-07 21:16:03 +02:00
Vincent Rabaud
7ba44f80f3 Homogenize "__asm__ volatile" vs "asm volatile"
According to https://gcc.gnu.org/onlinedocs/gcc/extensions-to-the-c-language-family/how-to-use-inline-assembly-language-in-c-code.html

For the C language, the asm keyword is a GNU extension. When
writing C code that can be compiled with -ansi and the -std options
that select C dialects without GNU extensions, use __asm__ instead
of asm (see Alternate Keywords). For the C++ language, asm is a
standard keyword, but __asm__ can be used for code compiled with
-fno-asm.

Change-Id: I4af950e67c857c890290c1e3d9cc886da0748784
2023-09-06 17:15:05 +02:00
James Zern
68e271354e webp-container-spec: reorder example chunk layout
place the unknown 'XYZW' chunk at the end of the file to agree with the
order given by the 'Extended File Format' section.

Change-Id: I5cec5a61069a03f3487f5f9ff9209f5ead6de24c
2023-09-01 15:00:53 -07:00
James Zern
943b932a7e Merge changes I6a4d0a04,Ibc37b91e into main
* changes:
  decode.h: wrap idec example in /* */
  decode.h: fix decode example
2023-08-18 00:38:04 +00:00
James Zern
1cc94f9521 decode.h: wrap idec example in /* */
This makes it easier to read and copy/paste, though this is just rough
pseudo-code. It also matches the formatting of the advanced decoder
example.

Change-Id: I6a4d0a04a12bfc1f1956ac965ff4869cefc4f3df
2023-08-15 19:11:50 -07:00
James Zern
63acdd1e06 decode.h: fix decode example
spotted by tsutsui123 at gmail

Bug: webp:615
Change-Id: Ibc37b91e85427b2424b698043a40cce98bae356d
Fixed: webp:615
2023-08-15 19:07:11 -07:00
James Zern
aac5c5d0df ReadHuffmanCode: rm redundant num code lengths check
4 bits are read ([0, 15]) with 4 added to the result. The check that the
result is not > NUM_CODE_LENGTH_CODES (19) is redundant. This makes the
check an assert for documentation purposes.

webp-lossless-bitstream-spec.txt is updated accordingly.

Bug: webp:611
Change-Id: Ie461017dc9de3da4cfe6856543d3dcf58f53a180
2023-08-14 18:07:17 -07:00
James Zern
a2de25f6b6 webp-lossless-bitstream-spec: normalize list item case
In Section 6.2 Details, use uppercase after a :. This is more consistent
with the rest of the doc.

Bug: webp:611
Change-Id: I7ac862c90fd8e5fe0bad0dd5e3515d3095a6dc9a
2023-08-14 17:38:06 -07:00
James Zern
68820f0e53 webp-lossless-bitstream-spec: normalize pixel ref
x, y -> (x, y)

Bug: webp:611
Change-Id: Ic25ae76a9978156e7cd67ad17432ee1a1e172641
2023-08-14 17:38:03 -07:00
James Zern
cdb31aa806 webp-lossless-bitstream-spec: add missing periods
in ordered list in "6.2. Details". This is more consistent with the rest
of the document.

Bug: webp:611
Change-Id: Ie467c771afd5813a30855b24c80cf92673a5281c
2023-08-14 17:37:57 -07:00
James Zern
0535a8cf88 webp-lossless-bitstream-spec: fix grammar
...in same row... -> in the same row

Bug: webp:611
Change-Id: I837ab571084b206cc1a57c534c05cdcd0dfff0fa
2023-08-14 17:37:39 -07:00
James Zern
b6c4ce2635 normalize numbered list item format
from edits made during the RFC AUTH48 process

Change-Id: I82a5d78c0ea611e71927ffb13aa78ccdddfd6dd0
2023-08-09 13:51:38 -07:00
James Zern
dd7364c3ce Merge "palette.c: fix msvc warnings" into main 2023-07-28 20:05:58 +00:00
James Zern
c63c5df618 palette.c: fix msvc warnings
after:
1432ebba Refactor palette sorting computation.

fixes:
src\utils\palette.c(384): warning C4028: formal parameter 2 different
  from declaration
src\utils\palette.c(384): warning C4028: formal parameter 3 different
  from declaration
src\utils\palette.c(384): warning C4028: formal parameter 5 different
  from declaration

Change-Id: If29205f346e674108646045b7a3d90f078fed9b0
2023-07-28 09:07:11 -07:00
James Zern
0a2cad5115 webp-container-spec: move terms from intro section
to 'Terminology & Basics'

Change-Id: Iec9923086a2d339f12025c55da53b1e8a6919380
2023-07-27 16:18:57 -07:00
James Zern
dd88d2ff3e webp-lossless-bitstream-spec: color_cache -> color cache
The text is referring to the color cache, not a variable.

Bug: webp:611
Change-Id: Ife7e8246817ea0831993702bc050ed79998a0ee4
2023-07-27 12:41:04 -07:00
James Zern
6e75054736 Merge changes I644d7d39,Icf05491e,Ic02e6652,I63b11258 into main
* changes:
  webp-lossless-bitstream-spec: fix code blocks
  webp-lossless-bitstream-spec: block -> chunk
  webp-lossless-bitstream-spec: add some missing commas
  webp-lossless-bitstream-spec: normalize item text in 5.1
2023-07-27 19:34:20 +00:00
James Zern
67a7cc2b07 webp-lossless-bitstream-spec: fix code blocks
+ change "> 19" to "greater than 19" as it's referred to in prose

Bug: webp:611
Change-Id: I644d7d39f9c4a19050ff0256114873057aee95ef
2023-07-26 09:42:00 -07:00
Vincent Rabaud
1432ebbadb Refactor palette sorting computation.
This will ease the integration of new methods.

Change-Id: Icec3eddaa4ab9030d28ccfe579eb6dc13ded2f02
2023-07-26 10:25:14 +02:00
James Zern
cd436142f6 webp-lossless-bitstream-spec: block -> chunk
when referring to the RIFF chunk size; this is more consistent with
other documentation.

Bug: webp:611
Change-Id: Icf05491ee79f5c48fab0b4935da397b4e4e45a71
2023-07-25 22:10:06 -07:00
James Zern
3cb66f64b0 webp-lossless-bitstream-spec: add some missing commas
The serial comma change is based on the Chicago Manual of Style
(CMOS), 17th edition.

Bug: webp:611
Change-Id: Ic02e6652662608414c16e0fead2912781a47633d
2023-07-25 22:09:59 -07:00
James Zern
56471a53cf webp-lossless-bitstream-spec: normalize item text in 5.1
Makes references to earlier sections consistent. Based on RFC editor
update.

Bug: webp:611
Change-Id: I63b1125810a3d8afa957d392e98c68a632749d76
2023-07-25 22:08:51 -07:00
James Zern
af7fbfd2d9 vp8l_dec,ReadTransform: improve error status reporting
ExpandColorMap() can fail due to a memory allocation failure.

Found by Nallocfuzz (https://github.com/catenacyber/nallocfuzz).

Change-Id: I868c5db2fee18e876f4aa3b63e744d7297d1a91b
2023-07-21 16:30:50 -07:00
James Zern
7d8e0896e9 vp8l_dec: add VP8LSetError()
similar to VP8SetError(); the first error set takes precedence

Change-Id: Id00eb134cac328f72142a2ec0909e72768a6be0e
2023-07-21 16:30:49 -07:00
James Zern
a71ce1cf74 animencoder_fuzzer: fix error check w/Nallocfuzz
WebPAnimEncoderAdd() may fail due to muxer errors that are reported as
booleans. When running under the nallocfuzz engine, ignore all failures.

Found by Nallocfuzz (https://github.com/catenacyber/nallocfuzz).

Change-Id: I36589545d20ac30a67f7e09264146db085dee6ca
2023-07-21 16:30:48 -07:00
James Zern
e94b36d66d webp-lossless-bitstream-spec: relocate details from 5.1
Move the details given for meta prefix codes and the transforms from
"5.1. Roles of Image Data" to their corresponding sections.

Bug: webp:611
Change-Id: I750a3f45956d0a3928a22113180a2590ac1a36db
2023-07-21 15:50:38 -07:00
James Zern
84628e5611 webp-lossless-bitstream-spec: clarify image width changes
After processing the Color Indexing Transform the image width is
subsampled by the transform's width_bits.

Bug: webp:611
Change-Id: If8d2d47dbe05e5c8085fb3fb4c1b63552be9028b
2023-07-20 17:54:20 -07:00
James Zern
ee72299796 alpha_dec: add missing VP8SetError()
in AllocateAlphaPlane() and VP8DecompressAlphaRows().

Found by Nallocfuzz (https://github.com/catenacyber/nallocfuzz).

Change-Id: I39eb305abfe9f4d7915cce5d91e72917f482bc20
2023-07-18 16:25:29 -07:00
James Zern
0081693d61 enc_dec_fuzzer: use WebPDecode()
rather than WebPDecodeRGBA(). This allows finer grained error detection
and avoids an abort() when running under the nallocfuzz engine.

Change-Id: I8ff37f2fe7e1c8b39bd4a8bfe7b26ac41149ba42
2023-07-18 16:24:11 -07:00
James Zern
0fcb311cfc enc_dec_fuzzer: fix WebPEncode/pic.error_code check
pic.error_code may be set to VP8_ENC_ERROR_BAD_WRITE if the writer fails
due to a memory allocation failure.

Found by Nallocfuzz (https://github.com/catenacyber/nallocfuzz).

Change-Id: I912c9e5f9a37b78832c52d9ab6f0710967fbadac
2023-07-18 16:24:09 -07:00
James Zern
982c177c8a webp-lossless-bitstream-spec: fix struct member refs
remove trailing '_' to match the definition of ColorTransformElement

Bug: webp:611
Change-Id: I741213b389fc88473c72c64090a4733f51d87925
2023-07-14 15:13:27 -07:00
James Zern
56cf562570 webp-lossless-bitstream-spec: use RFC 7405 for ABNF
This allows for case sensitive literals.

Bug: webp:611
Change-Id: I5258c67ab12c48593d433449328fd85d461a05d2
2023-07-14 15:13:27 -07:00
James Zern
6c6b3fd317 webp-lossless-bitstream-spec,cosmetics: delete blank lines
This normalizes the spacing between sections and quiets some lint
warnings.

Bug: webp:611
Change-Id: Ic36eb08d55a566def74f746e2ec225c67ff8aecf
2023-07-14 15:12:35 -07:00
James Zern
29b9eb1517 Merge changes Id56ca4fd,I662bd1d7 into main
* changes:
  webp-lossless-bitstream-spec: add validity note for max_symbol
  webp-lossless-bitstream-spec: fix max_symbol definition
2023-07-13 20:43:51 +00:00
James Zern
47c0af8daf ReadHuffmanCodes: rm max_alphabet_size calc
This is unnecessary as green will have the largest value; the sizes are
currently: 256 + 24 + color_cache_size, 256, 40, in that order.

Change-Id: Ib9ce3292285a7b9c6089557b68a87184b68d17a5
2023-07-12 12:04:57 -07:00
James Zern
b92deba353 animencoder_fuzzer: no WebPAnimEncoderAssemble check w/nallocfuzz
This function may fail due to allocation failures. Use the
NALLOC_FUZZ_VERSION environment variable to detect the engine. This was
added in:
9c9a9883cc

Change-Id: Ia5b6fd9458ffa1f810152a10ab49a48c75d17687
2023-07-10 15:10:00 -07:00
James Zern
6be9bf8bae animencoder_fuzzer: fix leak on alloc failure
Change-Id: Id626145a336fc33c4a4158719957f3c96db156c8
2023-07-10 15:09:17 -07:00
James Zern
5c965e55dd vp8l_dec,cosmetics: add some /*param=*/ comments
Change-Id: I8912a5d8a8f550517e644e1af6b468b49505247f
2023-07-07 19:57:47 -07:00
James Zern
e4fc2f78c7 webp-lossless-bitstream-spec: add validity note for max_symbol
Bug: webp:611
Change-Id: Id56ca4fd0ad3cfc17c9c971281ccfb8ce7eaa2f4
2023-07-07 15:54:34 -07:00
James Zern
71916726b6 webp-lossless-bitstream-spec: fix max_symbol definition
If ReadBits(0) == 0, the value of max_symbol is set to the alphabet size
for each symbol type.

See vp8l_dec.c, ReadHuffmanCode(), which passes alphabet_size to
ReadHuffmanCodeLengths() as num_symbols, and ReadHuffmanCodeLengths()
then sets max_symbol to that.

Bug: webp:611
Change-Id: I662bd1d7f372e7f2e9c71cc86f87aefd02f36647
2023-07-07 15:54:34 -07:00
Vincent Rabaud
eac3bd5c53 Have the palette code be in its own file.
Change-Id: I099a342effedd9f451c94d00a14aead27079e6cc
2023-07-06 22:09:24 +02:00
Vincent Rabaud
e2c85878f6 Add an initializer for the SharpYuvOptions struct.
Change-Id: I36510bc361b040d3d3e7d261ab67b24ffc3013a6
2023-07-01 21:15:37 +02:00
James Zern
4222b00679 libwebp-1.3.1
- 6/23/2023: version 1.3.1
   This is a binary compatible release.
   * security fixes for lossless encoder (#603, chromium: #1420107, #1455619,
     CVE-2023-1999)
   * improve error reporting through WebPPicture error codes
   * fix upsampling for RGB565 and RGBA4444 in NEON builds
   * img2webp: add -sharp_yuv & -near_lossless
   * Windows builds:
     - fix compatibility with clang-cl (#607)
     - improve Arm64 performance with cl.exe
     - add Arm64EC support
   * fix webp_js with emcc >= 3.1.27 (stack size change, #614)
   * CMake fixes (#592, #610, #612)
   * further updates to the container and lossless bitstream docs (#581, #611)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEaw5rcJdt4wPt8vYB+cPWvbgjK10FAmSc53oACgkQ+cPWvbgj
 K120Fg//f0JkK3oKnO8P4B5XSAK26/5845xBPU8D06UuUqhct+mjfF5kM1CFxxex
 49W4rT7RJCpgGlwmRFFgRB3a9j7cW4C+Kt5MAfM++vudVrxnpnX6o3rdVDQ60PEZ
 C4T5u2jio/HuZAkPWYwwmIAz1vfqTjYpi0D12hn7yoBoketGcISlMuTgmwfjyQKg
 bn3JcjcjKtERfXSH36aCtnGAXJdf0Ok2WJtwS4kAcZiMByi5wf0AdEK0pnhmE3Y6
 YFPc0/RM50RXITnsDxmLZVRqpsAYr4l3RZvHwDDWVFMELWBsGWNF/kgzWlZ3/KjO
 4CUPE+810P4oVGJuRZ8++0hMSD0L1qh17awElpqLoBlDXfS1fEIw5QodbmoJzi0H
 mhiLH7fIZlpjoZyWuwNCzlkhykRLO4cEIaxxq28p5eoC70LXsv77rWqomfAja/6/
 88BQz6wrxHr0k4MmdOa+G8B5sMOBRVXXeW4bP1XCVGUfk8FN2rz0vlhbHk8sx/6/
 jqW19Bk3t2QnUZschBi1GKHKa0KkefFhTezTm/CV4fPmT50Z4k/+TTjJ6snSxAAX
 oYabJDtVARLgPxOcN64Hbsy1t5L9pWGLTfwbYBTVipX4lmofL9SHhgyg6oYVnZd5
 qbCVdqpYOOrbXXT/AByOuzo3tuaLMd8Ytas0I5/HHnI6QCTthg0=
 =/atT
 -----END PGP SIGNATURE-----

Merge tag 'v1.3.1'

libwebp-1.3.1

- 6/23/2023: version 1.3.1
  This is a binary compatible release.
  * security fixes for lossless encoder (#603, chromium: #1420107, #1455619,
    CVE-2023-1999)
  * improve error reporting through WebPPicture error codes
  * fix upsampling for RGB565 and RGBA4444 in NEON builds
  * img2webp: add -sharp_yuv & -near_lossless
  * Windows builds:
    - fix compatibility with clang-cl (#607)
    - improve Arm64 performance with cl.exe
    - add Arm64EC support
  * fix webp_js with emcc >= 3.1.27 (stack size change, #614)
  * CMake fixes (#592, #610, #612)
  * further updates to the container and lossless bitstream docs (#581, #611)

* tag 'v1.3.1':
  update ChangeLog
  update NEWS
  enc/*: normalize WebPEncodingSetError() calls
  enc/*: add missing WebPEncodingSetError() calls
  EncodeAlphaInternal: add missing error check
  vp8l_enc,WriteImage: add missing error check
  muxread,MuxImageParse: add missing error checks
  cmake,emscripten: explicitly set stack size
  WebPDecodeYUV: check u/v/stride/uv_stride ptrs
  Call png_get_channels() to see if image has alpha
  update ChangeLog
  update NEWS
  bump version to 1.3.1
  update AUTHORS
  update .mailmap

Bug: webp:608
Bug: b/281615350
Change-Id: Ic3e1956c92fef0ae22040bbc3e81b297c65008af
2023-06-28 19:34:13 -07:00
Vincent Rabaud
25d94f473b Implement more transfer functions in libsharpyuv
This is inspired by https://github.com/AOMediaCodec/libavif/pull/444/files

Change-Id: I98fae61696b3b8bbc1b5941e7950810d3ac3d588
2023-06-28 11:43:37 +02:00
James Zern
2153a6797c Merge changes Id0300937,I5dba5ccf,I57bb68e0,I2dba7b4e,I172aca36, ... into main
* changes:
  webp-lossless-bitstream-spec: add PredictorTransformOutput
  webp-lossless-bitstream-spec: fix RIFF-header ABNF
  webp-lossless-bitstream-spec: split LZ77 Backward Ref section
  webp-lossless-bitstream-spec: split Meta Prefix Codes section
  webp-lossless-bitstream-spec: note transform order
  webp-lossless-bitstream-spec: update transformations text
2023-06-27 21:56:43 +00:00
James Zern
4298e9765c webp-lossless-bitstream-spec: add PredictorTransformOutput
Describe the addition of the residual value to the predicted value.

Bug: webp:611
Change-Id: Id0300937eeebbafec3b2cd15376c56418c98a3bf
2023-06-26 12:51:36 -07:00
James Zern
cd7e02bece webp-lossless-bitstream-spec: fix RIFF-header ABNF
0x2f is a part of the image header, not RIFF header

Bug: webp:611
Change-Id: I5dba5ccfebeb25586723a1f3e00eebc317806928
2023-06-26 12:51:36 -07:00
James Zern
6c3845f9e0 webp-lossless-bitstream-spec: split LZ77 Backward Ref section
Make Distance Mapping its section for ease of reference.

Bug: webp:611
Change-Id: I57bb68e0fcf4d23ce0013f327adce93c6377be3a
2023-06-26 12:51:36 -07:00
James Zern
7f1b6799db webp-lossless-bitstream-spec: split Meta Prefix Codes section
Make Entropy Image and Interpretation of Meta Prefix Codes their own
section for ease of reference.

Bug: webp:611
Change-Id: I2dba7b4efd02d8bb250810ebff42ac1687262804
2023-06-26 12:51:36 -07:00
James Zern
7b634d8f0c webp-lossless-bitstream-spec: note transform order
transforms are applied in reverse bitstream order.

Bug: webp:611
Change-Id: I172aca36bbd5c3358a71b0acb49c5704ceee63d7
2023-06-26 12:51:36 -07:00
James Zern
6d6d4915ce webp-lossless-bitstream-spec: update transformations text
follow up to:
29c9f2d4 webp-lossless-bitstream-spec: minor wording updates

Universally use 'transform' over 'transformation'. The doc generally
uses 'transform' to talk about the individual transforms themselves as
well as their related data.

Bug: webp:611
Change-Id: I097701873bbc440bd399ab5440a914a14f7c62f6
2023-06-26 12:50:39 -07:00
James Zern
fd7bb21c0c update ChangeLog
Bug: webp:608
Change-Id: Id619a5e39a71d1372fd2209774f4f57d87712aa7
2023-06-23 11:52:38 -07:00
James Zern
e1adea50ed update NEWS
Bug: webp:608
Change-Id: I8c09742daa8502e7a1fdc626afa3b747e03569bf
2023-06-23 10:16:35 -07:00
James Zern
6b1c722a5b lossless_common.h,cosmetics: fix a typo
Change-Id: I22d2f96fa1fd2e3c9f059c26996fb11d998159a9
2023-06-22 18:31:36 -07:00
James Zern
08d60d6006 webp-lossless-bitstream-spec: split code length section
Make Simple / Normal Code Length Code their own section for ease of
reference.

Bug: webp:611
Change-Id: I1e6ed50d98f9258cacb163d2059716b5356e8b6f
2023-06-21 19:20:12 -07:00
James Zern
7a12afcc54 webp-lossless-bitstream-spec: rm unused anchor
The last use of #decoding-the-code-lengths was removed in:
86f94ee0 Update lossless spec with Huffman codes.

Also remove the redundant section header associated with it.

Bug: webp:611
Change-Id: I7f6bb1a1b75255324f185f4591313d9e6d49d1e9
2023-06-21 19:16:39 -07:00
James Zern
4339332038 enc/*: normalize WebPEncodingSetError() calls
return WebPEncodingSetError() directly where possible (it returns 0 /
failure for convenience).

Change-Id: I89a937778886c15ecbbe078af5b4c8c89ef0f9af
2023-06-21 16:43:00 -07:00
James Zern
287fdefe95 enc/*: add missing WebPEncodingSetError() calls
Users of the encoder (including anim_encode.c) and areas of the encoder
itself rely on the status returned via WebPPicture.

Change-Id: Id786176b8ac3b2329d1e41b9dacbb8dcc5d822e4
2023-06-21 16:43:00 -07:00
James Zern
c3bd7cff2e EncodeAlphaInternal: add missing error check
VP8LBitWriterFinish() may cause the VP8LBitWriter's buffer to be grown.
If that allocation fails, VP8LBitWriterNumBytes() will return a size
larger than the current allocation resulting in a heap overwrite of the
missing bytes.

==13==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x61900005b880 at pc 0x00000049ffc1 bp 0x7fff144f5b40 sp 0x7fff144f5310
READ of size 1028 at 0x61900005b880 thread T0
    #0 0x49ffc0 in __asan_memcpy
    #1 0x695861 in VP8BitWriterAppend src/utils/bit_writer_utils.c:186:3
    #2 0x65acf9 in EncodeAlphaInternal src/enc/alpha_enc.c:169:14

Found by Nallocfuzz (https://github.com/catenacyber/nallocfuzz).

This is the same issue that was fixed in the non-alpha lossless path in:
d49cfbb3 vp8l_enc,WriteImage: add missing error check

Bug: chromium:1455619
Change-Id: I6bd10de213707d3d6b7ce3d0d2b3942af45d317f
2023-06-21 16:43:00 -07:00
James Zern
14a9dbfba0 webp-lossless-bitstream-spec: refine single node text
Remove the ambiguous 'should' which in other contexts might result in
questions as to whether it is a SHOULD or a MUST.

Change-Id: I9b396187ebde5ea5a0dbaf42daee6acf541258cd
2023-06-20 19:30:20 -07:00
Vincent Rabaud
64819c7cf3 Implement ExtractGreen_SSE2
Change-Id: I74f50e0c01603a640aa8cf7c9658d477e696ea8a
2023-06-19 13:31:46 +02:00
James Zern
d49cfbb348 vp8l_enc,WriteImage: add missing error check
VP8LBitWriterFinish() may cause the VP8LBitWriter's buffer to be grown.
If that allocation fails, VP8LBitWriterNumBytes() will return a size
larger than the current allocation resulting in a heap overwrite of the
missing bytes.

==3531848==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x61d000000880 at pc 0x556eddfa1007 bp 0x7ffe434c7a90 sp 0x7ffe434c7260
READ of size 2052 at 0x61d000000880 thread T0
    #0 0x556eddfa1006 in __asan_memcpy
    #1 0x556eddfeeccf in WebPMemoryWrite src/enc/picture_enc.c:220:5
    #2 0x556ede0f9f87 in WriteImage src/enc/vp8l_enc.c:1454:8

Found by Nallocfuzz (https://github.com/catenacyber/nallocfuzz).

Change-Id: Ib1c9454c2c51849b0ba58c5347e6bd5b02a12fbe
2023-06-15 15:09:10 -07:00
James Zern
2e5a9ec3b6 muxread,MuxImageParse: add missing error checks
This prevents leaks should an allocation fail.

Spotted by Philippe Antoine (p dot antoine at catenacyber dot fr)
and https://github.com/catenacyber/nallocfuzz.

Change-Id: I07a8a475a282b18bf2f9015cc5b1120772babd48
2023-06-14 13:53:59 -07:00
James Zern
ebb6f949f4 cmake,emscripten: explicitly set stack size
The default was changed from 5MB to 64KB in 3.1.27 [1] causing image
decodes to fail. This restores the old default. In testing, 1536KB was
enough for the sample image, 1024KB was not.

[1]: https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md#3127---112922

Bug: webp:614
Change-Id: I1ff7afc72fa49d88d2efe88d2a04dfadbea3b1a5
Fixed: webp:614
Test: emcc 3.1.18 & 3.1.41
2023-06-13 21:47:52 -07:00
James Zern
59a2b1f9e3 WebPDecodeYUV: check u/v/stride/uv_stride ptrs
The buffers are made mandatory to match WebPDecodeYUVInto(), though this
conflicts with WebPIDecGetYUVA().

spotted by Oliver Kunz (okunz at google dot com)

Change-Id: Ic4740c53b75da6b93d4f3462303fb9be0ebfbd48
2023-06-13 17:39:45 -07:00
Wan-Teh Chang
8e965ccb0f Call png_get_channels() to see if image has alpha
After the png_read_update_info() call, call png_get_channels() to find
out if the image has alpha.

Change-Id: I6fa709418744b4de90d10ff96eaeefe454ffa290
2023-06-13 17:35:31 -07:00
James Zern
fe80fbbd6b webp-container-spec: add some missing commas
The serial comma change is based on the Chicago Manual of Style
(CMOS), 17th edition.

Change-Id: I642d6eb87492bb671869b25415c59b96b749c798
2023-06-12 22:03:01 -07:00
Pascal Massimino
e8ed317609 Merge "treat FILTER_NONE as a regular Unfilter[] call" into main 2023-06-12 14:19:04 +00:00
James Zern
03a7a04892 webp-lossless-bitstream-spec: rm redundant statement
Within the 'Entropy image' subsection, its clear this is what is being
described in the following paragraphs. Remove 'as described below' from
the first sentence.

Bug: webp:611
Change-Id: I365d69c8f6963cd826849ebdd96e46206d38b55d
2023-06-08 11:22:10 -07:00
James Zern
c437c7aace webp-lossless-bitstream-spec: mv up prefix code group def
Move this to the top-level of the "Details" section as prefix codes are
discussed in both "Decoding and Building the Prefix Codes" and "Decoding
of Meta Prefix Codes"

Bug: webp:611
Change-Id: Ide2dfedf081d6c94122ac16ecded968ed760f90c
2023-06-08 11:22:10 -07:00
James Zern
e4f17a31a7 webp-lossless-bitstream-spec: fix section reference
in the Transformations section describing decoding of the transform
data followed by the image data. The section numbers were adjusted by 1
in:
337cf69f webp-lossless-bitstream-spec: mv Nomenclature after Intro

Bug: webp:611
Change-Id: I4eede0d068fabdef51a140a0268436ab6629e8bb
2023-06-08 11:22:10 -07:00
James Zern
e2ecd5e937 webp-lossless-bitstream-spec: clarify ABNF syntax
Give some examples of repetition and binary value notation to limit the
need to follow the ABNF reference.

Bug: webp:611
Change-Id: I5b5a7632f011e1523b4a528653fe3630afba3e3e
2023-06-08 11:22:10 -07:00
James Zern
8b55425a56 webp-lossless-bitstream-spec: refine pixel copy text
in 6.2.3 Decoding Entropy-Coded Image Data.

The copying of distance code pixels cause some confusion during the
AUTH48 portion of the RFC review process.

Bug: webp:611
Change-Id: I78f547ae10c95f180355a4c93ec6d48acdc09141
2023-06-08 11:22:10 -07:00
James Zern
29c9f2d410 webp-lossless-bitstream-spec: minor wording updates
Mostly grammatical and addition/subtraction of commas from the AUTH48
portion of the RFC review process.

The serial comma changes are based on the Chicago Manual of Style
(CMOS), 17th edition.

Bug: webp:611
Change-Id: I5ae2d1cc0196009dbf3a4c2195cc73c2ef809b49
2023-06-08 11:21:55 -07:00
skal
6b02f66015 treat FILTER_NONE as a regular Unfilter[] call
Removes the hard-coded memcpy() in alpha-decoding.

Change-Id: I1dfd98db206893d7715a79d05a1bd9272690471a
2023-06-07 15:42:16 +02:00
James Zern
7f75c91ced webp-container-spec: fix location of informative msg
preprocessing bits are informative, not the filtering bits.

since:
391f9db9 Ordering of description of bits in container spec

Change-Id: I1c0da963074ce9cf4d33a13b4b36c9421b3e3b9d
2023-06-06 22:09:41 -07:00
James Zern
f6499943c4 webp-container-spec: consistently quote FourCCs
from the AUTH48 portion of the RFC review process

Change-Id: I3aad4b32c95517735e98ffa0120228ee24be6a4d
2023-06-06 18:47:20 -07:00
James Zern
49918af32b webp-container-spec: minor wording updates
Mostly grammatical and addition/subtraction of commas from the AUTH48
portion of the RFC review process.

The serial comma changes are based on the Chicago Manual of Style
(CMOS), 17th edition.

Change-Id: Ic75abf2e53e09c8a849e28e9c40e16c127515287
2023-06-05 18:26:34 -07:00
James Zern
7f0a341943 update ChangeLog
Bug: webp:608
Change-Id: Ic2188807076eee4c311ea20b999ba66265df9003
2023-06-02 09:37:51 -07:00
James Zern
bab7efbe73 update NEWS
Bug: webp:608
Change-Id: I96245759d1f0d7ccb42de47e10e18677a509feaa
2023-06-02 09:31:46 -07:00
James Zern
7138bf8fc3 bump version to 1.3.1
libwebp{,decoder} - 1.3.1
libwebp libtool - 8.7.1
libwebpdecoder libtool - 4.7.1

mux - 1.3.1
libtool - 3.12.0

demux - 1.3.1
libtool - 2.13.0

sharpyuv - 0.2.1
libtool - 0.1.0

Bug: webp:608
Change-Id: Ia80c54651a45caa1baa595f66820a3c1091d05c4
2023-06-01 18:56:12 -07:00
James Zern
435b4ded42 update AUTHORS
Bug: webp:608
Change-Id: I84f5ea6a9de352cfb216198aee9f6fd204cd1c46
2023-06-01 17:13:22 -07:00
James Zern
473512298a update .mailmap
Bug: webp:608
Change-Id: Ib7d6fd5d9537770f7e4c6a3290a5071f617f9b91
2023-06-01 17:13:21 -07:00
Vincent Rabaud
46bc4fc9d9 Merge "Switch ExtraCost to ints and implement it in SSE." into main 2023-06-01 11:05:12 +00:00
Vincent Rabaud
828b4ce062 Switch ExtraCost to ints and implement it in SSE.
The histograms count the occurrences of len/dist in entropy images.
Those (at most (1<<14) by (1<<14)) are sub-sampled by at least
MIN_HUFFMAN_BITS == 2, hence at most 24 bits in a histogram value.
At most, we multiply by 19 (because the longest histogram is of
size 40 and we do 40>>1, cf code) for the bit cost. So it all fits
in 32 bits.

Change-Id: Ife24b035f54794851ff31f2fac07901f724c6d7f
2023-06-01 10:17:13 +02:00
James Zern
ff6c7f4e71 CONTRIBUTING.md: add C style / cmake-format notes
Change-Id: I54ad0e27341025a6385a736d5a79ab8b6556a6ec
2023-05-30 13:54:12 -07:00
James Zern
dd530437f6 add .cmake-format.py
Created with cmake-format 0.6.13 using:
--dump-config --max-subgroups-hwrap 3 --first-comment-is-literal true

Change-Id: Ica8ca81086dcf466d4ea9693ffcb4e31aa0af002
2023-05-30 13:54:06 -07:00
James Zern
adbe2cb17e cmake,cosmetics: apply cmake-format
using the defaults present in 0.6.13 and setting
--first-comment-is-literal to avoid reflowing the copyright block and
--max-subgroups-hwrap 3 (default is 2) to avoid making some short set()
statements multi-line.

Change-Id: I3d90c025b5b2bb353046f4da19b8e442a044b902
2023-05-30 12:14:28 -07:00
James Zern
15b365083d doc/webp-container-spec: rm future codec comment
From the compression standpoint the file format is fixed at this point.

Change-Id: I788fcf7106e4840bf2f9950dfb099a7bab88b3bf
2023-05-26 15:48:31 -07:00
James Zern
c369c4bf0b doc/webp-lossless-bitstream-spec: improve link text
Reference the section by number, rather than 'this section'. Fixes a
lint warning:

Style notice: Write unique, descriptive link text that makes sense
without the surrounding text. Don't use phrases such as this document,
this article, or click here.
https://developers.google.com/style/link-text?hl=en#write-link-text

Change-Id: Iab33e4980528dddb5eed4404d25a4a746705131a
2023-05-26 15:48:28 -07:00
James Zern
1de35f476b doc/webp-container-spec: don't use 'currently'
Provide examples of formats that WebP performs better than.

https://developers.google.com/style/timeless-documentation

Change-Id: I4ead60be349d8650478788484989bde9ff18f6b6
2023-05-26 15:48:26 -07:00
James Zern
bb06a16ed1 doc/webp-container-spec: prefer present tense
https://developers.google.com/style/tense

Change-Id: I0cd4e1431cddc340adf5634c07f0c60635b3d4f2
2023-05-26 15:48:23 -07:00
James Zern
9f38b71e01 doc/webp-lossless-bitstream-spec: prefer present tense
https://developers.google.com/style/tense

Change-Id: I1151ad0f585afd388920e6910a30aca4c2d0cc32
2023-05-26 15:48:17 -07:00
James Zern
7acb6b829a doc/webp-container-spec: avoid i.e. & e.g.
Using 'that is' or 'for example' is recommended:
https://developers.google.com/style/abbreviations#dont-use

Change-Id: I25b45f5b41687dfbd25a0fbea4978d6bc8e44ad2
2023-05-26 15:48:12 -07:00
James Zern
4967e7cd78 doc/webp-lossless-bitstream-spec: avoid i.e. & e.g.
Using 'that is' or 'for example' is recommended:
https://developers.google.com/style/abbreviations#dont-use

Change-Id: I5d0dad2ee7ae5ebaf73661d5d79a4a2f1dc1802a
2023-05-26 15:48:09 -07:00
Vincent Rabaud
e3366659a0 Merge "Do not find_package image libraries if not needed." into main 2023-05-26 20:55:09 +00:00
Jyrki Alakuijala
428588ef90 clarify single leaf node trees and use of canonical prefix coding
remove AMENDED-notes (the last functional spec change to match with the
implementation is from 2014, other amendments are clarifications)

Bug: webp:581
Change-Id: Ic47739be0fd5a975fd734d6813567ca615304f1d
2023-05-25 17:25:48 -07:00
Vincent Rabaud
709ec152df Do not find_package image libraries if not needed.
This can be tested by running:
cmake ../ -DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF -DWEBP_BUILD_EXTRAS=OFF

Bug: webp:612

Change-Id: Ie06d8f0535676d6d31ff0047ff7a6c026e16118e
2023-05-26 00:14:05 +02:00
James Zern
8dd80ef814 fuzz_utils.h: lower kFuzzPxLimit w/ASan
prevents some timeouts when decoding large jpeg source images.

Change-Id: I5cb6a10cbf0658a71fa9f49fc7da4c8d3e70fa00
2023-05-24 19:39:38 -07:00
Vincent Rabaud
8f187b9f7f Clean message calls in CMake
Change-Id: If1a959d9b8d544c9f4671c84880b1d0d11d3d285
2023-05-24 19:39:26 -07:00
James Zern
cba300781f WebPConfig.cmake.in: use calculated include path
when setting WebP_INCLUDE_DIRS; this value is relative to the
WebPConfig.cmake install location (${PACKAGE_PREFIX_DIR}/include) and
allows the install to be relocated after creation.

See also:
https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html#example-generating-package-files

Bug: webp:610
Change-Id: If877625e96584a9808b0bba902e3f0b2a744aa60
Fixed: webp:610
2023-05-16 17:39:50 -07:00
James Zern
6cf9a76ae2 Merge "webp-lossless-bitstream-spec: remove use of 'dynamics'" into main 2023-05-16 22:00:51 +00:00
James Zern
740943b276 Merge "Specialize and optimize ITransform_SSE2 using do_two" into main 2023-05-16 19:57:48 +00:00
Yannis Guyon
2d547e24dc Compare kFuzzPxLimit to max_num_operations
To avoid timeouts caused by extreme rescaling such as
1x14339 -> 51712x1

Change-Id: I291d8e3b24155c190256411a506b7312abde8c45
2023-05-16 13:20:14 +02:00
Nozomi Isozaki
ac42dde1c5 Specialize and optimize ITransform_SSE2 using do_two
Change-Id: I976eb4a0cc4e669a02b55012d4aba1536f193781
2023-05-16 12:07:58 +09:00
James Zern
17e0ef1da5 webp-lossless-bitstream-spec: remove use of 'dynamics'
when bit width or precision are meant.

Change-Id: I89c2279e99b02c3e8a3bf39860364d2ce6d909c8
2023-05-12 15:10:30 -07:00
James Zern
ed27437160 neon.h,cosmetics: clear a couple lint warnings
Missing space after ,  [whitespace/comma] [3]

Change-Id: Ib8fc05c31cbef5318a752e98ab5106dad55d69e9
2023-05-02 17:32:14 -07:00
James Zern
3fb8294762 cpu.h,cosmetics: segment defines
Change-Id: Idc6dcd31e95de1c89b2a35b4c67fa66b92fe1a60
2023-05-02 12:28:50 -07:00
James Zern
0c496a4ff9 cpu.h: add WEBP_AARCH64
and define it to true for __aarch64__ and Win Arm64 + Visual Studio.

Microsoft's compiler (cl.exe) does not define __aarch64__, but relies on
_M_ARM64 & _M_ARM64EC

Bug: b/277254922
Change-Id: I20e4fa07a4031599db69e3d7ba9050345315ef51
2023-05-02 12:28:50 -07:00
James Zern
8151f388eb move VP8GetCPUInfo declaration to cpu.c
This avoids defining a version in each translation unit when using
__declspec(dllexport) which causes failures due to multiply defined
symbols with clang-cl:

lld-link: error: duplicate symbol: VP8GetCPUInfo
>>> defined at CMakeFiles\webpdecode.dir\Debug\src\dec\alpha_dec.c.obj
>>> defined at CMakeFiles\webpdsp.dir\Debug\src\dsp\dec_sse41.c.obj
...

Bug: webp:607
Change-Id: I6cd1ee75b3db984aa513263a05516e867a64925d
2023-04-27 12:39:13 -07:00
Yannis Guyon
916548c28c Make kFuzzPxLimit sanitizer dependent
Change-Id: Ib70f3c05fc845494c45cb357e70e9602a7e876a3
2023-04-25 08:14:22 +02:00
James Zern
4070b271ab advanced_api_fuzzer: reduce scaling limit
avoids another timeout while fuzzing with ASan

Change-Id: Ic5dfed15347bdd36f42274b8b2a25aec79fd568c
2023-04-18 16:56:23 -07:00
James Zern
761f49c3ab Merge "webp-lossless-bitstream-spec: add missing bits to ABNF" into main 2023-04-13 20:53:32 +00:00
James Zern
84d04c4845 webp-lossless-bitstream-spec: add missing bits to ABNF
alpha-is-used and the version number were missing before 'image-stream'

spotted by thakis@

Change-Id: I7a4f1d2e0f0962bb1a79a0400c229738159d88a5
2023-04-13 12:13:34 -07:00
James Zern
0696e1a7fb advanced_api_fuzzer: reduce scaling limit
avoids another timeout while fuzzing with ASan

Change-Id: Icf7209f3f93b894684ac7364864e4568b6b2c057
2023-04-11 12:16:39 -07:00
James Zern
93d88aa25b Merge "deps.cmake: remove unneeded header checks" into main 2023-04-11 19:13:10 +00:00
James Zern
118e0035df deps.cmake: remove unneeded header checks
These were picked up when matching autoconf's default checks and aren't
useful except to compare the generated config.h. Removing them speeds up
cmake, especially on windows where creating new processes is slow.

Change-Id: Ie891aad0a809af16357168d2ff7fd65922ee4011
2023-04-11 11:37:24 -07:00
James Zern
4c3d7018c0 webp-lossless-bitstream-spec: condense normal-prefix-code
Have this match simple-prefix-code and redirect to "Normal Code Length
Code" as the added indirection to 'code-length-code' and the undefined
'encoded-code-lengths' doesn't add much.

spotted by thakis@

Change-Id: Icd6b64a47c4e0001e93271d9ae5585be4a6d5906
2023-04-10 17:22:55 -07:00
James Zern
a6a09b3296 webp-lossless-bitstream-spec: fix 2 code typos
- add missing '(' in DIV_ROUND_UP
- in 6.2.2, rename 'pos' variable reference to match definition
  ('position')

spotted by thakis@

Change-Id: Ida3ed281c2c753ebbb0e1eb3c4ed04dadc79ca24
2023-04-10 17:18:52 -07:00
James Zern
50ac4f7c97 Merge "cpu.h: enable NEON w/_M_ARM64EC" into main 2023-04-07 20:31:49 +00:00
Yannis Guyon
4b7d7b4f2b Add contribution instructions
Change-Id: Icc58ef6c1e79e59977e0093973ad353237560e8e
2023-04-07 15:10:16 +02:00
James Zern
0afbd97b45 cpu.h: enable NEON w/_M_ARM64EC
The Arm64EC (Emulation Compatible) ABI was added for Windows 11 [1].

[1] https://learn.microsoft.com/en-us/windows/arm/arm64ec

Bug: b/277254922
Change-Id: I3767e1b3db61fa9c33eef7a9ed7abee7c502e36f
2023-04-06 13:49:36 -07:00
James Zern
349f4353dd Merge changes Ibd89e56b,Ic57e7f84,I89096614 into main
* changes:
  advanced_api_fuzzer: reduce scaling limit
  Skip slow scaling in libwebp advanced_api_fuzzer
  Reduce libwebp advanced_api_fuzzer threshold
2023-03-25 01:50:02 +00:00
James Zern
8f7513b7c0 upsampling_neon.c: fix WEBP_SWAP_16BIT_CSP check
this is always defined by default to 0 since:
v0.6.0-158-g663a6d9d unify the ALTERNATE_CODE flag usage

previously the !defined() check would cause a mismatch between C and
assembly.

Change-Id: Idca0b8e39ca90d63785fd4125aeb7af86c5aae61
2023-03-24 11:20:35 -07:00
James Zern
cbf624b561 advanced_api_fuzzer: reduce scaling limit
avoids another timeout while fuzzing with ASan

Change-Id: Ibd89e56bf936aeea040cd4c47ccae20960417ac0
2023-03-24 10:52:46 -07:00
yguyon@google.com
89edfdd1e9 Skip slow scaling in libwebp advanced_api_fuzzer
Change-Id: Ic57e7f8418afec42f042197a401aaf4cc047b23f
2023-03-24 10:52:43 -07:00
yguyon@google.com
859f19f74f Reduce libwebp advanced_api_fuzzer threshold
To avoid timeouts.

Change-Id: I8909661479cdbcb940bb44c6f9130906cab3f271
2023-03-24 10:52:40 -07:00
James Zern
a4f0483579 Merge changes Ic389aaa2,I329ccd79 into main
* changes:
  img2webp: normalize help output
  cwebp: reflow -near_lossless help text
2023-03-20 19:46:23 +00:00
James Zern
1275fac820 Makefile.vc: fix img2webp link w/dynamic cfg
add a dependency on libsharpyuv, which is needed after:
0825faa4c img2webp: add -sharp_yuv/-near_lossless

Change-Id: I2471549aa85a4ead6e00d6c459d9774ea4254eaa
2023-03-18 13:58:21 -07:00
James Zern
2fe27bb96d img2webp: normalize help output
this makes the output from img2webp and the ordering in doc/tools.md and
man/img2webp.1 consistent

Change-Id: Ic389aaa29c20128f2b87f231be383094602f125b
2023-03-17 15:37:55 -07:00
James Zern
24bed3d9fb cwebp: reflow -near_lossless help text
this matches the output from img2webp added in:
0825faa4 img2webp: add -sharp_yuv/-near_lossless

Change-Id: I329ccd796d7e9bee36de1429fceafe83d7dc5532
2023-03-17 15:17:31 -07:00
jzern@google.com
0825faa4c1 img2webp: add -sharp_yuv/-near_lossless
Both are global settings. Modifying them at the frame level is left as a
follow up based on need.

Bug: b/272739498
Change-Id: If15256c052f73fe3df56be5e0095e76d9870cc0f
2023-03-17 09:35:29 -07:00
James Zern
d64e6d7d9d Merge "PaletteSortModifiedZeng: fix leak on error" into main 2023-02-28 00:23:05 +00:00
James Zern
0e12a22d88 Merge "EncodeAlphaInternal: clear result->bw on error" into main 2023-02-28 00:22:57 +00:00
James Zern
0edbb6ea71 PaletteSortModifiedZeng: fix leak on error
Change-Id: I462bd9a3bc4670efdf251c295f6771a38c08a6ce
2023-02-23 22:03:31 -08:00
James Zern
41ffe04e12 Merge "Update yapf style from "chromium" to "yapf"" into main 2023-02-24 01:29:40 +00:00
Thiago Perrotta
2d9d9265f5 Update yapf style from "chromium" to "yapf"
yapf v0.30.0 renamed "chromium" style to "yapf".

Bug: chromium:1306598
Change-Id: I2a637d2c5d64f81ba411b1c0d07339ad7480bd66
2023-02-23 18:10:53 -05:00
James Zern
a486d800b6 EncodeAlphaInternal: clear result->bw on error
This avoids a double free should the function fail prior to
VP8BitWriterInit() and a previous trial result's buffer carried over.
Previously in ApplyFiltersAndEncode() trial.bw (with a previous
iteration's buffer) would be freed, followed by best.bw pointing to the
same buffer.

Since:
187d379d add a fallback to ALPHA_NO_COMPRESSION

In addition, check the return value of VP8BitWriterInit() in this
function.

Bug: webp:603
Change-Id: Ic258381ee26c8c16bc211d157c8153831c8c6910
2023-02-22 22:23:41 -08:00
Yannis Guyon
1347a32d82 Skip big scaled advanced_api_fuzzer
To avoid timeouts.

Change-Id: I8f04fd45313bef47004a616d2460be992692030d
2023-02-08 10:53:40 +01:00
Yannis Guyon
52b6f06703 Fix scaling limit in advanced_api_fuzzer.c
config.options.scaled_width or config.options.scaled_height being 0
means a ratio-conservative scaling so 7361842 was not enough.

Change-Id: Ib75241eb683cf824bc46222c5c07535b6c6d7313
2023-02-07 18:05:42 +01:00
Yannis Guyon
7361842839 Limit scaling in libwebp advanced_api_fuzzer.c
Change-Id: Ic1e3fdc76f4bdcb1ac68cf4f9334d2e77ca29374
2023-01-27 14:39:14 +01:00
James Zern
b54d21a01d Merge "CMakeLists.txt: allow CMAKE_INSTALL_RPATH to be set empty" into main 2023-01-18 19:10:44 +00:00
James Zern
31c28db53c libwebp{,demux,mux}.pc.in: Requires -> Requires.private
The libraries don't expose the symbols in libsharpyuv / libwebp, they're
only needed when static linking.

Noted for libwebp (Requires: libsharpyuv) in:
https://crbug.com/webp/590#c5. libwebpdemux and libwebpmux had a similar
issue with libwebp.

See also:
https://web.archive.org/web/20190921014607/https://wiki.openmandriva.org/en/Overlinking_issues_in_packaging

Change-Id: Ia1866b6b44cbb1ef1a77fd45fbcf10c027eae788
2023-01-17 18:32:44 -08:00
James Zern
d9a505ffb6 CMakeLists.txt: allow CMAKE_INSTALL_RPATH to be set empty
this allows the user to override the default non-empty value added in:
b4994eaa CMake: set rpath for shared objects

Bug: webp:592
Change-Id: I069dcbcd8c2f1e8654d9bc98149139f398ac2c93
Fixed: webp:592
2023-01-17 18:22:47 -08:00
James Zern
bdf33d03b0 libwebp-1.3.0
- 12/16/2022: version 1.3.0
   This is a binary compatible release.
   * add libsharpyuv, which exposes -sharp_yuv/config.use_sharp_yuv
     functionality to other libraries; libwebp now depends on this library
   * major updates to the container and lossless bitstream docs (#448, #546,
     #551)
   * miscellaneous warning, bug & build fixes (#576, #583, #584)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEaw5rcJdt4wPt8vYB+cPWvbgjK10FAmPAtgoACgkQ+cPWvbgj
 K11C9A/9FVNCbB6BTa0q2iZsgoEj49k+6KCsYQs80yhAwBBKtB+b2qHbjoaoGYQN
 cRNeanWvP2XxWcInPvkr6CIOhOaP9U3j3PKlubCeWv4YzI58mOx6uVGv1T9r6Isr
 ogPXrSOATUnVnlgG0RtJLRivOadY0mY+u4JNj2R8kHmSgp50poZRrw8GIiclh1ml
 KVq9RJ9St/p8ps4mJROLowxnaB5pH2jTif5T1rkmq4GsQskkLzPtHfELrM4hQjMz
 dc/pcdT0DCMMRqJZ/ePGMK0BjVjzHEBsxHYuHGfayKesO+MYajwfsTyYxxSGOD3y
 fEb0H7NCwHemGm94AyYj6NyjKUuIG2G2dku+0h0dWn/Ml855RzghGLIqCzqMXs0s
 AwaSpoyxWMBJw39pHcuk+ZuVX+uhy7dndLC5OtTLfEDCDwxKAktGaUdzRIy1nL/k
 NzH0IWCOnb/awux6heamP1gmTfKIKk+IsJwFiFJyfi+VQwxil7jD4rVCYsavL5f0
 hTkBFcZNzZsNSkuFJzqDiCnCFtcXWJ8mQ9fwx38wlvESH+U3k0yggo02cXmLpH8J
 pSYdlOU5kCpipdfgmS7Aa4HHo91SgkjlvL4+bzOa22UBpMQEgD3wgMnkVUm4dZ9F
 bgwMsZLt9KQYso6OKBdvOx+wy6Bp7/gOnIhVPleRZZk/HWoAHdE=
 =67V9
 -----END PGP SIGNATURE-----

Merge tag 'v1.3.0'

libwebp-1.3.0

- 12/16/2022: version 1.3.0
  This is a binary compatible release.
  * add libsharpyuv, which exposes -sharp_yuv/config.use_sharp_yuv
    functionality to other libraries; libwebp now depends on this library
  * major updates to the container and lossless bitstream docs (#448, #546,
    #551)
  * miscellaneous warning, bug & build fixes (#576, #583, #584)

* tag 'v1.3.0':
  update ChangeLog
  update NEWS
  bump version to 1.3.0
  update AUTHORS

Bug: webp:590
Bug: b/262806895
Change-Id: I4bc5cfb0708fab3569dc567d22bfdbcb5ff2a1ad
2023-01-12 17:58:29 -08:00
James Zern
b557776962 update ChangeLog
Change-Id: If794cc65c0813fbff7f5e0ecbd519d5387beb16d
2022-12-19 16:23:35 -08:00
James Zern
0ba772442e update NEWS
Bug: webp:590
Change-Id: I877bda2d177bd371cd2a43974200c66cf5fa8a10
2022-12-16 16:47:42 -08:00
James Zern
e763eb1ea3 bump version to 1.3.0
libwebp{,decoder} - 1.3.0
libwebp libtool - 8.6.1
libwebpdecoder libtool - 4.6.1

mux - 1.3.0
libtool - 3.11.0

demux - 1.3.0
libtool - 2.12.0

sharpyuv - 0.2.0 (unchanged, first release)
libtool - 0.0.0 (ditto)

Bug: webp:590
Change-Id: Ibf3ed56af87667c30650d8dd60eb0ff3bdcb6749
2022-12-16 16:47:42 -08:00
James Zern
2a8686fcab update AUTHORS
Bug: webp:590
Change-Id: I5f18987cd56f5efd47fe901b097669346c698446
2022-12-16 16:47:36 -08:00
James Zern
106a57c1db Merge "*/Android.mk: add a check for NDK_ROOT" into main 2022-12-16 20:59:49 +00:00
James Zern
c5e841c417 Merge "extras: WebpToSDL -> WebPToSDL" into main 2022-12-16 20:15:12 +00:00
James Zern
dbc3071512 Merge "xcframeworkbuild.sh: bump MACOSX_CATALYST_MIN_VERSION" into main 2022-12-16 20:13:44 +00:00
James Zern
6fc1a9f96e */Android.mk: add a check for NDK_ROOT
This simplifies integration with the Android platform and avoids the
files from being used when a non-NDK build is performed. In that case
Android.bp is preferred.

Change-Id: I6e334cf8b05a19da8452405f5f448f9e4b6e4a40
2022-12-16 12:10:36 -08:00
James Zern
d3e151fc03 doc/api.md,webp_js/README.md: Webp -> WebP
Change-Id: Ib30d008b5750d2e4064aaf478db6f5bc7aa5902e
2022-12-15 18:14:19 -08:00
James Zern
ed92a62649 extras: WebpToSDL -> WebPToSDL
this normalizes the function case to what's more commonly used in the
project

Change-Id: If614cb8eff4afba96b2468e28c52d850651a759b
2022-12-15 18:11:40 -08:00
James Zern
6eb0189b24 xcframeworkbuild.sh: bump MACOSX_CATALYST_MIN_VERSION
14.0 (-target x86_64-apple-ios14.0-macabi) is supported by default in
Xcode 14.0.1.

Change-Id: I05bc318fe321758c68c7be2e339d77512dd81684
2022-12-15 15:14:44 -08:00
James Zern
1d58575b18 CMake: align .pc variables with autoconf
Use prefix/exec_prefix for includedir/libdir if
CMAKE_INSTALL_{LIBDIR,INCLUDEDIR} are relative and the CMake variable
alone if they're absolute.

This matches what autoconf will produce if a custom --libdir or
--includedir are used.

See also: https://github.com/AOMediaCodec/libavif/issues/1220

Change-Id: I6fbc016c0009ede42e1e5db3a9ee7ae9545d8da0
2022-12-14 19:21:12 -08:00
James Zern
e5fe2cfc1b webp-lossless-bitstream-spec,cosmetics: reflow paragraphs
Change-Id: Ifd7472fe0678b45efc62faa66de8e8dc2e9931e3
2022-11-22 11:38:01 -08:00
James Zern
0ceeeab987 webp-lossless-bitstream-spec: add amendment note
for fixes to the distance_map pseudo-code, the inverse color transform
description and the num_code_lengths check.

Bug: webp:448
Bug: webp:551
Change-Id: Id7e791b97704dd64bb9519657ce48b92cb457ae4
2022-11-22 11:38:01 -08:00
James Zern
607611cd86 Merge "webp-container-spec: normalize section title case" into main 2022-11-22 19:35:41 +00:00
James Zern
f853685e13 lossless: SUBTRACT_GREEN -> SUBTRACT_GREEN_TRANSFORM
this makes the name of the TransformType enum value match the other
members

Bug: webp:448
Change-Id: I85b2f615f97b40fc6d544197cccfb7189dcf4fc0
2022-11-21 16:48:51 -08:00
James Zern
786497e48a webp-lossless-bitstream-spec: fix inv color txfm description
The prose describing the process was missed in:
44dd765d webp-lossless-bitstream-spec: fix ColorTransform impl

Bug: webp:448
Bug: webp:551
Change-Id: If5fb95103ffedeed113e3ad62510f3a19bfd280e
2022-11-21 16:48:51 -08:00
James Zern
c6ac672dbc webp-lossless-bitstream-spec: fix num_code_lengths check
in the 'Normal Code Length Code' description the number of valid code
lengths is 19, not 18.

Bug: webp:448
Bug: webp:551
Change-Id: Id929604e1d771cb09b2d0ac617e83f21077f21de
2022-11-21 16:48:51 -08:00
James Zern
b5700efb70 webp-lossless-bitstream-spec,cosmetics: grammar/capitalization
Bug: webp:448
Change-Id: I2d6cc66b45342716fdba7792c570510601432109
2022-11-21 16:48:41 -08:00
James Zern
d8ed8c117c webp-container-spec: normalize section title case
Use 'title case' as recommended in RFC 7322 (Section 3.4 Capitalization)

Bug: webp:448
Change-Id: I9762402499eb58acbe9ccb75f4f8d2b9c3e9b26b
2022-11-21 10:53:13 -08:00
James Zern
52ec0b8f61 Merge changes Ie975dbb5,Ifc8c93af,I6ca7c5d6,I2e8d66f5,I152477b8 into main
* changes:
  webp-lossless-bitstream-spec,cosmetics: reflow abstract
  webp-lossless-bitstream-spec: reword abstract re alpha
  webp-lossless-bitstream-spec,cosmetics: normalize range syntax
  webp-lossless-bitstream-spec: limit dist map lut to 69 cols
  webp-lossless-bitstream-spec: fix dist mapping example
2022-11-18 18:28:15 +00:00
James Zern
5097ef6255 webp-container-spec,cosmetics: grammar/capitalization
Bug: webp:448
Change-Id: I8b5e218df95436b6b8b2ecc751c70015d46fe7a0
2022-11-17 19:13:39 -08:00
James Zern
e3ba2b1f5b webp-lossless-bitstream-spec,cosmetics: reflow abstract
Bug: webp:448
Change-Id: Ie975dbb52687c6c068b029fc8f84db8cf189523a
2022-11-17 18:25:13 -08:00
James Zern
1e8e3ded21 webp-lossless-bitstream-spec: reword abstract re alpha
'zero alpha pixels' was a bit hard to parse; replace this with something
more explicit

Bug: webp:448
Change-Id: Ifc8c93af5520ffdafc58e3fc311dfb4cb19626e9
2022-11-17 18:22:56 -08:00
James Zern
017cb6fa94 webp-container-spec,cosmetics: normalize range syntax
this makes the syntax in this document consistent with
webp-lossless-bitstream-spec.txt

[N-M] -> [N..M]

Bug: webp:448
Change-Id: Iebf39eefb7d3c081a3d10e2804ee215c3aed6b79
2022-11-17 18:13:32 -08:00
James Zern
f6a4684ba8 webp-lossless-bitstream-spec,cosmetics: normalize range syntax
[N-M], [N, M] -> [N..M]

these were missed in:
e74f8a62 webp-lossless-bitstream-spec,cosmetics: normalize range syntax

Bug: webp:448
Change-Id: I6ca7c5d6b0473fdf3de0c6dba00b0f1e3da46a23
2022-11-17 18:06:49 -08:00
James Zern
54ebd5a375 webp-lossless-bitstream-spec: limit dist map lut to 69 cols
this is similar to an earlier change for most of the code examples:
  7a0a9935 doc/*.txt: restrict code to 69 columns

some renderers may limit output to 72 and use a 3 space indent; this
avoids overflowing into the margin

Bug: webp:448
Change-Id: I2e8d66f598889c7bd824e911ea01fd70f98a4130
2022-11-17 18:06:45 -08:00
James Zern
44741f9c58 webp-lossless-bitstream-spec: fix dist mapping example
The distance code read from the bitstream is reduced by 1 before doing
the lookup. The prose describing the lookup was correct, the pseudocode
failed to subtract 1 and used x/y instead of xi/yi from the lookup.

Bug: webp:448
Change-Id: I152477b888c26a0473a35373d3d331fddd14237f
2022-11-17 18:06:31 -08:00
James Zern
fad0ece7ed pnmdec.c: use snprintf instead of sprintf
this is consistent with the rest of the example code

Change-Id: Id4c02e16be84fbe21ddc74c9049d8cbda2d875a8
2022-11-15 17:10:26 -08:00
James Zern
3f73e8f7ac sharpyuv: add SharpYuvGetVersion()
Change-Id: Ic7e93c7c3ec33b8ab0105a6e81b76a7869422b55
2022-10-28 19:15:32 -07:00
James Zern
ce2f2d668e SharpYuvConvert: fix a race on SharpYuvGetCPUInfo
Rather than make a copy, requiring an additional lock/unlock only to set
the pointer to itself, pass the address of SharpYuvGetCPUInfo and use it
as a sentinel to avoid updating the pointer.

Change-Id: I22fb467f1659c16805c0d3bc7aaeba6a1bb16dbb
2022-10-27 13:52:01 -07:00
James Zern
a458e3086c sharpyuv_dsp.h: restore sharpyuv_cpu.h include
this was removed in:
979c0ebb sharpyuv: add SharpYuvGetCPUInfo

but currently, consumers of sharpyuv_dsp.h depend on the presence of
WEBP_USE_*

Change-Id: I9524aa5ab767a1b46770022220372455a86f198f
2022-10-26 15:22:48 -07:00
James Zern
9ba800a745 Merge changes Id72fbf3b,Ic59d23a2 into main
* changes:
  sharpyuv: add SharpYuvGetCPUInfo
  cpu.c,cosmetics: fix a typo
2022-10-26 20:56:42 +00:00
James Zern
979c0ebbcd sharpyuv: add SharpYuvGetCPUInfo
This gives a similar structure to libwebp and fixes a bug where passing
NULL to SharpYuvInit() would unconditionally set optimized function
pointers. SharpYuvInit() is left as an undocumented public function and
SharpYuvGetCPUInfo is kept private to serialize updates to the pointer.

Change-Id: Id72fbf3ba5b396367510e3bcd1ee2e4e11b95b8c
2022-10-26 13:07:01 -07:00
James Zern
8bab09a4a8 Merge "*.pc.in: rename lib_prefix to webp_libname_prefix" into main 2022-10-26 19:57:24 +00:00
James Zern
769387c54a cpu.c,cosmetics: fix a typo
VP8DecGetCPUInfo -> VP8GetCPUInfo

Change-Id: Ic59d23a2964a881b853db62b3617117bf10ec66d
2022-10-25 16:24:07 -07:00
James Zern
a02978c250 sharpyuv/Makefile.am+cmake: add missing -lm
this lib uses functions from math.h

Change-Id: I316f058c9e42e4888cce0d380472518a77e21517
2022-10-25 15:58:21 -07:00
James Zern
28aedcb9b0 *.pc.in: rename lib_prefix to webp_libname_prefix
this will help avoid any future conflicts with the more generic autoconf
type name

Change-Id: I0311e03a11a541118025c7dbe8309365f6efa847
2022-10-24 16:44:42 -07:00
James Zern
c42e6d5a89 configure.ac: export an empty lib_prefix variable
this fixes the pkg-config files after:
2498209b *.pc.in: add lib prefix to lib names w/MSVC

Change-Id: I1c932103da175ca50826a8801796f0f6ee5ef583
2022-10-24 16:42:37 -07:00
James Zern
dfc843aa63 Merge "*.pc.in: add lib prefix to lib names w/MSVC" into main 2022-10-20 18:25:42 +00:00
James Zern
2498209ba9 *.pc.in: add lib prefix to lib names w/MSVC
this fixes the library names output after:
9ac25bcb3 CMakeLists.txt,win32: match naming convention used by nmake

before this change:
pkg-config --libs --msvc-syntax \
  libwebp libwebpdemux libwebpmux libsharpyuv libwebpdecoder
/libpath:.../lib webpdemux.lib webpmux.lib webp.lib
  sharpyuv.lib webpdecoder.lib

after:
pkg-config --libs --msvc-syntax \
  libwebp libwebpdemux libwebpmux libsharpyuv libwebpdecoder
/libpath:.../lib libwebpdemux.lib libwebpmux.lib libwebp.lib
  libsharpyuv.lib libwebpdecoder.lib

Bug: webp:584
Change-Id: Ic3693b58a40e0ba683333065003b1c00aab0cf48
Fixed: webp:584
2022-10-17 14:07:02 -07:00
James Zern
ac252b6118 Merge "analysis_enc.c: fix a dead store warning" into main 2022-10-17 17:34:34 +00:00
James Zern
5694476244 analysis_enc.c: fix a dead store warning
when threading is disabled; fixes:
src/enc/analysis_enc.c:429:15: warning: Value stored to 'split_row'
during its initialization is never read [deadcode.DeadStores]
    const int split_row = (9 * last_row + 15) >> 4;
              ^~~~~~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~

Change-Id: I2b02173bb8c930ed54360cce5c7b88ecce098d83
2022-10-14 19:20:00 -07:00
James Zern
d34f9b99b9 Merge "webp-lossless-bitstream-spec: convert BNF to ABNF" into main 2022-10-15 02:01:48 +00:00
James Zern
dc05b4db2a Merge changes I96bc063c,I45880467,If9e18e5a,I6ee938e4,I0a410b28, ... into main
* changes:
  webp-container-spec: add prose for rendering process
  webp-container-spec: note reserved fields MUST be ignored
  webp-lossless-bitstream-spec: improve 'small' color table stmt
  webp-container-spec: remove redundant sentence
  doc/webp-*: fix some punctuation, grammar
  webp-container-spec: clarify background color note
  webp-container-spec: come too late -> out of order
  webp-container-spec: prefer hex literals
  webp-container-spec: change SHOULD to MUST w/ANIM chunk
  webp-container-spec: add unknown fields MUST be ignored
  webp-container-spec: make padding byte=0 a MUST
  webp-container-spec: update note on trailing data
  webp-container-spec: clarify Chunk Size is in bytes
2022-10-14 04:05:31 +00:00
James Zern
83270c7f89 webp-container-spec: add prose for rendering process
this is given in addition to the pseudocode, which has been corrected in
the process

based on comments in:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_lars-eggert

Bug: webp:448
Change-Id: I96bc063c2a71572ff61609a731a9c4e8edc2b971
2022-10-13 19:34:54 -07:00
James Zern
73b19b64fd webp-container-spec: note reserved fields MUST be ignored
based on comments in:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_lars-eggert

Bug: webp:448
Change-Id: I45880467d8955389a2ef657beca9d734da223457
2022-10-13 19:34:54 -07:00
James Zern
57101d3fc5 webp-lossless-bitstream-spec: improve 'small' color table stmt
this is defined earlier as 16 or fewer unique values

based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_lars-eggert

Bug: webp:448
Change-Id: If9e18e5aaec3641e477c2bb68dacc0a4fd029cfb
2022-10-13 19:34:54 -07:00
James Zern
dfd32e4592 webp-container-spec: remove redundant sentence
in the note regarding metadata the possibility of multiple XMP/EXIF
chunks was already covered in the previous sentences.

based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_lars-eggert

Bug: webp:448
Change-Id: I6ee938e4d95bda1b144d3175fbf9f9296cf23352
2022-10-13 19:34:54 -07:00
James Zern
8a6185dd27 doc/webp-*: fix some punctuation, grammar
based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_lars-eggert

Bug: webp:448
Change-Id: I0a410b28b7b62fb4552ea3db444743be61469fe8
2022-10-13 19:34:54 -07:00
James Zern
72776530d8 webp-lossless-bitstream-spec: convert BNF to ABNF
this has a better canonical reference [1] and is preferred in IETF docs

[1] https://www.rfc-editor.org/rfc/rfc5234

Bug: webp:448
Change-Id: I3f0bd34d3ca4c62b255d5d6cbae0c55e2940dfb5
2022-10-12 16:55:46 -07:00
James Zern
d992bb08b7 cmake: rename cpufeatures target to cpufeatures-webp
this avoids name clashes with other targets of the same name:
https://github.com/webmproject/sjpeg/pull/117

Change-Id: I520dff992c71f0e737ac4a7e21f9ae80701d052d
2022-10-11 15:52:04 -07:00
James Zern
3ed2b27517 webp-container-spec: clarify background color note
replace ...a transparency value (alpha)... with clearer text

based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_lars-eggert

Bug: webp:448
Change-Id: I79157b669c4317ebfc4f8434ee38f2666d1559ec
2022-10-11 15:05:33 -07:00
James Zern
951c292d12 webp-container-spec: come too late -> out of order
based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_lars-eggert

Bug: webp:448
Change-Id: Ie32d5500f3966b3c9f910675fb11d8a2cc60de3c
2022-10-11 15:05:33 -07:00
James Zern
902dd78762 webp-container-spec: prefer hex literals
to ABNF-style values; this makes the doc more consistent with
doc/webp-lossless-bitstream-spec.txt.

based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_lars-eggert

Bug: webp:448
Change-Id: I751cf0b7f728866ae663beb06e6352e5b3d848b2
2022-10-11 15:05:33 -07:00
James Zern
a8f6b5ee94 webp-container-spec: change SHOULD to MUST w/ANIM chunk
based on comments in:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_paul-wouters

Bug: webp:448
Change-Id: I9464dbbd734f1b78b287139eff13b1db8814c8d9
2022-10-11 15:05:33 -07:00
James Zern
1dc594352f webp-container-spec: add unknown fields MUST be ignored
based on comments in:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_paul-wouters

Bug: webp:448
Change-Id: I1eccb573b536f931b123261662efad7f92700500
2022-10-11 15:05:33 -07:00
James Zern
280a810f2a webp-container-spec: make padding byte=0 a MUST
this is consistent with the RIFF specification.

based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_robert-wilton

Bug: webp:448
Change-Id: I7a09177c9ea001b2e8759dcc5102242864c78105
2022-10-11 15:05:33 -07:00
James Zern
41f0bf680b webp-container-spec: update note on trailing data
clarify that the data is after the size specified by the file size in
the header; an alternate way to read the previous statement was that the
data was after the 'WEBP' fourcc.

based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_robert-wilton

Bug: webp:448
Change-Id: I7c5c5440a94cb817da51fe07d1ccf45d6af0f001
2022-10-11 15:05:33 -07:00
James Zern
6bdd36dbe7 webp-container-spec: clarify Chunk Size is in bytes
based on comments from:
https://datatracker.ietf.org/doc/draft-zern-webp/ballot/#draft-zern-webp_robert-wilton

Bug: webp:448
Change-Id: Idc874e5fa04d3cd122d31b87e833bf9f30ec9d05
2022-10-11 15:05:33 -07:00
James Zern
87e36c485a Merge "webp_js/README.md,cosmetics: reflow some lines" into main 2022-10-10 18:29:48 +00:00
Maryla Ustarroz-Calonge
5b01f32162 Merge "Update Windows makefile to build libsharpyuv library." into main 2022-10-07 13:28:20 +00:00
James Zern
19b1a71c48 webp_js/README.md,cosmetics: reflow some lines
after:
cb90f76b Update wasm instructions.

Change-Id: I8d937d08dba98c23c4a298ba1165e4b1f553fea9
2022-10-06 14:10:03 -07:00
Maryla
780db75618 Update Windows makefile to build libsharpyuv library.
Change-Id: I2d260aa11c06ba1c33e40e94537f5a9afe5d3880
2022-10-05 14:21:35 +02:00
James Zern
e407d4b37c CMakeLists.txt: replace GLUT_glut_LIBRARY w/GLUT::GLUT
GLUT_glut_LIBRARY is a cache variable that is not recommended for use:

from cmake-3.24/Modules/FindGLUT.cmake:
This module may set the following variables depending on platform.
These variables may optionally be set to help this module find the
correct files, but clients should not use these as results:

...

``GLUT_glut_LIBRARY``
  The full path to the glut library.

based on a patch in the Krita and vcpkg projects:
7d51396a7a/3rdparty/ext_webp/0009-glut.patch
https://github.com/microsoft/vcpkg/blob/master/ports/libwebp/0009-glut.patch

Change-Id: If54e26cb1e4e2f582e40eebd7e49d7cc566dbb81
2022-10-04 16:20:11 -07:00
James Zern
abf73d628e Merge "WebPConfig.cmake.in: add find_dependency(Threads)" into main 2022-10-04 22:39:13 +00:00
James Zern
25807fb4cb Merge "cmake: restore compatibility with cmake < 3.12" into main 2022-10-04 21:06:52 +00:00
James Zern
5dbc4bfa1b WebPConfig.cmake.in: add find_dependency(Threads)
when WEBP_USE_THREAD=1; this is necessary after:
0d1b9bc4 WEBP_DEP_LIBRARIES: use Threads::Threads

fixes:
CMake Error at WebPTargets.cmake:76 (set_target_properties):
  The link interface of target "WebP::webp" contains:

    Threads::Threads

  but the target was not found.  Possible reasons include:

    * There is a typo in the target name.
    * A find_package call is missing for an IMPORTED target.
    * An ALIAS target is missing.

Bug: webp:583
Change-Id: I19633bcceccacb95be06aa9610512127f3c288a6
Fixed: webp:583
2022-10-04 13:01:12 -07:00
Vincent Rabaud
b2a175dd04 Merge "Update wasm instructions." into main 2022-10-04 19:33:17 +00:00
Vincent Rabaud
cb90f76b68 Update wasm instructions.
Also update the quotes in CMake following:
https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-specify-s-options-in-a-cmake-project
https://emscripten.org/docs/getting_started/FAQ.html#why-do-i-get-a-nameerror-or-a-problem-occurred-in-evaluating-content-after-a-s-when-i-use-a-s-option

Change-Id: I9cc0a5aece0019c81e3f435106bf288cd68d0fd0
2022-10-04 16:24:57 +02:00
James Zern
02d1525869 cmake: restore compatibility with cmake < 3.12
since:
bfad7ab5 CMakeLists.txt: correct libwebpmux name in WebPConfig.cmake

replace list(TRANSFORM ...) with string(REGEX REPLACE ...); the former
was added in 3.12, but currently 3.7 is supported

Change-Id: Ie2de2cf083c937ce0bb4d402d6f2452c09de0cea
2022-10-03 18:55:30 -07:00
Jeremy Maitin-Shepard
5ba046e25f CMake: add_definitions -> add_compile_options
`add_definitions` has been superseded by `add_compile_options` and
options added via `add_definitions` can have surprising behavior,
particularly when including `libwebp` as a sub-project via
`FetchContent`.

Change-Id: Icb8478dc92017576028becfd92c4567b4095fa60
2022-10-03 16:48:40 -07:00
James Zern
e68765af42 dsp,neon: use vaddv in a few more places
SumToInt_NEON
horizontal_add_uint32x4

Change-Id: I881831a7b2bab35a1810b0d83fee761470f3e09f
2022-09-12 10:55:58 -07:00
Maryla
e8f83de286 Set libsharpyuv include dir to 'webp' subdirectory.
Change-Id: I57cf12fd3d544485312fb0342aac3dcf5585136f
2022-08-19 10:22:30 +02:00
James Zern
15a91ab179 cmake,cosmetics: apply cmake-format
using the defaults present in 0.6.13 and setting
--first-comment-is-literal to avoid reflowing the copyright block and
--max-subgroups-hwrap 3 (default is 2) to avoid making some short set()
statements multi-line.

Change-Id: I77ec1f05a819f09c0143d6069c56b6e771ac6a37
2022-08-17 12:46:40 -07:00
James Zern
0dd49d1a3a CMakeLists.txt: set @ONLY in configure_file() calls
this matches the behavior in autoconf and avoids expanding the ${var}
references in the files; the .pc files now match the autoconf install.

pointed out by @kmilos in:
https://github.com/AOMediaCodec/libavif/pull/1035#discussion_r947847183

Change-Id: Ib1950a290b73b7e689658e6c2f25c8784b586180
2022-08-17 12:00:22 -07:00
James Zern
62b1bfe8bd Merge changes I2877e7bb,I777cad70,I15af7d1a,I686e6740,If10538a9, ... into main
* changes:
  picture_csp_enc.c: remove SafeInitSharpYuv
  sharpyuv: prefer webp/types.h
  sharpyuv,SharpYuvInit: add mutex protection when available
  sharyuv_{neon,sse2}.c: merge WEBP_USE_* sections
  add a few missing <stddef.h> includes for NULL
  sharpyuv.h: remove <inttypes.h>
2022-08-17 18:13:09 +00:00
James Zern
95c8fe5f3d Merge changes Iecea3603,I9dc228ab into main
* changes:
  cmake: fix dll exports
  cmake/cpu.cmake: remove unused variable
2022-08-17 18:11:27 +00:00
James Zern
e7c805cfad picture_csp_enc.c: remove SafeInitSharpYuv
thread safety was internalized in:
782ed48c sharpyuv,SharpYuvInit: add mutex protection when available

Change-Id: I2877e7bb78bf89ad7504c33d04b22952c0c0a968
2022-08-12 11:05:57 -07:00
James Zern
6af8845a8f sharpyuv: prefer webp/types.h
this provides better compatibility for older Visual Studio versions;
stdint.h is a part of C99.

this is consistent with the core libwebp library:
8fbb9188 prefer webp/types.h over stdint.h

Change-Id: I777cad70d9a407646c4193db9ca0f09e65d88735
2022-08-12 10:55:39 -07:00
James Zern
639619ce72 cmake: fix dll exports
move WEBP_EXTERN definition from Makefile.vc to webp/types.h using the
existing WEBP_DLL define to control its declaration to
__declspec(dllexport); the same is done for SHARPYUV_EXTERN

Change-Id: Iecea360305bdd19a878255470a00b9dcc344c730
2022-08-11 19:33:37 -07:00
James Zern
782ed48cd3 sharpyuv,SharpYuvInit: add mutex protection when available
this is similar to WEBP_DSP_INIT and avoids the potential for a race in
initializing the function pointers and gamma table

Change-Id: I15af7d1a3e92c42eaa735751ca33eba0d1e83283
2022-08-11 18:58:40 -07:00
James Zern
cad0d5adb6 sharyuv_{neon,sse2}.c: merge WEBP_USE_* sections
Change-Id: I686e6740717902d632fb01f9151e47fd3cb2cf79
2022-08-11 17:48:11 -07:00
James Zern
ef70ee06fa add a few missing <stddef.h> includes for NULL
and remove unused includes in sharpyuv/

Change-Id: If10538a994bd5dc55126f1485f2b163933ad8e91
2022-08-11 17:39:48 -07:00
James Zern
f0f9eda406 sharpyuv.h: remove <inttypes.h>
this hasn't been needed since:
93c54371 sharpyuv: add support for 10/12/16 bit rgb and 10/12 bit yuv.

Change-Id: I02051e8b576d7fd27824e13be0d087dc4e18209e
2022-08-11 17:18:49 -07:00
James Zern
9b902cbace Merge "picture_csp_enc.c,CheckNonOpaque: rm unneeded local" into main 2022-08-11 22:59:45 +00:00
James Zern
9c1d457c01 cmake/cpu.cmake: remove unused variable
Change-Id: I9dc228ab4ae5f1a9e2af742f37fd7b887f96d671
2022-08-11 15:04:29 -07:00
H. Vetinari
9ac25bcb39 CMakeLists.txt,win32: match naming convention used by nmake
Change-Id: Ib4d5c256b8c90afd54b4d7bcdee8df532095422d
2022-08-11 11:30:36 -07:00
James Zern
76c353bab7 picture_csp_enc.c,CheckNonOpaque: rm unneeded local
the ternary used with alpha_offset was removed in:
  3b07d327 Import,RGBA: fix for BigEndian import
use the ALPHA_OFFSET directly

Change-Id: Iee9b7c54f1498591e8c5834766dc4d34a321133d
2022-08-11 09:57:11 -07:00
James Zern
5000de5435 Merge "cwebp: fix WebPPictureHasTransparency call" into main 2022-08-11 16:55:40 +00:00
James Zern
e17293095b Merge "WebPPictureHasTransparency: add missing pointer check" into main 2022-08-11 16:55:21 +00:00
James Zern
00ff988a59 vp8l_enc,AddSingleSubGreen: clear int sanitizer warnings
this localizes the conversion to int in the function; the parameter was
previously changed in:
6ab496ed fix some 'unsigned integer overflow' warnings in ubsan

implicit conversion from type 'uint32_t' (aka 'unsigned int') of value
2350919223 (32-bit, unsigned) to type 'int' changed the value to
-1944048073 (32-bit, signed)

Bug: b/229626362
Change-Id: I589eec11c0dabaeba99e153e705f956181c570d2
2022-08-08 17:41:25 -07:00
James Zern
e2fecc22e1 dsp/lossless_enc.c: clear int sanitizer warnings
in TransformColorBlue; make new_blue an int to avoid:

implicit conversion from type 'int' of value 264 (32-bit, signed) to
type 'uint8_t' (aka 'unsigned char') changed the value to 8 (8-bit,
unsigned)

Bug: b/229626362
Change-Id: Ife276a59231075788396204e1a192f3b0c6d9e21
2022-08-08 17:34:01 -07:00
James Zern
129cf9e97e dsp/lossless.c: clear int sanitizer warnings
add explicit casts in calls to ColorTransformDelta()

clears warnings of the form:
implicit conversion from type 'uint8_t' (aka 'unsigned char') of value
254 (8-bit, unsigned) to type 'int8_t' (aka 'signed char') changed the
value to -2 (8-bit, signed)

Bug: b/229626362
Change-Id: Ic049ad9c9b5c6b669a1c943287f416533d6c873c
2022-08-08 17:34:01 -07:00
James Zern
ad7d1753c5 dsp/lossless_enc.c: clear int sanitizer warnings
add explicit casts in calls to ColorTransformDelta()

clears warnings of the form:
implicit conversion from type 'uint8_t' (aka 'unsigned char') of value
254 (8-bit, unsigned) to type 'int8_t' (aka 'signed char') changed the
value to -2 (8-bit, signed)

Bug: b/229626362
Change-Id: I40618209509508f56d8053f9daa29cf2e6999766
2022-08-08 17:34:00 -07:00
James Zern
5037220e55 VP8LSubtractGreenFromBlueAndRed_C: clear int sanitizer warnings
previously the types were changed to int to prevent unsigned overflow
warnings:
6ab496ed fix some 'unsigned integer overflow' warnings in ubsan

clears warnings of the form:
implicit conversion from type 'uint32_t' (aka 'unsigned int') of value
3724541952 (32-bit, unsigned) to type 'int' changed the value to
-570425344 (32-bit, signed)

implicit conversion from type 'int' of value -3361661 (32-bit, signed)
to type 'unsigned int' changed the value to 4291605635 (32-bit,
unsigned)

Bug: b/229626362
Change-Id: If1eb39c5dd7218d686c3c47fb7df72431b873be4
2022-08-08 17:34:00 -07:00
James Zern
2ee786c740 upsampling_sse2.c: clear int sanitizer warnings
clears warnings of the form:
src/dsp/upsampling_sse2.c:169:1: runtime error: implicit conversion from
type 'int' of value -16 (32-bit, signed) to type 'unsigned long' changed
the value to 18446744073709551600 (64-bit, unsigned)

Bug: b/229626362
Change-Id: I757d347808be5084e5fcf7c121a77d09812b743c
2022-08-08 17:34:00 -07:00
James Zern
4cc157d48a ParseOptionalChunks: clear int sanitizer warning
clears a warning of the form:
src/dec/webp_dec.c:182:62: runtime error: implicit conversion from type
'int' of value -2 (32-bit, signed) to type 'unsigned int' changed the
value to 4294967294 (32-bit, unsigned)

Bug: b/229626362
Change-Id: Ibf08f8bb9ec345381b51ca3872745368fca700c0
2022-08-08 17:34:00 -07:00
James Zern
892cf033b9 BuildHuffmanTable: clear int sanitizer warning
clears a warning of the form:
implicit conversion from type 'int' of value -1 (32-bit, signed) to type
'uint32_t' (aka 'unsigned int') changed the value to 4294967295 (32-bit,
unsigned)

Bug: b/229626362
Change-Id: I397fbd59bd3e6d787fcec1344b6230958b28d22c
2022-08-08 17:34:00 -07:00
James Zern
3a9a4d4589 VP8GetSigned: clear int sanitizer warnings
clears warnings of the form:
implicit conversion from type 'int32_t' (aka 'int') of value -1 (32-bit,
signed) to type 'unsigned int' changed the value to 4294967295 (32-bit,
unsigned)

Bug: b/229626362
Change-Id: I956671d4fee482c97c67bbe94032a97da49b0f6d
2022-08-08 17:34:00 -07:00
James Zern
704a3d0a1f dsp/lossless.c: quiet int sanitizer warnings
in calls to Clip255(); given the current implementation's use of a
logical shift the parameter is left as uint32_t and explicit casts are
added

clears warnings of the form:
src/dsp/lossless.c:52:18: runtime error: implicit conversion
from type 'int' of value -2 (32-bit, signed) to type 'uint32_t' (aka
'unsigned int') changed the value to 4294967294 (32-bit, unsigned)

Bug: b/229626362
Change-Id: If8a7f145c2d7e62e572e221da36b04281ed5c9bf
2022-08-08 17:30:45 -07:00
James Zern
1a6c109c99 WebPPictureHasTransparency: add missing pointer check
in the case of use_argb, alpha_offset may be non-zero which would cause
the null pointer check in CheckNonOpaque to pass

fixes a potential crash with invalid width/height set or an integer
sanitizer warning when passing a zeroed picture:
src/enc/picture_csp_enc.c:73:57: runtime error: applying non-zero offset
3 to null pointer

Change-Id: I9d499bba12c65ad5c65d8f9f3c8ee9298ac6081a
2022-08-08 16:45:20 -07:00
James Zern
c626e7d544 cwebp: fix WebPPictureHasTransparency call
when near_lossless is < 100; previously the zeroed 'picture' would be
passed in the check rather than the original picture. this would result
in alpha never been kept in the decode.

Change-Id: I6af3aef7de2d672e044025d975d8180b12d5fa40
2022-08-08 16:42:00 -07:00
James Zern
866e349cef libwebp-1.2.4
- 8/4/2022: version 1.2.4
   This is a binary compatible release.
   * restore CMake libwebpmux target name for compatibility with 1.2.2 (#575)
   * fix lossless crunch mode encoding with WEBP_REDUCE_SIZE
     (chromium: #1345547, #1345595, #1345772, #1345804)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEaw5rcJdt4wPt8vYB+cPWvbgjK10FAmLtz8MACgkQ+cPWvbgj
 K10v/A//R+sAs759jvKryQGJYDweXMKqbHbWWdkNbluX4FoitQH44Wy+YPecMrr2
 En3vSJWM50Bb8UvscvO+FoCI3x6DhgniEC7VbRnx43sSHioyd1K6XYBp+Q8Ksj6n
 qpdslDsjzpwj4uAKrDnTmdBr9CdSK8qxlXvgskqtWBwRnlePetRWXFSWO3ke7JKa
 d+SeLxboGgsZ+zjoWSqK+f7LCOEPGEkJk/JP3xOwn9K+FusLP2YMDhVw5Q78rWfh
 qNCamsM0SUFN9hfHp0/0FQvHO0B+c8BtB/hh5hjctZt7j5O+fQC+KAmiStnB2B3f
 CVjilU3ajnVH2VD4SYcsfHCVEV8hM+fHHjTgvnHh7jtz3wlokfcidMW9F1JujLZu
 M4FnD6XbJXERfitKx9lEzJ1h9RbChvrl84waU8Tkx/GboNIvHUQF5kROlOjXz3BL
 t+nkuNywxcb5RPph17OhYXT9MqPwGVHctrVG5DaAn+QjSKcxa65k03CFtZclD4Xm
 V8ozMwtKXiRZBqJRPwg7iYvnUOHixS3p+6p3OsUyjKelJEOLFfo1Z1vv7JvnXsmo
 xpvyetWnfWCnzzdMglahCVDu3ENVrjmNGV5g4wMTgDCcF0g/++M+7Yv/NfHNz0DX
 Y0uppjsXYUwNaq8Q3GpveQcpeZNrGpHRZQ88PsZkLxoNDn+hWHo=
 =BQmU
 -----END PGP SIGNATURE-----

Merge tag 'v1.2.4'

libwebp-1.2.4

- 8/4/2022: version 1.2.4
  This is a binary compatible release.
  * restore CMake libwebpmux target name for compatibility with 1.2.2 (#575)
  * fix lossless crunch mode encoding with WEBP_REDUCE_SIZE
    (chromium: #1345547, #1345595, #1345772, #1345804)

* tag 'v1.2.4':
  update ChangeLog
  update NEWS
  bump version to 1.2.4
  lossless: fix crunch mode w/WEBP_REDUCE_SIZE
  CMakeLists.txt: correct libwebpmux name in WebPConfig.cmake
  Revert "cmake: fix webpmux lib name for cmake linking"

Bug: webp:579
Change-Id: I7e1aa268d1ea9c1f3b38334cff2681e177bbdf36
2022-08-08 15:47:16 -07:00
Maryla Ustarroz-Calonge
c170df3830 Merge "Create libsharpyuv.a in makefile.unix." into main 2022-08-08 09:22:55 +00:00
Maryla
9d7ff74a55 Create libsharpyuv.a in makefile.unix.
Add libsharpyuv dependency to fuzzer makefile.

Issue: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=49778

Change-Id: Ib03219de33a97c3d7b13d0daffbee2035f2a3bde
2022-08-08 09:40:34 +02:00
James Zern
fcbc2d78ab Merge "doc/*.txt: restrict code to 69 columns" into main 2022-08-05 22:03:51 +00:00
James Zern
4ad0e1895e Merge "webp-container-spec.txt: normalize fourcc spelling" into main 2022-08-05 22:03:09 +00:00
James Zern
7a0a9935ed doc/*.txt: restrict code to 69 columns
some renderers may limit output to 72 and use a 3 space indent; this
avoids overflowing into the margin

Change-Id: Iaf4e8b71be27ef00fccd1d82b79bf96c01040f10
2022-08-04 19:35:24 -07:00
James Zern
c040a615b1 webp-container-spec.txt: normalize fourcc spelling
fourcc -> FourCC as it's defined in the terminology

Change-Id: I49e3a5aaba525b295701d8aac7b1700c4003ca77
2022-08-04 11:47:22 -07:00
James Zern
aff1c546ef dsp,x86: normalize types w/_mm_cvtsi128_si32 calls
fixes integer sanitizer warnings of the form:
implicit conversion from type 'int' of value -2122283647 (32-bit,
signed) to type 'uint32_t' (aka 'unsigned int') changed the value to
2172683649 (32-bit, unsigned)

implicit conversion from type 'uint32_t' (aka 'unsigned int') of value
3724541952 (32-bit, unsigned) to type 'int' changed the value to
-570425344 (32-bit, signed)

Bug: b/229626362
Change-Id: I79f68e3e2fcab7cc0402477d2e88d629348c9ff4
2022-08-04 11:26:23 -07:00
James Zern
ab540ae0c5 dsp,x86: normalize types w/_mm_cvtsi32_si128 calls
fixes integer sanitizer warnings of the form:
implicit conversion from type 'uint32_t' (aka 'unsigned int') of value
3724541952 (32-bit, unsigned) to type 'int' changed the value to
-570425344 (32-bit, signed)

Bug: b/229626362
Change-Id: Ie4d599aba88226e4e047250464ac37ca11d2cd3b
2022-08-04 11:26:23 -07:00
James Zern
8980362eed dsp,x86: normalize types w/_mm_set* calls (2)
missed in:
83539239 (origin/main, main) dsp,x86: normalize types w/_mm_set* calls

fixes integer sanitizer warnings of the form:
implicit conversion from type 'uint32_t' (aka 'unsigned int') of value
4292337446 (32-bit, unsigned) to type 'int' changed the value to
-2629850 (32-bit, signed)
runtime error: implicit conversion from type
'uint8_t' (aka 'unsigned char') of value 128 (8-bit, unsigned) to type
'char' changed the value to -128 (8-bit, signed)

Bug: b/229626362
Change-Id: Ie904da8ded26725b4e0a9b82cc0679234f0a5388
2022-08-04 11:26:23 -07:00
James Zern
835392393b dsp,x86: normalize types w/_mm_set* calls
fixes integer sanitizer warnings of the form:
runtime error: implicit conversion from type 'unsigned int' of value
4294967295 (32-bit, unsigned) to type 'int' changed the value to -1
(32-bit, signed)
runtime error: implicit conversion from type
'uint8_t' (aka 'unsigned char') of value 128 (8-bit, unsigned) to type
'char' changed the value to -128 (8-bit, signed)

Bug: b/229626362
Change-Id: I6be3c40407cf7a27b79d31ee32d3829ecb78ed66
2022-08-03 16:50:46 -07:00
James Zern
8a4576ce26 webp-container-spec.txt: replace &amp; with &
this conversion is handled by markdown processors

Change-Id: Ic679e40fcea577784deb8b455911bf1f201f2011
2022-08-03 11:12:23 -07:00
James Zern
db87088162 Merge "webp-container-spec.txt: make reserved 0 values a MUST" into main 2022-08-03 18:07:16 +00:00
James Zern
01d7d378d1 webp-lossless-bitstream-spec: number all sections
this makes the structure more consistent

Change-Id: Ie6c8b42506be73e565cfc4d39108eb4d8c038003
2022-08-02 19:03:51 -07:00
James Zern
337cf69f58 webp-lossless-bitstream-spec: mv Nomenclature after Intro
Change-Id: I3337513e48a8e604b154d91993bd7ff84d6c55ad
2022-08-02 18:50:59 -07:00
James Zern
79be856e6e Merge changes I7111d1f7,I872cd62c into main
* changes:
  libwebp.pc: add libsharpyuv to requires
  libsharpyuv: add pkg-config file
2022-08-03 01:43:10 +00:00
James Zern
5b87983ad0 webp-container-spec.txt: make reserved 0 values a MUST
these were intended as an extension point, but in this version of the
spec they're not defined. if they ever were used leaving them as SHOULD
could result in a source of incompatibility.

Change-Id: I1376ab7abe7d955ae335106f2faebc217dac77cd
2022-08-02 15:14:11 -07:00
James Zern
bd9391232d Merge changes I7a25b1a6,I51b2c2a0,I87d0cbcf,I6ec60af6,I0a3fe9dc into main
* changes:
  webp-container-spec.txt: clarify some SHOULDs
  webp-container-spec.txt: move ChunkHeader to terminology
  webp-container-spec.txt: clarify 'VP8 '/'XMP ' fourccs
  webp-container-spec.txt: rightsize table entries
  webp-container-spec.txt: update 'key words' text
2022-08-02 22:13:07 +00:00
Christopher Degawa
04764b56a0
libwebp.pc: add libsharpyuv to requires
Signed-off-by: Christopher Degawa <ccom@randomderp.com>
Change-Id: I7111d1f7738dad566dc74fc11be99ff92e11c50b
2022-08-02 15:58:49 -05:00
Christopher Degawa
7deee8103e
libsharpyuv: add pkg-config file
Signed-off-by: Christopher Degawa <ccom@randomderp.com>
Change-Id: I872cd62ccdf096044c7921afda8289849d141531
2022-08-02 15:46:19 -05:00
James Zern
1a64a7e649 webp-container-spec.txt: clarify some SHOULDs
for compatibility SHOULDs are left as is with some additional
description given of behavior if the recommendation is ignored.

Change-Id: I7a25b1a6fd9f9594390c30fce3af5ca17c3158c0
2022-08-02 13:12:27 -07:00
James Zern
bec2c88a11 webp-container-spec.txt: move ChunkHeader to terminology
this avoids presenting it in the description of a chunk where it could
appear it was defining an element of the diagram

Change-Id: I51b2c2a0dcecb4fc130711ad37c884a434920ecd
2022-08-02 12:46:53 -07:00
James Zern
c9359332a3 webp-container-spec.txt: clarify 'VP8 '/'XMP ' fourccs
Note the fourth character is an ASCII space to avoid confusion.
Also update the FourCC definition to mention that they're case
sensitive.

Change-Id: I87d0cbcf06e7c25bf2b33419b4c8c891adb82a8a
2022-08-01 18:51:35 -07:00
James Zern
70fe3063a5 webp-container-spec.txt: rightsize table entries
Use the correct number of lines for fixed width entries like
ChunkHeader(). ':' is used instead of '|' for variable length entries.

Bug: webp:546
Change-Id: I6ec60af674c0777d5ea6ae99c8aa3c7854ddd9f9
Fixed: webp:546
2022-08-01 18:49:43 -07:00
James Zern
ddbf3f3f2a webp-container-spec.txt: update 'key words' text
RFC 2119 was updated by RFC 8174; use the text from there

+ change INFORMATIVE to informative to avoid confusion with the key
  words in the RFCs

Change-Id: I0a3fe9dc48d284e7ac95633896ffb855ecd1a229
2022-08-01 18:42:21 -07:00
James Zern
c151e95bdc utils.h,WEBP_ALIGN: make bitmask unsigned
this fixes runtime warnings with clang -fsanitize=integer when using the
WEBP_ALIGN_CST constant in WEBP_ALIGN:
implicit conversion from type 'int' of value -32 (32-bit, signed) to
type 'unsigned int' changed the value to 4294967264 (32-bit, unsigned)

Bug: b/229626362
Change-Id: I524d80e620b9869de4e6d322b7de6ffa1ec8657f
2022-08-01 13:44:29 -07:00
James Zern
748e92bbb9 add WebPInt32ToMem
and use it in calls containing _mm_cvtsi32_si128; this calls
WebPUint32ToMem, but corrects the type to avoid runtime warnings with
clang -fsanitize=integer of the form:

implicit conversion from type 'int' of value -1904123502 (32-bit,
signed) to type 'uint32_t' (aka 'unsigned int') changed the value to
2390843794 (32-bit, unsigned)

Bug: b/229626362
Change-Id: I20545e822d8045fa44f688241879206055a0a148
2022-08-01 13:44:20 -07:00
Maryla Ustarroz-Calonge
3fe15b6773 Merge "Build libsharpyuv as a full installable library." into main 2022-08-01 13:10:09 +00:00
James Zern
4f402f34a1 add WebPMemToInt32
and use it with calls to _mm_cvtsi32_si128 and _mm_set_epi32; this calls
WebPMemToUint32, but corrects the type to avoid runtime warnings with
clang -fsanitize=integer of the form:

implicit conversion from type 'uint32_t' (aka 'unsigned int') of value
2155905152 (32-bit, unsigned) to type 'int' changed the value to
-2139062144 (32-bit, signed)

Bug: b/229626362
Change-Id: I50101ba2b46dfaa852f02d46830f3511c80b02d9
2022-07-28 22:10:22 -07:00
Maryla
a3b68c195e Build libsharpyuv as a full installable library.
Headers are installed in a "sharpyuv" subdirectory of the webp
dir, e.g. /usr/local/include/webp/sharpyuv/
Remove unnecessary dependency from sharpyuv to webp/types.h

Add SHARPYUV_EXTERN so that only symbols meant to be public
are exported.

Sharpyuv users can use the library with:

find_package(WebP)
if(TARGET WebP::sharpyuv)
  # ... use WebP::sharpyuv
endif()

Change-Id: I602a25521a135a2edc39d6587610484fe6447ec5
2022-07-28 12:31:59 +00:00
James Zern
b4994eaa6d CMake: set rpath for shared objects
this ensures the correct library is loaded when the install path is not
in the default search path; this matches the behavior of
autoconf/libtool

Change-Id: I7eaa458c353cbdb7f0a1f782a879c59662a5de79
2022-07-25 16:48:00 -07:00
James Zern
94cd711779 Merge "CMake: fix dylib versioning" into main 2022-07-25 23:29:50 +00:00
Vincent Rabaud
e91451b69b Fix the lossless specs a bit more.
Bug: webp:551

Change-Id: I03f729f69d660f17e27cc601e91c703b241f1b83
2022-07-25 22:36:51 +02:00
James Zern
231bdfb762 CMake: fix dylib versioning
match the behavior of autoconf in generating the -compatibility_version
and -current_version options. these use current + 1 and revision:
  # Darwin ld doesn't like 0 for these options...
  func_arith $current + 1
  minor_current=$func_arith_result
  ...
  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"

this requires CMake >= 3.17 to set the MACHO_COMPATIBILITY_VERSION and
MACHO_CURRENT_VERSION properties:
https://cmake.org/cmake/help/latest/prop_tgt/MACHO_COMPATIBILITY_VERSION.html

based on the fix in libexpat:
https://github.com/libexpat/libexpat/issues/55

Bug: webp:576
Fixed: webp:576
Change-Id: Ibc3ab99449aa213fc8c2ca3ae06def648c61acbd
2022-07-22 11:39:18 -07:00
James Zern
7366f7f394 Merge "lossless: fix crunch mode w/WEBP_REDUCE_SIZE" into main 2022-07-21 16:27:38 +00:00
James Zern
84163d9d02 lossless: fix crunch mode w/WEBP_REDUCE_SIZE
WEBP_REDUCE_SIZE was introduced to bring down the library size by
removing cropping and scaling support. Previously WebPPictureView() was
only used with these two, but in
  ec178f2c Add progress hook granularity in lossless
an additional use was added in VP8LEncodeStream() when extra side
configurations are used in crunch mode (-mt, quality == 100 & method ==
6 or quality >= 75 & method == 5 with a palette present currently).

WebPPictureView() and, for coherency, WebPPictureIsView() are
restored in this configuration to avoid affecting the general encode
path.

Previously WebPPictureView() was assumed to always succeed in these
cases which could result in crashes with WEBP_REDUCE_SIZE defined.

Bug: chromium:1345547
Bug: chromium:1345595
Bug: chromium:1345772
Bug: chromium:1345804
Change-Id: Ifecde36a726a434510478a764514b1469942c684
2022-07-20 22:04:34 -07:00
James Zern
d01c1eb309 webp-lossless-bitstream-spec,cosmetics: normalize capitalization
in section headings

Change-Id: I43b2208f5e0efa32029d519ac9805e871eb51ed3
2022-07-20 10:36:23 -07:00
James Zern
8813ca8e69 libwebp-1.2.3
- 6/30/2022: version 1.2.3
   This is a binary compatible release.
   * security fix for lossless encoder (#565, chromium:1313709)
   * improved progress granularity in WebPReportProgress() when using lossless
   * improved precision in Sharp YUV (-sharp_yuv) conversion
   * many corrections to webp-lossless-bitstream-spec.txt (#551)
   * crash/leak fixes on error/OOM and other bug fixes (#558, #563, #569, #573)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEaw5rcJdt4wPt8vYB+cPWvbgjK10FAmLR6rYACgkQ+cPWvbgj
 K13mwhAAmEqUPCxACgh1M7Tc6BfSkO0Q8FtUzm23/bYndf+t4+n3Oezxm7k5sldR
 OQUJfb9/pe+IegSpJHAOSL5ddTpQlSZfzj6glEHVkd346Ek+ZKzqLCZbWsTKO7xA
 xzv6BXLt49sA1jp62GWi5YyRZ4kQumjXKBxCCwGiaNEI8jd4D9Oduz8jzmRetGHS
 SPleaow7IlxMVgER6jnQZt+nyYGH7UMWI0CWLICRzefHqz+jzwm3GY+brWOPJBbx
 8zZGNmiDzxSOcD7Ce8C13+7EYuLw0GAN6seHa/Lk+y8+w3Eh5tyCp8Z4vHVN32Iv
 2mqXyOo9jgJudZPyMFEduFMUwMo2VmPwnVmQ+5REjfB5dpiFdngHUOoL6MFMNYN/
 +SIPy25mcVJFCYtXQ41FybwG6JfGiba8V6kC3dUedXRodBY/zv5Qw5kjjMe0qzlw
 ey6WO8L5i5LeiGvCJH1mq22JM1UWquNWb1icMsjCbp77QZCDLUH4MYQxJLOgUvoV
 GsX/q8X9kRKPQ3nbwoFGPUAkWd9kGfOd+awef1NENstT6L9eLGYNBmr/p70aYsYh
 G3XcRx/N68oV1zY+/2W//xL/09F/XzGaDIue0pSaXZFuCTcX7h2sKxHT8hodH+zh
 X1y6EY3ezR7ayi1rhfyc+vIw3oqDnX8+mat1xze73AAL5dERBeM=
 =dAgB
 -----END PGP SIGNATURE-----

Merge tag 'v1.2.3'

libwebp-1.2.3

- 6/30/2022: version 1.2.3
  This is a binary compatible release.
  * security fix for lossless encoder (#565, chromium:1313709)
  * improved progress granularity in WebPReportProgress() when using lossless
  * improved precision in Sharp YUV (-sharp_yuv) conversion
  * many corrections to webp-lossless-bitstream-spec.txt (#551)
  * crash/leak fixes on error/OOM and other bug fixes (#558, #563, #569, #573)

Bug: webp:568
Bug: b/230421671

* tag 'v1.2.3':
  update ChangeLog
  dsp/cpu.h: add missing extern "C"
  update ChangeLog
  vwebp: fix file name display in windows unicode build
  webpmux: fix -frame option in windows unicode build
  makefile.unix: add sharpyuv objects to clean target
  update NEWS
  bump version to 1.2.3
  update AUTHORS
  update .mailmap

Change-Id: I148041862bc930472e849d278471aa17ea12258b
2022-07-15 16:00:00 -07:00
261 changed files with 22547 additions and 10388 deletions

240
.cmake-format.py Normal file
View File

@ -0,0 +1,240 @@
# ----------------------------------
# Options affecting listfile parsing
# ----------------------------------
with section("parse"):
# Specify structure for custom cmake functions
additional_commands = { 'foo': { 'flags': ['BAR', 'BAZ'],
'kwargs': {'DEPENDS': '*', 'HEADERS': '*', 'SOURCES': '*'}}}
# Override configurations per-command where available
override_spec = {}
# Specify variable tags.
vartags = []
# Specify property tags.
proptags = []
# -----------------------------
# Options affecting formatting.
# -----------------------------
with section("format"):
# Disable formatting entirely, making cmake-format a no-op
disable = False
# How wide to allow formatted cmake files
line_width = 80
# How many spaces to tab for indent
tab_size = 2
# If true, lines are indented using tab characters (utf-8 0x09) instead of
# <tab_size> space characters (utf-8 0x20). In cases where the layout would
# require a fractional tab character, the behavior of the fractional
# indentation is governed by <fractional_tab_policy>
use_tabchars = False
# If <use_tabchars> is True, then the value of this variable indicates how
# fractional indentions are handled during whitespace replacement. If set to
# 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set
# to `round-up` fractional indentation is replaced with a single tab character
# (utf-8 0x09) effectively shifting the column to the next tabstop
fractional_tab_policy = 'use-space'
# If an argument group contains more than this many sub-groups (parg or kwarg
# groups) then force it to a vertical layout.
max_subgroups_hwrap = 3
# If a positional argument group contains more than this many arguments, then
# force it to a vertical layout.
max_pargs_hwrap = 6
# If a cmdline positional group consumes more than this many lines without
# nesting, then invalidate the layout (and nest)
max_rows_cmdline = 2
# If true, separate flow control names from their parentheses with a space
separate_ctrl_name_with_space = False
# If true, separate function names from parentheses with a space
separate_fn_name_with_space = False
# If a statement is wrapped to more than one line, than dangle the closing
# parenthesis on its own line.
dangle_parens = False
# If the trailing parenthesis must be 'dangled' on its on line, then align it
# to this reference: `prefix`: the start of the statement, `prefix-indent`:
# the start of the statement, plus one indentation level, `child`: align to
# the column of the arguments
dangle_align = 'prefix'
# If the statement spelling length (including space and parenthesis) is
# smaller than this amount, then force reject nested layouts.
min_prefix_chars = 4
# If the statement spelling length (including space and parenthesis) is larger
# than the tab width by more than this amount, then force reject un-nested
# layouts.
max_prefix_chars = 10
# If a candidate layout is wrapped horizontally but it exceeds this many
# lines, then reject the layout.
max_lines_hwrap = 2
# What style line endings to use in the output.
line_ending = 'unix'
# Format command names consistently as 'lower' or 'upper' case
command_case = 'canonical'
# Format keywords consistently as 'lower' or 'upper' case
keyword_case = 'unchanged'
# A list of command names which should always be wrapped
always_wrap = []
# If true, the argument lists which are known to be sortable will be sorted
# lexicographicall
enable_sort = True
# If true, the parsers may infer whether or not an argument list is sortable
# (without annotation).
autosort = False
# By default, if cmake-format cannot successfully fit everything into the
# desired linewidth it will apply the last, most agressive attempt that it
# made. If this flag is True, however, cmake-format will print error, exit
# with non-zero status code, and write-out nothing
require_valid_layout = False
# A dictionary mapping layout nodes to a list of wrap decisions. See the
# documentation for more information.
layout_passes = {}
# ------------------------------------------------
# Options affecting comment reflow and formatting.
# ------------------------------------------------
with section("markup"):
# What character to use for bulleted lists
bullet_char = '*'
# What character to use as punctuation after numerals in an enumerated list
enum_char = '.'
# If comment markup is enabled, don't reflow the first comment block in each
# listfile. Use this to preserve formatting of your copyright/license
# statements.
first_comment_is_literal = True
# If comment markup is enabled, don't reflow any comment block which matches
# this (regex) pattern. Default is `None` (disabled).
literal_comment_pattern = None
# Regular expression to match preformat fences in comments default=
# ``r'^\s*([`~]{3}[`~]*)(.*)$'``
fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
# Regular expression to match rulers in comments default=
# ``r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'``
ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
# If a comment line matches starts with this pattern then it is explicitly a
# trailing comment for the preceeding argument. Default is '#<'
explicit_trailing_pattern = '#<'
# If a comment line starts with at least this many consecutive hash
# characters, then don't lstrip() them off. This allows for lazy hash rulers
# where the first hash char is not separated by space
hashruler_min_length = 10
# If true, then insert a space between the first hash char and remaining hash
# chars in a hash ruler, and normalize its length to fill the column
canonicalize_hashrulers = True
# enable comment markup parsing and reflow
enable_markup = True
# ----------------------------
# Options affecting the linter
# ----------------------------
with section("lint"):
# a list of lint codes to disable
disabled_codes = []
# regular expression pattern describing valid function names
function_pattern = '[0-9a-z_]+'
# regular expression pattern describing valid macro names
macro_pattern = '[0-9A-Z_]+'
# regular expression pattern describing valid names for variables with global
# (cache) scope
global_var_pattern = '[A-Z][0-9A-Z_]+'
# regular expression pattern describing valid names for variables with global
# scope (but internal semantic)
internal_var_pattern = '_[A-Z][0-9A-Z_]+'
# regular expression pattern describing valid names for variables with local
# scope
local_var_pattern = '[a-z][a-z0-9_]+'
# regular expression pattern describing valid names for privatedirectory
# variables
private_var_pattern = '_[0-9a-z_]+'
# regular expression pattern describing valid names for public directory
# variables
public_var_pattern = '[A-Z][0-9A-Z_]+'
# regular expression pattern describing valid names for function/macro
# arguments and loop variables.
argument_var_pattern = '[a-z][a-z0-9_]+'
# regular expression pattern describing valid names for keywords used in
# functions or macros
keyword_pattern = '[A-Z][0-9A-Z_]+'
# In the heuristic for C0201, how many conditionals to match within a loop in
# before considering the loop a parser.
max_conditionals_custom_parser = 2
# Require at least this many newlines between statements
min_statement_spacing = 1
# Require no more than this many newlines between statements
max_statement_spacing = 2
max_returns = 6
max_branches = 12
max_arguments = 5
max_localvars = 15
max_statements = 50
# -------------------------------
# Options affecting file encoding
# -------------------------------
with section("encode"):
# If true, emit the unicode byte-order mark (BOM) at the start of the file
emit_byteorder_mark = False
# Specify the encoding of the input file. Defaults to utf-8
input_encoding = 'utf-8'
# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
# only claims to support utf-8 so be careful when using anything else
output_encoding = 'utf-8'
# -------------------------------------
# Miscellaneous configurations options.
# -------------------------------------
with section("misc"):
# A dictionary containing any per-command configuration overrides. Currently
# only `command_case` is supported.
per_command = {}

1
.gitignore vendored
View File

@ -52,5 +52,6 @@ tests/fuzzer/animdecoder_fuzzer
tests/fuzzer/animencoder_fuzzer
tests/fuzzer/demux_api_fuzzer
tests/fuzzer/enc_dec_fuzzer
tests/fuzzer/huffman_fuzzer
tests/fuzzer/mux_demux_api_fuzzer
tests/fuzzer/simple_api_fuzzer

View File

@ -16,3 +16,4 @@ James Zern <jzern@google.com>
Roberto Alanis <alanisbaez@google.com>
Brian Ledger <brianpl@google.com>
Maryla Ustarroz-Calonge <maryla@google.com>
Yannis Guyon <yguyon@google.com>

View File

@ -1,2 +1,2 @@
[style]
based_on_style = chromium
based_on_style = yapf

14
AUTHORS
View File

@ -2,6 +2,8 @@ Contributors:
- Aidan O'Loan (aidanol at gmail dot com)
- Alan Browning (browning at google dot com)
- Alexandru Ardelean (ardeleanalex at gmail dot com)
- Anuraag Agrawal (anuraaga at gmail dot com)
- Arthur Eubanks (aeubanks at google dot com)
- Brian Ledger (brianpl at google dot com)
- Charles Munger (clm at google dot com)
- Cheng Yi (cyi at google dot com)
@ -9,14 +11,20 @@ Contributors:
- Christopher Degawa (ccom at randomderp dot com)
- Clement Courbet (courbet at google dot com)
- Djordje Pesut (djordje dot pesut at imgtec dot com)
- Frank (1433351828 at qq dot com)
- Frank Barchard (fbarchard at google dot com)
- Hui Su (huisu at google dot com)
- H. Vetinari (h dot vetinari at gmx dot com)
- Ilya Kurdyukov (jpegqs at gmail dot com)
- Ingvar Stepanyan (rreverser at google dot com)
- Istvan Stefan (Istvan dot Stefan at arm dot com)
- James Zern (jzern at google dot com)
- Jan Engelhardt (jengelh at medozas dot de)
- Jehan (jehan at girinstud dot io)
- Jeremy Maitin-Shepard (jbms at google dot com)
- Johann Koenig (johann dot koenig at duck dot com)
- Jonathan Grant (jgrantinfotech at gmail dot com)
- Jonliu1993 (13720414433 at 163 dot com)
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
- Jyrki Alakuijala (jyrki at google dot com)
- Konstantin Ivlev (tomskside at gmail dot com)
@ -26,12 +34,16 @@ Contributors:
- Marcin Kowalczyk (qrczak at google dot com)
- Martin Olsson (mnemo at minimum dot se)
- Maryla Ustarroz-Calonge (maryla at google dot com)
- Masahiro Hanada (hanada at atmark-techno dot com)
- Mikołaj Zalewski (mikolajz at google dot com)
- Mislav Bradac (mislavm at google dot com)
- natewood (natewood at fb dot com)
- Nico Weber (thakis at chromium dot org)
- Noel Chromium (noel at chromium dot org)
- Nozomi Isozaki (nontan at pixiv dot co dot jp)
- Oliver Wolff (oliver dot wolff at qt dot io)
- Owen Rodley (orodley at google dot com)
- Ozkan Sezer (sezeroz at gmail dot com)
- Parag Salasakar (img dot mips1 at gmail dot com)
- Pascal Massimino (pascal dot massimino at gmail dot com)
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
@ -45,12 +57,14 @@ Contributors:
- Somnath Banerjee (somnath dot banerjee at gmail dot com)
- Sriraman Tallam (tmsriram at google dot com)
- Tamar Levy (tamar dot levy at intel dot com)
- Thiago Perrotta (tperrotta at google dot com)
- Timothy Gu (timothygu99 at gmail dot com)
- Urvang Joshi (urvang at google dot com)
- Vikas Arora (vikasa at google dot com)
- Vincent Rabaud (vrabaud at google dot com)
- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
- Wan-Teh Chang (wtc at google dot com)
- wrv (wrv at utexas dot edu)
- 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

@ -1,3 +1,5 @@
# Ignore this file during non-NDK builds.
ifdef NDK_ROOT
LOCAL_PATH := $(call my-dir)
WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD
@ -35,6 +37,7 @@ endif
sharpyuv_srcs := \
sharpyuv/sharpyuv.c \
sharpyuv/sharpyuv_cpu.c \
sharpyuv/sharpyuv_csp.c \
sharpyuv/sharpyuv_dsp.c \
sharpyuv/sharpyuv_gamma.c \
@ -161,6 +164,7 @@ utils_dec_srcs := \
src/utils/color_cache_utils.c \
src/utils/filters_utils.c \
src/utils/huffman_utils.c \
src/utils/palette.c \
src/utils/quant_levels_dec_utils.c \
src/utils/random_utils.c \
src/utils/rescaler_utils.c \
@ -218,7 +222,7 @@ LOCAL_SRC_FILES := \
$(utils_enc_srcs) \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src $(LOCAL_PATH)
# prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm
@ -288,3 +292,4 @@ include $(WEBP_SRC_PATH)/examples/Android.mk
ifeq ($(USE_CPUFEATURES),yes)
$(call import-module,android/cpufeatures)
endif
endif # NDK_ROOT

View File

@ -6,10 +6,10 @@
# 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.7)
if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW)
if(APPLE)
cmake_minimum_required(VERSION 3.17)
else()
cmake_minimum_required(VERSION 3.16)
endif()
project(WebP C)
@ -41,18 +41,21 @@ 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_BUILD_FUZZTEST "Build the fuzztest tests." 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)
set(WEBP_BITTRACE "0" CACHE STRING "Bit trace mode (0=none, 1=bit, 2=bytes)")
set_property(CACHE WEBP_BITTRACE PROPERTY STRINGS 0 1 2)
option(WEBP_ENABLE_WUNUSED_RESULT "Add [[nodiscard]] to some functions. \
CMake must be at least 3.21 to force C23" OFF)
if(WEBP_LINK_STATIC)
if(WIN32)
SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
else()
SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# vwebp does not compile on Ubuntu with static libraries so disabling it for
@ -78,23 +81,42 @@ if(WEBP_BUILD_WEBP_JS)
set(WEBP_USE_THREAD OFF)
if(WEBP_ENABLE_SIMD)
message("wasm2js does not support SIMD, disabling webp.js generation.")
message(NOTICE
"wasm2js does not support SIMD, disabling webp.js generation.")
endif()
endif()
set(SHARPYUV_DEP_LIBRARIES)
set(SHARPYUV_DEP_INCLUDE_DIRS)
set(WEBP_DEP_LIBRARIES)
set(WEBP_DEP_INCLUDE_DIRS)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release"
CACHE STRING "Build type: Release, Debug, MinSizeRel or RelWithDebInfo"
FORCE)
FORCE)
endif()
# Include dependencies.
if(WEBP_BUILD_ANIM_UTILS
OR WEBP_BUILD_CWEBP
OR WEBP_BUILD_DWEBP
OR WEBP_BUILD_EXTRAS
OR WEBP_BUILD_GIF2WEBP
OR WEBP_BUILD_IMG2WEBP)
set(WEBP_FIND_IMG_LIBS TRUE)
else()
set(WEBP_FIND_IMG_LIBS FALSE)
endif()
include(cmake/deps.cmake)
include(GNUInstallDirs)
if(BUILD_SHARED_LIBS AND NOT DEFINED CMAKE_INSTALL_RPATH)
# Set the rpath to match autoconf/libtool behavior. Note this must be set
# before target creation.
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif()
# ##############################################################################
# Options.
if(WEBP_ENABLE_SWAP_16BIT_CSP)
@ -110,26 +132,63 @@ if(WEBP_UNICODE)
add_definitions(-DUNICODE -D_UNICODE)
endif()
if(WIN32 AND BUILD_SHARED_LIBS)
add_definitions(-DWEBP_DLL)
endif()
# pkg-config variables used by *.pc.in.
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix "\$\{prefix\}")
set(libdir "\$\{prefix\}/lib")
set(includedir "\$\{prefix\}/include")
set(exec_prefix "\${prefix}")
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
set(libdir "${CMAKE_INSTALL_LIBDIR}")
else()
set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
set(includedir "${CMAKE_INSTALL_INCLUDEDIR}")
else()
set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif()
set(PTHREAD_LIBS ${CMAKE_THREAD_LIBS_INIT})
set(INSTALLED_LIBRARIES)
set(CMAKE_C_VISIBILITY_PRESET hidden)
if(MSVC)
# match the naming convention used by nmake
set(webp_libname_prefix "lib")
set(CMAKE_SHARED_LIBRARY_PREFIX "${webp_libname_prefix}")
set(CMAKE_IMPORT_LIBRARY_PREFIX "${webp_libname_prefix}")
set(CMAKE_STATIC_LIBRARY_PREFIX "${webp_libname_prefix}")
endif()
if(NOT WIN32)
set(CMAKE_C_VISIBILITY_PRESET hidden)
endif()
if(WEBP_ENABLE_WUNUSED_RESULT)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21.0)
set(CMAKE_C_STANDARD 23)
else()
unset(CMAKE_C_STANDARD)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-std=gnu2x>)
endif()
add_compile_options(-Wunused-result)
add_definitions(-DWEBP_ENABLE_NODISCARD=1)
endif()
# ##############################################################################
# Android only.
if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
add_library(cpufeatures STATIC
add_library(cpufeatures-webp STATIC
${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
list(APPEND INSTALLED_LIBRARIES cpufeatures)
target_link_libraries(cpufeatures dl)
set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} cpufeatures)
set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS}
${ANDROID_NDK}/sources/android/cpufeatures)
list(APPEND INSTALLED_LIBRARIES cpufeatures-webp)
target_link_libraries(cpufeatures-webp dl)
set(SHARPYUV_DEP_LIBRARIES ${SHARPYUV_DEP_LIBRARIES} cpufeatures-webp)
set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} cpufeatures-webp)
set(cpufeatures_include_dir ${ANDROID_NDK}/sources/android/cpufeatures)
set(SHARPYUV_DEP_INCLUDE_DIRS ${SHARPYUV_DEP_INCLUDE_DIRS}
${cpufeatures_include_dir})
set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS} ${cpufeatures_include_dir})
add_definitions(-DHAVE_CPU_FEATURES_H=1)
set(HAVE_CPU_FEATURES_H 1)
else()
@ -138,7 +197,7 @@ endif()
function(configure_pkg_config FILE)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${FILE}.in"
"${CMAKE_CURRENT_BINARY_DIR}/${FILE}")
"${CMAKE_CURRENT_BINARY_DIR}/${FILE}" @ONLY)
if(HAVE_MATH_LIBRARY)
# MSVC doesn't have libm
@ -147,10 +206,8 @@ function(configure_pkg_config FILE)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${FILE} ${data})
endif()
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/${FILE}"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${FILE}"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endfunction()
# ##############################################################################
@ -160,23 +217,15 @@ endfunction()
# E.g.: libimagedec_la_SOURCES = image_dec.c image_dec.h
function(parse_Makefile_am FOLDER VAR SRC_REGEX)
file(READ ${FOLDER}/Makefile.am MAKEFILE_AM)
string(REGEX MATCHALL
"${SRC_REGEX}_SOURCES[ ]*\\+?=[ ]+[0-9a-z\\._ ]*"
FILES_PER_LINE
${MAKEFILE_AM})
string(REGEX MATCHALL "${SRC_REGEX}_SOURCES[ ]*\\+?=[ ]+[0-9a-z\\._ ]*"
FILES_PER_LINE ${MAKEFILE_AM})
set(SRCS ${${VAR}})
foreach(FILES ${FILES_PER_LINE})
string(FIND ${FILES} "=" OFFSET)
math(EXPR OFFSET "${OFFSET} + 2")
string(SUBSTRING ${FILES}
${OFFSET}
-1
FILES)
string(SUBSTRING ${FILES} ${OFFSET} -1 FILES)
if(FILES)
string(REGEX MATCHALL
"[0-9a-z\\._]+"
FILES
${FILES})
string(REGEX MATCHALL "[0-9a-z\\._]+" FILES ${FILES})
foreach(FILE ${FILES})
list(APPEND SRCS ${FOLDER}/${FILE})
endforeach()
@ -205,175 +254,17 @@ endforeach()
# Generate the config.h file.
configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/src/webp/config.h)
${CMAKE_CURRENT_BINARY_DIR}/src/webp/config.h @ONLY)
add_definitions(-DHAVE_CONFIG_H)
# ##############################################################################
# Build the webpdecoder library.
# Creates a source file with an unused stub function in $CMAKE_BINARY_DIR and
# adds it to the specified target. Currently used only with Xcode.
#
# See also:
# https://cmake.org/cmake/help/v3.18/command/add_library.html#object-libraries
# "Some native build systems (such as Xcode) may not like targets that have
# only object files, so consider adding at least one real source file to any
# target that references $<TARGET_OBJECTS:objlib>."
function(libwebp_add_stub_file TARGET)
set(stub_source_dir "${CMAKE_BINARY_DIR}")
set(stub_source_file
"${stub_source_dir}/libwebp_${TARGET}_stub.c")
set(stub_source_code
"// Generated file. DO NOT EDIT!\n"
"// C source file created for target ${TARGET}.\n"
"void libwebp_${TARGET}_stub_function(void)\;\n"
"void libwebp_${TARGET}_stub_function(void) {}\n")
file(WRITE "${stub_source_file}" ${stub_source_code})
target_sources(${TARGET} PRIVATE ${stub_source_file})
endfunction()
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv "WEBP_SHARPYUV_SRCS"
"")
add_library(sharpyuv OBJECT ${WEBP_SHARPYUV_SRCS})
target_include_directories(sharpyuv
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(
sharpyuv
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv.h;\
${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv_csp.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
if(MSVC)
# avoid security warnings for e.g., fopen() used in the examples.
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else()
add_definitions(-Wall)
endif()
include_directories(${WEBP_DEP_INCLUDE_DIRS})
add_library(webpdecode OBJECT ${WEBP_DEC_SRCS})
target_include_directories(webpdecode
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webpdspdecode OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS})
target_include_directories(webpdspdecode
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webputilsdecode
OBJECT
${WEBP_UTILS_COMMON_SRCS}
${WEBP_UTILS_DEC_SRCS})
target_include_directories(webputilsdecode
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webpdecoder
$<TARGET_OBJECTS:webpdecode>
$<TARGET_OBJECTS:webpdspdecode>
$<TARGET_OBJECTS:webputilsdecode>)
if(XCODE)
libwebp_add_stub_file(webpdecoder)
endif()
target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES})
target_include_directories(
webpdecoder
PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
set_target_properties(
webpdecoder
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/libwebpdecoder.pc")
# Build the webp library.
add_library(webpencode OBJECT ${WEBP_ENC_SRCS})
target_include_directories(webpencode
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webpdsp
OBJECT
${WEBP_DSP_COMMON_SRCS}
${WEBP_DSP_DEC_SRCS}
${WEBP_DSP_ENC_SRCS})
target_include_directories(webpdsp
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webputils
OBJECT
${WEBP_UTILS_COMMON_SRCS}
${WEBP_UTILS_DEC_SRCS}
${WEBP_UTILS_ENC_SRCS})
target_include_directories(webputils
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webp
$<TARGET_OBJECTS:sharpyuv>
$<TARGET_OBJECTS:webpdecode>
$<TARGET_OBJECTS:webpdsp>
$<TARGET_OBJECTS:webpencode>
$<TARGET_OBJECTS:webputils>)
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 $<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;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/encode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
# Make sure the OBJECT libraries are built with position independent code (it is
# not ON by default).
set_target_properties(sharpyuv
webpdecode
webpdspdecode
webputilsdecode
webpencode
webpdsp
webputils
PROPERTIES POSITION_INDEPENDENT_CODE ON)
configure_pkg_config("src/libwebp.pc")
# Build the webp demux library.
add_library(webpdemux ${WEBP_DEMUX_SRCS})
target_link_libraries(webpdemux webp)
target_include_directories(webpdemux
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
PUBLIC $<INSTALL_INTERFACE:include>)
set_target_properties(
webpdemux
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/demux.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/demux/libwebpdemux.pc")
# Set the version numbers.
macro(set_version FILE TARGET_NAME NAME_IN_MAKEFILE)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/${FILE} SOURCE_FILE)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} SOURCE_FILE)
string(REGEX MATCH
"${NAME_IN_MAKEFILE}_la_LDFLAGS[^\n]* -version-info [0-9:]+"
TMP
"${NAME_IN_MAKEFILE}_la_LDFLAGS[^\n]* -version-info [0-9:]+" TMP
${SOURCE_FILE})
string(REGEX MATCH
"[0-9:]+"
TMP
${TMP})
string(REGEX
REPLACE ":"
" "
LT_VERSION
${TMP})
string(REGEX MATCH "[0-9:]+" TMP ${TMP})
string(REGEX REPLACE ":" " " LT_VERSION ${TMP})
# See the libtool docs for more information:
# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
@ -392,23 +283,166 @@ macro(set_version FILE TARGET_NAME NAME_IN_MAKEFILE)
set_target_properties(
${TARGET_NAME}
PROPERTIES VERSION
${LT_CURRENT_MINUS_AGE}.${LT_AGE}.${LT_REVISION}
SOVERSION
${LT_CURRENT_MINUS_AGE})
PROPERTIES VERSION ${LT_CURRENT_MINUS_AGE}.${LT_AGE}.${LT_REVISION}
SOVERSION ${LT_CURRENT_MINUS_AGE})
if(APPLE)
# For compatibility, set MACHO_COMPATIBILITY_VERSION and
# MACHO_CURRENT_VERSION to match libtool. These properties were introduced
# in 3.17:
# https://cmake.org/cmake/help/latest/prop_tgt/MACHO_COMPATIBILITY_VERSION.html
math(EXPR LIBWEBP_MACHO_COMPATIBILITY_VERSION "${LT_CURRENT} + 1")
set_target_properties(
${TARGET_NAME}
PROPERTIES MACHO_COMPATIBILITY_VERSION
${LIBWEBP_MACHO_COMPATIBILITY_VERSION}
MACHO_CURRENT_VERSION
${LIBWEBP_MACHO_COMPATIBILITY_VERSION}.${LT_REVISION})
endif()
endmacro()
set_version(Makefile.am webp webp)
set_version(Makefile.am webpdecoder webpdecoder)
set_version(demux/Makefile.am webpdemux webpdemux)
# ##############################################################################
# Build the webpdecoder library.
# Creates a source file with an unused stub function in $CMAKE_BINARY_DIR and
# adds it to the specified target. Currently used only with Xcode.
#
# See also:
# https://cmake.org/cmake/help/v3.18/command/add_library.html#object-libraries
# "Some native build systems (such as Xcode) may not like targets that have only
# object files, so consider adding at least one real source file to any target
# that references $<TARGET_OBJECTS:objlib>."
function(libwebp_add_stub_file TARGET)
set(stub_source_dir "${CMAKE_BINARY_DIR}")
set(stub_source_file "${stub_source_dir}/libwebp_${TARGET}_stub.c")
set(stub_source_code
"// Generated file. DO NOT EDIT!\n"
"// C source file created for target ${TARGET}.\n"
"void libwebp_${TARGET}_stub_function(void)\;\n"
"void libwebp_${TARGET}_stub_function(void) {}\n")
file(WRITE "${stub_source_file}" ${stub_source_code})
target_sources(${TARGET} PRIVATE ${stub_source_file})
endfunction()
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv "WEBP_SHARPYUV_SRCS" "")
add_library(sharpyuv ${WEBP_SHARPYUV_SRCS})
target_link_libraries(sharpyuv ${SHARPYUV_DEP_LIBRARIES})
set_version(sharpyuv/Makefile.am sharpyuv sharpyuv)
target_include_directories(
sharpyuv PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src)
set_target_properties(
sharpyuv
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv.h;\
${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv_csp.h")
configure_pkg_config("sharpyuv/libsharpyuv.pc")
install(
TARGETS sharpyuv
EXPORT ${PROJECT_NAME}Targets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp/sharpyuv
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
${CMAKE_INSTALL_INCLUDEDIR}/webp
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if(MSVC)
# avoid security warnings for e.g., fopen() used in the examples.
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else()
add_compile_options(-Wall)
endif()
include_directories(${WEBP_DEP_INCLUDE_DIRS})
add_library(webpdecode OBJECT ${WEBP_DEC_SRCS})
target_include_directories(webpdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webpdspdecode OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS})
target_include_directories(webpdspdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webputilsdecode OBJECT ${WEBP_UTILS_COMMON_SRCS}
${WEBP_UTILS_DEC_SRCS})
target_include_directories(webputilsdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(
webpdecoder $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdspdecode>
$<TARGET_OBJECTS:webputilsdecode>)
if(XCODE)
libwebp_add_stub_file(webpdecoder)
endif()
target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES})
target_include_directories(
webpdecoder
PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}>"
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
set_target_properties(
webpdecoder
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/libwebpdecoder.pc")
# Build the webp library.
add_library(webpencode OBJECT ${WEBP_ENC_SRCS})
target_include_directories(
webpencode PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src)
add_library(webpdsp OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS}
${WEBP_DSP_ENC_SRCS})
target_include_directories(webpdsp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webputils OBJECT ${WEBP_UTILS_COMMON_SRCS} ${WEBP_UTILS_DEC_SRCS}
${WEBP_UTILS_ENC_SRCS})
target_include_directories(webputils PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webp $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdsp>
$<TARGET_OBJECTS:webpencode> $<TARGET_OBJECTS:webputils>)
target_link_libraries(webp sharpyuv)
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 $<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;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/encode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
# Make sure the OBJECT libraries are built with position independent code (it is
# not ON by default).
set_target_properties(webpdecode webpdspdecode webputilsdecode webpencode
webpdsp webputils PROPERTIES POSITION_INDEPENDENT_CODE ON)
configure_pkg_config("src/libwebp.pc")
# Build the webp demux library.
add_library(webpdemux ${WEBP_DEMUX_SRCS})
target_link_libraries(webpdemux webp)
target_include_directories(
webpdemux PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
PUBLIC $<INSTALL_INTERFACE:include>)
set_target_properties(
webpdemux
PROPERTIES
PUBLIC_HEADER
"${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/demux.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/demux/libwebpdemux.pc")
set_version(src/Makefile.am webp webp)
set_version(src/Makefile.am webpdecoder webpdecoder)
set_version(src/demux/Makefile.am webpdemux webpdemux)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE)
string(REGEX MATCH
"AC_INIT\\([^\n]*\\[[0-9\\.]+\\]"
TMP
${CONFIGURE_FILE})
string(REGEX MATCH
"[0-9\\.]+"
PROJECT_VERSION
${TMP})
string(REGEX MATCH "AC_INIT\\([^\n]*\\[[0-9\\.]+\\]" TMP ${CONFIGURE_FILE})
string(REGEX MATCH "[0-9\\.]+" PROJECT_VERSION ${TMP})
# Define the libraries to install.
list(APPEND INSTALLED_LIBRARIES webpdecoder webp webpdemux)
@ -421,10 +455,8 @@ math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE
foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
list(GET WEBP_SIMD_FILES_TO_INCLUDE ${I_FILE} FILE)
list(GET WEBP_SIMD_FLAGS_TO_INCLUDE ${I_FILE} SIMD_COMPILE_FLAG)
set_source_files_properties(${FILE}
PROPERTIES
COMPILE_FLAGS
${SIMD_COMPILE_FLAG})
set_source_files_properties(${FILE} PROPERTIES COMPILE_FLAGS
${SIMD_COMPILE_FLAG})
endforeach()
if(NOT WEBP_BUILD_LIBWEBPMUX)
@ -445,6 +477,8 @@ endif()
if(WEBP_BUILD_ANIM_UTILS
OR WEBP_BUILD_CWEBP
OR WEBP_BUILD_DWEBP
OR WEBP_BUILD_EXTRAS
OR WEBP_BUILD_FUZZTEST
OR WEBP_BUILD_GIF2WEBP
OR WEBP_BUILD_IMG2WEBP
OR WEBP_BUILD_VWEBP
@ -456,8 +490,7 @@ if(WEBP_BUILD_ANIM_UTILS
list(APPEND EXAMPLEUTIL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
add_library(exampleutil STATIC ${EXAMPLEUTIL_SRCS})
target_include_directories(
exampleutil
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
exampleutil PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEIOUTILS_SRCS"
"imageio_util_[^ ]*")
@ -469,10 +502,7 @@ if(WEBP_BUILD_ANIM_UTILS
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEDEC_SRCS"
"imagedec_[^ ]*")
add_library(imagedec STATIC ${IMAGEDEC_SRCS})
target_link_libraries(imagedec
imageioutil
webpdemux
webp
target_link_libraries(imagedec imageioutil webpdemux webp
${WEBP_DEP_IMG_LIBRARIES})
# Image-encoding utility library.
@ -481,12 +511,12 @@ if(WEBP_BUILD_ANIM_UTILS
add_library(imageenc STATIC ${IMAGEENC_SRCS})
target_link_libraries(imageenc imageioutil webp)
set_property(TARGET exampleutil
imageioutil
imagedec
imageenc
PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src)
set_property(
TARGET exampleutil imageioutil imagedec imageenc
PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src)
target_include_directories(imagedec PRIVATE ${WEBP_DEP_IMG_INCLUDE_DIRS})
target_include_directories(imageenc PRIVATE ${WEBP_DEP_IMG_INCLUDE_DIRS})
endif()
if(WEBP_BUILD_DWEBP)
@ -503,7 +533,8 @@ if(WEBP_BUILD_CWEBP)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "CWEBP_SRCS" "cwebp")
add_executable(cwebp ${CWEBP_SRCS})
target_link_libraries(cwebp exampleutil imagedec webp)
target_include_directories(cwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
target_include_directories(cwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
@ -511,13 +542,12 @@ 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})
set_version(mux/Makefile.am libwebpmux webpmux)
set_target_properties(libwebpmux
PROPERTIES PUBLIC_HEADER
"${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
target_include_directories(libwebpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
set_version(src/mux/Makefile.am libwebpmux webpmux)
set_target_properties(
libwebpmux
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h;")
set_target_properties(libwebpmux PROPERTIES OUTPUT_NAME webpmux)
@ -531,13 +561,10 @@ if(WEBP_BUILD_GIF2WEBP)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "GIF2WEBP_SRCS"
"gif2webp")
add_executable(gif2webp ${GIF2WEBP_SRCS})
target_link_libraries(gif2webp
exampleutil
imageioutil
webp
libwebpmux
target_link_libraries(gif2webp exampleutil imageioutil webp libwebpmux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(gif2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
target_include_directories(gif2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS gif2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
@ -547,13 +574,10 @@ if(WEBP_BUILD_IMG2WEBP)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "IMG2WEBP_SRCS"
"img2webp")
add_executable(img2webp ${IMG2WEBP_SRCS})
target_link_libraries(img2webp
exampleutil
imagedec
imageioutil
webp
target_link_libraries(img2webp exampleutil imagedec imageioutil webp
libwebpmux)
target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS img2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
@ -564,17 +588,17 @@ if(WEBP_BUILD_VWEBP)
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "VWEBP_SRCS" "vwebp")
add_executable(vwebp ${VWEBP_SRCS})
target_link_libraries(vwebp
${OPENGL_LIBRARIES}
exampleutil
${GLUT_glut_LIBRARY}
imageioutil
webp
webpdemux)
target_include_directories(vwebp
PRIVATE ${GLUT_INCLUDE_DIR}
${CMAKE_CURRENT_BINARY_DIR}/src
${OPENGL_INCLUDE_DIR})
target_link_libraries(
vwebp
${OPENGL_LIBRARIES}
exampleutil
GLUT::GLUT
imageioutil
webp
webpdemux)
target_include_directories(
vwebp PRIVATE ${GLUT_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src
${OPENGL_INCLUDE_DIR})
install(TARGETS vwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
check_c_compiler_flag("-Wno-deprecated-declarations" HAS_NO_DEPRECATED)
@ -592,9 +616,8 @@ if(WEBP_BUILD_WEBPINFO)
"webpinfo")
add_executable(webpinfo ${WEBPINFO_SRCS})
target_link_libraries(webpinfo exampleutil imageioutil)
target_include_directories(webpinfo
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/src)
target_include_directories(webpinfo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/src)
install(TARGETS webpinfo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
@ -617,66 +640,99 @@ if(WEBP_BUILD_EXTRAS)
# libextras
add_library(extras STATIC ${WEBP_EXTRAS_SRCS})
target_include_directories(extras
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src)
target_include_directories(
extras PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src)
# get_disto
add_executable(get_disto ${GET_DISTO_SRCS})
target_link_libraries(get_disto imagedec)
target_include_directories(get_disto
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}/src)
target_include_directories(get_disto PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}/src)
# webp_quality
add_executable(webp_quality ${WEBP_QUALITY_SRCS})
target_link_libraries(webp_quality exampleutil imagedec extras)
target_include_directories(webp_quality
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(webp_quality PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR})
# vwebp_sdl
find_package(SDL)
if(WEBP_BUILD_VWEBP AND SDL_FOUND)
find_package(SDL2 QUIET)
if(WEBP_BUILD_VWEBP AND SDL2_FOUND)
add_executable(vwebp_sdl ${VWEBP_SDL_SRCS})
target_link_libraries(vwebp_sdl ${SDL_LIBRARY} imageioutil webp)
target_include_directories(vwebp_sdl
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/src
${SDL_INCLUDE_DIR})
target_link_libraries(vwebp_sdl ${SDL2_LIBRARIES} imageioutil webp)
target_include_directories(
vwebp_sdl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/src ${SDL2_INCLUDE_DIRS})
set(WEBP_HAVE_SDL 1)
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
set(CMAKE_REQUIRED_INCLUDES "${SDL2_INCLUDE_DIRS}")
check_c_source_compiles(
"
#define SDL_MAIN_HANDLED
#include \"SDL.h\"
int main(void) {
return 0;
}
"
HAVE_JUST_SDL_H)
set(CMAKE_REQUIRED_INCLUDES)
if(HAVE_JUST_SDL_H)
target_compile_definitions(vwebp_sdl PRIVATE WEBP_HAVE_JUST_SDL_H)
endif()
endif()
endif()
if(WEBP_BUILD_WEBP_JS)
# The default stack size changed from 5MB to 64KB in 3.1.27. See
# https://crbug.com/webp/614.
if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "3.1.27")
# TOTAL_STACK size was renamed to STACK_SIZE in 3.1.27. The old name was
# kept for compatibility, but prefer the new one in case it is removed in
# the future.
set(emscripten_stack_size "-sSTACK_SIZE=5MB")
else()
set(emscripten_stack_size "-sTOTAL_STACK=5MB")
endif()
find_package(SDL2 REQUIRED)
# wasm2js does not support SIMD.
if(NOT WEBP_ENABLE_SIMD)
# JavaScript version
add_executable(webp_js ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
target_link_libraries(webp_js webpdecoder SDL)
target_link_libraries(webp_js webpdecoder SDL2)
target_include_directories(webp_js PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set(WEBP_HAVE_SDL 1)
set_target_properties(
webp_js
PROPERTIES LINK_FLAGS "-s WASM=0 \
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
-s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
PROPERTIES
# Emscripten puts -sUSE_SDL2=1 in this variable, though it's needed at
# compile time to ensure the headers are downloaded.
COMPILE_OPTIONS "${SDL2_LIBRARIES}"
LINK_FLAGS
"-sWASM=0 ${emscripten_stack_size} \
-sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
-sEXPORTED_RUNTIME_METHODS=cwrap ${SDL2_LIBRARIES} \
-sALLOW_MEMORY_GROWTH")
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
endif()
# WASM version
add_executable(webp_wasm ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
target_link_libraries(webp_wasm webpdecoder SDL)
target_link_libraries(webp_wasm webpdecoder SDL2)
target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(
webp_wasm
PROPERTIES LINK_FLAGS "-s WASM=1 \
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
-s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
PROPERTIES
# Emscripten puts -sUSE_SDL2=1 in this variable, though it's needed at
# compile time to ensure the headers are downloaded.
COMPILE_OPTIONS "${SDL2_LIBRARIES}"
LINK_FLAGS
"-sWASM=1 ${emscripten_stack_size} \
-sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
-sEXPORTED_RUNTIME_METHODS=cwrap ${SDL2_LIBRARIES} \
-sALLOW_MEMORY_GROWTH")
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
@ -688,14 +744,15 @@ if(WEBP_BUILD_ANIM_UTILS)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DIFF_SRCS"
"anim_diff")
add_executable(anim_diff ${ANIM_DIFF_SRCS})
target_link_libraries(anim_diff
exampleutil
imagedec
imageenc
imageioutil
webp
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_link_libraries(
anim_diff
exampleutil
imagedec
imageenc
imageioutil
webp
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
# anim_dump
@ -703,49 +760,63 @@ if(WEBP_BUILD_ANIM_UTILS)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DUMP_SRCS"
"anim_dump")
add_executable(anim_dump ${ANIM_DUMP_SRCS})
target_link_libraries(anim_dump
exampleutil
imagedec
imageenc
imageioutil
webp
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_link_libraries(
anim_dump
exampleutil
imagedec
imageenc
imageioutil
webp
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
endif()
if(WEBP_BUILD_FUZZTEST)
add_subdirectory(tests/fuzzer)
endif()
# Install the different headers and libraries.
install(TARGETS ${INSTALLED_LIBRARIES}
EXPORT ${PROJECT_NAME}Targets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(
TARGETS ${INSTALLED_LIBRARIES}
EXPORT ${PROJECT_NAME}Targets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
set(ConfigPackageLocation ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake/)
install(EXPORT ${PROJECT_NAME}Targets
NAMESPACE ${PROJECT_NAME}::
install(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}::
DESTINATION ${ConfigPackageLocation})
# Create the CMake version file.
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
VERSION ${PACKAGE_VERSION}
COMPATIBILITY AnyNewerVersion)
VERSION ${PACKAGE_VERSION} COMPATIBILITY AnyNewerVersion)
# Create the Config file.
include(CMakePackageConfigHelpers)
# Fix libwebpmux reference. The target name libwebpmux is used for
# compatibility purposes, but the library mentioned in WebPConfig.cmake should
# be the unprefixed version.
list(TRANSFORM INSTALLED_LIBRARIES REPLACE "libwebpmux" "webpmux")
# Fix libwebpmux reference. The target name libwebpmux is used for compatibility
# purposes, but the library mentioned in WebPConfig.cmake should be the
# unprefixed version. Note string(...) can be replaced with list(TRANSFORM ...)
# if cmake_minimum_required is >= 3.12.
string(REGEX REPLACE "libwebpmux" "webpmux" INSTALLED_LIBRARIES
"${INSTALLED_LIBRARIES}")
if(MSVC)
# For compatibility with nmake, MSVC builds use a custom prefix (lib) that
# needs to be included in the library name.
string(REGEX REPLACE "[A-Za-z0-9_]+" "${CMAKE_STATIC_LIBRARY_PREFIX}\\0"
INSTALLED_LIBRARIES "${INSTALLED_LIBRARIES}")
endif()
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/WebPConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake
INSTALL_DESTINATION
${ConfigPackageLocation})
INSTALL_DESTINATION ${ConfigPackageLocation}
PATH_VARS CMAKE_INSTALL_INCLUDEDIR)
# Install the generated CMake files.
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
@ -777,7 +848,6 @@ foreach(I_MAN RANGE ${MAN_PAGES_RANGE})
if(WEBP_BUILD_${EXEC_BUILD})
list(GET MAN_PAGES ${I_MAN} MAN_PAGE)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man/${MAN_PAGE}
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
COMPONENT doc)
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT doc)
endif()
endforeach()

View File

@ -19,10 +19,59 @@ again.
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
https://chromium-review.googlesource.com for this purpose.
## Sending patches
The basic git workflow for modifying libwebp code and sending for review is:
1. Get the latest version of the repository locally:
```sh
git clone https://chromium.googlesource.com/webm/libwebp && cd libwebp
```
2. Copy the commit-msg script into ./git/hooks (this will add an ID to all of
your commits):
```sh
curl -Lo .git/hooks/commit-msg https://chromium-review.googlesource.com/tools/hooks/commit-msg && chmod u+x .git/hooks/commit-msg
```
3. Modify the local copy of libwebp. Make sure the code
[builds successfully](https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/building.md#cmake).
4. Choose a short and representative commit message:
```sh
git commit -a -m "Set commit message here"
```
5. Send the patch for review:
```sh
git push https://chromium-review.googlesource.com/webm/libwebp HEAD:refs/for/main
```
Go to https://chromium-review.googlesource.com to view your patch and
request a review from the maintainers.
See the
[WebM Project page](https://www.webmproject.org/code/contribute/submitting-patches/)
for additional details.
## Code Style
The C code style is based on the
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and
`clang-format --style=Google`, though this project doesn't use the tool to
enforce the formatting.
CMake files are formatted with
[cmake-format](https://cmake-format.readthedocs.io/en/latest/). `cmake-format
-i` can be used to format individual files, it will use the settings from
`.cmake-format.py`.
## Community Guidelines
This project follows

512
ChangeLog
View File

@ -1,8 +1,516 @@
c3d85ce4 update NEWS
ad14e811 tests/fuzzer/*: add missing <string_view> include
74cd026e fuzz_utils.cc: fix build error w/WEBP_REDUCE_SIZE
a027aa93 mux_demux_api_fuzzer.cc: fix -Wshadow warning
25e17c68 update ChangeLog (tag: v1.5.0-rc1)
aa2684fc update NEWS
36923846 bump version to 1.5.0
ceea8ff6 update AUTHORS
e4f7a9f0 img2webp: add a warning for unused options
1b4c967f Merge "Properly check the data size against the end of the RIFF chunk" into main
9e5ecfaf Properly check the data size against the end of the RIFF chunk
da0d9c7d examples: exit w/failure w/no args
fcff86c7 {gif,img}2webp: sync -m help w/cwebp
b76c4a84 man/img2webp.1: sync -m text w/cwebp.1 & gif2webp.1
30633519 muxread: fix reading of buffers > riff size
4c85d860 yuv.h: update RGB<->YUV coefficients in comment
0ab789e0 Merge changes I6dfedfd5,I2376e2dc into main
03236450 {ios,xcframework}build.sh: fix compilation w/Xcode 16
61e2cfda rework AddVectorEq_SSE2
7bda3deb rework AddVector_SSE2
2ddaaf0a Fix variable names in SharpYuvComputeConversionMatrix
a3ba6f19 Makefile.vc: fix gif2webp link error
f999d94f gif2webp: add -sharp_yuv/-near_lossless
dfdcb7f9 Merge "lossless.h: fix function declaration mismatches" into main (tag: webp-rfc9649)
78ed6839 fix overread in Intra4Preds_NEON
d516a68e lossless.h: fix function declaration mismatches
87406904 Merge "Improve documentation of SharpYuvConversionMatrix." into main
fdb229ea Merge changes I07a7e36a,Ib29980f7,I2316122d,I2356e314,I32b53dd3, ... into main
0c3cd9cc Improve documentation of SharpYuvConversionMatrix.
169dfbf9 disable Intra4Preds_NEON
2dd5eb98 dsp/yuv*: use WEBP_RESTRICT qualifier
23bbafbe dsp/upsampling*: use WEBP_RESTRICT qualifier
35915b38 dsp/rescaler*: use WEBP_RESTRICT qualifier
a32b436b dsp/lossless*: use WEBP_RESTRICT qualifier
04d4b4f3 dsp/filters*: use WEBP_RESTRICT qualifier
b1cb37e6 dsp/enc*: use WEBP_RESTRICT qualifier
201894ef dsp/dec*: use WEBP_RESTRICT qualifier
02eac8a7 dsp/cost*: use WEBP_RESTRICT qualifier
84b118c9 Merge "webp-container-spec: normalize notes & unknown chunk link" into main
052cf42f webp-container-spec: normalize notes & unknown chunk link
220ee529 Search for best predictor transform bits
78619478 Try to reduce the sampling for the entropy image
14f09ab7 webp-container-spec: reorder chunk size - N text
a78c5356 Remove a useless malloc for entropy image
bc491763 Merge "Refactor predictor finding" into main
34f92238 man/{cwebp,img2webp}.1: rm 'if needed' from -sharp_yuv
367ca938 Refactor predictor finding
a582b53b webp-lossless-bitstream-spec: clarify some text
0fd25d84 Merge "anim_encode.c: fix function ref in comment" into main
f8882913 anim_encode.c: fix function ref in comment
40e4ca60 specs_generation.md: update kramdown command line
57883c78 img2webp: add -exact/-noexact per-frame options
1c8eba97 img2webp,cosmetics: add missing '.' spacers to help
2e81017c Convert predictor_enc.c to fixed point
94de6c7f Merge "Fix fuzztest link errors w/-DBUILD_SHARED_LIBS=1" into main
51d9832a Fix fuzztest link errors w/-DBUILD_SHARED_LIBS=1
7bcb36b8 Merge "Fix static overflow warning." into main
8e0cc14c Fix static overflow warning.
cea68462 README.md: add security report note
615e5874 Merge "make VP8LPredictor[01]_C() static" into main
233e86b9 Merge changes Ie43dc5ef,I94cd8bab into main
1a29fd2f make VP8LPredictor[01]_C() static
dd9d3770 Do*Filter_*: remove row & num_rows parameters
ab451a49 Do*Filter_C: remove dead 'inverse' code paths
f9a480f7 {TrueMotion,TM16}_NEON: remove zero extension
04834aca Merge changes I25c30a9e,I0a192fc6,I4cf89575 into main
39a602af webp-lossless-bitstream-spec: normalize predictor transform ref
f28c837d Merge "webp-container-spec: align anim pseudocode w/prose" into main
74be8e22 Fix implicit conversion issues
0c01db7c Merge "Increase the transform bits if possible." into main
f2d6dc1e Increase the transform bits if possible.
caa19e5b update link to issue tracker
c9dd9bd4 webp-container-spec: align anim pseudocode w/prose
8a7c8dc6 WASM: Enable VP8L_USE_FAST_LOAD
f0c53cd9 WASM: don't use USE_GENERIC_TREE
eef903d0 WASM: Enable 64-bit BITS caching
6296cc8d iterator_enc: make VP8IteratorReset() static
fbd93896 histogram_enc: make VP8LGetHistogramSize static
cc7ff545 cost_enc: make VP8CalculateLevelCosts[] static
4e2828ba vp8l_dec: make VP8LClear() static
d742b24a Intra16Preds_NEON: fix truemotion saturation
c7bb4cb5 Intra4Preds_NEON: fix truemotion saturation
952a989b Merge "Remove TODO now that log is using fixed point." into main
dde11574 Remove TODO now that log is using fixed point.
a1ca153d Fix hidden myerr in my_error_exit
3bd94202 Merge changes Iff6e47ed,I24c67cd5,Id781e761 into main
d27d246e Merge "Convert VP8LFastSLog2 to fixed point" into main
4838611f Disable msg_code use in fuzzing mode
314a142a Use QuantizeBlock_NEON for VP8EncQuantizeBlockWHT on Arm
3bfb05e3 Add AArch64 Neon implementation of Intra16Preds
baa93808 Add AArch64 Neon implementation of Intra4Preds
41a5e582 Fix errors when compiling code as C++
fb444b69 Convert VP8LFastSLog2 to fixed point
c1c89f51 Fix WEBP_NODISCARD comment and C++ version
66408c2c Switch the histogram_enc.h API to fixed point
ac1e410d Remove leftover tiff dep
b78d3957 Disable TIFF on fuzztest.
cff21a7d Do not build statically on oss-fuzz.
6853a8e5 Merge "Move more internal fuzzers to public." into main
9bc09db4 Merge "Convert VP8LFastLog2 to fixed point" into main
0a9f1c19 Convert VP8LFastLog2 to fixed point
db0cb9c2 Move more internal fuzzers to public.
ff2b5b15 Merge "advanced_api_fuzzer.cc: use crop dims in OOM check" into main
c4af79d0 Put 0 at the end of a palette and do not store it.
0ec80aef Delete last references to delta palettization
96d79f84 advanced_api_fuzzer.cc: use crop dims in OOM check
c35c7e02 Fix huffman fuzzer to not leak.
f2fe8dec Bump fuzztest dependency.
9ce982fd Fix fuzz tests to work on oss-fuzz
3ba8af1a Do not escape quotes anymore in build.sh
ea0e121b Allow centipede to be used as a fuzzing engine.
27731afd make VP8I4ModeOffsets & VP8MakeIntra4Preds static
ddd6245e oss-fuzz/build.sh: use heredoc for script creation
50074930 oss-fuzz/build.sh,cosmetics: fix indent
20e92f7d Limit the possible fuzz engines.
4f200de5 Switch public fuzz tests to fuzztest.
64186bb3 Add huffman_fuzzer to .gitignore
0905f61c Move build script from oss-fuzz repo to here.
e8678758 Fix link to Javascript documentation
5e5b8f0c Fix SSE2 Transform_AC3 function name
45129ee0 Revert "Check all the rows."
ee26766a Check all the rows.
7ec51c59 Increase the transform bits if possible.
3cd16fd3 Revert "Increase the transform bits if possible."
971a03d8 Increase the transform bits if possible.
1bf198a2 Allow transform_bits to be different during encoding.
1e462ca8 Define MAX_TRANSFORM_BITS according to the specification.
64d1ec23 Use (MIN/NUM)_(TRANSFORM/HUFFMAN)_BITS where appropriate
a90160e1 Refactor histograms in predictors.
a7aa7525 Fix some function declarations
68ff4e1e Merge "jpegdec: add a hint for EOF/READ errors" into main
79e7968a jpegdec: add a hint for EOF/READ errors
d33455cd man/*: s/BUGS/REPORTING BUGS/
a67ff735 normalize example exit status
edc28909 upsampling_{neon,sse41}: fix int sanitizer warning
3cada4ce ImgIoUtilReadFile: check ftell() return
dc950585 Merge tag 'v1.4.0'
845d5476 update ChangeLog (tag: v1.4.0, origin/1.4.0)
8a6a55bb update NEWS
cf7c5a5d provide a way to opt-out/override WEBP_NODISCARD
cc34288a update ChangeLog (tag: v1.4.0-rc1)
f13c0886 NEWS: fix date
74555950 Merge "vwebp: fix window title when options are given" into 1.4.0
d781646c vwebp: fix window title when options are given
c2e394de update NEWS
f6d15cb7 bump version to 1.4.0
57c388b8 update AUTHORS
b3d1b2cb Merge changes I26f4aa22,I83386b6c,I320ed1a2 into main
07216886 webp-container-spec: fix VP8 chunk ref ('VP8'->'VP8 ')
f88666eb webp_js/*.html: fix canvas mapping
e2c8f233 cmake,wasm: simplify SDL2 related flags
d537cd37 cmake: fix vwebp_sdl compile w/libsdl-org release
6c484cbf CMakeLists.txt: add missing WEBP_BUILD_EXTRAS check
7b0bc235 man/cwebp.1: add more detail to -partition_limit
3c0011bb WebPMuxGetChunk: add an assert
955a3d14 Merge "muxread,MuxGet: add an assert" into main
00abc000 muxread,MuxGet: add an assert
40e85a0b Have the window title reflect the filename.
1bf46358 man/cwebp.1: clarify -pass > 1 behavior w/o -size/-psnr
eba03acb webp-container-spec: replace 'above' with 'earlier'
a16d30cb webp-container-spec: clarify chunk order requirements
8a7e9112 Merge "CMakeLists.txt: apply cmake-format" into main
7fac6c1b Merge "Copy C code to not have multiplication overflow" into main
e2922e43 Merge "Check for the presence of the ANDROID_ABI variable" into main
501d9274 Copy C code to not have multiplication overflow
fba7d62e CMakeLists.txt: apply cmake-format
661c1b66 Merge "windows exports: use dllexport attribute, instead of visibility." into main
8487860a windows exports: use dllexport attribute, instead of visibility.
8ea678b9 webp/mux.h: data lifetime note w/copy_data=0
79e05c7f Check for the presence of the ANDROID_ABI variable
45f995a3 Expose functions for managing non-image chunks on WebPAnimEncoder
1fb9f3dc gifdec: fix ErrorGIFNotAvailable() declaration
4723db65 cosmetics: s/SANITY_CHECK/DCHECK/
f4b9bc9e clear -Wextra-semi-stmt warnings
713982b8 Limit animdecoder_fuzzer to 320MB
cbe825e4 cmake: fix sharpyuv simd files' build
f99305e9 Makefile.vc: add ARM64 support
5efd6300 mv SharpYuvEstimate420Risk to extras/
e78e924f Makefile.vc: add sharpyuv_risk_table.obj
d7a0506d Add YUV420 riskiness metric.
89c5b917 Merge "BuildHuffmanTable check sorted[] array bounds before writing" into main
34c80749 Remove alpha encoding pessimization.
13d9c30b Add a WEBP_NODISCARD
24d7f9cb Switch code to SDL2.
0b56dedc BuildHuffmanTable check sorted[] array bounds before writing
a429c0de sharpyuv: convert some for() to do/while
f0cd7861 DoSharpArgbToYuv: remove constant from loop
339231cc SharpYuvConvertWithOptions,cosmetics: fix formatting
307071f1 Remove medium/large code model-specific inline asm
deadc339 Fix transfer functions where toGamma and toLinear are swapped.
e7b78d43 Merge "Fix bug in FromLinearLog100." into main
15a1309e Merge "webp-lossless-bitstream-spec: delete extra blank line" into main
54ca9752 Fix bug in FromLinearLog100.
d2cb2d8c Dereference after NULL check.
e9d50107 webp-lossless-bitstream-spec: delete extra blank line
78657971 Merge changes Ief442c90,Ie6e9c9a5 into main
e30a5884 webp-lossless-bitstream-spec: update variable names
09ca1368 Merge "webp-container-spec: change assert to MUST be TRUE" into main
38cb4fc0 iosbuild,xcframeworkbuild: add SharpYuv framework
40afa926 webp-lossless-bitstream-spec: simplify abstract
9db21143 webp-container-spec: change assert to MUST be TRUE
cdbf88ae Fix typo in API docs for incremental decoding
05c46984 Reformat vcpkg build instructions.
8534f539 Merge "Never send VP8_STATUS_SUSPENDED back in non-incremental." into main
35e197bd Never send VP8_STATUS_SUSPENDED back in non-incremental.
61441425 Add vcpkg installation instructions
dce8397f Fix next is invalid pointer when WebPSafeMalloc fails
57c58105 Cmake: wrong public macro WEBP_INCLUDE_DIRS
c1ffd9ac Merge "vp8l_enc: fix non-C90 code" into main
a3965948 Merge changes If628bb93,Ic79f6309,I45f0db23 into main
f80e9b7e vp8l_enc: fix non-C90 code
accd141d Update lossless spec for two simple codes.
ac17ffff Fix non-C90 code.
433c7dca Fix static analyzer warnings.
5fac76cf Merge tag 'v1.3.2'
ca332209 update ChangeLog (tag: v1.3.2)
1ace578c update NEWS
63234c42 bump version to 1.3.2
a35ea50d Add a fuzzer for ReadHuffmanCodes
95ea5226 Fix invalid incremental decoding check.
2af26267 Fix OOB write in BuildHuffmanTable.
902bc919 Fix OOB write in BuildHuffmanTable.
7ba44f80 Homogenize "__asm__ volatile" vs "asm volatile"
68e27135 webp-container-spec: reorder example chunk layout
943b932a Merge changes I6a4d0a04,Ibc37b91e into main
1cc94f95 decode.h: wrap idec example in /* */
63acdd1e decode.h: fix decode example
aac5c5d0 ReadHuffmanCode: rm redundant num code lengths check
a2de25f6 webp-lossless-bitstream-spec: normalize list item case
68820f0e webp-lossless-bitstream-spec: normalize pixel ref
cdb31aa8 webp-lossless-bitstream-spec: add missing periods
0535a8cf webp-lossless-bitstream-spec: fix grammar
b6c4ce26 normalize numbered list item format
dd7364c3 Merge "palette.c: fix msvc warnings" into main
c63c5df6 palette.c: fix msvc warnings
0a2cad51 webp-container-spec: move terms from intro section
dd88d2ff webp-lossless-bitstream-spec: color_cache -> color cache
6e750547 Merge changes I644d7d39,Icf05491e,Ic02e6652,I63b11258 into main
67a7cc2b webp-lossless-bitstream-spec: fix code blocks
1432ebba Refactor palette sorting computation.
cd436142 webp-lossless-bitstream-spec: block -> chunk
3cb66f64 webp-lossless-bitstream-spec: add some missing commas
56471a53 webp-lossless-bitstream-spec: normalize item text in 5.1
af7fbfd2 vp8l_dec,ReadTransform: improve error status reporting
7d8e0896 vp8l_dec: add VP8LSetError()
a71ce1cf animencoder_fuzzer: fix error check w/Nallocfuzz
e94b36d6 webp-lossless-bitstream-spec: relocate details from 5.1
84628e56 webp-lossless-bitstream-spec: clarify image width changes
ee722997 alpha_dec: add missing VP8SetError()
0081693d enc_dec_fuzzer: use WebPDecode()
0fcb311c enc_dec_fuzzer: fix WebPEncode/pic.error_code check
982c177c webp-lossless-bitstream-spec: fix struct member refs
56cf5625 webp-lossless-bitstream-spec: use RFC 7405 for ABNF
6c6b3fd3 webp-lossless-bitstream-spec,cosmetics: delete blank lines
29b9eb15 Merge changes Id56ca4fd,I662bd1d7 into main
47c0af8d ReadHuffmanCodes: rm max_alphabet_size calc
b92deba3 animencoder_fuzzer: no WebPAnimEncoderAssemble check w/nallocfuzz
6be9bf8b animencoder_fuzzer: fix leak on alloc failure
5c965e55 vp8l_dec,cosmetics: add some /*param=*/ comments
e4fc2f78 webp-lossless-bitstream-spec: add validity note for max_symbol
71916726 webp-lossless-bitstream-spec: fix max_symbol definition
eac3bd5c Have the palette code be in its own file.
e2c85878 Add an initializer for the SharpYuvOptions struct.
4222b006 Merge tag 'v1.3.1'
25d94f47 Implement more transfer functions in libsharpyuv
2153a679 Merge changes Id0300937,I5dba5ccf,I57bb68e0,I2dba7b4e,I172aca36, ... into main
4298e976 webp-lossless-bitstream-spec: add PredictorTransformOutput
cd7e02be webp-lossless-bitstream-spec: fix RIFF-header ABNF
6c3845f9 webp-lossless-bitstream-spec: split LZ77 Backward Ref section
7f1b6799 webp-lossless-bitstream-spec: split Meta Prefix Codes section
7b634d8f webp-lossless-bitstream-spec: note transform order
6d6d4915 webp-lossless-bitstream-spec: update transformations text
fd7bb21c update ChangeLog (tag: v1.3.1-rc2, tag: v1.3.1)
e1adea50 update NEWS
6b1c722a lossless_common.h,cosmetics: fix a typo
08d60d60 webp-lossless-bitstream-spec: split code length section
7a12afcc webp-lossless-bitstream-spec: rm unused anchor
43393320 enc/*: normalize WebPEncodingSetError() calls
287fdefe enc/*: add missing WebPEncodingSetError() calls
c3bd7cff EncodeAlphaInternal: add missing error check
14a9dbfb webp-lossless-bitstream-spec: refine single node text
64819c7c Implement ExtractGreen_SSE2
d49cfbb3 vp8l_enc,WriteImage: add missing error check
2e5a9ec3 muxread,MuxImageParse: add missing error checks
ebb6f949 cmake,emscripten: explicitly set stack size
59a2b1f9 WebPDecodeYUV: check u/v/stride/uv_stride ptrs
8e965ccb Call png_get_channels() to see if image has alpha
fe80fbbd webp-container-spec: add some missing commas
e8ed3176 Merge "treat FILTER_NONE as a regular Unfilter[] call" into main
03a7a048 webp-lossless-bitstream-spec: rm redundant statement
c437c7aa webp-lossless-bitstream-spec: mv up prefix code group def
e4f17a31 webp-lossless-bitstream-spec: fix section reference
e2ecd5e9 webp-lossless-bitstream-spec: clarify ABNF syntax
8b55425a webp-lossless-bitstream-spec: refine pixel copy text
29c9f2d4 webp-lossless-bitstream-spec: minor wording updates
6b02f660 treat FILTER_NONE as a regular Unfilter[] call
7f75c91c webp-container-spec: fix location of informative msg
f6499943 webp-container-spec: consistently quote FourCCs
49918af3 webp-container-spec: minor wording updates
7f0a3419 update ChangeLog (tag: v1.3.1-rc1)
bab7efbe update NEWS
7138bf8f bump version to 1.3.1
435b4ded update AUTHORS
47351229 update .mailmap
46bc4fc9 Merge "Switch ExtraCost to ints and implement it in SSE." into main
828b4ce0 Switch ExtraCost to ints and implement it in SSE.
ff6c7f4e CONTRIBUTING.md: add C style / cmake-format notes
dd530437 add .cmake-format.py
adbe2cb1 cmake,cosmetics: apply cmake-format
15b36508 doc/webp-container-spec: rm future codec comment
c369c4bf doc/webp-lossless-bitstream-spec: improve link text
1de35f47 doc/webp-container-spec: don't use 'currently'
bb06a16e doc/webp-container-spec: prefer present tense
9f38b71e doc/webp-lossless-bitstream-spec: prefer present tense
7acb6b82 doc/webp-container-spec: avoid i.e. & e.g.
4967e7cd doc/webp-lossless-bitstream-spec: avoid i.e. & e.g.
e3366659 Merge "Do not find_package image libraries if not needed." into main
428588ef clarify single leaf node trees and use of canonical prefix coding
709ec152 Do not find_package image libraries if not needed.
8dd80ef8 fuzz_utils.h: lower kFuzzPxLimit w/ASan
8f187b9f Clean message calls in CMake
cba30078 WebPConfig.cmake.in: use calculated include path
6cf9a76a Merge "webp-lossless-bitstream-spec: remove use of 'dynamics'" into main
740943b2 Merge "Specialize and optimize ITransform_SSE2 using do_two" into main
2d547e24 Compare kFuzzPxLimit to max_num_operations
ac42dde1 Specialize and optimize ITransform_SSE2 using do_two
17e0ef1d webp-lossless-bitstream-spec: remove use of 'dynamics'
ed274371 neon.h,cosmetics: clear a couple lint warnings
3fb82947 cpu.h,cosmetics: segment defines
0c496a4f cpu.h: add WEBP_AARCH64
8151f388 move VP8GetCPUInfo declaration to cpu.c
916548c2 Make kFuzzPxLimit sanitizer dependent
4070b271 advanced_api_fuzzer: reduce scaling limit
761f49c3 Merge "webp-lossless-bitstream-spec: add missing bits to ABNF" into main
84d04c48 webp-lossless-bitstream-spec: add missing bits to ABNF
0696e1a7 advanced_api_fuzzer: reduce scaling limit
93d88aa2 Merge "deps.cmake: remove unneeded header checks" into main
118e0035 deps.cmake: remove unneeded header checks
4c3d7018 webp-lossless-bitstream-spec: condense normal-prefix-code
a6a09b32 webp-lossless-bitstream-spec: fix 2 code typos
50ac4f7c Merge "cpu.h: enable NEON w/_M_ARM64EC" into main
4b7d7b4f Add contribution instructions
0afbd97b cpu.h: enable NEON w/_M_ARM64EC
349f4353 Merge changes Ibd89e56b,Ic57e7f84,I89096614 into main
8f7513b7 upsampling_neon.c: fix WEBP_SWAP_16BIT_CSP check
cbf624b5 advanced_api_fuzzer: reduce scaling limit
89edfdd1 Skip slow scaling in libwebp advanced_api_fuzzer
859f19f7 Reduce libwebp advanced_api_fuzzer threshold
a4f04835 Merge changes Ic389aaa2,I329ccd79 into main
1275fac8 Makefile.vc: fix img2webp link w/dynamic cfg
2fe27bb9 img2webp: normalize help output
24bed3d9 cwebp: reflow -near_lossless help text
0825faa4 img2webp: add -sharp_yuv/-near_lossless
d64e6d7d Merge "PaletteSortModifiedZeng: fix leak on error" into main
0e12a22d Merge "EncodeAlphaInternal: clear result->bw on error" into main
0edbb6ea PaletteSortModifiedZeng: fix leak on error
41ffe04e Merge "Update yapf style from "chromium" to "yapf"" into main
2d9d9265 Update yapf style from "chromium" to "yapf"
a486d800 EncodeAlphaInternal: clear result->bw on error
1347a32d Skip big scaled advanced_api_fuzzer
52b6f067 Fix scaling limit in advanced_api_fuzzer.c
73618428 Limit scaling in libwebp advanced_api_fuzzer.c
b54d21a0 Merge "CMakeLists.txt: allow CMAKE_INSTALL_RPATH to be set empty" into main
31c28db5 libwebp{,demux,mux}.pc.in: Requires -> Requires.private
d9a505ff CMakeLists.txt: allow CMAKE_INSTALL_RPATH to be set empty
bdf33d03 Merge tag 'v1.3.0'
b5577769 update ChangeLog (tag: v1.3.0-rc1, tag: v1.3.0)
0ba77244 update NEWS
e763eb1e bump version to 1.3.0
2a8686fc update AUTHORS
106a57c1 Merge "*/Android.mk: add a check for NDK_ROOT" into main
c5e841c4 Merge "extras: WebpToSDL -> WebPToSDL" into main
dbc30715 Merge "xcframeworkbuild.sh: bump MACOSX_CATALYST_MIN_VERSION" into main
6fc1a9f9 */Android.mk: add a check for NDK_ROOT
d3e151fc doc/api.md,webp_js/README.md: Webp -> WebP
ed92a626 extras: WebpToSDL -> WebPToSDL
6eb0189b xcframeworkbuild.sh: bump MACOSX_CATALYST_MIN_VERSION
1d58575b CMake: align .pc variables with autoconf
e5fe2cfc webp-lossless-bitstream-spec,cosmetics: reflow paragraphs
0ceeeab9 webp-lossless-bitstream-spec: add amendment note
607611cd Merge "webp-container-spec: normalize section title case" into main
f853685e lossless: SUBTRACT_GREEN -> SUBTRACT_GREEN_TRANSFORM
786497e4 webp-lossless-bitstream-spec: fix inv color txfm description
c6ac672d webp-lossless-bitstream-spec: fix num_code_lengths check
b5700efb webp-lossless-bitstream-spec,cosmetics: grammar/capitalization
d8ed8c11 webp-container-spec: normalize section title case
52ec0b8f Merge changes Ie975dbb5,Ifc8c93af,I6ca7c5d6,I2e8d66f5,I152477b8 into main
5097ef62 webp-container-spec,cosmetics: grammar/capitalization
e3ba2b1f webp-lossless-bitstream-spec,cosmetics: reflow abstract
1e8e3ded webp-lossless-bitstream-spec: reword abstract re alpha
017cb6fa webp-container-spec,cosmetics: normalize range syntax
f6a4684b webp-lossless-bitstream-spec,cosmetics: normalize range syntax
54ebd5a3 webp-lossless-bitstream-spec: limit dist map lut to 69 cols
44741f9c webp-lossless-bitstream-spec: fix dist mapping example
fad0ece7 pnmdec.c: use snprintf instead of sprintf
3f73e8f7 sharpyuv: add SharpYuvGetVersion()
ce2f2d66 SharpYuvConvert: fix a race on SharpYuvGetCPUInfo
a458e308 sharpyuv_dsp.h: restore sharpyuv_cpu.h include
9ba800a7 Merge changes Id72fbf3b,Ic59d23a2 into main
979c0ebb sharpyuv: add SharpYuvGetCPUInfo
8bab09a4 Merge "*.pc.in: rename lib_prefix to webp_libname_prefix" into main
769387c5 cpu.c,cosmetics: fix a typo
a02978c2 sharpyuv/Makefile.am+cmake: add missing -lm
28aedcb9 *.pc.in: rename lib_prefix to webp_libname_prefix
c42e6d5a configure.ac: export an empty lib_prefix variable
dfc843aa Merge "*.pc.in: add lib prefix to lib names w/MSVC" into main
2498209b *.pc.in: add lib prefix to lib names w/MSVC
ac252b61 Merge "analysis_enc.c: fix a dead store warning" into main
56944762 analysis_enc.c: fix a dead store warning
d34f9b99 Merge "webp-lossless-bitstream-spec: convert BNF to ABNF" into main
dc05b4db Merge changes I96bc063c,I45880467,If9e18e5a,I6ee938e4,I0a410b28, ... into main
83270c7f webp-container-spec: add prose for rendering process
73b19b64 webp-container-spec: note reserved fields MUST be ignored
57101d3f webp-lossless-bitstream-spec: improve 'small' color table stmt
dfd32e45 webp-container-spec: remove redundant sentence
8a6185dd doc/webp-*: fix some punctuation, grammar
72776530 webp-lossless-bitstream-spec: convert BNF to ABNF
d992bb08 cmake: rename cpufeatures target to cpufeatures-webp
3ed2b275 webp-container-spec: clarify background color note
951c292d webp-container-spec: come too late -> out of order
902dd787 webp-container-spec: prefer hex literals
a8f6b5ee webp-container-spec: change SHOULD to MUST w/ANIM chunk
1dc59435 webp-container-spec: add unknown fields MUST be ignored
280a810f webp-container-spec: make padding byte=0 a MUST
41f0bf68 webp-container-spec: update note on trailing data
6bdd36db webp-container-spec: clarify Chunk Size is in bytes
87e36c48 Merge "webp_js/README.md,cosmetics: reflow some lines" into main
5b01f321 Merge "Update Windows makefile to build libsharpyuv library." into main
19b1a71c webp_js/README.md,cosmetics: reflow some lines
780db756 Update Windows makefile to build libsharpyuv library.
e407d4b3 CMakeLists.txt: replace GLUT_glut_LIBRARY w/GLUT::GLUT
abf73d62 Merge "WebPConfig.cmake.in: add find_dependency(Threads)" into main
25807fb4 Merge "cmake: restore compatibility with cmake < 3.12" into main
5dbc4bfa WebPConfig.cmake.in: add find_dependency(Threads)
b2a175dd Merge "Update wasm instructions." into main
cb90f76b Update wasm instructions.
02d15258 cmake: restore compatibility with cmake < 3.12
5ba046e2 CMake: add_definitions -> add_compile_options
e68765af dsp,neon: use vaddv in a few more places
e8f83de2 Set libsharpyuv include dir to 'webp' subdirectory.
15a91ab1 cmake,cosmetics: apply cmake-format
0dd49d1a CMakeLists.txt: set @ONLY in configure_file() calls
62b1bfe8 Merge changes I2877e7bb,I777cad70,I15af7d1a,I686e6740,If10538a9, ... into main
95c8fe5f Merge changes Iecea3603,I9dc228ab into main
e7c805cf picture_csp_enc.c: remove SafeInitSharpYuv
6af8845a sharpyuv: prefer webp/types.h
639619ce cmake: fix dll exports
782ed48c sharpyuv,SharpYuvInit: add mutex protection when available
cad0d5ad sharyuv_{neon,sse2}.c: merge WEBP_USE_* sections
ef70ee06 add a few missing <stddef.h> includes for NULL
f0f9eda4 sharpyuv.h: remove <inttypes.h>
9b902cba Merge "picture_csp_enc.c,CheckNonOpaque: rm unneeded local" into main
9c1d457c cmake/cpu.cmake: remove unused variable
9ac25bcb CMakeLists.txt,win32: match naming convention used by nmake
76c353ba picture_csp_enc.c,CheckNonOpaque: rm unneeded local
5000de54 Merge "cwebp: fix WebPPictureHasTransparency call" into main
e1729309 Merge "WebPPictureHasTransparency: add missing pointer check" into main
00ff988a vp8l_enc,AddSingleSubGreen: clear int sanitizer warnings
e2fecc22 dsp/lossless_enc.c: clear int sanitizer warnings
129cf9e9 dsp/lossless.c: clear int sanitizer warnings
ad7d1753 dsp/lossless_enc.c: clear int sanitizer warnings
5037220e VP8LSubtractGreenFromBlueAndRed_C: clear int sanitizer warnings
2ee786c7 upsampling_sse2.c: clear int sanitizer warnings
4cc157d4 ParseOptionalChunks: clear int sanitizer warning
892cf033 BuildHuffmanTable: clear int sanitizer warning
3a9a4d45 VP8GetSigned: clear int sanitizer warnings
704a3d0a dsp/lossless.c: quiet int sanitizer warnings
1a6c109c WebPPictureHasTransparency: add missing pointer check
c626e7d5 cwebp: fix WebPPictureHasTransparency call
866e349c Merge tag 'v1.2.4'
c170df38 Merge "Create libsharpyuv.a in makefile.unix." into main
9d7ff74a Create libsharpyuv.a in makefile.unix.
0d1f1254 update ChangeLog (tag: v1.2.4)
fcbc2d78 Merge "doc/*.txt: restrict code to 69 columns" into main
4ad0e189 Merge "webp-container-spec.txt: normalize fourcc spelling" into main
980d2488 update NEWS
9fde8127 bump version to 1.2.4
7a0a9935 doc/*.txt: restrict code to 69 columns
c040a615 webp-container-spec.txt: normalize fourcc spelling
aff1c546 dsp,x86: normalize types w/_mm_cvtsi128_si32 calls
ab540ae0 dsp,x86: normalize types w/_mm_cvtsi32_si128 calls
8980362e dsp,x86: normalize types w/_mm_set* calls (2)
e626925c lossless: fix crunch mode w/WEBP_REDUCE_SIZE
83539239 dsp,x86: normalize types w/_mm_set* calls
8a4576ce webp-container-spec.txt: replace &amp; with &
db870881 Merge "webp-container-spec.txt: make reserved 0 values a MUST" into main
01d7d378 webp-lossless-bitstream-spec: number all sections
337cf69f webp-lossless-bitstream-spec: mv Nomenclature after Intro
79be856e Merge changes I7111d1f7,I872cd62c into main
5b87983a webp-container-spec.txt: make reserved 0 values a MUST
bd939123 Merge changes I7a25b1a6,I51b2c2a0,I87d0cbcf,I6ec60af6,I0a3fe9dc into main
04764b56 libwebp.pc: add libsharpyuv to requires
7deee810 libsharpyuv: add pkg-config file
1a64a7e6 webp-container-spec.txt: clarify some SHOULDs
bec2c88a webp-container-spec.txt: move ChunkHeader to terminology
c9359332 webp-container-spec.txt: clarify 'VP8 '/'XMP ' fourccs
70fe3063 webp-container-spec.txt: rightsize table entries
ddbf3f3f webp-container-spec.txt: update 'key words' text
c151e95b utils.h,WEBP_ALIGN: make bitmask unsigned
748e92bb add WebPInt32ToMem
3fe15b67 Merge "Build libsharpyuv as a full installable library." into main
4f402f34 add WebPMemToInt32
a3b68c19 Build libsharpyuv as a full installable library.
b4994eaa CMake: set rpath for shared objects
94cd7117 Merge "CMake: fix dylib versioning" into main
e91451b6 Fix the lossless specs a bit more.
231bdfb7 CMake: fix dylib versioning
bfad7ab5 CMakeLists.txt: correct libwebpmux name in WebPConfig.cmake
c2e3fd30 Revert "cmake: fix webpmux lib name for cmake linking"
7366f7f3 Merge "lossless: fix crunch mode w/WEBP_REDUCE_SIZE" into main
84163d9d lossless: fix crunch mode w/WEBP_REDUCE_SIZE
d01c1eb3 webp-lossless-bitstream-spec,cosmetics: normalize capitalization
8813ca8e Merge tag 'v1.2.3'
3c4a0fbf update ChangeLog (tag: v1.2.3)
56a480e8 dsp/cpu.h: add missing extern "C"
62b45bdd update ChangeLog (tag: v1.2.3-rc1)
@ -993,7 +1501,7 @@ b016cb91 NEON: faster fancy upsampling
f04eb376 Merge tag 'v0.5.2'
341d711c NEON: 5% faster conversion to RGB565 and RGBA4444
abb54827 remove Clang warnings with unused arch arguments.
ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2, origin/0.5.2)
ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2)
aa7744ca anim_util: quiet implicit conv warnings in 32-bit
d9120271 jpegdec: correct ContextFill signature
24eb3940 Remove some errors when compiling the code as C++.
@ -1280,7 +1788,7 @@ bbb6ecd9 Merge "Add MSA optimized distortion functions"
c0991a14 io,EmitRescaledAlphaYUV: factor out a common expr
48bf5ed1 build.gradle: remove tab
bfef6c9f Merge tag 'v0.5.1'
3d97bb75 update ChangeLog (tag: v0.5.1, origin/0.5.1)
3d97bb75 update ChangeLog (tag: v0.5.1)
deb54d91 Clarify the expected 'config' lifespan in WebPIDecode()
435308e0 Add MSA optimized encoder transform functions
dce64bfa Add MSA optimized alpha filter functions

View File

@ -5,12 +5,15 @@ LIBWEBPDECODER_BASENAME = libwebpdecoder
LIBWEBP_BASENAME = libwebp
LIBWEBPMUX_BASENAME = libwebpmux
LIBWEBPDEMUX_BASENAME = libwebpdemux
LIBSHARPYUV_BASENAME = libsharpyuv
!IFNDEF ARCH
!IF ! [ cl 2>&1 | find "x86" > NUL ]
ARCH = x86
!ELSE IF ! [ cl 2>&1 | find "x64" > NUL ]
ARCH = x64
!ELSE IF ! [ cl 2>&1 | find "ARM64" > NUL ]
ARCH = ARM64
!ELSE IF ! [ cl 2>&1 | find "ARM" > NUL ]
ARCH = ARM
!ELSE
@ -29,7 +32,7 @@ PLATFORM_LDFLAGS = /SAFESEH
NOLOGO = /nologo
CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG
CCDEBUG = cl.exe $(NOLOGO) /Od /Zi /D_DEBUG /RTC1
CFLAGS = /I. /Isrc $(NOLOGO) /W3 /EHsc /c
CFLAGS = /I. /Isrc $(NOLOGO) /MP /W3 /EHsc /c
CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
LDFLAGS = /LARGEADDRESSAWARE /MANIFEST:EMBED /NXCOMPAT /DYNAMICBASE
LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS)
@ -96,6 +99,7 @@ LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug
!ELSE IF "$(CFG)" == "release-dynamic"
CC = $(CCNODBG)
RC = $(RCNODBG)
@ -109,6 +113,7 @@ LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug
!ENDIF
!IF "$(STATICLIBBUILD)" == "TRUE"
@ -118,13 +123,14 @@ LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME).lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib
LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME).lib
!ELSE IF "$(DLLBUILD)" == "TRUE"
DLLINC = webp_dll.h
CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL
CC = $(CC) /I$(DIROBJ) $(RTLIB) /DWEBP_DLL
LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME)_dll.lib
LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME)_dll.lib
LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb
CFGSET = TRUE
!ENDIF
@ -176,6 +182,7 @@ CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
SHARPYUV_OBJS = \
$(DIROBJ)\sharpyuv\sharpyuv.obj \
$(DIROBJ)\sharpyuv\sharpyuv_cpu.obj \
$(DIROBJ)\sharpyuv\sharpyuv_csp.obj \
$(DIROBJ)\sharpyuv\sharpyuv_dsp.obj \
$(DIROBJ)\sharpyuv\sharpyuv_gamma.obj \
@ -224,6 +231,7 @@ DSP_DEC_OBJS = \
$(DIROBJ)\dsp\lossless_neon.obj \
$(DIROBJ)\dsp\lossless_sse2.obj \
$(DIROBJ)\dsp\lossless_sse41.obj \
$(DIROBJ)\dsp\lossless_avx2.obj \
$(DIROBJ)\dsp\rescaler.obj \
$(DIROBJ)\dsp\rescaler_mips32.obj \
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
@ -263,6 +271,7 @@ DSP_ENC_OBJS = \
$(DIROBJ)\dsp\lossless_enc_neon.obj \
$(DIROBJ)\dsp\lossless_enc_sse2.obj \
$(DIROBJ)\dsp\lossless_enc_sse41.obj \
$(DIROBJ)\dsp\lossless_enc_avx2.obj \
$(DIROBJ)\dsp\ssim.obj \
$(DIROBJ)\dsp\ssim_sse2.obj \
@ -316,6 +325,7 @@ ENC_OBJS = \
EXTRAS_OBJS = \
$(DIROBJ)\extras\extras.obj \
$(DIROBJ)\extras\quality_estimate.obj \
$(DIROBJ)\extras\sharpyuv_risk_table.obj \
IMAGEIO_UTIL_OBJS = \
$(DIROBJ)\imageio\imageio_util.obj \
@ -331,6 +341,7 @@ UTILS_DEC_OBJS = \
$(DIROBJ)\utils\color_cache_utils.obj \
$(DIROBJ)\utils\filters_utils.obj \
$(DIROBJ)\utils\huffman_utils.obj \
$(DIROBJ)\utils\palette.obj \
$(DIROBJ)\utils\quant_levels_dec_utils.obj \
$(DIROBJ)\utils\rescaler_utils.obj \
$(DIROBJ)\utils\random_utils.obj \
@ -343,12 +354,13 @@ UTILS_ENC_OBJS = \
$(DIROBJ)\utils\quant_levels_utils.obj \
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(SHARPYUV_OBJS) $(ENC_OBJS) \
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
$(DSP_ENC_OBJS) $(UTILS_ENC_OBJS) $(DLL_OBJS)
LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS)
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS)
LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS)
OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP)
OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP) $(LIBSHARPYUV)
!IF "$(ARCH)" == "ARM"
ex: $(OUT_LIBS)
all: ex
@ -376,14 +388,14 @@ $(DIRBIN)\anim_dump.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\anim_dump.exe: $(IMAGEIO_ENC_OBJS)
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\cwebp.exe: $(LIBWEBPDEMUX)
$(DIRBIN)\cwebp.exe: $(LIBWEBPDEMUX) $(LIBSHARPYUV)
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS)
$(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\dwebp.exe: $(LIBWEBPDEMUX)
$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS)
$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX)
$(DIRBIN)\gif2webp.exe: $(LIBWEBP)
$(DIRBIN)\gif2webp.exe: $(LIBWEBP) $(LIBSHARPYUV)
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS)
$(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\vwebp_sdl.obj
@ -394,7 +406,7 @@ $(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
$(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX)
$(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP) $(LIBSHARPYUV)
$(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj
$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\get_disto.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
@ -417,17 +429,16 @@ $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS): $(OUTPUT_DIRS)
$(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(EXTRAS_OBJS): $(OUTPUT_DIRS)
!ENDIF # ARCH == ARM
$(LIBSHARPYUV): $(LIBSHARPYUV_OBJS)
$(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS)
$(LIBWEBP): $(LIBWEBP_OBJS)
$(LIBWEBP): $(LIBWEBP_OBJS) $(LIBSHARPYUV)
$(LIBWEBPMUX): $(LIBWEBPMUX_OBJS)
$(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS)
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(OUTPUT_DIRS)
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS) $(LIBSHARPYUV_OBJS): \
$(OUTPUT_DIRS)
!IF "$(DLLBUILD)" == "TRUE"
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
$(DIROBJ)\$(DLLINC)
{$(DIROBJ)}.c{$(DIROBJ)}.obj:
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
@ -437,20 +448,20 @@ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
$(RC) /fo$@ $<
{src\mux}.rc{$(DIROBJ)\mux}.res:
$(RC) /fo$@ $<
{sharpyuv}.rc{$(DIROBJ)\sharpyuv}.res:
$(RC) /fo$@ $<
$(LIBWEBP): $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
$(LIBSHARPYUV): $(DIROBJ)\sharpyuv\$(LIBSHARPYUV_BASENAME:_debug=).res
$(LIBWEBP): $(LIBSHARPYUV) $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
$(LIBWEBPDECODER): $(DIROBJ)\$(LIBWEBPDECODER_BASENAME:_debug=).res
$(LIBWEBPMUX): $(LIBWEBP) $(DIROBJ)\mux\$(LIBWEBPMUX_BASENAME:_debug=).res
$(LIBWEBPDEMUX): $(LIBWEBP) $(DIROBJ)\demux\$(LIBWEBPDEMUX_BASENAME:_debug=).res
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV):
$(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
clean::
@-erase /s $(DIROBJ)\$(DLLINC) 2> NUL
!ELSE
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV):
$(LNKLIB) /out:$@ $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
!ENDIF
@ -458,13 +469,6 @@ $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(OUTPUT_DIRS):
@if not exist "$(@)" mkdir "$(@)"
# generate a helper include to define WEBP_EXTERN suitable for the DLL build
$(DIROBJ)\$(DLLINC):
@echo #ifndef WEBP_DLL_H_ > $@
@echo #define WEBP_DLL_H_ >> $@
@echo #define WEBP_EXTERN __declspec(dllexport) >> $@
@echo #endif /* WEBP_DLL_H_ */ >> $@
.SUFFIXES: .c .obj .res .exe
# File-specific flag builds. Note batch rules take precedence over wildcards,
# so for now name each file individually.

64
NEWS
View File

@ -1,3 +1,67 @@
- 12/19/2024 version 1.5.0
This is a binary compatible release.
API changes:
- `cross_color_transform_bits` added to WebPAuxStats
* minor lossless encoder speed and compression improvements
* lossless encoding does not use floats anymore
* additional Arm optimizations for lossy & lossless + general code generation
improvements
* improvements to WASM performance (#643)
* improvements and corrections in webp-container-spec.txt and
webp-lossless-bitstream-spec.txt (#646, #355607636)
* further security related hardening and increased fuzzing coverage w/fuzztest
(oss-fuzz: #382816119, #70112, #70102, #69873, #69825, #69508, #69208)
* miscellaneous warning, bug & build fixes (#499, #562, #381372617,
#381109771, #42340561, #375011696, #372109644, chromium: #334120888)
Tool updates:
* gif2webp: add -sharp_yuv & -near_lossless
* img2webp: add -exact & -noexact
* exit codes normalized; running an example program with no
arguments will output its help and exit with an error (#42340557,
#381372617)
- 4/12/2024: version 1.4.0
This is a binary compatible release.
* API changes:
- libwebpmux: WebPAnimEncoderSetChunk, WebPAnimEncoderGetChunk,
WebPAnimEncoderDeleteChunk
- libsharpyuv: SharpYuvOptionsInit, SharpYuvConvertWithOptions
- extras: SharpYuvEstimate420Risk
* further security related hardening in libwebp & examples
* some minor optimizations in the lossless encoder
* added WEBP_NODISCARD to report unused result warnings; enable with
-DWEBP_ENABLE_NODISCARD=1
* improvements and corrections in webp-container-spec.txt and
webp-lossless-bitstream-spec.txt (#611)
* miscellaneous warning, bug & build fixes (#615, #619, #632, #635)
- 9/13/2023: version 1.3.2
This is a binary compatible release.
* security fix for lossless decoder (chromium: #1479274, CVE-2023-4863)
- 6/23/2023: version 1.3.1
This is a binary compatible release.
* security fixes for lossless encoder (#603, chromium: #1420107, #1455619,
CVE-2023-1999)
* improve error reporting through WebPPicture error codes
* fix upsampling for RGB565 and RGBA4444 in NEON builds
* img2webp: add -sharp_yuv & -near_lossless
* Windows builds:
- fix compatibility with clang-cl (#607)
- improve Arm64 performance with cl.exe
- add Arm64EC support
* fix webp_js with emcc >= 3.1.27 (stack size change, #614)
* CMake fixes (#592, #610, #612)
* further updates to the container and lossless bitstream docs (#581, #611)
- 12/16/2022: version 1.3.0
This is a binary compatible release.
* add libsharpyuv, which exposes -sharp_yuv/config.use_sharp_yuv
functionality to other libraries; libwebp now depends on this library
* major updates to the container and lossless bitstream docs (#448, #546,
#551)
* miscellaneous warning, bug & build fixes (#576, #583, #584)
- 8/4/2022: version 1.2.4
This is a binary compatible release.
* restore CMake libwebpmux target name for compatibility with 1.2.2 (#575)

View File

@ -7,7 +7,7 @@
\__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v1.2.4
\____/____/\_____/_____/____/v1.5.0
```
WebP codec is a library to encode and decode images in WebP format. This package
@ -42,7 +42,8 @@ See the [APIs documentation](doc/api.md), and API usage examples in the
## Bugs
Please report all bugs to the issue tracker: https://bugs.chromium.org/p/webp
Please report all bugs to the [issue tracker](https://issues.webmproject.org).
For security reports, select 'Security report' from the Template dropdown.
Patches welcome! See [how to contribute](CONTRIBUTING.md).

View File

@ -107,6 +107,7 @@ model {
source {
srcDir "sharpyuv"
include "sharpyuv.c"
include "sharpyuv_cpu.c"
include "sharpyuv_csp.c"
include "sharpyuv_dsp.c"
include "sharpyuv_gamma.c"
@ -172,6 +173,7 @@ model {
include "color_cache_utils.c"
include "filters_utils.c"
include "huffman_utils.c"
include "palette.c"
include "quant_levels_dec_utils.c"
include "random_utils.c"
include "rescaler_utils.c"

View File

@ -3,9 +3,17 @@ set(WEBP_VERSION ${WebP_VERSION})
@PACKAGE_INIT@
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
if(@WEBP_USE_THREAD@)
include(CMakeFindDependencyMacro)
find_dependency(Threads REQUIRED)
endif()
set(WebP_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
set_and_check(WebP_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
set(WebP_INCLUDE_DIRS ${WebP_INCLUDE_DIR})
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIR})
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
check_required_components(WebP)

View File

@ -16,48 +16,18 @@
/* Define to 1 if you have the <cpu-features.h> header file. */
#cmakedefine HAVE_CPU_FEATURES_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H 1
/* Define to 1 if you have the <GLUT/glut.h> header file. */
#cmakedefine HAVE_GLUT_GLUT_H 1
/* Define to 1 if you have the <GL/glut.h> header file. */
#cmakedefine HAVE_GL_GLUT_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H 1
/* Define to 1 if you have the <OpenGL/glut.h> header file. */
#cmakedefine HAVE_OPENGL_GLUT_H 1
/* Have PTHREAD_PRIO_INHERIT. */
#cmakedefine HAVE_PTHREAD_PRIO_INHERIT @HAVE_PTHREAD_PRIO_INHERIT@
/* Define to 1 if you have the <shlwapi.h> header file. */
#cmakedefine HAVE_SHLWAPI_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1
@ -93,9 +63,6 @@
/* Define to the version of this package. */
#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1
/* Version number of package */
#cmakedefine VERSION "@VERSION@"
@ -127,6 +94,9 @@
/* Set to 1 if SSE4.1 is supported */
#cmakedefine WEBP_HAVE_SSE41 1
/* Set to 1 if AVX2 is supported */
#cmakedefine WEBP_HAVE_AVX2 1
/* Set to 1 if TIFF library is installed */
#cmakedefine WEBP_HAVE_TIFF 1

View File

@ -18,7 +18,8 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE)
cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
check_c_source_compiles("
check_c_source_compiles(
"
#include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\"
int main(void) {
#if !defined(WEBP_USE_${WEBP_SIMD_FLAG})
@ -26,7 +27,8 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
#endif
return 0;
}
" WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
"
WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
cmake_pop_check_state()
if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE)
@ -36,9 +38,9 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
endfunction()
# those are included in the names of WEBP_USE_* in c++ code.
set(WEBP_SIMD_FLAGS "SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA")
set(WEBP_SIMD_FLAGS "AVX2;SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA")
set(WEBP_SIMD_FILE_EXTENSIONS
"_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
"_avx2.c;_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC")
# With at least Visual Studio 12 (2013)+ /arch is not necessary to build SSE2
# or SSE4 code unless a lesser /arch is forced. MSVC does not have a SSE4
@ -48,21 +50,18 @@ if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC")
if(MSVC_VERSION GREATER_EQUAL 1800 AND NOT CMAKE_C_FLAGS MATCHES "/arch:")
set(SIMD_ENABLE_FLAGS)
else()
set(SIMD_ENABLE_FLAGS "/arch:AVX;/arch:SSE2;;;;")
set(SIMD_ENABLE_FLAGS "/arch:AVX2;/arch:AVX;/arch:SSE2;;;;")
endif()
set(SIMD_DISABLE_FLAGS)
else()
set(SIMD_ENABLE_FLAGS
"-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
set(SIMD_DISABLE_FLAGS
"-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa")
set(SIMD_ENABLE_FLAGS "-mavx2;-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
set(SIMD_DISABLE_FLAGS "-mno-avx2;-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa")
endif()
set(WEBP_SIMD_FILES_TO_NOT_INCLUDE)
set(WEBP_SIMD_FILES_TO_INCLUDE)
set(WEBP_SIMD_FLAGS_TO_INCLUDE)
if(${ANDROID})
if(ANDROID AND ANDROID_ABI)
if(${ANDROID_ABI} STREQUAL "armeabi-v7a")
# This is because Android studio uses the configuration "-march=armv7-a
# -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon
@ -75,8 +74,8 @@ list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH)
math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
# With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the
# source will fail to compile.
# With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the source
# will fail to compile.
if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 2)
break()
endif()
@ -107,8 +106,9 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
endif()
# Check which files we should include or not.
list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
"src/dsp/*${WEBP_SIMD_FILE_EXTENSION}")
file(GLOB SIMD_FILES
"${CMAKE_CURRENT_LIST_DIR}/../sharpyuv/*${WEBP_SIMD_FILE_EXTENSION}"
"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/*${WEBP_SIMD_FILE_EXTENSION}")
if(WEBP_HAVE_${WEBP_SIMD_FLAG})
# Memorize the file and flags.
foreach(FILE ${SIMD_FILES})
@ -142,11 +142,9 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
set(COMMON_PATTERNS)
endif()
set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG})
check_c_source_compiles("int main(void) {return 0;}"
FLAG_${SIMD_COMPILE_FLAG}
FAIL_REGEX
"warning: argument unused during compilation:"
${COMMON_PATTERNS})
check_c_source_compiles(
"int main(void) {return 0;}" FLAG_${SIMD_COMPILE_FLAG} FAIL_REGEX
"warning: argument unused during compilation:" ${COMMON_PATTERNS})
if(NOT FLAG_${SIMD_COMPILE_FLAG})
unset(HAS_COMPILE_FLAG)
unset(HAS_COMPILE_FLAG CACHE)

View File

@ -10,24 +10,30 @@
# Check for compiler options.
include(CheckCSourceCompiles)
check_c_source_compiles("
check_c_source_compiles(
"
int main(void) {
(void)__builtin_bswap16(0);
return 0;
}
" HAVE_BUILTIN_BSWAP16)
check_c_source_compiles("
"
HAVE_BUILTIN_BSWAP16)
check_c_source_compiles(
"
int main(void) {
(void)__builtin_bswap32(0);
return 0;
}
" HAVE_BUILTIN_BSWAP32)
check_c_source_compiles("
"
HAVE_BUILTIN_BSWAP32)
check_c_source_compiles(
"
int main(void) {
(void)__builtin_bswap64(0);
return 0;
}
" HAVE_BUILTIN_BSWAP64)
"
HAVE_BUILTIN_BSWAP64)
# Check for libraries.
if(WEBP_USE_THREAD)
@ -37,14 +43,6 @@ if(WEBP_USE_THREAD)
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 Threads::Threads)
endif()
set(WEBP_USE_THREAD ${Threads_FOUND})
@ -59,94 +57,88 @@ set(WEBP_HAVE_GL ${OPENGL_FOUND})
# Check if we need to link to the C math library. We do not look for it as it is
# not found when cross-compiling, while it is here.
check_c_source_compiles("
check_c_source_compiles(
"
#include <math.h>
int main(int argc, char** argv) {
return (int)pow(argc, 2.5);
}
" HAVE_MATH_LIBRARY)
"
HAVE_MATH_LIBRARY)
if(NOT HAVE_MATH_LIBRARY)
message(STATUS "Adding -lm flag.")
list(APPEND SHARPYUV_DEP_LIBRARIES m)
list(APPEND WEBP_DEP_LIBRARIES m)
endif()
# Find the standard image libraries.
set(WEBP_DEP_IMG_LIBRARIES)
set(WEBP_DEP_IMG_INCLUDE_DIRS)
foreach(I_LIB PNG JPEG TIFF)
# Disable tiff when compiling in static mode as it is failing on Ubuntu.
if(WEBP_LINK_STATIC AND ${I_LIB} STREQUAL "TIFF")
message("TIFF is disabled when statically linking.")
continue()
if(WEBP_FIND_IMG_LIBS)
foreach(I_LIB PNG JPEG TIFF)
# Disable tiff when compiling in static mode as it is failing on Ubuntu.
if(WEBP_LINK_STATIC AND ${I_LIB} STREQUAL "TIFF")
message(STATUS "TIFF is disabled when statically linking.")
continue()
endif()
find_package(${I_LIB})
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
if(${I_LIB}_FOUND)
list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIR}
${${I_LIB}_INCLUDE_DIRS})
endif()
endforeach()
if(WEBP_DEP_IMG_INCLUDE_DIRS)
list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS)
endif()
find_package(${I_LIB})
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
if(${I_LIB}_FOUND)
list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIR}
${${I_LIB}_INCLUDE_DIRS})
endif()
endforeach()
if(WEBP_DEP_IMG_INCLUDE_DIRS)
list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS)
endif()
# GIF detection, gifdec isn't part of the imageio lib.
include(CMakePushCheckState)
set(WEBP_DEP_GIF_LIBRARIES)
set(WEBP_DEP_GIF_INCLUDE_DIRS)
find_package(GIF)
set(WEBP_HAVE_GIF ${GIF_FOUND})
if(GIF_FOUND)
# GIF find_package only locates the header and library, it doesn't fail
# compile tests when detecting the version, but falls back to 3 (as of at
# least cmake 3.7.2). Make sure the library links to avoid incorrect detection
# when cross compiling.
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES})
set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR})
check_c_source_compiles("
# GIF detection, gifdec isn't part of the imageio lib.
include(CMakePushCheckState)
set(WEBP_DEP_GIF_LIBRARIES)
set(WEBP_DEP_GIF_INCLUDE_DIRS)
find_package(GIF)
set(WEBP_HAVE_GIF ${GIF_FOUND})
if(GIF_FOUND)
# GIF find_package only locates the header and library, it doesn't fail
# compile tests when detecting the version, but falls back to 3 (as of at
# least cmake 3.7.2). Make sure the library links to avoid incorrect
# detection when cross compiling.
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES})
set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR})
check_c_source_compiles(
"
#include <gif_lib.h>
int main(void) {
(void)DGifOpenFileHandle;
return 0;
}
" GIF_COMPILES)
cmake_pop_check_state()
if(GIF_COMPILES)
list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
else()
unset(GIF_FOUND)
"
GIF_COMPILES)
cmake_pop_check_state()
if(GIF_COMPILES)
list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
else()
unset(GIF_FOUND)
endif()
endif()
endif()
# Check for specific headers.
include(CheckIncludeFiles)
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
check_include_files(dlfcn.h HAVE_DLFCN_H)
check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
check_include_files(GL/glut.h HAVE_GL_GLUT_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(memory.h HAVE_MEMORY_H)
check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
check_include_files(shlwapi.h HAVE_SHLWAPI_H)
check_include_files(stdint.h HAVE_STDINT_H)
check_include_files(stdlib.h HAVE_STDLIB_H)
check_include_files(strings.h HAVE_STRINGS_H)
check_include_files(string.h HAVE_STRING_H)
check_include_files(sys/stat.h HAVE_SYS_STAT_H)
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(wincodec.h HAVE_WINCODEC_H)
check_include_files(windows.h HAVE_WINDOWS_H)
# Windows specifics
if(HAVE_WINCODEC_H)
list(APPEND WEBP_DEP_LIBRARIES
shlwapi
ole32
windowscodecs)
list(APPEND WEBP_DEP_LIBRARIES shlwapi ole32 windowscodecs)
endif()
# Check for SIMD extensions.
@ -158,17 +150,12 @@ set(PACKAGE_NAME ${PROJECT_NAME})
# Read from configure.ac.
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC)
string(REGEX MATCHALL
"\\[([0-9a-z\\.:/]*)\\]"
CONFIGURE_AC_PACKAGE_INFO
string(REGEX MATCHALL "\\[([0-9a-z\\.:/]*)\\]" CONFIGURE_AC_PACKAGE_INFO
${CONFIGURE_AC})
function(strip_bracket VAR)
string(LENGTH ${${VAR}} TMP_LEN)
math(EXPR TMP_LEN ${TMP_LEN}-2)
string(SUBSTRING ${${VAR}}
1
${TMP_LEN}
TMP_SUB)
string(SUBSTRING ${${VAR}} 1 ${TMP_LEN} TMP_SUB)
set(${VAR} ${TMP_SUB} PARENT_SCOPE)
endfunction()

View File

@ -1,5 +1,5 @@
AC_INIT([libwebp], [1.2.4],
[https://bugs.chromium.org/p/webp],,
AC_INIT([libwebp], [1.5.0],
[https://issues.webmproject.org],,
[https://developers.google.com/speed/webp])
AC_CANONICAL_HOST
AC_PREREQ([2.60])
@ -106,6 +106,7 @@ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wconstant-conversion])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra-semi-stmt])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-nonliteral])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-security])
@ -115,6 +116,7 @@ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wparentheses-equality])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wstrict-prototypes])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wundef])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code-aggressive])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code])
@ -159,6 +161,25 @@ AS_IF([test "$GCC" = "yes" ], [
AC_SUBST([AM_CFLAGS])
dnl === Check for machine specific flags
AC_ARG_ENABLE([avx2],
AS_HELP_STRING([--disable-avx2],
[Disable detection of AVX2 support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_avx2" != "xno" -a "x$enable_sse4_1" != "xno"
-a "x$enable_sse2" != "xno"], [
AVX2_FLAGS="$INTRINSICS_CFLAGS $AVX2_FLAGS"
TEST_AND_ADD_CFLAGS([AVX2_FLAGS], [-mavx2])
AS_IF([test -n "$AVX2_FLAGS"], [
SAVED_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $AVX2_FLAGS"
AC_CHECK_HEADER([immintrin.h],
[AC_DEFINE(WEBP_HAVE_AVX2, [1],
[Set to 1 if AVX2 is supported])],
[AVX2_FLAGS=""])
CFLAGS=$SAVED_CFLAGS])
AC_SUBST([AVX2_FLAGS])])
AC_ARG_ENABLE([sse4.1],
AS_HELP_STRING([--disable-sse4.1],
[Disable detection of SSE4.1 support
@ -464,7 +485,7 @@ AC_ARG_ENABLE([sdl],
@<:@default=auto@:>@]))
AS_IF([test "x$enable_sdl" != "xno"], [
CLEAR_LIBVARS([SDL])
AC_PATH_PROGS([LIBSDL_CONFIG], [sdl-config])
AC_PATH_PROGS([LIBSDL_CONFIG], [sdl2-config])
if test -n "$LIBSDL_CONFIG"; then
SDL_INCLUDES=`$LIBSDL_CONFIG --cflags`
SDL_LIBS="`$LIBSDL_CONFIG --libs`"
@ -474,13 +495,12 @@ AS_IF([test "x$enable_sdl" != "xno"], [
sdl_header="no"
LIBCHECK_PROLOGUE([SDL])
AC_CHECK_HEADER([SDL/SDL.h], [sdl_header="SDL/SDL.h"],
[AC_CHECK_HEADER([SDL.h], [sdl_header="SDL.h"],
[AC_MSG_WARN(SDL library not available - no sdl.h)])])
AC_CHECK_HEADER([SDL2/SDL.h], [sdl_header="SDL2/SDL.h"],
[AC_MSG_WARN(SDL2 library not available - no SDL.h)])
if test x"$sdl_header" != "xno"; then
AC_LANG_PUSH(C)
SDL_SAVED_LIBS="$LIBS"
for lib in "" "-lSDL" "-lSDLmain -lSDL"; do
for lib in "" "-lSDL2" "-lSDL2main -lSDL2"; do
LIBS="$SDL_SAVED_LIBS $lib"
# Perform a full link to ensure SDL_main is resolved if needed.
AC_LINK_IFELSE(
@ -749,18 +769,21 @@ fi
dnl =========================
dnl Add an empty webp_libname_prefix variable for use in *.pc.in.
AC_SUBST([webp_libname_prefix])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([src/webp/config.h])
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
examples/Makefile extras/Makefile imageio/Makefile \
sharpyuv/Makefile \
sharpyuv/Makefile sharpyuv/libsharpyuv.pc \
src/dec/Makefile src/enc/Makefile src/dsp/Makefile \
src/demux/Makefile src/mux/Makefile \
src/utils/Makefile \
src/libwebp.pc src/libwebpdecoder.pc \
src/demux/libwebpdemux.pc src/mux/libwebpmux.pc])
dnl fix exports from MinGW builds
AC_CONFIG_COMMANDS_POST([$SED -i 's/-DDLL_EXPORT/-DWEBP_DLL/' config.status])
AC_OUTPUT
AC_MSG_NOTICE([

View File

@ -157,7 +157,7 @@ decoding is not finished yet or VP8_STATUS_OK when decoding is done. Any other
status is an error condition.
The 'idec' object must always be released (even upon an error condition) by
calling: WebPDelete(idec).
calling: WebPIDelete(idec).
To retrieve partially decoded picture samples, one must use the corresponding
method: WebPIDecGetRGB or WebPIDecGetYUVA. It will return the last displayable
@ -233,7 +233,7 @@ WebPIDelete(idec);
WebPFreeDecBuffer(&config.output);
```
## Webp Mux
## WebP Mux
WebPMux is a set of two libraries 'Mux' and 'Demux' for creation, extraction and
manipulation of an extended format WebP file, which can have features like color

View File

@ -96,6 +96,24 @@ make
make install
```
## Building libwebp - Using vcpkg
You can download and install libwebp using the
[vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
```shell
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install libwebp
```
The libwebp port in vcpkg is kept up to date by Microsoft team members and
community contributors. If the version is out of date, please
[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the
vcpkg repository.
## CMake
With CMake, you can compile libwebp, cwebp, dwebp, gif2webp, img2webp, webpinfo
@ -210,4 +228,4 @@ generated code, but is untested.
## Javascript decoder
Libwebp can be compiled into a JavaScript decoder using Emscripten and CMake.
See the [corresponding documentation](../README.md)
See the [corresponding documentation](../webp_js/README.md)

View File

@ -17,10 +17,11 @@ rubygems will install automatically. The following will apply inline CSS
styling; an external stylesheet is not needed.
```shell
$ kramdown doc/webp-lossless-bitstream-spec.txt --template \
doc/template.html --coderay-css style --coderay-line-numbers ' ' \
--coderay-default-lang c > \
doc/output/webp-lossless-bitstream-spec.html
$ kramdown doc/webp-lossless-bitstream-spec.txt \
--template doc/template.html \
-x syntax-coderay --syntax-highlighter coderay \
--syntax-highlighter-opts "{default_lang: c, line_numbers: , css: style}" \
> doc/output/webp-lossless-bitstream-spec.html
```
Optimally, use kramdown 0.13.7 or newer if syntax highlighting desired.

View File

@ -82,8 +82,8 @@ Options:
green=0xe0 and blue=0xd0
-noalpha ............... discard any transparency information
-lossless .............. encode image losslessly, default=off
-near_lossless <int> ... use near-lossless image
preprocessing (0..100=off), default=100
-near_lossless <int> ... use near-lossless image preprocessing
(0..100=off), default=100
-hint <string> ......... specify image characteristics hint,
one of: photo, picture or graph
@ -295,19 +295,23 @@ etc.
Usage:
```shell
img2webp [file_options] [[frame_options] frame_file]...
img2webp [file_options] [[frame_options] frame_file]... [-o webp_file]
```
File-level options (only used at the start of compression):
```
-min_size ............ minimize size
-loop <int> .......... loop count (default: 0, = infinite loop)
-kmax <int> .......... maximum number of frame between key-frames
(0=only keyframes)
-kmin <int> .......... minimum number of frame between key-frames
(0=disable key-frames altogether)
-mixed ............... use mixed lossy/lossless automatic mode
-near_lossless <int> . use near-lossless image preprocessing
(0..100=off), default=100
-sharp_yuv ........... use sharper (and slower) RGB->YUV conversion
(lossy only)
-loop <int> .......... loop count (default: 0, = infinite loop)
-v ................... verbose mode
-h ................... this help
-version ............. print version number and exit
@ -317,10 +321,13 @@ Per-frame options (only used for subsequent images input):
```
-d <int> ............. frame duration in ms (default: 100)
-lossless ........... use lossless mode (default)
-lossy ... ........... use lossy mode
-lossless ............ use lossless mode (default)
-lossy ............... use lossy mode
-q <float> ........... quality
-m <int> ............. method to use
-m <int> ............. compression method (0=fast, 6=slowest), default=4
-exact, -noexact ..... preserve or alter RGB values in transparent area
(default: -noexact, may cause artifacts
with lossy animations)
```
example: `img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp`
@ -347,8 +354,12 @@ Options:
-lossy ................. encode image using lossy compression
-mixed ................. for each frame in the image, pick lossy
or lossless compression heuristically
-near_lossless <int> ... use near-lossless image preprocessing
(0..100=off), default=100
-sharp_yuv ............. use sharper (and slower) RGB->YUV conversion
(lossy only)
-q <float> ............. quality factor (0:small..100:big)
-m <int> ............... compression method (0=fast, 6=slowest)
-m <int> ............... compression method (0=fast, 6=slowest), default=4
-min_size .............. minimize output size (default:off)
lossless compression by default; can be
combined with -q, -m, -lossy or -mixed

View File

@ -20,46 +20,48 @@ WebP Container Specification
Introduction
------------
WebP is an image format that uses either (i) the VP8 key frame encoding
to compress image data in a lossy way, or (ii) the WebP lossless encoding
(and possibly other encodings in the future). These encoding schemes should
make it more efficient than currently used formats. It is optimized for fast
image transfer over the network (e.g., for websites). The WebP format has
feature parity (color profile, metadata, animation etc) with other formats as
well. This document describes the structure of a WebP file.
WebP is an image format that uses either (i) the VP8 key frame encoding to
compress image data in a lossy way or (ii) the WebP lossless encoding. These
encoding schemes should make it more efficient than older formats, such as JPEG,
GIF, and PNG. It is optimized for fast image transfer over the network (for
example, for websites). The WebP format has feature parity (color profile,
metadata, animation, etc.) with other formats as well. This document describes
the structure of a WebP file.
The WebP container (i.e., RIFF container for WebP) allows feature support over
and above the basic use case of WebP (i.e., a file containing a single image
encoded as a VP8 key frame). The WebP container provides additional support
for:
The WebP container (that is, the RIFF container for WebP) allows feature support
over and above the basic use case of WebP (that is, a file containing a single
image encoded as a VP8 key frame). The WebP container provides additional
support for the following:
* **Lossless compression.** An image can be losslessly compressed, using the
* Lossless Compression: An image can be losslessly compressed, using the
WebP Lossless Format.
* **Metadata.** An image may have metadata stored in Exif or XMP formats.
* Metadata: An image may have metadata stored in Exchangeable Image File
Format (Exif) or Extensible Metadata Platform (XMP) format.
* **Transparency.** An image may have transparency, i.e., an alpha channel.
* Transparency: An image may have transparency, that is, an alpha channel.
* **Color Profile.** An image may have an embedded ICC profile as described
* Color Profile: An image may have an embedded ICC profile as described
by the [International Color Consortium][iccspec].
* **Animation.** An image may have multiple frames with pauses between them,
* Animation: An image may have multiple frames with pauses between them,
making it an animation.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [RFC 2119][].
Terminology & Basics
--------------------
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in BCP 14 [RFC 2119][] [RFC 8174][]
when, and only when, they appear in all capitals, as shown here.
A WebP file contains either a still image (that is, an encoded matrix of pixels)
or an [animation](#animation). Optionally, it can also contain transparency
information, a color profile and metadata. We refer to the matrix of pixels as
the _canvas_ of the image.
Bit numbering in chunk diagrams starts at `0` for the most significant bit
('MSB 0') as described in [RFC 1166][].
Terminology &amp; Basics
------------------------
A WebP file contains either a still image (i.e., an encoded matrix of pixels)
or an [animation](#animation). Optionally, it can also contain transparency
information, color profile and metadata. In case we need to refer only to the
matrix of pixels, we will call it the _canvas_ of the image.
('MSB 0'), as described in [RFC 1166][].
Below are additional terms used throughout this document:
@ -82,13 +84,19 @@ _uint32_
_FourCC_
: A _FourCC_ (four-character code) is a _uint32_ created by concatenating four
ASCII characters in little-endian order.
: A four-character code (FourCC) is a _uint32_ created by concatenating four
ASCII characters in little-endian order. This means 'aaaa' (0x61616161) and
'AAAA' (0x41414141) are treated as different _FourCCs_.
_1-based_
: An unsigned integer field storing values offset by `-1`. e.g., Such a field
would store value _25_ as _24_.
: An unsigned integer field storing values offset by `-1`, for example, such a
field would store value _25_ as _24_.
_ChunkHeader('ABCD')_
: Used to describe the _FourCC_ and _Chunk Size_ header of individual chunks,
where 'ABCD' is the FourCC for the chunk. This element's size is 8 bytes.
RIFF File Format
@ -106,7 +114,7 @@ The basic element of a RIFF file is a _chunk_. It consists of:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Chunk Size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Chunk Payload |
: Chunk Payload :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk FourCC: 32 bits
@ -115,21 +123,15 @@ Chunk FourCC: 32 bits
Chunk Size: 32 bits (_uint32_)
: The size of the chunk not including this field, the chunk identifier or
padding.
: The size of the chunk in bytes, not including this field, the chunk
identifier, or padding.
Chunk Payload: _Chunk Size_ bytes
: The data payload. If _Chunk Size_ is odd, a single padding byte -- that
SHOULD be `0` -- is added.
: The data payload. If _Chunk Size_ is odd, a single padding byte -- which MUST
be `0` to conform with RIFF -- is added.
_ChunkHeader('ABCD')_
: This is used to describe the _FourCC_ and _Chunk Size_ header of individual
chunks, where 'ABCD' is the FourCC for the chunk. This element's
size is 8 bytes.
**Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard
**Note**: RIFF has a convention that all-uppercase chunk FourCCs are standard
chunks that apply to any RIFF file format, while FourCCs specific to a file
format are all lowercase. WebP does not follow this convention.
@ -149,23 +151,25 @@ WebP File Header
'RIFF': 32 bits
: The ASCII characters 'R' 'I' 'F' 'F'.
: The ASCII characters 'R', 'I', 'F', 'F'.
File Size: 32 bits (_uint32_)
: The size of the file in bytes starting at offset 8. The maximum value of
: The size of the file in bytes, starting at offset 8. The maximum value of
this field is 2^32 minus 10 bytes and thus the size of the whole file is at
most 4GiB minus 2 bytes.
most 4 GiB minus 2 bytes.
'WEBP': 32 bits
: The ASCII characters 'W' 'E' 'B' 'P'.
: The ASCII characters 'W', 'E', 'B', 'P'.
A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size
in the header is the total size of the chunks that follow plus `4` bytes for
the 'WEBP' FourCC. The file SHOULD NOT contain anything after it. As the size
of any chunk is even, the size given by the RIFF header is also even. The
contents of individual chunks will be described in the following sections.
the 'WEBP' FourCC. The file SHOULD NOT contain any data after the data
specified by _File Size_. Readers MAY parse such files, ignoring the trailing
data. As the size of any chunk is even, the size given by the RIFF header is
also even. The contents of individual chunks are described in the following
sections.
Simple File Format (Lossy)
@ -180,37 +184,43 @@ Simple WebP (lossy) file format:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| WebP file header (12 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8 chunk |
: 'VP8 ' Chunk :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8 chunk:
'VP8 ' Chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8 ') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8 data |
: VP8 data :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8 data: _Chunk Size_ bytes
: VP8 bitstream data.
The VP8 bitstream format specification can be found at [VP8 Data Format and
Decoding Guide][vp8spec]. Note that the VP8 frame header contains the VP8 frame
Note that the fourth character in the 'VP8 ' FourCC is an ASCII space (0x20).
The VP8 bitstream format specification is described in [VP8 Data Format and
Decoding Guide][rfc 6386]. Note that the VP8 frame header contains the VP8 frame
width and height. That is assumed to be the width and height of the canvas.
The VP8 specification describes how to decode the image into Y'CbCr
format. To convert to RGB, Rec. 601 SHOULD be used.
The VP8 specification describes how to decode the image into Y'CbCr format. To
convert to RGB, [Recommendation BT.601][rec601] SHOULD be used. Applications MAY
use another conversion method, but visual results may differ among decoders.
Simple File Format (Lossless)
-----------------------------
**Note:** Older readers may not support files using the lossless format.
**Note**: Older readers may not support files using the lossless format.
This layout SHOULD be used if the image requires _lossless_ encoding (with an
optional transparency channel) and does not require advanced features provided
@ -221,19 +231,22 @@ Simple WebP (lossless) file format:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| WebP file header (12 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8L chunk |
: 'VP8L' Chunk :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8L chunk:
'VP8L' Chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8L') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8L data |
: VP8L data :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8L data: _Chunk Size_ bytes
@ -249,21 +262,21 @@ and height of the canvas.
Extended File Format
--------------------
**Note:** Older readers may not support files using the extended format.
**Note**: Older readers may not support files using the extended format.
An extended format file consists of:
* A 'VP8X' chunk with information about features used in the file.
* A 'VP8X' Chunk with information about features used in the file.
* An optional 'ICCP' chunk with color profile.
* An optional 'ICCP' Chunk with a color profile.
* An optional 'ANIM' chunk with animation control data.
* An optional 'ANIM' Chunk with animation control data.
* Image data.
* An optional 'EXIF' chunk with Exif metadata.
* An optional 'EXIF' Chunk with Exif metadata.
* An optional 'XMP ' chunk with XMP metadata.
* An optional 'XMP ' Chunk with XMP metadata.
* An optional list of [unknown chunks](#unknown-chunks).
@ -277,15 +290,18 @@ up of:
For an _animated image_, the _image data_ consists of multiple frames. More
details about frames can be found in the [Animation](#animation) section.
All chunks SHOULD be placed in the same order as listed above. If a chunk
appears in the wrong place, the file is invalid, but readers MAY parse the
file, ignoring the chunks that come too late.
All chunks necessary for reconstruction and color correction, that is, 'VP8X',
'ICCP', 'ANIM', 'ANMF', 'ALPH', 'VP8 ', and 'VP8L', MUST appear in the order
described earlier. Readers SHOULD fail when chunks necessary for reconstruction
and color correction are out of order.
**Rationale:** Setting the order of chunks should allow quicker file
parsing. For example, if an 'ALPH' chunk does not appear in its required
position, a decoder can choose to stop searching for it. The rule of
ignoring late chunks should make programs that need to do a full search
give the same results as the ones stopping early.
[Metadata](#metadata) and [unknown chunks](#unknown-chunks) MAY appear out of
order.
**Rationale:** The chunks necessary for reconstruction should appear first in
the file to allow a reader to begin decoding an image before receiving all of
the data. An application may benefit from varying the order of metadata and
custom chunks to suit the implementation.
Extended WebP file header:
{:#extended_header}
@ -293,9 +309,12 @@ Extended WebP file header:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| WebP file header (12 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8X') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv|I|L|E|X|A|R| Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -306,11 +325,11 @@ Extended WebP file header:
Reserved (Rsv): 2 bits
: SHOULD be `0`.
: MUST be `0`. Readers MUST ignore this field.
ICC profile (I): 1 bit
: Set if the file contains an ICC profile.
: Set if the file contains an 'ICCP' Chunk.
Alpha (L): 1 bit
@ -327,16 +346,16 @@ XMP metadata (X): 1 bit
Animation (A): 1 bit
: Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be
: Set if this is an animated image. Data in 'ANIM' and 'ANMF' Chunks should be
used to control the animation.
Reserved (R): 1 bit
: SHOULD be `0`.
: MUST be `0`. Readers MUST ignore this field.
Reserved: 24 bits
: SHOULD be `0`.
: MUST be `0`. Readers MUST ignore this field.
Canvas Width Minus One: 24 bits
@ -350,15 +369,15 @@ Canvas Height Minus One: 24 bits
The product of _Canvas Width_ and _Canvas Height_ MUST be at most `2^32 - 1`.
Future specifications MAY add more fields.
Future specifications may add more fields. Unknown fields MUST be ignored.
### Chunks
#### Animation
An animation is controlled by ANIM and ANMF chunks.
An animation is controlled by 'ANIM' and 'ANMF' Chunks.
ANIM Chunk:
'ANIM' Chunk:
{:#anim_chunk}
For an animated image, this chunk contains the _global parameters_ of the
@ -368,6 +387,7 @@ animation.
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ANIM') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Background Color |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -379,14 +399,14 @@ Background Color: 32 bits (_uint32_)
: The default background color of the canvas in \[Blue, Green, Red, Alpha\]
byte order. This color MAY be used to fill the unused space on the canvas
around the frames, as well as the transparent pixels of the first frame.
Background color is also used when disposal method is `1`.
The background color is also used when the Disposal method is `1`.
**Note**:
**Notes**:
* Background color MAY contain a transparency value (alpha), even if the
_Alpha_ flag in [VP8X chunk](#extended_header) is unset.
* The background color MAY contain a non-opaque alpha value, even if the
_Alpha_ flag in the ['VP8X' Chunk](#extended_header) is unset.
* Viewer applications SHOULD treat the background color value as a hint, and
* Viewer applications SHOULD treat the background color value as a hint and
are not required to use it.
* The canvas is cleared at the start of each loop. The background color MAY be
@ -394,13 +414,14 @@ Background Color: 32 bits (_uint32_)
Loop Count: 16 bits (_uint16_)
: The number of times to loop the animation. `0` means infinitely.
: The number of times to loop the animation. If it is `0`, this means
infinitely.
This chunk MUST appear if the _Animation_ flag in the VP8X chunk is set.
If the _Animation_ flag is not set and this chunk is present, it
SHOULD be ignored.
This chunk MUST appear if the _Animation_ flag in the 'VP8X' Chunk is set.
If the _Animation_ flag is not set and this chunk is present, it MUST be
ignored.
ANMF chunk:
'ANMF' Chunk:
For animated images, this chunk contains information about a _single_ frame.
If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
@ -409,6 +430,7 @@ If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ANMF') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame X | ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -418,7 +440,7 @@ If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Duration | Reserved |B|D|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Data |
: Frame Data :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Frame X: 24 bits (_uint24_)
@ -441,24 +463,24 @@ Frame Height Minus One: 24 bits (_uint24_)
Frame Duration: 24 bits (_uint24_)
: The time to wait before displaying the next frame, in 1 millisecond units.
Note the interpretation of frame duration of 0 (and often <= 10) is
implementation defined. Many tools and browsers assign a minimum duration
similar to GIF.
: The time to wait before displaying the next frame, in 1-millisecond units.
Note that the interpretation of the Frame Duration of 0 (and often <= 10) is
defined by the implementation. Many tools and browsers assign a minimum
duration similar to GIF.
Reserved: 6 bits
: SHOULD be 0.
: MUST be `0`. Readers MUST ignore this field.
Blending method (B): 1 bit
: Indicates how transparent pixels of _the current frame_ are to be blended
with corresponding pixels of the previous canvas:
* `0`: Use alpha blending. After disposing of the previous frame, render the
* `0`: Use alpha-blending. After disposing of the previous frame, render the
current frame on the canvas using [alpha-blending](#alpha-blending). If
the current frame does not have an alpha channel, assume alpha value of
255, effectively replacing the rectangle.
the current frame does not have an alpha channel, assume the alpha value
is 255, effectively replacing the rectangle.
* `1`: Do not blend. After disposing of the previous frame, render the
current frame on the canvas by overwriting the rectangle covered by the
@ -471,20 +493,20 @@ Disposal method (D): 1 bit
* `0`: Do not dispose. Leave the canvas as is.
* `1`: Dispose to background color. Fill the _rectangle_ on the canvas
covered by the _current frame_ with background color specified in the
[ANIM chunk](#anim_chunk).
* `1`: Dispose to the background color. Fill the _rectangle_ on the canvas
covered by the _current frame_ with the background color specified in the
['ANIM' Chunk](#anim_chunk).
**Notes**:
* The frame disposal only applies to the _frame rectangle_, that is, the
rectangle defined by _Frame X_, _Frame Y_, _frame width_ and _frame height_.
It may or may not cover the whole canvas.
rectangle defined by _Frame X_, _Frame Y_, _frame width_, and _frame
height_. It may or may not cover the whole canvas.
{:#alpha-blending}
* **Alpha-blending**:
* Alpha-blending:
Given that each of the R, G, B and A channels is 8-bit, and the RGB
Given that each of the R, G, B, and A channels is 8 bits, and the RGB
channels are _not premultiplied_ by alpha, the formula for blending
'dst' onto 'src' is:
@ -493,16 +515,17 @@ Disposal method (D): 1 bit
if blend.A = 0 then
blend.RGB = 0
else
blend.RGB = (src.RGB * src.A +
dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
blend.RGB =
(src.RGB * src.A +
dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
~~~~~
* Alpha-blending SHOULD be done in linear color space, by taking into account
the [color profile](#color-profile) of the image. If the color profile is
not present, sRGB is to be assumed. (Note that sRGB also needs to be
linearized due to a gamma of ~2.2).
not present, standard RGB (sRGB) is to be assumed. (Note that sRGB also
needs to be linearized due to a gamma of ~2.2.)
Frame Data: _Chunk Size_ - `16` bytes
Frame Data: _Chunk Size_ bytes - `16`
: Consists of:
@ -512,8 +535,8 @@ Frame Data: _Chunk Size_ - `16` bytes
* An optional list of [unknown chunks](#unknown-chunks).
**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual
_padded_ chunks as described by the [RIFF file format](#riff-file-format).
**Note**: The 'ANMF' payload, _Frame Data_, consists of individual
_padded_ chunks, as described by the [RIFF file format](#riff-file-format).
#### Alpha
@ -521,26 +544,29 @@ _padded_ chunks as described by the [RIFF file format](#riff-file-format).
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ALPH') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv| P | F | C | Alpha Bitstream... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Reserved (Rsv): 2 bits
: SHOULD be `0`.
: MUST be `0`. Readers MUST ignore this field.
Pre-processing (P): 2 bits
Preprocessing (P): 2 bits
: These INFORMATIVE bits are used to signal the pre-processing that has
: These _informative_ bits are used to signal the preprocessing that has
been performed during compression. The decoder can use this information to
e.g. dither the values or smooth the gradients prior to display.
for example, dither the values or smooth the gradients prior to display.
* `0`: no pre-processing
* `1`: level reduction
* `0`: No preprocessing.
* `1`: Level reduction.
Decoders are not required to use this information in any specified way.
Filtering method (F): 2 bits
: The filtering method used:
: The filtering methods used are described as follows:
* `0`: None.
* `1`: Horizontal filter.
@ -564,27 +590,25 @@ made depending on the filtering method:
where `clip(v)` is equal to:
* 0 if v < 0
* 255 if v > 255
* 0 if v < 0,
* 255 if v > 255, or
* v otherwise
The final value is derived by adding the decompressed value `X` to the
predictor and using modulo-256 arithmetic to wrap the \[256-511\] range
into the \[0-255\] one:
predictor and using modulo-256 arithmetic to wrap the \[256..511\] range
into the \[0..255\] one:
`alpha = (predictor + X) % 256`
There are special cases for left-most and top-most pixel positions:
There are special cases for the left-most and top-most pixel positions. For
example, the top-left value at location (0, 0) uses 0 as the predictor value.
Otherwise:
* Top-left value at location (0,0) uses 0 as predictor value. Otherwise,
* For horizontal or gradient filtering methods, the left-most pixels at
location (0, y) are predicted using the location (0, y-1) just above.
* For vertical or gradient filtering methods, the top-most pixels at
location (x, 0) are predicted using the location (x-1, 0) on the left.
Decoders are not required to use this information in any specified way.
Compression method (C): 2 bits
: The compression method used:
@ -592,37 +616,37 @@ Compression method (C): 2 bits
* `0`: No compression.
* `1`: Compressed using the WebP lossless format.
Alpha bitstream: _Chunk Size_ - `1` bytes
Alpha bitstream: _Chunk Size_ bytes - `1`
: Encoded alpha bitstream.
This optional chunk contains encoded alpha data for this frame. A frame
containing a 'VP8L' chunk SHOULD NOT contain this chunk.
containing a 'VP8L' Chunk SHOULD NOT contain this chunk.
**Rationale**: The transparency information is already part of the 'VP8L'
chunk.
Chunk.
The alpha channel data is stored as uncompressed raw data (when
The alpha channel data is stored as uncompressed raw data (when the
compression method is '0') or compressed using the lossless format
(when the compression method is '1').
* Raw data: consists of a byte sequence of length width * height,
* Raw data: This consists of a byte sequence of length = width * height,
containing all the 8-bit transparency values in scan order.
* Lossless format compression: the byte sequence is a compressed
image-stream (as described in the [WebP Lossless Bitstream Format]
[webpllspec]) of implicit dimension width x height. That is, this
image-stream does NOT contain any headers describing the image dimension.
* Lossless format compression: The byte sequence is a compressed
image-stream (as described in ["WebP Lossless Bitstream Format"]
[webpllspec]) of implicit dimensions width x height. That is, this
image-stream does NOT contain any headers describing the image dimensions.
**Rationale**: the dimension is already known from other sources,
so storing it again would be redundant and error-prone.
**Rationale**: The dimensions are already known from other sources,
so storing them again would be redundant and prone to error.
Once the image-stream is decoded into ARGB color values, following
the process described in the lossless format specification, the
transparency information must be extracted from the *green* channel
of the ARGB quadruplet.
Once the image-stream is decoded into Alpha, Red, Green, Blue (ARGB) color
values, following the process described in the lossless format
specification, the transparency information must be extracted from the
*green* channel of the ARGB quadruplet.
**Rationale**: the green channel is allowed extra transformation
**Rationale**: The green channel is allowed extra transformation
steps in the specification -- unlike the other channels -- that can
improve compression.
@ -630,22 +654,23 @@ compression method is '0') or compressed using the lossless format
This chunk contains compressed bitstream data for a single frame.
A bitstream chunk may be either (i) a VP8 chunk, using "VP8 " (note the
significant fourth-character space) as its tag _or_ (ii) a VP8L chunk, using
"VP8L" as its tag.
A bitstream chunk may be either (i) a 'VP8 ' Chunk, using 'VP8 ' (note the
significant fourth-character space) as its FourCC, _or_ (ii) a 'VP8L' Chunk,
using 'VP8L' as its FourCC.
The formats of VP8 and VP8L chunks are as described in sections
The formats of 'VP8 ' and 'VP8L' Chunks are as described in sections
[Simple File Format (Lossy)](#simple-file-format-lossy)
and [Simple File Format (Lossless)](#simple-file-format-lossless) respectively.
and [Simple File Format (Lossless)](#simple-file-format-lossless), respectively.
#### Color profile
#### Color Profile
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ICCP') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Color Profile |
: Color Profile :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Color Profile: _Chunk Size_ bytes
@ -662,114 +687,145 @@ If this chunk is not present, sRGB SHOULD be assumed.
#### Metadata
Metadata can be stored in 'EXIF' or 'XMP ' chunks.
Metadata can be stored in 'EXIF' or 'XMP ' Chunks.
There SHOULD be at most one chunk of each type ('EXIF' and 'XMP '). If there
are more such chunks, readers MAY ignore all except the first one. Also, a file
may possibly contain both 'EXIF' and 'XMP ' chunks.
are more such chunks, readers MAY ignore all except the first one.
The chunks are defined as follows:
EXIF chunk:
'EXIF' Chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('EXIF') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Exif Metadata |
: Exif Metadata :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Exif Metadata: _Chunk Size_ bytes
: image metadata in Exif format.
: Image metadata in Exif format.
XMP chunk:
'XMP ' Chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('XMP ') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| XMP Metadata |
: XMP Metadata :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
XMP Metadata: _Chunk Size_ bytes
: image metadata in XMP format.
: Image metadata in XMP format.
Note that the fourth character in the 'XMP ' FourCC is an ASCII space (0x20).
Additional guidance about handling metadata can be found in the
Metadata Working Group's [Guidelines for Handling Metadata][metadata].
Metadata Working Group's ["Guidelines for Handling Metadata"][metadata].
#### Unknown Chunks
A RIFF chunk (described in [this](#terminology-amp-basics) section) whose _chunk
tag_ is different from any of the chunks described in this document, is
A RIFF chunk (described in the [RIFF File Format](#riff-file-format) section)
whose FourCC is different from any of the chunks described in this document, is
considered an _unknown chunk_.
**Rationale**: Allowing unknown chunks gives a provision for future extension
of the format, and also allows storage of any application-specific data.
of the format and also allows storage of any application-specific data.
A file MAY contain unknown chunks:
* At the end of the file as described in [Extended WebP file
header](#extended_header) section.
* At the end of ANMF chunks as described in the
* at the end of the file, as described in [Extended WebP file
header](#extended_header) section, or
* at the end of 'ANMF' Chunks, as described in the
[Animation](#animation) section.
Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their
original order (unless they specifically intend to modify these chunks).
### Assembling the Canvas from frames
### Canvas Assembly from Frames
Here we provide an overview of how a reader should assemble a canvas in the
case of an animated image. The notation _VP8X.field_ means the field in the
'VP8X' chunk with the same description.
Here we provide an overview of how a reader MUST assemble a canvas in the case
of an animated image.
Displaying an _animated image_ canvas MUST be equivalent to the following
pseudocode:
The process begins with creating a canvas using the dimensions given in the
'VP8X' Chunk, `Canvas Width Minus One + 1` pixels wide by `Canvas Height Minus
One + 1` pixels high. The `Loop Count` field from the 'ANIM' Chunk controls how
many times the animation process is repeated. This is `Loop Count - 1` for
nonzero `Loop Count` values or infinite if the `Loop Count` is zero.
At the beginning of each loop iteration, the canvas is filled using the
background color from the 'ANIM' Chunk or an application-defined color.
'ANMF' Chunks contain individual frames given in display order. Before rendering
each frame, the previous frame's `Disposal method` is applied.
The rendering of the decoded frame begins at the Cartesian coordinates (`2 *
Frame X`, `2 * Frame Y`), using the top-left corner of the canvas as the origin.
`Frame Width Minus One + 1` pixels wide by `Frame Height Minus One + 1` pixels
high are rendered onto the canvas using the `Blending method`.
The canvas is displayed for `Frame Duration` milliseconds. This continues until
all frames given by 'ANMF' Chunks have been displayed. A new loop iteration is
then begun, or the canvas is left in its final state if all iterations have been
completed.
The following pseudocode illustrates the rendering process. The notation
_VP8X.field_ means the field in the 'VP8X' Chunk with the same description.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assert VP8X.flags.hasAnimation
VP8X.flags.hasAnimation MUST be TRUE
canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
background color ANIM.background_color.
background color ANIM.background_color or
application-defined color.
loop_count ← ANIM.loopCount
dispose_method ← ANIM.disposeMethod
dispose_method ← Dispose to background color
if loop_count == 0:
loop_count = ∞
loop_count = ∞
frame_params ← nil
assert next chunk in image_data is ANMF
next chunk in image_data is ANMF MUST be TRUE
for loop = 0..loop_count - 1
clear canvas to ANIM.background_color or application defined color
until eof or non-ANMF chunk
frame_params.frameX = Frame X
frame_params.frameY = Frame Y
frame_params.frameWidth = Frame Width Minus One + 1
frame_params.frameHeight = Frame Height Minus One + 1
frame_params.frameDuration = Frame Duration
frame_right = frame_params.frameX + frame_params.frameWidth
frame_bottom = frame_params.frameY + frame_params.frameHeight
assert VP8X.canvasWidth >= frame_right
assert VP8X.canvasHeight >= frame_bottom
for subchunk in 'Frame Data':
if subchunk.tag == "ALPH":
assert alpha subchunks not found in 'Frame Data' earlier
frame_params.alpha = alpha_data
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
assert bitstream subchunks not found in 'Frame Data' earlier
frame_params.bitstream = bitstream_data
render frame with frame_params.alpha and frame_params.bitstream on
canvas with top-left corner at (frame_params.frameX,
frame_params.frameY), using dispose method dispose_method.
canvas contains the decoded image.
Show the contents of the canvas for frame_params.frameDuration * 1ms.
clear canvas to ANIM.background_color or application-defined color
until eof or non-ANMF chunk
frame_params.frameX = Frame X
frame_params.frameY = Frame Y
frame_params.frameWidth = Frame Width Minus One + 1
frame_params.frameHeight = Frame Height Minus One + 1
frame_params.frameDuration = Frame Duration
frame_right = frame_params.frameX + frame_params.frameWidth
frame_bottom = frame_params.frameY + frame_params.frameHeight
VP8X.canvasWidth >= frame_right MUST be TRUE
VP8X.canvasHeight >= frame_bottom MUST be TRUE
for subchunk in 'Frame Data':
if subchunk.tag == "ALPH":
alpha subchunks not found in 'Frame Data' earlier MUST be
TRUE
frame_params.alpha = alpha_data
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
bitstream subchunks not found in 'Frame Data' earlier MUST
be TRUE
frame_params.bitstream = bitstream_data
apply dispose_method.
render frame with frame_params.alpha and frame_params.bitstream
on canvas with top-left corner at (frame_params.frameX,
frame_params.frameY), using Blending method
frame_params.blendingMethod.
canvas contains the decoded image.
Show the contents of the canvas for
frame_params.frameDuration * 1 ms.
dispose_method = frame_params.disposeMethod
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example File Layouts
--------------------
A lossy encoded image with alpha may look as follows:
A lossy-encoded image with alpha may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
@ -778,16 +834,16 @@ RIFF/WEBP
+- VP8 (bitstream)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A losslessly encoded image may look as follows:
A lossless-encoded image may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
+- VP8X (descriptions of features used)
+- XYZW (unknown chunk)
+- VP8L (lossless bitstream)
+- XYZW (unknown chunk)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A lossless image with ICC profile and XMP metadata may
A lossless image with an ICC profile and XMP metadata may
look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -811,9 +867,11 @@ RIFF/WEBP
+- EXIF (metadata)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[vp8spec]: https://datatracker.ietf.org/doc/html/rfc6386
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt
[iccspec]: https://www.color.org/icc_specs2.xalter
[metadata]: https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
[rec601]: https://www.itu.int/rec/R-REC-BT.601
[rfc 1166]: https://datatracker.ietf.org/doc/html/rfc1166
[rfc 2119]: https://datatracker.ietf.org/doc/html/rfc2119
[rfc 6386]: https://datatracker.ietf.org/doc/html/rfc6386
[rfc 8174]: https://datatracker.ietf.org/doc/html/rfc8174

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
# Ignore this file during non-NDK builds.
ifdef NDK_ROOT
LOCAL_PATH := $(call my-dir)
################################################################################
@ -91,3 +93,4 @@ LOCAL_STATIC_LIBRARIES := example_util imageio_util webp
LOCAL_MODULE := webpinfo_example
include $(BUILD_EXECUTABLE)
endif # NDK_ROOT

View File

@ -47,7 +47,7 @@ anim_dump_LDADD += ../imageio/libimageenc.la
anim_dump_LDADD += $(PNG_LIBS) $(GIF_LIBS) $(TIFF_LIBS) -lm
cwebp_SOURCES = cwebp.c stopwatch.h
cwebp_CPPFLAGS = $(AM_CPPFLAGS)
cwebp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)
cwebp_LDADD =
cwebp_LDADD += libexample_util.la
cwebp_LDADD += ../imageio/libimageio_util.la
@ -67,7 +67,7 @@ dwebp_LDADD += ../src/libwebp.la
dwebp_LDADD +=$(PNG_LIBS) $(JPEG_LIBS)
gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES)
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) -I$(top_srcdir)
gif2webp_LDADD =
gif2webp_LDADD += libexample_util.la
gif2webp_LDADD += ../imageio/libimageio_util.la
@ -92,7 +92,7 @@ webpmux_LDADD += ../src/mux/libwebpmux.la
webpmux_LDADD += ../src/libwebp.la
img2webp_SOURCES = img2webp.c
img2webp_CPPFLAGS = $(AM_CPPFLAGS)
img2webp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)
img2webp_LDADD =
img2webp_LDADD += libexample_util.la
img2webp_LDADD += ../imageio/libimageio_util.la

View File

@ -16,7 +16,7 @@
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h> // for 'strtod'.
#include <stdlib.h>
#include <string.h> // for 'strcmp'.
#include "./anim_util.h"
@ -206,8 +206,9 @@ static void Help(void) {
printf(" -version ............ print version number and exit\n");
}
// Returns 0 on success, 1 if animation files differ, and 2 for any error.
int main(int argc, const char* argv[]) {
int return_code = -1;
int return_code = 2;
int dump_frames = 0;
const char* dump_folder = NULL;
double min_psnr = 0.;
@ -269,18 +270,18 @@ int main(int argc, const char* argv[]) {
}
if (parse_error) {
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(return_code);
}
}
if (argc < 3) {
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(return_code);
}
if (!got_input2) {
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(return_code);
}
if (dump_frames) {
@ -293,7 +294,7 @@ int main(int argc, const char* argv[]) {
if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) {
WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n",
(const W_CHAR*)files[i]);
return_code = -2;
return_code = 2;
goto End;
} else {
MinimizeAnimationFrames(&images[i], max_diff);
@ -304,7 +305,7 @@ int main(int argc, const char* argv[]) {
premultiply, min_psnr)) {
WFPRINTF(stderr, "\nFiles %s and %s differ.\n", (const W_CHAR*)files[0],
(const W_CHAR*)files[1]);
return_code = -3;
return_code = 1;
} else {
WPRINTF("\nFiles %s and %s are identical.\n", (const W_CHAR*)files[0],
(const W_CHAR*)files[1]);

View File

@ -12,6 +12,7 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for 'strcmp'.
#include "./anim_util.h"
@ -35,6 +36,7 @@ static void Help(void) {
printf(" -version ............ print version number and exit\n");
}
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
int error = 0;
const W_CHAR* dump_folder = TO_W_CHAR(".");
@ -47,7 +49,7 @@ int main(int argc, const char* argv[]) {
if (argc < 2) {
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
for (c = 1; !error && c < argc; ++c) {
@ -73,7 +75,7 @@ int main(int argc, const char* argv[]) {
suffix = TO_W_CHAR("pam");
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-version")) {
int dec_version, demux_version;
GetAnimatedImageVersions(&dec_version, &demux_version);
@ -82,7 +84,7 @@ int main(int argc, const char* argv[]) {
(dec_version >> 0) & 0xff,
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
(demux_version >> 0) & 0xff);
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else {
uint32_t i;
AnimatedImage image;
@ -98,7 +100,11 @@ int main(int argc, const char* argv[]) {
for (i = 0; !error && i < image.num_frames; ++i) {
W_CHAR out_file[1024];
WebPDecBuffer buffer;
WebPInitDecBuffer(&buffer);
if (!WebPInitDecBuffer(&buffer)) {
fprintf(stderr, "Cannot init dec buffer\n");
error = 1;
continue;
}
buffer.colorspace = MODE_RGBA;
buffer.is_external_memory = 1;
buffer.width = image.canvas_width;
@ -117,5 +123,5 @@ int main(int argc, const char* argv[]) {
ClearAnimatedImage(&image);
}
}
FREE_WARGV_AND_RETURN(error ? 1 : 0);
FREE_WARGV_AND_RETURN(error ? EXIT_FAILURE : EXIT_SUCCESS);
}

View File

@ -771,6 +771,7 @@ void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
*psnr = 99.; // PSNR when images are identical.
} else {
sse /= stride * height;
assert(sse != 0.0);
*psnr = 4.3429448 * log(255. * 255. / sse);
}
}

View File

@ -27,6 +27,7 @@
#include "../imageio/webpdec.h"
#include "./stopwatch.h"
#include "./unicode.h"
#include "sharpyuv/sharpyuv.h"
#include "webp/encode.h"
#ifndef WEBP_DLL
@ -177,8 +178,14 @@ static void PrintFullLosslessInfo(const WebPAuxStats* const stats,
if (stats->lossless_features & 8) fprintf(stderr, " PALETTE");
fprintf(stderr, "\n");
}
fprintf(stderr, " * Precision Bits: histogram=%d transform=%d cache=%d\n",
stats->histogram_bits, stats->transform_bits, stats->cache_bits);
fprintf(stderr, " * Precision Bits: histogram=%d", stats->histogram_bits);
if (stats->lossless_features & 1) {
fprintf(stderr, " prediction=%d", stats->transform_bits);
}
if (stats->lossless_features & 2) {
fprintf(stderr, " cross-color=%d", stats->cross_color_transform_bits);
}
fprintf(stderr, " cache=%d\n", stats->cache_bits);
if (stats->palette_size > 0) {
fprintf(stderr, " * Palette size: %d\n", stats->palette_size);
}
@ -305,6 +312,7 @@ static int MyWriter(const uint8_t* data, size_t data_size,
// Dumps a picture as a PGM file using the IMC4 layout.
static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
int y;
int ok = 0;
const int uv_width = (picture->width + 1) / 2;
const int uv_height = (picture->height + 1) / 2;
const int stride = (picture->width + 1) & ~1;
@ -319,23 +327,26 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
if (f == NULL) return 0;
fprintf(f, "P5\n%d %d\n255\n", stride, height);
for (y = 0; y < picture->height; ++y) {
if (fwrite(src_y, picture->width, 1, f) != 1) return 0;
if (fwrite(src_y, picture->width, 1, f) != 1) goto Error;
if (picture->width & 1) fputc(0, f); // pad
src_y += picture->y_stride;
}
for (y = 0; y < uv_height; ++y) {
if (fwrite(src_u, uv_width, 1, f) != 1) return 0;
if (fwrite(src_v, uv_width, 1, f) != 1) return 0;
if (fwrite(src_u, uv_width, 1, f) != 1) goto Error;
if (fwrite(src_v, uv_width, 1, f) != 1) goto Error;
src_u += picture->uv_stride;
src_v += picture->uv_stride;
}
for (y = 0; y < alpha_height; ++y) {
if (fwrite(src_a, picture->width, 1, f) != 1) return 0;
if (fwrite(src_a, picture->width, 1, f) != 1) goto Error;
if (picture->width & 1) fputc(0, f); // pad
src_a += picture->a_stride;
}
ok = 1;
Error:
fclose(f);
return 1;
return ok;
}
// -----------------------------------------------------------------------------
@ -591,9 +602,8 @@ static void HelpLong(void) {
" green=0xe0 and blue=0xd0\n");
printf(" -noalpha ............... discard any transparency information\n");
printf(" -lossless .............. encode image losslessly, default=off\n");
printf(" -near_lossless <int> ... use near-lossless image\n"
" preprocessing (0..100=off), "
"default=100\n");
printf(" -near_lossless <int> ... use near-lossless image preprocessing\n"
" (0..100=off), default=100\n");
printf(" -hint <string> ......... specify image characteristics hint,\n");
printf(" one of: photo, picture or graph\n");
@ -647,8 +657,9 @@ static const char* const kErrorMessages[VP8_ENC_ERROR_LAST] = {
//------------------------------------------------------------------------------
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
int return_value = -1;
int return_value = EXIT_FAILURE;
const char* in_file = NULL, *out_file = NULL, *dump_file = NULL;
FILE* out = NULL;
int c;
@ -682,22 +693,22 @@ int main(int argc, const char* argv[]) {
!WebPPictureInit(&original_picture) ||
!WebPConfigInit(&config)) {
fprintf(stderr, "Error! Version mismatch!\n");
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
if (argc == 1) {
HelpShort();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
HelpShort();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
HelpLong();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-o") && c + 1 < argc) {
out_file = (const char*)GET_WARGV(argv, ++c);
} else if (!strcmp(argv[c], "-d") && c + 1 < argc) {
@ -832,9 +843,13 @@ int main(int argc, const char* argv[]) {
#endif
} else if (!strcmp(argv[c], "-version")) {
const int version = WebPGetEncoderVersion();
const int sharpyuv_version = SharpYuvGetVersion();
printf("%d.%d.%d\n",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
FREE_WARGV_AND_RETURN(0);
printf("libsharpyuv: %d.%d.%d\n",
(sharpyuv_version >> 24) & 0xff, (sharpyuv_version >> 16) & 0xffff,
sharpyuv_version & 0xff);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-progress")) {
show_progress = 1;
} else if (!strcmp(argv[c], "-quiet")) {
@ -896,7 +911,7 @@ int main(int argc, const char* argv[]) {
if (i == kNumTokens) {
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
(int)(token - start), start);
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
start = token + 1;
}
@ -915,14 +930,14 @@ int main(int argc, const char* argv[]) {
} else if (argv[c][0] == '-') {
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
HelpLong();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
} else {
in_file = (const char*)GET_WARGV(argv, c);
}
if (parse_error) {
HelpLong();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
}
if (in_file == NULL) {
@ -1140,9 +1155,10 @@ int main(int argc, const char* argv[]) {
}
picture.use_argb = 1;
if (!ReadWebP(memory_writer.mem, memory_writer.size, &picture,
/*keep_alpha=*/WebPPictureHasTransparency(&picture),
/*metadata=*/NULL)) {
if (!ReadWebP(
memory_writer.mem, memory_writer.size, &picture,
/*keep_alpha=*/WebPPictureHasTransparency(&original_picture),
/*metadata=*/NULL)) {
fprintf(stderr, "Error! Cannot decode encoded WebP bitstream\n");
fprintf(stderr, "Error code: %d (%s)\n", picture.error_code,
kErrorMessages[picture.error_code]);
@ -1222,7 +1238,7 @@ int main(int argc, const char* argv[]) {
PrintMetadataInfo(&metadata, metadata_written);
}
}
return_value = 0;
return_value = EXIT_SUCCESS;
Error:
WebPMemoryWriterClear(&memory_writer);

View File

@ -177,6 +177,7 @@ static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
return external_buffer;
}
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
int ok = 0;
const char* in_file = NULL;
@ -197,14 +198,14 @@ int main(int argc, const char* argv[]) {
if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n");
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
out_file = (const char*)GET_WARGV(argv, ++c);
} else if (!strcmp(argv[c], "-alpha")) {
@ -227,7 +228,7 @@ int main(int argc, const char* argv[]) {
const int version = WebPGetDecoderVersion();
printf("%d.%d.%d\n",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-pgm")) {
format = PGM;
} else if (!strcmp(argv[c], "-yuv")) {
@ -293,21 +294,21 @@ int main(int argc, const char* argv[]) {
} else if (argv[c][0] == '-') {
fprintf(stderr, "Unknown option '%s'\n", argv[c]);
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
} else {
in_file = (const char*)GET_WARGV(argv, c);
}
if (parse_error) {
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
}
if (in_file == NULL) {
fprintf(stderr, "missing input file!!\n");
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
if (quiet) verbose = 0;
@ -316,7 +317,7 @@ int main(int argc, const char* argv[]) {
VP8StatusCode status = VP8_STATUS_OK;
size_t data_size = 0;
if (!LoadWebP(in_file, &data, &data_size, bitstream)) {
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
switch (format) {
@ -415,7 +416,7 @@ int main(int argc, const char* argv[]) {
WebPFreeDecBuffer(output_buffer);
WebPFree((void*)external_buffer);
WebPFree((void*)data);
FREE_WARGV_AND_RETURN(ok ? 0 : -1);
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
//------------------------------------------------------------------------------

View File

@ -66,17 +66,17 @@ float ExUtilGetFloat(const char* const v, int* const error) {
static void ResetCommandLineArguments(int argc, const char* argv[],
CommandLineArguments* const args) {
assert(args != NULL);
args->argc_ = argc;
args->argv_ = argv;
args->own_argv_ = 0;
WebPDataInit(&args->argv_data_);
args->argc = argc;
args->argv = argv;
args->own_argv = 0;
WebPDataInit(&args->argv_data);
}
void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args) {
if (args != NULL) {
if (args->own_argv_) {
WebPFree((void*)args->argv_);
WebPDataClear(&args->argv_data_);
if (args->own_argv) {
WebPFree((void*)args->argv);
WebPDataClear(&args->argv_data);
}
ResetCommandLineArguments(0, NULL, args);
}
@ -98,18 +98,18 @@ int ExUtilInitCommandLineArguments(int argc, const char* argv[],
return 0;
#endif
if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data_)) {
if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data)) {
return 0;
}
args->own_argv_ = 1;
args->argv_ = (const char**)WebPMalloc(MAX_ARGC * sizeof(*args->argv_));
if (args->argv_ == NULL) {
args->own_argv = 1;
args->argv = (const char**)WebPMalloc(MAX_ARGC * sizeof(*args->argv));
if (args->argv == NULL) {
ExUtilDeleteCommandLineArguments(args);
return 0;
}
argc = 0;
for (cur = strtok((char*)args->argv_data_.bytes, sep);
for (cur = strtok((char*)args->argv_data.bytes, sep);
cur != NULL;
cur = strtok(NULL, sep)) {
if (argc == MAX_ARGC) {
@ -118,9 +118,9 @@ int ExUtilInitCommandLineArguments(int argc, const char* argv[],
return 0;
}
assert(strlen(cur) != 0);
args->argv_[argc++] = cur;
args->argv[argc++] = cur;
}
args->argc_ = argc;
args->argc = argc;
}
return 1;
}

View File

@ -45,10 +45,10 @@ int ExUtilReadFileToWebPData(const char* const filename,
// Command-line arguments
typedef struct {
int argc_;
const char** argv_;
WebPData argv_data_;
int own_argv_;
int argc;
const char** argv;
WebPData argv_data;
int own_argv;
} CommandLineArguments;
// Initializes the structure from the command-line parameters. If there is

View File

@ -28,6 +28,7 @@
#endif
#include <gif_lib.h>
#include "sharpyuv/sharpyuv.h"
#include "webp/encode.h"
#include "webp/mux.h"
#include "../examples/example_util.h"
@ -70,8 +71,14 @@ static void Help(void) {
printf(" -lossy ................. encode image using lossy compression\n");
printf(" -mixed ................. for each frame in the image, pick lossy\n"
" or lossless compression heuristically\n");
printf(" -near_lossless <int> ... use near-lossless image preprocessing\n"
" (0..100=off), default=100\n");
printf(" -sharp_yuv ............. use sharper (and slower) RGB->YUV "
"conversion\n"
" (lossy only)\n");
printf(" -q <float> ............. quality factor (0:small..100:big)\n");
printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n");
printf(" -m <int> ............... compression method (0=fast, 6=slowest), "
"default=4\n");
printf(" -min_size .............. minimize output size (default:off)\n"
" lossless compression by default; can be\n"
" combined with -q, -m, -lossy or -mixed\n"
@ -96,6 +103,7 @@ static void Help(void) {
//------------------------------------------------------------------------------
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
int verbose = 0;
int gif_error = GIF_ERROR;
@ -140,7 +148,7 @@ int main(int argc, const char* argv[]) {
!WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) ||
!WebPPictureInit(&prev_canvas)) {
fprintf(stderr, "Error! Version mismatch!\n");
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
config.lossless = 1; // Use lossless compression by default.
@ -150,14 +158,14 @@ int main(int argc, const char* argv[]) {
if (argc == 1) {
Help();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
out_file = GET_WARGV(argv, ++c);
} else if (!strcmp(argv[c], "-lossy")) {
@ -165,6 +173,10 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-mixed")) {
enc_options.allow_mixed = 1;
config.lossless = 0;
} else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) {
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-sharp_yuv")) {
config.use_sharp_yuv = 1;
} else if (!strcmp(argv[c], "-loop_compatibility")) {
loop_compatibility = 1;
} else if (!strcmp(argv[c], "-q") && c < argc - 1) {
@ -216,7 +228,7 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
(int)(token - start), start);
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
start = token + 1;
}
@ -225,11 +237,14 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-version")) {
const int enc_version = WebPGetEncoderVersion();
const int mux_version = WebPGetMuxVersion();
const int sharpyuv_version = SharpYuvGetVersion();
printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n",
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
enc_version & 0xff, (mux_version >> 16) & 0xff,
(mux_version >> 8) & 0xff, mux_version & 0xff);
FREE_WARGV_AND_RETURN(0);
printf("libsharpyuv: %d.%d.%d\n", (sharpyuv_version >> 24) & 0xff,
(sharpyuv_version >> 16) & 0xffff, sharpyuv_version & 0xff);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-quiet")) {
quiet = 1;
enc_options.verbose = 0;
@ -242,14 +257,14 @@ int main(int argc, const char* argv[]) {
} else if (argv[c][0] == '-') {
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
} else {
in_file = GET_WARGV(argv, c);
}
if (parse_error) {
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
}
@ -593,7 +608,7 @@ int main(int argc, const char* argv[]) {
#endif
}
FREE_WARGV_AND_RETURN(!ok);
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
#else // !WEBP_HAVE_GIF
@ -601,7 +616,7 @@ int main(int argc, const char* argv[]) {
int main(int argc, const char* argv[]) {
fprintf(stderr, "GIF support not enabled in %s.\n", argv[0]);
(void)argc;
return 0;
return EXIT_FAILURE;
}
#endif

View File

@ -317,7 +317,7 @@ void GIFDisplayError(const GifFileType* const gif, int gif_error) {
#else // !WEBP_HAVE_GIF
static void ErrorGIFNotAvailable() {
static void ErrorGIFNotAvailable(void) {
fprintf(stderr, "GIF support not compiled. Please install the libgif-dev "
"package before building.\n");
}

View File

@ -28,6 +28,7 @@
#include "../imageio/imageio_util.h"
#include "./stopwatch.h"
#include "./unicode.h"
#include "sharpyuv/sharpyuv.h"
#include "webp/encode.h"
#include "webp/mux.h"
@ -35,17 +36,22 @@
static void Help(void) {
printf("Usage:\n\n");
printf(" img2webp [file_options] [[frame_options] frame_file]...\n");
printf("\n");
printf(" img2webp [file_options] [[frame_options] frame_file]...");
printf(" [-o webp_file]\n\n");
printf("File-level options (only used at the start of compression):\n");
printf(" -min_size ............ minimize size\n");
printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
printf(" -kmax <int> .......... maximum number of frame between key-frames\n"
" (0=only keyframes)\n");
printf(" -kmin <int> .......... minimum number of frame between key-frames\n"
" (0=disable key-frames altogether)\n");
printf(" -mixed ............... use mixed lossy/lossless automatic mode\n");
printf(" -near_lossless <int> . use near-lossless image preprocessing\n"
" (0..100=off), default=100\n");
printf(" -sharp_yuv ........... use sharper (and slower) RGB->YUV "
"conversion\n "
"(lossy only)\n");
printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
printf(" -v ................... verbose mode\n");
printf(" -h ................... this help\n");
printf(" -version ............. print version number and exit\n");
@ -53,10 +59,15 @@ static void Help(void) {
printf("Per-frame options (only used for subsequent images input):\n");
printf(" -d <int> ............. frame duration in ms (default: 100)\n");
printf(" -lossless ........... use lossless mode (default)\n");
printf(" -lossy ... ........... use lossy mode\n");
printf(" -lossless ............ use lossless mode (default)\n");
printf(" -lossy ............... use lossy mode\n");
printf(" -q <float> ........... quality\n");
printf(" -m <int> ............. method to use\n");
printf(" -m <int> ............. compression method (0=fast, 6=slowest), "
"default=4\n");
printf(" -exact, -noexact ..... preserve or alter RGB values in transparent "
"area\n"
" (default: -noexact, may cause artifacts\n"
" with lossy animations)\n");
printf("\n");
printf("example: img2webp -loop 2 in0.png -lossy in1.jpg\n"
@ -124,6 +135,7 @@ static int SetLoopCount(int loop_count, WebPData* const webp_data) {
//------------------------------------------------------------------------------
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
const char* output = NULL;
WebPAnimEncoder* enc = NULL;
@ -139,16 +151,17 @@ int main(int argc, const char* argv[]) {
WebPData webp_data;
int c;
int have_input = 0;
int last_input_index = 0;
CommandLineArguments cmd_args;
int ok;
INIT_WARGV(argc, argv);
ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args);
if (!ok) FREE_WARGV_AND_RETURN(1);
if (!ok) FREE_WARGV_AND_RETURN(EXIT_FAILURE);
argc = cmd_args.argc_;
argv = cmd_args.argv_;
argc = cmd_args.argc;
argv = cmd_args.argv;
WebPDataInit(&webp_data);
if (!WebPAnimEncoderOptionsInit(&anim_config) ||
@ -184,18 +197,26 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-mixed")) {
anim_config.allow_mixed = 1;
config.lossless = 0;
} else if (!strcmp(argv[c], "-near_lossless") && c + 1 < argc) {
argv[c] = NULL;
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-sharp_yuv")) {
config.use_sharp_yuv = 1;
} else if (!strcmp(argv[c], "-v")) {
verbose = 1;
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-version")) {
const int enc_version = WebPGetEncoderVersion();
const int mux_version = WebPGetMuxVersion();
const int sharpyuv_version = SharpYuvGetVersion();
printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n",
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
enc_version & 0xff, (mux_version >> 16) & 0xff,
(mux_version >> 8) & 0xff, mux_version & 0xff);
printf("libsharpyuv: %d.%d.%d\n", (sharpyuv_version >> 24) & 0xff,
(sharpyuv_version >> 16) & 0xffff, sharpyuv_version & 0xff);
goto End;
} else {
continue;
@ -209,6 +230,8 @@ int main(int argc, const char* argv[]) {
}
if (!have_input) {
fprintf(stderr, "No input file(s) for generating animation!\n");
ok = 0;
Help();
goto End;
}
@ -233,6 +256,10 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Invalid negative duration (%d)\n", duration);
parse_error = 1;
}
} else if (!strcmp(argv[c], "-exact")) {
config.exact = 1;
} else if (!strcmp(argv[c], "-noexact")) {
config.exact = 0;
} else {
parse_error = 1; // shouldn't be here.
fprintf(stderr, "Unknown option [%s]\n", argv[c]);
@ -253,6 +280,7 @@ int main(int argc, const char* argv[]) {
// read next input image
pic.use_argb = 1;
ok = ReadImage((const char*)GET_WARGV_SHIFTED(argv, c), &pic);
last_input_index = c;
if (!ok) goto End;
if (enc == NULL) {
@ -291,6 +319,13 @@ int main(int argc, const char* argv[]) {
++pic_num;
}
for (c = last_input_index + 1; c < argc; ++c) {
if (argv[c] != NULL) {
fprintf(stderr, "Warning: unused option [%s]!"
" Frame options go before the input frame.\n", argv[c]);
}
}
// add a last fake frame to signal the last duration
ok = ok && WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL);
ok = ok && WebPAnimEncoderAssemble(enc, &webp_data);
@ -321,5 +356,5 @@ int main(int argc, const char* argv[]) {
}
WebPDataClear(&webp_data);
ExUtilDeleteCommandLineArguments(&cmd_args);
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}

View File

@ -18,6 +18,7 @@
#define _POSIX_C_SOURCE 200112L // for setenv
#endif
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -430,10 +431,13 @@ static void HandleDisplay(void) {
#endif
}
static void StartDisplay(void) {
static void StartDisplay(const char* filename) {
int width = kParams.canvas_width;
int height = kParams.canvas_height;
int screen_width, screen_height;
const char viewername[] = " - WebP viewer";
// max linux file len + viewername string
char title[4096 + sizeof(viewername)] = "";
// TODO(webp:365) GLUT_DOUBLE results in flickering / old frames to be
// partially displayed with animated webp + alpha.
#if defined(__APPLE__) || defined(_WIN32)
@ -453,8 +457,9 @@ static void StartDisplay(void) {
height = screen_height;
}
}
snprintf(title, sizeof(title), "%s%s", filename, viewername);
glutInitWindowSize(width, height);
glutCreateWindow("WebP viewer");
glutCreateWindow(title);
glutDisplayFunc(HandleDisplay);
glutReshapeFunc(HandleReshape);
glutIdleFunc(NULL);
@ -493,7 +498,7 @@ static void Help(void) {
}
int main(int argc, char* argv[]) {
int c;
int c, file_name_argv_index = 1;
WebPDecoderConfig* const config = &kParams.config;
WebPIterator* const curr = &kParams.curr_frame;
@ -501,7 +506,7 @@ int main(int argc, char* argv[]) {
if (!WebPInitDecoderConfig(config)) {
fprintf(stderr, "Library version mismatch!\n");
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
config->options.dithering_strength = 50;
config->options.alpha_dithering_strength = 100;
@ -513,7 +518,7 @@ int main(int argc, char* argv[]) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-noicc")) {
kParams.use_color_profile = 0;
} else if (!strcmp(argv[c], "-nofancy")) {
@ -536,30 +541,34 @@ int main(int argc, char* argv[]) {
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
dec_version & 0xff, (dmux_version >> 16) & 0xff,
(dmux_version >> 8) & 0xff, dmux_version & 0xff);
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-mt")) {
config->options.use_threads = 1;
} else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) kParams.file_name = (const char*)GET_WARGV(argv, ++c);
if (c < argc - 1) {
kParams.file_name = (const char*)GET_WARGV(argv, ++c);
file_name_argv_index = c;
}
break;
} else if (argv[c][0] == '-') {
printf("Unknown option '%s'\n", argv[c]);
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
} else {
kParams.file_name = (const char*)GET_WARGV(argv, c);
file_name_argv_index = c;
}
if (parse_error) {
Help();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
}
if (kParams.file_name == NULL) {
printf("missing input file!!\n");
Help();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
if (!ImgIoUtilReadFile(kParams.file_name,
@ -613,7 +622,7 @@ int main(int argc, char* argv[]) {
// Position iterator to last frame. Next call to HandleDisplay will wrap over.
// We take this into account by bumping up loop_count.
WebPDemuxGetFrame(kParams.dmux, 0, curr);
if (!WebPDemuxGetFrame(kParams.dmux, 0, curr)) goto Error;
if (kParams.loop_count) ++kParams.loop_count;
#if defined(__unix__) || defined(__CYGWIN__)
@ -627,18 +636,18 @@ int main(int argc, char* argv[]) {
#ifdef FREEGLUT
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
#endif
StartDisplay();
StartDisplay(argv[file_name_argv_index]);
if (kParams.has_animation) glutTimerFunc(0, decode_callback, 0);
glutMainLoop();
// Should only be reached when using FREEGLUT:
ClearParams();
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
Error:
ClearParams();
FREE_WARGV_AND_RETURN(-1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
#else // !WEBP_HAVE_GL
@ -646,7 +655,7 @@ int main(int argc, char* argv[]) {
int main(int argc, const char* argv[]) {
fprintf(stderr, "OpenGL support not enabled in %s.\n", argv[0]);
(void)argc;
return 0;
return EXIT_FAILURE;
}
#endif

View File

@ -14,6 +14,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
@ -31,17 +32,17 @@
#define LOG_ERROR(MESSAGE) \
do { \
if (webp_info->show_diagnosis_) { \
if (webp_info->show_diagnosis) { \
fprintf(stderr, "Error: %s\n", MESSAGE); \
} \
} while (0)
#define LOG_WARN(MESSAGE) \
do { \
if (webp_info->show_diagnosis_) { \
if (webp_info->show_diagnosis) { \
fprintf(stderr, "Warning: %s\n", MESSAGE); \
} \
++webp_info->num_warnings_; \
++webp_info->num_warnings; \
} while (0)
static const char* const kFormats[3] = {
@ -89,36 +90,36 @@ typedef enum ChunkID {
} ChunkID;
typedef struct {
size_t start_;
size_t end_;
const uint8_t* buf_;
size_t start;
size_t end;
const uint8_t* buf;
} MemBuffer;
typedef struct {
size_t offset_;
size_t size_;
const uint8_t* payload_;
ChunkID id_;
size_t offset;
size_t size;
const uint8_t* payload;
ChunkID id;
} ChunkData;
typedef struct WebPInfo {
int canvas_width_;
int canvas_height_;
int loop_count_;
int num_frames_;
int chunk_counts_[CHUNK_TYPES];
int anmf_subchunk_counts_[3]; // 0 VP8; 1 VP8L; 2 ALPH.
uint32_t bgcolor_;
int feature_flags_;
int has_alpha_;
int canvas_width;
int canvas_height;
int loop_count;
int num_frames;
int chunk_counts[CHUNK_TYPES];
int anmf_subchunk_counts[3]; // 0 VP8; 1 VP8L; 2 ALPH.
uint32_t bgcolor;
int feature_flags;
int has_alpha;
// Used for parsing ANMF chunks.
int frame_width_, frame_height_;
size_t anim_frame_data_size_;
int is_processing_anim_frame_, seen_alpha_subchunk_, seen_image_subchunk_;
int frame_width, frame_height;
size_t anim_frame_data_size;
int is_processing_anim_frame, seen_alpha_subchunk, seen_image_subchunk;
// Print output control.
int quiet_, show_diagnosis_, show_summary_;
int num_warnings_;
int parse_bitstream_;
int quiet, show_diagnosis, show_summary;
int num_warnings;
int parse_bitstream;
} WebPInfo;
static void WebPInfoInit(WebPInfo* const webp_info) {
@ -184,25 +185,25 @@ static int ReadFileToWebPData(const char* const filename,
// MemBuffer object.
static void InitMemBuffer(MemBuffer* const mem, const WebPData* webp_data) {
mem->buf_ = webp_data->bytes;
mem->start_ = 0;
mem->end_ = webp_data->size;
mem->buf = webp_data->bytes;
mem->start = 0;
mem->end = webp_data->size;
}
static size_t MemDataSize(const MemBuffer* const mem) {
return (mem->end_ - mem->start_);
return (mem->end - mem->start);
}
static const uint8_t* GetBuffer(MemBuffer* const mem) {
return mem->buf_ + mem->start_;
return mem->buf + mem->start;
}
static void Skip(MemBuffer* const mem, size_t size) {
mem->start_ += size;
mem->start += size;
}
static uint32_t ReadMemBufLE32(MemBuffer* const mem) {
const uint8_t* const data = mem->buf_ + mem->start_;
const uint8_t* const data = mem->buf + mem->start;
const uint32_t val = GetLE32(data);
assert(MemDataSize(mem) >= 4);
Skip(mem, 4);
@ -333,8 +334,8 @@ static WebPInfoStatus ParseLossyFilterHeader(const WebPInfo* const webp_info,
static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
const WebPInfo* const webp_info) {
const uint8_t* data = chunk_data->payload_;
size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
const uint8_t* data = chunk_data->payload;
size_t data_size = chunk_data->size - CHUNK_HEADER_SIZE;
const uint32_t bits = (uint32_t)data[0] | (data[1] << 8) | (data[2] << 16);
const int key_frame = !(bits & 1);
const int profile = (bits >> 1) & 7;
@ -346,7 +347,7 @@ static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
int colorspace, clamp_type;
printf(" Parsing lossy bitstream...\n");
// Calling WebPGetFeatures() in ProcessImageChunk() should ensure this.
assert(chunk_data->size_ >= CHUNK_HEADER_SIZE + 10);
assert(chunk_data->size >= CHUNK_HEADER_SIZE + 10);
if (profile > 3) {
LOG_ERROR("Unknown profile.");
return WEBP_INFO_BITSTREAM_ERROR;
@ -357,12 +358,12 @@ static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
}
data += 3;
data_size -= 3;
printf(" Key frame: %s\n"
" Profile: %d\n"
" Display: %s\n"
" Part. 0 length: %d\n",
key_frame ? "Yes" : "No", profile,
display ? "Yes" : "No", partition0_length);
printf(
" Key frame: %s\n"
" Profile: %d\n"
" Display: Yes\n"
" Part. 0 length: %d\n",
key_frame ? "Yes" : "No", profile, partition0_length);
if (key_frame) {
if (!(data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a)) {
LOG_ERROR("Invalid lossy bitstream signature.");
@ -504,8 +505,8 @@ static WebPInfoStatus ParseLosslessTransform(WebPInfo* const webp_info,
static WebPInfoStatus ParseLosslessHeader(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
const uint8_t* data = chunk_data->payload_;
size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
const uint8_t* data = chunk_data->payload;
size_t data_size = chunk_data->size - CHUNK_HEADER_SIZE;
uint64_t bit_position = 0;
uint64_t* const bit_pos = &bit_position;
WebPInfoStatus status;
@ -540,8 +541,8 @@ static WebPInfoStatus ParseLosslessHeader(const ChunkData* const chunk_data,
static WebPInfoStatus ParseAlphaHeader(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
const uint8_t* data = chunk_data->payload_;
size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
const uint8_t* data = chunk_data->payload;
size_t data_size = chunk_data->size - CHUNK_HEADER_SIZE;
if (data_size <= ALPHA_HEADER_LEN) {
LOG_ERROR("Truncated ALPH chunk.");
return WEBP_INFO_TRUNCATED_DATA;
@ -606,14 +607,14 @@ static WebPInfoStatus ParseRIFFHeader(WebPInfo* const webp_info,
return WEBP_INFO_PARSE_ERROR;
}
riff_size += CHUNK_HEADER_SIZE;
if (!webp_info->quiet_) {
if (!webp_info->quiet) {
printf("RIFF HEADER:\n");
printf(" File size: %6d\n", (int)riff_size);
}
if (riff_size < mem->end_) {
if (riff_size < mem->end) {
LOG_WARN("RIFF size is smaller than the file size.");
mem->end_ = riff_size;
} else if (riff_size > mem->end_) {
mem->end = riff_size;
} else if (riff_size > mem->end) {
LOG_ERROR("Truncated data detected when parsing RIFF payload.");
return WEBP_INFO_TRUNCATED_DATA;
}
@ -629,7 +630,7 @@ static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info,
LOG_ERROR("Truncated data detected when parsing chunk header.");
return WEBP_INFO_TRUNCATED_DATA;
} else {
const size_t chunk_start_offset = mem->start_;
const size_t chunk_start_offset = mem->start;
const uint32_t fourcc = ReadMemBufLE32(mem);
const uint32_t payload_size = ReadMemBufLE32(mem);
const uint32_t payload_size_padded = payload_size + (payload_size & 1);
@ -646,11 +647,11 @@ static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info,
for (i = 0; i < CHUNK_TYPES; ++i) {
if (kWebPChunkTags[i] == fourcc) break;
}
chunk_data->offset_ = chunk_start_offset;
chunk_data->size_ = chunk_size;
chunk_data->id_ = (ChunkID)i;
chunk_data->payload_ = GetBuffer(mem);
if (chunk_data->id_ == CHUNK_ANMF) {
chunk_data->offset = chunk_start_offset;
chunk_data->size = chunk_size;
chunk_data->id = (ChunkID)i;
chunk_data->payload = GetBuffer(mem);
if (chunk_data->id == CHUNK_ANMF) {
if (payload_size != payload_size_padded) {
LOG_ERROR("ANMF chunk size should always be even.");
return WEBP_INFO_PARSE_ERROR;
@ -669,39 +670,39 @@ static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info,
static WebPInfoStatus ProcessVP8XChunk(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
const uint8_t* data = chunk_data->payload_;
if (webp_info->chunk_counts_[CHUNK_VP8] ||
webp_info->chunk_counts_[CHUNK_VP8L] ||
webp_info->chunk_counts_[CHUNK_VP8X]) {
const uint8_t* data = chunk_data->payload;
if (webp_info->chunk_counts[CHUNK_VP8] ||
webp_info->chunk_counts[CHUNK_VP8L] ||
webp_info->chunk_counts[CHUNK_VP8X]) {
LOG_ERROR("Already seen a VP8/VP8L/VP8X chunk when parsing VP8X chunk.");
return WEBP_INFO_PARSE_ERROR;
}
if (chunk_data->size_ != VP8X_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
if (chunk_data->size != VP8X_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
LOG_ERROR("Corrupted VP8X chunk.");
return WEBP_INFO_PARSE_ERROR;
}
++webp_info->chunk_counts_[CHUNK_VP8X];
webp_info->feature_flags_ = *data;
++webp_info->chunk_counts[CHUNK_VP8X];
webp_info->feature_flags = *data;
data += 4;
webp_info->canvas_width_ = 1 + ReadLE24(&data);
webp_info->canvas_height_ = 1 + ReadLE24(&data);
if (!webp_info->quiet_) {
webp_info->canvas_width = 1 + ReadLE24(&data);
webp_info->canvas_height = 1 + ReadLE24(&data);
if (!webp_info->quiet) {
printf(" ICCP: %d\n Alpha: %d\n EXIF: %d\n XMP: %d\n Animation: %d\n",
(webp_info->feature_flags_ & ICCP_FLAG) != 0,
(webp_info->feature_flags_ & ALPHA_FLAG) != 0,
(webp_info->feature_flags_ & EXIF_FLAG) != 0,
(webp_info->feature_flags_ & XMP_FLAG) != 0,
(webp_info->feature_flags_ & ANIMATION_FLAG) != 0);
(webp_info->feature_flags & ICCP_FLAG) != 0,
(webp_info->feature_flags & ALPHA_FLAG) != 0,
(webp_info->feature_flags & EXIF_FLAG) != 0,
(webp_info->feature_flags & XMP_FLAG) != 0,
(webp_info->feature_flags & ANIMATION_FLAG) != 0);
printf(" Canvas size %d x %d\n",
webp_info->canvas_width_, webp_info->canvas_height_);
webp_info->canvas_width, webp_info->canvas_height);
}
if (webp_info->canvas_width_ > MAX_CANVAS_SIZE) {
if (webp_info->canvas_width > MAX_CANVAS_SIZE) {
LOG_WARN("Canvas width is out of range in VP8X chunk.");
}
if (webp_info->canvas_height_ > MAX_CANVAS_SIZE) {
if (webp_info->canvas_height > MAX_CANVAS_SIZE) {
LOG_WARN("Canvas height is out of range in VP8X chunk.");
}
if ((uint64_t)webp_info->canvas_width_ * webp_info->canvas_height_ >
if ((uint64_t)webp_info->canvas_width * webp_info->canvas_height >
MAX_IMAGE_AREA) {
LOG_WARN("Canvas area is out of range in VP8X chunk.");
}
@ -710,27 +711,27 @@ static WebPInfoStatus ProcessVP8XChunk(const ChunkData* const chunk_data,
static WebPInfoStatus ProcessANIMChunk(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
const uint8_t* data = chunk_data->payload_;
if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
const uint8_t* data = chunk_data->payload;
if (!webp_info->chunk_counts[CHUNK_VP8X]) {
LOG_ERROR("ANIM chunk detected before VP8X chunk.");
return WEBP_INFO_PARSE_ERROR;
}
if (chunk_data->size_ != ANIM_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
if (chunk_data->size != ANIM_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
LOG_ERROR("Corrupted ANIM chunk.");
return WEBP_INFO_PARSE_ERROR;
}
webp_info->bgcolor_ = ReadLE32(&data);
webp_info->loop_count_ = ReadLE16(&data);
++webp_info->chunk_counts_[CHUNK_ANIM];
if (!webp_info->quiet_) {
webp_info->bgcolor = ReadLE32(&data);
webp_info->loop_count = ReadLE16(&data);
++webp_info->chunk_counts[CHUNK_ANIM];
if (!webp_info->quiet) {
printf(" Background color:(ARGB) %02x %02x %02x %02x\n",
(webp_info->bgcolor_ >> 24) & 0xff,
(webp_info->bgcolor_ >> 16) & 0xff,
(webp_info->bgcolor_ >> 8) & 0xff,
webp_info->bgcolor_ & 0xff);
printf(" Loop count : %d\n", webp_info->loop_count_);
(webp_info->bgcolor >> 24) & 0xff,
(webp_info->bgcolor >> 16) & 0xff,
(webp_info->bgcolor >> 8) & 0xff,
webp_info->bgcolor & 0xff);
printf(" Loop count : %d\n", webp_info->loop_count);
}
if (webp_info->loop_count_ > MAX_LOOP_COUNT) {
if (webp_info->loop_count > MAX_LOOP_COUNT) {
LOG_WARN("Loop count is out of range in ANIM chunk.");
}
return WEBP_INFO_OK;
@ -738,17 +739,17 @@ static WebPInfoStatus ProcessANIMChunk(const ChunkData* const chunk_data,
static WebPInfoStatus ProcessANMFChunk(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
const uint8_t* data = chunk_data->payload_;
const uint8_t* data = chunk_data->payload;
int offset_x, offset_y, width, height, duration, blend, dispose, temp;
if (webp_info->is_processing_anim_frame_) {
if (webp_info->is_processing_anim_frame) {
LOG_ERROR("ANMF chunk detected within another ANMF chunk.");
return WEBP_INFO_PARSE_ERROR;
}
if (!webp_info->chunk_counts_[CHUNK_ANIM]) {
if (!webp_info->chunk_counts[CHUNK_ANIM]) {
LOG_ERROR("ANMF chunk detected before ANIM chunk.");
return WEBP_INFO_PARSE_ERROR;
}
if (chunk_data->size_ <= CHUNK_HEADER_SIZE + ANMF_CHUNK_SIZE) {
if (chunk_data->size <= CHUNK_HEADER_SIZE + ANMF_CHUNK_SIZE) {
LOG_ERROR("Truncated data detected when parsing ANMF chunk.");
return WEBP_INFO_TRUNCATED_DATA;
}
@ -760,8 +761,8 @@ static WebPInfoStatus ProcessANMFChunk(const ChunkData* const chunk_data,
temp = *data;
dispose = temp & 1;
blend = (temp >> 1) & 1;
++webp_info->chunk_counts_[CHUNK_ANMF];
if (!webp_info->quiet_) {
++webp_info->chunk_counts[CHUNK_ANMF];
if (!webp_info->quiet) {
printf(" Offset_X: %d\n Offset_Y: %d\n Width: %d\n Height: %d\n"
" Duration: %d\n Dispose: %d\n Blend: %d\n",
offset_x, offset_y, width, height, duration, dispose, blend);
@ -774,92 +775,92 @@ static WebPInfoStatus ProcessANMFChunk(const ChunkData* const chunk_data,
LOG_ERROR("Invalid offset parameters in ANMF chunk.");
return WEBP_INFO_INVALID_PARAM;
}
if ((uint64_t)offset_x + width > (uint64_t)webp_info->canvas_width_ ||
(uint64_t)offset_y + height > (uint64_t)webp_info->canvas_height_) {
if ((uint64_t)offset_x + width > (uint64_t)webp_info->canvas_width ||
(uint64_t)offset_y + height > (uint64_t)webp_info->canvas_height) {
LOG_ERROR("Frame exceeds canvas in ANMF chunk.");
return WEBP_INFO_INVALID_PARAM;
}
webp_info->is_processing_anim_frame_ = 1;
webp_info->seen_alpha_subchunk_ = 0;
webp_info->seen_image_subchunk_ = 0;
webp_info->frame_width_ = width;
webp_info->frame_height_ = height;
webp_info->anim_frame_data_size_ =
chunk_data->size_ - CHUNK_HEADER_SIZE - ANMF_CHUNK_SIZE;
webp_info->is_processing_anim_frame = 1;
webp_info->seen_alpha_subchunk = 0;
webp_info->seen_image_subchunk = 0;
webp_info->frame_width = width;
webp_info->frame_height = height;
webp_info->anim_frame_data_size =
chunk_data->size - CHUNK_HEADER_SIZE - ANMF_CHUNK_SIZE;
return WEBP_INFO_OK;
}
static WebPInfoStatus ProcessImageChunk(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
const uint8_t* data = chunk_data->payload_ - CHUNK_HEADER_SIZE;
const uint8_t* data = chunk_data->payload - CHUNK_HEADER_SIZE;
WebPBitstreamFeatures features;
const VP8StatusCode vp8_status =
WebPGetFeatures(data, chunk_data->size_, &features);
WebPGetFeatures(data, chunk_data->size, &features);
if (vp8_status != VP8_STATUS_OK) {
LOG_ERROR("VP8/VP8L bitstream error.");
return WEBP_INFO_BITSTREAM_ERROR;
}
if (!webp_info->quiet_) {
if (!webp_info->quiet) {
assert(features.format >= 0 && features.format <= 2);
printf(" Width: %d\n Height: %d\n Alpha: %d\n Animation: %d\n"
" Format: %s (%d)\n",
features.width, features.height, features.has_alpha,
features.has_animation, kFormats[features.format], features.format);
}
if (webp_info->is_processing_anim_frame_) {
++webp_info->anmf_subchunk_counts_[chunk_data->id_ == CHUNK_VP8 ? 0 : 1];
if (chunk_data->id_ == CHUNK_VP8L && webp_info->seen_alpha_subchunk_) {
if (webp_info->is_processing_anim_frame) {
++webp_info->anmf_subchunk_counts[chunk_data->id == CHUNK_VP8 ? 0 : 1];
if (chunk_data->id == CHUNK_VP8L && webp_info->seen_alpha_subchunk) {
LOG_ERROR("Both VP8L and ALPH sub-chunks are present in an ANMF chunk.");
return WEBP_INFO_PARSE_ERROR;
}
if (webp_info->frame_width_ != features.width ||
webp_info->frame_height_ != features.height) {
if (webp_info->frame_width != features.width ||
webp_info->frame_height != features.height) {
LOG_ERROR("Frame size in VP8/VP8L sub-chunk differs from ANMF header.");
return WEBP_INFO_PARSE_ERROR;
}
if (webp_info->seen_image_subchunk_) {
if (webp_info->seen_image_subchunk) {
LOG_ERROR("Consecutive VP8/VP8L sub-chunks in an ANMF chunk.");
return WEBP_INFO_PARSE_ERROR;
}
webp_info->seen_image_subchunk_ = 1;
webp_info->seen_image_subchunk = 1;
} else {
if (webp_info->chunk_counts_[CHUNK_VP8] ||
webp_info->chunk_counts_[CHUNK_VP8L]) {
if (webp_info->chunk_counts[CHUNK_VP8] ||
webp_info->chunk_counts[CHUNK_VP8L]) {
LOG_ERROR("Multiple VP8/VP8L chunks detected.");
return WEBP_INFO_PARSE_ERROR;
}
if (chunk_data->id_ == CHUNK_VP8L &&
webp_info->chunk_counts_[CHUNK_ALPHA]) {
if (chunk_data->id == CHUNK_VP8L &&
webp_info->chunk_counts[CHUNK_ALPHA]) {
LOG_WARN("Both VP8L and ALPH chunks are detected.");
}
if (webp_info->chunk_counts_[CHUNK_ANIM] ||
webp_info->chunk_counts_[CHUNK_ANMF]) {
if (webp_info->chunk_counts[CHUNK_ANIM] ||
webp_info->chunk_counts[CHUNK_ANMF]) {
LOG_ERROR("VP8/VP8L chunk and ANIM/ANMF chunk are both detected.");
return WEBP_INFO_PARSE_ERROR;
}
if (webp_info->chunk_counts_[CHUNK_VP8X]) {
if (webp_info->canvas_width_ != features.width ||
webp_info->canvas_height_ != features.height) {
if (webp_info->chunk_counts[CHUNK_VP8X]) {
if (webp_info->canvas_width != features.width ||
webp_info->canvas_height != features.height) {
LOG_ERROR("Image size in VP8/VP8L chunk differs from VP8X chunk.");
return WEBP_INFO_PARSE_ERROR;
}
} else {
webp_info->canvas_width_ = features.width;
webp_info->canvas_height_ = features.height;
if (webp_info->canvas_width_ < 1 || webp_info->canvas_height_ < 1 ||
webp_info->canvas_width_ > MAX_CANVAS_SIZE ||
webp_info->canvas_height_ > MAX_CANVAS_SIZE ||
(uint64_t)webp_info->canvas_width_ * webp_info->canvas_height_ >
webp_info->canvas_width = features.width;
webp_info->canvas_height = features.height;
if (webp_info->canvas_width < 1 || webp_info->canvas_height < 1 ||
webp_info->canvas_width > MAX_CANVAS_SIZE ||
webp_info->canvas_height > MAX_CANVAS_SIZE ||
(uint64_t)webp_info->canvas_width * webp_info->canvas_height >
MAX_IMAGE_AREA) {
LOG_WARN("Invalid parameters in VP8/VP8L chunk.");
}
}
++webp_info->chunk_counts_[chunk_data->id_];
++webp_info->chunk_counts[chunk_data->id];
}
++webp_info->num_frames_;
webp_info->has_alpha_ |= features.has_alpha;
if (webp_info->parse_bitstream_) {
const int is_lossy = (chunk_data->id_ == CHUNK_VP8);
++webp_info->num_frames;
webp_info->has_alpha |= features.has_alpha;
if (webp_info->parse_bitstream) {
const int is_lossy = (chunk_data->id == CHUNK_VP8);
const WebPInfoStatus status =
is_lossy ? ParseLossyHeader(chunk_data, webp_info)
: ParseLosslessHeader(chunk_data, webp_info);
@ -870,41 +871,41 @@ static WebPInfoStatus ProcessImageChunk(const ChunkData* const chunk_data,
static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
if (webp_info->is_processing_anim_frame_) {
++webp_info->anmf_subchunk_counts_[2];
if (webp_info->seen_alpha_subchunk_) {
if (webp_info->is_processing_anim_frame) {
++webp_info->anmf_subchunk_counts[2];
if (webp_info->seen_alpha_subchunk) {
LOG_ERROR("Consecutive ALPH sub-chunks in an ANMF chunk.");
return WEBP_INFO_PARSE_ERROR;
}
webp_info->seen_alpha_subchunk_ = 1;
webp_info->seen_alpha_subchunk = 1;
if (webp_info->seen_image_subchunk_) {
if (webp_info->seen_image_subchunk) {
LOG_ERROR("ALPHA sub-chunk detected after VP8 sub-chunk "
"in an ANMF chunk.");
return WEBP_INFO_PARSE_ERROR;
}
} else {
if (webp_info->chunk_counts_[CHUNK_ANIM] ||
webp_info->chunk_counts_[CHUNK_ANMF]) {
if (webp_info->chunk_counts[CHUNK_ANIM] ||
webp_info->chunk_counts[CHUNK_ANMF]) {
LOG_ERROR("ALPHA chunk and ANIM/ANMF chunk are both detected.");
return WEBP_INFO_PARSE_ERROR;
}
if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
if (!webp_info->chunk_counts[CHUNK_VP8X]) {
LOG_ERROR("ALPHA chunk detected before VP8X chunk.");
return WEBP_INFO_PARSE_ERROR;
}
if (webp_info->chunk_counts_[CHUNK_VP8]) {
if (webp_info->chunk_counts[CHUNK_VP8]) {
LOG_ERROR("ALPHA chunk detected after VP8 chunk.");
return WEBP_INFO_PARSE_ERROR;
}
if (webp_info->chunk_counts_[CHUNK_ALPHA]) {
if (webp_info->chunk_counts[CHUNK_ALPHA]) {
LOG_ERROR("Multiple ALPHA chunks detected.");
return WEBP_INFO_PARSE_ERROR;
}
++webp_info->chunk_counts_[CHUNK_ALPHA];
++webp_info->chunk_counts[CHUNK_ALPHA];
}
webp_info->has_alpha_ = 1;
if (webp_info->parse_bitstream_) {
webp_info->has_alpha = 1;
if (webp_info->parse_bitstream) {
const WebPInfoStatus status = ParseAlphaHeader(chunk_data, webp_info);
if (status != WEBP_INFO_OK) return status;
}
@ -914,41 +915,41 @@ static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data,
static WebPInfoStatus ProcessICCPChunk(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
(void)chunk_data;
if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
if (!webp_info->chunk_counts[CHUNK_VP8X]) {
LOG_ERROR("ICCP chunk detected before VP8X chunk.");
return WEBP_INFO_PARSE_ERROR;
}
if (webp_info->chunk_counts_[CHUNK_VP8] ||
webp_info->chunk_counts_[CHUNK_VP8L] ||
webp_info->chunk_counts_[CHUNK_ANIM]) {
if (webp_info->chunk_counts[CHUNK_VP8] ||
webp_info->chunk_counts[CHUNK_VP8L] ||
webp_info->chunk_counts[CHUNK_ANIM]) {
LOG_ERROR("ICCP chunk detected after image data.");
return WEBP_INFO_PARSE_ERROR;
}
++webp_info->chunk_counts_[CHUNK_ICCP];
++webp_info->chunk_counts[CHUNK_ICCP];
return WEBP_INFO_OK;
}
static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
WebPInfoStatus status = WEBP_INFO_OK;
ChunkID id = chunk_data->id_;
if (chunk_data->id_ == CHUNK_UNKNOWN) {
ChunkID id = chunk_data->id;
if (chunk_data->id == CHUNK_UNKNOWN) {
char error_message[50];
snprintf(error_message, 50, "Unknown chunk at offset %6d, length %6d",
(int)chunk_data->offset_, (int)chunk_data->size_);
(int)chunk_data->offset, (int)chunk_data->size);
LOG_WARN(error_message);
} else {
if (!webp_info->quiet_) {
if (!webp_info->quiet) {
char tag[4];
uint32_t fourcc = kWebPChunkTags[chunk_data->id_];
uint32_t fourcc = kWebPChunkTags[chunk_data->id];
#ifdef WORDS_BIGENDIAN
fourcc = (fourcc >> 24) | ((fourcc >> 8) & 0xff00) |
((fourcc << 8) & 0xff0000) | (fourcc << 24);
#endif
memcpy(tag, &fourcc, sizeof(tag));
printf("Chunk %c%c%c%c at offset %6d, length %6d\n",
tag[0], tag[1], tag[2], tag[3], (int)chunk_data->offset_,
(int)chunk_data->size_);
tag[0], tag[1], tag[2], tag[3], (int)chunk_data->offset,
(int)chunk_data->size);
}
}
switch (id) {
@ -973,21 +974,21 @@ static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
break;
case CHUNK_EXIF:
case CHUNK_XMP:
++webp_info->chunk_counts_[id];
++webp_info->chunk_counts[id];
break;
case CHUNK_UNKNOWN:
default:
break;
}
if (webp_info->is_processing_anim_frame_ && id != CHUNK_ANMF) {
if (webp_info->anim_frame_data_size_ == chunk_data->size_) {
if (!webp_info->seen_image_subchunk_) {
if (webp_info->is_processing_anim_frame && id != CHUNK_ANMF) {
if (webp_info->anim_frame_data_size == chunk_data->size) {
if (!webp_info->seen_image_subchunk) {
LOG_ERROR("No VP8/VP8L chunk detected in an ANMF chunk.");
return WEBP_INFO_PARSE_ERROR;
}
webp_info->is_processing_anim_frame_ = 0;
} else if (webp_info->anim_frame_data_size_ > chunk_data->size_) {
webp_info->anim_frame_data_size_ -= chunk_data->size_;
webp_info->is_processing_anim_frame = 0;
} else if (webp_info->anim_frame_data_size > chunk_data->size) {
webp_info->anim_frame_data_size -= chunk_data->size;
} else {
LOG_ERROR("Truncated data detected when parsing ANMF chunk.");
return WEBP_INFO_TRUNCATED_DATA;
@ -997,55 +998,55 @@ static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
}
static WebPInfoStatus Validate(WebPInfo* const webp_info) {
if (webp_info->num_frames_ < 1) {
if (webp_info->num_frames < 1) {
LOG_ERROR("No image/frame detected.");
return WEBP_INFO_MISSING_DATA;
}
if (webp_info->chunk_counts_[CHUNK_VP8X]) {
const int iccp = !!(webp_info->feature_flags_ & ICCP_FLAG);
const int exif = !!(webp_info->feature_flags_ & EXIF_FLAG);
const int xmp = !!(webp_info->feature_flags_ & XMP_FLAG);
const int animation = !!(webp_info->feature_flags_ & ANIMATION_FLAG);
const int alpha = !!(webp_info->feature_flags_ & ALPHA_FLAG);
if (!alpha && webp_info->has_alpha_) {
if (webp_info->chunk_counts[CHUNK_VP8X]) {
const int iccp = !!(webp_info->feature_flags & ICCP_FLAG);
const int exif = !!(webp_info->feature_flags & EXIF_FLAG);
const int xmp = !!(webp_info->feature_flags & XMP_FLAG);
const int animation = !!(webp_info->feature_flags & ANIMATION_FLAG);
const int alpha = !!(webp_info->feature_flags & ALPHA_FLAG);
if (!alpha && webp_info->has_alpha) {
LOG_ERROR("Unexpected alpha data detected.");
return WEBP_INFO_PARSE_ERROR;
}
if (alpha && !webp_info->has_alpha_) {
if (alpha && !webp_info->has_alpha) {
LOG_WARN("Alpha flag is set with no alpha data present.");
}
if (iccp && !webp_info->chunk_counts_[CHUNK_ICCP]) {
if (iccp && !webp_info->chunk_counts[CHUNK_ICCP]) {
LOG_ERROR("Missing ICCP chunk.");
return WEBP_INFO_MISSING_DATA;
}
if (exif && !webp_info->chunk_counts_[CHUNK_EXIF]) {
if (exif && !webp_info->chunk_counts[CHUNK_EXIF]) {
LOG_ERROR("Missing EXIF chunk.");
return WEBP_INFO_MISSING_DATA;
}
if (xmp && !webp_info->chunk_counts_[CHUNK_XMP]) {
if (xmp && !webp_info->chunk_counts[CHUNK_XMP]) {
LOG_ERROR("Missing XMP chunk.");
return WEBP_INFO_MISSING_DATA;
}
if (!iccp && webp_info->chunk_counts_[CHUNK_ICCP]) {
if (!iccp && webp_info->chunk_counts[CHUNK_ICCP]) {
LOG_ERROR("Unexpected ICCP chunk detected.");
return WEBP_INFO_PARSE_ERROR;
}
if (!exif && webp_info->chunk_counts_[CHUNK_EXIF]) {
if (!exif && webp_info->chunk_counts[CHUNK_EXIF]) {
LOG_ERROR("Unexpected EXIF chunk detected.");
return WEBP_INFO_PARSE_ERROR;
}
if (!xmp && webp_info->chunk_counts_[CHUNK_XMP]) {
if (!xmp && webp_info->chunk_counts[CHUNK_XMP]) {
LOG_ERROR("Unexpected XMP chunk detected.");
return WEBP_INFO_PARSE_ERROR;
}
// Incomplete animation frame.
if (webp_info->is_processing_anim_frame_) return WEBP_INFO_MISSING_DATA;
if (!animation && webp_info->num_frames_ > 1) {
if (webp_info->is_processing_anim_frame) return WEBP_INFO_MISSING_DATA;
if (!animation && webp_info->num_frames > 1) {
LOG_ERROR("More than 1 frame detected in non-animation file.");
return WEBP_INFO_PARSE_ERROR;
}
if (animation && (!webp_info->chunk_counts_[CHUNK_ANIM] ||
!webp_info->chunk_counts_[CHUNK_ANMF])) {
if (animation && (!webp_info->chunk_counts[CHUNK_ANIM] ||
!webp_info->chunk_counts[CHUNK_ANMF])) {
LOG_ERROR("No ANIM/ANMF chunk detected in animation file.");
return WEBP_INFO_PARSE_ERROR;
}
@ -1056,17 +1057,17 @@ static WebPInfoStatus Validate(WebPInfo* const webp_info) {
static void ShowSummary(const WebPInfo* const webp_info) {
int i;
printf("Summary:\n");
printf("Number of frames: %d\n", webp_info->num_frames_);
printf("Number of frames: %d\n", webp_info->num_frames);
printf("Chunk type : VP8 VP8L VP8X ALPH ANIM ANMF(VP8 /VP8L/ALPH) ICCP "
"EXIF XMP\n");
printf("Chunk counts: ");
for (i = 0; i < CHUNK_TYPES; ++i) {
printf("%4d ", webp_info->chunk_counts_[i]);
printf("%4d ", webp_info->chunk_counts[i]);
if (i == CHUNK_ANMF) {
printf("%4d %4d %4d ",
webp_info->anmf_subchunk_counts_[0],
webp_info->anmf_subchunk_counts_[1],
webp_info->anmf_subchunk_counts_[2]);
webp_info->anmf_subchunk_counts[0],
webp_info->anmf_subchunk_counts[1],
webp_info->anmf_subchunk_counts[2]);
}
}
printf("\n");
@ -1089,20 +1090,20 @@ static WebPInfoStatus AnalyzeWebP(WebPInfo* const webp_info,
webp_info_status = ProcessChunk(&chunk_data, webp_info);
}
if (webp_info_status != WEBP_INFO_OK) goto Error;
if (webp_info->show_summary_) ShowSummary(webp_info);
if (webp_info->show_summary) ShowSummary(webp_info);
// Final check.
webp_info_status = Validate(webp_info);
Error:
if (!webp_info->quiet_) {
if (!webp_info->quiet) {
if (webp_info_status == WEBP_INFO_OK) {
printf("No error detected.\n");
} else {
printf("Errors detected.\n");
}
if (webp_info->num_warnings_ > 0) {
printf("There were %d warning(s).\n", webp_info->num_warnings_);
if (webp_info->num_warnings > 0) {
printf("There were %d warning(s).\n", webp_info->num_warnings);
}
}
return webp_info_status;
@ -1120,6 +1121,7 @@ static void Help(void) {
" -bitstream_info .... Parse bitstream header.\n");
}
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
int c, quiet = 0, show_diag = 0, show_summary = 0;
int parse_bitstream = 0;
@ -1130,7 +1132,7 @@ int main(int argc, const char* argv[]) {
if (argc == 1) {
Help();
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
// Parse command-line input.
@ -1138,7 +1140,7 @@ int main(int argc, const char* argv[]) {
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help") ||
!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
Help();
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else if (!strcmp(argv[c], "-quiet")) {
quiet = 1;
} else if (!strcmp(argv[c], "-diag")) {
@ -1151,7 +1153,7 @@ int main(int argc, const char* argv[]) {
const int version = WebPGetDecoderVersion();
printf("WebP Decoder version: %d.%d.%d\n",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else { // Assume the remaining are all input files.
break;
}
@ -1159,7 +1161,7 @@ int main(int argc, const char* argv[]) {
if (c == argc) {
Help();
FREE_WARGV_AND_RETURN(WEBP_INFO_INVALID_COMMAND);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
// Process input files one by one.
@ -1167,10 +1169,10 @@ int main(int argc, const char* argv[]) {
WebPData webp_data;
const W_CHAR* in_file = NULL;
WebPInfoInit(&webp_info);
webp_info.quiet_ = quiet;
webp_info.show_diagnosis_ = show_diag;
webp_info.show_summary_ = show_summary;
webp_info.parse_bitstream_ = parse_bitstream;
webp_info.quiet = quiet;
webp_info.show_diagnosis = show_diag;
webp_info.show_summary = show_summary;
webp_info.parse_bitstream = parse_bitstream;
in_file = GET_WARGV(argv, c);
if (in_file == NULL ||
!ReadFileToWebPData((const char*)in_file, &webp_data)) {
@ -1178,9 +1180,10 @@ int main(int argc, const char* argv[]) {
WFPRINTF(stderr, "Failed to open input file %s.\n", in_file);
continue;
}
if (!webp_info.quiet_) WPRINTF("File: %s\n", in_file);
if (!webp_info.quiet) WPRINTF("File: %s\n", in_file);
webp_info_status = AnalyzeWebP(&webp_info, &webp_data);
WebPDataClear(&webp_data);
}
FREE_WARGV_AND_RETURN(webp_info_status);
FREE_WARGV_AND_RETURN((webp_info_status == WEBP_INFO_OK) ? EXIT_SUCCESS
: EXIT_FAILURE);
}

View File

@ -59,6 +59,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "webp/decode.h"
#include "webp/mux.h"
#include "../examples/example_util.h"
@ -86,9 +87,9 @@ typedef enum {
} FeatureSubType;
typedef struct {
FeatureSubType subtype_;
const char* filename_;
const char* params_;
FeatureSubType subtype;
const char* filename;
const char* params;
} FeatureArg;
typedef enum {
@ -113,14 +114,14 @@ static const char* const kDescriptions[LAST_FEATURE] = {
};
typedef struct {
CommandLineArguments cmd_args_;
CommandLineArguments cmd_args;
ActionType action_type_;
const char* input_;
const char* output_;
FeatureType type_;
FeatureArg* args_;
int arg_count_;
ActionType action_type;
const char* input;
const char* output;
FeatureType type;
FeatureArg* args;
int arg_count;
} Config;
//------------------------------------------------------------------------------
@ -131,8 +132,8 @@ static int CountOccurrences(const CommandLineArguments* const args,
int i;
int num_occurences = 0;
for (i = 0; i < args->argc_; ++i) {
if (!strcmp(args->argv_[i], arg)) {
for (i = 0; i < args->argc; ++i) {
if (!strcmp(args->argv[i], arg)) {
++num_occurences;
}
}
@ -150,16 +151,20 @@ static const char* ErrorString(WebPMuxError err) {
}
#define RETURN_IF_ERROR(ERR_MSG) \
if (err != WEBP_MUX_OK) { \
fprintf(stderr, ERR_MSG); \
return err; \
}
do { \
if (err != WEBP_MUX_OK) { \
fprintf(stderr, ERR_MSG); \
return err; \
} \
} while (0)
#define RETURN_IF_ERROR3(ERR_MSG, FORMAT_STR1, FORMAT_STR2) \
if (err != WEBP_MUX_OK) { \
fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
return err; \
}
do { \
if (err != WEBP_MUX_OK) { \
fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
return err; \
} \
} while (0)
#define ERROR_GOTO1(ERR_MSG, LABEL) \
do { \
@ -522,8 +527,8 @@ static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
static void DeleteConfig(Config* const config) {
if (config != NULL) {
free(config->args_);
ExUtilDeleteCommandLineArguments(&config->cmd_args_);
free(config->args);
ExUtilDeleteCommandLineArguments(&config->cmd_args);
memset(config, 0, sizeof(*config));
}
}
@ -600,25 +605,31 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
return ok;
}
#define ACTION_IS_NIL (config->action_type_ == NIL_ACTION)
#define ACTION_IS_NIL (config->action_type == NIL_ACTION)
#define FEATURETYPE_IS_NIL (config->type_ == NIL_FEATURE)
#define FEATURETYPE_IS_NIL (config->type == NIL_FEATURE)
#define CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL) \
if (argc < i + (NUM)) { \
fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
goto LABEL; \
}
do { \
if (argc < i + (NUM)) { \
fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
goto LABEL; \
} \
} while (0)
#define CHECK_NUM_ARGS_AT_MOST(NUM, LABEL) \
if (argc > i + (NUM)) { \
fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
goto LABEL; \
}
do { \
if (argc > i + (NUM)) { \
fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
goto LABEL; \
} \
} while (0)
#define CHECK_NUM_ARGS_EXACTLY(NUM, LABEL) \
CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL); \
CHECK_NUM_ARGS_AT_MOST(NUM, LABEL);
do { \
CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL); \
CHECK_NUM_ARGS_AT_MOST(NUM, LABEL); \
} while (0)
// Parses command-line arguments to fill up config object. Also performs some
// semantic checks. unicode_argv contains wchar_t arguments or is null.
@ -626,98 +637,98 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
int i = 0;
int feature_arg_index = 0;
int ok = 1;
int argc = config->cmd_args_.argc_;
const char* const* argv = config->cmd_args_.argv_;
int argc = config->cmd_args.argc;
const char* const* argv = config->cmd_args.argv;
// Unicode file paths will be used if available.
const char* const* wargv =
(unicode_argv != NULL) ? (const char**)(unicode_argv + 1) : argv;
while (i < argc) {
FeatureArg* const arg = &config->args_[feature_arg_index];
FeatureArg* const arg = &config->args[feature_arg_index];
if (argv[i][0] == '-') { // One of the action types or output.
if (!strcmp(argv[i], "-set")) {
if (ACTION_IS_NIL) {
config->action_type_ = ACTION_SET;
config->action_type = ACTION_SET;
} else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
}
++i;
} else if (!strcmp(argv[i], "-duration")) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_DURATION) {
config->action_type_ = ACTION_DURATION;
if (ACTION_IS_NIL || config->action_type == ACTION_DURATION) {
config->action_type = ACTION_DURATION;
} else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
}
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_DURATION) {
config->type_ = FEATURE_DURATION;
if (FEATURETYPE_IS_NIL || config->type == FEATURE_DURATION) {
config->type = FEATURE_DURATION;
} else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
}
arg->params_ = argv[i + 1];
arg->params = argv[i + 1];
++feature_arg_index;
i += 2;
} else if (!strcmp(argv[i], "-get")) {
if (ACTION_IS_NIL) {
config->action_type_ = ACTION_GET;
config->action_type = ACTION_GET;
} else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
}
++i;
} else if (!strcmp(argv[i], "-strip")) {
if (ACTION_IS_NIL) {
config->action_type_ = ACTION_STRIP;
config->arg_count_ = 0;
config->action_type = ACTION_STRIP;
config->arg_count = 0;
} else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
}
++i;
} else if (!strcmp(argv[i], "-frame")) {
CHECK_NUM_ARGS_AT_LEAST(3, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
config->action_type_ = ACTION_SET;
if (ACTION_IS_NIL || config->action_type == ACTION_SET) {
config->action_type = ACTION_SET;
} else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
}
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) {
config->type_ = FEATURE_ANMF;
if (FEATURETYPE_IS_NIL || config->type == FEATURE_ANMF) {
config->type = FEATURE_ANMF;
} else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
}
arg->subtype_ = SUBTYPE_ANMF;
arg->filename_ = wargv[i + 1];
arg->params_ = argv[i + 2];
arg->subtype = SUBTYPE_ANMF;
arg->filename = wargv[i + 1];
arg->params = argv[i + 2];
++feature_arg_index;
i += 3;
} else if (!strcmp(argv[i], "-loop") || !strcmp(argv[i], "-bgcolor")) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
config->action_type_ = ACTION_SET;
if (ACTION_IS_NIL || config->action_type == ACTION_SET) {
config->action_type = ACTION_SET;
} else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
}
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) {
config->type_ = FEATURE_ANMF;
if (FEATURETYPE_IS_NIL || config->type == FEATURE_ANMF) {
config->type = FEATURE_ANMF;
} else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
}
arg->subtype_ =
arg->subtype =
!strcmp(argv[i], "-loop") ? SUBTYPE_LOOP : SUBTYPE_BGCOLOR;
arg->params_ = argv[i + 1];
arg->params = argv[i + 1];
++feature_arg_index;
i += 2;
} else if (!strcmp(argv[i], "-o")) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
config->output_ = wargv[i + 1];
config->output = wargv[i + 1];
i += 2;
} else if (!strcmp(argv[i], "-info")) {
CHECK_NUM_ARGS_EXACTLY(2, ErrParse);
if (config->action_type_ != NIL_ACTION) {
if (config->action_type != NIL_ACTION) {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} else {
config->action_type_ = ACTION_INFO;
config->arg_count_ = 0;
config->input_ = wargv[i + 1];
config->action_type = ACTION_INFO;
config->arg_count = 0;
config->input = wargv[i + 1];
}
i += 2;
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) {
@ -735,8 +746,8 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
} else if (!strcmp(argv[i], "--")) {
if (i < argc - 1) {
++i;
if (config->input_ == NULL) {
config->input_ = wargv[i];
if (config->input == NULL) {
config->input = wargv[i];
} else {
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
argv[i], ErrParse);
@ -754,43 +765,43 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") ||
!strcmp(argv[i], "xmp")) {
if (FEATURETYPE_IS_NIL) {
config->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
config->type = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
(!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP;
} else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
}
if (config->action_type_ == ACTION_SET) {
if (config->action_type == ACTION_SET) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
arg->filename_ = wargv[i + 1];
arg->filename = wargv[i + 1];
++feature_arg_index;
i += 2;
} else {
++i;
}
} else if (!strcmp(argv[i], "frame") &&
(config->action_type_ == ACTION_GET)) {
(config->action_type == ACTION_GET)) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
config->type_ = FEATURE_ANMF;
arg->params_ = argv[i + 1];
config->type = FEATURE_ANMF;
arg->params = argv[i + 1];
++feature_arg_index;
i += 2;
} else if (!strcmp(argv[i], "loop") &&
(config->action_type_ == ACTION_SET)) {
(config->action_type == ACTION_SET)) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
config->type_ = FEATURE_LOOP;
arg->params_ = argv[i + 1];
config->type = FEATURE_LOOP;
arg->params = argv[i + 1];
++feature_arg_index;
i += 2;
} else if (!strcmp(argv[i], "bgcolor") &&
(config->action_type_ == ACTION_SET)) {
(config->action_type == ACTION_SET)) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
config->type_ = FEATURE_BGCOLOR;
arg->params_ = argv[i + 1];
config->type = FEATURE_BGCOLOR;
arg->params = argv[i + 1];
++feature_arg_index;
i += 2;
} else { // Assume input file.
if (config->input_ == NULL) {
config->input_ = wargv[i];
if (config->input == NULL) {
config->input = wargv[i];
} else {
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
argv[i], ErrParse);
@ -813,21 +824,21 @@ static int ValidateConfig(Config* const config) {
}
// Feature type.
if (FEATURETYPE_IS_NIL && config->action_type_ != ACTION_INFO) {
if (FEATURETYPE_IS_NIL && config->action_type != ACTION_INFO) {
ERROR_GOTO1("ERROR: No feature specified.\n", ErrValidate2);
}
// Input file.
if (config->input_ == NULL) {
if (config->action_type_ != ACTION_SET) {
if (config->input == NULL) {
if (config->action_type != ACTION_SET) {
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
} else if (config->type_ != FEATURE_ANMF) {
} else if (config->type != FEATURE_ANMF) {
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
}
}
// Output file.
if (config->output_ == NULL && config->action_type_ != ACTION_INFO) {
if (config->output == NULL && config->action_type != ACTION_INFO) {
ERROR_GOTO1("ERROR: No output file specified.\n", ErrValidate2);
}
@ -843,17 +854,17 @@ static int InitializeConfig(int argc, const char* argv[], Config* const config,
memset(config, 0, sizeof(*config));
ok = ExUtilInitCommandLineArguments(argc, argv, &config->cmd_args_);
ok = ExUtilInitCommandLineArguments(argc, argv, &config->cmd_args);
if (!ok) return 0;
// Validate command-line arguments.
if (!ValidateCommandLine(&config->cmd_args_, &num_feature_args)) {
if (!ValidateCommandLine(&config->cmd_args, &num_feature_args)) {
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
}
config->arg_count_ = num_feature_args;
config->args_ = (FeatureArg*)calloc(num_feature_args, sizeof(*config->args_));
if (config->args_ == NULL) {
config->arg_count = num_feature_args;
config->args = (FeatureArg*)calloc(num_feature_args, sizeof(*config->args));
if (config->args == NULL) {
ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
}
@ -885,7 +896,7 @@ static int GetFrame(const WebPMux* mux, const Config* config) {
WebPMuxFrameInfo info;
WebPDataInit(&info.bitstream);
num = ExUtilGetInt(config->args_[0].params_, 10, &parse_error);
num = ExUtilGetInt(config->args[0].params, 10, &parse_error);
if (num < 0) {
ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet);
}
@ -910,7 +921,7 @@ static int GetFrame(const WebPMux* mux, const Config* config) {
ErrorString(err), ErrGet);
}
ok = WriteWebP(mux_single, config->output_);
ok = WriteWebP(mux_single, config->output);
ErrGet:
WebPDataClear(&info.bitstream);
@ -925,11 +936,11 @@ static int Process(const Config* config) {
WebPMuxError err = WEBP_MUX_OK;
int ok = 1;
switch (config->action_type_) {
switch (config->action_type) {
case ACTION_GET: {
ok = CreateMux(config->input_, &mux);
ok = CreateMux(config->input, &mux);
if (!ok) goto Err2;
switch (config->type_) {
switch (config->type) {
case FEATURE_ANMF:
ok = GetFrame(mux, config);
break;
@ -937,12 +948,12 @@ static int Process(const Config* config) {
case FEATURE_ICCP:
case FEATURE_EXIF:
case FEATURE_XMP:
err = WebPMuxGetChunk(mux, kFourccList[config->type_], &chunk);
err = WebPMuxGetChunk(mux, kFourccList[config->type], &chunk);
if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not get the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2);
ErrorString(err), kDescriptions[config->type], Err2);
}
ok = WriteData(config->output_, &chunk);
ok = WriteData(config->output, &chunk);
break;
default:
@ -952,7 +963,7 @@ static int Process(const Config* config) {
break;
}
case ACTION_SET: {
switch (config->type_) {
switch (config->type) {
case FEATURE_ANMF: {
int i;
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
@ -961,11 +972,11 @@ static int Process(const Config* config) {
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
}
for (i = 0; i < config->arg_count_; ++i) {
switch (config->args_[i].subtype_) {
for (i = 0; i < config->arg_count; ++i) {
switch (config->args[i].subtype) {
case SUBTYPE_BGCOLOR: {
uint32_t bgcolor;
ok = ParseBgcolorArgs(config->args_[i].params_, &bgcolor);
ok = ParseBgcolorArgs(config->args[i].params, &bgcolor);
if (!ok) {
ERROR_GOTO1("ERROR: Could not parse the background color \n",
Err2);
@ -976,7 +987,7 @@ static int Process(const Config* config) {
case SUBTYPE_LOOP: {
int parse_error = 0;
const int loop_count =
ExUtilGetInt(config->args_[i].params_, 10, &parse_error);
ExUtilGetInt(config->args[i].params, 10, &parse_error);
if (loop_count < 0 || loop_count > 65535) {
// Note: This is only a 'necessary' condition for loop_count
// to be valid. The 'sufficient' conditioned in checked in
@ -992,10 +1003,10 @@ static int Process(const Config* config) {
case SUBTYPE_ANMF: {
WebPMuxFrameInfo frame;
frame.id = WEBP_CHUNK_ANMF;
ok = ExUtilReadFileToWebPData(config->args_[i].filename_,
ok = ExUtilReadFileToWebPData(config->args[i].filename,
&frame.bitstream);
if (!ok) goto Err2;
ok = ParseFrameArgs(config->args_[i].params_, &frame);
ok = ParseFrameArgs(config->args[i].params, &frame);
if (!ok) {
WebPDataClear(&frame.bitstream);
ERROR_GOTO1("ERROR: Could not parse frame properties.\n",
@ -1026,15 +1037,15 @@ static int Process(const Config* config) {
case FEATURE_ICCP:
case FEATURE_EXIF:
case FEATURE_XMP: {
ok = CreateMux(config->input_, &mux);
ok = CreateMux(config->input, &mux);
if (!ok) goto Err2;
ok = ExUtilReadFileToWebPData(config->args_[0].filename_, &chunk);
ok = ExUtilReadFileToWebPData(config->args[0].filename, &chunk);
if (!ok) goto Err2;
err = WebPMuxSetChunk(mux, kFourccList[config->type_], &chunk, 1);
err = WebPMuxSetChunk(mux, kFourccList[config->type], &chunk, 1);
WebPDataClear(&chunk);
if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not set the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2);
ErrorString(err), kDescriptions[config->type], Err2);
}
break;
}
@ -1042,12 +1053,12 @@ static int Process(const Config* config) {
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
int parse_error = 0;
const int loop_count =
ExUtilGetInt(config->args_[0].params_, 10, &parse_error);
ExUtilGetInt(config->args[0].params, 10, &parse_error);
if (loop_count < 0 || loop_count > 65535 || parse_error) {
ERROR_GOTO1("ERROR: Loop count must be in the range 0 to 65535.\n",
Err2);
}
ok = CreateMux(config->input_, &mux);
ok = CreateMux(config->input, &mux);
if (!ok) goto Err2;
ok = (WebPMuxGetAnimationParams(mux, &params) == WEBP_MUX_OK);
if (!ok) {
@ -1066,12 +1077,12 @@ static int Process(const Config* config) {
case FEATURE_BGCOLOR: {
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
uint32_t bgcolor;
ok = ParseBgcolorArgs(config->args_[0].params_, &bgcolor);
ok = ParseBgcolorArgs(config->args[0].params, &bgcolor);
if (!ok) {
ERROR_GOTO1("ERROR: Could not parse the background color.\n",
Err2);
}
ok = CreateMux(config->input_, &mux);
ok = CreateMux(config->input, &mux);
if (!ok) goto Err2;
ok = (WebPMuxGetAnimationParams(mux, &params) == WEBP_MUX_OK);
if (!ok) {
@ -1092,12 +1103,12 @@ static int Process(const Config* config) {
break;
}
}
ok = WriteWebP(mux, config->output_);
ok = WriteWebP(mux, config->output);
break;
}
case ACTION_DURATION: {
int num_frames;
ok = CreateMux(config->input_, &mux);
ok = CreateMux(config->input, &mux);
if (!ok) goto Err2;
err = WebPMuxNumChunks(mux, WEBP_CHUNK_ANMF, &num_frames);
ok = (err == WEBP_MUX_OK);
@ -1107,7 +1118,7 @@ static int Process(const Config* config) {
if (num_frames == 0) {
fprintf(stderr, "Doesn't look like the source is animated. "
"Skipping duration setting.\n");
ok = WriteWebP(mux, config->output_);
ok = WriteWebP(mux, config->output);
if (!ok) goto Err2;
} else {
int i;
@ -1119,11 +1130,11 @@ static int Process(const Config* config) {
for (i = 0; i < num_frames; ++i) durations[i] = -1;
// Parse intervals to process.
for (i = 0; i < config->arg_count_; ++i) {
for (i = 0; i < config->arg_count; ++i) {
int k;
int args[3];
int duration, start, end;
const int nb_args = ExUtilGetInts(config->args_[i].params_,
const int nb_args = ExUtilGetInts(config->args[i].params,
10, 3, args);
ok = (nb_args >= 1);
if (!ok) goto Err3;
@ -1167,7 +1178,7 @@ static int Process(const Config* config) {
WebPDataClear(&frame.bitstream);
}
WebPMuxDelete(mux);
ok = WriteWebP(new_mux, config->output_);
ok = WriteWebP(new_mux, config->output);
mux = new_mux; // transfer for the WebPMuxDelete() call
new_mux = NULL;
@ -1179,24 +1190,24 @@ static int Process(const Config* config) {
break;
}
case ACTION_STRIP: {
ok = CreateMux(config->input_, &mux);
ok = CreateMux(config->input, &mux);
if (!ok) goto Err2;
if (config->type_ == FEATURE_ICCP || config->type_ == FEATURE_EXIF ||
config->type_ == FEATURE_XMP) {
err = WebPMuxDeleteChunk(mux, kFourccList[config->type_]);
if (config->type == FEATURE_ICCP || config->type == FEATURE_EXIF ||
config->type == FEATURE_XMP) {
err = WebPMuxDeleteChunk(mux, kFourccList[config->type]);
if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2);
ErrorString(err), kDescriptions[config->type], Err2);
}
} else {
ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
break;
}
ok = WriteWebP(mux, config->output_);
ok = WriteWebP(mux, config->output);
break;
}
case ACTION_INFO: {
ok = CreateMux(config->input_, &mux);
ok = CreateMux(config->input, &mux);
if (!ok) goto Err2;
ok = (DisplayInfo(mux) == WEBP_MUX_OK);
break;
@ -1215,6 +1226,7 @@ static int Process(const Config* config) {
//------------------------------------------------------------------------------
// Main.
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
Config config;
int ok;
@ -1228,7 +1240,7 @@ int main(int argc, const char* argv[]) {
PrintHelp();
}
DeleteConfig(&config);
FREE_WARGV_AND_RETURN(!ok);
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
//------------------------------------------------------------------------------

View File

@ -7,6 +7,7 @@ noinst_HEADERS += ../src/webp/types.h
libwebpextras_la_SOURCES =
libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c
libwebpextras_la_SOURCES += sharpyuv_risk_table.c sharpyuv_risk_table.h
libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
libwebpextras_la_LDFLAGS = -lm

View File

@ -11,15 +11,21 @@
//
#include "extras/extras.h"
#include "webp/format_constants.h"
#include "src/dsp/dsp.h"
#include <assert.h>
#include <limits.h>
#include <string.h>
#include "extras/sharpyuv_risk_table.h"
#include "sharpyuv/sharpyuv.h"
#include "src/dsp/dsp.h"
#include "src/utils/utils.h"
#include "webp/format_constants.h"
#include "webp/types.h"
#define XTRA_MAJ_VERSION 1
#define XTRA_MIN_VERSION 2
#define XTRA_REV_VERSION 4
#define XTRA_MIN_VERSION 5
#define XTRA_REV_VERSION 0
//------------------------------------------------------------------------------
@ -160,3 +166,159 @@ int WebPUnmultiplyARGB(WebPPicture* pic) {
}
//------------------------------------------------------------------------------
// 420 risk metric
#define YUV_FIX 16 // fixed-point precision for RGB->YUV
static const int kYuvHalf = 1 << (YUV_FIX - 1);
// Maps a value in [0, (256 << YUV_FIX) - 1] to [0,
// precomputed_scores_table_sampling - 1]. It is important that the extremal
// values are preserved and 1:1 mapped:
// ConvertValue(0) = 0
// ConvertValue((256 << 16) - 1) = rgb_sampling_size - 1
static int SharpYuvConvertValueToSampledIdx(int v, int rgb_sampling_size) {
v = (v + kYuvHalf) >> YUV_FIX;
v = (v < 0) ? 0 : (v > 255) ? 255 : v;
return (v * (rgb_sampling_size - 1)) / 255;
}
#undef YUV_FIX
// For each pixel, computes the index to look up that color in a precomputed
// risk score table where the YUV space is subsampled to a size of
// precomputed_scores_table_sampling^3 (see sharpyuv_risk_table.h)
static int SharpYuvConvertToYuvSharpnessIndex(
int r, int g, int b, const SharpYuvConversionMatrix* matrix,
int precomputed_scores_table_sampling) {
const int y = SharpYuvConvertValueToSampledIdx(
matrix->rgb_to_y[0] * r + matrix->rgb_to_y[1] * g +
matrix->rgb_to_y[2] * b + matrix->rgb_to_y[3],
precomputed_scores_table_sampling);
const int u = SharpYuvConvertValueToSampledIdx(
matrix->rgb_to_u[0] * r + matrix->rgb_to_u[1] * g +
matrix->rgb_to_u[2] * b + matrix->rgb_to_u[3],
precomputed_scores_table_sampling);
const int v = SharpYuvConvertValueToSampledIdx(
matrix->rgb_to_v[0] * r + matrix->rgb_to_v[1] * g +
matrix->rgb_to_v[2] * b + matrix->rgb_to_v[3],
precomputed_scores_table_sampling);
return y + u * precomputed_scores_table_sampling +
v * precomputed_scores_table_sampling *
precomputed_scores_table_sampling;
}
static void SharpYuvRowToYuvSharpnessIndex(
const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr,
int rgb_step, int rgb_bit_depth, int width, uint16_t* dst,
const SharpYuvConversionMatrix* matrix,
int precomputed_scores_table_sampling) {
int i;
assert(rgb_bit_depth == 8);
(void)rgb_bit_depth; // Unused for now.
for (i = 0; i < width;
++i, r_ptr += rgb_step, g_ptr += rgb_step, b_ptr += rgb_step) {
dst[i] =
SharpYuvConvertToYuvSharpnessIndex(r_ptr[0], g_ptr[0], b_ptr[0], matrix,
precomputed_scores_table_sampling);
}
}
#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((uint64_t)(W) * (H), sizeof(T)))
static int DoEstimateRisk(const uint8_t* r_ptr, const uint8_t* g_ptr,
const uint8_t* b_ptr, int rgb_step, int rgb_stride,
int rgb_bit_depth, int width, int height,
const SharpYuvOptions* options,
const uint8_t precomputed_scores_table[],
int precomputed_scores_table_sampling,
float* score_out) {
const int sampling3 = precomputed_scores_table_sampling *
precomputed_scores_table_sampling *
precomputed_scores_table_sampling;
const int kNoiseLevel = 4;
double total_score = 0;
double count = 0;
// Rows of indices in
uint16_t* row1 = SAFE_ALLOC(width, 1, uint16_t);
uint16_t* row2 = SAFE_ALLOC(width, 1, uint16_t);
uint16_t* tmp;
int i, j;
if (row1 == NULL || row2 == NULL) {
WebPFree(row1);
WebPFree(row2);
return 0;
}
// Convert the first row ahead.
SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
width, row2, options->yuv_matrix,
precomputed_scores_table_sampling);
for (j = 1; j < height; ++j) {
r_ptr += rgb_stride;
g_ptr += rgb_stride;
b_ptr += rgb_stride;
// Swap row 1 and row 2.
tmp = row1;
row1 = row2;
row2 = tmp;
// Convert the row below.
SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
width, row2, options->yuv_matrix,
precomputed_scores_table_sampling);
for (i = 0; i < width - 1; ++i) {
const int idx0 = row1[i + 0];
const int idx1 = row1[i + 1];
const int idx2 = row2[i + 0];
const int score = precomputed_scores_table[idx0 + sampling3 * idx1] +
precomputed_scores_table[idx0 + sampling3 * idx2] +
precomputed_scores_table[idx1 + sampling3 * idx2];
if (score > kNoiseLevel) {
total_score += score;
count += 1.0;
}
}
}
if (count > 0.) total_score /= count;
// If less than 1% of pixels were evaluated -> below noise level.
if (100. * count / (width * height) < 1.) total_score = 0.;
// Rescale to [0:100]
total_score = (total_score > 25.) ? 100. : total_score * 100. / 25.;
WebPFree(row1);
WebPFree(row2);
*score_out = (float)total_score;
return 1;
}
#undef SAFE_ALLOC
int SharpYuvEstimate420Risk(const void* r_ptr, const void* g_ptr,
const void* b_ptr, int rgb_step, int rgb_stride,
int rgb_bit_depth, int width, int height,
const SharpYuvOptions* options, float* score) {
if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || options == NULL ||
score == NULL) {
return 0;
}
if (rgb_bit_depth != 8) {
return 0;
}
if (width <= 4 || height <= 4) {
*score = 0.0f; // too small, no real risk.
return 1;
}
return DoEstimateRisk(
(const uint8_t*)r_ptr, (const uint8_t*)g_ptr, (const uint8_t*)b_ptr,
rgb_step, rgb_stride, rgb_bit_depth, width, height, options,
kSharpYuvPrecomputedRisk, kSharpYuvPrecomputedRiskYuvSampling, score);
}
//------------------------------------------------------------------------------

View File

@ -17,9 +17,10 @@
extern "C" {
#endif
#include "sharpyuv/sharpyuv.h"
#include "webp/encode.h"
#define WEBP_EXTRAS_ABI_VERSION 0x0002 // MAJOR(8b) + MINOR(8b)
#define WEBP_EXTRAS_ABI_VERSION 0x0003 // MAJOR(8b) + MINOR(8b)
//------------------------------------------------------------------------------
@ -70,6 +71,38 @@ WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size);
//------------------------------------------------------------------------------
// Computes a score between 0 and 100 which represents the risk of having visual
// quality loss from converting an RGB image to YUV420.
// A low score, typically < 40, means there is a low risk of artifacts from
// chroma subsampling and a simple averaging algorithm can be used instead of
// the more expensive SharpYuvConvert function.
// A medium score, typically >= 40 and < 70, means that simple chroma
// subsampling will produce artifacts and it may be advisable to use the more
// costly SharpYuvConvert for YUV420 conversion.
// A high score, typically >= 70, means there is a very high risk of artifacts
// from chroma subsampling even with SharpYuvConvert, and best results might be
// achieved by using YUV444.
// If not using SharpYuvConvert, a threshold of about 50 can be used to decide
// between (simple averaging) 420 and 444.
// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point
// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise.
// rgb_step: distance in bytes between two horizontally adjacent pixels on the
// r, g and b channels. If rgb_bit_depth is > 8, it should be a
// multiple of 2.
// rgb_stride: distance in bytes between two vertically adjacent pixels on the
// r, g, and b channels. If rgb_bit_depth is > 8, it should be a
// multiple of 2.
// rgb_bit_depth: number of bits for each r/g/b value. Only a value of 8 is
// currently supported.
// width, height: width and height of the image in pixels
// Returns 0 on failure.
WEBP_EXTERN int SharpYuvEstimate420Risk(
const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step,
int rgb_stride, int rgb_bit_depth, int width, int height,
const SharpYuvOptions* options, float* score);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -227,10 +227,11 @@ static void Help(void) {
WebPGetEnabledInputFileFormats());
}
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
WebPPicture pic1, pic2;
size_t size1 = 0, size2 = 0;
int ret = 1;
int ret = EXIT_FAILURE;
float disto[5];
int type = 0;
int c;
@ -246,7 +247,7 @@ int main(int argc, const char* argv[]) {
if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) {
fprintf(stderr, "Can't init pictures\n");
FREE_WARGV_AND_RETURN(1);
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
}
for (c = 1; c < argc; ++c) {
@ -262,7 +263,7 @@ int main(int argc, const char* argv[]) {
use_gray = 1;
} else if (!strcmp(argv[c], "-h")) {
help = 1;
ret = 0;
ret = EXIT_SUCCESS;
} else if (!strcmp(argv[c], "-o")) {
if (++c == argc) {
fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]);
@ -337,7 +338,8 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Error during lossless encoding.\n");
goto End;
}
ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1;
ret = ImgIoUtilWriteFile(output, data, data_size) ? EXIT_SUCCESS
: EXIT_FAILURE;
WebPFree(data);
if (ret) goto End;
#else
@ -345,9 +347,10 @@ int main(int argc, const char* argv[]) {
(void)data_size;
fprintf(stderr, "Cannot save the difference map. Please recompile "
"without the WEBP_REDUCE_CSP flag.\n");
goto End;
#endif // WEBP_REDUCE_CSP
}
ret = 0;
ret = EXIT_SUCCESS;
End:
WebPPictureFree(&pic1);

View File

@ -76,7 +76,7 @@ int VP8EstimateQuality(const uint8_t* const data, size_t size) {
GET_BIT(2); // colorspace + clamp type
// Segment header
if (GET_BIT(1)) { // use_segment_
if (GET_BIT(1)) { // use_segment
int s;
const int update_map = GET_BIT(1);
if (GET_BIT(1)) { // update data

6210
extras/sharpyuv_risk_table.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
// Copyright 2023 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Precomputed data for 420 risk estimation.
#ifndef WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
#define WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
#include "src/webp/types.h"
extern const int kSharpYuvPrecomputedRiskYuvSampling;
// Table of precomputed risk scores when chroma subsampling images with two
// given colors.
// Since precomputing values for all possible YUV colors would create a huge
// table, the YUV space (i.e. [0, 255]^3) is reduced to
// [0, kSharpYuvPrecomputedRiskYuvSampling-1]^3
// where 255 maps to kSharpYuvPrecomputedRiskYuvSampling-1.
// Table size: kSharpYuvPrecomputedRiskYuvSampling^6 bytes or 114 KiB
extern const uint8_t kSharpYuvPrecomputedRisk[];
#endif // WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_

View File

@ -15,6 +15,7 @@
// Author: James Zern (jzern@google.com)
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
@ -30,7 +31,7 @@
#if defined(WEBP_HAVE_JUST_SDL_H)
#include <SDL.h>
#else
#include <SDL/SDL.h>
#include <SDL2/SDL.h>
#endif
static void ProcessEvents(void) {
@ -49,19 +50,26 @@ static void ProcessEvents(void) {
}
}
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, char* argv[]) {
int c;
int ok = 0;
INIT_WARGV(argc, argv);
if (argc == 1) {
fprintf(stderr, "Usage: %s [-h] image.webp [more_files.webp...]\n",
argv[0]);
goto Error;
}
for (c = 1; c < argc; ++c) {
const char* file = NULL;
const uint8_t* webp = NULL;
size_t webp_size = 0;
if (!strcmp(argv[c], "-h")) {
printf("Usage: %s [-h] image.webp [more_files.webp...]\n", argv[0]);
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else {
file = (const char*)GET_WARGV(argv, c);
}
@ -75,7 +83,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, "File too large.\n");
goto Error;
}
ok = WebpToSDL((const char*)webp, (int)webp_size);
ok = WebPToSDL((const char*)webp, (int)webp_size);
free((void*)webp);
if (!ok) {
WFPRINTF(stderr, "Error decoding file %s\n", (const W_CHAR*)file);
@ -87,7 +95,7 @@ int main(int argc, char* argv[]) {
Error:
SDL_Quit();
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
#else // !WEBP_HAVE_SDL

View File

@ -15,6 +15,7 @@
#include "imageio/imageio_util.h"
#include "../examples/unicode.h"
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
int main(int argc, const char* argv[]) {
int c;
int quiet = 0;
@ -27,7 +28,7 @@ int main(int argc, const char* argv[]) {
quiet = 1;
} else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
printf("webp_quality [-h][-quiet] webp_files...\n");
FREE_WARGV_AND_RETURN(0);
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
} else {
const char* const filename = (const char*)GET_WARGV(argv, c);
const uint8_t* data = NULL;
@ -50,5 +51,5 @@ int main(int argc, const char* argv[]) {
free((void*)data);
}
}
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}

View File

@ -20,88 +20,75 @@
#include "webp_to_sdl.h"
#include <stdio.h>
#include "src/webp/decode.h"
#if defined(WEBP_HAVE_JUST_SDL_H)
#include <SDL.h>
#else
#include <SDL/SDL.h>
#include <SDL2/SDL.h>
#endif
static int init_ok = 0;
int WebpToSDL(const char* data, unsigned int data_size) {
int WebPToSDL(const char* data, unsigned int data_size) {
int ok = 0;
VP8StatusCode status;
WebPDecoderConfig config;
WebPBitstreamFeatures* const input = &config.input;
WebPDecBuffer* const output = &config.output;
SDL_Surface* screen = NULL;
SDL_Surface* surface = NULL;
if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n");
return 0;
}
WebPBitstreamFeatures input;
uint8_t* output = NULL;
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Texture* texture = NULL;
int width, height;
if (!init_ok) {
SDL_Init(SDL_INIT_VIDEO);
init_ok = 1;
}
status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &config.input);
status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &input);
if (status != VP8_STATUS_OK) goto Error;
width = input.width;
height = input.height;
screen = SDL_SetVideoMode(input->width, input->height, 32, SDL_SWSURFACE);
if (screen == NULL) {
fprintf(stderr, "Unable to set video mode (32bpp %dx%d)!\n",
input->width, input->height);
SDL_CreateWindowAndRenderer(width, height, 0, &window, &renderer);
if (window == NULL || renderer == NULL) {
fprintf(stderr, "Unable to create window or renderer!\n");
goto Error;
}
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
"linear"); // make the scaled rendering look smoother.
SDL_RenderSetLogicalSize(renderer, width, height);
surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
input->width, input->height, 32,
0x000000ffu, // R mask
0x0000ff00u, // G mask
0x00ff0000u, // B mask
0xff000000u); // A mask
if (surface == NULL) {
fprintf(stderr, "Unable to create %dx%d RGBA surface!\n",
input->width, input->height);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
SDL_TEXTUREACCESS_STREAMING, width, height);
if (texture == NULL) {
fprintf(stderr, "Unable to create %dx%d RGBA texture!\n", width, height);
goto Error;
}
if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
output->colorspace = MODE_BGRA;
output = WebPDecodeBGRA((const uint8_t*)data, (size_t)data_size, &width,
&height);
#else
output->colorspace = MODE_RGBA;
output = WebPDecodeRGBA((const uint8_t*)data, (size_t)data_size, &width,
&height);
#endif
output->width = surface->w;
output->height = surface->h;
output->u.RGBA.rgba = surface->pixels;
output->u.RGBA.stride = surface->pitch;
output->u.RGBA.size = surface->pitch * surface->h;
output->is_external_memory = 1;
status = WebPDecode((const uint8_t*)data, (size_t)data_size, &config);
if (status != VP8_STATUS_OK) {
if (output == NULL) {
fprintf(stderr, "Error decoding image (%d)\n", status);
goto Error;
}
if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
if (SDL_BlitSurface(surface, NULL, screen, NULL) ||
SDL_Flip(screen)) {
goto Error;
}
SDL_UpdateTexture(texture, NULL, output, width * sizeof(uint32_t));
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
ok = 1;
Error:
SDL_FreeSurface(surface);
SDL_FreeSurface(screen);
WebPFreeDecBuffer(output);
// We should call SDL_DestroyWindow(window) but that makes .js fail.
SDL_DestroyRenderer(renderer);
SDL_DestroyTexture(texture);
WebPFree(output);
return ok;
}

View File

@ -14,9 +14,9 @@
#ifndef WEBP_EXTRAS_WEBP_TO_SDL_H_
#define WEBP_EXTRAS_WEBP_TO_SDL_H_
// Exports the method WebpToSDL(const char* data, int data_size) which decodes
// Exports the method WebPToSDL(const char* data, int data_size) which decodes
// a WebP bitstream into an RGBA SDL surface.
// Return false on failure.
extern int WebpToSDL(const char* data, unsigned int data_size);
extern int WebPToSDL(const char* data, unsigned int data_size);
#endif // WEBP_EXTRAS_WEBP_TO_SDL_H_

View File

@ -1,3 +1,5 @@
# Ignore this file during non-NDK builds.
ifdef NDK_ROOT
LOCAL_PATH := $(call my-dir)
################################################################################
@ -52,3 +54,4 @@ LOCAL_STATIC_LIBRARIES := imageio_util
LOCAL_MODULE := imageenc
include $(BUILD_STATIC_LIBRARY)
endif # NDK_ROOT

View File

@ -260,14 +260,20 @@ int WebPWritePAM(FILE* fout, const WebPDecBuffer* const buffer) {
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
uint32_t width, height;
uint8_t* rgba;
int stride;
const uint32_t bytes_per_px = 2;
uint32_t y;
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
if (fout == NULL || buffer == NULL) return 0;
width = buffer->width;
height = buffer->height;
rgba = buffer->u.RGBA.rgba;
stride = buffer->u.RGBA.stride;
if (rgba == NULL) return 0;
fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height);
for (y = 0; y < height; ++y) {
@ -295,22 +301,29 @@ static void PutLE32(uint8_t* const dst, uint32_t value) {
#define BMP_HEADER_SIZE 54
#define BMP_HEADER_ALPHA_EXTRA_SIZE 16 // for alpha info
int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
const int header_size =
BMP_HEADER_SIZE + (has_alpha ? BMP_HEADER_ALPHA_EXTRA_SIZE : 0);
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint32_t bytes_per_px = has_alpha ? 4 : 3;
int has_alpha, header_size;
uint32_t width, height;
uint8_t* rgba;
int stride;
uint32_t y;
const uint32_t line_size = bytes_per_px * width;
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
const uint32_t image_size = bmp_stride * height;
const uint32_t total_size = image_size + header_size;
uint32_t bytes_per_px, line_size, image_size, bmp_stride, total_size;
uint8_t bmp_header[BMP_HEADER_SIZE + BMP_HEADER_ALPHA_EXTRA_SIZE] = { 0 };
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
if (fout == NULL || buffer == NULL) return 0;
has_alpha = WebPIsAlphaMode(buffer->colorspace);
header_size = BMP_HEADER_SIZE + (has_alpha ? BMP_HEADER_ALPHA_EXTRA_SIZE : 0);
width = buffer->width;
height = buffer->height;
rgba = buffer->u.RGBA.rgba;
stride = buffer->u.RGBA.stride;
bytes_per_px = has_alpha ? 4 : 3;
line_size = bytes_per_px * width;
bmp_stride = (line_size + 3) & ~3; // pad to 4
image_size = bmp_stride * height;
total_size = image_size + header_size;
if (rgba == NULL) return 0;
// bitmap file header
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
@ -372,17 +385,14 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint8_t bytes_per_px = has_alpha ? 4 : 3;
const uint8_t assoc_alpha =
WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
int has_alpha;
uint32_t width, height;
uint8_t* rgba;
int stride;
uint8_t bytes_per_px = 0;
const uint8_t assoc_alpha = 0;
// For non-alpha case, we omit tag 0x152 (ExtraSamples).
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
: NUM_IFD_ENTRIES - 1;
const uint8_t num_ifd_entries = 0;
uint8_t tiff_header[TIFF_HEADER_SIZE] = {
0x49, 0x49, 0x2a, 0x00, // little endian signature
8, 0, 0, 0, // offset to the unique IFD that follows
@ -416,7 +426,20 @@ int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
};
uint32_t y;
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
if (fout == NULL || buffer == NULL) return 0;
has_alpha = WebPIsAlphaMode(buffer->colorspace);
width = buffer->width;
height = buffer->height;
rgba = buffer->u.RGBA.rgba;
stride = buffer->u.RGBA.stride;
if (rgba == NULL) return 0;
// Update bytes_per_px, num_ifd_entries and assoc_alpha.
tiff_header[38] = tiff_header[102] = bytes_per_px = has_alpha ? 4 : 3;
tiff_header[8] = has_alpha ? NUM_IFD_ENTRIES : NUM_IFD_ENTRIES - 1;
tiff_header[186] = WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
// Fill placeholders in IFD:
PutLE32(tiff_header + 10 + 8, width);

View File

@ -89,6 +89,11 @@ int ImgIoUtilReadFile(const char* const file_name,
}
fseek(in, 0, SEEK_END);
file_size = ftell(in);
if (file_size == (size_t)-1) {
fclose(in);
WFPRINTF(stderr, "error getting size of '%s'\n", (const W_CHAR*)file_name);
return 0;
}
fseek(in, 0, SEEK_SET);
// we allocate one extra byte for the \0 terminator
file_data = (uint8_t*)WebPMalloc(file_size + 1);

View File

@ -206,8 +206,18 @@ struct my_error_mgr {
static void my_error_exit(j_common_ptr dinfo) {
struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err;
// The following code is disabled in fuzzing mode because:
// - the logs can be flooded due to invalid JPEG files
// - msg_code is wrongfully seen as uninitialized by msan when the libjpeg
// dependency is not built with sanitizers enabled
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
const int msg_code = myerr->pub.msg_code;
fprintf(stderr, "libjpeg error: ");
dinfo->err->output_message(dinfo);
if (msg_code == JERR_INPUT_EOF || msg_code == JERR_FILE_READ) {
fprintf(stderr, "`jpegtran -copy all` MAY be able to process this file.\n");
}
#endif
longjmp(myerr->setjmp_buffer, 1);
}

View File

@ -139,6 +139,8 @@ static const struct {
{ "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) },
// Exiftool puts exif data in APP1 chunk, too.
{ "Raw profile type APP1", ProcessRawProfile, METADATA_OFFSET(exif) },
// ImageMagick uses lowercase app1.
{ "Raw profile type app1", ProcessRawProfile, METADATA_OFFSET(exif) },
// XMP Specification Part 3, Section 3 #PNG
{ "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) },
{ NULL, NULL, 0 },
@ -159,6 +161,20 @@ static int ExtractMetadataFromPNG(png_structp png,
png_textp text = NULL;
const png_uint_32 num = png_get_text(png, info, &text, NULL);
png_uint_32 i;
#ifdef PNG_eXIf_SUPPORTED
// Look for an 'eXIf' tag. Preference is given to this tag as it's newer
// than the TextualData tags.
{
png_bytep exif;
png_uint_32 len;
if (png_get_eXIf_1(png, info, &len, &exif) == PNG_INFO_eXIf) {
if (!MetadataCopy((const char*)exif, len, &metadata->exif)) return 0;
}
}
#endif // PNG_eXIf_SUPPORTED
// Look for EXIF / XMP metadata.
for (i = 0; i < num; ++i, ++text) {
int j;
@ -192,6 +208,7 @@ static int ExtractMetadataFromPNG(png_structp png,
}
}
}
#ifdef PNG_iCCP_SUPPORTED
// Look for an ICC profile.
{
png_charp name;
@ -208,6 +225,7 @@ static int ExtractMetadataFromPNG(png_structp png,
if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0;
}
}
#endif // PNG_iCCP_SUPPORTED
}
return 1;
}
@ -235,7 +253,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
volatile png_infop end_info = NULL;
PNGReadContext context = { NULL, 0, 0 };
int color_type, bit_depth, interlaced;
int has_alpha;
int num_channels;
int num_passes;
int p;
volatile int ok = 0;
@ -293,9 +311,6 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
}
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png);
has_alpha = 1;
} else {
has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
}
// Apply gamma correction if needed.
@ -310,13 +325,16 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
if (!keep_alpha) {
png_set_strip_alpha(png);
has_alpha = 0;
}
num_passes = png_set_interlace_handling(png);
png_read_update_info(png, info);
stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb);
num_channels = png_get_channels(png, info);
if (num_channels != 3 && num_channels != 4) {
goto Error;
}
stride = (int64_t)num_channels * width * sizeof(*rgb);
if (stride != (int)stride ||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
goto Error;
@ -341,8 +359,8 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
pic->width = (int)width;
pic->height = (int)height;
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride)
: WebPPictureImportRGB(pic, rgb, (int)stride);
ok = (num_channels == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride)
: WebPPictureImportRGB(pic, rgb, (int)stride);
if (!ok) {
goto Error;

View File

@ -20,6 +20,10 @@
#include "webp/encode.h"
#include "./imageio_util.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
typedef enum {
WIDTH_FLAG = 1 << 0,
HEIGHT_FLAG = 1 << 1,
@ -111,8 +115,9 @@ static size_t ReadPAMFields(PNMInfo* const info, size_t off) {
break;
} else {
static const char kEllipsis[] = " ...";
const size_t kLen = strlen(kEllipsis) + 1; // +1 = trailing \0
int i;
if (out_size > 20) sprintf(out + 20 - strlen(kEllipsis), kEllipsis);
if (out_size > 20) snprintf(out + 20 - kLen, kLen, kEllipsis);
for (i = 0; i < (int)strlen(out); ++i) {
// isprint() might trigger a "char-subscripts" warning if given a char.
if (!isprint((int)out[i])) out[i] = ' ';

View File

@ -41,6 +41,7 @@ readonly TARGETDIR="${TOPDIR}/WebP.framework"
readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework"
readonly MUXTARGETDIR="${TOPDIR}/WebPMux.framework"
readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.framework"
readonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.framework"
readonly DEVELOPER=$(xcode-select --print-path)
readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
@ -52,7 +53,7 @@ DEMUXLIBLIST=''
if [[ -z "${SDK}" ]]; then
echo "iOS SDK not available"
exit 1
elif [[ ${SDK%%.*} -gt 8 ]]; then
elif [[ ${SDK%%.*} -gt 8 && "${XCODE%%.*}" -lt 16 ]]; then
EXTRA_CFLAGS="-fembed-bitcode"
elif [[ ${SDK%%.*} -le 6 ]]; then
echo "You need iOS SDK version 6.0 or above"
@ -63,7 +64,8 @@ echo "Xcode Version: ${XCODE}"
echo "iOS SDK Version: ${SDK}"
if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \
|| -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" ]]; then
|| -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" \
|| -e "${SHARPYUVTARGETDIR}" ]]; then
cat << EOF
WARNING: The following directories will be deleted:
WARNING: ${BUILDDIR}
@ -71,14 +73,16 @@ WARNING: ${TARGETDIR}
WARNING: ${DECTARGETDIR}
WARNING: ${MUXTARGETDIR}
WARNING: ${DEMUXTARGETDIR}
WARNING: ${SHARPYUVTARGETDIR}
WARNING: The build will continue in 5 seconds...
EOF
sleep 5
fi
rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \
${MUXTARGETDIR} ${DEMUXTARGETDIR}
${MUXTARGETDIR} ${DEMUXTARGETDIR} ${SHARPYUVTARGETDIR}
mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/ \
${MUXTARGETDIR}/Headers/ ${DEMUXTARGETDIR}/Headers/
${MUXTARGETDIR}/Headers/ ${DEMUXTARGETDIR}/Headers/ \
${SHARPYUVTARGETDIR}/Headers/
if [[ ! -e ${SRCDIR}/configure ]]; then
if ! (cd ${SRCDIR} && sh autogen.sh); then
@ -134,13 +138,14 @@ for PLATFORM in ${PLATFORMS}; do
set +x
# Build only the libraries, skip the examples.
make V=0 -C sharpyuv
make V=0 -C sharpyuv install
make V=0 -C src install
LIBLIST+=" ${ROOTDIR}/lib/libwebp.a"
DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
MUXLIBLIST+=" ${ROOTDIR}/lib/libwebpmux.a"
DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a"
SHARPYUVLIBLIST+=" ${ROOTDIR}/lib/libsharpyuv.a"
make clean
@ -165,4 +170,9 @@ cp -a ${SRCDIR}/src/webp/{decode,types,mux_types,demux}.h \
${DEMUXTARGETDIR}/Headers/
${LIPO} -create ${DEMUXLIBLIST} -output ${DEMUXTARGETDIR}/WebPDemux
echo "SHARPYUVLIBLIST = ${SHARPYUVLIBLIST}"
cp -a ${SRCDIR}/sharpyuv/{sharpyuv,sharpyuv_csp}.h \
${SHARPYUVTARGETDIR}/Headers/
${LIPO} -create ${SHARPYUVLIBLIST} -output ${SHARPYUVTARGETDIR}/SharpYuv
echo "SUCCESS"

View File

@ -3,7 +3,8 @@
# It will not install the libraries system-wide, but just create the 'cwebp'
# and 'dwebp' tools in the examples/ directory, along with the static
# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a',
# 'src/demux/libwebpdemux.a' and 'extras/libwebpextras.a'.
# 'src/demux/libwebpdemux.a', 'extras/libwebpextras.a' and
# 'sharpyuv/libsharpyuv.a'.
#
# To build the library and examples, use:
# make -f makefile.unix
@ -36,13 +37,13 @@ else
endif
# SDL flags: use sdl-config if it exists
SDL_CONFIG = $(shell sdl-config --version 2> /dev/null)
SDL_CONFIG = $(shell sdl2-config --version 2> /dev/null)
ifneq ($(SDL_CONFIG),)
SDL_LIBS = $(shell sdl-config --libs)
SDL_FLAGS = $(shell sdl-config --cflags)
SDL_LIBS = $(shell sdl2-config --libs)
SDL_FLAGS = $(shell sdl2-config --cflags)
else
# use best-guess
SDL_LIBS = -lSDL
SDL_LIBS = -lSDL2
SDL_FLAGS =
endif
@ -127,6 +128,7 @@ ANIM_UTIL_OBJS = \
SHARPYUV_OBJS = \
sharpyuv/sharpyuv.o \
sharpyuv/sharpyuv_cpu.o \
sharpyuv/sharpyuv_csp.o \
sharpyuv/sharpyuv_dsp.o \
sharpyuv/sharpyuv_gamma.o \
@ -274,6 +276,7 @@ UTILS_DEC_OBJS = \
src/utils/color_cache_utils.o \
src/utils/filters_utils.o \
src/utils/huffman_utils.o \
src/utils/palette.o \
src/utils/quant_levels_dec_utils.o \
src/utils/random_utils.o \
src/utils/rescaler_utils.o \
@ -288,13 +291,15 @@ UTILS_ENC_OBJS = \
EXTRA_OBJS = \
extras/extras.o \
extras/quality_estimate.o \
extras/sharpyuv_risk_table.o \
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
LIBWEBP_OBJS = $(SHARPYUV_OBJS) $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
$(DSP_ENC_OBJS) $(UTILS_ENC_OBJS)
LIBWEBPMUX_OBJS = $(MUX_OBJS)
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS)
LIBWEBPEXTRA_OBJS = $(EXTRA_OBJS)
LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS)
HDRS_INSTALLED = \
src/webp/decode.h \
@ -304,6 +309,11 @@ HDRS_INSTALLED = \
src/webp/mux_types.h \
src/webp/types.h \
SHARPYUV_HDRS_INSTALLED = \
sharpyuv/sharpyuv.h \
sharpyuv/sharpyuv_cpu.h \
sharpyuv/sharpyuv_csp.h \
HDRS = \
src/dec/alphai_dec.h \
src/dec/common_dec.h \
@ -335,6 +345,7 @@ HDRS = \
src/utils/filters_utils.h \
src/utils/huffman_utils.h \
src/utils/huffman_encode_utils.h \
src/utils/palette.h \
src/utils/quant_levels_utils.h \
src/utils/quant_levels_dec_utils.h \
src/utils/random_utils.h \
@ -343,6 +354,7 @@ HDRS = \
src/utils/utils.h \
src/webp/format_constants.h \
$(HDRS_INSTALLED) \
$(SHARPYUV_HDRS_INSTALLED) \
OUT_LIBS = examples/libexample_util.a
OUT_LIBS += imageio/libimageio_util.a
@ -350,6 +362,7 @@ OUT_LIBS += imageio/libimagedec.a
OUT_LIBS += imageio/libimageenc.a
OUT_LIBS += src/libwebpdecoder.a
OUT_LIBS += src/libwebp.a
OUT_LIBS += sharpyuv/libsharpyuv.a
EXTRA_LIB = extras/libwebpextras.a
OUT_EXAMPLES = examples/cwebp examples/dwebp
EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \
@ -395,6 +408,7 @@ src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS)
src/libwebp.a: $(LIBWEBP_OBJS)
src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS)
src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
sharpyuv/libsharpyuv.a: $(LIBSHARPYUV_OBJS)
%.a:
$(AR) $(ARFLAGS) $@ $^
@ -412,6 +426,7 @@ examples/webpinfo: examples/webpinfo.o
examples/anim_diff: examples/libanim_util.a examples/libgifdec.a
examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a
examples/anim_diff: imageio/libimageio_util.a src/libwebp.a
examples/anim_diff: sharpyuv/libsharpyuv.a
examples/anim_diff: override EXTRA_LIBS += $(GIF_LIBS)
examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF
examples/anim_dump: examples/libanim_util.a examples/libgifdec.a
@ -420,12 +435,14 @@ examples/anim_dump: examples/libexample_util.a
examples/anim_dump: imageio/libimageio_util.a
examples/anim_dump: imageio/libimageenc.a
examples/anim_dump: src/libwebp.a
examples/anim_dump: sharpyuv/libsharpyuv.a
examples/anim_dump: override EXTRA_LIBS += $(GIF_LIBS) $(DWEBP_LIBS)
examples/cwebp: examples/libexample_util.a
examples/cwebp: imageio/libimagedec.a
examples/cwebp: src/demux/libwebpdemux.a
examples/cwebp: imageio/libimageio_util.a
examples/cwebp: src/libwebp.a
examples/cwebp: sharpyuv/libsharpyuv.a
examples/cwebp: override EXTRA_LIBS += $(CWEBP_LIBS)
examples/dwebp: examples/libexample_util.a
examples/dwebp: imageio/libimagedec.a
@ -433,13 +450,16 @@ examples/dwebp: src/demux/libwebpdemux.a
examples/dwebp: imageio/libimageenc.a
examples/dwebp: imageio/libimageio_util.a
examples/dwebp: src/libwebp.a
examples/dwebp: sharpyuv/libsharpyuv.a
examples/dwebp: override EXTRA_LIBS += $(DWEBP_LIBS)
examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a
examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a
examples/gif2webp: sharpyuv/libsharpyuv.a
examples/gif2webp: override EXTRA_LIBS += $(GIF_LIBS)
examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF
examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a
examples/vwebp: imageio/libimageio_util.a src/libwebp.a
examples/vwebp: sharpyuv/libsharpyuv.a
examples/vwebp: override EXTRA_LIBS += $(GL_LIBS)
examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL
examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a
@ -447,7 +467,9 @@ examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a
examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a
examples/img2webp: imageio/libimagedec.a
examples/img2webp: src/demux/libwebpdemux.a
examples/img2webp: src/mux/libwebpmux.a src/libwebp.a
examples/img2webp: src/mux/libwebpmux.a
examples/img2webp: src/libwebp.a
examples/img2webp: sharpyuv/libsharpyuv.a
examples/img2webp: override EXTRA_LIBS += $(CWEBP_LIBS)
examples/webpinfo: examples/libexample_util.a imageio/libimageio_util.a
examples/webpinfo: src/libwebpdecoder.a
@ -457,16 +479,19 @@ extras/get_disto: imageio/libimagedec.a
extras/get_disto: src/demux/libwebpdemux.a
extras/get_disto: imageio/libimageio_util.a
extras/get_disto: src/libwebp.a
extras/get_disto: sharpyuv/libsharpyuv.a
extras/get_disto: override EXTRA_LIBS += $(CWEBP_LIBS)
extras/webp_quality: extras/webp_quality.o
extras/webp_quality: imageio/libimageio_util.a
extras/webp_quality: $(EXTRA_LIB) src/libwebp.a
extras/webp_quality: sharpyuv/libsharpyuv.a
extras/vwebp_sdl: extras/vwebp_sdl.o
extras/vwebp_sdl: extras/webp_to_sdl.o
extras/vwebp_sdl: imageio/libimageio_util.a
extras/vwebp_sdl: src/libwebp.a
extras/vwebp_sdl: sharpyuv/libsharpyuv.a
extras/vwebp_sdl: EXTRA_FLAGS += -DWEBP_HAVE_SDL $(SDL_FLAGS)
extras/vwebp_sdl: override EXTRA_LIBS += $(SDL_LIBS)
@ -477,12 +502,15 @@ dist: DESTDIR := dist
dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES)
dist: all
$(INSTALL) -m755 -d $(DESTDIR)/include/webp \
$(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib
$(DESTDIR)/include/webp/sharpyuv \
$(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib
$(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)/bin
$(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp
$(INSTALL) -m644 $(SHARPYUV_HDRS_INSTALLED) $(DESTDIR)/include/webp/sharpyuv
$(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
$(INSTALL) -m644 sharpyuv/libsharpyuv.a $(DESTDIR)/lib
umask 022; \
for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \
man/img2webp.1 man/webpinfo.1; do \

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
.TH CWEBP 1 "March 17, 2022"
.TH CWEBP 1 "September 17, 2024"
.SH NAME
cwebp \- compress an image file to a WebP file
.SH SYNOPSIS
@ -135,7 +135,9 @@ are used, \fB\-size\fP value will prevail.
Set a maximum number of passes to use during the dichotomy used by
options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10, default is 1.
If options \fB\-size\fP or \fB\-psnr\fP were used, but \fB\-pass\fP wasn't
specified, a default value of '6' passes will be used.
specified, a default value of '6' passes will be used. If \fB\-pass\fP is
specified, but neither \fB-size\fP nor \fB-psnr\fP are, a target PSNR of 40dB
will be used.
.TP
.BI \-qrange " int int
Specifies the permissible interval for the quality factor. This is particularly
@ -178,8 +180,8 @@ Disable strong filtering (if filtering is being used thanks to the
\fB\-f\fP option) and use simple filtering instead.
.TP
.B \-sharp_yuv
Use more accurate and sharper RGB->YUV conversion if needed. Note that this
process is slower than the default 'fast' RGB->YUV conversion.
Use more accurate and sharper RGB->YUV conversion. Note that this process is
slower than the default 'fast' RGB->YUV conversion.
.TP
.BI \-sns " int
Specify the amplitude of the spatial noise shaping. Spatial noise shaping
@ -202,7 +204,8 @@ In the VP8 format, the so\-called control partition has a limit of 512k and
is used to store the following information: whether the macroblock is skipped,
which segment it belongs to, whether it is coded as intra 4x4 or intra 16x16
mode, and finally the prediction modes to use for each of the sub\-blocks.
For a very large image, 512k only leaves room to few bits per 16x16 macroblock.
For a very large image, 512k only leaves room for a few bits per 16x16
macroblock.
The absolute minimum is 4 bits per macroblock. Skip, segment, and mode
information can use up almost all these 4 bits (although the case is unlikely),
which is problematic for very large images. The partition_limit factor controls
@ -211,7 +214,8 @@ useful in case the 512k limit is reached and the following message is displayed:
\fIError code: 6 (PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k)\fP.
If using \fB\-partition_limit\fP is not enough to meet the 512k constraint, one
should use less segments in order to save more header bits per macroblock.
See the \fB\-segments\fP option.
See the \fB\-segments\fP option. Note the \fB-m\fP and \fB-q\fP options also
influence the encoder's decisions and ability to hit this limit.
.SS LOGGING OPTIONS
These options control the level of output:
@ -295,12 +299,12 @@ Note: each input format may not support all combinations.
.B \-noasm
Disable all assembly optimizations.
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH EXIT STATUS
If there were no problems during execution, \fBcwebp\fP exits with the value of
the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
.PP
If an error occurs, \fBcwebp\fP exits with the value of the C constant
\fBEXIT_FAILURE\fP. This is usually one.
.SH EXAMPLES
cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp
@ -320,6 +324,13 @@ https://chromium.googlesource.com/webm/libwebp
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
for the Debian project (and may be used by others).
.SH REPORTING BUGS
Please report all bugs to the issue tracker:
https://issues.webmproject.org
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH SEE ALSO
.BR dwebp (1),
.BR gif2webp (1)

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
.TH DWEBP 1 "November 17, 2021"
.TH DWEBP 1 "July 18, 2024"
.SH NAME
dwebp \- decompress a WebP file to an image file
.SH SYNOPSIS
@ -108,12 +108,12 @@ Print extra information (decoding time in particular).
.B \-noasm
Disable all assembly optimizations.
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH EXIT STATUS
If there were no problems during execution, \fBdwebp\fP exits with the value of
the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
.PP
If an error occurs, \fBdwebp\fP exits with the value of the C constant
\fBEXIT_FAILURE\fP. This is usually one.
.SH EXAMPLES
dwebp picture.webp \-o output.png
@ -133,6 +133,13 @@ https://chromium.googlesource.com/webm/libwebp
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
for the Debian project (and may be used by others).
.SH REPORTING BUGS
Please report all bugs to the issue tracker:
https://issues.webmproject.org
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH SEE ALSO
.BR cwebp (1),
.BR gif2webp (1),

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
.TH GIF2WEBP 1 "November 17, 2021"
.TH GIF2WEBP 1 "November 4, 2024"
.SH NAME
gif2webp \- Convert a GIF image to WebP
.SH SYNOPSIS
@ -39,6 +39,18 @@ Encode the image using lossy compression.
Mixed compression mode: optimize compression of the image by picking either
lossy or lossless compression for each frame heuristically.
.TP
.BI \-near_lossless " int
Specify the level of near\-lossless image preprocessing. This option adjusts
pixel values to help compressibility, but has minimal impact on the visual
quality. It triggers lossless compression mode automatically. The range is 0
(maximum preprocessing) to 100 (no preprocessing, the default). The typical
value is around 60. Note that lossy with \fB\-q 100\fP can at times yield
better results.
.TP
.B \-sharp_yuv
Use more accurate and sharper RGB->YUV conversion. Note that this process is
slower than the default 'fast' RGB->YUV conversion.
.TP
.BI \-q " float
Specify the compression factor for RGB channels between 0 and 100. The default
is 75.
@ -126,12 +138,12 @@ Print extra information.
.B \-quiet
Do not print anything.
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH EXIT STATUS
If there were no problems during execution, \fBgif2webp\fP exits with the value
of the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
.PP
If an error occurs, \fBgif2webp\fP exits with the value of the C constant
\fBEXIT_FAILURE\fP. This is usually one.
.SH EXAMPLES
gif2webp picture.gif \-o picture.webp
@ -155,6 +167,13 @@ https://chromium.googlesource.com/webm/libwebp
This manual page was written by Urvang Joshi <urvang@google.com>, for the
Debian project (and may be used by others).
.SH REPORTING BUGS
Please report all bugs to the issue tracker:
https://issues.webmproject.org
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH SEE ALSO
.BR cwebp (1),
.BR dwebp (1),

View File

@ -1,10 +1,10 @@
.\" Hey, EMACS: -*- nroff -*-
.TH IMG2WEBP 1 "January 5, 2022"
.TH IMG2WEBP 1 "November 26, 2024"
.SH NAME
img2webp \- create animated WebP file from a sequence of input images.
.SH SYNOPSIS
.B img2webp
[file_options] [[frame_options] frame_file]...
[file_options] [[frame_options] frame_file]... [\-o webp_file]
.br
.B img2webp argument_file_name
.br
@ -44,6 +44,18 @@ Mixed compression mode: optimize compression of the image by picking either
lossy or lossless compression for each frame heuristically. This global
option disables the local option \fB-lossy\fP and \fB-lossless\fP .
.TP
.BI \-near_lossless " int
Specify the level of near\-lossless image preprocessing. This option adjusts
pixel values to help compressibility, but has minimal impact on the visual
quality. It triggers lossless compression mode automatically. The range is 0
(maximum preprocessing) to 100 (no preprocessing, the default). The typical
value is around 60. Note that lossy with \fB\-q 100\fP can at times yield
better results.
.TP
.B \-sharp_yuv
Use more accurate and sharper RGB->YUV conversion. Note that this process is
slower than the default 'fast' RGB->YUV conversion.
.TP
.BI \-loop " int
Specifies the number of times the animation should loop. Using '0'
means 'loop indefinitely'.
@ -76,18 +88,27 @@ Specify the compression factor between 0 and 100. The default is 75.
Specify the compression method to use. This parameter controls the
trade off between encoding speed and the compressed file size and quality.
Possible values range from 0 to 6. Default value is 4.
When higher values are used, the encoder will spend more time inspecting
additional encoding possibilities and decide on the quality gain.
Lower value can result in faster processing time at the expense of
larger file size and lower compression quality.
.TP
.B \-exact, \-noexact
Preserve or alter RGB values in transparent area. The default is
\fB-noexact\fP, to help compressibility. Note \fB\-noexact\fP may cause
artifacts in frames compressed with \fB\-lossy\fP.
.SH EXIT STATUS
If there were no problems during execution, \fBimg2webp\fP exits with the value
of the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
.PP
If an error occurs, \fBimg2webp\fP exits with the value of the C constant
\fBEXIT_FAILURE\fP. This is usually one.
.SH EXAMPLE
img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp
.br
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH AUTHORS
\fBimg2webp\fP is a part of libwebp and was written by the WebP team.
.br
@ -97,6 +118,13 @@ https://chromium.googlesource.com/webm/libwebp
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
for the Debian project (and may be used by others).
.SH REPORTING BUGS
Please report all bugs to the issue tracker:
https://issues.webmproject.org
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH SEE ALSO
.BR webpmux (1),
.BR gif2webp (1)

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
.TH VWEBP 1 "November 17, 2021"
.TH VWEBP 1 "July 18, 2024"
.SH NAME
vwebp \- decompress a WebP file and display it in a window
.SH SYNOPSIS
@ -72,12 +72,12 @@ Disable blending and disposal process, for debugging purposes.
.B 'q' / 'Q' / ESC
Quit.
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH EXIT STATUS
If there were no problems during execution, \fBvwebp\fP exits with the value of
the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
.PP
If an error occurs, \fBvwebp\fP exits with the value of the C constant
\fBEXIT_FAILURE\fP. This is usually one.
.SH EXAMPLES
vwebp picture.webp
@ -94,6 +94,13 @@ https://chromium.googlesource.com/webm/libwebp
.PP
This manual page was written for the Debian project (and may be used by others).
.SH REPORTING BUGS
Please report all bugs to the issue tracker:
https://issues.webmproject.org
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH SEE ALSO
.BR dwebp (1)
.br

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
.TH WEBPINFO 1 "November 17, 2021"
.TH WEBPINFO 1 "July 18, 2024"
.SH NAME
webpinfo \- print out the chunk level structure of WebP files
along with basic integrity checks.
@ -47,12 +47,12 @@ Detailed usage instructions.
Input files in WebP format. Input files must come last, following
options (if any). There can be multiple input files.
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH EXIT STATUS
If there were no problems during execution, \fBwebpinfo\fP exits with the value
of the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
.PP
If an error occurs, \fBwebpinfo\fP exits with the value of the C constant
\fBEXIT_FAILURE\fP. This is usually one.
.SH EXAMPLES
.br
@ -73,6 +73,13 @@ https://chromium.googlesource.com/webm/libwebp
This manual page was written by Hui Su <huisu@google.com>,
for the Debian project (and may be used by others).
.SH REPORTING BUGS
Please report all bugs to the issue tracker:
https://issues.webmproject.org
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH SEE ALSO
.BR webpmux (1)
.br

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
.TH WEBPMUX 1 "November 17, 2021"
.TH WEBPMUX 1 "July 18, 2024"
.SH NAME
webpmux \- create animated WebP files from non\-animated WebP images, extract
frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
@ -186,12 +186,12 @@ Output file in WebP format.
.TP
The nature of EXIF, XMP and ICC data is not checked and is assumed to be valid.
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH EXIT STATUS
If there were no problems during execution, \fBwebpmux\fP exits with the value
of the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
.PP
If an error occurs, \fBwebpmux\fP exits with the value of the C constant
\fBEXIT_FAILURE\fP. This is usually one.
.SH EXAMPLES
.P
@ -262,6 +262,13 @@ https://chromium.googlesource.com/webm/libwebp
This manual page was written by Vikas Arora <vikaas.arora@gmail.com>,
for the Debian project (and may be used by others).
.SH REPORTING BUGS
Please report all bugs to the issue tracker:
https://issues.webmproject.org
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH SEE ALSO
.BR cwebp (1),
.BR dwebp (1),

View File

@ -1,13 +1,19 @@
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
lib_LTLIBRARIES = libsharpyuv.la
noinst_LTLIBRARIES =
noinst_LTLIBRARIES += libsharpyuv.la
noinst_LTLIBRARIES += libsharpyuv_sse2.la
noinst_LTLIBRARIES += libsharpyuv_neon.la
libsharpyuvinclude_HEADERS =
libsharpyuvinclude_HEADERS += sharpyuv.h
libsharpyuvinclude_HEADERS += sharpyuv_csp.h
noinst_HEADERS =
noinst_HEADERS += ../src/webp/types.h
noinst_HEADERS += ../src/dsp/cpu.c
noinst_HEADERS += ../src/dsp/cpu.h
noinst_HEADERS += ../src/webp/types.h
libsharpyuv_sse2_la_SOURCES =
libsharpyuv_sse2_la_SOURCES += sharpyuv_sse2.c
@ -20,15 +26,16 @@ libsharpyuv_neon_la_CPPFLAGS = $(libsharpyuv_la_CPPFLAGS)
libsharpyuv_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS)
libsharpyuv_la_SOURCES =
libsharpyuv_la_SOURCES += sharpyuv_cpu.c sharpyuv_cpu.h
libsharpyuv_la_SOURCES += sharpyuv_csp.c sharpyuv_csp.h
libsharpyuv_la_SOURCES += sharpyuv_dsp.c sharpyuv_dsp.h
libsharpyuv_la_SOURCES += sharpyuv_gamma.c sharpyuv_gamma.h
libsharpyuv_la_SOURCES += sharpyuv.c sharpyuv.h
libsharpyuv_la_CPPFLAGS = $(AM_CPPFLAGS)
libsharpyuv_la_LDFLAGS =
libsharpyuv_la_LDFLAGS = -no-undefined -version-info 1:1:1 -lm
libsharpyuv_la_LIBADD =
libsharpyuv_la_LIBADD += libsharpyuv_sse2.la
libsharpyuv_la_LIBADD += libsharpyuv_neon.la
noinst_PROGRAMS =
libsharpyuvincludedir = $(includedir)/webp/sharpyuv
pkgconfig_DATA = libsharpyuv.pc

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@/webp
Name: libsharpyuv
Description: Library for sharp RGB to YUV conversion
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -l@webp_libname_prefix@sharpyuv
Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@

41
sharpyuv/libsharpyuv.rc Normal file
View File

@ -0,0 +1,41 @@
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,0,4,1
PRODUCTVERSION 0,0,4,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libsharpyuv DLL"
VALUE "FileVersion", "0.4.1"
VALUE "InternalName", "libsharpyuv.dll"
VALUE "LegalCopyright", "Copyright (C) 2024"
VALUE "OriginalFilename", "libsharpyuv.dll"
VALUE "ProductName", "SharpYuv Library"
VALUE "ProductVersion", "0.4.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources

View File

@ -15,15 +15,21 @@
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "src/webp/types.h"
#include "src/dsp/cpu.h"
#include "sharpyuv/sharpyuv_cpu.h"
#include "sharpyuv/sharpyuv_dsp.h"
#include "sharpyuv/sharpyuv_gamma.h"
//------------------------------------------------------------------------------
int SharpYuvGetVersion(void) {
return SHARPYUV_VERSION;
}
//------------------------------------------------------------------------------
// Sharp RGB->YUV conversion
@ -69,41 +75,48 @@ static int RGBToGray(int64_t r, int64_t g, int64_t b) {
}
static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
int rgb_bit_depth) {
int rgb_bit_depth,
SharpYuvTransferFunctionType transfer_type) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
const uint32_t A = SharpYuvGammaToLinear(a, bit_depth);
const uint32_t B = SharpYuvGammaToLinear(b, bit_depth);
const uint32_t C = SharpYuvGammaToLinear(c, bit_depth);
const uint32_t D = SharpYuvGammaToLinear(d, bit_depth);
return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth);
const uint32_t A = SharpYuvGammaToLinear(a, bit_depth, transfer_type);
const uint32_t B = SharpYuvGammaToLinear(b, bit_depth, transfer_type);
const uint32_t C = SharpYuvGammaToLinear(c, bit_depth, transfer_type);
const uint32_t D = SharpYuvGammaToLinear(d, bit_depth, transfer_type);
return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth,
transfer_type);
}
static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
int rgb_bit_depth) {
int rgb_bit_depth,
SharpYuvTransferFunctionType transfer_type) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
int i;
for (i = 0; i < w; ++i) {
const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth);
const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth);
const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth);
int i = 0;
do {
const uint32_t R =
SharpYuvGammaToLinear(src[0 * w + i], bit_depth, transfer_type);
const uint32_t G =
SharpYuvGammaToLinear(src[1 * w + i], bit_depth, transfer_type);
const uint32_t B =
SharpYuvGammaToLinear(src[2 * w + i], bit_depth, transfer_type);
const uint32_t Y = RGBToGray(R, G, B);
dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth);
}
dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth, transfer_type);
} while (++i < w);
}
static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
fixed_t* dst, int uv_w, int rgb_bit_depth) {
int i;
for (i = 0; i < uv_w; ++i) {
fixed_t* dst, int uv_w, int rgb_bit_depth,
SharpYuvTransferFunctionType transfer_type) {
int i = 0;
do {
const int r =
ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0],
src2[0 * uv_w + 1], rgb_bit_depth);
src2[0 * uv_w + 1], rgb_bit_depth, transfer_type);
const int g =
ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0],
src2[2 * uv_w + 1], rgb_bit_depth);
src2[2 * uv_w + 1], rgb_bit_depth, transfer_type);
const int b =
ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0],
src2[4 * uv_w + 1], rgb_bit_depth);
src2[4 * uv_w + 1], rgb_bit_depth, transfer_type);
const int W = RGBToGray(r, g, b);
dst[0 * uv_w] = (fixed_t)(r - W);
dst[1 * uv_w] = (fixed_t)(g - W);
@ -111,15 +124,15 @@ static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
dst += 1;
src1 += 2;
src2 += 2;
}
} while (++i < uv_w);
}
static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
int i;
int i = 0;
assert(w > 0);
for (i = 0; i < w; ++i) {
do {
y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
}
} while (++i < w);
}
//------------------------------------------------------------------------------
@ -145,9 +158,9 @@ static void ImportOneRow(const uint8_t* const r_ptr,
// Convert the rgb_step from a number of bytes to a number of uint8_t or
// uint16_t values depending the bit depth.
const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step;
int i;
int i = 0;
const int w = (pic_width + 1) & ~1;
for (i = 0; i < pic_width; ++i) {
do {
const int off = i * step;
const int shift = GetPrecisionShift(rgb_bit_depth);
if (rgb_bit_depth == 8) {
@ -159,7 +172,7 @@ static void ImportOneRow(const uint8_t* const r_ptr,
dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift);
dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift);
}
}
} while (++i < pic_width);
if (pic_width & 1) { // replicate rightmost pixel
dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
@ -227,8 +240,11 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
const int sfix = GetPrecisionShift(rgb_bit_depth);
const int yuv_max = (1 << yuv_bit_depth) - 1;
for (best_uv = best_uv_base, j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
best_uv = best_uv_base;
j = 0;
do {
i = 0;
do {
const int off = (i >> 1);
const int W = best_y[i];
const int r = best_uv[off + 0 * uv_w] + W;
@ -240,19 +256,22 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
} else {
((uint16_t*)y_ptr)[i] = clip(y, yuv_max);
}
}
} while (++i < width);
best_y += w;
best_uv += (j & 1) * 3 * uv_w;
y_ptr += y_stride;
}
for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
for (i = 0; i < uv_w; ++i) {
const int off = i;
} while (++j < height);
best_uv = best_uv_base;
j = 0;
do {
i = 0;
do {
// Note r, g and b values here are off by W, but a constant offset on all
// 3 components doesn't change the value of u and v with a YCbCr matrix.
const int r = best_uv[off + 0 * uv_w];
const int g = best_uv[off + 1 * uv_w];
const int b = best_uv[off + 2 * uv_w];
const int r = best_uv[i + 0 * uv_w];
const int g = best_uv[i + 1 * uv_w];
const int b = best_uv[i + 2 * uv_w];
const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix);
const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix);
if (yuv_bit_depth <= 8) {
@ -262,11 +281,11 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
((uint16_t*)u_ptr)[i] = clip(u, yuv_max);
((uint16_t*)v_ptr)[i] = clip(v, yuv_max);
}
}
} while (++i < uv_w);
best_uv += 3 * uv_w;
u_ptr += u_stride;
v_ptr += v_stride;
}
} while (++j < uv_h);
return 1;
}
@ -279,7 +298,7 @@ static void* SafeMalloc(uint64_t nmemb, size_t size) {
return malloc((size_t)total_size);
}
#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T)))
#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((uint64_t)(W) * (H), sizeof(T)))
static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
const uint8_t* b_ptr, int rgb_step, int rgb_stride,
@ -287,12 +306,14 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
uint8_t* u_ptr, int u_stride, uint8_t* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int height,
const SharpYuvConversionMatrix* yuv_matrix) {
const SharpYuvConversionMatrix* yuv_matrix,
SharpYuvTransferFunctionType transfer_type) {
// we expand the right/bottom border if needed
const int w = (width + 1) & ~1;
const int h = (height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
const int y_bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
uint64_t prev_diff_y_sum = ~0;
int j, iter;
@ -340,9 +361,9 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
StoreGray(src1, best_y + 0, w);
StoreGray(src2, best_y + w, w);
UpdateW(src1, target_y, w, rgb_bit_depth);
UpdateW(src2, target_y + w, w, rgb_bit_depth);
UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth);
UpdateW(src1, target_y, w, rgb_bit_depth, transfer_type);
UpdateW(src2, target_y + w, w, rgb_bit_depth, transfer_type);
UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth, transfer_type);
memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
best_y += 2 * w;
best_uv += 3 * uv_w;
@ -363,7 +384,8 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
best_uv = best_uv_base;
target_y = target_y_base;
target_uv = target_uv_base;
for (j = 0; j < h; j += 2) {
j = 0;
do {
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
{
@ -374,21 +396,21 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
cur_uv = next_uv;
}
UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth);
UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth);
UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth);
UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth, transfer_type);
UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth, transfer_type);
UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth, transfer_type);
// update two rows of Y and one row of RGB
diff_y_sum +=
SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w,
rgb_bit_depth + GetPrecisionShift(rgb_bit_depth));
SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w, y_bit_depth);
SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
}
j += 2;
} while (j < h);
// test exit condition
if (iter > 0) {
if (diff_y_sum < diff_y_threshold) break;
@ -412,34 +434,87 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
free(tmp_buffer);
return ok;
}
#undef SAFE_ALLOC
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
#include <pthread.h> // NOLINT
#define LOCK_ACCESS \
static pthread_mutex_t sharpyuv_lock = PTHREAD_MUTEX_INITIALIZER; \
if (pthread_mutex_lock(&sharpyuv_lock)) return
#define UNLOCK_ACCESS_AND_RETURN \
do { \
(void)pthread_mutex_unlock(&sharpyuv_lock); \
return; \
} while (0)
#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
#define LOCK_ACCESS do {} while (0)
#define UNLOCK_ACCESS_AND_RETURN return
#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
// Hidden exported init function.
// By default SharpYuvConvert calls it with NULL. If needed, users can declare
// it as extern and call it with a VP8CPUInfo function.
extern void SharpYuvInit(VP8CPUInfo cpu_info_func);
// By default SharpYuvConvert calls it with SharpYuvGetCPUInfo. If needed,
// users can declare it as extern and call it with an alternate VP8CPUInfo
// function.
extern VP8CPUInfo SharpYuvGetCPUInfo;
SHARPYUV_EXTERN void SharpYuvInit(VP8CPUInfo cpu_info_func);
void SharpYuvInit(VP8CPUInfo cpu_info_func) {
static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used =
(VP8CPUInfo)&sharpyuv_last_cpuinfo_used;
const int initialized =
(sharpyuv_last_cpuinfo_used != (VP8CPUInfo)&sharpyuv_last_cpuinfo_used);
if (cpu_info_func == NULL && initialized) return;
if (sharpyuv_last_cpuinfo_used == cpu_info_func) return;
SharpYuvInitDsp(cpu_info_func);
if (!initialized) {
SharpYuvInitGammaTables();
LOCK_ACCESS;
// Only update SharpYuvGetCPUInfo when called from external code to avoid a
// race on reading the value in SharpYuvConvert().
if (cpu_info_func != (VP8CPUInfo)&SharpYuvGetCPUInfo) {
SharpYuvGetCPUInfo = cpu_info_func;
}
if (sharpyuv_last_cpuinfo_used == SharpYuvGetCPUInfo) {
UNLOCK_ACCESS_AND_RETURN;
}
sharpyuv_last_cpuinfo_used = cpu_info_func;
SharpYuvInitDsp();
SharpYuvInitGammaTables();
sharpyuv_last_cpuinfo_used = SharpYuvGetCPUInfo;
UNLOCK_ACCESS_AND_RETURN;
}
int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
const void* b_ptr, int rgb_step, int rgb_stride,
int rgb_bit_depth, void* y_ptr, int y_stride,
void* u_ptr, int u_stride, void* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr,
int rgb_step, int rgb_stride, int rgb_bit_depth,
void* y_ptr, int y_stride, void* u_ptr, int u_stride,
void* v_ptr, int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvConversionMatrix* yuv_matrix) {
SharpYuvOptions options;
options.yuv_matrix = yuv_matrix;
options.transfer_type = kSharpYuvTransferFunctionSrgb;
return SharpYuvConvertWithOptions(
r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride, rgb_bit_depth, y_ptr, y_stride,
u_ptr, u_stride, v_ptr, v_stride, yuv_bit_depth, width, height, &options);
}
int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix* yuv_matrix,
SharpYuvOptions* options, int version) {
const int major = (version >> 24);
const int minor = (version >> 16) & 0xff;
if (options == NULL || yuv_matrix == NULL ||
(major == SHARPYUV_VERSION_MAJOR && major == 0 &&
minor != SHARPYUV_VERSION_MINOR) ||
(major != SHARPYUV_VERSION_MAJOR)) {
return 0;
}
options->yuv_matrix = yuv_matrix;
options->transfer_type = kSharpYuvTransferFunctionSrgb;
return 1;
}
int SharpYuvConvertWithOptions(const void* r_ptr, const void* g_ptr,
const void* b_ptr, int rgb_step, int rgb_stride,
int rgb_bit_depth, void* y_ptr, int y_stride,
void* u_ptr, int u_stride, void* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvOptions* options) {
const SharpYuvConversionMatrix* yuv_matrix = options->yuv_matrix;
SharpYuvTransferFunctionType transfer_type = options->transfer_type;
SharpYuvConversionMatrix scaled_matrix;
const int rgb_max = (1 << rgb_bit_depth) - 1;
const int rgb_round = 1 << (rgb_bit_depth - 1);
@ -458,7 +533,7 @@ int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) {
return 0;
}
if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) {
if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride % 2 != 0)) {
// Step/stride should be even for uint16_t buffers.
return 0;
}
@ -467,7 +542,8 @@ int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
// Stride should be even for uint16_t buffers.
return 0;
}
SharpYuvInit(NULL);
// The address of the function pointer is used to avoid a read race.
SharpYuvInit((VP8CPUInfo)&SharpYuvGetCPUInfo);
// Add scaling factor to go from rgb_bit_depth to yuv_bit_depth, to the
// rgb->yuv conversion matrix.
@ -489,10 +565,11 @@ int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
scaled_matrix.rgb_to_u[3] = Shift(yuv_matrix->rgb_to_u[3], sfix);
scaled_matrix.rgb_to_v[3] = Shift(yuv_matrix->rgb_to_v[3], sfix);
return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride,
rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride,
v_ptr, v_stride, yuv_bit_depth, width, height,
&scaled_matrix);
return DoSharpArgbToYuv(
(const uint8_t*)r_ptr, (const uint8_t*)g_ptr, (const uint8_t*)b_ptr,
rgb_step, rgb_stride, rgb_bit_depth, (uint8_t*)y_ptr, y_stride,
(uint8_t*)u_ptr, u_stride, (uint8_t*)v_ptr, v_stride, yuv_bit_depth,
width, height, &scaled_matrix, transfer_type);
}
//------------------------------------------------------------------------------

View File

@ -12,16 +12,47 @@
#ifndef WEBP_SHARPYUV_SHARPYUV_H_
#define WEBP_SHARPYUV_SHARPYUV_H_
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SHARPYUV_EXTERN
#ifdef WEBP_EXTERN
#define SHARPYUV_EXTERN WEBP_EXTERN
#else
// This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds.
#if defined(_WIN32) && defined(WEBP_DLL)
#define SHARPYUV_EXTERN __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
#define SHARPYUV_EXTERN extern __attribute__((visibility("default")))
#else
#define SHARPYUV_EXTERN extern
#endif /* defined(_WIN32) && defined(WEBP_DLL) */
#endif /* WEBP_EXTERN */
#endif /* SHARPYUV_EXTERN */
#ifndef SHARPYUV_INLINE
#ifdef WEBP_INLINE
#define SHARPYUV_INLINE WEBP_INLINE
#else
#ifndef _MSC_VER
#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
#define SHARPYUV_INLINE inline
#else
#define SHARPYUV_INLINE
#endif
#else
#define SHARPYUV_INLINE __forceinline
#endif /* _MSC_VER */
#endif /* WEBP_INLINE */
#endif /* SHARPYUV_INLINE */
// SharpYUV API version following the convention from semver.org
#define SHARPYUV_VERSION_MAJOR 0
#define SHARPYUV_VERSION_MINOR 1
#define SHARPYUV_VERSION_PATCH 0
#define SHARPYUV_VERSION_MINOR 4
#define SHARPYUV_VERSION_PATCH 1
// Version as a uint32_t. The major number is the high 8 bits.
// The minor number is the middle 8 bits. The patch number is the low 16 bits.
#define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \
@ -30,17 +61,55 @@ extern "C" {
SHARPYUV_MAKE_VERSION(SHARPYUV_VERSION_MAJOR, SHARPYUV_VERSION_MINOR, \
SHARPYUV_VERSION_PATCH)
// Returns the library's version number, packed in hexadecimal. See
// SHARPYUV_VERSION.
SHARPYUV_EXTERN int SharpYuvGetVersion(void);
// RGB to YUV conversion matrix, in 16 bit fixed point.
// y = rgb_to_y[0] * r + rgb_to_y[1] * g + rgb_to_y[2] * b + rgb_to_y[3]
// u = rgb_to_u[0] * r + rgb_to_u[1] * g + rgb_to_u[2] * b + rgb_to_u[3]
// v = rgb_to_v[0] * r + rgb_to_v[1] * g + rgb_to_v[2] * b + rgb_to_v[3]
// Then y, u and v values are divided by 1<<16 and rounded.
// y_ = rgb_to_y[0] * r + rgb_to_y[1] * g + rgb_to_y[2] * b + rgb_to_y[3]
// u_ = rgb_to_u[0] * r + rgb_to_u[1] * g + rgb_to_u[2] * b + rgb_to_u[3]
// v_ = rgb_to_v[0] * r + rgb_to_v[1] * g + rgb_to_v[2] * b + rgb_to_v[3]
// Then the values are divided by 1<<16 and rounded.
// y = (y_ + (1 << 15)) >> 16
// u = (u_ + (1 << 15)) >> 16
// v = (v_ + (1 << 15)) >> 16
//
// Typically, the offset values rgb_to_y[3], rgb_to_u[3] and rgb_to_v[3] depend
// on the input's bit depth, e.g., rgb_to_u[3] = 1 << (rgb_bit_depth - 1 + 16).
// See also sharpyuv_csp.h to get a predefined matrix or generate a matrix.
typedef struct {
int rgb_to_y[4];
int rgb_to_u[4];
int rgb_to_v[4];
} SharpYuvConversionMatrix;
typedef struct SharpYuvOptions SharpYuvOptions;
// Enums for transfer functions, as defined in H.273,
// https://www.itu.int/rec/T-REC-H.273-202107-I/en
typedef enum SharpYuvTransferFunctionType {
// 0 is reserved
kSharpYuvTransferFunctionBt709 = 1,
// 2 is unspecified
// 3 is reserved
kSharpYuvTransferFunctionBt470M = 4,
kSharpYuvTransferFunctionBt470Bg = 5,
kSharpYuvTransferFunctionBt601 = 6,
kSharpYuvTransferFunctionSmpte240 = 7,
kSharpYuvTransferFunctionLinear = 8,
kSharpYuvTransferFunctionLog100 = 9,
kSharpYuvTransferFunctionLog100_Sqrt10 = 10,
kSharpYuvTransferFunctionIec61966 = 11,
kSharpYuvTransferFunctionBt1361 = 12,
kSharpYuvTransferFunctionSrgb = 13,
kSharpYuvTransferFunctionBt2020_10Bit = 14,
kSharpYuvTransferFunctionBt2020_12Bit = 15,
kSharpYuvTransferFunctionSmpte2084 = 16, // PQ
kSharpYuvTransferFunctionSmpte428 = 17,
kSharpYuvTransferFunctionHlg = 18,
kSharpYuvTransferFunctionNum
} SharpYuvTransferFunctionType;
// Converts RGB to YUV420 using a downsampling algorithm that minimizes
// artefacts caused by chroma subsampling.
// This is slower than standard downsampling (averaging of 4 UV values).
@ -65,11 +134,42 @@ typedef struct {
// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they
// should be multiples of 2.
// width, height: width and height of the image in pixels
int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr,
int rgb_step, int rgb_stride, int rgb_bit_depth,
void* y_ptr, int y_stride, void* u_ptr, int u_stride,
void* v_ptr, int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvConversionMatrix* yuv_matrix);
// yuv_matrix: RGB to YUV conversion matrix. The matrix values typically
// depend on the input's rgb_bit_depth.
// This function calls SharpYuvConvertWithOptions with a default transfer
// function of kSharpYuvTransferFunctionSrgb.
SHARPYUV_EXTERN int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
const void* b_ptr, int rgb_step,
int rgb_stride, int rgb_bit_depth,
void* y_ptr, int y_stride, void* u_ptr,
int u_stride, void* v_ptr, int v_stride,
int yuv_bit_depth, int width, int height,
const SharpYuvConversionMatrix* yuv_matrix);
struct SharpYuvOptions {
// This matrix cannot be NULL and can be initialized by
// SharpYuvComputeConversionMatrix.
const SharpYuvConversionMatrix* yuv_matrix;
SharpYuvTransferFunctionType transfer_type;
};
// Internal, version-checked, entry point
SHARPYUV_EXTERN int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix*,
SharpYuvOptions*, int);
// Should always be called, to initialize a fresh SharpYuvOptions
// structure before modification. SharpYuvOptionsInit() must have succeeded
// before using the 'options' object.
static SHARPYUV_INLINE int SharpYuvOptionsInit(
const SharpYuvConversionMatrix* yuv_matrix, SharpYuvOptions* options) {
return SharpYuvOptionsInitInternal(yuv_matrix, options, SHARPYUV_VERSION);
}
SHARPYUV_EXTERN int SharpYuvConvertWithOptions(
const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step,
int rgb_stride, int rgb_bit_depth, void* y_ptr, int y_stride, void* u_ptr,
int u_stride, void* v_ptr, int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvOptions* options);
// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
// support (it's rarely used in practice, especially for images).

14
sharpyuv/sharpyuv_cpu.c Normal file
View File

@ -0,0 +1,14 @@
// Copyright 2022 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.
// -----------------------------------------------------------------------------
//
#include "sharpyuv/sharpyuv_cpu.h"
// Include src/dsp/cpu.c to create SharpYuvGetCPUInfo from VP8GetCPUInfo. The
// function pointer is renamed in sharpyuv_cpu.h.
#include "src/dsp/cpu.c"

22
sharpyuv/sharpyuv_cpu.h Normal file
View File

@ -0,0 +1,22 @@
// Copyright 2022 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.
// -----------------------------------------------------------------------------
//
#ifndef WEBP_SHARPYUV_SHARPYUV_CPU_H_
#define WEBP_SHARPYUV_SHARPYUV_CPU_H_
#include "sharpyuv/sharpyuv.h"
// Avoid exporting SharpYuvGetCPUInfo in shared object / DLL builds.
// SharpYuvInit() replaces the use of the function pointer.
#undef WEBP_EXTERN
#define WEBP_EXTERN extern
#define VP8GetCPUInfo SharpYuvGetCPUInfo
#include "src/dsp/cpu.h"
#endif // WEBP_SHARPYUV_SHARPYUV_CPU_H_

View File

@ -13,7 +13,7 @@
#include <assert.h>
#include <math.h>
#include <string.h>
#include <stddef.h>
static int ToFixed16(float f) { return (int)floor(f * (1 << 16) + 0.5f); }
@ -22,16 +22,16 @@ void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space,
const float kr = yuv_color_space->kr;
const float kb = yuv_color_space->kb;
const float kg = 1.0f - kr - kb;
const float cr = 0.5f / (1.0f - kb);
const float cb = 0.5f / (1.0f - kr);
const float cb = 0.5f / (1.0f - kb);
const float cr = 0.5f / (1.0f - kr);
const int shift = yuv_color_space->bit_depth - 8;
const float denom = (float)((1 << yuv_color_space->bit_depth) - 1);
float scale_y = 1.0f;
float add_y = 0.0f;
float scale_u = cr;
float scale_v = cb;
float scale_u = cb;
float scale_v = cr;
float add_uv = (float)(128 << shift);
assert(yuv_color_space->bit_depth >= 8);
@ -59,31 +59,35 @@ void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space,
}
// Matrices are in YUV_FIX fixed point precision.
// WebP's matrix, similar but not identical to kRec601LimitedMatrix.
// WebP's matrix, similar but not identical to kRec601LimitedMatrix
// Derived using the following formulas:
// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
static const SharpYuvConversionMatrix kWebpMatrix = {
{16839, 33059, 6420, 16 << 16},
{-9719, -19081, 28800, 128 << 16},
{28800, -24116, -4684, 128 << 16},
};
// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeLimited
// Kr=0.2990f Kb=0.1140f bit_depth=8 range=kSharpYuvRangeLimited
static const SharpYuvConversionMatrix kRec601LimitedMatrix = {
{16829, 33039, 6416, 16 << 16},
{-9714, -19071, 28784, 128 << 16},
{28784, -24103, -4681, 128 << 16},
};
// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeFull
// Kr=0.2990f Kb=0.1140f bit_depth=8 range=kSharpYuvRangeFull
static const SharpYuvConversionMatrix kRec601FullMatrix = {
{19595, 38470, 7471, 0},
{-11058, -21710, 32768, 128 << 16},
{32768, -27439, -5329, 128 << 16},
};
// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeLimited
// Kr=0.2126f Kb=0.0722f bit_depth=8 range=kSharpYuvRangeLimited
static const SharpYuvConversionMatrix kRec709LimitedMatrix = {
{11966, 40254, 4064, 16 << 16},
{-6596, -22189, 28784, 128 << 16},
{28784, -26145, -2639, 128 << 16},
};
// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeFull
// Kr=0.2126f Kb=0.0722f bit_depth=8 range=kSharpYuvRangeFull
static const SharpYuvConversionMatrix kRec709FullMatrix = {
{13933, 46871, 4732, 0},
{-7509, -25259, 32768, 128 << 16},

View File

@ -35,21 +35,27 @@ typedef struct {
} SharpYuvColorSpace;
// Fills in 'matrix' for the given YUVColorSpace.
void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space,
SharpYuvConversionMatrix* matrix);
SHARPYUV_EXTERN void SharpYuvComputeConversionMatrix(
const SharpYuvColorSpace* yuv_color_space,
SharpYuvConversionMatrix* matrix);
// Enums for precomputed conversion matrices.
typedef enum {
// WebP's matrix, similar but not identical to kSharpYuvMatrixRec601Limited
kSharpYuvMatrixWebp = 0,
// Kr=0.2990f Kb=0.1140f bit_depth=8 range=kSharpYuvRangeLimited
kSharpYuvMatrixRec601Limited,
// Kr=0.2990f Kb=0.1140f bit_depth=8 range=kSharpYuvRangeFull
kSharpYuvMatrixRec601Full,
// Kr=0.2126f Kb=0.0722f bit_depth=8 range=kSharpYuvRangeLimited
kSharpYuvMatrixRec709Limited,
// Kr=0.2126f Kb=0.0722f bit_depth=8 range=kSharpYuvRangeFull
kSharpYuvMatrixRec709Full,
kSharpYuvMatrixNum
} SharpYuvMatrixType;
// Returns a pointer to a matrix for one of the predefined colorspaces.
const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
SHARPYUV_EXTERN const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
SharpYuvMatrixType matrix_type);
#ifdef __cplusplus

View File

@ -16,7 +16,8 @@
#include <assert.h>
#include <stdlib.h>
#include "src/dsp/cpu.h"
#include "sharpyuv/sharpyuv_cpu.h"
#include "src/webp/types.h"
//-----------------------------------------------------------------------------
@ -69,29 +70,30 @@ uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst,
int len);
void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out,
int bit_depth);
const uint16_t* best_y, uint16_t* out, int bit_depth);
extern VP8CPUInfo SharpYuvGetCPUInfo;
extern void InitSharpYuvSSE2(void);
extern void InitSharpYuvNEON(void);
void SharpYuvInitDsp(VP8CPUInfo cpu_info_func) {
(void)cpu_info_func;
void SharpYuvInitDsp(void) {
#if !WEBP_NEON_OMIT_C_CODE
SharpYuvUpdateY = SharpYuvUpdateY_C;
SharpYuvUpdateRGB = SharpYuvUpdateRGB_C;
SharpYuvFilterRow = SharpYuvFilterRow_C;
#endif
if (SharpYuvGetCPUInfo != NULL) {
#if defined(WEBP_HAVE_SSE2)
if (cpu_info_func == NULL || cpu_info_func(kSSE2)) {
InitSharpYuvSSE2();
}
if (SharpYuvGetCPUInfo(kSSE2)) {
InitSharpYuvSSE2();
}
#endif // WEBP_HAVE_SSE2
}
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE || cpu_info_func == NULL || cpu_info_func(kNEON)) {
if (WEBP_NEON_OMIT_C_CODE ||
(SharpYuvGetCPUInfo != NULL && SharpYuvGetCPUInfo(kNEON))) {
InitSharpYuvNEON();
}
#endif // WEBP_HAVE_NEON

View File

@ -12,9 +12,8 @@
#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_
#define WEBP_SHARPYUV_SHARPYUV_DSP_H_
#include <stdint.h>
#include "src/dsp/cpu.h"
#include "sharpyuv/sharpyuv_cpu.h"
#include "src/webp/types.h"
extern uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
uint16_t* dst, int len, int bit_depth);
@ -24,6 +23,6 @@ extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out,
int bit_depth);
void SharpYuvInitDsp(VP8CPUInfo cpu_info_func);
void SharpYuvInitDsp(void);
#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_

View File

@ -12,8 +12,8 @@
#include "sharpyuv/sharpyuv_gamma.h"
#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdint.h>
#include "src/webp/types.h"
@ -98,7 +98,7 @@ static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab,
return result;
}
uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
static uint32_t ToLinearSrgb(uint16_t v, int bit_depth) {
const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth;
if (shift > 0) {
return kGammaToLinearTabS[v << shift];
@ -106,9 +106,314 @@ uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0);
}
uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth) {
static uint16_t FromLinearSrgb(uint32_t value, int bit_depth) {
return FixedPointInterpolation(
value, kLinearToGammaTabS,
(GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS),
bit_depth - GAMMA_TO_LINEAR_BITS);
}
////////////////////////////////////////////////////////////////////////////////
#define CLAMP(x, low, high) \
(((x) < (low)) ? (low) : (((high) < (x)) ? (high) : (x)))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
static WEBP_INLINE float Roundf(float x) {
if (x < 0)
return (float)ceil((double)(x - 0.5f));
else
return (float)floor((double)(x + 0.5f));
}
static WEBP_INLINE float Powf(float base, float exp) {
return (float)pow((double)base, (double)exp);
}
static WEBP_INLINE float Log10f(float x) { return (float)log10((double)x); }
static float ToLinear709(float gamma) {
if (gamma < 0.f) {
return 0.f;
} else if (gamma < 4.5f * 0.018053968510807f) {
return gamma / 4.5f;
} else if (gamma < 1.f) {
return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
}
return 1.f;
}
static float FromLinear709(float linear) {
if (linear < 0.f) {
return 0.f;
} else if (linear < 0.018053968510807f) {
return linear * 4.5f;
} else if (linear < 1.f) {
return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
}
return 1.f;
}
static float ToLinear470M(float gamma) {
return Powf(CLAMP(gamma, 0.f, 1.f), 2.2f);
}
static float FromLinear470M(float linear) {
return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.2f);
}
static float ToLinear470Bg(float gamma) {
return Powf(CLAMP(gamma, 0.f, 1.f), 2.8f);
}
static float FromLinear470Bg(float linear) {
return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.8f);
}
static float ToLinearSmpte240(float gamma) {
if (gamma < 0.f) {
return 0.f;
} else if (gamma < 4.f * 0.022821585529445f) {
return gamma / 4.f;
} else if (gamma < 1.f) {
return Powf((gamma + 0.111572195921731f) / 1.111572195921731f, 1.f / 0.45f);
}
return 1.f;
}
static float FromLinearSmpte240(float linear) {
if (linear < 0.f) {
return 0.f;
} else if (linear < 0.022821585529445f) {
return linear * 4.f;
} else if (linear < 1.f) {
return 1.111572195921731f * Powf(linear, 0.45f) - 0.111572195921731f;
}
return 1.f;
}
static float ToLinearLog100(float gamma) {
// The function is non-bijective so choose the middle of [0, 0.01].
const float mid_interval = 0.01f / 2.f;
return (gamma <= 0.0f) ? mid_interval
: Powf(10.0f, 2.f * (MIN(gamma, 1.f) - 1.0f));
}
static float FromLinearLog100(float linear) {
return (linear < 0.01f) ? 0.0f : 1.0f + Log10f(MIN(linear, 1.f)) / 2.0f;
}
static float ToLinearLog100Sqrt10(float gamma) {
// The function is non-bijective so choose the middle of [0, 0.00316227766f[.
const float mid_interval = 0.00316227766f / 2.f;
return (gamma <= 0.0f) ? mid_interval
: Powf(10.0f, 2.5f * (MIN(gamma, 1.f) - 1.0f));
}
static float FromLinearLog100Sqrt10(float linear) {
return (linear < 0.00316227766f) ? 0.0f
: 1.0f + Log10f(MIN(linear, 1.f)) / 2.5f;
}
static float ToLinearIec61966(float gamma) {
if (gamma <= -4.5f * 0.018053968510807f) {
return Powf((-gamma + 0.09929682680944f) / -1.09929682680944f, 1.f / 0.45f);
} else if (gamma < 4.5f * 0.018053968510807f) {
return gamma / 4.5f;
}
return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
}
static float FromLinearIec61966(float linear) {
if (linear <= -0.018053968510807f) {
return -1.09929682680944f * Powf(-linear, 0.45f) + 0.09929682680944f;
} else if (linear < 0.018053968510807f) {
return linear * 4.5f;
}
return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
}
static float ToLinearBt1361(float gamma) {
if (gamma < -0.25f) {
return -0.25f;
} else if (gamma < 0.f) {
return Powf((gamma - 0.02482420670236f) / -0.27482420670236f, 1.f / 0.45f) /
-4.f;
} else if (gamma < 4.5f * 0.018053968510807f) {
return gamma / 4.5f;
} else if (gamma < 1.f) {
return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
}
return 1.f;
}
static float FromLinearBt1361(float linear) {
if (linear < -0.25f) {
return -0.25f;
} else if (linear < 0.f) {
return -0.27482420670236f * Powf(-4.f * linear, 0.45f) + 0.02482420670236f;
} else if (linear < 0.018053968510807f) {
return linear * 4.5f;
} else if (linear < 1.f) {
return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
}
return 1.f;
}
static float ToLinearPq(float gamma) {
if (gamma > 0.f) {
const float pow_gamma = Powf(gamma, 32.f / 2523.f);
const float num = MAX(pow_gamma - 107.f / 128.f, 0.0f);
const float den = MAX(2413.f / 128.f - 2392.f / 128.f * pow_gamma, FLT_MIN);
return Powf(num / den, 4096.f / 653.f);
}
return 0.f;
}
static float FromLinearPq(float linear) {
if (linear > 0.f) {
const float pow_linear = Powf(linear, 653.f / 4096.f);
const float num = 107.f / 128.f + 2413.f / 128.f * pow_linear;
const float den = 1.0f + 2392.f / 128.f * pow_linear;
return Powf(num / den, 2523.f / 32.f);
}
return 0.f;
}
static float ToLinearSmpte428(float gamma) {
return Powf(MAX(gamma, 0.f), 2.6f) / 0.91655527974030934f;
}
static float FromLinearSmpte428(float linear) {
return Powf(0.91655527974030934f * MAX(linear, 0.f), 1.f / 2.6f);
}
// Conversion in BT.2100 requires RGB info. Simplify to gamma correction here.
static float ToLinearHlg(float gamma) {
if (gamma < 0.f) {
return 0.f;
} else if (gamma <= 0.5f) {
return Powf((gamma * gamma) * (1.f / 3.f), 1.2f);
}
return Powf((expf((gamma - 0.55991073f) / 0.17883277f) + 0.28466892f) / 12.0f,
1.2f);
}
static float FromLinearHlg(float linear) {
linear = Powf(linear, 1.f / 1.2f);
if (linear < 0.f) {
return 0.f;
} else if (linear <= (1.f / 12.f)) {
return sqrtf(3.f * linear);
}
return 0.17883277f * logf(12.f * linear - 0.28466892f) + 0.55991073f;
}
uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth,
SharpYuvTransferFunctionType transfer_type) {
float v_float, linear;
if (transfer_type == kSharpYuvTransferFunctionSrgb) {
return ToLinearSrgb(v, bit_depth);
}
v_float = (float)v / ((1 << bit_depth) - 1);
switch (transfer_type) {
case kSharpYuvTransferFunctionBt709:
case kSharpYuvTransferFunctionBt601:
case kSharpYuvTransferFunctionBt2020_10Bit:
case kSharpYuvTransferFunctionBt2020_12Bit:
linear = ToLinear709(v_float);
break;
case kSharpYuvTransferFunctionBt470M:
linear = ToLinear470M(v_float);
break;
case kSharpYuvTransferFunctionBt470Bg:
linear = ToLinear470Bg(v_float);
break;
case kSharpYuvTransferFunctionSmpte240:
linear = ToLinearSmpte240(v_float);
break;
case kSharpYuvTransferFunctionLinear:
return v;
case kSharpYuvTransferFunctionLog100:
linear = ToLinearLog100(v_float);
break;
case kSharpYuvTransferFunctionLog100_Sqrt10:
linear = ToLinearLog100Sqrt10(v_float);
break;
case kSharpYuvTransferFunctionIec61966:
linear = ToLinearIec61966(v_float);
break;
case kSharpYuvTransferFunctionBt1361:
linear = ToLinearBt1361(v_float);
break;
case kSharpYuvTransferFunctionSmpte2084:
linear = ToLinearPq(v_float);
break;
case kSharpYuvTransferFunctionSmpte428:
linear = ToLinearSmpte428(v_float);
break;
case kSharpYuvTransferFunctionHlg:
linear = ToLinearHlg(v_float);
break;
default:
assert(0);
linear = 0;
break;
}
return (uint32_t)Roundf(linear * ((1 << 16) - 1));
}
uint16_t SharpYuvLinearToGamma(uint32_t v, int bit_depth,
SharpYuvTransferFunctionType transfer_type) {
float v_float, linear;
if (transfer_type == kSharpYuvTransferFunctionSrgb) {
return FromLinearSrgb(v, bit_depth);
}
v_float = (float)v / ((1 << 16) - 1);
switch (transfer_type) {
case kSharpYuvTransferFunctionBt709:
case kSharpYuvTransferFunctionBt601:
case kSharpYuvTransferFunctionBt2020_10Bit:
case kSharpYuvTransferFunctionBt2020_12Bit:
linear = FromLinear709(v_float);
break;
case kSharpYuvTransferFunctionBt470M:
linear = FromLinear470M(v_float);
break;
case kSharpYuvTransferFunctionBt470Bg:
linear = FromLinear470Bg(v_float);
break;
case kSharpYuvTransferFunctionSmpte240:
linear = FromLinearSmpte240(v_float);
break;
case kSharpYuvTransferFunctionLinear:
return v;
case kSharpYuvTransferFunctionLog100:
linear = FromLinearLog100(v_float);
break;
case kSharpYuvTransferFunctionLog100_Sqrt10:
linear = FromLinearLog100Sqrt10(v_float);
break;
case kSharpYuvTransferFunctionIec61966:
linear = FromLinearIec61966(v_float);
break;
case kSharpYuvTransferFunctionBt1361:
linear = FromLinearBt1361(v_float);
break;
case kSharpYuvTransferFunctionSmpte2084:
linear = FromLinearPq(v_float);
break;
case kSharpYuvTransferFunctionSmpte428:
linear = FromLinearSmpte428(v_float);
break;
case kSharpYuvTransferFunctionHlg:
linear = FromLinearHlg(v_float);
break;
default:
assert(0);
linear = 0;
break;
}
return (uint16_t)Roundf(linear * ((1 << bit_depth) - 1));
}

View File

@ -12,7 +12,8 @@
#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
#include <stdint.h>
#include "sharpyuv/sharpyuv.h"
#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@ -22,11 +23,13 @@ extern "C" {
// SharpYuvGammaToLinear or SharpYuvLinearToGamma.
void SharpYuvInitGammaTables(void);
// Converts a gamma color value on 'bit_depth' bits to a 16 bit linear value.
uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth);
// Converts a 'bit_depth'-bit gamma color value to a 16-bit linear value.
uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth,
SharpYuvTransferFunctionType transfer_type);
// Converts a 16 bit linear color value to a gamma value on 'bit_depth' bits.
uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth);
// Converts a 16-bit linear color value to a 'bit_depth'-bit gamma value.
uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth,
SharpYuvTransferFunctionType transfer_type);
#ifdef __cplusplus
} // extern "C"

View File

@ -17,11 +17,6 @@
#include <assert.h>
#include <stdlib.h>
#include <arm_neon.h>
#endif
extern void InitSharpYuvNEON(void);
#if defined(WEBP_USE_NEON)
static uint16_t clip_NEON(int v, int max) {
return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
@ -169,6 +164,8 @@ static void SharpYuvFilterRow_NEON(const int16_t* A, const int16_t* B, int len,
//------------------------------------------------------------------------------
extern void InitSharpYuvNEON(void);
WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) {
SharpYuvUpdateY = SharpYuvUpdateY_NEON;
SharpYuvUpdateRGB = SharpYuvUpdateRGB_NEON;
@ -177,6 +174,8 @@ WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) {
#else // !WEBP_USE_NEON
extern void InitSharpYuvNEON(void);
void InitSharpYuvNEON(void) {}
#endif // WEBP_USE_NEON

View File

@ -16,11 +16,6 @@
#if defined(WEBP_USE_SSE2)
#include <stdlib.h>
#include <emmintrin.h>
#endif
extern void InitSharpYuvSSE2(void);
#if defined(WEBP_USE_SSE2)
static uint16_t clip_SSE2(int v, int max) {
return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
@ -199,6 +194,8 @@ WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvSSE2(void) {
}
#else // !WEBP_USE_SSE2
extern void InitSharpYuvSSE2(void);
void InitSharpYuvSSE2(void) {}
#endif // WEBP_USE_SSE2

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:5:1
libwebp_la_LDFLAGS = -no-undefined -version-info 8:10: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:5:1
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:10:1
pkgconfig_DATA += libwebpdecoder.pc
endif

View File

@ -13,18 +13,20 @@
#include <stdlib.h>
#include "src/dec/alphai_dec.h"
#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
#include "src/dsp/dsp.h"
#include "src/utils/quant_levels_dec_utils.h"
#include "src/utils/utils.h"
#include "src/webp/format_constants.h"
#include "src/webp/types.h"
//------------------------------------------------------------------------------
// ALPHDecoder object.
// Allocates a new alpha decoder instance.
static ALPHDecoder* ALPHNew(void) {
WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
return dec;
}
@ -32,8 +34,8 @@ static ALPHDecoder* ALPHNew(void) {
// Clears and deallocates an alpha decoder instance.
static void ALPHDelete(ALPHDecoder* const dec) {
if (dec != NULL) {
VP8LDelete(dec->vp8l_dec_);
dec->vp8l_dec_ = NULL;
VP8LDelete(dec->vp8l_dec);
dec->vp8l_dec = NULL;
WebPSafeFree(dec);
}
}
@ -45,41 +47,43 @@ static void ALPHDelete(ALPHDecoder* const dec) {
// header for alpha data stored using lossless compression.
// Returns false in case of error in alpha header (data too short, invalid
// compression method or filter, error in lossless header data etc).
static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
size_t data_size, const VP8Io* const src_io,
uint8_t* output) {
WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
size_t data_size, const VP8Io* const src_io,
uint8_t* output) {
int ok = 0;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
int rsrv;
VP8Io* const io = &dec->io_;
VP8Io* const io = &dec->io;
assert(data != NULL && output != NULL && src_io != NULL);
VP8FiltersInit();
dec->output_ = output;
dec->width_ = src_io->width;
dec->height_ = src_io->height;
assert(dec->width_ > 0 && dec->height_ > 0);
dec->output = output;
dec->width = src_io->width;
dec->height = src_io->height;
assert(dec->width > 0 && dec->height > 0);
if (data_size <= ALPHA_HEADER_LEN) {
return 0;
}
dec->method_ = (data[0] >> 0) & 0x03;
dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
dec->pre_processing_ = (data[0] >> 4) & 0x03;
dec->method = (data[0] >> 0) & 0x03;
dec->filter = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
dec->pre_processing = (data[0] >> 4) & 0x03;
rsrv = (data[0] >> 6) & 0x03;
if (dec->method_ < ALPHA_NO_COMPRESSION ||
dec->method_ > ALPHA_LOSSLESS_COMPRESSION ||
dec->filter_ >= WEBP_FILTER_LAST ||
dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS ||
if (dec->method < ALPHA_NO_COMPRESSION ||
dec->method > ALPHA_LOSSLESS_COMPRESSION ||
dec->filter >= WEBP_FILTER_LAST ||
dec->pre_processing > ALPHA_PREPROCESSED_LEVELS ||
rsrv != 0) {
return 0;
}
// Copy the necessary parameters from src_io to io
VP8InitIo(io);
if (!VP8InitIo(io)) {
return 0;
}
WebPInitCustomIo(NULL, io);
io->opaque = dec;
io->width = src_io->width;
@ -92,11 +96,11 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
io->crop_bottom = src_io->crop_bottom;
// No need to copy the scaling parameters.
if (dec->method_ == ALPHA_NO_COMPRESSION) {
const size_t alpha_decoded_size = dec->width_ * dec->height_;
if (dec->method == ALPHA_NO_COMPRESSION) {
const size_t alpha_decoded_size = dec->width * dec->height;
ok = (alpha_data_size >= alpha_decoded_size);
} else {
assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION);
assert(dec->method == ALPHA_LOSSLESS_COMPRESSION);
ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);
}
@ -107,76 +111,70 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
// starting from row number 'row'. It assumes that rows up to (row - 1) have
// already been decoded.
// Returns false in case of bitstream error.
static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
ALPHDecoder* const alph_dec = dec->alph_dec_;
const int width = alph_dec->width_;
const int height = alph_dec->io_.crop_bottom;
if (alph_dec->method_ == ALPHA_NO_COMPRESSION) {
WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,
int num_rows) {
ALPHDecoder* const alph_dec = dec->alph_dec;
const int width = alph_dec->width;
const int height = alph_dec->io.crop_bottom;
if (alph_dec->method == ALPHA_NO_COMPRESSION) {
int y;
const uint8_t* prev_line = dec->alpha_prev_line_;
const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width;
uint8_t* dst = dec->alpha_plane_ + row * width;
assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]);
if (alph_dec->filter_ != WEBP_FILTER_NONE) {
assert(WebPUnfilters[alph_dec->filter_] != NULL);
for (y = 0; y < num_rows; ++y) {
WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);
prev_line = dst;
dst += width;
deltas += width;
}
} else {
for (y = 0; y < num_rows; ++y) {
memcpy(dst, deltas, width * sizeof(*dst));
prev_line = dst;
dst += width;
deltas += width;
}
const uint8_t* prev_line = dec->alpha_prev_line;
const uint8_t* deltas = dec->alpha_data + ALPHA_HEADER_LEN + row * width;
uint8_t* dst = dec->alpha_plane + row * width;
assert(deltas <= &dec->alpha_data[dec->alpha_data_size]);
assert(WebPUnfilters[alph_dec->filter] != NULL);
for (y = 0; y < num_rows; ++y) {
WebPUnfilters[alph_dec->filter](prev_line, deltas, dst, width);
prev_line = dst;
dst += width;
deltas += width;
}
dec->alpha_prev_line_ = prev_line;
} else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
assert(alph_dec->vp8l_dec_ != NULL);
dec->alpha_prev_line = prev_line;
} else { // alph_dec->method == ALPHA_LOSSLESS_COMPRESSION
assert(alph_dec->vp8l_dec != NULL);
if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
return 0;
}
}
if (row + num_rows >= height) {
dec->is_alpha_decoded_ = 1;
dec->is_alpha_decoded = 1;
}
return 1;
}
static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,
const VP8Io* const io) {
const int stride = io->width;
const int height = io->crop_bottom;
const uint64_t alpha_size = (uint64_t)stride * height;
assert(dec->alpha_plane_mem_ == NULL);
dec->alpha_plane_mem_ =
(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_));
if (dec->alpha_plane_mem_ == NULL) {
return 0;
assert(dec->alpha_plane_mem == NULL);
dec->alpha_plane_mem =
(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane));
if (dec->alpha_plane_mem == NULL) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"Alpha decoder initialization failed.");
}
dec->alpha_plane_ = dec->alpha_plane_mem_;
dec->alpha_prev_line_ = NULL;
dec->alpha_plane = dec->alpha_plane_mem;
dec->alpha_prev_line = NULL;
return 1;
}
void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
assert(dec != NULL);
WebPSafeFree(dec->alpha_plane_mem_);
dec->alpha_plane_mem_ = NULL;
dec->alpha_plane_ = NULL;
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
WebPSafeFree(dec->alpha_plane_mem);
dec->alpha_plane_mem = NULL;
dec->alpha_plane = NULL;
ALPHDelete(dec->alph_dec);
dec->alph_dec = NULL;
}
//------------------------------------------------------------------------------
// Main entry point.
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
const VP8Io* const io,
int row, int num_rows) {
WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
const VP8Io* const io,
int row, int num_rows) {
const int width = io->width;
const int height = io->crop_bottom;
@ -186,37 +184,46 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
return NULL;
}
if (!dec->is_alpha_decoded_) {
if (dec->alph_dec_ == NULL) { // Initialize decoder.
dec->alph_dec_ = ALPHNew();
if (dec->alph_dec_ == NULL) return NULL;
if (!dec->is_alpha_decoded) {
if (dec->alph_dec == NULL) { // Initialize decoder.
dec->alph_dec = ALPHNew();
if (dec->alph_dec == NULL) {
VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"Alpha decoder initialization failed.");
return NULL;
}
if (!AllocateAlphaPlane(dec, io)) goto Error;
if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
io, dec->alpha_plane_)) {
if (!ALPHInit(dec->alph_dec, dec->alpha_data, dec->alpha_data_size,
io, dec->alpha_plane)) {
VP8LDecoder* const vp8l_dec = dec->alph_dec->vp8l_dec;
VP8SetError(dec,
(vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY
: vp8l_dec->status,
"Alpha decoder initialization failed.");
goto Error;
}
// if we allowed use of alpha dithering, check whether it's needed at all
if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) {
dec->alpha_dithering_ = 0; // disable dithering
if (dec->alph_dec->pre_processing != ALPHA_PREPROCESSED_LEVELS) {
dec->alpha_dithering = 0; // disable dithering
} else {
num_rows = height - row; // decode everything in one pass
}
}
assert(dec->alph_dec_ != NULL);
assert(dec->alph_dec != NULL);
assert(row + num_rows <= height);
if (!ALPHDecode(dec, row, num_rows)) goto Error;
if (dec->is_alpha_decoded_) { // finished?
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
if (dec->alpha_dithering_ > 0) {
uint8_t* const alpha = dec->alpha_plane_ + io->crop_top * width
if (dec->is_alpha_decoded) { // finished?
ALPHDelete(dec->alph_dec);
dec->alph_dec = NULL;
if (dec->alpha_dithering > 0) {
uint8_t* const alpha = dec->alpha_plane + io->crop_top * width
+ io->crop_left;
if (!WebPDequantizeLevels(alpha,
io->crop_right - io->crop_left,
io->crop_bottom - io->crop_top,
width, dec->alpha_dithering_)) {
width, dec->alpha_dithering)) {
goto Error;
}
}
@ -224,7 +231,7 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
}
// Return a pointer to the current decoded row.
return dec->alpha_plane_ + row * width;
return dec->alpha_plane + row * width;
Error:
WebPDeallocateAlphaMemory(dec);

View File

@ -25,24 +25,24 @@ struct VP8LDecoder; // Defined in dec/vp8li.h.
typedef struct ALPHDecoder ALPHDecoder;
struct ALPHDecoder {
int width_;
int height_;
int method_;
WEBP_FILTER_TYPE filter_;
int pre_processing_;
struct VP8LDecoder* vp8l_dec_;
VP8Io io_;
int use_8b_decode_; // Although alpha channel requires only 1 byte per
int width;
int height;
int method;
WEBP_FILTER_TYPE filter;
int pre_processing;
struct VP8LDecoder* vp8l_dec;
VP8Io io;
int use_8b_decode; // Although alpha channel requires only 1 byte per
// pixel, sometimes VP8LDecoder may need to allocate
// 4 bytes per pixel internally during decode.
uint8_t* output_;
const uint8_t* prev_line_; // last output row (or NULL)
uint8_t* output;
const uint8_t* prev_line; // last output row (or NULL)
};
//------------------------------------------------------------------------------
// internal functions. Not public.
// Deallocate memory associated to dec->alpha_plane_ decoding
// Deallocate memory associated to dec->alpha_plane decoding
void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
//------------------------------------------------------------------------------

View File

@ -26,10 +26,9 @@ static const uint8_t kModeBpp[MODE_LAST] = {
4, 4, 4, 2, // pre-multiplied modes
1, 1 };
// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
// Convert to an integer to handle both the unsigned/signed enum cases
// without the need for casting to remove type limit warnings.
static int IsValidColorspace(int webp_csp_mode) {
int IsValidColorspace(int webp_csp_mode) {
return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
}
@ -75,7 +74,7 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
const int stride = abs(buf->stride);
const uint64_t size =
MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
MIN_BUFFER_SIZE((uint64_t)width * kModeBpp[mode], height, stride);
ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL);

View File

@ -51,4 +51,7 @@ enum { MB_FEATURE_TREE_PROBS = 3,
NUM_PROBAS = 11
};
// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
int IsValidColorspace(int webp_csp_mode);
#endif // WEBP_DEC_COMMON_DEC_H_

View File

@ -72,11 +72,11 @@ static void ReconstructRow(const VP8Decoder* const dec,
const VP8ThreadContext* ctx) {
int j;
int mb_x;
const int mb_y = ctx->mb_y_;
const int cache_id = ctx->id_;
uint8_t* const y_dst = dec->yuv_b_ + Y_OFF;
uint8_t* const u_dst = dec->yuv_b_ + U_OFF;
uint8_t* const v_dst = dec->yuv_b_ + V_OFF;
const int mb_y = ctx->mb_y;
const int cache_id = ctx->id;
uint8_t* const y_dst = dec->yuv_b + Y_OFF;
uint8_t* const u_dst = dec->yuv_b + U_OFF;
uint8_t* const v_dst = dec->yuv_b + V_OFF;
// Initialize left-most block.
for (j = 0; j < 16; ++j) {
@ -99,8 +99,8 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
// Reconstruct one row.
for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) {
const VP8MBData* const block = ctx->mb_data_ + mb_x;
for (mb_x = 0; mb_x < dec->mb_w; ++mb_x) {
const VP8MBData* const block = ctx->mb_data + mb_x;
// Rotate in the left samples from previously decoded block. We move four
// pixels at a time for alignment reason, and because of in-loop filter.
@ -115,9 +115,9 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
{
// bring top samples into the cache
VP8TopSamples* const top_yuv = dec->yuv_t_ + mb_x;
const int16_t* const coeffs = block->coeffs_;
uint32_t bits = block->non_zero_y_;
VP8TopSamples* const top_yuv = dec->yuv_t + mb_x;
const int16_t* const coeffs = block->coeffs;
uint32_t bits = block->non_zero_y;
int n;
if (mb_y > 0) {
@ -127,11 +127,11 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
// predict and add residuals
if (block->is_i4x4_) { // 4x4
if (block->is_i4x4) { // 4x4
uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16);
if (mb_y > 0) {
if (mb_x >= dec->mb_w_ - 1) { // on rightmost border
if (mb_x >= dec->mb_w - 1) { // on rightmost border
memset(top_right, top_yuv[0].y[15], sizeof(*top_right));
} else {
memcpy(top_right, top_yuv[1].y, sizeof(*top_right));
@ -143,11 +143,11 @@ static void ReconstructRow(const VP8Decoder* const dec,
// predict and add residuals for all 4x4 blocks in turn.
for (n = 0; n < 16; ++n, bits <<= 2) {
uint8_t* const dst = y_dst + kScan[n];
VP8PredLuma4[block->imodes_[n]](dst);
VP8PredLuma4[block->imodes[n]](dst);
DoTransform(bits, coeffs + n * 16, dst);
}
} else { // 16x16
const int pred_func = CheckMode(mb_x, mb_y, block->imodes_[0]);
const int pred_func = CheckMode(mb_x, mb_y, block->imodes[0]);
VP8PredLuma16[pred_func](y_dst);
if (bits != 0) {
for (n = 0; n < 16; ++n, bits <<= 2) {
@ -157,8 +157,8 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
{
// Chroma
const uint32_t bits_uv = block->non_zero_uv_;
const int pred_func = CheckMode(mb_x, mb_y, block->uvmode_);
const uint32_t bits_uv = block->non_zero_uv;
const int pred_func = CheckMode(mb_x, mb_y, block->uvmode);
VP8PredChroma8[pred_func](u_dst);
VP8PredChroma8[pred_func](v_dst);
DoUVTransform(bits_uv >> 0, coeffs + 16 * 16, u_dst);
@ -166,25 +166,25 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
// stash away top samples for next block
if (mb_y < dec->mb_h_ - 1) {
if (mb_y < dec->mb_h - 1) {
memcpy(top_yuv[0].y, y_dst + 15 * BPS, 16);
memcpy(top_yuv[0].u, u_dst + 7 * BPS, 8);
memcpy(top_yuv[0].v, v_dst + 7 * BPS, 8);
}
}
// Transfer reconstructed samples from yuv_b_ cache to final destination.
// Transfer reconstructed samples from yuv_b cache to final destination.
{
const int y_offset = cache_id * 16 * dec->cache_y_stride_;
const int uv_offset = cache_id * 8 * dec->cache_uv_stride_;
uint8_t* const y_out = dec->cache_y_ + mb_x * 16 + y_offset;
uint8_t* const u_out = dec->cache_u_ + mb_x * 8 + uv_offset;
uint8_t* const v_out = dec->cache_v_ + mb_x * 8 + uv_offset;
const int y_offset = cache_id * 16 * dec->cache_y_stride;
const int uv_offset = cache_id * 8 * dec->cache_uv_stride;
uint8_t* const y_out = dec->cache_y + mb_x * 16 + y_offset;
uint8_t* const u_out = dec->cache_u + mb_x * 8 + uv_offset;
uint8_t* const v_out = dec->cache_v + mb_x * 8 + uv_offset;
for (j = 0; j < 16; ++j) {
memcpy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16);
memcpy(y_out + j * dec->cache_y_stride, y_dst + j * BPS, 16);
}
for (j = 0; j < 8; ++j) {
memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8);
memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8);
memcpy(u_out + j * dec->cache_uv_stride, u_dst + j * BPS, 8);
memcpy(v_out + j * dec->cache_uv_stride, v_dst + j * BPS, 8);
}
}
}
@ -201,40 +201,40 @@ static void ReconstructRow(const VP8Decoder* const dec,
static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 };
static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
const int cache_id = ctx->id_;
const int y_bps = dec->cache_y_stride_;
const VP8FInfo* const f_info = ctx->f_info_ + mb_x;
uint8_t* const y_dst = dec->cache_y_ + cache_id * 16 * y_bps + mb_x * 16;
const int ilevel = f_info->f_ilevel_;
const int limit = f_info->f_limit_;
const VP8ThreadContext* const ctx = &dec->thread_ctx;
const int cache_id = ctx->id;
const int y_bps = dec->cache_y_stride;
const VP8FInfo* const f_info = ctx->f_info + mb_x;
uint8_t* const y_dst = dec->cache_y + cache_id * 16 * y_bps + mb_x * 16;
const int ilevel = f_info->f_ilevel;
const int limit = f_info->f_limit;
if (limit == 0) {
return;
}
assert(limit >= 3);
if (dec->filter_type_ == 1) { // simple
if (dec->filter_type == 1) { // simple
if (mb_x > 0) {
VP8SimpleHFilter16(y_dst, y_bps, limit + 4);
}
if (f_info->f_inner_) {
if (f_info->f_inner) {
VP8SimpleHFilter16i(y_dst, y_bps, limit);
}
if (mb_y > 0) {
VP8SimpleVFilter16(y_dst, y_bps, limit + 4);
}
if (f_info->f_inner_) {
if (f_info->f_inner) {
VP8SimpleVFilter16i(y_dst, y_bps, limit);
}
} else { // complex
const int uv_bps = dec->cache_uv_stride_;
uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8;
uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8;
const int hev_thresh = f_info->hev_thresh_;
const int uv_bps = dec->cache_uv_stride;
uint8_t* const u_dst = dec->cache_u + cache_id * 8 * uv_bps + mb_x * 8;
uint8_t* const v_dst = dec->cache_v + cache_id * 8 * uv_bps + mb_x * 8;
const int hev_thresh = f_info->hev_thresh;
if (mb_x > 0) {
VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
}
if (f_info->f_inner_) {
if (f_info->f_inner) {
VP8HFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh);
VP8HFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
}
@ -242,7 +242,7 @@ static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
VP8VFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
VP8VFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
}
if (f_info->f_inner_) {
if (f_info->f_inner) {
VP8VFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh);
VP8VFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
}
@ -252,9 +252,9 @@ static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
// Filter the decoded macroblock row (if needed)
static void FilterRow(const VP8Decoder* const dec) {
int mb_x;
const int mb_y = dec->thread_ctx_.mb_y_;
assert(dec->thread_ctx_.filter_row_);
for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) {
const int mb_y = dec->thread_ctx.mb_y;
assert(dec->thread_ctx.filter_row);
for (mb_x = dec->tl_mb_x; mb_x < dec->br_mb_x; ++mb_x) {
DoFilter(dec, mb_x, mb_y);
}
}
@ -263,51 +263,51 @@ static void FilterRow(const VP8Decoder* const dec) {
// Precompute the filtering strength for each segment and each i4x4/i16x16 mode.
static void PrecomputeFilterStrengths(VP8Decoder* const dec) {
if (dec->filter_type_ > 0) {
if (dec->filter_type > 0) {
int s;
const VP8FilterHeader* const hdr = &dec->filter_hdr_;
const VP8FilterHeader* const hdr = &dec->filter_hdr;
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
int i4x4;
// First, compute the initial level
int base_level;
if (dec->segment_hdr_.use_segment_) {
base_level = dec->segment_hdr_.filter_strength_[s];
if (!dec->segment_hdr_.absolute_delta_) {
base_level += hdr->level_;
if (dec->segment_hdr.use_segment) {
base_level = dec->segment_hdr.filter_strength[s];
if (!dec->segment_hdr.absolute_delta) {
base_level += hdr->level;
}
} else {
base_level = hdr->level_;
base_level = hdr->level;
}
for (i4x4 = 0; i4x4 <= 1; ++i4x4) {
VP8FInfo* const info = &dec->fstrengths_[s][i4x4];
VP8FInfo* const info = &dec->fstrengths[s][i4x4];
int level = base_level;
if (hdr->use_lf_delta_) {
level += hdr->ref_lf_delta_[0];
if (hdr->use_lf_delta) {
level += hdr->ref_lf_delta[0];
if (i4x4) {
level += hdr->mode_lf_delta_[0];
level += hdr->mode_lf_delta[0];
}
}
level = (level < 0) ? 0 : (level > 63) ? 63 : level;
if (level > 0) {
int ilevel = level;
if (hdr->sharpness_ > 0) {
if (hdr->sharpness_ > 4) {
if (hdr->sharpness > 0) {
if (hdr->sharpness > 4) {
ilevel >>= 2;
} else {
ilevel >>= 1;
}
if (ilevel > 9 - hdr->sharpness_) {
ilevel = 9 - hdr->sharpness_;
if (ilevel > 9 - hdr->sharpness) {
ilevel = 9 - hdr->sharpness;
}
}
if (ilevel < 1) ilevel = 1;
info->f_ilevel_ = ilevel;
info->f_limit_ = 2 * level + ilevel;
info->hev_thresh_ = (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
info->f_ilevel = ilevel;
info->f_limit = 2 * level + ilevel;
info->hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
} else {
info->f_limit_ = 0; // no filtering
info->f_limit = 0; // no filtering
}
info->f_inner_ = i4x4;
info->f_inner = i4x4;
}
}
}
@ -321,7 +321,7 @@ static void PrecomputeFilterStrengths(VP8Decoder* const dec) {
#define DITHER_AMP_TAB_SIZE 12
static const uint8_t kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = {
// roughly, it's dqm->uv_mat_[1]
// roughly, it's dqm->uv_mat[1]
8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1
};
@ -336,24 +336,24 @@ void VP8InitDithering(const WebPDecoderOptions* const options,
int s;
int all_amp = 0;
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
VP8QuantMatrix* const dqm = &dec->dqm_[s];
if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) {
const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_;
dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3;
VP8QuantMatrix* const dqm = &dec->dqm[s];
if (dqm->uv_quant < DITHER_AMP_TAB_SIZE) {
const int idx = (dqm->uv_quant < 0) ? 0 : dqm->uv_quant;
dqm->dither = (f * kQuantToDitherAmp[idx]) >> 3;
}
all_amp |= dqm->dither_;
all_amp |= dqm->dither;
}
if (all_amp != 0) {
VP8InitRandom(&dec->dithering_rg_, 1.0f);
dec->dither_ = 1;
VP8InitRandom(&dec->dithering_rg, 1.0f);
dec->dither = 1;
}
}
// potentially allow alpha dithering
dec->alpha_dithering_ = options->alpha_dithering_strength;
if (dec->alpha_dithering_ > 100) {
dec->alpha_dithering_ = 100;
} else if (dec->alpha_dithering_ < 0) {
dec->alpha_dithering_ = 0;
dec->alpha_dithering = options->alpha_dithering_strength;
if (dec->alpha_dithering > 100) {
dec->alpha_dithering = 100;
} else if (dec->alpha_dithering < 0) {
dec->alpha_dithering = 0;
}
}
}
@ -370,17 +370,17 @@ static void Dither8x8(VP8Random* const rg, uint8_t* dst, int bps, int amp) {
static void DitherRow(VP8Decoder* const dec) {
int mb_x;
assert(dec->dither_);
for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) {
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
const VP8MBData* const data = ctx->mb_data_ + mb_x;
const int cache_id = ctx->id_;
const int uv_bps = dec->cache_uv_stride_;
if (data->dither_ >= MIN_DITHER_AMP) {
uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8;
uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8;
Dither8x8(&dec->dithering_rg_, u_dst, uv_bps, data->dither_);
Dither8x8(&dec->dithering_rg_, v_dst, uv_bps, data->dither_);
assert(dec->dither);
for (mb_x = dec->tl_mb_x; mb_x < dec->br_mb_x; ++mb_x) {
const VP8ThreadContext* const ctx = &dec->thread_ctx;
const VP8MBData* const data = ctx->mb_data + mb_x;
const int cache_id = ctx->id;
const int uv_bps = dec->cache_uv_stride;
if (data->dither >= MIN_DITHER_AMP) {
uint8_t* const u_dst = dec->cache_u + cache_id * 8 * uv_bps + mb_x * 8;
uint8_t* const v_dst = dec->cache_v + cache_id * 8 * uv_bps + mb_x * 8;
Dither8x8(&dec->dithering_rg, u_dst, uv_bps, data->dither);
Dither8x8(&dec->dithering_rg, v_dst, uv_bps, data->dither);
}
}
}
@ -403,29 +403,29 @@ static int FinishRow(void* arg1, void* arg2) {
VP8Decoder* const dec = (VP8Decoder*)arg1;
VP8Io* const io = (VP8Io*)arg2;
int ok = 1;
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
const int cache_id = ctx->id_;
const int extra_y_rows = kFilterExtraRows[dec->filter_type_];
const int ysize = extra_y_rows * dec->cache_y_stride_;
const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_;
const int y_offset = cache_id * 16 * dec->cache_y_stride_;
const int uv_offset = cache_id * 8 * dec->cache_uv_stride_;
uint8_t* const ydst = dec->cache_y_ - ysize + y_offset;
uint8_t* const udst = dec->cache_u_ - uvsize + uv_offset;
uint8_t* const vdst = dec->cache_v_ - uvsize + uv_offset;
const int mb_y = ctx->mb_y_;
const VP8ThreadContext* const ctx = &dec->thread_ctx;
const int cache_id = ctx->id;
const int extra_y_rows = kFilterExtraRows[dec->filter_type];
const int ysize = extra_y_rows * dec->cache_y_stride;
const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride;
const int y_offset = cache_id * 16 * dec->cache_y_stride;
const int uv_offset = cache_id * 8 * dec->cache_uv_stride;
uint8_t* const ydst = dec->cache_y - ysize + y_offset;
uint8_t* const udst = dec->cache_u - uvsize + uv_offset;
uint8_t* const vdst = dec->cache_v - uvsize + uv_offset;
const int mb_y = ctx->mb_y;
const int is_first_row = (mb_y == 0);
const int is_last_row = (mb_y >= dec->br_mb_y_ - 1);
const int is_last_row = (mb_y >= dec->br_mb_y - 1);
if (dec->mt_method_ == 2) {
if (dec->mt_method == 2) {
ReconstructRow(dec, ctx);
}
if (ctx->filter_row_) {
if (ctx->filter_row) {
FilterRow(dec);
}
if (dec->dither_) {
if (dec->dither) {
DitherRow(dec);
}
@ -438,9 +438,9 @@ static int FinishRow(void* arg1, void* arg2) {
io->u = udst;
io->v = vdst;
} else {
io->y = dec->cache_y_ + y_offset;
io->u = dec->cache_u_ + uv_offset;
io->v = dec->cache_v_ + uv_offset;
io->y = dec->cache_y + y_offset;
io->u = dec->cache_u + uv_offset;
io->v = dec->cache_v + uv_offset;
}
if (!is_last_row) {
@ -449,9 +449,9 @@ static int FinishRow(void* arg1, void* arg2) {
if (y_end > io->crop_bottom) {
y_end = io->crop_bottom; // make sure we don't overflow on last row.
}
// If dec->alpha_data_ is not NULL, we have some alpha plane present.
// If dec->alpha_data is not NULL, we have some alpha plane present.
io->a = NULL;
if (dec->alpha_data_ != NULL && y_start < y_end) {
if (dec->alpha_data != NULL && y_start < y_end) {
io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start);
if (io->a == NULL) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
@ -462,9 +462,9 @@ static int FinishRow(void* arg1, void* arg2) {
const int delta_y = io->crop_top - y_start;
y_start = io->crop_top;
assert(!(delta_y & 1));
io->y += dec->cache_y_stride_ * delta_y;
io->u += dec->cache_uv_stride_ * (delta_y >> 1);
io->v += dec->cache_uv_stride_ * (delta_y >> 1);
io->y += dec->cache_y_stride * delta_y;
io->u += dec->cache_uv_stride * (delta_y >> 1);
io->v += dec->cache_uv_stride * (delta_y >> 1);
if (io->a != NULL) {
io->a += io->width * delta_y;
}
@ -483,11 +483,11 @@ static int FinishRow(void* arg1, void* arg2) {
}
}
// rotate top samples if needed
if (cache_id + 1 == dec->num_caches_) {
if (cache_id + 1 == dec->num_caches) {
if (!is_last_row) {
memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize);
memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize);
memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize);
memcpy(dec->cache_y - ysize, ydst + 16 * dec->cache_y_stride, ysize);
memcpy(dec->cache_u - uvsize, udst + 8 * dec->cache_uv_stride, uvsize);
memcpy(dec->cache_v - uvsize, vdst + 8 * dec->cache_uv_stride, uvsize);
}
}
@ -500,43 +500,43 @@ static int FinishRow(void* arg1, void* arg2) {
int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) {
int ok = 1;
VP8ThreadContext* const ctx = &dec->thread_ctx_;
VP8ThreadContext* const ctx = &dec->thread_ctx;
const int filter_row =
(dec->filter_type_ > 0) &&
(dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_);
if (dec->mt_method_ == 0) {
// ctx->id_ and ctx->f_info_ are already set
ctx->mb_y_ = dec->mb_y_;
ctx->filter_row_ = filter_row;
(dec->filter_type > 0) &&
(dec->mb_y >= dec->tl_mb_y) && (dec->mb_y <= dec->br_mb_y);
if (dec->mt_method == 0) {
// ctx->id and ctx->f_info are already set
ctx->mb_y = dec->mb_y;
ctx->filter_row = filter_row;
ReconstructRow(dec, ctx);
ok = FinishRow(dec, io);
} else {
WebPWorker* const worker = &dec->worker_;
WebPWorker* const worker = &dec->worker;
// Finish previous job *before* updating context
ok &= WebPGetWorkerInterface()->Sync(worker);
assert(worker->status_ == OK);
assert(worker->status == OK);
if (ok) { // spawn a new deblocking/output job
ctx->io_ = *io;
ctx->id_ = dec->cache_id_;
ctx->mb_y_ = dec->mb_y_;
ctx->filter_row_ = filter_row;
if (dec->mt_method_ == 2) { // swap macroblock data
VP8MBData* const tmp = ctx->mb_data_;
ctx->mb_data_ = dec->mb_data_;
dec->mb_data_ = tmp;
ctx->io = *io;
ctx->id = dec->cache_id;
ctx->mb_y = dec->mb_y;
ctx->filter_row = filter_row;
if (dec->mt_method == 2) { // swap macroblock data
VP8MBData* const tmp = ctx->mb_data;
ctx->mb_data = dec->mb_data;
dec->mb_data = tmp;
} else {
// perform reconstruction directly in main thread
ReconstructRow(dec, ctx);
}
if (filter_row) { // swap filter info
VP8FInfo* const tmp = ctx->f_info_;
ctx->f_info_ = dec->f_info_;
dec->f_info_ = tmp;
VP8FInfo* const tmp = ctx->f_info;
ctx->f_info = dec->f_info;
dec->f_info = tmp;
}
// (reconstruct)+filter in parallel
WebPGetWorkerInterface()->Launch(worker);
if (++dec->cache_id_ == dec->num_caches_) {
dec->cache_id_ = 0;
if (++dec->cache_id == dec->num_caches) {
dec->cache_id = 0;
}
}
}
@ -551,12 +551,12 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
// Note: Afterward, we must call teardown() no matter what.
if (io->setup != NULL && !io->setup(io)) {
VP8SetError(dec, VP8_STATUS_USER_ABORT, "Frame setup failed");
return dec->status_;
return dec->status;
}
// Disable filtering per user request
if (io->bypass_filtering) {
dec->filter_type_ = 0;
dec->filter_type = 0;
}
// Define the area where we can skip in-loop filtering, in case of cropping.
@ -569,29 +569,29 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
// top-left corner of the picture (MB #0). We must filter all the previous
// macroblocks.
{
const int extra_pixels = kFilterExtraRows[dec->filter_type_];
if (dec->filter_type_ == 2) {
const int extra_pixels = kFilterExtraRows[dec->filter_type];
if (dec->filter_type == 2) {
// For complex filter, we need to preserve the dependency chain.
dec->tl_mb_x_ = 0;
dec->tl_mb_y_ = 0;
dec->tl_mb_x = 0;
dec->tl_mb_y = 0;
} else {
// For simple filter, we can filter only the cropped region.
// We include 'extra_pixels' on the other side of the boundary, since
// vertical or horizontal filtering of the previous macroblock can
// modify some abutting pixels.
dec->tl_mb_x_ = (io->crop_left - extra_pixels) >> 4;
dec->tl_mb_y_ = (io->crop_top - extra_pixels) >> 4;
if (dec->tl_mb_x_ < 0) dec->tl_mb_x_ = 0;
if (dec->tl_mb_y_ < 0) dec->tl_mb_y_ = 0;
dec->tl_mb_x = (io->crop_left - extra_pixels) >> 4;
dec->tl_mb_y = (io->crop_top - extra_pixels) >> 4;
if (dec->tl_mb_x < 0) dec->tl_mb_x = 0;
if (dec->tl_mb_y < 0) dec->tl_mb_y = 0;
}
// We need some 'extra' pixels on the right/bottom.
dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4;
dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4;
if (dec->br_mb_x_ > dec->mb_w_) {
dec->br_mb_x_ = dec->mb_w_;
dec->br_mb_y = (io->crop_bottom + 15 + extra_pixels) >> 4;
dec->br_mb_x = (io->crop_right + 15 + extra_pixels) >> 4;
if (dec->br_mb_x > dec->mb_w) {
dec->br_mb_x = dec->mb_w;
}
if (dec->br_mb_y_ > dec->mb_h_) {
dec->br_mb_y_ = dec->mb_h_;
if (dec->br_mb_y > dec->mb_h) {
dec->br_mb_y = dec->mb_h;
}
}
PrecomputeFilterStrengths(dec);
@ -600,8 +600,8 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
int ok = 1;
if (dec->mt_method_ > 0) {
ok = WebPGetWorkerInterface()->Sync(&dec->worker_);
if (dec->mt_method > 0) {
ok = WebPGetWorkerInterface()->Sync(&dec->worker);
}
if (io->teardown != NULL) {
@ -639,20 +639,20 @@ int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
// Initialize multi/single-thread worker
static int InitThreadContext(VP8Decoder* const dec) {
dec->cache_id_ = 0;
if (dec->mt_method_ > 0) {
WebPWorker* const worker = &dec->worker_;
dec->cache_id = 0;
if (dec->mt_method > 0) {
WebPWorker* const worker = &dec->worker;
if (!WebPGetWorkerInterface()->Reset(worker)) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"thread initialization failed.");
}
worker->data1 = dec;
worker->data2 = (void*)&dec->thread_ctx_.io_;
worker->data2 = (void*)&dec->thread_ctx.io;
worker->hook = FinishRow;
dec->num_caches_ =
(dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
dec->num_caches =
(dec->filter_type > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
} else {
dec->num_caches_ = ST_CACHE_LINES;
dec->num_caches = ST_CACHE_LINES;
}
return 1;
}
@ -680,25 +680,25 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
// Memory setup
static int AllocateMemory(VP8Decoder* const dec) {
const int num_caches = dec->num_caches_;
const int mb_w = dec->mb_w_;
const int num_caches = dec->num_caches;
const int mb_w = dec->mb_w;
// Note: we use 'size_t' when there's no overflow risk, uint64_t otherwise.
const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t);
const size_t top_size = sizeof(VP8TopSamples) * mb_w;
const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB);
const size_t f_info_size =
(dec->filter_type_ > 0) ?
mb_w * (dec->mt_method_ > 0 ? 2 : 1) * sizeof(VP8FInfo)
(dec->filter_type > 0) ?
mb_w * (dec->mt_method > 0 ? 2 : 1) * sizeof(VP8FInfo)
: 0;
const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_);
const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b);
const size_t mb_data_size =
(dec->mt_method_ == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data_);
(dec->mt_method == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data);
const size_t cache_height = (16 * num_caches
+ kFilterExtraRows[dec->filter_type_]) * 3 / 2;
+ kFilterExtraRows[dec->filter_type]) * 3 / 2;
const size_t cache_size = top_size * cache_height;
// alpha_size is the only one that scales as width x height.
const uint64_t alpha_size = (dec->alpha_data_ != NULL) ?
(uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL;
const uint64_t alpha_size = (dec->alpha_data != NULL) ?
(uint64_t)dec->pic_hdr.width * dec->pic_hdr.height : 0ULL;
const uint64_t needed = (uint64_t)intra_pred_mode_size
+ top_size + mb_info_size + f_info_size
+ yuv_size + mb_data_size
@ -706,77 +706,77 @@ static int AllocateMemory(VP8Decoder* const dec) {
uint8_t* mem;
if (!CheckSizeOverflow(needed)) return 0; // check for overflow
if (needed > dec->mem_size_) {
WebPSafeFree(dec->mem_);
dec->mem_size_ = 0;
dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t));
if (dec->mem_ == NULL) {
if (needed > dec->mem_size) {
WebPSafeFree(dec->mem);
dec->mem_size = 0;
dec->mem = WebPSafeMalloc(needed, sizeof(uint8_t));
if (dec->mem == NULL) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"no memory during frame initialization.");
}
// down-cast is ok, thanks to WebPSafeMalloc() above.
dec->mem_size_ = (size_t)needed;
dec->mem_size = (size_t)needed;
}
mem = (uint8_t*)dec->mem_;
dec->intra_t_ = mem;
mem = (uint8_t*)dec->mem;
dec->intra_t = mem;
mem += intra_pred_mode_size;
dec->yuv_t_ = (VP8TopSamples*)mem;
dec->yuv_t = (VP8TopSamples*)mem;
mem += top_size;
dec->mb_info_ = ((VP8MB*)mem) + 1;
dec->mb_info = ((VP8MB*)mem) + 1;
mem += mb_info_size;
dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL;
dec->f_info = f_info_size ? (VP8FInfo*)mem : NULL;
mem += f_info_size;
dec->thread_ctx_.id_ = 0;
dec->thread_ctx_.f_info_ = dec->f_info_;
if (dec->filter_type_ > 0 && dec->mt_method_ > 0) {
dec->thread_ctx.id = 0;
dec->thread_ctx.f_info = dec->f_info;
if (dec->filter_type > 0 && dec->mt_method > 0) {
// secondary cache line. The deblocking process need to make use of the
// filtering strength from previous macroblock row, while the new ones
// are being decoded in parallel. We'll just swap the pointers.
dec->thread_ctx_.f_info_ += mb_w;
dec->thread_ctx.f_info += mb_w;
}
mem = (uint8_t*)WEBP_ALIGN(mem);
assert((yuv_size & WEBP_ALIGN_CST) == 0);
dec->yuv_b_ = mem;
dec->yuv_b = mem;
mem += yuv_size;
dec->mb_data_ = (VP8MBData*)mem;
dec->thread_ctx_.mb_data_ = (VP8MBData*)mem;
if (dec->mt_method_ == 2) {
dec->thread_ctx_.mb_data_ += mb_w;
dec->mb_data = (VP8MBData*)mem;
dec->thread_ctx.mb_data = (VP8MBData*)mem;
if (dec->mt_method == 2) {
dec->thread_ctx.mb_data += mb_w;
}
mem += mb_data_size;
dec->cache_y_stride_ = 16 * mb_w;
dec->cache_uv_stride_ = 8 * mb_w;
dec->cache_y_stride = 16 * mb_w;
dec->cache_uv_stride = 8 * mb_w;
{
const int extra_rows = kFilterExtraRows[dec->filter_type_];
const int extra_y = extra_rows * dec->cache_y_stride_;
const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
dec->cache_y_ = mem + extra_y;
dec->cache_u_ = dec->cache_y_
+ 16 * num_caches * dec->cache_y_stride_ + extra_uv;
dec->cache_v_ = dec->cache_u_
+ 8 * num_caches * dec->cache_uv_stride_ + extra_uv;
dec->cache_id_ = 0;
const int extra_rows = kFilterExtraRows[dec->filter_type];
const int extra_y = extra_rows * dec->cache_y_stride;
const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride;
dec->cache_y = mem + extra_y;
dec->cache_u = dec->cache_y
+ 16 * num_caches * dec->cache_y_stride + extra_uv;
dec->cache_v = dec->cache_u
+ 8 * num_caches * dec->cache_uv_stride + extra_uv;
dec->cache_id = 0;
}
mem += cache_size;
// alpha plane
dec->alpha_plane_ = alpha_size ? mem : NULL;
dec->alpha_plane = alpha_size ? mem : NULL;
mem += alpha_size;
assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);
assert(mem <= (uint8_t*)dec->mem + dec->mem_size);
// note: left/top-info is initialized once for all.
memset(dec->mb_info_ - 1, 0, mb_info_size);
memset(dec->mb_info - 1, 0, mb_info_size);
VP8InitScanline(dec); // initialize left too.
// initialize top
memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
memset(dec->intra_t, B_DC_PRED, intra_pred_mode_size);
return 1;
}
@ -784,16 +784,16 @@ static int AllocateMemory(VP8Decoder* const dec) {
static void InitIo(VP8Decoder* const dec, VP8Io* io) {
// prepare 'io'
io->mb_y = 0;
io->y = dec->cache_y_;
io->u = dec->cache_u_;
io->v = dec->cache_v_;
io->y_stride = dec->cache_y_stride_;
io->uv_stride = dec->cache_uv_stride_;
io->y = dec->cache_y;
io->u = dec->cache_u;
io->v = dec->cache_v;
io->y_stride = dec->cache_y_stride;
io->uv_stride = dec->cache_uv_stride;
io->a = NULL;
}
int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io) {
if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_.
if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches.
if (!AllocateMemory(dec)) return 0;
InitIo(dec, io);
VP8DspInit(); // Init critical function pointers and look-up tables.

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,9 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "src/dec/vp8i_dec.h"
#include "src/dec/webpi_dec.h"
#include "src/dsp/dsp.h"
@ -25,9 +27,9 @@
static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
WebPDecBuffer* output = p->output;
const WebPYUVABuffer* const buf = &output->u.YUVA;
uint8_t* const y_dst = buf->y + (size_t)io->mb_y * buf->y_stride;
uint8_t* const u_dst = buf->u + (size_t)(io->mb_y >> 1) * buf->u_stride;
uint8_t* const v_dst = buf->v + (size_t)(io->mb_y >> 1) * buf->v_stride;
uint8_t* const y_dst = buf->y + (ptrdiff_t)io->mb_y * buf->y_stride;
uint8_t* const u_dst = buf->u + (ptrdiff_t)(io->mb_y >> 1) * buf->u_stride;
uint8_t* const v_dst = buf->v + (ptrdiff_t)(io->mb_y >> 1) * buf->v_stride;
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
const int uv_w = (mb_w + 1) / 2;
@ -42,7 +44,7 @@ static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
WebPDecBuffer* const output = p->output;
WebPRGBABuffer* const buf = &output->u.RGBA;
uint8_t* const dst = buf->rgba + (size_t)io->mb_y * buf->stride;
uint8_t* const dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride;
WebPSamplerProcessPlane(io->y, io->y_stride,
io->u, io->v, io->uv_stride,
dst, buf->stride, io->mb_w, io->mb_h,
@ -57,7 +59,7 @@ static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
int num_lines_out = io->mb_h; // a priori guess
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* dst = buf->rgba + (size_t)io->mb_y * buf->stride;
uint8_t* dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride;
WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
const uint8_t* cur_y = io->y;
const uint8_t* cur_u = io->u;
@ -128,7 +130,7 @@ static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
uint8_t* dst = buf->a + (size_t)io->mb_y * buf->a_stride;
uint8_t* dst = buf->a + (ptrdiff_t)io->mb_y * buf->a_stride;
int j;
(void)expected_num_lines_out;
assert(expected_num_lines_out == mb_h);
@ -181,8 +183,8 @@ static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
int num_rows;
const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride;
uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3);
const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w,
num_rows, dst, buf->stride);
@ -205,8 +207,8 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
int num_rows;
const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride;
#if (WEBP_SWAP_16BIT_CSP == 1)
uint8_t* alpha_dst = base_rgba;
#else
@ -257,7 +259,7 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
// Before rescaling, we premultiply the luma directly into the io->y
// internal buffer. This is OK since these samples are not used for
// intra-prediction (the top samples are saved in cache_y_/u_/v_).
// intra-prediction (the top samples are saved in cache_y/u/v).
// But we need to cast the const away, though.
WebPMultRows((uint8_t*)io->y, io->y_stride,
io->a, io->width, io->mb_w, mb_h, 0);
@ -271,9 +273,9 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
int expected_num_lines_out) {
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
uint8_t* const dst_a = buf->a + (size_t)p->last_y * buf->a_stride;
uint8_t* const dst_a = buf->a + (ptrdiff_t)p->last_y * buf->a_stride;
if (io->a != NULL) {
uint8_t* const dst_y = buf->y + (size_t)p->last_y * buf->y_stride;
uint8_t* const dst_y = buf->y + (ptrdiff_t)p->last_y * buf->y_stride;
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a);
assert(expected_num_lines_out == num_lines_out);
if (num_lines_out > 0) { // unmultiply the Y
@ -362,7 +364,7 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
const WebPYUV444Converter convert =
WebPYUV444Converters[p->output->colorspace];
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* dst = buf->rgba + (size_t)y_pos * buf->stride;
uint8_t* dst = buf->rgba + (ptrdiff_t)y_pos * buf->stride;
int num_lines_out = 0;
// For RGB rescaling, because of the YUV420, current scan position
// U/V can be +1/-1 line from the Y one. Hence the double test.
@ -389,14 +391,14 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
while (j < mb_h) {
const int y_lines_in =
WebPRescalerImport(p->scaler_y, mb_h - j,
io->y + (size_t)j * io->y_stride, io->y_stride);
io->y + (ptrdiff_t)j * io->y_stride, io->y_stride);
j += y_lines_in;
if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) {
const int u_lines_in = WebPRescalerImport(
p->scaler_u, uv_mb_h - uv_j, io->u + (size_t)uv_j * io->uv_stride,
p->scaler_u, uv_mb_h - uv_j, io->u + (ptrdiff_t)uv_j * io->uv_stride,
io->uv_stride);
const int v_lines_in = WebPRescalerImport(
p->scaler_v, uv_mb_h - uv_j, io->v + (size_t)uv_j * io->uv_stride,
p->scaler_v, uv_mb_h - uv_j, io->v + (ptrdiff_t)uv_j * io->uv_stride,
io->uv_stride);
(void)v_lines_in; // remove a gcc warning
assert(u_lines_in == v_lines_in);
@ -409,7 +411,7 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride;
uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride;
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int alpha_first =
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
@ -437,7 +439,7 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride;
uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride;
#if (WEBP_SWAP_16BIT_CSP == 1)
uint8_t* alpha_dst = base_rgba;
#else
@ -476,7 +478,7 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
int lines_left = expected_num_out_lines;
const int y_end = p->last_y + lines_left;
while (lines_left > 0) {
const int64_t row_offset = (int64_t)scaler->src_y - io->mb_y;
const int64_t row_offset = (ptrdiff_t)scaler->src_y - io->mb_y;
WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y,
io->a + row_offset * io->width, io->width);
lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left);

View File

@ -60,7 +60,7 @@ static const uint16_t kAcTable[128] = {
// Paragraph 9.6
void VP8ParseQuant(VP8Decoder* const dec) {
VP8BitReader* const br = &dec->br_;
VP8BitReader* const br = &dec->br;
const int base_q0 = VP8GetValue(br, 7, "global-header");
const int dqy1_dc = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 4, "global-header") : 0;
@ -73,40 +73,40 @@ void VP8ParseQuant(VP8Decoder* const dec) {
const int dquv_ac = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 4, "global-header") : 0;
const VP8SegmentHeader* const hdr = &dec->segment_hdr_;
const VP8SegmentHeader* const hdr = &dec->segment_hdr;
int i;
for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
int q;
if (hdr->use_segment_) {
q = hdr->quantizer_[i];
if (!hdr->absolute_delta_) {
if (hdr->use_segment) {
q = hdr->quantizer[i];
if (!hdr->absolute_delta) {
q += base_q0;
}
} else {
if (i > 0) {
dec->dqm_[i] = dec->dqm_[0];
dec->dqm[i] = dec->dqm[0];
continue;
} else {
q = base_q0;
}
}
{
VP8QuantMatrix* const m = &dec->dqm_[i];
m->y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)];
m->y1_mat_[1] = kAcTable[clip(q + 0, 127)];
VP8QuantMatrix* const m = &dec->dqm[i];
m->y1_mat[0] = kDcTable[clip(q + dqy1_dc, 127)];
m->y1_mat[1] = kAcTable[clip(q + 0, 127)];
m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2;
m->y2_mat[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2;
// For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16.
// The smallest precision for that is '(x*6349) >> 12' but 16 is a good
// word size.
m->y2_mat_[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16;
if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8;
m->y2_mat[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16;
if (m->y2_mat[1] < 8) m->y2_mat[1] = 8;
m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)];
m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)];
m->uv_mat[0] = kDcTable[clip(q + dquv_dc, 117)];
m->uv_mat[1] = kAcTable[clip(q + dquv_ac, 127)];
m->uv_quant_ = q + dquv_ac; // for dithering strength evaluation
m->uv_quant = q + dquv_ac; // for dithering strength evaluation
}
}
}

View File

@ -12,10 +12,12 @@
// Author: Skal (pascal.massimino@gmail.com)
#include "src/dec/vp8i_dec.h"
#include "src/dsp/cpu.h"
#include "src/utils/bit_reader_inl_utils.h"
#if !defined(USE_GENERIC_TREE)
#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
#if !defined(__arm__) && !defined(_M_ARM) && !WEBP_AARCH64 && \
!defined(__wasm__)
// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then.
#define USE_GENERIC_TREE 1 // ALTERNATE_CODE
#else
@ -282,40 +284,40 @@ static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
};
void VP8ResetProba(VP8Proba* const proba) {
memset(proba->segments_, 255u, sizeof(proba->segments_));
// proba->bands_[][] is initialized later
memset(proba->segments, 255u, sizeof(proba->segments));
// proba->bands[][] is initialized later
}
static void ParseIntraMode(VP8BitReader* const br,
VP8Decoder* const dec, int mb_x) {
uint8_t* const top = dec->intra_t_ + 4 * mb_x;
uint8_t* const left = dec->intra_l_;
VP8MBData* const block = dec->mb_data_ + mb_x;
uint8_t* const top = dec->intra_t + 4 * mb_x;
uint8_t* const left = dec->intra_l;
VP8MBData* const block = dec->mb_data + mb_x;
// Note: we don't save segment map (yet), as we don't expect
// to decode more than 1 keyframe.
if (dec->segment_hdr_.update_map_) {
if (dec->segment_hdr.update_map) {
// Hardcoded tree parsing
block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0], "segments")
? VP8GetBit(br, dec->proba_.segments_[1], "segments")
: VP8GetBit(br, dec->proba_.segments_[2], "segments") + 2;
block->segment = !VP8GetBit(br, dec->proba.segments[0], "segments")
? VP8GetBit(br, dec->proba.segments[1], "segments")
: VP8GetBit(br, dec->proba.segments[2], "segments") + 2;
} else {
block->segment_ = 0; // default for intra
block->segment = 0; // default for intra
}
if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_, "skip");
if (dec->use_skip_proba) block->skip = VP8GetBit(br, dec->skip_p, "skip");
block->is_i4x4_ = !VP8GetBit(br, 145, "block-size");
if (!block->is_i4x4_) {
block->is_i4x4 = !VP8GetBit(br, 145, "block-size");
if (!block->is_i4x4) {
// Hardcoded 16x16 intra-mode decision tree.
const int ymode =
VP8GetBit(br, 156, "pred-modes") ?
(VP8GetBit(br, 128, "pred-modes") ? TM_PRED : H_PRED) :
(VP8GetBit(br, 163, "pred-modes") ? V_PRED : DC_PRED);
block->imodes_[0] = ymode;
block->imodes[0] = ymode;
memset(top, ymode, 4 * sizeof(*top));
memset(left, ymode, 4 * sizeof(*left));
} else {
uint8_t* modes = block->imodes_;
uint8_t* modes = block->imodes;
int y;
for (y = 0; y < 4; ++y) {
int ymode = left[y];
@ -352,17 +354,17 @@ static void ParseIntraMode(VP8BitReader* const br,
}
}
// Hardcoded UVMode decision tree
block->uvmode_ = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED
: !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED
: VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED;
block->uvmode = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED
: !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED
: VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED;
}
int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) {
int mb_x;
for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) {
for (mb_x = 0; mb_x < dec->mb_w; ++mb_x) {
ParseIntraMode(br, dec, mb_x);
}
return !dec->br_.eof_;
return !dec->br.eof;
}
//------------------------------------------------------------------------------
@ -512,7 +514,7 @@ static const uint8_t kBands[16 + 1] = {
};
void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
VP8Proba* const proba = &dec->proba_;
VP8Proba* const proba = &dec->proba;
int t, b, c, p;
for (t = 0; t < NUM_TYPES; ++t) {
for (b = 0; b < NUM_BANDS; ++b) {
@ -522,16 +524,16 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
VP8GetBit(br, CoeffsUpdateProba[t][b][c][p], "global-header") ?
VP8GetValue(br, 8, "global-header") :
CoeffsProba0[t][b][c][p];
proba->bands_[t][b].probas_[c][p] = v;
proba->bands[t][b].probas[c][p] = v;
}
}
}
for (b = 0; b < 16 + 1; ++b) {
proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]];
proba->bands_ptr[t][b] = &proba->bands[t][kBands[b]];
}
}
dec->use_skip_proba_ = VP8Get(br, "global-header");
if (dec->use_skip_proba_) {
dec->skip_p_ = VP8GetValue(br, 8, "global-header");
dec->use_skip_proba = VP8Get(br, "global-header");
if (dec->use_skip_proba) {
dec->skip_p = VP8GetValue(br, 8, "global-header");
}
}

View File

@ -40,8 +40,8 @@ static void InitGetCoeffs(void);
// VP8Decoder
static void SetOk(VP8Decoder* const dec) {
dec->status_ = VP8_STATUS_OK;
dec->error_msg_ = "OK";
dec->status = VP8_STATUS_OK;
dec->error_msg = "OK";
}
int VP8InitIoInternal(VP8Io* const io, int version) {
@ -58,9 +58,9 @@ VP8Decoder* VP8New(void) {
VP8Decoder* const dec = (VP8Decoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec != NULL) {
SetOk(dec);
WebPGetWorkerInterface()->Init(&dec->worker_);
dec->ready_ = 0;
dec->num_parts_minus_one_ = 0;
WebPGetWorkerInterface()->Init(&dec->worker);
dec->ready = 0;
dec->num_parts_minus_one = 0;
InitGetCoeffs();
}
return dec;
@ -68,13 +68,13 @@ VP8Decoder* VP8New(void) {
VP8StatusCode VP8Status(VP8Decoder* const dec) {
if (!dec) return VP8_STATUS_INVALID_PARAM;
return dec->status_;
return dec->status;
}
const char* VP8StatusMessage(VP8Decoder* const dec) {
if (dec == NULL) return "no object";
if (!dec->error_msg_) return "OK";
return dec->error_msg_;
if (!dec->error_msg) return "OK";
return dec->error_msg;
}
void VP8Delete(VP8Decoder* const dec) {
@ -86,11 +86,13 @@ void VP8Delete(VP8Decoder* const dec) {
int VP8SetError(VP8Decoder* const dec,
VP8StatusCode error, const char* const msg) {
// VP8_STATUS_SUSPENDED is only meaningful in incremental decoding.
assert(dec->incremental || error != VP8_STATUS_SUSPENDED);
// The oldest error reported takes precedence over the new one.
if (dec->status_ == VP8_STATUS_OK) {
dec->status_ = error;
dec->error_msg_ = msg;
dec->ready_ = 0;
if (dec->status == VP8_STATUS_OK) {
dec->status = error;
dec->error_msg = msg;
dec->ready = 0;
}
return 0;
}
@ -149,11 +151,11 @@ int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
static void ResetSegmentHeader(VP8SegmentHeader* const hdr) {
assert(hdr != NULL);
hdr->use_segment_ = 0;
hdr->update_map_ = 0;
hdr->absolute_delta_ = 1;
memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_));
memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_));
hdr->use_segment = 0;
hdr->update_map = 0;
hdr->absolute_delta = 1;
memset(hdr->quantizer, 0, sizeof(hdr->quantizer));
memset(hdr->filter_strength, 0, sizeof(hdr->filter_strength));
}
// Paragraph 9.3
@ -161,46 +163,46 @@ static int ParseSegmentHeader(VP8BitReader* br,
VP8SegmentHeader* hdr, VP8Proba* proba) {
assert(br != NULL);
assert(hdr != NULL);
hdr->use_segment_ = VP8Get(br, "global-header");
if (hdr->use_segment_) {
hdr->update_map_ = VP8Get(br, "global-header");
hdr->use_segment = VP8Get(br, "global-header");
if (hdr->use_segment) {
hdr->update_map = VP8Get(br, "global-header");
if (VP8Get(br, "global-header")) { // update data
int s;
hdr->absolute_delta_ = VP8Get(br, "global-header");
hdr->absolute_delta = VP8Get(br, "global-header");
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
hdr->quantizer_[s] = VP8Get(br, "global-header") ?
hdr->quantizer[s] = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 7, "global-header") : 0;
}
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
hdr->filter_strength_[s] = VP8Get(br, "global-header") ?
hdr->filter_strength[s] = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 6, "global-header") : 0;
}
}
if (hdr->update_map_) {
if (hdr->update_map) {
int s;
for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
proba->segments_[s] = VP8Get(br, "global-header") ?
proba->segments[s] = VP8Get(br, "global-header") ?
VP8GetValue(br, 8, "global-header") : 255u;
}
}
} else {
hdr->update_map_ = 0;
hdr->update_map = 0;
}
return !br->eof_;
return !br->eof;
}
// Paragraph 9.5
// This function returns VP8_STATUS_SUSPENDED if we don't have all the
// necessary data in 'buf'.
// This case is not necessarily an error (for incremental decoding).
// Still, no bitreader is ever initialized to make it possible to read
// unavailable memory.
// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA
// If we don't have all the necessary data in 'buf', this function returns
// VP8_STATUS_SUSPENDED in incremental decoding, VP8_STATUS_NOT_ENOUGH_DATA
// otherwise.
// In incremental decoding, this case is not necessarily an error. Still, no
// bitreader is ever initialized to make it possible to read unavailable memory.
// If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA
// is returned, and this is an unrecoverable error.
// If the partitions were positioned ok, VP8_STATUS_OK is returned.
static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
const uint8_t* buf, size_t size) {
VP8BitReader* const br = &dec->br_;
VP8BitReader* const br = &dec->br;
const uint8_t* sz = buf;
const uint8_t* buf_end = buf + size;
const uint8_t* part_start;
@ -208,8 +210,8 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
size_t last_part;
size_t p;
dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2, "global-header")) - 1;
last_part = dec->num_parts_minus_one_;
dec->num_parts_minus_one = (1 << VP8GetValue(br, 2, "global-header")) - 1;
last_part = dec->num_parts_minus_one;
if (size < 3 * last_part) {
// we can't even read the sizes with sz[]! That's a failure.
return VP8_STATUS_NOT_ENOUGH_DATA;
@ -219,40 +221,42 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
for (p = 0; p < last_part; ++p) {
size_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
if (psize > size_left) psize = size_left;
VP8InitBitReader(dec->parts_ + p, part_start, psize);
VP8InitBitReader(dec->parts + p, part_start, psize);
part_start += psize;
size_left -= psize;
sz += 3;
}
VP8InitBitReader(dec->parts_ + last_part, part_start, size_left);
return (part_start < buf_end) ? VP8_STATUS_OK :
VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data
VP8InitBitReader(dec->parts + last_part, part_start, size_left);
if (part_start < buf_end) return VP8_STATUS_OK;
return dec->incremental
? VP8_STATUS_SUSPENDED // Init is ok, but there's not enough data
: VP8_STATUS_NOT_ENOUGH_DATA;
}
// Paragraph 9.4
static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
VP8FilterHeader* const hdr = &dec->filter_hdr_;
hdr->simple_ = VP8Get(br, "global-header");
hdr->level_ = VP8GetValue(br, 6, "global-header");
hdr->sharpness_ = VP8GetValue(br, 3, "global-header");
hdr->use_lf_delta_ = VP8Get(br, "global-header");
if (hdr->use_lf_delta_) {
VP8FilterHeader* const hdr = &dec->filter_hdr;
hdr->simple = VP8Get(br, "global-header");
hdr->level = VP8GetValue(br, 6, "global-header");
hdr->sharpness = VP8GetValue(br, 3, "global-header");
hdr->use_lf_delta = VP8Get(br, "global-header");
if (hdr->use_lf_delta) {
if (VP8Get(br, "global-header")) { // update lf-delta?
int i;
for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
if (VP8Get(br, "global-header")) {
hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header");
hdr->ref_lf_delta[i] = VP8GetSignedValue(br, 6, "global-header");
}
}
for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
if (VP8Get(br, "global-header")) {
hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header");
hdr->mode_lf_delta[i] = VP8GetSignedValue(br, 6, "global-header");
}
}
}
}
dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2;
return !br->eof_;
dec->filter_type = (hdr->level == 0) ? 0 : hdr->simple ? 1 : 2;
return !br->eof;
}
// Topmost call
@ -282,16 +286,16 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
// Paragraph 9.1
{
const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
frm_hdr = &dec->frm_hdr_;
frm_hdr->key_frame_ = !(bits & 1);
frm_hdr->profile_ = (bits >> 1) & 7;
frm_hdr->show_ = (bits >> 4) & 1;
frm_hdr->partition_length_ = (bits >> 5);
if (frm_hdr->profile_ > 3) {
frm_hdr = &dec->frm_hdr;
frm_hdr->key_frame = !(bits & 1);
frm_hdr->profile = (bits >> 1) & 7;
frm_hdr->show = (bits >> 4) & 1;
frm_hdr->partition_length = (bits >> 5);
if (frm_hdr->profile > 3) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"Incorrect keyframe parameters.");
}
if (!frm_hdr->show_) {
if (!frm_hdr->show) {
return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
"Frame not displayable.");
}
@ -299,8 +303,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
buf_size -= 3;
}
pic_hdr = &dec->pic_hdr_;
if (frm_hdr->key_frame_) {
pic_hdr = &dec->pic_hdr;
if (frm_hdr->key_frame) {
// Paragraph 9.2
if (buf_size < 7) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
@ -310,20 +314,20 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"Bad code word");
}
pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff;
pic_hdr->xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2
pic_hdr->height_ = ((buf[6] << 8) | buf[5]) & 0x3fff;
pic_hdr->yscale_ = buf[6] >> 6;
pic_hdr->width = ((buf[4] << 8) | buf[3]) & 0x3fff;
pic_hdr->xscale = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2
pic_hdr->height = ((buf[6] << 8) | buf[5]) & 0x3fff;
pic_hdr->yscale = buf[6] >> 6;
buf += 7;
buf_size -= 7;
dec->mb_w_ = (pic_hdr->width_ + 15) >> 4;
dec->mb_h_ = (pic_hdr->height_ + 15) >> 4;
dec->mb_w = (pic_hdr->width + 15) >> 4;
dec->mb_h = (pic_hdr->height + 15) >> 4;
// Setup default output area (can be later modified during io->setup())
io->width = pic_hdr->width_;
io->height = pic_hdr->height_;
// IMPORTANT! use some sane dimensions in crop_* and scaled_* fields.
io->width = pic_hdr->width;
io->height = pic_hdr->height;
// IMPORTANT! use some sane dimensions in crop* and scaled* fields.
// So they can be used interchangeably without always testing for
// 'use_cropping'.
io->use_cropping = 0;
@ -338,27 +342,27 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
io->mb_w = io->width; // for soundness
io->mb_h = io->height; // ditto
VP8ResetProba(&dec->proba_);
ResetSegmentHeader(&dec->segment_hdr_);
VP8ResetProba(&dec->proba);
ResetSegmentHeader(&dec->segment_hdr);
}
// Check if we have all the partition #0 available, and initialize dec->br_
// Check if we have all the partition #0 available, and initialize dec->br
// to read this partition (and this partition only).
if (frm_hdr->partition_length_ > buf_size) {
if (frm_hdr->partition_length > buf_size) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"bad partition length");
}
br = &dec->br_;
VP8InitBitReader(br, buf, frm_hdr->partition_length_);
buf += frm_hdr->partition_length_;
buf_size -= frm_hdr->partition_length_;
br = &dec->br;
VP8InitBitReader(br, buf, frm_hdr->partition_length);
buf += frm_hdr->partition_length;
buf_size -= frm_hdr->partition_length;
if (frm_hdr->key_frame_) {
pic_hdr->colorspace_ = VP8Get(br, "global-header");
pic_hdr->clamp_type_ = VP8Get(br, "global-header");
if (frm_hdr->key_frame) {
pic_hdr->colorspace = VP8Get(br, "global-header");
pic_hdr->clamp_type = VP8Get(br, "global-header");
}
if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) {
if (!ParseSegmentHeader(br, &dec->segment_hdr, &dec->proba)) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"cannot parse segment header");
}
@ -376,17 +380,17 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
VP8ParseQuant(dec);
// Frame buffer marking
if (!frm_hdr->key_frame_) {
if (!frm_hdr->key_frame) {
return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
"Not a key frame.");
}
VP8Get(br, "global-header"); // ignore the value of update_proba_
VP8Get(br, "global-header"); // ignore the value of 'update_proba'
VP8ParseProba(br, dec);
// sanitized state
dec->ready_ = 1;
dec->ready = 1;
return 1;
}
@ -439,17 +443,17 @@ static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
static int GetCoeffsFast(VP8BitReader* const br,
const VP8BandProbas* const prob[],
int ctx, const quant_t dq, int n, int16_t* out) {
const uint8_t* p = prob[n]->probas_[ctx];
const uint8_t* p = prob[n]->probas[ctx];
for (; n < 16; ++n) {
if (!VP8GetBit(br, p[0], "coeffs")) {
return n; // previous coeff was last non-zero coeff
}
while (!VP8GetBit(br, p[1], "coeffs")) { // sequence of zero coeffs
p = prob[++n]->probas_[0];
p = prob[++n]->probas[0];
if (n == 16) return 16;
}
{ // non zero coeff
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas[0];
int v;
if (!VP8GetBit(br, p[2], "coeffs")) {
v = 1;
@ -469,17 +473,17 @@ static int GetCoeffsFast(VP8BitReader* const br,
static int GetCoeffsAlt(VP8BitReader* const br,
const VP8BandProbas* const prob[],
int ctx, const quant_t dq, int n, int16_t* out) {
const uint8_t* p = prob[n]->probas_[ctx];
const uint8_t* p = prob[n]->probas[ctx];
for (; n < 16; ++n) {
if (!VP8GetBitAlt(br, p[0], "coeffs")) {
return n; // previous coeff was last non-zero coeff
}
while (!VP8GetBitAlt(br, p[1], "coeffs")) { // sequence of zero coeffs
p = prob[++n]->probas_[0];
p = prob[++n]->probas[0];
if (n == 16) return 16;
}
{ // non zero coeff
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas[0];
int v;
if (!VP8GetBitAlt(br, p[2], "coeffs")) {
v = 1;
@ -494,6 +498,8 @@ static int GetCoeffsAlt(VP8BitReader* const br,
return 16;
}
extern VP8CPUInfo VP8GetCPUInfo;
WEBP_DSP_INIT_FUNC(InitGetCoeffs) {
if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
GetCoeffs = GetCoeffsAlt;
@ -510,12 +516,12 @@ static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) {
static int ParseResiduals(VP8Decoder* const dec,
VP8MB* const mb, VP8BitReader* const token_br) {
const VP8BandProbas* (* const bands)[16 + 1] = dec->proba_.bands_ptr_;
const VP8BandProbas* (* const bands)[16 + 1] = dec->proba.bands_ptr;
const VP8BandProbas* const * ac_proba;
VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
const VP8QuantMatrix* const q = &dec->dqm_[block->segment_];
int16_t* dst = block->coeffs_;
VP8MB* const left_mb = dec->mb_info_ - 1;
VP8MBData* const block = dec->mb_data + dec->mb_x;
const VP8QuantMatrix* const q = &dec->dqm[block->segment];
int16_t* dst = block->coeffs;
VP8MB* const left_mb = dec->mb_info - 1;
uint8_t tnz, lnz;
uint32_t non_zero_y = 0;
uint32_t non_zero_uv = 0;
@ -524,11 +530,11 @@ static int ParseResiduals(VP8Decoder* const dec,
int first;
memset(dst, 0, 384 * sizeof(*dst));
if (!block->is_i4x4_) { // parse DC
if (!block->is_i4x4) { // parse DC
int16_t dc[16] = { 0 };
const int ctx = mb->nz_dc_ + left_mb->nz_dc_;
const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat_, 0, dc);
mb->nz_dc_ = left_mb->nz_dc_ = (nz > 0);
const int ctx = mb->nz_dc + left_mb->nz_dc;
const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat, 0, dc);
mb->nz_dc = left_mb->nz_dc = (nz > 0);
if (nz > 1) { // more than just the DC -> perform the full transform
VP8TransformWHT(dc, dst);
} else { // only DC is non-zero -> inlined simplified transform
@ -543,14 +549,14 @@ static int ParseResiduals(VP8Decoder* const dec,
ac_proba = bands[3];
}
tnz = mb->nz_ & 0x0f;
lnz = left_mb->nz_ & 0x0f;
tnz = mb->nz & 0x0f;
lnz = left_mb->nz & 0x0f;
for (y = 0; y < 4; ++y) {
int l = lnz & 1;
uint32_t nz_coeffs = 0;
for (x = 0; x < 4; ++x) {
const int ctx = l + (tnz & 1);
const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat_, first, dst);
const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat, first, dst);
l = (nz > first);
tnz = (tnz >> 1) | (l << 7);
nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0);
@ -565,13 +571,13 @@ static int ParseResiduals(VP8Decoder* const dec,
for (ch = 0; ch < 4; ch += 2) {
uint32_t nz_coeffs = 0;
tnz = mb->nz_ >> (4 + ch);
lnz = left_mb->nz_ >> (4 + ch);
tnz = mb->nz >> (4 + ch);
lnz = left_mb->nz >> (4 + ch);
for (y = 0; y < 2; ++y) {
int l = lnz & 1;
for (x = 0; x < 2; ++x) {
const int ctx = l + (tnz & 1);
const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat_, 0, dst);
const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat, 0, dst);
l = (nz > 0);
tnz = (tnz >> 1) | (l << 3);
nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0);
@ -585,16 +591,16 @@ static int ParseResiduals(VP8Decoder* const dec,
out_t_nz |= (tnz << 4) << ch;
out_l_nz |= (lnz & 0xf0) << ch;
}
mb->nz_ = out_t_nz;
left_mb->nz_ = out_l_nz;
mb->nz = out_t_nz;
left_mb->nz = out_l_nz;
block->non_zero_y_ = non_zero_y;
block->non_zero_uv_ = non_zero_uv;
block->non_zero_y = non_zero_y;
block->non_zero_uv = non_zero_uv;
// We look at the mode-code of each block and check if some blocks have less
// than three non-zero coeffs (code < 2). This is to avoid dithering flat and
// empty blocks.
block->dither_ = (non_zero_uv & 0xaaaa) ? 0 : q->dither_;
block->dither = (non_zero_uv & 0xaaaa) ? 0 : q->dither;
return !(non_zero_y | non_zero_uv); // will be used for further optimization
}
@ -603,50 +609,50 @@ static int ParseResiduals(VP8Decoder* const dec,
// Main loop
int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
VP8MB* const left = dec->mb_info_ - 1;
VP8MB* const mb = dec->mb_info_ + dec->mb_x_;
VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
int skip = dec->use_skip_proba_ ? block->skip_ : 0;
VP8MB* const left = dec->mb_info - 1;
VP8MB* const mb = dec->mb_info + dec->mb_x;
VP8MBData* const block = dec->mb_data + dec->mb_x;
int skip = dec->use_skip_proba ? block->skip : 0;
if (!skip) {
skip = ParseResiduals(dec, mb, token_br);
} else {
left->nz_ = mb->nz_ = 0;
if (!block->is_i4x4_) {
left->nz_dc_ = mb->nz_dc_ = 0;
left->nz = mb->nz = 0;
if (!block->is_i4x4) {
left->nz_dc = mb->nz_dc = 0;
}
block->non_zero_y_ = 0;
block->non_zero_uv_ = 0;
block->dither_ = 0;
block->non_zero_y = 0;
block->non_zero_uv = 0;
block->dither = 0;
}
if (dec->filter_type_ > 0) { // store filter info
VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_;
*finfo = dec->fstrengths_[block->segment_][block->is_i4x4_];
finfo->f_inner_ |= !skip;
if (dec->filter_type > 0) { // store filter info
VP8FInfo* const finfo = dec->f_info + dec->mb_x;
*finfo = dec->fstrengths[block->segment][block->is_i4x4];
finfo->f_inner |= !skip;
}
return !token_br->eof_;
return !token_br->eof;
}
void VP8InitScanline(VP8Decoder* const dec) {
VP8MB* const left = dec->mb_info_ - 1;
left->nz_ = 0;
left->nz_dc_ = 0;
memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
dec->mb_x_ = 0;
VP8MB* const left = dec->mb_info - 1;
left->nz = 0;
left->nz_dc = 0;
memset(dec->intra_l, B_DC_PRED, sizeof(dec->intra_l));
dec->mb_x = 0;
}
static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) {
for (dec->mb_y = 0; dec->mb_y < dec->br_mb_y; ++dec->mb_y) {
// Parse bitstream for this row.
VP8BitReader* const token_br =
&dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_];
if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
&dec->parts[dec->mb_y & dec->num_parts_minus_one];
if (!VP8ParseIntraModeRow(&dec->br, dec)) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"Premature end-of-partition0 encountered.");
}
for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
for (; dec->mb_x < dec->mb_w; ++dec->mb_x) {
if (!VP8DecodeMB(dec, token_br)) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"Premature end-of-file encountered.");
@ -659,8 +665,8 @@ static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted.");
}
}
if (dec->mt_method_ > 0) {
if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) return 0;
if (dec->mt_method > 0) {
if (!WebPGetWorkerInterface()->Sync(&dec->worker)) return 0;
}
return 1;
@ -677,12 +683,12 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
"NULL VP8Io parameter in VP8Decode().");
}
if (!dec->ready_) {
if (!dec->ready) {
if (!VP8GetHeaders(dec, io)) {
return 0;
}
}
assert(dec->ready_);
assert(dec->ready);
// Finish setting up the decoding parameter. Will call io->setup().
ok = (VP8EnterCritical(dec, io) == VP8_STATUS_OK);
@ -702,7 +708,7 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
return 0;
}
dec->ready_ = 0;
dec->ready = 0;
return ok;
}
@ -710,13 +716,13 @@ void VP8Clear(VP8Decoder* const dec) {
if (dec == NULL) {
return;
}
WebPGetWorkerInterface()->End(&dec->worker_);
WebPGetWorkerInterface()->End(&dec->worker);
WebPDeallocateAlphaMemory(dec);
WebPSafeFree(dec->mem_);
dec->mem_ = NULL;
dec->mem_size_ = 0;
memset(&dec->br_, 0, sizeof(dec->br_));
dec->ready_ = 0;
WebPSafeFree(dec->mem);
dec->mem = NULL;
dec->mem_size = 0;
memset(&dec->br, 0, sizeof(dec->br));
dec->ready = 0;
}
//------------------------------------------------------------------------------

View File

@ -15,6 +15,7 @@
#define WEBP_DEC_VP8_DEC_H_
#include "src/webp/decode.h"
#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@ -108,16 +109,14 @@ struct VP8Io {
};
// Internal, version-checked, entry point
int VP8InitIoInternal(VP8Io* const, int);
WEBP_NODISCARD int VP8InitIoInternal(VP8Io* const, int);
// Set the custom IO function pointers and user-data. The setter for IO hooks
// should be called before initiating incremental decoding. Returns true if
// WebPIDecoder object is successfully modified, false otherwise.
int WebPISetIOHooks(WebPIDecoder* const idec,
VP8IoPutHook put,
VP8IoSetupHook setup,
VP8IoTeardownHook teardown,
void* user_data);
WEBP_NODISCARD int WebPISetIOHooks(WebPIDecoder* const idec, VP8IoPutHook put,
VP8IoSetupHook setup,
VP8IoTeardownHook teardown, void* user_data);
// Main decoding object. This is an opaque structure.
typedef struct VP8Decoder VP8Decoder;
@ -128,17 +127,17 @@ VP8Decoder* VP8New(void);
// Must be called to make sure 'io' is initialized properly.
// Returns false in case of version mismatch. Upon such failure, no other
// decoding function should be called (VP8Decode, VP8GetHeaders, ...)
static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
WEBP_NODISCARD static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
}
// Decode the VP8 frame header. Returns true if ok.
// Note: 'io->data' must be pointing to the start of the VP8 frame header.
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
WEBP_NODISCARD int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
// Returns false in case of error.
int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
WEBP_NODISCARD int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
// Return current status of the decoder:
VP8StatusCode VP8Status(VP8Decoder* const dec);

View File

@ -21,6 +21,7 @@
#include "src/utils/random_utils.h"
#include "src/utils/thread_utils.h"
#include "src/dsp/dsp.h"
#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@ -31,8 +32,8 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 2
#define DEC_REV_VERSION 4
#define DEC_MIN_VERSION 5
#define DEC_REV_VERSION 0
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
@ -68,85 +69,85 @@ extern "C" {
// Headers
typedef struct {
uint8_t key_frame_;
uint8_t profile_;
uint8_t show_;
uint32_t partition_length_;
uint8_t key_frame;
uint8_t profile;
uint8_t show;
uint32_t partition_length;
} VP8FrameHeader;
typedef struct {
uint16_t width_;
uint16_t height_;
uint8_t xscale_;
uint8_t yscale_;
uint8_t colorspace_; // 0 = YCbCr
uint8_t clamp_type_;
uint16_t width;
uint16_t height;
uint8_t xscale;
uint8_t yscale;
uint8_t colorspace; // 0 = YCbCr
uint8_t clamp_type;
} VP8PictureHeader;
// segment features
typedef struct {
int use_segment_;
int update_map_; // whether to update the segment map or not
int absolute_delta_; // absolute or delta values for quantizer and filter
int8_t quantizer_[NUM_MB_SEGMENTS]; // quantization changes
int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments
int use_segment;
int update_map; // whether to update the segment map or not
int absolute_delta; // absolute or delta values for quantizer and filter
int8_t quantizer[NUM_MB_SEGMENTS]; // quantization changes
int8_t filter_strength[NUM_MB_SEGMENTS]; // filter strength for segments
} VP8SegmentHeader;
// probas associated to one of the contexts
typedef uint8_t VP8ProbaArray[NUM_PROBAS];
typedef struct { // all the probas associated to one band
VP8ProbaArray probas_[NUM_CTX];
VP8ProbaArray probas[NUM_CTX];
} VP8BandProbas;
// Struct collecting all frame-persistent probabilities.
typedef struct {
uint8_t segments_[MB_FEATURE_TREE_PROBS];
uint8_t segments[MB_FEATURE_TREE_PROBS];
// Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4
VP8BandProbas bands_[NUM_TYPES][NUM_BANDS];
const VP8BandProbas* bands_ptr_[NUM_TYPES][16 + 1];
VP8BandProbas bands[NUM_TYPES][NUM_BANDS];
const VP8BandProbas* bands_ptr[NUM_TYPES][16 + 1];
} VP8Proba;
// Filter parameters
typedef struct {
int simple_; // 0=complex, 1=simple
int level_; // [0..63]
int sharpness_; // [0..7]
int use_lf_delta_;
int ref_lf_delta_[NUM_REF_LF_DELTAS];
int mode_lf_delta_[NUM_MODE_LF_DELTAS];
int simple; // 0=complex, 1=simple
int level; // [0..63]
int sharpness; // [0..7]
int use_lf_delta;
int ref_lf_delta[NUM_REF_LF_DELTAS];
int mode_lf_delta[NUM_MODE_LF_DELTAS];
} VP8FilterHeader;
//------------------------------------------------------------------------------
// Informations about the macroblocks.
typedef struct { // filter specs
uint8_t f_limit_; // filter limit in [3..189], or 0 if no filtering
uint8_t f_ilevel_; // inner limit in [1..63]
uint8_t f_inner_; // do inner filtering?
uint8_t hev_thresh_; // high edge variance threshold in [0..2]
uint8_t f_limit; // filter limit in [3..189], or 0 if no filtering
uint8_t f_ilevel; // inner limit in [1..63]
uint8_t f_inner; // do inner filtering?
uint8_t hev_thresh; // high edge variance threshold in [0..2]
} VP8FInfo;
typedef struct { // Top/Left Contexts used for syntax-parsing
uint8_t nz_; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma)
uint8_t nz_dc_; // non-zero DC coeff (1bit)
uint8_t nz; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma)
uint8_t nz_dc; // non-zero DC coeff (1bit)
} VP8MB;
// Dequantization matrices
typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower).
typedef struct {
quant_t y1_mat_, y2_mat_, uv_mat_;
quant_t y1_mat, y2_mat, uv_mat;
int uv_quant_; // U/V quantizer value
int dither_; // dithering amplitude (0 = off, max=255)
int uv_quant; // U/V quantizer value
int dither; // dithering amplitude (0 = off, max=255)
} VP8QuantMatrix;
// Data needed to reconstruct a macroblock
typedef struct {
int16_t coeffs_[384]; // 384 coeffs = (16+4+4) * 4*4
uint8_t is_i4x4_; // true if intra4x4
uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
uint8_t uvmode_; // chroma prediction mode
int16_t coeffs[384]; // 384 coeffs = (16+4+4) * 4*4
uint8_t is_i4x4; // true if intra4x4
uint8_t imodes[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
uint8_t uvmode; // chroma prediction mode
// bit-wise info about the content of each sub-4x4 blocks (in decoding order).
// Each of the 4x4 blocks for y/u/v is associated with a 2b code according to:
// code=0 -> no coefficient
@ -154,21 +155,21 @@ typedef struct {
// code=2 -> first three coefficients are non-zero
// code=3 -> more than three coefficients are non-zero
// This allows to call specialized transform functions.
uint32_t non_zero_y_;
uint32_t non_zero_uv_;
uint8_t dither_; // local dithering strength (deduced from non_zero_*)
uint8_t skip_;
uint8_t segment_;
uint32_t non_zero_y;
uint32_t non_zero_uv;
uint8_t dither; // local dithering strength (deduced from non_zero*)
uint8_t skip;
uint8_t segment;
} VP8MBData;
// Persistent information needed by the parallel processing
typedef struct {
int id_; // cache row to process (in [0..2])
int mb_y_; // macroblock position of the row
int filter_row_; // true if row-filtering is needed
VP8FInfo* f_info_; // filter strengths (swapped with dec->f_info_)
VP8MBData* mb_data_; // reconstruction data (swapped with dec->mb_data_)
VP8Io io_; // copy of the VP8Io to pass to put()
int id; // cache row to process (in [0..2])
int mb_y; // macroblock position of the row
int filter_row; // true if row-filtering is needed
VP8FInfo* f_info; // filter strengths (swapped with dec->f_info)
VP8MBData* mb_data; // reconstruction data (swapped with dec->mb_data)
VP8Io io; // copy of the VP8Io to pass to put()
} VP8ThreadContext;
// Saved top samples, per macroblock. Fits into a cache-line.
@ -180,88 +181,89 @@ typedef struct {
// VP8Decoder: the main opaque structure handed over to user
struct VP8Decoder {
VP8StatusCode status_;
int ready_; // true if ready to decode a picture with VP8Decode()
const char* error_msg_; // set when status_ is not OK.
VP8StatusCode status;
int ready; // true if ready to decode a picture with VP8Decode()
const char* error_msg; // set when status is not OK.
// Main data source
VP8BitReader br_;
VP8BitReader br;
int incremental; // if true, incremental decoding is expected
// headers
VP8FrameHeader frm_hdr_;
VP8PictureHeader pic_hdr_;
VP8FilterHeader filter_hdr_;
VP8SegmentHeader segment_hdr_;
VP8FrameHeader frm_hdr;
VP8PictureHeader pic_hdr;
VP8FilterHeader filter_hdr;
VP8SegmentHeader segment_hdr;
// Worker
WebPWorker worker_;
int mt_method_; // multi-thread method: 0=off, 1=[parse+recon][filter]
// 2=[parse][recon+filter]
int cache_id_; // current cache row
int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3)
VP8ThreadContext thread_ctx_; // Thread context
WebPWorker worker;
int mt_method; // multi-thread method: 0=off, 1=[parse+recon][filter]
// 2=[parse][recon+filter]
int cache_id; // current cache row
int num_caches; // number of cached rows of 16 pixels (1, 2 or 3)
VP8ThreadContext thread_ctx; // Thread context
// dimension, in macroblock units.
int mb_w_, mb_h_;
int mb_w, mb_h;
// Macroblock to process/filter, depending on cropping and filter_type.
int tl_mb_x_, tl_mb_y_; // top-left MB that must be in-loop filtered
int br_mb_x_, br_mb_y_; // last bottom-right MB that must be decoded
int tl_mb_x, tl_mb_y; // top-left MB that must be in-loop filtered
int br_mb_x, br_mb_y; // last bottom-right MB that must be decoded
// number of partitions minus one.
uint32_t num_parts_minus_one_;
uint32_t num_parts_minus_one;
// per-partition boolean decoders.
VP8BitReader parts_[MAX_NUM_PARTITIONS];
VP8BitReader parts[MAX_NUM_PARTITIONS];
// Dithering strength, deduced from decoding options
int dither_; // whether to use dithering or not
VP8Random dithering_rg_; // random generator for dithering
int dither; // whether to use dithering or not
VP8Random dithering_rg; // random generator for dithering
// dequantization (one set of DC/AC dequant factor per segment)
VP8QuantMatrix dqm_[NUM_MB_SEGMENTS];
VP8QuantMatrix dqm[NUM_MB_SEGMENTS];
// probabilities
VP8Proba proba_;
int use_skip_proba_;
uint8_t skip_p_;
VP8Proba proba;
int use_skip_proba;
uint8_t skip_p;
// Boundary data cache and persistent buffers.
uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
uint8_t intra_l_[4]; // left intra modes values
uint8_t* intra_t; // top intra modes values: 4 * mb_w
uint8_t intra_l[4]; // left intra modes values
VP8TopSamples* yuv_t_; // top y/u/v samples
VP8TopSamples* yuv_t; // top y/u/v samples
VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1)
VP8FInfo* f_info_; // filter strength info
uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE)
VP8MB* mb_info; // contextual macroblock info (mb_w + 1)
VP8FInfo* f_info; // filter strength info
uint8_t* yuv_b; // main block for Y/U/V (size = YUV_SIZE)
uint8_t* cache_y_; // macroblock row for storing unfiltered samples
uint8_t* cache_u_;
uint8_t* cache_v_;
int cache_y_stride_;
int cache_uv_stride_;
uint8_t* cache_y; // macroblock row for storing unfiltered samples
uint8_t* cache_u;
uint8_t* cache_v;
int cache_y_stride;
int cache_uv_stride;
// main memory chunk for the above data. Persistent.
void* mem_;
size_t mem_size_;
void* mem;
size_t mem_size;
// Per macroblock non-persistent infos.
int mb_x_, mb_y_; // current position, in macroblock units
VP8MBData* mb_data_; // parsed reconstruction data
int mb_x, mb_y; // current position, in macroblock units
VP8MBData* mb_data; // parsed reconstruction data
// Filtering side-info
int filter_type_; // 0=off, 1=simple, 2=complex
VP8FInfo fstrengths_[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type
int filter_type; // 0=off, 1=simple, 2=complex
VP8FInfo fstrengths[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type
// Alpha
struct ALPHDecoder* alph_dec_; // alpha-plane decoder object
const uint8_t* alpha_data_; // compressed alpha data (if present)
size_t alpha_data_size_;
int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_
uint8_t* alpha_plane_mem_; // memory allocated for alpha_plane_
uint8_t* alpha_plane_; // output. Persistent, contains the whole data.
const uint8_t* alpha_prev_line_; // last decoded alpha row (or NULL)
int alpha_dithering_; // derived from decoding options (0=off, 100=full)
struct ALPHDecoder* alph_dec; // alpha-plane decoder object
const uint8_t* alpha_data; // compressed alpha data (if present)
size_t alpha_data_size;
int is_alpha_decoded; // true if alpha_data is decoded in alpha_plane
uint8_t* alpha_plane_mem; // memory allocated for alpha_plane
uint8_t* alpha_plane; // output. Persistent, contains the whole data.
const uint8_t* alpha_prev_line; // last decoded alpha row (or NULL)
int alpha_dithering; // derived from decoding options (0=off, 100=full)
};
//------------------------------------------------------------------------------
@ -281,7 +283,7 @@ int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec);
void VP8ParseQuant(VP8Decoder* const dec);
// in frame.c
int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
WEBP_NODISCARD int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
// Call io->setup() and finish setting up scan parameters.
// After this call returns, one must always call VP8ExitCritical() with the
// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK
@ -289,7 +291,7 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
// Must always be called in pair with VP8EnterCritical().
// Returns false in case of error.
int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
WEBP_NODISCARD int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
// Return the multi-threading method to use (0=off), depending
// on options and bitstream size. Only for lossy decoding.
int VP8GetThreadMethod(const WebPDecoderOptions* const options,
@ -299,11 +301,12 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
void VP8InitDithering(const WebPDecoderOptions* const options,
VP8Decoder* const dec);
// Process the last decoded row (filtering + output).
int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
WEBP_NODISCARD int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
// To be called at the start of a new scanline, to initialize predictors.
void VP8InitScanline(VP8Decoder* const dec);
// Decode one macroblock. Returns false if there is not enough data.
int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br);
WEBP_NODISCARD int VP8DecodeMB(VP8Decoder* const dec,
VP8BitReader* const token_br);
// in alpha.c
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#include "src/utils/bit_reader_utils.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/huffman_utils.h"
#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@ -33,58 +34,58 @@ typedef enum {
typedef struct VP8LTransform VP8LTransform;
struct VP8LTransform {
VP8LImageTransformType type_; // transform type.
int bits_; // subsampling bits defining transform window.
int xsize_; // transform window X index.
int ysize_; // transform window Y index.
uint32_t* data_; // transform data.
VP8LImageTransformType type; // transform type.
int bits; // subsampling bits defining transform window.
int xsize; // transform window X index.
int ysize; // transform window Y index.
uint32_t* data; // transform data.
};
typedef struct {
int color_cache_size_;
VP8LColorCache color_cache_;
VP8LColorCache saved_color_cache_; // for incremental
int color_cache_size;
VP8LColorCache color_cache;
VP8LColorCache saved_color_cache; // for incremental
int huffman_mask_;
int huffman_subsample_bits_;
int huffman_xsize_;
uint32_t* huffman_image_;
int num_htree_groups_;
HTreeGroup* htree_groups_;
HuffmanCode* huffman_tables_;
int huffman_mask;
int huffman_subsample_bits;
int huffman_xsize;
uint32_t* huffman_image;
int num_htree_groups;
HTreeGroup* htree_groups;
HuffmanTables huffman_tables;
} VP8LMetadata;
typedef struct VP8LDecoder VP8LDecoder;
struct VP8LDecoder {
VP8StatusCode status_;
VP8LDecodeState state_;
VP8Io* io_;
VP8StatusCode status;
VP8LDecodeState state;
VP8Io* io;
const WebPDecBuffer* output_; // shortcut to io->opaque->output
const WebPDecBuffer* output; // shortcut to io->opaque->output
uint32_t* pixels_; // Internal data: either uint8_t* for alpha
// or uint32_t* for BGRA.
uint32_t* argb_cache_; // Scratch buffer for temporary BGRA storage.
uint32_t* pixels; // Internal data: either uint8_t* for alpha
// or uint32_t* for BGRA.
uint32_t* argb_cache; // Scratch buffer for temporary BGRA storage.
VP8LBitReader br_;
int incremental_; // if true, incremental decoding is expected
VP8LBitReader saved_br_; // note: could be local variables too
int saved_last_pixel_;
VP8LBitReader br;
int incremental; // if true, incremental decoding is expected
VP8LBitReader saved_br; // note: could be local variables too
int saved_last_pixel;
int width_;
int height_;
int last_row_; // last input row decoded so far.
int last_pixel_; // last pixel decoded so far. However, it may
// not be transformed, scaled and
// color-converted yet.
int last_out_row_; // last row output so far.
int width;
int height;
int last_row; // last input row decoded so far.
int last_pixel; // last pixel decoded so far. However, it may
// not be transformed, scaled and
// color-converted yet.
int last_out_row; // last row output so far.
VP8LMetadata hdr_;
VP8LMetadata hdr;
int next_transform_;
VP8LTransform transforms_[NUM_TRANSFORMS];
int next_transform;
VP8LTransform transforms[NUM_TRANSFORMS];
// or'd bitset storing the transforms types.
uint32_t transforms_seen_;
uint32_t transforms_seen;
uint8_t* rescaler_memory; // Working memory for rescaling work.
WebPRescaler* rescaler; // Common rescaler for all channels.
@ -99,33 +100,42 @@ struct ALPHDecoder; // Defined in dec/alphai.h.
// Decodes image header for alpha data stored using lossless compression.
// Returns false in case of error.
int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
const uint8_t* const data, size_t data_size);
WEBP_NODISCARD int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
const uint8_t* const data,
size_t data_size);
// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
// already decoded in previous call(s), it will resume decoding from where it
// was paused.
// Returns false in case of bitstream error.
int VP8LDecodeAlphaImageStream(struct ALPHDecoder* const alph_dec,
int last_row);
WEBP_NODISCARD int VP8LDecodeAlphaImageStream(
struct ALPHDecoder* const alph_dec, int last_row);
// Allocates and initialize a new lossless decoder instance.
VP8LDecoder* VP8LNew(void);
WEBP_NODISCARD VP8LDecoder* VP8LNew(void);
// Decodes the image header. Returns false in case of error.
int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
WEBP_NODISCARD int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
// Decodes an image. It's required to decode the lossless header before calling
// this function. Returns false in case of error, with updated dec->status_.
int VP8LDecodeImage(VP8LDecoder* const dec);
// Resets the decoder in its initial state, reclaiming memory.
// Preserves the dec->status_ value.
void VP8LClear(VP8LDecoder* const dec);
// this function. Returns false in case of error, with updated dec->status.
WEBP_NODISCARD int VP8LDecodeImage(VP8LDecoder* const dec);
// Clears and deallocate a lossless decoder instance.
void VP8LDelete(VP8LDecoder* const dec);
// Helper function for reading the different Huffman codes and storing them in
// 'huffman_tables' and 'htree_groups'.
// If mapping is NULL 'num_htree_groups_max' must equal 'num_htree_groups'.
// If it is not NULL, it maps 'num_htree_groups_max' indices to the
// 'num_htree_groups' groups. If 'num_htree_groups_max' > 'num_htree_groups',
// some of those indices map to -1. This is used for non-balanced codes to
// limit memory usage.
WEBP_NODISCARD int ReadHuffmanCodesHelper(
int color_cache_bits, int num_htree_groups, int num_htree_groups_max,
const int* const mapping, VP8LDecoder* const dec,
HuffmanTables* const huffman_tables, HTreeGroup** const htree_groups);
//------------------------------------------------------------------------------
#ifdef __cplusplus

View File

@ -13,11 +13,16 @@
#include <stdlib.h>
#include "src/dec/common_dec.h"
#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
#include "src/dec/webpi_dec.h"
#include "src/utils/rescaler_utils.h"
#include "src/utils/utils.h"
#include "src/webp/decode.h"
#include "src/webp/mux_types.h" // ALPHA_FLAG
#include "src/webp/types.h"
//------------------------------------------------------------------------------
// RIFF layout is:
@ -179,7 +184,7 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
}
// For odd-sized chunk-payload, there's one byte padding at the end.
disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1u;
total_size += disk_chunk_size;
// Check that total bytes skipped so far does not exceed riff_size.
@ -444,8 +449,9 @@ void WebPResetDecParams(WebPDecParams* const params) {
// "Into" decoding variants
// Main flow
static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
WebPDecParams* const params) {
WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
size_t data_size,
WebPDecParams* const params) {
VP8StatusCode status;
VP8Io io;
WebPHeaderStructure headers;
@ -459,7 +465,9 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
}
assert(params != NULL);
VP8InitIo(&io);
if (!VP8InitIo(&io)) {
return VP8_STATUS_INVALID_PARAM;
}
io.data = headers.data + headers.offset;
io.data_size = headers.data_size - headers.offset;
WebPInitCustomIo(params, &io); // Plug the I/O functions.
@ -469,23 +477,23 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
if (dec == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
}
dec->alpha_data_ = headers.alpha_data;
dec->alpha_data_size_ = headers.alpha_data_size;
dec->alpha_data = headers.alpha_data;
dec->alpha_data_size = headers.alpha_data_size;
// Decode bitstream header, update io->width/io->height.
if (!VP8GetHeaders(dec, &io)) {
status = dec->status_; // An error occurred. Grab error status.
status = dec->status; // An error occurred. Grab error status.
} else {
// Allocate/check output buffers.
status = WebPAllocateDecBuffer(io.width, io.height, params->options,
params->output);
if (status == VP8_STATUS_OK) { // Decode
// This change must be done before calling VP8Decode()
dec->mt_method_ = VP8GetThreadMethod(params->options, &headers,
io.width, io.height);
dec->mt_method = VP8GetThreadMethod(params->options, &headers,
io.width, io.height);
VP8InitDithering(params->options, dec);
if (!VP8Decode(dec, &io)) {
status = dec->status_;
status = dec->status;
}
}
}
@ -496,14 +504,14 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
return VP8_STATUS_OUT_OF_MEMORY;
}
if (!VP8LDecodeHeader(dec, &io)) {
status = dec->status_; // An error occurred. Grab error status.
status = dec->status; // An error occurred. Grab error status.
} else {
// Allocate/check output buffers.
status = WebPAllocateDecBuffer(io.width, io.height, params->options,
params->output);
if (status == VP8_STATUS_OK) { // Decode
if (!VP8LDecodeImage(dec)) {
status = dec->status_;
status = dec->status;
}
}
}
@ -523,17 +531,16 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
}
// Helpers
static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
const uint8_t* const data,
size_t data_size,
uint8_t* const rgba,
int stride, size_t size) {
WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
const uint8_t* const data,
size_t data_size,
uint8_t* const rgba,
int stride, size_t size) {
WebPDecParams params;
WebPDecBuffer buf;
if (rgba == NULL) {
if (rgba == NULL || !WebPInitDecBuffer(&buf)) {
return NULL;
}
WebPInitDecBuffer(&buf);
WebPResetDecParams(&params);
params.output = &buf;
buf.colorspace = colorspace;
@ -578,8 +585,7 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
uint8_t* v, size_t v_size, int v_stride) {
WebPDecParams params;
WebPDecBuffer output;
if (luma == NULL) return NULL;
WebPInitDecBuffer(&output);
if (luma == NULL || !WebPInitDecBuffer(&output)) return NULL;
WebPResetDecParams(&params);
params.output = &output;
output.colorspace = MODE_YUV;
@ -601,13 +607,17 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
//------------------------------------------------------------------------------
static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data,
size_t data_size, int* const width, int* const height,
WebPDecBuffer* const keep_info) {
WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode,
const uint8_t* const data,
size_t data_size, int* const width,
int* const height,
WebPDecBuffer* const keep_info) {
WebPDecParams params;
WebPDecBuffer output;
WebPInitDecBuffer(&output);
if (!WebPInitDecBuffer(&output)) {
return NULL;
}
WebPResetDecParams(&params);
params.output = &output;
output.colorspace = mode;
@ -658,19 +668,26 @@ uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
int* width, int* height, uint8_t** u, uint8_t** v,
int* stride, int* uv_stride) {
WebPDecBuffer output; // only to preserve the side-infos
uint8_t* const out = Decode(MODE_YUV, data, data_size,
width, height, &output);
if (out != NULL) {
const WebPYUVABuffer* const buf = &output.u.YUVA;
*u = buf->u;
*v = buf->v;
*stride = buf->y_stride;
*uv_stride = buf->u_stride;
assert(buf->u_stride == buf->v_stride);
// data, width and height are checked by Decode().
if (u == NULL || v == NULL || stride == NULL || uv_stride == NULL) {
return NULL;
}
{
WebPDecBuffer output; // only to preserve the side-infos
uint8_t* const out = Decode(MODE_YUV, data, data_size,
width, height, &output);
if (out != NULL) {
const WebPYUVABuffer* const buf = &output.u.YUVA;
*u = buf->u;
*v = buf->v;
*stride = buf->y_stride;
*uv_stride = buf->u_stride;
assert(buf->u_stride == buf->v_stride);
}
return out;
}
return out;
}
static void DefaultFeatures(WebPBitstreamFeatures* const features) {
@ -726,7 +743,64 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
}
memset(config, 0, sizeof(*config));
DefaultFeatures(&config->input);
WebPInitDecBuffer(&config->output);
if (!WebPInitDecBuffer(&config->output)) {
return 0;
}
return 1;
}
static int WebPCheckCropDimensionsBasic(int x, int y, int w, int h) {
return !(x < 0 || y < 0 || w <= 0 || h <= 0);
}
int WebPValidateDecoderConfig(const WebPDecoderConfig* config) {
const WebPDecoderOptions* options;
if (config == NULL) return 0;
if (!IsValidColorspace(config->output.colorspace)) {
return 0;
}
options = &config->options;
// bypass_filtering, no_fancy_upsampling, use_cropping, use_scaling,
// use_threads, flip can be any integer and are interpreted as boolean.
// Check for cropping.
if (options->use_cropping && !WebPCheckCropDimensionsBasic(
options->crop_left, options->crop_top,
options->crop_width, options->crop_height)) {
return 0;
}
// Check for scaling.
if (options->use_scaling &&
(options->scaled_width < 0 || options->scaled_height < 0 ||
(options->scaled_width == 0 && options->scaled_height == 0))) {
return 0;
}
// In case the WebPBitstreamFeatures has been filled in, check further.
if (config->input.width > 0 || config->input.height > 0) {
int scaled_width = options->scaled_width;
int scaled_height = options->scaled_height;
if (options->use_cropping &&
!WebPCheckCropDimensions(config->input.width, config->input.height,
options->crop_left, options->crop_top,
options->crop_width, options->crop_height)) {
return 0;
}
if (options->use_scaling && !WebPRescalerGetScaledDimensions(
config->input.width, config->input.height,
&scaled_width, &scaled_height)) {
return 0;
}
}
// Check for dithering.
if (options->dithering_strength < 0 || options->dithering_strength > 100 ||
options->alpha_dithering_strength < 0 ||
options->alpha_dithering_strength > 100) {
return 0;
}
return 1;
}
@ -765,7 +839,9 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
if (WebPAvoidSlowMemory(params.output, &config->input)) {
// decoding to slow memory: use a temporary in-mem buffer to decode into.
WebPDecBuffer in_mem_buffer;
WebPInitDecBuffer(&in_mem_buffer);
if (!WebPInitDecBuffer(&in_mem_buffer)) {
return VP8_STATUS_INVALID_PARAM;
}
in_mem_buffer.colorspace = config->output.colorspace;
in_mem_buffer.width = config->input.width;
in_mem_buffer.height = config->input.height;
@ -787,8 +863,8 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
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 ||
return WebPCheckCropDimensionsBasic(x, y, w, h) &&
!(x >= image_width || w > image_width || w > image_width - x ||
y >= image_height || h > image_height || h > image_height - y);
}

View File

@ -20,6 +20,7 @@ extern "C" {
#include "src/utils/rescaler_utils.h"
#include "src/dec/vp8_dec.h"
#include "src/webp/decode.h"
//------------------------------------------------------------------------------
// WebPDecParams: Decoding output parameters. Transient internal object.
@ -87,8 +88,9 @@ void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers
// to the *compressed* format, not the output one.
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
VP8Io* const io, WEBP_CSP_MODE src_colorspace);
WEBP_NODISCARD int WebPIoInitFromOptions(
const WebPDecoderOptions* const options, VP8Io* const io,
WEBP_CSP_MODE src_colorspace);
//------------------------------------------------------------------------------
// Internal functions regarding WebPDecBuffer memory (in buffer.c).

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:11:0
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:16:0
libwebpdemuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpdemux.pc

View File

@ -20,6 +20,7 @@
#include "src/utils/utils.h"
#include "src/webp/decode.h"
#include "src/webp/demux.h"
#include "src/webp/types.h"
#define NUM_CHANNELS 4
@ -38,18 +39,18 @@ static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
int num_pixels);
struct WebPAnimDecoder {
WebPDemuxer* demux_; // Demuxer created from given WebP bitstream.
WebPDecoderConfig config_; // Decoder config.
WebPDemuxer* demux; // Demuxer created from given WebP bitstream.
WebPDecoderConfig config; // Decoder config.
// Note: we use a pointer to a function blending multiple pixels at a time to
// allow possible inlining of per-pixel blending function.
BlendRowFunc blend_func_; // Pointer to the chose blend row function.
WebPAnimInfo info_; // Global info about the animation.
uint8_t* curr_frame_; // Current canvas (not disposed).
uint8_t* prev_frame_disposed_; // Previous canvas (properly disposed).
int prev_frame_timestamp_; // Previous frame timestamp (milliseconds).
WebPIterator prev_iter_; // Iterator object for previous frame.
int prev_frame_was_keyframe_; // True if previous frame was a keyframe.
int next_frame_; // Index of the next frame to be decoded
BlendRowFunc blend_func; // Pointer to the chose blend row function.
WebPAnimInfo info; // Global info about the animation.
uint8_t* curr_frame; // Current canvas (not disposed).
uint8_t* prev_frame_disposed; // Previous canvas (properly disposed).
int prev_frame_timestamp; // Previous frame timestamp (milliseconds).
WebPIterator prev_iter; // Iterator object for previous frame.
int prev_frame_was_keyframe; // True if previous frame was a keyframe.
int next_frame; // Index of the next frame to be decoded
// (starting from 1).
};
@ -68,10 +69,11 @@ int WebPAnimDecoderOptionsInitInternal(WebPAnimDecoderOptions* dec_options,
return 1;
}
static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
WebPAnimDecoder* const dec) {
WEBP_NODISCARD static int ApplyDecoderOptions(
const WebPAnimDecoderOptions* const dec_options,
WebPAnimDecoder* const dec) {
WEBP_CSP_MODE mode;
WebPDecoderConfig* config = &dec->config_;
WebPDecoderConfig* config = &dec->config;
assert(dec_options != NULL);
mode = dec_options->color_mode;
@ -79,10 +81,12 @@ static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
mode != MODE_rgbA && mode != MODE_bgrA) {
return 0;
}
dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA)
? &BlendPixelRowNonPremult
: &BlendPixelRowPremult;
WebPInitDecoderConfig(config);
dec->blend_func = (mode == MODE_RGBA || mode == MODE_BGRA)
? &BlendPixelRowNonPremult
: &BlendPixelRowPremult;
if (!WebPInitDecoderConfig(config)) {
return 0;
}
config->output.colorspace = mode;
config->output.is_external_memory = 1;
config->options.use_threads = dec_options->use_threads;
@ -119,22 +123,22 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
}
if (!ApplyDecoderOptions(&options, dec)) goto Error;
dec->demux_ = WebPDemux(webp_data);
if (dec->demux_ == NULL) goto Error;
dec->demux = WebPDemux(webp_data);
if (dec->demux == NULL) goto Error;
dec->info_.canvas_width = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_WIDTH);
dec->info_.canvas_height = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_HEIGHT);
dec->info_.loop_count = WebPDemuxGetI(dec->demux_, WEBP_FF_LOOP_COUNT);
dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR);
dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT);
dec->info.canvas_width = WebPDemuxGetI(dec->demux, WEBP_FF_CANVAS_WIDTH);
dec->info.canvas_height = WebPDemuxGetI(dec->demux, WEBP_FF_CANVAS_HEIGHT);
dec->info.loop_count = WebPDemuxGetI(dec->demux, WEBP_FF_LOOP_COUNT);
dec->info.bgcolor = WebPDemuxGetI(dec->demux, WEBP_FF_BACKGROUND_COLOR);
dec->info.frame_count = WebPDemuxGetI(dec->demux, WEBP_FF_FRAME_COUNT);
// Note: calloc() because we fill frame with zeroes as well.
dec->curr_frame_ = (uint8_t*)WebPSafeCalloc(
dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height);
if (dec->curr_frame_ == NULL) goto Error;
dec->prev_frame_disposed_ = (uint8_t*)WebPSafeCalloc(
dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height);
if (dec->prev_frame_disposed_ == NULL) goto Error;
dec->curr_frame = (uint8_t*)WebPSafeCalloc(
dec->info.canvas_width * NUM_CHANNELS, dec->info.canvas_height);
if (dec->curr_frame == NULL) goto Error;
dec->prev_frame_disposed = (uint8_t*)WebPSafeCalloc(
dec->info.canvas_width * NUM_CHANNELS, dec->info.canvas_height);
if (dec->prev_frame_disposed == NULL) goto Error;
WebPAnimDecoderReset(dec);
return dec;
@ -146,7 +150,7 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) {
if (dec == NULL || info == NULL) return 0;
*info = dec->info_;
*info = dec->info;
return 1;
}
@ -157,8 +161,8 @@ static int IsFullFrame(int width, int height, int canvas_width,
}
// Clear the canvas to transparent.
static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
uint32_t canvas_height) {
WEBP_NODISCARD static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
uint32_t canvas_height) {
const uint64_t size =
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
if (!CheckSizeOverflow(size)) return 0;
@ -179,8 +183,8 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
}
// Copy width * height pixels from 'src' to 'dst'.
static int CopyCanvas(const uint8_t* src, uint8_t* dst,
uint32_t width, uint32_t height) {
WEBP_NODISCARD static int CopyCanvas(const uint8_t* src, uint8_t* dst,
uint32_t width, uint32_t height) {
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
if (!CheckSizeOverflow(size)) return 0;
assert(src != NULL && dst != NULL);
@ -334,25 +338,25 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
if (dec == NULL || buf_ptr == NULL || timestamp_ptr == NULL) return 0;
if (!WebPAnimDecoderHasMoreFrames(dec)) return 0;
width = dec->info_.canvas_width;
height = dec->info_.canvas_height;
blend_row = dec->blend_func_;
width = dec->info.canvas_width;
height = dec->info.canvas_height;
blend_row = dec->blend_func;
// Get compressed frame.
if (!WebPDemuxGetFrame(dec->demux_, dec->next_frame_, &iter)) {
if (!WebPDemuxGetFrame(dec->demux, dec->next_frame, &iter)) {
return 0;
}
timestamp = dec->prev_frame_timestamp_ + iter.duration;
timestamp = dec->prev_frame_timestamp + iter.duration;
// Initialize.
is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_,
dec->prev_frame_was_keyframe_, width, height);
is_key_frame = IsKeyFrame(&iter, &dec->prev_iter,
dec->prev_frame_was_keyframe, width, height);
if (is_key_frame) {
if (!ZeroFillCanvas(dec->curr_frame_, width, height)) {
if (!ZeroFillCanvas(dec->curr_frame, width, height)) {
goto Error;
}
} else {
if (!CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_,
if (!CopyCanvas(dec->prev_frame_disposed, dec->curr_frame,
width, height)) {
goto Error;
}
@ -366,12 +370,12 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
const uint64_t out_offset = (uint64_t)iter.y_offset * stride +
(uint64_t)iter.x_offset * NUM_CHANNELS; // 53b
const uint64_t size = (uint64_t)iter.height * stride; // at most 25 + 27b
WebPDecoderConfig* const config = &dec->config_;
WebPDecoderConfig* const config = &dec->config;
WebPRGBABuffer* const buf = &config->output.u.RGBA;
if ((size_t)size != size) goto Error;
buf->stride = (int)stride;
buf->size = (size_t)size;
buf->rgba = dec->curr_frame_ + out_offset;
buf->rgba = dec->curr_frame + out_offset;
if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) {
goto Error;
@ -384,18 +388,18 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
// that pixel in the previous frame if blending method of is WEBP_MUX_BLEND.
if (iter.frame_num > 1 && iter.blend_method == WEBP_MUX_BLEND &&
!is_key_frame) {
if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_NONE) {
if (dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_NONE) {
int y;
// Blend transparent pixels with pixels in previous canvas.
for (y = 0; y < iter.height; ++y) {
const size_t offset =
(iter.y_offset + y) * width + iter.x_offset;
blend_row((uint32_t*)dec->curr_frame_ + offset,
(uint32_t*)dec->prev_frame_disposed_ + offset, iter.width);
blend_row((uint32_t*)dec->curr_frame + offset,
(uint32_t*)dec->prev_frame_disposed + offset, iter.width);
}
} else {
int y;
assert(dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND);
assert(dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND);
// We need to blend a transparent pixel with its value just after
// initialization. That is, blend it with:
// * Fully transparent pixel if it belongs to prevRect <-- No-op.
@ -403,37 +407,39 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
for (y = 0; y < iter.height; ++y) {
const int canvas_y = iter.y_offset + y;
int left1, width1, left2, width2;
FindBlendRangeAtRow(&iter, &dec->prev_iter_, canvas_y, &left1, &width1,
FindBlendRangeAtRow(&iter, &dec->prev_iter, canvas_y, &left1, &width1,
&left2, &width2);
if (width1 > 0) {
const size_t offset1 = canvas_y * width + left1;
blend_row((uint32_t*)dec->curr_frame_ + offset1,
(uint32_t*)dec->prev_frame_disposed_ + offset1, width1);
blend_row((uint32_t*)dec->curr_frame + offset1,
(uint32_t*)dec->prev_frame_disposed + offset1, width1);
}
if (width2 > 0) {
const size_t offset2 = canvas_y * width + left2;
blend_row((uint32_t*)dec->curr_frame_ + offset2,
(uint32_t*)dec->prev_frame_disposed_ + offset2, width2);
blend_row((uint32_t*)dec->curr_frame + offset2,
(uint32_t*)dec->prev_frame_disposed + offset2, width2);
}
}
}
}
// Update info of the previous frame and dispose it for the next iteration.
dec->prev_frame_timestamp_ = timestamp;
WebPDemuxReleaseIterator(&dec->prev_iter_);
dec->prev_iter_ = iter;
dec->prev_frame_was_keyframe_ = is_key_frame;
CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height);
if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS,
dec->prev_iter_.x_offset, dec->prev_iter_.y_offset,
dec->prev_iter_.width, dec->prev_iter_.height);
dec->prev_frame_timestamp = timestamp;
WebPDemuxReleaseIterator(&dec->prev_iter);
dec->prev_iter = iter;
dec->prev_frame_was_keyframe = is_key_frame;
if (!CopyCanvas(dec->curr_frame, dec->prev_frame_disposed, width, height)) {
goto Error;
}
++dec->next_frame_;
if (dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
ZeroFillFrameRect(dec->prev_frame_disposed, width * NUM_CHANNELS,
dec->prev_iter.x_offset, dec->prev_iter.y_offset,
dec->prev_iter.width, dec->prev_iter.height);
}
++dec->next_frame;
// All OK, fill in the values.
*buf_ptr = dec->curr_frame_;
*buf_ptr = dec->curr_frame;
*timestamp_ptr = timestamp;
return 1;
@ -444,30 +450,30 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) {
if (dec == NULL) return 0;
return (dec->next_frame_ <= (int)dec->info_.frame_count);
return (dec->next_frame <= (int)dec->info.frame_count);
}
void WebPAnimDecoderReset(WebPAnimDecoder* dec) {
if (dec != NULL) {
dec->prev_frame_timestamp_ = 0;
WebPDemuxReleaseIterator(&dec->prev_iter_);
memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_));
dec->prev_frame_was_keyframe_ = 0;
dec->next_frame_ = 1;
dec->prev_frame_timestamp = 0;
WebPDemuxReleaseIterator(&dec->prev_iter);
memset(&dec->prev_iter, 0, sizeof(dec->prev_iter));
dec->prev_frame_was_keyframe = 0;
dec->next_frame = 1;
}
}
const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) {
if (dec == NULL) return NULL;
return dec->demux_;
return dec->demux;
}
void WebPAnimDecoderDelete(WebPAnimDecoder* dec) {
if (dec != NULL) {
WebPDemuxReleaseIterator(&dec->prev_iter_);
WebPDemuxDelete(dec->demux_);
WebPSafeFree(dec->curr_frame_);
WebPSafeFree(dec->prev_frame_disposed_);
WebPDemuxReleaseIterator(&dec->prev_iter);
WebPDemuxDelete(dec->demux);
WebPSafeFree(dec->curr_frame);
WebPSafeFree(dec->prev_frame_disposed);
WebPSafeFree(dec);
}
}

View File

@ -24,53 +24,53 @@
#include "src/webp/format_constants.h"
#define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 2
#define DMUX_REV_VERSION 4
#define DMUX_MIN_VERSION 5
#define DMUX_REV_VERSION 0
typedef struct {
size_t start_; // start location of the data
size_t end_; // end location
size_t riff_end_; // riff chunk end location, can be > end_.
size_t buf_size_; // size of the buffer
const uint8_t* buf_;
size_t start; // start location of the data
size_t end; // end location
size_t riff_end; // riff chunk end location, can be > end.
size_t buf_size; // size of the buffer
const uint8_t* buf;
} MemBuffer;
typedef struct {
size_t offset_;
size_t size_;
size_t offset;
size_t size;
} ChunkData;
typedef struct Frame {
int x_offset_, y_offset_;
int width_, height_;
int has_alpha_;
int duration_;
WebPMuxAnimDispose dispose_method_;
WebPMuxAnimBlend blend_method_;
int frame_num_;
int complete_; // img_components_ contains a full image.
ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH
struct Frame* next_;
int x_offset, y_offset;
int width, height;
int has_alpha;
int duration;
WebPMuxAnimDispose dispose_method;
WebPMuxAnimBlend blend_method;
int frame_num;
int complete; // img_components contains a full image.
ChunkData img_components[2]; // 0=VP8{,L} 1=ALPH
struct Frame* next;
} Frame;
typedef struct Chunk {
ChunkData data_;
struct Chunk* next_;
ChunkData data;
struct Chunk* next;
} Chunk;
struct WebPDemuxer {
MemBuffer mem_;
WebPDemuxState state_;
int is_ext_format_;
uint32_t feature_flags_;
int canvas_width_, canvas_height_;
int loop_count_;
uint32_t bgcolor_;
int num_frames_;
Frame* frames_;
Frame** frames_tail_;
Chunk* chunks_; // non-image chunks
Chunk** chunks_tail_;
MemBuffer mem;
WebPDemuxState state;
int is_ext_format;
uint32_t feature_flags;
int canvas_width, canvas_height;
int loop_count;
uint32_t bgcolor;
int num_frames;
Frame* frames;
Frame** frames_tail;
Chunk* chunks; // non-image chunks
Chunk** chunks_tail;
};
typedef enum {
@ -108,10 +108,10 @@ int WebPGetDemuxVersion(void) {
static int RemapMemBuffer(MemBuffer* const mem,
const uint8_t* data, size_t size) {
if (size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
if (size < mem->buf_size) return 0; // can't remap to a shorter buffer!
mem->buf_ = data;
mem->end_ = mem->buf_size_ = size;
mem->buf = data;
mem->end = mem->buf_size = size;
return 1;
}
@ -123,49 +123,49 @@ static int InitMemBuffer(MemBuffer* const mem,
// Return the remaining data size available in 'mem'.
static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) {
return (mem->end_ - mem->start_);
return (mem->end - mem->start);
}
// Return true if 'size' exceeds the end of the RIFF chunk.
static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) {
return (size > mem->riff_end_ - mem->start_);
return (size > mem->riff_end - mem->start);
}
static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) {
mem->start_ += size;
mem->start += size;
}
static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) {
mem->start_ -= size;
mem->start -= size;
}
static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) {
return mem->buf_ + mem->start_;
return mem->buf + mem->start;
}
// Read from 'mem' and skip the read bytes.
static WEBP_INLINE uint8_t ReadByte(MemBuffer* const mem) {
const uint8_t byte = mem->buf_[mem->start_];
const uint8_t byte = mem->buf[mem->start];
Skip(mem, 1);
return byte;
}
static WEBP_INLINE int ReadLE16s(MemBuffer* const mem) {
const uint8_t* const data = mem->buf_ + mem->start_;
const uint8_t* const data = mem->buf + mem->start;
const int val = GetLE16(data);
Skip(mem, 2);
return val;
}
static WEBP_INLINE int ReadLE24s(MemBuffer* const mem) {
const uint8_t* const data = mem->buf_ + mem->start_;
const uint8_t* const data = mem->buf + mem->start;
const int val = GetLE24(data);
Skip(mem, 3);
return val;
}
static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) {
const uint8_t* const data = mem->buf_ + mem->start_;
const uint8_t* const data = mem->buf + mem->start;
const uint32_t val = GetLE32(data);
Skip(mem, 4);
return val;
@ -175,20 +175,20 @@ static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) {
// Secondary chunk parsing
static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) {
*dmux->chunks_tail_ = chunk;
chunk->next_ = NULL;
dmux->chunks_tail_ = &chunk->next_;
*dmux->chunks_tail = chunk;
chunk->next = NULL;
dmux->chunks_tail = &chunk->next;
}
// Add a frame to the end of the list, ensuring the last frame is complete.
// Returns true on success, false otherwise.
static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
const Frame* const last_frame = *dmux->frames_tail_;
if (last_frame != NULL && !last_frame->complete_) return 0;
const Frame* const last_frame = *dmux->frames_tail;
if (last_frame != NULL && !last_frame->complete) return 0;
*dmux->frames_tail_ = frame;
frame->next_ = NULL;
dmux->frames_tail_ = &frame->next_;
*dmux->frames_tail = frame;
frame->next = NULL;
dmux->frames_tail = &frame->next;
return 1;
}
@ -196,13 +196,13 @@ static void SetFrameInfo(size_t start_offset, size_t size,
int frame_num, int complete,
const WebPBitstreamFeatures* const features,
Frame* const frame) {
frame->img_components_[0].offset_ = start_offset;
frame->img_components_[0].size_ = size;
frame->width_ = features->width;
frame->height_ = features->height;
frame->has_alpha_ |= features->has_alpha;
frame->frame_num_ = frame_num;
frame->complete_ = complete;
frame->img_components[0].offset = start_offset;
frame->img_components[0].size = size;
frame->width = features->width;
frame->height = features->height;
frame->has_alpha |= features->has_alpha;
frame->frame_num = frame_num;
frame->complete = complete;
}
// Store image bearing chunks to 'frame'. 'min_size' is an optional size
@ -218,7 +218,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
if (done) return PARSE_NEED_MORE_DATA;
do {
const size_t chunk_start_offset = mem->start_;
const size_t chunk_start_offset = mem->start;
const uint32_t fourcc = ReadLE32(mem);
const uint32_t payload_size = ReadLE32(mem);
uint32_t payload_size_padded;
@ -238,10 +238,10 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
case MKFOURCC('A', 'L', 'P', 'H'):
if (alpha_chunks == 0) {
++alpha_chunks;
frame->img_components_[1].offset_ = chunk_start_offset;
frame->img_components_[1].size_ = chunk_size;
frame->has_alpha_ = 1;
frame->frame_num_ = frame_num;
frame->img_components[1].offset = chunk_start_offset;
frame->img_components[1].size = chunk_size;
frame->has_alpha = 1;
frame->frame_num = frame_num;
Skip(mem, payload_available);
} else {
goto Done;
@ -256,7 +256,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
// is incomplete.
WebPBitstreamFeatures features;
const VP8StatusCode vp8_status =
WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size,
WebPGetFeatures(mem->buf + chunk_start_offset, chunk_size,
&features);
if (status == PARSE_NEED_MORE_DATA &&
vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) {
@ -281,7 +281,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
break;
}
if (mem->start_ == mem->riff_end_) {
if (mem->start == mem->riff_end) {
done = 1;
} else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
status = PARSE_NEED_MORE_DATA;
@ -310,42 +310,42 @@ static ParseStatus NewFrame(const MemBuffer* const mem,
// 'frame_chunk_size' is the previously validated, padded chunk size.
static ParseStatus ParseAnimationFrame(
WebPDemuxer* const dmux, uint32_t frame_chunk_size) {
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG);
const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
int added_frame = 0;
int bits;
MemBuffer* const mem = &dmux->mem_;
MemBuffer* const mem = &dmux->mem;
Frame* frame;
size_t start_offset;
ParseStatus status =
NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame);
if (status != PARSE_OK) return status;
frame->x_offset_ = 2 * ReadLE24s(mem);
frame->y_offset_ = 2 * ReadLE24s(mem);
frame->width_ = 1 + ReadLE24s(mem);
frame->height_ = 1 + ReadLE24s(mem);
frame->duration_ = ReadLE24s(mem);
frame->x_offset = 2 * ReadLE24s(mem);
frame->y_offset = 2 * ReadLE24s(mem);
frame->width = 1 + ReadLE24s(mem);
frame->height = 1 + ReadLE24s(mem);
frame->duration = ReadLE24s(mem);
bits = ReadByte(mem);
frame->dispose_method_ =
frame->dispose_method =
(bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
if (frame->width * (uint64_t)frame->height >= MAX_IMAGE_AREA) {
WebPSafeFree(frame);
return PARSE_ERROR;
}
// Store a frame only if the animation flag is set there is some data for
// this frame is available.
start_offset = mem->start_;
status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame);
if (status != PARSE_ERROR && mem->start_ - start_offset > anmf_payload_size) {
start_offset = mem->start;
status = StoreFrame(dmux->num_frames + 1, anmf_payload_size, mem, frame);
if (status != PARSE_ERROR && mem->start - start_offset > anmf_payload_size) {
status = PARSE_ERROR;
}
if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) {
if (status != PARSE_ERROR && is_animation && frame->frame_num > 0) {
added_frame = AddFrame(dmux, frame);
if (added_frame) {
++dmux->num_frames_;
++dmux->num_frames;
} else {
status = PARSE_ERROR;
}
@ -364,8 +364,8 @@ static int StoreChunk(WebPDemuxer* const dmux,
Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk));
if (chunk == NULL) return 0;
chunk->data_.offset_ = start_offset;
chunk->data_.size_ = size;
chunk->data.offset = start_offset;
chunk->data.size = size;
AddChunk(dmux, chunk);
return 1;
}
@ -389,9 +389,9 @@ static ParseStatus ReadHeader(MemBuffer* const mem) {
if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
// There's no point in reading past the end of the RIFF chunk
mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE;
if (mem->buf_size_ > mem->riff_end_) {
mem->buf_size_ = mem->end_ = mem->riff_end_;
mem->riff_end = riff_size + CHUNK_HEADER_SIZE;
if (mem->buf_size > mem->riff_end) {
mem->buf_size = mem->end = mem->riff_end;
}
Skip(mem, RIFF_HEADER_SIZE);
@ -400,12 +400,12 @@ static ParseStatus ReadHeader(MemBuffer* const mem) {
static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
const size_t min_size = CHUNK_HEADER_SIZE;
MemBuffer* const mem = &dmux->mem_;
MemBuffer* const mem = &dmux->mem;
Frame* frame;
ParseStatus status;
int image_added = 0;
if (dmux->frames_ != NULL) return PARSE_ERROR;
if (dmux->frames != NULL) return PARSE_ERROR;
if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
@ -414,29 +414,29 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
// For the single image case we allow parsing of a partial frame, so no
// minimum size is imposed here.
status = StoreFrame(1, 0, &dmux->mem_, frame);
status = StoreFrame(1, 0, &dmux->mem, frame);
if (status != PARSE_ERROR) {
const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
const int has_alpha = !!(dmux->feature_flags & ALPHA_FLAG);
// Clear any alpha when the alpha flag is missing.
if (!has_alpha && frame->img_components_[1].size_ > 0) {
frame->img_components_[1].offset_ = 0;
frame->img_components_[1].size_ = 0;
frame->has_alpha_ = 0;
if (!has_alpha && frame->img_components[1].size > 0) {
frame->img_components[1].offset = 0;
frame->img_components[1].size = 0;
frame->has_alpha = 0;
}
// Use the frame width/height as the canvas values for non-vp8x files.
// Also, set ALPHA_FLAG if this is a lossless image with alpha.
if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) {
dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
dmux->canvas_width_ = frame->width_;
dmux->canvas_height_ = frame->height_;
dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
if (!dmux->is_ext_format && frame->width > 0 && frame->height > 0) {
dmux->state = WEBP_DEMUX_PARSED_HEADER;
dmux->canvas_width = frame->width;
dmux->canvas_height = frame->height;
dmux->feature_flags |= frame->has_alpha ? ALPHA_FLAG : 0;
}
if (!AddFrame(dmux, frame)) {
status = PARSE_ERROR; // last frame was left incomplete
} else {
image_added = 1;
dmux->num_frames_ = 1;
dmux->num_frames = 1;
}
}
@ -445,14 +445,14 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
}
static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
MemBuffer* const mem = &dmux->mem_;
const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG);
MemBuffer* const mem = &dmux->mem;
int anim_chunks = 0;
ParseStatus status = PARSE_OK;
do {
int store_chunk = 1;
const size_t chunk_start_offset = mem->start_;
const size_t chunk_start_offset = mem->start;
const uint32_t fourcc = ReadLE32(mem);
const uint32_t chunk_size = ReadLE32(mem);
uint32_t chunk_size_padded;
@ -483,8 +483,8 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
status = PARSE_NEED_MORE_DATA;
} else if (anim_chunks == 0) {
++anim_chunks;
dmux->bgcolor_ = ReadLE32(mem);
dmux->loop_count_ = ReadLE16s(mem);
dmux->bgcolor = ReadLE32(mem);
dmux->loop_count = ReadLE16s(mem);
Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE);
} else {
store_chunk = 0;
@ -498,15 +498,15 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
break;
}
case MKFOURCC('I', 'C', 'C', 'P'): {
store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG);
store_chunk = !!(dmux->feature_flags & ICCP_FLAG);
goto Skip;
}
case MKFOURCC('E', 'X', 'I', 'F'): {
store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG);
store_chunk = !!(dmux->feature_flags & EXIF_FLAG);
goto Skip;
}
case MKFOURCC('X', 'M', 'P', ' '): {
store_chunk = !!(dmux->feature_flags_ & XMP_FLAG);
store_chunk = !!(dmux->feature_flags & XMP_FLAG);
goto Skip;
}
Skip:
@ -527,7 +527,7 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
}
}
if (mem->start_ == mem->riff_end_) {
if (mem->start == mem->riff_end) {
break;
} else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
status = PARSE_NEED_MORE_DATA;
@ -538,12 +538,12 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
}
static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
MemBuffer* const mem = &dmux->mem_;
MemBuffer* const mem = &dmux->mem;
uint32_t vp8x_size;
if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
dmux->is_ext_format_ = 1;
dmux->is_ext_format = 1;
Skip(mem, TAG_SIZE); // VP8X
vp8x_size = ReadLE32(mem);
if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
@ -552,15 +552,15 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR;
if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA;
dmux->feature_flags_ = ReadByte(mem);
dmux->feature_flags = ReadByte(mem);
Skip(mem, 3); // Reserved.
dmux->canvas_width_ = 1 + ReadLE24s(mem);
dmux->canvas_height_ = 1 + ReadLE24s(mem);
if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) {
dmux->canvas_width = 1 + ReadLE24s(mem);
dmux->canvas_height = 1 + ReadLE24s(mem);
if (dmux->canvas_width * (uint64_t)dmux->canvas_height >= MAX_IMAGE_AREA) {
return PARSE_ERROR; // image final dimension is too large
}
Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data.
dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
dmux->state = WEBP_DEMUX_PARSED_HEADER;
if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR;
if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
@ -572,13 +572,13 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
// Format validation
static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
const Frame* const frame = dmux->frames_;
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
const Frame* const frame = dmux->frames;
if (dmux->state == WEBP_DEMUX_PARSING_HEADER) return 1;
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0;
if (dmux->canvas_width <= 0 || dmux->canvas_height <= 0) return 0;
if (dmux->state == WEBP_DEMUX_DONE && frame == NULL) return 0;
if (frame->width_ <= 0 || frame->height_ <= 0) return 0;
if (frame->width <= 0 || frame->height <= 0) return 0;
return 1;
}
@ -587,65 +587,65 @@ static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
static int CheckFrameBounds(const Frame* const frame, int exact,
int canvas_width, int canvas_height) {
if (exact) {
if (frame->x_offset_ != 0 || frame->y_offset_ != 0) {
if (frame->x_offset != 0 || frame->y_offset != 0) {
return 0;
}
if (frame->width_ != canvas_width || frame->height_ != canvas_height) {
if (frame->width != canvas_width || frame->height != canvas_height) {
return 0;
}
} else {
if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0;
if (frame->width_ + frame->x_offset_ > canvas_width) return 0;
if (frame->height_ + frame->y_offset_ > canvas_height) return 0;
if (frame->x_offset < 0 || frame->y_offset < 0) return 0;
if (frame->width + frame->x_offset > canvas_width) return 0;
if (frame->height + frame->y_offset > canvas_height) return 0;
}
return 1;
}
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
const Frame* f = dmux->frames_;
const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG);
const Frame* f = dmux->frames;
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
if (dmux->state == WEBP_DEMUX_PARSING_HEADER) return 1;
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
if (dmux->loop_count_ < 0) return 0;
if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream
if (dmux->canvas_width <= 0 || dmux->canvas_height <= 0) return 0;
if (dmux->loop_count < 0) return 0;
if (dmux->state == WEBP_DEMUX_DONE && dmux->frames == NULL) return 0;
if (dmux->feature_flags & ~ALL_VALID_FLAGS) return 0; // invalid bitstream
while (f != NULL) {
const int cur_frame_set = f->frame_num_;
const int cur_frame_set = f->frame_num;
// Check frame properties.
for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
const ChunkData* const image = f->img_components_;
const ChunkData* const alpha = f->img_components_ + 1;
for (; f != NULL && f->frame_num == cur_frame_set; f = f->next) {
const ChunkData* const image = f->img_components;
const ChunkData* const alpha = f->img_components + 1;
if (!is_animation && f->frame_num_ > 1) return 0;
if (!is_animation && f->frame_num > 1) return 0;
if (f->complete_) {
if (alpha->size_ == 0 && image->size_ == 0) return 0;
if (f->complete) {
if (alpha->size == 0 && image->size == 0) return 0;
// Ensure alpha precedes image bitstream.
if (alpha->size_ > 0 && alpha->offset_ > image->offset_) {
if (alpha->size > 0 && alpha->offset > image->offset) {
return 0;
}
if (f->width_ <= 0 || f->height_ <= 0) return 0;
if (f->width <= 0 || f->height <= 0) return 0;
} else {
// There shouldn't be a partial frame in a complete file.
if (dmux->state_ == WEBP_DEMUX_DONE) return 0;
if (dmux->state == WEBP_DEMUX_DONE) return 0;
// Ensure alpha precedes image bitstream.
if (alpha->size_ > 0 && image->size_ > 0 &&
alpha->offset_ > image->offset_) {
if (alpha->size > 0 && image->size > 0 &&
alpha->offset > image->offset) {
return 0;
}
// There shouldn't be any frames after an incomplete one.
if (f->next_ != NULL) return 0;
if (f->next != NULL) return 0;
}
if (f->width_ > 0 && f->height_ > 0 &&
if (f->width > 0 && f->height > 0 &&
!CheckFrameBounds(f, !is_animation,
dmux->canvas_width_, dmux->canvas_height_)) {
dmux->canvas_width, dmux->canvas_height)) {
return 0;
}
}
@ -657,21 +657,21 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
// WebPDemuxer object
static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
dmux->state_ = WEBP_DEMUX_PARSING_HEADER;
dmux->loop_count_ = 1;
dmux->bgcolor_ = 0xFFFFFFFF; // White background by default.
dmux->canvas_width_ = -1;
dmux->canvas_height_ = -1;
dmux->frames_tail_ = &dmux->frames_;
dmux->chunks_tail_ = &dmux->chunks_;
dmux->mem_ = *mem;
dmux->state = WEBP_DEMUX_PARSING_HEADER;
dmux->loop_count = 1;
dmux->bgcolor = 0xFFFFFFFF; // White background by default.
dmux->canvas_width = -1;
dmux->canvas_height = -1;
dmux->frames_tail = &dmux->frames;
dmux->chunks_tail = &dmux->chunks;
dmux->mem = *mem;
}
static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem,
WebPDemuxer** demuxer) {
WebPBitstreamFeatures features;
const VP8StatusCode status =
WebPGetFeatures(mem->buf_, mem->buf_size_, &features);
WebPGetFeatures(mem->buf, mem->buf_size, &features);
*demuxer = NULL;
if (status != VP8_STATUS_OK) {
return (status == VP8_STATUS_NOT_ENOUGH_DATA) ? PARSE_NEED_MORE_DATA
@ -683,14 +683,14 @@ static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem,
Frame* const frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
if (dmux == NULL || frame == NULL) goto Error;
InitDemux(dmux, mem);
SetFrameInfo(0, mem->buf_size_, 1 /*frame_num*/, 1 /*complete*/, &features,
SetFrameInfo(0, mem->buf_size, 1 /*frame_num*/, 1 /*complete*/, &features,
frame);
if (!AddFrame(dmux, frame)) goto Error;
dmux->state_ = WEBP_DEMUX_DONE;
dmux->canvas_width_ = frame->width_;
dmux->canvas_height_ = frame->height_;
dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
dmux->num_frames_ = 1;
dmux->state = WEBP_DEMUX_DONE;
dmux->canvas_width = frame->width;
dmux->canvas_height = frame->height;
dmux->feature_flags |= frame->has_alpha ? ALPHA_FLAG : 0;
dmux->num_frames = 1;
assert(IsValidSimpleFormat(dmux));
*demuxer = dmux;
return PARSE_OK;
@ -734,7 +734,7 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
return NULL;
}
partial = (mem.buf_size_ < mem.riff_end_);
partial = (mem.buf_size < mem.riff_end);
if (!allow_partial && partial) return NULL;
dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux));
@ -743,16 +743,16 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
status = PARSE_ERROR;
for (parser = kMasterChunks; parser->parse != NULL; ++parser) {
if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) {
if (!memcmp(parser->id, GetBuffer(&dmux->mem), TAG_SIZE)) {
status = parser->parse(dmux);
if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE;
if (status == PARSE_OK) dmux->state = WEBP_DEMUX_DONE;
if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR;
if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR;
if (status == PARSE_ERROR) dmux->state_ = WEBP_DEMUX_PARSE_ERROR;
if (status == PARSE_ERROR) dmux->state = WEBP_DEMUX_PARSE_ERROR;
break;
}
}
if (state != NULL) *state = dmux->state_;
if (state != NULL) *state = dmux->state;
if (status == PARSE_ERROR) {
WebPDemuxDelete(dmux);
@ -766,14 +766,14 @@ void WebPDemuxDelete(WebPDemuxer* dmux) {
Frame* f;
if (dmux == NULL) return;
for (f = dmux->frames_; f != NULL;) {
for (f = dmux->frames; f != NULL;) {
Frame* const cur_frame = f;
f = f->next_;
f = f->next;
WebPSafeFree(cur_frame);
}
for (c = dmux->chunks_; c != NULL;) {
for (c = dmux->chunks; c != NULL;) {
Chunk* const cur_chunk = c;
c = c->next_;
c = c->next;
WebPSafeFree(cur_chunk);
}
WebPSafeFree(dmux);
@ -785,12 +785,12 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) {
if (dmux == NULL) return 0;
switch (feature) {
case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags_;
case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width_;
case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height_;
case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_;
case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor_;
case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames_;
case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags;
case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width;
case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height;
case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count;
case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor;
case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames;
}
return 0;
}
@ -800,8 +800,8 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) {
static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) {
const Frame* f;
for (f = dmux->frames_; f != NULL; f = f->next_) {
if (frame_num == f->frame_num_) break;
for (f = dmux->frames; f != NULL; f = f->next) {
if (frame_num == f->frame_num) break;
}
return f;
}
@ -811,19 +811,19 @@ static const uint8_t* GetFramePayload(const uint8_t* const mem_buf,
size_t* const data_size) {
*data_size = 0;
if (frame != NULL) {
const ChunkData* const image = frame->img_components_;
const ChunkData* const alpha = frame->img_components_ + 1;
size_t start_offset = image->offset_;
*data_size = image->size_;
const ChunkData* const image = frame->img_components;
const ChunkData* const alpha = frame->img_components + 1;
size_t start_offset = image->offset;
*data_size = image->size;
// if alpha exists it precedes image, update the size allowing for
// intervening chunks.
if (alpha->size_ > 0) {
const size_t inter_size = (image->offset_ > 0)
? image->offset_ - (alpha->offset_ + alpha->size_)
if (alpha->size > 0) {
const size_t inter_size = (image->offset > 0)
? image->offset - (alpha->offset + alpha->size)
: 0;
start_offset = alpha->offset_;
*data_size += alpha->size_ + inter_size;
start_offset = alpha->offset;
*data_size += alpha->size + inter_size;
}
return mem_buf + start_offset;
}
@ -834,23 +834,23 @@ static const uint8_t* GetFramePayload(const uint8_t* const mem_buf,
static int SynthesizeFrame(const WebPDemuxer* const dmux,
const Frame* const frame,
WebPIterator* const iter) {
const uint8_t* const mem_buf = dmux->mem_.buf_;
const uint8_t* const mem_buf = dmux->mem.buf;
size_t payload_size = 0;
const uint8_t* const payload = GetFramePayload(mem_buf, frame, &payload_size);
if (payload == NULL) return 0;
assert(frame != NULL);
iter->frame_num = frame->frame_num_;
iter->num_frames = dmux->num_frames_;
iter->x_offset = frame->x_offset_;
iter->y_offset = frame->y_offset_;
iter->width = frame->width_;
iter->height = frame->height_;
iter->has_alpha = frame->has_alpha_;
iter->duration = frame->duration_;
iter->dispose_method = frame->dispose_method_;
iter->blend_method = frame->blend_method_;
iter->complete = frame->complete_;
iter->frame_num = frame->frame_num;
iter->num_frames = dmux->num_frames;
iter->x_offset = frame->x_offset;
iter->y_offset = frame->y_offset;
iter->width = frame->width;
iter->height = frame->height;
iter->has_alpha = frame->has_alpha;
iter->duration = frame->duration;
iter->dispose_method = frame->dispose_method;
iter->blend_method = frame->blend_method;
iter->complete = frame->complete;
iter->fragment.bytes = payload;
iter->fragment.size = payload_size;
return 1;
@ -860,8 +860,8 @@ static int SetFrame(int frame_num, WebPIterator* const iter) {
const Frame* frame;
const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
if (dmux == NULL || frame_num < 0) return 0;
if (frame_num > dmux->num_frames_) return 0;
if (frame_num == 0) frame_num = dmux->num_frames_;
if (frame_num > dmux->num_frames) return 0;
if (frame_num == 0) frame_num = dmux->num_frames;
frame = GetFrame(dmux, frame_num);
if (frame == NULL) return 0;
@ -896,11 +896,11 @@ void WebPDemuxReleaseIterator(WebPIterator* iter) {
// Chunk iteration
static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) {
const uint8_t* const mem_buf = dmux->mem_.buf_;
const uint8_t* const mem_buf = dmux->mem.buf;
const Chunk* c;
int count = 0;
for (c = dmux->chunks_; c != NULL; c = c->next_) {
const uint8_t* const header = mem_buf + c->data_.offset_;
for (c = dmux->chunks; c != NULL; c = c->next) {
const uint8_t* const header = mem_buf + c->data.offset;
if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
}
return count;
@ -908,11 +908,11 @@ static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) {
static const Chunk* GetChunk(const WebPDemuxer* const dmux,
const char fourcc[4], int chunk_num) {
const uint8_t* const mem_buf = dmux->mem_.buf_;
const uint8_t* const mem_buf = dmux->mem.buf;
const Chunk* c;
int count = 0;
for (c = dmux->chunks_; c != NULL; c = c->next_) {
const uint8_t* const header = mem_buf + c->data_.offset_;
for (c = dmux->chunks; c != NULL; c = c->next) {
const uint8_t* const header = mem_buf + c->data.offset;
if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
if (count == chunk_num) break;
}
@ -930,10 +930,10 @@ static int SetChunk(const char fourcc[4], int chunk_num,
if (chunk_num == 0) chunk_num = count;
if (chunk_num <= count) {
const uint8_t* const mem_buf = dmux->mem_.buf_;
const uint8_t* const mem_buf = dmux->mem.buf;
const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num);
iter->chunk.bytes = mem_buf + chunk->data_.offset_ + CHUNK_HEADER_SIZE;
iter->chunk.size = chunk->data_.size_ - CHUNK_HEADER_SIZE;
iter->chunk.bytes = mem_buf + chunk->data.offset + CHUNK_HEADER_SIZE;
iter->chunk.size = chunk->data.size - CHUNK_HEADER_SIZE;
iter->num_chunks = count;
iter->chunk_num = chunk_num;
return 1;

Some files were not shown because too many files have changed in this diff Show More