diff --git a/src/3rdparty/libwebp.pri b/src/3rdparty/libwebp.pri index f21ba6db57c7adb7b83fcd2827385c6fa36d409e..61fbee9807481c4157cd912cdca5df7b45f4219c 100644 --- a/src/3rdparty/libwebp.pri +++ b/src/3rdparty/libwebp.pri @@ -1,30 +1,29 @@ -CONFIG += object_parallel_to_source no_batch - INCLUDEPATH += \ $$PWD/libwebp \ $$PWD/libwebp/src \ $$PWD/libwebp/src/dec \ $$PWD/libwebp/src/enc \ - $$PWD/libwebp/src/extra \ $$PWD/libwebp/src/dsp \ $$PWD/libwebp/src/mux \ $$PWD/libwebp/src/utils \ $$PWD/libwebp/src/webp SOURCES += \ - $$PWD/libwebp/src/dec/alpha.c \ - $$PWD/libwebp/src/dec/buffer.c \ - $$PWD/libwebp/src/dec/frame.c \ - $$PWD/libwebp/src/dec/idec.c \ - $$PWD/libwebp/src/dec/io.c \ - $$PWD/libwebp/src/dec/quant.c \ - $$PWD/libwebp/src/dec/tree.c \ - $$PWD/libwebp/src/dec/vp8.c \ - $$PWD/libwebp/src/dec/vp8l.c \ - $$PWD/libwebp/src/dec/webp.c \ + $$PWD/libwebp/src/dec/alpha_dec.c \ + $$PWD/libwebp/src/dec/buffer_dec.c \ + $$PWD/libwebp/src/dec/frame_dec.c \ + $$PWD/libwebp/src/dec/idec_dec.c \ + $$PWD/libwebp/src/dec/io_dec.c \ + $$PWD/libwebp/src/dec/quant_dec.c \ + $$PWD/libwebp/src/dec/tree_dec.c \ + $$PWD/libwebp/src/dec/vp8_dec.c \ + $$PWD/libwebp/src/dec/vp8l_dec.c \ + $$PWD/libwebp/src/dec/webp_dec.c \ $$PWD/libwebp/src/demux/demux.c \ $$PWD/libwebp/src/demux/anim_decode.c \ + $$PWD/libwebp/src/dsp/alpha_processing.c \ $$PWD/libwebp/src/dsp/alpha_processing_mips_dsp_r2.c \ + $$PWD/libwebp/src/dsp/alpha_processing_sse2.c \ $$PWD/libwebp/src/dsp/alpha_processing_sse41.c \ $$PWD/libwebp/src/dsp/argb.c \ $$PWD/libwebp/src/dsp/argb_mips_dsp_r2.c \ @@ -35,80 +34,83 @@ SOURCES += \ $$PWD/libwebp/src/dsp/cost_sse2.c \ $$PWD/libwebp/src/dsp/cpu.c \ $$PWD/libwebp/src/dsp/dec.c \ + $$PWD/libwebp/src/dsp/dec_clip_tables.c \ + $$PWD/libwebp/src/dsp/dec_mips32.c \ $$PWD/libwebp/src/dsp/dec_mips_dsp_r2.c \ $$PWD/libwebp/src/dsp/dec_msa.c \ $$PWD/libwebp/src/dsp/dec_sse2.c \ $$PWD/libwebp/src/dsp/dec_sse41.c \ $$PWD/libwebp/src/dsp/enc.c \ + $$PWD/libwebp/src/dsp/enc_avx2.c \ + $$PWD/libwebp/src/dsp/enc_mips32.c \ $$PWD/libwebp/src/dsp/enc_mips_dsp_r2.c \ + $$PWD/libwebp/src/dsp/enc_msa.c \ $$PWD/libwebp/src/dsp/enc_sse2.c \ $$PWD/libwebp/src/dsp/enc_sse41.c \ $$PWD/libwebp/src/dsp/filters.c \ $$PWD/libwebp/src/dsp/filters_mips_dsp_r2.c \ + $$PWD/libwebp/src/dsp/filters_msa.c \ $$PWD/libwebp/src/dsp/filters_sse2.c \ $$PWD/libwebp/src/dsp/lossless.c \ $$PWD/libwebp/src/dsp/lossless_enc.c \ $$PWD/libwebp/src/dsp/lossless_enc_mips32.c \ $$PWD/libwebp/src/dsp/lossless_enc_mips_dsp_r2.c \ + $$PWD/libwebp/src/dsp/lossless_enc_msa.c \ $$PWD/libwebp/src/dsp/lossless_enc_sse2.c \ $$PWD/libwebp/src/dsp/lossless_enc_sse41.c \ $$PWD/libwebp/src/dsp/lossless_mips_dsp_r2.c \ $$PWD/libwebp/src/dsp/rescaler.c \ $$PWD/libwebp/src/dsp/rescaler_mips32.c \ $$PWD/libwebp/src/dsp/rescaler_mips_dsp_r2.c \ + $$PWD/libwebp/src/dsp/rescaler_msa.c \ $$PWD/libwebp/src/dsp/rescaler_sse2.c \ $$PWD/libwebp/src/dsp/upsampling.c \ $$PWD/libwebp/src/dsp/upsampling_mips_dsp_r2.c \ + $$PWD/libwebp/src/dsp/upsampling_msa.c \ $$PWD/libwebp/src/dsp/upsampling_sse2.c \ $$PWD/libwebp/src/dsp/yuv.c \ $$PWD/libwebp/src/dsp/yuv_mips_dsp_r2.c \ - $$PWD/libwebp/src/dsp/alpha_processing.c \ - $$PWD/libwebp/src/dsp/alpha_processing_sse2.c \ - $$PWD/libwebp/src/dsp/dec_clip_tables.c \ - $$PWD/libwebp/src/dsp/dec_mips32.c \ - $$PWD/libwebp/src/dsp/enc_avx2.c \ - $$PWD/libwebp/src/dsp/enc_mips32.c \ $$PWD/libwebp/src/dsp/lossless_sse2.c \ $$PWD/libwebp/src/dsp/yuv_mips32.c \ $$PWD/libwebp/src/dsp/yuv_sse2.c \ - $$PWD/libwebp/src/enc/alpha.c \ - $$PWD/libwebp/src/enc/analysis.c \ - $$PWD/libwebp/src/enc/backward_references.c \ - $$PWD/libwebp/src/enc/config.c \ - $$PWD/libwebp/src/enc/cost.c \ - $$PWD/libwebp/src/enc/delta_palettization.c \ - $$PWD/libwebp/src/enc/filter.c \ - $$PWD/libwebp/src/enc/frame.c \ - $$PWD/libwebp/src/enc/histogram.c \ - $$PWD/libwebp/src/enc/iterator.c \ - $$PWD/libwebp/src/enc/near_lossless.c \ - $$PWD/libwebp/src/enc/picture.c \ - $$PWD/libwebp/src/enc/quant.c \ - $$PWD/libwebp/src/enc/syntax.c \ - $$PWD/libwebp/src/enc/token.c \ - $$PWD/libwebp/src/enc/tree.c \ - $$PWD/libwebp/src/enc/vp8l.c \ - $$PWD/libwebp/src/enc/webpenc.c \ - $$PWD/libwebp/src/enc/picture_csp.c \ - $$PWD/libwebp/src/enc/picture_psnr.c \ - $$PWD/libwebp/src/enc/picture_rescale.c \ - $$PWD/libwebp/src/enc/picture_tools.c \ - $$PWD/libwebp/src/extras/extras.c \ + $$PWD/libwebp/src/enc/alpha_enc.c \ + $$PWD/libwebp/src/enc/analysis_enc.c \ + $$PWD/libwebp/src/enc/backward_references_enc.c \ + $$PWD/libwebp/src/enc/config_enc.c \ + $$PWD/libwebp/src/enc/cost_enc.c \ + $$PWD/libwebp/src/enc/delta_palettization_enc.c \ + $$PWD/libwebp/src/enc/filter_enc.c \ + $$PWD/libwebp/src/enc/frame_enc.c \ + $$PWD/libwebp/src/enc/histogram_enc.c \ + $$PWD/libwebp/src/enc/iterator_enc.c \ + $$PWD/libwebp/src/enc/near_lossless_enc.c \ + $$PWD/libwebp/src/enc/picture_enc.c \ + $$PWD/libwebp/src/enc/picture_csp_enc.c \ + $$PWD/libwebp/src/enc/picture_psnr_enc.c \ + $$PWD/libwebp/src/enc/picture_rescale_enc.c \ + $$PWD/libwebp/src/enc/picture_tools_enc.c \ + $$PWD/libwebp/src/enc/predictor_enc.c \ + $$PWD/libwebp/src/enc/quant_enc.c \ + $$PWD/libwebp/src/enc/syntax_enc.c \ + $$PWD/libwebp/src/enc/token_enc.c \ + $$PWD/libwebp/src/enc/tree_enc.c \ + $$PWD/libwebp/src/enc/vp8l_enc.c \ + $$PWD/libwebp/src/enc/webp_enc.c \ $$PWD/libwebp/src/mux/anim_encode.c \ $$PWD/libwebp/src/mux/muxedit.c \ $$PWD/libwebp/src/mux/muxinternal.c \ $$PWD/libwebp/src/mux/muxread.c \ - $$PWD/libwebp/src/utils/bit_reader.c \ - $$PWD/libwebp/src/utils/bit_writer.c \ - $$PWD/libwebp/src/utils/color_cache.c \ - $$PWD/libwebp/src/utils/filters.c \ - $$PWD/libwebp/src/utils/huffman.c \ - $$PWD/libwebp/src/utils/huffman_encode.c \ - $$PWD/libwebp/src/utils/quant_levels.c \ - $$PWD/libwebp/src/utils/quant_levels_dec.c \ - $$PWD/libwebp/src/utils/random.c \ - $$PWD/libwebp/src/utils/rescaler.c \ - $$PWD/libwebp/src/utils/thread.c \ + $$PWD/libwebp/src/utils/bit_reader_utils.c \ + $$PWD/libwebp/src/utils/bit_writer_utils.c \ + $$PWD/libwebp/src/utils/color_cache_utils.c \ + $$PWD/libwebp/src/utils/filters_utils.c \ + $$PWD/libwebp/src/utils/huffman_utils.c \ + $$PWD/libwebp/src/utils/huffman_encode_utils.c \ + $$PWD/libwebp/src/utils/quant_levels_utils.c \ + $$PWD/libwebp/src/utils/quant_levels_dec_utils.c \ + $$PWD/libwebp/src/utils/random_utils.c \ + $$PWD/libwebp/src/utils/rescaler_utils.c \ + $$PWD/libwebp/src/utils/thread_utils.c \ $$PWD/libwebp/src/utils/utils.c android { @@ -122,8 +124,10 @@ integrity { equals(QT_ARCH, arm)|equals(QT_ARCH, arm64) { SOURCES_FOR_NEON += \ + $$PWD/libwebp/src/dsp/alpha_processing_neon.c \ $$PWD/libwebp/src/dsp/dec_neon.c \ $$PWD/libwebp/src/dsp/enc_neon.c \ + $$PWD/libwebp/src/dsp/filters_neon.c \ $$PWD/libwebp/src/dsp/lossless_enc_neon.c \ $$PWD/libwebp/src/dsp/lossless_neon.c \ $$PWD/libwebp/src/dsp/rescaler_neon.c \ diff --git a/src/3rdparty/libwebp/AUTHORS b/src/3rdparty/libwebp/AUTHORS index 0f382daba656db2767bfba52f6807ca2053f15e9..b6e9cfb89c108bc26ea8035657bf5b16fb14f29c 100644 --- a/src/3rdparty/libwebp/AUTHORS +++ b/src/3rdparty/libwebp/AUTHORS @@ -2,8 +2,10 @@ Contributors: - Charles Munger (clm at google dot com) - Christian Duvivier (cduvivier at google dot com) - Djordje Pesut (djordje dot pesut at imgtec dot com) +- Hui Su (huisu at google dot com) - James Zern (jzern at google dot com) - Jan Engelhardt (jengelh at medozas dot de) +- Jehan (jehan at girinstud dot io) - Johann (johann dot koenig at duck dot com) - Jovan Zelincevic (jovan dot zelincevic at imgtec dot com) - Jyrki Alakuijala (jyrki at google dot com) @@ -16,6 +18,7 @@ Contributors: - Mislav Bradac (mislavm at google dot com) - Nico Weber (thakis at chromium dot org) - Noel Chromium (noel at chromium dot org) +- Owen Rodley (orodley at google dot com) - Parag Salasakar (img dot mips1 at gmail dot com) - Pascal Massimino (pascal dot massimino at gmail dot com) - PaweĹ‚ Hajdan, Jr (phajdan dot jr at chromium dot org) diff --git a/src/3rdparty/libwebp/ChangeLog b/src/3rdparty/libwebp/ChangeLog index 99fb3c0260e3784ef4e487bad90230361c540325..7ac7b5f8822632a7a24eff30e28a29d484d2af22 100644 --- a/src/3rdparty/libwebp/ChangeLog +++ b/src/3rdparty/libwebp/ChangeLog @@ -1,3105 +1,3484 @@ -deb54d9 Clarify the expected 'config' lifespan in WebPIDecode() -c7e2d24 update ChangeLog (tag: v0.5.1-rc5) -c7eb06f Fix corner case in CostManagerInit. -ab7937a gif2webp: normalize the number of .'s in the help message -3cdec84 vwebp: normalize the number of .'s in the help message -bdf6241 cwebp: normalize the number of .'s in the help message -06a38c7 fix rescaling bug: alpha plane wasn't filled with 0xff -319e37b Improve lossless compression. -447adbc 'our bug tracker' -> 'the bug tracker' -97b9e64 normalize the number of .'s in the help message -bb50bf4 pngdec,ReadFunc: throw an error on invalid read -38063af decode.h,WebPGetInfo: normalize function comment -9e8e1b7 Inline GetResidual for speed. -7d58d1b Speed-up uniform-region processing. -23e29cb Merge "Fix a boundary case in BackwardReferencesHashChainDistanceOnly." into 0.5.1 -0bb23b2 free -> WebPSafeFree() -e7b9177 Merge "DecodeImageData(): change the incorrect assert" into 0.5.1 -2abfa54 DecodeImageData(): change the incorrect assert -5a48fcd Merge "configure: test for -Wfloat-conversion" -0174d18 Fix a boundary case in BackwardReferencesHashChainDistanceOnly. -6a9c262 Merge "Added MSA optimized transform functions" -cfbcc5e Make sure to consider small distances in LZ77. -5e60c42 Added MSA optimized transform functions -3dc28d7 configure: test for -Wfloat-conversion -f2a0946 add some asserts to delimit the perimeter of CostManager's operation -9a583c6 fix invalid-write bug for alpha-decoding -f66512d make gradlew executable -6fda58f backward_references: quiet double->int warning -a48cc9d Merge "Fix a compression regression for images with long uniform regions." into 0.5.1 -cc2720c Merge "Revert an LZ77 boundary constant." into 0.5.1 -059aab4 Fix a compression regression for images with long uniform regions. -b0c7e49 Check more backward matches with higher quality. -a361151 Revert an LZ77 boundary constant. -8190374 README: fix typo -7551db4 update NEWS -0fb2269 bump version to 0.5.1 -f453761 update AUTHORS & .mailmap -3259571 Refactor GetColorPalette method. -1df5e26 avoid using tmp histogram in PreparePair() -7685123 fix comment typos -a246b92 Speedup backward references. -76d73f1 Merge "CostManager: introduce a free-list of ~10 intervals" -eab39d8 CostManager: introduce a free-list of ~10 intervals -4c59aac Merge "mips msa webp configuration" -043c33f Merge "Improve speed and compression in backward reference for lossless." -71be9b8 Merge "clarify variable names in HistogramRemap()" -0ba7fd7 Improve speed and compression in backward reference for lossless. -0481d42 CostManager: cache one interval and re-use it when possible -41b7e6b Merge "histogram: fix bin calculation" -96c3d62 histogram: fix bin calculation -fe9e31e clarify variable names in HistogramRemap() -ce3c824 disable near-lossless quantization if palette is used -e11da08 mips msa webp configuration -5f8f998 mux: Presence of unknown chunks should trigger VP8X chunk output. -cadec0b Merge "Sync mips32 and dsp_r2 YUV->RGB code with C verison" -d963775 Compute the hash chain once and for all for lossless compression. -50a4866 Sync mips32 and dsp_r2 YUV->RGB code with C verison -eee788e Merge "introduce a common signature for all image reader function" -d77b877 introduce a common signature for all image reader function -ca8d951 remove some obsolete TODOs -ae2a722 collect all decoding utilities from examples/ in libexampledec.a -0b8ae85 Merge "Move DitherCombine8x8 to dsp/dec.c" -77cad88 Merge "ReadWebP: avoid conversion to ARGB if final format is YUVA" -ab8d669 ReadWebP: avoid conversion to ARGB if final format is YUVA -f8b7ce9 Merge "test pointer to NULL explicitly" -5df6f21 test pointer to NULL explicitly -77f21c9 Move DitherCombine8x8 to dsp/dec.c -c9e6d86 Add gradle support -c65f41e Revert "Add gradle support" -bf731ed Add gradle support -08333b8 WebPAnimEncoder: Detect when canvas is modified, restore only when needed. -0209d7e Merge "speed-up MapToPalette() with binary search" -fdd29a3 speed-up MapToPalette() with binary search -cf4a651 Revert "Refactor GetColorPalette method." -0a27aca Merge changes Idfa8ce83,I19adc9c4 -f25c440 WebPAnimEncoder: Restore original canvas between multiple encodes. -169004b Refactor GetColorPalette method. -576362a VP8LDoFillBitWindow: support big-endian in fast path -ac49e4e bit_reader.c: s/VP8L_USE_UNALIGNED_LOAD/VP8L_USE_FAST_LOAD/ -d39ceb5 VP8LDoFillBitWindow: remove stale TODO -2ec2de1 Merge "Speed-up BackwardReferencesHashChainDistanceOnly." -3e023c1 Speed-up BackwardReferencesHashChainDistanceOnly. -f2e1efb Improve near lossless compression when a prediction filter is used. -e15afbc dsp.h: fix ubsan macro name -e53c9cc dsp.h: add WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW -af81fdb utils.h: quiet -fsanitize=undefined warnings -ea0be35 dsp.h: remove utils.h include -cd276ae utils/*.c: ../utils/utils.h -> ./utils.h -c892713 utils/Makefile.am: add some missing headers -ea24e02 Merge "dsp.h: add WEBP_UBSAN_IGNORE_UNDEF" -369e264 dsp.h: add WEBP_UBSAN_IGNORE_UNDEF -0d020a7 Merge "add runtime NEON detection" -5ee2136 Merge "add VP8LAddPixels() to lossless.h" -47435a6 add VP8LAddPixels() to lossless.h -8fa6ac6 remove two ubsan warnings -74fb56f add runtime NEON detection -4154a83 MIPS update to new Unfilter API -c80b9fc Merge "cherry-pick decoder fix for 64-bit android devices" -6235147 cherry-pick decoder fix for 64-bit android devices -d41b8c4 configure: test for -Wformat-* w/-Wformat present -5f95589 Fix WEBP_ALIGN in case the argument is a pointer to a type larger than a byte. -2309fd5 replace num_parts_ by num_parts_minus_one_ (unsigned) -9629f4b SimplifySegments: quiet -Warray-bounds warning -de47492 Merge "update the Unfilter API in dsp to process one row independently" -2102ccd update the Unfilter API in dsp to process one row independently -e3912d5 WebPAnimEncoder: Restore canvas before evaluating blending possibility. -6e12e1e WebPAnimEncoder: Fix for single-frame optimization. -602f344 Merge changes I1d03acac,Ifcb64219 -95ecccf only apply color-mapping for alpha on the cropped area -47dd070 anim_diff: Add an experimental option for max inter-frame diff. -aa809cf only allocate alpha_plane_ up to crop_bottom row -31f2b8d WebPAnimEncoder: FlattenSimilarPixels(): look for similar -774dfbd perform alpha filtering within the decoding loop -a4cae68 lossless decoding: only process decoded row up to last_row -238cdcd Only call WebPDequantizeLevels() on cropped area -cf6c713 alpha: preparatory cleanup -b95ac0a Merge "VP8GetHeaders(): initialize VP8Io with sane value for crop/scale dimensions" -8923139 VP8GetHeaders(): initialize VP8Io with sane value for crop/scale dimensions -5828e19 use_8b_decode -> use_8b_decode_ -8dca024 fix bug in alpha.c that was triggering a memory error in incremental mode -9a950c5 WebPAnimEncoder: Disable filtering when blending is used with lossy encoding. -eb42390 WebPAnimEncoder: choose max diff for framerect based on quality. -ff0a94b WebPAnimEncoder lossy: ignore small pixel differences for frame rectangles. -f804008 gif2webp: Remove the 'prev_to_prev_canvas' buffer. -6d8c07d Merge "WebPDequantizeLevels(): use stride in CountLevels()" -d96fe5e WebPDequantizeLevels(): use stride in CountLevels() -ec1b240 WebPPictureImport*: check output pointer -c076876 Merge "Revert "Re-enable encoding of alpha plane with color cache for next release."" -41f14bc WebPPictureImport*: check src pointer -64eed38 Pass stride parameter to WebPDequantizeLevels() -97934e2 Revert "Re-enable encoding of alpha plane with color cache for next release." -e88c4ca fix -m 2 mode-cost evaluation (causing partition0 overflow) -4562e83 Merge "add extra meaning to WebPDecBuffer::is_external_memory" -abdb109 add extra meaning to WebPDecBuffer::is_external_memory -875aec7 enc_neon,cosmetics: break long comment -71e856c GetMBSSIM,cosmetics: fix alignment -a90edff fix missing 'extern' for SSIM function in dsp/ -423ecaf move some SSIM-accumulation function for dsp/ -f08e662 Merge "Fix FindClosestDiscretized in near lossless:" -0d40cc5 enc_neon,Disto4x4: remove an unnecessary transpose -e8feb20 Fix FindClosestDiscretized in near lossless: -8200643 anim_util: quiet static analysis warning -a6f23c4 Merge "AnimEncoder: Support progress hook and user data." -a519377 Merge "Near lossless feature: fix some comments." -da98d31 AnimEncoder: Support progress hook and user data. -3335713 Near lossless feature: fix some comments. -0beed01 cosmetics: fix indent after 2f5e898 -6753f35 Merge "FTransformWHT optimization." -6583bb1 Improve SSE4.1 implementation of TTransform. -7561d0c FTransformWHT optimization. -7ccdb73 fix indentation after patch #328220 -6ec0d2a clarify the logic of the error path when decoding fails. -8aa352b Merge "Remove an unnecessary transposition in TTransform." -db86088 Merge "remove useless #include" -9960c31 Remove an unnecessary transposition in TTransform. -6e36b51 Small speedup in FTransform. -9dbd4aa Merge "fix C and SIMD flags completion." -e60853e Add missing common_sse2.h file to makefile.unix -696eb2b fix C and SIMD flags completion. -2b4fe33 Merge "fix multiple allocation for transform buffer" -2f5e898 fix multiple allocation for transform buffer -bf2b4f1 Regroup common SSE code + optimization. -4ed650a force "-pass 6" if -psnr or -size is used but -pass isn't. -3ef1ce9 yuv_sse2: fix -Wconstant-conversion warning -a7a03e9 Merge changes I4852d18f,I51ccb85d -5e122bd gif2webp: set enc_options.verbose = 0 w/-quiet -ab3c258 anim_encode,DefaultEncoderOptions: init verbose -8f0dee7 Merge "configure: fix builtin detection w/-Werror" -4a7b85a cmake: fix builtin detection w/-Werror -b74657f configure: fix builtin detection w/-Werror -3661b98 Add a CMakeLists.txt -75f4af4 remove useless #include -6c1d763 avoid Yoda style for comparison -8ce975a SSE optimization for vector mismatch. -7db5383 Merge tag 'v0.5.0' -37f0494 update ChangeLog (tag: v0.5.0-rc1, tag: v0.5.0, origin/0.5.0, 0.5.0) -7e7b6cc faster rgb565/rgb4444/argb output -4c7f565 update NEWS -1f62b6b update AUTHORS -e224fdc update mailmap -7110050 bump version to 0.5.0 -230a685 README: update help text, repo link -d48e427 Merge "demux: accept raw bitstreams" -99a01f4 Merge "Unify some entropy functions." -4b025f1 Merge "configure: disable asserts by default" -92cbddf Merge "fix PrintBlockInfo()" -ca509a3 Unify some entropy functions. -367bf90 fix PrintBlockInfo() -b0547ff move back common constants for lossless_enc*.c into the .h -fb4c783 lossless: simpler alpha cleanup preprocessing -ba7f4b6 Merge "anim_diff: add brief description of options" -47ddd5a Move some codec logic out of ./dsp . -b4106c4 anim_diff: add brief description of options -357f455 yuv_sse2: fix 32-bit visual studio build -b9d80fa configure: disable asserts by default -7badd3d cosmetic fix: sizeof(type) -> sizeof(*var) -80ce27d Speed up 24-bit packing / unpacking in YUV / RGB conversions. -68eebcb remove a TODO about rotation -2dee296 remove few obsolete TODO about aligned loads in SSE2 -e0c0bb3 remove TODO about unused ref_lf_delta[] -9cf1cc2 remove few TODO: * 256 -> RD_DISTO_MULT * don't use TDisto for UV mode picking -7918964 Merge changes from topic 'demux-fragment-cleanup' -47399f9 demux: remove GetFragment() -d3cfb79 demux: remove dead fragment related TODO -ab714b8 demux, Frame: remove is_fragment_ field -b105921 yuv_sse2, cosmetics: fix indent -466c92e demux,WebPIterator: remove fragment_num/num_fragments -11714ff demux: remove WebPDemuxSelectFragment -c0f7cc4 fix for bug #280: UMR in next->bits -578beeb Merge "enc/Makefile.am: add missing headers" -1a819f0 makefile.unix: make visibility=hidden the default -d4f9c2e enc/Makefile.am: add missing headers -846caff configure: check for -fvisibility=hidden -3f3ea2c demux: accept raw bitstreams -d6dad5d man cwebp: add precision about exactness of the 'lossless' mode -46bb1e3 Merge "gifdec: remove utils.h include" -2b882e9 Merge "Makefile.vc: define WEBP_HAVE_GIF for gifdec.c" -892b923 Merge "man/*, AUTHORS: clarify origin of the tool" -e5687a1 Merge "fix optimized build with -mcmodel=medium" -e56e685 Makefile.vc: define WEBP_HAVE_GIF for gifdec.c -4077d94 gifdec: remove utils.h include -b5e30da man/*, AUTHORS: clarify origin of the tool -b275e59 fix optimized build with -mcmodel=medium -64da45a cosmetics, cwebp: fix indent -038a060 Merge "add disto-based refinement for UV mode (if method = 1 or 2)" -2835089 Provide an SSE2 implementation of CombinedShannonEntropy. -e6c9351 add disto-based refinement for UV mode (if method = 1 or 2) -04507dc Merge "fix undefined behaviour during shift, using a cast" -793c526 Merge "wicdec: add support for reading from stdin" -d3d1639 Optimize the heap usage in HistogramCombineGreedy. -202a710 fix undefined behaviour during shift, using a cast -14d27a4 improve method #2 by merging DistoRefine() and SimpleQuantize() -cb1ce99 Merge "10% faster table-less SSE2/NEON version of YUV->RGB conversion" -ac761a3 10% faster table-less SSE2/NEON version of YUV->RGB conversion -79fcf29 wicdec: add support for reading from stdin -015f173 Merge "cwebp: add support for stdin input" -a9947c3 cwebp: add support for stdin input -7eb01ff Merge "Improved alpha cleanup for the webp encoder when prediction transform is used." -fb8c910 Merge "introduce WebPMemToUint32 and WebPUint32ToMem for memory access" -bd91af2 Merge "bit_reader: remove aarch64 BITS TODO" -6c702b8 Speed up hash chain initialization using memset. -4c60f63 make ReadPNG and ReadJPEG take a filename instead of a FILE -464ed10 bit_reader: remove aarch64 BITS TODO -d478e58 Merge "configure: update issue tracker" -6938111 Improved alpha cleanup for the webp encoder when prediction transform is used. -2c08aac introduce WebPMemToUint32 and WebPUint32ToMem for memory access -010ca3d Fix FindMatchLength with non-aligned buffers. -a90e1e3 README: add prerequisites for an autoconf build -458f086 configure: update issue tracker -3391459 vwebp: work around the transparent background with GLUT bug -e4a7eed cosmetics: fix indent -0837512 Merge "Make a separate case for low_effort in CopyImageWithPrediction" -aa2eb2d Merge "cosmetics: fix indent" -b7551e9 cosmetics: fix indent -5bda52d Make a separate case for low_effort in CopyImageWithPrediction -66fa598 Merge "configure: fix intrinsics build w/older gcc" -5ae220b backward_references.c: Fixed compiler warning -1556da0 Merge "configure: restore 2 warnings" -71a17e5 configure: restore 2 warnings -9eeabc0 configure: fix intrinsics build w/older gcc -363babe Merge "fix some warning about unaligned 32b reads" -a141178 Optimization in hash chain comparison for 64 bit Arrays were compared 32 bits at a time, it is now done 64 bits at a time. Overall encoding speed-up is only of 0.2% on @skal's small PNG corpus. It is of 3% on my initial 1.3 Mp desktop screenshot image. -829bd14 Combine Huffman cost and bit entropy into one loop -a7a954c Merge "lossless: make prediction in encoder work per scanline" -61b605b Merge "fix of undefined multiply (int32 overflow)" -239421c lossless: make prediction in encoder work per scanline -f5ca40e fix of undefined multiply (int32 overflow) -5cd2ef4 Merge changes from topic 'win-threading-compat' -76ce918 Makefile.vc: enable WEBP_USE_THREAD for windows phone -d2afe97 thread: use CreateThread for windows phone -0fd0e12 thread: use WaitForSingleObjectEx if available -63fadc9 thread: use InitializeCriticalSectionEx if available -110ad58 thread: use native windows cond var if available -912c9fd dec/webp: use GetLE(24|32) from utils -f169448 utils/GetLE32: correct uint32 promotion -158763d Merge "always call WebPInitSamplers(), don't try to be smart" -3770f3b Merge "cleanup the YFIX/TFIX difference by removing some code and #define" -a40f60a Merge "3% speed improvement for lossless webp encoder for low effort mode:" -ed1c2bc always call WebPInitSamplers(), don't try to be smart -b8c44f1 3% speed improvement for lossless webp encoder for low effort mode: -997e103 cleanup the YFIX/TFIX difference by removing some code and #define -d73d1c8 Merge "Make discarding invisible RGB values (cleanup alpha) the default." -1f9be97 Make discarding invisible RGB values (cleanup alpha) the default. -f240117 Make dwebp listen more to the -quiet flag -b37b017 fix for issue #275: don't compare to out-of-bound pointers -21735e0 speed-up trivial one-symbol decoding case for lossless -397863b Refactor CopyPlane() and CopyPixels() methods: put them in utils. -6ecd72f Re-enable encoding of alpha plane with color cache for next release. -1f7148a Merge "remove unused fields from WebPDecoderOptions and WebPBitstreamFeatures" -6ae395f Merge "use ExReadFile() for ReadYUV()" -8076a00 gitignore list: add anim_diff. -1c1702d use ExReadFile() for ReadYUV() -775d3a3 remove unused fields from WebPDecoderOptions and WebPBitstreamFeatures -c13245c AnimEncoder: Add a GetError() method. -688b265 AnimDecoder API: Add a GetDemuxer() method. -1aa4e3d WebPAnimDecoder: add an option to enable multi-threaded decoding. -3584abc AnimDecoder: option to decode to common color modes. -afd5a62 Merge "mux.h does NOT need to include encode.h" -8550d44 Merge "migrate anim_diff tool from C++ to C89" -96201e5 migrate anim_diff tool from C++ to C89 -945cfa3 mux.h does NOT need to include encode.h -8da07e8 Merge "~2x faster SSE2 RGB24toY, BGR24toY, ARGBToY|UV" -bfd3fc0 ~2x faster SSE2 RGB24toY, BGR24toY, ARGBToY|UV -0243242 man/cwebp.1, cosmetics: escape '-'s -96f5b42 man/cwebp: group lossy-only options -52fdbdf extract some RGB24 to Luma conversion function from enc/ to dsp/ -ab8c230 add missing \n -8304179 sync NEWS with 0.4.4 -5bd04a0 sync versions with 0.4.4 -8f1fcc1 Merge "Move ARGB->YUV functions from dec/vp8l.c to dsp/yuv.c" -25bf2ce fix some warning about unaligned 32b reads -922268f s/TIFF/WebP -fa8927e Move ARGB->YUV functions from dec/vp8l.c to dsp/yuv.c -9b37359 Merge "for ReadXXXX() image-readers, use the value of pic->use_argb" -f7c507a Merge "remove unnecessary #include "yuv.h"" -7861578 for ReadXXXX() image-readers, use the value of pic->use_argb -14e4043 remove unnecessary #include "yuv.h" -469ba2c vwebp: fix incorrect clipping w/NO_BLEND -4b9186b update issue tracker url -d64d376 change WEBP_ALIGN_CST value to 31 -f717b82 vp8l.c, cosmetics: fix indent after 95509f9 -927ccdc Merge "fix alignment of allocated memory in AllocateTransformBuffer" -fea94b2 fix alignment of allocated memory in AllocateTransformBuffer -5aa8d61 Merge "MIPS: rescaler code synced with C implementation" -e7fb267 MIPS: rescaler code synced with C implementation -93c86ed Merge "format_constants.h: MKFOURCC, correct cast" -5d791d2 format_constants.h: MKFOURCC, correct cast -65726cd dsp/lossless: Average2, make a constant unsigned -d26d9de Use __has_builtin to check clang support -12ec204 moved ALIGN_CST into util/utils.h and renamed WEBP_ALIGN_xxx -a264083 Merge "rescaler: ~20% faster SSE2 implementation for lossless ImportRowExpand" -3fb600d Merge "wicdec: fix alpha detection w/64bpp BGRA/RGBA" -67c547f rescaler: ~20% faster SSE2 implementation for lossless ImportRowExpand -99e3f81 Merge "large re-organization of the delta-palettization code" -95509f9 large re-organization of the delta-palettization code -74fb458 fix for weird msvc warning message -ae49ad8 Merge "SSE2 implementation of ImportRowShrink" -932fd4d SSE2 implementation of ImportRowShrink -badfcba wicdec: fix alpha detection w/64bpp BGRA/RGBA -35cafa6 Merge "iosbuild: fix linking with Xcode 7 / iOS SDK 9" -b0c9d8a label rename: NO_CHANGE -> NoChange -b4e731c neon-implementation for rescaler code -db1321a iosbuild: fix linking with Xcode 7 / iOS SDK 9 -6dfa5e3 rescaler: better handling of the fxy_scale=0 special case. -55c0529 Revert "rescaler: better handling of the fxy_scale=0 special case." -9f226bf rescaler: better handling of the fxy_scale=0 special case. -f7b8f90 delta_palettization.*: add copyright -c1e1b71 Changed delta palette to compress better -0dd2826 Merge "Add delta_palettization feature to WebP" -48f66b6 Add delta_palettization feature to WebP -27933e2 anim_encoder: drop a frame if it has same pixels as the prev frame. -df9f6ec Merge "webpmux/DisplayInfo: send non-error output to stdout" -8af4993 Merge "rescaler_mips_dsp_r2: cosmetics, fix indent" -2b9d249 Merge "rescaler: cosmetics, join two lines" -cc020a8 webpmux/DisplayInfo: send non-error output to stdout -a288e74 configure: add -Wshorten-64-to-32 -c4c3cf2 pngdec: fix type conversion warnings -bef8e97 webpmux: fix type conversion warning -5a84460 rescaler_mips_dsp_r2: cosmetics, fix indent -acde0aa rescaler: cosmetics, join two lines -306ce4f rescaler: move the 1x1 or 2x1 handling one level up -cced974 remove _mm_set_epi64x(), which is too specific -56668c9 fix warnings about uint64_t -> uint32_t conversion -76a7dc3 rescaler: add some SSE2 code -1df1d0e rescaler: harmonize function protos -9ba1894 rescaler: simplify ImportRow logic -5ff0079 fix rescaler vertical interpolation -cd82440 VP8LAllocateHistogramSet: align histogram[] entries -a406b1d Merge "fix memory over-allocation in lossless rescaler init" -0fde33e add missing const in VP8InitFrame signature -ac7d5e8 fix memory over-allocation in lossless rescaler init -017f8cc Loosen the buffer size checks for Y/U/V/A too. -15ca501 loosen the padding check on buffer size -d623a87 dec_neon: add whitespace around stringizing operator -29377d5 dsp/mips: cosmetics: add whitespace around XSTR macro -eebaf97 dsp/mips: add whitespace around stringizing operator -d39dc8f Create a WebPAnimDecoder API. -03fb752 gif2webp: print output file size -14efabb Android: limit use of cpufeatures -7b83adb preparatory cosmetics for Rescaler code fix and clean-up -77fb41c dec/vp8l/DecodeAlphaData: remove redundant cast -90fcfcd Insert less hash chain entries from the beginnings of long copies. -bd55604 SSE2: add yuv444 converters, re-using yuv_sse2.c -41a5d99 add a -quiet option to 'dwebp' -80ab3ed Merge "README: update dwebp help output after 1e595fe" -32b71b2 README: update dwebp help output after 1e595fe -3ec1182 use the DispatchAlpha() call from dsp -c5f0062 incorporate bzero() into WebPRescalerInit() instead of call site -3ebcdd4 remove duplicate "#include <stdlib.h>" -1e595fe dwebp: add -resize as a synonym for -scale -24a9693 dec: allow 0 as a scaling dimension -b918724 utils/rescaler: add WebPRescalerGetScaledDimensions -923e8ed Merge "update NEWS" -020fd09 Merge "WebPPictureDistortion: support ARGB format for 'pic' when computing distortion." -6a5292f update NEWS -56a2e9f WebPPictureDistortion: support ARGB format for 'pic' when computing distortion. -0ae582e configure: test and add -Wunreachable-code -c2f9dc0 bit_writer: convert VP8L macro values to immediates -b969f88 Reduce magic in palette reordering -acb297e anim_diff: add a -raw_comparison flag -155c1b2 Merge changes I76f4d6fe,I45434639 -717e4d5 mips32/mipsDSPr2: function ImportRow rebased -7df9389 fix rescaling bug (uninitialized read, see bug #254). -5cdcd56 lossless_enc_neon: add VP8LTransformColor -a53c336 lossless_neon: add VP8LTransformColorInverse -99131e7 Merge changes I9fb25a89,Ibc648e9e -c455676 simplify the main loop for downscaling -2a010f9 lossless_neon: remove predictors 5-13 -ca221bb ll_enc_neon: enable VP8LSubtractGreenFromBlueAndRed -585d93d Container spec: clarify ordering of ALPH chunk. -01d61fd lossless: ~20 % speedup -f722c8f lossless: Speed up ComputeCacheEntropy by 40 % -1ceecdc add a VP8LColorCacheSet() method for color cache -17eb609 lossless: Allow copying from prev row in rle-mode. -f3a7a5b lossless: bit writer optimization -d97b9ff Merge changes from topic 'lossless-enc-improvements' -0250dfc msvc: fix pointer type warning in BitsLog2Floor -52931fd lossless: combine the Huffman code with extra bits -c4855ca lossless: Inlining add literal -8e9c94d lossless: simplify HashChainFindCopy heuristics -888429f lossless: 0.5 % compression density improvement -7b23b19 lossless: Add zeroes into the predicted histograms. -85b44d8 lossless: encoding, don't compute unnecessary histo -d92453f lossless: Remove about 25 % of the speed degradation -2cce031 Faster alpha coding for webp -5e75642 lossless: rle mode not to accept lengths smaller than 4. -84326e4 lossless: Less code for the entropy selection -16ab951 lossless: 0.37 % compression density improvement -822f113 add WebPFree() to the API -0ae2c2e SSE2/SSE41: optimize SSE_16xN loops -39216e5 cosmetics: fix indent after 32462a07 -559e54c Merge "SSE2: slightly faster FTransformWHT" -8ef9a63 SSE2: slightly faster FTransformWHT -f27f773 lossless_neon: enable VP8LAddGreenToBlueAndRed -36e9c4b SSE2: minor cosmetrics on in-loop filter code -4741fac dsp/lossless_*sse2: remove some unnecessary inlines -1819965 fix warning ("left shift of negative value") using a cast -7017001 SSE2: speed-up some lossless-encoding functions -abcb012 Merge "SSE2: slightly faster (~5%) AddGreenToBlueAndRed()" -2df5bd3 Merge "Speedup to HuffmanCostCombinedCount" -9e356d6 SSE2: slightly faster (~5%) AddGreenToBlueAndRed() -fc6c75a SSE2: 53% faster TransformColor[Inverse] -49073da SSE2: 46% speed-up of TransformColor[Inverse] -32462a0 Speedup to HuffmanCostCombinedCount -f3d687e SSE4.1 implementation of some lossless encoding functions -bfc300c SSE4.1 implementation of some alpha-processing functions -7f9c98f Merge "sse2 in-loop: simplify SignedShift8b() a bit" -ef314a5 dec_sse2/GetNotHEV: micro optimization -a729cff sse2 in-loop: simplify SignedShift8b() a bit -422ec9f simplify Load8x4() a bit -8df238e Merge "remove some duplicate FlipSign()" -751506c remove some duplicate FlipSign() -65ef5af Merge "lossless: 0.13% compression density gain" -2beef2f lossless: 0.13% compression density gain -3033f24 lossless: 0.06 % compression density improvement -64960da dec_neon: add VE8uv / VE16 -14dbd87 dec_neon: add HE8uv / HE16 -ac76801 introduce FTransform2 to perform two transforms at a time. -aa6065a dec_neon: use vld1_dup(mem) rather than vdup(mem[0]) -8b63ac7 Merge "dec_neon: add TM16" -f51be09 Merge "dec_neon/TrueMotion: simply left border load" -dc48196 dec_neon: add TM16 -ea95b30 dec_neon/TrueMotion: simply left border load -f262d61 speed-up SetResidualSSE2 -bf46d0a fix mips2 build target -929a0fd enc_sse2/TTransform: simplify abs calculation -17dbd05 enc_sse2/CollectHistogram: simplify abs calculation -a6c1593 dec_neon: add DC16 intra predictors -03b4f50 Makefile.vc: add anim_diff build support. -1b98987 Merge changes I9cd84125,Iee7e387f,I7548be72 -acd7b5a Introduce a test tool anim_diff. -f274a96 dsp/enc_sse2: add luma4 intra predictors -040b11b dsp/enc_sse2: add chroma intra predictors -aee021b dsp/enc_sse2: add luma16 intra predictors -9e00a49 makefile.unix: remove superclean target -cefc9c0 makefile.unix: clean up after extras target -4c9af02 dec_neon: add DC8uvNoTopLeft -dd55b87 Merge "doc/webp-container-spec: update repo browser link" -f048696 doc/webp-container-spec: update repo browser link -9287761 Merge "GetResidualCostSSE2: simplify abs calculation" -0e00936 dsp/cpu.c(x86): check maximum supported cpuid feature -b243a4b GetResidualCostSSE2: simplify abs calculation -6d4602b Merge "fix typo: constitutes -> constitute" -5fe1fe3 fix typo: constitutes -> constitute -b83bd7c Merge "populate 'libwebpextras' with: import gray, rgb565 and rgb4444 functions" -b0114a3 Merge "histogram.h: cosmetics: remove unnecessary includes" -feab45e gifdec: Move inclusion of webp/config.h to header. -dbba67d histogram.h: cosmetics: remove unnecessary includes -e978fec Merge "VP8LBitReader: fix remaining ubsan error with large shifts" -d6fe588 Merge "ReconstructRow: move some one-time inits out of the main loop" -a21d647 ReconstructRow: move some one-time inits out of the main loop -7a01c3c VP8LBitReader: fix remaining ubsan error with large shifts -7fa67c9 change GetPixPairHash64() return type to uint32_t -ec1fb9f Merge "dsp/enc.c: cosmetics: move DST() def closer to use" -7073bfb Merge "split 64-mult hashing into two 32-bit multiplies" -0768b25 dsp/enc.c: cosmetics: move DST() def closer to use -6a48b8f Merge "fix MSVC size_t->int conversion warning" -1db07cd Merge "anim_encode: cosmetics: fix alignment" -e28271a anim_encode: cosmetics: fix alignment -7fe357b split 64-mult hashing into two 32-bit multiplies -af74c14 populate 'libwebpextras' with: import gray, rgb565 and rgb4444 functions -6121413 remove VP8Residual::cost unused field -e254482 fix MSVC size_t->int conversion warning -b69a6c3 vwebp: don't redefine snprintf with VS2015+ -0ac29c5 AnimEncoder API: Consistent use of trailing underscores in struct. -d484555 AnimEncoder API: Use timestamp instead of duration as input to Add(). -9904e36 dsp/dec_sse2: DC8uv / DC8uvNoLeft speedup -7df2049 dsp/dec_sse2: DC16 / DC16NoLeft speedup -8e515df Merge "makefile.unix: add some missing headers" -db12250 cosmetics: vp8enci.h: break long line -bf516a8 makefile.unix: add some missing headers -b44eda3 dsp: add DSP_INIT_STUB -03e76e9 clarify the comment about double-setting the status in SetError() -9fecdd7 remove unused EmitRGB() -43f010d move ReconstructRow to top -82d9802 add a dec/common.h header to collect common enc/dec #defines -5d4744a Merge "enc_sse41: add Disto4x4 / Disto16x16" -e38886a mux.h: Bump up ABI version -46305ca configure: add --disable-<avx2|sse4.1|sse2> -2fc8b65 CPPFLAGS->CFLAGS for detecting sse4.1 in preprocessor -1a338fb enc_sse41: add Disto4x4 / Disto16x16 -9405550 encoding SSE4.1 stub for StoreHistogram + Quantize + SSE_16xN -c64659e remove duplicate variables after the lossless{_enc}.c split -67ba7c7 enc_sse2: call local FTransform in CollectHistogram -1824979 dsp: s/VP8LSetHistogramData/VP8SetHistogramData/ -ede5e15 cosmetics: dsp/lossless.h: reorder prototypes -553051f dsp/lossless: split enc/dec functions -9064adc Merge "conditionally add -msse4.1 in Makefile.unix" -cecf509 dsp/yuv*.c: rework WEBP_USE_<arch> ifdef -6584d39 dsp/upsampling*.c: rework WEBP_USE_<arch> ifdef -8080942 dsp/rescaler*.c: rework WEBP_USE_<arch> ifdef -1d93dde dsp/lossless*.c: rework WEBP_USE_<arch> ifdef -73805ff dsp/filters*.c: rework WEBP_USE_<arch> ifdef -fbdcef2 dsp/enc*.c: rework WEBP_USE_<arch> ifdef -66de69c dsp/dec*.c: rework WEBP_USE_<arch> ifdef -48e4ffd dsp/cost*.c: rework WEBP_USE_<arch> ifdef -29fd6f9 dsp/argb*.c: rework WEBP_USE_<arch> ifdef -80ff381 dsp/alpha*.c: rework WEBP_USE_<arch> ifdef -bf09cf1 conditionally add -msse4.1 in Makefile.unix -e9570dd stub for SSE4.1 support. -4a95384 Merge "dsp: add sse4.1 detection" -cabf4bd dsp: add sse4.1 detection -4ecba1a thread.h: rename interface param -b8d706c Merge "sync versions with 0.4.3" -ae64a71 Merge "add shell for libwebpextras" -92a5da9 sync versions with 0.4.3 -9d4e2d1 Merge "~30% faster smart-yuv (-pre 4) with early-out criterion" -b1bdbba ~30% faster smart-yuv (-pre 4) with early-out criterion -7efb974 Merge "Disable NEON code on Native Client" -ac4f578 Disable NEON code on Native Client -0873f85 AnimEncoder API: Support input frames in YUV(A) format. -5c176d2 add shell for libwebpextras -44bd956 fix signature for VP8RecordCoeffTokens() -c9b8ea0 small cosmetics on TokenBuffer. -76394c0 Merge "MIPS: dspr2: added optimization for TrueMotion" -0f77369 WebPPictureRescale: add a note about 0 width/height -241bb5d MIPS: dspr2: added optimization for TrueMotion -6cef0e4 examples/Android.mk: add webpmux_example target -53c16ff Android.mk: add webpmux target -21852a0 Android.mk: add webpdemux target -8697a3b Android.mk: add webpdecoder{,_static} targets -4a67049 Android.mk: split source lists per-directory -b5e7942 MIPS: dspr2: Added optimization for some convert functions -0f595db MIPS: dspr2: Added optimization for some convert functions -8a218b4 MIPS: [mips32|dspr2]: GetResidualCost rebased -ef98750 Speedup method StoreImageToBitMask by 5%. -602a00f fix iOS arm64 build with Xcode 6.3 -2382050 1-2% faster encoding by removing an indirection in GetResidualCost() -eddb7e7 MIPS: dspr2: added otpimization for DC8uv, DC8uvNoTop and DC8uvNoLeft -73ba291 MIPS: dspr2: added optimization for functions RD4 and LD4 -c7129da Merge "4-5% faster encoding using SSE2 for GetResidualCost" -94380d0 MIPS: dspr2: added optimizaton for functions VE4 and DC4 -2a40709 4-5% faster encoding using SSE2 for GetResidualCost -17e1986 Merge "MIPS: dspr2: added optimization for simple filtering functions" -3ec404c Merge "dsp: normalize WEBP_TSAN_IGNORE_FUNCTION usage" -b969f5d dsp: normalize WEBP_TSAN_IGNORE_FUNCTION usage -d7b8e71 MIPS: dspr2: added optimization for simple filtering functions -235f774 Merge "MIPS: dspr2: Added optimization for function VP8LTransformColorInverse_C" -42a8a62 MIPS: dspr2: Added optimization for function VP8LTransformColorInverse_C -b442bef Merge "ApplyFiltersAndEncode: only copy lossless stats" -b510fbf doc/webp-container-spec: note MSB order for chunk diagrams -9bc0f92 ApplyFiltersAndEncode: only copy lossless stats -3030f11 Merge "dsp/mips: add some missing TSan annotations" -dfcf459 Merge "MIPS: dspr2: Added optimization for function VP8LAddGreenToBlueAndRed_C" -55c75a2 dsp/mips: add some missing TSan annotations -2cb879f MIPS: dspr2: Added optimization for function VP8LAddGreenToBlueAndRed_C -e155601 move some cost tables from enc/ to dsp/ -c3a0316 Merge "picture_csp: fix build w/USE_GAMMA_COMPRESSION undefined" -39537d7 Merge "VP8LDspInitMIPSdspR2: add missing TSan annotation" -1dd419c picture_csp: fix build w/USE_GAMMA_COMPRESSION undefined -43fd354 VP8LDspInitMIPSdspR2: add missing TSan annotation -c7233df Merge "VP8LDspInit: remove memcpy" -0ec4da9 picture_csp::InitGammaTables*: add missing TSan annotations -35579a4 VP8LDspInit: remove memcpy -97f6aff VP8YUVInit: add missing TSan annotation -f9016d6 dsp/enc::InitTables: add missing TSan annotation -e3d9771 VP8EncDspCostInit*: add missing TSan annotations -d97c143 Merge "doc/webp-container-spec: cosmetics" -309b790 MIPS: mips32: Added optimization for function SetResidualCoeffs -a987fae MIPS: dspr2: added optimization for function GetResidualCost -e7d3df2 doc/webp-container-spec: cosmetics -be6635e Merge "VP8TBufferClear: remove some misleading const's" -02971e7 Merge "VP8EmitTokens: remove unnecessary param void cast" -3b77e5a VP8TBufferClear: remove some misleading const's -aa139c8 VP8EmitTokens: remove unnecessary param void cast -c24d8f1 cosmetics: upsampling_sse2: add const to some casts -1829c42 cosmetics: lossless_sse2: add const to some casts -183168f cosmetics: enc_sse2: add const to some casts -860badc cosmetics: dec_sse2: add const to some casts -0254db9 cosmetics: argb_sse2: add const to some casts -1aadf85 cosmetics: alpha_processing_sse2: add const to some casts -1579de3 vwebp: clear canvas at the beginning of each loop -4b9fa5d Merge "webp-container-spec: clarify background clear on loop" -4c82284 Updated the near-lossless level mapping. -5603947 webp-container-spec: clarify background clear on loop -19f0ba0 Implement true-motion prediction in SSE2 -774d4cb make VP8PredLuma16[] array non-const -d7eabb8 Merge "MIPS: dspr2: Added optimization for function CollectHistogram" -fe42739 Use integers for kmin/kmax for simplicity. -b9df35f AnimEncode API: kmax=0 should imply all keyframes. -6ce296d MIPS: dspr2: Added optimization for function CollectHistogram -2c906c4 vwebp: remove unnecessary static Help() prototype -be0fd1d Merge "dec/vp8: clear 'dither_' on skipped blocks" -e96170f Merge "vwebp/animation: display last frame on end-of-loop" -0f017b5 vwebp/animation: display last frame on end-of-loop -c86b40c enc/near_lossless.c: fix alignment -66935fb dec/vp8: clear 'dither_' on skipped blocks -b7de794 Merge "lossless_neon: enable subtract green for aarch64" -77724f7 SSE2 version of GradientUnfilter -416e1ce lossless_neon: enable subtract green for aarch64 -72831f6 Speedup AnalyzeAndInit for low effort compression. -a659748 Speedup Analyze methods for lossless compression. -98c8138 Enable Near-lossless feature. -c6b2454 AnimEncoder API: Fix for kmax=1 and default kmin case. -022d2f8 add SSE2 variants for alpha filtering functions -2db15a9 Temporarily disable encoding of alpha plane with color cache. -1d575cc Merge "Lossless decoding: Remove an unnecessary if condition." -cafa1d8 Merge "Simplify backward refs calculation for low-effort." -7afdaf8 Alpha coding: reorganize the filter/unfiltering code -4d6d728 Simplify backward refs calculation for low-effort. -ec0d1be Cleaup Near-lossless code. -9814ddb Remove the post-transform near-lossless heuristic. -4509e32 Lossless decoding: Remove an unnecessary if condition. -f2ebc4a Merge "Regression fix for lossless decoding" -783a8cd Regression fix for lossless decoding -9a062b8 AnimEncoder: Bugfix for kmin = 1 and kmax = 2. -0f027a7 simplify smart RGB->YUV conversion code -0d5b334 BackwardReferencesHashChainFollowChosenPath: remove unused variable -f480d1a Fix to near lossless artefacts on palettized images. -d4615d0 Merge changes Ia1686828,I399fda40 -cb4a18a rename HashChainInit into HashChainReset -f079e48 use uint16_t for chosen_path[] -da09121 MIPS: dspr2: Added optimization for function FTransformWHT -b8c2013 Merge "wicdec: (msvs) quiet some /analyze warnings" -9b228b5 wicdec: (msvs) quiet some /analyze warnings -daeb276 Merge "MIPS: dspr2: Added optimization for MultARGBRow function" -cc08742 Merge "dsp/cpu: (msvs) add include for __cpuidex" -4a82aab Merge changes I87544e92,I0bb6cda5 -7a19139 dwebp/WritePNG: mark png variables volatile -775dfad dwebp: include setjmp.h w/WEBP_HAVE_PNG -47d26be dwebp: correct sign in format strings -f0e0677 VP8LEncodeStream: add an assert -c5f7747 VP8LColorCacheCopy: promote an int before shifting -0de5f33 dsp/cpu: (msvs) add include for __cpuidex -7d850f7 MIPS: dspr2: Added optimization for MultARGBRow function -5487529 MIPS: dspr2: added optimization for function QuantizeBlock -4fbe9cf dsp/cpu: (msvs) avoid immintrin.h on _M_ARM -3fd5903 simplify/reorganize arguments for CollectColorBlueTransforms -b9e356b Disable costly TraceBackwards for method=0. -a7e7caa MIPS: dspr2: added optimization for function TransformColorRed -2cb3918 Merge "MIPS: dspr2: added optimization for function TransformColorBlue" -279e661 Merge "dsp/cpu: add include for _xgetbv() w/MSVS" -b6c0428 dsp/cpu: add include for _xgetbv() w/MSVS -d1c4ffa gif2webp: Move GIF decoding related code to a support library. -07c3955 Merge "AnimEncoder API: Add info in README.mux" -7b16197 MIPS: dspr2: added optimization for function TransformColorBlue -d7c4b02 cpu: fix AVX2 detection for gcc/clang targets -9d29946 AnimEncoder API: Add info in README.mux -d581ba4 follow-up: clean up WebPRescalerXXX dsp function -f8740f0 dsp: s/USE_INTRINSICS/WEBP_USE_INTRINSICS/ -ce73abe Merge "introduce a separate WebPRescalerDspInit to initialize pointers" -ab66bec introduce a separate WebPRescalerDspInit to initialize pointers -205c7f2 fix handling of zero-sized partition #0 corner case -cbcdd5f Merge "move rescaler functions to rescaler* files in src/dsp/" -bf586e8 Merge changes I230b3532,Idf3057a7 -6dc79dc Merge "anim_encode: fix type conversion warnings" -11fce25 Merge "dec_neon: remove returns from void functions" -c4e63f9 Makefile.vc: add gif2webp target -4f43d38 enable NEON for Windows ARM builds -3f6615a Makefile.vc: add rudimentary Windows ARM support -e7c5954 dec_neon: remove returns from void functions -f79c163 anim_encode: fix type conversion warnings -0f54f1e Remove gif2webp_util which is no longer needed. -cbcbedd move rescaler functions to rescaler* files in src/dsp/ -ac79ed1 webpmux: remove experimental fragment handling -e8694d4 mux: remove experimental FRGM parsing -9e92b6e AnimEncoder API: Optimize single-frame animated images -abbae27 Merge "Move over gif2webp to the new AnimEncoder API." -a28c4b3 MIPS: move WORK_AROUND_GCC define to appropriate place -012d2c6 MIPS: dspr2: added optimization for functions SSEAxB -67720c8 Move over gif2webp to the new AnimEncoder API. -9241ecf MIPS: dspr2: added optimization for function Average -9422211 Merge "Tune BackwardReferencesLz77 for low_effort (m=0)." -df40057 Merge "Speedup VP8LGetHistoImageSymbols for low effort (m=0) mode." -ea08466 Tune BackwardReferencesLz77 for low_effort (m=0). -b0b973c Speedup VP8LGetHistoImageSymbols for low effort (m=0) mode. -c6d3292 argb_sse2: cosmetics -67f601c make the 'last_cpuinfo_used' variable names unique -b948986 AnimEncoder API: Init method for default options. -856f8ec Merge "AnimEncoder API: Remove AnimEncoderFrameOptions." -c537514 Merge "AnimEncoder API: GenerateCandidates bugfix." -dc0ce03 Merge "AnimEncoder API: Compute change rectangle for first frame too." -f00b639 Merge "AnimEncoder API: In Assemble(), always set animation parameters." -29ed796 Merge "AnimEncoder lib cleanup: prev to prev canvas not needed." -9f0dd6e Merge "WebPAnimEncoder API: Header and implementation" -5e56bbe AnimEncoder API: Remove AnimEncoderFrameOptions. -b902c3e AnimEncoder API: GenerateCandidates bugfix. -ef3c39b AnimEncoder API: Compute change rectangle for first frame too. -eec423a AnimEncoder API: In Assemble(), always set animation parameters. -ae1c046 AnimEncoder lib cleanup: prev to prev canvas not needed. -4b997ae WebPAnimEncoder API: Header and implementation -72208be move argb_*.o build target to encoder list -9592053 Merge "multi-thread fix: lock each entry points with a static var" -4c1b300 Merge "SSE2 implementation of VP8PackARGB" -fbcc200 Merge "add -Wformat-nonliteral and -Wformat-security" -80d950d add -Wformat-nonliteral and -Wformat-security -04c20e7 Merge "MIPS: dspr2: added optimization for function Intra4Preds" -a437694 multi-thread fix: lock each entry points with a static var -ca7f60d SSE2 implementation of VP8PackARGB -72d573f simplify the PackARGB signature -4e2589f demux: restore strict fragment flag check -4ba8e07 Merge "webp-container-spec: remove references to fragments" -e752f0a Merge "demux: remove experimental FRGM parsing" -f8abb11 Merge changes I109ec4d9,I73fe7743 -ae2188a MIPS: dspr2: added optimization for function Intra4Preds -1f4b864 move VP8EncDspARGBInit() call closer to where it's needed -14108d7 dec_neon: add DC8uvNoTop / DC8uvNoLeft -d8340da dec_neon: add DC8uv -a66e66c webp-container-spec: remove references to fragments -7ce8788 MIPS: dspr2: added optimization for function MakeARGB32 -012e623 demux: remove experimental FRGM parsing -87c3d53 method=0: Don't evaluate any predictor -6f4fcb9 Merge "MIPS: dspr2: added optimization for function ImportRow" -2428445 replace unneeded calls to HistogramCopy() by swaps -bdf7b40 MIPS: dspr2: added optimization for function ImportRow -e66a922 Merge "MIPS: dspr2: added optimization for function ExportRowC" -c279fec MIPS: dspr2: added optimization for function ExportRowC -31a9cf6 Speedup WebP lossless compression for low effort (m=0) mode with following: - Disable Cross-Color transform. - Evaluate predictors #11 (paeth), #12 and #13 only. -9275d91 MIPS: dspr2: added optimization for function TrueMotion -26106d6 Merge "enc_neon: fix building with non-Xcode clang (iOS)" -1c4e3ef unroll the kBands[] indirection to remove a dereference in GetCoeffs() -a3946b8 enc_neon: fix building with non-Xcode clang (iOS) -8ed9c00 Merge "simplify the Histogram struct, to only store max_value and last_nz" -bad7757 simplify the Histogram struct, to only store max_value and last_nz -3cca0dc MIPS: dspr2: Added optimization for DCMode function -37e395f MIPS: fix functions to use generic BPS istead of hardcoded value -9475bef PickBestUV: fix VP8Copy16x8 invocation -441f273 Merge changes I55f8da52,Id73a1e96 -4a279a6 cosmetics: add some missing != NULL comparisons -66ad372 factorize BPS definition in dsp.h and add VP8Copy16x8 -432e5b5 make ALIGN_xxx naming consistent -5760604 encoder: switch BPS to 32 instead of 16 -1b66bbe MIPS: dspr2: added optimization for function TransformColor_C -c6d0f9e histogram: cosmetics -f399d30 Merge changes I6eac17e5,I32d2b514 -9de9074 dec_neon: add TM8uv -8e517ec bit_reader/kVP8NewRange: range_t -> uint8_t -e185713 dsp: initialize VP8PredChroma8 in VP8DspInit() -e0c809a Move Entropy methods to lossless.c -a96ccf8 iosbuild: add x64_64 simulator support -a0df551 Remove handling for WEBP_HINT_GRAPH -413dfc0 Move static method definition before its usage. -0f23566 Update BackwardRefsWithLocalCache. -d69e36e Remove TODOs from lossless encoder code. -fdaac8e Optmize VP8LGetBackwardReferences LZ77 references. -2f0e2ba MIPS: dspr2: added optimization for function Select -a3e79a4 Merge "WebPEncode: Support encoding same pic twice (even if modified)" -e4f4ddd WebPEncode: Support encoding same pic twice (even if modified) -cbc3fbb Merge "Updated VP8LGetBackwardReferences and color cache." -95a9bd8 Updated VP8LGetBackwardReferences and color cache. -54f2c14 MIPS: dspr2: added optimization for function FTransform -aa42f42 MIPS: dspr2: Added optimization for function VP8LSubtractGreenFromBlueAndRed -11a25f7 Merge "FlattenSimilarBlocks should only be tried when blending is possible." -5cccdad FlattenSimilarBlocks should only be tried when blending is possible. -95ca44a MIPS: dspr2: added optimization for Disto4x4 -4171b67 backward_references.c: reindent after c8581b0 -c8581b0 Optimize BackwardReferences for RLE encoding. -5798eee MIPS: dspr2: unfilters bugfix (Ie7b7387478a6b5c3f08691628ae00f059cf6d899) -4167a3f Optimize backwardreferences -d18554c Merge "webp/types.h: use inline for clang++/-std=c++11" -7489b0e gif2webp: Add '-min-size' option to get best compression. -77bdddf Speed up BackwardReferences -6638710 webp/types.h: use inline for clang++/-std=c++11 -abf0420 Enable entropy based merge histo for (q<100) -572022a filters_mips_dsp_r2.c: disable unfilters -a28e21b MIPS: dspr2: Added optimization for function ClampedAddSubtractFull -18d5a1e MIPS: dspr2: added optimization for function ClampedAddSubtractHalf -829a8c1 MIPS: dspr2: added optimization for ITransform -c94ed49 gif2webp: Use the default hint instead of WEBP_HINT_GRAPH. -653ace5 Increase the MAX_COLOR_CACHE_BITS from 9 to 10. -919220c Change the logic adjusting the Histogram bits. -53b096c Merge "Fix bug in VP8LCalculateEstimateForCacheSize." -e912bd5 Fix bug in VP8LCalculateEstimateForCacheSize. -541d783 Merge "dec_neon: add RD4 intra predictor" -f8cd067 Merge "Makefile.vc: add a 'legacy' RTLIBCFG option" -22881c9 dec_neon: add RD4 intra predictor -613d281 update NEWS -1304eb3 Merge "dec_neon: DC4: use pair-wise adds for top row" -34c20c0 Makefile.vc: add a 'legacy' RTLIBCFG option -7083006 Merge "dsp/dec_{neon,sse2}: VE4: normalize variable names" -0db9031 dsp/dec_{neon,sse2}: VE4: normalize variable names -b5bc153 dec_neon: DC4: use pair-wise adds for top row -5b90d8f Unify the API between VP8BitWriter and VP8LBitWriter -f7ada56 Merge changes I2e06907b,Ia9ed4ca6,I782282ff -5beb6bf Merge "dec_neon: add VE4 intra predictor" -eba6ce0 dec_neon: add DC4 intra predictor -79abfbd dec_neon: add TM4 intra predictor -fe395f0 dec_neon: add LD4 intra predictor -32de385 dec_neon: add VE4 intra predictor -72395ba Merge "Modify CostModel to allocate optimal memory." -65e5eb8 gif2webp: Support GIF_DISPOSE_RESTORE_PREVIOUS -e4c829e gif2webp: Handle frames with odd offsets + disposal to background. -c2b5a03 Modify CostModel to allocate optimal memory. -b7a33d7 implement VE4/HE4/RD4/... in SSE2 -97c76f1 make VP8PredLuma4[] non-const and initialize array in VP8DspInit() -0ea8c6c Merge "PrintReg: output to stderr" -d7ff2f9 Merge "stopwatch.h: fix includes" -f85ec71 PrintReg: output to stderr -54edbf6 stopwatch.h: fix includes -139142e Optimize BackwardReferenceHashChainFollowPath. -5f36b68 enc/backward_references.c: fix indent -e0e9960 Merge "sync version numbers to 0.4.2 release" -64ac514 sync version numbers to 0.4.2 release -c24f895 Simplify and speedup Backward refs computation. -d1c359e fix shared object build with -fvisibility=hidden -a4c3a31 WEBP_TSAN_IGNORE_FUNCTION: fix gcc compat warning -f358eeb add code for testing random incremental decoding in dwebp -8024729 mark some init function as being safe for thread_sanitizer. -79b5bdb bit_reader.h: cosmetics: fix a typo -6c67368 Improved near-lossless mode. -0ce27e7 enc_mips32: workaround gcc-4.9 bug -aca1b98 enc/vp8l.c: fix indent -ca00502 Evaluate non-palette compression for palette image -c8a87bb AssignSegments: quiet -Warray-bounds warning -32f67e3 Merge "enc_neon: initialize vectors w/vdup_n_u32" -fabc65d 1-3% faster encoding optimizing SSE_NxN functions -7534d71 enc_neon: initialize vectors w/vdup_n_u32 -5f81391 Merge "Fix return code of EncodeImageInternal()" -e321abe Fix return code of EncodeImageInternal() -f82cb06 optimize palette ordering -f545fee don't set the alpha value for histogram index image -2d9b0a4 add WebPDispatchAlphaToGreen() to dsp -1bd4c2a Merge "Change Entropy based Histogram Combine heuristic." -e295b8f Merge "iosbuild: cleanup" -1be4e76 Merge "iosbuild: output autoconf req. on failure" -d5e498d Change Entropy based Histogram Combine heuristic. -47a2d8e fix MSVC float->int conversion warning -041956f iosbuild: cleanup -767eb40 iosbuild: output autoconf req. on failure -35ad48b HistoHeapInit: correct positions allocation size -45d9635 lossless: entropy clustering for high qualities. -dc37df8 fix type warning for VS9_x64 -9f7d9e6 iosbuild: make iOS 6 the minimum requirement -fdd6528 Remove unused VP8LDecoder member variable -ea3bba5 Merge "rewrite Disto4x4 in enc_neon.c with intrinsic" -f060dfc add lossless incremental decoding support -ab70794 rewrite Disto4x4 in enc_neon.c with intrinsic -d447163 MIPS: dspr2: added optimization for function FilterLoop24 -2aef54d Merge "prepare VP8LDecodeImage for incremental decode" -aed0f5a Merge "MIPS: dspr2: added optimization for function FilterLoop26" -2863068 prepare VP8LDecodeImage for incremental decode -248f3ae remove br->error_ field -49e1504 MIPS: dspr2: added optimization for function FilterLoop26 -38128cb iobuild.sh: only install .h files in Headers -c792d41 Premultiply with alpha during U/V downsampling -0cc811d gif2webp: Background color correction -d7167ff Amend the lossless spec according to issue #205, #206 and #224 -b901416 Record the lossless size stats. -cddd334 Add a WebPExtractAlpha function to dsp -0716a98 fix indent after I0204949917836f74c0eb4ba5a7f4052a4797833b -f9ced95 Optimize lossless decoding for trivial(ARB) codes. -924fcfd Merge "webpmux: simplify InitializeConfig()" -c0a462c webpmux: simplify InitializeConfig() -6986bb5 webpmux: fix indent -f89e169 webpmux: fix exit status on numeric value parse error -2172cb6 Merge "webpmux: fix loop_count range check" -e3b343e Merge "examples: warn on invalid numeric parameters" -0e23c48 webpmux: fix loop_count range check -6208338 Merge "fix loop bug in DispatchAlpha()" -d51f3e4 gif2webp: Handle frames with missing graphic control extension -690b491 fix loop bug in DispatchAlpha() -96d43a8 examples: warn on invalid numeric parameters -3101f53 MIPS: dspr2: added optimization for TransformOne -a6bb9b1 SSE2 for inverse Mult(ARGB)Row and ApplyAlphaMultiply -d84a8ff Remove default initialization of decoder status. -be70b86 configure: simplify libpng-config invocation -e0a9932 Rectify bug in lossless incremental decoding. -e2502a9 MIPS: dspr2: added optimization for TransformAC3 -24e1072 MIPS: dspr2: added optimization for TransformDC -c0e84df Merge "Slightly faster lossless decoding (1%)" -8dd28bb Slightly faster lossless decoding (1%) -f010359 MIPS: dspr2: added optimization for ColorIndexInverseTransforms -d3242ae make VP8LSetBitPos() set br->eos_ flag -a9decb5 Lossless decoding: fix eos_ flag condition -3fea6a2 fix erroneous dec->status_ setting -80b8099 MIPS: dspr2: add some specific mips code to commit I2c3f2b12f8df15b785fad5a9c56316e954ae0c53 -e564062 Merge "further refine the COPY_PATTERN optim for DecodeAlpha" -854509f enc/histogram.c: reindent after f4059d0 -3442196 Merge "~3-5% faster encoding optimizing PickBestIntra*()" -865069c further refine the COPY_PATTERN optim for DecodeAlpha -a595622 added C-level optimization for DecodeAlphaData function -187d379 add a fallback to ALPHA_NO_COMPRESSION -a48a2d7 ~3-5% faster encoding optimizing PickBestIntra*() -a614019 ExUtilReadFromStdin: (windows) open stdin in bin mode -e80eab1 webpmux: (windows) open stdout in binary mode -e9bfb11 cwebp: (windows) open stdout in binary mode -5927e15 example_util: add ExUtilSetBinaryMode -30f3b75 webpmux man page: Clarify some title, descriptions and examples -77d4c7e address cosmetic comments from patch #71380 -f75dfbf Speed up Huffman decoding for lossless -637b388 dsp/lossless: workaround gcc-4.9 bug on arm -8323a90 dsp.h: collect gcc/clang version test macros -e6c4b52 move static initialization of WebPYUV444Converters[] to the Init function. -49911d4 Merge "fix indentation" -f4059d0 Code cleanup for HistogramRemap. -e632b09 fix indentation -f5c04d6 Merge "add a DispatchAlpha() for SSE2 that handles 8 pixels at a time" -fc98edd add a DispatchAlpha() for SSE2 that handles 8 pixels at a time -73d361d introduce VP8EncQuantize2Blocks to quantize two blocks at a time -0b21c30 MIPS: dspr2: added optimization for EmitAlphaRGB -953acd5 enc_neon: enable QuantizeBlock for aarch64 -f4ae143 MIPS: mips32: code rebase -5697715 MIPS: dspr2: added optimizations for VP8YuvTo* -2523aa7 SmartRGBYUV: fix odd-width problem with pixel replication -ee52dc4 fix some MSVC64 warning about float conversion -3fca851 cpu: check for _MSC_VER before using msvc inline asm -e2a83d7 faster RGB->YUV conversion function (~7% speedup) -de2d03e Merge "Add smart RGB->YUV conversion option -pre 4" -3fc4c53 Add smart RGB->YUV conversion option -pre 4 -b4dc406 MIPS: dspr2: added optimization for (un)filters -137e609 Merge "configure: add work around for gcc-4.9 aarch64 bug" -b61c9ce MIPS: dspr2: Optimization of some simple point-sampling functions -e2b8cec configure: add work around for gcc-4.9 aarch64 bug -98c5410 MIPS: mips32r2: added optimization for BSwap32 -dab702b Update PATENTS to reflect s/VP8/WebM/g -b564f7c Merge "MIPS: detect mips32r6 and disable mips32r1 code" -b7e5a5c MIPS: detect mips32r6 and disable mips32r1 code -63c2fc0 Correctly use the AC_CANONICAL_* macros -bb07022 Merge "cosmetics" -e300c9d cosmetics -0e519ee Merge "cosmetics: remove some extraneous 'extern's" -3ef0f08 Merge "vp8enci.h: cosmetics: fix '*' placement" -4c6dde3 bit_writer: cosmetics: rename kFlush() -> Flush() -f7b4c48 cosmetics: remove some extraneous 'extern's -b47fb00 vp8enci.h: cosmetics: fix '*' placement -b5a36cc add -near_lossless [0..100] experimental option -0524d9e dsp: detect mips64 & disable mips32 code -d3485d9 cwebp.1: fix quality description placement -29a9fe2 Merge tag 'v0.4.1' -8af2771 update ChangeLog (tag: v0.4.1, origin/0.4.1, 0.4.1) -e09e9ff Record & log the image pre-processing time. -f59c0b4 iosbuild.sh: specify optimization flags -8d34ea3 update ChangeLog (tag: v0.4.1-rc1) -dbc3da6 makefile.unix: add vwebp.1 to the dist target -89a7c83 update ChangeLog -ffe67ee Merge "update NEWS for the next release" into 0.4.1 -2def1fe gif2webp: dust up the help message -fb668d7 remove -noalphadither option from README/vwebp.1 -e49f693 update NEWS for the next release -cd01358 Merge "update AUTHORS" into 0.4.1 -268d01e update AUTHORS -85213b9 bump version to 0.4.1 -695f80a Merge "restore mux API compatibility" into 0.4.1 -862d296 restore mux API compatibility -8f6f8c5 remove the !WEBP_REFERENCE_IMPLEMENTATION tweak in Put8x8uv -d713a69 Merge changes If4debc15,I437a5d5f into 0.4.1 -c2fc52e restore encode API compatibility -793368e restore decode API compatibility -b8984f3 gif2webp: fix compile with giflib 5.1.0 -222f9b1 gif2webp: simplify giflib version checking -d2cc61b Extend MakeARGB32() to accept Alpha channel. -4595b62 Merge "use explicit size of kErrorMessages[] arrays" -157de01 Merge "Actuate memory stats for PRINT_MEMORY_INFO" -fbda2f4 JPEG decoder: delay conversion to YUV to WebPEncode() call -0b747b1 use explicit size of kErrorMessages[] arrays -3398d81 Actuate memory stats for PRINT_MEMORY_INFO -6f3202b Merge "move WebPPictureInit to picture.c" -6c347bb move WebPPictureInit to picture.c -fb3acf1 fix configure message for multi-thread -40b086f configure: check for _beginthreadex -1549d62 reorder the YUVA->ARGB and ARGB->YUVA functions correctly -c6461bf Merge "extract colorspace code from picture.c into picture_csp.c" -736f2a1 extract colorspace code from picture.c into picture_csp.c -645daa0 Merge "configure: check for -Wformat-security" -abafed8 configure: check for -Wformat-security -fbadb48 split monolithic picture.c into picture_{tools,psnr,rescale}.c -c76f07e dec_neon/TransformAC3: initialize vector w/vcreate -bb4fc05 gif2webp: Allow single-frame animations -46fd44c thread: remove harmless race on status_ in End() -5a1a726 Merge "configure: check for __builtin_bswapXX()" -6781423 configure: check for __builtin_bswapXX() -6450c48 configure: fix iOS builds -6422e68 VP8LFillBitWindow: enable fast path for 32-bit builds -4f7f52b VP8LFillBitWindow: respect WEBP_FORCE_ALIGNED -e458bad endian_inl.h: implement htoleXX with BSwapXX -f2664d1 endian_inl.h: add BSwap16 -6fbf534 Merge "configure: add --enable-aligned" -dc0f479 configure: add --enable-aligned -9cc69e2 Merge "configure: support WIC + OpenGL under mingw64" -257adfb remove experimental YUV444 YUV422 and YUV400 code -10f4257 configure: support WIC + OpenGL under mingw64 -380cca4 configure.ac: add AC_C_BIGENDIAN -ee70a90 endian_inl.h: add BSwap64 -47779d4 endian_inl.h: add BSwap32 -d5104b1 utils: add endian_inl.h -58ab622 Merge "make alpha-detection loop in IsKeyFrame() in good x/y order" -9d56290 make alpha-detection loop in IsKeyFrame() in good x/y order -516971b lossless: Remove unaligned read warning -b8b596f Merge "configure.ac: add an autoconf version prerequisite" -34b02f8 configure.ac: add an autoconf version prerequisite -e59f536 neon: normalize vdup_n_* usage -6ee7160 Merge changes I0da7b3d3,Idad2f278,I4accc305 -abc02f2 Merge "fix (uncompiled) typo" -bc03670 neon: add INIT_VECTOR4 -6c1c632 neon: add INIT_VECTOR3 -dc7687e neon: add INIT_VECTOR2 -4536e7c add WebPMuxSetCanvasSize() to the mux API -824eab1 fix (uncompiled) typo -1f3e5f1 remove unused 'shift' argument and QFIX2 define -8e86705 Merge "VP8LoadNewBytes: use __builtin_bswap32 if available" -1b6a263 Merge "Fix handling of weird GIF with canvas dimension 0x0" -1da3d46 VP8LoadNewBytes: use __builtin_bswap32 if available -1582e40 Fix handling of weird GIF with canvas dimension 0x0 -b8811da Merge "rename interface -> winterface" -db8b8b5 Fix logic in the GIF LOOP-detection parsing -25aaddc rename interface -> winterface -5584d9d make WebPSetWorkerInterface() check its arguments -a9ef7ef Merge "cosmetics: update thread.h comments" -c6af999 Merge "dust up the help message" -0a8b886 dust up the help message -a9cf319 cosmetics: update thread.h comments -27bfeee QuantizeBlock SSE2 Optimization: -2bc0dc3 Merge "webpmux: warn when odd frame offsets are used" -3114ebe Merge changes Id8edd3c1,Id418eb96,Ide05e3be -c072663 webpmux: warn when odd frame offsets are used -c5c6b40 Merge "add alpha dithering for lossy" -d514678 examples/Android.mk: add cwebp -ca0fa7c Android.mk: move dwebp to examples/Android.mk -73d8fca Android.mk: add ENABLE_SHARED flag -6e93317 muxread: fix out of bounds read -8b0f6a4 Makefile.vc: fix CFLAGS assignment w/HAVE_AVX2=1 -bbe32df add alpha dithering for lossy -7902076 Merge "make error-code reporting consistent upon malloc failure" -77bf441 make error-code reporting consistent upon malloc failure -7a93c00 **/Makefile.am: remove unused AM_CPPFLAGS -24e3080 Add an interface abstraction to the WebP worker thread implementation -d6cd635 Merge "fix orig_rect==NULL case" -2bfd1ff fix orig_rect==NULL case -059e21c Merge "configure: move config.h to src/webp/config.h" -f05fe00 properly report back encoding error code in WebPFrameCacheAddFrame() -32b3137 configure: move config.h to src/webp/config.h -90090d9 Merge changes I7c675e51,I84f7d785 -ae7661b makefiles: define WEBP_HAVE_AVX2 when appropriate -69fce2e remove the special casing for res->first in VP8SetResidualCoeffs -6e61a3a configure: test for -msse2 -b9d2efc rename upsampling_mips32.c to yuv_mips32.c -bdfeeba dsp/yuv: move sse2 functions to yuv_sse2.c -46b32e8 Merge "configure: set WEBP_HAVE_AVX2 when available" -88305db Merge "VP8RandomBits2: prevent signed int overflow" -73fee88 VP8RandomBits2: prevent signed int overflow -db4860b enc_sse2: prevent signed int overflow -3fdaf4d Merge "real fix for longjmp warning" -385e334 real fix for longjmp warning -230a055 configure: set WEBP_HAVE_AVX2 when available -a2ac8a4 restore original value_/range_ field order -5e2ee56 Merge "remove libwebpdspdecode dep on libwebpdsp_avx2" -61362db remove libwebpdspdecode dep on libwebpdsp_avx2 -42c447a Merge "lossy bit-reader clean-up:" -479ffd8 Merge "remove unused #include's" -9754d39 Merge "strong filtering speed-up (~2-3% x86, ~1-2% for NEON)" -158aff9 remove unused #include's -09545ee lossy bit-reader clean-up: -ea8b0a1 strong filtering speed-up (~2-3% x86, ~1-2% for NEON) -6679f89 Optimize VP8SetResidualCoeffs. -ac591cf fix for gcc-4.9 warnings about longjmp + local variables -4dfa86b dsp/cpu: NaCl has no support for xgetbv -4c39869 Merge "cwebp: fallback to native webp decode in WIC builds" -33aa497 Merge "cwebp: add some missing newlines in longhelp output" -c9b340a fix missing WebPInitAlphaProcessing call for premultiplied colorspace output -57897ba Merge "lossless_neon: use vcreate_*() where appropriate" -6aa4777 Merge "(enc|dec)_neon: use vcreate_*() where appropriate" -0d346e4 Always reinit VP8TransformWHT instead of hard-coding -7d039fc cwebp: fallback to native webp decode in WIC builds -d471f42 cwebp: add some missing newlines in longhelp output -bf0e003 lossless_neon: use vcreate_*() where appropriate -9251c2f (enc|dec)_neon: use vcreate_*() where appropriate -399b916 lossy decoding: correct alpha-rescaling for YUVA format -78c12ed Merge "Makefile.vc: add rudimentary avx2 support" -dc5b122 try to remove the spurious warning for static analysis -ddfefd6 Makefile.vc: add rudimentary avx2 support -a891164 Merge "simplify VP8LInitBitReader()" -fdbcd44 simplify VP8LInitBitReader() -7c00428 makefile.unix: add rudimentary avx2 support -515e35c Merge "add stub dsp/enc_avx2.c" -a05dc14 SSE2: yuv->rgb speed-up for point-sampling -178e9a6 add stub dsp/enc_avx2.c -1b99c09 Merge "configure: add a test for -mavx2" -fe72807 configure: add a test for -mavx2 -e46a247 cpu: fix check for __cpuidex availability -176fda2 fix the bit-writer for lossless in 32bit mode -541784c dsp.h: add a check for AVX2 / define WEBP_USE_AVX2 -bdb151e dsp/cpu: add AVX2 detection -ab9f2f8 Merge "revamp the point-sampling functions by processing a full plane" -a2f8b28 revamp the point-sampling functions by processing a full plane -ef07602 use decoder's DSP functions for autofilter -2b5cb32 Merge "dsp/cpu: add AVX detection" -df08e67 dsp/cpu: add AVX detection -e2f405c Merge "clean-up and slight speed-up in-loop filtering SSE2" -f60957b clean-up and slight speed-up in-loop filtering SSE2 -9fc3ae4 .gitattributes: treat .ppm as binary -3da924b Merge "dsp/WEBP_USE_NEON: test for __aarch64__" -c716449 Android.mk: always include *_neon.c in the build -a577b23 dsp/WEBP_USE_NEON: test for __aarch64__ -54bfffc move RemapBitReader() from idec.c to bit_reader code -34168ec Merge "remove all unused layer code" -f1e7717 remove all unused layer code -b0757db Code cleanup for VP8LGetHistoImageSymbols. -5fe628d make the token page size be variable instead of fixed 8192 -f948d08 memory debug: allow setting pre-defined malloc failure points -ca3d746 use block-based allocation for backward refs storage, and free-lists -1ba61b0 enable NEON intrinsics in aarch64 builds -b9d2bb6 dsp/neon.h: coalesce intrinsics-related defines -b5c7525 iosbuild: add support for iOSv7/aarch64 -9383afd Reduce number of memory allocations while decoding lossless. -888e63e Merge "dsp/lossless: prevent signed int overflow in left shift ops" -8137f3e Merge "instrument memory allocation routines for debugging" -2aa1873 instrument memory allocation routines for debugging -d3bcf72 Don't allocate VP8LHashChain, but treat like automatic object -bd6b861 dsp/lossless: prevent signed int overflow in left shift ops -b7f19b8 Merge "dec/vp8l: prevent signed int overflow in left shift ops" -29059d5 Merge "remove some uint64_t casts and use." -e69a1df dec/vp8l: prevent signed int overflow in left shift ops -cf5eb8a remove some uint64_t casts and use. -38e2db3 MIPS: MIPS32r1: Added optimization for HistogramAdd. -e0609ad dwebp: fix exit code on webp load failure -bbd358a Merge "example_util.h: avoid forward declaring enums" -8955da2 example_util.h: avoid forward declaring enums -6d6865f Added SSE2 variants for Average2/3/4 -b3a616b make HistogramAdd() a pointer in dsp -c8bbb63 dec_neon: relocate some inline-asm defines -4e393bb dec_neon: enable intrinsics-only functions -ba99a92 dec_neon: use positive tests for USE_INTRINSICS -69058ff Merge "example_util: add ExUtilDecodeWebPIncremental" -a7828e8 dec_neon: make WORK_AROUND_GCC conditional on version -3f3d717 Merge "enc_neon: enable intrinsics-only functions" -de3cb6c Merge "move LOCAL_GCC_VERSION def to dsp.h" -1b2fe14 example_util: add ExUtilDecodeWebPIncremental -ca49e7a Merge "enc_neon: move Transpose4x4 to dsp/neon.h" -ad900ab Merge "fix warning about size_t -> int conversion" -4825b43 fix warning about size_t -> int conversion -42b35e0 enc_neon: enable intrinsics-only functions -f937e01 move LOCAL_GCC_VERSION def to dsp.h -5e1a17e enc_neon: move Transpose4x4 to dsp/neon.h -c7b92a5 dec_neon: (WORK_AROUND_GCC) delete unused Load4x8 -8e5f90b Merge "make ExUtilLoadWebP() accept NULL bitstream param." -05d4c1b Merge "cwebp: add webpdec" -ddeb6ac cwebp: add webpdec -35d7d09 Merge "Reduce memory footprint for encoding WebP lossless." -0b89610 Reduce memory footprint for encoding WebP lossless. -f0b65c9 make ExUtilLoadWebP() accept NULL bitstream param. -9c0a60c Merge "dwebp: move webp decoding to example_util" -1d62acf MIPS: MIPS32r1: Added optimization for HuffmanCost functions. -4a0e739 dwebp: move webp decoding to example_util -c022046 Merge "Bugfix: Incremental decode of lossy-alpha" -8c7cd72 Bugfix: Incremental decode of lossy-alpha -7955152 MIPS: fix error with number of registers. -b1dabe3 Merge "Move the HuffmanCost() function to dsp lib" -75b1200 Move the HuffmanCost() function to dsp lib -2772b8b MIPS: fix assembler error revealed by clang's debug build -6653b60 enc_mips32: fix unused symbol warning in debug -8dec120 enc_mips32: disable ITransform(One) in debug builds -98519dd enc_neon: convert Disto4x4 to intrinsics -fe9317c cosmetics: -953b074 enc_neon: cosmetics -a9fc697 Merge "WIP: extract the float-calculation of HuffmanCost from loop" -3f84b52 Merge "replace some mult-long (vmull_u8) with mult-long-accumulate (vmlal_u8)" -4ae0533 MIPS: MIPS32r1: Added optimizations for ExtraCost functions. -b30a04c WIP: extract the float-calculation of HuffmanCost from loop -a8fe8ce Merge "NEON intrinsics version of CollectHistogram" -95203d2 NEON intrinsics version of CollectHistogram -7ca2e74 replace some mult-long (vmull_u8) with mult-long-accumulate (vmlal_u8) -41c6efb fix lossless_neon.c -8ff96a0 NEON intrinsics version of FTransform -0214f4a Merge "MIPS: MIPS32r1: Added optimizations for FastLog2" -baabf1e MIPS: MIPS32r1: Added optimizations for FastLog2 -3d49871 NEON functions for lossless coding -3fe0291 MIPS: MIPS32r1: Added optimizations for SSE functions. -c503b48 Merge "fix the gcc-4.6.0 bug by implementing alternative method" -abe6f48 fix the gcc-4.6.0 bug by implementing alternative method -5598bde enc_mips32.c: fix file mode -2b1b4d5 MIPS: MIPS32r1: Add optimization for GetResidualCost -f0a1f3c Merge "MIPS: MIPS32r1: Added optimization for FTransform" -7231f61 MIPS: MIPS32r1: Added optimization for FTransform -869eaf6 ~30% encoding speedup: use NEON for QuantizeBlock() -f758af6 enc_neon: convert FTransformWHT to intrinsics -7dad095 MIPS: MIPS32r1: Added optimization for Disto4x4 (TTransform) -2298d5f MIPS: MIPS32r1: Added optimization for QuantizeBlock -e88150c Merge "MIPS: MIPS32r1: Add optimization for ITransform" -de693f2 lossless_neon: disable VP8LConvert* functions -4143332 NEON intrinsics for encoding -0ca2914 MIPS: MIPS32r1: Add optimization for ITransform -71bca5e dec_neon: use vst_lane instead of vget_lane -bf06105 Intrinsics NEON version of TransformOne -19c6f1b Merge "dec_neon: use vld?_lane instead of vset?_lane" -7a94c0c upsampling_neon: drop NEON suffix from local functions -d14669c upsampling_sse2: drop SSE2 suffix from local functions -2ca42a4 enc_sse2: drop SSE2 suffix from local functions -d038e61 dec_sse2: drop SSE2 suffix from local functions -fa52d75 dec_neon: use vld?_lane instead of vset?_lane -c520e77 cosmetic: fix long line -4b0f2da Merge "add intrinsics NEON code for chroma strong-filtering" -e351ec0 add intrinsics NEON code for chroma strong-filtering -aaf734b Merge "Add SSE2 version of forward cross-color transform" -c90a902 Add SSE2 version of forward cross-color transform -bc374ff Use histogram_bits to initalize transform_bits. -2132992 Merge "Add strong filtering intrinsics (inner and outer edges)" -5fbff3a Add strong filtering intrinsics (inner and outer edges) -d4813f0 Add SSE2 function for Inverse Cross-color Transform -2602956 dec_neon: add strong loopfilter intrinsics -cca7d7e Merge "add intrinsics version of SimpleHFilter16NEON()" -1a05dfa windows: fix dll builds -d6c50d8 Merge "add some colorspace conversion functions in NEON" -4fd7c82 SSE2 variants of Subtract-Green: Rectify loop condition -97e5fac add some colorspace conversion functions in NEON -b9a7a45 add intrinsics version of SimpleHFilter16NEON() -daccbf4 add light filtering NEON intrinsics -af44460 fix typo in STORE_WHT -6af6b8e Tune HistogramCombineBin for large images. -af93bdd use WebPSafe[CM]alloc/WebPSafeFree instead of [cm]alloc/free -51f406a lossless_sse2: relocate VP8LDspInitSSE2 proto -0f4f721 separate SSE2 lossless functions into its own file -514fc25 VP8LConvertFromBGRA: use conversion function pointers -6d2f352 dsp/dec: TransformDCUV: use VP8TransformDC -defc8e1 Merge "fix out-of-bound read during alpha-plane decoding" -fbed364 Merge "dsp: reuse wht transform from dec in encoder" -d846708 Merge "Add SSE2 version of ARGB -> BGR/RGB/... conversion functions" -207d03b fix out-of-bound read during alpha-plane decoding -d1b33ad 2-5% faster trellis with clang/MacOS (and ~2-3% on ARM) -369c26d Add SSE2 version of ARGB -> BGR/RGB/... conversion functions -df230f2 dsp: reuse wht transform from dec in encoder -80e218d Android.mk: fix build with APP_ABI=armeabi-v7a-hard -59daf08 Merge "cosmetics:" -5362200 cosmetics: -3e7f34a AssignSegments: quiet array-bounds warning -3c2ebf5 Merge "UpdateHistogramCost: avoid implicit double->float" -cf821c8 UpdateHistogramCost: avoid implicit double->float -312e638 Extend the search space for GetBestGreenRedToBlue -1c58526 Fix few nits -fef2270 Optimize and re-structure VP8LGetHistoImageSymbols -068b14a Optimize lossless decoding. -5f0cfa8 Do a binary search to get the optimum cache bits. -24ca367 Merge "allow 'cwebp -o -' to emit output to stdout" -e12f874 allow 'cwebp -o -' to emit output to stdout -2bcad89 allow some more stdin/stout I/O -84ed4b3 fix cwebp.1 typos after patch #69199 -65b99f1 add a -z option to cwebp, and WebPConfigLosslessPreset() function -3017661 4-5% faster trellis by removing some unneeded calculations. -687a58e histogram.c: reindent after b33e8a0 -06d456f Merge "~3-4% faster lossless encoding" -c60de26 ~3-4% faster lossless encoding -42eb06f Merge "few cosmetics after patch #69079" -82af826 few cosmetics after patch #69079 -b33e8a0 Refactor code for HistogramCombine. -ca1bfff Merge "5-10% encoding speedup with faster trellis (-m 6)" -5aeeb08 5-10% encoding speedup with faster trellis (-m 6) -82ae1bf cosmetics: normalize VP8GetCPUInfo checks -e3dd924 Merge "Refactor GetBestPredictorForTile for future tuning." -206cc1b Refactor GetBestPredictorForTile for future tuning. -3cb8406 Merge "speed-up trellis quant (~5-10% overall speed-up)" -b66f222 Merge "lossy encoding: ~3% speed-up" -4287d0d speed-up trellis quant (~5-10% overall speed-up) -390c8b3 lossy encoding: ~3% speed-up -9a463c4 Merge "dec_neon: convert TransformWHT to intrinsics" -e8605e9 Merge "dec_neon: add ConvertU8ToS16" -4aa3e41 MIPS: MIPS32r1: rescaler bugfix -c16cd99 Speed up lossless encoder. -9d6b5ff dec_neon: convert TransformWHT to intrinsics -2ff0aae dec_neon: add ConvertU8ToS16 -77a8f91 fix compilation with USE_YUVj flag -4acbec1 Merge changes I3b240ffb,Ia9370283,Ia2d28728 -2719bb7 dec_neon: TransformAC3: work on packed vectors -b7b60ca dec_neon: add SaturateAndStore4x4 -b7685d7 Rescale: let ImportRow / ExportRow be pointer-to-function -e02f16e dec_neon.c: convert TransformDC to intrinsics -9cba963 add missing file -8992ddb use static clipping tables -0235d5e 1-2% faster quantization in SSE2 -b2fbc36 fix VC12-x64 warning -6e37cb9 Merge "cosmetics: backward_references.c: reindent after a7d2ee3" -a42ea97 cosmetics: backward_references.c: reindent after a7d2ee3 -6c32744 Merge "fix missing __BIG_ENDIAN__ definition on some platform" -a8b6aad fix missing __BIG_ENDIAN__ definition on some platform -fde2904 Increase initial buffer size for VP8L Bit Writer. -a7d2ee3 Optimize cache estimate logic. -7fb6095 Merge "dec_neon.c: add TransformAC3" -bf182e8 VP8LBitWriter: use a bit-accumulator -3f40b4a Merge "MIPS: MIPS32r1: clang macro warning resolved" -1684f4e WebP Decoder: Mark some truncated bitstreams as invalid -acbedac MIPS: MIPS32r1: clang macro warning resolved -228e487 dec_neon.c: add TransformAC3 -393f89b Android.mk: avoid gcc-specific flags with clang -32aeaf1 revamp VP8LColorSpaceTransform() a bit -0c7cc4c Merge "Don't dereference NULL, ensure HashChain fully initialized" -391316f Don't dereference NULL, ensure HashChain fully initialized -926ff40 WEBP_SWAP_16BIT_CSP: remove code dup -1d1cd3b Fix decode bug for rgbA_4444/RGBA_4444 color-modes. -939e70e update AUTHORS file -8934a62 cosmetics: *_mips32.c -dd438c9 MIPS: MIPS32r1: Optimization of some simple point-sampling functions. PATCH [6/6] -5352091 Added support for calling sampling functions via pointers. -d16c697 MIPS: MIPS32r1: Optimization of filter functions. PATCH [5/6] -04336fc MIPS: MIPS32r1: Optimization of function TransformOne. PATCH [4/6] -92d8fc7 MIPS: MIPS32r1: Optimization of function WebPRescalerImportRow. PATCH [3/6] -bbc23ff parse one row of intra modes altogether -a2f608f Merge "MIPS: MIPS32r1: Optimization of function WebPRescalerExportRow. [2/6]" -8823085 MIPS: MIPS32r1: Optimization of function WebPRescalerExportRow. [2/6] -c5a5b02 decode mt+incremental: fix segfault in debug builds -9882b2f always use fast-analysis for all methods. -000adac Merge "autoconf: update ax_pthread.m4" -2d2fc37 update .gitignore -5bf4255 Merge "Make it possible to avoid automagic dependencies" -c1cb193 disable NEON for arm64 platform -73a304e Make it possible to avoid automagic dependencies -4d493f8 MIPS: MIPS32r1: Decoder bit reader function optimized. PATCH [1/6] -c741183 make WebPCleanupTransparentArea work with argb picture -5da1855 add a decoding option to flip image vertically -00c3c4e Merge "add man/vwebp.1" -2c6bb42 add man/vwebp.1 -ea59a8e Merge "Merge tag 'v0.4.0'" -7574bed fix comments related to array sizes -0b5a90f dwebp.1: fix option formatting -effcb0f Merge tag 'v0.4.0' -7c76255 autoconf: update ax_pthread.m4 -fff2a11 make -short work with -print_ssim, -print_psnr, etc. -68e7901 update ChangeLog (tag: v0.4.0-rc1, tag: v0.4.0, origin/0.4.0, 0.4.0) -256e433 update NEWS description with new general features -2962534 Merge "gif2webp: don't use C99 %zu" into 0.4.0 -3b9f9dd gif2webp: don't use C99 %zu -b5b2e3c cwebp: fix metadata output w/lossy+alpha -ad26df1 makefile.unix: clean up libgif2webp_util.a -c3b4557 update Changelog -ca84112 Merge "bump version to 0.4.0" into 0.4.0 -8c524db bump version to 0.4.0 -eec2398 update AUTHORS & .mailmap -b9bbf6a update NEWS for 0.4.0 -c72e081 Merge "dec/webp.c: don't wait for data before reporting w/h" -5ad6531 dec/frame.c: fix formatting -f7fc4bc dec/webp.c: don't wait for data before reporting w/h -66a32af Merge "NEON speed up" -26d842e NEON speed up -f307f98 Merge "webpmux: let -- stop parameter parsing" -fe051da Merge "README: add a section on gif2webp" -6fd2bd6 Merge "manpage pedantry" -4af1900 README: add a section on gif2webp -6f36ade manpage pedantry -f9016cb README: update dwebp options -b4fa0a4 webpmux: let -- stop parameter parsing -a9a20ac gif2webp: Add a multi-threaded encode option -495bef4 fix bug in TrellisQuantize -605a712 simplify __cplusplus ifdef -33109f9 Merge "drop: ifdef __cplusplus checks from C files" -7f9de0b Merge changes I994a5587,I8467bb71,I13b50688,I1e2c9c7b -5459030 gif2webp: let -- stop parameter parsing -a4b0aa0 vwebp: let -- stop parameter parsing -98af68f cwebp: let -- stop parameter parsing -a33831e dwebp: let -- stop parameter parsing -3630124 add some checks on error paths -ce4c713 Merge "autoconf: add --disable-wic" -5227d99 drop: ifdef __cplusplus checks from C files -f645355 dwebp.1: fix typo -f91034f Merge "cwebp: print metadata stats when no output file is given" -d493455 gif2webp: Backward compatibility for giflib version <= 4.1.3 -4c617d3 gif2webp: Disable output of ICC profile by default -73b731f introduce a special quantization function for WHT -41c0cc4 Make Forward WHT transform use 32bit fixed-point calculation -a3359f5 Only compute quantization params once -7049043 cwebp: print metadata stats when no output file is given -d513bb6 * fix off-by-one zthresh calculation * remove the sharpening for non luma-AC coeffs * adjust the bias a little bit to compensate for this -ad9dec0 Merge "cosmetics: dwebp: fix local function name format" -f737f03 Merge "dwebp: remove a dead store" -3c3a70d Merge "makefile.unix: install binaries in $(DESTDIR)/bin/" -150b655 Merge "Android.mk: add some release compile flags" -dbebd33 cosmetics: dwebp: fix local function name format -2774995 dwebp: remove a dead store -a01e04f autoconf: add --disable-wic -5009b22 makefile.unix: install binaries in $(DESTDIR)/bin/ -bab30fc Merge "fix -print_psnr / ssim options" -ebef7fb fix -print_psnr / ssim options -cb63785 Merge "fix bug due to overzealous check in WebPPictureYUVAToARGB()" -8189885 Merge "EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE" -4ad7d33 Android.mk: add some release compile flags -c12e236 cosmetics: fix a few typos -6f10403 fix bug due to overzealous check in WebPPictureYUVAToARGB() -3f6c35c EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE -cc55790 Merge changes I8bb7a4dc,I2c180051,I021a014f,I8a224a62 -c536afb Merge "cosmetics: fix some typos" -cbdd3e6 add a -dither dithering option to the decoder -e812401 Updated iosbuild.sh for XCode 5.x -4931c32 cosmetics: fix some typos -05aacf7 mux: add some missing casts -617d934 enc/vp8l: add a missing cast -46db286 idec: add some missing casts -b524e33 ErrorStatusLossless: correct return type -cb261f7 fix a descaling bug for vertical/horizontal U/V interpolation -bcb3955 Merge changes I48968468,I181bc736 -73f5213 gif2webp: Add a mixed compression mode -6198715 demux: split chunk parsing from ParseVP8X -d2e3f4e demux: add a tail pointer for chunks -87cffcc demux: cosmetics: s/has_frames/is_animation/ -e18e667 demux: strictly enforce the animation flag -c4f39f4 demux: cosmetics: remove a useless break -61cb884 demux: (non-exp) fail if the fragmented flag is set -ff379db few % speedup of lossless encoding -df3649a remove all disabled code related to P-frames -6d0cb3d Merge "gif2webp: kmin = 0 should suppress key-frame addition." -3655598 gif2webp: kmin = 0 should suppress key-frame addition. -7708e60 Merge "detect flatness in blocks and favor DC prediction" -06b1503 Merge "add comment about the kLevelsFromDelta[][] LUT generation" -5935259 add comment about the kLevelsFromDelta[][] LUT generation -e3312ea detect flatness in blocks and favor DC prediction -ebc9b1e Merge "VPLBitReader bugfix: Catch error if bit_pos > LBITS too." -96ad0e0 VPLBitReader bugfix: Catch error if bit_pos > LBITS too. -a014e9c tune quantization biases toward higher precision -1e89861 add helpful PrintBlockInfo() function -596a6d7 make use of 'extern' consistent in function declarations -c8d48c6 Merge "extract random utils to their own file util/random.[ch]" -98aa33c extract random utils to their own file util/random.[ch] -432a723 Merge "swig: add basic go bindings" -fab618b Merge "rename libwebp.i -> libwebp.swig" -e4e7fcd swig: add basic go bindings -d340872 Merge "fast auto-determined filtering strength" -f8bfd5c fast auto-determined filtering strength -ac0bf95 small clean-up in ExpandMatrix() -1939607 rename libwebp.i -> libwebp.swig -43148b6 filtering: precompute ilimit and hev_threshold -18f992e simplify f_inner calculation a little -241d11f add missing const -86c0031 add a 'format' field to WebPBitstreamFeatures -dde91fd Demux: Correct the extended format validation -5d6c5bd add entry for '-resize' option in cwebp's man -7c098d1 Use some gamma-curve range compression when computing U/V average -0b2b050 Use deterministic random-dithering during RGB->YUV conversion -8a2fa09 Add a second multi-thread method -7d6f2da Merge "up to 20% faster multi-threaded decoding" -266f63e Merge "libwebp.jar: build w/Java 1.6 for Android compat" -0532149 up to 20% faster multi-threaded decoding -38efdc2 Simplify the gif2webp tool: move the optimization details to util -de89951 libwebp.jar: build w/Java 1.6 for Android compat -cb22155 Decode a full row of bitstream before reconstructing -dca8a4d Merge "NEON/simple loopfilter: avoid q4-q7 registers" -9e84d90 Merge "NEON/TransformWHT: avoid q4-q7 registers" -fc10249 NEON/simple loopfilter: avoid q4-q7 registers -2f09d63 NEON/TransformWHT: avoid q4-q7 registers -77585a2 Merge "use a macrofunc for setting NzCoeffs bits" -d155507 Merge "use HINT_GRAPH as image_hint for gif source" -9c56164 Merge "only print GIF_DISPOSE_WARNING once" -0587986 use HINT_GRAPH as image_hint for gif source -0b28d7a use a macrofunc for setting NzCoeffs bits -f9bbc2a Special-case sparse transform -0012519 gif2webp: detect and flatten uniformly similar blocks -0deaf0f only print GIF_DISPOSE_WARNING once -6a8c0eb Merge "small optimization in segment-smoothing loop" -f7146bc small optimization in segment-smoothing loop -5a7533c small gif2webp fix -4df0c89 Merge changes Ic697660c,I27285521 -5b2e6bd Android.mk: add a dwebp target -f910a84 Android.mk: update build flags -63f9aba special-case WHT transform when there's only DC -80911ae Merge "7-8% faster decoding by rewriting GetCoeffs()" -606c430 gif2webp: Improved compression for lossy animated WebP -fb887f7 gif2webp: Different kmin/kmax defaults for lossy and lossless -2a98136 7-8% faster decoding by rewriting GetCoeffs() -92d47e4 improve VP8L signature detection by checking the version bits too -5cd43e4 Add -incremental option to dwebp -54b8e3f webpmux: DisplayInfo(): remove unnecessary error checks. -40ae352 fix memleak in WebPIDelete() -d966265 mux.h doc: WebPMuxGetFrame() can return WEBP_MUX_MEMORY_ERROR too. -0e6747f webpmux -info: display dimensions and has_alpha per frame -d78a82c Sanity check for underflow -8498f4b Merge "remove -Wshadow warnings" -e89c6fc Avoid a potential memleak -3ebe175 Merge "break down the proba 4D-array into some handy structs" -6a44550 break down the proba 4D-array into some handy structs -2f5e893 remove -Wshadow warnings -bf3a29b Merge "add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags" -2b0a759 Merge "fix some warnings from static analysis" -22dd07c mux.h: Some doc corrections -79ff034 add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags -d51f45f fix some warnings from static analysis -d134307 fix conversion warning on MSVC -d538cea gif2webp: Support a 'min' and 'max' key frame interval -80b54e1 allow search with token buffer loop and fix PARTITION0 problem -b7d4e04 add VP8EstimateTokenSize() -10fddf5 enc/quant.c: silence a warning -399cd45 Merge "fix compile error on ARM/gcc" -9f24519 encoder: misc rate-related fixes -c663bb2 Merge "simplify VP8IteratorSaveBoundary() arg passing" -fa46b31 Demux.h: Correct a method name reference -f8398c9 fix compile error on ARM/gcc -f691f0e simplify VP8IteratorSaveBoundary() arg passing -42542be up to 6% faster encoding with clang compiler -93402f0 multi-threaded segment analysis -7e2d659 Merge "remove the PACK() bit-packing tricks" -c13fecf remove the PACK() bit-packing tricks -2fd091c Merge "use NULL for lf_stats_ testing, not bool" -b11c9d6 dwebp: use default dct_method -4bb8465 Merge "(de)mux.h: wrap pseudo-code in /* */" -cfb56b1 make -pass option work with token buffers -5416aab (de)mux.h: wrap pseudo-code in /* */ -35dba33 use NULL for lf_stats_ testing, not bool -733a7fa enc->Iterator memory cleanup -e81fac8 Add support for "no blend" in webpmux binary -3b80bc4 gif2webp: Separate out each step into a method -bef7e9c Add doc precision about demux object keeping pointers to data. -61405a1 dwebp: enable stdout output with WIC -6eabb88 Merge "Animated WebP: add "do no blend" option to spec" -be20dec fix compilation for BITS 24 -e58cc13 Merge "dwebp: s/unsigned char/uint8_t/" -72501d4 dwebp: s/unsigned char/uint8_t/ -2c9633e Merge "gif2webp: Insert independent frames at regular intervals." -f0d6a14 gif2webp: Insert independent frames at regular intervals. -b25a6fb yuv.h: fix indent -ede3602 Merge "cosmetics: fix indent" -3a65122 dwebp: fix stdout related output -388a724 cosmetics: fix indent -4c7322c Merge "dsp: msvc compatibility" -d50c7e3 Merge "5-7% faster SSE2 versions of YUV->RGB conversion functions" -b8ab784 Merge "simplify upsampler calls: only allow 'bottom' to be NULL" -df6cebf 5-7% faster SSE2 versions of YUV->RGB conversion functions -ad6ac32 simplify upsampler calls: only allow 'bottom' to be NULL -a5e8afa output to stdout if file name is "-" -f358450 dsp: msvc compatibility -43a7c8e Merge "cosmetics" -4c5f19c Merge "bit_reader.h: cosmetics" -f72fab7 cosmetics -14dd5e7 fix const-ness -b20aec4 Merge "Support for 'do not blend' option in vwebp" -dcf6522 Support for 'do not blend' option in vwebp -d5bad03 Animated WebP: add "do no blend" option to spec -a2f5f73 Merge "Support for "Do not blend" in mux and demux libraries" -e081f2f Pack code & extra_bits to Struct (VP8LPrefixCode). -6284854 Support for "Do not blend" in mux and demux libraries -f486aaa Merge "slightly faster ParseIntraMode" -d171863 slightly faster ParseIntraMode -3ceca8a bit_reader.h: cosmetics -69257f7 Create LUT for PrefixEncode. -988b708 add WebPWorkerExecute() for convenient bypass -06e2498 Merge "VP8EncIterator clean-up" -de4d4ad VP8EncIterator clean-up -7bbe952 Merge "cosmetics: thread.c: drop a redundant comment" -da41148 cosmetics: thread.c: drop a redundant comment -feb4b6e thread.h: #ifdef when checking WEBP_USE_THREAD -8924a3a thread.c: drop WebPWorker prefix from static funcs -1aed8f2 Merge "fix indent" -4038ed1 fix indent -1693fd9 Demux: A new state WEBP_DEMUX_PARSE_ERROR -8dcae8b fix rescaling-with-alpha inaccuracy -11249ab Merge changes I9b4dc36c,I4e0eef4d -52508a1 Mux: support parsing unknown chunks within a frame/fragment. -05db057 WebPMuxSetChunk: remove unused variable -8ba1bf6 Stricter check for presence of alpha when writing lossless images -a03c351 Demux: WebPIterator now also denotes if the frame has alpha. -6df743a Decoder: handle fragments case correctly too. -faa4b07 Support for unknown chunks in mux library -7d60bbc Speed up HashChainFindCopy function. -6674014 Speedup Alpha plane encoding. -b7346a1 0.1 % speedup to decoding -c606182 webp-container-spec: Tighten language added by last -a34a502 pngdec: output error messages from libpng -e84c625 Merge "Detect canvas and image size mismatch in decoder." -f626fe2 Detect canvas and image size mismatch in decoder. -f5fbdee demux: stricter image bounds check -30c8158 add extra assert in Huffman decode code -8967b9f SSE2 for lossless decoding (critical) functions. -699d80e Jump-lookup for Huffman coding -c34307a fix some VS9 warnings about type conversion -eeada35 pngdec: add missing include -54b6510 gif2webp: If aligning to even offsets, extra pixels should be transparent -0bcf5ce Merge "remove a malloc() in case we're using only FILTER_NONE for alpha" -2c07143 remove a malloc() in case we're using only FILTER_NONE for alpha -a4d5f59 Faster lossless decoding -fd53bb7 Merge "alternate LUT-base reverse-bits code" -d1c166e Merge "Container spec: a clarification on background color." -fdb9177 Rename a method -5e96753 Container spec: a clarification on background color. -30e77d0 Merge branch '0.3.0' -1b631e2 alternate LUT-base reverse-bits code -24cc307 ~20% faster lossless decoding -313d853 Speedup for decoding lossless WebP photographs: -24ee098 change the bytes_per_pixels_ field into more evocative use_8b_decode -2a04b03 update ChangeLog (tag: v0.3.1-rc2, tag: v0.3.1) -7288950 Regression fix for alpha channels using color cache: -2e377b5 wicdec: silence a format warning -ad9e42a muxedit: silence some uninitialized warnings -3307c16 Don't set alpha-channel to 0xff for alpha->green uplift -5130770 Merge "wicdec: silence a format warning" -a37eff4 Regression fix for alpha channels using color cache: -241cf99 Merge "muxedit: silence some uninitialized warnings" -c8f9c84 Regression fix for alpha unfiltering: -14cd5c6 muxedit: silence some uninitialized warnings -a368db8 dec/vp8l: quiet vs9 x64 type conversion warning -ffae9f3 wicdec: silence a format warning -8cf0701 Alpha encoding: never filter in case of NO_COMPRESSION -825e73b update ChangeLog (tag: v0.3.1-rc1) -abf6f69 update NEWS -5a92c1a bump version to 0.3.1 -86daf77 store top Y/U/V samples in packed fashion -67bc353 Revert "add WebPBlendAlpha() function to blend colors against background" -068db59 Intertwined decoding of alpha and RGB -38cc011 Simplify forward-WHT + SSE2 version -3fa595a Support decoding upto given row in DECODE_DATA_FUNC -520f005 DequantizeLevels(): Add 'row' and 'num_rows' args -47374b8 Alpha unfilter for given set of rows -f32097e probe input file and quick-check for WebP format. -a2aed1d configure: improve gl/glut library test -c7e89cb update copyright text -a00380d configure: remove use of AS_VAR_APPEND -a94a88d fix EXIF parsing in PNG -a71e5d8 add doc precision for WebPPictureCopy() and WebPPictureView() -8287012 remove datatype qualifier for vmnv -e190843 fix a memory leak in gif2webp -0b18b9e fix two minor memory leaks in webpmux -db5095d remove some cruft from swig/libwebp.jar -850e956 README: update swig notes -bddd9b0 swig/python: add minimal documentation -d573a8d swig: add python encode support -6b93187 swig/java: reduce wrapper function code duplication -6fe536f swig/java: rework uint8_t typemap -a2ea464 Fix the bug in ApplyPalette. -7bb28d2 webp/lossless: fix big endian BGRA output -f036d4b Speed up ApplyPalette for ARGB pixels. -8112c8c remove some warnings: -cc128e0 Further reduce memory to decode lossy+alpha images -07db70d fix for big-endian -eda8a7d gif2webp: Fix signed/unsigned comparison mismatch -31f346f Makefile.vc: fix libwebpdemux dll variable typo -6c76d28 swig: add python (decode) support -b4f5bb6 swig: cosmetics -498d4dd WebP-Lossless encoding improvements. -26e7244 swig: ifdef some Java specific code -8ecec68 configure: add warning related flags -e676b04 configure: add GLUT detection; build vwebp -b0ffc43 Alpha decoding: significantly reduce memory usage -20aa7a8 configure: add --enable-everything -b8307cc configure.ac: add some helper macros -980e7ae Remove the gcc compilation comments -7f25ff9 gif2webp: Fix ICC and XMP support -d8e5321 Add missing name to AUTHORS -11edf5e Demux: Fix a potential memleak -c7b9218 don't forward declare enums -7a650c6 prevent signed int overflow in left shift ops -31bea32 add precision about dynamic output reallocation with IDecoder -c22877f Add incremental support for extended format files -5051245 Makefile.vc: have 'all' target build everything -8191dec Makefile.vc: flags cleanup -b9d7473 Makefile.vc: drop /FD flag -5568dbc update gitignore -f4c7b65 WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded. -1fb04be pngdec: Avoid a double-free. -dcbb1ca add WebPBlendAlpha() function to blend colors against background -bc9f5fb configure.ac: add AM_PROG_AR for automake >= 1.12 -bf867bf Tuned cross_color parameter (step) for lower qual -90e2ec5 Merge "probe input file and quick-check for WebP format." -7180d7f Merge "update copyright text" -830f72b probe input file and quick-check for WebP format. -2ccf58d configure: improve gl/glut library test -d640614 update copyright text -c2113ad Merge "configure: remove use of AS_VAR_APPEND" -9326a56 configure: remove use of AS_VAR_APPEND -ea63d61 fix a type warning on VS9 x86 -bec1109 fix EXIF parsing in PNG -b6e65f3 Merge "fix warnings for vs9 x64" -438946d fix warnings for vs9 x64 -f4710e3 collect macroblock reconstruction data in VP8MBData struct -23d28e2 add doc precision for WebPPictureCopy() and WebPPictureView() -518f2cd cosmetics: gif2webp: fix indent -af358e6 Merge "remove datatype qualifier for vmnv" -3fe9163 remove datatype qualifier for vmnv -764fdff fix a memory leak in gif2webp -3e59a74 fix two minor memory leaks in webpmux -47b9862 Merge "README: update swig notes" -325d15f remove some cruft from swig/libwebp.jar -4a7627c README: update swig notes -5da81e3 Merge "swig/python: add minimal documentation" -f39e08f Merge "swig: add python encode support" -6ca4a3e Merge "swig/java: reduce wrapper function code duplication" -8f8702b Merge "swig/java: rework uint8_t typemap" -91413be reduce memory for VP8MB and remove bitfields use -7413394 Fix the memory leak in ApplyFilters. -2053c2c simplify the alpha-filter testing loop -825b64d swig/python: add minimal documentation -14677e1 swig: add python encode support -a5c297c swig/java: reduce wrapper function code duplication -ad4a367 swig/java: rework uint8_t typemap -0d25876 use uint8_t for inv_palette[] -afa3450 Fix the bug in ApplyPalette. -2d6ac42 Merge "webp/lossless: fix big endian BGRA output" -2ca8396 webp/lossless: fix big endian BGRA output -742110c Speed up ApplyPalette for ARGB pixels. -2451e47 misc code cleanup -83db404 Merge "swig: add python (decode) support" -eeeea8b Merge "swig: cosmetics" -d5f9b8f Merge "libwebp: fix vp8 encoder mem alloc offsetting" -d8edd83 libwebp: fix vp8 encoder mem alloc offsetting -8983b83 remove use of bit-fields in VP8FInfo -87a4fca remove some warnings: -ba8f74e Merge "fix for big-endian" -a65067f Merge "Further reduce memory to decode lossy+alpha images" -64c8448 Further reduce memory to decode lossy+alpha images -332130b Mux: make a few methods static -4437061 fix for big-endian -5199eab Merge "add uncompressed TIFF output support" -a3aede9 add uncompressed TIFF output support -f975b67 Merge "gif2webp: Fix signed/unsigned comparison mismatch" -5fbc734 Merge "GetFeatures: Detect invalid VP8X/VP8/VP8L data" -d5060c8 Merge "mux.h: A comment fix + some consistency fixes" -352d0de GetFeatures: Detect invalid VP8X/VP8/VP8L data -3ef79fe Cosmetic: "width * height" -043e1ae gif2webp: Fix signed/unsigned comparison mismatch -5818cff mux.h: A comment fix + some consistency fixes -1153f88 Merge "swig: ifdef some Java specific code" -3eeedae Makefile.vc: fix libwebpdemux dll variable typo -f980faf swig: add python (decode) support -7f5f42b swig: cosmetics -8eae188 WebP-Lossless encoding improvements. -c7247c4 swig: ifdef some Java specific code -4cb234d Merge "Mux: make ValidateForSingleImage() method static" -ed6f530 Merge "Add GetCanvasSize() method to mux" -1d530c9 Mux: make ValidateForSingleImage() method static -bba4c2b configure: add warning related flags -fffefd1 Add GetCanvasSize() method to mux -732da8d Merge "configure: add GLUT detection; build vwebp" -0e513f7 configure: add GLUT detection; build vwebp -55d1c15 Merge "Alpha decoding: significantly reduce memory usage" -13d99fb Merge "configure: add --enable-everything" -2bf698f Merge "configure.ac: add some helper macros" -edccd19 Alpha decoding: significantly reduce memory usage -3cafcc9 configure: add --enable-everything -4ef1447 configure.ac: add some helper macros -a4e1cdb Remove the gcc compilation comments -6393fe4 Cosmetic fixes -9c4ce97 Simplify forward-WHT + SSE2 version -878b9da fix missed optim -0004617 VP8GetInfo(): Check for zero width or height. -9bf3129 align VP8Encoder::nz_ allocation -5da165c fix CheckMode() signature -0ece07d Merge "explicitly pad bitfields to 32-bits" -9dbc9d1 explicitly pad bitfields to 32-bits -5369a80 Merge "prevent signed int overflow in left shift ops" -70e3971 Merge "cosmetics: remove unnecessary ';'s" -d3136ce Merge "don't forward declare enums" -b26e5ad gif2webp: Fix ICC and XMP support -46089b2 Add missing name to AUTHORS -94328d6 Demux: Fix a potential memleak -96e948d don't forward declare enums -f4f9088 prevent signed int overflow in left shift ops -0261545 cosmetics: remove unnecessary ';'s -7ebdf11 Merge "Fix few missing comparisons to NULL" -1579989 Fix few missing comparisons to NULL -ea1b21c Cleaned up VP8GetHeaders() so that it parses only frame header -b66caee dwebp: add support for BMP output -ff885bf add precision about dynamic output reallocation with IDecoder -79241d5 Merge "Makefile.vc: have 'all' target build everything" -ac1c729 Merge "Makefile.vc: flags cleanup" -118a055 Merge "Makefile.vc: drop /FD flag" -ecad010 Merge "update gitignore" -a681b4f Rename PRE_VP8 state to WEBP_HEADER -ead4d47 Add incremental support for extended format files -69d0f92 Makefile.vc: have 'all' target build everything -5296749 Makefile.vc: flags cleanup -c61baf0 Makefile.vc: drop /FD flag -3a15125 update gitignore -5167ca4 Merge "WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded." -67708d6 WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded. -b68912a pngdec: Avoid a double-free. -82abbe1 Merge "configure.ac: add AM_PROG_AR for automake >= 1.12" -e7d9548 add WebPBlendAlpha() function to blend colors against background -ed4dc71 configure.ac: add AM_PROG_AR for automake >= 1.12 -df4a406 Merge branch '0.3.0' -1e0d4b8 Update ChangeLog (tag: v0.3.0-rc7, tag: v0.3.0) -d52b405 Cosmetic fixes -6cb4a61 misc style fix -68111ab add missing YUVA->ARGB automatic conversion in WebPEncode() -e9a7990 Cosmetic fixes -403bfe8 Container spec: Clarify frame disposal -2aaa423 Merge "add missing YUVA->ARGB automatic conversion in WebPEncode()" -07d87bd add missing YUVA->ARGB automatic conversion in WebPEncode() -142c462 misc style fix -3e7a13a Merge "Container spec: clarify the background color field" into 0.3.0 -14af774 container doc: add a note about the 'ANMF' payload -cc635ef Container spec: clarify the background color field -e3e3394 container doc: move RIFF description to own section -4299f39 libwebp/mux: fix double free -33f9a69 Merge "demux: keep a frame tail pointer; used in AddFrame" into 0.3.0 -a2a7b95 use WebPDataCopy() instead of re-coding it. -6f18f12 demux: keep a frame tail pointer; used in AddFrame -e5af49e add doc precision about WebPParseHeaders() return codes -db46daa Merge "Makefile.vc: fix dynamic builds" into 0.3.0 -53c77af Merge "gif2webp: Bgcolor fix for a special case" into 0.3.0 -a5ebd14 gif2webp: Bgcolor fix for a special case -6378f23 Merge "vwebp/animation: fix background dispose" into 0.3.0 -3c8eb9a fix bad saturation order in QuantizeBlock -04c7a2e vwebp/animation: fix background dispose -81a5069 Makefile.vc: fix dynamic builds -5f25c39 update ChangeLog (tag: v0.3.0-rc6) -14d42af examples: don't use C99 %zu -5ccf1fe update ChangeLog -2560c24 update NEWS -f43bafc Merge changes Iecccb09c,If5ee9fd2,I3e181ce4 into 0.3.0 -a788644 dwebp: warn when decoding animated webp's -302efcd Decode: return more meaningful error for animation -ad45273 WebPBitstreamFeatures: add has_animation field -783dfa4 disable FRGM decoding for good in libwebpmux -4b956be Update ChangeLog -ad8b86d update NEWS -3e084f6 Merge "demux cosmetics: comments/rename internal function" into 0.3.0 -d3f8c62 Merge "move WebPFeatureFlags declaration" into 0.3.0 -7386fe5 Merge "libwebp{demux,mux}: install mux_types.h" into 0.3.0 -d6cd4e9 Merge "bump decode abi" into 0.3.0 -17f8da5 bump decode abi -97684ae Merge "add doc precision about WebPDemuxPartial()" into 0.3.0 -f933fd2 move WebPFeatureFlags declaration -289bc47 libwebp{demux,mux}: install mux_types.h -224e8d4 add doc precision about WebPDemuxPartial() -4c18e80 demux cosmetics: comments/rename internal function -7cfd1bf update AUTHORS -401f7b8 Merge "speed-up lossless (~3%) with ad-hoc histogram cost evaluation" into 0.3.0 -1fc8ffc Merge "makefile.unix: dist related changes" into 0.3.0 -8a89c6e Merge changes I466c377f,Ib761ebd3,I694857fc into 0.3.0 -f4ffb2d speed-up lossless (~3%) with ad-hoc histogram cost evaluation -723847d gif2webp: only write error messages to stderr -701b9e2 makefile.unix: dist related changes -bb85b43 Merge "update NEWS" into 0.3.0 -59423a2 gif2webp: fix crash on open failure with libgif5 -9acb17d gif2webp: silence a unused param warning -7d9fdc2 Merge "README updates" into 0.3.0 -5621934 Merge "build: fix install race on shared headers" into 0.3.0 -70809d8 Merge "bump version to 0.3.0" into 0.3.0 -d851cd1 demux: make the parse a bit more strict -28bb410 update NEWS -cef9388 bump version to 0.3.0 -9048494 build: fix install race on shared headers -1e67e8e README updates -42b611a Merge "configure: drop experimental from mux/demux" into 0.3.0 -096a8e3 Merge "vwebp: add color profile support" into 0.3.0 -ddfee5d vwebp: add color profile support -0d6927d Merge "Mark fragment options as experimental in webpmux" into 0.3.0 -5dbd403 Mark fragment options as experimental in webpmux -a0a6648 configure: drop experimental from mux/demux -ee65bad Merge "add support for BITS > 32" into 0.3.0 -744930d add support for BITS > 32 -7dd288f cwebp: fix build -19a8dd0 Merge "Makefile.vc: add vwebp.exe target" into 0.3.0 -50eedda Merge "examples: normalize icc related program arguments" into 0.3.0 -757f637 Merge "Makefile.vc: add libwebpdecoder target" into 0.3.0 -b65c4b7 Makefile.vc: add libwebpdecoder target -f8db7b4 Merge "vwebp: replace doubles w/floats where appropriate" into 0.3.0 -d99aa56 Makefile.vc: add vwebp.exe target -013023e vwebp: replace doubles w/floats where appropriate -9b3db89 README.mux: add version reference -7b6a26c Merge "cwebp: output metadata statistics" into 0.3.0 -d8dc72a examples: normalize icc related program arguments -7bfc905 Merge "make alpha unfilter work in-place" into 0.3.0 -0037b2d Merge "add LUT-free reference code for YUV->RGB conversion." into 0.3.0 -166bf74 Merge "demux: disable fragment parsing" into 0.3.0 -126974b add LUT-free reference code for YUV->RGB conversion. -0aef3eb make alpha unfilter work in-place -14ef500 Merge "Remove 'status: experimental' from container spec" into 0.3.0 -d40c98e Merge "webpmux binary: tiny style fix" into 0.3.0 -0bc4268 cwebp: output metadata statistics -bc03980 Merge "autoconf: normalize experimental define" into 0.3.0 -d1e21b1 Remove 'status: experimental' from container spec -7681bb9 webpmux binary: tiny style fix -a3dd3d0 avoid installing example_util.h -252320e demux: disable fragment parsing -537bde0 autoconf: normalize experimental define -5e338e0 Merge changes I33e8a613,I8e8a7b44 into 0.3.0 -d9d0ea1 Merge changes If21e3ec7,I991fc30b into 0.3.0 -627f5ca automake: add reference to libwebp for mux/demux -eef73d0 don't consolidate proba stats too often -05ec4cc libwebp{,decoder}.pc: add pthread flags -1bfcf5b add libwebpmux.pc -26ca843 add libwebpdemux.pc -69e2590 Merge "Tune Lossless compression for lower qualities." -0478b5d Tune Lossless compression for lower qualities. -39f7586 add a mention of parallel alpha encoding in the NEWS -5a21d96 Merge "1.5x-2x faster encoding for method 3 and up" -9bfbdd1 1.5x-2x faster encoding for method 3 and up -27dc741 Correct frame options order in README.mux -be2fd17 Mux: fix a scenario with bad ANMF/FRGM size -19eb012 Merge "Demux: Add option to get frame count using GetI()" -7368b8c Merge "WebPGetFeatures() out of if condition for clarity." -f604c9a Merge "fix windows build" -153f94e fix windows build -847b492 Merge "vwebp: use magenta for 'i'nfo display" -25ea46b Merge "vwebp: add keyboard shortcuts to help output" -bea7cca vwebp: use magenta for 'i'nfo display -8fab161 webpmux: correct -frame param order in help output -03cc23d vwebp: add keyboard shortcuts to help output -068eba8 Demux: Add option to get frame count using GetI() -988b8f5 WebPGetFeatures() out of if condition for clarity. -6933d91 Merge "gif2webp: Be lenient about background color index." -4d0f7c5 Merge "WebPGetFeatures() behavior change:" -fdeeb01 gif2webp: Be lenient about background color index. -ad25032 Merge "multi-threaded alpha encoding for lossy" -4e32d3e Merge "fix compilation of token.c" -f817930 multi-threaded alpha encoding for lossy -8805035 fix compilation of token.c -fc81621 code using the actual values for num_parts_, not the ones from config -7265535 Merge "move the config check from .c to .h" -dd9e76f move the config check from .c to .h -956b217 WebPGetFeatures() behavior change: -df02e4c WebPDemuxGetI behavior change: -633c004 Merge "rebalance method tools (-m) for methods [0..4]" -58ca6f6 rebalance method tools (-m) for methods [0..4] -7648c3c Merge "describe rd-opt levels introduce VP8RDLevel enum" -67fb100 Merge "autoconf: enable silent-rules by default" -a5042a3 GetVersion() methods for mux and demux -5189957 describe rd-opt levels introduce VP8RDLevel enum -4e094ac autoconf: enable silent-rules by default -b7eaa85 inline VP8LFastLog2() and VP8LFastSLog2 for small values -5cf7792 split quant_levels.c into decoder and encoder version -e5d3ffe Merge "Update code example in README.mux" -ac5a915 Update code example in README.mux -38a91e9 Add example code snippet for demux API -5f557f3 README.mux: add info about Demux API and vwebp -c0ba090 backward_references: avoid signed integer overflow -943386d disable SSE2 for now -9479fb7 lossless encoding speedup -ec2030a merge two lines together -b67956c Merge "Remove ReadOneBit() and ReadSymbolUnsafe()" -1667bde Remove ReadOneBit() and ReadSymbolUnsafe() -3151669 wicdec + dwebp cosmetics: normalize formatting -92668da change default filtering parameters: * type is now 'strong' * strength is now '60' -b7490f8 introduce WEBP_REFERENCE_IMPLEMENTATION compile option -3383885 faster decoding (3%-6%) -5c3e381 Merge "add a -jpeg_like option" -c231104 remove unused declaration of VP8Zigzag -3615295 Merge "wicdec: add alpha support for paletted formats" -c9f1649 wicdec: add alpha support for paletted formats -1262f81 Merge "wicdec: silence some warnings" -e7ea61e wicdec: silence some warnings -23c0f35 fix missing intptr_t->int cast for MSVC -e895059 add a -jpeg_like option -1f803f6 Merge "Tune alpha quality mapping to more reasonable values." -1267d49 Tune alpha quality mapping to more reasonable values. -043076e Merge "speed-up lossless in BackwardTrace" -f3a44dc remove one malloc from TraceBackwards() -0fc1a3a speed-up lossless in BackwardTrace -7c732e5 cwebp: centralize WebPCleanupTransparentArea() -7381254 Merge "wicdec: add ICC profile extraction" -e83ff7d wicdec: add ICC profile extraction -146c6e3 Merge "cosmetics: pngdec: normalize default label location" -a8f549d Merge "manpages: italicize option parameters" -e118db8 Merge "encode.h: note the need to free() WebPMemoryWriter" -1dfee6d cosmetics: pngdec: normalize default label location -14c3820 manpages: italicize option parameters -7defbfa encode.h: note the need to free() WebPMemoryWriter -88d382a cwebp: cleanup after memory_writer -12d6cec fix extra space in dwebp.1 man -b01681a Fix for demuxer frame iteration: -56c12aa Demuxer creation fix: -66c810b add a -yuv option to dwebp (very similar to -pgm) -841a3ba Merge "Remove -Wshadow warnings." -8fd0252 Merge "upsampling_neon.c: fix build" -6efed26 Remove -Wshadow warnings. -60904aa Merge "allow WebPINewRGB/YUVA to be passed a NULL output buffer." -b7adf37 allow WebPINewRGB/YUVA to be passed a NULL output buffer. -27f8f74 upsampling_neon.c: fix build -06b9cdf gitignore: add IOS related directories -f112221 Merge "Fix more comments for iobuild.sh" -fe4d25d Fix more comments for iobuild.sh -1de3e25 Merge "NEON optimised yuv to rgb conversion" -090b708 NEON optimised yuv to rgb conversion -daa0647 Merge "Add ios build script for building iOS library." -79fe39e Add ios build script for building iOS library. -126c035 remove some more -Wshadow warnings -522e9d6 Merge "cwebp: enable '-metadata'" -76ec5fa cwebp: enable '-metadata' -aeb91a9 Merge "cosmetics: break a few long lines" -be7c96b cosmetics: break a few long lines -cff8ddb Merge "add libwebpdecoder.pc" -93148ab Merge "libwebp.pc.in: detab" -6477f95 Merge "Makefile.vc: normalize path separator" -bed1ed7 add libwebpdecoder.pc -46168b2 libwebp.pc.in: detab -a941a34 Fixed few nits in the build files. -dd7a49b Makefile.vc: normalize path separator -9161be8 Merge "cwebp: extract WIC decoding to its own module" -08e7c58 Merge "Provide an option to build decoder library." -0aeba52 Provide an option to build decoder library. -757ebcb catch malloc(0)/calloc(0) with an assert -152ec3d Merge "handle malloc(0) and calloc(0) uniformly on all platforms" -a452a55 cwebp: extract WIC decoding to its own module -2b252a5 Merge "Provide option to swap bytes for 16 bit colormodes" -94a48b4 Provide option to swap bytes for 16 bit colormodes -42f8f93 handle malloc(0) and calloc(0) uniformly on all platforms -8b2152c Merge "add an extra assert to check memory bounds" -0d19fbf remove some -Wshadow warnings -cd22f65 add an extra assert to check memory bounds -8189fed Merge "Add details and reference about the YUV->RGB conversion" -1d2702b Merge "Formatting fixes in lossless bitstream spec" -8425aae Formatting fixes in lossless bitstream spec -a556cb1 Add details and reference about the YUV->RGB conversion -d8f21e0 add link to SSIM description on Wikipedia -18e9167 Merge "WebP-lossless spec clarifications:" -98e25b9 Merge "cwebp: add -metadata option" -f01c2a5 WebP-lossless spec clarifications: -f4a9797 Merge "Disto4x4 and Disto16x16 in NEON" -47b7b0b Disto4x4 and Disto16x16 in NEON -7eaee9f cwebp: add -metadata option -36c52c2 tiffdec: use toff_t for exif ifd offset -7c8111e Merge "cwebp/tiffdec: add TIFF metadata extraction" -e6409ad Remove redundant include from dsp/lossless code. -1ab5b3a Merge "configure: fix --with-gifincludedir" -03c749e configure: fix --with-gifincludedir -8b65063 multiple libgif versions support for gif2webp -476e293 gif2webp: Use DGifOpenFileName() -b50f277 tiffdec: correct format string -2b9048e Merge "tiffdec: check error returns for width/height" -a1b5a9a Merge "cwebp/tiff: use the first image directory" -079423f tiffdec: check error returns for width/height -d62824a Merge "cwebp/jpegdec: add JPEG metadata extraction" -03afaca Merge "cwebp: add PNG metadata extraction" -2c72496 cwebp/jpegdec: add JPEG metadata extraction -dba64d9 cwebp: add PNG metadata extraction -1f075f8 Lossless spec corrections/rewording/clarifications -2914ecf cwebp/tiffdec: add TIFF metadata extraction -d82a3e3 More corrections/clarifications in lossless spec: -bd00255 cwebp/tiff: use the first image directory -df7aa07 Merge "Cleanup around jpegdec" -0f57dcc decoding speed-up (~1%) -bcec339 Lossless bitstream clarification: -6bf2087 add examples/metadata.c -207f89c Merge "configure: add libwebpdemux status to summary" -1bd287a Cleanup around jpegdec -9145567 Merge "cosmetics: use '== 0' in size checks" -d6b88b7 cosmetics: use '== 0' in size checks -d3dace2 cosmetics: jpegdec -2f69af7 configure: add libwebpdemux status to summary -1c1c564 cwebp: extract tiff decoding to its own module -6a871d6 cwebp: extract jpeg decoding to its own module -2ee228f cwebp: extract png decoding to its own module -4679db0 Merge "cwebp: add metadata framework" -63aba3a cwebp: add metadata framework -931bd51 lossless bitstream: block size bits correction -e4fc4c1 lossless bitstream: block size bits correction -d65ec67 fix build, move token.c to src/enc/ -657f5c9 move token buffer to its own file (token.c) -c34a375 introduce GetLargeValue() to slim-fast GetCoeffs(). -d5838cd faster non-transposing SSE2 4x4 FTransform -f76191f speed up GetResidualCost() -ba2aa0f Add support for BITS=24 case -2e7f6e8 makefile.unix: Dependency on libraries -dca8421 Merge "Separate out mux and demux code and libraries:" -23782f9 Separate out mux and demux code and libraries: -bd56a01 configure: add summary output -90e5e31 dwebp manual: point to webpmux, gif2webp. -540790c gif2webp.c: add a note about prerequisites -d1edf69 cwebp man page: meaning of '-q' for lossy/lossless -79efa1d Add man page for gif2webp utility -2243e40 Merge "gif2webp build support with autoconf tools" -c40efca gif2webp build support with autoconf tools -6523e2d WebP Container: -4da788d Merge "simplify the fwd transform" -42c3b55 simplify the fwd transform -41a6ced user GLfloat instead of float -b542611 fix indentation -68f282f * handle offset in anim viewer 'vwebp' * fix gif2webp to handle disposal method and odd offset correctly -118cb31 Merge "add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case" -8a7c3cc Merge "Change the order of -frame argument to be more natural" -99e0a70 Merge "Simplify the texture evaluation Disto4x4()" -0f923c3 make the bundling work in a tmp buffer -e5c3b3f Simplify the texture evaluation Disto4x4() -4860008 Change the order of -frame argument to be more natural -35bfd4c add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case -a7305c2 Clarification for unknown chunks -4c4398e Refine WebP Container Spec wrt unknown chunks. -2ca642e Rectify WebPMuxGetFeatures: -7caab1d Some cosmetic/comment fixes. -60b2651 Merge "Write a GIF to WebP converter based on libgif." -c7127a4 Merge "Add NEON version of FTransformWHT" -11b2721 Write a GIF to WebP converter based on libgif. -e9a15a3 ExUtilWriteFile() to write memory segment to file -74356eb Add a simple cleanup step in mux assembly: -51bb1e5 mux.h: correct WebPDemuxSelectFragment() prototype -22a0fd9 Add NEON version of FTransformWHT -fa30c86 Update mux code to match the spec wrt animation -d9c5fbe by-pass Analysis pass in case segments=1 -d2ad445 Merge changes Ibeccffc3,Id1585b16 -5c8be25 Merge "Chunk fourCCs for XMP/EXIF" -a00a3da Use 'frgm' instead of 'tile' in webpmux parameters -81b8a74 Design change in ANMF and FRGM chunks: -f903cba Chunk fourCCs for XMP/EXIF -812933d Tune performance of HistogramCombine -52ad197 Animation specification in container spec -001b930 Image fragment specification in container spec -391f9db Ordering of description of bits in container spec -d573577 Metadata specification in container spec -1c4609b Merge commit 'v0.2.1' -0ca584c Merge "Color profile specification in container spec" -e8b41ad add NEON asm version for WHT inverse transform -af6f0db Color profile specification in container spec -a61a824 Merge "Add NULL check in chunk APIs" -0e8b7ee fix WebPPictureView() unassigned strides -75e5f17 ARM/NEON: 30% encoding speed-up -02b4356 Add NULL check in chunk APIs -a077072 mux struct naming -6c66dde Merge "Tune Lossless encoder" -ab5ea21 Tune Lossless encoder -74fefc8 Update ChangeLog (tag: v0.2.1, origin/0.2.0, 0.2.0) -92f8059 Rename some chunks: -3bb4bbe Merge "Mux API change:" -d0c79f0 Mux API change: -abc0604 Merge "update NEWS" into 0.2.0 -57cf313 update NEWS -25f585c bump version to 0.2.1 -fed7c04 libwebp: validate chunk size in ParseOptionalChunks -552cd9b cwebp (windows): fix alpha image import on XP -b14fea9 autoconf/libwebp: enable dll builds for mingw -4a8fb27 [cd]webp: always output windows errors -d662158 fix double to float conversion warning -72b96a6 cwebp: fix jpg encodes on XP -734f762 VP8LAllocateHistogramSet: fix overflow in size calculation -f9cb58f GetHistoBits: fix integer overflow -b30add2 EncodeImageInternal: fix uninitialized free -3de58d7 fix the -g/O3 discrepancy for 32bit compile -77aa7d5 fix the BITS=8 case -e5970bd Make *InitSSE2() functions be empty on non-SSE2 platform -ef5cc47 make *InitSSE2() functions be empty on non-SSE2 platform -c4ea259 make VP8DspInitNEON() public -8344ead Merge "libwebp: validate chunk size in ParseOptionalChunks" -4828bb9 Merge "cwebp (windows): fix alpha image import on XP" -3076333 libwebp: validate chunk size in ParseOptionalChunks -7048189 AccumulateLSIM: fix double -> float warnings -eda8ee4 cwebp (windows): fix alpha image import on XP -c6e9865 Merge "add EXPERIMENTAL code for YUV-JPEG colorspace" -f0360b4 add EXPERIMENTAL code for YUV-JPEG colorspace -f86e6ab add LSIM metric to WebPPictureDistortion() -c3aa215 Speed up HistogramCombine for lower qualities. -1765cb1 Merge "autoconf/libwebp: enable dll builds for mingw" -a13562e autoconf/libwebp: enable dll builds for mingw -9f469b5 typo: no_fancy -> no_fancy_upsampling -1a27f2f Merge "fix double to float conversion warning" -cf1e90d Merge "cwebp: fix jpg encodes on XP" -f2b5d19 [cd]webp: always output windows errors -e855208 fix double to float conversion warning -ecd66f7 cwebp: fix jpg encodes on XP -7b3eb37 Tune lossless compression to get better gains. -ce8bff4 Merge "VP8LAllocateHistogramSet: fix overflow in size calculation" -ab5b67a Merge "EncodeImageInternal: fix uninitialized free" -7fee5d1 Merge "GetHistoBits: fix integer overflow" -a6ae04d VP8LAllocateHistogramSet: fix overflow in size calculation -80237c4 GetHistoBits: fix integer overflow -8a99723 EncodeImageInternal: fix uninitialized free -0b9e682 minor cosmetics -a792b91 fix the -g/O3 discrepancy for 32bit compile -73ba435 Merge "detect and merge similar segments" -fee6627 detect and merge similar segments -0c44f41 src/webp/*.h: don't forward declare enums in C++ -d7a5ac8 vwebp: use demux interface -931e0ea Merge "replace 'typedef struct {} X;" by "typedef struct X X; struct X {};"" -8f216f7 remove cases of equal comparison for qsort() -28d25c8 replace 'typedef struct {} X;" by "typedef struct X X; struct X {};" -2afee60 speed up for ARM using 8bit for boolean decoder -5725cab new segmentation algorithm -2cf1f81 Merge "fix the BITS=8 case" -12f78ae fix the BITS=8 case -6920c71 fix MSVC warnings regarding implicit uint64 to uint32 conversions -f6c096a webpmux binary: Rename 'xmp' option to 'meta' -ddfe871 webpmux help correction -b7c5544 Merge "Make *InitSSE2() functions be empty on non-SSE2 platform" -1c04a0d Common APIs for chunks metadata and color profile. -2a3117a Merge "Create WebPMuxFrameInfo struct for Mux APIs" -5c3a723 Make *InitSSE2() functions be empty on non-SSE2 platform -7c6e60f make *InitSSE2() functions be empty on non-SSE2 platform -c7eb457 make VP8DspInitNEON() public -ab3234a Create WebPMuxFrameInfo struct for Mux APIs -e3990fd Alignment fixes -e55fbd6 Merge branch '0.2.0' -4238bc0 Update ChangeLog (tag: v0.2.0) -c655380 dec/io.c: cosmetics -fe1958f RGBA4444: harmonize lossless/lossy alpha values -681cb30 fix RGBA4444 output w/fancy upsampling -f06c1d8 Merge "Alignment fix" into 0.2.0 -f56e98f Alignment fix -6fe843b avoid rgb-premultiply if there's only trivial alpha values -528a11a fix the ARGB4444 premultiply arithmetic -a0a4885 Lossless decoder fix for a special transform order -62dd9bb Update encoding heuristic w.r.t palette colors. -6f4272b remove unused ApplyInverseTransform() -93bf0fa Update ChangeLog (tag: v0.2.0-rc1) -5934fc5 update AUTHORS -014a711 update NEWS -43b0d61 add support for ARGB -> YUVA conversion for lossless decoder -33705ca bump version to 0.2.0 -c40d7ef fix alpha-plane check + add extra checks -a06f802 MODE_YUVA: set alpha to opaque if the image has none -52a87dd Merge "silence one more warning" into 0.2.0 -3b02309 silence one more warning -f94b04f move some RGB->YUV functions to yuv.h -4b71ba0 README: sync [cd]webp help output -c9ae57f man/dwebp.1: add links to output file format details -292ec5c quiet a few 'uninitialized' warnings -4af3f6c fix indentation -9b261bf remove the last NOT_HAVE_LOG2 instances -323dc4d remove use of log2(). Use VP8LFastLog2() instead. -8c515d5 Merge "harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc" into 0.2.0 -d4b4bb0 Merge changes I46090628,I1a41b2ce into 0.2.0 -bff34ac harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc -a3c063c Merge "extra size check for security" into 0.2.0 -5e79630 Merge "WebPEncode: clear stats at the start of encode" into 0.2.0 -f1edf62 Merge "rationalize use of color-cache" into 0.2.0 -c193331 extra size check for security -906be65 rationalize use of color-cache -dd1c387 Add image-hint for low-color images. -4eb7aa6 Merge "WebPCheckMalloc() and WebPCheckCalloc():" into 0.2.0 -80cc730 WebPCheckMalloc() and WebPCheckCalloc(): -183cba8 check VP8LBitWriterInit return -cbfa9ee lossless: fix crash on user abort -256afef cwebp: exit immediately on version mismatch -475d87d WebPEncode: clear stats at the start of encode -a7cc729 fix type and conversion warnings -7d853d7 add stats for lossless -d39177b make QuantizeLevels() store the sum of squared error -5955cf5 replace x*155/100 by x*101581>>16 -7d732f9 make QuantizeLevels() store the sum of squared error -e45a446 replace x*155/100 by x*101581>>16 -159b75d cwebp output size consistency: -cbee59e Merge commit 'v0.1.99' -1889e9b dwebp: report -alpha option -3bc3f7c Merge "dwebp: add PAM output support" into 0.2.0 -d919ed0 dwebp: add PAM output support -85e215d README/manpages/configure: update website link -c3a207b Update ChangeLog (tag: v0.1.99) -d1fd782 Merge "add extra precision about default values and behaviour" into 0.2.0 -efc826e add extra precision about default values and behaviour -9f29635 header/doc clean up -ff9fd1b Makefile.vc: fix webpmux.exe *-dynamic builds -8aacc7b remove INAM, ICOP, ... chunks from the test webp file. -2fc1301 harmonize authors as "Name (mail@address)" -4a9f37b Merge "update NEWS" into 0.2.0 -7415ae1 makefile.unix: provide examples/webpmux target -ce82ced update NEWS -641e28e Merge "man/cwebp.1: wording, change the date" into 0.2.0 -c37c23e README: cosmetics -3976dcd man/cwebp.1: wording, change the date -3e5bbe1 Merge "rename 'use_argb_input' to 'use_argb'" into 0.2.0 -ce90847 Merge "add some padding bytes areas for later use" into 0.2.0 -2390dab Merge "fixing the findings by Frederic Kayser to the bitstream spec" into 0.2.0 -0275159 add a very crude progress report for lossless -a4b9b1c Remove some unused enum values. -dd10817 rename 'use_argb_input' to 'use_argb' -90516ae add some padding bytes areas for later use -d03b250 fixing the findings by Frederic Kayser to the bitstream spec -ce156af add missing ABI compatibility checks -9d45416 Merge "Doc: container spec text tweaks" into 0.2.0 -4e2e0a8 Doc: container spec text tweaks -f7f16a2 add ABI compatibility check -2a77557 Merge "swig: add WebPEncodeLossless* wrappers" into 0.2.0 -a3ec622 mux.h: remove '* const' from function parameters -31426eb encode.h: remove '* const' from function parameters -9838e5d decode.h: remove '* const' from function parameters -4972302 swig: add WebPEncodeLossless* wrappers -9ff00ca bump encoder/decoder versions -c2416c9 add lossless quick encoding functions to the public API -4c1f5d6 Merge "NEWS: mention decode_vp8.h is no longer installed" into 0.2.0 -6cb2277 NEWS: mention decode_vp8.h is no longer installed -d5e5ad6 move decode_vp8.h from webp/ to dec/ -8d3b04a Merge "header clean-up" into 0.2.0 -02201c3 Merge "remove one malloc() by making color_cache non dynamic" into 0.2.0 -d708ec1 Merge "move MIN/MAX_HISTO_BITS to format_constants.h" into 0.2.0 -ab2da3e Merge "add a malloc() check" into 0.2.0 -2d571bd add a malloc() check -7f0c178 remove one malloc() by making color_cache non dynamic -6569cd7 Merge "VP8LFillBitWindow: use 64-bit path for msvc x64 builds" into 0.2.0 -23d34f3 header clean-up -2a3ab6f move MIN/MAX_HISTO_BITS to format_constants.h -985d3da Merge "shuffle variables in HashChainFindCopy" into 0.2.0 -cdf885c shuffle variables in HashChainFindCopy -c3b014d Android.mk: add missing lossless files -8c1cc6b makefile.unix dist: explicitly name installed includes -7f4647e Merge "clarify the colorspace naming and byte ordering of decoded samples" into 0.2.0 -cbf6972 clarify the colorspace naming and byte ordering of decoded samples -857650c Mux: Add WebPDataInit() and remove WebPImageInfo -ff771e7 don't install webp/decode_vp8.h -596dff7 VP8LFillBitWindow: use 64-bit path for msvc x64 builds -3ca7ce9 Merge "doc: remove non-finalized chunk references" into 0.2.0 -1efaa5a Merge "bump versions" into 0.2.0 -51fa13e Merge "README: update cwebp help output" into 0.2.0 -12f9aed README: update cwebp help output -f0b5def bump versions -4c42a61 update AUTHORS -6431a1c doc: remove non-finalized chunk references -8130c4c Merge "build: remove libwebpmux from default targets/config" -23b4443 Merge "configure: broaden test for libpng-config" -85bff2c Merge "doc: correct lossless prefix coding table & code" -05108f6 Merge "More spec/code matching in mux:" -6808e69 More spec/code matching in mux: -bd2b46f Merge "doc/webp-container-spec: light cosmetics" -20ead32 doc/webp-container-spec: light cosmetics -1d40a8b configure: add pthread detection -b5e9067 fix some int <-> size_t mix for buffer sizes -e41a759 build: remove libwebpmux from default targets/config -0fc2baa configure: broaden test for libpng-config -45b8272 Merge "restore authorship to lossless bitstream doc" -06ba059 restore authorship to lossless bitstream doc -44a09a3 add missing description of the alpha filtering methods -63db87d Merge "vwebp: add checkboard background for alpha display" -a73b897 vwebp: add checkboard background for alpha display -939158c Merge "vwebp: fix info display" -b35c07d vwebp: fix info display -48b39eb fix underflow for very short bitstreams -7e62298 cosmetics: param alignment, manpage wording -1bd7dd5 Merge changes I7b0afb0d,I7ecc9708 -ac69e63 Merge "Updated cwebp man's help for Alpha & Lossless." -c0e8859 Get rid of image_info_ from WebPChunk struct. -135ca69 WebP Container Spec: -eb6f9b8 Updated cwebp man's help for Alpha & Lossless. -0fa844f cosmetic fixes on assert and 'const' where applicable -7f22bd2 check limit of width * height is 32 bits -16c46e8 autoconf/make: cosmetics: break long lines -ab22a07 configure: add helper macro to define --with-* -c17699b configure: add libtiff test -0e09732 Merge "cwebp: fix crash with yuv input + lossless" -88a510f Merge "fix big-endian VP8LWriteBits" -da99e3b Merge "Makefile.vc: split mux into separate lib" -7bda392 cwebp: fix crash with yuv input + lossless -f56a369 fix big-endian VP8LWriteBits -54169d6 Merge "cwebp: name InputFileFormat members consistently" -e2feefa Makefile.vc: split mux into separate lib -27caa5a Merge "cwebp: add basic TIFF support" -d8921dd cwebp: name InputFileFormat members consistently -6f76d24 cwebp: add basic TIFF support -4691407 Merge changes If39ab7f5,I3658b5ae -cca7c7b Fixed nit: 10 -> 10.f -5d09a24 WebPMuxCreate() error handling: -777341c Fix a memleak in WebPMuxCreate() -61c9d16 doc: correct lossless prefix coding table & code -4c39757 Merge "mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN" -e4e36cc Merge "Mux: Allow only some frames/tiles to have alpha." -ad2aad3 Merge "WebP Decoding error handling:" -97649c8 Mux: Allow only some frames/tiles to have alpha. -f864be3 Lower the quality settings for Alpha encoding. -3ba81bb WebP Decoding error handling: -fcc6992 add automatic YUVA/ARGB conversion during WebPEncode() -802e012 fix compilation in non-FANCY_UPSAMPLING mode -e012dfd make width/height coding match the spec -228d96a mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN -637a314 remove the now unused *KeepA variants -d11f6fc webpmux returns error strings rather than numbers -fcec059 makefile.unix: cwebp: fix OSX link -6b811f1 Merge "doc: remove lossless pdf" -c963482 doc: remove lossless pdf -b9ae4f0 cosmetics after mux changes b74ed6e, b494ad5 -b494ad5 Mux: only allow adding frame/tiles at the end. -2c341b0 Merge "Added image characteristic hint for the codec." -d373076 Added image characteristic hint for the codec. -2ed2adb Merge "msvc: add intrinsic based BitsLog2Floor" -e595e7c Merge "add demux.c to the makefiles" -da47b5b Merge "demux: add {Next,Prev}Chunk" -e5f4674 add demux.c to the makefiles -4708393 demux: add {Next,Prev}Chunk -e8a0a82 demux: quiet msvc warnings -7f8472a Update the WebP Container Spec. -31b68fe cleanup WebPPicture struct and API -9144a18 add overflow check before calling malloc() -81720c9 consistency cosmetics -2ebe839 Merge "Add kramdown version information to README" -7144308 enc/vp8l.c: fix build -b7ac19f Add kramdown version information to README -efdcb66 Merge "Edit for consistency, usage and grammar." -0822010 Enable alpha in vvwebp -8de9a08 Merge "Mux API change:" -b74ed6e Mux API change: -233a589 take picture->argb_stride into account for lossless coding -04e33f1 Edit for consistency, usage and grammar. -a575b4b Merge "cosmetics: add missing const" -8d99b0f Merge "cosmetics: remove unimplemented function proto" -69d0221 cosmetics: add missing const -5b08318 cosmetics: remove unimplemented function proto -b7fb0ed Log warning for unsupported options for lossless. -e1f769f msvc: add intrinsic based BitsLog2Floor -8a69c7d Bug-fix: Clamp backward dist to 1. -b5b6ac9 Merge "Bring the special writer 'WebPMemoryWriter' to public API" -a6a1909 Merge "Fix floating point exception with cwebp -progress" -f2cee06 Fix floating point exception with cwebp -progress -91b7a8c Bring the special writer 'WebPMemoryWriter' to public API -310e297 support resize and crop for RGBA input -a89835d Merge changes Ice662960,Ie8d7aa90,I2d996d5e,I01c04772 -ce614c0 Merge "dec/vp8: avoid setting decoder status twice" -900285d dec/vp8: avoid setting decoder status twice -8227adc Merge changes I6f02b0d0,I5cbc9c0a,I9dd9d4ed,Id684d2a1 -dcda59c Merge "demux: rename SetTile to SelectTile" -622ef12 demux: rename SetTile to SelectTile -81ebd37 Merge "demux: add {Next,Prev}Frame" -02dd37a demux: add {Next,Prev}Frame -4b79fa5 Merge "Limit the maximum size of huffman Image to 16MB." -9aa34b3 Manually number "chapters," as chapter numbers are used in the narrative. -2a4c6c2 Re-wrap at <= 72 columns -a45adc1 Apply inline emphasis and monospacing, per gdoc / PDF -9101120 Incorporate gdoc changes through 2012-06-08 -7a18248 Removed CodeRay syntax declarations ... -b3ec18c Provide for code-block syntax highlighting. -709d770 Replace high ASCII artifacts (curly quotes, etc.). -930e8ab Lossless WebP doc largely ported to markdown text. -18cae37 msvc: silence some build warnings -b392308 Limit the maximum size of huffman Image to 16MB. -f180df2 Merge "libwebp/demux: add Frame/Chunk iteration" -2bbe1c9 Merge "Enable lossless encoder code" -d0601b0 Merge changes I1d97a633,I81c59093 -78f3e34 Enable lossless encoder code -d974a9c Merge "libwebp/demux: add simple format parsing" -26bf223 Merge "libwebp: add WebPDemux stub functions" -2f66668 Merge "modify WebPParseHeaders to allow reuse by GetFeatures" -b402b1f libwebp/demux: add Frame/Chunk iteration -ad9ada3 libwebp/demux: add WebPDemuxGetI -2f2d4d5 libwebp/demux: add extended format parsing -962dcef libwebp/demux: add simple format parsing -f8f9408 libwebp: add WebPDemux stub functions -fb47bb5 Merge "NumNamedElements() should take an enum param." -7c68980 Fix asserts in Palette and BackwardReference code. -fbdcb7e NumNamedElements() should take an enum param. -fb4943b modify WebPParseHeaders to allow reuse by GetFeatures -3697b5c write an ad-hoc EncodeImageInternal variant -eaee9e7 Bug-Fix: Decode small (less than 32 bytes) images. -0bceae4 Merge "cwebp: fix alpha reporting in stats output" -0424b1e Rebase default encoding settings. -c71ff9e cwebp: fix alpha reporting in stats output -e2ffe44 Merge "Stop indefinite recursion for Huffman Image." -70eb2bd Stop indefinite recursion for Huffman Image. -f3bab8e Update vwebp -6d5c797 Remove support for partial files in Mux. -f1df558 WebPMuxAssemble() returns WebPData*. -814a063 Rename 'Add' APIs to 'Set'. -bbb0218 Update Mux psuedo-code examples. -4fc4a47 Use WebPData in MUX set APIs -c67bc97 Merge "add WebPPictureImportRGBX() and WebPPictureImportBGRX()" -27519bc add WebPPictureImportRGBX() and WebPPictureImportBGRX() -f80cd27 factorize code in Import() -9b71502 histogram: add log2 wrapper -8c34378 Merge "fix some implicit type conversion warnings" -42f6df9 fix some implicit type conversion warnings -250c16e Merge "doc: update lossless pdf" -9d9daba Merge "add a PDF of the lossless spec" -8fbb918 prefer webp/types.h over stdint.h -0ca170c doc: update lossless pdf -0862ac6 add a PDF of the lossless spec -437999f introduce a generic WebPPictureHasTransparency() function -d2b6c6c cosmetic fixes after Idaba281a -b4e6645 Merge "add colorspace for premultiplied alpha" -48f8275 add colorspace for premultiplied alpha -069f903 Change in lossless bit-stream. -5f7bb3f Merge "WebPReportProgress: use non-encoder specific params" -f18281f WebPReportProgress: use non-encoder specific params -9ef3228 Add support for raw lossless bitstream in decoder. -7cbee29 Fix bug: InitIo reseting fancy_upsampling flag. -880fd98 vwebp: fix exit w/freeglut -1875d92 trap two unchecked error conditions -87b4a90 no need to have mux.h as noinst clause in enc/ -88f41ec doc: fix bit alignment in VP8X chunk -52f5a4e Merge "fix bug with lossy-alpha output stride" -3bde22d fix bug with lossy-alpha output stride -42d61b6 update the spec for the lossy-alpha compression methods. -e75dc80 Move some more defines to format_constants.h -c13f663 Move consts to internal header format_constants.h -7f2dfc9 use a bit-set transforms_seen_ instead of looping -18da1f5 modulate alpha-compression effort according to config.method -f5f2fff Merge "Alpha flag fix for lossless." -c975c44 Alpha flag fix for lossless. -4f067fb Merge "Android: only build dec_neon with NEON support" -255c66b Android: only build dec_neon with NEON support -8f9117a cosmetics: signature fixes -39bf5d6 use header-less lossless bitstream for alpha channel -75d7f3b Merge "make input data be 'const' for VP8LInverseTransform()" -9a721c6 make input data be 'const' for VP8LInverseTransform() -9fc64ed Disallow re-use of same transformation. -98ec717 use a function pointer for ProcessRows() -f7ae5e3 cosmetics: join line -140b89a factor out buffer alloc in AllocateARGBBuffers() -a107dfa Rectify WebPParseOptionalChunks(). -237eab6 Add two more color-spaces for lossless decoding. -27f417a fix orthographic typo -489ec33 add VP8LEncodeStream() to compress lossless image stream -fa8bc3d make WebPEncodingSetError() take a const picture -638528c bitstream update for lossy alpha compression -d73e63a add DequantizeLevels() placeholder -ec122e0 remove arch-dependent rand() -d40e765 fix alignment -1dd6a8b Merge "remove tcoder, switch alpha-plane compression to lossless" -3e863dd remove tcoder, switch alpha-plane compression to lossless -8d77dc2 Add support for lossless in mux: -831bd13 Make tile size a function of encoding method. -778c522 Merge "remove some variable shadowing" -817c9dc Few more HuffmanTreeToken conversions. -37a77a6 remove some variable shadowing -89c07c9 Merge "normalize example header includes" -4aff411 Merge "add example_util.[hc]" -00b29e2 normalize example header includes -061263a add example_util.[hc] -c6882c4 merge all tree processing into a single VP8LProcessTree() -9c7a3cf fix VP8LHistogramNumCodes to handle the case palette_code_bits == 0 -b5551d2 Merge "Added HuffmanTreeCode Struct for tree codes." -8b85d01 Added HuffmanTreeCode Struct for tree codes. -093f76d Merge "Allocate single memory in GetHuffBitLengthsAndCodes." -41d8049 Allocate single memory in GetHuffBitLengthsAndCodes. -1b04f6d Correct size in VP8L header. -2924a5a Makefile.vc: split object lists based on directory -c8f2416 Merge "add assert(tokens)" -4323994 add assert(tokens) -9f54745 Catch an error in DecodeImageData(). -ac8e5e4 minor typo and style fix -9f566d1 clean-up around Huffman-encode -c579a71 Introduce CHUNK_SIZE_BYTES in muxi.h. -14757f8 Make sure huffman trees always have valid symbols -4105061 makefile.unix: add support for building vwebp -48b3772 Merge "fixed signed/unsigned comparison warning" -57f696d Merge "EncodeImageInternal: fix potential leak" -d972cdf EncodeImageInternal: fix potential leak -5cd12c3 fixed signed/unsigned comparison warning -cdca30d Merge "cosmetics: shorten long line" -e025fb5 cosmetics: shorten long line -22671ed Merge "enc/vp8l: fix double free on error" -e1b9b05 Merge "cosmetics: VP8LCreateHuffmanTree: fix indent" -a8e725f enc/vp8l: fix double free on error -27541fb cosmetics: VP8LCreateHuffmanTree: fix indent -1d38b25 cwebp/windows: use MAKE_REFGUID where appropriate -817ef6e Merge "cwebp: fix WIC/Microsoft SDK compatibility issue" -902d3e3 cwebp: fix WIC/Microsoft SDK compatibility issue -89d803c Merge "Fix a crash due to wrong pointer-integer arithmetic." -cb1bd74 Merge "Fix a crash in lossless decoder." -de2fe20 Merge "Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability." -ce69177 Fix a crash due to wrong pointer-integer arithmetic. -e40a368 Fix a crash in lossless decoder. -3927ff3 remove unneeded error condition for WebPMuxNumNamedElements() -2c140e1 Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability. -861a5b7 add support for animation -eb5c16c Merge "Set correct encode size in encoder's stats." -4abe04a fix the return value and handle missing input file case. -2fafb85 Set correct encode size in encoder's stats. -e7167a2 Provide one entry point for backward references. -c4ccab6 Print relevant lossless encoding stats in cwebp. -e3302cf GetHuffBitLengthsAndCodes: reduce level of indirection -b5f2a9e enc/vp8l: fix uninitialized variable warning -7885f8b makefile.unix: add lossless encoder files -1261a4c Merge "cosmetics" -3926b5b Merge "dsp/cpu.c: Android: fix crash on non-neon arm builds" -834f937 dsp/cpu.c: Android: fix crash on non-neon arm builds -126e160 cosmetics -e38602d Merge branch 'lossless_encoder' -e8d3d6a split StoreHuffmanCode() into smaller functions -d0d8899 more consolidation: introduce VP8LHistogramSet -1a210ef big code clean-up and refactoring and optimization -41b5c8f Some cosmetics in histogram.c -ada6ff7 Approximate FastLog between value range [256, 8192] -ec123ca Forgot to update out_bit_costs to symbol_bit_costs at one instance. -cf33ccd Evaluate output cluster's bit_costs once in HistogramRefine. -781c01f Simple Huffman code changes. -a2849bc Lossless decoder: remove an unneeded param in ReadHuffmanCodeLengths(). -b39e748 Reducing emerging palette size from 11 to 9 bits. -bfc73db Move GetHistImageSymbols to histogram.c -889a578 Improve predict vs no-predict heuristic. -01f5066 code-moving and clean-up -31035f3 reduce memory usage by allocating only one histo -fbb501b Restrict histo_bits to ensure histo_image size is under 32MB -8415ddf further simplification for the meta-Huffman coding -e491729 A quick pass of cleanup in backward reference code -83332b3 Make transform bits a function of encode method (-m). -72920ca introduce -lossless option, protected by USE_LOSSLESS_ENCODER -c6ac4df Run TraceBackwards for higher qualities. -412222c Make histo_bits and transform_bits function of quality. -149b509 Update lossless encoder strategy: -0e6fa06 cache_bits passed to EncodeImageInternal() -e38b40a Factorize code for clearing HtreeGroup. -6f4a16e Removing the indirection of meta-huffman tables. -3d33ecd Some renaming/comments related to palette in lossless encoder. -4d02d58 Lossless encoder: correction in Palette storage -4a63623 fix a memleak in EncodeImageInternal() -0993a61 Full and final fix for prediction transform -afd2102 Fix cross-color transform in lossless encoder -b96d874 Need to write a '0' bit at the end of transforms. -54dad7e Color cache size should be counted as 0 when cache bits = 0 -4f0c5ca Fix prediction transform in lossless encoder. -36dabda Fix memory leak in method EncodeImageInternal for histogram_image. -352a4f4 Get rid of PackLiteralBitLengths() -d673b6b Change the predictor function to pass left pixel -b2f9946 Fix CopyTileWithPrediction() -84547f5 Add EncodeImageInternal() method. -6b38378 Guard the lossless encoder (in flux) under a flag -09f7532 Fix few nits (const qualifiers) -648be39 Added implementation for various lossless functions -32714ce Add VP8L prefix to backward ref & histogram methods. -fcba7be Fixed header file tag (WEBP_UTILS_HUFFMAN_ENCODE_H_) -bc70374 Add backward_ref, histogram & huffman encode modules from lossless. -fdccaad Fixing nits -227110c libwebp interface changes for lossless encoding. -50679ac minor style fixes -b38dfcc remove unneeded reference to NUM_LITERAL_CODES -8979675 harmonize header description -c04eb7b tcoder.c: define NOT_HAVE_LOG2 for MSVC builds -9a214fa Merge "VP8[L]GetInfo: check input pointers" -5c5be8b VP8[L]GetInfo: check input pointers -0c188fe Merge changes I431acdfe,I713659b7 -b3515c6 mux: drop 'chunk' from ChunkInfo member names -aea7923 muxi.h: remove some unused defines -0142249 update NEWS file for next release -29e3f7e Merge "dec: remove deprecated WebPINew()" -4718e44 Merge "muxedit: a few more size_t changes" -82654f9 Merge "muxedit: remove a few redundant NULL checks" -02f27fb dec: remove deprecated WebPINew() -ccddb3f muxedit: remove a few redundant NULL checks -a6cdf71 muxedit: a few more size_t changes -a384689 Merge "mux: remove unused LIST_ID" -11ae46a alpha.c: quiet some size_t -> int conversion warnings -dee4669 mux: remove unused LIST_ID -03f1f49 mux: add version checked entry points -6a0abda Merge "doc: tile/alpha corrections" -c8139fb Merge "few cosmetics" -6833873 Merge "lossless: remove some size_t -> int conversions" -5249e94 doc: tile/alpha corrections -d96e722 huffman: quiet int64 -> int conversion warning -532020f lossless: remove some size_t -> int conversions -23be6ed few cosmetics -1349eda Merge "configure: AC_ARG_* use AS_HELP_STRING" -bfbcc60 configure: AC_ARG_* use AS_HELP_STRING -1427ca8 Merge "Makefile.am: header file maintenance" -087332e Merge "remove unused parameter 'round' from CalcProba()" -9630e16 remove unused parameter 'round' from CalcProba() -92092ea Merge "bit_reader.h: correct include" -a87fc3f Merge "mux: ensure # images = # tiles" -53af99b Merge "mux: use size_t consistently" -39a57da Makefile.am: header file maintenance -1bd0bd0 bit_reader.h: correct include -326a3c6 mux: ensure # images = # tiles -95667b8 mux: use size_t consistently -231ec1f Removing the indirection of meta-huffman tables. -15ebcba check return pointer from MuxImageGetListFromId -b0d6c4a Merge "configure: remove test for zlib.h" -8cccac5 Merge "dsp/lossless: silence some build warnings" -b08819a dsp/lossless: silence some build warnings -7ae2252 Android.mk: SSE2 & NEON updates -0a49e3f Merge "makefile.unix add missing header files" -2e75a9a Merge "decode.h: use size_t consistently" -fa13035 configure: remove test for zlib.h -d3adc81 makefile.unix add missing header files -262fe01 Merge "makefile.unix & Android.mk: cosmetics" -4cce137 Merge "enc_sse2 add missing stdlib.h include" -80256b8 enc_sse2 add missing stdlib.h include -9b3d1f3 decode.h: use size_t consistently -64083d3 Merge "Makefile.am: cosmetics" -dceb8b4 Merge changes If1331d3c,I86fe3847 -0e33d7b Merge "webp/decode.h: fix prototypes" -fac0f12 rename BitReader to VP8LBitReader -fbd82b5 types.h: centralize use of stddef.h -2154835 Makefile.am: cosmetics -1c92bd3 vp8io: use size_t for buffer size -90ead71 fix some more uint32_t -> size_t typing -cbe705c webp/decode.h: fix prototypes -3f8ec1c makefile.unix & Android.mk: cosmetics -217ec7f Remove tabs in configure.ac -b3d35fc Merge "Android.mk & Makefile.vc: add new files" -0df04b9 Android.mk & Makefile.vc: add new files -e4f20c5 Merge "automake: replace 'silent-rules' w/AM_SILENT_RULES" -8d254a0 cosmetics -6860c2e fix some uint32_t -> size_t typing -4af1858 Fix a crash due to max symbol in a tree >= alphabet size -6f01b83 split the VP8 and VP8L decoding properly -f2623db enable lossless decoder -b96efd7 add dec/vp8i.h changes from experimental -19f6398 add dec/vp8l{i.h,.c} from experimental -c4ae53c add utils/bit_reader.[hc] changes from experimental -514d008 add dsp/lossless.[hc] from experimental -9c67291 add utils/huffman.[hc] from experimental -337914a add utils/color_cache.[hc] from experimental -b3bf8fe the read-overflow code-path wasn't reporting as an error -1db888b take colorspace into account when cropping -61c2d51 move the rescaling code into its own file and make enc/ and dec/ use it. -efc2016 Make rescaler methods generic -3eacee8 Move rescaler methods out of io.c. -a69b893 automake: replace 'silent-rules' w/AM_SILENT_RULES -6f7bf64 issue 111: fix little-endian problem in bit-reader -ed278e2 Removed unnecessary lookup -cd8c3ba fix some warnings: down-cast and possibly-uninitialized variable -0a7102b ~1% improvement of alpha compression -3bc1b14 Merge "Reformat container doc" -dc17abd mux: cosmetics -cb5810d Merge "WebPMuxGetImage: allow image param to be NULL" -506a4af mux: cosmetics -135e8b1 WebPMuxGetImage: allow image param to be NULL -de556b6 Merge "README.mux: reword some descriptions" -0ee2aeb Makefile.vc: use batch mode rules -d9acddc msvc: move {i,p}db creation to object directory -237c9aa Merge "expose WebPFree function for DLL builds" -b3e4054 silence msvc debug build warning -45feb55 expose WebPFree function for DLL builds -11316d8 README.mux: reword some descriptions -4be52f4 factorize WebPMuxValidate -14f6b9f mux: light cleanup -5e96a5d add more param checks to WebPPictureDistortion() -8abaf82 Merge "silence some type size related warnings" -1601a39 silence some type size related warnings -f3abe52 Merge "idec: simplify buffer size calculation" -a9c5cd4 idec: simplify buffer size calculation -7b06bd7 Merge "configure/automake: add silent-rules option" -e9a7d14 Reformat container doc -d4e5c7f configure/automake: add silent-rules option -5081db7 configure/automake: no -version-info for convenience libs -85b6ff6 Merge "idec: fix WebPIUpdate failure" -7bb6a9c idec: fix internal state corruption -89cd1bb idec: fix WebPIUpdate failure -01b6380 4-5% faster decoding, optimized byte loads in arithmetic decoder. -631117e Merge "cosmetics & warnings" -a0b2736 cosmetics & warnings -f73947f use 32bit for storing dequant coeffs, instead of 16b. -b960030 Merge "store prediction mode array as uint8_t[16], not int[16]." -7b67881 store prediction mode array as uint8_t[16], not int[16]. -cab8d4d Merge "NEON TransformOne" -ba503fd NEON TransformOne -9f740e3 Merge "gcc warning fix: remove the 'const' qualifier." -f76d358 gcc warning fix: remove the 'const' qualifier. -e78478d Merge "webpmux: make more use of WebPData" -f85bba3 Merge "manpages: add BUGS section" -48a43bb Merge "makefile.unix: variable cosmetics" -c274dc9 makefile.unix: variable cosmetics -1f7b859 re-organize the error-handling in the main loop a bit -1336fa7 Only recompute level_cost_[] when needed -771ee44 manpages: add BUGS section -0f7820e webpmux: make more use of WebPData -974aaff examples: logging updates -6c14aad Merge "better token buffer code" -f405425 better token buffer code -18d959f Merge "mux: add WebPData type" -eec4b87 mux: add WebPData type -0de3096 use 16bit counters for recording proba counts -7f23678 fix for LevelCost + little speed-up -7107d54 further speed-up/cleanup of RecordCoeffs() and GetResidualCost() -fd22104 Introduce Token buffer (unused for now) -5fa148f Merge "speed-up GetResidualCost()" -28a9d9b speed-up GetResidualCost() -11e7dad Merge "misc cosmetics" -378086b misc cosmetics -d61479f add -print_psnr and -print_ssim options to cwebp. -2e3e8b2 add a WebPCleanupTransparentArea() method -552c121 Merge "mux: plug some memory leaks on error" -a2a81f7 Merge "fix Mach-O shared library build" -b3482c4 Merge "fix gcc-4.0 apple 32-bit build" -e4e3ec1 fix gcc-4.0 apple 32-bit build -b0d2fec mux: plug some memory leaks on error -f0d2c7a pass of cosmetics -b309a6f fix Mach-O shared library build -241ddd3 doc: delete mux container pdf -8b1ba27 doc: update VP8 decode guide link -7e4371c WebPMuxCreate: fix unchecked malloc -eb42558 Merge "have makefile.unix clean up src/webp/*~ too" -a85c363 Merge "correct EncodeAlpha documentation" -a33842f Merge "Update webp container spec with alpha filter options." -8d6490d Incremental support for some of the mux APIs. -b8375ab have makefile.unix clean up src/webp/*~ too -b5855fc correct EncodeAlpha documentation -dba37fe Update webp container spec with alpha filter options. -2e74ec8 fix compile under MINGW -716d1d7 fix suboptimal MAX_LEN cut-off limit -57cab7b Harmonize the alpha-filter predictions at boundary -3a98953 Merge "Fix bug for Alpha in RGBA_4444 color-mode." -8ca2076 Introduce a 'fast' alpha mode -221a06b Fix bug for Alpha in RGBA_4444 color-mode. -ad1e163 cosmetics: normalize copyright headers -c77424d cosmetics: light include cleanup -9d0e17c fix msvc build breakage after 252028a -7c4c177 Some readability fixes for mux library -d8a47e6 Merge "Add predictive filtering option for Alpha." -252028a Add predictive filtering option for Alpha. -9b69be1 Merge "Simplify mux library code" -a056170 Simplify mux library code -992187a improve log2 test -e852f83 update Android.mk file list -a90cb2b reduce number of copies and mallocs in alpha plane enc/dec -b1662b0 fix some more type conversion warnings w/MSVC -223d8c6 fix some uint64_t -> int conversion warnings with MSC -c1a0437 Merge "simplify checks for enabling SSE2 code" -f06817a simplify checks for enabling SSE2 code -948d4fe silence a msvc build warning -9117954 vwebp: msvc build tweaks -7937b40 simple WebP viewer, based on OpenGL -6aac1df add a bunch of missing 'extern "C"' -421eb99 Merge "Remove assigned-but-not-used variable "br"" -91e27f4 better fitting names for upsampling functions -a5d7ed5 Remove assigned-but-not-used variable "br" -f62d2c9 remove unused 'has_alpha' from VP8GetInfo() signature -08e8658 trap alpha-decoding error -b361eca add cut-off to arith coder probability update. -8666a93 Some bug-fixes for images with alpha. -273a12a fix off-by-1 diff in case cropping and simple filtering -2f741d1 webpmux: ReadImage: fix ptr free in error case -721f3f4 fix alpha decode -60942c8 fix the has_alpha_ order -30971c9 Implement progress report (and user abort) -eda520a cosmetics after 9523f2a -38bd5bb Merge "Better alpha support in webpmux binary" -ccbaebf Merge "Updated the includes to relative paths." -d71fbdc fix small typo in error message array -cdf97aa Better alpha support in webpmux binary -885f25b Updated the includes to relative paths. -a0ec9aa Update WebP encoder (cwebp) to support Alpha. -667b769 Fixed the include for types.h within mux.h -9523f2a Add Alpha Encode support from WebPEncode. -16612dd Merge "Add Alpha Decode support from WebPDecode." -d117a94 Add Alpha Decode support from WebPDecode. -6722873 cosmetics after e1947a9 -e1947a9 Add Alpha encode/decode code. -afc4c5d simplify code by introducing a CopyPlane() helper func -113b312 Merge "MUX API Updates" -c398f59 MUX API Updates -5acf04e remove orphan source file -059f03e Merge "dec: validate colorspace before using as array index" -70a0398 Merge "factorize some code" -9b243b3 factorize some code -372e2b4 Correct a bug in ReadPNG() with GRAY_ALPHA images -469d6eb Merge "Makefile.am: remove redundant noinst_HEADERS" -9fe3372 dec: validate colorspace before using as array index -8962030 remove orphan source file -ced3e3f Makefile.am: remove redundant noinst_HEADERS -964387e use WEBP_INLINE for inline function declarations -90880a1 Merge "manpages: break long lines" -b591089 Merge "manpages: minor formatting updates" -4c451e4 Merge "Rectify the Chunk parsing logic." -04e84cf examples: slight cleanup -099717c manpages: break long lines -1daf39b manpages: minor formatting updates -abd030b fix missing "(void)" in function signature -f6a7d75 remove useless test -f07b213 Rectify the Chunk parsing logic. -b8634f7 webpmux: fix lib link order -42c2e68 Fix missing coma (on uncompiled code) -d8329d4 Android.mk: add missing source files -13a54df Merge "More aggressive copy-edit; add TODO; validate HTML5" -868b96a More aggressive copy-edit; add TODO; validate HTML5 -767afea configure: check for a symbol contained in libpng -408b891 Merge "Linewrap at 72 cols. Casual copy-edit." -3ae318c Merge "Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.)" -918eb2d Merge "Basic container doc source clean-up; fix lists and pseudocode blocks." -03bec9e Linewrap at 72 cols. Casual copy-edit. -2678d81 Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.) -428674d Basic container doc source clean-up; fix lists and pseudocode blocks. -6a77d92 Merge "Makefile.vc: cosmetics" -28c38e8 Merge "Makefile.vc: condense directory creation rules" -55be2cf Initial import of container spec document, from pdftotext transform. -a82a788 Makefile.vc: cosmetics -c8f41ce Makefile.vc: condense directory creation rules -2b877cd Some fixes to Makefile.vc to support the src\mux directory. -3eb969b Merge "Add Makefile.vc for Mux library & binary." -e78e971 Add Makefile.vc for Mux library & binary. -6aedde5 Add manual for WebPMux tool. -8a360d0 Merge "Added WebPMux Binary." -a4f32ca Added WebPMux Binary. -f3bf4c7 Added Mux Container Spec & README for MUX-API. -9f761cf Changed function signature for WebPMuxCreate -5f31b5e Merge "Add Mux library for manipulating WebP container." -2315785 Add Mux library for manipulating WebP container. -7e198ab update ChangeLog (tag: v0.1.3) -dfc9c1e Harmonize the dates -28ad70c Fix PNG decoding bug -846e93c Update AUTHORS & add .mailmap -563e52d cosmetics after '76036f5 Refactor decoder library' -76036f5 Refactor decoder library -377ef43 configure.ac: update AC_INIT params -7a8d876 use a user-visible MACRO for max width/height. -d4e9f55 NEON decode support in WebP -0ee683b update libtool version-info -fdbe02c windows: match _cond_destroy logic w/return variable name -206b686 README: correct advanced decode api pseudo-code -6a32a0f make VP8BitReader a typedef, for better re-use -b112e83 create a libwebputils under src/utils -ee697d9 harmonize the include guards and #endif comments -a1ec07a Fixing compiler error in non x86 arch. -dcfa509 Fixed recursive inclusion of bit_writer.h and vp8enci.h. -e06ac08 create a separate libwebpdsp under src/dsp -ebeb412 use unsigned int for bitfields -341cc56 make kNewRange a static array -227a91e README: minor wording update -05bd8e6 add man pages to dist -812dfa1 bump up versions in preparations for 0.1.3 -a5b78c8 wrap alpha-related options under WEBP_EXPERIMENTAL_FEATURES flag -34dc790 regen ChangeLog for 0.1.3-rc2 -7c43663 Silence some (more) Visual Studio warnings. -60306e8 add top-level gitattributes -2aa6b80 Slience some Visual Studio warnings. -4cbbb29 Merge "bump up version for next freeze" -a329167 bump up version for next freeze -c7e86ab cosmetics: fix comment line lengths -c9e037a makefile.unix: add simple dist target -87d58ce makefile.unix: rule maintenance -d477de7 mend -fac15ec Update NEWS & README for next release V0.1.3 -6215595 Merge "add a -partition_limit option to limit the number of bits used by intra4x4" -3814b76 Merge "reorganize chunk-parsing code" -900286e add a -partition_limit option to limit the number of bits used by intra4x4 -cd12b4b add the missing cost for I4/I16 mode selection -dfcc213 reorganize chunk-parsing code -3cf2030 initialize pointers to function within VP8DspInit() -d21b479 Merge "windows: add decode threading support" -473ae95 fix hang on thread creation failure -fccca42 windows: add decode threading support -a31f843 Use the exact PNG_INCLUDES/PNG_LIBS when testing for -lpng -ad9b45f Merge "Makefile.vc: rule maintenance" -565a2ca Makefile.vc: rule maintenance -2d0da68 makefile.unix: disable Wvla by default -fc7815d multi-thread decoding: ~25-30% faster -acd8ba4 io->teardown() was not always called upon error -c85527b Merge "Makefile.vc: add DLL configs" -e1e9be3 cosmetics: spelling/grammar in README and lib headers -b4d0ef8 Makefile.vc: add DLL configs -998754a remove unused nb_i4_ and nb_i16_ fields. -9f01ce3 rename WebPDecBuffer::memory -> private_memory -fb5d659 fix an overflow bug in LUT calculation -d646d5c swig: add WebPDecodeARGB -78aeed4 add missing WebPDecodeARGBInto() and switch ARGB4444 to RGBA4444 as was intended -cd7c529 explicitly mark library functions as extern -19db59f add support for RGB565, ARGB4444 and ARGB colorspace (decoder) -c915fb2 encoder speed-up: hardcode special level values -c558bda Rename and improve the API to retrieve decoded area -bf599d7 Merge "makefile.unix: disable -Wvla by default" -c9ea03d SSE2 version of strong filtering -993af3e makefile.unix: disable -Wvla by default -3827e1b Merge "examples: (windows/WIC) add alpha support" -e291fae SSE2 functions for the fancy upsampler. -a06bbe2 add WebPISetIOHooks() to set some custom hooks on the incremental decoder object. -7643a6f Merge "makefile.unix: use uname to detect OSX environment" -5142a0b export alpha channel (if present) when dumping to PGM format -14d5731 makefile.unix: use uname to detect OSX environment -0805706 examples: quiet warnings -3cfe088 examples: (windows/WIC) add alpha support -13ed94b add compile warning for variable-length-array -5a18eb1 Merge "add Advanced Decoding Interface" -5c4f27f add missing \n -f4c4e41 80 cols fix -d260310 add Advanced Decoding Interface -bd2f65f sse2 version of the complex filter -96ed9ce perform two idct transforms at a time when possible -01af7b6 use aligned stored -0e1d1fd Merge "Makefile.vc: add experimental target" -2a1292a Makefile.vc: add experimental target -23bf351 Enable decode SSE2 for Visual Studio -131a4b7 dec/dsp_sse2: fix visual studio compile -00d9d68 swig: file reorganization -7fc7e0d Merge "swig/java: basic encode support" -3be57b1 fix MSVC compile for WEBP_EXPERIMENTAL_FEATURES -40a7e34 dec/dsp: disable sse2 for Visual Studio builds -e4d540c add SSE2 code for transform -54f2170 swig/java: basic encode support -c5d4584 call function pointers instead of C-version -ea43f04 Merge "configure: mingw32 targets: test for WIC support" -a11009d SSE2 version of simple in-loop filtering -42548da shave one unneeded filter-cache line -31f9dc6 configure: mingw32 targets: test for WIC support -1955969 Merge "split expression in two." -415dbe4 split expression in two. -e29072a configure: test for zlib only w/--enable-experimental -b2b0090 Simplify Visual Studio ifdefs -ca7a2fd Add error reporting from encoding failures. -6c9405d Merge "Makefile.vc: require CFG with clean target" -0424ecd Makefile.vc: require CFG with clean target -003417c Enable SSE2 for Visual Studio builds -af10db4 little speed up for VP8BitUpdate() -e71418f more MSVC files to ignore -46d9036 cosmetics -edf59ab typo fix -72229f5 Add support for x64 and SSE2 builds under Windows. -92e5c6e VP8GetInfo() + WebPResetDecParams() -416b7a6 raise the fixed-point precision for the rescaler -aa87e4e fix alignment -eb66670 disable WEBP_EXPERIMENTAL_FEATURES -c5ae7f6 typo fix: USE_ => WEBP_ -d041efa swig: add libwebp.jar/libwebp_java_wrap.c -f6fb387 add swig interface -e927390 align buffer for double too -842c009 fix -strong option -d0a7038 Merge "cosmetics" -fc0a02e fix the dichotomy loop -38369c0 cosmetics -8dfc4c6 factorize and unify GetAlpha() between the C and SSE2 version -6d0e66c prepare experimentation with yuv444 / 422 -79cc49f add a --enable-experimental option to './configure' -d757523 sse2 version of CollectHistogram() -c1c728d add an extra #ifdef WEBP_EXPERIMENTAL_FEATURES to avoid 'unused variable' warning -60c61d2 always call VP*EncDeleteAlpha() unconditionnally, for simplicity -0f8c638 simply don't call WriteExtensions() if WEBP_EXPERIMENTAL_FEATURES is not defined -47c661d rename swap -> swap_rb -10d55bb move chunk[] declaration out of the for() loop -517cec2 fix indentation -f7d9e26 fix merge problems -8fd42b3 add a stride 'a_stride' for the alpha plane -b8dcbf2 fix alpha-plane copy and crop methods -cdef89d fix some 'unused variable' warning -fb29c26 SSE2 version of the fwd transform and the squared sum metric -2ab4b72 EXPERIMENTAL: add support for alpha channel -cfbf88a add SSE2 functions. ~2x faster encoding on average. -e7ff3f9 merge two ITransforms together when applicable and change the TTransform to return the sum directly. -ca55413 fix WebPIDecGetRGB() to accept any RGB(A) mode, not just MODE_RGB -8aa50ef fix some 'man' typos -d3f3bdd update ChangeLog (tag: v0.1.2) -d7e9a69 update contributor list -261abb8 add a 'superclean' section -276ae82 Remove files not mean to be in git, and update .gitignore -2486845 build: prepare libwebp.pc -14ceb6e add "-version" description to man pages -b247a3b Create the m4 directory, and also place .gitignore in there for libtool. -cdd734c Resolve automake warnings -c5fa726 build: add pkgconfig files -b20aaca build: just use autoreconf, avoid calling tools manually -4b0b0d6 cwebp: use modern functions -efbc6c4 update Android.mk -7777570 better version of ChangeLog -fa70d2b update version number in the DOC -f8db5d5 more C89-fixes -0de013b fix typos -650ffa3 add version getters for decoder and encoder -be4867d doc for incremental decoding -56732a1 add idec.obj in MSVC makefile -208afb5 add c++ guards -8bf76fe add incremental decoding -1f28832 'inline' isn't defined in strict ansi c89 -8b77c63 move the quantization function to dsp.c -b2c3575 add a 'last_y' field to WebPDecParams -2654c3d correctly pass along the exact same status returned from ParsePartitions -4704146 add missing precision in the man -6d978a6 add error messages -6463e6a add some install instructions, and fix intel-mac flags -05fb7bf Merge ".gitignore: initial version" -c33f019 .gitignore: initial version -e532b9a Makefile: allow out of tree builds -4c0da7a enable sparse dc/ac transforms -07dbb8d clarify the return logic -5c69e1b fix bigger-by-1 array -7c5267e fix a (harmless) typo: non_zero_ -> non_zero_ac_ -bc75213 fix missing free() -af3e2aa remove trailing spaces -13e50da make the bitreader preload at least 8bits, instead of post-load them (this makes initialization easier and will be helpful for incremental decoding). Modify ParsePartitions() to accommodate for truncated input. -f4888f7 emit 9 - nb_bits trailing zeros instead of 8 -3db6525 separate block-parsing into a visible VP8DecodeMB() -a871de0 add missing extern "C" -b3ce8c5 remove a gcc warning about type pun by using a proper union'd type -e186371 update after addition of webpi.h -3e856e2 Extract some useful functions around decoding buffer WebPDecParams. -d5bc05a make the filtering process match libvpx and ffvp8 -dd60138 add man pages for cwebp(1) and dwebp(1) -c4fa364 fix header -5b70b37 * add an option to bypass_filtering in VP8Io. -b97a400 simplify QuantizeBlock code a bit -84b58eb add more checks around picture allocation -b65a3e1 remove absolute_delta_ field and syntax code -0744e84 Dont' open output file until we're sure the input file is valid -d5bd54c fix typo and buggy line -f7a9549 Add a simple top-level makefile.unix for quick & easy build. -5f36b94 update the doc for the -f option -f61d14a a WebP encoder converts PNG & JPEG to WebP -81c9662 oops: forgotten call to Initialize() + move the error message to a more useful place -87ffa00 typo: fix a missing 'R', was confusing. -b04b857 * add decoding measurement using stopwatch.h (use -v option) * support PNG output through WIC on Win32 -746a482 * make (*put)() hook return a bool for abort request. * add an enum for VP8Status() to make things clearer -73c973e * strengthen riff/chunk size checks * don't consider odd-sized chunks being an error -1dc4611 add support for PNG output (default) regularize include guards -860641d fix a typo: sizeof(kYModeProbaInter0) => sizeof(kUVModeProbaInter0) -3254fc5 fix some petty constness fix the ./configure file too -504d339 fix eof_ mis-initialization -2bc0778 leftover Makefile.* from previous commit -d2cf04e move Makefile.am one level below, to src/dec fix typos here and there dwebp is now an installed program -ade92de typo: vp8.h -> decode_vp8.h -d724124 forgot to declare types.h to be installed -6421a7a move the decoder sourcetree to a sub-location src/dec to make room for future libs sources -a9b3eab correct layout name is IMC4. -2330522 handle corner case of zero-dimensions -280c365 make VP8Init() handle short buffers (< 2 bytes) correctly -b1c9e8b handle error cases more robustly -0e94935 Merge "table-less version of clip_8b()" -1e0a2d2 table-less version of clip_8b() -e12109e dwebp: change -yuv option to -raw change the layout to IMC2 -d72180a speed-up fancy upscaler -9145f3b reset eof_ at construction time -a7ee055 simplify the logic of GetCoeffs() -f67b593 lot of cosmetics -ea27d7c fix endian problem on PowerPC -beb0a1b fix signature of VP8StoreBlock -b128c5e Merge "fancy chroma upscaling" -6a37a2a fancy chroma upscaling -ff565ed fix two numeric typos -5a936a0 use uintptr_t for casting pointers to ints -e14a030 for cross_compiling=yes to prevent executing any binary -83b545e add vc9+ makefile -296f691 fix output loop for small height -cbfbb5c convert to plain-C -f09f96e Fix declaration after statement warning -5981ee5 Fix UV plane ac/dc quantizer transposition -c8d15ef convert to ANSI-C -c3f41cb Initial commit +20a7fea0 extras/Makefile.am: fix libwebpextras.la reference +415f3ffe update ChangeLog (tag: v0.6.0-rc3) +3c6d1224 update NEWS +ee4a4141 update AUTHORS +32ed856f Fix "all|no frames are keyframes" settings. +f4dc56fd disable GradientUnfilter_NEON +0d8e0588 img2webp: treat -loop as a no-op w/single images +b0450139 ReadImage(): restore size reporting +0ad3b4ef update ChangeLog (tag: v0.6.0-rc2) +6451709e img2webp,get_disto: fix image decode w/WIC builds +92504d21 get_disto: make ReadPicture() return a bool +c3e4b3a9 update NEWS +3363eb6d man/img2webp.1: fix formatting warning +4d1312f2 update NEWS +36c42ea4 bump version to 0.6.0 +bb498a51 update AUTHORS +84cef16f Makefile.vc: fix CFG=debug-dynamic build +919f9e2f Merge "add .rc files for windows dll versioning" +f1ae8af4 Merge ".gitignore: add img2webp" +4689ce16 cwebp: add a -sharp_yuv option for 'sharp' RGB->YUV conversion +79bf46f1 rename the pretentious SmartYUV into SharpYUV +eb1dc89a silently expose use_delta_palette in the WebPConfig API +c85b0dde .gitignore: add img2webp +43d3f01a add .rc files for windows dll versioning +668e1dd4 src/{dec,enc,utils}: give filenames a unique suffix +0e6b7f33 Merge "iosbuild.sh: only add required headers to framework" +29ed6f9a iosbuild.sh: only add required headers to framework +71c53f1a NEON: speed-up strong filtering +73f567ea Merge "get_disto: remove redundant reader check" +9e14276f Merge "makefiles: prune get_disto & webp_quality deps" +99965bac Merge "Makefile.vc: add get_disto.exe, webp_quality.exe" +d4912238 get_disto: remove redundant reader check +ea482409 makefiles: prune get_disto & webp_quality deps +2ede5a19 Makefile.vc: add get_disto.exe, webp_quality.exe +a345068a ARM: speed up bitreader by avoiding tables +1dc82a6b Merge "introduce a generic GetCoeffs() function pointer" +8074b89e introduce a generic GetCoeffs() function pointer +749a45a5 Merge "NEON: implement alpha-filters (horizontal/vertical/gradient)" +74c053b5 Merge "NEON: fix overflow in SSE NxN calculation" +0a3aeff7 Merge "dsp: WebPExtractGreen function for alpha decompression" +1de931c6 NEON: implement alpha-filters (horizontal/vertical/gradient) +9b3aca40 NEON: fix overflow in SSE NxN calculation +1c07a3c6 dsp: WebPExtractGreen function for alpha decompression +9ed5e3e5 use pointers for WebPRescaler's in WebPDecParams +db013a8d Merge "ARM: don't use USE_GENERIC_TREE" +fcd4784d use a 8b table for C-version for clz() +fbb5c473 ARM: don't use USE_GENERIC_TREE +8fda5612 Merge "add a kSlowSSSE3 feature for CPUInfo" +86bbd245 add a kSlowSSSE3 feature for CPUInfo +7c2779e9 Get code to fully compile in C++. +250c3586 Merge "When compiling as C++, avoid narrowing warnings." +c0648ac2 When compiling as C++, avoid narrowing warnings. +0d55f60c 40% faster ApplyAlphaMultiply_SSE2 +49d0280d NEON: implement several alpha-processing functions +48b1e85f SSE2: 15% faster alpha-processing functions +e3b8abbc fix warning from static analysis. +28fe054e SSE2: 30% faster ApplyAlphaMultiply() +f44acd25 Merge "Properly compute the optimal color cache size." +527844fe Properly compute the optimal color cache size. +be0ef639 fix a comment typo +8874b162 Fix a non-deterministic color cache size computation. +d712e20d Do not allow a color cache size bigger than the number of colors. +ecff04f6 re-introduce some comments in Huffman Cost. +259e9828 replace 'ptr + y * stride' by 'ptr += stride' +00b08c88 Merge "NEON: 5% faster conversion to RGB565 and RGBA4444" +0e7f4447 Merge "NEON: faster fancy upsampling" +b016cb91 NEON: faster fancy upsampling +1cb63801 Call the C function to finish off lossless SSE loops only when necessary. +875fafc1 Implement BundleColorMap in SSE2. +3674d49e Merge "remove Clang warnings with unused arch arguments." +f04eb376 Merge tag 'v0.5.2' +341d711c NEON: 5% faster conversion to RGB565 and RGBA4444 +abb54827 remove Clang warnings with unused arch arguments. +ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2, origin/0.5.2, 0.5.2) +aa7744ca anim_util: quiet implicit conv warnings in 32-bit +d9120271 jpegdec: correct ContextFill signature +24eb3940 Remove some errors when compiling the code as C++. +a4a8e5f3 vwebp: clear canvas during resize w/o animation +67c25ad5 vwebp: clear canvas during resize w/o animation +a4bbe4b3 fix indentation +31ca2a80 tiffdec: restore libtiff 3.9.x compatibility +b2f77b57 update NEWS +5ab6d9de AnimEncoder: avoid freeing uninitialized memory pointer. +f29bf582 WebPAnimEncoder: If 'minimize_size' and 'allow_mixed' on, try lossy + lossless. +3ebe1c00 AnimEncoder: avoid freeing uninitialized memory pointer. +df780e0e fix a potential overflow with MALLOC_LIMIT +58fc5078 Merge "PredictorSub: implement fully-SSE2 version" +9cc42167 PredictorSub: implement fully-SSE2 version +0aa1f35c remove dependency of imageio/ to stopwatch.h +cb9ec84b Merge "remove the dependency to stop_watch.[ch] in imageio" +dc0c01fb Merge "anim_util: quiet implicit conv warnings in 32-bit" +827d3c50 Merge "fix a potential overflow with MALLOC_LIMIT" +1e2e25b0 anim_util: quiet implicit conv warnings in 32-bit +218460cd bump version to 0.5.2 +de7d654d update AUTHORS & .mailmap +273367c1 Merge "dsp/lossless.c,cosmetics: fix indent" +76bbcf2e fix a potential overflow with MALLOC_LIMIT +8ac1abfe Merge "jpegdec: correct ContextFill signature" +cb215aed remove the dependency to stop_watch.[ch] in imageio +2423017a dsp/lossless.c,cosmetics: fix indent +74a12b10 iosbuild.sh: add WebPDecoder.framework + encoder +a9cc7621 Merge "iosbuild.sh: add WebPDecoder.framework + encoder" +fbba5bc2 optimize predictor #1 in plain-C For some reason, gcc has hard time inlining this one... +9ae0b3f6 Merge "SSE2: slightly (~2%) faster Predictor #1" +c1f97bd7 SSE2: slightly (~2%) faster Predictor #1 +ea664b89 SSE2: 10% faster Predictor #11 +be7dcc08 AnimEncoder: Correctly skip a frame when sub-rectangle is empty. +40885830 Fix assertions in WebPRescalerExportRow() +1d5046d1 iosbuild.sh: add WebPDecoder.framework + encoder +cec72014 jpegdec: correct ContextFill signature +8f38c72e fix a typo in WebPPictureYUVAToARGB's doc +33ca93f9 systematically call WebPDemuxReleaseIterator() on dec->prev_iter_ +76e19073 doc: use two's complement explicitly for uint8->int8 conversion +f91ba963 Anim_encoder: correctly handle enc->prev_candidate_undecided_ +25d74e65 WebPPictureDistortion(): free() -> WebPSafeFree() +03f1c008 mux/Makefile.am: add missing -lm +58410cd6 fix bug in RefineUsingDistortion() +e168af8c fix filtering auto-adjustment +ed9dec41 fix doc and code snippet for WebPINewDecoder() doc +3c49178f prevent 32b overflow for very large canvas_width / height +9595f290 fix anim_util.c compilation when HAVE_GIF is not defined. +7ec9552c Make gif transparent color to be transparent black +b3fb8bb6 slightly faster Predictor #11 in NEON +9871335f Add a CMake option for WEBP_SWAP_16BIT_CSP. +0ae32226 Fix missing cpu-features for Android. +ab4c8056 cpu.cmake: improve webp_check_compiler_flag output +eec5fa3a Provide support for CMake on Android studio 2.2. +004d5690 Split the main CMake file. +4fe5d588 Android.mk: use -fvisibility=hidden +bd63a31a vwebp: ensure setenv() is available in stdlib.h +363a5681 vwebp: handle window resizing properly +a0d2753f lower WEBP_MAX_ALLOCABLE_MEMORY default +31fe11a5 fix infinite loop in case of PARTITION0 overflow +532215dd Change the rule of picking UV mode in MBAnalyzeBestUVMode() +9c75dbd3 cwebp.1: improve some grammar +af2e05cb vwebp: Clear previous frame when a key triggers a redraw +26ffa296 Add descriptions of default configuration in help info. +7416280d Fix an unsigned integer overflow error in enc/cost.h +13cf1d2e Do token recording and counting in a single loop +eb9a4b97 Reset segment id if we decide not to update segment map +42ebe3b7 configure: fix NEON flag detection under gcc 6 +76ebbfff NEON: implement predictor #13 +95b12a08 Merge "Revert Average3 and Average4" +54ab2e75 Revert Average3 and Average4 +fe12330c 3-5% faster Predictor #5, #6, #7 and #10 for NEON +fbfb3bef ~2% faster predictor #10 for NEON +d4b7d801 lossless_sse2: use the local functions +a5e3b225 Lossless decoder SSE2 improvements. +58a1f124 ~2% faster predictor #12 in NEON. +906c3b63 Merge "Implement lossless transforms in NEON." +d23abe4e Implement lossless transforms in NEON. +2e6cb6f3 Give more flexibility to the predictor generating macro. +28e0bb70 Merge "Fix race condition in multi-threading initialization." +64704530 Fix race condition in multi-threading initialization. +bded7848 img2webp: fix default -lossless value and use pic.argb=1 +0e61a513 Merge "img2webp: convert a sequence of images to an animated webp" +1cc79e92 AnimEncoder: Correctly skip a frame when sub-rectangle is empty. +03f40955 img2webp: convert a sequence of images to an animated webp +ea72cd60 add missing 'extern' keyword for predictor dcl +67879e6d SSE implementation of decoding predictors. +34aee990 Merge "vwebp: make 'd' key toggle the debugging of fragments" +a41296ae Fix potentially uninitialized value. +c85adb33 vwebp: make 'd' key toggle the debugging of fragments +4239a148 Make the lossless predictors work on a batch of pixels. +bc18ebad fix extra 'const's in signatures +71e2f5ca Remove memcpy in lossless decoding. +7474d46e Do not use a register array in SSE. +67748b41 Improve latency of FTransform2. +16951b19 Merge "Provide an SSE implementation of ConvertBGRAToRGB" +6540cd0e Provide an SSE implementation of ConvertBGRAToRGB +de568abf Android.mk: use -fvisibility=hidden +3c2a61b0 remove some unneeded casts +9ac063c3 add dsp functions for SmartYUV +22efabdd Merge "smart_yuv: switch to planar instead of packed r/g/b processing" +1d6e7bf3 smart_yuv: switch to planar instead of packed r/g/b processing +0a3838ca fix bug in RefineUsingDistortion() +c0699515 webpmux -duration: set default 'end' value equal to 'start' +83cbfa09 Import: use relative pointer offsets +a1ade40e PreprocessARGB: use relative pointer offsets +fd4d090f ConvertWRGBToYUV: use relative pointer offsets +9daad459 ImportYUVAFromRGBA: use relative pointer offsets +f90c60d1 Merge "add a "-duration duration,start,end" option to webpmux" +3f182d36 add a "-duration duration,start,end" option to webpmux +342e15f0 Import: use relative pointer offsets +1147ab4e PreprocessARGB: use relative pointer offsets +e4cd4daf fix filtering auto-adjustment +e7152856 fix doc and code snippet for WebPINewDecoder() doc +de9fa507 ConvertWRGBToYUV: use relative pointer offsets +deb1b831 ImportYUVAFromRGBA: use relative pointer offsets +c284780f imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow +e375080d gifdec,Remap: avoid out of bounds colormap read +c222a053 additional fix for stride type as size_t +bb233617 fix potential overflow when width * height * 4 >= (1<<32) +883d41fb gif2webp: fix crash with NULL extension data +cac9a36a gifdec,Remap: avoid out of bounds colormap read +4595e01f Revert "gifdec,Remap: avoid out of bounds colormap read" +fb52d443 gifdec: make some constants unsigned +f048d38d gifdec,Remap: avoid out of bounds colormap read +31b1e343 fix SSIM metric ... by ignoring too-dark area +2f51b614 introduce WebPPlaneDistortion to compute plane distortion +0104d730 configure: fix NEON flag detection under gcc 6 +265abbe9 Merge "additional fix for stride type as size_t" +f7601aa6 Merge "Introduce a generic WebPGetImageReader(type) function" +ce873320 Introduce a generic WebPGetImageReader(type) function +2a2773ea imageio/*dec,Read*: add input parameter checks +9f5c8eca additional fix for stride type as size_t +4eb5df28 remove unused stride fields from VP8Iterator +11bc423a MIN_LENGTH cleanups. +273d035a Merge "fix a typo in WebPPictureYUVAToARGB's doc" +4db82a17 Merge "fix potential overflow when width * height * 4 >= (1<<32)" +e2affacc fix potential overflow when width * height * 4 >= (1<<32) +dc789ada fix a typo in WebPPictureYUVAToARGB's doc +539f5a68 Fix non-included header in config.c. +aaf2a6a6 systematically call WebPDemuxReleaseIterator() on dec->prev_iter_ +20ef9915 Merge "imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow" +bc86b7a8 imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow +806f6279 gif2webp: fix crash with NULL extension data +68ae5b67 Add libwebp/src/mux/animi.h +28ce3043 Remove some errors when compiling the code as C++. +b34abcb8 Favor keeping the areas locally similar in spatial prediction mode selection +ba843a92 fix some SSIM calculations +51b71fd2 Merge "vwebp: ensure setenv() is available in stdlib.h" +fb01743a get_disto: fix the r/g/b order for luma calculation +bfab8947 vwebp: ensure setenv() is available in stdlib.h +9310d192 vwebp: handle window resizing properly +f79450ca Speedup ApplyMap. +cfdda7c6 Merge "prevent 32b overflow for very large canvas_width / height" +e36396ba Merge "get_disto: new option to compute SSIM map and convert to gray" +18a9a0ab Add an API to import a color-mapped image. +30d43706 Speed-up Combined entropy for palettized histograms. +36aa087b get_disto: new option to compute SSIM map and convert to gray +86a84b35 2x faster SSE2 implementation of SSIMGet +b8384b53 lower WEBP_MAX_ALLOCABLE_MEMORY default +1c364400 prevent 32b overflow for very large canvas_width / height +eee0cce1 Merge "Small LZ77 speedups." +5f1caf29 Small LZ77 speedups. +1effde7b fix anim_util.c compilation when HAVE_GIF is not defined. +a2fe9bf4 Speedup TrellisQuantizeBlock(). +573cce27 smartYUV improvements +21e7537a fix infinite loop in case of PARTITION0 overflow +053a1565 Merge "Change the rule of picking UV mode in MBAnalyzeBestUVMode()" +1377ac2e Change the rule of picking UV mode in MBAnalyzeBestUVMode() +7c1fb7d0 fix uint32_t initialization (0. -> 0) +bfff0bf3 speed-up SSIM calculation +64577de8 De-VP8L-ize GetEntropUnrefinedHelper. +a7be7328 Merge "refactor the PSNR / SSIM calculation code" +50c3d7da refactor the PSNR / SSIM calculation code +d6228aed indentation fix after I7055d3ee3bd7ed5e78e94ae82cb858fa7db3ddc0 +dd538b19 Remove unused declaration. +6cc48b17 Move some lossless logic out of dsp. +78363e9e Merge "Remove a redundant call to InitLeft() in VP8IteratorReset()" +ffd01929 Refactor VP8IteratorNext(). +c4f6d9c9 Remove a redundant call to InitLeft() in VP8IteratorReset() +c27d8210 Merge "smartYUV: simplify main loop" +07795296 smartYUV: simplify main loop +c9b45863 Split off common lossless dsp inline functions. +490ae5b1 smartYUV: improve initial state for faster convergence +894232be smartYUV: fix and simplify the over-zealous stop criterion +8de08483 Remove unused code in webpi.h +41cab7fe imageio/Android.mk: correct imagedec dependencies +82c91c70 Merge "libimageenc.a: extract image-saving code from dwebp" +af1ad3e2 libimageenc.a: extract image-saving code from dwebp +dd7309e3 Merge "doc: use two's complement explicitly for uint8->int8 conversion" +6105777e Merge "add gif2webp to CMake" +13ae011e doc: use two's complement explicitly for uint8->int8 conversion +4bda0cfb add gif2webp to CMake +6029c7fe Merge "remove mention of fragment, frgm, FRGM, etc." +545c147f remove mention of fragment, frgm, FRGM, etc. +5b46f7fc cwebp.1: improve some grammar +9e478f80 dec/vp8l.c: add assertions in EmitRescaledRowsRGBA/YUVA +43bd8958 Make gif transparent color to be transparent black +0887fc2d Merge "get_disto: add a '-o file' option to save a diff map" +0de48e18 get_disto: add a '-o file' option to save a diff map +0a57ad0d cosmetics: WebPSafeAlloc -> WebPSafeMalloc +0a4699bc Merge "WebPPictureDistortion(): free() -> WebPSafeFree()" +29fedbf5 Anim_encoder: correctly handle enc->prev_candidate_undecided_ +32dead4e WebPPictureDistortion(): free() -> WebPSafeFree() +85cd5d06 Smarter LZ77 for uniform regions. +6585075f Change PixelsAreSimilar() to handle black pixels correctly. +c0a27fd2 vwebp: Clear previous frame when a key triggers a redraw +57a5e3b6 webp_quality should return '0' in case of success. +7f1b897b Faster stochastic histogram merging. +48c810b8 Merge "remove WEBP_FORCE_ALIGNED and use memcpy() instead." +3884972e remove WEBP_FORCE_ALIGNED and use memcpy() instead. +485cac1a switch libimagedec.a and libimageio_util.a to avoid undefined symbol +005e15b1 Merge "{extras,mux}/Makefile.am: add missing -lm" +6ab496ed fix some 'unsigned integer overflow' warnings in ubsan +8a4ebc6a Revert "fix 'unsigned integer overflow' warnings in ubsan" +9d4f209f Merge changes I25711dd5,I43188fab +e44f5248 fix 'unsigned integer overflow' warnings in ubsan +27b5d991 Fix assertions in WebPRescalerExportRow() +74f6f9e7 Add descriptions of default configuration in help info. +aaf2530c {extras,mux}/Makefile.am: add missing -lm +1269dc7c Refactor VP8LColorCacheContains() +40872fb2 dec_neon,NeedsHev: micro optimization +7b54e26b Add a CMake option for WEBP_SWAP_16BIT_CSP. +d2223d8d Fix missing cpu-features for Android. +bf16a4b4 Merge "cpu.cmake: improve webp_check_compiler_flag output" +ee1057e3 cpu.cmake: improve webp_check_compiler_flag output +b551e587 cosmetics: add {}s on continued control statements +d2e4484e dsp/Makefile.am: put msa source in correct lib +c7f66c82 Merge "utils/thread.c,cosmetics: join a few lines" +98d8f295 Merge "examples/Makefile.am,cosmetics: sort binary targets" +39f4ffbc utils/thread.c,cosmetics: join a few lines +a86ce2b1 Merge "extras/Makefile.am: don't install libwebpextras" +6fa9fe24 extras/Makefile.am: don't install libwebpextras +0b2c58a9 Fix an unsigned integer overflow error in enc/cost.h +d7ce4a2e examples/Makefile.am,cosmetics: sort binary targets +386e4ba2 Reset segment id if we decide not to update segment map +7b87e848 Merge "Add MSA optimized YUV to RGB upsampling functions" +d3ddacb6 Add MSA optimized YUV to RGB upsampling functions +eb98d8d8 webp_quality: detect lossless format and features +ebee57f4 move imageio/example_util.[hc] (back to) examples/ +99542bbf webpdec: s/ExUtil// +da573cf4 imageio_util: s/ExUtil/ImgIoUtil/ +bdda5bd4 split example_util.h +15ed462b .gitignore: add extras/{get_disto,webp_quality} +7be57489 Merge "VP8EstimateQuality(): roughty estimate webp bitstream quality factor" +57020525 Makefile.vc: add missing imageio target +e8ab6a82 VP8EstimateQuality(): roughty estimate webp bitstream quality factor +fee7b3d6 Merge "'extras/get_disto' example: compute PSNR between two files" +1e7d4401 'extras/get_disto' example: compute PSNR between two files +4cecab63 pngdec.c,jpegdec.[hc]: remove unnecessary includes +259f0434 makefile.unix: normalize image decode lib name +ed34c39b fix: examples/libexample_dec.a => imageio/libexample_dec.a +33d8d0d4 Merge "move examples/{example_util,image_dec} to imageio/" +c960b82e Merge "extras.h: correct include guard" +fe3cd28a Merge ".gitignore: add .gradle, /build" +45fbeba5 Merge "Do token recording and counting in a single loop" +4f33c820 .gitignore: add .gradle, /build +c379b55a move examples/{example_util,image_dec} to imageio/ +5108d9aa extras.h: correct include guard +ad497fbc move src/extras to the top-level +0c0fb832 Do token recording and counting in a single loop +9ac74f92 Add MSA optimized rescaling functions +cb19dbc1 Add MSA optimized color transform functions +3f4042b5 WebPAnimEncoder: If 'minimize_size' and 'allow_mixed' on, try lossy + lossless. +5e2eb89e cosmetics,dsp/*msa.c: associate '*' with the type +5b60db5c FastMBAnalyze() for quick i16/i4 decision +567e6977 Add MSA optimized CollectHistogram function +c54ab8dd Add MSA optimized quantization functions +ec6f68c5 Merge "Remove QuantizeBlockWHT() in enc.c" +2a5c417c Apply the RLE heuristic to LZ77. +91b59e88 Remove QuantizeBlockWHT() in enc.c +fe572737 Add MSA optimized SSE functions +6b53ca87 cosmetics,(dec|enc)_sse2.c: fix indent +b15d00d9 Merge "Add MSA optimized encoder IntraChromaPreds function" +afe3cec8 Add MSA optimized encoder IntraChromaPreds function +fc8cad9f reduce the number of malloc/free cycles in huffman.c +7b4b05e0 Add MSA optimized encoder Intra16Preds function +c18787a0 Add MSA optimized encoder Intra4Preds function +479d1908 webpmux: Also print compression info per frame. +a80e8cfd Provide support for CMake on Android studio 2.2. +6c628410 Split the main CMake file. +bbb6ecd9 Merge "Add MSA optimized distortion functions" +7915396f Add MSA optimized distortion functions +652e944f Merge "build.gradle: remove tab" +c0991a14 io,EmitRescaledAlphaYUV: factor out a common expr +48bf5ed1 build.gradle: remove tab +bfef6c9f Merge tag 'v0.5.1' +3d97bb75 update ChangeLog (tag: v0.5.1, origin/0.5.1, 0.5.1) +deb54d91 Clarify the expected 'config' lifespan in WebPIDecode() +435308e0 Add MSA optimized encoder transform functions +dce64bfa Add MSA optimized alpha filter functions +429120d0 Add MSA optimized color transform functions +c7e2d245 update ChangeLog (tag: v0.5.1-rc5) +55b2fede normalize the macros' "do {...} while (0)" constructs +701c772e Add MSA optimized colorspace conversion functions +c7eb06f7 Fix corner case in CostManagerInit. +f918cb10 fix rescaling bug: alpha plane wasn't filled with 0xff +ab7937a5 gif2webp: normalize the number of .'s in the help message +3cdec847 vwebp: normalize the number of .'s in the help message +bdf6241e cwebp: normalize the number of .'s in the help message +06a38c7b fix rescaling bug: alpha plane wasn't filled with 0xff +319e37be Improve lossless compression. +6a197937 Add MSA optimized intra pred chroma functions +447adbce 'our bug tracker' -> 'the bug tracker' +97b9e644 normalize the number of .'s in the help message +293d786f Added MSA optimized intra prediction 16x16 functions +0afa0ce2 Added MSA optimized intra prediction 4x4 functions +a6621bac Added MSA optimized simple edge filtering functions +bb50bf42 pngdec,ReadFunc: throw an error on invalid read +38063af1 decode.h,WebPGetInfo: normalize function comment +1ebf193c Added MSA optimized chroma edge filtering functions +9ad2352d Merge "Added MSA optimized edge filtering functions" +60751096 Added MSA optimized edge filtering functions +9e8e1b7b Inline GetResidual for speed. +7d58d1b7 Speed-up uniform-region processing. +8ec7032b simplify HistogramCombineEntropyBin() +23e29cb1 Merge "Fix a boundary case in BackwardReferencesHashChainDistanceOnly." into 0.5.1 +472a049b remove bin_map[] allocation altogether +0bb23b2c free -> WebPSafeFree() +a977b4b5 Merge "rewrite the bin_map clustering to use less memory" +3591ba66 rewrite the bin_map clustering to use less memory +e6ac450c utils.[hc]: s/MAX_COLOR_COUNT/MAX_PALETTE_SIZE/ +e7b91772 Merge "DecodeImageData(): change the incorrect assert" into 0.5.1 +2abfa54f DecodeImageData(): change the incorrect assert +5a48fcd8 Merge "configure: test for -Wfloat-conversion" +0174d18d Fix a boundary case in BackwardReferencesHashChainDistanceOnly. +6a9c262a Merge "Added MSA optimized transform functions" +cfbcc5ec Make sure to consider small distances in LZ77. +5e60c42a Added MSA optimized transform functions +3dc28d76 configure: test for -Wfloat-conversion +f2a0946a add some asserts to delimit the perimeter of CostManager's operation +9a583c66 fix invalid-write bug for alpha-decoding +f66512db make gradlew executable +6fda58f1 backward_references: quiet double->int warning +a48cc9d2 Merge "Fix a compression regression for images with long uniform regions." into 0.5.1 +cc2720c1 Merge "Revert an LZ77 boundary constant." into 0.5.1 +059aab4f Fix a compression regression for images with long uniform regions. +b0c7e49e Check more backward matches with higher quality. +a3611513 Revert an LZ77 boundary constant. +8190374c README: fix typo +7551db44 update NEWS +0fb2269c bump version to 0.5.1 +f4537610 update AUTHORS & .mailmap +3259571e Refactor GetColorPalette method. +1df5e260 avoid using tmp histogram in PreparePair() +7685123a fix comment typos +a246b921 Speedup backward references. +76d73f18 Merge "CostManager: introduce a free-list of ~10 intervals" +eab39d81 CostManager: introduce a free-list of ~10 intervals +4c59aac0 Merge "mips msa webp configuration" +043c33f1 Merge "Improve speed and compression in backward reference for lossless." +71be9b8c Merge "clarify variable names in HistogramRemap()" +0ba7fd70 Improve speed and compression in backward reference for lossless. +0481d42a CostManager: cache one interval and re-use it when possible +41b7e6b5 Merge "histogram: fix bin calculation" +96c3d624 histogram: fix bin calculation +fe9e31ef clarify variable names in HistogramRemap() +ce3c8247 disable near-lossless quantization if palette is used +e11da081 mips msa webp configuration +5f8f998d mux: Presence of unknown chunks should trigger VP8X chunk output. +cadec0b1 Merge "Sync mips32 and dsp_r2 YUV->RGB code with C verison" +d9637758 Compute the hash chain once and for all for lossless compression. +50a48665 Sync mips32 and dsp_r2 YUV->RGB code with C verison +eee788e2 Merge "introduce a common signature for all image reader function" +d77b877c introduce a common signature for all image reader function +ca8d9519 remove some obsolete TODOs +ae2a7222 collect all decoding utilities from examples/ in libexampledec.a +0b8ae852 Merge "Move DitherCombine8x8 to dsp/dec.c" +77cad885 Merge "ReadWebP: avoid conversion to ARGB if final format is YUVA" +ab8d6698 ReadWebP: avoid conversion to ARGB if final format is YUVA +f8b7ce9e Merge "test pointer to NULL explicitly" +5df6f214 test pointer to NULL explicitly +77f21c9c Move DitherCombine8x8 to dsp/dec.c +c9e6d865 Add gradle support +c65f41e8 Revert "Add gradle support" +bf731ede Add gradle support +08333b85 WebPAnimEncoder: Detect when canvas is modified, restore only when needed. +0209d7e6 Merge "speed-up MapToPalette() with binary search" +fdd29a3d speed-up MapToPalette() with binary search +cf4a651b Revert "Refactor GetColorPalette method." +0a27aca3 Merge changes Idfa8ce83,I19adc9c4 +f25c4406 WebPAnimEncoder: Restore original canvas between multiple encodes. +169004b1 Refactor GetColorPalette method. +576362ab VP8LDoFillBitWindow: support big-endian in fast path +ac49e4e4 bit_reader.c: s/VP8L_USE_UNALIGNED_LOAD/VP8L_USE_FAST_LOAD/ +d39ceb58 VP8LDoFillBitWindow: remove stale TODO +2ec2de14 Merge "Speed-up BackwardReferencesHashChainDistanceOnly." +3e023c17 Speed-up BackwardReferencesHashChainDistanceOnly. +f2e1efbe Improve near lossless compression when a prediction filter is used. +e15afbce dsp.h: fix ubsan macro name +e53c9ccb dsp.h: add WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW +af81fdb7 utils.h: quiet -fsanitize=undefined warnings +ea0be354 dsp.h: remove utils.h include +cd276aec utils/*.c: ../utils/utils.h -> ./utils.h +c8927131 utils/Makefile.am: add some missing headers +ea24e026 Merge "dsp.h: add WEBP_UBSAN_IGNORE_UNDEF" +369e264e dsp.h: add WEBP_UBSAN_IGNORE_UNDEF +0d020a78 Merge "add runtime NEON detection" +5ee2136a Merge "add VP8LAddPixels() to lossless.h" +47435a61 add VP8LAddPixels() to lossless.h +8fa6ac68 remove two ubsan warnings +74fb56fb add runtime NEON detection +4154a839 MIPS update to new Unfilter API +c80b9fc8 Merge "cherry-pick decoder fix for 64-bit android devices" +6235147e cherry-pick decoder fix for 64-bit android devices +d41b8c43 configure: test for -Wformat-* w/-Wformat present +5f95589f Fix WEBP_ALIGN in case the argument is a pointer to a type larger than a byte. +2309fd5c replace num_parts_ by num_parts_minus_one_ (unsigned) +9629f4bc SimplifySegments: quiet -Warray-bounds warning +de47492e Merge "update the Unfilter API in dsp to process one row independently" +2102ccd0 update the Unfilter API in dsp to process one row independently +e3912d56 WebPAnimEncoder: Restore canvas before evaluating blending possibility. +6e12e1e3 WebPAnimEncoder: Fix for single-frame optimization. +602f344a Merge changes I1d03acac,Ifcb64219 +95ecccf6 only apply color-mapping for alpha on the cropped area +47dd0708 anim_diff: Add an experimental option for max inter-frame diff. +aa809cfe only allocate alpha_plane_ up to crop_bottom row +31f2b8d8 WebPAnimEncoder: FlattenSimilarPixels(): look for similar +774dfbdc perform alpha filtering within the decoding loop +a4cae68d lossless decoding: only process decoded row up to last_row +238cdcdb Only call WebPDequantizeLevels() on cropped area +cf6c713a alpha: preparatory cleanup +b95ac0a2 Merge "VP8GetHeaders(): initialize VP8Io with sane value for crop/scale dimensions" +89231394 VP8GetHeaders(): initialize VP8Io with sane value for crop/scale dimensions +5828e199 use_8b_decode -> use_8b_decode_ +8dca0247 fix bug in alpha.c that was triggering a memory error in incremental mode +9a950c53 WebPAnimEncoder: Disable filtering when blending is used with lossy encoding. +eb423903 WebPAnimEncoder: choose max diff for framerect based on quality. +ff0a94be WebPAnimEncoder lossy: ignore small pixel differences for frame rectangles. +f8040084 gif2webp: Remove the 'prev_to_prev_canvas' buffer. +6d8c07d3 Merge "WebPDequantizeLevels(): use stride in CountLevels()" +d96fe5e0 WebPDequantizeLevels(): use stride in CountLevels() +ec1b2407 WebPPictureImport*: check output pointer +c0768769 Merge "Revert "Re-enable encoding of alpha plane with color cache for next release."" +41f14bcb WebPPictureImport*: check src pointer +64eed387 Pass stride parameter to WebPDequantizeLevels() +97934e24 Revert "Re-enable encoding of alpha plane with color cache for next release." +e88c4ca0 fix -m 2 mode-cost evaluation (causing partition0 overflow) +4562e83d Merge "add extra meaning to WebPDecBuffer::is_external_memory" +abdb109f add extra meaning to WebPDecBuffer::is_external_memory +875aec70 enc_neon,cosmetics: break long comment +71e856cf GetMBSSIM,cosmetics: fix alignment +a90edffb fix missing 'extern' for SSIM function in dsp/ +423ecaf4 move some SSIM-accumulation function for dsp/ +f08e6624 Merge "Fix FindClosestDiscretized in near lossless:" +0d40cc5e enc_neon,Disto4x4: remove an unnecessary transpose +e8feb20e Fix FindClosestDiscretized in near lossless: +82006430 anim_util: quiet static analysis warning +a6f23c49 Merge "AnimEncoder: Support progress hook and user data." +a5193774 Merge "Near lossless feature: fix some comments." +da98d31c AnimEncoder: Support progress hook and user data. +33357131 Near lossless feature: fix some comments. +0beed01a cosmetics: fix indent after 2f5e898 +6753f35c Merge "FTransformWHT optimization." +6583bb1a Improve SSE4.1 implementation of TTransform. +7561d0c3 FTransformWHT optimization. +7ccdb734 fix indentation after patch #328220 +6ec0d2a9 clarify the logic of the error path when decoding fails. +8aa352b2 Merge "Remove an unnecessary transposition in TTransform." +db860884 Merge "remove useless #include" +9960c316 Remove an unnecessary transposition in TTransform. +6e36b511 Small speedup in FTransform. +9dbd4aad Merge "fix C and SIMD flags completion." +e60853ea Add missing common_sse2.h file to makefile.unix +696eb2b0 fix C and SIMD flags completion. +2b4fe33e Merge "fix multiple allocation for transform buffer" +2f5e8986 fix multiple allocation for transform buffer +bf2b4f11 Regroup common SSE code + optimization. +4ed650a1 force "-pass 6" if -psnr or -size is used but -pass isn't. +3ef1ce98 yuv_sse2: fix -Wconstant-conversion warning +a7a03e9f Merge changes I4852d18f,I51ccb85d +5e122bd6 gif2webp: set enc_options.verbose = 0 w/-quiet +ab3c2583 anim_encode,DefaultEncoderOptions: init verbose +8f0dee77 Merge "configure: fix builtin detection w/-Werror" +4a7b85a9 cmake: fix builtin detection w/-Werror +b74657fb configure: fix builtin detection w/-Werror +3661b980 Add a CMakeLists.txt +75f4af4d remove useless #include +6c1d7631 avoid Yoda style for comparison +8ce975ac SSE optimization for vector mismatch. +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) +7e7b6ccc faster rgb565/rgb4444/argb output +4c7f565f update NEWS +1f62b6b2 update AUTHORS +e224fdc8 update mailmap +71100500 bump version to 0.5.0 +230a685e README: update help text, repo link +d48e427b Merge "demux: accept raw bitstreams" +99a01f4f Merge "Unify some entropy functions." +4b025f10 Merge "configure: disable asserts by default" +92cbddf8 Merge "fix PrintBlockInfo()" +ca509a33 Unify some entropy functions. +367bf903 fix PrintBlockInfo() +b0547ff0 move back common constants for lossless_enc*.c into the .h +fb4c7832 lossless: simpler alpha cleanup preprocessing +ba7f4b68 Merge "anim_diff: add brief description of options" +47ddd5a4 Move some codec logic out of ./dsp . +b4106c44 anim_diff: add brief description of options +357f455d yuv_sse2: fix 32-bit visual studio build +b9d80fa4 configure: disable asserts by default +7badd3da cosmetic fix: sizeof(type) -> sizeof(*var) +80ce27d3 Speed up 24-bit packing / unpacking in YUV / RGB conversions. +68eebcb0 remove a TODO about rotation +2dee2966 remove few obsolete TODO about aligned loads in SSE2 +e0c0bb34 remove TODO about unused ref_lf_delta[] +9cf1cc2b remove few TODO: * 256 -> RD_DISTO_MULT * don't use TDisto for UV mode picking +79189645 Merge changes from topic 'demux-fragment-cleanup' +47399f92 demux: remove GetFragment() +d3cfb79a demux: remove dead fragment related TODO +ab714b8a demux, Frame: remove is_fragment_ field +b105921c yuv_sse2, cosmetics: fix indent +466c92e8 demux,WebPIterator: remove fragment_num/num_fragments +11714ff1 demux: remove WebPDemuxSelectFragment +c0f7cc47 fix for bug #280: UMR in next->bits +578beeb8 Merge "enc/Makefile.am: add missing headers" +1a819f00 makefile.unix: make visibility=hidden the default +d4f9c2ef enc/Makefile.am: add missing headers +846caff4 configure: check for -fvisibility=hidden +3f3ea2c5 demux: accept raw bitstreams +d6dad5d0 man cwebp: add precision about exactness of the 'lossless' mode +46bb1e34 Merge "gifdec: remove utils.h include" +2b882e94 Merge "Makefile.vc: define WEBP_HAVE_GIF for gifdec.c" +892b9238 Merge "man/*, AUTHORS: clarify origin of the tool" +e5687a18 Merge "fix optimized build with -mcmodel=medium" +e56e6859 Makefile.vc: define WEBP_HAVE_GIF for gifdec.c +4077d944 gifdec: remove utils.h include +b5e30dac man/*, AUTHORS: clarify origin of the tool +b275e598 fix optimized build with -mcmodel=medium +64da45a9 cosmetics, cwebp: fix indent +038a060d Merge "add disto-based refinement for UV mode (if method = 1 or 2)" +2835089d Provide an SSE2 implementation of CombinedShannonEntropy. +e6c93519 add disto-based refinement for UV mode (if method = 1 or 2) +04507dc9 Merge "fix undefined behaviour during shift, using a cast" +793c5261 Merge "wicdec: add support for reading from stdin" +d3d16397 Optimize the heap usage in HistogramCombineGreedy. +202a710b fix undefined behaviour during shift, using a cast +14d27a46 improve method #2 by merging DistoRefine() and SimpleQuantize() +cb1ce996 Merge "10% faster table-less SSE2/NEON version of YUV->RGB conversion" +ac761a37 10% faster table-less SSE2/NEON version of YUV->RGB conversion +79fcf29a wicdec: add support for reading from stdin +015f173f Merge "cwebp: add support for stdin input" +a9947c32 cwebp: add support for stdin input +7eb01ff3 Merge "Improved alpha cleanup for the webp encoder when prediction transform is used." +fb8c9106 Merge "introduce WebPMemToUint32 and WebPUint32ToMem for memory access" +bd91af20 Merge "bit_reader: remove aarch64 BITS TODO" +6c702b81 Speed up hash chain initialization using memset. +4c60f63c make ReadPNG and ReadJPEG take a filename instead of a FILE +464ed10f bit_reader: remove aarch64 BITS TODO +d478e589 Merge "configure: update issue tracker" +69381113 Improved alpha cleanup for the webp encoder when prediction transform is used. +2c08aac8 introduce WebPMemToUint32 and WebPUint32ToMem for memory access +010ca3d1 Fix FindMatchLength with non-aligned buffers. +a90e1e3f README: add prerequisites for an autoconf build +458f0866 configure: update issue tracker +33914595 vwebp: work around the transparent background with GLUT bug +e4a7eed4 cosmetics: fix indent +08375129 Merge "Make a separate case for low_effort in CopyImageWithPrediction" +aa2eb2d4 Merge "cosmetics: fix indent" +b7551e90 cosmetics: fix indent +5bda52d4 Make a separate case for low_effort in CopyImageWithPrediction +66fa598a Merge "configure: fix intrinsics build w/older gcc" +5ae220be backward_references.c: Fixed compiler warning +1556da09 Merge "configure: restore 2 warnings" +71a17e58 configure: restore 2 warnings +9eeabc07 configure: fix intrinsics build w/older gcc +363babe2 Merge "fix some warning about unaligned 32b reads" +a1411782 Optimization in hash chain comparison for 64 bit Arrays were compared 32 bits at a time, it is now done 64 bits at a time. Overall encoding speed-up is only of 0.2% on @skal's small PNG corpus. It is of 3% on my initial 1.3 Mp desktop screenshot image. +829bd141 Combine Huffman cost and bit entropy into one loop +a7a954c8 Merge "lossless: make prediction in encoder work per scanline" +61b605b4 Merge "fix of undefined multiply (int32 overflow)" +239421c5 lossless: make prediction in encoder work per scanline +f5ca40e0 fix of undefined multiply (int32 overflow) +5cd2ef4c Merge changes from topic 'win-threading-compat' +76ce9187 Makefile.vc: enable WEBP_USE_THREAD for windows phone +d2afe974 thread: use CreateThread for windows phone +0fd0e12b thread: use WaitForSingleObjectEx if available +63fadc9f thread: use InitializeCriticalSectionEx if available +110ad583 thread: use native windows cond var if available +912c9fdf dec/webp: use GetLE(24|32) from utils +f1694481 utils/GetLE32: correct uint32 promotion +158763de Merge "always call WebPInitSamplers(), don't try to be smart" +3770f3bb Merge "cleanup the YFIX/TFIX difference by removing some code and #define" +a40f60a9 Merge "3% speed improvement for lossless webp encoder for low effort mode:" +ed1c2bc6 always call WebPInitSamplers(), don't try to be smart +b8c44f1a 3% speed improvement for lossless webp encoder for low effort mode: +997e1038 cleanup the YFIX/TFIX difference by removing some code and #define +d73d1c8b Merge "Make discarding invisible RGB values (cleanup alpha) the default." +1f9be97c Make discarding invisible RGB values (cleanup alpha) the default. +f240117b Make dwebp listen more to the -quiet flag +b37b0179 fix for issue #275: don't compare to out-of-bound pointers +21735e06 speed-up trivial one-symbol decoding case for lossless +397863bd Refactor CopyPlane() and CopyPixels() methods: put them in utils. +6ecd72f8 Re-enable encoding of alpha plane with color cache for next release. +1f7148a4 Merge "remove unused fields from WebPDecoderOptions and WebPBitstreamFeatures" +6ae395fa Merge "use ExReadFile() for ReadYUV()" +8076a00e gitignore list: add anim_diff. +1c1702d8 use ExReadFile() for ReadYUV() +775d3a37 remove unused fields from WebPDecoderOptions and WebPBitstreamFeatures +c13245c7 AnimEncoder: Add a GetError() method. +688b265d AnimDecoder API: Add a GetDemuxer() method. +1aa4e3d6 WebPAnimDecoder: add an option to enable multi-threaded decoding. +3584abca AnimDecoder: option to decode to common color modes. +afd5a62c Merge "mux.h does NOT need to include encode.h" +8550d443 Merge "migrate anim_diff tool from C++ to C89" +96201e50 migrate anim_diff tool from C++ to C89 +945cfa3b mux.h does NOT need to include encode.h +8da07e8d Merge "~2x faster SSE2 RGB24toY, BGR24toY, ARGBToY|UV" +bfd3fc02 ~2x faster SSE2 RGB24toY, BGR24toY, ARGBToY|UV +02432427 man/cwebp.1, cosmetics: escape '-'s +96f5b423 man/cwebp: group lossy-only options +52fdbdfe extract some RGB24 to Luma conversion function from enc/ to dsp/ +ab8c2300 add missing \n +8304179a sync NEWS with 0.4.4 +5bd04a08 sync versions with 0.4.4 +8f1fcc15 Merge "Move ARGB->YUV functions from dec/vp8l.c to dsp/yuv.c" +25bf2ce5 fix some warning about unaligned 32b reads +922268fd s/TIFF/WebP +fa8927ef Move ARGB->YUV functions from dec/vp8l.c to dsp/yuv.c +9b373598 Merge "for ReadXXXX() image-readers, use the value of pic->use_argb" +f7c507a5 Merge "remove unnecessary #include "yuv.h"" +7861578b for ReadXXXX() image-readers, use the value of pic->use_argb +14e4043b remove unnecessary #include "yuv.h" +469ba2cd vwebp: fix incorrect clipping w/NO_BLEND +4b9186b2 update issue tracker url +d64d376c change WEBP_ALIGN_CST value to 31 +f717b828 vp8l.c, cosmetics: fix indent after 95509f9 +927ccdc4 Merge "fix alignment of allocated memory in AllocateTransformBuffer" +fea94b2b fix alignment of allocated memory in AllocateTransformBuffer +5aa8d61f Merge "MIPS: rescaler code synced with C implementation" +e7fb267d MIPS: rescaler code synced with C implementation +93c86ed5 Merge "format_constants.h: MKFOURCC, correct cast" +5d791d26 format_constants.h: MKFOURCC, correct cast +65726cd3 dsp/lossless: Average2, make a constant unsigned +d26d9def Use __has_builtin to check clang support +12ec204e moved ALIGN_CST into util/utils.h and renamed WEBP_ALIGN_xxx +a2640838 Merge "rescaler: ~20% faster SSE2 implementation for lossless ImportRowExpand" +3fb600d5 Merge "wicdec: fix alpha detection w/64bpp BGRA/RGBA" +67c547fd rescaler: ~20% faster SSE2 implementation for lossless ImportRowExpand +99e3f812 Merge "large re-organization of the delta-palettization code" +95509f99 large re-organization of the delta-palettization code +74fb458b fix for weird msvc warning message +ae49ad86 Merge "SSE2 implementation of ImportRowShrink" +932fd4df SSE2 implementation of ImportRowShrink +badfcbaa wicdec: fix alpha detection w/64bpp BGRA/RGBA +35cafa6c Merge "iosbuild: fix linking with Xcode 7 / iOS SDK 9" +b0c9d8af label rename: NO_CHANGE -> NoChange +b4e731cd neon-implementation for rescaler code +db1321a6 iosbuild: fix linking with Xcode 7 / iOS SDK 9 +6dfa5e3e rescaler: better handling of the fxy_scale=0 special case. +55c05293 Revert "rescaler: better handling of the fxy_scale=0 special case." +9f226bf8 rescaler: better handling of the fxy_scale=0 special case. +f7b8f907 delta_palettization.*: add copyright +c1e1b710 Changed delta palette to compress better +0dd28267 Merge "Add delta_palettization feature to WebP" +48f66b66 Add delta_palettization feature to WebP +27933e2a anim_encoder: drop a frame if it has same pixels as the prev frame. +df9f6ec8 Merge "webpmux/DisplayInfo: send non-error output to stdout" +8af4993b Merge "rescaler_mips_dsp_r2: cosmetics, fix indent" +2b9d2495 Merge "rescaler: cosmetics, join two lines" +cc020a8c webpmux/DisplayInfo: send non-error output to stdout +a288e746 configure: add -Wshorten-64-to-32 +c4c3cf2d pngdec: fix type conversion warnings +bef8e97d webpmux: fix type conversion warning +5a84460d rescaler_mips_dsp_r2: cosmetics, fix indent +acde0aae rescaler: cosmetics, join two lines +306ce4fd rescaler: move the 1x1 or 2x1 handling one level up +cced974b remove _mm_set_epi64x(), which is too specific +56668c9f fix warnings about uint64_t -> uint32_t conversion +76a7dc39 rescaler: add some SSE2 code +1df1d0ee rescaler: harmonize function protos +9ba1894b rescaler: simplify ImportRow logic +5ff0079e fix rescaler vertical interpolation +cd82440e VP8LAllocateHistogramSet: align histogram[] entries +a406b1dd Merge "fix memory over-allocation in lossless rescaler init" +0fde33e3 add missing const in VP8InitFrame signature +ac7d5e8d fix memory over-allocation in lossless rescaler init +017f8ccc Loosen the buffer size checks for Y/U/V/A too. +15ca5014 loosen the padding check on buffer size +d623a870 dec_neon: add whitespace around stringizing operator +29377d55 dsp/mips: cosmetics: add whitespace around XSTR macro +eebaf97f dsp/mips: add whitespace around stringizing operator +d39dc8f3 Create a WebPAnimDecoder API. +03fb7522 gif2webp: print output file size +14efabbf Android: limit use of cpufeatures +7b83adbe preparatory cosmetics for Rescaler code fix and clean-up +77fb41c2 dec/vp8l/DecodeAlphaData: remove redundant cast +90fcfcd9 Insert less hash chain entries from the beginnings of long copies. +bd55604d SSE2: add yuv444 converters, re-using yuv_sse2.c +41a5d99d add a -quiet option to 'dwebp' +80ab3edb Merge "README: update dwebp help output after 1e595fe" +32b71b2e README: update dwebp help output after 1e595fe +3ec11827 use the DispatchAlpha() call from dsp +c5f00621 incorporate bzero() into WebPRescalerInit() instead of call site +3ebcdd41 remove duplicate "#include <stdlib.h>" +1e595fe1 dwebp: add -resize as a synonym for -scale +24a96932 dec: allow 0 as a scaling dimension +b9187242 utils/rescaler: add WebPRescalerGetScaledDimensions +923e8eda Merge "update NEWS" +020fd099 Merge "WebPPictureDistortion: support ARGB format for 'pic' when computing distortion." +6a5292f6 update NEWS +56a2e9f5 WebPPictureDistortion: support ARGB format for 'pic' when computing distortion. +0ae582e4 configure: test and add -Wunreachable-code +c2f9dc06 bit_writer: convert VP8L macro values to immediates +b969f888 Reduce magic in palette reordering +acb297e9 anim_diff: add a -raw_comparison flag +155c1b22 Merge changes I76f4d6fe,I45434639 +717e4d5a mips32/mipsDSPr2: function ImportRow rebased +7df93893 fix rescaling bug (uninitialized read, see bug #254). +5cdcd561 lossless_enc_neon: add VP8LTransformColor +a53c3369 lossless_neon: add VP8LTransformColorInverse +99131e7f Merge changes I9fb25a89,Ibc648e9e +c4556766 simplify the main loop for downscaling +2a010f99 lossless_neon: remove predictors 5-13 +ca221bbc ll_enc_neon: enable VP8LSubtractGreenFromBlueAndRed +585d93db Container spec: clarify ordering of ALPH chunk. +01d61fd9 lossless: ~20 % speedup +f722c8f0 lossless: Speed up ComputeCacheEntropy by 40 % +1ceecdc8 add a VP8LColorCacheSet() method for color cache +17eb6099 lossless: Allow copying from prev row in rle-mode. +f3a7a5bf lossless: bit writer optimization +d97b9ff7 Merge changes from topic 'lossless-enc-improvements' +0250dfcc msvc: fix pointer type warning in BitsLog2Floor +52931fd5 lossless: combine the Huffman code with extra bits +c4855ca2 lossless: Inlining add literal +8e9c94de lossless: simplify HashChainFindCopy heuristics +888429f4 lossless: 0.5 % compression density improvement +7b23b198 lossless: Add zeroes into the predicted histograms. +85b44d8a lossless: encoding, don't compute unnecessary histo +d92453f3 lossless: Remove about 25 % of the speed degradation +2cce0317 Faster alpha coding for webp +5e75642e lossless: rle mode not to accept lengths smaller than 4. +84326e4a lossless: Less code for the entropy selection +16ab951a lossless: 0.37 % compression density improvement +822f113e add WebPFree() to the API +0ae2c2e4 SSE2/SSE41: optimize SSE_16xN loops +39216e59 cosmetics: fix indent after 32462a07 +559e54ca Merge "SSE2: slightly faster FTransformWHT" +8ef9a63b SSE2: slightly faster FTransformWHT +f27f7735 lossless_neon: enable VP8LAddGreenToBlueAndRed +36e9c4bc SSE2: minor cosmetrics on in-loop filter code +4741fac4 dsp/lossless_*sse2: remove some unnecessary inlines +1819965e fix warning ("left shift of negative value") using a cast +70170014 SSE2: speed-up some lossless-encoding functions +abcb0128 Merge "SSE2: slightly faster (~5%) AddGreenToBlueAndRed()" +2df5bd30 Merge "Speedup to HuffmanCostCombinedCount" +9e356d6b SSE2: slightly faster (~5%) AddGreenToBlueAndRed() +fc6c75a2 SSE2: 53% faster TransformColor[Inverse] +49073da6 SSE2: 46% speed-up of TransformColor[Inverse] +32462a07 Speedup to HuffmanCostCombinedCount +f3d687e3 SSE4.1 implementation of some lossless encoding functions +bfc300c7 SSE4.1 implementation of some alpha-processing functions +7f9c98f2 Merge "sse2 in-loop: simplify SignedShift8b() a bit" +ef314a5d dec_sse2/GetNotHEV: micro optimization +a729cff9 sse2 in-loop: simplify SignedShift8b() a bit +422ec9fb simplify Load8x4() a bit +8df238ec Merge "remove some duplicate FlipSign()" +751506c4 remove some duplicate FlipSign() +65ef5afc Merge "lossless: 0.13% compression density gain" +2beef2f2 lossless: 0.13% compression density gain +3033f24c lossless: 0.06 % compression density improvement +64960da9 dec_neon: add VE8uv / VE16 +14dbd87b dec_neon: add HE8uv / HE16 +ac768011 introduce FTransform2 to perform two transforms at a time. +aa6065ae dec_neon: use vld1_dup(mem) rather than vdup(mem[0]) +8b63ac78 Merge "dec_neon: add TM16" +f51be09e Merge "dec_neon/TrueMotion: simply left border load" +dc48196b dec_neon: add TM16 +ea95b305 dec_neon/TrueMotion: simply left border load +f262d612 speed-up SetResidualSSE2 +bf46d0ac fix mips2 build target +929a0fdc enc_sse2/TTransform: simplify abs calculation +17dbd058 enc_sse2/CollectHistogram: simplify abs calculation +a6c15936 dec_neon: add DC16 intra predictors +03b4f50d Makefile.vc: add anim_diff build support. +1b989874 Merge changes I9cd84125,Iee7e387f,I7548be72 +acd7b5af Introduce a test tool anim_diff. +f274a96c dsp/enc_sse2: add luma4 intra predictors +040b11bd dsp/enc_sse2: add chroma intra predictors +aee021bb dsp/enc_sse2: add luma16 intra predictors +9e00a499 makefile.unix: remove superclean target +cefc9c09 makefile.unix: clean up after extras target +4c9af023 dec_neon: add DC8uvNoTopLeft +dd55b873 Merge "doc/webp-container-spec: update repo browser link" +f0486968 doc/webp-container-spec: update repo browser link +9287761d Merge "GetResidualCostSSE2: simplify abs calculation" +0e009366 dsp/cpu.c(x86): check maximum supported cpuid feature +b243a4bc GetResidualCostSSE2: simplify abs calculation +6d4602b8 Merge "fix typo: constitutes -> constitute" +5fe1fe37 fix typo: constitutes -> constitute +b83bd7c4 Merge "populate 'libwebpextras' with: import gray, rgb565 and rgb4444 functions" +b0114a32 Merge "histogram.h: cosmetics: remove unnecessary includes" +feab45ef gifdec: Move inclusion of webp/config.h to header. +dbba67d1 histogram.h: cosmetics: remove unnecessary includes +e978fec6 Merge "VP8LBitReader: fix remaining ubsan error with large shifts" +d6fe5884 Merge "ReconstructRow: move some one-time inits out of the main loop" +a21d647c ReconstructRow: move some one-time inits out of the main loop +7a01c3c3 VP8LBitReader: fix remaining ubsan error with large shifts +7fa67c9b change GetPixPairHash64() return type to uint32_t +ec1fb9f8 Merge "dsp/enc.c: cosmetics: move DST() def closer to use" +7073bfb3 Merge "split 64-mult hashing into two 32-bit multiplies" +0768b252 dsp/enc.c: cosmetics: move DST() def closer to use +6a48b8f0 Merge "fix MSVC size_t->int conversion warning" +1db07cde Merge "anim_encode: cosmetics: fix alignment" +e28271a3 anim_encode: cosmetics: fix alignment +7fe357b8 split 64-mult hashing into two 32-bit multiplies +af74c145 populate 'libwebpextras' with: import gray, rgb565 and rgb4444 functions +61214134 remove VP8Residual::cost unused field +e2544823 fix MSVC size_t->int conversion warning +b69a6c35 vwebp: don't redefine snprintf with VS2015+ +0ac29c51 AnimEncoder API: Consistent use of trailing underscores in struct. +d4845550 AnimEncoder API: Use timestamp instead of duration as input to Add(). +9904e365 dsp/dec_sse2: DC8uv / DC8uvNoLeft speedup +7df20497 dsp/dec_sse2: DC16 / DC16NoLeft speedup +8e515dfe Merge "makefile.unix: add some missing headers" +db12250f cosmetics: vp8enci.h: break long line +bf516a87 makefile.unix: add some missing headers +b44eda3f dsp: add DSP_INIT_STUB +03e76e96 clarify the comment about double-setting the status in SetError() +9fecdd71 remove unused EmitRGB() +43f010dd move ReconstructRow to top +82d98020 add a dec/common.h header to collect common enc/dec #defines +5d4744a2 Merge "enc_sse41: add Disto4x4 / Disto16x16" +e38886a7 mux.h: Bump up ABI version +46305ca6 configure: add --disable-<avx2|sse4.1|sse2> +2fc8b658 CPPFLAGS->CFLAGS for detecting sse4.1 in preprocessor +1a338fb3 enc_sse41: add Disto4x4 / Disto16x16 +94055503 encoding SSE4.1 stub for StoreHistogram + Quantize + SSE_16xN +c64659e1 remove duplicate variables after the lossless{_enc}.c split +67ba7c7a enc_sse2: call local FTransform in CollectHistogram +18249799 dsp: s/VP8LSetHistogramData/VP8SetHistogramData/ +ede5e158 cosmetics: dsp/lossless.h: reorder prototypes +553051f7 dsp/lossless: split enc/dec functions +9064adc8 Merge "conditionally add -msse4.1 in Makefile.unix" +cecf5096 dsp/yuv*.c: rework WEBP_USE_<arch> ifdef +6584d398 dsp/upsampling*.c: rework WEBP_USE_<arch> ifdef +80809422 dsp/rescaler*.c: rework WEBP_USE_<arch> ifdef +1d93ddec dsp/lossless*.c: rework WEBP_USE_<arch> ifdef +73805ff2 dsp/filters*.c: rework WEBP_USE_<arch> ifdef +fbdcef24 dsp/enc*.c: rework WEBP_USE_<arch> ifdef +66de69c1 dsp/dec*.c: rework WEBP_USE_<arch> ifdef +48e4ffd1 dsp/cost*.c: rework WEBP_USE_<arch> ifdef +29fd6f90 dsp/argb*.c: rework WEBP_USE_<arch> ifdef +80ff3813 dsp/alpha*.c: rework WEBP_USE_<arch> ifdef +bf09cf1e conditionally add -msse4.1 in Makefile.unix +e9570dd9 stub for SSE4.1 support. +4a95384b Merge "dsp: add sse4.1 detection" +cabf4bd2 dsp: add sse4.1 detection +4ecba1ab thread.h: rename interface param +b8d706c8 Merge "sync versions with 0.4.3" +ae64a711 Merge "add shell for libwebpextras" +92a5da9c sync versions with 0.4.3 +9d4e2d16 Merge "~30% faster smart-yuv (-pre 4) with early-out criterion" +b1bdbbab ~30% faster smart-yuv (-pre 4) with early-out criterion +7efb9748 Merge "Disable NEON code on Native Client" +ac4f5784 Disable NEON code on Native Client +0873f85b AnimEncoder API: Support input frames in YUV(A) format. +5c176d2d add shell for libwebpextras +44bd9561 fix signature for VP8RecordCoeffTokens() +c9b8ea0e small cosmetics on TokenBuffer. +76394c09 Merge "MIPS: dspr2: added optimization for TrueMotion" +0f773693 WebPPictureRescale: add a note about 0 width/height +241bb5d9 MIPS: dspr2: added optimization for TrueMotion +6cef0e4f examples/Android.mk: add webpmux_example target +53c16ff0 Android.mk: add webpmux target +21852a00 Android.mk: add webpdemux target +8697a3bc Android.mk: add webpdecoder{,_static} targets +4a670491 Android.mk: split source lists per-directory +b5e79422 MIPS: dspr2: Added optimization for some convert functions +0f595db6 MIPS: dspr2: Added optimization for some convert functions +8a218b4a MIPS: [mips32|dspr2]: GetResidualCost rebased +ef987500 Speedup method StoreImageToBitMask by 5%. +602a00f9 fix iOS arm64 build with Xcode 6.3 +23820507 1-2% faster encoding by removing an indirection in GetResidualCost() +eddb7e70 MIPS: dspr2: added otpimization for DC8uv, DC8uvNoTop and DC8uvNoLeft +73ba2915 MIPS: dspr2: added optimization for functions RD4 and LD4 +c7129da5 Merge "4-5% faster encoding using SSE2 for GetResidualCost" +94380d00 MIPS: dspr2: added optimizaton for functions VE4 and DC4 +2a407092 4-5% faster encoding using SSE2 for GetResidualCost +17e19862 Merge "MIPS: dspr2: added optimization for simple filtering functions" +3ec404c4 Merge "dsp: normalize WEBP_TSAN_IGNORE_FUNCTION usage" +b969f5df dsp: normalize WEBP_TSAN_IGNORE_FUNCTION usage +d7b8e711 MIPS: dspr2: added optimization for simple filtering functions +235f774e Merge "MIPS: dspr2: Added optimization for function VP8LTransformColorInverse_C" +42a8a628 MIPS: dspr2: Added optimization for function VP8LTransformColorInverse_C +b442bef3 Merge "ApplyFiltersAndEncode: only copy lossless stats" +b510fbfe doc/webp-container-spec: note MSB order for chunk diagrams +9bc0f922 ApplyFiltersAndEncode: only copy lossless stats +3030f115 Merge "dsp/mips: add some missing TSan annotations" +dfcf4593 Merge "MIPS: dspr2: Added optimization for function VP8LAddGreenToBlueAndRed_C" +55c75a25 dsp/mips: add some missing TSan annotations +2cb879f0 MIPS: dspr2: Added optimization for function VP8LAddGreenToBlueAndRed_C +e1556010 move some cost tables from enc/ to dsp/ +c3a03168 Merge "picture_csp: fix build w/USE_GAMMA_COMPRESSION undefined" +39537d7c Merge "VP8LDspInitMIPSdspR2: add missing TSan annotation" +1dd419ce picture_csp: fix build w/USE_GAMMA_COMPRESSION undefined +43fd3543 VP8LDspInitMIPSdspR2: add missing TSan annotation +c7233dfc Merge "VP8LDspInit: remove memcpy" +0ec4da96 picture_csp::InitGammaTables*: add missing TSan annotations +35579a49 VP8LDspInit: remove memcpy +97f6aff8 VP8YUVInit: add missing TSan annotation +f9016d66 dsp/enc::InitTables: add missing TSan annotation +e3d9771a VP8EncDspCostInit*: add missing TSan annotations +d97c143d Merge "doc/webp-container-spec: cosmetics" +309b7908 MIPS: mips32: Added optimization for function SetResidualCoeffs +a987faed MIPS: dspr2: added optimization for function GetResidualCost +e7d3df23 doc/webp-container-spec: cosmetics +be6635e9 Merge "VP8TBufferClear: remove some misleading const's" +02971e72 Merge "VP8EmitTokens: remove unnecessary param void cast" +3b77e5a7 VP8TBufferClear: remove some misleading const's +aa139c8f VP8EmitTokens: remove unnecessary param void cast +c24d8f14 cosmetics: upsampling_sse2: add const to some casts +1829c42c cosmetics: lossless_sse2: add const to some casts +183168f3 cosmetics: enc_sse2: add const to some casts +860badca cosmetics: dec_sse2: add const to some casts +0254db97 cosmetics: argb_sse2: add const to some casts +1aadf856 cosmetics: alpha_processing_sse2: add const to some casts +1579de3c vwebp: clear canvas at the beginning of each loop +4b9fa5d0 Merge "webp-container-spec: clarify background clear on loop" +4c82284d Updated the near-lossless level mapping. +56039479 webp-container-spec: clarify background clear on loop +19f0ba0e Implement true-motion prediction in SSE2 +774d4cb7 make VP8PredLuma16[] array non-const +d7eabb80 Merge "MIPS: dspr2: Added optimization for function CollectHistogram" +fe42739c Use integers for kmin/kmax for simplicity. +b9df35f7 AnimEncode API: kmax=0 should imply all keyframes. +6ce296da MIPS: dspr2: Added optimization for function CollectHistogram +2c906c40 vwebp: remove unnecessary static Help() prototype +be0fd1d5 Merge "dec/vp8: clear 'dither_' on skipped blocks" +e96170fe Merge "vwebp/animation: display last frame on end-of-loop" +0f017b56 vwebp/animation: display last frame on end-of-loop +c86b40cc enc/near_lossless.c: fix alignment +66935fb9 dec/vp8: clear 'dither_' on skipped blocks +b7de7946 Merge "lossless_neon: enable subtract green for aarch64" +77724f70 SSE2 version of GradientUnfilter +416e1cea lossless_neon: enable subtract green for aarch64 +72831f6b Speedup AnalyzeAndInit for low effort compression. +a6597483 Speedup Analyze methods for lossless compression. +98c81386 Enable Near-lossless feature. +c6b24543 AnimEncoder API: Fix for kmax=1 and default kmin case. +022d2f88 add SSE2 variants for alpha filtering functions +2db15a95 Temporarily disable encoding of alpha plane with color cache. +1d575ccd Merge "Lossless decoding: Remove an unnecessary if condition." +cafa1d88 Merge "Simplify backward refs calculation for low-effort." +7afdaf84 Alpha coding: reorganize the filter/unfiltering code +4d6d7285 Simplify backward refs calculation for low-effort. +ec0d1be5 Cleaup Near-lossless code. +9814ddb6 Remove the post-transform near-lossless heuristic. +4509e32e Lossless decoding: Remove an unnecessary if condition. +f2ebc4a8 Merge "Regression fix for lossless decoding" +783a8cda Regression fix for lossless decoding +9a062b8e AnimEncoder: Bugfix for kmin = 1 and kmax = 2. +0f027a72 simplify smart RGB->YUV conversion code +0d5b334e BackwardReferencesHashChainFollowChosenPath: remove unused variable +f480d1a7 Fix to near lossless artefacts on palettized images. +d4615d08 Merge changes Ia1686828,I399fda40 +cb4a18a7 rename HashChainInit into HashChainReset +f079e487 use uint16_t for chosen_path[] +da091212 MIPS: dspr2: Added optimization for function FTransformWHT +b8c20135 Merge "wicdec: (msvs) quiet some /analyze warnings" +9b228b54 wicdec: (msvs) quiet some /analyze warnings +daeb276a Merge "MIPS: dspr2: Added optimization for MultARGBRow function" +cc087424 Merge "dsp/cpu: (msvs) add include for __cpuidex" +4a82aab5 Merge changes I87544e92,I0bb6cda5 +7a191398 dwebp/WritePNG: mark png variables volatile +775dfad2 dwebp: include setjmp.h w/WEBP_HAVE_PNG +47d26be7 dwebp: correct sign in format strings +f0e0677b VP8LEncodeStream: add an assert +c5f7747f VP8LColorCacheCopy: promote an int before shifting +0de5f33e dsp/cpu: (msvs) add include for __cpuidex +7d850f7b MIPS: dspr2: Added optimization for MultARGBRow function +54875293 MIPS: dspr2: added optimization for function QuantizeBlock +4fbe9cf2 dsp/cpu: (msvs) avoid immintrin.h on _M_ARM +3fd59039 simplify/reorganize arguments for CollectColorBlueTransforms +b9e356b9 Disable costly TraceBackwards for method=0. +a7e7caa4 MIPS: dspr2: added optimization for function TransformColorRed +2cb39180 Merge "MIPS: dspr2: added optimization for function TransformColorBlue" +279e6613 Merge "dsp/cpu: add include for _xgetbv() w/MSVS" +b6c0428e dsp/cpu: add include for _xgetbv() w/MSVS +d1c4ffae gif2webp: Move GIF decoding related code to a support library. +07c39559 Merge "AnimEncoder API: Add info in README.mux" +7b161973 MIPS: dspr2: added optimization for function TransformColorBlue +d7c4b02a cpu: fix AVX2 detection for gcc/clang targets +9d299469 AnimEncoder API: Add info in README.mux +d581ba40 follow-up: clean up WebPRescalerXXX dsp function +f8740f0d dsp: s/USE_INTRINSICS/WEBP_USE_INTRINSICS/ +ce73abe0 Merge "introduce a separate WebPRescalerDspInit to initialize pointers" +ab66beca introduce a separate WebPRescalerDspInit to initialize pointers +205c7f26 fix handling of zero-sized partition #0 corner case +cbcdd5ff Merge "move rescaler functions to rescaler* files in src/dsp/" +bf586e88 Merge changes I230b3532,Idf3057a7 +6dc79dc2 Merge "anim_encode: fix type conversion warnings" +11fce25a Merge "dec_neon: remove returns from void functions" +c4e63f99 Makefile.vc: add gif2webp target +4f43d38c enable NEON for Windows ARM builds +3f6615ac Makefile.vc: add rudimentary Windows ARM support +e7c5954c dec_neon: remove returns from void functions +f79c163b anim_encode: fix type conversion warnings +0f54f1ec Remove gif2webp_util which is no longer needed. +cbcbedd0 move rescaler functions to rescaler* files in src/dsp/ +ac79ed19 webpmux: remove experimental fragment handling +e8694d4d mux: remove experimental FRGM parsing +9e92b6ea AnimEncoder API: Optimize single-frame animated images +abbae279 Merge "Move over gif2webp to the new AnimEncoder API." +a28c4b36 MIPS: move WORK_AROUND_GCC define to appropriate place +012d2c60 MIPS: dspr2: added optimization for functions SSEAxB +67720c8b Move over gif2webp to the new AnimEncoder API. +9241ecf4 MIPS: dspr2: added optimization for function Average +9422211d Merge "Tune BackwardReferencesLz77 for low_effort (m=0)." +df40057b Merge "Speedup VP8LGetHistoImageSymbols for low effort (m=0) mode." +ea08466d Tune BackwardReferencesLz77 for low_effort (m=0). +b0b973c3 Speedup VP8LGetHistoImageSymbols for low effort (m=0) mode. +c6d32927 argb_sse2: cosmetics +67f601cd make the 'last_cpuinfo_used' variable names unique +b9489861 AnimEncoder API: Init method for default options. +856f8ec1 Merge "AnimEncoder API: Remove AnimEncoderFrameOptions." +c537514d Merge "AnimEncoder API: GenerateCandidates bugfix." +dc0ce039 Merge "AnimEncoder API: Compute change rectangle for first frame too." +f00b639b Merge "AnimEncoder API: In Assemble(), always set animation parameters." +29ed796c Merge "AnimEncoder lib cleanup: prev to prev canvas not needed." +9f0dd6e5 Merge "WebPAnimEncoder API: Header and implementation" +5e56bbe0 AnimEncoder API: Remove AnimEncoderFrameOptions. +b902c3ea AnimEncoder API: GenerateCandidates bugfix. +ef3c39bb AnimEncoder API: Compute change rectangle for first frame too. +eec423ab AnimEncoder API: In Assemble(), always set animation parameters. +ae1c046e AnimEncoder lib cleanup: prev to prev canvas not needed. +4b997ae4 WebPAnimEncoder API: Header and implementation +72208bec move argb_*.o build target to encoder list +95920538 Merge "multi-thread fix: lock each entry points with a static var" +4c1b300a Merge "SSE2 implementation of VP8PackARGB" +fbcc2004 Merge "add -Wformat-nonliteral and -Wformat-security" +80d950d9 add -Wformat-nonliteral and -Wformat-security +04c20e75 Merge "MIPS: dspr2: added optimization for function Intra4Preds" +a437694a multi-thread fix: lock each entry points with a static var +ca7f60db SSE2 implementation of VP8PackARGB +72d573f6 simplify the PackARGB signature +4e2589ff demux: restore strict fragment flag check +4ba8e074 Merge "webp-container-spec: remove references to fragments" +e752f0a6 Merge "demux: remove experimental FRGM parsing" +f8abb112 Merge changes I109ec4d9,I73fe7743 +ae2188a4 MIPS: dspr2: added optimization for function Intra4Preds +1f4b8642 move VP8EncDspARGBInit() call closer to where it's needed +14108d78 dec_neon: add DC8uvNoTop / DC8uvNoLeft +d8340da7 dec_neon: add DC8uv +a66e66c7 webp-container-spec: remove references to fragments +7ce8788b MIPS: dspr2: added optimization for function MakeARGB32 +012e623d demux: remove experimental FRGM parsing +87c3d531 method=0: Don't evaluate any predictor +6f4fcb98 Merge "MIPS: dspr2: added optimization for function ImportRow" +24284459 replace unneeded calls to HistogramCopy() by swaps +bdf7b40c MIPS: dspr2: added optimization for function ImportRow +e66a9225 Merge "MIPS: dspr2: added optimization for function ExportRowC" +c279fec1 MIPS: dspr2: added optimization for function ExportRowC +31a9cf64 Speedup WebP lossless compression for low effort (m=0) mode with following: - Disable Cross-Color transform. - Evaluate predictors #11 (paeth), #12 and #13 only. +9275d91c MIPS: dspr2: added optimization for function TrueMotion +26106d66 Merge "enc_neon: fix building with non-Xcode clang (iOS)" +1c4e3efe unroll the kBands[] indirection to remove a dereference in GetCoeffs() +a3946b89 enc_neon: fix building with non-Xcode clang (iOS) +8ed9c00d Merge "simplify the Histogram struct, to only store max_value and last_nz" +bad77571 simplify the Histogram struct, to only store max_value and last_nz +3cca0dc7 MIPS: dspr2: Added optimization for DCMode function +37e395fd MIPS: fix functions to use generic BPS istead of hardcoded value +9475bef4 PickBestUV: fix VP8Copy16x8 invocation +441f273f Merge changes I55f8da52,Id73a1e96 +4a279a68 cosmetics: add some missing != NULL comparisons +66ad3725 factorize BPS definition in dsp.h and add VP8Copy16x8 +432e5b55 make ALIGN_xxx naming consistent +57606047 encoder: switch BPS to 32 instead of 16 +1b66bbe9 MIPS: dspr2: added optimization for function TransformColor_C +c6d0f9e7 histogram: cosmetics +f399d307 Merge changes I6eac17e5,I32d2b514 +9de9074c dec_neon: add TM8uv +8e517eca bit_reader/kVP8NewRange: range_t -> uint8_t +e1857139 dsp: initialize VP8PredChroma8 in VP8DspInit() +e0c809ad Move Entropy methods to lossless.c +a96ccf8f iosbuild: add x64_64 simulator support +a0df5510 Remove handling for WEBP_HINT_GRAPH +413dfc0c Move static method definition before its usage. +0f235665 Update BackwardRefsWithLocalCache. +d69e36ec Remove TODOs from lossless encoder code. +fdaac8e0 Optmize VP8LGetBackwardReferences LZ77 references. +2f0e2ba8 MIPS: dspr2: added optimization for function Select +a3e79a46 Merge "WebPEncode: Support encoding same pic twice (even if modified)" +e4f4dddb WebPEncode: Support encoding same pic twice (even if modified) +cbc3fbb4 Merge "Updated VP8LGetBackwardReferences and color cache." +95a9bd85 Updated VP8LGetBackwardReferences and color cache. +54f2c14c MIPS: dspr2: added optimization for function FTransform +aa42f423 MIPS: dspr2: Added optimization for function VP8LSubtractGreenFromBlueAndRed +11a25f75 Merge "FlattenSimilarBlocks should only be tried when blending is possible." +5cccdadf FlattenSimilarBlocks should only be tried when blending is possible. +95ca44a7 MIPS: dspr2: added optimization for Disto4x4 +4171b672 backward_references.c: reindent after c8581b0 +c8581b06 Optimize BackwardReferences for RLE encoding. +5798eee6 MIPS: dspr2: unfilters bugfix (Ie7b7387478a6b5c3f08691628ae00f059cf6d899) +4167a3f5 Optimize backwardreferences +d18554c3 Merge "webp/types.h: use inline for clang++/-std=c++11" +7489b0e7 gif2webp: Add '-min-size' option to get best compression. +77bdddf0 Speed up BackwardReferences +6638710b webp/types.h: use inline for clang++/-std=c++11 +abf04205 Enable entropy based merge histo for (q<100) +572022a3 filters_mips_dsp_r2.c: disable unfilters +a28e21b1 MIPS: dspr2: Added optimization for function ClampedAddSubtractFull +18d5a1ef MIPS: dspr2: added optimization for function ClampedAddSubtractHalf +829a8c19 MIPS: dspr2: added optimization for ITransform +c94ed49e gif2webp: Use the default hint instead of WEBP_HINT_GRAPH. +653ace55 Increase the MAX_COLOR_CACHE_BITS from 9 to 10. +919220c7 Change the logic adjusting the Histogram bits. +53b096c0 Merge "Fix bug in VP8LCalculateEstimateForCacheSize." +e912bd55 Fix bug in VP8LCalculateEstimateForCacheSize. +541d7839 Merge "dec_neon: add RD4 intra predictor" +f8cd0672 Merge "Makefile.vc: add a 'legacy' RTLIBCFG option" +22881c99 dec_neon: add RD4 intra predictor +613d281e update NEWS +1304eb34 Merge "dec_neon: DC4: use pair-wise adds for top row" +34c20c06 Makefile.vc: add a 'legacy' RTLIBCFG option +7083006b Merge "dsp/dec_{neon,sse2}: VE4: normalize variable names" +0db9031c dsp/dec_{neon,sse2}: VE4: normalize variable names +b5bc1530 dec_neon: DC4: use pair-wise adds for top row +5b90d8fe Unify the API between VP8BitWriter and VP8LBitWriter +f7ada560 Merge changes I2e06907b,Ia9ed4ca6,I782282ff +5beb6bf0 Merge "dec_neon: add VE4 intra predictor" +eba6ce06 dec_neon: add DC4 intra predictor +79abfbd9 dec_neon: add TM4 intra predictor +fe395f0e dec_neon: add LD4 intra predictor +32de385e dec_neon: add VE4 intra predictor +72395ba9 Merge "Modify CostModel to allocate optimal memory." +65e5eb8a gif2webp: Support GIF_DISPOSE_RESTORE_PREVIOUS +e4c829ef gif2webp: Handle frames with odd offsets + disposal to background. +c2b5a039 Modify CostModel to allocate optimal memory. +b7a33d7e implement VE4/HE4/RD4/... in SSE2 +97c76f1f make VP8PredLuma4[] non-const and initialize array in VP8DspInit() +0ea8c6c2 Merge "PrintReg: output to stderr" +d7ff2f97 Merge "stopwatch.h: fix includes" +f85ec712 PrintReg: output to stderr +54edbf65 stopwatch.h: fix includes +139142e4 Optimize BackwardReferenceHashChainFollowPath. +5f36b68d enc/backward_references.c: fix indent +e0e9960d Merge "sync version numbers to 0.4.2 release" +64ac5144 sync version numbers to 0.4.2 release +c24f8954 Simplify and speedup Backward refs computation. +d1c359ef fix shared object build with -fvisibility=hidden +a4c3a31b WEBP_TSAN_IGNORE_FUNCTION: fix gcc compat warning +f358eeb8 add code for testing random incremental decoding in dwebp +80247291 mark some init function as being safe for thread_sanitizer. +79b5bdbf bit_reader.h: cosmetics: fix a typo +6c673681 Improved near-lossless mode. +0ce27e71 enc_mips32: workaround gcc-4.9 bug +aca1b98f enc/vp8l.c: fix indent +ca005027 Evaluate non-palette compression for palette image +c8a87bb6 AssignSegments: quiet -Warray-bounds warning +32f67e30 Merge "enc_neon: initialize vectors w/vdup_n_u32" +fabc65da 1-3% faster encoding optimizing SSE_NxN functions +7534d716 enc_neon: initialize vectors w/vdup_n_u32 +5f813912 Merge "Fix return code of EncodeImageInternal()" +e321abe4 Fix return code of EncodeImageInternal() +f82cb06a optimize palette ordering +f545feee don't set the alpha value for histogram index image +2d9b0a44 add WebPDispatchAlphaToGreen() to dsp +1bd4c2ad Merge "Change Entropy based Histogram Combine heuristic." +e295b8f1 Merge "iosbuild: cleanup" +1be4e760 Merge "iosbuild: output autoconf req. on failure" +d5e498d4 Change Entropy based Histogram Combine heuristic. +47a2d8e1 fix MSVC float->int conversion warning +041956f6 iosbuild: cleanup +767eb402 iosbuild: output autoconf req. on failure +35ad48b8 HistoHeapInit: correct positions allocation size +45d9635f lossless: entropy clustering for high qualities. +dc37df8c fix type warning for VS9_x64 +9f7d9e6d iosbuild: make iOS 6 the minimum requirement +fdd6528b Remove unused VP8LDecoder member variable +ea3bba5a Merge "rewrite Disto4x4 in enc_neon.c with intrinsic" +f060dfc4 add lossless incremental decoding support +ab70794d rewrite Disto4x4 in enc_neon.c with intrinsic +d4471637 MIPS: dspr2: added optimization for function FilterLoop24 +2aef54d4 Merge "prepare VP8LDecodeImage for incremental decode" +aed0f5a2 Merge "MIPS: dspr2: added optimization for function FilterLoop26" +28630685 prepare VP8LDecodeImage for incremental decode +248f3aed remove br->error_ field +49e15044 MIPS: dspr2: added optimization for function FilterLoop26 +38128cb9 iobuild.sh: only install .h files in Headers +c792d412 Premultiply with alpha during U/V downsampling +0cc811d7 gif2webp: Background color correction +d7167ff7 Amend the lossless spec according to issue #205, #206 and #224 +b901416b Record the lossless size stats. +cddd3340 Add a WebPExtractAlpha function to dsp +0716a98e fix indent after I0204949917836f74c0eb4ba5a7f4052a4797833b +f9ced95a Optimize lossless decoding for trivial(ARB) codes. +924fcfd9 Merge "webpmux: simplify InitializeConfig()" +c0a462ca webpmux: simplify InitializeConfig() +6986bb5e webpmux: fix indent +f89e1690 webpmux: fix exit status on numeric value parse error +2172cb62 Merge "webpmux: fix loop_count range check" +e3b343ec Merge "examples: warn on invalid numeric parameters" +0e23c487 webpmux: fix loop_count range check +6208338a Merge "fix loop bug in DispatchAlpha()" +d51f3e40 gif2webp: Handle frames with missing graphic control extension +690b491a fix loop bug in DispatchAlpha() +96d43a87 examples: warn on invalid numeric parameters +3101f537 MIPS: dspr2: added optimization for TransformOne +a6bb9b17 SSE2 for inverse Mult(ARGB)Row and ApplyAlphaMultiply +d84a8ffd Remove default initialization of decoder status. +be70b86c configure: simplify libpng-config invocation +e0a99321 Rectify bug in lossless incremental decoding. +e2502a97 MIPS: dspr2: added optimization for TransformAC3 +24e1072a MIPS: dspr2: added optimization for TransformDC +c0e84df8 Merge "Slightly faster lossless decoding (1%)" +8dd28bb5 Slightly faster lossless decoding (1%) +f0103595 MIPS: dspr2: added optimization for ColorIndexInverseTransforms +d3242aee make VP8LSetBitPos() set br->eos_ flag +a9decb55 Lossless decoding: fix eos_ flag condition +3fea6a28 fix erroneous dec->status_ setting +80b8099f MIPS: dspr2: add some specific mips code to commit I2c3f2b12f8df15b785fad5a9c56316e954ae0c53 +e5640625 Merge "further refine the COPY_PATTERN optim for DecodeAlpha" +854509fe enc/histogram.c: reindent after f4059d0 +34421964 Merge "~3-5% faster encoding optimizing PickBestIntra*()" +865069c1 further refine the COPY_PATTERN optim for DecodeAlpha +a5956228 added C-level optimization for DecodeAlphaData function +187d379d add a fallback to ALPHA_NO_COMPRESSION +a48a2d76 ~3-5% faster encoding optimizing PickBestIntra*() +a6140194 ExUtilReadFromStdin: (windows) open stdin in bin mode +e80eab1f webpmux: (windows) open stdout in binary mode +e9bfb116 cwebp: (windows) open stdout in binary mode +5927e15b example_util: add ExUtilSetBinaryMode +30f3b75b webpmux man page: Clarify some title, descriptions and examples +77d4c7e3 address cosmetic comments from patch #71380 +f75dfbf2 Speed up Huffman decoding for lossless +637b3888 dsp/lossless: workaround gcc-4.9 bug on arm +8323a903 dsp.h: collect gcc/clang version test macros +e6c4b52f move static initialization of WebPYUV444Converters[] to the Init function. +49911d4d Merge "fix indentation" +f4059d0c Code cleanup for HistogramRemap. +e632b092 fix indentation +f5c04d64 Merge "add a DispatchAlpha() for SSE2 that handles 8 pixels at a time" +fc98edd9 add a DispatchAlpha() for SSE2 that handles 8 pixels at a time +73d361dd introduce VP8EncQuantize2Blocks to quantize two blocks at a time +0b21c30b MIPS: dspr2: added optimization for EmitAlphaRGB +953acd56 enc_neon: enable QuantizeBlock for aarch64 +f4ae1437 MIPS: mips32: code rebase +56977154 MIPS: dspr2: added optimizations for VP8YuvTo* +2523aa73 SmartRGBYUV: fix odd-width problem with pixel replication +ee52dc4e fix some MSVC64 warning about float conversion +3fca851a cpu: check for _MSC_VER before using msvc inline asm +e2a83d71 faster RGB->YUV conversion function (~7% speedup) +de2d03e1 Merge "Add smart RGB->YUV conversion option -pre 4" +3fc4c539 Add smart RGB->YUV conversion option -pre 4 +b4dc4069 MIPS: dspr2: added optimization for (un)filters +137e6090 Merge "configure: add work around for gcc-4.9 aarch64 bug" +b61c9cec MIPS: dspr2: Optimization of some simple point-sampling functions +e2b8cec0 configure: add work around for gcc-4.9 aarch64 bug +98c54107 MIPS: mips32r2: added optimization for BSwap32 +dab702b3 Update PATENTS to reflect s/VP8/WebM/g +b564f7c7 Merge "MIPS: detect mips32r6 and disable mips32r1 code" +b7e5a5c4 MIPS: detect mips32r6 and disable mips32r1 code +63c2fc02 Correctly use the AC_CANONICAL_* macros +bb07022b Merge "cosmetics" +e300c9d8 cosmetics +0e519eea Merge "cosmetics: remove some extraneous 'extern's" +3ef0f08a Merge "vp8enci.h: cosmetics: fix '*' placement" +4c6dde37 bit_writer: cosmetics: rename kFlush() -> Flush() +f7b4c48b cosmetics: remove some extraneous 'extern's +b47fb00a vp8enci.h: cosmetics: fix '*' placement +b5a36cc9 add -near_lossless [0..100] experimental option +0524d9e5 dsp: detect mips64 & disable mips32 code +d3485d96 cwebp.1: fix quality description placement +29a9fe22 Merge tag 'v0.4.1' +8af27718 update ChangeLog (tag: v0.4.1, origin/0.4.1, 0.4.1) +e09e9ff6 Record & log the image pre-processing time. +f59c0b4b iosbuild.sh: specify optimization flags +8d34ea3e update ChangeLog (tag: v0.4.1-rc1) +dbc3da66 makefile.unix: add vwebp.1 to the dist target +89a7c83c update ChangeLog +ffe67ee9 Merge "update NEWS for the next release" into 0.4.1 +2def1fe6 gif2webp: dust up the help message +fb668d78 remove -noalphadither option from README/vwebp.1 +e49f693b update NEWS for the next release +cd013580 Merge "update AUTHORS" into 0.4.1 +268d01eb update AUTHORS +85213b9b bump version to 0.4.1 +695f80ae Merge "restore mux API compatibility" into 0.4.1 +862d296c restore mux API compatibility +8f6f8c5d remove the !WEBP_REFERENCE_IMPLEMENTATION tweak in Put8x8uv +d713a696 Merge changes If4debc15,I437a5d5f into 0.4.1 +c2fc52e4 restore encode API compatibility +793368e8 restore decode API compatibility +b8984f31 gif2webp: fix compile with giflib 5.1.0 +222f9b1a gif2webp: simplify giflib version checking +d2cc61b7 Extend MakeARGB32() to accept Alpha channel. +4595b62b Merge "use explicit size of kErrorMessages[] arrays" +157de015 Merge "Actuate memory stats for PRINT_MEMORY_INFO" +fbda2f49 JPEG decoder: delay conversion to YUV to WebPEncode() call +0b747b1b use explicit size of kErrorMessages[] arrays +3398d81a Actuate memory stats for PRINT_MEMORY_INFO +6f3202be Merge "move WebPPictureInit to picture.c" +6c347bbb move WebPPictureInit to picture.c +fb3acf19 fix configure message for multi-thread +40b086f7 configure: check for _beginthreadex +1549d620 reorder the YUVA->ARGB and ARGB->YUVA functions correctly +c6461bfd Merge "extract colorspace code from picture.c into picture_csp.c" +736f2a17 extract colorspace code from picture.c into picture_csp.c +645daa03 Merge "configure: check for -Wformat-security" +abafed86 configure: check for -Wformat-security +fbadb480 split monolithic picture.c into picture_{tools,psnr,rescale}.c +c76f07ec dec_neon/TransformAC3: initialize vector w/vcreate +bb4fc051 gif2webp: Allow single-frame animations +46fd44c1 thread: remove harmless race on status_ in End() +5a1a7264 Merge "configure: check for __builtin_bswapXX()" +6781423b configure: check for __builtin_bswapXX() +6450c48d configure: fix iOS builds +6422e683 VP8LFillBitWindow: enable fast path for 32-bit builds +4f7f52b2 VP8LFillBitWindow: respect WEBP_FORCE_ALIGNED +e458badc endian_inl.h: implement htoleXX with BSwapXX +f2664d1a endian_inl.h: add BSwap16 +6fbf5345 Merge "configure: add --enable-aligned" +dc0f479d configure: add --enable-aligned +9cc69e2b Merge "configure: support WIC + OpenGL under mingw64" +257adfb0 remove experimental YUV444 YUV422 and YUV400 code +10f4257c configure: support WIC + OpenGL under mingw64 +380cca4f configure.ac: add AC_C_BIGENDIAN +ee70a901 endian_inl.h: add BSwap64 +47779d46 endian_inl.h: add BSwap32 +d5104b1f utils: add endian_inl.h +58ab6224 Merge "make alpha-detection loop in IsKeyFrame() in good x/y order" +9d562902 make alpha-detection loop in IsKeyFrame() in good x/y order +516971b1 lossless: Remove unaligned read warning +b8b596f6 Merge "configure.ac: add an autoconf version prerequisite" +34b02f8c configure.ac: add an autoconf version prerequisite +e59f5360 neon: normalize vdup_n_* usage +6ee7160d Merge changes I0da7b3d3,Idad2f278,I4accc305 +abc02f24 Merge "fix (uncompiled) typo" +bc03670f neon: add INIT_VECTOR4 +6c1c632b neon: add INIT_VECTOR3 +dc7687e5 neon: add INIT_VECTOR2 +4536e7c4 add WebPMuxSetCanvasSize() to the mux API +824eab10 fix (uncompiled) typo +1f3e5f1e remove unused 'shift' argument and QFIX2 define +8e867051 Merge "VP8LoadNewBytes: use __builtin_bswap32 if available" +1b6a2635 Merge "Fix handling of weird GIF with canvas dimension 0x0" +1da3d461 VP8LoadNewBytes: use __builtin_bswap32 if available +1582e402 Fix handling of weird GIF with canvas dimension 0x0 +b8811dac Merge "rename interface -> winterface" +db8b8b5f Fix logic in the GIF LOOP-detection parsing +25aaddc8 rename interface -> winterface +5584d9d2 make WebPSetWorkerInterface() check its arguments +a9ef7ef9 Merge "cosmetics: update thread.h comments" +c6af9991 Merge "dust up the help message" +0a8b8863 dust up the help message +a9cf3191 cosmetics: update thread.h comments +27bfeee4 QuantizeBlock SSE2 Optimization: +2bc0dc3e Merge "webpmux: warn when odd frame offsets are used" +3114ebe4 Merge changes Id8edd3c1,Id418eb96,Ide05e3be +c0726634 webpmux: warn when odd frame offsets are used +c5c6b408 Merge "add alpha dithering for lossy" +d5146784 examples/Android.mk: add cwebp +ca0fa7c7 Android.mk: move dwebp to examples/Android.mk +73d8fca0 Android.mk: add ENABLE_SHARED flag +6e93317f muxread: fix out of bounds read +8b0f6a48 Makefile.vc: fix CFLAGS assignment w/HAVE_AVX2=1 +bbe32df1 add alpha dithering for lossy +79020767 Merge "make error-code reporting consistent upon malloc failure" +77bf4410 make error-code reporting consistent upon malloc failure +7a93c000 **/Makefile.am: remove unused AM_CPPFLAGS +24e30805 Add an interface abstraction to the WebP worker thread implementation +d6cd6358 Merge "fix orig_rect==NULL case" +2bfd1ffa fix orig_rect==NULL case +059e21c1 Merge "configure: move config.h to src/webp/config.h" +f05fe006 properly report back encoding error code in WebPFrameCacheAddFrame() +32b31379 configure: move config.h to src/webp/config.h +90090d99 Merge changes I7c675e51,I84f7d785 +ae7661b3 makefiles: define WEBP_HAVE_AVX2 when appropriate +69fce2ea remove the special casing for res->first in VP8SetResidualCoeffs +6e61a3a9 configure: test for -msse2 +b9d2efc6 rename upsampling_mips32.c to yuv_mips32.c +bdfeebaa dsp/yuv: move sse2 functions to yuv_sse2.c +46b32e86 Merge "configure: set WEBP_HAVE_AVX2 when available" +88305db4 Merge "VP8RandomBits2: prevent signed int overflow" +73fee88c VP8RandomBits2: prevent signed int overflow +db4860b3 enc_sse2: prevent signed int overflow +3fdaf4d2 Merge "real fix for longjmp warning" +385e3340 real fix for longjmp warning +230a0555 configure: set WEBP_HAVE_AVX2 when available +a2ac8a42 restore original value_/range_ field order +5e2ee56f Merge "remove libwebpdspdecode dep on libwebpdsp_avx2" +61362db5 remove libwebpdspdecode dep on libwebpdsp_avx2 +42c447ae Merge "lossy bit-reader clean-up:" +479ffd8b Merge "remove unused #include's" +9754d39a Merge "strong filtering speed-up (~2-3% x86, ~1-2% for NEON)" +158aff9b remove unused #include's +09545eea lossy bit-reader clean-up: +ea8b0a17 strong filtering speed-up (~2-3% x86, ~1-2% for NEON) +6679f899 Optimize VP8SetResidualCoeffs. +ac591cf2 fix for gcc-4.9 warnings about longjmp + local variables +4dfa86b2 dsp/cpu: NaCl has no support for xgetbv +4c398699 Merge "cwebp: fallback to native webp decode in WIC builds" +33aa497e Merge "cwebp: add some missing newlines in longhelp output" +c9b340a2 fix missing WebPInitAlphaProcessing call for premultiplied colorspace output +57897bae Merge "lossless_neon: use vcreate_*() where appropriate" +6aa4777b Merge "(enc|dec)_neon: use vcreate_*() where appropriate" +0d346e41 Always reinit VP8TransformWHT instead of hard-coding +7d039fc3 cwebp: fallback to native webp decode in WIC builds +d471f424 cwebp: add some missing newlines in longhelp output +bf0e0030 lossless_neon: use vcreate_*() where appropriate +9251c2f6 (enc|dec)_neon: use vcreate_*() where appropriate +399b916d lossy decoding: correct alpha-rescaling for YUVA format +78c12ed8 Merge "Makefile.vc: add rudimentary avx2 support" +dc5b122f try to remove the spurious warning for static analysis +ddfefd62 Makefile.vc: add rudimentary avx2 support +a8911643 Merge "simplify VP8LInitBitReader()" +fdbcd44d simplify VP8LInitBitReader() +7c004287 makefile.unix: add rudimentary avx2 support +515e35cf Merge "add stub dsp/enc_avx2.c" +a05dc140 SSE2: yuv->rgb speed-up for point-sampling +178e9a69 add stub dsp/enc_avx2.c +1b99c09c Merge "configure: add a test for -mavx2" +fe728071 configure: add a test for -mavx2 +e46a247c cpu: fix check for __cpuidex availability +176fda26 fix the bit-writer for lossless in 32bit mode +541784c7 dsp.h: add a check for AVX2 / define WEBP_USE_AVX2 +bdb151ee dsp/cpu: add AVX2 detection +ab9f2f86 Merge "revamp the point-sampling functions by processing a full plane" +a2f8b289 revamp the point-sampling functions by processing a full plane +ef076026 use decoder's DSP functions for autofilter +2b5cb326 Merge "dsp/cpu: add AVX detection" +df08e67e dsp/cpu: add AVX detection +e2f405c9 Merge "clean-up and slight speed-up in-loop filtering SSE2" +f60957bf clean-up and slight speed-up in-loop filtering SSE2 +9fc3ae46 .gitattributes: treat .ppm as binary +3da924b5 Merge "dsp/WEBP_USE_NEON: test for __aarch64__" +c7164490 Android.mk: always include *_neon.c in the build +a577b23a dsp/WEBP_USE_NEON: test for __aarch64__ +54bfffca move RemapBitReader() from idec.c to bit_reader code +34168ecb Merge "remove all unused layer code" +f1e77173 remove all unused layer code +b0757db7 Code cleanup for VP8LGetHistoImageSymbols. +5fe628d3 make the token page size be variable instead of fixed 8192 +f948d08c memory debug: allow setting pre-defined malloc failure points +ca3d746e use block-based allocation for backward refs storage, and free-lists +1ba61b09 enable NEON intrinsics in aarch64 builds +b9d2bb67 dsp/neon.h: coalesce intrinsics-related defines +b5c75258 iosbuild: add support for iOSv7/aarch64 +9383afd5 Reduce number of memory allocations while decoding lossless. +888e63ed Merge "dsp/lossless: prevent signed int overflow in left shift ops" +8137f3ed Merge "instrument memory allocation routines for debugging" +2aa18736 instrument memory allocation routines for debugging +d3bcf72b Don't allocate VP8LHashChain, but treat like automatic object +bd6b8619 dsp/lossless: prevent signed int overflow in left shift ops +b7f19b83 Merge "dec/vp8l: prevent signed int overflow in left shift ops" +29059d51 Merge "remove some uint64_t casts and use." +e69a1df4 dec/vp8l: prevent signed int overflow in left shift ops +cf5eb8ad remove some uint64_t casts and use. +38e2db3e MIPS: MIPS32r1: Added optimization for HistogramAdd. +e0609ade dwebp: fix exit code on webp load failure +bbd358a8 Merge "example_util.h: avoid forward declaring enums" +8955da21 example_util.h: avoid forward declaring enums +6d6865f0 Added SSE2 variants for Average2/3/4 +b3a616b3 make HistogramAdd() a pointer in dsp +c8bbb636 dec_neon: relocate some inline-asm defines +4e393bb9 dec_neon: enable intrinsics-only functions +ba99a922 dec_neon: use positive tests for USE_INTRINSICS +69058ff8 Merge "example_util: add ExUtilDecodeWebPIncremental" +a7828e8b dec_neon: make WORK_AROUND_GCC conditional on version +3f3d717a Merge "enc_neon: enable intrinsics-only functions" +de3cb6c8 Merge "move LOCAL_GCC_VERSION def to dsp.h" +1b2fe14d example_util: add ExUtilDecodeWebPIncremental +ca49e7ad Merge "enc_neon: move Transpose4x4 to dsp/neon.h" +ad900abd Merge "fix warning about size_t -> int conversion" +4825b436 fix warning about size_t -> int conversion +42b35e08 enc_neon: enable intrinsics-only functions +f937e012 move LOCAL_GCC_VERSION def to dsp.h +5e1a17ef enc_neon: move Transpose4x4 to dsp/neon.h +c7b92a5a dec_neon: (WORK_AROUND_GCC) delete unused Load4x8 +8e5f90b0 Merge "make ExUtilLoadWebP() accept NULL bitstream param." +05d4c1b7 Merge "cwebp: add webpdec" +ddeb6ac8 cwebp: add webpdec +35d7d095 Merge "Reduce memory footprint for encoding WebP lossless." +0b896101 Reduce memory footprint for encoding WebP lossless. +f0b65c9a make ExUtilLoadWebP() accept NULL bitstream param. +9c0a60cc Merge "dwebp: move webp decoding to example_util" +1d62acf6 MIPS: MIPS32r1: Added optimization for HuffmanCost functions. +4a0e7390 dwebp: move webp decoding to example_util +c0220460 Merge "Bugfix: Incremental decode of lossy-alpha" +8c7cd722 Bugfix: Incremental decode of lossy-alpha +7955152d MIPS: fix error with number of registers. +b1dabe37 Merge "Move the HuffmanCost() function to dsp lib" +75b12006 Move the HuffmanCost() function to dsp lib +2772b8bd MIPS: fix assembler error revealed by clang's debug build +6653b601 enc_mips32: fix unused symbol warning in debug +8dec1209 enc_mips32: disable ITransform(One) in debug builds +98519dd5 enc_neon: convert Disto4x4 to intrinsics +fe9317c9 cosmetics: +953b0746 enc_neon: cosmetics +a9fc697c Merge "WIP: extract the float-calculation of HuffmanCost from loop" +3f84b521 Merge "replace some mult-long (vmull_u8) with mult-long-accumulate (vmlal_u8)" +4ae0533f MIPS: MIPS32r1: Added optimizations for ExtraCost functions. +b30a04cf WIP: extract the float-calculation of HuffmanCost from loop +a8fe8ce2 Merge "NEON intrinsics version of CollectHistogram" +95203d2d NEON intrinsics version of CollectHistogram +7ca2e74b replace some mult-long (vmull_u8) with mult-long-accumulate (vmlal_u8) +41c6efbd fix lossless_neon.c +8ff96a02 NEON intrinsics version of FTransform +0214f4a9 Merge "MIPS: MIPS32r1: Added optimizations for FastLog2" +baabf1ea MIPS: MIPS32r1: Added optimizations for FastLog2 +3d49871d NEON functions for lossless coding +3fe02915 MIPS: MIPS32r1: Added optimizations for SSE functions. +c503b485 Merge "fix the gcc-4.6.0 bug by implementing alternative method" +abe6f487 fix the gcc-4.6.0 bug by implementing alternative method +5598bdec enc_mips32.c: fix file mode +2b1b4d5a MIPS: MIPS32r1: Add optimization for GetResidualCost +f0a1f3cd Merge "MIPS: MIPS32r1: Added optimization for FTransform" +7231f610 MIPS: MIPS32r1: Added optimization for FTransform +869eaf6c ~30% encoding speedup: use NEON for QuantizeBlock() +f758af6b enc_neon: convert FTransformWHT to intrinsics +7dad095b MIPS: MIPS32r1: Added optimization for Disto4x4 (TTransform) +2298d5f3 MIPS: MIPS32r1: Added optimization for QuantizeBlock +e88150c9 Merge "MIPS: MIPS32r1: Add optimization for ITransform" +de693f25 lossless_neon: disable VP8LConvert* functions +4143332b NEON intrinsics for encoding +0ca2914b MIPS: MIPS32r1: Add optimization for ITransform +71bca5ec dec_neon: use vst_lane instead of vget_lane +bf061052 Intrinsics NEON version of TransformOne +19c6f1ba Merge "dec_neon: use vld?_lane instead of vset?_lane" +7a94c0cf upsampling_neon: drop NEON suffix from local functions +d14669c8 upsampling_sse2: drop SSE2 suffix from local functions +2ca42a4f enc_sse2: drop SSE2 suffix from local functions +d038e619 dec_sse2: drop SSE2 suffix from local functions +fa52d752 dec_neon: use vld?_lane instead of vset?_lane +c520e77d cosmetic: fix long line +4b0f2dae Merge "add intrinsics NEON code for chroma strong-filtering" +e351ec07 add intrinsics NEON code for chroma strong-filtering +aaf734b8 Merge "Add SSE2 version of forward cross-color transform" +c90a902e Add SSE2 version of forward cross-color transform +bc374ff3 Use histogram_bits to initalize transform_bits. +2132992d Merge "Add strong filtering intrinsics (inner and outer edges)" +5fbff3a6 Add strong filtering intrinsics (inner and outer edges) +d4813f0c Add SSE2 function for Inverse Cross-color Transform +26029568 dec_neon: add strong loopfilter intrinsics +cca7d7ef Merge "add intrinsics version of SimpleHFilter16NEON()" +1a05dfa7 windows: fix dll builds +d6c50d8a Merge "add some colorspace conversion functions in NEON" +4fd7c82e SSE2 variants of Subtract-Green: Rectify loop condition +97e5fac3 add some colorspace conversion functions in NEON +b9a7a45f add intrinsics version of SimpleHFilter16NEON() +daccbf40 add light filtering NEON intrinsics +af444608 fix typo in STORE_WHT +6af6b8e1 Tune HistogramCombineBin for large images. +af93bdd6 use WebPSafe[CM]alloc/WebPSafeFree instead of [cm]alloc/free +51f406a5 lossless_sse2: relocate VP8LDspInitSSE2 proto +0f4f721b separate SSE2 lossless functions into its own file +514fc251 VP8LConvertFromBGRA: use conversion function pointers +6d2f3527 dsp/dec: TransformDCUV: use VP8TransformDC +defc8e1b Merge "fix out-of-bound read during alpha-plane decoding" +fbed3643 Merge "dsp: reuse wht transform from dec in encoder" +d8467084 Merge "Add SSE2 version of ARGB -> BGR/RGB/... conversion functions" +207d03b4 fix out-of-bound read during alpha-plane decoding +d1b33ad5 2-5% faster trellis with clang/MacOS (and ~2-3% on ARM) +369c26dd Add SSE2 version of ARGB -> BGR/RGB/... conversion functions +df230f27 dsp: reuse wht transform from dec in encoder +80e218d4 Android.mk: fix build with APP_ABI=armeabi-v7a-hard +59daf083 Merge "cosmetics:" +53622008 cosmetics: +3e7f34a3 AssignSegments: quiet array-bounds warning +3c2ebf58 Merge "UpdateHistogramCost: avoid implicit double->float" +cf821c82 UpdateHistogramCost: avoid implicit double->float +312e638f Extend the search space for GetBestGreenRedToBlue +1c58526f Fix few nits +fef22704 Optimize and re-structure VP8LGetHistoImageSymbols +068b14ac Optimize lossless decoding. +5f0cfa80 Do a binary search to get the optimum cache bits. +24ca3678 Merge "allow 'cwebp -o -' to emit output to stdout" +e12f874e allow 'cwebp -o -' to emit output to stdout +2bcad89b allow some more stdin/stout I/O +84ed4b3a fix cwebp.1 typos after patch #69199 +65b99f1c add a -z option to cwebp, and WebPConfigLosslessPreset() function +30176619 4-5% faster trellis by removing some unneeded calculations. +687a58ec histogram.c: reindent after b33e8a0 +06d456f6 Merge "~3-4% faster lossless encoding" +c60de260 ~3-4% faster lossless encoding +42eb06fc Merge "few cosmetics after patch #69079" +82af8264 few cosmetics after patch #69079 +b33e8a05 Refactor code for HistogramCombine. +ca1bfff5 Merge "5-10% encoding speedup with faster trellis (-m 6)" +5aeeb087 5-10% encoding speedup with faster trellis (-m 6) +82ae1bf2 cosmetics: normalize VP8GetCPUInfo checks +e3dd9243 Merge "Refactor GetBestPredictorForTile for future tuning." +206cc1be Refactor GetBestPredictorForTile for future tuning. +3cb84062 Merge "speed-up trellis quant (~5-10% overall speed-up)" +b66f2227 Merge "lossy encoding: ~3% speed-up" +4287d0d4 speed-up trellis quant (~5-10% overall speed-up) +390c8b31 lossy encoding: ~3% speed-up +9a463c4a Merge "dec_neon: convert TransformWHT to intrinsics" +e8605e96 Merge "dec_neon: add ConvertU8ToS16" +4aa3e412 MIPS: MIPS32r1: rescaler bugfix +c16cd99a Speed up lossless encoder. +9d6b5ff1 dec_neon: convert TransformWHT to intrinsics +2ff0aae2 dec_neon: add ConvertU8ToS16 +77a8f919 fix compilation with USE_YUVj flag +4acbec1b Merge changes I3b240ffb,Ia9370283,Ia2d28728 +2719bb7e dec_neon: TransformAC3: work on packed vectors +b7b60ca1 dec_neon: add SaturateAndStore4x4 +b7685d73 Rescale: let ImportRow / ExportRow be pointer-to-function +e02f16ef dec_neon.c: convert TransformDC to intrinsics +9cba963f add missing file +8992ddb7 use static clipping tables +0235d5e4 1-2% faster quantization in SSE2 +b2fbc36c fix VC12-x64 warning +6e37cb94 Merge "cosmetics: backward_references.c: reindent after a7d2ee3" +a42ea974 cosmetics: backward_references.c: reindent after a7d2ee3 +6c327442 Merge "fix missing __BIG_ENDIAN__ definition on some platform" +a8b6aad1 fix missing __BIG_ENDIAN__ definition on some platform +fde2904b Increase initial buffer size for VP8L Bit Writer. +a7d2ee39 Optimize cache estimate logic. +7fb6095b Merge "dec_neon.c: add TransformAC3" +bf182e83 VP8LBitWriter: use a bit-accumulator +3f40b4a5 Merge "MIPS: MIPS32r1: clang macro warning resolved" +1684f4ee WebP Decoder: Mark some truncated bitstreams as invalid +acbedac4 MIPS: MIPS32r1: clang macro warning resolved +228e4877 dec_neon.c: add TransformAC3 +393f89b7 Android.mk: avoid gcc-specific flags with clang +32aeaf11 revamp VP8LColorSpaceTransform() a bit +0c7cc4ca Merge "Don't dereference NULL, ensure HashChain fully initialized" +391316fe Don't dereference NULL, ensure HashChain fully initialized +926ff402 WEBP_SWAP_16BIT_CSP: remove code dup +1d1cd3bb Fix decode bug for rgbA_4444/RGBA_4444 color-modes. +939e70e7 update AUTHORS file +8934a622 cosmetics: *_mips32.c +dd438c9a MIPS: MIPS32r1: Optimization of some simple point-sampling functions. PATCH [6/6] +53520911 Added support for calling sampling functions via pointers. +d16c6974 MIPS: MIPS32r1: Optimization of filter functions. PATCH [5/6] +04336fc7 MIPS: MIPS32r1: Optimization of function TransformOne. PATCH [4/6] +92d8fc7d MIPS: MIPS32r1: Optimization of function WebPRescalerImportRow. PATCH [3/6] +bbc23ff3 parse one row of intra modes altogether +a2f608f9 Merge "MIPS: MIPS32r1: Optimization of function WebPRescalerExportRow. [2/6]" +88230854 MIPS: MIPS32r1: Optimization of function WebPRescalerExportRow. [2/6] +c5a5b028 decode mt+incremental: fix segfault in debug builds +9882b2f9 always use fast-analysis for all methods. +000adac0 Merge "autoconf: update ax_pthread.m4" +2d2fc37d update .gitignore +5bf4255a Merge "Make it possible to avoid automagic dependencies" +c1cb1933 disable NEON for arm64 platform +73a304e9 Make it possible to avoid automagic dependencies +4d493f8d MIPS: MIPS32r1: Decoder bit reader function optimized. PATCH [1/6] +c741183c make WebPCleanupTransparentArea work with argb picture +5da18552 add a decoding option to flip image vertically +00c3c4e1 Merge "add man/vwebp.1" +2c6bb428 add man/vwebp.1 +ea59a8e9 Merge "Merge tag 'v0.4.0'" +7574bed4 fix comments related to array sizes +0b5a90fd dwebp.1: fix option formatting +effcb0fd Merge tag 'v0.4.0' +7c76255d autoconf: update ax_pthread.m4 +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) +256e4333 update NEWS description with new general features +29625340 Merge "gif2webp: don't use C99 %zu" into 0.4.0 +3b9f9dd0 gif2webp: don't use C99 %zu +b5b2e3c7 cwebp: fix metadata output w/lossy+alpha +ad26df1a makefile.unix: clean up libgif2webp_util.a +c3b45570 update Changelog +ca841121 Merge "bump version to 0.4.0" into 0.4.0 +8c524db8 bump version to 0.4.0 +eec2398c update AUTHORS & .mailmap +b9bbf6a1 update NEWS for 0.4.0 +c72e0811 Merge "dec/webp.c: don't wait for data before reporting w/h" +5ad65314 dec/frame.c: fix formatting +f7fc4bc8 dec/webp.c: don't wait for data before reporting w/h +66a32af5 Merge "NEON speed up" +26d842eb NEON speed up +f307f98b Merge "webpmux: let -- stop parameter parsing" +fe051da7 Merge "README: add a section on gif2webp" +6fd2bd62 Merge "manpage pedantry" +4af19007 README: add a section on gif2webp +6f36ade9 manpage pedantry +f9016cb9 README: update dwebp options +b4fa0a47 webpmux: let -- stop parameter parsing +a9a20acf gif2webp: Add a multi-threaded encode option +495bef41 fix bug in TrellisQuantize +605a7127 simplify __cplusplus ifdef +33109f99 Merge "drop: ifdef __cplusplus checks from C files" +7f9de0b9 Merge changes I994a5587,I8467bb71,I13b50688,I1e2c9c7b +5459030b gif2webp: let -- stop parameter parsing +a4b0aa06 vwebp: let -- stop parameter parsing +98af68fe cwebp: let -- stop parameter parsing +a33831e2 dwebp: let -- stop parameter parsing +36301249 add some checks on error paths +ce4c7139 Merge "autoconf: add --disable-wic" +5227d991 drop: ifdef __cplusplus checks from C files +f6453559 dwebp.1: fix typo +f91034f2 Merge "cwebp: print metadata stats when no output file is given" +d4934553 gif2webp: Backward compatibility for giflib version <= 4.1.3 +4c617d32 gif2webp: Disable output of ICC profile by default +73b731fb introduce a special quantization function for WHT +41c0cc4b Make Forward WHT transform use 32bit fixed-point calculation +a3359f5d Only compute quantization params once +70490437 cwebp: print metadata stats when no output file is given +d513bb62 * fix off-by-one zthresh calculation * remove the sharpening for non luma-AC coeffs * adjust the bias a little bit to compensate for this +ad9dec0c Merge "cosmetics: dwebp: fix local function name format" +f737f037 Merge "dwebp: remove a dead store" +3c3a70da Merge "makefile.unix: install binaries in $(DESTDIR)/bin/" +150b655f Merge "Android.mk: add some release compile flags" +dbebd33b cosmetics: dwebp: fix local function name format +27749951 dwebp: remove a dead store +a01e04fe autoconf: add --disable-wic +5009b227 makefile.unix: install binaries in $(DESTDIR)/bin/ +bab30fca Merge "fix -print_psnr / ssim options" +ebef7fb3 fix -print_psnr / ssim options +cb637855 Merge "fix bug due to overzealous check in WebPPictureYUVAToARGB()" +8189885b Merge "EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE" +4ad7d335 Android.mk: add some release compile flags +c12e2369 cosmetics: fix a few typos +6f104034 fix bug due to overzealous check in WebPPictureYUVAToARGB() +3f6c35c6 EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE +cc55790e Merge changes I8bb7a4dc,I2c180051,I021a014f,I8a224a62 +c536afb5 Merge "cosmetics: fix some typos" +cbdd3e6e add a -dither dithering option to the decoder +e8124012 Updated iosbuild.sh for XCode 5.x +4931c329 cosmetics: fix some typos +05aacf77 mux: add some missing casts +617d9348 enc/vp8l: add a missing cast +46db2865 idec: add some missing casts +b524e336 ErrorStatusLossless: correct return type +cb261f79 fix a descaling bug for vertical/horizontal U/V interpolation +bcb3955c Merge changes I48968468,I181bc736 +73f52133 gif2webp: Add a mixed compression mode +6198715e demux: split chunk parsing from ParseVP8X +d2e3f4e6 demux: add a tail pointer for chunks +87cffcc3 demux: cosmetics: s/has_frames/is_animation/ +e18e6677 demux: strictly enforce the animation flag +c4f39f4a demux: cosmetics: remove a useless break +61cb884d demux: (non-exp) fail if the fragmented flag is set +ff379db3 few % speedup of lossless encoding +df3649a2 remove all disabled code related to P-frames +6d0cb3de Merge "gif2webp: kmin = 0 should suppress key-frame addition." +36555983 gif2webp: kmin = 0 should suppress key-frame addition. +7708e609 Merge "detect flatness in blocks and favor DC prediction" +06b1503e Merge "add comment about the kLevelsFromDelta[][] LUT generation" +5935259c add comment about the kLevelsFromDelta[][] LUT generation +e3312ea6 detect flatness in blocks and favor DC prediction +ebc9b1ee Merge "VPLBitReader bugfix: Catch error if bit_pos > LBITS too." +96ad0e0a VPLBitReader bugfix: Catch error if bit_pos > LBITS too. +a014e9c9 tune quantization biases toward higher precision +1e898619 add helpful PrintBlockInfo() function +596a6d73 make use of 'extern' consistent in function declarations +c8d48c6e Merge "extract random utils to their own file util/random.[ch]" +98aa33cf extract random utils to their own file util/random.[ch] +432a723e Merge "swig: add basic go bindings" +fab618b5 Merge "rename libwebp.i -> libwebp.swig" +e4e7fcd6 swig: add basic go bindings +d3408720 Merge "fast auto-determined filtering strength" +f8bfd5cd fast auto-determined filtering strength +ac0bf951 small clean-up in ExpandMatrix() +1939607e rename libwebp.i -> libwebp.swig +43148b6c filtering: precompute ilimit and hev_threshold +18f992ec simplify f_inner calculation a little +241d11f1 add missing const +86c0031e add a 'format' field to WebPBitstreamFeatures +dde91fde Demux: Correct the extended format validation +5d6c5bd2 add entry for '-resize' option in cwebp's man +7c098d18 Use some gamma-curve range compression when computing U/V average +0b2b0504 Use deterministic random-dithering during RGB->YUV conversion +8a2fa099 Add a second multi-thread method +7d6f2da0 Merge "up to 20% faster multi-threaded decoding" +266f63ea Merge "libwebp.jar: build w/Java 1.6 for Android compat" +0532149c up to 20% faster multi-threaded decoding +38efdc2e Simplify the gif2webp tool: move the optimization details to util +de899516 libwebp.jar: build w/Java 1.6 for Android compat +cb221552 Decode a full row of bitstream before reconstructing +dca8a4d3 Merge "NEON/simple loopfilter: avoid q4-q7 registers" +9e84d901 Merge "NEON/TransformWHT: avoid q4-q7 registers" +fc10249b NEON/simple loopfilter: avoid q4-q7 registers +2f09d63e NEON/TransformWHT: avoid q4-q7 registers +77585a2b Merge "use a macrofunc for setting NzCoeffs bits" +d155507c Merge "use HINT_GRAPH as image_hint for gif source" +9c561646 Merge "only print GIF_DISPOSE_WARNING once" +05879865 use HINT_GRAPH as image_hint for gif source +0b28d7ab use a macrofunc for setting NzCoeffs bits +f9bbc2a0 Special-case sparse transform +00125196 gif2webp: detect and flatten uniformly similar blocks +0deaf0fa only print GIF_DISPOSE_WARNING once +6a8c0eb7 Merge "small optimization in segment-smoothing loop" +f7146bc1 small optimization in segment-smoothing loop +5a7533ce small gif2webp fix +4df0c89e Merge changes Ic697660c,I27285521 +5b2e6bd3 Android.mk: add a dwebp target +f910a84e Android.mk: update build flags +63f9aba4 special-case WHT transform when there's only DC +80911aef Merge "7-8% faster decoding by rewriting GetCoeffs()" +606c4304 gif2webp: Improved compression for lossy animated WebP +fb887f7f gif2webp: Different kmin/kmax defaults for lossy and lossless +2a981366 7-8% faster decoding by rewriting GetCoeffs() +92d47e4c improve VP8L signature detection by checking the version bits too +5cd43e43 Add -incremental option to dwebp +54b8e3f6 webpmux: DisplayInfo(): remove unnecessary error checks. +40ae3520 fix memleak in WebPIDelete() +d9662658 mux.h doc: WebPMuxGetFrame() can return WEBP_MUX_MEMORY_ERROR too. +0e6747f8 webpmux -info: display dimensions and has_alpha per frame +d78a82c4 Sanity check for underflow +8498f4bf Merge "remove -Wshadow warnings" +e89c6fc8 Avoid a potential memleak +3ebe1757 Merge "break down the proba 4D-array into some handy structs" +6a44550a break down the proba 4D-array into some handy structs +2f5e8934 remove -Wshadow warnings +bf3a29b3 Merge "add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags" +2b0a7593 Merge "fix some warnings from static analysis" +22dd07ce mux.h: Some doc corrections +79ff0346 add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags +d51f45f0 fix some warnings from static analysis +d134307b fix conversion warning on MSVC +d538cea8 gif2webp: Support a 'min' and 'max' key frame interval +80b54e1c allow search with token buffer loop and fix PARTITION0 problem +b7d4e042 add VP8EstimateTokenSize() +10fddf53 enc/quant.c: silence a warning +399cd456 Merge "fix compile error on ARM/gcc" +9f24519e encoder: misc rate-related fixes +c663bb21 Merge "simplify VP8IteratorSaveBoundary() arg passing" +fa46b312 Demux.h: Correct a method name reference +f8398c9d fix compile error on ARM/gcc +f691f0e4 simplify VP8IteratorSaveBoundary() arg passing +42542be8 up to 6% faster encoding with clang compiler +93402f02 multi-threaded segment analysis +7e2d6595 Merge "remove the PACK() bit-packing tricks" +c13fecf9 remove the PACK() bit-packing tricks +2fd091c9 Merge "use NULL for lf_stats_ testing, not bool" +b11c9d62 dwebp: use default dct_method +4bb8465f Merge "(de)mux.h: wrap pseudo-code in /* */" +cfb56b17 make -pass option work with token buffers +5416aab4 (de)mux.h: wrap pseudo-code in /* */ +35dba337 use NULL for lf_stats_ testing, not bool +733a7faa enc->Iterator memory cleanup +e81fac86 Add support for "no blend" in webpmux binary +3b80bc48 gif2webp: Separate out each step into a method +bef7e9cc Add doc precision about demux object keeping pointers to data. +61405a14 dwebp: enable stdout output with WIC +6eabb886 Merge "Animated WebP: add "do no blend" option to spec" +be20decb fix compilation for BITS 24 +e58cc137 Merge "dwebp: s/unsigned char/uint8_t/" +72501d43 dwebp: s/unsigned char/uint8_t/ +2c9633e8 Merge "gif2webp: Insert independent frames at regular intervals." +f0d6a14b gif2webp: Insert independent frames at regular intervals. +b25a6fbf yuv.h: fix indent +ede3602e Merge "cosmetics: fix indent" +3a65122a dwebp: fix stdout related output +388a7249 cosmetics: fix indent +4c7322c8 Merge "dsp: msvc compatibility" +d50c7e32 Merge "5-7% faster SSE2 versions of YUV->RGB conversion functions" +b8ab7847 Merge "simplify upsampler calls: only allow 'bottom' to be NULL" +df6cebfa 5-7% faster SSE2 versions of YUV->RGB conversion functions +ad6ac32d simplify upsampler calls: only allow 'bottom' to be NULL +a5e8afaf output to stdout if file name is "-" +f358450f dsp: msvc compatibility +43a7c8eb Merge "cosmetics" +4c5f19c1 Merge "bit_reader.h: cosmetics" +f72fab70 cosmetics +14dd5e78 fix const-ness +b20aec49 Merge "Support for 'do not blend' option in vwebp" +dcf65222 Support for 'do not blend' option in vwebp +d5bad033 Animated WebP: add "do no blend" option to spec +a2f5f73d Merge "Support for "Do not blend" in mux and demux libraries" +e081f2f3 Pack code & extra_bits to Struct (VP8LPrefixCode). +6284854b Support for "Do not blend" in mux and demux libraries +f486aaa9 Merge "slightly faster ParseIntraMode" +d1718632 slightly faster ParseIntraMode +3ceca8ad bit_reader.h: cosmetics +69257f70 Create LUT for PrefixEncode. +988b7084 add WebPWorkerExecute() for convenient bypass +06e24987 Merge "VP8EncIterator clean-up" +de4d4ad5 VP8EncIterator clean-up +7bbe9529 Merge "cosmetics: thread.c: drop a redundant comment" +da411485 cosmetics: thread.c: drop a redundant comment +feb4b6e6 thread.h: #ifdef when checking WEBP_USE_THREAD +8924a3a7 thread.c: drop WebPWorker prefix from static funcs +1aed8f2a Merge "fix indent" +4038ed15 fix indent +1693fd9b Demux: A new state WEBP_DEMUX_PARSE_ERROR +8dcae8b3 fix rescaling-with-alpha inaccuracy +11249abf Merge changes I9b4dc36c,I4e0eef4d +52508a1f Mux: support parsing unknown chunks within a frame/fragment. +05db0572 WebPMuxSetChunk: remove unused variable +8ba1bf61 Stricter check for presence of alpha when writing lossless images +a03c3516 Demux: WebPIterator now also denotes if the frame has alpha. +6df743a3 Decoder: handle fragments case correctly too. +faa4b07e Support for unknown chunks in mux library +7d60bbc6 Speed up HashChainFindCopy function. +66740140 Speedup Alpha plane encoding. +b7346a1e 0.1 % speedup to decoding +c606182e webp-container-spec: Tighten language added by last +a34a5029 pngdec: output error messages from libpng +e84c625d Merge "Detect canvas and image size mismatch in decoder." +f626fe2e Detect canvas and image size mismatch in decoder. +f5fbdee0 demux: stricter image bounds check +30c8158a add extra assert in Huffman decode code +8967b9f3 SSE2 for lossless decoding (critical) functions. +699d80ea Jump-lookup for Huffman coding +c34307ab fix some VS9 warnings about type conversion +eeada35c pngdec: add missing include +54b65108 gif2webp: If aligning to even offsets, extra pixels should be transparent +0bcf5ce3 Merge "remove a malloc() in case we're using only FILTER_NONE for alpha" +2c07143b remove a malloc() in case we're using only FILTER_NONE for alpha +a4d5f59d Faster lossless decoding +fd53bb75 Merge "alternate LUT-base reverse-bits code" +d1c166ef Merge "Container spec: a clarification on background color." +fdb91779 Rename a method +5e967532 Container spec: a clarification on background color. +30e77d0f Merge branch '0.3.0' +1b631e29 alternate LUT-base reverse-bits code +24cc307a ~20% faster lossless decoding +313d853f Speedup for decoding lossless WebP photographs: +24ee098a change the bytes_per_pixels_ field into more evocative use_8b_decode +2a04b034 update ChangeLog (tag: v0.3.1-rc2, tag: v0.3.1) +7288950b Regression fix for alpha channels using color cache: +2e377b53 wicdec: silence a format warning +ad9e42a6 muxedit: silence some uninitialized warnings +3307c163 Don't set alpha-channel to 0xff for alpha->green uplift +5130770c Merge "wicdec: silence a format warning" +a37eff47 Regression fix for alpha channels using color cache: +241cf99b Merge "muxedit: silence some uninitialized warnings" +c8f9c84d Regression fix for alpha unfiltering: +14cd5c6c muxedit: silence some uninitialized warnings +a368db81 dec/vp8l: quiet vs9 x64 type conversion warning +ffae9f31 wicdec: silence a format warning +8cf0701e Alpha encoding: never filter in case of NO_COMPRESSION +825e73b1 update ChangeLog (tag: v0.3.1-rc1) +abf6f691 update NEWS +5a92c1a5 bump version to 0.3.1 +86daf77c store top Y/U/V samples in packed fashion +67bc353e Revert "add WebPBlendAlpha() function to blend colors against background" +068db59e Intertwined decoding of alpha and RGB +38cc0114 Simplify forward-WHT + SSE2 version +3fa595a5 Support decoding upto given row in DECODE_DATA_FUNC +520f005f DequantizeLevels(): Add 'row' and 'num_rows' args +47374b82 Alpha unfilter for given set of rows +f32097e0 probe input file and quick-check for WebP format. +a2aed1d0 configure: improve gl/glut library test +c7e89cbb update copyright text +a00380d2 configure: remove use of AS_VAR_APPEND +a94a88dd fix EXIF parsing in PNG +a71e5d84 add doc precision for WebPPictureCopy() and WebPPictureView() +8287012e remove datatype qualifier for vmnv +e1908430 fix a memory leak in gif2webp +0b18b9ee fix two minor memory leaks in webpmux +db5095d5 remove some cruft from swig/libwebp.jar +850e956f README: update swig notes +bddd9b0a swig/python: add minimal documentation +d573a8d5 swig: add python encode support +6b931875 swig/java: reduce wrapper function code duplication +6fe536f4 swig/java: rework uint8_t typemap +a2ea4643 Fix the bug in ApplyPalette. +7bb28d2a webp/lossless: fix big endian BGRA output +f036d4bf Speed up ApplyPalette for ARGB pixels. +8112c8cf remove some warnings: +cc128e0b Further reduce memory to decode lossy+alpha images +07db70d2 fix for big-endian +eda8a7de gif2webp: Fix signed/unsigned comparison mismatch +31f346fe Makefile.vc: fix libwebpdemux dll variable typo +6c76d28e swig: add python (decode) support +b4f5bb6c swig: cosmetics +498d4dd6 WebP-Lossless encoding improvements. +26e72442 swig: ifdef some Java specific code +8ecec686 configure: add warning related flags +e676b043 configure: add GLUT detection; build vwebp +b0ffc437 Alpha decoding: significantly reduce memory usage +20aa7a8d configure: add --enable-everything +b8307cc0 configure.ac: add some helper macros +980e7ae9 Remove the gcc compilation comments +7f25ff99 gif2webp: Fix ICC and XMP support +d8e53211 Add missing name to AUTHORS +11edf5e2 Demux: Fix a potential memleak +c7b92184 don't forward declare enums +7a650c6a prevent signed int overflow in left shift ops +31bea324 add precision about dynamic output reallocation with IDecoder +c22877f7 Add incremental support for extended format files +5051245f Makefile.vc: have 'all' target build everything +8191deca Makefile.vc: flags cleanup +b9d74735 Makefile.vc: drop /FD flag +5568dbcf update gitignore +f4c7b654 WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded. +1fb04bec pngdec: Avoid a double-free. +dcbb1ca5 add WebPBlendAlpha() function to blend colors against background +bc9f5fbe configure.ac: add AM_PROG_AR for automake >= 1.12 +bf867bf2 Tuned cross_color parameter (step) for lower qual +90e2ec5a Merge "probe input file and quick-check for WebP format." +7180d7ff Merge "update copyright text" +830f72b7 probe input file and quick-check for WebP format. +2ccf58d6 configure: improve gl/glut library test +d640614d update copyright text +c2113ad4 Merge "configure: remove use of AS_VAR_APPEND" +9326a56f configure: remove use of AS_VAR_APPEND +ea63d619 fix a type warning on VS9 x86 +bec11092 fix EXIF parsing in PNG +b6e65f3d Merge "fix warnings for vs9 x64" +438946dc fix warnings for vs9 x64 +f4710e3b collect macroblock reconstruction data in VP8MBData struct +23d28e21 add doc precision for WebPPictureCopy() and WebPPictureView() +518f2cd7 cosmetics: gif2webp: fix indent +af358e68 Merge "remove datatype qualifier for vmnv" +3fe91635 remove datatype qualifier for vmnv +764fdffa fix a memory leak in gif2webp +3e59a74d fix two minor memory leaks in webpmux +47b9862f Merge "README: update swig notes" +325d15ff remove some cruft from swig/libwebp.jar +4a7627c2 README: update swig notes +5da81e33 Merge "swig/python: add minimal documentation" +f39e08f2 Merge "swig: add python encode support" +6ca4a3e3 Merge "swig/java: reduce wrapper function code duplication" +8f8702b0 Merge "swig/java: rework uint8_t typemap" +91413be2 reduce memory for VP8MB and remove bitfields use +7413394e Fix the memory leak in ApplyFilters. +2053c2cf simplify the alpha-filter testing loop +825b64db swig/python: add minimal documentation +14677e11 swig: add python encode support +a5c297c8 swig/java: reduce wrapper function code duplication +ad4a367d swig/java: rework uint8_t typemap +0d25876b use uint8_t for inv_palette[] +afa3450c Fix the bug in ApplyPalette. +2d6ac422 Merge "webp/lossless: fix big endian BGRA output" +2ca83968 webp/lossless: fix big endian BGRA output +742110cc Speed up ApplyPalette for ARGB pixels. +2451e47d misc code cleanup +83db4043 Merge "swig: add python (decode) support" +eeeea8b5 Merge "swig: cosmetics" +d5f9b8f3 Merge "libwebp: fix vp8 encoder mem alloc offsetting" +d8edd835 libwebp: fix vp8 encoder mem alloc offsetting +8983b83e remove use of bit-fields in VP8FInfo +87a4fca2 remove some warnings: +ba8f74e2 Merge "fix for big-endian" +a65067fa Merge "Further reduce memory to decode lossy+alpha images" +64c84486 Further reduce memory to decode lossy+alpha images +332130b9 Mux: make a few methods static +44370617 fix for big-endian +5199eab5 Merge "add uncompressed TIFF output support" +a3aede97 add uncompressed TIFF output support +f975b67f Merge "gif2webp: Fix signed/unsigned comparison mismatch" +5fbc734b Merge "GetFeatures: Detect invalid VP8X/VP8/VP8L data" +d5060c87 Merge "mux.h: A comment fix + some consistency fixes" +352d0dee GetFeatures: Detect invalid VP8X/VP8/VP8L data +3ef79fef Cosmetic: "width * height" +043e1ae4 gif2webp: Fix signed/unsigned comparison mismatch +5818cff7 mux.h: A comment fix + some consistency fixes +1153f888 Merge "swig: ifdef some Java specific code" +3eeedae1 Makefile.vc: fix libwebpdemux dll variable typo +f980faf4 swig: add python (decode) support +7f5f42bb swig: cosmetics +8eae188a WebP-Lossless encoding improvements. +c7247c4c swig: ifdef some Java specific code +4cb234d5 Merge "Mux: make ValidateForSingleImage() method static" +ed6f5308 Merge "Add GetCanvasSize() method to mux" +1d530c9a Mux: make ValidateForSingleImage() method static +bba4c2b2 configure: add warning related flags +fffefd18 Add GetCanvasSize() method to mux +732da8d0 Merge "configure: add GLUT detection; build vwebp" +0e513f7a configure: add GLUT detection; build vwebp +55d1c150 Merge "Alpha decoding: significantly reduce memory usage" +13d99fb5 Merge "configure: add --enable-everything" +2bf698fe Merge "configure.ac: add some helper macros" +edccd194 Alpha decoding: significantly reduce memory usage +3cafcc9a configure: add --enable-everything +4ef14477 configure.ac: add some helper macros +a4e1cdbb Remove the gcc compilation comments +6393fe4b Cosmetic fixes +9c4ce971 Simplify forward-WHT + SSE2 version +878b9da5 fix missed optim +00046171 VP8GetInfo(): Check for zero width or height. +9bf31293 align VP8Encoder::nz_ allocation +5da165cf fix CheckMode() signature +0ece07dc Merge "explicitly pad bitfields to 32-bits" +9dbc9d19 explicitly pad bitfields to 32-bits +5369a80f Merge "prevent signed int overflow in left shift ops" +70e39712 Merge "cosmetics: remove unnecessary ';'s" +d3136ce2 Merge "don't forward declare enums" +b26e5ad5 gif2webp: Fix ICC and XMP support +46089b20 Add missing name to AUTHORS +94328d64 Demux: Fix a potential memleak +96e948d7 don't forward declare enums +f4f90880 prevent signed int overflow in left shift ops +0261545e cosmetics: remove unnecessary ';'s +7ebdf110 Merge "Fix few missing comparisons to NULL" +1579989e Fix few missing comparisons to NULL +ea1b21cf Cleaned up VP8GetHeaders() so that it parses only frame header +b66caee4 dwebp: add support for BMP output +ff885bfe add precision about dynamic output reallocation with IDecoder +79241d5a Merge "Makefile.vc: have 'all' target build everything" +ac1c729b Merge "Makefile.vc: flags cleanup" +118a055c Merge "Makefile.vc: drop /FD flag" +ecad0109 Merge "update gitignore" +a681b4f4 Rename PRE_VP8 state to WEBP_HEADER +ead4d478 Add incremental support for extended format files +69d0f926 Makefile.vc: have 'all' target build everything +52967498 Makefile.vc: flags cleanup +c61baf0c Makefile.vc: drop /FD flag +3a15125d update gitignore +5167ca47 Merge "WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded." +67708d67 WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded. +b68912af pngdec: Avoid a double-free. +82abbe12 Merge "configure.ac: add AM_PROG_AR for automake >= 1.12" +e7d9548c add WebPBlendAlpha() function to blend colors against background +ed4dc717 configure.ac: add AM_PROG_AR for automake >= 1.12 +df4a406d Merge branch '0.3.0' +1e0d4b8c Update ChangeLog (tag: v0.3.0-rc7, tag: v0.3.0) +d52b405d Cosmetic fixes +6cb4a618 misc style fix +68111ab0 add missing YUVA->ARGB automatic conversion in WebPEncode() +e9a7990b Cosmetic fixes +403bfe82 Container spec: Clarify frame disposal +2aaa423b Merge "add missing YUVA->ARGB automatic conversion in WebPEncode()" +07d87bda add missing YUVA->ARGB automatic conversion in WebPEncode() +142c4629 misc style fix +3e7a13a0 Merge "Container spec: clarify the background color field" into 0.3.0 +14af7745 container doc: add a note about the 'ANMF' payload +cc635efa Container spec: clarify the background color field +e3e33949 container doc: move RIFF description to own section +4299f398 libwebp/mux: fix double free +33f9a692 Merge "demux: keep a frame tail pointer; used in AddFrame" into 0.3.0 +a2a7b959 use WebPDataCopy() instead of re-coding it. +6f18f12f demux: keep a frame tail pointer; used in AddFrame +e5af49e9 add doc precision about WebPParseHeaders() return codes +db46daab Merge "Makefile.vc: fix dynamic builds" into 0.3.0 +53c77afc Merge "gif2webp: Bgcolor fix for a special case" into 0.3.0 +a5ebd143 gif2webp: Bgcolor fix for a special case +6378f238 Merge "vwebp/animation: fix background dispose" into 0.3.0 +3c8eb9a8 fix bad saturation order in QuantizeBlock +04c7a2ec vwebp/animation: fix background dispose +81a50695 Makefile.vc: fix dynamic builds +5f25c396 update ChangeLog (tag: v0.3.0-rc6) +14d42af2 examples: don't use C99 %zu +5ccf1fe5 update ChangeLog +2560c243 update NEWS +f43bafc3 Merge changes Iecccb09c,If5ee9fd2,I3e181ce4 into 0.3.0 +a788644f dwebp: warn when decoding animated webp's +302efcdb Decode: return more meaningful error for animation +ad452735 WebPBitstreamFeatures: add has_animation field +783dfa49 disable FRGM decoding for good in libwebpmux +4b956be0 Update ChangeLog +ad8b86d7 update NEWS +3e084f63 Merge "demux cosmetics: comments/rename internal function" into 0.3.0 +d3f8c621 Merge "move WebPFeatureFlags declaration" into 0.3.0 +7386fe50 Merge "libwebp{demux,mux}: install mux_types.h" into 0.3.0 +d6cd4e90 Merge "bump decode abi" into 0.3.0 +17f8da5c bump decode abi +97684ae2 Merge "add doc precision about WebPDemuxPartial()" into 0.3.0 +f933fd2a move WebPFeatureFlags declaration +289bc47b libwebp{demux,mux}: install mux_types.h +224e8d46 add doc precision about WebPDemuxPartial() +4c18e80c demux cosmetics: comments/rename internal function +7cfd1bf1 update AUTHORS +401f7b85 Merge "speed-up lossless (~3%) with ad-hoc histogram cost evaluation" into 0.3.0 +1fc8ffca Merge "makefile.unix: dist related changes" into 0.3.0 +8a89c6ed Merge changes I466c377f,Ib761ebd3,I694857fc into 0.3.0 +f4ffb2d5 speed-up lossless (~3%) with ad-hoc histogram cost evaluation +723847d5 gif2webp: only write error messages to stderr +701b9e2a makefile.unix: dist related changes +bb85b437 Merge "update NEWS" into 0.3.0 +59423a24 gif2webp: fix crash on open failure with libgif5 +9acb17de gif2webp: silence a unused param warning +7d9fdc23 Merge "README updates" into 0.3.0 +5621934e Merge "build: fix install race on shared headers" into 0.3.0 +70809d89 Merge "bump version to 0.3.0" into 0.3.0 +d851cd1d demux: make the parse a bit more strict +28bb4107 update NEWS +cef93882 bump version to 0.3.0 +9048494d build: fix install race on shared headers +1e67e8ef README updates +42b611a4 Merge "configure: drop experimental from mux/demux" into 0.3.0 +096a8e32 Merge "vwebp: add color profile support" into 0.3.0 +ddfee5dc vwebp: add color profile support +0d6927d3 Merge "Mark fragment options as experimental in webpmux" into 0.3.0 +5dbd4030 Mark fragment options as experimental in webpmux +a0a6648c configure: drop experimental from mux/demux +ee65bad8 Merge "add support for BITS > 32" into 0.3.0 +744930db add support for BITS > 32 +7dd288f0 cwebp: fix build +19a8dd01 Merge "Makefile.vc: add vwebp.exe target" into 0.3.0 +50eeddad Merge "examples: normalize icc related program arguments" into 0.3.0 +757f637f Merge "Makefile.vc: add libwebpdecoder target" into 0.3.0 +b65c4b7c Makefile.vc: add libwebpdecoder target +f8db7b4a Merge "vwebp: replace doubles w/floats where appropriate" into 0.3.0 +d99aa56f Makefile.vc: add vwebp.exe target +013023e7 vwebp: replace doubles w/floats where appropriate +9b3db894 README.mux: add version reference +7b6a26cf Merge "cwebp: output metadata statistics" into 0.3.0 +d8dc72a0 examples: normalize icc related program arguments +7bfc9056 Merge "make alpha unfilter work in-place" into 0.3.0 +0037b2d2 Merge "add LUT-free reference code for YUV->RGB conversion." into 0.3.0 +166bf744 Merge "demux: disable fragment parsing" into 0.3.0 +126974b4 add LUT-free reference code for YUV->RGB conversion. +0aef3ebd make alpha unfilter work in-place +14ef5005 Merge "Remove 'status: experimental' from container spec" into 0.3.0 +d40c98e1 Merge "webpmux binary: tiny style fix" into 0.3.0 +0bc42689 cwebp: output metadata statistics +bc039803 Merge "autoconf: normalize experimental define" into 0.3.0 +d1e21b13 Remove 'status: experimental' from container spec +7681bb96 webpmux binary: tiny style fix +a3dd3d0f avoid installing example_util.h +252320e2 demux: disable fragment parsing +537bde05 autoconf: normalize experimental define +5e338e0b Merge changes I33e8a613,I8e8a7b44 into 0.3.0 +d9d0ea1b Merge changes If21e3ec7,I991fc30b into 0.3.0 +627f5ca6 automake: add reference to libwebp for mux/demux +eef73d07 don't consolidate proba stats too often +05ec4cc2 libwebp{,decoder}.pc: add pthread flags +1bfcf5bf add libwebpmux.pc +26ca843d add libwebpdemux.pc +69e25906 Merge "Tune Lossless compression for lower qualities." +0478b5d2 Tune Lossless compression for lower qualities. +39f7586f add a mention of parallel alpha encoding in the NEWS +5a21d967 Merge "1.5x-2x faster encoding for method 3 and up" +9bfbdd14 1.5x-2x faster encoding for method 3 and up +27dc741b Correct frame options order in README.mux +be2fd173 Mux: fix a scenario with bad ANMF/FRGM size +19eb012c Merge "Demux: Add option to get frame count using GetI()" +7368b8cb Merge "WebPGetFeatures() out of if condition for clarity." +f604c9a4 Merge "fix windows build" +153f94e8 fix windows build +847b4924 Merge "vwebp: use magenta for 'i'nfo display" +25ea46bd Merge "vwebp: add keyboard shortcuts to help output" +bea7ccaf vwebp: use magenta for 'i'nfo display +8fab161a webpmux: correct -frame param order in help output +03cc23d6 vwebp: add keyboard shortcuts to help output +068eba8d Demux: Add option to get frame count using GetI() +988b8f56 WebPGetFeatures() out of if condition for clarity. +6933d910 Merge "gif2webp: Be lenient about background color index." +4d0f7c55 Merge "WebPGetFeatures() behavior change:" +fdeeb01d gif2webp: Be lenient about background color index. +ad250320 Merge "multi-threaded alpha encoding for lossy" +4e32d3e1 Merge "fix compilation of token.c" +f817930a multi-threaded alpha encoding for lossy +88050351 fix compilation of token.c +fc816219 code using the actual values for num_parts_, not the ones from config +72655350 Merge "move the config check from .c to .h" +dd9e76f7 move the config check from .c to .h +956b217a WebPGetFeatures() behavior change: +df02e4ce WebPDemuxGetI behavior change: +633c004d Merge "rebalance method tools (-m) for methods [0..4]" +58ca6f65 rebalance method tools (-m) for methods [0..4] +7648c3cc Merge "describe rd-opt levels introduce VP8RDLevel enum" +67fb1003 Merge "autoconf: enable silent-rules by default" +a5042a32 GetVersion() methods for mux and demux +5189957e describe rd-opt levels introduce VP8RDLevel enum +4e094ace autoconf: enable silent-rules by default +b7eaa85d inline VP8LFastLog2() and VP8LFastSLog2 for small values +5cf7792e split quant_levels.c into decoder and encoder version +e5d3ffe2 Merge "Update code example in README.mux" +ac5a9156 Update code example in README.mux +38a91e99 Add example code snippet for demux API +5f557f3c README.mux: add info about Demux API and vwebp +c0ba0903 backward_references: avoid signed integer overflow +943386db disable SSE2 for now +9479fb7d lossless encoding speedup +ec2030a8 merge two lines together +b67956c0 Merge "Remove ReadOneBit() and ReadSymbolUnsafe()" +1667bded Remove ReadOneBit() and ReadSymbolUnsafe() +3151669b wicdec + dwebp cosmetics: normalize formatting +92668da6 change default filtering parameters: * type is now 'strong' * strength is now '60' +b7490f85 introduce WEBP_REFERENCE_IMPLEMENTATION compile option +33838857 faster decoding (3%-6%) +5c3e381b Merge "add a -jpeg_like option" +c2311046 remove unused declaration of VP8Zigzag +36152957 Merge "wicdec: add alpha support for paletted formats" +c9f16490 wicdec: add alpha support for paletted formats +1262f81e Merge "wicdec: silence some warnings" +e7ea61eb wicdec: silence some warnings +23c0f354 fix missing intptr_t->int cast for MSVC +e895059a add a -jpeg_like option +1f803f64 Merge "Tune alpha quality mapping to more reasonable values." +1267d498 Tune alpha quality mapping to more reasonable values. +043076e2 Merge "speed-up lossless in BackwardTrace" +f3a44dcd remove one malloc from TraceBackwards() +0fc1a3a0 speed-up lossless in BackwardTrace +7c732e59 cwebp: centralize WebPCleanupTransparentArea() +7381254e Merge "wicdec: add ICC profile extraction" +e83ff7de wicdec: add ICC profile extraction +146c6e3b Merge "cosmetics: pngdec: normalize default label location" +a8f549d7 Merge "manpages: italicize option parameters" +e118db83 Merge "encode.h: note the need to free() WebPMemoryWriter" +1dfee6db cosmetics: pngdec: normalize default label location +14c38200 manpages: italicize option parameters +7defbfad encode.h: note the need to free() WebPMemoryWriter +88d382a0 cwebp: cleanup after memory_writer +12d6cecf fix extra space in dwebp.1 man +b01681a9 Fix for demuxer frame iteration: +56c12aa6 Demuxer creation fix: +66c810bc add a -yuv option to dwebp (very similar to -pgm) +841a3ba5 Merge "Remove -Wshadow warnings." +8fd02527 Merge "upsampling_neon.c: fix build" +6efed268 Remove -Wshadow warnings. +60904aa6 Merge "allow WebPINewRGB/YUVA to be passed a NULL output buffer." +b7adf376 allow WebPINewRGB/YUVA to be passed a NULL output buffer. +27f8f742 upsampling_neon.c: fix build +06b9cdf1 gitignore: add IOS related directories +f112221e Merge "Fix more comments for iobuild.sh" +fe4d25dd Fix more comments for iobuild.sh +1de3e252 Merge "NEON optimised yuv to rgb conversion" +090b708a NEON optimised yuv to rgb conversion +daa06476 Merge "Add ios build script for building iOS library." +79fe39e2 Add ios build script for building iOS library. +126c035f remove some more -Wshadow warnings +522e9d61 Merge "cwebp: enable '-metadata'" +76ec5fa1 cwebp: enable '-metadata' +aeb91a9d Merge "cosmetics: break a few long lines" +be7c96b0 cosmetics: break a few long lines +cff8ddb6 Merge "add libwebpdecoder.pc" +93148ab8 Merge "libwebp.pc.in: detab" +6477f955 Merge "Makefile.vc: normalize path separator" +bed1ed7c add libwebpdecoder.pc +46168b2d libwebp.pc.in: detab +a941a346 Fixed few nits in the build files. +dd7a49b2 Makefile.vc: normalize path separator +9161be86 Merge "cwebp: extract WIC decoding to its own module" +08e7c58e Merge "Provide an option to build decoder library." +0aeba528 Provide an option to build decoder library. +757ebcb1 catch malloc(0)/calloc(0) with an assert +152ec3d2 Merge "handle malloc(0) and calloc(0) uniformly on all platforms" +a452a555 cwebp: extract WIC decoding to its own module +2b252a53 Merge "Provide option to swap bytes for 16 bit colormodes" +94a48b4b Provide option to swap bytes for 16 bit colormodes +42f8f934 handle malloc(0) and calloc(0) uniformly on all platforms +8b2152c5 Merge "add an extra assert to check memory bounds" +0d19fbff remove some -Wshadow warnings +cd22f655 add an extra assert to check memory bounds +8189feda Merge "Add details and reference about the YUV->RGB conversion" +1d2702b1 Merge "Formatting fixes in lossless bitstream spec" +8425aaee Formatting fixes in lossless bitstream spec +a556cb1a Add details and reference about the YUV->RGB conversion +d8f21e0b add link to SSIM description on Wikipedia +18e9167e Merge "WebP-lossless spec clarifications:" +98e25b9b Merge "cwebp: add -metadata option" +f01c2a53 WebP-lossless spec clarifications: +f4a97970 Merge "Disto4x4 and Disto16x16 in NEON" +47b7b0ba Disto4x4 and Disto16x16 in NEON +7eaee9f1 cwebp: add -metadata option +36c52c2c tiffdec: use toff_t for exif ifd offset +7c8111e4 Merge "cwebp/tiffdec: add TIFF metadata extraction" +e6409adc Remove redundant include from dsp/lossless code. +1ab5b3a7 Merge "configure: fix --with-gifincludedir" +03c749eb configure: fix --with-gifincludedir +8b650635 multiple libgif versions support for gif2webp +476e293f gif2webp: Use DGifOpenFileName() +b50f277b tiffdec: correct format string +2b9048e3 Merge "tiffdec: check error returns for width/height" +a1b5a9a3 Merge "cwebp/tiff: use the first image directory" +079423f5 tiffdec: check error returns for width/height +d62824af Merge "cwebp/jpegdec: add JPEG metadata extraction" +03afaca4 Merge "cwebp: add PNG metadata extraction" +2c724968 cwebp/jpegdec: add JPEG metadata extraction +dba64d91 cwebp: add PNG metadata extraction +1f075f89 Lossless spec corrections/rewording/clarifications +2914ecfd cwebp/tiffdec: add TIFF metadata extraction +d82a3e33 More corrections/clarifications in lossless spec: +bd002557 cwebp/tiff: use the first image directory +df7aa076 Merge "Cleanup around jpegdec" +0f57dcc3 decoding speed-up (~1%) +bcec339b Lossless bitstream clarification: +6bf20874 add examples/metadata.c +207f89c0 Merge "configure: add libwebpdemux status to summary" +1bd287a6 Cleanup around jpegdec +91455679 Merge "cosmetics: use '== 0' in size checks" +d6b88b76 cosmetics: use '== 0' in size checks +d3dace2f cosmetics: jpegdec +2f69af73 configure: add libwebpdemux status to summary +1c1c5646 cwebp: extract tiff decoding to its own module +6a871d66 cwebp: extract jpeg decoding to its own module +2ee228f9 cwebp: extract png decoding to its own module +4679db00 Merge "cwebp: add metadata framework" +63aba3ae cwebp: add metadata framework +931bd516 lossless bitstream: block size bits correction +e4fc4c1c lossless bitstream: block size bits correction +d65ec678 fix build, move token.c to src/enc/ +657f5c91 move token buffer to its own file (token.c) +c34a3758 introduce GetLargeValue() to slim-fast GetCoeffs(). +d5838cd5 faster non-transposing SSE2 4x4 FTransform +f76191f9 speed up GetResidualCost() +ba2aa0fd Add support for BITS=24 case +2e7f6e8e makefile.unix: Dependency on libraries +dca84219 Merge "Separate out mux and demux code and libraries:" +23782f95 Separate out mux and demux code and libraries: +bd56a01f configure: add summary output +90e5e319 dwebp manual: point to webpmux, gif2webp. +540790ca gif2webp.c: add a note about prerequisites +d1edf697 cwebp man page: meaning of '-q' for lossy/lossless +79efa1d0 Add man page for gif2webp utility +2243e40c Merge "gif2webp build support with autoconf tools" +c40efca1 gif2webp build support with autoconf tools +6523e2d4 WebP Container: +4da788da Merge "simplify the fwd transform" +42c3b550 simplify the fwd transform +41a6ced9 user GLfloat instead of float +b5426119 fix indentation +68f282f7 * handle offset in anim viewer 'vwebp' * fix gif2webp to handle disposal method and odd offset correctly +118cb312 Merge "add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case" +8a7c3cc8 Merge "Change the order of -frame argument to be more natural" +99e0a707 Merge "Simplify the texture evaluation Disto4x4()" +0f923c3f make the bundling work in a tmp buffer +e5c3b3f5 Simplify the texture evaluation Disto4x4() +48600084 Change the order of -frame argument to be more natural +35bfd4c0 add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case +a7305c2e Clarification for unknown chunks +4c4398e2 Refine WebP Container Spec wrt unknown chunks. +2ca642e0 Rectify WebPMuxGetFeatures: +7caab1d8 Some cosmetic/comment fixes. +60b2651a Merge "Write a GIF to WebP converter based on libgif." +c7127a4d Merge "Add NEON version of FTransformWHT" +11b27212 Write a GIF to WebP converter based on libgif. +e9a15a37 ExUtilWriteFile() to write memory segment to file +74356eb5 Add a simple cleanup step in mux assembly: +51bb1e5d mux.h: correct WebPDemuxSelectFragment() prototype +22a0fd9d Add NEON version of FTransformWHT +fa30c863 Update mux code to match the spec wrt animation +d9c5fbef by-pass Analysis pass in case segments=1 +d2ad4450 Merge changes Ibeccffc3,Id1585b16 +5c8be251 Merge "Chunk fourCCs for XMP/EXIF" +a00a3daf Use 'frgm' instead of 'tile' in webpmux parameters +81b8a741 Design change in ANMF and FRGM chunks: +f903cbab Chunk fourCCs for XMP/EXIF +812933d6 Tune performance of HistogramCombine +52ad1979 Animation specification in container spec +001b9302 Image fragment specification in container spec +391f9db9 Ordering of description of bits in container spec +d5735776 Metadata specification in container spec +1c4609b1 Merge commit 'v0.2.1' +0ca584cb Merge "Color profile specification in container spec" +e8b41ad1 add NEON asm version for WHT inverse transform +af6f0db2 Color profile specification in container spec +a61a824b Merge "Add NULL check in chunk APIs" +0e8b7eed fix WebPPictureView() unassigned strides +75e5f17e ARM/NEON: 30% encoding speed-up +02b43568 Add NULL check in chunk APIs +a0770727 mux struct naming +6c66dde8 Merge "Tune Lossless encoder" +ab5ea217 Tune Lossless encoder +74fefc8c Update ChangeLog (tag: v0.2.1, origin/0.2.0, 0.2.0) +92f8059c Rename some chunks: +3bb4bbeb Merge "Mux API change:" +d0c79f05 Mux API change: +abc06044 Merge "update NEWS" into 0.2.0 +57cf313b update NEWS +25f585c4 bump version to 0.2.1 +fed7c048 libwebp: validate chunk size in ParseOptionalChunks +552cd9bc cwebp (windows): fix alpha image import on XP +b14fea99 autoconf/libwebp: enable dll builds for mingw +4a8fb272 [cd]webp: always output windows errors +d6621580 fix double to float conversion warning +72b96a69 cwebp: fix jpg encodes on XP +734f762a VP8LAllocateHistogramSet: fix overflow in size calculation +f9cb58fb GetHistoBits: fix integer overflow +b30add20 EncodeImageInternal: fix uninitialized free +3de58d77 fix the -g/O3 discrepancy for 32bit compile +77aa7d50 fix the BITS=8 case +e5970bda Make *InitSSE2() functions be empty on non-SSE2 platform +ef5cc47e make *InitSSE2() functions be empty on non-SSE2 platform +c4ea259d make VP8DspInitNEON() public +8344eadf Merge "libwebp: validate chunk size in ParseOptionalChunks" +4828bb93 Merge "cwebp (windows): fix alpha image import on XP" +30763333 libwebp: validate chunk size in ParseOptionalChunks +70481898 AccumulateLSIM: fix double -> float warnings +eda8ee4b cwebp (windows): fix alpha image import on XP +c6e98658 Merge "add EXPERIMENTAL code for YUV-JPEG colorspace" +f0360b4f add EXPERIMENTAL code for YUV-JPEG colorspace +f86e6abe add LSIM metric to WebPPictureDistortion() +c3aa215a Speed up HistogramCombine for lower qualities. +1765cb1c Merge "autoconf/libwebp: enable dll builds for mingw" +a13562e8 autoconf/libwebp: enable dll builds for mingw +9f469b57 typo: no_fancy -> no_fancy_upsampling +1a27f2f8 Merge "fix double to float conversion warning" +cf1e90de Merge "cwebp: fix jpg encodes on XP" +f2b5d19b [cd]webp: always output windows errors +e855208c fix double to float conversion warning +ecd66f77 cwebp: fix jpg encodes on XP +7b3eb372 Tune lossless compression to get better gains. +ce8bff45 Merge "VP8LAllocateHistogramSet: fix overflow in size calculation" +ab5b67a1 Merge "EncodeImageInternal: fix uninitialized free" +7fee5d12 Merge "GetHistoBits: fix integer overflow" +a6ae04d4 VP8LAllocateHistogramSet: fix overflow in size calculation +80237c43 GetHistoBits: fix integer overflow +8a997235 EncodeImageInternal: fix uninitialized free +0b9e6829 minor cosmetics +a792b913 fix the -g/O3 discrepancy for 32bit compile +73ba4357 Merge "detect and merge similar segments" +fee66275 detect and merge similar segments +0c44f415 src/webp/*.h: don't forward declare enums in C++ +d7a5ac86 vwebp: use demux interface +931e0ea1 Merge "replace 'typedef struct {} X;" by "typedef struct X X; struct X {};"" +8f216f7e remove cases of equal comparison for qsort() +28d25c82 replace 'typedef struct {} X;" by "typedef struct X X; struct X {};" +2afee60a speed up for ARM using 8bit for boolean decoder +5725caba new segmentation algorithm +2cf1f815 Merge "fix the BITS=8 case" +12f78aec fix the BITS=8 case +6920c71f fix MSVC warnings regarding implicit uint64 to uint32 conversions +f6c096aa webpmux binary: Rename 'xmp' option to 'meta' +ddfe871a webpmux help correction +b7c55442 Merge "Make *InitSSE2() functions be empty on non-SSE2 platform" +1c04a0d4 Common APIs for chunks metadata and color profile. +2a3117a1 Merge "Create WebPMuxFrameInfo struct for Mux APIs" +5c3a7231 Make *InitSSE2() functions be empty on non-SSE2 platform +7c6e60f4 make *InitSSE2() functions be empty on non-SSE2 platform +c7eb4576 make VP8DspInitNEON() public +ab3234ae Create WebPMuxFrameInfo struct for Mux APIs +e3990fd8 Alignment fixes +e55fbd6d Merge branch '0.2.0' +4238bc0a Update ChangeLog (tag: v0.2.0) +c655380c dec/io.c: cosmetics +fe1958f1 RGBA4444: harmonize lossless/lossy alpha values +681cb30a fix RGBA4444 output w/fancy upsampling +f06c1d8f Merge "Alignment fix" into 0.2.0 +f56e98fd Alignment fix +6fe843ba avoid rgb-premultiply if there's only trivial alpha values +528a11af fix the ARGB4444 premultiply arithmetic +a0a48855 Lossless decoder fix for a special transform order +62dd9bb2 Update encoding heuristic w.r.t palette colors. +6f4272b0 remove unused ApplyInverseTransform() +93bf0faa Update ChangeLog (tag: v0.2.0-rc1) +5934fc59 update AUTHORS +014a711d update NEWS +43b0d610 add support for ARGB -> YUVA conversion for lossless decoder +33705ca0 bump version to 0.2.0 +c40d7ef1 fix alpha-plane check + add extra checks +a06f8023 MODE_YUVA: set alpha to opaque if the image has none +52a87dd7 Merge "silence one more warning" into 0.2.0 +3b023093 silence one more warning +f94b04f0 move some RGB->YUV functions to yuv.h +4b71ba03 README: sync [cd]webp help output +c9ae57f5 man/dwebp.1: add links to output file format details +292ec5cc quiet a few 'uninitialized' warnings +4af3f6c4 fix indentation +9b261bf5 remove the last NOT_HAVE_LOG2 instances +323dc4d9 remove use of log2(). Use VP8LFastLog2() instead. +8c515d54 Merge "harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc" into 0.2.0 +d4b4bb02 Merge changes I46090628,I1a41b2ce into 0.2.0 +bff34ac1 harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc +a3c063c7 Merge "extra size check for security" into 0.2.0 +5e796300 Merge "WebPEncode: clear stats at the start of encode" into 0.2.0 +f1edf62f Merge "rationalize use of color-cache" into 0.2.0 +c1933317 extra size check for security +906be657 rationalize use of color-cache +dd1c3873 Add image-hint for low-color images. +4eb7aa64 Merge "WebPCheckMalloc() and WebPCheckCalloc():" into 0.2.0 +80cc7303 WebPCheckMalloc() and WebPCheckCalloc(): +183cba83 check VP8LBitWriterInit return +cbfa9eec lossless: fix crash on user abort +256afefa cwebp: exit immediately on version mismatch +475d87d7 WebPEncode: clear stats at the start of encode +a7cc7291 fix type and conversion warnings +7d853d79 add stats for lossless +d39177b7 make QuantizeLevels() store the sum of squared error +5955cf5e replace x*155/100 by x*101581>>16 +7d732f90 make QuantizeLevels() store the sum of squared error +e45a446a replace x*155/100 by x*101581>>16 +159b75d3 cwebp output size consistency: +cbee59eb Merge commit 'v0.1.99' +1889e9b6 dwebp: report -alpha option +3bc3f7c0 Merge "dwebp: add PAM output support" into 0.2.0 +d919ed06 dwebp: add PAM output support +85e215d3 README/manpages/configure: update website link +c3a207b9 Update ChangeLog (tag: v0.1.99) +d1fd7826 Merge "add extra precision about default values and behaviour" into 0.2.0 +efc826e0 add extra precision about default values and behaviour +9f29635d header/doc clean up +ff9fd1ba Makefile.vc: fix webpmux.exe *-dynamic builds +8aacc7b0 remove INAM, ICOP, ... chunks from the test webp file. +2fc13015 harmonize authors as "Name (mail@address)" +4a9f37b7 Merge "update NEWS" into 0.2.0 +7415ae13 makefile.unix: provide examples/webpmux target +ce82cedc update NEWS +641e28e8 Merge "man/cwebp.1: wording, change the date" into 0.2.0 +c37c23e5 README: cosmetics +3976dcd5 man/cwebp.1: wording, change the date +3e5bbe1c Merge "rename 'use_argb_input' to 'use_argb'" into 0.2.0 +ce90847a Merge "add some padding bytes areas for later use" into 0.2.0 +2390dabc Merge "fixing the findings by Frederic Kayser to the bitstream spec" into 0.2.0 +02751591 add a very crude progress report for lossless +a4b9b1c6 Remove some unused enum values. +dd108176 rename 'use_argb_input' to 'use_argb' +90516ae8 add some padding bytes areas for later use +d03b2503 fixing the findings by Frederic Kayser to the bitstream spec +ce156afc add missing ABI compatibility checks +9d45416a Merge "Doc: container spec text tweaks" into 0.2.0 +4e2e0a8c Doc: container spec text tweaks +f7f16a29 add ABI compatibility check +2a775570 Merge "swig: add WebPEncodeLossless* wrappers" into 0.2.0 +a3ec6225 mux.h: remove '* const' from function parameters +31426eba encode.h: remove '* const' from function parameters +9838e5d5 decode.h: remove '* const' from function parameters +4972302d swig: add WebPEncodeLossless* wrappers +9ff00cae bump encoder/decoder versions +c2416c9b add lossless quick encoding functions to the public API +4c1f5d64 Merge "NEWS: mention decode_vp8.h is no longer installed" into 0.2.0 +6cb2277d NEWS: mention decode_vp8.h is no longer installed +d5e5ad63 move decode_vp8.h from webp/ to dec/ +8d3b04a2 Merge "header clean-up" into 0.2.0 +02201c35 Merge "remove one malloc() by making color_cache non dynamic" into 0.2.0 +d708ec14 Merge "move MIN/MAX_HISTO_BITS to format_constants.h" into 0.2.0 +ab2da3e9 Merge "add a malloc() check" into 0.2.0 +2d571bd8 add a malloc() check +7f0c178e remove one malloc() by making color_cache non dynamic +6569cd7c Merge "VP8LFillBitWindow: use 64-bit path for msvc x64 builds" into 0.2.0 +23d34f31 header clean-up +2a3ab6f9 move MIN/MAX_HISTO_BITS to format_constants.h +985d3da6 Merge "shuffle variables in HashChainFindCopy" into 0.2.0 +cdf885c6 shuffle variables in HashChainFindCopy +c3b014db Android.mk: add missing lossless files +8c1cc6b5 makefile.unix dist: explicitly name installed includes +7f4647ee Merge "clarify the colorspace naming and byte ordering of decoded samples" into 0.2.0 +cbf69724 clarify the colorspace naming and byte ordering of decoded samples +857650c8 Mux: Add WebPDataInit() and remove WebPImageInfo +ff771e77 don't install webp/decode_vp8.h +596dff78 VP8LFillBitWindow: use 64-bit path for msvc x64 builds +3ca7ce98 Merge "doc: remove non-finalized chunk references" into 0.2.0 +1efaa5a3 Merge "bump versions" into 0.2.0 +51fa13e1 Merge "README: update cwebp help output" into 0.2.0 +12f9aede README: update cwebp help output +f0b5defb bump versions +4c42a61b update AUTHORS +6431a1ce doc: remove non-finalized chunk references +8130c4cc Merge "build: remove libwebpmux from default targets/config" +23b44438 Merge "configure: broaden test for libpng-config" +85bff2cd Merge "doc: correct lossless prefix coding table & code" +05108f6e Merge "More spec/code matching in mux:" +6808e69d More spec/code matching in mux: +bd2b46f5 Merge "doc/webp-container-spec: light cosmetics" +20ead329 doc/webp-container-spec: light cosmetics +1d40a8bc configure: add pthread detection +b5e9067a fix some int <-> size_t mix for buffer sizes +e41a7596 build: remove libwebpmux from default targets/config +0fc2baae configure: broaden test for libpng-config +45b8272c Merge "restore authorship to lossless bitstream doc" +06ba0590 restore authorship to lossless bitstream doc +44a09a3c add missing description of the alpha filtering methods +63db87dd Merge "vwebp: add checkboard background for alpha display" +a73b8978 vwebp: add checkboard background for alpha display +939158ce Merge "vwebp: fix info display" +b35c07d9 vwebp: fix info display +48b39eb1 fix underflow for very short bitstreams +7e622984 cosmetics: param alignment, manpage wording +1bd7dd50 Merge changes I7b0afb0d,I7ecc9708 +ac69e63e Merge "Updated cwebp man's help for Alpha & Lossless." +c0e8859d Get rid of image_info_ from WebPChunk struct. +135ca69e WebP Container Spec: +eb6f9b8a Updated cwebp man's help for Alpha & Lossless. +0fa844fb cosmetic fixes on assert and 'const' where applicable +7f22bd25 check limit of width * height is 32 bits +16c46e83 autoconf/make: cosmetics: break long lines +ab22a07a configure: add helper macro to define --with-* +c17699b3 configure: add libtiff test +0e09732c Merge "cwebp: fix crash with yuv input + lossless" +88a510ff Merge "fix big-endian VP8LWriteBits" +da99e3bf Merge "Makefile.vc: split mux into separate lib" +7bda392b cwebp: fix crash with yuv input + lossless +f56a369a fix big-endian VP8LWriteBits +54169d6c Merge "cwebp: name InputFileFormat members consistently" +e2feefa9 Makefile.vc: split mux into separate lib +27caa5aa Merge "cwebp: add basic TIFF support" +d8921dd4 cwebp: name InputFileFormat members consistently +6f76d246 cwebp: add basic TIFF support +4691407b Merge changes If39ab7f5,I3658b5ae +cca7c7b8 Fixed nit: 10 -> 10.f +5d09a244 WebPMuxCreate() error handling: +777341c3 Fix a memleak in WebPMuxCreate() +61c9d161 doc: correct lossless prefix coding table & code +4c397579 Merge "mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN" +e4e36cc6 Merge "Mux: Allow only some frames/tiles to have alpha." +ad2aad3c Merge "WebP Decoding error handling:" +97649c8f Mux: Allow only some frames/tiles to have alpha. +f864be3b Lower the quality settings for Alpha encoding. +3ba81bbe WebP Decoding error handling: +fcc69923 add automatic YUVA/ARGB conversion during WebPEncode() +802e012a fix compilation in non-FANCY_UPSAMPLING mode +e012dfd9 make width/height coding match the spec +228d96a5 mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN +637a314f remove the now unused *KeepA variants +d11f6fcc webpmux returns error strings rather than numbers +fcec0593 makefile.unix: cwebp: fix OSX link +6b811f1b Merge "doc: remove lossless pdf" +c9634821 doc: remove lossless pdf +b9ae4f0d cosmetics after mux changes b74ed6e, b494ad5 +b494ad50 Mux: only allow adding frame/tiles at the end. +2c341b0e Merge "Added image characteristic hint for the codec." +d373076a Added image characteristic hint for the codec. +2ed2adb5 Merge "msvc: add intrinsic based BitsLog2Floor" +e595e7c5 Merge "add demux.c to the makefiles" +da47b5bd Merge "demux: add {Next,Prev}Chunk" +e5f46742 add demux.c to the makefiles +4708393c demux: add {Next,Prev}Chunk +e8a0a821 demux: quiet msvc warnings +7f8472a6 Update the WebP Container Spec. +31b68fe6 cleanup WebPPicture struct and API +9144a186 add overflow check before calling malloc() +81720c91 consistency cosmetics +2ebe8394 Merge "Add kramdown version information to README" +71443084 enc/vp8l.c: fix build +b7ac19fe Add kramdown version information to README +efdcb667 Merge "Edit for consistency, usage and grammar." +08220102 Enable alpha in vvwebp +8de9a084 Merge "Mux API change:" +b74ed6e7 Mux API change: +233a589e take picture->argb_stride into account for lossless coding +04e33f17 Edit for consistency, usage and grammar. +a575b4bc Merge "cosmetics: add missing const" +8d99b0f4 Merge "cosmetics: remove unimplemented function proto" +69d02217 cosmetics: add missing const +5b08318b cosmetics: remove unimplemented function proto +b7fb0ed5 Log warning for unsupported options for lossless. +e1f769fe msvc: add intrinsic based BitsLog2Floor +8a69c7d8 Bug-fix: Clamp backward dist to 1. +b5b6ac97 Merge "Bring the special writer 'WebPMemoryWriter' to public API" +a6a1909f Merge "Fix floating point exception with cwebp -progress" +f2cee067 Fix floating point exception with cwebp -progress +91b7a8c7 Bring the special writer 'WebPMemoryWriter' to public API +310e2972 support resize and crop for RGBA input +a89835d3 Merge changes Ice662960,Ie8d7aa90,I2d996d5e,I01c04772 +ce614c0c Merge "dec/vp8: avoid setting decoder status twice" +900285da dec/vp8: avoid setting decoder status twice +8227adc8 Merge changes I6f02b0d0,I5cbc9c0a,I9dd9d4ed,Id684d2a1 +dcda59c1 Merge "demux: rename SetTile to SelectTile" +622ef12e demux: rename SetTile to SelectTile +81ebd375 Merge "demux: add {Next,Prev}Frame" +02dd37a2 demux: add {Next,Prev}Frame +4b79fa59 Merge "Limit the maximum size of huffman Image to 16MB." +9aa34b34 Manually number "chapters," as chapter numbers are used in the narrative. +2a4c6c29 Re-wrap at <= 72 columns +a45adc19 Apply inline emphasis and monospacing, per gdoc / PDF +91011206 Incorporate gdoc changes through 2012-06-08 +7a182487 Removed CodeRay syntax declarations ... +b3ec18c5 Provide for code-block syntax highlighting. +709d7702 Replace high ASCII artifacts (curly quotes, etc.). +930e8abb Lossless WebP doc largely ported to markdown text. +18cae37b msvc: silence some build warnings +b3923084 Limit the maximum size of huffman Image to 16MB. +f180df2a Merge "libwebp/demux: add Frame/Chunk iteration" +2bbe1c9a Merge "Enable lossless encoder code" +d0601b01 Merge changes I1d97a633,I81c59093 +78f3e345 Enable lossless encoder code +d974a9cc Merge "libwebp/demux: add simple format parsing" +26bf2232 Merge "libwebp: add WebPDemux stub functions" +2f666688 Merge "modify WebPParseHeaders to allow reuse by GetFeatures" +b402b1fb libwebp/demux: add Frame/Chunk iteration +ad9ada3b libwebp/demux: add WebPDemuxGetI +2f2d4d58 libwebp/demux: add extended format parsing +962dcef6 libwebp/demux: add simple format parsing +f8f94081 libwebp: add WebPDemux stub functions +fb47bb5c Merge "NumNamedElements() should take an enum param." +7c689805 Fix asserts in Palette and BackwardReference code. +fbdcb7ea NumNamedElements() should take an enum param. +fb4943bd modify WebPParseHeaders to allow reuse by GetFeatures +3697b5ce write an ad-hoc EncodeImageInternal variant +eaee9e79 Bug-Fix: Decode small (less than 32 bytes) images. +0bceae48 Merge "cwebp: fix alpha reporting in stats output" +0424b1ef Rebase default encoding settings. +c71ff9e3 cwebp: fix alpha reporting in stats output +e2ffe446 Merge "Stop indefinite recursion for Huffman Image." +70eb2bd6 Stop indefinite recursion for Huffman Image. +f3bab8eb Update vwebp +6d5c797c Remove support for partial files in Mux. +f1df5587 WebPMuxAssemble() returns WebPData*. +814a0639 Rename 'Add' APIs to 'Set'. +bbb0218f Update Mux psuedo-code examples. +4fc4a47f Use WebPData in MUX set APIs +c67bc979 Merge "add WebPPictureImportRGBX() and WebPPictureImportBGRX()" +27519bc2 add WebPPictureImportRGBX() and WebPPictureImportBGRX() +f80cd27e factorize code in Import() +9b715026 histogram: add log2 wrapper +8c34378f Merge "fix some implicit type conversion warnings" +42f6df9d fix some implicit type conversion warnings +250c16e3 Merge "doc: update lossless pdf" +9d9daba4 Merge "add a PDF of the lossless spec" +8fbb9188 prefer webp/types.h over stdint.h +0ca170c2 doc: update lossless pdf +0862ac6e add a PDF of the lossless spec +437999fb introduce a generic WebPPictureHasTransparency() function +d2b6c6c0 cosmetic fixes after Idaba281a +b4e6645c Merge "add colorspace for premultiplied alpha" +48f82757 add colorspace for premultiplied alpha +069f903a Change in lossless bit-stream. +5f7bb3f5 Merge "WebPReportProgress: use non-encoder specific params" +f18281ff WebPReportProgress: use non-encoder specific params +9ef32283 Add support for raw lossless bitstream in decoder. +7cbee29a Fix bug: InitIo reseting fancy_upsampling flag. +880fd98c vwebp: fix exit w/freeglut +1875d926 trap two unchecked error conditions +87b4a908 no need to have mux.h as noinst clause in enc/ +88f41ec6 doc: fix bit alignment in VP8X chunk +52f5a4ef Merge "fix bug with lossy-alpha output stride" +3bde22d7 fix bug with lossy-alpha output stride +42d61b6d update the spec for the lossy-alpha compression methods. +e75dc805 Move some more defines to format_constants.h +c13f6632 Move consts to internal header format_constants.h +7f2dfc92 use a bit-set transforms_seen_ instead of looping +18da1f53 modulate alpha-compression effort according to config.method +f5f2fff6 Merge "Alpha flag fix for lossless." +c975c44e Alpha flag fix for lossless. +4f067fb2 Merge "Android: only build dec_neon with NEON support" +255c66b4 Android: only build dec_neon with NEON support +8f9117a9 cosmetics: signature fixes +39bf5d64 use header-less lossless bitstream for alpha channel +75d7f3b2 Merge "make input data be 'const' for VP8LInverseTransform()" +9a721c6d make input data be 'const' for VP8LInverseTransform() +9fc64edc Disallow re-use of same transformation. +98ec717f use a function pointer for ProcessRows() +f7ae5e37 cosmetics: join line +140b89a3 factor out buffer alloc in AllocateARGBBuffers() +a107dfa8 Rectify WebPParseOptionalChunks(). +237eab67 Add two more color-spaces for lossless decoding. +27f417ab fix orthographic typo +489ec335 add VP8LEncodeStream() to compress lossless image stream +fa8bc3db make WebPEncodingSetError() take a const picture +638528cd bitstream update for lossy alpha compression +d73e63a7 add DequantizeLevels() placeholder +ec122e09 remove arch-dependent rand() +d40e7653 fix alignment +1dd6a8b6 Merge "remove tcoder, switch alpha-plane compression to lossless" +3e863dda remove tcoder, switch alpha-plane compression to lossless +8d77dc29 Add support for lossless in mux: +831bd131 Make tile size a function of encoding method. +778c5228 Merge "remove some variable shadowing" +817c9dce Few more HuffmanTreeToken conversions. +37a77a6b remove some variable shadowing +89c07c96 Merge "normalize example header includes" +4aff411f Merge "add example_util.[hc]" +00b29e28 normalize example header includes +061263a7 add example_util.[hc] +c6882c49 merge all tree processing into a single VP8LProcessTree() +9c7a3cf5 fix VP8LHistogramNumCodes to handle the case palette_code_bits == 0 +b5551d2e Merge "Added HuffmanTreeCode Struct for tree codes." +8b85d01c Added HuffmanTreeCode Struct for tree codes. +093f76d8 Merge "Allocate single memory in GetHuffBitLengthsAndCodes." +41d80494 Allocate single memory in GetHuffBitLengthsAndCodes. +1b04f6d2 Correct size in VP8L header. +2924a5ae Makefile.vc: split object lists based on directory +c8f24165 Merge "add assert(tokens)" +43239947 add assert(tokens) +9f547450 Catch an error in DecodeImageData(). +ac8e5e42 minor typo and style fix +9f566d1d clean-up around Huffman-encode +c579a710 Introduce CHUNK_SIZE_BYTES in muxi.h. +14757f8a Make sure huffman trees always have valid symbols +41050618 makefile.unix: add support for building vwebp +48b37721 Merge "fixed signed/unsigned comparison warning" +57f696da Merge "EncodeImageInternal: fix potential leak" +d972cdf2 EncodeImageInternal: fix potential leak +5cd12c3d fixed signed/unsigned comparison warning +cdca30d0 Merge "cosmetics: shorten long line" +e025fb55 cosmetics: shorten long line +22671ed6 Merge "enc/vp8l: fix double free on error" +e1b9b052 Merge "cosmetics: VP8LCreateHuffmanTree: fix indent" +a8e725f8 enc/vp8l: fix double free on error +27541fbd cosmetics: VP8LCreateHuffmanTree: fix indent +1d38b258 cwebp/windows: use MAKE_REFGUID where appropriate +817ef6e9 Merge "cwebp: fix WIC/Microsoft SDK compatibility issue" +902d3e3b cwebp: fix WIC/Microsoft SDK compatibility issue +89d803c4 Merge "Fix a crash due to wrong pointer-integer arithmetic." +cb1bd741 Merge "Fix a crash in lossless decoder." +de2fe202 Merge "Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability." +ce69177a Fix a crash due to wrong pointer-integer arithmetic. +e40a3684 Fix a crash in lossless decoder. +3927ff3a remove unneeded error condition for WebPMuxNumNamedElements() +2c140e11 Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability. +861a5b7b add support for animation +eb5c16cc Merge "Set correct encode size in encoder's stats." +4abe04a2 fix the return value and handle missing input file case. +2fafb855 Set correct encode size in encoder's stats. +e7167a2b Provide one entry point for backward references. +c4ccab64 Print relevant lossless encoding stats in cwebp. +e3302cfd GetHuffBitLengthsAndCodes: reduce level of indirection +b5f2a9ed enc/vp8l: fix uninitialized variable warning +7885f8b2 makefile.unix: add lossless encoder files +1261a4c8 Merge "cosmetics" +3926b5be Merge "dsp/cpu.c: Android: fix crash on non-neon arm builds" +834f937f dsp/cpu.c: Android: fix crash on non-neon arm builds +126e1606 cosmetics +e38602d2 Merge branch 'lossless_encoder' +e8d3d6a0 split StoreHuffmanCode() into smaller functions +d0d88990 more consolidation: introduce VP8LHistogramSet +1a210ef1 big code clean-up and refactoring and optimization +41b5c8ff Some cosmetics in histogram.c +ada6ff77 Approximate FastLog between value range [256, 8192] +ec123ca3 Forgot to update out_bit_costs to symbol_bit_costs at one instance. +cf33ccd1 Evaluate output cluster's bit_costs once in HistogramRefine. +781c01f4 Simple Huffman code changes. +a2849bc5 Lossless decoder: remove an unneeded param in ReadHuffmanCodeLengths(). +b39e7487 Reducing emerging palette size from 11 to 9 bits. +bfc73db4 Move GetHistImageSymbols to histogram.c +889a5786 Improve predict vs no-predict heuristic. +01f50663 code-moving and clean-up +31035f3b reduce memory usage by allocating only one histo +fbb501b8 Restrict histo_bits to ensure histo_image size is under 32MB +8415ddf3 further simplification for the meta-Huffman coding +e4917299 A quick pass of cleanup in backward reference code +83332b3c Make transform bits a function of encode method (-m). +72920caa introduce -lossless option, protected by USE_LOSSLESS_ENCODER +c6ac4dfb Run TraceBackwards for higher qualities. +412222c8 Make histo_bits and transform_bits function of quality. +149b5098 Update lossless encoder strategy: +0e6fa065 cache_bits passed to EncodeImageInternal() +e38b40a9 Factorize code for clearing HtreeGroup. +6f4a16ea Removing the indirection of meta-huffman tables. +3d33ecd1 Some renaming/comments related to palette in lossless encoder. +4d02d586 Lossless encoder: correction in Palette storage +4a636235 fix a memleak in EncodeImageInternal() +0993a611 Full and final fix for prediction transform +afd2102f Fix cross-color transform in lossless encoder +b96d8740 Need to write a '0' bit at the end of transforms. +54dad7e5 Color cache size should be counted as 0 when cache bits = 0 +4f0c5caf Fix prediction transform in lossless encoder. +36dabdad Fix memory leak in method EncodeImageInternal for histogram_image. +352a4f49 Get rid of PackLiteralBitLengths() +d673b6b9 Change the predictor function to pass left pixel +b2f99465 Fix CopyTileWithPrediction() +84547f54 Add EncodeImageInternal() method. +6b38378a Guard the lossless encoder (in flux) under a flag +09f7532c Fix few nits (const qualifiers) +648be393 Added implementation for various lossless functions +32714ce3 Add VP8L prefix to backward ref & histogram methods. +fcba7be2 Fixed header file tag (WEBP_UTILS_HUFFMAN_ENCODE_H_) +bc703746 Add backward_ref, histogram & huffman encode modules from lossless. +fdccaadd Fixing nits +227110c4 libwebp interface changes for lossless encoding. +50679acf minor style fixes +b38dfccf remove unneeded reference to NUM_LITERAL_CODES +8979675b harmonize header description +c04eb7be tcoder.c: define NOT_HAVE_LOG2 for MSVC builds +9a214fa1 Merge "VP8[L]GetInfo: check input pointers" +5c5be8ba VP8[L]GetInfo: check input pointers +0c188fec Merge changes I431acdfe,I713659b7 +b3515c62 mux: drop 'chunk' from ChunkInfo member names +aea7923c muxi.h: remove some unused defines +01422492 update NEWS file for next release +29e3f7ec Merge "dec: remove deprecated WebPINew()" +4718e449 Merge "muxedit: a few more size_t changes" +82654f96 Merge "muxedit: remove a few redundant NULL checks" +02f27fbd dec: remove deprecated WebPINew() +ccddb3fc muxedit: remove a few redundant NULL checks +a6cdf710 muxedit: a few more size_t changes +a3846892 Merge "mux: remove unused LIST_ID" +11ae46ae alpha.c: quiet some size_t -> int conversion warnings +dee46692 mux: remove unused LIST_ID +03f1f493 mux: add version checked entry points +6a0abdaa Merge "doc: tile/alpha corrections" +c8139fbe Merge "few cosmetics" +68338737 Merge "lossless: remove some size_t -> int conversions" +5249e94a doc: tile/alpha corrections +d96e722b huffman: quiet int64 -> int conversion warning +532020f2 lossless: remove some size_t -> int conversions +23be6edf few cosmetics +1349edad Merge "configure: AC_ARG_* use AS_HELP_STRING" +bfbcc60a configure: AC_ARG_* use AS_HELP_STRING +1427ca8e Merge "Makefile.am: header file maintenance" +087332e3 Merge "remove unused parameter 'round' from CalcProba()" +9630e168 remove unused parameter 'round' from CalcProba() +92092eaa Merge "bit_reader.h: correct include" +a87fc3f6 Merge "mux: ensure # images = # tiles" +53af99b1 Merge "mux: use size_t consistently" +39a57dae Makefile.am: header file maintenance +1bd0bd0d bit_reader.h: correct include +326a3c6b mux: ensure # images = # tiles +95667b8d mux: use size_t consistently +231ec1fb Removing the indirection of meta-huffman tables. +15ebcbaa check return pointer from MuxImageGetListFromId +b0d6c4a7 Merge "configure: remove test for zlib.h" +8cccac50 Merge "dsp/lossless: silence some build warnings" +b08819a6 dsp/lossless: silence some build warnings +7ae22521 Android.mk: SSE2 & NEON updates +0a49e3f3 Merge "makefile.unix add missing header files" +2e75a9a1 Merge "decode.h: use size_t consistently" +fa13035e configure: remove test for zlib.h +d3adc81d makefile.unix add missing header files +262fe01b Merge "makefile.unix & Android.mk: cosmetics" +4cce137e Merge "enc_sse2 add missing stdlib.h include" +80256b85 enc_sse2 add missing stdlib.h include +9b3d1f3a decode.h: use size_t consistently +64083d3c Merge "Makefile.am: cosmetics" +dceb8b4d Merge changes If1331d3c,I86fe3847 +0e33d7bf Merge "webp/decode.h: fix prototypes" +fac0f12e rename BitReader to VP8LBitReader +fbd82b5a types.h: centralize use of stddef.h +2154835f Makefile.am: cosmetics +1c92bd37 vp8io: use size_t for buffer size +90ead710 fix some more uint32_t -> size_t typing +cbe705c7 webp/decode.h: fix prototypes +3f8ec1c2 makefile.unix & Android.mk: cosmetics +217ec7f4 Remove tabs in configure.ac +b3d35fc1 Merge "Android.mk & Makefile.vc: add new files" +0df04b9e Android.mk & Makefile.vc: add new files +e4f20c5b Merge "automake: replace 'silent-rules' w/AM_SILENT_RULES" +8d254a09 cosmetics +6860c2ea fix some uint32_t -> size_t typing +4af1858a Fix a crash due to max symbol in a tree >= alphabet size +6f01b830 split the VP8 and VP8L decoding properly +f2623dbe enable lossless decoder +b96efd7d add dec/vp8i.h changes from experimental +19f6398e add dec/vp8l{i.h,.c} from experimental +c4ae53c8 add utils/bit_reader.[hc] changes from experimental +514d0089 add dsp/lossless.[hc] from experimental +9c67291d add utils/huffman.[hc] from experimental +337914a0 add utils/color_cache.[hc] from experimental +b3bf8fe7 the read-overflow code-path wasn't reporting as an error +1db888ba take colorspace into account when cropping +61c2d51f move the rescaling code into its own file and make enc/ and dec/ use it. +efc2016a Make rescaler methods generic +3eacee81 Move rescaler methods out of io.c. +a69b893d automake: replace 'silent-rules' w/AM_SILENT_RULES +6f7bf645 issue 111: fix little-endian problem in bit-reader +ed278e22 Removed unnecessary lookup +cd8c3ba7 fix some warnings: down-cast and possibly-uninitialized variable +0a7102ba ~1% improvement of alpha compression +3bc1b141 Merge "Reformat container doc" +dc17abdc mux: cosmetics +cb5810df Merge "WebPMuxGetImage: allow image param to be NULL" +506a4af2 mux: cosmetics +135e8b19 WebPMuxGetImage: allow image param to be NULL +de556b68 Merge "README.mux: reword some descriptions" +0ee2aeb9 Makefile.vc: use batch mode rules +d9acddc0 msvc: move {i,p}db creation to object directory +237c9aa7 Merge "expose WebPFree function for DLL builds" +b3e4054f silence msvc debug build warning +45feb55d expose WebPFree function for DLL builds +11316d84 README.mux: reword some descriptions +4be52f4a factorize WebPMuxValidate +14f6b9f6 mux: light cleanup +5e96a5db add more param checks to WebPPictureDistortion() +8abaf820 Merge "silence some type size related warnings" +1601a39b silence some type size related warnings +f3abe520 Merge "idec: simplify buffer size calculation" +a9c5cd4c idec: simplify buffer size calculation +7b06bd7f Merge "configure/automake: add silent-rules option" +e9a7d145 Reformat container doc +d4e5c7f3 configure/automake: add silent-rules option +5081db78 configure/automake: no -version-info for convenience libs +85b6ff68 Merge "idec: fix WebPIUpdate failure" +7bb6a9cc idec: fix internal state corruption +89cd1bb8 idec: fix WebPIUpdate failure +01b63806 4-5% faster decoding, optimized byte loads in arithmetic decoder. +631117ea Merge "cosmetics & warnings" +a0b2736d cosmetics & warnings +f73947f4 use 32bit for storing dequant coeffs, instead of 16b. +b9600308 Merge "store prediction mode array as uint8_t[16], not int[16]." +7b67881a store prediction mode array as uint8_t[16], not int[16]. +cab8d4dc Merge "NEON TransformOne" +ba503fda NEON TransformOne +9f740e3b Merge "gcc warning fix: remove the 'const' qualifier." +f76d3587 gcc warning fix: remove the 'const' qualifier. +e78478d6 Merge "webpmux: make more use of WebPData" +f85bba3d Merge "manpages: add BUGS section" +48a43bbf Merge "makefile.unix: variable cosmetics" +c274dc96 makefile.unix: variable cosmetics +1f7b8595 re-organize the error-handling in the main loop a bit +1336fa71 Only recompute level_cost_[] when needed +771ee449 manpages: add BUGS section +0f7820e6 webpmux: make more use of WebPData +974aaff3 examples: logging updates +6c14aadd Merge "better token buffer code" +f4054250 better token buffer code +18d959fa Merge "mux: add WebPData type" +eec4b877 mux: add WebPData type +0de3096b use 16bit counters for recording proba counts +7f23678d fix for LevelCost + little speed-up +7107d544 further speed-up/cleanup of RecordCoeffs() and GetResidualCost() +fd221040 Introduce Token buffer (unused for now) +5fa148f4 Merge "speed-up GetResidualCost()" +28a9d9b4 speed-up GetResidualCost() +11e7dadd Merge "misc cosmetics" +378086bd misc cosmetics +d61479f9 add -print_psnr and -print_ssim options to cwebp. +2e3e8b2e add a WebPCleanupTransparentArea() method +552c1217 Merge "mux: plug some memory leaks on error" +a2a81f7d Merge "fix Mach-O shared library build" +b3482c43 Merge "fix gcc-4.0 apple 32-bit build" +e4e3ec19 fix gcc-4.0 apple 32-bit build +b0d2fecf mux: plug some memory leaks on error +f0d2c7a7 pass of cosmetics +b309a6f9 fix Mach-O shared library build +241ddd38 doc: delete mux container pdf +8b1ba272 doc: update VP8 decode guide link +7e4371c5 WebPMuxCreate: fix unchecked malloc +eb425586 Merge "have makefile.unix clean up src/webp/*~ too" +a85c3631 Merge "correct EncodeAlpha documentation" +a33842fd Merge "Update webp container spec with alpha filter options." +8d6490da Incremental support for some of the mux APIs. +b8375abd have makefile.unix clean up src/webp/*~ too +b5855fc7 correct EncodeAlpha documentation +dba37fea Update webp container spec with alpha filter options. +2e74ec8b fix compile under MINGW +716d1d7f fix suboptimal MAX_LEN cut-off limit +57cab7b8 Harmonize the alpha-filter predictions at boundary +3a989534 Merge "Fix bug for Alpha in RGBA_4444 color-mode." +8ca2076d Introduce a 'fast' alpha mode +221a06bb Fix bug for Alpha in RGBA_4444 color-mode. +ad1e163a cosmetics: normalize copyright headers +c77424d7 cosmetics: light include cleanup +9d0e17c9 fix msvc build breakage after 252028a +7c4c177c Some readability fixes for mux library +d8a47e66 Merge "Add predictive filtering option for Alpha." +252028aa Add predictive filtering option for Alpha. +9b69be1c Merge "Simplify mux library code" +a056170e Simplify mux library code +992187a3 improve log2 test +e852f832 update Android.mk file list +a90cb2be reduce number of copies and mallocs in alpha plane enc/dec +b1662b05 fix some more type conversion warnings w/MSVC +223d8c60 fix some uint64_t -> int conversion warnings with MSC +c1a0437b Merge "simplify checks for enabling SSE2 code" +f06817aa simplify checks for enabling SSE2 code +948d4fe9 silence a msvc build warning +91179549 vwebp: msvc build tweaks +7937b409 simple WebP viewer, based on OpenGL +6aac1df1 add a bunch of missing 'extern "C"' +421eb99d Merge "Remove assigned-but-not-used variable "br"" +91e27f45 better fitting names for upsampling functions +a5d7ed5c Remove assigned-but-not-used variable "br" +f62d2c94 remove unused 'has_alpha' from VP8GetInfo() signature +08e86582 trap alpha-decoding error +b361eca1 add cut-off to arith coder probability update. +8666a93a Some bug-fixes for images with alpha. +273a12a0 fix off-by-1 diff in case cropping and simple filtering +2f741d1e webpmux: ReadImage: fix ptr free in error case +721f3f48 fix alpha decode +60942c8c fix the has_alpha_ order +30971c9e Implement progress report (and user abort) +eda520a9 cosmetics after 9523f2a +38bd5bb5 Merge "Better alpha support in webpmux binary" +ccbaebfe Merge "Updated the includes to relative paths." +d71fbdcc fix small typo in error message array +cdf97aa2 Better alpha support in webpmux binary +885f25bc Updated the includes to relative paths. +a0ec9aac Update WebP encoder (cwebp) to support Alpha. +667b769a Fixed the include for types.h within mux.h +9523f2a5 Add Alpha Encode support from WebPEncode. +16612ddd Merge "Add Alpha Decode support from WebPDecode." +d117a940 Add Alpha Decode support from WebPDecode. +67228734 cosmetics after e1947a9 +e1947a92 Add Alpha encode/decode code. +afc4c5d6 simplify code by introducing a CopyPlane() helper func +113b3128 Merge "MUX API Updates" +c398f595 MUX API Updates +5acf04ef remove orphan source file +059f03ef Merge "dec: validate colorspace before using as array index" +70a03989 Merge "factorize some code" +9b243b3d factorize some code +372e2b46 Correct a bug in ReadPNG() with GRAY_ALPHA images +469d6eb9 Merge "Makefile.am: remove redundant noinst_HEADERS" +9fe3372f dec: validate colorspace before using as array index +8962030f remove orphan source file +ced3e3f4 Makefile.am: remove redundant noinst_HEADERS +964387ed use WEBP_INLINE for inline function declarations +90880a11 Merge "manpages: break long lines" +b5910895 Merge "manpages: minor formatting updates" +4c451e4a Merge "Rectify the Chunk parsing logic." +04e84cf1 examples: slight cleanup +099717ce manpages: break long lines +1daf39bb manpages: minor formatting updates +abd030b5 fix missing "(void)" in function signature +f6a7d758 remove useless test +f07b2138 Rectify the Chunk parsing logic. +b8634f7d webpmux: fix lib link order +42c2e682 Fix missing coma (on uncompiled code) +d8329d41 Android.mk: add missing source files +13a54df5 Merge "More aggressive copy-edit; add TODO; validate HTML5" +868b96ae More aggressive copy-edit; add TODO; validate HTML5 +767afea2 configure: check for a symbol contained in libpng +408b8918 Merge "Linewrap at 72 cols. Casual copy-edit." +3ae318c7 Merge "Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.)" +918eb2d8 Merge "Basic container doc source clean-up; fix lists and pseudocode blocks." +03bec9e0 Linewrap at 72 cols. Casual copy-edit. +2678d819 Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.) +428674da Basic container doc source clean-up; fix lists and pseudocode blocks. +6a77d928 Merge "Makefile.vc: cosmetics" +28c38e8c Merge "Makefile.vc: condense directory creation rules" +55be2cf8 Initial import of container spec document, from pdftotext transform. +a82a788b Makefile.vc: cosmetics +c8f41ce5 Makefile.vc: condense directory creation rules +2b877cd0 Some fixes to Makefile.vc to support the src\mux directory. +3eb969b3 Merge "Add Makefile.vc for Mux library & binary." +e78e971e Add Makefile.vc for Mux library & binary. +6aedde58 Add manual for WebPMux tool. +8a360d0a Merge "Added WebPMux Binary." +a4f32cae Added WebPMux Binary. +f3bf4c76 Added Mux Container Spec & README for MUX-API. +9f761cfa Changed function signature for WebPMuxCreate +5f31b5ec Merge "Add Mux library for manipulating WebP container." +2315785f Add Mux library for manipulating WebP container. +7e198abb update ChangeLog (tag: v0.1.3) +dfc9c1ea Harmonize the dates +28ad70c5 Fix PNG decoding bug +846e93c5 Update AUTHORS & add .mailmap +563e52d6 cosmetics after '76036f5 Refactor decoder library' +76036f54 Refactor decoder library +377ef43c configure.ac: update AC_INIT params +7a8d8762 use a user-visible MACRO for max width/height. +d4e9f559 NEON decode support in WebP +0ee683b5 update libtool version-info +fdbe02c5 windows: match _cond_destroy logic w/return variable name +206b686b README: correct advanced decode api pseudo-code +6a32a0f5 make VP8BitReader a typedef, for better re-use +b112e836 create a libwebputils under src/utils +ee697d9f harmonize the include guards and #endif comments +a1ec07a6 Fixing compiler error in non x86 arch. +dcfa509a Fixed recursive inclusion of bit_writer.h and vp8enci.h. +e06ac088 create a separate libwebpdsp under src/dsp +ebeb412a use unsigned int for bitfields +341cc56a make kNewRange a static array +227a91e5 README: minor wording update +05bd8e6a add man pages to dist +812dfa1a bump up versions in preparations for 0.1.3 +a5b78c81 wrap alpha-related options under WEBP_EXPERIMENTAL_FEATURES flag +34dc7907 regen ChangeLog for 0.1.3-rc2 +7c436630 Silence some (more) Visual Studio warnings. +60306e8c add top-level gitattributes +2aa6b80e Slience some Visual Studio warnings. +4cbbb290 Merge "bump up version for next freeze" +a3291674 bump up version for next freeze +c7e86aba cosmetics: fix comment line lengths +c9e037ab makefile.unix: add simple dist target +87d58ce9 makefile.unix: rule maintenance +d477de77 mend +fac15ec7 Update NEWS & README for next release V0.1.3 +6215595c Merge "add a -partition_limit option to limit the number of bits used by intra4x4" +3814b76c Merge "reorganize chunk-parsing code" +900286e0 add a -partition_limit option to limit the number of bits used by intra4x4 +cd12b4b0 add the missing cost for I4/I16 mode selection +dfcc2136 reorganize chunk-parsing code +3cf20306 initialize pointers to function within VP8DspInit() +d21b4795 Merge "windows: add decode threading support" +473ae953 fix hang on thread creation failure +fccca420 windows: add decode threading support +a31f843a Use the exact PNG_INCLUDES/PNG_LIBS when testing for -lpng +ad9b45f1 Merge "Makefile.vc: rule maintenance" +565a2cab Makefile.vc: rule maintenance +2d0da681 makefile.unix: disable Wvla by default +fc7815d6 multi-thread decoding: ~25-30% faster +acd8ba42 io->teardown() was not always called upon error +c85527b1 Merge "Makefile.vc: add DLL configs" +e1e9be35 cosmetics: spelling/grammar in README and lib headers +b4d0ef8f Makefile.vc: add DLL configs +998754a7 remove unused nb_i4_ and nb_i16_ fields. +9f01ce3a rename WebPDecBuffer::memory -> private_memory +fb5d659b fix an overflow bug in LUT calculation +d646d5c7 swig: add WebPDecodeARGB +78aeed40 add missing WebPDecodeARGBInto() and switch ARGB4444 to RGBA4444 as was intended +cd7c5292 explicitly mark library functions as extern +19db59f8 add support for RGB565, ARGB4444 and ARGB colorspace (decoder) +c915fb2a encoder speed-up: hardcode special level values +c558bdad Rename and improve the API to retrieve decoded area +bf599d74 Merge "makefile.unix: disable -Wvla by default" +c9ea03d7 SSE2 version of strong filtering +993af3e2 makefile.unix: disable -Wvla by default +3827e1bc Merge "examples: (windows/WIC) add alpha support" +e291fae0 SSE2 functions for the fancy upsampler. +a06bbe2e add WebPISetIOHooks() to set some custom hooks on the incremental decoder object. +7643a6f2 Merge "makefile.unix: use uname to detect OSX environment" +5142a0be export alpha channel (if present) when dumping to PGM format +14d5731c makefile.unix: use uname to detect OSX environment +08057062 examples: quiet warnings +3cfe0888 examples: (windows/WIC) add alpha support +13ed94b8 add compile warning for variable-length-array +5a18eb1a Merge "add Advanced Decoding Interface" +5c4f27f9 add missing \n +f4c4e416 80 cols fix +d2603105 add Advanced Decoding Interface +bd2f65f6 sse2 version of the complex filter +96ed9ce0 perform two idct transforms at a time when possible +01af7b69 use aligned stored +0e1d1fdf Merge "Makefile.vc: add experimental target" +2a1292a6 Makefile.vc: add experimental target +23bf351e Enable decode SSE2 for Visual Studio +131a4b7b dec/dsp_sse2: fix visual studio compile +00d9d680 swig: file reorganization +7fc7e0d9 Merge "swig/java: basic encode support" +3be57b16 fix MSVC compile for WEBP_EXPERIMENTAL_FEATURES +40a7e347 dec/dsp: disable sse2 for Visual Studio builds +e4d540c8 add SSE2 code for transform +54f2170a swig/java: basic encode support +c5d4584b call function pointers instead of C-version +ea43f045 Merge "configure: mingw32 targets: test for WIC support" +a11009d7 SSE2 version of simple in-loop filtering +42548da9 shave one unneeded filter-cache line +31f9dc6f configure: mingw32 targets: test for WIC support +19559699 Merge "split expression in two." +415dbe46 split expression in two. +e29072a8 configure: test for zlib only w/--enable-experimental +b2b0090b Simplify Visual Studio ifdefs +ca7a2fd6 Add error reporting from encoding failures. +6c9405db Merge "Makefile.vc: require CFG with clean target" +0424ecd9 Makefile.vc: require CFG with clean target +003417c7 Enable SSE2 for Visual Studio builds +af10db4a little speed up for VP8BitUpdate() +e71418f8 more MSVC files to ignore +46d90363 cosmetics +edf59ab3 typo fix +72229f5f Add support for x64 and SSE2 builds under Windows. +92e5c6e1 VP8GetInfo() + WebPResetDecParams() +416b7a6b raise the fixed-point precision for the rescaler +aa87e4e0 fix alignment +eb66670c disable WEBP_EXPERIMENTAL_FEATURES +c5ae7f65 typo fix: USE_ => WEBP_ +d041efae swig: add libwebp.jar/libwebp_java_wrap.c +f6fb3877 add swig interface +e9273902 align buffer for double too +842c009b fix -strong option +d0a70387 Merge "cosmetics" +fc0a02e5 fix the dichotomy loop +38369c03 cosmetics +8dfc4c6f factorize and unify GetAlpha() between the C and SSE2 version +6d0e66c2 prepare experimentation with yuv444 / 422 +79cc49f5 add a --enable-experimental option to './configure' +d7575238 sse2 version of CollectHistogram() +c1c728d6 add an extra #ifdef WEBP_EXPERIMENTAL_FEATURES to avoid 'unused variable' warning +60c61d2d always call VP*EncDeleteAlpha() unconditionnally, for simplicity +0f8c6384 simply don't call WriteExtensions() if WEBP_EXPERIMENTAL_FEATURES is not defined +47c661d5 rename swap -> swap_rb +10d55bbb move chunk[] declaration out of the for() loop +517cec21 fix indentation +f7d9e261 fix merge problems +8fd42b3a add a stride 'a_stride' for the alpha plane +b8dcbf2f fix alpha-plane copy and crop methods +cdef89de fix some 'unused variable' warning +fb29c262 SSE2 version of the fwd transform and the squared sum metric +2ab4b72f EXPERIMENTAL: add support for alpha channel +cfbf88a6 add SSE2 functions. ~2x faster encoding on average. +e7ff3f9a merge two ITransforms together when applicable and change the TTransform to return the sum directly. +ca554137 fix WebPIDecGetRGB() to accept any RGB(A) mode, not just MODE_RGB +8aa50efd fix some 'man' typos +d3f3bdda update ChangeLog (tag: v0.1.2) +d7e9a69c update contributor list +261abb8e add a 'superclean' section +276ae825 Remove files not mean to be in git, and update .gitignore +24868455 build: prepare libwebp.pc +14ceb6e8 add "-version" description to man pages +b247a3b2 Create the m4 directory, and also place .gitignore in there for libtool. +cdd734c9 Resolve automake warnings +c5fa726e build: add pkgconfig files +b20aaca2 build: just use autoreconf, avoid calling tools manually +4b0b0d66 cwebp: use modern functions +efbc6c41 update Android.mk +7777570b better version of ChangeLog +fa70d2b7 update version number in the DOC +f8db5d5d more C89-fixes +0de013b3 fix typos +650ffa3b add version getters for decoder and encoder +be4867d2 doc for incremental decoding +56732a1b add idec.obj in MSVC makefile +208afb5e add c++ guards +8bf76fe0 add incremental decoding +1f288328 'inline' isn't defined in strict ansi c89 +8b77c632 move the quantization function to dsp.c +b2c3575c add a 'last_y' field to WebPDecParams +2654c3da correctly pass along the exact same status returned from ParsePartitions +4704146a add missing precision in the man +6d978a6c add error messages +6463e6ab add some install instructions, and fix intel-mac flags +05fb7bfc Merge ".gitignore: initial version" +c33f0195 .gitignore: initial version +e532b9ab Makefile: allow out of tree builds +4c0da7aa enable sparse dc/ac transforms +07dbb8d5 clarify the return logic +5c69e1bb fix bigger-by-1 array +7c5267e3 fix a (harmless) typo: non_zero_ -> non_zero_ac_ +bc752135 fix missing free() +af3e2aaa remove trailing spaces +13e50da6 make the bitreader preload at least 8bits, instead of post-load them (this makes initialization easier and will be helpful for incremental decoding). Modify ParsePartitions() to accommodate for truncated input. +f4888f77 emit 9 - nb_bits trailing zeros instead of 8 +3db65255 separate block-parsing into a visible VP8DecodeMB() +a871de02 add missing extern "C" +b3ce8c52 remove a gcc warning about type pun by using a proper union'd type +e1863715 update after addition of webpi.h +3e856e2d Extract some useful functions around decoding buffer WebPDecParams. +d5bc05a4 make the filtering process match libvpx and ffvp8 +dd60138d add man pages for cwebp(1) and dwebp(1) +c4fa3644 fix header +5b70b378 * add an option to bypass_filtering in VP8Io. +b97a4003 simplify QuantizeBlock code a bit +84b58ebb add more checks around picture allocation +b65a3e10 remove absolute_delta_ field and syntax code +0744e842 Dont' open output file until we're sure the input file is valid +d5bd54c7 fix typo and buggy line +f7a9549d Add a simple top-level makefile.unix for quick & easy build. +5f36b944 update the doc for the -f option +f61d14aa a WebP encoder converts PNG & JPEG to WebP +81c96621 oops: forgotten call to Initialize() + move the error message to a more useful place +87ffa005 typo: fix a missing 'R', was confusing. +b04b857a * add decoding measurement using stopwatch.h (use -v option) * support PNG output through WIC on Win32 +746a4820 * make (*put)() hook return a bool for abort request. * add an enum for VP8Status() to make things clearer +73c973e6 * strengthen riff/chunk size checks * don't consider odd-sized chunks being an error +1dc4611a add support for PNG output (default) regularize include guards +860641df fix a typo: sizeof(kYModeProbaInter0) => sizeof(kUVModeProbaInter0) +3254fc52 fix some petty constness fix the ./configure file too +504d3393 fix eof_ mis-initialization +2bc0778f leftover Makefile.* from previous commit +d2cf04e4 move Makefile.am one level below, to src/dec fix typos here and there dwebp is now an installed program +ade92de8 typo: vp8.h -> decode_vp8.h +d7241241 forgot to declare types.h to be installed +6421a7a4 move the decoder sourcetree to a sub-location src/dec to make room for future libs sources +a9b3eab6 correct layout name is IMC4. +2330522c handle corner case of zero-dimensions +280c3658 make VP8Init() handle short buffers (< 2 bytes) correctly +b1c9e8b4 handle error cases more robustly +0e94935c Merge "table-less version of clip_8b()" +1e0a2d25 table-less version of clip_8b() +e12109ee dwebp: change -yuv option to -raw change the layout to IMC2 +d72180a4 speed-up fancy upscaler +9145f3bc reset eof_ at construction time +a7ee0559 simplify the logic of GetCoeffs() +f67b5939 lot of cosmetics +ea27d7c6 fix endian problem on PowerPC +beb0a1ba fix signature of VP8StoreBlock +b128c5e2 Merge "fancy chroma upscaling" +6a37a2aa fancy chroma upscaling +ff565edc fix two numeric typos +5a936a0a use uintptr_t for casting pointers to ints +e14a0301 for cross_compiling=yes to prevent executing any binary +83b545ee add vc9+ makefile +296f6914 fix output loop for small height +cbfbb5c3 convert to plain-C +f09f96ee Fix declaration after statement warning +5981ee55 Fix UV plane ac/dc quantizer transposition +c8d15efa convert to ANSI-C +c3f41cb4 Initial commit diff --git a/src/3rdparty/libwebp/NEWS b/src/3rdparty/libwebp/NEWS index 30554bf6fa742a61196a9358c3baed8bf5c7805d..3bf4bd05290f5609c4bf24a8ff14639bbd364c4b 100644 --- a/src/3rdparty/libwebp/NEWS +++ b/src/3rdparty/libwebp/NEWS @@ -1,3 +1,31 @@ +- 1/26/2017: version 0.6.0 + * lossless performance and compression improvements + * miscellaneous performance improvements (SSE2, NEON, MSA) + * webpmux gained a -duration option allowing for frame timing modification + * new img2webp utility allowing a sequence of images to be converted to + animated webp + * API changes: + - libwebp: + WebPPictureSharpARGBToYUVA + WebPPlaneDistortion + - libwebpmux / gif2webp: + WebPAnimEncoderOptions: kmax <= 0 now disables keyframes, kmax == 1 + forces all keyframes. See mux.h and the gif2webp + manpage for details. + +- 12/13/2016: version 0.5.2 + This is a binary compatible release. + This release covers CVE-2016-8888 and CVE-2016-9085. + * further security related hardening in the tools; fixes to + gif2webp/AnimEncoder (issues #310, #314, #316, #322), cwebp/libwebp (issue + #312) + * full libwebp (encoder & decoder) iOS framework; libwebpdecoder + WebP.framework renamed to WebPDecoder.framework (issue #307) + * CMake support for Android Studio (2.2) + * miscellaneous build related fixes (issue #306, #313) + * miscellaneous documentation improvements (issue #225) + * minor lossy encoder fixes and improvements + - 6/14/2016: version 0.5.1 This is a binary compatible release. * miscellaneous bug fixes (issues #280, #289) diff --git a/src/3rdparty/libwebp/README b/src/3rdparty/libwebp/README index 90f8f10fceaea9eafd9d2552c26154f7de0d9e80..4c15c4ad875998df9d8cb1b31d3e016770004f3c 100644 --- a/src/3rdparty/libwebp/README +++ b/src/3rdparty/libwebp/README @@ -4,7 +4,7 @@ \__\__/\____/\_____/__/ ____ ___ / _/ / \ \ / _ \/ _/ / \_/ / / \ \ __/ \__ - \____/____/\_____/_____/____/v0.5.1 + \____/____/\_____/_____/____/v0.6.0 Description: ============ @@ -220,8 +220,9 @@ assumed to be a PNG, JPEG, TIFF or WebP file. Options: -h / -help ............. short help -H / -longhelp ......... long help - -q <float> ............. quality factor (0:small..100:big) - -alpha_q <int> ......... transparency-compression quality (0..100) + -q <float> ............. quality factor (0:small..100:big), default=75 + -alpha_q <int> ......... transparency-compression quality (0..100), + default=100 -preset <string> ....... preset setting, one of: default, photo, picture, drawing, icon, text @@ -229,17 +230,18 @@ Options: -z <int> ............... activates lossless preset with given level in [0:fast, ..., 9:slowest] - -m <int> ............... compression method (0=fast, 6=slowest) - -segments <int> ........ number of segments to use (1..4) + -m <int> ............... compression method (0=fast, 6=slowest), default=4 + -segments <int> ........ number of segments to use (1..4), default=4 -size <int> ............ target size (in bytes) -psnr <float> .......... target PSNR (in dB. typically: 42) -s <int> <int> ......... input size (width x height) for YUV - -sns <int> ............. spatial noise shaping (0:off, 100:max) - -f <int> ............... filter strength (0=off..100) - -sharpness <int> ....... filter sharpness (0:most .. 7:least sharp) + -sns <int> ............. spatial noise shaping (0:off, 100:max), default=50 + -f <int> ............... filter strength (0=off..100), default=60 + -sharpness <int> ....... filter sharpness (0:most .. 7:least sharp), default=0 -strong ................ use strong filter instead of simple (default) -nostrong .............. use simple filter instead of strong + -sharp_yuv ............. use sharper (and slower) RGB->YUV conversion -partition_limit <int> . limit quality to fit the 512k limit on the first partition (0=no degradation ... 100=full) -pass <int> ............ analysis pass number (1..10) @@ -252,18 +254,18 @@ Options: -print_ssim ............ prints averaged SSIM distortion -print_lsim ............ prints local-similarity distortion -d <file.pgm> .......... dump the compressed output (PGM file) - -alpha_method <int> .... transparency-compression method (0..1) + -alpha_method <int> .... transparency-compression method (0..1), default=1 -alpha_filter <string> . predictive filtering for alpha plane, one of: none, fast (default) or best - -exact ................. preserve RGB values in transparent area + -exact ................. preserve RGB values in transparent area, default=off -blend_alpha <hex> ..... blend colors against background color expressed as RGB values written in hexadecimal, e.g. 0xc0e0d0 for red=0xc0 green=0xe0 and blue=0xd0 -noalpha ............... discard any transparency information - -lossless .............. encode image losslessly + -lossless .............. encode image losslessly, default=off -near_lossless <int> ... use near-lossless image - preprocessing (0..100=off) + preprocessing (0..100=off), default=100 -hint <string> ......... specify image characteristics hint, one of: photo, picture or graph @@ -383,6 +385,7 @@ Options are: Keyboard shortcuts: 'c' ................ toggle use of color profile 'i' ................ overlay file information + 'd' ................ disable blending & disposal (debug) 'q' / 'Q' / ESC .... quit Building: @@ -411,6 +414,37 @@ $ make -f makefile.unix examples/vwebp > nmake /f Makefile.vc CFG=release-static \ ../obj/x64/release-static/bin/vwebp.exe +Animation creation tool: +======================== +The utility 'img2webp' can turn a sequence of input images (PNG, JPEG, ...) +into an animated WebP file. It offers fine control over duration, encoding +modes, etc. + +Usage: + + img2webp [file-level options] [image files...] [per-frame options...] + +File-level options (only used at the start of compression): + -min_size ............ minimize size + -loop <int> .......... loop count (default: 0, = infinite loop) + -kmax <int> .......... maximum number of frame between key-frames + (0=only keyframes) + -kmin <int> .......... minimum number of frame between key-frames + (0=disable key-frames altogether) + -mixed ............... use mixed lossy/lossless automatic mode + -v ................... verbose mode + -h ................... this help + +Per-frame options (only used for subsequent images input): + -d <int> ............. frame duration in ms (default: 100) + -lossless ........... use lossless mode (default) + -lossy ... ........... use lossy mode + -q <float> ........... quality + -m <int> ............. method to use + +example: img2webp -loop 2 in0.png -lossy in1.jpg + -d 80 in2.tiff -o out.webp + Animated GIF conversion: ======================== Animated GIF files can be converted to WebP files with animation using the diff --git a/src/3rdparty/libwebp/qt_attribution.json b/src/3rdparty/libwebp/qt_attribution.json index 825cfeae7d33344f4d1d82b33e58a1aaf3269672..09f91dda944279accb6ae33d2a713b31498c58d3 100644 --- a/src/3rdparty/libwebp/qt_attribution.json +++ b/src/3rdparty/libwebp/qt_attribution.json @@ -6,7 +6,7 @@ "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/", - "Version": "0.5.1", + "Version": "0.6.0", "License": "BSD 3-clause \"New\" or \"Revised\" License", "LicenseId": "BSD-3-Clause", "LicenseFile": "COPYING", diff --git a/src/3rdparty/libwebp/src/dec/alpha.c b/src/3rdparty/libwebp/src/dec/alpha_dec.c similarity index 97% rename from src/3rdparty/libwebp/src/dec/alpha.c rename to src/3rdparty/libwebp/src/dec/alpha_dec.c index 028eb3d50ba4a32a2aeb35a96aaee4821fc0d53d..83ffd4b609e1b6da614230138ff889cbee17b0c4 100644 --- a/src/3rdparty/libwebp/src/dec/alpha.c +++ b/src/3rdparty/libwebp/src/dec/alpha_dec.c @@ -12,11 +12,11 @@ // Author: Skal (pascal.massimino@gmail.com) #include <stdlib.h> -#include "./alphai.h" -#include "./vp8i.h" -#include "./vp8li.h" +#include "./alphai_dec.h" +#include "./vp8i_dec.h" +#include "./vp8li_dec.h" #include "../dsp/dsp.h" -#include "../utils/quant_levels_dec.h" +#include "../utils/quant_levels_dec_utils.h" #include "../utils/utils.h" #include "../webp/format_constants.h" @@ -67,7 +67,7 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, } dec->method_ = (data[0] >> 0) & 0x03; - dec->filter_ = (data[0] >> 2) & 0x03; + dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03); dec->pre_processing_ = (data[0] >> 4) & 0x03; rsrv = (data[0] >> 6) & 0x03; if (dec->method_ < ALPHA_NO_COMPRESSION || diff --git a/src/3rdparty/libwebp/src/dec/alphai.h b/src/3rdparty/libwebp/src/dec/alphai_dec.h similarity index 96% rename from src/3rdparty/libwebp/src/dec/alphai.h rename to src/3rdparty/libwebp/src/dec/alphai_dec.h index 69dd7c0f5d610db7ba218402b785d180f2aed2d3..561e8151eebaea59ab1437e74c994fec6b518650 100644 --- a/src/3rdparty/libwebp/src/dec/alphai.h +++ b/src/3rdparty/libwebp/src/dec/alphai_dec.h @@ -14,8 +14,8 @@ #ifndef WEBP_DEC_ALPHAI_H_ #define WEBP_DEC_ALPHAI_H_ -#include "./webpi.h" -#include "../utils/filters.h" +#include "./webpi_dec.h" +#include "../utils/filters_utils.h" #ifdef __cplusplus extern "C" { diff --git a/src/3rdparty/libwebp/src/dec/buffer.c b/src/3rdparty/libwebp/src/dec/buffer_dec.c similarity index 99% rename from src/3rdparty/libwebp/src/dec/buffer.c rename to src/3rdparty/libwebp/src/dec/buffer_dec.c index 547e69b434f8018f3712e64df27b449a4f1f168e..c685fd5646bd34337a7596b5d56634391dd956c7 100644 --- a/src/3rdparty/libwebp/src/dec/buffer.c +++ b/src/3rdparty/libwebp/src/dec/buffer_dec.c @@ -13,8 +13,8 @@ #include <stdlib.h> -#include "./vp8i.h" -#include "./webpi.h" +#include "./vp8i_dec.h" +#include "./webpi_dec.h" #include "../utils/utils.h" //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/dec/common.h b/src/3rdparty/libwebp/src/dec/common_dec.h similarity index 100% rename from src/3rdparty/libwebp/src/dec/common.h rename to src/3rdparty/libwebp/src/dec/common_dec.h diff --git a/src/3rdparty/libwebp/src/dec/frame.c b/src/3rdparty/libwebp/src/dec/frame_dec.c similarity index 99% rename from src/3rdparty/libwebp/src/dec/frame.c rename to src/3rdparty/libwebp/src/dec/frame_dec.c index 22d291d2cd8a0b3f451aed8f1acb2d154890efbf..f91e27f7c8b9e979e210c685fbae9de14f1c7447 100644 --- a/src/3rdparty/libwebp/src/dec/frame.c +++ b/src/3rdparty/libwebp/src/dec/frame_dec.c @@ -12,7 +12,7 @@ // Author: Skal (pascal.massimino@gmail.com) #include <stdlib.h> -#include "./vp8i.h" +#include "./vp8i_dec.h" #include "../utils/utils.h" //------------------------------------------------------------------------------ @@ -723,7 +723,7 @@ static int AllocateMemory(VP8Decoder* const dec) { return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "no memory during frame initialization."); } - // down-cast is ok, thanks to WebPSafeAlloc() above. + // down-cast is ok, thanks to WebPSafeMalloc() above. dec->mem_size_ = (size_t)needed; } diff --git a/src/3rdparty/libwebp/src/dec/idec.c b/src/3rdparty/libwebp/src/dec/idec_dec.c similarity index 99% rename from src/3rdparty/libwebp/src/dec/idec.c rename to src/3rdparty/libwebp/src/dec/idec_dec.c index 8de131916e035c5c441b9bcf90868e4fa89551ea..78fb2e7186180595b846bb7d07645c74d85f5538 100644 --- a/src/3rdparty/libwebp/src/dec/idec.c +++ b/src/3rdparty/libwebp/src/dec/idec_dec.c @@ -15,9 +15,9 @@ #include <string.h> #include <stdlib.h> -#include "./alphai.h" -#include "./webpi.h" -#include "./vp8i.h" +#include "./alphai_dec.h" +#include "./webpi_dec.h" +#include "./vp8i_dec.h" #include "../utils/utils.h" // In append mode, buffer allocations increase as multiples of this value. diff --git a/src/3rdparty/libwebp/src/dec/io.c b/src/3rdparty/libwebp/src/dec/io_dec.c similarity index 86% rename from src/3rdparty/libwebp/src/dec/io.c rename to src/3rdparty/libwebp/src/dec/io_dec.c index 8d5c43f325d0b0d37ad67c8e4b0a7fb6e8af7488..8bfab86959a81791bc334dd8e22c940fa298d143 100644 --- a/src/3rdparty/libwebp/src/dec/io.c +++ b/src/3rdparty/libwebp/src/dec/io_dec.c @@ -13,8 +13,8 @@ #include <assert.h> #include <stdlib.h> -#include "../dec/vp8i.h" -#include "./webpi.h" +#include "../dec/vp8i_dec.h" +#include "./webpi_dec.h" #include "../dsp/dsp.h" #include "../dsp/yuv.h" #include "../utils/utils.h" @@ -256,7 +256,7 @@ static int Rescale(const uint8_t* src, int src_stride, static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { const int mb_h = io->mb_h; const int uv_mb_h = (mb_h + 1) >> 1; - WebPRescaler* const scaler = &p->scaler_y; + WebPRescaler* const scaler = p->scaler_y; int num_lines_out = 0; if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { // Before rescaling, we premultiply the luma directly into the io->y @@ -267,29 +267,28 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { io->a, io->width, io->mb_w, mb_h, 0); } num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler); - Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u); - Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v); + Rescale(io->u, io->uv_stride, uv_mb_h, p->scaler_u); + Rescale(io->v, io->uv_stride, uv_mb_h, p->scaler_v); return num_lines_out; } static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, int expected_num_lines_out) { const WebPYUVABuffer* const buf = &p->output->u.YUVA; + uint8_t* const dst_a = buf->a + p->last_y * buf->a_stride; if (io->a != NULL) { - uint8_t* dst_y = buf->y + p->last_y * buf->y_stride; - const uint8_t* src_a = buf->a + p->last_y * buf->a_stride; - const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a); - (void)expected_num_lines_out; + uint8_t* const dst_y = buf->y + p->last_y * buf->y_stride; + const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a); assert(expected_num_lines_out == num_lines_out); if (num_lines_out > 0) { // unmultiply the Y - WebPMultRows(dst_y, buf->y_stride, src_a, buf->a_stride, - p->scaler_a.dst_width, num_lines_out, 1); + WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride, + p->scaler_a->dst_width, num_lines_out, 1); } } else if (buf->a != NULL) { // the user requested alpha, but there is none, set it to opaque. assert(p->last_y + expected_num_lines_out <= io->scaled_height); - FillAlphaPlane(buf->a + p->last_y * buf->a_stride, - io->scaled_width, expected_num_lines_out, buf->a_stride); + FillAlphaPlane(dst_a, io->scaled_width, expected_num_lines_out, + buf->a_stride); } return 0; } @@ -305,31 +304,42 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { const int uv_in_height = (io->mb_h + 1) >> 1; const size_t work_size = 2 * out_width; // scratch memory for luma rescaler const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones - size_t tmp_size; + size_t tmp_size, rescaler_size; rescaler_t* work; + WebPRescaler* scalers; + const int num_rescalers = has_alpha ? 4 : 3; tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work); if (has_alpha) { tmp_size += work_size * sizeof(*work); } - p->memory = WebPSafeMalloc(1ULL, tmp_size); + rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST; + + p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size); if (p->memory == NULL) { return 0; // memory error } work = (rescaler_t*)p->memory; - WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, + + scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size); + p->scaler_y = &scalers[0]; + p->scaler_u = &scalers[1]; + p->scaler_v = &scalers[2]; + p->scaler_a = has_alpha ? &scalers[3] : NULL; + + WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h, buf->y, out_width, out_height, buf->y_stride, 1, work); - WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, + WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height, buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, work + work_size); - WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, + WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height, buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, work + work_size + uv_work_size); p->emit = EmitRescaledYUV; if (has_alpha) { - WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, + WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h, buf->a, out_width, out_height, buf->a_stride, 1, work + work_size + 2 * uv_work_size); p->emit_alpha = EmitRescaledAlphaYUV; @@ -349,15 +359,15 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) { int num_lines_out = 0; // For RGB rescaling, because of the YUV420, current scan position // U/V can be +1/-1 line from the Y one. Hence the double test. - while (WebPRescalerHasPendingOutput(&p->scaler_y) && - WebPRescalerHasPendingOutput(&p->scaler_u)) { + while (WebPRescalerHasPendingOutput(p->scaler_y) && + WebPRescalerHasPendingOutput(p->scaler_u)) { assert(y_pos + num_lines_out < p->output->height); - assert(p->scaler_u.y_accum == p->scaler_v.y_accum); - WebPRescalerExportRow(&p->scaler_y); - WebPRescalerExportRow(&p->scaler_u); - WebPRescalerExportRow(&p->scaler_v); - convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst, - dst, p->scaler_y.dst_width); + assert(p->scaler_u->y_accum == p->scaler_v->y_accum); + WebPRescalerExportRow(p->scaler_y); + WebPRescalerExportRow(p->scaler_u); + WebPRescalerExportRow(p->scaler_v); + convert(p->scaler_y->dst, p->scaler_u->dst, p->scaler_v->dst, + dst, p->scaler_y->dst_width); dst += buf->stride; ++num_lines_out; } @@ -371,15 +381,15 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { int num_lines_out = 0; while (j < mb_h) { const int y_lines_in = - WebPRescalerImport(&p->scaler_y, mb_h - j, + WebPRescalerImport(p->scaler_y, mb_h - j, io->y + j * io->y_stride, io->y_stride); j += y_lines_in; - if (WebPRescaleNeededLines(&p->scaler_u, uv_mb_h - uv_j)) { + if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) { const int u_lines_in = - WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j, + WebPRescalerImport(p->scaler_u, uv_mb_h - uv_j, io->u + uv_j * io->uv_stride, io->uv_stride); const int v_lines_in = - WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j, + WebPRescalerImport(p->scaler_v, uv_mb_h - uv_j, io->v + uv_j * io->uv_stride, io->uv_stride); (void)v_lines_in; // remove a gcc warning assert(u_lines_in == v_lines_in); @@ -400,13 +410,13 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { int num_lines_out = 0; const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); uint32_t non_opaque = 0; - const int width = p->scaler_a.dst_width; + const int width = p->scaler_a->dst_width; - while (WebPRescalerHasPendingOutput(&p->scaler_a) && + while (WebPRescalerHasPendingOutput(p->scaler_a) && num_lines_out < max_lines_out) { assert(y_pos + num_lines_out < p->output->height); - WebPRescalerExportRow(&p->scaler_a); - non_opaque |= WebPDispatchAlpha(p->scaler_a.dst, 0, width, 1, dst, 0); + WebPRescalerExportRow(p->scaler_a); + non_opaque |= WebPDispatchAlpha(p->scaler_a->dst, 0, width, 1, dst, 0); dst += buf->stride; ++num_lines_out; } @@ -428,18 +438,18 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, #endif int num_lines_out = 0; const WEBP_CSP_MODE colorspace = p->output->colorspace; - const int width = p->scaler_a.dst_width; + const int width = p->scaler_a->dst_width; const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); uint32_t alpha_mask = 0x0f; - while (WebPRescalerHasPendingOutput(&p->scaler_a) && + while (WebPRescalerHasPendingOutput(p->scaler_a) && num_lines_out < max_lines_out) { int i; assert(y_pos + num_lines_out < p->output->height); - WebPRescalerExportRow(&p->scaler_a); + WebPRescalerExportRow(p->scaler_a); for (i = 0; i < width; ++i) { // Fill in the alpha value (converted to 4 bits). - const uint32_t alpha_value = p->scaler_a.dst[i] >> 4; + const uint32_t alpha_value = p->scaler_a->dst[i] >> 4; alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; alpha_mask &= alpha_value; } @@ -455,7 +465,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p, int expected_num_out_lines) { if (io->a != NULL) { - WebPRescaler* const scaler = &p->scaler_a; + WebPRescaler* const scaler = p->scaler_a; int lines_left = expected_num_out_lines; const int y_end = p->last_y + lines_left; while (lines_left > 0) { @@ -477,7 +487,9 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { const size_t work_size = 2 * out_width; // scratch memory for one rescaler rescaler_t* work; // rescalers work area uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion - size_t tmp_size1, tmp_size2, total_size; + size_t tmp_size1, tmp_size2, total_size, rescaler_size; + WebPRescaler* scalers; + const int num_rescalers = has_alpha ? 4 : 3; tmp_size1 = 3 * work_size; tmp_size2 = 3 * out_width; @@ -486,26 +498,35 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { tmp_size2 += out_width; } total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp); - p->memory = WebPSafeMalloc(1ULL, total_size); + rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST; + + p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size); if (p->memory == NULL) { return 0; // memory error } work = (rescaler_t*)p->memory; tmp = (uint8_t*)(work + tmp_size1); - WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, + + scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size); + p->scaler_y = &scalers[0]; + p->scaler_u = &scalers[1]; + p->scaler_v = &scalers[2]; + p->scaler_a = has_alpha ? &scalers[3] : NULL; + + WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h, tmp + 0 * out_width, out_width, out_height, 0, 1, work + 0 * work_size); - WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, + WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height, tmp + 1 * out_width, out_width, out_height, 0, 1, work + 1 * work_size); - WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, + WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height, tmp + 2 * out_width, out_width, out_height, 0, 1, work + 2 * work_size); p->emit = EmitRescaledRGB; WebPInitYUV444Converters(); if (has_alpha) { - WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, + WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h, tmp + 3 * out_width, out_width, out_height, 0, 1, work + 3 * work_size); p->emit_alpha = EmitRescaledAlphaRGB; diff --git a/src/3rdparty/libwebp/src/dec/quant.c b/src/3rdparty/libwebp/src/dec/quant_dec.c similarity index 99% rename from src/3rdparty/libwebp/src/dec/quant.c rename to src/3rdparty/libwebp/src/dec/quant_dec.c index 5b648f942c5e7d4ad2aaa7dff16ab9d4e32e94f0..14e31989465ff255318046ed30e8eee0a4669612 100644 --- a/src/3rdparty/libwebp/src/dec/quant.c +++ b/src/3rdparty/libwebp/src/dec/quant_dec.c @@ -11,7 +11,7 @@ // // Author: Skal (pascal.massimino@gmail.com) -#include "./vp8i.h" +#include "./vp8i_dec.h" static WEBP_INLINE int clip(int v, int M) { return v < 0 ? 0 : v > M ? M : v; diff --git a/src/3rdparty/libwebp/src/dec/tree.c b/src/3rdparty/libwebp/src/dec/tree_dec.c similarity index 99% rename from src/3rdparty/libwebp/src/dec/tree.c rename to src/3rdparty/libwebp/src/dec/tree_dec.c index c2007ea733dd1ef926118b6f107fda26c1a1d6cf..9e805f60f3f11dd133b57380ba00732abe6e79dc 100644 --- a/src/3rdparty/libwebp/src/dec/tree.c +++ b/src/3rdparty/libwebp/src/dec/tree_dec.c @@ -11,10 +11,13 @@ // // Author: Skal (pascal.massimino@gmail.com) -#include "./vp8i.h" -#include "../utils/bit_reader_inl.h" +#include "./vp8i_dec.h" +#include "../utils/bit_reader_inl_utils.h" +#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__) +// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then. #define USE_GENERIC_TREE +#endif #ifdef USE_GENERIC_TREE static const int8_t kYModesIntra4[18] = { diff --git a/src/3rdparty/libwebp/src/dec/vp8.c b/src/3rdparty/libwebp/src/dec/vp8_dec.c similarity index 90% rename from src/3rdparty/libwebp/src/dec/vp8.c rename to src/3rdparty/libwebp/src/dec/vp8_dec.c index 336680c38c03bc3f52fe79f02b9dc115a18c7a5f..fad8d9cf352b33877ef304c8613849403d31a960 100644 --- a/src/3rdparty/libwebp/src/dec/vp8.c +++ b/src/3rdparty/libwebp/src/dec/vp8_dec.c @@ -13,11 +13,11 @@ #include <stdlib.h> -#include "./alphai.h" -#include "./vp8i.h" -#include "./vp8li.h" -#include "./webpi.h" -#include "../utils/bit_reader_inl.h" +#include "./alphai_dec.h" +#include "./vp8i_dec.h" +#include "./vp8li_dec.h" +#include "./webpi_dec.h" +#include "../utils/bit_reader_inl_utils.h" #include "../utils/utils.h" //------------------------------------------------------------------------------ @@ -26,6 +26,16 @@ int WebPGetDecoderVersion(void) { return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION; } +//------------------------------------------------------------------------------ +// Signature and pointer-to-function for GetCoeffs() variants below. + +typedef int (*GetCoeffsFunc)(VP8BitReader* const br, + const VP8BandProbas* const prob[], + int ctx, const quant_t dq, int n, int16_t* out); +static volatile GetCoeffsFunc GetCoeffs = NULL; + +static void InitGetCoeffs(void); + //------------------------------------------------------------------------------ // VP8Decoder @@ -51,6 +61,7 @@ VP8Decoder* VP8New(void) { WebPGetWorkerInterface()->Init(&dec->worker_); dec->ready_ = 0; dec->num_parts_minus_one_ = 0; + InitGetCoeffs(); } return dec; } @@ -273,12 +284,14 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { frm_hdr->profile_ = (bits >> 1) & 7; frm_hdr->show_ = (bits >> 4) & 1; frm_hdr->partition_length_ = (bits >> 5); - if (frm_hdr->profile_ > 3) + if (frm_hdr->profile_ > 3) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Incorrect keyframe parameters."); - if (!frm_hdr->show_) + } + if (!frm_hdr->show_) { return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, "Frame not displayable."); + } buf += 3; buf_size -= 3; } @@ -420,8 +433,9 @@ static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) { } // Returns the position of the last non-zero coeff plus one -static int GetCoeffs(VP8BitReader* const br, const VP8BandProbas* const prob[], - int ctx, const quant_t dq, int n, int16_t* out) { +static int GetCoeffsFast(VP8BitReader* const br, + const VP8BandProbas* const prob[], + int ctx, const quant_t dq, int n, int16_t* out) { const uint8_t* p = prob[n]->probas_[ctx]; for (; n < 16; ++n) { if (!VP8GetBit(br, p[0])) { @@ -447,6 +461,46 @@ static int GetCoeffs(VP8BitReader* const br, const VP8BandProbas* const prob[], return 16; } +// This version of GetCoeffs() uses VP8GetBitAlt() which is an alternate version +// of VP8GetBitAlt() targeting specific platforms. +static int GetCoeffsAlt(VP8BitReader* const br, + const VP8BandProbas* const prob[], + int ctx, const quant_t dq, int n, int16_t* out) { + const uint8_t* p = prob[n]->probas_[ctx]; + for (; n < 16; ++n) { + if (!VP8GetBitAlt(br, p[0])) { + return n; // previous coeff was last non-zero coeff + } + while (!VP8GetBitAlt(br, p[1])) { // sequence of zero coeffs + p = prob[++n]->probas_[0]; + if (n == 16) return 16; + } + { // non zero coeff + const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; + int v; + if (!VP8GetBitAlt(br, p[2])) { + v = 1; + p = p_ctx[1]; + } else { + v = GetLargeValue(br, p); + p = p_ctx[2]; + } + out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0]; + } + } + return 16; +} + +WEBP_TSAN_IGNORE_FUNCTION static void InitGetCoeffs(void) { + if (GetCoeffs == NULL) { + if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) { + GetCoeffs = GetCoeffsAlt; + } else { + GetCoeffs = GetCoeffsFast; + } + } +} + static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) { nz_coeffs <<= 2; nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz; diff --git a/src/3rdparty/libwebp/src/dec/decode_vp8.h b/src/3rdparty/libwebp/src/dec/vp8_dec.h similarity index 100% rename from src/3rdparty/libwebp/src/dec/decode_vp8.h rename to src/3rdparty/libwebp/src/dec/vp8_dec.h diff --git a/src/3rdparty/libwebp/src/dec/vp8i.h b/src/3rdparty/libwebp/src/dec/vp8i_dec.h similarity index 98% rename from src/3rdparty/libwebp/src/dec/vp8i.h rename to src/3rdparty/libwebp/src/dec/vp8i_dec.h index 00da02badcbe569be5b4a0ade503ebfdcb48be5b..555853e8f87f922217eb425eaf24a55a1d76b512 100644 --- a/src/3rdparty/libwebp/src/dec/vp8i.h +++ b/src/3rdparty/libwebp/src/dec/vp8i_dec.h @@ -15,11 +15,11 @@ #define WEBP_DEC_VP8I_H_ #include <string.h> // for memcpy() -#include "./common.h" -#include "./vp8li.h" -#include "../utils/bit_reader.h" -#include "../utils/random.h" -#include "../utils/thread.h" +#include "./common_dec.h" +#include "./vp8li_dec.h" +#include "../utils/bit_reader_utils.h" +#include "../utils/random_utils.h" +#include "../utils/thread_utils.h" #include "../dsp/dsp.h" #ifdef __cplusplus @@ -31,8 +31,8 @@ extern "C" { // version numbers #define DEC_MAJ_VERSION 0 -#define DEC_MIN_VERSION 5 -#define DEC_REV_VERSION 1 +#define DEC_MIN_VERSION 6 +#define DEC_REV_VERSION 0 // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // Constraints are: We need to store one 16x16 block of luma samples (y), diff --git a/src/3rdparty/libwebp/src/dec/vp8l.c b/src/3rdparty/libwebp/src/dec/vp8l_dec.c similarity index 98% rename from src/3rdparty/libwebp/src/dec/vp8l.c rename to src/3rdparty/libwebp/src/dec/vp8l_dec.c index cb2e3176b6346051f5250ea5fe5a265fc3731978..ef359a91f0a13d16b1ae11e8e60056fc8d12e61c 100644 --- a/src/3rdparty/libwebp/src/dec/vp8l.c +++ b/src/3rdparty/libwebp/src/dec/vp8l_dec.c @@ -14,13 +14,14 @@ #include <stdlib.h> -#include "./alphai.h" -#include "./vp8li.h" +#include "./alphai_dec.h" +#include "./vp8li_dec.h" #include "../dsp/dsp.h" #include "../dsp/lossless.h" +#include "../dsp/lossless_common.h" #include "../dsp/yuv.h" -#include "../utils/endian_inl.h" -#include "../utils/huffman.h" +#include "../utils/endian_inl_utils.h" +#include "../utils/huffman_utils.h" #include "../utils/utils.h" #define NUM_ARGB_CACHE_ROWS 16 @@ -547,11 +548,14 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec, uint8_t* const row_out = out + num_lines_out * out_stride; const int lines_left = mb_h - num_lines_in; const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); + int lines_imported; assert(needed_lines > 0 && needed_lines <= lines_left); WebPMultARGBRows(row_in, in_stride, dec->rescaler->src_width, needed_lines, 0); - WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride); - num_lines_in += needed_lines; + lines_imported = + WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride); + assert(lines_imported == needed_lines); + num_lines_in += lines_imported; num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out); } return num_lines_out; @@ -623,9 +627,12 @@ static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec, while (num_lines_in < mb_h) { const int lines_left = mb_h - num_lines_in; const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); + int lines_imported; WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0); - WebPRescalerImport(dec->rescaler, lines_left, in, in_stride); - num_lines_in += needed_lines; + lines_imported = + WebPRescalerImport(dec->rescaler, lines_left, in, in_stride); + assert(lines_imported == needed_lines); + num_lines_in += lines_imported; in += needed_lines * in_stride; y_pos += ExportYUVA(dec, y_pos); } @@ -705,13 +712,15 @@ static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows, uint32_t* const rows_out = dec->argb_cache_; // Inverse transforms. - // TODO: most transforms only need to operate on the cropped region only. - memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out)); while (n-- > 0) { VP8LTransform* const transform = &dec->transforms_[n]; VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); rows_in = rows_out; } + if (rows_in != rows_out) { + // No transform called, hence just copy. + memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out)); + } } // Processes (transforms, scales & color-converts) the rows decoded after the @@ -1210,8 +1219,9 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { // Equivalent to AddPixelEq(), on a byte-basis. new_data[i] = (data[i] + new_data[i - 4]) & 0xff; } - for (; i < 4 * final_num_colors; ++i) + for (; i < 4 * final_num_colors; ++i) { new_data[i] = 0; // black tail. + } WebPSafeFree(transform->data_); transform->data_ = new_color_map; } @@ -1482,9 +1492,8 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) { const int cache_pixs = width * num_rows_to_process; uint8_t* const dst = output + width * cur_row; const uint32_t* const src = dec->argb_cache_; - int i; ApplyInverseTransforms(dec, num_rows_to_process, in); - for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff; + WebPExtractGreen(src, dst, cache_pixs); AlphaApplyFilter(alph_dec, cur_row, cur_row + num_rows_to_process, dst, width); num_rows -= num_rows_to_process; @@ -1552,6 +1561,8 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) { return 1; // done } + if (!alph_dec->use_8b_decode_) WebPInitAlphaProcessing(); + // Decode (with special row processing). return alph_dec->use_8b_decode_ ? DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_, diff --git a/src/3rdparty/libwebp/src/dec/vp8li.h b/src/3rdparty/libwebp/src/dec/vp8li_dec.h similarity index 97% rename from src/3rdparty/libwebp/src/dec/vp8li.h rename to src/3rdparty/libwebp/src/dec/vp8li_dec.h index 9313bdc0af97f0e21433bd83e5f8fbdbb263320f..097a9d0589f3df2598c1d8df583ab331377dccda 100644 --- a/src/3rdparty/libwebp/src/dec/vp8li.h +++ b/src/3rdparty/libwebp/src/dec/vp8li_dec.h @@ -16,10 +16,10 @@ #define WEBP_DEC_VP8LI_H_ #include <string.h> // for memcpy() -#include "./webpi.h" -#include "../utils/bit_reader.h" -#include "../utils/color_cache.h" -#include "../utils/huffman.h" +#include "./webpi_dec.h" +#include "../utils/bit_reader_utils.h" +#include "../utils/color_cache_utils.h" +#include "../utils/huffman_utils.h" #ifdef __cplusplus extern "C" { diff --git a/src/3rdparty/libwebp/src/dec/webp.c b/src/3rdparty/libwebp/src/dec/webp_dec.c similarity index 98% rename from src/3rdparty/libwebp/src/dec/webp.c rename to src/3rdparty/libwebp/src/dec/webp_dec.c index d0b912f02f6ca024db1f610800f38361e1d570bc..a8e9c2c510bf6e27e5d41e67f5842055857eafd0 100644 --- a/src/3rdparty/libwebp/src/dec/webp.c +++ b/src/3rdparty/libwebp/src/dec/webp_dec.c @@ -13,9 +13,9 @@ #include <stdlib.h> -#include "./vp8i.h" -#include "./vp8li.h" -#include "./webpi.h" +#include "./vp8i_dec.h" +#include "./vp8li_dec.h" +#include "./webpi_dec.h" #include "../utils/utils.h" #include "../webp/mux_types.h" // ALPHA_FLAG @@ -39,8 +39,8 @@ // 20..23 VP8X flags bit-map corresponding to the chunk-types present. // 24..26 Width of the Canvas Image. // 27..29 Height of the Canvas Image. -// There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8, -// VP8L, XMP, EXIF ...) +// There can be extra chunks after the "VP8X" chunk (ICCP, ANMF, VP8, VP8L, +// XMP, EXIF ...) // All sizes are in little-endian order. // Note: chunk data size must be padded to multiple of 2 when written. @@ -289,7 +289,6 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data, int found_riff = 0; int found_vp8x = 0; int animation_present = 0; - int fragments_present = 0; const int have_all_data = (headers != NULL) ? headers->have_all_data : 0; VP8StatusCode status; @@ -318,7 +317,6 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data, return status; // Wrong VP8X / insufficient data. } animation_present = !!(flags & ANIMATION_FLAG); - fragments_present = !!(flags & FRAGMENTS_FLAG); if (!found_riff && found_vp8x) { // Note: This restriction may be removed in the future, if it becomes // necessary to send VP8X chunk to the decoder. @@ -330,8 +328,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data, image_width = canvas_width; image_height = canvas_height; - if (found_vp8x && (animation_present || fragments_present) && - headers == NULL) { + if (found_vp8x && animation_present && headers == NULL) { status = VP8_STATUS_OK; goto ReturnWidthHeight; // Just return features from VP8X header. } @@ -362,7 +359,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data, return VP8_STATUS_BITSTREAM_ERROR; } - if (format != NULL && !(animation_present || fragments_present)) { + if (format != NULL && !animation_present) { *format = hdrs.is_lossless ? 2 : 1; } diff --git a/src/3rdparty/libwebp/src/dec/webpi.h b/src/3rdparty/libwebp/src/dec/webpi_dec.h similarity index 90% rename from src/3rdparty/libwebp/src/dec/webpi.h rename to src/3rdparty/libwebp/src/dec/webpi_dec.h index 991b194c228c61b310c44d6e8e57e76863deb207..696abc1958aac8e82db841d7520bd1857435bf22 100644 --- a/src/3rdparty/libwebp/src/dec/webpi.h +++ b/src/3rdparty/libwebp/src/dec/webpi_dec.h @@ -18,8 +18,8 @@ extern "C" { #endif -#include "../utils/rescaler.h" -#include "./decode_vp8.h" +#include "../utils/rescaler_utils.h" +#include "./vp8_dec.h" //------------------------------------------------------------------------------ // WebPDecParams: Decoding output parameters. Transient internal object. @@ -38,27 +38,18 @@ struct WebPDecParams { int last_y; // coordinate of the line that was last output const WebPDecoderOptions* options; // if not NULL, use alt decoding features - // rescalers - WebPRescaler scaler_y, scaler_u, scaler_v, scaler_a; + + WebPRescaler* scaler_y, *scaler_u, *scaler_v, *scaler_a; // rescalers void* memory; // overall scratch memory for the output work. OutputFunc emit; // output RGB or YUV samples OutputAlphaFunc emit_alpha; // output alpha channel OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values - - WebPDecBuffer* final_output; // In case the user supplied a slow-memory - // output, we decode image in temporary buffer - // (this::output) and copy it here. - WebPDecBuffer tmp_buffer; // this::output will point to this one in case - // of slow memory. }; // Should be called first, before any use of the WebPDecParams object. void WebPResetDecParams(WebPDecParams* const params); -// Delete all memory (after an error occurred, for instance) -void WebPFreeDecParams(WebPDecParams* const params); - //------------------------------------------------------------------------------ // Header parsing helpers diff --git a/src/3rdparty/libwebp/src/demux/anim_decode.c b/src/3rdparty/libwebp/src/demux/anim_decode.c index 1989eb4ab4c94ca99be8a6b7094b187895cac695..f1cf176e72d410664d8dc7578f19d449cc8ae704 100644 --- a/src/3rdparty/libwebp/src/demux/anim_decode.c +++ b/src/3rdparty/libwebp/src/demux/anim_decode.c @@ -112,18 +112,15 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal( dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR); dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT); - { - const int canvas_bytes = - dec->info_.canvas_width * NUM_CHANNELS * dec->info_.canvas_height; - // Note: calloc() because we fill frame with zeroes as well. - dec->curr_frame_ = WebPSafeCalloc(1ULL, canvas_bytes); - if (dec->curr_frame_ == NULL) goto Error; - dec->prev_frame_disposed_ = WebPSafeCalloc(1ULL, canvas_bytes); - if (dec->prev_frame_disposed_ == NULL) goto Error; - } + // Note: calloc() because we fill frame with zeroes as well. + dec->curr_frame_ = (uint8_t*)WebPSafeCalloc( + dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height); + if (dec->curr_frame_ == NULL) goto Error; + dec->prev_frame_disposed_ = (uint8_t*)WebPSafeCalloc( + dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height); + if (dec->prev_frame_disposed_ == NULL) goto Error; WebPAnimDecoderReset(dec); - return dec; Error: @@ -144,9 +141,13 @@ static int IsFullFrame(int width, int height, int canvas_width, } // Clear the canvas to transparent. -static void ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width, - uint32_t canvas_height) { - memset(buf, 0, canvas_width * NUM_CHANNELS * canvas_height); +static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width, + uint32_t canvas_height) { + const uint64_t size = + (uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf); + if (size != (size_t)size) return 0; + memset(buf, 0, (size_t)size); + return 1; } // Clear given frame rectangle to transparent. @@ -162,10 +163,13 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset, } // Copy width * height pixels from 'src' to 'dst'. -static void CopyCanvas(const uint8_t* src, uint8_t* dst, - uint32_t width, uint32_t height) { +static int CopyCanvas(const uint8_t* src, uint8_t* dst, + uint32_t width, uint32_t height) { + const uint64_t size = (uint64_t)width * height * NUM_CHANNELS; + if (size != (size_t)size) return 0; assert(src != NULL && dst != NULL); - memcpy(dst, src, width * NUM_CHANNELS * height); + memcpy(dst, src, (size_t)size); + return 1; } // Returns true if the current frame is a key-frame. @@ -328,9 +332,14 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_, dec->prev_frame_was_keyframe_, width, height); if (is_key_frame) { - ZeroFillCanvas(dec->curr_frame_, width, height); + if (!ZeroFillCanvas(dec->curr_frame_, width, height)) { + goto Error; + } } else { - CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_, width, height); + if (!CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_, + width, height)) { + goto Error; + } } // Decode. @@ -393,6 +402,7 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, // Update info of the previous frame and dispose it for the next iteration. dec->prev_frame_timestamp_ = timestamp; + WebPDemuxReleaseIterator(&dec->prev_iter_); dec->prev_iter_ = iter; dec->prev_frame_was_keyframe_ = is_key_frame; CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height); @@ -421,6 +431,7 @@ int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) { void WebPAnimDecoderReset(WebPAnimDecoder* dec) { if (dec != NULL) { dec->prev_frame_timestamp_ = 0; + WebPDemuxReleaseIterator(&dec->prev_iter_); memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_)); dec->prev_frame_was_keyframe_ = 0; dec->next_frame_ = 1; @@ -434,6 +445,7 @@ const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) { void WebPAnimDecoderDelete(WebPAnimDecoder* dec) { if (dec != NULL) { + WebPDemuxReleaseIterator(&dec->prev_iter_); WebPDemuxDelete(dec->demux_); WebPSafeFree(dec->curr_frame_); WebPSafeFree(dec->prev_frame_disposed_); diff --git a/src/3rdparty/libwebp/src/demux/demux.c b/src/3rdparty/libwebp/src/demux/demux.c index 0d2989f6f49d5c841a9993ad297ac66d38ea5db3..100eab8c0128705bdd9f977e3a7382a74fe1b80b 100644 --- a/src/3rdparty/libwebp/src/demux/demux.c +++ b/src/3rdparty/libwebp/src/demux/demux.c @@ -25,7 +25,7 @@ #define DMUX_MAJ_VERSION 0 #define DMUX_MIN_VERSION 3 -#define DMUX_REV_VERSION 0 +#define DMUX_REV_VERSION 2 typedef struct { size_t start_; // start location of the data @@ -590,7 +590,6 @@ static int CheckFrameBounds(const Frame* const frame, int exact, static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); - const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG); const Frame* f = dmux->frames_; if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; @@ -598,7 +597,7 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; if (dmux->loop_count_ < 0) return 0; if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; - if (is_fragmented) return 0; + if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream while (f != NULL) { const int cur_frame_set = f->frame_num_; diff --git a/src/3rdparty/libwebp/src/dsp/alpha_processing.c b/src/3rdparty/libwebp/src/dsp/alpha_processing.c index 1716cace8d558993187b56202512ac6b549fa55d..4b60e092be4021ec063867800da8621716edd700 100644 --- a/src/3rdparty/libwebp/src/dsp/alpha_processing.c +++ b/src/3rdparty/libwebp/src/dsp/alpha_processing.c @@ -284,9 +284,9 @@ static void ApplyAlphaMultiply_16b(uint8_t* rgba4444, #endif } -static int DispatchAlpha(const uint8_t* alpha, int alpha_stride, - int width, int height, - uint8_t* dst, int dst_stride) { +static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride, + int width, int height, + uint8_t* dst, int dst_stride) { uint32_t alpha_mask = 0xff; int i, j; @@ -303,9 +303,9 @@ static int DispatchAlpha(const uint8_t* alpha, int alpha_stride, return (alpha_mask != 0xff); } -static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride, - int width, int height, - uint32_t* dst, int dst_stride) { +static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride, + int width, int height, + uint32_t* dst, int dst_stride) { int i, j; for (j = 0; j < height; ++j) { for (i = 0; i < width; ++i) { @@ -316,9 +316,9 @@ static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride, } } -static int ExtractAlpha(const uint8_t* argb, int argb_stride, - int width, int height, - uint8_t* alpha, int alpha_stride) { +static int ExtractAlpha_C(const uint8_t* argb, int argb_stride, + int width, int height, + uint8_t* alpha, int alpha_stride) { uint8_t alpha_mask = 0xff; int i, j; @@ -334,11 +334,17 @@ static int ExtractAlpha(const uint8_t* argb, int argb_stride, return (alpha_mask == 0xff); } +static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) { + int i; + for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8; +} + void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int); void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int); int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int); void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int); int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int); +void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size); //------------------------------------------------------------------------------ // Init function @@ -346,6 +352,7 @@ int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int); extern void WebPInitAlphaProcessingMIPSdspR2(void); extern void WebPInitAlphaProcessingSSE2(void); extern void WebPInitAlphaProcessingSSE41(void); +extern void WebPInitAlphaProcessingNEON(void); static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used = (VP8CPUInfo)&alpha_processing_last_cpuinfo_used; @@ -357,9 +364,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) { WebPMultRow = WebPMultRowC; WebPApplyAlphaMultiply = ApplyAlphaMultiply; WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b; - WebPDispatchAlpha = DispatchAlpha; - WebPDispatchAlphaToGreen = DispatchAlphaToGreen; - WebPExtractAlpha = ExtractAlpha; + + WebPDispatchAlpha = DispatchAlpha_C; + WebPDispatchAlphaToGreen = DispatchAlphaToGreen_C; + WebPExtractAlpha = ExtractAlpha_C; + WebPExtractGreen = ExtractGreen_C; // If defined, use CPUInfo() to overwrite some pointers with faster versions. if (VP8GetCPUInfo != NULL) { @@ -373,6 +382,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) { #endif } #endif +#if defined(WEBP_USE_NEON) + if (VP8GetCPUInfo(kNEON)) { + WebPInitAlphaProcessingNEON(); + } +#endif #if defined(WEBP_USE_MIPS_DSP_R2) if (VP8GetCPUInfo(kMIPSdspR2)) { WebPInitAlphaProcessingMIPSdspR2(); diff --git a/src/3rdparty/libwebp/src/dsp/alpha_processing_neon.c b/src/3rdparty/libwebp/src/dsp/alpha_processing_neon.c new file mode 100644 index 0000000000000000000000000000000000000000..606a401cf795d1f3ecb46c5698c33e3551147645 --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/alpha_processing_neon.c @@ -0,0 +1,191 @@ +// Copyright 2017 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. +// ----------------------------------------------------------------------------- +// +// Utilities for processing transparent channel, NEON version. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "./dsp.h" + +#if defined(WEBP_USE_NEON) + +#include "./neon.h" + +//------------------------------------------------------------------------------ + +#define MULTIPLIER(a) ((a) * 0x8081) +#define PREMULTIPLY(x, m) (((x) * (m)) >> 23) + +#define MULTIPLY_BY_ALPHA(V, ALPHA, OTHER) do { \ + const uint8x8_t alpha = (V).val[(ALPHA)]; \ + const uint16x8_t r1 = vmull_u8((V).val[1], alpha); \ + const uint16x8_t g1 = vmull_u8((V).val[2], alpha); \ + const uint16x8_t b1 = vmull_u8((V).val[(OTHER)], alpha); \ + /* we use: v / 255 = (v + 1 + (v >> 8)) >> 8 */ \ + const uint16x8_t r2 = vsraq_n_u16(r1, r1, 8); \ + const uint16x8_t g2 = vsraq_n_u16(g1, g1, 8); \ + const uint16x8_t b2 = vsraq_n_u16(b1, b1, 8); \ + const uint16x8_t r3 = vaddq_u16(r2, kOne); \ + const uint16x8_t g3 = vaddq_u16(g2, kOne); \ + const uint16x8_t b3 = vaddq_u16(b2, kOne); \ + (V).val[1] = vshrn_n_u16(r3, 8); \ + (V).val[2] = vshrn_n_u16(g3, 8); \ + (V).val[(OTHER)] = vshrn_n_u16(b3, 8); \ +} while (0) + +static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first, + int w, int h, int stride) { + const uint16x8_t kOne = vdupq_n_u16(1u); + while (h-- > 0) { + uint32_t* const rgbx = (uint32_t*)rgba; + int i = 0; + if (alpha_first) { + for (; i + 8 <= w; i += 8) { + // load aaaa...|rrrr...|gggg...|bbbb... + uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i)); + MULTIPLY_BY_ALPHA(RGBX, 0, 3); + vst4_u8((uint8_t*)(rgbx + i), RGBX); + } + } else { + for (; i + 8 <= w; i += 8) { + uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i)); + MULTIPLY_BY_ALPHA(RGBX, 3, 0); + vst4_u8((uint8_t*)(rgbx + i), RGBX); + } + } + // Finish with left-overs. + for (; i < w; ++i) { + uint8_t* const rgb = rgba + (alpha_first ? 1 : 0); + const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3); + const uint32_t a = alpha[4 * i]; + if (a != 0xff) { + const uint32_t mult = MULTIPLIER(a); + rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult); + rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult); + rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult); + } + } + rgba += stride; + } +} +#undef MULTIPLY_BY_ALPHA +#undef MULTIPLIER +#undef PREMULTIPLY + +//------------------------------------------------------------------------------ + +static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride, + int width, int height, + uint8_t* dst, int dst_stride) { + uint32_t alpha_mask = 0xffffffffu; + uint8x8_t mask8 = vdup_n_u8(0xff); + uint32_t tmp[2]; + int i, j; + for (j = 0; j < height; ++j) { + // We don't know if alpha is first or last in dst[] (depending on rgbA/Argb + // mode). So we must be sure dst[4*i + 8 - 1] is writable for the store. + // Hence the test with 'width - 1' instead of just 'width'. + for (i = 0; i + 8 <= width - 1; i += 8) { + uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(dst + 4 * i)); + const uint8x8_t alphas = vld1_u8(alpha + i); + rgbX.val[0] = alphas; + vst4_u8((uint8_t*)(dst + 4 * i), rgbX); + mask8 = vand_u8(mask8, alphas); + } + for (; i < width; ++i) { + const uint32_t alpha_value = alpha[i]; + dst[4 * i] = alpha_value; + alpha_mask &= alpha_value; + } + alpha += alpha_stride; + dst += dst_stride; + } + vst1_u8((uint8_t*)tmp, mask8); + alpha_mask &= tmp[0]; + alpha_mask &= tmp[1]; + return (alpha_mask != 0xffffffffu); +} + +static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride, + int width, int height, + uint32_t* dst, int dst_stride) { + int i, j; + uint8x8x4_t greens; // leave A/R/B channels zero'd. + greens.val[0] = vdup_n_u8(0); + greens.val[2] = vdup_n_u8(0); + greens.val[3] = vdup_n_u8(0); + for (j = 0; j < height; ++j) { + for (i = 0; i + 8 <= width; i += 8) { + greens.val[1] = vld1_u8(alpha + i); + vst4_u8((uint8_t*)(dst + i), greens); + } + for (; i < width; ++i) dst[i] = alpha[i] << 8; + alpha += alpha_stride; + dst += dst_stride; + } +} + +static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride, + int width, int height, + uint8_t* alpha, int alpha_stride) { + uint32_t alpha_mask = 0xffffffffu; + uint8x8_t mask8 = vdup_n_u8(0xff); + uint32_t tmp[2]; + int i, j; + for (j = 0; j < height; ++j) { + // We don't know if alpha is first or last in dst[] (depending on rgbA/Argb + // mode). So we must be sure dst[4*i + 8 - 1] is writable for the store. + // Hence the test with 'width - 1' instead of just 'width'. + for (i = 0; i + 8 <= width - 1; i += 8) { + const uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(argb + 4 * i)); + const uint8x8_t alphas = rgbX.val[0]; + vst1_u8((uint8_t*)(alpha + i), alphas); + mask8 = vand_u8(mask8, alphas); + } + for (; i < width; ++i) { + alpha[i] = argb[4 * i]; + alpha_mask &= alpha[i]; + } + argb += argb_stride; + alpha += alpha_stride; + } + vst1_u8((uint8_t*)tmp, mask8); + alpha_mask &= tmp[0]; + alpha_mask &= tmp[1]; + return (alpha_mask == 0xffffffffu); +} + +static void ExtractGreen_NEON(const uint32_t* argb, + uint8_t* alpha, int size) { + int i; + for (i = 0; i + 16 <= size; i += 16) { + const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i)); + const uint8x16_t greens = rgbX.val[1]; + vst1q_u8(alpha + i, greens); + } + for (; i < size; ++i) alpha[i] = (argb[i] >> 8) & 0xff; +} + +//------------------------------------------------------------------------------ + +extern void WebPInitAlphaProcessingNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingNEON(void) { + WebPApplyAlphaMultiply = ApplyAlphaMultiply_NEON; + WebPDispatchAlpha = DispatchAlpha_NEON; + WebPDispatchAlphaToGreen = DispatchAlphaToGreen_NEON; + WebPExtractAlpha = ExtractAlpha_NEON; + WebPExtractGreen = ExtractGreen_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingNEON) + +#endif // WEBP_USE_NEON diff --git a/src/3rdparty/libwebp/src/dsp/alpha_processing_sse2.c b/src/3rdparty/libwebp/src/dsp/alpha_processing_sse2.c index 5acb481dcddbb7d71c0008d45f56d3cafbd8bb6d..83dc559fac4c0e048bd4285a4f56e0a91ae34516 100644 --- a/src/3rdparty/libwebp/src/dsp/alpha_processing_sse2.c +++ b/src/3rdparty/libwebp/src/dsp/alpha_processing_sse2.c @@ -150,46 +150,46 @@ static int ExtractAlpha(const uint8_t* argb, int argb_stride, #define PREMULTIPLY(x, m) (((x) * (m)) >> 23) // We can't use a 'const int' for the SHUFFLE value, because it has to be an -// immediate in the _mm_shufflexx_epi16() instruction. We really a macro here. -#define APPLY_ALPHA(RGBX, SHUFFLE, MASK, MULT) do { \ - const __m128i argb0 = _mm_loadl_epi64((__m128i*)&(RGBX)); \ - const __m128i argb1 = _mm_unpacklo_epi8(argb0, zero); \ - const __m128i alpha0 = _mm_and_si128(argb1, MASK); \ - const __m128i alpha1 = _mm_shufflelo_epi16(alpha0, SHUFFLE); \ - const __m128i alpha2 = _mm_shufflehi_epi16(alpha1, SHUFFLE); \ - /* alpha2 = [0 a0 a0 a0][0 a1 a1 a1] */ \ - const __m128i scale0 = _mm_mullo_epi16(alpha2, MULT); \ - const __m128i scale1 = _mm_mulhi_epu16(alpha2, MULT); \ - const __m128i argb2 = _mm_mulhi_epu16(argb1, scale0); \ - const __m128i argb3 = _mm_mullo_epi16(argb1, scale1); \ - const __m128i argb4 = _mm_adds_epu16(argb2, argb3); \ - const __m128i argb5 = _mm_srli_epi16(argb4, 7); \ - const __m128i argb6 = _mm_or_si128(argb5, alpha0); \ - const __m128i argb7 = _mm_packus_epi16(argb6, zero); \ - _mm_storel_epi64((__m128i*)&(RGBX), argb7); \ +// immediate in the _mm_shufflexx_epi16() instruction. We really need a macro. +// We use: v / 255 = (v * 0x8081) >> 23, where v = alpha * {r,g,b} is a 16bit +// value. +#define APPLY_ALPHA(RGBX, SHUFFLE) do { \ + const __m128i argb0 = _mm_loadu_si128((const __m128i*)&(RGBX)); \ + const __m128i argb1_lo = _mm_unpacklo_epi8(argb0, zero); \ + const __m128i argb1_hi = _mm_unpackhi_epi8(argb0, zero); \ + const __m128i alpha0_lo = _mm_or_si128(argb1_lo, kMask); \ + const __m128i alpha0_hi = _mm_or_si128(argb1_hi, kMask); \ + const __m128i alpha1_lo = _mm_shufflelo_epi16(alpha0_lo, SHUFFLE); \ + const __m128i alpha1_hi = _mm_shufflelo_epi16(alpha0_hi, SHUFFLE); \ + const __m128i alpha2_lo = _mm_shufflehi_epi16(alpha1_lo, SHUFFLE); \ + const __m128i alpha2_hi = _mm_shufflehi_epi16(alpha1_hi, SHUFFLE); \ + /* alpha2 = [ff a0 a0 a0][ff a1 a1 a1] */ \ + const __m128i A0_lo = _mm_mullo_epi16(alpha2_lo, argb1_lo); \ + const __m128i A0_hi = _mm_mullo_epi16(alpha2_hi, argb1_hi); \ + const __m128i A1_lo = _mm_mulhi_epu16(A0_lo, kMult); \ + const __m128i A1_hi = _mm_mulhi_epu16(A0_hi, kMult); \ + const __m128i A2_lo = _mm_srli_epi16(A1_lo, 7); \ + const __m128i A2_hi = _mm_srli_epi16(A1_hi, 7); \ + const __m128i A3 = _mm_packus_epi16(A2_lo, A2_hi); \ + _mm_storeu_si128((__m128i*)&(RGBX), A3); \ } while (0) -static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first, - int w, int h, int stride) { +static void ApplyAlphaMultiply_SSE2(uint8_t* rgba, int alpha_first, + int w, int h, int stride) { const __m128i zero = _mm_setzero_si128(); - const int kSpan = 2; - const int w2 = w & ~(kSpan - 1); + const __m128i kMult = _mm_set1_epi16(0x8081u); + const __m128i kMask = _mm_set_epi16(0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0); + const int kSpan = 4; while (h-- > 0) { uint32_t* const rgbx = (uint32_t*)rgba; int i; if (!alpha_first) { - const __m128i kMask = _mm_set_epi16(0xff, 0, 0, 0, 0xff, 0, 0, 0); - const __m128i kMult = - _mm_set_epi16(0, 0x8081, 0x8081, 0x8081, 0, 0x8081, 0x8081, 0x8081); - for (i = 0; i < w2; i += kSpan) { - APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 3, 3, 3), kMask, kMult); + for (i = 0; i + kSpan <= w; i += kSpan) { + APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(2, 3, 3, 3)); } } else { - const __m128i kMask = _mm_set_epi16(0, 0, 0, 0xff, 0, 0, 0, 0xff); - const __m128i kMult = - _mm_set_epi16(0x8081, 0x8081, 0x8081, 0, 0x8081, 0x8081, 0x8081, 0); - for (i = 0; i < w2; i += kSpan) { - APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 0, 0, 3), kMask, kMult); + for (i = 0; i + kSpan <= w; i += kSpan) { + APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 0, 0, 1)); } } // Finish with left-overs. @@ -213,64 +213,51 @@ static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first, // ----------------------------------------------------------------------------- // Apply alpha value to rows -// We use: kINV255 = (1 << 24) / 255 = 0x010101 -// So: a * kINV255 = (a << 16) | [(a << 8) | a] -// -> _mm_mulhi_epu16() takes care of the (a<<16) part, -// and _mm_mullo_epu16(a * 0x0101,...) takes care of the "(a << 8) | a" one. - -static void MultARGBRow(uint32_t* const ptr, int width, int inverse) { +static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) { int x = 0; if (!inverse) { const int kSpan = 2; const __m128i zero = _mm_setzero_si128(); - const __m128i kRound = - _mm_set_epi16(0, 1 << 7, 1 << 7, 1 << 7, 0, 1 << 7, 1 << 7, 1 << 7); - const __m128i kMult = - _mm_set_epi16(0, 0x0101, 0x0101, 0x0101, 0, 0x0101, 0x0101, 0x0101); - const __m128i kOne64 = _mm_set_epi16(1u << 8, 0, 0, 0, 1u << 8, 0, 0, 0); - const int w2 = width & ~(kSpan - 1); - for (x = 0; x < w2; x += kSpan) { - const __m128i argb0 = _mm_loadl_epi64((__m128i*)&ptr[x]); - const __m128i argb1 = _mm_unpacklo_epi8(argb0, zero); - const __m128i tmp0 = _mm_shufflelo_epi16(argb1, _MM_SHUFFLE(3, 3, 3, 3)); - const __m128i tmp1 = _mm_shufflehi_epi16(tmp0, _MM_SHUFFLE(3, 3, 3, 3)); - const __m128i tmp2 = _mm_srli_epi64(tmp1, 16); - const __m128i scale0 = _mm_mullo_epi16(tmp1, kMult); - const __m128i scale1 = _mm_or_si128(tmp2, kOne64); - const __m128i argb2 = _mm_mulhi_epu16(argb1, scale0); - const __m128i argb3 = _mm_mullo_epi16(argb1, scale1); - const __m128i argb4 = _mm_adds_epu16(argb2, argb3); - const __m128i argb5 = _mm_adds_epu16(argb4, kRound); - const __m128i argb6 = _mm_srli_epi16(argb5, 8); - const __m128i argb7 = _mm_packus_epi16(argb6, zero); - _mm_storel_epi64((__m128i*)&ptr[x], argb7); + const __m128i k128 = _mm_set1_epi16(128); + const __m128i kMult = _mm_set1_epi16(0x0101); + const __m128i kMask = _mm_set_epi16(0, 0xff, 0, 0, 0, 0xff, 0, 0); + for (x = 0; x + kSpan <= width; x += kSpan) { + // To compute 'result = (int)(a * x / 255. + .5)', we use: + // tmp = a * v + 128, result = (tmp * 0x0101u) >> 16 + const __m128i A0 = _mm_loadl_epi64((const __m128i*)&ptr[x]); + const __m128i A1 = _mm_unpacklo_epi8(A0, zero); + const __m128i A2 = _mm_or_si128(A1, kMask); + const __m128i A3 = _mm_shufflelo_epi16(A2, _MM_SHUFFLE(2, 3, 3, 3)); + const __m128i A4 = _mm_shufflehi_epi16(A3, _MM_SHUFFLE(2, 3, 3, 3)); + // here, A4 = [ff a0 a0 a0][ff a1 a1 a1] + const __m128i A5 = _mm_mullo_epi16(A4, A1); + const __m128i A6 = _mm_add_epi16(A5, k128); + const __m128i A7 = _mm_mulhi_epu16(A6, kMult); + const __m128i A10 = _mm_packus_epi16(A7, zero); + _mm_storel_epi64((__m128i*)&ptr[x], A10); } } width -= x; if (width > 0) WebPMultARGBRowC(ptr + x, width, inverse); } -static void MultRow(uint8_t* const ptr, const uint8_t* const alpha, - int width, int inverse) { +static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha, + int width, int inverse) { int x = 0; if (!inverse) { - const int kSpan = 8; const __m128i zero = _mm_setzero_si128(); - const __m128i kRound = _mm_set1_epi16(1 << 7); - const int w2 = width & ~(kSpan - 1); - for (x = 0; x < w2; x += kSpan) { + const __m128i k128 = _mm_set1_epi16(128); + const __m128i kMult = _mm_set1_epi16(0x0101); + for (x = 0; x + 8 <= width; x += 8) { const __m128i v0 = _mm_loadl_epi64((__m128i*)&ptr[x]); + const __m128i a0 = _mm_loadl_epi64((const __m128i*)&alpha[x]); const __m128i v1 = _mm_unpacklo_epi8(v0, zero); - const __m128i alpha0 = _mm_loadl_epi64((const __m128i*)&alpha[x]); - const __m128i alpha1 = _mm_unpacklo_epi8(alpha0, zero); - const __m128i alpha2 = _mm_unpacklo_epi8(alpha0, alpha0); - const __m128i v2 = _mm_mulhi_epu16(v1, alpha2); - const __m128i v3 = _mm_mullo_epi16(v1, alpha1); - const __m128i v4 = _mm_adds_epu16(v2, v3); - const __m128i v5 = _mm_adds_epu16(v4, kRound); - const __m128i v6 = _mm_srli_epi16(v5, 8); - const __m128i v7 = _mm_packus_epi16(v6, zero); - _mm_storel_epi64((__m128i*)&ptr[x], v7); + const __m128i a1 = _mm_unpacklo_epi8(a0, zero); + const __m128i v2 = _mm_mullo_epi16(v1, a1); + const __m128i v3 = _mm_add_epi16(v2, k128); + const __m128i v4 = _mm_mulhi_epu16(v3, kMult); + const __m128i v5 = _mm_packus_epi16(v4, zero); + _mm_storel_epi64((__m128i*)&ptr[x], v5); } } width -= x; @@ -283,9 +270,9 @@ static void MultRow(uint8_t* const ptr, const uint8_t* const alpha, extern void WebPInitAlphaProcessingSSE2(void); WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) { - WebPMultARGBRow = MultARGBRow; - WebPMultRow = MultRow; - WebPApplyAlphaMultiply = ApplyAlphaMultiply; + WebPMultARGBRow = MultARGBRow_SSE2; + WebPMultRow = MultRow_SSE2; + WebPApplyAlphaMultiply = ApplyAlphaMultiply_SSE2; WebPDispatchAlpha = DispatchAlpha; WebPDispatchAlphaToGreen = DispatchAlphaToGreen; WebPExtractAlpha = ExtractAlpha; diff --git a/src/3rdparty/libwebp/src/dsp/common_sse2.h b/src/3rdparty/libwebp/src/dsp/common_sse2.h index 7cea13fb3cb580afedea46958c33af804fe4bc75..995d7cf4eafde1d74ee87ecc69864789df7d055a 100644 --- a/src/3rdparty/libwebp/src/dsp/common_sse2.h +++ b/src/3rdparty/libwebp/src/dsp/common_sse2.h @@ -100,6 +100,91 @@ static WEBP_INLINE void VP8Transpose_2_4x4_16b( // a03 a13 a23 a33 b03 b13 b23 b33 } +//------------------------------------------------------------------------------ +// Channel mixing. + +// Function used several times in VP8PlanarTo24b. +// It samples the in buffer as follows: one every two unsigned char is stored +// at the beginning of the buffer, while the other half is stored at the end. +#define VP8PlanarTo24bHelper(IN, OUT) \ + do { \ + const __m128i v_mask = _mm_set1_epi16(0x00ff); \ + /* Take one every two upper 8b values.*/ \ + (OUT##0) = _mm_packus_epi16(_mm_and_si128((IN##0), v_mask), \ + _mm_and_si128((IN##1), v_mask)); \ + (OUT##1) = _mm_packus_epi16(_mm_and_si128((IN##2), v_mask), \ + _mm_and_si128((IN##3), v_mask)); \ + (OUT##2) = _mm_packus_epi16(_mm_and_si128((IN##4), v_mask), \ + _mm_and_si128((IN##5), v_mask)); \ + /* Take one every two lower 8b values.*/ \ + (OUT##3) = _mm_packus_epi16(_mm_srli_epi16((IN##0), 8), \ + _mm_srli_epi16((IN##1), 8)); \ + (OUT##4) = _mm_packus_epi16(_mm_srli_epi16((IN##2), 8), \ + _mm_srli_epi16((IN##3), 8)); \ + (OUT##5) = _mm_packus_epi16(_mm_srli_epi16((IN##4), 8), \ + _mm_srli_epi16((IN##5), 8)); \ + } while (0) + +// Pack the planar buffers +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... +static WEBP_INLINE void VP8PlanarTo24b(__m128i* const in0, __m128i* const in1, + __m128i* const in2, __m128i* const in3, + __m128i* const in4, __m128i* const in5) { + // The input is 6 registers of sixteen 8b but for the sake of explanation, + // let's take 6 registers of four 8b values. + // To pack, we will keep taking one every two 8b integer and move it + // around as follows: + // Input: + // r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7 + // Split the 6 registers in two sets of 3 registers: the first set as the even + // 8b bytes, the second the odd ones: + // r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7 + // Repeat the same permutations twice more: + // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7 + // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7 + __m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + VP8PlanarTo24bHelper(*in, tmp); + VP8PlanarTo24bHelper(tmp, *in); + VP8PlanarTo24bHelper(*in, tmp); + // We need to do it two more times than the example as we have sixteen bytes. + { + __m128i out0, out1, out2, out3, out4, out5; + VP8PlanarTo24bHelper(tmp, out); + VP8PlanarTo24bHelper(out, *in); + } +} + +#undef VP8PlanarTo24bHelper + +// Convert four packed four-channel buffers like argbargbargbargb... into the +// split channels aaaaa ... rrrr ... gggg .... bbbbb ...... +static WEBP_INLINE void VP8L32bToPlanar(__m128i* const in0, + __m128i* const in1, + __m128i* const in2, + __m128i* const in3) { + // Column-wise transpose. + const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1); + const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1); + const __m128i A2 = _mm_unpacklo_epi8(*in2, *in3); + const __m128i A3 = _mm_unpackhi_epi8(*in2, *in3); + const __m128i B0 = _mm_unpacklo_epi8(A0, A1); + const __m128i B1 = _mm_unpackhi_epi8(A0, A1); + const __m128i B2 = _mm_unpacklo_epi8(A2, A3); + const __m128i B3 = _mm_unpackhi_epi8(A2, A3); + // C0 = g7 g6 ... g1 g0 | b7 b6 ... b1 b0 + // C1 = a7 a6 ... a1 a0 | r7 r6 ... r1 r0 + const __m128i C0 = _mm_unpacklo_epi8(B0, B1); + const __m128i C1 = _mm_unpackhi_epi8(B0, B1); + const __m128i C2 = _mm_unpacklo_epi8(B2, B3); + const __m128i C3 = _mm_unpackhi_epi8(B2, B3); + // Gather the channels. + *in0 = _mm_unpackhi_epi64(C1, C3); + *in1 = _mm_unpacklo_epi64(C1, C3); + *in2 = _mm_unpackhi_epi64(C0, C2); + *in3 = _mm_unpacklo_epi64(C0, C2); +} + #endif // WEBP_USE_SSE2 #ifdef __cplusplus diff --git a/src/3rdparty/libwebp/src/dsp/cost.c b/src/3rdparty/libwebp/src/dsp/cost.c index fe72d26e7917855688687a5c9560491d6a7d0238..58ddea72487f208112254284cb2dd7978994cc67 100644 --- a/src/3rdparty/libwebp/src/dsp/cost.c +++ b/src/3rdparty/libwebp/src/dsp/cost.c @@ -10,7 +10,7 @@ // Author: Skal (pascal.massimino@gmail.com) #include "./dsp.h" -#include "../enc/cost.h" +#include "../enc/cost_enc.h" //------------------------------------------------------------------------------ // Boolean-cost cost table diff --git a/src/3rdparty/libwebp/src/dsp/cost_mips32.c b/src/3rdparty/libwebp/src/dsp/cost_mips32.c index d1e240e1912cd9018fc31866f64b983be25e89a9..3102da877a06d33dd5009990cbf3275023095d50 100644 --- a/src/3rdparty/libwebp/src/dsp/cost_mips32.c +++ b/src/3rdparty/libwebp/src/dsp/cost_mips32.c @@ -13,7 +13,7 @@ #if defined(WEBP_USE_MIPS32) -#include "../enc/cost.h" +#include "../enc/cost_enc.h" static int GetResidualCost(int ctx0, const VP8Residual* const res) { int temp0, temp1; diff --git a/src/3rdparty/libwebp/src/dsp/cost_mips_dsp_r2.c b/src/3rdparty/libwebp/src/dsp/cost_mips_dsp_r2.c index ce64067756fb03de486d60a85fb87c1cfa9acc2b..6ec8aeb610febc76008e7a6eb47489676b5a10de 100644 --- a/src/3rdparty/libwebp/src/dsp/cost_mips_dsp_r2.c +++ b/src/3rdparty/libwebp/src/dsp/cost_mips_dsp_r2.c @@ -13,7 +13,7 @@ #if defined(WEBP_USE_MIPS_DSP_R2) -#include "../enc/cost.h" +#include "../enc/cost_enc.h" static int GetResidualCost(int ctx0, const VP8Residual* const res) { int temp0, temp1; diff --git a/src/3rdparty/libwebp/src/dsp/cost_sse2.c b/src/3rdparty/libwebp/src/dsp/cost_sse2.c index 0cb1c1fa04421db60625cfee8dc6fe13c3758eed..421d51fdd52bbaedc53be800e77ae5be8911e1b5 100644 --- a/src/3rdparty/libwebp/src/dsp/cost_sse2.c +++ b/src/3rdparty/libwebp/src/dsp/cost_sse2.c @@ -16,8 +16,8 @@ #if defined(WEBP_USE_SSE2) #include <emmintrin.h> -#include "../enc/cost.h" -#include "../enc/vp8enci.h" +#include "../enc/cost_enc.h" +#include "../enc/vp8i_enc.h" #include "../utils/utils.h" //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/dsp/cpu.c b/src/3rdparty/libwebp/src/dsp/cpu.c index cbb08db90ae33840d381519930d5980178fbd8bf..b5583b6e9b3953cfe046b2badcb5340318da0918 100644 --- a/src/3rdparty/libwebp/src/dsp/cpu.c +++ b/src/3rdparty/libwebp/src/dsp/cpu.c @@ -95,26 +95,62 @@ static WEBP_INLINE uint64_t xgetbv(void) { #endif #if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2) + +// helper function for run-time detection of slow SSSE3 platforms +static int CheckSlowModel(int info) { + // Table listing display models with longer latencies for the bsr instruction + // (ie 2 cycles vs 10/16 cycles) and some SSSE3 instructions like pshufb. + // Refer to Intel 64 and IA-32 Architectures Optimization Reference Manual. + static const uint8_t kSlowModels[] = { + 0x37, 0x4a, 0x4d, // Silvermont Microarchitecture + 0x1c, 0x26, 0x27 // Atom Microarchitecture + }; + const uint32_t model = ((info & 0xf0000) >> 12) | ((info >> 4) & 0xf); + const uint32_t family = (info >> 8) & 0xf; + if (family == 0x06) { + size_t i; + for (i = 0; i < sizeof(kSlowModels) / sizeof(kSlowModels[0]); ++i) { + if (model == kSlowModels[i]) return 1; + } + } + return 0; +} + static int x86CPUInfo(CPUFeature feature) { int max_cpuid_value; int cpu_info[4]; + int is_intel = 0; // get the highest feature value cpuid supports GetCPUInfo(cpu_info, 0); max_cpuid_value = cpu_info[0]; if (max_cpuid_value < 1) { return 0; + } else { + const int VENDOR_ID_INTEL_EBX = 0x756e6547; // uneG + const int VENDOR_ID_INTEL_EDX = 0x49656e69; // Ieni + const int VENDOR_ID_INTEL_ECX = 0x6c65746e; // letn + is_intel = (cpu_info[1] == VENDOR_ID_INTEL_EBX && + cpu_info[2] == VENDOR_ID_INTEL_ECX && + cpu_info[3] == VENDOR_ID_INTEL_EDX); // genuine Intel? } GetCPUInfo(cpu_info, 1); if (feature == kSSE2) { - return 0 != (cpu_info[3] & 0x04000000); + return !!(cpu_info[3] & (1 << 26)); } if (feature == kSSE3) { - return 0 != (cpu_info[2] & 0x00000001); + return !!(cpu_info[2] & (1 << 0)); + } + if (feature == kSlowSSSE3) { + if (is_intel && (cpu_info[2] & (1 << 0))) { // SSSE3? + return CheckSlowModel(cpu_info[0]); + } + return 0; } + if (feature == kSSE4_1) { - return 0 != (cpu_info[2] & 0x00080000); + return !!(cpu_info[2] & (1 << 19)); } if (feature == kAVX) { // bits 27 (OSXSAVE) & 28 (256-bit AVX) @@ -126,7 +162,7 @@ static int x86CPUInfo(CPUFeature feature) { if (feature == kAVX2) { if (x86CPUInfo(kAVX) && max_cpuid_value >= 7) { GetCPUInfo(cpu_info, 7); - return ((cpu_info[1] & 0x00000020) == 0x00000020); + return !!(cpu_info[1] & (1 << 5)); } } return 0; @@ -184,4 +220,3 @@ VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo; #else VP8CPUInfo VP8GetCPUInfo = NULL; #endif - diff --git a/src/3rdparty/libwebp/src/dsp/dec.c b/src/3rdparty/libwebp/src/dsp/dec.c index e92d693362211cf1f6fbc048667c34ed9cb5f768..007e985d8b62e01f5f7045ff28d0c5b0e5c22300 100644 --- a/src/3rdparty/libwebp/src/dsp/dec.c +++ b/src/3rdparty/libwebp/src/dsp/dec.c @@ -12,7 +12,7 @@ // Author: Skal (pascal.massimino@gmail.com) #include "./dsp.h" -#include "../dec/vp8i.h" +#include "../dec/vp8i_dec.h" #include "../utils/utils.h" //------------------------------------------------------------------------------ @@ -239,7 +239,7 @@ VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES]; //------------------------------------------------------------------------------ // 4x4 -#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) +#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2)) #define AVG2(a, b) (((a) + (b) + 1) >> 1) static void VE4(uint8_t* dst) { // vertical diff --git a/src/3rdparty/libwebp/src/dsp/dec_clip_tables.c b/src/3rdparty/libwebp/src/dsp/dec_clip_tables.c index 3b6dde86ba0b605be21f40342e5f1d2e4d43a3d6..74ba34c0bb61509a74abba70aa96f050c139d4cd 100644 --- a/src/3rdparty/libwebp/src/dsp/dec_clip_tables.c +++ b/src/3rdparty/libwebp/src/dsp/dec_clip_tables.c @@ -63,7 +63,7 @@ static const uint8_t abs0[255 + 255 + 1] = { 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; -static const int8_t sclip1[1020 + 1020 + 1] = { +static const uint8_t sclip1[1020 + 1020 + 1] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, @@ -236,7 +236,7 @@ static const int8_t sclip1[1020 + 1020 + 1] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }; -static const int8_t sclip2[112 + 112 + 1] = { +static const uint8_t sclip2[112 + 112 + 1] = { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, @@ -339,8 +339,8 @@ static volatile int tables_ok = 0; #endif -const int8_t* const VP8ksclip1 = &sclip1[1020]; -const int8_t* const VP8ksclip2 = &sclip2[112]; +const int8_t* const VP8ksclip1 = (const int8_t*)&sclip1[1020]; +const int8_t* const VP8ksclip2 = (const int8_t*)&sclip2[112]; const uint8_t* const VP8kclip1 = &clip1[255]; const uint8_t* const VP8kabs0 = &abs0[255]; diff --git a/src/3rdparty/libwebp/src/dsp/dec_msa.c b/src/3rdparty/libwebp/src/dsp/dec_msa.c index f76055cab07c4fdfb47dc145880d4fdbac57c95d..8d9c98c3cfe1e5d65a3cf56c2103cbb6f1c0fc63 100644 --- a/src/3rdparty/libwebp/src/dsp/dec_msa.c +++ b/src/3rdparty/libwebp/src/dsp/dec_msa.c @@ -153,6 +153,820 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) { ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS); } +//------------------------------------------------------------------------------ +// Edge filtering functions + +#define FLIP_SIGN2(in0, in1, out0, out1) { \ + out0 = (v16i8)__msa_xori_b(in0, 0x80); \ + out1 = (v16i8)__msa_xori_b(in1, 0x80); \ +} + +#define FLIP_SIGN4(in0, in1, in2, in3, out0, out1, out2, out3) { \ + FLIP_SIGN2(in0, in1, out0, out1); \ + FLIP_SIGN2(in2, in3, out2, out3); \ +} + +#define FILT_VAL(q0_m, p0_m, mask, filt) do { \ + v16i8 q0_sub_p0; \ + q0_sub_p0 = __msa_subs_s_b(q0_m, p0_m); \ + filt = __msa_adds_s_b(filt, q0_sub_p0); \ + filt = __msa_adds_s_b(filt, q0_sub_p0); \ + filt = __msa_adds_s_b(filt, q0_sub_p0); \ + filt = filt & mask; \ +} while (0) + +#define FILT2(q_m, p_m, q, p) do { \ + u_r = SRAI_H(temp1, 7); \ + u_r = __msa_sat_s_h(u_r, 7); \ + u_l = SRAI_H(temp3, 7); \ + u_l = __msa_sat_s_h(u_l, 7); \ + u = __msa_pckev_b((v16i8)u_l, (v16i8)u_r); \ + q_m = __msa_subs_s_b(q_m, u); \ + p_m = __msa_adds_s_b(p_m, u); \ + q = __msa_xori_b((v16u8)q_m, 0x80); \ + p = __msa_xori_b((v16u8)p_m, 0x80); \ +} while (0) + +#define LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev) do { \ + v16i8 p1_m, p0_m, q0_m, q1_m; \ + v16i8 filt, t1, t2; \ + const v16i8 cnst4b = __msa_ldi_b(4); \ + const v16i8 cnst3b = __msa_ldi_b(3); \ + \ + FLIP_SIGN4(p1, p0, q0, q1, p1_m, p0_m, q0_m, q1_m); \ + filt = __msa_subs_s_b(p1_m, q1_m); \ + filt = filt & hev; \ + FILT_VAL(q0_m, p0_m, mask, filt); \ + t1 = __msa_adds_s_b(filt, cnst4b); \ + t1 = SRAI_B(t1, 3); \ + t2 = __msa_adds_s_b(filt, cnst3b); \ + t2 = SRAI_B(t2, 3); \ + q0_m = __msa_subs_s_b(q0_m, t1); \ + q0 = __msa_xori_b((v16u8)q0_m, 0x80); \ + p0_m = __msa_adds_s_b(p0_m, t2); \ + p0 = __msa_xori_b((v16u8)p0_m, 0x80); \ + filt = __msa_srari_b(t1, 1); \ + hev = __msa_xori_b(hev, 0xff); \ + filt = filt & hev; \ + q1_m = __msa_subs_s_b(q1_m, filt); \ + q1 = __msa_xori_b((v16u8)q1_m, 0x80); \ + p1_m = __msa_adds_s_b(p1_m, filt); \ + p1 = __msa_xori_b((v16u8)p1_m, 0x80); \ +} while (0) + +#define LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev) do { \ + v16i8 p2_m, p1_m, p0_m, q2_m, q1_m, q0_m; \ + v16i8 u, filt, t1, t2, filt_sign; \ + v8i16 filt_r, filt_l, u_r, u_l; \ + v8i16 temp0, temp1, temp2, temp3; \ + const v16i8 cnst4b = __msa_ldi_b(4); \ + const v16i8 cnst3b = __msa_ldi_b(3); \ + const v8i16 cnst9h = __msa_ldi_h(9); \ + \ + FLIP_SIGN4(p1, p0, q0, q1, p1_m, p0_m, q0_m, q1_m); \ + filt = __msa_subs_s_b(p1_m, q1_m); \ + FILT_VAL(q0_m, p0_m, mask, filt); \ + FLIP_SIGN2(p2, q2, p2_m, q2_m); \ + t2 = filt & hev; \ + /* filt_val &= ~hev */ \ + hev = __msa_xori_b(hev, 0xff); \ + filt = filt & hev; \ + t1 = __msa_adds_s_b(t2, cnst4b); \ + t1 = SRAI_B(t1, 3); \ + t2 = __msa_adds_s_b(t2, cnst3b); \ + t2 = SRAI_B(t2, 3); \ + q0_m = __msa_subs_s_b(q0_m, t1); \ + p0_m = __msa_adds_s_b(p0_m, t2); \ + filt_sign = __msa_clti_s_b(filt, 0); \ + ILVRL_B2_SH(filt_sign, filt, filt_r, filt_l); \ + /* update q2/p2 */ \ + temp0 = filt_r * cnst9h; \ + temp1 = ADDVI_H(temp0, 63); \ + temp2 = filt_l * cnst9h; \ + temp3 = ADDVI_H(temp2, 63); \ + FILT2(q2_m, p2_m, q2, p2); \ + /* update q1/p1 */ \ + temp1 = temp1 + temp0; \ + temp3 = temp3 + temp2; \ + FILT2(q1_m, p1_m, q1, p1); \ + /* update q0/p0 */ \ + temp1 = temp1 + temp0; \ + temp3 = temp3 + temp2; \ + FILT2(q0_m, p0_m, q0, p0); \ +} while (0) + +#define LPF_MASK_HEV(p3_in, p2_in, p1_in, p0_in, \ + q0_in, q1_in, q2_in, q3_in, \ + limit_in, b_limit_in, thresh_in, \ + hev_out, mask_out) do { \ + v16u8 p3_asub_p2_m, p2_asub_p1_m, p1_asub_p0_m, q1_asub_q0_m; \ + v16u8 p1_asub_q1_m, p0_asub_q0_m, q3_asub_q2_m, q2_asub_q1_m; \ + v16u8 flat_out; \ + \ + /* absolute subtraction of pixel values */ \ + p3_asub_p2_m = __msa_asub_u_b(p3_in, p2_in); \ + p2_asub_p1_m = __msa_asub_u_b(p2_in, p1_in); \ + p1_asub_p0_m = __msa_asub_u_b(p1_in, p0_in); \ + q1_asub_q0_m = __msa_asub_u_b(q1_in, q0_in); \ + q2_asub_q1_m = __msa_asub_u_b(q2_in, q1_in); \ + q3_asub_q2_m = __msa_asub_u_b(q3_in, q2_in); \ + p0_asub_q0_m = __msa_asub_u_b(p0_in, q0_in); \ + p1_asub_q1_m = __msa_asub_u_b(p1_in, q1_in); \ + /* calculation of hev */ \ + flat_out = __msa_max_u_b(p1_asub_p0_m, q1_asub_q0_m); \ + hev_out = (thresh_in < flat_out); \ + /* calculation of mask */ \ + p0_asub_q0_m = __msa_adds_u_b(p0_asub_q0_m, p0_asub_q0_m); \ + p1_asub_q1_m = SRAI_B(p1_asub_q1_m, 1); \ + p0_asub_q0_m = __msa_adds_u_b(p0_asub_q0_m, p1_asub_q1_m); \ + mask_out = (b_limit_in < p0_asub_q0_m); \ + mask_out = __msa_max_u_b(flat_out, mask_out); \ + p3_asub_p2_m = __msa_max_u_b(p3_asub_p2_m, p2_asub_p1_m); \ + mask_out = __msa_max_u_b(p3_asub_p2_m, mask_out); \ + q2_asub_q1_m = __msa_max_u_b(q2_asub_q1_m, q3_asub_q2_m); \ + mask_out = __msa_max_u_b(q2_asub_q1_m, mask_out); \ + mask_out = (limit_in < mask_out); \ + mask_out = __msa_xori_b(mask_out, 0xff); \ +} while (0) + +#define ST6x1_UB(in0, in0_idx, in1, in1_idx, pdst, stride) do { \ + const uint16_t tmp0_h = __msa_copy_s_h((v8i16)in1, in1_idx); \ + const uint32_t tmp0_w = __msa_copy_s_w((v4i32)in0, in0_idx); \ + SW(tmp0_w, pdst); \ + SH(tmp0_h, pdst + stride); \ +} while (0) + +#define ST6x4_UB(in0, start_in0_idx, in1, start_in1_idx, pdst, stride) do { \ + uint8_t* ptmp1 = (uint8_t*)pdst; \ + ST6x1_UB(in0, start_in0_idx, in1, start_in1_idx, ptmp1, 4); \ + ptmp1 += stride; \ + ST6x1_UB(in0, start_in0_idx + 1, in1, start_in1_idx + 1, ptmp1, 4); \ + ptmp1 += stride; \ + ST6x1_UB(in0, start_in0_idx + 2, in1, start_in1_idx + 2, ptmp1, 4); \ + ptmp1 += stride; \ + ST6x1_UB(in0, start_in0_idx + 3, in1, start_in1_idx + 3, ptmp1, 4); \ +} while (0) + +#define LPF_SIMPLE_FILT(p1_in, p0_in, q0_in, q1_in, mask) do { \ + v16i8 p1_m, p0_m, q0_m, q1_m, filt, filt1, filt2; \ + const v16i8 cnst4b = __msa_ldi_b(4); \ + const v16i8 cnst3b = __msa_ldi_b(3); \ + \ + FLIP_SIGN4(p1_in, p0_in, q0_in, q1_in, p1_m, p0_m, q0_m, q1_m); \ + filt = __msa_subs_s_b(p1_m, q1_m); \ + FILT_VAL(q0_m, p0_m, mask, filt); \ + filt1 = __msa_adds_s_b(filt, cnst4b); \ + filt1 = SRAI_B(filt1, 3); \ + filt2 = __msa_adds_s_b(filt, cnst3b); \ + filt2 = SRAI_B(filt2, 3); \ + q0_m = __msa_subs_s_b(q0_m, filt1); \ + p0_m = __msa_adds_s_b(p0_m, filt2); \ + q0_in = __msa_xori_b((v16u8)q0_m, 0x80); \ + p0_in = __msa_xori_b((v16u8)p0_m, 0x80); \ +} while (0) + +#define LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask) do { \ + v16u8 p1_a_sub_q1, p0_a_sub_q0; \ + \ + p0_a_sub_q0 = __msa_asub_u_b(p0, q0); \ + p1_a_sub_q1 = __msa_asub_u_b(p1, q1); \ + p1_a_sub_q1 = (v16u8)__msa_srli_b((v16i8)p1_a_sub_q1, 1); \ + p0_a_sub_q0 = __msa_adds_u_b(p0_a_sub_q0, p0_a_sub_q0); \ + mask = __msa_adds_u_b(p0_a_sub_q0, p1_a_sub_q1); \ + mask = (mask <= b_limit); \ +} while (0) + +static void VFilter16(uint8_t* src, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint8_t* ptemp = src - 4 * stride; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0; + v16u8 mask, hev; + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + + LD_UB8(ptemp, stride, p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev); + ptemp = src - 3 * stride; + ST_UB4(p2, p1, p0, q0, ptemp, stride); + ptemp += (4 * stride); + ST_UB2(q1, q2, ptemp, stride); +} + +static void HFilter16(uint8_t* src, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint8_t* ptmp = src - 4; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0; + v16u8 mask, hev; + v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8; + v16u8 row9, row10, row11, row12, row13, row14, row15; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + + LD_UB8(ptmp, stride, row0, row1, row2, row3, row4, row5, row6, row7); + ptmp += (8 * stride); + LD_UB8(ptmp, stride, row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev); + ILVR_B2_SH(p1, p2, q0, p0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp3, tmp4); + ILVL_B2_SH(p1, p2, q0, p0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp6, tmp7); + ILVRL_B2_SH(q2, q1, tmp2, tmp5); + ptmp = src - 3; + ST6x1_UB(tmp3, 0, tmp2, 0, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp3, 1, tmp2, 1, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp3, 2, tmp2, 2, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp3, 3, tmp2, 3, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp4, 0, tmp2, 4, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp4, 1, tmp2, 5, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp4, 2, tmp2, 6, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp4, 3, tmp2, 7, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp6, 0, tmp5, 0, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp6, 1, tmp5, 1, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp6, 2, tmp5, 2, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp6, 3, tmp5, 3, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp7, 0, tmp5, 4, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp7, 1, tmp5, 5, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp7, 2, tmp5, 6, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp7, 3, tmp5, 7, ptmp, 4); +} + +// on three inner edges +static void VFilterHorEdge16i(uint8_t* src, int stride, + int b_limit, int limit, int thresh) { + v16u8 mask, hev; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0; + const v16u8 thresh0 = (v16u8)__msa_fill_b(thresh); + const v16u8 b_limit0 = (v16u8)__msa_fill_b(b_limit); + const v16u8 limit0 = (v16u8)__msa_fill_b(limit); + + LD_UB8((src - 4 * stride), stride, p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit0, b_limit0, thresh0, + hev, mask); + LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev); + ST_UB4(p1, p0, q0, q1, (src - 2 * stride), stride); +} + +static void VFilter16i(uint8_t* src_y, int stride, + int b_limit, int limit, int thresh) { + VFilterHorEdge16i(src_y + 4 * stride, stride, b_limit, limit, thresh); + VFilterHorEdge16i(src_y + 8 * stride, stride, b_limit, limit, thresh); + VFilterHorEdge16i(src_y + 12 * stride, stride, b_limit, limit, thresh); +} + +static void HFilterVertEdge16i(uint8_t* src, int stride, + int b_limit, int limit, int thresh) { + v16u8 mask, hev; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0; + v16u8 row0, row1, row2, row3, row4, row5, row6, row7; + v16u8 row8, row9, row10, row11, row12, row13, row14, row15; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + const v16u8 thresh0 = (v16u8)__msa_fill_b(thresh); + const v16u8 b_limit0 = (v16u8)__msa_fill_b(b_limit); + const v16u8 limit0 = (v16u8)__msa_fill_b(limit); + + LD_UB8(src - 4, stride, row0, row1, row2, row3, row4, row5, row6, row7); + LD_UB8(src - 4 + (8 * stride), stride, + row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit0, b_limit0, thresh0, + hev, mask); + LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev); + ILVR_B2_SH(p0, p1, q1, q0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp2, tmp3); + ILVL_B2_SH(p0, p1, q1, q0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp4, tmp5); + src -= 2; + ST4x8_UB(tmp2, tmp3, src, stride); + src += (8 * stride); + ST4x8_UB(tmp4, tmp5, src, stride); +} + +static void HFilter16i(uint8_t* src_y, int stride, + int b_limit, int limit, int thresh) { + HFilterVertEdge16i(src_y + 4, stride, b_limit, limit, thresh); + HFilterVertEdge16i(src_y + 8, stride, b_limit, limit, thresh); + HFilterVertEdge16i(src_y + 12, stride, b_limit, limit, thresh); +} + +// 8-pixels wide variants, for chroma filtering +static void VFilter8(uint8_t* src_u, uint8_t* src_v, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint8_t* ptmp_src_u = src_u - 4 * stride; + uint8_t* ptmp_src_v = src_v - 4 * stride; + uint64_t p2_d, p1_d, p0_d, q0_d, q1_d, q2_d; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; + v16u8 p3_u, p2_u, p1_u, p0_u, q3_u, q2_u, q1_u, q0_u; + v16u8 p3_v, p2_v, p1_v, p0_v, q3_v, q2_v, q1_v, q0_v; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + + LD_UB8(ptmp_src_u, stride, p3_u, p2_u, p1_u, p0_u, q0_u, q1_u, q2_u, q3_u); + LD_UB8(ptmp_src_v, stride, p3_v, p2_v, p1_v, p0_v, q0_v, q1_v, q2_v, q3_v); + ILVR_D4_UB(p3_v, p3_u, p2_v, p2_u, p1_v, p1_u, p0_v, p0_u, p3, p2, p1, p0); + ILVR_D4_UB(q0_v, q0_u, q1_v, q1_u, q2_v, q2_u, q3_v, q3_u, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev); + p2_d = __msa_copy_s_d((v2i64)p2, 0); + p1_d = __msa_copy_s_d((v2i64)p1, 0); + p0_d = __msa_copy_s_d((v2i64)p0, 0); + q0_d = __msa_copy_s_d((v2i64)q0, 0); + q1_d = __msa_copy_s_d((v2i64)q1, 0); + q2_d = __msa_copy_s_d((v2i64)q2, 0); + ptmp_src_u += stride; + SD4(p2_d, p1_d, p0_d, q0_d, ptmp_src_u, stride); + ptmp_src_u += (4 * stride); + SD(q1_d, ptmp_src_u); + ptmp_src_u += stride; + SD(q2_d, ptmp_src_u); + p2_d = __msa_copy_s_d((v2i64)p2, 1); + p1_d = __msa_copy_s_d((v2i64)p1, 1); + p0_d = __msa_copy_s_d((v2i64)p0, 1); + q0_d = __msa_copy_s_d((v2i64)q0, 1); + q1_d = __msa_copy_s_d((v2i64)q1, 1); + q2_d = __msa_copy_s_d((v2i64)q2, 1); + ptmp_src_v += stride; + SD4(p2_d, p1_d, p0_d, q0_d, ptmp_src_v, stride); + ptmp_src_v += (4 * stride); + SD(q1_d, ptmp_src_v); + ptmp_src_v += stride; + SD(q2_d, ptmp_src_v); +} + +static void HFilter8(uint8_t* src_u, uint8_t* src_v, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint8_t* ptmp_src_u = src_u - 4; + uint8_t* ptmp_src_v = src_v - 4; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; + v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8; + v16u8 row9, row10, row11, row12, row13, row14, row15; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + + LD_UB8(ptmp_src_u, stride, row0, row1, row2, row3, row4, row5, row6, row7); + LD_UB8(ptmp_src_v, stride, + row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev); + ILVR_B2_SH(p1, p2, q0, p0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp3, tmp4); + ILVL_B2_SH(p1, p2, q0, p0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp6, tmp7); + ILVRL_B2_SH(q2, q1, tmp2, tmp5); + ptmp_src_u += 1; + ST6x4_UB(tmp3, 0, tmp2, 0, ptmp_src_u, stride); + ptmp_src_u += 4 * stride; + ST6x4_UB(tmp4, 0, tmp2, 4, ptmp_src_u, stride); + ptmp_src_v += 1; + ST6x4_UB(tmp6, 0, tmp5, 0, ptmp_src_v, stride); + ptmp_src_v += 4 * stride; + ST6x4_UB(tmp7, 0, tmp5, 4, ptmp_src_v, stride); +} + +static void VFilter8i(uint8_t* src_u, uint8_t* src_v, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint64_t p1_d, p0_d, q0_d, q1_d; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; + v16u8 p3_u, p2_u, p1_u, p0_u, q3_u, q2_u, q1_u, q0_u; + v16u8 p3_v, p2_v, p1_v, p0_v, q3_v, q2_v, q1_v, q0_v; + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + + LD_UB8(src_u, stride, p3_u, p2_u, p1_u, p0_u, q0_u, q1_u, q2_u, q3_u); + src_u += (5 * stride); + LD_UB8(src_v, stride, p3_v, p2_v, p1_v, p0_v, q0_v, q1_v, q2_v, q3_v); + src_v += (5 * stride); + ILVR_D4_UB(p3_v, p3_u, p2_v, p2_u, p1_v, p1_u, p0_v, p0_u, p3, p2, p1, p0); + ILVR_D4_UB(q0_v, q0_u, q1_v, q1_u, q2_v, q2_u, q3_v, q3_u, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev); + p1_d = __msa_copy_s_d((v2i64)p1, 0); + p0_d = __msa_copy_s_d((v2i64)p0, 0); + q0_d = __msa_copy_s_d((v2i64)q0, 0); + q1_d = __msa_copy_s_d((v2i64)q1, 0); + SD4(q1_d, q0_d, p0_d, p1_d, src_u, -stride); + p1_d = __msa_copy_s_d((v2i64)p1, 1); + p0_d = __msa_copy_s_d((v2i64)p0, 1); + q0_d = __msa_copy_s_d((v2i64)q0, 1); + q1_d = __msa_copy_s_d((v2i64)q1, 1); + SD4(q1_d, q0_d, p0_d, p1_d, src_v, -stride); +} + +static void HFilter8i(uint8_t* src_u, uint8_t* src_v, int stride, + int b_limit_in, int limit_in, int thresh_in) { + v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; + v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8; + v16u8 row9, row10, row11, row12, row13, row14, row15; + v4i32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + + LD_UB8(src_u, stride, row0, row1, row2, row3, row4, row5, row6, row7); + LD_UB8(src_v, stride, + row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev); + ILVR_B2_SW(p0, p1, q1, q0, tmp0, tmp1); + ILVRL_H2_SW(tmp1, tmp0, tmp2, tmp3); + ILVL_B2_SW(p0, p1, q1, q0, tmp0, tmp1); + ILVRL_H2_SW(tmp1, tmp0, tmp4, tmp5); + src_u += 2; + ST4x4_UB(tmp2, tmp2, 0, 1, 2, 3, src_u, stride); + src_u += 4 * stride; + ST4x4_UB(tmp3, tmp3, 0, 1, 2, 3, src_u, stride); + src_v += 2; + ST4x4_UB(tmp4, tmp4, 0, 1, 2, 3, src_v, stride); + src_v += 4 * stride; + ST4x4_UB(tmp5, tmp5, 0, 1, 2, 3, src_v, stride); +} + +static void SimpleVFilter16(uint8_t* src, int stride, int b_limit_in) { + v16u8 p1, p0, q1, q0, mask; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + + LD_UB4(src - 2 * stride, stride, p1, p0, q0, q1); + LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask); + LPF_SIMPLE_FILT(p1, p0, q0, q1, mask); + ST_UB2(p0, q0, src - stride, stride); +} + +static void SimpleHFilter16(uint8_t* src, int stride, int b_limit_in) { + v16u8 p1, p0, q1, q0, mask, row0, row1, row2, row3, row4, row5, row6, row7; + v16u8 row8, row9, row10, row11, row12, row13, row14, row15; + v8i16 tmp0, tmp1; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + uint8_t* ptemp_src = src - 2; + + LD_UB8(ptemp_src, stride, row0, row1, row2, row3, row4, row5, row6, row7); + LD_UB8(ptemp_src + 8 * stride, stride, + row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x4_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p1, p0, q0, q1); + LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask); + LPF_SIMPLE_FILT(p1, p0, q0, q1, mask); + ILVRL_B2_SH(q0, p0, tmp1, tmp0); + ptemp_src += 1; + ST2x4_UB(tmp1, 0, ptemp_src, stride); + ptemp_src += 4 * stride; + ST2x4_UB(tmp1, 4, ptemp_src, stride); + ptemp_src += 4 * stride; + ST2x4_UB(tmp0, 0, ptemp_src, stride); + ptemp_src += 4 * stride; + ST2x4_UB(tmp0, 4, ptemp_src, stride); + ptemp_src += 4 * stride; +} + +static void SimpleVFilter16i(uint8_t* src_y, int stride, int b_limit_in) { + SimpleVFilter16(src_y + 4 * stride, stride, b_limit_in); + SimpleVFilter16(src_y + 8 * stride, stride, b_limit_in); + SimpleVFilter16(src_y + 12 * stride, stride, b_limit_in); +} + +static void SimpleHFilter16i(uint8_t* src_y, int stride, int b_limit_in) { + SimpleHFilter16(src_y + 4, stride, b_limit_in); + SimpleHFilter16(src_y + 8, stride, b_limit_in); + SimpleHFilter16(src_y + 12, stride, b_limit_in); +} + +//------------------------------------------------------------------------------ +// Intra predictions +//------------------------------------------------------------------------------ + +// 4x4 + +static void DC4(uint8_t* dst) { // DC + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS]; + dc >>= 3; + dc = dc | (dc << 8) | (dc << 16) | (dc << 24); + SW4(dc, dc, dc, dc, dst, BPS); +} + +static void TM4(uint8_t* dst) { + const uint8_t* const ptemp = dst - BPS - 1; + v8i16 T, d, r0, r1, r2, r3; + const v16i8 zero = { 0 }; + const v8i16 TL = (v8i16)__msa_fill_h(ptemp[0 * BPS]); + const v8i16 L0 = (v8i16)__msa_fill_h(ptemp[1 * BPS]); + const v8i16 L1 = (v8i16)__msa_fill_h(ptemp[2 * BPS]); + const v8i16 L2 = (v8i16)__msa_fill_h(ptemp[3 * BPS]); + const v8i16 L3 = (v8i16)__msa_fill_h(ptemp[4 * BPS]); + const v16u8 T1 = LD_UB(ptemp + 1); + + T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1); + d = T - TL; + ADD4(d, L0, d, L1, d, L2, d, L3, r0, r1, r2, r3); + CLIP_SH4_0_255(r0, r1, r2, r3); + PCKEV_ST4x4_UB(r0, r1, r2, r3, dst, BPS); +} + +static void VE4(uint8_t* dst) { // vertical + const uint8_t* const ptop = dst - BPS - 1; + const uint32_t val0 = LW(ptop + 0); + const uint32_t val1 = LW(ptop + 4); + uint32_t out; + v16u8 A, B, C, AC, B2, R; + + INSERT_W2_UB(val0, val1, A); + B = SLDI_UB(A, A, 1); + C = SLDI_UB(A, A, 2); + AC = __msa_ave_u_b(A, C); + B2 = __msa_ave_u_b(B, B); + R = __msa_aver_u_b(AC, B2); + out = __msa_copy_s_w((v4i32)R, 0); + SW4(out, out, out, out, dst, BPS); +} + +static void RD4(uint8_t* dst) { // Down-right + const uint8_t* const ptop = dst - 1 - BPS; + uint32_t val0 = LW(ptop + 0); + uint32_t val1 = LW(ptop + 4); + uint32_t val2, val3; + v16u8 A, B, C, AC, B2, R, A1; + + INSERT_W2_UB(val0, val1, A1); + A = SLDI_UB(A1, A1, 12); + A = (v16u8)__msa_insert_b((v16i8)A, 3, ptop[1 * BPS]); + A = (v16u8)__msa_insert_b((v16i8)A, 2, ptop[2 * BPS]); + A = (v16u8)__msa_insert_b((v16i8)A, 1, ptop[3 * BPS]); + A = (v16u8)__msa_insert_b((v16i8)A, 0, ptop[4 * BPS]); + B = SLDI_UB(A, A, 1); + C = SLDI_UB(A, A, 2); + AC = __msa_ave_u_b(A, C); + B2 = __msa_ave_u_b(B, B); + R = __msa_aver_u_b(AC, B2); + val3 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val2 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val1 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val0 = __msa_copy_s_w((v4i32)R, 0); + SW4(val0, val1, val2, val3, dst, BPS); +} + +static void LD4(uint8_t* dst) { // Down-Left + const uint8_t* const ptop = dst - BPS; + uint32_t val0 = LW(ptop + 0); + uint32_t val1 = LW(ptop + 4); + uint32_t val2, val3; + v16u8 A, B, C, AC, B2, R; + + INSERT_W2_UB(val0, val1, A); + B = SLDI_UB(A, A, 1); + C = SLDI_UB(A, A, 2); + C = (v16u8)__msa_insert_b((v16i8)C, 6, ptop[7]); + AC = __msa_ave_u_b(A, C); + B2 = __msa_ave_u_b(B, B); + R = __msa_aver_u_b(AC, B2); + val0 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val1 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val2 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val3 = __msa_copy_s_w((v4i32)R, 0); + SW4(val0, val1, val2, val3, dst, BPS); +} + +// 16x16 + +static void DC16(uint8_t* dst) { // DC + uint32_t dc = 16; + int i; + const v16u8 rtop = LD_UB(dst - BPS); + const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); + v16u8 out; + + for (i = 0; i < 16; ++i) { + dc += dst[-1 + i * BPS]; + } + dc += HADD_UH_U32(dctop); + out = (v16u8)__msa_fill_b(dc >> 5); + ST_UB8(out, out, out, out, out, out, out, out, dst, BPS); + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); +} + +static void TM16(uint8_t* dst) { + int j; + v8i16 d1, d2; + const v16i8 zero = { 0 }; + const v8i16 TL = (v8i16)__msa_fill_h(dst[-1 - BPS]); + const v16i8 T = LD_SB(dst - BPS); + + ILVRL_B2_SH(zero, T, d1, d2); + SUB2(d1, TL, d2, TL, d1, d2); + for (j = 0; j < 16; j += 4) { + v16i8 t0, t1, t2, t3; + v8i16 r0, r1, r2, r3, r4, r5, r6, r7; + const v8i16 L0 = (v8i16)__msa_fill_h(dst[-1 + 0 * BPS]); + const v8i16 L1 = (v8i16)__msa_fill_h(dst[-1 + 1 * BPS]); + const v8i16 L2 = (v8i16)__msa_fill_h(dst[-1 + 2 * BPS]); + const v8i16 L3 = (v8i16)__msa_fill_h(dst[-1 + 3 * BPS]); + ADD4(d1, L0, d1, L1, d1, L2, d1, L3, r0, r1, r2, r3); + ADD4(d2, L0, d2, L1, d2, L2, d2, L3, r4, r5, r6, r7); + CLIP_SH4_0_255(r0, r1, r2, r3); + CLIP_SH4_0_255(r4, r5, r6, r7); + PCKEV_B4_SB(r4, r0, r5, r1, r6, r2, r7, r3, t0, t1, t2, t3); + ST_SB4(t0, t1, t2, t3, dst, BPS); + dst += 4 * BPS; + } +} + +static void VE16(uint8_t* dst) { // vertical + const v16u8 rtop = LD_UB(dst - BPS); + ST_UB8(rtop, rtop, rtop, rtop, rtop, rtop, rtop, rtop, dst, BPS); + ST_UB8(rtop, rtop, rtop, rtop, rtop, rtop, rtop, rtop, dst + 8 * BPS, BPS); +} + +static void HE16(uint8_t* dst) { // horizontal + int j; + for (j = 16; j > 0; j -= 4) { + const v16u8 L0 = (v16u8)__msa_fill_b(dst[-1 + 0 * BPS]); + const v16u8 L1 = (v16u8)__msa_fill_b(dst[-1 + 1 * BPS]); + const v16u8 L2 = (v16u8)__msa_fill_b(dst[-1 + 2 * BPS]); + const v16u8 L3 = (v16u8)__msa_fill_b(dst[-1 + 3 * BPS]); + ST_UB4(L0, L1, L2, L3, dst, BPS); + dst += 4 * BPS; + } +} + +static void DC16NoTop(uint8_t* dst) { // DC with top samples not available + int j; + uint32_t dc = 8; + v16u8 out; + + for (j = 0; j < 16; ++j) { + dc += dst[-1 + j * BPS]; + } + out = (v16u8)__msa_fill_b(dc >> 4); + ST_UB8(out, out, out, out, out, out, out, out, dst, BPS); + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); +} + +static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available + uint32_t dc = 8; + const v16u8 rtop = LD_UB(dst - BPS); + const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); + v16u8 out; + + dc += HADD_UH_U32(dctop); + out = (v16u8)__msa_fill_b(dc >> 4); + ST_UB8(out, out, out, out, out, out, out, out, dst, BPS); + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); +} + +static void DC16NoTopLeft(uint8_t* dst) { // DC with nothing + const v16u8 out = (v16u8)__msa_fill_b(0x80); + ST_UB8(out, out, out, out, out, out, out, out, dst, BPS); + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); +} + +// Chroma + +#define STORE8x8(out, dst) do { \ + SD4(out, out, out, out, dst + 0 * BPS, BPS); \ + SD4(out, out, out, out, dst + 4 * BPS, BPS); \ +} while (0) + +static void DC8uv(uint8_t* dst) { // DC + uint32_t dc = 8; + int i; + uint64_t out; + const v16u8 rtop = LD_UB(dst - BPS); + const v8u16 temp0 = __msa_hadd_u_h(rtop, rtop); + const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0); + const v2u64 temp2 = __msa_hadd_u_d(temp1, temp1); + v16u8 dctemp; + + for (i = 0; i < 8; ++i) { + dc += dst[-1 + i * BPS]; + } + dc += __msa_copy_s_w((v4i32)temp2, 0); + dctemp = (v16u8)__msa_fill_b(dc >> 4); + out = __msa_copy_s_d((v2i64)dctemp, 0); + STORE8x8(out, dst); +} + +static void TM8uv(uint8_t* dst) { + int j; + const v16i8 T1 = LD_SB(dst - BPS); + const v16i8 zero = { 0 }; + const v8i16 T = (v8i16)__msa_ilvr_b(zero, T1); + const v8i16 TL = (v8i16)__msa_fill_h(dst[-1 - BPS]); + const v8i16 d = T - TL; + + for (j = 0; j < 8; j += 4) { + v16i8 t0, t1; + v8i16 r0 = (v8i16)__msa_fill_h(dst[-1 + 0 * BPS]); + v8i16 r1 = (v8i16)__msa_fill_h(dst[-1 + 1 * BPS]); + v8i16 r2 = (v8i16)__msa_fill_h(dst[-1 + 2 * BPS]); + v8i16 r3 = (v8i16)__msa_fill_h(dst[-1 + 3 * BPS]); + ADD4(d, r0, d, r1, d, r2, d, r3, r0, r1, r2, r3); + CLIP_SH4_0_255(r0, r1, r2, r3); + PCKEV_B2_SB(r1, r0, r3, r2, t0, t1); + ST4x4_UB(t0, t1, 0, 2, 0, 2, dst, BPS); + ST4x4_UB(t0, t1, 1, 3, 1, 3, dst + 4, BPS); + dst += 4 * BPS; + } +} + +static void VE8uv(uint8_t* dst) { // vertical + const v16u8 rtop = LD_UB(dst - BPS); + const uint64_t out = __msa_copy_s_d((v2i64)rtop, 0); + STORE8x8(out, dst); +} + +static void HE8uv(uint8_t* dst) { // horizontal + int j; + for (j = 0; j < 8; j += 4) { + const v16u8 L0 = (v16u8)__msa_fill_b(dst[-1 + 0 * BPS]); + const v16u8 L1 = (v16u8)__msa_fill_b(dst[-1 + 1 * BPS]); + const v16u8 L2 = (v16u8)__msa_fill_b(dst[-1 + 2 * BPS]); + const v16u8 L3 = (v16u8)__msa_fill_b(dst[-1 + 3 * BPS]); + const uint64_t out0 = __msa_copy_s_d((v2i64)L0, 0); + const uint64_t out1 = __msa_copy_s_d((v2i64)L1, 0); + const uint64_t out2 = __msa_copy_s_d((v2i64)L2, 0); + const uint64_t out3 = __msa_copy_s_d((v2i64)L3, 0); + SD4(out0, out1, out2, out3, dst, BPS); + dst += 4 * BPS; + } +} + +static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples + const uint32_t dc = 4; + const v16u8 rtop = LD_UB(dst - BPS); + const v8u16 temp0 = __msa_hadd_u_h(rtop, rtop); + const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0); + const v2u64 temp2 = __msa_hadd_u_d(temp1, temp1); + const uint32_t sum_m = __msa_copy_s_w((v4i32)temp2, 0); + const v16u8 dcval = (v16u8)__msa_fill_b((dc + sum_m) >> 3); + const uint64_t out = __msa_copy_s_d((v2i64)dcval, 0); + STORE8x8(out, dst); +} + +static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples + uint32_t dc = 4; + int i; + uint64_t out; + v16u8 dctemp; + + for (i = 0; i < 8; ++i) { + dc += dst[-1 + i * BPS]; + } + dctemp = (v16u8)__msa_fill_b(dc >> 3); + out = __msa_copy_s_d((v2i64)dctemp, 0); + STORE8x8(out, dst); +} + +static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing + const uint64_t out = 0x8080808080808080ULL; + STORE8x8(out, dst); +} + //------------------------------------------------------------------------------ // Entry point @@ -163,6 +977,39 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitMSA(void) { VP8Transform = TransformTwo; VP8TransformDC = TransformDC; VP8TransformAC3 = TransformAC3; + + VP8VFilter16 = VFilter16; + VP8HFilter16 = HFilter16; + VP8VFilter16i = VFilter16i; + VP8HFilter16i = HFilter16i; + VP8VFilter8 = VFilter8; + VP8HFilter8 = HFilter8; + VP8VFilter8i = VFilter8i; + VP8HFilter8i = HFilter8i; + VP8SimpleVFilter16 = SimpleVFilter16; + VP8SimpleHFilter16 = SimpleHFilter16; + VP8SimpleVFilter16i = SimpleVFilter16i; + VP8SimpleHFilter16i = SimpleHFilter16i; + + VP8PredLuma4[0] = DC4; + VP8PredLuma4[1] = TM4; + VP8PredLuma4[2] = VE4; + VP8PredLuma4[4] = RD4; + VP8PredLuma4[6] = LD4; + VP8PredLuma16[0] = DC16; + VP8PredLuma16[1] = TM16; + VP8PredLuma16[2] = VE16; + VP8PredLuma16[3] = HE16; + VP8PredLuma16[4] = DC16NoTop; + VP8PredLuma16[5] = DC16NoLeft; + VP8PredLuma16[6] = DC16NoTopLeft; + VP8PredChroma8[0] = DC8uv; + VP8PredChroma8[1] = TM8uv; + VP8PredChroma8[2] = VE8uv; + VP8PredChroma8[3] = HE8uv; + VP8PredChroma8[4] = DC8uvNoTop; + VP8PredChroma8[5] = DC8uvNoLeft; + VP8PredChroma8[6] = DC8uvNoTopLeft; } #else // !WEBP_USE_MSA diff --git a/src/3rdparty/libwebp/src/dsp/dec_neon.c b/src/3rdparty/libwebp/src/dsp/dec_neon.c index a63f43fe172dbba84f7e7ecc3bebc76c2a30b85b..34796cf4a2fb6f80d71dacf3079a1bd78eab54b2 100644 --- a/src/3rdparty/libwebp/src/dsp/dec_neon.c +++ b/src/3rdparty/libwebp/src/dsp/dec_neon.c @@ -17,7 +17,7 @@ #if defined(WEBP_USE_NEON) #include "./neon.h" -#include "../dec/vp8i.h" +#include "../dec/vp8i_dec.h" //------------------------------------------------------------------------------ // NxM Loading functions @@ -666,9 +666,8 @@ static uint8x16_t NeedsHev(const uint8x16_t p1, const uint8x16_t p0, const uint8x16_t hev_thresh_v = vdupq_n_u8((uint8_t)hev_thresh); const uint8x16_t a_p1_p0 = vabdq_u8(p1, p0); // abs(p1 - p0) const uint8x16_t a_q1_q0 = vabdq_u8(q1, q0); // abs(q1 - q0) - const uint8x16_t mask1 = vcgtq_u8(a_p1_p0, hev_thresh_v); - const uint8x16_t mask2 = vcgtq_u8(a_q1_q0, hev_thresh_v); - const uint8x16_t mask = vorrq_u8(mask1, mask2); + const uint8x16_t a_max = vmaxq_u8(a_p1_p0, a_q1_q0); + const uint8x16_t mask = vcgtq_u8(a_max, hev_thresh_v); return mask; } @@ -756,24 +755,25 @@ static void ApplyFilter6( const int8x16_t delta, uint8x16_t* const op2, uint8x16_t* const op1, uint8x16_t* const op0, uint8x16_t* const oq0, uint8x16_t* const oq1, uint8x16_t* const oq2) { - const int16x8_t kCst63 = vdupq_n_s16(63); - const int8x8_t kCst27 = vdup_n_s8(27); - const int8x8_t kCst18 = vdup_n_s8(18); - const int8x8_t kCst9 = vdup_n_s8(9); + // We have to compute: X = (9*a+63) >> 7, Y = (18*a+63)>>7, Z = (27*a+63) >> 7 + // Turns out, there's a common sub-expression S=9 * a - 1 that can be used + // with the special vqrshrn_n_s16 rounding-shift-and-narrow instruction: + // X = (S + 64) >> 7, Y = (S + 32) >> 6, Z = (18 * a + S + 64) >> 7 const int8x8_t delta_lo = vget_low_s8(delta); const int8x8_t delta_hi = vget_high_s8(delta); - const int16x8_t s1_lo = vmlal_s8(kCst63, kCst27, delta_lo); // 63 + 27 * a - const int16x8_t s1_hi = vmlal_s8(kCst63, kCst27, delta_hi); // 63 + 27 * a - const int16x8_t s2_lo = vmlal_s8(kCst63, kCst18, delta_lo); // 63 + 18 * a - const int16x8_t s2_hi = vmlal_s8(kCst63, kCst18, delta_hi); // 63 + 18 * a - const int16x8_t s3_lo = vmlal_s8(kCst63, kCst9, delta_lo); // 63 + 9 * a - const int16x8_t s3_hi = vmlal_s8(kCst63, kCst9, delta_hi); // 63 + 9 * a - const int8x8_t a1_lo = vqshrn_n_s16(s1_lo, 7); - const int8x8_t a1_hi = vqshrn_n_s16(s1_hi, 7); - const int8x8_t a2_lo = vqshrn_n_s16(s2_lo, 7); - const int8x8_t a2_hi = vqshrn_n_s16(s2_hi, 7); - const int8x8_t a3_lo = vqshrn_n_s16(s3_lo, 7); - const int8x8_t a3_hi = vqshrn_n_s16(s3_hi, 7); + const int8x8_t kCst9 = vdup_n_s8(9); + const int16x8_t kCstm1 = vdupq_n_s16(-1); + const int8x8_t kCst18 = vdup_n_s8(18); + const int16x8_t S_lo = vmlal_s8(kCstm1, kCst9, delta_lo); // S = 9 * a - 1 + const int16x8_t S_hi = vmlal_s8(kCstm1, kCst9, delta_hi); + const int16x8_t Z_lo = vmlal_s8(S_lo, kCst18, delta_lo); // S + 18 * a + const int16x8_t Z_hi = vmlal_s8(S_hi, kCst18, delta_hi); + const int8x8_t a3_lo = vqrshrn_n_s16(S_lo, 7); // (9 * a + 63) >> 7 + const int8x8_t a3_hi = vqrshrn_n_s16(S_hi, 7); + const int8x8_t a2_lo = vqrshrn_n_s16(S_lo, 6); // (9 * a + 31) >> 6 + const int8x8_t a2_hi = vqrshrn_n_s16(S_hi, 6); + const int8x8_t a1_lo = vqrshrn_n_s16(Z_lo, 7); // (27 * a + 63) >> 7 + const int8x8_t a1_hi = vqrshrn_n_s16(Z_hi, 7); const int8x16_t a1 = vcombine_s8(a1_lo, a1_hi); const int8x16_t a2 = vcombine_s8(a2_lo, a2_hi); const int8x16_t a3 = vcombine_s8(a3_lo, a3_hi); diff --git a/src/3rdparty/libwebp/src/dsp/dec_sse2.c b/src/3rdparty/libwebp/src/dsp/dec_sse2.c index f0a8ddcaf338ba13fff60ef5cc7606179797e7ad..411fb027689e312b72cc4ae386fa884a190c4ee4 100644 --- a/src/3rdparty/libwebp/src/dsp/dec_sse2.c +++ b/src/3rdparty/libwebp/src/dsp/dec_sse2.c @@ -22,7 +22,7 @@ #include <emmintrin.h> #include "./common_sse2.h" -#include "../dec/vp8i.h" +#include "../dec/vp8i_dec.h" #include "../utils/utils.h" //------------------------------------------------------------------------------ @@ -140,7 +140,7 @@ static void Transform(const int16_t* in, uint8_t* dst, int do_two) { // Transpose the two 4x4. VP8Transpose_2_4x4_16b(&shifted0, &shifted1, &shifted2, &shifted3, &T0, &T1, - &T2, &T3); + &T2, &T3); } // Add inverse transform to 'dst' and store. diff --git a/src/3rdparty/libwebp/src/dsp/dec_sse41.c b/src/3rdparty/libwebp/src/dsp/dec_sse41.c index 8d6aed13e6e414f41de5bf361cbc27b76656e83a..4e81ec4d804df39f3e478bbf6b9c81d94a4c344d 100644 --- a/src/3rdparty/libwebp/src/dsp/dec_sse41.c +++ b/src/3rdparty/libwebp/src/dsp/dec_sse41.c @@ -16,7 +16,7 @@ #if defined(WEBP_USE_SSE41) #include <smmintrin.h> -#include "../dec/vp8i.h" +#include "../dec/vp8i_dec.h" #include "../utils/utils.h" static void HE16(uint8_t* dst) { // horizontal diff --git a/src/3rdparty/libwebp/src/dsp/dsp.h b/src/3rdparty/libwebp/src/dsp/dsp.h index 1faac27b2ba6ac96fb3edb715445cea43bd505b4..813fed4a35704edad872ff8a86d8103e24fce08c 100644 --- a/src/3rdparty/libwebp/src/dsp/dsp.h +++ b/src/3rdparty/libwebp/src/dsp/dsp.h @@ -111,8 +111,7 @@ extern "C" { #define WEBP_UBSAN_IGNORE_UNDEF #define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW -#if !defined(WEBP_FORCE_ALIGNED) && defined(__clang__) && \ - defined(__has_attribute) +#if defined(__clang__) && defined(__has_attribute) #if __has_attribute(no_sanitize) // This macro prevents the undefined behavior sanitizer from reporting // failures. This is only meant to silence unaligned loads on platforms that @@ -133,6 +132,7 @@ extern "C" { typedef enum { kSSE2, kSSE3, + kSlowSSSE3, // special feature for slow SSSE3 architectures kSSE4_1, kAVX, kAVX2, @@ -185,6 +185,11 @@ typedef int (*VP8WMetric)(const uint8_t* pix, const uint8_t* ref, // 4 by 4 symmetric matrix. extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16; +// Compute the average (DC) of four 4x4 blocks. +// Each sub-4x4 block #i sum is stored in dc[i]. +typedef void (*VP8MeanMetric)(const uint8_t* ref, uint32_t dc[4]); +extern VP8MeanMetric VP8Mean16x4; + typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst); extern VP8BlockCopy VP8Copy4x4; extern VP8BlockCopy VP8Copy16x8; @@ -246,30 +251,37 @@ extern VP8GetResidualCostFunc VP8GetResidualCost; void VP8EncDspCostInit(void); //------------------------------------------------------------------------------ -// SSIM utils +// SSIM / PSNR utils // struct for accumulating statistical moments typedef struct { - double w; // sum(w_i) : sum of weights - double xm, ym; // sum(w_i * x_i), sum(w_i * y_i) - double xxm, xym, yym; // sum(w_i * x_i * x_i), etc. + uint32_t w; // sum(w_i) : sum of weights + uint32_t xm, ym; // sum(w_i * x_i), sum(w_i * y_i) + uint32_t xxm, xym, yym; // sum(w_i * x_i * x_i), etc. } VP8DistoStats; +// Compute the final SSIM value +// The non-clipped version assumes stats->w = (2 * VP8_SSIM_KERNEL + 1)^2. +double VP8SSIMFromStats(const VP8DistoStats* const stats); +double VP8SSIMFromStatsClipped(const VP8DistoStats* const stats); + #define VP8_SSIM_KERNEL 3 // total size of the kernel: 2 * VP8_SSIM_KERNEL + 1 -typedef void (*VP8SSIMAccumulateClippedFunc)(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int xo, int yo, // center position - int W, int H, // plane dimension - VP8DistoStats* const stats); +typedef double (*VP8SSIMGetClippedFunc)(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2, + int xo, int yo, // center position + int W, int H); // plane dimension // This version is called with the guarantee that you can load 8 bytes and // 8 rows at offset src1 and src2 -typedef void (*VP8SSIMAccumulateFunc)(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - VP8DistoStats* const stats); +typedef double (*VP8SSIMGetFunc)(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2); + +extern VP8SSIMGetFunc VP8SSIMGet; // unclipped / unchecked +extern VP8SSIMGetClippedFunc VP8SSIMGetClipped; // with clipping -extern VP8SSIMAccumulateFunc VP8SSIMAccumulate; // unclipped / unchecked -extern VP8SSIMAccumulateClippedFunc VP8SSIMAccumulateClipped; // with clipping +typedef uint32_t (*VP8AccumulateSSEFunc)(const uint8_t* src1, + const uint8_t* src2, int len); +extern VP8AccumulateSSEFunc VP8AccumulateSSE; // must be called before using any of the above directly void VP8SSIMDspInit(void); @@ -416,6 +428,15 @@ extern void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v, extern void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, uint8_t* u, uint8_t* v, int width); +// utilities for accurate RGB->YUV conversion +extern uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* src, const uint16_t* ref, + uint16_t* dst, int len); +extern void (*WebPSharpYUVUpdateRGB)(const int16_t* src, const int16_t* ref, + int16_t* dst, int len); +extern void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, + int len, + const uint16_t* best_y, uint16_t* out); + // Must be called before using the above. void WebPInitConvertARGBToYUV(void); @@ -488,6 +509,10 @@ extern int (*WebPExtractAlpha)(const uint8_t* argb, int argb_stride, int width, int height, uint8_t* alpha, int alpha_stride); +// Extract the green values from 32b values in argb[] and pack them into alpha[] +// (this is the opposite of WebPDispatchAlphaToGreen). +extern void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size); + // Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B). // Un-Multiply operation transforms x into x * 255 / A. diff --git a/src/3rdparty/libwebp/src/dsp/enc.c b/src/3rdparty/libwebp/src/dsp/enc.c index f639f5570c436bc6b914376ab93fe786aa1083fb..f31bc6de1852458c0c233a09b7499b0f588d9129 100644 --- a/src/3rdparty/libwebp/src/dsp/enc.c +++ b/src/3rdparty/libwebp/src/dsp/enc.c @@ -15,7 +15,7 @@ #include <stdlib.h> // for abs() #include "./dsp.h" -#include "../enc/vp8enci.h" +#include "../enc/vp8i_enc.h" static WEBP_INLINE uint8_t clip_8b(int v) { return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; @@ -335,7 +335,7 @@ static void Intra16Preds(uint8_t* dst, // luma 4x4 prediction #define DST(x, y) dst[(x) + (y) * BPS] -#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) +#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2)) #define AVG2(a, b) (((a) + (b) + 1) >> 1) static void VE4(uint8_t* dst, const uint8_t* top) { // vertical @@ -551,6 +551,20 @@ static int SSE4x4(const uint8_t* a, const uint8_t* b) { return GetSSE(a, b, 4, 4); } +static void Mean16x4(const uint8_t* ref, uint32_t dc[4]) { + int k, x, y; + for (k = 0; k < 4; ++k) { + uint32_t avg = 0; + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + avg += ref[x + y * BPS]; + } + } + dc[k] = avg; + ref += 4; // go to next 4x4 block. + } +} + //------------------------------------------------------------------------------ // Texture distortion // @@ -656,32 +670,6 @@ static int Quantize2Blocks(int16_t in[32], int16_t out[32], return nz; } -static int QuantizeBlockWHT(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - int n, last = -1; - for (n = 0; n < 16; ++n) { - const int j = kZigzag[n]; - const int sign = (in[j] < 0); - const uint32_t coeff = sign ? -in[j] : in[j]; - assert(mtx->sharpen_[j] == 0); - if (coeff > mtx->zthresh_[j]) { - const uint32_t Q = mtx->q_[j]; - const uint32_t iQ = mtx->iq_[j]; - const uint32_t B = mtx->bias_[j]; - int level = QUANTDIV(coeff, iQ, B); - if (level > MAX_LEVEL) level = MAX_LEVEL; - if (sign) level = -level; - in[j] = level * (int)Q; - out[n] = level; - if (level) last = n; - } else { - out[n] = 0; - in[j] = 0; - } - } - return (last >= 0); -} - //------------------------------------------------------------------------------ // Block copy @@ -703,11 +691,51 @@ static void Copy16x8(const uint8_t* src, uint8_t* dst) { } //------------------------------------------------------------------------------ +// SSIM / PSNR -static void SSIMAccumulateClipped(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int xo, int yo, int W, int H, - VP8DistoStats* const stats) { +// hat-shaped filter. Sum of coefficients is equal to 16. +static const uint32_t kWeight[2 * VP8_SSIM_KERNEL + 1] = { + 1, 2, 3, 4, 3, 2, 1 +}; +static const uint32_t kWeightSum = 16 * 16; // sum{kWeight}^2 + +static WEBP_INLINE double SSIMCalculation( + const VP8DistoStats* const stats, uint32_t N /*num samples*/) { + const uint32_t w2 = N * N; + const uint32_t C1 = 20 * w2; + const uint32_t C2 = 60 * w2; + const uint32_t C3 = 8 * 8 * w2; // 'dark' limit ~= 6 + const uint64_t xmxm = (uint64_t)stats->xm * stats->xm; + const uint64_t ymym = (uint64_t)stats->ym * stats->ym; + if (xmxm + ymym >= C3) { + const int64_t xmym = (int64_t)stats->xm * stats->ym; + const int64_t sxy = (int64_t)stats->xym * N - xmym; // can be negative + const uint64_t sxx = (uint64_t)stats->xxm * N - xmxm; + const uint64_t syy = (uint64_t)stats->yym * N - ymym; + // we descale by 8 to prevent overflow during the fnum/fden multiply. + const uint64_t num_S = (2 * (uint64_t)(sxy < 0 ? 0 : sxy) + C2) >> 8; + const uint64_t den_S = (sxx + syy + C2) >> 8; + const uint64_t fnum = (2 * xmym + C1) * num_S; + const uint64_t fden = (xmxm + ymym + C1) * den_S; + const double r = (double)fnum / fden; + assert(r >= 0. && r <= 1.0); + return r; + } + return 1.; // area is too dark to contribute meaningfully +} + +double VP8SSIMFromStats(const VP8DistoStats* const stats) { + return SSIMCalculation(stats, kWeightSum); +} + +double VP8SSIMFromStatsClipped(const VP8DistoStats* const stats) { + return SSIMCalculation(stats, stats->w); +} + +static double SSIMGetClipped_C(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2, + int xo, int yo, int W, int H) { + VP8DistoStats stats = { 0, 0, 0, 0, 0, 0 }; const int ymin = (yo - VP8_SSIM_KERNEL < 0) ? 0 : yo - VP8_SSIM_KERNEL; const int ymax = (yo + VP8_SSIM_KERNEL > H - 1) ? H - 1 : yo + VP8_SSIM_KERNEL; @@ -719,38 +747,61 @@ static void SSIMAccumulateClipped(const uint8_t* src1, int stride1, src2 += ymin * stride2; for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) { for (x = xmin; x <= xmax; ++x) { - const int s1 = src1[x]; - const int s2 = src2[x]; - stats->w += 1; - stats->xm += s1; - stats->ym += s2; - stats->xxm += s1 * s1; - stats->xym += s1 * s2; - stats->yym += s2 * s2; + const uint32_t w = kWeight[VP8_SSIM_KERNEL + x - xo] + * kWeight[VP8_SSIM_KERNEL + y - yo]; + const uint32_t s1 = src1[x]; + const uint32_t s2 = src2[x]; + stats.w += w; + stats.xm += w * s1; + stats.ym += w * s2; + stats.xxm += w * s1 * s1; + stats.xym += w * s1 * s2; + stats.yym += w * s2 * s2; } } + return VP8SSIMFromStatsClipped(&stats); } -static void SSIMAccumulate(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - VP8DistoStats* const stats) { +static double SSIMGet_C(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2) { + VP8DistoStats stats = { 0, 0, 0, 0, 0, 0 }; int x, y; for (y = 0; y <= 2 * VP8_SSIM_KERNEL; ++y, src1 += stride1, src2 += stride2) { for (x = 0; x <= 2 * VP8_SSIM_KERNEL; ++x) { - const int s1 = src1[x]; - const int s2 = src2[x]; - stats->w += 1; - stats->xm += s1; - stats->ym += s2; - stats->xxm += s1 * s1; - stats->xym += s1 * s2; - stats->yym += s2 * s2; + const uint32_t w = kWeight[x] * kWeight[y]; + const uint32_t s1 = src1[x]; + const uint32_t s2 = src2[x]; + stats.xm += w * s1; + stats.ym += w * s2; + stats.xxm += w * s1 * s1; + stats.xym += w * s1 * s2; + stats.yym += w * s2 * s2; } } + return VP8SSIMFromStats(&stats); +} + +//------------------------------------------------------------------------------ + +static uint32_t AccumulateSSE(const uint8_t* src1, + const uint8_t* src2, int len) { + int i; + uint32_t sse2 = 0; + assert(len <= 65535); // to ensure that accumulation fits within uint32_t + for (i = 0; i < len; ++i) { + const int32_t diff = src1[i] - src2[i]; + sse2 += diff * diff; + } + return sse2; } -VP8SSIMAccumulateFunc VP8SSIMAccumulate; -VP8SSIMAccumulateClippedFunc VP8SSIMAccumulateClipped; +//------------------------------------------------------------------------------ + +VP8SSIMGetFunc VP8SSIMGet; +VP8SSIMGetClippedFunc VP8SSIMGetClipped; +VP8AccumulateSSEFunc VP8AccumulateSSE; + +extern void VP8SSIMDspInitSSE2(void); static volatile VP8CPUInfo ssim_last_cpuinfo_used = (VP8CPUInfo)&ssim_last_cpuinfo_used; @@ -758,8 +809,17 @@ static volatile VP8CPUInfo ssim_last_cpuinfo_used = WEBP_TSAN_IGNORE_FUNCTION void VP8SSIMDspInit(void) { if (ssim_last_cpuinfo_used == VP8GetCPUInfo) return; - VP8SSIMAccumulate = SSIMAccumulate; - VP8SSIMAccumulateClipped = SSIMAccumulateClipped; + VP8SSIMGetClipped = SSIMGetClipped_C; + VP8SSIMGet = SSIMGet_C; + + VP8AccumulateSSE = AccumulateSSE; + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_USE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8SSIMDspInitSSE2(); + } +#endif + } ssim_last_cpuinfo_used = VP8GetCPUInfo; } @@ -783,6 +843,7 @@ VP8Metric VP8SSE16x8; VP8Metric VP8SSE4x4; VP8WMetric VP8TDisto4x4; VP8WMetric VP8TDisto16x16; +VP8MeanMetric VP8Mean16x4; VP8QuantizeBlock VP8EncQuantizeBlock; VP8Quantize2Blocks VP8EncQuantize2Blocks; VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT; @@ -795,6 +856,7 @@ extern void VP8EncDspInitAVX2(void); extern void VP8EncDspInitNEON(void); extern void VP8EncDspInitMIPS32(void); extern void VP8EncDspInitMIPSdspR2(void); +extern void VP8EncDspInitMSA(void); static volatile VP8CPUInfo enc_last_cpuinfo_used = (VP8CPUInfo)&enc_last_cpuinfo_used; @@ -820,9 +882,10 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInit(void) { VP8SSE4x4 = SSE4x4; VP8TDisto4x4 = Disto4x4; VP8TDisto16x16 = Disto16x16; + VP8Mean16x4 = Mean16x4; VP8EncQuantizeBlock = QuantizeBlock; VP8EncQuantize2Blocks = Quantize2Blocks; - VP8EncQuantizeBlockWHT = QuantizeBlockWHT; + VP8EncQuantizeBlockWHT = QuantizeBlock; VP8Copy4x4 = Copy4x4; VP8Copy16x8 = Copy16x8; @@ -857,6 +920,11 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInit(void) { if (VP8GetCPUInfo(kMIPSdspR2)) { VP8EncDspInitMIPSdspR2(); } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8EncDspInitMSA(); + } #endif } enc_last_cpuinfo_used = VP8GetCPUInfo; diff --git a/src/3rdparty/libwebp/src/dsp/enc_mips32.c b/src/3rdparty/libwebp/src/dsp/enc_mips32.c index fd10143de9068199fff9fb7e68f332ec7c953413..752b14daf6b1d1c2adb34e77f156ce9f7dc16366 100644 --- a/src/3rdparty/libwebp/src/dsp/enc_mips32.c +++ b/src/3rdparty/libwebp/src/dsp/enc_mips32.c @@ -18,8 +18,8 @@ #if defined(WEBP_USE_MIPS32) #include "./mips_macro.h" -#include "../enc/vp8enci.h" -#include "../enc/cost.h" +#include "../enc/vp8i_enc.h" +#include "../enc/cost_enc.h" static const int kC1 = 20091 + (1 << 16); static const int kC2 = 35468; diff --git a/src/3rdparty/libwebp/src/dsp/enc_mips_dsp_r2.c b/src/3rdparty/libwebp/src/dsp/enc_mips_dsp_r2.c index 7ab96f6800a915e5cfe01fc9b95e5d71e898158b..6c8c1c6acd037864c7425f61bcd1cd06c32ecb39 100644 --- a/src/3rdparty/libwebp/src/dsp/enc_mips_dsp_r2.c +++ b/src/3rdparty/libwebp/src/dsp/enc_mips_dsp_r2.c @@ -17,8 +17,8 @@ #if defined(WEBP_USE_MIPS_DSP_R2) #include "./mips_macro.h" -#include "../enc/cost.h" -#include "../enc/vp8enci.h" +#include "../enc/cost_enc.h" +#include "../enc/vp8i_enc.h" static const int kC1 = 20091 + (1 << 16); static const int kC2 = 35468; diff --git a/src/3rdparty/libwebp/src/dsp/enc_msa.c b/src/3rdparty/libwebp/src/dsp/enc_msa.c new file mode 100644 index 0000000000000000000000000000000000000000..909b46d5d9813b6ddb13df500bf2082c79eafa17 --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/enc_msa.c @@ -0,0 +1,892 @@ +// Copyright 2016 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. +// ----------------------------------------------------------------------------- +// +// MSA version of encoder dsp functions. +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include "./dsp.h" + +#if defined(WEBP_USE_MSA) + +#include <stdlib.h> +#include "./msa_macro.h" +#include "../enc/vp8i_enc.h" + +//------------------------------------------------------------------------------ +// Transforms + +#define IDCT_1D_W(in0, in1, in2, in3, out0, out1, out2, out3) do { \ + v4i32 a1_m, b1_m, c1_m, d1_m; \ + const v4i32 cospi8sqrt2minus1 = __msa_fill_w(20091); \ + const v4i32 sinpi8sqrt2 = __msa_fill_w(35468); \ + v4i32 c_tmp1_m = in1 * sinpi8sqrt2; \ + v4i32 c_tmp2_m = in3 * cospi8sqrt2minus1; \ + v4i32 d_tmp1_m = in1 * cospi8sqrt2minus1; \ + v4i32 d_tmp2_m = in3 * sinpi8sqrt2; \ + \ + ADDSUB2(in0, in2, a1_m, b1_m); \ + SRAI_W2_SW(c_tmp1_m, c_tmp2_m, 16); \ + c_tmp2_m = c_tmp2_m + in3; \ + c1_m = c_tmp1_m - c_tmp2_m; \ + SRAI_W2_SW(d_tmp1_m, d_tmp2_m, 16); \ + d_tmp1_m = d_tmp1_m + in1; \ + d1_m = d_tmp1_m + d_tmp2_m; \ + BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \ +} while (0) + +static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, + uint8_t* dst) { + v8i16 input0, input1; + v4i32 in0, in1, in2, in3, hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3; + v4i32 res0, res1, res2, res3; + v16i8 dest0, dest1, dest2, dest3; + const v16i8 zero = { 0 }; + + LD_SH2(in, 8, input0, input1); + UNPCK_SH_SW(input0, in0, in1); + UNPCK_SH_SW(input1, in2, in3); + IDCT_1D_W(in0, in1, in2, in3, hz0, hz1, hz2, hz3); + TRANSPOSE4x4_SW_SW(hz0, hz1, hz2, hz3, hz0, hz1, hz2, hz3); + IDCT_1D_W(hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3); + SRARI_W4_SW(vt0, vt1, vt2, vt3, 3); + TRANSPOSE4x4_SW_SW(vt0, vt1, vt2, vt3, vt0, vt1, vt2, vt3); + LD_SB4(ref, BPS, dest0, dest1, dest2, dest3); + ILVR_B4_SW(zero, dest0, zero, dest1, zero, dest2, zero, dest3, + res0, res1, res2, res3); + ILVR_H4_SW(zero, res0, zero, res1, zero, res2, zero, res3, + res0, res1, res2, res3); + ADD4(res0, vt0, res1, vt1, res2, vt2, res3, vt3, res0, res1, res2, res3); + CLIP_SW4_0_255(res0, res1, res2, res3); + PCKEV_B2_SW(res0, res1, res2, res3, vt0, vt1); + res0 = (v4i32)__msa_pckev_b((v16i8)vt0, (v16i8)vt1); + ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS); +} + +static void ITransform(const uint8_t* ref, const int16_t* in, uint8_t* dst, + int do_two) { + ITransformOne(ref, in, dst); + if (do_two) { + ITransformOne(ref + 4, in + 16, dst + 4); + } +} + +static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) { + uint64_t out0, out1, out2, out3; + uint32_t in0, in1, in2, in3; + v4i32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 t0, t1, t2, t3; + v16u8 srcl0, srcl1, src0, src1; + const v8i16 mask0 = { 0, 4, 8, 12, 1, 5, 9, 13 }; + const v8i16 mask1 = { 3, 7, 11, 15, 2, 6, 10, 14 }; + const v8i16 mask2 = { 4, 0, 5, 1, 6, 2, 7, 3 }; + const v8i16 mask3 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + const v8i16 cnst0 = { 2217, -5352, 2217, -5352, 2217, -5352, 2217, -5352 }; + const v8i16 cnst1 = { 5352, 2217, 5352, 2217, 5352, 2217, 5352, 2217 }; + + LW4(src, BPS, in0, in1, in2, in3); + INSERT_W4_UB(in0, in1, in2, in3, src0); + LW4(ref, BPS, in0, in1, in2, in3); + INSERT_W4_UB(in0, in1, in2, in3, src1); + ILVRL_B2_UB(src0, src1, srcl0, srcl1); + HSUB_UB2_SH(srcl0, srcl1, t0, t1); + VSHF_H2_SH(t0, t1, t0, t1, mask0, mask1, t2, t3); + ADDSUB2(t2, t3, t0, t1); + t0 = SRLI_H(t0, 3); + VSHF_H2_SH(t0, t0, t1, t1, mask2, mask3, t3, t2); + tmp0 = __msa_hadd_s_w(t3, t3); + tmp2 = __msa_hsub_s_w(t3, t3); + FILL_W2_SW(1812, 937, tmp1, tmp3); + DPADD_SH2_SW(t2, t2, cnst0, cnst1, tmp3, tmp1); + SRAI_W2_SW(tmp1, tmp3, 9); + PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, t0, t1); + VSHF_H2_SH(t0, t1, t0, t1, mask0, mask1, t2, t3); + ADDSUB2(t2, t3, t0, t1); + VSHF_H2_SH(t0, t0, t1, t1, mask2, mask3, t3, t2); + tmp0 = __msa_hadd_s_w(t3, t3); + tmp2 = __msa_hsub_s_w(t3, t3); + ADDVI_W2_SW(tmp0, 7, tmp2, 7, tmp0, tmp2); + SRAI_W2_SW(tmp0, tmp2, 4); + FILL_W2_SW(12000, 51000, tmp1, tmp3); + DPADD_SH2_SW(t2, t2, cnst0, cnst1, tmp3, tmp1); + SRAI_W2_SW(tmp1, tmp3, 16); + UNPCK_R_SH_SW(t1, tmp4); + tmp5 = __msa_ceqi_w(tmp4, 0); + tmp4 = (v4i32)__msa_nor_v((v16u8)tmp5, (v16u8)tmp5); + tmp5 = __msa_fill_w(1); + tmp5 = (v4i32)__msa_and_v((v16u8)tmp5, (v16u8)tmp4); + tmp1 += tmp5; + PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, t0, t1); + out0 = __msa_copy_s_d((v2i64)t0, 0); + out1 = __msa_copy_s_d((v2i64)t0, 1); + out2 = __msa_copy_s_d((v2i64)t1, 0); + out3 = __msa_copy_s_d((v2i64)t1, 1); + SD4(out0, out1, out2, out3, out, 8); +} + +static void FTransformWHT(const int16_t* in, int16_t* out) { + v8i16 in0 = { 0 }; + v8i16 in1 = { 0 }; + v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 out0, out1; + const v8i16 mask0 = { 0, 1, 2, 3, 8, 9, 10, 11 }; + const v8i16 mask1 = { 4, 5, 6, 7, 12, 13, 14, 15 }; + const v8i16 mask2 = { 0, 4, 8, 12, 1, 5, 9, 13 }; + const v8i16 mask3 = { 3, 7, 11, 15, 2, 6, 10, 14 }; + + in0 = __msa_insert_h(in0, 0, in[ 0]); + in0 = __msa_insert_h(in0, 1, in[ 64]); + in0 = __msa_insert_h(in0, 2, in[128]); + in0 = __msa_insert_h(in0, 3, in[192]); + in0 = __msa_insert_h(in0, 4, in[ 16]); + in0 = __msa_insert_h(in0, 5, in[ 80]); + in0 = __msa_insert_h(in0, 6, in[144]); + in0 = __msa_insert_h(in0, 7, in[208]); + in1 = __msa_insert_h(in1, 0, in[ 48]); + in1 = __msa_insert_h(in1, 1, in[112]); + in1 = __msa_insert_h(in1, 2, in[176]); + in1 = __msa_insert_h(in1, 3, in[240]); + in1 = __msa_insert_h(in1, 4, in[ 32]); + in1 = __msa_insert_h(in1, 5, in[ 96]); + in1 = __msa_insert_h(in1, 6, in[160]); + in1 = __msa_insert_h(in1, 7, in[224]); + ADDSUB2(in0, in1, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + ADDSUB2(tmp2, tmp3, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); + ADDSUB2(in0, in1, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + ADDSUB2(tmp2, tmp3, out0, out1); + SRAI_H2_SH(out0, out1, 1); + ST_SH2(out0, out1, out, 8); +} + +static int TTransform(const uint8_t* in, const uint16_t* w) { + int sum; + uint32_t in0_m, in1_m, in2_m, in3_m; + v16i8 src0; + v8i16 in0, in1, tmp0, tmp1, tmp2, tmp3; + v4i32 dst0, dst1; + const v16i8 zero = { 0 }; + const v8i16 mask0 = { 0, 1, 2, 3, 8, 9, 10, 11 }; + const v8i16 mask1 = { 4, 5, 6, 7, 12, 13, 14, 15 }; + const v8i16 mask2 = { 0, 4, 8, 12, 1, 5, 9, 13 }; + const v8i16 mask3 = { 3, 7, 11, 15, 2, 6, 10, 14 }; + + LW4(in, BPS, in0_m, in1_m, in2_m, in3_m); + INSERT_W4_SB(in0_m, in1_m, in2_m, in3_m, src0); + ILVRL_B2_SH(zero, src0, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); + ADDSUB2(in0, in1, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + ADDSUB2(tmp2, tmp3, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); + ADDSUB2(in0, in1, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + ADDSUB2(tmp2, tmp3, tmp0, tmp1); + tmp0 = __msa_add_a_h(tmp0, (v8i16)zero); + tmp1 = __msa_add_a_h(tmp1, (v8i16)zero); + LD_SH2(w, 8, tmp2, tmp3); + DOTP_SH2_SW(tmp0, tmp1, tmp2, tmp3, dst0, dst1); + dst0 = dst0 + dst1; + sum = HADD_SW_S32(dst0); + return sum; +} + +static int Disto4x4(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + const int sum1 = TTransform(a, w); + const int sum2 = TTransform(b, w); + return abs(sum2 - sum1) >> 5; +} + +static int Disto16x16(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4(a + x + y, b + x + y, w); + } + } + return D; +} + +//------------------------------------------------------------------------------ +// Histogram + +static void CollectHistogram(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block, + VP8Histogram* const histo) { + int j; + int distribution[MAX_COEFF_THRESH + 1] = { 0 }; + for (j = start_block; j < end_block; ++j) { + int16_t out[16]; + VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + { + int k; + v8i16 coeff0, coeff1; + const v8i16 zero = { 0 }; + const v8i16 max_coeff_thr = __msa_ldi_h(MAX_COEFF_THRESH); + LD_SH2(&out[0], 8, coeff0, coeff1); + coeff0 = __msa_add_a_h(coeff0, zero); + coeff1 = __msa_add_a_h(coeff1, zero); + SRAI_H2_SH(coeff0, coeff1, 3); + coeff0 = __msa_min_s_h(coeff0, max_coeff_thr); + coeff1 = __msa_min_s_h(coeff1, max_coeff_thr); + ST_SH2(coeff0, coeff1, &out[0], 8); + for (k = 0; k < 16; ++k) { + ++distribution[out[k]]; + } + } + } + VP8SetHistogramData(distribution, histo); +} + +//------------------------------------------------------------------------------ +// Intra predictions + +// luma 4x4 prediction + +#define DST(x, y) dst[(x) + (y) * BPS] +#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) +#define AVG2(a, b) (((a) + (b) + 1) >> 1) + +static WEBP_INLINE void VE4(uint8_t* dst, const uint8_t* top) { // vertical + const uint64_t val_m = LD(top - 1); + const v16u8 A = (v16u8)__msa_insert_d((v2i64)A, 0, val_m); + const v16u8 B = SLDI_UB(A, A, 1); + const v16u8 C = SLDI_UB(A, A, 2); + const v16u8 AC = __msa_ave_u_b(A, C); + const v16u8 B2 = __msa_ave_u_b(B, B); + const v16u8 R = __msa_aver_u_b(AC, B2); + const uint32_t out = __msa_copy_s_w((v4i32)R, 0); + SW4(out, out, out, out, dst, BPS); +} + +static WEBP_INLINE void HE4(uint8_t* dst, const uint8_t* top) { // horizontal + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + WebPUint32ToMem(dst + 0 * BPS, 0x01010101U * AVG3(X, I, J)); + WebPUint32ToMem(dst + 1 * BPS, 0x01010101U * AVG3(I, J, K)); + WebPUint32ToMem(dst + 2 * BPS, 0x01010101U * AVG3(J, K, L)); + WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(K, L, L)); +} + +static WEBP_INLINE void DC4(uint8_t* dst, const uint8_t* top) { + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i]; + dc >>= 3; + dc = dc | (dc << 8) | (dc << 16) | (dc << 24); + SW4(dc, dc, dc, dc, dst, BPS); +} + +static WEBP_INLINE void RD4(uint8_t* dst, const uint8_t* top) { + const uint64_t val_m = LD(top - 5); + const v16u8 A1 = (v16u8)__msa_insert_d((v2i64)A1, 0, val_m); + const v16u8 A = (v16u8)__msa_insert_b((v16i8)A1, 8, top[3]); + const v16u8 B = SLDI_UB(A, A, 1); + const v16u8 C = SLDI_UB(A, A, 2); + const v16u8 AC = __msa_ave_u_b(A, C); + const v16u8 B2 = __msa_ave_u_b(B, B); + const v16u8 R0 = __msa_aver_u_b(AC, B2); + const v16u8 R1 = SLDI_UB(R0, R0, 1); + const v16u8 R2 = SLDI_UB(R1, R1, 1); + const v16u8 R3 = SLDI_UB(R2, R2, 1); + const uint32_t val0 = __msa_copy_s_w((v4i32)R0, 0); + const uint32_t val1 = __msa_copy_s_w((v4i32)R1, 0); + const uint32_t val2 = __msa_copy_s_w((v4i32)R2, 0); + const uint32_t val3 = __msa_copy_s_w((v4i32)R3, 0); + SW4(val3, val2, val1, val0, dst, BPS); +} + +static WEBP_INLINE void LD4(uint8_t* dst, const uint8_t* top) { + const uint64_t val_m = LD(top); + const v16u8 A = (v16u8)__msa_insert_d((v2i64)A, 0, val_m); + const v16u8 B = SLDI_UB(A, A, 1); + const v16u8 C1 = SLDI_UB(A, A, 2); + const v16u8 C = (v16u8)__msa_insert_b((v16i8)C1, 6, top[7]); + const v16u8 AC = __msa_ave_u_b(A, C); + const v16u8 B2 = __msa_ave_u_b(B, B); + const v16u8 R0 = __msa_aver_u_b(AC, B2); + const v16u8 R1 = SLDI_UB(R0, R0, 1); + const v16u8 R2 = SLDI_UB(R1, R1, 1); + const v16u8 R3 = SLDI_UB(R2, R2, 1); + const uint32_t val0 = __msa_copy_s_w((v4i32)R0, 0); + const uint32_t val1 = __msa_copy_s_w((v4i32)R1, 0); + const uint32_t val2 = __msa_copy_s_w((v4i32)R2, 0); + const uint32_t val3 = __msa_copy_s_w((v4i32)R3, 0); + SW4(val0, val1, val2, val3, dst, BPS); +} + +static WEBP_INLINE void VR4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + DST(0, 0) = DST(1, 2) = AVG2(X, A); + DST(1, 0) = DST(2, 2) = AVG2(A, B); + DST(2, 0) = DST(3, 2) = AVG2(B, C); + DST(3, 0) = AVG2(C, D); + DST(0, 3) = AVG3(K, J, I); + DST(0, 2) = AVG3(J, I, X); + DST(0, 1) = DST(1, 3) = AVG3(I, X, A); + DST(1, 1) = DST(2, 3) = AVG3(X, A, B); + DST(2, 1) = DST(3, 3) = AVG3(A, B, C); + DST(3, 1) = AVG3(B, C, D); +} + +static WEBP_INLINE void VL4(uint8_t* dst, const uint8_t* top) { + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + const int E = top[4]; + const int F = top[5]; + const int G = top[6]; + const int H = top[7]; + DST(0, 0) = AVG2(A, B); + DST(1, 0) = DST(0, 2) = AVG2(B, C); + DST(2, 0) = DST(1, 2) = AVG2(C, D); + DST(3, 0) = DST(2, 2) = AVG2(D, E); + DST(0, 1) = AVG3(A, B, C); + DST(1, 1) = DST(0, 3) = AVG3(B, C, D); + DST(2, 1) = DST(1, 3) = AVG3(C, D, E); + DST(3, 1) = DST(2, 3) = AVG3(D, E, F); + DST(3, 2) = AVG3(E, F, G); + DST(3, 3) = AVG3(F, G, H); +} + +static WEBP_INLINE void HU4(uint8_t* dst, const uint8_t* top) { + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + DST(0, 0) = AVG2(I, J); + DST(2, 0) = DST(0, 1) = AVG2(J, K); + DST(2, 1) = DST(0, 2) = AVG2(K, L); + DST(1, 0) = AVG3(I, J, K); + DST(3, 0) = DST(1, 1) = AVG3(J, K, L); + DST(3, 1) = DST(1, 2) = AVG3(K, L, L); + DST(3, 2) = DST(2, 2) = + DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; +} + +static WEBP_INLINE void HD4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + DST(0, 0) = DST(2, 1) = AVG2(I, X); + DST(0, 1) = DST(2, 2) = AVG2(J, I); + DST(0, 2) = DST(2, 3) = AVG2(K, J); + DST(0, 3) = AVG2(L, K); + DST(3, 0) = AVG3(A, B, C); + DST(2, 0) = AVG3(X, A, B); + DST(1, 0) = DST(3, 1) = AVG3(I, X, A); + DST(1, 1) = DST(3, 2) = AVG3(J, I, X); + DST(1, 2) = DST(3, 3) = AVG3(K, J, I); + DST(1, 3) = AVG3(L, K, J); +} + +static WEBP_INLINE void TM4(uint8_t* dst, const uint8_t* top) { + const v16i8 zero = { 0 }; + const v8i16 TL = (v8i16)__msa_fill_h(top[-1]); + const v8i16 L0 = (v8i16)__msa_fill_h(top[-2]); + const v8i16 L1 = (v8i16)__msa_fill_h(top[-3]); + const v8i16 L2 = (v8i16)__msa_fill_h(top[-4]); + const v8i16 L3 = (v8i16)__msa_fill_h(top[-5]); + const v16u8 T1 = LD_UB(top); + const v8i16 T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1); + const v8i16 d = T - TL; + v8i16 r0, r1, r2, r3; + ADD4(d, L0, d, L1, d, L2, d, L3, r0, r1, r2, r3); + CLIP_SH4_0_255(r0, r1, r2, r3); + PCKEV_ST4x4_UB(r0, r1, r2, r3, dst, BPS); +} + +#undef DST +#undef AVG3 +#undef AVG2 + +static void Intra4Preds(uint8_t* dst, const uint8_t* top) { + DC4(I4DC4 + dst, top); + TM4(I4TM4 + dst, top); + VE4(I4VE4 + dst, top); + HE4(I4HE4 + dst, top); + RD4(I4RD4 + dst, top); + VR4(I4VR4 + dst, top); + LD4(I4LD4 + dst, top); + VL4(I4VL4 + dst, top); + HD4(I4HD4 + dst, top); + HU4(I4HU4 + dst, top); +} + +// luma 16x16 prediction + +#define STORE16x16(out, dst) do { \ + ST_UB8(out, out, out, out, out, out, out, out, dst + 0 * BPS, BPS); \ + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); \ +} while (0) + +static WEBP_INLINE void VerticalPred16x16(uint8_t* dst, const uint8_t* top) { + if (top != NULL) { + const v16u8 out = LD_UB(top); + STORE16x16(out, dst); + } else { + const v16u8 out = (v16u8)__msa_fill_b(0x7f); + STORE16x16(out, dst); + } +} + +static WEBP_INLINE void HorizontalPred16x16(uint8_t* dst, + const uint8_t* left) { + if (left != NULL) { + int j; + for (j = 0; j < 16; j += 4) { + const v16u8 L0 = (v16u8)__msa_fill_b(left[0]); + const v16u8 L1 = (v16u8)__msa_fill_b(left[1]); + const v16u8 L2 = (v16u8)__msa_fill_b(left[2]); + const v16u8 L3 = (v16u8)__msa_fill_b(left[3]); + ST_UB4(L0, L1, L2, L3, dst, BPS); + dst += 4 * BPS; + left += 4; + } + } else { + const v16u8 out = (v16u8)__msa_fill_b(0x81); + STORE16x16(out, dst); + } +} + +static WEBP_INLINE void TrueMotion16x16(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + if (left != NULL) { + if (top != NULL) { + int j; + v8i16 d1, d2; + const v16i8 zero = { 0 }; + const v8i16 TL = (v8i16)__msa_fill_h(left[-1]); + const v16u8 T = LD_UB(top); + ILVRL_B2_SH(zero, T, d1, d2); + SUB2(d1, TL, d2, TL, d1, d2); + for (j = 0; j < 16; j += 4) { + v16i8 t0, t1, t2, t3; + v8i16 r0, r1, r2, r3, r4, r5, r6, r7; + const v8i16 L0 = (v8i16)__msa_fill_h(left[j + 0]); + const v8i16 L1 = (v8i16)__msa_fill_h(left[j + 1]); + const v8i16 L2 = (v8i16)__msa_fill_h(left[j + 2]); + const v8i16 L3 = (v8i16)__msa_fill_h(left[j + 3]); + ADD4(d1, L0, d1, L1, d1, L2, d1, L3, r0, r1, r2, r3); + ADD4(d2, L0, d2, L1, d2, L2, d2, L3, r4, r5, r6, r7); + CLIP_SH4_0_255(r0, r1, r2, r3); + CLIP_SH4_0_255(r4, r5, r6, r7); + PCKEV_B4_SB(r4, r0, r5, r1, r6, r2, r7, r3, t0, t1, t2, t3); + ST_SB4(t0, t1, t2, t3, dst, BPS); + dst += 4 * BPS; + } + } else { + HorizontalPred16x16(dst, left); + } + } else { + if (top != NULL) { + VerticalPred16x16(dst, top); + } else { + const v16u8 out = (v16u8)__msa_fill_b(0x81); + STORE16x16(out, dst); + } + } +} + +static WEBP_INLINE void DCMode16x16(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + int DC; + v16u8 out; + if (top != NULL && left != NULL) { + const v16u8 rtop = LD_UB(top); + const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); + const v16u8 rleft = LD_UB(left); + const v8u16 dcleft = __msa_hadd_u_h(rleft, rleft); + const v8u16 dctemp = dctop + dcleft; + DC = HADD_UH_U32(dctemp); + DC = (DC + 16) >> 5; + } else if (left != NULL) { // left but no top + const v16u8 rleft = LD_UB(left); + const v8u16 dcleft = __msa_hadd_u_h(rleft, rleft); + DC = HADD_UH_U32(dcleft); + DC = (DC + DC + 16) >> 5; + } else if (top != NULL) { // top but no left + const v16u8 rtop = LD_UB(top); + const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); + DC = HADD_UH_U32(dctop); + DC = (DC + DC + 16) >> 5; + } else { // no top, no left, nothing. + DC = 0x80; + } + out = (v16u8)__msa_fill_b(DC); + STORE16x16(out, dst); +} + +static void Intra16Preds(uint8_t* dst, + const uint8_t* left, const uint8_t* top) { + DCMode16x16(I16DC16 + dst, left, top); + VerticalPred16x16(I16VE16 + dst, top); + HorizontalPred16x16(I16HE16 + dst, left); + TrueMotion16x16(I16TM16 + dst, left, top); +} + +// Chroma 8x8 prediction + +#define CALC_DC8(in, out) do { \ + const v8u16 temp0 = __msa_hadd_u_h(in, in); \ + const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0); \ + const v2i64 temp2 = (v2i64)__msa_hadd_u_d(temp1, temp1); \ + const v2i64 temp3 = __msa_splati_d(temp2, 1); \ + const v2i64 temp4 = temp3 + temp2; \ + const v16i8 temp5 = (v16i8)__msa_srari_d(temp4, 4); \ + const v2i64 temp6 = (v2i64)__msa_splati_b(temp5, 0); \ + out = __msa_copy_s_d(temp6, 0); \ +} while (0) + +#define STORE8x8(out, dst) do { \ + SD4(out, out, out, out, dst + 0 * BPS, BPS); \ + SD4(out, out, out, out, dst + 4 * BPS, BPS); \ +} while (0) + +static WEBP_INLINE void VerticalPred8x8(uint8_t* dst, const uint8_t* top) { + if (top != NULL) { + const uint64_t out = LD(top); + STORE8x8(out, dst); + } else { + const uint64_t out = 0x7f7f7f7f7f7f7f7fULL; + STORE8x8(out, dst); + } +} + +static WEBP_INLINE void HorizontalPred8x8(uint8_t* dst, const uint8_t* left) { + if (left != NULL) { + int j; + for (j = 0; j < 8; j += 4) { + const v16u8 L0 = (v16u8)__msa_fill_b(left[0]); + const v16u8 L1 = (v16u8)__msa_fill_b(left[1]); + const v16u8 L2 = (v16u8)__msa_fill_b(left[2]); + const v16u8 L3 = (v16u8)__msa_fill_b(left[3]); + const uint64_t out0 = __msa_copy_s_d((v2i64)L0, 0); + const uint64_t out1 = __msa_copy_s_d((v2i64)L1, 0); + const uint64_t out2 = __msa_copy_s_d((v2i64)L2, 0); + const uint64_t out3 = __msa_copy_s_d((v2i64)L3, 0); + SD4(out0, out1, out2, out3, dst, BPS); + dst += 4 * BPS; + left += 4; + } + } else { + const uint64_t out = 0x8181818181818181ULL; + STORE8x8(out, dst); + } +} + +static WEBP_INLINE void TrueMotion8x8(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + if (left != NULL) { + if (top != NULL) { + int j; + const v8i16 TL = (v8i16)__msa_fill_h(left[-1]); + const v16u8 T1 = LD_UB(top); + const v16i8 zero = { 0 }; + const v8i16 T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1); + const v8i16 d = T - TL; + for (j = 0; j < 8; j += 4) { + uint64_t out0, out1, out2, out3; + v16i8 t0, t1; + v8i16 r0 = (v8i16)__msa_fill_h(left[j + 0]); + v8i16 r1 = (v8i16)__msa_fill_h(left[j + 1]); + v8i16 r2 = (v8i16)__msa_fill_h(left[j + 2]); + v8i16 r3 = (v8i16)__msa_fill_h(left[j + 3]); + ADD4(d, r0, d, r1, d, r2, d, r3, r0, r1, r2, r3); + CLIP_SH4_0_255(r0, r1, r2, r3); + PCKEV_B2_SB(r1, r0, r3, r2, t0, t1); + out0 = __msa_copy_s_d((v2i64)t0, 0); + out1 = __msa_copy_s_d((v2i64)t0, 1); + out2 = __msa_copy_s_d((v2i64)t1, 0); + out3 = __msa_copy_s_d((v2i64)t1, 1); + SD4(out0, out1, out2, out3, dst, BPS); + dst += 4 * BPS; + } + } else { + HorizontalPred8x8(dst, left); + } + } else { + if (top != NULL) { + VerticalPred8x8(dst, top); + } else { + const uint64_t out = 0x8181818181818181ULL; + STORE8x8(out, dst); + } + } +} + +static WEBP_INLINE void DCMode8x8(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + uint64_t out; + v16u8 src; + if (top != NULL && left != NULL) { + const uint64_t left_m = LD(left); + const uint64_t top_m = LD(top); + INSERT_D2_UB(left_m, top_m, src); + CALC_DC8(src, out); + } else if (left != NULL) { // left but no top + const uint64_t left_m = LD(left); + INSERT_D2_UB(left_m, left_m, src); + CALC_DC8(src, out); + } else if (top != NULL) { // top but no left + const uint64_t top_m = LD(top); + INSERT_D2_UB(top_m, top_m, src); + CALC_DC8(src, out); + } else { // no top, no left, nothing. + src = (v16u8)__msa_fill_b(0x80); + out = __msa_copy_s_d((v2i64)src, 0); + } + STORE8x8(out, dst); +} + +static void IntraChromaPreds(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + // U block + DCMode8x8(C8DC8 + dst, left, top); + VerticalPred8x8(C8VE8 + dst, top); + HorizontalPred8x8(C8HE8 + dst, left); + TrueMotion8x8(C8TM8 + dst, left, top); + // V block + dst += 8; + if (top != NULL) top += 8; + if (left != NULL) left += 16; + DCMode8x8(C8DC8 + dst, left, top); + VerticalPred8x8(C8VE8 + dst, top); + HorizontalPred8x8(C8HE8 + dst, left); + TrueMotion8x8(C8TM8 + dst, left, top); +} + +//------------------------------------------------------------------------------ +// Metric + +#define PACK_DOTP_UB4_SW(in0, in1, in2, in3, out0, out1, out2, out3) do { \ + v16u8 tmp0, tmp1; \ + v8i16 tmp2, tmp3; \ + ILVRL_B2_UB(in0, in1, tmp0, tmp1); \ + HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ + DOTP_SH2_SW(tmp2, tmp3, tmp2, tmp3, out0, out1); \ + ILVRL_B2_UB(in2, in3, tmp0, tmp1); \ + HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ + DOTP_SH2_SW(tmp2, tmp3, tmp2, tmp3, out2, out3); \ +} while (0) + +#define PACK_DPADD_UB4_SW(in0, in1, in2, in3, out0, out1, out2, out3) do { \ + v16u8 tmp0, tmp1; \ + v8i16 tmp2, tmp3; \ + ILVRL_B2_UB(in0, in1, tmp0, tmp1); \ + HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ + DPADD_SH2_SW(tmp2, tmp3, tmp2, tmp3, out0, out1); \ + ILVRL_B2_UB(in2, in3, tmp0, tmp1); \ + HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ + DPADD_SH2_SW(tmp2, tmp3, tmp2, tmp3, out2, out3); \ +} while (0) + +static int SSE16x16(const uint8_t* a, const uint8_t* b) { + uint32_t sum; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; + v4i32 out0, out1, out2, out3; + + LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); + PACK_DOTP_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); + a += 8 * BPS; + b += 8 * BPS; + LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); + PACK_DPADD_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); + out0 += out1; + out2 += out3; + out0 += out2; + sum = HADD_SW_S32(out0); + return sum; +} + +static int SSE16x8(const uint8_t* a, const uint8_t* b) { + uint32_t sum; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; + v4i32 out0, out1, out2, out3; + + LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); + PACK_DOTP_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); + out0 += out1; + out2 += out3; + out0 += out2; + sum = HADD_SW_S32(out0); + return sum; +} + +static int SSE8x8(const uint8_t* a, const uint8_t* b) { + uint32_t sum; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; + v16u8 t0, t1, t2, t3; + v4i32 out0, out1, out2, out3; + + LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); + ILVR_B4_UB(src0, src1, src2, src3, ref0, ref1, ref2, ref3, t0, t1, t2, t3); + PACK_DOTP_UB4_SW(t0, t2, t1, t3, out0, out1, out2, out3); + ILVR_B4_UB(src4, src5, src6, src7, ref4, ref5, ref6, ref7, t0, t1, t2, t3); + PACK_DPADD_UB4_SW(t0, t2, t1, t3, out0, out1, out2, out3); + out0 += out1; + out2 += out3; + out0 += out2; + sum = HADD_SW_S32(out0); + return sum; +} + +static int SSE4x4(const uint8_t* a, const uint8_t* b) { + uint32_t sum = 0; + uint32_t src0, src1, src2, src3, ref0, ref1, ref2, ref3; + v16u8 src, ref, tmp0, tmp1; + v8i16 diff0, diff1; + v4i32 out0, out1; + + LW4(a, BPS, src0, src1, src2, src3); + LW4(b, BPS, ref0, ref1, ref2, ref3); + INSERT_W4_UB(src0, src1, src2, src3, src); + INSERT_W4_UB(ref0, ref1, ref2, ref3, ref); + ILVRL_B2_UB(src, ref, tmp0, tmp1); + HSUB_UB2_SH(tmp0, tmp1, diff0, diff1); + DOTP_SH2_SW(diff0, diff1, diff0, diff1, out0, out1); + out0 += out1; + sum = HADD_SW_S32(out0); + return sum; +} + +//------------------------------------------------------------------------------ +// Quantization + +static int QuantizeBlock(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + int sum; + v8i16 in0, in1, sh0, sh1, out0, out1; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, sign0, sign1; + v4i32 s0, s1, s2, s3, b0, b1, b2, b3, t0, t1, t2, t3; + const v8i16 zero = { 0 }; + const v8i16 zigzag0 = { 0, 1, 4, 8, 5, 2, 3, 6 }; + const v8i16 zigzag1 = { 9, 12, 13, 10, 7, 11, 14, 15 }; + const v8i16 maxlevel = __msa_fill_h(MAX_LEVEL); + + LD_SH2(&in[0], 8, in0, in1); + LD_SH2(&mtx->sharpen_[0], 8, sh0, sh1); + tmp4 = __msa_add_a_h(in0, zero); + tmp5 = __msa_add_a_h(in1, zero); + ILVRL_H2_SH(sh0, tmp4, tmp0, tmp1); + ILVRL_H2_SH(sh1, tmp5, tmp2, tmp3); + HADD_SH4_SW(tmp0, tmp1, tmp2, tmp3, s0, s1, s2, s3); + sign0 = (in0 < zero); + sign1 = (in1 < zero); // sign + LD_SH2(&mtx->iq_[0], 8, tmp0, tmp1); // iq + ILVRL_H2_SW(zero, tmp0, t0, t1); + ILVRL_H2_SW(zero, tmp1, t2, t3); + LD_SW4(&mtx->bias_[0], 4, b0, b1, b2, b3); // bias + MUL4(t0, s0, t1, s1, t2, s2, t3, s3, t0, t1, t2, t3); + ADD4(b0, t0, b1, t1, b2, t2, b3, t3, b0, b1, b2, b3); + SRAI_W4_SW(b0, b1, b2, b3, 17); + PCKEV_H2_SH(b1, b0, b3, b2, tmp2, tmp3); + tmp0 = (tmp2 > maxlevel); + tmp1 = (tmp3 > maxlevel); + tmp2 = (v8i16)__msa_bmnz_v((v16u8)tmp2, (v16u8)maxlevel, (v16u8)tmp0); + tmp3 = (v8i16)__msa_bmnz_v((v16u8)tmp3, (v16u8)maxlevel, (v16u8)tmp1); + SUB2(0, tmp2, 0, tmp3, tmp0, tmp1); + tmp2 = (v8i16)__msa_bmnz_v((v16u8)tmp2, (v16u8)tmp0, (v16u8)sign0); + tmp3 = (v8i16)__msa_bmnz_v((v16u8)tmp3, (v16u8)tmp1, (v16u8)sign1); + LD_SW4(&mtx->zthresh_[0], 4, t0, t1, t2, t3); // zthresh + t0 = (s0 > t0); + t1 = (s1 > t1); + t2 = (s2 > t2); + t3 = (s3 > t3); + PCKEV_H2_SH(t1, t0, t3, t2, tmp0, tmp1); + tmp4 = (v8i16)__msa_bmnz_v((v16u8)zero, (v16u8)tmp2, (v16u8)tmp0); + tmp5 = (v8i16)__msa_bmnz_v((v16u8)zero, (v16u8)tmp3, (v16u8)tmp1); + LD_SH2(&mtx->q_[0], 8, tmp0, tmp1); + MUL2(tmp4, tmp0, tmp5, tmp1, in0, in1); + VSHF_H2_SH(tmp4, tmp5, tmp4, tmp5, zigzag0, zigzag1, out0, out1); + ST_SH2(in0, in1, &in[0], 8); + ST_SH2(out0, out1, &out[0], 8); + out0 = __msa_add_a_h(out0, out1); + sum = HADD_SH_S32(out0); + return (sum > 0); +} + +static int Quantize2Blocks(int16_t in[32], int16_t out[32], + const VP8Matrix* const mtx) { + int nz; + nz = VP8EncQuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0; + nz |= VP8EncQuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1; + return nz; +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMSA(void) { + VP8ITransform = ITransform; + VP8FTransform = FTransform; + VP8FTransformWHT = FTransformWHT; + + VP8TDisto4x4 = Disto4x4; + VP8TDisto16x16 = Disto16x16; + VP8CollectHistogram = CollectHistogram; + + VP8EncPredLuma4 = Intra4Preds; + VP8EncPredLuma16 = Intra16Preds; + VP8EncPredChroma8 = IntraChromaPreds; + + VP8SSE16x16 = SSE16x16; + VP8SSE16x8 = SSE16x8; + VP8SSE8x8 = SSE8x8; + VP8SSE4x4 = SSE4x4; + + VP8EncQuantizeBlock = QuantizeBlock; + VP8EncQuantize2Blocks = Quantize2Blocks; + VP8EncQuantizeBlockWHT = QuantizeBlock; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8EncDspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/src/3rdparty/libwebp/src/dsp/enc_neon.c b/src/3rdparty/libwebp/src/dsp/enc_neon.c index 46f6bf9a33f8d3fcf16b9bbebd9b11161a9c15d9..6a078d632d89572df9aa7f85400b3ae7cfb42c7c 100644 --- a/src/3rdparty/libwebp/src/dsp/enc_neon.c +++ b/src/3rdparty/libwebp/src/dsp/enc_neon.c @@ -18,7 +18,7 @@ #include <assert.h> #include "./neon.h" -#include "../enc/vp8enci.h" +#include "../enc/vp8i_enc.h" //------------------------------------------------------------------------------ // Transforms (Paragraph 14.4) @@ -746,9 +746,14 @@ static WEBP_INLINE void AccumulateSSE16(const uint8_t* const a, const uint8x16_t a0 = vld1q_u8(a); const uint8x16_t b0 = vld1q_u8(b); const uint8x16_t abs_diff = vabdq_u8(a0, b0); - uint16x8_t prod = vmull_u8(vget_low_u8(abs_diff), vget_low_u8(abs_diff)); - prod = vmlal_u8(prod, vget_high_u8(abs_diff), vget_high_u8(abs_diff)); - *sum = vpadalq_u16(*sum, prod); // pair-wise add and accumulate + const uint16x8_t prod1 = vmull_u8(vget_low_u8(abs_diff), + vget_low_u8(abs_diff)); + const uint16x8_t prod2 = vmull_u8(vget_high_u8(abs_diff), + vget_high_u8(abs_diff)); + /* pair-wise adds and widen */ + const uint32x4_t sum1 = vpaddlq_u16(prod1); + const uint32x4_t sum2 = vpaddlq_u16(prod2); + *sum = vaddq_u32(*sum, vaddq_u32(sum1, sum2)); } // Horizontal sum of all four uint32_t values in 'sum'. @@ -758,7 +763,7 @@ static int SumToInt(uint32x4_t sum) { return (int)sum3; } -static int SSE16x16(const uint8_t* a, const uint8_t* b) { +static int SSE16x16_NEON(const uint8_t* a, const uint8_t* b) { uint32x4_t sum = vdupq_n_u32(0); int y; for (y = 0; y < 16; ++y) { @@ -767,7 +772,7 @@ static int SSE16x16(const uint8_t* a, const uint8_t* b) { return SumToInt(sum); } -static int SSE16x8(const uint8_t* a, const uint8_t* b) { +static int SSE16x8_NEON(const uint8_t* a, const uint8_t* b) { uint32x4_t sum = vdupq_n_u32(0); int y; for (y = 0; y < 8; ++y) { @@ -776,7 +781,7 @@ static int SSE16x8(const uint8_t* a, const uint8_t* b) { return SumToInt(sum); } -static int SSE8x8(const uint8_t* a, const uint8_t* b) { +static int SSE8x8_NEON(const uint8_t* a, const uint8_t* b) { uint32x4_t sum = vdupq_n_u32(0); int y; for (y = 0; y < 8; ++y) { @@ -789,13 +794,18 @@ static int SSE8x8(const uint8_t* a, const uint8_t* b) { return SumToInt(sum); } -static int SSE4x4(const uint8_t* a, const uint8_t* b) { +static int SSE4x4_NEON(const uint8_t* a, const uint8_t* b) { const uint8x16_t a0 = Load4x4(a); const uint8x16_t b0 = Load4x4(b); const uint8x16_t abs_diff = vabdq_u8(a0, b0); - uint16x8_t prod = vmull_u8(vget_low_u8(abs_diff), vget_low_u8(abs_diff)); - prod = vmlal_u8(prod, vget_high_u8(abs_diff), vget_high_u8(abs_diff)); - return SumToInt(vpaddlq_u16(prod)); + const uint16x8_t prod1 = vmull_u8(vget_low_u8(abs_diff), + vget_low_u8(abs_diff)); + const uint16x8_t prod2 = vmull_u8(vget_high_u8(abs_diff), + vget_high_u8(abs_diff)); + /* pair-wise adds and widen */ + const uint32x4_t sum1 = vpaddlq_u16(prod1); + const uint32x4_t sum2 = vpaddlq_u16(prod2); + return SumToInt(vaddq_u32(sum1, sum2)); } //------------------------------------------------------------------------------ @@ -903,10 +913,12 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitNEON(void) { VP8TDisto4x4 = Disto4x4; VP8TDisto16x16 = Disto16x16; VP8CollectHistogram = CollectHistogram; - VP8SSE16x16 = SSE16x16; - VP8SSE16x8 = SSE16x8; - VP8SSE8x8 = SSE8x8; - VP8SSE4x4 = SSE4x4; + + VP8SSE16x16 = SSE16x16_NEON; + VP8SSE16x8 = SSE16x8_NEON; + VP8SSE8x8 = SSE8x8_NEON; + VP8SSE4x4 = SSE4x4_NEON; + #if !defined(WORK_AROUND_GCC) VP8EncQuantizeBlock = QuantizeBlock; VP8EncQuantize2Blocks = Quantize2Blocks; diff --git a/src/3rdparty/libwebp/src/dsp/enc_sse2.c b/src/3rdparty/libwebp/src/dsp/enc_sse2.c index 4a2e3ce14f8d390de9f7b4b5e027a80c1631fc03..2026a74c91afaae9ddbb5fae16ffad7dfd2e1193 100644 --- a/src/3rdparty/libwebp/src/dsp/enc_sse2.c +++ b/src/3rdparty/libwebp/src/dsp/enc_sse2.c @@ -14,12 +14,13 @@ #include "./dsp.h" #if defined(WEBP_USE_SSE2) +#include <assert.h> #include <stdlib.h> // for abs() #include <emmintrin.h> #include "./common_sse2.h" -#include "../enc/cost.h" -#include "../enc/vp8enci.h" +#include "../enc/cost_enc.h" +#include "../enc/vp8i_enc.h" //------------------------------------------------------------------------------ // Transforms (Paragraph 14.4) @@ -139,7 +140,7 @@ static void ITransform(const uint8_t* ref, const int16_t* in, uint8_t* dst, // Transpose the two 4x4. VP8Transpose_2_4x4_16b(&shifted0, &shifted1, &shifted2, &shifted3, &T0, &T1, - &T2, &T3); + &T2, &T3); } // Add inverse transform to 'ref' and store. @@ -250,25 +251,11 @@ static void FTransformPass2(const __m128i* const v01, const __m128i* const v32, const __m128i k51000 = _mm_set1_epi32(51000); // Same operations are done on the (0,3) and (1,2) pairs. - // a0 = v0 + v3 - // a1 = v1 + v2 // a3 = v0 - v3 // a2 = v1 - v2 - const __m128i a01 = _mm_add_epi16(*v01, *v32); const __m128i a32 = _mm_sub_epi16(*v01, *v32); - const __m128i a11 = _mm_unpackhi_epi64(a01, a01); const __m128i a22 = _mm_unpackhi_epi64(a32, a32); - const __m128i a01_plus_7 = _mm_add_epi16(a01, seven); - // d0 = (a0 + a1 + 7) >> 4; - // d2 = (a0 - a1 + 7) >> 4; - const __m128i c0 = _mm_add_epi16(a01_plus_7, a11); - const __m128i c2 = _mm_sub_epi16(a01_plus_7, a11); - const __m128i d0 = _mm_srai_epi16(c0, 4); - const __m128i d2 = _mm_srai_epi16(c2, 4); - - // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16) - // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16) const __m128i b23 = _mm_unpacklo_epi16(a22, a32); const __m128i c1 = _mm_madd_epi16(b23, k5352_2217); const __m128i c3 = _mm_madd_epi16(b23, k2217_5352); @@ -276,14 +263,28 @@ static void FTransformPass2(const __m128i* const v01, const __m128i* const v32, const __m128i d3 = _mm_add_epi32(c3, k51000); const __m128i e1 = _mm_srai_epi32(d1, 16); const __m128i e3 = _mm_srai_epi32(d3, 16); + // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16) + // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16) const __m128i f1 = _mm_packs_epi32(e1, e1); const __m128i f3 = _mm_packs_epi32(e3, e3); - // f1 = f1 + (a3 != 0); + // g1 = f1 + (a3 != 0); // The compare will return (0xffff, 0) for (==0, !=0). To turn that into the // desired (0, 1), we add one earlier through k12000_plus_one. - // -> f1 = f1 + 1 - (a3 == 0) + // -> g1 = f1 + 1 - (a3 == 0) const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero)); + // a0 = v0 + v3 + // a1 = v1 + v2 + const __m128i a01 = _mm_add_epi16(*v01, *v32); + const __m128i a01_plus_7 = _mm_add_epi16(a01, seven); + const __m128i a11 = _mm_unpackhi_epi64(a01, a01); + const __m128i c0 = _mm_add_epi16(a01_plus_7, a11); + const __m128i c2 = _mm_sub_epi16(a01_plus_7, a11); + // d0 = (a0 + a1 + 7) >> 4; + // d2 = (a0 - a1 + 7) >> 4; + const __m128i d0 = _mm_srai_epi16(c0, 4); + const __m128i d2 = _mm_srai_epi16(c2, 4); + const __m128i d0_g1 = _mm_unpacklo_epi64(d0, g1); const __m128i d2_f3 = _mm_unpacklo_epi64(d2, f3); _mm_storeu_si128((__m128i*)&out[0], d0_g1); @@ -1045,6 +1046,37 @@ static int SSE4x4(const uint8_t* a, const uint8_t* b) { return (tmp[3] + tmp[2] + tmp[1] + tmp[0]); } +//------------------------------------------------------------------------------ + +static void Mean16x4(const uint8_t* ref, uint32_t dc[4]) { + const __m128i mask = _mm_set1_epi16(0x00ff); + const __m128i a0 = _mm_loadu_si128((const __m128i*)&ref[BPS * 0]); + const __m128i a1 = _mm_loadu_si128((const __m128i*)&ref[BPS * 1]); + const __m128i a2 = _mm_loadu_si128((const __m128i*)&ref[BPS * 2]); + const __m128i a3 = _mm_loadu_si128((const __m128i*)&ref[BPS * 3]); + const __m128i b0 = _mm_srli_epi16(a0, 8); // hi byte + const __m128i b1 = _mm_srli_epi16(a1, 8); + const __m128i b2 = _mm_srli_epi16(a2, 8); + const __m128i b3 = _mm_srli_epi16(a3, 8); + const __m128i c0 = _mm_and_si128(a0, mask); // lo byte + const __m128i c1 = _mm_and_si128(a1, mask); + const __m128i c2 = _mm_and_si128(a2, mask); + const __m128i c3 = _mm_and_si128(a3, mask); + const __m128i d0 = _mm_add_epi32(b0, c0); + const __m128i d1 = _mm_add_epi32(b1, c1); + const __m128i d2 = _mm_add_epi32(b2, c2); + const __m128i d3 = _mm_add_epi32(b3, c3); + const __m128i e0 = _mm_add_epi32(d0, d1); + const __m128i e1 = _mm_add_epi32(d2, d3); + const __m128i f0 = _mm_add_epi32(e0, e1); + uint16_t tmp[8]; + _mm_storeu_si128((__m128i*)tmp, f0); + dc[0] = tmp[0] + tmp[1]; + dc[1] = tmp[2] + tmp[3]; + dc[2] = tmp[4] + tmp[5]; + dc[3] = tmp[6] + tmp[7]; +} + //------------------------------------------------------------------------------ // Texture distortion // @@ -1331,10 +1363,122 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitSSE2(void) { VP8SSE4x4 = SSE4x4; VP8TDisto4x4 = Disto4x4; VP8TDisto16x16 = Disto16x16; + VP8Mean16x4 = Mean16x4; +} + +//------------------------------------------------------------------------------ +// SSIM / PSNR entry point (TODO(skal): move to its own file later) + +static uint32_t AccumulateSSE_SSE2(const uint8_t* src1, + const uint8_t* src2, int len) { + int i = 0; + uint32_t sse2 = 0; + if (len >= 16) { + const int limit = len - 32; + int32_t tmp[4]; + __m128i sum1; + __m128i sum = _mm_setzero_si128(); + __m128i a0 = _mm_loadu_si128((const __m128i*)&src1[i]); + __m128i b0 = _mm_loadu_si128((const __m128i*)&src2[i]); + i += 16; + while (i <= limit) { + const __m128i a1 = _mm_loadu_si128((const __m128i*)&src1[i]); + const __m128i b1 = _mm_loadu_si128((const __m128i*)&src2[i]); + __m128i sum2; + i += 16; + SubtractAndAccumulate(a0, b0, &sum1); + sum = _mm_add_epi32(sum, sum1); + a0 = _mm_loadu_si128((const __m128i*)&src1[i]); + b0 = _mm_loadu_si128((const __m128i*)&src2[i]); + i += 16; + SubtractAndAccumulate(a1, b1, &sum2); + sum = _mm_add_epi32(sum, sum2); + } + SubtractAndAccumulate(a0, b0, &sum1); + sum = _mm_add_epi32(sum, sum1); + _mm_storeu_si128((__m128i*)tmp, sum); + sse2 += (tmp[3] + tmp[2] + tmp[1] + tmp[0]); + } + + for (; i < len; ++i) { + const int32_t diff = src1[i] - src2[i]; + sse2 += diff * diff; + } + return sse2; +} + +static uint32_t HorizontalAdd16b(const __m128i* const m) { + uint16_t tmp[8]; + const __m128i a = _mm_srli_si128(*m, 8); + const __m128i b = _mm_add_epi16(*m, a); + _mm_storeu_si128((__m128i*)tmp, b); + return (uint32_t)tmp[3] + tmp[2] + tmp[1] + tmp[0]; +} + +static uint32_t HorizontalAdd32b(const __m128i* const m) { + const __m128i a = _mm_srli_si128(*m, 8); + const __m128i b = _mm_add_epi32(*m, a); + const __m128i c = _mm_add_epi32(b, _mm_srli_si128(b, 4)); + return (uint32_t)_mm_cvtsi128_si32(c); +} + +static const uint16_t kWeight[] = { 1, 2, 3, 4, 3, 2, 1, 0 }; + +#define ACCUMULATE_ROW(WEIGHT) do { \ + /* compute row weight (Wx * Wy) */ \ + const __m128i Wy = _mm_set1_epi16((WEIGHT)); \ + const __m128i W = _mm_mullo_epi16(Wx, Wy); \ + /* process 8 bytes at a time (7 bytes, actually) */ \ + const __m128i a0 = _mm_loadl_epi64((const __m128i*)src1); \ + const __m128i b0 = _mm_loadl_epi64((const __m128i*)src2); \ + /* convert to 16b and multiply by weight */ \ + const __m128i a1 = _mm_unpacklo_epi8(a0, zero); \ + const __m128i b1 = _mm_unpacklo_epi8(b0, zero); \ + const __m128i wa1 = _mm_mullo_epi16(a1, W); \ + const __m128i wb1 = _mm_mullo_epi16(b1, W); \ + /* accumulate */ \ + xm = _mm_add_epi16(xm, wa1); \ + ym = _mm_add_epi16(ym, wb1); \ + xxm = _mm_add_epi32(xxm, _mm_madd_epi16(a1, wa1)); \ + xym = _mm_add_epi32(xym, _mm_madd_epi16(a1, wb1)); \ + yym = _mm_add_epi32(yym, _mm_madd_epi16(b1, wb1)); \ + src1 += stride1; \ + src2 += stride2; \ +} while (0) + +static double SSIMGet_SSE2(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2) { + VP8DistoStats stats; + const __m128i zero = _mm_setzero_si128(); + __m128i xm = zero, ym = zero; // 16b accums + __m128i xxm = zero, yym = zero, xym = zero; // 32b accum + const __m128i Wx = _mm_loadu_si128((const __m128i*)kWeight); + assert(2 * VP8_SSIM_KERNEL + 1 == 7); + ACCUMULATE_ROW(1); + ACCUMULATE_ROW(2); + ACCUMULATE_ROW(3); + ACCUMULATE_ROW(4); + ACCUMULATE_ROW(3); + ACCUMULATE_ROW(2); + ACCUMULATE_ROW(1); + stats.xm = HorizontalAdd16b(&xm); + stats.ym = HorizontalAdd16b(&ym); + stats.xxm = HorizontalAdd32b(&xxm); + stats.xym = HorizontalAdd32b(&xym); + stats.yym = HorizontalAdd32b(&yym); + return VP8SSIMFromStats(&stats); +} + +extern void VP8SSIMDspInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8SSIMDspInitSSE2(void) { + VP8AccumulateSSE = AccumulateSSE_SSE2; + VP8SSIMGet = SSIMGet_SSE2; } #else // !WEBP_USE_SSE2 WEBP_DSP_INIT_STUB(VP8EncDspInitSSE2) +WEBP_DSP_INIT_STUB(VP8SSIMDspInitSSE2) #endif // WEBP_USE_SSE2 diff --git a/src/3rdparty/libwebp/src/dsp/enc_sse41.c b/src/3rdparty/libwebp/src/dsp/enc_sse41.c index a1783901a6b48af3d9d2f040b3fd509726a45439..e32086d9fd3fa475c5ee7aeb9c33ac0dd4bb7e2a 100644 --- a/src/3rdparty/libwebp/src/dsp/enc_sse41.c +++ b/src/3rdparty/libwebp/src/dsp/enc_sse41.c @@ -18,7 +18,7 @@ #include <stdlib.h> // for abs() #include "./common_sse2.h" -#include "../enc/vp8enci.h" +#include "../enc/vp8i_enc.h" //------------------------------------------------------------------------------ // Compute susceptibility based on DCT-coeff histograms. diff --git a/src/3rdparty/libwebp/src/dsp/filters.c b/src/3rdparty/libwebp/src/dsp/filters.c index 9f04faf0cb1a4430f4600393aafabf841f8217e1..65f34aad1f17971bc8c11657baf2306e6d1e9d68 100644 --- a/src/3rdparty/libwebp/src/dsp/filters.c +++ b/src/3rdparty/libwebp/src/dsp/filters.c @@ -227,6 +227,8 @@ WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST]; extern void VP8FiltersInitMIPSdspR2(void); +extern void VP8FiltersInitMSA(void); +extern void VP8FiltersInitNEON(void); extern void VP8FiltersInitSSE2(void); static volatile VP8CPUInfo filters_last_cpuinfo_used = @@ -251,10 +253,20 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) { VP8FiltersInitSSE2(); } #endif +#if defined(WEBP_USE_NEON) + if (VP8GetCPUInfo(kNEON)) { + VP8FiltersInitNEON(); + } +#endif #if defined(WEBP_USE_MIPS_DSP_R2) if (VP8GetCPUInfo(kMIPSdspR2)) { VP8FiltersInitMIPSdspR2(); } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8FiltersInitMSA(); + } #endif } filters_last_cpuinfo_used = VP8GetCPUInfo; diff --git a/src/3rdparty/libwebp/src/dsp/filters_msa.c b/src/3rdparty/libwebp/src/dsp/filters_msa.c new file mode 100644 index 0000000000000000000000000000000000000000..4b8922d0bcccc7f181b2d7a55f062b752e183421 --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/filters_msa.c @@ -0,0 +1,202 @@ +// Copyright 2016 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. +// ----------------------------------------------------------------------------- +// +// MSA variant of alpha filters +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include "./dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "./msa_macro.h" + +#include <assert.h> + +static WEBP_INLINE void PredictLineInverse0(const uint8_t* src, + const uint8_t* pred, + uint8_t* dst, int length) { + v16u8 src0, pred0, dst0; + assert(length >= 0); + while (length >= 32) { + v16u8 src1, pred1, dst1; + LD_UB2(src, 16, src0, src1); + LD_UB2(pred, 16, pred0, pred1); + SUB2(src0, pred0, src1, pred1, dst0, dst1); + ST_UB2(dst0, dst1, dst, 16); + src += 32; + pred += 32; + dst += 32; + length -= 32; + } + if (length > 0) { + int i; + if (length >= 16) { + src0 = LD_UB(src); + pred0 = LD_UB(pred); + dst0 = src0 - pred0; + ST_UB(dst0, dst); + src += 16; + pred += 16; + dst += 16; + length -= 16; + } + for (i = 0; i < length; i++) { + dst[i] = src[i] - pred[i]; + } + } +} + +//------------------------------------------------------------------------------ +// Helpful macro. + +#define SANITY_CHECK(in, out) \ + assert(in != NULL); \ + assert(out != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(stride >= width); + +//------------------------------------------------------------------------------ +// Horrizontal filter + +static void HorizontalFilter(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + const uint8_t* preds = data; + const uint8_t* in = data; + uint8_t* out = filtered_data; + int row = 1; + SANITY_CHECK(in, out); + + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLineInverse0(in + 1, preds, out + 1, width - 1); + preds += stride; + in += stride; + out += stride; + // Filter line-by-line. + while (row < height) { + // Leftmost pixel is predicted from above. + PredictLineInverse0(in, preds - stride, out, 1); + PredictLineInverse0(in + 1, preds, out + 1, width - 1); + ++row; + preds += stride; + in += stride; + out += stride; + } +} + +//------------------------------------------------------------------------------ +// Gradient filter + +static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput, + const uint8_t* ppred, + uint8_t* poutput, int stride, + int size) { + int w; + const v16i8 zero = { 0 }; + while (size >= 16) { + v16u8 pred0, dst0; + v8i16 a0, a1, b0, b1, c0, c1; + const v16u8 tmp0 = LD_UB(ppred - 1); + const v16u8 tmp1 = LD_UB(ppred - stride); + const v16u8 tmp2 = LD_UB(ppred - stride - 1); + const v16u8 src0 = LD_UB(pinput); + ILVRL_B2_SH(zero, tmp0, a0, a1); + ILVRL_B2_SH(zero, tmp1, b0, b1); + ILVRL_B2_SH(zero, tmp2, c0, c1); + ADD2(a0, b0, a1, b1, a0, a1); + SUB2(a0, c0, a1, c1, a0, a1); + CLIP_SH2_0_255(a0, a1); + pred0 = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0); + dst0 = src0 - pred0; + ST_UB(dst0, poutput); + ppred += 16; + pinput += 16; + poutput += 16; + size -= 16; + } + for (w = 0; w < size; ++w) { + const int pred = ppred[w - 1] + ppred[w - stride] - ppred[w - stride - 1]; + poutput[w] = pinput[w] - (pred < 0 ? 0 : pred > 255 ? 255 : pred); + } +} + + +static void GradientFilter(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + const uint8_t* in = data; + const uint8_t* preds = data; + uint8_t* out = filtered_data; + int row = 1; + SANITY_CHECK(in, out); + + // left prediction for top scan-line + out[0] = in[0]; + PredictLineInverse0(in + 1, preds, out + 1, width - 1); + preds += stride; + in += stride; + out += stride; + // Filter line-by-line. + while (row < height) { + out[0] = in[0] - preds[- stride]; + PredictLineGradient(preds + 1, in + 1, out + 1, stride, width - 1); + ++row; + preds += stride; + in += stride; + out += stride; + } +} + +//------------------------------------------------------------------------------ +// Vertical filter + +static void VerticalFilter(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + const uint8_t* in = data; + const uint8_t* preds = data; + uint8_t* out = filtered_data; + int row = 1; + SANITY_CHECK(in, out); + + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLineInverse0(in + 1, preds, out + 1, width - 1); + in += stride; + out += stride; + + // Filter line-by-line. + while (row < height) { + PredictLineInverse0(in, preds, out, width); + ++row; + preds += stride; + in += stride; + out += stride; + } +} + +#undef SANITY_CHECK + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8FiltersInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMSA(void) { + WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter; + WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter; + WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8FiltersInitMSA) + +#endif // WEBP_USE_MSA diff --git a/src/3rdparty/libwebp/src/dsp/filters_neon.c b/src/3rdparty/libwebp/src/dsp/filters_neon.c new file mode 100644 index 0000000000000000000000000000000000000000..4d6e50cc764106d1a6099199b9e53bc8ab4bfb7b --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/filters_neon.c @@ -0,0 +1,327 @@ +// Copyright 2017 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. +// ----------------------------------------------------------------------------- +// +// NEON variant of alpha filters +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "./dsp.h" + +#if defined(WEBP_USE_NEON) + +#include <assert.h> +#include "./neon.h" + +//------------------------------------------------------------------------------ +// Helpful macros. + +# define SANITY_CHECK(in, out) \ + assert(in != NULL); \ + assert(out != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(stride >= width); \ + assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ + (void)height; // Silence unused warning. + +// load eight u8 and widen to s16 +#define U8_TO_S16(A) vreinterpretq_s16_u16(vmovl_u8(A)) +#define LOAD_U8_TO_S16(A) U8_TO_S16(vld1_u8(A)) + +// shift left or right by N byte, inserting zeros +#define SHIFT_RIGHT_N_Q(A, N) vextq_u8((A), zero, (N)) +#define SHIFT_LEFT_N_Q(A, N) vextq_u8(zero, (A), (16 - (N)) % 16) + +// rotate left by N bytes +#define ROTATE_LEFT_N(A, N) vext_u8((A), (A), (N)) +// rotate right by N bytes +#define ROTATE_RIGHT_N(A, N) vext_u8((A), (A), (8 - (N)) % 8) + +static void PredictLine_NEON(const uint8_t* src, const uint8_t* pred, + uint8_t* dst, int length) { + int i; + assert(length >= 0); + for (i = 0; i + 16 <= length; i += 16) { + const uint8x16_t A = vld1q_u8(&src[i]); + const uint8x16_t B = vld1q_u8(&pred[i]); + const uint8x16_t C = vsubq_u8(A, B); + vst1q_u8(&dst[i], C); + } + for (; i < length; ++i) dst[i] = src[i] - pred[i]; +} + +// Special case for left-based prediction (when preds==dst-1 or preds==src-1). +static void PredictLineLeft_NEON(const uint8_t* src, uint8_t* dst, int length) { + PredictLine_NEON(src, src - 1, dst, length); +} + +//------------------------------------------------------------------------------ +// Horizontal filter. + +static WEBP_INLINE void DoHorizontalFilter_NEON(const uint8_t* in, + int width, int height, + int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + SANITY_CHECK(in, out); + in += start_offset; + out += start_offset; + + if (row == 0) { + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + // Leftmost pixel is predicted from above. + out[0] = in[0] - in[-stride]; + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + ++row; + in += stride; + out += stride; + } +} + +static void HorizontalFilter_NEON(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoHorizontalFilter_NEON(data, width, height, stride, 0, height, + filtered_data); +} + +//------------------------------------------------------------------------------ +// Vertical filter. + +static WEBP_INLINE void DoVerticalFilter_NEON(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + SANITY_CHECK(in, out); + in += start_offset; + out += start_offset; + + if (row == 0) { + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + PredictLine_NEON(in, in - stride, out, width); + ++row; + in += stride; + out += stride; + } +} + +static void VerticalFilter_NEON(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoVerticalFilter_NEON(data, width, height, stride, 0, height, + filtered_data); +} + +//------------------------------------------------------------------------------ +// Gradient filter. + +static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) { + const int g = a + b - c; + return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit +} + +static void GradientPredictDirect_NEON(const uint8_t* const row, + const uint8_t* const top, + uint8_t* const out, int length) { + int i; + for (i = 0; i + 8 <= length; i += 8) { + const uint8x8_t A = vld1_u8(&row[i - 1]); + const uint8x8_t B = vld1_u8(&top[i + 0]); + const int16x8_t C = vreinterpretq_s16_u16(vaddl_u8(A, B)); + const int16x8_t D = LOAD_U8_TO_S16(&top[i - 1]); + const uint8x8_t E = vqmovun_s16(vsubq_s16(C, D)); + const uint8x8_t F = vld1_u8(&row[i + 0]); + vst1_u8(&out[i], vsub_u8(F, E)); + } + for (; i < length; ++i) { + out[i] = row[i] - GradientPredictor_C(row[i - 1], top[i], top[i - 1]); + } +} + +static WEBP_INLINE void DoGradientFilter_NEON(const uint8_t* in, + int width, int height, + int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + SANITY_CHECK(in, out); + in += start_offset; + out += start_offset; + + // left prediction for top scan-line + if (row == 0) { + out[0] = in[0]; + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + out[0] = in[0] - in[-stride]; + GradientPredictDirect_NEON(in + 1, in + 1 - stride, out + 1, width - 1); + ++row; + in += stride; + out += stride; + } +} + +static void GradientFilter_NEON(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoGradientFilter_NEON(data, width, height, stride, 0, height, + filtered_data); +} + +#undef SANITY_CHECK + +//------------------------------------------------------------------------------ +// Inverse transforms + +static void HorizontalUnfilter_NEON(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + int i; + const uint8x16_t zero = vdupq_n_u8(0); + uint8x16_t last; + out[0] = in[0] + (prev == NULL ? 0 : prev[0]); + if (width <= 1) return; + last = vsetq_lane_u8(out[0], zero, 0); + for (i = 1; i + 16 <= width; i += 16) { + const uint8x16_t A0 = vld1q_u8(&in[i]); + const uint8x16_t A1 = vaddq_u8(A0, last); + const uint8x16_t A2 = SHIFT_LEFT_N_Q(A1, 1); + const uint8x16_t A3 = vaddq_u8(A1, A2); + const uint8x16_t A4 = SHIFT_LEFT_N_Q(A3, 2); + const uint8x16_t A5 = vaddq_u8(A3, A4); + const uint8x16_t A6 = SHIFT_LEFT_N_Q(A5, 4); + const uint8x16_t A7 = vaddq_u8(A5, A6); + const uint8x16_t A8 = SHIFT_LEFT_N_Q(A7, 8); + const uint8x16_t A9 = vaddq_u8(A7, A8); + vst1q_u8(&out[i], A9); + last = SHIFT_RIGHT_N_Q(A9, 15); + } + for (; i < width; ++i) out[i] = in[i] + out[i - 1]; +} + +static void VerticalUnfilter_NEON(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_NEON(NULL, in, out, width); + } else { + int i; + assert(width >= 0); + for (i = 0; i + 16 <= width; i += 16) { + const uint8x16_t A = vld1q_u8(&in[i]); + const uint8x16_t B = vld1q_u8(&prev[i]); + const uint8x16_t C = vaddq_u8(A, B); + vst1q_u8(&out[i], C); + } + for (; i < width; ++i) out[i] = in[i] + prev[i]; + } +} + +// GradientUnfilter_NEON is correct but slower than the C-version, +// at least on ARM64. For armv7, it's a wash. +// So best is to disable it for now, but keep the idea around... +// #define USE_GRADIENT_UNFILTER + +#if defined(USE_GRADIENT_UNFILTER) +#define GRAD_PROCESS_LANE(L) do { \ + const uint8x8_t tmp1 = ROTATE_RIGHT_N(pred, 1); /* rotate predictor in */ \ + const int16x8_t tmp2 = vaddq_s16(BC, U8_TO_S16(tmp1)); \ + const uint8x8_t delta = vqmovun_s16(tmp2); \ + pred = vadd_u8(D, delta); \ + out = vext_u8(out, ROTATE_LEFT_N(pred, (L)), 1); \ +} while (0) + +static void GradientPredictInverse_NEON(const uint8_t* const in, + const uint8_t* const top, + uint8_t* const row, int length) { + if (length > 0) { + int i; + uint8x8_t pred = vdup_n_u8(row[-1]); // left sample + uint8x8_t out = vdup_n_u8(0); + for (i = 0; i + 8 <= length; i += 8) { + const int16x8_t B = LOAD_U8_TO_S16(&top[i + 0]); + const int16x8_t C = LOAD_U8_TO_S16(&top[i - 1]); + const int16x8_t BC = vsubq_s16(B, C); // unclipped gradient basis B - C + const uint8x8_t D = vld1_u8(&in[i]); // base input + GRAD_PROCESS_LANE(0); + GRAD_PROCESS_LANE(1); + GRAD_PROCESS_LANE(2); + GRAD_PROCESS_LANE(3); + GRAD_PROCESS_LANE(4); + GRAD_PROCESS_LANE(5); + GRAD_PROCESS_LANE(6); + GRAD_PROCESS_LANE(7); + vst1_u8(&row[i], out); + } + for (; i < length; ++i) { + row[i] = in[i] + GradientPredictor_C(row[i - 1], top[i], top[i - 1]); + } + } +} +#undef GRAD_PROCESS_LANE + +static void GradientUnfilter_NEON(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_NEON(NULL, in, out, width); + } else { + out[0] = in[0] + prev[0]; // predict from above + GradientPredictInverse_NEON(in + 1, prev + 1, out + 1, width - 1); + } +} + +#endif // USE_GRADIENT_UNFILTER + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8FiltersInitNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitNEON(void) { + WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_NEON; + WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_NEON; +#if defined(USE_GRADIENT_UNFILTER) + WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_NEON; +#endif + + WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_NEON; + WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_NEON; + WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(VP8FiltersInitNEON) + +#endif // WEBP_USE_NEON diff --git a/src/3rdparty/libwebp/src/dsp/lossless.c b/src/3rdparty/libwebp/src/dsp/lossless.c index af913efccb4ae66ee5a11cb7b8231be222c8412f..20d18f6ecdceacbf4d113982e2a5b203d657835c 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless.c +++ b/src/3rdparty/libwebp/src/dsp/lossless.c @@ -17,20 +17,16 @@ #include <math.h> #include <stdlib.h> -#include "../dec/vp8li.h" -#include "../utils/endian_inl.h" +#include "../dec/vp8li_dec.h" +#include "../utils/endian_inl_utils.h" #include "./lossless.h" +#include "./lossless_common.h" #define MAX_DIFF_COST (1e30f) //------------------------------------------------------------------------------ // Image transforms. -// In-place sum of each component with mod 256. -static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) { - *a = VP8LAddPixels(*a, b); -} - static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) { return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1); } @@ -171,21 +167,41 @@ static uint32_t Predictor13(uint32_t left, const uint32_t* const top) { return pred; } +GENERATE_PREDICTOR_ADD(Predictor0, PredictorAdd0) +static void PredictorAdd1(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint32_t left = out[-1]; + for (i = 0; i < num_pixels; ++i) { + out[i] = left = VP8LAddPixels(in[i], left); + } + (void)upper; +} +GENERATE_PREDICTOR_ADD(Predictor2, PredictorAdd2) +GENERATE_PREDICTOR_ADD(Predictor3, PredictorAdd3) +GENERATE_PREDICTOR_ADD(Predictor4, PredictorAdd4) +GENERATE_PREDICTOR_ADD(Predictor5, PredictorAdd5) +GENERATE_PREDICTOR_ADD(Predictor6, PredictorAdd6) +GENERATE_PREDICTOR_ADD(Predictor7, PredictorAdd7) +GENERATE_PREDICTOR_ADD(Predictor8, PredictorAdd8) +GENERATE_PREDICTOR_ADD(Predictor9, PredictorAdd9) +GENERATE_PREDICTOR_ADD(Predictor10, PredictorAdd10) +GENERATE_PREDICTOR_ADD(Predictor11, PredictorAdd11) +GENERATE_PREDICTOR_ADD(Predictor12, PredictorAdd12) +GENERATE_PREDICTOR_ADD(Predictor13, PredictorAdd13) + //------------------------------------------------------------------------------ // Inverse prediction. static void PredictorInverseTransform(const VP8LTransform* const transform, - int y_start, int y_end, uint32_t* data) { + int y_start, int y_end, + const uint32_t* in, uint32_t* out) { const int width = transform->xsize_; if (y_start == 0) { // First Row follows the L (mode=1) mode. - int x; - const uint32_t pred0 = Predictor0(data[-1], NULL); - AddPixelsEq(data, pred0); - for (x = 1; x < width; ++x) { - const uint32_t pred1 = Predictor1(data[x - 1], NULL); - AddPixelsEq(data + x, pred1); - } - data += width; + PredictorAdd0(in, NULL, 1, out); + PredictorAdd1(in + 1, NULL, width - 1, out + 1); + in += width; + out += width; ++y_start; } @@ -193,36 +209,26 @@ static void PredictorInverseTransform(const VP8LTransform* const transform, int y = y_start; const int tile_width = 1 << transform->bits_; const int mask = tile_width - 1; - const int safe_width = width & ~mask; const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); const uint32_t* pred_mode_base = transform->data_ + (y >> transform->bits_) * tiles_per_row; while (y < y_end) { - const uint32_t pred2 = Predictor2(data[-1], data - width); const uint32_t* pred_mode_src = pred_mode_base; - VP8LPredictorFunc pred_func; int x = 1; - int t = 1; // First pixel follows the T (mode=2) mode. - AddPixelsEq(data, pred2); + PredictorAdd2(in, out - width, 1, out); // .. the rest: - while (x < safe_width) { - pred_func = VP8LPredictors[((*pred_mode_src++) >> 8) & 0xf]; - for (; t < tile_width; ++t, ++x) { - const uint32_t pred = pred_func(data[x - 1], data + x - width); - AddPixelsEq(data + x, pred); - } - t = 0; - } - if (x < width) { - pred_func = VP8LPredictors[((*pred_mode_src++) >> 8) & 0xf]; - for (; x < width; ++x) { - const uint32_t pred = pred_func(data[x - 1], data + x - width); - AddPixelsEq(data + x, pred); - } + while (x < width) { + const VP8LPredictorAddSubFunc pred_func = + VP8LPredictorsAdd[((*pred_mode_src++) >> 8) & 0xf]; + int x_end = (x & ~mask) + tile_width; + if (x_end > width) x_end = width; + pred_func(in + x, out + x - width, x_end - x, out + x); + x = x_end; } - data += width; + in += width; + out += width; ++y; if ((y & mask) == 0) { // Use the same mask, since tiles are squares. pred_mode_base += tiles_per_row; @@ -233,21 +239,22 @@ static void PredictorInverseTransform(const VP8LTransform* const transform, // Add green to blue and red channels (i.e. perform the inverse transform of // 'subtract green'). -void VP8LAddGreenToBlueAndRed_C(uint32_t* data, int num_pixels) { +void VP8LAddGreenToBlueAndRed_C(const uint32_t* src, int num_pixels, + uint32_t* dst) { int i; for (i = 0; i < num_pixels; ++i) { - const uint32_t argb = data[i]; + const uint32_t argb = src[i]; const uint32_t green = ((argb >> 8) & 0xff); uint32_t red_blue = (argb & 0x00ff00ffu); red_blue += (green << 16) | green; red_blue &= 0x00ff00ffu; - data[i] = (argb & 0xff00ff00u) | red_blue; + dst[i] = (argb & 0xff00ff00u) | red_blue; } } -static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred, - int8_t color) { - return (uint32_t)((int)(color_pred) * color) >> 5; +static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, + int8_t color) { + return ((int)color_pred * color) >> 5; } static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, @@ -257,27 +264,29 @@ static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, m->red_to_blue_ = (color_code >> 16) & 0xff; } -void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, uint32_t* data, - int num_pixels) { +void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, + const uint32_t* src, int num_pixels, + uint32_t* dst) { int i; for (i = 0; i < num_pixels; ++i) { - const uint32_t argb = data[i]; + const uint32_t argb = src[i]; const uint32_t green = argb >> 8; const uint32_t red = argb >> 16; - uint32_t new_red = red; - uint32_t new_blue = argb; + int new_red = red; + int new_blue = argb; new_red += ColorTransformDelta(m->green_to_red_, green); new_red &= 0xff; new_blue += ColorTransformDelta(m->green_to_blue_, green); new_blue += ColorTransformDelta(m->red_to_blue_, new_red); new_blue &= 0xff; - data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); + dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); } } // Color space inverse transform. static void ColorSpaceInverseTransform(const VP8LTransform* const transform, - int y_start, int y_end, uint32_t* data) { + int y_start, int y_end, + const uint32_t* src, uint32_t* dst) { const int width = transform->xsize_; const int tile_width = 1 << transform->bits_; const int mask = tile_width - 1; @@ -291,17 +300,19 @@ static void ColorSpaceInverseTransform(const VP8LTransform* const transform, while (y < y_end) { const uint32_t* pred = pred_row; VP8LMultipliers m = { 0, 0, 0 }; - const uint32_t* const data_safe_end = data + safe_width; - const uint32_t* const data_end = data + width; - while (data < data_safe_end) { + const uint32_t* const src_safe_end = src + safe_width; + const uint32_t* const src_end = src + width; + while (src < src_safe_end) { ColorCodeToMultipliers(*pred++, &m); - VP8LTransformColorInverse(&m, data, tile_width); - data += tile_width; + VP8LTransformColorInverse(&m, src, tile_width, dst); + src += tile_width; + dst += tile_width; } - if (data < data_end) { // Left-overs using C-version. + if (src < src_end) { // Left-overs using C-version. ColorCodeToMultipliers(*pred++, &m); - VP8LTransformColorInverse(&m, data, remaining_width); - data += remaining_width; + VP8LTransformColorInverse(&m, src, remaining_width, dst); + src += remaining_width; + dst += remaining_width; } ++y; if ((y & mask) == 0) pred_row += tiles_per_row; @@ -366,10 +377,10 @@ void VP8LInverseTransform(const VP8LTransform* const transform, assert(row_end <= transform->ysize_); switch (transform->type_) { case SUBTRACT_GREEN: - VP8LAddGreenToBlueAndRed(out, (row_end - row_start) * width); + VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out); break; case PREDICTOR_TRANSFORM: - PredictorInverseTransform(transform, row_start, row_end, out); + PredictorInverseTransform(transform, row_start, row_end, in, out); if (row_end != transform->ysize_) { // The last predicted row in this iteration will be the top-pred row // for the first row in next iteration. @@ -378,7 +389,7 @@ void VP8LInverseTransform(const VP8LTransform* const transform, } break; case CROSS_COLOR_TRANSFORM: - ColorSpaceInverseTransform(transform, row_start, row_end, out); + ColorSpaceInverseTransform(transform, row_start, row_end, in, out); break; case COLOR_INDEXING_TRANSFORM: if (in == out && transform->bits_ > 0) { @@ -555,10 +566,15 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, //------------------------------------------------------------------------------ -VP8LProcessBlueAndRedFunc VP8LAddGreenToBlueAndRed; +VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed; +VP8LPredictorAddSubFunc VP8LPredictorsAdd[16]; VP8LPredictorFunc VP8LPredictors[16]; -VP8LTransformColorFunc VP8LTransformColorInverse; +// exposed plain-C implementations +VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16]; +VP8LPredictorFunc VP8LPredictors_C[16]; + +VP8LTransformColorInverseFunc VP8LTransformColorInverse; VP8LConvertFunc VP8LConvertBGRAToRGB; VP8LConvertFunc VP8LConvertBGRAToRGBA; @@ -572,29 +588,37 @@ VP8LMapAlphaFunc VP8LMapColor8b; extern void VP8LDspInitSSE2(void); extern void VP8LDspInitNEON(void); extern void VP8LDspInitMIPSdspR2(void); +extern void VP8LDspInitMSA(void); static volatile VP8CPUInfo lossless_last_cpuinfo_used = (VP8CPUInfo)&lossless_last_cpuinfo_used; +#define COPY_PREDICTOR_ARRAY(IN, OUT) do { \ + (OUT)[0] = IN##0; \ + (OUT)[1] = IN##1; \ + (OUT)[2] = IN##2; \ + (OUT)[3] = IN##3; \ + (OUT)[4] = IN##4; \ + (OUT)[5] = IN##5; \ + (OUT)[6] = IN##6; \ + (OUT)[7] = IN##7; \ + (OUT)[8] = IN##8; \ + (OUT)[9] = IN##9; \ + (OUT)[10] = IN##10; \ + (OUT)[11] = IN##11; \ + (OUT)[12] = IN##12; \ + (OUT)[13] = IN##13; \ + (OUT)[14] = IN##0; /* <- padding security sentinels*/ \ + (OUT)[15] = IN##0; \ +} while (0); + WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) { if (lossless_last_cpuinfo_used == VP8GetCPUInfo) return; - VP8LPredictors[0] = Predictor0; - VP8LPredictors[1] = Predictor1; - VP8LPredictors[2] = Predictor2; - VP8LPredictors[3] = Predictor3; - VP8LPredictors[4] = Predictor4; - VP8LPredictors[5] = Predictor5; - VP8LPredictors[6] = Predictor6; - VP8LPredictors[7] = Predictor7; - VP8LPredictors[8] = Predictor8; - VP8LPredictors[9] = Predictor9; - VP8LPredictors[10] = Predictor10; - VP8LPredictors[11] = Predictor11; - VP8LPredictors[12] = Predictor12; - VP8LPredictors[13] = Predictor13; - VP8LPredictors[14] = Predictor0; // <- padding security sentinels - VP8LPredictors[15] = Predictor0; + COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors) + COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors_C) + COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd) + COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd_C) VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C; @@ -625,9 +649,15 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) { if (VP8GetCPUInfo(kMIPSdspR2)) { VP8LDspInitMIPSdspR2(); } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8LDspInitMSA(); + } #endif } lossless_last_cpuinfo_used = VP8GetCPUInfo; } +#undef COPY_PREDICTOR_ARRAY //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/dsp/lossless.h b/src/3rdparty/libwebp/src/dsp/lossless.h index 9f0d7a25b72d9fb2802e407d1b19fea5a1e8bbb5..352a54e5095dc567f0724fd4d98e3c6e2f94d48a 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless.h +++ b/src/3rdparty/libwebp/src/dsp/lossless.h @@ -18,7 +18,7 @@ #include "../webp/types.h" #include "../webp/decode.h" -#include "../enc/histogram.h" +#include "../enc/histogram_enc.h" #include "../utils/utils.h" #ifdef __cplusplus @@ -26,7 +26,7 @@ extern "C" { #endif #ifdef WEBP_EXPERIMENTAL_FEATURES -#include "../enc/delta_palettization.h" +#include "../enc/delta_palettization_enc.h" #endif // WEBP_EXPERIMENTAL_FEATURES //------------------------------------------------------------------------------ @@ -34,9 +34,17 @@ extern "C" { typedef uint32_t (*VP8LPredictorFunc)(uint32_t left, const uint32_t* const top); extern VP8LPredictorFunc VP8LPredictors[16]; - -typedef void (*VP8LProcessBlueAndRedFunc)(uint32_t* argb_data, int num_pixels); -extern VP8LProcessBlueAndRedFunc VP8LAddGreenToBlueAndRed; +extern VP8LPredictorFunc VP8LPredictors_C[16]; +// These Add/Sub function expects upper[-1] and out[-1] to be readable. +typedef void (*VP8LPredictorAddSubFunc)(const uint32_t* in, + const uint32_t* upper, int num_pixels, + uint32_t* out); +extern VP8LPredictorAddSubFunc VP8LPredictorsAdd[16]; +extern VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16]; + +typedef void (*VP8LProcessDecBlueAndRedFunc)(const uint32_t* src, + int num_pixels, uint32_t* dst); +extern VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed; typedef struct { // Note: the members are uint8_t, so that any negative values are @@ -45,9 +53,10 @@ typedef struct { uint8_t green_to_blue_; uint8_t red_to_blue_; } VP8LMultipliers; -typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m, - uint32_t* argb_data, int num_pixels); -extern VP8LTransformColorFunc VP8LTransformColorInverse; +typedef void (*VP8LTransformColorInverseFunc)(const VP8LMultipliers* const m, + const uint32_t* src, + int num_pixels, uint32_t* dst); +extern VP8LTransformColorInverseFunc VP8LTransformColorInverse; struct VP8LTransform; // Defined in dec/vp8li.h. @@ -72,23 +81,6 @@ extern VP8LConvertFunc VP8LConvertBGRAToBGR; void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, WEBP_CSP_MODE out_colorspace, uint8_t* const rgba); -// color mapping related functions. -static WEBP_INLINE uint32_t VP8GetARGBIndex(uint32_t idx) { - return (idx >> 8) & 0xff; -} - -static WEBP_INLINE uint8_t VP8GetAlphaIndex(uint8_t idx) { - return idx; -} - -static WEBP_INLINE uint32_t VP8GetARGBValue(uint32_t val) { - return val; -} - -static WEBP_INLINE uint8_t VP8GetAlphaValue(uint32_t val) { - return (val >> 8) & 0xff; -} - typedef void (*VP8LMapARGBFunc)(const uint32_t* src, const uint32_t* const color_map, uint32_t* dst, int y_start, @@ -110,7 +102,8 @@ void VP8LColorIndexInverseTransformAlpha( // Expose some C-only fallback functions void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, - uint32_t* data, int num_pixels); + const uint32_t* src, int num_pixels, + uint32_t* dst); void VP8LConvertBGRAToRGB_C(const uint32_t* src, int num_pixels, uint8_t* dst); void VP8LConvertBGRAToRGBA_C(const uint32_t* src, int num_pixels, uint8_t* dst); @@ -119,7 +112,8 @@ void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src, void VP8LConvertBGRAToRGB565_C(const uint32_t* src, int num_pixels, uint8_t* dst); void VP8LConvertBGRAToBGR_C(const uint32_t* src, int num_pixels, uint8_t* dst); -void VP8LAddGreenToBlueAndRed_C(uint32_t* data, int num_pixels); +void VP8LAddGreenToBlueAndRed_C(const uint32_t* src, int num_pixels, + uint32_t* dst); // Must be called before calling any of the above methods. void VP8LDspInit(void); @@ -127,7 +121,10 @@ void VP8LDspInit(void); //------------------------------------------------------------------------------ // Encoding -extern VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; +typedef void (*VP8LProcessEncBlueAndRedFunc)(uint32_t* dst, int num_pixels); +extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; +typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m, + uint32_t* const dst, int num_pixels); extern VP8LTransformColorFunc VP8LTransformColor; typedef void (*VP8LCollectColorBlueTransformsFunc)( const uint32_t* argb, int stride, @@ -153,62 +150,8 @@ void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, int green_to_blue, int red_to_blue, int histo[]); -//------------------------------------------------------------------------------ -// Image transforms. - -void VP8LResidualImage(int width, int height, int bits, int low_effort, - uint32_t* const argb, uint32_t* const argb_scratch, - uint32_t* const image, int near_lossless, int exact, - int used_subtract_green); - -void VP8LColorSpaceTransform(int width, int height, int bits, int quality, - uint32_t* const argb, uint32_t* image); - -//------------------------------------------------------------------------------ -// Misc methods. - -// Computes sampled size of 'size' when sampling using 'sampling bits'. -static WEBP_INLINE uint32_t VP8LSubSampleSize(uint32_t size, - uint32_t sampling_bits) { - return (size + (1 << sampling_bits) - 1) >> sampling_bits; -} - -// Converts near lossless quality into max number of bits shaved off. -static WEBP_INLINE int VP8LNearLosslessBits(int near_lossless_quality) { - // 100 -> 0 - // 80..99 -> 1 - // 60..79 -> 2 - // 40..59 -> 3 - // 20..39 -> 4 - // 0..19 -> 5 - return 5 - near_lossless_quality / 20; -} - -// ----------------------------------------------------------------------------- -// Faster logarithm for integers. Small values use a look-up table. - -// The threshold till approximate version of log_2 can be used. -// Practically, we can get rid of the call to log() as the two values match to -// very high degree (the ratio of these two is 0.99999x). -// Keeping a high threshold for now. -#define APPROX_LOG_WITH_CORRECTION_MAX 65536 -#define APPROX_LOG_MAX 4096 -#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086 -#define LOG_LOOKUP_IDX_MAX 256 -extern const float kLog2Table[LOG_LOOKUP_IDX_MAX]; -extern const float kSLog2Table[LOG_LOOKUP_IDX_MAX]; -typedef float (*VP8LFastLog2SlowFunc)(uint32_t v); - -extern VP8LFastLog2SlowFunc VP8LFastLog2Slow; -extern VP8LFastLog2SlowFunc VP8LFastSLog2Slow; - -static WEBP_INLINE float VP8LFastLog2(uint32_t v) { - return (v < LOG_LOOKUP_IDX_MAX) ? kLog2Table[v] : VP8LFastLog2Slow(v); -} -// Fast calculation of v * log2(v) for integer input. -static WEBP_INLINE float VP8LFastSLog2(uint32_t v) { - return (v < LOG_LOOKUP_IDX_MAX) ? kSLog2Table[v] : VP8LFastSLog2Slow(v); -} +extern VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; +extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; // ----------------------------------------------------------------------------- // Huffman-cost related functions. @@ -228,11 +171,6 @@ typedef struct { // small struct to hold counters int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3] } VP8LStreaks; -typedef VP8LStreaks (*VP8LCostCombinedCountFunc)(const uint32_t* X, - const uint32_t* Y, int length); - -extern VP8LCostCombinedCountFunc VP8LHuffmanCostCombinedCount; - typedef struct { // small struct to hold bit entropy results double entropy; // entropy uint32_t sum; // sum of the population @@ -246,26 +184,20 @@ void VP8LBitEntropyInit(VP8LBitEntropy* const entropy); // Get the combined symbol bit entropy and Huffman cost stats for the // distributions 'X' and 'Y'. Those results can then be refined according to // codec specific heuristics. -void VP8LGetCombinedEntropyUnrefined(const uint32_t* const X, - const uint32_t* const Y, int length, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats); +typedef void (*VP8LGetCombinedEntropyUnrefinedFunc)( + const uint32_t X[], const uint32_t Y[], int length, + VP8LBitEntropy* const bit_entropy, VP8LStreaks* const stats); +extern VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined; + // Get the entropy for the distribution 'X'. -void VP8LGetEntropyUnrefined(const uint32_t* const X, int length, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats); +typedef void (*VP8LGetEntropyUnrefinedFunc)(const uint32_t X[], int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats); +extern VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, VP8LBitEntropy* const entropy); -typedef void (*GetEntropyUnrefinedHelperFunc)(uint32_t val, int i, - uint32_t* const val_prev, - int* const i_prev, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats); -// Internal function used by VP8LGet*EntropyUnrefined. -extern GetEntropyUnrefinedHelperFunc VP8LGetEntropyUnrefinedHelper; - typedef void (*VP8LHistogramAddFunc)(const VP8LHistogram* const a, const VP8LHistogram* const b, VP8LHistogram* const out); @@ -279,86 +211,11 @@ typedef int (*VP8LVectorMismatchFunc)(const uint32_t* const array1, // Returns the first index where array1 and array2 are different. extern VP8LVectorMismatchFunc VP8LVectorMismatch; -static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) { - const int log_floor = BitsLog2Floor(n); - if (n == (n & ~(n - 1))) // zero or a power of two. - return log_floor; - else - return log_floor + 1; -} - -// Splitting of distance and length codes into prefixes and -// extra bits. The prefixes are encoded with an entropy code -// while the extra bits are stored just as normal bits. -static WEBP_INLINE void VP8LPrefixEncodeBitsNoLUT(int distance, int* const code, - int* const extra_bits) { - const int highest_bit = BitsLog2Floor(--distance); - const int second_highest_bit = (distance >> (highest_bit - 1)) & 1; - *extra_bits = highest_bit - 1; - *code = 2 * highest_bit + second_highest_bit; -} - -static WEBP_INLINE void VP8LPrefixEncodeNoLUT(int distance, int* const code, - int* const extra_bits, - int* const extra_bits_value) { - const int highest_bit = BitsLog2Floor(--distance); - const int second_highest_bit = (distance >> (highest_bit - 1)) & 1; - *extra_bits = highest_bit - 1; - *extra_bits_value = distance & ((1 << *extra_bits) - 1); - *code = 2 * highest_bit + second_highest_bit; -} - -#define PREFIX_LOOKUP_IDX_MAX 512 -typedef struct { - int8_t code_; - int8_t extra_bits_; -} VP8LPrefixCode; - -// These tables are derived using VP8LPrefixEncodeNoLUT. -extern const VP8LPrefixCode kPrefixEncodeCode[PREFIX_LOOKUP_IDX_MAX]; -extern const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX]; -static WEBP_INLINE void VP8LPrefixEncodeBits(int distance, int* const code, - int* const extra_bits) { - if (distance < PREFIX_LOOKUP_IDX_MAX) { - const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; - *code = prefix_code.code_; - *extra_bits = prefix_code.extra_bits_; - } else { - VP8LPrefixEncodeBitsNoLUT(distance, code, extra_bits); - } -} - -static WEBP_INLINE void VP8LPrefixEncode(int distance, int* const code, - int* const extra_bits, - int* const extra_bits_value) { - if (distance < PREFIX_LOOKUP_IDX_MAX) { - const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; - *code = prefix_code.code_; - *extra_bits = prefix_code.extra_bits_; - *extra_bits_value = kPrefixEncodeExtraBitsValue[distance]; - } else { - VP8LPrefixEncodeNoLUT(distance, code, extra_bits, extra_bits_value); - } -} - -// Sum of each component, mod 256. -static WEBP_INLINE uint32_t VP8LAddPixels(uint32_t a, uint32_t b) { - const uint32_t alpha_and_green = (a & 0xff00ff00u) + (b & 0xff00ff00u); - const uint32_t red_and_blue = (a & 0x00ff00ffu) + (b & 0x00ff00ffu); - return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); -} - -// Difference of each component, mod 256. -static WEBP_INLINE uint32_t VP8LSubPixels(uint32_t a, uint32_t b) { - const uint32_t alpha_and_green = - 0x00ff00ffu + (a & 0xff00ff00u) - (b & 0xff00ff00u); - const uint32_t red_and_blue = - 0xff00ff00u + (a & 0x00ff00ffu) - (b & 0x00ff00ffu); - return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); -} - -void VP8LBundleColorMap(const uint8_t* const row, int width, - int xbits, uint32_t* const dst); +typedef void (*VP8LBundleColorMapFunc)(const uint8_t* const row, int width, + int xbits, uint32_t* dst); +extern VP8LBundleColorMapFunc VP8LBundleColorMap; +void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits, + uint32_t* dst); // Must be called before calling any of the above methods. void VP8LEncDspInit(void); diff --git a/src/3rdparty/libwebp/src/dsp/lossless_common.h b/src/3rdparty/libwebp/src/dsp/lossless_common.h new file mode 100644 index 0000000000000000000000000000000000000000..c40f7112084fc8e748801c779c3c0e9c3e836ad4 --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/lossless_common.h @@ -0,0 +1,210 @@ +// Copyright 2012 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. +// ----------------------------------------------------------------------------- +// +// Image transforms and color space conversion methods for lossless decoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) +// Vincent Rabaud (vrabaud@google.com) + +#ifndef WEBP_DSP_LOSSLESS_COMMON_H_ +#define WEBP_DSP_LOSSLESS_COMMON_H_ + +#include "../webp/types.h" + +#include "../utils/utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Decoding + +// color mapping related functions. +static WEBP_INLINE uint32_t VP8GetARGBIndex(uint32_t idx) { + return (idx >> 8) & 0xff; +} + +static WEBP_INLINE uint8_t VP8GetAlphaIndex(uint8_t idx) { + return idx; +} + +static WEBP_INLINE uint32_t VP8GetARGBValue(uint32_t val) { + return val; +} + +static WEBP_INLINE uint8_t VP8GetAlphaValue(uint32_t val) { + return (val >> 8) & 0xff; +} + +//------------------------------------------------------------------------------ +// Misc methods. + +// Computes sampled size of 'size' when sampling using 'sampling bits'. +static WEBP_INLINE uint32_t VP8LSubSampleSize(uint32_t size, + uint32_t sampling_bits) { + return (size + (1 << sampling_bits) - 1) >> sampling_bits; +} + +// Converts near lossless quality into max number of bits shaved off. +static WEBP_INLINE int VP8LNearLosslessBits(int near_lossless_quality) { + // 100 -> 0 + // 80..99 -> 1 + // 60..79 -> 2 + // 40..59 -> 3 + // 20..39 -> 4 + // 0..19 -> 5 + return 5 - near_lossless_quality / 20; +} + +// ----------------------------------------------------------------------------- +// Faster logarithm for integers. Small values use a look-up table. + +// The threshold till approximate version of log_2 can be used. +// Practically, we can get rid of the call to log() as the two values match to +// very high degree (the ratio of these two is 0.99999x). +// Keeping a high threshold for now. +#define APPROX_LOG_WITH_CORRECTION_MAX 65536 +#define APPROX_LOG_MAX 4096 +#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086 +#define LOG_LOOKUP_IDX_MAX 256 +extern const float kLog2Table[LOG_LOOKUP_IDX_MAX]; +extern const float kSLog2Table[LOG_LOOKUP_IDX_MAX]; +typedef float (*VP8LFastLog2SlowFunc)(uint32_t v); + +extern VP8LFastLog2SlowFunc VP8LFastLog2Slow; +extern VP8LFastLog2SlowFunc VP8LFastSLog2Slow; + +static WEBP_INLINE float VP8LFastLog2(uint32_t v) { + return (v < LOG_LOOKUP_IDX_MAX) ? kLog2Table[v] : VP8LFastLog2Slow(v); +} +// Fast calculation of v * log2(v) for integer input. +static WEBP_INLINE float VP8LFastSLog2(uint32_t v) { + return (v < LOG_LOOKUP_IDX_MAX) ? kSLog2Table[v] : VP8LFastSLog2Slow(v); +} + +// ----------------------------------------------------------------------------- +// PrefixEncode() + +static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) { + const int log_floor = BitsLog2Floor(n); + if (n == (n & ~(n - 1))) { // zero or a power of two. + return log_floor; + } + return log_floor + 1; +} + +// Splitting of distance and length codes into prefixes and +// extra bits. The prefixes are encoded with an entropy code +// while the extra bits are stored just as normal bits. +static WEBP_INLINE void VP8LPrefixEncodeBitsNoLUT(int distance, int* const code, + int* const extra_bits) { + const int highest_bit = BitsLog2Floor(--distance); + const int second_highest_bit = (distance >> (highest_bit - 1)) & 1; + *extra_bits = highest_bit - 1; + *code = 2 * highest_bit + second_highest_bit; +} + +static WEBP_INLINE void VP8LPrefixEncodeNoLUT(int distance, int* const code, + int* const extra_bits, + int* const extra_bits_value) { + const int highest_bit = BitsLog2Floor(--distance); + const int second_highest_bit = (distance >> (highest_bit - 1)) & 1; + *extra_bits = highest_bit - 1; + *extra_bits_value = distance & ((1 << *extra_bits) - 1); + *code = 2 * highest_bit + second_highest_bit; +} + +#define PREFIX_LOOKUP_IDX_MAX 512 +typedef struct { + int8_t code_; + int8_t extra_bits_; +} VP8LPrefixCode; + +// These tables are derived using VP8LPrefixEncodeNoLUT. +extern const VP8LPrefixCode kPrefixEncodeCode[PREFIX_LOOKUP_IDX_MAX]; +extern const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX]; +static WEBP_INLINE void VP8LPrefixEncodeBits(int distance, int* const code, + int* const extra_bits) { + if (distance < PREFIX_LOOKUP_IDX_MAX) { + const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; + *code = prefix_code.code_; + *extra_bits = prefix_code.extra_bits_; + } else { + VP8LPrefixEncodeBitsNoLUT(distance, code, extra_bits); + } +} + +static WEBP_INLINE void VP8LPrefixEncode(int distance, int* const code, + int* const extra_bits, + int* const extra_bits_value) { + if (distance < PREFIX_LOOKUP_IDX_MAX) { + const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; + *code = prefix_code.code_; + *extra_bits = prefix_code.extra_bits_; + *extra_bits_value = kPrefixEncodeExtraBitsValue[distance]; + } else { + VP8LPrefixEncodeNoLUT(distance, code, extra_bits, extra_bits_value); + } +} + +// Sum of each component, mod 256. +static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE +uint32_t VP8LAddPixels(uint32_t a, uint32_t b) { + const uint32_t alpha_and_green = (a & 0xff00ff00u) + (b & 0xff00ff00u); + const uint32_t red_and_blue = (a & 0x00ff00ffu) + (b & 0x00ff00ffu); + return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); +} + +// Difference of each component, mod 256. +static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE +uint32_t VP8LSubPixels(uint32_t a, uint32_t b) { + const uint32_t alpha_and_green = + 0x00ff00ffu + (a & 0xff00ff00u) - (b & 0xff00ff00u); + const uint32_t red_and_blue = + 0xff00ff00u + (a & 0x00ff00ffu) - (b & 0x00ff00ffu); + return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); +} + +//------------------------------------------------------------------------------ +// Transform-related functions use din both encoding and decoding. + +// Macros used to create a batch predictor that iteratively uses a +// one-pixel predictor. + +// The predictor is added to the output pixel (which +// is therefore considered as a residual) to get the final prediction. +#define GENERATE_PREDICTOR_ADD(PREDICTOR, PREDICTOR_ADD) \ +static void PREDICTOR_ADD(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int x; \ + for (x = 0; x < num_pixels; ++x) { \ + const uint32_t pred = (PREDICTOR)(out[x - 1], upper + x); \ + out[x] = VP8LAddPixels(in[x], pred); \ + } \ +} + +// It subtracts the prediction from the input pixel and stores the residual +// in the output pixel. +#define GENERATE_PREDICTOR_SUB(PREDICTOR, PREDICTOR_SUB) \ +static void PREDICTOR_SUB(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int x; \ + for (x = 0; x < num_pixels; ++x) { \ + const uint32_t pred = (PREDICTOR)(in[x - 1], upper + x); \ + out[x] = VP8LSubPixels(in[x], pred); \ + } \ +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_LOSSLESS_COMMON_H_ diff --git a/src/3rdparty/libwebp/src/dsp/lossless_enc.c b/src/3rdparty/libwebp/src/dsp/lossless_enc.c index 256f6f5f8b7f6538b42b779f1b6af229cd2309b7..4e46fbab8b2cfb25fb0540c3d31e943f92902b5b 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless_enc.c +++ b/src/3rdparty/libwebp/src/dsp/lossless_enc.c @@ -17,16 +17,12 @@ #include <math.h> #include <stdlib.h> -#include "../dec/vp8li.h" -#include "../utils/endian_inl.h" +#include "../dec/vp8li_dec.h" +#include "../utils/endian_inl_utils.h" #include "./lossless.h" +#include "./lossless_common.h" #include "./yuv.h" -#define MAX_DIFF_COST (1e30f) - -static const int kPredLowEffort = 11; -static const uint32_t kMaskAlpha = 0xff000000; - // lookup table for small values of log2(int) const float kLog2Table[LOG_LOOKUP_IDX_MAX] = { 0.0000000000000000f, 0.0000000000000000f, @@ -380,26 +376,9 @@ static float FastLog2Slow(uint32_t v) { } } -// Mostly used to reduce code size + readability -static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; } -static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; } - //------------------------------------------------------------------------------ // Methods to calculate Entropy (Shannon). -static float PredictionCostSpatial(const int counts[256], int weight_0, - double exp_val) { - const int significant_symbols = 256 >> 4; - const double exp_decay_factor = 0.6; - double bits = weight_0 * counts[0]; - int i; - for (i = 1; i < significant_symbols; ++i) { - bits += exp_val * (counts[i] + counts[256 - i]); - exp_val *= exp_decay_factor; - } - return (float)(-0.1 * bits); -} - // Compute the combined Shanon's entropy for distribution {X} and {X+Y} static float CombinedShannonEntropy(const int X[256], const int Y[256]) { int i; @@ -422,18 +401,6 @@ static float CombinedShannonEntropy(const int X[256], const int Y[256]) { return (float)retval; } -static float PredictionCostSpatialHistogram(const int accumulated[4][256], - const int tile[4][256]) { - int i; - double retval = 0; - for (i = 0; i < 4; ++i) { - const double kExpValue = 0.94; - retval += PredictionCostSpatial(tile[i], 1, kExpValue); - retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]); - } - return (float)retval; -} - void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) { entropy->entropy = 0.; entropy->sum = 0; @@ -486,9 +453,9 @@ static WEBP_INLINE void GetEntropyUnrefinedHelper( *i_prev = i; } -void VP8LGetEntropyUnrefined(const uint32_t* const X, int length, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats) { +static void GetEntropyUnrefined(const uint32_t X[], int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats) { int i; int i_prev = 0; uint32_t x_prev = X[0]; @@ -499,18 +466,18 @@ void VP8LGetEntropyUnrefined(const uint32_t* const X, int length, for (i = 1; i < length; ++i) { const uint32_t x = X[i]; if (x != x_prev) { - VP8LGetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); + GetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); } } - VP8LGetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); + GetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); } -void VP8LGetCombinedEntropyUnrefined(const uint32_t* const X, - const uint32_t* const Y, int length, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats) { +static void GetCombinedEntropyUnrefined(const uint32_t X[], const uint32_t Y[], + int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats) { int i = 1; int i_prev = 0; uint32_t xy_prev = X[0] + Y[0]; @@ -521,439 +488,29 @@ void VP8LGetCombinedEntropyUnrefined(const uint32_t* const X, for (i = 1; i < length; ++i) { const uint32_t xy = X[i] + Y[i]; if (xy != xy_prev) { - VP8LGetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, bit_entropy, - stats); + GetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, bit_entropy, stats); } } - VP8LGetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, bit_entropy, stats); + GetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, bit_entropy, stats); bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); } -static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) { - ++histo_argb[0][argb >> 24]; - ++histo_argb[1][(argb >> 16) & 0xff]; - ++histo_argb[2][(argb >> 8) & 0xff]; - ++histo_argb[3][argb & 0xff]; -} - //------------------------------------------------------------------------------ -static WEBP_INLINE uint32_t Predict(VP8LPredictorFunc pred_func, - int x, int y, - const uint32_t* current_row, - const uint32_t* upper_row) { - if (y == 0) { - return (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left. - } else if (x == 0) { - return upper_row[x]; // Top. - } else { - return pred_func(current_row[x - 1], upper_row + x); - } -} - -static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) { - const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24)); - const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff)); - const int diff_g = abs((int)((p1 >> 8) & 0xff) - (int)((p2 >> 8) & 0xff)); - const int diff_b = abs((int)(p1 & 0xff) - (int)(p2 & 0xff)); - return GetMax(GetMax(diff_a, diff_r), GetMax(diff_g, diff_b)); -} - -static int MaxDiffAroundPixel(uint32_t current, uint32_t up, uint32_t down, - uint32_t left, uint32_t right) { - const int diff_up = MaxDiffBetweenPixels(current, up); - const int diff_down = MaxDiffBetweenPixels(current, down); - const int diff_left = MaxDiffBetweenPixels(current, left); - const int diff_right = MaxDiffBetweenPixels(current, right); - return GetMax(GetMax(diff_up, diff_down), GetMax(diff_left, diff_right)); -} - -static uint32_t AddGreenToBlueAndRed(uint32_t argb) { - const uint32_t green = (argb >> 8) & 0xff; - uint32_t red_blue = argb & 0x00ff00ffu; - red_blue += (green << 16) | green; - red_blue &= 0x00ff00ffu; - return (argb & 0xff00ff00u) | red_blue; -} - -static void MaxDiffsForRow(int width, int stride, const uint32_t* const argb, - uint8_t* const max_diffs, int used_subtract_green) { - uint32_t current, up, down, left, right; - int x; - if (width <= 2) return; - current = argb[0]; - right = argb[1]; - if (used_subtract_green) { - current = AddGreenToBlueAndRed(current); - right = AddGreenToBlueAndRed(right); - } - // max_diffs[0] and max_diffs[width - 1] are never used. - for (x = 1; x < width - 1; ++x) { - up = argb[-stride + x]; - down = argb[stride + x]; - left = current; - current = right; - right = argb[x + 1]; - if (used_subtract_green) { - up = AddGreenToBlueAndRed(up); - down = AddGreenToBlueAndRed(down); - right = AddGreenToBlueAndRed(right); - } - max_diffs[x] = MaxDiffAroundPixel(current, up, down, left, right); - } -} - -// Quantize the difference between the actual component value and its prediction -// to a multiple of quantization, working modulo 256, taking care not to cross -// a boundary (inclusive upper limit). -static uint8_t NearLosslessComponent(uint8_t value, uint8_t predict, - uint8_t boundary, int quantization) { - const int residual = (value - predict) & 0xff; - const int boundary_residual = (boundary - predict) & 0xff; - const int lower = residual & ~(quantization - 1); - const int upper = lower + quantization; - // Resolve ties towards a value closer to the prediction (i.e. towards lower - // if value comes after prediction and towards upper otherwise). - const int bias = ((boundary - value) & 0xff) < boundary_residual; - if (residual - lower < upper - residual + bias) { - // lower is closer to residual than upper. - if (residual > boundary_residual && lower <= boundary_residual) { - // Halve quantization step to avoid crossing boundary. This midpoint is - // on the same side of boundary as residual because midpoint >= residual - // (since lower is closer than upper) and residual is above the boundary. - return lower + (quantization >> 1); - } - return lower; - } else { - // upper is closer to residual than lower. - if (residual <= boundary_residual && upper > boundary_residual) { - // Halve quantization step to avoid crossing boundary. This midpoint is - // on the same side of boundary as residual because midpoint <= residual - // (since upper is closer than lower) and residual is below the boundary. - return lower + (quantization >> 1); - } - return upper & 0xff; - } -} - -// Quantize every component of the difference between the actual pixel value and -// its prediction to a multiple of a quantization (a power of 2, not larger than -// max_quantization which is a power of 2, smaller than max_diff). Take care if -// value and predict have undergone subtract green, which means that red and -// blue are represented as offsets from green. -static uint32_t NearLossless(uint32_t value, uint32_t predict, - int max_quantization, int max_diff, - int used_subtract_green) { - int quantization; - uint8_t new_green = 0; - uint8_t green_diff = 0; - uint8_t a, r, g, b; - if (max_diff <= 2) { - return VP8LSubPixels(value, predict); - } - quantization = max_quantization; - while (quantization >= max_diff) { - quantization >>= 1; - } - if ((value >> 24) == 0 || (value >> 24) == 0xff) { - // Preserve transparency of fully transparent or fully opaque pixels. - a = ((value >> 24) - (predict >> 24)) & 0xff; - } else { - a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization); - } - g = NearLosslessComponent((value >> 8) & 0xff, (predict >> 8) & 0xff, 0xff, - quantization); - if (used_subtract_green) { - // The green offset will be added to red and blue components during decoding - // to obtain the actual red and blue values. - new_green = ((predict >> 8) + g) & 0xff; - // The amount by which green has been adjusted during quantization. It is - // subtracted from red and blue for compensation, to avoid accumulating two - // quantization errors in them. - green_diff = (new_green - (value >> 8)) & 0xff; - } - r = NearLosslessComponent(((value >> 16) - green_diff) & 0xff, - (predict >> 16) & 0xff, 0xff - new_green, - quantization); - b = NearLosslessComponent((value - green_diff) & 0xff, predict & 0xff, - 0xff - new_green, quantization); - return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; -} - -// Returns the difference between the pixel and its prediction. In case of a -// lossy encoding, updates the source image to avoid propagating the deviation -// further to pixels which depend on the current pixel for their predictions. -static WEBP_INLINE uint32_t GetResidual(int width, int height, - uint32_t* const upper_row, - uint32_t* const current_row, - const uint8_t* const max_diffs, - int mode, VP8LPredictorFunc pred_func, - int x, int y, int max_quantization, - int exact, int used_subtract_green) { - const uint32_t predict = Predict(pred_func, x, y, current_row, upper_row); - uint32_t residual; - if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 || - x == 0 || x == width - 1) { - residual = VP8LSubPixels(current_row[x], predict); - } else { - residual = NearLossless(current_row[x], predict, max_quantization, - max_diffs[x], used_subtract_green); - // Update the source image. - current_row[x] = VP8LAddPixels(predict, residual); - // x is never 0 here so we do not need to update upper_row like below. - } - if (!exact && (current_row[x] & kMaskAlpha) == 0) { - // If alpha is 0, cleanup RGB. We can choose the RGB values of the residual - // for best compression. The prediction of alpha itself can be non-zero and - // must be kept though. We choose RGB of the residual to be 0. - residual &= kMaskAlpha; - // Update the source image. - current_row[x] = predict & ~kMaskAlpha; - // The prediction for the rightmost pixel in a row uses the leftmost pixel - // in that row as its top-right context pixel. Hence if we change the - // leftmost pixel of current_row, the corresponding change must be applied - // to upper_row as well where top-right context is being read from. - if (x == 0 && y != 0) upper_row[width] = current_row[0]; - } - return residual; -} - -// Returns best predictor and updates the accumulated histogram. -// If max_quantization > 1, assumes that near lossless processing will be -// applied, quantizing residuals to multiples of quantization levels up to -// max_quantization (the actual quantization level depends on smoothness near -// the given pixel). -static int GetBestPredictorForTile(int width, int height, - int tile_x, int tile_y, int bits, - int accumulated[4][256], - uint32_t* const argb_scratch, - const uint32_t* const argb, - int max_quantization, - int exact, int used_subtract_green) { - const int kNumPredModes = 14; - const int start_x = tile_x << bits; - const int start_y = tile_y << bits; - const int tile_size = 1 << bits; - const int max_y = GetMin(tile_size, height - start_y); - const int max_x = GetMin(tile_size, width - start_x); - // Whether there exist columns just outside the tile. - const int have_left = (start_x > 0); - const int have_right = (max_x < width - start_x); - // Position and size of the strip covering the tile and adjacent columns if - // they exist. - const int context_start_x = start_x - have_left; - const int context_width = max_x + have_left + have_right; - // The width of upper_row and current_row is one pixel larger than image width - // to allow the top right pixel to point to the leftmost pixel of the next row - // when at the right edge. - uint32_t* upper_row = argb_scratch; - uint32_t* current_row = upper_row + width + 1; - uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1); - float best_diff = MAX_DIFF_COST; - int best_mode = 0; - int mode; - int histo_stack_1[4][256]; - int histo_stack_2[4][256]; - // Need pointers to be able to swap arrays. - int (*histo_argb)[256] = histo_stack_1; - int (*best_histo)[256] = histo_stack_2; - int i, j; - - for (mode = 0; mode < kNumPredModes; ++mode) { - const VP8LPredictorFunc pred_func = VP8LPredictors[mode]; - float cur_diff; - int relative_y; - memset(histo_argb, 0, sizeof(histo_stack_1)); - if (start_y > 0) { - // Read the row above the tile which will become the first upper_row. - // Include a pixel to the left if it exists; include a pixel to the right - // in all cases (wrapping to the leftmost pixel of the next row if it does - // not exist). - memcpy(current_row + context_start_x, - argb + (start_y - 1) * width + context_start_x, - sizeof(*argb) * (max_x + have_left + 1)); - } - for (relative_y = 0; relative_y < max_y; ++relative_y) { - const int y = start_y + relative_y; - int relative_x; - uint32_t* tmp = upper_row; - upper_row = current_row; - current_row = tmp; - // Read current_row. Include a pixel to the left if it exists; include a - // pixel to the right in all cases except at the bottom right corner of - // the image (wrapping to the leftmost pixel of the next row if it does - // not exist in the current row). - memcpy(current_row + context_start_x, - argb + y * width + context_start_x, - sizeof(*argb) * (max_x + have_left + (y + 1 < height))); - if (max_quantization > 1 && y >= 1 && y + 1 < height) { - MaxDiffsForRow(context_width, width, argb + y * width + context_start_x, - max_diffs + context_start_x, used_subtract_green); - } - - for (relative_x = 0; relative_x < max_x; ++relative_x) { - const int x = start_x + relative_x; - UpdateHisto(histo_argb, - GetResidual(width, height, upper_row, current_row, - max_diffs, mode, pred_func, x, y, - max_quantization, exact, used_subtract_green)); - } - } - cur_diff = PredictionCostSpatialHistogram( - (const int (*)[256])accumulated, (const int (*)[256])histo_argb); - if (cur_diff < best_diff) { - int (*tmp)[256] = histo_argb; - histo_argb = best_histo; - best_histo = tmp; - best_diff = cur_diff; - best_mode = mode; - } - } - - for (i = 0; i < 4; i++) { - for (j = 0; j < 256; j++) { - accumulated[i][j] += best_histo[i][j]; - } - } - - return best_mode; -} - -// Converts pixels of the image to residuals with respect to predictions. -// If max_quantization > 1, applies near lossless processing, quantizing -// residuals to multiples of quantization levels up to max_quantization -// (the actual quantization level depends on smoothness near the given pixel). -static void CopyImageWithPrediction(int width, int height, - int bits, uint32_t* const modes, - uint32_t* const argb_scratch, - uint32_t* const argb, - int low_effort, int max_quantization, - int exact, int used_subtract_green) { - const int tiles_per_row = VP8LSubSampleSize(width, bits); - const int mask = (1 << bits) - 1; - // The width of upper_row and current_row is one pixel larger than image width - // to allow the top right pixel to point to the leftmost pixel of the next row - // when at the right edge. - uint32_t* upper_row = argb_scratch; - uint32_t* current_row = upper_row + width + 1; - uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1); - uint8_t* lower_max_diffs = current_max_diffs + width; - int y; - int mode = 0; - VP8LPredictorFunc pred_func = NULL; - - for (y = 0; y < height; ++y) { - int x; - uint32_t* const tmp32 = upper_row; - upper_row = current_row; - current_row = tmp32; - memcpy(current_row, argb + y * width, - sizeof(*argb) * (width + (y + 1 < height))); - - if (low_effort) { - for (x = 0; x < width; ++x) { - const uint32_t predict = Predict(VP8LPredictors[kPredLowEffort], x, y, - current_row, upper_row); - argb[y * width + x] = VP8LSubPixels(current_row[x], predict); - } - } else { - if (max_quantization > 1) { - // Compute max_diffs for the lower row now, because that needs the - // contents of argb for the current row, which we will overwrite with - // residuals before proceeding with the next row. - uint8_t* const tmp8 = current_max_diffs; - current_max_diffs = lower_max_diffs; - lower_max_diffs = tmp8; - if (y + 2 < height) { - MaxDiffsForRow(width, width, argb + (y + 1) * width, lower_max_diffs, - used_subtract_green); - } - } - for (x = 0; x < width; ++x) { - if ((x & mask) == 0) { - mode = (modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff; - pred_func = VP8LPredictors[mode]; - } - argb[y * width + x] = GetResidual( - width, height, upper_row, current_row, current_max_diffs, mode, - pred_func, x, y, max_quantization, exact, used_subtract_green); - } - } - } -} - -// Finds the best predictor for each tile, and converts the image to residuals -// with respect to predictions. If near_lossless_quality < 100, applies -// near lossless processing, shaving off more bits of residuals for lower -// qualities. -void VP8LResidualImage(int width, int height, int bits, int low_effort, - uint32_t* const argb, uint32_t* const argb_scratch, - uint32_t* const image, int near_lossless_quality, - int exact, int used_subtract_green) { - const int tiles_per_row = VP8LSubSampleSize(width, bits); - const int tiles_per_col = VP8LSubSampleSize(height, bits); - int tile_y; - int histo[4][256]; - const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality); - if (low_effort) { - int i; - for (i = 0; i < tiles_per_row * tiles_per_col; ++i) { - image[i] = ARGB_BLACK | (kPredLowEffort << 8); - } - } else { - memset(histo, 0, sizeof(histo)); - for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) { - int tile_x; - for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) { - const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y, - bits, histo, argb_scratch, argb, max_quantization, exact, - used_subtract_green); - image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8); - } - } - } - - CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb, - low_effort, max_quantization, exact, - used_subtract_green); -} - void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) { int i; for (i = 0; i < num_pixels; ++i) { - const uint32_t argb = argb_data[i]; - const uint32_t green = (argb >> 8) & 0xff; + const int argb = argb_data[i]; + const int green = (argb >> 8) & 0xff; const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff; - const uint32_t new_b = ((argb & 0xff) - green) & 0xff; - argb_data[i] = (argb & 0xff00ff00) | (new_r << 16) | new_b; + const uint32_t new_b = (((argb >> 0) & 0xff) - green) & 0xff; + argb_data[i] = (argb & 0xff00ff00u) | (new_r << 16) | new_b; } } -static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) { - m->green_to_red_ = 0; - m->green_to_blue_ = 0; - m->red_to_blue_ = 0; -} - -static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred, - int8_t color) { - return (uint32_t)((int)(color_pred) * color) >> 5; -} - -static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, - VP8LMultipliers* const m) { - m->green_to_red_ = (color_code >> 0) & 0xff; - m->green_to_blue_ = (color_code >> 8) & 0xff; - m->red_to_blue_ = (color_code >> 16) & 0xff; -} - -static WEBP_INLINE uint32_t MultipliersToColorCode( - const VP8LMultipliers* const m) { - return 0xff000000u | - ((uint32_t)(m->red_to_blue_) << 16) | - ((uint32_t)(m->green_to_blue_) << 8) | - m->green_to_red_; +static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, int8_t color) { + return ((int)color_pred * color) >> 5; } void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data, @@ -963,8 +520,8 @@ void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data, const uint32_t argb = data[i]; const uint32_t green = argb >> 8; const uint32_t red = argb >> 16; - uint32_t new_red = red; - uint32_t new_blue = argb; + int new_red = red; + int new_blue = argb; new_red -= ColorTransformDelta(m->green_to_red_, green); new_red &= 0xff; new_blue -= ColorTransformDelta(m->green_to_blue_, green); @@ -977,7 +534,7 @@ void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data, static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red, uint32_t argb) { const uint32_t green = argb >> 8; - uint32_t new_red = argb >> 16; + int new_red = argb >> 16; new_red -= ColorTransformDelta(green_to_red, green); return (new_red & 0xff); } @@ -993,15 +550,6 @@ static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue, return (new_blue & 0xff); } -static float PredictionCostCrossColor(const int accumulated[256], - const int counts[256]) { - // Favor low entropy, locally and globally. - // Favor small absolute values for PredictionCostSpatial - static const double kExpValue = 2.4; - return VP8LCombinedShannonEntropy(counts, accumulated) + - PredictionCostSpatial(counts, 3, kExpValue); -} - void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride, int tile_width, int tile_height, int green_to_red, int histo[]) { @@ -1014,59 +562,6 @@ void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride, } } -static float GetPredictionCostCrossColorRed( - const uint32_t* argb, int stride, int tile_width, int tile_height, - VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red, - const int accumulated_red_histo[256]) { - int histo[256] = { 0 }; - float cur_diff; - - VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height, - green_to_red, histo); - - cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo); - if ((uint8_t)green_to_red == prev_x.green_to_red_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if ((uint8_t)green_to_red == prev_y.green_to_red_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if (green_to_red == 0) { - cur_diff -= 3; - } - return cur_diff; -} - -static void GetBestGreenToRed( - const uint32_t* argb, int stride, int tile_width, int tile_height, - VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, - const int accumulated_red_histo[256], VP8LMultipliers* const best_tx) { - const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6] - int green_to_red_best = 0; - int iter, offset; - float best_diff = GetPredictionCostCrossColorRed( - argb, stride, tile_width, tile_height, prev_x, prev_y, - green_to_red_best, accumulated_red_histo); - for (iter = 0; iter < kMaxIters; ++iter) { - // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to - // one in color computation. Having initial delta here as 1 is sufficient - // to explore the range of (-2, 2). - const int delta = 32 >> iter; - // Try a negative and a positive delta from the best known value. - for (offset = -delta; offset <= delta; offset += 2 * delta) { - const int green_to_red_cur = offset + green_to_red_best; - const float cur_diff = GetPredictionCostCrossColorRed( - argb, stride, tile_width, tile_height, prev_x, prev_y, - green_to_red_cur, accumulated_red_histo); - if (cur_diff < best_diff) { - best_diff = cur_diff; - green_to_red_best = green_to_red_cur; - } - } - } - best_tx->green_to_red_ = green_to_red_best; -} - void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, int tile_width, int tile_height, int green_to_blue, int red_to_blue, @@ -1080,187 +575,6 @@ void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, } } -static float GetPredictionCostCrossColorBlue( - const uint32_t* argb, int stride, int tile_width, int tile_height, - VP8LMultipliers prev_x, VP8LMultipliers prev_y, - int green_to_blue, int red_to_blue, const int accumulated_blue_histo[256]) { - int histo[256] = { 0 }; - float cur_diff; - - VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height, - green_to_blue, red_to_blue, histo); - - cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo); - if ((uint8_t)green_to_blue == prev_x.green_to_blue_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if ((uint8_t)green_to_blue == prev_y.green_to_blue_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if ((uint8_t)red_to_blue == prev_x.red_to_blue_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if ((uint8_t)red_to_blue == prev_y.red_to_blue_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if (green_to_blue == 0) { - cur_diff -= 3; - } - if (red_to_blue == 0) { - cur_diff -= 3; - } - return cur_diff; -} - -#define kGreenRedToBlueNumAxis 8 -#define kGreenRedToBlueMaxIters 7 -static void GetBestGreenRedToBlue( - const uint32_t* argb, int stride, int tile_width, int tile_height, - VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, - const int accumulated_blue_histo[256], - VP8LMultipliers* const best_tx) { - const int8_t offset[kGreenRedToBlueNumAxis][2] = - {{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}}; - const int8_t delta_lut[kGreenRedToBlueMaxIters] = { 16, 16, 8, 4, 2, 2, 2 }; - const int iters = - (quality < 25) ? 1 : (quality > 50) ? kGreenRedToBlueMaxIters : 4; - int green_to_blue_best = 0; - int red_to_blue_best = 0; - int iter; - // Initial value at origin: - float best_diff = GetPredictionCostCrossColorBlue( - argb, stride, tile_width, tile_height, prev_x, prev_y, - green_to_blue_best, red_to_blue_best, accumulated_blue_histo); - for (iter = 0; iter < iters; ++iter) { - const int delta = delta_lut[iter]; - int axis; - for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) { - const int green_to_blue_cur = - offset[axis][0] * delta + green_to_blue_best; - const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best; - const float cur_diff = GetPredictionCostCrossColorBlue( - argb, stride, tile_width, tile_height, prev_x, prev_y, - green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo); - if (cur_diff < best_diff) { - best_diff = cur_diff; - green_to_blue_best = green_to_blue_cur; - red_to_blue_best = red_to_blue_cur; - } - if (quality < 25 && iter == 4) { - // Only axis aligned diffs for lower quality. - break; // next iter. - } - } - if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) { - // Further iterations would not help. - break; // out of iter-loop. - } - } - best_tx->green_to_blue_ = green_to_blue_best; - best_tx->red_to_blue_ = red_to_blue_best; -} -#undef kGreenRedToBlueMaxIters -#undef kGreenRedToBlueNumAxis - -static VP8LMultipliers GetBestColorTransformForTile( - int tile_x, int tile_y, int bits, - VP8LMultipliers prev_x, - VP8LMultipliers prev_y, - int quality, int xsize, int ysize, - const int accumulated_red_histo[256], - const int accumulated_blue_histo[256], - const uint32_t* const argb) { - const int max_tile_size = 1 << bits; - const int tile_y_offset = tile_y * max_tile_size; - const int tile_x_offset = tile_x * max_tile_size; - const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize); - const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize); - const int tile_width = all_x_max - tile_x_offset; - const int tile_height = all_y_max - tile_y_offset; - const uint32_t* const tile_argb = argb + tile_y_offset * xsize - + tile_x_offset; - VP8LMultipliers best_tx; - MultipliersClear(&best_tx); - - GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height, - prev_x, prev_y, quality, accumulated_red_histo, &best_tx); - GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height, - prev_x, prev_y, quality, accumulated_blue_histo, - &best_tx); - return best_tx; -} - -static void CopyTileWithColorTransform(int xsize, int ysize, - int tile_x, int tile_y, - int max_tile_size, - VP8LMultipliers color_transform, - uint32_t* argb) { - const int xscan = GetMin(max_tile_size, xsize - tile_x); - int yscan = GetMin(max_tile_size, ysize - tile_y); - argb += tile_y * xsize + tile_x; - while (yscan-- > 0) { - VP8LTransformColor(&color_transform, argb, xscan); - argb += xsize; - } -} - -void VP8LColorSpaceTransform(int width, int height, int bits, int quality, - uint32_t* const argb, uint32_t* image) { - const int max_tile_size = 1 << bits; - const int tile_xsize = VP8LSubSampleSize(width, bits); - const int tile_ysize = VP8LSubSampleSize(height, bits); - int accumulated_red_histo[256] = { 0 }; - int accumulated_blue_histo[256] = { 0 }; - int tile_x, tile_y; - VP8LMultipliers prev_x, prev_y; - MultipliersClear(&prev_y); - MultipliersClear(&prev_x); - for (tile_y = 0; tile_y < tile_ysize; ++tile_y) { - for (tile_x = 0; tile_x < tile_xsize; ++tile_x) { - int y; - const int tile_x_offset = tile_x * max_tile_size; - const int tile_y_offset = tile_y * max_tile_size; - const int all_x_max = GetMin(tile_x_offset + max_tile_size, width); - const int all_y_max = GetMin(tile_y_offset + max_tile_size, height); - const int offset = tile_y * tile_xsize + tile_x; - if (tile_y != 0) { - ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y); - } - prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits, - prev_x, prev_y, - quality, width, height, - accumulated_red_histo, - accumulated_blue_histo, - argb); - image[offset] = MultipliersToColorCode(&prev_x); - CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset, - max_tile_size, prev_x, argb); - - // Gather accumulated histogram data. - for (y = tile_y_offset; y < all_y_max; ++y) { - int ix = y * width + tile_x_offset; - const int ix_end = ix + all_x_max - tile_x_offset; - for (; ix < ix_end; ++ix) { - const uint32_t pix = argb[ix]; - if (ix >= 2 && - pix == argb[ix - 2] && - pix == argb[ix - 1]) { - continue; // repeated pixels are handled by backward references - } - if (ix >= width + 2 && - argb[ix - 2] == argb[ix - width - 2] && - argb[ix - 1] == argb[ix - width - 1] && - pix == argb[ix - width]) { - continue; // repeated pixels are handled by backward references - } - ++accumulated_red_histo[(pix >> 16) & 0xff]; - ++accumulated_blue_histo[(pix >> 0) & 0xff]; - } - } - } - } -} - //------------------------------------------------------------------------------ static int VectorMismatch(const uint32_t* const array1, @@ -1274,8 +588,8 @@ static int VectorMismatch(const uint32_t* const array1, } // Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. -void VP8LBundleColorMap(const uint8_t* const row, int width, - int xbits, uint32_t* const dst) { +void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits, + uint32_t* dst) { int x; if (xbits > 0) { const int bit_depth = 1 << (3 - xbits); @@ -1350,8 +664,172 @@ static void HistogramAdd(const VP8LHistogram* const a, } //------------------------------------------------------------------------------ +// Image transforms. -VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; +static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) { + return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1); +} + +static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) { + return Average2(Average2(a0, a2), a1); +} + +static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1, + uint32_t a2, uint32_t a3) { + return Average2(Average2(a0, a1), Average2(a2, a3)); +} + +static WEBP_INLINE uint32_t Clip255(uint32_t a) { + if (a < 256) { + return a; + } + // return 0, when a is a negative integer. + // return 255, when a is positive. + return ~a >> 24; +} + +static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) { + return Clip255(a + b - c); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1, + uint32_t c2) { + const int a = AddSubtractComponentFull(c0 >> 24, c1 >> 24, c2 >> 24); + const int r = AddSubtractComponentFull((c0 >> 16) & 0xff, + (c1 >> 16) & 0xff, + (c2 >> 16) & 0xff); + const int g = AddSubtractComponentFull((c0 >> 8) & 0xff, + (c1 >> 8) & 0xff, + (c2 >> 8) & 0xff); + const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff); + return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b; +} + +static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) { + return Clip255(a + (a - b) / 2); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1, + uint32_t c2) { + const uint32_t ave = Average2(c0, c1); + const int a = AddSubtractComponentHalf(ave >> 24, c2 >> 24); + const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff); + const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff); + const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff); + return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b; +} + +// gcc-4.9 on ARM generates incorrect code in Select() when Sub3() is inlined. +#if defined(__arm__) && \ + (LOCAL_GCC_VERSION == 0x409 || LOCAL_GCC_VERSION == 0x408) +# define LOCAL_INLINE __attribute__ ((noinline)) +#else +# define LOCAL_INLINE WEBP_INLINE +#endif + +static LOCAL_INLINE int Sub3(int a, int b, int c) { + const int pb = b - c; + const int pa = a - c; + return abs(pb) - abs(pa); +} + +#undef LOCAL_INLINE + +static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) { + const int pa_minus_pb = + Sub3((a >> 24) , (b >> 24) , (c >> 24) ) + + Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) + + Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) + + Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff); + return (pa_minus_pb <= 0) ? a : b; +} + +//------------------------------------------------------------------------------ +// Predictors + +static uint32_t Predictor2(uint32_t left, const uint32_t* const top) { + (void)left; + return top[0]; +} +static uint32_t Predictor3(uint32_t left, const uint32_t* const top) { + (void)left; + return top[1]; +} +static uint32_t Predictor4(uint32_t left, const uint32_t* const top) { + (void)left; + return top[-1]; +} +static uint32_t Predictor5(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average3(left, top[0], top[1]); + return pred; +} +static uint32_t Predictor6(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average2(left, top[-1]); + return pred; +} +static uint32_t Predictor7(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average2(left, top[0]); + return pred; +} +static uint32_t Predictor8(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average2(top[-1], top[0]); + (void)left; + return pred; +} +static uint32_t Predictor9(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average2(top[0], top[1]); + (void)left; + return pred; +} +static uint32_t Predictor10(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average4(left, top[-1], top[0], top[1]); + return pred; +} +static uint32_t Predictor11(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Select(top[0], left, top[-1]); + return pred; +} +static uint32_t Predictor12(uint32_t left, const uint32_t* const top) { + const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]); + return pred; +} +static uint32_t Predictor13(uint32_t left, const uint32_t* const top) { + const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]); + return pred; +} + +//------------------------------------------------------------------------------ + +static void PredictorSub0_C(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i < num_pixels; ++i) out[i] = VP8LSubPixels(in[i], ARGB_BLACK); + (void)upper; +} + +static void PredictorSub1_C(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i < num_pixels; ++i) out[i] = VP8LSubPixels(in[i], in[i - 1]); + (void)upper; +} + +GENERATE_PREDICTOR_SUB(Predictor2, PredictorSub2_C) +GENERATE_PREDICTOR_SUB(Predictor3, PredictorSub3_C) +GENERATE_PREDICTOR_SUB(Predictor4, PredictorSub4_C) +GENERATE_PREDICTOR_SUB(Predictor5, PredictorSub5_C) +GENERATE_PREDICTOR_SUB(Predictor6, PredictorSub6_C) +GENERATE_PREDICTOR_SUB(Predictor7, PredictorSub7_C) +GENERATE_PREDICTOR_SUB(Predictor8, PredictorSub8_C) +GENERATE_PREDICTOR_SUB(Predictor9, PredictorSub9_C) +GENERATE_PREDICTOR_SUB(Predictor10, PredictorSub10_C) +GENERATE_PREDICTOR_SUB(Predictor11, PredictorSub11_C) +GENERATE_PREDICTOR_SUB(Predictor12, PredictorSub12_C) +GENERATE_PREDICTOR_SUB(Predictor13, PredictorSub13_C) + +//------------------------------------------------------------------------------ + +VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; VP8LTransformColorFunc VP8LTransformColor; @@ -1365,17 +843,23 @@ VP8LCostFunc VP8LExtraCost; VP8LCostCombinedFunc VP8LExtraCostCombined; VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; -GetEntropyUnrefinedHelperFunc VP8LGetEntropyUnrefinedHelper; +VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; +VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined; VP8LHistogramAddFunc VP8LHistogramAdd; VP8LVectorMismatchFunc VP8LVectorMismatch; +VP8LBundleColorMapFunc VP8LBundleColorMap; + +VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; +VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; extern void VP8LEncDspInitSSE2(void); extern void VP8LEncDspInitSSE41(void); extern void VP8LEncDspInitNEON(void); extern void VP8LEncDspInitMIPS32(void); extern void VP8LEncDspInitMIPSdspR2(void); +extern void VP8LEncDspInitMSA(void); static volatile VP8CPUInfo lossless_enc_last_cpuinfo_used = (VP8CPUInfo)&lossless_enc_last_cpuinfo_used; @@ -1399,11 +883,47 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInit(void) { VP8LExtraCostCombined = ExtraCostCombined; VP8LCombinedShannonEntropy = CombinedShannonEntropy; - VP8LGetEntropyUnrefinedHelper = GetEntropyUnrefinedHelper; + VP8LGetEntropyUnrefined = GetEntropyUnrefined; + VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined; VP8LHistogramAdd = HistogramAdd; VP8LVectorMismatch = VectorMismatch; + VP8LBundleColorMap = VP8LBundleColorMap_C; + + VP8LPredictorsSub[0] = PredictorSub0_C; + VP8LPredictorsSub[1] = PredictorSub1_C; + VP8LPredictorsSub[2] = PredictorSub2_C; + VP8LPredictorsSub[3] = PredictorSub3_C; + VP8LPredictorsSub[4] = PredictorSub4_C; + VP8LPredictorsSub[5] = PredictorSub5_C; + VP8LPredictorsSub[6] = PredictorSub6_C; + VP8LPredictorsSub[7] = PredictorSub7_C; + VP8LPredictorsSub[8] = PredictorSub8_C; + VP8LPredictorsSub[9] = PredictorSub9_C; + VP8LPredictorsSub[10] = PredictorSub10_C; + VP8LPredictorsSub[11] = PredictorSub11_C; + VP8LPredictorsSub[12] = PredictorSub12_C; + VP8LPredictorsSub[13] = PredictorSub13_C; + VP8LPredictorsSub[14] = PredictorSub0_C; // <- padding security sentinels + VP8LPredictorsSub[15] = PredictorSub0_C; + + VP8LPredictorsSub_C[0] = PredictorSub0_C; + VP8LPredictorsSub_C[1] = PredictorSub1_C; + VP8LPredictorsSub_C[2] = PredictorSub2_C; + VP8LPredictorsSub_C[3] = PredictorSub3_C; + VP8LPredictorsSub_C[4] = PredictorSub4_C; + VP8LPredictorsSub_C[5] = PredictorSub5_C; + VP8LPredictorsSub_C[6] = PredictorSub6_C; + VP8LPredictorsSub_C[7] = PredictorSub7_C; + VP8LPredictorsSub_C[8] = PredictorSub8_C; + VP8LPredictorsSub_C[9] = PredictorSub9_C; + VP8LPredictorsSub_C[10] = PredictorSub10_C; + VP8LPredictorsSub_C[11] = PredictorSub11_C; + VP8LPredictorsSub_C[12] = PredictorSub12_C; + VP8LPredictorsSub_C[13] = PredictorSub13_C; + VP8LPredictorsSub_C[14] = PredictorSub0_C; // <- padding security sentinels + VP8LPredictorsSub_C[15] = PredictorSub0_C; // If defined, use CPUInfo() to overwrite some pointers with faster versions. if (VP8GetCPUInfo != NULL) { @@ -1431,6 +951,11 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInit(void) { if (VP8GetCPUInfo(kMIPSdspR2)) { VP8LEncDspInitMIPSdspR2(); } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8LEncDspInitMSA(); + } #endif } lossless_enc_last_cpuinfo_used = VP8GetCPUInfo; diff --git a/src/3rdparty/libwebp/src/dsp/lossless_enc_mips32.c b/src/3rdparty/libwebp/src/dsp/lossless_enc_mips32.c index 49c666d4fd547d5c52d55eb1b88c3f39a2a73f09..4186b9f50d47846bbd87d647820384f4aa45f6bd 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless_enc_mips32.c +++ b/src/3rdparty/libwebp/src/dsp/lossless_enc_mips32.c @@ -14,6 +14,7 @@ #include "./dsp.h" #include "./lossless.h" +#include "./lossless_common.h" #if defined(WEBP_USE_MIPS32) @@ -240,6 +241,49 @@ static WEBP_INLINE void GetEntropyUnrefinedHelper( *i_prev = i; } +static void GetEntropyUnrefined(const uint32_t X[], int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats) { + int i; + int i_prev = 0; + uint32_t x_prev = X[0]; + + memset(stats, 0, sizeof(*stats)); + VP8LBitEntropyInit(bit_entropy); + + for (i = 1; i < length; ++i) { + const uint32_t x = X[i]; + if (x != x_prev) { + GetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); + } + } + GetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); + + bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); +} + +static void GetCombinedEntropyUnrefined(const uint32_t X[], const uint32_t Y[], + int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats) { + int i = 1; + int i_prev = 0; + uint32_t xy_prev = X[0] + Y[0]; + + memset(stats, 0, sizeof(*stats)); + VP8LBitEntropyInit(bit_entropy); + + for (i = 1; i < length; ++i) { + const uint32_t xy = X[i] + Y[i]; + if (xy != xy_prev) { + GetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, bit_entropy, stats); + } + } + GetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, bit_entropy, stats); + + bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); +} + #define ASM_START \ __asm__ volatile( \ ".set push \n\t" \ @@ -375,7 +419,8 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPS32(void) { VP8LFastLog2Slow = FastLog2Slow; VP8LExtraCost = ExtraCost; VP8LExtraCostCombined = ExtraCostCombined; - VP8LGetEntropyUnrefinedHelper = GetEntropyUnrefinedHelper; + VP8LGetEntropyUnrefined = GetEntropyUnrefined; + VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined; VP8LHistogramAdd = HistogramAdd; } diff --git a/src/3rdparty/libwebp/src/dsp/lossless_enc_msa.c b/src/3rdparty/libwebp/src/dsp/lossless_enc_msa.c new file mode 100644 index 0000000000000000000000000000000000000000..2f69ba3bca3714a40c748de707d86cb3a1df0eb6 --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/lossless_enc_msa.c @@ -0,0 +1,147 @@ +// Copyright 2016 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. +// ----------------------------------------------------------------------------- +// +// MSA variant of Image transform methods for lossless encoder. +// +// Authors: Prashant Patil (Prashant.Patil@imgtec.com) + +#include "./dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "./lossless.h" +#include "./msa_macro.h" + +#define TRANSFORM_COLOR_8(src0, src1, dst0, dst1, c0, c1, mask0, mask1) do { \ + v8i16 g0, g1, t0, t1, t2, t3; \ + v4i32 t4, t5; \ + VSHF_B2_SH(src0, src0, src1, src1, mask0, mask0, g0, g1); \ + DOTP_SB2_SH(g0, g1, c0, c0, t0, t1); \ + SRAI_H2_SH(t0, t1, 5); \ + t0 = __msa_subv_h((v8i16)src0, t0); \ + t1 = __msa_subv_h((v8i16)src1, t1); \ + t4 = __msa_srli_w((v4i32)src0, 16); \ + t5 = __msa_srli_w((v4i32)src1, 16); \ + DOTP_SB2_SH(t4, t5, c1, c1, t2, t3); \ + SRAI_H2_SH(t2, t3, 5); \ + SUB2(t0, t2, t1, t3, t0, t1); \ + VSHF_B2_UB(src0, t0, src1, t1, mask1, mask1, dst0, dst1); \ +} while (0) + +#define TRANSFORM_COLOR_4(src, dst, c0, c1, mask0, mask1) do { \ + const v16i8 g0 = VSHF_SB(src, src, mask0); \ + v8i16 t0 = __msa_dotp_s_h(c0, g0); \ + v8i16 t1; \ + v4i32 t2; \ + t0 = SRAI_H(t0, 5); \ + t0 = __msa_subv_h((v8i16)src, t0); \ + t2 = __msa_srli_w((v4i32)src, 16); \ + t1 = __msa_dotp_s_h(c1, (v16i8)t2); \ + t1 = SRAI_H(t1, 5); \ + t0 = t0 - t1; \ + dst = VSHF_UB(src, t0, mask1); \ +} while (0) + +static void TransformColor(const VP8LMultipliers* const m, uint32_t* data, + int num_pixels) { + v16u8 src0, dst0; + const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue_ | + (m->green_to_red_ << 16)); + const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue_); + const v16u8 mask0 = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, + 13, 255, 13, 255 }; + const v16u8 mask1 = { 16, 1, 18, 3, 20, 5, 22, 7, 24, 9, 26, 11, + 28, 13, 30, 15 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1; + LD_UB2(data, 4, src0, src1); + TRANSFORM_COLOR_8(src0, src1, dst0, dst1, g2br, r2b, mask0, mask1); + ST_UB2(dst0, dst1, data, 4); + data += 8; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(data); + TRANSFORM_COLOR_4(src0, dst0, g2br, r2b, mask0, mask1); + ST_UB(dst0, data); + data += 4; + num_pixels -= 4; + } + if (num_pixels > 0) { + src0 = LD_UB(data); + TRANSFORM_COLOR_4(src0, dst0, g2br, r2b, mask0, mask1); + if (num_pixels == 3) { + const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); + const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 2); + SD(pix_d, data + 0); + SW(pix_w, data + 2); + } else if (num_pixels == 2) { + const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); + SD(pix_d, data); + } else { + const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 0); + SW(pix_w, data); + } + } + } +} + +static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) { + int i; + uint8_t* ptemp_data = (uint8_t*)argb_data; + v16u8 src0, dst0, tmp0; + const v16u8 mask = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, + 13, 255, 13, 255 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1, tmp1; + LD_UB2(ptemp_data, 16, src0, src1); + VSHF_B2_UB(src0, src1, src1, src0, mask, mask, tmp0, tmp1); + SUB2(src0, tmp0, src1, tmp1, dst0, dst1); + ST_UB2(dst0, dst1, ptemp_data, 16); + ptemp_data += 8 * 4; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(ptemp_data); + tmp0 = VSHF_UB(src0, src0, mask); + dst0 = src0 - tmp0; + ST_UB(dst0, ptemp_data); + ptemp_data += 4 * 4; + num_pixels -= 4; + } + for (i = 0; i < num_pixels; i++) { + const uint8_t b = ptemp_data[0]; + const uint8_t g = ptemp_data[1]; + const uint8_t r = ptemp_data[2]; + ptemp_data[0] = (b - g) & 0xff; + ptemp_data[2] = (r - g) & 0xff; + ptemp_data += 4; + } + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LEncDspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMSA(void) { + VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed; + VP8LTransformColor = TransformColor; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8LEncDspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/src/3rdparty/libwebp/src/dsp/lossless_enc_sse2.c b/src/3rdparty/libwebp/src/dsp/lossless_enc_sse2.c index 7c894e7ca4d32f9fb95df2e8de89f3e46f2e2167..8ad85d94d7af6f8e2dca5ddd53f5e19ca5bd2f09 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless_enc_sse2.c +++ b/src/3rdparty/libwebp/src/dsp/lossless_enc_sse2.c @@ -17,6 +17,8 @@ #include <assert.h> #include <emmintrin.h> #include "./lossless.h" +#include "./common_sse2.h" +#include "./lossless_common.h" // For sign-extended multiplying constants, pre-shifted by 5: #define CST_5b(X) (((int16_t)((uint16_t)X << 8)) >> 5) @@ -35,7 +37,9 @@ static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) { _mm_storeu_si128((__m128i*)&argb_data[i], out); } // fallthrough and finish off with plain-C - VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); + if (i != num_pixels) { + VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); + } } //------------------------------------------------------------------------------ @@ -69,7 +73,9 @@ static void TransformColor(const VP8LMultipliers* const m, _mm_storeu_si128((__m128i*)&argb_data[i], out); } // fallthrough and finish off with plain-C - VP8LTransformColor_C(m, argb_data + i, num_pixels - i); + if (i != num_pixels) { + VP8LTransformColor_C(m, argb_data + i, num_pixels - i); + } } //------------------------------------------------------------------------------ @@ -364,8 +370,9 @@ static int VectorMismatch(const uint32_t* const array1, if (length >= 8 && _mm_movemask_epi8(_mm_cmpeq_epi32( _mm_loadu_si128((const __m128i*)&array1[4]), - _mm_loadu_si128((const __m128i*)&array2[4]))) == 0xffff) + _mm_loadu_si128((const __m128i*)&array2[4]))) == 0xffff) { match_len = 8; + } } } @@ -375,6 +382,295 @@ static int VectorMismatch(const uint32_t* const array1, return match_len; } +// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. +static void BundleColorMap_SSE2(const uint8_t* const row, int width, int xbits, + uint32_t* dst) { + int x; + assert(xbits >= 0); + assert(xbits <= 3); + switch (xbits) { + case 0: { + const __m128i ff = _mm_set1_epi16(0xff00); + const __m128i zero = _mm_setzero_si128(); + // Store 0xff000000 | (row[x] << 8). + for (x = 0; x + 16 <= width; x += 16, dst += 16) { + const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); + const __m128i in_lo = _mm_unpacklo_epi8(zero, in); + const __m128i dst0 = _mm_unpacklo_epi16(in_lo, ff); + const __m128i dst1 = _mm_unpackhi_epi16(in_lo, ff); + const __m128i in_hi = _mm_unpackhi_epi8(zero, in); + const __m128i dst2 = _mm_unpacklo_epi16(in_hi, ff); + const __m128i dst3 = _mm_unpackhi_epi16(in_hi, ff); + _mm_storeu_si128((__m128i*)&dst[0], dst0); + _mm_storeu_si128((__m128i*)&dst[4], dst1); + _mm_storeu_si128((__m128i*)&dst[8], dst2); + _mm_storeu_si128((__m128i*)&dst[12], dst3); + } + break; + } + case 1: { + const __m128i ff = _mm_set1_epi16(0xff00); + const __m128i mul = _mm_set1_epi16(0x110); + for (x = 0; x + 16 <= width; x += 16, dst += 8) { + // 0a0b | (where a/b are 4 bits). + const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); + const __m128i tmp = _mm_mullo_epi16(in, mul); // aba0 + const __m128i pack = _mm_and_si128(tmp, ff); // ab00 + const __m128i dst0 = _mm_unpacklo_epi16(pack, ff); + const __m128i dst1 = _mm_unpackhi_epi16(pack, ff); + _mm_storeu_si128((__m128i*)&dst[0], dst0); + _mm_storeu_si128((__m128i*)&dst[4], dst1); + } + break; + } + case 2: { + const __m128i mask_or = _mm_set1_epi32(0xff000000); + const __m128i mul_cst = _mm_set1_epi16(0x0104); + const __m128i mask_mul = _mm_set1_epi16(0x0f00); + for (x = 0; x + 16 <= width; x += 16, dst += 4) { + // 000a000b000c000d | (where a/b/c/d are 2 bits). + const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); + const __m128i mul = _mm_mullo_epi16(in, mul_cst); // 00ab00b000cd00d0 + const __m128i tmp = _mm_and_si128(mul, mask_mul); // 00ab000000cd0000 + const __m128i shift = _mm_srli_epi32(tmp, 12); // 00000000ab000000 + const __m128i pack = _mm_or_si128(shift, tmp); // 00000000abcd0000 + // Convert to 0xff00**00. + const __m128i res = _mm_or_si128(pack, mask_or); + _mm_storeu_si128((__m128i*)dst, res); + } + break; + } + default: { + assert(xbits == 3); + for (x = 0; x + 16 <= width; x += 16, dst += 2) { + // 0000000a00000000b... | (where a/b are 1 bit). + const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); + const __m128i shift = _mm_slli_epi64(in, 7); + const uint32_t move = _mm_movemask_epi8(shift); + dst[0] = 0xff000000 | ((move & 0xff) << 8); + dst[1] = 0xff000000 | (move & 0xff00); + } + break; + } + } + if (x != width) { + VP8LBundleColorMap_C(row + x, width - x, xbits, dst); + } +} + +//------------------------------------------------------------------------------ +// Batch version of Predictor Transform subtraction + +static WEBP_INLINE void Average2_m128i(const __m128i* const a0, + const __m128i* const a1, + __m128i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m128i ones = _mm_set1_epi8(1); + const __m128i avg1 = _mm_avg_epu8(*a0, *a1); + const __m128i one = _mm_and_si128(_mm_xor_si128(*a0, *a1), ones); + *avg = _mm_sub_epi8(avg1, one); +} + +// Predictor0: ARGB_BLACK. +static void PredictorSub0_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i black = _mm_set1_epi32(ARGB_BLACK); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i res = _mm_sub_epi8(src, black); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[0](in + i, upper + i, num_pixels - i, out + i); + } +} + +#define GENERATE_PREDICTOR_1(X, IN) \ +static void PredictorSub##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ + const __m128i pred = _mm_loadu_si128((const __m128i*)&(IN)); \ + const __m128i res = _mm_sub_epi8(src, pred); \ + _mm_storeu_si128((__m128i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsSub_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ +} + +GENERATE_PREDICTOR_1(1, in[i - 1]) // Predictor1: L +GENERATE_PREDICTOR_1(2, upper[i]) // Predictor2: T +GENERATE_PREDICTOR_1(3, upper[i + 1]) // Predictor3: TR +GENERATE_PREDICTOR_1(4, upper[i - 1]) // Predictor4: TL +#undef GENERATE_PREDICTOR_1 + +// Predictor5: avg2(avg2(L, TR), T) +static void PredictorSub5_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]); + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + __m128i avg, pred, res; + Average2_m128i(&L, &TR, &avg); + Average2_m128i(&avg, &T, &pred); + res = _mm_sub_epi8(src, pred); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[5](in + i, upper + i, num_pixels - i, out + i); + } +} + +#define GENERATE_PREDICTOR_2(X, A, B) \ +static void PredictorSub##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const __m128i tA = _mm_loadu_si128((const __m128i*)&(A)); \ + const __m128i tB = _mm_loadu_si128((const __m128i*)&(B)); \ + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ + __m128i pred, res; \ + Average2_m128i(&tA, &tB, &pred); \ + res = _mm_sub_epi8(src, pred); \ + _mm_storeu_si128((__m128i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsSub_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ +} + +GENERATE_PREDICTOR_2(6, in[i - 1], upper[i - 1]) // Predictor6: avg(L, TL) +GENERATE_PREDICTOR_2(7, in[i - 1], upper[i]) // Predictor7: avg(L, T) +GENERATE_PREDICTOR_2(8, upper[i - 1], upper[i]) // Predictor8: avg(TL, T) +GENERATE_PREDICTOR_2(9, upper[i], upper[i + 1]) // Predictor9: average(T, TR) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: avg(avg(L,TL), avg(T, TR)). +static void PredictorSub10_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]); + __m128i avgTTR, avgLTL, avg, res; + Average2_m128i(&T, &TR, &avgTTR); + Average2_m128i(&L, &TL, &avgLTL); + Average2_m128i(&avgTTR, &avgLTL, &avg); + res = _mm_sub_epi8(src, avg); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[10](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor11: select. +static void GetSumAbsDiff32(const __m128i* const A, const __m128i* const B, + __m128i* const out) { + // We can unpack with any value on the upper 32 bits, provided it's the same + // on both operands (to that their sum of abs diff is zero). Here we use *A. + const __m128i A_lo = _mm_unpacklo_epi32(*A, *A); + const __m128i B_lo = _mm_unpacklo_epi32(*B, *A); + const __m128i A_hi = _mm_unpackhi_epi32(*A, *A); + const __m128i B_hi = _mm_unpackhi_epi32(*B, *A); + const __m128i s_lo = _mm_sad_epu8(A_lo, B_lo); + const __m128i s_hi = _mm_sad_epu8(A_hi, B_hi); + *out = _mm_packs_epi32(s_lo, s_hi); +} + +static void PredictorSub11_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + __m128i pa, pb; + GetSumAbsDiff32(&T, &TL, &pa); // pa = sum |T-TL| + GetSumAbsDiff32(&L, &TL, &pb); // pb = sum |L-TL| + { + const __m128i mask = _mm_cmpgt_epi32(pb, pa); + const __m128i A = _mm_and_si128(mask, L); + const __m128i B = _mm_andnot_si128(mask, T); + const __m128i pred = _mm_or_si128(A, B); // pred = (L > T)? L : T + const __m128i res = _mm_sub_epi8(src, pred); + _mm_storeu_si128((__m128i*)&out[i], res); + } + } + if (i != num_pixels) { + VP8LPredictorsSub_C[11](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor12: ClampedSubSubtractFull. +static void PredictorSub12_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i L_lo = _mm_unpacklo_epi8(L, zero); + const __m128i L_hi = _mm_unpackhi_epi8(L, zero); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i T_lo = _mm_unpacklo_epi8(T, zero); + const __m128i T_hi = _mm_unpackhi_epi8(T, zero); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); + const __m128i TL_hi = _mm_unpackhi_epi8(TL, zero); + const __m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo); + const __m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi); + const __m128i pred_lo = _mm_add_epi16(L_lo, diff_lo); + const __m128i pred_hi = _mm_add_epi16(L_hi, diff_hi); + const __m128i pred = _mm_packus_epi16(pred_lo, pred_hi); + const __m128i res = _mm_sub_epi8(src, pred); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[12](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictors13: ClampedAddSubtractHalf +static void PredictorSub13_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 2 <= num_pixels; i += 2) { + // we can only process two pixels at a time + const __m128i L = _mm_loadl_epi64((const __m128i*)&in[i - 1]); + const __m128i src = _mm_loadl_epi64((const __m128i*)&in[i]); + const __m128i T = _mm_loadl_epi64((const __m128i*)&upper[i]); + const __m128i TL = _mm_loadl_epi64((const __m128i*)&upper[i - 1]); + const __m128i L_lo = _mm_unpacklo_epi8(L, zero); + const __m128i T_lo = _mm_unpacklo_epi8(T, zero); + const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); + const __m128i sum = _mm_add_epi16(T_lo, L_lo); + const __m128i avg = _mm_srli_epi16(sum, 1); + const __m128i A1 = _mm_sub_epi16(avg, TL_lo); + const __m128i bit_fix = _mm_cmpgt_epi16(TL_lo, avg); + const __m128i A2 = _mm_sub_epi16(A1, bit_fix); + const __m128i A3 = _mm_srai_epi16(A2, 1); + const __m128i A4 = _mm_add_epi16(avg, A3); + const __m128i pred = _mm_packus_epi16(A4, A4); + const __m128i res = _mm_sub_epi8(src, pred); + _mm_storel_epi64((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[13](in + i, upper + i, num_pixels - i, out + i); + } +} + //------------------------------------------------------------------------------ // Entry point @@ -388,6 +684,24 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) { VP8LHistogramAdd = HistogramAdd; VP8LCombinedShannonEntropy = CombinedShannonEntropy; VP8LVectorMismatch = VectorMismatch; + VP8LBundleColorMap = BundleColorMap_SSE2; + + VP8LPredictorsSub[0] = PredictorSub0_SSE2; + VP8LPredictorsSub[1] = PredictorSub1_SSE2; + VP8LPredictorsSub[2] = PredictorSub2_SSE2; + VP8LPredictorsSub[3] = PredictorSub3_SSE2; + VP8LPredictorsSub[4] = PredictorSub4_SSE2; + VP8LPredictorsSub[5] = PredictorSub5_SSE2; + VP8LPredictorsSub[6] = PredictorSub6_SSE2; + VP8LPredictorsSub[7] = PredictorSub7_SSE2; + VP8LPredictorsSub[8] = PredictorSub8_SSE2; + VP8LPredictorsSub[9] = PredictorSub9_SSE2; + VP8LPredictorsSub[10] = PredictorSub10_SSE2; + VP8LPredictorsSub[11] = PredictorSub11_SSE2; + VP8LPredictorsSub[12] = PredictorSub12_SSE2; + VP8LPredictorsSub[13] = PredictorSub13_SSE2; + VP8LPredictorsSub[14] = PredictorSub0_SSE2; // <- padding security sentinels + VP8LPredictorsSub[15] = PredictorSub0_SSE2; } #else // !WEBP_USE_SSE2 diff --git a/src/3rdparty/libwebp/src/dsp/lossless_enc_sse41.c b/src/3rdparty/libwebp/src/dsp/lossless_enc_sse41.c index 3e493198dbefc708a18d994bfcab4a6af9069b86..821057ccd4aaad073a12af7e0af080c4187da0e0 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless_enc_sse41.c +++ b/src/3rdparty/libwebp/src/dsp/lossless_enc_sse41.c @@ -32,7 +32,9 @@ static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) { _mm_storeu_si128((__m128i*)&argb_data[i], out); } // fallthrough and finish off with plain-C - VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); + if (i != num_pixels) { + VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); + } } //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/dsp/lossless_mips_dsp_r2.c b/src/3rdparty/libwebp/src/dsp/lossless_mips_dsp_r2.c index 90aed7f1510d2be5b17becb87ceb949a70762e97..2984ce8df796277ef5217b6af3b4dd2088fc6f15 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless_mips_dsp_r2.c +++ b/src/3rdparty/libwebp/src/dsp/lossless_mips_dsp_r2.c @@ -17,6 +17,7 @@ #if defined(WEBP_USE_MIPS_DSP_R2) #include "./lossless.h" +#include "./lossless_common.h" #define MAP_COLOR_FUNCS(FUNC_NAME, TYPE, GET_INDEX, GET_VALUE) \ static void FUNC_NAME(const TYPE* src, \ @@ -227,25 +228,27 @@ static uint32_t Predictor13(uint32_t left, const uint32_t* const top) { // Add green to blue and red channels (i.e. perform the inverse transform of // 'subtract green'). -static void AddGreenToBlueAndRed(uint32_t* data, int num_pixels) { +static void AddGreenToBlueAndRed(const uint32_t* src, int num_pixels, + uint32_t* dst) { uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - uint32_t* const p_loop1_end = data + (num_pixels & ~3); - uint32_t* const p_loop2_end = data + num_pixels; + const uint32_t* const p_loop1_end = src + (num_pixels & ~3); + const uint32_t* const p_loop2_end = src + num_pixels; __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" - "beq %[data], %[p_loop1_end], 3f \n\t" + "beq %[src], %[p_loop1_end], 3f \n\t" " nop \n\t" "0: \n\t" - "lw %[temp0], 0(%[data]) \n\t" - "lw %[temp1], 4(%[data]) \n\t" - "lw %[temp2], 8(%[data]) \n\t" - "lw %[temp3], 12(%[data]) \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "lw %[temp1], 4(%[src]) \n\t" + "lw %[temp2], 8(%[src]) \n\t" + "lw %[temp3], 12(%[src]) \n\t" "ext %[temp4], %[temp0], 8, 8 \n\t" "ext %[temp5], %[temp1], 8, 8 \n\t" "ext %[temp6], %[temp2], 8, 8 \n\t" "ext %[temp7], %[temp3], 8, 8 \n\t" - "addiu %[data], %[data], 16 \n\t" + "addiu %[src], %[src], 16 \n\t" + "addiu %[dst], %[dst], 16 \n\t" "replv.ph %[temp4], %[temp4] \n\t" "replv.ph %[temp5], %[temp5] \n\t" "replv.ph %[temp6], %[temp6] \n\t" @@ -254,44 +257,47 @@ static void AddGreenToBlueAndRed(uint32_t* data, int num_pixels) { "addu.qb %[temp1], %[temp1], %[temp5] \n\t" "addu.qb %[temp2], %[temp2], %[temp6] \n\t" "addu.qb %[temp3], %[temp3], %[temp7] \n\t" - "sw %[temp0], -16(%[data]) \n\t" - "sw %[temp1], -12(%[data]) \n\t" - "sw %[temp2], -8(%[data]) \n\t" - "bne %[data], %[p_loop1_end], 0b \n\t" - " sw %[temp3], -4(%[data]) \n\t" + "sw %[temp0], -16(%[dst]) \n\t" + "sw %[temp1], -12(%[dst]) \n\t" + "sw %[temp2], -8(%[dst]) \n\t" + "bne %[src], %[p_loop1_end], 0b \n\t" + " sw %[temp3], -4(%[dst]) \n\t" "3: \n\t" - "beq %[data], %[p_loop2_end], 2f \n\t" + "beq %[src], %[p_loop2_end], 2f \n\t" " nop \n\t" "1: \n\t" - "lw %[temp0], 0(%[data]) \n\t" - "addiu %[data], %[data], 4 \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "addiu %[src], %[src], 4 \n\t" + "addiu %[dst], %[dst], 4 \n\t" "ext %[temp4], %[temp0], 8, 8 \n\t" "replv.ph %[temp4], %[temp4] \n\t" "addu.qb %[temp0], %[temp0], %[temp4] \n\t" - "bne %[data], %[p_loop2_end], 1b \n\t" - " sw %[temp0], -4(%[data]) \n\t" + "bne %[src], %[p_loop2_end], 1b \n\t" + " sw %[temp0], -4(%[dst]) \n\t" "2: \n\t" ".set pop \n\t" - : [data]"+&r"(data), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), - [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), [temp7]"=&r"(temp7) + : [dst]"+&r"(dst), [src]"+&r"(src), [temp0]"=&r"(temp0), + [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), + [temp7]"=&r"(temp7) : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) : "memory" ); } static void TransformColorInverse(const VP8LMultipliers* const m, - uint32_t* data, int num_pixels) { + const uint32_t* src, int num_pixels, + uint32_t* dst) { int temp0, temp1, temp2, temp3, temp4, temp5; uint32_t argb, argb1, new_red; const uint32_t G_to_R = m->green_to_red_; const uint32_t G_to_B = m->green_to_blue_; const uint32_t R_to_B = m->red_to_blue_; - uint32_t* const p_loop_end = data + (num_pixels & ~1); + const uint32_t* const p_loop_end = src + (num_pixels & ~1); __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" - "beq %[data], %[p_loop_end], 1f \n\t" + "beq %[src], %[p_loop_end], 1f \n\t" " nop \n\t" "replv.ph %[temp0], %[G_to_R] \n\t" "replv.ph %[temp1], %[G_to_B] \n\t" @@ -303,9 +309,12 @@ static void TransformColorInverse(const VP8LMultipliers* const m, "shra.ph %[temp1], %[temp1], 8 \n\t" "shra.ph %[temp2], %[temp2], 8 \n\t" "0: \n\t" - "lw %[argb], 0(%[data]) \n\t" - "lw %[argb1], 4(%[data]) \n\t" - "addiu %[data], %[data], 8 \n\t" + "lw %[argb], 0(%[src]) \n\t" + "lw %[argb1], 4(%[src]) \n\t" + "sw %[argb], 0(%[dst]) \n\t" + "sw %[argb1], 4(%[dst]) \n\t" + "addiu %[src], %[src], 8 \n\t" + "addiu %[dst], %[dst], 8 \n\t" "precrq.qb.ph %[temp3], %[argb], %[argb1] \n\t" "preceu.ph.qbra %[temp3], %[temp3] \n\t" "shll.ph %[temp3], %[temp3], 8 \n\t" @@ -322,29 +331,29 @@ static void TransformColorInverse(const VP8LMultipliers* const m, "shll.ph %[temp4], %[temp5], 8 \n\t" "shra.ph %[temp4], %[temp4], 8 \n\t" "mul.ph %[temp4], %[temp4], %[temp2] \n\t" - "sb %[temp5], -2(%[data]) \n\t" + "sb %[temp5], -2(%[dst]) \n\t" "sra %[temp5], %[temp5], 16 \n\t" "shra.ph %[temp4], %[temp4], 5 \n\t" "addu.ph %[argb1], %[argb1], %[temp4] \n\t" "preceu.ph.qbra %[temp3], %[argb1] \n\t" - "sb %[temp5], -6(%[data]) \n\t" - "sb %[temp3], -4(%[data]) \n\t" + "sb %[temp5], -6(%[dst]) \n\t" + "sb %[temp3], -4(%[dst]) \n\t" "sra %[temp3], %[temp3], 16 \n\t" - "bne %[data], %[p_loop_end], 0b \n\t" - " sb %[temp3], -8(%[data]) \n\t" + "bne %[src], %[p_loop_end], 0b \n\t" + " sb %[temp3], -8(%[dst]) \n\t" "1: \n\t" ".set pop \n\t" : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [new_red]"=&r"(new_red), [argb]"=&r"(argb), - [argb1]"=&r"(argb1), [data]"+&r"(data) + [argb1]"=&r"(argb1), [dst]"+&r"(dst), [src]"+&r"(src) : [G_to_R]"r"(G_to_R), [R_to_B]"r"(R_to_B), [G_to_B]"r"(G_to_B), [p_loop_end]"r"(p_loop_end) : "memory", "hi", "lo" ); // Fall-back to C-version for left-overs. - if (num_pixels & 1) VP8LTransformColorInverse_C(m, data, 1); + if (num_pixels & 1) VP8LTransformColorInverse_C(m, src, 1, dst); } static void ConvertBGRAToRGB(const uint32_t* src, diff --git a/src/3rdparty/libwebp/src/dsp/lossless_msa.c b/src/3rdparty/libwebp/src/dsp/lossless_msa.c new file mode 100644 index 0000000000000000000000000000000000000000..f6dd5649ac9f73a3d6f17100d69473686f8fc315 --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/lossless_msa.c @@ -0,0 +1,355 @@ +// Copyright 2016 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. +// ----------------------------------------------------------------------------- +// +// MSA variant of methods for lossless decoder +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include "./dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "./lossless.h" +#include "./msa_macro.h" + +//------------------------------------------------------------------------------ +// Colorspace conversion functions + +#define CONVERT16_BGRA_XXX(psrc, pdst, m0, m1, m2) do { \ + v16u8 src0, src1, src2, src3, dst0, dst1, dst2; \ + LD_UB4(psrc, 16, src0, src1, src2, src3); \ + VSHF_B2_UB(src0, src1, src1, src2, m0, m1, dst0, dst1); \ + dst2 = VSHF_UB(src2, src3, m2); \ + ST_UB2(dst0, dst1, pdst, 16); \ + ST_UB(dst2, pdst + 32); \ +} while (0) + +#define CONVERT12_BGRA_XXX(psrc, pdst, m0, m1, m2) do { \ + uint32_t pix_w; \ + v16u8 src0, src1, src2, dst0, dst1, dst2; \ + LD_UB3(psrc, 16, src0, src1, src2); \ + VSHF_B2_UB(src0, src1, src1, src2, m0, m1, dst0, dst1); \ + dst2 = VSHF_UB(src2, src2, m2); \ + ST_UB2(dst0, dst1, pdst, 16); \ + pix_w = __msa_copy_s_w((v4i32)dst2, 0); \ + SW(pix_w, pdst + 32); \ +} while (0) + +#define CONVERT8_BGRA_XXX(psrc, pdst, m0, m1) do { \ + uint64_t pix_d; \ + v16u8 src0, src1, src2, dst0, dst1; \ + LD_UB2(psrc, 16, src0, src1); \ + VSHF_B2_UB(src0, src1, src1, src2, m0, m1, dst0, dst1); \ + ST_UB(dst0, pdst); \ + pix_d = __msa_copy_s_d((v2i64)dst1, 0); \ + SD(pix_d, pdst + 16); \ +} while (0) + +#define CONVERT4_BGRA_XXX(psrc, pdst, m) do { \ + const v16u8 src0 = LD_UB(psrc); \ + const v16u8 dst0 = VSHF_UB(src0, src0, m); \ + uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); \ + uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 2); \ + SD(pix_d, pdst + 0); \ + SW(pix_w, pdst + 8); \ +} while (0) + +#define CONVERT1_BGRA_BGR(psrc, pdst) do { \ + const int32_t b = (psrc)[0]; \ + const int32_t g = (psrc)[1]; \ + const int32_t r = (psrc)[2]; \ + (pdst)[0] = b; \ + (pdst)[1] = g; \ + (pdst)[2] = r; \ +} while (0) + +#define CONVERT1_BGRA_RGB(psrc, pdst) do { \ + const int32_t b = (psrc)[0]; \ + const int32_t g = (psrc)[1]; \ + const int32_t r = (psrc)[2]; \ + (pdst)[0] = r; \ + (pdst)[1] = g; \ + (pdst)[2] = b; \ +} while (0) + +#define TRANSFORM_COLOR_INVERSE_8(src0, src1, dst0, dst1, \ + c0, c1, mask0, mask1) do { \ + v8i16 g0, g1, t0, t1, t2, t3; \ + v4i32 t4, t5; \ + VSHF_B2_SH(src0, src0, src1, src1, mask0, mask0, g0, g1); \ + DOTP_SB2_SH(g0, g1, c0, c0, t0, t1); \ + SRAI_H2_SH(t0, t1, 5); \ + t0 = __msa_addv_h(t0, (v8i16)src0); \ + t1 = __msa_addv_h(t1, (v8i16)src1); \ + t4 = __msa_srli_w((v4i32)t0, 16); \ + t5 = __msa_srli_w((v4i32)t1, 16); \ + DOTP_SB2_SH(t4, t5, c1, c1, t2, t3); \ + SRAI_H2_SH(t2, t3, 5); \ + ADD2(t0, t2, t1, t3, t0, t1); \ + VSHF_B2_UB(src0, t0, src1, t1, mask1, mask1, dst0, dst1); \ +} while (0) + +#define TRANSFORM_COLOR_INVERSE_4(src, dst, c0, c1, mask0, mask1) do { \ + const v16i8 g0 = VSHF_SB(src, src, mask0); \ + v8i16 t0 = __msa_dotp_s_h(c0, g0); \ + v8i16 t1; \ + v4i32 t2; \ + t0 = SRAI_H(t0, 5); \ + t0 = __msa_addv_h(t0, (v8i16)src); \ + t2 = __msa_srli_w((v4i32)t0, 16); \ + t1 = __msa_dotp_s_h(c1, (v16i8)t2); \ + t1 = SRAI_H(t1, 5); \ + t0 = t0 + t1; \ + dst = VSHF_UB(src, t0, mask1); \ +} while (0) + +static void ConvertBGRAToRGBA(const uint32_t* src, + int num_pixels, uint8_t* dst) { + int i; + const uint8_t* ptemp_src = (const uint8_t*)src; + uint8_t* ptemp_dst = (uint8_t*)dst; + v16u8 src0, dst0; + const v16u8 mask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1; + LD_UB2(ptemp_src, 16, src0, src1); + VSHF_B2_UB(src0, src0, src1, src1, mask, mask, dst0, dst1); + ST_UB2(dst0, dst1, ptemp_dst, 16); + ptemp_src += 32; + ptemp_dst += 32; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(ptemp_src); + dst0 = VSHF_UB(src0, src0, mask); + ST_UB(dst0, ptemp_dst); + ptemp_src += 16; + ptemp_dst += 16; + num_pixels -= 4; + } + for (i = 0; i < num_pixels; i++) { + const uint8_t b = ptemp_src[2]; + const uint8_t g = ptemp_src[1]; + const uint8_t r = ptemp_src[0]; + const uint8_t a = ptemp_src[3]; + ptemp_dst[0] = b; + ptemp_dst[1] = g; + ptemp_dst[2] = r; + ptemp_dst[3] = a; + ptemp_src += 4; + ptemp_dst += 4; + } + } +} + +static void ConvertBGRAToBGR(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint8_t* ptemp_src = (const uint8_t*)src; + uint8_t* ptemp_dst = (uint8_t*)dst; + const v16u8 mask0 = { 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, + 16, 17, 18, 20 }; + const v16u8 mask1 = { 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18, 20, + 21, 22, 24, 25 }; + const v16u8 mask2 = { 10, 12, 13, 14, 16, 17, 18, 20, 21, 22, 24, 25, + 26, 28, 29, 30 }; + + while (num_pixels >= 16) { + CONVERT16_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1, mask2); + ptemp_src += 64; + ptemp_dst += 48; + num_pixels -= 16; + } + if (num_pixels > 0) { + if (num_pixels >= 12) { + CONVERT12_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1, mask2); + ptemp_src += 48; + ptemp_dst += 36; + num_pixels -= 12; + } else if (num_pixels >= 8) { + CONVERT8_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1); + ptemp_src += 32; + ptemp_dst += 24; + num_pixels -= 8; + } else if (num_pixels >= 4) { + CONVERT4_BGRA_XXX(ptemp_src, ptemp_dst, mask0); + ptemp_src += 16; + ptemp_dst += 12; + num_pixels -= 4; + } + if (num_pixels == 3) { + CONVERT1_BGRA_BGR(ptemp_src + 0, ptemp_dst + 0); + CONVERT1_BGRA_BGR(ptemp_src + 4, ptemp_dst + 3); + CONVERT1_BGRA_BGR(ptemp_src + 8, ptemp_dst + 6); + } else if (num_pixels == 2) { + CONVERT1_BGRA_BGR(ptemp_src + 0, ptemp_dst + 0); + CONVERT1_BGRA_BGR(ptemp_src + 4, ptemp_dst + 3); + } else if (num_pixels == 1) { + CONVERT1_BGRA_BGR(ptemp_src, ptemp_dst); + } + } +} + +static void ConvertBGRAToRGB(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint8_t* ptemp_src = (const uint8_t*)src; + uint8_t* ptemp_dst = (uint8_t*)dst; + const v16u8 mask0 = { 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, + 18, 17, 16, 22 }; + const v16u8 mask1 = { 5, 4, 10, 9, 8, 14, 13, 12, 18, 17, 16, 22, + 21, 20, 26, 25 }; + const v16u8 mask2 = { 8, 14, 13, 12, 18, 17, 16, 22, 21, 20, 26, 25, + 24, 30, 29, 28 }; + + while (num_pixels >= 16) { + CONVERT16_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1, mask2); + ptemp_src += 64; + ptemp_dst += 48; + num_pixels -= 16; + } + if (num_pixels) { + if (num_pixels >= 12) { + CONVERT12_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1, mask2); + ptemp_src += 48; + ptemp_dst += 36; + num_pixels -= 12; + } else if (num_pixels >= 8) { + CONVERT8_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1); + ptemp_src += 32; + ptemp_dst += 24; + num_pixels -= 8; + } else if (num_pixels >= 4) { + CONVERT4_BGRA_XXX(ptemp_src, ptemp_dst, mask0); + ptemp_src += 16; + ptemp_dst += 12; + num_pixels -= 4; + } + if (num_pixels == 3) { + CONVERT1_BGRA_RGB(ptemp_src + 0, ptemp_dst + 0); + CONVERT1_BGRA_RGB(ptemp_src + 4, ptemp_dst + 3); + CONVERT1_BGRA_RGB(ptemp_src + 8, ptemp_dst + 6); + } else if (num_pixels == 2) { + CONVERT1_BGRA_RGB(ptemp_src + 0, ptemp_dst + 0); + CONVERT1_BGRA_RGB(ptemp_src + 4, ptemp_dst + 3); + } else if (num_pixels == 1) { + CONVERT1_BGRA_RGB(ptemp_src, ptemp_dst); + } + } +} + +static void AddGreenToBlueAndRed(const uint32_t* const src, int num_pixels, + uint32_t* dst) { + int i; + const uint8_t* in = (const uint8_t*)src; + uint8_t* out = (uint8_t*)dst; + v16u8 src0, dst0, tmp0; + const v16u8 mask = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, + 13, 255, 13, 255 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1, tmp1; + LD_UB2(in, 16, src0, src1); + VSHF_B2_UB(src0, src1, src1, src0, mask, mask, tmp0, tmp1); + ADD2(src0, tmp0, src1, tmp1, dst0, dst1); + ST_UB2(dst0, dst1, out, 16); + in += 32; + out += 32; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(in); + tmp0 = VSHF_UB(src0, src0, mask); + dst0 = src0 + tmp0; + ST_UB(dst0, out); + in += 16; + out += 16; + num_pixels -= 4; + } + for (i = 0; i < num_pixels; i++) { + const uint8_t b = in[0]; + const uint8_t g = in[1]; + const uint8_t r = in[2]; + out[0] = (b + g) & 0xff; + out[1] = g; + out[2] = (r + g) & 0xff; + out[4] = in[4]; + out += 4; + } + } +} + +static void TransformColorInverse(const VP8LMultipliers* const m, + const uint32_t* src, int num_pixels, + uint32_t* dst) { + v16u8 src0, dst0; + const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue_ | + (m->green_to_red_ << 16)); + const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue_); + const v16u8 mask0 = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, + 13, 255, 13, 255 }; + const v16u8 mask1 = { 16, 1, 18, 3, 20, 5, 22, 7, 24, 9, 26, 11, + 28, 13, 30, 15 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1; + LD_UB2(src, 4, src0, src1); + TRANSFORM_COLOR_INVERSE_8(src0, src1, dst0, dst1, g2br, r2b, mask0, mask1); + ST_UB2(dst0, dst1, dst, 4); + src += 8; + dst += 8; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(src); + TRANSFORM_COLOR_INVERSE_4(src0, dst0, g2br, r2b, mask0, mask1); + ST_UB(dst0, dst); + src += 4; + dst += 4; + num_pixels -= 4; + } + if (num_pixels > 0) { + src0 = LD_UB(src); + TRANSFORM_COLOR_INVERSE_4(src0, dst0, g2br, r2b, mask0, mask1); + if (num_pixels == 3) { + const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); + const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 2); + SD(pix_d, dst + 0); + SW(pix_w, dst + 2); + } else if (num_pixels == 2) { + const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); + SD(pix_d, dst); + } else { + const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 0); + SW(pix_w, dst); + } + } + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LDspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitMSA(void) { + VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA; + VP8LConvertBGRAToBGR = ConvertBGRAToBGR; + VP8LConvertBGRAToRGB = ConvertBGRAToRGB; + VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed; + VP8LTransformColorInverse = TransformColorInverse; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8LDspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/src/3rdparty/libwebp/src/dsp/lossless_neon.c b/src/3rdparty/libwebp/src/dsp/lossless_neon.c index 6faccb8f977a184d31b126504a6a1005686a65f8..1145d5fad0f0791162a734ffeacea49498e5a993 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless_neon.c +++ b/src/3rdparty/libwebp/src/dsp/lossless_neon.c @@ -139,6 +139,357 @@ static void ConvertBGRAToRGB(const uint32_t* src, #endif // !WORK_AROUND_GCC + +//------------------------------------------------------------------------------ +// Predictor Transform + +#define LOAD_U32_AS_U8(IN) vreinterpret_u8_u32(vdup_n_u32((IN))) +#define LOAD_U32P_AS_U8(IN) vreinterpret_u8_u32(vld1_u32((IN))) +#define LOADQ_U32_AS_U8(IN) vreinterpretq_u8_u32(vdupq_n_u32((IN))) +#define LOADQ_U32P_AS_U8(IN) vreinterpretq_u8_u32(vld1q_u32((IN))) +#define GET_U8_AS_U32(IN) vget_lane_u32(vreinterpret_u32_u8((IN)), 0); +#define GETQ_U8_AS_U32(IN) vgetq_lane_u32(vreinterpretq_u32_u8((IN)), 0); +#define STOREQ_U8_AS_U32P(OUT, IN) vst1q_u32((OUT), vreinterpretq_u32_u8((IN))); +#define ROTATE32_LEFT(L) vextq_u8((L), (L), 12) // D|C|B|A -> C|B|A|D + +static WEBP_INLINE uint8x8_t Average2_u8_NEON(uint32_t a0, uint32_t a1) { + const uint8x8_t A0 = LOAD_U32_AS_U8(a0); + const uint8x8_t A1 = LOAD_U32_AS_U8(a1); + return vhadd_u8(A0, A1); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractHalf_NEON(uint32_t c0, + uint32_t c1, + uint32_t c2) { + const uint8x8_t avg = Average2_u8_NEON(c0, c1); + // Remove one to c2 when bigger than avg. + const uint8x8_t C2 = LOAD_U32_AS_U8(c2); + const uint8x8_t cmp = vcgt_u8(C2, avg); + const uint8x8_t C2_1 = vadd_u8(C2, cmp); + // Compute half of the difference between avg and c2. + const int8x8_t diff_avg = vreinterpret_s8_u8(vhsub_u8(avg, C2_1)); + // Compute the sum with avg and saturate. + const int16x8_t avg_16 = vreinterpretq_s16_u16(vmovl_u8(avg)); + const uint8x8_t res = vqmovun_s16(vaddw_s8(avg_16, diff_avg)); + const uint32_t output = GET_U8_AS_U32(res); + return output; +} + +static WEBP_INLINE uint32_t Average2_NEON(uint32_t a0, uint32_t a1) { + const uint8x8_t avg_u8x8 = Average2_u8_NEON(a0, a1); + const uint32_t avg = GET_U8_AS_U32(avg_u8x8); + return avg; +} + +static WEBP_INLINE uint32_t Average3_NEON(uint32_t a0, uint32_t a1, + uint32_t a2) { + const uint8x8_t avg0 = Average2_u8_NEON(a0, a2); + const uint8x8_t A1 = LOAD_U32_AS_U8(a1); + const uint32_t avg = GET_U8_AS_U32(vhadd_u8(avg0, A1)); + return avg; +} + +static uint32_t Predictor5_NEON(uint32_t left, const uint32_t* const top) { + return Average3_NEON(left, top[0], top[1]); +} +static uint32_t Predictor6_NEON(uint32_t left, const uint32_t* const top) { + return Average2_NEON(left, top[-1]); +} +static uint32_t Predictor7_NEON(uint32_t left, const uint32_t* const top) { + return Average2_NEON(left, top[0]); +} +static uint32_t Predictor13_NEON(uint32_t left, const uint32_t* const top) { + return ClampedAddSubtractHalf_NEON(left, top[0], top[-1]); +} + +// Batch versions of those functions. + +// Predictor0: ARGB_BLACK. +static void PredictorAdd0_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const uint8x16_t black = vreinterpretq_u8_u32(vdupq_n_u32(ARGB_BLACK)); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t res = vaddq_u8(src, black); + STOREQ_U8_AS_U32P(&out[i], res); + } + VP8LPredictorsAdd_C[0](in + i, upper + i, num_pixels - i, out + i); +} + +// Predictor1: left. +static void PredictorAdd1_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const uint8x16_t zero = LOADQ_U32_AS_U8(0); + for (i = 0; i + 4 <= num_pixels; i += 4) { + // a | b | c | d + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + // 0 | a | b | c + const uint8x16_t shift0 = vextq_u8(zero, src, 12); + // a | a + b | b + c | c + d + const uint8x16_t sum0 = vaddq_u8(src, shift0); + // 0 | 0 | a | a + b + const uint8x16_t shift1 = vextq_u8(zero, sum0, 8); + // a | a + b | a + b + c | a + b + c + d + const uint8x16_t sum1 = vaddq_u8(sum0, shift1); + const uint8x16_t prev = LOADQ_U32_AS_U8(out[i - 1]); + const uint8x16_t res = vaddq_u8(sum1, prev); + STOREQ_U8_AS_U32P(&out[i], res); + } + VP8LPredictorsAdd_C[1](in + i, upper + i, num_pixels - i, out + i); +} + +// Macro that adds 32-bit integers from IN using mod 256 arithmetic +// per 8 bit channel. +#define GENERATE_PREDICTOR_1(X, IN) \ +static void PredictorAdd##X##_NEON(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); \ + const uint8x16_t other = LOADQ_U32P_AS_U8(&(IN)); \ + const uint8x16_t res = vaddq_u8(src, other); \ + STOREQ_U8_AS_U32P(&out[i], res); \ + } \ + VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ +} +// Predictor2: Top. +GENERATE_PREDICTOR_1(2, upper[i]) +// Predictor3: Top-right. +GENERATE_PREDICTOR_1(3, upper[i + 1]) +// Predictor4: Top-left. +GENERATE_PREDICTOR_1(4, upper[i - 1]) +#undef GENERATE_PREDICTOR_1 + +// Predictor5: average(average(left, TR), T) +#define DO_PRED5(LANE) do { \ + const uint8x16_t avgLTR = vhaddq_u8(L, TR); \ + const uint8x16_t avg = vhaddq_u8(avgLTR, T); \ + const uint8x16_t res = vaddq_u8(avg, src); \ + vst1q_lane_u32(&out[i + (LANE)], vreinterpretq_u32_u8(res), (LANE)); \ + L = ROTATE32_LEFT(res); \ +} while (0) + +static void PredictorAdd5_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i + 0]); + const uint8x16_t TR = LOADQ_U32P_AS_U8(&upper[i + 1]); + DO_PRED5(0); + DO_PRED5(1); + DO_PRED5(2); + DO_PRED5(3); + } + VP8LPredictorsAdd_C[5](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED5 + +#define DO_PRED67(LANE) do { \ + const uint8x16_t avg = vhaddq_u8(L, top); \ + const uint8x16_t res = vaddq_u8(avg, src); \ + vst1q_lane_u32(&out[i + (LANE)], vreinterpretq_u32_u8(res), (LANE)); \ + L = ROTATE32_LEFT(res); \ +} while (0) + +// Predictor6: average(left, TL) +static void PredictorAdd6_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t top = LOADQ_U32P_AS_U8(&upper[i - 1]); + DO_PRED67(0); + DO_PRED67(1); + DO_PRED67(2); + DO_PRED67(3); + } + VP8LPredictorsAdd_C[6](in + i, upper + i, num_pixels - i, out + i); +} + +// Predictor7: average(left, T) +static void PredictorAdd7_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t top = LOADQ_U32P_AS_U8(&upper[i]); + DO_PRED67(0); + DO_PRED67(1); + DO_PRED67(2); + DO_PRED67(3); + } + VP8LPredictorsAdd_C[7](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED67 + +#define GENERATE_PREDICTOR_2(X, IN) \ +static void PredictorAdd##X##_NEON(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); \ + const uint8x16_t Tother = LOADQ_U32P_AS_U8(&(IN)); \ + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); \ + const uint8x16_t avg = vhaddq_u8(T, Tother); \ + const uint8x16_t res = vaddq_u8(avg, src); \ + STOREQ_U8_AS_U32P(&out[i], res); \ + } \ + VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ +} +// Predictor8: average TL T. +GENERATE_PREDICTOR_2(8, upper[i - 1]) +// Predictor9: average T TR. +GENERATE_PREDICTOR_2(9, upper[i + 1]) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: average of (average of (L,TL), average of (T, TR)). +#define DO_PRED10(LANE) do { \ + const uint8x16_t avgLTL = vhaddq_u8(L, TL); \ + const uint8x16_t avg = vhaddq_u8(avgTTR, avgLTL); \ + const uint8x16_t res = vaddq_u8(avg, src); \ + vst1q_lane_u32(&out[i + (LANE)], vreinterpretq_u32_u8(res), (LANE)); \ + L = ROTATE32_LEFT(res); \ +} while (0) + +static void PredictorAdd10_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t TL = LOADQ_U32P_AS_U8(&upper[i - 1]); + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); + const uint8x16_t TR = LOADQ_U32P_AS_U8(&upper[i + 1]); + const uint8x16_t avgTTR = vhaddq_u8(T, TR); + DO_PRED10(0); + DO_PRED10(1); + DO_PRED10(2); + DO_PRED10(3); + } + VP8LPredictorsAdd_C[10](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED10 + +// Predictor11: select. +#define DO_PRED11(LANE) do { \ + const uint8x16_t sumLin = vaddq_u8(L, src); /* in + L */ \ + const uint8x16_t pLTL = vabdq_u8(L, TL); /* |L - TL| */ \ + const uint16x8_t sum_LTL = vpaddlq_u8(pLTL); \ + const uint32x4_t pa = vpaddlq_u16(sum_LTL); \ + const uint32x4_t mask = vcleq_u32(pa, pb); \ + const uint8x16_t res = vbslq_u8(vreinterpretq_u8_u32(mask), sumTin, sumLin); \ + vst1q_lane_u32(&out[i + (LANE)], vreinterpretq_u32_u8(res), (LANE)); \ + L = ROTATE32_LEFT(res); \ +} while (0) + +static void PredictorAdd11_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); + const uint8x16_t TL = LOADQ_U32P_AS_U8(&upper[i - 1]); + const uint8x16_t pTTL = vabdq_u8(T, TL); // |T - TL| + const uint16x8_t sum_TTL = vpaddlq_u8(pTTL); + const uint32x4_t pb = vpaddlq_u16(sum_TTL); + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t sumTin = vaddq_u8(T, src); // in + T + DO_PRED11(0); + DO_PRED11(1); + DO_PRED11(2); + DO_PRED11(3); + } + VP8LPredictorsAdd_C[11](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED11 + +// Predictor12: ClampedAddSubtractFull. +#define DO_PRED12(DIFF, LANE) do { \ + const uint8x8_t pred = \ + vqmovun_s16(vaddq_s16(vreinterpretq_s16_u16(L), (DIFF))); \ + const uint8x8_t res = \ + vadd_u8(pred, (LANE <= 1) ? vget_low_u8(src) : vget_high_u8(src)); \ + const uint16x8_t res16 = vmovl_u8(res); \ + vst1_lane_u32(&out[i + (LANE)], vreinterpret_u32_u8(res), (LANE) & 1); \ + /* rotate in the left predictor for next iteration */ \ + L = vextq_u16(res16, res16, 4); \ +} while (0) + +static void PredictorAdd12_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint16x8_t L = vmovl_u8(LOAD_U32_AS_U8(out[-1])); + for (i = 0; i + 4 <= num_pixels; i += 4) { + // load four pixels of source + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + // precompute the difference T - TL once for all, stored as s16 + const uint8x16_t TL = LOADQ_U32P_AS_U8(&upper[i - 1]); + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); + const int16x8_t diff_lo = + vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(T), vget_low_u8(TL))); + const int16x8_t diff_hi = + vreinterpretq_s16_u16(vsubl_u8(vget_high_u8(T), vget_high_u8(TL))); + // loop over the four reconstructed pixels + DO_PRED12(diff_lo, 0); + DO_PRED12(diff_lo, 1); + DO_PRED12(diff_hi, 2); + DO_PRED12(diff_hi, 3); + } + VP8LPredictorsAdd_C[12](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED12 + +// Predictor13: ClampedAddSubtractHalf +#define DO_PRED13(LANE, LOW_OR_HI) do { \ + const uint8x16_t avg = vhaddq_u8(L, T); \ + const uint8x16_t cmp = vcgtq_u8(TL, avg); \ + const uint8x16_t TL_1 = vaddq_u8(TL, cmp); \ + /* Compute half of the difference between avg and TL'. */ \ + const int8x8_t diff_avg = \ + vreinterpret_s8_u8(LOW_OR_HI(vhsubq_u8(avg, TL_1))); \ + /* Compute the sum with avg and saturate. */ \ + const int16x8_t avg_16 = vreinterpretq_s16_u16(vmovl_u8(LOW_OR_HI(avg))); \ + const uint8x8_t delta = vqmovun_s16(vaddw_s8(avg_16, diff_avg)); \ + const uint8x8_t res = vadd_u8(LOW_OR_HI(src), delta); \ + const uint8x16_t res2 = vcombine_u8(res, res); \ + vst1_lane_u32(&out[i + (LANE)], vreinterpret_u32_u8(res), (LANE) & 1); \ + L = ROTATE32_LEFT(res2); \ +} while (0) + +static void PredictorAdd13_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); + const uint8x16_t TL = LOADQ_U32P_AS_U8(&upper[i - 1]); + DO_PRED13(0, vget_low_u8); + DO_PRED13(1, vget_low_u8); + DO_PRED13(2, vget_high_u8); + DO_PRED13(3, vget_high_u8); + } + VP8LPredictorsAdd_C[13](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED13 + +#undef LOAD_U32_AS_U8 +#undef LOAD_U32P_AS_U8 +#undef LOADQ_U32_AS_U8 +#undef LOADQ_U32P_AS_U8 +#undef GET_U8_AS_U32 +#undef GETQ_U8_AS_U32 +#undef STOREQ_U8_AS_U32P +#undef ROTATE32_LEFT + //------------------------------------------------------------------------------ // Subtract-Green Transform @@ -171,28 +522,30 @@ static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb, } #endif // USE_VTBLQ -static void AddGreenToBlueAndRed(uint32_t* argb_data, int num_pixels) { - const uint32_t* const end = argb_data + (num_pixels & ~3); +static void AddGreenToBlueAndRed(const uint32_t* src, int num_pixels, + uint32_t* dst) { + const uint32_t* const end = src + (num_pixels & ~3); #ifdef USE_VTBLQ const uint8x16_t shuffle = vld1q_u8(kGreenShuffle); #else const uint8x8_t shuffle = vld1_u8(kGreenShuffle); #endif - for (; argb_data < end; argb_data += 4) { - const uint8x16_t argb = vld1q_u8((uint8_t*)argb_data); + for (; src < end; src += 4, dst += 4) { + const uint8x16_t argb = vld1q_u8((const uint8_t*)src); const uint8x16_t greens = DoGreenShuffle(argb, shuffle); - vst1q_u8((uint8_t*)argb_data, vaddq_u8(argb, greens)); + vst1q_u8((uint8_t*)dst, vaddq_u8(argb, greens)); } // fallthrough and finish off with plain-C - VP8LAddGreenToBlueAndRed_C(argb_data, num_pixels & 3); + VP8LAddGreenToBlueAndRed_C(src, num_pixels & 3, dst); } //------------------------------------------------------------------------------ // Color Transform static void TransformColorInverse(const VP8LMultipliers* const m, - uint32_t* argb_data, int num_pixels) { - // sign-extended multiplying constants, pre-shifted by 6. + const uint32_t* const src, int num_pixels, + uint32_t* dst) { +// sign-extended multiplying constants, pre-shifted by 6. #define CST(X) (((int16_t)(m->X << 8)) >> 6) const int16_t rb[8] = { CST(green_to_blue_), CST(green_to_red_), @@ -219,7 +572,7 @@ static void TransformColorInverse(const VP8LMultipliers* const m, const uint32x4_t mask_ag = vdupq_n_u32(0xff00ff00u); int i; for (i = 0; i + 4 <= num_pixels; i += 4) { - const uint8x16_t in = vld1q_u8((uint8_t*)(argb_data + i)); + const uint8x16_t in = vld1q_u8((const uint8_t*)(src + i)); const uint32x4_t a0g0 = vandq_u32(vreinterpretq_u32_u8(in), mask_ag); // 0 g 0 g const uint8x16_t greens = DoGreenShuffle(in, shuffle); @@ -240,10 +593,10 @@ static void TransformColorInverse(const VP8LMultipliers* const m, // 0 r' 0 b'' const uint16x8_t G = vshrq_n_u16(vreinterpretq_u16_s8(F), 8); const uint32x4_t out = vorrq_u32(vreinterpretq_u32_u16(G), a0g0); - vst1q_u32(argb_data + i, out); + vst1q_u32(dst + i, out); } // Fall-back to C-version for left-overs. - VP8LTransformColorInverse_C(m, argb_data + i, num_pixels - i); + VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i); } #undef USE_VTBLQ @@ -254,6 +607,26 @@ static void TransformColorInverse(const VP8LMultipliers* const m, extern void VP8LDspInitNEON(void); WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitNEON(void) { + VP8LPredictors[5] = Predictor5_NEON; + VP8LPredictors[6] = Predictor6_NEON; + VP8LPredictors[7] = Predictor7_NEON; + VP8LPredictors[13] = Predictor13_NEON; + + VP8LPredictorsAdd[0] = PredictorAdd0_NEON; + VP8LPredictorsAdd[1] = PredictorAdd1_NEON; + VP8LPredictorsAdd[2] = PredictorAdd2_NEON; + VP8LPredictorsAdd[3] = PredictorAdd3_NEON; + VP8LPredictorsAdd[4] = PredictorAdd4_NEON; + VP8LPredictorsAdd[5] = PredictorAdd5_NEON; + VP8LPredictorsAdd[6] = PredictorAdd6_NEON; + VP8LPredictorsAdd[7] = PredictorAdd7_NEON; + VP8LPredictorsAdd[8] = PredictorAdd8_NEON; + VP8LPredictorsAdd[9] = PredictorAdd9_NEON; + VP8LPredictorsAdd[10] = PredictorAdd10_NEON; + VP8LPredictorsAdd[11] = PredictorAdd11_NEON; + VP8LPredictorsAdd[12] = PredictorAdd12_NEON; + VP8LPredictorsAdd[13] = PredictorAdd13_NEON; + VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA; VP8LConvertBGRAToBGR = ConvertBGRAToBGR; VP8LConvertBGRAToRGB = ConvertBGRAToRGB; diff --git a/src/3rdparty/libwebp/src/dsp/lossless_sse2.c b/src/3rdparty/libwebp/src/dsp/lossless_sse2.c index 2d016c2911b7db88cbd93cb0a026be588c27b6d0..15aae93869cd0c77e98035d02ba53ab9cc4d9338 100644 --- a/src/3rdparty/libwebp/src/dsp/lossless_sse2.c +++ b/src/3rdparty/libwebp/src/dsp/lossless_sse2.c @@ -14,9 +14,12 @@ #include "./dsp.h" #if defined(WEBP_USE_SSE2) + +#include "./common_sse2.h" +#include "./lossless.h" +#include "./lossless_common.h" #include <assert.h> #include <emmintrin.h> -#include "./lossless.h" //------------------------------------------------------------------------------ // Predictor Transform @@ -75,25 +78,44 @@ static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) { return (pa_minus_pb <= 0) ? a : b; } -static WEBP_INLINE __m128i Average2_128i(uint32_t a0, uint32_t a1) { +static WEBP_INLINE void Average2_m128i(const __m128i* const a0, + const __m128i* const a1, + __m128i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m128i ones = _mm_set1_epi8(1); + const __m128i avg1 = _mm_avg_epu8(*a0, *a1); + const __m128i one = _mm_and_si128(_mm_xor_si128(*a0, *a1), ones); + *avg = _mm_sub_epi8(avg1, one); +} + +static WEBP_INLINE void Average2_uint32(const uint32_t a0, const uint32_t a1, + __m128i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m128i ones = _mm_set1_epi8(1); + const __m128i A0 = _mm_cvtsi32_si128(a0); + const __m128i A1 = _mm_cvtsi32_si128(a1); + const __m128i avg1 = _mm_avg_epu8(A0, A1); + const __m128i one = _mm_and_si128(_mm_xor_si128(A0, A1), ones); + *avg = _mm_sub_epi8(avg1, one); +} + +static WEBP_INLINE __m128i Average2_uint32_16(uint32_t a0, uint32_t a1) { const __m128i zero = _mm_setzero_si128(); const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a0), zero); const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero); const __m128i sum = _mm_add_epi16(A1, A0); - const __m128i avg = _mm_srli_epi16(sum, 1); - return avg; + return _mm_srli_epi16(sum, 1); } static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) { - const __m128i avg = Average2_128i(a0, a1); - const __m128i A2 = _mm_packus_epi16(avg, avg); - const uint32_t output = _mm_cvtsi128_si32(A2); - return output; + __m128i output; + Average2_uint32(a0, a1, &output); + return _mm_cvtsi128_si32(output); } static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) { const __m128i zero = _mm_setzero_si128(); - const __m128i avg1 = Average2_128i(a0, a2); + const __m128i avg1 = Average2_uint32_16(a0, a2); const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero); const __m128i sum = _mm_add_epi16(avg1, A1); const __m128i avg2 = _mm_srli_epi16(sum, 1); @@ -104,8 +126,8 @@ static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) { static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3) { - const __m128i avg1 = Average2_128i(a0, a1); - const __m128i avg2 = Average2_128i(a2, a3); + const __m128i avg1 = Average2_uint32_16(a0, a1); + const __m128i avg2 = Average2_uint32_16(a2, a3); const __m128i sum = _mm_add_epi16(avg2, avg1); const __m128i avg3 = _mm_srli_epi16(sum, 1); const __m128i A0 = _mm_packus_epi16(avg3, avg3); @@ -113,68 +135,289 @@ static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1, return output; } -static uint32_t Predictor5(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor5_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = Average3(left, top[0], top[1]); return pred; } -static uint32_t Predictor6(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor6_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = Average2(left, top[-1]); return pred; } -static uint32_t Predictor7(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor7_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = Average2(left, top[0]); return pred; } -static uint32_t Predictor8(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor8_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = Average2(top[-1], top[0]); (void)left; return pred; } -static uint32_t Predictor9(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor9_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = Average2(top[0], top[1]); (void)left; return pred; } -static uint32_t Predictor10(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor10_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = Average4(left, top[-1], top[0], top[1]); return pred; } -static uint32_t Predictor11(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor11_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = Select(top[0], left, top[-1]); return pred; } -static uint32_t Predictor12(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor12_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]); return pred; } -static uint32_t Predictor13(uint32_t left, const uint32_t* const top) { +static uint32_t Predictor13_SSE2(uint32_t left, const uint32_t* const top) { const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]); return pred; } +// Batch versions of those functions. + +// Predictor0: ARGB_BLACK. +static void PredictorAdd0_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i black = _mm_set1_epi32(ARGB_BLACK); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i res = _mm_add_epi8(src, black); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[0](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor1: left. +static void PredictorAdd1_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + __m128i prev = _mm_set1_epi32(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + // a | b | c | d + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + // 0 | a | b | c + const __m128i shift0 = _mm_slli_si128(src, 4); + // a | a + b | b + c | c + d + const __m128i sum0 = _mm_add_epi8(src, shift0); + // 0 | 0 | a | a + b + const __m128i shift1 = _mm_slli_si128(sum0, 8); + // a | a + b | a + b + c | a + b + c + d + const __m128i sum1 = _mm_add_epi8(sum0, shift1); + const __m128i res = _mm_add_epi8(sum1, prev); + _mm_storeu_si128((__m128i*)&out[i], res); + // replicate prev output on the four lanes + prev = _mm_shuffle_epi32(res, (3 << 0) | (3 << 2) | (3 << 4) | (3 << 6)); + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[1](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Macro that adds 32-bit integers from IN using mod 256 arithmetic +// per 8 bit channel. +#define GENERATE_PREDICTOR_1(X, IN) \ +static void PredictorAdd##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ + const __m128i other = _mm_loadu_si128((const __m128i*)&(IN)); \ + const __m128i res = _mm_add_epi8(src, other); \ + _mm_storeu_si128((__m128i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ +} + +// Predictor2: Top. +GENERATE_PREDICTOR_1(2, upper[i]) +// Predictor3: Top-right. +GENERATE_PREDICTOR_1(3, upper[i + 1]) +// Predictor4: Top-left. +GENERATE_PREDICTOR_1(4, upper[i - 1]) +#undef GENERATE_PREDICTOR_1 + +// Due to averages with integers, values cannot be accumulated in parallel for +// predictors 5 to 7. +GENERATE_PREDICTOR_ADD(Predictor5_SSE2, PredictorAdd5_SSE2) +GENERATE_PREDICTOR_ADD(Predictor6_SSE2, PredictorAdd6_SSE2) +GENERATE_PREDICTOR_ADD(Predictor7_SSE2, PredictorAdd7_SSE2) + +#define GENERATE_PREDICTOR_2(X, IN) \ +static void PredictorAdd##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const __m128i Tother = _mm_loadu_si128((const __m128i*)&(IN)); \ + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); \ + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ + __m128i avg, res; \ + Average2_m128i(&T, &Tother, &avg); \ + res = _mm_add_epi8(avg, src); \ + _mm_storeu_si128((__m128i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ +} +// Predictor8: average TL T. +GENERATE_PREDICTOR_2(8, upper[i - 1]) +// Predictor9: average T TR. +GENERATE_PREDICTOR_2(9, upper[i + 1]) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: average of (average of (L,TL), average of (T, TR)). +static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i, j; + __m128i L = _mm_cvtsi32_si128(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]); + __m128i avgTTR; + Average2_m128i(&T, &TR, &avgTTR); + for (j = 0; j < 4; ++j) { + __m128i avgLTL, avg; + Average2_m128i(&L, &TL, &avgLTL); + Average2_m128i(&avgTTR, &avgLTL, &avg); + L = _mm_add_epi8(avg, src); + out[i + j] = _mm_cvtsi128_si32(L); + // Rotate the pre-computed values for the next iteration. + avgTTR = _mm_srli_si128(avgTTR, 4); + TL = _mm_srli_si128(TL, 4); + src = _mm_srli_si128(src, 4); + } + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[10](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor11: select. +static void GetSumAbsDiff32(const __m128i* const A, const __m128i* const B, + __m128i* const out) { + // We can unpack with any value on the upper 32 bits, provided it's the same + // on both operands (to that their sum of abs diff is zero). Here we use *A. + const __m128i A_lo = _mm_unpacklo_epi32(*A, *A); + const __m128i B_lo = _mm_unpacklo_epi32(*B, *A); + const __m128i A_hi = _mm_unpackhi_epi32(*A, *A); + const __m128i B_hi = _mm_unpackhi_epi32(*B, *A); + const __m128i s_lo = _mm_sad_epu8(A_lo, B_lo); + const __m128i s_hi = _mm_sad_epu8(A_hi, B_hi); + *out = _mm_packs_epi32(s_lo, s_hi); +} + +static void PredictorAdd11_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i, j; + __m128i L = _mm_cvtsi32_si128(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + __m128i pa; + GetSumAbsDiff32(&T, &TL, &pa); // pa = sum |T-TL| + for (j = 0; j < 4; ++j) { + const __m128i L_lo = _mm_unpacklo_epi32(L, L); + const __m128i TL_lo = _mm_unpacklo_epi32(TL, L); + const __m128i pb = _mm_sad_epu8(L_lo, TL_lo); // pb = sum |L-TL| + const __m128i mask = _mm_cmpgt_epi32(pb, pa); + const __m128i A = _mm_and_si128(mask, L); + const __m128i B = _mm_andnot_si128(mask, T); + const __m128i pred = _mm_or_si128(A, B); // pred = (L > T)? L : T + L = _mm_add_epi8(src, pred); + out[i + j] = _mm_cvtsi128_si32(L); + // Shift the pre-computed value for the next iteration. + T = _mm_srli_si128(T, 4); + TL = _mm_srli_si128(TL, 4); + src = _mm_srli_si128(src, 4); + pa = _mm_srli_si128(pa, 4); + } + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[11](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor12: ClampedAddSubtractFull. +#define DO_PRED12(DIFF, LANE, OUT) \ +do { \ + const __m128i all = _mm_add_epi16(L, (DIFF)); \ + const __m128i alls = _mm_packus_epi16(all, all); \ + const __m128i res = _mm_add_epi8(src, alls); \ + out[i + (OUT)] = _mm_cvtsi128_si32(res); \ + L = _mm_unpacklo_epi8(res, zero); \ + /* Shift the pre-computed value for the next iteration.*/ \ + if (LANE == 0) (DIFF) = _mm_srli_si128((DIFF), 8); \ + src = _mm_srli_si128(src, 4); \ +} while (0) + +static void PredictorAdd12_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i zero = _mm_setzero_si128(); + const __m128i L8 = _mm_cvtsi32_si128(out[-1]); + __m128i L = _mm_unpacklo_epi8(L8, zero); + for (i = 0; i + 4 <= num_pixels; i += 4) { + // Load 4 pixels at a time. + __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i T_lo = _mm_unpacklo_epi8(T, zero); + const __m128i T_hi = _mm_unpackhi_epi8(T, zero); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); + const __m128i TL_hi = _mm_unpackhi_epi8(TL, zero); + __m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo); + __m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi); + DO_PRED12(diff_lo, 0, 0); + DO_PRED12(diff_lo, 1, 1); + DO_PRED12(diff_hi, 0, 2); + DO_PRED12(diff_hi, 1, 3); + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[12](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED12 + +// Due to averages with integers, values cannot be accumulated in parallel for +// predictors 13. +GENERATE_PREDICTOR_ADD(Predictor13_SSE2, PredictorAdd13_SSE2) + //------------------------------------------------------------------------------ // Subtract-Green Transform -static void AddGreenToBlueAndRed(uint32_t* argb_data, int num_pixels) { +static void AddGreenToBlueAndRed(const uint32_t* const src, int num_pixels, + uint32_t* dst) { int i; for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb + const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb const __m128i A = _mm_srli_epi16(in, 8); // 0 a 0 g const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // 0g0g const __m128i out = _mm_add_epi8(in, C); - _mm_storeu_si128((__m128i*)&argb_data[i], out); + _mm_storeu_si128((__m128i*)&dst[i], out); } // fallthrough and finish off with plain-C - VP8LAddGreenToBlueAndRed_C(argb_data + i, num_pixels - i); + if (i != num_pixels) { + VP8LAddGreenToBlueAndRed_C(src + i, num_pixels - i, dst + i); + } } //------------------------------------------------------------------------------ // Color Transform static void TransformColorInverse(const VP8LMultipliers* const m, - uint32_t* argb_data, int num_pixels) { - // sign-extended multiplying constants, pre-shifted by 5. + const uint32_t* const src, int num_pixels, + uint32_t* dst) { +// sign-extended multiplying constants, pre-shifted by 5. #define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend const __m128i mults_rb = _mm_set_epi16( CST(green_to_red_), CST(green_to_blue_), @@ -188,7 +431,7 @@ static void TransformColorInverse(const VP8LMultipliers* const m, const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks int i; for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb + const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb const __m128i A = _mm_and_si128(in, mask_ag); // a 0 g 0 const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // g0g0 @@ -200,15 +443,53 @@ static void TransformColorInverse(const VP8LMultipliers* const m, const __m128i I = _mm_add_epi8(H, F); // r' x b'' 0 const __m128i J = _mm_srli_epi16(I, 8); // 0 r' 0 b'' const __m128i out = _mm_or_si128(J, A); - _mm_storeu_si128((__m128i*)&argb_data[i], out); + _mm_storeu_si128((__m128i*)&dst[i], out); } // Fall-back to C-version for left-overs. - VP8LTransformColorInverse_C(m, argb_data + i, num_pixels - i); + if (i != num_pixels) { + VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i); + } } //------------------------------------------------------------------------------ // Color-space conversion functions +static void ConvertBGRAToRGB(const uint32_t* src, int num_pixels, + uint8_t* dst) { + const __m128i* in = (const __m128i*)src; + __m128i* out = (__m128i*)dst; + + while (num_pixels >= 32) { + // Load the BGRA buffers. + __m128i in0 = _mm_loadu_si128(in + 0); + __m128i in1 = _mm_loadu_si128(in + 1); + __m128i in2 = _mm_loadu_si128(in + 2); + __m128i in3 = _mm_loadu_si128(in + 3); + __m128i in4 = _mm_loadu_si128(in + 4); + __m128i in5 = _mm_loadu_si128(in + 5); + __m128i in6 = _mm_loadu_si128(in + 6); + __m128i in7 = _mm_loadu_si128(in + 7); + VP8L32bToPlanar(&in0, &in1, &in2, &in3); + VP8L32bToPlanar(&in4, &in5, &in6, &in7); + // At this points, in1/in5 contains red only, in2/in6 green only ... + // Pack the colors in 24b RGB. + VP8PlanarTo24b(&in1, &in5, &in2, &in6, &in3, &in7); + _mm_storeu_si128(out + 0, in1); + _mm_storeu_si128(out + 1, in5); + _mm_storeu_si128(out + 2, in2); + _mm_storeu_si128(out + 3, in6); + _mm_storeu_si128(out + 4, in3); + _mm_storeu_si128(out + 5, in7); + in += 8; + out += 6; + num_pixels -= 32; + } + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToRGB_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + static void ConvertBGRAToRGBA(const uint32_t* src, int num_pixels, uint8_t* dst) { const __m128i* in = (const __m128i*)src; @@ -233,7 +514,9 @@ static void ConvertBGRAToRGBA(const uint32_t* src, num_pixels -= 8; } // left-overs - VP8LConvertBGRAToRGBA_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + if (num_pixels > 0) { + VP8LConvertBGRAToRGBA_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } } static void ConvertBGRAToRGBA4444(const uint32_t* src, @@ -267,7 +550,9 @@ static void ConvertBGRAToRGBA4444(const uint32_t* src, num_pixels -= 8; } // left-overs - VP8LConvertBGRAToRGBA4444_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + if (num_pixels > 0) { + VP8LConvertBGRAToRGBA4444_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } } static void ConvertBGRAToRGB565(const uint32_t* src, @@ -306,7 +591,9 @@ static void ConvertBGRAToRGB565(const uint32_t* src, num_pixels -= 8; } // left-overs - VP8LConvertBGRAToRGB565_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + if (num_pixels > 0) { + VP8LConvertBGRAToRGB565_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } } static void ConvertBGRAToBGR(const uint32_t* src, @@ -337,7 +624,9 @@ static void ConvertBGRAToBGR(const uint32_t* src, num_pixels -= 8; } // left-overs - VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, dst); + if (num_pixels > 0) { + VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, dst); + } } //------------------------------------------------------------------------------ @@ -346,19 +635,35 @@ static void ConvertBGRAToBGR(const uint32_t* src, extern void VP8LDspInitSSE2(void); WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) { - VP8LPredictors[5] = Predictor5; - VP8LPredictors[6] = Predictor6; - VP8LPredictors[7] = Predictor7; - VP8LPredictors[8] = Predictor8; - VP8LPredictors[9] = Predictor9; - VP8LPredictors[10] = Predictor10; - VP8LPredictors[11] = Predictor11; - VP8LPredictors[12] = Predictor12; - VP8LPredictors[13] = Predictor13; + VP8LPredictors[5] = Predictor5_SSE2; + VP8LPredictors[6] = Predictor6_SSE2; + VP8LPredictors[7] = Predictor7_SSE2; + VP8LPredictors[8] = Predictor8_SSE2; + VP8LPredictors[9] = Predictor9_SSE2; + VP8LPredictors[10] = Predictor10_SSE2; + VP8LPredictors[11] = Predictor11_SSE2; + VP8LPredictors[12] = Predictor12_SSE2; + VP8LPredictors[13] = Predictor13_SSE2; + + VP8LPredictorsAdd[0] = PredictorAdd0_SSE2; + VP8LPredictorsAdd[1] = PredictorAdd1_SSE2; + VP8LPredictorsAdd[2] = PredictorAdd2_SSE2; + VP8LPredictorsAdd[3] = PredictorAdd3_SSE2; + VP8LPredictorsAdd[4] = PredictorAdd4_SSE2; + VP8LPredictorsAdd[5] = PredictorAdd5_SSE2; + VP8LPredictorsAdd[6] = PredictorAdd6_SSE2; + VP8LPredictorsAdd[7] = PredictorAdd7_SSE2; + VP8LPredictorsAdd[8] = PredictorAdd8_SSE2; + VP8LPredictorsAdd[9] = PredictorAdd9_SSE2; + VP8LPredictorsAdd[10] = PredictorAdd10_SSE2; + VP8LPredictorsAdd[11] = PredictorAdd11_SSE2; + VP8LPredictorsAdd[12] = PredictorAdd12_SSE2; + VP8LPredictorsAdd[13] = PredictorAdd13_SSE2; VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed; VP8LTransformColorInverse = TransformColorInverse; + VP8LConvertBGRAToRGB = ConvertBGRAToRGB; VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA; VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444; VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565; diff --git a/src/3rdparty/libwebp/src/dsp/msa_macro.h b/src/3rdparty/libwebp/src/dsp/msa_macro.h index 5c707f476ae6f030966f22b35fbff34da5b57ed1..d0e5f45e0141d1cc160494fcef31c4a9b3c80df3 100644 --- a/src/3rdparty/libwebp/src/dsp/msa_macro.h +++ b/src/3rdparty/libwebp/src/dsp/msa_macro.h @@ -23,12 +23,24 @@ #ifdef CLANG_BUILD #define ADDVI_H(a, b) __msa_addvi_h((v8i16)a, b) + #define ADDVI_W(a, b) __msa_addvi_w((v4i32)a, b) + #define SRAI_B(a, b) __msa_srai_b((v16i8)a, b) #define SRAI_H(a, b) __msa_srai_h((v8i16)a, b) #define SRAI_W(a, b) __msa_srai_w((v4i32)a, b) + #define SRLI_H(a, b) __msa_srli_h((v8i16)a, b) + #define SLLI_B(a, b) __msa_slli_b((v4i32)a, b) + #define ANDI_B(a, b) __msa_andi_b((v16u8)a, b) + #define ORI_B(a, b) __msa_ori_b((v16u8)a, b) #else #define ADDVI_H(a, b) (a + b) + #define ADDVI_W(a, b) (a + b) + #define SRAI_B(a, b) (a >> b) #define SRAI_H(a, b) (a >> b) #define SRAI_W(a, b) (a >> b) + #define SRLI_H(a, b) (a << b) + #define SLLI_B(a, b) (a << b) + #define ANDI_B(a, b) (a & b) + #define ORI_B(a, b) (a | b) #endif #define LD_B(RTYPE, psrc) *((RTYPE*)(psrc)) @@ -116,13 +128,13 @@ #define SH(val, pdst) MSA_STORE(val, pdst, msa_ush) MSA_STORE_FUNC(uint32_t, usw, msa_usw); #define SW(val, pdst) MSA_STORE(val, pdst, msa_usw) - #define SD(val, pdst) { \ + #define SD(val, pdst) do { \ uint8_t* const pdst_sd_m = (uint8_t*)(pdst); \ const uint32_t val0_m = (uint32_t)(val & 0x00000000FFFFFFFF); \ const uint32_t val1_m = (uint32_t)((val >> 32) & 0x00000000FFFFFFFF); \ SW(val0_m, pdst_sd_m); \ SW(val1_m, pdst_sd_m + 4); \ - } + } while (0) #endif // (__mips_isa_rev >= 6) /* Description : Load 4 words with stride @@ -133,34 +145,68 @@ * Load word in 'out2' from (psrc + 2 * stride) * Load word in 'out3' from (psrc + 3 * stride) */ -#define LW4(psrc, stride, out0, out1, out2, out3) { \ - const uint8_t* ptmp = (const uint8_t*)psrc; \ - out0 = LW(ptmp); \ - ptmp += stride; \ - out1 = LW(ptmp); \ - ptmp += stride; \ - out2 = LW(ptmp); \ - ptmp += stride; \ - out3 = LW(ptmp); \ -} +#define LW4(psrc, stride, out0, out1, out2, out3) do { \ + const uint8_t* ptmp = (const uint8_t*)psrc; \ + out0 = LW(ptmp); \ + ptmp += stride; \ + out1 = LW(ptmp); \ + ptmp += stride; \ + out2 = LW(ptmp); \ + ptmp += stride; \ + out3 = LW(ptmp); \ +} while (0) -/* Description : Store 4 words with stride +/* Description : Store words with stride * Arguments : Inputs - in0, in1, in2, in3, pdst, stride * Details : Store word from 'in0' to (pdst) * Store word from 'in1' to (pdst + stride) * Store word from 'in2' to (pdst + 2 * stride) * Store word from 'in3' to (pdst + 3 * stride) */ -#define SW4(in0, in1, in2, in3, pdst, stride) { \ - uint8_t* ptmp = (uint8_t*)pdst; \ - SW(in0, ptmp); \ - ptmp += stride; \ - SW(in1, ptmp); \ - ptmp += stride; \ - SW(in2, ptmp); \ - ptmp += stride; \ - SW(in3, ptmp); \ -} +#define SW4(in0, in1, in2, in3, pdst, stride) do { \ + uint8_t* ptmp = (uint8_t*)pdst; \ + SW(in0, ptmp); \ + ptmp += stride; \ + SW(in1, ptmp); \ + ptmp += stride; \ + SW(in2, ptmp); \ + ptmp += stride; \ + SW(in3, ptmp); \ +} while (0) + +#define SW3(in0, in1, in2, pdst, stride) do { \ + uint8_t* ptmp = (uint8_t*)pdst; \ + SW(in0, ptmp); \ + ptmp += stride; \ + SW(in1, ptmp); \ + ptmp += stride; \ + SW(in2, ptmp); \ +} while (0) + +#define SW2(in0, in1, pdst, stride) do { \ + uint8_t* ptmp = (uint8_t*)pdst; \ + SW(in0, ptmp); \ + ptmp += stride; \ + SW(in1, ptmp); \ +} while (0) + +/* Description : Store 4 double words with stride + * Arguments : Inputs - in0, in1, in2, in3, pdst, stride + * Details : Store double word from 'in0' to (pdst) + * Store double word from 'in1' to (pdst + stride) + * Store double word from 'in2' to (pdst + 2 * stride) + * Store double word from 'in3' to (pdst + 3 * stride) + */ +#define SD4(in0, in1, in2, in3, pdst, stride) do { \ + uint8_t* ptmp = (uint8_t*)pdst; \ + SD(in0, ptmp); \ + ptmp += stride; \ + SD(in1, ptmp); \ + ptmp += stride; \ + SD(in2, ptmp); \ + ptmp += stride; \ + SD(in3, ptmp); \ +} while (0) /* Description : Load vectors with 16 byte elements with stride * Arguments : Inputs - psrc, stride @@ -169,33 +215,169 @@ * Details : Load 16 byte elements in 'out0' from (psrc) * Load 16 byte elements in 'out1' from (psrc + stride) */ -#define LD_B2(RTYPE, psrc, stride, out0, out1) { \ - out0 = LD_B(RTYPE, psrc); \ - out1 = LD_B(RTYPE, psrc + stride); \ -} +#define LD_B2(RTYPE, psrc, stride, out0, out1) do { \ + out0 = LD_B(RTYPE, psrc); \ + out1 = LD_B(RTYPE, psrc + stride); \ +} while (0) #define LD_UB2(...) LD_B2(v16u8, __VA_ARGS__) #define LD_SB2(...) LD_B2(v16i8, __VA_ARGS__) -#define LD_B4(RTYPE, psrc, stride, out0, out1, out2, out3) { \ - LD_B2(RTYPE, psrc, stride, out0, out1); \ - LD_B2(RTYPE, psrc + 2 * stride , stride, out2, out3); \ -} +#define LD_B3(RTYPE, psrc, stride, out0, out1, out2) do { \ + LD_B2(RTYPE, psrc, stride, out0, out1); \ + out2 = LD_B(RTYPE, psrc + 2 * stride); \ +} while (0) +#define LD_UB3(...) LD_B3(v16u8, __VA_ARGS__) +#define LD_SB3(...) LD_B3(v16i8, __VA_ARGS__) + +#define LD_B4(RTYPE, psrc, stride, out0, out1, out2, out3) do { \ + LD_B2(RTYPE, psrc, stride, out0, out1); \ + LD_B2(RTYPE, psrc + 2 * stride , stride, out2, out3); \ +} while (0) #define LD_UB4(...) LD_B4(v16u8, __VA_ARGS__) #define LD_SB4(...) LD_B4(v16i8, __VA_ARGS__) +#define LD_B8(RTYPE, psrc, stride, \ + out0, out1, out2, out3, out4, out5, out6, out7) do { \ + LD_B4(RTYPE, psrc, stride, out0, out1, out2, out3); \ + LD_B4(RTYPE, psrc + 4 * stride, stride, out4, out5, out6, out7); \ +} while (0) +#define LD_UB8(...) LD_B8(v16u8, __VA_ARGS__) +#define LD_SB8(...) LD_B8(v16i8, __VA_ARGS__) + /* Description : Load vectors with 8 halfword elements with stride * Arguments : Inputs - psrc, stride * Outputs - out0, out1 * Details : Load 8 halfword elements in 'out0' from (psrc) * Load 8 halfword elements in 'out1' from (psrc + stride) */ -#define LD_H2(RTYPE, psrc, stride, out0, out1) { \ - out0 = LD_H(RTYPE, psrc); \ - out1 = LD_H(RTYPE, psrc + stride); \ -} +#define LD_H2(RTYPE, psrc, stride, out0, out1) do { \ + out0 = LD_H(RTYPE, psrc); \ + out1 = LD_H(RTYPE, psrc + stride); \ +} while (0) #define LD_UH2(...) LD_H2(v8u16, __VA_ARGS__) #define LD_SH2(...) LD_H2(v8i16, __VA_ARGS__) +/* Description : Load vectors with 4 word elements with stride + * Arguments : Inputs - psrc, stride + * Outputs - out0, out1, out2, out3 + * Details : Load 4 word elements in 'out0' from (psrc + 0 * stride) + * Load 4 word elements in 'out1' from (psrc + 1 * stride) + * Load 4 word elements in 'out2' from (psrc + 2 * stride) + * Load 4 word elements in 'out3' from (psrc + 3 * stride) + */ +#define LD_W2(RTYPE, psrc, stride, out0, out1) do { \ + out0 = LD_W(RTYPE, psrc); \ + out1 = LD_W(RTYPE, psrc + stride); \ +} while (0) +#define LD_UW2(...) LD_W2(v4u32, __VA_ARGS__) +#define LD_SW2(...) LD_W2(v4i32, __VA_ARGS__) + +#define LD_W3(RTYPE, psrc, stride, out0, out1, out2) do { \ + LD_W2(RTYPE, psrc, stride, out0, out1); \ + out2 = LD_W(RTYPE, psrc + 2 * stride); \ +} while (0) +#define LD_UW3(...) LD_W3(v4u32, __VA_ARGS__) +#define LD_SW3(...) LD_W3(v4i32, __VA_ARGS__) + +#define LD_W4(RTYPE, psrc, stride, out0, out1, out2, out3) do { \ + LD_W2(RTYPE, psrc, stride, out0, out1); \ + LD_W2(RTYPE, psrc + 2 * stride, stride, out2, out3); \ +} while (0) +#define LD_UW4(...) LD_W4(v4u32, __VA_ARGS__) +#define LD_SW4(...) LD_W4(v4i32, __VA_ARGS__) + +/* Description : Store vectors of 16 byte elements with stride + * Arguments : Inputs - in0, in1, pdst, stride + * Details : Store 16 byte elements from 'in0' to (pdst) + * Store 16 byte elements from 'in1' to (pdst + stride) + */ +#define ST_B2(RTYPE, in0, in1, pdst, stride) do { \ + ST_B(RTYPE, in0, pdst); \ + ST_B(RTYPE, in1, pdst + stride); \ +} while (0) +#define ST_UB2(...) ST_B2(v16u8, __VA_ARGS__) +#define ST_SB2(...) ST_B2(v16i8, __VA_ARGS__) + +#define ST_B4(RTYPE, in0, in1, in2, in3, pdst, stride) do { \ + ST_B2(RTYPE, in0, in1, pdst, stride); \ + ST_B2(RTYPE, in2, in3, pdst + 2 * stride, stride); \ +} while (0) +#define ST_UB4(...) ST_B4(v16u8, __VA_ARGS__) +#define ST_SB4(...) ST_B4(v16i8, __VA_ARGS__) + +#define ST_B8(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ + pdst, stride) do { \ + ST_B4(RTYPE, in0, in1, in2, in3, pdst, stride); \ + ST_B4(RTYPE, in4, in5, in6, in7, pdst + 4 * stride, stride); \ +} while (0) +#define ST_UB8(...) ST_B8(v16u8, __VA_ARGS__) + +/* Description : Store vectors of 4 word elements with stride + * Arguments : Inputs - in0, in1, in2, in3, pdst, stride + * Details : Store 4 word elements from 'in0' to (pdst + 0 * stride) + * Store 4 word elements from 'in1' to (pdst + 1 * stride) + * Store 4 word elements from 'in2' to (pdst + 2 * stride) + * Store 4 word elements from 'in3' to (pdst + 3 * stride) + */ +#define ST_W2(RTYPE, in0, in1, pdst, stride) do { \ + ST_W(RTYPE, in0, pdst); \ + ST_W(RTYPE, in1, pdst + stride); \ +} while (0) +#define ST_UW2(...) ST_W2(v4u32, __VA_ARGS__) +#define ST_SW2(...) ST_W2(v4i32, __VA_ARGS__) + +#define ST_W3(RTYPE, in0, in1, in2, pdst, stride) do { \ + ST_W2(RTYPE, in0, in1, pdst, stride); \ + ST_W(RTYPE, in2, pdst + 2 * stride); \ +} while (0) +#define ST_UW3(...) ST_W3(v4u32, __VA_ARGS__) +#define ST_SW3(...) ST_W3(v4i32, __VA_ARGS__) + +#define ST_W4(RTYPE, in0, in1, in2, in3, pdst, stride) do { \ + ST_W2(RTYPE, in0, in1, pdst, stride); \ + ST_W2(RTYPE, in2, in3, pdst + 2 * stride, stride); \ +} while (0) +#define ST_UW4(...) ST_W4(v4u32, __VA_ARGS__) +#define ST_SW4(...) ST_W4(v4i32, __VA_ARGS__) + +/* Description : Store vectors of 8 halfword elements with stride + * Arguments : Inputs - in0, in1, pdst, stride + * Details : Store 8 halfword elements from 'in0' to (pdst) + * Store 8 halfword elements from 'in1' to (pdst + stride) + */ +#define ST_H2(RTYPE, in0, in1, pdst, stride) do { \ + ST_H(RTYPE, in0, pdst); \ + ST_H(RTYPE, in1, pdst + stride); \ +} while (0) +#define ST_UH2(...) ST_H2(v8u16, __VA_ARGS__) +#define ST_SH2(...) ST_H2(v8i16, __VA_ARGS__) + +/* Description : Store 2x4 byte block to destination memory from input vector + * Arguments : Inputs - in, stidx, pdst, stride + * Details : Index 'stidx' halfword element from 'in' vector is copied to + * the GP register and stored to (pdst) + * Index 'stidx+1' halfword element from 'in' vector is copied to + * the GP register and stored to (pdst + stride) + * Index 'stidx+2' halfword element from 'in' vector is copied to + * the GP register and stored to (pdst + 2 * stride) + * Index 'stidx+3' halfword element from 'in' vector is copied to + * the GP register and stored to (pdst + 3 * stride) + */ +#define ST2x4_UB(in, stidx, pdst, stride) do { \ + uint8_t* pblk_2x4_m = (uint8_t*)pdst; \ + const uint16_t out0_m = __msa_copy_s_h((v8i16)in, stidx); \ + const uint16_t out1_m = __msa_copy_s_h((v8i16)in, stidx + 1); \ + const uint16_t out2_m = __msa_copy_s_h((v8i16)in, stidx + 2); \ + const uint16_t out3_m = __msa_copy_s_h((v8i16)in, stidx + 3); \ + SH(out0_m, pblk_2x4_m); \ + pblk_2x4_m += stride; \ + SH(out1_m, pblk_2x4_m); \ + pblk_2x4_m += stride; \ + SH(out2_m, pblk_2x4_m); \ + pblk_2x4_m += stride; \ + SH(out3_m, pblk_2x4_m); \ +} while (0) + /* Description : Store 4x4 byte block to destination memory from input vector * Arguments : Inputs - in0, in1, pdst, stride * Details : 'Idx0' word element from input vector 'in0' is copied to the @@ -207,14 +389,20 @@ * 'Idx3' word element from input vector 'in0' is copied to the * GP register and stored to (pdst + 3 * stride) */ -#define ST4x4_UB(in0, in1, idx0, idx1, idx2, idx3, pdst, stride) { \ - uint8_t* const pblk_4x4_m = (uint8_t*)pdst; \ - const uint32_t out0_m = __msa_copy_s_w((v4i32)in0, idx0); \ - const uint32_t out1_m = __msa_copy_s_w((v4i32)in0, idx1); \ - const uint32_t out2_m = __msa_copy_s_w((v4i32)in1, idx2); \ - const uint32_t out3_m = __msa_copy_s_w((v4i32)in1, idx3); \ - SW4(out0_m, out1_m, out2_m, out3_m, pblk_4x4_m, stride); \ -} +#define ST4x4_UB(in0, in1, idx0, idx1, idx2, idx3, pdst, stride) do { \ + uint8_t* const pblk_4x4_m = (uint8_t*)pdst; \ + const uint32_t out0_m = __msa_copy_s_w((v4i32)in0, idx0); \ + const uint32_t out1_m = __msa_copy_s_w((v4i32)in0, idx1); \ + const uint32_t out2_m = __msa_copy_s_w((v4i32)in1, idx2); \ + const uint32_t out3_m = __msa_copy_s_w((v4i32)in1, idx3); \ + SW4(out0_m, out1_m, out2_m, out3_m, pblk_4x4_m, stride); \ +} while (0) + +#define ST4x8_UB(in0, in1, pdst, stride) do { \ + uint8_t* const pblk_4x8 = (uint8_t*)pdst; \ + ST4x4_UB(in0, in0, 0, 1, 2, 3, pblk_4x8, stride); \ + ST4x4_UB(in1, in1, 0, 1, 2, 3, pblk_4x8 + 4 * stride, stride); \ +} while (0) /* Description : Immediate number of elements to slide * Arguments : Inputs - in0, in1, slide_val @@ -230,6 +418,30 @@ #define SLDI_SB(...) SLDI_B(v16i8, __VA_ARGS__) #define SLDI_SH(...) SLDI_B(v8i16, __VA_ARGS__) +/* Description : Shuffle byte vector elements as per mask vector + * Arguments : Inputs - in0, in1, in2, in3, mask0, mask1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Byte elements from 'in0' & 'in1' are copied selectively to + * 'out0' as per control vector 'mask0' + */ +#define VSHF_B(RTYPE, in0, in1, mask) \ + (RTYPE)__msa_vshf_b((v16i8)mask, (v16i8)in1, (v16i8)in0) + +#define VSHF_UB(...) VSHF_B(v16u8, __VA_ARGS__) +#define VSHF_SB(...) VSHF_B(v16i8, __VA_ARGS__) +#define VSHF_UH(...) VSHF_B(v8u16, __VA_ARGS__) +#define VSHF_SH(...) VSHF_B(v8i16, __VA_ARGS__) + +#define VSHF_B2(RTYPE, in0, in1, in2, in3, mask0, mask1, out0, out1) do { \ + out0 = VSHF_B(RTYPE, in0, in1, mask0); \ + out1 = VSHF_B(RTYPE, in2, in3, mask1); \ +} while (0) +#define VSHF_B2_UB(...) VSHF_B2(v16u8, __VA_ARGS__) +#define VSHF_B2_SB(...) VSHF_B2(v16i8, __VA_ARGS__) +#define VSHF_B2_UH(...) VSHF_B2(v8u16, __VA_ARGS__) +#define VSHF_B2_SH(...) VSHF_B2(v8i16, __VA_ARGS__) + /* Description : Shuffle halfword vector elements as per mask vector * Arguments : Inputs - in0, in1, in2, in3, mask0, mask1 * Outputs - out0, out1 @@ -237,44 +449,219 @@ * Details : halfword elements from 'in0' & 'in1' are copied selectively to * 'out0' as per control vector 'mask0' */ -#define VSHF_H2(RTYPE, in0, in1, in2, in3, mask0, mask1, out0, out1) { \ - out0 = (RTYPE)__msa_vshf_h((v8i16)mask0, (v8i16)in1, (v8i16)in0); \ - out1 = (RTYPE)__msa_vshf_h((v8i16)mask1, (v8i16)in3, (v8i16)in2); \ -} +#define VSHF_H2(RTYPE, in0, in1, in2, in3, mask0, mask1, out0, out1) do { \ + out0 = (RTYPE)__msa_vshf_h((v8i16)mask0, (v8i16)in1, (v8i16)in0); \ + out1 = (RTYPE)__msa_vshf_h((v8i16)mask1, (v8i16)in3, (v8i16)in2); \ +} while (0) #define VSHF_H2_UH(...) VSHF_H2(v8u16, __VA_ARGS__) #define VSHF_H2_SH(...) VSHF_H2(v8i16, __VA_ARGS__) +/* Description : Dot product of byte vector elements + * Arguments : Inputs - mult0, mult1, cnst0, cnst1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Signed byte elements from 'mult0' are multiplied with + * signed byte elements from 'cnst0' producing a result + * twice the size of input i.e. signed halfword. + * The multiplication result of adjacent odd-even elements + * are added together and written to the 'out0' vector +*/ +#define DOTP_SB2(RTYPE, mult0, mult1, cnst0, cnst1, out0, out1) do { \ + out0 = (RTYPE)__msa_dotp_s_h((v16i8)mult0, (v16i8)cnst0); \ + out1 = (RTYPE)__msa_dotp_s_h((v16i8)mult1, (v16i8)cnst1); \ +} while (0) +#define DOTP_SB2_SH(...) DOTP_SB2(v8i16, __VA_ARGS__) + +/* Description : Dot product of halfword vector elements + * Arguments : Inputs - mult0, mult1, cnst0, cnst1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Signed halfword elements from 'mult0' are multiplied with + * signed halfword elements from 'cnst0' producing a result + * twice the size of input i.e. signed word. + * The multiplication result of adjacent odd-even elements + * are added together and written to the 'out0' vector + */ +#define DOTP_SH2(RTYPE, mult0, mult1, cnst0, cnst1, out0, out1) do { \ + out0 = (RTYPE)__msa_dotp_s_w((v8i16)mult0, (v8i16)cnst0); \ + out1 = (RTYPE)__msa_dotp_s_w((v8i16)mult1, (v8i16)cnst1); \ +} while (0) +#define DOTP_SH2_SW(...) DOTP_SH2(v4i32, __VA_ARGS__) + +/* Description : Dot product of unsigned word vector elements + * Arguments : Inputs - mult0, mult1, cnst0, cnst1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Unsigned word elements from 'mult0' are multiplied with + * unsigned word elements from 'cnst0' producing a result + * twice the size of input i.e. unsigned double word. + * The multiplication result of adjacent odd-even elements + * are added together and written to the 'out0' vector + */ +#define DOTP_UW2(RTYPE, mult0, mult1, cnst0, cnst1, out0, out1) do { \ + out0 = (RTYPE)__msa_dotp_u_d((v4u32)mult0, (v4u32)cnst0); \ + out1 = (RTYPE)__msa_dotp_u_d((v4u32)mult1, (v4u32)cnst1); \ +} while (0) +#define DOTP_UW2_UD(...) DOTP_UW2(v2u64, __VA_ARGS__) + +/* Description : Dot product & addition of halfword vector elements + * Arguments : Inputs - mult0, mult1, cnst0, cnst1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Signed halfword elements from 'mult0' are multiplied with + * signed halfword elements from 'cnst0' producing a result + * twice the size of input i.e. signed word. + * The multiplication result of adjacent odd-even elements + * are added to the 'out0' vector + */ +#define DPADD_SH2(RTYPE, mult0, mult1, cnst0, cnst1, out0, out1) do { \ + out0 = (RTYPE)__msa_dpadd_s_w((v4i32)out0, (v8i16)mult0, (v8i16)cnst0); \ + out1 = (RTYPE)__msa_dpadd_s_w((v4i32)out1, (v8i16)mult1, (v8i16)cnst1); \ +} while (0) +#define DPADD_SH2_SW(...) DPADD_SH2(v4i32, __VA_ARGS__) + /* Description : Clips all signed halfword elements of input vector * between 0 & 255 * Arguments : Input/output - val * Return Type - signed halfword */ -#define CLIP_SH_0_255(val) { \ +#define CLIP_SH_0_255(val) do { \ const v8i16 max_m = __msa_ldi_h(255); \ val = __msa_maxi_s_h((v8i16)val, 0); \ val = __msa_min_s_h(max_m, (v8i16)val); \ -} -#define CLIP_SH2_0_255(in0, in1) { \ - CLIP_SH_0_255(in0); \ - CLIP_SH_0_255(in1); \ -} +} while (0) + +#define CLIP_SH2_0_255(in0, in1) do { \ + CLIP_SH_0_255(in0); \ + CLIP_SH_0_255(in1); \ +} while (0) + +#define CLIP_SH4_0_255(in0, in1, in2, in3) do { \ + CLIP_SH2_0_255(in0, in1); \ + CLIP_SH2_0_255(in2, in3); \ +} while (0) + +/* Description : Clips all unsigned halfword elements of input vector + * between 0 & 255 + * Arguments : Input - in + * Output - out_m + * Return Type - unsigned halfword + */ +#define CLIP_UH_0_255(in) do { \ + const v8u16 max_m = (v8u16)__msa_ldi_h(255); \ + in = __msa_maxi_u_h((v8u16) in, 0); \ + in = __msa_min_u_h((v8u16) max_m, (v8u16) in); \ +} while (0) + +#define CLIP_UH2_0_255(in0, in1) do { \ + CLIP_UH_0_255(in0); \ + CLIP_UH_0_255(in1); \ +} while (0) /* Description : Clips all signed word elements of input vector * between 0 & 255 * Arguments : Input/output - val * Return Type - signed word */ -#define CLIP_SW_0_255(val) { \ +#define CLIP_SW_0_255(val) do { \ const v4i32 max_m = __msa_ldi_w(255); \ val = __msa_maxi_s_w((v4i32)val, 0); \ val = __msa_min_s_w(max_m, (v4i32)val); \ +} while (0) + +#define CLIP_SW4_0_255(in0, in1, in2, in3) do { \ + CLIP_SW_0_255(in0); \ + CLIP_SW_0_255(in1); \ + CLIP_SW_0_255(in2); \ + CLIP_SW_0_255(in3); \ +} while (0) + +/* Description : Horizontal addition of 4 signed word elements of input vector + * Arguments : Input - in (signed word vector) + * Output - sum_m (i32 sum) + * Return Type - signed word (GP) + * Details : 4 signed word elements of 'in' vector are added together and + * the resulting integer sum is returned + */ +static WEBP_INLINE int32_t func_hadd_sw_s32(v4i32 in) { + const v2i64 res0_m = __msa_hadd_s_d((v4i32)in, (v4i32)in); + const v2i64 res1_m = __msa_splati_d(res0_m, 1); + const v2i64 out = res0_m + res1_m; + int32_t sum_m = __msa_copy_s_w((v4i32)out, 0); + return sum_m; } -#define CLIP_SW4_0_255(in0, in1, in2, in3) { \ - CLIP_SW_0_255(in0); \ - CLIP_SW_0_255(in1); \ - CLIP_SW_0_255(in2); \ - CLIP_SW_0_255(in3); \ +#define HADD_SW_S32(in) func_hadd_sw_s32(in) + +/* Description : Horizontal addition of 8 signed halfword elements + * Arguments : Input - in (signed halfword vector) + * Output - sum_m (s32 sum) + * Return Type - signed word + * Details : 8 signed halfword elements of input vector are added + * together and the resulting integer sum is returned + */ +static WEBP_INLINE int32_t func_hadd_sh_s32(v8i16 in) { + const v4i32 res = __msa_hadd_s_w(in, in); + const v2i64 res0 = __msa_hadd_s_d(res, res); + const v2i64 res1 = __msa_splati_d(res0, 1); + const v2i64 res2 = res0 + res1; + const int32_t sum_m = __msa_copy_s_w((v4i32)res2, 0); + return sum_m; +} +#define HADD_SH_S32(in) func_hadd_sh_s32(in) + +/* Description : Horizontal addition of 8 unsigned halfword elements + * Arguments : Input - in (unsigned halfword vector) + * Output - sum_m (u32 sum) + * Return Type - unsigned word + * Details : 8 unsigned halfword elements of input vector are added + * together and the resulting integer sum is returned + */ +static WEBP_INLINE uint32_t func_hadd_uh_u32(v8u16 in) { + uint32_t sum_m; + const v4u32 res_m = __msa_hadd_u_w(in, in); + v2u64 res0_m = __msa_hadd_u_d(res_m, res_m); + v2u64 res1_m = (v2u64)__msa_splati_d((v2i64)res0_m, 1); + res0_m = res0_m + res1_m; + sum_m = __msa_copy_s_w((v4i32)res0_m, 0); + return sum_m; } +#define HADD_UH_U32(in) func_hadd_uh_u32(in) + +/* Description : Horizontal addition of signed half word vector elements + Arguments : Inputs - in0, in1 + Outputs - out0, out1 + Return Type - as per RTYPE + Details : Each signed odd half word element from 'in0' is added to + even signed half word element from 'in0' (pairwise) and the + halfword result is written in 'out0' +*/ +#define HADD_SH2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_hadd_s_w((v8i16)in0, (v8i16)in0); \ + out1 = (RTYPE)__msa_hadd_s_w((v8i16)in1, (v8i16)in1); \ +} while (0) +#define HADD_SH2_SW(...) HADD_SH2(v4i32, __VA_ARGS__) + +#define HADD_SH4(RTYPE, in0, in1, in2, in3, out0, out1, out2, out3) do { \ + HADD_SH2(RTYPE, in0, in1, out0, out1); \ + HADD_SH2(RTYPE, in2, in3, out2, out3); \ +} while (0) +#define HADD_SH4_SW(...) HADD_SH4(v4i32, __VA_ARGS__) + +/* Description : Horizontal subtraction of unsigned byte vector elements + * Arguments : Inputs - in0, in1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Each unsigned odd byte element from 'in0' is subtracted from + * even unsigned byte element from 'in0' (pairwise) and the + * halfword result is written to 'out0' + */ +#define HSUB_UB2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_hsub_u_h((v16u8)in0, (v16u8)in0); \ + out1 = (RTYPE)__msa_hsub_u_h((v16u8)in1, (v16u8)in1); \ +} while (0) +#define HSUB_UB2_UH(...) HSUB_UB2(v8u16, __VA_ARGS__) +#define HSUB_UB2_SH(...) HSUB_UB2(v8i16, __VA_ARGS__) +#define HSUB_UB2_SW(...) HSUB_UB2(v4i32, __VA_ARGS__) /* Description : Set element n input vector to GPR value * Arguments : Inputs - in0, in1, in2, in3 @@ -282,23 +669,188 @@ * Return Type - as per RTYPE * Details : Set element 0 in vector 'out' to value specified in 'in0' */ -#define INSERT_W2(RTYPE, in0, in1, out) { \ +#define INSERT_W2(RTYPE, in0, in1, out) do { \ out = (RTYPE)__msa_insert_w((v4i32)out, 0, in0); \ out = (RTYPE)__msa_insert_w((v4i32)out, 1, in1); \ -} +} while (0) #define INSERT_W2_UB(...) INSERT_W2(v16u8, __VA_ARGS__) #define INSERT_W2_SB(...) INSERT_W2(v16i8, __VA_ARGS__) -#define INSERT_W4(RTYPE, in0, in1, in2, in3, out) { \ - out = (RTYPE)__msa_insert_w((v4i32)out, 0, in0); \ - out = (RTYPE)__msa_insert_w((v4i32)out, 1, in1); \ - out = (RTYPE)__msa_insert_w((v4i32)out, 2, in2); \ - out = (RTYPE)__msa_insert_w((v4i32)out, 3, in3); \ -} +#define INSERT_W4(RTYPE, in0, in1, in2, in3, out) do { \ + out = (RTYPE)__msa_insert_w((v4i32)out, 0, in0); \ + out = (RTYPE)__msa_insert_w((v4i32)out, 1, in1); \ + out = (RTYPE)__msa_insert_w((v4i32)out, 2, in2); \ + out = (RTYPE)__msa_insert_w((v4i32)out, 3, in3); \ +} while (0) #define INSERT_W4_UB(...) INSERT_W4(v16u8, __VA_ARGS__) #define INSERT_W4_SB(...) INSERT_W4(v16i8, __VA_ARGS__) #define INSERT_W4_SW(...) INSERT_W4(v4i32, __VA_ARGS__) +/* Description : Set element n of double word input vector to GPR value + * Arguments : Inputs - in0, in1 + * Output - out + * Return Type - as per RTYPE + * Details : Set element 0 in vector 'out' to GPR value specified in 'in0' + * Set element 1 in vector 'out' to GPR value specified in 'in1' + */ +#define INSERT_D2(RTYPE, in0, in1, out) do { \ + out = (RTYPE)__msa_insert_d((v2i64)out, 0, in0); \ + out = (RTYPE)__msa_insert_d((v2i64)out, 1, in1); \ +} while (0) +#define INSERT_D2_UB(...) INSERT_D2(v16u8, __VA_ARGS__) +#define INSERT_D2_SB(...) INSERT_D2(v16i8, __VA_ARGS__) + +/* Description : Interleave even byte elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even byte elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVEV_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_b((v16i8)in1, (v16i8)in0); \ + out1 = (RTYPE)__msa_ilvev_b((v16i8)in3, (v16i8)in2); \ +} while (0) +#define ILVEV_B2_UB(...) ILVEV_B2(v16u8, __VA_ARGS__) +#define ILVEV_B2_SB(...) ILVEV_B2(v16i8, __VA_ARGS__) +#define ILVEV_B2_UH(...) ILVEV_B2(v8u16, __VA_ARGS__) +#define ILVEV_B2_SH(...) ILVEV_B2(v8i16, __VA_ARGS__) +#define ILVEV_B2_SD(...) ILVEV_B2(v2i64, __VA_ARGS__) + +/* Description : Interleave odd byte elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Odd byte elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVOD_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvod_b((v16i8)in1, (v16i8)in0); \ + out1 = (RTYPE)__msa_ilvod_b((v16i8)in3, (v16i8)in2); \ +} while (0) +#define ILVOD_B2_UB(...) ILVOD_B2(v16u8, __VA_ARGS__) +#define ILVOD_B2_SB(...) ILVOD_B2(v16i8, __VA_ARGS__) +#define ILVOD_B2_UH(...) ILVOD_B2(v8u16, __VA_ARGS__) +#define ILVOD_B2_SH(...) ILVOD_B2(v8i16, __VA_ARGS__) +#define ILVOD_B2_SD(...) ILVOD_B2(v2i64, __VA_ARGS__) + +/* Description : Interleave even halfword elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even halfword elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVEV_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_h((v8i16)in1, (v8i16)in0); \ + out1 = (RTYPE)__msa_ilvev_h((v8i16)in3, (v8i16)in2); \ +} while (0) +#define ILVEV_H2_UB(...) ILVEV_H2(v16u8, __VA_ARGS__) +#define ILVEV_H2_UH(...) ILVEV_H2(v8u16, __VA_ARGS__) +#define ILVEV_H2_SH(...) ILVEV_H2(v8i16, __VA_ARGS__) +#define ILVEV_H2_SW(...) ILVEV_H2(v4i32, __VA_ARGS__) + +/* Description : Interleave odd halfword elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Odd halfword elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVOD_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvod_h((v8i16)in1, (v8i16)in0); \ + out1 = (RTYPE)__msa_ilvod_h((v8i16)in3, (v8i16)in2); \ +} while (0) +#define ILVOD_H2_UB(...) ILVOD_H2(v16u8, __VA_ARGS__) +#define ILVOD_H2_UH(...) ILVOD_H2(v8u16, __VA_ARGS__) +#define ILVOD_H2_SH(...) ILVOD_H2(v8i16, __VA_ARGS__) +#define ILVOD_H2_SW(...) ILVOD_H2(v4i32, __VA_ARGS__) + +/* Description : Interleave even word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even word elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVEV_W2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_w((v4i32)in1, (v4i32)in0); \ + out1 = (RTYPE)__msa_ilvev_w((v4i32)in3, (v4i32)in2); \ +} while (0) +#define ILVEV_W2_UB(...) ILVEV_W2(v16u8, __VA_ARGS__) +#define ILVEV_W2_SB(...) ILVEV_W2(v16i8, __VA_ARGS__) +#define ILVEV_W2_UH(...) ILVEV_W2(v8u16, __VA_ARGS__) +#define ILVEV_W2_SD(...) ILVEV_W2(v2i64, __VA_ARGS__) + +/* Description : Interleave even-odd word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even word elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + * Odd word elements of 'in2' and 'in3' are interleaved + * and written to 'out1' + */ +#define ILVEVOD_W2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_w((v4i32)in1, (v4i32)in0); \ + out1 = (RTYPE)__msa_ilvod_w((v4i32)in3, (v4i32)in2); \ +} while (0) +#define ILVEVOD_W2_UB(...) ILVEVOD_W2(v16u8, __VA_ARGS__) +#define ILVEVOD_W2_UH(...) ILVEVOD_W2(v8u16, __VA_ARGS__) +#define ILVEVOD_W2_SH(...) ILVEVOD_W2(v8i16, __VA_ARGS__) +#define ILVEVOD_W2_SW(...) ILVEVOD_W2(v4i32, __VA_ARGS__) + +/* Description : Interleave even-odd half-word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even half-word elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + * Odd half-word elements of 'in2' and 'in3' are interleaved + * and written to 'out1' + */ +#define ILVEVOD_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_h((v8i16)in1, (v8i16)in0); \ + out1 = (RTYPE)__msa_ilvod_h((v8i16)in3, (v8i16)in2); \ +} while (0) +#define ILVEVOD_H2_UB(...) ILVEVOD_H2(v16u8, __VA_ARGS__) +#define ILVEVOD_H2_UH(...) ILVEVOD_H2(v8u16, __VA_ARGS__) +#define ILVEVOD_H2_SH(...) ILVEVOD_H2(v8i16, __VA_ARGS__) +#define ILVEVOD_H2_SW(...) ILVEVOD_H2(v4i32, __VA_ARGS__) + +/* Description : Interleave even double word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even double word elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVEV_D2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_d((v2i64)in1, (v2i64)in0); \ + out1 = (RTYPE)__msa_ilvev_d((v2i64)in3, (v2i64)in2); \ +} while (0) +#define ILVEV_D2_UB(...) ILVEV_D2(v16u8, __VA_ARGS__) +#define ILVEV_D2_SB(...) ILVEV_D2(v16i8, __VA_ARGS__) +#define ILVEV_D2_SW(...) ILVEV_D2(v4i32, __VA_ARGS__) +#define ILVEV_D2_SD(...) ILVEV_D2(v2i64, __VA_ARGS__) + +/* Description : Interleave left half of byte elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Left half of byte elements of 'in0' and 'in1' are interleaved + * and written to 'out0'. + */ +#define ILVL_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvl_b((v16i8)in0, (v16i8)in1); \ + out1 = (RTYPE)__msa_ilvl_b((v16i8)in2, (v16i8)in3); \ +} while (0) +#define ILVL_B2_UB(...) ILVL_B2(v16u8, __VA_ARGS__) +#define ILVL_B2_SB(...) ILVL_B2(v16i8, __VA_ARGS__) +#define ILVL_B2_UH(...) ILVL_B2(v8u16, __VA_ARGS__) +#define ILVL_B2_SH(...) ILVL_B2(v8i16, __VA_ARGS__) +#define ILVL_B2_SW(...) ILVL_B2(v4i32, __VA_ARGS__) + /* Description : Interleave right half of byte elements from vectors * Arguments : Inputs - in0, in1, in2, in3 * Outputs - out0, out1 @@ -306,10 +858,10 @@ * Details : Right half of byte elements of 'in0' and 'in1' are interleaved * and written to out0. */ -#define ILVR_B2(RTYPE, in0, in1, in2, in3, out0, out1) { \ - out0 = (RTYPE)__msa_ilvr_b((v16i8)in0, (v16i8)in1); \ - out1 = (RTYPE)__msa_ilvr_b((v16i8)in2, (v16i8)in3); \ -} +#define ILVR_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_b((v16i8)in0, (v16i8)in1); \ + out1 = (RTYPE)__msa_ilvr_b((v16i8)in2, (v16i8)in3); \ +} while (0) #define ILVR_B2_UB(...) ILVR_B2(v16u8, __VA_ARGS__) #define ILVR_B2_SB(...) ILVR_B2(v16i8, __VA_ARGS__) #define ILVR_B2_UH(...) ILVR_B2(v8u16, __VA_ARGS__) @@ -317,10 +869,10 @@ #define ILVR_B2_SW(...) ILVR_B2(v4i32, __VA_ARGS__) #define ILVR_B4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ - out0, out1, out2, out3) { \ + out0, out1, out2, out3) do { \ ILVR_B2(RTYPE, in0, in1, in2, in3, out0, out1); \ ILVR_B2(RTYPE, in4, in5, in6, in7, out2, out3); \ -} +} while (0) #define ILVR_B4_UB(...) ILVR_B4(v16u8, __VA_ARGS__) #define ILVR_B4_SB(...) ILVR_B4(v16i8, __VA_ARGS__) #define ILVR_B4_UH(...) ILVR_B4(v8u16, __VA_ARGS__) @@ -334,19 +886,19 @@ * Details : Right half of halfword elements of 'in0' and 'in1' are * interleaved and written to 'out0'. */ -#define ILVR_H2(RTYPE, in0, in1, in2, in3, out0, out1) { \ - out0 = (RTYPE)__msa_ilvr_h((v8i16)in0, (v8i16)in1); \ - out1 = (RTYPE)__msa_ilvr_h((v8i16)in2, (v8i16)in3); \ -} +#define ILVR_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_h((v8i16)in0, (v8i16)in1); \ + out1 = (RTYPE)__msa_ilvr_h((v8i16)in2, (v8i16)in3); \ +} while (0) #define ILVR_H2_UB(...) ILVR_H2(v16u8, __VA_ARGS__) #define ILVR_H2_SH(...) ILVR_H2(v8i16, __VA_ARGS__) #define ILVR_H2_SW(...) ILVR_H2(v4i32, __VA_ARGS__) #define ILVR_H4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ - out0, out1, out2, out3) { \ + out0, out1, out2, out3) do { \ ILVR_H2(RTYPE, in0, in1, in2, in3, out0, out1); \ ILVR_H2(RTYPE, in4, in5, in6, in7, out2, out3); \ -} +} while (0) #define ILVR_H4_UB(...) ILVR_H4(v16u8, __VA_ARGS__) #define ILVR_H4_SH(...) ILVR_H4(v8i16, __VA_ARGS__) #define ILVR_H4_SW(...) ILVR_H4(v4i32, __VA_ARGS__) @@ -358,31 +910,57 @@ * Details : Right half of double word elements of 'in0' and 'in1' are * interleaved and written to 'out0'. */ -#define ILVR_D2(RTYPE, in0, in1, in2, in3, out0, out1) { \ - out0 = (RTYPE)__msa_ilvr_d((v2i64)in0, (v2i64)in1); \ - out1 = (RTYPE)__msa_ilvr_d((v2i64)in2, (v2i64)in3); \ -} +#define ILVR_D2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_d((v2i64)in0, (v2i64)in1); \ + out1 = (RTYPE)__msa_ilvr_d((v2i64)in2, (v2i64)in3); \ +} while (0) #define ILVR_D2_UB(...) ILVR_D2(v16u8, __VA_ARGS__) #define ILVR_D2_SB(...) ILVR_D2(v16i8, __VA_ARGS__) #define ILVR_D2_SH(...) ILVR_D2(v8i16, __VA_ARGS__) -#define ILVRL_H2(RTYPE, in0, in1, out0, out1) { \ +#define ILVR_D4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + ILVR_D2(RTYPE, in0, in1, in2, in3, out0, out1); \ + ILVR_D2(RTYPE, in4, in5, in6, in7, out2, out3); \ +} while (0) +#define ILVR_D4_SB(...) ILVR_D4(v16i8, __VA_ARGS__) +#define ILVR_D4_UB(...) ILVR_D4(v16u8, __VA_ARGS__) + +/* Description : Interleave both left and right half of input vectors + * Arguments : Inputs - in0, in1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Right half of byte elements from 'in0' and 'in1' are + * interleaved and written to 'out0' + */ +#define ILVRL_B2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_b((v16i8)in0, (v16i8)in1); \ + out1 = (RTYPE)__msa_ilvl_b((v16i8)in0, (v16i8)in1); \ +} while (0) +#define ILVRL_B2_UB(...) ILVRL_B2(v16u8, __VA_ARGS__) +#define ILVRL_B2_SB(...) ILVRL_B2(v16i8, __VA_ARGS__) +#define ILVRL_B2_UH(...) ILVRL_B2(v8u16, __VA_ARGS__) +#define ILVRL_B2_SH(...) ILVRL_B2(v8i16, __VA_ARGS__) +#define ILVRL_B2_SW(...) ILVRL_B2(v4i32, __VA_ARGS__) + +#define ILVRL_H2(RTYPE, in0, in1, out0, out1) do { \ out0 = (RTYPE)__msa_ilvr_h((v8i16)in0, (v8i16)in1); \ out1 = (RTYPE)__msa_ilvl_h((v8i16)in0, (v8i16)in1); \ -} +} while (0) #define ILVRL_H2_UB(...) ILVRL_H2(v16u8, __VA_ARGS__) #define ILVRL_H2_SB(...) ILVRL_H2(v16i8, __VA_ARGS__) #define ILVRL_H2_SH(...) ILVRL_H2(v8i16, __VA_ARGS__) #define ILVRL_H2_SW(...) ILVRL_H2(v4i32, __VA_ARGS__) #define ILVRL_H2_UW(...) ILVRL_H2(v4u32, __VA_ARGS__) -#define ILVRL_W2(RTYPE, in0, in1, out0, out1) { \ +#define ILVRL_W2(RTYPE, in0, in1, out0, out1) do { \ out0 = (RTYPE)__msa_ilvr_w((v4i32)in0, (v4i32)in1); \ out1 = (RTYPE)__msa_ilvl_w((v4i32)in0, (v4i32)in1); \ -} +} while (0) #define ILVRL_W2_UB(...) ILVRL_W2(v16u8, __VA_ARGS__) #define ILVRL_W2_SH(...) ILVRL_W2(v8i16, __VA_ARGS__) #define ILVRL_W2_SW(...) ILVRL_W2(v4i32, __VA_ARGS__) +#define ILVRL_W2_UW(...) ILVRL_W2(v4u32, __VA_ARGS__) /* Description : Pack even byte elements of vector pairs * Arguments : Inputs - in0, in1, in2, in3 @@ -392,15 +970,76 @@ * 'out0' & even byte elements of 'in1' are copied to the right * half of 'out0'. */ -#define PCKEV_B2(RTYPE, in0, in1, in2, in3, out0, out1) { \ - out0 = (RTYPE)__msa_pckev_b((v16i8)in0, (v16i8)in1); \ - out1 = (RTYPE)__msa_pckev_b((v16i8)in2, (v16i8)in3); \ -} +#define PCKEV_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_pckev_b((v16i8)in0, (v16i8)in1); \ + out1 = (RTYPE)__msa_pckev_b((v16i8)in2, (v16i8)in3); \ +} while (0) #define PCKEV_B2_SB(...) PCKEV_B2(v16i8, __VA_ARGS__) #define PCKEV_B2_UB(...) PCKEV_B2(v16u8, __VA_ARGS__) #define PCKEV_B2_SH(...) PCKEV_B2(v8i16, __VA_ARGS__) #define PCKEV_B2_SW(...) PCKEV_B2(v4i32, __VA_ARGS__) +#define PCKEV_B4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + PCKEV_B2(RTYPE, in0, in1, in2, in3, out0, out1); \ + PCKEV_B2(RTYPE, in4, in5, in6, in7, out2, out3); \ +} while (0) +#define PCKEV_B4_SB(...) PCKEV_B4(v16i8, __VA_ARGS__) +#define PCKEV_B4_UB(...) PCKEV_B4(v16u8, __VA_ARGS__) +#define PCKEV_B4_SH(...) PCKEV_B4(v8i16, __VA_ARGS__) +#define PCKEV_B4_SW(...) PCKEV_B4(v4i32, __VA_ARGS__) + +/* Description : Pack even halfword elements of vector pairs + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even halfword elements of 'in0' are copied to the left half of + * 'out0' & even halfword elements of 'in1' are copied to the + * right half of 'out0'. + */ +#define PCKEV_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_pckev_h((v8i16)in0, (v8i16)in1); \ + out1 = (RTYPE)__msa_pckev_h((v8i16)in2, (v8i16)in3); \ +} while (0) +#define PCKEV_H2_UH(...) PCKEV_H2(v8u16, __VA_ARGS__) +#define PCKEV_H2_SH(...) PCKEV_H2(v8i16, __VA_ARGS__) +#define PCKEV_H2_SW(...) PCKEV_H2(v4i32, __VA_ARGS__) +#define PCKEV_H2_UW(...) PCKEV_H2(v4u32, __VA_ARGS__) + +/* Description : Pack even word elements of vector pairs + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even word elements of 'in0' are copied to the left half of + * 'out0' & even word elements of 'in1' are copied to the + * right half of 'out0'. + */ +#define PCKEV_W2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_pckev_w((v4i32)in0, (v4i32)in1); \ + out1 = (RTYPE)__msa_pckev_w((v4i32)in2, (v4i32)in3); \ +} while (0) +#define PCKEV_W2_UH(...) PCKEV_W2(v8u16, __VA_ARGS__) +#define PCKEV_W2_SH(...) PCKEV_W2(v8i16, __VA_ARGS__) +#define PCKEV_W2_SW(...) PCKEV_W2(v4i32, __VA_ARGS__) +#define PCKEV_W2_UW(...) PCKEV_W2(v4u32, __VA_ARGS__) + +/* Description : Pack odd halfword elements of vector pairs + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Odd halfword elements of 'in0' are copied to the left half of + * 'out0' & odd halfword elements of 'in1' are copied to the + * right half of 'out0'. + */ +#define PCKOD_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_pckod_h((v8i16)in0, (v8i16)in1); \ + out1 = (RTYPE)__msa_pckod_h((v8i16)in2, (v8i16)in3); \ +} while (0) +#define PCKOD_H2_UH(...) PCKOD_H2(v8u16, __VA_ARGS__) +#define PCKOD_H2_SH(...) PCKOD_H2(v8i16, __VA_ARGS__) +#define PCKOD_H2_SW(...) PCKOD_H2(v4i32, __VA_ARGS__) +#define PCKOD_H2_UW(...) PCKOD_H2(v4u32, __VA_ARGS__) + /* Description : Arithmetic immediate shift right all elements of word vector * Arguments : Inputs - in0, in1, shift * Outputs - in place operation @@ -408,17 +1047,17 @@ * Details : Each element of vector 'in0' is right shifted by 'shift' and * the result is written in-place. 'shift' is a GP variable. */ -#define SRAI_W2(RTYPE, in0, in1, shift_val) { \ - in0 = (RTYPE)SRAI_W(in0, shift_val); \ - in1 = (RTYPE)SRAI_W(in1, shift_val); \ -} +#define SRAI_W2(RTYPE, in0, in1, shift_val) do { \ + in0 = (RTYPE)SRAI_W(in0, shift_val); \ + in1 = (RTYPE)SRAI_W(in1, shift_val); \ +} while (0) #define SRAI_W2_SW(...) SRAI_W2(v4i32, __VA_ARGS__) #define SRAI_W2_UW(...) SRAI_W2(v4u32, __VA_ARGS__) -#define SRAI_W4(RTYPE, in0, in1, in2, in3, shift_val) { \ - SRAI_W2(RTYPE, in0, in1, shift_val); \ - SRAI_W2(RTYPE, in2, in3, shift_val); \ -} +#define SRAI_W4(RTYPE, in0, in1, in2, in3, shift_val) do { \ + SRAI_W2(RTYPE, in0, in1, shift_val); \ + SRAI_W2(RTYPE, in2, in3, shift_val); \ +} while (0) #define SRAI_W4_SW(...) SRAI_W4(v4i32, __VA_ARGS__) #define SRAI_W4_UW(...) SRAI_W4(v4u32, __VA_ARGS__) @@ -429,10 +1068,10 @@ * Details : Each element of vector 'in0' is right shifted by 'shift' and * the result is written in-place. 'shift' is a GP variable. */ -#define SRAI_H2(RTYPE, in0, in1, shift_val) { \ - in0 = (RTYPE)SRAI_H(in0, shift_val); \ - in1 = (RTYPE)SRAI_H(in1, shift_val); \ -} +#define SRAI_H2(RTYPE, in0, in1, shift_val) do { \ + in0 = (RTYPE)SRAI_H(in0, shift_val); \ + in1 = (RTYPE)SRAI_H(in1, shift_val); \ +} while (0) #define SRAI_H2_SH(...) SRAI_H2(v8i16, __VA_ARGS__) #define SRAI_H2_UH(...) SRAI_H2(v8u16, __VA_ARGS__) @@ -443,48 +1082,166 @@ * Details : Each element of vector 'in0' is right shifted by 'shift' and * the result is written in-place. 'shift' is a GP variable. */ -#define SRARI_W2(RTYPE, in0, in1, shift) { \ +#define SRARI_W2(RTYPE, in0, in1, shift) do { \ in0 = (RTYPE)__msa_srari_w((v4i32)in0, shift); \ in1 = (RTYPE)__msa_srari_w((v4i32)in1, shift); \ -} +} while (0) #define SRARI_W2_SW(...) SRARI_W2(v4i32, __VA_ARGS__) -#define SRARI_W4(RTYPE, in0, in1, in2, in3, shift) { \ - SRARI_W2(RTYPE, in0, in1, shift); \ - SRARI_W2(RTYPE, in2, in3, shift); \ -} +#define SRARI_W4(RTYPE, in0, in1, in2, in3, shift) do { \ + SRARI_W2(RTYPE, in0, in1, shift); \ + SRARI_W2(RTYPE, in2, in3, shift); \ +} while (0) #define SRARI_W4_SH(...) SRARI_W4(v8i16, __VA_ARGS__) #define SRARI_W4_UW(...) SRARI_W4(v4u32, __VA_ARGS__) #define SRARI_W4_SW(...) SRARI_W4(v4i32, __VA_ARGS__) +/* Description : Shift right arithmetic rounded double words + * Arguments : Inputs - in0, in1, shift + * Outputs - in place operation + * Return Type - as per RTYPE + * Details : Each element of vector 'in0' is shifted right arithmetically by + * the number of bits in the corresponding element in the vector + * 'shift'. The last discarded bit is added to shifted value for + * rounding and the result is written in-place. + * 'shift' is a vector. + */ +#define SRAR_D2(RTYPE, in0, in1, shift) do { \ + in0 = (RTYPE)__msa_srar_d((v2i64)in0, (v2i64)shift); \ + in1 = (RTYPE)__msa_srar_d((v2i64)in1, (v2i64)shift); \ +} while (0) +#define SRAR_D2_SW(...) SRAR_D2(v4i32, __VA_ARGS__) +#define SRAR_D2_SD(...) SRAR_D2(v2i64, __VA_ARGS__) +#define SRAR_D2_UD(...) SRAR_D2(v2u64, __VA_ARGS__) + +#define SRAR_D4(RTYPE, in0, in1, in2, in3, shift) do { \ + SRAR_D2(RTYPE, in0, in1, shift); \ + SRAR_D2(RTYPE, in2, in3, shift); \ +} while (0) +#define SRAR_D4_SD(...) SRAR_D4(v2i64, __VA_ARGS__) +#define SRAR_D4_UD(...) SRAR_D4(v2u64, __VA_ARGS__) + /* Description : Addition of 2 pairs of half-word vectors * Arguments : Inputs - in0, in1, in2, in3 * Outputs - out0, out1 * Details : Each element in 'in0' is added to 'in1' and result is written * to 'out0'. */ -#define ADDVI_H2(RTYPE, in0, in1, in2, in3, out0, out1) { \ - out0 = (RTYPE)ADDVI_H(in0, in1); \ - out1 = (RTYPE)ADDVI_H(in2, in3); \ -} +#define ADDVI_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)ADDVI_H(in0, in1); \ + out1 = (RTYPE)ADDVI_H(in2, in3); \ +} while (0) #define ADDVI_H2_SH(...) ADDVI_H2(v8i16, __VA_ARGS__) #define ADDVI_H2_UH(...) ADDVI_H2(v8u16, __VA_ARGS__) +/* Description : Addition of 2 pairs of word vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Details : Each element in 'in0' is added to 'in1' and result is written + * to 'out0'. + */ +#define ADDVI_W2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)ADDVI_W(in0, in1); \ + out1 = (RTYPE)ADDVI_W(in2, in3); \ +} while (0) +#define ADDVI_W2_SW(...) ADDVI_W2(v4i32, __VA_ARGS__) + +/* Description : Fill 2 pairs of word vectors with GP registers + * Arguments : Inputs - in0, in1 + * Outputs - out0, out1 + * Details : GP register in0 is replicated in each word element of out0 + * GP register in1 is replicated in each word element of out1 + */ +#define FILL_W2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_fill_w(in0); \ + out1 = (RTYPE)__msa_fill_w(in1); \ +} while (0) +#define FILL_W2_SW(...) FILL_W2(v4i32, __VA_ARGS__) + /* Description : Addition of 2 pairs of vectors * Arguments : Inputs - in0, in1, in2, in3 * Outputs - out0, out1 * Details : Each element in 'in0' is added to 'in1' and result is written * to 'out0'. */ -#define ADD2(in0, in1, in2, in3, out0, out1) { \ - out0 = in0 + in1; \ - out1 = in2 + in3; \ -} +#define ADD2(in0, in1, in2, in3, out0, out1) do { \ + out0 = in0 + in1; \ + out1 = in2 + in3; \ +} while (0) + #define ADD4(in0, in1, in2, in3, in4, in5, in6, in7, \ - out0, out1, out2, out3) { \ + out0, out1, out2, out3) do { \ ADD2(in0, in1, in2, in3, out0, out1); \ ADD2(in4, in5, in6, in7, out2, out3); \ -} +} while (0) + +/* Description : Subtraction of 2 pairs of vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Details : Each element in 'in1' is subtracted from 'in0' and result is + * written to 'out0'. + */ +#define SUB2(in0, in1, in2, in3, out0, out1) do { \ + out0 = in0 - in1; \ + out1 = in2 - in3; \ +} while (0) + +#define SUB3(in0, in1, in2, in3, in4, in5, out0, out1, out2) do { \ + out0 = in0 - in1; \ + out1 = in2 - in3; \ + out2 = in4 - in5; \ +} while (0) + +#define SUB4(in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + out0 = in0 - in1; \ + out1 = in2 - in3; \ + out2 = in4 - in5; \ + out3 = in6 - in7; \ +} while (0) + +/* Description : Addition - Subtraction of input vectors + * Arguments : Inputs - in0, in1 + * Outputs - out0, out1 + * Details : Each element in 'in1' is added to 'in0' and result is + * written to 'out0'. + * Each element in 'in1' is subtracted from 'in0' and result is + * written to 'out1'. + */ +#define ADDSUB2(in0, in1, out0, out1) do { \ + out0 = in0 + in1; \ + out1 = in0 - in1; \ +} while (0) + +/* Description : Multiplication of pairs of vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Details : Each element from 'in0' is multiplied with elements from 'in1' + * and the result is written to 'out0' + */ +#define MUL2(in0, in1, in2, in3, out0, out1) do { \ + out0 = in0 * in1; \ + out1 = in2 * in3; \ +} while (0) + +#define MUL4(in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + MUL2(in0, in1, in2, in3, out0, out1); \ + MUL2(in4, in5, in6, in7, out2, out3); \ +} while (0) + +/* Description : Sign extend halfword elements from right half of the vector + * Arguments : Input - in (halfword vector) + * Output - out (sign extended word vector) + * Return Type - signed word + * Details : Sign bit of halfword elements from input vector 'in' is + * extracted and interleaved with same vector 'in0' to generate + * 4 word elements keeping sign intact + */ +#define UNPCK_R_SH_SW(in, out) do { \ + const v8i16 sign_m = __msa_clti_s_h((v8i16)in, 0); \ + out = (v4i32)__msa_ilvr_h(sign_m, (v8i16)in); \ +} while (0) /* Description : Sign extend halfword elements from input vector and return * the result in pair of vectors @@ -497,29 +1254,82 @@ * Then interleaved left with same vector 'in0' to * generate 4 signed word elements in 'out1' */ -#define UNPCK_SH_SW(in, out0, out1) { \ +#define UNPCK_SH_SW(in, out0, out1) do { \ const v8i16 tmp_m = __msa_clti_s_h((v8i16)in, 0); \ ILVRL_H2_SW(tmp_m, in, out0, out1); \ -} +} while (0) /* Description : Butterfly of 4 input vectors * Arguments : Inputs - in0, in1, in2, in3 * Outputs - out0, out1, out2, out3 * Details : Butterfly operation */ -#define BUTTERFLY_4(in0, in1, in2, in3, out0, out1, out2, out3) { \ - out0 = in0 + in3; \ - out1 = in1 + in2; \ - out2 = in1 - in2; \ - out3 = in0 - in3; \ -} +#define BUTTERFLY_4(in0, in1, in2, in3, out0, out1, out2, out3) do { \ + out0 = in0 + in3; \ + out1 = in1 + in2; \ + out2 = in1 - in2; \ + out3 = in0 - in3; \ +} while (0) + +/* Description : Transpose 16x4 block into 4x16 with byte elements in vectors + * Arguments : Inputs - in0, in1, in2, in3, in4, in5, in6, in7, + * in8, in9, in10, in11, in12, in13, in14, in15 + * Outputs - out0, out1, out2, out3 + * Return Type - unsigned byte + */ +#define TRANSPOSE16x4_UB_UB(in0, in1, in2, in3, in4, in5, in6, in7, \ + in8, in9, in10, in11, in12, in13, in14, in15, \ + out0, out1, out2, out3) do { \ + v2i64 tmp0_m, tmp1_m, tmp2_m, tmp3_m, tmp4_m, tmp5_m; \ + ILVEV_W2_SD(in0, in4, in8, in12, tmp2_m, tmp3_m); \ + ILVEV_W2_SD(in1, in5, in9, in13, tmp0_m, tmp1_m); \ + ILVEV_D2_UB(tmp2_m, tmp3_m, tmp0_m, tmp1_m, out1, out3); \ + ILVEV_W2_SD(in2, in6, in10, in14, tmp4_m, tmp5_m); \ + ILVEV_W2_SD(in3, in7, in11, in15, tmp0_m, tmp1_m); \ + ILVEV_D2_SD(tmp4_m, tmp5_m, tmp0_m, tmp1_m, tmp2_m, tmp3_m); \ + ILVEV_B2_SD(out1, out3, tmp2_m, tmp3_m, tmp0_m, tmp1_m); \ + ILVEVOD_H2_UB(tmp0_m, tmp1_m, tmp0_m, tmp1_m, out0, out2); \ + ILVOD_B2_SD(out1, out3, tmp2_m, tmp3_m, tmp0_m, tmp1_m); \ + ILVEVOD_H2_UB(tmp0_m, tmp1_m, tmp0_m, tmp1_m, out1, out3); \ +} while (0) + +/* Description : Transpose 16x8 block into 8x16 with byte elements in vectors + * Arguments : Inputs - in0, in1, in2, in3, in4, in5, in6, in7, + * in8, in9, in10, in11, in12, in13, in14, in15 + * Outputs - out0, out1, out2, out3, out4, out5, out6, out7 + * Return Type - unsigned byte + */ +#define TRANSPOSE16x8_UB_UB(in0, in1, in2, in3, in4, in5, in6, in7, \ + in8, in9, in10, in11, in12, in13, in14, in15, \ + out0, out1, out2, out3, out4, out5, \ + out6, out7) do { \ + v8i16 tmp0_m, tmp1_m, tmp4_m, tmp5_m, tmp6_m, tmp7_m; \ + v4i32 tmp2_m, tmp3_m; \ + ILVEV_D2_UB(in0, in8, in1, in9, out7, out6); \ + ILVEV_D2_UB(in2, in10, in3, in11, out5, out4); \ + ILVEV_D2_UB(in4, in12, in5, in13, out3, out2); \ + ILVEV_D2_UB(in6, in14, in7, in15, out1, out0); \ + ILVEV_B2_SH(out7, out6, out5, out4, tmp0_m, tmp1_m); \ + ILVOD_B2_SH(out7, out6, out5, out4, tmp4_m, tmp5_m); \ + ILVEV_B2_UB(out3, out2, out1, out0, out5, out7); \ + ILVOD_B2_SH(out3, out2, out1, out0, tmp6_m, tmp7_m); \ + ILVEV_H2_SW(tmp0_m, tmp1_m, out5, out7, tmp2_m, tmp3_m); \ + ILVEVOD_W2_UB(tmp2_m, tmp3_m, tmp2_m, tmp3_m, out0, out4); \ + ILVOD_H2_SW(tmp0_m, tmp1_m, out5, out7, tmp2_m, tmp3_m); \ + ILVEVOD_W2_UB(tmp2_m, tmp3_m, tmp2_m, tmp3_m, out2, out6); \ + ILVEV_H2_SW(tmp4_m, tmp5_m, tmp6_m, tmp7_m, tmp2_m, tmp3_m); \ + ILVEVOD_W2_UB(tmp2_m, tmp3_m, tmp2_m, tmp3_m, out1, out5); \ + ILVOD_H2_SW(tmp4_m, tmp5_m, tmp6_m, tmp7_m, tmp2_m, tmp3_m); \ + ILVEVOD_W2_UB(tmp2_m, tmp3_m, tmp2_m, tmp3_m, out3, out7); \ +} while (0) /* Description : Transpose 4x4 block with word elements in vectors * Arguments : Inputs - in0, in1, in2, in3 * Outputs - out0, out1, out2, out3 * Return Type - as per RTYPE */ -#define TRANSPOSE4x4_W(RTYPE, in0, in1, in2, in3, out0, out1, out2, out3) { \ +#define TRANSPOSE4x4_W(RTYPE, in0, in1, in2, in3, \ + out0, out1, out2, out3) do { \ v4i32 s0_m, s1_m, s2_m, s3_m; \ ILVRL_W2_SW(in1, in0, s0_m, s1_m); \ ILVRL_W2_SW(in3, in2, s2_m, s3_m); \ @@ -527,7 +1337,7 @@ out1 = (RTYPE)__msa_ilvl_d((v2i64)s2_m, (v2i64)s0_m); \ out2 = (RTYPE)__msa_ilvr_d((v2i64)s3_m, (v2i64)s1_m); \ out3 = (RTYPE)__msa_ilvl_d((v2i64)s3_m, (v2i64)s1_m); \ -} +} while (0) #define TRANSPOSE4x4_SW_SW(...) TRANSPOSE4x4_W(v4i32, __VA_ARGS__) /* Description : Add block 4x4 @@ -535,7 +1345,7 @@ * Details : Least significant 4 bytes from each input vector are added to * the destination bytes, clipped between 0-255 and stored. */ -#define ADDBLK_ST4x4_UB(in0, in1, in2, in3, pdst, stride) { \ +#define ADDBLK_ST4x4_UB(in0, in1, in2, in3, pdst, stride) do { \ uint32_t src0_m, src1_m, src2_m, src3_m; \ v8i16 inp0_m, inp1_m, res0_m, res1_m; \ v16i8 dst0_m = { 0 }; \ @@ -550,6 +1360,31 @@ CLIP_SH2_0_255(res0_m, res1_m); \ PCKEV_B2_SB(res0_m, res0_m, res1_m, res1_m, dst0_m, dst1_m); \ ST4x4_UB(dst0_m, dst1_m, 0, 1, 0, 1, pdst, stride); \ -} +} while (0) + +/* Description : Pack even byte elements, extract 0 & 2 index words from pair + * of results and store 4 words in destination memory as per + * stride + * Arguments : Inputs - in0, in1, in2, in3, pdst, stride + */ +#define PCKEV_ST4x4_UB(in0, in1, in2, in3, pdst, stride) do { \ + v16i8 tmp0_m, tmp1_m; \ + PCKEV_B2_SB(in1, in0, in3, in2, tmp0_m, tmp1_m); \ + ST4x4_UB(tmp0_m, tmp1_m, 0, 2, 0, 2, pdst, stride); \ +} while (0) + +/* Description : average with rounding (in0 + in1 + 1) / 2. + * Arguments : Inputs - in0, in1, in2, in3, + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Each unsigned byte element from 'in0' vector is added with + * each unsigned byte element from 'in1' vector. Then the average + * with rounding is calculated and written to 'out0' + */ +#define AVER_UB2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_aver_u_b((v16u8)in0, (v16u8)in1); \ + out1 = (RTYPE)__msa_aver_u_b((v16u8)in2, (v16u8)in3); \ +} while (0) +#define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__) #endif /* WEBP_DSP_MSA_MACRO_H_ */ diff --git a/src/3rdparty/libwebp/src/dsp/neon.h b/src/3rdparty/libwebp/src/dsp/neon.h index 0a06266848f223b99ee60e44aefc1929da3b46a6..3b548a685591480177aee85287f1fb3456b7a1fc 100644 --- a/src/3rdparty/libwebp/src/dsp/neon.h +++ b/src/3rdparty/libwebp/src/dsp/neon.h @@ -79,4 +79,22 @@ static WEBP_INLINE int32x4x4_t Transpose4x4(const int32x4x4_t rows) { } } +#if 0 // Useful debug macro. +#include <stdio.h> +#define PRINT_REG(REG, SIZE) do { \ + int i; \ + printf("%s \t[%d]: 0x", #REG, SIZE); \ + if (SIZE == 8) { \ + uint8_t _tmp[8]; \ + vst1_u8(_tmp, (REG)); \ + for (i = 0; i < 8; ++i) printf("%.2x ", _tmp[i]); \ + } else if (SIZE == 16) { \ + uint16_t _tmp[4]; \ + vst1_u16(_tmp, (REG)); \ + for (i = 0; i < 4; ++i) printf("%.4x ", _tmp[i]); \ + } \ + printf("\n"); \ +} while (0) +#endif + #endif // WEBP_DSP_NEON_H_ diff --git a/src/3rdparty/libwebp/src/dsp/rescaler.c b/src/3rdparty/libwebp/src/dsp/rescaler.c index bc743d5dc54ff239692593d39a33aef14313275a..0f545023521958e276d91a138c17b41fe47c05b1 100644 --- a/src/3rdparty/libwebp/src/dsp/rescaler.c +++ b/src/3rdparty/libwebp/src/dsp/rescaler.c @@ -14,7 +14,7 @@ #include <assert.h> #include "./dsp.h" -#include "../utils/rescaler.h" +#include "../utils/rescaler_utils.h" //------------------------------------------------------------------------------ // Implementations of critical functions ImportRow / ExportRow @@ -173,10 +173,10 @@ void WebPRescalerExportRow(WebPRescaler* const wrk) { WebPRescalerExportRowExpand(wrk); } else if (wrk->fxy_scale) { WebPRescalerExportRowShrink(wrk); - } else { // very special case for src = dst = 1x1 + } else { // special case int i; + assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1); assert(wrk->src_width == 1 && wrk->dst_width <= 2); - assert(wrk->src_height == 1 && wrk->dst_height == 1); for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { wrk->dst[i] = wrk->irow[i]; wrk->irow[i] = 0; @@ -199,6 +199,7 @@ WebPRescalerExportRowFunc WebPRescalerExportRowShrink; extern void WebPRescalerDspInitSSE2(void); extern void WebPRescalerDspInitMIPS32(void); extern void WebPRescalerDspInitMIPSdspR2(void); +extern void WebPRescalerDspInitMSA(void); extern void WebPRescalerDspInitNEON(void); static volatile VP8CPUInfo rescaler_last_cpuinfo_used = @@ -232,6 +233,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) { if (VP8GetCPUInfo(kMIPSdspR2)) { WebPRescalerDspInitMIPSdspR2(); } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + WebPRescalerDspInitMSA(); + } #endif } rescaler_last_cpuinfo_used = VP8GetCPUInfo; diff --git a/src/3rdparty/libwebp/src/dsp/rescaler_mips32.c b/src/3rdparty/libwebp/src/dsp/rescaler_mips32.c index ddaa39133639a6b8d1998ab42c88e0a6f807db5f..e09ad5d19f037e47ba7720f544252d7a635edcbf 100644 --- a/src/3rdparty/libwebp/src/dsp/rescaler_mips32.c +++ b/src/3rdparty/libwebp/src/dsp/rescaler_mips32.c @@ -16,7 +16,7 @@ #if defined(WEBP_USE_MIPS32) #include <assert.h> -#include "../utils/rescaler.h" +#include "../utils/rescaler_utils.h" //------------------------------------------------------------------------------ // Row import diff --git a/src/3rdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c b/src/3rdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c index b457d0a30a6861197914d432c89a47b4a7db3c22..2308d6454418df64574e021637a157454245311d 100644 --- a/src/3rdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c +++ b/src/3rdparty/libwebp/src/dsp/rescaler_mips_dsp_r2.c @@ -16,7 +16,7 @@ #if defined(WEBP_USE_MIPS_DSP_R2) #include <assert.h> -#include "../utils/rescaler.h" +#include "../utils/rescaler_utils.h" #define ROUNDER (WEBP_RESCALER_ONE >> 1) #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) diff --git a/src/3rdparty/libwebp/src/dsp/rescaler_msa.c b/src/3rdparty/libwebp/src/dsp/rescaler_msa.c new file mode 100644 index 0000000000000000000000000000000000000000..2c10e55d8cfc38be79b9f573f40af1e7330ad17d --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/rescaler_msa.c @@ -0,0 +1,444 @@ +// Copyright 2016 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. +// ----------------------------------------------------------------------------- +// +// MSA version of rescaling functions +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include "./dsp.h" + +#if defined(WEBP_USE_MSA) + +#include <assert.h> + +#include "../utils/rescaler_utils.h" +#include "./msa_macro.h" + +#define ROUNDER (WEBP_RESCALER_ONE >> 1) +#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) + +#define CALC_MULT_FIX_16(in0, in1, in2, in3, scale, shift, dst) do { \ + v4u32 tmp0, tmp1, tmp2, tmp3; \ + v16u8 t0, t1, t2, t3, t4, t5; \ + v2u64 out0, out1, out2, out3; \ + ILVRL_W2_UW(zero, in0, tmp0, tmp1); \ + ILVRL_W2_UW(zero, in1, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, scale, scale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_B2_UB(out1, out0, out3, out2, t0, t1); \ + ILVRL_W2_UW(zero, in2, tmp0, tmp1); \ + ILVRL_W2_UW(zero, in3, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, scale, scale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_B2_UB(out1, out0, out3, out2, t2, t3); \ + PCKEV_B2_UB(t1, t0, t3, t2, t4, t5); \ + dst = (v16u8)__msa_pckev_b((v16i8)t5, (v16i8)t4); \ +} while (0) + +#define CALC_MULT_FIX_4(in0, scale, shift, dst) do { \ + v4u32 tmp0, tmp1; \ + v16i8 t0, t1; \ + v2u64 out0, out1; \ + ILVRL_W2_UW(zero, in0, tmp0, tmp1); \ + DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1); \ + SRAR_D2_UD(out0, out1, shift); \ + t0 = __msa_pckev_b((v16i8)out1, (v16i8)out0); \ + t1 = __msa_pckev_b(t0, t0); \ + t0 = __msa_pckev_b(t1, t1); \ + dst = __msa_copy_s_w((v4i32)t0, 0); \ +} while (0) + +#define CALC_MULT_FIX1_16(in0, in1, in2, in3, fyscale, shift, \ + dst0, dst1, dst2, dst3) do { \ + v4u32 tmp0, tmp1, tmp2, tmp3; \ + v2u64 out0, out1, out2, out3; \ + ILVRL_W2_UW(zero, in0, tmp0, tmp1); \ + ILVRL_W2_UW(zero, in1, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, fyscale, fyscale, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, fyscale, fyscale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_W2_UW(out1, out0, out3, out2, dst0, dst1); \ + ILVRL_W2_UW(zero, in2, tmp0, tmp1); \ + ILVRL_W2_UW(zero, in3, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, fyscale, fyscale, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, fyscale, fyscale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_W2_UW(out1, out0, out3, out2, dst2, dst3); \ +} while (0) + +#define CALC_MULT_FIX1_4(in0, scale, shift, dst) do { \ + v4u32 tmp0, tmp1; \ + v2u64 out0, out1; \ + ILVRL_W2_UW(zero, in0, tmp0, tmp1); \ + DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1); \ + SRAR_D2_UD(out0, out1, shift); \ + dst = (v4u32)__msa_pckev_w((v4i32)out1, (v4i32)out0); \ +} while (0) + +#define CALC_MULT_FIX2_16(in0, in1, in2, in3, mult, scale, shift, \ + dst0, dst1) do { \ + v4u32 tmp0, tmp1, tmp2, tmp3; \ + v2u64 out0, out1, out2, out3; \ + ILVRL_W2_UW(in0, in2, tmp0, tmp1); \ + ILVRL_W2_UW(in1, in3, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, mult, mult, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, mult, mult, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + DOTP_UW2_UD(out0, out1, scale, scale, out0, out1); \ + DOTP_UW2_UD(out2, out3, scale, scale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_B2_UB(out1, out0, out3, out2, dst0, dst1); \ +} while (0) + +#define CALC_MULT_FIX2_4(in0, in1, mult, scale, shift, dst) do { \ + v4u32 tmp0, tmp1; \ + v2u64 out0, out1; \ + v16i8 t0, t1; \ + ILVRL_W2_UW(in0, in1, tmp0, tmp1); \ + DOTP_UW2_UD(tmp0, tmp1, mult, mult, out0, out1); \ + SRAR_D2_UD(out0, out1, shift); \ + DOTP_UW2_UD(out0, out1, scale, scale, out0, out1); \ + SRAR_D2_UD(out0, out1, shift); \ + t0 = __msa_pckev_b((v16i8)out1, (v16i8)out0); \ + t1 = __msa_pckev_b(t0, t0); \ + t0 = __msa_pckev_b(t1, t1); \ + dst = __msa_copy_s_w((v4i32)t0, 0); \ +} while (0) + +static WEBP_INLINE void ExportRowExpand_0(const uint32_t* frow, uint8_t* dst, + int length, + WebPRescaler* const wrk) { + const v4u32 scale = (v4u32)__msa_fill_w(wrk->fy_scale); + const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); + const v4i32 zero = { 0 }; + + while (length >= 16) { + v4u32 src0, src1, src2, src3; + v16u8 out; + LD_UW4(frow, 4, src0, src1, src2, src3); + CALC_MULT_FIX_16(src0, src1, src2, src3, scale, shift, out); + ST_UB(out, dst); + length -= 16; + frow += 16; + dst += 16; + } + if (length > 0) { + int x_out; + if (length >= 12) { + uint32_t val0_m, val1_m, val2_m; + v4u32 src0, src1, src2; + LD_UW3(frow, 4, src0, src1, src2); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + CALC_MULT_FIX_4(src1, scale, shift, val1_m); + CALC_MULT_FIX_4(src2, scale, shift, val2_m); + SW3(val0_m, val1_m, val2_m, dst, 4); + length -= 12; + frow += 12; + dst += 12; + } else if (length >= 8) { + uint32_t val0_m, val1_m; + v4u32 src0, src1; + LD_UW2(frow, 4, src0, src1); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + CALC_MULT_FIX_4(src1, scale, shift, val1_m); + SW2(val0_m, val1_m, dst, 4); + length -= 8; + frow += 8; + dst += 8; + } else if (length >= 4) { + uint32_t val0_m; + const v4u32 src0 = LD_UW(frow); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + SW(val0_m, dst); + length -= 4; + frow += 4; + dst += 4; + } + for (x_out = 0; x_out < length; ++x_out) { + const uint32_t J = frow[x_out]; + const int v = (int)MULT_FIX(J, wrk->fy_scale); + assert(v >= 0 && v <= 255); + dst[x_out] = v; + } + } +} + +static WEBP_INLINE void ExportRowExpand_1(const uint32_t* frow, uint32_t* irow, + uint8_t* dst, int length, + WebPRescaler* const wrk) { + const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); + const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); + const v4i32 B1 = __msa_fill_w(B); + const v4i32 A1 = __msa_fill_w(A); + const v4i32 AB = __msa_ilvr_w(A1, B1); + const v4u32 scale = (v4u32)__msa_fill_w(wrk->fy_scale); + const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); + + while (length >= 16) { + v4u32 frow0, frow1, frow2, frow3, irow0, irow1, irow2, irow3; + v16u8 t0, t1, t2, t3, t4, t5; + LD_UW4(frow, 4, frow0, frow1, frow2, frow3); + LD_UW4(irow, 4, irow0, irow1, irow2, irow3); + CALC_MULT_FIX2_16(frow0, frow1, irow0, irow1, AB, scale, shift, t0, t1); + CALC_MULT_FIX2_16(frow2, frow3, irow2, irow3, AB, scale, shift, t2, t3); + PCKEV_B2_UB(t1, t0, t3, t2, t4, t5); + t0 = (v16u8)__msa_pckev_b((v16i8)t5, (v16i8)t4); + ST_UB(t0, dst); + frow += 16; + irow += 16; + dst += 16; + length -= 16; + } + if (length > 0) { + int x_out; + if (length >= 12) { + uint32_t val0_m, val1_m, val2_m; + v4u32 frow0, frow1, frow2, irow0, irow1, irow2; + LD_UW3(frow, 4, frow0, frow1, frow2); + LD_UW3(irow, 4, irow0, irow1, irow2); + CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m); + CALC_MULT_FIX2_4(frow1, irow1, AB, scale, shift, val1_m); + CALC_MULT_FIX2_4(frow2, irow2, AB, scale, shift, val2_m); + SW3(val0_m, val1_m, val2_m, dst, 4); + frow += 12; + irow += 12; + dst += 12; + length -= 12; + } else if (length >= 8) { + uint32_t val0_m, val1_m; + v4u32 frow0, frow1, irow0, irow1; + LD_UW2(frow, 4, frow0, frow1); + LD_UW2(irow, 4, irow0, irow1); + CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m); + CALC_MULT_FIX2_4(frow1, irow1, AB, scale, shift, val1_m); + SW2(val0_m, val1_m, dst, 4); + frow += 4; + irow += 4; + dst += 4; + length -= 4; + } else if (length >= 4) { + uint32_t val0_m; + const v4u32 frow0 = LD_UW(frow + 0); + const v4u32 irow0 = LD_UW(irow + 0); + CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m); + SW(val0_m, dst); + frow += 4; + irow += 4; + dst += 4; + length -= 4; + } + for (x_out = 0; x_out < length; ++x_out) { + const uint64_t I = (uint64_t)A * frow[x_out] + + (uint64_t)B * irow[x_out]; + const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); + const int v = (int)MULT_FIX(J, wrk->fy_scale); + assert(v >= 0 && v <= 255); + dst[x_out] = v; + } + } +} + +static void RescalerExportRowExpand(WebPRescaler* const wrk) { + uint8_t* dst = wrk->dst; + rescaler_t* irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* frow = wrk->frow; + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(wrk->y_expand); + assert(wrk->y_sub != 0); + if (wrk->y_accum == 0) { + ExportRowExpand_0(frow, dst, x_out_max, wrk); + } else { + ExportRowExpand_1(frow, irow, dst, x_out_max, wrk); + } +} + +static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow, + uint8_t* dst, int length, + const uint32_t yscale, + WebPRescaler* const wrk) { + const v4u32 y_scale = (v4u32)__msa_fill_w(yscale); + const v4u32 fxyscale = (v4u32)__msa_fill_w(wrk->fxy_scale); + const v4u32 shiftval = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); + const v4i32 zero = { 0 }; + + while (length >= 16) { + v4u32 src0, src1, src2, src3, frac0, frac1, frac2, frac3; + v16u8 out; + LD_UW4(frow, 4, src0, src1, src2, src3); + CALC_MULT_FIX1_16(src0, src1, src2, src3, y_scale, shiftval, + frac0, frac1, frac2, frac3); + LD_UW4(irow, 4, src0, src1, src2, src3); + SUB4(src0, frac0, src1, frac1, src2, frac2, src3, frac3, + src0, src1, src2, src3); + CALC_MULT_FIX_16(src0, src1, src2, src3, fxyscale, shiftval, out); + ST_UB(out, dst); + ST_UW4(frac0, frac1, frac2, frac3, irow, 4); + frow += 16; + irow += 16; + dst += 16; + length -= 16; + } + if (length > 0) { + int x_out; + if (length >= 12) { + uint32_t val0_m, val1_m, val2_m; + v4u32 src0, src1, src2, frac0, frac1, frac2; + LD_UW3(frow, 4, src0, src1, src2); + CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0); + CALC_MULT_FIX1_4(src1, y_scale, shiftval, frac1); + CALC_MULT_FIX1_4(src2, y_scale, shiftval, frac2); + LD_UW3(irow, 4, src0, src1, src2); + SUB3(src0, frac0, src1, frac1, src2, frac2, src0, src1, src2); + CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m); + CALC_MULT_FIX_4(src1, fxyscale, shiftval, val1_m); + CALC_MULT_FIX_4(src2, fxyscale, shiftval, val2_m); + SW3(val0_m, val1_m, val2_m, dst, 4); + ST_UW3(frac0, frac1, frac2, irow, 4); + frow += 12; + irow += 12; + dst += 12; + length -= 12; + } else if (length >= 8) { + uint32_t val0_m, val1_m; + v4u32 src0, src1, frac0, frac1; + LD_UW2(frow, 4, src0, src1); + CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0); + CALC_MULT_FIX1_4(src1, y_scale, shiftval, frac1); + LD_UW2(irow, 4, src0, src1); + SUB2(src0, frac0, src1, frac1, src0, src1); + CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m); + CALC_MULT_FIX_4(src1, fxyscale, shiftval, val1_m); + SW2(val0_m, val1_m, dst, 4); + ST_UW2(frac0, frac1, irow, 4); + frow += 8; + irow += 8; + dst += 8; + length -= 8; + } else if (length >= 4) { + uint32_t val0_m; + v4u32 frac0; + v4u32 src0 = LD_UW(frow); + CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0); + src0 = LD_UW(irow); + src0 = src0 - frac0; + CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m); + SW(val0_m, dst); + ST_UW(frac0, irow); + frow += 4; + irow += 4; + dst += 4; + length -= 4; + } + for (x_out = 0; x_out < length; ++x_out) { + 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); + assert(v >= 0 && v <= 255); + dst[x_out] = v; + irow[x_out] = frac; + } + } +} + +static WEBP_INLINE void ExportRowShrink_1(uint32_t* irow, uint8_t* dst, + int length, + WebPRescaler* const wrk) { + const v4u32 scale = (v4u32)__msa_fill_w(wrk->fxy_scale); + const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); + const v4i32 zero = { 0 }; + + while (length >= 16) { + v4u32 src0, src1, src2, src3; + v16u8 dst0; + LD_UW4(irow, 4, src0, src1, src2, src3); + CALC_MULT_FIX_16(src0, src1, src2, src3, scale, shift, dst0); + ST_UB(dst0, dst); + ST_SW4(zero, zero, zero, zero, irow, 4); + length -= 16; + irow += 16; + dst += 16; + } + if (length > 0) { + int x_out; + if (length >= 12) { + uint32_t val0_m, val1_m, val2_m; + v4u32 src0, src1, src2; + LD_UW3(irow, 4, src0, src1, src2); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + CALC_MULT_FIX_4(src1, scale, shift, val1_m); + CALC_MULT_FIX_4(src2, scale, shift, val2_m); + SW3(val0_m, val1_m, val2_m, dst, 4); + ST_SW3(zero, zero, zero, irow, 4); + length -= 12; + irow += 12; + dst += 12; + } else if (length >= 8) { + uint32_t val0_m, val1_m; + v4u32 src0, src1; + LD_UW2(irow, 4, src0, src1); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + CALC_MULT_FIX_4(src1, scale, shift, val1_m); + SW2(val0_m, val1_m, dst, 4); + ST_SW2(zero, zero, irow, 4); + length -= 8; + irow += 8; + dst += 8; + } else if (length >= 4) { + uint32_t val0_m; + const v4u32 src0 = LD_UW(irow + 0); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + SW(val0_m, dst); + ST_SW(zero, irow); + length -= 4; + irow += 4; + dst += 4; + } + for (x_out = 0; x_out < length; ++x_out) { + const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); + assert(v >= 0 && v <= 255); + dst[x_out] = v; + irow[x_out] = 0; + } + } +} + +static void RescalerExportRowShrink(WebPRescaler* const wrk) { + uint8_t* dst = wrk->dst; + rescaler_t* irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* frow = wrk->frow; + const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(!wrk->y_expand); + if (yscale) { + ExportRowShrink_0(frow, irow, dst, x_out_max, yscale, wrk); + } else { + ExportRowShrink_1(irow, dst, x_out_max, wrk); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPRescalerDspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMSA(void) { + WebPRescalerExportRowExpand = RescalerExportRowExpand; + WebPRescalerExportRowShrink = RescalerExportRowShrink; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(WebPRescalerDspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/src/3rdparty/libwebp/src/dsp/rescaler_neon.c b/src/3rdparty/libwebp/src/dsp/rescaler_neon.c index 16fd450ea3e7c328bca2e397a102c8c2ca0610da..b2dd8f30cc4eb57f9eadc21bbb7fde36c742009d 100644 --- a/src/3rdparty/libwebp/src/dsp/rescaler_neon.c +++ b/src/3rdparty/libwebp/src/dsp/rescaler_neon.c @@ -18,7 +18,7 @@ #include <arm_neon.h> #include <assert.h> #include "./neon.h" -#include "../utils/rescaler.h" +#include "../utils/rescaler_utils.h" #define ROUNDER (WEBP_RESCALER_ONE >> 1) #define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) diff --git a/src/3rdparty/libwebp/src/dsp/rescaler_sse2.c b/src/3rdparty/libwebp/src/dsp/rescaler_sse2.c index 5b9702817c0befffaa8b4ff5fc4475c43c032f59..8271c22e0546dd209a0848ed5563805e79adba57 100644 --- a/src/3rdparty/libwebp/src/dsp/rescaler_sse2.c +++ b/src/3rdparty/libwebp/src/dsp/rescaler_sse2.c @@ -17,7 +17,7 @@ #include <emmintrin.h> #include <assert.h> -#include "../utils/rescaler.h" +#include "../utils/rescaler_utils.h" #include "../utils/utils.h" //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/dsp/upsampling.c b/src/3rdparty/libwebp/src/dsp/upsampling.c index 651274fcee6bc849cba0da71234bf2d6cf5d7323..265e722c1091275359b1700ad54362c4a71000d6 100644 --- a/src/3rdparty/libwebp/src/dsp/upsampling.c +++ b/src/3rdparty/libwebp/src/dsp/upsampling.c @@ -215,6 +215,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void) { extern void WebPInitUpsamplersSSE2(void); extern void WebPInitUpsamplersNEON(void); extern void WebPInitUpsamplersMIPSdspR2(void); +extern void WebPInitUpsamplersMSA(void); static volatile VP8CPUInfo upsampling_last_cpuinfo_used2 = (VP8CPUInfo)&upsampling_last_cpuinfo_used2; @@ -251,6 +252,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) { if (VP8GetCPUInfo(kMIPSdspR2)) { WebPInitUpsamplersMIPSdspR2(); } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + WebPInitUpsamplersMSA(); + } #endif } #endif // FANCY_UPSAMPLING diff --git a/src/3rdparty/libwebp/src/dsp/upsampling_msa.c b/src/3rdparty/libwebp/src/dsp/upsampling_msa.c new file mode 100644 index 0000000000000000000000000000000000000000..f24926fa94f0d6e522495defb9ea27c092051f13 --- /dev/null +++ b/src/3rdparty/libwebp/src/dsp/upsampling_msa.c @@ -0,0 +1,678 @@ +// Copyright 2016 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. +// ----------------------------------------------------------------------------- +// +// MSA version of YUV to RGB upsampling functions. +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include <string.h> +#include "./dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "./msa_macro.h" +#include "./yuv.h" + +#ifdef FANCY_UPSAMPLING + +#define ILVR_UW2(in, out0, out1) do { \ + const v8i16 t0 = (v8i16)__msa_ilvr_b((v16i8)zero, (v16i8)in); \ + out0 = (v4u32)__msa_ilvr_h((v8i16)zero, t0); \ + out1 = (v4u32)__msa_ilvl_h((v8i16)zero, t0); \ +} while (0) + +#define ILVRL_UW4(in, out0, out1, out2, out3) do { \ + v16u8 t0, t1; \ + ILVRL_B2_UB(zero, in, t0, t1); \ + ILVRL_H2_UW(zero, t0, out0, out1); \ + ILVRL_H2_UW(zero, t1, out2, out3); \ +} while (0) + +#define MULTHI_16(in0, in1, in2, in3, cnst, out0, out1) do { \ + const v4i32 const0 = (v4i32)__msa_fill_w(cnst * 256); \ + v4u32 temp0, temp1, temp2, temp3; \ + MUL4(in0, const0, in1, const0, in2, const0, in3, const0, \ + temp0, temp1, temp2, temp3); \ + PCKOD_H2_UH(temp1, temp0, temp3, temp2, out0, out1); \ +} while (0) + +#define MULTHI_8(in0, in1, cnst, out0) do { \ + const v4i32 const0 = (v4i32)__msa_fill_w(cnst * 256); \ + v4u32 temp0, temp1; \ + MUL2(in0, const0, in1, const0, temp0, temp1); \ + out0 = (v8u16)__msa_pckod_h((v8i16)temp1, (v8i16)temp0); \ +} while (0) + +#define CALC_R16(y0, y1, v0, v1, dst) do { \ + const v8i16 const_a = (v8i16)__msa_fill_h(14234); \ + const v8i16 a0 = __msa_adds_s_h((v8i16)y0, (v8i16)v0); \ + const v8i16 a1 = __msa_adds_s_h((v8i16)y1, (v8i16)v1); \ + v8i16 b0 = __msa_subs_s_h(a0, const_a); \ + v8i16 b1 = __msa_subs_s_h(a1, const_a); \ + SRAI_H2_SH(b0, b1, 6); \ + CLIP_SH2_0_255(b0, b1); \ + dst = (v16u8)__msa_pckev_b((v16i8)b1, (v16i8)b0); \ +} while (0) + +#define CALC_R8(y0, v0, dst) do { \ + const v8i16 const_a = (v8i16)__msa_fill_h(14234); \ + const v8i16 a0 = __msa_adds_s_h((v8i16)y0, (v8i16)v0); \ + v8i16 b0 = __msa_subs_s_h(a0, const_a); \ + b0 = SRAI_H(b0, 6); \ + CLIP_SH_0_255(b0); \ + dst = (v16u8)__msa_pckev_b((v16i8)b0, (v16i8)b0); \ +} while (0) + +#define CALC_G16(y0, y1, u0, u1, v0, v1, dst) do { \ + const v8i16 const_a = (v8i16)__msa_fill_h(8708); \ + v8i16 a0 = __msa_subs_s_h((v8i16)y0, (v8i16)u0); \ + v8i16 a1 = __msa_subs_s_h((v8i16)y1, (v8i16)u1); \ + const v8i16 b0 = __msa_subs_s_h(a0, (v8i16)v0); \ + const v8i16 b1 = __msa_subs_s_h(a1, (v8i16)v1); \ + a0 = __msa_adds_s_h(b0, const_a); \ + a1 = __msa_adds_s_h(b1, const_a); \ + SRAI_H2_SH(a0, a1, 6); \ + CLIP_SH2_0_255(a0, a1); \ + dst = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0); \ +} while (0) + +#define CALC_G8(y0, u0, v0, dst) do { \ + const v8i16 const_a = (v8i16)__msa_fill_h(8708); \ + v8i16 a0 = __msa_subs_s_h((v8i16)y0, (v8i16)u0); \ + const v8i16 b0 = __msa_subs_s_h(a0, (v8i16)v0); \ + a0 = __msa_adds_s_h(b0, const_a); \ + a0 = SRAI_H(a0, 6); \ + CLIP_SH_0_255(a0); \ + dst = (v16u8)__msa_pckev_b((v16i8)a0, (v16i8)a0); \ +} while (0) + +#define CALC_B16(y0, y1, u0, u1, dst) do { \ + const v8u16 const_a = (v8u16)__msa_fill_h(17685); \ + const v8u16 a0 = __msa_adds_u_h((v8u16)y0, u0); \ + const v8u16 a1 = __msa_adds_u_h((v8u16)y1, u1); \ + v8u16 b0 = __msa_subs_u_h(a0, const_a); \ + v8u16 b1 = __msa_subs_u_h(a1, const_a); \ + SRAI_H2_UH(b0, b1, 6); \ + CLIP_UH2_0_255(b0, b1); \ + dst = (v16u8)__msa_pckev_b((v16i8)b1, (v16i8)b0); \ +} while (0) + +#define CALC_B8(y0, u0, dst) do { \ + const v8u16 const_a = (v8u16)__msa_fill_h(17685); \ + const v8u16 a0 = __msa_adds_u_h((v8u16)y0, u0); \ + v8u16 b0 = __msa_subs_u_h(a0, const_a); \ + b0 = SRAI_H(b0, 6); \ + CLIP_UH_0_255(b0); \ + dst = (v16u8)__msa_pckev_b((v16i8)b0, (v16i8)b0); \ +} while (0) + +#define CALC_RGB16(y, u, v, R, G, B) do { \ + const v16u8 zero = { 0 }; \ + v8u16 y0, y1, u0, u1, v0, v1; \ + v4u32 p0, p1, p2, p3; \ + const v16u8 in_y = LD_UB(y); \ + const v16u8 in_u = LD_UB(u); \ + const v16u8 in_v = LD_UB(v); \ + ILVRL_UW4(in_y, p0, p1, p2, p3); \ + MULTHI_16(p0, p1, p2, p3, 19077, y0, y1); \ + ILVRL_UW4(in_v, p0, p1, p2, p3); \ + MULTHI_16(p0, p1, p2, p3, 26149, v0, v1); \ + CALC_R16(y0, y1, v0, v1, R); \ + MULTHI_16(p0, p1, p2, p3, 13320, v0, v1); \ + ILVRL_UW4(in_u, p0, p1, p2, p3); \ + MULTHI_16(p0, p1, p2, p3, 6419, u0, u1); \ + CALC_G16(y0, y1, u0, u1, v0, v1, G); \ + MULTHI_16(p0, p1, p2, p3, 33050, u0, u1); \ + CALC_B16(y0, y1, u0, u1, B); \ +} while (0) + +#define CALC_RGB8(y, u, v, R, G, B) do { \ + const v16u8 zero = { 0 }; \ + v8u16 y0, u0, v0; \ + v4u32 p0, p1; \ + const v16u8 in_y = LD_UB(y); \ + const v16u8 in_u = LD_UB(u); \ + const v16u8 in_v = LD_UB(v); \ + ILVR_UW2(in_y, p0, p1); \ + MULTHI_8(p0, p1, 19077, y0); \ + ILVR_UW2(in_v, p0, p1); \ + MULTHI_8(p0, p1, 26149, v0); \ + CALC_R8(y0, v0, R); \ + MULTHI_8(p0, p1, 13320, v0); \ + ILVR_UW2(in_u, p0, p1); \ + MULTHI_8(p0, p1, 6419, u0); \ + CALC_G8(y0, u0, v0, G); \ + MULTHI_8(p0, p1, 33050, u0); \ + CALC_B8(y0, u0, B); \ +} while (0) + +#define STORE16_3(a0, a1, a2, dst) do { \ + const v16u8 mask0 = { 0, 1, 16, 2, 3, 17, 4, 5, 18, 6, 7, 19, \ + 8, 9, 20, 10 }; \ + const v16u8 mask1 = { 0, 21, 1, 2, 22, 3, 4, 23, 5, 6, 24, 7, \ + 8, 25, 9, 10 }; \ + const v16u8 mask2 = { 26, 0, 1, 27, 2, 3, 28, 4, 5, 29, 6, 7, \ + 30, 8, 9, 31 }; \ + v16u8 out0, out1, out2, tmp0, tmp1, tmp2; \ + ILVRL_B2_UB(a1, a0, tmp0, tmp1); \ + out0 = VSHF_UB(tmp0, a2, mask0); \ + tmp2 = SLDI_UB(tmp1, tmp0, 11); \ + out1 = VSHF_UB(tmp2, a2, mask1); \ + tmp2 = SLDI_UB(tmp1, tmp1, 6); \ + out2 = VSHF_UB(tmp2, a2, mask2); \ + ST_UB(out0, dst + 0); \ + ST_UB(out1, dst + 16); \ + ST_UB(out2, dst + 32); \ +} while (0) + +#define STORE8_3(a0, a1, a2, dst) do { \ + int64_t out_m; \ + const v16u8 mask0 = { 0, 1, 16, 2, 3, 17, 4, 5, 18, 6, 7, 19, \ + 8, 9, 20, 10 }; \ + const v16u8 mask1 = { 11, 21, 12, 13, 22, 14, 15, 23, \ + 255, 255, 255, 255, 255, 255, 255, 255 }; \ + const v16u8 tmp0 = (v16u8)__msa_ilvr_b((v16i8)a1, (v16i8)a0); \ + v16u8 out0, out1; \ + VSHF_B2_UB(tmp0, a2, tmp0, a2, mask0, mask1, out0, out1); \ + ST_UB(out0, dst); \ + out_m = __msa_copy_s_d((v2i64)out1, 0); \ + SD(out_m, dst + 16); \ +} while (0) + +#define STORE16_4(a0, a1, a2, a3, dst) do { \ + v16u8 tmp0, tmp1, tmp2, tmp3; \ + v16u8 out0, out1, out2, out3; \ + ILVRL_B2_UB(a1, a0, tmp0, tmp1); \ + ILVRL_B2_UB(a3, a2, tmp2, tmp3); \ + ILVRL_H2_UB(tmp2, tmp0, out0, out1); \ + ILVRL_H2_UB(tmp3, tmp1, out2, out3); \ + ST_UB(out0, dst + 0); \ + ST_UB(out1, dst + 16); \ + ST_UB(out2, dst + 32); \ + ST_UB(out3, dst + 48); \ +} while (0) + +#define STORE8_4(a0, a1, a2, a3, dst) do { \ + v16u8 tmp0, tmp1, tmp2, tmp3; \ + ILVR_B2_UB(a1, a0, a3, a2, tmp0, tmp1); \ + ILVRL_H2_UB(tmp1, tmp0, tmp2, tmp3); \ + ST_UB(tmp2, dst + 0); \ + ST_UB(tmp3, dst + 16); \ +} while (0) + +#define STORE2_16(a0, a1, dst) do { \ + v16u8 out0, out1; \ + ILVRL_B2_UB(a1, a0, out0, out1); \ + ST_UB(out0, dst + 0); \ + ST_UB(out1, dst + 16); \ +} while (0) + +#define STORE2_8(a0, a1, dst) do { \ + const v16u8 out0 = (v16u8)__msa_ilvr_b((v16i8)a1, (v16i8)a0); \ + ST_UB(out0, dst); \ +} while (0) + +#define CALC_RGBA4444(y, u, v, out0, out1, N, dst) do { \ + CALC_RGB##N(y, u, v, R, G, B); \ + tmp0 = ANDI_B(R, 0xf0); \ + tmp1 = SRAI_B(G, 4); \ + RG = tmp0 | tmp1; \ + tmp0 = ANDI_B(B, 0xf0); \ + BA = ORI_B(tmp0, 0x0f); \ + STORE2_##N(out0, out1, dst); \ +} while (0) + +#define CALC_RGB565(y, u, v, out0, out1, N, dst) do { \ + CALC_RGB##N(y, u, v, R, G, B); \ + tmp0 = ANDI_B(R, 0xf8); \ + tmp1 = SRAI_B(G, 5); \ + RG = tmp0 | tmp1; \ + tmp0 = SLLI_B(G, 3); \ + tmp1 = ANDI_B(tmp0, 0xe0); \ + tmp0 = SRAI_B(B, 3); \ + GB = tmp0 | tmp1; \ + STORE2_##N(out0, out1, dst); \ +} while (0) + +static WEBP_INLINE int Clip8(int v) { + return v < 0 ? 0 : v > 255 ? 255 : v; +} + +static void YuvToRgb(int y, int u, int v, uint8_t* const rgb) { + const int y1 = MultHi(y, 19077); + const int r1 = y1 + MultHi(v, 26149) - 14234; + const int g1 = y1 - MultHi(u, 6419) - MultHi(v, 13320) + 8708; + const int b1 = y1 + MultHi(u, 33050) - 17685; + rgb[0] = Clip8(r1 >> 6); + rgb[1] = Clip8(g1 >> 6); + rgb[2] = Clip8(b1 >> 6); +} + +static void YuvToBgr(int y, int u, int v, uint8_t* const bgr) { + const int y1 = MultHi(y, 19077); + const int r1 = y1 + MultHi(v, 26149) - 14234; + const int g1 = y1 - MultHi(u, 6419) - MultHi(v, 13320) + 8708; + const int b1 = y1 + MultHi(u, 33050) - 17685; + bgr[0] = Clip8(b1 >> 6); + bgr[1] = Clip8(g1 >> 6); + bgr[2] = Clip8(r1 >> 6); +} + +static void YuvToRgb565(int y, int u, int v, uint8_t* const rgb) { + const int y1 = MultHi(y, 19077); + const int r1 = y1 + MultHi(v, 26149) - 14234; + const int g1 = y1 - MultHi(u, 6419) - MultHi(v, 13320) + 8708; + const int b1 = y1 + MultHi(u, 33050) - 17685; + const int r = Clip8(r1 >> 6); + const int g = Clip8(g1 >> 6); + const int b = Clip8(b1 >> 6); + const int rg = (r & 0xf8) | (g >> 5); + const int gb = ((g << 3) & 0xe0) | (b >> 3); +#ifdef WEBP_SWAP_16BIT_CSP + rgb[0] = gb; + rgb[1] = rg; +#else + rgb[0] = rg; + rgb[1] = gb; +#endif +} + +static void YuvToRgba4444(int y, int u, int v, uint8_t* const argb) { + const int y1 = MultHi(y, 19077); + const int r1 = y1 + MultHi(v, 26149) - 14234; + const int g1 = y1 - MultHi(u, 6419) - MultHi(v, 13320) + 8708; + const int b1 = y1 + MultHi(u, 33050) - 17685; + const int r = Clip8(r1 >> 6); + const int g = Clip8(g1 >> 6); + const int b = Clip8(b1 >> 6); + const int rg = (r & 0xf0) | (g >> 4); + const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits +#ifdef WEBP_SWAP_16BIT_CSP + argb[0] = ba; + argb[1] = rg; +#else + argb[0] = rg; + argb[1] = ba; +#endif +} + +static void YuvToArgb(uint8_t y, uint8_t u, uint8_t v, uint8_t* const argb) { + argb[0] = 0xff; + YuvToRgb(y, u, v, argb + 1); +} + +static void YuvToBgra(uint8_t y, uint8_t u, uint8_t v, uint8_t* const bgra) { + YuvToBgr(y, u, v, bgra); + bgra[3] = 0xff; +} + +static void YuvToRgba(uint8_t y, uint8_t u, uint8_t v, uint8_t* const rgba) { + YuvToRgb(y, u, v, rgba); + rgba[3] = 0xff; +} + +static void YuvToRgbLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_3(R, G, B, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 3; + length -= 16; + } + if (length > 8) { + uint8_t temp[3 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(temp, u, v, R, G, B); + STORE16_3(R, G, B, temp); + memcpy(dst, temp, length * 3 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[3 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_3(R, G, B, temp); + memcpy(dst, temp, length * 3 * sizeof(*dst)); + } +} + +static void YuvToBgrLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_3(B, G, R, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 3; + length -= 16; + } + if (length > 8) { + uint8_t temp[3 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(temp, u, v, R, G, B); + STORE16_3(B, G, R, temp); + memcpy(dst, temp, length * 3 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[3 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_3(B, G, R, temp); + memcpy(dst, temp, length * 3 * sizeof(*dst)); + } +} + +static void YuvToRgbaLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + const v16u8 A = (v16u8)__msa_ldi_b(0xff); + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_4(R, G, B, A, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 4; + length -= 16; + } + if (length > 8) { + uint8_t temp[4 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(&temp[0], u, v, R, G, B); + STORE16_4(R, G, B, A, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[4 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_4(R, G, B, A, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } +} + +static void YuvToBgraLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + const v16u8 A = (v16u8)__msa_ldi_b(0xff); + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_4(B, G, R, A, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 4; + length -= 16; + } + if (length > 8) { + uint8_t temp[4 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(temp, u, v, R, G, B); + STORE16_4(B, G, R, A, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[4 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_4(B, G, R, A, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } +} + +static void YuvToArgbLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + const v16u8 A = (v16u8)__msa_ldi_b(0xff); + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_4(A, R, G, B, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 4; + length -= 16; + } + if (length > 8) { + uint8_t temp[4 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(temp, u, v, R, G, B); + STORE16_4(A, R, G, B, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[4 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_4(A, R, G, B, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } +} + +static void YuvToRgba4444Line(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B, RG, BA, tmp0, tmp1; + while (length >= 16) { + #ifdef WEBP_SWAP_16BIT_CSP + CALC_RGBA4444(y, u, v, BA, RG, 16, dst); + #else + CALC_RGBA4444(y, u, v, RG, BA, 16, dst); + #endif + y += 16; + u += 16; + v += 16; + dst += 16 * 2; + length -= 16; + } + if (length > 8) { + uint8_t temp[2 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); +#ifdef WEBP_SWAP_16BIT_CSP + CALC_RGBA4444(temp, u, v, BA, RG, 16, temp); +#else + CALC_RGBA4444(temp, u, v, RG, BA, 16, temp); +#endif + memcpy(dst, temp, length * 2 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[2 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); +#ifdef WEBP_SWAP_16BIT_CSP + CALC_RGBA4444(temp, u, v, BA, RG, 8, temp); +#else + CALC_RGBA4444(temp, u, v, RG, BA, 8, temp); +#endif + memcpy(dst, temp, length * 2 * sizeof(*dst)); + } +} + +static void YuvToRgb565Line(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B, RG, GB, tmp0, tmp1; + while (length >= 16) { + #ifdef WEBP_SWAP_16BIT_CSP + CALC_RGB565(y, u, v, GB, RG, 16, dst); + #else + CALC_RGB565(y, u, v, RG, GB, 16, dst); + #endif + y += 16; + u += 16; + v += 16; + dst += 16 * 2; + length -= 16; + } + if (length > 8) { + uint8_t temp[2 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); +#ifdef WEBP_SWAP_16BIT_CSP + CALC_RGB565(temp, u, v, GB, RG, 16, temp); +#else + CALC_RGB565(temp, u, v, RG, GB, 16, temp); +#endif + memcpy(dst, temp, length * 2 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[2 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); +#ifdef WEBP_SWAP_16BIT_CSP + CALC_RGB565(temp, u, v, GB, RG, 8, temp); +#else + CALC_RGB565(temp, u, v, RG, GB, 8, temp); +#endif + memcpy(dst, temp, length * 2 * sizeof(*dst)); + } +} + +#define UPSAMPLE_32PIXELS(a, b, c, d) do { \ + v16u8 s = __msa_aver_u_b(a, d); \ + v16u8 t = __msa_aver_u_b(b, c); \ + const v16u8 st = s ^ t; \ + v16u8 ad = a ^ d; \ + v16u8 bc = b ^ c; \ + v16u8 t0 = ad | bc; \ + v16u8 t1 = t0 | st; \ + v16u8 t2 = ANDI_B(t1, 1); \ + v16u8 t3 = __msa_aver_u_b(s, t); \ + const v16u8 k = t3 - t2; \ + v16u8 diag1, diag2; \ + AVER_UB2_UB(t, k, s, k, t0, t1); \ + bc = bc & st; \ + ad = ad & st; \ + t = t ^ k; \ + s = s ^ k; \ + t2 = bc | t; \ + t3 = ad | s; \ + t2 = ANDI_B(t2, 1); \ + t3 = ANDI_B(t3, 1); \ + SUB2(t0, t2, t1, t3, diag1, diag2); \ + AVER_UB2_UB(a, diag1, b, diag2, t0, t1); \ + ILVRL_B2_UB(t1, t0, a, b); \ + if (pbot_y != NULL) { \ + AVER_UB2_UB(c, diag2, d, diag1, t0, t1); \ + ILVRL_B2_UB(t1, t0, c, d); \ + } \ +} while (0) + +#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bot_dst, int len) \ +{ \ + int size = (len - 1) >> 1; \ + uint8_t temp_u[64]; \ + uint8_t temp_v[64]; \ + const uint32_t tl_uv = ((top_u[0]) | ((top_v[0]) << 16)); \ + const uint32_t l_uv = ((cur_u[0]) | ((cur_v[0]) << 16)); \ + const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ + const uint8_t* ptop_y = &top_y[1]; \ + uint8_t *ptop_dst = top_dst + XSTEP; \ + const uint8_t* pbot_y = &bot_y[1]; \ + uint8_t *pbot_dst = bot_dst + XSTEP; \ + \ + FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \ + if (bot_y != NULL) { \ + const uint32_t uv1 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ + FUNC(bot_y[0], uv1 & 0xff, (uv1 >> 16), bot_dst); \ + } \ + while (size >= 16) { \ + v16u8 tu0, tu1, tv0, tv1, cu0, cu1, cv0, cv1; \ + LD_UB2(top_u, 1, tu0, tu1); \ + LD_UB2(cur_u, 1, cu0, cu1); \ + LD_UB2(top_v, 1, tv0, tv1); \ + LD_UB2(cur_v, 1, cv0, cv1); \ + UPSAMPLE_32PIXELS(tu0, tu1, cu0, cu1); \ + UPSAMPLE_32PIXELS(tv0, tv1, cv0, cv1); \ + ST_UB4(tu0, tu1, cu0, cu1, &temp_u[0], 16); \ + ST_UB4(tv0, tv1, cv0, cv1, &temp_v[0], 16); \ + FUNC##Line(ptop_y, &temp_u[ 0], &temp_v[0], ptop_dst, 32); \ + if (bot_y != NULL) { \ + FUNC##Line(pbot_y, &temp_u[32], &temp_v[32], pbot_dst, 32); \ + } \ + ptop_y += 32; \ + pbot_y += 32; \ + ptop_dst += XSTEP * 32; \ + pbot_dst += XSTEP * 32; \ + top_u += 16; \ + top_v += 16; \ + cur_u += 16; \ + cur_v += 16; \ + size -= 16; \ + } \ + if (size > 0) { \ + v16u8 tu0, tu1, tv0, tv1, cu0, cu1, cv0, cv1; \ + memcpy(&temp_u[ 0], top_u, 17 * sizeof(uint8_t)); \ + memcpy(&temp_u[32], cur_u, 17 * sizeof(uint8_t)); \ + memcpy(&temp_v[ 0], top_v, 17 * sizeof(uint8_t)); \ + memcpy(&temp_v[32], cur_v, 17 * sizeof(uint8_t)); \ + LD_UB2(&temp_u[ 0], 1, tu0, tu1); \ + LD_UB2(&temp_u[32], 1, cu0, cu1); \ + LD_UB2(&temp_v[ 0], 1, tv0, tv1); \ + LD_UB2(&temp_v[32], 1, cv0, cv1); \ + UPSAMPLE_32PIXELS(tu0, tu1, cu0, cu1); \ + UPSAMPLE_32PIXELS(tv0, tv1, cv0, cv1); \ + ST_UB4(tu0, tu1, cu0, cu1, &temp_u[0], 16); \ + ST_UB4(tv0, tv1, cv0, cv1, &temp_v[0], 16); \ + FUNC##Line(ptop_y, &temp_u[ 0], &temp_v[0], ptop_dst, size * 2); \ + if (bot_y != NULL) { \ + FUNC##Line(pbot_y, &temp_u[32], &temp_v[32], pbot_dst, size * 2); \ + } \ + top_u += size; \ + top_v += size; \ + cur_u += size; \ + cur_v += size; \ + } \ + if (!(len & 1)) { \ + const uint32_t t0 = ((top_u[0]) | ((top_v[0]) << 16)); \ + const uint32_t c0 = ((cur_u[0]) | ((cur_v[0]) << 16)); \ + const uint32_t tmp0 = (3 * t0 + c0 + 0x00020002u) >> 2; \ + FUNC(top_y[len - 1], tmp0 & 0xff, (tmp0 >> 16), \ + top_dst + (len - 1) * XSTEP); \ + if (bot_y != NULL) { \ + const uint32_t tmp1 = (3 * c0 + t0 + 0x00020002u) >> 2; \ + FUNC(bot_y[len - 1], tmp1 & 0xff, (tmp1 >> 16), \ + bot_dst + (len - 1) * XSTEP); \ + } \ + } \ +} + +UPSAMPLE_FUNC(UpsampleRgbLinePair, YuvToRgb, 3) +UPSAMPLE_FUNC(UpsampleBgrLinePair, YuvToBgr, 3) +UPSAMPLE_FUNC(UpsampleRgbaLinePair, YuvToRgba, 4) +UPSAMPLE_FUNC(UpsampleBgraLinePair, YuvToBgra, 4) +UPSAMPLE_FUNC(UpsampleArgbLinePair, YuvToArgb, 4) +UPSAMPLE_FUNC(UpsampleRgba4444LinePair, YuvToRgba4444, 2) +UPSAMPLE_FUNC(UpsampleRgb565LinePair, YuvToRgb565, 2) + +//------------------------------------------------------------------------------ +// Entry point + +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +extern void WebPInitUpsamplersMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersMSA(void) { + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair; + WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair; + WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair; + WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair; + WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair; + WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair; + WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair; + WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair; + WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair; + WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair; +} + +#endif // FANCY_UPSAMPLING + +#endif // WEBP_USE_MSA + +#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_MSA)) +WEBP_DSP_INIT_STUB(WebPInitUpsamplersMSA) +#endif diff --git a/src/3rdparty/libwebp/src/dsp/upsampling_neon.c b/src/3rdparty/libwebp/src/dsp/upsampling_neon.c index 2b0c99bddb1de9d0f287b80b9d837317bf462550..d371a834ff978188bcc577a40650a488f2541121 100644 --- a/src/3rdparty/libwebp/src/dsp/upsampling_neon.c +++ b/src/3rdparty/libwebp/src/dsp/upsampling_neon.c @@ -28,47 +28,34 @@ // U/V upsampling // Loads 9 pixels each from rows r1 and r2 and generates 16 pixels. -#define UPSAMPLE_16PIXELS(r1, r2, out) { \ - uint8x8_t a = vld1_u8(r1); \ - uint8x8_t b = vld1_u8(r1 + 1); \ - uint8x8_t c = vld1_u8(r2); \ - uint8x8_t d = vld1_u8(r2 + 1); \ - \ - uint16x8_t al = vshll_n_u8(a, 1); \ - uint16x8_t bl = vshll_n_u8(b, 1); \ - uint16x8_t cl = vshll_n_u8(c, 1); \ - uint16x8_t dl = vshll_n_u8(d, 1); \ - \ - uint8x8_t diag1, diag2; \ - uint16x8_t sl; \ - \ +#define UPSAMPLE_16PIXELS(r1, r2, out) do { \ + const uint8x8_t a = vld1_u8(r1 + 0); \ + const uint8x8_t b = vld1_u8(r1 + 1); \ + const uint8x8_t c = vld1_u8(r2 + 0); \ + const uint8x8_t d = vld1_u8(r2 + 1); \ /* a + b + c + d */ \ - sl = vaddl_u8(a, b); \ - sl = vaddw_u8(sl, c); \ - sl = vaddw_u8(sl, d); \ - \ - al = vaddq_u16(sl, al); /* 3a + b + c + d */ \ - bl = vaddq_u16(sl, bl); /* a + 3b + c + d */ \ - \ - al = vaddq_u16(al, dl); /* 3a + b + c + 3d */ \ - bl = vaddq_u16(bl, cl); /* a + 3b + 3c + d */ \ + const uint16x8_t ad = vaddl_u8(a, d); \ + const uint16x8_t bc = vaddl_u8(b, c); \ + const uint16x8_t abcd = vaddq_u16(ad, bc); \ + /* 3a + b + c + 3d */ \ + const uint16x8_t al = vaddq_u16(abcd, vshlq_n_u16(ad, 1)); \ + /* a + 3b + 3c + d */ \ + const uint16x8_t bl = vaddq_u16(abcd, vshlq_n_u16(bc, 1)); \ \ - diag2 = vshrn_n_u16(al, 3); \ - diag1 = vshrn_n_u16(bl, 3); \ + const uint8x8_t diag2 = vshrn_n_u16(al, 3); \ + const uint8x8_t diag1 = vshrn_n_u16(bl, 3); \ \ - a = vrhadd_u8(a, diag1); \ - b = vrhadd_u8(b, diag2); \ - c = vrhadd_u8(c, diag2); \ - d = vrhadd_u8(d, diag1); \ + const uint8x8_t A = vrhadd_u8(a, diag1); \ + const uint8x8_t B = vrhadd_u8(b, diag2); \ + const uint8x8_t C = vrhadd_u8(c, diag2); \ + const uint8x8_t D = vrhadd_u8(d, diag1); \ \ - { \ - uint8x8x2_t a_b, c_d; \ - INIT_VECTOR2(a_b, a, b); \ - INIT_VECTOR2(c_d, c, d); \ - vst2_u8(out, a_b); \ - vst2_u8(out + 32, c_d); \ - } \ -} + uint8x8x2_t A_B, C_D; \ + INIT_VECTOR2(A_B, A, B); \ + INIT_VECTOR2(C_D, C, D); \ + vst2_u8(out + 0, A_B); \ + vst2_u8(out + 32, C_D); \ +} while (0) // Turn the macro into a function for reducing code-size when non-critical static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2, @@ -93,7 +80,6 @@ static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2, static const int16_t kCoeffs1[4] = { 19077, 26149, 6419, 13320 }; #define v255 vdup_n_u8(255) -#define v_0x0f vdup_n_u8(15) #define STORE_Rgb(out, r, g, b) do { \ uint8x8x3_t r_g_b; \ @@ -132,21 +118,16 @@ static const int16_t kCoeffs1[4] = { 19077, 26149, 6419, 13320 }; #endif #define STORE_Rgba4444(out, r, g, b) do { \ - const uint8x8_t r1 = vshl_n_u8(vshr_n_u8(r, 4), 4); /* 4bits */ \ - const uint8x8_t g1 = vshr_n_u8(g, 4); \ - const uint8x8_t ba = vorr_u8(b, v_0x0f); \ - const uint8x8_t rg = vorr_u8(r1, g1); \ + const uint8x8_t rg = vsri_n_u8(r, g, 4); /* shift g, insert r */ \ + const uint8x8_t ba = vsri_n_u8(b, v255, 4); /* shift a, insert b */ \ const uint8x8x2_t rgba4444 = ZIP_U8(rg, ba); \ vst1q_u8(out, vcombine_u8(rgba4444.val[0], rgba4444.val[1])); \ } while (0) #define STORE_Rgb565(out, r, g, b) do { \ - const uint8x8_t r1 = vshl_n_u8(vshr_n_u8(r, 3), 3); /* 5bits */ \ - const uint8x8_t g1 = vshr_n_u8(g, 5); /* upper 3bits */\ - const uint8x8_t g2 = vshl_n_u8(vshr_n_u8(g, 2), 5); /* lower 3bits */\ - const uint8x8_t b1 = vshr_n_u8(b, 3); /* 5bits */ \ - const uint8x8_t rg = vorr_u8(r1, g1); \ - const uint8x8_t gb = vorr_u8(g2, b1); \ + const uint8x8_t rg = vsri_n_u8(r, g, 5); /* shift g and insert r */ \ + const uint8x8_t g1 = vshl_n_u8(g, 3); /* pre-shift g: 3bits */ \ + const uint8x8_t gb = vsri_n_u8(g1, b, 3); /* shift b and insert g */ \ const uint8x8x2_t rgb565 = ZIP_U8(rg, gb); \ vst1q_u8(out, vcombine_u8(rgb565.val[0], rgb565.val[1])); \ } while (0) diff --git a/src/3rdparty/libwebp/src/dsp/yuv.c b/src/3rdparty/libwebp/src/dsp/yuv.c index f50a253168fee677de8effcd772d846cdeb3f3dd..dd7d9dedfa7ee37ed0e8bdcce496723f63653efb 100644 --- a/src/3rdparty/libwebp/src/dsp/yuv.c +++ b/src/3rdparty/libwebp/src/dsp/yuv.c @@ -13,6 +13,8 @@ #include "./yuv.h" +#include <stdlib.h> + #if defined(WEBP_YUV_USE_TABLE) static int done = 0; @@ -244,6 +246,48 @@ void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, //----------------------------------------------------------------------------- +#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic +static uint16_t clip_y(int v) { + return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v; +} + +static uint64_t SharpYUVUpdateY_C(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len) { + uint64_t diff = 0; + int i; + for (i = 0; i < len; ++i) { + const int diff_y = ref[i] - src[i]; + const int new_y = (int)dst[i] + diff_y; + dst[i] = clip_y(new_y); + diff += (uint64_t)abs(diff_y); + } + return diff; +} + +static void SharpYUVUpdateRGB_C(const int16_t* ref, const int16_t* src, + int16_t* dst, int len) { + int i; + for (i = 0; i < len; ++i) { + const int diff_uv = ref[i] - src[i]; + dst[i] += diff_uv; + } +} + +static void SharpYUVFilterRow_C(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out) { + int i; + for (i = 0; i < len; ++i, ++A, ++B) { + const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4; + const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4; + out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0); + out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1); + } +} + +#undef MAX_Y + +//----------------------------------------------------------------------------- + void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width); void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width); void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb, @@ -253,10 +297,18 @@ void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width); void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v, int src_width, int do_store); +uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len); +void (*WebPSharpYUVUpdateRGB)(const int16_t* ref, const int16_t* src, + int16_t* dst, int len); +void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out); + static volatile VP8CPUInfo rgba_to_yuv_last_cpuinfo_used = (VP8CPUInfo)&rgba_to_yuv_last_cpuinfo_used; extern void WebPInitConvertARGBToYUVSSE2(void); +extern void WebPInitSharpYUVSSE2(void); WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) { if (rgba_to_yuv_last_cpuinfo_used == VP8GetCPUInfo) return; @@ -269,10 +321,15 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) { WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C; + WebPSharpYUVUpdateY = SharpYUVUpdateY_C; + WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_C; + WebPSharpYUVFilterRow = SharpYUVFilterRow_C; + if (VP8GetCPUInfo != NULL) { #if defined(WEBP_USE_SSE2) if (VP8GetCPUInfo(kSSE2)) { WebPInitConvertARGBToYUVSSE2(); + WebPInitSharpYUVSSE2(); } #endif // WEBP_USE_SSE2 } diff --git a/src/3rdparty/libwebp/src/dsp/yuv.h b/src/3rdparty/libwebp/src/dsp/yuv.h index 01c40fcb8465d434bac4845028609d3383f889b5..1d33b5863be4880d4b6368b8d993b4dd76b7cbaf 100644 --- a/src/3rdparty/libwebp/src/dsp/yuv.h +++ b/src/3rdparty/libwebp/src/dsp/yuv.h @@ -36,7 +36,7 @@ #define WEBP_DSP_YUV_H_ #include "./dsp.h" -#include "../dec/decode_vp8.h" +#include "../dec/vp8_dec.h" #if defined(WEBP_EXPERIMENTAL_FEATURES) // Do NOT activate this feature for real compression. This is only experimental! diff --git a/src/3rdparty/libwebp/src/dsp/yuv_sse2.c b/src/3rdparty/libwebp/src/dsp/yuv_sse2.c index e19bddff6c5d17819d602730d3e1c032c70ddc79..e33c2bbafde4714ae5157dc8c83b08fe43d023d2 100644 --- a/src/3rdparty/libwebp/src/dsp/yuv_sse2.c +++ b/src/3rdparty/libwebp/src/dsp/yuv_sse2.c @@ -15,6 +15,8 @@ #if defined(WEBP_USE_SSE2) +#include "./common_sse2.h" +#include <stdlib.h> #include <emmintrin.h> //----------------------------------------------------------------------------- @@ -155,30 +157,13 @@ static WEBP_INLINE void PackAndStore565(const __m128i* const R, _mm_storeu_si128((__m128i*)dst, rgb565); } -// Function used several times in PlanarTo24b. -// It samples the in buffer as follows: one every two unsigned char is stored -// at the beginning of the buffer, while the other half is stored at the end. -static WEBP_INLINE void PlanarTo24bHelper(const __m128i* const in /*in[6]*/, - __m128i* const out /*out[6]*/) { - const __m128i v_mask = _mm_set1_epi16(0x00ff); - - // Take one every two upper 8b values. - out[0] = _mm_packus_epi16(_mm_and_si128(in[0], v_mask), - _mm_and_si128(in[1], v_mask)); - out[1] = _mm_packus_epi16(_mm_and_si128(in[2], v_mask), - _mm_and_si128(in[3], v_mask)); - out[2] = _mm_packus_epi16(_mm_and_si128(in[4], v_mask), - _mm_and_si128(in[5], v_mask)); - // Take one every two lower 8b values. - out[3] = _mm_packus_epi16(_mm_srli_epi16(in[0], 8), _mm_srli_epi16(in[1], 8)); - out[4] = _mm_packus_epi16(_mm_srli_epi16(in[2], 8), _mm_srli_epi16(in[3], 8)); - out[5] = _mm_packus_epi16(_mm_srli_epi16(in[4], 8), _mm_srli_epi16(in[5], 8)); -} - // Pack the planar buffers // rrrr... rrrr... gggg... gggg... bbbb... bbbb.... // triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... -static WEBP_INLINE void PlanarTo24b(__m128i* const in /*in[6]*/, uint8_t* rgb) { +static WEBP_INLINE void PlanarTo24b(__m128i* const in0, __m128i* const in1, + __m128i* const in2, __m128i* const in3, + __m128i* const in4, __m128i* const in5, + uint8_t* const rgb) { // The input is 6 registers of sixteen 8b but for the sake of explanation, // let's take 6 registers of four 8b values. // To pack, we will keep taking one every two 8b integer and move it @@ -191,22 +176,15 @@ static WEBP_INLINE void PlanarTo24b(__m128i* const in /*in[6]*/, uint8_t* rgb) { // Repeat the same permutations twice more: // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7 // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7 - __m128i tmp[6]; - PlanarTo24bHelper(in, tmp); - PlanarTo24bHelper(tmp, in); - PlanarTo24bHelper(in, tmp); - // We need to do it two more times than the example as we have sixteen bytes. - PlanarTo24bHelper(tmp, in); - PlanarTo24bHelper(in, tmp); - - _mm_storeu_si128((__m128i*)(rgb + 0), tmp[0]); - _mm_storeu_si128((__m128i*)(rgb + 16), tmp[1]); - _mm_storeu_si128((__m128i*)(rgb + 32), tmp[2]); - _mm_storeu_si128((__m128i*)(rgb + 48), tmp[3]); - _mm_storeu_si128((__m128i*)(rgb + 64), tmp[4]); - _mm_storeu_si128((__m128i*)(rgb + 80), tmp[5]); -} -#undef MK_UINT32 + VP8PlanarTo24b(in0, in1, in2, in3, in4, in5); + + _mm_storeu_si128((__m128i*)(rgb + 0), *in0); + _mm_storeu_si128((__m128i*)(rgb + 16), *in1); + _mm_storeu_si128((__m128i*)(rgb + 32), *in2); + _mm_storeu_si128((__m128i*)(rgb + 48), *in3); + _mm_storeu_si128((__m128i*)(rgb + 64), *in4); + _mm_storeu_si128((__m128i*)(rgb + 80), *in5); +} void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v, uint8_t* dst) { @@ -265,29 +243,29 @@ void VP8YuvToRgb56532(const uint8_t* y, const uint8_t* u, const uint8_t* v, void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v, uint8_t* dst) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; - __m128i rgb[6]; + __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; - YUV444ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0); - YUV444ToRGB(y + 8, u + 8, v + 8, &R1, &G1, &B1); + YUV444ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV444ToRGB(y + 8, u + 8, v + 8, &R1, &G1, &B1); YUV444ToRGB(y + 16, u + 16, v + 16, &R2, &G2, &B2); YUV444ToRGB(y + 24, u + 24, v + 24, &R3, &G3, &B3); // Cast to 8b and store as RRRRGGGGBBBB. - rgb[0] = _mm_packus_epi16(R0, R1); - rgb[1] = _mm_packus_epi16(R2, R3); - rgb[2] = _mm_packus_epi16(G0, G1); - rgb[3] = _mm_packus_epi16(G2, G3); - rgb[4] = _mm_packus_epi16(B0, B1); - rgb[5] = _mm_packus_epi16(B2, B3); + rgb0 = _mm_packus_epi16(R0, R1); + rgb1 = _mm_packus_epi16(R2, R3); + rgb2 = _mm_packus_epi16(G0, G1); + rgb3 = _mm_packus_epi16(G2, G3); + rgb4 = _mm_packus_epi16(B0, B1); + rgb5 = _mm_packus_epi16(B2, B3); // Pack as RGBRGBRGBRGB. - PlanarTo24b(rgb, dst); + PlanarTo24b(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); } void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v, uint8_t* dst) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; - __m128i bgr[6]; + __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; YUV444ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0); YUV444ToRGB(y + 8, u + 8, v + 8, &R1, &G1, &B1); @@ -295,15 +273,15 @@ void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v, YUV444ToRGB(y + 24, u + 24, v + 24, &R3, &G3, &B3); // Cast to 8b and store as BBBBGGGGRRRR. - bgr[0] = _mm_packus_epi16(B0, B1); - bgr[1] = _mm_packus_epi16(B2, B3); - bgr[2] = _mm_packus_epi16(G0, G1); - bgr[3] = _mm_packus_epi16(G2, G3); - bgr[4] = _mm_packus_epi16(R0, R1); - bgr[5] = _mm_packus_epi16(R2, R3); + bgr0 = _mm_packus_epi16(B0, B1); + bgr1 = _mm_packus_epi16(B2, B3); + bgr2 = _mm_packus_epi16(G0, G1); + bgr3 = _mm_packus_epi16(G2, G3); + bgr4 = _mm_packus_epi16(R0, R1); + bgr5= _mm_packus_epi16(R2, R3); // Pack as BGRBGRBGRBGR. - PlanarTo24b(bgr, dst); + PlanarTo24b(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst); } //----------------------------------------------------------------------------- @@ -377,7 +355,7 @@ static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v, int n; for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; - __m128i rgb[6]; + __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; YUV420ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0); YUV420ToRGB(y + 8, u + 4, v + 4, &R1, &G1, &B1); @@ -385,15 +363,15 @@ static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v, YUV420ToRGB(y + 24, u + 12, v + 12, &R3, &G3, &B3); // Cast to 8b and store as RRRRGGGGBBBB. - rgb[0] = _mm_packus_epi16(R0, R1); - rgb[1] = _mm_packus_epi16(R2, R3); - rgb[2] = _mm_packus_epi16(G0, G1); - rgb[3] = _mm_packus_epi16(G2, G3); - rgb[4] = _mm_packus_epi16(B0, B1); - rgb[5] = _mm_packus_epi16(B2, B3); + rgb0 = _mm_packus_epi16(R0, R1); + rgb1 = _mm_packus_epi16(R2, R3); + rgb2 = _mm_packus_epi16(G0, G1); + rgb3 = _mm_packus_epi16(G2, G3); + rgb4 = _mm_packus_epi16(B0, B1); + rgb5 = _mm_packus_epi16(B2, B3); // Pack as RGBRGBRGBRGB. - PlanarTo24b(rgb, dst); + PlanarTo24b(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); y += 32; u += 16; @@ -413,7 +391,7 @@ static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v, int n; for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; - __m128i bgr[6]; + __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; YUV420ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0); YUV420ToRGB(y + 8, u + 4, v + 4, &R1, &G1, &B1); @@ -421,15 +399,15 @@ static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v, YUV420ToRGB(y + 24, u + 12, v + 12, &R3, &G3, &B3); // Cast to 8b and store as BBBBGGGGRRRR. - bgr[0] = _mm_packus_epi16(B0, B1); - bgr[1] = _mm_packus_epi16(B2, B3); - bgr[2] = _mm_packus_epi16(G0, G1); - bgr[3] = _mm_packus_epi16(G2, G3); - bgr[4] = _mm_packus_epi16(R0, R1); - bgr[5] = _mm_packus_epi16(R2, R3); + bgr0 = _mm_packus_epi16(B0, B1); + bgr1 = _mm_packus_epi16(B2, B3); + bgr2 = _mm_packus_epi16(G0, G1); + bgr3 = _mm_packus_epi16(G2, G3); + bgr4 = _mm_packus_epi16(R0, R1); + bgr5 = _mm_packus_epi16(R2, R3); // Pack as BGRBGRBGRBGR. - PlanarTo24b(bgr, dst); + PlanarTo24b(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst); y += 32; u += 16; @@ -499,25 +477,19 @@ static WEBP_INLINE void RGB24PackedToPlanar(const uint8_t* const rgb, // Convert 8 packed ARGB to r[], g[], b[] static WEBP_INLINE void RGB32PackedToPlanar(const uint32_t* const argb, - __m128i* const r, - __m128i* const g, - __m128i* const b) { + __m128i* const rgb /*in[6]*/) { const __m128i zero = _mm_setzero_si128(); - const __m128i in0 = LOAD_16(argb + 0); // argb3 | argb2 | argb1 | argb0 - const __m128i in1 = LOAD_16(argb + 4); // argb7 | argb6 | argb5 | argb4 - // column-wise transpose - const __m128i A0 = _mm_unpacklo_epi8(in0, in1); - const __m128i A1 = _mm_unpackhi_epi8(in0, in1); - const __m128i B0 = _mm_unpacklo_epi8(A0, A1); - const __m128i B1 = _mm_unpackhi_epi8(A0, A1); - // C0 = g7 g6 ... g1 g0 | b7 b6 ... b1 b0 - // C1 = a7 a6 ... a1 a0 | r7 r6 ... r1 r0 - const __m128i C0 = _mm_unpacklo_epi8(B0, B1); - const __m128i C1 = _mm_unpackhi_epi8(B0, B1); - // store 16b - *r = _mm_unpacklo_epi8(C1, zero); - *g = _mm_unpackhi_epi8(C0, zero); - *b = _mm_unpacklo_epi8(C0, zero); + __m128i a0 = LOAD_16(argb + 0); + __m128i a1 = LOAD_16(argb + 4); + __m128i a2 = LOAD_16(argb + 8); + __m128i a3 = LOAD_16(argb + 12); + VP8L32bToPlanar(&a0, &a1, &a2, &a3); + rgb[0] = _mm_unpacklo_epi8(a1, zero); + rgb[1] = _mm_unpackhi_epi8(a1, zero); + rgb[2] = _mm_unpacklo_epi8(a2, zero); + rgb[3] = _mm_unpackhi_epi8(a2, zero); + rgb[4] = _mm_unpacklo_epi8(a3, zero); + rgb[5] = _mm_unpackhi_epi8(a3, zero); } // This macro computes (RG * MULT_RG + GB * MULT_GB + ROUNDER) >> DESCALE_FIX @@ -649,11 +621,10 @@ static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) { const int max_width = width & ~15; int i; for (i = 0; i < max_width; i += 16) { - __m128i r, g, b, Y0, Y1; - RGB32PackedToPlanar(&argb[i + 0], &r, &g, &b); - ConvertRGBToY(&r, &g, &b, &Y0); - RGB32PackedToPlanar(&argb[i + 8], &r, &g, &b); - ConvertRGBToY(&r, &g, &b, &Y1); + __m128i Y0, Y1, rgb[6]; + RGB32PackedToPlanar(&argb[i], rgb); + ConvertRGBToY(&rgb[0], &rgb[2], &rgb[4], &Y0); + ConvertRGBToY(&rgb[1], &rgb[3], &rgb[5], &Y1); STORE_16(_mm_packus_epi16(Y0, Y1), y + i); } for (; i < width; ++i) { // left-over @@ -678,20 +649,18 @@ static void ConvertARGBToUV(const uint32_t* argb, uint8_t* u, uint8_t* v, const int max_width = src_width & ~31; int i; for (i = 0; i < max_width; i += 32, u += 16, v += 16) { - __m128i r0, g0, b0, r1, g1, b1, U0, V0, U1, V1; - RGB32PackedToPlanar(&argb[i + 0], &r0, &g0, &b0); - RGB32PackedToPlanar(&argb[i + 8], &r1, &g1, &b1); - HorizontalAddPack(&r0, &r1, &r0); - HorizontalAddPack(&g0, &g1, &g0); - HorizontalAddPack(&b0, &b1, &b0); - ConvertRGBToUV(&r0, &g0, &b0, &U0, &V0); - - RGB32PackedToPlanar(&argb[i + 16], &r0, &g0, &b0); - RGB32PackedToPlanar(&argb[i + 24], &r1, &g1, &b1); - HorizontalAddPack(&r0, &r1, &r0); - HorizontalAddPack(&g0, &g1, &g0); - HorizontalAddPack(&b0, &b1, &b0); - ConvertRGBToUV(&r0, &g0, &b0, &U1, &V1); + __m128i rgb[6], U0, V0, U1, V1; + RGB32PackedToPlanar(&argb[i], rgb); + HorizontalAddPack(&rgb[0], &rgb[1], &rgb[0]); + HorizontalAddPack(&rgb[2], &rgb[3], &rgb[2]); + HorizontalAddPack(&rgb[4], &rgb[5], &rgb[4]); + ConvertRGBToUV(&rgb[0], &rgb[2], &rgb[4], &U0, &V0); + + RGB32PackedToPlanar(&argb[i + 16], rgb); + HorizontalAddPack(&rgb[0], &rgb[1], &rgb[0]); + HorizontalAddPack(&rgb[2], &rgb[3], &rgb[2]); + HorizontalAddPack(&rgb[4], &rgb[5], &rgb[4]); + ConvertRGBToUV(&rgb[0], &rgb[2], &rgb[4], &U1, &V1); U0 = _mm_packus_epi16(U0, U1); V0 = _mm_packus_epi16(V0, V1); @@ -767,9 +736,128 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) { WebPConvertRGBA32ToUV = ConvertRGBA32ToUV; } +//------------------------------------------------------------------------------ + +#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic +static uint16_t clip_y(int v) { + return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v; +} + +static uint64_t SharpYUVUpdateY_SSE2(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len) { + uint64_t diff = 0; + uint32_t tmp[4]; + int i; + const __m128i zero = _mm_setzero_si128(); + const __m128i max = _mm_set1_epi16(MAX_Y); + const __m128i one = _mm_set1_epi16(1); + __m128i sum = zero; + + for (i = 0; i + 8 <= len; i += 8) { + const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); + const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); + const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); + const __m128i D = _mm_sub_epi16(A, B); // diff_y + const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0) + const __m128i F = _mm_add_epi16(C, D); // new_y + const __m128i G = _mm_or_si128(E, one); // -1 or 1 + const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero); + const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...)) + _mm_storeu_si128((__m128i*)(dst + i), H); + sum = _mm_add_epi32(sum, I); + } + _mm_storeu_si128((__m128i*)tmp, sum); + diff = tmp[3] + tmp[2] + tmp[1] + tmp[0]; + for (; i < len; ++i) { + const int diff_y = ref[i] - src[i]; + const int new_y = (int)dst[i] + diff_y; + dst[i] = clip_y(new_y); + diff += (uint64_t)abs(diff_y); + } + return diff; +} + +static void SharpYUVUpdateRGB_SSE2(const int16_t* ref, const int16_t* src, + int16_t* dst, int len) { + int i = 0; + for (i = 0; i + 8 <= len; i += 8) { + const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); + const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); + const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); + const __m128i D = _mm_sub_epi16(A, B); // diff_uv + const __m128i E = _mm_add_epi16(C, D); // new_uv + _mm_storeu_si128((__m128i*)(dst + i), E); + } + for (; i < len; ++i) { + const int diff_uv = ref[i] - src[i]; + dst[i] += diff_uv; + } +} + +static void SharpYUVFilterRow_SSE2(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out) { + int i; + const __m128i kCst8 = _mm_set1_epi16(8); + const __m128i max = _mm_set1_epi16(MAX_Y); + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 8 <= len; i += 8) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0)); + const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1)); + const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0)); + const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1)); + const __m128i a0b1 = _mm_add_epi16(a0, b1); + const __m128i a1b0 = _mm_add_epi16(a1, b0); + const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1 + const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8); + const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1) + const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0) + const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3); + const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3); + const __m128i d0 = _mm_add_epi16(c1, a0); + const __m128i d1 = _mm_add_epi16(c0, a1); + const __m128i e0 = _mm_srai_epi16(d0, 1); + const __m128i e1 = _mm_srai_epi16(d1, 1); + const __m128i f0 = _mm_unpacklo_epi16(e0, e1); + const __m128i f1 = _mm_unpackhi_epi16(e0, e1); + const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0)); + const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8)); + const __m128i h0 = _mm_add_epi16(g0, f0); + const __m128i h1 = _mm_add_epi16(g1, f1); + const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero); + const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero); + _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0); + _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1); + } + for (; i < len; ++i) { + // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 = + // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4 + // We reuse the common sub-expressions. + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0); + out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1); + } +} + +#undef MAX_Y + +//------------------------------------------------------------------------------ + +extern void WebPInitSharpYUVSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVSSE2(void) { + WebPSharpYUVUpdateY = SharpYUVUpdateY_SSE2; + WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_SSE2; + WebPSharpYUVFilterRow = SharpYUVFilterRow_SSE2; +} + #else // !WEBP_USE_SSE2 WEBP_DSP_INIT_STUB(WebPInitSamplersSSE2) WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE2) +WEBP_DSP_INIT_STUB(WebPInitSharpYUVSSE2) #endif // WEBP_USE_SSE2 diff --git a/src/3rdparty/libwebp/src/enc/alpha.c b/src/3rdparty/libwebp/src/enc/alpha_enc.c similarity index 99% rename from src/3rdparty/libwebp/src/enc/alpha.c rename to src/3rdparty/libwebp/src/enc/alpha_enc.c index 03e3ad07f5f86743c32370946724fcd6bf52afbb..5a2c931f92cfcb5eb2efa5dbd2842cf7e2229ff6 100644 --- a/src/3rdparty/libwebp/src/enc/alpha.c +++ b/src/3rdparty/libwebp/src/enc/alpha_enc.c @@ -14,10 +14,10 @@ #include <assert.h> #include <stdlib.h> -#include "./vp8enci.h" +#include "./vp8i_enc.h" #include "../dsp/dsp.h" -#include "../utils/filters.h" -#include "../utils/quant_levels.h" +#include "../utils/filters_utils.h" +#include "../utils/quant_levels_utils.h" #include "../utils/utils.h" #include "../webp/format_constants.h" @@ -44,7 +44,7 @@ // invalid quality or method, or // memory allocation for the compressed data fails. -#include "../enc/vp8li.h" +#include "../enc/vp8li_enc.h" static int EncodeLossless(const uint8_t* const data, int width, int height, int effort_level, // in [0..6] range diff --git a/src/3rdparty/libwebp/src/enc/analysis.c b/src/3rdparty/libwebp/src/enc/analysis_enc.c similarity index 91% rename from src/3rdparty/libwebp/src/enc/analysis.c rename to src/3rdparty/libwebp/src/enc/analysis_enc.c index b55128fd4880631ea52d7e6a86233b0af4f473bd..dce159b316f1c2d44c6aa42cfb76d364f948252f 100644 --- a/src/3rdparty/libwebp/src/enc/analysis.c +++ b/src/3rdparty/libwebp/src/enc/analysis_enc.c @@ -15,8 +15,8 @@ #include <string.h> #include <assert.h> -#include "./vp8enci.h" -#include "./cost.h" +#include "./vp8i_enc.h" +#include "./cost_enc.h" #include "../utils/utils.h" #define MAX_ITERS_K_MEANS 6 @@ -262,6 +262,29 @@ static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) { return best_alpha; } +static int FastMBAnalyze(VP8EncIterator* const it) { + // Empirical cut-off value, should be around 16 (~=block size). We use the + // [8-17] range and favor intra4 at high quality, intra16 for low quality. + const int q = (int)it->enc_->config_->quality; + const uint32_t kThreshold = 8 + (17 - 8) * q / 100; + int k; + uint32_t dc[16], m, m2; + for (k = 0; k < 16; k += 4) { + VP8Mean16x4(it->yuv_in_ + Y_OFF_ENC + k * BPS, &dc[k]); + } + for (m = 0, m2 = 0, k = 0; k < 16; ++k) { + m += dc[k]; + m2 += dc[k] * dc[k]; + } + if (kThreshold * m2 < m * m) { + VP8SetIntra16Mode(it, 0); // DC16 + } else { + const uint8_t modes[16] = { 0 }; // DC4 + VP8SetIntra4Mode(it, modes); + } + return 0; +} + static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it, int best_alpha) { uint8_t modes[16]; @@ -307,6 +330,7 @@ static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it, static int MBAnalyzeBestUVMode(VP8EncIterator* const it) { int best_alpha = DEFAULT_ALPHA; + int smallest_alpha = 0; int best_mode = 0; const int max_mode = MAX_UV_MODE; int mode; @@ -322,6 +346,10 @@ static int MBAnalyzeBestUVMode(VP8EncIterator* const it) { alpha = GetAlpha(&histo); if (IS_BETTER_ALPHA(alpha, best_alpha)) { best_alpha = alpha; + } + // The best prediction mode tends to be the one with the smallest alpha. + if (mode == 0 || alpha < smallest_alpha) { + smallest_alpha = alpha; best_mode = mode; } } @@ -339,13 +367,17 @@ static void MBAnalyze(VP8EncIterator* const it, VP8SetSkip(it, 0); // not skipped VP8SetSegment(it, 0); // default segment, spec-wise. - best_alpha = MBAnalyzeBestIntra16Mode(it); - if (enc->method_ >= 5) { - // We go and make a fast decision for intra4/intra16. - // It's usually not a good and definitive pick, but helps seeding the stats - // about level bit-cost. - // TODO(skal): improve criterion. - best_alpha = MBAnalyzeBestIntra4Mode(it, best_alpha); + if (enc->method_ <= 1) { + best_alpha = FastMBAnalyze(it); + } else { + best_alpha = MBAnalyzeBestIntra16Mode(it); + if (enc->method_ >= 5) { + // We go and make a fast decision for intra4/intra16. + // It's usually not a good and definitive pick, but helps seeding the + // stats about level bit-cost. + // TODO(skal): improve criterion. + best_alpha = MBAnalyzeBestIntra4Mode(it, best_alpha); + } } best_uv_alpha = MBAnalyzeBestUVMode(it); @@ -448,7 +480,7 @@ int VP8EncAnalyze(VP8Encoder* const enc) { const int do_segments = enc->config_->emulate_jpeg_size || // We need the complexity evaluation. (enc->segment_hdr_.num_segments_ > 1) || - (enc->method_ == 0); // for method 0, we need preds_[] to be filled. + (enc->method_ <= 1); // for method 0 - 1, we need preds_[] to be filled. if (do_segments) { const int last_row = enc->mb_h_; // We give a little more than a half work to the main thread. diff --git a/src/3rdparty/libwebp/src/enc/backward_references.c b/src/3rdparty/libwebp/src/enc/backward_references_enc.c similarity index 87% rename from src/3rdparty/libwebp/src/enc/backward_references.c rename to src/3rdparty/libwebp/src/enc/backward_references_enc.c index 136a24a8c31c810bd8b1b228f07ad2c9681de364..7c0559ff1e146dc9c1604dd4ac7a94b959e9abb5 100644 --- a/src/3rdparty/libwebp/src/enc/backward_references.c +++ b/src/3rdparty/libwebp/src/enc/backward_references_enc.c @@ -13,11 +13,12 @@ #include <assert.h> #include <math.h> -#include "./backward_references.h" -#include "./histogram.h" +#include "./backward_references_enc.h" +#include "./histogram_enc.h" #include "../dsp/lossless.h" +#include "../dsp/lossless_common.h" #include "../dsp/dsp.h" -#include "../utils/color_cache.h" +#include "../utils/color_cache_utils.h" #include "../utils/utils.h" #define VALUES_IN_BYTE 256 @@ -30,8 +31,9 @@ #define WINDOW_SIZE_BITS 20 #define WINDOW_SIZE ((1 << WINDOW_SIZE_BITS) - 120) -// Bounds for the match length. -#define MIN_LENGTH 2 +// Minimum number of pixels for which it is cheaper to encode a +// distance + length instead of each pixel as a literal. +#define MIN_LENGTH 4 // If you change this, you need MAX_LENGTH_BITS + WINDOW_SIZE_BITS <= 32 as it // is used in VP8LHashChain. #define MAX_LENGTH_BITS 12 @@ -211,13 +213,13 @@ void VP8LHashChainClear(VP8LHashChain* const p) { // ----------------------------------------------------------------------------- -#define HASH_MULTIPLIER_HI (0xc6a4a793U) -#define HASH_MULTIPLIER_LO (0x5bd1e996U) +#define HASH_MULTIPLIER_HI (0xc6a4a793ULL) +#define HASH_MULTIPLIER_LO (0x5bd1e996ULL) static WEBP_INLINE uint32_t GetPixPairHash64(const uint32_t* const argb) { uint32_t key; - key = argb[1] * HASH_MULTIPLIER_HI; - key += argb[0] * HASH_MULTIPLIER_LO; + key = (argb[1] * HASH_MULTIPLIER_HI) & 0xffffffffu; + key += (argb[0] * HASH_MULTIPLIER_LO) & 0xffffffffu; key = key >> (32 - HASH_BITS); return key; } @@ -242,19 +244,26 @@ static WEBP_INLINE int MaxFindCopyLength(int len) { } int VP8LHashChainFill(VP8LHashChain* const p, int quality, - const uint32_t* const argb, int xsize, int ysize) { + const uint32_t* const argb, int xsize, int ysize, + int low_effort) { const int size = xsize * ysize; const int iter_max = GetMaxItersForQuality(quality); - const int iter_min = iter_max - quality / 10; const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize); int pos; + int argb_comp; uint32_t base_position; int32_t* hash_to_first_index; // Temporarily use the p->offset_length_ as a hash chain. int32_t* chain = (int32_t*)p->offset_length_; + assert(size > 0); assert(p->size_ != 0); assert(p->offset_length_ != NULL); + if (size <= 2) { + p->offset_length_[0] = p->offset_length_[size - 1] = 0; + return 1; + } + hash_to_first_index = (int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index)); if (hash_to_first_index == NULL) return 0; @@ -262,48 +271,111 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality, // Set the int32_t array to -1. memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index)); // Fill the chain linking pixels with the same hash. - for (pos = 0; pos < size - 1; ++pos) { - const uint32_t hash_code = GetPixPairHash64(argb + pos); - chain[pos] = hash_to_first_index[hash_code]; - hash_to_first_index[hash_code] = pos; + argb_comp = (argb[0] == argb[1]); + for (pos = 0; pos < size - 2;) { + uint32_t hash_code; + const int argb_comp_next = (argb[pos + 1] == argb[pos + 2]); + if (argb_comp && argb_comp_next) { + // Consecutive pixels with the same color will share the same hash. + // We therefore use a different hash: the color and its repetition + // length. + uint32_t tmp[2]; + uint32_t len = 1; + tmp[0] = argb[pos]; + // Figure out how far the pixels are the same. + // The last pixel has a different 64 bit hash, as its next pixel does + // not have the same color, so we just need to get to the last pixel equal + // to its follower. + while (pos + (int)len + 2 < size && argb[pos + len + 2] == argb[pos]) { + ++len; + } + if (len > MAX_LENGTH) { + // Skip the pixels that match for distance=1 and length>MAX_LENGTH + // because they are linked to their predecessor and we automatically + // check that in the main for loop below. Skipping means setting no + // predecessor in the chain, hence -1. + memset(chain + pos, 0xff, (len - MAX_LENGTH) * sizeof(*chain)); + pos += len - MAX_LENGTH; + len = MAX_LENGTH; + } + // Process the rest of the hash chain. + while (len) { + tmp[1] = len--; + hash_code = GetPixPairHash64(tmp); + chain[pos] = hash_to_first_index[hash_code]; + hash_to_first_index[hash_code] = pos++; + } + argb_comp = 0; + } else { + // Just move one pixel forward. + hash_code = GetPixPairHash64(argb + pos); + chain[pos] = hash_to_first_index[hash_code]; + hash_to_first_index[hash_code] = pos++; + argb_comp = argb_comp_next; + } } + // Process the penultimate pixel. + chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)]; + WebPSafeFree(hash_to_first_index); // Find the best match interval at each pixel, defined by an offset to the // pixel and a length. The right-most pixel cannot match anything to the right // (hence a best length of 0) and the left-most pixel nothing to the left // (hence an offset of 0). + assert(size > 2); p->offset_length_[0] = p->offset_length_[size - 1] = 0; - for (base_position = size - 2 < 0 ? 0 : size - 2; base_position > 0;) { + for (base_position = size - 2; base_position > 0;) { const int max_len = MaxFindCopyLength(size - 1 - base_position); const uint32_t* const argb_start = argb + base_position; int iter = iter_max; int best_length = 0; uint32_t best_distance = 0; + uint32_t best_argb; const int min_pos = (base_position > window_size) ? base_position - window_size : 0; const int length_max = (max_len < 256) ? max_len : 256; uint32_t max_base_position; - for (pos = chain[base_position]; pos >= min_pos; pos = chain[pos]) { + pos = chain[base_position]; + if (!low_effort) { int curr_length; - if (--iter < 0) { - break; + // Heuristic: use the comparison with the above line as an initialization. + if (base_position >= (uint32_t)xsize) { + curr_length = FindMatchLength(argb_start - xsize, argb_start, + best_length, max_len); + if (curr_length > best_length) { + best_length = curr_length; + best_distance = xsize; + } + --iter; + } + // Heuristic: compare to the previous pixel. + curr_length = + FindMatchLength(argb_start - 1, argb_start, best_length, max_len); + if (curr_length > best_length) { + best_length = curr_length; + best_distance = 1; } + --iter; + // Skip the for loop if we already have the maximum. + if (best_length == MAX_LENGTH) pos = min_pos - 1; + } + best_argb = argb_start[best_length]; + + for (; pos >= min_pos && --iter; pos = chain[pos]) { + int curr_length; assert(base_position > (uint32_t)pos); - curr_length = - FindMatchLength(argb + pos, argb_start, best_length, max_len); + if (argb[pos + best_length] != best_argb) continue; + + curr_length = VP8LVectorMismatch(argb + pos, argb_start, max_len); if (best_length < curr_length) { best_length = curr_length; best_distance = base_position - pos; - // Stop if we have reached the maximum length. Otherwise, make sure - // we have executed a minimum number of iterations depending on the - // quality. - if ((best_length == MAX_LENGTH) || - (curr_length >= length_max && iter < iter_min)) { - break; - } + best_argb = argb_start[best_length]; + // Stop if we have reached a good enough length. + if (best_length >= length_max) break; } } // We have the best match but in case the two intervals continue matching @@ -392,17 +464,16 @@ static int BackwardReferencesRle(int xsize, int ysize, i = 1; while (i < pix_count) { const int max_len = MaxFindCopyLength(pix_count - i); - const int kMinLength = 4; const int rle_len = FindMatchLength(argb + i, argb + i - 1, 0, max_len); const int prev_row_len = (i < xsize) ? 0 : FindMatchLength(argb + i, argb + i - xsize, 0, max_len); - if (rle_len >= prev_row_len && rle_len >= kMinLength) { + if (rle_len >= prev_row_len && rle_len >= MIN_LENGTH) { BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, rle_len)); // We don't need to update the color cache here since it is always the // same pixel being copied, and that does not change the color cache // state. i += rle_len; - } else if (prev_row_len >= kMinLength) { + } else if (prev_row_len >= MIN_LENGTH) { BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(xsize, prev_row_len)); if (use_color_cache) { for (k = 0; k < prev_row_len; ++k) { @@ -442,7 +513,7 @@ static int BackwardReferencesLz77(int xsize, int ysize, int len = 0; int j; HashChainFindCopy(hash_chain, i, &offset, &len); - if (len > MIN_LENGTH + 1) { + if (len >= MIN_LENGTH) { const int len_ini = len; int max_reach = 0; assert(i + len < pix_count); @@ -457,7 +528,7 @@ static int BackwardReferencesLz77(int xsize, int ysize, for (j = i_last_check + 1; j <= i + len_ini; ++j) { const int len_j = HashChainFindLength(hash_chain, j); const int reach = - j + (len_j > MIN_LENGTH + 1 ? len_j : 1); // 1 for single literal. + j + (len_j >= MIN_LENGTH ? len_j : 1); // 1 for single literal. if (reach > max_reach) { len = j - i; max_reach = reach; @@ -581,9 +652,10 @@ static void AddSingleLiteralWithCostModel(const uint32_t* const argb, uint16_t* const dist_array) { double cost_val = prev_cost; const uint32_t color = argb[0]; - if (use_color_cache && VP8LColorCacheContains(hashers, color)) { + const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1; + if (ix >= 0) { + // use_color_cache is true and hashers contains color const double mul0 = 0.68; - const int ix = VP8LColorCacheGetIndex(hashers, color); cost_val += GetCacheCost(cost_model, ix) * mul0; } else { const double mul1 = 0.82; @@ -1215,7 +1287,8 @@ static int BackwardReferencesHashChainDistanceOnly( int offset = 0, len = 0; double prev_cost = cost_manager->costs_[i - 1]; HashChainFindCopy(hash_chain, i, &offset, &len); - if (len >= MIN_LENGTH) { + if (len >= 2) { + // If we are dealing with a non-literal. const int code = DistanceToPlaneCode(xsize, offset); const double offset_cost = GetDistanceCost(cost_model, code); const int first_i = i; @@ -1304,20 +1377,17 @@ static int BackwardReferencesHashChainDistanceOnly( } goto next_symbol; } - if (len > MIN_LENGTH) { - int code_min_length; - double cost_total; - offset = HashChainFindOffset(hash_chain, i); - code_min_length = DistanceToPlaneCode(xsize, offset); - cost_total = prev_cost + - GetDistanceCost(cost_model, code_min_length) + - GetLengthCost(cost_model, 1); + if (len > 2) { + // Also try the smallest interval possible (size 2). + double cost_total = + prev_cost + offset_cost + GetLengthCost(cost_model, 1); if (cost_manager->costs_[i + 1] > cost_total) { cost_manager->costs_[i + 1] = (float)cost_total; dist_array[i + 1] = 2; } } - } else { // len < MIN_LENGTH + } else { + // The pixel is added as a single literal so just update the costs. UpdateCostPerIndex(cost_manager, i + 1); } @@ -1393,9 +1463,11 @@ static int BackwardReferencesHashChainFollowChosenPath( i += len; } else { PixOrCopy v; - if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) { + const int idx = + use_color_cache ? VP8LColorCacheContains(&hashers, argb[i]) : -1; + if (idx >= 0) { + // use_color_cache is true and hashers contains argb[i] // push pixel as a color cache index - const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]); v = PixOrCopyCreateCacheIdx(idx); } else { if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); @@ -1454,63 +1526,89 @@ static void BackwardReferences2DLocality(int xsize, } } -// Returns entropy for the given cache bits. -static double ComputeCacheEntropy(const uint32_t* argb, - const VP8LBackwardRefs* const refs, - int cache_bits) { - const int use_color_cache = (cache_bits > 0); - int cc_init = 0; - double entropy = MAX_ENTROPY; - const double kSmallPenaltyForLargeCache = 4.0; - VP8LColorCache hashers; +// Computes the entropies for a color cache size (in bits) between 0 (unused) +// and cache_bits_max (inclusive). +// Returns 1 on success, 0 in case of allocation error. +static int ComputeCacheEntropies(const uint32_t* argb, + const VP8LBackwardRefs* const refs, + int cache_bits_max, double entropies[]) { + int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 }; + VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1]; VP8LRefsCursor c = VP8LRefsCursorInit(refs); - VP8LHistogram* histo = VP8LAllocateHistogram(cache_bits); - if (histo == NULL) goto Error; + VP8LHistogram* histos[MAX_COLOR_CACHE_BITS + 1] = { NULL }; + int ok = 0; + int i; - if (use_color_cache) { - cc_init = VP8LColorCacheInit(&hashers, cache_bits); - if (!cc_init) goto Error; + for (i = 0; i <= cache_bits_max; ++i) { + histos[i] = VP8LAllocateHistogram(i); + if (histos[i] == NULL) goto Error; + if (i == 0) continue; + cc_init[i] = VP8LColorCacheInit(&hashers[i], i); + if (!cc_init[i]) goto Error; } - if (!use_color_cache) { - while (VP8LRefsCursorOk(&c)) { - VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos); - VP8LRefsCursorNext(&c); - } - } else { + + assert(cache_bits_max >= 0); + // Do not use the color cache for cache_bits=0. + while (VP8LRefsCursorOk(&c)) { + VP8LHistogramAddSinglePixOrCopy(histos[0], c.cur_pos); + VP8LRefsCursorNext(&c); + } + if (cache_bits_max > 0) { + c = VP8LRefsCursorInit(refs); while (VP8LRefsCursorOk(&c)) { const PixOrCopy* const v = c.cur_pos; if (PixOrCopyIsLiteral(v)) { const uint32_t pix = *argb++; - const uint32_t key = VP8LColorCacheGetIndex(&hashers, pix); - if (VP8LColorCacheLookup(&hashers, key) == pix) { - ++histo->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key]; - } else { - VP8LColorCacheSet(&hashers, key, pix); - ++histo->blue_[pix & 0xff]; - ++histo->literal_[(pix >> 8) & 0xff]; - ++histo->red_[(pix >> 16) & 0xff]; - ++histo->alpha_[pix >> 24]; + // The keys of the caches can be derived from the longest one. + int key = HashPix(pix, 32 - cache_bits_max); + for (i = cache_bits_max; i >= 1; --i, key >>= 1) { + if (VP8LColorCacheLookup(&hashers[i], key) == pix) { + ++histos[i]->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key]; + } else { + VP8LColorCacheSet(&hashers[i], key, pix); + ++histos[i]->blue_[pix & 0xff]; + ++histos[i]->literal_[(pix >> 8) & 0xff]; + ++histos[i]->red_[(pix >> 16) & 0xff]; + ++histos[i]->alpha_[pix >> 24]; + } } } else { + // Update the histograms for distance/length. int len = PixOrCopyLength(v); - int code, extra_bits; - VP8LPrefixEncodeBits(len, &code, &extra_bits); - ++histo->literal_[NUM_LITERAL_CODES + code]; - VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits); - ++histo->distance_[code]; + int code_dist, code_len, extra_bits; + uint32_t argb_prev = *argb ^ 0xffffffffu; + VP8LPrefixEncodeBits(len, &code_len, &extra_bits); + VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code_dist, &extra_bits); + for (i = 1; i <= cache_bits_max; ++i) { + ++histos[i]->literal_[NUM_LITERAL_CODES + code_len]; + ++histos[i]->distance_[code_dist]; + } + // Update the colors caches. do { - VP8LColorCacheInsert(&hashers, *argb++); - } while(--len != 0); + if (*argb != argb_prev) { + // Efficiency: insert only if the color changes. + int key = HashPix(*argb, 32 - cache_bits_max); + for (i = cache_bits_max; i >= 1; --i, key >>= 1) { + hashers[i].colors_[key] = *argb; + } + argb_prev = *argb; + } + argb++; + } while (--len != 0); } VP8LRefsCursorNext(&c); } } - entropy = VP8LHistogramEstimateBits(histo) + - kSmallPenaltyForLargeCache * cache_bits; - Error: - if (cc_init) VP8LColorCacheClear(&hashers); - VP8LFreeHistogram(histo); - return entropy; + for (i = 0; i <= cache_bits_max; ++i) { + entropies[i] = VP8LHistogramEstimateBits(histos[i]); + } + ok = 1; +Error: + for (i = 0; i <= cache_bits_max; ++i) { + if (cc_init[i]) VP8LColorCacheClear(&hashers[i]); + VP8LFreeHistogram(histos[i]); + } + return ok; } // Evaluate optimal cache bits for the local color cache. @@ -1524,13 +1622,10 @@ static int CalculateBestCacheSize(const uint32_t* const argb, VP8LBackwardRefs* const refs, int* const lz77_computed, int* const best_cache_bits) { - int eval_low = 1; - int eval_high = 1; - double entropy_low = MAX_ENTROPY; - double entropy_high = MAX_ENTROPY; - const double cost_mul = 5e-4; - int cache_bits_low = 0; + int i; int cache_bits_high = (quality <= 25) ? 0 : *best_cache_bits; + double entropy_min = MAX_ENTROPY; + double entropies[MAX_COLOR_CACHE_BITS + 1]; assert(cache_bits_high <= MAX_COLOR_CACHE_BITS); @@ -1540,34 +1635,23 @@ static int CalculateBestCacheSize(const uint32_t* const argb, // Local color cache is disabled. return 1; } - if (!BackwardReferencesLz77(xsize, ysize, argb, cache_bits_low, hash_chain, - refs)) { + // Compute LZ77 with no cache (0 bits), as the ideal LZ77 with a color cache + // is not that different in practice. + if (!BackwardReferencesLz77(xsize, ysize, argb, 0, hash_chain, refs)) { return 0; } - // Do a binary search to find the optimal entropy for cache_bits. - while (eval_low || eval_high) { - if (eval_low) { - entropy_low = ComputeCacheEntropy(argb, refs, cache_bits_low); - entropy_low += entropy_low * cache_bits_low * cost_mul; - eval_low = 0; - } - if (eval_high) { - entropy_high = ComputeCacheEntropy(argb, refs, cache_bits_high); - entropy_high += entropy_high * cache_bits_high * cost_mul; - eval_high = 0; - } - if (entropy_high < entropy_low) { - const int prev_cache_bits_low = cache_bits_low; - *best_cache_bits = cache_bits_high; - cache_bits_low = (cache_bits_low + cache_bits_high) / 2; - if (cache_bits_low != prev_cache_bits_low) eval_low = 1; - } else { - *best_cache_bits = cache_bits_low; - cache_bits_high = (cache_bits_low + cache_bits_high) / 2; - if (cache_bits_high != cache_bits_low) eval_high = 1; + // Find the cache_bits giving the lowest entropy. The search is done in a + // brute-force way as the function (entropy w.r.t cache_bits) can be + // anything in practice. + if (!ComputeCacheEntropies(argb, refs, cache_bits_high, entropies)) { + return 0; + } + for (i = 0; i <= cache_bits_high; ++i) { + if (i == 0 || entropies[i] < entropy_min) { + entropy_min = entropies[i]; + *best_cache_bits = i; } } - *lz77_computed = 1; return 1; } @@ -1584,8 +1668,9 @@ static int BackwardRefsWithLocalCache(const uint32_t* const argb, PixOrCopy* const v = c.cur_pos; if (PixOrCopyIsLiteral(v)) { const uint32_t argb_literal = v->argb_or_distance; - if (VP8LColorCacheContains(&hashers, argb_literal)) { - const int ix = VP8LColorCacheGetIndex(&hashers, argb_literal); + const int ix = VP8LColorCacheContains(&hashers, argb_literal); + if (ix >= 0) { + // hashers contains argb_literal *v = PixOrCopyCreateCacheIdx(ix); } else { VP8LColorCacheInsert(&hashers, argb_literal); diff --git a/src/3rdparty/libwebp/src/enc/backward_references.h b/src/3rdparty/libwebp/src/enc/backward_references_enc.h similarity index 99% rename from src/3rdparty/libwebp/src/enc/backward_references.h rename to src/3rdparty/libwebp/src/enc/backward_references_enc.h index 0cadb11e11ef421d5099aa9037f98be8f936b28f..3a19aa763eae4095670a8b7cd97d774629f0c81b 100644 --- a/src/3rdparty/libwebp/src/enc/backward_references.h +++ b/src/3rdparty/libwebp/src/enc/backward_references_enc.h @@ -130,7 +130,8 @@ struct VP8LHashChain { int VP8LHashChainInit(VP8LHashChain* const p, int size); // Pre-compute the best matches for argb. int VP8LHashChainFill(VP8LHashChain* const p, int quality, - const uint32_t* const argb, int xsize, int ysize); + const uint32_t* const argb, int xsize, int ysize, + int low_effort); void VP8LHashChainClear(VP8LHashChain* const p); // release memory // ----------------------------------------------------------------------------- diff --git a/src/3rdparty/libwebp/src/enc/config.c b/src/3rdparty/libwebp/src/enc/config_enc.c similarity index 71% rename from src/3rdparty/libwebp/src/enc/config.c rename to src/3rdparty/libwebp/src/enc/config_enc.c index f9f7961d58816cf996bd3dfef035d43cd8ac789e..4589dc0619e0cc6eac5dd621967c994ce59aef01 100644 --- a/src/3rdparty/libwebp/src/enc/config.c +++ b/src/3rdparty/libwebp/src/enc/config_enc.c @@ -11,6 +11,10 @@ // // Author: Skal (pascal.massimino@gmail.com) +#ifdef HAVE_CONFIG_H +#include "../webp/config.h" +#endif + #include "../webp/encode.h" //------------------------------------------------------------------------------ @@ -49,9 +53,8 @@ int WebPConfigInitInternal(WebPConfig* config, config->thread_level = 0; config->low_memory = 0; config->near_lossless = 100; -#ifdef WEBP_EXPERIMENTAL_FEATURES - config->delta_palettization = 0; -#endif // WEBP_EXPERIMENTAL_FEATURES + config->use_delta_palette = 0; + config->use_sharp_yuv = 0; // TODO(skal): tune. switch (preset) { @@ -92,60 +95,36 @@ int WebPConfigInitInternal(WebPConfig* config, int WebPValidateConfig(const WebPConfig* config) { if (config == NULL) return 0; - if (config->quality < 0 || config->quality > 100) - return 0; - if (config->target_size < 0) - return 0; - if (config->target_PSNR < 0) - return 0; - if (config->method < 0 || config->method > 6) - return 0; - if (config->segments < 1 || config->segments > 4) - return 0; - if (config->sns_strength < 0 || config->sns_strength > 100) - return 0; - if (config->filter_strength < 0 || config->filter_strength > 100) - return 0; - if (config->filter_sharpness < 0 || config->filter_sharpness > 7) - return 0; - if (config->filter_type < 0 || config->filter_type > 1) - return 0; - if (config->autofilter < 0 || config->autofilter > 1) - return 0; - if (config->pass < 1 || config->pass > 10) - return 0; - if (config->show_compressed < 0 || config->show_compressed > 1) - return 0; - if (config->preprocessing < 0 || config->preprocessing > 7) - return 0; - if (config->partitions < 0 || config->partitions > 3) + if (config->quality < 0 || config->quality > 100) return 0; + if (config->target_size < 0) return 0; + if (config->target_PSNR < 0) return 0; + if (config->method < 0 || config->method > 6) return 0; + if (config->segments < 1 || config->segments > 4) return 0; + if (config->sns_strength < 0 || config->sns_strength > 100) return 0; + if (config->filter_strength < 0 || config->filter_strength > 100) return 0; + if (config->filter_sharpness < 0 || config->filter_sharpness > 7) return 0; + if (config->filter_type < 0 || config->filter_type > 1) return 0; + if (config->autofilter < 0 || config->autofilter > 1) return 0; + if (config->pass < 1 || config->pass > 10) return 0; + if (config->show_compressed < 0 || config->show_compressed > 1) return 0; + if (config->preprocessing < 0 || config->preprocessing > 7) return 0; + if (config->partitions < 0 || config->partitions > 3) return 0; + if (config->partition_limit < 0 || config->partition_limit > 100) return 0; + if (config->alpha_compression < 0) return 0; + if (config->alpha_filtering < 0) return 0; + if (config->alpha_quality < 0 || config->alpha_quality > 100) return 0; + if (config->lossless < 0 || config->lossless > 1) return 0; + if (config->near_lossless < 0 || config->near_lossless > 100) return 0; + if (config->image_hint >= WEBP_HINT_LAST) return 0; + if (config->emulate_jpeg_size < 0 || config->emulate_jpeg_size > 1) return 0; + if (config->thread_level < 0 || config->thread_level > 1) return 0; + if (config->low_memory < 0 || config->low_memory > 1) return 0; + if (config->exact < 0 || config->exact > 1) return 0; + if (config->use_delta_palette < 0 || config->use_delta_palette > 1) { return 0; - if (config->partition_limit < 0 || config->partition_limit > 100) - return 0; - if (config->alpha_compression < 0) - return 0; - if (config->alpha_filtering < 0) - return 0; - if (config->alpha_quality < 0 || config->alpha_quality > 100) - return 0; - if (config->lossless < 0 || config->lossless > 1) - return 0; - if (config->near_lossless < 0 || config->near_lossless > 100) - return 0; - if (config->image_hint >= WEBP_HINT_LAST) - return 0; - if (config->emulate_jpeg_size < 0 || config->emulate_jpeg_size > 1) - return 0; - if (config->thread_level < 0 || config->thread_level > 1) - return 0; - if (config->low_memory < 0 || config->low_memory > 1) - return 0; - if (config->exact < 0 || config->exact > 1) - return 0; -#ifdef WEBP_EXPERIMENTAL_FEATURES - if (config->delta_palettization < 0 || config->delta_palettization > 1) - return 0; -#endif // WEBP_EXPERIMENTAL_FEATURES + } + if (config->use_sharp_yuv < 0 || config->use_sharp_yuv > 1) return 0; + return 1; } diff --git a/src/3rdparty/libwebp/src/enc/cost.c b/src/3rdparty/libwebp/src/enc/cost_enc.c similarity index 93% rename from src/3rdparty/libwebp/src/enc/cost.c rename to src/3rdparty/libwebp/src/enc/cost_enc.c index ae7fe0138843326c2d0fe6d5611527cb5eda84a8..c823f5a664966ce3c750cff019b4e35c3354ebc3 100644 --- a/src/3rdparty/libwebp/src/enc/cost.c +++ b/src/3rdparty/libwebp/src/enc/cost_enc.c @@ -11,7 +11,7 @@ // // Author: Skal (pascal.massimino@gmail.com) -#include "./cost.h" +#include "./cost_enc.h" //------------------------------------------------------------------------------ // Level cost tables @@ -281,18 +281,6 @@ int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) { //------------------------------------------------------------------------------ // Recording of token probabilities. -// Record proba context used -static int Record(int bit, proba_t* const stats) { - proba_t p = *stats; - if (p >= 0xffff0000u) { // an overflow is inbound. - p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2. - } - // record bit count (lower 16 bits) and increment total count (upper 16 bits). - p += 0x00010000u + bit; - *stats = p; - return bit; -} - // We keep the table-free variant around for reference, in case. #define USE_LEVEL_CODE_TABLE @@ -303,31 +291,31 @@ int VP8RecordCoeffs(int ctx, const VP8Residual* const res) { // should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1 proba_t* s = res->stats[n][ctx]; if (res->last < 0) { - Record(0, s + 0); + VP8RecordStats(0, s + 0); return 0; } while (n <= res->last) { int v; - Record(1, s + 0); // order of record doesn't matter + VP8RecordStats(1, s + 0); // order of record doesn't matter while ((v = res->coeffs[n++]) == 0) { - Record(0, s + 1); + VP8RecordStats(0, s + 1); s = res->stats[VP8EncBands[n]][0]; } - Record(1, s + 1); - if (!Record(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1 + VP8RecordStats(1, s + 1); + if (!VP8RecordStats(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1 s = res->stats[VP8EncBands[n]][1]; } else { v = abs(v); #if !defined(USE_LEVEL_CODE_TABLE) - if (!Record(v > 4, s + 3)) { - if (Record(v != 2, s + 4)) - Record(v == 4, s + 5); - } else if (!Record(v > 10, s + 6)) { - Record(v > 6, s + 7); - } else if (!Record((v >= 3 + (8 << 2)), s + 8)) { - Record((v >= 3 + (8 << 1)), s + 9); + if (!VP8RecordStats(v > 4, s + 3)) { + if (VP8RecordStats(v != 2, s + 4)) + VP8RecordStats(v == 4, s + 5); + } else if (!VP8RecordStats(v > 10, s + 6)) { + VP8RecordStats(v > 6, s + 7); + } else if (!VP8RecordStats((v >= 3 + (8 << 2)), s + 8)) { + VP8RecordStats((v >= 3 + (8 << 1)), s + 9); } else { - Record((v >= 3 + (8 << 3)), s + 10); + VP8RecordStats((v >= 3 + (8 << 3)), s + 10); } #else if (v > MAX_VARIABLE_LEVEL) { @@ -340,14 +328,14 @@ int VP8RecordCoeffs(int ctx, const VP8Residual* const res) { int i; for (i = 0; (pattern >>= 1) != 0; ++i) { const int mask = 2 << i; - if (pattern & 1) Record(!!(bits & mask), s + 3 + i); + if (pattern & 1) VP8RecordStats(!!(bits & mask), s + 3 + i); } } #endif s = res->stats[VP8EncBands[n]][2]; } } - if (n < 16) Record(0, s + 0); + if (n < 16) VP8RecordStats(0, s + 0); return 1; } diff --git a/src/3rdparty/libwebp/src/enc/cost.h b/src/3rdparty/libwebp/src/enc/cost_enc.h similarity index 79% rename from src/3rdparty/libwebp/src/enc/cost.h rename to src/3rdparty/libwebp/src/enc/cost_enc.h index 20960d6d74c0283688eefde24b3dae7dd62f57b1..99e4b37aa33c1557bc803912e4e54babc3d94ac1 100644 --- a/src/3rdparty/libwebp/src/enc/cost.h +++ b/src/3rdparty/libwebp/src/enc/cost_enc.h @@ -16,7 +16,7 @@ #include <assert.h> #include <stdlib.h> -#include "./vp8enci.h" +#include "./vp8i_enc.h" #ifdef __cplusplus extern "C" { @@ -41,6 +41,20 @@ void VP8InitResidual(int first, int coeff_type, int VP8RecordCoeffs(int ctx, const VP8Residual* const res); +// Record proba context used. +static WEBP_INLINE int VP8RecordStats(int bit, proba_t* const stats) { + proba_t p = *stats; + // An overflow is inbound. Note we handle this at 0xfffe0000u instead of + // 0xffff0000u to make sure p + 1u does not overflow. + if (p >= 0xfffe0000u) { + p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2. + } + // record bit count (lower 16 bits) and increment total count (upper 16 bits). + p += 0x00010000u + bit; + *stats = p; + return bit; +} + // Cost of coding one event with probability 'proba'. static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) { return !bit ? VP8EntropyCost[proba] : VP8EntropyCost[255 - proba]; diff --git a/src/3rdparty/libwebp/src/enc/delta_palettization.c b/src/3rdparty/libwebp/src/enc/delta_palettization_enc.c similarity index 99% rename from src/3rdparty/libwebp/src/enc/delta_palettization.c rename to src/3rdparty/libwebp/src/enc/delta_palettization_enc.c index 062e588d79f2db7823d3e5b8b013a5d2be07d367..eaf0f050ea7621e6528494b5d172ccbac4379e6a 100644 --- a/src/3rdparty/libwebp/src/enc/delta_palettization.c +++ b/src/3rdparty/libwebp/src/enc/delta_palettization_enc.c @@ -10,7 +10,7 @@ // Author: Mislav Bradac (mislavm@google.com) // -#include "./delta_palettization.h" +#include "./delta_palettization_enc.h" #ifdef WEBP_EXPERIMENTAL_FEATURES #include "../webp/types.h" diff --git a/src/3rdparty/libwebp/src/enc/delta_palettization.h b/src/3rdparty/libwebp/src/enc/delta_palettization_enc.h similarity index 97% rename from src/3rdparty/libwebp/src/enc/delta_palettization.h rename to src/3rdparty/libwebp/src/enc/delta_palettization_enc.h index e41c0c5ab56095e93d2ed77f526a858e261c21de..63048ec6e8f625b98e9a10191472243291005c79 100644 --- a/src/3rdparty/libwebp/src/enc/delta_palettization.h +++ b/src/3rdparty/libwebp/src/enc/delta_palettization_enc.h @@ -14,7 +14,7 @@ #define WEBP_ENC_DELTA_PALETTIZATION_H_ #include "../webp/encode.h" -#include "../enc/vp8li.h" +#include "../enc/vp8li_enc.h" // Replaces enc->argb_[] input by a palettizable approximation of it, // and generates optimal enc->palette_[]. diff --git a/src/3rdparty/libwebp/src/enc/filter.c b/src/3rdparty/libwebp/src/enc/filter_enc.c similarity index 70% rename from src/3rdparty/libwebp/src/enc/filter.c rename to src/3rdparty/libwebp/src/enc/filter_enc.c index e8ea8b4ff29c2dcd9f2bc17c9a9cdb1e3974c64f..4bc367274cb0d15bf59e4d0d370113ecbb1d4d9f 100644 --- a/src/3rdparty/libwebp/src/enc/filter.c +++ b/src/3rdparty/libwebp/src/enc/filter_enc.c @@ -12,7 +12,7 @@ // Author: somnath@google.com (Somnath Banerjee) #include <assert.h> -#include "./vp8enci.h" +#include "./vp8i_enc.h" #include "../dsp/dsp.h" // This table gives, for a given sharpness, the filtering strength to be @@ -105,115 +105,28 @@ static void DoFilter(const VP8EncIterator* const it, int level) { } //------------------------------------------------------------------------------ -// SSIM metric - -static const double kMinValue = 1.e-10; // minimal threshold - -void VP8SSIMAddStats(const VP8DistoStats* const src, VP8DistoStats* const dst) { - dst->w += src->w; - dst->xm += src->xm; - dst->ym += src->ym; - dst->xxm += src->xxm; - dst->xym += src->xym; - dst->yym += src->yym; -} - -double VP8SSIMGet(const VP8DistoStats* const stats) { - const double xmxm = stats->xm * stats->xm; - const double ymym = stats->ym * stats->ym; - const double xmym = stats->xm * stats->ym; - const double w2 = stats->w * stats->w; - double sxx = stats->xxm * stats->w - xmxm; - double syy = stats->yym * stats->w - ymym; - double sxy = stats->xym * stats->w - xmym; - double C1, C2; - double fnum; - double fden; - // small errors are possible, due to rounding. Clamp to zero. - if (sxx < 0.) sxx = 0.; - if (syy < 0.) syy = 0.; - C1 = 6.5025 * w2; - C2 = 58.5225 * w2; - fnum = (2 * xmym + C1) * (2 * sxy + C2); - fden = (xmxm + ymym + C1) * (sxx + syy + C2); - return (fden != 0.) ? fnum / fden : kMinValue; -} - -double VP8SSIMGetSquaredError(const VP8DistoStats* const s) { - if (s->w > 0.) { - const double iw2 = 1. / (s->w * s->w); - const double sxx = s->xxm * s->w - s->xm * s->xm; - const double syy = s->yym * s->w - s->ym * s->ym; - const double sxy = s->xym * s->w - s->xm * s->ym; - const double SSE = iw2 * (sxx + syy - 2. * sxy); - if (SSE > kMinValue) return SSE; - } - return kMinValue; -} - -#define LIMIT(A, M) ((A) > (M) ? (M) : (A)) -static void VP8SSIMAccumulateRow(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int y, int W, int H, - VP8DistoStats* const stats) { - int x = 0; - const int w0 = LIMIT(VP8_SSIM_KERNEL, W); - for (x = 0; x < w0; ++x) { - VP8SSIMAccumulateClipped(src1, stride1, src2, stride2, x, y, W, H, stats); - } - for (; x <= W - 8 + VP8_SSIM_KERNEL; ++x) { - VP8SSIMAccumulate( - src1 + (y - VP8_SSIM_KERNEL) * stride1 + (x - VP8_SSIM_KERNEL), stride1, - src2 + (y - VP8_SSIM_KERNEL) * stride2 + (x - VP8_SSIM_KERNEL), stride2, - stats); - } - for (; x < W; ++x) { - VP8SSIMAccumulateClipped(src1, stride1, src2, stride2, x, y, W, H, stats); - } -} - -void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int W, int H, VP8DistoStats* const stats) { - int x, y; - const int h0 = LIMIT(VP8_SSIM_KERNEL, H); - const int h1 = LIMIT(VP8_SSIM_KERNEL, H - VP8_SSIM_KERNEL); - for (y = 0; y < h0; ++y) { - for (x = 0; x < W; ++x) { - VP8SSIMAccumulateClipped(src1, stride1, src2, stride2, x, y, W, H, stats); - } - } - for (; y < h1; ++y) { - VP8SSIMAccumulateRow(src1, stride1, src2, stride2, y, W, H, stats); - } - for (; y < H; ++y) { - for (x = 0; x < W; ++x) { - VP8SSIMAccumulateClipped(src1, stride1, src2, stride2, x, y, W, H, stats); - } - } -} -#undef LIMIT +// SSIM metric for one macroblock static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) { int x, y; - VP8DistoStats s = { .0, .0, .0, .0, .0, .0 }; + double sum = 0.; // compute SSIM in a 10 x 10 window for (y = VP8_SSIM_KERNEL; y < 16 - VP8_SSIM_KERNEL; y++) { for (x = VP8_SSIM_KERNEL; x < 16 - VP8_SSIM_KERNEL; x++) { - VP8SSIMAccumulateClipped(yuv1 + Y_OFF_ENC, BPS, yuv2 + Y_OFF_ENC, BPS, - x, y, 16, 16, &s); + sum += VP8SSIMGetClipped(yuv1 + Y_OFF_ENC, BPS, yuv2 + Y_OFF_ENC, BPS, + x, y, 16, 16); } } for (x = 1; x < 7; x++) { for (y = 1; y < 7; y++) { - VP8SSIMAccumulateClipped(yuv1 + U_OFF_ENC, BPS, yuv2 + U_OFF_ENC, BPS, - x, y, 8, 8, &s); - VP8SSIMAccumulateClipped(yuv1 + V_OFF_ENC, BPS, yuv2 + V_OFF_ENC, BPS, - x, y, 8, 8, &s); + sum += VP8SSIMGetClipped(yuv1 + U_OFF_ENC, BPS, yuv2 + U_OFF_ENC, BPS, + x, y, 8, 8); + sum += VP8SSIMGetClipped(yuv1 + V_OFF_ENC, BPS, yuv2 + V_OFF_ENC, BPS, + x, y, 8, 8); } } - return VP8SSIMGet(&s); + return sum; } //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/enc/frame.c b/src/3rdparty/libwebp/src/enc/frame_enc.c similarity index 97% rename from src/3rdparty/libwebp/src/enc/frame.c rename to src/3rdparty/libwebp/src/enc/frame_enc.c index 5b7a40b9ad0b01ed6e52d7cfd5de68a6e71d1336..abef523bbfdf53fdb4b251c3964a07ee5aa82e79 100644 --- a/src/3rdparty/libwebp/src/enc/frame.c +++ b/src/3rdparty/libwebp/src/enc/frame_enc.c @@ -14,8 +14,8 @@ #include <string.h> #include <math.h> -#include "./cost.h" -#include "./vp8enci.h" +#include "./cost_enc.h" +#include "./vp8i_enc.h" #include "../dsp/dsp.h" #include "../webp/format_constants.h" // RIFF constants @@ -185,6 +185,13 @@ static int GetProba(int a, int b) { : (255 * a + total / 2) / total; // rounded proba } +static void ResetSegments(VP8Encoder* const enc) { + int n; + for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { + enc->mb_info_[n].segment_ = 0; + } +} + static void SetSegmentProbas(VP8Encoder* const enc) { int p[NUM_MB_SEGMENTS] = { 0 }; int n; @@ -206,6 +213,7 @@ static void SetSegmentProbas(VP8Encoder* const enc) { enc->segment_hdr_.update_map_ = (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255); + if (!enc->segment_hdr_.update_map_) ResetSegments(enc); enc->segment_hdr_.size_ = p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) + p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) + @@ -240,8 +248,9 @@ static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) { p = res->prob[VP8EncBands[n]][1]; } else { if (!VP8PutBit(bw, v > 4, p[3])) { - if (VP8PutBit(bw, v != 2, p[4])) + if (VP8PutBit(bw, v != 2, p[4])) { VP8PutBit(bw, v == 4, p[5]); + } } else if (!VP8PutBit(bw, v > 10, p[6])) { if (!VP8PutBit(bw, v > 6, p[7])) { VP8PutBit(bw, v == 6, 159); @@ -406,9 +415,7 @@ static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd, VP8InitResidual(0, 1, enc, &res); VP8SetResidualCoeffs(rd->y_dc_levels, &res); it->top_nz_[8] = it->left_nz_[8] = - VP8RecordCoeffTokens(ctx, 1, - res.first, res.last, res.coeffs, tokens); - VP8RecordCoeffs(ctx, &res); + VP8RecordCoeffTokens(ctx, &res, tokens); VP8InitResidual(1, 0, enc, &res); } else { VP8InitResidual(0, 3, enc, &res); @@ -420,9 +427,7 @@ static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd, const int ctx = it->top_nz_[x] + it->left_nz_[y]; VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); it->top_nz_[x] = it->left_nz_[y] = - VP8RecordCoeffTokens(ctx, res.coeff_type, - res.first, res.last, res.coeffs, tokens); - VP8RecordCoeffs(ctx, &res); + VP8RecordCoeffTokens(ctx, &res, tokens); } } @@ -434,9 +439,7 @@ static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd, const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = - VP8RecordCoeffTokens(ctx, 2, - res.first, res.last, res.coeffs, tokens); - VP8RecordCoeffs(ctx, &res); + VP8RecordCoeffTokens(ctx, &res, tokens); } } } @@ -555,8 +558,9 @@ static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt, size += info.R + info.H; size_p0 += info.H; distortion += info.D; - if (percent_delta && !VP8IteratorProgress(&it, percent_delta)) + if (percent_delta && !VP8IteratorProgress(&it, percent_delta)) { return 0; + } VP8IteratorSaveBoundary(&it); } while (VP8IteratorNext(&it) && --nb_mbs > 0); @@ -814,7 +818,7 @@ int VP8EncTokenLoop(VP8Encoder* const enc) { num_pass_left, stats.last_value, stats.value, stats.last_q, stats.q, stats.dq); #endif - if (size_p0 > PARTITION0_SIZE_LIMIT) { + if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { ++num_pass_left; enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation... continue; // ...and start over diff --git a/src/3rdparty/libwebp/src/enc/histogram.c b/src/3rdparty/libwebp/src/enc/histogram_enc.c similarity index 78% rename from src/3rdparty/libwebp/src/enc/histogram.c rename to src/3rdparty/libwebp/src/enc/histogram_enc.c index 395372b245a346773e6ffcb3932ea5154a875944..808b6f78abbbf55c4636a0d4416c19aa0d8f96b3 100644 --- a/src/3rdparty/libwebp/src/enc/histogram.c +++ b/src/3rdparty/libwebp/src/enc/histogram_enc.c @@ -15,9 +15,10 @@ #include <math.h> -#include "./backward_references.h" -#include "./histogram.h" +#include "./backward_references_enc.h" +#include "./histogram_enc.h" #include "../dsp/lossless.h" +#include "../dsp/lossless_common.h" #include "../utils/utils.h" #define MAX_COST 1.e38 @@ -213,10 +214,19 @@ static double InitialHuffmanCost(void) { // Finalize the Huffman cost based on streak numbers and length type (<3 or >=3) static double FinalHuffmanCost(const VP8LStreaks* const stats) { + // The constants in this function are experimental and got rounded from + // their original values in 1/8 when switched to 1/1024. double retval = InitialHuffmanCost(); + // Second coefficient: Many zeros in the histogram are covered efficiently + // by a run-length encode. Originally 2/8. retval += stats->counts[0] * 1.5625 + 0.234375 * stats->streaks[0][1]; + // Second coefficient: Constant values are encoded less efficiently, but still + // RLE'ed. Originally 6/8. retval += stats->counts[1] * 2.578125 + 0.703125 * stats->streaks[1][1]; + // 0s are usually encoded more efficiently than non-0s. + // Originally 15/8. retval += 1.796875 * stats->streaks[0][0]; + // Originally 26/8. retval += 3.28125 * stats->streaks[1][0]; return retval; } @@ -236,14 +246,30 @@ static double PopulationCost(const uint32_t* const population, int length, return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); } +// trivial_at_end is 1 if the two histograms only have one element that is +// non-zero: both the zero-th one, or both the last one. static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X, const uint32_t* const Y, - int length) { - VP8LBitEntropy bit_entropy; + int length, int trivial_at_end) { VP8LStreaks stats; - VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats); + if (trivial_at_end) { + // This configuration is due to palettization that transforms an indexed + // pixel into 0xff000000 | (pixel << 8) in VP8LBundleColorMap. + // BitsEntropyRefine is 0 for histograms with only one non-zero value. + // Only FinalHuffmanCost needs to be evaluated. + memset(&stats, 0, sizeof(stats)); + // Deal with the non-zero value at index 0 or length-1. + stats.streaks[1][0] += 1; + // Deal with the following/previous zero streak. + stats.counts[0] += 1; + stats.streaks[0][1] += length - 1; + return FinalHuffmanCost(&stats); + } else { + VP8LBitEntropy bit_entropy; + VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats); - return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); + return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); + } } // Estimates the Entropy + Huffman + other block overhead size cost. @@ -267,24 +293,42 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a, double cost_threshold, double* cost) { const int palette_code_bits = a->palette_code_bits_; + int trivial_at_end = 0; assert(a->palette_code_bits_ == b->palette_code_bits_); *cost += GetCombinedEntropy(a->literal_, b->literal_, - VP8LHistogramNumCodes(palette_code_bits)); + VP8LHistogramNumCodes(palette_code_bits), 0); *cost += VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES, b->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES); if (*cost > cost_threshold) return 0; - *cost += GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES); + if (a->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM && + a->trivial_symbol_ == b->trivial_symbol_) { + // A, R and B are all 0 or 0xff. + const uint32_t color_a = (a->trivial_symbol_ >> 24) & 0xff; + const uint32_t color_r = (a->trivial_symbol_ >> 16) & 0xff; + const uint32_t color_b = (a->trivial_symbol_ >> 0) & 0xff; + if ((color_a == 0 || color_a == 0xff) && + (color_r == 0 || color_r == 0xff) && + (color_b == 0 || color_b == 0xff)) { + trivial_at_end = 1; + } + } + + *cost += + GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES, trivial_at_end); if (*cost > cost_threshold) return 0; - *cost += GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES); + *cost += + GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES, trivial_at_end); if (*cost > cost_threshold) return 0; - *cost += GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES); + *cost += GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES, + trivial_at_end); if (*cost > cost_threshold) return 0; - *cost += GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES); + *cost += + GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES, 0); *cost += VP8LExtraCostCombined(a->distance_, b->distance_, NUM_DISTANCE_CODES); if (*cost > cost_threshold) return 0; @@ -292,6 +336,15 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a, return 1; } +static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const a, + const VP8LHistogram* const b, + VP8LHistogram* const out) { + VP8LHistogramAdd(a, b, out); + out->trivial_symbol_ = (a->trivial_symbol_ == b->trivial_symbol_) + ? a->trivial_symbol_ + : VP8L_NON_TRIVIAL_SYM; +} + // Performs out = a + b, computing the cost C(a+b) - C(a) - C(b) while comparing // to the threshold value 'cost_threshold'. The score returned is // Score = C(a+b) - C(a) - C(b), where C(a) + C(b) is known and fixed. @@ -307,11 +360,9 @@ static double HistogramAddEval(const VP8LHistogram* const a, cost_threshold += sum_cost; if (GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) { - VP8LHistogramAdd(a, b, out); + HistogramAdd(a, b, out); out->bit_cost_ = cost; out->palette_code_bits_ = a->palette_code_bits_; - out->trivial_symbol_ = (a->trivial_symbol_ == b->trivial_symbol_) ? - a->trivial_symbol_ : VP8L_NON_TRIVIAL_SYM; } return cost - sum_cost; @@ -450,113 +501,103 @@ static void HistogramCopyAndAnalyze( // Partition histograms to different entropy bins for three dominant (literal, // red and blue) symbol costs and compute the histogram aggregate bit_cost. static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo, - int16_t* const bin_map, int low_effort) { + uint16_t* const bin_map, + int low_effort) { int i; VP8LHistogram** const histograms = image_histo->histograms; const int histo_size = image_histo->size; - const int bin_depth = histo_size + 1; DominantCostRange cost_range; DominantCostRangeInit(&cost_range); // Analyze the dominant (literal, red and blue) entropy costs. for (i = 0; i < histo_size; ++i) { - VP8LHistogram* const histo = histograms[i]; - UpdateDominantCostRange(histo, &cost_range); + UpdateDominantCostRange(histograms[i], &cost_range); } // bin-hash histograms on three of the dominant (literal, red and blue) - // symbol costs. + // symbol costs and store the resulting bin_id for each histogram. for (i = 0; i < histo_size; ++i) { - const VP8LHistogram* const histo = histograms[i]; - const int bin_id = GetHistoBinIndex(histo, &cost_range, low_effort); - const int bin_offset = bin_id * bin_depth; - // bin_map[n][0] for every bin 'n' maintains the counter for the number of - // histograms in that bin. - // Get and increment the num_histos in that bin. - const int num_histos = ++bin_map[bin_offset]; - assert(bin_offset + num_histos < bin_depth * BIN_SIZE); - // Add histogram i'th index at num_histos (last) position in the bin_map. - bin_map[bin_offset + num_histos] = i; - } -} - -// Compact the histogram set by removing unused entries. -static void HistogramCompactBins(VP8LHistogramSet* const image_histo) { - VP8LHistogram** const histograms = image_histo->histograms; - int i, j; - - for (i = 0, j = 0; i < image_histo->size; ++i) { - if (histograms[i] != NULL && histograms[i]->bit_cost_ != 0.) { - if (j < i) { - histograms[j] = histograms[i]; - histograms[i] = NULL; - } - ++j; - } + bin_map[i] = GetHistoBinIndex(histograms[i], &cost_range, low_effort); } - image_histo->size = j; } +// Compact image_histo[] by merging some histograms with same bin_id together if +// it's advantageous. static VP8LHistogram* HistogramCombineEntropyBin( VP8LHistogramSet* const image_histo, VP8LHistogram* cur_combo, - int16_t* const bin_map, int bin_depth, int num_bins, + const uint16_t* const bin_map, int bin_map_size, int num_bins, double combine_cost_factor, int low_effort) { - int bin_id; VP8LHistogram** const histograms = image_histo->histograms; - - for (bin_id = 0; bin_id < num_bins; ++bin_id) { - const int bin_offset = bin_id * bin_depth; - const int num_histos = bin_map[bin_offset]; - const int idx1 = bin_map[bin_offset + 1]; - int num_combine_failures = 0; - int n; - for (n = 2; n <= num_histos; ++n) { - const int idx2 = bin_map[bin_offset + n]; - if (low_effort) { - // Merge all histograms with the same bin index, irrespective of cost of - // the merged histograms. - VP8LHistogramAdd(histograms[idx1], histograms[idx2], histograms[idx1]); - histograms[idx2]->bit_cost_ = 0.; - } else { - const double bit_cost_idx2 = histograms[idx2]->bit_cost_; - if (bit_cost_idx2 > 0.) { - const double bit_cost_thresh = -bit_cost_idx2 * combine_cost_factor; - const double curr_cost_diff = - HistogramAddEval(histograms[idx1], histograms[idx2], - cur_combo, bit_cost_thresh); - if (curr_cost_diff < bit_cost_thresh) { - // Try to merge two histograms only if the combo is a trivial one or - // the two candidate histograms are already non-trivial. - // For some images, 'try_combine' turns out to be false for a lot of - // histogram pairs. In that case, we fallback to combining - // histograms as usual to avoid increasing the header size. - const int try_combine = - (cur_combo->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM) || - ((histograms[idx1]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM) && - (histograms[idx2]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM)); - const int max_combine_failures = 32; - if (try_combine || (num_combine_failures >= max_combine_failures)) { - HistogramSwap(&cur_combo, &histograms[idx1]); - histograms[idx2]->bit_cost_ = 0.; - } else { - ++num_combine_failures; - } - } + int idx; + // Work in-place: processed histograms are put at the beginning of + // image_histo[]. At the end, we just have to truncate the array. + int size = 0; + struct { + int16_t first; // position of the histogram that accumulates all + // histograms with the same bin_id + uint16_t num_combine_failures; // number of combine failures per bin_id + } bin_info[BIN_SIZE]; + + assert(num_bins <= BIN_SIZE); + for (idx = 0; idx < num_bins; ++idx) { + bin_info[idx].first = -1; + bin_info[idx].num_combine_failures = 0; + } + + for (idx = 0; idx < bin_map_size; ++idx) { + const int bin_id = bin_map[idx]; + const int first = bin_info[bin_id].first; + assert(size <= idx); + if (first == -1) { + // just move histogram #idx to its final position + histograms[size] = histograms[idx]; + bin_info[bin_id].first = size++; + } else if (low_effort) { + HistogramAdd(histograms[idx], histograms[first], histograms[first]); + } else { + // try to merge #idx into #first (both share the same bin_id) + const double bit_cost = histograms[idx]->bit_cost_; + const double bit_cost_thresh = -bit_cost * combine_cost_factor; + const double curr_cost_diff = + HistogramAddEval(histograms[first], histograms[idx], + cur_combo, bit_cost_thresh); + if (curr_cost_diff < bit_cost_thresh) { + // Try to merge two histograms only if the combo is a trivial one or + // the two candidate histograms are already non-trivial. + // For some images, 'try_combine' turns out to be false for a lot of + // histogram pairs. In that case, we fallback to combining + // histograms as usual to avoid increasing the header size. + const int try_combine = + (cur_combo->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM) || + ((histograms[idx]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM) && + (histograms[first]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM)); + const int max_combine_failures = 32; + if (try_combine || + bin_info[bin_id].num_combine_failures >= max_combine_failures) { + // move the (better) merged histogram to its final slot + HistogramSwap(&cur_combo, &histograms[first]); + } else { + histograms[size++] = histograms[idx]; + ++bin_info[bin_id].num_combine_failures; } + } else { + histograms[size++] = histograms[idx]; } } - if (low_effort) { - // Update the bit_cost for the merged histograms (per bin index). - UpdateHistogramCost(histograms[idx1]); + } + image_histo->size = size; + if (low_effort) { + // for low_effort case, update the final cost when everything is merged + for (idx = 0; idx < size; ++idx) { + UpdateHistogramCost(histograms[idx]); } } - HistogramCompactBins(image_histo); return cur_combo; } -static uint32_t MyRand(uint32_t *seed) { - *seed *= 16807U; +static uint32_t MyRand(uint32_t* const seed) { + *seed = (*seed * 16807ull) & 0xffffffffu; if (*seed == 0) { *seed = 1; } @@ -592,8 +633,8 @@ static int HistoQueueInit(HistoQueue* const histo_queue, const int max_index) { histo_queue->max_size = max_index * max_index; // We allocate max_size + 1 because the last element at index "size" is // used as temporary data (and it could be up to max_size). - histo_queue->queue = WebPSafeMalloc(histo_queue->max_size + 1, - sizeof(*histo_queue->queue)); + histo_queue->queue = (HistogramPair*)WebPSafeMalloc( + histo_queue->max_size + 1, sizeof(*histo_queue->queue)); return histo_queue->queue != NULL; } @@ -659,7 +700,8 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) { int i, j; VP8LHistogram** const histograms = image_histo->histograms; // Indexes of remaining histograms. - int* const clusters = WebPSafeMalloc(image_histo_size, sizeof(*clusters)); + int* const clusters = + (int*)WebPSafeMalloc(image_histo_size, sizeof(*clusters)); // Priority queue of histogram pairs. HistoQueue histo_queue; @@ -681,7 +723,7 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) { HistogramPair* copy_to; const int idx1 = histo_queue.queue[0].idx1; const int idx2 = histo_queue.queue[0].idx2; - VP8LHistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]); + HistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]); histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; // Remove merged histogram. for (i = 0; i + 1 < image_histo_size; ++i) { @@ -747,6 +789,8 @@ static void HistogramCombineStochastic(VP8LHistogramSet* const image_histo, const int outer_iters = image_histo_size * iter_mult; const int num_pairs = image_histo_size / 2; const int num_tries_no_success = outer_iters / 2; + int idx2_max = image_histo_size - 1; + int do_brute_dorce = 0; VP8LHistogram** const histograms = image_histo->histograms; // Collapse similar histograms in 'image_histo'. @@ -757,43 +801,62 @@ static void HistogramCombineStochastic(VP8LHistogramSet* const image_histo, double best_cost_diff = 0.; int best_idx1 = -1, best_idx2 = 1; int j; - const int num_tries = + int num_tries = (num_pairs < image_histo_size) ? num_pairs : image_histo_size; + // Use a brute force approach if: + // - stochastic has not worked for a while and + // - if the number of iterations for brute force is less than the number of + // iterations if we never find a match ever again stochastically (hence + // num_tries times the number of remaining outer iterations). + do_brute_dorce = + (tries_with_no_success > 10) && + (idx2_max * (idx2_max + 1) < 2 * num_tries * (outer_iters - iter)); + if (do_brute_dorce) num_tries = idx2_max; + seed += iter; for (j = 0; j < num_tries; ++j) { double curr_cost_diff; // Choose two histograms at random and try to combine them. - const uint32_t idx1 = MyRand(&seed) % image_histo_size; - const uint32_t tmp = (j & 7) + 1; - const uint32_t diff = - (tmp < 3) ? tmp : MyRand(&seed) % (image_histo_size - 1); - const uint32_t idx2 = (idx1 + diff + 1) % image_histo_size; - if (idx1 == idx2) { - continue; + uint32_t idx1, idx2; + if (do_brute_dorce) { + // Use a brute force approach. + idx1 = (uint32_t)j; + idx2 = (uint32_t)idx2_max; + } else { + const uint32_t tmp = (j & 7) + 1; + const uint32_t diff = + (tmp < 3) ? tmp : MyRand(&seed) % (image_histo_size - 1); + idx1 = MyRand(&seed) % image_histo_size; + idx2 = (idx1 + diff + 1) % image_histo_size; + if (idx1 == idx2) { + continue; + } } // Calculate cost reduction on combining. curr_cost_diff = HistogramAddEval(histograms[idx1], histograms[idx2], tmp_histo, best_cost_diff); - if (curr_cost_diff < best_cost_diff) { // found a better pair? + if (curr_cost_diff < best_cost_diff) { // found a better pair? HistogramSwap(&best_combo, &tmp_histo); best_cost_diff = curr_cost_diff; best_idx1 = idx1; best_idx2 = idx2; } } + if (do_brute_dorce) --idx2_max; if (best_idx1 >= 0) { HistogramSwap(&best_combo, &histograms[best_idx1]); // swap best_idx2 slot with last one (which is now unused) --image_histo_size; + if (idx2_max >= image_histo_size) idx2_max = image_histo_size - 1; if (best_idx2 != image_histo_size) { HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]); histograms[image_histo_size] = NULL; } tries_with_no_success = 0; } - if (++tries_with_no_success >= num_tries_no_success) { + if (++tries_with_no_success >= num_tries_no_success || idx2_max == 0) { break; } } @@ -842,7 +905,7 @@ static void HistogramRemap(const VP8LHistogramSet* const in, for (i = 0; i < in_size; ++i) { const int idx = symbols[i]; - VP8LHistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]); + HistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]); } } @@ -868,32 +931,18 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1; const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1; const int image_histo_raw_size = histo_xsize * histo_ysize; - const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE; - - // The bin_map for every bin follows following semantics: - // bin_map[n][0] = num_histo; // The number of histograms in that bin. - // bin_map[n][1] = index of first histogram in that bin; - // bin_map[n][num_histo] = index of last histogram in that bin; - // bin_map[n][num_histo + 1] ... bin_map[n][bin_depth - 1] = unused indices. - const int bin_depth = image_histo_raw_size + 1; - int16_t* bin_map = NULL; VP8LHistogramSet* const orig_histo = VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits); VP8LHistogram* cur_combo; + // Don't attempt linear bin-partition heuristic for + // histograms of small sizes (as bin_map will be very sparse) and + // maximum quality q==100 (to preserve the compression gains at that level). + const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE; const int entropy_combine = (orig_histo->size > entropy_combine_num_bins * 2) && (quality < 100); if (orig_histo == NULL) goto Error; - // Don't attempt linear bin-partition heuristic for: - // histograms of small sizes, as bin_map will be very sparse and; - // Maximum quality (q==100), to preserve the compression gains at that level. - if (entropy_combine) { - const int bin_map_size = bin_depth * entropy_combine_num_bins; - bin_map = (int16_t*)WebPSafeCalloc(bin_map_size, sizeof(*bin_map)); - if (bin_map == NULL) goto Error; - } - // Construct the histograms from backward references. HistogramBuild(xsize, histo_bits, refs, orig_histo); // Copies the histograms and computes its bit_cost. @@ -901,12 +950,17 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, cur_combo = tmp_histos->histograms[1]; // pick up working slot if (entropy_combine) { + const int bin_map_size = orig_histo->size; + // Reuse histogram_symbols storage. By definition, it's guaranteed to be ok. + uint16_t* const bin_map = histogram_symbols; const double combine_cost_factor = GetCombineCostFactor(image_histo_raw_size, quality); + HistogramAnalyzeEntropyBin(orig_histo, bin_map, low_effort); // Collapse histograms with similar entropy. - cur_combo = HistogramCombineEntropyBin(image_histo, cur_combo, bin_map, - bin_depth, entropy_combine_num_bins, + cur_combo = HistogramCombineEntropyBin(image_histo, cur_combo, + bin_map, bin_map_size, + entropy_combine_num_bins, combine_cost_factor, low_effort); } @@ -931,7 +985,6 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, ok = 1; Error: - WebPSafeFree(bin_map); VP8LFreeHistogramSet(orig_histo); return ok; } diff --git a/src/3rdparty/libwebp/src/enc/histogram.h b/src/3rdparty/libwebp/src/enc/histogram_enc.h similarity index 99% rename from src/3rdparty/libwebp/src/enc/histogram.h rename to src/3rdparty/libwebp/src/enc/histogram_enc.h index d303d1d58ba61caae7b7e85bc1f08a96340e0ed9..a9d258a1665e5c5c4f5b8dad14cb8598fdff1b24 100644 --- a/src/3rdparty/libwebp/src/enc/histogram.h +++ b/src/3rdparty/libwebp/src/enc/histogram_enc.h @@ -16,7 +16,7 @@ #include <string.h> -#include "./backward_references.h" +#include "./backward_references_enc.h" #include "../webp/format_constants.h" #include "../webp/types.h" diff --git a/src/3rdparty/libwebp/src/enc/iterator.c b/src/3rdparty/libwebp/src/enc/iterator_enc.c similarity index 98% rename from src/3rdparty/libwebp/src/enc/iterator.c rename to src/3rdparty/libwebp/src/enc/iterator_enc.c index 99d960a547dd00a40038c230447b5a30c27c8968..e48d30bd314bed9eb057491b3f8681873ee64d9d 100644 --- a/src/3rdparty/libwebp/src/enc/iterator.c +++ b/src/3rdparty/libwebp/src/enc/iterator_enc.c @@ -13,7 +13,7 @@ #include <string.h> -#include "./vp8enci.h" +#include "./vp8i_enc.h" //------------------------------------------------------------------------------ // VP8Iterator @@ -53,7 +53,6 @@ void VP8IteratorReset(VP8EncIterator* const it) { VP8IteratorSetRow(it, 0); VP8IteratorSetCountDown(it, enc->mb_w_ * enc->mb_h_); // default InitTop(it); - InitLeft(it); memset(it->bit_count_, 0, sizeof(it->bit_count_)); it->do_trellis_ = 0; } @@ -68,8 +67,6 @@ int VP8IteratorIsDone(const VP8EncIterator* const it) { void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) { it->enc_ = enc; - it->y_stride_ = enc->pic_->y_stride; - it->uv_stride_ = enc->pic_->uv_stride; it->yuv_in_ = (uint8_t*)WEBP_ALIGN(it->yuv_mem_); it->yuv_out_ = it->yuv_in_ + YUV_SIZE_ENC; it->yuv_out2_ = it->yuv_out_ + YUV_SIZE_ENC; @@ -309,14 +306,14 @@ void VP8IteratorSaveBoundary(VP8EncIterator* const it) { } int VP8IteratorNext(VP8EncIterator* const it) { - it->preds_ += 4; - it->mb_ += 1; - it->nz_ += 1; - it->y_top_ += 16; - it->uv_top_ += 16; - it->x_ += 1; - if (it->x_ == it->enc_->mb_w_) { + if (++it->x_ == it->enc_->mb_w_) { VP8IteratorSetRow(it, ++it->y_); + } else { + it->preds_ += 4; + it->mb_ += 1; + it->nz_ += 1; + it->y_top_ += 16; + it->uv_top_ += 16; } return (0 < --it->count_down_); } diff --git a/src/3rdparty/libwebp/src/enc/near_lossless.c b/src/3rdparty/libwebp/src/enc/near_lossless_enc.c similarity index 98% rename from src/3rdparty/libwebp/src/enc/near_lossless.c rename to src/3rdparty/libwebp/src/enc/near_lossless_enc.c index f4ab91f5716ba7fcbdad7b1acb21bd187c9f9ca2..2bd03ab20dabbaf9944f91d7352b13d238562ac2 100644 --- a/src/3rdparty/libwebp/src/enc/near_lossless.c +++ b/src/3rdparty/libwebp/src/enc/near_lossless_enc.c @@ -17,9 +17,9 @@ #include <assert.h> #include <stdlib.h> -#include "../dsp/lossless.h" +#include "../dsp/lossless_common.h" #include "../utils/utils.h" -#include "./vp8enci.h" +#include "./vp8i_enc.h" #define MIN_DIM_FOR_NEAR_LOSSLESS 64 #define MAX_LIMIT_BITS 5 diff --git a/src/3rdparty/libwebp/src/enc/picture_csp.c b/src/3rdparty/libwebp/src/enc/picture_csp_enc.c similarity index 77% rename from src/3rdparty/libwebp/src/enc/picture_csp.c rename to src/3rdparty/libwebp/src/enc/picture_csp_enc.c index 607a6240b04541c242a19ade3b7113e989d33b86..e5d1c75a66632782f16b4f383da09f13bfc112e8 100644 --- a/src/3rdparty/libwebp/src/enc/picture_csp.c +++ b/src/3rdparty/libwebp/src/enc/picture_csp_enc.c @@ -15,8 +15,8 @@ #include <stdlib.h> #include <math.h> -#include "./vp8enci.h" -#include "../utils/random.h" +#include "./vp8i_enc.h" +#include "../utils/random_utils.h" #include "../utils/utils.h" #include "../dsp/yuv.h" @@ -153,9 +153,9 @@ static int RGBToV(int r, int g, int b, VP8Random* const rg) { } //------------------------------------------------------------------------------ -// Smart RGB->YUV conversion +// Sharp RGB->YUV conversion -static const int kNumIterations = 6; +static const int kNumIterations = 4; static const int kMinDimensionIterativeConversion = 4; // We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some @@ -171,9 +171,9 @@ typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W #if defined(USE_GAMMA_COMPRESSION) // float variant of gamma-correction -// We use tables of different size and precision, along with a 'real-world' -// Gamma value close to ~2. -#define kGammaF 2.2 +// We use tables of different size and precision for the Rec709 +// transfer function. +#define kGammaF (1./0.45) static float kGammaToLinearTabF[MAX_Y_T + 1]; // size scales with Y_FIX static float kLinearToGammaTabF[kGammaTabSize + 2]; static volatile int kGammaTablesFOk = 0; @@ -183,11 +183,26 @@ static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) { int v; const double norm = 1. / MAX_Y_T; const double scale = 1. / kGammaTabSize; + const double a = 0.099; + const double thresh = 0.018; for (v = 0; v <= MAX_Y_T; ++v) { - kGammaToLinearTabF[v] = (float)pow(norm * v, kGammaF); + const double g = norm * v; + if (g <= thresh * 4.5) { + kGammaToLinearTabF[v] = (float)(g / 4.5); + } else { + const double a_rec = 1. / (1. + a); + kGammaToLinearTabF[v] = (float)pow(a_rec * (g + a), kGammaF); + } } for (v = 0; v <= kGammaTabSize; ++v) { - kLinearToGammaTabF[v] = (float)(MAX_Y_T * pow(scale * v, 1. / kGammaF)); + const double g = scale * v; + double value; + if (g <= thresh) { + value = 4.5 * g; + } else { + value = (1. + a) * pow(g, 1. / kGammaF) - a; + } + kLinearToGammaTabF[v] = (float)(MAX_Y_T * value); } // to prevent small rounding errors to cause read-overflow: kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize]; @@ -235,12 +250,12 @@ static fixed_y_t clip_y(int y) { //------------------------------------------------------------------------------ static int RGBToGray(int r, int g, int b) { - const int luma = 19595 * r + 38470 * g + 7471 * b + YUV_HALF; + const int luma = 13933 * r + 46871 * g + 4732 * b + YUV_HALF; return (luma >> YUV_FIX); } static float RGBToGrayF(float r, float g, float b) { - return 0.299f * r + 0.587f * g + 0.114f * b; + return (float)(0.2126 * r + 0.7152 * g + 0.0722 * b); } static int ScaleDown(int a, int b, int c, int d) { @@ -251,58 +266,50 @@ static int ScaleDown(int a, int b, int c, int d) { return LinearToGammaF(0.25f * (A + B + C + D)); } -static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int len) { - while (len-- > 0) { - const float R = GammaToLinearF(src[0]); - const float G = GammaToLinearF(src[1]); - const float B = GammaToLinearF(src[2]); +static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) { + int i; + for (i = 0; i < w; ++i) { + const float R = GammaToLinearF(src[0 * w + i]); + const float G = GammaToLinearF(src[1 * w + i]); + const float B = GammaToLinearF(src[2 * w + i]); const float Y = RGBToGrayF(R, G, B); - *dst++ = (fixed_y_t)LinearToGammaF(Y); - src += 3; + dst[i] = (fixed_y_t)LinearToGammaF(Y); } } -static int UpdateChroma(const fixed_y_t* src1, - const fixed_y_t* src2, - fixed_t* dst, fixed_y_t* tmp, int len) { - int diff = 0; - while (len--> 0) { - const int r = ScaleDown(src1[0], src1[3], src2[0], src2[3]); - const int g = ScaleDown(src1[1], src1[4], src2[1], src2[4]); - const int b = ScaleDown(src1[2], src1[5], src2[2], src2[5]); +static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2, + fixed_t* dst, int uv_w) { + int i; + for (i = 0; i < uv_w; ++i) { + const int r = ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], + src2[0 * uv_w + 0], src2[0 * uv_w + 1]); + const int g = ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], + src2[2 * uv_w + 0], src2[2 * uv_w + 1]); + const int b = ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], + src2[4 * uv_w + 0], src2[4 * uv_w + 1]); const int W = RGBToGray(r, g, b); - const int r_avg = (src1[0] + src1[3] + src2[0] + src2[3] + 2) >> 2; - const int g_avg = (src1[1] + src1[4] + src2[1] + src2[4] + 2) >> 2; - const int b_avg = (src1[2] + src1[5] + src2[2] + src2[5] + 2) >> 2; - dst[0] = (fixed_t)(r - W); - dst[1] = (fixed_t)(g - W); - dst[2] = (fixed_t)(b - W); - dst += 3; - src1 += 6; - src2 += 6; - if (tmp != NULL) { - tmp[0] = tmp[1] = clip_y(W); - tmp += 2; - } - diff += abs(RGBToGray(r_avg, g_avg, b_avg) - W); + dst[0 * uv_w] = (fixed_t)(r - W); + dst[1 * uv_w] = (fixed_t)(g - W); + dst[2 * uv_w] = (fixed_t)(b - W); + dst += 1; + src1 += 2; + src2 += 2; } - return diff; } -//------------------------------------------------------------------------------ - -static WEBP_INLINE int Filter(const fixed_t* const A, const fixed_t* const B, - int rightwise) { - int v; - if (!rightwise) { - v = (A[0] * 9 + A[-3] * 3 + B[0] * 3 + B[-3]); - } else { - v = (A[0] * 9 + A[+3] * 3 + B[0] * 3 + B[+3]); +static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) { + int i; + for (i = 0; i < w; ++i) { + y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]); } - return (v + 8) >> 4; } -static WEBP_INLINE int Filter2(int A, int B) { return (A * 3 + B + 2) >> 2; } +//------------------------------------------------------------------------------ + +static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0) { + const int v0 = (A * 3 + B + 2) >> 2; + return clip_y(v0 + W0); +} //------------------------------------------------------------------------------ @@ -317,52 +324,50 @@ static void ImportOneRow(const uint8_t* const r_ptr, int pic_width, fixed_y_t* const dst) { int i; + const int w = (pic_width + 1) & ~1; for (i = 0; i < pic_width; ++i) { const int off = i * step; - dst[3 * i + 0] = UpLift(r_ptr[off]); - dst[3 * i + 1] = UpLift(g_ptr[off]); - dst[3 * i + 2] = UpLift(b_ptr[off]); + dst[i + 0 * w] = UpLift(r_ptr[off]); + dst[i + 1 * w] = UpLift(g_ptr[off]); + dst[i + 2 * w] = UpLift(b_ptr[off]); } if (pic_width & 1) { // replicate rightmost pixel - memcpy(dst + 3 * pic_width, dst + 3 * (pic_width - 1), 3 * sizeof(*dst)); + dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1]; + dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1]; + dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1]; } } static void InterpolateTwoRows(const fixed_y_t* const best_y, - const fixed_t* const prev_uv, - const fixed_t* const cur_uv, - const fixed_t* const next_uv, + const fixed_t* prev_uv, + const fixed_t* cur_uv, + const fixed_t* next_uv, int w, - fixed_y_t* const out1, - fixed_y_t* const out2) { - int i, k; - { // special boundary case for i==0 - const int W0 = best_y[0]; - const int W1 = best_y[w]; - for (k = 0; k <= 2; ++k) { - out1[k] = clip_y(Filter2(cur_uv[k], prev_uv[k]) + W0); - out2[k] = clip_y(Filter2(cur_uv[k], next_uv[k]) + W1); - } - } - for (i = 1; i < w - 1; ++i) { - const int W0 = best_y[i + 0]; - const int W1 = best_y[i + w]; - const int off = 3 * (i >> 1); - for (k = 0; k <= 2; ++k) { - const int tmp0 = Filter(cur_uv + off + k, prev_uv + off + k, i & 1); - const int tmp1 = Filter(cur_uv + off + k, next_uv + off + k, i & 1); - out1[3 * i + k] = clip_y(tmp0 + W0); - out2[3 * i + k] = clip_y(tmp1 + W1); - } - } - { // special boundary case for i == w - 1 - const int W0 = best_y[i + 0]; - const int W1 = best_y[i + w]; - const int off = 3 * (i >> 1); - for (k = 0; k <= 2; ++k) { - out1[3 * i + k] = clip_y(Filter2(cur_uv[off + k], prev_uv[off + k]) + W0); - out2[3 * i + k] = clip_y(Filter2(cur_uv[off + k], next_uv[off + k]) + W1); + fixed_y_t* out1, + fixed_y_t* out2) { + const int uv_w = w >> 1; + const int len = (w - 1) >> 1; // length to filter + int k = 3; + while (k-- > 0) { // process each R/G/B segments in turn + // special boundary case for i==0 + out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0]); + out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w]); + + WebPSharpYUVFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1); + WebPSharpYUVFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1); + + // special boundary case for i == w - 1 when w is even + if (!(w & 1)) { + out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1], + best_y[w - 1 + 0]); + out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1], + best_y[w - 1 + w]); } + out1 += w; + out2 += w; + prev_uv += uv_w; + cur_uv += uv_w; + next_uv += uv_w; } } @@ -381,36 +386,42 @@ static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) { return clip_8b(128 + (v >> (YUV_FIX + SFIX))); } -static int ConvertWRGBToYUV(const fixed_y_t* const best_y, - const fixed_t* const best_uv, +static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv, WebPPicture* const picture) { int i, j; + uint8_t* dst_y = picture->y; + uint8_t* dst_u = picture->u; + uint8_t* dst_v = picture->v; + const fixed_t* const best_uv_base = best_uv; const int w = (picture->width + 1) & ~1; const int h = (picture->height + 1) & ~1; const int uv_w = w >> 1; const int uv_h = h >> 1; - for (j = 0; j < picture->height; ++j) { + for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) { for (i = 0; i < picture->width; ++i) { - const int off = 3 * ((i >> 1) + (j >> 1) * uv_w); - const int off2 = i + j * picture->y_stride; - const int W = best_y[i + j * w]; - const int r = best_uv[off + 0] + W; - const int g = best_uv[off + 1] + W; - const int b = best_uv[off + 2] + W; - picture->y[off2] = ConvertRGBToY(r, g, b); + const int off = (i >> 1); + const int W = best_y[i]; + const int r = best_uv[off + 0 * uv_w] + W; + const int g = best_uv[off + 1 * uv_w] + W; + const int b = best_uv[off + 2 * uv_w] + W; + dst_y[i] = ConvertRGBToY(r, g, b); } + best_y += w; + best_uv += (j & 1) * 3 * uv_w; + dst_y += picture->y_stride; } - for (j = 0; j < uv_h; ++j) { - uint8_t* const dst_u = picture->u + j * picture->uv_stride; - uint8_t* const dst_v = picture->v + j * picture->uv_stride; + for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) { for (i = 0; i < uv_w; ++i) { - const int off = 3 * (i + j * uv_w); - const int r = best_uv[off + 0]; - const int g = best_uv[off + 1]; - const int b = best_uv[off + 2]; + const int off = i; + const int r = best_uv[off + 0 * uv_w]; + const int g = best_uv[off + 1 * uv_w]; + const int b = best_uv[off + 2 * uv_w]; dst_u[i] = ConvertRGBToU(r, g, b); dst_v[i] = ConvertRGBToV(r, g, b); } + best_uv += 3 * uv_w; + dst_u += picture->uv_stride; + dst_v += picture->uv_stride; } return 1; } @@ -420,9 +431,9 @@ static int ConvertWRGBToYUV(const fixed_y_t* const best_y, #define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T))) -static int PreprocessARGB(const uint8_t* const r_ptr, - const uint8_t* const g_ptr, - const uint8_t* const b_ptr, +static int PreprocessARGB(const uint8_t* r_ptr, + const uint8_t* g_ptr, + const uint8_t* b_ptr, int step, int rgb_stride, WebPPicture* const picture) { // we expand the right/bottom border if needed @@ -430,25 +441,27 @@ static int PreprocessARGB(const uint8_t* const r_ptr, const int h = (picture->height + 1) & ~1; const int uv_w = w >> 1; const int uv_h = h >> 1; - int i, j, iter; + uint64_t prev_diff_y_sum = ~0; + int j, iter; // TODO(skal): allocate one big memory chunk. But for now, it's easier // for valgrind debugging to have several chunks. fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch - fixed_y_t* const best_y = SAFE_ALLOC(w, h, fixed_y_t); - fixed_y_t* const target_y = SAFE_ALLOC(w, h, fixed_y_t); + fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t); + fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t); fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); - fixed_t* const best_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); - fixed_t* const target_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); + fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); + fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); + fixed_y_t* best_y = best_y_base; + fixed_y_t* target_y = target_y_base; + fixed_t* best_uv = best_uv_base; + fixed_t* target_uv = target_uv_base; + const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h); int ok; - int diff_sum = 0; - const int first_diff_threshold = (int)(2.5 * w * h); - const int min_improvement = 5; // stop if improvement is below this % - const int min_first_improvement = 80; - if (best_y == NULL || best_uv == NULL || - target_y == NULL || target_uv == NULL || + if (best_y_base == NULL || best_uv_base == NULL || + target_y_base == NULL || target_uv_base == NULL || best_rgb_y == NULL || best_rgb_uv == NULL || tmp_buffer == NULL) { ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); @@ -457,101 +470,86 @@ static int PreprocessARGB(const uint8_t* const r_ptr, assert(picture->width >= kMinDimensionIterativeConversion); assert(picture->height >= kMinDimensionIterativeConversion); + WebPInitConvertARGBToYUV(); + // Import RGB samples to W/RGB representation. for (j = 0; j < picture->height; j += 2) { const int is_last_row = (j == picture->height - 1); - fixed_y_t* const src1 = tmp_buffer; + fixed_y_t* const src1 = tmp_buffer + 0 * w; fixed_y_t* const src2 = tmp_buffer + 3 * w; - const int off1 = j * rgb_stride; - const int off2 = off1 + rgb_stride; - const int uv_off = (j >> 1) * 3 * uv_w; - fixed_y_t* const dst_y = best_y + j * w; // prepare two rows of input - ImportOneRow(r_ptr + off1, g_ptr + off1, b_ptr + off1, - step, picture->width, src1); + ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1); if (!is_last_row) { - ImportOneRow(r_ptr + off2, g_ptr + off2, b_ptr + off2, + ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride, step, picture->width, src2); } else { memcpy(src2, src1, 3 * w * sizeof(*src2)); } - UpdateW(src1, target_y + (j + 0) * w, w); - UpdateW(src2, target_y + (j + 1) * w, w); - diff_sum += UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w); - memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv)); - memcpy(dst_y + w, dst_y, w * sizeof(*dst_y)); + StoreGray(src1, best_y + 0, w); + StoreGray(src2, best_y + w, w); + + UpdateW(src1, target_y, w); + UpdateW(src2, target_y + w, w); + UpdateChroma(src1, src2, target_uv, uv_w); + memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv)); + best_y += 2 * w; + best_uv += 3 * uv_w; + target_y += 2 * w; + target_uv += 3 * uv_w; + r_ptr += 2 * rgb_stride; + g_ptr += 2 * rgb_stride; + b_ptr += 2 * rgb_stride; } // Iterate and resolve clipping conflicts. for (iter = 0; iter < kNumIterations; ++iter) { - int k; - const fixed_t* cur_uv = best_uv; - const fixed_t* prev_uv = best_uv; - const int old_diff_sum = diff_sum; - diff_sum = 0; + const fixed_t* cur_uv = best_uv_base; + const fixed_t* prev_uv = best_uv_base; + uint64_t diff_y_sum = 0; + + best_y = best_y_base; + best_uv = best_uv_base; + target_y = target_y_base; + target_uv = target_uv_base; for (j = 0; j < h; j += 2) { - fixed_y_t* const src1 = tmp_buffer; + fixed_y_t* const src1 = tmp_buffer + 0 * w; fixed_y_t* const src2 = tmp_buffer + 3 * w; { const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); - InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv, - w, src1, src2); + InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2); prev_uv = cur_uv; cur_uv = next_uv; } UpdateW(src1, best_rgb_y + 0 * w, w); UpdateW(src2, best_rgb_y + 1 * w, w); - diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); + UpdateChroma(src1, src2, best_rgb_uv, uv_w); // update two rows of Y and one row of RGB - for (i = 0; i < 2 * w; ++i) { - const int off = i + j * w; - const int diff_y = target_y[off] - best_rgb_y[i]; - const int new_y = (int)best_y[off] + diff_y; - best_y[off] = clip_y(new_y); - } - for (i = 0; i < uv_w; ++i) { - const int off = 3 * (i + (j >> 1) * uv_w); - int W; - for (k = 0; k <= 2; ++k) { - const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[3 * i + k]; - best_uv[off + k] += diff_uv; - } - W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]); - for (k = 0; k <= 2; ++k) { - best_uv[off + k] -= W; - } - } + diff_y_sum += WebPSharpYUVUpdateY(target_y, best_rgb_y, best_y, 2 * w); + WebPSharpYUVUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w); + + best_y += 2 * w; + best_uv += 3 * uv_w; + target_y += 2 * w; + target_uv += 3 * uv_w; } // test exit condition - if (diff_sum > 0) { - const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum; - // Check if first iteration gave good result already, without a large - // jump of improvement (otherwise it means we need to try few extra - // iterations, just to be sure). - if (iter == 0 && diff_sum < first_diff_threshold && - improvement < min_first_improvement) { - break; - } - // then, check if improvement is stalling. - if (improvement < min_improvement) { - break; - } - } else { - break; + if (iter > 0) { + if (diff_y_sum < diff_y_threshold) break; + if (diff_y_sum > prev_diff_y_sum) break; } + prev_diff_y_sum = diff_y_sum; } - // final reconstruction - ok = ConvertWRGBToYUV(best_y, best_uv, picture); + ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture); End: - WebPSafeFree(best_y); - WebPSafeFree(best_uv); - WebPSafeFree(target_y); - WebPSafeFree(target_uv); + WebPSafeFree(best_y_base); + WebPSafeFree(best_uv_base); + WebPSafeFree(target_y_base); + WebPSafeFree(target_uv_base); WebPSafeFree(best_rgb_y); WebPSafeFree(best_rgb_uv); WebPSafeFree(tmp_buffer); @@ -830,10 +828,10 @@ static WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb, } } -static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, - const uint8_t* const g_ptr, - const uint8_t* const b_ptr, - const uint8_t* const a_ptr, +static int ImportYUVAFromRGBA(const uint8_t* r_ptr, + const uint8_t* g_ptr, + const uint8_t* b_ptr, + const uint8_t* a_ptr, int step, // bytes per pixel int rgb_stride, // bytes per scanline float dithering, @@ -900,36 +898,34 @@ static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, // Downsample Y/U/V planes, two rows at a time for (y = 0; y < (height >> 1); ++y) { int rows_have_alpha = has_alpha; - const int off1 = (2 * y + 0) * rgb_stride; - const int off2 = (2 * y + 1) * rgb_stride; if (use_dsp) { if (is_rgb) { - WebPConvertRGB24ToY(r_ptr + off1, dst_y, width); - WebPConvertRGB24ToY(r_ptr + off2, dst_y + picture->y_stride, width); + WebPConvertRGB24ToY(r_ptr, dst_y, width); + WebPConvertRGB24ToY(r_ptr + rgb_stride, + dst_y + picture->y_stride, width); } else { - WebPConvertBGR24ToY(b_ptr + off1, dst_y, width); - WebPConvertBGR24ToY(b_ptr + off2, dst_y + picture->y_stride, width); + WebPConvertBGR24ToY(b_ptr, dst_y, width); + WebPConvertBGR24ToY(b_ptr + rgb_stride, + dst_y + picture->y_stride, width); } } else { - ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step, - dst_y, width, rg); - ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step, + ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); + ConvertRowToY(r_ptr + rgb_stride, + g_ptr + rgb_stride, + b_ptr + rgb_stride, step, dst_y + picture->y_stride, width, rg); } dst_y += 2 * picture->y_stride; if (has_alpha) { - rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride, - width, 2, + rows_have_alpha &= !WebPExtractAlpha(a_ptr, rgb_stride, width, 2, dst_a, picture->a_stride); dst_a += 2 * picture->a_stride; } // Collect averaged R/G/B(/A) if (!rows_have_alpha) { - AccumulateRGB(r_ptr + off1, g_ptr + off1, b_ptr + off1, - step, rgb_stride, tmp_rgb, width); + AccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width); } else { - AccumulateRGBA(r_ptr + off1, g_ptr + off1, b_ptr + off1, a_ptr + off1, - rgb_stride, tmp_rgb, width); + AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb, width); } // Convert to U/V if (rg == NULL) { @@ -939,31 +935,33 @@ static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, } dst_u += picture->uv_stride; dst_v += picture->uv_stride; + r_ptr += 2 * rgb_stride; + b_ptr += 2 * rgb_stride; + g_ptr += 2 * rgb_stride; + if (has_alpha) a_ptr += 2 * rgb_stride; } if (height & 1) { // extra last row - const int off = 2 * y * rgb_stride; int row_has_alpha = has_alpha; if (use_dsp) { if (r_ptr < b_ptr) { - WebPConvertRGB24ToY(r_ptr + off, dst_y, width); + WebPConvertRGB24ToY(r_ptr, dst_y, width); } else { - WebPConvertBGR24ToY(b_ptr + off, dst_y, width); + WebPConvertBGR24ToY(b_ptr, dst_y, width); } } else { - ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step, - dst_y, width, rg); + ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); } if (row_has_alpha) { - row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0); + row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0); } // Collect averaged R/G/B(/A) if (!row_has_alpha) { // Collect averaged R/G/B - AccumulateRGB(r_ptr + off, g_ptr + off, b_ptr + off, - step, /* rgb_stride = */ 0, tmp_rgb, width); + AccumulateRGB(r_ptr, g_ptr, b_ptr, step, /* rgb_stride = */ 0, + tmp_rgb, width); } else { - AccumulateRGBA(r_ptr + off, g_ptr + off, b_ptr + off, a_ptr + off, - /* rgb_stride = */ 0, tmp_rgb, width); + AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /* rgb_stride = */ 0, + tmp_rgb, width); } if (rg == NULL) { WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); @@ -1013,9 +1011,13 @@ int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) { return PictureARGBToYUVA(picture, colorspace, 0.f, 0); } -int WebPPictureSmartARGBToYUVA(WebPPicture* picture) { +int WebPPictureSharpARGBToYUVA(WebPPicture* picture) { return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1); } +// for backward compatibility +int WebPPictureSmartARGBToYUVA(WebPPicture* picture) { + return WebPPictureSharpARGBToYUVA(picture); +} //------------------------------------------------------------------------------ // call for YUVA -> ARGB conversion @@ -1086,10 +1088,10 @@ static int Import(WebPPicture* const picture, const uint8_t* const rgb, int rgb_stride, int step, int swap_rb, int import_alpha) { int y; - const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0); - const uint8_t* const g_ptr = rgb + 1; - const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2); - const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL; + const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0); + const uint8_t* g_ptr = rgb + 1; + const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2); + const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL; const int width = picture->width; const int height = picture->height; @@ -1102,20 +1104,25 @@ static int Import(WebPPicture* const picture, VP8EncDspARGBInit(); if (import_alpha) { + uint32_t* dst = picture->argb; assert(step == 4); for (y = 0; y < height; ++y) { - uint32_t* const dst = &picture->argb[y * picture->argb_stride]; - const int offset = y * rgb_stride; - VP8PackARGB(a_ptr + offset, r_ptr + offset, g_ptr + offset, - b_ptr + offset, width, dst); + VP8PackARGB(a_ptr, r_ptr, g_ptr, b_ptr, width, dst); + a_ptr += rgb_stride; + r_ptr += rgb_stride; + g_ptr += rgb_stride; + b_ptr += rgb_stride; + dst += picture->argb_stride; } } else { + uint32_t* dst = picture->argb; assert(step >= 3); for (y = 0; y < height; ++y) { - uint32_t* const dst = &picture->argb[y * picture->argb_stride]; - const int offset = y * rgb_stride; - VP8PackRGB(r_ptr + offset, g_ptr + offset, b_ptr + offset, - width, step, dst); + VP8PackRGB(r_ptr, g_ptr, b_ptr, width, step, dst); + r_ptr += rgb_stride; + g_ptr += rgb_stride; + b_ptr += rgb_stride; + dst += picture->argb_stride; } } return 1; diff --git a/src/3rdparty/libwebp/src/enc/picture.c b/src/3rdparty/libwebp/src/enc/picture_enc.c similarity index 97% rename from src/3rdparty/libwebp/src/enc/picture.c rename to src/3rdparty/libwebp/src/enc/picture_enc.c index d9befbc47d93fa0dcd1a1c5ac73c4a748f1df747..dfa66510fbe26011323fb9bbc4eca0d75ac1080c 100644 --- a/src/3rdparty/libwebp/src/enc/picture.c +++ b/src/3rdparty/libwebp/src/enc/picture_enc.c @@ -14,7 +14,7 @@ #include <assert.h> #include <stdlib.h> -#include "./vp8enci.h" +#include "./vp8i_enc.h" #include "../dsp/dsp.h" #include "../utils/utils.h" @@ -88,8 +88,9 @@ int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) { } int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) { - const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK; - const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT; + const WebPEncCSP uv_csp = + (WebPEncCSP)((int)picture->colorspace & WEBP_CSP_UV_MASK); + const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT; const int y_stride = width; const int uv_width = (width + 1) >> 1; const int uv_height = (height + 1) >> 1; diff --git a/src/3rdparty/libwebp/src/enc/picture_psnr.c b/src/3rdparty/libwebp/src/enc/picture_psnr.c deleted file mode 100644 index 81ab1b5ca1c371c677035fe75d5b7c5661985ed2..0000000000000000000000000000000000000000 --- a/src/3rdparty/libwebp/src/enc/picture_psnr.c +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2014 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. -// ----------------------------------------------------------------------------- -// -// WebPPicture tools for measuring distortion -// -// Author: Skal (pascal.massimino@gmail.com) - -#include <math.h> -#include <stdlib.h> - -#include "./vp8enci.h" -#include "../utils/utils.h" - -//------------------------------------------------------------------------------ -// local-min distortion -// -// For every pixel in the *reference* picture, we search for the local best -// match in the compressed image. This is not a symmetrical measure. - -#define RADIUS 2 // search radius. Shouldn't be too large. - -static void AccumulateLSIM(const uint8_t* src, int src_stride, - const uint8_t* ref, int ref_stride, - int w, int h, VP8DistoStats* stats) { - int x, y; - double total_sse = 0.; - for (y = 0; y < h; ++y) { - const int y_0 = (y - RADIUS < 0) ? 0 : y - RADIUS; - const int y_1 = (y + RADIUS + 1 >= h) ? h : y + RADIUS + 1; - for (x = 0; x < w; ++x) { - const int x_0 = (x - RADIUS < 0) ? 0 : x - RADIUS; - const int x_1 = (x + RADIUS + 1 >= w) ? w : x + RADIUS + 1; - double best_sse = 255. * 255.; - const double value = (double)ref[y * ref_stride + x]; - int i, j; - for (j = y_0; j < y_1; ++j) { - const uint8_t* const s = src + j * src_stride; - for (i = x_0; i < x_1; ++i) { - const double diff = s[i] - value; - const double sse = diff * diff; - if (sse < best_sse) best_sse = sse; - } - } - total_sse += best_sse; - } - } - stats->w = w * h; - stats->xm = 0; - stats->ym = 0; - stats->xxm = total_sse; - stats->yym = 0; - stats->xxm = 0; -} -#undef RADIUS - -//------------------------------------------------------------------------------ -// Distortion - -// Max value returned in case of exact similarity. -static const double kMinDistortion_dB = 99.; -static float GetPSNR(const double v) { - return (float)((v > 0.) ? -4.3429448 * log(v / (255 * 255.)) - : kMinDistortion_dB); -} - -int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, - int type, float result[5]) { - VP8DistoStats stats[5]; - int w, h; - - memset(stats, 0, sizeof(stats)); - - VP8SSIMDspInit(); - - if (src == NULL || ref == NULL || - src->width != ref->width || src->height != ref->height || - src->use_argb != ref->use_argb || result == NULL) { - return 0; - } - w = src->width; - h = src->height; - - if (src->use_argb == 1) { - if (src->argb == NULL || ref->argb == NULL) { - return 0; - } else { - int i, j, c; - uint8_t* tmp1, *tmp2; - uint8_t* const tmp_plane = - (uint8_t*)WebPSafeMalloc(2ULL * w * h, sizeof(*tmp_plane)); - if (tmp_plane == NULL) return 0; - tmp1 = tmp_plane; - tmp2 = tmp_plane + w * h; - for (c = 0; c < 4; ++c) { - for (j = 0; j < h; ++j) { - for (i = 0; i < w; ++i) { - tmp1[j * w + i] = src->argb[i + j * src->argb_stride] >> (c * 8); - tmp2[j * w + i] = ref->argb[i + j * ref->argb_stride] >> (c * 8); - } - } - if (type >= 2) { - AccumulateLSIM(tmp1, w, tmp2, w, w, h, &stats[c]); - } else { - VP8SSIMAccumulatePlane(tmp1, w, tmp2, w, w, h, &stats[c]); - } - } - free(tmp_plane); - } - } else { - int has_alpha, uv_w, uv_h; - if (src->y == NULL || ref->y == NULL || - src->u == NULL || ref->u == NULL || - src->v == NULL || ref->v == NULL) { - return 0; - } - has_alpha = !!(src->colorspace & WEBP_CSP_ALPHA_BIT); - if (has_alpha != !!(ref->colorspace & WEBP_CSP_ALPHA_BIT) || - (has_alpha && (src->a == NULL || ref->a == NULL))) { - return 0; - } - - uv_w = (src->width + 1) >> 1; - uv_h = (src->height + 1) >> 1; - if (type >= 2) { - AccumulateLSIM(src->y, src->y_stride, ref->y, ref->y_stride, - w, h, &stats[0]); - AccumulateLSIM(src->u, src->uv_stride, ref->u, ref->uv_stride, - uv_w, uv_h, &stats[1]); - AccumulateLSIM(src->v, src->uv_stride, ref->v, ref->uv_stride, - uv_w, uv_h, &stats[2]); - if (has_alpha) { - AccumulateLSIM(src->a, src->a_stride, ref->a, ref->a_stride, - w, h, &stats[3]); - } - } else { - VP8SSIMAccumulatePlane(src->y, src->y_stride, - ref->y, ref->y_stride, - w, h, &stats[0]); - VP8SSIMAccumulatePlane(src->u, src->uv_stride, - ref->u, ref->uv_stride, - uv_w, uv_h, &stats[1]); - VP8SSIMAccumulatePlane(src->v, src->uv_stride, - ref->v, ref->uv_stride, - uv_w, uv_h, &stats[2]); - if (has_alpha) { - VP8SSIMAccumulatePlane(src->a, src->a_stride, - ref->a, ref->a_stride, - w, h, &stats[3]); - } - } - } - // Final stat calculations. - { - int c; - for (c = 0; c <= 4; ++c) { - if (type == 1) { - const double v = VP8SSIMGet(&stats[c]); - result[c] = (float)((v < 1.) ? -10.0 * log10(1. - v) - : kMinDistortion_dB); - } else { - const double v = VP8SSIMGetSquaredError(&stats[c]); - result[c] = GetPSNR(v); - } - // Accumulate forward - if (c < 4) VP8SSIMAddStats(&stats[c], &stats[4]); - } - } - return 1; -} - -//------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/enc/picture_psnr_enc.c b/src/3rdparty/libwebp/src/enc/picture_psnr_enc.c new file mode 100644 index 0000000000000000000000000000000000000000..9c0b2295077103e2c5ce8432363efe1f45c31e4e --- /dev/null +++ b/src/3rdparty/libwebp/src/enc/picture_psnr_enc.c @@ -0,0 +1,213 @@ +// Copyright 2014 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. +// ----------------------------------------------------------------------------- +// +// WebPPicture tools for measuring distortion +// +// Author: Skal (pascal.massimino@gmail.com) + +#include <math.h> +#include <stdlib.h> + +#include "./vp8i_enc.h" +#include "../utils/utils.h" + +typedef double (*AccumulateFunc)(const uint8_t* src, int src_stride, + const uint8_t* ref, int ref_stride, + int w, int h); + +//------------------------------------------------------------------------------ +// local-min distortion +// +// For every pixel in the *reference* picture, we search for the local best +// match in the compressed image. This is not a symmetrical measure. + +#define RADIUS 2 // search radius. Shouldn't be too large. + +static double AccumulateLSIM(const uint8_t* src, int src_stride, + const uint8_t* ref, int ref_stride, + int w, int h) { + int x, y; + double total_sse = 0.; + for (y = 0; y < h; ++y) { + const int y_0 = (y - RADIUS < 0) ? 0 : y - RADIUS; + const int y_1 = (y + RADIUS + 1 >= h) ? h : y + RADIUS + 1; + for (x = 0; x < w; ++x) { + const int x_0 = (x - RADIUS < 0) ? 0 : x - RADIUS; + const int x_1 = (x + RADIUS + 1 >= w) ? w : x + RADIUS + 1; + double best_sse = 255. * 255.; + const double value = (double)ref[y * ref_stride + x]; + int i, j; + for (j = y_0; j < y_1; ++j) { + const uint8_t* const s = src + j * src_stride; + for (i = x_0; i < x_1; ++i) { + const double diff = s[i] - value; + const double sse = diff * diff; + if (sse < best_sse) best_sse = sse; + } + } + total_sse += best_sse; + } + } + return total_sse; +} +#undef RADIUS + +static double AccumulateSSE(const uint8_t* src, int src_stride, + const uint8_t* ref, int ref_stride, + int w, int h) { + int y; + double total_sse = 0.; + for (y = 0; y < h; ++y) { + total_sse += VP8AccumulateSSE(src, ref, w); + src += src_stride; + ref += ref_stride; + } + return total_sse; +} + +//------------------------------------------------------------------------------ + +static double AccumulateSSIM(const uint8_t* src, int src_stride, + const uint8_t* ref, int ref_stride, + int w, int h) { + const int w0 = (w < VP8_SSIM_KERNEL) ? w : VP8_SSIM_KERNEL; + const int w1 = w - VP8_SSIM_KERNEL - 1; + const int h0 = (h < VP8_SSIM_KERNEL) ? h : VP8_SSIM_KERNEL; + const int h1 = h - VP8_SSIM_KERNEL - 1; + int x, y; + double sum = 0.; + for (y = 0; y < h0; ++y) { + for (x = 0; x < w; ++x) { + sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); + } + } + for (; y < h1; ++y) { + for (x = 0; x < w0; ++x) { + sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); + } + for (; x < w1; ++x) { + const int off1 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * src_stride; + const int off2 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * ref_stride; + sum += VP8SSIMGet(src + off1, src_stride, ref + off2, ref_stride); + } + for (; x < w; ++x) { + sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); + } + } + for (; y < h; ++y) { + for (x = 0; x < w; ++x) { + sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); + } + } + return sum; +} + +//------------------------------------------------------------------------------ +// Distortion + +// Max value returned in case of exact similarity. +static const double kMinDistortion_dB = 99.; + +static double GetPSNR(double v, double size) { + return (v > 0. && size > 0.) ? -4.3429448 * log(v / (size * 255 * 255.)) + : kMinDistortion_dB; +} + +static double GetLogSSIM(double v, double size) { + v = (size > 0.) ? v / size : 1.; + return (v < 1.) ? -10.0 * log10(1. - v) : kMinDistortion_dB; +} + +int WebPPlaneDistortion(const uint8_t* src, size_t src_stride, + const uint8_t* ref, size_t ref_stride, + int width, int height, size_t x_step, + int type, float* distortion, float* result) { + uint8_t* allocated = NULL; + const AccumulateFunc metric = (type == 0) ? AccumulateSSE : + (type == 1) ? AccumulateSSIM : + AccumulateLSIM; + if (src == NULL || ref == NULL || + src_stride < x_step * width || ref_stride < x_step * width || + result == NULL || distortion == NULL) { + return 0; + } + + VP8SSIMDspInit(); + if (x_step != 1) { // extract a packed plane if needed + int x, y; + uint8_t* tmp1; + uint8_t* tmp2; + allocated = + (uint8_t*)WebPSafeMalloc(2ULL * width * height, sizeof(*allocated)); + if (allocated == NULL) return 0; + tmp1 = allocated; + tmp2 = tmp1 + (size_t)width * height; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + tmp1[x + y * width] = src[x * x_step + y * src_stride]; + tmp2[x + y * width] = ref[x * x_step + y * ref_stride]; + } + } + src = tmp1; + ref = tmp2; + } + *distortion = (float)metric(src, width, ref, width, width, height); + WebPSafeFree(allocated); + + *result = (type == 1) ? (float)GetLogSSIM(*distortion, (double)width * height) + : (float)GetPSNR(*distortion, (double)width * height); + return 1; +} + +int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, + int type, float results[5]) { + int w, h, c; + int ok = 0; + WebPPicture p0, p1; + double total_size = 0., total_distortion = 0.; + if (src == NULL || ref == NULL || + src->width != ref->width || src->height != ref->height || + results == NULL) { + return 0; + } + + VP8SSIMDspInit(); + if (!WebPPictureInit(&p0) || !WebPPictureInit(&p1)) return 0; + w = src->width; + h = src->height; + if (!WebPPictureView(src, 0, 0, w, h, &p0)) goto Error; + if (!WebPPictureView(ref, 0, 0, w, h, &p1)) goto Error; + + // We always measure distortion in ARGB space. + if (p0.use_argb == 0 && !WebPPictureYUVAToARGB(&p0)) goto Error; + if (p1.use_argb == 0 && !WebPPictureYUVAToARGB(&p1)) goto Error; + for (c = 0; c < 4; ++c) { + float distortion; + const size_t stride0 = 4 * (size_t)p0.argb_stride; + const size_t stride1 = 4 * (size_t)p1.argb_stride; + if (!WebPPlaneDistortion((const uint8_t*)p0.argb + c, stride0, + (const uint8_t*)p1.argb + c, stride1, + w, h, 4, type, &distortion, results + c)) { + goto Error; + } + total_distortion += distortion; + total_size += w * h; + } + + results[4] = (type == 1) ? (float)GetLogSSIM(total_distortion, total_size) + : (float)GetPSNR(total_distortion, total_size); + ok = 1; + + Error: + WebPPictureFree(&p0); + WebPPictureFree(&p1); + return ok; +} + +//------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/enc/picture_rescale.c b/src/3rdparty/libwebp/src/enc/picture_rescale_enc.c similarity index 99% rename from src/3rdparty/libwebp/src/enc/picture_rescale.c rename to src/3rdparty/libwebp/src/enc/picture_rescale_enc.c index 9f19e8e80f48ceb86e686d1aec918119acd0eb7c..0b7181c0d7145c87ddd9109bd1f4529bf32d35ab 100644 --- a/src/3rdparty/libwebp/src/enc/picture_rescale.c +++ b/src/3rdparty/libwebp/src/enc/picture_rescale_enc.c @@ -14,8 +14,8 @@ #include <assert.h> #include <stdlib.h> -#include "./vp8enci.h" -#include "../utils/rescaler.h" +#include "./vp8i_enc.h" +#include "../utils/rescaler_utils.h" #include "../utils/utils.h" #define HALVE(x) (((x) + 1) >> 1) diff --git a/src/3rdparty/libwebp/src/enc/picture_tools.c b/src/3rdparty/libwebp/src/enc/picture_tools_enc.c similarity index 99% rename from src/3rdparty/libwebp/src/enc/picture_tools.c rename to src/3rdparty/libwebp/src/enc/picture_tools_enc.c index bf97af84081a8173aaead759c8362897eb3eca9d..895df51156d86dc899290a3f8aa4a6e0c7171a6c 100644 --- a/src/3rdparty/libwebp/src/enc/picture_tools.c +++ b/src/3rdparty/libwebp/src/enc/picture_tools_enc.c @@ -13,7 +13,7 @@ #include <assert.h> -#include "./vp8enci.h" +#include "./vp8i_enc.h" #include "../dsp/yuv.h" static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) { diff --git a/src/3rdparty/libwebp/src/enc/predictor_enc.c b/src/3rdparty/libwebp/src/enc/predictor_enc.c new file mode 100644 index 0000000000000000000000000000000000000000..0639b74f1cc08b324d265eb78c19231167fbdbf3 --- /dev/null +++ b/src/3rdparty/libwebp/src/enc/predictor_enc.c @@ -0,0 +1,750 @@ +// Copyright 2016 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. +// ----------------------------------------------------------------------------- +// +// Image transform methods for lossless encoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) +// Urvang Joshi (urvang@google.com) +// Vincent Rabaud (vrabaud@google.com) + +#include "../dsp/lossless.h" +#include "../dsp/lossless_common.h" +#include "./vp8li_enc.h" + +#define MAX_DIFF_COST (1e30f) + +static const float kSpatialPredictorBias = 15.f; +static const int kPredLowEffort = 11; +static const uint32_t kMaskAlpha = 0xff000000; + +// Mostly used to reduce code size + readability +static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; } +static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; } + +//------------------------------------------------------------------------------ +// Methods to calculate Entropy (Shannon). + +static float PredictionCostSpatial(const int counts[256], int weight_0, + double exp_val) { + const int significant_symbols = 256 >> 4; + const double exp_decay_factor = 0.6; + double bits = weight_0 * counts[0]; + int i; + for (i = 1; i < significant_symbols; ++i) { + bits += exp_val * (counts[i] + counts[256 - i]); + exp_val *= exp_decay_factor; + } + return (float)(-0.1 * bits); +} + +static float PredictionCostSpatialHistogram(const int accumulated[4][256], + const int tile[4][256]) { + int i; + double retval = 0; + for (i = 0; i < 4; ++i) { + const double kExpValue = 0.94; + retval += PredictionCostSpatial(tile[i], 1, kExpValue); + retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]); + } + return (float)retval; +} + +static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) { + ++histo_argb[0][argb >> 24]; + ++histo_argb[1][(argb >> 16) & 0xff]; + ++histo_argb[2][(argb >> 8) & 0xff]; + ++histo_argb[3][argb & 0xff]; +} + +//------------------------------------------------------------------------------ +// Spatial transform functions. + +static WEBP_INLINE void PredictBatch(int mode, int x_start, int y, + int num_pixels, const uint32_t* current, + const uint32_t* upper, uint32_t* out) { + if (x_start == 0) { + if (y == 0) { + // ARGB_BLACK. + VP8LPredictorsSub[0](current, NULL, 1, out); + } else { + // Top one. + VP8LPredictorsSub[2](current, upper, 1, out); + } + ++x_start; + ++out; + --num_pixels; + } + if (y == 0) { + // Left one. + VP8LPredictorsSub[1](current + x_start, NULL, num_pixels, out); + } else { + VP8LPredictorsSub[mode](current + x_start, upper + x_start, num_pixels, + out); + } +} + +static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) { + const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24)); + const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff)); + const int diff_g = abs((int)((p1 >> 8) & 0xff) - (int)((p2 >> 8) & 0xff)); + const int diff_b = abs((int)(p1 & 0xff) - (int)(p2 & 0xff)); + return GetMax(GetMax(diff_a, diff_r), GetMax(diff_g, diff_b)); +} + +static int MaxDiffAroundPixel(uint32_t current, uint32_t up, uint32_t down, + uint32_t left, uint32_t right) { + const int diff_up = MaxDiffBetweenPixels(current, up); + const int diff_down = MaxDiffBetweenPixels(current, down); + const int diff_left = MaxDiffBetweenPixels(current, left); + const int diff_right = MaxDiffBetweenPixels(current, right); + return GetMax(GetMax(diff_up, diff_down), GetMax(diff_left, diff_right)); +} + +static uint32_t AddGreenToBlueAndRed(uint32_t argb) { + const uint32_t green = (argb >> 8) & 0xff; + uint32_t red_blue = argb & 0x00ff00ffu; + red_blue += (green << 16) | green; + red_blue &= 0x00ff00ffu; + return (argb & 0xff00ff00u) | red_blue; +} + +static void MaxDiffsForRow(int width, int stride, const uint32_t* const argb, + uint8_t* const max_diffs, int used_subtract_green) { + uint32_t current, up, down, left, right; + int x; + if (width <= 2) return; + current = argb[0]; + right = argb[1]; + if (used_subtract_green) { + current = AddGreenToBlueAndRed(current); + right = AddGreenToBlueAndRed(right); + } + // max_diffs[0] and max_diffs[width - 1] are never used. + for (x = 1; x < width - 1; ++x) { + up = argb[-stride + x]; + down = argb[stride + x]; + left = current; + current = right; + right = argb[x + 1]; + if (used_subtract_green) { + up = AddGreenToBlueAndRed(up); + down = AddGreenToBlueAndRed(down); + right = AddGreenToBlueAndRed(right); + } + max_diffs[x] = MaxDiffAroundPixel(current, up, down, left, right); + } +} + +// Quantize the difference between the actual component value and its prediction +// to a multiple of quantization, working modulo 256, taking care not to cross +// a boundary (inclusive upper limit). +static uint8_t NearLosslessComponent(uint8_t value, uint8_t predict, + uint8_t boundary, int quantization) { + const int residual = (value - predict) & 0xff; + const int boundary_residual = (boundary - predict) & 0xff; + const int lower = residual & ~(quantization - 1); + const int upper = lower + quantization; + // Resolve ties towards a value closer to the prediction (i.e. towards lower + // if value comes after prediction and towards upper otherwise). + const int bias = ((boundary - value) & 0xff) < boundary_residual; + if (residual - lower < upper - residual + bias) { + // lower is closer to residual than upper. + if (residual > boundary_residual && lower <= boundary_residual) { + // Halve quantization step to avoid crossing boundary. This midpoint is + // on the same side of boundary as residual because midpoint >= residual + // (since lower is closer than upper) and residual is above the boundary. + return lower + (quantization >> 1); + } + return lower; + } else { + // upper is closer to residual than lower. + if (residual <= boundary_residual && upper > boundary_residual) { + // Halve quantization step to avoid crossing boundary. This midpoint is + // on the same side of boundary as residual because midpoint <= residual + // (since upper is closer than lower) and residual is below the boundary. + return lower + (quantization >> 1); + } + return upper & 0xff; + } +} + +// Quantize every component of the difference between the actual pixel value and +// its prediction to a multiple of a quantization (a power of 2, not larger than +// max_quantization which is a power of 2, smaller than max_diff). Take care if +// value and predict have undergone subtract green, which means that red and +// blue are represented as offsets from green. +static uint32_t NearLossless(uint32_t value, uint32_t predict, + int max_quantization, int max_diff, + int used_subtract_green) { + int quantization; + uint8_t new_green = 0; + uint8_t green_diff = 0; + uint8_t a, r, g, b; + if (max_diff <= 2) { + return VP8LSubPixels(value, predict); + } + quantization = max_quantization; + while (quantization >= max_diff) { + quantization >>= 1; + } + if ((value >> 24) == 0 || (value >> 24) == 0xff) { + // Preserve transparency of fully transparent or fully opaque pixels. + a = ((value >> 24) - (predict >> 24)) & 0xff; + } else { + a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization); + } + g = NearLosslessComponent((value >> 8) & 0xff, (predict >> 8) & 0xff, 0xff, + quantization); + if (used_subtract_green) { + // The green offset will be added to red and blue components during decoding + // to obtain the actual red and blue values. + new_green = ((predict >> 8) + g) & 0xff; + // The amount by which green has been adjusted during quantization. It is + // subtracted from red and blue for compensation, to avoid accumulating two + // quantization errors in them. + green_diff = (new_green - (value >> 8)) & 0xff; + } + r = NearLosslessComponent(((value >> 16) - green_diff) & 0xff, + (predict >> 16) & 0xff, 0xff - new_green, + quantization); + b = NearLosslessComponent((value - green_diff) & 0xff, predict & 0xff, + 0xff - new_green, quantization); + return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + +// Stores the difference between the pixel and its prediction in "out". +// In case of a lossy encoding, updates the source image to avoid propagating +// the deviation further to pixels which depend on the current pixel for their +// predictions. +static WEBP_INLINE void GetResidual( + int width, int height, uint32_t* const upper_row, + uint32_t* const current_row, const uint8_t* const max_diffs, int mode, + int x_start, int x_end, int y, int max_quantization, int exact, + int used_subtract_green, uint32_t* const out) { + if (exact) { + PredictBatch(mode, x_start, y, x_end - x_start, current_row, upper_row, + out); + } else { + const VP8LPredictorFunc pred_func = VP8LPredictors[mode]; + int x; + for (x = x_start; x < x_end; ++x) { + uint32_t predict; + uint32_t residual; + if (y == 0) { + predict = (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left. + } else if (x == 0) { + predict = upper_row[x]; // Top. + } else { + predict = pred_func(current_row[x - 1], upper_row + x); + } + if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 || + x == 0 || x == width - 1) { + residual = VP8LSubPixels(current_row[x], predict); + } else { + residual = NearLossless(current_row[x], predict, max_quantization, + max_diffs[x], used_subtract_green); + // Update the source image. + current_row[x] = VP8LAddPixels(predict, residual); + // x is never 0 here so we do not need to update upper_row like below. + } + if ((current_row[x] & kMaskAlpha) == 0) { + // If alpha is 0, cleanup RGB. We can choose the RGB values of the + // residual for best compression. The prediction of alpha itself can be + // non-zero and must be kept though. We choose RGB of the residual to be + // 0. + residual &= kMaskAlpha; + // Update the source image. + current_row[x] = predict & ~kMaskAlpha; + // The prediction for the rightmost pixel in a row uses the leftmost + // pixel + // in that row as its top-right context pixel. Hence if we change the + // leftmost pixel of current_row, the corresponding change must be + // applied + // to upper_row as well where top-right context is being read from. + if (x == 0 && y != 0) upper_row[width] = current_row[0]; + } + out[x - x_start] = residual; + } + } +} + +// Returns best predictor and updates the accumulated histogram. +// If max_quantization > 1, assumes that near lossless processing will be +// applied, quantizing residuals to multiples of quantization levels up to +// max_quantization (the actual quantization level depends on smoothness near +// the given pixel). +static int GetBestPredictorForTile(int width, int height, + int tile_x, int tile_y, int bits, + int accumulated[4][256], + uint32_t* const argb_scratch, + const uint32_t* const argb, + int max_quantization, + int exact, int used_subtract_green, + const uint32_t* const modes) { + const int kNumPredModes = 14; + const int start_x = tile_x << bits; + const int start_y = tile_y << bits; + const int tile_size = 1 << bits; + const int max_y = GetMin(tile_size, height - start_y); + const int max_x = GetMin(tile_size, width - start_x); + // Whether there exist columns just outside the tile. + const int have_left = (start_x > 0); + const int have_right = (max_x < width - start_x); + // Position and size of the strip covering the tile and adjacent columns if + // they exist. + const int context_start_x = start_x - have_left; + const int context_width = max_x + have_left + have_right; + const int tiles_per_row = VP8LSubSampleSize(width, bits); + // Prediction modes of the left and above neighbor tiles. + const int left_mode = (tile_x > 0) ? + (modes[tile_y * tiles_per_row + tile_x - 1] >> 8) & 0xff : 0xff; + const int above_mode = (tile_y > 0) ? + (modes[(tile_y - 1) * tiles_per_row + tile_x] >> 8) & 0xff : 0xff; + // The width of upper_row and current_row is one pixel larger than image width + // to allow the top right pixel to point to the leftmost pixel of the next row + // when at the right edge. + uint32_t* upper_row = argb_scratch; + uint32_t* current_row = upper_row + width + 1; + uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1); + float best_diff = MAX_DIFF_COST; + int best_mode = 0; + int mode; + int histo_stack_1[4][256]; + int histo_stack_2[4][256]; + // Need pointers to be able to swap arrays. + int (*histo_argb)[256] = histo_stack_1; + int (*best_histo)[256] = histo_stack_2; + int i, j; + uint32_t residuals[1 << MAX_TRANSFORM_BITS]; + assert(bits <= MAX_TRANSFORM_BITS); + assert(max_x <= (1 << MAX_TRANSFORM_BITS)); + + for (mode = 0; mode < kNumPredModes; ++mode) { + float cur_diff; + int relative_y; + memset(histo_argb, 0, sizeof(histo_stack_1)); + if (start_y > 0) { + // Read the row above the tile which will become the first upper_row. + // Include a pixel to the left if it exists; include a pixel to the right + // in all cases (wrapping to the leftmost pixel of the next row if it does + // not exist). + memcpy(current_row + context_start_x, + argb + (start_y - 1) * width + context_start_x, + sizeof(*argb) * (max_x + have_left + 1)); + } + for (relative_y = 0; relative_y < max_y; ++relative_y) { + const int y = start_y + relative_y; + int relative_x; + uint32_t* tmp = upper_row; + upper_row = current_row; + current_row = tmp; + // Read current_row. Include a pixel to the left if it exists; include a + // pixel to the right in all cases except at the bottom right corner of + // the image (wrapping to the leftmost pixel of the next row if it does + // not exist in the current row). + memcpy(current_row + context_start_x, + argb + y * width + context_start_x, + sizeof(*argb) * (max_x + have_left + (y + 1 < height))); + if (max_quantization > 1 && y >= 1 && y + 1 < height) { + MaxDiffsForRow(context_width, width, argb + y * width + context_start_x, + max_diffs + context_start_x, used_subtract_green); + } + + GetResidual(width, height, upper_row, current_row, max_diffs, mode, + start_x, start_x + max_x, y, max_quantization, exact, + used_subtract_green, residuals); + for (relative_x = 0; relative_x < max_x; ++relative_x) { + UpdateHisto(histo_argb, residuals[relative_x]); + } + } + cur_diff = PredictionCostSpatialHistogram( + (const int (*)[256])accumulated, (const int (*)[256])histo_argb); + // Favor keeping the areas locally similar. + if (mode == left_mode) cur_diff -= kSpatialPredictorBias; + if (mode == above_mode) cur_diff -= kSpatialPredictorBias; + + if (cur_diff < best_diff) { + int (*tmp)[256] = histo_argb; + histo_argb = best_histo; + best_histo = tmp; + best_diff = cur_diff; + best_mode = mode; + } + } + + for (i = 0; i < 4; i++) { + for (j = 0; j < 256; j++) { + accumulated[i][j] += best_histo[i][j]; + } + } + + return best_mode; +} + +// Converts pixels of the image to residuals with respect to predictions. +// If max_quantization > 1, applies near lossless processing, quantizing +// residuals to multiples of quantization levels up to max_quantization +// (the actual quantization level depends on smoothness near the given pixel). +static void CopyImageWithPrediction(int width, int height, + int bits, uint32_t* const modes, + uint32_t* const argb_scratch, + uint32_t* const argb, + int low_effort, int max_quantization, + int exact, int used_subtract_green) { + const int tiles_per_row = VP8LSubSampleSize(width, bits); + // The width of upper_row and current_row is one pixel larger than image width + // to allow the top right pixel to point to the leftmost pixel of the next row + // when at the right edge. + uint32_t* upper_row = argb_scratch; + uint32_t* current_row = upper_row + width + 1; + uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1); + uint8_t* lower_max_diffs = current_max_diffs + width; + int y; + + for (y = 0; y < height; ++y) { + int x; + uint32_t* const tmp32 = upper_row; + upper_row = current_row; + current_row = tmp32; + memcpy(current_row, argb + y * width, + sizeof(*argb) * (width + (y + 1 < height))); + + if (low_effort) { + PredictBatch(kPredLowEffort, 0, y, width, current_row, upper_row, + argb + y * width); + } else { + if (max_quantization > 1) { + // Compute max_diffs for the lower row now, because that needs the + // contents of argb for the current row, which we will overwrite with + // residuals before proceeding with the next row. + uint8_t* const tmp8 = current_max_diffs; + current_max_diffs = lower_max_diffs; + lower_max_diffs = tmp8; + if (y + 2 < height) { + MaxDiffsForRow(width, width, argb + (y + 1) * width, lower_max_diffs, + used_subtract_green); + } + } + for (x = 0; x < width;) { + const int mode = + (modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff; + int x_end = x + (1 << bits); + if (x_end > width) x_end = width; + GetResidual(width, height, upper_row, current_row, current_max_diffs, + mode, x, x_end, y, max_quantization, exact, + used_subtract_green, argb + y * width + x); + x = x_end; + } + } + } +} + +// Finds the best predictor for each tile, and converts the image to residuals +// with respect to predictions. If near_lossless_quality < 100, applies +// near lossless processing, shaving off more bits of residuals for lower +// qualities. +void VP8LResidualImage(int width, int height, int bits, int low_effort, + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image, int near_lossless_quality, + int exact, int used_subtract_green) { + const int tiles_per_row = VP8LSubSampleSize(width, bits); + const int tiles_per_col = VP8LSubSampleSize(height, bits); + int tile_y; + int histo[4][256]; + const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality); + if (low_effort) { + int i; + for (i = 0; i < tiles_per_row * tiles_per_col; ++i) { + image[i] = ARGB_BLACK | (kPredLowEffort << 8); + } + } else { + memset(histo, 0, sizeof(histo)); + for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) { + int tile_x; + for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) { + const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y, + bits, histo, argb_scratch, argb, max_quantization, exact, + used_subtract_green, image); + image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8); + } + } + } + + CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb, + low_effort, max_quantization, exact, + used_subtract_green); +} + +//------------------------------------------------------------------------------ +// Color transform functions. + +static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) { + m->green_to_red_ = 0; + m->green_to_blue_ = 0; + m->red_to_blue_ = 0; +} + +static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, + VP8LMultipliers* const m) { + m->green_to_red_ = (color_code >> 0) & 0xff; + m->green_to_blue_ = (color_code >> 8) & 0xff; + m->red_to_blue_ = (color_code >> 16) & 0xff; +} + +static WEBP_INLINE uint32_t MultipliersToColorCode( + const VP8LMultipliers* const m) { + return 0xff000000u | + ((uint32_t)(m->red_to_blue_) << 16) | + ((uint32_t)(m->green_to_blue_) << 8) | + m->green_to_red_; +} + +static float PredictionCostCrossColor(const int accumulated[256], + const int counts[256]) { + // Favor low entropy, locally and globally. + // Favor small absolute values for PredictionCostSpatial + static const double kExpValue = 2.4; + return VP8LCombinedShannonEntropy(counts, accumulated) + + PredictionCostSpatial(counts, 3, kExpValue); +} + +static float GetPredictionCostCrossColorRed( + const uint32_t* argb, int stride, int tile_width, int tile_height, + VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red, + const int accumulated_red_histo[256]) { + int histo[256] = { 0 }; + float cur_diff; + + VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height, + green_to_red, histo); + + cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo); + if ((uint8_t)green_to_red == prev_x.green_to_red_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if ((uint8_t)green_to_red == prev_y.green_to_red_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (green_to_red == 0) { + cur_diff -= 3; + } + return cur_diff; +} + +static void GetBestGreenToRed( + const uint32_t* argb, int stride, int tile_width, int tile_height, + VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, + const int accumulated_red_histo[256], VP8LMultipliers* const best_tx) { + const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6] + int green_to_red_best = 0; + int iter, offset; + float best_diff = GetPredictionCostCrossColorRed( + argb, stride, tile_width, tile_height, prev_x, prev_y, + green_to_red_best, accumulated_red_histo); + for (iter = 0; iter < kMaxIters; ++iter) { + // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to + // one in color computation. Having initial delta here as 1 is sufficient + // to explore the range of (-2, 2). + const int delta = 32 >> iter; + // Try a negative and a positive delta from the best known value. + for (offset = -delta; offset <= delta; offset += 2 * delta) { + const int green_to_red_cur = offset + green_to_red_best; + const float cur_diff = GetPredictionCostCrossColorRed( + argb, stride, tile_width, tile_height, prev_x, prev_y, + green_to_red_cur, accumulated_red_histo); + if (cur_diff < best_diff) { + best_diff = cur_diff; + green_to_red_best = green_to_red_cur; + } + } + } + best_tx->green_to_red_ = green_to_red_best; +} + +static float GetPredictionCostCrossColorBlue( + const uint32_t* argb, int stride, int tile_width, int tile_height, + VP8LMultipliers prev_x, VP8LMultipliers prev_y, + int green_to_blue, int red_to_blue, const int accumulated_blue_histo[256]) { + int histo[256] = { 0 }; + float cur_diff; + + VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height, + green_to_blue, red_to_blue, histo); + + cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo); + if ((uint8_t)green_to_blue == prev_x.green_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if ((uint8_t)green_to_blue == prev_y.green_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if ((uint8_t)red_to_blue == prev_x.red_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if ((uint8_t)red_to_blue == prev_y.red_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (green_to_blue == 0) { + cur_diff -= 3; + } + if (red_to_blue == 0) { + cur_diff -= 3; + } + return cur_diff; +} + +#define kGreenRedToBlueNumAxis 8 +#define kGreenRedToBlueMaxIters 7 +static void GetBestGreenRedToBlue( + const uint32_t* argb, int stride, int tile_width, int tile_height, + VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, + const int accumulated_blue_histo[256], + VP8LMultipliers* const best_tx) { + const int8_t offset[kGreenRedToBlueNumAxis][2] = + {{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}}; + const int8_t delta_lut[kGreenRedToBlueMaxIters] = { 16, 16, 8, 4, 2, 2, 2 }; + const int iters = + (quality < 25) ? 1 : (quality > 50) ? kGreenRedToBlueMaxIters : 4; + int green_to_blue_best = 0; + int red_to_blue_best = 0; + int iter; + // Initial value at origin: + float best_diff = GetPredictionCostCrossColorBlue( + argb, stride, tile_width, tile_height, prev_x, prev_y, + green_to_blue_best, red_to_blue_best, accumulated_blue_histo); + for (iter = 0; iter < iters; ++iter) { + const int delta = delta_lut[iter]; + int axis; + for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) { + const int green_to_blue_cur = + offset[axis][0] * delta + green_to_blue_best; + const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best; + const float cur_diff = GetPredictionCostCrossColorBlue( + argb, stride, tile_width, tile_height, prev_x, prev_y, + green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo); + if (cur_diff < best_diff) { + best_diff = cur_diff; + green_to_blue_best = green_to_blue_cur; + red_to_blue_best = red_to_blue_cur; + } + if (quality < 25 && iter == 4) { + // Only axis aligned diffs for lower quality. + break; // next iter. + } + } + if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) { + // Further iterations would not help. + break; // out of iter-loop. + } + } + best_tx->green_to_blue_ = green_to_blue_best; + best_tx->red_to_blue_ = red_to_blue_best; +} +#undef kGreenRedToBlueMaxIters +#undef kGreenRedToBlueNumAxis + +static VP8LMultipliers GetBestColorTransformForTile( + int tile_x, int tile_y, int bits, + VP8LMultipliers prev_x, + VP8LMultipliers prev_y, + int quality, int xsize, int ysize, + const int accumulated_red_histo[256], + const int accumulated_blue_histo[256], + const uint32_t* const argb) { + const int max_tile_size = 1 << bits; + const int tile_y_offset = tile_y * max_tile_size; + const int tile_x_offset = tile_x * max_tile_size; + const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize); + const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize); + const int tile_width = all_x_max - tile_x_offset; + const int tile_height = all_y_max - tile_y_offset; + const uint32_t* const tile_argb = argb + tile_y_offset * xsize + + tile_x_offset; + VP8LMultipliers best_tx; + MultipliersClear(&best_tx); + + GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height, + prev_x, prev_y, quality, accumulated_red_histo, &best_tx); + GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height, + prev_x, prev_y, quality, accumulated_blue_histo, + &best_tx); + return best_tx; +} + +static void CopyTileWithColorTransform(int xsize, int ysize, + int tile_x, int tile_y, + int max_tile_size, + VP8LMultipliers color_transform, + uint32_t* argb) { + const int xscan = GetMin(max_tile_size, xsize - tile_x); + int yscan = GetMin(max_tile_size, ysize - tile_y); + argb += tile_y * xsize + tile_x; + while (yscan-- > 0) { + VP8LTransformColor(&color_transform, argb, xscan); + argb += xsize; + } +} + +void VP8LColorSpaceTransform(int width, int height, int bits, int quality, + uint32_t* const argb, uint32_t* image) { + const int max_tile_size = 1 << bits; + const int tile_xsize = VP8LSubSampleSize(width, bits); + const int tile_ysize = VP8LSubSampleSize(height, bits); + int accumulated_red_histo[256] = { 0 }; + int accumulated_blue_histo[256] = { 0 }; + int tile_x, tile_y; + VP8LMultipliers prev_x, prev_y; + MultipliersClear(&prev_y); + MultipliersClear(&prev_x); + for (tile_y = 0; tile_y < tile_ysize; ++tile_y) { + for (tile_x = 0; tile_x < tile_xsize; ++tile_x) { + int y; + const int tile_x_offset = tile_x * max_tile_size; + const int tile_y_offset = tile_y * max_tile_size; + const int all_x_max = GetMin(tile_x_offset + max_tile_size, width); + const int all_y_max = GetMin(tile_y_offset + max_tile_size, height); + const int offset = tile_y * tile_xsize + tile_x; + if (tile_y != 0) { + ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y); + } + prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits, + prev_x, prev_y, + quality, width, height, + accumulated_red_histo, + accumulated_blue_histo, + argb); + image[offset] = MultipliersToColorCode(&prev_x); + CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset, + max_tile_size, prev_x, argb); + + // Gather accumulated histogram data. + for (y = tile_y_offset; y < all_y_max; ++y) { + int ix = y * width + tile_x_offset; + const int ix_end = ix + all_x_max - tile_x_offset; + for (; ix < ix_end; ++ix) { + const uint32_t pix = argb[ix]; + if (ix >= 2 && + pix == argb[ix - 2] && + pix == argb[ix - 1]) { + continue; // repeated pixels are handled by backward references + } + if (ix >= width + 2 && + argb[ix - 2] == argb[ix - width - 2] && + argb[ix - 1] == argb[ix - width - 1] && + pix == argb[ix - width]) { + continue; // repeated pixels are handled by backward references + } + ++accumulated_red_histo[(pix >> 16) & 0xff]; + ++accumulated_blue_histo[(pix >> 0) & 0xff]; + } + } + } + } +} diff --git a/src/3rdparty/libwebp/src/enc/quant.c b/src/3rdparty/libwebp/src/enc/quant_enc.c similarity index 98% rename from src/3rdparty/libwebp/src/enc/quant.c rename to src/3rdparty/libwebp/src/enc/quant_enc.c index 549ad26f932e9393a308db26b8d8bef6851b6d5f..b118fb2a137bae6ce52c02d97ab51bd6340fe796 100644 --- a/src/3rdparty/libwebp/src/enc/quant.c +++ b/src/3rdparty/libwebp/src/enc/quant_enc.c @@ -15,8 +15,8 @@ #include <math.h> #include <stdlib.h> // for abs() -#include "./vp8enci.h" -#include "./cost.h" +#include "./vp8i_enc.h" +#include "./cost_enc.h" #define DO_TRELLIS_I4 1 #define DO_TRELLIS_I16 1 // not a huge gain, but ok at low bitrate. @@ -278,7 +278,7 @@ static void SetupMatrices(VP8Encoder* enc) { CheckLambdaValue(&m->lambda_trellis_uv_); CheckLambdaValue(&m->tlambda_); - m->min_disto_ = 10 * m->y1_.q_[0]; // quantization-aware min disto + m->min_disto_ = 20 * m->y1_.q_[0]; // quantization-aware min disto m->max_edge_ = 0; m->i4_penalty_ = 1000 * q_i4 * q_i4; @@ -643,6 +643,8 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc, const int sign = (in[j] < 0); const uint32_t coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; int level0 = QUANTDIV(coeff0, iQ, B); + int thresh_level = QUANTDIV(coeff0, iQ, BIAS(0x80)); + if (thresh_level > MAX_LEVEL) thresh_level = MAX_LEVEL; if (level0 > MAX_LEVEL) level0 = MAX_LEVEL; { // Swap current and previous score states @@ -657,23 +659,17 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc, int level = level0 + m; const int ctx = (level > 2) ? 2 : level; const int band = VP8EncBands[n + 1]; - score_t base_score, last_pos_score; + score_t base_score; score_t best_cur_score = MAX_COST; int best_prev = 0; // default, in case ss_cur[m].score = MAX_COST; ss_cur[m].costs = costs[n + 1][ctx]; - if (level > MAX_LEVEL || level < 0) { // node is dead? + if (level < 0 || level > thresh_level) { + // Node is dead. continue; } - // Compute extra rate cost if last coeff's position is < 15 - { - const score_t last_pos_cost = - (n < 15) ? VP8BitCost(0, probas[band][ctx][0]) : 0; - last_pos_score = RDScoreTrellis(lambda, last_pos_cost, 0); - } - { // Compute delta_error = how much coding this level will // subtract to max_error as distortion. @@ -705,6 +701,9 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc, // Now, record best terminal node (and thus best entry in the graph). if (level != 0) { + const score_t last_pos_cost = + (n < 15) ? VP8BitCost(0, probas[band][ctx][0]) : 0; + const score_t last_pos_score = RDScoreTrellis(lambda, last_pos_cost, 0); const score_t score = best_cur_score + last_pos_score; if (score < best_score) { best_score = score; @@ -874,9 +873,9 @@ static void StoreMaxDelta(VP8SegmentInfo* const dqm, const int16_t DCs[16]) { // We look at the first three AC coefficients to determine what is the average // delta between each sub-4x4 block. const int v0 = abs(DCs[1]); - const int v1 = abs(DCs[4]); - const int v2 = abs(DCs[5]); - int max_v = (v0 > v1) ? v1 : v0; + const int v1 = abs(DCs[2]); + const int v2 = abs(DCs[4]); + int max_v = (v1 > v0) ? v1 : v0; max_v = (v2 > max_v) ? v2 : max_v; if (max_v > dqm->max_edge_) dqm->max_edge_ = max_v; } @@ -957,7 +956,7 @@ static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) { // we have a blocky macroblock (only DCs are non-zero) with fairly high // distortion, record max delta so we can later adjust the minimal filtering // strength needed to smooth these blocks out. - if ((rd->nz & 0xffff) == 0 && rd->D > dqm->min_disto_) { + if ((rd->nz & 0x100ffff) == 0x1000000 && rd->D > dqm->min_disto_) { StoreMaxDelta(dqm, rd->y_dc_levels); } } @@ -1155,7 +1154,8 @@ static void RefineUsingDistortion(VP8EncIterator* const it, const int lambda_d_uv = 120; score_t score_i4 = dqm->i4_penalty_; score_t i4_bit_sum = 0; - const score_t bit_limit = it->enc_->mb_header_limit_; + const score_t bit_limit = try_both_modes ? it->enc_->mb_header_limit_ + : MAX_COST; // no early-out allowed if (is_i16) { // First, evaluate Intra16 distortion int best_mode = -1; diff --git a/src/3rdparty/libwebp/src/enc/syntax.c b/src/3rdparty/libwebp/src/enc/syntax_enc.c similarity index 99% rename from src/3rdparty/libwebp/src/enc/syntax.c rename to src/3rdparty/libwebp/src/enc/syntax_enc.c index a0e79ef404735b2b25bab97f9fa082ddc2c23c23..90665bd7e5a0f87ba1ced4fba9ef11bb00adbffd 100644 --- a/src/3rdparty/libwebp/src/enc/syntax.c +++ b/src/3rdparty/libwebp/src/enc/syntax_enc.c @@ -16,7 +16,7 @@ #include "../utils/utils.h" #include "../webp/format_constants.h" // RIFF constants #include "../webp/mux_types.h" // ALPHA_FLAG -#include "./vp8enci.h" +#include "./vp8i_enc.h" //------------------------------------------------------------------------------ // Helper functions @@ -362,8 +362,7 @@ int VP8EncWrite(VP8Encoder* const enc) { for (p = 0; p < enc->num_parts_; ++p) { const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p); const size_t size = VP8BitWriterSize(enc->parts_ + p); - if (size) - ok = ok && pic->writer(buf, size, pic); + if (size) ok = ok && pic->writer(buf, size, pic); VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer. ok = ok && WebPReportProgress(pic, enc->percent_ + percent_per_part, &enc->percent_); diff --git a/src/3rdparty/libwebp/src/enc/token.c b/src/3rdparty/libwebp/src/enc/token_enc.c similarity index 82% rename from src/3rdparty/libwebp/src/enc/token.c rename to src/3rdparty/libwebp/src/enc/token_enc.c index e73256b37e933cc99817ea7c70096784e6e8a003..02a0d72cc6d712bd380145663c92d1123343d82a 100644 --- a/src/3rdparty/libwebp/src/enc/token.c +++ b/src/3rdparty/libwebp/src/enc/token_enc.c @@ -20,8 +20,8 @@ #include <stdlib.h> #include <string.h> -#include "./cost.h" -#include "./vp8enci.h" +#include "./cost_enc.h" +#include "./vp8i_enc.h" #include "../utils/utils.h" #if !defined(DISABLE_TOKEN_BUFFER) @@ -87,14 +87,16 @@ static int TBufferNewPage(VP8TBuffer* const b) { #define TOKEN_ID(t, b, ctx) \ (NUM_PROBAS * ((ctx) + NUM_CTX * ((b) + NUM_BANDS * (t)))) -static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, - uint32_t bit, uint32_t proba_idx) { +static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, uint32_t bit, + uint32_t proba_idx, + proba_t* const stats) { assert(proba_idx < FIXED_PROBA_BIT); assert(bit <= 1); if (b->left_ > 0 || TBufferNewPage(b)) { const int slot = --b->left_; b->tokens_[slot] = (bit << 15) | proba_idx; } + VP8RecordStats(bit, stats); return bit; } @@ -108,13 +110,16 @@ static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b, } } -int VP8RecordCoeffTokens(const int ctx, const int coeff_type, - int first, int last, - const int16_t* const coeffs, +int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res, VP8TBuffer* const tokens) { - int n = first; + const int16_t* const coeffs = res->coeffs; + const int coeff_type = res->coeff_type; + const int last = res->last; + int n = res->first; uint32_t base_id = TOKEN_ID(coeff_type, n, ctx); - if (!AddToken(tokens, last >= 0, base_id + 0)) { + // should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1 + proba_t* s = res->stats[n][ctx]; + if (!AddToken(tokens, last >= 0, base_id + 0, s + 0)) { return 0; } @@ -122,18 +127,21 @@ int VP8RecordCoeffTokens(const int ctx, const int coeff_type, const int c = coeffs[n++]; const int sign = c < 0; const uint32_t v = sign ? -c : c; - if (!AddToken(tokens, v != 0, base_id + 1)) { + if (!AddToken(tokens, v != 0, base_id + 1, s + 1)) { base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 0); // ctx=0 + s = res->stats[VP8EncBands[n]][0]; continue; } - if (!AddToken(tokens, v > 1, base_id + 2)) { + if (!AddToken(tokens, v > 1, base_id + 2, s + 2)) { base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 1); // ctx=1 + s = res->stats[VP8EncBands[n]][1]; } else { - if (!AddToken(tokens, v > 4, base_id + 3)) { - if (AddToken(tokens, v != 2, base_id + 4)) - AddToken(tokens, v == 4, base_id + 5); - } else if (!AddToken(tokens, v > 10, base_id + 6)) { - if (!AddToken(tokens, v > 6, base_id + 7)) { + if (!AddToken(tokens, v > 4, base_id + 3, s + 3)) { + if (AddToken(tokens, v != 2, base_id + 4, s + 4)) { + AddToken(tokens, v == 4, base_id + 5, s + 5); + } + } else if (!AddToken(tokens, v > 10, base_id + 6, s + 6)) { + if (!AddToken(tokens, v > 6, base_id + 7, s + 7)) { AddConstantToken(tokens, v == 6, 159); } else { AddConstantToken(tokens, v >= 9, 165); @@ -144,26 +152,26 @@ int VP8RecordCoeffTokens(const int ctx, const int coeff_type, const uint8_t* tab; uint32_t residue = v - 3; if (residue < (8 << 1)) { // VP8Cat3 (3b) - AddToken(tokens, 0, base_id + 8); - AddToken(tokens, 0, base_id + 9); + AddToken(tokens, 0, base_id + 8, s + 8); + AddToken(tokens, 0, base_id + 9, s + 9); residue -= (8 << 0); mask = 1 << 2; tab = VP8Cat3; } else if (residue < (8 << 2)) { // VP8Cat4 (4b) - AddToken(tokens, 0, base_id + 8); - AddToken(tokens, 1, base_id + 9); + AddToken(tokens, 0, base_id + 8, s + 8); + AddToken(tokens, 1, base_id + 9, s + 9); residue -= (8 << 1); mask = 1 << 3; tab = VP8Cat4; } else if (residue < (8 << 3)) { // VP8Cat5 (5b) - AddToken(tokens, 1, base_id + 8); - AddToken(tokens, 0, base_id + 10); + AddToken(tokens, 1, base_id + 8, s + 8); + AddToken(tokens, 0, base_id + 10, s + 9); residue -= (8 << 2); mask = 1 << 4; tab = VP8Cat5; } else { // VP8Cat6 (11b) - AddToken(tokens, 1, base_id + 8); - AddToken(tokens, 1, base_id + 10); + AddToken(tokens, 1, base_id + 8, s + 8); + AddToken(tokens, 1, base_id + 10, s + 9); residue -= (8 << 3); mask = 1 << 10; tab = VP8Cat6; @@ -174,9 +182,10 @@ int VP8RecordCoeffTokens(const int ctx, const int coeff_type, } } base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 2); // ctx=2 + s = res->stats[VP8EncBands[n]][2]; } AddConstantToken(tokens, sign, 128); - if (n == 16 || !AddToken(tokens, n <= last, base_id + 0)) { + if (n == 16 || !AddToken(tokens, n <= last, base_id + 0, s + 0)) { return 1; // EOB } } diff --git a/src/3rdparty/libwebp/src/enc/tree.c b/src/3rdparty/libwebp/src/enc/tree_enc.c similarity index 99% rename from src/3rdparty/libwebp/src/enc/tree.c rename to src/3rdparty/libwebp/src/enc/tree_enc.c index f141006d19b2d96965fec0315d4dcbdada01e03c..2c40fe7f3d8ce0aff9dfacfbbc2522536fdf315a 100644 --- a/src/3rdparty/libwebp/src/enc/tree.c +++ b/src/3rdparty/libwebp/src/enc/tree_enc.c @@ -11,7 +11,7 @@ // // Author: Skal (pascal.massimino@gmail.com) -#include "./vp8enci.h" +#include "./vp8i_enc.h" //------------------------------------------------------------------------------ // Default probabilities diff --git a/src/3rdparty/libwebp/src/enc/vp8enci.h b/src/3rdparty/libwebp/src/enc/vp8i_enc.h similarity index 96% rename from src/3rdparty/libwebp/src/enc/vp8enci.h rename to src/3rdparty/libwebp/src/enc/vp8i_enc.h index c1fbd7644e3defb4ad459f56c1f00de290a13e0d..93c95ecbfb5a915ad9c1ad37c57fdb91bd4c9c8e 100644 --- a/src/3rdparty/libwebp/src/enc/vp8enci.h +++ b/src/3rdparty/libwebp/src/enc/vp8i_enc.h @@ -15,10 +15,10 @@ #define WEBP_ENC_VP8ENCI_H_ #include <string.h> // for memcpy() -#include "../dec/common.h" +#include "../dec/common_dec.h" #include "../dsp/dsp.h" -#include "../utils/bit_writer.h" -#include "../utils/thread.h" +#include "../utils/bit_writer_utils.h" +#include "../utils/thread_utils.h" #include "../utils/utils.h" #include "../webp/encode.h" @@ -31,8 +31,8 @@ extern "C" { // version numbers #define ENC_MAJ_VERSION 0 -#define ENC_MIN_VERSION 5 -#define ENC_REV_VERSION 1 +#define ENC_MIN_VERSION 6 +#define ENC_REV_VERSION 0 enum { MAX_LF_LEVELS = 64, // Maximum loop filter level MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost @@ -219,7 +219,6 @@ typedef struct { // right neighbouring data (samples, predictions, contexts, ...) typedef struct { int x_, y_; // current macroblock - int y_stride_, uv_stride_; // respective strides uint8_t* yuv_in_; // input samples uint8_t* yuv_out_; // output samples uint8_t* yuv_out2_; // secondary buffer swapped with yuv_out_. @@ -325,9 +324,7 @@ int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw, const uint8_t* const probas, int final_pass); // record the coding of coefficients without knowing the probabilities yet -int VP8RecordCoeffTokens(const int ctx, const int coeff_type, - int first, int last, - const int16_t* const coeffs, +int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res, VP8TBuffer* const tokens); // Estimate the final coded size given a set of 'probas'. @@ -476,14 +473,6 @@ int VP8EncStartAlpha(VP8Encoder* const enc); // start alpha coding process int VP8EncFinishAlpha(VP8Encoder* const enc); // finalize compressed data int VP8EncDeleteAlpha(VP8Encoder* const enc); // delete compressed data - // in filter.c -void VP8SSIMAddStats(const VP8DistoStats* const src, VP8DistoStats* const dst); -void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int W, int H, VP8DistoStats* const stats); -double VP8SSIMGet(const VP8DistoStats* const stats); -double VP8SSIMGetSquaredError(const VP8DistoStats* const stats); - // autofilter void VP8InitFilter(VP8EncIterator* const it); void VP8StoreFilterStats(VP8EncIterator* const it); diff --git a/src/3rdparty/libwebp/src/enc/vp8l.c b/src/3rdparty/libwebp/src/enc/vp8l_enc.c similarity index 88% rename from src/3rdparty/libwebp/src/enc/vp8l.c rename to src/3rdparty/libwebp/src/enc/vp8l_enc.c index c16e2560ec82059139bfdf7e64c93a8b3ab6a89b..b1a793d956e379d4820bb6046009853508a0c607 100644 --- a/src/3rdparty/libwebp/src/enc/vp8l.c +++ b/src/3rdparty/libwebp/src/enc/vp8l_enc.c @@ -15,17 +15,18 @@ #include <assert.h> #include <stdlib.h> -#include "./backward_references.h" -#include "./histogram.h" -#include "./vp8enci.h" -#include "./vp8li.h" +#include "./backward_references_enc.h" +#include "./histogram_enc.h" +#include "./vp8i_enc.h" +#include "./vp8li_enc.h" #include "../dsp/lossless.h" -#include "../utils/bit_writer.h" -#include "../utils/huffman_encode.h" +#include "../dsp/lossless_common.h" +#include "../utils/bit_writer_utils.h" +#include "../utils/huffman_encode_utils.h" #include "../utils/utils.h" #include "../webp/format_constants.h" -#include "./delta_palettization.h" +#include "./delta_palettization_enc.h" #define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. // Maximum number of histogram images (sub-blocks). @@ -34,8 +35,8 @@ // Palette reordering for smaller sum of deltas (and for smaller storage). static int PaletteCompareColorsForQsort(const void* p1, const void* p2) { - const uint32_t a = WebPMemToUint32(p1); - const uint32_t b = WebPMemToUint32(p2); + const uint32_t a = WebPMemToUint32((uint8_t*)p1); + const uint32_t b = WebPMemToUint32((uint8_t*)p2); assert(a != b); return (a < b) ? -1 : 1; } @@ -163,18 +164,25 @@ typedef enum { kHistoTotal // Must be last. } HistoIx; -static void AddSingleSubGreen(uint32_t p, uint32_t* r, uint32_t* b) { - const uint32_t green = p >> 8; // The upper bits are masked away later. +static void AddSingleSubGreen(int p, uint32_t* const r, uint32_t* const b) { + const int green = p >> 8; // The upper bits are masked away later. ++r[((p >> 16) - green) & 0xff]; - ++b[(p - green) & 0xff]; + ++b[((p >> 0) - green) & 0xff]; } static void AddSingle(uint32_t p, - uint32_t* a, uint32_t* r, uint32_t* g, uint32_t* b) { - ++a[p >> 24]; + uint32_t* const a, uint32_t* const r, + uint32_t* const g, uint32_t* const b) { + ++a[(p >> 24) & 0xff]; ++r[(p >> 16) & 0xff]; - ++g[(p >> 8) & 0xff]; - ++b[(p & 0xff)]; + ++g[(p >> 8) & 0xff]; + ++b[(p >> 0) & 0xff]; +} + +static WEBP_INLINE uint32_t HashPix(uint32_t pix) { + // Note that masking with 0xffffffffu is for preventing an + // 'unsigned int overflow' warning. Doesn't impact the compiled code. + return ((((uint64_t)pix + (pix >> 19)) * 0x39c5fba7ull) & 0xffffffffu) >> 24; } static int AnalyzeEntropy(const uint32_t* argb, @@ -214,8 +222,8 @@ static int AnalyzeEntropy(const uint32_t* argb, &histo[kHistoBluePredSubGreen * 256]); { // Approximate the palette by the entropy of the multiplicative hash. - const int hash = ((pix + (pix >> 19)) * 0x39c5fba7) >> 24; - ++histo[kHistoPalette * 256 + (hash & 0xff)]; + const uint32_t hash = HashPix(pix); + ++histo[kHistoPalette * 256 + hash]; } } prev_row = curr_row; @@ -224,9 +232,8 @@ static int AnalyzeEntropy(const uint32_t* argb, { double entropy_comp[kHistoTotal]; double entropy[kNumEntropyIx]; - EntropyIx k; - EntropyIx last_mode_to_analyze = - use_palette ? kPalette : kSpatialSubGreen; + int k; + int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen; int j; // Let's add one zero to the predicted histograms. The zeros are removed // too efficiently by the pix_diff == 0 comparison, at least one of the @@ -263,7 +270,7 @@ static int AnalyzeEntropy(const uint32_t* argb, *min_entropy_ix = kDirect; for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) { if (entropy[*min_entropy_ix] > entropy[k]) { - *min_entropy_ix = k; + *min_entropy_ix = (EntropyIx)k; } } *red_and_blue_always_zero = 1; @@ -312,7 +319,10 @@ static int GetHistoBits(int method, int use_palette, int width, int height) { static int GetTransformBits(int method, int histo_bits) { const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5; - return (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits; + const int res = + (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits; + assert(res <= MAX_TRANSFORM_BITS); + return res; } static int AnalyzeAndInit(VP8LEncoder* const enc) { @@ -697,7 +707,7 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[2], int width, int height, - int quality) { + int quality, int low_effort) { int i; int max_tokens = 0; WebPEncodingError err = VP8_ENC_OK; @@ -715,7 +725,8 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, } // Calculate backward references from ARGB image. - if (VP8LHashChainFill(hash_chain, quality, argb, width, height) == 0) { + if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, + low_effort)) { err = VP8_ENC_ERROR_OUT_OF_MEMORY; goto Error; } @@ -815,11 +826,18 @@ static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw, goto Error; } - *cache_bits = use_cache ? MAX_COLOR_CACHE_BITS : 0; + if (use_cache) { + // If the value is different from zero, it has been set during the + // palette analysis. + if (*cache_bits == 0) *cache_bits = MAX_COLOR_CACHE_BITS; + } else { + *cache_bits = 0; + } // 'best_refs' is the reference to the best backward refs and points to one // of refs_array[0] or refs_array[1]. // Calculate backward references from ARGB image. - if (VP8LHashChainFill(hash_chain, quality, argb, width, height) == 0) { + if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, + low_effort)) { err = VP8_ENC_ERROR_OUT_OF_MEMORY; goto Error; } @@ -900,7 +918,7 @@ static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw, err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array, VP8LSubSampleSize(width, histogram_bits), VP8LSubSampleSize(height, histogram_bits), - quality); + quality, low_effort); WebPSafeFree(histogram_argb); if (err != VP8_ENC_OK) goto Error; } @@ -991,12 +1009,12 @@ static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc, (VP8LHashChain*)&enc->hash_chain_, (VP8LBackwardRefs*)enc->refs_, // cast const away transform_width, transform_height, - quality); + quality, low_effort); } static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, int width, int height, - int quality, + int quality, int low_effort, VP8LBitWriter* const bw) { const int ccolor_transform_bits = enc->transform_bits_; const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); @@ -1012,7 +1030,7 @@ static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, (VP8LHashChain*)&enc->hash_chain_, (VP8LBackwardRefs*)enc->refs_, // cast const away transform_width, transform_height, - quality); + quality, low_effort); } // ----------------------------------------------------------------------------- @@ -1157,7 +1175,8 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) { // ----------------------------------------------------------------------------- -static int SearchColor(const uint32_t sorted[], uint32_t color, int hi) { +static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, + int hi) { int low = 0; if (sorted[low] == color) return low; // loop invariant: sorted[low] != color while (1) { @@ -1172,35 +1191,68 @@ static int SearchColor(const uint32_t sorted[], uint32_t color, int hi) { } } +#define APPLY_PALETTE_GREEDY_MAX 4 + +static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[], + int palette_size, + uint32_t color) { + (void)palette_size; + assert(palette_size < APPLY_PALETTE_GREEDY_MAX); + assert(3 == APPLY_PALETTE_GREEDY_MAX - 1); + if (color == palette[0]) return 0; + if (color == palette[1]) return 1; + if (color == palette[2]) return 2; + return 3; +} + +static WEBP_INLINE uint32_t ApplyPaletteHash0(uint32_t color) { + // Focus on the green color. + return (color >> 8) & 0xff; +} + +#define PALETTE_INV_SIZE_BITS 11 +#define PALETTE_INV_SIZE (1 << PALETTE_INV_SIZE_BITS) + +static WEBP_INLINE uint32_t ApplyPaletteHash1(uint32_t color) { + // Forget about alpha. + return ((color & 0x00ffffffu) * 4222244071u) >> (32 - PALETTE_INV_SIZE_BITS); +} + +static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) { + // Forget about alpha. + return (color & 0x00ffffffu) * ((1u << 31) - 1) >> + (32 - PALETTE_INV_SIZE_BITS); +} + // Sort palette in increasing order and prepare an inverse mapping array. static void PrepareMapToPalette(const uint32_t palette[], int num_colors, - uint32_t sorted[], int idx_map[]) { + uint32_t sorted[], uint32_t idx_map[]) { int i; memcpy(sorted, palette, num_colors * sizeof(*sorted)); qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort); for (i = 0; i < num_colors; ++i) { - idx_map[SearchColor(sorted, palette[i], num_colors)] = i; + idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i; } } -static void MapToPalette(const uint32_t sorted_palette[], int num_colors, - uint32_t* const last_pix, int* const last_idx, - const int idx_map[], - const uint32_t* src, uint8_t* dst, int width) { - int x; - int prev_idx = *last_idx; - uint32_t prev_pix = *last_pix; - for (x = 0; x < width; ++x) { - const uint32_t pix = src[x]; - if (pix != prev_pix) { - prev_idx = idx_map[SearchColor(sorted_palette, pix, num_colors)]; - prev_pix = pix; - } - dst[x] = prev_idx; - } - *last_idx = prev_idx; - *last_pix = prev_pix; -} +// Use 1 pixel cache for ARGB pixels. +#define APPLY_PALETTE_FOR(COLOR_INDEX) do { \ + uint32_t prev_pix = palette[0]; \ + uint32_t prev_idx = 0; \ + for (y = 0; y < height; ++y) { \ + for (x = 0; x < width; ++x) { \ + const uint32_t pix = src[x]; \ + if (pix != prev_pix) { \ + prev_idx = COLOR_INDEX; \ + prev_pix = pix; \ + } \ + tmp_row[x] = prev_idx; \ + } \ + VP8LBundleColorMap(tmp_row, width, xbits, dst); \ + src += src_stride; \ + dst += dst_stride; \ + } \ +} while (0) // Remap argb values in src[] to packed palettes entries in dst[] // using 'row' as a temporary buffer of size 'width'. @@ -1213,52 +1265,59 @@ static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride, // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be // made to work in-place. uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row)); - int i, x, y; - int use_LUT = 1; + int x, y; if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; - for (i = 0; i < palette_size; ++i) { - if ((palette[i] & 0xffff00ffu) != 0) { - use_LUT = 0; - break; - } - } - if (use_LUT) { - uint8_t inv_palette[MAX_PALETTE_SIZE] = { 0 }; - for (i = 0; i < palette_size; ++i) { - const int color = (palette[i] >> 8) & 0xff; - inv_palette[color] = i; - } - for (y = 0; y < height; ++y) { - for (x = 0; x < width; ++x) { - const int color = (src[x] >> 8) & 0xff; - tmp_row[x] = inv_palette[color]; + if (palette_size < APPLY_PALETTE_GREEDY_MAX) { + APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix)); + } else { + int i, j; + uint16_t buffer[PALETTE_INV_SIZE]; + uint32_t (*const hash_functions[])(uint32_t) = { + ApplyPaletteHash0, ApplyPaletteHash1, ApplyPaletteHash2 + }; + + // Try to find a perfect hash function able to go from a color to an index + // within 1 << PALETTE_INV_SIZE_BITS in order to build a hash map to go + // from color to index in palette. + for (i = 0; i < 3; ++i) { + int use_LUT = 1; + // Set each element in buffer to max uint16_t. + memset(buffer, 0xff, sizeof(buffer)); + for (j = 0; j < palette_size; ++j) { + const uint32_t ind = hash_functions[i](palette[j]); + if (buffer[ind] != 0xffffu) { + use_LUT = 0; + break; + } else { + buffer[ind] = j; + } } - VP8LBundleColorMap(tmp_row, width, xbits, dst); - src += src_stride; - dst += dst_stride; + if (use_LUT) break; } - } else { - // Use 1 pixel cache for ARGB pixels. - uint32_t last_pix; - int last_idx; - uint32_t sorted[MAX_PALETTE_SIZE]; - int idx_map[MAX_PALETTE_SIZE]; - PrepareMapToPalette(palette, palette_size, sorted, idx_map); - last_pix = palette[0]; - last_idx = 0; - for (y = 0; y < height; ++y) { - MapToPalette(sorted, palette_size, &last_pix, &last_idx, - idx_map, src, tmp_row, width); - VP8LBundleColorMap(tmp_row, width, xbits, dst); - src += src_stride; - dst += dst_stride; + + if (i == 0) { + APPLY_PALETTE_FOR(buffer[ApplyPaletteHash0(pix)]); + } else if (i == 1) { + APPLY_PALETTE_FOR(buffer[ApplyPaletteHash1(pix)]); + } else if (i == 2) { + APPLY_PALETTE_FOR(buffer[ApplyPaletteHash2(pix)]); + } else { + uint32_t idx_map[MAX_PALETTE_SIZE]; + uint32_t palette_sorted[MAX_PALETTE_SIZE]; + PrepareMapToPalette(palette, palette_size, palette_sorted, idx_map); + APPLY_PALETTE_FOR( + idx_map[SearchColorNoIdx(palette_sorted, pix, palette_size)]); } } WebPSafeFree(tmp_row); return VP8_ENC_OK; } +#undef APPLY_PALETTE_FOR +#undef PALETTE_INV_SIZE_BITS +#undef PALETTE_INV_SIZE +#undef APPLY_PALETTE_GREEDY_MAX // Note: Expects "enc->palette_" to be set properly. static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc, @@ -1291,7 +1350,7 @@ static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc, } // Save palette_[] to bitstream. -static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, +static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort, VP8LEncoder* const enc) { int i; uint32_t tmp_palette[MAX_PALETTE_SIZE]; @@ -1306,13 +1365,14 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, } tmp_palette[0] = palette[0]; return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, enc->refs_, - palette_size, 1, 20 /* quality */); + palette_size, 1, 20 /* quality */, low_effort); } #ifdef WEBP_EXPERIMENTAL_FEATURES static WebPEncodingError EncodeDeltaPalettePredictorImage( - VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality) { + VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality, + int low_effort) { const WebPPicture* const pic = enc->pic_; const int width = pic->width; const int height = pic->height; @@ -1343,7 +1403,7 @@ static WebPEncodingError EncodeDeltaPalettePredictorImage( err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_, (VP8LBackwardRefs*)enc->refs_, // cast const away transform_width, transform_height, - quality); + quality, low_effort); WebPSafeFree(predictors); return err; } @@ -1394,7 +1454,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, int use_near_lossless = 0; int hdr_size = 0; int data_size = 0; - int use_delta_palettization = 0; + int use_delta_palette = 0; if (enc == NULL) { err = VP8_ENC_ERROR_OUT_OF_MEMORY; @@ -1421,7 +1481,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, } #ifdef WEBP_EXPERIMENTAL_FEATURES - if (config->delta_palettization) { + if (config->use_delta_palette) { enc->use_predict_ = 1; enc->use_cross_color_ = 0; enc->use_subtract_green_ = 0; @@ -1433,21 +1493,25 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, if (enc->use_palette_) { err = AllocateTransformBuffer(enc, width, height); if (err != VP8_ENC_OK) goto Error; - err = EncodeDeltaPalettePredictorImage(bw, enc, quality); + err = EncodeDeltaPalettePredictorImage(bw, enc, quality, low_effort); if (err != VP8_ENC_OK) goto Error; - use_delta_palettization = 1; + use_delta_palette = 1; } } #endif // WEBP_EXPERIMENTAL_FEATURES // Encode palette if (enc->use_palette_) { - err = EncodePalette(bw, enc); + err = EncodePalette(bw, low_effort, enc); if (err != VP8_ENC_OK) goto Error; - err = MapImageFromPalette(enc, use_delta_palettization); + err = MapImageFromPalette(enc, use_delta_palette); if (err != VP8_ENC_OK) goto Error; + // If using a color cache, do not have it bigger than the number of colors. + if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { + enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1; + } } - if (!use_delta_palettization) { + if (!use_delta_palette) { // In case image is not packed. if (enc->argb_ == NULL) { err = MakeInputImageCopy(enc); @@ -1469,7 +1533,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, if (enc->use_cross_color_) { err = ApplyCrossColorFilter(enc, enc->current_width_, - height, quality, bw); + height, quality, low_effort, bw); if (err != VP8_ENC_OK) goto Error; } } diff --git a/src/3rdparty/libwebp/src/enc/vp8li.h b/src/3rdparty/libwebp/src/enc/vp8li_enc.h similarity index 78% rename from src/3rdparty/libwebp/src/enc/vp8li.h rename to src/3rdparty/libwebp/src/enc/vp8li_enc.h index 371e276ee091967a89cda0df01fdb108ffd21a17..8c5fbcbb2ea7aa445e2cdd98bbcacbd63039f75d 100644 --- a/src/3rdparty/libwebp/src/enc/vp8li.h +++ b/src/3rdparty/libwebp/src/enc/vp8li_enc.h @@ -14,9 +14,9 @@ #ifndef WEBP_ENC_VP8LI_H_ #define WEBP_ENC_VP8LI_H_ -#include "./backward_references.h" -#include "./histogram.h" -#include "../utils/bit_writer.h" +#include "./backward_references_enc.h" +#include "./histogram_enc.h" +#include "../utils/bit_writer_utils.h" #include "../webp/encode.h" #include "../webp/format_constants.h" @@ -24,6 +24,9 @@ extern "C" { #endif +// maximum value of transform_bits_ in VP8LEncoder. +#define MAX_TRANSFORM_BITS 6 + typedef struct { const WebPConfig* config_; // user configuration and parameters const WebPPicture* pic_; // input picture. @@ -39,7 +42,7 @@ typedef struct { // Encoding parameters derived from quality parameter. int histo_bits_; - int transform_bits_; + int transform_bits_; // <= MAX_TRANSFORM_BITS. int cache_bits_; // If equal to 0, don't use color cache. // Encoding parameters derived from image characteristics. @@ -72,6 +75,17 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, const WebPPicture* const picture, VP8LBitWriter* const bw, int use_cache); +//------------------------------------------------------------------------------ +// Image transforms in predictor.c. + +void VP8LResidualImage(int width, int height, int bits, int low_effort, + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image, int near_lossless, int exact, + int used_subtract_green); + +void VP8LColorSpaceTransform(int width, int height, int bits, int quality, + uint32_t* const argb, uint32_t* image); + //------------------------------------------------------------------------------ #ifdef __cplusplus diff --git a/src/3rdparty/libwebp/src/enc/webpenc.c b/src/3rdparty/libwebp/src/enc/webp_enc.c similarity index 96% rename from src/3rdparty/libwebp/src/enc/webpenc.c rename to src/3rdparty/libwebp/src/enc/webp_enc.c index a7d04ea2cef54455c2d60bfa715422134ed1966e..f18461ef92ba176acf2039e494b824f964866401 100644 --- a/src/3rdparty/libwebp/src/enc/webpenc.c +++ b/src/3rdparty/libwebp/src/enc/webp_enc.c @@ -16,9 +16,9 @@ #include <string.h> #include <math.h> -#include "./cost.h" -#include "./vp8enci.h" -#include "./vp8li.h" +#include "./cost_enc.h" +#include "./vp8i_enc.h" +#include "./vp8li_enc.h" #include "../utils/utils.h" // #define PRINT_MEMORY_INFO @@ -75,7 +75,7 @@ static void ResetBoundaryPredictions(VP8Encoder* const enc) { //-------------------+---+---+---+---+---+---+---+ // dynamic proba | ~ | x | x | x | x | x | x | //-------------------+---+---+---+---+---+---+---+ -// fast mode analysis| | | | | x | x | x | +// fast mode analysis|[x]|[x]| | | x | x | x | //-------------------+---+---+---+---+---+---+---+ // basic rd-opt | | | | x | x | x | x | //-------------------+---+---+---+---+---+---+---+ @@ -315,18 +315,21 @@ int WebPReportProgress(const WebPPicture* const pic, int WebPEncode(const WebPConfig* config, WebPPicture* pic) { int ok = 0; + if (pic == NULL) return 0; - if (pic == NULL) - return 0; WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far - if (config == NULL) // bad params + if (config == NULL) { // bad params return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); - if (!WebPValidateConfig(config)) + } + if (!WebPValidateConfig(config)) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); - if (pic->width <= 0 || pic->height <= 0) + } + if (pic->width <= 0 || pic->height <= 0) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); - if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) + } + if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); + } if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats)); @@ -339,8 +342,8 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) { if (pic->use_argb || pic->y == NULL || pic->u == NULL || pic->v == NULL) { // Make sure we have YUVA samples. - if (config->preprocessing & 4) { - if (!WebPPictureSmartARGBToYUVA(pic)) { + if (config->use_sharp_yuv || (config->preprocessing & 4)) { + if (!WebPPictureSharpARGBToYUVA(pic)) { return 0; } } else { diff --git a/src/3rdparty/libwebp/src/extras/extras.c b/src/3rdparty/libwebp/src/extras/extras.c deleted file mode 100644 index ca32fbcd862b6c4ae469b112c236dce96efcda3c..0000000000000000000000000000000000000000 --- a/src/3rdparty/libwebp/src/extras/extras.c +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2015 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. -// ----------------------------------------------------------------------------- -// -// Additional WebP utilities. -// - -#include "../webp/extras.h" - -#include <string.h> - -#define XTRA_MAJ_VERSION 0 -#define XTRA_MIN_VERSION 0 -#define XTRA_REV_VERSION 0 - -//------------------------------------------------------------------------------ - -int WebPGetExtrasVersion(void) { - return (XTRA_MAJ_VERSION << 16) | (XTRA_MIN_VERSION << 8) | XTRA_REV_VERSION; -} - -//------------------------------------------------------------------------------ - -int WebPImportGray(const uint8_t* gray_data, WebPPicture* pic) { - int y, width, uv_width; - if (pic == NULL || gray_data == NULL) return 0; - pic->colorspace = WEBP_YUV420; - if (!WebPPictureAlloc(pic)) return 0; - width = pic->width; - uv_width = (width + 1) >> 1; - for (y = 0; y < pic->height; ++y) { - memcpy(pic->y + y * pic->y_stride, gray_data, width); - gray_data += width; // <- we could use some 'data_stride' here if needed - if ((y & 1) == 0) { - memset(pic->u + (y >> 1) * pic->uv_stride, 128, uv_width); - memset(pic->v + (y >> 1) * pic->uv_stride, 128, uv_width); - } - } - return 1; -} - -int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) { - int x, y; - if (pic == NULL || rgb565 == NULL) return 0; - pic->colorspace = WEBP_YUV420; - pic->use_argb = 1; - if (!WebPPictureAlloc(pic)) return 0; - for (y = 0; y < pic->height; ++y) { - const int width = pic->width; - uint32_t* dst = pic->argb + y * pic->argb_stride; - for (x = 0; x < width; ++x) { -#ifdef WEBP_SWAP_16BIT_CSP - const uint32_t rg = rgb565[2 * x + 1]; - const uint32_t gb = rgb565[2 * x + 0]; -#else - const uint32_t rg = rgb565[2 * x + 0]; - const uint32_t gb = rgb565[2 * x + 1]; -#endif - uint32_t r = rg & 0xf8; - uint32_t g = ((rg << 5) | (gb >> 3)) & 0xfc; - uint32_t b = (gb << 5); - // dithering - r = r | (r >> 5); - g = g | (g >> 6); - b = b | (b >> 5); - dst[x] = (r << 16) | (g << 8) | b; - } - rgb565 += 2 * width; - } - return 1; -} - -int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) { - int x, y; - if (pic == NULL || rgb4444 == NULL) return 0; - pic->colorspace = WEBP_YUV420; - pic->use_argb = 1; - if (!WebPPictureAlloc(pic)) return 0; - for (y = 0; y < pic->height; ++y) { - const int width = pic->width; - uint32_t* dst = pic->argb + y * pic->argb_stride; - for (x = 0; x < width; ++x) { -#ifdef WEBP_SWAP_16BIT_CSP - const uint32_t rg = rgb4444[2 * x + 1]; - const uint32_t ba = rgb4444[2 * x + 0]; -#else - const uint32_t rg = rgb4444[2 * x + 0]; - const uint32_t ba = rgb4444[2 * x + 1]; -#endif - uint32_t r = rg & 0xf0; - uint32_t g = (rg << 4); - uint32_t b = (ba & 0xf0); - uint32_t a = (ba << 4); - // dithering - r = r | (r >> 4); - g = g | (g >> 4); - b = b | (b >> 4); - a = a | (a >> 4); - dst[x] = (a << 24) | (r << 16) | (g << 8) | b; - } - rgb4444 += 2 * width; - } - return 1; -} - -//------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/mux/anim_encode.c b/src/3rdparty/libwebp/src/mux/anim_encode.c index 53e2906a8291053f309fb70474ea520cf5e9cad4..60663887270e28adf38e70123f447807b75285f5 100644 --- a/src/3rdparty/libwebp/src/mux/anim_encode.c +++ b/src/3rdparty/libwebp/src/mux/anim_encode.c @@ -16,6 +16,7 @@ #include <stdio.h> #include <stdlib.h> // for abs() +#include "../mux/animi.h" #include "../utils/utils.h" #include "../webp/decode.h" #include "../webp/encode.h" @@ -128,14 +129,13 @@ static void SanitizeEncoderOptions(WebPAnimEncoderOptions* const enc_options) { DisableKeyframes(enc_options); } - if (enc_options->kmin <= 0) { - DisableKeyframes(enc_options); - print_warning = 0; - } - if (enc_options->kmax <= 0) { // All frames will be key-frames. + if (enc_options->kmax == 1) { // All frames will be key-frames. enc_options->kmin = 0; enc_options->kmax = 0; return; + } else if (enc_options->kmax <= 0) { + DisableKeyframes(enc_options); + print_warning = 0; } if (enc_options->kmin >= enc_options->kmax) { @@ -378,10 +378,10 @@ static WEBP_INLINE int PixelsAreSimilar(uint32_t src, uint32_t dst, const int dst_g = (dst >> 8) & 0xff; const int dst_b = (dst >> 0) & 0xff; - return (abs(src_r * src_a - dst_r * dst_a) <= (max_allowed_diff * 255)) && - (abs(src_g * src_a - dst_g * dst_a) <= (max_allowed_diff * 255)) && - (abs(src_b * src_a - dst_b * dst_a) <= (max_allowed_diff * 255)) && - (abs(src_a - dst_a) <= max_allowed_diff); + return (src_a == dst_a) && + (abs(src_r - dst_r) * dst_a <= (max_allowed_diff * 255)) && + (abs(src_g - dst_g) * dst_a <= (max_allowed_diff * 255)) && + (abs(src_b - dst_b) * dst_a <= (max_allowed_diff * 255)); } // Returns true if 'length' number of pixels in 'src' and 'dst' are within an @@ -586,6 +586,39 @@ static int GetSubRects(const WebPPicture* const prev_canvas, ¶ms->rect_lossy_, ¶ms->sub_frame_lossy_); } +static WEBP_INLINE int clip(int v, int min_v, int max_v) { + return (v < min_v) ? min_v : (v > max_v) ? max_v : v; +} + +int WebPAnimEncoderRefineRect( + const WebPPicture* const prev_canvas, const WebPPicture* const curr_canvas, + int is_lossless, float quality, int* const x_offset, int* const y_offset, + int* const width, int* const height) { + FrameRect rect; + const int right = clip(*x_offset + *width, 0, curr_canvas->width); + const int left = clip(*x_offset, 0, curr_canvas->width - 1); + const int bottom = clip(*y_offset + *height, 0, curr_canvas->height); + const int top = clip(*y_offset, 0, curr_canvas->height - 1); + if (prev_canvas == NULL || curr_canvas == NULL || + prev_canvas->width != curr_canvas->width || + prev_canvas->height != curr_canvas->height || + !prev_canvas->use_argb || !curr_canvas->use_argb) { + return 0; + } + rect.x_offset_ = left; + rect.y_offset_ = top; + rect.width_ = clip(right - left, 0, curr_canvas->width - rect.x_offset_); + rect.height_ = clip(bottom - top, 0, curr_canvas->height - rect.y_offset_); + MinimizeChangeRectangle(prev_canvas, curr_canvas, &rect, is_lossless, + quality); + SnapToEvenOffsets(&rect); + *x_offset = rect.x_offset_; + *y_offset = rect.y_offset_; + *width = rect.width_; + *height = rect.height_; + return 1; +} + static void DisposeFrameRectangle(int dispose_method, const FrameRect* const rect, WebPPicture* const curr_canvas) { @@ -829,8 +862,8 @@ static WebPEncodingError GenerateCandidates( WebPPicture* const curr_canvas = &enc->curr_canvas_copy_; const WebPPicture* const prev_canvas = is_dispose_none ? &enc->prev_canvas_ : &enc->prev_canvas_disposed_; - int use_blending_ll; - int use_blending_lossy; + int use_blending_ll, use_blending_lossy; + int evaluate_ll, evaluate_lossy; CopyCurrentCanvas(enc); use_blending_ll = @@ -843,16 +876,19 @@ static WebPEncodingError GenerateCandidates( // Pick candidates to be tried. if (!enc->options_.allow_mixed) { - candidate_ll->evaluate_ = is_lossless; - candidate_lossy->evaluate_ = !is_lossless; + evaluate_ll = is_lossless; + evaluate_lossy = !is_lossless; + } else if (enc->options_.minimize_size) { + evaluate_ll = 1; + evaluate_lossy = 1; } else { // Use a heuristic for trying lossless and/or lossy compression. const int num_colors = WebPGetColorPalette(¶ms->sub_frame_ll_, NULL); - candidate_ll->evaluate_ = (num_colors < MAX_COLORS_LOSSLESS); - candidate_lossy->evaluate_ = (num_colors >= MIN_COLORS_LOSSY); + evaluate_ll = (num_colors < MAX_COLORS_LOSSLESS); + evaluate_lossy = (num_colors >= MIN_COLORS_LOSSY); } // Generate candidates. - if (candidate_ll->evaluate_) { + if (evaluate_ll) { CopyCurrentCanvas(enc); if (use_blending_ll) { enc->curr_canvas_copy_modified_ = @@ -862,7 +898,7 @@ static WebPEncodingError GenerateCandidates( config_ll, use_blending_ll, candidate_ll); if (error_code != VP8_ENC_OK) return error_code; } - if (candidate_lossy->evaluate_) { + if (evaluate_lossy) { CopyCurrentCanvas(enc); if (use_blending_lossy) { enc->curr_canvas_copy_modified_ = @@ -1029,6 +1065,8 @@ static WebPEncodingError SetFrame(WebPAnimEncoder* const enc, const WebPPicture* const prev_canvas = &enc->prev_canvas_; Candidate candidates[CANDIDATE_COUNT]; const int is_lossless = config->lossless; + const int consider_lossless = is_lossless || enc->options_.allow_mixed; + const int consider_lossy = !is_lossless || enc->options_.allow_mixed; const int is_first_frame = enc->is_first_frame_; // First frame cannot be skipped as there is no 'previous frame' to merge it @@ -1066,9 +1104,7 @@ static WebPEncodingError SetFrame(WebPAnimEncoder* const enc, return VP8_ENC_ERROR_INVALID_CONFIGURATION; } - for (i = 0; i < CANDIDATE_COUNT; ++i) { - candidates[i].evaluate_ = 0; - } + memset(candidates, 0, sizeof(candidates)); // Change-rectangle assuming previous frame was DISPOSE_NONE. if (!GetSubRects(prev_canvas, curr_canvas, is_key_frame, is_first_frame, @@ -1077,8 +1113,8 @@ static WebPEncodingError SetFrame(WebPAnimEncoder* const enc, goto Err; } - if ((is_lossless && IsEmptyRect(&dispose_none_params.rect_ll_)) || - (!is_lossless && IsEmptyRect(&dispose_none_params.rect_lossy_))) { + if ((consider_lossless && IsEmptyRect(&dispose_none_params.rect_ll_)) || + (consider_lossy && IsEmptyRect(&dispose_none_params.rect_lossy_))) { // Don't encode the frame at all. Instead, the duration of the previous // frame will be increased later. assert(empty_rect_allowed_none); @@ -1187,16 +1223,20 @@ static int CacheFrame(WebPAnimEncoder* const enc, enc->prev_candidate_undecided_ = 0; } else { int64_t curr_delta; + FrameRect prev_rect_key, prev_rect_sub; // Add this as a frame rectangle to enc. error_code = SetFrame(enc, config, 0, encoded_frame, &frame_skipped); if (error_code != VP8_ENC_OK) goto End; if (frame_skipped) goto Skip; + prev_rect_sub = enc->prev_rect_; + // Add this as a key-frame to enc, too. error_code = SetFrame(enc, config, 1, encoded_frame, &frame_skipped); if (error_code != VP8_ENC_OK) goto End; assert(frame_skipped == 0); // Key-frame cannot be an empty rectangle. + prev_rect_key = enc->prev_rect_; // Analyze size difference of the two variants. curr_delta = KeyFramePenalty(encoded_frame); @@ -1207,11 +1247,13 @@ static int CacheFrame(WebPAnimEncoder* const enc, old_keyframe->is_key_frame_ = 0; } encoded_frame->is_key_frame_ = 1; + enc->prev_candidate_undecided_ = 1; enc->keyframe_ = (int)position; enc->best_delta_ = curr_delta; enc->flush_count_ = enc->count_ - 1; // We can flush previous frames. } else { encoded_frame->is_key_frame_ = 0; + enc->prev_candidate_undecided_ = 0; } // Note: We need '>=' below because when kmin and kmax are both zero, // count_since_key_frame will always be > kmax. @@ -1221,7 +1263,10 @@ static int CacheFrame(WebPAnimEncoder* const enc, enc->keyframe_ = KEYFRAME_NONE; enc->best_delta_ = DELTA_INFINITY; } - enc->prev_candidate_undecided_ = 1; + if (!enc->prev_candidate_undecided_) { + enc->prev_rect_ = + encoded_frame->is_key_frame_ ? prev_rect_key : prev_rect_sub; + } } } diff --git a/src/3rdparty/libwebp/src/mux/animi.h b/src/3rdparty/libwebp/src/mux/animi.h new file mode 100644 index 0000000000000000000000000000000000000000..cecaf1fee55e71dfd8904d98e4dbb78b9677f76d --- /dev/null +++ b/src/3rdparty/libwebp/src/mux/animi.h @@ -0,0 +1,43 @@ +// Copyright 2016 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. +// ----------------------------------------------------------------------------- +// +// Internal header for animation related functions. +// +// Author: Hui Su (huisu@google.com) + +#ifndef WEBP_MUX_ANIMI_H_ +#define WEBP_MUX_ANIMI_H_ + +#include "../webp/mux.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Picks the optimal rectangle between two pictures, starting with initial +// values of offsets and dimensions that are passed in. The initial +// values will be clipped, if necessary, to make sure the rectangle is +// within the canvas. "use_argb" must be true for both pictures. +// Parameters: +// prev_canvas, curr_canvas - (in) two input pictures to compare. +// is_lossless, quality - (in) encoding settings. +// x_offset, y_offset, width, height - (in/out) rectangle between the two +// input pictures. +// Returns true on success. +int WebPAnimEncoderRefineRect( + const struct WebPPicture* const prev_canvas, + const struct WebPPicture* const curr_canvas, + int is_lossless, float quality, int* const x_offset, int* const y_offset, + int* const width, int* const height); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* WEBP_MUX_ANIMI_H_ */ diff --git a/src/3rdparty/libwebp/src/mux/muxedit.c b/src/3rdparty/libwebp/src/mux/muxedit.c index 9bbed42b1a40f4158ceda274a924859eb4532ac4..d2c5305372b220816159361a028a0ff9148d151b 100644 --- a/src/3rdparty/libwebp/src/mux/muxedit.c +++ b/src/3rdparty/libwebp/src/mux/muxedit.c @@ -93,34 +93,32 @@ static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, uint32_t nth, } #undef SWITCH_ID_LIST -// Create data for frame/fragment given image data, offsets and duration. -static WebPMuxError CreateFrameFragmentData( - int width, int height, const WebPMuxFrameInfo* const info, int is_frame, - WebPData* const frame_frgm) { - uint8_t* frame_frgm_bytes; - const size_t frame_frgm_size = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].size; +// Create data for frame given image data, offsets and duration. +static WebPMuxError CreateFrameData( + int width, int height, const WebPMuxFrameInfo* const info, + WebPData* const frame) { + uint8_t* frame_bytes; + const size_t frame_size = kChunks[IDX_ANMF].size; assert(width > 0 && height > 0 && info->duration >= 0); assert(info->dispose_method == (info->dispose_method & 1)); // Note: assertion on upper bounds is done in PutLE24(). - frame_frgm_bytes = (uint8_t*)WebPSafeMalloc(1ULL, frame_frgm_size); - if (frame_frgm_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; + frame_bytes = (uint8_t*)WebPSafeMalloc(1ULL, frame_size); + if (frame_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; - PutLE24(frame_frgm_bytes + 0, info->x_offset / 2); - PutLE24(frame_frgm_bytes + 3, info->y_offset / 2); + PutLE24(frame_bytes + 0, info->x_offset / 2); + PutLE24(frame_bytes + 3, info->y_offset / 2); - if (is_frame) { - PutLE24(frame_frgm_bytes + 6, width - 1); - PutLE24(frame_frgm_bytes + 9, height - 1); - PutLE24(frame_frgm_bytes + 12, info->duration); - frame_frgm_bytes[15] = - (info->blend_method == WEBP_MUX_NO_BLEND ? 2 : 0) | - (info->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? 1 : 0); - } + PutLE24(frame_bytes + 6, width - 1); + PutLE24(frame_bytes + 9, height - 1); + PutLE24(frame_bytes + 12, info->duration); + frame_bytes[15] = + (info->blend_method == WEBP_MUX_NO_BLEND ? 2 : 0) | + (info->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? 1 : 0); - frame_frgm->bytes = frame_frgm_bytes; - frame_frgm->size = frame_frgm_size; + frame->bytes = frame_bytes; + frame->size = frame_size; return WEBP_MUX_OK; } @@ -264,23 +262,16 @@ WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream, return err; } -WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame, +WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info, int copy_data) { WebPMuxImage wpi; WebPMuxError err; - int is_frame; - const WebPData* const bitstream = &frame->bitstream; + const WebPData* const bitstream = &info->bitstream; // Sanity checks. - if (mux == NULL || frame == NULL) return WEBP_MUX_INVALID_ARGUMENT; + if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT; - is_frame = (frame->id == WEBP_CHUNK_ANMF); - if (!(is_frame || (frame->id == WEBP_CHUNK_FRGM))) { - return WEBP_MUX_INVALID_ARGUMENT; - } - if (frame->id == WEBP_CHUNK_FRGM) { // Dead experiment. - return WEBP_MUX_INVALID_ARGUMENT; - } + if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT; if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; @@ -290,7 +281,7 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame, const WebPMuxImage* const image = mux->images_; const uint32_t image_id = (image->header_ != NULL) ? ChunkGetIdFromTag(image->header_->tag_) : WEBP_CHUNK_IMAGE; - if (image_id != frame->id) { + if (image_id != info->id) { return WEBP_MUX_INVALID_ARGUMENT; // Conflicting frame types. } } @@ -301,16 +292,11 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame, assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful. { - WebPData frame_frgm; - const uint32_t tag = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].tag; - WebPMuxFrameInfo tmp = *frame; + WebPData frame; + const uint32_t tag = kChunks[IDX_ANMF].tag; + WebPMuxFrameInfo tmp = *info; tmp.x_offset &= ~1; // Snap offsets to even. tmp.y_offset &= ~1; - if (!is_frame) { // Reset unused values. - tmp.duration = 1; - tmp.dispose_method = WEBP_MUX_DISPOSE_NONE; - tmp.blend_method = WEBP_MUX_BLEND; - } if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET || tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET || (tmp.duration < 0 || tmp.duration >= MAX_DURATION) || @@ -318,12 +304,11 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame, err = WEBP_MUX_INVALID_ARGUMENT; goto Err; } - err = CreateFrameFragmentData(wpi.width_, wpi.height_, &tmp, is_frame, - &frame_frgm); + err = CreateFrameData(wpi.width_, wpi.height_, &tmp, &frame); if (err != WEBP_MUX_OK) goto Err; - // Add frame/fragment chunk (with copy_data = 1). - err = AddDataToChunkList(&frame_frgm, 1, tag, &wpi.header_); - WebPDataClear(&frame_frgm); // frame_frgm owned by wpi.header_ now. + // Add frame chunk (with copy_data = 1). + err = AddDataToChunkList(&frame, 1, tag, &wpi.header_); + WebPDataClear(&frame); // frame owned by wpi.header_ now. if (err != WEBP_MUX_OK) goto Err; } @@ -402,21 +387,18 @@ WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) { //------------------------------------------------------------------------------ // Assembly of the WebP RIFF file. -static WebPMuxError GetFrameFragmentInfo( - const WebPChunk* const frame_frgm_chunk, +static WebPMuxError GetFrameInfo( + const WebPChunk* const frame_chunk, int* const x_offset, int* const y_offset, int* const duration) { - const uint32_t tag = frame_frgm_chunk->tag_; - const int is_frame = (tag == kChunks[IDX_ANMF].tag); - const WebPData* const data = &frame_frgm_chunk->data_; - const size_t expected_data_size = - is_frame ? ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE; - assert(frame_frgm_chunk != NULL); - assert(tag == kChunks[IDX_ANMF].tag || tag == kChunks[IDX_FRGM].tag); + const WebPData* const data = &frame_chunk->data_; + const size_t expected_data_size = ANMF_CHUNK_SIZE; + assert(frame_chunk->tag_ == kChunks[IDX_ANMF].tag); + assert(frame_chunk != NULL); if (data->size != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT; *x_offset = 2 * GetLE24(data->bytes + 0); *y_offset = 2 * GetLE24(data->bytes + 3); - if (is_frame) *duration = GetLE24(data->bytes + 12); + *duration = GetLE24(data->bytes + 12); return WEBP_MUX_OK; } @@ -424,13 +406,13 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi, int* const x_offset, int* const y_offset, int* const duration, int* const width, int* const height) { - const WebPChunk* const frame_frgm_chunk = wpi->header_; + const WebPChunk* const frame_chunk = wpi->header_; WebPMuxError err; assert(wpi != NULL); - assert(frame_frgm_chunk != NULL); + assert(frame_chunk != NULL); - // Get offsets and duration from ANMF/FRGM chunk. - err = GetFrameFragmentInfo(frame_frgm_chunk, x_offset, y_offset, duration); + // Get offsets and duration from ANMF chunk. + err = GetFrameInfo(frame_chunk, x_offset, y_offset, duration); if (err != WEBP_MUX_OK) return err; // Get width and height from VP8/VP8L chunk. @@ -441,7 +423,6 @@ static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi, // Returns the tightest dimension for the canvas considering the image list. static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux, - uint32_t flags, int* const width, int* const height) { WebPMuxImage* wpi = NULL; assert(mux != NULL); @@ -452,12 +433,10 @@ static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux, assert(wpi->img_ != NULL); if (wpi->next_ != NULL) { - int max_x = 0; - int max_y = 0; - int64_t image_area = 0; + int max_x = 0, max_y = 0; // if we have a chain of wpi's, header_ is necessarily set assert(wpi->header_ != NULL); - // Aggregate the bounding box for animation frames & fragmented images. + // Aggregate the bounding box for animation frames. for (; wpi != NULL; wpi = wpi->next_) { int x_offset = 0, y_offset = 0, duration = 0, w = 0, h = 0; const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset, @@ -470,19 +449,9 @@ static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux, if (max_x_pos > max_x) max_x = max_x_pos; if (max_y_pos > max_y) max_y = max_y_pos; - image_area += w * h; } *width = max_x; *height = max_y; - // Crude check to validate that there are no image overlaps/holes for - // fragmented images. Check that the aggregated image area for individual - // fragments exactly matches the image area of the constructed canvas. - // However, the area-match is necessary but not sufficient condition. - if ((flags & FRAGMENTS_FLAG) && (image_area != (max_x * max_y))) { - *width = 0; - *height = 0; - return WEBP_MUX_INVALID_ARGUMENT; - } } else { // For a single image, canvas dimensions are same as image dimensions. *width = wpi->width_; @@ -528,10 +497,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { flags |= XMP_FLAG; } if (images->header_ != NULL) { - if (images->header_->tag_ == kChunks[IDX_FRGM].tag) { - // This is a fragmented image. - flags |= FRAGMENTS_FLAG; - } else if (images->header_->tag_ == kChunks[IDX_ANMF].tag) { + if (images->header_->tag_ == kChunks[IDX_ANMF].tag) { // This is an image with animation. flags |= ANIMATION_FLAG; } @@ -540,7 +506,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { flags |= ALPHA_FLAG; // Some images have an alpha channel. } - err = GetAdjustedCanvasSize(mux, flags, &width, &height); + err = GetAdjustedCanvasSize(mux, &width, &height); if (err != WEBP_MUX_OK) return err; if (width <= 0 || height <= 0) { @@ -580,31 +546,26 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { // Cleans up 'mux' by removing any unnecessary chunks. static WebPMuxError MuxCleanup(WebPMux* const mux) { int num_frames; - int num_fragments; int num_anim_chunks; - // If we have an image with a single fragment or frame, and its rectangle - // covers the whole canvas, convert it to a non-animated non-fragmented image - // (to avoid writing FRGM/ANMF chunk unnecessarily). + // If we have an image with a single frame, and its rectangle + // covers the whole canvas, convert it to a non-animated image + // (to avoid writing ANMF chunk unnecessarily). WebPMuxError err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames); if (err != WEBP_MUX_OK) return err; - err = WebPMuxNumChunks(mux, kChunks[IDX_FRGM].id, &num_fragments); - if (err != WEBP_MUX_OK) return err; - if (num_frames == 1 || num_fragments == 1) { - WebPMuxImage* frame_frag; - err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame_frag); - assert(err == WEBP_MUX_OK); // We know that one frame/fragment does exist. - assert(frame_frag != NULL); - if (frame_frag->header_ != NULL && + if (num_frames == 1) { + WebPMuxImage* frame = NULL; + err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame); + assert(err == WEBP_MUX_OK); // We know that one frame does exist. + assert(frame != NULL); + if (frame->header_ != NULL && ((mux->canvas_width_ == 0 && mux->canvas_height_ == 0) || - (frame_frag->width_ == mux->canvas_width_ && - frame_frag->height_ == mux->canvas_height_))) { - assert(frame_frag->header_->tag_ == kChunks[IDX_ANMF].tag || - frame_frag->header_->tag_ == kChunks[IDX_FRGM].tag); - ChunkDelete(frame_frag->header_); // Removes ANMF/FRGM chunk. - frame_frag->header_ = NULL; + (frame->width_ == mux->canvas_width_ && + frame->height_ == mux->canvas_height_))) { + assert(frame->header_->tag_ == kChunks[IDX_ANMF].tag); + ChunkDelete(frame->header_); // Removes ANMF chunk. + frame->header_ = NULL; num_frames = 0; - num_fragments = 0; } } // Remove ANIM chunk if this is a non-animated image. diff --git a/src/3rdparty/libwebp/src/mux/muxi.h b/src/3rdparty/libwebp/src/mux/muxi.h index d4d5cbad916269545865038cbaa93f288eee99cd..e6606aa5d1bde03b4a884b1c4852682de7853e1f 100644 --- a/src/3rdparty/libwebp/src/mux/muxi.h +++ b/src/3rdparty/libwebp/src/mux/muxi.h @@ -15,8 +15,8 @@ #define WEBP_MUX_MUXI_H_ #include <stdlib.h> -#include "../dec/vp8i.h" -#include "../dec/vp8li.h" +#include "../dec/vp8i_dec.h" +#include "../dec/vp8li_dec.h" #include "../webp/mux.h" #ifdef __cplusplus @@ -27,8 +27,8 @@ extern "C" { // Defines and constants. #define MUX_MAJ_VERSION 0 -#define MUX_MIN_VERSION 3 -#define MUX_REV_VERSION 1 +#define MUX_MIN_VERSION 4 +#define MUX_REV_VERSION 0 // Chunk object. typedef struct WebPChunk WebPChunk; @@ -36,16 +36,16 @@ struct WebPChunk { uint32_t tag_; int owner_; // True if *data_ memory is owned internally. // VP8X, ANIM, and other internally created chunks - // like ANMF/FRGM are always owned. + // like ANMF are always owned. WebPData data_; WebPChunk* next_; }; -// MuxImage object. Store a full WebP image (including ANMF/FRGM chunk, ALPH +// MuxImage object. Store a full WebP image (including ANMF chunk, ALPH // chunk and VP8/VP8L chunk), typedef struct WebPMuxImage WebPMuxImage; struct WebPMuxImage { - WebPChunk* header_; // Corresponds to WEBP_CHUNK_ANMF/WEBP_CHUNK_FRGM. + WebPChunk* header_; // Corresponds to WEBP_CHUNK_ANMF. WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA. WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE. WebPChunk* unknown_; // Corresponds to WEBP_CHUNK_UNKNOWN. @@ -79,7 +79,6 @@ typedef enum { IDX_ICCP, IDX_ANIM, IDX_ANMF, - IDX_FRGM, IDX_ALPHA, IDX_VP8, IDX_VP8L, @@ -185,7 +184,6 @@ int MuxImageFinalize(WebPMuxImage* const wpi); static WEBP_INLINE int IsWPI(WebPChunkId id) { switch (id) { case WEBP_CHUNK_ANMF: - case WEBP_CHUNK_FRGM: case WEBP_CHUNK_ALPHA: case WEBP_CHUNK_IMAGE: return 1; default: return 0; diff --git a/src/3rdparty/libwebp/src/mux/muxinternal.c b/src/3rdparty/libwebp/src/mux/muxinternal.c index 4babbe82fc8af455efef41b4d20a271edcecc3a9..387b57e8fe38a968009e28be1038cd489269375e 100644 --- a/src/3rdparty/libwebp/src/mux/muxinternal.c +++ b/src/3rdparty/libwebp/src/mux/muxinternal.c @@ -16,14 +16,13 @@ #include "./muxi.h" #include "../utils/utils.h" -#define UNDEFINED_CHUNK_SIZE (-1) +#define UNDEFINED_CHUNK_SIZE ((uint32_t)(-1)) const ChunkInfo kChunks[] = { { MKFOURCC('V', 'P', '8', 'X'), WEBP_CHUNK_VP8X, VP8X_CHUNK_SIZE }, { MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('A', 'N', 'I', 'M'), WEBP_CHUNK_ANIM, ANIM_CHUNK_SIZE }, { MKFOURCC('A', 'N', 'M', 'F'), WEBP_CHUNK_ANMF, ANMF_CHUNK_SIZE }, - { MKFOURCC('F', 'R', 'G', 'M'), WEBP_CHUNK_FRGM, FRGM_CHUNK_SIZE }, { MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, @@ -251,8 +250,7 @@ static WebPChunk** GetChunkListFromId(const WebPMuxImage* const wpi, WebPChunkId id) { assert(wpi != NULL); switch (id) { - case WEBP_CHUNK_ANMF: - case WEBP_CHUNK_FRGM: return (WebPChunk**)&wpi->header_; + case WEBP_CHUNK_ANMF: return (WebPChunk**)&wpi->header_; case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_; case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_; default: return NULL; @@ -372,13 +370,12 @@ size_t MuxImageDiskSize(const WebPMuxImage* const wpi) { return size; } -// Special case as ANMF/FRGM chunk encapsulates other image chunks. +// Special case as ANMF chunk encapsulates other image chunks. static uint8_t* ChunkEmitSpecial(const WebPChunk* const header, size_t total_size, uint8_t* dst) { const size_t header_size = header->data_.size; const size_t offset_to_next = total_size - CHUNK_HEADER_SIZE; - assert(header->tag_ == kChunks[IDX_ANMF].tag || - header->tag_ == kChunks[IDX_FRGM].tag); + assert(header->tag_ == kChunks[IDX_ANMF].tag); PutLE32(dst + 0, header->tag_); PutLE32(dst + TAG_SIZE, (uint32_t)offset_to_next); assert(header_size == (uint32_t)header_size); @@ -391,7 +388,7 @@ static uint8_t* ChunkEmitSpecial(const WebPChunk* const header, uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) { // Ordering of chunks to be emitted is strictly as follows: - // 1. ANMF/FRGM chunk (if present). + // 1. ANMF chunk (if present). // 2. ALPH chunk (if present). // 3. VP8/VP8L chunk. assert(wpi); @@ -439,7 +436,7 @@ static int IsNotCompatible(int feature, int num_items) { return (feature != 0) != (num_items > 0); } -#define NO_FLAG 0 +#define NO_FLAG ((WebPFeatureFlags)0) // Test basic constraints: // retrieval, maximum number of chunks by index (use -1 to skip) @@ -465,7 +462,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) { int num_xmp; int num_anim; int num_frames; - int num_fragments; int num_vp8x; int num_images; int num_alpha; @@ -510,10 +506,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) { } } - // Fragmentation: FRAGMENTS_FLAG and FRGM chunk(s) are consistent. - err = ValidateChunk(mux, IDX_FRGM, FRAGMENTS_FLAG, flags, -1, &num_fragments); - if (err != WEBP_MUX_OK) return err; - // Verify either VP8X chunk is present OR there is only one elem in // mux->images_. err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x); @@ -537,11 +529,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) { if (flags & ALPHA_FLAG) return WEBP_MUX_INVALID_ARGUMENT; } - // num_fragments & num_images are consistent. - if (num_fragments > 0 && num_images != num_fragments) { - return WEBP_MUX_INVALID_ARGUMENT; - } - return WEBP_MUX_OK; } diff --git a/src/3rdparty/libwebp/src/mux/muxread.c b/src/3rdparty/libwebp/src/mux/muxread.c index 8957a1e46e219034e30b296237486d6547ecb628..410acd9119cb66a6435497f37d5642b294e4de03 100644 --- a/src/3rdparty/libwebp/src/mux/muxread.c +++ b/src/3rdparty/libwebp/src/mux/muxread.c @@ -104,17 +104,15 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data, size_t subchunk_size; ChunkInit(&subchunk); - assert(chunk->tag_ == kChunks[IDX_ANMF].tag || - chunk->tag_ == kChunks[IDX_FRGM].tag); + assert(chunk->tag_ == kChunks[IDX_ANMF].tag); assert(!wpi->is_partial_); - // ANMF/FRGM. + // ANMF. { - const size_t hdr_size = (chunk->tag_ == kChunks[IDX_ANMF].tag) ? - ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE; + const size_t hdr_size = ANMF_CHUNK_SIZE; const WebPData temp = { bytes, hdr_size }; - // Each of ANMF and FRGM chunk contain a header at the beginning. So, its - // size should at least be 'hdr_size'. + // Each of ANMF chunk contain a header at the beginning. So, its size should + // be at least 'hdr_size'. if (size < hdr_size) goto Fail; ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_); } @@ -292,16 +290,15 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, static WebPMuxError ValidateForSingleImage(const WebPMux* const mux) { const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE); const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_ANMF); - const int num_fragments = MuxImageCount(mux->images_, WEBP_CHUNK_FRGM); if (num_images == 0) { // No images in mux. return WEBP_MUX_NOT_FOUND; - } else if (num_images == 1 && num_frames == 0 && num_fragments == 0) { + } else if (num_images == 1 && num_frames == 0) { // Valid case (single image). return WEBP_MUX_OK; } else { - // Frame/Fragment case OR an invalid mux. + // Frame case OR an invalid mux. return WEBP_MUX_INVALID_ARGUMENT; } } @@ -379,7 +376,7 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, const int need_vp8x = (wpi->alpha_ != NULL); const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0; const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0; - // Note: No need to output ANMF/FRGM chunk for a single image. + // Note: No need to output ANMF chunk for a single image. const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size + ChunkDiskSize(wpi->img_); uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size); @@ -436,29 +433,24 @@ static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi, return SynthesizeBitstream(wpi, &info->bitstream); } -static WebPMuxError MuxGetFrameFragmentInternal(const WebPMuxImage* const wpi, - WebPMuxFrameInfo* const frame) { +static WebPMuxError MuxGetFrameInternal(const WebPMuxImage* const wpi, + WebPMuxFrameInfo* const frame) { const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag); - const CHUNK_INDEX idx = is_frame ? IDX_ANMF : IDX_FRGM; - const WebPData* frame_frgm_data; + const WebPData* frame_data; if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT; assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame(). - // Get frame/fragment chunk. - frame_frgm_data = &wpi->header_->data_; - if (frame_frgm_data->size < kChunks[idx].size) return WEBP_MUX_BAD_DATA; + // Get frame chunk. + frame_data = &wpi->header_->data_; + if (frame_data->size < kChunks[IDX_ANMF].size) return WEBP_MUX_BAD_DATA; // Extract info. - frame->x_offset = 2 * GetLE24(frame_frgm_data->bytes + 0); - frame->y_offset = 2 * GetLE24(frame_frgm_data->bytes + 3); - if (is_frame) { - const uint8_t bits = frame_frgm_data->bytes[15]; - frame->duration = GetLE24(frame_frgm_data->bytes + 12); + frame->x_offset = 2 * GetLE24(frame_data->bytes + 0); + frame->y_offset = 2 * GetLE24(frame_data->bytes + 3); + { + const uint8_t bits = frame_data->bytes[15]; + frame->duration = GetLE24(frame_data->bytes + 12); frame->dispose_method = (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; - } else { // Defaults for unused values. - frame->duration = 1; - frame->dispose_method = WEBP_MUX_DISPOSE_NONE; - frame->blend_method = WEBP_MUX_BLEND; } frame->id = ChunkGetIdFromTag(wpi->header_->tag_); return SynthesizeBitstream(wpi, &frame->bitstream); @@ -482,7 +474,7 @@ WebPMuxError WebPMuxGetFrame( if (wpi->header_ == NULL) { return MuxGetImageInternal(wpi, frame); } else { - return MuxGetFrameFragmentInternal(wpi, frame); + return MuxGetFrameInternal(wpi, frame); } } diff --git a/src/3rdparty/libwebp/src/utils/bit_reader_inl.h b/src/3rdparty/libwebp/src/utils/bit_reader_inl_utils.h similarity index 82% rename from src/3rdparty/libwebp/src/utils/bit_reader_inl.h rename to src/3rdparty/libwebp/src/utils/bit_reader_inl_utils.h index 99ed3137d2cf912acec9f605adc161eb88a4173c..fd7fb0446c71fb6ef5f2b90077b402d67533b1ee 100644 --- a/src/3rdparty/libwebp/src/utils/bit_reader_inl.h +++ b/src/3rdparty/libwebp/src/utils/bit_reader_inl_utils.h @@ -20,13 +20,12 @@ #include "../webp/config.h" #endif -#ifdef WEBP_FORCE_ALIGNED -#include <string.h> // memcpy -#endif +#include <string.h> // for memcpy #include "../dsp/dsp.h" -#include "./bit_reader.h" -#include "./endian_inl.h" +#include "./bit_reader_utils.h" +#include "./endian_inl_utils.h" +#include "./utils.h" #ifdef __cplusplus extern "C" { @@ -62,10 +61,7 @@ void VP8LoadNewBytes(VP8BitReader* const br) { if (br->buf_ < br->buf_max_) { // convert memory type to register type (with some zero'ing!) bit_t bits; -#if defined(WEBP_FORCE_ALIGNED) - lbit_t in_bits; - memcpy(&in_bits, br->buf_, sizeof(in_bits)); -#elif defined(WEBP_USE_MIPS32) +#if defined(WEBP_USE_MIPS32) // This is needed because of un-aligned read. lbit_t in_bits; lbit_t* p_buf_ = (lbit_t*)br->buf_; @@ -80,7 +76,8 @@ void VP8LoadNewBytes(VP8BitReader* const br) { : "memory", "at" ); #else - const lbit_t in_bits = *(const lbit_t*)br->buf_; + lbit_t in_bits; + memcpy(&in_bits, br->buf_, sizeof(in_bits)); #endif br->buf_ += BITS >> 3; #if !defined(WORDS_BIGENDIAN) @@ -119,37 +116,26 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) { const int pos = br->bits_; const range_t split = (range * prob) >> 8; const range_t value = (range_t)(br->value_ >> pos); -#if defined(__arm__) || defined(_M_ARM) // ARM-specific - const int bit = ((int)(split - value) >> 31) & 1; - if (value > split) { - range -= split + 1; - br->value_ -= (bit_t)(split + 1) << pos; - } else { - range = split; - } -#else // faster version on x86 - int bit; // Don't use 'const int bit = (value > split);", it's slower. - if (value > split) { - range -= split + 1; + const int bit = (value > split); + if (bit) { + range -= split; br->value_ -= (bit_t)(split + 1) << pos; - bit = 1; } else { - range = split; - bit = 0; + range = split + 1; } -#endif - if (range <= (range_t)0x7e) { - const int shift = kVP8Log2Range[range]; - range = kVP8NewRange[range]; + { + const int shift = 7 ^ BitsLog2Floor(range); + range <<= shift; br->bits_ -= shift; } - br->range_ = range; + br->range_ = range - 1; return bit; } } // simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here) -static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) { +static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE +int VP8GetSigned(VP8BitReader* const br, int v) { if (br->bits_ < 0) { VP8LoadNewBytes(br); } @@ -166,6 +152,37 @@ static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) { } } +static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) { + // Don't move this declaration! It makes a big speed difference to store + // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't + // alter br->range_ value. + range_t range = br->range_; + if (br->bits_ < 0) { + VP8LoadNewBytes(br); + } + { + const int pos = br->bits_; + const range_t split = (range * prob) >> 8; + const range_t value = (range_t)(br->value_ >> pos); + int bit; // Don't use 'const int bit = (value > split);", it's slower. + if (value > split) { + range -= split + 1; + br->value_ -= (bit_t)(split + 1) << pos; + bit = 1; + } else { + range = split; + bit = 0; + } + if (range <= (range_t)0x7e) { + const int shift = kVP8Log2Range[range]; + range = kVP8NewRange[range]; + br->bits_ -= shift; + } + br->range_ = range; + return bit; + } +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/3rdparty/libwebp/src/utils/bit_reader.c b/src/3rdparty/libwebp/src/utils/bit_reader_utils.c similarity index 99% rename from src/3rdparty/libwebp/src/utils/bit_reader.c rename to src/3rdparty/libwebp/src/utils/bit_reader_utils.c index 50ffb74f9c8b9016e2ee9986ace64ae1c0d66392..c3157e8fe8349c1c6dbae2f2efea99e9cd89285c 100644 --- a/src/3rdparty/libwebp/src/utils/bit_reader.c +++ b/src/3rdparty/libwebp/src/utils/bit_reader_utils.c @@ -15,7 +15,7 @@ #include "../webp/config.h" #endif -#include "./bit_reader_inl.h" +#include "./bit_reader_inl_utils.h" #include "../utils/utils.h" //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/utils/bit_reader.h b/src/3rdparty/libwebp/src/utils/bit_reader_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/bit_reader.h rename to src/3rdparty/libwebp/src/utils/bit_reader_utils.h diff --git a/src/3rdparty/libwebp/src/utils/bit_writer.c b/src/3rdparty/libwebp/src/utils/bit_writer_utils.c similarity index 98% rename from src/3rdparty/libwebp/src/utils/bit_writer.c rename to src/3rdparty/libwebp/src/utils/bit_writer_utils.c index 064428691b4788befb0813bdf4cee3e3162c74de..ab0c49dce826dfb3ab1d6ba0031386bf1b79dcb5 100644 --- a/src/3rdparty/libwebp/src/utils/bit_writer.c +++ b/src/3rdparty/libwebp/src/utils/bit_writer_utils.c @@ -16,8 +16,8 @@ #include <string.h> // for memcpy() #include <stdlib.h> -#include "./bit_writer.h" -#include "./endian_inl.h" +#include "./bit_writer_utils.h" +#include "./endian_inl_utils.h" #include "./utils.h" //------------------------------------------------------------------------------ @@ -143,13 +143,13 @@ int VP8PutBitUniform(VP8BitWriter* const bw, int bit) { void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits) { uint32_t mask; assert(nb_bits > 0 && nb_bits < 32); - for (mask = 1u << (nb_bits - 1); mask; mask >>= 1) + for (mask = 1u << (nb_bits - 1); mask; mask >>= 1) { VP8PutBitUniform(bw, value & mask); + } } void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits) { - if (!VP8PutBitUniform(bw, value != 0)) - return; + if (!VP8PutBitUniform(bw, value != 0)) return; if (value < 0) { VP8PutBits(bw, ((-value) << 1) | 1, nb_bits + 1); } else { diff --git a/src/3rdparty/libwebp/src/utils/bit_writer.h b/src/3rdparty/libwebp/src/utils/bit_writer_utils.h similarity index 97% rename from src/3rdparty/libwebp/src/utils/bit_writer.h rename to src/3rdparty/libwebp/src/utils/bit_writer_utils.h index ef360d1dc6f315fcd7692f6da391d0ed3135daec..9c02bbc06d9377e81300db25d018e3def98b0041 100644 --- a/src/3rdparty/libwebp/src/utils/bit_writer.h +++ b/src/3rdparty/libwebp/src/utils/bit_writer_utils.h @@ -54,7 +54,8 @@ int VP8BitWriterAppend(VP8BitWriter* const bw, // return approximate write position (in bits) static WEBP_INLINE uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) { - return (uint64_t)(bw->pos_ + bw->run_) * 8 + 8 + bw->nb_bits_; + const uint64_t nb_bits = 8 + bw->nb_bits_; // bw->nb_bits_ is <= 0, note + return (bw->pos_ + bw->run_) * 8 + nb_bits; } // Returns a pointer to the internal buffer. diff --git a/src/3rdparty/libwebp/src/utils/color_cache.c b/src/3rdparty/libwebp/src/utils/color_cache_utils.c similarity index 97% rename from src/3rdparty/libwebp/src/utils/color_cache.c rename to src/3rdparty/libwebp/src/utils/color_cache_utils.c index c34b2e7f1a636c9aeaa972d7471ed77efb195913..0172590c48d4d7b15e4616ab0a857b3750c0569d 100644 --- a/src/3rdparty/libwebp/src/utils/color_cache.c +++ b/src/3rdparty/libwebp/src/utils/color_cache_utils.c @@ -14,7 +14,7 @@ #include <assert.h> #include <stdlib.h> #include <string.h> -#include "./color_cache.h" +#include "./color_cache_utils.h" #include "./utils.h" //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/utils/color_cache.h b/src/3rdparty/libwebp/src/utils/color_cache_utils.h similarity index 85% rename from src/3rdparty/libwebp/src/utils/color_cache.h rename to src/3rdparty/libwebp/src/utils/color_cache_utils.h index a9a9f64270fe18f630ecdd36073d8f3e85d1db59..c373e6b3610676d6a179be4fd3b2977406d0bc1f 100644 --- a/src/3rdparty/libwebp/src/utils/color_cache.h +++ b/src/3rdparty/libwebp/src/utils/color_cache_utils.h @@ -28,7 +28,11 @@ typedef struct { int hash_bits_; } VP8LColorCache; -static const uint32_t kHashMul = 0x1e35a7bd; +static const uint64_t kHashMul = 0x1e35a7bdull; + +static WEBP_INLINE int HashPix(uint32_t argb, int shift) { + return (int)(((argb * kHashMul) & 0xffffffffu) >> shift); +} static WEBP_INLINE uint32_t VP8LColorCacheLookup( const VP8LColorCache* const cc, uint32_t key) { @@ -44,19 +48,20 @@ static WEBP_INLINE void VP8LColorCacheSet(const VP8LColorCache* const cc, static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc, uint32_t argb) { - const uint32_t key = (kHashMul * argb) >> cc->hash_shift_; + const int key = HashPix(argb, cc->hash_shift_); cc->colors_[key] = argb; } static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc, uint32_t argb) { - return (kHashMul * argb) >> cc->hash_shift_; + return HashPix(argb, cc->hash_shift_); } +// Return the key if cc contains argb, and -1 otherwise. static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc, uint32_t argb) { - const uint32_t key = (kHashMul * argb) >> cc->hash_shift_; - return (cc->colors_[key] == argb); + const int key = HashPix(argb, cc->hash_shift_); + return (cc->colors_[key] == argb) ? key : -1; } //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/utils/endian_inl.h b/src/3rdparty/libwebp/src/utils/endian_inl_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/endian_inl.h rename to src/3rdparty/libwebp/src/utils/endian_inl_utils.h diff --git a/src/3rdparty/libwebp/src/utils/filters.c b/src/3rdparty/libwebp/src/utils/filters_utils.c similarity index 98% rename from src/3rdparty/libwebp/src/utils/filters.c rename to src/3rdparty/libwebp/src/utils/filters_utils.c index 15543b1271e67904991a419d3babbaeb161973c4..49c1d18a22b6327a63a1b1ead65e7340bb1c9591 100644 --- a/src/3rdparty/libwebp/src/utils/filters.c +++ b/src/3rdparty/libwebp/src/utils/filters_utils.c @@ -11,7 +11,7 @@ // // Author: Urvang (urvang@google.com) -#include "./filters.h" +#include "./filters_utils.h" #include <stdlib.h> #include <string.h> diff --git a/src/3rdparty/libwebp/src/utils/filters.h b/src/3rdparty/libwebp/src/utils/filters_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/filters.h rename to src/3rdparty/libwebp/src/utils/filters_utils.h diff --git a/src/3rdparty/libwebp/src/utils/huffman_encode.c b/src/3rdparty/libwebp/src/utils/huffman_encode_utils.c similarity index 99% rename from src/3rdparty/libwebp/src/utils/huffman_encode.c rename to src/3rdparty/libwebp/src/utils/huffman_encode_utils.c index 4e5ef6b447d54102111672d5700b1a2657a67af1..f9504658ead42971464b446567a118315b51b1d5 100644 --- a/src/3rdparty/libwebp/src/utils/huffman_encode.c +++ b/src/3rdparty/libwebp/src/utils/huffman_encode_utils.c @@ -14,7 +14,7 @@ #include <assert.h> #include <stdlib.h> #include <string.h> -#include "./huffman_encode.h" +#include "./huffman_encode_utils.h" #include "./utils.h" #include "../webp/format_constants.h" diff --git a/src/3rdparty/libwebp/src/utils/huffman_encode.h b/src/3rdparty/libwebp/src/utils/huffman_encode_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/huffman_encode.h rename to src/3rdparty/libwebp/src/utils/huffman_encode_utils.h diff --git a/src/3rdparty/libwebp/src/utils/huffman.c b/src/3rdparty/libwebp/src/utils/huffman_utils.c similarity index 82% rename from src/3rdparty/libwebp/src/utils/huffman.c rename to src/3rdparty/libwebp/src/utils/huffman_utils.c index 36e5502836ab82bd5294f107e231c919601f19c8..008b5d746fb9fc02339568e8336c5b6cfbebe075 100644 --- a/src/3rdparty/libwebp/src/utils/huffman.c +++ b/src/3rdparty/libwebp/src/utils/huffman_utils.c @@ -14,7 +14,7 @@ #include <assert.h> #include <stdlib.h> #include <string.h> -#include "./huffman.h" +#include "./huffman_utils.h" #include "./utils.h" #include "../webp/format_constants.h" @@ -45,7 +45,7 @@ static WEBP_INLINE uint32_t GetNextKey(uint32_t key, int len) { while (key & step) { step >>= 1; } - return (key & (step - 1)) + step; + return step ? (key & (step - 1)) + step : key; } // Stores code in table[0], table[step], table[2*step], ..., table[end]. @@ -75,11 +75,13 @@ static WEBP_INLINE int NextTableBitSize(const int* const count, return len - root_bits; } -int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, - const int code_lengths[], int code_lengths_size) { +// sorted[code_lengths_size] is a pre-allocated array for sorting symbols +// by code length. +static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits, + const int code_lengths[], int code_lengths_size, + uint16_t sorted[]) { HuffmanCode* table = root_table; // next available space in table int total_size = 1 << root_bits; // total size root table + 2nd level table - int* sorted = NULL; // symbols sorted by code length int len; // current code length int symbol; // symbol index in original or sorted table // number of codes of each length: @@ -114,11 +116,6 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, offset[len + 1] = offset[len] + count[len]; } - sorted = (int*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted)); - if (sorted == NULL) { - return 0; - } - // Sort symbols by length, by symbol order within each length. for (symbol = 0; symbol < code_lengths_size; ++symbol) { const int symbol_code_length = code_lengths[symbol]; @@ -133,7 +130,6 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, code.bits = 0; code.value = (uint16_t)sorted[0]; ReplicateValue(table, 1, total_size, code); - WebPSafeFree(sorted); return total_size; } @@ -153,7 +149,6 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, num_nodes += num_open; num_open -= count[len]; if (num_open < 0) { - WebPSafeFree(sorted); return 0; } for (; count[len] > 0; --count[len]) { @@ -172,7 +167,6 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, num_nodes += num_open; num_open -= count[len]; if (num_open < 0) { - WebPSafeFree(sorted); return 0; } for (; count[len] > 0; --count[len]) { @@ -195,11 +189,35 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, // Check if tree is full. if (num_nodes != 2 * offset[MAX_ALLOWED_CODE_LENGTH] - 1) { - WebPSafeFree(sorted); return 0; } } - WebPSafeFree(sorted); + return total_size; +} + +// Maximum code_lengths_size is 2328 (reached for 11-bit color_cache_bits). +// More commonly, the value is around ~280. +#define MAX_CODE_LENGTHS_SIZE \ + ((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES) +// Cut-off value for switching between heap and stack allocation. +#define SORTED_SIZE_CUTOFF 512 +int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, + const int code_lengths[], int code_lengths_size) { + int total_size; + assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE); + if (code_lengths_size <= SORTED_SIZE_CUTOFF) { + // use local stack-allocated array. + uint16_t sorted[SORTED_SIZE_CUTOFF]; + total_size = BuildHuffmanTable(root_table, root_bits, + code_lengths, code_lengths_size, sorted); + } else { // rare case. Use heap allocation. + uint16_t* const sorted = + (uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted)); + if (sorted == NULL) return 0; + total_size = BuildHuffmanTable(root_table, root_bits, + code_lengths, code_lengths_size, sorted); + WebPSafeFree(sorted); + } return total_size; } diff --git a/src/3rdparty/libwebp/src/utils/huffman.h b/src/3rdparty/libwebp/src/utils/huffman_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/huffman.h rename to src/3rdparty/libwebp/src/utils/huffman_utils.h diff --git a/src/3rdparty/libwebp/src/utils/quant_levels_dec.c b/src/3rdparty/libwebp/src/utils/quant_levels_dec_utils.c similarity index 99% rename from src/3rdparty/libwebp/src/utils/quant_levels_dec.c rename to src/3rdparty/libwebp/src/utils/quant_levels_dec_utils.c index ee0a3fe127d26e3fe1d41fc96949516b73a8c5e8..d4d23d314723e5145c0017f65c19aeb026bc2f4b 100644 --- a/src/3rdparty/libwebp/src/utils/quant_levels_dec.c +++ b/src/3rdparty/libwebp/src/utils/quant_levels_dec_utils.c @@ -14,7 +14,7 @@ // // Author: Skal (pascal.massimino@gmail.com) -#include "./quant_levels_dec.h" +#include "./quant_levels_dec_utils.h" #include <string.h> // for memset diff --git a/src/3rdparty/libwebp/src/utils/quant_levels_dec.h b/src/3rdparty/libwebp/src/utils/quant_levels_dec_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/quant_levels_dec.h rename to src/3rdparty/libwebp/src/utils/quant_levels_dec_utils.h diff --git a/src/3rdparty/libwebp/src/utils/quant_levels.c b/src/3rdparty/libwebp/src/utils/quant_levels_utils.c similarity index 99% rename from src/3rdparty/libwebp/src/utils/quant_levels.c rename to src/3rdparty/libwebp/src/utils/quant_levels_utils.c index d7c8aab92212394b01a9a359b67ea15e93254fd0..73174e8ab9b102d5589d31c5d6d704e5e1f3dcab 100644 --- a/src/3rdparty/libwebp/src/utils/quant_levels.c +++ b/src/3rdparty/libwebp/src/utils/quant_levels_utils.c @@ -14,7 +14,7 @@ #include <assert.h> -#include "./quant_levels.h" +#include "./quant_levels_utils.h" #define NUM_SYMBOLS 256 diff --git a/src/3rdparty/libwebp/src/utils/quant_levels.h b/src/3rdparty/libwebp/src/utils/quant_levels_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/quant_levels.h rename to src/3rdparty/libwebp/src/utils/quant_levels_utils.h diff --git a/src/3rdparty/libwebp/src/utils/random.c b/src/3rdparty/libwebp/src/utils/random_utils.c similarity index 98% rename from src/3rdparty/libwebp/src/utils/random.c rename to src/3rdparty/libwebp/src/utils/random_utils.c index 24e96ad648b9c1a7fa303e4a4eccc431c8821d26..9f1e4154a6682793d8bb1ea1571a6fb41c61335e 100644 --- a/src/3rdparty/libwebp/src/utils/random.c +++ b/src/3rdparty/libwebp/src/utils/random_utils.c @@ -12,7 +12,7 @@ // Author: Skal (pascal.massimino@gmail.com) #include <string.h> -#include "./random.h" +#include "./random_utils.h" //------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/utils/random.h b/src/3rdparty/libwebp/src/utils/random_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/random.h rename to src/3rdparty/libwebp/src/utils/random_utils.h diff --git a/src/3rdparty/libwebp/src/utils/rescaler.c b/src/3rdparty/libwebp/src/utils/rescaler_utils.c similarity index 91% rename from src/3rdparty/libwebp/src/utils/rescaler.c rename to src/3rdparty/libwebp/src/utils/rescaler_utils.c index 00c9300bfbdd5009e88f87e45b9a59f158584884..0d1f80da240dce75cb428d18a62267f3cf095940 100644 --- a/src/3rdparty/libwebp/src/utils/rescaler.c +++ b/src/3rdparty/libwebp/src/utils/rescaler_utils.c @@ -15,7 +15,7 @@ #include <stdlib.h> #include <string.h> #include "../dsp/dsp.h" -#include "./rescaler.h" +#include "./rescaler_utils.h" //------------------------------------------------------------------------------ @@ -48,11 +48,15 @@ void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, wrk->y_sub = wrk->y_expand ? y_sub - 1 : y_sub; wrk->y_accum = wrk->y_expand ? wrk->y_sub : wrk->y_add; if (!wrk->y_expand) { - // this is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast. + // This is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast. + // Its value is <= WEBP_RESCALER_ONE, because dst_height <= wrk->y_add, and + // wrk->x_add >= 1; const uint64_t ratio = (uint64_t)dst_height * WEBP_RESCALER_ONE / (wrk->x_add * wrk->y_add); if (ratio != (uint32_t)ratio) { - // We can't represent the ratio with the current fixed-point precision. + // When ratio == WEBP_RESCALER_ONE, we can't represent the ratio with the + // current fixed-point precision. This happens when src_height == + // wrk->y_add (which == src_height), and wrk->x_add == 1. // => We special-case fxy_scale = 0, in WebPRescalerExportRow(). wrk->fxy_scale = 0; } else { diff --git a/src/3rdparty/libwebp/src/utils/rescaler.h b/src/3rdparty/libwebp/src/utils/rescaler_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/rescaler.h rename to src/3rdparty/libwebp/src/utils/rescaler_utils.h diff --git a/src/3rdparty/libwebp/src/utils/thread.c b/src/3rdparty/libwebp/src/utils/thread_utils.c similarity index 98% rename from src/3rdparty/libwebp/src/utils/thread.c rename to src/3rdparty/libwebp/src/utils/thread_utils.c index 93f7622797f05f6acc1126e8296c481d276e4047..1729060c704bb7a6937ad7c6d2b6647da9ce8eb9 100644 --- a/src/3rdparty/libwebp/src/utils/thread.c +++ b/src/3rdparty/libwebp/src/utils/thread_utils.c @@ -13,7 +13,7 @@ #include <assert.h> #include <string.h> // for memset() -#include "./thread.h" +#include "./thread_utils.h" #include "./utils.h" #ifdef WEBP_USE_THREAD @@ -183,8 +183,7 @@ static int pthread_cond_wait(pthread_cond_t* const condition, #else // note that there is a consumer available so the signal isn't dropped in // pthread_cond_signal - if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) - return 1; + if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) return 1; // now unlock the mutex so pthread_cond_signal may be issued pthread_mutex_unlock(mutex); ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == @@ -226,8 +225,7 @@ static THREADFN ThreadLoop(void* ptr) { } // main thread state control -static void ChangeState(WebPWorker* const worker, - WebPWorkerStatus new_status) { +static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) { // No-op when attempting to change state on a thread that didn't come up. // Checking status_ without acquiring the lock first would result in a data // race. diff --git a/src/3rdparty/libwebp/src/utils/thread.h b/src/3rdparty/libwebp/src/utils/thread_utils.h similarity index 100% rename from src/3rdparty/libwebp/src/utils/thread.h rename to src/3rdparty/libwebp/src/utils/thread_utils.h diff --git a/src/3rdparty/libwebp/src/utils/utils.c b/src/3rdparty/libwebp/src/utils/utils.c index 2602ca3c9f6e4fee63010b8beea6c5499e5869c6..504d924b6062f20e93e895e3ab5abde4f7eb1dec 100644 --- a/src/3rdparty/libwebp/src/utils/utils.c +++ b/src/3rdparty/libwebp/src/utils/utils.c @@ -25,7 +25,7 @@ // http://valgrind.org/docs/manual/ms-manual.html // Here is an example command line: /* valgrind --tool=massif --massif-out-file=massif.out \ - --stacks=yes --alloc-fn=WebPSafeAlloc --alloc-fn=WebPSafeCalloc + --stacks=yes --alloc-fn=WebPSafeMalloc --alloc-fn=WebPSafeCalloc ms_print massif.out */ // In addition: @@ -175,8 +175,12 @@ static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) { } #endif #if defined(MALLOC_LIMIT) - if (mem_limit > 0 && total_mem + total_size >= mem_limit) { - return 0; // fake fail! + if (mem_limit > 0) { + const uint64_t new_total_mem = (uint64_t)total_mem + total_size; + if (new_total_mem != (size_t)new_total_mem || + new_total_mem > mem_limit) { + return 0; // fake fail! + } } #endif @@ -239,8 +243,7 @@ void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) { //------------------------------------------------------------------------------ -#define MAX_COLOR_COUNT MAX_PALETTE_SIZE -#define COLOR_HASH_SIZE (MAX_COLOR_COUNT * 4) +#define COLOR_HASH_SIZE (MAX_PALETTE_SIZE * 4) #define COLOR_HASH_RIGHT_SHIFT 22 // 32 - log2(COLOR_HASH_SIZE). int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) { @@ -249,7 +252,7 @@ int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) { int num_colors = 0; uint8_t in_use[COLOR_HASH_SIZE] = { 0 }; uint32_t colors[COLOR_HASH_SIZE]; - static const uint32_t kHashMul = 0x1e35a7bdU; + static const uint64_t kHashMul = 0x1e35a7bdull; const uint32_t* argb = pic->argb; const int width = pic->width; const int height = pic->height; @@ -264,14 +267,14 @@ int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) { continue; } last_pix = argb[x]; - key = (kHashMul * last_pix) >> COLOR_HASH_RIGHT_SHIFT; + key = ((last_pix * kHashMul) & 0xffffffffu) >> COLOR_HASH_RIGHT_SHIFT; while (1) { if (!in_use[key]) { colors[key] = last_pix; in_use[key] = 1; ++num_colors; - if (num_colors > MAX_COLOR_COUNT) { - return MAX_COLOR_COUNT + 1; // Exact count not needed. + if (num_colors > MAX_PALETTE_SIZE) { + return MAX_PALETTE_SIZE + 1; // Exact count not needed. } break; } else if (colors[key] == last_pix) { @@ -298,8 +301,30 @@ int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) { return num_colors; } -#undef MAX_COLOR_COUNT #undef COLOR_HASH_SIZE #undef COLOR_HASH_RIGHT_SHIFT //------------------------------------------------------------------------------ + +#if defined(WEBP_NEED_LOG_TABLE_8BIT) +const uint8_t WebPLogTable8bit[256] = { // 31 ^ clz(i) + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; +#endif + +//------------------------------------------------------------------------------ diff --git a/src/3rdparty/libwebp/src/utils/utils.h b/src/3rdparty/libwebp/src/utils/utils.h index e0a81126df8e703b10cf529b2a89c610573c0b93..3ab459050aaf0d4a49a38f3a3db53eaddfb70c49 100644 --- a/src/3rdparty/libwebp/src/utils/utils.h +++ b/src/3rdparty/libwebp/src/utils/utils.h @@ -20,6 +20,7 @@ #endif #include <assert.h> +#include <limits.h> #include "../dsp/dsp.h" #include "../webp/types.h" @@ -32,7 +33,14 @@ extern "C" { // Memory allocation // This is the maximum memory amount that libwebp will ever try to allocate. -#define WEBP_MAX_ALLOCABLE_MEMORY (1ULL << 40) +#ifndef WEBP_MAX_ALLOCABLE_MEMORY +#if SIZE_MAX > (1ULL << 34) +#define WEBP_MAX_ALLOCABLE_MEMORY (1ULL << 34) +#else +// For 32-bit targets keep this below INT_MAX to avoid valgrind warnings. +#define WEBP_MAX_ALLOCABLE_MEMORY ((1ULL << 31) - (1 << 16)) +#endif +#endif // WEBP_MAX_ALLOCABLE_MEMORY // size-checking safe malloc/calloc: verify that the requested size is not too // large, or return NULL. You don't need to call these for constructs like @@ -54,7 +62,6 @@ WEBP_EXTERN(void) WebPSafeFree(void* const ptr); #define WEBP_ALIGN_CST 31 #define WEBP_ALIGN(PTR) (((uintptr_t)(PTR) + WEBP_ALIGN_CST) & ~WEBP_ALIGN_CST) -#if defined(WEBP_FORCE_ALIGNED) #include <string.h> // memcpy() is the safe way of moving potentially unaligned 32b memory. static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) { @@ -65,16 +72,6 @@ static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) { static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) { memcpy(ptr, &val, sizeof(val)); } -#else -static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE -uint32_t WebPMemToUint32(const uint8_t* const ptr) { - return *(const uint32_t*)ptr; -} -static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE -void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) { - *(uint32_t*)ptr = val; -} -#endif //------------------------------------------------------------------------------ // Reading/writing data. @@ -110,6 +107,19 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) { 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 = 0; + while (n >= 256) { + log += 8; + n >>= 8; + } + return log + WebPLogTable8bit[n]; +} + // Returns (int)floor(log2(n)). n must be > 0. // use GNU builtins where available. #if defined(__GNUC__) && \ @@ -127,22 +137,8 @@ static WEBP_INLINE int BitsLog2Floor(uint32_t n) { _BitScanReverse(&first_set_bit, n); return first_set_bit; } -#else -static WEBP_INLINE int BitsLog2Floor(uint32_t n) { - int log = 0; - uint32_t value = n; - int i; - - for (i = 4; i >= 0; --i) { - const int shift = (1 << i); - const uint32_t x = value >> shift; - if (x != 0) { - value = x; - log += shift; - } - } - return log; -} +#else // default: use the C-version. +static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); } #endif //------------------------------------------------------------------------------ @@ -164,12 +160,12 @@ WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src, // Unique colors. // Returns count of unique colors in 'pic', assuming pic->use_argb is true. -// If the unique color count is more than MAX_COLOR_COUNT, returns -// MAX_COLOR_COUNT+1. +// If the unique color count is more than MAX_PALETTE_SIZE, returns +// MAX_PALETTE_SIZE+1. // If 'palette' is not NULL and number of unique colors is less than or equal to -// MAX_COLOR_COUNT, also outputs the actual unique colors into 'palette'. +// MAX_PALETTE_SIZE, also outputs the actual unique colors into 'palette'. // Note: 'palette' is assumed to be an array already allocated with at least -// MAX_COLOR_COUNT elements. +// MAX_PALETTE_SIZE elements. WEBP_EXTERN(int) WebPGetColorPalette(const struct WebPPicture* const pic, uint32_t* const palette); diff --git a/src/3rdparty/libwebp/src/webp/config.h b/src/3rdparty/libwebp/src/webp/config.h index 118ac382af51d8adc2a4dda9feed0573601625f0..731115bc9de4239107c36e61d1036043463a58ec 100644 --- a/src/3rdparty/libwebp/src/webp/config.h +++ b/src/3rdparty/libwebp/src/webp/config.h @@ -79,7 +79,7 @@ #define PACKAGE_NAME "libwebp" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libwebp 0.5.1" +#define PACKAGE_STRING "libwebp 0.6.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libwebp" @@ -88,7 +88,7 @@ #define PACKAGE_URL "http://developers.google.com/speed/webp" /* Define to the version of this package. */ -#define PACKAGE_VERSION "0.5.1" +#define PACKAGE_VERSION "0.6.0" /* Define to necessary symbol if this constant uses a non-standard name on your system. */ @@ -98,7 +98,7 @@ /* #undef STDC_HEADERS */ /* Version number of package */ -#define VERSION "0.5.1" +#define VERSION "0.6.0" /* Enable experimental code */ /* #undef WEBP_EXPERIMENTAL_FEATURES */ diff --git a/src/3rdparty/libwebp/src/webp/decode.h b/src/3rdparty/libwebp/src/webp/decode.h index 7a3bed93a4e1201f1425a031af9058458835a5c7..4c5e74ac3693cb0621ad5b6c31d2590fc78b05a5 100644 --- a/src/3rdparty/libwebp/src/webp/decode.h +++ b/src/3rdparty/libwebp/src/webp/decode.h @@ -248,19 +248,19 @@ typedef enum VP8StatusCode { // picture is only partially decoded, pending additional input. // Code example: // -// WebPInitDecBuffer(&buffer); -// buffer.colorspace = mode; +// WebPInitDecBuffer(&output_buffer); +// output_buffer.colorspace = mode; // ... -// WebPIDecoder* idec = WebPINewDecoder(&buffer); -// while (has_more_data) { -// // ... (get additional data) +// WebPIDecoder* idec = WebPINewDecoder(&output_buffer); +// while (additional_data_is_available) { +// // ... (get additional data in some new_data[] buffer) // status = WebPIAppend(idec, new_data, new_data_size); -// if (status != VP8_STATUS_SUSPENDED || -// break; +// if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) { +// break; // an error occurred. // } // // // The above call decodes the current available buffer. -// // Part of the image can now be refreshed by calling to +// // Part of the image can now be refreshed by calling // // WebPIDecGetRGB()/WebPIDecGetYUVA() etc. // } // WebPIDelete(idec); diff --git a/src/3rdparty/libwebp/src/webp/encode.h b/src/3rdparty/libwebp/src/webp/encode.h index 9291b7195c2acc1e110c47e8bf38f8b64f0a26ee..35fde1d052713d418b684fadc3230ac7e8d0e9df 100644 --- a/src/3rdparty/libwebp/src/webp/encode.h +++ b/src/3rdparty/libwebp/src/webp/encode.h @@ -20,7 +20,7 @@ extern "C" { #endif -#define WEBP_ENCODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b) +#define WEBP_ENCODER_ABI_VERSION 0x020e // MAJOR(8b) + MINOR(8b) // Note: forward declaring enumerations is not allowed in (strict) C and C++, // the types are left here for reference. @@ -141,12 +141,10 @@ struct WebPConfig { // RGB information for better compression. The default // value is 0. -#ifdef WEBP_EXPERIMENTAL_FEATURES - int delta_palettization; + int use_delta_palette; // reserved for future lossless feature + int use_sharp_yuv; // if needed, use sharp (and slow) RGB->YUV conversion + uint32_t pad[2]; // padding for later use -#else - uint32_t pad[3]; // padding for later use -#endif // WEBP_EXPERIMENTAL_FEATURES }; // Enumerate some predefined settings for WebPConfig, depending on the type @@ -388,9 +386,24 @@ WEBP_EXTERN(void) WebPPictureFree(WebPPicture* picture); // Returns false in case of memory allocation error. WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* src, WebPPicture* dst); +// Compute the single distortion for packed planes of samples. +// 'src' will be compared to 'ref', and the raw distortion stored into +// '*distortion'. The refined metric (log(MSE), log(1 - ssim),...' will be +// stored in '*result'. +// 'x_step' is the horizontal stride (in bytes) between samples. +// 'src/ref_stride' is the byte distance between rows. +// Returns false in case of error (bad parameter, memory allocation error, ...). +WEBP_EXTERN(int) WebPPlaneDistortion(const uint8_t* src, size_t src_stride, + const uint8_t* ref, size_t ref_stride, + int width, int height, + size_t x_step, + int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM + float* distortion, float* result); + // Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results -// are in dB, stored in result[] in the Y/U/V/Alpha/All or B/G/R/A/All order. -// Returns false in case of error (src and ref don't have same dimension, ...) +// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is +// always performed using ARGB samples. Hence if the input is YUV(A), the +// picture will be internally converted to ARGB (just for the measurement). // Warning: this function is rather CPU-intensive. WEBP_EXTERN(int) WebPPictureDistortion( const WebPPicture* src, const WebPPicture* ref, @@ -473,18 +486,20 @@ WEBP_EXTERN(int) WebPPictureARGBToYUVA(WebPPicture* picture, WEBP_EXTERN(int) WebPPictureARGBToYUVADithered( WebPPicture* picture, WebPEncCSP colorspace, float dithering); -// Performs 'smart' RGBA->YUVA420 downsampling and colorspace conversion. +// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion. // Downsampling is handled with extra care in case of color clipping. This // method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better -// YUV representation. +// and sharper YUV representation. // Returns false in case of error. +WEBP_EXTERN(int) WebPPictureSharpARGBToYUVA(WebPPicture* picture); +// kept for backward compatibility: WEBP_EXTERN(int) WebPPictureSmartARGBToYUVA(WebPPicture* picture); // Converts picture->yuv to picture->argb and sets picture->use_argb to true. -// The input format must be YUV_420 or YUV_420A. -// Note that the use of this method is discouraged if one has access to the -// raw ARGB samples, since using YUV420 is comparatively lossy. Also, the -// conversion from YUV420 to ARGB incurs a small loss too. +// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to +// ARGB incurs a small loss too. +// Note that the use of this colorspace is discouraged if one has access to the +// raw ARGB samples, since using YUV420 is comparatively lossy. // Returns false in case of error. WEBP_EXTERN(int) WebPPictureYUVAToARGB(WebPPicture* picture); diff --git a/src/3rdparty/libwebp/src/webp/extras.h b/src/3rdparty/libwebp/src/webp/extras.h deleted file mode 100644 index 1c24be2e0c1fc77b107e56bf7ecf12f69944d8b5..0000000000000000000000000000000000000000 --- a/src/3rdparty/libwebp/src/webp/extras.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 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_WEBP_EXTRAS_H_ -#define WEBP_WEBP_EXTRAS_H_ - -#include "./types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include "./encode.h" - -#define WEBP_EXTRAS_ABI_VERSION 0x0000 // MAJOR(8b) + MINOR(8b) - -//------------------------------------------------------------------------------ - -// Returns the version number of the extras library, packed in hexadecimal using -// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507. -WEBP_EXTERN(int) WebPGetExtrasVersion(void); - -//------------------------------------------------------------------------------ -// Ad-hoc colorspace importers. - -// Import luma sample (gray scale image) into 'picture'. The 'picture' -// width and height must be set prior to calling this function. -WEBP_EXTERN(int) WebPImportGray(const uint8_t* gray, WebPPicture* picture); - -// Import rgb sample in RGB565 packed format into 'picture'. The 'picture' -// width and height must be set prior to calling this function. -WEBP_EXTERN(int) WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic); - -// Import rgb sample in RGB4444 packed format into 'picture'. The 'picture' -// width and height must be set prior to calling this function. -WEBP_EXTERN(int) WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic); - -//------------------------------------------------------------------------------ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif /* WEBP_WEBP_EXTRAS_H_ */ diff --git a/src/3rdparty/libwebp/src/webp/format_constants.h b/src/3rdparty/libwebp/src/webp/format_constants.h index b6e78a643ed0b4368fabf14639ddae673666695d..329fc8a3b04dd6b59807fcf5f643564ffb8b091c 100644 --- a/src/3rdparty/libwebp/src/webp/format_constants.h +++ b/src/3rdparty/libwebp/src/webp/format_constants.h @@ -72,14 +72,13 @@ typedef enum { #define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP"). #define ANMF_CHUNK_SIZE 16 // Size of an ANMF chunk. #define ANIM_CHUNK_SIZE 6 // Size of an ANIM chunk. -#define FRGM_CHUNK_SIZE 6 // Size of a FRGM chunk. #define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk. #define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height. #define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. #define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count #define MAX_DURATION (1 << 24) // maximum duration -#define MAX_POSITION_OFFSET (1 << 24) // maximum frame/fragment x/y offset +#define MAX_POSITION_OFFSET (1 << 24) // maximum frame x/y offset // Maximum chunk payload is such that adding the header and padding won't // overflow a uint32_t. diff --git a/src/3rdparty/libwebp/src/webp/mux.h b/src/3rdparty/libwebp/src/webp/mux.h index b72658c7411aa34113121ce74282fa59671afd8b..daccc65e8692180b06bc34ff84068fb529418f42 100644 --- a/src/3rdparty/libwebp/src/webp/mux.h +++ b/src/3rdparty/libwebp/src/webp/mux.h @@ -21,13 +21,13 @@ extern "C" { #endif -#define WEBP_MUX_ABI_VERSION 0x0106 // MAJOR(8b) + MINOR(8b) +#define WEBP_MUX_ABI_VERSION 0x0108 // MAJOR(8b) + MINOR(8b) //------------------------------------------------------------------------------ // Mux API // // This API allows manipulation of WebP container images containing features -// like color profile, metadata, animation and fragmented images. +// like color profile, metadata, animation. // // Code Example#1: Create a WebPMux object with image data, color profile and // XMP metadata. @@ -81,16 +81,16 @@ typedef enum WebPMuxError { // IDs for different types of chunks. typedef enum WebPChunkId { - WEBP_CHUNK_VP8X, // VP8X - WEBP_CHUNK_ICCP, // ICCP - WEBP_CHUNK_ANIM, // ANIM - WEBP_CHUNK_ANMF, // ANMF - WEBP_CHUNK_FRGM, // FRGM - WEBP_CHUNK_ALPHA, // ALPH - WEBP_CHUNK_IMAGE, // VP8/VP8L - WEBP_CHUNK_EXIF, // EXIF - WEBP_CHUNK_XMP, // XMP - WEBP_CHUNK_UNKNOWN, // Other chunks. + WEBP_CHUNK_VP8X, // VP8X + WEBP_CHUNK_ICCP, // ICCP + WEBP_CHUNK_ANIM, // ANIM + WEBP_CHUNK_ANMF, // ANMF + WEBP_CHUNK_DEPRECATED, // (deprecated from FRGM) + WEBP_CHUNK_ALPHA, // ALPH + WEBP_CHUNK_IMAGE, // VP8/VP8L + WEBP_CHUNK_EXIF, // EXIF + WEBP_CHUNK_XMP, // XMP + WEBP_CHUNK_UNKNOWN, // Other chunks. WEBP_CHUNK_NIL } WebPChunkId; @@ -142,7 +142,7 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream, // Non-image chunks. // Note: Only non-image related chunks should be managed through chunk APIs. -// (Image related chunks are: "ANMF", "FRGM", "VP8 ", "VP8L" and "ALPH"). +// (Image related chunks are: "ANMF", "VP8 ", "VP8L" and "ALPH"). // To add, get and delete images, use WebPMuxSetImage(), WebPMuxPushFrame(), // WebPMuxGetFrame() and WebPMuxDeleteFrame(). @@ -195,7 +195,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteChunk( //------------------------------------------------------------------------------ // Images. -// Encapsulates data about a single frame/fragment. +// Encapsulates data about a single frame. struct WebPMuxFrameInfo { WebPData bitstream; // image data: can be a raw VP8/VP8L bitstream // or a single-image WebP file. @@ -203,19 +203,19 @@ struct WebPMuxFrameInfo { int y_offset; // y-offset of the frame. int duration; // duration of the frame (in milliseconds). - WebPChunkId id; // frame type: should be one of WEBP_CHUNK_ANMF, - // WEBP_CHUNK_FRGM or WEBP_CHUNK_IMAGE + WebPChunkId id; // frame type: should be one of WEBP_CHUNK_ANMF + // or WEBP_CHUNK_IMAGE WebPMuxAnimDispose dispose_method; // Disposal method for the frame. WebPMuxAnimBlend blend_method; // Blend operation for the frame. uint32_t pad[1]; // padding for later use }; -// Sets the (non-animated and non-fragmented) image in the mux object. -// Note: Any existing images (including frames/fragments) will be removed. +// Sets the (non-animated) image in the mux object. +// Note: Any existing images (including frames) will be removed. // Parameters: // mux - (in/out) object in which the image is to be set // bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image -// WebP file (non-animated and non-fragmented) +// WebP file (non-animated) // copy_data - (in) value 1 indicates given data WILL be copied to the mux // object and value 0 indicates data will NOT be copied. // Returns: @@ -226,9 +226,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetImage( WebPMux* mux, const WebPData* bitstream, int copy_data); // Adds a frame at the end of the mux object. -// Notes: (1) frame.id should be one of WEBP_CHUNK_ANMF or WEBP_CHUNK_FRGM -// (2) For setting a non-animated non-fragmented image, use -// WebPMuxSetImage() instead. +// Notes: (1) frame.id should be WEBP_CHUNK_ANMF +// (2) For setting a non-animated image, use WebPMuxSetImage() instead. // (3) Type of frame being pushed must be same as the frames in mux. // (4) As WebP only supports even offsets, any odd offset will be snapped // to an even location using: offset &= ~1 @@ -431,9 +430,10 @@ struct WebPAnimEncoderOptions { // frames in the output. The library may insert some key // frames as needed to satisfy this criteria. // Note that these conditions should hold: kmax > kmin - // and kmin >= kmax / 2 + 1. Also, if kmin == 0, then - // key-frame insertion is disabled; and if kmax == 0, - // then all frames will be key-frames. + // and kmin >= kmax / 2 + 1. Also, if kmax <= 0, then + // key-frame insertion is disabled; and if kmax == 1, + // then all frames will be key-frames (kmin value does + // not matter for these special cases). int allow_mixed; // If true, use mixed compression mode; may choose // either lossy and lossless for each frame. int verbose; // If true, print info and warning messages to stderr. diff --git a/src/3rdparty/libwebp/src/webp/mux_types.h b/src/3rdparty/libwebp/src/webp/mux_types.h index c94043a3c025e9c278b764e5bf6ed46add751f84..b37e2c67aaaea3b32501feca07e466b9cfda9ba7 100644 --- a/src/3rdparty/libwebp/src/webp/mux_types.h +++ b/src/3rdparty/libwebp/src/webp/mux_types.h @@ -31,12 +31,13 @@ typedef struct WebPData WebPData; // VP8X Feature Flags. typedef enum WebPFeatureFlags { - FRAGMENTS_FLAG = 0x00000001, ANIMATION_FLAG = 0x00000002, XMP_FLAG = 0x00000004, EXIF_FLAG = 0x00000008, ALPHA_FLAG = 0x00000010, - ICCP_FLAG = 0x00000020 + ICCP_FLAG = 0x00000020, + + ALL_VALID_FLAGS = 0x0000003e } WebPFeatureFlags; // Dispose method (animation only). Indicates how the area used by the current