mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-16 13:59:51 +02:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
20ceff7eb3 | |||
258f74e883 | |||
d21fa8d4c2 | |||
34ddf5b232 | |||
17674ecf85 | |||
7dfde712a4 | |||
059d4a59c2 | |||
113968ca47 |
1
.mailmap
1
.mailmap
@ -11,4 +11,3 @@ Vikas Arora <vikasa@google.com>
|
||||
Tamar Levy <tamar.levy@intel.com>
|
||||
<qrczak@google.com> <qrczak>
|
||||
Hui Su <huisu@google.com>
|
||||
James Zern <jzern@google.com>
|
||||
|
4
AUTHORS
4
AUTHORS
@ -4,11 +4,8 @@ Contributors:
|
||||
- Charles Munger (clm at google dot com)
|
||||
- Cheng Yi (cyi at google dot com)
|
||||
- Christian Duvivier (cduvivier at google dot com)
|
||||
- Christopher Degawa (ccom at randomderp dot com)
|
||||
- Clement Courbet (courbet at google dot com)
|
||||
- Djordje Pesut (djordje dot pesut at imgtec dot com)
|
||||
- Hui Su (huisu at google dot com)
|
||||
- Ilya Kurdyukov (jpegqs at gmail dot com)
|
||||
- Ingvar Stepanyan (rreverser at google dot com)
|
||||
- James Zern (jzern at google dot com)
|
||||
- Jan Engelhardt (jengelh at medozas dot de)
|
||||
@ -48,4 +45,3 @@ Contributors:
|
||||
- Wan-Teh Chang (wtc at google dot com)
|
||||
- Yang Zhang (yang dot zhang at arm dot com)
|
||||
- Yannis Guyon (yguyon at google dot com)
|
||||
- Zhi An Ng (zhin at chromium dot org)
|
||||
|
@ -74,7 +74,6 @@ dsp_dec_srcs := \
|
||||
src/dsp/lossless_msa.c \
|
||||
src/dsp/lossless_neon.$(NEON) \
|
||||
src/dsp/lossless_sse2.c \
|
||||
src/dsp/lossless_sse41.c \
|
||||
src/dsp/rescaler.c \
|
||||
src/dsp/rescaler_mips32.c \
|
||||
src/dsp/rescaler_mips_dsp_r2.c \
|
||||
|
110
CMakeLists.txt
110
CMakeLists.txt
@ -1,17 +1,14 @@
|
||||
# Copyright (c) 2020 Google LLC.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
##
|
||||
## Copyright (c) 2020 Google LLC.
|
||||
##
|
||||
## Use of this source code is governed by a BSD-style license
|
||||
## that can be found in the LICENSE file in the root of the source
|
||||
## tree. An additional intellectual property rights grant can be found
|
||||
## in the file PATENTS. All contributing project authors may
|
||||
## be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
if(POLICY CMP0072)
|
||||
cmake_policy(SET CMP0072 NEW)
|
||||
endif()
|
||||
|
||||
project(WebP C)
|
||||
|
||||
# Options for coder / decoder executables.
|
||||
@ -29,11 +26,9 @@ option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." ON)
|
||||
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." ON)
|
||||
option(WEBP_BUILD_VWEBP "Build the vwebp viewer tool." ON)
|
||||
option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." ON)
|
||||
option(WEBP_BUILD_LIBWEBPMUX "Build the libwebpmux library." ON)
|
||||
option(WEBP_BUILD_WEBPMUX "Build the webpmux command line tool." ON)
|
||||
option(WEBP_BUILD_EXTRAS "Build extras." ON)
|
||||
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
|
||||
option(WEBP_USE_THREAD "Enable threading support" ON)
|
||||
option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
|
||||
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
|
||||
OFF)
|
||||
@ -55,7 +50,6 @@ if(WEBP_BUILD_WEBP_JS)
|
||||
set(WEBP_BUILD_WEBPINFO OFF)
|
||||
set(WEBP_BUILD_WEBPMUX OFF)
|
||||
set(WEBP_BUILD_EXTRAS OFF)
|
||||
set(WEBP_USE_THREAD OFF)
|
||||
|
||||
if(WEBP_ENABLE_SIMD)
|
||||
message("wasm2js does not support SIMD, disabling webp.js generation.")
|
||||
@ -283,12 +277,10 @@ 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>)
|
||||
target_include_directories(webp
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
PUBLIC $<INSTALL_INTERFACE:include>)
|
||||
set_target_properties(
|
||||
webp
|
||||
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
|
||||
@ -323,10 +315,10 @@ ${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)
|
||||
function(parse_version FILE NAME VAR)
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/${FILE} SOURCE_FILE)
|
||||
string(REGEX MATCH
|
||||
"${NAME_IN_MAKEFILE}_la_LDFLAGS[^\n]* -version-info [0-9:]+"
|
||||
"${NAME}_la_LDFLAGS[^\n]* -version-info [0-9:]+"
|
||||
TMP
|
||||
${SOURCE_FILE})
|
||||
string(REGEX MATCH
|
||||
@ -335,35 +327,29 @@ macro(set_version FILE TARGET_NAME NAME_IN_MAKEFILE)
|
||||
${TMP})
|
||||
string(REGEX
|
||||
REPLACE ":"
|
||||
" "
|
||||
LT_VERSION
|
||||
"."
|
||||
VERSION
|
||||
${TMP})
|
||||
|
||||
# See the libtool docs for more information:
|
||||
# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
|
||||
#
|
||||
# c=<current>, a=<age>, r=<revision>
|
||||
#
|
||||
# libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is
|
||||
# passed to libtool.
|
||||
#
|
||||
# We set FULL = [c-a].a.r and MAJOR = [c-a].
|
||||
separate_arguments(LT_VERSION)
|
||||
list(GET LT_VERSION 0 LT_CURRENT)
|
||||
list(GET LT_VERSION 1 LT_REVISION)
|
||||
list(GET LT_VERSION 2 LT_AGE)
|
||||
math(EXPR LT_CURRENT_MINUS_AGE "${LT_CURRENT} - ${LT_AGE}")
|
||||
|
||||
set_target_properties(
|
||||
${TARGET_NAME}
|
||||
PROPERTIES VERSION
|
||||
${LT_CURRENT_MINUS_AGE}.${LT_AGE}.${LT_REVISION}
|
||||
SOVERSION
|
||||
${LT_CURRENT_MINUS_AGE})
|
||||
endmacro()
|
||||
set_version(Makefile.am webp webp)
|
||||
set_version(Makefile.am webpdecoder webpdecoder)
|
||||
set_version(demux/Makefile.am webpdemux webpdemux)
|
||||
set(${VAR} "${VERSION}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
parse_version(Makefile.am webp WEBP_WEBP_SOVERSION)
|
||||
set_target_properties(webp
|
||||
PROPERTIES VERSION
|
||||
${PACKAGE_VERSION}
|
||||
SOVERSION
|
||||
${WEBP_WEBP_SOVERSION})
|
||||
parse_version(Makefile.am webpdecoder WEBP_DECODER_SOVERSION)
|
||||
set_target_properties(webpdecoder
|
||||
PROPERTIES VERSION
|
||||
${PACKAGE_VERSION}
|
||||
SOVERSION
|
||||
${WEBP_DECODER_SOVERSION})
|
||||
parse_version(demux/Makefile.am webpdemux WEBP_DEMUX_SOVERSION)
|
||||
set_target_properties(webpdemux
|
||||
PROPERTIES VERSION
|
||||
${PACKAGE_VERSION}
|
||||
SOVERSION
|
||||
${WEBP_DEMUX_SOVERSION})
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE)
|
||||
string(REGEX MATCH
|
||||
"AC_INIT\\([^\n]*\\[[0-9\\.]+\\]"
|
||||
@ -391,12 +377,6 @@ foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
|
||||
${SIMD_COMPILE_FLAG})
|
||||
endforeach()
|
||||
|
||||
if(NOT WEBP_BUILD_LIBWEBPMUX)
|
||||
set(WEBP_BUILD_GIF2WEBP OFF)
|
||||
set(WEBP_BUILD_IMG2WEBP OFF)
|
||||
set(WEBP_BUILD_WEBPMUX OFF)
|
||||
endif()
|
||||
|
||||
if(WEBP_BUILD_GIF2WEBP AND NOT GIF_FOUND)
|
||||
set(WEBP_BUILD_GIF2WEBP OFF)
|
||||
endif()
|
||||
@ -469,14 +449,19 @@ if(WEBP_BUILD_CWEBP)
|
||||
install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
if(WEBP_BUILD_LIBWEBPMUX)
|
||||
if(WEBP_BUILD_GIF2WEBP OR WEBP_BUILD_IMG2WEBP)
|
||||
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)
|
||||
parse_version(mux/Makefile.am webpmux WEBP_MUX_SOVERSION)
|
||||
set_target_properties(libwebpmux
|
||||
PROPERTIES VERSION
|
||||
${PACKAGE_VERSION}
|
||||
SOVERSION
|
||||
${WEBP_MUX_SOVERSION})
|
||||
set_target_properties(libwebpmux
|
||||
PROPERTIES PUBLIC_HEADER
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
|
||||
@ -582,6 +567,7 @@ if(WEBP_BUILD_EXTRAS)
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||
install(TARGETS get_disto RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# webp_quality
|
||||
add_executable(webp_quality ${WEBP_QUALITY_SRCS} ${WEBP_EXTRAS_SRCS})
|
||||
@ -589,6 +575,7 @@ if(WEBP_BUILD_EXTRAS)
|
||||
target_include_directories(webp_quality
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
install(TARGETS webp_quality RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# vwebp_sdl
|
||||
find_package(SDL)
|
||||
@ -603,6 +590,7 @@ if(WEBP_BUILD_EXTRAS)
|
||||
${SDL_INCLUDE_DIR})
|
||||
set(WEBP_HAVE_SDL 1)
|
||||
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
|
||||
install(TARGETS vwebp_sdl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -618,7 +606,7 @@ if(WEBP_BUILD_WEBP_JS)
|
||||
webp_js
|
||||
PROPERTIES LINK_FLAGS "-s WASM=0 \
|
||||
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
|
||||
-s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
|
||||
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
||||
endif()
|
||||
@ -631,7 +619,7 @@ if(WEBP_BUILD_WEBP_JS)
|
||||
webp_wasm
|
||||
PROPERTIES LINK_FLAGS "-s WASM=1 \
|
||||
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
|
||||
-s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
||||
|
||||
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
|
||||
@ -649,6 +637,7 @@ if(WEBP_BUILD_ANIM_UTILS)
|
||||
imageenc
|
||||
imageioutil
|
||||
webp
|
||||
libwebpmux
|
||||
webpdemux
|
||||
${WEBP_DEP_GIF_LIBRARIES})
|
||||
target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||
@ -664,6 +653,7 @@ if(WEBP_BUILD_ANIM_UTILS)
|
||||
imageenc
|
||||
imageioutil
|
||||
webp
|
||||
libwebpmux
|
||||
webpdemux
|
||||
${WEBP_DEP_GIF_LIBRARIES})
|
||||
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||
|
@ -1,29 +0,0 @@
|
||||
# How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement. You (or your employer) retain the copyright to your contribution;
|
||||
this simply gives us permission to use and redistribute your contributions as
|
||||
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||
your current agreements on file or to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use a [Gerrit](https://www.gerritcodereview.com) instance hosted at
|
||||
https://chromium-review.googlesource.com for this purpose. See the
|
||||
[WebM Project page](https://www.webmproject.org/code/contribute/submitting-patches/)
|
||||
for additional details.
|
||||
|
||||
## Community Guidelines
|
||||
|
||||
This project follows
|
||||
[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).
|
99
ChangeLog
99
ChangeLog
@ -1,109 +1,10 @@
|
||||
d9191588 fuzzer/*: normalize src/ includes
|
||||
53b6f762 fix indent
|
||||
731246ba update ChangeLog (tag: v1.2.1-rc2)
|
||||
d250f01d dsp/*: use WEBP_HAVE_* to determine Init availability
|
||||
3a4d3ecd update NEWS
|
||||
b2bc8093 bump version to 1.2.1
|
||||
e542fc7a update AUTHORS
|
||||
e0241154 Merge "libwebp/CMake: Add <BUILD_INTERFACE> to webp incl" into main
|
||||
edea6444 libwebp/CMake: Add <BUILD_INTERFACE> to webp incl
|
||||
ece18e55 dsp.h: respect --disable-sse2/sse4.1/neon
|
||||
a89a3230 wicdec: support alpha from WebP WIC decoder
|
||||
26f4aa01 Merge "alpha_processing: fix visual studio warnings" into main
|
||||
8f594663 alpha_processing: fix visual studio warnings
|
||||
46d844e6 Merge "cpu.cmake: fix compiler flag detection w/3.17.0+" into main
|
||||
298d26ea Merge changes I593adf92,If20675e7,Ifac68eac into main
|
||||
a1e5dae0 alpha_processing*: use WEBP_RESTRICT qualifier
|
||||
327ef24f cpu.cmake: fix compiler flag detection w/3.17.0+
|
||||
f70819de configure: enable libwebpmux by default
|
||||
dc7e2b42 configure: add informational notices when disabling binaries
|
||||
9df23ddd configure: move lib flag checks before binaries
|
||||
a2e18f10 Merge "WebPConfig.config.in: correct WEBP_INCLUDE_DIRS" into main
|
||||
e1a8d4f3 Merge "bit_reader_inl_utils: uniformly apply WEBP_RESTRICT" into main
|
||||
4de35f43 rescaler.c: fix alignment
|
||||
0f13eec7 bit_reader_inl_utils: uniformly apply WEBP_RESTRICT
|
||||
277d3074 Fix size_t overflow in WebPRescalerInit
|
||||
97adbba5 WebPConfig.config.in: correct WEBP_INCLUDE_DIRS
|
||||
b60d4603 advanced_api_fuzzer: add extreme config value coverage
|
||||
72fe52f6 anim_encode.c,cosmetics: normalize indent
|
||||
116d235c anim_encode: Fix encoded_frames_[] overflow
|
||||
6f445b3e CMake: set CMP0072 to NEW
|
||||
b1cf887f define WEBP_RESTRICT for MSVC
|
||||
3e265136 Add WEBP_RESTRICT & use it in VP8BitReader
|
||||
f6d29247 vp8l_dec::ProcessRows: fix int overflow in multiply
|
||||
de3b4ba8 CMake: add WEBP_BUILD_LIBWEBPMUX
|
||||
7f09d3d1 CMakeLists.txt: rm libwebpmux dep from anim_{diff,dump}
|
||||
4edea4a6 Init{RGB,YUV}Rescaler: fix a few more int overflows
|
||||
c9e26bdb rescaler_utils: set max valid scaled w/h to INT_MAX/2
|
||||
28d488e6 utils.h: add SizeOverflow()
|
||||
695bdaa2 Export/EmitRescaledRowsRGBA: fix pointer offset int overflow
|
||||
685d073e Init{RGB,YUV}Rescaler: fix int overflows in multiplication
|
||||
d38bd0dd WebPFlipBuffer: fix integer overflow
|
||||
109ff0f1 utils: allow MALLOC_LIMIT to indicate a max
|
||||
a2fce867 WebPRescalerImportRowExpand_C: promote some vals before multiply
|
||||
776983d4 AllocateBuffer: fix int multiplication overflow check
|
||||
315abbd6 Merge "Revert "Do not use a palette for one color images.""
|
||||
eae815d0 Merge changes Ica3bbf75,I82f82954
|
||||
afbca5a1 Require Emscripten 2.0.18
|
||||
3320416b CMakeLists,emscripten: use EXPORTED_RUNTIME_METHODS
|
||||
29145ed6 Update README instructions for using Emscripten
|
||||
1f579139 cosmetics: remove use of 'sanity' / 'master'
|
||||
29b6129c WebPAnimEncoderNewInternal: remove some unnecessary inits
|
||||
b60869a1 Revert "Do not use a palette for one color images."
|
||||
6fb4cddc demux: move padded size calc post unpadded validation
|
||||
05b72d42 vp8l_enc.c: normalize index types
|
||||
b6513fba Do not use a palette for one color images.
|
||||
98bbe35b Fix multi-threading with palettes.
|
||||
b1674240 Add modified Zeng's method to palette sorting.
|
||||
88c90c45 add CONTRIBUTING.md
|
||||
6a9916d7 WebPRescalerInit: add missing int64_t promotion
|
||||
b6cf52d5 WebPIoInitFromOptions: treat use_scaling as a bool
|
||||
3b12b7f4 WebPIoInitFromOptions: treat use_cropping as a bool
|
||||
595fa13f add WebPCheckCropDimensions()
|
||||
8fdaecb0 Disable cross-color when palette is used.
|
||||
8933bac2 WebPIoInitFromOptions: respect incoming bypass_filtering val
|
||||
7d416ff0 webpdec,cosmetics: match error text to function call
|
||||
ec6cfeb5 Fix typo on WebPPictureAlloc() in README
|
||||
7e58a1a2 *.cmake: add license header
|
||||
5651a6b2 cmake: fix .so versioning
|
||||
25ae67b3 xcframeworkbuild.sh: add arm64 simulator target
|
||||
5d4ee4c3 cosmetics: remove use of the term 'dummy'
|
||||
01b38ee1 faster CollectColorXXXTransforms_SSE41
|
||||
652aa344 Merge "Use BitCtz for FastSLog2Slow_C"
|
||||
0320e1e3 add the missing default BitsCtz() code
|
||||
8886f620 Use BitCtz for FastSLog2Slow_C
|
||||
fae41617 faster CombinedShannonEntropy_SSE2
|
||||
5bd2704e Introduce the BitCtz() function.
|
||||
fee64287 Merge "wicdec,icc: treat unsupported op as non-fatal"
|
||||
33ddb894 lossless_sse{2,41}: remove some unneeded includes
|
||||
b27ea852 wicdec,icc: treat unsupported op as non-fatal
|
||||
b78494a9 Merge "Fix undefined signed shift."
|
||||
e79974cd Fix undefined signed shift.
|
||||
a8853394 SSE4.1 versions of BGRA to RGB/BGR color-space conversions
|
||||
a09a6472 SSE4.1 version of TransformColorInverse
|
||||
401da22b Merge "pngdec: check version before using png_get_chunk_malloc_max"
|
||||
26907822 pngdec: check version before using png_get_chunk_malloc_max
|
||||
06c1e72e Code cleanup
|
||||
8f0d41aa Merge changes Id135bbf4,I99e59797
|
||||
373eb170 gif2webp: don't store loop-count if there's only 1 frame
|
||||
759b9d5a cmake: add WEBP_USE_THREAD option
|
||||
926ce921 cmake: don't install binaries from extras/
|
||||
9c367bc6 WebPAnimDecoderNewInternal: validate bitstream before alloc
|
||||
47f64f6e filters_sse2: import Chromium change
|
||||
cc3577e9 fuzzer/*: use src/ based include paths
|
||||
004d77ff Merge tag 'v1.2.0'
|
||||
fedac6cc update ChangeLog (tag: v1.2.0-rc3, tag: v1.2.0)
|
||||
170a8712 Fix check_c_source_compiles with pthread.
|
||||
ceddb5fc Fix check_c_source_compiles with pthread.
|
||||
85995719 disable CombinedShannonEntropy_SSE2 on x86
|
||||
289757fe TiffDec: enforce stricter mem/dimension limit on tiles
|
||||
8af7436f Merge "{ios,xcframework}build.sh: make min version(s) more visible" into 1.2.0
|
||||
e56c3c5b pngdec: raise memory limit if needed
|
||||
8696147d pngdec: raise memory limit if needed
|
||||
13b8e9fe {ios,xcframework}build.sh: make min version(s) more visible
|
||||
a9225410 animdecoder_fuzzer: fix memory leak
|
||||
d6c2285d update gradle to 6.1.1
|
||||
8df77fb1 animdecoder_fuzzer: fix memory leak
|
||||
52ce6333 update NEWS
|
||||
28c49820 bump version to 1.2.0
|
||||
7363dff2 webp/encode.h: restore WEBP_ENCODER_ABI_VERSION to v1.1.0
|
||||
|
@ -215,7 +215,6 @@ DSP_DEC_OBJS = \
|
||||
$(DIROBJ)\dsp\lossless_msa.obj \
|
||||
$(DIROBJ)\dsp\lossless_neon.obj \
|
||||
$(DIROBJ)\dsp\lossless_sse2.obj \
|
||||
$(DIROBJ)\dsp\lossless_sse41.obj \
|
||||
$(DIROBJ)\dsp\rescaler.obj \
|
||||
$(DIROBJ)\dsp\rescaler_mips32.obj \
|
||||
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
|
||||
|
12
NEWS
12
NEWS
@ -1,15 +1,3 @@
|
||||
- 7/20/2021: version 1.2.1
|
||||
This is a binary compatible release.
|
||||
* minor lossless encoder improvements and x86 color conversion speed up
|
||||
* add ARM64 simulator support to xcframeworkbuild.sh (#510)
|
||||
* further security related hardening in libwebp & examples
|
||||
(issues: #497, #508, #518)
|
||||
(chromium: #1196480, #1196773, #1196775, #1196777, #1196778, #1196850)
|
||||
(oss-fuzz: #28658, #28978)
|
||||
* toolchain updates and bug fixes (#498, #501, #502, #504, #505, #506, #509,
|
||||
#533)
|
||||
* use more inclusive language within the source (#507)
|
||||
|
||||
- 12/23/2020: version 1.2.0
|
||||
* API changes:
|
||||
- libwebp:
|
||||
|
4
README
4
README
@ -4,7 +4,7 @@
|
||||
\__\__/\____/\_____/__/ ____ ___
|
||||
/ _/ / \ \ / _ \/ _/
|
||||
/ \_/ / / \ \ __/ \__
|
||||
\____/____/\_____/_____/____/v1.2.1
|
||||
\____/____/\_____/_____/____/v1.2.0
|
||||
|
||||
Description:
|
||||
============
|
||||
@ -619,7 +619,7 @@ The encoding flow looks like:
|
||||
pic.width = width;
|
||||
pic.height = height;
|
||||
// allocated picture of dimension width x height
|
||||
if (!WebPPictureAlloc(&pic)) {
|
||||
if (!WebPPictureAllocate(&pic)) {
|
||||
return 0; // memory error
|
||||
}
|
||||
// at this point, 'pic' has been initialized as a container,
|
||||
|
@ -1,7 +1,7 @@
|
||||
__ __ ____ ____ ____ __ __ _ __ __
|
||||
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
|
||||
\ / __/ _ \ __/ / / (_/ /__
|
||||
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.2.1
|
||||
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.2.0
|
||||
|
||||
|
||||
Description:
|
||||
|
@ -10,18 +10,26 @@ This file describes the compilation of libwebp into a JavaScript decoder
|
||||
using Emscripten and CMake.
|
||||
|
||||
- install the Emscripten SDK following the procedure described at:
|
||||
https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended
|
||||
https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
|
||||
After installation, you should have some global variable positioned to the
|
||||
location of the SDK. In particular, $EMSDK should point to the
|
||||
location of the SDK. In particular, $EMSCRIPTEN should point to the
|
||||
top-level directory containing Emscripten tools.
|
||||
|
||||
- make sure the file $EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake is
|
||||
accessible. This is the toolchain file used by CMake to invoke Emscripten.
|
||||
If $EMSCRIPTEN is unset search for Emscripten.cmake under $EMSDK and set
|
||||
$EMSCRIPTEN accordingly, for example:
|
||||
unix-like environments: export EMSCRIPTEN=$EMSDK/upstream/emscripten
|
||||
windows: set EMSCRIPTEN=%EMSDK%\upstream\emscripten
|
||||
|
||||
- configure the project 'WEBP_JS' with CMake using:
|
||||
|
||||
cd webp_js && \
|
||||
emcmake cmake -DWEBP_BUILD_WEBP_JS=ON \
|
||||
cmake -DWEBP_BUILD_WEBP_JS=ON \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
|
||||
../
|
||||
|
||||
- compile webp.js using 'emmake make'.
|
||||
- compile webp.js using 'make'.
|
||||
|
||||
- that's it! Upon completion, you should have the webp.js and
|
||||
webp.wasm files generated.
|
||||
@ -50,7 +58,7 @@ Web-Assembly (WASM) version:
|
||||
See webp_js/index_wasm.html for a simple demo page using the WASM version
|
||||
of the library.
|
||||
|
||||
You will need a fairly recent version of Emscripten (at least 2.0.18,
|
||||
You will need a fairly recent version of Emscripten (at least 1.37.8,
|
||||
latest-upstream is recommended) and of your WASM-enabled browser to run this
|
||||
version.
|
||||
|
||||
|
@ -141,7 +141,6 @@ model {
|
||||
include "lossless_msa.c"
|
||||
include "lossless_neon.$NEON"
|
||||
include "lossless_sse2.c"
|
||||
include "lossless_sse41.c"
|
||||
include "rescaler.c"
|
||||
include "rescaler_mips32.c"
|
||||
include "rescaler_mips_dsp_r2.c"
|
||||
|
@ -5,7 +5,7 @@ set(WEBP_VERSION ${WebP_VERSION})
|
||||
|
||||
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
|
||||
set(WebP_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||
set(WebP_INCLUDE_DIRS "webp")
|
||||
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
|
||||
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
|
||||
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
|
||||
|
@ -1,11 +1,3 @@
|
||||
# Copyright (c) 2021 Google LLC.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
# Check for SIMD extensions.
|
||||
include(CMakePushCheckState)
|
||||
|
||||
@ -125,12 +117,6 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
||||
list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
||||
include(CheckCCompilerFlag)
|
||||
if(SIMD_COMPILE_FLAG)
|
||||
# Between 3.17.0 and 3.18.2 check_cxx_compiler_flag() sets a normal
|
||||
# variable at parent scope while check_cxx_source_compiles() continues
|
||||
# to set an internal cache variable, so we unset both to avoid the
|
||||
# failure / success state persisting between checks. See
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/21207.
|
||||
unset(HAS_COMPILE_FLAG)
|
||||
unset(HAS_COMPILE_FLAG CACHE)
|
||||
check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
|
||||
if(HAS_COMPILE_FLAG)
|
||||
@ -148,7 +134,6 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
||||
"warning: argument unused during compilation:"
|
||||
${COMMON_PATTERNS})
|
||||
if(NOT FLAG_${SIMD_COMPILE_FLAG})
|
||||
unset(HAS_COMPILE_FLAG)
|
||||
unset(HAS_COMPILE_FLAG CACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -1,11 +1,3 @@
|
||||
# Copyright (c) 2021 Google LLC.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
# Generate the config.h to compile with specific intrinsics / libs.
|
||||
|
||||
# Check for compiler options.
|
||||
@ -30,25 +22,26 @@ check_c_source_compiles("
|
||||
" HAVE_BUILTIN_BSWAP64)
|
||||
|
||||
# Check for libraries.
|
||||
if(WEBP_USE_THREAD)
|
||||
if(NOT WEBP_BUILD_WEBP_JS)
|
||||
# Disable pThreads for WASM.
|
||||
find_package(Threads)
|
||||
if(Threads_FOUND)
|
||||
# work around cmake bug on QNX (https://cmake.org/Bug/view.php?id=11333)
|
||||
if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
#include <pthread.h>
|
||||
int main (void) {
|
||||
int attr = PTHREAD_PRIO_INHERIT;
|
||||
return attr;
|
||||
}
|
||||
" FLAG_HAVE_PTHREAD_PRIO_INHERIT)
|
||||
set(HAVE_PTHREAD_PRIO_INHERIT ${FLAG_HAVE_PTHREAD_PRIO_INHERIT})
|
||||
list(APPEND WEBP_DEP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
set(WEBP_USE_THREAD ${Threads_FOUND})
|
||||
endif()
|
||||
if(Threads_FOUND)
|
||||
# work around cmake bug on QNX (https://cmake.org/Bug/view.php?id=11333)
|
||||
if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
#include <pthread.h>
|
||||
int main (void) {
|
||||
int attr = PTHREAD_PRIO_INHERIT;
|
||||
return attr;
|
||||
}
|
||||
" FLAG_HAVE_PTHREAD_PRIO_INHERIT)
|
||||
set(HAVE_PTHREAD_PRIO_INHERIT ${FLAG_HAVE_PTHREAD_PRIO_INHERIT})
|
||||
list(APPEND WEBP_DEP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
set(WEBP_USE_THREAD ${Threads_FOUND})
|
||||
|
||||
# TODO: this seems unused, check with autotools.
|
||||
set(LT_OBJDIR ".libs/")
|
||||
|
90
configure.ac
90
configure.ac
@ -1,4 +1,4 @@
|
||||
AC_INIT([libwebp], [1.2.1],
|
||||
AC_INIT([libwebp], [1.2.0],
|
||||
[https://bugs.chromium.org/p/webp],,
|
||||
[http://developers.google.com/speed/webp])
|
||||
AC_CANONICAL_HOST
|
||||
@ -32,40 +32,6 @@ AC_ARG_ENABLE([everything],
|
||||
SET_IF_UNSET([enable_libwebpextras], [$enableval])
|
||||
SET_IF_UNSET([enable_libwebpmux], [$enableval])])
|
||||
|
||||
dnl === Check whether libwebpmux should be built
|
||||
AC_MSG_CHECKING(whether libwebpmux is to be built)
|
||||
AC_ARG_ENABLE([libwebpmux],
|
||||
AS_HELP_STRING([--disable-libwebpmux],
|
||||
[Disable libwebpmux @<:@default=no@:>@]),
|
||||
[], [enable_libwebpmux=yes])
|
||||
AC_MSG_RESULT(${enable_libwebpmux-no})
|
||||
AM_CONDITIONAL([BUILD_MUX], [test "$enable_libwebpmux" = "yes"])
|
||||
|
||||
dnl === Check whether libwebpdemux should be built
|
||||
AC_MSG_CHECKING(whether libwebpdemux is to be built)
|
||||
AC_ARG_ENABLE([libwebpdemux],
|
||||
AS_HELP_STRING([--disable-libwebpdemux],
|
||||
[Disable libwebpdemux @<:@default=no@:>@]),
|
||||
[], [enable_libwebpdemux=yes])
|
||||
AC_MSG_RESULT(${enable_libwebpdemux-no})
|
||||
AM_CONDITIONAL([BUILD_DEMUX], [test "$enable_libwebpdemux" = "yes"])
|
||||
|
||||
dnl === Check whether decoder library should be built.
|
||||
AC_MSG_CHECKING(whether decoder library is to be built)
|
||||
AC_ARG_ENABLE([libwebpdecoder],
|
||||
AS_HELP_STRING([--enable-libwebpdecoder],
|
||||
[Build libwebpdecoder @<:@default=no@:>@]))
|
||||
AC_MSG_RESULT(${enable_libwebpdecoder-no})
|
||||
AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"])
|
||||
|
||||
dnl === Check whether libwebpextras should be built
|
||||
AC_MSG_CHECKING(whether libwebpextras is to be built)
|
||||
AC_ARG_ENABLE([libwebpextras],
|
||||
AS_HELP_STRING([--enable-libwebpextras],
|
||||
[Build libwebpextras @<:@default=no@:>@]))
|
||||
AC_MSG_RESULT(${enable_libwebpextras-no})
|
||||
AM_CONDITIONAL([BUILD_EXTRAS], [test "$enable_libwebpextras" = "yes"])
|
||||
|
||||
dnl === If --enable-asserts is not defined, define NDEBUG
|
||||
|
||||
AC_MSG_CHECKING(whether asserts are enabled)
|
||||
@ -259,9 +225,6 @@ AS_IF([test "x$enable_neon" != "xno"], [
|
||||
*android*) AC_CHECK_HEADERS([cpu-features.h]) ;;
|
||||
esac
|
||||
;;
|
||||
aarch64*|arm64*)
|
||||
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
|
||||
;;
|
||||
esac
|
||||
AC_SUBST([NEON_FLAGS])])
|
||||
|
||||
@ -446,10 +409,6 @@ AS_IF([test "x$enable_gl" != "xno"], [
|
||||
|
||||
if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then
|
||||
build_vwebp=yes
|
||||
else
|
||||
AC_MSG_NOTICE(
|
||||
m4_normalize([Not building vwebp.
|
||||
OpenGL libraries and --enable-libwebpdemux are required.]))
|
||||
fi
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
|
||||
@ -509,7 +468,7 @@ AS_IF([test "x$enable_sdl" != "xno"], [
|
||||
if test x"$sdl_support" = "xyes"; then
|
||||
build_vwebp_sdl=yes
|
||||
else
|
||||
AC_MSG_NOTICE([Not building vwebp-sdl. SDL library is required.])
|
||||
AC_MSG_WARN(Optional SDL library not found)
|
||||
fi
|
||||
])
|
||||
|
||||
@ -633,17 +592,11 @@ AS_IF([test "x$enable_gif" != "xno"], [
|
||||
if test "$gif_support" = "yes" -a \
|
||||
"$enable_libwebpdemux" = "yes"; then
|
||||
build_anim_diff=yes
|
||||
else
|
||||
AC_MSG_NOTICE(
|
||||
[Not building anim_diff. libgif and --enable-libwebpdemux are required.])
|
||||
fi
|
||||
|
||||
if test "$gif_support" = "yes" -a \
|
||||
"$enable_libwebpmux" = "yes"; then
|
||||
build_gif2webp=yes
|
||||
else
|
||||
AC_MSG_NOTICE(
|
||||
[Not building gif2webp. libgif and --enable-libwebpmux are required.])
|
||||
fi
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_anim_diff}" = "yes"])
|
||||
@ -651,17 +604,11 @@ AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
|
||||
|
||||
if test "$enable_libwebpdemux" = "yes" -a "$enable_libwebpmux" = "yes"; then
|
||||
build_img2webp=yes
|
||||
else
|
||||
AC_MSG_NOTICE(
|
||||
m4_normalize([Not building img2webp.
|
||||
--enable-libwebpdemux & --enable-libwebpmux are required.]))
|
||||
fi
|
||||
AM_CONDITIONAL([BUILD_IMG2WEBP], [test "${build_img2webp}" = "yes"])
|
||||
|
||||
if test "$enable_libwebpmux" = "yes"; then
|
||||
build_webpinfo=yes
|
||||
else
|
||||
AC_MSG_NOTICE([Not building webpinfo. --enable-libwebpdemux is required.])
|
||||
fi
|
||||
AM_CONDITIONAL([BUILD_WEBPINFO], [test "${build_webpinfo}" = "yes"])
|
||||
|
||||
@ -745,6 +692,39 @@ else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
dnl === Check whether libwebpmux should be built
|
||||
AC_MSG_CHECKING(whether libwebpmux is to be built)
|
||||
AC_ARG_ENABLE([libwebpmux],
|
||||
AS_HELP_STRING([--enable-libwebpmux],
|
||||
[Build libwebpmux @<:@default=no@:>@]))
|
||||
AC_MSG_RESULT(${enable_libwebpmux-no})
|
||||
AM_CONDITIONAL([BUILD_MUX], [test "$enable_libwebpmux" = "yes"])
|
||||
|
||||
dnl === Check whether libwebpdemux should be built
|
||||
AC_MSG_CHECKING(whether libwebpdemux is to be built)
|
||||
AC_ARG_ENABLE([libwebpdemux],
|
||||
AS_HELP_STRING([--disable-libwebpdemux],
|
||||
[Disable libwebpdemux @<:@default=no@:>@]),
|
||||
[], [enable_libwebpdemux=yes])
|
||||
AC_MSG_RESULT(${enable_libwebpdemux-no})
|
||||
AM_CONDITIONAL([BUILD_DEMUX], [test "$enable_libwebpdemux" = "yes"])
|
||||
|
||||
dnl === Check whether decoder library should be built.
|
||||
AC_MSG_CHECKING(whether decoder library is to be built)
|
||||
AC_ARG_ENABLE([libwebpdecoder],
|
||||
AS_HELP_STRING([--enable-libwebpdecoder],
|
||||
[Build libwebpdecoder @<:@default=no@:>@]))
|
||||
AC_MSG_RESULT(${enable_libwebpdecoder-no})
|
||||
AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"])
|
||||
|
||||
dnl === Check whether libwebpextras should be built
|
||||
AC_MSG_CHECKING(whether libwebpextras is to be built)
|
||||
AC_ARG_ENABLE([libwebpextras],
|
||||
AS_HELP_STRING([--enable-libwebpextras],
|
||||
[Build libwebpextras @<:@default=no@:>@]))
|
||||
AC_MSG_RESULT(${enable_libwebpextras-no})
|
||||
AM_CONDITIONAL([BUILD_EXTRAS], [test "$enable_libwebpextras" = "yes"])
|
||||
|
||||
dnl =========================
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
@ -816,7 +816,7 @@ RIFF/WEBP
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
[vp8spec]: http://tools.ietf.org/html/rfc6386
|
||||
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt
|
||||
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
|
||||
[iccspec]: http://www.color.org/icc_specs2.xalter
|
||||
[metadata]: http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
|
||||
[rfc 1166]: http://tools.ietf.org/html/rfc1166
|
||||
|
@ -465,10 +465,8 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
|
||||
goto End;
|
||||
}
|
||||
// If there's only one frame, we don't need to handle loop count.
|
||||
if (frame_number == 1) {
|
||||
loop_count = 0;
|
||||
} else if (!loop_compatibility) {
|
||||
|
||||
if (!loop_compatibility) {
|
||||
if (!stored_loop_count) {
|
||||
// if no loop-count element is seen, the default is '1' (loop-once)
|
||||
// and we need to signal it explicitly in WebP. Note however that
|
||||
|
@ -472,11 +472,11 @@ static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
|
||||
}
|
||||
|
||||
static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
||||
int dispose_method, unused;
|
||||
int dispose_method, dummy;
|
||||
char plus_minus, blend_method;
|
||||
const int num_args = sscanf(args, "+%d+%d+%d+%d%c%c+%d", &info->duration,
|
||||
&info->x_offset, &info->y_offset, &dispose_method,
|
||||
&plus_minus, &blend_method, &unused);
|
||||
&plus_minus, &blend_method, &dummy);
|
||||
switch (num_args) {
|
||||
case 1:
|
||||
info->x_offset = info->y_offset = 0; // fall through
|
||||
@ -495,7 +495,7 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
||||
|
||||
WarnAboutOddOffset(info);
|
||||
|
||||
// Note: The validity of the following conversion is checked by
|
||||
// Note: The sanity of the following conversion is checked by
|
||||
// WebPMuxPushFrame().
|
||||
info->dispose_method = (WebPMuxAnimDispose)dispose_method;
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#define XTRA_MAJ_VERSION 1
|
||||
#define XTRA_MIN_VERSION 2
|
||||
#define XTRA_REV_VERSION 1
|
||||
#define XTRA_REV_VERSION 0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -155,8 +155,8 @@ int WebPWritePNG(const char* out_file_name, int use_stdout,
|
||||
}
|
||||
|
||||
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
|
||||
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp unused) {
|
||||
(void)unused; // remove variable-unused warning
|
||||
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp dummy) {
|
||||
(void)dummy; // remove variable-unused warning
|
||||
longjmp(png_jmpbuf(png), 1);
|
||||
}
|
||||
|
||||
@ -320,7 +320,7 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
PutLE16(bmp_header + 26, 1); // number of planes
|
||||
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
|
||||
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
|
||||
PutLE32(bmp_header + 34, 0); // image size (placeholder)
|
||||
PutLE32(bmp_header + 34, 0); // image size (dummy)
|
||||
PutLE32(bmp_header + 38, 2400); // x pixels/meter
|
||||
PutLE32(bmp_header + 42, 2400); // y pixels/meter
|
||||
PutLE32(bmp_header + 46, 0); // number of palette colors
|
||||
|
@ -148,11 +148,9 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height) {
|
||||
const uint64_t total_size = stride * height;
|
||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
|
||||
const uint64_t total_size = nmemb * size;
|
||||
int ok = (total_size == (size_t)total_size);
|
||||
// check that 'stride' is representable as int:
|
||||
ok = ok && ((uint64_t)(int)stride == stride);
|
||||
#if defined(WEBP_MAX_IMAGE_SIZE)
|
||||
ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE);
|
||||
#endif
|
||||
|
@ -54,8 +54,8 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Returns 0 in case of overflow, memory over-allocation or excessive dimension.
|
||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height);
|
||||
// Returns 0 in case of overflow of nmemb * size.
|
||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
@ -274,7 +274,7 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
||||
ctx.data = data;
|
||||
ctx.data_size = data_size;
|
||||
|
||||
memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp safety
|
||||
memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp sanity
|
||||
dinfo.err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
|
||||
|
@ -157,7 +157,6 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
||||
MyData my_data = { data, (toff_t)data_size, 0 };
|
||||
TIFF* tif;
|
||||
uint32_t image_width, image_height, tile_width, tile_height;
|
||||
uint64_t stride;
|
||||
uint16_t samples_per_px = 0;
|
||||
uint16_t extra_samples = 0;
|
||||
uint16_t* extra_samples_ptr = NULL;
|
||||
@ -195,31 +194,20 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
||||
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
|
||||
goto End;
|
||||
}
|
||||
stride = (uint64_t)image_width * sizeof(*raster);
|
||||
if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, image_height)) {
|
||||
fprintf(stderr, "Error! TIFF image dimension (%d x %d) is too large.\n",
|
||||
image_width, image_height);
|
||||
if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)image_width * image_height,
|
||||
sizeof(*raster))) {
|
||||
goto End;
|
||||
}
|
||||
|
||||
// According to spec, a tile can be bigger than the image. However it should
|
||||
// be a multiple of 16 and not way too large, so check that it's not more
|
||||
// than twice the image size, for dimensions above some arbitrary minimum
|
||||
// 32. We also check that they respect WebP's dimension and memory limit.
|
||||
// Note that a tile can be 6byte/px in some cases. Here we assume
|
||||
// 4byte/px with sizeof(*raster), to be conservative.
|
||||
if (TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) &&
|
||||
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height)) {
|
||||
if ((tile_width > 32 && tile_width / 2 > image_width) ||
|
||||
(tile_height > 32 && tile_height / 2 > image_height) ||
|
||||
ImgIoUtilCheckSizeArgumentsOverflow(
|
||||
(uint64_t)tile_width * sizeof(*raster), tile_height)) {
|
||||
fprintf(stderr, "Error! TIFF tile dimension (%d x %d) is too large.\n",
|
||||
tile_width, tile_height);
|
||||
goto End;
|
||||
}
|
||||
// be a multiple of 16 and not way too large, so check that it's not more than
|
||||
// twice the image size, for dimensions above some arbitrary minimum 32.
|
||||
if ((TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) &&
|
||||
tile_width > 32 && tile_width / 2 > image_width) ||
|
||||
(TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height) &&
|
||||
tile_height > 32 && tile_height / 2 > image_height)) {
|
||||
fprintf(stderr, "Error! TIFF tile dimensions are too big.\n");
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (samples_per_px > 3 && !TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
|
||||
&extra_samples, &extra_samples_ptr)) {
|
||||
fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n");
|
||||
@ -227,13 +215,15 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
||||
}
|
||||
|
||||
// _Tiffmalloc uses a signed type for size.
|
||||
alloc_size = (int64_t)(stride * image_height);
|
||||
alloc_size =
|
||||
(int64_t)((uint64_t)image_width * image_height * sizeof(*raster));
|
||||
if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
|
||||
|
||||
raster = (uint32*)_TIFFmalloc((tsize_t)alloc_size);
|
||||
if (raster != NULL) {
|
||||
if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster,
|
||||
ORIENTATION_TOPLEFT, 1)) {
|
||||
const int stride = image_width * sizeof(*raster);
|
||||
pic->width = image_width;
|
||||
pic->height = image_height;
|
||||
// TIFF data is ABGR
|
||||
@ -251,8 +241,8 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
||||
}
|
||||
}
|
||||
ok = keep_alpha
|
||||
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, (int)stride)
|
||||
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, (int)stride);
|
||||
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
|
||||
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
|
||||
}
|
||||
_TIFFfree(raster);
|
||||
} else {
|
||||
|
@ -95,7 +95,7 @@ VP8StatusCode DecodeWebPIncremental(
|
||||
{
|
||||
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
|
||||
if (idec == NULL) {
|
||||
fprintf(stderr, "Failed during WebPIDecode().\n");
|
||||
fprintf(stderr, "Failed during WebPINewDecoder().\n");
|
||||
return VP8_STATUS_OUT_OF_MEMORY;
|
||||
} else {
|
||||
status = WebPIUpdate(idec, data, data_size);
|
||||
|
@ -134,10 +134,7 @@ static HRESULT ExtractICCP(IWICImagingFactory* const factory,
|
||||
IWICColorContext** color_contexts;
|
||||
|
||||
IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
|
||||
if (FAILED(hr) || count == 0) {
|
||||
// Treat unsupported operation as a non-fatal error. See crbug.com/webp/506.
|
||||
return (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) ? S_OK : hr;
|
||||
}
|
||||
if (FAILED(hr) || count == 0) return hr;
|
||||
|
||||
color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts));
|
||||
if (color_contexts == NULL) return E_OUTOFMEMORY;
|
||||
@ -273,15 +270,10 @@ int ReadPictureWithWIC(const char* const filename,
|
||||
WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
|
||||
const WICFormatImporter* importer = NULL;
|
||||
GUID src_container_format = GUID_NULL_;
|
||||
// From Windows Kits\10\Include\10.0.19041.0\um\wincodec.h
|
||||
WEBP_DEFINE_GUID(GUID_ContainerFormatWebp_,
|
||||
0xe094b0e2, 0x67f2, 0x45b3,
|
||||
0xb0, 0xea, 0x11, 0x53, 0x37, 0xca, 0x7c, 0xf3);
|
||||
static const GUID* kAlphaContainers[] = {
|
||||
&GUID_ContainerFormatBmp,
|
||||
&GUID_ContainerFormatPng,
|
||||
&GUID_ContainerFormatTiff,
|
||||
&GUID_ContainerFormatWebp_,
|
||||
NULL
|
||||
};
|
||||
int has_alpha = 0;
|
||||
|
@ -166,7 +166,6 @@ DSP_DEC_OBJS = \
|
||||
src/dsp/lossless_msa.o \
|
||||
src/dsp/lossless_neon.o \
|
||||
src/dsp/lossless_sse2.o \
|
||||
src/dsp/lossless_sse41.o \
|
||||
src/dsp/rescaler.o \
|
||||
src/dsp/rescaler_mips32.o \
|
||||
src/dsp/rescaler_mips_dsp_r2.o \
|
||||
|
@ -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:2:1
|
||||
libwebp_la_LDFLAGS = -no-undefined -version-info 8:1: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:2:1
|
||||
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:1:1
|
||||
pkgconfig_DATA += libwebpdecoder.pc
|
||||
endif
|
||||
|
||||
|
@ -183,7 +183,7 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
|
||||
assert(dec != NULL && io != NULL);
|
||||
|
||||
if (row < 0 || num_rows <= 0 || row + num_rows > height) {
|
||||
return NULL;
|
||||
return NULL; // sanity check.
|
||||
}
|
||||
|
||||
if (!dec->is_alpha_decoded_) {
|
||||
|
@ -102,7 +102,7 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
|
||||
int stride;
|
||||
uint64_t size;
|
||||
|
||||
if ((uint64_t)w * kModeBpp[mode] >= (1ull << 31)) {
|
||||
if ((uint64_t)w * kModeBpp[mode] >= (1ull << 32)) {
|
||||
return VP8_STATUS_INVALID_PARAM;
|
||||
}
|
||||
stride = w * kModeBpp[mode];
|
||||
@ -117,6 +117,7 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
|
||||
}
|
||||
total_size = size + 2 * uv_size + a_size;
|
||||
|
||||
// Security/sanity checks
|
||||
output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
|
||||
if (output == NULL) {
|
||||
return VP8_STATUS_OUT_OF_MEMORY;
|
||||
@ -155,11 +156,11 @@ VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
|
||||
}
|
||||
if (WebPIsRGBMode(buffer->colorspace)) {
|
||||
WebPRGBABuffer* const buf = &buffer->u.RGBA;
|
||||
buf->rgba += (int64_t)(buffer->height - 1) * buf->stride;
|
||||
buf->rgba += (buffer->height - 1) * buf->stride;
|
||||
buf->stride = -buf->stride;
|
||||
} else {
|
||||
WebPYUVABuffer* const buf = &buffer->u.YUVA;
|
||||
const int64_t H = buffer->height;
|
||||
const int H = buffer->height;
|
||||
buf->y += (H - 1) * buf->y_stride;
|
||||
buf->y_stride = -buf->y_stride;
|
||||
buf->u += ((H - 1) >> 1) * buf->u_stride;
|
||||
@ -187,7 +188,8 @@ VP8StatusCode WebPAllocateDecBuffer(int width, int height,
|
||||
const int ch = options->crop_height;
|
||||
const int x = options->crop_left & ~1;
|
||||
const int y = options->crop_top & ~1;
|
||||
if (!WebPCheckCropDimensions(width, height, x, y, cw, ch)) {
|
||||
if (x < 0 || y < 0 || cw <= 0 || ch <= 0 ||
|
||||
x + cw > width || y + ch > height) {
|
||||
return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
|
||||
}
|
||||
width = cw;
|
||||
|
@ -705,7 +705,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
|
||||
+ cache_size + alpha_size + WEBP_ALIGN_CST;
|
||||
uint8_t* mem;
|
||||
|
||||
if (!CheckSizeOverflow(needed)) return 0; // check for overflow
|
||||
if (needed != (size_t)needed) return 0; // check for overflow
|
||||
if (needed > dec->mem_size_) {
|
||||
WebPSafeFree(dec->mem_);
|
||||
dec->mem_size_ = 0;
|
||||
|
@ -298,57 +298,46 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
const int uv_out_height = (out_height + 1) >> 1;
|
||||
const int uv_in_width = (io->mb_w + 1) >> 1;
|
||||
const int uv_in_height = (io->mb_h + 1) >> 1;
|
||||
// scratch memory for luma rescaler
|
||||
const size_t work_size = 2 * (size_t)out_width;
|
||||
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
|
||||
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
|
||||
uint64_t total_size;
|
||||
size_t rescaler_size;
|
||||
size_t tmp_size, rescaler_size;
|
||||
rescaler_t* work;
|
||||
WebPRescaler* scalers;
|
||||
const int num_rescalers = has_alpha ? 4 : 3;
|
||||
|
||||
total_size = ((uint64_t)work_size + 2 * uv_work_size) * sizeof(*work);
|
||||
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
|
||||
if (has_alpha) {
|
||||
total_size += (uint64_t)work_size * sizeof(*work);
|
||||
tmp_size += work_size * sizeof(*work);
|
||||
}
|
||||
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
|
||||
total_size += rescaler_size;
|
||||
if (!CheckSizeOverflow(total_size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
|
||||
p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size);
|
||||
if (p->memory == NULL) {
|
||||
return 0; // memory error
|
||||
}
|
||||
work = (rescaler_t*)p->memory;
|
||||
|
||||
scalers = (WebPRescaler*)WEBP_ALIGN(
|
||||
(const uint8_t*)work + total_size - rescaler_size);
|
||||
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size);
|
||||
p->scaler_y = &scalers[0];
|
||||
p->scaler_u = &scalers[1];
|
||||
p->scaler_v = &scalers[2];
|
||||
p->scaler_a = has_alpha ? &scalers[3] : NULL;
|
||||
|
||||
if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
||||
buf->y, out_width, out_height, buf->y_stride, 1,
|
||||
work) ||
|
||||
!WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
||||
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
|
||||
work + work_size) ||
|
||||
!WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
||||
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
|
||||
work + work_size + uv_work_size)) {
|
||||
return 0;
|
||||
}
|
||||
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
||||
buf->y, out_width, out_height, buf->y_stride, 1,
|
||||
work);
|
||||
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
||||
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
|
||||
work + work_size);
|
||||
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
||||
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
|
||||
work + work_size + uv_work_size);
|
||||
p->emit = EmitRescaledYUV;
|
||||
|
||||
if (has_alpha) {
|
||||
if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
||||
buf->a, out_width, out_height, buf->a_stride, 1,
|
||||
work + work_size + 2 * uv_work_size)) {
|
||||
return 0;
|
||||
}
|
||||
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
||||
buf->a, out_width, out_height, buf->a_stride, 1,
|
||||
work + work_size + 2 * uv_work_size);
|
||||
p->emit_alpha = EmitRescaledAlphaYUV;
|
||||
WebPInitAlphaProcessing();
|
||||
}
|
||||
@ -491,58 +480,51 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
const int out_height = io->scaled_height;
|
||||
const int uv_in_width = (io->mb_w + 1) >> 1;
|
||||
const int uv_in_height = (io->mb_h + 1) >> 1;
|
||||
// scratch memory for one rescaler
|
||||
const size_t work_size = 2 * (size_t)out_width;
|
||||
const size_t work_size = 2 * out_width; // scratch memory for one rescaler
|
||||
rescaler_t* work; // rescalers work area
|
||||
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
|
||||
uint64_t tmp_size1, tmp_size2, total_size;
|
||||
size_t rescaler_size;
|
||||
size_t tmp_size1, tmp_size2, total_size, rescaler_size;
|
||||
WebPRescaler* scalers;
|
||||
const int num_rescalers = has_alpha ? 4 : 3;
|
||||
|
||||
tmp_size1 = (uint64_t)num_rescalers * work_size;
|
||||
tmp_size2 = (uint64_t)num_rescalers * out_width;
|
||||
tmp_size1 = 3 * work_size;
|
||||
tmp_size2 = 3 * out_width;
|
||||
if (has_alpha) {
|
||||
tmp_size1 += work_size;
|
||||
tmp_size2 += out_width;
|
||||
}
|
||||
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
|
||||
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
|
||||
total_size += rescaler_size;
|
||||
if (!CheckSizeOverflow(total_size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
|
||||
p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size);
|
||||
if (p->memory == NULL) {
|
||||
return 0; // memory error
|
||||
}
|
||||
work = (rescaler_t*)p->memory;
|
||||
tmp = (uint8_t*)(work + tmp_size1);
|
||||
|
||||
scalers = (WebPRescaler*)WEBP_ALIGN(
|
||||
(const uint8_t*)work + total_size - rescaler_size);
|
||||
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size);
|
||||
p->scaler_y = &scalers[0];
|
||||
p->scaler_u = &scalers[1];
|
||||
p->scaler_v = &scalers[2];
|
||||
p->scaler_a = has_alpha ? &scalers[3] : NULL;
|
||||
|
||||
if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
||||
tmp + 0 * out_width, out_width, out_height, 0, 1,
|
||||
work + 0 * work_size) ||
|
||||
!WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
||||
tmp + 1 * out_width, out_width, out_height, 0, 1,
|
||||
work + 1 * work_size) ||
|
||||
!WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
||||
tmp + 2 * out_width, out_width, out_height, 0, 1,
|
||||
work + 2 * work_size)) {
|
||||
return 0;
|
||||
}
|
||||
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
||||
tmp + 0 * out_width, out_width, out_height, 0, 1,
|
||||
work + 0 * work_size);
|
||||
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
||||
tmp + 1 * out_width, out_width, out_height, 0, 1,
|
||||
work + 1 * work_size);
|
||||
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
||||
tmp + 2 * out_width, out_width, out_height, 0, 1,
|
||||
work + 2 * work_size);
|
||||
p->emit = EmitRescaledRGB;
|
||||
WebPInitYUV444Converters();
|
||||
|
||||
if (has_alpha) {
|
||||
if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
||||
tmp + 3 * out_width, out_width, out_height, 0, 1,
|
||||
work + 3 * work_size)) {
|
||||
return 0;
|
||||
}
|
||||
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
||||
tmp + 3 * out_width, out_width, out_height, 0, 1,
|
||||
work + 3 * work_size);
|
||||
p->emit_alpha = EmitRescaledAlphaRGB;
|
||||
if (p->output->colorspace == MODE_RGBA_4444 ||
|
||||
p->output->colorspace == MODE_rgbA_4444) {
|
||||
|
@ -335,7 +335,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
io->scaled_width = io->width;
|
||||
io->scaled_height = io->height;
|
||||
|
||||
io->mb_w = io->width; // for soundness
|
||||
io->mb_w = io->width; // sanity check
|
||||
io->mb_h = io->height; // ditto
|
||||
|
||||
VP8ResetProba(&dec->proba_);
|
||||
|
@ -32,7 +32,7 @@ extern "C" {
|
||||
// version numbers
|
||||
#define DEC_MAJ_VERSION 1
|
||||
#define DEC_MIN_VERSION 2
|
||||
#define DEC_REV_VERSION 1
|
||||
#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),
|
||||
|
@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
|
||||
int symbol;
|
||||
int max_symbol;
|
||||
int prev_code_len = DEFAULT_CODE_LENGTH;
|
||||
HuffmanCode table[1 << LENGTHS_TABLE_BITS];
|
||||
HuffmanTables tables;
|
||||
|
||||
if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
|
||||
code_length_code_lengths,
|
||||
NUM_CODE_LENGTH_CODES)) {
|
||||
if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
|
||||
!VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
|
||||
code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
|
||||
goto End;
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths(
|
||||
int code_len;
|
||||
if (max_symbol-- == 0) break;
|
||||
VP8LFillBitWindow(br);
|
||||
p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
|
||||
p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
|
||||
VP8LSetBitPos(br, br->bit_pos_ + p->bits);
|
||||
code_len = p->value;
|
||||
if (code_len < kCodeLengthLiterals) {
|
||||
@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths(
|
||||
ok = 1;
|
||||
|
||||
End:
|
||||
VP8LHuffmanTablesDeallocate(&tables);
|
||||
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
|
||||
return ok;
|
||||
}
|
||||
@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths(
|
||||
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
|
||||
// tree.
|
||||
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
||||
int* const code_lengths, HuffmanCode* const table) {
|
||||
int* const code_lengths,
|
||||
HuffmanTables* const table) {
|
||||
int ok = 0;
|
||||
int size = 0;
|
||||
VP8LBitReader* const br = &dec->br_;
|
||||
@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
VP8LMetadata* const hdr = &dec->hdr_;
|
||||
uint32_t* huffman_image = NULL;
|
||||
HTreeGroup* htree_groups = NULL;
|
||||
HuffmanCode* huffman_tables = NULL;
|
||||
HuffmanCode* huffman_table = NULL;
|
||||
HuffmanTables* huffman_tables = &hdr->huffman_tables_;
|
||||
int num_htree_groups = 1;
|
||||
int num_htree_groups_max = 1;
|
||||
int max_alphabet_size = 0;
|
||||
@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
int* mapping = NULL;
|
||||
int ok = 0;
|
||||
|
||||
// Check the table has been 0 initialized (through InitMetadata).
|
||||
assert(huffman_tables->root.start == NULL);
|
||||
assert(huffman_tables->curr_segment == NULL);
|
||||
|
||||
if (allow_recursion && VP8LReadBits(br, 1)) {
|
||||
// use meta Huffman codes.
|
||||
const int huffman_precision = VP8LReadBits(br, 3) + 2;
|
||||
@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
|
||||
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
|
||||
sizeof(*code_lengths));
|
||||
huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
|
||||
sizeof(*huffman_tables));
|
||||
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
|
||||
|
||||
if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
|
||||
if (htree_groups == NULL || code_lengths == NULL ||
|
||||
!VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
|
||||
huffman_tables)) {
|
||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
huffman_table = huffman_tables;
|
||||
for (i = 0; i < num_htree_groups_max; ++i) {
|
||||
// If the index "i" is unused in the Huffman image, just make sure the
|
||||
// coefficients are valid but do not store them.
|
||||
@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
int max_bits = 0;
|
||||
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||
int alphabet_size = kAlphabetSize[j];
|
||||
htrees[j] = huffman_table;
|
||||
if (j == 0 && color_cache_bits > 0) {
|
||||
alphabet_size += (1 << color_cache_bits);
|
||||
}
|
||||
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
|
||||
size =
|
||||
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
|
||||
htrees[j] = huffman_tables->curr_segment->curr_table;
|
||||
if (size == 0) {
|
||||
goto Error;
|
||||
}
|
||||
if (is_trivial_literal && kLiteralMap[j] == 1) {
|
||||
is_trivial_literal = (huffman_table->bits == 0);
|
||||
is_trivial_literal = (htrees[j]->bits == 0);
|
||||
}
|
||||
total_size += huffman_table->bits;
|
||||
huffman_table += size;
|
||||
total_size += htrees[j]->bits;
|
||||
huffman_tables->curr_segment->curr_table += size;
|
||||
if (j <= ALPHA) {
|
||||
int local_max_bits = code_lengths[0];
|
||||
int k;
|
||||
@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
hdr->huffman_image_ = huffman_image;
|
||||
hdr->num_htree_groups_ = num_htree_groups;
|
||||
hdr->htree_groups_ = htree_groups;
|
||||
hdr->huffman_tables_ = huffman_tables;
|
||||
|
||||
Error:
|
||||
WebPSafeFree(code_lengths);
|
||||
WebPSafeFree(mapping);
|
||||
if (!ok) {
|
||||
WebPSafeFree(huffman_image);
|
||||
WebPSafeFree(huffman_tables);
|
||||
VP8LHuffmanTablesDeallocate(huffman_tables);
|
||||
VP8LHtreeGroupsFree(htree_groups);
|
||||
}
|
||||
return ok;
|
||||
@ -559,11 +563,8 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
||||
memory += work_size * sizeof(*work);
|
||||
scaled_data = (uint32_t*)memory;
|
||||
|
||||
if (!WebPRescalerInit(dec->rescaler, in_width, in_height,
|
||||
(uint8_t*)scaled_data, out_width, out_height,
|
||||
0, num_channels, work)) {
|
||||
return 0;
|
||||
}
|
||||
WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
|
||||
out_width, out_height, 0, num_channels, work);
|
||||
return 1;
|
||||
}
|
||||
#endif // WEBP_REDUCE_SIZE
|
||||
@ -577,14 +578,13 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
||||
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
|
||||
int rgba_stride, uint8_t* const rgba) {
|
||||
uint32_t* const src = (uint32_t*)rescaler->dst;
|
||||
uint8_t* dst = rgba;
|
||||
const int dst_width = rescaler->dst_width;
|
||||
int num_lines_out = 0;
|
||||
while (WebPRescalerHasPendingOutput(rescaler)) {
|
||||
uint8_t* const dst = rgba + num_lines_out * rgba_stride;
|
||||
WebPRescalerExportRow(rescaler);
|
||||
WebPMultARGBRow(src, dst_width, 1);
|
||||
VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
|
||||
dst += rgba_stride;
|
||||
++num_lines_out;
|
||||
}
|
||||
return num_lines_out;
|
||||
@ -598,8 +598,8 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
|
||||
int num_lines_in = 0;
|
||||
int num_lines_out = 0;
|
||||
while (num_lines_in < mb_h) {
|
||||
uint8_t* const row_in = in + (uint64_t)num_lines_in * in_stride;
|
||||
uint8_t* const row_out = out + (uint64_t)num_lines_out * out_stride;
|
||||
uint8_t* const row_in = in + num_lines_in * in_stride;
|
||||
uint8_t* const row_out = out + num_lines_out * out_stride;
|
||||
const int lines_left = mb_h - num_lines_in;
|
||||
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
|
||||
int lines_imported;
|
||||
@ -800,8 +800,7 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
|
||||
const WebPDecBuffer* const output = dec->output_;
|
||||
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
|
||||
const WebPRGBABuffer* const buf = &output->u.RGBA;
|
||||
uint8_t* const rgba =
|
||||
buf->rgba + (int64_t)dec->last_out_row_ * buf->stride;
|
||||
uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
|
||||
const int num_rows_out =
|
||||
#if !defined(WEBP_REDUCE_SIZE)
|
||||
io->use_scaling ?
|
||||
@ -1358,7 +1357,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
|
||||
assert(hdr != NULL);
|
||||
|
||||
WebPSafeFree(hdr->huffman_image_);
|
||||
WebPSafeFree(hdr->huffman_tables_);
|
||||
VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
|
||||
VP8LHtreeGroupsFree(hdr->htree_groups_);
|
||||
VP8LColorCacheClear(&hdr->color_cache_);
|
||||
VP8LColorCacheClear(&hdr->saved_color_cache_);
|
||||
@ -1519,7 +1518,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
|
||||
assert(dec->width_ <= final_width);
|
||||
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
|
||||
if (dec->pixels_ == NULL) {
|
||||
dec->argb_cache_ = NULL; // for soundness
|
||||
dec->argb_cache_ = NULL; // for sanity check
|
||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||
return 0;
|
||||
}
|
||||
@ -1529,7 +1528,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
|
||||
|
||||
static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
|
||||
const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_;
|
||||
dec->argb_cache_ = NULL; // for soundness
|
||||
dec->argb_cache_ = NULL; // for sanity check
|
||||
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
|
||||
if (dec->pixels_ == NULL) {
|
||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||
@ -1671,9 +1670,10 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
|
||||
VP8Io* io = NULL;
|
||||
WebPDecParams* params = NULL;
|
||||
|
||||
// Sanity checks.
|
||||
if (dec == NULL) return 0;
|
||||
|
||||
assert(dec->hdr_.huffman_tables_ != NULL);
|
||||
assert(dec->hdr_.huffman_tables_.root.start != NULL);
|
||||
assert(dec->hdr_.htree_groups_ != NULL);
|
||||
assert(dec->hdr_.num_htree_groups_ > 0);
|
||||
|
||||
|
@ -51,7 +51,7 @@ typedef struct {
|
||||
uint32_t* huffman_image_;
|
||||
int num_htree_groups_;
|
||||
HTreeGroup* htree_groups_;
|
||||
HuffmanCode* huffman_tables_;
|
||||
HuffmanTables huffman_tables_;
|
||||
} VP8LMetadata;
|
||||
|
||||
typedef struct VP8LDecoder VP8LDecoder;
|
||||
|
@ -785,13 +785,6 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
|
||||
//------------------------------------------------------------------------------
|
||||
// Cropping and rescaling.
|
||||
|
||||
int WebPCheckCropDimensions(int image_width, int image_height,
|
||||
int x, int y, int w, int h) {
|
||||
return !(x < 0 || y < 0 || w <= 0 || h <= 0 ||
|
||||
x >= image_width || w > image_width || w > image_width - x ||
|
||||
y >= image_height || h > image_height || h > image_height - y);
|
||||
}
|
||||
|
||||
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||
VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
|
||||
const int W = io->width;
|
||||
@ -799,7 +792,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||
int x = 0, y = 0, w = W, h = H;
|
||||
|
||||
// Cropping
|
||||
io->use_cropping = (options != NULL) && options->use_cropping;
|
||||
io->use_cropping = (options != NULL) && (options->use_cropping > 0);
|
||||
if (io->use_cropping) {
|
||||
w = options->crop_width;
|
||||
h = options->crop_height;
|
||||
@ -809,7 +802,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||
x &= ~1;
|
||||
y &= ~1;
|
||||
}
|
||||
if (!WebPCheckCropDimensions(W, H, x, y, w, h)) {
|
||||
if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
|
||||
return 0; // out of frame boundary error
|
||||
}
|
||||
}
|
||||
@ -821,7 +814,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||
io->mb_h = h;
|
||||
|
||||
// Scaling
|
||||
io->use_scaling = (options != NULL) && options->use_scaling;
|
||||
io->use_scaling = (options != NULL) && (options->use_scaling > 0);
|
||||
if (io->use_scaling) {
|
||||
int scaled_width = options->scaled_width;
|
||||
int scaled_height = options->scaled_height;
|
||||
@ -842,8 +835,8 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||
|
||||
if (io->use_scaling) {
|
||||
// disable filter (only for large downscaling ratio).
|
||||
io->bypass_filtering |= (io->scaled_width < W * 3 / 4) &&
|
||||
(io->scaled_height < H * 3 / 4);
|
||||
io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
|
||||
(io->scaled_height < H * 3 / 4);
|
||||
io->fancy_upsampling = 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -77,10 +77,6 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
|
||||
//------------------------------------------------------------------------------
|
||||
// Misc utils
|
||||
|
||||
// Returns true if crop dimensions are within image bounds.
|
||||
int WebPCheckCropDimensions(int image_width, int image_height,
|
||||
int x, int y, int w, int h);
|
||||
|
||||
// Initializes VP8Io with custom setup, io and teardown functions. The default
|
||||
// hooks will use the supplied 'params' as io->opaque handle.
|
||||
void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
|
||||
|
@ -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:8:0
|
||||
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:7:0
|
||||
libwebpdemuxincludedir = $(includedir)/webp
|
||||
pkgconfig_DATA = libwebpdemux.pc
|
||||
|
@ -87,19 +87,11 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
|
||||
int abi_version) {
|
||||
WebPAnimDecoderOptions options;
|
||||
WebPAnimDecoder* dec = NULL;
|
||||
WebPBitstreamFeatures features;
|
||||
if (webp_data == NULL ||
|
||||
WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Validate the bitstream before doing expensive allocations. The demuxer may
|
||||
// be more tolerant than the decoder.
|
||||
if (WebPGetFeatures(webp_data->bytes, webp_data->size, &features) !=
|
||||
VP8_STATUS_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Note: calloc() so that the pointer members are initialized to NULL.
|
||||
dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
|
||||
if (dec == NULL) goto Error;
|
||||
@ -153,7 +145,7 @@ static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
|
||||
uint32_t canvas_height) {
|
||||
const uint64_t size =
|
||||
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
|
||||
if (!CheckSizeOverflow(size)) return 0;
|
||||
if (size != (size_t)size) return 0;
|
||||
memset(buf, 0, (size_t)size);
|
||||
return 1;
|
||||
}
|
||||
@ -174,7 +166,7 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
|
||||
static int CopyCanvas(const uint8_t* src, uint8_t* dst,
|
||||
uint32_t width, uint32_t height) {
|
||||
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
|
||||
if (!CheckSizeOverflow(size)) return 0;
|
||||
if (size != (size_t)size) return 0;
|
||||
assert(src != NULL && dst != NULL);
|
||||
memcpy(dst, src, (size_t)size);
|
||||
return 1;
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#define DMUX_MAJ_VERSION 1
|
||||
#define DMUX_MIN_VERSION 2
|
||||
#define DMUX_REV_VERSION 1
|
||||
#define DMUX_REV_VERSION 0
|
||||
|
||||
typedef struct {
|
||||
size_t start_; // start location of the data
|
||||
@ -221,16 +221,12 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
||||
const size_t chunk_start_offset = mem->start_;
|
||||
const uint32_t fourcc = ReadLE32(mem);
|
||||
const uint32_t payload_size = ReadLE32(mem);
|
||||
uint32_t payload_size_padded;
|
||||
size_t payload_available;
|
||||
size_t chunk_size;
|
||||
const uint32_t payload_size_padded = payload_size + (payload_size & 1);
|
||||
const size_t payload_available = (payload_size_padded > MemDataSize(mem))
|
||||
? MemDataSize(mem) : payload_size_padded;
|
||||
const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available;
|
||||
|
||||
if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
||||
|
||||
payload_size_padded = payload_size + (payload_size & 1);
|
||||
payload_available = (payload_size_padded > MemDataSize(mem))
|
||||
? MemDataSize(mem) : payload_size_padded;
|
||||
chunk_size = CHUNK_HEADER_SIZE + payload_available;
|
||||
if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR;
|
||||
if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA;
|
||||
|
||||
@ -455,11 +451,9 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
||||
const size_t chunk_start_offset = mem->start_;
|
||||
const uint32_t fourcc = ReadLE32(mem);
|
||||
const uint32_t chunk_size = ReadLE32(mem);
|
||||
uint32_t chunk_size_padded;
|
||||
const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1);
|
||||
|
||||
if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
||||
|
||||
chunk_size_padded = chunk_size + (chunk_size & 1);
|
||||
if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR;
|
||||
|
||||
switch (fourcc) {
|
||||
|
@ -6,8 +6,8 @@
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,2,1
|
||||
PRODUCTVERSION 1,0,2,1
|
||||
FILEVERSION 1,0,2,0
|
||||
PRODUCTVERSION 1,0,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -24,12 +24,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Google, Inc."
|
||||
VALUE "FileDescription", "libwebpdemux DLL"
|
||||
VALUE "FileVersion", "1.2.1"
|
||||
VALUE "FileVersion", "1.2.0"
|
||||
VALUE "InternalName", "libwebpdemux.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2021"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2019"
|
||||
VALUE "OriginalFilename", "libwebpdemux.dll"
|
||||
VALUE "ProductName", "WebP Image Demuxer"
|
||||
VALUE "ProductVersion", "1.2.1"
|
||||
VALUE "ProductVersion", "1.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -46,7 +46,6 @@ ENC_SOURCES += ssim.c
|
||||
libwebpdspdecode_sse41_la_SOURCES =
|
||||
libwebpdspdecode_sse41_la_SOURCES += alpha_processing_sse41.c
|
||||
libwebpdspdecode_sse41_la_SOURCES += dec_sse41.c
|
||||
libwebpdspdecode_sse41_la_SOURCES += lossless_sse41.c
|
||||
libwebpdspdecode_sse41_la_SOURCES += upsampling_sse41.c
|
||||
libwebpdspdecode_sse41_la_SOURCES += yuv_sse41.c
|
||||
libwebpdspdecode_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
|
||||
|
@ -157,8 +157,7 @@ void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) {
|
||||
}
|
||||
}
|
||||
|
||||
void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
|
||||
const uint8_t* WEBP_RESTRICT const alpha,
|
||||
void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
|
||||
int width, int inverse) {
|
||||
int x;
|
||||
for (x = 0; x < width; ++x) {
|
||||
@ -179,8 +178,7 @@ void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
|
||||
#undef MFIX
|
||||
|
||||
void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
|
||||
void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr,
|
||||
const uint8_t* WEBP_RESTRICT const alpha,
|
||||
void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
|
||||
int width, int inverse);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -195,8 +193,8 @@ void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
|
||||
}
|
||||
}
|
||||
|
||||
void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride,
|
||||
const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
|
||||
void WebPMultRows(uint8_t* ptr, int stride,
|
||||
const uint8_t* alpha, int alpha_stride,
|
||||
int width, int num_rows, int inverse) {
|
||||
int n;
|
||||
for (n = 0; n < num_rows; ++n) {
|
||||
@ -292,9 +290,9 @@ static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444,
|
||||
}
|
||||
|
||||
#if !WEBP_NEON_OMIT_C_CODE
|
||||
static int DispatchAlpha_C(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
|
||||
static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
|
||||
int width, int height,
|
||||
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
|
||||
uint8_t* dst, int dst_stride) {
|
||||
uint32_t alpha_mask = 0xff;
|
||||
int i, j;
|
||||
|
||||
@ -311,10 +309,9 @@ static int DispatchAlpha_C(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
|
||||
return (alpha_mask != 0xff);
|
||||
}
|
||||
|
||||
static void DispatchAlphaToGreen_C(const uint8_t* WEBP_RESTRICT alpha,
|
||||
int alpha_stride, int width, int height,
|
||||
uint32_t* WEBP_RESTRICT dst,
|
||||
int dst_stride) {
|
||||
static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
|
||||
int width, int height,
|
||||
uint32_t* dst, int dst_stride) {
|
||||
int i, j;
|
||||
for (j = 0; j < height; ++j) {
|
||||
for (i = 0; i < width; ++i) {
|
||||
@ -325,9 +322,9 @@ static void DispatchAlphaToGreen_C(const uint8_t* WEBP_RESTRICT alpha,
|
||||
}
|
||||
}
|
||||
|
||||
static int ExtractAlpha_C(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
|
||||
static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
|
||||
int width, int height,
|
||||
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
|
||||
uint8_t* alpha, int alpha_stride) {
|
||||
uint8_t alpha_mask = 0xff;
|
||||
int i, j;
|
||||
|
||||
@ -343,8 +340,7 @@ static int ExtractAlpha_C(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
|
||||
return (alpha_mask == 0xff);
|
||||
}
|
||||
|
||||
static void ExtractGreen_C(const uint32_t* WEBP_RESTRICT argb,
|
||||
uint8_t* WEBP_RESTRICT alpha, int size) {
|
||||
static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) {
|
||||
int i;
|
||||
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
|
||||
}
|
||||
@ -376,11 +372,8 @@ static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
static void PackARGB_C(const uint8_t* WEBP_RESTRICT a,
|
||||
const uint8_t* WEBP_RESTRICT r,
|
||||
const uint8_t* WEBP_RESTRICT g,
|
||||
const uint8_t* WEBP_RESTRICT b,
|
||||
int len, uint32_t* WEBP_RESTRICT out) {
|
||||
static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
|
||||
const uint8_t* b, int len, uint32_t* out) {
|
||||
int i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
|
||||
@ -388,10 +381,8 @@ static void PackARGB_C(const uint8_t* WEBP_RESTRICT a,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void PackRGB_C(const uint8_t* WEBP_RESTRICT r,
|
||||
const uint8_t* WEBP_RESTRICT g,
|
||||
const uint8_t* WEBP_RESTRICT b,
|
||||
int len, int step, uint32_t* WEBP_RESTRICT out) {
|
||||
static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
||||
int len, int step, uint32_t* out) {
|
||||
int i, offset = 0;
|
||||
for (i = 0; i < len; ++i) {
|
||||
out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
|
||||
@ -401,22 +392,16 @@ static void PackRGB_C(const uint8_t* WEBP_RESTRICT r,
|
||||
|
||||
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
||||
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
||||
int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
|
||||
uint8_t* WEBP_RESTRICT, int);
|
||||
void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT, int, int, int,
|
||||
uint32_t* WEBP_RESTRICT, int);
|
||||
int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
|
||||
uint8_t* WEBP_RESTRICT, int);
|
||||
void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb,
|
||||
uint8_t* WEBP_RESTRICT alpha, int size);
|
||||
int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
||||
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
|
||||
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
||||
void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
|
||||
const uint8_t* b, int, uint32_t*);
|
||||
#endif
|
||||
void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r,
|
||||
const uint8_t* WEBP_RESTRICT g,
|
||||
const uint8_t* WEBP_RESTRICT b,
|
||||
int len, int step, uint32_t* WEBP_RESTRICT out);
|
||||
void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
||||
int len, int step, uint32_t* out);
|
||||
|
||||
int (*WebPHasAlpha8b)(const uint8_t* src, int length);
|
||||
int (*WebPHasAlpha32b)(const uint8_t* src, int length);
|
||||
@ -453,10 +438,10 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
WebPInitAlphaProcessingSSE2();
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
WebPInitAlphaProcessingSSE41();
|
||||
}
|
||||
@ -470,7 +455,7 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
WebPInitAlphaProcessingNEON();
|
||||
|
@ -80,9 +80,9 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
|
||||
int alpha_stride, int width, int height,
|
||||
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
|
||||
static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
|
||||
int width, int height,
|
||||
uint8_t* dst, int dst_stride) {
|
||||
uint32_t alpha_mask = 0xffu;
|
||||
uint8x8_t mask8 = vdup_n_u8(0xff);
|
||||
uint32_t tmp[2];
|
||||
@ -113,10 +113,9 @@ static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
|
||||
return (alpha_mask != 0xffffffffu);
|
||||
}
|
||||
|
||||
static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,
|
||||
int alpha_stride, int width, int height,
|
||||
uint32_t* WEBP_RESTRICT dst,
|
||||
int dst_stride) {
|
||||
static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
|
||||
int width, int height,
|
||||
uint32_t* dst, int dst_stride) {
|
||||
int i, j;
|
||||
uint8x8x4_t greens; // leave A/R/B channels zero'd.
|
||||
greens.val[0] = vdup_n_u8(0);
|
||||
@ -133,9 +132,9 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,
|
||||
}
|
||||
}
|
||||
|
||||
static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
|
||||
static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
|
||||
int width, int height,
|
||||
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
|
||||
uint8_t* alpha, int alpha_stride) {
|
||||
uint32_t alpha_mask = 0xffu;
|
||||
uint8x8_t mask8 = vdup_n_u8(0xff);
|
||||
uint32_t tmp[2];
|
||||
@ -164,8 +163,8 @@ static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
|
||||
return (alpha_mask == 0xffffffffu);
|
||||
}
|
||||
|
||||
static void ExtractGreen_NEON(const uint32_t* WEBP_RESTRICT argb,
|
||||
uint8_t* WEBP_RESTRICT alpha, int size) {
|
||||
static void ExtractGreen_NEON(const uint32_t* argb,
|
||||
uint8_t* alpha, int size) {
|
||||
int i;
|
||||
for (i = 0; i + 16 <= size; i += 16) {
|
||||
const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));
|
||||
|
@ -18,9 +18,9 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha,
|
||||
int alpha_stride, int width, int height,
|
||||
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
|
||||
static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
|
||||
int width, int height,
|
||||
uint8_t* dst, int dst_stride) {
|
||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||
uint32_t alpha_and = 0xff;
|
||||
@ -72,10 +72,9 @@ static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha,
|
||||
return (alpha_and != 0xff);
|
||||
}
|
||||
|
||||
static void DispatchAlphaToGreen_SSE2(const uint8_t* WEBP_RESTRICT alpha,
|
||||
int alpha_stride, int width, int height,
|
||||
uint32_t* WEBP_RESTRICT dst,
|
||||
int dst_stride) {
|
||||
static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
|
||||
int width, int height,
|
||||
uint32_t* dst, int dst_stride) {
|
||||
int i, j;
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
const int limit = width & ~15;
|
||||
@ -99,9 +98,9 @@ static void DispatchAlphaToGreen_SSE2(const uint8_t* WEBP_RESTRICT alpha,
|
||||
}
|
||||
}
|
||||
|
||||
static int ExtractAlpha_SSE2(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
|
||||
static int ExtractAlpha_SSE2(const uint8_t* argb, int argb_stride,
|
||||
int width, int height,
|
||||
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
|
||||
uint8_t* alpha, int alpha_stride) {
|
||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||
uint32_t alpha_and = 0xff;
|
||||
@ -318,8 +317,7 @@ static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) {
|
||||
if (width > 0) WebPMultARGBRow_C(ptr + x, width, inverse);
|
||||
}
|
||||
|
||||
static void MultRow_SSE2(uint8_t* WEBP_RESTRICT const ptr,
|
||||
const uint8_t* WEBP_RESTRICT const alpha,
|
||||
static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
|
||||
int width, int inverse) {
|
||||
int x = 0;
|
||||
if (!inverse) {
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static int ExtractAlpha_SSE41(const uint8_t* WEBP_RESTRICT argb,
|
||||
int argb_stride, int width, int height,
|
||||
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
|
||||
static int ExtractAlpha_SSE41(const uint8_t* argb, int argb_stride,
|
||||
int width, int height,
|
||||
uint8_t* alpha, int alpha_stride) {
|
||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||
uint32_t alpha_and = 0xff;
|
||||
|
@ -395,12 +395,12 @@ WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) {
|
||||
VP8EncDspCostInitMIPSdspR2();
|
||||
}
|
||||
#endif
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
VP8EncDspCostInitSSE2();
|
||||
}
|
||||
#endif
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (VP8GetCPUInfo(kNEON)) {
|
||||
VP8EncDspCostInitNEON();
|
||||
}
|
||||
|
@ -189,17 +189,17 @@ VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
|
||||
// Use compile flags as an indicator of SIMD support instead of a runtime check.
|
||||
static int wasmCPUInfo(CPUFeature feature) {
|
||||
switch (feature) {
|
||||
#ifdef WEBP_HAVE_SSE2
|
||||
#ifdef WEBP_USE_SSE2
|
||||
case kSSE2:
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef WEBP_HAVE_SSE41
|
||||
#ifdef WEBP_USE_SSE41
|
||||
case kSSE3:
|
||||
case kSlowSSSE3:
|
||||
case kSSE4_1:
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef WEBP_HAVE_NEON
|
||||
#ifdef WEBP_USE_NEON
|
||||
case kNEON:
|
||||
return 1;
|
||||
#endif
|
||||
@ -209,10 +209,9 @@ static int wasmCPUInfo(CPUFeature feature) {
|
||||
return 0;
|
||||
}
|
||||
VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo;
|
||||
#elif defined(WEBP_HAVE_NEON)
|
||||
// In most cases this function doesn't check for NEON support (it's assumed by
|
||||
// the configuration), but enables turning off NEON at runtime, for testing
|
||||
// purposes, by setting VP8DecGetCPUInfo = NULL.
|
||||
#elif defined(WEBP_USE_NEON)
|
||||
// define a dummy function to enable turning off NEON at runtime by setting
|
||||
// VP8DecGetCPUInfo = NULL
|
||||
static int armCPUInfo(CPUFeature feature) {
|
||||
if (feature != kNEON) return 0;
|
||||
#if defined(__linux__) && defined(WEBP_HAVE_NEON_RTCD)
|
||||
|
@ -807,10 +807,10 @@ WEBP_DSP_INIT_FUNC(VP8DspInit) {
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
VP8DspInitSSE2();
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
VP8DspInitSSE41();
|
||||
}
|
||||
@ -834,7 +834,7 @@ WEBP_DSP_INIT_FUNC(VP8DspInit) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
VP8DspInitNEON();
|
||||
|
@ -26,23 +26,6 @@ extern "C" {
|
||||
|
||||
#define BPS 32 // this is the common stride for enc/dec
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// WEBP_RESTRICT
|
||||
|
||||
// Declares a pointer with the restrict type qualifier if available.
|
||||
// This allows code to hint to the compiler that only this pointer references a
|
||||
// particular object or memory region within the scope of the block in which it
|
||||
// is declared. This may allow for improved optimizations due to the lack of
|
||||
// pointer aliasing. See also:
|
||||
// https://en.cppreference.com/w/c/language/restrict
|
||||
#if defined(__GNUC__)
|
||||
#define WEBP_RESTRICT __restrict__
|
||||
#elif defined(_MSC_VER)
|
||||
#define WEBP_RESTRICT __restrict
|
||||
#else
|
||||
#define WEBP_RESTRICT
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CPU detection
|
||||
|
||||
@ -84,31 +67,21 @@ extern "C" {
|
||||
// files without intrinsics, allowing the corresponding Init() to be called.
|
||||
// Files containing intrinsics will need to be built targeting the instruction
|
||||
// set so should succeed on one of the earlier tests.
|
||||
#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
|
||||
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
|
||||
#if defined(__SSE2__) || defined(WEBP_MSC_SSE2) || defined(WEBP_HAVE_SSE2)
|
||||
#define WEBP_USE_SSE2
|
||||
#endif
|
||||
|
||||
#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
|
||||
#define WEBP_HAVE_SSE2
|
||||
#endif
|
||||
|
||||
#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
|
||||
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
|
||||
#if defined(__SSE4_1__) || defined(WEBP_MSC_SSE41) || defined(WEBP_HAVE_SSE41)
|
||||
#define WEBP_USE_SSE41
|
||||
#endif
|
||||
|
||||
#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
|
||||
#define WEBP_HAVE_SSE41
|
||||
#endif
|
||||
|
||||
#undef WEBP_MSC_SSE41
|
||||
#undef WEBP_MSC_SSE2
|
||||
|
||||
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
|
||||
// inline assembly would need to be modified for use with Native Client.
|
||||
#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
|
||||
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
|
||||
#if (defined(__ARM_NEON__) || \
|
||||
defined(__aarch64__) || defined(WEBP_HAVE_NEON)) && \
|
||||
!defined(__native_client__)
|
||||
#define WEBP_USE_NEON
|
||||
#endif
|
||||
@ -124,10 +97,6 @@ extern "C" {
|
||||
#define WEBP_USE_INTRINSICS
|
||||
#endif
|
||||
|
||||
#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
|
||||
#define WEBP_HAVE_NEON
|
||||
#endif
|
||||
|
||||
#if defined(__mips__) && !defined(__mips64) && \
|
||||
defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
|
||||
#define WEBP_USE_MIPS32
|
||||
@ -147,7 +116,7 @@ extern "C" {
|
||||
#define WEBP_DSP_OMIT_C_CODE 1
|
||||
#endif
|
||||
|
||||
#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
|
||||
#if (defined(__aarch64__) || defined(__ARM_NEON__)) && WEBP_DSP_OMIT_C_CODE
|
||||
#define WEBP_NEON_OMIT_C_CODE 1
|
||||
#else
|
||||
#define WEBP_NEON_OMIT_C_CODE 0
|
||||
@ -609,29 +578,26 @@ extern void (*WebPApplyAlphaMultiply4444)(
|
||||
|
||||
// Dispatch the values from alpha[] plane to the ARGB destination 'dst'.
|
||||
// Returns true if alpha[] plane has non-trivial values different from 0xff.
|
||||
extern int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT alpha,
|
||||
int alpha_stride, int width, int height,
|
||||
uint8_t* WEBP_RESTRICT dst, int dst_stride);
|
||||
extern int (*WebPDispatchAlpha)(const uint8_t* alpha, int alpha_stride,
|
||||
int width, int height,
|
||||
uint8_t* dst, int dst_stride);
|
||||
|
||||
// Transfer packed 8b alpha[] values to green channel in dst[], zero'ing the
|
||||
// A/R/B values. 'dst_stride' is the stride for dst[] in uint32_t units.
|
||||
extern void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT alpha,
|
||||
int alpha_stride, int width, int height,
|
||||
uint32_t* WEBP_RESTRICT dst,
|
||||
int dst_stride);
|
||||
extern void (*WebPDispatchAlphaToGreen)(const uint8_t* alpha, int alpha_stride,
|
||||
int width, int height,
|
||||
uint32_t* dst, int dst_stride);
|
||||
|
||||
// Extract the alpha values from 32b values in argb[] and pack them into alpha[]
|
||||
// (this is the opposite of WebPDispatchAlpha).
|
||||
// Returns true if there's only trivial 0xff alpha values.
|
||||
extern int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT argb,
|
||||
int argb_stride, int width, int height,
|
||||
uint8_t* WEBP_RESTRICT alpha,
|
||||
int alpha_stride);
|
||||
extern int (*WebPExtractAlpha)(const uint8_t* argb, int argb_stride,
|
||||
int width, int height,
|
||||
uint8_t* alpha, int alpha_stride);
|
||||
|
||||
// Extract the green values from 32b values in argb[] and pack them into alpha[]
|
||||
// (this is the opposite of WebPDispatchAlphaToGreen).
|
||||
extern void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb,
|
||||
uint8_t* WEBP_RESTRICT alpha, int size);
|
||||
extern void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
|
||||
|
||||
// Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B).
|
||||
// Un-Multiply operation transforms x into x * 255 / A.
|
||||
@ -644,35 +610,29 @@ void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
|
||||
int inverse);
|
||||
|
||||
// Same for a row of single values, with side alpha values.
|
||||
extern void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr,
|
||||
const uint8_t* WEBP_RESTRICT const alpha,
|
||||
extern void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
|
||||
int width, int inverse);
|
||||
|
||||
// Same a WebPMultRow(), but for several 'num_rows' rows.
|
||||
void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride,
|
||||
const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
|
||||
void WebPMultRows(uint8_t* ptr, int stride,
|
||||
const uint8_t* alpha, int alpha_stride,
|
||||
int width, int num_rows, int inverse);
|
||||
|
||||
// Plain-C versions, used as fallback by some implementations.
|
||||
void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
|
||||
const uint8_t* WEBP_RESTRICT const alpha,
|
||||
void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
|
||||
int width, int inverse);
|
||||
void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse);
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
// ARGB packing function: a/r/g/b input is rgba or bgra order.
|
||||
extern void (*WebPPackARGB)(const uint8_t* WEBP_RESTRICT a,
|
||||
const uint8_t* WEBP_RESTRICT r,
|
||||
const uint8_t* WEBP_RESTRICT g,
|
||||
const uint8_t* WEBP_RESTRICT b,
|
||||
int len, uint32_t* WEBP_RESTRICT out);
|
||||
extern void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r,
|
||||
const uint8_t* g, const uint8_t* b, int len,
|
||||
uint32_t* out);
|
||||
#endif
|
||||
|
||||
// RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order.
|
||||
extern void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r,
|
||||
const uint8_t* WEBP_RESTRICT g,
|
||||
const uint8_t* WEBP_RESTRICT b,
|
||||
int len, int step, uint32_t* WEBP_RESTRICT out);
|
||||
extern void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
||||
int len, int step, uint32_t* out);
|
||||
|
||||
// This function returns true if src[i] contains a value different from 0xff.
|
||||
extern int (*WebPHasAlpha8b)(const uint8_t* src, int length);
|
||||
|
@ -773,10 +773,10 @@ WEBP_DSP_INIT_FUNC(VP8EncDspInit) {
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
VP8EncDspInitSSE2();
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
VP8EncDspInitSSE41();
|
||||
}
|
||||
@ -800,7 +800,7 @@ WEBP_DSP_INIT_FUNC(VP8EncDspInit) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
VP8EncDspInitNEON();
|
||||
|
@ -254,7 +254,7 @@ WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
|
||||
#endif
|
||||
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
VP8FiltersInitSSE2();
|
||||
}
|
||||
@ -271,7 +271,7 @@ WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
VP8FiltersInitNEON();
|
||||
|
@ -320,12 +320,7 @@ extern void VP8FiltersInitSSE2(void);
|
||||
|
||||
WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) {
|
||||
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_SSE2;
|
||||
#if defined(CHROMIUM)
|
||||
// TODO(crbug.com/654974)
|
||||
(void)VerticalUnfilter_SSE2;
|
||||
#else
|
||||
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_SSE2;
|
||||
#endif
|
||||
WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_SSE2;
|
||||
|
||||
WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_SSE2;
|
||||
|
@ -575,7 +575,6 @@ VP8LMapARGBFunc VP8LMapColor32b;
|
||||
VP8LMapAlphaFunc VP8LMapColor8b;
|
||||
|
||||
extern void VP8LDspInitSSE2(void);
|
||||
extern void VP8LDspInitSSE41(void);
|
||||
extern void VP8LDspInitNEON(void);
|
||||
extern void VP8LDspInitMIPSdspR2(void);
|
||||
extern void VP8LDspInitMSA(void);
|
||||
@ -622,14 +621,9 @@ WEBP_DSP_INIT_FUNC(VP8LDspInit) {
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
VP8LDspInitSSE2();
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
VP8LDspInitSSE41();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if defined(WEBP_USE_MIPS_DSP_R2)
|
||||
@ -644,7 +638,7 @@ WEBP_DSP_INIT_FUNC(VP8LDspInit) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
VP8LDspInitNEON();
|
||||
|
@ -329,15 +329,6 @@ const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX] = {
|
||||
static float FastSLog2Slow_C(uint32_t v) {
|
||||
assert(v >= LOG_LOOKUP_IDX_MAX);
|
||||
if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
|
||||
#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ)
|
||||
// use clz if available
|
||||
const int log_cnt = BitsLog2Floor(v) - 7;
|
||||
const uint32_t y = 1 << log_cnt;
|
||||
int correction = 0;
|
||||
const float v_f = (float)v;
|
||||
const uint32_t orig_v = v;
|
||||
v >>= log_cnt;
|
||||
#else
|
||||
int log_cnt = 0;
|
||||
uint32_t y = 1;
|
||||
int correction = 0;
|
||||
@ -348,7 +339,6 @@ static float FastSLog2Slow_C(uint32_t v) {
|
||||
v = v >> 1;
|
||||
y = y << 1;
|
||||
} while (v >= LOG_LOOKUP_IDX_MAX);
|
||||
#endif
|
||||
// vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256
|
||||
// Xf = floor(Xf) * (1 + (v % y) / v)
|
||||
// log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v)
|
||||
@ -365,14 +355,6 @@ static float FastSLog2Slow_C(uint32_t v) {
|
||||
static float FastLog2Slow_C(uint32_t v) {
|
||||
assert(v >= LOG_LOOKUP_IDX_MAX);
|
||||
if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
|
||||
#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ)
|
||||
// use clz if available
|
||||
const int log_cnt = BitsLog2Floor(v) - 7;
|
||||
const uint32_t y = 1 << log_cnt;
|
||||
const uint32_t orig_v = v;
|
||||
double log_2;
|
||||
v >>= log_cnt;
|
||||
#else
|
||||
int log_cnt = 0;
|
||||
uint32_t y = 1;
|
||||
const uint32_t orig_v = v;
|
||||
@ -382,7 +364,6 @@ static float FastLog2Slow_C(uint32_t v) {
|
||||
v = v >> 1;
|
||||
y = y << 1;
|
||||
} while (v >= LOG_LOOKUP_IDX_MAX);
|
||||
#endif
|
||||
log_2 = kLog2Table[v] + log_cnt;
|
||||
if (orig_v >= APPROX_LOG_MAX) {
|
||||
// Since the division is still expensive, add this correction factor only
|
||||
@ -862,10 +843,10 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
VP8LEncDspInitSSE2();
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
VP8LEncDspInitSSE41();
|
||||
}
|
||||
@ -889,7 +870,7 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
VP8LEncDspInitNEON();
|
||||
|
@ -232,55 +232,79 @@ static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
|
||||
//------------------------------------------------------------------------------
|
||||
// Entropy
|
||||
|
||||
// TODO(https://crbug.com/webp/499): this function produces different results
|
||||
// from the C code due to use of double/float resulting in output differences
|
||||
// when compared to -noasm.
|
||||
#if !(defined(WEBP_HAVE_SLOW_CLZ_CTZ) || defined(__i386__) || defined(_M_IX86))
|
||||
// Checks whether the X or Y contribution is worth computing and adding.
|
||||
// Used in loop unrolling.
|
||||
#define ANALYZE_X_OR_Y(x_or_y, j) \
|
||||
do { \
|
||||
if ((x_or_y)[i + (j)] != 0) retval -= VP8LFastSLog2((x_or_y)[i + (j)]); \
|
||||
} while (0)
|
||||
|
||||
// Checks whether the X + Y contribution is worth computing and adding.
|
||||
// Used in loop unrolling.
|
||||
#define ANALYZE_XY(j) \
|
||||
do { \
|
||||
if (tmp[j] != 0) { \
|
||||
retval -= VP8LFastSLog2(tmp[j]); \
|
||||
ANALYZE_X_OR_Y(X, j); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if !(defined(__i386__) || defined(_M_IX86))
|
||||
static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) {
|
||||
int i;
|
||||
double retval = 0.;
|
||||
int sumX = 0, sumXY = 0;
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
int sumX, sumXY;
|
||||
int32_t tmp[4];
|
||||
__m128i zero = _mm_setzero_si128();
|
||||
// Sums up X + Y, 4 ints at a time (and will merge it at the end for sumXY).
|
||||
__m128i sumXY_128 = zero;
|
||||
__m128i sumX_128 = zero;
|
||||
|
||||
for (i = 0; i < 256; i += 16) {
|
||||
const __m128i x0 = _mm_loadu_si128((const __m128i*)(X + i + 0));
|
||||
const __m128i y0 = _mm_loadu_si128((const __m128i*)(Y + i + 0));
|
||||
const __m128i x1 = _mm_loadu_si128((const __m128i*)(X + i + 4));
|
||||
const __m128i y1 = _mm_loadu_si128((const __m128i*)(Y + i + 4));
|
||||
const __m128i x2 = _mm_loadu_si128((const __m128i*)(X + i + 8));
|
||||
const __m128i y2 = _mm_loadu_si128((const __m128i*)(Y + i + 8));
|
||||
const __m128i x3 = _mm_loadu_si128((const __m128i*)(X + i + 12));
|
||||
const __m128i y3 = _mm_loadu_si128((const __m128i*)(Y + i + 12));
|
||||
const __m128i x4 = _mm_packs_epi16(_mm_packs_epi32(x0, x1),
|
||||
_mm_packs_epi32(x2, x3));
|
||||
const __m128i y4 = _mm_packs_epi16(_mm_packs_epi32(y0, y1),
|
||||
_mm_packs_epi32(y2, y3));
|
||||
const int32_t mx = _mm_movemask_epi8(_mm_cmpgt_epi8(x4, zero));
|
||||
int32_t my = _mm_movemask_epi8(_mm_cmpgt_epi8(y4, zero)) | mx;
|
||||
while (my) {
|
||||
const int32_t j = BitsCtz(my);
|
||||
int xy;
|
||||
if ((mx >> j) & 1) {
|
||||
const int x = X[i + j];
|
||||
sumXY += x;
|
||||
retval -= VP8LFastSLog2(x);
|
||||
}
|
||||
xy = X[i + j] + Y[i + j];
|
||||
sumX += xy;
|
||||
retval -= VP8LFastSLog2(xy);
|
||||
my &= my - 1;
|
||||
for (i = 0; i < 256; i += 4) {
|
||||
const __m128i x = _mm_loadu_si128((const __m128i*)(X + i));
|
||||
const __m128i y = _mm_loadu_si128((const __m128i*)(Y + i));
|
||||
|
||||
// Check if any X is non-zero: this actually provides a speedup as X is
|
||||
// usually sparse.
|
||||
if (_mm_movemask_epi8(_mm_cmpeq_epi32(x, zero)) != 0xFFFF) {
|
||||
const __m128i xy_128 = _mm_add_epi32(x, y);
|
||||
sumXY_128 = _mm_add_epi32(sumXY_128, xy_128);
|
||||
|
||||
sumX_128 = _mm_add_epi32(sumX_128, x);
|
||||
|
||||
// Analyze the different X + Y.
|
||||
_mm_storeu_si128((__m128i*)tmp, xy_128);
|
||||
|
||||
ANALYZE_XY(0);
|
||||
ANALYZE_XY(1);
|
||||
ANALYZE_XY(2);
|
||||
ANALYZE_XY(3);
|
||||
} else {
|
||||
// X is fully 0, so only deal with Y.
|
||||
sumXY_128 = _mm_add_epi32(sumXY_128, y);
|
||||
|
||||
ANALYZE_X_OR_Y(Y, 0);
|
||||
ANALYZE_X_OR_Y(Y, 1);
|
||||
ANALYZE_X_OR_Y(Y, 2);
|
||||
ANALYZE_X_OR_Y(Y, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Sum up sumX_128 to get sumX.
|
||||
_mm_storeu_si128((__m128i*)tmp, sumX_128);
|
||||
sumX = tmp[3] + tmp[2] + tmp[1] + tmp[0];
|
||||
|
||||
// Sum up sumXY_128 to get sumXY.
|
||||
_mm_storeu_si128((__m128i*)tmp, sumXY_128);
|
||||
sumXY = tmp[3] + tmp[2] + tmp[1] + tmp[0];
|
||||
|
||||
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
|
||||
return (float)retval;
|
||||
}
|
||||
#endif // !(defined(__i386__) || defined(_M_IX86))
|
||||
|
||||
#else
|
||||
|
||||
#define DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC // won't be faster
|
||||
|
||||
#endif
|
||||
#undef ANALYZE_X_OR_Y
|
||||
#undef ANALYZE_XY
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -638,7 +662,10 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) {
|
||||
VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE2;
|
||||
VP8LAddVector = AddVector_SSE2;
|
||||
VP8LAddVectorEq = AddVectorEq_SSE2;
|
||||
#if !defined(DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC)
|
||||
// TODO(https://crbug.com/webp/499): this function produces different results
|
||||
// from the C code due to use of double/float resulting in output differences
|
||||
// when compared to -noasm.
|
||||
#if !(defined(__i386__) || defined(_M_IX86))
|
||||
VP8LCombinedShannonEntropy = CombinedShannonEntropy_SSE2;
|
||||
#endif
|
||||
VP8LVectorMismatch = VectorMismatch_SSE2;
|
||||
|
@ -44,47 +44,46 @@ static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data,
|
||||
//------------------------------------------------------------------------------
|
||||
// Color Transform
|
||||
|
||||
#define MK_CST_16(HI, LO) \
|
||||
_mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff)))
|
||||
|
||||
#define SPAN 8
|
||||
static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride,
|
||||
int tile_width, int tile_height,
|
||||
int green_to_blue, int red_to_blue,
|
||||
int histo[]) {
|
||||
const __m128i mult =
|
||||
MK_CST_16(CST_5b(red_to_blue) + 256,CST_5b(green_to_blue));
|
||||
const __m128i perm =
|
||||
_mm_setr_epi8(-1, 1, -1, 2, -1, 5, -1, 6, -1, 9, -1, 10, -1, 13, -1, 14);
|
||||
if (tile_width >= 4) {
|
||||
int y;
|
||||
for (y = 0; y < tile_height; ++y) {
|
||||
const uint32_t* const src = argb + y * stride;
|
||||
const __m128i A1 = _mm_loadu_si128((const __m128i*)src);
|
||||
const __m128i B1 = _mm_shuffle_epi8(A1, perm);
|
||||
const __m128i C1 = _mm_mulhi_epi16(B1, mult);
|
||||
const __m128i D1 = _mm_sub_epi16(A1, C1);
|
||||
__m128i E = _mm_add_epi16(_mm_srli_epi32(D1, 16), D1);
|
||||
int x;
|
||||
for (x = 4; x + 4 <= tile_width; x += 4) {
|
||||
const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x));
|
||||
__m128i B2, C2, D2;
|
||||
++histo[_mm_extract_epi8(E, 0)];
|
||||
B2 = _mm_shuffle_epi8(A2, perm);
|
||||
++histo[_mm_extract_epi8(E, 4)];
|
||||
C2 = _mm_mulhi_epi16(B2, mult);
|
||||
++histo[_mm_extract_epi8(E, 8)];
|
||||
D2 = _mm_sub_epi16(A2, C2);
|
||||
++histo[_mm_extract_epi8(E, 12)];
|
||||
E = _mm_add_epi16(_mm_srli_epi32(D2, 16), D2);
|
||||
}
|
||||
++histo[_mm_extract_epi8(E, 0)];
|
||||
++histo[_mm_extract_epi8(E, 4)];
|
||||
++histo[_mm_extract_epi8(E, 8)];
|
||||
++histo[_mm_extract_epi8(E, 12)];
|
||||
const __m128i mults_r = _mm_set1_epi16(CST_5b(red_to_blue));
|
||||
const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_blue));
|
||||
const __m128i mask_g = _mm_set1_epi16((short)0xff00); // green mask
|
||||
const __m128i mask_gb = _mm_set1_epi32(0xffff); // green/blue mask
|
||||
const __m128i mask_b = _mm_set1_epi16(0x00ff); // blue mask
|
||||
const __m128i shuffler_lo = _mm_setr_epi8(-1, 2, -1, 6, -1, 10, -1, 14, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1);
|
||||
const __m128i shuffler_hi = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
2, -1, 6, -1, 10, -1, 14);
|
||||
int y;
|
||||
for (y = 0; y < tile_height; ++y) {
|
||||
const uint32_t* const src = argb + y * stride;
|
||||
int i, x;
|
||||
for (x = 0; x + SPAN <= tile_width; x += SPAN) {
|
||||
uint16_t values[SPAN];
|
||||
const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]);
|
||||
const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]);
|
||||
const __m128i r0 = _mm_shuffle_epi8(in0, shuffler_lo);
|
||||
const __m128i r1 = _mm_shuffle_epi8(in1, shuffler_hi);
|
||||
const __m128i r = _mm_or_si128(r0, r1); // r 0
|
||||
const __m128i gb0 = _mm_and_si128(in0, mask_gb);
|
||||
const __m128i gb1 = _mm_and_si128(in1, mask_gb);
|
||||
const __m128i gb = _mm_packus_epi32(gb0, gb1); // g b
|
||||
const __m128i g = _mm_and_si128(gb, mask_g); // g 0
|
||||
const __m128i A = _mm_mulhi_epi16(r, mults_r); // x dbr
|
||||
const __m128i B = _mm_mulhi_epi16(g, mults_g); // x dbg
|
||||
const __m128i C = _mm_sub_epi8(gb, B); // x b'
|
||||
const __m128i D = _mm_sub_epi8(C, A); // x b''
|
||||
const __m128i E = _mm_and_si128(D, mask_b); // 0 b''
|
||||
_mm_storeu_si128((__m128i*)values, E);
|
||||
for (i = 0; i < SPAN; ++i) ++histo[values[i]];
|
||||
}
|
||||
}
|
||||
{
|
||||
const int left_over = tile_width & 3;
|
||||
const int left_over = tile_width & (SPAN - 1);
|
||||
if (left_over > 0) {
|
||||
VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride,
|
||||
left_over, tile_height,
|
||||
@ -96,37 +95,33 @@ static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride,
|
||||
static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride,
|
||||
int tile_width, int tile_height,
|
||||
int green_to_red, int histo[]) {
|
||||
const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_red));
|
||||
const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask
|
||||
const __m128i mask = _mm_set1_epi16(0xff);
|
||||
|
||||
const __m128i mult = MK_CST_16(0, CST_5b(green_to_red));
|
||||
const __m128i mask_g = _mm_set1_epi32(0x0000ff00);
|
||||
if (tile_width >= 4) {
|
||||
int y;
|
||||
for (y = 0; y < tile_height; ++y) {
|
||||
const uint32_t* const src = argb + y * stride;
|
||||
const __m128i A1 = _mm_loadu_si128((const __m128i*)src);
|
||||
const __m128i B1 = _mm_and_si128(A1, mask_g);
|
||||
const __m128i C1 = _mm_madd_epi16(B1, mult);
|
||||
__m128i D = _mm_sub_epi16(A1, C1);
|
||||
int x;
|
||||
for (x = 4; x + 4 <= tile_width; x += 4) {
|
||||
const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x));
|
||||
__m128i B2, C2;
|
||||
++histo[_mm_extract_epi8(D, 2)];
|
||||
B2 = _mm_and_si128(A2, mask_g);
|
||||
++histo[_mm_extract_epi8(D, 6)];
|
||||
C2 = _mm_madd_epi16(B2, mult);
|
||||
++histo[_mm_extract_epi8(D, 10)];
|
||||
++histo[_mm_extract_epi8(D, 14)];
|
||||
D = _mm_sub_epi16(A2, C2);
|
||||
}
|
||||
++histo[_mm_extract_epi8(D, 2)];
|
||||
++histo[_mm_extract_epi8(D, 6)];
|
||||
++histo[_mm_extract_epi8(D, 10)];
|
||||
++histo[_mm_extract_epi8(D, 14)];
|
||||
int y;
|
||||
for (y = 0; y < tile_height; ++y) {
|
||||
const uint32_t* const src = argb + y * stride;
|
||||
int i, x;
|
||||
for (x = 0; x + SPAN <= tile_width; x += SPAN) {
|
||||
uint16_t values[SPAN];
|
||||
const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]);
|
||||
const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]);
|
||||
const __m128i g0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0
|
||||
const __m128i g1 = _mm_and_si128(in1, mask_g);
|
||||
const __m128i g = _mm_packus_epi32(g0, g1); // g 0
|
||||
const __m128i A0 = _mm_srli_epi32(in0, 16); // 0 0 | x r
|
||||
const __m128i A1 = _mm_srli_epi32(in1, 16);
|
||||
const __m128i A = _mm_packus_epi32(A0, A1); // x r
|
||||
const __m128i B = _mm_mulhi_epi16(g, mults_g); // x dr
|
||||
const __m128i C = _mm_sub_epi8(A, B); // x r'
|
||||
const __m128i D = _mm_and_si128(C, mask); // 0 r'
|
||||
_mm_storeu_si128((__m128i*)values, D);
|
||||
for (i = 0; i < SPAN; ++i) ++histo[values[i]];
|
||||
}
|
||||
}
|
||||
{
|
||||
const int left_over = tile_width & 3;
|
||||
const int left_over = tile_width & (SPAN - 1);
|
||||
if (left_over > 0) {
|
||||
VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride,
|
||||
left_over, tile_height, green_to_red,
|
||||
@ -135,8 +130,6 @@ static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride,
|
||||
}
|
||||
}
|
||||
|
||||
#undef MK_CST_16
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Entry point
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "src/dsp/common_sse2.h"
|
||||
#include "src/dsp/lossless.h"
|
||||
#include "src/dsp/lossless_common.h"
|
||||
#include <assert.h>
|
||||
#include <emmintrin.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -1,132 +0,0 @@
|
||||
// Copyright 2021 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the COPYING file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// SSE41 variant of methods for lossless decoder
|
||||
|
||||
#include "src/dsp/dsp.h"
|
||||
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
|
||||
#include "src/dsp/common_sse41.h"
|
||||
#include "src/dsp/lossless.h"
|
||||
#include "src/dsp/lossless_common.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Color-space conversion functions
|
||||
|
||||
static void TransformColorInverse_SSE41(const VP8LMultipliers* const m,
|
||||
const uint32_t* const src,
|
||||
int num_pixels, uint32_t* dst) {
|
||||
// sign-extended multiplying constants, pre-shifted by 5.
|
||||
#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend
|
||||
const __m128i mults_rb = _mm_set1_epi32((uint32_t)CST(green_to_red_) << 16 |
|
||||
(CST(green_to_blue_) & 0xffff));
|
||||
const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue_));
|
||||
#undef CST
|
||||
const __m128i mask_ag = _mm_set1_epi32(0xff00ff00);
|
||||
const __m128i perm1 = _mm_setr_epi8(-1, 1, -1, 1, -1, 5, -1, 5,
|
||||
-1, 9, -1, 9, -1, 13, -1, 13);
|
||||
const __m128i perm2 = _mm_setr_epi8(-1, 2, -1, -1, -1, 6, -1, -1,
|
||||
-1, 10, -1, -1, -1, 14, -1, -1);
|
||||
int i;
|
||||
for (i = 0; i + 4 <= num_pixels; i += 4) {
|
||||
const __m128i A = _mm_loadu_si128((const __m128i*)(src + i));
|
||||
const __m128i B = _mm_shuffle_epi8(A, perm1); // argb -> g0g0
|
||||
const __m128i C = _mm_mulhi_epi16(B, mults_rb);
|
||||
const __m128i D = _mm_add_epi8(A, C);
|
||||
const __m128i E = _mm_shuffle_epi8(D, perm2);
|
||||
const __m128i F = _mm_mulhi_epi16(E, mults_b2);
|
||||
const __m128i G = _mm_add_epi8(D, F);
|
||||
const __m128i out = _mm_blendv_epi8(G, A, mask_ag);
|
||||
_mm_storeu_si128((__m128i*)&dst[i], out);
|
||||
}
|
||||
// Fall-back to C-version for left-overs.
|
||||
if (i != num_pixels) {
|
||||
VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define ARGB_TO_RGB_SSE41 do { \
|
||||
while (num_pixels >= 16) { \
|
||||
const __m128i in0 = _mm_loadu_si128(in + 0); \
|
||||
const __m128i in1 = _mm_loadu_si128(in + 1); \
|
||||
const __m128i in2 = _mm_loadu_si128(in + 2); \
|
||||
const __m128i in3 = _mm_loadu_si128(in + 3); \
|
||||
const __m128i a0 = _mm_shuffle_epi8(in0, perm0); \
|
||||
const __m128i a1 = _mm_shuffle_epi8(in1, perm1); \
|
||||
const __m128i a2 = _mm_shuffle_epi8(in2, perm2); \
|
||||
const __m128i a3 = _mm_shuffle_epi8(in3, perm3); \
|
||||
const __m128i b0 = _mm_blend_epi16(a0, a1, 0xc0); \
|
||||
const __m128i b1 = _mm_blend_epi16(a1, a2, 0xf0); \
|
||||
const __m128i b2 = _mm_blend_epi16(a2, a3, 0xfc); \
|
||||
_mm_storeu_si128(out + 0, b0); \
|
||||
_mm_storeu_si128(out + 1, b1); \
|
||||
_mm_storeu_si128(out + 2, b2); \
|
||||
in += 4; \
|
||||
out += 3; \
|
||||
num_pixels -= 16; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void ConvertBGRAToRGB_SSE41(const uint32_t* src, int num_pixels,
|
||||
uint8_t* dst) {
|
||||
const __m128i* in = (const __m128i*)src;
|
||||
__m128i* out = (__m128i*)dst;
|
||||
const __m128i perm0 = _mm_setr_epi8(2, 1, 0, 6, 5, 4, 10, 9,
|
||||
8, 14, 13, 12, -1, -1, -1, -1);
|
||||
const __m128i perm1 = _mm_shuffle_epi32(perm0, 0x39);
|
||||
const __m128i perm2 = _mm_shuffle_epi32(perm0, 0x4e);
|
||||
const __m128i perm3 = _mm_shuffle_epi32(perm0, 0x93);
|
||||
|
||||
ARGB_TO_RGB_SSE41;
|
||||
|
||||
// left-overs
|
||||
if (num_pixels > 0) {
|
||||
VP8LConvertBGRAToRGB_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertBGRAToBGR_SSE41(const uint32_t* src,
|
||||
int num_pixels, uint8_t* dst) {
|
||||
const __m128i* in = (const __m128i*)src;
|
||||
__m128i* out = (__m128i*)dst;
|
||||
const __m128i perm0 = _mm_setr_epi8(0, 1, 2, 4, 5, 6, 8, 9, 10,
|
||||
12, 13, 14, -1, -1, -1, -1);
|
||||
const __m128i perm1 = _mm_shuffle_epi32(perm0, 0x39);
|
||||
const __m128i perm2 = _mm_shuffle_epi32(perm0, 0x4e);
|
||||
const __m128i perm3 = _mm_shuffle_epi32(perm0, 0x93);
|
||||
|
||||
ARGB_TO_RGB_SSE41;
|
||||
|
||||
// left-overs
|
||||
if (num_pixels > 0) {
|
||||
VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
|
||||
}
|
||||
}
|
||||
|
||||
#undef ARGB_TO_RGB_SSE41
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Entry point
|
||||
|
||||
extern void VP8LDspInitSSE41(void);
|
||||
|
||||
WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE41(void) {
|
||||
VP8LTransformColorInverse = TransformColorInverse_SSE41;
|
||||
VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE41;
|
||||
VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE41;
|
||||
}
|
||||
|
||||
#else // !WEBP_USE_SSE41
|
||||
|
||||
WEBP_DSP_INIT_STUB(VP8LDspInitSSE41)
|
||||
|
||||
#endif // WEBP_USE_SSE41
|
@ -38,9 +38,8 @@ void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
|
||||
int x_out = channel;
|
||||
// simple bilinear interpolation
|
||||
int accum = wrk->x_add;
|
||||
rescaler_t left = (rescaler_t)src[x_in];
|
||||
rescaler_t right =
|
||||
(wrk->src_width > 1) ? (rescaler_t)src[x_in + x_stride] : left;
|
||||
int left = src[x_in];
|
||||
int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
|
||||
x_in += x_stride;
|
||||
while (1) {
|
||||
wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
|
||||
@ -51,7 +50,7 @@ void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
|
||||
left = right;
|
||||
x_in += x_stride;
|
||||
assert(x_in < wrk->src_width * x_stride);
|
||||
right = (rescaler_t)src[x_in];
|
||||
right = src[x_in];
|
||||
accum += wrk->x_add;
|
||||
}
|
||||
}
|
||||
@ -214,7 +213,7 @@ WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
|
||||
WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
|
||||
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
WebPRescalerDspInitSSE2();
|
||||
}
|
||||
@ -236,7 +235,7 @@ WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
WebPRescalerDspInitNEON();
|
||||
|
@ -150,7 +150,7 @@ WEBP_DSP_INIT_FUNC(VP8SSIMDspInit) {
|
||||
#endif
|
||||
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
VP8SSIMDspInitSSE2();
|
||||
}
|
||||
|
@ -233,12 +233,12 @@ WEBP_DSP_INIT_FUNC(WebPInitYUV444Converters) {
|
||||
WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444_C;
|
||||
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
WebPInitYUV444ConvertersSSE2();
|
||||
}
|
||||
#endif
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
WebPInitYUV444ConvertersSSE41();
|
||||
}
|
||||
@ -278,12 +278,12 @@ WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) {
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
WebPInitUpsamplersSSE2();
|
||||
}
|
||||
#endif
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
WebPInitUpsamplersSSE41();
|
||||
}
|
||||
@ -300,7 +300,7 @@ WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
WebPInitUpsamplersNEON();
|
||||
|
@ -90,16 +90,16 @@ WEBP_DSP_INIT_FUNC(WebPInitSamplers) {
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
WebPInitSamplersSSE2();
|
||||
}
|
||||
#endif // WEBP_HAVE_SSE2
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
#endif // WEBP_USE_SSE2
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
WebPInitSamplersSSE41();
|
||||
}
|
||||
#endif // WEBP_HAVE_SSE41
|
||||
#endif // WEBP_USE_SSE41
|
||||
#if defined(WEBP_USE_MIPS32)
|
||||
if (VP8GetCPUInfo(kMIPS32)) {
|
||||
WebPInitSamplersMIPS32();
|
||||
@ -276,26 +276,26 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
|
||||
#endif
|
||||
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
#if defined(WEBP_HAVE_SSE2)
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
if (VP8GetCPUInfo(kSSE2)) {
|
||||
WebPInitConvertARGBToYUVSSE2();
|
||||
WebPInitSharpYUVSSE2();
|
||||
}
|
||||
#endif // WEBP_HAVE_SSE2
|
||||
#if defined(WEBP_HAVE_SSE41)
|
||||
#endif // WEBP_USE_SSE2
|
||||
#if defined(WEBP_USE_SSE41)
|
||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||
WebPInitConvertARGBToYUVSSE41();
|
||||
}
|
||||
#endif // WEBP_HAVE_SSE41
|
||||
#endif // WEBP_USE_SSE41
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_NEON)
|
||||
#if defined(WEBP_USE_NEON)
|
||||
if (WEBP_NEON_OMIT_C_CODE ||
|
||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||
WebPInitConvertARGBToYUVNEON();
|
||||
WebPInitSharpYUVNEON();
|
||||
}
|
||||
#endif // WEBP_HAVE_NEON
|
||||
#endif // WEBP_USE_NEON
|
||||
|
||||
assert(WebPConvertARGBToY != NULL);
|
||||
assert(WebPConvertARGBToUV != NULL);
|
||||
|
@ -303,7 +303,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
|
||||
int ok = 1;
|
||||
const int reduce_levels = (quality < 100);
|
||||
|
||||
// quick correctness checks
|
||||
// quick sanity checks
|
||||
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
|
||||
assert(enc != NULL && pic != NULL && pic->a != NULL);
|
||||
assert(output != NULL && output_size != NULL);
|
||||
@ -361,7 +361,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
|
||||
//------------------------------------------------------------------------------
|
||||
// Main calls
|
||||
|
||||
static int CompressAlphaJob(void* arg1, void* unused) {
|
||||
static int CompressAlphaJob(void* arg1, void* dummy) {
|
||||
VP8Encoder* const enc = (VP8Encoder*)arg1;
|
||||
const WebPConfig* config = enc->config_;
|
||||
uint8_t* alpha_data = NULL;
|
||||
@ -375,13 +375,13 @@ static int CompressAlphaJob(void* arg1, void* unused) {
|
||||
filter, effort_level, &alpha_data, &alpha_size)) {
|
||||
return 0;
|
||||
}
|
||||
if (alpha_size != (uint32_t)alpha_size) { // Soundness check.
|
||||
if (alpha_size != (uint32_t)alpha_size) { // Sanity check.
|
||||
WebPSafeFree(alpha_data);
|
||||
return 0;
|
||||
}
|
||||
enc->alpha_data_size_ = (uint32_t)alpha_size;
|
||||
enc->alpha_data_ = alpha_data;
|
||||
(void)unused;
|
||||
(void)dummy;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1171,15 +1171,13 @@ static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) {
|
||||
int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int quality, int low_effort,
|
||||
int histogram_bits, int cache_bits,
|
||||
int histo_bits, int cache_bits,
|
||||
VP8LHistogramSet* const image_histo,
|
||||
VP8LHistogram* const tmp_histo,
|
||||
uint16_t* const histogram_symbols) {
|
||||
int ok = 0;
|
||||
const int histo_xsize =
|
||||
histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1;
|
||||
const int histo_ysize =
|
||||
histogram_bits ? VP8LSubSampleSize(ysize, histogram_bits) : 1;
|
||||
const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1;
|
||||
const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1;
|
||||
const int image_histo_raw_size = histo_xsize * histo_ysize;
|
||||
VP8LHistogramSet* const orig_histo =
|
||||
VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits);
|
||||
@ -1195,7 +1193,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
||||
if (orig_histo == NULL || map_tmp == NULL) goto Error;
|
||||
|
||||
// Construct the histograms from backward references.
|
||||
HistogramBuild(xsize, histogram_bits, refs, orig_histo);
|
||||
HistogramBuild(xsize, histo_bits, refs, orig_histo);
|
||||
// Copies the histograms and computes its bit_cost.
|
||||
// histogram_symbols is optimized
|
||||
HistogramCopyAndAnalyze(orig_histo, image_histo, &num_used,
|
||||
|
@ -64,8 +64,8 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int palette_code_bits);
|
||||
|
||||
// Return the size of the histogram for a given cache_bits.
|
||||
int VP8LGetHistogramSize(int cache_bits);
|
||||
// Return the size of the histogram for a given palette_code_bits.
|
||||
int VP8LGetHistogramSize(int palette_code_bits);
|
||||
|
||||
// Set the palette_code_bits and reset the stats.
|
||||
// If init_arrays is true, the arrays are also filled with 0's.
|
||||
@ -110,7 +110,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int quality, int low_effort,
|
||||
int histogram_bits, int cache_bits,
|
||||
VP8LHistogramSet* const image_histo,
|
||||
VP8LHistogramSet* const image_in,
|
||||
VP8LHistogram* const tmp_histo,
|
||||
uint16_t* const histogram_symbols);
|
||||
|
||||
|
@ -164,25 +164,22 @@ int WebPPictureCrop(WebPPicture* pic,
|
||||
//------------------------------------------------------------------------------
|
||||
// Simple picture rescaler
|
||||
|
||||
static int RescalePlane(const uint8_t* src,
|
||||
int src_width, int src_height, int src_stride,
|
||||
uint8_t* dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
rescaler_t* const work,
|
||||
int num_channels) {
|
||||
static void RescalePlane(const uint8_t* src,
|
||||
int src_width, int src_height, int src_stride,
|
||||
uint8_t* dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
rescaler_t* const work,
|
||||
int num_channels) {
|
||||
WebPRescaler rescaler;
|
||||
int y = 0;
|
||||
if (!WebPRescalerInit(&rescaler, src_width, src_height,
|
||||
dst, dst_width, dst_height, dst_stride,
|
||||
num_channels, work)) {
|
||||
return 0;
|
||||
}
|
||||
WebPRescalerInit(&rescaler, src_width, src_height,
|
||||
dst, dst_width, dst_height, dst_stride,
|
||||
num_channels, work);
|
||||
while (y < src_height) {
|
||||
y += WebPRescalerImport(&rescaler, src_height - y,
|
||||
src + y * src_stride, src_stride);
|
||||
WebPRescalerExport(&rescaler);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
|
||||
@ -225,28 +222,25 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
|
||||
// If present, we need to rescale alpha first (for AlphaMultiplyY).
|
||||
if (pic->a != NULL) {
|
||||
WebPInitAlphaProcessing();
|
||||
if (!RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
|
||||
tmp.a, width, height, tmp.a_stride, work, 1)) {
|
||||
return 0;
|
||||
}
|
||||
RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
|
||||
tmp.a, width, height, tmp.a_stride, work, 1);
|
||||
}
|
||||
|
||||
// We take transparency into account on the luma plane only. That's not
|
||||
// totally exact blending, but still is a good approximation.
|
||||
AlphaMultiplyY(pic, 0);
|
||||
if (!RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
|
||||
tmp.y, width, height, tmp.y_stride, work, 1) ||
|
||||
!RescalePlane(pic->u,
|
||||
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
|
||||
tmp.u,
|
||||
HALVE(width), HALVE(height), tmp.uv_stride, work, 1) ||
|
||||
!RescalePlane(pic->v,
|
||||
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
|
||||
tmp.v,
|
||||
HALVE(width), HALVE(height), tmp.uv_stride, work, 1)) {
|
||||
return 0;
|
||||
}
|
||||
RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
|
||||
tmp.y, width, height, tmp.y_stride, work, 1);
|
||||
AlphaMultiplyY(&tmp, 1);
|
||||
|
||||
RescalePlane(pic->u,
|
||||
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
|
||||
tmp.u,
|
||||
HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
|
||||
RescalePlane(pic->v,
|
||||
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
|
||||
tmp.v,
|
||||
HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
|
||||
} else {
|
||||
work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
|
||||
if (work == NULL) {
|
||||
@ -258,12 +252,11 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
|
||||
// the premultiplication afterward (while preserving the alpha channel).
|
||||
WebPInitAlphaProcessing();
|
||||
AlphaMultiplyARGB(pic, 0);
|
||||
if (!RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
|
||||
pic->argb_stride * 4,
|
||||
(uint8_t*)tmp.argb, width, height,
|
||||
tmp.argb_stride * 4, work, 4)) {
|
||||
return 0;
|
||||
}
|
||||
RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
|
||||
pic->argb_stride * 4,
|
||||
(uint8_t*)tmp.argb, width, height,
|
||||
tmp.argb_stride * 4,
|
||||
work, 4);
|
||||
AlphaMultiplyARGB(&tmp, 1);
|
||||
}
|
||||
WebPPictureFree(pic);
|
||||
|
@ -349,7 +349,7 @@ int VP8EncWrite(VP8Encoder* const enc) {
|
||||
(enc->alpha_data_size_ & 1);
|
||||
riff_size += CHUNK_HEADER_SIZE + padded_alpha_size;
|
||||
}
|
||||
// RIFF size should fit in 32-bits.
|
||||
// Sanity check.
|
||||
if (riff_size > 0xfffffffeU) {
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ extern "C" {
|
||||
// version numbers
|
||||
#define ENC_MAJ_VERSION 1
|
||||
#define ENC_MIN_VERSION 2
|
||||
#define ENC_REV_VERSION 1
|
||||
#define ENC_REV_VERSION 0
|
||||
|
||||
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
|
||||
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
|
||||
@ -286,7 +286,8 @@ int VP8IteratorNext(VP8EncIterator* const it);
|
||||
// save the yuv_out_ boundary values to top_/left_ arrays for next iterations.
|
||||
void VP8IteratorSaveBoundary(VP8EncIterator* const it);
|
||||
// Report progression based on macroblock rows. Return 0 for user-abort request.
|
||||
int VP8IteratorProgress(const VP8EncIterator* const it, int delta);
|
||||
int VP8IteratorProgress(const VP8EncIterator* const it,
|
||||
int final_delta_percent);
|
||||
// Intra4x4 iterations
|
||||
void VP8IteratorStartI4(VP8EncIterator* const it);
|
||||
// returns true if not done.
|
||||
|
@ -65,22 +65,25 @@ static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
|
||||
*col2 = tmp;
|
||||
}
|
||||
|
||||
static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
|
||||
int num_colors) {
|
||||
int low = 0, hi = num_colors;
|
||||
if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
|
||||
while (1) {
|
||||
const int mid = (low + hi) >> 1;
|
||||
if (sorted[mid] == color) {
|
||||
return mid;
|
||||
} else if (sorted[mid] < color) {
|
||||
low = mid;
|
||||
} else {
|
||||
hi = mid;
|
||||
static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
|
||||
// Find greedily always the closest color of the predicted color to minimize
|
||||
// deltas in the palette. This reduces storage needs since the
|
||||
// palette is stored with delta encoding.
|
||||
uint32_t predict = 0x00000000;
|
||||
int i, k;
|
||||
for (i = 0; i < num_colors; ++i) {
|
||||
int best_ix = i;
|
||||
uint32_t best_score = ~0U;
|
||||
for (k = i; k < num_colors; ++k) {
|
||||
const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
|
||||
if (best_score > cur_score) {
|
||||
best_score = cur_score;
|
||||
best_ix = k;
|
||||
}
|
||||
}
|
||||
SwapColor(&palette[best_ix], &palette[i]);
|
||||
predict = palette[i];
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The palette has been sorted by alpha. This function checks if the other
|
||||
@ -89,8 +92,7 @@ static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
|
||||
// no benefit to re-organize them greedily. A monotonic development
|
||||
// would be spotted in green-only situations (like lossy alpha) or gray-scale
|
||||
// images.
|
||||
static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
|
||||
int num_colors) {
|
||||
static int PaletteHasNonMonotonousDeltas(uint32_t palette[], int num_colors) {
|
||||
uint32_t predict = 0x000000;
|
||||
int i;
|
||||
uint8_t sign_found = 0x00;
|
||||
@ -113,215 +115,28 @@ static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
|
||||
return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
|
||||
}
|
||||
|
||||
static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
|
||||
int num_colors, uint32_t* const palette) {
|
||||
uint32_t predict = 0x00000000;
|
||||
int i, k;
|
||||
memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
|
||||
if (!PaletteHasNonMonotonousDeltas(palette_sorted, num_colors)) return;
|
||||
// Find greedily always the closest color of the predicted color to minimize
|
||||
// deltas in the palette. This reduces storage needs since the
|
||||
// palette is stored with delta encoding.
|
||||
for (i = 0; i < num_colors; ++i) {
|
||||
int best_ix = i;
|
||||
uint32_t best_score = ~0U;
|
||||
for (k = i; k < num_colors; ++k) {
|
||||
const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
|
||||
if (best_score > cur_score) {
|
||||
best_score = cur_score;
|
||||
best_ix = k;
|
||||
}
|
||||
}
|
||||
SwapColor(&palette[best_ix], &palette[i]);
|
||||
predict = palette[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Sort palette in increasing order and prepare an inverse mapping array.
|
||||
static void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
|
||||
uint32_t sorted[], uint32_t idx_map[]) {
|
||||
uint32_t i;
|
||||
memcpy(sorted, palette, num_colors * sizeof(*sorted));
|
||||
qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
|
||||
for (i = 0; i < num_colors; ++i) {
|
||||
idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Modified Zeng method from "A Survey on Palette Reordering
|
||||
// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
|
||||
// Pinho and Antonio J. R. Neves.
|
||||
|
||||
// Finds the biggest cooccurrence in the matrix.
|
||||
static void CoOccurrenceFindMax(const uint32_t* const cooccurrence,
|
||||
uint32_t num_colors, uint8_t* const c1,
|
||||
uint8_t* const c2) {
|
||||
// Find the index that is most frequently located adjacent to other
|
||||
// (different) indexes.
|
||||
uint32_t best_sum = 0u;
|
||||
uint32_t i, j, best_cooccurrence;
|
||||
*c1 = 0u;
|
||||
for (i = 0; i < num_colors; ++i) {
|
||||
uint32_t sum = 0;
|
||||
for (j = 0; j < num_colors; ++j) sum += cooccurrence[i * num_colors + j];
|
||||
if (sum > best_sum) {
|
||||
best_sum = sum;
|
||||
*c1 = i;
|
||||
}
|
||||
}
|
||||
// Find the index that is most frequently found adjacent to *c1.
|
||||
*c2 = 0u;
|
||||
best_cooccurrence = 0u;
|
||||
for (i = 0; i < num_colors; ++i) {
|
||||
if (cooccurrence[*c1 * num_colors + i] > best_cooccurrence) {
|
||||
best_cooccurrence = cooccurrence[*c1 * num_colors + i];
|
||||
*c2 = i;
|
||||
}
|
||||
}
|
||||
assert(*c1 != *c2);
|
||||
}
|
||||
|
||||
// Builds the cooccurrence matrix
|
||||
static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic,
|
||||
const uint32_t* const palette,
|
||||
uint32_t num_colors,
|
||||
uint32_t* cooccurrence) {
|
||||
uint32_t *lines, *line_top, *line_current, *line_tmp;
|
||||
int x, y;
|
||||
const uint32_t* src = pic->argb;
|
||||
uint32_t prev_pix = ~src[0];
|
||||
uint32_t prev_idx = 0u;
|
||||
uint32_t idx_map[MAX_PALETTE_SIZE] = {0};
|
||||
uint32_t palette_sorted[MAX_PALETTE_SIZE];
|
||||
lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines));
|
||||
if (lines == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
line_top = &lines[0];
|
||||
line_current = &lines[pic->width];
|
||||
PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map);
|
||||
for (y = 0; y < pic->height; ++y) {
|
||||
for (x = 0; x < pic->width; ++x) {
|
||||
const uint32_t pix = src[x];
|
||||
if (pix != prev_pix) {
|
||||
prev_idx = idx_map[SearchColorNoIdx(palette_sorted, pix, num_colors)];
|
||||
prev_pix = pix;
|
||||
}
|
||||
line_current[x] = prev_idx;
|
||||
// 4-connectivity is what works best as mentioned in "On the relation
|
||||
// between Memon's and the modified Zeng's palette reordering methods".
|
||||
if (x > 0 && prev_idx != line_current[x - 1]) {
|
||||
const uint32_t left_idx = line_current[x - 1];
|
||||
++cooccurrence[prev_idx * num_colors + left_idx];
|
||||
++cooccurrence[left_idx * num_colors + prev_idx];
|
||||
}
|
||||
if (y > 0 && prev_idx != line_top[x]) {
|
||||
const uint32_t top_idx = line_top[x];
|
||||
++cooccurrence[prev_idx * num_colors + top_idx];
|
||||
++cooccurrence[top_idx * num_colors + prev_idx];
|
||||
}
|
||||
}
|
||||
line_tmp = line_top;
|
||||
line_top = line_current;
|
||||
line_current = line_tmp;
|
||||
src += pic->argb_stride;
|
||||
}
|
||||
WebPSafeFree(lines);
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
struct Sum {
|
||||
uint8_t index;
|
||||
uint32_t sum;
|
||||
};
|
||||
|
||||
// Implements the modified Zeng method from "A Survey on Palette Reordering
|
||||
// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
|
||||
// Pinho and Antonio J. R. Neves.
|
||||
static WebPEncodingError PaletteSortModifiedZeng(
|
||||
const WebPPicture* const pic, const uint32_t* const palette_sorted,
|
||||
uint32_t num_colors, uint32_t* const palette) {
|
||||
uint32_t i, j, ind;
|
||||
uint8_t remapping[MAX_PALETTE_SIZE];
|
||||
uint32_t* cooccurrence;
|
||||
struct Sum sums[MAX_PALETTE_SIZE];
|
||||
uint32_t first, last;
|
||||
uint32_t num_sums;
|
||||
// TODO(vrabaud) check whether one color images should use palette or not.
|
||||
if (num_colors <= 1) return VP8_ENC_OK;
|
||||
// Build the co-occurrence matrix.
|
||||
cooccurrence =
|
||||
(uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
|
||||
if (cooccurrence == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
if (CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence) !=
|
||||
VP8_ENC_OK) {
|
||||
WebPSafeFree(cooccurrence);
|
||||
return VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Initialize the mapping list with the two best indices.
|
||||
CoOccurrenceFindMax(cooccurrence, num_colors, &remapping[0], &remapping[1]);
|
||||
|
||||
// We need to append and prepend to the list of remapping. To this end, we
|
||||
// actually define the next start/end of the list as indices in a vector (with
|
||||
// a wrap around when the end is reached).
|
||||
first = 0;
|
||||
last = 1;
|
||||
num_sums = num_colors - 2; // -2 because we know the first two values
|
||||
if (num_sums > 0) {
|
||||
// Initialize the sums with the first two remappings and find the best one
|
||||
struct Sum* best_sum = &sums[0];
|
||||
best_sum->index = 0u;
|
||||
best_sum->sum = 0u;
|
||||
for (i = 0, j = 0; i < num_colors; ++i) {
|
||||
if (i == remapping[0] || i == remapping[1]) continue;
|
||||
sums[j].index = i;
|
||||
sums[j].sum = cooccurrence[i * num_colors + remapping[0]] +
|
||||
cooccurrence[i * num_colors + remapping[1]];
|
||||
if (sums[j].sum > best_sum->sum) best_sum = &sums[j];
|
||||
++j;
|
||||
}
|
||||
|
||||
while (num_sums > 0) {
|
||||
const uint8_t best_index = best_sum->index;
|
||||
// Compute delta to know if we need to prepend or append the best index.
|
||||
int32_t delta = 0;
|
||||
const int32_t n = num_colors - num_sums;
|
||||
for (ind = first, j = 0; (ind + j) % num_colors != last + 1; ++j) {
|
||||
const uint16_t l_j = remapping[(ind + j) % num_colors];
|
||||
delta += (n - 1 - 2 * (int32_t)j) *
|
||||
(int32_t)cooccurrence[best_index * num_colors + l_j];
|
||||
}
|
||||
if (delta > 0) {
|
||||
first = (first == 0) ? num_colors - 1 : first - 1;
|
||||
remapping[first] = best_index;
|
||||
} else {
|
||||
++last;
|
||||
remapping[last] = best_index;
|
||||
}
|
||||
// Remove best_sum from sums.
|
||||
*best_sum = sums[num_sums - 1];
|
||||
--num_sums;
|
||||
// Update all the sums and find the best one.
|
||||
best_sum = &sums[0];
|
||||
for (i = 0; i < num_sums; ++i) {
|
||||
sums[i].sum += cooccurrence[best_index * num_colors + sums[i].index];
|
||||
if (sums[i].sum > best_sum->sum) best_sum = &sums[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
assert((last + 1) % num_colors == first);
|
||||
WebPSafeFree(cooccurrence);
|
||||
|
||||
// Re-map the palette.
|
||||
for (i = 0; i < num_colors; ++i) {
|
||||
palette[i] = palette_sorted[remapping[(first + i) % num_colors]];
|
||||
}
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Palette
|
||||
|
||||
// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
|
||||
// creates a palette and returns true, else returns false.
|
||||
static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
|
||||
int low_effort,
|
||||
uint32_t palette[MAX_PALETTE_SIZE],
|
||||
int* const palette_size) {
|
||||
const int num_colors = WebPGetColorPalette(pic, palette);
|
||||
if (num_colors > MAX_PALETTE_SIZE) {
|
||||
*palette_size = 0;
|
||||
return 0;
|
||||
}
|
||||
*palette_size = num_colors;
|
||||
qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
|
||||
if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {
|
||||
GreedyMinimizeDeltas(palette, num_colors);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// These five modes are evaluated and their respective entropy is computed.
|
||||
typedef enum {
|
||||
kDirect = 0,
|
||||
@ -333,13 +148,6 @@ typedef enum {
|
||||
kNumEntropyIx = 6
|
||||
} EntropyIx;
|
||||
|
||||
typedef enum {
|
||||
kSortedDefault = 0,
|
||||
kMinimizeDelta = 1,
|
||||
kModifiedZeng = 2,
|
||||
kUnusedPalette = 3,
|
||||
} PaletteSorting;
|
||||
|
||||
typedef enum {
|
||||
kHistoAlpha = 0,
|
||||
kHistoAlphaPred,
|
||||
@ -554,14 +362,11 @@ typedef struct {
|
||||
} CrunchSubConfig;
|
||||
typedef struct {
|
||||
int entropy_idx_;
|
||||
PaletteSorting palette_sorting_type_;
|
||||
CrunchSubConfig sub_configs_[CRUNCH_SUBCONFIGS_MAX];
|
||||
int sub_configs_size_;
|
||||
} CrunchConfig;
|
||||
|
||||
// +2 because we add a palette sorting configuration for kPalette and
|
||||
// kPaletteAndSpatial.
|
||||
#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2)
|
||||
#define CRUNCH_CONFIGS_MAX kNumEntropyIx
|
||||
|
||||
static int EncoderAnalyze(VP8LEncoder* const enc,
|
||||
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],
|
||||
@ -581,15 +386,9 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
|
||||
int do_no_cache = 0;
|
||||
assert(pic != NULL && pic->argb != NULL);
|
||||
|
||||
// Check whether a palette is possible.
|
||||
enc->palette_size_ = WebPGetColorPalette(pic, enc->palette_sorted_);
|
||||
use_palette = (enc->palette_size_ <= MAX_PALETTE_SIZE);
|
||||
if (!use_palette) {
|
||||
enc->palette_size_ = 0;
|
||||
} else {
|
||||
qsort(enc->palette_sorted_, enc->palette_size_,
|
||||
sizeof(*enc->palette_sorted_), PaletteCompareColorsForQsort);
|
||||
}
|
||||
use_palette =
|
||||
AnalyzeAndCreatePalette(pic, low_effort,
|
||||
enc->palette_, &enc->palette_size_);
|
||||
|
||||
// Empirical bit sizes.
|
||||
enc->histo_bits_ = GetHistoBits(method, use_palette,
|
||||
@ -599,8 +398,6 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
|
||||
if (low_effort) {
|
||||
// AnalyzeEntropy is somewhat slow.
|
||||
crunch_configs[0].entropy_idx_ = use_palette ? kPalette : kSpatialSubGreen;
|
||||
crunch_configs[0].palette_sorting_type_ =
|
||||
use_palette ? kSortedDefault : kUnusedPalette;
|
||||
n_lz77s = 1;
|
||||
*crunch_configs_size = 1;
|
||||
} else {
|
||||
@ -621,28 +418,13 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
|
||||
// a palette.
|
||||
if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) {
|
||||
assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX);
|
||||
crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
|
||||
if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) {
|
||||
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
|
||||
kMinimizeDelta;
|
||||
++*crunch_configs_size;
|
||||
// Also add modified Zeng's method.
|
||||
crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
|
||||
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
|
||||
kModifiedZeng;
|
||||
} else {
|
||||
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
|
||||
kUnusedPalette;
|
||||
}
|
||||
++*crunch_configs_size;
|
||||
crunch_configs[(*crunch_configs_size)++].entropy_idx_ = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Only choose the guessed best transform.
|
||||
*crunch_configs_size = 1;
|
||||
crunch_configs[0].entropy_idx_ = min_entropy_ix;
|
||||
crunch_configs[0].palette_sorting_type_ =
|
||||
use_palette ? kMinimizeDelta : kUnusedPalette;
|
||||
if (config->quality >= 75 && method == 5) {
|
||||
// Test with and without color cache.
|
||||
do_no_cache = 1;
|
||||
@ -650,7 +432,6 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
|
||||
if (min_entropy_ix == kPalette) {
|
||||
*crunch_configs_size = 2;
|
||||
crunch_configs[1].entropy_idx_ = kPaletteAndSpatial;
|
||||
crunch_configs[1].palette_sorting_type_ = kMinimizeDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1502,6 +1283,22 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
|
||||
int hi) {
|
||||
int low = 0;
|
||||
if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
|
||||
while (1) {
|
||||
const int mid = (low + hi) >> 1;
|
||||
if (sorted[mid] == color) {
|
||||
return mid;
|
||||
} else if (sorted[mid] < color) {
|
||||
low = mid;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define APPLY_PALETTE_GREEDY_MAX 4
|
||||
|
||||
static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[],
|
||||
@ -1536,6 +1333,17 @@ static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) {
|
||||
(32 - PALETTE_INV_SIZE_BITS);
|
||||
}
|
||||
|
||||
// Sort palette in increasing order and prepare an inverse mapping array.
|
||||
static void PrepareMapToPalette(const uint32_t palette[], int num_colors,
|
||||
uint32_t sorted[], uint32_t idx_map[]) {
|
||||
int i;
|
||||
memcpy(sorted, palette, num_colors * sizeof(*sorted));
|
||||
qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
|
||||
for (i = 0; i < num_colors; ++i) {
|
||||
idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Use 1 pixel cache for ARGB pixels.
|
||||
#define APPLY_PALETTE_FOR(COLOR_INDEX) do { \
|
||||
uint32_t prev_pix = palette[0]; \
|
||||
@ -1763,8 +1571,7 @@ static int EncodeStreamHook(void* input, void* data2) {
|
||||
enc->use_predict_ = (entropy_idx == kSpatial) ||
|
||||
(entropy_idx == kSpatialSubGreen) ||
|
||||
(entropy_idx == kPaletteAndSpatial);
|
||||
// When using a palette, R/B==0, hence no need to test for cross-color.
|
||||
if (low_effort || enc->use_palette_) {
|
||||
if (low_effort) {
|
||||
enc->use_cross_color_ = 0;
|
||||
} else {
|
||||
enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_;
|
||||
@ -1796,19 +1603,6 @@ static int EncodeStreamHook(void* input, void* data2) {
|
||||
|
||||
// Encode palette
|
||||
if (enc->use_palette_) {
|
||||
if (crunch_configs[idx].palette_sorting_type_ == kSortedDefault) {
|
||||
// Nothing to do, we have already sorted the palette.
|
||||
memcpy(enc->palette_, enc->palette_sorted_,
|
||||
enc->palette_size_ * sizeof(*enc->palette_));
|
||||
} else if (crunch_configs[idx].palette_sorting_type_ == kMinimizeDelta) {
|
||||
PaletteSortMinimizeDeltas(enc->palette_sorted_, enc->palette_size_,
|
||||
enc->palette_);
|
||||
} else {
|
||||
assert(crunch_configs[idx].palette_sorting_type_ == kModifiedZeng);
|
||||
err = PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
|
||||
enc->palette_size_, enc->palette_);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
}
|
||||
err = EncodePalette(bw, low_effort, enc);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
err = MapImageFromPalette(enc, use_delta_palette);
|
||||
@ -1978,8 +1772,6 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
||||
enc_side->palette_size_ = enc_main->palette_size_;
|
||||
memcpy(enc_side->palette_, enc_main->palette_,
|
||||
sizeof(enc_main->palette_));
|
||||
memcpy(enc_side->palette_sorted_, enc_main->palette_sorted_,
|
||||
sizeof(enc_main->palette_sorted_));
|
||||
param->enc_ = enc_side;
|
||||
}
|
||||
// Create the workers.
|
||||
|
@ -69,8 +69,6 @@ typedef struct {
|
||||
int use_palette_;
|
||||
int palette_size_;
|
||||
uint32_t palette_[MAX_PALETTE_SIZE];
|
||||
// Sorted version of palette_ for cache purposes.
|
||||
uint32_t palette_sorted_[MAX_PALETTE_SIZE];
|
||||
|
||||
// Some 'scratch' (potentially large) objects.
|
||||
struct VP8LBackwardRefs refs_[4]; // Backward Refs array for temporaries.
|
||||
|
@ -6,8 +6,8 @@
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,2,1
|
||||
PRODUCTVERSION 1,0,2,1
|
||||
FILEVERSION 1,0,2,0
|
||||
PRODUCTVERSION 1,0,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -24,12 +24,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Google, Inc."
|
||||
VALUE "FileDescription", "libwebp DLL"
|
||||
VALUE "FileVersion", "1.2.1"
|
||||
VALUE "FileVersion", "1.2.0"
|
||||
VALUE "InternalName", "libwebp.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2021"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2019"
|
||||
VALUE "OriginalFilename", "libwebp.dll"
|
||||
VALUE "ProductName", "WebP Image Codec"
|
||||
VALUE "ProductVersion", "1.2.1"
|
||||
VALUE "ProductVersion", "1.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -6,8 +6,8 @@
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,2,1
|
||||
PRODUCTVERSION 1,0,2,1
|
||||
FILEVERSION 1,0,2,0
|
||||
PRODUCTVERSION 1,0,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -24,12 +24,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Google, Inc."
|
||||
VALUE "FileDescription", "libwebpdecoder DLL"
|
||||
VALUE "FileVersion", "1.2.1"
|
||||
VALUE "FileVersion", "1.2.0"
|
||||
VALUE "InternalName", "libwebpdecoder.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2021"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2019"
|
||||
VALUE "OriginalFilename", "libwebpdecoder.dll"
|
||||
VALUE "ProductName", "WebP Image Decoder"
|
||||
VALUE "ProductVersion", "1.2.1"
|
||||
VALUE "ProductVersion", "1.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -17,6 +17,6 @@ noinst_HEADERS =
|
||||
noinst_HEADERS += ../webp/format_constants.h
|
||||
|
||||
libwebpmux_la_LIBADD = ../libwebp.la
|
||||
libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:7:0 -lm
|
||||
libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:6:0 -lm
|
||||
libwebpmuxincludedir = $(includedir)/webp
|
||||
pkgconfig_DATA = libwebpmux.pc
|
||||
|
@ -248,6 +248,9 @@ WebPAnimEncoder* WebPAnimEncoderNewInternal(
|
||||
|
||||
enc = (WebPAnimEncoder*)WebPSafeCalloc(1, sizeof(*enc));
|
||||
if (enc == NULL) return NULL;
|
||||
// sanity inits, so we can call WebPAnimEncoderDelete():
|
||||
enc->encoded_frames_ = NULL;
|
||||
enc->mux_ = NULL;
|
||||
MarkNoError(enc);
|
||||
|
||||
// Dimensions and options.
|
||||
@ -418,7 +421,7 @@ static void MinimizeChangeRectangle(const WebPPicture* const src,
|
||||
const int max_allowed_diff_lossy = QualityToMaxDiff(quality);
|
||||
const int max_allowed_diff = is_lossless ? 0 : max_allowed_diff_lossy;
|
||||
|
||||
// Assumption/correctness checks.
|
||||
// Sanity checks.
|
||||
assert(src->width == dst->width && src->height == dst->height);
|
||||
assert(rect->x_offset_ + rect->width_ <= dst->width);
|
||||
assert(rect->y_offset_ + rect->height_ <= dst->height);
|
||||
@ -946,8 +949,7 @@ static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) {
|
||||
int new_duration;
|
||||
|
||||
assert(enc->count_ >= 1);
|
||||
assert(!prev_enc_frame->is_key_frame_ ||
|
||||
prev_enc_frame->sub_frame_.duration ==
|
||||
assert(prev_enc_frame->sub_frame_.duration ==
|
||||
prev_enc_frame->key_frame_.duration);
|
||||
assert(prev_enc_frame->sub_frame_.duration ==
|
||||
(prev_enc_frame->sub_frame_.duration & (MAX_DURATION - 1)));
|
||||
@ -964,7 +966,7 @@ static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) {
|
||||
0x10, 0x88, 0x88, 0x08
|
||||
};
|
||||
const WebPData lossless_1x1 = {
|
||||
lossless_1x1_bytes, sizeof(lossless_1x1_bytes)
|
||||
lossless_1x1_bytes, sizeof(lossless_1x1_bytes)
|
||||
};
|
||||
const uint8_t lossy_1x1_bytes[] = {
|
||||
0x52, 0x49, 0x46, 0x46, 0x40, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
|
||||
@ -1356,12 +1358,6 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
|
||||
if (!IncreasePreviousDuration(enc, (int)prev_frame_duration)) {
|
||||
return 0;
|
||||
}
|
||||
// IncreasePreviousDuration() may add a frame to avoid exceeding
|
||||
// MAX_DURATION which could cause CacheFrame() to over read encoded_frames_
|
||||
// before the next flush.
|
||||
if (enc->count_ == enc->size_ && !FlushFrames(enc)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
enc->first_timestamp_ = timestamp;
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,2,1
|
||||
PRODUCTVERSION 1,0,2,1
|
||||
FILEVERSION 1,0,2,0
|
||||
PRODUCTVERSION 1,0,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -24,12 +24,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Google, Inc."
|
||||
VALUE "FileDescription", "libwebpmux DLL"
|
||||
VALUE "FileVersion", "1.2.1"
|
||||
VALUE "FileVersion", "1.2.0"
|
||||
VALUE "InternalName", "libwebpmux.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2021"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2019"
|
||||
VALUE "OriginalFilename", "libwebpmux.dll"
|
||||
VALUE "ProductName", "WebP Image Muxer"
|
||||
VALUE "ProductVersion", "1.2.1"
|
||||
VALUE "ProductVersion", "1.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -235,6 +235,7 @@ WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream,
|
||||
WebPMuxImage wpi;
|
||||
WebPMuxError err;
|
||||
|
||||
// Sanity checks.
|
||||
if (mux == NULL || bitstream == NULL || bitstream->bytes == NULL ||
|
||||
bitstream->size > MAX_CHUNK_PAYLOAD) {
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
@ -266,6 +267,7 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info,
|
||||
WebPMuxImage wpi;
|
||||
WebPMuxError err;
|
||||
|
||||
// Sanity checks.
|
||||
if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
||||
|
||||
if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT;
|
||||
|
@ -29,7 +29,7 @@ extern "C" {
|
||||
|
||||
#define MUX_MAJ_VERSION 1
|
||||
#define MUX_MIN_VERSION 2
|
||||
#define MUX_REV_VERSION 1
|
||||
#define MUX_REV_VERSION 0
|
||||
|
||||
// Chunk object.
|
||||
typedef struct WebPChunk WebPChunk;
|
||||
|
@ -56,7 +56,7 @@ static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk,
|
||||
uint32_t chunk_size;
|
||||
WebPData chunk_data;
|
||||
|
||||
// Correctness checks.
|
||||
// Sanity checks.
|
||||
if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
|
||||
chunk_size = GetLE32(data + TAG_SIZE);
|
||||
if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA;
|
||||
@ -186,6 +186,7 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
|
||||
WebPChunk** chunk_list_ends[WEBP_CHUNK_NIL + 1] = { NULL };
|
||||
ChunkInit(&chunk);
|
||||
|
||||
// Sanity checks.
|
||||
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) {
|
||||
return NULL; // version mismatch
|
||||
}
|
||||
@ -480,6 +481,7 @@ WebPMuxError WebPMuxGetFrame(
|
||||
WebPMuxError err;
|
||||
WebPMuxImage* wpi;
|
||||
|
||||
// Sanity checks.
|
||||
if (mux == NULL || frame == NULL) {
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ void VP8LoadFinalBytes(VP8BitReader* const br);
|
||||
|
||||
// makes sure br->value_ has at least BITS bits worth of data
|
||||
static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE
|
||||
void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) {
|
||||
void VP8LoadNewBytes(VP8BitReader* const br) {
|
||||
assert(br != NULL && br->buf_ != NULL);
|
||||
// Read 'BITS' bits at a time if possible.
|
||||
if (br->buf_ < br->buf_max_) {
|
||||
@ -104,7 +104,7 @@ void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) {
|
||||
}
|
||||
|
||||
// Read a bit with proba 'prob'. Speed-critical function!
|
||||
static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br,
|
||||
static WEBP_INLINE int VP8GetBit(VP8BitReader* const br,
|
||||
int prob, const char label[]) {
|
||||
// Don't move this declaration! It makes a big speed difference to store
|
||||
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
|
||||
@ -137,8 +137,7 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br,
|
||||
|
||||
// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
|
||||
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
|
||||
int VP8GetSigned(VP8BitReader* WEBP_RESTRICT const br, int v,
|
||||
const char label[]) {
|
||||
int VP8GetSigned(VP8BitReader* const br, int v, const char label[]) {
|
||||
if (br->bits_ < 0) {
|
||||
VP8LoadNewBytes(br);
|
||||
}
|
||||
@ -156,7 +155,7 @@ int VP8GetSigned(VP8BitReader* WEBP_RESTRICT const br, int v,
|
||||
}
|
||||
}
|
||||
|
||||
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* WEBP_RESTRICT const br,
|
||||
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br,
|
||||
int prob, const char label[]) {
|
||||
// Don't move this declaration! It makes a big speed difference to store
|
||||
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
|
||||
|
@ -278,7 +278,7 @@ void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) {
|
||||
// If needed, make some room by flushing some bits out.
|
||||
if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
|
||||
const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
|
||||
if (!CheckSizeOverflow(extra_size) ||
|
||||
if (extra_size != (size_t)extra_size ||
|
||||
!VP8LBitWriterResize(bw, (size_t)extra_size)) {
|
||||
bw->cur_ = bw->buf_;
|
||||
bw->error_ = 1;
|
||||
@ -314,7 +314,7 @@ void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) {
|
||||
while (used >= VP8L_WRITER_BITS) {
|
||||
if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
|
||||
const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
|
||||
if (!CheckSizeOverflow(extra_size) ||
|
||||
if (extra_size != (size_t)extra_size ||
|
||||
!VP8LBitWriterResize(bw, (size_t)extra_size)) {
|
||||
bw->cur_ = bw->buf_;
|
||||
bw->error_ = 1;
|
||||
|
@ -20,22 +20,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// VP8LColorCache.
|
||||
|
||||
int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits) {
|
||||
int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) {
|
||||
const int hash_size = 1 << hash_bits;
|
||||
assert(color_cache != NULL);
|
||||
assert(cc != NULL);
|
||||
assert(hash_bits > 0);
|
||||
color_cache->colors_ = (uint32_t*)WebPSafeCalloc(
|
||||
(uint64_t)hash_size, sizeof(*color_cache->colors_));
|
||||
if (color_cache->colors_ == NULL) return 0;
|
||||
color_cache->hash_shift_ = 32 - hash_bits;
|
||||
color_cache->hash_bits_ = hash_bits;
|
||||
cc->colors_ = (uint32_t*)WebPSafeCalloc((uint64_t)hash_size,
|
||||
sizeof(*cc->colors_));
|
||||
if (cc->colors_ == NULL) return 0;
|
||||
cc->hash_shift_ = 32 - hash_bits;
|
||||
cc->hash_bits_ = hash_bits;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VP8LColorCacheClear(VP8LColorCache* const color_cache) {
|
||||
if (color_cache != NULL) {
|
||||
WebPSafeFree(color_cache->colors_);
|
||||
color_cache->colors_ = NULL;
|
||||
void VP8LColorCacheClear(VP8LColorCache* const cc) {
|
||||
if (cc != NULL) {
|
||||
WebPSafeFree(cc->colors_);
|
||||
cc->colors_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +404,8 @@ static void ConvertBitDepthsToSymbols(HuffmanTreeCode* const tree) {
|
||||
// Main entry point
|
||||
|
||||
void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
|
||||
uint8_t* const buf_rle, HuffmanTree* const huff_tree,
|
||||
uint8_t* const buf_rle,
|
||||
HuffmanTree* const huff_tree,
|
||||
HuffmanTreeCode* const huff_code) {
|
||||
const int num_symbols = huff_code->num_symbols;
|
||||
memset(buf_rle, 0, num_symbols * sizeof(*buf_rle));
|
||||
|
@ -51,7 +51,7 @@ int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree,
|
||||
// huffman code tree.
|
||||
void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
|
||||
uint8_t* const buf_rle, HuffmanTree* const huff_tree,
|
||||
HuffmanTreeCode* const huff_code);
|
||||
HuffmanTreeCode* const tree);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
if (num_open < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (root_table == NULL) continue;
|
||||
for (; count[len] > 0; --count[len]) {
|
||||
HuffmanCode code;
|
||||
if ((key & mask) != low) {
|
||||
table += table_size;
|
||||
if (root_table != NULL) table += table_size;
|
||||
table_bits = NextTableBitSize(count, len, root_bits);
|
||||
table_size = 1 << table_bits;
|
||||
total_size += table_size;
|
||||
low = key & mask;
|
||||
root_table[low].bits = (uint8_t)(table_bits + root_bits);
|
||||
root_table[low].value = (uint16_t)((table - root_table) - low);
|
||||
if (root_table != NULL) {
|
||||
root_table[low].bits = (uint8_t)(table_bits + root_bits);
|
||||
root_table[low].value = (uint16_t)((table - root_table) - low);
|
||||
}
|
||||
}
|
||||
if (root_table != NULL) {
|
||||
code.bits = (uint8_t)(len - root_bits);
|
||||
code.value = (uint16_t)sorted[symbol++];
|
||||
ReplicateValue(&table[key >> root_bits], step, table_size, code);
|
||||
}
|
||||
code.bits = (uint8_t)(len - root_bits);
|
||||
code.value = (uint16_t)sorted[symbol++];
|
||||
ReplicateValue(&table[key >> root_bits], step, table_size, code);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
@ -211,25 +214,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES)
|
||||
// Cut-off value for switching between heap and stack allocation.
|
||||
#define SORTED_SIZE_CUTOFF 512
|
||||
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
|
||||
const int code_lengths[], int code_lengths_size) {
|
||||
int total_size;
|
||||
const int total_size =
|
||||
BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL);
|
||||
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
|
||||
if (root_table == NULL) {
|
||||
total_size = BuildHuffmanTable(NULL, root_bits,
|
||||
code_lengths, code_lengths_size, NULL);
|
||||
} else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
||||
if (total_size == 0 || root_table == NULL) return total_size;
|
||||
|
||||
if (root_table->curr_segment->curr_table + total_size >=
|
||||
root_table->curr_segment->start + root_table->curr_segment->size) {
|
||||
// If 'root_table' does not have enough memory, allocate a new segment.
|
||||
// The available part of root_table->curr_segment is left unused because we
|
||||
// need a contiguous buffer.
|
||||
const int segment_size = root_table->curr_segment->size;
|
||||
struct HuffmanTablesSegment* next =
|
||||
(HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next));
|
||||
if (next == NULL) return 0;
|
||||
// Fill the new segment.
|
||||
// We need at least 'total_size' but if that value is small, it is better to
|
||||
// allocate a big chunk to prevent more allocations later. 'segment_size' is
|
||||
// therefore chosen (any other arbitrary value could be chosen).
|
||||
next->size = total_size > segment_size ? total_size : segment_size;
|
||||
next->start =
|
||||
(HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start));
|
||||
if (next->start == NULL) {
|
||||
WebPSafeFree(next);
|
||||
return 0;
|
||||
}
|
||||
next->curr_table = next->start;
|
||||
next->next = NULL;
|
||||
// Point to the new segment.
|
||||
root_table->curr_segment->next = next;
|
||||
root_table->curr_segment = next;
|
||||
}
|
||||
if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
||||
// use local stack-allocated array.
|
||||
uint16_t sorted[SORTED_SIZE_CUTOFF];
|
||||
total_size = BuildHuffmanTable(root_table, root_bits,
|
||||
code_lengths, code_lengths_size, sorted);
|
||||
} else { // rare case. Use heap allocation.
|
||||
BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
|
||||
code_lengths, code_lengths_size, sorted);
|
||||
} else { // rare case. Use heap allocation.
|
||||
uint16_t* const sorted =
|
||||
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
|
||||
if (sorted == NULL) return 0;
|
||||
total_size = BuildHuffmanTable(root_table, root_bits,
|
||||
code_lengths, code_lengths_size, sorted);
|
||||
BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
|
||||
code_lengths, code_lengths_size, sorted);
|
||||
WebPSafeFree(sorted);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
|
||||
// Have 'segment' point to the first segment for now, 'root'.
|
||||
HuffmanTablesSegment* const root = &huffman_tables->root;
|
||||
huffman_tables->curr_segment = root;
|
||||
// Allocate root.
|
||||
root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
|
||||
if (root->start == NULL) return 0;
|
||||
root->curr_table = root->start;
|
||||
root->next = NULL;
|
||||
root->size = size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) {
|
||||
HuffmanTablesSegment *current, *next;
|
||||
if (huffman_tables == NULL) return;
|
||||
// Free the root node.
|
||||
current = &huffman_tables->root;
|
||||
next = current->next;
|
||||
WebPSafeFree(current->start);
|
||||
current->start = NULL;
|
||||
current->next = NULL;
|
||||
current = next;
|
||||
// Free the following nodes.
|
||||
while (current != NULL) {
|
||||
next = current->next;
|
||||
WebPSafeFree(current->start);
|
||||
WebPSafeFree(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,29 @@ typedef struct {
|
||||
// or non-literal symbol otherwise
|
||||
} HuffmanCode32;
|
||||
|
||||
// Contiguous memory segment of HuffmanCodes.
|
||||
typedef struct HuffmanTablesSegment {
|
||||
HuffmanCode* start;
|
||||
// Pointer to where we are writing into the segment. Starts at 'start' and
|
||||
// cannot go beyond 'start' + 'size'.
|
||||
HuffmanCode* curr_table;
|
||||
// Pointer to the next segment in the chain.
|
||||
struct HuffmanTablesSegment* next;
|
||||
int size;
|
||||
} HuffmanTablesSegment;
|
||||
|
||||
// Chained memory segments of HuffmanCodes.
|
||||
typedef struct HuffmanTables {
|
||||
HuffmanTablesSegment root;
|
||||
// Currently processed segment. At first, this is 'root'.
|
||||
HuffmanTablesSegment* curr_segment;
|
||||
} HuffmanTables;
|
||||
|
||||
// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
|
||||
// memory allocation error, 1 otherwise.
|
||||
int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables);
|
||||
void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
|
||||
|
||||
#define HUFFMAN_PACKED_BITS 6
|
||||
#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
|
||||
|
||||
@ -78,9 +101,7 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
|
||||
// the huffman table.
|
||||
// Returns built table size or 0 in case of error (invalid tree or
|
||||
// memory error).
|
||||
// If root_table is NULL, it returns 0 if a lookup cannot be built, something
|
||||
// > 0 otherwise (but not the table size).
|
||||
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
|
||||
const int code_lengths[], int code_lengths_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -12,74 +12,66 @@
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/utils/rescaler_utils.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int WebPRescalerInit(WebPRescaler* const rescaler,
|
||||
int src_width, int src_height,
|
||||
uint8_t* const dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
int num_channels, rescaler_t* const work) {
|
||||
void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
|
||||
uint8_t* const dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
int num_channels, rescaler_t* const work) {
|
||||
const int x_add = src_width, x_sub = dst_width;
|
||||
const int y_add = src_height, y_sub = dst_height;
|
||||
const uint64_t total_size = 2ull * dst_width * num_channels * sizeof(*work);
|
||||
if (!CheckSizeOverflow(total_size)) return 0;
|
||||
|
||||
rescaler->x_expand = (src_width < dst_width);
|
||||
rescaler->y_expand = (src_height < dst_height);
|
||||
rescaler->src_width = src_width;
|
||||
rescaler->src_height = src_height;
|
||||
rescaler->dst_width = dst_width;
|
||||
rescaler->dst_height = dst_height;
|
||||
rescaler->src_y = 0;
|
||||
rescaler->dst_y = 0;
|
||||
rescaler->dst = dst;
|
||||
rescaler->dst_stride = dst_stride;
|
||||
rescaler->num_channels = num_channels;
|
||||
wrk->x_expand = (src_width < dst_width);
|
||||
wrk->y_expand = (src_height < dst_height);
|
||||
wrk->src_width = src_width;
|
||||
wrk->src_height = src_height;
|
||||
wrk->dst_width = dst_width;
|
||||
wrk->dst_height = dst_height;
|
||||
wrk->src_y = 0;
|
||||
wrk->dst_y = 0;
|
||||
wrk->dst = dst;
|
||||
wrk->dst_stride = dst_stride;
|
||||
wrk->num_channels = num_channels;
|
||||
|
||||
// for 'x_expand', we use bilinear interpolation
|
||||
rescaler->x_add = rescaler->x_expand ? (x_sub - 1) : x_add;
|
||||
rescaler->x_sub = rescaler->x_expand ? (x_add - 1) : x_sub;
|
||||
if (!rescaler->x_expand) { // fx_scale is not used otherwise
|
||||
rescaler->fx_scale = WEBP_RESCALER_FRAC(1, rescaler->x_sub);
|
||||
wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add;
|
||||
wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
|
||||
if (!wrk->x_expand) { // fx_scale is not used otherwise
|
||||
wrk->fx_scale = WEBP_RESCALER_FRAC(1, wrk->x_sub);
|
||||
}
|
||||
// vertical scaling parameters
|
||||
rescaler->y_add = rescaler->y_expand ? y_add - 1 : y_add;
|
||||
rescaler->y_sub = rescaler->y_expand ? y_sub - 1 : y_sub;
|
||||
rescaler->y_accum = rescaler->y_expand ? rescaler->y_sub : rescaler->y_add;
|
||||
if (!rescaler->y_expand) {
|
||||
wrk->y_add = wrk->y_expand ? y_add - 1 : y_add;
|
||||
wrk->y_sub = wrk->y_expand ? y_sub - 1 : y_sub;
|
||||
wrk->y_accum = wrk->y_expand ? wrk->y_sub : wrk->y_add;
|
||||
if (!wrk->y_expand) {
|
||||
// This is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast.
|
||||
// Its value is <= WEBP_RESCALER_ONE, because dst_height <= rescaler->y_add
|
||||
// and rescaler->x_add >= 1;
|
||||
const uint64_t num = (uint64_t)dst_height * WEBP_RESCALER_ONE;
|
||||
const uint64_t den = (uint64_t)rescaler->x_add * rescaler->y_add;
|
||||
const uint64_t ratio = num / den;
|
||||
// Its value is <= WEBP_RESCALER_ONE, because dst_height <= wrk->y_add, and
|
||||
// wrk->x_add >= 1;
|
||||
const uint64_t ratio =
|
||||
(uint64_t)dst_height * WEBP_RESCALER_ONE / (wrk->x_add * wrk->y_add);
|
||||
if (ratio != (uint32_t)ratio) {
|
||||
// When ratio == WEBP_RESCALER_ONE, we can't represent the ratio with the
|
||||
// current fixed-point precision. This happens when src_height ==
|
||||
// rescaler->y_add (which == src_height), and rescaler->x_add == 1.
|
||||
// wrk->y_add (which == src_height), and wrk->x_add == 1.
|
||||
// => We special-case fxy_scale = 0, in WebPRescalerExportRow().
|
||||
rescaler->fxy_scale = 0;
|
||||
wrk->fxy_scale = 0;
|
||||
} else {
|
||||
rescaler->fxy_scale = (uint32_t)ratio;
|
||||
wrk->fxy_scale = (uint32_t)ratio;
|
||||
}
|
||||
rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->y_sub);
|
||||
wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->y_sub);
|
||||
} else {
|
||||
rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->x_add);
|
||||
// rescaler->fxy_scale is unused here.
|
||||
wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->x_add);
|
||||
// wrk->fxy_scale is unused here.
|
||||
}
|
||||
rescaler->irow = work;
|
||||
rescaler->frow = work + num_channels * dst_width;
|
||||
memset(work, 0, (size_t)total_size);
|
||||
wrk->irow = work;
|
||||
wrk->frow = work + num_channels * dst_width;
|
||||
memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
|
||||
|
||||
WebPRescalerDspInit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPRescalerGetScaledDimensions(int src_width, int src_height,
|
||||
@ -90,7 +82,6 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
|
||||
{
|
||||
int width = *scaled_width;
|
||||
int height = *scaled_height;
|
||||
const int max_size = INT_MAX / 2;
|
||||
|
||||
// if width is unspecified, scale original proportionally to height ratio.
|
||||
if (width == 0 && src_height > 0) {
|
||||
@ -103,7 +94,7 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
|
||||
(int)(((uint64_t)src_height * width + src_width - 1) / src_width);
|
||||
}
|
||||
// Check if the overall dimensions still make sense.
|
||||
if (width <= 0 || height <= 0 || width > max_size || height > max_size) {
|
||||
if (width <= 0 || height <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -116,34 +107,31 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
|
||||
//------------------------------------------------------------------------------
|
||||
// all-in-one calls
|
||||
|
||||
int WebPRescaleNeededLines(const WebPRescaler* const rescaler,
|
||||
int max_num_lines) {
|
||||
const int num_lines =
|
||||
(rescaler->y_accum + rescaler->y_sub - 1) / rescaler->y_sub;
|
||||
int WebPRescaleNeededLines(const WebPRescaler* const wrk, int max_num_lines) {
|
||||
const int num_lines = (wrk->y_accum + wrk->y_sub - 1) / wrk->y_sub;
|
||||
return (num_lines > max_num_lines) ? max_num_lines : num_lines;
|
||||
}
|
||||
|
||||
int WebPRescalerImport(WebPRescaler* const rescaler, int num_lines,
|
||||
int WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
|
||||
const uint8_t* src, int src_stride) {
|
||||
int total_imported = 0;
|
||||
while (total_imported < num_lines &&
|
||||
!WebPRescalerHasPendingOutput(rescaler)) {
|
||||
if (rescaler->y_expand) {
|
||||
rescaler_t* const tmp = rescaler->irow;
|
||||
rescaler->irow = rescaler->frow;
|
||||
rescaler->frow = tmp;
|
||||
while (total_imported < num_lines && !WebPRescalerHasPendingOutput(wrk)) {
|
||||
if (wrk->y_expand) {
|
||||
rescaler_t* const tmp = wrk->irow;
|
||||
wrk->irow = wrk->frow;
|
||||
wrk->frow = tmp;
|
||||
}
|
||||
WebPRescalerImportRow(rescaler, src);
|
||||
if (!rescaler->y_expand) { // Accumulate the contribution of the new row.
|
||||
WebPRescalerImportRow(wrk, src);
|
||||
if (!wrk->y_expand) { // Accumulate the contribution of the new row.
|
||||
int x;
|
||||
for (x = 0; x < rescaler->num_channels * rescaler->dst_width; ++x) {
|
||||
rescaler->irow[x] += rescaler->frow[x];
|
||||
for (x = 0; x < wrk->num_channels * wrk->dst_width; ++x) {
|
||||
wrk->irow[x] += wrk->frow[x];
|
||||
}
|
||||
}
|
||||
++rescaler->src_y;
|
||||
++wrk->src_y;
|
||||
src += src_stride;
|
||||
++total_imported;
|
||||
rescaler->y_accum -= rescaler->y_sub;
|
||||
wrk->y_accum -= wrk->y_sub;
|
||||
}
|
||||
return total_imported;
|
||||
}
|
||||
|
@ -47,13 +47,12 @@ struct WebPRescaler {
|
||||
};
|
||||
|
||||
// Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
|
||||
// Returns false in case of error.
|
||||
int WebPRescalerInit(WebPRescaler* const rescaler,
|
||||
int src_width, int src_height,
|
||||
uint8_t* const dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
int num_channels,
|
||||
rescaler_t* const work);
|
||||
void WebPRescalerInit(WebPRescaler* const rescaler,
|
||||
int src_width, int src_height,
|
||||
uint8_t* const dst,
|
||||
int dst_width, int dst_height, int dst_stride,
|
||||
int num_channels,
|
||||
rescaler_t* const work);
|
||||
|
||||
// If either 'scaled_width' or 'scaled_height' (but not both) is 0 the value
|
||||
// will be calculated preserving the aspect ratio, otherwise the values are
|
||||
|
@ -101,9 +101,6 @@ static void Increment(int* const v) {
|
||||
#if defined(MALLOC_LIMIT)
|
||||
{
|
||||
const char* const malloc_limit_str = getenv("MALLOC_LIMIT");
|
||||
#if MALLOC_LIMIT > 1
|
||||
mem_limit = (size_t)MALLOC_LIMIT;
|
||||
#endif
|
||||
if (malloc_limit_str != NULL) {
|
||||
mem_limit = atoi(malloc_limit_str);
|
||||
}
|
||||
@ -172,16 +169,16 @@ static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
|
||||
const uint64_t total_size = nmemb * size;
|
||||
if (nmemb == 0) return 1;
|
||||
if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0;
|
||||
if (!CheckSizeOverflow(total_size)) return 0;
|
||||
if (total_size != (size_t)total_size) return 0;
|
||||
#if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT)
|
||||
if (countdown_to_fail > 0 && --countdown_to_fail == 0) {
|
||||
return 0; // fake fail!
|
||||
}
|
||||
#endif
|
||||
#if defined(PRINT_MEM_INFO) && defined(MALLOC_LIMIT)
|
||||
#if defined(MALLOC_LIMIT)
|
||||
if (mem_limit > 0) {
|
||||
const uint64_t new_total_mem = (uint64_t)total_mem + total_size;
|
||||
if (!CheckSizeOverflow(new_total_mem) ||
|
||||
if (new_total_mem != (size_t)new_total_mem ||
|
||||
new_total_mem > mem_limit) {
|
||||
return 0; // fake fail!
|
||||
}
|
||||
|
@ -42,10 +42,6 @@ extern "C" {
|
||||
#endif
|
||||
#endif // WEBP_MAX_ALLOCABLE_MEMORY
|
||||
|
||||
static WEBP_INLINE int CheckSizeOverflow(uint64_t size) {
|
||||
return size == (size_t)size;
|
||||
}
|
||||
|
||||
// size-checking safe malloc/calloc: verify that the requested size is not too
|
||||
// large, or return NULL. You don't need to call these for constructs like
|
||||
// malloc(sizeof(foo)), but only if there's picture-dependent size involved
|
||||
@ -111,33 +107,24 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
|
||||
PutLE16(data + 2, (int)(val >> 16));
|
||||
}
|
||||
|
||||
// Returns (int)floor(log2(n)). n must be > 0.
|
||||
// use GNU builtins where available.
|
||||
#if defined(__GNUC__) && \
|
||||
((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
|
||||
// Returns (int)floor(log2(n)). n must be > 0.
|
||||
static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
|
||||
return 31 ^ __builtin_clz(n);
|
||||
}
|
||||
// counts the number of trailing zero
|
||||
static WEBP_INLINE int BitsCtz(uint32_t n) { return __builtin_ctz(n); }
|
||||
#elif defined(_MSC_VER) && _MSC_VER > 1310 && \
|
||||
(defined(_M_X64) || defined(_M_IX86))
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanReverse)
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
|
||||
static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
|
||||
unsigned long first_set_bit; // NOLINT (runtime/int)
|
||||
unsigned long first_set_bit;
|
||||
_BitScanReverse(&first_set_bit, n);
|
||||
return first_set_bit;
|
||||
}
|
||||
static WEBP_INLINE int BitsCtz(uint32_t n) {
|
||||
unsigned long first_set_bit; // NOLINT (runtime/int)
|
||||
_BitScanForward(&first_set_bit, n);
|
||||
return first_set_bit;
|
||||
}
|
||||
#else // default: use the (slow) C-version.
|
||||
#define WEBP_HAVE_SLOW_CLZ_CTZ // signal that the Clz/Ctz function are slow
|
||||
#else // default: use the C-version.
|
||||
// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either
|
||||
// based on table or not. Can be used as fallback if clz() is not available.
|
||||
#define WEBP_NEED_LOG_TABLE_8BIT
|
||||
@ -152,15 +139,6 @@ static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
|
||||
}
|
||||
|
||||
static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); }
|
||||
|
||||
static WEBP_INLINE int BitsCtz(uint32_t n) {
|
||||
int i;
|
||||
for (i = 0; i < 32; ++i, n >>= 1) {
|
||||
if (n & 1) return i;
|
||||
}
|
||||
return 32;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -2764,7 +2764,7 @@ SWIG_Python_DestroyModule(void *vptr)
|
||||
SWIGRUNTIME void
|
||||
SWIG_Python_SetModule(swig_module_info *swig_module) {
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
/* Add a placeholder module object into sys.modules */
|
||||
/* Add a dummy module object into sys.modules */
|
||||
PyObject *module = PyImport_AddModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION);
|
||||
#else
|
||||
static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} }; /* Sentinel */
|
||||
|
@ -14,13 +14,10 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "./fuzz_utils.h"
|
||||
#include "src/webp/decode.h"
|
||||
#include "webp/decode.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
||||
int i;
|
||||
WebPDecoderConfig config;
|
||||
if (!WebPInitDecoderConfig(&config)) return 0;
|
||||
if (WebPGetFeatures(data, size, &config.input) != VP8_STATUS_OK) return 0;
|
||||
@ -62,53 +59,39 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
||||
config.output.colorspace = (WEBP_CSP_MODE)(value % MODE_LAST);
|
||||
#endif // WEBP_REDUCE_CSP
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (i == 1) {
|
||||
// Use the bitstream data to generate extreme ranges for the options. An
|
||||
// alternative approach would be to use a custom corpus containing webp
|
||||
// files prepended with sizeof(config.options) zeroes to allow the fuzzer
|
||||
// to modify these independently.
|
||||
const int data_offset = 50;
|
||||
if (size > data_offset + sizeof(config.options)) {
|
||||
memcpy(&config.options, data + data_offset, sizeof(config.options));
|
||||
} else {
|
||||
break;
|
||||
if (size % 3) {
|
||||
// Decodes incrementally in chunks of increasing size.
|
||||
WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
|
||||
if (!idec) return 0;
|
||||
VP8StatusCode status;
|
||||
if (size & 8) {
|
||||
size_t available_size = value + 1;
|
||||
while (1) {
|
||||
if (available_size > size) available_size = size;
|
||||
status = WebPIUpdate(idec, data, available_size);
|
||||
if (status != VP8_STATUS_SUSPENDED || available_size == size) break;
|
||||
available_size *= 2;
|
||||
}
|
||||
}
|
||||
if (size % 3) {
|
||||
// Decodes incrementally in chunks of increasing size.
|
||||
WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
|
||||
if (!idec) return 0;
|
||||
VP8StatusCode status;
|
||||
if (size & 8) {
|
||||
size_t available_size = value + 1;
|
||||
while (1) {
|
||||
if (available_size > size) available_size = size;
|
||||
status = WebPIUpdate(idec, data, available_size);
|
||||
if (status != VP8_STATUS_SUSPENDED || available_size == size) break;
|
||||
available_size *= 2;
|
||||
}
|
||||
} else {
|
||||
// WebPIAppend expects new data and its size with each call.
|
||||
// Implemented here by simply advancing the pointer into data.
|
||||
const uint8_t* new_data = data;
|
||||
size_t new_size = value + 1;
|
||||
while (1) {
|
||||
if (new_data + new_size > data + size) {
|
||||
new_size = data + size - new_data;
|
||||
}
|
||||
status = WebPIAppend(idec, new_data, new_size);
|
||||
if (status != VP8_STATUS_SUSPENDED || new_size == 0) break;
|
||||
new_data += new_size;
|
||||
new_size *= 2;
|
||||
}
|
||||
}
|
||||
WebPIDelete(idec);
|
||||
} else {
|
||||
WebPDecode(data, size, &config);
|
||||
// WebPIAppend expects new data and its size with each call.
|
||||
// Implemented here by simply advancing the pointer into data.
|
||||
const uint8_t* new_data = data;
|
||||
size_t new_size = value + 1;
|
||||
while (1) {
|
||||
if (new_data + new_size > data + size) {
|
||||
new_size = data + size - new_data;
|
||||
}
|
||||
status = WebPIAppend(idec, new_data, new_size);
|
||||
if (status != VP8_STATUS_SUSPENDED || new_size == 0) break;
|
||||
new_data += new_size;
|
||||
new_size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
WebPFreeDecBuffer(&config.output);
|
||||
WebPIDelete(idec);
|
||||
} else {
|
||||
WebPDecode(data, size, &config);
|
||||
}
|
||||
|
||||
WebPFreeDecBuffer(&config.output);
|
||||
return 0;
|
||||
}
|
||||
|
@ -15,9 +15,9 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "./fuzz_utils.h"
|
||||
#include "src/webp/decode.h"
|
||||
#include "src/webp/demux.h"
|
||||
#include "src/webp/mux_types.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/demux.h"
|
||||
#include "webp/mux_types.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
||||
WebPData webp_data;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
#include "examples/anim_util.h"
|
||||
#include "imageio/imageio_util.h"
|
||||
#include "src/webp/demux.h"
|
||||
#include "webp/demux.h"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
// WebPAnimDecoderGetInfo() is too late to check the canvas size as
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./fuzz_utils.h"
|
||||
#include "src/webp/encode.h"
|
||||
#include "src/webp/mux.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/mux.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./fuzz_utils.h"
|
||||
#include "src/webp/decode.h"
|
||||
#include "src/webp/encode.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/encode.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -23,8 +23,8 @@
|
||||
#include "./img_alpha.h"
|
||||
#include "./img_grid.h"
|
||||
#include "./img_peak.h"
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/webp/encode.h"
|
||||
#include "dsp/dsp.h"
|
||||
#include "webp/encode.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Arbitrary limits to prevent OOM, timeout, or slow execution.
|
||||
|
@ -15,8 +15,8 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "./fuzz_utils.h"
|
||||
#include "src/webp/demux.h"
|
||||
#include "src/webp/mux.h"
|
||||
#include "webp/demux.h"
|
||||
#include "webp/mux.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
||||
WebPData webp_data;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user