Update bundled libwebp to version 1.0.3

[ChangeLog][Third-Party Code] Update bundled libwebp to version 1.0.3

Change-Id: I7aef89e209923af0e516024c26ebce4a8158d4d1
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Reviewed-by: Liang Qi <liang.qi@qt.io>
This commit is contained in:
André Klitzing 2019-07-19 11:48:50 +02:00
parent 7bdf0823b6
commit d4861c2a83
46 changed files with 534 additions and 348 deletions

View File

@ -1,4 +1,5 @@
Contributors: Contributors:
- Aidan O'Loan (aidanol at gmail dot com)
- Alan Browning (browning at google dot com) - Alan Browning (browning at google dot com)
- Charles Munger (clm at google dot com) - Charles Munger (clm at google dot com)
- Christian Duvivier (cduvivier at google dot com) - Christian Duvivier (cduvivier at google dot com)

View File

@ -1,3 +1,54 @@
2ad0916d update NEWS
1287362b bump version to 1.0.3
7b968cc2 update AUTHORS
9d6988f4 Fix the oscillating prediction problem at low quality
312f74d0 makefile.unix: allow *_LIBS to be overridden w/EXTRA_LIBS
92dbf237 filters_sse2,cosmetics: shorten some long lines
a277d197 filters_sse2.c: quiet integer sanitizer warnings
804540f1 Fix cpufeatures in CMake.
bf00c15b Add CMake option for bittrace.
a788b498 filters_sse2.c: quiet integer sanitizer warnings
e6a92c5e filters.c: quiet integer sanitizer warnings
ec1cc40a lossless.c: remove U32 -> S8 conversion warnings
1106478f remove conversion U32 -> S8 warnings
812a6b49 lossless_enc: fix some conversion warning
4627c1c9 lossless_enc,TransformColorBlue: quiet uint32_t conv warning
c84673a6 lossless_enc_sse{2,41}: quiet signed conv warnings
776a7757 dec_sse2: quiet signed conv warnings
bd39c063 Merge "thread_utils: release mutex before signaling"
0550576f Merge "(alpha_processing,enc}_sse2: quiet signed conv warnings"
6682f2c4 thread_utils: release mutex before signaling
e78dea75 (alpha_processing,enc}_sse2: quiet signed conv warnings
9acf18ba iosbuild.sh: add WebP{Demux,Mux}.framework
b9be7e65 vwebp: remove the -fit option (and make it default)
1394a2bb Merge "README.webp_js: update Emscripten.cmake note"
dd3e7f8a README.webp_js: update Emscripten.cmake note
32cf8801 predictor_enc,GetBestGreenRedToBlue: quiet implicit conv warnings
e1c8acb5 Merge "vwebp: add a -fit option"
cbd23dd5 vwebp: add a -fit option
2e672351 bit_writer_utils,Flush: quiet implicit conversion warnings
1326988d swig: update libwebp_python_wrap.c
0e7f8548 update generated swig files
17ed1438 Merge "PutLE{16,24}: quiet implicit conversion warnings"
24686538 PutLE{16,24}: quiet implicit conversion warnings
153bb3a0 fix some clang-7 warnings:
ab2dc893 Rescaler: fix rounding error
aa65f89a HistogramCombineStochastic: fix free of uninit value
af0bac64 Merge "encode.h: mention 'exact' default in WebPEncodeLossless*"
6d2e11ec encode.h: mention 'exact' default in WebPEncodeLossless*
8c3f04fe AndroidCPUInfo: reorder terms in conditional
fcfd9c71 BitTrace: if BITTRACE is > 0, record and print syntax bits used
067031ea Speedups for unused Huffman groups.
01ac46ba libwebp: Display "libjpeg error:" in imageio/jpegdec
d9a662e1 WebPRescalerGetScaledDimensions: round scaled dimension up
62eb3f08 libwebp: Fix missing '{' in README
e05f785a Merge "unicode,INIT_WARGV: add missing cast"
63c9a69f tag the VP8LHashPix() function for potential uint roll-over
2b7214ab unicode,INIT_WARGV: add missing cast
bf424b46 tag the GetPixPairHash64() function for potential uint roll-over
7d05d6ca Have the color cache computation be u32-bit only.
6bcf8769 Remove BINARYEN_METHOD in wasm settings.
2b98df90 update ChangeLog (tag: v1.0.2-rc1, tag: v1.0.2)
61e372b7 update NEWS 61e372b7 update NEWS
7ae658a0 bump version to 1.0.2 7ae658a0 bump version to 1.0.2
51c4907d update AUTHORS 51c4907d update AUTHORS
@ -16,7 +67,7 @@ f435de95 IsFlat: return int
9f4d4a3f neon: GetResidualCost 9f4d4a3f neon: GetResidualCost
0fd7514b neon: SetResidualCoeffs 0fd7514b neon: SetResidualCoeffs
f95a996c Simpler histogram clustering. f95a996c Simpler histogram clustering.
e85d3313 update ChangeLog (tag: v1.0.1-rc2, tag: v1.0.1, origin/1.0.1, 1.0.1) e85d3313 update ChangeLog (tag: v1.0.1-rc2, tag: v1.0.1)
fa8210e4 Fix pair update in stochastic entropy merging. fa8210e4 Fix pair update in stochastic entropy merging.
fd198f73 add codereview.settings fd198f73 add codereview.settings
825389ac README.mux: add a reference to the AnimDecoder API 825389ac README.mux: add a reference to the AnimDecoder API
@ -485,7 +536,7 @@ dcf9d82a imageio: add limited PNM support for reading
6524fcd6 vwebp_sdl: simple viewer based on SDL 6524fcd6 vwebp_sdl: simple viewer based on SDL
6cf24a24 get_disto: fix reference file read 6cf24a24 get_disto: fix reference file read
43d472aa Merge tag 'v0.6.0' 43d472aa Merge tag 'v0.6.0'
50d1a848 update ChangeLog (tag: v0.6.0, origin/0.6.0, 0.6.0) 50d1a848 update ChangeLog (tag: v0.6.0, origin/0.6.0)
20a7fea0 extras/Makefile.am: fix libwebpextras.la reference 20a7fea0 extras/Makefile.am: fix libwebpextras.la reference
415f3ffe update ChangeLog (tag: v0.6.0-rc3) 415f3ffe update ChangeLog (tag: v0.6.0-rc3)
3c6d1224 update NEWS 3c6d1224 update NEWS
@ -562,7 +613,7 @@ b016cb91 NEON: faster fancy upsampling
f04eb376 Merge tag 'v0.5.2' f04eb376 Merge tag 'v0.5.2'
341d711c NEON: 5% faster conversion to RGB565 and RGBA4444 341d711c NEON: 5% faster conversion to RGB565 and RGBA4444
abb54827 remove Clang warnings with unused arch arguments. abb54827 remove Clang warnings with unused arch arguments.
ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2, origin/0.5.2, 0.5.2) ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2, origin/0.5.2)
aa7744ca anim_util: quiet implicit conv warnings in 32-bit aa7744ca anim_util: quiet implicit conv warnings in 32-bit
d9120271 jpegdec: correct ContextFill signature d9120271 jpegdec: correct ContextFill signature
24eb3940 Remove some errors when compiling the code as C++. 24eb3940 Remove some errors when compiling the code as C++.
@ -849,7 +900,7 @@ bbb6ecd9 Merge "Add MSA optimized distortion functions"
c0991a14 io,EmitRescaledAlphaYUV: factor out a common expr c0991a14 io,EmitRescaledAlphaYUV: factor out a common expr
48bf5ed1 build.gradle: remove tab 48bf5ed1 build.gradle: remove tab
bfef6c9f Merge tag 'v0.5.1' bfef6c9f Merge tag 'v0.5.1'
3d97bb75 update ChangeLog (tag: v0.5.1, origin/0.5.1, 0.5.1) 3d97bb75 update ChangeLog (tag: v0.5.1, origin/0.5.1)
deb54d91 Clarify the expected 'config' lifespan in WebPIDecode() deb54d91 Clarify the expected 'config' lifespan in WebPIDecode()
435308e0 Add MSA optimized encoder transform functions 435308e0 Add MSA optimized encoder transform functions
dce64bfa Add MSA optimized alpha filter functions dce64bfa Add MSA optimized alpha filter functions
@ -1043,7 +1094,7 @@ b74657fb configure: fix builtin detection w/-Werror
6c1d7631 avoid Yoda style for comparison 6c1d7631 avoid Yoda style for comparison
8ce975ac SSE optimization for vector mismatch. 8ce975ac SSE optimization for vector mismatch.
7db53831 Merge tag 'v0.5.0' 7db53831 Merge tag 'v0.5.0'
37f04949 update ChangeLog (tag: v0.5.0-rc1, tag: v0.5.0, origin/0.5.0, 0.5.0) 37f04949 update ChangeLog (tag: v0.5.0-rc1, tag: v0.5.0, origin/0.5.0)
7e7b6ccc faster rgb565/rgb4444/argb output 7e7b6ccc faster rgb565/rgb4444/argb output
4c7f565f update NEWS 4c7f565f update NEWS
1f62b6b2 update AUTHORS 1f62b6b2 update AUTHORS
@ -1827,7 +1878,7 @@ b5a36cc9 add -near_lossless [0..100] experimental option
0524d9e5 dsp: detect mips64 & disable mips32 code 0524d9e5 dsp: detect mips64 & disable mips32 code
d3485d96 cwebp.1: fix quality description placement d3485d96 cwebp.1: fix quality description placement
29a9fe22 Merge tag 'v0.4.1' 29a9fe22 Merge tag 'v0.4.1'
8af27718 update ChangeLog (tag: v0.4.1, origin/0.4.1, 0.4.1) 8af27718 update ChangeLog (tag: v0.4.1, origin/0.4.1)
e09e9ff6 Record & log the image pre-processing time. e09e9ff6 Record & log the image pre-processing time.
f59c0b4b iosbuild.sh: specify optimization flags f59c0b4b iosbuild.sh: specify optimization flags
8d34ea3e update ChangeLog (tag: v0.4.1-rc1) 8d34ea3e update ChangeLog (tag: v0.4.1-rc1)
@ -2212,7 +2263,7 @@ ea59a8e9 Merge "Merge tag 'v0.4.0'"
effcb0fd Merge tag 'v0.4.0' effcb0fd Merge tag 'v0.4.0'
7c76255d autoconf: update ax_pthread.m4 7c76255d autoconf: update ax_pthread.m4
fff2a11b make -short work with -print_ssim, -print_psnr, etc. fff2a11b make -short work with -print_ssim, -print_psnr, etc.
68e7901d update ChangeLog (tag: v0.4.0-rc1, tag: v0.4.0, origin/0.4.0, 0.4.0) 68e7901d update ChangeLog (tag: v0.4.0-rc1, tag: v0.4.0, origin/0.4.0)
256e4333 update NEWS description with new general features 256e4333 update NEWS description with new general features
29625340 Merge "gif2webp: don't use C99 %zu" into 0.4.0 29625340 Merge "gif2webp: don't use C99 %zu" into 0.4.0
3b9f9dd0 gif2webp: don't use C99 %zu 3b9f9dd0 gif2webp: don't use C99 %zu
@ -2988,7 +3039,7 @@ a61a824b Merge "Add NULL check in chunk APIs"
a0770727 mux struct naming a0770727 mux struct naming
6c66dde8 Merge "Tune Lossless encoder" 6c66dde8 Merge "Tune Lossless encoder"
ab5ea217 Tune Lossless encoder ab5ea217 Tune Lossless encoder
74fefc8c Update ChangeLog (tag: v0.2.1, origin/0.2.0, 0.2.0) 74fefc8c Update ChangeLog (tag: v0.2.1, origin/0.2.0)
92f8059c Rename some chunks: 92f8059c Rename some chunks:
3bb4bbeb Merge "Mux API change:" 3bb4bbeb Merge "Mux API change:"
d0c79f05 Mux API change: d0c79f05 Mux API change:

View File

@ -1,3 +1,15 @@
- 7/4/2019: version 1.0.3
This is a binary compatible release.
* resize fixes for Nx1 sizes and the addition of non-opaque alpha values for
odd sizes (issues #418, #434)
* lossless encode/decode performance improvements
* lossy compression performance improvement at low quality levels with flat
content (issue #432)
* python swig files updated to support python 3
Tool updates:
vwebp will now preserve the aspect ratio of images that exceed monitor
resolution by scaling the image to fit (issue #433)
- 1/14/2019: version 1.0.2 - 1/14/2019: version 1.0.2
This is a binary compatible release. This is a binary compatible release.
* (Windows) unicode file support in the tools (linux and mac already had * (Windows) unicode file support in the tools (linux and mac already had

View File

@ -4,7 +4,7 @@
\__\__/\____/\_____/__/ ____ ___ \__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/ / _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__ / \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v1.0.2 \____/____/\_____/_____/____/v1.0.3
Description: Description:
============ ============
@ -597,7 +597,7 @@ The encoding flow looks like:
// Setup a config, starting form a preset and tuning some additional // Setup a config, starting form a preset and tuning some additional
// parameters // parameters
WebPConfig config; WebPConfig config;
if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor)) if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor)) {
return 0; // version error return 0; // version error
} }
// ... additional tuning // ... additional tuning

View File

@ -6,7 +6,7 @@
"Description": "WebP is a new image format that provides lossless and lossy compression for images on the web.", "Description": "WebP is a new image format that provides lossless and lossy compression for images on the web.",
"Homepage": "https://developers.google.com/speed/webp/", "Homepage": "https://developers.google.com/speed/webp/",
"Version": "1.0.2", "Version": "1.0.3",
"License": "BSD 3-clause \"New\" or \"Revised\" License", "License": "BSD 3-clause \"New\" or \"Revised\" License",
"LicenseId": "BSD-3-Clause", "LicenseId": "BSD-3-Clause",
"LicenseFile": "COPYING", "LicenseFile": "COPYING",

View File

@ -61,12 +61,17 @@ static const uint16_t kAcTable[128] = {
void VP8ParseQuant(VP8Decoder* const dec) { void VP8ParseQuant(VP8Decoder* const dec) {
VP8BitReader* const br = &dec->br_; VP8BitReader* const br = &dec->br_;
const int base_q0 = VP8GetValue(br, 7); const int base_q0 = VP8GetValue(br, 7, "global-header");
const int dqy1_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; const int dqy1_dc = VP8Get(br, "global-header") ?
const int dqy2_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; VP8GetSignedValue(br, 4, "global-header") : 0;
const int dqy2_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; const int dqy2_dc = VP8Get(br, "global-header") ?
const int dquv_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; VP8GetSignedValue(br, 4, "global-header") : 0;
const int dquv_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; const int dqy2_ac = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 4, "global-header") : 0;
const int dquv_dc = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 4, "global-header") : 0;
const int dquv_ac = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 4, "global-header") : 0;
const VP8SegmentHeader* const hdr = &dec->segment_hdr_; const VP8SegmentHeader* const hdr = &dec->segment_hdr_;
int i; int i;

View File

@ -296,20 +296,21 @@ static void ParseIntraMode(VP8BitReader* const br,
// to decode more than 1 keyframe. // to decode more than 1 keyframe.
if (dec->segment_hdr_.update_map_) { if (dec->segment_hdr_.update_map_) {
// Hardcoded tree parsing // Hardcoded tree parsing
block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0]) block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0], "segments")
? VP8GetBit(br, dec->proba_.segments_[1]) ? VP8GetBit(br, dec->proba_.segments_[1], "segments")
: 2 + VP8GetBit(br, dec->proba_.segments_[2]); : VP8GetBit(br, dec->proba_.segments_[2], "segments") + 2;
} else { } else {
block->segment_ = 0; // default for intra block->segment_ = 0; // default for intra
} }
if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_); if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_, "skip");
block->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first block->is_i4x4_ = !VP8GetBit(br, 145, "block-size");
if (!block->is_i4x4_) { if (!block->is_i4x4_) {
// Hardcoded 16x16 intra-mode decision tree. // Hardcoded 16x16 intra-mode decision tree.
const int ymode = const int ymode =
VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED) VP8GetBit(br, 156, "pred-modes") ?
: (VP8GetBit(br, 163) ? V_PRED : DC_PRED); (VP8GetBit(br, 128, "pred-modes") ? TM_PRED : H_PRED) :
(VP8GetBit(br, 163, "pred-modes") ? V_PRED : DC_PRED);
block->imodes_[0] = ymode; block->imodes_[0] = ymode;
memset(top, ymode, 4 * sizeof(*top)); memset(top, ymode, 4 * sizeof(*top));
memset(left, ymode, 4 * sizeof(*left)); memset(left, ymode, 4 * sizeof(*left));
@ -323,22 +324,25 @@ static void ParseIntraMode(VP8BitReader* const br,
const uint8_t* const prob = kBModesProba[top[x]][ymode]; const uint8_t* const prob = kBModesProba[top[x]][ymode];
#if (USE_GENERIC_TREE == 1) #if (USE_GENERIC_TREE == 1)
// Generic tree-parsing // Generic tree-parsing
int i = kYModesIntra4[VP8GetBit(br, prob[0])]; int i = kYModesIntra4[VP8GetBit(br, prob[0], "pred-modes")];
while (i > 0) { while (i > 0) {
i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])]; i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i], "pred-modes")];
} }
ymode = -i; ymode = -i;
#else #else
// Hardcoded tree parsing // Hardcoded tree parsing
ymode = !VP8GetBit(br, prob[0]) ? B_DC_PRED : ymode = !VP8GetBit(br, prob[0], "pred-modes") ? B_DC_PRED :
!VP8GetBit(br, prob[1]) ? B_TM_PRED : !VP8GetBit(br, prob[1], "pred-modes") ? B_TM_PRED :
!VP8GetBit(br, prob[2]) ? B_VE_PRED : !VP8GetBit(br, prob[2], "pred-modes") ? B_VE_PRED :
!VP8GetBit(br, prob[3]) ? !VP8GetBit(br, prob[3], "pred-modes") ?
(!VP8GetBit(br, prob[4]) ? B_HE_PRED : (!VP8GetBit(br, prob[4], "pred-modes") ? B_HE_PRED :
(!VP8GetBit(br, prob[5]) ? B_RD_PRED : B_VR_PRED)) : (!VP8GetBit(br, prob[5], "pred-modes") ? B_RD_PRED
(!VP8GetBit(br, prob[6]) ? B_LD_PRED : : B_VR_PRED)) :
(!VP8GetBit(br, prob[7]) ? B_VL_PRED : (!VP8GetBit(br, prob[6], "pred-modes") ? B_LD_PRED :
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED))); (!VP8GetBit(br, prob[7], "pred-modes") ? B_VL_PRED :
(!VP8GetBit(br, prob[8], "pred-modes") ? B_HD_PRED
: B_HU_PRED))
);
#endif // USE_GENERIC_TREE #endif // USE_GENERIC_TREE
top[x] = ymode; top[x] = ymode;
} }
@ -348,9 +352,9 @@ static void ParseIntraMode(VP8BitReader* const br,
} }
} }
// Hardcoded UVMode decision tree // Hardcoded UVMode decision tree
block->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED block->uvmode_ = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED
: !VP8GetBit(br, 114) ? V_PRED : !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED
: VP8GetBit(br, 183) ? TM_PRED : H_PRED; : VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED;
} }
int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) { int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) {
@ -514,8 +518,10 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
for (b = 0; b < NUM_BANDS; ++b) { for (b = 0; b < NUM_BANDS; ++b) {
for (c = 0; c < NUM_CTX; ++c) { for (c = 0; c < NUM_CTX; ++c) {
for (p = 0; p < NUM_PROBAS; ++p) { for (p = 0; p < NUM_PROBAS; ++p) {
const int v = VP8GetBit(br, CoeffsUpdateProba[t][b][c][p]) ? const int v =
VP8GetValue(br, 8) : CoeffsProba0[t][b][c][p]; VP8GetBit(br, CoeffsUpdateProba[t][b][c][p], "global-header") ?
VP8GetValue(br, 8, "global-header") :
CoeffsProba0[t][b][c][p];
proba->bands_[t][b].probas_[c][p] = v; proba->bands_[t][b].probas_[c][p] = v;
} }
} }
@ -524,9 +530,8 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]]; proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]];
} }
} }
dec->use_skip_proba_ = VP8Get(br); dec->use_skip_proba_ = VP8Get(br, "global-header");
if (dec->use_skip_proba_) { if (dec->use_skip_proba_) {
dec->skip_p_ = VP8GetValue(br, 8); dec->skip_p_ = VP8GetValue(br, 8, "global-header");
} }
} }

View File

@ -161,23 +161,26 @@ static int ParseSegmentHeader(VP8BitReader* br,
VP8SegmentHeader* hdr, VP8Proba* proba) { VP8SegmentHeader* hdr, VP8Proba* proba) {
assert(br != NULL); assert(br != NULL);
assert(hdr != NULL); assert(hdr != NULL);
hdr->use_segment_ = VP8Get(br); hdr->use_segment_ = VP8Get(br, "global-header");
if (hdr->use_segment_) { if (hdr->use_segment_) {
hdr->update_map_ = VP8Get(br); hdr->update_map_ = VP8Get(br, "global-header");
if (VP8Get(br)) { // update data if (VP8Get(br, "global-header")) { // update data
int s; int s;
hdr->absolute_delta_ = VP8Get(br); hdr->absolute_delta_ = VP8Get(br, "global-header");
for (s = 0; s < NUM_MB_SEGMENTS; ++s) { for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
hdr->quantizer_[s] = VP8Get(br) ? VP8GetSignedValue(br, 7) : 0; hdr->quantizer_[s] = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 7, "global-header") : 0;
} }
for (s = 0; s < NUM_MB_SEGMENTS; ++s) { for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
hdr->filter_strength_[s] = VP8Get(br) ? VP8GetSignedValue(br, 6) : 0; hdr->filter_strength_[s] = VP8Get(br, "global-header") ?
VP8GetSignedValue(br, 6, "global-header") : 0;
} }
} }
if (hdr->update_map_) { if (hdr->update_map_) {
int s; int s;
for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) { for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
proba->segments_[s] = VP8Get(br) ? VP8GetValue(br, 8) : 255u; proba->segments_[s] = VP8Get(br, "global-header") ?
VP8GetValue(br, 8, "global-header") : 255u;
} }
} }
} else { } else {
@ -205,7 +208,7 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
size_t last_part; size_t last_part;
size_t p; size_t p;
dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2)) - 1; dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2, "global-header")) - 1;
last_part = dec->num_parts_minus_one_; last_part = dec->num_parts_minus_one_;
if (size < 3 * last_part) { if (size < 3 * last_part) {
// we can't even read the sizes with sz[]! That's a failure. // we can't even read the sizes with sz[]! That's a failure.
@ -229,21 +232,21 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
// Paragraph 9.4 // Paragraph 9.4
static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) { static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
VP8FilterHeader* const hdr = &dec->filter_hdr_; VP8FilterHeader* const hdr = &dec->filter_hdr_;
hdr->simple_ = VP8Get(br); hdr->simple_ = VP8Get(br, "global-header");
hdr->level_ = VP8GetValue(br, 6); hdr->level_ = VP8GetValue(br, 6, "global-header");
hdr->sharpness_ = VP8GetValue(br, 3); hdr->sharpness_ = VP8GetValue(br, 3, "global-header");
hdr->use_lf_delta_ = VP8Get(br); hdr->use_lf_delta_ = VP8Get(br, "global-header");
if (hdr->use_lf_delta_) { if (hdr->use_lf_delta_) {
if (VP8Get(br)) { // update lf-delta? if (VP8Get(br, "global-header")) { // update lf-delta?
int i; int i;
for (i = 0; i < NUM_REF_LF_DELTAS; ++i) { for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
if (VP8Get(br)) { if (VP8Get(br, "global-header")) {
hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6); hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header");
} }
} }
for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) { for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
if (VP8Get(br)) { if (VP8Get(br, "global-header")) {
hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6); hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header");
} }
} }
} }
@ -352,8 +355,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
buf_size -= frm_hdr->partition_length_; buf_size -= frm_hdr->partition_length_;
if (frm_hdr->key_frame_) { if (frm_hdr->key_frame_) {
pic_hdr->colorspace_ = VP8Get(br); pic_hdr->colorspace_ = VP8Get(br, "global-header");
pic_hdr->clamp_type_ = VP8Get(br); pic_hdr->clamp_type_ = VP8Get(br, "global-header");
} }
if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) { if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
@ -378,7 +381,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
"Not a key frame."); "Not a key frame.");
} }
VP8Get(br); // ignore the value of update_proba_ VP8Get(br, "global-header"); // ignore the value of update_proba_
VP8ParseProba(br, dec); VP8ParseProba(br, dec);
@ -403,28 +406,28 @@ static const uint8_t kZigzag[16] = {
// See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2 // See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2
static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) { static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
int v; int v;
if (!VP8GetBit(br, p[3])) { if (!VP8GetBit(br, p[3], "coeffs")) {
if (!VP8GetBit(br, p[4])) { if (!VP8GetBit(br, p[4], "coeffs")) {
v = 2; v = 2;
} else { } else {
v = 3 + VP8GetBit(br, p[5]); v = 3 + VP8GetBit(br, p[5], "coeffs");
} }
} else { } else {
if (!VP8GetBit(br, p[6])) { if (!VP8GetBit(br, p[6], "coeffs")) {
if (!VP8GetBit(br, p[7])) { if (!VP8GetBit(br, p[7], "coeffs")) {
v = 5 + VP8GetBit(br, 159); v = 5 + VP8GetBit(br, 159, "coeffs");
} else { } else {
v = 7 + 2 * VP8GetBit(br, 165); v = 7 + 2 * VP8GetBit(br, 165, "coeffs");
v += VP8GetBit(br, 145); v += VP8GetBit(br, 145, "coeffs");
} }
} else { } else {
const uint8_t* tab; const uint8_t* tab;
const int bit1 = VP8GetBit(br, p[8]); const int bit1 = VP8GetBit(br, p[8], "coeffs");
const int bit0 = VP8GetBit(br, p[9 + bit1]); const int bit0 = VP8GetBit(br, p[9 + bit1], "coeffs");
const int cat = 2 * bit1 + bit0; const int cat = 2 * bit1 + bit0;
v = 0; v = 0;
for (tab = kCat3456[cat]; *tab; ++tab) { for (tab = kCat3456[cat]; *tab; ++tab) {
v += v + VP8GetBit(br, *tab); v += v + VP8GetBit(br, *tab, "coeffs");
} }
v += 3 + (8 << cat); v += 3 + (8 << cat);
} }
@ -438,24 +441,24 @@ static int GetCoeffsFast(VP8BitReader* const br,
int ctx, const quant_t dq, int n, int16_t* out) { int ctx, const quant_t dq, int n, int16_t* out) {
const uint8_t* p = prob[n]->probas_[ctx]; const uint8_t* p = prob[n]->probas_[ctx];
for (; n < 16; ++n) { for (; n < 16; ++n) {
if (!VP8GetBit(br, p[0])) { if (!VP8GetBit(br, p[0], "coeffs")) {
return n; // previous coeff was last non-zero coeff return n; // previous coeff was last non-zero coeff
} }
while (!VP8GetBit(br, p[1])) { // sequence of zero coeffs while (!VP8GetBit(br, p[1], "coeffs")) { // sequence of zero coeffs
p = prob[++n]->probas_[0]; p = prob[++n]->probas_[0];
if (n == 16) return 16; if (n == 16) return 16;
} }
{ // non zero coeff { // non zero coeff
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
int v; int v;
if (!VP8GetBit(br, p[2])) { if (!VP8GetBit(br, p[2], "coeffs")) {
v = 1; v = 1;
p = p_ctx[1]; p = p_ctx[1];
} else { } else {
v = GetLargeValue(br, p); v = GetLargeValue(br, p);
p = p_ctx[2]; p = p_ctx[2];
} }
out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0]; out[kZigzag[n]] = VP8GetSigned(br, v, "coeffs") * dq[n > 0];
} }
} }
return 16; return 16;
@ -468,24 +471,24 @@ static int GetCoeffsAlt(VP8BitReader* const br,
int ctx, const quant_t dq, int n, int16_t* out) { int ctx, const quant_t dq, int n, int16_t* out) {
const uint8_t* p = prob[n]->probas_[ctx]; const uint8_t* p = prob[n]->probas_[ctx];
for (; n < 16; ++n) { for (; n < 16; ++n) {
if (!VP8GetBitAlt(br, p[0])) { if (!VP8GetBitAlt(br, p[0], "coeffs")) {
return n; // previous coeff was last non-zero coeff return n; // previous coeff was last non-zero coeff
} }
while (!VP8GetBitAlt(br, p[1])) { // sequence of zero coeffs while (!VP8GetBitAlt(br, p[1], "coeffs")) { // sequence of zero coeffs
p = prob[++n]->probas_[0]; p = prob[++n]->probas_[0];
if (n == 16) return 16; if (n == 16) return 16;
} }
{ // non zero coeff { // non zero coeff
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
int v; int v;
if (!VP8GetBitAlt(br, p[2])) { if (!VP8GetBitAlt(br, p[2], "coeffs")) {
v = 1; v = 1;
p = p_ctx[1]; p = p_ctx[1];
} else { } else {
v = GetLargeValue(br, p); v = GetLargeValue(br, p);
p = p_ctx[2]; p = p_ctx[2];
} }
out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0]; out[kZigzag[n]] = VP8GetSigned(br, v, "coeffs") * dq[n > 0];
} }
} }
return 16; return 16;

View File

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

View File

@ -362,12 +362,8 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
VP8LMetadata* const hdr = &dec->hdr_; VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL; uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL; HTreeGroup* htree_groups = NULL;
// When reading htrees, some might be unused, as the format allows it.
// We will still read them but put them in this htree_group_bogus.
HTreeGroup htree_group_bogus;
HuffmanCode* huffman_tables = NULL; HuffmanCode* huffman_tables = NULL;
HuffmanCode* huffman_tables_bogus = NULL; HuffmanCode* huffman_table = NULL;
HuffmanCode* next = NULL;
int num_htree_groups = 1; int num_htree_groups = 1;
int num_htree_groups_max = 1; int num_htree_groups_max = 1;
int max_alphabet_size = 0; int max_alphabet_size = 0;
@ -418,12 +414,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
if (*mapped_group == -1) *mapped_group = num_htree_groups++; if (*mapped_group == -1) *mapped_group = num_htree_groups++;
huffman_image[i] = *mapped_group; huffman_image[i] = *mapped_group;
} }
huffman_tables_bogus = (HuffmanCode*)WebPSafeMalloc(
table_size, sizeof(*huffman_tables_bogus));
if (huffman_tables_bogus == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
} else { } else {
num_htree_groups = num_htree_groups_max; num_htree_groups = num_htree_groups_max;
} }
@ -453,63 +443,71 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
goto Error; goto Error;
} }
next = huffman_tables; huffman_table = huffman_tables;
for (i = 0; i < num_htree_groups_max; ++i) { for (i = 0; i < num_htree_groups_max; ++i) {
// If the index "i" is unused in the Huffman image, read the coefficients // If the index "i" is unused in the Huffman image, just make sure the
// but store them to a bogus htree_group. // coefficients are valid but do not store them.
const int is_bogus = (mapping != NULL && mapping[i] == -1); if (mapping != NULL && mapping[i] == -1) {
HTreeGroup* const htree_group = for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
is_bogus ? &htree_group_bogus : int alphabet_size = kAlphabetSize[j];
&htree_groups[(mapping == NULL) ? i : mapping[i]]; if (j == 0 && color_cache_bits > 0) {
HuffmanCode** const htrees = htree_group->htrees; alphabet_size += (1 << color_cache_bits);
HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next; }
int size; // Passing in NULL so that nothing gets filled.
int total_size = 0; if (!ReadHuffmanCode(alphabet_size, dec, code_lengths, NULL)) {
int is_trivial_literal = 1; goto Error;
int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j];
htrees[j] = huffman_tables_i;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += 1 << color_cache_bits;
}
size =
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i);
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
is_trivial_literal = (huffman_tables_i->bits == 0);
}
total_size += huffman_tables_i->bits;
huffman_tables_i += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
for (k = 1; k < alphabet_size; ++k) {
if (code_lengths[k] > local_max_bits) {
local_max_bits = code_lengths[k];
}
} }
max_bits += local_max_bits;
} }
} } else {
if (!is_bogus) next = huffman_tables_i; HTreeGroup* const htree_group =
htree_group->is_trivial_literal = is_trivial_literal; &htree_groups[(mapping == NULL) ? i : mapping[i]];
htree_group->is_trivial_code = 0; HuffmanCode** const htrees = htree_group->htrees;
if (is_trivial_literal) { int size;
const int red = htrees[RED][0].value; int total_size = 0;
const int blue = htrees[BLUE][0].value; int is_trivial_literal = 1;
const int alpha = htrees[ALPHA][0].value; int max_bits = 0;
htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue; for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) { int alphabet_size = kAlphabetSize[j];
htree_group->is_trivial_code = 1; htrees[j] = huffman_table;
htree_group->literal_arb |= htrees[GREEN][0].value << 8; if (j == 0 && color_cache_bits > 0) {
alphabet_size += (1 << color_cache_bits);
}
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
is_trivial_literal = (huffman_table->bits == 0);
}
total_size += huffman_table->bits;
huffman_table += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
for (k = 1; k < alphabet_size; ++k) {
if (code_lengths[k] > local_max_bits) {
local_max_bits = code_lengths[k];
}
}
max_bits += local_max_bits;
}
} }
htree_group->is_trivial_literal = is_trivial_literal;
htree_group->is_trivial_code = 0;
if (is_trivial_literal) {
const int red = htrees[RED][0].value;
const int blue = htrees[BLUE][0].value;
const int alpha = htrees[ALPHA][0].value;
htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
htree_group->is_trivial_code = 1;
htree_group->literal_arb |= htrees[GREEN][0].value << 8;
}
}
htree_group->use_packed_table =
!htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
} }
htree_group->use_packed_table =
!htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
} }
ok = 1; ok = 1;
@ -521,7 +519,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
Error: Error:
WebPSafeFree(code_lengths); WebPSafeFree(code_lengths);
WebPSafeFree(huffman_tables_bogus);
WebPSafeFree(mapping); WebPSafeFree(mapping);
if (!ok) { if (!ok) {
WebPSafeFree(huffman_image); WebPSafeFree(huffman_image);

View File

@ -25,7 +25,7 @@
#define DMUX_MAJ_VERSION 1 #define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 0 #define DMUX_MIN_VERSION 0
#define DMUX_REV_VERSION 2 #define DMUX_REV_VERSION 3
typedef struct { typedef struct {
size_t start_; // start location of the data size_t start_; // start location of the data

View File

@ -214,7 +214,7 @@ static void ApplyAlphaMultiply_SSE2(uint8_t* rgba, int alpha_first,
// Alpha detection // Alpha detection
static int HasAlpha8b_SSE2(const uint8_t* src, int length) { static int HasAlpha8b_SSE2(const uint8_t* src, int length) {
const __m128i all_0xff = _mm_set1_epi8(0xff); const __m128i all_0xff = _mm_set1_epi8((char)0xff);
int i = 0; int i = 0;
for (; i + 16 <= length; i += 16) { for (; i + 16 <= length; i += 16) {
const __m128i v = _mm_loadu_si128((const __m128i*)(src + i)); const __m128i v = _mm_loadu_si128((const __m128i*)(src + i));
@ -228,7 +228,7 @@ static int HasAlpha8b_SSE2(const uint8_t* src, int length) {
static int HasAlpha32b_SSE2(const uint8_t* src, int length) { static int HasAlpha32b_SSE2(const uint8_t* src, int length) {
const __m128i alpha_mask = _mm_set1_epi32(0xff); const __m128i alpha_mask = _mm_set1_epi32(0xff);
const __m128i all_0xff = _mm_set1_epi8(0xff); const __m128i all_0xff = _mm_set1_epi8((char)0xff);
int i = 0; int i = 0;
// We don't know if we can access the last 3 bytes after the last alpha // We don't know if we can access the last 3 bytes after the last alpha
// value 'src[4 * length - 4]' (because we don't know if alpha is the first // value 'src[4 * length - 4]' (because we don't know if alpha is the first

View File

@ -173,8 +173,8 @@ static int AndroidCPUInfo(CPUFeature feature) {
const AndroidCpuFamily cpu_family = android_getCpuFamily(); const AndroidCpuFamily cpu_family = android_getCpuFamily();
const uint64_t cpu_features = android_getCpuFeatures(); const uint64_t cpu_features = android_getCpuFeatures();
if (feature == kNEON) { if (feature == kNEON) {
return (cpu_family == ANDROID_CPU_FAMILY_ARM && return cpu_family == ANDROID_CPU_FAMILY_ARM &&
0 != (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON)); (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
} }
return 0; return 0;
} }

View File

@ -326,7 +326,7 @@ static WEBP_INLINE void Update2Pixels_SSE2(__m128i* const pi, __m128i* const qi,
const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7); const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7);
const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7); const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7);
const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi); const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi);
const __m128i sign_bit = _mm_set1_epi8(0x80); const __m128i sign_bit = _mm_set1_epi8((char)0x80);
*pi = _mm_adds_epi8(*pi, delta); *pi = _mm_adds_epi8(*pi, delta);
*qi = _mm_subs_epi8(*qi, delta); *qi = _mm_subs_epi8(*qi, delta);
FLIP_SIGN_BIT2(*pi, *qi); FLIP_SIGN_BIT2(*pi, *qi);
@ -338,9 +338,9 @@ static WEBP_INLINE void NeedsFilter_SSE2(const __m128i* const p1,
const __m128i* const q0, const __m128i* const q0,
const __m128i* const q1, const __m128i* const q1,
int thresh, __m128i* const mask) { int thresh, __m128i* const mask) {
const __m128i m_thresh = _mm_set1_epi8(thresh); const __m128i m_thresh = _mm_set1_epi8((char)thresh);
const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1) const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
const __m128i kFE = _mm_set1_epi8(0xFE); const __m128i kFE = _mm_set1_epi8((char)0xFE);
const __m128i t2 = _mm_and_si128(t1, kFE); // set lsb of each byte to zero const __m128i t2 = _mm_and_si128(t1, kFE); // set lsb of each byte to zero
const __m128i t3 = _mm_srli_epi16(t2, 1); // abs(p1 - q1) / 2 const __m128i t3 = _mm_srli_epi16(t2, 1); // abs(p1 - q1) / 2
@ -360,7 +360,7 @@ static WEBP_INLINE void DoFilter2_SSE2(__m128i* const p1, __m128i* const p0,
__m128i* const q0, __m128i* const q1, __m128i* const q0, __m128i* const q1,
int thresh) { int thresh) {
__m128i a, mask; __m128i a, mask;
const __m128i sign_bit = _mm_set1_epi8(0x80); const __m128i sign_bit = _mm_set1_epi8((char)0x80);
// convert p1/q1 to int8_t (for GetBaseDelta_SSE2) // convert p1/q1 to int8_t (for GetBaseDelta_SSE2)
const __m128i p1s = _mm_xor_si128(*p1, sign_bit); const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
const __m128i q1s = _mm_xor_si128(*q1, sign_bit); const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
@ -380,7 +380,7 @@ static WEBP_INLINE void DoFilter4_SSE2(__m128i* const p1, __m128i* const p0,
const __m128i* const mask, const __m128i* const mask,
int hev_thresh) { int hev_thresh) {
const __m128i zero = _mm_setzero_si128(); const __m128i zero = _mm_setzero_si128();
const __m128i sign_bit = _mm_set1_epi8(0x80); const __m128i sign_bit = _mm_set1_epi8((char)0x80);
const __m128i k64 = _mm_set1_epi8(64); const __m128i k64 = _mm_set1_epi8(64);
const __m128i k3 = _mm_set1_epi8(3); const __m128i k3 = _mm_set1_epi8(3);
const __m128i k4 = _mm_set1_epi8(4); const __m128i k4 = _mm_set1_epi8(4);
@ -427,7 +427,7 @@ static WEBP_INLINE void DoFilter6_SSE2(__m128i* const p2, __m128i* const p1,
const __m128i* const mask, const __m128i* const mask,
int hev_thresh) { int hev_thresh) {
const __m128i zero = _mm_setzero_si128(); const __m128i zero = _mm_setzero_si128();
const __m128i sign_bit = _mm_set1_epi8(0x80); const __m128i sign_bit = _mm_set1_epi8((char)0x80);
__m128i a, not_hev; __m128i a, not_hev;
// compute hev mask // compute hev mask
@ -941,7 +941,7 @@ static void VR4_SSE2(uint8_t* dst) { // Vertical-Right
const __m128i ABCD0 = _mm_srli_si128(XABCD, 1); const __m128i ABCD0 = _mm_srli_si128(XABCD, 1);
const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0); const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0);
const __m128i _XABCD = _mm_slli_si128(XABCD, 1); const __m128i _XABCD = _mm_slli_si128(XABCD, 1);
const __m128i IXABCD = _mm_insert_epi16(_XABCD, I | (X << 8), 0); const __m128i IXABCD = _mm_insert_epi16(_XABCD, (short)(I | (X << 8)), 0);
const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0); const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0);
const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one); const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one);
const __m128i avg2 = _mm_subs_epu8(avg1, lsb); const __m128i avg2 = _mm_subs_epu8(avg1, lsb);

View File

@ -55,12 +55,12 @@ extern "C" {
#if !defined(EMSCRIPTEN) #if !defined(EMSCRIPTEN)
#if defined(_MSC_VER) && _MSC_VER > 1310 && \ #if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86)) && !defined(__clang__) (defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets #define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
#endif #endif
#if defined(_MSC_VER) && _MSC_VER >= 1500 && \ #if defined(_MSC_VER) && _MSC_VER >= 1500 && \
(defined(_M_X64) || defined(_M_IX86)) && !defined(__clang__) (defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets #define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
#endif #endif
@ -90,7 +90,7 @@ extern "C" {
#define WEBP_USE_NEON #define WEBP_USE_NEON
#endif #endif
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM) && !defined(__clang__) #if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
#define WEBP_USE_NEON #define WEBP_USE_NEON
#define WEBP_USE_INTRINSICS #define WEBP_USE_INTRINSICS
#endif #endif

View File

@ -777,7 +777,7 @@ static WEBP_INLINE void VR4_SSE2(uint8_t* dst,
const __m128i ABCD0 = _mm_srli_si128(XABCD, 1); const __m128i ABCD0 = _mm_srli_si128(XABCD, 1);
const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0); const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0);
const __m128i _XABCD = _mm_slli_si128(XABCD, 1); const __m128i _XABCD = _mm_slli_si128(XABCD, 1);
const __m128i IXABCD = _mm_insert_epi16(_XABCD, I | (X << 8), 0); const __m128i IXABCD = _mm_insert_epi16(_XABCD, (short)(I | (X << 8)), 0);
const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0); const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0);
const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one); const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one);
const __m128i avg2 = _mm_subs_epu8(avg1, lsb); const __m128i avg2 = _mm_subs_epu8(avg1, lsb);

View File

@ -33,9 +33,9 @@ static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred,
uint8_t* dst, int length, int inverse) { uint8_t* dst, int length, int inverse) {
int i; int i;
if (inverse) { if (inverse) {
for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i]; for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] + pred[i]);
} else { } else {
for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i]; for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] - pred[i]);
} }
} }
@ -155,7 +155,7 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
const int pred = GradientPredictor_C(preds[w - 1], const int pred = GradientPredictor_C(preds[w - 1],
preds[w - stride], preds[w - stride],
preds[w - stride - 1]); preds[w - stride - 1]);
out[w] = in[w] + (inverse ? pred : -pred); out[w] = (uint8_t)(in[w] + (inverse ? pred : -pred));
} }
++row; ++row;
preds += stride; preds += stride;
@ -194,7 +194,7 @@ static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in,
uint8_t pred = (prev == NULL) ? 0 : prev[0]; uint8_t pred = (prev == NULL) ? 0 : prev[0];
int i; int i;
for (i = 0; i < width; ++i) { for (i = 0; i < width; ++i) {
out[i] = pred + in[i]; out[i] = (uint8_t)(pred + in[i]);
pred = out[i]; pred = out[i];
} }
} }
@ -206,7 +206,7 @@ static void VerticalUnfilter_C(const uint8_t* prev, const uint8_t* in,
HorizontalUnfilter_C(NULL, in, out, width); HorizontalUnfilter_C(NULL, in, out, width);
} else { } else {
int i; int i;
for (i = 0; i < width; ++i) out[i] = prev[i] + in[i]; for (i = 0; i < width; ++i) out[i] = (uint8_t)(prev[i] + in[i]);
} }
} }
#endif // !WEBP_NEON_OMIT_C_CODE #endif // !WEBP_NEON_OMIT_C_CODE
@ -220,7 +220,7 @@ static void GradientUnfilter_C(const uint8_t* prev, const uint8_t* in,
int i; int i;
for (i = 0; i < width; ++i) { for (i = 0; i < width; ++i) {
top = prev[i]; // need to read this first, in case prev==out top = prev[i]; // need to read this first, in case prev==out
left = in[i] + GradientPredictor_C(left, top, top_left); left = (uint8_t)(in[i] + GradientPredictor_C(left, top, top_left));
top_left = top; top_left = top;
out[i] = left; out[i] = left;
} }

View File

@ -163,7 +163,8 @@ static void GradientPredictDirect_SSE2(const uint8_t* const row,
_mm_storel_epi64((__m128i*)(out + i), H); _mm_storel_epi64((__m128i*)(out + i), H);
} }
for (; i < length; ++i) { for (; i < length; ++i) {
out[i] = row[i] - GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]); const int delta = GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
out[i] = (uint8_t)(row[i] - delta);
} }
} }
@ -188,7 +189,7 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
// Filter line-by-line. // Filter line-by-line.
while (row < last_row) { while (row < last_row) {
out[0] = in[0] - in[-stride]; out[0] = (uint8_t)(in[0] - in[-stride]);
GradientPredictDirect_SSE2(in + 1, in + 1 - stride, out + 1, width - 1); GradientPredictDirect_SSE2(in + 1, in + 1 - stride, out + 1, width - 1);
++row; ++row;
in += stride; in += stride;
@ -223,7 +224,7 @@ static void HorizontalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
uint8_t* out, int width) { uint8_t* out, int width) {
int i; int i;
__m128i last; __m128i last;
out[0] = in[0] + (prev == NULL ? 0 : prev[0]); out[0] = (uint8_t)(in[0] + (prev == NULL ? 0 : prev[0]));
if (width <= 1) return; if (width <= 1) return;
last = _mm_set_epi32(0, 0, 0, out[0]); last = _mm_set_epi32(0, 0, 0, out[0]);
for (i = 1; i + 8 <= width; i += 8) { for (i = 1; i + 8 <= width; i += 8) {
@ -238,7 +239,7 @@ static void HorizontalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
_mm_storel_epi64((__m128i*)(out + i), A7); _mm_storel_epi64((__m128i*)(out + i), A7);
last = _mm_srli_epi64(A7, 56); last = _mm_srli_epi64(A7, 56);
} }
for (; i < width; ++i) out[i] = in[i] + out[i - 1]; for (; i < width; ++i) out[i] = (uint8_t)(in[i] + out[i - 1]);
} }
static void VerticalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in, static void VerticalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
@ -259,7 +260,7 @@ static void VerticalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
_mm_storeu_si128((__m128i*)&out[i + 0], C0); _mm_storeu_si128((__m128i*)&out[i + 0], C0);
_mm_storeu_si128((__m128i*)&out[i + 16], C1); _mm_storeu_si128((__m128i*)&out[i + 16], C1);
} }
for (; i < width; ++i) out[i] = in[i] + prev[i]; for (; i < width; ++i) out[i] = (uint8_t)(in[i] + prev[i]);
} }
} }
@ -296,7 +297,8 @@ static void GradientPredictInverse_SSE2(const uint8_t* const in,
_mm_storel_epi64((__m128i*)&row[i], out); _mm_storel_epi64((__m128i*)&row[i], out);
} }
for (; i < length; ++i) { for (; i < length; ++i) {
row[i] = in[i] + GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]); const int delta = GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
row[i] = (uint8_t)(in[i] + delta);
} }
} }
} }
@ -306,7 +308,7 @@ static void GradientUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
if (prev == NULL) { if (prev == NULL) {
HorizontalUnfilter_SSE2(NULL, in, out, width); HorizontalUnfilter_SSE2(NULL, in, out, width);
} else { } else {
out[0] = in[0] + prev[0]; // predict from above out[0] = (uint8_t)(in[0] + prev[0]); // predict from above
GradientPredictInverse_SSE2(in + 1, prev + 1, out + 1, width - 1); GradientPredictInverse_SSE2(in + 1, prev + 1, out + 1, width - 1);
} }
} }

View File

@ -270,14 +270,14 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
int i; int i;
for (i = 0; i < num_pixels; ++i) { for (i = 0; i < num_pixels; ++i) {
const uint32_t argb = src[i]; const uint32_t argb = src[i];
const uint32_t green = argb >> 8; const int8_t green = (int8_t)(argb >> 8);
const uint32_t red = argb >> 16; const uint32_t red = argb >> 16;
int new_red = red & 0xff; int new_red = red & 0xff;
int new_blue = argb & 0xff; int new_blue = argb & 0xff;
new_red += ColorTransformDelta(m->green_to_red_, green); new_red += ColorTransformDelta(m->green_to_red_, green);
new_red &= 0xff; new_red &= 0xff;
new_blue += ColorTransformDelta(m->green_to_blue_, green); new_blue += ColorTransformDelta(m->green_to_blue_, green);
new_blue += ColorTransformDelta(m->red_to_blue_, new_red); new_blue += ColorTransformDelta(m->red_to_blue_, (int8_t)new_red);
new_blue &= 0xff; new_blue &= 0xff;
dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
} }

View File

@ -515,13 +515,17 @@ static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, int8_t color) {
return ((int)color_pred * color) >> 5; return ((int)color_pred * color) >> 5;
} }
static WEBP_INLINE int8_t U32ToS8(uint32_t v) {
return (int8_t)(v & 0xff);
}
void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data, void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data,
int num_pixels) { int num_pixels) {
int i; int i;
for (i = 0; i < num_pixels; ++i) { for (i = 0; i < num_pixels; ++i) {
const uint32_t argb = data[i]; const uint32_t argb = data[i];
const uint32_t green = argb >> 8; const int8_t green = U32ToS8(argb >> 8);
const uint32_t red = argb >> 16; const int8_t red = U32ToS8(argb >> 16);
int new_red = red & 0xff; int new_red = red & 0xff;
int new_blue = argb & 0xff; int new_blue = argb & 0xff;
new_red -= ColorTransformDelta(m->green_to_red_, green); new_red -= ColorTransformDelta(m->green_to_red_, green);
@ -535,7 +539,7 @@ void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data,
static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red, static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red,
uint32_t argb) { uint32_t argb) {
const uint32_t green = argb >> 8; const int8_t green = U32ToS8(argb >> 8);
int new_red = argb >> 16; int new_red = argb >> 16;
new_red -= ColorTransformDelta(green_to_red, green); new_red -= ColorTransformDelta(green_to_red, green);
return (new_red & 0xff); return (new_red & 0xff);
@ -544,9 +548,9 @@ static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red,
static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue, static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue,
uint8_t red_to_blue, uint8_t red_to_blue,
uint32_t argb) { uint32_t argb) {
const uint32_t green = argb >> 8; const int8_t green = U32ToS8(argb >> 8);
const uint32_t red = argb >> 16; const int8_t red = U32ToS8(argb >> 16);
uint8_t new_blue = argb; uint8_t new_blue = argb & 0xff;
new_blue -= ColorTransformDelta(green_to_blue, green); new_blue -= ColorTransformDelta(green_to_blue, green);
new_blue -= ColorTransformDelta(red_to_blue, red); new_blue -= ColorTransformDelta(red_to_blue, red);
return (new_blue & 0xff); return (new_blue & 0xff);
@ -558,7 +562,7 @@ void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride,
while (tile_height-- > 0) { while (tile_height-- > 0) {
int x; int x;
for (x = 0; x < tile_width; ++x) { for (x = 0; x < tile_width; ++x) {
++histo[TransformColorRed(green_to_red, argb[x])]; ++histo[TransformColorRed((uint8_t)green_to_red, argb[x])];
} }
argb += stride; argb += stride;
} }
@ -571,7 +575,8 @@ void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride,
while (tile_height-- > 0) { while (tile_height-- > 0) {
int x; int x;
for (x = 0; x < tile_width; ++x) { for (x = 0; x < tile_width; ++x) {
++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[x])]; ++histo[TransformColorBlue((uint8_t)green_to_blue, (uint8_t)red_to_blue,
argb[x])];
} }
argb += stride; argb += stride;
} }

View File

@ -363,7 +363,7 @@ static void BundleColorMap_SSE2(const uint8_t* const row, int width, int xbits,
assert(xbits <= 3); assert(xbits <= 3);
switch (xbits) { switch (xbits) {
case 0: { case 0: {
const __m128i ff = _mm_set1_epi16(0xff00); const __m128i ff = _mm_set1_epi16((short)0xff00);
const __m128i zero = _mm_setzero_si128(); const __m128i zero = _mm_setzero_si128();
// Store 0xff000000 | (row[x] << 8). // Store 0xff000000 | (row[x] << 8).
for (x = 0; x + 16 <= width; x += 16, dst += 16) { for (x = 0; x + 16 <= width; x += 16, dst += 16) {
@ -382,7 +382,7 @@ static void BundleColorMap_SSE2(const uint8_t* const row, int width, int xbits,
break; break;
} }
case 1: { case 1: {
const __m128i ff = _mm_set1_epi16(0xff00); const __m128i ff = _mm_set1_epi16((short)0xff00);
const __m128i mul = _mm_set1_epi16(0x110); const __m128i mul = _mm_set1_epi16(0x110);
for (x = 0; x + 16 <= width; x += 16, dst += 8) { for (x = 0; x + 16 <= width; x += 16, dst += 8) {
// 0a0b | (where a/b are 4 bits). // 0a0b | (where a/b are 4 bits).

View File

@ -51,9 +51,9 @@ static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride,
int histo[]) { int histo[]) {
const __m128i mults_r = _mm_set1_epi16(CST_5b(red_to_blue)); 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 mults_g = _mm_set1_epi16(CST_5b(green_to_blue));
const __m128i mask_g = _mm_set1_epi16(0xff00); // green mask 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_gb = _mm_set1_epi32(0xffff); // green/blue mask
const __m128i mask_b = _mm_set1_epi16(0x00ff); // 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, const __m128i shuffler_lo = _mm_setr_epi8(-1, 2, -1, 6, -1, 10, -1, 14, -1,
-1, -1, -1, -1, -1, -1, -1); -1, -1, -1, -1, -1, -1, -1);
const __m128i shuffler_hi = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, const __m128i shuffler_hi = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1,

View File

@ -10,6 +10,8 @@
#ifndef WEBP_DSP_QUANT_H_ #ifndef WEBP_DSP_QUANT_H_
#define WEBP_DSP_QUANT_H_ #define WEBP_DSP_QUANT_H_
#include <string.h>
#include "src/dsp/dsp.h" #include "src/dsp/dsp.h"
#include "src/webp/types.h" #include "src/webp/types.h"
@ -67,4 +69,17 @@ static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
#endif // defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) && #endif // defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) &&
// !defined(WEBP_HAVE_NEON_RTCD) // !defined(WEBP_HAVE_NEON_RTCD)
static WEBP_INLINE int IsFlatSource16(const uint8_t* src) {
const uint32_t v = src[0] * 0x01010101u;
int i;
for (i = 0; i < 16; ++i) {
if (memcmp(src + 0, &v, 4) || memcmp(src + 4, &v, 4) ||
memcmp(src + 8, &v, 4) || memcmp(src + 12, &v, 4)) {
return 0;
}
src += BPS;
}
return 1;
}
#endif // WEBP_DSP_QUANT_H_ #endif // WEBP_DSP_QUANT_H_

View File

@ -109,8 +109,7 @@ void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
for (x_out = 0; x_out < x_out_max; ++x_out) { for (x_out = 0; x_out < x_out_max; ++x_out) {
const uint32_t J = frow[x_out]; const uint32_t J = frow[x_out];
const int v = (int)MULT_FIX(J, wrk->fy_scale); const int v = (int)MULT_FIX(J, wrk->fy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
} }
} else { } else {
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
@ -120,8 +119,7 @@ void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
+ (uint64_t)B * irow[x_out]; + (uint64_t)B * irow[x_out];
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
const int v = (int)MULT_FIX(J, wrk->fy_scale); const int v = (int)MULT_FIX(J, wrk->fy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
} }
} }
} }
@ -138,17 +136,15 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
assert(!wrk->y_expand); assert(!wrk->y_expand);
if (yscale) { if (yscale) {
for (x_out = 0; x_out < x_out_max; ++x_out) { for (x_out = 0; x_out < x_out_max; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale); const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale); const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
irow[x_out] = frac; // new fractional start irow[x_out] = frac; // new fractional start
} }
} else { } else {
for (x_out = 0; x_out < x_out_max; ++x_out) { for (x_out = 0; x_out < x_out_max; ++x_out) {
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
irow[x_out] = 0; irow[x_out] = 0;
} }
} }

View File

@ -107,10 +107,9 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
); );
} }
for (i = 0; i < (x_out_max & 0x3); ++i) { for (i = 0; i < (x_out_max & 0x3); ++i) {
const uint32_t frac = (uint32_t)MULT_FIX(*frow++, yscale); const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(*frow++, yscale);
const int v = (int)MULT_FIX_FLOOR(*irow - frac, wrk->fxy_scale); const int v = (int)MULT_FIX(*irow - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255); *dst++ = (v > 255) ? 255u : (uint8_t)v;
*dst++ = v;
*irow++ = frac; // new fractional start *irow++ = frac; // new fractional start
} }
} else { } else {
@ -157,8 +156,7 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
} }
for (i = 0; i < (x_out_max & 0x3); ++i) { for (i = 0; i < (x_out_max & 0x3); ++i) {
const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale); const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale);
assert(v >= 0 && v <= 255); *dst++ = (v > 255) ? 255u : (uint8_t)v;
*dst++ = v;
*irow++ = 0; *irow++ = 0;
} }
} }
@ -219,8 +217,7 @@ static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
for (i = 0; i < (x_out_max & 0x3); ++i) { for (i = 0; i < (x_out_max & 0x3); ++i) {
const uint32_t J = *frow++; const uint32_t J = *frow++;
const int v = (int)MULT_FIX(J, wrk->fy_scale); const int v = (int)MULT_FIX(J, wrk->fy_scale);
assert(v >= 0 && v <= 255); *dst++ = (v > 255) ? 255u : (uint8_t)v;
*dst++ = v;
} }
} else { } else {
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
@ -291,8 +288,7 @@ static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
+ (uint64_t)B * *irow++; + (uint64_t)B * *irow++;
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
const int v = (int)MULT_FIX(J, wrk->fy_scale); const int v = (int)MULT_FIX(J, wrk->fy_scale);
assert(v >= 0 && v <= 255); *dst++ = (v > 255) ? 255u : (uint8_t)v;
*dst++ = v;
} }
} }
} }

View File

@ -166,8 +166,7 @@ static WEBP_INLINE void ExportRowExpand_0(const uint32_t* frow, uint8_t* dst,
for (x_out = 0; x_out < length; ++x_out) { for (x_out = 0; x_out < length; ++x_out) {
const uint32_t J = frow[x_out]; const uint32_t J = frow[x_out];
const int v = (int)MULT_FIX(J, wrk->fy_scale); const int v = (int)MULT_FIX(J, wrk->fy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
} }
} }
} }
@ -241,8 +240,7 @@ static WEBP_INLINE void ExportRowExpand_1(const uint32_t* frow, uint32_t* irow,
+ (uint64_t)B * irow[x_out]; + (uint64_t)B * irow[x_out];
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
const int v = (int)MULT_FIX(J, wrk->fy_scale); const int v = (int)MULT_FIX(J, wrk->fy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
} }
} }
} }
@ -342,10 +340,9 @@ static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
length -= 4; length -= 4;
} }
for (x_out = 0; x_out < length; ++x_out) { for (x_out = 0; x_out < length; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale); const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale); const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
irow[x_out] = frac; irow[x_out] = frac;
} }
} }
@ -406,8 +403,7 @@ static WEBP_INLINE void ExportRowShrink_1(uint32_t* irow, uint8_t* dst,
} }
for (x_out = 0; x_out < length; ++x_out) { for (x_out = 0; x_out < length; ++x_out) {
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
irow[x_out] = 0; irow[x_out] = 0;
} }
} }

View File

@ -81,14 +81,13 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
const uint32x4_t B1 = MULT_FIX(A1, fy_scale_half); const uint32x4_t B1 = MULT_FIX(A1, fy_scale_half);
const uint16x4_t C0 = vmovn_u32(B0); const uint16x4_t C0 = vmovn_u32(B0);
const uint16x4_t C1 = vmovn_u32(B1); const uint16x4_t C1 = vmovn_u32(B1);
const uint8x8_t D = vmovn_u16(vcombine_u16(C0, C1)); const uint8x8_t D = vqmovn_u16(vcombine_u16(C0, C1));
vst1_u8(dst + x_out, D); vst1_u8(dst + x_out, D);
} }
for (; x_out < x_out_max; ++x_out) { for (; x_out < x_out_max; ++x_out) {
const uint32_t J = frow[x_out]; const uint32_t J = frow[x_out];
const int v = (int)MULT_FIX_C(J, fy_scale); const int v = (int)MULT_FIX_C(J, fy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
} }
} else { } else {
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
@ -102,7 +101,7 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half); const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half);
const uint16x4_t E0 = vmovn_u32(D0); const uint16x4_t E0 = vmovn_u32(D0);
const uint16x4_t E1 = vmovn_u32(D1); const uint16x4_t E1 = vmovn_u32(D1);
const uint8x8_t F = vmovn_u16(vcombine_u16(E0, E1)); const uint8x8_t F = vqmovn_u16(vcombine_u16(E0, E1));
vst1_u8(dst + x_out, F); vst1_u8(dst + x_out, F);
} }
for (; x_out < x_out_max; ++x_out) { for (; x_out < x_out_max; ++x_out) {
@ -110,8 +109,7 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
+ (uint64_t)B * irow[x_out]; + (uint64_t)B * irow[x_out];
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
const int v = (int)MULT_FIX_C(J, fy_scale); const int v = (int)MULT_FIX_C(J, fy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
} }
} }
} }
@ -135,23 +133,22 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
for (x_out = 0; x_out < max_span; x_out += 8) { for (x_out = 0; x_out < max_span; x_out += 8) {
LOAD_32x8(frow + x_out, in0, in1); LOAD_32x8(frow + x_out, in0, in1);
LOAD_32x8(irow + x_out, in2, in3); LOAD_32x8(irow + x_out, in2, in3);
const uint32x4_t A0 = MULT_FIX(in0, yscale_half); const uint32x4_t A0 = MULT_FIX_FLOOR(in0, yscale_half);
const uint32x4_t A1 = MULT_FIX(in1, yscale_half); const uint32x4_t A1 = MULT_FIX_FLOOR(in1, yscale_half);
const uint32x4_t B0 = vqsubq_u32(in2, A0); const uint32x4_t B0 = vqsubq_u32(in2, A0);
const uint32x4_t B1 = vqsubq_u32(in3, A1); const uint32x4_t B1 = vqsubq_u32(in3, A1);
const uint32x4_t C0 = MULT_FIX_FLOOR(B0, fxy_scale_half); const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half);
const uint32x4_t C1 = MULT_FIX_FLOOR(B1, fxy_scale_half); const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half);
const uint16x4_t D0 = vmovn_u32(C0); const uint16x4_t D0 = vmovn_u32(C0);
const uint16x4_t D1 = vmovn_u32(C1); const uint16x4_t D1 = vmovn_u32(C1);
const uint8x8_t E = vmovn_u16(vcombine_u16(D0, D1)); const uint8x8_t E = vqmovn_u16(vcombine_u16(D0, D1));
vst1_u8(dst + x_out, E); vst1_u8(dst + x_out, E);
STORE_32x8(A0, A1, irow + x_out); STORE_32x8(A0, A1, irow + x_out);
} }
for (; x_out < x_out_max; ++x_out) { for (; x_out < x_out_max; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX_C(frow[x_out], yscale); const uint32_t frac = (uint32_t)MULT_FIX_FLOOR_C(frow[x_out], yscale);
const int v = (int)MULT_FIX_FLOOR_C(irow[x_out] - frac, fxy_scale); const int v = (int)MULT_FIX_C(irow[x_out] - frac, fxy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
irow[x_out] = frac; // new fractional start irow[x_out] = frac; // new fractional start
} }
} else { } else {
@ -161,14 +158,13 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
const uint32x4_t A1 = MULT_FIX(in1, fxy_scale_half); const uint32x4_t A1 = MULT_FIX(in1, fxy_scale_half);
const uint16x4_t B0 = vmovn_u32(A0); const uint16x4_t B0 = vmovn_u32(A0);
const uint16x4_t B1 = vmovn_u32(A1); const uint16x4_t B1 = vmovn_u32(A1);
const uint8x8_t C = vmovn_u16(vcombine_u16(B0, B1)); const uint8x8_t C = vqmovn_u16(vcombine_u16(B0, B1));
vst1_u8(dst + x_out, C); vst1_u8(dst + x_out, C);
STORE_32x8(zero, zero, irow + x_out); STORE_32x8(zero, zero, irow + x_out);
} }
for (; x_out < x_out_max; ++x_out) { for (; x_out < x_out_max; ++x_out) {
const int v = (int)MULT_FIX_C(irow[x_out], fxy_scale); const int v = (int)MULT_FIX_C(irow[x_out], fxy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
irow[x_out] = 0; irow[x_out] = 0;
} }
} }

View File

@ -225,35 +225,6 @@ static WEBP_INLINE void ProcessRow_SSE2(const __m128i* const A0,
_mm_storel_epi64((__m128i*)dst, G); _mm_storel_epi64((__m128i*)dst, G);
} }
static WEBP_INLINE void ProcessRow_Floor_SSE2(const __m128i* const A0,
const __m128i* const A1,
const __m128i* const A2,
const __m128i* const A3,
const __m128i* const mult,
uint8_t* const dst) {
const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
const __m128i B0 = _mm_mul_epu32(*A0, *mult);
const __m128i B1 = _mm_mul_epu32(*A1, *mult);
const __m128i B2 = _mm_mul_epu32(*A2, *mult);
const __m128i B3 = _mm_mul_epu32(*A3, *mult);
const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX);
const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
#if (WEBP_RESCALER_RFIX < 32)
const __m128i D2 =
_mm_and_si128(_mm_slli_epi64(B2, 32 - WEBP_RESCALER_RFIX), mask);
const __m128i D3 =
_mm_and_si128(_mm_slli_epi64(B3, 32 - WEBP_RESCALER_RFIX), mask);
#else
const __m128i D2 = _mm_and_si128(B2, mask);
const __m128i D3 = _mm_and_si128(B3, mask);
#endif
const __m128i E0 = _mm_or_si128(D0, D2);
const __m128i E1 = _mm_or_si128(D1, D3);
const __m128i F = _mm_packs_epi32(E0, E1);
const __m128i G = _mm_packus_epi16(F, F);
_mm_storel_epi64((__m128i*)dst, G);
}
static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) { static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
int x_out; int x_out;
uint8_t* const dst = wrk->dst; uint8_t* const dst = wrk->dst;
@ -274,8 +245,7 @@ static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
for (; x_out < x_out_max; ++x_out) { for (; x_out < x_out_max; ++x_out) {
const uint32_t J = frow[x_out]; const uint32_t J = frow[x_out];
const int v = (int)MULT_FIX(J, wrk->fy_scale); const int v = (int)MULT_FIX(J, wrk->fy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
} }
} else { } else {
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
@ -308,8 +278,7 @@ static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
+ (uint64_t)B * irow[x_out]; + (uint64_t)B * irow[x_out];
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
const int v = (int)MULT_FIX(J, wrk->fy_scale); const int v = (int)MULT_FIX(J, wrk->fy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
} }
} }
} }
@ -328,20 +297,15 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
const int scale_xy = wrk->fxy_scale; const int scale_xy = wrk->fxy_scale;
const __m128i mult_xy = _mm_set_epi32(0, scale_xy, 0, scale_xy); const __m128i mult_xy = _mm_set_epi32(0, scale_xy, 0, scale_xy);
const __m128i mult_y = _mm_set_epi32(0, yscale, 0, yscale); const __m128i mult_y = _mm_set_epi32(0, yscale, 0, yscale);
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) { for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
__m128i A0, A1, A2, A3, B0, B1, B2, B3; __m128i A0, A1, A2, A3, B0, B1, B2, B3;
LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3); LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3);
LoadDispatchAndMult_SSE2(frow + x_out, &mult_y, &B0, &B1, &B2, &B3); LoadDispatchAndMult_SSE2(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
{ {
const __m128i C0 = _mm_add_epi64(B0, rounder); const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX); // = frac
const __m128i C1 = _mm_add_epi64(B1, rounder); const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
const __m128i C2 = _mm_add_epi64(B2, rounder); const __m128i D2 = _mm_srli_epi64(B2, WEBP_RESCALER_RFIX);
const __m128i C3 = _mm_add_epi64(B3, rounder); const __m128i D3 = _mm_srli_epi64(B3, WEBP_RESCALER_RFIX);
const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX); // = frac
const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX);
const __m128i D2 = _mm_srli_epi64(C2, WEBP_RESCALER_RFIX);
const __m128i D3 = _mm_srli_epi64(C3, WEBP_RESCALER_RFIX);
const __m128i E0 = _mm_sub_epi64(A0, D0); // irow[x] - frac const __m128i E0 = _mm_sub_epi64(A0, D0); // irow[x] - frac
const __m128i E1 = _mm_sub_epi64(A1, D1); const __m128i E1 = _mm_sub_epi64(A1, D1);
const __m128i E2 = _mm_sub_epi64(A2, D2); const __m128i E2 = _mm_sub_epi64(A2, D2);
@ -352,14 +316,13 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
const __m128i G1 = _mm_or_si128(D1, F3); const __m128i G1 = _mm_or_si128(D1, F3);
_mm_storeu_si128((__m128i*)(irow + x_out + 0), G0); _mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
_mm_storeu_si128((__m128i*)(irow + x_out + 4), G1); _mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
ProcessRow_Floor_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out); ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
} }
} }
for (; x_out < x_out_max; ++x_out) { for (; x_out < x_out_max; ++x_out) {
const uint32_t frac = (int)MULT_FIX(frow[x_out], yscale); const uint32_t frac = (int)MULT_FIX_FLOOR(frow[x_out], yscale);
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale); const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
irow[x_out] = frac; // new fractional start irow[x_out] = frac; // new fractional start
} }
} else { } else {
@ -375,8 +338,7 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
} }
for (; x_out < x_out_max; ++x_out) { for (; x_out < x_out_max; ++x_out) {
const int v = (int)MULT_FIX(irow[x_out], scale); const int v = (int)MULT_FIX(irow[x_out], scale);
assert(v >= 0 && v <= 255); dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
dst[x_out] = v;
irow[x_out] = 0; irow[x_out] = 0;
} }
} }

View File

@ -191,13 +191,14 @@ void VP8LHashChainClear(VP8LHashChain* const p) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#define HASH_MULTIPLIER_HI (0xc6a4a793ULL) static const uint32_t kHashMultiplierHi = 0xc6a4a793u;
#define HASH_MULTIPLIER_LO (0x5bd1e996ULL) static const uint32_t kHashMultiplierLo = 0x5bd1e996u;
static WEBP_INLINE uint32_t GetPixPairHash64(const uint32_t* const argb) { static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
uint32_t GetPixPairHash64(const uint32_t* const argb) {
uint32_t key; uint32_t key;
key = (argb[1] * HASH_MULTIPLIER_HI) & 0xffffffffu; key = argb[1] * kHashMultiplierHi;
key += (argb[0] * HASH_MULTIPLIER_LO) & 0xffffffffu; key += argb[0] * kHashMultiplierLo;
key = key >> (32 - HASH_BITS); key = key >> (32 - HASH_BITS);
return key; return key;
} }

View File

@ -929,9 +929,8 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
} }
mappings = (int*) WebPSafeMalloc(*num_used, sizeof(*mappings)); mappings = (int*) WebPSafeMalloc(*num_used, sizeof(*mappings));
if (mappings == NULL || !HistoQueueInit(&histo_queue, kHistoQueueSize)) { if (mappings == NULL) return 0;
goto End; if (!HistoQueueInit(&histo_queue, kHistoQueueSize)) goto End;
}
// Fill the initial mapping. // Fill the initial mapping.
for (j = 0, iter = 0; iter < image_histo->size; ++iter) { for (j = 0, iter = 0; iter < image_histo->size; ++iter) {
if (histograms[iter] == NULL) continue; if (histograms[iter] == NULL) continue;

View File

@ -202,7 +202,7 @@ static uint32_t NearLossless(uint32_t value, uint32_t predict,
} }
if ((value >> 24) == 0 || (value >> 24) == 0xff) { if ((value >> 24) == 0 || (value >> 24) == 0xff) {
// Preserve transparency of fully transparent or fully opaque pixels. // Preserve transparency of fully transparent or fully opaque pixels.
a = NearLosslessDiff(value >> 24, predict >> 24); a = NearLosslessDiff((value >> 24) & 0xff, (predict >> 24) & 0xff);
} else { } else {
a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization); a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization);
} }
@ -215,12 +215,12 @@ static uint32_t NearLossless(uint32_t value, uint32_t predict,
// The amount by which green has been adjusted during quantization. It is // The amount by which green has been adjusted during quantization. It is
// subtracted from red and blue for compensation, to avoid accumulating two // subtracted from red and blue for compensation, to avoid accumulating two
// quantization errors in them. // quantization errors in them.
green_diff = NearLosslessDiff(new_green, value >> 8); green_diff = NearLosslessDiff(new_green, (value >> 8) & 0xff);
} }
r = NearLosslessComponent(NearLosslessDiff(value >> 16, green_diff), r = NearLosslessComponent(NearLosslessDiff((value >> 16) & 0xff, green_diff),
(predict >> 16) & 0xff, 0xff - new_green, (predict >> 16) & 0xff, 0xff - new_green,
quantization); quantization);
b = NearLosslessComponent(NearLosslessDiff(value, green_diff), b = NearLosslessComponent(NearLosslessDiff(value & 0xff, green_diff),
predict & 0xff, 0xff - new_green, quantization); predict & 0xff, 0xff - new_green, quantization);
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
} }
@ -587,7 +587,7 @@ static void GetBestGreenToRed(
} }
} }
} }
best_tx->green_to_red_ = green_to_red_best; best_tx->green_to_red_ = (green_to_red_best & 0xff);
} }
static float GetPredictionCostCrossColorBlue( static float GetPredictionCostCrossColorBlue(
@ -666,8 +666,8 @@ static void GetBestGreenRedToBlue(
break; // out of iter-loop. break; // out of iter-loop.
} }
} }
best_tx->green_to_blue_ = green_to_blue_best; best_tx->green_to_blue_ = green_to_blue_best & 0xff;
best_tx->red_to_blue_ = red_to_blue_best; best_tx->red_to_blue_ = red_to_blue_best & 0xff;
} }
#undef kGreenRedToBlueMaxIters #undef kGreenRedToBlueMaxIters
#undef kGreenRedToBlueNumAxis #undef kGreenRedToBlueNumAxis

View File

@ -33,7 +33,7 @@
// number of non-zero coeffs below which we consider the block very flat // number of non-zero coeffs below which we consider the block very flat
// (and apply a penalty to complex predictions) // (and apply a penalty to complex predictions)
#define FLATNESS_LIMIT_I16 10 // I16 mode #define FLATNESS_LIMIT_I16 0 // I16 mode (special case)
#define FLATNESS_LIMIT_I4 3 // I4 mode #define FLATNESS_LIMIT_I4 3 // I4 mode
#define FLATNESS_LIMIT_UV 2 // UV mode #define FLATNESS_LIMIT_UV 2 // UV mode
#define FLATNESS_PENALTY 140 // roughly ~1bit per block #define FLATNESS_PENALTY 140 // roughly ~1bit per block
@ -988,6 +988,7 @@ static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
VP8ModeScore* rd_cur = &rd_tmp; VP8ModeScore* rd_cur = &rd_tmp;
VP8ModeScore* rd_best = rd; VP8ModeScore* rd_best = rd;
int mode; int mode;
int is_flat = IsFlatSource16(it->yuv_in_ + Y_OFF_ENC);
rd->mode_i16 = -1; rd->mode_i16 = -1;
for (mode = 0; mode < NUM_PRED_MODES; ++mode) { for (mode = 0; mode < NUM_PRED_MODES; ++mode) {
@ -1003,10 +1004,14 @@ static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY)) : 0; tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY)) : 0;
rd_cur->H = VP8FixedCostsI16[mode]; rd_cur->H = VP8FixedCostsI16[mode];
rd_cur->R = VP8GetCostLuma16(it, rd_cur); rd_cur->R = VP8GetCostLuma16(it, rd_cur);
if (mode > 0 && if (is_flat) {
IsFlat(rd_cur->y_ac_levels[0], kNumBlocks, FLATNESS_LIMIT_I16)) { // refine the first impression (which was in pixel space)
// penalty to avoid flat area to be mispredicted by complex mode is_flat = IsFlat(rd_cur->y_ac_levels[0], kNumBlocks, FLATNESS_LIMIT_I16);
rd_cur->R += FLATNESS_PENALTY * kNumBlocks; if (is_flat) {
// Block is very flat. We put emphasis on the distortion being very low!
rd_cur->D *= 2;
rd_cur->SD *= 2;
}
} }
// Since we always examine Intra16 first, we can overwrite *rd directly. // Since we always examine Intra16 first, we can overwrite *rd directly.
@ -1087,7 +1092,8 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
: 0; : 0;
rd_tmp.H = mode_costs[mode]; rd_tmp.H = mode_costs[mode];
// Add flatness penalty // Add flatness penalty, to avoid flat area to be mispredicted
// by a complex mode.
if (mode > 0 && IsFlat(tmp_levels, kNumBlocks, FLATNESS_LIMIT_I4)) { if (mode > 0 && IsFlat(tmp_levels, kNumBlocks, FLATNESS_LIMIT_I4)) {
rd_tmp.R = FLATNESS_PENALTY * kNumBlocks; rd_tmp.R = FLATNESS_PENALTY * kNumBlocks;
} else { } else {
@ -1242,11 +1248,19 @@ static void RefineUsingDistortion(VP8EncIterator* const it,
if (mode > 0 && VP8FixedCostsI16[mode] > bit_limit) { if (mode > 0 && VP8FixedCostsI16[mode] > bit_limit) {
continue; continue;
} }
if (score < best_score) { if (score < best_score) {
best_mode = mode; best_mode = mode;
best_score = score; best_score = score;
} }
} }
if (it->x_ == 0 || it->y_ == 0) {
// avoid starting a checkerboard resonance from the border. See bug #432.
if (IsFlatSource16(src)) {
best_mode = (it->x_ == 0) ? 0 : 2;
try_both_modes = 0; // stick to i16
}
}
VP8SetIntra16Mode(it, best_mode); VP8SetIntra16Mode(it, best_mode);
// we'll reconstruct later, if i16 mode actually gets selected // we'll reconstruct later, if i16 mode actually gets selected
} }

View File

@ -32,7 +32,7 @@ extern "C" {
// version numbers // version numbers
#define ENC_MAJ_VERSION 1 #define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 0 #define ENC_MIN_VERSION 0
#define ENC_REV_VERSION 2 #define ENC_REV_VERSION 3
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost

View File

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

View File

@ -104,7 +104,8 @@ void VP8LoadNewBytes(VP8BitReader* const br) {
} }
// Read a bit with proba 'prob'. Speed-critical function! // Read a bit with proba 'prob'. Speed-critical function!
static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) { 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 // Don't move this declaration! It makes a big speed difference to store
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
// alter br->range_ value. // alter br->range_ value.
@ -129,13 +130,14 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
br->bits_ -= shift; br->bits_ -= shift;
} }
br->range_ = range - 1; br->range_ = range - 1;
BT_TRACK(br);
return bit; return bit;
} }
} }
// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here) // simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
int VP8GetSigned(VP8BitReader* const br, int v) { int VP8GetSigned(VP8BitReader* const br, int v, const char label[]) {
if (br->bits_ < 0) { if (br->bits_ < 0) {
VP8LoadNewBytes(br); VP8LoadNewBytes(br);
} }
@ -148,11 +150,13 @@ int VP8GetSigned(VP8BitReader* const br, int v) {
br->range_ += mask; br->range_ += mask;
br->range_ |= 1; br->range_ |= 1;
br->value_ -= (bit_t)((split + 1) & mask) << pos; br->value_ -= (bit_t)((split + 1) & mask) << pos;
BT_TRACK(br);
return (v ^ mask) - mask; return (v ^ mask) - mask;
} }
} }
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) { 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 // Don't move this declaration! It makes a big speed difference to store
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
// alter br->range_ value. // alter br->range_ value.
@ -179,6 +183,7 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
br->bits_ -= shift; br->bits_ -= shift;
} }
br->range_ = range; br->range_ = range;
BT_TRACK(br);
return bit; return bit;
} }
} }

View File

@ -102,17 +102,18 @@ void VP8LoadFinalBytes(VP8BitReader* const br) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Higher-level calls // Higher-level calls
uint32_t VP8GetValue(VP8BitReader* const br, int bits) { uint32_t VP8GetValue(VP8BitReader* const br, int bits, const char label[]) {
uint32_t v = 0; uint32_t v = 0;
while (bits-- > 0) { while (bits-- > 0) {
v |= VP8GetBit(br, 0x80) << bits; v |= VP8GetBit(br, 0x80, label) << bits;
} }
return v; return v;
} }
int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) { int32_t VP8GetSignedValue(VP8BitReader* const br, int bits,
const int value = VP8GetValue(br, bits); const char label[]) {
return VP8Get(br) ? -value : value; const int value = VP8GetValue(br, bits, label);
return VP8Get(br, label) ? -value : value;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -220,3 +221,78 @@ uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Bit-tracing tool
#if (BITTRACE > 0)
#include <stdlib.h> // for atexit()
#include <stdio.h>
#include <string.h>
#define MAX_NUM_LABELS 32
static struct {
const char* label;
int size;
int count;
} kLabels[MAX_NUM_LABELS];
static int last_label = 0;
static int last_pos = 0;
static const uint8_t* buf_start = NULL;
static int init_done = 0;
static void PrintBitTraces(void) {
int i;
int scale = 1;
int total = 0;
const char* units = "bits";
#if (BITTRACE == 2)
scale = 8;
units = "bytes";
#endif
for (i = 0; i < last_label; ++i) total += kLabels[i].size;
if (total < 1) total = 1; // avoid rounding errors
printf("=== Bit traces ===\n");
for (i = 0; i < last_label; ++i) {
const int skip = 16 - (int)strlen(kLabels[i].label);
const int value = (kLabels[i].size + scale - 1) / scale;
assert(skip > 0);
printf("%s \%*s: %6d %s \t[%5.2f%%] [count: %7d]\n",
kLabels[i].label, skip, "", value, units,
100.f * kLabels[i].size / total,
kLabels[i].count);
}
total = (total + scale - 1) / scale;
printf("Total: %d %s\n", total, units);
}
void BitTrace(const struct VP8BitReader* const br, const char label[]) {
int i, pos;
if (!init_done) {
memset(kLabels, 0, sizeof(kLabels));
atexit(PrintBitTraces);
buf_start = br->buf_;
init_done = 1;
}
pos = (int)(br->buf_ - buf_start) * 8 - br->bits_;
// if there's a too large jump, we've changed partition -> reset counter
if (abs(pos - last_pos) > 32) {
buf_start = br->buf_;
pos = 0;
last_pos = 0;
}
if (br->range_ >= 0x7f) pos += kVP8Log2Range[br->range_ - 0x7f];
for (i = 0; i < last_label; ++i) {
if (!strcmp(label, kLabels[i].label)) break;
}
if (i == MAX_NUM_LABELS) abort(); // overflow!
kLabels[i].label = label;
kLabels[i].size += pos - last_pos;
kLabels[i].count += 1;
if (i == last_label) ++last_label;
last_pos = pos;
}
#endif // BITTRACE > 0
//------------------------------------------------------------------------------

View File

@ -21,6 +21,27 @@
#endif #endif
#include "src/webp/types.h" #include "src/webp/types.h"
// Warning! This macro triggers quite some MACRO wizardry around func signature!
#if !defined(BITTRACE)
#define BITTRACE 0 // 0 = off, 1 = print bits, 2 = print bytes
#endif
#if (BITTRACE > 0)
struct VP8BitReader;
extern void BitTrace(const struct VP8BitReader* const br, const char label[]);
#define BT_TRACK(br) BitTrace(br, label)
#define VP8Get(BR, L) VP8GetValue(BR, 1, L)
#else
#define BT_TRACK(br)
// We'll REMOVE the 'const char label[]' from all signatures and calls (!!):
#define VP8GetValue(BR, N, L) VP8GetValue(BR, N)
#define VP8Get(BR, L) VP8GetValue(BR, 1, L)
#define VP8GetSignedValue(BR, N, L) VP8GetSignedValue(BR, N)
#define VP8GetBit(BR, P, L) VP8GetBit(BR, P)
#define VP8GetBitAlt(BR, P, L) VP8GetBitAlt(BR, P)
#define VP8GetSigned(BR, V, L) VP8GetSigned(BR, V)
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -92,17 +113,15 @@ void VP8BitReaderSetBuffer(VP8BitReader* const br,
void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset); void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset);
// return the next value made of 'num_bits' bits // return the next value made of 'num_bits' bits
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits); uint32_t VP8GetValue(VP8BitReader* const br, int num_bits, const char label[]);
static WEBP_INLINE uint32_t VP8Get(VP8BitReader* const br) {
return VP8GetValue(br, 1);
}
// return the next value with sign-extension. // return the next value with sign-extension.
int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits); int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits,
const char label[]);
// bit_reader_inl.h will implement the following methods: // bit_reader_inl.h will implement the following methods:
// static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) // static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob, ...)
// static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) // static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v, ...)
// and should be included by the .c files that actually need them. // and should be included by the .c files that actually need them.
// This is to avoid recompiling the whole library whenever this file is touched, // This is to avoid recompiling the whole library whenever this file is touched,
// and also allowing platform-specific ad-hoc hacks. // and also allowing platform-specific ad-hoc hacks.

View File

@ -70,7 +70,7 @@ static void Flush(VP8BitWriter* const bw) {
const int value = (bits & 0x100) ? 0x00 : 0xff; const int value = (bits & 0x100) ? 0x00 : 0xff;
for (; bw->run_ > 0; --bw->run_) bw->buf_[pos++] = value; for (; bw->run_ > 0; --bw->run_) bw->buf_[pos++] = value;
} }
bw->buf_[pos++] = bits; bw->buf_[pos++] = bits & 0xff;
bw->pos_ = pos; bw->pos_ = pos;
} else { } else {
bw->run_++; // delay writing of bytes 0xff, pending eventual carry. bw->run_++; // delay writing of bytes 0xff, pending eventual carry.

View File

@ -17,6 +17,7 @@
#include <assert.h> #include <assert.h>
#include "src/dsp/dsp.h"
#include "src/webp/types.h" #include "src/webp/types.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -30,10 +31,11 @@ typedef struct {
int hash_bits_; int hash_bits_;
} VP8LColorCache; } VP8LColorCache;
static const uint64_t kHashMul = 0x1e35a7bdull; static const uint32_t kHashMul = 0x1e35a7bdu;
static WEBP_INLINE int VP8LHashPix(uint32_t argb, int shift) { static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
return (int)(((argb * kHashMul) & 0xffffffffu) >> shift); int VP8LHashPix(uint32_t argb, int shift) {
return (int)((argb * kHashMul) >> shift);
} }
static WEBP_INLINE uint32_t VP8LColorCacheLookup( static WEBP_INLINE uint32_t VP8LColorCacheLookup(

View File

@ -91,7 +91,8 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
assert(code_lengths_size != 0); assert(code_lengths_size != 0);
assert(code_lengths != NULL); assert(code_lengths != NULL);
assert(root_table != NULL); assert((root_table != NULL && sorted != NULL) ||
(root_table == NULL && sorted == NULL));
assert(root_bits > 0); assert(root_bits > 0);
// Build histogram of code lengths. // Build histogram of code lengths.
@ -120,16 +121,22 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
for (symbol = 0; symbol < code_lengths_size; ++symbol) { for (symbol = 0; symbol < code_lengths_size; ++symbol) {
const int symbol_code_length = code_lengths[symbol]; const int symbol_code_length = code_lengths[symbol];
if (code_lengths[symbol] > 0) { if (code_lengths[symbol] > 0) {
sorted[offset[symbol_code_length]++] = symbol; if (sorted != NULL) {
sorted[offset[symbol_code_length]++] = symbol;
} else {
offset[symbol_code_length]++;
}
} }
} }
// Special case code with only one value. // Special case code with only one value.
if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) { if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) {
HuffmanCode code; if (sorted != NULL) {
code.bits = 0; HuffmanCode code;
code.value = (uint16_t)sorted[0]; code.bits = 0;
ReplicateValue(table, 1, total_size, code); code.value = (uint16_t)sorted[0];
ReplicateValue(table, 1, total_size, code);
}
return total_size; return total_size;
} }
@ -151,6 +158,7 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
if (num_open < 0) { if (num_open < 0) {
return 0; return 0;
} }
if (root_table == NULL) continue;
for (; count[len] > 0; --count[len]) { for (; count[len] > 0; --count[len]) {
HuffmanCode code; HuffmanCode code;
code.bits = (uint8_t)len; code.bits = (uint8_t)len;
@ -169,6 +177,7 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
if (num_open < 0) { if (num_open < 0) {
return 0; return 0;
} }
if (root_table == NULL) continue;
for (; count[len] > 0; --count[len]) { for (; count[len] > 0; --count[len]) {
HuffmanCode code; HuffmanCode code;
if ((key & mask) != low) { if ((key & mask) != low) {
@ -206,7 +215,10 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size) { const int code_lengths[], int code_lengths_size) {
int total_size; int total_size;
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE); assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
if (code_lengths_size <= SORTED_SIZE_CUTOFF) { if (root_table == NULL) {
total_size = BuildHuffmanTable(NULL, root_bits,
code_lengths, code_lengths_size, NULL);
} else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
// use local stack-allocated array. // use local stack-allocated array.
uint16_t sorted[SORTED_SIZE_CUTOFF]; uint16_t sorted[SORTED_SIZE_CUTOFF];
total_size = BuildHuffmanTable(root_table, root_bits, total_size = BuildHuffmanTable(root_table, root_bits,

View File

@ -78,6 +78,8 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
// the huffman table. // the huffman table.
// Returns built table size or 0 in case of error (invalid tree or // Returns built table size or 0 in case of error (invalid tree or
// memory error). // 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(HuffmanCode* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size); const int code_lengths[], int code_lengths_size);

View File

@ -84,14 +84,14 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
int height = *scaled_height; int height = *scaled_height;
// if width is unspecified, scale original proportionally to height ratio. // if width is unspecified, scale original proportionally to height ratio.
if (width == 0) { if (width == 0 && src_height > 0) {
width = width =
(int)(((uint64_t)src_width * height + src_height / 2) / src_height); (int)(((uint64_t)src_width * height + src_height - 1) / src_height);
} }
// if height is unspecified, scale original proportionally to width ratio. // if height is unspecified, scale original proportionally to width ratio.
if (height == 0) { if (height == 0 && src_width > 0) {
height = height =
(int)(((uint64_t)src_height * width + src_width / 2) / src_width); (int)(((uint64_t)src_height * width + src_width - 1) / src_width);
} }
// Check if the overall dimensions still make sense. // Check if the overall dimensions still make sense.
if (width <= 0 || height <= 0) { if (width <= 0 || height <= 0) {

View File

@ -217,8 +217,12 @@ static THREADFN ThreadLoop(void* ptr) {
done = 1; done = 1;
} }
// signal to the main thread that we're done (for Sync()) // signal to the main thread that we're done (for Sync())
pthread_cond_signal(&impl->condition_); // Note the associated mutex does not need to be held when signaling the
// condition. Unlocking the mutex first may improve performance in some
// implementations, avoiding the case where the waiting thread can't
// reacquire the mutex when woken.
pthread_mutex_unlock(&impl->mutex_); pthread_mutex_unlock(&impl->mutex_);
pthread_cond_signal(&impl->condition_);
} }
return THREAD_RETURN(NULL); // Thread is finished return THREAD_RETURN(NULL); // Thread is finished
} }
@ -240,7 +244,13 @@ static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) {
// assign new status and release the working thread if needed // assign new status and release the working thread if needed
if (new_status != OK) { if (new_status != OK) {
worker->status_ = new_status; worker->status_ = new_status;
// Note the associated mutex does not need to be held when signaling the
// condition. Unlocking the mutex first may improve performance in some
// implementations, avoiding the case where the waiting thread can't
// reacquire the mutex when woken.
pthread_mutex_unlock(&impl->mutex_);
pthread_cond_signal(&impl->condition_); pthread_cond_signal(&impl->condition_);
return;
} }
} }
pthread_mutex_unlock(&impl->mutex_); pthread_mutex_unlock(&impl->mutex_);

View File

@ -92,14 +92,14 @@ static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) {
// Store 16, 24 or 32 bits in little-endian order. // Store 16, 24 or 32 bits in little-endian order.
static WEBP_INLINE void PutLE16(uint8_t* const data, int val) { static WEBP_INLINE void PutLE16(uint8_t* const data, int val) {
assert(val < (1 << 16)); assert(val < (1 << 16));
data[0] = (val >> 0); data[0] = (val >> 0) & 0xff;
data[1] = (val >> 8); data[1] = (val >> 8) & 0xff;
} }
static WEBP_INLINE void PutLE24(uint8_t* const data, int val) { static WEBP_INLINE void PutLE24(uint8_t* const data, int val) {
assert(val < (1 << 24)); assert(val < (1 << 24));
PutLE16(data, val & 0xffff); PutLE16(data, val & 0xffff);
data[2] = (val >> 16); data[2] = (val >> 16) & 0xff;
} }
static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) { static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {

View File

@ -81,7 +81,7 @@
#define PACKAGE_NAME "libwebp" #define PACKAGE_NAME "libwebp"
/* Define to the full name and version of this package. */ /* Define to the full name and version of this package. */
#define PACKAGE_STRING "libwebp 1.0.2" #define PACKAGE_STRING "libwebp 1.0.3"
/* Define to the one symbol short name of this package. */ /* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libwebp" #define PACKAGE_TARNAME "libwebp"
@ -90,7 +90,7 @@
#define PACKAGE_URL "http://developers.google.com/speed/webp" #define PACKAGE_URL "http://developers.google.com/speed/webp"
/* Define to the version of this package. */ /* Define to the version of this package. */
#define PACKAGE_VERSION "1.0.2" #define PACKAGE_VERSION "1.0.3"
/* Define to necessary symbol if this constant uses a non-standard name on /* Define to necessary symbol if this constant uses a non-standard name on
your system. */ your system. */
@ -100,7 +100,7 @@
/* #undef STDC_HEADERS */ /* #undef STDC_HEADERS */
/* Version number of package */ /* Version number of package */
#define VERSION "1.0.2" #define VERSION "1.0.3"
/* Enable experimental code */ /* Enable experimental code */
/* #undef WEBP_EXPERIMENTAL_FEATURES */ /* #undef WEBP_EXPERIMENTAL_FEATURES */

View File

@ -62,6 +62,10 @@ WEBP_EXTERN size_t WebPEncodeBGRA(const uint8_t* bgra,
// These functions are the equivalent of the above, but compressing in a // These functions are the equivalent of the above, but compressing in a
// lossless manner. Files are usually larger than lossy format, but will // lossless manner. Files are usually larger than lossy format, but will
// not suffer any compression loss. // not suffer any compression loss.
// Note these functions, like the lossy versions, use the library's default
// settings. For lossless this means 'exact' is disabled. RGB values in
// transparent areas will be modified to improve compression. To avoid this,
// use WebPEncode() and set WebPConfig::exact to 1.
WEBP_EXTERN size_t WebPEncodeLosslessRGB(const uint8_t* rgb, WEBP_EXTERN size_t WebPEncodeLosslessRGB(const uint8_t* rgb,
int width, int height, int stride, int width, int height, int stride,
uint8_t** output); uint8_t** output);