Update libwebp to version 1.0.2

This resolves #939.
This commit is contained in:
wolfbeast 2019-01-21 13:09:32 +01:00 • committed by Roy Tam
commit 072fbe1a93
46 changed files with 395 additions and 173 deletions

View file

@ -1,4 +1,5 @@
Contributors: Contributors:
- 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)
- Djordje Pesut (djordje dot pesut at imgtec dot com) - Djordje Pesut (djordje dot pesut at imgtec dot com)
@ -6,9 +7,10 @@ Contributors:
- James Zern (jzern at google dot com) - James Zern (jzern at google dot com)
- Jan Engelhardt (jengelh at medozas dot de) - Jan Engelhardt (jengelh at medozas dot de)
- Jehan (jehan at girinstud dot io) - Jehan (jehan at girinstud dot io)
- Johann (johann dot koenig at duck dot com) - Johann Koenig (johann dot koenig at duck dot com)
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com) - Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
- Jyrki Alakuijala (jyrki at google dot com) - Jyrki Alakuijala (jyrki at google dot com)
- Konstantin Ivlev (tomskside at gmail dot com)
- Lode Vandevenne (lode at google dot com) - Lode Vandevenne (lode at google dot com)
- Lou Quillio (louquillio at google dot com) - Lou Quillio (louquillio at google dot com)
- Mans Rullgard (mans at mansr dot com) - Mans Rullgard (mans at mansr dot com)
@ -37,3 +39,4 @@ Contributors:
- Vincent Rabaud (vrabaud at google dot com) - Vincent Rabaud (vrabaud at google dot com)
- Vlad Tsyrklevich (vtsyrklevich at chromium dot org) - Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
- Yang Zhang (yang dot zhang at arm dot com) - Yang Zhang (yang dot zhang at arm dot com)
- Yannis Guyon (yguyon at google dot com)

View file

@ -1,3 +1,23 @@
- 1/14/2019: version 1.0.2
This is a binary compatible release.
* (Windows) unicode file support in the tools (linux and mac already had
support, issue #398)
* lossless encoder speedups
* lossy encoder speedup on ARM
* lossless multi-threaded security fix (chromium:917029)
- 11/2/2018: version 1.0.1
This is a binary compatible release.
* lossless encoder speedups
* big-endian fix for alpha decoding (issue #393)
* gif2webp fix for loop count=65535 transcode (issue #382)
* further security related hardening in libwebp & libwebpmux
(issues #383, #385, #386, #387, #388, #391)
(oss-fuzz #9099, #9100, #9105, #9106, #9111, #9112, #9119, #9123, #9170,
#9178, #9179, #9183, #9186, #9191, #9364, #9417, #9496, #10349,
#10423, #10634, #10700, #10838, #10922, #11021, #11088, #11152)
* miscellaneous bug & build fixes (issues #381, #394, #396, #397, #400)
- 4/2/2018: version 1.0.0 - 4/2/2018: version 1.0.0
This is a binary compatible release. This is a binary compatible release.
* lossy encoder improvements to avoid chroma shifts in various circumstances * lossy encoder improvements to avoid chroma shifts in various circumstances

View file

@ -4,7 +4,7 @@
\__\__/\____/\_____/__/ ____ ___ \__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/ / _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__ / \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v1.0.0 \____/____/\_____/_____/____/v1.0.2
Description: Description:
============ ============
@ -136,6 +136,8 @@ cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
or through your favorite interface (like ccmake or cmake-qt-gui). or through your favorite interface (like ccmake or cmake-qt-gui).
Use option -DWEBP_UNICODE=ON for Unicode support on Windows (with chcp 65001).
Finally, once installed, you can also use WebP in your CMake project by doing: Finally, once installed, you can also use WebP in your CMake project by doing:
find_package(WebP) find_package(WebP)
@ -402,12 +404,14 @@ Options are:
-nofilter .... disable in-loop filtering -nofilter .... disable in-loop filtering
-dither <int> dithering strength (0..100), default=50 -dither <int> dithering strength (0..100), default=50
-noalphadither disable alpha plane dithering -noalphadither disable alpha plane dithering
-usebgcolor .. display background color
-mt .......... use multi-threading -mt .......... use multi-threading
-info ........ print info -info ........ print info
-h ........... this help message -h ........... this help message
Keyboard shortcuts: Keyboard shortcuts:
'c' ................ toggle use of color profile 'c' ................ toggle use of color profile
'b' ................ toggle background color display
'i' ................ overlay file information 'i' ................ overlay file information
'd' ................ disable blending & disposal (debug) 'd' ................ disable blending & disposal (debug)
'q' / 'Q' / ESC .... quit 'q' / 'Q' / ESC .... quit
@ -470,6 +474,9 @@ Per-frame options (only used for subsequent images input):
example: img2webp -loop 2 in0.png -lossy in1.jpg example: img2webp -loop 2 in0.png -lossy in1.jpg
-d 80 in2.tiff -o out.webp -d 80 in2.tiff -o out.webp
Note: if a single file name is passed as the argument, the arguments will be
tokenized from this file. The file name must not start with the character '-'.
Animated GIF conversion: Animated GIF conversion:
======================== ========================
Animated GIF files can be converted to WebP files with animation using the Animated GIF files can be converted to WebP files with animation using the

View file

@ -1,7 +1,7 @@
 __ __ ____ ____ ____ __ __ _ __ __  __ __ ____ ____ ____ __ __ _ __ __
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\ / \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
\ / __/ _ \ __/ / / (_/ /__ \ / __/ _ \ __/ / / (_/ /__
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.0 \__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.2
Description: Description:
@ -211,6 +211,35 @@ Code example:
For a detailed AnimEncoder API reference, please refer to the header file For a detailed AnimEncoder API reference, please refer to the header file
(src/webp/mux.h). (src/webp/mux.h).
AnimDecoder API:
================
This AnimDecoder API allows decoding (possibly) animated WebP images.
Code Example:
WebPAnimDecoderOptions dec_options;
WebPAnimDecoderOptionsInit(&dec_options);
// Tune 'dec_options' as needed.
WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options);
WebPAnimInfo anim_info;
WebPAnimDecoderGetInfo(dec, &anim_info);
for (uint32_t i = 0; i < anim_info.loop_count; ++i) {
while (WebPAnimDecoderHasMoreFrames(dec)) {
uint8_t* buf;
int timestamp;
WebPAnimDecoderGetNext(dec, &buf, &timestamp);
// ... (Render 'buf' based on 'timestamp').
// ... (Do NOT free 'buf', as it is owned by 'dec').
}
WebPAnimDecoderReset(dec);
}
const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec);
// ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data).
WebPAnimDecoderDelete(dec);
For a detailed AnimDecoder API reference, please refer to the header file
(src/webp/demux.h).
Bugs: Bugs:
===== =====

View file

@ -2,3 +2,4 @@ Changes made to pristine libwebp source by Moonchild Productions and mozilla.org
2017/01/27 -- Synced with libwebp-0.6.0 (BZ #1294490). 2017/01/27 -- Synced with libwebp-0.6.0 (BZ #1294490).
2018/06/29 -- Synced with libwebp-1.0.0 + BUG=webp:381,383,384. 2018/06/29 -- Synced with libwebp-1.0.0 + BUG=webp:381,383,384.
2019/01/21 -- Synced with libwebp-1.0.2

View file

@ -51,4 +51,4 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_ALPHAI_DEC_H_ */ #endif // WEBP_DEC_ALPHAI_DEC_H_

View file

@ -338,7 +338,6 @@ void VP8InitDithering(const WebPDecoderOptions* const options,
for (s = 0; s < NUM_MB_SEGMENTS; ++s) { for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
VP8QuantMatrix* const dqm = &dec->dqm_[s]; VP8QuantMatrix* const dqm = &dec->dqm_[s];
if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) { if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) {
// TODO(skal): should we specially dither more for uv_quant_ < 0?
const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_; const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_;
dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3; dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3;
} }
@ -669,15 +668,9 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
(void)height; (void)height;
assert(headers == NULL || !headers->is_lossless); assert(headers == NULL || !headers->is_lossless);
#if defined(WEBP_USE_THREAD) #if defined(WEBP_USE_THREAD)
if (width < MIN_WIDTH_FOR_THREADS) return 0; if (width >= MIN_WIDTH_FOR_THREADS) return 2;
// TODO(skal): tune the heuristic further
#if 0
if (height < 2 * width) return 2;
#endif #endif
return 2;
#else // !WEBP_USE_THREAD
return 0; return 0;
#endif
} }
#undef MT_CACHE_LINES #undef MT_CACHE_LINES

View file

@ -140,10 +140,9 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
if (NeedCompressedAlpha(idec)) { if (NeedCompressedAlpha(idec)) {
ALPHDecoder* const alph_dec = dec->alph_dec_; ALPHDecoder* const alph_dec = dec->alph_dec_;
dec->alpha_data_ += offset; dec->alpha_data_ += offset;
if (alph_dec != NULL) { if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) {
if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) {
VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_;
assert(alph_vp8l_dec != NULL);
assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN); assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN);
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_, VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_,
dec->alpha_data_ + ALPHA_HEADER_LEN, dec->alpha_data_ + ALPHA_HEADER_LEN,
@ -449,7 +448,10 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_; VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8Io* const io = &idec->io_; VP8Io* const io = &idec->io_;
assert(dec->ready_); // Make sure partition #0 has been read before, to set dec to ready_.
if (!dec->ready_) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
if (idec->last_mb_y_ != dec->mb_y_) { if (idec->last_mb_y_ != dec->mb_y_) {
if (!VP8ParseIntraModeRow(&dec->br_, dec)) { if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
@ -471,6 +473,12 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
MemDataSize(&idec->mem_) > MAX_MB_SIZE) { MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
} }
// Synchronize the threads.
if (dec->mt_method_ > 0) {
if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
}
RestoreContext(&context, dec, token_br); RestoreContext(&context, dec, token_br);
return VP8_STATUS_SUSPENDED; return VP8_STATUS_SUSPENDED;
} }
@ -489,6 +497,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
} }
// Synchronize the thread and check for errors. // Synchronize the thread and check for errors.
if (!VP8ExitCritical(dec, io)) { if (!VP8ExitCritical(dec, io)) {
idec->state_ = STATE_ERROR; // prevent re-entry in IDecError
return IDecError(idec, VP8_STATUS_USER_ABORT); return IDecError(idec, VP8_STATUS_USER_ABORT);
} }
dec->ready_ = 0; dec->ready_ = 0;
@ -569,6 +578,10 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
status = DecodePartition0(idec); status = DecodePartition0(idec);
} }
if (idec->state_ == STATE_VP8_DATA) { if (idec->state_ == STATE_VP8_DATA) {
const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
if (dec == NULL) {
return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
}
status = DecodeRemaining(idec); status = DecodeRemaining(idec);
} }
if (idec->state_ == STATE_VP8L_HEADER) { if (idec->state_ == STATE_VP8L_HEADER) {

View file

@ -182,4 +182,4 @@ WEBP_EXTERN int VP8LGetInfo(
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_VP8_DEC_H_ */ #endif // WEBP_DEC_VP8_DEC_H_

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 0 #define DEC_REV_VERSION 2
// 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),
@ -316,4 +316,4 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_VP8I_DEC_H_ */ #endif // WEBP_DEC_VP8I_DEC_H_

View file

@ -359,17 +359,22 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int color_cache_bits, int allow_recursion) { int color_cache_bits, int allow_recursion) {
int i, j; int i, j;
VP8LBitReader* const br = &dec->br_; VP8LBitReader* const br = &dec->br_;
VP8LBitReader br_tmp;
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* next = NULL; HuffmanCode* next = NULL;
int num_htree_groups = 1; int num_htree_groups = 1;
int num_htree_groups_limit = 1; int num_htree_groups_max = 1;
int max_alphabet_size = 0; int max_alphabet_size = 0;
int* code_lengths = NULL; int* code_lengths = NULL;
const int table_size = kTableSize[color_cache_bits]; const int table_size = kTableSize[color_cache_bits];
int* mapping = NULL;
int ok = 0;
if (allow_recursion && VP8LReadBits(br, 1)) { if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes. // use meta Huffman codes.
@ -386,21 +391,41 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
// The huffman data is stored in red and green bytes. // The huffman data is stored in red and green bytes.
const int group = (huffman_image[i] >> 8) & 0xffff; const int group = (huffman_image[i] >> 8) & 0xffff;
huffman_image[i] = group; huffman_image[i] = group;
if (group >= num_htree_groups) { if (group >= num_htree_groups_max) {
num_htree_groups = group + 1; num_htree_groups_max = group + 1;
} }
} }
// Check the validity of num_htree_groups. If it seems too big, use a // Check the validity of num_htree_groups_max. If it seems too big, use a
// smaller value for later. This will prevent big memory allocations to end // smaller value for later. This will prevent big memory allocations to end
// up with a bad bitstream anyway. // up with a bad bitstream anyway.
// The value of 1000 is totally arbitrary. We know that num_htree_groups // The value of 1000 is totally arbitrary. We know that num_htree_groups_max
// is smaller than (1 << 16) and should be smaller than the number of pixels // is smaller than (1 << 16) and should be smaller than the number of pixels
// (though the format allows it to be bigger). // (though the format allows it to be bigger).
if (num_htree_groups > 1000 || num_htree_groups > xsize * ysize) { if (num_htree_groups_max > 1000 || num_htree_groups_max > xsize * ysize) {
num_htree_groups_limit = (xsize * ysize > 1000) ? 1000 : xsize * ysize; // Create a mapping from the used indices to the minimal set of used
br_tmp = dec->br_; // values [0, num_htree_groups)
mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
if (mapping == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
// -1 means a value is unmapped, and therefore unused in the Huffman
// image.
memset(mapping, 0xff, num_htree_groups_max * sizeof(*mapping));
for (num_htree_groups = 0, i = 0; i < huffman_pixs; ++i) {
// Get the current mapping for the group and remap the Huffman image.
int* const mapped_group = &mapping[huffman_image[i]];
if (*mapped_group == -1) *mapped_group = num_htree_groups++;
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_limit = num_htree_groups; num_htree_groups = num_htree_groups_max;
} }
} }
@ -419,46 +444,45 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
sizeof(*code_lengths)); sizeof(*code_lengths));
// If num_htree_groups_tmp == num_htree_groups, the following loop is executed huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
// once. sizeof(*huffman_tables));
// If num_htree_groups_tmp != num_htree_groups, we execute the loop the first htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
// time with little memory allocation in the hope that there is a bitstream
// error. If after num_htree_groups_tmp iterations, no error appears,
// num_htree_groups is probably the right value so try it out.
do {
huffman_tables = (HuffmanCode*)WebPSafeMalloc(
num_htree_groups_limit * table_size, sizeof(*huffman_tables));
htree_groups = VP8LHtreeGroupsNew(num_htree_groups_limit);
if (htree_groups == NULL || code_lengths == NULL || if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
huffman_tables == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY; dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error; goto Error;
} }
next = huffman_tables; next = huffman_tables;
for (i = 0; i < num_htree_groups_limit; ++i) { for (i = 0; i < num_htree_groups_max; ++i) {
HTreeGroup* const htree_group = &htree_groups[i]; // If the index "i" is unused in the Huffman image, read the coefficients
// but store them to a bogus htree_group.
const int is_bogus = (mapping != NULL && mapping[i] == -1);
HTreeGroup* const htree_group =
is_bogus ? &htree_group_bogus :
&htree_groups[(mapping == NULL) ? i : mapping[i]];
HuffmanCode** const htrees = htree_group->htrees; HuffmanCode** const htrees = htree_group->htrees;
HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next;
int size; int size;
int total_size = 0; int total_size = 0;
int is_trivial_literal = 1; int is_trivial_literal = 1;
int max_bits = 0; int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j]; int alphabet_size = kAlphabetSize[j];
htrees[j] = next; htrees[j] = huffman_tables_i;
if (j == 0 && color_cache_bits > 0) { if (j == 0 && color_cache_bits > 0) {
alphabet_size += 1 << color_cache_bits; alphabet_size += 1 << color_cache_bits;
} }
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next); size =
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i);
if (size == 0) { if (size == 0) {
goto Error; goto Error;
} }
if (is_trivial_literal && kLiteralMap[j] == 1) { if (is_trivial_literal && kLiteralMap[j] == 1) {
is_trivial_literal = (next->bits == 0); is_trivial_literal = (huffman_tables_i->bits == 0);
} }
total_size += next->bits; total_size += huffman_tables_i->bits;
next += size; huffman_tables_i += size;
if (j <= ALPHA) { if (j <= ALPHA) {
int local_max_bits = code_lengths[0]; int local_max_bits = code_lengths[0];
int k; int k;
@ -470,6 +494,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
max_bits += local_max_bits; max_bits += local_max_bits;
} }
} }
if (!is_bogus) next = huffman_tables_i;
htree_group->is_trivial_literal = is_trivial_literal; htree_group->is_trivial_literal = is_trivial_literal;
htree_group->is_trivial_code = 0; htree_group->is_trivial_code = 0;
if (is_trivial_literal) { if (is_trivial_literal) {
@ -486,32 +511,24 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
!htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS); !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
if (htree_group->use_packed_table) BuildPackedTable(htree_group); if (htree_group->use_packed_table) BuildPackedTable(htree_group);
} }
// If we have survived up to here, num_htree_groups might actually be ok = 1;
// that big so restart with a proper allocation.
if (num_htree_groups != num_htree_groups_limit) {
num_htree_groups_limit = num_htree_groups;
WebPSafeFree(huffman_tables);
VP8LHtreeGroupsFree(htree_groups);
huffman_tables = NULL;
htree_groups = NULL;
dec->br_ = br_tmp;
}
} while (i != num_htree_groups);
WebPSafeFree(code_lengths);
// All OK. Finalize pointers and return. // All OK. Finalize pointers.
hdr->huffman_image_ = huffman_image; hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups; hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups; hdr->htree_groups_ = htree_groups;
hdr->huffman_tables_ = huffman_tables; hdr->huffman_tables_ = huffman_tables;
return 1;
Error: Error:
WebPSafeFree(code_lengths); WebPSafeFree(code_lengths);
WebPSafeFree(huffman_tables_bogus);
WebPSafeFree(mapping);
if (!ok) {
WebPSafeFree(huffman_image); WebPSafeFree(huffman_image);
WebPSafeFree(huffman_tables); WebPSafeFree(huffman_tables);
VP8LHtreeGroupsFree(htree_groups); VP8LHtreeGroupsFree(htree_groups);
return 0; }
return ok;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -916,7 +933,11 @@ static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) {
#endif #endif
break; break;
case 2: case 2:
#if !defined(WORDS_BIGENDIAN)
memcpy(&pattern, src, sizeof(uint16_t)); memcpy(&pattern, src, sizeof(uint16_t));
#else
pattern = ((uint32_t)src[0] << 8) | src[1];
#endif
#if defined(__arm__) || defined(_M_ARM) #if defined(__arm__) || defined(_M_ARM)
pattern |= pattern << 16; pattern |= pattern << 16;
#elif defined(WEBP_USE_MIPS_DSP_R2) #elif defined(WEBP_USE_MIPS_DSP_R2)
@ -1555,7 +1576,6 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
if (dec == NULL) return 0; if (dec == NULL) return 0;
assert(alph_dec != NULL); assert(alph_dec != NULL);
alph_dec->vp8l_dec_ = dec;
dec->width_ = alph_dec->width_; dec->width_ = alph_dec->width_;
dec->height_ = alph_dec->height_; dec->height_ = alph_dec->height_;
@ -1587,11 +1607,12 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
if (!ok) goto Err; if (!ok) goto Err;
// Only set here, once we are sure it is valid (to avoid thread races).
alph_dec->vp8l_dec_ = dec;
return 1; return 1;
Err: Err:
VP8LDelete(alph_dec->vp8l_dec_); VP8LDelete(dec);
alph_dec->vp8l_dec_ = NULL;
return 0; return 0;
} }

View file

@ -132,4 +132,4 @@ void VP8LDelete(VP8LDecoder* const dec);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_VP8LI_DEC_H_ */ #endif // WEBP_DEC_VP8LI_DEC_H_

View file

@ -130,4 +130,4 @@ int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_WEBPI_DEC_H_ */ #endif // WEBP_DEC_WEBPI_DEC_H_

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 0 #define DMUX_REV_VERSION 2
typedef struct { typedef struct {
size_t start_; // start location of the data size_t start_; // start location of the data

View file

@ -76,10 +76,6 @@ extern "C" {
#define WEBP_USE_SSE41 #define WEBP_USE_SSE41
#endif #endif
#if defined(__AVX2__) || defined(WEBP_HAVE_AVX2)
#define WEBP_USE_AVX2
#endif
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the // The intrinsics currently cause compiler errors with arm-nacl-gcc and the
// inline assembly would need to be modified for use with Native Client. // inline assembly would need to be modified for use with Native Client.
#if (defined(__ARM_NEON__) || \ #if (defined(__ARM_NEON__) || \
@ -679,4 +675,4 @@ void VP8FiltersInit(void);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DSP_DSP_H_ */ #endif // WEBP_DSP_DSP_H_

View file

@ -23,8 +23,6 @@
#include "../dsp/lossless.h" #include "../dsp/lossless.h"
#include "../dsp/lossless_common.h" #include "../dsp/lossless_common.h"
#define MAX_DIFF_COST (1e30f)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Image transforms. // Image transforms.

View file

@ -163,7 +163,7 @@ extern VP8LCostCombinedFunc VP8LExtraCostCombined;
extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy;
typedef struct { // small struct to hold counters typedef struct { // small struct to hold counters
int counts[2]; // index: 0=zero steak, 1=non-zero streak int counts[2]; // index: 0=zero streak, 1=non-zero streak
int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3] int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3]
} VP8LStreaks; } VP8LStreaks;
@ -194,10 +194,14 @@ extern VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined;
void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n,
VP8LBitEntropy* const entropy); VP8LBitEntropy* const entropy);
typedef void (*VP8LHistogramAddFunc)(const VP8LHistogram* const a, typedef void (*VP8LAddVectorFunc)(const uint32_t* a, const uint32_t* b,
uint32_t* out, int size);
extern VP8LAddVectorFunc VP8LAddVector;
typedef void (*VP8LAddVectorEqFunc)(const uint32_t* a, uint32_t* out, int size);
extern VP8LAddVectorEqFunc VP8LAddVectorEq;
void VP8LHistogramAdd(const VP8LHistogram* const a,
const VP8LHistogram* const b, const VP8LHistogram* const b,
VP8LHistogram* const out); VP8LHistogram* const out);
extern VP8LHistogramAddFunc VP8LHistogramAdd;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// PrefixEncode() // PrefixEncode()

View file

@ -1389,4 +1389,4 @@ static WEBP_INLINE uint32_t func_hadd_uh_u32(v8u16 in) {
} while (0) } while (0)
#define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__) #define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__)
#endif /* WEBP_DSP_MSA_MACRO_H_ */ #endif // WEBP_DSP_MSA_MACRO_H_

70
media/libwebp/dsp/quant.h Normal file
View file

@ -0,0 +1,70 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
#ifndef WEBP_DSP_QUANT_H_
#define WEBP_DSP_QUANT_H_
#include "../dsp/dsp.h"
#include "../webp/types.h"
#if defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) && \
!defined(WEBP_HAVE_NEON_RTCD)
#include <arm_neon.h>
#define IsFlat IsFlat_NEON
static uint32x2_t horizontal_add_uint32x4(const uint32x4_t a) {
const uint64x2_t b = vpaddlq_u32(a);
return vadd_u32(vreinterpret_u32_u64(vget_low_u64(b)),
vreinterpret_u32_u64(vget_high_u64(b)));
}
static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
int thresh) {
const int16x8_t tst_ones = vdupq_n_s16(-1);
uint32x4_t sum = vdupq_n_u32(0);
for (int i = 0; i < num_blocks; ++i) {
// Set DC to zero.
const int16x8_t a_0 = vsetq_lane_s16(0, vld1q_s16(levels), 0);
const int16x8_t a_1 = vld1q_s16(levels + 8);
const uint16x8_t b_0 = vshrq_n_u16(vtstq_s16(a_0, tst_ones), 15);
const uint16x8_t b_1 = vshrq_n_u16(vtstq_s16(a_1, tst_ones), 15);
sum = vpadalq_u16(sum, b_0);
sum = vpadalq_u16(sum, b_1);
levels += 16;
}
return thresh >= (int32_t)vget_lane_u32(horizontal_add_uint32x4(sum), 0);
}
#else
#define IsFlat IsFlat_C
static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
int thresh) {
int score = 0;
while (num_blocks-- > 0) { // TODO(skal): refine positional scoring?
int i;
for (i = 1; i < 16; ++i) { // omit DC, we're only interested in AC
score += (levels[i] != 0);
if (score > thresh) return 0;
}
levels += 16;
}
return 1;
}
#endif // defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) &&
// !defined(WEBP_HAVE_NEON_RTCD)
#endif // WEBP_DSP_QUANT_H_

View file

@ -21,6 +21,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1) #define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Row import // Row import
@ -138,7 +139,7 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
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(frow[x_out], yscale);
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255); assert(v >= 0 && v <= 255);
dst[x_out] = v; dst[x_out] = v;
irow[x_out] = frac; // new fractional start irow[x_out] = frac; // new fractional start
@ -153,6 +154,7 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
} }
} }
#undef MULT_FIX_FLOOR
#undef MULT_FIX #undef MULT_FIX
#undef ROUNDER #undef ROUNDER

View file

@ -22,6 +22,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1) #define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) #define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
#define MULT_FIX_FLOOR_C(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
#define LOAD_32x4(SRC, DST) const uint32x4_t DST = vld1q_u32((SRC)) #define LOAD_32x4(SRC, DST) const uint32x4_t DST = vld1q_u32((SRC))
#define LOAD_32x8(SRC, DST0, DST1) \ #define LOAD_32x8(SRC, DST0, DST1) \
@ -35,8 +36,11 @@
#if (WEBP_RESCALER_RFIX == 32) #if (WEBP_RESCALER_RFIX == 32)
#define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1)) #define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1))
#define MULT_FIX(A, B) /* note: B is actualy scale>>1. See MAKE_HALF_CST */ \ // note: B is actualy scale>>1. See MAKE_HALF_CST
#define MULT_FIX(A, B) \
vreinterpretq_u32_s32(vqrdmulhq_s32(vreinterpretq_s32_u32((A)), (B))) vreinterpretq_u32_s32(vqrdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
#define MULT_FIX_FLOOR(A, B) \
vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
#else #else
#error "MULT_FIX/WEBP_RESCALER_RFIX need some more work" #error "MULT_FIX/WEBP_RESCALER_RFIX need some more work"
#endif #endif
@ -135,8 +139,8 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
const uint32x4_t A1 = MULT_FIX(in1, yscale_half); const uint32x4_t A1 = MULT_FIX(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(B0, fxy_scale_half); const uint32x4_t C0 = MULT_FIX_FLOOR(B0, fxy_scale_half);
const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half); const uint32x4_t C1 = MULT_FIX_FLOOR(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 = vmovn_u16(vcombine_u16(D0, D1));
@ -145,7 +149,7 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
} }
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_C(frow[x_out], yscale);
const int v = (int)MULT_FIX_C(irow[x_out] - frac, wrk->fxy_scale); const int v = (int)MULT_FIX_FLOOR_C(irow[x_out] - frac, fxy_scale);
assert(v >= 0 && v <= 255); assert(v >= 0 && v <= 255);
dst[x_out] = v; dst[x_out] = v;
irow[x_out] = frac; // new fractional start irow[x_out] = frac; // new fractional start
@ -170,6 +174,12 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
} }
} }
#undef MULT_FIX_FLOOR_C
#undef MULT_FIX_C
#undef MULT_FIX_FLOOR
#undef MULT_FIX
#undef ROUNDER
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
extern void WebPRescalerDspInitNEON(void); extern void WebPRescalerDspInitNEON(void);

View file

@ -25,6 +25,7 @@
#define ROUNDER (WEBP_RESCALER_ONE >> 1) #define ROUNDER (WEBP_RESCALER_ONE >> 1)
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
// input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0 // input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0
static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) { static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) {
@ -224,6 +225,35 @@ 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;
@ -322,12 +352,12 @@ 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_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out); ProcessRow_Floor_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(frow[x_out], yscale);
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
assert(v >= 0 && v <= 255); assert(v >= 0 && v <= 255);
dst[x_out] = v; dst[x_out] = v;
irow[x_out] = frac; // new fractional start irow[x_out] = frac; // new fractional start
@ -352,6 +382,7 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
} }
} }
#undef MULT_FIX_FLOOR
#undef MULT_FIX #undef MULT_FIX
#undef ROUNDER #undef ROUNDER

View file

@ -207,4 +207,4 @@ static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DSP_YUV_H_ */ #endif // WEBP_DSP_YUV_H_

View file

@ -79,4 +79,4 @@ extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_ENC_COST_ENC_H_ */ #endif // WEBP_ENC_COST_ENC_H_

View file

@ -44,6 +44,7 @@ typedef struct {
double literal_cost_; // Cached values of dominant entropy costs: double literal_cost_; // Cached values of dominant entropy costs:
double red_cost_; // literal, red & blue. double red_cost_; // literal, red & blue.
double blue_cost_; double blue_cost_;
uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance
} VP8LHistogram; } VP8LHistogram;
// Collection of histograms with fixed capacity, allocated as one // Collection of histograms with fixed capacity, allocated as one
@ -67,7 +68,9 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
int VP8LGetHistogramSize(int palette_code_bits); int VP8LGetHistogramSize(int palette_code_bits);
// Set the palette_code_bits and reset the stats. // Set the palette_code_bits and reset the stats.
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits); // If init_arrays is true, the arrays are also filled with 0's.
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
int init_arrays);
// Collect all the references into a histogram (without reset) // Collect all the references into a histogram (without reset)
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
@ -83,6 +86,9 @@ void VP8LFreeHistogramSet(VP8LHistogramSet* const histo);
// using 'cache_bits'. Return NULL in case of memory error. // using 'cache_bits'. Return NULL in case of memory error.
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits); VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
// Set the histograms in set to 0.
void VP8LHistogramSetClear(VP8LHistogramSet* const set);
// Allocate and initialize histogram object with specified 'cache_bits'. // Allocate and initialize histogram object with specified 'cache_bits'.
// Returns NULL in case of memory error. // Returns NULL in case of memory error.
// Special case of VP8LAllocateHistogramSet, with size equals 1. // Special case of VP8LAllocateHistogramSet, with size equals 1.
@ -113,7 +119,7 @@ double VP8LBitsEntropy(const uint32_t* const array, int n);
// Estimate how many bits the combined entropy of literals and distance // Estimate how many bits the combined entropy of literals and distance
// approximately maps to. // approximately maps to.
double VP8LHistogramEstimateBits(const VP8LHistogram* const p); double VP8LHistogramEstimateBits(VP8LHistogram* const p);
#ifdef __cplusplus #ifdef __cplusplus
} }

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 0 #define ENC_REV_VERSION 2
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
@ -278,7 +278,7 @@ int VP8IteratorIsDone(const VP8EncIterator* const it);
// Import uncompressed samples from source. // Import uncompressed samples from source.
// If tmp_32 is not NULL, import boundary samples too. // If tmp_32 is not NULL, import boundary samples too.
// tmp_32 is a 32-bytes scratch buffer that must be aligned in memory. // tmp_32 is a 32-bytes scratch buffer that must be aligned in memory.
void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32); void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32);
// export decimated samples // export decimated samples
void VP8IteratorExport(const VP8EncIterator* const it); void VP8IteratorExport(const VP8EncIterator* const it);
// go to next macroblock. Returns false if not finished. // go to next macroblock. Returns false if not finished.
@ -515,4 +515,4 @@ void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_ENC_VP8I_ENC_H_ */ #endif // WEBP_ENC_VP8I_ENC_H_

View file

@ -115,4 +115,4 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_ENC_VP8LI_ENC_H_ */ #endif // WEBP_ENC_VP8LI_ENC_H_

View file

@ -172,4 +172,4 @@ static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) {
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_BIT_READER_UTILS_H_ */ #endif // WEBP_UTILS_BIT_READER_UTILS_H_

View file

@ -151,4 +151,4 @@ static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_BIT_WRITER_UTILS_H_ */ #endif // WEBP_UTILS_BIT_WRITER_UTILS_H_

View file

@ -29,4 +29,4 @@ WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_FILTERS_UTILS_H_ */ #endif // WEBP_UTILS_FILTERS_UTILS_H_

View file

@ -261,9 +261,15 @@ static void CleanupParams(SmoothParams* const p) {
int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride, int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
int strength) { int strength) {
const int radius = 4 * strength / 100; int radius = 4 * strength / 100;
if (strength < 0 || strength > 100) return 0; if (strength < 0 || strength > 100) return 0;
if (data == NULL || width <= 0 || height <= 0) return 0; // bad params if (data == NULL || width <= 0 || height <= 0) return 0; // bad params
// limit the filter size to not exceed the image dimensions
if (2 * radius + 1 > width) radius = (width - 1) >> 1;
if (2 * radius + 1 > height) radius = (height - 1) >> 1;
if (radius > 0) { if (radius > 0) {
SmoothParams p; SmoothParams p;
memset(&p, 0, sizeof(p)); memset(&p, 0, sizeof(p));

View file

@ -32,4 +32,4 @@ int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ */ #endif // WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_

View file

@ -33,4 +33,4 @@ int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_QUANT_LEVELS_UTILS_H_ */ #endif // WEBP_UTILS_QUANT_LEVELS_UTILS_H_

View file

@ -60,4 +60,4 @@ static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_RANDOM_UTILS_H_ */ #endif // WEBP_UTILS_RANDOM_UTILS_H_

View file

@ -98,4 +98,4 @@ int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_RESCALER_UTILS_H_ */ #endif // WEBP_UTILS_RESCALER_UTILS_H_

View file

@ -87,4 +87,4 @@ WEBP_EXTERN const WebPWorkerInterface* WebPGetWorkerInterface(void);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_THREAD_UTILS_H_ */ #endif // WEBP_UTILS_THREAD_UTILS_H_

View file

@ -107,19 +107,6 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
PutLE16(data + 2, (int)(val >> 16)); PutLE16(data + 2, (int)(val >> 16));
} }
// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either
// based on table or not. Can be used as fallback if clz() is not available.
#define WEBP_NEED_LOG_TABLE_8BIT
extern const uint8_t WebPLogTable8bit[256];
static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
int log_value = 0;
while (n >= 256) {
log_value += 8;
n >>= 8;
}
return log_value + WebPLogTable8bit[n];
}
// Returns (int)floor(log2(n)). n must be > 0. // Returns (int)floor(log2(n)). n must be > 0.
// use GNU builtins where available. // use GNU builtins where available.
#if defined(__GNUC__) && \ #if defined(__GNUC__) && \
@ -138,6 +125,19 @@ static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
return first_set_bit; return first_set_bit;
} }
#else // default: use the C-version. #else // default: use the C-version.
// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either
// based on table or not. Can be used as fallback if clz() is not available.
#define WEBP_NEED_LOG_TABLE_8BIT
extern const uint8_t WebPLogTable8bit[256];
static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
int log_value = 0;
while (n >= 256) {
log_value += 8;
n >>= 8;
}
return log_value + WebPLogTable8bit[n];
}
static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); } static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); }
#endif #endif
@ -175,4 +175,4 @@ WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_UTILS_UTILS_H_ */ #endif // WEBP_UTILS_UTILS_H_

View file

@ -42,6 +42,12 @@ WEBP_EXTERN int WebPGetDecoderVersion(void);
// This function will also validate the header, returning true on success, // This function will also validate the header, returning true on success,
// false otherwise. '*width' and '*height' are only valid on successful return. // false otherwise. '*width' and '*height' are only valid on successful return.
// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant. // Pointers 'width' and 'height' can be passed NULL if deemed irrelevant.
// Note: The following chunk sequences (before the raw VP8/VP8L data) are
// considered valid by this function:
// RIFF + VP8(L)
// RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size, WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size,
int* width, int* height); int* width, int* height);
@ -425,6 +431,12 @@ WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(
// Returns VP8_STATUS_OK when the features are successfully retrieved. Returns // Returns VP8_STATUS_OK when the features are successfully retrieved. Returns
// VP8_STATUS_NOT_ENOUGH_DATA when more data is needed to retrieve the // VP8_STATUS_NOT_ENOUGH_DATA when more data is needed to retrieve the
// features from headers. Returns error in other cases. // features from headers. Returns error in other cases.
// Note: The following chunk sequences (before the raw VP8/VP8L data) are
// considered valid by this function:
// RIFF + VP8(L)
// RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
static WEBP_INLINE VP8StatusCode WebPGetFeatures( static WEBP_INLINE VP8StatusCode WebPGetFeatures(
const uint8_t* data, size_t data_size, const uint8_t* data, size_t data_size,
WebPBitstreamFeatures* features) { WebPBitstreamFeatures* features) {
@ -491,4 +503,4 @@ WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_WEBP_DECODE_H_ */ #endif // WEBP_WEBP_DECODE_H_

View file

@ -360,4 +360,4 @@ WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_WEBP_DEMUX_H_ */ #endif // WEBP_WEBP_DEMUX_H_

View file

@ -542,4 +542,4 @@ WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_WEBP_ENCODE_H_ */ #endif // WEBP_WEBP_ENCODE_H_

View file

@ -84,4 +84,4 @@ typedef enum {
// overflow a uint32_t. // overflow a uint32_t.
#define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1) #define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1)
#endif /* WEBP_WEBP_FORMAT_CONSTANTS_H_ */ #endif // WEBP_WEBP_FORMAT_CONSTANTS_H_

View file

@ -527,4 +527,4 @@ WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_WEBP_MUX_H_ */ #endif // WEBP_WEBP_MUX_H_

View file

@ -95,4 +95,4 @@ static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) {
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_WEBP_MUX_TYPES_H_ */ #endif // WEBP_WEBP_MUX_TYPES_H_

View file

@ -49,4 +49,4 @@ typedef long long int int64_t;
// Macro to check ABI compatibility (same major revision number) // Macro to check ABI compatibility (same major revision number)
#define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8)) #define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8))
#endif /* WEBP_WEBP_TYPES_H_ */ #endif // WEBP_WEBP_TYPES_H_