Compare commits

..

1525 Commits

Author SHA1 Message Date
68e7901da5 update ChangeLog
Change-Id: If51472e72adaec0a198a8b09becb8be192153ca8
2013-12-20 00:49:40 -08:00
256e4333e1 update NEWS description with new general features
Change-Id: I22be12d843e84f80965dc5f2cb16ba2475ce16ad
2013-12-20 00:36:47 -08:00
296253407c Merge "gif2webp: don't use C99 %zu" into 0.4.0 2013-12-20 00:06:33 -08:00
3b9f9dd07b gif2webp: don't use C99 %zu
this would require a PRIuS or similar macro for proper platform
compatibility (Visual Studio for instance would be variants of %lu)

Change-Id: I2b9fcb1639db024775fb47dbcf79a2240f3d98f2
2013-12-19 18:52:48 -08:00
b5b2e3c7f5 cwebp: fix metadata output w/lossy+alpha
Change-Id: Ic96da6523fc73a7b67c68ef8a4c9d12081f8a535
2013-12-19 10:17:08 -08:00
ad26df1a05 makefile.unix: clean up libgif2webp_util.a
Change-Id: Iee8650ce91f65f2db568926773d44441633459f3
2013-12-18 23:26:18 -08:00
c3b4557064 update Changelog
Change-Id: I60525ce8dedf0843578c1881f6e140098e01211c
2013-12-18 19:36:44 -08:00
ca84112120 Merge "bump version to 0.4.0" into 0.4.0 2013-12-18 19:33:24 -08:00
8c524db84c bump version to 0.4.0
libwebp{,decoder} - 0.4.0
libwebp libtool - 5.0.0
libwebpdecoder libtool - 1.0.0

mux/demux - 0.2.0
libtool - 1.0.0

Change-Id: Idbd067f95a6af2f0057d6a63ab43176fcdbb767d
2013-12-18 19:20:00 -08:00
eec2398cec update AUTHORS & .mailmap
Change-Id: I5419731cd7ac6a06e42ef12433286a97e8e13bb4
2013-12-18 19:09:11 -08:00
b9bbf6a1a0 update NEWS for 0.4.0
Change-Id: I90327d5169b1dba8245c427a03064d562aa26cc9
2013-12-18 19:05:46 -08:00
c72e08119a Merge "dec/webp.c: don't wait for data before reporting w/h" 2013-12-18 18:47:43 -08:00
5ad653145a dec/frame.c: fix formatting
since 26d842e NEON speed up

+ drop a duplicate and from a comment

Change-Id: I710f46f83b80161064910c7efc16788b88c089fe
2013-12-18 17:16:31 -08:00
f7fc4bc89b dec/webp.c: don't wait for data before reporting w/h
this partially reverts
f626fe2 Detect canvas and image size mismatch in decoder.

the original change would cause calls to e.g., WebPGetInfo to fail until
a portion of the image chunk was available. With lossy+alpha this meant
waiting for the entire ALPH chunk to be received.
this change restores the original behavior -- reporting the values from
VP8X if available -- while retaining some of the added canvas/image size
checks if the image data is available

Change-Id: I6295b00a2e2d0d4d8847371756af347e4a80bc0e
2013-12-18 17:09:04 -08:00
66a32af5e1 Merge "NEON speed up" 2013-12-18 14:17:19 -08:00
26d842eb8f NEON speed up
add TransformDC special case, and make the switch function inlined.
Recovers a few of the CPU lost during the addition of TransformAC3
(only on ARM)

Change-Id: I21c1f0c6a9cb9d1dfc1e307b4f473a2791273bd6
2013-12-18 22:32:58 +01:00
f307f98b21 Merge "webpmux: let -- stop parameter parsing" 2013-12-18 11:05:43 -08:00
fe051da772 Merge "README: add a section on gif2webp" 2013-12-18 11:02:55 -08:00
6fd2bd626f Merge "manpage pedantry" 2013-12-18 10:57:27 -08:00
4af19007a4 README: add a section on gif2webp
Change-Id: Ie701da16223df7482f7b017150242ba2d381d0b5
2013-12-18 10:49:49 -08:00
6f36ade926 manpage pedantry
from man-pages (7):
provides a comma-separated list of related man pages, ordered by section
number and then alphabetically by name, possibly followed by other
related pages or documents. Do not terminate this with a period.

Change-Id: I6763b3b3a89f3c2e9ed5c1a4e9d05fb9ce85dd40
2013-12-17 23:30:34 -08:00
f9016cb964 README: update dwebp options
Change-Id: I25300e374215578d091557380ce3dc599d58bd49
2013-12-17 21:51:41 -08:00
b4fa0a47ea webpmux: let -- stop parameter parsing
this enables webpmux to accept input files starting with '-' when using
-get/-set/-strip; -info & -frame expect an input file as one of their
parameters so no changes are necessary there.

Change-Id: I154eb6dc388258a7fb743ec76ba869bf9589be1b
2013-12-17 20:50:46 -08:00
a9a20acfa6 gif2webp: Add a multi-threaded encode option
Change-Id: If16a5f434e0ab2965a7ac9392633ecaf8c4aff46
2013-12-17 17:01:59 -08:00
495bef413d fix bug in TrellisQuantize
the *quantized* level should be clipped to 2047, not the
original coeff.
(similar problem was fixed in the regular quantize function
quite some time ago)

Change-Id: I2fd2f8d94561ff0204e60535321ab41a565e8f85
2013-12-17 11:08:01 -08:00
605a712701 simplify __cplusplus ifdef
drop c_plusplus which is from a quite ancient pre-standard compiler

Change-Id: I9e357b3292a6b52b14c2641ba11f4f872c04b7fb
2013-12-16 20:16:02 -08:00
33109f990a Merge "drop: ifdef __cplusplus checks from C files" 2013-12-16 20:13:09 -08:00
7f9de0b948 Merge changes I994a5587,I8467bb71,I13b50688,I1e2c9c7b
* changes:
  gif2webp: let -- stop parameter parsing
  vwebp: let -- stop parameter parsing
  cwebp: let -- stop parameter parsing
  dwebp: let -- stop parameter parsing
2013-12-16 16:53:27 -08:00
5459030be0 gif2webp: let -- stop parameter parsing
this enables gif2webp to accept input files starting with '-'

Change-Id: I994a5587e16e3af83ca45bfda8caf2dc39068b6c
2013-12-16 15:15:20 -08:00
a4b0aa06ee vwebp: let -- stop parameter parsing
this enables vwebp to accept input files starting with '-'

Change-Id: I8467bb719ba745b2aa14a5c5ce2ff392cd9601d5
2013-12-16 15:14:00 -08:00
98af68fe26 cwebp: let -- stop parameter parsing
this enables cwebp to accept input files starting with '-'

Change-Id: I13b506886c3df8a4e8fb350f3d365eaf7e072a4a
2013-12-16 15:13:54 -08:00
a33831e21a dwebp: let -- stop parameter parsing
this enables dwebp to accept input files starting with '-'

Change-Id: I1e2c9c7bc2963d77be039c99e72f744560f0b0a2
2013-12-16 15:13:32 -08:00
363012497b add some checks on error paths
malloc failure could lead to free'ing non-initialized pointers

Change-Id: I8156aac1fce9a47825cfd0d88eb2bd8c38a630d5
2013-12-16 13:33:45 -08:00
ce4c713904 Merge "autoconf: add --disable-wic" 2013-12-16 10:45:11 -08:00
5227d99146 drop: ifdef __cplusplus checks from C files
the prototypes are already marked in the headers

Change-Id: I172fe742200c939ca32a70a2299809b8baf9b094
2013-12-13 11:42:13 -08:00
f64535591c dwebp.1: fix typo
ICM4 -> IMC4

Change-Id: I065a1ac0dfd0b60efa782bc1a4df1adcb28b90e4
2013-12-12 20:38:23 -08:00
f91034f241 Merge "cwebp: print metadata stats when no output file is given" 2013-12-12 19:28:35 -08:00
d49345533f gif2webp: Backward compatibility for giflib version <= 4.1.3
Fixes https://code.google.com/p/webp/issues/detail?id=172

We use 'int' instead of 'GifWord', which was introduced in version
4.1.4.

Tested OK on 4.1.3
(http://sourceforge.net/projects/giflib/files/giflib-4.x/giflib%204.1.3/)
and 5.0.4

Change-Id: I77628b0f9175a91eb3a22e64fc55dd00633add1f
2013-12-11 08:46:38 -08:00
4c617d3286 gif2webp: Disable output of ICC profile by default
This is to discourage generation of animated WebP images with ICC
profile, as
the real-world use-case for such images is rare at best.

Output of ICC/XMP metadata is now controlled by the '-metadata' option.

Change-Id: I8e3e29878c32bf46cbc661f50661bac602603c43
2013-12-10 14:53:06 -08:00
73b731fb42 introduce a special quantization function for WHT
WHT is somewhat a special case: no sharpen[] bias, etc.
Will be useful in a later CL when precision of input is changed.

Change-Id: I851b06deb94abdfc1ef00acafb8aa731801b4299
2013-12-10 14:21:47 +01:00
41c0cc4b9a Make Forward WHT transform use 32bit fixed-point calculation
This is in preparation for a future change where input will
be 16bit instead of 12bit

No speed diff observed.

Note that the NEON implementation was using 32bit calc already.

Change-Id: If06935db5c56a77fc9cefcb2dec617483f5f62b4
2013-12-10 06:10:52 +01:00
a3359f5d2c Only compute quantization params once
(all quantization params #1..#15 are the same)

Change-Id: If04058bd89fe2677b5b118ee4e1bcce88f0e4bf5
2013-12-10 05:36:23 +01:00
7049043775 cwebp: print metadata stats when no output file is given
this is more consistent with the encode stats

Change-Id: I5793062b3b29f5cb891461d6faaa53b43c0a4482
2013-12-09 20:15:54 -08:00
d513bb62bc * fix off-by-one zthresh calculation
* remove the sharpening for non luma-AC coeffs
* adjust the bias a little bit to compensate for this

Using the multiply-by-reciprocal doesn't always give the same result
as the exact divide, given the QFIX fixed-point precision we use.
-> removed few now-unneeded SSE2 instructions (and checked for
bit-exactness using -noasm)

Change-Id: Ib68057cbdd69c4e589af56a01a8e7085db762c24
2013-12-09 13:56:04 +01:00
ad9dec0c24 Merge "cosmetics: dwebp: fix local function name format" 2013-12-07 13:38:54 -08:00
f737f0376a Merge "dwebp: remove a dead store" 2013-12-07 13:38:42 -08:00
3c3a70da6d Merge "makefile.unix: install binaries in $(DESTDIR)/bin/" 2013-12-07 13:38:28 -08:00
150b655f74 Merge "Android.mk: add some release compile flags" 2013-12-07 13:38:15 -08:00
dbebd33be7 cosmetics: dwebp: fix local function name format
error_function -> PNGErrorFunction

Change-Id: Ic6c0e676cc47bca2c1a1e0d8e95639e780982b1b
2013-12-07 13:26:05 -08:00
2774995185 dwebp: remove a dead store
Change-Id: I48205472e99e997702d25c39f1b4d7a4699c15d6
2013-12-07 13:22:22 -08:00
a01e04fee0 autoconf: add --disable-wic
this allows windows builds to prefer libjpeg, libpng etc. for import and
export

Change-Id: Ibe1648b68a3f7b5016044e82530843dea46a94a4
2013-12-07 11:56:34 -08:00
5009b22746 makefile.unix: install binaries in $(DESTDIR)/bin/
Change-Id: I6c8f87aaa185fc043b80800430d99deaa1e5966b
2013-12-06 20:40:12 -08:00
bab30fcab5 Merge "fix -print_psnr / ssim options" 2013-12-05 14:04:37 -08:00
ebef7fb307 fix -print_psnr / ssim options
original/compressed pictures were not converted to an adequate YUVA
colorspace before computing the distortion.

Change-Id: I37775e9b7dbd6eca16c38e235e1df325858d36a1
2013-12-05 14:03:59 -08:00
cb63785545 Merge "fix bug due to overzealous check in WebPPictureYUVAToARGB()" 2013-12-04 00:54:35 -08:00
8189885b6d Merge "EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE" 2013-12-03 23:32:41 -08:00
4ad7d33510 Android.mk: add some release compile flags
-ffunction-sections / -fdata-sections
can improve final binary size when used with --gc-sections, speed impact
untested

Change-Id: I37f4b5da2f34acede7965c2da2e1b97125473adc
2013-12-03 23:00:49 -08:00
c12e2369d8 cosmetics: fix a few typos
Change-Id: I73b1900b2d960c4c57ef7078df137c776b321a1b
2013-12-03 22:36:29 -08:00
6f104034a1 fix bug due to overzealous check in WebPPictureYUVAToARGB()
This tests prevented views to be converted to ARGB

https://code.google.com/p/webp/issues/detail?id=178

Change-Id: I5ba66da2791e6f1d2bfd8c55b5fffe6955263374
2013-12-02 15:23:12 +01:00
3f6c35c6f3 EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE
this change allows the code to be built with a C++ compiler without the
addition of an operator++

Change-Id: I2f2fae720b9772abfc3c540bb2e3bf9107d96cc9
2013-11-27 20:10:45 -08:00
cc55790e37 Merge changes I8bb7a4dc,I2c180051,I021a014f,I8a224a62
* changes:
  mux: add some missing casts
  enc/vp8l: add a missing cast
  idec: add some missing casts
  ErrorStatusLossless: correct return type
2013-11-27 17:06:35 -08:00
c536afb57b Merge "cosmetics: fix some typos" 2013-11-27 17:04:00 -08:00
cbdd3e6e53 add a -dither dithering option to the decoder
Even at high quality setting, the U/V quantizer step is limited
to 4 which can lead to banding on gradient.
This option allows to selectively apply some randomness to
potentially flattened-out U/V blocks and attenuate the banding.

This option is off by default in 'dwebp', but set to -dither 50
by default in 'vwebp'.

Note: depending on the number of blocks selectively dithered,
we can have up to a 10% slow-down in decoding speed it seems.

Change-Id: Icc2446007f33ddacb60b3a80a9e63f2d5ad162de
2013-11-27 00:57:51 -08:00
e812401299 Updated iosbuild.sh for XCode 5.x
Change-Id: I4bf545c4f394c28842cbb85ac70214d2e5477ae0
2013-11-26 20:08:02 -08:00
4931c3294b cosmetics: fix some typos
Change-Id: I0d6efebd817815139db5ae87236fd8911df4d53c
2013-11-26 19:21:14 -08:00
05aacf77c2 mux: add some missing casts
+ fix a return value
+ fix a param type

Change-Id: I8bb7a4dc4c76b11140f8693c909aeb10f660e6e5
2013-11-25 20:53:15 -08:00
617d93480e enc/vp8l: add a missing cast
Change-Id: I2c1800516eb4573ae2599866ace10017b865f23a
2013-11-25 20:48:13 -08:00
46db286572 idec: add some missing casts
Change-Id: I021a014f1f3a597f37ba8d9f4006c8cb4100723c
2013-11-25 20:47:35 -08:00
b524e3369c ErrorStatusLossless: correct return type
int -> VP8StatusCode

Change-Id: I8a224a622e98d401a6e401047780fa6b25cb0ae4
2013-11-25 20:45:53 -08:00
cb261f790f fix a descaling bug for vertical/horizontal U/V interpolation
RGBToU/V calls expects two extra precision bits, they were only
given one by SUM2H and SUM2H macros.

For rounding coherency, also changed SUM1 macro.

Change-Id: I05f96a46f5d4f17b830d0420eaf79b066cdf78d4
2013-11-19 11:24:09 +01:00
bcb3955c41 Merge changes I48968468,I181bc736
* changes:
  demux: split chunk parsing from ParseVP8X
  demux: add a tail pointer for chunks
2013-11-18 17:03:33 -08:00
73f52133a1 gif2webp: Add a mixed compression mode
When '-mixed' option is given, each frame would be heuristically chosen
to be
encoded using lossy or lossless compression.

The heuristic is based on the number of colors in the image:
- If num_colors <= 31, pick lossless compression
- If num_colors >= 194, pick lossy compression
- Otherwise, try both and pick the one that compresses better.

Change-Id: I908c73493ddc38e8db35b7b1959300569e6d3a97
2013-11-17 18:04:07 -08:00
6198715e89 demux: split chunk parsing from ParseVP8X
makes the header and chunk parsing portions slightly more digestible

Change-Id: I48968468b2529506b830e96a2f13e8d29976179b
2013-11-16 11:06:43 -08:00
d2e3f4e6b5 demux: add a tail pointer for chunks
a large number of non-frame chunks could slow the parse

Change-Id: I181bc73626e92263c3c5b2a6dc2bf6e6a0481d52
2013-11-16 10:57:09 -08:00
87cffcc3c9 demux: cosmetics: s/has_frames/is_animation/
animation matches the flag name
s/has_fragments/is_fragmented/ to match.

Change-Id: I86c834e19bab6db6610ea2ccf900ab3ebffafa8a
2013-11-16 10:32:56 -08:00
e18e66779b demux: strictly enforce the animation flag
if the flag is incorrectly set in a VP8L or VP8/ALPH single image file
the demux will now fail.

Change-Id: Id4d5f2d3f6922a29b442c5d3d0acbe3d679e468a
2013-11-14 16:01:36 -08:00
c4f39f4a31 demux: cosmetics: remove a useless break
+ reword a comment

Change-Id: I52b64abcde2c8322b59c594f2f75b509ed367bff
2013-11-13 21:08:07 -08:00
61cb884d79 demux: (non-exp) fail if the fragmented flag is set
otherwise make sure that all frames are marked as a fragment. there's
still some work to do with validation if fragments are expected to cover
the entire canvas.

Change-Id: Id59e95ac01b9340ba8c6039b0c3b65484b91c42f
2013-11-12 21:50:27 -08:00
ff379db317 few % speedup of lossless encoding
mostly visible for method 4 and up

Change-Id: I1561d871bc055ec5f7998eb193d927927d3f2add
2013-11-12 00:09:45 +01:00
df3649a287 remove all disabled code related to P-frames
it's drifting out of sync, and won't be used anyway...

Change-Id: I931b288e1c8480bf3bccd685b3a356bb6bd8e10b
2013-11-04 11:52:05 +01:00
6d0cb3debf Merge "gif2webp: kmin = 0 should suppress key-frame addition." 2013-11-01 12:22:26 -07:00
36555983f0 gif2webp: kmin = 0 should suppress key-frame addition.
This is to conform to man/gif2webp.1
Earlier, one needed to give both '-kmin 0' and '-kmax 0' for this to
work.

Also, suppress further warnings for kmin = 0 and/or kmax = 0 case.

Change-Id: I6f5eeb609aeffc159d0252a40a5734162f7e4e7d
2013-11-01 12:01:59 -07:00
7708e60908 Merge "detect flatness in blocks and favor DC prediction" 2013-11-01 11:24:09 -07:00
06b1503eff Merge "add comment about the kLevelsFromDelta[][] LUT generation" 2013-10-31 21:37:55 -07:00
5935259cd0 add comment about the kLevelsFromDelta[][] LUT generation
Change-Id: Id1a91932bf05aeee421761667af351ef2200c334
2013-10-31 21:35:55 -07:00
e3312ea681 detect flatness in blocks and favor DC prediction
this avoids local-minima that look bad, even if the distortion
looks low (e.g. gradients, sky,...). Mostly visible in the q=50-80 range.
Output size is mostly unchanged.

Change-Id: I425b600ec45420db409911367cda375870bc2c63
2013-11-01 00:47:04 +01:00
ebc9b1eedf Merge "VPLBitReader bugfix: Catch error if bit_pos > LBITS too." 2013-10-31 16:38:15 -07:00
96ad0e0aef VPLBitReader bugfix: Catch error if bit_pos > LBITS too.
Earlier we were only testing for bit_pos == LBITS. But this is not
sufficient,
as bit_pos can jump from < LBITS to > LBITS.

This was resulting in some bit-stream truncation errors not being
caught.

Note: Not a security bug though, as br->pos wasn't incremented in such
cases
and so we weren't reading beyond the buffer.

Change-Id: Idadcdcbc6a5713f8fac3470f907fa37a63074836
2013-10-30 16:33:36 -07:00
a014e9c9cd tune quantization biases toward higher precision
* raise U/V quantization bias to more neutral values
* also raise the non-zero AC bias for Y1/Y2 matrices

(we need all the precision we can for U/V leves, which are often empty)
This will increase quality in the higher range (q >= 90) mostly.
Files size is exacted to raise a little (5-7%). and SSIM accordingly of course.

Change-Id: I8a9ffdb6d8fb6dadb959e3fd392e66dc5aaed64e
2013-10-30 23:57:23 +01:00
1e898619cb add helpful PrintBlockInfo() function
(protected under a DEBUG_BLOCK compile flag)

Change-Id: Icb8da02dbd00e5cf856c314943c212f1c9578d9b
2013-10-30 19:25:27 +01:00
596a6d73ce make use of 'extern' consistent in function declarations
Change-Id: I18e050db3111e52acfe97da09cdf1860f3e15936
2013-10-30 03:23:21 -07:00
c8d48c6e0d Merge "extract random utils to their own file util/random.[ch]" 2013-10-30 02:07:28 -07:00
98aa33cf1e extract random utils to their own file util/random.[ch]
they'll be used for decoding too, probably.

Change-Id: Id9cbb250c74fc0e876d4ea46b1b3dbf8356d6725
2013-10-30 02:00:33 -07:00
432a723e0b Merge "swig: add basic go bindings" 2013-10-30 01:03:32 -07:00
fab618b5fb Merge "rename libwebp.i -> libwebp.swig" 2013-10-30 01:02:05 -07:00
e4e7fcd69b swig: add basic go bindings
WebPGetDecoderVersion
WebPGetInfo

Change-Id: Icb66207c2f492c9d20642544c0b31cc92b91cdcc
2013-10-29 21:44:20 +01:00
d3408720d8 Merge "fast auto-determined filtering strength" 2013-10-29 12:47:58 -07:00
f8bfd5cd1e fast auto-determined filtering strength
kLevelsFromDelta[sharpness][delta] is an inverse look-up table
that tells the minimum filtering strength needed to trigger the
filtering of a step with amplitude 'delta'. We use this table
in various situations:

a) when computing the initial (/global) filtering
strength for each segment. We look at the quantization
step and deduce the proper filtering strength needed
to result this quantization noise (talking the -f option
into account).

b) during intra16 calculation, when a block ends up
very empty (only DC coeffs are non-zero, all ACs have
vanished). We'll rely on the in-loop filtering to
restore the smoothness (if the source was gradient-like
smooth. That's why we look at the distortion too before
triggering the filtering).

Step b) goes _in addition_ to a), potentially raising
the filtering strength if blockiness is likely.

Change-Id: Icaeca93ef21da195b079e6587a44d9edfc8e9efa
2013-10-29 20:13:29 +01:00
ac0bf951ca small clean-up in ExpandMatrix()
Change-Id: Ib06cb1658a6548f06bb7320310b3864881b606a7
2013-10-29 19:58:57 +01:00
1939607e7f rename libwebp.i -> libwebp.swig
.swig provides better tool compatibility

Change-Id: I35587b84dd32e12e8cedad14b36ac518b63896bc
2013-10-29 19:51:04 +01:00
43148b6cd2 filtering: precompute ilimit and hev_threshold
no speed change, just simplifying the logic

Change-Id: I518800494428596733d4fbae69072049828aec3c
2013-10-28 13:37:33 +01:00
18f992ec0f simplify f_inner calculation a little
by incorporating the is_4x4 flag at init

Change-Id: I042e04aacb15181db0bf86f3212c880087519189
2013-10-28 01:49:09 -07:00
241d11f141 add missing const
Change-Id: Id1c767d21d52197ed2e4497005eb9c4795c602f0
2013-10-25 20:34:14 +02:00
86c0031eb2 add a 'format' field to WebPBitstreamFeatures
Change-Id: I79a688e4c34fb77527127bbdf4bc844efa6aa9a4
2013-10-25 20:34:06 +02:00
dde91fde96 Demux: Correct the extended format validation
Earlier "f = f->next_" was executing for both inner and outer loop, thus
skipping validation of some frames.

Change-Id: Ice5cdb4ff5da78384aa0573addd3a5e5efa0b10c
2013-10-23 17:25:23 -07:00
5d6c5bd2a5 add entry for '-resize' option in cwebp's man
Change-Id: I04b2853825527b03cfa73377004b1a2a40b4c94f
2013-10-23 02:22:15 -07:00
7c098d1814 Use some gamma-curve range compression when computing U/V average
This helps for discolorated chroma-subsampled edges.

Change-Id: I1d8ce87b66cb7e8b3572e6722905beabf0f50554
2013-10-18 21:28:05 +02:00
0b2b05049f Use deterministic random-dithering during RGB->YUV conversion
-> helps debanding (sky, gradients, etc.)

This dithering can only be triggered when using -preset photo
or -pre 2 (as a preprocessing). Everything is unchanged otherwise.

Note that this change is likely to make the perceived PSNR/SSIM drop
since we're altering the input internally.

Change-Id: Id8d4326245d9b828141de162c94ba381b1fa5813
2013-10-17 22:36:49 +02:00
8a2fa099cc Add a second multi-thread method
method 1 grouping: [parse + reconstruction] // [filtering + output]
method 2 grouping: [parse] // [reconstruction+filtering + output]

Depending on some heuristics (see VP8ThreadMethod()), we
can pick one of the other when -mt flag (or option.use_threads)
is selected.

Conservatively, we always use method #2 for now until the heuristic
is refined (so, timing should be the same the before this patch)

+ replace 'use_threads' by 'mt_method'
+ define MIN_WIDTH_FOR_THREADS constant
+ fix comment alignment

Change-Id: I11a756dea9070d6e21b1a9481d357a1e8aa0663e
2013-10-15 23:58:31 +02:00
7d6f2da075 Merge "up to 20% faster multi-threaded decoding" 2013-10-15 14:51:12 -07:00
266f63ea89 Merge "libwebp.jar: build w/Java 1.6 for Android compat" 2013-10-15 02:04:41 -07:00
0532149c8a up to 20% faster multi-threaded decoding
Mostly visible for large images.
Reconstruction+filtering is now done in parallel to bitstream-parsing.

Change-Id: I4cc4483d803b255f4d97a2fcd9158b1c291dd900
2013-10-15 00:25:21 +02:00
38efdc2e9c Simplify the gif2webp tool: move the optimization details to util
Specifically:
- Merge OptimizeAndEncodeFrame with WebPFrameCacheAddFrame: they use the same
  if-else structure.
- Move maintenance of 'prev_canvas' and 'curr_canvas' to util.
- Move ReduceTransparency() and FlattenPixels() calls to SetFrame(): This is in
  preparation for the next patch: which will try try lossless encoding for
  each frame, even when '-lossy' option is given.
- Make most methods static inside util.

No changes to output expected.

Change-Id: I1f65af25246665508cb20f0f6e338f9aaba9367b
2013-10-14 14:39:46 -07:00
de899516c7 libwebp.jar: build w/Java 1.6 for Android compat
broken since:
 a5c297c swig/java: reduce wrapper function code duplication

this was a part of v0.3.1, but not v0.3.0.

Change-Id: I001d4bd0a7a1aa1b2d267bc63bc1d8226bff00c1
2013-10-11 17:59:37 +02:00
cb22155201 Decode a full row of bitstream before reconstructing
Needs more memory but allows for future parallelization.
Noticeably faster on ARM, slightly faster on x86

also: remove dec->filter_row_ unnecessary field

Change-Id: I044a808839b4e000c838a477e3e8688820436d9a
2013-10-10 21:29:58 +02:00
dca8a4d315 Merge "NEON/simple loopfilter: avoid q4-q7 registers" 2013-10-10 01:58:41 -07:00
9e84d901d2 Merge "NEON/TransformWHT: avoid q4-q7 registers" 2013-10-09 09:32:59 -07:00
fc10249b36 NEON/simple loopfilter: avoid q4-q7 registers
very tiny speed improvement

Change-Id: I3024f120feb7275ce20bfff21af31ea8650a5a03
2013-10-09 18:17:31 +02:00
2f09d63e30 NEON/TransformWHT: avoid q4-q7 registers
very tiny speed improvement

Change-Id: Iace78b9038af412d0a794845ff19f54afa88ccdc
2013-10-09 18:17:23 +02:00
77585a2be6 Merge "use a macrofunc for setting NzCoeffs bits" 2013-10-09 03:00:49 -07:00
d155507cb9 Merge "use HINT_GRAPH as image_hint for gif source" 2013-10-09 02:58:15 -07:00
9c561646ac Merge "only print GIF_DISPOSE_WARNING once" 2013-10-09 02:56:45 -07:00
05879865da use HINT_GRAPH as image_hint for gif source
quite rarely, it gives a different output
then without the HINT, but that's often for
a smaller size (tested with default -m and -m 6)

Change-Id: I51d221ab61f8e007983325031345728e8d80b241
2013-10-09 11:55:51 +02:00
0b28d7ab08 use a macrofunc for setting NzCoeffs bits
(avoids code dup)

Change-Id: I776f065538e562673ca08f3bc43c7167d13254d9
2013-10-09 11:46:32 +02:00
f9bbc2a034 Special-case sparse transform
If the number of non-zero coeffs is <= 3, use a
simplified transform for luma.

Change-Id: I78a1252704228d21720d4bc1221252c84338d9c8
2013-10-08 22:05:38 +02:00
00125196f3 gif2webp: detect and flatten uniformly similar blocks
helps during lossless compression.

10% average saving, but that's mostly on what was previously
'difficult' cases, where the gain is ~30-50% actually.
Non-difficult cases are mostly unchanged.
Tested over ~7k random web gifs.

Change-Id: I09db4560e4ab09105d1cad28e6dbf83842eda8e9
2013-10-08 15:04:52 +02:00
0deaf0fa44 only print GIF_DISPOSE_WARNING once
Change-Id: Iece235a6ee767cc2e3866bb6c9bb1d56d9a9ffb9
2013-10-08 15:02:33 +02:00
6a8c0eb718 Merge "small optimization in segment-smoothing loop" 2013-10-08 04:13:37 -07:00
f7146bc1e6 small optimization in segment-smoothing loop
probably not much of a speed difference

Change-Id: I08c41d82c3c2eb5ff9ec9ca9d81af2bb09b362de
2013-10-07 07:44:51 -07:00
5a7533ceb3 small gif2webp fix
the old kmin value was printed instead of the new one.

Change-Id: I0dcf23a29b7ce6bad08013a1980c5ce027b1bfe9
2013-10-04 21:13:35 +02:00
4df0c89e24 Merge changes Ic697660c,I27285521
* changes:
  Android.mk: add a dwebp target
  Android.mk: update build flags
2013-10-04 05:02:13 -07:00
5b2e6bd3e8 Android.mk: add a dwebp target
Change-Id: Ic697660c1a5f7185d2ad00934b314b44870cec00
2013-10-04 11:26:37 +02:00
f910a84ea5 Android.mk: update build flags
- split out release specific flags
- set LOCAL_ARM_MODE to arm

Change-Id: I272855216583d6c8d0a4106e8b3fde46aa59dfa9
2013-10-04 11:18:09 +02:00
63f9aba4b3 special-case WHT transform when there's only DC
happens surprisingly often at low quality, so we might
as well hard-code a simplified TransformWHT() directly.

Change-Id: Ib7a858ef74e8f334bd59d6512bf5bd3e455c5459
2013-10-02 14:27:36 +02:00
80911aef38 Merge "7-8% faster decoding by rewriting GetCoeffs()" 2013-10-02 01:51:53 -07:00
606c4304c4 gif2webp: Improved compression for lossy animated WebP
We reduce transparency by turning some transparent pixels into
corresponding RGB values from previous canvas.

This improves compression by about 23%.

Change-Id: I02d70a43a1d0906ac09a7e2dc510be3b2d38f593
2013-09-30 16:48:39 -07:00
fb887f7fe6 gif2webp: Different kmin/kmax defaults for lossy and lossless
These were the best values found considering the compression gain and
decoding speed.

Change-Id: Iddae4c5b78c6aa42b1f8a034d1c1b93843071a81
2013-09-30 14:25:58 -07:00
2a98136667 7-8% faster decoding by rewriting GetCoeffs()
Change-Id: Ib7c27e985d3b5222e8fa1f98cec462458caa9541
2013-09-30 23:17:34 +02:00
92d47e4ca9 improve VP8L signature detection by checking the version bits too
Change-Id: I20bea00b9582d7ea8c7b643616c78f717ce1bdf2
2013-09-27 18:17:23 +02:00
5cd43e4316 Add -incremental option to dwebp
useful for testing. Not listed in the man or README, since
it's only useful for testing the incremental decoding
(e.g. measuring the timing difference compared to non-incremental)

Change-Id: I8df8046e031d21006242babb5bcac09f8ff9f710
2013-09-19 13:20:45 +02:00
54b8e3f6e2 webpmux: DisplayInfo(): remove unnecessary error checks.
As WebPMuxCreate() would have succeeded by then, many of the calls
cannot fail.

Change-Id: I3220c59e9aa47c948da9f8741b4098c47b91a8fc
2013-09-18 11:44:24 -07:00
40ae3520b1 fix memleak in WebPIDelete()
happens when decoding is partial (past Partition0), without error and
interrupted by calling WebPIDelete()

WebPIDelete() needs to call VP8ExitCritical() to free in-flight resources

Change-Id: Id4faef1b92f7edd8c17d642c58860e70dd570506
2013-09-17 15:45:43 -07:00
d9662658d9 mux.h doc: WebPMuxGetFrame() can return WEBP_MUX_MEMORY_ERROR too.
Change-Id: Icc0305f162d1f5d15ad1b4713ac08e210c85c306
2013-09-17 14:37:12 -07:00
0e6747f88d webpmux -info: display dimensions and has_alpha per frame
Also, more readable dispose and blend methods.

Change-Id: I318431f94dcdee4c5da296a48e6f3762aa254c1f
2013-09-16 15:29:24 -07:00
d78a82c407 Sanity check for underflow
Change-Id: I52dbdcbd02c344c6260f196afad30005d14d3ee0
2013-09-16 13:35:13 -07:00
8498f4bfe2 Merge "remove -Wshadow warnings" 2013-09-16 13:19:39 -07:00
e89c6fc867 Avoid a potential memleak
Change-Id: I76f30fb40743a989bce25b40238cf0db55bd07e0
2013-09-16 13:12:33 -07:00
3ebe175781 Merge "break down the proba 4D-array into some handy structs" 2013-09-14 03:14:30 -07:00
6a44550a8c break down the proba 4D-array into some handy structs
Makes it easy to later add derived satellite fields...

Change-Id: I445767ea78cc788d11aec367479e74e485fdabe5
2013-09-14 03:12:09 -07:00
2f5e893400 remove -Wshadow warnings
"warning: declaration of ‘index’ shadows a global declaration"

Change-Id: I65f079aa4cd300cd1b3887a040b75c6b0f36ca1d
2013-09-14 02:02:09 -07:00
bf3a29b302 Merge "add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags" 2013-09-14 01:57:36 -07:00
2b0a759335 Merge "fix some warnings from static analysis" 2013-09-13 13:00:12 -07:00
22dd07cee9 mux.h: Some doc corrections
Change-Id: Ia2840a489d87001de241a9a8fbc88a127af55ff9
2013-09-13 12:51:36 -07:00
79ff03460a add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags
...and make gif2webp and vwebp compile without them.

Makefile.vc still to be updated...
Meanwhile the CL environment variable can be supplemented with

set CL=/DWEBP_HAVE_GL /IC:\opt\freeglut\include

Change-Id: I37a60b8c32aafd125bffa98b6cc9f57c022ebbd0
2013-09-13 12:46:41 -07:00
d51f45f047 fix some warnings from static analysis
http://code.google.com/p/webp/issues/detail?id=138

Change-Id: I21470e965357cc14eab356e2c477c7846ff76ef2
2013-09-13 11:33:30 +02:00
d134307b7f fix conversion warning on MSVC
"src\enc\frame.c(88) : warning C4244: '=' : conversion from 'const double' to 'float', possible loss of data"

Change-Id: I143cb0bb6b69e1b8befe9b4f24b71adbc28095c2
2013-09-12 18:57:51 -07:00
d538cea8c2 gif2webp: Support a 'min' and 'max' key frame interval
Change-Id: If910c8849d7210e7227db0f45affa26fce7da102
2013-09-12 13:41:09 -07:00
80b54e1c69 allow search with token buffer loop and fix PARTITION0 problem
The convergence algo is noticeably faster and more accurate.

Try it with: 'cwebp -size xxxxx -pass 8 ...' or 'cwebp -psnr 39 -pass 8 ...'
for instance

Allow full-looping with TokenBuffer case, and make the non-TokenBuffer
case match too.

In case Partition0 is likely to overflow, retry encoding with harder
limits on max_i4_header_bits_.

This CL should make -partition_limit option somewhat useless,
since the fix made automatically (albeit in a non-optimal way yet).

Change-Id: I46fde3564188b13b89d4cb69f847a5f24b8c735b
2013-09-11 21:15:28 +02:00
b7d4e04255 add VP8EstimateTokenSize()
estimates final size of coded tokens given a set of probabilities

Change-Id: Ia5a459422557d98b78b3cd8e1a88cb30835825b6
2013-09-11 10:08:49 +02:00
10fddf53bb enc/quant.c: silence a warning
score_t -> int: rd_i4.H contains a value from a uint16_t
lookup

Change-Id: I7227de2dfab74b4f796abbc47955197ffa0e6110
2013-09-11 00:04:11 -07:00
399cd4568b Merge "fix compile error on ARM/gcc" 2013-09-10 15:12:30 -07:00
9f24519e82 encoder: misc rate-related fixes
* fix VP8FixedCostsI4ÆÅ table
   (the constant cost '211' was erronenously included)
* use the rd-score for '211' correctly (calling SetRDScore() for good)
* count partition0 bits separately during rd-opt

No meaningful difference in rd-curve.

Change-Id: I6c49a150cf28928d9a92c32fff097600d7145ca4
2013-09-10 00:25:32 -07:00
c663bb214a Merge "simplify VP8IteratorSaveBoundary() arg passing" 2013-09-06 14:21:42 -07:00
fa46b31269 Demux.h: Correct a method name reference
Change-Id: I5638a4e40d9fcb44860952028f8b5ef2ea78621d
2013-09-06 11:26:00 -07:00
f8398c9dab fix compile error on ARM/gcc
use of uint8_t type was causing error like:
src/dsp/upsampling.c:223:1: internal compiler error: in vect_determine_vectorization_factor, at tree-vect-loop.c:349

with gcc 4.6.3

Change-Id: Ieb6189a1375c47fc4ff992e6c09b34a7f1f605da
2013-09-06 03:07:28 -07:00
f691f0e461 simplify VP8IteratorSaveBoundary() arg passing
we only need to save yuv_out_, so no need for the arg

Change-Id: I7bad5d910e81ed2eda5c9787821fd1cfe905bd92
2013-09-06 02:11:16 -07:00
42542be855 up to 6% faster encoding with clang compiler
mostly by revamping the main loop of GetResidualCost() and avoiding some branches

Change-Id: Ib05763e18a6bf46c82dc3d5d1d8eb65e99474207
2013-09-05 10:38:22 -07:00
93402f02db multi-threaded segment analysis
When -mt is used, the analysis pass will be split in two
and each halves performed in parallel. This gives a 5%-9% speed-up.

This was a good occasion to revamp the iterator and analysis-loop
code. As a result, the default (non-mt) behaviour is a tad (~1%) faster.

Change-Id: Id0828c2ebe2e968db8ca227da80af591d6a4055f
2013-09-05 09:13:36 +02:00
7e2d65950f Merge "remove the PACK() bit-packing tricks" 2013-09-04 23:55:41 -07:00
c13fecf908 remove the PACK() bit-packing tricks
was too smart for its own good :)
This is more ARM-friendly, since it removes a mult.

Change-Id: If146034c8efa2e71e3eaaf1230cb553884a42ebb
2013-09-05 08:53:36 +02:00
2fd091c9ae Merge "use NULL for lf_stats_ testing, not bool" 2013-09-04 07:18:42 -07:00
b11c9d6284 dwebp: use default dct_method
No significant speed diff was observed.
Avoids idct mismatch artifacts.

Change-Id: I9ca64d165d313f23b4aa231e7a97a20213ff86c7
2013-09-03 15:48:41 -07:00
4bb8465f8c Merge "(de)mux.h: wrap pseudo-code in /* */" 2013-09-03 15:47:42 -07:00
cfb56b1707 make -pass option work with token buffers
-pass 2 can be useful sometimes. More passes usually don't help more.
This change is a step toward being able to re-code the whole picture
with varying parameter (when token buffer is used).

Change-Id: Ia2538e2069a53c080e2ad248c18a1e04623a9304
2013-09-03 23:37:42 +02:00
5416aab479 (de)mux.h: wrap pseudo-code in /* */
easier to copy / read as a block

Change-Id: Ia22689a13afd8ea2325dcdf432e35fc802d8177a
2013-09-03 14:31:02 -07:00
35dba337a3 use NULL for lf_stats_ testing, not bool
Change-Id: I14c6341bce1c745b7f2d1b790f2d4f8441d01be6
2013-09-03 08:45:59 -07:00
733a7faae4 enc->Iterator memory cleanup
* move yuv_in_/out_* scratch buffers to iterator
* add y_top_/uv_top_ shortcuts in iterator

That's ~3k of stack size instead of heap.
But it allows having several iterators work in parallel.

Change-Id: I6a437c0f2ef1e5d398c1d6a2fd4974fa0869f0c1
2013-08-31 23:38:11 +02:00
e81fac86dd Add support for "no blend" in webpmux binary
Change-Id: I6d07b120626317df73f1a6f026931c5b9485a340
2013-08-26 18:04:52 -07:00
3b80bc4859 gif2webp: Separate out each step into a method
We now have ReadFrame(), OptimizeFrame(), EncodeFrame() and
DisposeFrame()
methods.

Change-Id: I522834bad18dd6a7a3ddac7c00dfd829c48248f8
2013-08-22 11:14:51 -07:00
bef7e9ccd1 Add doc precision about demux object keeping pointers to data.
Change-Id: I3d2139f975eedcce36606e586e0cbd6fa7d207e6
2013-08-21 11:09:37 -07:00
61405a143d dwebp: enable stdout output with WIC
Change-Id: Ieb73a414784480945bba6cb2687468517e24e755
2013-08-20 19:59:30 -07:00
6eabb88637 Merge "Animated WebP: add "do no blend" option to spec" 2013-08-20 19:14:17 -07:00
be20decb5c fix compilation for BITS 24
in_bits is const. Trying to apply bswap on it, one gets the error message:
error: read-only variable 'in_bits' used as 'asm' output

Change-Id: I0bef494b822c83d8ea87b1938b0e486d94de4742
2013-08-20 18:55:00 -07:00
e58cc13706 Merge "dwebp: s/unsigned char/uint8_t/" 2013-08-20 15:03:46 -07:00
72501d4309 dwebp: s/unsigned char/uint8_t/
Change-Id: I579e9b0a4d03998ca1dd8683d83d30d852551e45
2013-08-20 14:57:35 -07:00
2c9633e8e0 Merge "gif2webp: Insert independent frames at regular intervals." 2013-08-20 13:59:50 -07:00
f0d6a14b64 gif2webp: Insert independent frames at regular intervals.
We use the 'do not blend' option for creating independent frames.
We also mark the already independent frames as 'do not blend'.

This bounds the maximum number of frames that need to be decoded to
decode a given frame, thus leading to a much better decoding performance.

Change-Id: I7cef98af2b53751ec36993fd2bd54f7f4c4aad2b
2013-08-20 11:47:48 -07:00
b25a6fbfdc yuv.h: fix indent
Change-Id: I0c0bd5f7f71bc44e10134bd4f788769ec25cec1f
2013-08-19 18:06:15 -07:00
ede3602e5d Merge "cosmetics: fix indent" 2013-08-19 17:56:21 -07:00
3a65122a53 dwebp: fix stdout related output
logic was incorrect for the error output

Change-Id: I89e665f8065490e12e1bf3d3008087d42daee16b
2013-08-19 17:52:33 -07:00
388a7249c9 cosmetics: fix indent
Change-Id: Iad0fce79886bed0d61ddf2510ce133a5355ebc1f
2013-08-19 17:51:04 -07:00
4c7322c86f Merge "dsp: msvc compatibility" 2013-08-19 17:42:16 -07:00
d50c7e3275 Merge "5-7% faster SSE2 versions of YUV->RGB conversion functions" 2013-08-19 17:27:44 -07:00
b8ab784745 Merge "simplify upsampler calls: only allow 'bottom' to be NULL" 2013-08-19 17:27:36 -07:00
df6cebfa9e 5-7% faster SSE2 versions of YUV->RGB conversion functions
The C-version gets ~7-8% slower in order to match the SSE2
output exactly. The old (now off-by-1) code is kept under
the WEBP_YUV_USE_TABLE flag for reference.

(note that calc rounding precision is slightly better ~= +0.02dB)

on ARM-neon, we somehow recover the ~4% speed that was lost by mimicking
the initial C-version (see https://gerrit.chromium.org/gerrit/#/c/41610)

Change-Id: Ia4363c5ed9b4c9edff5d932b002e57bb7814bf6f
2013-08-19 17:05:58 -07:00
ad6ac32d7c simplify upsampler calls: only allow 'bottom' to be NULL
If 'top' was meant to be NULL, then bottom and top can be
swapped. Logic is simpler.

+ fix compilation in non-FANCY_UPSAMPLING mode

Change-Id: I7c62bbb59454017f072c0945d1ff2d24d89286ff
2013-08-19 16:47:51 -07:00
a5e8afafcb output to stdout if file name is "-"
Doesn't work with WIC

+ redirect some info messages from stdout to stderr
+ fix the error reporting upon output-writing error

Change-Id: I92b8bd7a15e656a3f3cdfbf56299f024e39453f8
2013-08-19 13:30:27 -07:00
f358450feb dsp: msvc compatibility
intrin.h is available after VS2003

patch from the FreeImage project

Change-Id: I58a18a0db00e247f871d05e3ba99772704f0e079
2013-08-16 20:46:16 -07:00
43a7c8ebee Merge "cosmetics" 2013-08-15 11:24:30 -07:00
4c5f19c148 Merge "bit_reader.h: cosmetics" 2013-08-15 11:11:03 -07:00
f72fab7045 cosmetics
Change-Id: Ib6fa2a7e1db8c5c48607c7097520ffca34a6cb66
2013-08-15 04:16:37 -07:00
14dd5e781a fix const-ness
Change-Id: I09c85fdb90b4380c8fc03c8b5652bb9cf29b2021
2013-08-15 00:21:15 -07:00
b20aec4949 Merge "Support for 'do not blend' option in vwebp" 2013-08-14 20:01:38 -07:00
dcf652223a Support for 'do not blend' option in vwebp
Change-Id: I563e192fa727816d11d8647c559ec407205ef40b
2013-08-14 19:51:46 -07:00
d5bad03328 Animated WebP: add "do no blend" option to spec
Marking certain frames as "do not blend" helps avoiding alpha-blending
at decode/render time.

It also helps inserting I-frames (frames which can be independently
decoded) into the animation.

Change-Id: Iaa222805db88d2f1c81104ce9d882e7c7ff8cfdb
2013-08-14 11:50:15 -07:00
a2f5f73de3 Merge "Support for "Do not blend" in mux and demux libraries" 2013-08-14 09:27:58 -07:00
e081f2f359 Pack code & extra_bits to Struct (VP8LPrefixCode).
Also created variant VP8LPrefixEncodeBits that returns the
code & extra_bits only.
There's no impact on compression density and compression speed.

Change-Id: I2cafdd3438ac9270cd72ad9d57b383cdddfdfa4c
2013-08-12 11:56:42 -07:00
6284854bd5 Support for "Do not blend" in mux and demux libraries
Change-Id: I9566a8e2d059fe1ebd9ca99c7e13311bf3f8f281
2013-08-12 11:49:00 -07:00
f486aaa9f8 Merge "slightly faster ParseIntraMode" 2013-08-09 02:17:16 -07:00
d17186328c slightly faster ParseIntraMode
+ cosmetics

Change-Id: Icb906d5f84f025ef9e04b71a73801a22cc990ee5
2013-08-09 02:15:21 -07:00
3ceca8ad31 bit_reader.h: cosmetics
- use const where applicable
- drop unnecessary string.h include

Change-Id: I560eef84fe17d3925768f6817c02ea79604c4379
2013-08-06 14:25:26 -07:00
69257f70df Create LUT for PrefixEncode.
This speeds up lossless compression by 5%.
Change-Id: Ifd114b1d9850dc3aac74593809e7d48529d35e3d
2013-08-05 10:20:18 -07:00
988b70844e add WebPWorkerExecute() for convenient bypass
This is mainly for re-using the worker structs without using the
thread.

Change-Id: I8e1be29e53874ef425b15c192fb68036b4c0a359
2013-08-02 12:20:15 -07:00
06e24987e7 Merge "VP8EncIterator clean-up" 2013-08-02 00:40:02 -07:00
de4d4ad598 VP8EncIterator clean-up
- remove unused fields from iterator
- introduce VP8IteratorSetRow() too
- rename 'done_' to 'countdown_'
- bring y_left_/u_left_/v_left_ from VP8Encoder

Change-Id: Idc1c15743157936e4cbb7002ebb5cc3c90e7f92a
2013-08-01 23:05:54 -07:00
7bbe95293f Merge "cosmetics: thread.c: drop a redundant comment" 2013-07-31 23:56:06 -07:00
da41148560 cosmetics: thread.c: drop a redundant comment
+ fix #if/#else/#endif comment

Change-Id: I76bfd3b123ed181897ed0feba721d5c1a3a2b0d7
2013-07-31 22:55:51 -07:00
feb4b6e6b3 thread.h: #ifdef when checking WEBP_USE_THREAD
prevents a warning with -Wundef and is consistent with thread.c

Change-Id: I60fa337c3b9daeea7302e86802402cb943cdb262
2013-07-31 22:50:57 -07:00
8924a3a704 thread.c: drop WebPWorker prefix from static funcs
Change-Id: I7cd39c9e41bbf11157c488aff18631ef17fde464
2013-07-31 19:22:44 -07:00
1aed8f2afc Merge "fix indent" 2013-07-26 17:08:37 -07:00
4038ed154d fix indent
Change-Id: I7f226ec4276e5e1b46896086a7d96cb67f36de6a
2013-07-26 17:03:19 -07:00
1693fd9b16 Demux: A new state WEBP_DEMUX_PARSE_ERROR
WebPDemuxPartial() returns NULL for both of the following cases:
- There was a parsing error.
- It doesn't have enough data to start parsing.

Now, one can differentiate between these two cases by checking the value
of 'state' returned by WebPDemuxPartial().

Change-Id: Ia2377f0c516b3fcfae475c0662c4932d2eddcd0b
2013-07-26 14:35:46 -07:00
8dcae8b3cf fix rescaling-with-alpha inaccuracy
(still missing YUVA decoding case for now)

https://code.google.com/p/webp/issues/detail?id=160

Change-Id: If723b4a5c0a303d0853ec9d839f995adce056095
2013-07-26 12:10:26 -07:00
11249abfc7 Merge changes I9b4dc36c,I4e0eef4d
* changes:
  Mux: support parsing unknown chunks within a frame/fragment.
  Stricter check for presence of alpha when writing lossless images
2013-07-22 17:05:27 -07:00
52508a1fe4 Mux: support parsing unknown chunks within a frame/fragment.
Change-Id: I9b4dc36c5ccc4b46f60cd64c1ee21008e20c8b95
2013-07-22 17:00:41 -07:00
05db0572f8 WebPMuxSetChunk: remove unused variable
and unnecessary call to ChunkGetIndexFromFourCC()

Change-Id: Ic1ed53750a3be43df827a6fb9a4b9ff3eb25c6c7
2013-07-19 13:03:25 -07:00
8ba1bf61a0 Stricter check for presence of alpha when writing lossless images
Earlier, all lossless images were assumed to contain alpha.
Now, we use the 'alpha_is_used' bit from the VP8L bitstream to determine
the
same.

Detecting an absence of alpha can sometimes lead to much more efficient
rendering, especially for animated images.

Related: refine mux code to read width/height/has_alpha information only
once
per frame/fragment. This avoid frequent calls to VP8(L)GetInfo().

Change-Id: I4e0eef4db7d94425396c7dff6ca5599d5bca8297
2013-07-19 11:55:09 -07:00
a03c3516cb Demux: WebPIterator now also denotes if the frame has alpha.
Change-Id: Ia300385a49c1ee5afa8f114f2560ee8d1c7664bb
2013-07-18 19:41:38 -07:00
6df743a33e Decoder: handle fragments case correctly too.
Exit early from ParseHeaderInternal() in case of fragmented image too.

Change-Id: I3e24be2c869cc2d87c43b705257f21be81127dbd
2013-07-18 19:23:57 -07:00
faa4b07eda Support for unknown chunks in mux library
WebPMuxSetChunk/WebPMuxGetChunk/WebPMuxDeleteChunk now correctly handle
unknown chunks.

Change-Id: I2b75106ef08260f2bce03eb1782924b620643746
2013-07-17 16:34:50 -07:00
7d60bbc6d9 Speed up HashChainFindCopy function.
Speed up HashChainFindCopy by optimizing on number of calls to
FindMatchLength method.
This change speeds up the lossless & lossy (Alpha) encoding by 20%
without loss of compression density.
At method=3, lossy (Alpha) compression speed (and density) remains
unchanged, as at that settings, the costly Backward Refs method is not
called

Change-Id: Ia1797148e9e4ee2787011837fa248afbae2242cb
2013-07-16 19:58:18 -07:00
6674014077 Speedup Alpha plane encoding.
Disable costly 'BackwardReferencesTraceBackwards' for encoding Alpha plane.
Increase the threshold for triggering 'BackwardReferencesTraceBackwards' to
quality 25 and above. Also lower the Alpha quality (at method 3) to be
lesser than this threshold (25).

Change-Id: Ic29fb2e6943472c564223df9fe099b19ccda0f31
2013-07-12 11:02:13 -07:00
b7346a1ed2 0.1 % speedup to decoding
Change-Id: If2add8a8b6f339f1d4b6a9581ce8d3d0f792d372
2013-07-09 18:47:06 -07:00
c606182edd webp-container-spec: Tighten language added by last
Change-Id: Id7719ba7f1ddfd7b54a1985771b2811318a7c0d7
2013-07-09 18:45:39 -07:00
a34a502989 pngdec: output error messages from libpng
Change-Id: I1981562eeab2ad07eb797cea589a033943e7f21d
2013-07-09 17:33:21 -07:00
e84c625d92 Merge "Detect canvas and image size mismatch in decoder." 2013-07-03 00:51:26 -07:00
f626fe2e9f Detect canvas and image size mismatch in decoder.
Will probably have to be re-visited when FRGM are
switched on.

Change-Id: I51c15e4c3887ab8f04d92ec783deca274cd09f41
2013-07-02 16:19:08 -07:00
f5fbdee0ba demux: stricter image bounds check
- validate x/y offset vs. canvas size
- with single images verify image res. == canvas res.

Change-Id: I737451d7f75c0c43c88180a903d5227f1d90cec1
2013-07-02 16:17:28 -07:00
30c8158a53 add extra assert in Huffman decode code
Change-Id: Ic0372d30827f11b727d63eac6c5eac01d1e9870d
2013-06-29 01:36:53 -07:00
8967b9f37e SSE2 for lossless decoding (critical) functions.
This speeds up WebP lossless decoding by 20%. In particular, the
photographic images get 35% speedup.

Change-Id: Idb94750342a140ec05df52c07e12be4bba335adc
2013-06-27 11:42:45 -07:00
699d80ea6b Jump-lookup for Huffman coding
speeds up those codes that are not part of the main lookup.
This gives a 10 % speedup for a photographic image.

Change-Id: Ief54b0ad77db790a01314402ad351b40ac9a7be4
2013-06-27 08:59:55 +02:00
c34307abda fix some VS9 warnings about type conversion
Change-Id: Ia6db5f70cecb1d0c29536d710a22cc5107e242ea
2013-06-27 08:49:01 +02:00
eeada35cd6 pngdec: add missing include
strcmp -> string.h

Change-Id: I07392d07cbad420f5d4f3abfd3ffde8626f0c0f2
2013-06-25 23:32:19 -07:00
54b65108ad gif2webp: If aligning to even offsets, extra pixels should be transparent
This is to ensure that the output WebP image is consistent with original
GIF when displayed against any background color.

Change-Id: I14218848153eb40358aa4ce331b2543d2fc2e86c
2013-06-24 15:18:35 -07:00
0bcf5ce39a Merge "remove a malloc() in case we're using only FILTER_NONE for alpha" 2013-06-24 12:55:40 -07:00
2c07143b9d remove a malloc() in case we're using only FILTER_NONE for alpha
+ some revamp and cleanup of the alpha-filter trial loop
+ EncodeAlphaInternal() now just takes a FilterTrial param

Change-Id: Ief84385083b1cba02678bbcd3dbf707245ee962f
2013-06-24 02:07:52 -07:00
a4d5f59d9e Faster lossless decoding
Specialize and simplify the alpha-decoding case, which is used when:
 - no color-cache is use
 - all red/blue/alpha values are the same (and hence their Huffman tree has
 only 1 symbol. We don't need to consume any bits for reading these).

 + revamped the loop to use size_t and offsets instead of pointers.

 ~2-3% faster on Unix (gcc) but up to 25% faster lossy+alpha decoding
 on Mac (llvm) and ARM.

Change-Id: I43c9688d1e4811cab0ecf0108a5b8f45781083e6
2013-06-24 09:34:30 +02:00
fd53bb758e Merge "alternate LUT-base reverse-bits code" 2013-06-24 00:32:39 -07:00
d1c166ef3f Merge "Container spec: a clarification on background color." 2013-06-21 00:53:12 -07:00
fdb9177917 Rename a method
Change-Id: Idc5f4ea1019a828a5fa1fbd81804fa51cd7e8673
2013-06-21 00:35:39 -07:00
5e9675329c Container spec: a clarification on background color.
Change-Id: Ifeb565bd162abfa03dfcbf8b576657fe83956a6c
2013-06-20 17:38:08 -07:00
30e77d0f66 Merge branch '0.3.0'
* 0.3.0: (57 commits)
  update ChangeLog
  Regression fix for alpha channels using color cache:
  wicdec: silence a format warning
  muxedit: silence some uninitialized warnings
  update ChangeLog
  update NEWS
  bump version to 0.3.1
  Revert "add WebPBlendAlpha() function to blend colors against background"
  Simplify forward-WHT + SSE2 version
  probe input file and quick-check for WebP format.
  configure: improve gl/glut library test
  update copyright text
  configure: remove use of AS_VAR_APPEND
  fix EXIF parsing in PNG
  add doc precision for WebPPictureCopy() and WebPPictureView()
  remove datatype qualifier for vmnv
  fix a memory leak in gif2webp
  fix two minor memory leaks in webpmux
  remove some cruft from swig/libwebp.jar
  README: update swig notes
  ...

Conflicts:
	NEWS
	examples/gif2webp.c
	src/dec/alpha.c
	src/dec/idec.c
	src/dec/vp8l.c
	src/enc/alpha.c
	src/enc/vp8l.c

Change-Id: Ib202fad7825a090c3b3a5169acd171369cface47
2013-06-20 14:47:48 -07:00
1b631e291a alternate LUT-base reverse-bits code
Not faster on Unix/x86. Left the code for reference though.

Change-Id: I7d419e9835e7746b85b8f8cc6f2af92db0eb8b03
2013-06-20 19:58:11 +02:00
24cc307ae3 ~20% faster lossless decoding
We use help from small LUTs for Huffman decoding.

Change-Id: I58db4ecd37282822094519f2aa14cf544beba975
2013-06-20 09:41:29 +02:00
313d853fa9 Speedup for decoding lossless WebP photographs:
use bit_pos instead num_bit to update the bit-reader
37.69 MB/s -> 39.79 MB/s, 5.6 %

Change-Id: Ica476cc3e2fc2db084d6961bea8586b050bb221d
2013-06-18 17:26:52 +02:00
24ee098a00 change the bytes_per_pixels_ field into more evocative use_8b_decode
+ split AllocateInternalBuffers() into two 32b/8b variants instead of
trying to do everything in one function.

Change-Id: I35cac9fcd990a2194c95da4b2a4046ca3a514343
2013-06-18 17:24:14 +02:00
2a04b034f7 update ChangeLog
Change-Id: Idea3464bbcb28896179c99488e7b96a4341b508a
2013-06-17 16:53:22 -07:00
7288950b88 Regression fix for alpha channels using color cache:
Considering the fact that insert to/lookup from the color cache is always 32
bit, use DecodeImageData() variant in that case.

Conflicts:
	src/dec/vp8l.c

Change-Id: I6c665a6cfbd9bd10651c1e82fa54e687cbd54a2b
(cherry picked from commit a37eff47d6)
2013-06-17 16:29:09 -07:00
2e377b53b0 wicdec: silence a format warning
from x86_64-w64-mingw32-gcc

examples/wicdec.c: In function ‘ExtractICCP’:
examples/wicdec.c:131:21: warning: format ‘%u’ expects argument of type
‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat]

Change-Id: I6642dae62265a2276ae9ac96dd8ce6f1e2d37ca5
(cherry picked from commit ffae9f31e8)
2013-06-17 15:43:33 -07:00
ad9e42a6fe muxedit: silence some uninitialized warnings
src/mux/muxedit.c:490: warning: 'x_offset' may be used uninitialized in this function
src/mux/muxedit.c:490: warning: 'y_offset' may be used uninitialized in this function

Change-Id: I4fd27f717e59a556354d0560b633d0edafe7a4d8
(cherry picked from commit 14cd5c6c40)
2013-06-17 15:43:33 -07:00
3307c16327 Don't set alpha-channel to 0xff for alpha->green uplift
usually saves ~4 bytes on average (but, up to 10 -or even 16- sometimes).

Change-Id: Ib500e1a35471a2f3da453ffc8c7e95d28b8d34fe
2013-06-18 00:03:32 +02:00
5130770cd3 Merge "wicdec: silence a format warning" 2013-06-17 14:45:01 -07:00
a37eff47d6 Regression fix for alpha channels using color cache:
Considering the fact that insert to/lookup from the color cache is always 32
bit, use DecodeImageData() variant in that case.

Change-Id: I6c665a6cfbd9bd10651c1e82fa54e687cbd54a2b
2013-06-17 03:49:30 -07:00
241cf99bc0 Merge "muxedit: silence some uninitialized warnings" 2013-06-16 23:23:20 -07:00
c8f9c84d5e Regression fix for alpha unfiltering:
For vertical filter, correctly initialize 'preds' when not starting at
row 0.

Change-Id: I69697d73dde8a2f701f376ff3986d09fa6f7fee3
2013-06-16 02:00:44 -07:00
14cd5c6c40 muxedit: silence some uninitialized warnings
src/mux/muxedit.c:490: warning: 'x_offset' may be used uninitialized in this function
src/mux/muxedit.c:490: warning: 'y_offset' may be used uninitialized in this function

Change-Id: I4fd27f717e59a556354d0560b633d0edafe7a4d8
2013-06-15 14:30:22 -07:00
a368db81c6 dec/vp8l: quiet vs9 x64 type conversion warning
src\dec\vp8l.c(816) : warning C4244: '=' : conversion from '__int64' to
'int', possible loss of data
src\dec\vp8l.c(817) : warning C4244: '=' : conversion from '__int64' to
'int', possible loss of data

Change-Id: I1d376d5dea909395bff8741aba16e8eed83a6e8f
2013-06-14 19:24:54 -07:00
ffae9f31e8 wicdec: silence a format warning
from x86_64-w64-mingw32-gcc

examples/wicdec.c: In function ‘ExtractICCP’:
examples/wicdec.c:131:21: warning: format ‘%u’ expects argument of type
‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat]

Change-Id: I6642dae62265a2276ae9ac96dd8ce6f1e2d37ca5
2013-06-14 18:44:59 -07:00
8cf0701eb0 Alpha encoding: never filter in case of NO_COMPRESSION
This is because, filtering would never affect compression density for
this case.

Change-Id: I4bb14d3eb7da0a3805fda140eb1dfbf9ccc134f5
2013-06-14 13:34:25 -07:00
825e73b1a6 update ChangeLog
Change-Id: I2e67e5d80cb8f8e4453cee45144bcc01e9a3efeb
2013-06-12 23:32:59 -07:00
abf6f6915f update NEWS
Change-Id: Ie831ecc6995679acaf238686e2f287bfaa0221a7
2013-06-12 23:25:09 -07:00
5a92c1a5e9 bump version to 0.3.1
libwebp{,decoder} - 0.3.1
libwebp libtool - 4.3.0 (compatible release)
libwebpdecoder libtool - 0.1.0 (compatible release)

mux/demux - 0.1.1
libtool - 0.1.0 (compatible release)

Change-Id: Icc8329a6bcd9eea5a715ea83f1535a66d6ba4b58
2013-06-12 23:19:13 -07:00
86daf77c47 store top Y/U/V samples in packed fashion
More cache-line friendly than storing them split.

Change-Id: Ifb23cc3518ff1b5c37afe007558d4278868d75ea
2013-06-13 06:01:27 +02:00
67bc353e6d Revert "add WebPBlendAlpha() function to blend colors against background"
This reverts commit dcbb1ca54a.

Dropping this for now to maintain compatibility for 0.3.1.

Change-Id: I44e032a072d317bb67e1439c42cff923e603038f
2013-06-12 15:02:09 -07:00
068db59e26 Intertwined decoding of alpha and RGB
This will reduce the time to first decoded pixel.

Change-Id: I07b900c0ed4af3aac806b2731e11cd18ec16d016
2013-06-12 14:10:59 -07:00
38cc011408 Simplify forward-WHT + SSE2 version
no precision loss observed
speed is not really faster (0.5% at max), as forward-WHT isn't called often.

also: replaced a "int << 3" (undefined by C-spec) by a "int * 8"
( supersedes https://gerrit.chromium.org/gerrit/#/c/48739/ )

Change-Id: I2d980ec2f20f4ff6be5636105ff4f1c70ffde401
(cherry picked from commit 9c4ce971a8)
2013-06-12 13:48:11 -07:00
3fa595a571 Support decoding upto given row in DECODE_DATA_FUNC
This is in preparation for supporting Intertwined decoding of RGB and
alpha.

Change-Id: Ie1905d1212f4a00718a64dca020be3f4b1b870ec
2013-06-11 16:00:58 -07:00
520f005f85 DequantizeLevels(): Add 'row' and 'num_rows' args
Change-Id: I0032e25c30f34362105d942f2dbb9ac75200f911
2013-06-11 15:59:21 -07:00
47374b8273 Alpha unfilter for given set of rows
Support reconstruction of small number of rows at a time.

Change-Id: Ief1bc78c7ad011ec6df856551f3beb5f907fd8e0
2013-06-11 15:57:42 -07:00
f32097e0df probe input file and quick-check for WebP format.
Error message is clearer that 'can't create demux object'.

Change-Id: Iec008601892f7cd8399e1948751747ac23305eef
(cherry picked from commit 830f72b7e9)
2013-06-11 15:03:23 -07:00
a2aed1d08c configure: improve gl/glut library test
add a check for a libGL function (glOrtho) in addition to glutMainLoop
when establishing the need for libGL at link time.

fixes vwebp link failure on ubuntu 13.04+

Change-Id: I537e9a5cab5cf4cd8875e06268d2107f377e625e
(cherry picked from commit 2ccf58d648)
2013-06-11 15:03:23 -07:00
c7e89cbb02 update copyright text
rather than symlink the webm/vpx terms, use the same header as libvpx to
reference in-tree files

based on the discussion in:
https://codereview.chromium.org/12771026/

Change-Id: Ia3067ecddefaa7ee01550136e00f7b3f086d4af4
(cherry picked from commit d640614d54)
2013-06-11 15:03:22 -07:00
a00380d2ed configure: remove use of AS_VAR_APPEND
This wasn't used often and benefits were likely minimal. Dropping it
outright is a bit simpler than adding a compatibility ifdef.

provides some compatibility with older versions of autoconf.
tested with autoconf 2.59/automake 1.7/aclocal 1.7

Change-Id: Ifed892346cf2329597985704830a96fc58d65607
(cherry picked from commit 9326a56f8d)
2013-06-11 15:03:22 -07:00
a94a88dd62 fix EXIF parsing in PNG
'exiftool' puts an 'APP1' chunk for exif, e.g.:
https://metacpan.org/source/EXIFTOOL/Image-ExifTool-5.87/lib/Image/ExifTool/PNG.pm#L305

Change-Id: I313d3e6945898526b8a4baf3d9016a2591a1a817
(cherry picked from commit bec11092ca)
2013-06-11 15:03:22 -07:00
a71e5d84e9 add doc precision for WebPPictureCopy() and WebPPictureView()
output picture object is overwritten, not free'd or destroyed.

Change-Id: Ibb47ab444063e7ad90ff3d296260807ffe7ddbf9
(cherry picked from commit 23d28e216d)
2013-06-11 15:03:21 -07:00
8287012ec7 remove datatype qualifier for vmnv
this fix is for clang (LLVM v4.2). gcc was fine.

Change-Id: Id4076cda84813f6f9548a01775b094cff22b4be9
(cherry picked from commit 3fe91635df)
2013-06-11 15:03:21 -07:00
e190843029 fix a memory leak in gif2webp
(rgba->yuv allocates memory)
Also fixed few warning and cleaned the code up.

Change-Id: Id904ad3ad8802ea9fc3d34247d27193dfa7b0b99
(cherry picked from commit 764fdffaac)
2013-06-11 15:03:21 -07:00
0b18b9eef6 fix two minor memory leaks in webpmux
(only occur in case of error)

Change-Id: Icab69bb364b77f8eae6cae91047354c27e610602
(cherry picked from commit 3e59a74d72)
2013-06-11 15:03:21 -07:00
db5095d5b6 remove some cruft from swig/libwebp.jar
picked up a few unnecessary classes from a dirty tree in the last commit

Change-Id: I98be16a0bc8716476ce440da542d113f254aee78
(cherry picked from commit 325d15ff30)
2013-06-11 15:03:21 -07:00
850e956f9b README: update swig notes
add python, required version notes

Change-Id: Iec2e94075f6cf54455ce5a658f9b7258109f4d01
(cherry picked from commit 4a7627c215)
2013-06-11 15:03:21 -07:00
bddd9b0a93 swig/python: add minimal documentation
uses autodoc to display the function arguments rather than the
inscrutable va_args (*args).

Change-Id: Iec2ff8276c1533b14c3032836d822fbdae632521
(cherry picked from commit 825b64db53)
2013-06-11 15:00:48 -07:00
d573a8d53f swig: add python encode support
wraps the simple interface similar to java.

Change-Id: Ib922bbcae322b2345b6dce5dee08faad705a77fd
(cherry picked from commit 14677e11d4)
2013-06-11 15:00:47 -07:00
6b931875ac swig/java: reduce wrapper function code duplication
define a macro to emit the wrapper code

Change-Id: I672416016162d6d9ce6f455d224044e0837e3ace
(cherry picked from commit a5c297c842)
2013-06-11 15:00:47 -07:00
6fe536f4ba swig/java: rework uint8_t typemap
reuse the declarations from arrays_java.i for signed char to make an
explicit uint8_t mapping. this avoids sign conversion build warnings.

Change-Id: Icfb5b865cf1fd404e89f2cd889111f0a94e3c604
(cherry picked from commit ad4a367dba)
2013-06-11 15:00:47 -07:00
a2ea46439e Fix the bug in ApplyPalette.
The auto-infer logic of detecting the 'Alpha' use case
(via check '(palette[i] & 0x00ff00ffu) != 0' is failing
for this corner case image with all black pixels (rgb = 0)
and different Alpha values.

-> switch generic use-LUT detection

Change-Id: I982a8b28c8bcc43e3dc68ac358f978a4bcc14c36
(cherry picked from commit afa3450c11)
2013-06-11 15:00:47 -07:00
7bb28d2a55 webp/lossless: fix big endian BGRA output
Change-Id: I3d4b3d21f561cb526dbe7697a31ea847d3e8b2c1
(cherry picked from commit 2ca83968ae)
2013-06-11 15:00:47 -07:00
f036d4bfa6 Speed up ApplyPalette for ARGB pixels.
Added 1 pixel cache for palette colors for faster lookup.
This will speedup images that require ApplyPalette by 6.5% for lossless
compression.

Change-Id: Id0c5174d797ffabdb09905c2ba76e60601b686f8
(cherry picked from commit 742110ccce)
2013-06-11 15:00:46 -07:00
8112c8cf54 remove some warnings:
* "declaration of ‘index’ shadows a global declaration [-Wshadow]"
* "signed and unsigned type in conditional expression [-Wsign-compare]"

Change-Id: I891182d919b18b6c84048486e0385027bd93b57d
(cherry picked from commit 87a4fca25f)
2013-06-11 15:00:46 -07:00
cc128e0bfc Further reduce memory to decode lossy+alpha images
Earlier such images were using roughly 9 * width * height bytes for
decoding. Now, they take 6 * width * height memory.

Change-Id: Ie4a681ca5074d96d64f30b2597fafdca648dd8f7
(cherry picked from commit 64c844863a)
2013-06-11 15:00:46 -07:00
07db70d20f fix for big-endian
(Issue #150: https://code.google.com/p/webp/issues/detail?id=150)

Change-Id: Iad46d375a8c5eabae37cde8f55b3e7448601f264
(cherry picked from commit 4437061735)
2013-06-11 15:00:46 -07:00
eda8a7dec5 gif2webp: Fix signed/unsigned comparison mismatch
Change-Id: I355f0614424276550db71b24e5bb1948e5c6894c
(cherry picked from commit 043e1ae4bd)
2013-06-11 15:00:46 -07:00
31f346fe0c Makefile.vc: fix libwebpdemux dll variable typo
Fixes issue #149

Patch by: Jason Stevens  (cypher497 at gmail dot com)

Change-Id: I65cceaad37d22b96e5e92cb78f859fc0b7c38b67
(cherry picked from commit 3eeedae1bc)
2013-06-11 15:00:45 -07:00
6c76d28e4b swig: add python (decode) support
similar to Java, simple interface only

Change-Id: I8a3d344e5d89f73627e4e0cb2067512260d46fdd
(cherry picked from commit f980faf417)
2013-06-11 15:00:45 -07:00
b4f5bb6ca3 swig: cosmetics
normalize formatting
- update decode prototypes
- match project function name style

Change-Id: Ib481b5602171b72dbb1a5d462e6d5166e9b8566e
(cherry picked from commit 7f5f42bb36)
2013-06-11 15:00:45 -07:00
498d4dd634 WebP-Lossless encoding improvements.
Lossy (with Alpha) image compression gets 2.3X speedup.
Compressing lossless images is 20%-40% faster now.

Change-Id: I41f0225838b48ae5c60b1effd1b0de72fecb3ae6
(cherry picked from commit 8eae188a62)
2013-06-11 15:00:45 -07:00
26e7244221 swig: ifdef some Java specific code
no implementation change

Change-Id: I077c707e1f6293188e6fa11ba24757009a709f77
(cherry picked from commit c7247c4c68)
2013-06-11 15:00:45 -07:00
8ecec68652 configure: add warning related flags
adds TEST_AND_ADD_CFLAGS function
uses AM_CFLAGS to allow CFLAGS override

Change-Id: I9352aec6e5d905a41d832bf5ad0c8dcd154f7e97
(cherry picked from commit bba4c2b2a6)
2013-06-11 15:00:44 -07:00
e676b04309 configure: add GLUT detection; build vwebp
Change-Id: I7f0964db2d04c22ff9ec274e8cd1cbed7379a165
(cherry picked from commit 0e513f7ae3)
2013-06-11 15:00:44 -07:00
b0ffc43700 Alpha decoding: significantly reduce memory usage
Simply get rid of an intermediate buffer of size width x height, by
using the fact that stride == width in this case.

Change-Id: I92376a2561a3beb6e723e8bcf7340c7f348e02c2
(cherry picked from commit edccd19436)
2013-06-11 15:00:44 -07:00
20aa7a8dd5 configure: add --enable-everything
Change-Id: Ie1b3abd42459de7f789fe985759c465c2a196727
(cherry picked from commit 3cafcc9a8d)
2013-06-11 15:00:44 -07:00
b8307cc08b configure.ac: add some helper macros
library check related variable maintenance -> *_INCLUDES / *_LIBS

CLEAR_LIBVARS / LIBCHECK_PROLOGUE / LIBCHECK_EPILOGUE

Change-Id: I72e292dc1f69b02f69a26639308f247db0471e2b
(cherry picked from commit 4ef1447792)
2013-06-11 15:00:44 -07:00
980e7ae951 Remove the gcc compilation comments
They went out of sync some time ago, and are
no longer really required since we have them
buildable from makefile.unix

Change-Id: Ica2dcf5c55f44365598f832f55204d123d7aa601
(cherry picked from commit a4e1cdbbe8)
2013-06-11 15:00:44 -07:00
7f25ff99fd gif2webp: Fix ICC and XMP support
Change-Id: Ib5aafef388bd191610e4cc2f8180f35cd454f1d3
(cherry picked from commit b26e5ad540)
2013-06-11 15:00:43 -07:00
d8e5321144 Add missing name to AUTHORS
Change-Id: I00092e5bb676b48abc05b94080b589b48c911c82
(cherry picked from commit 46089b207d)
2013-06-11 15:00:43 -07:00
11edf5e24b Demux: Fix a potential memleak
Change-Id: Ic0dcac010da088b791c130be4abacdd8c31e92cf
(cherry picked from commit 94328d6457)
2013-06-11 15:00:43 -07:00
c7b92184df don't forward declare enums
doing so is not part of ISO C; removes some pedantic warnings

Change-Id: I739ad8c5cacc133e2546e9f45c0db9d92fb93d7e
(cherry picked from commit 96e948d7b0)
2013-06-11 15:00:43 -07:00
7a650c6ad6 prevent signed int overflow in left shift ops
force unsigned when shifting by 24.

Change-Id: Ie229d252e2e4078107cd705b09397e686a321ffd
(cherry picked from commit f4f90880a8)
2013-06-11 15:00:43 -07:00
31bea32408 add precision about dynamic output reallocation with IDecoder
The output surface CAN be changed inbetween calls to
WebPIUpdate() or WebPIAppend(), but with precautions.

Change-Id: I899afbd95738a6a8e0e7000f8daef3e74c99ddd8
(cherry picked from commit ff885bfe1f)
2013-06-11 15:00:43 -07:00
c22877f70f Add incremental support for extended format files
This applies to images with optional chunks (e.g. images with ALPH
chunk,
ICCP chunk etc). Before this, the incremental decoding used to work like
non-incremental decoding for such files, that is, no rows were decoded
until
all data was available.

The change is in 2 parts:
- During optional chunk parsing, don't wait for the full VP8/VP8L chunk.
- Remap 'alpha_data' pointer whenever a new buffer is allocated/used in
WebPIAppend() and WebPIUpdate().

Change-Id: I6cfd6ca1f334b9c6610fcbf662cd85fa494f2a91
(cherry picked from commit ead4d47859)
2013-06-11 15:00:42 -07:00
5051245f3a Makefile.vc: have 'all' target build everything
default is still the core examples as makefile.unix

Change-Id: Ica3fe6123f4359aefa130b39d2b0739b65e34c0b
(cherry picked from commit 69d0f92658)
2013-06-11 15:00:42 -07:00
8191decae9 Makefile.vc: flags cleanup
- drop some unnecessary link flags
- use lib.exe directly for creating libraries
- factorize /nologo and use it consistently

Change-Id: Ie76119bc051e9bc53e4d6bba1a0a3f124f9062fc
(cherry picked from commit 52967498b3)
2013-06-11 15:00:42 -07:00
b9d747351a Makefile.vc: drop /FD flag
breaks under wine; from MSDN:
/FD is only used by the development environment, and it should not be
used from the command line or a build script.

Change-Id: I180c9813e721b163cc645b9b7f14fe36556019d3
(cherry picked from commit c61baf0c10)
2013-06-11 15:00:42 -07:00
5568dbcfe6 update gitignore
*.a, new examples and new automake-1.12 file (ar-lib)

Change-Id: I28d7bc59a2977a7c5959940936e3d13a71dd149c
(cherry picked from commit 3a15125d2f)
2013-06-11 15:00:42 -07:00
f4c7b6547b WebPEncode: An additional check.
Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded.

Change-Id: Id1faca3e6def88102329ae2b4974bd4d6d4c4a7a
(cherry picked from commit 67708d6701)
2013-06-11 15:00:42 -07:00
1fb04bec99 pngdec: Avoid a double-free.
Earlier, at line#275, if ok == 0, it would have triggered a double free
of 'rgb'.

Change-Id: Iaee1f35824a66f6e4b488e523416f73b87c5ec30
(cherry picked from commit b68912af2c)
2013-06-11 15:00:42 -07:00
dcbb1ca54a add WebPBlendAlpha() function to blend colors against background
new option: -blend_alpha 0xrrggbb
also: don't force picture.use_argb value for lossless. Instead,
delay the YUVA<->ARGB conversion till WebPEncode() is called.
This make the blending more accurate when source is ARGB
and lossy compression is used (YUVA).
This has an effect on cropping/rescaling. E.g. for PNG, these
are now done in ARGB colorspace instead of YUV when lossy compression
is used.

Change-Id: I18571f1b1179881737a8dbd23ad0aa8cddae3c6b
(cherry picked from commit e7d9548c9b)
2013-06-11 15:00:41 -07:00
bc9f5fbe0f configure.ac: add AM_PROG_AR for automake >= 1.12
fixes:
automake-1.12/am/ltlibrary.am: warning: 'libwebp.la': linking libtool libraries using a non-POSIX
automake-1.12/am/ltlibrary.am: archiver requires 'AM_PROG_AR' in 'configure.ac'

Change-Id: I223f93e5f075aaf23cfefceef55e2ab8eeb34ccd
(cherry picked from commit ed4dc71769)
2013-06-11 15:00:41 -07:00
bf867bf296 Tuned cross_color parameter (step) for lower qual
Tuned the cross_color transform parameter (step) for lower quality
levels. This change gives speedup of 20% at lower qualities (25) and 10% at
moderate quality level (50) with a loss of 0.25% in compression density.
Also removed TODO for cross_color transform. Observed good correlation of
this with the predict transform.

Change-Id: I8a1044e9f24e6a5f84295c030fd444d0eec7d154
2013-06-11 12:15:07 -07:00
90e2ec5a1b Merge "probe input file and quick-check for WebP format." 2013-06-10 12:29:58 -07:00
7180d7ffbd Merge "update copyright text" 2013-06-10 12:23:44 -07:00
830f72b7e9 probe input file and quick-check for WebP format.
Error message is clearer that 'can't create demux object'.

Change-Id: Iec008601892f7cd8399e1948751747ac23305eef
2013-06-10 05:46:22 -07:00
2ccf58d648 configure: improve gl/glut library test
add a check for a libGL function (glOrtho) in addition to glutMainLoop
when establishing the need for libGL at link time.

fixes vwebp link failure on ubuntu 13.04+

Change-Id: I537e9a5cab5cf4cd8875e06268d2107f377e625e
2013-06-07 20:15:53 -07:00
d640614d54 update copyright text
rather than symlink the webm/vpx terms, use the same header as libvpx to
reference in-tree files

based on the discussion in:
https://codereview.chromium.org/12771026/

Change-Id: Ia3067ecddefaa7ee01550136e00f7b3f086d4af4
2013-06-06 23:09:14 -07:00
c2113ad4f9 Merge "configure: remove use of AS_VAR_APPEND" 2013-06-06 00:23:29 -07:00
9326a56f8d configure: remove use of AS_VAR_APPEND
This wasn't used often and benefits were likely minimal. Dropping it
outright is a bit simpler than adding a compatibility ifdef.

provides some compatibility with older versions of autoconf.
tested with autoconf 2.59/automake 1.7/aclocal 1.7

Change-Id: Ifed892346cf2329597985704830a96fc58d65607
2013-06-06 00:14:02 -07:00
ea63d61937 fix a type warning on VS9 x86
"warning C4244: 'function' : conversion from 'uint64_t' to 'size_t', possible loss of data"

Change-Id: Ibd9f6a24993518d658d08127d616a17d7b99e0e4
2013-06-05 10:14:04 +02:00
bec11092ca fix EXIF parsing in PNG
'exiftool' puts an 'APP1' chunk for exif, e.g.:
https://metacpan.org/source/EXIFTOOL/Image-ExifTool-5.87/lib/Image/ExifTool/PNG.pm#L305

Change-Id: I313d3e6945898526b8a4baf3d9016a2591a1a817
2013-06-05 10:07:48 +02:00
b6e65f3d35 Merge "fix warnings for vs9 x64" 2013-06-03 22:27:03 -07:00
438946dcc6 fix warnings for vs9 x64
Change-Id: Id022d48a0a898a8bf7dce437b078da6c98afd75c
2013-06-01 22:48:08 -07:00
f4710e3b89 collect macroblock reconstruction data in VP8MBData struct
This is to better separate bitstream parsing from reconstruction.

Change-Id: I872b58e9940c4b14f72ebee50fba545468ff754c
2013-05-31 22:38:12 +02:00
23d28e216d add doc precision for WebPPictureCopy() and WebPPictureView()
output picture object is overwritten, not free'd or destroyed.

Change-Id: Ibb47ab444063e7ad90ff3d296260807ffe7ddbf9
2013-05-31 10:41:19 +02:00
518f2cd738 cosmetics: gif2webp: fix indent
Change-Id: I9b7aaefb33b4101bcb572577ce17fb3953599c2b
2013-05-29 16:00:05 -07:00
af358e68ed Merge "remove datatype qualifier for vmnv" 2013-05-23 06:12:06 -07:00
3fe91635df remove datatype qualifier for vmnv
this fix is for clang (LLVM v4.2). gcc was fine.

Change-Id: Id4076cda84813f6f9548a01775b094cff22b4be9
2013-05-23 13:52:24 +02:00
764fdffaac fix a memory leak in gif2webp
(rgba->yuv allocates memory)
Also fixed few warning and cleaned the code up.

Change-Id: Id904ad3ad8802ea9fc3d34247d27193dfa7b0b99
2013-05-22 23:49:24 +02:00
3e59a74d72 fix two minor memory leaks in webpmux
(only occur in case of error)

Change-Id: Icab69bb364b77f8eae6cae91047354c27e610602
2013-05-22 00:58:53 +02:00
47b9862f30 Merge "README: update swig notes" 2013-05-21 15:09:30 -07:00
325d15ff30 remove some cruft from swig/libwebp.jar
picked up a few unnecessary classes from a dirty tree in the last commit

Change-Id: I98be16a0bc8716476ce440da542d113f254aee78
2013-05-21 15:01:15 -07:00
4a7627c215 README: update swig notes
add python, required version notes

Change-Id: Iec2e94075f6cf54455ce5a658f9b7258109f4d01
2013-05-21 14:58:32 -07:00
5da81e3383 Merge "swig/python: add minimal documentation" 2013-05-21 14:49:46 -07:00
f39e08f2e3 Merge "swig: add python encode support" 2013-05-21 14:48:36 -07:00
6ca4a3e385 Merge "swig/java: reduce wrapper function code duplication" 2013-05-21 14:44:16 -07:00
8f8702b034 Merge "swig/java: rework uint8_t typemap" 2013-05-21 14:42:58 -07:00
91413be2f9 reduce memory for VP8MB and remove bitfields use
~1% faster on ARMv7

Change-Id: I3e3524e0c25ebd31a04269aae0d304932f1a781a
2013-05-21 23:20:04 +02:00
7413394e7f Fix the memory leak in ApplyFilters.
Change-Id: Iba1b1adf3088ea9c43e4f602a93e77450f6c6170
2013-05-21 14:00:26 -07:00
2053c2cff2 simplify the alpha-filter testing loop
Change-Id: Iacebae749c37edc87a3c94c76cd589a2565ee642
2013-05-21 10:29:27 +02:00
825b64db53 swig/python: add minimal documentation
uses autodoc to display the function arguments rather than the
inscrutable va_args (*args).

Change-Id: Iec2ff8276c1533b14c3032836d822fbdae632521
2013-05-20 17:14:51 -07:00
14677e11d4 swig: add python encode support
wraps the simple interface similar to java.

Change-Id: Ib922bbcae322b2345b6dce5dee08faad705a77fd
2013-05-20 17:14:50 -07:00
a5c297c842 swig/java: reduce wrapper function code duplication
define a macro to emit the wrapper code

Change-Id: I672416016162d6d9ce6f455d224044e0837e3ace
2013-05-20 17:13:27 -07:00
ad4a367dba swig/java: rework uint8_t typemap
reuse the declarations from arrays_java.i for signed char to make an
explicit uint8_t mapping. this avoids sign conversion build warnings.

Change-Id: Icfb5b865cf1fd404e89f2cd889111f0a94e3c604
2013-05-20 13:16:14 -07:00
0d25876bad use uint8_t for inv_palette[]
Change-Id: I5005ce68d89bfb657d46ad8acc4368c29fa0c4fd
2013-05-18 17:13:58 +02:00
afa3450c11 Fix the bug in ApplyPalette.
The auto-infer logic of detecting the 'Alpha' use case
(via check '(palette[i] & 0x00ff00ffu) != 0' is failing
for this corner case image with all black pixels (rgb = 0)
and different Alpha values.

-> switch generic use-LUT detection

Change-Id: I982a8b28c8bcc43e3dc68ac358f978a4bcc14c36
2013-05-18 17:03:18 +02:00
2d6ac422cf Merge "webp/lossless: fix big endian BGRA output" 2013-05-17 00:36:15 -07:00
2ca83968ae webp/lossless: fix big endian BGRA output
Change-Id: I3d4b3d21f561cb526dbe7697a31ea847d3e8b2c1
2013-05-17 00:32:01 -07:00
742110ccce Speed up ApplyPalette for ARGB pixels.
Added 1 pixel cache for palette colors for faster lookup.
This will speedup images that require ApplyPalette by 6.5% for lossless
compression.

Change-Id: Id0c5174d797ffabdb09905c2ba76e60601b686f8
2013-05-16 15:44:21 -07:00
2451e47dca misc code cleanup
* remove dec->skip_
* fix some naming

(no speed diff observed)

Change-Id: I12545ef79d29dd6f893c344d8fb171b0a8c7cc46
2013-05-15 20:03:15 +02:00
83db404390 Merge "swig: add python (decode) support" 2013-05-15 00:42:36 -07:00
eeeea8b530 Merge "swig: cosmetics" 2013-05-15 00:42:08 -07:00
d5f9b8f383 Merge "libwebp: fix vp8 encoder mem alloc offsetting" 2013-05-15 00:41:14 -07:00
d8edd83551 libwebp: fix vp8 encoder mem alloc offsetting
'mem' was being offset once by DO_ALIGN() then shifted 'nz_size' which
would end up accounting for more than ALIGN_CST and exceed the allocation.

broken since:
  9bf3129 align VP8Encoder::nz_ allocation

Change-Id: I04a4e0bbf80d909253ce057f8550ed98e0cf1054
2013-05-15 00:31:23 -07:00
8983b83ee1 remove use of bit-fields in VP8FInfo
(in favor of just plain uint8_t's)

Change-Id: I6187587a4d8a9f5c304a132d98ec42ce24fd244a
2013-05-15 09:21:30 +02:00
87a4fca25f remove some warnings:
* "declaration of ‘index’ shadows a global declaration [-Wshadow]"
* "signed and unsigned type in conditional expression [-Wsign-compare]"

Change-Id: I891182d919b18b6c84048486e0385027bd93b57d
2013-05-14 22:28:32 +02:00
ba8f74e229 Merge "fix for big-endian" 2013-05-14 01:58:06 -07:00
a65067fa77 Merge "Further reduce memory to decode lossy+alpha images" 2013-05-14 01:56:54 -07:00
64c844863a Further reduce memory to decode lossy+alpha images
Earlier such images were using roughly 9 * width * height bytes for
decoding. Now, they take 6 * width * height memory.

Change-Id: Ie4a681ca5074d96d64f30b2597fafdca648dd8f7
2013-05-13 16:24:49 -07:00
332130b9b3 Mux: make a few methods static
Change-Id: I8a8b0b403116c89933e84c93502a8230026f819e
2013-05-13 13:26:33 -07:00
4437061735 fix for big-endian
(Issue #150: https://code.google.com/p/webp/issues/detail?id=150)

Change-Id: Iad46d375a8c5eabae37cde8f55b3e7448601f264
2013-05-13 10:19:29 -07:00
5199eab516 Merge "add uncompressed TIFF output support" 2013-05-13 08:59:48 -07:00
a3aede9739 add uncompressed TIFF output support
new option: 'dwebp -tiff ...'
This is a very simple uncompressed-tiff writing method.

Change-Id: Ie2182c8498bce570de3cde363abe1099e18596cb
2013-05-11 01:46:24 -07:00
f975b67f66 Merge "gif2webp: Fix signed/unsigned comparison mismatch" 2013-05-11 00:53:20 -07:00
5fbc734b90 Merge "GetFeatures: Detect invalid VP8X/VP8/VP8L data" 2013-05-11 00:51:39 -07:00
d5060c873c Merge "mux.h: A comment fix + some consistency fixes" 2013-05-11 00:41:35 -07:00
352d0dee99 GetFeatures: Detect invalid VP8X/VP8/VP8L data
This facilitates early error detection during decode/render.
Also, related refactoring.

Change-Id: Ia6c7cd91dec202a2a68dae2118f5981cf1eaa83d
2013-05-10 14:27:11 -07:00
3ef79fefec Cosmetic: "width * height"
Change-Id: I567c0d95355160a9f6721f949b38e2b8b6270b7a
2013-05-10 13:39:58 -07:00
043e1ae4bd gif2webp: Fix signed/unsigned comparison mismatch
Change-Id: I355f0614424276550db71b24e5bb1948e5c6894c
2013-05-10 13:37:20 -07:00
5818cff770 mux.h: A comment fix + some consistency fixes
Change-Id: I0aee1090322bac3ae3dabf9a48661cbb6de3ca52
2013-05-10 13:35:16 -07:00
1153f888c9 Merge "swig: ifdef some Java specific code" 2013-05-10 02:00:02 -07:00
3eeedae1bc Makefile.vc: fix libwebpdemux dll variable typo
Fixes issue #149

Patch by: Jason Stevens  (cypher497 at gmail dot com)

Change-Id: I65cceaad37d22b96e5e92cb78f859fc0b7c38b67
2013-05-09 23:49:39 -07:00
f980faf417 swig: add python (decode) support
similar to Java, simple interface only

Change-Id: I8a3d344e5d89f73627e4e0cb2067512260d46fdd
2013-05-09 23:29:35 -07:00
7f5f42bb36 swig: cosmetics
normalize formatting
- update decode prototypes
- match project function name style

Change-Id: Ib481b5602171b72dbb1a5d462e6d5166e9b8566e
2013-05-08 18:00:30 -07:00
8eae188a62 WebP-Lossless encoding improvements.
Lossy (with Alpha) image compression gets 2.3X speedup.
Compressing lossless images is 20%-40% faster now.

Change-Id: I41f0225838b48ae5c60b1effd1b0de72fecb3ae6
2013-05-08 17:22:11 -07:00
c7247c4c68 swig: ifdef some Java specific code
no implementation change

Change-Id: I077c707e1f6293188e6fa11ba24757009a709f77
2013-05-08 17:13:40 -07:00
4cb234d5b5 Merge "Mux: make ValidateForSingleImage() method static" 2013-05-08 01:54:28 -07:00
ed6f53086b Merge "Add GetCanvasSize() method to mux" 2013-05-08 01:53:22 -07:00
1d530c9a7e Mux: make ValidateForSingleImage() method static
Change-Id: I96ac5e3be26b8e8ecd9f055501a5feb7710bc324
2013-05-07 12:57:51 -07:00
bba4c2b2a6 configure: add warning related flags
adds TEST_AND_ADD_CFLAGS function
uses AM_CFLAGS to allow CFLAGS override

Change-Id: I9352aec6e5d905a41d832bf5ad0c8dcd154f7e97
2013-05-07 12:48:12 -07:00
fffefd18c3 Add GetCanvasSize() method to mux
Change-Id: If910f5024f4c301a92e6c2e8ee9c315a103c5df7
2013-05-07 12:47:48 -07:00
732da8d0f0 Merge "configure: add GLUT detection; build vwebp" 2013-05-07 12:15:50 -07:00
0e513f7ae3 configure: add GLUT detection; build vwebp
Change-Id: I7f0964db2d04c22ff9ec274e8cd1cbed7379a165
2013-05-07 11:42:15 -07:00
55d1c150ea Merge "Alpha decoding: significantly reduce memory usage" 2013-05-07 09:14:56 -07:00
13d99fb58b Merge "configure: add --enable-everything" 2013-05-07 08:50:57 -07:00
2bf698fe49 Merge "configure.ac: add some helper macros" 2013-05-07 08:49:21 -07:00
edccd19436 Alpha decoding: significantly reduce memory usage
Simply get rid of an intermediate buffer of size width x height, by
using the fact that stride == width in this case.

Change-Id: I92376a2561a3beb6e723e8bcf7340c7f348e02c2
2013-05-02 18:24:46 -07:00
3cafcc9a8d configure: add --enable-everything
Change-Id: Ie1b3abd42459de7f789fe985759c465c2a196727
2013-05-01 18:25:00 -07:00
4ef1447792 configure.ac: add some helper macros
library check related variable maintenance -> *_INCLUDES / *_LIBS

CLEAR_LIBVARS / LIBCHECK_PROLOGUE / LIBCHECK_EPILOGUE

Change-Id: I72e292dc1f69b02f69a26639308f247db0471e2b
2013-05-01 18:24:49 -07:00
a4e1cdbbe8 Remove the gcc compilation comments
They went out of sync some time ago, and are
no longer really required since we have them
buildable from makefile.unix

Change-Id: Ica2dcf5c55f44365598f832f55204d123d7aa601
2013-05-01 15:01:37 -07:00
6393fe4b7c Cosmetic fixes
Change-Id: I7d5a337077ba1d0406769190fef9b47146ed8b24
2013-04-26 15:55:42 -07:00
9c4ce971a8 Simplify forward-WHT + SSE2 version
no precision loss observed
speed is not really faster (0.5% at max), as forward-WHT isn't called often.

also: replaced a "int << 3" (undefined by C-spec) by a "int * 8"
( supersedes https://gerrit.chromium.org/gerrit/#/c/48739/ )

Change-Id: I2d980ec2f20f4ff6be5636105ff4f1c70ffde401
2013-04-26 08:57:18 +02:00
878b9da5bf fix missed optim
it's not often the case, but could happen, that chroma has non-zero
coeff but luma hasn't. In such case, we should skip luma right away

Change-Id: I9515573ffaec8aad8b069d2c02ffbda4a6eff97c
2013-04-25 22:46:12 +02:00
00046171a5 VP8GetInfo(): Check for zero width or height.
Change-Id: I0bf40621ed0776e1a185ad8abab5a914a3d29d69
2013-04-25 12:08:40 -07:00
9bf312938f align VP8Encoder::nz_ allocation
prevents unaligned uint32_t load/store

Change-Id: I3f5e1b434a7452f618009d5e4bbe4f3260e3e321
2013-04-25 02:55:39 -07:00
5da165cfad fix CheckMode() signature
should have been 'const VP8Decoder* const dec', but actually
we just need to pass mb_x_ and mb_y_

Change-Id: I21ca0d67ab33302d6eaa45698d53ed6c2de76981
2013-04-24 14:33:44 +02:00
0ece07dcb1 Merge "explicitly pad bitfields to 32-bits" 2013-04-22 13:13:29 -07:00
9dbc9d1909 explicitly pad bitfields to 32-bits
suggested by fbarchard@chromium; may affect alignment in some cases

Change-Id: I63552eb1a0f9e81754d30ce6e9b1cfe5748bdbc9
2013-04-22 13:00:28 -07:00
5369a80fd4 Merge "prevent signed int overflow in left shift ops" 2013-04-19 00:13:16 -07:00
70e3971260 Merge "cosmetics: remove unnecessary ';'s" 2013-04-19 00:11:10 -07:00
d3136ce27d Merge "don't forward declare enums" 2013-04-19 00:10:39 -07:00
b26e5ad540 gif2webp: Fix ICC and XMP support
Change-Id: Ib5aafef388bd191610e4cc2f8180f35cd454f1d3
2013-04-18 14:19:25 -07:00
46089b207d Add missing name to AUTHORS
Change-Id: I00092e5bb676b48abc05b94080b589b48c911c82
2013-04-18 11:29:36 +02:00
94328d6457 Demux: Fix a potential memleak
Change-Id: Ic0dcac010da088b791c130be4abacdd8c31e92cf
2013-04-16 14:13:45 -07:00
96e948d7b0 don't forward declare enums
doing so is not part of ISO C; removes some pedantic warnings

Change-Id: I739ad8c5cacc133e2546e9f45c0db9d92fb93d7e
2013-04-13 11:08:42 -07:00
f4f90880a8 prevent signed int overflow in left shift ops
force unsigned when shifting by 24.

Change-Id: Ie229d252e2e4078107cd705b09397e686a321ffd
2013-04-13 10:57:31 -07:00
0261545e0b cosmetics: remove unnecessary ';'s
Change-Id: I5fefd9a5b2fe3795c2b5d785c30335b85bac0b43
2013-04-13 10:49:35 -07:00
7ebdf110af Merge "Fix few missing comparisons to NULL" 2013-04-13 10:42:51 -07:00
1579989e7b Fix few missing comparisons to NULL
Change-Id: I0d2ff8e8b507d17e80669b2b59fd5b017af995ed
2013-04-13 10:36:33 -07:00
ea1b21cfdb Cleaned up VP8GetHeaders() so that it parses only frame header
Removed a call to WebPParseHeaders() inside VP8GetHeaders(). This was not needed
anyway, as all call flows already call WebPParseHeaders() before calling
VP8GetHeaders().

This avoids duplicate calls to WebPParseHeaders().

Change-Id: Icb2d618bd26c44220d956c17a69c9c45a62d5237
2013-04-11 11:35:18 -07:00
b66caee410 dwebp: add support for BMP output
Supports alpha output too.

Change-Id: I42ea0bf7b6bbb420f0e537d372a3b13fe00528a9
2013-04-09 18:52:34 -07:00
ff885bfe1f add precision about dynamic output reallocation with IDecoder
The output surface CAN be changed inbetween calls to
WebPIUpdate() or WebPIAppend(), but with precautions.

Change-Id: I899afbd95738a6a8e0e7000f8daef3e74c99ddd8
2013-04-09 18:05:11 -07:00
79241d5a0d Merge "Makefile.vc: have 'all' target build everything" 2013-04-09 14:02:22 -07:00
ac1c729bd8 Merge "Makefile.vc: flags cleanup" 2013-04-08 17:21:24 -07:00
118a055c3d Merge "Makefile.vc: drop /FD flag" 2013-04-08 17:20:32 -07:00
ecad0109d5 Merge "update gitignore" 2013-04-08 17:20:02 -07:00
a681b4f4e5 Rename PRE_VP8 state to WEBP_HEADER
Also, rename state VP8_FRAME_HEADER to VP8_HEADER (to be consistent with
VP8L_HEADER).

Change-Id: Ief2d2f483e36d37f00d8d0db87026ad059f27327
2013-04-08 14:46:05 -07:00
ead4d47859 Add incremental support for extended format files
This applies to images with optional chunks (e.g. images with ALPH
chunk,
ICCP chunk etc). Before this, the incremental decoding used to work like
non-incremental decoding for such files, that is, no rows were decoded
until
all data was available.

The change is in 2 parts:
- During optional chunk parsing, don't wait for the full VP8/VP8L chunk.
- Remap 'alpha_data' pointer whenever a new buffer is allocated/used in
WebPIAppend() and WebPIUpdate().

Change-Id: I6cfd6ca1f334b9c6610fcbf662cd85fa494f2a91
2013-04-08 14:29:14 -07:00
69d0f92658 Makefile.vc: have 'all' target build everything
default is still the core examples as makefile.unix

Change-Id: Ica3fe6123f4359aefa130b39d2b0739b65e34c0b
2013-04-05 19:21:01 -07:00
52967498b3 Makefile.vc: flags cleanup
- drop some unnecessary link flags
- use lib.exe directly for creating libraries
- factorize /nologo and use it consistently

Change-Id: Ie76119bc051e9bc53e4d6bba1a0a3f124f9062fc
2013-04-05 18:47:18 -07:00
c61baf0c10 Makefile.vc: drop /FD flag
breaks under wine; from MSDN:
/FD is only used by the development environment, and it should not be
used from the command line or a build script.

Change-Id: I180c9813e721b163cc645b9b7f14fe36556019d3
2013-04-05 14:54:05 -07:00
3a15125d2f update gitignore
*.a, new examples and new automake-1.12 file (ar-lib)

Change-Id: I28d7bc59a2977a7c5959940936e3d13a71dd149c
2013-04-05 14:51:02 -07:00
5167ca4759 Merge "WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded." 2013-04-05 12:00:46 -07:00
67708d6701 WebPEncode: An additional check.
Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded.

Change-Id: Id1faca3e6def88102329ae2b4974bd4d6d4c4a7a
2013-04-05 11:33:44 -07:00
b68912af2c pngdec: Avoid a double-free.
Earlier, at line#275, if ok == 0, it would have triggered a double free
of 'rgb'.

Change-Id: Iaee1f35824a66f6e4b488e523416f73b87c5ec30
2013-04-05 11:24:59 -07:00
82abbe12fb Merge "configure.ac: add AM_PROG_AR for automake >= 1.12" 2013-04-04 20:09:00 -07:00
e7d9548c9b add WebPBlendAlpha() function to blend colors against background
new option: -blend_alpha 0xrrggbb
also: don't force picture.use_argb value for lossless. Instead,
delay the YUVA<->ARGB conversion till WebPEncode() is called.
This make the blending more accurate when source is ARGB
and lossy compression is used (YUVA).
This has an effect on cropping/rescaling. E.g. for PNG, these
are now done in ARGB colorspace instead of YUV when lossy compression
is used.

Change-Id: I18571f1b1179881737a8dbd23ad0aa8cddae3c6b
2013-04-02 19:14:30 -07:00
ed4dc71769 configure.ac: add AM_PROG_AR for automake >= 1.12
fixes:
automake-1.12/am/ltlibrary.am: warning: 'libwebp.la': linking libtool libraries using a non-POSIX
automake-1.12/am/ltlibrary.am: archiver requires 'AM_PROG_AR' in 'configure.ac'

Change-Id: I223f93e5f075aaf23cfefceef55e2ab8eeb34ccd
2013-04-02 18:45:02 -07:00
df4a406d8d Merge branch '0.3.0'
* 0.3.0: (65 commits)
  Update ChangeLog
  Cosmetic fixes
  misc style fix
  add missing YUVA->ARGB automatic conversion in WebPEncode()
  Container spec: Clarify frame disposal
  container doc: add a note about the 'ANMF' payload
  Container spec: clarify the background color field
  container doc: move RIFF description to own section
  libwebp/mux: fix double free
  use WebPDataCopy() instead of re-coding it.
  demux: keep a frame tail pointer; used in AddFrame
  add doc precision about WebPParseHeaders() return codes
  gif2webp: Bgcolor fix for a special case
  fix bad saturation order in QuantizeBlock
  vwebp/animation: fix background dispose
  Makefile.vc: fix dynamic builds
  update ChangeLog
  examples: don't use C99 %zu
  update ChangeLog
  update NEWS
  ...

Conflicts:
	src/webp/format_constants.h

Change-Id: Ie659644d3ea5592cde64ec3af90a00cd17838247
2013-04-01 19:11:52 -07:00
1e0d4b8c8b Update ChangeLog
Change-Id: I381ab93458df3d1851aec36161cc4b2cbd1265be
2013-03-29 15:55:16 -07:00
d52b405dbd Cosmetic fixes
Change-Id: Ia878115086edc3fdfee3f0ca76e5e74ea5906f21
(cherry picked from commit e9a7990bc5)
2013-03-29 15:49:15 -07:00
6cb4a61825 misc style fix
(cherry picked from commit 142c46291e)

Conflicts:
	src/webp/format_constants.h

Change-Id: Ib764cb09bd78ab6e72c60f495d55b752ad4dbe4d
2013-03-29 15:49:05 -07:00
68111ab02f add missing YUVA->ARGB automatic conversion in WebPEncode()
user can now call WebPEncode() with any YUVA or ARGB format, for
lossy or lossless compression

also: simplified error reporting, which is done in WebPPictureARGBToYUVA()
and WebPPictureYUVAToARGB()

Change-Id: Ifb68909217175bcf5a050e5c68d06de9849468f7
(cherry picked from commit 07d87bda1b)
2013-03-29 15:33:14 -07:00
e9a7990bc5 Cosmetic fixes
Change-Id: Ia878115086edc3fdfee3f0ca76e5e74ea5906f21
2013-03-29 14:21:56 -07:00
403bfe820c Container spec: Clarify frame disposal
- Add a note that disposal only applies to the frame rectangle
- Add the formula for alpha-blending.
- Note that alpha-blending would occur for the common rectangle
- Also note the case when both color profile and disposal are
present.

Change-Id: I214787dd64453edf3b0cdaff3951015281a32ee4
2013-03-29 11:42:17 -07:00
2aaa423b20 Merge "add missing YUVA->ARGB automatic conversion in WebPEncode()" 2013-03-29 11:39:04 -07:00
07d87bda1b add missing YUVA->ARGB automatic conversion in WebPEncode()
user can now call WebPEncode() with any YUVA or ARGB format, for
lossy or lossless compression

also: simplified error reporting, which is done in WebPPictureARGBToYUVA()
and WebPPictureYUVAToARGB()

Change-Id: Ifb68909217175bcf5a050e5c68d06de9849468f7
2013-03-29 04:31:37 -07:00
142c46291e misc style fix
Change-Id: Ib764cb09bd78ab6e72c60f495d55b752ad4dbe4d
2013-03-29 03:13:43 -07:00
3e7a13a008 Merge "Container spec: clarify the background color field" into 0.3.0 2013-03-26 17:38:07 -07:00
14af77452b container doc: add a note about the 'ANMF' payload
this consists of padded chunks, so ANMF should require none

Change-Id: I5dff623b56d8a466dc9be03ee87d1d2d19efc088
2013-03-26 17:25:27 -07:00
cc635efa01 Container spec: clarify the background color field
Change-Id: I03f634cbd147c2851eb06ddbc7b1014e04e21038
2013-03-26 17:22:18 -07:00
e3e339497e container doc: move RIFF description to own section
- remove some little used terms
- condense file header description
- add description of FourCC

Change-Id: Ia873652f41789811f3fb2ec97182a068ac727961
2013-03-26 17:16:12 -07:00
4299f39852 libwebp/mux: fix double free
transfer ownership of chunk passed in ChunkSetNth(). prevents freeing
the chunk in e.g., MuxImageParse() when a partial assignment (alpha but
no image) has occurred.

Change-Id: Ia69656b04fdf50f098f3816b54abd4e191248de3
2013-03-26 13:31:47 -07:00
33f9a692d9 Merge "demux: keep a frame tail pointer; used in AddFrame" into 0.3.0 2013-03-26 13:30:10 -07:00
a2a7b95916 use WebPDataCopy() instead of re-coding it.
also: fix some 0 vs NULL tests

Change-Id: I2b6f65a1e658211e5b4a323c4f9f502744206ec7
2013-03-26 20:40:24 +01:00
6f18f12f99 demux: keep a frame tail pointer; used in AddFrame
this speeds up the parse of a file with a large number of frames.

Change-Id: Ibc61324eb50a04438f811a6f7787d378d763c104
2013-03-26 11:27:51 -07:00
e5af49e9c0 add doc precision about WebPParseHeaders() return codes
Change-Id: I970900f4a5abb4877a716bd4eb15939655ef5dad
2013-03-25 17:54:46 -07:00
db46daab97 Merge "Makefile.vc: fix dynamic builds" into 0.3.0 2013-03-25 16:41:26 -07:00
53c77afc52 Merge "gif2webp: Bgcolor fix for a special case" into 0.3.0 2013-03-25 16:33:51 -07:00
a5ebd143d6 gif2webp: Bgcolor fix for a special case
When transparent color index and background color index are same,
we should set background color to 0x00ffffff (transparent).

For this, we delay setting the background color until we have read the
first frame.

Change-Id: I443609b9c7697a2b94a66992460cff8465b3c127
2013-03-25 16:30:27 -07:00
6378f23876 Merge "vwebp/animation: fix background dispose" into 0.3.0 2013-03-25 16:24:02 -07:00
3c8eb9a806 fix bad saturation order in QuantizeBlock
Saturation was done on input coeff, not quantized one.

This saturation is not absolutely needed: output of FTransformWHT
is in range [-16320, 16321]. At quality 100, max quantization steps is 8,
so the maximal range used by QuantizeBlock() is [-2040, 2040].
But there's some extra bias (mtx->bias_[] and mtx->sharpen_[]) so
it's better to leave this saturation check for now.

addresses issue #145

Change-Id: I4b14f71cdc80c46f9eaadb2a4e8e03d396879d28
2013-03-25 14:53:29 -07:00
04c7a2ecf0 vwebp/animation: fix background dispose
buffer the last frame's details to perform DISPOSE_BACKGROUND on the
image's area, rather than the entire canvas.

also fixes transparent backgrounds with animated images

Change-Id: I53e4d70c441e1eeb136f1d01e7c88de4f9ecff53
2013-03-25 13:39:27 -07:00
81a50695de Makefile.vc: fix dynamic builds
broken since:
e2feefa Makefile.vc: split mux into separate lib

broken even more since:
b65c4b7 Makefile.vc: add libwebpdecoder target

Change-Id: Ibb7a7f2c71ae63434a60d988ce15f0a4ed8fcaee
2013-03-21 19:30:34 -07:00
5f25c396ab update ChangeLog
Change-Id: I52d96e616bb8687f69c6eaa2f28d40939a0e7813
2013-03-20 17:09:12 -07:00
14d42af207 examples: don't use C99 %zu
this would require a PRIuS or similar macro for proper platform
compatibility (Visual Studio for instance would be variants of %lu)

Change-Id: I1af530c7c358c91b845acde1d8c12ef46c2ef746
2013-03-20 16:59:35 -07:00
5ccf1fe540 update ChangeLog
Change-Id: If845005a1d62730d23f7f138ffad4f45acdd2bfe
2013-03-20 15:02:23 -07:00
2560c243f3 update NEWS
Change-Id: Ic17003de4451ae50901b9a9fbffa15f2929561b8
2013-03-20 14:59:58 -07:00
f43bafc3e6 Merge changes Iecccb09c,If5ee9fd2,I3e181ce4 into 0.3.0
* changes:
  dwebp: warn when decoding animated webp's
  Decode: return more meaningful error for animation
  WebPBitstreamFeatures: add has_animation field
2013-03-20 14:56:29 -07:00
a788644f93 dwebp: warn when decoding animated webp's
the decode will fail; provide a bit more background info

Change-Id: Iecccb09cf0fa9f8c1c3e87636a55e1f251dee023
2013-03-20 13:59:38 -07:00
302efcdb41 Decode: return more meaningful error for animation
VP8_STATUS_NOT_ENOUGH_DATA -> VP8_STATUS_UNSUPPORTED_FEATURE

Change-Id: If5ee9fd2c99fc5502996d3c786848fd9cc118fe7
2013-03-20 13:59:22 -07:00
ad452735c3 WebPBitstreamFeatures: add has_animation field
Change-Id: I3e181ce463b0e4833bfd29f8052b21ebe0bca977
2013-03-20 13:49:56 -07:00
783dfa4995 disable FRGM decoding for good in libwebpmux
Change-Id: I2f24d100f93488f6b0bf9ccc5818f9177d73948b
2013-03-20 13:31:14 -07:00
4b956be095 Update ChangeLog
Change-Id: I5f74413ec584442aa824238ccc390a53f9fd8638
2013-03-19 18:12:49 -07:00
ad8b86d707 update NEWS
Change-Id: I72598ecd3e7e6f41f8554c645cf25cd21304fe61
2013-03-19 17:36:38 -07:00
3e084f63f5 Merge "demux cosmetics: comments/rename internal function" into 0.3.0 2013-03-19 17:09:07 -07:00
d3f8c621b5 Merge "move WebPFeatureFlags declaration" into 0.3.0 2013-03-19 17:08:31 -07:00
7386fe5047 Merge "libwebp{demux,mux}: install mux_types.h" into 0.3.0 2013-03-19 17:07:32 -07:00
d6cd4e9056 Merge "bump decode abi" into 0.3.0 2013-03-19 16:52:06 -07:00
17f8da5c51 bump decode abi
treating as a patch number in this case to disambiguate releases.

Change-Id: Ica1379c66473a961f2dcd5f3282281b8bf1bc276
2013-03-19 16:48:56 -07:00
97684ae269 Merge "add doc precision about WebPDemuxPartial()" into 0.3.0 2013-03-19 16:44:26 -07:00
f933fd2a27 move WebPFeatureFlags declaration
from private format_constants.h to public mux_types.h
also do the reverse for MKFOURCC()

Change-Id: I3aa86b007e9dbfed37a170989164ac3a77de2bd5
2013-03-19 16:10:41 -07:00
289bc47b65 libwebp{demux,mux}: install mux_types.h
required by demux.h and mux.h

Change-Id: Ib33cee1d95e575233204e70b62caf7a6366772c7
2013-03-19 14:54:04 -07:00
224e8d4630 add doc precision about WebPDemuxPartial()
it wasn't clear the data can be incomplete

Change-Id: I1482379aaea31e08a65c90f15e32edec2472e17e
2013-03-19 14:25:59 -07:00
4c18e80cf7 demux cosmetics: comments/rename internal function
ParseFrame -> ParseAnimationFrame

Change-Id: I27538927d16285e0793be5be78b0f15f4155dd83
2013-03-19 13:55:29 -07:00
7cfd1bf1fc update AUTHORS
Change-Id: I8d90f49439c04f86e8570ecca25e18339cb46917
2013-03-19 00:26:05 -07:00
401f7b856f Merge "speed-up lossless (~3%) with ad-hoc histogram cost evaluation" into 0.3.0 2013-03-18 17:48:59 -07:00
1fc8ffca35 Merge "makefile.unix: dist related changes" into 0.3.0 2013-03-18 16:53:46 -07:00
8a89c6ed28 Merge changes I466c377f,Ib761ebd3,I694857fc into 0.3.0
* changes:
  gif2webp: only write error messages to stderr
  gif2webp: fix crash on open failure with libgif5
  gif2webp: silence a unused param warning
2013-03-18 16:52:28 -07:00
f4ffb2d59a speed-up lossless (~3%) with ad-hoc histogram cost evaluation
* merge cost calculation functions (BitsEntropy() and HuffmanCost())
* have HistogramAdd() specialized into separate functions
* use threshold to bail-out early
* revamp code a bit

* also: save memory by freeing free(histogram_image)

Change-Id: I8ee5d2cfa1462d5d6ea6361f5c89925a3720ef55
2013-03-18 22:34:32 +01:00
723847d5d7 gif2webp: only write error messages to stderr
also output something if -o is not given, but the process succeeded

Change-Id: I466c377f0cbf8c9f45bb1839191b04dada9c5f0f
2013-03-18 11:13:35 -07:00
701b9e2af4 makefile.unix: dist related changes
* make the 'all' target really build everything (default is still the
    core examples).
  * add demux/mux.h to HDRS_INSTALLED, install the corresponding libs
    too
  * install vwebp, webpmux, gif2webp and related manpages

Change-Id: Ib6036f2a1a05e40f106914c4bdbe9e3ad7336464
2013-03-18 11:10:02 -07:00
bb85b43727 Merge "update NEWS" into 0.3.0 2013-03-17 23:39:21 -07:00
59423a2486 gif2webp: fix crash on open failure with libgif5
output the current gif_error and use it instead of the NULL context to
retrieve an error message.

Change-Id: Ib761ebd36b3ddd6288375de46e671022d2381083
2013-03-17 18:06:39 -07:00
9acb17dea4 gif2webp: silence a unused param warning
Change-Id: I694857fc6adb011f19d14780de4f8c71e2719707
2013-03-17 17:04:54 -07:00
7d9fdc2389 Merge "README updates" into 0.3.0 2013-03-17 02:40:44 -07:00
5621934e82 Merge "build: fix install race on shared headers" into 0.3.0 2013-03-17 02:38:16 -07:00
70809d89bb Merge "bump version to 0.3.0" into 0.3.0 2013-03-17 02:32:37 -07:00
d851cd1d85 demux: make the parse a bit more strict
* VP8L shouldn't have an alpha chunk
 * expect an animation to only contain frames, not a mix of image chunks
 * enforce ANIM/ANMF order
 * expect a full frame in a complete file

Change-Id: I953a8b6058f9bc00f1d042635548f158abdf6fce
2013-03-16 16:37:31 -07:00
28bb4107b1 update NEWS
Change-Id: Icb277027ee6209527d82978ebcec03391940aac2
2013-03-16 15:02:31 -07:00
cef9388283 bump version to 0.3.0
libwebp{,decoder} - 0.3.0
libwebp libtool - 4.2.0 (compatible release)
libwebpdecoder libtool - 0.0.0 (new release)

mux/demux - 0.1.0
libtool - 0.0.0 (new release)

Change-Id: Ied6efa390b2f97f1f41fc8349a365613c639d6cc
2013-03-16 14:08:14 -07:00
9048494df6 build: fix install race on shared headers
subdirectories with more than one target can have the install targets
run in parallel with make -jN. group the shared headers in one place to
produce a common install target.

Change-Id: I1f3aa338a8ee6d681de1e5d0b2c6244d2c3d5451
2013-03-16 13:29:49 -07:00
1e67e8ef9e README updates
* build related notes
  * merge vwebp descriptions
  * miscellaneous cosmetics

Change-Id: Ic4e580127bd2c4dff8e5a81ccb10b15a3568f8b1
2013-03-16 12:35:49 -07:00
42b611a491 Merge "configure: drop experimental from mux/demux" into 0.3.0 2013-03-16 12:05:30 -07:00
096a8e321d Merge "vwebp: add color profile support" into 0.3.0 2013-03-16 11:58:19 -07:00
ddfee5dce5 vwebp: add color profile support
uses qcms from Mozilla / Chromium:

http://hg.mozilla.org/mozilla-central/file/0e7639e3bdfb/gfx/qcms
http://src.chromium.org/viewvc/chrome/trunk/src/third_party/qcms

Change-Id: I674e16adb6ca085719816e984acbf00721b28fb0
2013-03-16 11:55:00 -07:00
0d6927d3cd Merge "Mark fragment options as experimental in webpmux" into 0.3.0 2013-03-16 10:45:52 -07:00
5dbd403029 Mark fragment options as experimental in webpmux
This is to disallow any accidental creation/parsing of fragmented images
by users.

Change-Id: I970a4bd5ec5a522867b24a0c9efb45164ae67047
2013-03-16 04:07:19 -07:00
a0a6648cc2 configure: drop experimental from mux/demux
--enable-libwebpdemux
--enable-libwebpmux

These are going stable with any remaining experimental features under
--enable-experimental

Change-Id: I8da0736438b2a58a2ea58b37b2630911ce300632
2013-03-15 20:55:54 -07:00
ee65bad8f2 Merge "add support for BITS > 32" into 0.3.0 2013-03-15 19:00:14 -07:00
744930dbe2 add support for BITS > 32
on x86_64 desktop, it's a little faster to use BITS=56
on MacOS (/llvm) it's _much_ faster (~10%)

Change-Id: I47c66ab7488341d8d1696d9301954b86b241b36d
2013-03-15 18:37:08 -07:00
7dd288f098 cwebp: fix build
METADATA_ICCP was renamed to METADATA_ICC in
  d8dc72a examples: normalize icc related program arguments
but was merged without rebasing after
  0bc4268 cwebp: output metadata statistics

Change-Id: Ie317208488cc851d5d21300591c91cebf5abd4a7
2013-03-15 16:42:58 -07:00
19a8dd0154 Merge "Makefile.vc: add vwebp.exe target" into 0.3.0 2013-03-15 16:38:40 -07:00
50eeddad3d Merge "examples: normalize icc related program arguments" into 0.3.0 2013-03-15 16:37:30 -07:00
757f637f33 Merge "Makefile.vc: add libwebpdecoder target" into 0.3.0 2013-03-15 16:33:37 -07:00
b65c4b7cbc Makefile.vc: add libwebpdecoder target
Change-Id: I43e5974dd4ec7280ee49d3dd258db227db757064
2013-03-15 16:32:58 -07:00
f8db7b4a05 Merge "vwebp: replace doubles w/floats where appropriate" into 0.3.0 2013-03-15 15:07:09 -07:00
d99aa56fbf Makefile.vc: add vwebp.exe target
Change-Id: I4de63628fef66fe2b1000cbc62c7db28f68c2cb8
2013-03-15 12:18:25 -07:00
013023e771 vwebp: replace doubles w/floats where appropriate
Change-Id: Ief1ef5213a5f357004922989e6e5d97ef3561a23
2013-03-15 12:17:45 -07:00
9b3db89473 README.mux: add version reference
Change-Id: Ic37de8303c4e04ccb7b4964844a1094cf8c737a4
2013-03-14 19:38:02 -07:00
7b6a26cff9 Merge "cwebp: output metadata statistics" into 0.3.0 2013-03-14 19:09:58 -07:00
d8dc72a039 examples: normalize icc related program arguments
use 'icc' rather than 'iccp'.

Change-Id: I9667f286bfa1cfeb0ac49148ba341d268b051b98
2013-03-14 19:05:22 -07:00
7bfc9056ad Merge "make alpha unfilter work in-place" into 0.3.0 2013-03-14 18:48:45 -07:00
0037b2d280 Merge "add LUT-free reference code for YUV->RGB conversion." into 0.3.0 2013-03-14 18:44:29 -07:00
166bf744b9 Merge "demux: disable fragment parsing" into 0.3.0 2013-03-14 18:39:06 -07:00
126974b45b add LUT-free reference code for YUV->RGB conversion.
Reported to eventually be 4% on ARM
(see https://code.google.com/p/webp/issues/detail?id=134 for details)
We might activate it selectively later...

Output values is not bitwise the same as the LUT-based
version, but difference is only +/-1 at max.

Change-Id: I1cc790ff4459885ed2ae2e72f31c5f3740095f07
2013-03-15 01:37:55 +01:00
0aef3ebdea make alpha unfilter work in-place
* remove a malloc
* remove the unused 'bpp' argument from filter/unfilter functions

Change-Id: I28d78baaaddc20f1d5a3bb2bd0b4e96a12a920d8
2013-03-15 01:36:38 +01:00
14ef5005a2 Merge "Remove 'status: experimental' from container spec" into 0.3.0 2013-03-14 00:04:58 -07:00
d40c98e172 Merge "webpmux binary: tiny style fix" into 0.3.0 2013-03-14 00:02:58 -07:00
0bc42689e4 cwebp: output metadata statistics
Change-Id: Ida33555bab3c9330e82158863c355e51f90d0a76
2013-03-13 22:57:54 -07:00
bc03980336 Merge "autoconf: normalize experimental define" into 0.3.0 2013-03-13 22:24:33 -07:00
d1e21b13b7 Remove 'status: experimental' from container spec
For features that are to be released in v0.3.0.

Change-Id: Ib8961f8cde0474aeaad5796bd0821db812edffcd
2013-03-13 18:16:30 -07:00
7681bb961d webpmux binary: tiny style fix
Change-Id: I195929d79940cd3d060977ef7feee9cd13f7d041
2013-03-13 18:10:56 -07:00
a3dd3d0f9e avoid installing example_util.h
older versions of automake (1.9) it seems would install the headers
regardless of the fact that the library was marked noinst_

this change follows some of the header guidance found here:
http://www.gnu.org/software/automake/manual/automake.html#Headers

Change-Id: I80acc00935097ebf36004e9871574fb9ef09aabf
2013-03-13 15:48:34 -07:00
252320e287 demux: disable fragment parsing
put this feature under WEBP_EXPERIMENTAL_FEATURES

Change-Id: I6405c5e6bed3ad1196aa1d111c83cca4c70c4c41
2013-03-13 13:54:53 -07:00
537bde05cc autoconf: normalize experimental define
EXPERIMENTAL -> WEBP_EXPERIMENTAL_FEATURES
the former is not used in the source; this adds
WEBP_EXPERIMENTAL_FEATURES to config.h

Change-Id: I4822bd3be1ea631e96629ae249dc778cdb5d8bb6
2013-03-13 13:53:02 -07:00
5e338e0b9a Merge changes I33e8a613,I8e8a7b44 into 0.3.0
* changes:
  automake: add reference to libwebp for mux/demux
  libwebp{,decoder}.pc: add pthread flags
2013-03-13 13:17:24 -07:00
d9d0ea1bf9 Merge changes If21e3ec7,I991fc30b into 0.3.0
* changes:
  add libwebpmux.pc
  add libwebpdemux.pc
2013-03-13 12:53:32 -07:00
627f5ca66b automake: add reference to libwebp for mux/demux
this allows DLLs to be built under mingw and sets up a more obvious
dependency in the shared objects

Change-Id: I33e8a6132a16ca49563492438a1b3b74be9ed6a1
2013-03-13 12:29:37 -07:00
eef73d07a3 don't consolidate proba stats too often
adds a minimum count before FinalizeToken() is called for update.

Change-Id: I445be6a3e347620583d87c33067cefa656a25039
2013-03-13 13:50:08 +01:00
05ec4cc2d3 libwebp{,decoder}.pc: add pthread flags
expands to e.g., -lpthread/-pthread, etc. if --enable-threading is used
and additional libs/flags are required

Change-Id: I8e8a7b44450bee32ddc58097e1e309d972b1092a
2013-03-12 23:02:12 -07:00
1bfcf5bf42 add libwebpmux.pc
Change-Id: If21e3ec73f2eb451c6042d1aecda8d03259f601f
2013-03-12 22:58:37 -07:00
26ca843d71 add libwebpdemux.pc
Change-Id: I991fc30b5287016066fae1ba11ec842c88994c41
2013-03-12 22:58:37 -07:00
69e2590642 Merge "Tune Lossless compression for lower qualities." 2013-03-12 22:08:29 -07:00
0478b5d214 Tune Lossless compression for lower qualities.
This is required for WebP lossy+Alpha images, where Alpha channel is taking
60-70% of the compression (CPU) cycles.

Also evaluated on 1000 PNG corpus and overall compression speed
is 15-40% better for lossy (PNG+Alpha) compression.
The pure lossless compression numbers are almost same (or little
better) with this change.

Change-Id: I9e5ae7372ed6227a9a5b64cd9cff84c747195a57
2013-03-12 14:17:28 -07:00
39f7586f31 add a mention of parallel alpha encoding in the NEWS
Change-Id: I3ef53fab45069b874faaa853c6f6c188e999ffda
2013-03-11 17:14:25 -07:00
5a21d96741 Merge "1.5x-2x faster encoding for method 3 and up" 2013-03-11 17:14:18 -07:00
9bfbdd144f 1.5x-2x faster encoding for method 3 and up
using token-buffer (that is: slightly more memory. O(output_size))

This change is ON by default. To return to previous behaviour, use
'cwebp -low_memory' or set config.low_memory to true.

Side-effect of this new mode: it forces 1 partition only (which was
default anyway), and makes some statistics about the bitstream
no longer available. cwebp will no longer report 'intra4-coeffs', etc.

This mode also doesn't work (yet) with multi-pass, and -low_memory
is currently forced for multi-pass.

also: reversed the flag: USE_TOKEN_BUFFER -> DISABLE_TOKEN_BUFFER
also: fixed the kAverageBytesPerMB estimate

Change-Id: I4ea80382038d6df4309663e0cb7bd88d9bca9cf1
2013-03-11 17:01:33 -07:00
27dc741bda Correct frame options order in README.mux
Change-Id: Ia65f5f0f0d0fc50c3b360cd010112ae5ecece91a
2013-03-11 13:58:34 -07:00
be2fd1735a Mux: fix a scenario with bad ANMF/FRGM size
When a ANMF/FRGM chunk size (read from file) is smaller than ANMF/FRGM header
size (which is constant and implicit), the parser should report an error.

Change-Id: I91d71889937f5133a97f1e83d5254cb2d7f37028
2013-03-08 17:34:20 -08:00
19eb012c55 Merge "Demux: Add option to get frame count using GetI()" 2013-03-08 16:11:37 -08:00
7368b8cbb2 Merge "WebPGetFeatures() out of if condition for clarity." 2013-03-08 16:07:47 -08:00
f604c9a4a2 Merge "fix windows build" 2013-03-08 15:51:07 -08:00
153f94e8b5 fix windows build
broken since:
ad25032 Merge "multi-threaded alpha encoding for lossy"

this produced an error due to an empty VP8TBuffer struct.

Change-Id: I640809d07d20092c1d660e2b59b58a62a12e4371
2013-03-08 15:50:04 -08:00
847b49243e Merge "vwebp: use magenta for 'i'nfo display" 2013-03-08 05:17:57 -08:00
25ea46bdee Merge "vwebp: add keyboard shortcuts to help output" 2013-03-08 05:15:17 -08:00
bea7ccaffd vwebp: use magenta for 'i'nfo display
replaces black

Change-Id: I8ca52c187c7b4b890378dec2a526e51c7819f7e1
2013-03-07 19:42:41 -08:00
8fab161a3f webpmux: correct -frame param order in help output
params were reordered to +duration+x offset+...

Change-Id: I99e8a70c8a645552238294ab82c3f7ffe01e70bd
2013-03-07 19:15:37 -08:00
03cc23d6f9 vwebp: add keyboard shortcuts to help output
Change-Id: Ida94b3f99115ddeb6b6eec1411918f99e964ed91
2013-03-07 19:13:00 -08:00
068eba8d58 Demux: Add option to get frame count using GetI()
Also tweak the code for single image and fragmented image cases, so that
dmux->num_frames_ is always correct.

Change-Id: I31e6904222e4d96a54a0d8c8aa73d43b7a9094e7
2013-03-06 13:14:05 -08:00
988b8f56b3 WebPGetFeatures() out of if condition for clarity.
Also, some comment tweaks in decode.h

Change-Id: I9d4e80f2ffdc51d35bd3215486e26448bddd143b
2013-03-05 18:05:12 -08:00
6933d91057 Merge "gif2webp: Be lenient about background color index." 2013-03-05 17:04:16 -08:00
4d0f7c5543 Merge "WebPGetFeatures() behavior change:" 2013-03-05 17:03:20 -08:00
fdeeb01dc6 gif2webp: Be lenient about background color index.
Change-Id: I4440cffff4e8cefb3b0327a9b4925e05a7bbfc50
2013-03-05 13:41:55 -08:00
ad2503203a Merge "multi-threaded alpha encoding for lossy" 2013-03-01 16:00:10 -08:00
4e32d3e1e7 Merge "fix compilation of token.c" 2013-03-01 01:07:56 -08:00
f817930a55 multi-threaded alpha encoding for lossy
new option: 'cwebp -mt ...'
new config flag: config.thread_level
(allowed thread_level are 0 or 1 for now. Maybe more later...)
If -mt is activated (and WEBP_USE_THREAD is used for compile), the alpha-compression
will be done in parallel to RGB coding for lossy. Can save quite a bit of latency...
Has no effect for lossless encoding.

Change-Id: I769d0bf90e7380cf99344ad62cd77277f4df5a46
2013-03-01 10:04:08 +01:00
88050351f4 fix compilation of token.c
(TOKEN_BUFFER still disabled)
also: made VP8TBufferClear() always visible

Change-Id: Iff353fe70b2f3c5b0ab4ef7f143e1d65b0ab2b0d
2013-03-01 09:58:14 +01:00
fc816219e1 code using the actual values for num_parts_, not the ones from config
Change-Id: Icb961c66fe62cb703a12c5ff8a9aa4fc884bac1c
2013-03-01 09:48:33 +01:00
72655350ea Merge "move the config check from .c to .h" 2013-02-28 12:25:53 -08:00
dd9e76f7b4 move the config check from .c to .h
+ minor doc cosmetics

Change-Id: I351ce63f4463fd1c1546f58697440ad01eac860c
2013-02-28 21:23:39 +01:00
956b217a8b WebPGetFeatures() behavior change:
It should return VP8_STATUS_NOT_ENOUGH_DATA when it doesn't have enough
data.

Change-Id: I5acff04f9ba51dab150dc6d137c5ad00ea61c64a
2013-02-27 15:27:43 -08:00
df02e4ce93 WebPDemuxGetI behavior change:
It now returns ALPHA_FLAG for lossless images with alpha, that don't
have a VP8X chunk.

This is consistent with similar methods WebPMuxGetFeatures() and
WebPGetFeatures().

Change-Id: Ia3a4ca8f3e0f102f478bd33e0727ca5be98593df
2013-02-27 11:49:26 -08:00
633c004db1 Merge "rebalance method tools (-m) for methods [0..4]" 2013-02-27 10:20:27 -08:00
58ca6f65b7 rebalance method tools (-m) for methods [0..4]
(methods 5 and 6 are still untouched).

Methods #0 and #1 got much faster
Method #2 gets vastly improved in quality
Method #3 is noticeably faster for little lower quality
Method #4 (default) is 10-20% faster for comparable quality

+ update the internal doc about the methods' tools.

Example of speed difference:

Time to encode picture:
Method | Before | After
-m 0   | 1.272s | 0.517s
-m 1   | 1.295s | 0.623s
-m 2   | 2.217s | 0.834s
-m 3   | 2.816s | 2.243s
-m 4   | 3.235s | 3.014s
-m 5   | 3.668s | 3.654s
-m 6   | 8.296s | 8.235s

Change-Id: Ic41fda5de65066b3a6586cb8ae1ebb0206d47fe0
2013-02-27 02:19:20 -08:00
7648c3ccb8 Merge "describe rd-opt levels introduce VP8RDLevel enum" 2013-02-27 01:45:14 -08:00
67fb1003bf Merge "autoconf: enable silent-rules by default" 2013-02-27 01:43:42 -08:00
a5042a3240 GetVersion() methods for mux and demux
Also use the same in example binaries.

Change-Id: Id4bb4c4231a6b8fe9ed4370a6f46567c52a04a17
2013-02-26 14:22:06 -08:00
5189957e07 describe rd-opt levels introduce VP8RDLevel enum
makes things somehow clearer compared to using magic constants

Change-Id: I9115cee71252511f722806427ee8a97f1a1cd95f
2013-02-26 02:20:59 -08:00
4e094ace8c autoconf: enable silent-rules by default
simplify macro check: use m4_ifdef rather than
m4_define_default/AM_SILENT_RULES

Change-Id: I1746aaa6b22bd6a8c4804e742e1071165094b150
2013-02-25 16:11:14 -08:00
b7eaa85d6a inline VP8LFastLog2() and VP8LFastSLog2 for small values
larger values are still dealt with in the .cc

~5% faster encoding
Output size is slightly different (variably), because of
different floating-point calculation ordering.

Change-Id: I6ede18b09c753997cf78aa1199a807d9ddb5d4b4
2013-02-25 22:46:52 +01:00
5cf7792e40 split quant_levels.c into decoder and encoder version
-> split libraries further into decoder / encoder
-> add libwebpdecoder.a in Makefile.unix
-> make dwebp link against libwebpdecoder.a in Makefile.unix

also: in makefile.unix, pass EXTRA_FLAGS to LDFLAGS too
(otherwise, -m32 wouldn't work, e.g.)

Change-Id: Ief3da02a729dd86bbaf949ed048836716941657f
2013-02-24 21:40:39 +01:00
e5d3ffe275 Merge "Update code example in README.mux" 2013-02-23 00:52:48 -08:00
ac5a9156b1 Update code example in README.mux
As per changes in code example in demux.h

Change-Id: Idb63e854dc2668ba35517ed9622195a12b6942d7
2013-02-22 15:13:10 -08:00
38a91e990b Add example code snippet for demux API
Change-Id: I4e9f32d030dd7f184e1cedf5b37f6f640ba4845e
2013-02-22 14:16:48 -08:00
5f557f3c1b README.mux: add info about Demux API and vwebp
Also use a naming 'extended format' rather than 'container file' to be
consistent with the container specification.

Change-Id: I3b07f95e0244d3534fe17b03f60db22f61e17836
2013-02-21 16:56:48 -08:00
c0ba090335 backward_references: avoid signed integer overflow
signed integer overflow behavior is undefined, split PrefixEncode() to
two branches to avoid this.

Change-Id: I6e2761d0d77f0aaceafdc4e07232e089c22beb64
2013-02-20 13:35:00 -08:00
943386db4b disable SSE2 for now
(until proper run-time detection is ready)

Change-Id: I7b8eee52b23fce2f1612ad7d4ed603ffb02620a2
2013-02-20 08:20:47 +01:00
9479fb7d2d lossless encoding speedup
* add SSE2 variant for lossless
* speed-up TransformColor calls using specialized TransformColorBlue/Red
* Fuse the Shannon Entropy calls to compute it for X and X+Y simultaneously.

This latter changes the output size a little bit.

Change-Id: Ie5df94da78bf51a58da859c9099b56340da9ec89
2013-02-20 08:13:12 +01:00
ec2030a8a2 merge two lines together
Change-Id: I6f7935cfdac52d793ba08b1c050160d3417b8eb0
2013-02-19 23:01:10 -08:00
b67956c037 Merge "Remove ReadOneBit() and ReadSymbolUnsafe()" 2013-02-19 15:16:21 -08:00
1667bded67 Remove ReadOneBit() and ReadSymbolUnsafe()
Simplify and re-organize the VP8L bit-reader functions
(e.g.: the 40-bit look-ahead code was helping much)

Speed-up with LBITS=64, on arm7-a:

=> before:
./dwebp_justify_24_neon -v bryce_ll.webp
Time to decode picture: 11.393s
File bryce_ll.webp can be decoded (dimensions: 11158 x 2156).
...

=> after (LBITS=64):	Time to decode picture: 9.953s

making the VP8L bit-reader in 32 bit mode is going to be
harder (because we need to be able to read two symbols
at a time, each with max length 15 bits)

Change-Id: I89746fb103b87b5e2fd40a3208a6fbc584b88297
2013-02-20 00:13:23 +01:00
3151669b15 wicdec + dwebp cosmetics: normalize formatting
- drop mixed use of Hungarian notation
- fix some line continuations

Change-Id: I9e6ec5cd6c746eb78048cf3532586fd93cef4ddb
2013-02-15 20:39:45 -08:00
92668da6f2 change default filtering parameters:
* type is now 'strong'
  * strength is now '60'

These help with gradients and blocking

Change-Id: Ie1c8265c557306ef5e9ccefacf43e10946e55370
2013-02-15 01:09:32 -08:00
b7490f8553 introduce WEBP_REFERENCE_IMPLEMENTATION compile option
This flag will make the code use no uint64, no asm, and no fancy
trick, but instead aim at being as simple and straightforward as
possible.
Main use is to help emscripten generate proper JS code.
More code needs to be simplified later.

Also: tune the BITS values to be 24 and make use of WEBP_RIGHT_JUSTIFY
Here are the typical timing for decoding a large image:

        ARM7-a:
        dwebp_justify_32_neon Time to decode picture: 3.280s
        dwebp_justify_24_neon Time to decode picture: 2.640s
        dwebp_justify_16_neon Time to decode picture: 2.723s
        dwebp_justify_8_neon Time to decode picture: 2.802s
        dwebp_justify_32 Time to decode picture: 4.264s
        dwebp_justify_24 Time to decode picture: 3.696s
        dwebp_justify_16 Time to decode picture: 3.779s
        dwebp_justify_8 Time to decode picture: 3.834s
        dwebp_32_neon Time to decode picture: 4.010s
        dwebp_24_neon Time to decode picture: 2.725s
        dwebp_16_neon Time to decode picture: 2.852s
        dwebp_8_neon Time to decode picture: 2.778s
        dwebp_32 Time to decode picture: 4.587s
        dwebp_24 Time to decode picture: 3.800s
        dwebp_16 Time to decode picture: 3.902s
        dwebp_8 Time to decode picture: 3.815s
        REFERENCE (HEAD) Time to decode picture: 3.818s

        x86_64:
        dwebp_justify_32 Time to decode picture: 0.473s
        dwebp_justify_24 Time to decode picture: 0.434s
        dwebp_justify_16 Time to decode picture: 0.450s
        dwebp_justify_8 Time to decode picture: 0.467s
        dwebp_32 Time to decode picture: 0.474s
        dwebp_24 Time to decode picture: 0.468s
        dwebp_16 Time to decode picture: 0.468s
        dwebp_8 Time to decode picture: 0.481s
        REFERENCE (HEAD) Time to decode picture: 0.436s

        i386:
        dwebp_justify_32 Time to decode picture: 0.723s
        dwebp_justify_24 Time to decode picture: 0.618s
        dwebp_justify_16 Time to decode picture: 0.626s
        dwebp_justify_8 Time to decode picture: 0.651s
        dwebp_32 Time to decode picture: 0.744s
        dwebp_24 Time to decode picture: 0.627s
        dwebp_16 Time to decode picture: 0.642s
        dwebp_8 Time to decode picture: 0.642s

Change-Id: Ie56c7235733a24f94fbfc2e4351aae36ec39c225
2013-02-14 15:46:12 +01:00
3383885799 faster decoding (3%-6%)
. revamped the boolean decoder to use less shifts
. added some description and ASCII art as explanations too.
. clarified the types further (bit_t, lbit_t, range_t, etc.)
. changed the negative field 'missing_' into positive 'bits_'

Some stats, decoding some randomly encoded WebP files:

with USE_RIGHT_JUSTIFY:
  BITS=32 => 133 files, 50 loops => 7.3s (1.097 ms/file/iterations)
  BITS=24 => 133 files, 50 loops => 7.3s (1.097 ms/file/iterations)
  BITS=16 => 133 files, 50 loops => 7.4s (1.120 ms/file/iterations)
  BITS=8 => 133 files, 50 loops => 7.5s (1.128 ms/file/iterations)

without USE_RIGHT_JUSTIFY:
  BITS=32 => 133 files, 50 loops => 7.5s (1.131 ms/file/iterations)
  BITS=24 => 133 files, 50 loops => 7.6s (1.142 ms/file/iterations)
  BITS=16 => 133 files, 50 loops => 7.6s (1.143 ms/file/iterations)
  BITS=8 => 133 files, 50 loops => 7.6s (1.149 ms/file/iterations)

Change-Id: I9277fb051676c05582e9c7ea3cb5a4b2a3ffb12e
2013-02-14 15:42:58 +01:00
5c3e381b2f Merge "add a -jpeg_like option" 2013-02-13 22:17:58 -08:00
c23110467e remove unused declaration of VP8Zigzag
Change-Id: I80bdf4b692dcdad1fc2b0cfffcaebb5fef5dde34
2013-02-12 07:14:21 -08:00
36152957af Merge "wicdec: add alpha support for paletted formats" 2013-02-06 23:33:24 -08:00
c9f1649012 wicdec: add alpha support for paletted formats
Fixes issue #141.

Change-Id: I5d8163329a9e363da9db9d70d25edeb29da32e9e
2013-02-06 23:29:32 -08:00
1262f81e37 Merge "wicdec: silence some warnings" 2013-02-06 23:21:26 -08:00
e7ea61eb75 wicdec: silence some warnings
-Wformat, -Wmissing-field-initializers and size type related

Change-Id: I92b1c7cc485bf59f94b5c0f8bb2137d87604f831
2013-02-06 23:16:50 -08:00
23c0f354a6 fix missing intptr_t->int cast for MSVC
Change-Id: I39acdfbe287ef7b7f615d59e0729aab161189bf9
2013-02-06 17:51:10 +01:00
e895059a05 add a -jpeg_like option
This option remaps internal parameters to better match
the expected compression curve of JPEG and produce output files
of similar size, but with better quality.

Change-Id: I96a1cbb480b1f6a0c6845a23c33dfd63f197b689
2013-02-06 14:19:16 +01:00
1f803f645d Merge "Tune alpha quality mapping to more reasonable values." 2013-02-05 10:50:28 -08:00
1267d498dc Tune alpha quality mapping to more reasonable values.
This results in a significant speedup  with minimal increase in file sizes.

Change-Id: I6ecefe33eee219fba4099810d04a916f7efbd292
2013-02-05 19:49:35 +01:00
043076e2ef Merge "speed-up lossless in BackwardTrace" 2013-02-05 10:46:06 -08:00
f3a44dcd83 remove one malloc from TraceBackwards()
Change-Id: I4f77c0240ca2ece86e8beab11d02c74277409921
2013-02-05 19:43:43 +01:00
0fc1a3a072 speed-up lossless in BackwardTrace
we special-case code=2 (with a later TODO to adapt this on quality)

Change-Id: I93d43f5b3f8f1ef9f211cce253bb4b415918ee57
2013-02-05 19:42:23 +01:00
7c732e59f4 cwebp: centralize WebPCleanupTransparentArea()
this can be safely called whether the picture has alpha or not

Change-Id: I0047fd4c110f1072f183f3d340682502bd6623d7
2013-02-04 15:44:26 -08:00
7381254e9a Merge "wicdec: add ICC profile extraction" 2013-02-04 15:43:39 -08:00
e83ff7decd wicdec: add ICC profile extraction
Change-Id: I4522cdd5a529f802f1eb566b6d94539612e0976b
2013-02-02 10:40:49 -08:00
146c6e3be8 Merge "cosmetics: pngdec: normalize default label location" 2013-02-02 00:18:37 -08:00
a8f549d799 Merge "manpages: italicize option parameters" 2013-02-02 00:18:05 -08:00
e118db83b1 Merge "encode.h: note the need to free() WebPMemoryWriter" 2013-02-02 00:12:59 -08:00
1dfee6dbea cosmetics: pngdec: normalize default label location
Change-Id: I25dd0e61898af3fcaff3d17cddedd3d39d4930aa
2013-02-01 20:37:05 -08:00
14c3820038 manpages: italicize option parameters
Change-Id: Id7e4edde2a1c91fe4fbf96ddc280a06132e9986a
2013-02-01 20:35:58 -08:00
7defbfadbe encode.h: note the need to free() WebPMemoryWriter
Change-Id: Iec873764e9f4c085c634498630b8c1ced3283984
2013-02-01 19:18:47 -08:00
88d382a042 cwebp: cleanup after memory_writer
always initialize the memory_writer so it can be unconditionally freed
on exit

Change-Id: I9226addb588309446ec94abadfdde201f23195d2
2013-02-01 19:17:26 -08:00
12d6cecfbd fix extra space in dwebp.1 man
Change-Id: Ifa3d91c73e0efeecb02365bc2168c830a01c759a
2013-01-30 04:50:03 -08:00
b01681a93f Fix for demuxer frame iteration:
Return error in WebPDemuxGetFrame() when static method GetFrame()
returns NULL.

Change-Id: Idbc54037047c3df75209ac67ff8bede3f83042be
2013-01-29 10:58:04 -08:00
56c12aa698 Demuxer creation fix:
If it's not a partial file and parser returns PARSE_NEED_MORE_DATA, then
consider it to be PARSE_ERROR.

Change-Id: Id652a345bd2a9f574970272dd0a00517de113215
2013-01-29 10:53:52 -08:00
66c810bc3c add a -yuv option to dwebp (very similar to -pgm)
It will decode to raw (flat) YUV format, similar to what
cwebp can take as input. Makes the PSNR/SSIM calculation easier.

Change-Id: Iebfaedfc0bedc70c169b24ae4aabc701488d0644
2013-01-28 23:22:14 +01:00
841a3ba5da Merge "Remove -Wshadow warnings." 2013-01-28 13:15:54 -08:00
8fd0252787 Merge "upsampling_neon.c: fix build" 2013-01-28 13:14:39 -08:00
6efed26865 Remove -Wshadow warnings.
Accidentally carried some bad habits from SSE code. Copy over fixes
from 0d19fbf

Change-Id: I763312c9d176c434ba41f95602bada1aeffebfb2
2013-01-28 12:29:12 -08:00
60904aa629 Merge "allow WebPINewRGB/YUVA to be passed a NULL output buffer." 2013-01-28 04:06:16 -08:00
b7adf37621 allow WebPINewRGB/YUVA to be passed a NULL output buffer.
If a NULL pre-allocated buffer is passed, a buffer will be automatically
allocated.

+ add some parameter checks.

reported in http://code.google.com/p/webp/issues/detail?id=139

Change-Id: I9e14ed97db30ee12e46b5e92aac7eeaaeb99bfd5
2013-01-28 00:07:32 -08:00
27f8f7420e upsampling_neon.c: fix build
store values to a temporary variable before calling functions that take
vector types.
removes non-standard constructs such as:
  (uint8x8x2_t){{ a, b }}
fixing:
  src/dsp/upsampling_neon.c:69:32: error: macro "vst2_u8" passed 3
arguments, but takes just 2

Change-Id: Ib4368e16e3a3efac18024f02be94e76243ade2dc
Fixes: https://code.google.com/p/webp/issues/detail?id=140
2013-01-25 19:42:50 -08:00
06b9cdf1e7 gitignore: add IOS related directories
iosbuild / WebP.framework courtesy of iosbuild.sh

Change-Id: I706fd5fada5fab2528e89d6b09fe93fa44486035
2013-01-25 18:25:28 -08:00
f112221e77 Merge "Fix more comments for iobuild.sh" 2013-01-25 17:52:23 -08:00
fe4d25ddad Fix more comments for iobuild.sh
Change-Id: If97af61a00c0f2dfbd09758c121a9ddd9536b6d1
2013-01-25 16:07:59 -08:00
1de3e25271 Merge "NEON optimised yuv to rgb conversion" 2013-01-25 15:51:40 -08:00
090b708a00 NEON optimised yuv to rgb conversion
- along the lines of the SSE chroma upsampling.
Total speedup is ~30%.

4% speed loss on YuvToRgbXX conversion using tables instead
of 14-bit fixed precision. TODO(later): investigate, and compare
to x86.

see http://code.google.com/p/webp/issues/detail?id=134

Change-Id: Idc2261037cd13b4553ca20ecc4c4007099c37009
2013-01-25 15:46:40 -08:00
daa06476e1 Merge "Add ios build script for building iOS library." 2013-01-25 15:26:09 -08:00
79fe39e2f2 Add ios build script for building iOS library.
This build script (iosbuild.sh) will build for following platforms:
iPhoneSimulator, iPhoneOS-V7 & iPhoneOS-V7s

Change-Id: Icbb69e00277a4164f848b8766089302e299506e0
2013-01-25 10:10:50 -08:00
126c035f3f remove some more -Wshadow warnings
Change-Id: Icaba088b9a74732137bd35d82854eed858ec88f8
2013-01-25 00:44:31 -08:00
522e9d6108 Merge "cwebp: enable '-metadata'" 2013-01-24 20:04:09 -08:00
76ec5fa1b6 cwebp: enable '-metadata'
This copies metadata selected by -metadata from the input to the output
if present.
Currently there is no WIC support for Windows builds.

Change-Id: I34fb2443729d80ffe3a6da0979d9f6fa9b3fe536
2013-01-24 19:52:50 -08:00
aeb91a9d49 Merge "cosmetics: break a few long lines" 2013-01-23 15:05:40 -08:00
be7c96b069 cosmetics: break a few long lines
Change-Id: I785763b974b4e7664ad8e9884251aa2d5274b456
2013-01-23 14:50:19 -08:00
cff8ddb61b Merge "add libwebpdecoder.pc" 2013-01-23 14:27:41 -08:00
93148ab867 Merge "libwebp.pc.in: detab" 2013-01-23 14:25:06 -08:00
6477f955b6 Merge "Makefile.vc: normalize path separator" 2013-01-23 14:21:36 -08:00
bed1ed7c28 add libwebpdecoder.pc
Change-Id: Ifc47549a9fe206fa174236664345d3ee064849f5
2013-01-23 13:57:08 -08:00
46168b2d00 libwebp.pc.in: detab
Change-Id: I60f38e9f6e1cdba29163240a394b5be0a14c4bca
2013-01-23 13:31:43 -08:00
a941a3463e Fixed few nits in the build files.
Fixed the nits from last change (Provide an option to build decoder
library).

Change-Id: I7d8675b8156dc63cf21ef64810722552e7fb59f6
2013-01-23 13:22:06 -08:00
dd7a49b21b Makefile.vc: normalize path separator
/ -> \

Change-Id: I691c03683650b8b97a365281e9384f4a3f3fe1ca
2013-01-23 12:46:18 -08:00
9161be863d Merge "cwebp: extract WIC decoding to its own module" 2013-01-23 12:44:22 -08:00
08e7c58ee1 Merge "Provide an option to build decoder library." 2013-01-23 11:54:24 -08:00
0aeba52852 Provide an option to build decoder library.
When the config option '--enable-libwebpdecoder' is specified, the
lean decoder library 'libwebpdecoder' will be created in addition to
libwebp. Also dwebp binary will be linked to libwebpdecoder, if this
config option is specified.

Change-Id: I9de3e149b59c9a8390fae2ba660941749640e54a
2013-01-23 11:43:36 -08:00
757ebcb1c1 catch malloc(0)/calloc(0) with an assert
Actually, it turns out we now should never call these functions
with a zero size, otherwise something is wrong in the logic.

Change-Id: Ie414fcbec95486c169190470a71f2cff0843782a
2013-01-23 20:09:28 +01:00
152ec3d2ee Merge "handle malloc(0) and calloc(0) uniformly on all platforms" 2013-01-23 04:41:36 -08:00
a452a5554a cwebp: extract WIC decoding to its own module
Change-Id: I8e3e20787f6c3cc0616bd33beb2a6ccdda1e04f7
2013-01-22 18:31:28 -08:00
2b252a53a8 Merge "Provide option to swap bytes for 16 bit colormodes" 2013-01-22 15:00:39 -08:00
94a48b4bc3 Provide option to swap bytes for 16 bit colormodes
Color modes: RGB_565 & RGBA_4444
Change-Id: I571b6832b9848e5c4109272978f68623ca373383
2013-01-22 14:51:20 -08:00
42f8f9346c handle malloc(0) and calloc(0) uniformly on all platforms
also change lossless encoder logic, which was relying on explicit
NULL return from WebPSafeMalloc(0)

renamed function to CheckSizeArgumentsOverflow() explicitly

addresses issue #138

Change-Id: Ibbd51cc0281e60e86dfd4c5496274399e4c0f7f3
2013-01-22 23:40:16 +01:00
8b2152c579 Merge "add an extra assert to check memory bounds" 2013-01-22 14:10:02 -08:00
0d19fbff51 remove some -Wshadow warnings
these are quite noisy, but it's not a big deal to remove
them.

Change-Id: I5deb08f10263feb77e2cc8a70be44ad4f725febd
2013-01-22 23:06:28 +01:00
cd22f655e8 add an extra assert to check memory bounds
-> will remove a static-analysis warning about unused value.
addresses issue #138

Change-Id: I8ba4bf71a41e32759da41907aab73108dd230bc4
2013-01-22 13:38:58 +01:00
8189feda50 Merge "Add details and reference about the YUV->RGB conversion" 2013-01-21 07:10:42 -08:00
1d2702b1da Merge "Formatting fixes in lossless bitstream spec" 2013-01-18 14:41:56 -08:00
8425aaee8f Formatting fixes in lossless bitstream spec
- Escape brackets for which kramdown was generating a warning.
Note: This only changes this source file; output HTML would look exactly
the same.
- Also write '5' in words ('five').

Change-Id: I472a03c090a12eb7520719ea463469b36a2736b9
2013-01-18 14:35:47 -08:00
a556cb1ab4 Add details and reference about the YUV->RGB conversion
Originated from the discussion at
   http://code.google.com/p/webp/issues/detail?id=134

Change-Id: I24384e2d2f5cf262d8632fc98303cba5e2d27224
2013-01-18 23:26:55 +01:00
d8f21e0bab add link to SSIM description on Wikipedia
+ a brief description of LSIM

Change-Id: I4344f3e3b28d8bc4109b729dec9000e9c8fcbdbb
2013-01-18 13:13:56 +01:00
18e9167ea6 Merge "WebP-lossless spec clarifications:" 2013-01-18 00:15:01 -08:00
98e25b9b81 Merge "cwebp: add -metadata option" 2013-01-18 00:13:40 -08:00
f01c2a538c WebP-lossless spec clarifications:
- Clarify the BNF using 'Huffman code groups' and 'Huffman code group'.
- Introduce same terminology in 'Interpretation of meta Huffman codes'.
- Make explicit mention of what is the number of Huffman code groups,
  number of Huffman codes and the relation between the two.

Change-Id: I07aa9b62c1d464cd25dc02ac1a68d338b575bdc2
2013-01-17 15:19:09 -08:00
f4a97970de Merge "Disto4x4 and Disto16x16 in NEON" 2013-01-17 11:07:20 -08:00
47b7b0ba47 Disto4x4 and Disto16x16 in NEON
Change-Id: Ic6d9dbbc97b5025ce359332c33ae306d5d8925a5
2013-01-16 16:57:33 -08:00
7eaee9f1ac cwebp: add -metadata option
currently has no effect except to disable metadata extraction from the
input when the value is 'none'.

Change-Id: Ic50d4c9d634cc1f6b72ae4e130e99736c85a6477
2013-01-14 17:44:54 -08:00
36c52c2cf1 tiffdec: use toff_t for exif ifd offset
versions < 4.0.0 used uint32 interchangeably, but with 4.0.0 toff_t
became 64-bit and TIFFTAG_EXIFIFD began returning it rather than
TIFF_LONG/uint32.

Change-Id: I42492bd24613a884c7496e7bfc0c5d892758bce9
2013-01-10 21:33:24 -08:00
7c8111e4a8 Merge "cwebp/tiffdec: add TIFF metadata extraction" 2013-01-10 15:52:05 -08:00
e6409adc2e Remove redundant include from dsp/lossless code.
Change-Id: Ie8a497a486653f907c2a27f4027640a3308c6cc8
2013-01-10 15:09:19 -08:00
1ab5b3a7bd Merge "configure: fix --with-gifincludedir" 2013-01-08 13:54:23 -08:00
03c749ebb8 configure: fix --with-gifincludedir
GIF_INCLUDES were not being used by examples/Makefile.am

Change-Id: I981ad473f6efe24f095e2b9cc8b133d6ae3658b6
2013-01-08 12:39:43 -08:00
8b650635df multiple libgif versions support for gif2webp
Make it work for libgif v5.0+, for which a couple of APIs have changed.

Change-Id: I6dd49bb5bf1b60f96f3a164d58ef2ef19281c96b
2013-01-08 11:52:24 -08:00
476e293fe8 gif2webp: Use DGifOpenFileName()
This removes some unnecessary code.

Change-Id: Ic87baa402362f43b30d7c4a75be2f58e8f13f4a1
2013-01-08 11:07:13 -08:00
b50f277bc7 tiffdec: correct format string
the expression using dircount will be promoted to int when tdir_t is an
unsigned short.
quiets:
warning: format specifies type 'unsigned short' but the argument has
      type 'int' [-Wformat]

Change-Id: If2e8c27454826556178b0a972aaed272d5fbfa07
2013-01-07 19:06:20 -08:00
2b9048e324 Merge "tiffdec: check error returns for width/height" 2012-12-22 06:29:23 -08:00
a1b5a9a3e0 Merge "cwebp/tiff: use the first image directory" 2012-12-21 08:37:11 -08:00
079423f5c5 tiffdec: check error returns for width/height
Change-Id: I1399a7b75aea54044f30c6a53ac11843c1e75877
2012-12-20 22:33:52 -08:00
d62824af42 Merge "cwebp/jpegdec: add JPEG metadata extraction" 2012-12-20 22:25:46 -08:00
03afaca4a2 Merge "cwebp: add PNG metadata extraction" 2012-12-20 22:20:12 -08:00
2c724968d2 cwebp/jpegdec: add JPEG metadata extraction
the values of EXIF/XMP/ICC are unused and Extended XMP for payloads >
64k is unsupported.

Change-Id: If721aa2009335ce090148b7ecd7ea8459f9b942d
2012-12-20 18:35:38 -08:00
dba64d91bb cwebp: add PNG metadata extraction
the values of XMP/EXIF/ICC are currently unused.

Change-Id: I39d78b9a179f2d36c9c8ea12776bfdf6d8d18663
2012-12-20 18:32:09 -08:00
1f075f89b0 Lossless spec corrections/rewording/clarifications
- Correct BNF for 'predictor-image' and 'color image'
- Correct some references to 'br', 'VP8LReadBits' and 'ReadStream'
- Correct value ranges in distance mapping table.
- Rewrite section 4 (some rearrangement, rewording, adding context etc).
- Similarly, rewrite section 5.

Change-Id: If487490c2553b3f7982b9fcca68d98bab5017e3c
2012-12-20 10:44:42 -08:00
2914ecfd56 cwebp/tiffdec: add TIFF metadata extraction
currently the values of XMP/ICC are unused and EXIF is ignored.

Change-Id: I1d8b73bde4db2768f117158f986aadbaaec45804
2012-12-19 18:26:05 -08:00
d82a3e3391 More corrections/clarifications in lossless spec:
- Rectify a few BNF descriptions
- Corrections in "Decoding Flow of Image Data" section:
  1. The sequence in case of "S < 256" should be green, red, blue, alpha.
  2. In case of "S >= 256 + 24", the index should be "S - (256 + 24)".
- Provide more description to clarify "Decoding Flow of Image Data" section.
- Some cosmetics: use '1's instead of '1, 2, 3...' sequence, as kramdown takes
  care of sequencing.

Change-Id: I2b76caf72f67aae813522dc1a4115f8ec8ea6db7
2012-12-17 11:40:23 -08:00
bd0025579f cwebp/tiff: use the first image directory
tiffdec does not support and warns about multi-directory images.
previously, the code would read all the directories and thus attempt to
use the last rather than the first as the message suggests.

Change-Id: I3a10c778e6e924a3df75b41c26a9c03afb761044
2012-12-15 18:49:38 -08:00
df7aa07605 Merge "Cleanup around jpegdec" 2012-12-14 19:27:49 -08:00
0f57dcc31f decoding speed-up (~1%)
- precompute filtering strength once for all at the beginning
  instead of per-macroblock
- reduce size of VP8MB struct from 8 bytes to 4.
- removed VP8StoreBlock() accordingly

Change-Id: Icf3d329473e21c464770be3d72a04c9ee4c321f2
2012-12-14 10:22:54 -08:00
bcec339b01 Lossless bitstream clarification:
Clarify what the pixels of a color transform image are.

Change-Id: I720248b5417857468d54952440cf1bae6c091042
2012-12-12 14:03:44 -08:00
6bf208748c add examples/metadata.c
relocates the static functions from metadata.h and adds MetadataCopy()
to the interface

Change-Id: I28bfa9233d3dd70dddf6b561fe0bf4be378db1ec
2012-12-11 18:10:09 -08:00
207f89c0dc Merge "configure: add libwebpdemux status to summary" 2012-12-11 02:07:35 -08:00
1bd287a6e4 Cleanup around jpegdec
* change some (*func_ptr) construct to func_ptr simply.
  * remove one memcpy
  * group #include related to decoding together

Change-Id: If751cfbd9e78be75c57fb60fc9c937900c2c8fe0
2012-12-11 11:02:39 +01:00
9145567982 Merge "cosmetics: use '== 0' in size checks" 2012-12-11 01:48:54 -08:00
d6b88b7694 cosmetics: use '== 0' in size checks
Change-Id: I8ac18e2e570e4c6a8569a3955afa11fc943bee28
2012-12-10 23:27:34 -08:00
d3dace2ff0 cosmetics: jpegdec
- squash some whitespace
- remove unnecessary pointer check

Change-Id: I06208566a5621786479956ea658434f5c4d62fcc
2012-12-10 23:26:11 -08:00
2f69af732e configure: add libwebpdemux status to summary
Change-Id: I3b11d91de6780496b72bd89f93b49350e4350203
2012-12-10 23:08:53 -08:00
1c1c5646a5 cwebp: extract tiff decoding to its own module
Change-Id: If98d0d37de34b63ac10d826150237b5f99446532
2012-12-10 22:37:04 -08:00
6a871d66a4 cwebp: extract jpeg decoding to its own module
Change-Id: I45e1f0fa7b34286dd98926e0485e5a8ab1964570
2012-12-07 20:12:46 -08:00
2ee228f9a5 cwebp: extract png decoding to its own module
Change-Id: I80dd09fe1f1c6317e9d0cdd422438bda11b43ed5
2012-12-07 20:02:41 -08:00
4679db006c Merge "cwebp: add metadata framework" 2012-12-06 14:35:20 -08:00
63aba3aef1 cwebp: add metadata framework
unused currently, but the intent is to allow each format to populate
exif/xmp/icc with cwebp then transferring it to the webp file.

Change-Id: I0514f62de52fa7f89c595ee7ef2ad7dced910a41
2012-12-06 14:29:10 -08:00
931bd516b8 lossless bitstream: block size bits correction
The color transform block size is stored as 3 bits, not 4.
Fixed the description. The code snippet is already correct.

Change-Id: I830d848b54c121cb5426ca06853a3f1184fd9a31
2012-12-05 13:38:05 -08:00
e4fc4c1c63 lossless bitstream: block size bits correction
The prediction block size is stored as 3 bits, not 4.
Fixed the description. The code snippet is already correct.

Change-Id: Iaa66a7e9817b58a2557c9a71c2231cc400b6ae4d
2012-12-05 00:01:28 -08:00
d65ec6786a fix build, move token.c to src/enc/
broken in:
  657f5c9 move token buffer to its own file (token.c)

Change-Id: I8944a0b5760979bd43008c501b55df1d22d32180
2012-12-03 11:16:08 -08:00
657f5c91b1 move token buffer to its own file (token.c)
Change-Id: Ib9791c52f48d98fad5ed3830f36894ef5ac362fa
2012-12-03 13:50:14 +01:00
c34a3758ad introduce GetLargeValue() to slim-fast GetCoeffs().
GetCoeffs is (by far) the most consuming function of the decoder.
No speed change (unfortunately), but the main loop is somehow clearer.

Change-Id: I78f1c10cadc2c8696c041f5cbda86cab92cc6598
2012-11-28 08:24:23 +01:00
d5838cd598 faster non-transposing SSE2 4x4 FTransform
1-2% faster.
uses pmaddwd instead of transpose + pmullw.
Can possibly be simplified further.

Change-Id: I420e148816c4c6ab5e2080c9b1719dbbe6762d4e
2012-11-27 08:38:24 +01:00
f76191f9db speed up GetResidualCost()
* treat the last coeff as a special case
* re-arrange the inner code to be shorter
* replace some VP8EncBands[n] by n, for n = 0 or 1

Change-Id: I71e17b014cffad7b073e787fde06260905a6953f
2012-11-26 23:50:37 +01:00
ba2aa0fdda Add support for BITS=24 case
The main advantage is that you can avoid the use of uint64_t
some times, sticking to 32bit only.
Default still is BITS=32, this is mainly "in case".

Change-Id: Id694028793117ba822c37d46ef6c52fa0afed4ac
2012-11-26 23:47:08 +01:00
2e7f6e8ef2 makefile.unix: Dependency on libraries
The binaries should have dependency on related libraries only.
For example, 'vwebp' sould not depend on libpng, libjpeg etc.

Change-Id: I517b7ae6a9092d5de891b46d0e75d07d91548e93
2012-11-21 12:12:29 -08:00
dca84219ec Merge "Separate out mux and demux code and libraries:" 2012-11-19 15:12:55 -08:00
23782f95b4 Separate out mux and demux code and libraries:
- Separate out mux.h and demux.h
- muxtypes.h: new header for data types common to mux/demux
- Move some misc read/write utilities to utils/utils.h
- Remove some duplicate methods.
- Separate out mux/demux libraries

Change-Id: If9b9569b10d55d922ad9317ef51710544315d6de
2012-11-19 11:40:18 -08:00
bd56a01f87 configure: add summary output
Change-Id: Ib5d5f470aedf4e9537c10458d0e268735e6fca83
2012-11-16 18:59:46 -08:00
90e5e3190c dwebp manual: point to webpmux, gif2webp.
Change-Id: If140e3021ee1b60d6afa355883574be07e65b10c
2012-11-16 10:25:16 -08:00
540790ca6b gif2webp.c: add a note about prerequisites
Change-Id: I25a88f13b0c38c5968b5c4a3be0955e18e990723
2012-11-15 22:31:55 -08:00
d1edf697b2 cwebp man page: meaning of '-q' for lossy/lossless
Change-Id: I00b1e6a4f35c6c191072b3c30077166e7b143f56
2012-11-15 15:57:50 -08:00
79efa1d006 Add man page for gif2webp utility
Change-Id: Ia4826134db4e97427ab27977af7cc358b26e2b86
2012-11-15 15:55:06 -08:00
2243e40c39 Merge "gif2webp build support with autoconf tools" 2012-11-15 12:14:53 -08:00
c40efca157 gif2webp build support with autoconf tools
Change-Id: I51a007e7931f05f2eb2ac062038309c2127df3fd
2012-11-15 11:04:12 -08:00
6523e2d41d WebP Container:
annotate specific sections as experimental

Change-Id: If43222cef1c4fc2a8164b5f6ca4e89033379757d
2012-11-15 11:01:41 -08:00
4da788da3f Merge "simplify the fwd transform" 2012-11-15 00:54:10 -08:00
42c3b550ba simplify the fwd transform
-> remove two shifts

Change-Id: Ibc55bca98588da30553a7870224ffd0e13d57f52
2012-11-15 09:51:35 +01:00
41a6ced92e user GLfloat instead of float
Change-Id: I1af65f9a6046835cd4d390f37ccb0e659016ba1d
2012-11-15 09:35:01 +01:00
b542611964 fix indentation
Change-Id: Ieb22b158d52b16f9782a7e747dd5edbf29099ec5
2012-11-15 09:34:34 +01:00
68f282f79c * handle offset in anim viewer 'vwebp'
* fix gif2webp to handle disposal method and odd offset correctly

+ remove -scale and -crop option from vwebp, since it'll be broken
  with offsets and fragments. Needs a revisit.
+ remove a warning in gif2web

Change-Id: If04c6d085806e32540f2f15a37244c4407b719b3
2012-11-15 09:15:04 +01:00
118cb31270 Merge "add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case" 2012-11-15 00:07:44 -08:00
8a7c3cc8ee Merge "Change the order of -frame argument to be more natural" 2012-11-15 00:07:28 -08:00
99e0a707da Merge "Simplify the texture evaluation Disto4x4()" 2012-11-15 00:07:11 -08:00
0f923c3ffd make the bundling work in a tmp buffer
This avoids modifying the source picture.

Change-Id: I5b472859cda17fd3236a9e0fbedbb68977e09f85
2012-11-15 09:05:25 +01:00
e5c3b3f554 Simplify the texture evaluation Disto4x4()
We don't need to use the exact forward transform,
since it's only a rough evaluation.
-> Removed some shifts and rounding constants.

Change-Id: I3fdf8b4fe9720473894155e1ad0345f4d1fd9a33
2012-11-14 07:49:31 +01:00
4860008483 Change the order of -frame argument to be more natural
Now, its: +duration+xoffset+yoffset+disposal
+disposal can be omitted and will default to +0 (NONE)
additionally, +xoffset+yoffset can be omitted and will default to +0+0

Change-Id: I62138c9f675d4fc4408305babbcd485cb32b73d3
2012-11-14 06:19:31 +01:00
35bfd4c08f add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case
+ replace mm_set1_ps(0) by _mm_setzero_si128()

Change-Id: I4601033c27466532373f5dabfaf349ce5e5039da
2012-11-14 06:16:49 +01:00
a7305c2ef0 Clarification for unknown chunks
clarify that writers *may* modify unknown chunks if they specifically
intend to do so.

Change-Id: I8348df2ec84648201ea781c7bfffd1f36eb3c8e5
2012-11-13 10:41:13 -08:00
4c4398e2d5 Refine WebP Container Spec wrt unknown chunks.
Change-Id: Ibe950ab7afb2a7349f61c6fb81d587fba9ff27b6
2012-11-12 14:32:44 -08:00
2ca642e02a Rectify WebPMuxGetFeatures:
It should return ALPHA_FLAG for lossless bit-stream

Change-Id: I900bd5b58bf75bc25fca1abf4ecc12aea26eac1c
2012-11-09 14:37:20 -08:00
7caab1d8f6 Some cosmetic/comment fixes.
Change-Id: Id0613f84cc53fcbeceb913c835a262451687e27b
2012-11-09 10:46:38 -08:00
60b2651a8c Merge "Write a GIF to WebP converter based on libgif." 2012-11-09 08:01:07 -08:00
c7127a4dec Merge "Add NEON version of FTransformWHT" 2012-11-09 06:54:28 -08:00
11b2721258 Write a GIF to WebP converter based on libgif.
Change-Id: Ic64bf5307996a788ec61caf59a99ab37b4b1ae96
2012-11-08 11:21:25 -08:00
e9a15a37cf ExUtilWriteFile() to write memory segment to file
Change-Id: I4a93358e55ba5527667e017e178009251f64560e
2012-11-08 11:20:01 -08:00
74356eb558 Add a simple cleanup step in mux assembly:
In particular, this removes any unnecessary FRGM/ANMF/ANIM chunks, and
indirectly leads to removal of unnecessary VP8X chunks as well.
This is especially useful for GIF to WebP conversion - it saves 56 bytes
(ANMF: 16+8 bytes, ANIM: 6+8 bytes, VP8X: 10+8 bytes) for non-animated GIFs.

Change-Id: I3b50a96ca585844c421b0fa4cd8593e52c3f95c5
2012-11-08 11:15:22 -08:00
51bb1e5de7 mux.h: correct WebPDemuxSelectFragment() prototype
This is a correction to the following change:
a00a3daf5b Use 'frgm' instead of 'tile' in
webpmux parameters

Change-Id: I8fa0bce98efdde38827fd25712017a98a6ea7388
2012-11-08 11:04:39 -08:00
22a0fd9d01 Add NEON version of FTransformWHT
Contributed by Wayne Chen (datoudatou at gmail dot com)

Change-Id: I007c21db4eeadbf82b89f0963256f965deda7d90
2012-11-08 08:28:51 -08:00
fa30c86323 Update mux code to match the spec wrt animation
- Allow a duration of 0
- Rename LOOP chunk to ANIM and add the background color field to it.
- Add a disposal method field for each animation frame.
- Modify webpmux.c binary interface to allow the input of background color
  and disposal methods. Also make '-loop' and '-bgcolor' arguments optional
  with some default values.

Change-Id: I807372a61cdb8a0d3080ae3552caf2848070bf4d
2012-11-07 11:43:06 -08:00
d9c5fbefa4 by-pass Analysis pass in case segments=1
10-15% faster encoding.

Almost same output, binary wise. The main difference is
that we can't compute uv_alpha susceptibility, means there
can be subtle differences with different -sns values.

Change-Id: Id1b1a50929bf125b6372212fee1ed75a3bed975f
2012-11-06 22:53:13 -08:00
d2ad4450ce Merge changes Ibeccffc3,Id1585b16
* changes:
  Use 'frgm' instead of 'tile' in webpmux parameters
  Design change in ANMF and FRGM chunks:
2012-11-06 22:43:43 -08:00
5c8be2515d Merge "Chunk fourCCs for XMP/EXIF" 2012-11-06 16:17:32 -08:00
a00a3daf5b Use 'frgm' instead of 'tile' in webpmux parameters
- Also, use the term 'fragments' instead of 'tiling' in code
- This makes code consistent with the spec.

Change-Id: Ibeccffc35db23bbedb88cc5e18e29e51621931f8
2012-11-06 16:09:10 -08:00
81b8a741ed Design change in ANMF and FRGM chunks:
- Make ANMF and FRGM chunks hierarchical so that they encompass all chunks of
  that frame.
- Use this in demuxer: stop parsing a frame if all image data for it isn't
  available yet. Thus, we have a frame-level incremental support; that is,
  all frames that are fully available can be parsed.
- Note: We still keep incremental support for single images - so that they can
  be decoded with incremental decoding.

Change-Id: Id1585b16b06caee1d84009c42a25d2de29fa6135
2012-11-06 16:04:33 -08:00
f903cbab9a Chunk fourCCs for XMP/EXIF
Use separate fourCCs "XMP " and "EXIF" instead of a common "META"
Also, some refactorization in webpmux.c

Change-Id: Iad3337e5c1b81e785c60670ce28b1f536dd7ee31
2012-11-06 14:53:21 -08:00
812933d6ba Tune performance of HistogramCombine
Number of pairs selected are limited between 25% of histogram
images (at start) and number of histogram images left at any iteration.
Increase the range of iter_mult.
Removed min_cluster_size as parameter for tuning HistogramCombine.

Change-Id: Ia4068cd7af4d0f63c5af9001aceda8a40b9de740
2012-11-05 16:45:39 -08:00
52ad1979d2 Animation specification in container spec
Change-Id: I3cb1d994a460d9a712998ca1045bf6bc7d953c04
2012-11-05 13:29:23 -08:00
001b930219 Image fragment specification in container spec
Change-Id: If8cad296738465df4327dfb6b44efa7e0356070e
2012-11-02 15:37:49 -07:00
391f9db9fa Ordering of description of bits in container spec
The description of bits in a byte should be from MSB to LSB

Change-Id: I50f2dfbb79b33eb434a771cca252c5d0f81fc71e
2012-11-02 15:27:37 -07:00
d57357762a Metadata specification in container spec
Change-Id: I4b76697efb160145ffef3fd9df9905544c4e8792
2012-11-02 15:14:47 -07:00
1c4609b1f8 Merge commit 'v0.2.1'
* commit 'v0.2.1':
  Update ChangeLog
  update NEWS
  bump version to 0.2.1
  libwebp: validate chunk size in ParseOptionalChunks
  cwebp (windows): fix alpha image import on XP
  autoconf/libwebp: enable dll builds for mingw
  [cd]webp: always output windows errors
  fix double to float conversion warning
  cwebp: fix jpg encodes on XP
  VP8LAllocateHistogramSet: fix overflow in size calculation
  GetHistoBits: fix integer overflow
  EncodeImageInternal: fix uninitialized free
  fix the -g/O3 discrepancy for 32bit compile
  fix the BITS=8 case
  Make *InitSSE2() functions be empty on non-SSE2 platform
  make *InitSSE2() functions be empty on non-SSE2 platform
  make VP8DspInitNEON() public

Conflicts:
	src/Makefile.am
	src/dsp/dec_neon.c

Change-Id: Iddc5152e4a6892db96c12d7c3f74adbc85fe6178
2012-11-02 12:20:19 -07:00
0ca584cbbf Merge "Color profile specification in container spec" 2012-11-01 19:20:46 -07:00
e8b41ad136 add NEON asm version for WHT inverse transform
Contributed by Wayne Chen (datoudatou at gmail dot com)

+ some header cleanup
+ remove the NEON suffix in static functions

Change-Id: I75bf5e9b54cf5e1acc53764c6f081d61690f8e3d
2012-11-01 16:31:01 -07:00
af6f0db291 Color profile specification in container spec
Change-Id: I53f849c7d93e1cdc971dda1fffd8f359f40607d3
2012-11-01 11:16:29 -07:00
a61a824b3a Merge "Add NULL check in chunk APIs" 2012-10-31 16:07:24 -07:00
0e8b7eedaa fix WebPPictureView() unassigned strides
y_stride/uv_stride/argb_stride were not set properly.

Change-Id: I001b8d46f873ca04b5c68eccd6f232061020f9ec
2012-10-31 16:01:34 -07:00
75e5f17e3b ARM/NEON: 30% encoding speed-up
(implements the backward and forward transforms in the encoder)

original patch by Wayne Chen (datoudatou at gmail dot com)

Change-Id: Ic00f3bffcdf7a924f043006728735c810ee47a57
2012-10-31 14:00:20 -07:00
02b4356875 Add NULL check in chunk APIs
Change-Id: I173ff6c9259111762580c1963ff60e34fd1e9b6b
2012-10-31 13:33:20 -07:00
a077072777 mux struct naming
members of public structs should not have a trailing underscore.

Change-Id: Ieef42e1da115bf42b0ea42159701e32bed7b9f60
2012-10-31 11:37:49 -07:00
6c66dde80f Merge "Tune Lossless encoder" 2012-10-30 18:27:14 -07:00
ab5ea217f7 Tune Lossless encoder
- Changed the dynamic range where more aggressive
  (BackwardReferencesTraceBackward) heuristic is run from quality > 10
  (instead of quality > 25).
- Limit the backward-ref Window size to 16*width & 256*width for lower
  qualities ([0, 25[ & [25, 50[) respectively, instead of 1M window.
- Evaluate the params for HashChainFindCopy outside this function call
  and pass it, instead of recomputing them for every call.

Change-Id: If9eedfc14b978e7632d7cf69c96186e2910b0554
2012-10-30 17:30:17 -07:00
74fefc8ce8 Update ChangeLog
Change-Id: I89a9c8cf6793c38e2b13d6e0557414fb05620eec
2012-10-30 16:32:36 -07:00
92f8059ce4 Rename some chunks:
TILE --> FRGM and FRM --> ANMF

Change-Id: I752f90b950413501aecb021a8f57882da0e01484
2012-10-30 15:02:15 -07:00
3bb4bbeb60 Merge "Mux API change:" 2012-10-30 14:55:39 -07:00
d0c79f0552 Mux API change:
Create common APIs for image, frame and tile.

Change-Id: I709ad752133094bd5bc89dd9c832ff79802aac68
2012-10-30 14:16:29 -07:00
abc06044e7 Merge "update NEWS" into 0.2.0 2012-10-29 20:42:00 -07:00
57cf313bba update NEWS
Change-Id: Ie225646ba11a6a1d61f5642405c37ed2d20334f8
2012-10-29 19:26:26 -07:00
25f585c4f2 bump version to 0.2.1
lib - 0.2.1
libtool - 4.1.0 (compatible release)

Change-Id: Ib6ca47f2008d5c97d818422816ac60d0d0d8cffa
2012-10-29 19:17:17 -07:00
fed7c0485a libwebp: validate chunk size in ParseOptionalChunks
the max wasn't checked leading to a rollover case, possibly exploitable.
additionally check the RIFF size early, to avoid similar issues.

pulled from chromium:
 http://codereview.chromium.org/11229048/

Change-Id: I4050b13a7e61ec023c0ef50958c45f651cf34c49
2012-10-29 14:00:33 -07:00
552cd9bce0 cwebp (windows): fix alpha image import on XP
Query the converter to ensure the format is supported; add BGR formats
as RGBA was failing for PNG on XP

Fixes issue 129

Change-Id: Ib42aaf160a6c18e767e8c7dbe93dec7c45953399
2012-10-29 14:00:28 -07:00
b14fea993a autoconf/libwebp: enable dll builds for mingw
Change-Id: Ic1ace62aad1d8de95bc370c6729ded83b7b71f0b
2012-10-29 14:00:24 -07:00
4a8fb27223 [cd]webp: always output windows errors
don't hide failures with -v.

Change-Id: I1578dbb7be67f041f0984bf6696c0c895c1600d9
2012-10-29 14:00:18 -07:00
d662158010 fix double to float conversion warning
introduced in:
 a792b91 fix the -g/O3 discrepancy for 32bit compile

Change-Id: Ic77d6170a5a91cf58ec10c68656ac61a7c0ee41d
2012-10-29 14:00:14 -07:00
72b96a6905 cwebp: fix jpg encodes on XP
correct has_alpha check; previously it was controlled by keep_alpha,
which overrode the source format check.
fixes issue #127

Change-Id: I414cfd9c5ed60b13673ccd2262ee5e4505ed6f6a
2012-10-29 14:00:10 -07:00
734f762a08 VP8LAllocateHistogramSet: fix overflow in size calculation
the multiplications done for total_size would be done with integers,
possibly overflowing, before being promoted to 64-bit for the addition

Change-Id: I32c3a6400fc2ef120c38e01a8693f4cb1727234d
2012-10-29 14:00:05 -07:00
f9cb58fbce GetHistoBits: fix integer overflow
huff_image_size was a size_t (=32 bits with 32-bit builds) which could
rollover causing an incorrectly sized allocation and a crash in lossless
encoding.
fixes issue #128

Change-Id: I0f20cee98c29b2b40b02607930b6b7a7ca56996d
2012-10-29 14:00:01 -07:00
b30add2017 EncodeImageInternal: fix uninitialized free
on allocation error refs.refs would be uninitialized and free'd, causing
a crash

Change-Id: Idb7daec7aec3e5d769d8103595c28a9d0d0b86f4
2012-10-29 13:59:57 -07:00
3de58d7730 fix the -g/O3 discrepancy for 32bit compile
in debug mode, some float operations see their intermediate
values stored in memory rather than staying in the FPU (which
is 80bit precision).

Several fixes are possible (breaking long calculations into
atomic steps for instance), but simpler of all is just about
turning the cost[] array into float* instead of double*.

The code is a tad faster, and i didn't see any major output
size difference.

Change-Id: I053e6d340850f02761687e072b0782c6734d4bf8
2012-10-29 13:59:52 -07:00
77aa7d50a4 fix the BITS=8 case
spotted by Måns Rullgård (mans at mansr dot com)

Change-Id: I4484b1f00223a0be18cbe924b24a9f5ccffb7ea2
2012-10-29 13:59:48 -07:00
e5970bda8a Make *InitSSE2() functions be empty on non-SSE2 platform
this avoids the '*.o has no symbols' warning messages

Change-Id: Ib47f9faf9073e39293acad6b2f21f21dba8c5378
2012-10-29 13:59:44 -07:00
ef5cc47ee7 make *InitSSE2() functions be empty on non-SSE2 platform
this avoids the '*.o has no symbols' warning messages

Change-Id: I96aad8637fba47fdaa5a12740e3881ed362c805b
2012-10-29 13:59:38 -07:00
c4ea259db4 make VP8DspInitNEON() public
this will avoid the "dec_neon.o has no symbol" warning

no change in binary size observed on linux.

Change-Id: Ifd83dfc6a0c61905481599b06cb5e711f55efa7d
2012-10-29 13:59:31 -07:00
8344eadfe0 Merge "libwebp: validate chunk size in ParseOptionalChunks" 2012-10-23 02:07:13 -07:00
4828bb931d Merge "cwebp (windows): fix alpha image import on XP" 2012-10-23 00:57:21 -07:00
30763333f3 libwebp: validate chunk size in ParseOptionalChunks
the max wasn't checked leading to a rollover case, possibly exploitable.
additionally check the RIFF size early, to avoid similar issues.

pulled from chromium:
 http://codereview.chromium.org/11229048/

Change-Id: Ifebc712bf3d3de0129b76ca4c57c68e062abc429
2012-10-22 21:57:59 -07:00
704818980f AccumulateLSIM: fix double -> float warnings
Change-Id: I234a5cd09b9351dbbbbc5076be35bb794d1bf890
2012-10-22 18:00:20 -07:00
eda8ee4b3b cwebp (windows): fix alpha image import on XP
Query the converter to ensure the format is supported; add BGR formats
as RGBA was failing for PNG on XP

Fixes issue 129

Change-Id: I02e0d74b3b21337bc5fffd6a5dc158b7809b9aa9
2012-10-19 18:48:47 -07:00
c6e98658d2 Merge "add EXPERIMENTAL code for YUV-JPEG colorspace" 2012-10-19 12:13:34 -07:00
f0360b4fcf add EXPERIMENTAL code for YUV-JPEG colorspace
This is mostly for experimentation!
Need to define USE_YUVj flag in the code for that.

suggested by benwreder at hotmail dot com

Change-Id: If0b8e2c1863efc08ce097de6de20f4c7efc3f7e8
2012-10-19 20:15:58 +02:00
f86e6abe1f add LSIM metric to WebPPictureDistortion()
LSIM stands for "local similarity": before matching
a compressed pixel to the source, we search around in the source
and minimise the squared error. So, this is close to PSNR calculation,
but mitigates some of its limitations (pure translation and noise for instance).

There's a new -print_lsim option to cwebp too.

Change-Id: Ia38561034c7a90e71d2ea0f55bb1de527eda245b
2012-10-19 06:48:11 -07:00
c3aa215afa Speed up HistogramCombine for lower qualities.
Make the heuristic for combining Histograms a function of compression
quality. This change will speed-up compression time for compression
quality less than 75. The compression time/density remains unchanged
for compression quality 75 and higher.

Change-Id: I94513d51078340fbc0737d459fab2cebdd2d6082
2012-10-16 15:45:36 -07:00
1765cb1ca5 Merge "autoconf/libwebp: enable dll builds for mingw" 2012-10-09 13:24:25 -07:00
a13562e800 autoconf/libwebp: enable dll builds for mingw
Change-Id: I7e0ee9f514a7102ee002c432dfb280187f06a596
2012-10-09 10:53:31 -07:00
9f469b57a9 typo: no_fancy -> no_fancy_upsampling
Change-Id: Ia0cb8c4a5b586861fb89253f59555e555a3a44db
2012-10-09 15:14:24 +02:00
1a27f2f808 Merge "fix double to float conversion warning" 2012-10-09 00:06:52 -07:00
cf1e90dec7 Merge "cwebp: fix jpg encodes on XP" 2012-10-09 00:04:19 -07:00
f2b5d19b30 [cd]webp: always output windows errors
don't hide failures with -v.

Change-Id: I46485a66f266fd9e9e8c640d1051cd22cfa40658
2012-10-08 18:36:10 -07:00
e855208c16 fix double to float conversion warning
introduced in:
 a792b91 fix the -g/O3 discrepancy for 32bit compile

Change-Id: I6a77223f237527eda4ee1d6eaa993351bd74f1d6
2012-10-08 18:27:27 -07:00
ecd66f774d cwebp: fix jpg encodes on XP
correct has_alpha check; previously it was controlled by keep_alpha,
which overrode the source format check.
fixes issue #127

Change-Id: I949be90419b03610c64900be0fd37f83b70cbe73
2012-10-08 18:26:21 -07:00
7b3eb372ad Tune lossless compression to get better gains.
Tune compression heuristics to get better gains across wide quality range.

Change-Id: Ic342d4dbcf83fe2086a34e5c184aef0714109430
2012-10-05 09:58:29 -07:00
ce8bff45bc Merge "VP8LAllocateHistogramSet: fix overflow in size calculation" 2012-10-03 14:57:15 -07:00
ab5b67a1d0 Merge "EncodeImageInternal: fix uninitialized free" 2012-10-03 14:53:35 -07:00
7fee5d1231 Merge "GetHistoBits: fix integer overflow" 2012-10-03 14:51:22 -07:00
a6ae04d455 VP8LAllocateHistogramSet: fix overflow in size calculation
the multiplications done for total_size would be done with integers,
possibly overflowing, before being promoted to 64-bit for the addition

Change-Id: Id5c127c8a497ce5de89a276c17f36b59eeb67c21
2012-10-03 12:18:00 -07:00
80237c4371 GetHistoBits: fix integer overflow
huff_image_size was a size_t (=32 bits with 32-bit builds) which could
rollover causing an incorrectly sized allocation and a crash in lossless
encoding.
fixes issue #128

Change-Id: I175c8c6132ba9792034807c5c1028dfddfeb4ea5
2012-10-03 12:17:52 -07:00
8a9972353d EncodeImageInternal: fix uninitialized free
on allocation error refs.refs would be uninitialized and free'd, causing
a crash

Change-Id: I8d77069aadc594758aaa79b2b73376c0107e57e4
2012-10-03 12:17:47 -07:00
0b9e682934 minor cosmetics
spotted in patch #34187

Change-Id: Ia706af6ef7674ec7a1d7250da08f718ed7c09e72
2012-10-03 15:22:33 +02:00
a792b913bd fix the -g/O3 discrepancy for 32bit compile
in debug mode, some float operations see their intermediate
values stored in memory rather than staying in the FPU (which
is 80bit precision).

Several fixes are possible (breaking long calculations into
atomic steps for instance), but simpler of all is just about
turning the cost[] array into float* instead of double*.

The code is a tad faster, and i didn't see any major output
size difference.

Change-Id: Icf1f833e15f8ee4ecc7f9a521d07fdc96ef711aa
2012-10-03 15:15:58 +02:00
73ba4357fe Merge "detect and merge similar segments" 2012-10-02 06:22:23 -07:00
fee6627538 detect and merge similar segments
similar = same quant and filter strength.
This save some bits in the segment map

Change-Id: I6f594474ad82bddf013278d47089e43a02e07e63
2012-10-01 21:18:03 +02:00
0c44f41585 src/webp/*.h: don't forward declare enums in C++
Change-Id: I36d3765e94d2b5529b321c186ccee1744785c5b3
fixes:
 error: ISO C++ forbids forward references to 'enum' types
since:
 28d25c8 replace 'typedef struct {} X;" by "typedef struct X X; struct X {};"
2012-09-28 21:21:41 -07:00
d7a5ac86b9 vwebp: use demux interface
fixes broken build since:
 ab3234a Create WebPMuxFrameInfo struct for Mux APIs

Change-Id: I19d472f672b9234b15425a2e55ca89a3ea35bd64
2012-09-26 23:44:59 -07:00
931e0ea1d5 Merge "replace 'typedef struct {} X;" by "typedef struct X X; struct X {};"" 2012-09-26 07:13:36 -07:00
8f216f7e60 remove cases of equal comparison for qsort()
Returning 0 (equal) can lead to undefined behaviour.
And, in our cases we'll never have equal keys (added asserts for that)

Change-Id: Ifaf202df321d3f877ad2a03de42e0d6cdd1b2388
2012-09-25 19:03:41 +02:00
28d25c8256 replace 'typedef struct {} X;" by "typedef struct X X; struct X {};"
Change-Id: I937dc8781bc87ef0c4e109d49dc1cf6f18033f12
2012-09-25 18:39:22 +02:00
2afee60a7c speed up for ARM using 8bit for boolean decoder
SBITS=8 is reported 20-30% faster on ARM (where 64bit ops
are expensive).

Also use 32bits for i32.

Change-Id: Id6a7197d805061aeb8832f20432512d0d930ebfa
2012-09-10 23:27:58 +02:00
5725cabac0 new segmentation algorithm
fixes the 'blocky sky problem' (saturation problem: when luma was flat,
chroma noise was taking over, resulting in random segment id assigned.
When just using a common uniform segment was better).

+ side clean-up and readibility/experimentability MACRO'ization
+ added '-map 7' option

Change-Id: I35982a9e43c0fecbfdd7b05e4813e8ba8c121d71
2012-09-04 23:09:15 +02:00
2cf1f81590 Merge "fix the BITS=8 case" 2012-09-03 02:36:03 -07:00
12f78aec48 fix the BITS=8 case
spotted by Måns Rullgård (mans at mansr dot com)
Change-Id: I4720dc2eeb645af894e396739be6fa11b5fe2739
2012-09-03 02:29:14 -07:00
6920c71f0a fix MSVC warnings regarding implicit uint64 to uint32 conversions
Change-Id: I284dae9222a3817bba3c5ba6be271b31b5bf660d
2012-09-01 07:21:45 -07:00
f6c096aad3 webpmux binary: Rename 'xmp' option to 'meta'
Change-Id: I00d7d2aa43ccb1e86b58e75e8677ea8ef7e1226e
2012-08-29 22:24:10 -07:00
ddfe871a51 webpmux help correction
Clarify 'SET_OPTIONS'

Change-Id: I623ea955beb2a800709412b914a257abd95266cc
2012-08-29 22:23:12 -07:00
b7c5544216 Merge "Make *InitSSE2() functions be empty on non-SSE2 platform" 2012-08-29 08:26:42 -07:00
1c04a0d438 Common APIs for chunks metadata and color profile.
Change-Id: Ie105ce913c0b56e34cc26fd7ec397103354f268a
2012-08-29 08:21:43 -07:00
2a3117a1e6 Merge "Create WebPMuxFrameInfo struct for Mux APIs" 2012-08-29 08:19:07 -07:00
5c3a7231ca Make *InitSSE2() functions be empty on non-SSE2 platform
this avoids the '*.o has no symbols' warning messages

Change-Id: I00cf527a9041a810d896bd24b993112af6276323
2012-08-28 11:02:38 -07:00
7c6e60f4bd make *InitSSE2() functions be empty on non-SSE2 platform
this avoids the '*.o has no symbols' warning messages

Change-Id: Idbaa02f5c2f7c632997a26f9507926922d191b6e
2012-08-27 23:40:47 -07:00
c7eb45764f make VP8DspInitNEON() public
this will avoid the "dec_neon.o has no symbol" warning

no change in binary size observed on linux.

Change-Id: Ia27ae2bc5a03d714afa7e46671fdcf4cb630784d
2012-08-27 00:28:13 -07:00
ab3234ae6b Create WebPMuxFrameInfo struct for Mux APIs
Change-Id: I1f3b15d679280b5347124e1d59865a3df089043b
2012-08-23 15:18:51 +05:30
e3990fd8e4 Alignment fixes
Change-Id: I99b570a6621be271abd3df1c3316cdd7286cfe83
2012-08-23 13:22:59 +05:30
e55fbd6d2c Merge branch '0.2.0'
* 0.2.0: (42 commits)
  Update ChangeLog
  dec/io.c: cosmetics
  RGBA4444: harmonize lossless/lossy alpha values
  fix RGBA4444 output w/fancy upsampling
  Alignment fix
  avoid rgb-premultiply if there's only trivial alpha values
  fix the ARGB4444 premultiply arithmetic
  Lossless decoder fix for a special transform order
  Update encoding heuristic w.r.t palette colors.
  remove unused ApplyInverseTransform()
  Update ChangeLog
  update AUTHORS
  update NEWS
  add support for ARGB -> YUVA conversion for lossless decoder
  bump version to 0.2.0
  fix alpha-plane check + add extra checks
  MODE_YUVA: set alpha to opaque if the image has none
  silence one more warning
  move some RGB->YUV functions to yuv.h
  README: sync [cd]webp help output
  ...

Change-Id: I4c4e3be2e88655d25d4dd2eae46c580d960b12ac
2012-08-17 14:33:56 -07:00
4238bc0adb Update ChangeLog
Change-Id: I598aaf69c1a45a694c36f2f3166ed9adc20ace84
2012-08-15 22:49:03 -07:00
c655380c36 dec/io.c: cosmetics
- deindent EmitAlphaRGB*
- add some missing consts

Change-Id: I65f88da295e6a0afa383fadc2ef90a40613c2d62
2012-08-15 10:27:54 -07:00
fe1958f17d RGBA4444: harmonize lossless/lossy alpha values
lossy was rounding with a bias toward opaque:
[232+, 8] -> [15, 1]
now both paths use the range:
[240+, 16] -> [15, 1]

Change-Id: I3da2063b4959b9e9f45bae09e640acc1f43470c5
2012-08-14 14:02:30 -07:00
681cb30ad2 fix RGBA4444 output w/fancy upsampling
compensates for the 1-line delay in the upscaler, outputting the correct
alpha row

Change-Id: Ia9a65bcb3cfa19e42185523cc6e706101a39d45d
2012-08-14 13:11:53 -07:00
f06c1d8f7b Merge "Alignment fix" into 0.2.0 2012-08-09 16:09:58 -07:00
f56e98fd11 Alignment fix
Change-Id: Ia5475247f03456b01571ae7531da90f74c068045
2012-08-10 02:10:32 +05:30
6fe843baeb avoid rgb-premultiply if there's only trivial alpha values
With this, MODE_rgbA can safely be used without speed penalty
even in case of pure-lossy alpha-less input.
It's also an optimization when cropping a fully-opaque region from
an image with alpha: premultiply is then skipped

Change-Id: Ibee28c75744f193dacdfccd5a2e7cd1e44604db6
2012-08-09 11:33:29 -07:00
528a11af35 fix the ARGB4444 premultiply arithmetic
* green was not descaled properly
* alpha was over-dithered, making the value '0x0f' not be a fixed point
* alpha value was not restored ok.

Change-Id: Ia4a4d75bdad41257f7c07ef76a487065ac36fede
2012-08-09 11:32:30 -07:00
a0a488554d Lossless decoder fix for a special transform order
Fix the lossless decoder for the case when it has to apply other
inverse transforms before applying Color indexing inverse transform.

The main idea is to make ColorIndexingInverse virtually in-place: we
use the fact that the argb_cache is allocated to accommodate all
*unpacked* pixels of a macro-row, not just *packed* pixels.

Change-Id: I27f11f3043f863dfd753cc2580bc5b36376800c4
2012-08-08 23:52:08 -07:00
62dd9bb242 Update encoding heuristic w.r.t palette colors.
Added a threshold of MAX_COLORS_FOR_GRAPH for color-palettes, above
which the graph hint is ignored.

Change-Id: Ia5d7f45e52731b6eaf2806999d6be82861744fd3
2012-08-08 18:57:52 -07:00
6f4272b090 remove unused ApplyInverseTransform()
transforms are only allowed for is_level0

Change-Id: Iec8ce8bdbe024aae6cae2688e2934ab8f445000c
2012-08-07 22:41:25 -07:00
93bf0faafa Update ChangeLog
Change-Id: I5ff337065b8a6f8952dc77c3f9c7798267ee6727
2012-08-03 16:21:12 -07:00
5934fc59db update AUTHORS
Change-Id: I205422ac3be5e363adfc84dcf84f6d5d84b9a40f
2012-08-03 16:15:38 -07:00
014a711d96 update NEWS
changes since v0.1.99

Change-Id: Iaab1545516ef8df9f9dd6b4bc9cbf07539cb454f
2012-08-03 16:13:29 -07:00
43b0d6107a add support for ARGB -> YUVA conversion for lossless decoder
This was returning an (hard-to-explain) error before.
(through WebPDecodeYUV() for instance).

+ rationalize the incremental API:
-> add WebPINewYUVA
-> deprecated WebPINewYUV
-> add WebPIDecGetYUVA
-> deprecated WebPIDecGetYUV

+ some NULL cosmetics

Change-Id: I39a6bd6018a34294d898b29f6c40e2cf76f1037e
2012-08-03 15:41:01 -07:00
33705ca093 bump version to 0.2.0
Change-Id: I01cb50b9c4c8e9245aede3947481cbbd27d6a19d
2012-08-03 15:41:01 -07:00
c40d7ef125 fix alpha-plane check + add extra checks
Change-Id: I9d8c9743f9d4f3d394544773ed2d0c31a9acf24d
2012-08-03 14:44:35 -07:00
a06f802325 MODE_YUVA: set alpha to opaque if the image has none
this change avoids returning uninitialized alpha values when decoding
lossy with alpha to YUVA

Change-Id: I1e02459ac28b36f1f2b422063d057a5faba2f8f2
2012-08-03 12:04:44 -07:00
52a87dd7ff Merge "silence one more warning" into 0.2.0 2012-08-02 17:53:04 -07:00
3b02309347 silence one more warning
inadvertently added in last warning roundup

Change-Id: I38e6bcfb18c133f2dc2b38cec81e12d2ff556011
2012-08-02 17:50:12 -07:00
f94b04f045 move some RGB->YUV functions to yuv.h
will be needed later

Change-Id: I6b9e460db2d398b9fecd5d3c1bbdb3f2f3d4f5db
2012-08-02 17:23:02 -07:00
4b71ba035a README: sync [cd]webp help output
Change-Id: Ic54e0f3e5e2e667adb369321e5849890d3b96e42
dwebp: -pam, -alpha
2012-08-02 16:11:02 -07:00
c9ae57f596 man/dwebp.1: add links to output file format details
Change-Id: I30e3e52e428c9e68ba2ec263024a1edc56ad6741
2012-08-02 15:10:31 -07:00
292ec5cc7d quiet a few 'uninitialized' warnings
spurious in this case, but addresses e.g.,
... potentially uninitialized local variable 'weighted_average' used

Change-Id: Ib99998bf49e4af7a82ee66f13fb850ca5b17dc71
2012-08-02 14:03:30 -07:00
4af3f6c4d3 fix indentation
Change-Id: Ib00b3cdc21ac336a56390f1e71c169e7fd4767a6
2012-08-02 11:55:55 -07:00
9b261bf521 remove the last NOT_HAVE_LOG2 instances
Change-Id: I193ecf82316cd1d5d7ddeebebf8fc98afccf0ede
2012-08-02 06:42:41 -07:00
323dc4d9b9 remove use of log2(). Use VP8LFastLog2() instead.
Order-by-cost mostly unchanged (up to a scaling constant 1/log(2))
(except for few minor diff in < 2% of cases)

+ remove unused field cost_mode->cache_bits_

Change-Id: I714f8ab12f49a23f5d499a64c741382c9b489a3e
2012-08-02 00:08:58 -07:00
8c515d54ea Merge "harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc" into 0.2.0 2012-08-01 18:16:46 -07:00
d4b4bb0248 Merge changes I46090628,I1a41b2ce into 0.2.0
* changes:
  check VP8LBitWriterInit return
  lossless: fix crash on user abort
2012-08-01 13:19:32 -07:00
bff34ac1ca harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc
quite a large security sweep.

Change-Id: If150dfbb46e6e9b56210473a109c8ad6ccd0cea4
2012-08-01 12:06:04 -07:00
a3c063c714 Merge "extra size check for security" into 0.2.0 2012-08-01 12:00:30 -07:00
5e7963000a Merge "WebPEncode: clear stats at the start of encode" into 0.2.0 2012-08-01 12:00:09 -07:00
f1edf62fae Merge "rationalize use of color-cache" into 0.2.0 2012-08-01 11:55:36 -07:00
c19333173a extra size check for security
no speed diff observed by removing the test before calling BitWriterResize().

+ remove some unnecessary memset() in VP8LBitWriter
+ fix mixed code/variable-decl in BIG_ENDIAN mode

Change-Id: I36be61f83d10a43e4682b680c2dae0e494da4218
2012-08-01 00:37:24 -07:00
906be65744 rationalize use of color-cache
* ~1-4% faster
* if it's not used, don't use it
* remove the special handling of cache_bits = 0
* remove some tests in the loops

Change-Id: I19d87c3ca731052ff532ea8b2d8e89816507b75f
2012-08-01 00:32:12 -07:00
dd1c3873fe Add image-hint for low-color images.
For low-color images, it may be better to not use color-palettes.
Users should treat this as one another hint (as with Photo &
Picture) and another parameter for tuning the compression density.
The optimum compression can still be obtained by running (outer loop)
compression with all possible tunable parameters.

Change-Id: Icb1a4face2a84774e16e801aee4a8ae97e232e8a
2012-07-31 23:11:19 -07:00
4eb7aa64da Merge "WebPCheckMalloc() and WebPCheckCalloc():" into 0.2.0 2012-07-31 18:37:14 -07:00
80cc7303ab WebPCheckMalloc() and WebPCheckCalloc():
safe size-checking versions of malloc() and calloc()

Change-Id: Iffa3138c48b9b254b3d7eaad913e1f852d9dafba
2012-07-31 16:56:39 -07:00
183cba83a7 check VP8LBitWriterInit return
Change-Id: I460906281598f5792bd75a25b14b449c8daaff8c
2012-07-31 12:11:40 -07:00
cbfa9eecf4 lossless: fix crash on user abort
avoid free on uninitialized bit writer buffer

Change-Id: I1a41b2cea421bf5a2ea0af33c6e84018cb997caf
2012-07-31 11:59:54 -07:00
256afefa50 cwebp: exit immediately on version mismatch
{Picture,Config}Init don't do allocations and attempting to free any of
their contents on version mismatch will likely cause a crash

Change-Id: I2a5aece235f9680fb406aec4799adceea7f62cfc
2012-07-27 19:58:58 -07:00
475d87d767 WebPEncode: clear stats at the start of encode
also relocate user_data from WebPAuxStats to the WebPPicture struct to
make clearing easier while placing it closer to the progress hook with
which it's used.
prior to this change some spurious lossless data could be reported in
the lossy (sans alpha) encoding case. additionally user_data could be
lost during lossless encoding.

Change-Id: I929fae3dfde4d445ff81bbaad51445ea586dd80b
2012-07-27 19:57:18 -07:00
a7cc729126 fix type and conversion warnings
avoids warning messages on MSVC mainly

Change-Id: I80f281d5263a54c6a224bb095175497cf2f4ce1e
2012-07-25 14:18:21 -07:00
7d853d79dc add stats for lossless
* Extend AuxStats with new fields
  it's slightly ABI-incompatible, but i guess it's ok for 0.1.99+
  I expect to add more stats later, possibly (predictor stats, etc.)
* Have cwebp report the features used by lossless
  compression (either for alpha or full lossless coding)
* Print the PSNR for alpha (useful in case of -alpha_q)
* clean-up alpha.c signatures
+ misc cleanup (added const '* const ptr', etc.)

Change-Id: I157a21581f1793cb0c6cc0882e7b0a2dde68a970
2012-07-24 16:17:13 -07:00
d39177b74c make QuantizeLevels() store the sum of squared error
(instead of MSE).
Useful for directly storing the alpha-PSNR (in another patch)

Change-Id: I4072864f9c53eb4f38366e8025a2816eb14f504e
2012-07-24 15:06:18 -07:00
5955cf5e89 replace x*155/100 by x*101581>>16
Don't expect a visible speed diff. it's just cool.
(and, that's one less TODO in the code).

Change-Id: Iaeb2f1c930debb51501e170ee806f2f945fb1a8d
2012-07-24 15:06:00 -07:00
7d732f905b make QuantizeLevels() store the sum of squared error
(instead of MSE).
Useful for directly storing the alpha-PSNR (in another patch)

Change-Id: I4072864f9c53eb4f38366e8025a2816eb14f504e
2012-07-23 14:26:56 -07:00
e45a446ad5 replace x*155/100 by x*101581>>16
Don't expect a visible speed diff. it's just cool.
(and, that's one less TODO in the code).

Change-Id: Iaeb2f1c930debb51501e170ee806f2f945fb1a8d
2012-07-23 14:23:33 -07:00
159b75d31a cwebp output size consistency:
In case of lossless too, it should report full file size.
Fixes this issue: http://code.google.com/p/webp/issues/detail?id=126

Change-Id: I96e2bf09e6c9470a0267f5eea911d9b40d1addb3
2012-07-23 12:47:24 +05:30
cbee59eba4 Merge commit 'v0.1.99'
* commit 'v0.1.99': (39 commits)
  Update ChangeLog
  add extra precision about default values and behaviour
  header/doc clean up
  Makefile.vc: fix webpmux.exe *-dynamic builds
  remove INAM, ICOP, ... chunks from the test webp file.
  harmonize authors as "Name (mail@address)"
  makefile.unix: provide examples/webpmux target
  update NEWS
  README: cosmetics
  man/cwebp.1: wording, change the date
  add a very crude progress report for lossless
  rename 'use_argb_input' to 'use_argb'
  add some padding bytes areas for later use
  fixing the findings by Frederic Kayser to the bitstream spec
  add missing ABI compatibility checks
  Doc: container spec text tweaks
  add ABI compatibility check
  mux.h: remove '* const' from function parameters
  encode.h: remove '* const' from function parameters
  decode.h: remove '* const' from function parameters
  ...

Conflicts:
	src/mux/muxinternal.c

Change-Id: I635d095c451742e878088464fe6232637a331511
2012-07-21 12:20:19 -07:00
1889e9b6cc dwebp: report -alpha option
remove from WEBP_EXPERIMENTAL_FEATURES block; alpha is no longer
experimental.

Change-Id: I57df006ecac8122a987e52084813dc84ca7bcfd6
2012-07-20 19:42:56 -07:00
3bc3f7c0ee Merge "dwebp: add PAM output support" into 0.2.0 2012-07-20 19:09:45 -07:00
d919ed06eb dwebp: add PAM output support
retains the alpha channel rather than stripping it as with PPM.

display from ImageMagick can render the files

Change-Id: I4f3a5d332937e0aeaf4e3fbd214fdae3b5382fb8
2012-07-20 19:06:01 -07:00
85e215d36f README/manpages/configure: update website link
code.google was moved to developers.google

Change-Id: I072cab38ccb6f45c3d1d6e533d1626420cdbba56
2012-07-20 16:25:04 -07:00
c3a207b9f4 Update ChangeLog
Change-Id: I7e8192f4c5fd90354669c492235b1348debdc839
2012-07-19 18:19:33 -07:00
d1fd78263f Merge "add extra precision about default values and behaviour" into 0.2.0 2012-07-19 18:15:45 -07:00
efc826e04a add extra precision about default values and behaviour
Change-Id: I445f4d3b20a53d32819fe361f74443e0a0c8a632
2012-07-19 18:08:42 -07:00
9f29635d95 header/doc clean up
Put emphasis on RGBA decoding instead of RGB/BGR
Clarify doc at some rough spots
Misc typo fix and cosmetics

Change-Id: Ic5fcfcc5bf4d612c5de23b0a5499f1fadde55bfe
2012-07-19 18:05:03 -07:00
ff9fd1bac6 Makefile.vc: fix webpmux.exe *-dynamic builds
the libwebpmux objects depend on the generated webp_dll.[hc] files as
well

Change-Id: I26177b56f415d69e4bc34b24d32c70a13c6c053c
2012-07-19 17:55:50 -07:00
8aacc7b056 remove INAM, ICOP, ... chunks from the test webp file.
Change-Id: Ia396d932b8b1af85717f693251c76985abc86395
2012-07-19 17:34:04 -07:00
2fc1301577 harmonize authors as "Name (mail@address)"
Change-Id: I85bfae61a37de75a5ed945a906002de2ef75149f
2012-07-19 16:09:47 -07:00
4a9f37b742 Merge "update NEWS" into 0.2.0 2012-07-19 14:44:06 -07:00
7415ae1386 makefile.unix: provide examples/webpmux target
this target is experimental so must be explicitly set

missing since:
e41a759 build: remove libwebpmux from default targets/config

Change-Id: I128d9e6a06ba3e7102ae3175dc3db52c6f4b1439
2012-07-19 14:39:26 -07:00
ce82cedc4b update NEWS
mention TIFF support, cwebp's alpha encoding disposition

Change-Id: I0340590f43e1617c6fb3fc2e98a609dbf4a880ce
2012-07-19 12:59:39 -07:00
641e28e8dc Merge "man/cwebp.1: wording, change the date" into 0.2.0 2012-07-19 12:58:13 -07:00
c37c23e594 README: cosmetics
- update swig function references
- remove references to decode_vp8.h (no longer installed)
- add lossless references
- some grammar/spelling changes

Change-Id: Icebfbcf6f638762f42d844b6bd3c0129c64d9340
2012-07-19 12:38:46 -07:00
3976dcd59f man/cwebp.1: wording, change the date
options were added since the last date refresh

Change-Id: I3899ebd429ba0260a28ce02bb973e1ee015c6e6e
2012-07-19 12:20:01 -07:00
3e5bbe1c2e Merge "rename 'use_argb_input' to 'use_argb'" into 0.2.0 2012-07-18 23:26:42 -07:00
ce90847a40 Merge "add some padding bytes areas for later use" into 0.2.0 2012-07-18 23:26:18 -07:00
2390dabcb6 Merge "fixing the findings by Frederic Kayser to the bitstream spec" into 0.2.0 2012-07-18 23:19:34 -07:00
0275159143 add a very crude progress report for lossless
better than nothing. Removed the warning in cwebp.c
(and silenced the warning in quiet mode too)

Change-Id: I85bbeaf77e0f60ead798886043dc053e6b44def5
2012-07-18 22:54:50 -07:00
a4b9b1c604 Remove some unused enum values.
- WEBP_MUX_INVALID_PARAMETER: was used only at one place, and that too
should actually be an assert().
- WEBP_MUX_ERROR: was never used.

Change-Id: I8883cb4dfae7a7918507501f21fced0c04dda36a
2012-07-19 11:23:37 +05:30
dd1081763c rename 'use_argb_input' to 'use_argb'
long name, and there's not really an 'output' equivalent

Change-Id: I9133ff734ae8d6572cb2f607211361f011fc0bc1
2012-07-18 22:47:16 -07:00
90516ae8f5 add some padding bytes areas for later use
so we can add few fields without breaking ABI

+ re-order fields
+ refresh the doc

Change-Id: Id60ec33934f6346e35c95fcdb4abbe1bc7b50acb
2012-07-18 22:47:13 -07:00
d03b250369 fixing the findings by Frederic Kayser to the bitstream spec
Change-Id: I4bcc428412dd4c21675d90159771e2e0b338ecf3
2012-07-18 22:47:11 -07:00
ce156afccf add missing ABI compatibility checks
original change:
f7f16a2 add ABI compatibility check

Change-Id: I7cd6508f8d8e0d957a3d62ad52a117876fa5ec29
2012-07-18 22:24:33 -07:00
9d45416aa7 Merge "Doc: container spec text tweaks" into 0.2.0 2012-07-18 21:49:24 -07:00
4e2e0a8cac Doc: container spec text tweaks
Change-Id: I8e29f1c814b0c8f6aa268562d8653989caaf281d
modified:   doc/webp-container-spec.txt
2012-07-18 16:38:50 -07:00
f7f16a2976 add ABI compatibility check
minor revision shouldn't matter, we only check major revision number.
Bumped all version numbers so that incompatibility starts *now*

Change-Id: Id06c20f03039845ae4cfb3fd121807b931d67ee4
2012-07-18 11:53:25 -07:00
2a77557002 Merge "swig: add WebPEncodeLossless* wrappers" into 0.2.0 2012-07-17 17:30:17 -07:00
a3ec6225d5 mux.h: remove '* const' from function parameters
makes the public interface consistent and more readable

Change-Id: I33f1d1c4ee752e353e4c10636a4df4e44d7cd03f
2012-07-17 17:21:54 -07:00
31426ebaec encode.h: remove '* const' from function parameters
makes the public interface consistent and more readable

Change-Id: Ib93614e901e0af44bb64782357cfd9e724e050be
2012-07-17 16:26:54 -07:00
9838e5d5ff decode.h: remove '* const' from function parameters
makes the public interface consistent and more readable

Change-Id: I067eb5ecc1094216ef6aecc65f636f69873de8f9
2012-07-17 15:48:00 -07:00
4972302d24 swig: add WebPEncodeLossless* wrappers
Change-Id: If373a5d2953ec53b856900666422fb2b4f9939a4
2012-07-17 14:41:51 -07:00
9ff00cae72 bump encoder/decoder versions
those returned by WebPGet(Encoder|Decoder)Version()

Change-Id: I7584d04060ae7ca552f8f3aaf9df294d310a5be6
2012-07-17 13:43:39 -07:00
c2416c9b61 add lossless quick encoding functions to the public API
New functions:
   WebPEncodeLosslessRGB()
   WebPEncodeLosslessBGR()
   WebPEncodeLosslessRGBA()
   WebPEncodeLosslessBGRA()

Change-Id: Id56da7569eee80c57de8f1f053fb87b217d33a4b
2012-07-17 12:02:53 -07:00
4c1f5d6435 Merge "NEWS: mention decode_vp8.h is no longer installed" into 0.2.0 2012-07-17 11:20:55 -07:00
6cb2277d0f NEWS: mention decode_vp8.h is no longer installed
Change-Id: Id1075b4a917c83552446fb62dada8868dbdb21ef
2012-07-17 11:19:42 -07:00
d5e5ad6356 move decode_vp8.h from webp/ to dec/
the functions contained in it are now private

Change-Id: Ief6c81b32ae3f6d97052edac625716e5b909e66e
2012-07-16 22:12:59 -07:00
8d3b04a25d Merge "header clean-up" into 0.2.0 2012-07-16 19:21:49 -07:00
02201c35a0 Merge "remove one malloc() by making color_cache non dynamic" into 0.2.0 2012-07-16 19:21:05 -07:00
d708ec1452 Merge "move MIN/MAX_HISTO_BITS to format_constants.h" into 0.2.0 2012-07-16 19:19:32 -07:00
ab2da3e9fd Merge "add a malloc() check" into 0.2.0 2012-07-16 19:18:28 -07:00
2d571bd89f add a malloc() check
mostly a sanity measure to be future-proof

Change-Id: I55a81345819b2a8e939c98f0da883dc5c0cc16a2
2012-07-16 19:15:00 -07:00
7f0c178e46 remove one malloc() by making color_cache non dynamic
Change-Id: I7c71a056f79a79bfacfe64a263f1eb8476c05456
2012-07-16 19:13:58 -07:00
6569cd7c88 Merge "VP8LFillBitWindow: use 64-bit path for msvc x64 builds" into 0.2.0 2012-07-16 19:13:30 -07:00
23d34f3142 header clean-up
remove unused VP8LHistogramRemove function
make HistogramEstimateBitsHeader static

Change-Id: I0dc6a6f4c41d3c5f55a8153cd7d710c9f84582a7
2012-07-16 19:13:01 -07:00
2a3ab6f925 move MIN/MAX_HISTO_BITS to format_constants.h
(under the name MAX_HUFFMAN_BITS, since the specs read:
	int huffman_bits = ReadBits(3) + 2;
)

Change-Id: Ifc66576bbd8e48518d3d78a3f515f851cf1883dc
2012-07-16 19:11:54 -07:00
985d3da6c4 Merge "shuffle variables in HashChainFindCopy" into 0.2.0 2012-07-16 19:11:00 -07:00
cdf885c67c shuffle variables in HashChainFindCopy
might lead to observable speed-up on some compiler/arch

Change-Id: I6c89ec9cd4f490e7e22b790785f80097a47d27b5
2012-07-16 19:08:59 -07:00
c3b014db28 Android.mk: add missing lossless files
Change-Id: I5d97e22392ed3847e97f3b31c928d3828fa6732a
2012-07-16 18:43:07 -07:00
8c1cc6b5dc makefile.unix dist: explicitly name installed includes
avoids mux.h, format_constants.h

Change-Id: I6c8458dd1ce7faa23fbf1e3df84a8dfc4a884a3e
2012-07-16 16:32:15 -07:00
7f4647eecb Merge "clarify the colorspace naming and byte ordering of decoded samples" into 0.2.0 2012-07-16 12:16:17 -07:00
cbf69724d2 clarify the colorspace naming and byte ordering of decoded samples
Change-Id: If5ac331bd1e45e7c959b5fa60248268ae2bbe861
2012-07-16 12:09:51 -07:00
857650c8fc Mux: Add WebPDataInit() and remove WebPImageInfo
Change-Id: If661f7d198e284a103a53a451e9f74805119fcf9
2012-07-16 11:12:05 +05:30
ff771e7705 don't install webp/decode_vp8.h
the VP8 decode functions do not need to be public; only
GetInfo/CheckSignature need to be marked extern as they're used by
libwebpmux.

Change-Id: Id9ab4d6166b0271cf5d04563c6dac1fcc84adbdc
2012-07-14 21:23:03 -07:00
596dff784d VP8LFillBitWindow: use 64-bit path for msvc x64 builds
Change-Id: I14a3865f4091dd048e02abc99aa4e7f1e325e12a
2012-07-14 13:20:26 -07:00
3ca7ce9805 Merge "doc: remove non-finalized chunk references" into 0.2.0 2012-07-14 10:58:52 -07:00
1efaa5a369 Merge "bump versions" into 0.2.0 2012-07-14 10:57:58 -07:00
51fa13e170 Merge "README: update cwebp help output" into 0.2.0 2012-07-14 09:29:19 -07:00
12f9aede7e README: update cwebp help output
Change-Id: Ifc2fafca8131e53a894056e37bb22d25fedfa150
2012-07-13 14:55:39 -07:00
f0b5defb0a bump versions
lib - 0.1.99
libtool - 3.0.0 (interface changes)

Change-Id: Id52f8b8df5b941b15af6cb54b1cc05daf322179f
2012-07-13 14:07:51 -07:00
4c42a61b9a update AUTHORS
Change-Id: Ibf5b8c6aa101e6dd6cbcb69485ae582364387d80
2012-07-13 13:55:31 -07:00
6431a1ce3d doc: remove non-finalized chunk references
tiles, animation, etc.

Change-Id: Ie83135be576f516fe475c7be21171f9d12a17ce4
2012-07-13 12:33:49 -07:00
8130c4cc64 Merge "build: remove libwebpmux from default targets/config" 2012-07-13 11:33:52 -07:00
23b44438dd Merge "configure: broaden test for libpng-config" 2012-07-13 11:13:26 -07:00
85bff2cdbe Merge "doc: correct lossless prefix coding table & code" 2012-07-13 11:12:14 -07:00
05108f6ea0 Merge "More spec/code matching in mux:" 2012-07-12 23:53:58 -07:00
6808e69db8 More spec/code matching in mux:
- Match offsets, duration, width/height for frames/tiles and enforce
some constraints.
- Note that this also means using 'int's instead of 'uint32_t's for
16-bit and 24-bit fields.

Change-Id: If0b229ad9fce296372d961104aa36731a3b1304b
2012-07-13 11:47:24 +05:30
bd2b46f5f2 Merge "doc/webp-container-spec: light cosmetics" 2012-07-12 21:04:27 -07:00
20ead3290f doc/webp-container-spec: light cosmetics
- provide anchor links to the bitstream chunks referenced in the
  extended format section
- remove some unnecessary parenthetical notation and add some
  consistency to various chunk element definitions

Change-Id: Ifd946fee81b36e4e555399555a2a58c853fdc3b7
2012-07-12 19:19:39 -07:00
1d40a8bce8 configure: add pthread detection
adds a --disable-threading option to prevent the check.
uses AX_PTHREAD from:
git://git.savannah.gnu.org/autoconf-archive.git
100644 blob d90de34d14    ax_pthread.m4

Change-Id: Icf3ad1ebcf052748bc341706effcc9ba02a259e4
2012-07-12 16:27:29 -07:00
b5e9067a28 fix some int <-> size_t mix for buffer sizes
could have led to some negative overflow on 32bit arch
(if it was not for the "total_size == (size_t)total_size" test)

Change-Id: I7640340b605b9c674d30dd58a1e2144707299683
2012-07-12 07:23:01 -07:00
e41a759615 build: remove libwebpmux from default targets/config
the extended file format is still under development and related
libs/binaries are not fit for release

configure:
--enable/disable-libwebpmux; default is disabled.

makefile.unix:
src/mux/libwebpmux.a and examples/webpmux must be explicitly specified

Makefile.vc:
$(DIRLIB)\libwebpmux.lib and $(DIRBIN)\webpmux.exe must be explicitly
specified

Change-Id: I8246746b256010dd2a2e4de58291222d7eaf0457
2012-07-11 14:25:41 -07:00
0fc2baae5c configure: broaden test for libpng-config
some versions of cygwin's libpng-devel only install libpngXX-config,
e.g., libpng12-config, but do not create libpng-config. the library also
has a version number.

Change-Id: I35332b7011e2dbabb95b599f810523a729d6097e
2012-07-11 14:21:50 -07:00
45b8272c31 Merge "restore authorship to lossless bitstream doc" 2012-07-11 13:56:10 -07:00
06ba05909e restore authorship to lossless bitstream doc
lost in port from pdf

Change-Id: I17bad348577be9818c036e557a0beba63ffcc689
2012-07-11 13:46:00 -07:00
44a09a3ccd add missing description of the alpha filtering methods
Change-Id: Id7bdf5e30121ce5d610b7fa00f64bcd2d7bed2bf
2012-07-10 19:50:30 -07:00
63db87dd2a Merge "vwebp: add checkboard background for alpha display" 2012-07-10 12:38:16 -07:00
a73b8978d1 vwebp: add checkboard background for alpha display
Change-Id: Iefb02f38c0479e61334844d9110cd1b735f0395d
2012-07-10 12:02:03 -07:00
939158ce4f Merge "vwebp: fix info display" 2012-07-10 07:37:28 -07:00
b35c07d9a7 vwebp: fix info display
change alpha intensity to 1 from 0; broken since alpha blending was enabled.

Change-Id: Ic8bb73b62e602ae56e08e9d5a77fdc6aa76b54c5
2012-07-09 22:47:10 -07:00
48b39eb17a fix underflow for very short bitstreams
+ hardened the asserts

Change-Id: Ie798ef2f9d848c131f6f84a35ea28ef254822d1e
2012-07-09 16:47:34 -07:00
7e622984bb cosmetics: param alignment, manpage wording
after eb6f9b8, c0e8859

Change-Id: I79bcea77d65eb6d1abf1156796996f3b9909b62b
2012-07-07 10:37:26 -07:00
1bd7dd5097 Merge changes I7b0afb0d,I7ecc9708
* changes:
  Get rid of image_info_ from WebPChunk struct.
  WebP Container Spec:
2012-07-04 16:32:29 -07:00
ac69e63eeb Merge "Updated cwebp man's help for Alpha & Lossless." 2012-07-04 16:30:03 -07:00
c0e8859d81 Get rid of image_info_ from WebPChunk struct.
The image_info_ was used only in GetImageCanvasWidthHeight(). So, now
we infer it from data there.
This removal fixes a bug: earlier, 'image_info' wasn't initialized in
the WebPMuxCreate() flow, and so the canvas width/height were being
calculated to be zero.

Also, a related refactoring: Combine CreateImageInfo() and
CreateDataFromImageInfo() into a single function CreateFrameTileData().

Change-Id: I7b0afb0d36dc6e13b9d6a1135fb027aa4e03716c
2012-07-04 18:49:56 +05:30
135ca69eb7 WebP Container Spec:
Clarify that a file must contain at least one frame.

Change-Id: I7ecc97084498adc108275585d0c7d0aaa9f5c6ed
2012-07-04 17:28:17 +05:30
eb6f9b8a72 Updated cwebp man's help for Alpha & Lossless.
Change-Id: Iaa129685fdbd95c3b408c92c77532b321bc2637f
2012-07-04 12:51:56 +05:30
0fa844fb8f cosmetic fixes on assert and 'const' where applicable
Change-Id: Iede15b8464be453e7d12929513ed82183921265c
2012-07-03 05:50:36 -07:00
7f22bd2596 check limit of width * height is 32 bits
Update the RIFF-specs file too

Change-Id: I113a7e25da2f7a19c1344c1dc5d496127cfe2596
2012-07-03 05:42:13 -07:00
16c46e83ac autoconf/make: cosmetics: break long lines
Change-Id: If08350a27cdfc4371dcb28ecb9d88d05eceaf977
2012-07-02 21:48:18 -07:00
ab22a07afc configure: add helper macro to define --with-*
replaces repeated --with-{jpeg,png,tiff}{include,lib}dir defines

Change-Id: Ic0eb8622dfc94184ab74f8302112c36547a34664
2012-07-02 21:26:48 -07:00
c17699b343 configure: add libtiff test
Change-Id: Ia5828797bae9c993a3d00ddd5e0089d3b828e975
2012-07-02 18:01:49 -07:00
0e09732c5e Merge "cwebp: fix crash with yuv input + lossless" 2012-07-02 14:40:00 -07:00
88a510ff53 Merge "fix big-endian VP8LWriteBits" 2012-07-02 14:38:32 -07:00
da99e3bfcd Merge "Makefile.vc: split mux into separate lib" 2012-07-02 14:36:17 -07:00
7bda392b50 cwebp: fix crash with yuv input + lossless
Change-Id: Ia27c925f532a4243369288e954abdc063b9f94f9
2012-07-02 14:33:25 -07:00
f56a369ab0 fix big-endian VP8LWriteBits
bits would be lost if n_bits was > 17

Change-Id: Id315d075075338a08e10c04faa91cab347a53591
2012-07-02 14:30:41 -07:00
54169d6cd7 Merge "cwebp: name InputFileFormat members consistently" 2012-07-02 13:19:27 -07:00
e2feefa9b8 Makefile.vc: split mux into separate lib
similar to other builds, reusing some variable naming from
makefile.unix.
also change the main output file names to libwebp{,mux}.{lib,dll} with
the import lib retaining the _dll suffix.

Change-Id: I6bbc4fb39ab37957f153e9f31954387b24094581
2012-07-02 12:37:57 -07:00
27caa5aa34 Merge "cwebp: add basic TIFF support" 2012-07-02 11:39:21 -07:00
d8921dd4e6 cwebp: name InputFileFormat members consistently
append an '_'. TIFF introduced TIFF_ to avoid a name clash.

Change-Id: Iebe484d43aeb8e1912cd5bd10d36e1c5e66a4b42
2012-07-02 11:24:23 -07:00
6f76d246ba cwebp: add basic TIFF support
Change-Id: I29f354e1ef9cf8f23002cf2e15814a53a94b4ed5
2012-07-02 11:22:52 -07:00
4691407bb3 Merge changes If39ab7f5,I3658b5ae
* changes:
  WebPMuxCreate() error handling:
  Fix a memleak in WebPMuxCreate()
2012-07-02 01:46:17 -07:00
cca7c7b81b Fixed nit: 10 -> 10.f
Change-Id: I0cdb096525460b27f3adcb9f802f6dc193d5f590
2012-07-02 11:29:01 +05:30
5d09a244b7 WebPMuxCreate() error handling:
Directly return NULL if no allocation is done yet.

Change-Id: If39ab7f5a55833263d3372fa0a5d9b0a600cb9ed
2012-07-02 11:20:09 +05:30
777341c3d0 Fix a memleak in WebPMuxCreate()
Change-Id: I3658b5ae487082aef28989eb8abc274c207fef0f
2012-07-02 10:19:21 +05:30
61c9d161d5 doc: correct lossless prefix coding table & code
extra bit counts and literal distance return value

Change-Id: I290e3ee8900469503a323f87e9dbb8ca5cb4afc7
2012-07-01 14:10:32 -07:00
4c3975792b Merge "mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN" 2012-06-29 10:31:26 -07:00
e4e36cc6c6 Merge "Mux: Allow only some frames/tiles to have alpha." 2012-06-29 05:17:26 -07:00
ad2aad3c21 Merge "WebP Decoding error handling:" 2012-06-29 05:15:55 -07:00
97649c8f6b Mux: Allow only some frames/tiles to have alpha.
And related const fixes.

Change-Id: I79f6f1b9f8c6faac8cc4ef24b58edff6d90de045
2012-06-29 17:17:19 +05:30
f864be3b2c Lower the quality settings for Alpha encoding.
Evaluated the impact of this change over 1000 image corpus.
The compression density is up (on average) by 1.2% and encoding time has
gone down considerably from 716 ms (per file) to 146 ms (per file)
(4.9X improvement in encoding time).

Change-Id: Ida562cc0bfe18c9d6f5f00873c95f8396b480eab
2012-06-29 16:19:42 +05:30
3ba81bbe8b WebP Decoding error handling:
- Don't allow any extended chunks (except ALPH) without RIFF & VP8X
chunks.
- Also, don't allow VP8X without RIFF.

Change-Id: I1beba43e617ec637901aeeb93f2f484ec086a75d
2012-06-29 14:32:21 +05:30
fcc69923b9 add automatic YUVA/ARGB conversion during WebPEncode()
Adds new methods WebPPictureARGBToYUVA() and WebPPictureYUVAToARGB()
Depending on the value of picture->use_argb_input,
the main call WebPEncode() will convert appropriately.
Note that both conversions are lossy, so it's recommended to:
* use YUVA input for lossy compression (picture->use_argb_input=0)
* use ARGB input for lossless compression (picture->use_argb_input=1)

Change-Id: I8269d607723ee8a1136b9f4999f7ff4e657bbb04
2012-06-28 00:34:23 -07:00
802e012a18 fix compilation in non-FANCY_UPSAMPLING mode
Change-Id: Id0b1fad3a4888b6e9563a227412b2e6a656d9a2a
2012-06-28 00:26:35 -07:00
e012dfd90f make width/height coding match the spec
* width/height in VP8X chunk is 24bit now
* Added some more constants #defines

Change-Id: I2f8ca7f965a247bccd341dd079ed2abf549c39d7
2012-06-28 00:20:28 -07:00
228d96a538 mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN
these functions are used by libwebpmux

Change-Id: Ifcb79e685f3a6b53007c0dc5f220737daba97d47
2012-06-27 16:07:33 -07:00
637a314f97 remove the now unused *KeepA variants
Change-Id: I65217f3075e30bc9a7f38a49d09f01c9d7271d6a
2012-06-27 10:00:48 -07:00
d11f6fcc82 webpmux returns error strings rather than numbers
Change-Id: Ifc8d8aaf0f6c03ecb1508ec7fbc34c918bf69c61
2012-06-27 16:55:57 +05:30
fcec059322 makefile.unix: cwebp: fix OSX link
this is more a workaround than a fix. this change forces the tables
from yuv.h into the data section rather than generating them as common
blocks. prior to this the linkage would fail with e.g.,

Undefined symbols:
...
  "_VP8kClip4Bits", referenced from:
      _Yuv444ToRgba4444 in libwebp.a(libwebpdsp_la-upsampling.o)

broken since:
 48f8275 add colorspace for premultiplied alpha

Change-Id: I69c36758c31cd3a4b3ea5c412674d1a47b45447e
2012-06-26 18:09:55 -07:00
6b811f1b06 Merge "doc: remove lossless pdf" 2012-06-22 15:43:20 -07:00
c963482124 doc: remove lossless pdf
superseded by webp-lossless-bitstream-spec.txt

Change-Id: I5f233d4c3c2fa048a180db950ad4319ffdb9bced
2012-06-22 15:25:03 -07:00
b9ae4f0d88 cosmetics after mux changes b74ed6e, b494ad5
Change-Id: I8f693b1ba2537de89bda1dfbcf3b95abd17e420a
2012-06-22 14:30:01 -07:00
b494ad5096 Mux: only allow adding frame/tiles at the end.
Change-Id: I5d685628da8c8ac85144cee2e5808b30ec79fef9
2012-06-22 11:18:18 -07:00
2c341b0eed Merge "Added image characteristic hint for the codec." 2012-06-22 02:54:51 -07:00
d373076a53 Added image characteristic hint for the codec.
This image type hint is used by codec to apply appropriate set of
transform filters to the image.

Change-Id: Ibb24e47ba14c40fa7f9f2c50ae86e03f2b29e9a6
2012-06-22 14:03:46 +05:30
2ed2adb5ba Merge "msvc: add intrinsic based BitsLog2Floor" 2012-06-22 00:13:47 -07:00
e595e7c552 Merge "add demux.c to the makefiles" 2012-06-21 23:44:44 -07:00
da47b5bda7 Merge "demux: add {Next,Prev}Chunk" 2012-06-21 23:43:03 -07:00
e5f467420d add demux.c to the makefiles
Change-Id: If98c0ea859c845261218196df35e905589f09e76
2012-06-21 23:21:41 -07:00
4708393c3b demux: add {Next,Prev}Chunk
replaces WebPDemuxSetChunk(). makes this consistent with the Frame
interface.

Change-Id: Ia2b1b98cc290f35b41fd14ee35a2a17cecac7ba8
2012-06-21 23:18:39 -07:00
e8a0a821d2 demux: quiet msvc warnings
min_size is safe to be a uint32_t so avoid the size_t -> uint32_t
conversion

Change-Id: Ib53fe58d313b55dfcf3bee35d0cad48f210d07bf
2012-06-21 23:09:38 -07:00
7f8472a610 Update the WebP Container Spec.
- Add details about the VP8L chunk support.
- Also add new example bitsteams containing VP8L chunk.
- Add back a section describing the VP8 chunk.
- Restrict some fields to 16 or 24 bits instead of 32 bits.
- Fields whose values are always positive are stored 1-based
instead of 0-based.
- Unknown chunks can only occur at certain places in the file.
- Remove the restriction for some fields to be divisible by 32 or 16.
  Instead they are restricted to be even.
- Add a restriction for (canvas_width * canvas_height) product.
- Add 3 bits for rotation & symmetry in VP8X flags.
- Add some new example layouts.
- Add/clarify some nitty-gritties throughout the doc.
- Use the terms frame/tile more consistently and logically.
- Update related TODOs.

Change-Id: I611c1f58ecc3ee87546ca31bad1609376fad251e
2012-06-21 16:04:58 -07:00
31b68fe639 cleanup WebPPicture struct and API
* add a real proper pointer for holding memory chunk pointer
  (instead of using y and argb fields)
* polish the doc with details
* add a WebPPictureView() that extract a view from a picture
  without any copy (kind of a fast-crop).
* properly snap the top-left corner for Crop/View. Previously,
  the luma position was not snapped, and was off compared to the chroma.

Change-Id: I8a3620c7f5fc6f7d1f8dd89d9da167c91e237439
2012-06-21 00:30:43 -07:00
9144a18643 add overflow check before calling malloc()
It's preferable to be over-strict and paranoid here.

Change-Id: Ia928b279b753fa8f836d17decb17a35e6dc441b3
2012-06-20 23:58:43 -07:00
81720c9139 consistency cosmetics
Change-Id: Ie8e372ddcdd6e48527478f70bf716953ed18292a
2012-06-20 23:56:11 -07:00
2ebe8394f8 Merge "Add kramdown version information to README" 2012-06-20 16:02:03 -07:00
7144308402 enc/vp8l.c: fix build
broken since:
233a589 take picture->argb_stride into account for lossless coding

Change-Id: I9ecbbf65f3048be3077d28c3a20dfc0e1afa10be
2012-06-20 14:44:39 -07:00
b7ac19fec9 Add kramdown version information to README
Example kramdown command line to apply syntax highlighting requires
kramdown latest. Command is slightly different for earlier versions.

modified:   doc/README

Change-Id: Icda1197436b5c5ed936ceff53c1dc51aa4ce409b
2012-06-20 14:17:36 -07:00
efdcb6670c Merge "Edit for consistency, usage and grammar." 2012-06-20 14:01:13 -07:00
08220102d1 Enable alpha in vvwebp
Change-Id: I9499b6d4ea64b7eab18cb377f0bb09b6b494c534
2012-06-20 11:20:48 -07:00
8de9a0847b Merge "Mux API change:" 2012-06-20 11:11:49 -07:00
b74ed6e766 Mux API change:
'Set' and 'Get' methods for images take/return a bitstream as input,
instead of separate 'image' and 'alpha' arguments.

Also,
- Make WebPDataCopy() a public API
- Use WebPData for storing data in WebPChunk.
- Fix a potential memleak.

Change-Id: I4bf5ee6b39971384cb124b5b43921c27e9aabf3e
2012-06-20 11:00:42 -07:00
233a589ea9 take picture->argb_stride into account for lossless coding
analysis phase was assuming flat layout...

Change-Id: I96681f6d76aa3faabc51dd2ee3dffbe77ff90d36
2012-06-20 10:13:04 -07:00
04e33f17de Edit for consistency, usage and grammar.
Substantial edit, though less than 100% thorough.  This
makes changes that are clearly safe, but avoids others
where my domain knowledge is incomplete and accuracy
might be compromised.

modified:   doc/webp-lossless-bitstream-spec.txt

Change-Id: I89361a2e1157b8d2e44a8b4f4603f65833f0c1e6
2012-06-20 10:08:53 -07:00
a575b4bc15 Merge "cosmetics: add missing const" 2012-06-19 22:34:28 -07:00
8d99b0f4bd Merge "cosmetics: remove unimplemented function proto" 2012-06-19 22:33:54 -07:00
69d022176d cosmetics: add missing const
Change-Id: I0c0e89bbe826961b02a40ada5a6f89e02abee378
2012-06-19 22:28:34 -07:00
5b08318b57 cosmetics: remove unimplemented function proto
Change-Id: I580fcc756d161cebbabf753ee68c09d189628d7f
2012-06-19 22:27:56 -07:00
b7fb0ed567 Log warning for unsupported options for lossless.
Change-Id: I30d4e775959c7a4a8f5b649c8c90a4edb8cced47
2012-06-20 10:51:50 +05:30
e1f769fe1c msvc: add intrinsic based BitsLog2Floor
Change-Id: Ic0c7d2f03e300c6699e130916a759403e672f9d8
2012-06-19 16:14:54 -07:00
8a69c7d8af Bug-fix: Clamp backward dist to 1.
Check for valid bounds on the 'dist' in backward reference case.
Clamp it to 1 in case of zero and negative values.

Change-Id: I78e956d4595955efa02b1f9628b475093f6ee001
2012-06-19 16:44:03 +05:30
b5b6ac979f Merge "Bring the special writer 'WebPMemoryWriter' to public API" 2012-06-18 16:22:17 -07:00
a6a1909fff Merge "Fix floating point exception with cwebp -progress" 2012-06-18 16:11:53 -07:00
f2cee06708 Fix floating point exception with cwebp -progress
Adds a test of enc->mb_h_ to VP8IteratorProgress() to avoid a division
by zero. Fixes issue #121.

Original patch from even rouault (even dot rouault at gmail dot com).

Change-Id: Ie5fcc1821860c0a9366d5aa11f3aded4f5b98ed7
2012-06-18 15:43:28 -07:00
91b7a8c754 Bring the special writer 'WebPMemoryWriter' to public API
=> WebPMemoryWriter, WebPMemoryWriterInit(), WebPMemoryWrite()

Change-Id: I142fb22b0290ece7a6f6d74f00964a2e9e58ec9b
2012-06-18 15:42:56 -07:00
310e297205 support resize and crop for RGBA input
Change-Id: I19eac3fb4f8ecb973ff5872ac3a921f8947054bf
2012-06-18 15:20:46 -07:00
a89835d33a Merge changes Ice662960,Ie8d7aa90,I2d996d5e,I01c04772
* changes:
  Manually number "chapters," as chapter numbers are used in the narrative.
  Re-wrap at <= 72 columns
  Apply inline emphasis and monospacing, per gdoc / PDF
  Incorporate gdoc changes through 2012-06-08
2012-06-18 14:19:58 -07:00
ce614c0caf Merge "dec/vp8: avoid setting decoder status twice" 2012-06-18 14:12:21 -07:00
900285dac3 dec/vp8: avoid setting decoder status twice
Has the potential of returning confusing USER_ABORT for bitstream errors
in some cases.

Change-Id: I358fdb0b36549179df6dc2a95c09a872bd35aa24
2012-06-18 14:10:01 -07:00
8227adc878 Merge changes I6f02b0d0,I5cbc9c0a,I9dd9d4ed,Id684d2a1
* changes:
  Removed CodeRay syntax declarations ...
  Provide for code-block syntax highlighting.
  Replace high ASCII artifacts (curly quotes, etc.).
  Lossless WebP doc largely ported to markdown text.
2012-06-18 13:55:21 -07:00
dcda59c12d Merge "demux: rename SetTile to SelectTile" 2012-06-18 13:50:45 -07:00
622ef12ea5 demux: rename SetTile to SelectTile
Change-Id: I52b0b30578aeb77b71069f355c6b00901b948634
2012-06-18 13:49:41 -07:00
81ebd37505 Merge "demux: add {Next,Prev}Frame" 2012-06-18 13:41:42 -07:00
02dd37a2a3 demux: add {Next,Prev}Frame
Replaces WebPDemuxSetFrame().

Change-Id: I38cef0ebeabb5c2f164322502abe1780f7a65e06
2012-06-18 13:37:16 -07:00
4b79fa5923 Merge "Limit the maximum size of huffman Image to 16MB." 2012-06-17 00:20:26 -07:00
9aa34b3438 Manually number "chapters," as chapter numbers are used in the narrative.
modified:   doc/webp-lossless-bitstream-spec.txt

Change-Id: Ice662960ff988a6ff577a8ca5a594e14ba69d4de
2012-06-15 14:54:19 -07:00
2a4c6c29a0 Re-wrap at <= 72 columns
modified:   doc/webp-lossless-bitstream-spec.txt

Change-Id: Ie8d7aa907dc20d941b74455f8657d4e1b4e23bbb
2012-06-15 14:54:13 -07:00
a45adc1918 Apply inline emphasis and monospacing, per gdoc / PDF
modified:   doc/webp-lossless-bitstream-spec.txt

Change-Id: I2d996d5e80967641e22997d4f6e7173b39df0978
2012-06-15 14:54:06 -07:00
91011206ad Incorporate gdoc changes through 2012-06-08
modified:   doc/webp-lossless-bitstream-spec.txt

Change-Id: I01c04772bff7e3d7d6f0b526949cd846b5a97c8d
2012-06-15 14:53:55 -07:00
7a18248716 Removed CodeRay syntax declarations ...
... as they became unnecessary when upstream (kramdown)
implemented LQ feature request:
17625c8082

Also updated (and simplified) syntax-highlighting instructions.

modified:   doc/README
modified:   doc/webp-lossless-bitstream-spec.txt
Change-Id: I6f02b0d0a69a4d1d96cb0f771936cbe9e2e6bbec
2012-06-15 14:53:39 -07:00
b3ec18c556 Provide for code-block syntax highlighting.
modified:   doc/README
modified:   doc/webp-lossless-bitstream-spec.txt

Change-Id: I5cbc9c0a4fbbcc049a4d792e1fac367d28acf4a6
2012-06-15 14:53:29 -07:00
709d770241 Replace high ASCII artifacts (curly quotes, etc.).
modified:   doc/webp-lossless-bitstream-spec.txt
Change-Id: I9dd9d4ed05c8f93d4cafadf8c99cc21c300a9299
2012-06-15 14:53:16 -07:00
930e8abbda Lossless WebP doc largely ported to markdown text.
Word-level formatting (italics, bold) remains to be done,
but awaits final author edits, to avoid rework.

modified:   doc/template.html
new file:   doc/webp-lossless-bitstream-spec.txt

Change-Id: Id684d2a10d02e197d660a960540fe83f87d317f2
2012-06-15 14:52:57 -07:00
18cae37b91 msvc: silence some build warnings
these are related to the removal of USE_LOSSLESS_ENCODER

Change-Id: Ib0ca5bc2766c351130507bc2e657a034c8455b34
2012-06-13 13:51:50 -07:00
b3923084b9 Limit the maximum size of huffman Image to 16MB.
This limit corresponds to default histo_bits=3 for images upto sizes 400x400.
Any image higher than this dimension will bump up the histo_bits to 4 internally.

Change-Id: Ic8ba3dcd50e9c588cbbc4a0457289086498ff4ee
2012-06-13 13:27:43 +05:30
f180df2afd Merge "libwebp/demux: add Frame/Chunk iteration" 2012-06-13 00:29:29 -07:00
2bbe1c9aa0 Merge "Enable lossless encoder code" 2012-06-13 00:28:42 -07:00
d0601b0107 Merge changes I1d97a633,I81c59093
* changes:
  libwebp/demux: add WebPDemuxGetI
  libwebp/demux: add extended format parsing
2012-06-13 00:28:25 -07:00
78f3e34504 Enable lossless encoder code
Remove USE_LOSSLESS_ENCODER compile flag
Update Makefile.am and makefile.unix

Change-Id: If7080c4d8f37994c7c784730c5e547bb0a851455
2012-06-13 00:26:58 -07:00
d974a9cc15 Merge "libwebp/demux: add simple format parsing" 2012-06-13 00:03:37 -07:00
26bf223280 Merge "libwebp: add WebPDemux stub functions" 2012-06-12 23:57:18 -07:00
2f66668882 Merge "modify WebPParseHeaders to allow reuse by GetFeatures" 2012-06-12 23:51:55 -07:00
b402b1fbb9 libwebp/demux: add Frame/Chunk iteration
Change-Id: I2da68611b375de48391adcf446df31a93450c7d8
2012-06-12 23:45:11 -07:00
ad9ada3b9f libwebp/demux: add WebPDemuxGetI
Enables queries for format flag, canvas width/height.

Change-Id: I1d97a633712141e42dfc86c95492eb6da5cefa01
2012-06-12 23:45:10 -07:00
2f2d4d5889 libwebp/demux: add extended format parsing
Extends parser to support 'VP8X' and its components

Change-Id: I81c59093b02c7ad27810a7b0473129ea06f99952
2012-06-12 23:45:08 -07:00
962dcef6a8 libwebp/demux: add simple format parsing
Adds image parsing / validation framework for 'VP8 '/'VP8L' files

Change-Id: I8b0a5d1f20d86ab137c881a01dba3275ea191aa4
2012-06-12 23:45:06 -07:00
f8f94081be libwebp: add WebPDemux stub functions
beginning of a separate interface to demux webp files.

Change-Id: If8bf9c43defe5f6c8678afd03541f7cd8261c99a
2012-06-12 23:45:02 -07:00
fb47bb5cf4 Merge "NumNamedElements() should take an enum param." 2012-06-11 00:23:39 -07:00
7c6898051e Fix asserts in Palette and BackwardReference code.
Fix inequality assertion on number of palette colors.
Fix inequality assertion test in BackwardReferencesHashChainFollowChosenPath.

Change-Id: Ie3242f1bbeaf96db91b839b6732ccce2634cebf3
2012-06-11 12:27:59 +05:30
fbdcb7ea38 NumNamedElements() should take an enum param.
- Move TAG_ID to webp/mux.h
- Rename it to WebPChunkId
- Rename IDs to WEBP_CHUNK_<tag>
- Remove "name" param from ChunkInfo struct and related changes.
- Rename WebPMuxNumNamedElements to WebPMuxNumChunks().
- WebPMuxNumChunks() takes WebPChunkId as param.

Change-Id: Ic6546e4a9ab823b556cdbc600faa137076546a2b
2012-06-11 12:26:13 +05:30
fb4943bdf9 modify WebPParseHeaders to allow reuse by GetFeatures
moves the implementation to ParseHeadersInternal. this also allows
decoding to start at a VP8X sub-chunk, e.g. 'ALPH'.

Change-Id: I06791f87d90f888de32746ecb02705e4b0ff227a
2012-06-08 14:55:14 -07:00
3697b5ceb2 write an ad-hoc EncodeImageInternal variant
Used when we don't code a Huffman Image.
-> Simplify the code quite some because we don't have to
deal with special cases of histo bits

Change-Id: I0c3f46cbf3b501e021c093e07253e7404c01ff4f
2012-06-08 11:52:31 -07:00
eaee9e79f7 Bug-Fix: Decode small (less than 32 bytes) images.
ParseVP8X was checking for presence of extra 20 bytes (after RIFF header).
This check should not be executed for non-mux (non-VP8X) images.

Change-Id: I3fc89fa098ac0a53102e7bbf6c291269817c8e47
2012-06-08 14:30:56 +05:30
0bceae488e Merge "cwebp: fix alpha reporting in stats output" 2012-06-07 21:27:02 -07:00
0424b1ef3b Rebase default encoding settings.
Updated histo_bits to 3 from 4 and changed the quality threshold for inner loop for HashChainFindCopy.
Impact: 0.5%-0.8% better bpp with 15%-20% hit on encoding throughput
at default encoding settings.

Change-Id: I316ef88403148b1e19036fa0817d944eb0301255
2012-06-08 09:18:15 +05:30
c71ff9e359 cwebp: fix alpha reporting in stats output
Since
 437999f introduce a generic WebPPictureHasTransparency() function
lossy encodes will not encode alpha if the alpha channel is completely
opaque.

Change-Id: I1826669c3932483650d7f8ce806cfebd4e5225fc
2012-06-07 17:32:29 -07:00
e2ffe446bd Merge "Stop indefinite recursion for Huffman Image." 2012-06-07 10:52:26 -07:00
70eb2bd687 Stop indefinite recursion for Huffman Image.
Ensure that the lossless bit-stream doesn't allow for such cases and
safe-gaurd decoder against indefinite recursion.

Change-Id: Ia6d7f519291de8739f79a977a5800982872aae71
2012-06-07 17:27:19 +05:30
f3bab8eb27 Update vwebp
... with updated mux API calls.

Change-Id: I0f8a36eeffaeb041964ec4f582e369d48bba4978
2012-06-07 17:20:26 +05:30
6d5c797cee Remove support for partial files in Mux.
Change-Id: Ie084f308c79a3cfaf2ea13e800397debc2643470
2012-06-07 13:46:42 +05:30
f1df5587d9 WebPMuxAssemble() returns WebPData*.
Also add an API 'WebPDataFree()'

Change-Id: I00dc4c67fd78a541a18aaf0e65b8ef62d9769803
2012-06-07 11:05:57 +05:30
814a063925 Rename 'Add' APIs to 'Set'.
Change-Id: I10a836a5bc3c9207b6f7fa423bb64bc9bcac055b
2012-06-05 20:37:51 +05:30
bbb0218fa5 Update Mux psuedo-code examples.
Change-Id: I9df4d509286c9b892272181646403c0c7893db70
2012-06-05 20:29:42 +05:30
4fc4a47f6e Use WebPData in MUX set APIs
Change-Id: Ibdede3c1cd02c6aeef333718592da313f10f6408
2012-06-05 14:21:46 +05:30
c67bc979dd Merge "add WebPPictureImportRGBX() and WebPPictureImportBGRX()" 2012-06-05 00:28:04 -07:00
27519bc2b6 add WebPPictureImportRGBX() and WebPPictureImportBGRX()
When importing BGRA or RGBA data for encoding, provide variants of
the WEBPImportPicture API for RGBX and BRGX data meaning the alpha
channel should be ignored.

Author: noel@chromium.org
from Chromium patch: https://chromiumcodereview.appspot.com/10496016/

Change-Id: I15fcaa4160c69a2b5549394204b6e6d7a1c5d333
2012-06-05 00:26:17 -07:00
f80cd27e28 factorize code in Import()
Change-Id: I6a4e77715c3a5be5238c81e029bfb6479d36de05
2012-06-04 23:27:01 -07:00
9b71502669 histogram: add log2 wrapper
Change-Id: I5e68efaf5f763a42ace1af83f4b7887e0ddfd099
2012-06-04 23:14:41 -07:00
8c34378ff3 Merge "fix some implicit type conversion warnings" 2012-06-04 22:46:33 -07:00
42f6df9da3 fix some implicit type conversion warnings
Change-Id: I0653d10410c0d46f91fedad4c4dffa9c1de402cb
2012-06-04 22:33:32 -07:00
250c16e3d5 Merge "doc: update lossless pdf" 2012-06-04 22:30:41 -07:00
9d9daba43d Merge "add a PDF of the lossless spec" 2012-06-04 22:30:19 -07:00
8fbb91884e prefer webp/types.h over stdint.h
stdint.h is part of C99 and is notably lacking under MSVC

Change-Id: Iff60dcb8bdcc7f948dc35fb0b5d47478520b570f
2012-06-04 18:34:24 -07:00
0ca170c2dd doc: update lossless pdf
Change-Id: I8c6d0e6fc21196f6dd239b21eda2097ba4ce2bba
2012-06-04 16:53:16 -07:00
0862ac6e7e add a PDF of the lossless spec
(cherry picked from commit db9967748781d73832b3875db1dfcbefb180f7c9)

Change-Id: I5909abc48d9b4c4415f81a019681968f06d6a3d7
2012-06-04 16:51:39 -07:00
437999fb77 introduce a generic WebPPictureHasTransparency() function
VP8-lossy will now avoid writing an ALPH chunk if the
alpha values are trivial.

+ changed DumpPicture() accordingly in cwebp
+ prevented the -d option to be active with lossless
 (DumpPicture wouldn't work).

Change-Id: I34fdb108a2b6207e93fa6cd00b1d2509a8e1dc4b
2012-06-04 16:17:55 -07:00
d2b6c6c03b cosmetic fixes after Idaba281a
Change-Id: I275a3dee5696fe1a3e2db0976f8241f2044be512
2012-06-04 13:19:28 -07:00
b4e6645c61 Merge "add colorspace for premultiplied alpha" 2012-06-04 07:56:37 -07:00
48f827574e add colorspace for premultiplied alpha
The new modes are
       MODE_rgbA
       MODE_bgrA
       MODE_Argb
       MODE_rgbA_4444
It's binary incompatible, since the enums changed.

While at it, i removed the now unneeded KeepAlpha methods.
-> Saved ~12k of code!

* made explicit mention that alpha_plane is persistent,
so we have access to the full alpha plane data at all time.
Incremental decoding of alpha was planned for, but not
implemented. So better not dragged this constaint for now
and make the code easier until we revisit that.

Change-Id: Idaba281a6ca819965ca062d1c23329f36d90c7ff
2012-06-04 07:50:41 -07:00
069f903a08 Change in lossless bit-stream.
Change the lossless signature to 0x2f
Add 1 bit indicator for 'droppable (or trivial) alpha)'.
Add 3 bit lossless version (for future extension like yuv support).
Change the sub-resolution information to 3 bits implying range [2 .. 9]

Change-Id: Ic7b8c069240bbcd326cf5d5d4cd2dde8667851e2
2012-06-04 12:47:01 +05:30
5f7bb3f53a Merge "WebPReportProgress: use non-encoder specific params" 2012-05-31 13:02:30 -07:00
f18281ffa0 WebPReportProgress: use non-encoder specific params
Take picture and percent value storage location instead of VP8Encoder.
This will allow reuse by the lossless encoder.

Change-Id: Ic49dbc800cc3e2df60d20f4ebac277f68ed6031b
2012-05-31 11:28:48 -07:00
9ef3228301 Add support for raw lossless bitstream in decoder.
Previously, it used to assume any raw bitstream is a VP8 one.

Also,
- Factor out VP8CheckSignature() & VP8LCheckSignature().
- Use a local var for *data_ptr in ParseVP8Header() for
readability.

Change-Id: I0fa8aa177dad7865e00c8898f7e7ce76a9db19d5
2012-05-31 14:03:17 +05:30
7cbee29afa Fix bug: InitIo reseting fancy_upsampling flag.
frame's InitIo should not reset fancy_upsampling flag.
This flag (fancy_upsampling) is set via CustomSetup -> WebPIoInitFromOptions
and frame's InitIo() is resetting it to 0.

Change-Id: I64b54cdfba43799c0a5aa8e384575af5d6331674
2012-05-30 14:46:22 +05:30
880fd98ca1 vwebp: fix exit w/freeglut
GLUT_ACTION_CONTINUE_EXECUTION is required to allow glutMainLoop to
return.

Change-Id: I8eb7e657a52d6923858959b7b03447a7ddb53ca0
2012-05-25 15:06:21 -07:00
1875d926e7 trap two unchecked error conditions
CostModelBuild() and TrackBackwards() returns weren't checked

+ code clean-up
+ de-inline VP8LBackwardRefs non-critical methods
+ shuffle the .h around to group things together
+ extract some constants as #define's
+ fixed the "if (!(cc_init = ...)) {...}" constructs
+ removed some unneeded VP8L prefixes

Change-Id: Ic634cb87bc6b2033242d3e8e8731fab4c134f327
2012-05-25 02:52:44 -07:00
87b4a908a5 no need to have mux.h as noinst clause in enc/
Change-Id: I93c65838f33d01170fc63340650edeeee753786f
2012-05-24 15:05:19 -07:00
88f41ec6ec doc: fix bit alignment in VP8X chunk
Change-Id: I7eaa7be48213642e3eceaaac95ad00952e085330
2012-05-24 12:33:48 -07:00
52f5a4eff0 Merge "fix bug with lossy-alpha output stride" 2012-05-24 08:56:44 -07:00
3bde22d768 fix bug with lossy-alpha output stride
dec->width_ != final_width in case of Bundle transform!

thanks to Pepijn for spotting the problem

Change-Id: I08b451a32097dcbf23b73deabc8cc6a2d59f0119
2012-05-24 08:54:02 -07:00
42d61b6def update the spec for the lossy-alpha compression methods.
No further experiments are to be expected, so this is quite the
final format so far, pending supplemental feedbacks.

Change-Id: I2a3de025c90b7bb5fdd8792b2b2ccdc2e3753f56
2012-05-24 07:22:52 -07:00
e75dc80516 Move some more defines to format_constants.h
Also remove some duplicate const/defines.

Change-Id: I0ec48866b874f546022d72e938fb65669b0b3211
2012-05-24 17:46:01 +05:30
c13f663261 Move consts to internal header format_constants.h
Change-Id: Ic6180c16d0b4245680738992925e4608c593fbe8
2012-05-24 15:02:02 +05:30
7f2dfc92dc use a bit-set transforms_seen_ instead of looping
may be useful later for instance to bypass some code
if we know we don't use the Bundle+ColorMap transform.

Change-Id: I9dc70d18165b2363ad9ede763684ef3d8eba5903
2012-05-24 02:04:23 -07:00
18da1f53fc modulate alpha-compression effort according to config.method
we vary linearly lossless-method between 0 and 6,
and lossless-quality between 50 and 100, so that encoding
speed can go from 'quite fast' to 'rather slow'.
Impact on size is moderate, but visible.

Change-Id: I0b7917e7170eb50258afb1a4e248028cd9e9207d
2012-05-24 01:54:12 -07:00
f5f2fff657 Merge "Alpha flag fix for lossless." 2012-05-24 01:11:07 -07:00
c975c44ea5 Alpha flag fix for lossless.
- Make sure alpha flag is set in case of a lossless file with VP8X chunk.
  The semantic of ALPHA_FLAG changes with this: it means the images
  contain alpha (rather than ALPH chunk in particular).
- Update the mux container spec to add 1-line description of alpha
  flag.
- Rename "HasLosslessImages()" to "MuxHasLosslessImages()", and other
  similar function renames.
- Rename FeatureFlags to WebPFeatureFlags
- Elaborated a comment for a special case.
- A misc comment fix.

Change-Id: If212ccf4338c125b4c71c10bf281a51b3ba7ff45
2012-05-24 11:35:12 +05:30
4f067fb254 Merge "Android: only build dec_neon with NEON support" 2012-05-23 22:26:03 -07:00
255c66b48f Android: only build dec_neon with NEON support
Defining LOCAL_ARM_NEON = true can result in neon instructions being
used in portions unprotected by the cpu check.
This changes defines a WEBP_USE_NEON/WEBP_ANDROID_NEON pair similar to
the SSE2 code and MSVC.

Change-Id: Ifac010b06e42c73d5aca529baa2198c6796674bd
2012-05-23 22:21:10 -07:00
8f9117a9f0 cosmetics: signature fixes
Change-Id: Id0e1026d43c0a6928dd740c88117df638bfb6db6
2012-05-23 12:45:05 -07:00
39bf5d6497 use header-less lossless bitstream for alpha channel
This saves ~26 bytes of headers.
* introduce new VP8LDecodeAlphaImageStream() for decoding
* use VP8LEncodeStream() for encoding
* refactor code a bit

still TODO: make the alpha-quality/enc-method user-configurable

Change-Id: I23e599bebe335cfb5868e746e076c3358ef12e71
2012-05-23 08:01:44 -07:00
75d7f3b222 Merge "make input data be 'const' for VP8LInverseTransform()" 2012-05-23 07:54:12 -07:00
9a721c6d24 make input data be 'const' for VP8LInverseTransform()
Change-Id: I5b5b1e29bca6c42704df141b21632a0d0fcb07cf
2012-05-23 07:21:53 -07:00
9fc64edc21 Disallow re-use of same transformation.
Limit the overall number of transformations to 4 and disallow any
duplicate transform for decoding an image.

Change-Id: Ic4b0ecd553db96702e117fd073617237d95e45c0
2012-05-23 17:04:57 +05:30
98ec717f1e use a function pointer for ProcessRows()
this allows later customization of data output method.
No perf diff observed, even if ProcessRows is no longer inlined.

Change-Id: I6933a3612a9cf6c108cf2776dfde0ae80c6c07c0
2012-05-23 02:00:14 -07:00
f7ae5e370a cosmetics: join line
Change-Id: Ib27ed202fff439b94431360c8b0654d88962fb9a
2012-05-23 01:56:29 -07:00
140b89a323 factor out buffer alloc in AllocateARGBBuffers()
+ small opportunistic fixes:
  * allow NULL decoded_data to be passed to DecodeStream
    and clarity (with assert()) when to do so
  * AllocateAndInitRescaler() was already setting error status,
    as it should. No need to do it at caller's site

Change-Id: I30867e596564a7f459a0d1ddbf6f5d312414b7fd
2012-05-23 01:53:57 -07:00
a107dfa806 Rectify WebPParseOptionalChunks().
Now it stops at either VP8/VP8L chunk.

Change-Id: Iadac4fa47396b61b9b720b8b7b19138c89df24cc
2012-05-23 13:59:52 +05:30
237eab6764 Add two more color-spaces for lossless decoding.
Added color-spaces (RGBA_4444 and RGB_565), required for Android device
to lossless decoding.

Change-Id: I229832edd4deca59e066f463e7454f77457c5bcd
2012-05-23 12:10:13 +05:30
27f417ab66 fix orthographic typo
Change-Id: I4f62e9c125ef3bc1ab75871e6725551f1c89f5e8
2012-05-22 13:20:57 -07:00
489ec335a1 add VP8LEncodeStream() to compress lossless image stream
* RIFF header is omitted
* rename NewVP8LEncoder and DeleteVP8Encoder
* change the signature to take a "const WebPPicture*"
  (it was non-const just because we were setting some error potentially)
* made the pic_ field const in VP8LEncoder too.
* trap the bitwriter::error_ too
* simplify some signatures to take WebPPicture* instead
  of unneeded VP8LEncoder*

VP8LEncodeStream() will be called directly to compress alpha channel
header-less.

Change-Id: Ibceef63d2b3fbc412f0dffc38dc05c2dee6b6bbf
2012-05-22 03:15:58 -07:00
fa8bc3dbca make WebPEncodingSetError() take a const picture
This is a border-case situation: the picture is not const, because
we're change its error status. But taking it non-const forces
the caller to carry a non-const picture all around the code just
in case (0.00001% of the time?) something bad happen.
This pretty much the same as making all objects non-const because
we'll eventually call delete or free() on them, which is quite a
non-const operation. Well... Better allow constness enforcement for
the remaining 99.9999% of the code.

Change-Id: I9b93892a189a50feaec1a3a518ebf488eb6ff22f
2012-05-22 02:51:38 -07:00
638528cd1e bitstream update for lossy alpha compression
now, we only use 2 bits for the filtering method, and 2 bits
for the compression method.
There's two additional bits which are INFORMATIVE, to specify
whether the source has been pre-processed (level reduction)
during compression. This can be used at decompression time
for some post-processing (see DequantizeLevels()).

New relevant spec excerpt:

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                      ChunkHeader('ALPH')                      |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |Rsv| P | F | C |     Alpha Bitstream...                        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Compression method (C): 2 bits

: The compression method used:

  * `0`: No compression.
  * `1`: Backward reference counts encoded with arithmetic encoder.

Filtering method (F): 2 bits

: The filtering method used:

  * `0`: None.
  * `1`: Horizontal filter.
  * `2`: Vertical filter.
  * `3`: Gradient filter.

Pre-processing (P): 2 bits

: These INFORMATIVE bits are used to signal the pre-processing that has
been performed during compression. The decoder can use this information to
e.g. dither the values or smooth the gradients prior to display.

  * `0`: no pre-processing
  * `1`: level reduction

Decoders are not required to use this information in any specified way.

Reserved (Rsv): 2 bits

: SHOULD be `0`.

Alpha bitstream: _Chunk Size_ - `1` bytes

: Encoded alpha bitstream.

This optional chunk contains encoded alpha data for a single tile.
Either **ALL or NONE** of the tiles must contain this chunk.

The alpha channel data is losslessly stored as raw data (when
compression method is '0') or compressed using the lossless format
(when the compression method is '1').

Change-Id: Ied8f5fb922707a953e6a2b601c69c73e552dda6b
2012-05-22 02:36:22 -07:00
d73e63a726 add DequantizeLevels() placeholder
will be called by alpha post-processing, although doing nothing for now.
Gradient smoothing would be nice-to-have here. Patch welcome!

Change-Id: I534cde866bdc75da22d0f0a6d1373c90e21366f3
2012-05-22 02:28:19 -07:00
ec122e0986 remove arch-dependent rand()
let's use our own simple pseudo-random number generator

Change-Id: I7b4a190cdf4d338b1fae5ef3622ebd82c6e19274
2012-05-22 00:17:04 -07:00
d40e7653db fix alignment
Change-Id: Ieb36de1bcf8c624024f8a3d5a238a2b508d4bb51
2012-05-21 14:31:16 -07:00
1dd6a8b65e Merge "remove tcoder, switch alpha-plane compression to lossless" 2012-05-21 06:38:45 -07:00
3e863dda61 remove tcoder, switch alpha-plane compression to lossless
* Method #1 is now calling the lossless encoder on the alpha plane.
Format is not final, it's just a first draft. We need ad-hoc functions.
* removed now useless utils/alpha.*
* added utils/quant_levels.h instead
* removed the TCoder code altogether

Change-Id: I636840b6129a43171b74860e0a0fc5bb1bcffc6a
2012-05-21 06:24:48 -07:00
8d77dc29e1 Add support for lossless in mux:
- Separate out 'CHUNK_INDEX' from 'TAG_ID' (this is to help with the
  situation where two different tags - "VP8 " and "VP8L" can have the
  same TAG_ID -> IMAGE_ID).
- Some internal methods now take 'CHUNK_INDEX' param instea of 'TAG_ID'
  as appropriate.
- Add kChunks[] entry for lossless.
- Rename WebPMuxImage.vp8_ --> WebPMuxImage.img_
- SetImage() and AddFrame/Tile() infer whether the bitstream is a
  lossless one based on LOSSLESS_MAGIC_BYTE. The correct tag is stored
  based on this.

Also, handle the case when GetVP8Info/GetVP8LInfo() fails.

Change-Id: I6b3bc9555cedb791b43f743b5a7770958864bb05
2012-05-21 13:54:18 +05:30
831bd13168 Make tile size a function of encoding method.
Higher method implies more encoding effort (CPU) achieved with
smaller tile sizes (lower histo_bits).

Change-Id: Ic39c8d882c87835f74fde41172afb002ac3fd1c3
2012-05-18 12:16:39 +05:30
778c52284b Merge "remove some variable shadowing" 2012-05-17 14:03:10 -07:00
817c9dce61 Few more HuffmanTreeToken conversions.
Change-Id: I932b5368d279f83c462c7d916978dab3e81d7709
2012-05-16 12:15:52 +05:30
37a77a6bf4 remove some variable shadowing
Change-Id: I4348253ec6b50639095b22c4745dc26da0904466
2012-05-15 14:04:24 -07:00
89c07c9660 Merge "normalize example header includes" 2012-05-15 13:50:27 -07:00
4aff411fe0 Merge "add example_util.[hc]" 2012-05-15 13:49:21 -07:00
00b29e282f normalize example header includes
headers from examples/ aren't installed so prefix with './' to be
explicit.

Change-Id: Ie6c1544a026a9859b7fc0cf238b21e031ef0013f
2012-05-15 13:48:11 -07:00
061263a787 add example_util.[hc]
moves ReadFile to a common location

Change-Id: Ia81230671f16d7d4d218b9954a5be55577a85413
2012-05-15 13:42:57 -07:00
c6882c49e3 merge all tree processing into a single VP8LProcessTree()
-> 0.1% size improvement because we're calling OptimizeForRLE()
systematically now.

Change-Id: I03bd712175728e0d46323f375134cae5a241db4b
2012-05-14 05:49:02 -07:00
9c7a3cf5e7 fix VP8LHistogramNumCodes to handle the case palette_code_bits == 0
-> lot of simplifications ensue and we should be able to get rid of
 ClearHuffmanTreeIfOnlyOneSymbol() too, in a subsequent patch.

Change-Id: Ic4c51d05e4b1970e37f94ffd85fae6a02e4a6422
2012-05-14 01:23:58 -07:00
b5551d2e1d Merge "Added HuffmanTreeCode Struct for tree codes." 2012-05-14 01:23:08 -07:00
8b85d01c45 Added HuffmanTreeCode Struct for tree codes.
To represent tree codes (depth and bits array).

Change-Id: I87650886384dd10d95b16ab808dfd3bb573172bc
2012-05-14 13:50:35 +05:30
093f76d831 Merge "Allocate single memory in GetHuffBitLengthsAndCodes." 2012-05-14 01:15:46 -07:00
41d8049451 Allocate single memory in GetHuffBitLengthsAndCodes.
Allocate big chunk of memory in GetHuffBitLengthsAndCodes, instead of allocating in a loop.
Also fixed the potential memleak.

Change-Id: Idc23ffa306f76100217304444191a8d2fef9c44a
2012-05-14 13:41:59 +05:30
1b04f6d234 Correct size in VP8L header.
The size written in VP8L header should be without padding.
(Also clarified this code using consts).

Change-Id: Ic6583d760c0f52ef61924ab0330c65c668a12fdc
2012-05-14 12:49:16 +05:30
2924a5aee6 Makefile.vc: split object lists based on directory
Change-Id: I4e189193817f26117e6459da078e2a72c9f3ef5f
2012-05-11 18:29:33 -07:00
c8f24165b7 Merge "add assert(tokens)" 2012-05-11 01:46:45 -07:00
432399472f add assert(tokens)
Change-Id: I952a5cd15ff0a80cff349293e6403357cbc7bd8d
2012-05-11 01:45:06 -07:00
9f547450e0 Catch an error in DecodeImageData().
When we are at end-of-stream, but haven't decoded all pixels, we should
return an error.
Also remove an obsolete TODO.

Change-Id: I3fb1646136e706da536d537a54d1fa487a890630
2012-05-11 14:10:01 +05:30
ac8e5e42d1 minor typo and style fix
Change-Id: If4927beb7a8f3c96379eee1fedc687a5046a6951
2012-05-11 01:17:31 -07:00
9f566d1d36 clean-up around Huffman-encode
* refine doc
* use LUT for bit-reversal
* added assert
* Introduce HuffmanTreeToken instead of separate code/extra_bits arrays

Change-Id: I0fe0b50b55eb43a4be9f730b1abe40632a6fa7f0
2012-05-10 09:11:47 -07:00
c579a71012 Introduce CHUNK_SIZE_BYTES in muxi.h.
Plus a style fix.

Change-Id: Id94df6c91a96598cb022c813e0981f542aebe982
2012-05-10 13:16:18 +05:30
14757f8ae2 Make sure huffman trees always have valid symbols
- Symbols added to the tree are valid inside HuffmanTreeBuildExplicit().
- In HuffmanTreeBuildImplicit(), make sure 'root_symbol' is
valid in case of a single symbol tree.

Change-Id: I7de5de71ff28f41e2d6228b29ed8dd4a20813e99
2012-05-10 11:40:18 +05:30
4105061840 makefile.unix: add support for building vwebp
standalone from the normal examples due to the additional OpenGL
dependencies.
$ make -f makefile.unix examples/vwebp

Change-Id: I7e3f0b5e0328230cb32acdd1e2a011cbbb80e55d
2012-05-09 15:47:00 -07:00
48b37721fc Merge "fixed signed/unsigned comparison warning" 2012-05-09 14:10:32 -07:00
57f696daef Merge "EncodeImageInternal: fix potential leak" 2012-05-09 13:58:55 -07:00
d972cdf2dd EncodeImageInternal: fix potential leak
if histogram_image_size is reduced in when writing the histogram_image
the bit arrays would leak any remaining elements. store their element
count separately.

Change-Id: I710142a11ebd4325faec7bd65c2d2572aae19307
2012-05-09 13:49:10 -07:00
5cd12c3df2 fixed signed/unsigned comparison warning
present in an assert in backward_references.h

Change-Id: Id9a528896689e51d784ad64fdc1ca052e97fe7a2
2012-05-09 13:45:26 -07:00
cdca30d0b5 Merge "cosmetics: shorten long line" 2012-05-09 13:45:12 -07:00
e025fb5546 cosmetics: shorten long line
Change-Id: I78bb19cf593730e74734e08d3d6de08a29bd9cbc
2012-05-09 13:42:31 -07:00
22671ed6a3 Merge "enc/vp8l: fix double free on error" 2012-05-09 13:36:38 -07:00
e1b9b05258 Merge "cosmetics: VP8LCreateHuffmanTree: fix indent" 2012-05-09 13:23:24 -07:00
a8e725f800 enc/vp8l: fix double free on error
GetHuffBitLengthsAndCodes and the caller would both free
bit_lengths/bit_codes

Change-Id: I1b62ff727c82567f11c39a847f74fe765b5f527c
2012-05-09 12:56:07 -07:00
27541fbdc0 cosmetics: VP8LCreateHuffmanTree: fix indent
Change-Id: I025fada400366f8937208e1f9b8df483cd53a942
2012-05-09 12:11:22 -07:00
1d38b258b8 cwebp/windows: use MAKE_REFGUID where appropriate
Change-Id: If595c75a833d37df86c16bf926da5f032015c68e
2012-05-09 11:52:01 -07:00
817ef6e9af Merge "cwebp: fix WIC/Microsoft SDK compatibility issue" 2012-05-09 11:50:05 -07:00
902d3e3b5f cwebp: fix WIC/Microsoft SDK compatibility issue
Fixes issue #115.
Define local copies of GUID_WICPixelFormat24bppRGB &
GUID_WICPixelFormat32bppRGBA (and GUID_WICPixelFormat32bppBGRA for
symmetry) to avoid link issues when building against older versions of
the SDK.

Change-Id: I2a26be1b7fe6d970feb3211cf0059e5898e3028d
2012-05-09 11:47:15 -07:00
89d803c423 Merge "Fix a crash due to wrong pointer-integer arithmetic." 2012-05-09 02:22:01 -07:00
cb1bd741f9 Merge "Fix a crash in lossless decoder." 2012-05-09 02:21:13 -07:00
de2fe20290 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." 2012-05-09 02:15:42 -07:00
ce69177a41 Fix a crash due to wrong pointer-integer arithmetic.
[Basically, the condition "src - dist < data" can be wrongly evaluated
to be false if "src < dist" due to underflow. Instead, "src - data <
dist" is the correct condition, as "src > data" is always true and so
there would never be an underflow].

Change-Id: Ic9f64bfe76a9acae97abc1fb7c1f4868e81f1eb8
2012-05-09 14:40:06 +05:30
e40a3684f5 Fix a crash in lossless decoder.
This was due to incorrect update of 'ok'.

Change-Id: I91edfb5682527e8bc7eaa10e635c0261edb016b6
2012-05-09 14:35:11 +05:30
3927ff3abc remove unneeded error condition for WebPMuxNumNamedElements()
+ fix error message

Change-Id: If283ff6609ee0c5dff81a9c1c3f194faa729161c
2012-05-09 01:57:15 -07:00
2c140e113c 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.

Change-Id: I5cb3cc942afac6e9f51a0b97c57ee897677a48a2
2012-05-09 14:26:01 +05:30
861a5b7bc9 add support for animation
it's using glutTimerFunc() for trigger next frame's decoding

Reminder: how to build and use manually (integration in makefile.unix coming soon)

Unix:
cd libwebp
make -f makefile.unix
cd examples
cc -o vwebp vwebp.c -framework GLUT -framework OpenGL -I../src/ ../src/libwebp.a ../src/mux/libwebpmux.a

Mac + xcode:
cd libwebp
make -f makefile.unix
cd examples
cc -o vwebp vwebp.c -lglut -lGL -lpthread -lm -I../src/ ../src/libwebp.a ../src/mux/libwebpmux.a

Change-Id: Id49e87c26628c2b58ec221f6030cbd2e46a807b4
2012-05-09 01:23:39 -07:00
eb5c16cc18 Merge "Set correct encode size in encoder's stats." 2012-05-09 00:37:25 -07:00
4abe04a204 fix the return value and handle missing input file case.
Change-Id: I42a64fcf7587ff3a487115808e2cfa51cec0031d
2012-05-09 00:34:30 -07:00
2fafb85579 Set correct encode size in encoder's stats.
The current implementation doesn't take care one byte
signature and associated one byte padding (for odd sized chunk).

Change-Id: I35b81d0644818cdba38189aa48c75db5f92e68f4
2012-05-09 12:33:58 +05:30
e7167a2b95 Provide one entry point for backward references.
The new method VP8LGetBackwardReferences hides internal
heuristics used for choosing RLE or LZ77 based refs.
- Tuned VP8LHashChainFindCopy for better compression at higher Q.
- Refactored code.
- Removed the unused method VP8LVerifyBackwardReferences.

Change-Id: Ibb7bb072bab5a49a001577a20d88226f52e6c663
2012-05-09 12:13:06 +05:30
c4ccab6463 Print relevant lossless encoding stats in cwebp.
Change-Id: Ib8dfab498b1a05e49734bba2d3e72810343e8b0a
2012-05-09 11:31:41 +05:30
e3302cfd73 GetHuffBitLengthsAndCodes: reduce level of indirection
arrays can be passed directly as only their members are being modified.
this also reduces the allocation for bit_codes[] by taking the
sizeof(type)=2 rather than sizeof(ptr)=4/8 in one case.

Change-Id: Idad20cead58c218b58d90b71699374fefd01cad9
2012-05-08 11:48:55 -07:00
b5f2a9ed49 enc/vp8l: fix uninitialized variable warning
histogram_image_size could be unset if the code branches to the 'Error'
label.

Change-Id: I690b20f86372f19a47d159c2bec8fbf49553f0d5
2012-05-08 11:45:04 -07:00
7885f8b25d makefile.unix: add lossless encoder files
comment out 'EXTRA_FLAGS += -DUSE_LOSSLESS_ENCODER' to disable

Change-Id: I75ead699c95644e319e7cbbf2a167d98e826fb7c
2012-05-08 11:25:28 -07:00
1261a4c888 Merge "cosmetics" 2012-05-07 17:54:43 -07:00
3926b5be3b Merge "dsp/cpu.c: Android: fix crash on non-neon arm builds" 2012-05-07 17:53:03 -07:00
834f937f3c dsp/cpu.c: Android: fix crash on non-neon arm builds
add proper cpu-detection for Android targets

Fixes issue #118 (and is a better solution for #117).

based on patch by pepijn vaneeckhoudt

Change-Id: I6b00ea6d51ca658ccf6a3d55b87b99c01c6805be
2012-05-07 17:52:15 -07:00
126e160672 cosmetics
vp8.[hc]:fix '*' placement in pointer types
vp8l.c: remove trailing ',' from enum
decode.h: fix stray WebPINew()

Change-Id: Id6749a14a12ed0a090649f28ef4267fda45a37a8
2012-05-07 17:47:51 -07:00
e38602d2ad Merge branch 'lossless_encoder'
* lossless_encoder: (46 commits)
  split StoreHuffmanCode() into smaller functions
  more consolidation: introduce VP8LHistogramSet
  big code clean-up and refactoring and optimization
  Some cosmetics in histogram.c
  Approximate FastLog between value range [256, 8192]
  Forgot to update out_bit_costs to symbol_bit_costs at one instance.
  Evaluate output cluster's bit_costs once in HistogramRefine.
  Simple Huffman code changes.
  Lossless decoder: remove an unneeded param in ReadHuffmanCodeLengths().
  Reducing emerging palette size from 11 to 9 bits.
  Move GetHistImageSymbols to histogram.c
  Improve predict vs no-predict heuristic.
  code-moving and clean-up
  reduce memory usage by allocating only one histo
  Restrict histo_bits to ensure histo_image size is under 32MB
  further simplification for the meta-Huffman coding
  A quick pass of cleanup in backward reference code
  Make transform bits a function of encode method (-m).
  introduce -lossless option, protected by USE_LOSSLESS_ENCODER
  Run TraceBackwards for higher qualities.
  ...

Conflicts:
	src/enc/webpenc.c

Change-Id: I9a5d98cba0889ea91d10699466939cc283da345a
2012-05-07 14:27:17 -07:00
e8d3d6a018 split StoreHuffmanCode() into smaller functions
Change-Id: Iaa715f4997505eebabee1e92e964a5d7ee6f3e7d
2012-05-07 14:25:32 -07:00
d0d88990d8 more consolidation: introduce VP8LHistogramSet
VP8LHistogramSet is container for pointers to histograms that
we can shuffle around. Allocation is one big chunk of memory.
Downside is that we don't de-allocate memory on-the-go during
HistogramRefine().

+ renamed HistogramRefine() into HistogramRemap(), so we don't
confuse with "HistogramCombine"
+ made VP8LHistogramClear() static.

Change-Id: Idf1a748a871c3b942cca5c8050072ccd82c7511d
2012-05-07 14:25:30 -07:00
1a210ef1a9 big code clean-up and refactoring and optimization
* de-inline some function
* make VP8LBackwardRefs be more like a vectorwith max capacity
* add bit_cost_ field to VP8LHistogram
* general code simplifications
* remove some memmov() from HistogramRefine
* simplify HistogramDistance()
...

Change-Id: I16904d9fa2380e1cf4a3fdddf56ed1fcadfa25dc
2012-05-07 14:25:29 -07:00
41b5c8ff71 Some cosmetics in histogram.c
Change-Id: I5d5872a793759fad593dba88c3f593f72b328b0c
2012-05-07 14:25:28 -07:00
ada6ff77df Approximate FastLog between value range [256, 8192]
Profiled data: Profiled few images and found that in the function VP8LFastLog,
90% of time table lookup is performed, while rest of time (10%) call to log
function is made. Typical lookup accounts for 10 CPU instructions and call to
log 200 instruction counts. The weighted average comes out to be 30
instructions per call. For mid qualities (25-75), this function (VP8LFastLog)
accounts for 30-50% of total CPU cycles (via call path: VP8LCOlorSpaceTransform
-> PredictionCostCrossColor -> ShannonEntropy). After this change, the log is
called less that 1% of time, with average instructions being 15 per call.
Measured the performance over 1000 files for various qualities and found
overall compression speedup between 10-15% (in quality range [0, 75]). The
compression density loss is around 0.5% (though at some qualities, compression
is little better as well).

Change-Id: I247bc6a8d4351819c871f19d65455dc23aea8650
2012-05-07 14:25:26 -07:00
ec123ca3f6 Forgot to update out_bit_costs to symbol_bit_costs at one instance.
Change-Id: Iaf952c0cb6e3fe35257d2503a16a437c6f2eb3aa
2012-05-07 14:25:25 -07:00
cf33ccd160 Evaluate output cluster's bit_costs once in HistogramRefine.
Avoid bit_costs evaluated every time in function HistogramDistance. Also moved
VP8LInitBackwardRefs and VP8LClearBackwardRefs to backward_references.h

Change-Id: Id507f164d0fc64480aebc4a3ea3e6950ed377a60
2012-05-07 14:25:23 -07:00
781c01f421 Simple Huffman code changes.
No empty trees are codified with the simple Huffman code. The simple Huffman
code is simplified to be either a 1-bit code or 8-bit code for symbols.

Change-Id: I3e2813027b5a643862729339303d80197c497aff
2012-05-07 14:25:21 -07:00
a2849bc502 Lossless decoder: remove an unneeded param in ReadHuffmanCodeLengths().
Change-Id: I279452fdf38b680737d5ba6e868a219281bc8962
2012-05-07 14:25:20 -07:00
b39e7487a7 Reducing emerging palette size from 11 to 9 bits.
This is required to reduce memory used to construct histo_image.

Change-Id: I491a06e10a3e3f3d8a00ecec286394378283ffea
2012-05-07 14:25:19 -07:00
bfc73db4a8 Move GetHistImageSymbols to histogram.c
Planning to revisit memory allocation scheme at several instanaces (next CL).

Change-Id: Id7b9f4854e9577e10b53d5b1d8595b7d862e6e01
2012-05-07 14:25:18 -07:00
889a578681 Improve predict vs no-predict heuristic.
This improves compression density. For example, at quality 95 on 1000 PNGs:
bpp(before) = 2.447 and bpp(after) = 2.412

Change-Id: I19c343ba05cca48a6940293721066502a5c3d693
2012-05-07 14:25:16 -07:00
01f50663dc code-moving and clean-up
* removed use_lz77_ field, and added cache_bits_ one.
* use more BackwardRefs params
* move code around to organize more logically
* reduce memory use on histo
...

Change-Id: I833217a1b950189cf486704049e3fe28382ce335
2012-05-07 14:25:14 -07:00
31035f3b49 reduce memory usage by allocating only one histo
instead of lz77+rle

* introduce VP8LBackwardRefs structure and simplify the code by not passing
  around {PixOrCopy/int} pairs.

More functions should be turned into using this struct (TODO(later)).

Change-Id: I69c5c9fa61dddd61a2abc2824d70b8606a1c55b6
2012-05-07 14:25:12 -07:00
fbb501b8ee Restrict histo_bits to ensure histo_image size is under 32MB
Change-Id: I75ccb65d56ee060b649de714287e71611a92c8e9
2012-05-07 14:25:10 -07:00
8415ddf3be further simplification for the meta-Huffman coding
* don't transmit the number of Huffman tree group explicitly
* move color-cache information before the meta-Huffman block

* also add a check that color_cache_bits is in [1..11] range, as per spec.

Change-Id: I81d7711068653b509cdbc1151d93e229c4254580
2012-05-07 14:25:07 -07:00
e491729905 A quick pass of cleanup in backward reference code
const correctness, renaming, cosmetics etc.

Change-Id: I432befbb22f0eafd9a613f5f632398b6ef03c0f6
2012-05-07 14:25:05 -07:00
83332b3c16 Make transform bits a function of encode method (-m).
Change-Id: Idc392f7cba6e160ea068eacd7f82be4ebc971eaa
2012-05-07 14:25:03 -07:00
72920caa61 introduce -lossless option, protected by USE_LOSSLESS_ENCODER
Change-Id: Ic5707082fefd964b9bcab0c9f9aa276992c22b06
2012-05-07 14:25:02 -07:00
c6ac4dfbb4 Run TraceBackwards for higher qualities.
Also reduce the iteration count in function VP8LHashChain_FindCopy.

Change-Id: I73e3811e142e81314515587fd655ab3bfa74d099
2012-05-07 14:25:00 -07:00
412222c88c Make histo_bits and transform_bits function of quality.
Change-Id: Ic34e40853604811abc63a38e09d6a01961649efc
2012-05-07 14:24:58 -07:00
149b5098a9 Update lossless encoder strategy:
Don't use any other transform when using palette.

Change-Id: I488ac546869677f1b6e4eed80e973569c757e997
2012-05-07 14:24:56 -07:00
0e6fa06595 cache_bits passed to EncodeImageInternal()
should be 0 when not using color cache.

Change-Id: Id15c9b6bfbeb7c69a0189fa4c411df2763f9dead
2012-05-07 14:24:54 -07:00
e38b40a996 Factorize code for clearing HtreeGroup.
Change-Id: I29de6dab7383b8cf071eec155e01340d5fdadee5
2012-05-07 14:24:53 -07:00
6f4a16ea00 Removing the indirection of meta-huffman tables.
Now, the indexing refers directly to 5 huffman codes that must be encoded
separately.

Change-Id: I92e10ccf8ca464aa7259867d5fae2869343e3b3c
2012-05-07 14:24:51 -07:00
3d33ecd12b Some renaming/comments related to palette in lossless encoder.
Change-Id: Iaab32912f4c31e809d7a49fd748099d8c0c3e7d9
2012-05-07 14:24:49 -07:00
4d02d5863f Lossless encoder: correction in Palette storage
(Essentially, there was no need of a separate 'argb_palette' array. And
argb_palette[0] was never being set).

Change-Id: Id0a8c7e063d3af41e39fc9b8661611b51ccc55cd
2012-05-07 14:24:47 -07:00
4a6362357a fix a memleak in EncodeImageInternal()
Change-Id: I55cd013211f192188b54c694ef0837af0c01b53c
2012-05-07 14:24:45 -07:00
0993a611cd Full and final fix for prediction transform
use (tile_size + 1) rows of scratch area.

Change-Id: I06d612fff1794fc045ba76275e94e7210802c332
2012-05-07 14:24:43 -07:00
afd2102f43 Fix cross-color transform in lossless encoder
make elements of "Multiplier" struct unsigned, so that any negative values are
automatically converted to "mod 256" values.

Change-Id: Iab4f9bacc50dcd94a557944727d9338dbb0982f7
2012-05-07 14:24:41 -07:00
b96d8740c9 Need to write a '0' bit at the end of transforms.
Also convert an 'if' to 'assert'.

Change-Id: Ia1129ad9ddb027c27b4f4fc1da4bbaf53a0a8f76
2012-05-07 14:24:39 -07:00
54dad7e553 Color cache size should be counted as 0 when cache bits = 0
Change-Id: I1d05e0561a92aebaf62162fe11ffc4b12496d698
2012-05-07 14:24:37 -07:00
4f0c5caf67 Fix prediction transform in lossless encoder.
(Keep one tile as a scratch buffer).

Change-Id: If112ada29bfd0bdc81b82e849a566b30dd331d2f
2012-05-07 14:24:35 -07:00
36dabdadf8 Fix memory leak in method EncodeImageInternal for histogram_image.
Change-Id: Ia1cfb96d9e6c120630732e2b5f39688376d1d208
2012-05-07 14:24:33 -07:00
352a4f49ab Get rid of PackLiteralBitLengths()
[and in turn a malloc]. Also, a few related const fixes.

Change-Id: I229519b1c34d41c78d9ad2403f1e25feab3c9d93
2012-05-07 14:24:31 -07:00
d673b6b9a0 Change the predictor function to pass left pixel
instead of pointer to the source.

Change-Id: Ia2c8e17c3140709a825c2f85a88c5e31bd6e462f
2012-05-07 14:24:29 -07:00
b2f99465a7 Fix CopyTileWithPrediction()
so that it uses original values of left, top etc for prediction rather than the
predicted values of the same. Also, do some renaming in the same to make it
more readable.

Change-Id: I2fe94e35a6700bd437f5c601e2af12323bf32445
2012-05-07 14:24:27 -07:00
84547f540c Add EncodeImageInternal() method.
Most of changes in enc/vp8l.c is cherry-picked from src/lossless/encode.c

Change-Id: I27938cb2590eccbfe1db0a454343e856bd483e75
2012-05-07 14:24:25 -07:00
6b38378acb Guard the lossless encoder (in flux) under a flag
Change-Id: I6dd8fd17089c199001c06b1afde14233dc3e3234
2012-05-07 14:24:23 -07:00
09f7532cce Fix few nits (const qualifiers)
Change-Id: I527e82af49956b695ab18625d34e143854067421
2012-05-07 14:24:21 -07:00
648be3939f Added implementation for various lossless functions
- VP8LEncAnalyze, EvalAndApplySubtractGreen, ApplyPredictFilter,
  ApplyCrossColorFilter
- Added palette handling and transform buffer management in VP8LEncodeImage()
- Add Transforms (subtract Green, Predict, cross_color) to dsp/lossless.c.

These are more-or-less copied from src/lossless code.

After this Change, will implement the EncodeImageInternal() method.

Change-Id: Idf71f803c24b3b5ae3b5079b15e019721784611d
2012-05-07 14:24:19 -07:00
32714ce3be Add VP8L prefix to backward ref & histogram methods.
Change-Id: I8c14fb219a1d7830d3244aa780c91c9964867330
2012-05-07 14:24:17 -07:00
fcba7be2d3 Fixed header file tag (WEBP_UTILS_HUFFMAN_ENCODE_H_)
Change-Id: I7ccd00361b1b0347639b05ee494e8e701c95cfe3
2012-05-07 14:24:16 -07:00
bc7037465d Add backward_ref, histogram & huffman encode modules from lossless.
Change-Id: Iac056d27972956782defa182caa3ea400cdb77f8
2012-05-07 14:24:14 -07:00
fdccaaddcf Fixing nits
- Const Handling of picture object, removed bitwriter from encoder.

Change-Id: Id943854de09324de81cca615ada960390c4b8152
2012-05-07 14:24:12 -07:00
227110c4c3 libwebp interface changes for lossless encoding.
Change-Id: I703a1a18347acf78378cb23fddc6e5ca6dc6a0bb
2012-05-07 14:24:09 -07:00
50679acf25 minor style fixes
Change-Id: I78a6fa19a799c41d6536631f547279692b658c4d
2012-05-04 19:01:11 -07:00
b38dfccf8d remove unneeded reference to NUM_LITERAL_CODES
Change-Id: I3e98acce3a69fa45054ffcf77644fcbbc04bd366
2012-05-04 19:01:09 -07:00
8979675bdf harmonize header description
Change-Id: Ie0256794e663b58557e7234f08af3d516071001e
2012-05-04 19:01:06 -07:00
c04eb7be9d tcoder.c: define NOT_HAVE_LOG2 for MSVC builds
no version of msvc currently implements log2(). unconditionally define
NOT_HAVE_LOG2 in this case to simplify building libwebp sources in other
projects.

Change-Id: Ia9d985b1125553c5a8271d7e539bc1b4f898d749
2012-05-03 16:59:13 -07:00
9a214fa112 Merge "VP8[L]GetInfo: check input pointers" 2012-05-02 16:07:47 -07:00
5c5be8ba69 VP8[L]GetInfo: check input pointers
validate data before using & width/height before assigning.

Change-Id: I0872e80fcbfea295d7c633b0d4cb7809e1d1883b
2012-05-02 16:05:02 -07:00
0c188feca1 Merge changes I431acdfe,I713659b7
* changes:
  mux: drop 'chunk' from ChunkInfo member names
  muxi.h: remove some unused defines
2012-05-02 16:03:06 -07:00
b3515c6215 mux: drop 'chunk' from ChunkInfo member names
fixes naming style (members should be lowercase, not camelcase).

Change-Id: I431acdfe3cc3740d9effe9df80a94ca284a072b6
2012-05-01 17:47:18 -07:00
aea7923ca2 muxi.h: remove some unused defines
Change-Id: I713659b7ed83bafedd94a0b16379decea293a2f0
2012-05-01 17:47:11 -07:00
0142249285 update NEWS file for next release
Change-Id: I93ba2432fb99334dd17bd1a9da3a39c19e495484
2012-05-01 17:34:14 -07:00
29e3f7ec75 Merge "dec: remove deprecated WebPINew()" 2012-05-01 11:26:31 -07:00
4718e44988 Merge "muxedit: a few more size_t changes" 2012-04-28 03:04:08 -07:00
82654f961d Merge "muxedit: remove a few redundant NULL checks" 2012-04-28 02:50:27 -07:00
02f27fbd3b dec: remove deprecated WebPINew()
Change-Id: I22ad1d297333f5ebc84456d142426a4e0e9a044b
2012-04-27 19:47:35 -07:00
ccddb3fc6f muxedit: remove a few redundant NULL checks
Change-Id: I8285a7694d40b0f5c986dbfe40703251682eaafc
2012-04-27 19:06:03 -07:00
a6cdf7107a muxedit: a few more size_t changes
Change-Id: I18266dc572426cb3daace6e0ad8f2ae21687a151
2012-04-27 18:53:08 -07:00
a384689292 Merge "mux: remove unused LIST_ID" 2012-04-27 03:03:34 -07:00
11ae46ae91 alpha.c: quiet some size_t -> int conversion warnings
Change-Id: I52026a9271bde4028f00df2d752e100c61fd3fe3
2012-04-26 18:47:08 -07:00
dee466926b mux: remove unused LIST_ID
The 'LIST' fourcc is not a well known value in the context of webp.

Change-Id: I6a571f5f3acd6463cf3cad7c5d5ffa89d0597fb6
2012-04-25 18:18:25 -07:00
03f1f49321 mux: add version checked entry points
Change-Id: I3bf5b25b17c06ec092f8ad1c14eea411aa9471c1
2012-04-25 17:27:16 -07:00
6a0abdaa3a Merge "doc: tile/alpha corrections" 2012-04-24 23:57:05 -07:00
c8139fbe5d Merge "few cosmetics" 2012-04-24 23:47:06 -07:00
683387374b Merge "lossless: remove some size_t -> int conversions" 2012-04-24 23:41:26 -07:00
5249e94a22 doc: tile/alpha corrections
- the tile chunk size does not include the alpha or vp8 chunks that
  follow
- remove 'experimental' note from alpha section
- drop an unused term from the terminology section

Change-Id: I46f0fd610bbce579446e19339c3458dddfb595f7
2012-04-24 17:43:06 -07:00
d96e722b0c huffman: quiet int64 -> int conversion warning
children_ is bounded by max_nodes_ and protected with IsFull checks

Change-Id: Iac1eb03c5030568140352174c1265a938fc28d97
2012-04-24 16:17:36 -07:00
532020f24a lossless: remove some size_t -> int conversions
Sizes are given as ints in the documentation and used as such elsewhere.

Change-Id: I51ecd9e501cf9b4e3948aa0e947d2c9b5c85a30f
2012-04-24 16:00:00 -07:00
23be6edfd4 few cosmetics
Change-Id: I85b44d811ecc7c551b75e74e64115e74645836b6
2012-04-24 11:53:10 -07:00
1349edade1 Merge "configure: AC_ARG_* use AS_HELP_STRING" 2012-04-24 10:54:39 -07:00
bfbcc60a18 configure: AC_ARG_* use AS_HELP_STRING
properly formats --help output

Change-Id: I18fad9039400df8415ef192a41c0295019c52775
2012-04-24 10:48:17 -07:00
1427ca8eae Merge "Makefile.am: header file maintenance" 2012-04-24 10:41:59 -07:00
087332e394 Merge "remove unused parameter 'round' from CalcProba()" 2012-04-24 06:41:54 -07:00
9630e16854 remove unused parameter 'round' from CalcProba()
Change-Id: I0d89c34565decb28776aee7500ebd261fc43caf7
2012-04-24 06:40:19 -07:00
92092eaa45 Merge "bit_reader.h: correct include" 2012-04-24 04:19:24 -07:00
a87fc3f609 Merge "mux: ensure # images = # tiles" 2012-04-24 04:18:35 -07:00
53af99b18f Merge "mux: use size_t consistently" 2012-04-24 04:09:44 -07:00
39a57dae22 Makefile.am: header file maintenance
src/dec/Makefile.am: add missing reference to vp8li.h
src/{dec,dsp,enc}/Makefile.am: move some headers to noinst_

Change-Id: I0e2bc69980bd8175d99ad0ab63f537ef9e425b77
2012-04-23 18:53:48 -07:00
1bd0bd0d4d bit_reader.h: correct include
use webp/types.h rather than webp/decode_vp8.h

Change-Id: I9c6da04b92ff00d6dac47ce3eb0bcb2d6a96712d
2012-04-23 17:04:22 -07:00
326a3c6bdc mux: ensure # images = # tiles
when a file contains tiles an image outside of a tile is not allowed.

Change-Id: I5d16759abc9aa9bb299103b2cd7d694fc9c89697
2012-04-23 16:44:37 -07:00
95667b8d86 mux: use size_t consistently
remove mixed use of uint32_t

Change-Id: I57f701a0d9fce255c4dd83c01e523079976ef5b5
2012-04-23 11:00:20 -07:00
231ec1fb6d Removing the indirection of meta-huffman tables.
Now, the indexing refers directly to 5 huffman codes  that must be encoded separately.

Change-Id: I4deeb04de1997e6d20c376046d2053ec7ee918de
2012-04-23 08:36:14 -07:00
15ebcbaaf4 check return pointer from MuxImageGetListFromId
previously, it could crash with nth=1 on a raw vp8 bitstream, e.g.

Change-Id: Ice555d95b984ba71017fc56314d0c2c1b5bdf599
2012-04-23 08:22:58 -07:00
b0d6c4a722 Merge "configure: remove test for zlib.h" 2012-04-21 15:34:41 -07:00
8cccac50ae Merge "dsp/lossless: silence some build warnings" 2012-04-21 15:32:45 -07:00
b08819a624 dsp/lossless: silence some build warnings
src/dsp/lossless.c: In function 'VP8LInverseTransform':
src/dsp/lossless.c:312:23: warning: 'packed_pixels' may be used
uninitialized in this function [-Wuninitialized]
src/dsp/lossless.c:304:16: note: 'packed_pixels' was declared here
src/dsp/lossless.c:258:34: warning: 'm.red_to_blue_' may be used
uninitialized in this function [-Wuninitialized]
src/dsp/lossless.c:275:17: note: 'm.red_to_blue_' was declared here
src/dsp/lossless.c:257:34: warning: 'm.green_to_blue_' may be used
uninitialized in this function [-Wuninitialized]
src/dsp/lossless.c:275:17: note: 'm.green_to_blue_' was declared here
src/dsp/lossless.c:255:33: warning: 'm.green_to_red_' may be used
uninitialized in this function [-Wuninitialized]
src/dsp/lossless.c:275:17: note: 'm.green_to_red_' was declared here

patch by pepijn vaneeckhoudt

Change-Id: Iffa4764487a75479df45e772169325cd9ee60d94
2012-04-20 12:35:35 -07:00
7ae225218d Android.mk: SSE2 & NEON updates
patch by pepijn vaneeckhoudt
- Android.mk should include dec/enc/upsampling sse2 variants. This
  provides sse2 optimizations when compiling for Android/x86
- LOCAL_ARM_NEON should be set to true when compiling for armeabi-v7a.
  Otherwise __ARM_NEON__ is not defined and all neon code is removed by
  the preprocessor.

Change-Id: I54f3505757fc5d2d63cca4b64d61be34a0b34eb8
2012-04-20 12:07:03 -07:00
0a49e3f3da Merge "makefile.unix add missing header files" 2012-04-20 00:34:35 -07:00
2e75a9a1ba Merge "decode.h: use size_t consistently" 2012-04-19 22:49:47 -07:00
fa13035e97 configure: remove test for zlib.h
hasn't been needed since:
  9523f2a Add Alpha Encode support from WebPEncode.

Change-Id: Ia784ac434ec6fd43aade8875a91e2ad9f0fa9c30
2012-04-19 16:54:59 -07:00
d3adc81db2 makefile.unix add missing header files
Change-Id: I440ea805fd14884242bab2577e8286088616e5c7
2012-04-19 16:13:26 -07:00
262fe01be2 Merge "makefile.unix & Android.mk: cosmetics" 2012-04-19 16:03:08 -07:00
4cce137ebf Merge "enc_sse2 add missing stdlib.h include" 2012-04-19 15:51:53 -07:00
80256b8567 enc_sse2 add missing stdlib.h include
lost in fbd82b5; most platforms were getting it indirectly through
emmintrin.h.

Change-Id: I310f8bc8e82d63cfbde74c34cd21b72514a16a01
2012-04-19 15:47:58 -07:00
9b3d1f3a1b decode.h: use size_t consistently
replaces mixed use of int/uint32_t for buffer sizes
further changes the API/ABI.

Change-Id: I91d70fd82ee3e1ac34b884b8ead9a114a9b1015a
2012-04-19 14:31:31 -07:00
64083d3c89 Merge "Makefile.am: cosmetics" 2012-04-19 13:51:33 -07:00
dceb8b4d9a Merge changes If1331d3c,I86fe3847
* changes:
  types.h: centralize use of stddef.h
  vp8io: use size_t for buffer size
2012-04-14 13:01:14 -07:00
0e33d7bf42 Merge "webp/decode.h: fix prototypes" 2012-04-13 10:46:14 -07:00
fac0f12e1b rename BitReader to VP8LBitReader
Change-Id: I192b76422e131a94fb58c2c4a5520a5dba807126
2012-04-13 01:56:31 -07:00
fbd82b5a39 types.h: centralize use of stddef.h
for size_t / NULL

Change-Id: If1331d3cf44296ed0ba9e838eae2f5b1bcaeb61b
2012-04-12 17:14:58 -07:00
2154835f73 Makefile.am: cosmetics
- use common file organization across subdir makefiles
- append lib/source/header list variables and sort

Change-Id: I0653e1c73a4552b0c43d21f321b22b4972d6e87b
2012-04-12 15:53:06 -07:00
1c92bd37f3 vp8io: use size_t for buffer size
changes the decoder ABI

Change-Id: I86fe384739b985bf63bcd9badbbbf4411e1eecae
2012-04-12 15:19:53 -07:00
90ead710dc fix some more uint32_t -> size_t typing
Change-Id: Ibbe85ff4a700b17126a65e9ca5a3fa8cbf00b8a6
2012-04-12 13:06:54 -07:00
cbe705c78a webp/decode.h: fix prototypes
fell out of sync with:
  6860c2e fix some uint32_t -> size_t typing

Change-Id: I897fcd61f6a9767fb6accc5899d8e7763c9f4de8
2012-04-12 12:52:17 -07:00
3f8ec1c21f makefile.unix & Android.mk: cosmetics
split object/source list to single line & sort
remove unnecessary tabs

Change-Id: I1db03555f9578e128c746853084438da2b9186eb
2012-04-12 12:29:57 -07:00
217ec7f4d0 Remove tabs in configure.ac
Change-Id: Ia6cd668523881ca6777a723bfe3460f38d064934
2012-04-12 00:13:06 -07:00
b3d35fc130 Merge "Android.mk & Makefile.vc: add new files" 2012-04-11 15:48:30 -07:00
0df04b9e19 Android.mk & Makefile.vc: add new files
from the lossless additions, fixes the build.

Change-Id: I3243c48f21cfb4e2244614bb5ab12ff94dd684e5
2012-04-11 15:47:04 -07:00
e4f20c5bd5 Merge "automake: replace 'silent-rules' w/AM_SILENT_RULES" 2012-04-11 15:45:55 -07:00
8d254a0927 cosmetics
long line, remove out of date TODO

Change-Id: Ic8a40c9d731178af85645b3e24c1cbd807d7d58b
2012-04-11 15:44:48 -07:00
6860c2ea9d fix some uint32_t -> size_t typing
Change-Id: I078243802a67498dfcd3d15b5f1bebf4b6b3b1bb
2012-04-11 04:27:45 -07:00
4af1858a10 Fix a crash due to max symbol in a tree >= alphabet size
(cherry picked from commit 15253f91567ce7a2a4a3de8d70e54ba4b0641af3)

Change-Id: I4fbeaea4c712dae3bef078aef9d302b44bc39ffb
2012-04-10 23:07:13 -07:00
6f01b830e2 split the VP8 and VP8L decoding properly
* each with their own decoder instances.
* Refactor the incremental buffer-update code a lot.
* remove br_offset_ for VP8LDecoder along the way
* make VP8GetHeaders() be used only for VP8, not VP8L bitstream
* remove VP8LInitDecoder()
* rename VP8LBitReaderResize() to VP8LBitReaderSetBuffer()
(cherry picked from commit 5529a2e6d47212a721ca4ab003215f97bd88ebb4)

Change-Id: I58f0b8abe1ef31c8b0e1a6175d2d86b863793ead
2012-04-10 23:06:58 -07:00
f2623dbe58 enable lossless decoder
import changes from experimental 5529a2e^
and enable build in autoconf and makefile.unix; windows will be treated
separately.

Change-Id: Ie2e177a99db63190b4cd647b3edee3b4e13719e9
2012-04-10 23:06:36 -07:00
b96efd7d50 add dec/vp8i.h changes from experimental
Pulled from 5529a2e^.

Change-Id: I51fe7a9c3acf1be4c43af834fd525ab3be5d7e65
2012-04-10 23:05:57 -07:00
19f6398ed7 add dec/vp8l{i.h,.c} from experimental
Pulled from 5529a2e^.
The history of this and related files is a bit entangled so rather
trying to split the changes and introduce some noise in master's history
we'll start with a fresh snapshot.
The file progression is still available in the experimental branch.

Change-Id: I490a49cb0084d556a29d7c5257c986ea695ce60c
2012-04-10 23:05:14 -07:00
c4ae53c8b3 add utils/bit_reader.[hc] changes from experimental
Pulled from the parent of the current version (5529a2e^).
The history of this and related files is a bit entangled so rather
trying to split the changes and introduce some noise in master's history
we'll start with a fresh snapshot.
The file progression is still available in the experimental branch.

Change-Id: I6dae97fc381cd6c1d1640c4c565b2084a41ec955
2012-04-10 17:48:49 -07:00
514d008921 add dsp/lossless.[hc] from experimental
Pulled from the current HEAD (218c32e).
The history of this and related files is a bit entangled so rather
trying to split the changes and introduce some noise in master's history
we'll start with a fresh snapshot.
The file progression is still available in the experimental branch.

Change-Id: I40538799dbf999abb9408ac83f55b897d8e22498
2012-04-10 17:37:44 -07:00
9c67291d67 add utils/huffman.[hc] from experimental
Pulled from the current HEAD (218c32e).
The history of this and related files is a bit entangled so rather
trying to split the changes and introduce some noise in master's history
we'll start with a fresh snapshot.
The file progression is still available in the experimental branch.

Change-Id: Ie57be21bf50ad83808c72aeb5fc706d9954d01d8
2012-04-10 17:31:54 -07:00
337914a036 add utils/color_cache.[hc] from experimental
Pulled from the current HEAD (218c32e).
The history of this and related files is a bit entangled so rather
trying to split the changes and introduce some noise in master's history
we'll start with a fresh snapshot.
The file progression is still available in the experimental branch.

Change-Id: Id879be453a94d9f44ec8d47747823ca7297ae008
2012-04-10 17:23:38 -07:00
b3bf8fe7a1 the read-overflow code-path wasn't reporting as an error
(since 'ok' was '1' by default)
(cherry picked from commit fe5eb4ffae74ff493e92fb5cd9a7a1625a113a7b)
2012-03-30 18:58:30 -07:00
1db888ba40 take colorspace into account when cropping
(cherry picked from commit 4e33653b52637c74ae30adde7990265d1d43994b)

Conflicts:

	src/dec/vp8l.c
2012-03-30 12:48:24 -07:00
61c2d51fd7 move the rescaling code into its own file and make enc/ and dec/ use it.
(cherry picked from commit 8e92d9e380a89b7443a2e2c3d16ce5a222e8c1e8)

Conflicts:

	Android.mk
	makefile.unix
	src/dec/vp8l.c
	src/utils/Makefile.am
2012-03-30 12:16:25 -07:00
efc2016a31 Make rescaler methods generic
to be used in rescaling of lossless bitstreams.
(cherry picked from commit 2e12a3045498b6faf13b93bc25391e8226119f0a)
2012-03-30 11:57:07 -07:00
3eacee8158 Move rescaler methods out of io.c.
(cherry picked from commit b5e9db1824f6efbe0bfb87e94b8d6e88a7973ef7)
2012-03-30 11:56:51 -07:00
a69b893dda automake: replace 'silent-rules' w/AM_SILENT_RULES
silent-rules is a new option with automake-1.11; older versions will
fatally exit with it. Using AM_SILENT_RULES will only result in a
warning at least through automake-1.9.

Change-Id: Ieae6a09780efd85f08f0c6442172634a1ce5ff33
2012-03-28 22:46:12 -07:00
6f7bf645b4 issue 111: fix little-endian problem in bit-reader
patch by naideflan

Change-Id: I874dbd5588d5cd2559c54ca9ad5582fa3a589b1b
2012-03-27 05:55:20 -07:00
ed278e2279 Removed unnecessary lookup
The lookup value is the same as the index.  The index in this
case is either a 0 or 1.

Change-Id: I0432dfcbea9e7bb20bca7574e25fb1fd8a51c8e9
2012-03-26 11:44:04 -04:00
cd8c3ba78f fix some warnings: down-cast and possibly-uninitialized variable
Change-Id: I5baf59bbcd5dcff69316b0601483ff5abe8e1454
2012-03-16 20:20:33 -07:00
0a7102ba60 ~1% improvement of alpha compression
by packing the symbol map more efficiently.

This is mainly useful in making it harder to generate invalid bitstream:
before this change, one could code the same symbol twice. Now, it's
impossible, since we code the position using empty symbol slots, instead
of total position.

* Fix the HasOnlyLeftChild() naming while at it.

Change-Id: I63c56c80a4f04a86ac83eded1e3306329815b6c9
2012-02-24 19:59:40 -08:00
3bc1b14191 Merge "Reformat container doc" 2012-02-24 19:30:40 -08:00
dc17abdcb6 mux: cosmetics
add a few missing consts and remove an unnecessary cast

Change-Id: I396571090ce379bbc7a173cbc90714a6b7b52a2a
2012-02-23 13:21:43 -08:00
cb5810dfbe Merge "WebPMuxGetImage: allow image param to be NULL" 2012-02-22 21:58:48 -08:00
506a4af2fa mux: cosmetics
group like parameters together in prototypes, comments, move variable
declarations closer to first use.

Change-Id: Idd6bd87d0366d783fed83f4dd21bd7968cbe6948
2012-02-22 16:14:32 -08:00
135e8b1942 WebPMuxGetImage: allow image param to be NULL
but not both alpha & image

Change-Id: I6822a740de7577eedcbe7529382aa2c020d1e8e4
2012-02-22 16:09:06 -08:00
de556b6866 Merge "README.mux: reword some descriptions" 2012-02-22 15:02:50 -08:00
0ee2aeb904 Makefile.vc: use batch mode rules
speeds up the build

Change-Id: I2471fb6b42bb5d51f8dd1634f65d5f8114355a22
2012-02-22 11:36:28 -08:00
d9acddc010 msvc: move {i,p}db creation to object directory
avoids cluttering the source tree.

Change-Id: I2885b36dd7152e294536584fa5cfe3ae8b04c7fa
2012-02-22 11:19:16 -08:00
237c9aa727 Merge "expose WebPFree function for DLL builds" 2012-02-22 10:55:52 -08:00
b3e4054f14 silence msvc debug build warning
_byteswap_ulong is defined in stdlib.h, release builds seem to pull it
in through a different path.

Change-Id: I510d2624150f89a4a77734bf3dc5b4db60a4ba95
2012-02-21 13:57:48 -08:00
45feb55dec expose WebPFree function for DLL builds
This allows managed code (e.g., C#) to free buffers returned by the API
instead of relying on free().
Based on suggestion from Steven (grokys at googlemail dot com).
Fixes issue #109.

Change-Id: I94826a77f6f4cb6e331c454f994c964e2e448cae
2012-02-21 13:48:06 -08:00
11316d84b4 README.mux: reword some descriptions
Change-Id: I334caaa908c9a50baf8e35125dd0062d764f2949
2012-02-17 14:39:31 -08:00
4be52f4a65 factorize WebPMuxValidate
move count extraction, count and feature flag validation to
ValidateChunk.

Change-Id: I4bd81bbc8a5a48e1263d11992ab3f285c45417b8
2012-02-15 11:54:10 -08:00
14f6b9f606 mux: light cleanup
- const / move declarations closer to first use
- remove unnecessary ()s
- don't return int unnecessarily with internal Init/Release
- compact some lines

Change-Id: If7ab505e417221debc356f21f075506939110a84
2012-02-14 13:51:41 -08:00
5e96a5dbef add more param checks to WebPPictureDistortion()
and use the proper alpha flag too.

Change-Id: I664c6c9dbcc747495bf20b3da95d00e1120b5baf
2012-02-10 02:52:48 -08:00
8abaf82083 Merge "silence some type size related warnings" 2012-02-09 19:21:39 -08:00
1601a39b09 silence some type size related warnings
size_t/ptrdiff_t -> uint32_t

Change-Id: Ic4d889b9239752311b9ed906c83076829d850874
2012-02-09 13:00:09 -08:00
f3abe520ac Merge "idec: simplify buffer size calculation" 2012-02-09 01:25:00 -08:00
a9c5cd4c97 idec: simplify buffer size calculation
Change-Id: Id0e20c44704ef9b0e14dcf5e71a05cea488fd95a
2012-02-08 14:29:25 -08:00
7b06bd7fcb Merge "configure/automake: add silent-rules option" 2012-02-08 14:04:12 -08:00
e9a7d145e7 Reformat container doc
- split the doc into sections for simple and extended format and move
  example layouts to the end.
- use ASCII tables to describe chunk formats
- attempt to consistently use MUST/SHOULD, etc.
- remove bold from most terms, but add them to definition lists which
  allow for the styling to be changed.

Change-Id: I93c1cd33bde9ccf0b265b202ec4182ce98fd6b48
2012-02-08 11:32:42 -08:00
d4e5c7f327 configure/automake: add silent-rules option
Enables --(enable|disable)-silent-rules and make V=[01] to control
compile output. Default is verbose as before.

Change-Id: Id9a65977ac8c719f4d9e3efe386750e520689b76
2012-02-07 18:08:08 -08:00
5081db78be configure/automake: no -version-info for convenience libs
Silences:
libtool: link: warning: `-version-info/-version-number' is ignored for
convenience libraries

Change-Id: I5705383b58f529fb06c2bf0932976b5a202446b6
2012-02-07 18:06:20 -08:00
85b6ff6897 Merge "idec: fix WebPIUpdate failure" 2012-01-31 23:39:02 -08:00
7bb6a9ccd6 idec: fix internal state corruption
A call to Append/Update would index the parts_ array w/-1 as num_parts_
had yet to be set by DecodePartition0. This would cause corruption
within the VP8Decoder member.

Fixes issue #106.

Change-Id: Ib9f2811594ff19e948a66fda862a4e0a384bb9aa
2012-01-31 17:10:29 -08:00
89cd1bb85b idec: fix WebPIUpdate failure
If the first call to WebPIUpdate contained all of partition 0, but not
enough to decode a macroblock the test for max macro block size could
fail (4096 bytes) due to a memory buffer offset not being updated.
This change offsets the buffer in the same manner as Append().

Fixes issue #105.

Change-Id: I90ca3d0dde92eedc076933b8349d2d297f2469e8
2012-01-31 16:55:10 -08:00
01b6380656 4-5% faster decoding, optimized byte loads in arithmetic decoder.
Bits are loaded 32bits at a time (and often aligned).
Rather 64bit-friendly

Change-Id: If7f67dbe5e37696efbeb6d579d9d8482350b79ee
2012-01-31 02:07:15 -08:00
631117ea5e Merge "cosmetics & warnings" 2012-01-30 22:04:11 -08:00
a0b2736d79 cosmetics & warnings
- remove some unused functions
- move global arrays from data to read only section
- explicitly cast malloc returns; not specifically necessary, but helps
  show intent
- miscellaneous formatting

Change-Id: Ib15fe5b37fe6c29c369ad928bdc3a7290cd13c84
2012-01-30 17:19:53 -08:00
f73947f41d use 32bit for storing dequant coeffs, instead of 16b.
is a tad faster

Change-Id: Ibef8f3b4f3f04a9a647098e5946f616e211a61cd
2012-01-29 17:38:37 -08:00
b9600308e8 Merge "store prediction mode array as uint8_t[16], not int[16]." 2012-01-27 07:16:50 -08:00
7b67881a23 store prediction mode array as uint8_t[16], not int[16].
This allow faster copy and gives a little bit of speed-up

Change-Id: I5f478229766098630b53b8a4982442fe29290ee6
2012-01-27 03:17:41 -08:00
cab8d4dc22 Merge "NEON TransformOne" 2012-01-26 11:38:16 -08:00
ba503fdac6 NEON TransformOne
As with the loop filter, implementing this with intrinsics is difficult
because we require subscript access for reading and writing 32 bits at a
time.

Approximately 5% decode speed improvement. This could be increased by
exposing TransformOne and rewriting TransformTwo to only handle dual
IDCTs.

Change-Id: Idd409264ab5d154a537107a1d54b419a48f7c1a8
2012-01-26 11:37:32 -08:00
9f740e3b1a Merge "gcc warning fix: remove the 'const' qualifier." 2012-01-25 15:53:10 -08:00
f76d3587e5 gcc warning fix: remove the 'const' qualifier.
Change-Id: I47b8f147f54072cb9b62669efd78c7b958aa5c08
2012-01-25 15:50:24 -08:00
e78478d62c Merge "webpmux: make more use of WebPData" 2012-01-25 13:06:49 -08:00
f85bba3dae Merge "manpages: add BUGS section" 2012-01-25 12:43:16 -08:00
48a43bbfae Merge "makefile.unix: variable cosmetics" 2012-01-25 12:42:09 -08:00
c274dc9679 makefile.unix: variable cosmetics
use CPPFLAGS to hold include paths, makes overriding CC a bit more
intuitive.

Change-Id: I6ecfc1957cae423dd150ebf37b878f1da6bbcef3
2012-01-25 10:46:28 -08:00
1f7b8595ae re-organize the error-handling in the main loop a bit
Change-Id: Id74298131df9c33a86b989e15c11ffb6d04960d8
2012-01-25 08:34:58 -08:00
1336fa719d Only recompute level_cost_[] when needed
Add a dirty_ flag to keep track of updated probabilities and the need to
recompute the level costs.
This only makes a difference for "-m 2" method which was sub-optimal.
But it's overall cleaner to have this flag.

Change-Id: I21c71201e1d07a923d97a3adf2fbbd7d67d35433
2012-01-25 07:52:34 -08:00
771ee449b0 manpages: add BUGS section
reorder sections to better match 'man man-pages'

Change-Id: I6cc3cd7f74b6cc6848c407cb1f042207c82f847e
2012-01-24 17:40:42 -08:00
0f7820e65c webpmux: make more use of WebPData
Add WebPDataCopy and use it in ReadImage which now returns WebPData*s.
Update ReadData prototype variables used with it to avoid unnecessary
const casting back and forth from void*.

Change-Id: I3f83db6729306eab0db9027b68706c8a7005ec10
2012-01-24 17:18:45 -08:00
974aaff360 examples: logging updates
- send errors to stderr
- send help to stdout
- add image size to webpmux -info output and send to stdout
- correct webpmux exit values

Change-Id: Ifd8e8493aab33a82765f7b7903cef345d96da9ae
2012-01-24 16:55:38 -08:00
6c14aaddc4 Merge "better token buffer code" 2012-01-23 18:55:11 -08:00
f40542508c better token buffer code
(still not finished, but compiles and works ok)

Change-Id: I7002bf8017e31e7af34a53126072b625d23e2589
2012-01-23 18:54:24 -08:00
18d959fa9a Merge "mux: add WebPData type" 2012-01-23 18:00:21 -08:00
eec4b87718 mux: add WebPData type
slightly simplifies Get process

Change-Id: I9db365da29038e02a032494e0ef3d8a0d7515210
2012-01-23 17:51:01 -08:00
0de3096b3a use 16bit counters for recording proba counts
This proved being ok, even for large pictures, provided one
takes care of overflow. When an overflow is bound to occur, the
counters are renormalized.
Overall, shaves ~12k of memory.

Change-Id: I2ba21a407964fe1a34c352371cba15166e0c4548
2012-01-23 17:50:58 -08:00
7f23678da0 fix for LevelCost + little speed-up
the p0 proba was incorrectly accumulated. Merging its contribution into
the LevelCost[] was creating more problems than anything (esp. with trellis)
so let's just not.

Change-Id: I4c07bfee471085df901228d97b20a4d9606ba44e
2012-01-23 09:21:17 -08:00
7107d54483 further speed-up/cleanup of RecordCoeffs() and GetResidualCost()
(note: Incorporated the cost of bin #1 into the LevelCost[])

Change-Id: I6408b2a822efdb97ad6a3a21d380bc7b0da9c715
2012-01-23 07:01:37 -08:00
fd22104022 Introduce Token buffer (unused for now)
Later, will be useful to collect stats and code bitstream in one single pass

Change-Id: Icf866473958b5eff879e219dbb1d7e350f2268ba
2012-01-23 05:57:12 -08:00
5fa148f47c Merge "speed-up GetResidualCost()" 2012-01-23 02:50:58 -08:00
28a9d9b41a speed-up GetResidualCost()
+ misc cosmetics and code polishing

Change-Id: I5830cd2f268d64c072b1cbccc0a4674833875055
2012-01-23 02:36:38 -08:00
11e7dadd96 Merge "misc cosmetics" 2012-01-22 23:52:29 -08:00
378086bd0a misc cosmetics
Change-Id: Iafc73f9fece13b5ca900a8b9c1039268872a181b
2012-01-22 23:20:53 -08:00
d61479f95b add -print_psnr and -print_ssim options to cwebp.
These will report the 7x7-averaged PSNR or SSIM, using the
new internal function WebPPictureDistortion().
This is for information only. These flags have no encoding impact.

+misc opportunistic cosmetics

Change-Id: I64c0a7eca679134d39062e438886274b22bb643f
2012-01-20 07:37:29 -08:00
2e3e8b2ef5 add a WebPCleanupTransparentArea() method
to 'clean up' the fully-transparent area and make it more compressible
new cwebp flags: -alpha_cleanup (off by default, since gain is not 100% guaranteed)

Change-Id: I74d77e1915eee146584cd61c9c1132a41db922eb
2012-01-18 14:01:24 -08:00
552c121715 Merge "mux: plug some memory leaks on error" 2012-01-18 13:46:38 -08:00
a2a81f7d61 Merge "fix Mach-O shared library build" 2012-01-18 13:16:12 -08:00
b3482c4300 Merge "fix gcc-4.0 apple 32-bit build" 2012-01-18 13:15:23 -08:00
e4e3ec19ad fix gcc-4.0 apple 32-bit build
gcc-4.0 defines __PIC__ but not __pic__. This leaves the test for
__pic__ should the inverse case exist.
Fixes issue #103; build failing with:
"error: can't find a register in class 'BREG' while reloading 'asm'"

Change-Id: Ia767a733de6ce0294146f9477ff9c46f0ebe13b0
2012-01-18 13:12:45 -08:00
b0d2fecf25 mux: plug some memory leaks on error
Make sure chunk->data and wpi are not leaked by
MuxAddFrameTileInternal() in case of MEMORY_ERROR in ChunkSetNth().

Change-Id: Ie20e84b92f4bdcb7c3b94520f36b20dd2e730545
2012-01-17 18:40:25 -08:00
f0d2c7a76f pass of cosmetics
Change-Id: Id031221b7499e8cfc460c873d0f8124c9bef3aa3
2012-01-17 18:32:27 -08:00
b309a6f901 fix Mach-O shared library build
Add extern to kChunks[] in muxi.h.
Fixes:
ld: duplicate symbol _kChunks in .libs/muxinternal.o and .libs/muxedit.o

Change-Id: Ibeb060f7fdec5fe904097a2443f0cda2f7ede884
2012-01-17 16:51:19 -08:00
241ddd38e2 doc: delete mux container pdf
The source is now webp-container-spec.txt.

Change-Id: I43debf616b7eec774b5e1586c286974c7332fb48
2012-01-17 12:54:51 -08:00
8b1ba272d2 doc: update VP8 decode guide link
The draft is now RFC6386.

Change-Id: Ief019357af5a5de9c6290cafd34db09d984f58aa
2012-01-17 12:52:27 -08:00
7e4371c5b3 WebPMuxCreate: fix unchecked malloc
Change-Id: Ic824cdfbede4abe8e5106904dd17d564bb1b32d4
2012-01-15 11:18:23 -08:00
eb425586e1 Merge "have makefile.unix clean up src/webp/*~ too" 2012-01-13 14:27:46 -08:00
a85c363186 Merge "correct EncodeAlpha documentation" 2012-01-13 14:27:03 -08:00
a33842fdb0 Merge "Update webp container spec with alpha filter options." 2012-01-13 14:25:39 -08:00
8d6490dae6 Incremental support for some of the mux APIs.
This CL adds incremental support for WebPMuxCreate() and
WebPMuxGetFeatures()

Change-Id: I312122f5e817d58366e18ae238cb9e2a493811fb
2012-01-13 14:47:53 +05:30
b8375abd08 have makefile.unix clean up src/webp/*~ too
Change-Id: Ida17b92346055b197fe6ccb60a9ac223ddd46f90
2012-01-12 18:49:29 -08:00
b5855fc78d correct EncodeAlpha documentation
The paeth filter was removed in 8ca2076

Change-Id: I743502147da4e0b5506e49382311b8f592973d41
2012-01-12 18:37:45 -08:00
dba37fea0e Update webp container spec with alpha filter options.
Change-Id: I032f350c8c698aeb139f7dd148f01a0a3b012b6d
2012-01-12 18:25:00 -08:00
2e74ec8b5f fix compile under MINGW
there was a type conflict around INT32 (in libjpeg).

Patch by nipmarsh
Issue 102: http://code.google.com/p/webp/issues/detail?id=102

Change-Id: I6425b6b9b9861bcaa8bb1adc8a78541e44031a6e
2012-01-12 04:53:30 -08:00
716d1d7f87 fix suboptimal MAX_LEN cut-off limit
MAX_LEN -> max_len
This was sub-optimal at the end of the picture, when there's
less than MAX_LEN bytes left to match.

Change-Id: I5ebe1fca4e7c112dcd34748a082d1c97f95eb099
2012-01-10 07:41:11 -08:00
57cab7b891 Harmonize the alpha-filter predictions at boundary
often reduces compressed size by ~10's of bytes
+ refactored / sped-up the prediction code (gradient: ~30% faster)

Change-Id: I26bd983655dad4f85d5c5ddc20a1980f384c4dd6
2012-01-10 03:21:13 -08:00
3a9895340f Merge "Fix bug for Alpha in RGBA_4444 color-mode." 2012-01-09 02:59:59 -08:00
8ca2076de1 Introduce a 'fast' alpha mode
.. where only 2 filtering modes are potentially
tried, instead of all of them. This is fast than the exhaustive 'best'
mode, and not much worse.

Options for cwebp are:
 -alpha_filter none
 -alpha_filter fast      (<- default)
 -alpha_filter best      (<- slow)

Change-Id: I8cb90ee11b8f981811e013ea4ad5bf72ba3ea7d4
2012-01-09 02:37:44 -08:00
221a06bb16 Fix bug for Alpha in RGBA_4444 color-mode.
Fix bug for Alpha data in RGBA_4444 color-mode.
The Alpha data is required to be clipped [0, 15] while
converting from 8 bits to 4 bits.

Change-Id: I80705d575c35121beb9633a05ec8823435c79586
2012-01-09 14:07:30 +05:30
ad1e163a0d cosmetics: normalize copyright headers
Change-Id: I5e2462b101e0447a4f15a1455c07131bc97a52dd
2012-01-06 14:49:06 -08:00
c77424d7eb cosmetics: light include cleanup
remove some unused includes

Change-Id: I07fabf707e8eac7f204757e68dab1057fd21aef1
2012-01-06 14:38:34 -08:00
9d0e17c9a9 fix msvc build breakage after 252028a
replace inline with WEBP_INLINE; inline is reserved for c++ code
w/visual studio

Change-Id: Ib06c6a12fd786701740d8b260d9aa310ee81fddf
2012-01-05 18:26:40 -08:00
7c4c177c39 Some readability fixes for mux library
Add a #define for UNDEFINED_CHUNK_SIZE and remove a misleading comment.

Change-Id: I5c56a12f1245e647f913c35c6a34d2e5d658415e
2012-01-05 17:53:51 +05:30
d8a47e66f7 Merge "Add predictive filtering option for Alpha." 2012-01-05 00:33:32 -08:00
252028aaac Add predictive filtering option for Alpha.
Add predictive filtering option for Alpha plane.
Valid range for filter option is [0, 5] corresponding to prediction
methods none, horizontal, vertical, gradient & paeth filter.
The prediction method 5 will try all the prediction methods (0 to 4)
and pick the prediction method that gives best compression.

Change-Id: I9244d4a9c5017501a9696c7cec5045f04c16d49b
2012-01-05 13:55:35 +05:30
9b69be1cdc Merge "Simplify mux library code" 2012-01-05 00:15:48 -08:00
a056170eca Simplify mux library code
Refactor mux code into Read APIs, Set/Delete APIs and internal
objects/utils.

Change-Id: Ia4ce32ec18cf0c1c75de9084fbb28840d46892b4
2012-01-05 12:23:08 +05:30
992187a380 improve log2 test
- add check for native log2 to configure
- use a common define (NOT_HAVE_LOG2) to enable use of local library
  version for non-autoconf platforms without their own version,
  currently msvc and android

This uses a negative (NOT_HAVE_) to simplify the ifdef

Change-Id: Id0610eed507f8bb9c5da338918112853d5c8127a
2012-01-04 18:49:37 -08:00
e852f83205 update Android.mk file list
Change-Id: Idffc497931c85582725e65f1d7b7384bcee0fdd5
2011-12-26 02:39:56 -08:00
a90cb2be6e reduce number of copies and mallocs in alpha plane enc/dec
Change-Id: Ice48d2dd403c18870567ee6e1b210b1eb3d5b44f
2011-12-23 01:21:53 -08:00
b1662b0530 fix some more type conversion warnings w/MSVC
API & memory related warnings will be dealt with separately

Change-Id: I8a7893baa4d5035c963fb3c16e0bb4eee742e968
2011-12-21 16:07:16 -08:00
223d8c60aa fix some uint64_t -> int conversion warnings with MSC
Change-Id: I5dc314c9d1a3cbda095be3c90886983500104867
2011-12-21 14:43:52 -08:00
c1a0437b87 Merge "simplify checks for enabling SSE2 code" 2011-12-20 17:42:59 -08:00
f06817aaea simplify checks for enabling SSE2 code
also fixes build issues under vs11 which has a native arm compiler for
windows 8 targets

Change-Id: Id76c2deae9fc9de147d13ad0d34edffcb5a726c4
2011-12-20 17:41:55 -08:00
948d4fe94f silence a msvc build warning
implicit double -> float conversion; avoiding sqrtf (c99) for
compatibility

Change-Id: If9b367dde237fc5173c1445cc60b16aa6ad2821c
2011-12-19 23:04:01 -08:00
911795490e vwebp: msvc build tweaks
snprintf -> _snprintf / remove double->float warnings

Change-Id: I5dcdc394cf7e2d37205beaf83ed0f80a18ec06ab
2011-12-16 19:30:33 -08:00
7937b409e7 simple WebP viewer, based on OpenGL
Quite handy and simple (for now).
It's not yet incorporated within the build system (autotools or
makefile.unix), because it gets complicated with OpenGL. TODO(later).

For now, there's some ready-to-use command line for compiling on Linux
or Mac in the header of vwebp.c

Later, this tool will be supplemented with support for animation,
tiling, zooming, etc.

Change-Id: I292972cea4862536afbe8c9ec444c590d152f086
2011-12-13 14:02:04 -08:00
6aac1df17b add a bunch of missing 'extern "C"'
Change-Id: I8c0ada049ce9fa7ef14164b90d58e999cdabba53
2011-12-13 10:51:32 -08:00
421eb99db3 Merge "Remove assigned-but-not-used variable "br"" 2011-12-08 10:41:18 -08:00
91e27f4573 better fitting names for upsampling functions
Change-Id: I816e81586c9e1a74ebc5516598dbd4ae0ddf48d8
2011-12-08 06:42:53 -08:00
a5d7ed5c4b Remove assigned-but-not-used variable "br"
Fixes gcc 4.6.x -Wunused-but-set-variable compiler warning:

	libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I../.. -Wextra -Wall -Wunused-but-set-variable -MT libwebpdecode_la-idec.lo -MD -MP -MF .deps/libwebpdecode_la-idec.Tpo -c idec.c  -fPIC -DPIC -o .libs/libwebpdecode_la-idec.o
	idec.c: In function 'DecodeRemaining':
	idec.c:371:17: warning: variable 'br' set but not used [-Wunused-but-set-variable]

Change-Id: Ib037be9634b5b802ba9f1e2ef156a8fdf9630752
2011-12-08 15:42:01 +01:00
f62d2c9497 remove unused 'has_alpha' from VP8GetInfo() signature
alpha information is not to be found at RIFF chunks level, not
in the VP8 bitstream (that was a tmp hack)

Change-Id: Idd1629c696b03c26f6f30650d7216f627f1761df
2011-12-08 06:41:40 -08:00
08e865822a trap alpha-decoding error
Improves robustness to bad bitstream.

Change-Id: I87ca03ccd12d4d690904b35f8dfc2a20a28fb47b
2011-12-08 06:34:00 -08:00
b361eca1c5 add cut-off to arith coder probability update.
This speeds things up for long message, while not damaging
the stats too much for usual-sized cases

Change-Id: I3f45e28b771d701e2e1da11eb800de18c4ed12fc
2011-12-08 06:27:11 -08:00
8666a93aae Some bug-fixes for images with alpha.
- Fix the off-by-one diff when cropping with simple-filter.
- Fix a bug in incremental decoding in case of alpha.
- In VP8FinishRow(), do not decode alpha when y_start > y_end.
- Correct output of alpha channel for MODE_ARGB.
- Correct output of alpha channel for MODE_RGBA_4444.

Change-Id: I785763a2a704b973cc742ad93ffbb53699d1fc0a
2011-12-07 15:12:50 +05:30
273a12a013 fix off-by-1 diff in case cropping and simple filtering
Change-Id: I6dea172d0cf129f9986b8a3e1eea85fa97a70402
2011-12-05 08:37:55 -08:00
2f741d1e13 webpmux: ReadImage: fix ptr free in error case
allocate to temporaries and deal with output pointers in one place to
reduce casting.

Change-Id: Ib12d866440184315536f35a15eb5adeba7879ae7
2011-12-02 17:58:20 -08:00
721f3f48e7 fix alpha decode
- remove left-over WEBP_EXPERIMENTAL_FEATURES #ifdef

Change-Id: I2b91ccd2e2b3ebea63d5f698f90206feec30a4db
2011-12-02 11:00:27 -08:00
60942c8cea fix the has_alpha_ order
Change-Id: I26211732584f6181bf763497818b45515e394c21
2011-12-02 10:26:42 -08:00
30971c9e95 Implement progress report (and user abort)
New cwebp flag is -progress

Change-Id: Ied872cca13f512036860783bbee1bdbccad72768
2011-12-01 14:19:40 -08:00
eda520a92e cosmetics after 9523f2a
spelling, indent and other style conformance

Change-Id: Iad720c0d85f2147676e302439d57628712d3b109
2011-12-01 13:05:31 -08:00
38bd5bb524 Merge "Better alpha support in webpmux binary" 2011-12-01 06:01:33 -08:00
ccbaebfe30 Merge "Updated the includes to relative paths." 2011-12-01 04:20:46 -08:00
d71fbdcca3 fix small typo in error message array
Change-Id: If34537e53cc56b5f5daa15afaefb1f49d11602f5
2011-12-01 03:34:22 -08:00
cdf97aa265 Better alpha support in webpmux binary
- Support for adding/getting frames/tiles with alpha in webpmux
- For "-info" option in webpmux binary, add alpha related info

Change-Id: Iccd2fd35ab8453dabd74779f12f2844ab76d0538
2011-12-01 16:15:57 +05:30
885f25bc83 Updated the includes to relative paths.
Change-Id: I0ea1a59dd0f6cb1df9f41e048e0c5a13e7fb8335
2011-12-01 15:30:41 +05:30
a0ec9aace9 Update WebP encoder (cwebp) to support Alpha.
Updated cwebp (Webp Encoder) binary to support Alpha encoding.
Modified man page and WebP container spec appropriately.

Change-Id: I52f6a5cb3e870c386591e9a7776293fa6a8fb04b
2011-12-01 15:13:17 +05:30
667b769aee Fixed the include for types.h within mux.h
Made the include (for types.h) to relative path w.r.t mux.h

Change-Id: Ifb2a36557d7c8b63490738a2cc48e03993d24639
2011-12-01 13:47:32 +05:30
9523f2a5de Add Alpha Encode support from WebPEncode.
Extend WebP Encode functionality to encode Alpha data and produce
bit-stream (RIFF+VP8X+ALPH+VP8) corresponding to WebP-Alpha.

Change-Id: I983b4cd97be94a86a8e6d03b3b9c728db851bf48
2011-12-01 12:15:58 +05:30
16612ddd30 Merge "Add Alpha Decode support from WebPDecode." 2011-11-30 22:02:03 -08:00
d117a94046 Add Alpha Decode support from WebPDecode.
Extend WebP decode functionality to extract Alpha data (support ALPH
chunk) and decode the Alpha plane using Alpha (utils/alpha) core-lib.

Change-Id: I6f0ee1b189c13caba3c1dd9b681383bfd00aa212
2011-12-01 11:24:50 +05:30
67228734dc cosmetics after e1947a9
indent / spelling / line length & a couple missing consts

Change-Id: Id282cb7bc6881d4738a3d9fa912b5b22a007c4d2
2011-11-30 18:51:20 -08:00
e1947a9299 Add Alpha encode/decode code.
Add code for Alpha encoding & decoding. The alpha compression is done
via backward reference counts encoded with Arithmetic encoder (TCoder).
Also provided is lossy Alpha pre-processing option via level-quantizations
using kNN heuristic.

Change-Id: Ib6b13530c1a4ab6493edcb586ad29fe242bc1766
2011-11-30 17:53:09 +05:30
afc4c5d695 simplify code by introducing a CopyPlane() helper func
Change-Id: Id1a2a5d8a3bf48cf614213442c1386a77c0d6880
2011-11-23 18:00:39 -08:00
113b312881 Merge "MUX API Updates" 2011-11-23 05:58:02 -08:00
c398f59536 MUX API Updates
- Add alpha support in mux.
- Remove WebPMuxAddNamedData() and WebPMuxGetNamedData() APIs. Add WebPMuxSetImage(), WebPmuxGetImage() and WebPMuxDeleteImage() APIs instead.
- Refactor code using WebPImage struct.
- Corresponding changes in webpmux binary.
- WebPMuxSetImage()/AddFrame()/AddTile() can now work with data which starts from "RIFF...". This simplifies reading a single-image webp file and adding it as an image/frame/tile in mux.

Change-Id: I7d98a6407dfe55c84a682ef7e46bc622f5a6f8d9
2011-11-23 19:03:13 +05:30
5acf04ef8c remove orphan source file
similar to 8962030 enc/enc_sse2.c became a part of dsp/ w/e06ac08.

Change-Id: Ia0cef3133e3f8ec5da0bd7a5172c22e86f1d41cb
2011-11-19 11:01:19 -08:00
059f03ef99 Merge "dec: validate colorspace before using as array index" 2011-11-17 10:24:59 -08:00
70a0398988 Merge "factorize some code" 2011-11-16 19:14:49 -08:00
9b243b3db0 factorize some code
Change-Id: Iac4cf0cf05888b7dd6613028dac619d8f5b0501b
2011-11-16 19:00:27 -08:00
372e2b463b Correct a bug in ReadPNG() with GRAY_ALPHA images
Change-Id: I4676160ee544ed914cc0de3f9cd140d9ee65addc
2011-11-16 18:56:23 -08:00
469d6eb974 Merge "Makefile.am: remove redundant noinst_HEADERS" 2011-11-16 18:41:55 -08:00
9fe3372f19 dec: validate colorspace before using as array index
Change-Id: I5bcf01769d58d39a5f8d50f54cf0cd83a2309602
2011-11-16 18:21:56 -08:00
8962030f52 remove orphan source file
enc/enc.c became a part of dsp/ w/e06ac08.

Change-Id: I9e99aa6eac7b28162f58f3f0dc180a68a279d136
2011-11-14 19:31:02 -08:00
ced3e3f4e0 Makefile.am: remove redundant noinst_HEADERS
When they appear in _SOURCES they won't be installed [1].

[1]: http://www.gnu.org/software/automake/manual/automake.html#Headers

Change-Id: I14fd816294682e7bd0fccefd6428e1526c9470d8
2011-11-11 16:29:32 -08:00
964387ed19 use WEBP_INLINE for inline function declarations
removes a #define inline, objectionable in certain projects

Change-Id: Iebe0ce0b25a030756304d402679ef769e5f854d1
2011-11-11 10:53:58 -08:00
90880a11b4 Merge "manpages: break long lines" 2011-11-09 19:12:32 -08:00
b5910895ed Merge "manpages: minor formatting updates" 2011-11-09 19:11:56 -08:00
4c451e4a34 Merge "Rectify the Chunk parsing logic." 2011-11-09 19:09:57 -08:00
04e84cf1f1 examples: slight cleanup
spelling/indent/condense a few lines
removal/restriction of extern "C" usage
add const where applicable

Change-Id: Idd49b3498b1d7fc391724b4cde63706022217cb0
2011-11-04 15:30:28 -07:00
099717ce92 manpages: break long lines
Change-Id: I3bea93d358e5c3b3f7dd3c91e433ab4f817d1cd8
2011-11-04 11:25:43 -07:00
1daf39bbbc manpages: minor formatting updates
escape '-'s
use consistent section names
webpmux.1:
 document -loop
 create subsections for each OPTION group

Change-Id: If41dc24d80e4a662024e82697d8d2cc4e194a35d
2011-11-04 11:20:59 -07:00
abd030b573 fix missing "(void)" in function signature
Change-Id: I7edfc36174b6d16df909594c2693e75a09e1ac13
2011-11-01 06:24:34 -07:00
f6a7d75885 remove useless test
Change-Id: I1b31842ddf719ddcc185a5d6a5032a20d5e593e2
2011-11-01 05:18:46 -07:00
f07b2138cd Rectify the Chunk parsing logic.
For odd-sized chunk-payload, there's one Byte padding at the end to make the
next chunk start at even-address. The chunk-skip logic needs to be updated to
handle such cases.

Change-Id: I8939ed07584a6195092fbe703eb0ea711fa5f153
2011-10-31 18:47:33 -07:00
b8634f7d8f webpmux: fix lib link order
fixes static link (--disable-shared)

Change-Id: Ife926179490954a1d966d2deb97dd366a9d0dacd
2011-10-28 18:11:00 -07:00
42c2e682e0 Fix missing coma (on uncompiled code)
Spotted by Jakub, Thanks!

Change-Id: Ic2509acc683690748089b831ee3d109ad2162dc2
2011-10-27 06:37:36 -07:00
d8329d41e3 Android.mk: add missing source files
Fell out of date with some of the dsp.c moves.
Fixes Issue #93.

Change-Id: I2fb4424dbb0bc31af236cef2bed5ee542622067b
2011-10-19 20:02:23 -07:00
13a54df529 Merge "More aggressive copy-edit; add TODO; validate HTML5" 2011-10-12 15:59:30 -07:00
868b96aef4 More aggressive copy-edit; add TODO; validate HTML5
Change-Id: I45e7fde3eb33067274b5d454451f1bf8785511fd
2011-10-12 15:54:02 -07:00
767afea250 configure: check for a symbol contained in libpng
rather than 'main'. this fixes mis-detection when cross compiling.

Change-Id: I9560ca4805ef9eea5bd7370aeef2dcf6ed293478
2011-10-07 19:44:03 -07:00
408b8918c1 Merge "Linewrap at 72 cols. Casual copy-edit." 2011-10-07 17:50:31 -07:00
3ae318c770 Merge "Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.)" 2011-10-07 16:07:41 -07:00
918eb2d822 Merge "Basic container doc source clean-up; fix lists and pseudocode blocks." 2011-10-07 15:15:36 -07:00
03bec9e0c0 Linewrap at 72 cols. Casual copy-edit.
Change-Id: Iebecff7eb0a64080eab456f903afacca178d9d59
2011-10-07 14:37:54 -07:00
2678d819a4 Restore (most) emphasis; add emphasis to normative
RFC 2119 terms (MUST, etc.)

Change-Id: Ia07a64dd4eadebfe9ba8a98a4eef613d1b5d614a
2011-10-07 14:31:43 -07:00
428674dad1 Basic container doc source clean-up; fix lists and pseudocode blocks.
Add some furniture (README, template).

Change-Id: Ida154a625fe7013a1a759d16f11fd7ccd867c25d
2011-10-07 14:28:18 -07:00
6a77d92835 Merge "Makefile.vc: cosmetics" 2011-10-05 12:16:24 -07:00
28c38e8c8f Merge "Makefile.vc: condense directory creation rules" 2011-10-05 12:14:06 -07:00
55be2cf878 Initial import of container spec document, from pdftotext transform.
new file:   doc/webp-container-spec.txt

Change-Id: I60b97d6f0219f0041c92b6d980cd8ebae8ae4ca5
2011-10-04 16:27:59 -07:00
a82a788ba0 Makefile.vc: cosmetics
- break long lines
- detab variable assignments
- sort object names

Change-Id: I33a210e617552a97c36ac3b1e255af4c7f2b0e35
2011-10-04 13:46:09 -07:00
c8f41ce54e Makefile.vc: condense directory creation rules
Change-Id: I39fb8278f17498998f8a9cf022a548e0735b1d11
2011-10-04 13:39:39 -07:00
2b877cd0c8 Some fixes to Makefile.vc to support the src\mux directory.
Change-Id: I5a4a3087032dc1d5f75750b2db2a3092d39f8fc0
2011-10-01 23:47:58 +02:00
3eb969b3ed Merge "Add Makefile.vc for Mux library & binary." 2011-09-30 03:55:11 -07:00
e78e971e98 Add Makefile.vc for Mux library & binary.
Add Makefile.vc for Windows platform to build Mux library and example
command line tool.

Change-Id: Ic9e2290feda0ae3e2f2fb3c5f8d46e79eada71a3
2011-09-30 16:05:33 +05:30
6aedde5891 Add manual for WebPMux tool.
This change adds manual page for the command-line tool webpmux.

Change-Id: I01aed259c9db4bc605433f528a7deff4f5292fbe
2011-09-30 14:04:54 +05:30
8a360d0a69 Merge "Added WebPMux Binary." 2011-09-30 00:43:27 -07:00
a4f32caef4 Added WebPMux Binary.
This change adds a command line tool (webpmux) which uses MUX library
for manipulating WebP Mux container. This tool can be used to create a
WebP container file and extract/strip relevant data from the container
file.

Change-Id: If17818239448a428703760747fc84f77586045e4
2011-09-30 12:46:29 +05:30
f3bf4c769f Added Mux Container Spec & README for MUX-API.
Added the Mux Container Spec (RIFF structure) for the features supported
(Color Profile, XMP Metadata, Animation & Tiling) via WebP Mux. Also
added README file with example psudo code for using the Mux API(s) and a
short description on webpmux (comand line tool, planned to be pushed out
in subsequent Git change).

Change-Id: I87c322cada89955bd758dd524a862a8cbc407541
2011-09-30 10:51:35 +05:30
9f761cfae9 Changed function signature for WebPMuxCreate
Changed function signature of method WebPMuxCreate and few other minor nits.
Header file has been re-organised to have declaration of set/get/Delete
methods for different use-cases (Metadata, ColorProfile etc) in one place
instead of declaring all Set methods together followed by Get & Delete.

Change-Id: I52f6dffd216b1c343423d55a5b45fa1b9b9c1347
2011-09-29 10:58:40 +05:30
5f31b5ec64 Merge "Add Mux library for manipulating WebP container." 2011-09-27 11:55:45 -07:00
2315785f2c Add Mux library for manipulating WebP container.
This change adds the WebP Mux library for manipulating the WebP Mux
Container. The library document and command line tool exhibiting the
usage of this libary will follow in subsequent Git change.

Change-Id: I4cba7dd12307483185ad5a68df33af6c36c154c8
2011-09-27 14:14:46 +05:30
161 changed files with 40850 additions and 7461 deletions

1
.gitattributes vendored
View File

@ -1,3 +1,4 @@
.gitattributes export-ignore
.gitignore export-ignore
.mailmap export-ignore
*.pdf -text -diff

10
.gitignore vendored
View File

@ -1,8 +1,9 @@
*.l[ao]
*.o
*.[ao]
.deps
.libs
/aclocal.m4
/ar-lib
/autom4te.cache
/compile
/config.*
@ -16,7 +17,12 @@
/stamp-h1
Makefile
Makefile.in
examples/[cd]webp
examples/[cdv]webp
examples/gif2webp
examples/webpmux
/output
/doc/output
*.idb
*.pdb
/iosbuild
/WebP.framework

View File

@ -1,2 +1,7 @@
<johann.koenig@duck.com> <johannkoenig@google.com>
Mikołaj Zalewski <mikolajz@google.com>
Pascal Massimino <pascal.massimino@gmail.com>
<pascal.massimino@gmail.com> <skal@google.com>
Vikas Arora <vikasa@google.com>
<vikasa@google.com> <vikasa@gmail.com>
<vikasa@google.com> <vikaas.arora@gmail.com>

View File

@ -1,9 +1,18 @@
Contributors:
- Charles Munger (clm at google dot com)
- Christian Duvivier (cduvivier at google dot com)
- James Zern (jzern at google dot com)
- Jan Engelhardt (jengelh at medozas dot de)
- Johann (johann dot koenig at duck dot com)
- Jyrki Alakuijala (jyrki at google dot com)
- Lou Quillio (louquillio at google dot com)
- Mans Rullgard (mans at mansr dot com)
- Martin Olsson (mnemo at minimum dot se)
- Mikołaj Zalewski (mikolajz at google dot com)
- Noel Chromium (noel at chromium dot org)
- Pascal Massimino (pascal dot massimino at gmail dot com)
- Pierre Joye (pierre dot php at gmail dot com)
- Scott LaVarnway (slavarnway at google dot com)
- Somnath Banerjee (somnath dot banerjee at gmail dot com)
- Urvang Joshi (urvang at google dot com)
- Vikas Arora (vikasa at google dot com)

View File

@ -1,47 +1,98 @@
LOCAL_PATH:= $(call my-dir)
LOCAL_PATH := $(call my-dir)
WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD
ifeq ($(APP_OPTIM),release)
WEBP_CFLAGS += -finline-functions -frename-registers -ffast-math -s \
-ffunction-sections -fdata-sections
endif
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
src/dec/alpha.c \
src/dec/dsp.c \
src/dec/frame.c \
src/dec/idec.c \
src/dec/layer.c \
src/dec/quant.c \
src/dec/tree.c \
src/dec/vp8.c \
src/dec/webp.c \
src/dec/io.c \
src/dec/buffer.c \
src/dsp/yuv.c \
src/dsp/upsampling.c \
src/dsp/cpu.c \
src/dsp/dec.c \
src/dsp/dec_neon.c \
src/dsp/enc.c \
src/enc/alpha.c \
src/enc/analysis.c \
src/enc/config.c \
src/enc/dsp.c \
src/enc/filter.c \
src/enc/frame.c \
src/enc/iterator.c \
src/enc/layer.c \
src/enc/picture.c \
src/enc/quant.c \
src/enc/syntax.c \
src/enc/tree.c \
src/enc/webpenc.c
src/utils/bit_reader.c \
src/utils/bit_writer.c \
src/utils/thread.c \
LOCAL_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD \
-finline-functions -frename-registers -ffast-math \
-s -fomit-frame-pointer -Isrc/webp
src/dec/alpha.c \
src/dec/buffer.c \
src/dec/frame.c \
src/dec/idec.c \
src/dec/io.c \
src/dec/layer.c \
src/dec/quant.c \
src/dec/tree.c \
src/dec/vp8.c \
src/dec/vp8l.c \
src/dec/webp.c \
src/dsp/cpu.c \
src/dsp/dec.c \
src/dsp/dec_sse2.c \
src/dsp/enc.c \
src/dsp/enc_sse2.c \
src/dsp/lossless.c \
src/dsp/upsampling.c \
src/dsp/upsampling_sse2.c \
src/dsp/yuv.c \
src/enc/alpha.c \
src/enc/analysis.c \
src/enc/backward_references.c \
src/enc/config.c \
src/enc/cost.c \
src/enc/filter.c \
src/enc/frame.c \
src/enc/histogram.c \
src/enc/iterator.c \
src/enc/layer.c \
src/enc/picture.c \
src/enc/quant.c \
src/enc/syntax.c \
src/enc/token.c \
src/enc/tree.c \
src/enc/vp8l.c \
src/enc/webpenc.c \
src/utils/alpha_processing.c \
src/utils/bit_reader.c \
src/utils/bit_writer.c \
src/utils/color_cache.c \
src/utils/filters.c \
src/utils/huffman.c \
src/utils/huffman_encode.c \
src/utils/quant_levels.c \
src/utils/quant_levels_dec.c \
src/utils/random.c \
src/utils/rescaler.c \
src/utils/thread.c \
src/utils/utils.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
LOCAL_MODULE:= webp
# prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
# Setting LOCAL_ARM_NEON will enable -mfpu=neon which may cause illegal
# instructions to be generated for armv7a code. Instead target the neon code
# specifically.
LOCAL_SRC_FILES += src/dsp/dec_neon.c.neon
LOCAL_SRC_FILES += src/dsp/upsampling_neon.c.neon
LOCAL_SRC_FILES += src/dsp/enc_neon.c.neon
endif
LOCAL_STATIC_LIBRARIES := cpufeatures
LOCAL_MODULE := webp
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
examples/dwebp.c \
examples/example_util.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src
LOCAL_STATIC_LIBRARIES := webp
LOCAL_MODULE := dwebp
include $(BUILD_EXECUTABLE)
$(call import-module,android/cpufeatures)

1527
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,10 @@
#
# Stem for static libs and DLLs
#
LIB_NAME = libwebp_a
LIB_NAME_DEBUG = libwebp_a_debug
#
# Stem for DLL import libs
#
IMPLIB_NAME = libwebp_dll
IMPLIB_NAME_DEBUG = libwebp_dll_debug
!IFNDEF DEP_PATH
DEPS_PATH = ../../deps
!ENDIF
LIBWEBPDECODER_BASENAME = libwebpdecoder
LIBWEBP_BASENAME = libwebp
LIBWEBPMUX_BASENAME = libwebpmux
LIBWEBPDEMUX_BASENAME = libwebpdemux
!IFNDEF ARCH
!IF ! [ cl 2>&1 | find "x86" > NUL ]
@ -32,17 +24,18 @@ PLATFORM_LDFLAGS = /SAFESEH
#############################################################
## Nothing more to do below this line!
MT = mt.exe
CCNODBG = cl.exe /nologo /O2 /DNDEBUG
CCDEBUG = cl.exe /nologo /Od /Gm /Zi /D_DEBUG /RTC1
CFLAGS = /Isrc /nologo /W3 /EHsc /FD /c /GS
NOLOGO = /nologo
CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG
CCDEBUG = cl.exe $(NOLOGO) /Od /Gm /Zi /D_DEBUG /RTC1
CFLAGS = /Isrc $(NOLOGO) /W3 /EHsc /c /GS
CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
CFLAGS = $(CFLAGS) /DHAVE_WINCODEC_H /DWEBP_USE_THREAD
LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE $(PLATFORM_LDFLAGS)
LNKDLL = link.exe /DLL
LNKLIB = link.exe /lib
LNKEXE = link.exe
LFLAGS = /nologo /machine:$(ARCH)
LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE
LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS)
LNKDLL = link.exe /DLL $(NOLOGO)
LNKEXE = link.exe $(NOLOGO)
LNKLIB = lib.exe $(NOLOGO)
MT = mt.exe $(NOLOGO)
CFGSET = FALSE
!IF "$(OBJDIR)" == ""
@ -65,36 +58,58 @@ DIROBJ = $(DIRBASE)\obj
DIRLIB = $(DIRBASE)\lib
DIRINC = $(DIRBASE)\include
DIRBIN = $(DIRBASE)\bin
LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME).pdb
OUTPUT_DIRS = $(DIRBIN) $(DIRINC) $(DIRLIB) \
$(DIROBJ)\dec \
$(DIROBJ)\demux \
$(DIROBJ)\dsp \
$(DIROBJ)\enc \
$(DIROBJ)\examples \
$(DIROBJ)\mux \
$(DIROBJ)\utils \
# Target configuration
!IF "$(CFG)" == "release-static"
TARGET = $(LIB_NAME).lib
CC = $(CCNODBG)
STATICLIBBUILD = TRUE
!ELSE IF "$(CFG)" == "debug-static"
TARGET = $(LIB_NAME_DEBUG).lib
CC = $(CCDEBUG)
RTLIB = $(RTLIBD)
STATICLIBBUILD = TRUE
LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
!ELSE IF "$(CFG)" == "release-dynamic"
TARGETDLL = $(LIB_NAME).dll
TARGET = $(IMPLIB_NAME).lib
CC = $(CCNODBG)
DLLBUILD = TRUE
!ELSE IF "$(CFG)" == "debug-dynamic"
TARGETDLL = $(LIB_NAME_DEBUG).dll
TARGET = $(IMPLIB_NAME_DEBUG).lib
CC = $(CCDEBUG)
RTLIB = $(RTLIBD)
DLLBUILD = TRUE
LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
!ENDIF
!IF "$(STATICLIBBUILD)" == "TRUE"
CC = $(CC) $(RTLIB)
LNK = $(LNKLIB) /out:$(DIRLIB)\$(TARGET)
CFGSET = TRUE
LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME).lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib
!ELSE IF "$(DLLBUILD)" == "TRUE"
DLLC = webp_dll.c
DLLINC = webp_dll.h
DLL_OBJS = $(DIROBJ)\$(DLLC:.c=.obj)
CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL
LNK = $(LNKDLL) /out:$(DIRBIN)\$(TARGETDLL) /implib:$(DIRLIB)\$(TARGET)
LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME)_dll.lib
LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb
CFGSET = TRUE
!ENDIF
@ -102,21 +117,25 @@ CFGSET = TRUE
# Usage
#
!IF "$(CFGSET)" == "FALSE"
!MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>] [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [<target>]
!MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>]
!MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [<target>]
!MESSAGE
!MESSAGE where <config> is one of:
!MESSAGE - release-static - release static library
!MESSAGE - debug-static - debug static library
!MESSAGE - release-dynamic - release dynamic link library (DLL)
!MESSAGE - debug-dynamic - debug dynamic link library (DLL)
!MESSAGE
!MESSAGE <target> may be:
!MESSAGE - clean - perform a clean for CFG
!MESSAGE - experimental - build CFG with experimental
!MESSAGE . features enabled. Requires zlib.
!MESSAGE . features enabled.
!MESSAGE - (empty) - build libwebp-based targets for CFG
!MESSAGE - all - build (de)mux-based targets for CFG
!MESSAGE
!MESSAGE <rtlibcfg> controls the runtime library linkage - can be 'static' or 'dynamic'.
!MESSAGE <target> can be left blank in which case all is assumed
!MESSAGE <path> is the path where you like to build (obj, bins, etc.)
!MESSAGE default to ..\obj\
!MESSAGE RTLIBCFG controls the runtime library linkage - 'static' or 'dynamic'.
!MESSAGE OBJDIR is the path where you like to build (obj, bins, etc.),
!MESSAGE defaults to ..\obj
!IF "$(CFG)" != ""
!MESSAGE
@ -131,94 +150,146 @@ CFGSET = TRUE
# A config was provided, so the library can be built.
#
X_OBJS= \
$(DIROBJ)\dec\frame.obj \
$(DIROBJ)\dec\quant.obj \
$(DIROBJ)\dec\tree.obj \
$(DIROBJ)\dec\vp8.obj \
$(DIROBJ)\dec\webp.obj \
$(DIROBJ)\dec\io.obj \
$(DIROBJ)\dec\buffer.obj \
$(DIROBJ)\dec\idec.obj \
$(DIROBJ)\dec\alpha.obj \
$(DIROBJ)\dec\layer.obj \
$(DIROBJ)\enc\analysis.obj \
$(DIROBJ)\enc\config.obj \
$(DIROBJ)\enc\cost.obj \
$(DIROBJ)\enc\frame.obj \
$(DIROBJ)\enc\filter.obj \
$(DIROBJ)\enc\iterator.obj \
$(DIROBJ)\enc\picture.obj \
$(DIROBJ)\enc\quant.obj \
$(DIROBJ)\enc\syntax.obj \
$(DIROBJ)\enc\tree.obj \
$(DIROBJ)\enc\webpenc.obj \
$(DIROBJ)\enc\alpha.obj \
$(DIROBJ)\enc\layer.obj \
$(DIROBJ)\dsp\enc.obj \
$(DIROBJ)\dsp\enc_sse2.obj \
$(DIROBJ)\dsp\upsampling.obj \
$(DIROBJ)\dsp\upsampling_sse2.obj \
$(DIROBJ)\dsp\dec.obj \
$(DIROBJ)\dsp\dec_sse2.obj \
$(DIROBJ)\dsp\cpu.obj \
$(DIROBJ)\dsp\yuv.obj \
$(DIROBJ)\utils\bit_reader.obj \
$(DIROBJ)\utils\bit_writer.obj \
$(DIROBJ)\utils\thread.obj \
$(RESOURCE)
DEC_OBJS = \
$(DIROBJ)\dec\alpha.obj \
$(DIROBJ)\dec\buffer.obj \
$(DIROBJ)\dec\frame.obj \
$(DIROBJ)\dec\idec.obj \
$(DIROBJ)\dec\io.obj \
$(DIROBJ)\dec\layer.obj \
$(DIROBJ)\dec\quant.obj \
$(DIROBJ)\dec\tree.obj \
$(DIROBJ)\dec\vp8.obj \
$(DIROBJ)\dec\vp8l.obj \
$(DIROBJ)\dec\webp.obj \
EXAMPLES_OBJS = \
$(DIROBJ)\examples\cwebp.obj \
$(DIROBJ)\examples\dwebp.obj
DEMUX_OBJS = \
$(DIROBJ)\demux\demux.obj \
all: $(DIRLIB)\$(TARGET) $(DIRBIN)\dwebp.exe $(DIRBIN)\cwebp.exe
DSP_DEC_OBJS = \
$(DIROBJ)\dsp\cpu.obj \
$(DIROBJ)\dsp\dec.obj \
$(DIROBJ)\dsp\dec_neon.obj \
$(DIROBJ)\dsp\dec_sse2.obj \
$(DIROBJ)\dsp\lossless.obj \
$(DIROBJ)\dsp\upsampling.obj \
$(DIROBJ)\dsp\upsampling_neon.obj \
$(DIROBJ)\dsp\upsampling_sse2.obj \
$(DIROBJ)\dsp\yuv.obj \
DSP_ENC_OBJS = \
$(DIROBJ)\dsp\enc.obj \
$(DIROBJ)\dsp\enc_neon.obj \
$(DIROBJ)\dsp\enc_sse2.obj \
EX_FORMAT_DEC_OBJS = \
$(DIROBJ)\examples\jpegdec.obj \
$(DIROBJ)\examples\metadata.obj \
$(DIROBJ)\examples\pngdec.obj \
$(DIROBJ)\examples\tiffdec.obj \
$(DIROBJ)\examples\wicdec.obj \
EX_UTIL_OBJS = \
$(DIROBJ)\examples\example_util.obj \
ENC_OBJS = \
$(DIROBJ)\enc\alpha.obj \
$(DIROBJ)\enc\analysis.obj \
$(DIROBJ)\enc\backward_references.obj \
$(DIROBJ)\enc\config.obj \
$(DIROBJ)\enc\cost.obj \
$(DIROBJ)\enc\filter.obj \
$(DIROBJ)\enc\frame.obj \
$(DIROBJ)\enc\histogram.obj \
$(DIROBJ)\enc\iterator.obj \
$(DIROBJ)\enc\layer.obj \
$(DIROBJ)\enc\picture.obj \
$(DIROBJ)\enc\quant.obj \
$(DIROBJ)\enc\syntax.obj \
$(DIROBJ)\enc\token.obj \
$(DIROBJ)\enc\tree.obj \
$(DIROBJ)\enc\vp8l.obj \
$(DIROBJ)\enc\webpenc.obj \
MUX_OBJS = \
$(DIROBJ)\mux\muxedit.obj \
$(DIROBJ)\mux\muxinternal.obj \
$(DIROBJ)\mux\muxread.obj \
UTILS_DEC_OBJS = \
$(DIROBJ)\utils\alpha_processing.obj \
$(DIROBJ)\utils\bit_reader.obj \
$(DIROBJ)\utils\color_cache.obj \
$(DIROBJ)\utils\filters.obj \
$(DIROBJ)\utils\huffman.obj \
$(DIROBJ)\utils\quant_levels_dec.obj \
$(DIROBJ)\utils\rescaler.obj \
$(DIROBJ)\utils\random.obj \
$(DIROBJ)\utils\thread.obj \
$(DIROBJ)\utils\utils.obj \
UTILS_ENC_OBJS = \
$(DIROBJ)\utils\bit_writer.obj \
$(DIROBJ)\utils\huffman_encode.obj \
$(DIROBJ)\utils\quant_levels.obj \
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
$(UTILS_ENC_OBJS) $(DLL_OBJS)
LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS)
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS)
OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP)
OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe
EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe
ex: $(OUT_LIBS) $(OUT_EXAMPLES)
all: ex $(EXTRA_EXAMPLES)
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(EX_FORMAT_DEC_OBJS)
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj
$(DIRBIN)\vwebp.exe: $(EX_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX)
$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(LIBWEBP)
$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP)
$(EX_UTIL_OBJS) $(EX_FORMAT_DEC_OBJS): $(OUTPUT_DIRS)
# Additional include and library paths (for zlib) can be passed via the CL and
# LINK environment variables respectively:
# > set CL=/I\zlib\include
# > set LINK=\zlib\zlib.lib
# > nmake /f Makefile.vc CFG=release-static experimental
experimental:
$(MAKE) /f Makefile.vc \
CFG=$(CFG) CFLAGS="$(CFLAGS) /DWEBP_EXPERIMENTAL_FEATURES" /$(MAKEFLAGS)
CFG=$(CFG) \
CFLAGS="$(CFLAGS) /DWEBP_EXPERIMENTAL_FEATURES" /$(MAKEFLAGS)
$(DIRLIB)\$(TARGET): $(X_OBJS)
$(LNK) $(LFLAGS) $(X_OBJS)
$(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS)
$(LIBWEBP): $(LIBWEBP_OBJS)
$(LIBWEBPMUX): $(LIBWEBPMUX_OBJS)
$(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS)
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(OUTPUT_DIRS)
!IF "$(DLLBUILD)" == "TRUE"
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
$(DIROBJ)\$(DLLINC) $(DIROBJ)\$(DLLC)
{$(DIROBJ)}.c{$(DIROBJ)}.obj:
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
$(LIBWEBPMUX): $(LIBWEBP)
$(LIBWEBPDEMUX): $(LIBWEBP)
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
$(X_OBJS): $(DIROBJ)\enc $(DIROBJ)\dec $(DIROBJ)\dsp $(DIROBJ)\utils $(DIRLIB) $(DIRINC) $(DIRBIN)
!IF "$(DLLBUILD)" == "TRUE"
$(X_OBJS): $(DIROBJ)\$(DLLINC)
clean::
@-erase /s $(DIROBJ)\$(DLLINC) 2> NUL
@-erase /s $(DIROBJ)\$(DLLC) $(DIROBJ)\$(DLLINC) 2> NUL
!ELSE
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LNKLIB) /out:$@ $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
!ENDIF
$(EXAMPLES_OBJS): $(DIROBJ)\examples $(DIRLIB)\$(TARGET)
$(DIROBJ)\enc:
@if not exist "$(DIROBJ)\enc" mkdir $(DIROBJ)\enc
$(DIROBJ)\examples:
@if not exist "$(DIROBJ)\examples" mkdir $(DIROBJ)\examples
$(DIROBJ)\dec:
@if not exist "$(DIROBJ)\dec" mkdir $(DIROBJ)\dec
$(DIROBJ)\dsp:
@if not exist "$(DIROBJ)\dsp" mkdir $(DIROBJ)\dsp
$(DIROBJ)\utils:
@if not exist "$(DIROBJ)\utils" mkdir $(DIROBJ)\utils
$(DIRLIB):
@if not exist "$(DIRLIB)" mkdir $(DIRLIB)
$(DIRINC):
@if not exist "$(DIRINC)" mkdir $(DIRINC)
$(DIRBIN):
@if not exist "$(DIRBIN)" mkdir $(DIRBIN)
$(OUTPUT_DIRS):
@if not exist "$(@)" mkdir "$(@)"
# generate a helper include to define WEBP_EXTERN suitable for the DLL build
$(DIROBJ)\$(DLLINC):
@ -227,20 +298,35 @@ $(DIROBJ)\$(DLLINC):
@echo #define WEBP_EXTERN(type) __declspec(dllexport) type >> $@
@echo #endif /* WEBP_DLL_H_ */ >> $@
# expose a WebPFree() function for use in managed code
$(DIROBJ)\$(DLLC): $(DIROBJ)\$(DLLINC)
@echo #include ^<stdlib.h^> > $@
@echo #include "webp_dll.h" >> $@
@echo // This function should be used in place of free() for memory >> $@
@echo // returned by the WebP API. >> $@
@echo WEBP_EXTERN(void) WebPFree(void* ptr) { >> $@
@echo free(ptr); >> $@
@echo } >> $@
.SUFFIXES: .c .obj .res .exe
{examples}.c{$(DIROBJ)\examples}.obj:
$(CC) $(CFLAGS) /Fo"$@" $<
{src\dec}.c{$(DIROBJ)\dec}.obj:
$(CC) $(CFLAGS) /Fo"$@" $<
{src\enc}.c{$(DIROBJ)\enc}.obj:
$(CC) $(CFLAGS) /Fo"$@" $<
{src\dsp}.c{$(DIROBJ)\dsp}.obj:
$(CC) $(CFLAGS) /Fo"$@" $<
{src\utils}.c{$(DIROBJ)\utils}.obj:
$(CC) $(CFLAGS) /Fo"$@" $<
{examples}.c{$(DIROBJ)\examples}.obj::
$(CC) $(CFLAGS) /Fd$(DIROBJ)\examples\ /Fo$(DIROBJ)\examples\ $<
{src\dec}.c{$(DIROBJ)\dec}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $<
{src\demux}.c{$(DIROBJ)\demux}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\demux\ $<
{src\dsp}.c{$(DIROBJ)\dsp}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dsp\ $<
{src\enc}.c{$(DIROBJ)\enc}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\enc\ $<
{src\mux}.c{$(DIROBJ)\mux}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\mux\ $<
{src\utils}.c{$(DIROBJ)\utils}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $<
{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
$(LNKEXE) $(LDFLAGS) /OUT:"$@" $< ole32.lib windowscodecs.lib shlwapi.lib $(DIRLIB)\$(TARGET)
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
ole32.lib windowscodecs.lib shlwapi.lib
$(MT) -manifest $@.manifest -outputresource:$@;1
del $@.manifest

62
NEWS
View File

@ -1,3 +1,65 @@
- 12/19/13: version 0.4.0
* improved gif2webp tool
* numerous fixes, compression improvement and speed-up
* dither option added to decoder (dwebp -dither 50 ...)
* improved multi-threaded modes (-mt option)
* improved filtering strength determination
* New function: WebPMuxGetCanvasSize
* BMP and TIFF format output added to 'dwebp'
* Significant memory reduction for decoding lossy images with alpha.
* Intertwined decoding of RGB and alpha for a shorter
time-to-first-decoded-pixel.
* WebPIterator has a new member 'has_alpha' denoting whether the frame
contains transparency.
* Container spec amended with new 'blending method' for animation.
- 6/13/13: version 0.3.1
This is a binary compatible release.
* Add incremental decoding support for images containing ALPH and ICCP chunks.
* Python bindings via swig for the simple encode/decode interfaces similar to
Java.
- 3/20/13: version 0.3.0
This is a binary compatible release.
* WebPINewRGB/WebPINewYUVA accept being passed a NULL output buffer
and will perform auto-allocation.
* default filter option is now '-strong -f 60'
* encoding speed-up for lossy methods 3 to 6
* alpha encoding can be done in parallel to lossy using 'cwebp -mt ...'
* color profile, metadata (XMP/EXIF) and animation support finalized in the
container.
* various NEON assembly additions
Tool updates / additions:
* gif2webp added
* vwebp given color profile & animation support
* cwebp can preserve color profile / metadata with '-metadata'
- 10/30/12: version 0.2.1
* Various security related fixes
* cwebp.exe: fix import errors on Windows XP
* enable DLL builds for mingw targets
- 8/3/12: version 0.2.0
* Add support for ARGB -> YUVA conversion for lossless decoder
New functions: WebPINewYUVA, WebPIDecGetYUVA
* Add stats for lossless and alpha encoding
* Security related hardening: allocation and size checks
* Add PAM output support to dwebp
- 7/19/12: version 0.1.99
* This is a pre-release of 0.2.0, not an rc to allow for further
incompatible changes based on user feedback.
* Alpha channel encode/decode support.
* Lossless encoder/decoder.
* Add TIFF input support to cwebp.
Incompatible changes:
* The encode ABI has been modified to support alpha encoding.
* Deprecated function WebPINew() has been removed.
* Decode function signatures have changed to consistently use size_t over
int/uint32_t.
* decode_vp8.h is no longer installed system-wide.
* cwebp will encode the alpha channel if present.
- 9/19/11: version 0.1.3
* Advanced decoding APIs.
* On-the-fly cropping and rescaling of images.

252
README
View File

@ -4,7 +4,7 @@
\__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v0.1.3
\____/____/\_____/_____/____/v0.4.0
Description:
============
@ -13,7 +13,7 @@ WebP codec: library to encode and decode images in WebP format. This package
contains the library that can be used in other programs to add WebP support,
as well as the command line tools 'cwebp' and 'dwebp'.
See http://code.google.com/speed/webp
See http://developers.google.com/speed/webp
Latest sources are available from http://www.webmproject.org/code/
@ -49,11 +49,13 @@ will build the binaries examples/cwebp and examples/dwebp, along
with the static library src/libwebp.a. No system-wide installation
is supplied, as this is a simple alternative to the full installation
system based on the autoconf tools (see below).
Please refer the makefile.unix for additional details and customizations.
Please refer to makefile.unix for additional details and customizations.
Using autoconf tools:
---------------------
./autogen.sh
When building from git sources, you will need to run autogen.sh to generate the
configure script.
./configure
make
make install
@ -61,7 +63,6 @@ make install
should be all you need to have the following files
/usr/local/include/webp/decode.h
/usr/local/include/webp/decode_vp8.h
/usr/local/include/webp/encode.h
/usr/local/include/webp/types.h
/usr/local/lib/libwebp.*
@ -70,32 +71,40 @@ should be all you need to have the following files
installed.
Note: The encoding and decoding libraries are compiled separately
(as src/dec/libwebpdecode.* and src/dec/libwebpencode.*). They
can be installed independently using a minor modification in the
corresponding Makefile.am configure files (see comments there).
Note: A decode-only library, libwebpdecoder, is available using the
'--enable-libwebpdecoder' flag. The encode library is built separately and can
be installed independently using a minor modification in the corresponding
Makefile.am configure files (see comments there). See './configure --help' for
more options.
SWIG bindings:
--------------
To generate language bindings from swig/libwebp.i swig-1.3
(http://www.swig.org) is required. 2.0 may work, but has not been tested.
To generate language bindings from swig/libwebp.swig at least swig-1.3
(http://www.swig.org) is required.
Currently the following functions are mapped:
Decode:
WebPGetDecoderVersion
WebPGetInfo
WebPDecodeRGB
WebPDecodeRGBA
WebPDecodeARGB
WebPDecodeBGR
WebPDecodeBGRA
WebPDecodeBGR
WebPDecodeRGB
Encode:
WebPGetEncoderVersion
WebPEncodeRGB
WebPEncodeRGBA
WebPEncodeBGR
WebPEncodeBGRA
WebPEncodeRGB
WebPEncodeBGR
WebPEncodeLosslessRGBA
WebPEncodeLosslessBGRA
WebPEncodeLosslessRGB
WebPEncodeLosslessBGR
See swig/README for more detailed build instructions.
Java bindings:
@ -103,6 +112,12 @@ To build the swig-generated JNI wrapper code at least JDK-1.5 (or equivalent)
is necessary for enum support. The output is intended to be a shared object /
DLL that can be loaded via System.loadLibrary("webp_jni").
Python bindings:
To build the swig-generated Python extension code at least Python 2.6 is
required. Python < 2.6 may build with some minor changes to libwebp.swig or the
generated code, but is untested.
Encoding tool:
==============
@ -111,9 +126,13 @@ decoding (dwebp) images.
The easiest use should look like:
cwebp input.png -q 80 -o output.webp
which will convert the input PNG or JPEG file to a WebP file using a
quality factor of 80 on a 0->100 scale (0 being the lowest quality,
100 being the best. Default value is 75).
which will convert the input file to a WebP file using a quality factor of 80
on a 0->100 scale (0 being the lowest quality, 100 being the best. Default
value is 75).
You might want to try the -lossless flag too, which will compress the source
(in RGBA format) without any loss. The -q quality parameter will in this case
control the amount of processing time spent trying to make the output file as
small as possible.
A longer list of options is available using the -longhelp command line flag:
@ -121,45 +140,67 @@ A longer list of options is available using the -longhelp command line flag:
Usage:
cwebp [-preset <...>] [options] in_file [-o out_file]
If input size (-s) for an image is not specified, it is assumed to be a either
PNG or JPEG format file.
If input size (-s) for an image is not specified, it is assumed to be a PNG,
JPEG or TIFF 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).
-preset <string> ....... Preset setting, one of:
default, photo, picture,
drawing, icon, text
-preset must come first, as it overwrites other parameters.
-m <int> ............... compression method (0=fast, 6=slowest)
-segments <int> ........ number of segments to use (1..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)
-strong ................ use strong filter instead of simple.
-strong ................ use strong filter instead of simple (default).
-nostrong .............. use simple filter instead of strong.
-partition_limit <int> . limit quality to fit the 512k limit on
the first partition (0=no degradation ... 100=full)
-alpha_comp <int> ...... set the transparency-compression
-noalpha ............... discard any transparency information.
-pass <int> ............ analysis pass number (1..10)
-partitions <int> ...... number of partitions to use (0..3)
-crop <x> <y> <w> <h> .. crop picture with the given rectangle
-resize <w> <h> ........ resize picture (after any cropping)
-mt .................... use multi-threading if available
-low_memory ............ reduce memory usage (slower encoding)
-map <int> ............. print map of extra info.
-print_psnr ............ prints averaged PSNR distortion.
-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_filter <string> . predictive filtering for alpha plane.
One of: none, fast (default) or best.
-alpha_cleanup ......... Clean RGB values in transparent area.
-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.
-hint <string> ......... Specify image characteristics hint.
One of: photo, picture or graph
-metadata <string> ..... comma separated list of metadata to
copy from the input to the output if present.
Valid values: all, none (default), exif, icc, xmp
-short ................. condense printed message
-quiet ................. don't print anything.
-version ............... print version number and exit.
-noasm ................. disable all assembly optimizations.
-v ..................... verbose, e.g. print encoding/decoding times
-progress .............. report encoding progress
Experimental Options:
-size <int> ............ Target size (in bytes)
-psnr <float> .......... Target PSNR (in dB. typically: 42)
-af <int> .............. adjust filter strength (0=off, 1=on)
-jpeg_like ............. Roughly match expected JPEG size.
-af .................... auto-adjust filter strength.
-pre <int> ............. pre-processing filter
@ -183,10 +224,11 @@ Namely:
but with better quality.
Typical value is around '75'.
* 'f' option directly links to the filtering strength used by the codec's
in-loop processing. The higher, the smoother will highly-compressed area
look. This is particularly useful when aiming at very small files.
Typical values are around 20-30. Note that using the option -strong will
change the type of filtering. Use "-f 0" to turn filtering off.
in-loop processing. The higher the value, the smoother the
highly-compressed area will look. This is particularly useful when aiming
at very small files. Typical values are around 20-30. Note that using the
option -strong/-nostrong will change the type of filtering. Use "-f 0" to
turn filtering off.
* 'm' controls the trade-off between encoding speed and quality. Default is 4.
You can try -m 5 or -m 6 to explore more (time-consuming) encoding
possibilities. A lower value will result in faster encoding at the expense
@ -211,20 +253,118 @@ Usage: dwebp in_file [options] [-o out_file]
Decodes the WebP image file to PNG format [Default]
Use following options to convert into alternate image formats:
-ppm ......... save the raw RGB samples as color PPM
-pam ......... save the raw RGBA samples as a color PAM
-ppm ......... save the raw RGB samples as a color PPM
-bmp ......... save as uncompressed BMP format
-tiff ........ save as uncompressed TIFF format
-pgm ......... save the raw YUV samples as a grayscale PGM
file with IMC4 layout.
file with IMC4 layout
-yuv ......... save the raw YUV samples in flat layout
Other options are:
-version .... print version number and exit.
-nofancy ..... don't use the fancy YUV420 upscaler.
-nofilter .... disable in-loop filtering.
-nodither .... disable dithering.
-dither <d> .. dithering strength (in 0..100)
-mt .......... use multi-threading
-crop <x> <y> <w> <h> ... crop output with the given rectangle
-scale <w> <h> .......... scale the output (*after* any cropping)
-alpha ....... only save the alpha plane.
-incremental . use incremental decoding (useful for tests)
-h ....... this help message.
-v ....... verbose (e.g. print encoding/decoding times)
-noasm ....... disable all assembly optimizations.
Visualization tool:
===================
There's a little self-serve visualization tool called 'vwebp' under the
examples/ directory. It uses OpenGL to open a simple drawing window and show
a decoded WebP file. It's not yet integrated in the automake build system, but
you can try to manually compile it using the recommendations below.
Usage: vwebp in_file [options]
Decodes the WebP image file and visualize it using OpenGL
Options are:
-version .... print version number and exit.
-noicc ....... don't use the icc profile if present.
-nofancy ..... don't use the fancy YUV420 upscaler.
-nofilter .... disable in-loop filtering.
-dither <int> dithering strength (0..100). Default=50.
-mt .......... use multi-threading.
-info ........ print info.
-h ....... this help message.
Keyboard shortcuts:
'c' ................ toggle use of color profile.
'i' ................ overlay file information.
'q' / 'Q' / ESC .... quit.
Building:
---------
Prerequisites:
1) OpenGL & OpenGL Utility Toolkit (GLUT)
Linux:
$ sudo apt-get install freeglut3-dev mesa-common-dev
Mac + XCode:
- These libraries should be available in the OpenGL / GLUT frameworks.
Windows:
http://freeglut.sourceforge.net/index.php#download
2) (Optional) qcms (Quick Color Management System)
i. Download qcms from Mozilla / Chromium:
http://hg.mozilla.org/mozilla-central/file/0e7639e3bdfb/gfx/qcms
http://src.chromium.org/viewvc/chrome/trunk/src/third_party/qcms
ii. Build and archive the source files as libqcms.a / qcms.lib
iii. Update makefile.unix / Makefile.vc
a) Define WEBP_HAVE_QCMS
b) Update include / library paths to reference the qcms directory.
Build using makefile.unix / Makefile.vc:
$ make -f makefile.unix examples/vwebp
> nmake /f Makefile.vc CFG=release-static \
../obj/x64/release-static/bin/vwebp.exe
Animated GIF conversion:
========================
Animated GIF files can be converted to WebP files with animation using the
gif2webp utility available under examples/. The files can then be viewed using
vwebp.
Usage:
gif2webp [options] gif_file -o webp_file
options:
-h / -help ............ this help
-lossy ................. Encode image using lossy compression.
-mixed ................. For each frame in the image, pick lossy
or lossless compression heuristically.
-q <float> ............. quality factor (0:small..100:big)
-m <int> ............... compression method (0=fast, 6=slowest)
-kmin <int> ............ Min distance between key frames
-kmax <int> ............ Max distance between key frames
-f <int> ............... filter strength (0=off..100)
-metadata <string> ..... comma separated list of metadata to
copy from the input to the output if present.
Valid values: all, none, icc, xmp (default)
-mt .................... use multi-threading if available
-version ............... print version number and exit.
-v ..................... verbose.
-quiet ................. don't print anything.
Building:
---------
With the libgif development files installed, gif2webp can be built using
makefile.unix:
$ make -f makefile.unix examples/gif2webp
or using autoconf:
$ ./configure --enable-everything
$ make
Encoding API:
=============
@ -242,6 +382,20 @@ size_t WebPEncodeBGRA(const uint8_t* bgra, int width, int height, int stride,
They will convert raw RGB samples to a WebP data. The only control supplied
is the quality factor.
There are some variants for using the lossless format:
size_t WebPEncodeLosslessRGB(const uint8_t* rgb, int width, int height,
int stride, uint8_t** output);
size_t WebPEncodeLosslessBGR(const uint8_t* bgr, int width, int height,
int stride, uint8_t** output);
size_t WebPEncodeLosslessRGBA(const uint8_t* rgba, int width, int height,
int stride, uint8_t** output);
size_t WebPEncodeLosslessBGRA(const uint8_t* bgra, int width, int height,
int stride, uint8_t** output);
Of course in this case, no quality factor is needed since the compression
occurs without loss of the input values, at the expense of larger output sizes.
Advanced encoding API:
----------------------
@ -306,21 +460,19 @@ Decoding API:
This is mainly just one function to call:
#include "webp/decode.h"
uint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size,
int *width, int *height);
uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
int* width, int* height);
Please have a look at the file src/webp/decode.h for the details.
There are variants for decoding in BGR/RGBA/ARGB/BGRA order, along with
decoding to raw Y'CbCr samples. One can also decode the image directly into a
pre-allocated buffer.
To detect a WebP file and gather picture's dimensions, the function:
int WebPGetInfo(const uint8_t* data, uint32_t data_size,
int *width, int *height);
To detect a WebP file and gather the picture's dimensions, the function:
int WebPGetInfo(const uint8_t* data, size_t data_size,
int* width, int* height);
is supplied. No decoding is involved when using it.
A lower-level API is available from the header file <webp/decode_vp8.h>
Incremental decoding API:
=========================
@ -330,7 +482,11 @@ is stored into an instance of the WebPIDecoder object. This object can be
created with the purpose of decoding either RGB or Y'CbCr samples.
For instance:
WebPIDecoder* idec = WebPINew(MODE_BGR);
WebPDecBuffer buffer;
WebPInitDecBuffer(&buffer);
buffer.colorspace = MODE_BGR;
...
WebPIDecoder* idec = WebPINewDecoder(&buffer);
As data is made progressively available, this incremental-decoder object
can be used to decode the picture further. There are two (mutually exclusive)
@ -344,23 +500,23 @@ or by just mentioning the new size of the transmitted data:
WebPIUpdate(idec, buffer, size_of_transmitted_buffer);
Note that 'buffer' can be modified between each calls to WebPIUpdate, in
Note that 'buffer' can be modified between each call to WebPIUpdate, in
particular when the buffer is resized to accommodate larger data.
These functions will return the decoding status: either VP8_STATUS_SUSPENDED if
decoding is not finished yet, or VP8_STATUS_OK when decoding is done.
Any other status is an error condition.
decoding is not finished yet or VP8_STATUS_OK when decoding is done. Any other
status is an error condition.
The idec object must always be released (even upon an error condition)
by calling: WebPDelete(idec).
The 'idec' object must always be released (even upon an error condition) by
calling: WebPDelete(idec).
To retrieve partially decoded picture samples, one must use the corresponding
method: WebPIDecGetRGB or WebPIDecGetYUV.
method: WebPIDecGetRGB or WebPIDecGetYUVA.
It will return the last displayable pixel row.
Lastly, note that decoding can also be performed into a pre-allocated pixel
buffer. This buffer must be passed when creating a WebPIDecoder, calling
WebPINewRGB() or WebPINewYUV().
WebPINewRGB() or WebPINewYUVA().
Please have a look at the src/webp/decode.h header for further details.

186
README.mux Normal file
View File

@ -0,0 +1,186 @@
 __ __ ____ ____ ____ __ __ _ __ __
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
\ / __/ _ \ __/ / / (_/ /__
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.2.0
Description:
============
WebPMux: set of two libraries 'Mux' and 'Demux' for creation, extraction and
manipulation of an extended format WebP file, which can have features like
color profile, metadata and animation. Reference command-line tools 'webpmux'
and 'vwebp' as well as the WebP container specification
'doc/webp-container-spec.txt' are also provided in this package.
WebP Mux tool:
==============
The examples/ directory contains a tool (webpmux) for manipulating WebP
files. The webpmux tool can be used to create an extended format WebP file and
also to extract or strip relevant data from such a file.
A list of options is available using the -help command line flag:
> webpmux -help
Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
webpmux -set SET_OPTIONS INPUT -o OUTPUT
webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT
webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]
[-bgcolor BACKGROUND_COLOR] -o OUTPUT
webpmux -info INPUT
webpmux [-h|-help]
webpmux -version
GET_OPTIONS:
Extract relevant data.
icc Get ICC profile.
exif Get EXIF metadata.
xmp Get XMP metadata.
frame n Get nth frame.
SET_OPTIONS:
Set color profile/metadata.
icc file.icc Set ICC profile.
exif file.exif Set EXIF metadata.
xmp file.xmp Set XMP metadata.
where: 'file.icc' contains the ICC profile to be set,
'file.exif' contains the EXIF metadata to be set
'file.xmp' contains the XMP metadata to be set
STRIP_OPTIONS:
Strip color profile/metadata.
icc Strip ICC profile.
exif Strip EXIF metadata.
xmp Strip XMP metadata.
FRAME_OPTIONS(i):
Create animation.
file_i +di+[xi+yi[+mi[bi]]]
where: 'file_i' is the i'th animation frame (WebP format),
'di' is the pause duration before next frame.
'xi','yi' specify the image offset for this frame.
'mi' is the dispose method for this frame (0 or 1).
'bi' is the blending method for this frame (+b or -b).
LOOP_COUNT:
Number of times to repeat the animation.
Valid range is 0 to 65535 [Default: 0 (infinite)].
BACKGROUND_COLOR:
Background color of the canvas.
A,R,G,B
where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying
the Alpha, Red, Green and Blue component values respectively
[Default: 255,255,255,255].
INPUT & OUTPUT are in WebP format.
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
valid.
Visualization tool:
===================
The examples/ directory also contains a tool (vwebp) for viewing WebP files.
It decodes the image and visualizes it using OpenGL. See the libwebp README
for details on building and running this program.
Mux API:
========
The Mux API contains methods for adding data to and reading data from WebP
files. This API currently supports XMP/EXIF metadata, ICC profile and animation.
Other features may be added in subsequent releases.
Example#1 (pseudo code): Creating a WebPMux object with image data, color
profile and XMP metadata.
int copy_data = 0;
WebPMux* mux = WebPMuxNew();
// ... (Prepare image data).
WebPMuxSetImage(mux, &image, copy_data);
// ... (Prepare ICC profile data).
WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
// ... (Prepare XMP metadata).
WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data);
// Get data from mux in WebP RIFF format.
WebPMuxAssemble(mux, &output_data);
WebPMuxDelete(mux);
// ... (Consume output_data; e.g. write output_data.bytes to file).
WebPDataClear(&output_data);
Example#2 (pseudo code): Get image and color profile data from a WebP file.
int copy_data = 0;
// ... (Read data from file).
WebPMux* mux = WebPMuxCreate(&data, copy_data);
WebPMuxGetFrame(mux, 1, &image);
// ... (Consume image; e.g. call WebPDecode() to decode the data).
WebPMuxGetChunk(mux, "ICCP", &icc_profile);
// ... (Consume icc_profile).
WebPMuxDelete(mux);
free(data);
For a detailed Mux API reference, please refer to the header file
(src/webp/mux.h).
Demux API:
==========
The Demux API enables extraction of images and extended format data from
WebP files. This API currently supports reading of XMP/EXIF metadata, ICC
profile and animated images. Other features may be added in subsequent
releases.
Code Example: Demuxing WebP data to extract all the frames, ICC profile
and EXIF/XMP metadata.
WebPDemuxer* demux = WebPDemux(&webp_data);
uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
// ... (Get information about the features present in the WebP file).
uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
// ... (Iterate over all frames).
WebPIterator iter;
if (WebPDemuxGetFrame(demux, 1, &iter)) {
do {
// ... (Consume 'iter'; e.g. Decode 'iter.fragment' with WebPDecode(),
// ... and get other frame properties like width, height, offsets etc.
// ... see 'struct WebPIterator' below for more info).
} while (WebPDemuxNextFrame(&iter));
WebPDemuxReleaseIterator(&iter);
}
// ... (Extract metadata).
WebPChunkIterator chunk_iter;
if (flags & ICCP_FLAG) WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter);
// ... (Consume the ICC profile in 'chunk_iter.chunk').
WebPDemuxReleaseChunkIterator(&chunk_iter);
if (flags & EXIF_FLAG) WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter);
// ... (Consume the EXIF metadata in 'chunk_iter.chunk').
WebPDemuxReleaseChunkIterator(&chunk_iter);
if (flags & XMP_FLAG) WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter);
// ... (Consume the XMP metadata in 'chunk_iter.chunk').
WebPDemuxReleaseChunkIterator(&chunk_iter);
WebPDemuxDelete(demux);
For a detailed Demux API reference, please refer to the header file
(src/webp/demux.h).
Bugs:
=====
Please report all bugs to our issue tracker:
http://code.google.com/p/webp/issues
Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/
Discuss:
========
Email: webp-discuss@webmproject.org
Web: http://groups.google.com/a/webmproject.org/group/webp-discuss

View File

@ -1,101 +1,328 @@
AC_INIT([libwebp], [0.1.3],
AC_INIT([libwebp], [0.4.0],
[http://code.google.com/p/webp/issues],,
[http://code.google.com/speed/webp])
[http://developers.google.com/speed/webp])
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
dnl === automake >= 1.12 requires this for 'unusual archivers' support.
dnl === it must occur before LT_INIT (AC_PROG_LIBTOOL).
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
AC_PROG_LIBTOOL
AM_PROG_CC_C_O
AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH],
[Path to the pkgconfig directory [[LIBDIR/pkgconfig]]]),
[pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
dnl === Enable less verbose output when building.
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl === SET_IF_UNSET(shell_var, value)
dnl === Set the shell variable 'shell_var' to 'value' if it is unset.
AC_DEFUN([SET_IF_UNSET], [test "${$1+set}" = "set" || $1=$2])
AC_ARG_ENABLE([everything],
AS_HELP_STRING([--enable-everything],
[Enable all optional targets. These can still be
disabled with --disable-target]),
[SET_IF_UNSET([enable_libwebpdecoder], [$enableval])
SET_IF_UNSET([enable_libwebpdemux], [$enableval])
SET_IF_UNSET([enable_libwebpmux], [$enableval])])
AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=DIR],
[Path to the pkgconfig directory @<:@LIBDIR/pkgconfig@:>@]),
[pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
AC_SUBST([pkgconfigdir])
dnl === Check libz is present
dnl === TEST_AND_ADD_CFLAGS(flag)
dnl === Checks whether $CC supports 'flag' and adds it to AM_CFLAGS on success.
AC_DEFUN([TEST_AND_ADD_CFLAGS],
[SAVED_CFLAGS="$CFLAGS"
CFLAGS="-Werror $1"
AC_MSG_CHECKING([whether $CC supports $1])
dnl Note AC_LANG_PROGRAM([]) uses an old-style main definition.
AC_COMPILE_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; }])],
[AC_MSG_RESULT([yes])]
dnl Simply append the variable avoiding a
dnl compatibility ifdef for AS_VAR_APPEND as this
dnl variable shouldn't grow all that large.
[AM_CFLAGS="$AM_CFLAGS $1"],
[AC_MSG_RESULT([no])])
CFLAGS="$SAVED_CFLAGS"])
TEST_AND_ADD_CFLAGS([-Wall])
TEST_AND_ADD_CFLAGS([-Wdeclaration-after-statement])
TEST_AND_ADD_CFLAGS([-Wextra])
TEST_AND_ADD_CFLAGS([-Wmissing-declarations])
TEST_AND_ADD_CFLAGS([-Wmissing-prototypes])
TEST_AND_ADD_CFLAGS([-Wold-style-definition])
TEST_AND_ADD_CFLAGS([-Wshadow])
TEST_AND_ADD_CFLAGS([-Wunused-but-set-variable])
TEST_AND_ADD_CFLAGS([-Wunused])
TEST_AND_ADD_CFLAGS([-Wvla])
AC_SUBST([AM_CFLAGS])
if test "$enable_experimental" = "yes"; then
AC_CHECK_HEADER(zlib.h,
AC_CHECK_LIB(z, gzsetparams,,AC_MSG_ERROR(zlib library not found)),
AC_MSG_ERROR(zlib not available - no zlib.h)
)
dnl === CLEAR_LIBVARS([var_pfx])
dnl === Clears <var_pfx>_{INCLUDES,LIBS}.
AC_DEFUN([CLEAR_LIBVARS], [$1_INCLUDES=""; $1_LIBS=""])
dnl === WITHLIB_OPTION([opt_pfx], [outvar_pfx])
dnl === Defines --with-<opt_pfx>{include,lib}dir options which set
dnl === the variables <outvar_pfx>_{INCLUDES,LIBS}.
AC_DEFUN([WITHLIB_OPTION],
[AC_ARG_WITH([$1includedir],
AS_HELP_STRING([--with-$1includedir=DIR],
[use $2 includes from DIR]),
$2_INCLUDES="-I$withval")
AC_ARG_WITH([$1libdir],
AS_HELP_STRING([--with-$1libdir=DIR],
[use $2 libraries from DIR]),
[$2_LIBS="-L$withval"])])
dnl === LIBCHECK_PROLOGUE([var_pfx])
dnl === Caches the current values of CPPFLAGS/LIBS in SAVED_* then
dnl === prepends the current values with <var_pfx>_{INCLUDES,LIBS}.
AC_DEFUN([LIBCHECK_PROLOGUE],
[SAVED_CPPFLAGS=$CPPFLAGS
SAVED_LIBS=$LIBS
CPPFLAGS="$$1_INCLUDES $CPPFLAGS"
LIBS="$$1_LIBS $LIBS"])
dnl === LIBCHECK_EPILOGUE([var_pfx])
dnl === Restores the values of CPPFLAGS/LIBS from SAVED_* and exports
dnl === <var_pfx>_{INCLUDES,LIBS} with AC_SUBST.
AC_DEFUN([LIBCHECK_EPILOGUE],
[AC_SUBST($1_LIBS)
AC_SUBST($1_INCLUDES)
CPPFLAGS=$SAVED_CPPFLAGS
LIBS=$SAVED_LIBS])
dnl === Check for pthread support
AC_ARG_ENABLE([threading],
AS_HELP_STRING([--disable-threading],
[Disable detection of thread support]),,
[enable_threading=yes])
if test "$enable_threading" = "yes"; then
AC_MSG_NOTICE([checking for threading support...])
AX_PTHREAD([AC_DEFINE([WEBP_USE_THREAD], [1],
[Undefine this to disable thread support.])
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
CC="$PTHREAD_CC"
],
[enable_threading=no])
fi
AC_MSG_NOTICE([checking if threading is enabled... ${enable_threading-no}])
dnl === check for OpenGL/GLUT support ===
CLEAR_LIBVARS([GL])
WITHLIB_OPTION([gl], [GL])
LIBCHECK_PROLOGUE([GL])
glut_cflags="none"
glut_ldflags="none"
case $host_os in
darwin*)
# Special case for OSX builds. Append these to give the user a chance to
# override with --with-gl*
glut_cflags="$glut_cflags|-framework GLUT -framework OpenGL"
glut_ldflags="$glut_ldflags|-framework GLUT -framework OpenGL"
;;
esac
GLUT_SAVED_CPPFLAGS="$CPPFLAGS"
SAVED_IFS="$IFS"
IFS="|"
for flag in $glut_cflags; do
# restore IFS immediately as the autoconf macros may need the default.
IFS="$SAVED_IFS"
unset ac_cv_header_GL_glut_h
unset ac_cv_header_OpenGL_glut_h
case $flag in
none) ;;
*) CPPFLAGS="$flag $CPPFLAGS";;
esac
AC_CHECK_HEADERS([GL/glut.h GLUT/glut.h OpenGL/glut.h],
[glut_headers=yes;
test "$flag" = "none" || GL_INCLUDES="$CPPFLAGS";
break])
CPPFLAGS="$GLUT_SAVED_CPPFLAGS"
test "$glut_headers" = "yes" && break
done
IFS="$SAVED_IFS"
if test "$glut_headers" = "yes"; then
AC_LANG_PUSH([C])
GLUT_SAVED_LDFLAGS="$LDFLAGS"
SAVED_IFS="$IFS"
IFS="|"
for flag in $glut_ldflags; do
# restore IFS immediately as the autoconf macros may need the default.
IFS="$SAVED_IFS"
unset ac_cv_search_glBegin
case $flag in
none) ;;
*) LDFLAGS="$flag $LDFLAGS";;
esac
# find libGL
GL_SAVED_LIBS="$LIBS"
AC_SEARCH_LIBS([glBegin], [GL OpenGL])
LIBS="$GL_SAVED_LIBS"
# A direct link to libGL may not be necessary on e.g., linux.
GLUT_SAVED_LIBS="$LIBS"
for lib in "" "-lglut" "-lglut $ac_cv_search_glBegin"; do
LIBS="$lib"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([
#ifdef __cplusplus
# define EXTERN_C extern "C"
#else
# define EXTERN_C
#endif
EXTERN_C char glOrtho();
EXTERN_C char glutMainLoop();
],[
glOrtho();
glutMainLoop();
])
],
AC_DEFINE(WEBP_HAVE_GL, [1],
[Set to 1 if OpenGL is supported])
[glut_support=yes], []
)
if test "$glut_support" = "yes"; then
GL_LIBS="$LDFLAGS $lib"
break
fi
done
LIBS="$GLUT_SAVED_LIBS"
LDFLAGS="$GLUT_SAVED_LDFLAGS"
test "$glut_support" = "yes" && break
done
IFS="$SAVED_IFS"
AC_LANG_POP
fi
LIBCHECK_EPILOGUE([GL])
if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then
build_vwebp=yes
fi
AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
dnl === check for PNG support ===
PNG_INCLUDES=""
PNG_LIBS=""
AC_PATH_PROG(LIBPNG_CONFIG, libpng-config)
CLEAR_LIBVARS([PNG])
AC_PATH_PROGS(LIBPNG_CONFIG,
[libpng-config libpng15-config libpng14-config libpng12-config])
if test -n "$LIBPNG_CONFIG"; then
PNG_INCLUDES=`$LIBPNG_CONFIG --cflags`
PNG_PREFIX=`$LIBPNG_CONFIG --prefix`
if test "${PNG_PREFIX}/lib" != "/usr/lib" ; then
PNG_LIBS="-L${PNG_PREFIX}/lib"
fi
PNG_LIBS="$PNG_LIBS `$LIBPNG_CONFIG --libs`"
fi
AC_ARG_WITH(pngincludedir,
[--with-pngincludedir=DIR use PNG includes from DIR],
PNG_INCLUDES="-I$withval")
AC_ARG_WITH(pnglibdir,
[--with-pnglibdir=DIR use PNG libraries from DIR],
[PNG_LIBS="-L$withval"])
SAVED_CPPFLAGS=$CPPFLAGS
SAVED_LIBS=$LIBS
CPPFLAGS="$PNG_INCLUDES $CPPFLAGS"
LIBS="$PNG_LIBS $LIBS"
WITHLIB_OPTION([png], [PNG])
LIBCHECK_PROLOGUE([PNG])
AC_CHECK_HEADER(png.h,
AC_CHECK_LIB(png, main,
[PNG_LIBS="$PNG_LIBS -lpng"
PNG_INCLUDES="$PNG_INCLUDES -DWEBP_HAVE_PNG"
AC_DEFINE(WEBP_HAVE_PNG, [1], [Set to 1 if PNG library is installed])
],
AC_MSG_WARN(Optional png library not found),
[$MATH_LIBS]),
AC_MSG_WARN(png library not available - no png.h)
AC_SEARCH_LIBS(png_get_libpng_ver, [png],
[test "$ac_cv_search_png_get_libpng_ver" = "none required" \
|| PNG_LIBS="$PNG_LIBS $ac_cv_search_png_get_libpng_ver"
PNG_INCLUDES="$PNG_INCLUDES -DWEBP_HAVE_PNG"
AC_DEFINE(WEBP_HAVE_PNG, [1],
[Set to 1 if PNG library is installed])
png_support=yes
],
[AC_MSG_WARN(Optional png library not found)
PNG_LIBS=""
PNG_INCLUDES=""
],
[$MATH_LIBS]),
[AC_MSG_WARN(png library not available - no png.h)
PNG_LIBS=""
PNG_INCLUDES=""
],
)
AC_SUBST(PNG_LIBS)
AC_SUBST(PNG_INCLUDES)
CPPFLAGS=$SAVED_CPPFLAGS
LIBS=$SAVED_LIBS
LIBCHECK_EPILOGUE([PNG])
dnl === check for JPEG support ===
JPEG_INCLUDES=""
JPEG_LIBS=""
AC_ARG_WITH(jpegincludedir,
[--with-jpegincludedir=DIR use JPEG includes from DIR],
JPEG_INCLUDES="-I$withval")
AC_ARG_WITH(jpeglibdir,
[--with-jpeglibdir=DIR use JPEG libraries from DIR],
[JPEG_LIBS="-L$withval"])
SAVED_CPPFLAGS=$CPPFLAGS
SAVED_LIBS=$LIBS
CPPFLAGS="$JPEG_INCLUDES $CPPFLAGS"
LIBS="$JPEG_LIBS $LIBS"
CLEAR_LIBVARS([JPEG])
WITHLIB_OPTION([jpeg], [JPEG])
LIBCHECK_PROLOGUE([JPEG])
AC_CHECK_HEADER(jpeglib.h,
AC_CHECK_LIB(jpeg, jpeg_set_defaults,
[JPEG_LIBS="$JPEG_LIBS -ljpeg"
JPEG_INCLUDES="$JPEG_INCLUDES -DWEBP_HAVE_JPEG"
AC_DEFINE(WEBP_HAVE_JPEG, [1], [Set to 1 if JPEG library is installed])
AC_DEFINE(WEBP_HAVE_JPEG, [1],
[Set to 1 if JPEG library is installed])
jpeg_support=yes
],
AC_MSG_WARN(Optional jpeg library not found),
[$MATH_LIBS]),
AC_MSG_WARN(jpeg library not available - no jpeglib.h)
)
AC_SUBST(JPEG_LIBS)
AC_SUBST(JPEG_INCLUDES)
LIBCHECK_EPILOGUE([JPEG])
CPPFLAGS=$SAVED_CPPFLAGS
LIBS=$SAVED_LIBS
dnl === check for TIFF support ===
CLEAR_LIBVARS([TIFF])
WITHLIB_OPTION([tiff], [TIFF])
LIBCHECK_PROLOGUE([TIFF])
AC_CHECK_HEADER(tiffio.h,
AC_CHECK_LIB(tiff, TIFFGetVersion,
[TIFF_LIBS="$TIFF_LIBS -ltiff"
TIFF_INCLUDES="$TIFF_INCLUDES -DWEBP_HAVE_TIFF"
AC_DEFINE(WEBP_HAVE_TIFF, [1],
[Set to 1 if TIFF library is installed])
tiff_support=yes
],
AC_MSG_WARN(Optional tiff library not found),
[$MATH_LIBS]),
AC_MSG_WARN(tiff library not available - no tiffio.h)
)
LIBCHECK_EPILOGUE([TIFF])
dnl === check for GIF support ===
CLEAR_LIBVARS([GIF])
WITHLIB_OPTION([gif], [GIF])
LIBCHECK_PROLOGUE([GIF])
AC_CHECK_HEADER(gif_lib.h,
AC_CHECK_LIB([gif], [DGifOpenFileHandle],
[GIF_LIBS="$GIF_LIBS -lgif"
AC_DEFINE(WEBP_HAVE_GIF, [1],
[Set to 1 if GIF library is installed])
gif_support=yes
],
AC_MSG_WARN(Optional gif library not found),
[$MATH_LIBS]),
AC_MSG_WARN(gif library not available - no gif_lib.h)
)
LIBCHECK_EPILOGUE([GIF])
if test "$gif_support" = "yes" -a \
"$enable_libwebpmux" = "yes"; then
build_gif2webp=yes
fi
AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
dnl === check for WIC support ===
if test "$target_os" = "mingw32"; then
AC_ARG_ENABLE([wic],
AS_HELP_STRING([--disable-wic],
[Disable Windows Imaging Component (WIC) detection.
@<:@default=auto@:>@]),,
[enable_wic=yes])
if test "$target_os" = "mingw32" -a "$enable_wic" = "yes"; then
AC_CHECK_HEADERS([wincodec.h shlwapi.h windows.h])
if test "$ac_cv_header_wincodec_h" = "yes"; then
AC_MSG_CHECKING(for Windows Imaging Component support)
@ -136,18 +363,56 @@ if test "$target_os" = "mingw32"; then
fi
fi
dnl === If --enable-experimental is defined, add the flag WEBP_EXPERIMENTAL_FEATURES
dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP
USE_SWAP_16BIT_CSP=""
AC_MSG_CHECKING(if --enable-swap-16bit-csp option is specified)
AC_ARG_ENABLE([swap-16bit-csp],
AS_HELP_STRING([--enable-swap-16bit-csp],
[Enable byte swap for 16 bit colorspaces]))
if test "$enable_swap_16bit_csp" = "yes"; then
USE_SWAP_16BIT_CSP="-DWEBP_SWAP_16BIT_CSP"
fi
AC_MSG_RESULT(${enable_swap_16bit_csp-no})
AC_SUBST(USE_SWAP_16BIT_CSP)
dnl === If --enable-experimental is defined, add -DWEBP_EXPERIMENTAL_FEATURES
USE_EXPERIMENTAL_CODE=""
AC_MSG_CHECKING(if --enable-experimental option is specified)
AC_ARG_ENABLE(experimental, [ --enable-experimental Activate experimental features])
AC_ARG_ENABLE([experimental], AS_HELP_STRING([--enable-experimental],
[Activate experimental features]))
if test "$enable_experimental" = "yes"; then
AC_DEFINE(EXPERIMENTAL,,[Enable experimental code])
USE_EXPERIMENTAL_CODE="-DWEBP_EXPERIMENTAL_FEATURES"
AC_DEFINE(WEBP_EXPERIMENTAL_FEATURES, [1], [Enable experimental code])
USE_EXPERIMENTAL_CODE="-DWEBP_EXPERIMENTAL_FEATURES"
fi
AC_MSG_RESULT(${enable_experimental-no})
AC_SUBST(USE_EXPERIMENTAL_CODE)
dnl === Check whether libwebpmux should be built
AC_MSG_CHECKING(whether libwebpmux is to be built)
AC_ARG_ENABLE([libwebpmux],
AS_HELP_STRING([--enable-libwebpmux],
[Build libwebpmux @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpmux-no})
AM_CONDITIONAL([WANT_MUX], [test "$enable_libwebpmux" = "yes"])
dnl === Check whether libwebpdemux should be built
AC_MSG_CHECKING(whether libwebpdemux is to be built)
AC_ARG_ENABLE([libwebpdemux],
AS_HELP_STRING([--enable-libwebpdemux],
[Build libwebpdemux @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpdemux-no})
AM_CONDITIONAL([WANT_DEMUX], [test "$enable_libwebpdemux" = "yes"])
dnl === Check whether decoder library should be built.
AC_MSG_CHECKING(whether decoder library is to be built)
AC_ARG_ENABLE([libwebpdecoder],
AS_HELP_STRING([--enable-libwebpdecoder],
[Build libwebpdecoder @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpdecoder-no})
AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"])
dnl =========================
AC_CONFIG_MACRO_DIR([m4])
@ -155,8 +420,41 @@ AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
examples/Makefile src/dec/Makefile \
src/enc/Makefile src/dsp/Makefile \
src/demux/Makefile src/mux/Makefile \
src/utils/Makefile \
src/libwebp.pc])
src/libwebp.pc src/libwebpdecoder.pc \
src/demux/libwebpdemux.pc src/mux/libwebpmux.pc])
AC_OUTPUT
AC_MSG_NOTICE([
WebP Configuration Summary
--------------------------
Shared libraries: ${enable_shared}
Static libraries: ${enable_static}
Threaded decode: ${enable_threading-no}
libwebp: yes
libwebpdecoder: ${enable_libwebpdecoder-no}
libwebpdemux: ${enable_libwebpdemux-no}
libwebpmux: ${enable_libwebpmux-no}
Tools:
cwebp : yes
Input format support
====================
JPEG : ${jpeg_support-no}
PNG : ${png_support-no}
TIFF : ${tiff_support-no}
WIC : ${wic_support-no}
dwebp : yes
Output format support
=====================
PNG : ${png_support-no}
WIC : ${wic_support-no}
GIF support : ${gif_support-no}
gif2webp : ${build_gif2webp-no}
webpmux : ${enable_libwebpmux-no}
vwebp : ${build_vwebp-no}
])

29
doc/README Normal file
View File

@ -0,0 +1,29 @@
Generate libwebp Container Spec Docs from Text Source
=====================================================
HTML generation requires kramdown [1], easily installed as a
rubygem [2]. Rubygems installation should satisfy dependencies
automatically.
[1]: http://kramdown.rubyforge.org/
[2]: http://rubygems.org/
HTML generation can then be done from the project root:
$ kramdown doc/webp-container-spec.txt --template doc/template.html > \
doc/output/webp-container-spec.html
kramdown can optionally syntax highlight code blocks, using CodeRay [3],
a dependency of kramdown that rubygems will install automatically. The
following will apply inline CSS styling; an external stylesheet is not
needed.
$ kramdown doc/webp-lossless-bitstream-spec.txt --template \
doc/template.html --coderay-css style --coderay-line-numbers ' ' \
--coderay-default-lang c > \
doc/output/webp-lossless-bitstream-spec.html
Optimally, use kramdown 0.13.7 or newer if syntax highlighting desired.
[3]: http://coderay.rubychan.de/

13
doc/TODO Normal file
View File

@ -0,0 +1,13 @@
<louquillio@google.com>, 20111004
* Determine that normative RFC 2119 terms (MUST, SHOULD, MAY, etc.) are
truly intended in all cases where capitalized.
* Several passages could be made clearer.
* Overall edit for scope. Portions are phrased as an introduction to
the 0.1.3 RIFF container additions, rather than a holistic guide to
WebP.
* To wit, suggest s/[spec|specification]/guide/g . "Spec" can imply a
standards track; in any case it's too formal for a work in progress.

94
doc/template.html Normal file
View File

@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WebP Container Specification</title>
<meta name="generator" content="kramdown <%= ::Kramdown::VERSION %>" />
<style type="text/css">
body {
color: #000;
background-color: #fff;
margin: 10%;
font-family: "Liberation Sans", "DejaVu Sans", "Bitstream Vera Sans", Arial, sans-serif;
line-height: 1.4;
}
h2 {
border-bottom: 1px solid #ccc;
padding-bottom: 0;
}
table {
border-collapse: collapse;
}
th, td {
border: 1px solid #999;
padding: .5em .7em;;
}
th {
color: #fff;
background-color: #000;
}
td {
}
hr {
}
code {
color: #000;
background-color: #f7f7f7;
padding: 0 3px;
font-family: "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Consolata, monospace;
}
pre {
background-color: #f7f7f7;
padding: 1em;
border: 1px solid #ccc;
width: 42em;
overflow: auto;
font-family: "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Consolata, monospace;
}
pre code {
background-color: #f7f7f7;
padding: 0; /* Only want padding on inline code, not blocks */
}
pre.terminal {
color: #fff;
background-color: #000;
border: 1px solid #ccc;
max-height: 30em;
}
pre.terminal code {
color: #fff;
background-color: #000;
font-size: smaller;
}
#markdown-toc ul {
list-style-type: disc;
}
ul#markdown-toc {
margin-top: -1em;
visibility: hidden;
-webkit-padding-start: 0;
}
ul#markdown-toc ul {
visibility: visible;
}
ul#markdown-toc ul ul{
visibility: visible;
}
ul#markdown-toc + hr {
margin-bottom: 4em;
}
ol ol { /* Format nested ordered lists */
list-style-type: lower-alpha;
}
dt {
font-style: italic;
font-weight: bold;
}
.caption {
}
</style>
</head>
<body>
<%= @body %>
</body>
</html>

909
doc/webp-container-spec.txt Normal file
View File

@ -0,0 +1,909 @@
<!--
Although you may be viewing an alternate representation, this document
is sourced in Markdown, a light-duty markup scheme, and is optimized for
the [kramdown](http://kramdown.rubyforge.org/) transformer.
See the accompanying README. External link targets are referenced at the
end of this file.
-->
WebP Container Specification
============================
* TOC placeholder
{:toc}
Introduction
------------
WebP is an image format that uses either (i) the VP8 key frame encoding
to compress image data in a lossy way, or (ii) the WebP lossless encoding
(and possibly other encodings in the future). These encoding schemes should
make it more efficient than currently used formats. It is optimized for fast
image transfer over the network (e.g., for websites). The WebP format has
feature parity (color profile, metadata, animation etc) with other formats as
well. This document describes the structure of a WebP file.
The WebP container (i.e., RIFF container for WebP) allows feature support over
and above the basic use case of WebP (i.e., a file containing a single image
encoded as a VP8 key frame). The WebP container provides additional support
for:
* **Lossless compression.** An image can be losslessly compressed, using the
WebP Lossless Format.
* **Metadata.** An image may have metadata stored in EXIF or XMP formats.
* **Transparency.** An image may have transparency, i.e., an alpha channel.
* **Color Profile.** An image may have an embedded ICC profile as described
by the [International Color Consortium][iccspec].
* **Animation.** An image may have multiple frames with pauses between them,
making it an animation.
* **Image Fragmentation.** A single bitstream in WebP has an inherent
limitation for width or height of 2^14 pixels, and, when using VP8, a 512
KiB limit on the size of the first compressed partition. To support larger
images, the format supports images that are composed of multiple fragments,
each encoded as a separate bitstream. All fragments logically form a single
image: they have common metadata, color profile, etc. Image fragmentation
may also improve efficiency for larger images, e.g., grass can be encoded
differently than sky.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [RFC 2119][].
**Note:** Out of the features mentioned above, lossy compression, lossless
compression, transparency, metadata, color profile and animation are finalized
and are to be considered stable. On the other hand, image fragmentation is
experimental as of now, and is open to discussion, feedback and comments.
The same is indicated using annotation "_status: experimental_" in the relevant
sections of this document.
Terminology &amp; Basics
------------------------
A WebP file contains either a still image (i.e., an encoded matrix of pixels)
or an [animation](#animation). Optionally, it can also contain transparency
information, color profile and metadata. In case we need to refer only to the
matrix of pixels, we will call it the _canvas_ of the image.
Below are additional terms used throughout this document:
_Reader/Writer_
: Code that reads WebP files is referred to as a _reader_, while code that
writes them is referred to as a _writer_.
_uint16_
: A 16-bit, little-endian, unsigned integer.
_uint24_
: A 24-bit, little-endian, unsigned integer.
_uint32_
: A 32-bit, little-endian, unsigned integer.
_FourCC_
: A _FourCC_ (four-character code) is a _uint32_ created by concatenating four
ASCII characters in little-endian order.
_1-based_
: An unsigned integer field storing values offset by `-1`. e.g., Such a field
would store value _25_ as _24_.
RIFF file format
----------------
The WebP file format is based on the RIFF (resource interchange file format)
document format.
The basic element of a RIFF file is a _chunk_. It consists of:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Chunk FourCC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Chunk Size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Chunk Payload |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk FourCC: 32 bits
: ASCII four-character code used for chunk identification.
Chunk Size: 32 bits (_uint32_)
: The size of the chunk not including this field, the chunk identifier or
padding.
Chunk Payload: _Chunk Size_ bytes
: The data payload. If _Chunk Size_ is odd, a single padding byte -- that
SHOULD be `0` -- is added.
_ChunkHeader('ABCD')_
: This is used to describe the _FourCC_ and _Chunk Size_ header of individual
chunks, where 'ABCD' is the FourCC for the chunk. This element's
size is 8 bytes.
**Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard
chunks that apply to any RIFF file format, while FourCCs specific to a file
format are all lowercase. WebP does not follow this convention.
WebP file header
----------------
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 'R' | 'I' | 'F' | 'F' |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| File Size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 'W' | 'E' | 'B' | 'P' |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
'RIFF': 32 bits
: The ASCII characters 'R' 'I' 'F' 'F'.
File Size: 32 bits (_uint32_)
: The size of the file in bytes starting at offset 8. The maximum value of
this field is 2^32 minus 10 bytes and thus the size of the whole file is at
most 4GiB minus 2 bytes.
'WEBP': 32 bits
: The ASCII characters 'W' 'E' 'B' 'P'.
A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size
in the header is the total size of the chunks that follow plus `4` bytes for
the 'WEBP' FourCC. The file SHOULD NOT contain anything after it. As the size
of any chunk is even, the size given by the RIFF header is also even. The
contents of individual chunks will be described in the following sections.
Simple file format (lossy)
--------------------------
This layout SHOULD be used if the image requires _lossy_ encoding and does not
require transparency or other advanced features provided by the extended format.
Files with this layout are smaller and supported by older software.
Simple WebP (lossy) file format:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| WebP file header (12 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8 chunk |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8 chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8 ') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8 data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8 data: _Chunk Size_ bytes
: VP8 bitstream data.
The VP8 bitstream format specification can be found at [VP8 Data Format and
Decoding Guide][vp8spec]. Note that the VP8 frame header contains the VP8 frame
width and height. That is assumed to be the width and height of the canvas.
The VP8 specification describes how to decode the image into Y'CbCr
format. To convert to RGB, Rec. 601 SHOULD be used.
Simple file format (lossless)
-----------------------------
**Note:** Older readers may not support files using the lossless format.
This layout SHOULD be used if the image requires _lossless_ encoding (with an
optional transparency channel) and does not require advanced features provided
by the extended format.
Simple WebP (lossless) file format:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| WebP file header (12 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8L chunk |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8L chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8L') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8L data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8L data: _Chunk Size_ bytes
: VP8L bitstream data.
The current specification of the VP8L bitstream can be found at
[WebP Lossless Bitstream Format][webpllspec]. Note that the VP8L header
contains the VP8L image width and height. That is assumed to be the width
and height of the canvas.
Extended file format
--------------------
**Note:** Older readers may not support files using the extended format.
An extended format file consists of:
* A 'VP8X' chunk with information about features used in the file.
* An optional 'ICCP' chunk with color profile.
* An optional 'ANIM' chunk with animation control data.
* Image data.
* An optional 'EXIF' chunk with EXIF metadata.
* An optional 'XMP ' chunk with XMP metadata.
* An optional list of [unknown chunks](#unknown-chunks). _\[status: experimental\]_
For a _still image_, the _image data_ consists of a single frame, whereas for
an _animated image_, it consists of multiple frames. More details about frames
can be found in the [Animation](#animation) section.
Moreover, each frame can be fragmented or non-fragmented, as will be described
in the [Extended WebP file header](#extended_header) section. More details about
fragments can be found in the [Fragments](#fragments) section.
All chunks SHOULD be placed in the same order as listed above. If a chunk
appears in the wrong place, the file is invalid, but readers MAY parse the
file, ignoring the chunks that come too late.
**Rationale:** Setting the order of chunks should allow quicker file
parsing. For example, if an 'ALPH' chunk does not appear in its required
position, a decoder can choose to stop searching for it. The rule of
ignoring late chunks should make programs that need to do a full search
give the same results as the ones stopping early.
Extended WebP file header:
{:#extended_header}
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| WebP file header (12 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8X') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv|I|L|E|X|A|F| Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Canvas Width Minus One | ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
... Canvas Height Minus One |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Reserved (Rsv): 2 bits
: SHOULD be `0`.
ICC profile (I): 1 bit
: Set if the file contains an ICC profile.
Alpha (L): 1 bit
: Set if any of the frames of the image contain transparency information
("alpha").
EXIF metadata (E): 1 bit
: Set if the file contains EXIF metadata.
XMP metadata (X): 1 bit
: Set if the file contains XMP metadata.
Animation (A): 1 bit
: Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be
used to control the animation.
Image Fragmentation (F): 1 bit _\[status: experimental\]_
: Set if any of the frames in the image are represented by fragments.
Reserved: 24 bits
: SHOULD be `0`.
Canvas Width Minus One: 24 bits
: _1-based_ width of the canvas in pixels.
The actual canvas width is '1 + Canvas Width Minus One'
Canvas Height Minus One: 24 bits
: _1-based_ height of the canvas in pixels.
The actual canvas height is '1 + Canvas Height Minus One'
The product of _Canvas Width_ and _Canvas Height_ MUST be at most `2^32 - 1`.
Future specifications MAY add more fields.
### Chunks
#### Animation
An animation is controlled by ANIM and ANMF chunks.
ANIM Chunk:
{:#anim_chunk}
For an animated image, this chunk contains the _global parameters_ of the
animation.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ANIM') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Background Color |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Loop Count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Background Color: 32 bits (_uint32_)
: The default background color of the canvas in \[Blue, Green, Red, Alpha\]
byte order. This color MAY be used to fill the unused space on the canvas around
the frames, as well as the transparent pixels of the first frame. Background
color is also used when disposal method is `1`.
**Note**:
* Background color MAY contain a transparency value (alpha), even if the
_Alpha_ flag in [VP8X chunk](#extended_header) is unset.
* Viewer applications SHOULD treat the background color value as a hint, and
are not required to use it.
Loop Count: 16 bits (_uint16_)
: The number of times to loop the animation. `0` means infinitely.
This chunk MUST appear if the _Animation_ flag in the VP8X chunk is set.
If the _Animation_ flag is not set and this chunk is present, it
SHOULD be ignored.
ANMF chunk:
For animated images, this chunk contains information about a _single_ frame.
If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ANMF') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame X | ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
... Frame Y | Frame Width Minus One ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
... | Frame Height Minus One |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Duration | Reserved |B|D|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Frame X: 24 bits (_uint24_)
: The X coordinate of the upper left corner of the frame is `Frame X * 2`
Frame Y: 24 bits (_uint24_)
: The Y coordinate of the upper left corner of the frame is `Frame Y * 2`
Frame Width Minus One: 24 bits (_uint24_)
: The _1-based_ width of the frame.
The frame width is `1 + Frame Width Minus One`
Frame Height Minus One: 24 bits (_uint24_)
: The _1-based_ height of the frame.
The frame height is `1 + Frame Height Minus One`
Frame Duration: 24 bits (_uint24_)
: The time to wait before displaying the next frame, in 1 millisecond units.
In particular, frame duration of 0 is useful when one wants to update multiple
areas of the canvas at once during the animation.
Reserved: 6 bits
: SHOULD be 0.
Blending method (B): 1 bit
: Indicates how transparent pixels of _the current frame_ are to be blended with
corresponding pixels of the previous canvas:
* `0`: Use alpha blending. After disposing of the previous frame, render the
current frame on the canvas using [alpha-blending](#alpha-blending). If the
current frame does not have an alpha channel, assume alpha value of 255,
effectively replacing the rectangle.
* `1`: Do not blend. After disposing of the previous frame, render the
current frame on the canvas by overwriting the rectangle covered by the
current frame.
Disposal method (D): 1 bit
: Indicates how _the current frame_ is to be treated after it has been displayed
(before rendering the next frame) on the canvas:
* `0`: Do not dispose. Leave the canvas as is.
* `1`: Dispose to background color. Fill the _rectangle_ on the canvas covered
by the _current frame_ with background color specified in the
[ANIM chunk](#anim_chunk).
**Notes**:
* The frame disposal only applies to the _frame rectangle_, that is, the
rectangle defined by _Frame X_, _Frame Y_, _frame width_ and _frame height_.
It may or may not cover the whole canvas.
{:#alpha-blending}
* **Alpha-blending**:
Given that each of the R, G, B and A channels is 8-bit, and the RGB
channels are _not premultiplied_ by alpha, the formula for blending
'dst' onto 'src' is:
~~~~~
blend.A = src.A + dst.A * (1 - src.A / 255)
if blend.A = 0 then
blend.RGB = 0
else
blend.RGB = (src.RGB * src.A +
dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
~~~~~
* Alpha-blending SHOULD be done in linear color space, by taking into account
the [color profile](#color-profile) of the image. If the color profile is
not present, sRGB is to be assumed. (Note that sRGB also needs to be
linearized due to a gamma of ~2.2).
Frame Data: _Chunk Size_ - `16` bytes
: For a fragmented frame, it consists of multiple [fragment chunks](#fragments).
: For a non-fragmented frame, it consists of:
* An optional [alpha subchunk](#alpha) for the frame.
* A [bitstream subchunk](#bitstream-vp8vp8l) for the frame.
* An optional list of [unknown chunks](#unknown-chunks).
**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual
_padded_ chunks as described by the [RIFF file format](#riff-file-format).
#### Fragments _\[status: experimental\]_
For images that are represented by fragments, this chunk contains data for
a single fragment. If the _Image Fragmentation Flag_ is not set, then this chunk
SHOULD NOT be present.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('FRGM') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Fragment X | ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
... Fragment Y | Fragment Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fragment X: 24 bits (_uint24_)
: The X coordinate of the upper left corner of the fragment is `Fragment X * 2`
Fragment Y: 24 bits (_uint24_)
: The Y coordinate of the upper left corner of the fragment is `Fragment Y * 2`
Fragment Data: _Chunk Size_ - `6` bytes
: It contains:
* An optional [alpha subchunk](#alpha) for the fragment.
* The [bitstream subchunk](#bitstream-vp8vp8l) for the fragment.
* An optional list of [unknown chunks](#unknown-chunks).
Note: The width and height of the fragment is obtained from the bitstream
subchunk.
The fragments of a frame SHOULD have the following properties:
* They collectively cover the whole frame.
* No pair of fragments have any overlapping region on the frame.
* No portion of any fragment should be located outside of the canvas.
#### Alpha
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ALPH') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv| P | F | C | Alpha Bitstream... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Reserved (Rsv): 2 bits
: SHOULD be `0`.
Pre-processing (P): 2 bits
: These INFORMATIVE bits are used to signal the pre-processing that has
been performed during compression. The decoder can use this information to
e.g. dither the values or smooth the gradients prior to display.
* `0`: no pre-processing
* `1`: level reduction
Filtering method (F): 2 bits
: The filtering method used:
* `0`: None.
* `1`: Horizontal filter.
* `2`: Vertical filter.
* `3`: Gradient filter.
For each pixel, filtering is performed using the following calculations.
Assume the alpha values surrounding the current `X` position are labeled as:
C | B |
---+---+
A | X |
We seek to compute the alpha value at position `X`. First, a prediction is
made depending on the filtering method:
* Method `0`: predictor = 0
* Method `1`: predictor = A
* Method `2`: predictor = B
* Method `3`: predictor = clip(A + B - C)
where `clip(v)` is equal to:
* 0 if v < 0
* 255 if v > 255
* v otherwise
The final value is derived by adding the decompressed value `X` to the
predictor and using modulo-256 arithmetic to wrap the \[256-511\] range
into the \[0-255\] one:
`alpha = (predictor + X) % 256`
There are special cases for left-most and top-most pixel positions:
* Top-left value at location (0,0) uses 0 as predictor value. Otherwise,
* For horizontal or gradient filtering methods, the left-most pixels at
location (0, y) are predicted using the location (0, y-1) just above.
* For vertical or gradient filtering methods, the top-most pixels at
location (x, 0) are predicted using the location (x-1, 0) on the left.
Decoders are not required to use this information in any specified way.
Compression method (C): 2 bits
: The compression method used:
* `0`: No compression.
* `1`: Compressed using the WebP lossless format.
Alpha bitstream: _Chunk Size_ - `1` bytes
: Encoded alpha bitstream.
This optional chunk contains encoded alpha data for this frame/fragment. A
frame/fragment containing a 'VP8L' chunk SHOULD NOT contain this chunk.
**Rationale**: The transparency information is already part of the 'VP8L'
chunk.
The alpha channel data is stored as uncompressed raw data (when
compression method is '0') or compressed using the lossless format
(when the compression method is '1').
* Raw data: consists of a byte sequence of length width * height,
containing all the 8-bit transparency values in scan order.
* Lossless format compression: the byte sequence is a compressed
image-stream (as described in the [WebP Lossless Bitstream Format]
[webpllspec]) of implicit dimension width x height. That is, this
image-stream does NOT contain any headers describing the image dimension.
**Rationale**: the dimension is already known from other sources,
so storing it again would be redundant and error-prone.
Once the image-stream is decoded into ARGB color values, following
the process described in the lossless format specification, the
transparency information must be extracted from the *green* channel
of the ARGB quadruplet.
**Rationale**: the green channel is allowed extra transformation
steps in the specification -- unlike the other channels -- that can
improve compression.
#### Bitstream (VP8/VP8L)
This chunk contains compressed bitstream data for a single frame/fragment.
A bitstream chunk may be either (i) a VP8 chunk, using "VP8 " (note the
significant fourth-character space) as its tag _or_ (ii) a VP8L chunk, using
"VP8L" as its tag.
The formats of VP8 and VP8L chunks are as described in sections
[Simple file format (lossy)](#simple-file-format-lossy)
and [Simple file format (lossless)](#simple-file-format-lossless) respectively.
#### Color profile
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ICCP') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Color Profile |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Color Profile: _Chunk Size_ bytes
: ICC profile.
This chunk MUST appear before the image data.
There SHOULD be at most one such chunk. If there are more such chunks, readers
MAY ignore all except the first one.
See the [ICC Specification][iccspec] for details.
If this chunk is not present, sRGB SHOULD be assumed.
#### Metadata
Metadata can be stored in 'EXIF' or 'XMP ' chunks.
There SHOULD be at most one chunk of each type ('EXIF' and 'XMP '). If there
are more such chunks, readers MAY ignore all except the first one. Also, a file
may possibly contain both 'EXIF' and 'XMP ' chunks.
The chunks are defined as follows:
EXIF chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('EXIF') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| EXIF Metadata |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
EXIF Metadata: _Chunk Size_ bytes
: image metadata in EXIF format.
XMP chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('XMP ') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| XMP Metadata |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
XMP Metadata: _Chunk Size_ bytes
: image metadata in XMP format.
Additional guidance about handling metadata can be found in the
Metadata Working Group's [Guidelines for Handling Metadata][metadata].
#### Unknown Chunks _\[status: experimental\]_
A RIFF chunk (described in [this](#terminology-amp-basics) section) whose _chunk
tag_ is different from any of the chunks described in this document, is
considered an _unknown chunk_.
**Rationale**: Allowing unknown chunks gives a provision for future extension
of the format, and also allows storage of any application-specific data.
A file MAY contain unknown chunks:
* At the end of the file as described in [Extended WebP file
header](#extended_header) section.
* At the end of FRGM and ANMF chunks as described in [Fragments](#fragments)
and [Animation](#animation) sections.
Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their
original order (unless they specifically intend to modify these chunks).
### Assembling the Canvas from fragments/frames
Here we provide an overview of how a reader should assemble a canvas in case
of a fragmented-image and in case of an animated image. The notation
_VP8X.field_ means the field in the 'VP8X' chunk with the same description.
Displaying a _fragmented image_ canvas MUST be equivalent to the following
pseudocode: _\[status: experimental\]_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assert VP8X.flags.hasFragments
canvas ← new black image of size VP8X.canvasWidth x VP8X.canvasHeight.
frgm_params ← nil
for chunk in image_data:
assert chunk.tag is "FRGM"
frgm_params.fragmentX = Fragment X
frgm_params.fragmentY = Fragment Y
for subchunk in 'Fragment Data':
if subchunk.tag == "ALPH":
assert alpha subchunks not found in 'Fragment Data' earlier
frgm_params.alpha = alpha_data
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
assert bitstream subchunks not found in 'Fragment Data' earlier
frgm_params.bitstream = bitstream_data
frgm_params.fragmentWidth = Width extracted from bitstream subchunk
frgm_params.fragmentHeight = Height extracted from bitstream subchunk
assert VP8X.canvasWidth >=
frgm_params.fragmentX + frgm_params.fragmentWidth
assert VP8X.canvasHeight >=
frgm_params.fragmentY + frgm_params.fragmentHeight
assert fragment has the properties mentioned in "Image Fragments" section.
render fragment with frame_params.alpha and frame_params.bitstream on canvas
with top-left corner in (frgm_params.fragmentX, frgm_params.fragmentY).
canvas contains the decoded canvas.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Displaying an _animated image_ canvas MUST be equivalent to the following
pseudocode:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assert VP8X.flags.hasAnimation
canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
background color ANIM.background_color.
loop_count ← ANIM.loopCount
dispose_method ← ANIM.disposeMethod
if loop_count == 0:
loop_count = ∞
frame_params ← nil
for loop = 0, ..., loop_count - 1
assert next chunk in image_data is ANMF
frame_params.frameX = Frame X
frame_params.frameY = Frame Y
frame_params.frameWidth = Frame Width Minus One + 1
frame_params.frameHeight = Frame Height Minus One + 1
frame_params.frameDuration = Frame Duration
assert VP8X.canvasWidth >= frame_params.frameX + frame_params.frameWidth
assert VP8X.canvasHeight >= frame_params.frameY + frame_params.frameHeight
if VP8X.flags.hasFragments and first subchunk in 'Frame Data' is FRGM
// Fragmented frame.
frame_params.{bitstream,alpha} = canvas decoded from subchunks in
'Frame Data' as per the pseudocode for
_fragmented image_ above.
else
// Non-fragmented frame.
for subchunk in 'Frame Data':
if subchunk.tag == "ALPH":
assert alpha subchunks not found in 'Frame Data' earlier
frame_params.alpha = alpha_data
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
assert bitstream subchunks not found in 'Frame Data' earlier
frame_params.bitstream = bitstream_data
render frame with frame_params.alpha and frame_params.bitstream on canvas
with top-left corner in (frame_params.frameX, frame_params.frameY), using
dispose method dispose_method.
Show the contents of the image for frame_params.frameDuration * 1ms.
canvas contains the decoded canvas.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example file layouts
--------------------
A lossy encoded image with alpha may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
+- VP8X (descriptions of features used)
+- ALPH (alpha bitstream)
+- VP8 (bitstream)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A losslessly encoded image may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
+- VP8X (descriptions of features used)
+- XYZW (unknown chunk)
+- VP8L (lossless bitstream)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A lossless image with ICC profile and XMP metadata may
look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
+- VP8X (descriptions of features used)
+- ICCP (color profile)
+- VP8L (lossless bitstream)
+- XMP (metadata)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A fragmented image may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
+- VP8X (descriptions of features used)
+- FRGM (fragment1 parameters + data)
+- FRGM (fragment2 parameters + data)
+- FRGM (fragment3 parameters + data)
+- FRGM (fragment4 parameters + data)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An animated image with EXIF metadata may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
+- VP8X (descriptions of features used)
+- ANIM (global animation parameters)
+- ANMF (frame1 parameters + data)
+- ANMF (frame2 parameters + data)
+- ANMF (frame3 parameters + data)
+- ANMF (frame4 parameters + data)
+- EXIF (metadata)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[vp8spec]: http://tools.ietf.org/html/rfc6386
[webpllspec]: https://gerrit.chromium.org/gerrit/gitweb?p=webm/libwebp.git;a=blob;f=doc/webp-lossless-bitstream-spec.txt;hb=master
[iccspec]: http://www.color.org/icc_specs2.xalter
[metadata]: http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
[rfc 2119]: http://tools.ietf.org/html/rfc2119

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,52 @@
AM_CPPFLAGS = -I$(top_srcdir)/src
bin_PROGRAMS = dwebp cwebp
if BUILD_VWEBP
bin_PROGRAMS += vwebp
endif
if WANT_MUX
bin_PROGRAMS += webpmux
endif
if BUILD_GIF2WEBP
bin_PROGRAMS += gif2webp
endif
noinst_LTLIBRARIES = libexampleutil.la
libexampleutil_la_SOURCES = example_util.c example_util.h
dwebp_SOURCES = dwebp.c stopwatch.h
dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) $(JPEG_INCLUDES) $(USE_EXPERIMENTAL_CODE)
dwebp_LDADD = ../src/libwebp.la $(PNG_LIBS) $(JPEG_LIBS)
dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES)
dwebp_LDADD = libexampleutil.la $(PNG_LIBS) $(JPEG_LIBS)
cwebp_SOURCES = cwebp.c stopwatch.h
cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) $(JPEG_INCLUDES) $(USE_EXPERIMENTAL_CODE)
cwebp_LDADD = ../src/libwebp.la $(PNG_LIBS) $(JPEG_LIBS)
cwebp_SOURCES = cwebp.c metadata.c metadata.h stopwatch.h
cwebp_SOURCES += jpegdec.c jpegdec.h
cwebp_SOURCES += pngdec.c pngdec.h
cwebp_SOURCES += tiffdec.c tiffdec.h
cwebp_SOURCES += wicdec.c wicdec.h
cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
cwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
cwebp_LDADD = ../src/libwebp.la $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS)
gif2webp_SOURCES = gif2webp.c gif2webp_util.c
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
gif2webp_LDADD = libexampleutil.la ../src/mux/libwebpmux.la ../src/libwebp.la
gif2webp_LDADD += $(GIF_LIBS)
webpmux_SOURCES = webpmux.c
webpmux_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
webpmux_LDADD = libexampleutil.la ../src/mux/libwebpmux.la ../src/libwebp.la
vwebp_SOURCES = vwebp.c
vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GL_INCLUDES)
vwebp_LDADD = libexampleutil.la ../src/demux/libwebpdemux.la $(GL_LIBS)
if BUILD_LIBWEBPDECODER
dwebp_LDADD += ../src/libwebpdecoder.la
vwebp_LDADD += ../src/libwebpdecoder.la
else
dwebp_LDADD += ../src/libwebp.la
vwebp_LDADD += ../src/libwebp.la
endif

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Command-line tool for decoding a WebP image
//
// Compile with: gcc -o dwebp dwebp.c -lwebpdecode
// Command-line tool for decoding a WebP image.
//
// Author: Skal (pascal.massimino@gmail.com)
@ -32,43 +32,56 @@
#define COBJMACROS
#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
// code with COBJMACROS.
#include <ole2.h> // CreateStreamOnHGlobal()
#include <shlwapi.h>
#include <windows.h>
#include <wincodec.h>
#endif
#include "webp/decode.h"
#include "stopwatch.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#if defined(_WIN32)
#include <fcntl.h> // for _O_BINARY
#include <io.h> // for _setmode()
#endif
#include "webp/decode.h"
#include "./example_util.h"
#include "./stopwatch.h"
static int verbose = 0;
#ifndef WEBP_DLL
extern void* VP8GetCPUInfo; // opaque forward declaration.
#ifdef __cplusplus
extern "C" {
#endif
extern void* VP8GetCPUInfo; // opaque forward declaration.
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_DLL
//------------------------------------------------------------------------------
// Output types
typedef enum {
PNG = 0,
PAM,
PPM,
PGM,
BMP,
TIFF,
YUV,
ALPHA_PLANE_ONLY // this is for experimenting only
} OutputFileFormat;
#ifdef HAVE_WINCODEC_H
#define IFS(fn) \
do { \
if (SUCCEEDED(hr)) \
{ \
hr = (fn); \
if (FAILED(hr) && verbose) \
printf(#fn " failed %08x\n", hr); \
} \
#define IFS(fn) \
do { \
if (SUCCEEDED(hr)) { \
hr = (fn); \
if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
} \
} while (0)
#ifdef __cplusplus
@ -78,70 +91,102 @@ typedef enum {
#endif
static HRESULT CreateOutputStream(const char* out_file_name,
IStream** ppStream) {
int write_to_mem, IStream** stream) {
HRESULT hr = S_OK;
IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, ppStream));
if (FAILED(hr))
printf("Error opening output file %s (%08x)\n", out_file_name, hr);
if (write_to_mem) {
// Output to a memory buffer. This is freed when 'stream' is released.
IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
} else {
IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream));
}
if (FAILED(hr)) {
fprintf(stderr, "Error opening output file %s (%08lx)\n",
out_file_name, hr);
}
return hr;
}
static HRESULT WriteUsingWIC(const char* out_file_name, REFGUID container_guid,
unsigned char* rgb, int stride,
static HRESULT WriteUsingWIC(const char* out_file_name, int use_stdout,
REFGUID container_guid,
uint8_t* rgb, int stride,
uint32_t width, uint32_t height, int has_alpha) {
HRESULT hr = S_OK;
IWICImagingFactory* pFactory = NULL;
IWICBitmapFrameEncode* pFrame = NULL;
IWICBitmapEncoder* pEncoder = NULL;
IStream* pStream = NULL;
IWICImagingFactory* factory = NULL;
IWICBitmapFrameEncode* frame = NULL;
IWICBitmapEncoder* encoder = NULL;
IStream* stream = NULL;
WICPixelFormatGUID pixel_format = has_alpha ? GUID_WICPixelFormat32bppBGRA
: GUID_WICPixelFormat24bppBGR;
IFS(CoInitialize(NULL));
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
CLSCTX_INPROC_SERVER, MAKE_REFGUID(IID_IWICImagingFactory),
(LPVOID*)&pFactory));
CLSCTX_INPROC_SERVER,
MAKE_REFGUID(IID_IWICImagingFactory),
(LPVOID*)&factory));
if (hr == REGDB_E_CLASSNOTREG) {
printf("Couldn't access Windows Imaging Component (are you running \n");
printf("Windows XP SP3 or newer?). PNG support not available.\n");
printf("Use -ppm or -pgm for available PPM and PGM formats.\n");
fprintf(stderr,
"Couldn't access Windows Imaging Component (are you running "
"Windows XP SP3 or newer?). PNG support not available. "
"Use -ppm or -pgm for available PPM and PGM formats.\n");
}
IFS(CreateOutputStream(out_file_name, &pStream));
IFS(IWICImagingFactory_CreateEncoder(pFactory, container_guid, NULL,
&pEncoder));
IFS(IWICBitmapEncoder_Initialize(pEncoder, pStream,
IFS(CreateOutputStream(out_file_name, use_stdout, &stream));
IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL,
&encoder));
IFS(IWICBitmapEncoder_Initialize(encoder, stream,
WICBitmapEncoderNoCache));
IFS(IWICBitmapEncoder_CreateNewFrame(pEncoder, &pFrame, NULL));
IFS(IWICBitmapFrameEncode_Initialize(pFrame, NULL));
IFS(IWICBitmapFrameEncode_SetSize(pFrame, width, height));
IFS(IWICBitmapFrameEncode_SetPixelFormat(pFrame, &pixel_format));
IFS(IWICBitmapFrameEncode_WritePixels(pFrame, height, stride,
height * stride, rgb));
IFS(IWICBitmapFrameEncode_Commit(pFrame));
IFS(IWICBitmapEncoder_Commit(pEncoder));
IFS(IWICBitmapEncoder_CreateNewFrame(encoder, &frame, NULL));
IFS(IWICBitmapFrameEncode_Initialize(frame, NULL));
IFS(IWICBitmapFrameEncode_SetSize(frame, width, height));
IFS(IWICBitmapFrameEncode_SetPixelFormat(frame, &pixel_format));
IFS(IWICBitmapFrameEncode_WritePixels(frame, height, stride,
height * stride, rgb));
IFS(IWICBitmapFrameEncode_Commit(frame));
IFS(IWICBitmapEncoder_Commit(encoder));
if (pFrame != NULL) IUnknown_Release(pFrame);
if (pEncoder != NULL) IUnknown_Release(pEncoder);
if (pFactory != NULL) IUnknown_Release(pFactory);
if (pStream != NULL) IUnknown_Release(pStream);
if (SUCCEEDED(hr) && use_stdout) {
HGLOBAL image;
IFS(GetHGlobalFromStream(stream, &image));
if (SUCCEEDED(hr)) {
HANDLE std_output = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
const BOOL update_mode = GetConsoleMode(std_output, &mode);
const void* const image_mem = GlobalLock(image);
DWORD bytes_written = 0;
// Clear output processing if necessary, then output the image.
if (update_mode) SetConsoleMode(std_output, 0);
if (!WriteFile(std_output, image_mem, (DWORD)GlobalSize(image),
&bytes_written, NULL) ||
bytes_written != GlobalSize(image)) {
hr = E_FAIL;
}
if (update_mode) SetConsoleMode(std_output, mode);
GlobalUnlock(image);
}
}
if (frame != NULL) IUnknown_Release(frame);
if (encoder != NULL) IUnknown_Release(encoder);
if (factory != NULL) IUnknown_Release(factory);
if (stream != NULL) IUnknown_Release(stream);
return hr;
}
static int WritePNG(const char* out_file_name,
static int WritePNG(const char* out_file_name, int use_stdout,
const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
unsigned char* const rgb = buffer->u.RGBA.rgba;
uint8_t* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = (buffer->colorspace == MODE_BGRA);
return SUCCEEDED(WriteUsingWIC(out_file_name,
MAKE_REFGUID(GUID_ContainerFormatPng), rgb, stride, width,
height, has_alpha));
return SUCCEEDED(WriteUsingWIC(out_file_name, use_stdout,
MAKE_REFGUID(GUID_ContainerFormatPng),
rgb, stride, width, height, has_alpha));
}
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp dummy) {
(void)dummy; // remove variable-unused warning
longjmp(png_jmpbuf(png), 1);
}
@ -149,7 +194,7 @@ static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
static int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
unsigned char* const rgb = buffer->u.RGBA.rgba;
uint8_t* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = (buffer->colorspace == MODE_RGBA);
png_structp png;
@ -157,7 +202,7 @@ static int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
png_uint_32 y;
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, error_function, NULL);
NULL, PNGErrorFunction, NULL);
if (png == NULL) {
return 0;
}
@ -185,38 +230,182 @@ static int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
return 1;
}
#else // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG
typedef uint32_t png_uint_32;
static int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
(void)out_file;
(void)buffer;
printf("PNG support not compiled. Please install the libpng development "
"package before building.\n");
printf("You can run with -ppm flag to decode in PPM format.\n");
fprintf(stderr, "PNG support not compiled. Please install the libpng "
"development package before building.\n");
fprintf(stderr, "You can run with -ppm flag to decode in PPM format.\n");
return 0;
}
#endif
static int WritePPM(FILE* fout, const WebPDecBuffer* const buffer) {
static int WritePPM(FILE* fout, const WebPDecBuffer* const buffer, int alpha) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const unsigned char* const rgb = buffer->u.RGBA.rgba;
const uint8_t* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const size_t bytes_per_px = alpha ? 4 : 3;
uint32_t y;
fprintf(fout, "P6\n%d %d\n255\n", width, height);
if (alpha) {
fprintf(fout, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\n"
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
} else {
fprintf(fout, "P6\n%d %d\n255\n", width, height);
}
for (y = 0; y < height; ++y) {
if (fwrite(rgb + y * stride, width, 3, fout) != 3) {
if (fwrite(rgb + y * stride, width, bytes_per_px, fout) != bytes_per_px) {
return 0;
}
}
return 1;
}
static void PutLE16(uint8_t* const dst, uint32_t value) {
dst[0] = (value >> 0) & 0xff;
dst[1] = (value >> 8) & 0xff;
}
static void PutLE32(uint8_t* const dst, uint32_t value) {
PutLE16(dst + 0, (value >> 0) & 0xffff);
PutLE16(dst + 2, (value >> 16) & 0xffff);
}
#define BMP_HEADER_SIZE 54
static int WriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
const int has_alpha = (buffer->colorspace != MODE_BGR);
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* const rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint32_t bytes_per_px = has_alpha ? 4 : 3;
uint32_t y;
const uint32_t line_size = bytes_per_px * width;
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
// bitmap file header
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
PutLE32(bmp_header + 2, total_size); // size including header
PutLE32(bmp_header + 6, 0); // reserved
PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
// bitmap info header
PutLE32(bmp_header + 14, 40); // DIB header size
PutLE32(bmp_header + 18, width); // dimensions
PutLE32(bmp_header + 22, -(int)height); // vertical flip!
PutLE16(bmp_header + 26, 1); // number of planes
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
PutLE32(bmp_header + 34, 0); // image size (dummy)
PutLE32(bmp_header + 38, 2400); // x pixels/meter
PutLE32(bmp_header + 42, 2400); // y pixels/meter
PutLE32(bmp_header + 46, 0); // number of palette colors
PutLE32(bmp_header + 50, 0); // important color count
// TODO(skal): color profile
// write header
if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
return 0;
}
// write pixel array
for (y = 0; y < height; ++y) {
if (fwrite(rgba + y * stride, line_size, 1, fout) != 1) {
return 0;
}
// write padding zeroes
if (bmp_stride != line_size) {
const uint8_t zeroes[3] = { 0 };
if (fwrite(zeroes, bmp_stride - line_size, 1, fout) != 1) {
return 0;
}
}
}
return 1;
}
#undef BMP_HEADER_SIZE
#define NUM_IFD_ENTRIES 15
#define EXTRA_DATA_SIZE 16
// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
#define EXTRA_DATA_OFFSET (10 + 12 * NUM_IFD_ENTRIES + 4)
#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
static int WriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
const int has_alpha = (buffer->colorspace != MODE_RGB);
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* const rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint8_t bytes_per_px = has_alpha ? 4 : 3;
// For non-alpha case, we omit tag 0x152 (ExtraSamples).
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
: NUM_IFD_ENTRIES - 1;
uint8_t tiff_header[TIFF_HEADER_SIZE] = {
0x49, 0x49, 0x2a, 0x00, // little endian signature
8, 0, 0, 0, // offset to the unique IFD that follows
// IFD (offset = 8). Entries must be written in increasing tag order.
num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
EXTRA_DATA_OFFSET + 0, 0, 0, 0,
0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none
0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
TIFF_HEADER_SIZE, 0, 0, 0, // data follows header
0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
bytes_per_px, 0, 0, 0,
0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD)
0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA
0, 0, 0, 0, // 190: IFD terminator
// EXTRA_DATA_OFFSET:
8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
};
uint32_t y;
// Fill placeholders in IFD:
PutLE32(tiff_header + 10 + 8, width);
PutLE32(tiff_header + 22 + 8, height);
PutLE32(tiff_header + 106 + 8, height);
PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
if (!has_alpha) PutLE32(tiff_header + 178, 0); // IFD terminator
// write header
if (fwrite(tiff_header, sizeof(tiff_header), 1, fout) != 1) {
return 0;
}
// write pixel values
for (y = 0; y < height; ++y) {
if (fwrite(rgba + y * stride, bytes_per_px, width, fout) != width) {
return 0;
}
}
return 1;
}
#undef TIFF_HEADER_SIZE
#undef EXTRA_DATA_OFFSET
#undef EXTRA_DATA_SIZE
#undef NUM_IFD_ENTRIES
static int WriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const unsigned char* const a = buffer->u.YUVA.a;
const uint8_t* const a = buffer->u.YUVA.a;
const int a_stride = buffer->u.YUVA.a_stride;
uint32_t y;
assert(a != NULL);
@ -229,101 +418,150 @@ static int WriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
return 1;
}
static int WritePGM(FILE* fout, const WebPDecBuffer* const buffer) {
// format=PGM: save a grayscale PGM file using the IMC4 layout
// (http://www.fourcc.org/yuv.php#IMC4). This is a very convenient format for
// viewing the samples, esp. for odd dimensions.
// format=YUV: just save the Y/U/V/A planes sequentially without header.
static int WritePGMOrYUV(FILE* fout, const WebPDecBuffer* const buffer,
OutputFileFormat format) {
const int width = buffer->width;
const int height = buffer->height;
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
// Save a grayscale PGM file using the IMC4 layout
// (http://www.fourcc.org/yuv.php#IMC4). This is a very
// convenient format for viewing the samples, esp. for
// odd dimensions.
int ok = 1;
int y;
const int pad = (format == YUV) ? 0 : 1;
const int uv_width = (width + 1) / 2;
const int uv_height = (height + 1) / 2;
const int out_stride = (width + 1) & ~1;
const int out_stride = (width + pad) & ~pad;
const int a_height = yuv->a ? height : 0;
fprintf(fout, "P5\n%d %d\n255\n", out_stride, height + uv_height + a_height);
if (format == PGM) {
fprintf(fout, "P5\n%d %d\n255\n",
out_stride, height + uv_height + a_height);
}
for (y = 0; ok && y < height; ++y) {
ok &= (fwrite(yuv->y + y * yuv->y_stride, width, 1, fout) == 1);
if (width & 1) fputc(0, fout); // padding byte
if (format == PGM) {
if (width & 1) fputc(0, fout); // padding byte
}
}
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
if (format == PGM) { // IMC4 layout
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
}
} else {
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
}
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
}
}
for (y = 0; ok && y < a_height; ++y) {
ok &= (fwrite(yuv->a + y * yuv->a_stride, width, 1, fout) == 1);
if (width & 1) fputc(0, fout); // padding byte
if (format == PGM) {
if (width & 1) fputc(0, fout); // padding byte
}
}
return ok;
}
static void SaveOutput(const WebPDecBuffer* const buffer,
OutputFileFormat format, const char* const out_file) {
static int SaveOutput(const WebPDecBuffer* const buffer,
OutputFileFormat format, const char* const out_file) {
FILE* fout = NULL;
int needs_open_file = 1;
const int use_stdout = !strcmp(out_file, "-");
int ok = 1;
Stopwatch stop_watch;
if (verbose)
StopwatchReadAndReset(&stop_watch);
if (verbose) {
StopwatchReset(&stop_watch);
}
#ifdef HAVE_WINCODEC_H
needs_open_file = (format != PNG);
#endif
#if defined(_WIN32)
if (use_stdout && _setmode(_fileno(stdout), _O_BINARY) == -1) {
fprintf(stderr, "Failed to reopen stdout in O_BINARY mode.\n");
return -1;
}
#endif
if (needs_open_file) {
fout = fopen(out_file, "wb");
if (!fout) {
fout = use_stdout ? stdout : fopen(out_file, "wb");
if (fout == NULL) {
fprintf(stderr, "Error opening output file %s\n", out_file);
return;
return 0;
}
}
if (format == PNG) {
#ifdef HAVE_WINCODEC_H
ok &= WritePNG(out_file, buffer);
ok &= WritePNG(out_file, use_stdout, buffer);
#else
ok &= WritePNG(fout, buffer);
#endif
} else if (format == PAM) {
ok &= WritePPM(fout, buffer, 1);
} else if (format == PPM) {
ok &= WritePPM(fout, buffer);
} else if (format == PGM) {
ok &= WritePGM(fout, buffer);
ok &= WritePPM(fout, buffer, 0);
} else if (format == BMP) {
ok &= WriteBMP(fout, buffer);
} else if (format == TIFF) {
ok &= WriteTIFF(fout, buffer);
} else if (format == PGM || format == YUV) {
ok &= WritePGMOrYUV(fout, buffer, format);
} else if (format == ALPHA_PLANE_ONLY) {
ok &= WriteAlphaPlane(fout, buffer);
}
if (fout) {
if (fout != NULL && fout != stdout) {
fclose(fout);
}
if (ok) {
printf("Saved file %s\n", out_file);
if (use_stdout) {
fprintf(stderr, "Saved to stdout\n");
} else {
fprintf(stderr, "Saved file %s\n", out_file);
}
if (verbose) {
const double time = StopwatchReadAndReset(&stop_watch);
printf("Time to write output: %.3fs\n", time);
const double write_time = StopwatchReadAndReset(&stop_watch);
fprintf(stderr, "Time to write output: %.3fs\n", write_time);
}
} else {
fprintf(stderr, "Error writing file %s !!\n", out_file);
if (use_stdout) {
fprintf(stderr, "Error writing to stdout !!\n");
} else {
fprintf(stderr, "Error writing file %s !!\n", out_file);
}
}
return ok;
}
static void Help(void) {
printf("Usage: dwebp in_file [options] [-o out_file]\n\n"
"Decodes the WebP image file to PNG format [Default]\n"
"Use following options to convert into alternate image formats:\n"
" -ppm ......... save the raw RGB samples as color PPM\n"
" -pam ......... save the raw RGBA samples as a color PAM\n"
" -ppm ......... save the raw RGB samples as a color PPM\n"
" -bmp ......... save as uncompressed BMP format\n"
" -tiff ........ save as uncompressed TIFF format\n"
" -pgm ......... save the raw YUV samples as a grayscale PGM\n"
" file with IMC4 layout.\n"
" file with IMC4 layout\n"
" -yuv ......... save the raw YUV samples in flat layout\n"
"\n"
" Other options are:\n"
" -version .... print version number and exit.\n"
" -nofancy ..... don't use the fancy YUV420 upscaler.\n"
" -nofilter .... disable in-loop filtering.\n"
" -nodither .... disable dithering.\n"
" -dither <d> .. dithering strength (in 0..100)\n"
" -mt .......... use multi-threading\n"
" -crop <x> <y> <w> <h> ... crop output with the given rectangle\n"
" -scale <w> <h> .......... scale the output (*after* any cropping)\n"
#ifdef WEBP_EXPERIMENTAL_FEATURES
" -alpha ....... only save the alpha plane.\n"
#endif
" -incremental . use incremental decoding (useful for tests)\n"
" -h ....... this help message.\n"
" -v ....... verbose (e.g. print encoding/decoding times)\n"
#ifndef WEBP_DLL
@ -337,7 +575,12 @@ static const char* const kStatusMessages[] = {
"UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
};
static const char* const kFormatType[] = {
"unspecified", "lossy", "lossless"
};
int main(int argc, const char *argv[]) {
int ok = 0;
const char *in_file = NULL;
const char *out_file = NULL;
@ -345,6 +588,7 @@ int main(int argc, const char *argv[]) {
WebPDecBuffer* const output_buffer = &config.output;
WebPBitstreamFeatures* const bitstream = &config.input;
OutputFileFormat format = PNG;
int incremental = 0;
int c;
if (!WebPInitDecoderConfig(&config)) {
@ -364,17 +608,29 @@ int main(int argc, const char *argv[]) {
config.options.no_fancy_upsampling = 1;
} else if (!strcmp(argv[c], "-nofilter")) {
config.options.bypass_filtering = 1;
} else if (!strcmp(argv[c], "-pam")) {
format = PAM;
} else if (!strcmp(argv[c], "-ppm")) {
format = PPM;
} else if (!strcmp(argv[c], "-bmp")) {
format = BMP;
} else if (!strcmp(argv[c], "-tiff")) {
format = TIFF;
} else if (!strcmp(argv[c], "-version")) {
const int version = WebPGetDecoderVersion();
printf("%d.%d.%d\n",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
return 0;
} else if (!strcmp(argv[c], "-pgm")) {
format = PGM;
} else if (!strcmp(argv[c], "-yuv")) {
format = YUV;
} else if (!strcmp(argv[c], "-mt")) {
config.options.use_threads = 1;
} else if (!strcmp(argv[c], "-nodither")) {
config.options.dithering_strength = 0;
} else if (!strcmp(argv[c], "-dither") && c < argc - 1) {
config.options.dithering_strength = strtol(argv[++c], NULL, 0);
} else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
config.options.use_cropping = 1;
config.options.crop_left = strtol(argv[++c], NULL, 0);
@ -391,8 +647,13 @@ int main(int argc, const char *argv[]) {
} else if (!strcmp(argv[c], "-noasm")) {
VP8GetCPUInfo = NULL;
#endif
} else if (!strcmp(argv[c], "-incremental")) {
incremental = 1;
} else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) in_file = argv[++c];
break;
} else if (argv[c][0] == '-') {
printf("Unknown option '%s'\n", argv[c]);
fprintf(stderr, "Unknown option '%s'\n", argv[c]);
Help();
return -1;
} else {
@ -401,7 +662,7 @@ int main(int argc, const char *argv[]) {
}
if (in_file == NULL) {
printf("missing input file!!\n");
fprintf(stderr, "missing input file!!\n");
Help();
return -1;
}
@ -409,36 +670,27 @@ int main(int argc, const char *argv[]) {
{
Stopwatch stop_watch;
VP8StatusCode status = VP8_STATUS_OK;
int ok;
uint32_t data_size = 0;
void* data = NULL;
FILE* const in = fopen(in_file, "rb");
size_t data_size = 0;
const uint8_t* data = NULL;
if (!in) {
fprintf(stderr, "cannot open input file '%s'\n", in_file);
return 1;
}
fseek(in, 0, SEEK_END);
data_size = ftell(in);
fseek(in, 0, SEEK_SET);
data = malloc(data_size);
ok = (fread(data, data_size, 1, in) == 1);
fclose(in);
if (!ok) {
fprintf(stderr, "Could not read %d bytes of data from file %s\n",
data_size, in_file);
free(data);
return -1;
if (!ExUtilReadFile(in_file, &data, &data_size)) return -1;
if (verbose) {
StopwatchReset(&stop_watch);
}
if (verbose)
StopwatchReadAndReset(&stop_watch);
status = WebPGetFeatures((const uint8_t*)data, data_size, bitstream);
status = WebPGetFeatures(data, data_size, bitstream);
if (status != VP8_STATUS_OK) {
goto end;
}
if (bitstream->has_animation) {
fprintf(stderr,
"Error! Decoding of an animated WebP file is not supported.\n"
" Use webpmux to extract the individual frames or\n"
" vwebp to view this image.\n");
}
switch (format) {
case PNG:
#ifdef HAVE_WINCODEC_H
@ -447,53 +699,79 @@ int main(int argc, const char *argv[]) {
output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB;
#endif
break;
case PAM:
output_buffer->colorspace = MODE_RGBA;
break;
case PPM:
output_buffer->colorspace = MODE_RGB; // drops alpha for PPM
break;
case BMP:
output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR;
break;
case TIFF: // note: force pre-multiplied alpha
output_buffer->colorspace =
bitstream->has_alpha ? MODE_rgbA : MODE_RGB;
break;
case PGM:
case YUV:
output_buffer->colorspace = bitstream->has_alpha ? MODE_YUVA : MODE_YUV;
break;
case ALPHA_PLANE_ONLY:
output_buffer->colorspace = MODE_YUVA;
break;
default:
free(data);
free((void*)data);
return -1;
}
status = WebPDecode((const uint8_t*)data, data_size, &config);
// Decoding call.
if (!incremental) {
status = WebPDecode(data, data_size, &config);
} else {
WebPIDecoder* const idec = WebPIDecode(data, data_size, &config);
if (idec == NULL) {
fprintf(stderr, "Failed during WebPINewDecoder().\n");
status = VP8_STATUS_OUT_OF_MEMORY;
goto end;
} else {
status = WebPIUpdate(idec, data, data_size);
WebPIDelete(idec);
}
}
if (verbose) {
const double time = StopwatchReadAndReset(&stop_watch);
printf("Time to decode picture: %.3fs\n", time);
const double decode_time = StopwatchReadAndReset(&stop_watch);
fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
}
end:
free(data);
free((void*)data);
ok = (status == VP8_STATUS_OK);
if (!ok) {
fprintf(stderr, "Decoding of %s failed.\n", in_file);
fprintf(stderr, "Status: %d (%s)\n", status, kStatusMessages[status]);
return -1;
goto Exit;
}
}
if (out_file) {
printf("Decoded %s. Dimensions: %d x %d%s. Now saving...\n", in_file,
output_buffer->width, output_buffer->height,
bitstream->has_alpha ? " (with alpha)" : "");
SaveOutput(output_buffer, format, out_file);
if (out_file != NULL) {
fprintf(stderr, "Decoded %s. Dimensions: %d x %d %s. Format: %s. "
"Now saving...\n",
in_file, output_buffer->width, output_buffer->height,
bitstream->has_alpha ? " (with alpha)" : "",
kFormatType[bitstream->format]);
ok = SaveOutput(output_buffer, format, out_file);
} else {
printf("File %s can be decoded (dimensions: %d x %d)%s.\n",
in_file, output_buffer->width, output_buffer->height,
bitstream->has_alpha ? " (with alpha)" : "");
printf("Nothing written; use -o flag to save the result as e.g. PNG.\n");
fprintf(stderr, "File %s can be decoded "
"(dimensions: %d x %d %s. Format: %s).\n",
in_file, output_buffer->width, output_buffer->height,
bitstream->has_alpha ? " (with alpha)" : "",
kFormatType[bitstream->format]);
fprintf(stderr, "Nothing written; "
"use -o flag to save the result as e.g. PNG.\n");
}
Exit:
WebPFreeDecBuffer(output_buffer);
return 0;
return ok ? 0 : -1;
}
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

72
examples/example_util.c Normal file
View File

@ -0,0 +1,72 @@
// 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.
// -----------------------------------------------------------------------------
//
// Utility functions used by the example programs.
//
#include "./example_util.h"
#include <stdio.h>
#include <stdlib.h>
// -----------------------------------------------------------------------------
// File I/O
int ExUtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size) {
int ok;
void* file_data;
size_t file_size;
FILE* in;
if (file_name == NULL || data == NULL || data_size == NULL) return 0;
*data = NULL;
*data_size = 0;
in = fopen(file_name, "rb");
if (in == NULL) {
fprintf(stderr, "cannot open input file '%s'\n", file_name);
return 0;
}
fseek(in, 0, SEEK_END);
file_size = ftell(in);
fseek(in, 0, SEEK_SET);
file_data = malloc(file_size);
if (file_data == NULL) return 0;
ok = (fread(file_data, file_size, 1, in) == 1);
fclose(in);
if (!ok) {
fprintf(stderr, "Could not read %d bytes of data from file %s\n",
(int)file_size, file_name);
free(file_data);
return 0;
}
*data = (uint8_t*)file_data;
*data_size = file_size;
return 1;
}
int ExUtilWriteFile(const char* const file_name,
const uint8_t* data, size_t data_size) {
int ok;
FILE* out;
if (file_name == NULL || data == NULL) {
return 0;
}
out = fopen(file_name, "wb");
if (out == NULL) {
fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
return 0;
}
ok = (fwrite(data, data_size, 1, out) == 1);
fclose(out);
return ok;
}

36
examples/example_util.h Normal file
View File

@ -0,0 +1,36 @@
// 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.
// -----------------------------------------------------------------------------
//
// Utility functions used by the example programs.
//
#ifndef WEBP_EXAMPLES_EXAMPLE_UTIL_H_
#define WEBP_EXAMPLES_EXAMPLE_UTIL_H_
#include "webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Allocates storage for entire file 'file_name' and returns contents and size
// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
// be deleted using free().
int ExUtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size);
// Write a data segment into a file named 'file_name'. Returns true if ok.
int ExUtilWriteFile(const char* const file_name,
const uint8_t* data, size_t data_size);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_EXAMPLE_UTIL_H_

663
examples/gif2webp.c Normal file
View File

@ -0,0 +1,663 @@
// 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.
// -----------------------------------------------------------------------------
//
// simple tool to convert animated GIFs to WebP
//
// Authors: Skal (pascal.massimino@gmail.com)
// Urvang (urvang@google.com)
#include <assert.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WEBP_HAVE_GIF
#include <gif_lib.h>
#include "webp/encode.h"
#include "webp/mux.h"
#include "./example_util.h"
#include "./gif2webp_util.h"
#define GIF_TRANSPARENT_MASK 0x01
#define GIF_DISPOSE_MASK 0x07
#define GIF_DISPOSE_SHIFT 2
#define WHITE_COLOR 0xffffffff
#define MAX_CACHE_SIZE 30
//------------------------------------------------------------------------------
static int transparent_index = -1; // Index of transparent color in the map.
static void SanitizeKeyFrameIntervals(size_t* const kmin_ptr,
size_t* const kmax_ptr) {
size_t kmin = *kmin_ptr;
size_t kmax = *kmax_ptr;
int print_warning = 1;
if (kmin == 0) { // Disable keyframe insertion.
kmax = ~0;
kmin = kmax - 1;
print_warning = 0;
}
if (kmax == 0) {
kmax = ~0;
print_warning = 0;
}
if (kmin >= kmax) {
kmin = kmax - 1;
if (print_warning) {
fprintf(stderr,
"WARNING: Setting kmin = %d, so that kmin < kmax.\n", (int)kmin);
}
} else if (kmin < (kmax / 2 + 1)) {
// This ensures that cache.keyframe + kmin >= kmax is always true. So, we
// can flush all the frames in the count_since_key_frame == kmax case.
kmin = (kmax / 2 + 1);
if (print_warning) {
fprintf(stderr,
"WARNING: Setting kmin = %d, so that kmin >= kmax / 2 + 1.\n",
(int)kmin);
}
}
// Limit the max number of frames that are allocated.
if (kmax - kmin > MAX_CACHE_SIZE) {
kmin = kmax - MAX_CACHE_SIZE;
if (print_warning) {
fprintf(stderr,
"WARNING: Setting kmin = %d, so that kmax - kmin <= 30.\n",
(int)kmin);
}
}
*kmin_ptr = kmin;
*kmax_ptr = kmax;
}
static void Remap(const uint8_t* const src, const GifFileType* const gif,
uint32_t* dst, int len) {
int i;
const GifColorType* colors;
const ColorMapObject* const cmap =
gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
if (cmap == NULL) return;
colors = cmap->Colors;
for (i = 0; i < len; ++i) {
const GifColorType c = colors[src[i]];
dst[i] = (src[i] == transparent_index) ? WEBP_UTIL_TRANSPARENT_COLOR
: c.Blue | (c.Green << 8) | (c.Red << 16) | (0xff << 24);
}
}
// Read the GIF image frame.
static int ReadFrame(GifFileType* const gif, WebPFrameRect* const gif_rect,
WebPPicture* const webp_frame) {
WebPPicture sub_image;
const GifImageDesc image_desc = gif->Image;
uint32_t* dst = NULL;
uint8_t* tmp = NULL;
int ok = 0;
WebPFrameRect rect = {
image_desc.Left, image_desc.Top, image_desc.Width, image_desc.Height
};
*gif_rect = rect;
// Use a view for the sub-picture:
if (!WebPPictureView(webp_frame, rect.x_offset, rect.y_offset,
rect.width, rect.height, &sub_image)) {
fprintf(stderr, "Sub-image %dx%d at position %d,%d is invalid!\n",
rect.width, rect.height, rect.x_offset, rect.y_offset);
return 0;
}
dst = sub_image.argb;
tmp = (uint8_t*)malloc(rect.width * sizeof(*tmp));
if (tmp == NULL) goto End;
if (image_desc.Interlace) { // Interlaced image.
// We need 4 passes, with the following offsets and jumps.
const int interlace_offsets[] = { 0, 4, 2, 1 };
const int interlace_jumps[] = { 8, 8, 4, 2 };
int pass;
for (pass = 0; pass < 4; ++pass) {
int y;
for (y = interlace_offsets[pass]; y < rect.height;
y += interlace_jumps[pass]) {
if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End;
Remap(tmp, gif, dst + y * sub_image.argb_stride, rect.width);
}
}
} else { // Non-interlaced image.
int y;
for (y = 0; y < rect.height; ++y) {
if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End;
Remap(tmp, gif, dst + y * sub_image.argb_stride, rect.width);
}
}
ok = 1;
End:
if (!ok) webp_frame->error_code = sub_image.error_code;
WebPPictureFree(&sub_image);
free(tmp);
return ok;
}
static int GetBackgroundColor(const ColorMapObject* const color_map,
int bgcolor_idx, uint32_t* const bgcolor) {
if (transparent_index != -1 && bgcolor_idx == transparent_index) {
*bgcolor = WEBP_UTIL_TRANSPARENT_COLOR; // Special case.
return 1;
} else if (color_map == NULL || color_map->Colors == NULL
|| bgcolor_idx >= color_map->ColorCount) {
return 0; // Invalid color map or index.
} else {
const GifColorType color = color_map->Colors[bgcolor_idx];
*bgcolor = (0xff << 24)
| (color.Red << 16)
| (color.Green << 8)
| (color.Blue << 0);
return 1;
}
}
static void DisplayGifError(const GifFileType* const gif, int gif_error) {
// GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
// libgif 4.2.0 has retired PrintGifError() and added GifErrorString().
#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) && \
((GIFLIB_MAJOR == 4 && GIFLIB_MINOR >= 2) || GIFLIB_MAJOR > 4)
#if GIFLIB_MAJOR >= 5
// Static string actually, hence the const char* cast.
const char* error_str = (const char*)GifErrorString(
(gif == NULL) ? gif_error : gif->Error);
#else
const char* error_str = (const char*)GifErrorString();
(void)gif;
#endif
if (error_str == NULL) error_str = "Unknown error";
fprintf(stderr, "GIFLib Error %d: %s\n", gif_error, error_str);
#else
(void)gif;
fprintf(stderr, "GIFLib Error %d: ", gif_error);
PrintGifError();
fprintf(stderr, "\n");
#endif
}
static const char* const kErrorMessages[] = {
"WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA",
"WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA"
};
static const char* ErrorString(WebPMuxError err) {
assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA);
return kErrorMessages[-err];
}
enum {
METADATA_ICC = (1 << 0),
METADATA_XMP = (1 << 1),
METADATA_ALL = METADATA_ICC | METADATA_XMP
};
//------------------------------------------------------------------------------
static void Help(void) {
printf("Usage:\n");
printf(" gif2webp [options] gif_file -o webp_file\n");
printf("options:\n");
printf(" -h / -help ............ this help\n");
printf(" -lossy ................. Encode image using lossy compression.\n");
printf(" -mixed ................. For each frame in the image, pick lossy\n"
" or lossless compression heuristically.\n");
printf(" -q <float> ............. quality factor (0:small..100:big)\n");
printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n");
printf(" -kmin <int> ............ Min distance between key frames\n");
printf(" -kmax <int> ............ Max distance between key frames\n");
printf(" -f <int> ............... filter strength (0=off..100)\n");
printf(" -metadata <string> ..... comma separated list of metadata to\n");
printf(" ");
printf("copy from the input to the output if present.\n");
printf(" "
"Valid values: all, none, icc, xmp (default)\n");
printf(" -mt .................... use multi-threading if available\n");
printf("\n");
printf(" -version ............... print version number and exit.\n");
printf(" -v ..................... verbose.\n");
printf(" -quiet ................. don't print anything.\n");
printf("\n");
}
//------------------------------------------------------------------------------
int main(int argc, const char *argv[]) {
int verbose = 0;
int gif_error = GIF_ERROR;
WebPMuxError err = WEBP_MUX_OK;
int ok = 0;
const char *in_file = NULL, *out_file = NULL;
FILE* out = NULL;
GifFileType* gif = NULL;
WebPConfig config;
WebPPicture frame;
WebPMuxFrameInfo info;
WebPMuxAnimParams anim = { WHITE_COLOR, 0 };
WebPFrameCache* cache = NULL;
int is_first_frame = 1; // Whether we are processing the first frame.
int done;
int c;
int quiet = 0;
WebPMux* mux = NULL;
WebPData webp_data = { NULL, 0 };
int keep_metadata = METADATA_XMP; // ICC not output by default.
int stored_icc = 0; // Whether we have already stored an ICC profile.
int stored_xmp = 0;
int default_kmin = 1; // Whether to use default kmin value.
int default_kmax = 1;
size_t kmin = 0;
size_t kmax = 0;
int allow_mixed = 0; // If true, each frame can be lossy or lossless.
memset(&info, 0, sizeof(info));
info.id = WEBP_CHUNK_ANMF;
info.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
info.blend_method = WEBP_MUX_BLEND;
if (!WebPConfigInit(&config) || !WebPPictureInit(&frame)) {
fprintf(stderr, "Error! Version mismatch!\n");
return -1;
}
config.lossless = 1; // Use lossless compression by default.
config.image_hint = WEBP_HINT_GRAPH; // always low-color
if (argc == 1) {
Help();
return 0;
}
for (c = 1; c < argc; ++c) {
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
return 0;
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
out_file = argv[++c];
} else if (!strcmp(argv[c], "-lossy")) {
config.lossless = 0;
} else if (!strcmp(argv[c], "-mixed")) {
allow_mixed = 1;
config.lossless = 0;
} else if (!strcmp(argv[c], "-q") && c < argc - 1) {
config.quality = (float)strtod(argv[++c], NULL);
} else if (!strcmp(argv[c], "-m") && c < argc - 1) {
config.method = strtol(argv[++c], NULL, 0);
} else if (!strcmp(argv[c], "-kmax") && c < argc - 1) {
kmax = strtoul(argv[++c], NULL, 0);
default_kmax = 0;
} else if (!strcmp(argv[c], "-kmin") && c < argc - 1) {
kmin = strtoul(argv[++c], NULL, 0);
default_kmin = 0;
} else if (!strcmp(argv[c], "-f") && c < argc - 1) {
config.filter_strength = strtol(argv[++c], NULL, 0);
} else if (!strcmp(argv[c], "-metadata") && c < argc - 1) {
static const struct {
const char* option;
int flag;
} kTokens[] = {
{ "all", METADATA_ALL },
{ "none", 0 },
{ "icc", METADATA_ICC },
{ "xmp", METADATA_XMP },
};
const size_t kNumTokens = sizeof(kTokens) / sizeof(*kTokens);
const char* start = argv[++c];
const char* const end = start + strlen(start);
keep_metadata = 0;
while (start < end) {
size_t i;
const char* token = strchr(start, ',');
if (token == NULL) token = end;
for (i = 0; i < kNumTokens; ++i) {
if ((size_t)(token - start) == strlen(kTokens[i].option) &&
!strncmp(start, kTokens[i].option, strlen(kTokens[i].option))) {
if (kTokens[i].flag != 0) {
keep_metadata |= kTokens[i].flag;
} else {
keep_metadata = 0;
}
break;
}
}
if (i == kNumTokens) {
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
(int)(token - start), start);
Help();
return -1;
}
start = token + 1;
}
} else if (!strcmp(argv[c], "-mt")) {
++config.thread_level;
} else if (!strcmp(argv[c], "-version")) {
const int enc_version = WebPGetEncoderVersion();
const int mux_version = WebPGetMuxVersion();
printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n",
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
enc_version & 0xff, (mux_version >> 16) & 0xff,
(mux_version >> 8) & 0xff, mux_version & 0xff);
return 0;
} else if (!strcmp(argv[c], "-quiet")) {
quiet = 1;
} else if (!strcmp(argv[c], "-v")) {
verbose = 1;
} else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) in_file = argv[++c];
break;
} else if (argv[c][0] == '-') {
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
Help();
return -1;
} else {
in_file = argv[c];
}
}
// Appropriate default kmin, kmax values for lossy and lossless.
if (default_kmin) {
kmin = config.lossless ? 9 : 3;
}
if (default_kmax) {
kmax = config.lossless ? 17 : 5;
}
SanitizeKeyFrameIntervals(&kmin, &kmax);
if (!WebPValidateConfig(&config)) {
fprintf(stderr, "Error! Invalid configuration.\n");
goto End;
}
if (in_file == NULL) {
fprintf(stderr, "No input file specified!\n");
Help();
goto End;
}
// Start the decoder object
#if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR >= 5)
// There was an API change in version 5.0.0.
gif = DGifOpenFileName(in_file, &gif_error);
#else
gif = DGifOpenFileName(in_file);
#endif
if (gif == NULL) goto End;
// Allocate current buffer
frame.width = gif->SWidth;
frame.height = gif->SHeight;
frame.use_argb = 1;
if (!WebPPictureAlloc(&frame)) goto End;
// Initialize cache
cache = WebPFrameCacheNew(frame.width, frame.height, kmin, kmax, allow_mixed);
if (cache == NULL) goto End;
mux = WebPMuxNew();
if (mux == NULL) {
fprintf(stderr, "ERROR: could not create a mux object.\n");
goto End;
}
// Loop over GIF images
done = 0;
do {
GifRecordType type;
if (DGifGetRecordType(gif, &type) == GIF_ERROR) goto End;
switch (type) {
case IMAGE_DESC_RECORD_TYPE: {
WebPFrameRect gif_rect;
if (!DGifGetImageDesc(gif)) goto End;
if (!ReadFrame(gif, &gif_rect, &frame)) {
goto End;
}
if (!WebPFrameCacheAddFrame(cache, &config, &gif_rect, &frame, &info)) {
fprintf(stderr, "Error! Cannot encode frame as WebP\n");
fprintf(stderr, "Error code: %d\n", frame.error_code);
}
err = WebPFrameCacheFlush(cache, verbose, mux);
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not add animation frame.\n",
ErrorString(err));
goto End;
}
is_first_frame = 0;
break;
}
case EXTENSION_RECORD_TYPE: {
int extension;
GifByteType *data = NULL;
if (DGifGetExtension(gif, &extension, &data) == GIF_ERROR) {
goto End;
}
switch (extension) {
case COMMENT_EXT_FUNC_CODE: {
break; // Do nothing for now.
}
case GRAPHICS_EXT_FUNC_CODE: {
const int flags = data[1];
const int dispose = (flags >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK;
const int delay = data[2] | (data[3] << 8); // In 10 ms units.
if (data[0] != 4) goto End;
info.duration = delay * 10; // Duration is in 1 ms units for WebP.
if (dispose == 3) {
static int warning_printed = 0;
if (!warning_printed) {
fprintf(stderr, "WARNING: GIF_DISPOSE_RESTORE unsupported.\n");
warning_printed = 1;
}
// failsafe. TODO(urvang): emulate the correct behaviour by
// recoding the whole frame.
info.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
} else {
info.dispose_method =
(dispose == 2) ? WEBP_MUX_DISPOSE_BACKGROUND
: WEBP_MUX_DISPOSE_NONE;
}
transparent_index = (flags & GIF_TRANSPARENT_MASK) ? data[4] : -1;
if (is_first_frame) {
if (!GetBackgroundColor(gif->SColorMap, gif->SBackGroundColor,
&anim.bgcolor)) {
fprintf(stderr, "GIF decode warning: invalid background color "
"index. Assuming white background.\n");
}
WebPUtilClearPic(&frame, NULL);
}
break;
}
case PLAINTEXT_EXT_FUNC_CODE: {
break;
}
case APPLICATION_EXT_FUNC_CODE: {
if (data[0] != 11) break; // Chunk is too short
if (!memcmp(data + 1, "NETSCAPE2.0", 11)) {
// Recognize and parse Netscape2.0 NAB extension for loop count.
if (DGifGetExtensionNext(gif, &data) == GIF_ERROR) goto End;
if (data == NULL) goto End; // Loop count sub-block missing.
if (data[0] != 3 && data[1] != 1) break; // wrong size/marker
anim.loop_count = data[2] | (data[3] << 8);
if (verbose) printf("Loop count: %d\n", anim.loop_count);
} else { // An extension containing metadata.
// We only store the first encountered chunk of each type, and
// only if requested by the user.
const int is_xmp = (keep_metadata & METADATA_XMP) &&
!stored_xmp &&
!memcmp(data + 1, "XMP DataXMP", 11);
const int is_icc = (keep_metadata & METADATA_ICC) &&
!stored_icc &&
!memcmp(data + 1, "ICCRGBG1012", 11);
if (is_xmp || is_icc) {
const char* const fourccs[2] = { "XMP " , "ICCP" };
const char* const features[2] = { "XMP" , "ICC" };
WebPData metadata = { NULL, 0 };
// Construct metadata from sub-blocks.
// Usual case (including ICC profile): In each sub-block, the
// first byte specifies its size in bytes (0 to 255) and the
// rest of the bytes contain the data.
// Special case for XMP data: In each sub-block, the first byte
// is also part of the XMP payload. XMP in GIF also has a 257
// byte padding data. See the XMP specification for details.
while (1) {
WebPData prev_metadata = metadata;
WebPData subblock;
if (DGifGetExtensionNext(gif, &data) == GIF_ERROR) {
WebPDataClear(&metadata);
goto End;
}
if (data == NULL) break; // Finished.
subblock.size = is_xmp ? data[0] + 1 : data[0];
assert(subblock.size > 0);
subblock.bytes = is_xmp ? data : data + 1;
metadata.bytes =
(uint8_t*)realloc((void*)metadata.bytes,
prev_metadata.size + subblock.size);
if (metadata.bytes == NULL) {
WebPDataClear(&prev_metadata);
goto End;
}
metadata.size += subblock.size;
memcpy((void*)(metadata.bytes + prev_metadata.size),
subblock.bytes, subblock.size);
}
if (is_xmp) {
// XMP padding data is 0x01, 0xff, 0xfe ... 0x01, 0x00.
const size_t xmp_pading_size = 257;
if (metadata.size > xmp_pading_size) {
metadata.size -= xmp_pading_size;
}
}
// Add metadata chunk.
err = WebPMuxSetChunk(mux, fourccs[is_icc], &metadata, 1);
if (verbose) {
printf("%s size: %d\n", features[is_icc], (int)metadata.size);
}
WebPDataClear(&metadata);
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not set %s chunk.\n",
ErrorString(err), features[is_icc]);
goto End;
}
if (is_icc) {
stored_icc = 1;
} else if (is_xmp) {
stored_xmp = 1;
}
}
}
break;
}
default: {
break; // skip
}
}
while (data != NULL) {
if (DGifGetExtensionNext(gif, &data) == GIF_ERROR) goto End;
}
break;
}
case TERMINATE_RECORD_TYPE: {
done = 1;
break;
}
default: {
if (verbose) {
fprintf(stderr, "Skipping over unknown record type %d\n", type);
}
break;
}
}
} while (!done);
// Flush any pending frames.
err = WebPFrameCacheFlushAll(cache, verbose, mux);
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not add animation frame.\n",
ErrorString(err));
goto End;
}
// Finish muxing
err = WebPMuxSetAnimationParams(mux, &anim);
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not set animation parameters.\n",
ErrorString(err));
goto End;
}
err = WebPMuxAssemble(mux, &webp_data);
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s) assembling the WebP file.\n", ErrorString(err));
goto End;
}
if (out_file != NULL) {
if (!ExUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) {
fprintf(stderr, "Error writing output file: %s\n", out_file);
goto End;
}
if (!quiet) {
printf("Saved output file: %s\n", out_file);
}
} else {
if (!quiet) {
printf("Nothing written; use -o flag to save the result.\n");
}
}
// All OK.
ok = 1;
gif_error = GIF_OK;
End:
WebPDataClear(&webp_data);
WebPMuxDelete(mux);
WebPPictureFree(&frame);
WebPFrameCacheDelete(cache);
if (out != NULL && out_file != NULL) fclose(out);
if (gif_error != GIF_OK) {
DisplayGifError(gif, gif_error);
}
if (gif != NULL) {
DGifCloseFile(gif);
}
return !ok;
}
#else // !WEBP_HAVE_GIF
int main(int argc, const char *argv[]) {
fprintf(stderr, "GIF support not enabled in %s.\n", argv[0]);
(void)argc;
return 0;
}
#endif
//------------------------------------------------------------------------------

667
examples/gif2webp_util.c Normal file
View File

@ -0,0 +1,667 @@
// Copyright 2013 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.
// -----------------------------------------------------------------------------
//
// Helper structs and methods for gif2webp tool.
//
#include <assert.h>
#include <stdio.h>
#include "webp/encode.h"
#include "./gif2webp_util.h"
#define DELTA_INFINITY 1ULL << 32
#define KEYFRAME_NONE -1
//------------------------------------------------------------------------------
// Helper utilities.
static void ClearRectangle(WebPPicture* const picture,
int left, int top, int width, int height) {
int j;
for (j = top; j < top + height; ++j) {
uint32_t* const dst = picture->argb + j * picture->argb_stride;
int i;
for (i = left; i < left + width; ++i) {
dst[i] = WEBP_UTIL_TRANSPARENT_COLOR;
}
}
}
void WebPUtilClearPic(WebPPicture* const picture,
const WebPFrameRect* const rect) {
if (rect != NULL) {
ClearRectangle(picture, rect->x_offset, rect->y_offset,
rect->width, rect->height);
} else {
ClearRectangle(picture, 0, 0, picture->width, picture->height);
}
}
// TODO: Also used in picture.c. Move to a common location?
// Copy width x height pixels from 'src' to 'dst' honoring the strides.
static void CopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride, int width, int height) {
while (height-- > 0) {
memcpy(dst, src, width);
src += src_stride;
dst += dst_stride;
}
}
// Copy pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are assumed
// to be already allocated.
static void CopyPixels(const WebPPicture* const src, WebPPicture* const dst) {
assert(src->width == dst->width && src->height == dst->height);
CopyPlane((uint8_t*)src->argb, 4 * src->argb_stride, (uint8_t*)dst->argb,
4 * dst->argb_stride, 4 * src->width, src->height);
}
// Given 'src' picture and its frame rectangle 'rect', blend it into 'dst'.
static void BlendPixels(const WebPPicture* const src,
const WebPFrameRect* const rect,
WebPPicture* const dst) {
int j;
assert(src->width == dst->width && src->height == dst->height);
for (j = rect->y_offset; j < rect->y_offset + rect->height; ++j) {
int i;
for (i = rect->x_offset; i < rect->x_offset + rect->width; ++i) {
const uint32_t src_pixel = src->argb[j * src->argb_stride + i];
const int src_alpha = src_pixel >> 24;
if (src_alpha != 0) {
dst->argb[j * dst->argb_stride + i] = src_pixel;
}
}
}
}
// Replace transparent pixels within 'dst_rect' of 'dst' by those in the 'src'.
static void ReduceTransparency(const WebPPicture* const src,
const WebPFrameRect* const rect,
WebPPicture* const dst) {
int i, j;
assert(src != NULL && dst != NULL && rect != NULL);
assert(src->width == dst->width && src->height == dst->height);
for (j = rect->y_offset; j < rect->y_offset + rect->height; ++j) {
for (i = rect->x_offset; i < rect->x_offset + rect->width; ++i) {
const uint32_t src_pixel = src->argb[j * src->argb_stride + i];
const int src_alpha = src_pixel >> 24;
const uint32_t dst_pixel = dst->argb[j * dst->argb_stride + i];
const int dst_alpha = dst_pixel >> 24;
if (dst_alpha == 0 && src_alpha == 0xff) {
dst->argb[j * dst->argb_stride + i] = src_pixel;
}
}
}
}
// Replace similar blocks of pixels by a 'see-through' transparent block
// with uniform average color.
static void FlattenSimilarBlocks(const WebPPicture* const src,
const WebPFrameRect* const rect,
WebPPicture* const dst) {
int i, j;
const int block_size = 8;
const int y_start = (rect->y_offset + block_size) & ~(block_size - 1);
const int y_end = (rect->y_offset + rect->height) & ~(block_size - 1);
const int x_start = (rect->x_offset + block_size) & ~(block_size - 1);
const int x_end = (rect->x_offset + rect->width) & ~(block_size - 1);
assert(src != NULL && dst != NULL && rect != NULL);
assert(src->width == dst->width && src->height == dst->height);
assert((block_size & (block_size - 1)) == 0); // must be a power of 2
// Iterate over each block and count similar pixels.
for (j = y_start; j < y_end; j += block_size) {
for (i = x_start; i < x_end; i += block_size) {
int cnt = 0;
int avg_r = 0, avg_g = 0, avg_b = 0;
int x, y;
const uint32_t* const psrc = src->argb + j * src->argb_stride + i;
uint32_t* const pdst = dst->argb + j * dst->argb_stride + i;
for (y = 0; y < block_size; ++y) {
for (x = 0; x < block_size; ++x) {
const uint32_t src_pixel = psrc[x + y * src->argb_stride];
const int alpha = src_pixel >> 24;
if (alpha == 0xff &&
src_pixel == pdst[x + y * dst->argb_stride]) {
++cnt;
avg_r += (src_pixel >> 16) & 0xff;
avg_g += (src_pixel >> 8) & 0xff;
avg_b += (src_pixel >> 0) & 0xff;
}
}
}
// If we have a fully similar block, we replace it with an
// average transparent block. This compresses better in lossy mode.
if (cnt == block_size * block_size) {
const uint32_t color = (0x00 << 24) |
((avg_r / cnt) << 16) |
((avg_g / cnt) << 8) |
((avg_b / cnt) << 0);
for (y = 0; y < block_size; ++y) {
for (x = 0; x < block_size; ++x) {
pdst[x + y * dst->argb_stride] = color;
}
}
}
}
}
}
//------------------------------------------------------------------------------
// Key frame related utilities.
// Returns true if 'curr' frame with frame rectangle 'curr_rect' is a key frame,
// that is, it can be decoded independently of 'prev' canvas.
static int IsKeyFrame(const WebPPicture* const curr,
const WebPFrameRect* const curr_rect,
const WebPPicture* const prev) {
int i, j;
int is_key_frame = 1;
// If previous canvas (with previous frame disposed) is all transparent,
// current frame is a key frame.
for (i = 0; i < prev->width; ++i) {
for (j = 0; j < prev->height; ++j) {
const uint32_t prev_alpha = (prev->argb[j * prev->argb_stride + i]) >> 24;
if (prev_alpha != 0) {
is_key_frame = 0;
break;
}
}
if (!is_key_frame) break;
}
if (is_key_frame) return 1;
// If current frame covers the whole canvas and does not contain any
// transparent pixels that depend on previous canvas, then current frame is
// a key frame.
if (curr_rect->width == curr->width && curr_rect->height == curr->height) {
assert(curr_rect->x_offset == 0 && curr_rect->y_offset == 0);
is_key_frame = 1;
for (j = 0; j < prev->height; ++j) {
for (i = 0; i < prev->width; ++i) {
const uint32_t prev_alpha =
(prev->argb[j * prev->argb_stride + i]) >> 24;
const uint32_t curr_alpha =
(curr->argb[j * curr->argb_stride + i]) >> 24;
if (curr_alpha != 0xff && prev_alpha != 0) {
is_key_frame = 0;
break;
}
}
if (!is_key_frame) break;
}
if (is_key_frame) return 1;
}
return 0;
}
// Given 'prev' frame and current frame rectangle 'rect', convert 'curr' frame
// to a key frame.
static void ConvertToKeyFrame(const WebPPicture* const prev,
WebPFrameRect* const rect,
WebPPicture* const curr) {
int j;
assert(curr->width == prev->width && curr->height == prev->height);
// Replace transparent pixels of current canvas with those from previous
// canvas (with previous frame disposed).
for (j = 0; j < curr->height; ++j) {
int i;
for (i = 0; i < curr->width; ++i) {
uint32_t* const curr_pixel = curr->argb + j * curr->argb_stride + i;
const int curr_alpha = *curr_pixel >> 24;
if (curr_alpha == 0) {
*curr_pixel = prev->argb[j * prev->argb_stride + i];
}
}
}
// Frame rectangle now covers the whole canvas.
rect->x_offset = 0;
rect->y_offset = 0;
rect->width = curr->width;
rect->height = curr->height;
}
//------------------------------------------------------------------------------
// Encoded frame.
// Used to store two candidates of encoded data for an animation frame. One of
// the two will be chosen later.
typedef struct {
WebPMuxFrameInfo sub_frame; // Encoded frame rectangle.
WebPMuxFrameInfo key_frame; // Encoded frame if it was converted to keyframe.
} EncodedFrame;
// Release the data contained by 'encoded_frame'.
static void FrameRelease(EncodedFrame* const encoded_frame) {
if (encoded_frame != NULL) {
WebPDataClear(&encoded_frame->sub_frame.bitstream);
WebPDataClear(&encoded_frame->key_frame.bitstream);
memset(encoded_frame, 0, sizeof(*encoded_frame));
}
}
//------------------------------------------------------------------------------
// Frame cache.
// Used to store encoded frames that haven't been output yet.
struct WebPFrameCache {
EncodedFrame* encoded_frames; // Array of encoded frames.
size_t size; // Number of allocated data elements.
size_t start; // Start index.
size_t count; // Number of valid data elements.
int flush_count; // If >0, flush_count frames starting from
// 'start' are ready to be added to mux.
int64_t best_delta; // min(canvas size - frame size) over the frames.
// Can be negative in certain cases due to
// transparent pixels in a frame.
int keyframe; // Index of selected keyframe relative to 'start'.
size_t kmin; // Min distance between key frames.
size_t kmax; // Max distance between key frames.
size_t count_since_key_frame; // Frames seen since the last key frame.
int allow_mixed; // If true, each frame can be lossy or lossless.
WebPPicture prev_canvas; // Previous canvas (properly disposed).
WebPPicture curr_canvas; // Current canvas (temporary buffer).
int is_first_frame; // True if no frames have been added to the cache
// since WebPFrameCacheNew().
};
// Reset the counters in the cache struct. Doesn't touch 'cache->encoded_frames'
// and 'cache->size'.
static void CacheReset(WebPFrameCache* const cache) {
cache->start = 0;
cache->count = 0;
cache->flush_count = 0;
cache->best_delta = DELTA_INFINITY;
cache->keyframe = KEYFRAME_NONE;
}
WebPFrameCache* WebPFrameCacheNew(int width, int height,
size_t kmin, size_t kmax, int allow_mixed) {
WebPFrameCache* cache = (WebPFrameCache*)malloc(sizeof(*cache));
if (cache == NULL) return NULL;
CacheReset(cache);
// sanity init, so we can call WebPFrameCacheDelete():
cache->encoded_frames = NULL;
cache->is_first_frame = 1;
// Picture buffers.
if (!WebPPictureInit(&cache->prev_canvas) ||
!WebPPictureInit(&cache->curr_canvas)) {
return NULL;
}
cache->prev_canvas.width = width;
cache->prev_canvas.height = height;
cache->prev_canvas.use_argb = 1;
if (!WebPPictureAlloc(&cache->prev_canvas) ||
!WebPPictureCopy(&cache->prev_canvas, &cache->curr_canvas)) {
goto Err;
}
WebPUtilClearPic(&cache->prev_canvas, NULL);
// Cache data.
cache->allow_mixed = allow_mixed;
cache->kmin = kmin;
cache->kmax = kmax;
cache->count_since_key_frame = 0;
assert(kmax > kmin);
cache->size = kmax - kmin;
cache->encoded_frames =
(EncodedFrame*)calloc(cache->size, sizeof(*cache->encoded_frames));
if (cache->encoded_frames == NULL) goto Err;
return cache; // All OK.
Err:
WebPFrameCacheDelete(cache);
return NULL;
}
void WebPFrameCacheDelete(WebPFrameCache* const cache) {
if (cache != NULL) {
if (cache->encoded_frames != NULL) {
size_t i;
for (i = 0; i < cache->size; ++i) {
FrameRelease(&cache->encoded_frames[i]);
}
free(cache->encoded_frames);
}
WebPPictureFree(&cache->prev_canvas);
WebPPictureFree(&cache->curr_canvas);
free(cache);
}
}
static int EncodeFrame(const WebPConfig* const config, WebPPicture* const pic,
WebPMemoryWriter* const memory) {
pic->use_argb = 1;
pic->writer = WebPMemoryWrite;
pic->custom_ptr = memory;
if (!WebPEncode(config, pic)) {
return 0;
}
return 1;
}
static void GetEncodedData(const WebPMemoryWriter* const memory,
WebPData* const encoded_data) {
encoded_data->bytes = memory->mem;
encoded_data->size = memory->size;
}
#define MIN_COLORS_LOSSY 31 // Don't try lossy below this threshold.
#define MAX_COLORS_LOSSLESS 194 // Don't try lossless above this threshold.
#define MAX_COLOR_COUNT 256 // Power of 2 greater than MAX_COLORS_LOSSLESS.
#define HASH_SIZE (MAX_COLOR_COUNT * 4)
#define HASH_RIGHT_SHIFT 22 // 32 - log2(HASH_SIZE).
// TODO(urvang): Also used in enc/vp8l.c. Move to utils.
// If the number of colors in the 'pic' is at least MAX_COLOR_COUNT, return
// MAX_COLOR_COUNT. Otherwise, return the exact number of colors in the 'pic'.
static int GetColorCount(const WebPPicture* const pic) {
int x, y;
int num_colors = 0;
uint8_t in_use[HASH_SIZE] = { 0 };
uint32_t colors[HASH_SIZE];
static const uint32_t kHashMul = 0x1e35a7bd;
const uint32_t* argb = pic->argb;
const int width = pic->width;
const int height = pic->height;
uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
int key;
if (argb[x] == last_pix) {
continue;
}
last_pix = argb[x];
key = (kHashMul * last_pix) >> 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; // Exact count not needed.
}
break;
} else if (colors[key] == last_pix) {
break; // The color is already there.
} else {
// Some other color sits here, so do linear conflict resolution.
++key;
key &= (HASH_SIZE - 1); // Key mask.
}
}
}
argb += pic->argb_stride;
}
return num_colors;
}
#undef MAX_COLOR_COUNT
#undef HASH_SIZE
#undef HASH_RIGHT_SHIFT
static int SetFrame(const WebPConfig* const config, int allow_mixed,
int is_key_frame, const WebPPicture* const prev_canvas,
WebPPicture* const frame, const WebPFrameRect* const rect,
const WebPMuxFrameInfo* const info,
WebPPicture* const sub_frame, EncodedFrame* encoded_frame) {
int try_lossless;
int try_lossy;
int try_both;
WebPMemoryWriter mem1, mem2;
WebPData* encoded_data;
WebPMuxFrameInfo* const dst =
is_key_frame ? &encoded_frame->key_frame : &encoded_frame->sub_frame;
*dst = *info;
encoded_data = &dst->bitstream;
WebPMemoryWriterInit(&mem1);
WebPMemoryWriterInit(&mem2);
if (!allow_mixed) {
try_lossless = config->lossless;
try_lossy = !try_lossless;
} else { // Use a heuristic for trying lossless and/or lossy compression.
const int num_colors = GetColorCount(sub_frame);
try_lossless = (num_colors < MAX_COLORS_LOSSLESS);
try_lossy = (num_colors >= MIN_COLORS_LOSSY);
}
try_both = try_lossless && try_lossy;
if (try_lossless) {
WebPConfig config_ll = *config;
config_ll.lossless = 1;
if (!EncodeFrame(&config_ll, sub_frame, &mem1)) {
goto Err;
}
}
if (try_lossy) {
WebPConfig config_lossy = *config;
config_lossy.lossless = 0;
if (!is_key_frame) {
// For lossy compression of a frame, it's better to replace transparent
// pixels of 'curr' with actual RGB values, whenever possible.
ReduceTransparency(prev_canvas, rect, frame);
// TODO(later): Investigate if this helps lossless compression as well.
FlattenSimilarBlocks(prev_canvas, rect, frame);
}
if (!EncodeFrame(&config_lossy, sub_frame, &mem2)) {
goto Err;
}
}
if (try_both) { // Pick the encoding with smallest size.
// TODO(later): Perhaps a rough SSIM/PSNR produced by the encoder should
// also be a criteria, in addition to sizes.
if (mem1.size <= mem2.size) {
free(mem2.mem);
GetEncodedData(&mem1, encoded_data);
} else {
free(mem1.mem);
GetEncodedData(&mem2, encoded_data);
}
} else {
GetEncodedData(try_lossless ? &mem1 : &mem2, encoded_data);
}
return 1;
Err:
free(mem1.mem);
free(mem2.mem);
return 0;
}
#undef MIN_COLORS_LOSSY
#undef MAX_COLORS_LOSSLESS
// Returns cached frame at given 'position' index.
static EncodedFrame* CacheGetFrame(const WebPFrameCache* const cache,
size_t position) {
assert(cache->start + position < cache->size);
return &cache->encoded_frames[cache->start + position];
}
// Calculate the penalty incurred if we encode given frame as a key frame
// instead of a sub-frame.
static int64_t KeyFramePenalty(const EncodedFrame* const encoded_frame) {
return ((int64_t)encoded_frame->key_frame.bitstream.size -
encoded_frame->sub_frame.bitstream.size);
}
static void DisposeFrame(WebPMuxAnimDispose dispose_method,
const WebPFrameRect* const gif_rect,
WebPPicture* const frame, WebPPicture* const canvas) {
if (dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
WebPUtilClearPic(frame, NULL);
WebPUtilClearPic(canvas, gif_rect);
}
}
int WebPFrameCacheAddFrame(WebPFrameCache* const cache,
const WebPConfig* const config,
const WebPFrameRect* const orig_rect,
WebPPicture* const frame,
WebPMuxFrameInfo* const info) {
int ok = 0;
WebPFrameRect rect = *orig_rect;
WebPPicture sub_image; // View extracted from 'frame' with rectangle 'rect'.
WebPPicture* const prev_canvas = &cache->prev_canvas;
const size_t position = cache->count;
const int allow_mixed = cache->allow_mixed;
EncodedFrame* const encoded_frame = CacheGetFrame(cache, position);
assert(position < cache->size);
// Snap to even offsets (and adjust dimensions if needed).
rect.width += (rect.x_offset & 1);
rect.height += (rect.y_offset & 1);
rect.x_offset &= ~1;
rect.y_offset &= ~1;
if (!WebPPictureView(frame, rect.x_offset, rect.y_offset,
rect.width, rect.height, &sub_image)) {
return 0;
}
info->x_offset = rect.x_offset;
info->y_offset = rect.y_offset;
++cache->count;
if (cache->is_first_frame || IsKeyFrame(frame, &rect, prev_canvas)) {
// Add this as a key frame.
if (!SetFrame(config, allow_mixed, 1, NULL, NULL, NULL, info, &sub_image,
encoded_frame)) {
goto End;
}
cache->keyframe = position;
cache->flush_count = cache->count;
cache->count_since_key_frame = 0;
// Update prev_canvas by simply copying from 'curr'.
CopyPixels(frame, prev_canvas);
} else {
++cache->count_since_key_frame;
if (cache->count_since_key_frame <= cache->kmin) {
// Add this as a frame rectangle.
if (!SetFrame(config, allow_mixed, 0, prev_canvas, frame, &rect, info,
&sub_image, encoded_frame)) {
goto End;
}
cache->flush_count = cache->count;
// Update prev_canvas by blending 'curr' into it.
BlendPixels(frame, orig_rect, prev_canvas);
} else {
WebPPicture full_image;
WebPMuxFrameInfo full_image_info;
int frame_added;
int64_t curr_delta;
// Add frame rectangle to cache.
if (!SetFrame(config, allow_mixed, 0, prev_canvas, frame, &rect, info,
&sub_image, encoded_frame)) {
goto End;
}
// Convert to a key frame.
CopyPixels(frame, &cache->curr_canvas);
ConvertToKeyFrame(prev_canvas, &rect, &cache->curr_canvas);
if (!WebPPictureView(&cache->curr_canvas, rect.x_offset, rect.y_offset,
rect.width, rect.height, &full_image)) {
goto End;
}
full_image_info = *info;
full_image_info.x_offset = rect.x_offset;
full_image_info.y_offset = rect.y_offset;
// Add key frame to cache, too.
frame_added = SetFrame(config, allow_mixed, 1, NULL, NULL, NULL,
&full_image_info, &full_image, encoded_frame);
WebPPictureFree(&full_image);
if (!frame_added) goto End;
// Analyze size difference of the two variants.
curr_delta = KeyFramePenalty(encoded_frame);
if (curr_delta <= cache->best_delta) { // Pick this as keyframe.
cache->keyframe = position;
cache->best_delta = curr_delta;
cache->flush_count = cache->count - 1; // We can flush previous frames.
}
if (cache->count_since_key_frame == cache->kmax) {
cache->flush_count = cache->count;
cache->count_since_key_frame = 0;
}
// Update prev_canvas by simply copying from 'curr_canvas'.
CopyPixels(&cache->curr_canvas, prev_canvas);
}
}
DisposeFrame(info->dispose_method, orig_rect, frame, prev_canvas);
cache->is_first_frame = 0;
ok = 1;
End:
WebPPictureFree(&sub_image);
if (!ok) {
FrameRelease(encoded_frame);
--cache->count; // We reset the count, as the frame addition failed.
}
return ok;
}
WebPMuxError WebPFrameCacheFlush(WebPFrameCache* const cache, int verbose,
WebPMux* const mux) {
while (cache->flush_count > 0) {
WebPMuxFrameInfo* info;
WebPMuxError err;
EncodedFrame* const curr = CacheGetFrame(cache, 0);
// Pick frame or full canvas.
if (cache->keyframe == 0) {
info = &curr->key_frame;
info->blend_method = WEBP_MUX_NO_BLEND;
cache->keyframe = KEYFRAME_NONE;
cache->best_delta = DELTA_INFINITY;
} else {
info = &curr->sub_frame;
info->blend_method = WEBP_MUX_BLEND;
}
// Add to mux.
err = WebPMuxPushFrame(mux, info, 1);
if (err != WEBP_MUX_OK) return err;
if (verbose) {
printf("Added frame. offset:%d,%d duration:%d dispose:%d blend:%d\n",
info->x_offset, info->y_offset, info->duration,
info->dispose_method, info->blend_method);
}
FrameRelease(curr);
++cache->start;
--cache->flush_count;
--cache->count;
if (cache->keyframe != KEYFRAME_NONE) --cache->keyframe;
}
if (cache->count == 0) CacheReset(cache);
return WEBP_MUX_OK;
}
WebPMuxError WebPFrameCacheFlushAll(WebPFrameCache* const cache, int verbose,
WebPMux* const mux) {
cache->flush_count = cache->count; // Force flushing of all frames.
return WebPFrameCacheFlush(cache, verbose, mux);
}
//------------------------------------------------------------------------------

80
examples/gif2webp_util.h Normal file
View File

@ -0,0 +1,80 @@
// Copyright 2013 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.
// -----------------------------------------------------------------------------
//
// Helper structs and methods for gif2webp tool.
//
// Author: Urvang (urvang@google.com)
#ifndef WEBP_EXAMPLES_GIF2WEBP_UTIL_H_
#define WEBP_EXAMPLES_GIF2WEBP_UTIL_H_
#include <stdlib.h>
#include "webp/mux.h"
#ifdef __cplusplus
extern "C" {
#endif
//------------------------------------------------------------------------------
// Helper utilities.
#define WEBP_UTIL_TRANSPARENT_COLOR 0x00ffffff
struct WebPPicture;
typedef struct {
int x_offset, y_offset, width, height;
} WebPFrameRect;
// Clear pixels in 'picture' within given 'rect' to transparent color.
void WebPUtilClearPic(struct WebPPicture* const picture,
const WebPFrameRect* const rect);
//------------------------------------------------------------------------------
// Frame cache.
typedef struct WebPFrameCache WebPFrameCache;
// Given the minimum distance between key frames 'kmin' and maximum distance
// between key frames 'kmax', returns an appropriately allocated cache object.
// If 'allow_mixed' is true, the subsequent calls to WebPFrameCacheAddFrame()
// will heuristically pick lossy or lossless compression for each frame.
// Use WebPFrameCacheDelete() to deallocate the 'cache'.
WebPFrameCache* WebPFrameCacheNew(int width, int height,
size_t kmin, size_t kmax, int allow_mixed);
// Release all the frame data from 'cache' and free 'cache'.
void WebPFrameCacheDelete(WebPFrameCache* const cache);
// Given an image described by 'frame', 'info' and 'orig_rect', optimize it for
// WebP, encode it and add it to 'cache'.
// This takes care of frame disposal too, according to 'info->dispose_method'.
int WebPFrameCacheAddFrame(WebPFrameCache* const cache,
const WebPConfig* const config,
const WebPFrameRect* const orig_rect,
WebPPicture* const frame,
WebPMuxFrameInfo* const info);
// Flush the *ready* frames from cache and add them to 'mux'. If 'verbose' is
// true, prints the information about these frames.
WebPMuxError WebPFrameCacheFlush(WebPFrameCache* const cache, int verbose,
WebPMux* const mux);
// Similar to 'WebPFrameCacheFlushFrames()', but flushes *all* the frames.
WebPMuxError WebPFrameCacheFlushAll(WebPFrameCache* const cache, int verbose,
WebPMux* const mux);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_GIF2WEBP_UTIL_H_

293
examples/jpegdec.c Normal file
View File

@ -0,0 +1,293 @@
// 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.
// -----------------------------------------------------------------------------
//
// JPEG decode.
#include "./jpegdec.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef WEBP_HAVE_JPEG
#include <jpeglib.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include "webp/encode.h"
#include "./metadata.h"
// -----------------------------------------------------------------------------
// Metadata processing
#ifndef JPEG_APP1
# define JPEG_APP1 (JPEG_APP0 + 1)
#endif
#ifndef JPEG_APP2
# define JPEG_APP2 (JPEG_APP0 + 2)
#endif
typedef struct {
const uint8_t* data;
size_t data_length;
int seq; // this segment's sequence number [1, 255] for use in reassembly.
} ICCPSegment;
static void SaveMetadataMarkers(j_decompress_ptr dinfo) {
const unsigned int max_marker_length = 0xffff;
jpeg_save_markers(dinfo, JPEG_APP1, max_marker_length); // Exif/XMP
jpeg_save_markers(dinfo, JPEG_APP2, max_marker_length); // ICC profile
}
static int CompareICCPSegments(const void* a, const void* b) {
const ICCPSegment* s1 = (const ICCPSegment*)a;
const ICCPSegment* s2 = (const ICCPSegment*)b;
return s1->seq - s2->seq;
}
// Extract ICC profile segments from the marker list in 'dinfo', reassembling
// and storing them in 'iccp'.
// Returns true on success and false for memory errors and corrupt profiles.
static int StoreICCP(j_decompress_ptr dinfo, MetadataPayload* const iccp) {
// ICC.1:2010-12 (4.3.0.0) Annex B.4 Embedding ICC Profiles in JPEG files
static const char kICCPSignature[] = "ICC_PROFILE";
static const size_t kICCPSignatureLength = 12; // signature includes '\0'
static const size_t kICCPSkipLength = 14; // signature + seq & count
int expected_count = 0;
int actual_count = 0;
int seq_max = 0;
size_t total_size = 0;
ICCPSegment iccp_segments[255];
jpeg_saved_marker_ptr marker;
memset(iccp_segments, 0, sizeof(iccp_segments));
for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) {
if (marker->marker == JPEG_APP2 &&
marker->data_length > kICCPSkipLength &&
!memcmp(marker->data, kICCPSignature, kICCPSignatureLength)) {
// ICC_PROFILE\0<seq><count>; 'seq' starts at 1.
const int seq = marker->data[kICCPSignatureLength];
const int count = marker->data[kICCPSignatureLength + 1];
const size_t segment_size = marker->data_length - kICCPSkipLength;
ICCPSegment* segment;
if (segment_size == 0 || count == 0 || seq == 0) {
fprintf(stderr, "[ICCP] size (%d) / count (%d) / sequence number (%d)"
" cannot be 0!\n",
(int)segment_size, seq, count);
return 0;
}
if (expected_count == 0) {
expected_count = count;
} else if (expected_count != count) {
fprintf(stderr, "[ICCP] Inconsistent segment count (%d / %d)!\n",
expected_count, count);
return 0;
}
segment = iccp_segments + seq - 1;
if (segment->data_length != 0) {
fprintf(stderr, "[ICCP] Duplicate segment number (%d)!\n" , seq);
return 0;
}
segment->data = marker->data + kICCPSkipLength;
segment->data_length = segment_size;
segment->seq = seq;
total_size += segment_size;
if (seq > seq_max) seq_max = seq;
++actual_count;
}
}
if (actual_count == 0) return 1;
if (seq_max != actual_count) {
fprintf(stderr, "[ICCP] Discontinuous segments, expected: %d actual: %d!\n",
actual_count, seq_max);
return 0;
}
if (expected_count != actual_count) {
fprintf(stderr, "[ICCP] Segment count: %d does not match expected: %d!\n",
actual_count, expected_count);
return 0;
}
// The segments may appear out of order in the file, sort them based on
// sequence number before assembling the payload.
qsort(iccp_segments, actual_count, sizeof(*iccp_segments),
CompareICCPSegments);
iccp->bytes = (uint8_t*)malloc(total_size);
if (iccp->bytes == NULL) return 0;
iccp->size = total_size;
{
int i;
size_t offset = 0;
for (i = 0; i < seq_max; ++i) {
memcpy(iccp->bytes + offset,
iccp_segments[i].data, iccp_segments[i].data_length);
offset += iccp_segments[i].data_length;
}
}
return 1;
}
// Returns true on success and false for memory errors and corrupt profiles.
// The caller must use MetadataFree() on 'metadata' in all cases.
static int ExtractMetadataFromJPEG(j_decompress_ptr dinfo,
Metadata* const metadata) {
static const struct {
int marker;
const char* signature;
size_t signature_length;
size_t storage_offset;
} kJPEGMetadataMap[] = {
// Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ...
{ JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif) },
// XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG
// TODO(jzern) Add support for 'ExtendedXMP'
{ JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp) },
{ 0, NULL, 0, 0 },
};
jpeg_saved_marker_ptr marker;
// Treat ICC profiles separately as they may be segmented and out of order.
if (!StoreICCP(dinfo, &metadata->iccp)) return 0;
for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) {
int i;
for (i = 0; kJPEGMetadataMap[i].marker != 0; ++i) {
if (marker->marker == kJPEGMetadataMap[i].marker &&
marker->data_length > kJPEGMetadataMap[i].signature_length &&
!memcmp(marker->data, kJPEGMetadataMap[i].signature,
kJPEGMetadataMap[i].signature_length)) {
MetadataPayload* const payload =
(MetadataPayload*)((uint8_t*)metadata +
kJPEGMetadataMap[i].storage_offset);
if (payload->bytes == NULL) {
const char* marker_data = (const char*)marker->data +
kJPEGMetadataMap[i].signature_length;
const size_t marker_data_length =
marker->data_length - kJPEGMetadataMap[i].signature_length;
if (!MetadataCopy(marker_data, marker_data_length, payload)) return 0;
} else {
fprintf(stderr, "Ignoring additional '%s' marker\n",
kJPEGMetadataMap[i].signature);
}
}
}
}
return 1;
}
#undef JPEG_APP1
#undef JPEG_APP2
// -----------------------------------------------------------------------------
// JPEG decoding
struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
static void my_error_exit(j_common_ptr dinfo) {
struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err;
dinfo->err->output_message(dinfo);
longjmp(myerr->setjmp_buffer, 1);
}
int ReadJPEG(FILE* in_file, WebPPicture* const pic, Metadata* const metadata) {
int ok = 0;
int stride, width, height;
struct jpeg_decompress_struct dinfo;
struct my_error_mgr jerr;
uint8_t* rgb = NULL;
JSAMPROW buffer[1];
dinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
Error:
MetadataFree(metadata);
jpeg_destroy_decompress(&dinfo);
goto End;
}
jpeg_create_decompress(&dinfo);
jpeg_stdio_src(&dinfo, in_file);
if (metadata != NULL) SaveMetadataMarkers(&dinfo);
jpeg_read_header(&dinfo, TRUE);
dinfo.out_color_space = JCS_RGB;
dinfo.do_fancy_upsampling = TRUE;
jpeg_start_decompress(&dinfo);
if (dinfo.output_components != 3) {
goto Error;
}
width = dinfo.output_width;
height = dinfo.output_height;
stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb);
rgb = (uint8_t*)malloc(stride * height);
if (rgb == NULL) {
goto End;
}
buffer[0] = (JSAMPLE*)rgb;
while (dinfo.output_scanline < dinfo.output_height) {
if (jpeg_read_scanlines(&dinfo, buffer, 1) != 1) {
goto End;
}
buffer[0] += stride;
}
if (metadata != NULL) {
ok = ExtractMetadataFromJPEG(&dinfo, metadata);
if (!ok) {
fprintf(stderr, "Error extracting JPEG metadata!\n");
goto Error;
}
}
jpeg_finish_decompress(&dinfo);
jpeg_destroy_decompress(&dinfo);
// WebP conversion.
pic->width = width;
pic->height = height;
ok = WebPPictureImportRGB(pic, rgb, stride);
if (!ok) goto Error;
End:
free(rgb);
return ok;
}
#else // !WEBP_HAVE_JPEG
int ReadJPEG(FILE* in_file, struct WebPPicture* const pic,
struct Metadata* const metadata) {
(void)in_file;
(void)pic;
(void)metadata;
fprintf(stderr, "JPEG support not compiled. Please install the libjpeg "
"development package before building.\n");
return 0;
}
#endif // WEBP_HAVE_JPEG
// -----------------------------------------------------------------------------

35
examples/jpegdec.h Normal file
View File

@ -0,0 +1,35 @@
// 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.
// -----------------------------------------------------------------------------
//
// JPEG decode.
#ifndef WEBP_EXAMPLES_JPEGDEC_H_
#define WEBP_EXAMPLES_JPEGDEC_H_
#include <stdio.h>
#include "webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
struct Metadata;
struct WebPPicture;
// Reads a JPEG from 'in_file', returning the decoded output in 'pic'.
// The output is RGB.
// Returns true on success.
int ReadJPEG(FILE* in_file, struct WebPPicture* const pic,
struct Metadata* const metadata);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_JPEGDEC_H_

49
examples/metadata.c Normal file
View File

@ -0,0 +1,49 @@
// 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.
// -----------------------------------------------------------------------------
//
// Metadata types and functions.
//
#include "./metadata.h"
#include <stdlib.h>
#include <string.h>
#include "webp/types.h"
void MetadataInit(Metadata* const metadata) {
if (metadata == NULL) return;
memset(metadata, 0, sizeof(*metadata));
}
void MetadataPayloadDelete(MetadataPayload* const payload) {
if (payload == NULL) return;
free(payload->bytes);
payload->bytes = NULL;
payload->size = 0;
}
void MetadataFree(Metadata* const metadata) {
if (metadata == NULL) return;
MetadataPayloadDelete(&metadata->exif);
MetadataPayloadDelete(&metadata->iccp);
MetadataPayloadDelete(&metadata->xmp);
}
int MetadataCopy(const char* metadata, size_t metadata_len,
MetadataPayload* const payload) {
if (metadata == NULL || metadata_len == 0 || payload == NULL) return 0;
payload->bytes = (uint8_t*)malloc(metadata_len);
if (payload->bytes == NULL) return 0;
payload->size = metadata_len;
memcpy(payload->bytes, metadata, metadata_len);
return 1;
}
// -----------------------------------------------------------------------------

47
examples/metadata.h Normal file
View File

@ -0,0 +1,47 @@
// 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.
// -----------------------------------------------------------------------------
//
// Metadata types and functions.
//
#ifndef WEBP_EXAMPLES_METADATA_H_
#define WEBP_EXAMPLES_METADATA_H_
#include "webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct MetadataPayload {
uint8_t* bytes;
size_t size;
} MetadataPayload;
typedef struct Metadata {
MetadataPayload exif;
MetadataPayload iccp;
MetadataPayload xmp;
} Metadata;
#define METADATA_OFFSET(x) offsetof(Metadata, x)
void MetadataInit(Metadata* const metadata);
void MetadataPayloadDelete(MetadataPayload* const payload);
void MetadataFree(Metadata* const metadata);
// Stores 'metadata' to 'payload->bytes', returns false on allocation error.
int MetadataCopy(const char* metadata, size_t metadata_len,
MetadataPayload* const payload);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_METADATA_H_

299
examples/pngdec.c Normal file
View File

@ -0,0 +1,299 @@
// 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.
// -----------------------------------------------------------------------------
//
// PNG decode.
#include "./pngdec.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef WEBP_HAVE_PNG
#include <png.h>
#include <setjmp.h> // note: this must be included *after* png.h
#include <stdlib.h>
#include <string.h>
#include "webp/encode.h"
#include "./metadata.h"
static void PNGAPI error_function(png_structp png, png_const_charp error) {
if (error != NULL) fprintf(stderr, "libpng error: %s\n", error);
longjmp(png_jmpbuf(png), 1);
}
// Converts the NULL terminated 'hexstring' which contains 2-byte character
// representations of hex values to raw data.
// 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs,
// e.g., 7af2..., separated by any number of newlines.
// 'expected_length' is the anticipated processed size.
// On success the raw buffer is returned with its length equivalent to
// 'expected_length'. NULL is returned if the processed length is less than
// 'expected_length' or any character aside from those above is encountered.
// The returned buffer must be freed by the caller.
static uint8_t* HexStringToBytes(const char* hexstring,
size_t expected_length) {
const char* src = hexstring;
size_t actual_length = 0;
uint8_t* const raw_data = (uint8_t*)malloc(expected_length);
uint8_t* dst;
if (raw_data == NULL) return NULL;
for (dst = raw_data; actual_length < expected_length && *src != '\0'; ++src) {
char* end;
char val[3];
if (*src == '\n') continue;
val[0] = *src++;
val[1] = *src;
val[2] = '\0';
*dst++ = (uint8_t)strtol(val, &end, 16);
if (end != val + 2) break;
++actual_length;
}
if (actual_length != expected_length) {
free(raw_data);
return NULL;
}
return raw_data;
}
static int ProcessRawProfile(const char* profile, size_t profile_len,
MetadataPayload* const payload) {
const char* src = profile;
char* end;
int expected_length;
if (profile == NULL || profile_len == 0) return 0;
// ImageMagick formats 'raw profiles' as
// '\n<name>\n<length>(%8lu)\n<hex payload>\n'.
if (*src != '\n') {
fprintf(stderr, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n",
*src);
return 0;
}
++src;
// skip the profile name and extract the length.
while (*src != '\0' && *src++ != '\n') {}
expected_length = (int)strtol(src, &end, 10);
if (*end != '\n') {
fprintf(stderr, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n",
*end);
return 0;
}
++end;
// 'end' now points to the profile payload.
payload->bytes = HexStringToBytes(end, expected_length);
if (payload->bytes == NULL) return 0;
payload->size = expected_length;
return 1;
}
static const struct {
const char* name;
int (*process)(const char* profile, size_t profile_len,
MetadataPayload* const payload);
size_t storage_offset;
} kPNGMetadataMap[] = {
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData
// See also: ExifTool on CPAN.
{ "Raw profile type exif", ProcessRawProfile, METADATA_OFFSET(exif) },
{ "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) },
// Exiftool puts exif data in APP1 chunk, too.
{ "Raw profile type APP1", ProcessRawProfile, METADATA_OFFSET(exif) },
// XMP Specification Part 3, Section 3 #PNG
{ "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) },
{ NULL, NULL, 0 },
};
// Looks for metadata at both the beginning and end of the PNG file, giving
// preference to the head.
// Returns true on success. The caller must use MetadataFree() on 'metadata' in
// all cases.
static int ExtractMetadataFromPNG(png_structp png,
png_infop const head_info,
png_infop const end_info,
Metadata* const metadata) {
int p;
for (p = 0; p < 2; ++p) {
png_infop const info = (p == 0) ? head_info : end_info;
png_textp text = NULL;
const int num = png_get_text(png, info, &text, NULL);
int i;
// Look for EXIF / XMP metadata.
for (i = 0; i < num; ++i, ++text) {
int j;
for (j = 0; kPNGMetadataMap[j].name != NULL; ++j) {
if (!strcmp(text->key, kPNGMetadataMap[j].name)) {
MetadataPayload* const payload =
(MetadataPayload*)((uint8_t*)metadata +
kPNGMetadataMap[j].storage_offset);
png_size_t text_length;
switch (text->compression) {
#ifdef PNG_iTXt_SUPPORTED
case PNG_ITXT_COMPRESSION_NONE:
case PNG_ITXT_COMPRESSION_zTXt:
text_length = text->itxt_length;
break;
#endif
case PNG_TEXT_COMPRESSION_NONE:
case PNG_TEXT_COMPRESSION_zTXt:
default:
text_length = text->text_length;
break;
}
if (payload->bytes != NULL) {
fprintf(stderr, "Ignoring additional '%s'\n", text->key);
} else if (!kPNGMetadataMap[j].process(text->text, text_length,
payload)) {
fprintf(stderr, "Failed to process: '%s'\n", text->key);
return 0;
}
break;
}
}
}
// Look for an ICC profile.
{
png_charp name;
int comp_type;
#if ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR << 0) < \
((1 << 8) | (5 << 0))
png_charp profile;
#else // >= libpng 1.5.0
png_bytep profile;
#endif
png_uint_32 len;
if (png_get_iCCP(png, info,
&name, &comp_type, &profile, &len) == PNG_INFO_iCCP) {
if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0;
}
}
}
return 1;
}
int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) {
png_structp png;
png_infop info = NULL;
png_infop end_info = NULL;
int color_type, bit_depth, interlaced;
int has_alpha;
int num_passes;
int p;
int ok = 0;
png_uint_32 width, height, y;
int stride;
uint8_t* rgb = NULL;
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (png == NULL) {
goto End;
}
png_set_error_fn(png, 0, error_function, NULL);
if (setjmp(png_jmpbuf(png))) {
Error:
MetadataFree(metadata);
png_destroy_read_struct(&png, &info, &end_info);
goto End;
}
info = png_create_info_struct(png);
if (info == NULL) goto Error;
end_info = png_create_info_struct(png);
if (end_info == NULL) goto Error;
png_init_io(png, in_file);
png_read_info(png, info);
if (!png_get_IHDR(png, info,
&width, &height, &bit_depth, &color_type, &interlaced,
NULL, NULL)) goto Error;
png_set_strip_16(png);
png_set_packing(png);
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
if (bit_depth < 8) {
png_set_expand_gray_1_2_4_to_8(png);
}
png_set_gray_to_rgb(png);
}
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png);
has_alpha = 1;
} else {
has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
}
if (!keep_alpha) {
png_set_strip_alpha(png);
has_alpha = 0;
}
num_passes = png_set_interlace_handling(png);
png_read_update_info(png, info);
stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
rgb = (uint8_t*)malloc(stride * height);
if (rgb == NULL) goto Error;
for (p = 0; p < num_passes; ++p) {
for (y = 0; y < height; ++y) {
png_bytep row = rgb + y * stride;
png_read_rows(png, &row, NULL, 1);
}
}
png_read_end(png, end_info);
if (metadata != NULL &&
!ExtractMetadataFromPNG(png, info, end_info, metadata)) {
fprintf(stderr, "Error extracting PNG metadata!\n");
goto Error;
}
png_destroy_read_struct(&png, &info, &end_info);
pic->width = width;
pic->height = height;
pic->use_argb = 1;
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
: WebPPictureImportRGB(pic, rgb, stride);
if (!ok) {
goto Error;
}
End:
free(rgb);
return ok;
}
#else // !WEBP_HAVE_PNG
int ReadPNG(FILE* in_file, struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata) {
(void)in_file;
(void)pic;
(void)keep_alpha;
(void)metadata;
fprintf(stderr, "PNG support not compiled. Please install the libpng "
"development package before building.\n");
return 0;
}
#endif // WEBP_HAVE_PNG
// -----------------------------------------------------------------------------

35
examples/pngdec.h Normal file
View File

@ -0,0 +1,35 @@
// 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.
// -----------------------------------------------------------------------------
//
// PNG decode.
#ifndef WEBP_EXAMPLES_PNGDEC_H_
#define WEBP_EXAMPLES_PNGDEC_H_
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
struct Metadata;
struct WebPPicture;
// Reads a PNG from 'in_file', returning the decoded output in 'pic'.
// If 'keep_alpha' is true and the PNG has an alpha channel, the output is RGBA
// otherwise it will be RGB.
// Returns true on success.
int ReadPNG(FILE* in_file, struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_PNGDEC_H_

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Helper functions to measure elapsed time.
@ -12,12 +14,16 @@
#ifndef WEBP_EXAMPLES_STOPWATCH_H_
#define WEBP_EXAMPLES_STOPWATCH_H_
#ifdef _WIN32
#if defined _WIN32 && !defined __GNUC__
#include <windows.h>
typedef LARGE_INTEGER Stopwatch;
static inline double StopwatchReadAndReset(Stopwatch* watch) {
static WEBP_INLINE void StopwatchReset(Stopwatch* watch) {
QueryPerformanceCounter(watch);
}
static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) {
const LARGE_INTEGER old_value = *watch;
LARGE_INTEGER freq;
if (!QueryPerformanceCounter(watch))
@ -35,7 +41,11 @@ static inline double StopwatchReadAndReset(Stopwatch* watch) {
typedef struct timeval Stopwatch;
static inline double StopwatchReadAndReset(Stopwatch* watch) {
static WEBP_INLINE void StopwatchReset(Stopwatch* watch) {
gettimeofday(watch, NULL);
}
static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) {
const struct timeval old_value = *watch;
gettimeofday(watch, NULL);
return watch->tv_sec - old_value.tv_sec +

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

141
examples/tiffdec.c Normal file
View File

@ -0,0 +1,141 @@
// 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.
// -----------------------------------------------------------------------------
//
// TIFF decode.
#include "./tiffdec.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef WEBP_HAVE_TIFF
#include <tiffio.h>
#include "webp/encode.h"
#include "./metadata.h"
static const struct {
ttag_t tag;
size_t storage_offset;
} kTIFFMetadataMap[] = {
{ TIFFTAG_ICCPROFILE, METADATA_OFFSET(iccp) },
{ TIFFTAG_XMLPACKET, METADATA_OFFSET(xmp) },
{ 0, 0 },
};
// Returns true on success. The caller must use MetadataFree() on 'metadata' in
// all cases.
static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) {
int i;
toff_t exif_ifd_offset;
for (i = 0; kTIFFMetadataMap[i].tag != 0; ++i) {
MetadataPayload* const payload =
(MetadataPayload*)((uint8_t*)metadata +
kTIFFMetadataMap[i].storage_offset);
void* tag_data;
uint32 tag_data_len;
if (TIFFGetField(tif, kTIFFMetadataMap[i].tag, &tag_data_len, &tag_data) &&
!MetadataCopy((const char*)tag_data, tag_data_len, payload)) {
return 0;
}
}
// TODO(jzern): To extract the raw EXIF directory some parsing of it would be
// necessary to determine the overall size. In addition, value offsets in
// individual directory entries may need to be updated as, depending on the
// type, they are file based.
// Exif 2.2 Section 4.6.2 Tag Structure
// TIFF Revision 6.0 Part 1 Section 2 TIFF Structure #Image File Directory
if (TIFFGetField(tif, TIFFTAG_EXIFIFD, &exif_ifd_offset)) {
fprintf(stderr, "Warning: EXIF extraction from TIFF is unsupported.\n");
}
return 1;
}
int ReadTIFF(const char* const filename,
WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) {
TIFF* const tif = TIFFOpen(filename, "r");
uint32 width, height;
uint32* raster;
int ok = 0;
tdir_t dircount;
if (tif == NULL) {
fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
return 0;
}
dircount = TIFFNumberOfDirectories(tif);
if (dircount > 1) {
fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n"
"Only the first will be used, %d will be ignored.\n",
dircount - 1);
}
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) &&
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) {
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
return 0;
}
raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster));
if (raster != NULL) {
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
ORIENTATION_TOPLEFT, 1)) {
const int stride = width * sizeof(*raster);
pic->width = width;
pic->height = height;
// TIFF data is ABGR
#ifdef __BIG_ENDIAN__
TIFFSwabArrayOfLong(raster, width * height);
#endif
pic->use_argb = 1;
ok = keep_alpha
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
}
_TIFFfree(raster);
} else {
fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
}
if (ok) {
if (metadata != NULL) {
ok = ExtractMetadataFromTIFF(tif, metadata);
if (!ok) {
fprintf(stderr, "Error extracting TIFF metadata!\n");
MetadataFree(metadata);
WebPPictureFree(pic);
}
}
}
TIFFClose(tif);
return ok;
}
#else // !WEBP_HAVE_TIFF
int ReadTIFF(const char* const filename,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata) {
(void)filename;
(void)pic;
(void)keep_alpha;
(void)metadata;
fprintf(stderr, "TIFF support not compiled. Please install the libtiff "
"development package before building.\n");
return 0;
}
#endif // WEBP_HAVE_TIFF
// -----------------------------------------------------------------------------

34
examples/tiffdec.h Normal file
View File

@ -0,0 +1,34 @@
// 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.
// -----------------------------------------------------------------------------
//
// TIFF decode.
#ifndef WEBP_EXAMPLES_TIFFDEC_H_
#define WEBP_EXAMPLES_TIFFDEC_H_
#ifdef __cplusplus
extern "C" {
#endif
struct Metadata;
struct WebPPicture;
// Reads a TIFF from 'filename', returning the decoded output in 'pic'.
// If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA
// otherwise it will be RGB.
// Returns true on success.
int ReadTIFF(const char* const filename,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_TIFFDEC_H_

536
examples/vwebp.c Normal file
View File

@ -0,0 +1,536 @@
// Copyright 2011 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.
// -----------------------------------------------------------------------------
//
// Simple OpenGL-based WebP file viewer.
//
// Author: Skal (pascal.massimino@gmail.com)
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(WEBP_HAVE_GL)
#if defined(HAVE_GLUT_GLUT_H)
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#ifdef FREEGLUT
#include <GL/freeglut.h>
#endif
#endif
#ifdef WEBP_HAVE_QCMS
#include <qcms.h>
#endif
#include "webp/decode.h"
#include "webp/demux.h"
#include "./example_util.h"
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
static void Help(void);
// Unfortunate global variables. Gathered into a struct for comfort.
static struct {
int has_animation;
int has_color_profile;
int done;
int decoding_error;
int print_info;
int use_color_profile;
int canvas_width, canvas_height;
int loop_count;
uint32_t bg_color;
const char* file_name;
WebPData data;
WebPDecoderConfig config;
const WebPDecBuffer* pic;
WebPDemuxer* dmux;
WebPIterator curr_frame;
WebPIterator prev_frame;
WebPChunkIterator iccp;
} kParams;
static void ClearPreviousPic(void) {
WebPFreeDecBuffer((WebPDecBuffer*)kParams.pic);
kParams.pic = NULL;
}
static void ClearParams(void) {
ClearPreviousPic();
WebPDataClear(&kParams.data);
WebPDemuxReleaseIterator(&kParams.curr_frame);
WebPDemuxReleaseIterator(&kParams.prev_frame);
WebPDemuxReleaseChunkIterator(&kParams.iccp);
WebPDemuxDelete(kParams.dmux);
kParams.dmux = NULL;
}
// -----------------------------------------------------------------------------
// Color profile handling
static int ApplyColorProfile(const WebPData* const profile,
WebPDecBuffer* const rgba) {
#ifdef WEBP_HAVE_QCMS
int i, ok = 0;
uint8_t* line;
uint8_t major_revision;
qcms_profile* input_profile = NULL;
qcms_profile* output_profile = NULL;
qcms_transform* transform = NULL;
const qcms_data_type input_type = QCMS_DATA_RGBA_8;
const qcms_data_type output_type = QCMS_DATA_RGBA_8;
const qcms_intent intent = QCMS_INTENT_DEFAULT;
if (profile == NULL || rgba == NULL) return 0;
if (profile->bytes == NULL || profile->size < 10) return 1;
major_revision = profile->bytes[8];
qcms_enable_iccv4();
input_profile = qcms_profile_from_memory(profile->bytes, profile->size);
// qcms_profile_is_bogus() is broken with ICCv4.
if (input_profile == NULL ||
(major_revision < 4 && qcms_profile_is_bogus(input_profile))) {
fprintf(stderr, "Color profile is bogus!\n");
goto Error;
}
output_profile = qcms_profile_sRGB();
if (output_profile == NULL) {
fprintf(stderr, "Error creating output color profile!\n");
goto Error;
}
qcms_profile_precache_output_transform(output_profile);
transform = qcms_transform_create(input_profile, input_type,
output_profile, output_type,
intent);
if (transform == NULL) {
fprintf(stderr, "Error creating color transform!\n");
goto Error;
}
line = rgba->u.RGBA.rgba;
for (i = 0; i < rgba->height; ++i, line += rgba->u.RGBA.stride) {
qcms_transform_data(transform, line, line, rgba->width);
}
ok = 1;
Error:
if (input_profile != NULL) qcms_profile_release(input_profile);
if (output_profile != NULL) qcms_profile_release(output_profile);
if (transform != NULL) qcms_transform_release(transform);
return ok;
#else
(void)profile;
(void)rgba;
return 1;
#endif // WEBP_HAVE_QCMS
}
//------------------------------------------------------------------------------
// File decoding
static int Decode(void) { // Fills kParams.curr_frame
const WebPIterator* const curr = &kParams.curr_frame;
WebPDecoderConfig* const config = &kParams.config;
WebPDecBuffer* const output_buffer = &config->output;
int ok = 0;
ClearPreviousPic();
output_buffer->colorspace = MODE_RGBA;
ok = (WebPDecode(curr->fragment.bytes, curr->fragment.size,
config) == VP8_STATUS_OK);
if (!ok) {
fprintf(stderr, "Decoding of frame #%d failed!\n", curr->frame_num);
} else {
kParams.pic = output_buffer;
if (kParams.use_color_profile) {
ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer);
if (!ok) {
fprintf(stderr, "Applying color profile to frame #%d failed!\n",
curr->frame_num);
}
}
}
return ok;
}
static void decode_callback(int what) {
if (what == 0 && !kParams.done) {
int duration = 0;
if (kParams.dmux != NULL) {
WebPIterator* const curr = &kParams.curr_frame;
if (!WebPDemuxNextFrame(curr)) {
WebPDemuxReleaseIterator(curr);
if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) {
--kParams.loop_count;
kParams.done = (kParams.loop_count == 0);
} else {
kParams.decoding_error = 1;
kParams.done = 1;
return;
}
}
duration = curr->duration;
}
if (!Decode()) {
kParams.decoding_error = 1;
kParams.done = 1;
} else {
glutPostRedisplay();
glutTimerFunc(duration, decode_callback, what);
}
}
}
//------------------------------------------------------------------------------
// Callbacks
static void HandleKey(unsigned char key, int pos_x, int pos_y) {
(void)pos_x;
(void)pos_y;
if (key == 'q' || key == 'Q' || key == 27 /* Esc */) {
#ifdef FREEGLUT
glutLeaveMainLoop();
#else
ClearParams();
exit(0);
#endif
} else if (key == 'c') {
if (kParams.has_color_profile && !kParams.decoding_error) {
kParams.use_color_profile = 1 - kParams.use_color_profile;
if (kParams.has_animation) {
// Restart the completed animation to pickup the color profile change.
if (kParams.done && kParams.loop_count == 0) {
kParams.loop_count =
(int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT) + 1;
kParams.done = 0;
// Start the decode loop immediately.
glutTimerFunc(0, decode_callback, 0);
}
} else {
Decode();
glutPostRedisplay();
}
}
} else if (key == 'i') {
kParams.print_info = 1 - kParams.print_info;
glutPostRedisplay();
}
}
static void HandleReshape(int width, int height) {
// TODO(skal): proper handling of resize, esp. for large pictures.
// + key control of the zoom.
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
static void PrintString(const char* const text) {
void* const font = GLUT_BITMAP_9_BY_15;
int i;
for (i = 0; text[i]; ++i) {
glutBitmapCharacter(font, text[i]);
}
}
static float GetColorf(uint32_t color, int shift) {
return (color >> shift) / 255.f;
}
static void DrawCheckerBoard(void) {
const int square_size = 8; // must be a power of 2
int x, y;
GLint viewport[4]; // x, y, width, height
glPushMatrix();
glGetIntegerv(GL_VIEWPORT, viewport);
// shift to integer coordinates with (0,0) being top-left.
glOrtho(0, viewport[2], viewport[3], 0, -1, 1);
for (y = 0; y < viewport[3]; y += square_size) {
for (x = 0; x < viewport[2]; x += square_size) {
const GLubyte color = 128 + 64 * (!((x + y) & square_size));
glColor3ub(color, color, color);
glRecti(x, y, x + square_size, y + square_size);
}
}
glPopMatrix();
}
static void HandleDisplay(void) {
const WebPDecBuffer* const pic = kParams.pic;
const WebPIterator* const curr = &kParams.curr_frame;
WebPIterator* const prev = &kParams.prev_frame;
GLfloat xoff, yoff;
if (pic == NULL) return;
glPushMatrix();
glPixelZoom(1, -1);
xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width);
yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height);
glRasterPos2f(-1.f + xoff, 1.f - yoff);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
curr->blend_method == WEBP_MUX_NO_BLEND) {
// TODO(later): these offsets and those above should factor in window size.
// they will be incorrect if the window is resized.
// glScissor() takes window coordinates (0,0 at bottom left).
int window_x, window_y;
if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
// Clear the previous frame rectangle.
window_x = prev->x_offset;
window_y = kParams.canvas_height - prev->y_offset - prev->height;
} else { // curr->blend_method == WEBP_MUX_NO_BLEND.
// We simulate no-blending behavior by first clearing the current frame
// rectangle (to a checker-board) and then alpha-blending against it.
window_x = curr->x_offset;
window_y = kParams.canvas_height - curr->y_offset - curr->height;
}
glEnable(GL_SCISSOR_TEST);
// Only update the requested area, not the whole canvas.
glScissor(window_x, window_y, prev->width, prev->height);
glClear(GL_COLOR_BUFFER_BIT); // use clear color
DrawCheckerBoard();
glDisable(GL_SCISSOR_TEST);
}
*prev = *curr;
glDrawPixels(pic->width, pic->height,
GL_RGBA, GL_UNSIGNED_BYTE,
(GLvoid*)pic->u.RGBA.rgba);
if (kParams.print_info) {
char tmp[32];
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
glRasterPos2f(-0.95f, 0.90f);
PrintString(kParams.file_name);
snprintf(tmp, sizeof(tmp), "Dimension:%d x %d", pic->width, pic->height);
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
glRasterPos2f(-0.95f, 0.80f);
PrintString(tmp);
if (curr->x_offset != 0 || curr->y_offset != 0) {
snprintf(tmp, sizeof(tmp), " (offset:%d,%d)",
curr->x_offset, curr->y_offset);
glRasterPos2f(-0.95f, 0.70f);
PrintString(tmp);
}
}
glPopMatrix();
glFlush();
}
static void StartDisplay(void) {
const int width = kParams.canvas_width;
const int height = kParams.canvas_height;
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(width, height);
glutCreateWindow("WebP viewer");
glutDisplayFunc(HandleDisplay);
glutIdleFunc(NULL);
glutKeyboardFunc(HandleKey);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glClearColor(GetColorf(kParams.bg_color, 0),
GetColorf(kParams.bg_color, 8),
GetColorf(kParams.bg_color, 16),
GetColorf(kParams.bg_color, 24));
HandleReshape(width, height);
glClear(GL_COLOR_BUFFER_BIT);
DrawCheckerBoard();
}
//------------------------------------------------------------------------------
// Main
static void Help(void) {
printf("Usage: vwebp in_file [options]\n\n"
"Decodes the WebP image file and visualize it using OpenGL\n"
"Options are:\n"
" -version .... print version number and exit.\n"
" -noicc ....... don't use the icc profile if present.\n"
" -nofancy ..... don't use the fancy YUV420 upscaler.\n"
" -nofilter .... disable in-loop filtering.\n"
" -dither <int> dithering strength (0..100). Default=50.\n"
" -mt .......... use multi-threading.\n"
" -info ........ print info.\n"
" -h ....... this help message.\n"
"\n"
"Keyboard shortcuts:\n"
" 'c' ................ toggle use of color profile.\n"
" 'i' ................ overlay file information.\n"
" 'q' / 'Q' / ESC .... quit.\n"
);
}
int main(int argc, char *argv[]) {
int c;
WebPDecoderConfig* const config = &kParams.config;
WebPIterator* const curr = &kParams.curr_frame;
WebPIterator* const prev = &kParams.prev_frame;
if (!WebPInitDecoderConfig(config)) {
fprintf(stderr, "Library version mismatch!\n");
return -1;
}
config->options.dithering_strength = 50;
kParams.use_color_profile = 1;
for (c = 1; c < argc; ++c) {
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
return 0;
} else if (!strcmp(argv[c], "-noicc")) {
kParams.use_color_profile = 0;
} else if (!strcmp(argv[c], "-nofancy")) {
config->options.no_fancy_upsampling = 1;
} else if (!strcmp(argv[c], "-nofilter")) {
config->options.bypass_filtering = 1;
} else if (!strcmp(argv[c], "-dither") && c + 1 < argc) {
config->options.dithering_strength = strtol(argv[++c], NULL, 0);
} else if (!strcmp(argv[c], "-info")) {
kParams.print_info = 1;
} else if (!strcmp(argv[c], "-version")) {
const int dec_version = WebPGetDecoderVersion();
const int dmux_version = WebPGetDemuxVersion();
printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n",
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
dec_version & 0xff, (dmux_version >> 16) & 0xff,
(dmux_version >> 8) & 0xff, dmux_version & 0xff);
return 0;
} else if (!strcmp(argv[c], "-mt")) {
config->options.use_threads = 1;
} else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) kParams.file_name = argv[++c];
break;
} else if (argv[c][0] == '-') {
printf("Unknown option '%s'\n", argv[c]);
Help();
return -1;
} else {
kParams.file_name = argv[c];
}
}
if (kParams.file_name == NULL) {
printf("missing input file!!\n");
Help();
return 0;
}
if (!ExUtilReadFile(kParams.file_name,
&kParams.data.bytes, &kParams.data.size)) {
goto Error;
}
if (!WebPGetInfo(kParams.data.bytes, kParams.data.size, NULL, NULL)) {
fprintf(stderr, "Input file doesn't appear to be WebP format.\n");
goto Error;
}
kParams.dmux = WebPDemux(&kParams.data);
if (kParams.dmux == NULL) {
fprintf(stderr, "Could not create demuxing object!\n");
goto Error;
}
if (WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & FRAGMENTS_FLAG) {
fprintf(stderr, "Image fragments are not supported for now!\n");
goto Error;
}
kParams.canvas_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH);
kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT);
if (kParams.print_info) {
printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height);
}
prev->width = kParams.canvas_width;
prev->height = kParams.canvas_height;
prev->x_offset = prev->y_offset = 0;
prev->dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
memset(&kParams.iccp, 0, sizeof(kParams.iccp));
kParams.has_color_profile =
!!(WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & ICCP_FLAG);
if (kParams.has_color_profile) {
#ifdef WEBP_HAVE_QCMS
if (!WebPDemuxGetChunk(kParams.dmux, "ICCP", 1, &kParams.iccp)) goto Error;
printf("VP8X: Found color profile\n");
#else
fprintf(stderr, "Warning: color profile present, but qcms is unavailable!\n"
"Build libqcms from Mozilla or Chromium and define WEBP_HAVE_QCMS "
"before building.\n");
#endif
}
if (!WebPDemuxGetFrame(kParams.dmux, 1, curr)) goto Error;
kParams.has_animation = (curr->num_frames > 1);
kParams.loop_count = (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT);
kParams.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR);
printf("VP8X: Found %d images in file (loop count = %d)\n",
curr->num_frames, kParams.loop_count);
// Decode first frame
if (!Decode()) goto Error;
// Position iterator to last frame. Next call to HandleDisplay will wrap over.
// We take this into account by bumping up loop_count.
WebPDemuxGetFrame(kParams.dmux, 0, curr);
if (kParams.loop_count) ++kParams.loop_count;
// Start display (and timer)
glutInit(&argc, argv);
#ifdef FREEGLUT
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
#endif
StartDisplay();
if (kParams.has_animation) glutTimerFunc(0, decode_callback, 0);
glutMainLoop();
// Should only be reached when using FREEGLUT:
ClearParams();
return 0;
Error:
ClearParams();
return -1;
}
#else // !WEBP_HAVE_GL
int main(int argc, const char *argv[]) {
fprintf(stderr, "OpenGL support not enabled in %s.\n", argv[0]);
(void)argc;
return 0;
}
#endif
//------------------------------------------------------------------------------

1069
examples/webpmux.c Normal file

File diff suppressed because it is too large Load Diff

349
examples/wicdec.c Normal file
View File

@ -0,0 +1,349 @@
// Copyright 2013 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.
// -----------------------------------------------------------------------------
//
// Windows Imaging Component (WIC) decode.
#include "./wicdec.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef HAVE_WINCODEC_H
#ifdef __MINGW32__
#define INITGUID // Without this GUIDs are declared extern and fail to link
#endif
#define CINTERFACE
#define COBJMACROS
#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
// code with COBJMACROS.
#include <shlwapi.h>
#include <windows.h>
#include <wincodec.h>
#include "webp/encode.h"
#include "./metadata.h"
#define IFS(fn) \
do { \
if (SUCCEEDED(hr)) { \
hr = (fn); \
if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
} \
} while (0)
// modified version of DEFINE_GUID from guiddef.h.
#define WEBP_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
static const GUID name = \
{ l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#ifdef __cplusplus
#define MAKE_REFGUID(x) (x)
#else
#define MAKE_REFGUID(x) &(x)
#endif
typedef struct WICFormatImporter {
const GUID* pixel_format;
int bytes_per_pixel;
int (*import)(WebPPicture* const, const uint8_t* const, int);
} WICFormatImporter;
// From Microsoft SDK 7.0a -- wincodec.h
// Create local copies for compatibility when building against earlier
// versions of the SDK.
WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_,
0x6fddc324, 0x4e03, 0x4bfe,
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c);
WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_,
0x6fddc324, 0x4e03, 0x4bfe,
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d);
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_,
0x6fddc324, 0x4e03, 0x4bfe,
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f);
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_,
0xf5c7ad2d, 0x6a8d, 0x43dd,
0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
static HRESULT OpenInputStream(const char* filename, IStream** stream) {
HRESULT hr = S_OK;
IFS(SHCreateStreamOnFileA(filename, STGM_READ, stream));
if (FAILED(hr)) {
fprintf(stderr, "Error opening input file %s (%08lx)\n", filename, hr);
}
return hr;
}
// -----------------------------------------------------------------------------
// Metadata processing
// Stores the first non-zero sized color profile from 'frame' to 'iccp'.
// Returns an HRESULT to indicate success or failure. The caller is responsible
// for freeing 'iccp->bytes' in either case.
static HRESULT ExtractICCP(IWICImagingFactory* const factory,
IWICBitmapFrameDecode* const frame,
MetadataPayload* const iccp) {
HRESULT hr = S_OK;
UINT i, count;
IWICColorContext** color_contexts;
IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
if (FAILED(hr) || count == 0) return hr;
color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts));
if (color_contexts == NULL) return E_OUTOFMEMORY;
for (i = 0; SUCCEEDED(hr) && i < count; ++i) {
IFS(IWICImagingFactory_CreateColorContext(factory, &color_contexts[i]));
}
if (SUCCEEDED(hr)) {
UINT num_color_contexts;
IFS(IWICBitmapFrameDecode_GetColorContexts(frame,
count, color_contexts,
&num_color_contexts));
for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) {
WICColorContextType type;
IFS(IWICColorContext_GetType(color_contexts[i], &type));
if (SUCCEEDED(hr) && type == WICColorContextProfile) {
UINT size;
IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
0, NULL, &size));
if (size > 0) {
iccp->bytes = (uint8_t*)malloc(size);
if (iccp->bytes == NULL) {
hr = E_OUTOFMEMORY;
break;
}
iccp->size = size;
IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
(UINT)iccp->size, iccp->bytes,
&size));
if (SUCCEEDED(hr) && size != iccp->size) {
fprintf(stderr, "Warning! ICC profile size (%u) != expected (%u)\n",
size, (uint32_t)iccp->size);
iccp->size = size;
}
break;
}
}
}
}
for (i = 0; i < count; ++i) {
if (color_contexts[i] != NULL) IUnknown_Release(color_contexts[i]);
}
free(color_contexts);
return hr;
}
static HRESULT ExtractMetadata(IWICImagingFactory* const factory,
IWICBitmapFrameDecode* const frame,
Metadata* const metadata) {
// TODO(jzern): add XMP/EXIF extraction.
const HRESULT hr = ExtractICCP(factory, frame, &metadata->iccp);
if (FAILED(hr)) MetadataFree(metadata);
return hr;
}
// -----------------------------------------------------------------------------
static int HasPalette(GUID pixel_format) {
return (IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat1bppIndexed)) ||
IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat2bppIndexed)) ||
IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat4bppIndexed)) ||
IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat8bppIndexed)));
}
static int HasAlpha(IWICImagingFactory* const factory,
IWICBitmapDecoder* const decoder,
IWICBitmapFrameDecode* const frame,
GUID pixel_format) {
int has_alpha;
if (HasPalette(pixel_format)) {
IWICPalette* frame_palette = NULL;
IWICPalette* global_palette = NULL;
BOOL frame_palette_has_alpha = FALSE;
BOOL global_palette_has_alpha = FALSE;
// A palette may exist at the frame or container level,
// check IWICPalette::HasAlpha() for both if present.
if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &frame_palette)) &&
SUCCEEDED(IWICBitmapFrameDecode_CopyPalette(frame, frame_palette))) {
IWICPalette_HasAlpha(frame_palette, &frame_palette_has_alpha);
}
if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &global_palette)) &&
SUCCEEDED(IWICBitmapDecoder_CopyPalette(decoder, global_palette))) {
IWICPalette_HasAlpha(global_palette, &global_palette_has_alpha);
}
has_alpha = frame_palette_has_alpha || global_palette_has_alpha;
if (frame_palette != NULL) IUnknown_Release(frame_palette);
if (global_palette != NULL) IUnknown_Release(global_palette);
} else {
has_alpha = IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) ||
IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_));
}
return has_alpha;
}
int ReadPictureWithWIC(const char* const filename,
WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) {
// From Microsoft SDK 6.0a -- ks.h
// Define a local copy to avoid link errors under mingw.
WEBP_DEFINE_GUID(GUID_NULL_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
static const WICFormatImporter kAlphaFormatImporters[] = {
{ &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA },
{ &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA },
{ NULL, 0, NULL },
};
static const WICFormatImporter kNonAlphaFormatImporters[] = {
{ &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR },
{ &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB },
{ NULL, 0, NULL },
};
HRESULT hr = S_OK;
IWICBitmapFrameDecode* frame = NULL;
IWICFormatConverter* converter = NULL;
IWICImagingFactory* factory = NULL;
IWICBitmapDecoder* decoder = NULL;
IStream* stream = NULL;
UINT frame_count = 0;
UINT width = 0, height = 0;
BYTE* rgb = NULL;
WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
const WICFormatImporter* importer = NULL;
GUID src_container_format = GUID_NULL_;
static const GUID* kAlphaContainers[] = {
&GUID_ContainerFormatBmp,
&GUID_ContainerFormatPng,
&GUID_ContainerFormatTiff,
NULL
};
int has_alpha = 0;
int stride;
IFS(CoInitialize(NULL));
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
CLSCTX_INPROC_SERVER,
MAKE_REFGUID(IID_IWICImagingFactory),
(LPVOID*)&factory));
if (hr == REGDB_E_CLASSNOTREG) {
fprintf(stderr,
"Couldn't access Windows Imaging Component (are you running "
"Windows XP SP3 or newer?). Most formats not available. "
"Use -s for the available YUV input.\n");
}
// Prepare for image decoding.
IFS(OpenInputStream(filename, &stream));
IFS(IWICImagingFactory_CreateDecoderFromStream(
factory, stream, NULL,
WICDecodeMetadataCacheOnDemand, &decoder));
IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count));
if (SUCCEEDED(hr) && frame_count == 0) {
fprintf(stderr, "No frame found in input file.\n");
hr = E_FAIL;
}
IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame));
IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format));
IFS(IWICBitmapDecoder_GetContainerFormat(decoder, &src_container_format));
if (keep_alpha) {
const GUID** guid;
for (guid = kAlphaContainers; *guid != NULL; ++guid) {
if (IsEqualGUID(MAKE_REFGUID(src_container_format),
MAKE_REFGUID(**guid))) {
has_alpha = HasAlpha(factory, decoder, frame, src_pixel_format);
break;
}
}
}
// Prepare for pixel format conversion (if necessary).
IFS(IWICImagingFactory_CreateFormatConverter(factory, &converter));
for (importer = has_alpha ? kAlphaFormatImporters : kNonAlphaFormatImporters;
hr == S_OK && importer->import != NULL; ++importer) {
BOOL can_convert;
const HRESULT cchr = IWICFormatConverter_CanConvert(
converter,
MAKE_REFGUID(src_pixel_format),
MAKE_REFGUID(*importer->pixel_format),
&can_convert);
if (SUCCEEDED(cchr) && can_convert) break;
}
if (importer->import == NULL) hr = E_FAIL;
IFS(IWICFormatConverter_Initialize(converter, (IWICBitmapSource*)frame,
importer->pixel_format,
WICBitmapDitherTypeNone,
NULL, 0.0, WICBitmapPaletteTypeCustom));
// Decode.
IFS(IWICFormatConverter_GetSize(converter, &width, &height));
stride = importer->bytes_per_pixel * width * sizeof(*rgb);
if (SUCCEEDED(hr)) {
rgb = (BYTE*)malloc(stride * height);
if (rgb == NULL)
hr = E_OUTOFMEMORY;
}
IFS(IWICFormatConverter_CopyPixels(converter, NULL,
stride, stride * height, rgb));
// WebP conversion.
if (SUCCEEDED(hr)) {
int ok;
pic->width = width;
pic->height = height;
pic->use_argb = 1;
ok = importer->import(pic, rgb, stride);
if (!ok) hr = E_FAIL;
}
if (SUCCEEDED(hr)) {
if (metadata != NULL) {
hr = ExtractMetadata(factory, frame, metadata);
if (FAILED(hr)) {
fprintf(stderr, "Error extracting image metadata using WIC!\n");
}
}
}
// Cleanup.
if (converter != NULL) IUnknown_Release(converter);
if (frame != NULL) IUnknown_Release(frame);
if (decoder != NULL) IUnknown_Release(decoder);
if (factory != NULL) IUnknown_Release(factory);
if (stream != NULL) IUnknown_Release(stream);
free(rgb);
return SUCCEEDED(hr);
}
#else // !HAVE_WINCODEC_H
int ReadPictureWithWIC(const char* const filename,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata) {
(void)filename;
(void)pic;
(void)keep_alpha;
(void)metadata;
fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. "
"Visual Studio and mingw-w64 builds support WIC. Make sure "
"wincodec.h detection is working correctly if using autoconf "
"and HAVE_WINCODEC_H is defined before building.\n");
return 0;
}
#endif // HAVE_WINCODEC_H
// -----------------------------------------------------------------------------

34
examples/wicdec.h Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2013 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.
// -----------------------------------------------------------------------------
//
// Windows Imaging Component (WIC) decode.
#ifndef WEBP_EXAMPLES_WICDEC_H_
#define WEBP_EXAMPLES_WICDEC_H_
#ifdef __cplusplus
extern "C" {
#endif
struct Metadata;
struct WebPPicture;
// Reads an image from 'filename', returning the decoded output in 'pic'.
// If 'keep_alpha' is true and the image has an alpha channel, the output is
// RGBA otherwise it will be RGB.
// Returns true on success.
int ReadPictureWithWIC(const char* const filename,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_WICDEC_H_

108
iosbuild.sh Executable file
View File

@ -0,0 +1,108 @@
#!/bin/bash
#
# This script generates 'WebP.framework'. An iOS app can decode WebP images
# by including 'WebP.framework'.
#
# Run ./iosbuild.sh to generate 'WebP.framework' under the current directory
# (previous build will be erased if it exists).
#
# This script is inspired by the build script written by Carson McDonald.
# (http://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
set -e
# Extract the latest SDK version from the final field of the form: iphoneosX.Y
declare -r SDK=$(xcodebuild -showsdks \
| grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}'
)
# Extract Xcode version.
declare -r XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2)
declare -r OLDPATH=${PATH}
# Add iPhoneOS-V6 to the list of platforms below if you need armv6 support.
# Note that iPhoneOS-V6 support is not available with the iOS6 SDK.
declare -r PLATFORMS="iPhoneSimulator iPhoneOS-V7 iPhoneOS-V7s"
declare -r SRCDIR=$(dirname $0)
declare -r TOPDIR=$(pwd)
declare -r BUILDDIR="${TOPDIR}/iosbuild"
declare -r TARGETDIR="${TOPDIR}/WebP.framework"
declare -r DEVELOPER=$(xcode-select --print-path)
declare -r PLATFORMSROOT="${DEVELOPER}/Platforms"
declare -r LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
LIBLIST=''
if [[ -z "${SDK}" ]]; then
echo "iOS SDK not available"
exit 1
elif [[ ${SDK} < 4.0 ]]; then
echo "You need iOS SDK version 4.0 or above"
exit 1
else
echo "iOS SDK Version ${SDK}"
fi
rm -rf ${BUILDDIR}
rm -rf ${TARGETDIR}
mkdir -p ${BUILDDIR}
mkdir -p ${TARGETDIR}/Headers/
[[ -e ${SRCDIR}/configure ]] || (cd ${SRCDIR} && sh autogen.sh)
for PLATFORM in ${PLATFORMS}; do
if [[ "${PLATFORM}" == "iPhoneOS-V7s" ]]; then
PLATFORM="iPhoneOS"
ARCH="armv7s"
elif [[ "${PLATFORM}" == "iPhoneOS-V7" ]]; then
PLATFORM="iPhoneOS"
ARCH="armv7"
elif [[ "${PLATFORM}" == "iPhoneOS-V6" ]]; then
PLATFORM="iPhoneOS"
ARCH="armv6"
else
ARCH="i386"
fi
ROOTDIR="${BUILDDIR}/${PLATFORM}-${SDK}-${ARCH}"
mkdir -p "${ROOTDIR}"
SDKROOT="${PLATFORMSROOT}/${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDK}.sdk/"
CFLAGS="-arch ${ARCH} -pipe -isysroot ${SDKROOT}"
LDFLAGS="-arch ${ARCH} -pipe -isysroot ${SDKROOT}"
if [[ -z "${XCODE}" ]]; then
echo "XCODE not available"
exit 1
elif [[ ${SDK} < 5.0.0 ]]; then
DEVROOT="${PLATFORMSROOT}/${PLATFORM}.platform/Developer/"
else
DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain"
CFLAGS+=" -miphoneos-version-min=5.0"
LDFLAGS+=" -miphoneos-version-min=5.0"
fi
export CFLAGS
export LDFLAGS
export CXXFLAGS=${CFLAGS}
export PATH="${DEVROOT}/usr/bin:${OLDPATH}"
${SRCDIR}/configure --host=${ARCH}-apple-darwin --prefix=${ROOTDIR} \
--build=$(${SRCDIR}/config.guess) \
--disable-shared --enable-static \
--enable-libwebpdecoder --enable-swap-16bit-csp
# run make only in the src/ directory to create libwebpdecoder.a
cd src/
make V=0
make install
LIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
make clean
cd ..
export PATH=${OLDPATH}
done
cp -a ${SRCDIR}/src/webp/* ${TARGETDIR}/Headers/
${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP

309
m4/ax_pthread.m4 Normal file
View File

@ -0,0 +1,309 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
# PTHREAD_CFLAGS.
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# Updated for Autoconf 2.68 by Daniel Richard G.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 18
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_PUSH([C])
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
AC_MSG_RESULT($ax_pthread_ok)
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case ${host_os} in
solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
darwin*)
ax_pthread_flags="-pthread $ax_pthread_flags"
;;
esac
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
static void routine(void *a) { a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
pthread_create(&th, 0, start_routine, 0);
pthread_join(th, 0);
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_cleanup_pop(0) /* ; */])],
[ax_pthread_ok=yes],
[])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($ax_pthread_ok)
if test "x$ax_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
[int attr = $attr; return attr /* ; */])],
[attr_name=$attr; break],
[])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case ${host_os} in
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
osf* | hpux*) flag="-D_REENTRANT";;
solaris*)
if test "$GCC" = "yes"; then
flag="-D_REENTRANT"
else
flag="-mt -D_REENTRANT"
fi
;;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
ax_cv_PTHREAD_PRIO_INHERIT, [
AC_LINK_IFELSE([
AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with xlc_r or cc_r
if test x"$GCC" != xyes; then
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
else
PTHREAD_CC=$CC
fi
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
ax_pthread_ok=no
$2
fi
AC_LANG_POP
])dnl AX_PTHREAD

View File

@ -2,7 +2,8 @@
# system, for simple local building of the libraries and tools.
# It will not install the libraries system-wide, but just create the 'cwebp'
# and 'dwebp' tools in the examples/ directory, along with the static
# library 'src/libwebp.a'.
# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a' and
# 'src/demux/libwebpdemux.a'.
#
# To build the library and examples, use:
# make -f makefile.unix
@ -10,23 +11,40 @@
#### Customizable part ####
# These flag assume you have libpng and libjpeg installed. If not, either
# follow below install instructions or just comment out the next lines.
EXTRA_FLAGS= -DWEBP_HAVE_PNG -DWEBP_HAVE_JPEG
EXTRA_LIBS= -lpng -ljpeg -lz
# These flags assume you have libpng, libjpeg, libtiff and libgif installed. If
# not, either follow the install instructions below or just comment out the next
# four lines.
EXTRA_FLAGS= -DWEBP_HAVE_PNG -DWEBP_HAVE_JPEG -DWEBP_HAVE_TIFF
DWEBP_LIBS= -lpng -lz
CWEBP_LIBS= $(DWEBP_LIBS) -ljpeg -ltiff
GIF_LIBS = -lgif
ifeq ($(strip $(shell uname)), Darwin)
# Work around a problem linking tables marked as common symbols,
# cf., src/enc/yuv.[hc]
# Failure observed with: gcc 4.2.1 and 4.0.1.
EXTRA_FLAGS += -fno-common
EXTRA_FLAGS += -DHAVE_GLUT_GLUT_H
EXTRA_FLAGS += -I/opt/local/include
EXTRA_LIBS += -L/opt/local/lib
GL_LIBS = -framework GLUT -framework OpenGL
else
GL_LIBS = -lglut -lGL
endif
# To install libraries on Mac OS X:
# 1. Install MacPorts (http://www.macports.org/install.php)
# 2. Run "sudo port install jpeg"
# 3. Run "sudo port install libpng"
# 4. Run "sudo port install tiff"
# 5. Run "sudo port install giflib"
# To install libraries on Linux:
# 1. Run "sudo apt-get install libjpeg62-dev"
# 2. Run "sudo apt-get install libpng12-dev"
# 3. Run "sudo apt-get install libtiff4-dev"
# 4. Run "sudo apt-get install libgif-dev"
# Uncomment for build for 32bit platform
# Alternatively, you can just use the command
@ -36,6 +54,9 @@ endif
# Extra flags to enable experimental features and code
# EXTRA_FLAGS += -DWEBP_EXPERIMENTAL_FEATURES
# Extra flags to enable byte swap for 16 bit colorspaces.
# EXTRA_FLAGS += -DWEBP_SWAP_16BIT_CSP
# Extra flags to enable multi-threading
EXTRA_FLAGS += -DWEBP_USE_THREAD
EXTRA_LIBS += -lpthread
@ -45,78 +66,228 @@ EXTRA_FLAGS += -Wextra -Wold-style-definition
EXTRA_FLAGS += -Wmissing-prototypes
EXTRA_FLAGS += -Wmissing-declarations
EXTRA_FLAGS += -Wdeclaration-after-statement
EXTRA_FLAGS += -Wshadow
# EXTRA_FLAGS += -Wvla
#### Nothing should normally be changed below this line ####
AR = ar
ARFLAGS = r
CC = gcc -Isrc/ -Iexamples/ -Wall
CC = gcc
CPPFLAGS = -Isrc/ -Wall
CFLAGS = -O3 -DNDEBUG $(EXTRA_FLAGS)
INSTALL = install
LDFLAGS = $(EXTRA_LIBS) -lm
GROFF = /usr/bin/groff
COL = /usr/bin/col
LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm
DEC_OBJS = src/dec/frame.o src/dec/webp.o src/dec/quant.o src/dec/tree.o \
src/dec/vp8.o src/dec/idec.o src/dec/alpha.o src/dec/layer.o \
src/dec/io.o src/dec/buffer.o
ENC_OBJS = src/enc/webpenc.o src/enc/syntax.o \
src/enc/alpha.o src/enc/layer.o \
src/enc/tree.o src/enc/config.o src/enc/frame.o \
src/enc/quant.o src/enc/iterator.o src/enc/analysis.o \
src/enc/cost.o src/enc/picture.o src/enc/filter.o
DSP_OBJS = src/dsp/cpu.o src/dsp/enc.o \
src/dsp/enc_sse2.o src/dsp/dec.o src/dsp/dec_sse2.o \
src/dsp/dec_neon.o src/dsp/upsampling.o src/dsp/upsampling_sse2.o \
src/dsp/yuv.o
UTILS_OBJS = src/utils/bit_reader.o src/utils/bit_writer.o src/utils/thread.o
DEC_OBJS = \
src/dec/alpha.o \
src/dec/buffer.o \
src/dec/frame.o \
src/dec/idec.o \
src/dec/io.o \
src/dec/layer.o \
src/dec/quant.o \
src/dec/tree.o \
src/dec/vp8.o \
src/dec/vp8l.o \
src/dec/webp.o \
OBJS = $(DEC_OBJS) $(ENC_OBJS) $(DSP_OBJS) $(UTILS_OBJS)
DEMUX_OBJS = \
src/demux/demux.o \
HDRS = src/webp/encode.h src/enc/vp8enci.h src/enc/cost.h \
src/dec/vp8i.h \
src/dsp/yuv.h src/dsp/dsp.h \
src/utils/bit_writer.h src/utils/bit_reader.h src/utils/thread.h
DSP_DEC_OBJS = \
src/dsp/cpu.o \
src/dsp/dec.o \
src/dsp/dec_neon.o \
src/dsp/dec_sse2.o \
src/dsp/lossless.o \
src/dsp/upsampling.o \
src/dsp/upsampling_neon.o \
src/dsp/upsampling_sse2.o \
src/dsp/yuv.o \
OUTPUT = examples/cwebp examples/dwebp src/libwebp.a
DSP_ENC_OBJS = \
src/dsp/enc.o \
src/dsp/enc_neon.o \
src/dsp/enc_sse2.o \
all:ex
ENC_OBJS = \
src/enc/alpha.o \
src/enc/analysis.o \
src/enc/backward_references.o \
src/enc/config.o \
src/enc/cost.o \
src/enc/filter.o \
src/enc/frame.o \
src/enc/histogram.o \
src/enc/iterator.o \
src/enc/layer.o \
src/enc/picture.o \
src/enc/quant.o \
src/enc/syntax.o \
src/enc/token.o \
src/enc/tree.o \
src/enc/vp8l.o \
src/enc/webpenc.o \
EX_FORMAT_DEC_OBJS = \
examples/jpegdec.o \
examples/metadata.o \
examples/pngdec.o \
examples/tiffdec.o \
EX_UTIL_OBJS = \
examples/example_util.o \
GIF2WEBP_UTIL_OBJS = \
examples/gif2webp_util.o \
MUX_OBJS = \
src/mux/muxedit.o \
src/mux/muxinternal.o \
src/mux/muxread.o \
UTILS_DEC_OBJS = \
src/utils/alpha_processing.o \
src/utils/bit_reader.o \
src/utils/color_cache.o \
src/utils/filters.o \
src/utils/huffman.o \
src/utils/quant_levels_dec.o \
src/utils/random.o \
src/utils/rescaler.o \
src/utils/thread.o \
src/utils/utils.o \
UTILS_ENC_OBJS = \
src/utils/bit_writer.o \
src/utils/huffman_encode.o \
src/utils/quant_levels.o \
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
$(UTILS_ENC_OBJS)
LIBWEBPMUX_OBJS = $(MUX_OBJS)
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS)
HDRS_INSTALLED = \
src/webp/decode.h \
src/webp/demux.h \
src/webp/encode.h \
src/webp/mux.h \
src/webp/mux_types.h \
src/webp/types.h \
HDRS = \
src/dec/alphai.h \
src/dec/decode_vp8.h \
src/dec/vp8i.h \
src/dec/vp8li.h \
src/dec/webpi.h \
src/dsp/dsp.h \
src/dsp/lossless.h \
src/dsp/yuv.h \
src/enc/cost.h \
src/enc/vp8enci.h \
src/utils/alpha_processing.h \
src/utils/bit_reader.h \
src/utils/bit_writer.h \
src/utils/color_cache.h \
src/utils/filters.h \
src/utils/huffman.h \
src/utils/huffman_encode.h \
src/utils/quant_levels.h \
src/utils/quant_levels_dec.h \
src/utils/random.h \
src/utils/rescaler.h \
src/utils/thread.h \
src/webp/format_constants.h \
$(HDRS_INSTALLED) \
OUT_LIBS = examples/libexample_util.a src/libwebpdecoder.a src/libwebp.a
OUT_EXAMPLES = examples/cwebp examples/dwebp
EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux
OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES)
ifeq ($(MAKECMDGOALS),clean)
OUTPUT += $(EXTRA_EXAMPLES)
OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a
OUTPUT += examples/libgif2webp_util.a
endif
ex: $(OUT_EXAMPLES)
all: ex $(EXTRA_EXAMPLES)
$(EX_FORMAT_DEC_OBJS): %.o: %.h
%.o: %.c $(HDRS)
$(CC) $(CFLAGS) -c $< -o $@
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
src/libwebp.a: $(OBJS)
examples/libexample_util.a: $(EX_UTIL_OBJS)
examples/libgif2webp_util.a: $(GIF2WEBP_UTIL_OBJS)
src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS)
src/libwebp.a: $(LIBWEBP_OBJS)
src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS)
src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
%.a:
$(AR) $(ARFLAGS) $@ $^
ex: examples/cwebp examples/dwebp
examples/cwebp: examples/cwebp.o $(EX_FORMAT_DEC_OBJS)
examples/dwebp: examples/dwebp.o
examples/gif2webp: examples/gif2webp.o
examples/vwebp: examples/vwebp.o
examples/webpmux: examples/webpmux.o
examples/cwebp: examples/cwebp.o src/libwebp.a
examples/dwebp: examples/dwebp.o src/libwebp.a
examples/cwebp examples/dwebp:
examples/cwebp: src/libwebp.a
examples/cwebp: EXTRA_LIBS += $(CWEBP_LIBS)
examples/dwebp: examples/libexample_util.a src/libwebpdecoder.a
examples/dwebp: EXTRA_LIBS += $(DWEBP_LIBS)
examples/gif2webp: examples/libexample_util.a examples/libgif2webp_util.a
examples/gif2webp: src/mux/libwebpmux.a src/libwebp.a
examples/gif2webp: EXTRA_LIBS += $(GIF_LIBS)
examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF
examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a
examples/vwebp: src/libwebp.a
examples/vwebp: EXTRA_LIBS += $(GL_LIBS)
examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL
examples/webpmux: examples/libexample_util.a src/mux/libwebpmux.a
examples/webpmux: src/libwebpdecoder.a
$(OUT_EXAMPLES) $(EXTRA_EXAMPLES):
$(CC) -o $@ $^ $(LDFLAGS)
dist: DESTDIR := dist
dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES)
dist: all
$(INSTALL) -m755 -d $(DESTDIR)/include/webp \
$(DESTDIR)/doc $(DESTDIR)/lib
$(INSTALL) -m755 -s examples/cwebp examples/dwebp $(DESTDIR)
$(INSTALL) -m644 src/webp/*.h $(DESTDIR)/include/webp
$(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib
$(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)/bin
$(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp
$(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
umask 022; \
for m in man/[cd]webp.1; do \
for m in man/[cd]webp.1 man/gif2webp.1 man/webpmux.1; do \
basenam=$$(basename $$m .1); \
/usr/bin/groff -t -e -man -T utf8 $$m \
| col -bx >$(DESTDIR)/doc/$${basenam}.txt; \
/usr/bin/groff -t -e -man -T html $$m \
| col -bx >$(DESTDIR)/doc/$${basenam}.html; \
$(GROFF) -t -e -man -T utf8 $$m \
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \
$(GROFF) -t -e -man -T html $$m \
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.html; \
done
clean:
$(RM) ${OUTPUT} *~ \
src/enc/*.o src/enc/*~ \
$(RM) $(OUTPUT) *~ \
examples/*.o examples/*~ \
src/dec/*.o src/dec/*~ \
src/demux/*.o src/demux/*~ \
src/dsp/*.o src/dsp/*~ \
src/enc/*.o src/enc/*~ \
src/mux/*.o src/mux/*~ \
src/utils/*.o src/utils/*~ \
examples/*.o examples/*~
src/webp/*~ man/*~ doc/*~ swig/*~ \
superclean: clean
$(RM) -r .git *.log *.cache *~
@ -127,7 +298,8 @@ superclean: clean
$(RM) Makefile */Makefile */*/Makefile
$(RM) Makefile.in */Makefile.in */*/Makefile.in
$(RM) config.log autom4te.cache libtool config.h stamp-h1
$(RM) aclocal.m4 compile config.guess config.h.in config.sub config.status
$(RM) aclocal.m4 compile
$(RM) config.guess config.h.in config.sub config.status
$(RM) configure depcomp install-sh ltmain.sh missing src/libwebp.pc
$(RM) m4/*

View File

@ -1,2 +1,8 @@
man_MANS = cwebp.1 dwebp.1
if WANT_MUX
man_MANS += webpmux.1
endif
if BUILD_GIF2WEBP
man_MANS += gif2webp.1
endif
EXTRA_DIST = $(man_MANS)

View File

@ -1,10 +1,10 @@
.\" Hey, EMACS: -*- nroff -*-
.TH CWEBP 1 "September 19, 2011"
.TH CWEBP 1 "December 12, 2013"
.SH NAME
cwebp \- compress an image file to a WebP file
.SH SYNOPSIS
.B cwebp
.RI [ options ] " input_file -o output_file.webp
.RI [ options ] " input_file \-o output_file.webp
.br
.SH DESCRIPTION
This manual page documents the
@ -12,13 +12,11 @@ This manual page documents the
command.
.PP
\fBcwebp\fP compresses an image using the WebP format.
Input format can be either PNG, JPEG, or raw Y'CbCr samples.
When using PNG, the transparency information (alpha channel) is currently
discarded.
Input format can be either PNG, JPEG, TIFF or raw Y'CbCr samples.
.SH OPTIONS
The basic options are:
.TP
.B \-o string
.BI \-o " string
Specify the name of the output WebP file. If omitted, \fBcwebp\fP will
perform compression but only report statistics.
.TP
@ -31,19 +29,30 @@ A summary of all the possible options.
.B \-version
Print the version number (as major.minor.revision) and exit.
.TP
.B \-q float
Specify the compression factor between 0 and 100. A small factor
produces a smaller file with lower quality. Best quality is achieved
using a value of 100. The default is 75.
.BI \-q " float
Specify the compression factor for RGB channels between 0 and 100. The default
is 75.
.br
In case of lossy compression (default), a small factor produces a smaller file
with lower quality. Best quality is achieved by using a value of 100.
.br
In case of lossless compression (specified by the \-lossless option), a small
factor enables faster compression speed, but produces a larger file. Maximum
compression is achieved by using a value of 100.
.TP
.B \-f int
.BI \-alpha_q " int
Specify the compression factor for alpha compression between 0 and 100.
Lossless compression of alpha is achieved using a value of 100, while the lower
values result in a lossy compression. The default is 100.
.TP
.BI \-f " int
Specify the strength of the deblocking filter, between 0 (no filtering)
and 100 (maximum filtering). A value of 0 will turn off any filtering.
Higher value will increase the strength of the filtering process applied
after decoding the picture. The higher the smoother the picture will
after decoding the picture. The higher the value the smoother the picture will
appear. Typical values are usually in the range of 20 to 50.
.TP
.B \-preset string
.BI \-preset " string
Specify a set of pre-defined parameters to suit a particular type of
source material. Possible values are: \fBdefault\fP, \fBphoto\fP,
\fBpicture\fP, \fBdrawing\fP, \fBicon\fP, \fBtext\fP. Since
@ -51,21 +60,40 @@ source material. Possible values are: \fBdefault\fP, \fBphoto\fP,
\fB\-q\fP one), this option should preferably appear first in the
order of the arguments.
.TP
.B \-sns int
.BI \-sns " int
Specify the amplitude of the spatial noise shaping. Spatial noise shaping
(or \fBsns\fP for short) refers to a general collection of built-in algorithms
used to decide which area of the picture should use relatively less bits,
and where else to better transfer these bits. The possible range goes from
0 (algorithm is off) to 100 (the maximal effect). The default value is 80.
.TP
.B \-m int
.BI \-m " int
Specify the compression method to use. This parameter controls the
tradeoff between encoding speed and the compressed file size and quality.
trade off between encoding speed and the compressed file size and quality.
Possible values range from 0 to 6. Default value is 4.
When higher values are used, the encoder will spend more time inspecting
additional encoding possibilities and decide on the quality gain.
Lower value can result is faster processing time at the expense of
larger filesize and lower compression quality.
Lower value can result in faster processing time at the expense of
larger file size and lower compression quality.
.TP
.B \-jpeg_like
Change the internal parameter mapping to better match the expected size
of JPEG compression. This flag will generally produce an output file of
similar size to its JPEG equivalent (for the same \fB\-q\fP setting), but
with less visual distortion.
.TP
.B \-mt
Use multi-threading for encoding, if possible. This option is only effective
when using lossy compression on a source with a transparency channel.
.TP
.B \-low_memory
Reduce memory usage of lossy encoding by saving four times the compressed
size (typically). This will make the encoding slower and the output slightly
different in size and distortion. This flag is only effective for methods
3 and up, and is off by default. Note that leaving this flag off will have
some side effects on the bitstream: it forces certain bitstream features
like number of partitions (forced to 1). Note that a more detailed report
of bitstream size is printed by \fBcwebp\fP when using this option.
.TP
.B \-af
Turns auto-filter on. This algorithm will spend additional time optimizing
@ -74,19 +102,25 @@ the filtering strength to reach a well-balanced quality.
.SH ADDITIONAL OPTIONS
More advanced options are:
.TP
.B \-sharpness int
.BI \-sharpness " int
Specify the sharpness of the filtering (if used).
Range is 0 (sharpest) to 7 (least sharp). Default is 0.
.TP
.B \-strong
Use a stronger filtering than the default one (if filtering is being
used thanks to the \fB\-f\fP option). Strong filtering is off by default.
Use strong filtering (if filtering is being used thanks to the
\fB\-f\fP option). Strong filtering is on by default.
.TP
.B \-segments int
.B \-nostrong
Disable strong filtering (if filtering is being used thanks to the
\fB\-f\fP option) and use simple filtering instead.
.TP
.BI \-segments " int
Change the number of partitions to use during the segmentation of the
sns algorithm. Segments should be in range 1 to 4. Default value is 4.
This option has no effect for methods 3 and up, unless \fB\-low_memory\fP
is used.
.TP
.B \-partition_limit int
.BI \-partition_limit " int
Degrade quality by limiting the number of bits used by some macroblocks.
Range is 0 (no degradation, the default) to 100 (full degradation).
Useful values are usually around 30-70 for moderately large images.
@ -105,37 +139,82 @@ If using \fB-partition_limit\fP is not enough to meet the 512k constraint, one
should use less segments in order to save more header bits per macroblock.
See the \fB-segments\fP option.
.TP
.B \-size int
.BI \-size " int
Specify a target size (in bytes) to try and reach for the compressed output.
Compressor will make several pass of partial encoding in order to get as
close as possible to this target.
.TP
.B \-psnr float
.BI \-psnr " float
Specify a target PSNR (in dB) to try and reach for the compressed output.
Compressor will make several pass of partial encoding in order to get as
close as possible to this target.
.TP
.B \-pass int
Set a maximum number of pass to use during the dichotomy used by
.BI \-pass " int
Set a maximum number of passes to use during the dichotomy used by
options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10.
.TP
.B \-crop x_position y_position width height
.BI \-resize " width height
Resize the source to a rectangle with size \fBwidth\fP x \fBheight\fP.
If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0,
the value will be calculated preserving the aspect-ratio.
.TP
.BI \-crop " x_position y_position width height
Crop the source to a rectangle with top-left corner at coordinates
(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP.
This cropping area must be fully contained within the source rectangle.
.TP
.B \-s width height
.BI \-s " width height
Specify that the input file actually consists of raw Y'CbCr samples following
the ITU-R BT.601 recommendation, in 4:2:0 linear format.
The luma plane has size \fBwidth\fP x \fBheight\fP.
.TP
.B \-map int
.BI \-map " int
Output additional ASCII-map of encoding information. Possible map values
range from 1 to 6. This is only meant to help debugging.
.TP
.B \-pre int
Specify a pre-processing filter. This option is a placeholder
and has currently no effect.
.BI \-pre " int
Specify some pre-processing steps. Using a value of '2' will trigger
quality-dependent pseudo-random dithering during RGBA->YUVA conversion
(lossy compression only).
.TP
.BI \-alpha_filter " string
Specify the predictive filtering method for the alpha plane. One of 'none',
\&'fast' or 'best', in increasing complexity and slowness order. Default is
\&'fast'. Internally, alpha filtering is performed using four possible
predictions (none, horizontal, vertical, gradient). The 'best' mode will try
each mode in turn and pick the one which gives the smaller size. The 'fast'
mode will just try to form an a-priori guess without testing all modes.
.TP
.BI \-alpha_method " int
Specify the algorithm used for alpha compression: 0 or 1. Algorithm 0 denotes
no compression, 1 uses WebP lossless format for compression. The default is 1.
.TP
.B \-alpha_cleanup
Modify unseen RGB values under fully transparent area, to help compressibility.
The default is off.
.TP
.BI \-blend_alpha " int
This option blends the alpha channel (if present) with the source using the
background color specified in hexadecimal as 0xrrggbb. The alpha channel is
afterward reset to the opaque value 255.
.TP
.B \-noalpha
Using this option will discard the alpha channel.
.TP
.B \-lossless
Encode the image without any loss.
.TP
.BI \-hint " string
Specify the hint about input image type. Possible values are:
\fBphoto\fP, \fBpicture\fP or \fBgraph\fP.
.TP
.BI \-metadata " string
A comma separated list of metadata to copy from the input to the output if
present.
Valid values: \fBall\fP, \fBnone\fP, \fBexif\fP, \fBicc\fP, \fBxmp\fP.
The default is \fBnone\fP.
Note: each input format may not support all combinations.
.TP
.B \-noasm
Disable all assembly optimizations.
@ -143,27 +222,53 @@ Disable all assembly optimizations.
.B \-v
Print extra information (encoding time in particular).
.TP
.B \-print_psnr
Compute and report average PSNR (Peak-Signal-To-Noise ratio).
.TP
.B \-print_ssim
Compute and report average SSIM (structural similarity
metric, see http://en.wikipedia.org/wiki/SSIM for additional details).
.TP
.B \-print_lsim
Compute and report local similarity metric (sum of lowest error amongst the
collocated pixel neighbors).
.TP
.B \-progress
Report encoding progress in percent.
.TP
.B \-quiet
Do not print anything.
.TP
.B \-short
Only print brief information (output file size and PSNR) for testing purpose.
.SH Examples:
cwebp -q 70 picture.png -o picture.webp
.SH BUGS
Please report all bugs to our issue tracker:
http://code.google.com/p/webp/issues
.br
cwebp -sns 70 -f 50 -strong -af -size 60000 picture.png -o picture.webp
Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/
.SH
.SH SEE ALSO
.BR dwebp (1).
.SH EXAMPLES
cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp
.br
Please refer to http://code.google.com/speed/webp/ for additional
information.
.SH AUTHOR
cwebp \-q 70 picture_with_alpha.png \-o picture_with_alpha.webp
.br
cwebp \-sns 70 \-f 50 \-size 60000 picture.png \-o picture.webp
.br
cwebp \-o picture.webp \-\- \-\-\-picture.png
.SH AUTHORS
\fBcwebp\fP was written by the WebP team.
.br
The latest source tree is available at http://www.webmproject.org/code
.PP
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
for the Debian project (and may be used by others).
.SH SEE ALSO
.BR dwebp (1),
.BR gif2webp (1)
.br
Please refer to http://developers.google.com/speed/webp/ for additional
information.

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
.TH DWEBP 1 "September 19, 2011"
.TH DWEBP 1 "December 12, 2013"
.SH NAME
dwebp \- decompress a WebP file to an image file
.SH SYNOPSIS
@ -11,7 +11,7 @@ This manual page documents the
.B dwebp
command.
.PP
\fBdwebp\fP decompresses WebP files into PNG, PPM or PGM images.
\fBdwebp\fP decompresses WebP files into PNG, PAM, PPM or PGM images.
.SH OPTIONS
The basic options are:
.TP
@ -21,16 +21,32 @@ Print usage summary.
.B \-version
Print the version number (as major.minor.revision) and exit.
.TP
.B \-o string
.BI \-o " string
Specify the name of the output file (as PNG format by default).
Using "-" as output name will direct output to 'stdout'.
.TP
.B \-bmp
Change the output format to uncompressed BMP.
.TP
.B \-tiff
Change the output format to uncompressed TIFF.
.TP
.B \-pam
Change the output format to PAM (retains alpha).
.TP
.B \-ppm
Change the output format to PPM.
Change the output format to PPM (discards alpha).
.TP
.B \-pgm
Change the output format to PGM. The output consist of luma/chroma
samples instead of RGB, using the ICM4 layout. This option is mainly
for verification and debugging purpose.
Change the output format to PGM. The output consists of luma/chroma
samples instead of RGB, using the IMC4 layout. This option is mainly
for verification and debugging purposes.
.TP
.B \-yuv
Change the output format to raw YUV. The output consists of
luma/chroma-U/chroma-V samples instead of RGB, saved sequentially as
individual planes. This option is mainly for verification and debugging
purposes.
.TP
.B \-nofancy
Don't use the fancy upscaler for YUV420. This may lead to jaggy
@ -39,12 +55,20 @@ edges (especially the red ones), but should be faster.
.B \-nofilter
Don't use the in-loop filtering process even if it is required by
the bitstream. This may produce visible blocks on the non-compliant output,
but will make the decoding faster.
but it will make the decoding faster.
.TP
.B \-dither " strength
Specify a dithering \fBstrength\fP between 0 and 100. Dithering is a
post-processing effect applied to chroma components in lossy compression.
It helps by smoothing gradients and avoiding banding artifacts.
.TP
.B \-nodither
Disable all dithering (default).
.TP
.B \-mt
Use multi-threading for decoding, if possible.
.TP
.B \-crop x_position y_position width height
.BI \-crop " x_position y_position width height
Crop the decoded picture to a rectangle with top-left corner at coordinates
(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP.
This cropping area must be fully contained within the source rectangle.
@ -52,11 +76,11 @@ The top-left corner will be snapped to even coordinates if needed.
This option is meant to reduce the memory needed for cropping large images.
Note: the cropping is applied \fIbefore\fP any scaling.
.TP
.B \-scale width height
Rescale the decoded picture to dimension \fBwidth\fP x \fBheight\fP. This option is
mostly intended to reducing the memory needed to decode large images,
when only a small version is needed (thumbnail, preview, etc.).
Note: scaling is applied \fIafter\fP cropping.
.BI \-scale " width height
Rescale the decoded picture to dimension \fBwidth\fP x \fBheight\fP. This
option is mostly intended to reducing the memory needed to decode large images,
when only a small version is needed (thumbnail, preview, etc.). Note: scaling
is applied \fIafter\fP cropping.
.TP
.B \-v
Print extra information (decoding time in particular).
@ -64,21 +88,40 @@ Print extra information (decoding time in particular).
.B \-noasm
Disable all assembly optimizations.
.SH Examples:
dwebp picture.webp -o output.png
.SH BUGS
Please report all bugs to our issue tracker:
http://code.google.com/p/webp/issues
.br
dwebp picture.webp -ppm -o output.ppm
Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/
.SH
.SH SEE ALSO
.BR cwebp (1).
.SH EXAMPLES
dwebp picture.webp \-o output.png
.br
Please refer to http://code.google.com/speed/webp/ for additional
information.
.SH AUTHOR
dwebp picture.webp \-ppm \-o output.ppm
.br
dwebp \-o output.ppm \-\- \-\-\-picture.webp
.SH AUTHORS
\fBdwebp\fP was written by the WebP team.
.br
The latest source tree is available at http://www.webmproject.org/code
.PP
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
for the Debian project (and may be used by others).
.SH SEE ALSO
.BR cwebp (1),
.BR gif2webp (1),
.BR webpmux (1)
.br
Please refer to http://developers.google.com/speed/webp/ for additional
information.
.SS Output file format details
PAM: http://netpbm.sourceforge.net/doc/pam.html
.br
PGM: http://netpbm.sourceforge.net/doc/pgm.html
.br
PPM: http://netpbm.sourceforge.net/doc/ppm.html
.br
PNG: http://www.libpng.org/pub/png/png-sitemap.html#info

143
man/gif2webp.1 Normal file
View File

@ -0,0 +1,143 @@
.\" Hey, EMACS: -*- nroff -*-
.TH GIF2WEBP 1 "December 17, 2013"
.SH NAME
gif2webp \- Convert a GIF image to WebP
.SH SYNOPSIS
.B gif2webp
.RI [ options ] " input_file.gif \-o output_file.webp
.br
.SH DESCRIPTION
This manual page documents the
.B gif2webp
command.
.PP
\fBgif2webp\fP converts a GIF image to a WebP image.
.SH OPTIONS
The basic options are:
.TP
.BI \-o " string
Specify the name of the output WebP file. If omitted, \fBgif2webp\fP will
perform conversion but only report statistics.
.TP
.B \-h, \-help
Usage information.
.TP
.B \-version
Print the version number (as major.minor.revision) and exit.
.TP
.B \-lossy
Encode the image using lossy compression.
.TP
.B \-mixed
Mixed compression mode: optimize compression of the image by picking either
lossy or lossless compression for each frame heuristically.
.TP
.BI \-q " float
Specify the compression factor for RGB channels between 0 and 100. The default
is 75.
.br
In case of lossless compression (default), a small factor enables faster
compression speed, but produces a larger file. Maximum compression is achieved
by using a value of 100.
.br
In case of lossy compression (specified by the \-lossy option), a small factor
produces a smaller file with lower quality. Best quality is achieved by using a
value of 100.
.TP
.BI \-m " int
Specify the compression method to use. This parameter controls the
trade off between encoding speed and the compressed file size and quality.
Possible values range from 0 to 6. Default value is 4.
When higher values are used, the encoder will spend more time inspecting
additional encoding possibilities and decide on the quality gain.
Lower value can result is faster processing time at the expense of
larger file size and lower compression quality.
.TP
.BI \-kmin " int
.TP
.BI \-kmax " int
Specify the minimum and maximum distance between consecutive key frames
(independently decodable frames) in the output animation. The tool will insert
some key frames into the output animation as needed so that this criteria is
satisfied.
.br
A 'kmin' value of 0 will turn off insertion of key frames.
Typical values are in the range 3 to 30. Default values are kmin = 9,
kmax = 17 for lossless compression and kmin = 3, kmax = 5 for lossy compression.
.br
These two options are relevant only for animated images with large number of
frames (>50).
.br
When lower values are used, more frames will be converted to key frames. This
may lead to smaller number of frames required to decode a frame on average,
thereby improving the decoding performance. But this may lead to slightly bigger
file sizes.
Higher values may lead to worse decoding performance, but smaller file sizes.
.br
Some restrictions:
.br
(i) kmin < kmax,
.br
(ii) kmin >= kmax / 2 + 1 and
.br
(iii) kmax - kmin <= 30.
.br
If any of these restrictions are not met, they will be enforced automatically.
.TP
.BI \-metadata " string
A comma separated list of metadata to copy from the input to the output if
present.
Valid values: \fBall\fP, \fBnone\fP, \fBicc\fP, \fBxmp\fP.
The default is \fBxmp\fP.
.TP
.BI \-f " int
For lossy encoding only (specified by the \-lossy option). Specify the strength
of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering).
A value of 0 will turn off any filtering. Higher value will increase the
strength of the filtering process applied after decoding the picture. The higher
the value the smoother the picture will appear. Typical values are usually in
the range of 20 to 50.
.TP
.B \-mt
Use multi-threading for encoding, if possible. This option is only effective
when using lossy compression.
.TP
.B \-v
Print extra information.
.TP
.B \-quiet
Do not print anything.
.SH BUGS
Please report all bugs to our issue tracker:
http://code.google.com/p/webp/issues
.br
Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/
.SH EXAMPLES
gif2webp picture.gif \-o picture.webp
.br
gif2webp \-q 70 picture.gif \-o picture.webp
.br
gif2webp \-lossy \-m 3 picture.gif \-o picture_lossy.webp
.br
gif2webp \-lossy \-f 50 picture.gif \-o picture.webp
.br
gif2webp \-q 70 \-o picture.webp \-\- \-\-\-picture.gif
.SH AUTHORS
\fBgif2webp\fP was written by the WebP team.
.br
The latest source tree is available at http://www.webmproject.org/code
.PP
This manual page was written by Urvang Joshi <urvang@google.com>, for the
Debian project (and may be used by others).
.SH SEE ALSO
.BR cwebp (1),
.BR dwebp (1),
.BR webpmux (1)
.br
Please refer to http://developers.google.com/speed/webp/ for additional
information.

185
man/webpmux.1 Normal file
View File

@ -0,0 +1,185 @@
.\" Hey, EMACS: -*- nroff -*-
.TH WEBPMUX 1 "December 17, 2013"
.SH NAME
webpmux \- command line tool to create WebP Mux/container file.
.SH SYNOPSIS
.B webpmux \-get
.I GET_OPTIONS
.I INPUT
.B \-o
.I OUTPUT
.br
.B webpmux \-set
.I SET_OPTIONS
.I INPUT
.B \-o
.I OUTPUT
.br
.B webpmux \-strip
.I STRIP_OPTIONS
.I INPUT
.B \-o
.I OUTPUT
.br
.B webpmux \-frame
.I FRAME_OPTIONS
.B [ \-frame ... ] [ \-loop
.I LOOP_COUNT
.B ]
.br
.RS 8
.B [ \-bgcolor
.I BACKGROUND_COLOR
.B ] \-o
.I OUTPUT
.RE
.br
.B webpmux \-info
.I INPUT
.br
.B webpmux [\-h|\-help]
.br
.B webpmux \-version
.SH DESCRIPTION
This manual page documents the
.B webpmux
command.
.PP
\fBwebpmux\fP can be used to create a WebP container file
and extract/strip relevant data from the container file.
.SH OPTIONS
.SS GET_OPTIONS (\-get):
.TP
.B icc
Get ICC profile.
.TP
.B exif
Get EXIF metadata.
.TP
.B xmp
Get XMP metadata.
.TP
.BI frame " n
Get nth frame.
.SS SET_OPTIONS (\-set)
.TP
.BI icc " file.icc
Set ICC profile.
.P
Where: 'file.icc' contains the ICC profile to be set.
.TP
.BI exif " file.exif
Set EXIF metadata.
.P
Where: 'file.exif' contains the EXIF metadata to be set.
.TP
.BI xmp " file.xmp
Set XMP metadata.
.P
Where: 'file.xmp' contains the XMP metadata to be set.
.SS STRIP_OPTIONS (\-strip)
.TP
.B icc
Strip ICC profile.
.TP
.B exif
Strip EXIF metadata.
.TP
.B xmp
Strip XMP metadata.
.SS FRAME_OPTIONS (\-frame)
.TP
.I file_i +di[+xi+yi[+mi[bi]]]
Where: 'file_i' is the i'th frame (WebP format), 'xi','yi' specify the image
offset for this frame, 'di' is the pause duration before next frame, 'mi' is
the dispose method for this frame (0 for NONE or 1 for BACKGROUND) and 'bi' is
the blending method for this frame (+b for BLEND or -b for NO_BLEND).
Argument 'bi' can be omitted and will default to +b (BLEND).
Also, 'mi' can be omitted if 'bi' is omitted and will default to 0 (NONE).
Finally, if 'mi' and 'bi' are omitted then 'xi' and 'yi' can be omitted and will
default to +0+0.
.TP
.BI \-loop " n
Loop the frames n number of times. 0 indicates the frames should loop forever.
Valid range is 0 to 65535 [Default: 0 (infinite)].
.TP
.BI \-bgcolor " A,R,G,B
Background color of the canvas.
.br
where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying the
Alpha, Red, Green and Blue component values respectively
[Default: 255,255,255,255].
.SS INPUT
.TP
Input file in WebP format.
.SS OUTPUT (\-o)
.TP
Output file in WebP format.
.SS Note:
.TP
The nature of EXIF, XMP and ICC data is not checked and is assumed to be valid.
.SH BUGS
Please report all bugs to our issue tracker:
http://code.google.com/p/webp/issues
.br
Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/
.SH EXAMPLES
webpmux \-set icc image_profile.icc in.webp \-o icc_container.webp
.br
webpmux \-get icc icc_container.webp \-o image_profile.icc
.br
webpmux \-strip icc icc_container.webp \-o without_icc.webp
.br
webpmux \-set xmp image_metadata.xmp in.webp \-o xmp_container.webp
.br
webpmux \-get xmp xmp_container.webp \-o image_metadata.xmp
.br
webpmux \-strip xmp xmp_container.webp \-o without_xmp.webp
.br
webpmux \-set exif image_metadata.exif in.webp \-o exif_container.webp
.br
webpmux \-get exif exif_container.webp \-o image_metadata.exif
.br
webpmux \-strip exif exif_container.webp \-o without_exif.webp
.br
webpmux \-frame anim_1.webp +100 \-frame anim_2.webp +100+50+50
.br
.RS 8
\-frame anim_2.webp +100+50+50+1+b \-loop 10 \-bgcolor 255,255,255,255
.br
.RS 8
\-o anim_container.webp
.RE
.br
webpmux \-get frame 2 anim_container.webp \-o frame_2.webp
.br
webpmux \-set icc image_profile.icc \-o icc_container.webp \-\- \-\-\-in.webp
.br
webpmux \-get icc \-o image_profile.icc \-\- \-\-\-icc_container.webp
.br
webpmux \-strip icc \-o without_icc.webp \-\- \-\-\-icc_container.webp
.SH AUTHORS
\fBwebpmux\fP is written by the WebP team.
.br
The latest source tree is available at http://www.webmproject.org/code
.PP
This manual page was written by Vikas Arora <vikaas.arora@gmail.com>,
for the Debian project (and may be used by others).
.SH SEE ALSO
.BR cwebp (1),
.BR dwebp (1),
.BR gif2webp (1)
.br
Please refer to http://developers.google.com/speed/webp/ for additional
information.

View File

@ -1,18 +1,55 @@
SUBDIRS = dec enc dsp utils
# The mux and demux libraries depend on libwebp, thus the '.' to force the
# build order so it's available to them.
SUBDIRS = dec enc dsp utils .
if WANT_MUX
SUBDIRS += mux
endif
if WANT_DEMUX
SUBDIRS += demux
endif
AM_CPPFLAGS = -I$(top_srcdir)/src
lib_LTLIBRARIES = libwebp.la
libwebp_la_SOURCES =
libwebp_la_LIBADD = dec/libwebpdecode.la \
enc/libwebpencode.la \
utils/libwebputils.la \
dsp/libwebpdsp.la
libwebp_la_LDFLAGS = -version-info 2:0:0
libwebpinclude_HEADERS = webp/types.h webp/decode.h webp/decode_vp8.h \
webp/encode.h
libwebpincludedir = $(includedir)/webp
if BUILD_LIBWEBPDECODER
lib_LTLIBRARIES += libwebpdecoder.la
endif
common_HEADERS =
common_HEADERS += webp/decode.h
common_HEADERS += webp/types.h
commondir = $(includedir)/webp
libwebp_la_SOURCES =
libwebpinclude_HEADERS =
libwebpinclude_HEADERS += webp/encode.h
noinst_HEADERS =
noinst_HEADERS += webp/format_constants.h
libwebp_la_LIBADD =
libwebp_la_LIBADD += dec/libwebpdecode.la
libwebp_la_LIBADD += dsp/libwebpdsp.la
libwebp_la_LIBADD += enc/libwebpencode.la
libwebp_la_LIBADD += utils/libwebputils.la
# Use '-no-undefined' to declare that libwebp does not depend on any libraries
# other than the ones listed on the command line, i.e., after linking, it will
# not have unresolved symbols. Some platforms (Windows among them) require all
# symbols in shared libraries to be resolved at library creation.
libwebp_la_LDFLAGS = -no-undefined -version-info 5:0:0
libwebpincludedir = $(includedir)/webp
pkgconfig_DATA = libwebp.pc
if BUILD_LIBWEBPDECODER
libwebpdecoder_la_SOURCES =
libwebpdecoder_la_LIBADD =
libwebpdecoder_la_LIBADD += dec/libwebpdecode.la
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 1:0:0
pkgconfig_DATA += libwebpdecoder.pc
endif
${pkgconfig_DATA}: ${top_builddir}/config.status

View File

@ -1,13 +1,29 @@
AM_CPPFLAGS = -I$(top_srcdir)/src
libwebpdecode_la_SOURCES = vp8i.h webpi.h \
frame.c quant.c tree.c vp8.c webp.c \
idec.c alpha.c layer.c io.c buffer.c
libwebpdecode_la_LDFLAGS = -version-info 2:0:0
libwebpdecode_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE)
libwebpdecodeinclude_HEADERS = ../webp/decode.h ../webp/decode_vp8.h ../webp/types.h
libwebpdecodeincludedir = $(includedir)/webp
noinst_HEADERS = vp8i.h webpi.h
noinst_LTLIBRARIES = libwebpdecode.la
libwebpdecode_la_SOURCES =
libwebpdecode_la_SOURCES += alpha.c
libwebpdecode_la_SOURCES += alphai.h
libwebpdecode_la_SOURCES += buffer.c
libwebpdecode_la_SOURCES += decode_vp8.h
libwebpdecode_la_SOURCES += frame.c
libwebpdecode_la_SOURCES += idec.c
libwebpdecode_la_SOURCES += io.c
libwebpdecode_la_SOURCES += layer.c
libwebpdecode_la_SOURCES += quant.c
libwebpdecode_la_SOURCES += tree.c
libwebpdecode_la_SOURCES += vp8.c
libwebpdecode_la_SOURCES += vp8i.h
libwebpdecode_la_SOURCES += vp8l.c
libwebpdecode_la_SOURCES += vp8li.h
libwebpdecode_la_SOURCES += webp.c
libwebpdecode_la_SOURCES += webpi.h
libwebpdecodeinclude_HEADERS =
libwebpdecodeinclude_HEADERS += ../webp/decode.h
libwebpdecodeinclude_HEADERS += ../webp/types.h
noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h
libwebpdecode_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE)
libwebpdecodeincludedir = $(includedir)/webp

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Alpha-plane decompression.
@ -10,60 +12,150 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
#include "vp8i.h"
#ifdef WEBP_EXPERIMENTAL_FEATURES
#include "zlib.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "./alphai.h"
#include "./vp8i.h"
#include "./vp8li.h"
#include "../utils/quant_levels_dec.h"
#include "../webp/format_constants.h"
//------------------------------------------------------------------------------
// ALPHDecoder object.
ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)calloc(1, sizeof(*dec));
return dec;
}
void ALPHDelete(ALPHDecoder* const dec) {
if (dec != NULL) {
VP8LDelete(dec->vp8l_dec_);
dec->vp8l_dec_ = NULL;
free(dec);
}
}
//------------------------------------------------------------------------------
// Decoding.
// Initialize alpha decoding by parsing the alpha header and decoding the image
// header for alpha data stored using lossless compression.
// Returns false in case of error in alpha header (data too short, invalid
// compression method or filter, error in lossless header data etc).
static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
size_t data_size, int width, int height, uint8_t* output) {
int ok = 0;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
int rsrv;
assert(width > 0 && height > 0);
assert(data != NULL && output != NULL);
dec->width_ = width;
dec->height_ = height;
if (data_size <= ALPHA_HEADER_LEN) {
return 0;
}
dec->method_ = (data[0] >> 0) & 0x03;
dec->filter_ = (data[0] >> 2) & 0x03;
dec->pre_processing_ = (data[0] >> 4) & 0x03;
rsrv = (data[0] >> 6) & 0x03;
if (dec->method_ < ALPHA_NO_COMPRESSION ||
dec->method_ > ALPHA_LOSSLESS_COMPRESSION ||
dec->filter_ >= WEBP_FILTER_LAST ||
dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS ||
rsrv != 0) {
return 0;
}
if (dec->method_ == ALPHA_NO_COMPRESSION) {
const size_t alpha_decoded_size = dec->width_ * dec->height_;
ok = (alpha_data_size >= alpha_decoded_size);
} else {
assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION);
ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size, output);
}
return ok;
}
// Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
// starting from row number 'row'. It assumes that rows up to (row - 1) have
// already been decoded.
// Returns false in case of bitstream error.
static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
ALPHDecoder* const alph_dec = dec->alph_dec_;
const int width = alph_dec->width_;
const int height = alph_dec->height_;
WebPUnfilterFunc unfilter_func = WebPUnfilters[alph_dec->filter_];
uint8_t* const output = dec->alpha_plane_;
if (alph_dec->method_ == ALPHA_NO_COMPRESSION) {
const size_t offset = row * width;
const size_t num_pixels = num_rows * width;
assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN + offset + num_pixels);
memcpy(dec->alpha_plane_ + offset,
dec->alpha_data_ + ALPHA_HEADER_LEN + offset, num_pixels);
} else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
assert(alph_dec->vp8l_dec_ != NULL);
if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
return 0;
}
}
if (unfilter_func != NULL) {
unfilter_func(width, height, width, row, num_rows, output);
}
if (alph_dec->pre_processing_ == ALPHA_PREPROCESSED_LEVELS) {
if (!DequantizeLevels(output, width, height, row, num_rows)) {
return 0;
}
}
if (row + num_rows == dec->pic_hdr_.height_) {
dec->is_alpha_decoded_ = 1;
}
return 1;
}
//------------------------------------------------------------------------------
// Main entry point.
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
int row, int num_rows) {
uint8_t* output = dec->alpha_plane_;
const int stride = dec->pic_hdr_.width_;
if (row < 0 || row + num_rows > dec->pic_hdr_.height_) {
return NULL; // sanity check
const int width = dec->pic_hdr_.width_;
const int height = dec->pic_hdr_.height_;
if (row < 0 || num_rows <= 0 || row + num_rows > height) {
return NULL; // sanity check.
}
if (row == 0) {
// TODO(skal): for now, we just decompress everything during the first call.
// Later, we'll decode progressively, but we need to store the
// z_stream state.
const uint8_t* data = dec->alpha_data_;
size_t data_size = dec->alpha_data_size_;
const size_t output_size = stride * dec->pic_hdr_.height_;
int ret = Z_OK;
z_stream strm;
memset(&strm, 0, sizeof(strm));
if (inflateInit(&strm) != Z_OK) {
return 0;
}
strm.avail_in = data_size;
strm.next_in = (unsigned char*)data;
do {
strm.avail_out = output_size;
strm.next_out = output;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
break;
}
} while (strm.avail_out == 0);
inflateEnd(&strm);
if (ret != Z_STREAM_END) {
return NULL; // error
// Initialize decoding.
assert(dec->alpha_plane_ != NULL);
dec->alph_dec_ = ALPHNew();
if (dec->alph_dec_ == NULL) return NULL;
if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
width, height, dec->alpha_plane_)) {
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
return NULL;
}
}
return output + row * stride;
if (!dec->is_alpha_decoded_) {
int ok = 0;
assert(dec->alph_dec_ != NULL);
ok = ALPHDecode(dec, row, num_rows);
if (!ok || dec->is_alpha_decoded_) {
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
}
if (!ok) return NULL; // Error.
}
// Return a pointer to the current decoded row.
return dec->alpha_plane_ + row * width;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif // WEBP_EXPERIMENTAL_FEATURES

55
src/dec/alphai.h Normal file
View File

@ -0,0 +1,55 @@
// Copyright 2013 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.
// -----------------------------------------------------------------------------
//
// Alpha decoder: internal header.
//
// Author: Urvang (urvang@google.com)
#ifndef WEBP_DEC_ALPHAI_H_
#define WEBP_DEC_ALPHAI_H_
#include "./webpi.h"
#include "../utils/filters.h"
#ifdef __cplusplus
extern "C" {
#endif
struct VP8LDecoder; // Defined in dec/vp8li.h.
typedef struct ALPHDecoder ALPHDecoder;
struct ALPHDecoder {
int width_;
int height_;
int method_;
WEBP_FILTER_TYPE filter_;
int pre_processing_;
struct VP8LDecoder* vp8l_dec_;
VP8Io io_;
int use_8b_decode; // Although alpha channel requires only 1 byte per
// pixel, sometimes VP8LDecoder may need to allocate
// 4 bytes per pixel internally during decode.
};
//------------------------------------------------------------------------------
// internal functions. Not public.
// Allocates a new alpha decoder instance.
ALPHDecoder* ALPHNew(void);
// Clears and deallocates an alpha decoder instance.
void ALPHDelete(ALPHDecoder* const dec);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* WEBP_DEC_ALPHAI_H_ */

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Everything about WebPDecBuffer
@ -10,44 +12,60 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
#include "vp8i.h"
#include "webpi.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "./vp8i.h"
#include "./webpi.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------
// WebPDecBuffer
// Number of bytes per pixel for the different color-spaces.
static const int kModeBpp[MODE_LAST] = { 3, 4, 3, 4, 4, 2, 2, 1, 1 };
static const int kModeBpp[MODE_LAST] = {
3, 4, 3, 4, 4, 2, 2,
4, 4, 4, 2, // pre-multiplied modes
1, 1 };
// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
// Convert to an integer to handle both the unsigned/signed enum cases
// without the need for casting to remove type limit warnings.
static int IsValidColorspace(int webp_csp_mode) {
return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
}
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
int ok = 1;
WEBP_CSP_MODE mode = buffer->colorspace;
const WEBP_CSP_MODE mode = buffer->colorspace;
const int width = buffer->width;
const int height = buffer->height;
if (mode >= MODE_YUV) { // YUV checks
if (!IsValidColorspace(mode)) {
ok = 0;
} else if (!WebPIsRGBMode(mode)) { // YUV checks
const WebPYUVABuffer* const buf = &buffer->u.YUVA;
const int size = buf->y_stride * height;
const int u_size = buf->u_stride * ((height + 1) / 2);
const int v_size = buf->v_stride * ((height + 1) / 2);
const int a_size = buf->a_stride * height;
ok &= (size <= buf->y_size);
const uint64_t y_size = (uint64_t)buf->y_stride * height;
const uint64_t u_size = (uint64_t)buf->u_stride * ((height + 1) / 2);
const uint64_t v_size = (uint64_t)buf->v_stride * ((height + 1) / 2);
const uint64_t a_size = (uint64_t)buf->a_stride * height;
ok &= (y_size <= buf->y_size);
ok &= (u_size <= buf->u_size);
ok &= (v_size <= buf->v_size);
ok &= (a_size <= buf->a_size);
ok &= (buf->y_stride >= width);
ok &= (buf->u_stride >= (width + 1) / 2);
ok &= (buf->v_stride >= (width + 1) / 2);
if (buf->a) {
ok &= (buf->y != NULL);
ok &= (buf->u != NULL);
ok &= (buf->v != NULL);
if (mode == MODE_YUVA) {
ok &= (buf->a_stride >= width);
ok &= (a_size <= buf->a_size);
ok &= (buf->a != NULL);
}
} else { // RGB checks
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
ok &= (buf->stride * height <= buf->size);
const uint64_t size = (uint64_t)buf->stride * height;
ok &= (size <= buf->size);
ok &= (buf->stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL);
}
return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
}
@ -55,24 +73,22 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
const int w = buffer->width;
const int h = buffer->height;
const WEBP_CSP_MODE mode = buffer->colorspace;
if (w <= 0 || h <= 0) {
if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) {
return VP8_STATUS_INVALID_PARAM;
}
if (!buffer->is_external_memory && buffer->private_memory == NULL) {
uint8_t* output;
WEBP_CSP_MODE mode = buffer->colorspace;
int stride;
int uv_stride = 0, a_stride = 0;
int uv_size = 0;
uint64_t size, a_size = 0, total_size;
uint64_t uv_size = 0, a_size = 0, total_size;
// We need memory and it hasn't been allocated yet.
// => initialize output buffer, now that dimensions are known.
stride = w * kModeBpp[mode];
size = (uint64_t)stride * h;
const int stride = w * kModeBpp[mode];
const uint64_t size = (uint64_t)stride * h;
if (mode >= MODE_YUV) {
if (!WebPIsRGBMode(mode)) {
uv_stride = (w + 1) / 2;
uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
if (mode == MODE_YUVA) {
@ -83,36 +99,33 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
total_size = size + 2 * uv_size + a_size;
// Security/sanity checks
if (((size_t)total_size != total_size) || (total_size >= (1ULL << 40))) {
return VP8_STATUS_INVALID_PARAM;
}
buffer->private_memory = output = (uint8_t*)malloc((size_t)total_size);
output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
if (output == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
}
buffer->private_memory = output;
if (mode >= MODE_YUV) { // YUVA initialization
if (!WebPIsRGBMode(mode)) { // YUVA initialization
WebPYUVABuffer* const buf = &buffer->u.YUVA;
buf->y = output;
buf->y_stride = stride;
buf->y_size = size;
buf->y_size = (size_t)size;
buf->u = output + size;
buf->u_stride = uv_stride;
buf->u_size = uv_size;
buf->u_size = (size_t)uv_size;
buf->v = output + size + uv_size;
buf->v_stride = uv_stride;
buf->v_size = uv_size;
buf->v_size = (size_t)uv_size;
if (mode == MODE_YUVA) {
buf->a = output + size + 2 * uv_size;
}
buf->a_size = a_size;
buf->a_size = (size_t)a_size;
buf->a_stride = a_stride;
} else { // RGBA initialization
WebPRGBABuffer* const buf = &buffer->u.RGBA;
buf->rgba = output;
buf->stride = stride;
buf->size = size;
buf->size = (size_t)size;
}
}
return CheckDecBuffer(buffer);
@ -140,7 +153,7 @@ VP8StatusCode WebPAllocateDecBuffer(int w, int h,
if (options->scaled_width <= 0 || options->scaled_height <= 0) {
return VP8_STATUS_INVALID_PARAM;
}
w = options->scaled_width;
w = options->scaled_width;
h = options->scaled_height;
}
}
@ -154,15 +167,17 @@ VP8StatusCode WebPAllocateDecBuffer(int w, int h,
//------------------------------------------------------------------------------
// constructors / destructors
int WebPInitDecBufferInternal(WebPDecBuffer* const buffer, int version) {
if (version != WEBP_DECODER_ABI_VERSION) return 0; // version mismatch
if (!buffer) return 0;
int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
return 0; // version mismatch
}
if (buffer == NULL) return 0;
memset(buffer, 0, sizeof(*buffer));
return 1;
}
void WebPFreeDecBuffer(WebPDecBuffer* const buffer) {
if (buffer) {
void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
if (buffer != NULL) {
if (!buffer->is_external_memory)
free(buffer->private_memory);
buffer->private_memory = NULL;
@ -171,9 +186,9 @@ void WebPFreeDecBuffer(WebPDecBuffer* const buffer) {
void WebPCopyDecBuffer(const WebPDecBuffer* const src,
WebPDecBuffer* const dst) {
if (src && dst) {
if (src != NULL && dst != NULL) {
*dst = *src;
if (src->private_memory) {
if (src->private_memory != NULL) {
dst->is_external_memory = 1; // dst buffer doesn't own the memory.
dst->private_memory = NULL;
}
@ -182,9 +197,9 @@ void WebPCopyDecBuffer(const WebPDecBuffer* const src,
// Copy and transfer ownership from src to dst (beware of parameter order!)
void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
if (src && dst) {
if (src != NULL && dst != NULL) {
*dst = *src;
if (src->private_memory) {
if (src->private_memory != NULL) {
src->is_external_memory = 1; // src relinquishes ownership
src->private_memory = NULL;
}
@ -193,6 +208,3 @@ void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Low-level API for VP8 decoder
@ -12,9 +14,9 @@
#ifndef WEBP_WEBP_DECODE_VP8_H_
#define WEBP_WEBP_DECODE_VP8_H_
#include "./decode.h"
#include "../webp/decode.h"
#if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
extern "C" {
#endif
@ -82,7 +84,7 @@ struct VP8Io {
int fancy_upsampling;
// Input buffer.
uint32_t data_size;
size_t data_size;
const uint8_t* data;
// If true, in-loop filtering will not be performed even if present in the
@ -99,58 +101,84 @@ struct VP8Io {
int use_scaling;
int scaled_width, scaled_height;
// pointer to the alpha data (if present) corresponding to the rows
// If non NULL, pointer to the alpha data (if present) corresponding to the
// start of the current row (That is: it is pre-offset by mb_y and takes
// cropping into account).
const uint8_t* a;
};
// Internal, version-checked, entry point
WEBP_EXTERN(int) VP8InitIoInternal(VP8Io* const, int);
int VP8InitIoInternal(VP8Io* const, int);
// Set the custom IO function pointers and user-data. The setter for IO hooks
// should be called before initiating incremental decoding. Returns true if
// WebPIDecoder object is successfully modified, false otherwise.
WEBP_EXTERN(int) WebPISetIOHooks(WebPIDecoder* const idec,
VP8IoPutHook put,
VP8IoSetupHook setup,
VP8IoTeardownHook teardown,
void* user_data);
int WebPISetIOHooks(WebPIDecoder* const idec,
VP8IoPutHook put,
VP8IoSetupHook setup,
VP8IoTeardownHook teardown,
void* user_data);
// Main decoding object. This is an opaque structure.
typedef struct VP8Decoder VP8Decoder;
// Create a new decoder object.
WEBP_EXTERN(VP8Decoder*) VP8New(void);
VP8Decoder* VP8New(void);
// Must be called to make sure 'io' is initialized properly.
// Returns false in case of version mismatch. Upon such failure, no other
// decoding function should be called (VP8Decode, VP8GetHeaders, ...)
static inline int VP8InitIo(VP8Io* const io) {
static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
}
// Start decoding a new picture. Returns true if ok.
WEBP_EXTERN(int) VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Decode the VP8 frame header. Returns true if ok.
// Note: 'io->data' must be pointing to the start of the VP8 frame header.
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
// Returns false in case of error.
WEBP_EXTERN(int) VP8Decode(VP8Decoder* const dec, VP8Io* const io);
int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
// Return current status of the decoder:
WEBP_EXTERN(VP8StatusCode) VP8Status(VP8Decoder* const dec);
VP8StatusCode VP8Status(VP8Decoder* const dec);
// return readable string corresponding to the last status.
WEBP_EXTERN(const char*) VP8StatusMessage(VP8Decoder* const dec);
const char* VP8StatusMessage(VP8Decoder* const dec);
// Resets the decoder in its initial state, reclaiming memory.
// Not a mandatory call between calls to VP8Decode().
WEBP_EXTERN(void) VP8Clear(VP8Decoder* const dec);
void VP8Clear(VP8Decoder* const dec);
// Destroy the decoder object.
WEBP_EXTERN(void) VP8Delete(VP8Decoder* const dec);
void VP8Delete(VP8Decoder* const dec);
//------------------------------------------------------------------------------
// Miscellaneous VP8/VP8L bitstream probing functions.
#if defined(__cplusplus) || defined(c_plusplus)
// Returns true if the next 3 bytes in data contain the VP8 signature.
WEBP_EXTERN(int) VP8CheckSignature(const uint8_t* const data, size_t data_size);
// Validates the VP8 data-header and retrieves basic header information viz
// width and height. Returns 0 in case of formatting error. *width/*height
// can be passed NULL.
WEBP_EXTERN(int) VP8GetInfo(
const uint8_t* data,
size_t data_size, // data available so far
size_t chunk_size, // total data size expected in the chunk
int* const width, int* const height);
// Returns true if the next byte(s) in data is a VP8L signature.
WEBP_EXTERN(int) VP8LCheckSignature(const uint8_t* const data, size_t size);
// Validates the VP8L data-header and retrieves basic header information viz
// width, height and alpha. Returns 0 in case of formatting error.
// width/height/has_alpha can be passed NULL.
WEBP_EXTERN(int) VP8LGetInfo(
const uint8_t* data, size_t data_size, // data available so far
int* const width, int* const height, int* const has_alpha);
#ifdef __cplusplus
} // extern "C"
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Incremental decoding
@ -13,26 +15,30 @@
#include <string.h>
#include <stdlib.h>
#include "webpi.h"
#include "vp8i.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "./alphai.h"
#include "./webpi.h"
#include "./vp8i.h"
#include "../utils/utils.h"
// In append mode, buffer allocations increase as multiples of this value.
// Needs to be a power of 2.
#define CHUNK_SIZE 4096
#define MAX_MB_SIZE 4096
//------------------------------------------------------------------------------
// Data structures for memory and states
// Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE.
// Decoding states. State normally flows as:
// WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and
// WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image.
// If there is any error the decoder goes into state ERROR.
typedef enum {
STATE_PRE_VP8, // All data before that of the first VP8 chunk.
STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk).
STATE_WEBP_HEADER, // All the data before that of the VP8/VP8L chunk.
STATE_VP8_HEADER, // The VP8 Frame header (within the VP8 chunk).
STATE_VP8_PARTS0,
STATE_VP8_DATA,
STATE_VP8L_HEADER,
STATE_VP8L_DATA,
STATE_DONE,
STATE_ERROR
} DecState;
@ -47,8 +53,8 @@ typedef enum {
// storage for partition #0 and partial data (in a rolling fashion)
typedef struct {
MemBufferMode mode_; // Operation mode
uint32_t start_; // start location of the data to be decoded
uint32_t end_; // end location
size_t start_; // start location of the data to be decoded
size_t end_; // end location
size_t buf_size_; // size of the allocated buffer
uint8_t* buf_; // We don't own this buffer in case WebPIUpdate()
@ -59,12 +65,13 @@ typedef struct {
struct WebPIDecoder {
DecState state_; // current decoding state
WebPDecParams params_; // Params to store output info
VP8Decoder* dec_;
int is_lossless_; // for down-casting 'dec_'.
void* dec_; // either a VP8Decoder or a VP8LDecoder instance
VP8Io io_;
MemBuffer mem_; // input memory buffer.
WebPDecBuffer output_; // output buffer (when no external one is supplied)
uint32_t vp8_size_; // VP8 size extracted from VP8 Header.
size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header.
};
// MB context to restore in case VP8DecodeMB() fails
@ -80,102 +87,144 @@ typedef struct {
//------------------------------------------------------------------------------
// MemBuffer: incoming data handling
#define REMAP(PTR, OLD_BASE, NEW_BASE) (PTR) = (NEW_BASE) + ((PTR) - OLD_BASE)
static void RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
if (br->buf_ != NULL) {
br->buf_ += offset;
br->buf_end_ += offset;
}
}
static inline size_t MemDataSize(const MemBuffer* mem) {
static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
return (mem->end_ - mem->start_);
}
// Check if we need to preserve the compressed alpha data, as it may not have
// been decoded yet.
static int NeedCompressedAlpha(const WebPIDecoder* const idec) {
if (idec->state_ == STATE_WEBP_HEADER) {
// We haven't parsed the headers yet, so we don't know whether the image is
// lossy or lossless. This also means that we haven't parsed the ALPH chunk.
return 0;
}
if (idec->is_lossless_) {
return 0; // ALPH chunk is not present for lossless images.
} else {
const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
assert(dec != NULL); // Must be true as idec->state_ != STATE_WEBP_HEADER.
return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_;
}
}
static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
MemBuffer* const mem = &idec->mem_;
const uint8_t* const new_base = mem->buf_ + mem->start_;
// note: for VP8, setting up idec->io_ is only really needed at the beginning
// of the decoding, till partition #0 is complete.
idec->io_.data = new_base;
idec->io_.data_size = MemDataSize(mem);
if (idec->dec_ != NULL) {
if (!idec->is_lossless_) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
const int last_part = dec->num_parts_ - 1;
if (offset != 0) {
int p;
for (p = 0; p <= last_part; ++p) {
RemapBitReader(dec->parts_ + p, offset);
}
// Remap partition #0 data pointer to new offset, but only in MAP
// mode (in APPEND mode, partition #0 is copied into a fixed memory).
if (mem->mode_ == MEM_MODE_MAP) {
RemapBitReader(&dec->br_, offset);
}
}
assert(last_part >= 0);
dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
if (NeedCompressedAlpha(idec)) {
ALPHDecoder* const alph_dec = dec->alph_dec_;
dec->alpha_data_ += offset;
if (alph_dec != NULL) {
if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) {
VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_;
assert(alph_vp8l_dec != NULL);
assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN);
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_,
dec->alpha_data_ + ALPHA_HEADER_LEN,
dec->alpha_data_size_ - ALPHA_HEADER_LEN);
} else { // alph_dec->method_ == ALPHA_NO_COMPRESSION
// Nothing special to do in this case.
}
}
}
} else { // Resize lossless bitreader
VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem));
}
}
}
// Appends data to the end of MemBuffer->buf_. It expands the allocated memory
// size if required and also updates VP8BitReader's if new memory is allocated.
static int AppendToMemBuffer(WebPIDecoder* const idec,
const uint8_t* const data, size_t data_size) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
MemBuffer* const mem = &idec->mem_;
VP8Decoder* const dec = idec->dec_;
const int last_part = dec->num_parts_ - 1;
const int need_compressed_alpha = NeedCompressedAlpha(idec);
const uint8_t* const old_start = mem->buf_ + mem->start_;
const uint8_t* const old_base =
need_compressed_alpha ? dec->alpha_data_ : old_start;
assert(mem->mode_ == MEM_MODE_APPEND);
if (data_size > MAX_CHUNK_PAYLOAD) {
// security safeguard: trying to allocate more than what the format
// allows for a chunk should be considered a smoke smell.
return 0;
}
if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory
int p;
uint8_t* new_buf = NULL;
const int num_chunks = (MemDataSize(mem) + data_size + CHUNK_SIZE - 1)
/ CHUNK_SIZE;
const size_t new_size = num_chunks * CHUNK_SIZE;
const uint8_t* const base = mem->buf_ + mem->start_;
new_buf = (uint8_t*)malloc(new_size);
if (!new_buf) return 0;
memcpy(new_buf, base, MemDataSize(mem));
// adjust VP8BitReader pointers
for (p = 0; p <= last_part; ++p) {
if (dec->parts_[p].buf_) {
REMAP(dec->parts_[p].buf_, base, new_buf);
REMAP(dec->parts_[p].buf_end_, base, new_buf);
}
}
// adjust memory pointers
const size_t new_mem_start = old_start - old_base;
const size_t current_size = MemDataSize(mem) + new_mem_start;
const uint64_t new_size = (uint64_t)current_size + data_size;
const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
uint8_t* const new_buf =
(uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
if (new_buf == NULL) return 0;
memcpy(new_buf, old_base, current_size);
free(mem->buf_);
mem->buf_ = new_buf;
mem->buf_size_ = new_size;
mem->end_ = MemDataSize(mem);
mem->start_ = 0;
mem->buf_size_ = (size_t)extra_size;
mem->start_ = new_mem_start;
mem->end_ = current_size;
}
memcpy(mem->buf_ + mem->end_, data, data_size);
mem->end_ += data_size;
assert(mem->end_ <= mem->buf_size_);
dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
// note: setting up idec->io_ is only really needed at the beginning
// of the decoding, till partition #0 is complete.
idec->io_.data = mem->buf_ + mem->start_;
idec->io_.data_size = MemDataSize(mem);
DoRemap(idec, mem->buf_ + mem->start_ - old_start);
return 1;
}
static int RemapMemBuffer(WebPIDecoder* const idec,
const uint8_t* const data, size_t data_size) {
int p;
MemBuffer* const mem = &idec->mem_;
VP8Decoder* const dec = idec->dec_;
const int last_part = dec->num_parts_ - 1;
const uint8_t* base = mem->buf_;
const uint8_t* const old_buf = mem->buf_;
const uint8_t* const old_start = old_buf + mem->start_;
assert(mem->mode_ == MEM_MODE_MAP);
if (data_size < mem->buf_size_) {
return 0; // we cannot remap to a shorter buffer!
}
for (p = 0; p <= last_part; ++p) {
if (dec->parts_[p].buf_) {
REMAP(dec->parts_[p].buf_, base, data);
REMAP(dec->parts_[p].buf_end_, base, data);
}
}
dec->parts_[last_part].buf_end_ = data + data_size;
// Remap partition #0 data pointer to new offset.
if (dec->br_.buf_) {
REMAP(dec->br_.buf_, base, data);
REMAP(dec->br_.buf_end_, base, data);
}
if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
mem->buf_ = (uint8_t*)data;
mem->end_ = mem->buf_size_ = data_size;
idec->io_.data = data;
idec->io_.data_size = data_size;
DoRemap(idec, mem->buf_ + mem->start_ - old_start);
return 1;
}
static void InitMemBuffer(MemBuffer* const mem) {
mem->mode_ = MEM_MODE_NONE;
mem->buf_ = 0;
mem->buf_ = NULL;
mem->buf_size_ = 0;
mem->part0_buf_ = 0;
mem->part0_buf_ = NULL;
mem->part0_size_ = 0;
}
@ -197,8 +246,6 @@ static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
return 1;
}
#undef REMAP
//------------------------------------------------------------------------------
// Macroblock-decoding contexts
@ -235,7 +282,7 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) {
VP8Io* const io = &idec->io_;
if (io->teardown) {
if (io->teardown != NULL) {
io->teardown(io);
}
}
@ -244,81 +291,106 @@ static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
}
static void ChangeState(WebPIDecoder* const idec, DecState new_state,
uint32_t consumed_bytes) {
size_t consumed_bytes) {
MemBuffer* const mem = &idec->mem_;
idec->state_ = new_state;
idec->mem_.start_ += consumed_bytes;
assert(idec->mem_.start_ <= idec->mem_.end_);
mem->start_ += consumed_bytes;
assert(mem->start_ <= mem->end_);
idec->io_.data = mem->buf_ + mem->start_;
idec->io_.data_size = MemDataSize(mem);
}
// Headers
static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_;
uint32_t curr_size = MemDataSize(&idec->mem_);
uint32_t vp8_size;
uint32_t bytes_skipped;
MemBuffer* const mem = &idec->mem_;
const uint8_t* data = mem->buf_ + mem->start_;
size_t curr_size = MemDataSize(mem);
VP8StatusCode status;
WebPHeaderStructure headers;
status = WebPParseHeaders(&data, &curr_size, &vp8_size, &bytes_skipped);
headers.data = data;
headers.data_size = curr_size;
status = WebPParseHeaders(&headers);
if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet.
} else if (status == VP8_STATUS_OK) {
idec->vp8_size_ = vp8_size;
ChangeState(idec, STATE_VP8_FRAME_HEADER, bytes_skipped);
return VP8_STATUS_OK; // We have skipped all pre-VP8 chunks.
} else {
} else if (status != VP8_STATUS_OK) {
return IDecError(idec, status);
}
idec->chunk_size_ = headers.compressed_size;
idec->is_lossless_ = headers.is_lossless;
if (!idec->is_lossless_) {
VP8Decoder* const dec = VP8New();
if (dec == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
}
idec->dec_ = dec;
dec->alpha_data_ = headers.alpha_data;
dec->alpha_data_size_ = headers.alpha_data_size;
ChangeState(idec, STATE_VP8_HEADER, headers.offset);
} else {
VP8LDecoder* const dec = VP8LNew();
if (dec == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
}
idec->dec_ = dec;
ChangeState(idec, STATE_VP8L_HEADER, headers.offset);
}
return VP8_STATUS_OK;
}
static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_;
const uint32_t curr_size = MemDataSize(&idec->mem_);
const size_t curr_size = MemDataSize(&idec->mem_);
int width, height;
uint32_t bits;
if (curr_size < VP8_FRAME_HEADER_SIZE) {
// Not enough data bytes to extract VP8 Frame Header.
return VP8_STATUS_SUSPENDED;
}
if (!VP8GetInfo(data, curr_size, idec->vp8_size_, NULL, NULL, NULL)) {
if (!VP8GetInfo(data, curr_size, idec->chunk_size_, &width, &height)) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
bits = data[0] | (data[1] << 8) | (data[2] << 16);
idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE;
idec->io_.data_size = curr_size;
idec->io_.data = data;
idec->io_.data_size = curr_size;
idec->state_ = STATE_VP8_PARTS0;
return VP8_STATUS_OK;
}
// Partition #0
static int CopyParts0Data(WebPIDecoder* idec) {
VP8BitReader* const br = &idec->dec_->br_;
static int CopyParts0Data(WebPIDecoder* const idec) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8BitReader* const br = &dec->br_;
const size_t psize = br->buf_end_ - br->buf_;
MemBuffer* const mem = &idec->mem_;
assert(!mem->part0_buf_);
assert(!idec->is_lossless_);
assert(mem->part0_buf_ == NULL);
assert(psize > 0);
assert(psize <= mem->part0_size_);
assert(psize <= mem->part0_size_); // Format limit: no need for runtime check
if (mem->mode_ == MEM_MODE_APPEND) {
// We copy and grab ownership of the partition #0 data.
uint8_t* const part0_buf = (uint8_t*)malloc(psize);
if (!part0_buf) {
if (part0_buf == NULL) {
return 0;
}
memcpy(part0_buf, br->buf_, psize);
mem->part0_buf_ = part0_buf;
mem->start_ += psize;
br->buf_ = part0_buf;
br->buf_end_ = part0_buf + psize;
} else {
// Else: just keep pointers to the partition #0's data in dec_->br_.
}
mem->start_ += psize;
return 1;
}
static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
VP8Decoder* const dec = idec->dec_;
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8Io* const io = &idec->io_;
const WebPDecParams* const params = &idec->params_;
WebPDecBuffer* const output = params->output;
@ -344,7 +416,10 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
if (dec->status_ != VP8_STATUS_OK) {
return IDecError(idec, dec->status_);
}
// This change must be done before calling VP8InitFrame()
dec->mt_method_ = VP8GetThreadMethod(params->options, NULL,
io->width, io->height);
VP8InitDithering(params->options, dec);
if (!CopyParts0Data(idec)) {
return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY);
}
@ -366,22 +441,15 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
// Remaining partitions
static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
VP8BitReader* br;
VP8Decoder* const dec = idec->dec_;
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8Io* const io = &idec->io_;
assert(dec->ready_);
br = &dec->br_;
for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
if (dec->mb_x_ == 0) {
VP8InitScanline(dec);
}
for (; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
MBContext context;
SaveContext(dec, token_br, &context);
if (!VP8DecodeMB(dec, token_br)) {
RestoreContext(&context, dec, token_br);
// We shouldn't fail when MAX_MB data was available
@ -390,20 +458,18 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
}
return VP8_STATUS_SUSPENDED;
}
VP8ReconstructBlock(dec);
// Store data and save block's filtering params
VP8StoreBlock(dec);
// Release buffer only if there is only one partition
if (dec->num_parts_ == 1) {
idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_;
assert(idec->mem_.start_ <= idec->mem_.end_);
}
}
VP8InitScanline(dec); // Prepare for next scanline
// Reconstruct, filter and emit the row.
if (!VP8ProcessRow(dec, io)) {
return IDecError(idec, VP8_STATUS_USER_ABORT);
}
dec->mb_x_ = 0;
}
// Synchronize the thread and check for errors.
if (!VP8ExitCritical(dec, io)) {
@ -415,15 +481,72 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
return VP8_STATUS_OK;
}
static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
VP8StatusCode status) {
if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
return VP8_STATUS_SUSPENDED;
}
return IDecError(idec, status);
}
static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) {
VP8Io* const io = &idec->io_;
VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
const WebPDecParams* const params = &idec->params_;
WebPDecBuffer* const output = params->output;
size_t curr_size = MemDataSize(&idec->mem_);
assert(idec->is_lossless_);
// Wait until there's enough data for decoding header.
if (curr_size < (idec->chunk_size_ >> 3)) {
return VP8_STATUS_SUSPENDED;
}
if (!VP8LDecodeHeader(dec, io)) {
return ErrorStatusLossless(idec, dec->status_);
}
// Allocate/verify output buffer now.
dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options,
output);
if (dec->status_ != VP8_STATUS_OK) {
return IDecError(idec, dec->status_);
}
idec->state_ = STATE_VP8L_DATA;
return VP8_STATUS_OK;
}
static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
const size_t curr_size = MemDataSize(&idec->mem_);
assert(idec->is_lossless_);
// At present Lossless decoder can't decode image incrementally. So wait till
// all the image data is aggregated before image can be decoded.
if (curr_size < idec->chunk_size_) {
return VP8_STATUS_SUSPENDED;
}
if (!VP8LDecodeImage(dec)) {
return ErrorStatusLossless(idec, dec->status_);
}
idec->state_ = STATE_DONE;
return VP8_STATUS_OK;
}
// Main decoding loop
static VP8StatusCode IDecode(WebPIDecoder* idec) {
VP8StatusCode status = VP8_STATUS_SUSPENDED;
assert(idec->dec_);
if (idec->state_ == STATE_PRE_VP8) {
if (idec->state_ == STATE_WEBP_HEADER) {
status = DecodeWebPHeaders(idec);
} else {
if (idec->dec_ == NULL) {
return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
}
}
if (idec->state_ == STATE_VP8_FRAME_HEADER) {
if (idec->state_ == STATE_VP8_HEADER) {
status = DecodeVP8FrameHeader(idec);
}
if (idec->state_ == STATE_VP8_PARTS0) {
@ -432,47 +555,41 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
if (idec->state_ == STATE_VP8_DATA) {
status = DecodeRemaining(idec);
}
if (idec->state_ == STATE_VP8L_HEADER) {
status = DecodeVP8LHeader(idec);
}
if (idec->state_ == STATE_VP8L_DATA) {
status = DecodeVP8LData(idec);
}
return status;
}
//------------------------------------------------------------------------------
// Public functions
WebPIDecoder* WebPINewDecoder(WebPDecBuffer* const output_buffer) {
WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(WebPIDecoder));
WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec));
if (idec == NULL) {
return NULL;
}
idec->dec_ = VP8New();
if (idec->dec_ == NULL) {
free(idec);
return NULL;
}
idec->state_ = STATE_PRE_VP8;
idec->state_ = STATE_WEBP_HEADER;
idec->chunk_size_ = 0;
InitMemBuffer(&idec->mem_);
WebPInitDecBuffer(&idec->output_);
VP8InitIo(&idec->io_);
WebPResetDecParams(&idec->params_);
idec->params_.output = output_buffer ? output_buffer : &idec->output_;
idec->params_.output = (output_buffer != NULL) ? output_buffer
: &idec->output_;
WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions.
#ifdef WEBP_USE_THREAD
idec->dec_->use_threads_ = idec->params_.options &&
(idec->params_.options->use_threads > 0);
#else
idec->dec_->use_threads_ = 0;
#endif
idec->vp8_size_ = 0;
return idec;
}
WebPIDecoder* WebPIDecode(const uint8_t* data, uint32_t data_size,
WebPDecoderConfig* const config) {
WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
WebPDecoderConfig* config) {
WebPIDecoder* idec;
// Parse the bitstream's features, if requested:
@ -483,7 +600,7 @@ WebPIDecoder* WebPIDecode(const uint8_t* data, uint32_t data_size,
}
// Create an instance of the incremental decoder
idec = WebPINewDecoder(config ? &config->output : NULL);
if (!idec) {
if (idec == NULL) {
return NULL;
}
// Finish initialization
@ -493,9 +610,19 @@ WebPIDecoder* WebPIDecode(const uint8_t* data, uint32_t data_size,
return idec;
}
void WebPIDelete(WebPIDecoder* const idec) {
if (!idec) return;
VP8Delete(idec->dec_);
void WebPIDelete(WebPIDecoder* idec) {
if (idec == NULL) return;
if (idec->dec_ != NULL) {
if (!idec->is_lossless_) {
if (idec->state_ == STATE_VP8_DATA) {
// Synchronize the thread, clean-up and check for errors.
VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
}
VP8Delete((VP8Decoder*)idec->dec_);
} else {
VP8LDelete((VP8LDecoder*)idec->dec_);
}
}
ClearMemBuffer(&idec->mem_);
WebPFreeDecBuffer(&idec->output_);
free(idec);
@ -504,34 +631,58 @@ void WebPIDelete(WebPIDecoder* const idec) {
//------------------------------------------------------------------------------
// Wrapper toward WebPINewDecoder
WebPIDecoder* WebPINew(WEBP_CSP_MODE mode) {
WebPIDecoder* const idec = WebPINewDecoder(NULL);
if (!idec) return NULL;
idec->output_.colorspace = mode;
return idec;
}
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
int output_buffer_size, int output_stride) {
size_t output_buffer_size, int output_stride) {
const int is_external_memory = (output_buffer != NULL);
WebPIDecoder* idec;
if (mode >= MODE_YUV) return NULL;
if (!is_external_memory) { // Overwrite parameters to sane values.
output_buffer_size = 0;
output_stride = 0;
} else { // A buffer was passed. Validate the other params.
if (output_stride == 0 || output_buffer_size == 0) {
return NULL; // invalid parameter.
}
}
idec = WebPINewDecoder(NULL);
if (!idec) return NULL;
if (idec == NULL) return NULL;
idec->output_.colorspace = mode;
idec->output_.is_external_memory = 1;
idec->output_.is_external_memory = is_external_memory;
idec->output_.u.RGBA.rgba = output_buffer;
idec->output_.u.RGBA.stride = output_stride;
idec->output_.u.RGBA.size = output_buffer_size;
return idec;
}
WebPIDecoder* WebPINewYUV(uint8_t* luma, int luma_size, int luma_stride,
uint8_t* u, int u_size, int u_stride,
uint8_t* v, int v_size, int v_stride) {
WebPIDecoder* const idec = WebPINewDecoder(NULL);
if (!idec) return NULL;
idec->output_.colorspace = MODE_YUV;
idec->output_.is_external_memory = 1;
WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride,
uint8_t* a, size_t a_size, int a_stride) {
const int is_external_memory = (luma != NULL);
WebPIDecoder* idec;
WEBP_CSP_MODE colorspace;
if (!is_external_memory) { // Overwrite parameters to sane values.
luma_size = u_size = v_size = a_size = 0;
luma_stride = u_stride = v_stride = a_stride = 0;
u = v = a = NULL;
colorspace = MODE_YUVA;
} else { // A luma buffer was passed. Validate the other parameters.
if (u == NULL || v == NULL) return NULL;
if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL;
if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL;
if (a != NULL) {
if (a_size == 0 || a_stride == 0) return NULL;
}
colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
}
idec = WebPINewDecoder(NULL);
if (idec == NULL) return NULL;
idec->output_.colorspace = colorspace;
idec->output_.is_external_memory = is_external_memory;
idec->output_.u.YUVA.y = luma;
idec->output_.u.YUVA.y_stride = luma_stride;
idec->output_.u.YUVA.y_size = luma_size;
@ -541,16 +692,25 @@ WebPIDecoder* WebPINewYUV(uint8_t* luma, int luma_size, int luma_stride,
idec->output_.u.YUVA.v = v;
idec->output_.u.YUVA.v_stride = v_stride;
idec->output_.u.YUVA.v_size = v_size;
idec->output_.u.YUVA.a = a;
idec->output_.u.YUVA.a_stride = a_stride;
idec->output_.u.YUVA.a_size = a_size;
return idec;
}
WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride) {
return WebPINewYUVA(luma, luma_size, luma_stride,
u, u_size, u_stride,
v, v_size, v_stride,
NULL, 0, 0);
}
//------------------------------------------------------------------------------
static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
assert(idec);
if (idec->dec_ == NULL) {
return VP8_STATUS_USER_ABORT;
}
if (idec->state_ == STATE_ERROR) {
return VP8_STATUS_BITSTREAM_ERROR;
}
@ -560,8 +720,8 @@ static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
return VP8_STATUS_SUSPENDED;
}
VP8StatusCode WebPIAppend(WebPIDecoder* const idec, const uint8_t* data,
uint32_t data_size) {
VP8StatusCode WebPIAppend(WebPIDecoder* idec,
const uint8_t* data, size_t data_size) {
VP8StatusCode status;
if (idec == NULL || data == NULL) {
return VP8_STATUS_INVALID_PARAM;
@ -581,8 +741,8 @@ VP8StatusCode WebPIAppend(WebPIDecoder* const idec, const uint8_t* data,
return IDecode(idec);
}
VP8StatusCode WebPIUpdate(WebPIDecoder* const idec, const uint8_t* data,
uint32_t data_size) {
VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
const uint8_t* data, size_t data_size) {
VP8StatusCode status;
if (idec == NULL || data == NULL) {
return VP8_STATUS_INVALID_PARAM;
@ -605,61 +765,67 @@ VP8StatusCode WebPIUpdate(WebPIDecoder* const idec, const uint8_t* data,
//------------------------------------------------------------------------------
static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) {
if (!idec || !idec->dec_ || idec->state_ <= STATE_VP8_PARTS0) {
if (idec == NULL || idec->dec_ == NULL) {
return NULL;
}
if (idec->state_ <= STATE_VP8_PARTS0) {
return NULL;
}
return idec->params_.output;
}
const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* const idec,
int* const left, int* const top,
int* const width, int* const height) {
const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
int* left, int* top,
int* width, int* height) {
const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (left) *left = 0;
if (top) *top = 0;
if (left != NULL) *left = 0;
if (top != NULL) *top = 0;
// TODO(skal): later include handling of rotations.
if (src) {
if (width) *width = src->width;
if (height) *height = idec->params_.last_y;
if (width != NULL) *width = src->width;
if (height != NULL) *height = idec->params_.last_y;
} else {
if (width) *width = 0;
if (height) *height = 0;
if (width != NULL) *width = 0;
if (height != NULL) *height = 0;
}
return src;
}
uint8_t* WebPIDecGetRGB(const WebPIDecoder* const idec, int* last_y,
uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
int* width, int* height, int* stride) {
const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (!src) return NULL;
if (src == NULL) return NULL;
if (src->colorspace >= MODE_YUV) {
return NULL;
}
if (last_y) *last_y = idec->params_.last_y;
if (width) *width = src->width;
if (height) *height = src->height;
if (stride) *stride = src->u.RGBA.stride;
if (last_y != NULL) *last_y = idec->params_.last_y;
if (width != NULL) *width = src->width;
if (height != NULL) *height = src->height;
if (stride != NULL) *stride = src->u.RGBA.stride;
return src->u.RGBA.rgba;
}
uint8_t* WebPIDecGetYUV(const WebPIDecoder* const idec, int* last_y,
uint8_t** u, uint8_t** v,
int* width, int* height, int *stride, int* uv_stride) {
uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
uint8_t** u, uint8_t** v, uint8_t** a,
int* width, int* height,
int* stride, int* uv_stride, int* a_stride) {
const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (!src) return NULL;
if (src == NULL) return NULL;
if (src->colorspace < MODE_YUV) {
return NULL;
}
if (last_y) *last_y = idec->params_.last_y;
if (u) *u = src->u.YUVA.u;
if (v) *v = src->u.YUVA.v;
if (width) *width = src->width;
if (height) *height = src->height;
if (stride) *stride = src->u.YUVA.y_stride;
if (uv_stride) *uv_stride = src->u.YUVA.u_stride;
if (last_y != NULL) *last_y = idec->params_.last_y;
if (u != NULL) *u = src->u.YUVA.u;
if (v != NULL) *v = src->u.YUVA.v;
if (a != NULL) *a = src->u.YUVA.a;
if (width != NULL) *width = src->width;
if (height != NULL) *height = src->height;
if (stride != NULL) *stride = src->u.YUVA.y_stride;
if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride;
if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride;
return src->u.YUVA.y;
}
@ -669,7 +835,7 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
VP8IoSetupHook setup,
VP8IoTeardownHook teardown,
void* user_data) {
if (!idec || !idec->dec_ || idec->state_ > STATE_PRE_VP8) {
if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) {
return 0;
}
@ -681,6 +847,3 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
return 1;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// functions for sample output.
@ -16,10 +18,6 @@
#include "../dsp/dsp.h"
#include "../dsp/yuv.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// Main YUV<->RGB conversion functions
@ -32,11 +30,12 @@ static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
const int uv_w = (mb_w + 1) / 2;
const int uv_h = (mb_h + 1) / 2;
int j;
for (j = 0; j < mb_h; ++j) {
memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
}
for (j = 0; j < (mb_h + 1) / 2; ++j) {
for (j = 0; j < uv_h; ++j) {
memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w);
memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
}
@ -103,29 +102,25 @@ static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
int num_lines_out = io->mb_h; // a priori guess
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
const WebPUpsampleLinePairFunc upsample =
io->a ? WebPUpsamplersKeepAlpha[p->output->colorspace]
: WebPUpsamplers[p->output->colorspace];
WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
const uint8_t* cur_y = io->y;
const uint8_t* cur_u = io->u;
const uint8_t* cur_v = io->v;
const uint8_t* top_u = p->tmp_u;
const uint8_t* top_v = p->tmp_v;
int y = io->mb_y;
int y_end = io->mb_y + io->mb_h;
const int y_end = io->mb_y + io->mb_h;
const int mb_w = io->mb_w;
const int uv_w = (mb_w + 1) / 2;
if (y == 0) {
// First line is special cased. We mirror the u/v samples at boundary.
upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, mb_w);
upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, mb_w);
} else {
// We can finish the left-over line from previous call.
// Warning! Don't overwrite the alpha values (if any), as they
// are not lagging one line behind but are already written.
upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v,
dst - buf->stride, dst, mb_w);
num_lines_out++;
++num_lines_out;
}
// Loop over each output pairs of row.
for (; y + 2 < y_end; y += 2) {
@ -153,7 +148,7 @@ static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
// Process the very last row of even-sized picture
if (!(y_end & 1)) {
upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v,
dst + buf->stride, NULL, mb_w);
dst + buf->stride, NULL, mb_w);
}
}
return num_lines_out;
@ -163,151 +158,130 @@ static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
//------------------------------------------------------------------------------
#ifdef WEBP_EXPERIMENTAL_FEATURES
static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
const uint8_t* alpha = io->a;
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
int j;
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
uint8_t* dst = buf->a + io->mb_y * buf->a_stride;
const uint8_t* alpha = io->a;
if (alpha) {
int j;
if (alpha != NULL) {
for (j = 0; j < mb_h; ++j) {
memcpy(dst, alpha, mb_w * sizeof(*dst));
alpha += io->width;
dst += buf->a_stride;
}
} else if (buf->a != NULL) {
// the user requested alpha, but there is none, set it to opaque.
for (j = 0; j < mb_h; ++j) {
memset(dst, 0xff, mb_w * sizeof(*dst));
dst += buf->a_stride;
}
}
return 0;
}
static int GetAlphaSourceRow(const VP8Io* const io,
const uint8_t** alpha, int* const num_rows) {
int start_y = io->mb_y;
*num_rows = io->mb_h;
// Compensate for the 1-line delay of the fancy upscaler.
// This is similar to EmitFancyRGB().
if (io->fancy_upsampling) {
if (start_y == 0) {
// We don't process the last row yet. It'll be done during the next call.
--*num_rows;
} else {
--start_y;
// Fortunately, *alpha data is persistent, so we can go back
// one row and finish alpha blending, now that the fancy upscaler
// completed the YUV->RGB interpolation.
*alpha -= io->width;
}
if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) {
// If it's the very last call, we process all the remaining rows!
*num_rows = io->crop_bottom - io->crop_top - start_y;
}
}
return start_y;
}
static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
int i, j;
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
const uint8_t* alpha = io->a;
if (alpha) {
for (j = 0; j < mb_h; ++j) {
if (alpha != NULL) {
const int mb_w = io->mb_w;
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int alpha_first =
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
int num_rows;
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
uint32_t alpha_mask = 0xff;
int i, j;
for (j = 0; j < num_rows; ++j) {
for (i = 0; i < mb_w; ++i) {
dst[4 * i + 3] = alpha[i];
const uint32_t alpha_value = alpha[i];
dst[4 * i] = alpha_value;
alpha_mask &= alpha_value;
}
alpha += io->width;
dst += buf->stride;
}
// alpha_mask is < 0xff if there's non-trivial alpha to premultiply with.
if (alpha_mask != 0xff && WebPIsPremultipliedMode(colorspace)) {
WebPApplyAlphaMultiply(base_rgba, alpha_first,
mb_w, num_rows, buf->stride);
}
}
return 0;
}
#endif /* WEBP_EXPERIMENTAL_FEATURES */
static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
const uint8_t* alpha = io->a;
if (alpha != NULL) {
const int mb_w = io->mb_w;
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
int num_rows;
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
uint8_t* alpha_dst = base_rgba + 1;
uint32_t alpha_mask = 0x0f;
int i, j;
//------------------------------------------------------------------------------
// Simple picture rescaler
// TODO(skal): start a common library for encoder and decoder, and factorize
// this code in.
#define RFIX 30
#define MULT(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX)
static void InitRescaler(WebPRescaler* const wrk,
int src_width, int src_height,
uint8_t* dst,
int dst_width, int dst_height, int dst_stride,
int x_add, int x_sub, int y_add, int y_sub,
int32_t* work) {
wrk->x_expand = (src_width < dst_width);
wrk->src_width = src_width;
wrk->src_height = src_height;
wrk->dst_width = dst_width;
wrk->dst_height = dst_height;
wrk->dst = dst;
wrk->dst_stride = dst_stride;
// for 'x_expand', we use bilinear interpolation
wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub;
wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
wrk->y_accum = y_add;
wrk->y_add = y_add;
wrk->y_sub = y_sub;
wrk->fx_scale = (1 << RFIX) / x_sub;
wrk->fy_scale = (1 << RFIX) / y_sub;
wrk->fxy_scale = wrk->x_expand ?
((int64_t)dst_height << RFIX) / (x_sub * src_height) :
((int64_t)dst_height << RFIX) / (x_add * src_height);
wrk->irow = work;
wrk->frow = work + dst_width;
}
static inline void ImportRow(const uint8_t* const src,
WebPRescaler* const wrk) {
int x_in = 0;
int x_out;
int accum = 0;
if (!wrk->x_expand) {
int sum = 0;
for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
accum += wrk->x_add;
for (; accum > 0; accum -= wrk->x_sub) {
sum += src[x_in++];
}
{ // Emit next horizontal pixel.
const int32_t base = src[x_in++];
const int32_t frac = base * (-accum);
wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac;
// fresh fractional start for next pixel
sum = MULT(frac, wrk->fx_scale);
for (j = 0; j < num_rows; ++j) {
for (i = 0; i < mb_w; ++i) {
// Fill in the alpha value (converted to 4 bits).
const uint32_t alpha_value = alpha[i] >> 4;
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
alpha_mask &= alpha_value;
}
alpha += io->width;
alpha_dst += buf->stride;
}
} else { // simple bilinear interpolation
int left = src[0], right = src[0];
for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
if (accum < 0) {
left = right;
right = src[++x_in];
accum += wrk->x_add;
}
wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
accum -= wrk->x_sub;
if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) {
WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride);
}
}
// Accumulate the new row's contribution
for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
wrk->irow[x_out] += wrk->frow[x_out];
}
return 0;
}
static void ExportRow(WebPRescaler* const wrk) {
int x_out;
const int yscale = wrk->fy_scale * (-wrk->y_accum);
assert(wrk->y_accum <= 0);
for (x_out = 0; x_out < wrk->dst_width; ++x_out) {
const int frac = MULT(wrk->frow[x_out], yscale);
const int v = (int)MULT(wrk->irow[x_out] - frac, wrk->fxy_scale);
wrk->dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
wrk->irow[x_out] = frac; // new fractional start
}
wrk->y_accum += wrk->y_add;
wrk->dst += wrk->dst_stride;
}
#undef MULT
#undef RFIX
//------------------------------------------------------------------------------
// YUV rescaling (no final RGB conversion needed)
static int Rescale(const uint8_t* src, int src_stride,
int new_lines, WebPRescaler* const wrk) {
int num_lines_out = 0;
while (new_lines-- > 0) { // import new contribution of one source row.
ImportRow(src, wrk);
src += src_stride;
wrk->y_accum -= wrk->y_sub;
while (wrk->y_accum <= 0) { // emit output row(s)
ExportRow(wrk);
num_lines_out++;
}
while (new_lines > 0) { // import new contributions of source rows.
const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride);
src += lines_in * src_stride;
new_lines -= lines_in;
num_lines_out += WebPRescalerExport(wrk); // emit output row(s)
}
return num_lines_out;
}
@ -322,19 +296,14 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
}
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
if (io->a) {
if (io->a != NULL) {
Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
}
return 0;
}
static int IsAlphaMode(WEBP_CSP_MODE mode) {
return (mode == MODE_RGBA || mode == MODE_BGRA || mode == MODE_ARGB ||
mode == MODE_RGBA_4444 || mode == MODE_YUVA);
}
static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int has_alpha = IsAlphaMode(p->output->colorspace);
const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
const int out_width = io->scaled_width;
const int out_height = io->scaled_height;
@ -356,26 +325,27 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
return 0; // memory error
}
work = (int32_t*)p->memory;
InitRescaler(&p->scaler_y, io->mb_w, io->mb_h,
buf->y, out_width, out_height, buf->y_stride,
io->mb_w, out_width, io->mb_h, out_height,
work);
InitRescaler(&p->scaler_u, uv_in_width, uv_in_height,
buf->u, uv_out_width, uv_out_height, buf->u_stride,
uv_in_width, uv_out_width,
uv_in_height, uv_out_height,
work + work_size);
InitRescaler(&p->scaler_v, uv_in_width, uv_in_height,
buf->v, uv_out_width, uv_out_height, buf->v_stride,
uv_in_width, uv_out_width,
uv_in_height, uv_out_height,
work + work_size + uv_work_size);
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
buf->y, out_width, out_height, buf->y_stride, 1,
io->mb_w, out_width, io->mb_h, out_height,
work);
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
uv_in_width, uv_out_width,
uv_in_height, uv_out_height,
work + work_size);
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
uv_in_width, uv_out_width,
uv_in_height, uv_out_height,
work + work_size + uv_work_size);
p->emit = EmitRescaledYUV;
if (has_alpha) {
InitRescaler(&p->scaler_a, io->mb_w, io->mb_h,
buf->a, out_width, out_height, buf->a_stride,
io->mb_w, out_width, io->mb_h, out_height,
work + work_size + 2 * uv_work_size);
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
buf->a, out_width, out_height, buf->a_stride, 1,
io->mb_w, out_width, io->mb_h, out_height,
work + work_size + 2 * uv_work_size);
p->emit_alpha = EmitRescaledAlphaYUV;
}
return 1;
@ -384,20 +354,6 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
//------------------------------------------------------------------------------
// RGBA rescaling
// import new contributions until one row is ready to be output, or all input
// is consumed.
static int Import(const uint8_t* src, int src_stride,
int new_lines, WebPRescaler* const wrk) {
int num_lines_in = 0;
while (num_lines_in < new_lines && wrk->y_accum > 0) {
ImportRow(src, wrk);
src += src_stride;
++num_lines_in;
wrk->y_accum -= wrk->y_sub;
}
return num_lines_in;
}
static int ExportRGB(WebPDecParams* const p, int y_pos) {
const WebPYUV444Converter convert =
WebPYUV444Converters[p->output->colorspace];
@ -406,16 +362,17 @@ 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 (p->scaler_y.y_accum <= 0 && p->scaler_u.y_accum <= 0) {
while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
WebPRescalerHasPendingOutput(&p->scaler_u)) {
assert(p->last_y + y_pos + num_lines_out < p->output->height);
assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
ExportRow(&p->scaler_y);
ExportRow(&p->scaler_u);
ExportRow(&p->scaler_v);
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++;
++num_lines_out;
}
return num_lines_out;
}
@ -426,12 +383,15 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
int j = 0, uv_j = 0;
int num_lines_out = 0;
while (j < mb_h) {
const int y_lines_in = Import(io->y + j * io->y_stride, io->y_stride,
mb_h - j, &p->scaler_y);
const int u_lines_in = Import(io->u + uv_j * io->uv_stride, io->uv_stride,
uv_mb_h - uv_j, &p->scaler_u);
const int v_lines_in = Import(io->v + uv_j * io->uv_stride, io->uv_stride,
uv_mb_h - uv_j, &p->scaler_v);
const int y_lines_in =
WebPRescalerImport(&p->scaler_y, mb_h - j,
io->y + j * io->y_stride, io->y_stride);
const int u_lines_in =
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,
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);
j += y_lines_in;
@ -443,34 +403,80 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
static int ExportAlpha(WebPDecParams* const p, int y_pos) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride;
uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int alpha_first =
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
int num_lines_out = 0;
while (p->scaler_a.y_accum <= 0) {
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
uint32_t alpha_mask = 0xff;
const int width = p->scaler_a.dst_width;
while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
int i;
assert(p->last_y + y_pos + num_lines_out < p->output->height);
ExportRow(&p->scaler_a);
for (i = 0; i < p->scaler_a.dst_width; ++i) {
dst[4 * i + 3] = p->scaler_a.dst[i];
WebPRescalerExportRow(&p->scaler_a);
for (i = 0; i < width; ++i) {
const uint32_t alpha_value = p->scaler_a.dst[i];
dst[4 * i] = alpha_value;
alpha_mask &= alpha_value;
}
dst += buf->stride;
num_lines_out++;
++num_lines_out;
}
if (is_premult_alpha && alpha_mask != 0xff) {
WebPApplyAlphaMultiply(base_rgba, alpha_first,
width, num_lines_out, buf->stride);
}
return num_lines_out;
}
static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
uint8_t* alpha_dst = base_rgba + 1;
int num_lines_out = 0;
const WEBP_CSP_MODE colorspace = p->output->colorspace;
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)) {
int i;
assert(p->last_y + y_pos + num_lines_out < p->output->height);
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;
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
alpha_mask &= alpha_value;
}
alpha_dst += buf->stride;
++num_lines_out;
}
if (is_premult_alpha && alpha_mask != 0x0f) {
WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);
}
return num_lines_out;
}
static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
if (io->a) {
int j = 0, pos = 0;
if (io->a != NULL) {
WebPRescaler* const scaler = &p->scaler_a;
int j = 0;
int pos = 0;
while (j < io->mb_h) {
j += Import(io->a + j * io->width, io->width, io->mb_h - j, &p->scaler_a);
pos += ExportAlpha(p, pos);
j += WebPRescalerImport(scaler, io->mb_h - j,
io->a + j * io->width, io->width);
pos += p->emit_alpha_row(p, pos);
}
}
return 0;
}
static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int has_alpha = IsAlphaMode(p->output->colorspace);
const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
const int out_width = io->scaled_width;
const int out_height = io->scaled_height;
const int uv_in_width = (io->mb_w + 1) >> 1;
@ -486,33 +492,38 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
tmp_size1 += work_size;
tmp_size2 += out_width;
}
p->memory =
calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
p->memory = calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
if (p->memory == NULL) {
return 0; // memory error
}
work = (int32_t*)p->memory;
tmp = (uint8_t*)(work + tmp_size1);
InitRescaler(&p->scaler_y, io->mb_w, io->mb_h,
tmp + 0 * out_width, out_width, out_height, 0,
io->mb_w, out_width, io->mb_h, out_height,
work + 0 * work_size);
InitRescaler(&p->scaler_u, uv_in_width, uv_in_height,
tmp + 1 * out_width, out_width, out_height, 0,
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
work + 1 * work_size);
InitRescaler(&p->scaler_v, uv_in_width, uv_in_height,
tmp + 2 * out_width, out_width, out_height, 0,
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
work + 2 * work_size);
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
tmp + 0 * out_width, out_width, out_height, 0, 1,
io->mb_w, out_width, io->mb_h, out_height,
work + 0 * work_size);
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
tmp + 1 * out_width, out_width, out_height, 0, 1,
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
work + 1 * work_size);
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
tmp + 2 * out_width, out_width, out_height, 0, 1,
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
work + 2 * work_size);
p->emit = EmitRescaledRGB;
if (has_alpha) {
InitRescaler(&p->scaler_a, io->mb_w, io->mb_h,
tmp + 3 * out_width, out_width, out_height, 0,
io->mb_w, out_width, io->mb_h, out_height,
work + 3 * work_size);
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
tmp + 3 * out_width, out_width, out_height, 0, 1,
io->mb_w, out_width, io->mb_h, out_height,
work + 3 * work_size);
p->emit_alpha = EmitRescaledAlphaRGB;
if (p->output->colorspace == MODE_RGBA_4444 ||
p->output->colorspace == MODE_rgbA_4444) {
p->emit_alpha_row = ExportAlphaRGBA4444;
} else {
p->emit_alpha_row = ExportAlpha;
}
}
return 1;
}
@ -520,67 +531,17 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
//------------------------------------------------------------------------------
// Default custom functions
// Setup crop_xxx fields, mb_w and mb_h
static int InitFromOptions(const WebPDecoderOptions* const options,
VP8Io* const io) {
const int W = io->width;
const int H = io->height;
int x = 0, y = 0, w = W, h = H;
// Cropping
io->use_cropping = (options != NULL) && (options->use_cropping > 0);
if (io->use_cropping) {
w = options->crop_width;
h = options->crop_height;
// TODO(skal): take colorspace into account. Don't assume YUV420.
x = options->crop_left & ~1;
y = options->crop_top & ~1;
if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
return 0; // out of frame boundary error
}
}
io->crop_left = x;
io->crop_top = y;
io->crop_right = x + w;
io->crop_bottom = y + h;
io->mb_w = w;
io->mb_h = h;
// Scaling
io->use_scaling = (options != NULL) && (options->use_scaling > 0);
if (io->use_scaling) {
if (options->scaled_width <= 0 || options->scaled_height <= 0) {
return 0;
}
io->scaled_width = options->scaled_width;
io->scaled_height = options->scaled_height;
}
// Filter
io->bypass_filtering = options && options->bypass_filtering;
// Fancy upsampler
#ifdef FANCY_UPSAMPLING
io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
#endif
if (io->use_scaling) {
// disable filter (only for large downscaling ratio).
io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
(io->scaled_height < H * 3 / 4);
io->fancy_upsampling = 0;
}
return 1;
}
static int CustomSetup(VP8Io* io) {
WebPDecParams* const p = (WebPDecParams*)io->opaque;
const int is_rgb = (p->output->colorspace < MODE_YUV);
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int is_rgb = WebPIsRGBMode(colorspace);
const int is_alpha = WebPIsAlphaMode(colorspace);
p->memory = NULL;
p->emit = NULL;
p->emit_alpha = NULL;
if (!InitFromOptions(p->options, io)) {
p->emit_alpha_row = NULL;
if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
return 0;
}
@ -609,12 +570,14 @@ static int CustomSetup(VP8Io* io) {
} else {
p->emit = EmitYUV;
}
#ifdef WEBP_EXPERIMENTAL_FEATURES
if (IsAlphaMode(p->output->colorspace)) {
// We need transparency output
p->emit_alpha = is_rgb ? EmitAlphaRGB : EmitAlphaYUV;
if (is_alpha) { // need transparency output
if (WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply();
p->emit_alpha =
(colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ?
EmitAlphaRGBA4444
: is_rgb ? EmitAlphaRGB
: EmitAlphaYUV;
}
#endif
}
if (is_rgb) {
@ -626,7 +589,7 @@ static int CustomSetup(VP8Io* io) {
//------------------------------------------------------------------------------
static int CustomPut(const VP8Io* io) {
WebPDecParams* p = (WebPDecParams*)io->opaque;
WebPDecParams* const p = (WebPDecParams*)io->opaque;
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
int num_lines_out;
@ -636,7 +599,7 @@ static int CustomPut(const VP8Io* io) {
return 0;
}
num_lines_out = p->emit(io, p);
if (p->emit_alpha) {
if (p->emit_alpha != NULL) {
p->emit_alpha(io, p);
}
p->last_y += num_lines_out;
@ -663,6 +626,3 @@ void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) {
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Enhancement layer (for YUV444/422)
@ -11,11 +13,8 @@
#include <assert.h>
#include <stdlib.h>
#include "vp8i.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "./vp8i.h"
//------------------------------------------------------------------------------
@ -29,6 +28,3 @@ int VP8DecodeLayer(VP8Decoder* const dec) {
return 1;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,21 +1,19 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Quantizer initialization
//
// Author: Skal (pascal.massimino@gmail.com)
#include "vp8i.h"
#include "./vp8i.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static inline int clip(int v, int M) {
static WEBP_INLINE int clip(int v, int M) {
return v < 0 ? 0 : v > M ? M : v;
}
@ -94,18 +92,19 @@ void VP8ParseQuant(VP8Decoder* const dec) {
m->y1_mat_[1] = kAcTable[clip(q + 0, 127)];
m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2;
// TODO(skal): make it another table?
m->y2_mat_[1] = kAcTable[clip(q + dqy2_ac, 127)] * 155 / 100;
// For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16.
// The smallest precision for that is '(x*6349) >> 12' but 16 is a good
// word size.
m->y2_mat_[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16;
if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8;
m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)];
m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)];
m->uv_quant_ = q + dquv_ac; // for dithering strength evaluation
}
}
}
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Coding trees and probas
@ -13,10 +15,6 @@
#define USE_GENERIC_TREE
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#ifdef USE_GENERIC_TREE
static const int8_t kYModesIntra4[18] = {
-B_DC_PRED, 1,
@ -31,61 +29,12 @@ static const int8_t kYModesIntra4[18] = {
};
#endif
#ifndef ONLY_KEYFRAME_CODE
// inter prediction modes
enum {
LEFT4 = 0, ABOVE4 = 1, ZERO4 = 2, NEW4 = 3,
NEARESTMV, NEARMV, ZEROMV, NEWMV, SPLITMV };
static const int8_t kYModesInter[8] = {
-DC_PRED, 1,
2, 3,
-V_PRED, -H_PRED,
-TM_PRED, -B_PRED
};
static const int8_t kMBSplit[6] = {
-3, 1,
-2, 2,
-0, -1
};
static const int8_t kMVRef[8] = {
-ZEROMV, 1,
-NEARESTMV, 2,
-NEARMV, 3,
-NEWMV, -SPLITMV
};
static const int8_t kMVRef4[6] = {
-LEFT4, 1
-ABOVE4, 2
-ZERO4, -NEW4
};
#endif
//------------------------------------------------------------------------------
// Default probabilities
// Inter
#ifndef ONLY_KEYFRAME_CODE
static const uint8_t kYModeProbaInter0[4] = { 112, 86, 140, 37 };
static const uint8_t kUVModeProbaInter0[3] = { 162, 101, 204 };
static const uint8_t kMVProba0[2][NUM_MV_PROBAS] = {
{ 162, 128, 225, 146, 172, 147, 214, 39,
156, 128, 129, 132, 75, 145, 178, 206,
239, 254, 254 },
{ 164, 128, 204, 170, 119, 235, 140, 230,
228, 128, 130, 130, 74, 148, 180, 203,
236, 254, 254 }
};
#endif
// Paragraph 13.5
static const uint8_t
CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
// genereated using vp8_default_coef_probs() in entropy.c:129
{ { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
@ -326,28 +275,25 @@ static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
void VP8ResetProba(VP8Proba* const proba) {
memset(proba->segments_, 255u, sizeof(proba->segments_));
memcpy(proba->coeffs_, CoeffsProba0, sizeof(CoeffsProba0));
#ifndef ONLY_KEYFRAME_CODE
memcpy(proba->mv_, kMVProba0, sizeof(kMVProba0));
memcpy(proba->ymode_, kYModeProbaInter0, sizeof(kYModeProbaInter0));
memcpy(proba->uvmode_, kUVModeProbaInter0, sizeof(kUVModeProbaInter0));
#endif
// proba->bands_[][] is initialized later
}
void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
uint8_t* const top = dec->intra_t_ + 4 * dec->mb_x_;
uint8_t* const left = dec->intra_l_;
// Hardcoded 16x16 intra-mode decision tree.
dec->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
if (!dec->is_i4x4_) {
VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
block->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
if (!block->is_i4x4_) {
// Hardcoded 16x16 intra-mode decision tree.
const int ymode =
VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED)
: (VP8GetBit(br, 163) ? V_PRED : DC_PRED);
dec->imodes_[0] = ymode;
memset(top, ymode, 4 * sizeof(top[0]));
memset(left, ymode, 4 * sizeof(left[0]));
block->imodes_[0] = ymode;
memset(top, ymode, 4 * sizeof(*top));
memset(left, ymode, 4 * sizeof(*left));
} else {
uint8_t* modes = dec->imodes_;
uint8_t* modes = block->imodes_;
int y;
for (y = 0; y < 4; ++y) {
int ymode = left[y];
@ -356,10 +302,10 @@ void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
const uint8_t* const prob = kBModesProba[top[x]][ymode];
#ifdef USE_GENERIC_TREE
// Generic tree-parsing
int i = 0;
do {
int i = kYModesIntra4[VP8GetBit(br, prob[0])];
while (i > 0) {
i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])];
} while (i > 0);
}
ymode = -i;
#else
// Hardcoded tree parsing
@ -374,15 +320,16 @@ void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
#endif // USE_GENERIC_TREE
top[x] = ymode;
*modes++ = ymode;
}
memcpy(modes, top, 4 * sizeof(*top));
modes += 4;
left[y] = ymode;
}
}
// Hardcoded UVMode decision tree
dec->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
: !VP8GetBit(br, 114) ? V_PRED
: VP8GetBit(br, 183) ? TM_PRED : H_PRED;
block->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
: !VP8GetBit(br, 114) ? V_PRED
: VP8GetBit(br, 183) ? TM_PRED : H_PRED;
}
//------------------------------------------------------------------------------
@ -524,17 +471,6 @@ static const uint8_t
}
};
#ifndef ONLY_KEYFRAME_CODE
static const uint8_t MVUpdateProba[2][NUM_MV_PROBAS] = {
{ 237, 246, 253, 253, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 250, 250,
252, 254, 254 },
{ 231, 243, 245, 253, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 251, 251,
254, 254, 254 }
};
#endif
// Paragraph 9.9
void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
VP8Proba* const proba = &dec->proba_;
@ -543,9 +479,9 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
for (b = 0; b < NUM_BANDS; ++b) {
for (c = 0; c < NUM_CTX; ++c) {
for (p = 0; p < NUM_PROBAS; ++p) {
if (VP8GetBit(br, CoeffsUpdateProba[t][b][c][p])) {
proba->coeffs_[t][b][c][p] = VP8GetValue(br, 8);
}
const int v = VP8GetBit(br, CoeffsUpdateProba[t][b][c][p]) ?
VP8GetValue(br, 8) : CoeffsProba0[t][b][c][p];
proba->bands_[t][b].probas_[c][p] = v;
}
}
}
@ -554,36 +490,5 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
if (dec->use_skip_proba_) {
dec->skip_p_ = VP8GetValue(br, 8);
}
#ifndef ONLY_KEYFRAME_CODE
if (!dec->frm_hdr_.key_frame_) {
int i;
dec->intra_p_ = VP8GetValue(br, 8);
dec->last_p_ = VP8GetValue(br, 8);
dec->golden_p_ = VP8GetValue(br, 8);
if (VP8Get(br)) { // update y-mode
for (i = 0; i < 4; ++i) {
proba->ymode_[i] = VP8GetValue(br, 8);
}
}
if (VP8Get(br)) { // update uv-mode
for (i = 0; i < 3; ++i) {
proba->uvmode_[i] = VP8GetValue(br, 8);
}
}
// update MV
for (i = 0; i < 2; ++i) {
int k;
for (k = 0; k < NUM_MV_PROBAS; ++k) {
if (VP8GetBit(br, MVUpdateProba[i][k])) {
const int v = VP8GetValue(br, 7);
proba->mv_[i][k] = v ? v << 1 : 1;
}
}
}
}
#endif
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// main entry for the decoder
@ -10,12 +12,12 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
#include "vp8i.h"
#include "webpi.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "./alphai.h"
#include "./vp8i.h"
#include "./vp8li.h"
#include "./webpi.h"
#include "../utils/bit_reader.h"
//------------------------------------------------------------------------------
@ -32,20 +34,22 @@ static void SetOk(VP8Decoder* const dec) {
}
int VP8InitIoInternal(VP8Io* const io, int version) {
if (version != WEBP_DECODER_ABI_VERSION)
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
return 0; // mismatch error
if (io) {
}
if (io != NULL) {
memset(io, 0, sizeof(*io));
}
return 1;
}
VP8Decoder* VP8New(void) {
VP8Decoder* dec = (VP8Decoder*)calloc(1, sizeof(VP8Decoder));
if (dec) {
VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(*dec));
if (dec != NULL) {
SetOk(dec);
WebPWorkerInit(&dec->worker_);
dec->ready_ = 0;
dec->num_parts_ = 1;
}
return dec;
}
@ -56,35 +60,46 @@ VP8StatusCode VP8Status(VP8Decoder* const dec) {
}
const char* VP8StatusMessage(VP8Decoder* const dec) {
if (!dec) return "no object";
if (dec == NULL) return "no object";
if (!dec->error_msg_) return "OK";
return dec->error_msg_;
}
void VP8Delete(VP8Decoder* const dec) {
if (dec) {
if (dec != NULL) {
VP8Clear(dec);
free(dec);
}
}
int VP8SetError(VP8Decoder* const dec,
VP8StatusCode error, const char * const msg) {
dec->status_ = error;
dec->error_msg_ = msg;
dec->ready_ = 0;
VP8StatusCode error, const char* const msg) {
// TODO This check would be unnecessary if alpha decompression was separated
// from VP8ProcessRow/FinishRow. This avoids setting 'dec->status_' to
// something other than VP8_STATUS_BITSTREAM_ERROR on alpha decompression
// failure.
if (dec->status_ == VP8_STATUS_OK) {
dec->status_ = error;
dec->error_msg_ = msg;
dec->ready_ = 0;
}
return 0;
}
//------------------------------------------------------------------------------
int VP8GetInfo(const uint8_t* data, uint32_t data_size, uint32_t chunk_size,
int* width, int* height, int* has_alpha) {
if (data_size < 10) {
int VP8CheckSignature(const uint8_t* const data, size_t data_size) {
return (data_size >= 3 &&
data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a);
}
int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
int* const width, int* const height) {
if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) {
return 0; // not enough data
}
// check signature
if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a) {
if (!VP8CheckSignature(data + 3, data_size - 3)) {
return 0; // Wrong signature.
} else {
const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16);
@ -92,14 +107,6 @@ int VP8GetInfo(const uint8_t* data, uint32_t data_size, uint32_t chunk_size,
const int w = ((data[7] << 8) | data[6]) & 0x3fff;
const int h = ((data[9] << 8) | data[8]) & 0x3fff;
if (has_alpha) {
#ifdef WEBP_EXPERIMENTAL_FEATURES
if (data_size < 11) return 0;
*has_alpha = !!(data[10] & 0x80); // the colorspace_ bit
#else
*has_alpha = 0;
#endif
}
if (!key_frame) { // Not a keyframe.
return 0;
}
@ -113,6 +120,9 @@ int VP8GetInfo(const uint8_t* data, uint32_t data_size, uint32_t chunk_size,
if (((bits >> 5)) >= chunk_size) { // partition_length
return 0; // inconsistent size information.
}
if (w == 0 || h == 0) {
return 0; // We don't support both width and height to be zero.
}
if (width) {
*width = w;
@ -129,7 +139,7 @@ int VP8GetInfo(const uint8_t* data, uint32_t data_size, uint32_t chunk_size,
// Header parsing
static void ResetSegmentHeader(VP8SegmentHeader* const hdr) {
assert(hdr);
assert(hdr != NULL);
hdr->use_segment_ = 0;
hdr->update_map_ = 0;
hdr->absolute_delta_ = 1;
@ -140,8 +150,8 @@ static void ResetSegmentHeader(VP8SegmentHeader* const hdr) {
// Paragraph 9.3
static int ParseSegmentHeader(VP8BitReader* br,
VP8SegmentHeader* hdr, VP8Proba* proba) {
assert(br);
assert(hdr);
assert(br != NULL);
assert(hdr != NULL);
hdr->use_segment_ = VP8Get(br);
if (hdr->use_segment_) {
hdr->update_map_ = VP8Get(br);
@ -177,7 +187,7 @@ static int ParseSegmentHeader(VP8BitReader* br,
// is returned, and this is an unrecoverable error.
// If the partitions were positioned ok, VP8_STATUS_OK is returned.
static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
const uint8_t* buf, uint32_t size) {
const uint8_t* buf, size_t size) {
VP8BitReader* const br = &dec->br_;
const uint8_t* sz = buf;
const uint8_t* buf_end = buf + size;
@ -228,29 +238,13 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
}
}
dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2;
if (dec->filter_type_ > 0) { // precompute filter levels per segment
if (dec->segment_hdr_.use_segment_) {
int s;
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
int strength = dec->segment_hdr_.filter_strength_[s];
if (!dec->segment_hdr_.absolute_delta_) {
strength += hdr->level_;
}
dec->filter_levels_[s] = strength;
}
} else {
dec->filter_levels_[0] = hdr->level_;
}
}
return !br->eof_;
}
// Topmost call
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
const uint8_t* buf;
uint32_t buf_size;
uint32_t vp8_chunk_size;
uint32_t bytes_skipped;
size_t buf_size;
VP8FrameHeader* frm_hdr;
VP8PictureHeader* pic_hdr;
VP8BitReader* br;
@ -264,17 +258,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
"null VP8Io passed to VP8GetHeaders()");
}
buf = io->data;
buf_size = io->data_size;
// Process Pre-VP8 chunks.
status = WebPParseHeaders(&buf, &buf_size, &vp8_chunk_size, &bytes_skipped);
if (status != VP8_STATUS_OK) {
return VP8SetError(dec, status, "Incorrect/incomplete header.");
}
// Process the VP8 frame header.
if (buf_size < 4) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"Truncated header.");
@ -305,7 +290,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"cannot parse picture header");
}
if (buf[0] != 0x9d || buf[1] != 0x01 || buf[2] != 0x2a) {
if (!VP8CheckSignature(buf, buf_size)) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"Bad code word");
}
@ -342,9 +327,6 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
"bad partition length");
}
dec->alpha_data_ = NULL;
dec->alpha_data_size_ = 0;
br = &dec->br_;
VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_);
buf += frm_hdr->partition_length_;
@ -373,38 +355,11 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
// Frame buffer marking
if (!frm_hdr->key_frame_) {
// Paragraph 9.7
#ifndef ONLY_KEYFRAME_CODE
dec->buffer_flags_ = VP8Get(br) << 0; // update golden
dec->buffer_flags_ |= VP8Get(br) << 1; // update alt ref
if (!(dec->buffer_flags_ & 1)) {
dec->buffer_flags_ |= VP8GetValue(br, 2) << 2;
}
if (!(dec->buffer_flags_ & 2)) {
dec->buffer_flags_ |= VP8GetValue(br, 2) << 4;
}
dec->buffer_flags_ |= VP8Get(br) << 6; // sign bias golden
dec->buffer_flags_ |= VP8Get(br) << 7; // sign bias alt ref
#else
return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
"Not a key frame.");
#endif
} else {
dec->buffer_flags_ = 0x003 | 0x100;
}
// Paragraph 9.8
#ifndef ONLY_KEYFRAME_CODE
dec->update_proba_ = VP8Get(br);
if (!dec->update_proba_) { // save for later restore
dec->proba_saved_ = dec->proba_;
}
dec->buffer_flags_ &= 1 << 8;
dec->buffer_flags_ |=
(frm_hdr->key_frame_ || VP8Get(br)) << 8; // refresh last frame
#else
VP8Get(br); // just ignore the value of update_proba_
#endif
VP8Get(br); // ignore the value of update_proba_
VP8ParseProba(br, dec);
@ -418,17 +373,9 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
if (frm_hdr->partition_length_ < kTrailerSize ||
ext_buf[kTrailerSize - 1] != kTrailerMarker) {
Error:
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"RIFF: Inconsistent extra information.");
}
// Alpha
size = (ext_buf[4] << 0) | (ext_buf[5] << 8) | (ext_buf[6] << 16);
if (frm_hdr->partition_length_ < size + kTrailerSize) {
goto Error;
}
dec->alpha_data_ = (size > 0) ? ext_buf - size : NULL;
dec->alpha_data_size_ = size;
// Layer
size = (ext_buf[0] << 0) | (ext_buf[1] << 8) | (ext_buf[2] << 16);
@ -446,7 +393,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
//------------------------------------------------------------------------------
// Residual decoding (Paragraph 13.2 / 13.3)
static const uint8_t kBands[16 + 1] = {
static const int kBands[16 + 1] = {
0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
0 // extra entry as sentinel
};
@ -461,166 +408,163 @@ static const uint8_t kZigzag[16] = {
0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
};
typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting
// Returns the position of the last non-zero coeff plus one
// (and 0 if there's no coeff at all)
static int GetCoeffs(VP8BitReader* const br, ProbaArray prob,
int ctx, const uint16_t dq[2], int n, int16_t* out) {
const uint8_t* p = prob[kBands[n]][ctx];
if (!VP8GetBit(br, p[0])) { // first EOB is more a 'CBP' bit.
return 0;
}
while (1) {
++n;
if (!VP8GetBit(br, p[1])) {
p = prob[kBands[n]][0];
} else { // non zero coeff
int v, j;
if (!VP8GetBit(br, p[2])) {
p = prob[kBands[n]][1];
v = 1;
// See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2
static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
int v;
if (!VP8GetBit(br, p[3])) {
if (!VP8GetBit(br, p[4])) {
v = 2;
} else {
v = 3 + VP8GetBit(br, p[5]);
}
} else {
if (!VP8GetBit(br, p[6])) {
if (!VP8GetBit(br, p[7])) {
v = 5 + VP8GetBit(br, 159);
} else {
if (!VP8GetBit(br, p[3])) {
if (!VP8GetBit(br, p[4])) {
v = 2;
} else {
v = 3 + VP8GetBit(br, p[5]);
}
} else {
if (!VP8GetBit(br, p[6])) {
if (!VP8GetBit(br, p[7])) {
v = 5 + VP8GetBit(br, 159);
} else {
v = 7 + 2 * VP8GetBit(br, 165);
v += VP8GetBit(br, 145);
}
} else {
const uint8_t* tab;
const int bit1 = VP8GetBit(br, p[8]);
const int bit0 = VP8GetBit(br, p[9 + bit1]);
const int cat = 2 * bit1 + bit0;
v = 0;
for (tab = kCat3456[cat]; *tab; ++tab) {
v += v + VP8GetBit(br, *tab);
}
v += 3 + (8 << cat);
}
}
p = prob[kBands[n]][2];
v = 7 + 2 * VP8GetBit(br, 165);
v += VP8GetBit(br, 145);
}
j = kZigzag[n - 1];
out[j] = VP8GetSigned(br, v) * dq[j > 0];
if (n == 16 || !VP8GetBit(br, p[0])) { // EOB
return n;
} else {
const uint8_t* tab;
const int bit1 = VP8GetBit(br, p[8]);
const int bit0 = VP8GetBit(br, p[9 + bit1]);
const int cat = 2 * bit1 + bit0;
v = 0;
for (tab = kCat3456[cat]; *tab; ++tab) {
v += v + VP8GetBit(br, *tab);
}
}
if (n == 16) {
return 16;
v += 3 + (8 << cat);
}
}
return v;
}
// Alias-safe way of converting 4bytes to 32bits.
typedef union {
uint8_t i8[4];
uint32_t i32;
} PackedNz;
// 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) {
// n is either 0 or 1 here. kBands[n] is not necessary for extracting '*p'.
const uint8_t* p = prob[n].probas_[ctx];
for (; n < 16; ++n) {
if (!VP8GetBit(br, p[0])) {
return n; // previous coeff was last non-zero coeff
}
while (!VP8GetBit(br, p[1])) { // sequence of zero coeffs
p = prob[kBands[++n]].probas_[0];
if (n == 16) return 16;
}
{ // non zero coeff
const VP8ProbaArray* const p_ctx = &prob[kBands[n + 1]].probas_[0];
int v;
if (!VP8GetBit(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;
}
// Table to unpack four bits into four bytes
static const PackedNz kUnpackTab[16] = {
{{0, 0, 0, 0}}, {{1, 0, 0, 0}}, {{0, 1, 0, 0}}, {{1, 1, 0, 0}},
{{0, 0, 1, 0}}, {{1, 0, 1, 0}}, {{0, 1, 1, 0}}, {{1, 1, 1, 0}},
{{0, 0, 0, 1}}, {{1, 0, 0, 1}}, {{0, 1, 0, 1}}, {{1, 1, 0, 1}},
{{0, 0, 1, 1}}, {{1, 0, 1, 1}}, {{0, 1, 1, 1}}, {{1, 1, 1, 1}} };
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;
return nz_coeffs;
}
// Macro to pack four LSB of four bytes into four bits.
#if defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
defined(__BIG_ENDIAN__)
#define PACK_CST 0x08040201U
#else
#define PACK_CST 0x01020408U
#endif
#define PACK(X, S) ((((X).i32 * PACK_CST) & 0xff000000) >> (S))
static void ParseResiduals(VP8Decoder* const dec,
VP8MB* const mb, VP8BitReader* const token_br) {
int out_t_nz, out_l_nz, first;
ProbaArray ac_prob;
const VP8QuantMatrix* q = &dec->dqm_[dec->segment_];
int16_t* dst = dec->coeffs_;
static int ParseResiduals(VP8Decoder* const dec,
VP8MB* const mb, VP8BitReader* const token_br) {
VP8BandProbas (* const bands)[NUM_BANDS] = dec->proba_.bands_;
const VP8BandProbas* ac_proba;
const VP8QuantMatrix* const q = &dec->dqm_[dec->segment_];
VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
int16_t* dst = block->coeffs_;
VP8MB* const left_mb = dec->mb_info_ - 1;
PackedNz nz_ac, nz_dc;
PackedNz tnz, lnz;
uint32_t non_zero_ac = 0;
uint32_t non_zero_dc = 0;
uint8_t tnz, lnz;
uint32_t non_zero_y = 0;
uint32_t non_zero_uv = 0;
int x, y, ch;
uint32_t out_t_nz, out_l_nz;
int first;
memset(dst, 0, 384 * sizeof(*dst));
if (!dec->is_i4x4_) { // parse DC
if (!block->is_i4x4_) { // parse DC
int16_t dc[16] = { 0 };
const int ctx = mb->dc_nz_ + left_mb->dc_nz_;
mb->dc_nz_ = left_mb->dc_nz_ =
(GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[1],
ctx, q->y2_mat_, 0, dc) > 0);
const int ctx = mb->nz_dc_ + left_mb->nz_dc_;
const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat_, 0, dc);
mb->nz_dc_ = left_mb->nz_dc_ = (nz > 0);
if (nz > 1) { // more than just the DC -> perform the full transform
VP8TransformWHT(dc, dst);
} else { // only DC is non-zero -> inlined simplified transform
int i;
const int dc0 = (dc[0] + 3) >> 3;
for (i = 0; i < 16 * 16; i += 16) dst[i] = dc0;
}
first = 1;
ac_prob = (ProbaArray)dec->proba_.coeffs_[0];
VP8TransformWHT(dc, dst);
ac_proba = bands[0];
} else {
first = 0;
ac_prob = (ProbaArray)dec->proba_.coeffs_[3];
ac_proba = bands[3];
}
tnz = kUnpackTab[mb->nz_ & 0xf];
lnz = kUnpackTab[left_mb->nz_ & 0xf];
tnz = mb->nz_ & 0x0f;
lnz = left_mb->nz_ & 0x0f;
for (y = 0; y < 4; ++y) {
int l = lnz.i8[y];
int l = lnz & 1;
uint32_t nz_coeffs = 0;
for (x = 0; x < 4; ++x) {
const int ctx = l + tnz.i8[x];
const int nz = GetCoeffs(token_br, ac_prob, ctx,
q->y1_mat_, first, dst);
tnz.i8[x] = l = (nz > 0);
nz_dc.i8[x] = (dst[0] != 0);
nz_ac.i8[x] = (nz > 1);
const int ctx = l + (tnz & 1);
const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat_, first, dst);
l = (nz > first);
tnz = (tnz >> 1) | (l << 7);
nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0);
dst += 16;
}
lnz.i8[y] = l;
non_zero_dc |= PACK(nz_dc, 24 - y * 4);
non_zero_ac |= PACK(nz_ac, 24 - y * 4);
tnz >>= 4;
lnz = (lnz >> 1) | (l << 7);
non_zero_y = (non_zero_y << 8) | nz_coeffs;
}
out_t_nz = PACK(tnz, 24);
out_l_nz = PACK(lnz, 24);
out_t_nz = tnz;
out_l_nz = lnz >> 4;
tnz = kUnpackTab[mb->nz_ >> 4];
lnz = kUnpackTab[left_mb->nz_ >> 4];
for (ch = 0; ch < 4; ch += 2) {
uint32_t nz_coeffs = 0;
tnz = mb->nz_ >> (4 + ch);
lnz = left_mb->nz_ >> (4 + ch);
for (y = 0; y < 2; ++y) {
int l = lnz.i8[ch + y];
int l = lnz & 1;
for (x = 0; x < 2; ++x) {
const int ctx = l + tnz.i8[ch + x];
const int nz =
GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[2],
ctx, q->uv_mat_, 0, dst);
tnz.i8[ch + x] = l = (nz > 0);
nz_dc.i8[y * 2 + x] = (dst[0] != 0);
nz_ac.i8[y * 2 + x] = (nz > 1);
const int ctx = l + (tnz & 1);
const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat_, 0, dst);
l = (nz > 0);
tnz = (tnz >> 1) | (l << 3);
nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0);
dst += 16;
}
lnz.i8[ch + y] = l;
tnz >>= 2;
lnz = (lnz >> 1) | (l << 5);
}
non_zero_dc |= PACK(nz_dc, 8 - ch * 2);
non_zero_ac |= PACK(nz_ac, 8 - ch * 2);
// Note: we don't really need the per-4x4 details for U/V blocks.
non_zero_uv |= nz_coeffs << (4 * ch);
out_t_nz |= (tnz << 4) << ch;
out_l_nz |= (lnz & 0xf0) << ch;
}
out_t_nz |= PACK(tnz, 20);
out_l_nz |= PACK(lnz, 20);
mb->nz_ = out_t_nz;
left_mb->nz_ = out_l_nz;
dec->non_zero_ac_ = non_zero_ac;
dec->non_zero_ = non_zero_ac | non_zero_dc;
mb->skip_ = !dec->non_zero_;
block->non_zero_y_ = non_zero_y;
block->non_zero_uv_ = non_zero_uv;
// We look at the mode-code of each block and check if some blocks have less
// than three non-zero coeffs (code < 2). This is to avoid dithering flat and
// empty blocks.
block->dither_ = (non_zero_uv & 0xaaaa) ? 0 : q->dither_;
return !(non_zero_y | non_zero_uv); // will be used for further optimization
}
#undef PACK
//------------------------------------------------------------------------------
// Main loop
@ -628,7 +572,9 @@ static void ParseResiduals(VP8Decoder* const dec,
int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
VP8BitReader* const br = &dec->br_;
VP8MB* const left = dec->mb_info_ - 1;
VP8MB* const info = dec->mb_info_ + dec->mb_x_;
VP8MB* const mb = dec->mb_info_ + dec->mb_x_;
VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
int skip;
// Note: we don't save segment map (yet), as we don't expect
// to decode more than 1 keyframe.
@ -638,67 +584,64 @@ int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
VP8GetBit(br, dec->proba_.segments_[1]) :
2 + VP8GetBit(br, dec->proba_.segments_[2]);
}
info->skip_ = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0;
skip = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0;
VP8ParseIntraMode(br, dec);
if (br->eof_) {
return 0;
}
if (!info->skip_) {
ParseResiduals(dec, info, token_br);
if (!skip) {
skip = ParseResiduals(dec, mb, token_br);
} else {
left->nz_ = info->nz_ = 0;
if (!dec->is_i4x4_) {
left->dc_nz_ = info->dc_nz_ = 0;
left->nz_ = mb->nz_ = 0;
if (!block->is_i4x4_) {
left->nz_dc_ = mb->nz_dc_ = 0;
}
dec->non_zero_ = 0;
dec->non_zero_ac_ = 0;
block->non_zero_y_ = 0;
block->non_zero_uv_ = 0;
}
return (!token_br->eof_);
if (dec->filter_type_ > 0) { // store filter info
VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_;
*finfo = dec->fstrengths_[dec->segment_][block->is_i4x4_];
finfo->f_inner_ |= !skip;
}
return !token_br->eof_;
}
void VP8InitScanline(VP8Decoder* const dec) {
VP8MB* const left = dec->mb_info_ - 1;
left->nz_ = 0;
left->dc_nz_ = 0;
left->nz_dc_ = 0;
memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
dec->filter_row_ =
(dec->filter_type_ > 0) &&
(dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_);
dec->mb_x_ = 0;
}
static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) {
// Parse bitstream for this row.
VP8BitReader* const token_br =
&dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
VP8InitScanline(dec);
for (dec->mb_x_ = 0; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
if (!VP8DecodeMB(dec, token_br)) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"Premature end-of-file encountered.");
}
VP8ReconstructBlock(dec);
// Store data and save block's filtering params
VP8StoreBlock(dec);
}
VP8InitScanline(dec); // Prepare for next scanline
// Reconstruct, filter and emit the row.
if (!VP8ProcessRow(dec, io)) {
return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted.");
}
}
if (dec->use_threads_ && !WebPWorkerSync(&dec->worker_)) {
return 0;
if (dec->mt_method_ > 0) {
if (!WebPWorkerSync(&dec->worker_)) return 0;
}
// Finish
#ifndef ONLY_KEYFRAME_CODE
if (!dec->update_proba_) {
dec->proba_ = dec->proba_saved_;
}
#endif
#ifdef WEBP_EXPERIMENTAL_FEATURES
if (dec->layer_data_size_ > 0) {
if (!VP8DecodeLayer(dec)) {
@ -747,19 +690,19 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
}
dec->ready_ = 0;
return 1;
return ok;
}
void VP8Clear(VP8Decoder* const dec) {
if (dec == NULL) {
return;
}
if (dec->use_threads_) {
if (dec->mt_method_ > 0) {
WebPWorkerEnd(&dec->worker_);
}
if (dec->mem_) {
free(dec->mem_);
}
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
free(dec->mem_);
dec->mem_ = NULL;
dec->mem_size_ = 0;
memset(&dec->br_, 0, sizeof(dec->br_));
@ -768,6 +711,3 @@ void VP8Clear(VP8Decoder* const dec) {
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// VP8 decoder: internal header.
@ -13,11 +15,13 @@
#define WEBP_DEC_VP8I_H_
#include <string.h> // for memcpy()
#include "./vp8li.h"
#include "../utils/bit_reader.h"
#include "../utils/random.h"
#include "../utils/thread.h"
#include "../dsp/dsp.h"
#if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
extern "C" {
#endif
@ -26,10 +30,8 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 0
#define DEC_MIN_VERSION 1
#define DEC_REV_VERSION 3
#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames
#define DEC_MIN_VERSION 4
#define DEC_REV_VERSION 0
// intra prediction modes
enum { B_DC_PRED = 0, // 4x4 modes
@ -97,6 +99,9 @@ enum { MB_FEATURE_TREE_PROBS = 3,
#define U_OFF (Y_OFF + BPS * 16 + BPS)
#define V_OFF (U_OFF + 16)
// minimal width under which lossy multi-threading is always disabled
#define MIN_WIDTH_FOR_THREADS 512
//------------------------------------------------------------------------------
// Headers
@ -125,15 +130,19 @@ typedef struct {
int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments
} VP8SegmentHeader;
// probas associated to one of the contexts
typedef uint8_t VP8ProbaArray[NUM_PROBAS];
typedef struct { // all the probas associated to one band
VP8ProbaArray probas_[NUM_CTX];
} VP8BandProbas;
// Struct collecting all frame-persistent probabilities.
typedef struct {
uint8_t segments_[MB_FEATURE_TREE_PROBS];
// Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4
uint8_t coeffs_[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS];
#ifndef ONLY_KEYFRAME_CODE
uint8_t ymode_[4], uvmode_[3];
uint8_t mv_[2][NUM_MV_PROBAS];
#endif
VP8BandProbas bands_[NUM_TYPES][NUM_BANDS];
} VP8Proba;
// Filter parameters
@ -150,31 +159,59 @@ typedef struct {
// Informations about the macroblocks.
typedef struct { // filter specs
unsigned int f_level_:6; // filter strength: 0..63
unsigned int f_ilevel_:6; // inner limit: 1..63
unsigned int f_inner_:1; // do inner filtering?
uint8_t f_limit_; // filter limit in [3..189], or 0 if no filtering
uint8_t f_ilevel_; // inner limit in [1..63]
uint8_t f_inner_; // do inner filtering?
uint8_t hev_thresh_; // high edge variance threshold in [0..2]
} VP8FInfo;
typedef struct { // used for syntax-parsing
unsigned int nz_; // non-zero AC/DC coeffs
unsigned int dc_nz_:1; // non-zero DC coeffs
unsigned int skip_:1; // block type
typedef struct { // Top/Left Contexts used for syntax-parsing
uint8_t nz_; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma)
uint8_t nz_dc_; // non-zero DC coeff (1bit)
} VP8MB;
// Dequantization matrices
typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower).
typedef struct {
uint16_t y1_mat_[2], y2_mat_[2], uv_mat_[2]; // [DC / AC]
quant_t y1_mat_, y2_mat_, uv_mat_;
int uv_quant_; // U/V quantizer value
int dither_; // dithering amplitude (0 = off, max=255)
} VP8QuantMatrix;
// Data needed to reconstruct a macroblock
typedef struct {
int16_t coeffs_[384]; // 384 coeffs = (16+4+4) * 4*4
uint8_t is_i4x4_; // true if intra4x4
uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
uint8_t uvmode_; // chroma prediction mode
// bit-wise info about the content of each sub-4x4 blocks (in decoding order).
// Each of the 4x4 blocks for y/u/v is associated with a 2b code according to:
// code=0 -> no coefficient
// code=1 -> only DC
// code=2 -> first three coefficients are non-zero
// code=3 -> more than three coefficients are non-zero
// This allows to call specialized transform functions.
uint32_t non_zero_y_;
uint32_t non_zero_uv_;
uint8_t dither_; // local dithering strength (deduced from non_zero_*)
} VP8MBData;
// Persistent information needed by the parallel processing
typedef struct {
int id_; // cache row to process (in [0..2])
int mb_y_; // macroblock position of the row
int filter_row_; // true if row-filtering is needed
VP8FInfo* f_info_; // filter strengths
VP8Io io_; // copy of the VP8Io to pass to put()
int id_; // cache row to process (in [0..2])
int mb_y_; // macroblock position of the row
int filter_row_; // true if row-filtering is needed
VP8FInfo* f_info_; // filter strengths (swapped with dec->f_info_)
VP8MBData* mb_data_; // reconstruction data (swapped with dec->mb_data_)
VP8Io io_; // copy of the VP8Io to pass to put()
} VP8ThreadContext;
// Saved top samples, per macroblock. Fits into a cache-line.
typedef struct {
uint8_t y[16], u[8], v[8];
} VP8TopSamples;
//------------------------------------------------------------------------------
// VP8Decoder: the main opaque structure handed over to user
@ -194,7 +231,8 @@ struct VP8Decoder {
// Worker
WebPWorker worker_;
int use_threads_; // use multi-thread
int mt_method_; // multi-thread method: 0=off, 1=[parse+recon][filter]
// 2=[parse][recon+filter]
int cache_id_; // current cache row
int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3)
VP8ThreadContext thread_ctx_; // Thread context
@ -211,12 +249,9 @@ struct VP8Decoder {
// per-partition boolean decoders.
VP8BitReader parts_[MAX_NUM_PARTITIONS];
// buffer refresh flags
// bit 0: refresh Gold, bit 1: refresh Alt
// bit 2-3: copy to Gold, bit 4-5: copy to Alt
// bit 6: Gold sign bias, bit 7: Alt sign bias
// bit 8: refresh last frame
uint32_t buffer_flags_;
// Dithering strength, deduced from decoding options
int dither_; // whether to use dithering or not
VP8Random dithering_rg_; // random generator for dithering
// dequantization (one set of DC/AC dequant factor per segment)
VP8QuantMatrix dqm_[NUM_MB_SEGMENTS];
@ -225,24 +260,19 @@ struct VP8Decoder {
VP8Proba proba_;
int use_skip_proba_;
uint8_t skip_p_;
#ifndef ONLY_KEYFRAME_CODE
uint8_t intra_p_, last_p_, golden_p_;
VP8Proba proba_saved_;
int update_proba_;
#endif
// Boundary data cache and persistent buffers.
uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
uint8_t intra_l_[4]; // left intra modes values
uint8_t* y_t_; // top luma samples: 16 * mb_w_
uint8_t* u_t_, *v_t_; // top u/v samples: 8 * mb_w_ each
uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
uint8_t intra_l_[4]; // left intra modes values
VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1)
VP8FInfo* f_info_; // filter strength info
uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE)
int16_t* coeffs_; // 384 coeffs = (16+8+8) * 4*4
uint8_t segment_; // segment of the currently parsed block
VP8TopSamples* yuv_t_; // top y/u/v samples
uint8_t* cache_y_; // macroblock row for storing unfiltered samples
VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1)
VP8FInfo* f_info_; // filter strength info
uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE)
uint8_t* cache_y_; // macroblock row for storing unfiltered samples
uint8_t* cache_u_;
uint8_t* cache_v_;
int cache_y_stride_;
@ -250,32 +280,24 @@ struct VP8Decoder {
// main memory chunk for the above data. Persistent.
void* mem_;
int mem_size_;
size_t mem_size_;
// Per macroblock non-persistent infos.
int mb_x_, mb_y_; // current position, in macroblock units
uint8_t is_i4x4_; // true if intra4x4
uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
uint8_t uvmode_; // chroma prediction mode
uint8_t segment_; // block's segment
// bit-wise info about the content of each sub-4x4 blocks: there are 16 bits
// for luma (bits #0->#15), then 4 bits for chroma-u (#16->#19) and 4 bits for
// chroma-v (#20->#23), each corresponding to one 4x4 block in decoding order.
// If the bit is set, the 4x4 block contains some non-zero coefficients.
uint32_t non_zero_;
uint32_t non_zero_ac_;
VP8MBData* mb_data_; // parsed reconstruction data
// Filtering side-info
int filter_type_; // 0=off, 1=simple, 2=complex
int filter_row_; // per-row flag
uint8_t filter_levels_[NUM_MB_SEGMENTS]; // precalculated per-segment
int filter_type_; // 0=off, 1=simple, 2=complex
VP8FInfo fstrengths_[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type
// Alpha
struct ALPHDecoder* alph_dec_; // alpha-plane decoder object
const uint8_t* alpha_data_; // compressed alpha data (if present)
size_t alpha_data_size_;
int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_
uint8_t* alpha_plane_; // output. Persistent, contains the whole data.
// extensions
const uint8_t* alpha_data_; // compressed alpha data (if present)
size_t alpha_data_size_;
uint8_t* alpha_plane_; // output
int layer_colorspace_;
const uint8_t* layer_data_; // compressed layer data (if present)
size_t layer_data_size_;
@ -286,15 +308,7 @@ struct VP8Decoder {
// in vp8.c
int VP8SetError(VP8Decoder* const dec,
VP8StatusCode error, const char * const msg);
// Validates the VP8 data-header and retrieve basic header information viz width
// and height. Returns 0 in case of formatting error. *width/*height/*has_alpha
// can be passed NULL.
int VP8GetInfo(const uint8_t* data,
uint32_t data_size, // data available so far
uint32_t chunk_size, // total data size expect in the chunk
int *width, int *height, int *has_alpha);
VP8StatusCode error, const char* const msg);
// in tree.c
void VP8ResetProba(VP8Proba* const proba);
@ -306,8 +320,6 @@ void VP8ParseQuant(VP8Decoder* const dec);
// in frame.c
int VP8InitFrame(VP8Decoder* const dec, VP8Io* io);
// Predict a block and add residual
void VP8ReconstructBlock(VP8Decoder* const dec);
// Call io->setup() and finish setting up scan parameters.
// After this call returns, one must always call VP8ExitCritical() with the
// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK
@ -316,14 +328,16 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
// Must always be called in pair with VP8EnterCritical().
// Returns false in case of error.
int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
// Filter the decoded macroblock row (if needed)
int VP8FinishRow(VP8Decoder* const dec, VP8Io* io); // multi threaded call
// Process the last decoded row (filtering + output)
// Return the multi-threading method to use (0=off), depending
// on options and bitstream size. Only for lossy decoding.
int VP8GetThreadMethod(const WebPDecoderOptions* const options,
const WebPHeaderStructure* const headers,
int width, int height);
// Initialize dithering post-process if needed.
void VP8InitDithering(const WebPDecoderOptions* const options,
VP8Decoder* const dec);
// Process the last decoded row (filtering + output).
int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
// Store a block, along with filtering params
void VP8StoreBlock(VP8Decoder* const dec);
// Finalize and transmit a complete row. Return false in case of user-abort.
int VP8FinishRow(VP8Decoder* const dec, VP8Io* const io);
// To be called at the start of a new scanline, to initialize predictors.
void VP8InitScanline(VP8Decoder* const dec);
// Decode one macroblock. Returns false if there is not enough data.
@ -338,7 +352,7 @@ int VP8DecodeLayer(VP8Decoder* const dec);
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
} // extern "C"
#endif

1380
src/dec/vp8l.c Normal file

File diff suppressed because it is too large Load Diff

137
src/dec/vp8li.h Normal file
View File

@ -0,0 +1,137 @@
// 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.
// -----------------------------------------------------------------------------
//
// Lossless decoder: internal header.
//
// Author: Skal (pascal.massimino@gmail.com)
// Vikas Arora(vikaas.arora@gmail.com)
#ifndef WEBP_DEC_VP8LI_H_
#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 "../webp/format_constants.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
READ_DATA = 0,
READ_HDR = 1,
READ_DIM = 2
} VP8LDecodeState;
typedef struct VP8LTransform VP8LTransform;
struct VP8LTransform {
VP8LImageTransformType type_; // transform type.
int bits_; // subsampling bits defining transform window.
int xsize_; // transform window X index.
int ysize_; // transform window Y index.
uint32_t *data_; // transform data.
};
typedef struct {
HuffmanTree htrees_[HUFFMAN_CODES_PER_META_CODE];
} HTreeGroup;
typedef struct {
int color_cache_size_;
VP8LColorCache color_cache_;
int huffman_mask_;
int huffman_subsample_bits_;
int huffman_xsize_;
uint32_t *huffman_image_;
int num_htree_groups_;
HTreeGroup *htree_groups_;
} VP8LMetadata;
typedef struct VP8LDecoder VP8LDecoder;
struct VP8LDecoder {
VP8StatusCode status_;
VP8LDecodeState action_;
VP8LDecodeState state_;
VP8Io *io_;
const WebPDecBuffer *output_; // shortcut to io->opaque->output
uint32_t *pixels_; // Internal data: either uint8_t* for alpha
// or uint32_t* for BGRA.
uint32_t *argb_cache_; // Scratch buffer for temporary BGRA storage.
VP8LBitReader br_;
int width_;
int height_;
int last_row_; // last input row decoded so far.
int last_pixel_; // last pixel decoded so far. However, it may
// not be transformed, scaled and
// color-converted yet.
int last_out_row_; // last row output so far.
VP8LMetadata hdr_;
int next_transform_;
VP8LTransform transforms_[NUM_TRANSFORMS];
// or'd bitset storing the transforms types.
uint32_t transforms_seen_;
uint8_t *rescaler_memory; // Working memory for rescaling work.
WebPRescaler *rescaler; // Common rescaler for all channels.
};
//------------------------------------------------------------------------------
// internal functions. Not public.
struct ALPHDecoder; // Defined in dec/alphai.h.
// in vp8l.c
// Decodes image header for alpha data stored using lossless compression.
// Returns false in case of error.
int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
const uint8_t* const data, size_t data_size,
uint8_t* const output);
// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
// already decoded in previous call(s), it will resume decoding from where it
// was paused.
// Returns false in case of bitstream error.
int VP8LDecodeAlphaImageStream(struct ALPHDecoder* const alph_dec,
int last_row);
// Allocates and initialize a new lossless decoder instance.
VP8LDecoder* VP8LNew(void);
// Decodes the image header. Returns false in case of error.
int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
// Decodes an image. It's required to decode the lossless header before calling
// this function. Returns false in case of error, with updated dec->status_.
int VP8LDecodeImage(VP8LDecoder* const dec);
// Resets the decoder in its initial state, reclaiming memory.
// Preserves the dec->status_ value.
void VP8LClear(VP8LDecoder* const dec);
// Clears and deallocate a lossless decoder instance.
void VP8LDelete(VP8LDecoder* const dec);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* WEBP_DEC_VP8LI_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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: WebP decoding parameters and custom IO on buffer
@ -12,33 +14,19 @@
#ifndef WEBP_DEC_WEBPI_H_
#define WEBP_DEC_WEBPI_H_
#if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
extern "C" {
#endif
#include "../webp/decode_vp8.h"
#include "../utils/rescaler.h"
#include "./decode_vp8.h"
//------------------------------------------------------------------------------
// WebPDecParams: Decoding output parameters. Transient internal object.
typedef struct WebPDecParams WebPDecParams;
typedef int (*OutputFunc)(const VP8Io* const io, WebPDecParams* const p);
// Structure use for on-the-fly rescaling
typedef struct {
int x_expand; // true if we're expanding in the x direction
int fy_scale, fx_scale; // fixed-point scaling factor
int64_t fxy_scale; // ''
// we need hpel-precise add/sub increments, for the downsampled U/V planes.
int y_accum; // vertical accumulator
int y_add, y_sub; // vertical increments (add ~= src, sub ~= dst)
int x_add, x_sub; // horizontal increments (add ~= src, sub ~= dst)
int src_width, src_height; // source dimensions
int dst_width, dst_height; // destination dimensions
uint8_t* dst;
int dst_stride;
int32_t* irow, *frow; // work buffer
} WebPRescaler;
typedef int (*OutputRowFunc)(WebPDecParams* const p, int y_pos);
struct WebPDecParams {
WebPDecBuffer* output; // output buffer.
@ -49,9 +37,11 @@ struct WebPDecParams {
const WebPDecoderOptions* options; // if not NULL, use alt decoding features
// rescalers
WebPRescaler scaler_y, scaler_u, scaler_v, scaler_a;
void* memory; // overall scratch memory for the output work.
OutputFunc emit; // output RGB or YUV samples
OutputFunc emit_alpha; // output alpha channel
void* memory; // overall scratch memory for the output work.
OutputFunc emit; // output RGB or YUV samples
OutputFunc emit_alpha; // output alpha channel
OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values
};
// Should be called first, before any use of the WebPDecParams object.
@ -60,69 +50,25 @@ void WebPResetDecParams(WebPDecParams* const params);
//------------------------------------------------------------------------------
// Header parsing helpers
#define TAG_SIZE 4
#define CHUNK_HEADER_SIZE 8
#define RIFF_HEADER_SIZE 12
#define FRAME_CHUNK_SIZE 20
#define LOOP_CHUNK_SIZE 4
#define TILE_CHUNK_SIZE 8
#define VP8X_CHUNK_SIZE 12
#define VP8_FRAME_HEADER_SIZE 10 // Size of the frame header within VP8 data.
// Structure storing a description of the RIFF headers.
typedef struct {
const uint8_t* data; // input buffer
size_t data_size; // input buffer size
size_t offset; // offset to main data chunk (VP8 or VP8L)
const uint8_t* alpha_data; // points to alpha chunk (if present)
size_t alpha_data_size; // alpha chunk size
size_t compressed_size; // VP8/VP8L compressed data size
size_t riff_size; // size of the riff payload (or 0 if absent)
int is_lossless; // true if a VP8L chunk is present
} WebPHeaderStructure;
// Validates the RIFF container (if detected) and skips over it.
// If a RIFF container is detected,
// Returns VP8_STATUS_BITSTREAM_ERROR for invalid header, and
// VP8_STATUS_OK otherwise.
// In case there are not enough bytes (partial RIFF container), return 0 for
// riff_size. Else return the riff_size extracted from the header.
VP8StatusCode WebPParseRIFF(const uint8_t** data, uint32_t* data_size,
uint32_t* riff_size);
// Validates the VP8X Header and skips over it.
// Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header,
// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
// VP8_STATUS_OK otherwise.
// If a VP8 chunk is found, bytes_skipped is set to the total number of bytes
// that are skipped; also Width, Height & Flags are set to the corresponding
// fields extracted from the VP8X chunk.
VP8StatusCode WebPParseVP8X(const uint8_t** data, uint32_t* data_size,
uint32_t* bytes_skipped,
int* width, int* height, uint32_t* flags);
// Skips to the next VP8 chunk header in the data given the size of the RIFF
// chunk 'riff_size'.
// Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered,
// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
// VP8_STATUS_OK otherwise.
// If a VP8 chunk is found, bytes_skipped is set to the total number of bytes
// that are skipped.
VP8StatusCode WebPParseOptionalChunks(const uint8_t** data, uint32_t* data_size,
uint32_t riff_size,
uint32_t* bytes_skipped);
// Validates the VP8 Header ("VP8 nnnn") and skips over it.
// Returns VP8_STATUS_BITSTREAM_ERROR for invalid (vp8_chunk_size greater than
// riff_size) VP8 header,
// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
// VP8_STATUS_OK otherwise.
// If a VP8 chunk is found, bytes_skipped is set to the total number of bytes
// that are skipped and vp8_chunk_size is set to the corresponding size
// extracted from the VP8 chunk header.
// For a partial VP8 chunk, vp8_chunk_size is set to 0.
VP8StatusCode WebPParseVP8Header(const uint8_t** data, uint32_t* data_size,
uint32_t riff_size, uint32_t* bytes_skipped,
uint32_t* vp8_chunk_size);
// Skips over all valid chunks prior to the first VP8 frame header.
// Returns VP8_STATUS_OK on success,
// VP8_STATUS_BITSTREAM_ERROR if an invalid header/chunk is found, and
// VP8_STATUS_NOT_ENOUGH_DATA if case of insufficient data.
// Also, data, data_size, vp8_size & bytes_skipped are updated appropriately
// on success, where
// vp8_size is the size of VP8 chunk data (extracted from VP8 chunk header) and
// bytes_skipped is set to the total number of bytes that are skipped.
VP8StatusCode WebPParseHeaders(const uint8_t** data, uint32_t* data_size,
uint32_t* vp8_size, uint32_t* bytes_skipped);
// Skips over all valid chunks prior to the first VP8/VP8L frame header.
// Returns: VP8_STATUS_OK, VP8_STATUS_BITSTREAM_ERROR (invalid header/chunk),
// VP8_STATUS_NOT_ENOUGH_DATA (partial input) or VP8_STATUS_UNSUPPORTED_FEATURE
// in the case of non-decodable features (animation for instance).
// In 'headers', compressed_size, offset, alpha_data, alpha_size, and lossless
// fields are updated appropriately upon success.
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
//------------------------------------------------------------------------------
// Misc utils
@ -131,6 +77,11 @@ VP8StatusCode WebPParseHeaders(const uint8_t** data, uint32_t* data_size,
// hooks will use the supplied 'params' as io->opaque handle.
void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers
// to the *compressed* format, not the output one.
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
VP8Io* const io, WEBP_CSP_MODE src_colorspace);
//------------------------------------------------------------------------------
// Internal functions regarding WebPDecBuffer memory (in buffer.c).
// Don't really need to be externally visible for now.
@ -154,9 +105,11 @@ void WebPCopyDecBuffer(const WebPDecBuffer* const src,
// Copy and transfer ownership from src to dst (beware of parameter order!)
void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst);
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
} // extern "C"
#endif

15
src/demux/Makefile.am Normal file
View File

@ -0,0 +1,15 @@
AM_CPPFLAGS = -I$(top_srcdir)/src
lib_LTLIBRARIES = libwebpdemux.la
libwebpdemux_la_SOURCES =
libwebpdemux_la_SOURCES += demux.c
libwebpdemuxinclude_HEADERS =
libwebpdemuxinclude_HEADERS += ../webp/demux.h
libwebpdemuxinclude_HEADERS += ../webp/mux_types.h
libwebpdemuxinclude_HEADERS += ../webp/types.h
libwebpdemux_la_LIBADD = ../libwebp.la
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 1:0:0
libwebpdemuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpdemux.pc

1002
src/demux/demux.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libwebpdemux
Description: Library for parsing the WebP graphics format container
Version: @PACKAGE_VERSION@
Requires: libwebp >= 0.2.0
Cflags: -I${includedir}
Libs: -L${libdir} -lwebpdemux

View File

@ -1,14 +1,44 @@
AM_CPPFLAGS = -I$(top_srcdir)/src
libwebpdsp_la_SOURCES = dsp.h cpu.c \
enc.c enc_sse2.c \
dec.c dec_sse2.c dec_neon.c \
upsampling.c upsampling_sse2.c \
yuv.h yuv.c
libwebpdsp_la_LDFLAGS = -version-info 0:0:0 -lm
libwebpdsp_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE)
libwebpdspinclude_HEADERS = ../webp/types.h
libwebpdspincludedir = $(includedir)/webp
noinst_HEADERS = dsp.h yuv.h
noinst_LTLIBRARIES = libwebpdsp.la
if BUILD_LIBWEBPDECODER
noinst_LTLIBRARIES += libwebpdspdecode.la
endif
common_HEADERS = ../webp/types.h
commondir = $(includedir)/webp
COMMON_SOURCES =
COMMON_SOURCES += cpu.c
COMMON_SOURCES += dec.c
COMMON_SOURCES += dec_neon.c
COMMON_SOURCES += dec_sse2.c
COMMON_SOURCES += dsp.h
COMMON_SOURCES += lossless.c
COMMON_SOURCES += lossless.h
COMMON_SOURCES += upsampling.c
COMMON_SOURCES += upsampling_neon.c
COMMON_SOURCES += upsampling_sse2.c
COMMON_SOURCES += yuv.c
COMMON_SOURCES += yuv.h
ENC_SOURCES =
ENC_SOURCES += enc.c
ENC_SOURCES += enc_neon.c
ENC_SOURCES += enc_sse2.c
libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES)
noinst_HEADERS =
noinst_HEADERS += ../dec/decode_vp8.h
noinst_HEADERS += ../webp/decode.h
libwebpdsp_la_LDFLAGS = -lm
libwebpdsp_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE) $(USE_SWAP_16BIT_CSP)
if BUILD_LIBWEBPDECODER
libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES)
libwebpdspdecode_la_LDFLAGS = $(libwebpdsp_la_LDFLAGS)
libwebpdspdecode_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
endif

View File

@ -1,28 +1,29 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// CPU detection
//
// Author: Christian Duvivier (cduvivier@google.com)
#include <stddef.h> // for NULL
#include "./dsp.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#if defined(__ANDROID__)
#include <cpu-features.h>
#endif
//------------------------------------------------------------------------------
// SSE2 detection.
//
#if defined(__pic__) && defined(__i386__)
static inline void GetCPUInfo(int cpu_info[4], int info_type) {
// apple/darwin gcc-4.0.1 defines __PIC__, but not __pic__ with -fPIC.
#if (defined(__pic__) || defined(__PIC__)) && defined(__i386__)
static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
"mov %%ebx, %%edi\n"
"cpuid\n"
@ -31,17 +32,17 @@ static inline void GetCPUInfo(int cpu_info[4], int info_type) {
: "a"(info_type));
}
#elif defined(__i386__) || defined(__x86_64__)
static inline void GetCPUInfo(int cpu_info[4], int info_type) {
static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
"cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type));
}
#elif defined(_MSC_VER) // Visual C++
#elif defined(WEBP_MSC_SSE2)
#define GetCPUInfo __cpuid
#endif
#if defined(__i386__) || defined(__x86_64__) || defined(_MSC_VER)
#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2)
static int x86CPUInfo(CPUFeature feature) {
int cpu_info[4];
GetCPUInfo(cpu_info, 1);
@ -54,10 +55,22 @@ static int x86CPUInfo(CPUFeature feature) {
return 0;
}
VP8CPUInfo VP8GetCPUInfo = x86CPUInfo;
#elif defined(WEBP_ANDROID_NEON)
static int AndroidCPUInfo(CPUFeature feature) {
const AndroidCpuFamily cpu_family = android_getCpuFamily();
const uint64_t cpu_features = android_getCpuFeatures();
if (feature == kNEON) {
return (cpu_family == ANDROID_CPU_FAMILY_ARM &&
0 != (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON));
}
return 0;
}
VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
#elif defined(__ARM_NEON__)
// define a dummy function to enable turning off NEON at runtime by setting
// VP8DecGetCPUInfo = NULL
static int armCPUInfo(CPUFeature feature) {
(void)feature;
return 1;
}
VP8CPUInfo VP8GetCPUInfo = armCPUInfo;
@ -65,6 +78,3 @@ VP8CPUInfo VP8GetCPUInfo = armCPUInfo;
VP8CPUInfo VP8GetCPUInfo = NULL;
#endif
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Speed-critical decoding functions.
@ -12,10 +14,6 @@
#include "./dsp.h"
#include "../dec/vp8i.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// run-time tables (~4k)
@ -49,7 +47,7 @@ static void DspInitTables(void) {
}
}
static inline uint8_t clip_8b(int v) {
static WEBP_INLINE uint8_t clip_8b(int v) {
return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
}
@ -59,6 +57,14 @@ static inline uint8_t clip_8b(int v) {
#define STORE(x, y, v) \
dst[x + y * BPS] = clip_8b(dst[x + y * BPS] + ((v) >> 3))
#define STORE2(y, dc, d, c) do { \
const int DC = (dc); \
STORE(0, y, DC + (d)); \
STORE(1, y, DC + (c)); \
STORE(2, y, DC - (c)); \
STORE(3, y, DC - (d)); \
} while (0)
static const int kC1 = 20091 + (1 << 16);
static const int kC2 = 35468;
#define MUL(a, b) (((a) * (b)) >> 16)
@ -101,7 +107,21 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
dst += BPS;
}
}
// Simplified transform when only in[0], in[1] and in[4] are non-zero
static void TransformAC3(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4;
const int c4 = MUL(in[4], kC2);
const int d4 = MUL(in[4], kC1);
const int c1 = MUL(in[1], kC2);
const int d1 = MUL(in[1], kC1);
STORE2(0, a + d4, d1, c1);
STORE2(1, a + c4, d1, c1);
STORE2(2, a - c4, d1, c1);
STORE2(3, a - d4, d1, c1);
}
#undef MUL
#undef STORE2
static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
TransformOne(in, dst);
@ -171,7 +191,7 @@ void (*VP8TransformWHT)(const int16_t* in, int16_t* out) = TransformWHT;
#define DST(x, y) dst[(x) + (y) * BPS]
static inline void TrueMotion(uint8_t *dst, int size) {
static WEBP_INLINE void TrueMotion(uint8_t *dst, int size) {
const uint8_t* top = dst - BPS;
const uint8_t* const clip0 = clip1 + 255 - top[-1];
int y;
@ -206,7 +226,7 @@ static void HE16(uint8_t *dst) { // horizontal
}
}
static inline void Put16(int v, uint8_t* dst) {
static WEBP_INLINE void Put16(int v, uint8_t* dst) {
int j;
for (j = 0; j < 16; ++j) {
memset(dst + j * BPS, v, 16);
@ -426,11 +446,16 @@ static void HE8uv(uint8_t *dst) { // horizontal
}
// helper for chroma-DC predictions
static inline void Put8x8uv(uint64_t v, uint8_t* dst) {
static WEBP_INLINE void Put8x8uv(uint8_t value, uint8_t* dst) {
int j;
#ifndef WEBP_REFERENCE_IMPLEMENTATION
const uint64_t v = (uint64_t)value * 0x0101010101010101ULL;
for (j = 0; j < 8; ++j) {
*(uint64_t*)(dst + j * BPS) = v;
}
#else
for (j = 0; j < 8; ++j) memset(dst + j * BPS, value, 8);
#endif
}
static void DC8uv(uint8_t *dst) { // DC
@ -439,7 +464,7 @@ static void DC8uv(uint8_t *dst) { // DC
for (i = 0; i < 8; ++i) {
dc0 += dst[i - BPS] + dst[-1 + i * BPS];
}
Put8x8uv((uint64_t)((dc0 >> 4) * 0x0101010101010101ULL), dst);
Put8x8uv(dc0 >> 4, dst);
}
static void DC8uvNoLeft(uint8_t *dst) { // DC with no left samples
@ -448,7 +473,7 @@ static void DC8uvNoLeft(uint8_t *dst) { // DC with no left samples
for (i = 0; i < 8; ++i) {
dc0 += dst[i - BPS];
}
Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst);
Put8x8uv(dc0 >> 3, dst);
}
static void DC8uvNoTop(uint8_t *dst) { // DC with no top samples
@ -457,26 +482,26 @@ static void DC8uvNoTop(uint8_t *dst) { // DC with no top samples
for (i = 0; i < 8; ++i) {
dc0 += dst[-1 + i * BPS];
}
Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst);
Put8x8uv(dc0 >> 3, dst);
}
static void DC8uvNoTopLeft(uint8_t *dst) { // DC with nothing
Put8x8uv(0x8080808080808080ULL, dst);
Put8x8uv(0x80, dst);
}
//------------------------------------------------------------------------------
// default C implementations
VP8PredFunc VP8PredLuma4[/* NUM_BMODES */] = {
const VP8PredFunc VP8PredLuma4[NUM_BMODES] = {
DC4, TM4, VE4, HE4, RD4, VR4, LD4, VL4, HD4, HU4
};
VP8PredFunc VP8PredLuma16[/*NUM_B_DC_MODES */] = {
const VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES] = {
DC16, TM16, VE16, HE16,
DC16NoTop, DC16NoLeft, DC16NoTopLeft
};
VP8PredFunc VP8PredChroma8[/*NUM_B_DC_MODES */] = {
const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = {
DC8uv, TM8uv, VE8uv, HE8uv,
DC8uvNoTop, DC8uvNoLeft, DC8uvNoTopLeft
};
@ -485,7 +510,7 @@ VP8PredFunc VP8PredChroma8[/*NUM_B_DC_MODES */] = {
// Edge filtering functions
// 4 pixels in, 2 pixels out
static inline void do_filter2(uint8_t* p, int step) {
static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1];
const int a1 = sclip2[112 + ((a + 4) >> 3)];
@ -495,7 +520,7 @@ static inline void do_filter2(uint8_t* p, int step) {
}
// 4 pixels in, 4 pixels out
static inline void do_filter4(uint8_t* p, int step) {
static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
const int a = 3 * (q0 - p0);
const int a1 = sclip2[112 + ((a + 4) >> 3)];
@ -508,7 +533,7 @@ static inline void do_filter4(uint8_t* p, int step) {
}
// 6 pixels in, 6 pixels out
static inline void do_filter6(uint8_t* p, int step) {
static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
const int q0 = p[0], q1 = p[step], q2 = p[2*step];
const int a = sclip1[1020 + 3 * (q0 - p0) + sclip1[1020 + p1 - q1]];
@ -523,17 +548,18 @@ static inline void do_filter6(uint8_t* p, int step) {
p[ 2*step] = clip1[255 + q2 - a3];
}
static inline int hev(const uint8_t* p, int step, int thresh) {
static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh);
}
static inline int needs_filter(const uint8_t* p, int step, int thresh) {
static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh;
}
static inline int needs_filter2(const uint8_t* p, int step, int t, int it) {
static WEBP_INLINE int needs_filter2(const uint8_t* p,
int step, int t, int it) {
const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step];
if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t)
@ -583,8 +609,9 @@ static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
//------------------------------------------------------------------------------
// Complex In-loop filtering (Paragraph 15.3)
static inline void FilterLoop26(uint8_t* p, int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
static WEBP_INLINE void FilterLoop26(uint8_t* p,
int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
while (size-- > 0) {
if (needs_filter2(p, hstride, thresh, ithresh)) {
if (hev(p, hstride, hev_thresh)) {
@ -597,8 +624,9 @@ static inline void FilterLoop26(uint8_t* p, int hstride, int vstride, int size,
}
}
static inline void FilterLoop24(uint8_t* p, int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
static WEBP_INLINE void FilterLoop24(uint8_t* p,
int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
while (size-- > 0) {
if (needs_filter2(p, hstride, thresh, ithresh)) {
if (hev(p, hstride, hev_thresh)) {
@ -669,6 +697,7 @@ static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
//------------------------------------------------------------------------------
VP8DecIdct2 VP8Transform;
VP8DecIdct VP8TransformAC3;
VP8DecIdct VP8TransformUV;
VP8DecIdct VP8TransformDC;
VP8DecIdct VP8TransformDCUV;
@ -696,6 +725,7 @@ void VP8DspInit(void) {
VP8TransformUV = TransformUV;
VP8TransformDC = TransformDC;
VP8TransformDCUV = TransformDCUV;
VP8TransformAC3 = TransformAC3;
VP8VFilter16 = VFilter16;
VP8HFilter16 = HFilter16;
@ -712,11 +742,11 @@ void VP8DspInit(void) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo) {
#if defined(__SSE2__) || defined(_MSC_VER)
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8DspInitSSE2();
}
#elif defined(__GNUC__) && defined(__ARM_NEON__)
#elif defined(WEBP_USE_NEON)
if (VP8GetCPUInfo(kNEON)) {
VP8DspInitNEON();
}
@ -724,6 +754,3 @@ void VP8DspInit(void) {
}
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,23 +1,24 @@
// Copyright 2011 Google Inc.
// Copyright 2012 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// ARM NEON version of dsp functions and loop filtering.
//
// Author: somnath@google.com (Somnath Banerjee)
// Authors: Somnath Banerjee (somnath@google.com)
// Johann Koenig (johannkoenig@google.com)
#if defined(__GNUC__) && defined(__ARM_NEON__)
#include "./dsp.h"
#if defined(WEBP_USE_NEON)
#include "../dec/vp8i.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#define QRegs "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", \
#define QRegs "q0", "q1", "q2", "q3", \
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
#define FLIP_SIGN_BIT2(a, b, s) \
@ -76,7 +77,7 @@ extern "C" {
"vld4.8 {" #c1"[6], " #c2"[6], " #c3"[6], " #c4"[6]}," #b1 "," #stride"\n" \
"vld4.8 {" #c1"[7], " #c2"[7], " #c3"[7], " #c4"[7]}," #b2 "," #stride"\n"
#define STORE8x2(c1, c2, p,stride) \
#define STORE8x2(c1, c2, p, stride) \
"vst2.8 {" #c1"[0], " #c2"[0]}," #p "," #stride " \n" \
"vst2.8 {" #c1"[1], " #c2"[1]}," #p "," #stride " \n" \
"vst2.8 {" #c1"[2], " #c2"[2]}," #p "," #stride " \n" \
@ -96,9 +97,9 @@ static void SimpleVFilter16NEON(uint8_t* p, int stride, int thresh) {
"vld1.u8 {q1}, [%[p]], %[stride] \n" // p1
"vld1.u8 {q2}, [%[p]], %[stride] \n" // p0
"vld1.u8 {q3}, [%[p]], %[stride] \n" // q0
"vld1.u8 {q4}, [%[p]] \n" // q1
"vld1.u8 {q12}, [%[p]] \n" // q1
DO_FILTER2(q1, q2, q3, q4, %[thresh])
DO_FILTER2(q1, q2, q3, q12, %[thresh])
"sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride
@ -117,18 +118,18 @@ static void SimpleHFilter16NEON(uint8_t* p, int stride, int thresh) {
"add r5, r4, %[stride] \n" // base2 = base1 + stride
LOAD8x4(d2, d3, d4, d5, [r4], [r5], r6)
LOAD8x4(d6, d7, d8, d9, [r4], [r5], r6)
"vswp d3, d6 \n" // p1:q1 p0:q3
"vswp d5, d8 \n" // q0:q2 q1:q4
"vswp q2, q3 \n" // p1:q1 p0:q2 q0:q3 q1:q4
LOAD8x4(d24, d25, d26, d27, [r4], [r5], r6)
"vswp d3, d24 \n" // p1:q1 p0:q3
"vswp d5, d26 \n" // q0:q2 q1:q4
"vswp q2, q12 \n" // p1:q1 p0:q2 q0:q3 q1:q4
DO_FILTER2(q1, q2, q3, q4, %[thresh])
DO_FILTER2(q1, q2, q12, q13, %[thresh])
"sub %[p], %[p], #1 \n" // p - 1
"vswp d5, d6 \n"
"vswp d5, d24 \n"
STORE8x2(d4, d5, [%[p]], %[stride])
STORE8x2(d6, d7, [%[p]], %[stride])
STORE8x2(d24, d25, [%[p]], %[stride])
: [p] "+r"(p)
: [stride] "r"(stride), [thresh] "r"(thresh)
@ -152,17 +153,281 @@ static void SimpleHFilter16iNEON(uint8_t* p, int stride, int thresh) {
}
}
//-----------------------------------------------------------------------------
// Inverse transforms (Paragraph 14.4)
static void TransformOne(const int16_t* in, uint8_t* dst) {
const int kBPS = BPS;
const int16_t constants[] = {20091, 17734, 0, 0};
/* kC1, kC2. Padded because vld1.16 loads 8 bytes
* Technically these are unsigned but vqdmulh is only available in signed.
* vqdmulh returns high half (effectively >> 16) but also doubles the value,
* changing the >> 16 to >> 15 and requiring an additional >> 1.
* We use this to our advantage with kC2. The canonical value is 35468.
* However, the high bit is set so treating it as signed will give incorrect
* results. We avoid this by down shifting by 1 here to clear the highest bit.
* Combined with the doubling effect of vqdmulh we get >> 16.
* This can not be applied to kC1 because the lowest bit is set. Down shifting
* the constant would reduce precision.
*/
/* libwebp uses a trick to avoid some extra addition that libvpx does.
* Instead of:
* temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16);
* libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the
* same issue with kC1 and vqdmulh that we work around by down shifting kC2
*/
/* Adapted from libvpx: vp8/common/arm/neon/shortidct4x4llm_neon.asm */
__asm__ volatile (
"vld1.16 {q1, q2}, [%[in]] \n"
"vld1.16 {d0}, [%[constants]] \n"
/* d2: in[0]
* d3: in[8]
* d4: in[4]
* d5: in[12]
*/
"vswp d3, d4 \n"
/* q8 = {in[4], in[12]} * kC1 * 2 >> 16
* q9 = {in[4], in[12]} * kC2 >> 16
*/
"vqdmulh.s16 q8, q2, d0[0] \n"
"vqdmulh.s16 q9, q2, d0[1] \n"
/* d22 = a = in[0] + in[8]
* d23 = b = in[0] - in[8]
*/
"vqadd.s16 d22, d2, d3 \n"
"vqsub.s16 d23, d2, d3 \n"
/* The multiplication should be x * kC1 >> 16
* However, with vqdmulh we get x * kC1 * 2 >> 16
* (multiply, double, return high half)
* We avoided this in kC2 by pre-shifting the constant.
* q8 = in[4]/[12] * kC1 >> 16
*/
"vshr.s16 q8, q8, #1 \n"
/* Add {in[4], in[12]} back after the multiplication. This is handled by
* adding 1 << 16 to kC1 in the libwebp C code.
*/
"vqadd.s16 q8, q2, q8 \n"
/* d20 = c = in[4]*kC2 - in[12]*kC1
* d21 = d = in[4]*kC1 + in[12]*kC2
*/
"vqsub.s16 d20, d18, d17 \n"
"vqadd.s16 d21, d19, d16 \n"
/* d2 = tmp[0] = a + d
* d3 = tmp[1] = b + c
* d4 = tmp[2] = b - c
* d5 = tmp[3] = a - d
*/
"vqadd.s16 d2, d22, d21 \n"
"vqadd.s16 d3, d23, d20 \n"
"vqsub.s16 d4, d23, d20 \n"
"vqsub.s16 d5, d22, d21 \n"
"vzip.16 q1, q2 \n"
"vzip.16 q1, q2 \n"
"vswp d3, d4 \n"
/* q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16
* q9 = {tmp[4], tmp[12]} * kC2 >> 16
*/
"vqdmulh.s16 q8, q2, d0[0] \n"
"vqdmulh.s16 q9, q2, d0[1] \n"
/* d22 = a = tmp[0] + tmp[8]
* d23 = b = tmp[0] - tmp[8]
*/
"vqadd.s16 d22, d2, d3 \n"
"vqsub.s16 d23, d2, d3 \n"
/* See long winded explanations prior */
"vshr.s16 q8, q8, #1 \n"
"vqadd.s16 q8, q2, q8 \n"
/* d20 = c = in[4]*kC2 - in[12]*kC1
* d21 = d = in[4]*kC1 + in[12]*kC2
*/
"vqsub.s16 d20, d18, d17 \n"
"vqadd.s16 d21, d19, d16 \n"
/* d2 = tmp[0] = a + d
* d3 = tmp[1] = b + c
* d4 = tmp[2] = b - c
* d5 = tmp[3] = a - d
*/
"vqadd.s16 d2, d22, d21 \n"
"vqadd.s16 d3, d23, d20 \n"
"vqsub.s16 d4, d23, d20 \n"
"vqsub.s16 d5, d22, d21 \n"
"vld1.32 d6[0], [%[dst]], %[kBPS] \n"
"vld1.32 d6[1], [%[dst]], %[kBPS] \n"
"vld1.32 d7[0], [%[dst]], %[kBPS] \n"
"vld1.32 d7[1], [%[dst]], %[kBPS] \n"
"sub %[dst], %[dst], %[kBPS], lsl #2 \n"
/* (val) + 4 >> 3 */
"vrshr.s16 d2, d2, #3 \n"
"vrshr.s16 d3, d3, #3 \n"
"vrshr.s16 d4, d4, #3 \n"
"vrshr.s16 d5, d5, #3 \n"
"vzip.16 q1, q2 \n"
"vzip.16 q1, q2 \n"
/* Must accumulate before saturating */
"vmovl.u8 q8, d6 \n"
"vmovl.u8 q9, d7 \n"
"vqadd.s16 q1, q1, q8 \n"
"vqadd.s16 q2, q2, q9 \n"
"vqmovun.s16 d0, q1 \n"
"vqmovun.s16 d1, q2 \n"
"vst1.32 d0[0], [%[dst]], %[kBPS] \n"
"vst1.32 d0[1], [%[dst]], %[kBPS] \n"
"vst1.32 d1[0], [%[dst]], %[kBPS] \n"
"vst1.32 d1[1], [%[dst]] \n"
: [in] "+r"(in), [dst] "+r"(dst) /* modified registers */
: [kBPS] "r"(kBPS), [constants] "r"(constants) /* constants */
: "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" /* clobbered */
);
}
static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
TransformOne(in, dst);
if (do_two) {
TransformOne(in + 16, dst + 4);
}
}
static void TransformDC(const int16_t* in, uint8_t* dst) {
const int DC = (in[0] + 4) >> 3;
const int kBPS = BPS;
__asm__ volatile (
"vdup.16 q1, %[DC] \n"
"vld1.32 d0[0], [%[dst]], %[kBPS] \n"
"vld1.32 d1[0], [%[dst]], %[kBPS] \n"
"vld1.32 d0[1], [%[dst]], %[kBPS] \n"
"vld1.32 d1[1], [%[dst]], %[kBPS] \n"
"sub %[dst], %[dst], %[kBPS], lsl #2 \n"
// add DC and convert to s16.
"vaddw.u8 q2, q1, d0 \n"
"vaddw.u8 q3, q1, d1 \n"
// convert back to u8 with saturation
"vqmovun.s16 d0, q2 \n"
"vqmovun.s16 d1, q3 \n"
"vst1.32 d0[0], [%[dst]], %[kBPS] \n"
"vst1.32 d1[0], [%[dst]], %[kBPS] \n"
"vst1.32 d0[1], [%[dst]], %[kBPS] \n"
"vst1.32 d1[1], [%[dst]] \n"
: [in] "+r"(in), [dst] "+r"(dst) /* modified registers */
: [kBPS] "r"(kBPS), /* constants */
[DC] "r"(DC)
: "memory", "q0", "q1", "q2", "q3" /* clobbered */
);
}
static void TransformWHT(const int16_t* in, int16_t* out) {
const int kStep = 32; // The store is only incrementing the pointer as if we
// had stored a single byte.
__asm__ volatile (
// part 1
// load data into q0, q1
"vld1.16 {q0, q1}, [%[in]] \n"
"vaddl.s16 q2, d0, d3 \n" // a0 = in[0] + in[12]
"vaddl.s16 q3, d1, d2 \n" // a1 = in[4] + in[8]
"vsubl.s16 q10, d1, d2 \n" // a2 = in[4] - in[8]
"vsubl.s16 q11, d0, d3 \n" // a3 = in[0] - in[12]
"vadd.s32 q0, q2, q3 \n" // tmp[0] = a0 + a1
"vsub.s32 q2, q2, q3 \n" // tmp[8] = a0 - a1
"vadd.s32 q1, q11, q10 \n" // tmp[4] = a3 + a2
"vsub.s32 q3, q11, q10 \n" // tmp[12] = a3 - a2
// Transpose
// q0 = tmp[0, 4, 8, 12], q1 = tmp[2, 6, 10, 14]
// q2 = tmp[1, 5, 9, 13], q3 = tmp[3, 7, 11, 15]
"vswp d1, d4 \n" // vtrn.64 q0, q2
"vswp d3, d6 \n" // vtrn.64 q1, q3
"vtrn.32 q0, q1 \n"
"vtrn.32 q2, q3 \n"
"vmov.s32 q10, #3 \n" // dc = 3
"vadd.s32 q0, q0, q10 \n" // dc = tmp[0] + 3
"vadd.s32 q12, q0, q3 \n" // a0 = dc + tmp[3]
"vadd.s32 q13, q1, q2 \n" // a1 = tmp[1] + tmp[2]
"vsub.s32 q8, q1, q2 \n" // a2 = tmp[1] - tmp[2]
"vsub.s32 q9, q0, q3 \n" // a3 = dc - tmp[3]
"vadd.s32 q0, q12, q13 \n"
"vshrn.s32 d0, q0, #3 \n" // (a0 + a1) >> 3
"vadd.s32 q1, q9, q8 \n"
"vshrn.s32 d1, q1, #3 \n" // (a3 + a2) >> 3
"vsub.s32 q2, q12, q13 \n"
"vshrn.s32 d2, q2, #3 \n" // (a0 - a1) >> 3
"vsub.s32 q3, q9, q8 \n"
"vshrn.s32 d3, q3, #3 \n" // (a3 - a2) >> 3
// set the results to output
"vst1.16 d0[0], [%[out]], %[kStep] \n"
"vst1.16 d1[0], [%[out]], %[kStep] \n"
"vst1.16 d2[0], [%[out]], %[kStep] \n"
"vst1.16 d3[0], [%[out]], %[kStep] \n"
"vst1.16 d0[1], [%[out]], %[kStep] \n"
"vst1.16 d1[1], [%[out]], %[kStep] \n"
"vst1.16 d2[1], [%[out]], %[kStep] \n"
"vst1.16 d3[1], [%[out]], %[kStep] \n"
"vst1.16 d0[2], [%[out]], %[kStep] \n"
"vst1.16 d1[2], [%[out]], %[kStep] \n"
"vst1.16 d2[2], [%[out]], %[kStep] \n"
"vst1.16 d3[2], [%[out]], %[kStep] \n"
"vst1.16 d0[3], [%[out]], %[kStep] \n"
"vst1.16 d1[3], [%[out]], %[kStep] \n"
"vst1.16 d2[3], [%[out]], %[kStep] \n"
"vst1.16 d3[3], [%[out]], %[kStep] \n"
: [out] "+r"(out) // modified registers
: [in] "r"(in), [kStep] "r"(kStep) // constants
: "memory", "q0", "q1", "q2", "q3",
"q8", "q9", "q10", "q11", "q12", "q13" // clobbered
);
}
#endif // WEBP_USE_NEON
//------------------------------------------------------------------------------
// Entry point
extern void VP8DspInitNEON(void);
void VP8DspInitNEON(void) {
#if defined(WEBP_USE_NEON)
VP8Transform = TransformTwo;
VP8TransformAC3 = TransformOne; // no special code here
VP8TransformDC = TransformDC;
VP8TransformWHT = TransformWHT;
VP8SimpleVFilter16 = SimpleVFilter16NEON;
VP8SimpleHFilter16 = SimpleHFilter16NEON;
VP8SimpleVFilter16i = SimpleVFilter16iNEON;
VP8SimpleHFilter16i = SimpleHFilter16iNEON;
#endif // WEBP_USE_NEON
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif // __GNUC__ && __ARM_NEON__

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// SSE2 version of some decoding functions (idct, loop filtering).
@ -10,15 +12,17 @@
// Author: somnath@google.com (Somnath Banerjee)
// cduvivier@google.com (Christian Duvivier)
#if defined(__SSE2__) || defined(_MSC_VER)
#include "./dsp.h"
#if defined(WEBP_USE_SSE2)
// The 3-coeff sparse transform in SSE2 is not really faster than the plain-C
// one it seems => disable it by default. Uncomment the following to enable:
// #define USE_TRANSFORM_AC3
#include <emmintrin.h>
#include "../dec/vp8i.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
@ -192,21 +196,21 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
// Add inverse transform to 'dst' and store.
{
const __m128i zero = _mm_set1_epi16(0);
const __m128i zero = _mm_setzero_si128();
// Load the reference(s).
__m128i dst0, dst1, dst2, dst3;
if (do_two) {
// Load eight bytes/pixels per line.
dst0 = _mm_loadl_epi64((__m128i*)&dst[0 * BPS]);
dst1 = _mm_loadl_epi64((__m128i*)&dst[1 * BPS]);
dst2 = _mm_loadl_epi64((__m128i*)&dst[2 * BPS]);
dst3 = _mm_loadl_epi64((__m128i*)&dst[3 * BPS]);
dst0 = _mm_loadl_epi64((__m128i*)(dst + 0 * BPS));
dst1 = _mm_loadl_epi64((__m128i*)(dst + 1 * BPS));
dst2 = _mm_loadl_epi64((__m128i*)(dst + 2 * BPS));
dst3 = _mm_loadl_epi64((__m128i*)(dst + 3 * BPS));
} else {
// Load four bytes/pixels per line.
dst0 = _mm_cvtsi32_si128(*(int*)&dst[0 * BPS]);
dst1 = _mm_cvtsi32_si128(*(int*)&dst[1 * BPS]);
dst2 = _mm_cvtsi32_si128(*(int*)&dst[2 * BPS]);
dst3 = _mm_cvtsi32_si128(*(int*)&dst[3 * BPS]);
dst0 = _mm_cvtsi32_si128(*(int*)(dst + 0 * BPS));
dst1 = _mm_cvtsi32_si128(*(int*)(dst + 1 * BPS));
dst2 = _mm_cvtsi32_si128(*(int*)(dst + 2 * BPS));
dst3 = _mm_cvtsi32_si128(*(int*)(dst + 3 * BPS));
}
// Convert to 16b.
dst0 = _mm_unpacklo_epi8(dst0, zero);
@ -226,20 +230,66 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
// Store the results.
if (do_two) {
// Store eight bytes/pixels per line.
_mm_storel_epi64((__m128i*)&dst[0 * BPS], dst0);
_mm_storel_epi64((__m128i*)&dst[1 * BPS], dst1);
_mm_storel_epi64((__m128i*)&dst[2 * BPS], dst2);
_mm_storel_epi64((__m128i*)&dst[3 * BPS], dst3);
_mm_storel_epi64((__m128i*)(dst + 0 * BPS), dst0);
_mm_storel_epi64((__m128i*)(dst + 1 * BPS), dst1);
_mm_storel_epi64((__m128i*)(dst + 2 * BPS), dst2);
_mm_storel_epi64((__m128i*)(dst + 3 * BPS), dst3);
} else {
// Store four bytes/pixels per line.
*((int32_t *)&dst[0 * BPS]) = _mm_cvtsi128_si32(dst0);
*((int32_t *)&dst[1 * BPS]) = _mm_cvtsi128_si32(dst1);
*((int32_t *)&dst[2 * BPS]) = _mm_cvtsi128_si32(dst2);
*((int32_t *)&dst[3 * BPS]) = _mm_cvtsi128_si32(dst3);
*(int*)(dst + 0 * BPS) = _mm_cvtsi128_si32(dst0);
*(int*)(dst + 1 * BPS) = _mm_cvtsi128_si32(dst1);
*(int*)(dst + 2 * BPS) = _mm_cvtsi128_si32(dst2);
*(int*)(dst + 3 * BPS) = _mm_cvtsi128_si32(dst3);
}
}
}
#if defined(USE_TRANSFORM_AC3)
#define MUL(a, b) (((a) * (b)) >> 16)
static void TransformAC3SSE2(const int16_t* in, uint8_t* dst) {
static const int kC1 = 20091 + (1 << 16);
static const int kC2 = 35468;
const __m128i A = _mm_set1_epi16(in[0] + 4);
const __m128i c4 = _mm_set1_epi16(MUL(in[4], kC2));
const __m128i d4 = _mm_set1_epi16(MUL(in[4], kC1));
const int c1 = MUL(in[1], kC2);
const int d1 = MUL(in[1], kC1);
const __m128i CD = _mm_set_epi16(0, 0, 0, 0, -d1, -c1, c1, d1);
const __m128i B = _mm_adds_epi16(A, CD);
const __m128i m0 = _mm_adds_epi16(B, d4);
const __m128i m1 = _mm_adds_epi16(B, c4);
const __m128i m2 = _mm_subs_epi16(B, c4);
const __m128i m3 = _mm_subs_epi16(B, d4);
const __m128i zero = _mm_setzero_si128();
// Load the source pixels.
__m128i dst0 = _mm_cvtsi32_si128(*(int*)(dst + 0 * BPS));
__m128i dst1 = _mm_cvtsi32_si128(*(int*)(dst + 1 * BPS));
__m128i dst2 = _mm_cvtsi32_si128(*(int*)(dst + 2 * BPS));
__m128i dst3 = _mm_cvtsi32_si128(*(int*)(dst + 3 * BPS));
// Convert to 16b.
dst0 = _mm_unpacklo_epi8(dst0, zero);
dst1 = _mm_unpacklo_epi8(dst1, zero);
dst2 = _mm_unpacklo_epi8(dst2, zero);
dst3 = _mm_unpacklo_epi8(dst3, zero);
// Add the inverse transform.
dst0 = _mm_adds_epi16(dst0, _mm_srai_epi16(m0, 3));
dst1 = _mm_adds_epi16(dst1, _mm_srai_epi16(m1, 3));
dst2 = _mm_adds_epi16(dst2, _mm_srai_epi16(m2, 3));
dst3 = _mm_adds_epi16(dst3, _mm_srai_epi16(m3, 3));
// Unsigned saturate to 8b.
dst0 = _mm_packus_epi16(dst0, dst0);
dst1 = _mm_packus_epi16(dst1, dst1);
dst2 = _mm_packus_epi16(dst2, dst2);
dst3 = _mm_packus_epi16(dst3, dst3);
// Store the results.
*(int*)(dst + 0 * BPS) = _mm_cvtsi128_si32(dst0);
*(int*)(dst + 1 * BPS) = _mm_cvtsi128_si32(dst1);
*(int*)(dst + 2 * BPS) = _mm_cvtsi128_si32(dst2);
*(int*)(dst + 3 * BPS) = _mm_cvtsi128_si32(dst3);
}
#undef MUL
#endif // USE_TRANSFORM_AC3
//------------------------------------------------------------------------------
// Loop Filter (Paragraph 15)
@ -276,14 +326,14 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
#define GET_NOTHEV(p1, p0, q0, q1, hev_thresh, not_hev) { \
const __m128i zero = _mm_setzero_si128(); \
const __m128i t1 = MM_ABS(p1, p0); \
const __m128i t2 = MM_ABS(q1, q0); \
const __m128i t_1 = MM_ABS(p1, p0); \
const __m128i t_2 = MM_ABS(q1, q0); \
\
const __m128i h = _mm_set1_epi8(hev_thresh); \
const __m128i t3 = _mm_subs_epu8(t1, h); /* abs(p1 - p0) - hev_tresh */ \
const __m128i t4 = _mm_subs_epu8(t2, h); /* abs(q1 - q0) - hev_tresh */ \
const __m128i t_3 = _mm_subs_epu8(t_1, h); /* abs(p1 - p0) - hev_tresh */ \
const __m128i t_4 = _mm_subs_epu8(t_2, h); /* abs(q1 - q0) - hev_tresh */ \
\
not_hev = _mm_or_si128(t3, t4); \
not_hev = _mm_or_si128(t_3, t_4); \
not_hev = _mm_cmpeq_epi8(not_hev, zero); /* not_hev <= t1 && not_hev <= t2 */\
}
@ -312,13 +362,13 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
// Updates values of 2 pixels at MB edge during complex filtering.
// Update operations:
// q = q - a and p = p + a; where a = [(a_hi >> 7), (a_lo >> 7)]
// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)]
#define UPDATE_2PIXELS(pi, qi, a_lo, a_hi) { \
const __m128i a_lo7 = _mm_srai_epi16(a_lo, 7); \
const __m128i a_hi7 = _mm_srai_epi16(a_hi, 7); \
const __m128i a = _mm_packs_epi16(a_lo7, a_hi7); \
pi = _mm_adds_epi8(pi, a); \
qi = _mm_subs_epi8(qi, a); \
const __m128i delta = _mm_packs_epi16(a_lo7, a_hi7); \
pi = _mm_adds_epi8(pi, delta); \
qi = _mm_subs_epi8(qi, delta); \
}
static void NeedsFilter(const __m128i* p1, const __m128i* p0, const __m128i* q0,
@ -341,8 +391,8 @@ static void NeedsFilter(const __m128i* p1, const __m128i* p0, const __m128i* q0,
// Edge filtering functions
// Applies filter on 2 pixels (p0 and q0)
static inline void DoFilter2(const __m128i* p1, __m128i* p0, __m128i* q0,
const __m128i* q1, int thresh) {
static WEBP_INLINE void DoFilter2(const __m128i* p1, __m128i* p0, __m128i* q0,
const __m128i* q1, int thresh) {
__m128i a, mask;
const __m128i sign_bit = _mm_set1_epi8(0x80);
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
@ -362,8 +412,9 @@ static inline void DoFilter2(const __m128i* p1, __m128i* p0, __m128i* q0,
}
// Applies filter on 4 pixels (p1, p0, q0 and q1)
static inline void DoFilter4(__m128i* p1, __m128i *p0, __m128i* q0, __m128i* q1,
const __m128i* mask, int hev_thresh) {
static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0,
__m128i* q0, __m128i* q1,
const __m128i* mask, int hev_thresh) {
__m128i not_hev;
__m128i t1, t2, t3;
const __m128i sign_bit = _mm_set1_epi8(0x80);
@ -408,9 +459,9 @@ static inline void DoFilter4(__m128i* p1, __m128i *p0, __m128i* q0, __m128i* q1,
}
// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
static inline void DoFilter6(__m128i *p2, __m128i* p1, __m128i *p0,
__m128i* q0, __m128i* q1, __m128i *q2,
const __m128i* mask, int hev_thresh) {
static WEBP_INLINE void DoFilter6(__m128i *p2, __m128i* p1, __m128i *p0,
__m128i* q0, __m128i* q1, __m128i *q2,
const __m128i* mask, int hev_thresh) {
__m128i a, not_hev;
const __m128i sign_bit = _mm_set1_epi8(0x80);
@ -466,8 +517,8 @@ static inline void DoFilter6(__m128i *p2, __m128i* p1, __m128i *p0,
//
// TODO(somnath): Investigate _mm_shuffle* also see if it can be broken into
// two Load4x4() to avoid code duplication.
static inline void Load8x4(const uint8_t* b, int stride,
__m128i* p, __m128i* q) {
static WEBP_INLINE void Load8x4(const uint8_t* b, int stride,
__m128i* p, __m128i* q) {
__m128i t1, t2;
// Load 0th, 1st, 4th and 5th rows
@ -506,9 +557,10 @@ static inline void Load8x4(const uint8_t* b, int stride,
*q = _mm_unpackhi_epi32(t1, t2);
}
static inline void Load16x4(const uint8_t* r0, const uint8_t* r8, int stride,
__m128i* p1, __m128i* p0,
__m128i* q0, __m128i* q1) {
static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8,
int stride,
__m128i* p1, __m128i* p0,
__m128i* q0, __m128i* q1) {
__m128i t1, t2;
// Assume the pixels around the edge (|) are numbered as follows
// 00 01 | 02 03
@ -540,7 +592,7 @@ static inline void Load16x4(const uint8_t* r0, const uint8_t* r8, int stride,
*q1 = _mm_unpackhi_epi64(t2, *q1);
}
static inline void Store4x4(__m128i* x, uint8_t* dst, int stride) {
static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) {
int i;
for (i = 0; i < 4; ++i, dst += stride) {
*((int32_t*)dst) = _mm_cvtsi128_si32(*x);
@ -549,8 +601,9 @@ static inline void Store4x4(__m128i* x, uint8_t* dst, int stride) {
}
// Transpose back and store
static inline void Store16x4(uint8_t* r0, uint8_t* r8, int stride, __m128i* p1,
__m128i* p0, __m128i* q0, __m128i* q1) {
static WEBP_INLINE void Store16x4(uint8_t* r0, uint8_t* r8, int stride,
__m128i* p1, __m128i* p0,
__m128i* q0, __m128i* q1) {
__m128i t1;
// p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
@ -871,10 +924,19 @@ static void HFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
Store16x4(u, v, stride, &p1, &p0, &q0, &q1);
}
#endif // WEBP_USE_SSE2
//------------------------------------------------------------------------------
// Entry point
extern void VP8DspInitSSE2(void);
void VP8DspInitSSE2(void) {
#if defined(WEBP_USE_SSE2)
VP8Transform = TransformSSE2;
#if defined(USE_TRANSFORM_AC3)
VP8TransformAC3 = TransformAC3SSE2;
#endif
VP8VFilter16 = VFilter16SSE2;
VP8HFilter16 = HFilter16SSE2;
@ -889,10 +951,6 @@ void VP8DspInitSSE2(void) {
VP8SimpleHFilter16 = SimpleHFilter16SSE2;
VP8SimpleVFilter16i = SimpleVFilter16iSSE2;
VP8SimpleHFilter16i = SimpleHFilter16iSSE2;
#endif // WEBP_USE_SSE2
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif //__SSE2__ || _MSC_VER

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Speed-critical functions.
@ -14,13 +16,30 @@
#include "../webp/types.h"
#if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
extern "C" {
#endif
//------------------------------------------------------------------------------
// CPU detection
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
#endif
#if defined(__SSE2__) || defined(WEBP_MSC_SSE2)
#define WEBP_USE_SSE2
#endif
#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
#define WEBP_ANDROID_NEON // Android targets that might support NEON
#endif
#if defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON)
#define WEBP_USE_NEON
#endif
typedef enum {
kSSE2,
kSSE3,
@ -33,8 +52,6 @@ extern VP8CPUInfo VP8GetCPUInfo;
//------------------------------------------------------------------------------
// Encoding
int VP8GetAlpha(const int histo[]);
// Transforms
// VP8Idct: Does one of two inverse transforms. If do_two is set, the transforms
// will be done for (ref, in, dst) and (ref + 4, in + 16, dst + 4).
@ -63,18 +80,22 @@ extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16;
typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst);
extern VP8BlockCopy VP8Copy4x4;
extern VP8BlockCopy VP8Copy8x8;
extern VP8BlockCopy VP8Copy16x16;
// Quantization
struct VP8Matrix; // forward declaration
typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16],
int n, const struct VP8Matrix* const mtx);
extern VP8QuantizeBlock VP8EncQuantizeBlock;
// Compute susceptibility based on DCT-coeff histograms:
// the higher, the "easier" the macroblock is to compress.
typedef int (*VP8CHisto)(const uint8_t* ref, const uint8_t* pred,
int start_block, int end_block);
// specific to 2nd transform:
typedef int (*VP8QuantizeBlockWHT)(int16_t in[16], int16_t out[16],
const struct VP8Matrix* const mtx);
extern VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT;
// Collect histogram for susceptibility calculation and accumulate in histo[].
struct VP8Histogram;
typedef void (*VP8CHisto)(const uint8_t* ref, const uint8_t* pred,
int start_block, int end_block,
struct VP8Histogram* const histo);
extern const int VP8DspScan[16 + 4 + 4];
extern VP8CHisto VP8CollectHistogram;
@ -87,17 +108,18 @@ typedef void (*VP8DecIdct)(const int16_t* coeffs, uint8_t* dst);
// when doing two transforms, coeffs is actually int16_t[2][16].
typedef void (*VP8DecIdct2)(const int16_t* coeffs, uint8_t* dst, int do_two);
extern VP8DecIdct2 VP8Transform;
extern VP8DecIdct VP8TransformAC3;
extern VP8DecIdct VP8TransformUV;
extern VP8DecIdct VP8TransformDC;
extern VP8DecIdct VP8TransformDCUV;
extern void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
extern VP8WHT VP8TransformWHT;
// *dst is the destination block, with stride BPS. Boundary samples are
// assumed accessible when needed.
typedef void (*VP8PredFunc)(uint8_t* dst);
extern VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
extern VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
extern VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
extern const VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
extern const VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
extern const VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
// simple filter (only for luma)
typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh);
@ -124,28 +146,32 @@ extern VP8ChromaFilterFunc VP8VFilter8i; // filtering u and v altogether
extern VP8ChromaFilterFunc VP8HFilter8i;
// must be called before anything using the above
extern void VP8DspInit(void);
void VP8DspInit(void);
//------------------------------------------------------------------------------
// WebP I/O
#define FANCY_UPSAMPLING // undefined to remove fancy upsampling support
#ifdef FANCY_UPSAMPLING
// Convert a pair of y/u/v lines together to the output rgb/a colorspace.
// bottom_y can be NULL if only one line of output is needed (at top/bottom).
typedef void (*WebPUpsampleLinePairFunc)(
const uint8_t* top_y, const uint8_t* bottom_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* bottom_dst, int len);
#ifdef FANCY_UPSAMPLING
// Fancy upsampling functions to convert YUV to RGB(A) modes
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
extern WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[/* MODE_LAST */];
// Initializes SSE2 version of the fancy upsamplers.
void WebPInitUpsamplersSSE2(void);
// NEON version
void WebPInitUpsamplersNEON(void);
#endif // FANCY_UPSAMPLING
// Point-sampling methods.
@ -156,6 +182,11 @@ typedef void (*WebPSampleLinePairFunc)(
extern const WebPSampleLinePairFunc WebPSamplers[/* MODE_LAST */];
// General function for converting two lines of ARGB or RGBA.
// 'alpha_is_last' should be true if 0xff000000 is stored in memory as
// as 0x00, 0x00, 0x00, 0xff (little endian).
WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last);
// YUV444->RGB converters
typedef void (*WebPYUV444Converter)(const uint8_t* y,
const uint8_t* u, const uint8_t* v,
@ -167,8 +198,26 @@ extern const WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
void WebPInitUpsamplers(void);
//------------------------------------------------------------------------------
// Pre-multiply planes with alpha values
#if defined(__cplusplus) || defined(c_plusplus)
// Apply alpha pre-multiply on an rgba, bgra or argb plane of size w * h.
// alpha_first should be 0 for argb, 1 for rgba or bgra (where alpha is last).
extern void (*WebPApplyAlphaMultiply)(
uint8_t* rgba, int alpha_first, int w, int h, int stride);
// Same, buf specifically for RGBA4444 format
extern void (*WebPApplyAlphaMultiply4444)(
uint8_t* rgba4444, int w, int h, int stride);
// To be called first before using the above.
void WebPInitPremultiply(void);
void WebPInitPremultiplySSE2(void); // should not be called directly.
void WebPInitPremultiplyNEON(void);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,45 +1,34 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Speed-critical encoding functions.
//
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include <stdlib.h> // for abs()
#include "./dsp.h"
#include "../enc/vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static WEBP_INLINE uint8_t clip_8b(int v) {
return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
}
static WEBP_INLINE int clip_max(int v, int max) {
return (v > max) ? max : v;
}
//------------------------------------------------------------------------------
// Compute susceptibility based on DCT-coeff histograms:
// the higher, the "easier" the macroblock is to compress.
static int ClipAlpha(int alpha) {
return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
}
int VP8GetAlpha(const int histo[MAX_COEFF_THRESH + 1]) {
int num = 0, den = 0, val = 0;
int k;
int alpha;
// note: changing this loop to avoid the numerous "k + 1" slows things down.
for (k = 0; k < MAX_COEFF_THRESH; ++k) {
if (histo[k + 1]) {
val += histo[k + 1];
num += val * (k + 1);
den += (k + 1) * (k + 1);
}
}
// we scale the value to a usable [0..255] range
alpha = den ? 10 * num / den - 5 : 0;
return ClipAlpha(alpha);
}
const int VP8DspScan[16 + 4 + 4] = {
// Luma
0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
@ -51,27 +40,23 @@ const int VP8DspScan[16 + 4 + 4] = {
8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V
};
static int CollectHistogram(const uint8_t* ref, const uint8_t* pred,
int start_block, int end_block) {
int histo[MAX_COEFF_THRESH + 1] = { 0 };
int16_t out[16];
int j, k;
static void CollectHistogram(const uint8_t* ref, const uint8_t* pred,
int start_block, int end_block,
VP8Histogram* const histo) {
int j;
for (j = start_block; j < end_block; ++j) {
int k;
int16_t out[16];
VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
// Convert coefficients to bin (within out[]).
// Convert coefficients to bin.
for (k = 0; k < 16; ++k) {
const int v = abs(out[k]) >> 2;
out[k] = (v > MAX_COEFF_THRESH) ? MAX_COEFF_THRESH : v;
}
// Use bin to update histogram.
for (k = 0; k < 16; ++k) {
histo[out[k]]++;
const int v = abs(out[k]) >> 3; // TODO(skal): add rounding?
const int clipped_value = clip_max(v, MAX_COEFF_THRESH);
histo->distribution[clipped_value]++;
}
}
return VP8GetAlpha(histo);
}
//------------------------------------------------------------------------------
@ -87,15 +72,12 @@ static void InitTables(void) {
if (!tables_ok) {
int i;
for (i = -255; i <= 255 + 255; ++i) {
clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
clip1[255 + i] = clip_8b(i);
}
tables_ok = 1;
}
}
static inline uint8_t clip_8b(int v) {
return (!(v & ~0xff)) ? v : v < 0 ? 0 : 255;
}
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
@ -107,8 +89,8 @@ static const int kC1 = 20091 + (1 << 16);
static const int kC2 = 35468;
#define MUL(a, b) (((a) * (b)) >> 16)
static inline void ITransformOne(const uint8_t* ref, const int16_t* in,
uint8_t* dst) {
static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
uint8_t* dst) {
int C[4 * 4], *tmp;
int i;
tmp = C;
@ -152,25 +134,25 @@ static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
int i;
int tmp[16];
for (i = 0; i < 4; ++i, src += BPS, ref += BPS) {
const int d0 = src[0] - ref[0];
const int d0 = src[0] - ref[0]; // 9bit dynamic range ([-255,255])
const int d1 = src[1] - ref[1];
const int d2 = src[2] - ref[2];
const int d3 = src[3] - ref[3];
const int a0 = (d0 + d3) << 3;
const int a1 = (d1 + d2) << 3;
const int a2 = (d1 - d2) << 3;
const int a3 = (d0 - d3) << 3;
tmp[0 + i * 4] = (a0 + a1);
tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 14500) >> 12;
tmp[2 + i * 4] = (a0 - a1);
tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 7500) >> 12;
const int a0 = (d0 + d3); // 10b [-510,510]
const int a1 = (d1 + d2);
const int a2 = (d1 - d2);
const int a3 = (d0 - d3);
tmp[0 + i * 4] = (a0 + a1) * 8; // 14b [-8160,8160]
tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 1812) >> 9; // [-7536,7542]
tmp[2 + i * 4] = (a0 - a1) * 8;
tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 937) >> 9;
}
for (i = 0; i < 4; ++i) {
const int a0 = (tmp[0 + i] + tmp[12 + i]);
const int a0 = (tmp[0 + i] + tmp[12 + i]); // 15b
const int a1 = (tmp[4 + i] + tmp[ 8 + i]);
const int a2 = (tmp[4 + i] - tmp[ 8 + i]);
const int a3 = (tmp[0 + i] - tmp[12 + i]);
out[0 + i] = (a0 + a1 + 7) >> 4;
out[0 + i] = (a0 + a1 + 7) >> 4; // 12b
out[4 + i] = ((a2 * 2217 + a3 * 5352 + 12000) >> 16) + (a3 != 0);
out[8 + i] = (a0 - a1 + 7) >> 4;
out[12+ i] = ((a3 * 2217 - a2 * 5352 + 51000) >> 16);
@ -205,31 +187,32 @@ static void ITransformWHT(const int16_t* in, int16_t* out) {
}
static void FTransformWHT(const int16_t* in, int16_t* out) {
int tmp[16];
// input is 12b signed
int32_t tmp[16];
int i;
for (i = 0; i < 4; ++i, in += 64) {
const int a0 = (in[0 * 16] + in[2 * 16]) << 2;
const int a1 = (in[1 * 16] + in[3 * 16]) << 2;
const int a2 = (in[1 * 16] - in[3 * 16]) << 2;
const int a3 = (in[0 * 16] - in[2 * 16]) << 2;
tmp[0 + i * 4] = (a0 + a1) + (a0 != 0);
const int a0 = (in[0 * 16] + in[2 * 16]); // 13b
const int a1 = (in[1 * 16] + in[3 * 16]);
const int a2 = (in[1 * 16] - in[3 * 16]);
const int a3 = (in[0 * 16] - in[2 * 16]);
tmp[0 + i * 4] = a0 + a1; // 14b
tmp[1 + i * 4] = a3 + a2;
tmp[2 + i * 4] = a3 - a2;
tmp[3 + i * 4] = a0 - a1;
}
for (i = 0; i < 4; ++i) {
const int a0 = (tmp[0 + i] + tmp[8 + i]);
const int a0 = (tmp[0 + i] + tmp[8 + i]); // 15b
const int a1 = (tmp[4 + i] + tmp[12+ i]);
const int a2 = (tmp[4 + i] - tmp[12+ i]);
const int a3 = (tmp[0 + i] - tmp[8 + i]);
const int b0 = a0 + a1;
const int b0 = a0 + a1; // 16b
const int b1 = a3 + a2;
const int b2 = a3 - a2;
const int b3 = a0 - a1;
out[ 0 + i] = (b0 + (b0 > 0) + 3) >> 3;
out[ 4 + i] = (b1 + (b1 > 0) + 3) >> 3;
out[ 8 + i] = (b2 + (b2 > 0) + 3) >> 3;
out[12 + i] = (b3 + (b3 > 0) + 3) >> 3;
out[ 0 + i] = b0 >> 1; // 15b
out[ 4 + i] = b1 >> 1;
out[ 8 + i] = b2 >> 1;
out[12 + i] = b3 >> 1;
}
}
@ -241,14 +224,15 @@ static void FTransformWHT(const int16_t* in, int16_t* out) {
#define DST(x, y) dst[(x) + (y) * BPS]
static inline void Fill(uint8_t* dst, int value, int size) {
static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) {
int j;
for (j = 0; j < size; ++j) {
memset(dst + j * BPS, value, size);
}
}
static inline void VerticalPred(uint8_t* dst, const uint8_t* top, int size) {
static WEBP_INLINE void VerticalPred(uint8_t* dst,
const uint8_t* top, int size) {
int j;
if (top) {
for (j = 0; j < size; ++j) memcpy(dst + j * BPS, top, size);
@ -257,7 +241,8 @@ static inline void VerticalPred(uint8_t* dst, const uint8_t* top, int size) {
}
}
static inline void HorizontalPred(uint8_t* dst, const uint8_t* left, int size) {
static WEBP_INLINE void HorizontalPred(uint8_t* dst,
const uint8_t* left, int size) {
if (left) {
int j;
for (j = 0; j < size; ++j) {
@ -268,8 +253,8 @@ static inline void HorizontalPred(uint8_t* dst, const uint8_t* left, int size) {
}
}
static inline void TrueMotion(uint8_t* dst, const uint8_t* left,
const uint8_t* top, int size) {
static WEBP_INLINE void TrueMotion(uint8_t* dst, const uint8_t* left,
const uint8_t* top, int size) {
int y;
if (left) {
if (top) {
@ -298,9 +283,9 @@ static inline void TrueMotion(uint8_t* dst, const uint8_t* left,
}
}
static inline void DCMode(uint8_t* dst, const uint8_t* left,
const uint8_t* top,
int size, int round, int shift) {
static WEBP_INLINE void DCMode(uint8_t* dst, const uint8_t* left,
const uint8_t* top,
int size, int round, int shift) {
int DC = 0;
int j;
if (top) {
@ -543,7 +528,8 @@ static void Intra4Preds(uint8_t* dst, const uint8_t* top) {
//------------------------------------------------------------------------------
// Metric
static inline int GetSSE(const uint8_t* a, const uint8_t* b, int w, int h) {
static WEBP_INLINE int GetSSE(const uint8_t* a, const uint8_t* b,
int w, int h) {
int count = 0;
int y, x;
for (y = 0; y < h; ++y) {
@ -584,30 +570,30 @@ static int TTransform(const uint8_t* in, const uint16_t* w) {
int i;
// horizontal pass
for (i = 0; i < 4; ++i, in += BPS) {
const int a0 = (in[0] + in[2]) << 2;
const int a1 = (in[1] + in[3]) << 2;
const int a2 = (in[1] - in[3]) << 2;
const int a3 = (in[0] - in[2]) << 2;
tmp[0 + i * 4] = a0 + a1 + (a0 != 0);
const int a0 = in[0] + in[2];
const int a1 = in[1] + in[3];
const int a2 = in[1] - in[3];
const int a3 = in[0] - in[2];
tmp[0 + i * 4] = a0 + a1;
tmp[1 + i * 4] = a3 + a2;
tmp[2 + i * 4] = a3 - a2;
tmp[3 + i * 4] = a0 - a1;
}
// vertical pass
for (i = 0; i < 4; ++i, ++w) {
const int a0 = (tmp[0 + i] + tmp[8 + i]);
const int a1 = (tmp[4 + i] + tmp[12+ i]);
const int a2 = (tmp[4 + i] - tmp[12+ i]);
const int a3 = (tmp[0 + i] - tmp[8 + i]);
const int a0 = tmp[0 + i] + tmp[8 + i];
const int a1 = tmp[4 + i] + tmp[12+ i];
const int a2 = tmp[4 + i] - tmp[12+ i];
const int a3 = tmp[0 + i] - tmp[8 + i];
const int b0 = a0 + a1;
const int b1 = a3 + a2;
const int b2 = a3 - a2;
const int b3 = a0 - a1;
// abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3
sum += w[ 0] * ((abs(b0) + 3) >> 3);
sum += w[ 4] * ((abs(b1) + 3) >> 3);
sum += w[ 8] * ((abs(b2) + 3) >> 3);
sum += w[12] * ((abs(b3) + 3) >> 3);
sum += w[ 0] * abs(b0);
sum += w[ 4] * abs(b1);
sum += w[ 8] * abs(b2);
sum += w[12] * abs(b3);
}
return sum;
}
@ -616,7 +602,7 @@ 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) + 8) >> 4;
return abs(sum2 - sum1) >> 5;
}
static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
@ -646,13 +632,38 @@ static int QuantizeBlock(int16_t in[16], int16_t out[16],
for (; n < 16; ++n) {
const int j = kZigzag[n];
const int sign = (in[j] < 0);
int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
if (coeff > 2047) coeff = 2047;
const int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
if (coeff > mtx->zthresh_[j]) {
const int Q = mtx->q_[j];
const int iQ = mtx->iq_[j];
const int B = mtx->bias_[j];
out[n] = QUANTDIV(coeff, iQ, B);
if (out[n] > MAX_LEVEL) out[n] = MAX_LEVEL;
if (sign) out[n] = -out[n];
in[j] = out[n] * Q;
if (out[n]) last = n;
} else {
out[n] = 0;
in[j] = 0;
}
}
return (last >= 0);
}
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 int coeff = sign ? -in[j] : in[j];
assert(mtx->sharpen_[j] == 0);
if (coeff > mtx->zthresh_[j]) {
const int Q = mtx->q_[j];
const int iQ = mtx->iq_[j];
const int B = mtx->bias_[j];
out[n] = QUANTDIV(coeff, iQ, B);
if (out[n] > MAX_LEVEL) out[n] = MAX_LEVEL;
if (sign) out[n] = -out[n];
in[j] = out[n] * Q;
if (out[n]) last = n;
@ -667,7 +678,7 @@ static int QuantizeBlock(int16_t in[16], int16_t out[16],
//------------------------------------------------------------------------------
// Block copy
static inline void Copy(const uint8_t* src, uint8_t* dst, int size) {
static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int size) {
int y;
for (y = 0; y < size; ++y) {
memcpy(dst, src, size);
@ -677,8 +688,6 @@ static inline void Copy(const uint8_t* src, uint8_t* dst, int size) {
}
static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); }
static void Copy8x8(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 8); }
static void Copy16x16(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 16); }
//------------------------------------------------------------------------------
// Initialization
@ -700,11 +709,11 @@ VP8Metric VP8SSE4x4;
VP8WMetric VP8TDisto4x4;
VP8WMetric VP8TDisto16x16;
VP8QuantizeBlock VP8EncQuantizeBlock;
VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT;
VP8BlockCopy VP8Copy4x4;
VP8BlockCopy VP8Copy8x8;
VP8BlockCopy VP8Copy16x16;
extern void VP8EncDspInitSSE2(void);
extern void VP8EncDspInitNEON(void);
void VP8EncDspInit(void) {
InitTables();
@ -725,20 +734,20 @@ void VP8EncDspInit(void) {
VP8TDisto4x4 = Disto4x4;
VP8TDisto16x16 = Disto16x16;
VP8EncQuantizeBlock = QuantizeBlock;
VP8EncQuantizeBlockWHT = QuantizeBlockWHT;
VP8Copy4x4 = Copy4x4;
VP8Copy8x8 = Copy8x8;
VP8Copy16x16 = Copy16x16;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo) {
#if defined(__SSE2__) || defined(_MSC_VER)
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8EncDspInitSSE2();
}
#elif defined(WEBP_USE_NEON)
if (VP8GetCPUInfo(kNEON)) {
VP8EncDspInitNEON();
}
#endif
}
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

632
src/dsp/enc_neon.c Normal file
View File

@ -0,0 +1,632 @@
// 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.
// -----------------------------------------------------------------------------
//
// ARM NEON version of speed-critical encoding functions.
//
// adapted from libvpx (http://www.webmproject.org/code/)
#include "./dsp.h"
#if defined(WEBP_USE_NEON)
#include "../enc/vp8enci.h"
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
// Inverse transform.
// This code is pretty much the same as TransformOneNEON in the decoder, except
// for subtraction to *ref. See the comments there for algorithmic explanations.
static void ITransformOne(const uint8_t* ref,
const int16_t* in, uint8_t* dst) {
const int kBPS = BPS;
const int16_t kC1C2[] = { 20091, 17734, 0, 0 }; // kC1 / (kC2 >> 1) / 0 / 0
__asm__ volatile (
"vld1.16 {q1, q2}, [%[in]] \n"
"vld1.16 {d0}, [%[kC1C2]] \n"
// d2: in[0]
// d3: in[8]
// d4: in[4]
// d5: in[12]
"vswp d3, d4 \n"
// q8 = {in[4], in[12]} * kC1 * 2 >> 16
// q9 = {in[4], in[12]} * kC2 >> 16
"vqdmulh.s16 q8, q2, d0[0] \n"
"vqdmulh.s16 q9, q2, d0[1] \n"
// d22 = a = in[0] + in[8]
// d23 = b = in[0] - in[8]
"vqadd.s16 d22, d2, d3 \n"
"vqsub.s16 d23, d2, d3 \n"
// q8 = in[4]/[12] * kC1 >> 16
"vshr.s16 q8, q8, #1 \n"
// Add {in[4], in[12]} back after the multiplication.
"vqadd.s16 q8, q2, q8 \n"
// d20 = c = in[4]*kC2 - in[12]*kC1
// d21 = d = in[4]*kC1 + in[12]*kC2
"vqsub.s16 d20, d18, d17 \n"
"vqadd.s16 d21, d19, d16 \n"
// d2 = tmp[0] = a + d
// d3 = tmp[1] = b + c
// d4 = tmp[2] = b - c
// d5 = tmp[3] = a - d
"vqadd.s16 d2, d22, d21 \n"
"vqadd.s16 d3, d23, d20 \n"
"vqsub.s16 d4, d23, d20 \n"
"vqsub.s16 d5, d22, d21 \n"
"vzip.16 q1, q2 \n"
"vzip.16 q1, q2 \n"
"vswp d3, d4 \n"
// q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16
// q9 = {tmp[4], tmp[12]} * kC2 >> 16
"vqdmulh.s16 q8, q2, d0[0] \n"
"vqdmulh.s16 q9, q2, d0[1] \n"
// d22 = a = tmp[0] + tmp[8]
// d23 = b = tmp[0] - tmp[8]
"vqadd.s16 d22, d2, d3 \n"
"vqsub.s16 d23, d2, d3 \n"
"vshr.s16 q8, q8, #1 \n"
"vqadd.s16 q8, q2, q8 \n"
// d20 = c = in[4]*kC2 - in[12]*kC1
// d21 = d = in[4]*kC1 + in[12]*kC2
"vqsub.s16 d20, d18, d17 \n"
"vqadd.s16 d21, d19, d16 \n"
// d2 = tmp[0] = a + d
// d3 = tmp[1] = b + c
// d4 = tmp[2] = b - c
// d5 = tmp[3] = a - d
"vqadd.s16 d2, d22, d21 \n"
"vqadd.s16 d3, d23, d20 \n"
"vqsub.s16 d4, d23, d20 \n"
"vqsub.s16 d5, d22, d21 \n"
"vld1.32 d6[0], [%[ref]], %[kBPS] \n"
"vld1.32 d6[1], [%[ref]], %[kBPS] \n"
"vld1.32 d7[0], [%[ref]], %[kBPS] \n"
"vld1.32 d7[1], [%[ref]], %[kBPS] \n"
"sub %[ref], %[ref], %[kBPS], lsl #2 \n"
// (val) + 4 >> 3
"vrshr.s16 d2, d2, #3 \n"
"vrshr.s16 d3, d3, #3 \n"
"vrshr.s16 d4, d4, #3 \n"
"vrshr.s16 d5, d5, #3 \n"
"vzip.16 q1, q2 \n"
"vzip.16 q1, q2 \n"
// Must accumulate before saturating
"vmovl.u8 q8, d6 \n"
"vmovl.u8 q9, d7 \n"
"vqadd.s16 q1, q1, q8 \n"
"vqadd.s16 q2, q2, q9 \n"
"vqmovun.s16 d0, q1 \n"
"vqmovun.s16 d1, q2 \n"
"vst1.32 d0[0], [%[dst]], %[kBPS] \n"
"vst1.32 d0[1], [%[dst]], %[kBPS] \n"
"vst1.32 d1[0], [%[dst]], %[kBPS] \n"
"vst1.32 d1[1], [%[dst]] \n"
: [in] "+r"(in), [dst] "+r"(dst) // modified registers
: [kBPS] "r"(kBPS), [kC1C2] "r"(kC1C2), [ref] "r"(ref) // constants
: "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" // clobbered
);
}
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);
}
}
// Same code as dec_neon.c
static void ITransformWHT(const int16_t* in, int16_t* out) {
const int kStep = 32; // The store is only incrementing the pointer as if we
// had stored a single byte.
__asm__ volatile (
// part 1
// load data into q0, q1
"vld1.16 {q0, q1}, [%[in]] \n"
"vaddl.s16 q2, d0, d3 \n" // a0 = in[0] + in[12]
"vaddl.s16 q3, d1, d2 \n" // a1 = in[4] + in[8]
"vsubl.s16 q4, d1, d2 \n" // a2 = in[4] - in[8]
"vsubl.s16 q5, d0, d3 \n" // a3 = in[0] - in[12]
"vadd.s32 q0, q2, q3 \n" // tmp[0] = a0 + a1
"vsub.s32 q2, q2, q3 \n" // tmp[8] = a0 - a1
"vadd.s32 q1, q5, q4 \n" // tmp[4] = a3 + a2
"vsub.s32 q3, q5, q4 \n" // tmp[12] = a3 - a2
// Transpose
// q0 = tmp[0, 4, 8, 12], q1 = tmp[2, 6, 10, 14]
// q2 = tmp[1, 5, 9, 13], q3 = tmp[3, 7, 11, 15]
"vswp d1, d4 \n" // vtrn.64 q0, q2
"vswp d3, d6 \n" // vtrn.64 q1, q3
"vtrn.32 q0, q1 \n"
"vtrn.32 q2, q3 \n"
"vmov.s32 q4, #3 \n" // dc = 3
"vadd.s32 q0, q0, q4 \n" // dc = tmp[0] + 3
"vadd.s32 q6, q0, q3 \n" // a0 = dc + tmp[3]
"vadd.s32 q7, q1, q2 \n" // a1 = tmp[1] + tmp[2]
"vsub.s32 q8, q1, q2 \n" // a2 = tmp[1] - tmp[2]
"vsub.s32 q9, q0, q3 \n" // a3 = dc - tmp[3]
"vadd.s32 q0, q6, q7 \n"
"vshrn.s32 d0, q0, #3 \n" // (a0 + a1) >> 3
"vadd.s32 q1, q9, q8 \n"
"vshrn.s32 d1, q1, #3 \n" // (a3 + a2) >> 3
"vsub.s32 q2, q6, q7 \n"
"vshrn.s32 d2, q2, #3 \n" // (a0 - a1) >> 3
"vsub.s32 q3, q9, q8 \n"
"vshrn.s32 d3, q3, #3 \n" // (a3 - a2) >> 3
// set the results to output
"vst1.16 d0[0], [%[out]], %[kStep] \n"
"vst1.16 d1[0], [%[out]], %[kStep] \n"
"vst1.16 d2[0], [%[out]], %[kStep] \n"
"vst1.16 d3[0], [%[out]], %[kStep] \n"
"vst1.16 d0[1], [%[out]], %[kStep] \n"
"vst1.16 d1[1], [%[out]], %[kStep] \n"
"vst1.16 d2[1], [%[out]], %[kStep] \n"
"vst1.16 d3[1], [%[out]], %[kStep] \n"
"vst1.16 d0[2], [%[out]], %[kStep] \n"
"vst1.16 d1[2], [%[out]], %[kStep] \n"
"vst1.16 d2[2], [%[out]], %[kStep] \n"
"vst1.16 d3[2], [%[out]], %[kStep] \n"
"vst1.16 d0[3], [%[out]], %[kStep] \n"
"vst1.16 d1[3], [%[out]], %[kStep] \n"
"vst1.16 d2[3], [%[out]], %[kStep] \n"
"vst1.16 d3[3], [%[out]], %[kStep] \n"
: [out] "+r"(out) // modified registers
: [in] "r"(in), [kStep] "r"(kStep) // constants
: "memory", "q0", "q1", "q2", "q3", "q4",
"q5", "q6", "q7", "q8", "q9" // clobbered
);
}
// Forward transform.
// adapted from vp8/encoder/arm/neon/shortfdct_neon.asm
static const int16_t kCoeff16[] = {
5352, 5352, 5352, 5352, 2217, 2217, 2217, 2217
};
static const int32_t kCoeff32[] = {
1812, 1812, 1812, 1812,
937, 937, 937, 937,
12000, 12000, 12000, 12000,
51000, 51000, 51000, 51000
};
static void FTransform(const uint8_t* src, const uint8_t* ref,
int16_t* out) {
const int kBPS = BPS;
const uint8_t* src_ptr = src;
const uint8_t* ref_ptr = ref;
const int16_t* coeff16 = kCoeff16;
const int32_t* coeff32 = kCoeff32;
__asm__ volatile (
// load src into q4, q5 in high half
"vld1.8 {d8}, [%[src_ptr]], %[kBPS] \n"
"vld1.8 {d10}, [%[src_ptr]], %[kBPS] \n"
"vld1.8 {d9}, [%[src_ptr]], %[kBPS] \n"
"vld1.8 {d11}, [%[src_ptr]] \n"
// load ref into q6, q7 in high half
"vld1.8 {d12}, [%[ref_ptr]], %[kBPS] \n"
"vld1.8 {d14}, [%[ref_ptr]], %[kBPS] \n"
"vld1.8 {d13}, [%[ref_ptr]], %[kBPS] \n"
"vld1.8 {d15}, [%[ref_ptr]] \n"
// Pack the high values in to q4 and q6
"vtrn.32 q4, q5 \n"
"vtrn.32 q6, q7 \n"
// d[0-3] = src - ref
"vsubl.u8 q0, d8, d12 \n"
"vsubl.u8 q1, d9, d13 \n"
// load coeff16 into q8(d16=5352, d17=2217)
"vld1.16 {q8}, [%[coeff16]] \n"
// load coeff32 high half into q9 = 1812, q10 = 937
"vld1.32 {q9, q10}, [%[coeff32]]! \n"
// load coeff32 low half into q11=12000, q12=51000
"vld1.32 {q11,q12}, [%[coeff32]] \n"
// part 1
// Transpose. Register dN is the same as dN in C
"vtrn.32 d0, d2 \n"
"vtrn.32 d1, d3 \n"
"vtrn.16 d0, d1 \n"
"vtrn.16 d2, d3 \n"
"vadd.s16 d4, d0, d3 \n" // a0 = d0 + d3
"vadd.s16 d5, d1, d2 \n" // a1 = d1 + d2
"vsub.s16 d6, d1, d2 \n" // a2 = d1 - d2
"vsub.s16 d7, d0, d3 \n" // a3 = d0 - d3
"vadd.s16 d0, d4, d5 \n" // a0 + a1
"vshl.s16 d0, d0, #3 \n" // temp[0+i*4] = (a0+a1) << 3
"vsub.s16 d2, d4, d5 \n" // a0 - a1
"vshl.s16 d2, d2, #3 \n" // (temp[2+i*4] = (a0-a1) << 3
"vmlal.s16 q9, d7, d16 \n" // a3*5352 + 1812
"vmlal.s16 q10, d7, d17 \n" // a3*2217 + 937
"vmlal.s16 q9, d6, d17 \n" // a2*2217 + a3*5352 + 1812
"vmlsl.s16 q10, d6, d16 \n" // a3*2217 + 937 - a2*5352
// temp[1+i*4] = (d2*2217 + d3*5352 + 1812) >> 9
// temp[3+i*4] = (d3*2217 + 937 - d2*5352) >> 9
"vshrn.s32 d1, q9, #9 \n"
"vshrn.s32 d3, q10, #9 \n"
// part 2
// transpose d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12]
"vtrn.32 d0, d2 \n"
"vtrn.32 d1, d3 \n"
"vtrn.16 d0, d1 \n"
"vtrn.16 d2, d3 \n"
"vmov.s16 d26, #7 \n"
"vadd.s16 d4, d0, d3 \n" // a1 = ip[0] + ip[12]
"vadd.s16 d5, d1, d2 \n" // b1 = ip[4] + ip[8]
"vsub.s16 d6, d1, d2 \n" // c1 = ip[4] - ip[8]
"vadd.s16 d4, d4, d26 \n" // a1 + 7
"vsub.s16 d7, d0, d3 \n" // d1 = ip[0] - ip[12]
"vadd.s16 d0, d4, d5 \n" // op[0] = a1 + b1 + 7
"vsub.s16 d2, d4, d5 \n" // op[8] = a1 - b1 + 7
"vmlal.s16 q11, d7, d16 \n" // d1*5352 + 12000
"vmlal.s16 q12, d7, d17 \n" // d1*2217 + 51000
"vceq.s16 d4, d7, #0 \n"
"vshr.s16 d0, d0, #4 \n"
"vshr.s16 d2, d2, #4 \n"
"vmlal.s16 q11, d6, d17 \n" // c1*2217 + d1*5352 + 12000
"vmlsl.s16 q12, d6, d16 \n" // d1*2217 - c1*5352 + 51000
"vmvn d4, d4 \n" // !(d1 == 0)
// op[4] = (c1*2217 + d1*5352 + 12000)>>16
"vshrn.s32 d1, q11, #16 \n"
// op[4] += (d1!=0)
"vsub.s16 d1, d1, d4 \n"
// op[12]= (d1*2217 - c1*5352 + 51000)>>16
"vshrn.s32 d3, q12, #16 \n"
// set result to out array
"vst1.16 {q0, q1}, [%[out]] \n"
: [src_ptr] "+r"(src_ptr), [ref_ptr] "+r"(ref_ptr),
[coeff32] "+r"(coeff32) // modified registers
: [kBPS] "r"(kBPS), [coeff16] "r"(coeff16),
[out] "r"(out) // constants
: "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
"q10", "q11", "q12", "q13" // clobbered
);
}
static void FTransformWHT(const int16_t* in, int16_t* out) {
const int kStep = 32;
__asm__ volatile (
// d0 = in[0 * 16] , d1 = in[1 * 16]
// d2 = in[2 * 16] , d3 = in[3 * 16]
"vld1.16 d0[0], [%[in]], %[kStep] \n"
"vld1.16 d1[0], [%[in]], %[kStep] \n"
"vld1.16 d2[0], [%[in]], %[kStep] \n"
"vld1.16 d3[0], [%[in]], %[kStep] \n"
"vld1.16 d0[1], [%[in]], %[kStep] \n"
"vld1.16 d1[1], [%[in]], %[kStep] \n"
"vld1.16 d2[1], [%[in]], %[kStep] \n"
"vld1.16 d3[1], [%[in]], %[kStep] \n"
"vld1.16 d0[2], [%[in]], %[kStep] \n"
"vld1.16 d1[2], [%[in]], %[kStep] \n"
"vld1.16 d2[2], [%[in]], %[kStep] \n"
"vld1.16 d3[2], [%[in]], %[kStep] \n"
"vld1.16 d0[3], [%[in]], %[kStep] \n"
"vld1.16 d1[3], [%[in]], %[kStep] \n"
"vld1.16 d2[3], [%[in]], %[kStep] \n"
"vld1.16 d3[3], [%[in]], %[kStep] \n"
"vaddl.s16 q2, d0, d2 \n" // a0=(in[0*16]+in[2*16])
"vaddl.s16 q3, d1, d3 \n" // a1=(in[1*16]+in[3*16])
"vsubl.s16 q4, d1, d3 \n" // a2=(in[1*16]-in[3*16])
"vsubl.s16 q5, d0, d2 \n" // a3=(in[0*16]-in[2*16])
"vqadd.s32 q6, q2, q3 \n" // a0 + a1
"vqadd.s32 q7, q5, q4 \n" // a3 + a2
"vqsub.s32 q8, q5, q4 \n" // a3 - a2
"vqsub.s32 q9, q2, q3 \n" // a0 - a1
// Transpose
// q6 = tmp[0, 1, 2, 3] ; q7 = tmp[ 4, 5, 6, 7]
// q8 = tmp[8, 9, 10, 11] ; q9 = tmp[12, 13, 14, 15]
"vswp d13, d16 \n" // vtrn.64 q0, q2
"vswp d15, d18 \n" // vtrn.64 q1, q3
"vtrn.32 q6, q7 \n"
"vtrn.32 q8, q9 \n"
"vqadd.s32 q0, q6, q8 \n" // a0 = tmp[0] + tmp[8]
"vqadd.s32 q1, q7, q9 \n" // a1 = tmp[4] + tmp[12]
"vqsub.s32 q2, q7, q9 \n" // a2 = tmp[4] - tmp[12]
"vqsub.s32 q3, q6, q8 \n" // a3 = tmp[0] - tmp[8]
"vqadd.s32 q4, q0, q1 \n" // b0 = a0 + a1
"vqadd.s32 q5, q3, q2 \n" // b1 = a3 + a2
"vqsub.s32 q6, q3, q2 \n" // b2 = a3 - a2
"vqsub.s32 q7, q0, q1 \n" // b3 = a0 - a1
"vshrn.s32 d18, q4, #1 \n" // b0 >> 1
"vshrn.s32 d19, q5, #1 \n" // b1 >> 1
"vshrn.s32 d20, q6, #1 \n" // b2 >> 1
"vshrn.s32 d21, q7, #1 \n" // b3 >> 1
"vst1.16 {q9, q10}, [%[out]] \n"
: [in] "+r"(in)
: [kStep] "r"(kStep), [out] "r"(out)
: "memory", "q0", "q1", "q2", "q3", "q4", "q5",
"q6", "q7", "q8", "q9", "q10" // clobbered
) ;
}
//------------------------------------------------------------------------------
// Texture distortion
//
// We try to match the spectral content (weighted) between source and
// reconstructed samples.
// Hadamard transform
// Returns the weighted sum of the absolute value of transformed coefficients.
// This uses a TTransform helper function in C
static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
const uint16_t* const w) {
const int kBPS = BPS;
const uint8_t* A = a;
const uint8_t* B = b;
const uint16_t* W = w;
int sum;
__asm__ volatile (
"vld1.32 d0[0], [%[a]], %[kBPS] \n"
"vld1.32 d0[1], [%[a]], %[kBPS] \n"
"vld1.32 d2[0], [%[a]], %[kBPS] \n"
"vld1.32 d2[1], [%[a]] \n"
"vld1.32 d1[0], [%[b]], %[kBPS] \n"
"vld1.32 d1[1], [%[b]], %[kBPS] \n"
"vld1.32 d3[0], [%[b]], %[kBPS] \n"
"vld1.32 d3[1], [%[b]] \n"
// a d0/d2, b d1/d3
// d0/d1: 01 01 01 01
// d2/d3: 23 23 23 23
// But: it goes 01 45 23 67
// Notice the middle values are transposed
"vtrn.16 q0, q1 \n"
// {a0, a1} = {in[0] + in[2], in[1] + in[3]}
"vaddl.u8 q2, d0, d2 \n"
"vaddl.u8 q10, d1, d3 \n"
// {a3, a2} = {in[0] - in[2], in[1] - in[3]}
"vsubl.u8 q3, d0, d2 \n"
"vsubl.u8 q11, d1, d3 \n"
// tmp[0] = a0 + a1
"vpaddl.s16 q0, q2 \n"
"vpaddl.s16 q8, q10 \n"
// tmp[1] = a3 + a2
"vpaddl.s16 q1, q3 \n"
"vpaddl.s16 q9, q11 \n"
// No pair subtract
// q2 = {a0, a3}
// q3 = {a1, a2}
"vtrn.16 q2, q3 \n"
"vtrn.16 q10, q11 \n"
// {tmp[3], tmp[2]} = {a0 - a1, a3 - a2}
"vsubl.s16 q12, d4, d6 \n"
"vsubl.s16 q13, d5, d7 \n"
"vsubl.s16 q14, d20, d22 \n"
"vsubl.s16 q15, d21, d23 \n"
// separate tmp[3] and tmp[2]
// q12 = tmp[3]
// q13 = tmp[2]
"vtrn.32 q12, q13 \n"
"vtrn.32 q14, q15 \n"
// Transpose tmp for a
"vswp d1, d26 \n" // vtrn.64
"vswp d3, d24 \n" // vtrn.64
"vtrn.32 q0, q1 \n"
"vtrn.32 q13, q12 \n"
// Transpose tmp for b
"vswp d17, d30 \n" // vtrn.64
"vswp d19, d28 \n" // vtrn.64
"vtrn.32 q8, q9 \n"
"vtrn.32 q15, q14 \n"
// The first Q register is a, the second b.
// q0/8 tmp[0-3]
// q13/15 tmp[4-7]
// q1/9 tmp[8-11]
// q12/14 tmp[12-15]
// These are still in 01 45 23 67 order. We fix it easily in the addition
// case but the subtraction propagates them.
"vswp d3, d27 \n"
"vswp d19, d31 \n"
// a0 = tmp[0] + tmp[8]
"vadd.s32 q2, q0, q1 \n"
"vadd.s32 q3, q8, q9 \n"
// a1 = tmp[4] + tmp[12]
"vadd.s32 q10, q13, q12 \n"
"vadd.s32 q11, q15, q14 \n"
// a2 = tmp[4] - tmp[12]
"vsub.s32 q13, q13, q12 \n"
"vsub.s32 q15, q15, q14 \n"
// a3 = tmp[0] - tmp[8]
"vsub.s32 q0, q0, q1 \n"
"vsub.s32 q8, q8, q9 \n"
// b0 = a0 + a1
"vadd.s32 q1, q2, q10 \n"
"vadd.s32 q9, q3, q11 \n"
// b1 = a3 + a2
"vadd.s32 q12, q0, q13 \n"
"vadd.s32 q14, q8, q15 \n"
// b2 = a3 - a2
"vsub.s32 q0, q0, q13 \n"
"vsub.s32 q8, q8, q15 \n"
// b3 = a0 - a1
"vsub.s32 q2, q2, q10 \n"
"vsub.s32 q3, q3, q11 \n"
"vld1.64 {q10, q11}, [%[w]] \n"
// abs(b0)
"vabs.s32 q1, q1 \n"
"vabs.s32 q9, q9 \n"
// abs(b1)
"vabs.s32 q12, q12 \n"
"vabs.s32 q14, q14 \n"
// abs(b2)
"vabs.s32 q0, q0 \n"
"vabs.s32 q8, q8 \n"
// abs(b3)
"vabs.s32 q2, q2 \n"
"vabs.s32 q3, q3 \n"
// expand w before using.
"vmovl.u16 q13, d20 \n"
"vmovl.u16 q15, d21 \n"
// w[0] * abs(b0)
"vmul.u32 q1, q1, q13 \n"
"vmul.u32 q9, q9, q13 \n"
// w[4] * abs(b1)
"vmla.u32 q1, q12, q15 \n"
"vmla.u32 q9, q14, q15 \n"
// expand w before using.
"vmovl.u16 q13, d22 \n"
"vmovl.u16 q15, d23 \n"
// w[8] * abs(b1)
"vmla.u32 q1, q0, q13 \n"
"vmla.u32 q9, q8, q13 \n"
// w[12] * abs(b1)
"vmla.u32 q1, q2, q15 \n"
"vmla.u32 q9, q3, q15 \n"
// Sum the arrays
"vpaddl.u32 q1, q1 \n"
"vpaddl.u32 q9, q9 \n"
"vadd.u64 d2, d3 \n"
"vadd.u64 d18, d19 \n"
// Hadamard transform needs 4 bits of extra precision (2 bits in each
// direction) for dynamic raw. Weights w[] are 16bits at max, so the maximum
// precision for coeff is 8bit of input + 4bits of Hadamard transform +
// 16bits for w[] + 2 bits of abs() summation.
//
// This uses a maximum of 31 bits (signed). Discarding the top 32 bits is
// A-OK.
// sum2 - sum1
"vsub.u32 d0, d2, d18 \n"
// abs(sum2 - sum1)
"vabs.s32 d0, d0 \n"
// abs(sum2 - sum1) >> 5
"vshr.u32 d0, #5 \n"
// It would be better to move the value straight into r0 but I'm not
// entirely sure how this works with inline assembly.
"vmov.32 %[sum], d0[0] \n"
: [sum] "=r"(sum), [a] "+r"(A), [b] "+r"(B), [w] "+r"(W)
: [kBPS] "r"(kBPS)
: "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
"q10", "q11", "q12", "q13", "q14", "q15" // clobbered
) ;
return sum;
}
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;
}
#endif // WEBP_USE_NEON
//------------------------------------------------------------------------------
// Entry point
extern void VP8EncDspInitNEON(void);
void VP8EncDspInitNEON(void) {
#if defined(WEBP_USE_NEON)
VP8ITransform = ITransform;
VP8FTransform = FTransform;
VP8ITransformWHT = ITransformWHT;
VP8FTransformWHT = FTransformWHT;
VP8TDisto4x4 = Disto4x4;
VP8TDisto16x16 = Disto16x16;
#endif // WEBP_USE_NEON
}

View File

@ -1,34 +1,66 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// SSE2 version of speed-critical encoding functions.
//
// Author: Christian Duvivier (cduvivier@google.com)
#if defined(__SSE2__) || defined(_MSC_VER)
#include "./dsp.h"
#if defined(WEBP_USE_SSE2)
#include <stdlib.h> // for abs()
#include <emmintrin.h>
#include "../enc/vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
//------------------------------------------------------------------------------
// Quite useful macro for debugging. Left here for convenience.
#if 0
#include <stdio.h>
static void PrintReg(const __m128i r, const char* const name, int size) {
int n;
union {
__m128i r;
uint8_t i8[16];
uint16_t i16[8];
uint32_t i32[4];
uint64_t i64[2];
} tmp;
tmp.r = r;
printf("%s\t: ", name);
if (size == 8) {
for (n = 0; n < 16; ++n) printf("%.2x ", tmp.i8[n]);
} else if (size == 16) {
for (n = 0; n < 8; ++n) printf("%.4x ", tmp.i16[n]);
} else if (size == 32) {
for (n = 0; n < 4; ++n) printf("%.8x ", tmp.i32[n]);
} else {
for (n = 0; n < 2; ++n) printf("%.16lx ", tmp.i64[n]);
}
printf("\n");
}
#endif
//------------------------------------------------------------------------------
// Compute susceptibility based on DCT-coeff histograms:
// the higher, the "easier" the macroblock is to compress.
static int CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
int start_block, int end_block) {
int histo[MAX_COEFF_THRESH + 1] = { 0 };
int16_t out[16];
int j, k;
static void CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
int start_block, int end_block,
VP8Histogram* const histo) {
const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH);
int j;
for (j = start_block; j < end_block; ++j) {
int16_t out[16];
int k;
VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
// Convert coefficients to bin (within out[]).
@ -44,9 +76,9 @@ static int CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
const __m128i xor1 = _mm_xor_si128(out1, sign1);
const __m128i abs0 = _mm_sub_epi16(xor0, sign0);
const __m128i abs1 = _mm_sub_epi16(xor1, sign1);
// v = abs(out) >> 2
const __m128i v0 = _mm_srai_epi16(abs0, 2);
const __m128i v1 = _mm_srai_epi16(abs1, 2);
// v = abs(out) >> 3
const __m128i v0 = _mm_srai_epi16(abs0, 3);
const __m128i v1 = _mm_srai_epi16(abs1, 3);
// bin = min(v, MAX_COEFF_THRESH)
const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh);
const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh);
@ -55,13 +87,11 @@ static int CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
_mm_storeu_si128((__m128i*)&out[8], bin1);
}
// Use bin to update histogram.
// Convert coefficients to bin.
for (k = 0; k < 16; ++k) {
histo[out[k]]++;
histo->distribution[out[k]]++;
}
}
return VP8GetAlpha(histo);
}
//------------------------------------------------------------------------------
@ -240,7 +270,7 @@ static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
// Add inverse transform to 'ref' and store.
{
const __m128i zero = _mm_set1_epi16(0);
const __m128i zero = _mm_setzero_si128();
// Load the reference(s).
__m128i ref0, ref1, ref2, ref3;
if (do_two) {
@ -292,17 +322,23 @@ static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
int16_t* out) {
const __m128i zero = _mm_setzero_si128();
const __m128i seven = _mm_set1_epi16(7);
const __m128i k7500 = _mm_set1_epi32(7500);
const __m128i k14500 = _mm_set1_epi32(14500);
const __m128i k937 = _mm_set1_epi32(937);
const __m128i k1812 = _mm_set1_epi32(1812);
const __m128i k51000 = _mm_set1_epi32(51000);
const __m128i k12000_plus_one = _mm_set1_epi32(12000 + (1 << 16));
const __m128i k5352_2217 = _mm_set_epi16(5352, 2217, 5352, 2217,
5352, 2217, 5352, 2217);
const __m128i k2217_5352 = _mm_set_epi16(2217, -5352, 2217, -5352,
2217, -5352, 2217, -5352);
const __m128i k88p = _mm_set_epi16(8, 8, 8, 8, 8, 8, 8, 8);
const __m128i k88m = _mm_set_epi16(-8, 8, -8, 8, -8, 8, -8, 8);
const __m128i k5352_2217p = _mm_set_epi16(2217, 5352, 2217, 5352,
2217, 5352, 2217, 5352);
const __m128i k5352_2217m = _mm_set_epi16(-5352, 2217, -5352, 2217,
-5352, 2217, -5352, 2217);
__m128i v01, v32;
// Difference between src and ref and initial transpose.
{
// Load src and convert to 16b.
@ -323,73 +359,52 @@ static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero);
const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero);
const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero);
// Compute difference.
// Compute difference. -> 00 01 02 03 00 00 00 00
const __m128i diff0 = _mm_sub_epi16(src_0, ref_0);
const __m128i diff1 = _mm_sub_epi16(src_1, ref_1);
const __m128i diff2 = _mm_sub_epi16(src_2, ref_2);
const __m128i diff3 = _mm_sub_epi16(src_3, ref_3);
// Transpose.
// Unpack and shuffle
// 00 01 02 03 0 0 0 0
// 10 11 12 13 0 0 0 0
// 20 21 22 23 0 0 0 0
// 30 31 32 33 0 0 0 0
const __m128i transpose0_0 = _mm_unpacklo_epi16(diff0, diff1);
const __m128i transpose0_1 = _mm_unpacklo_epi16(diff2, diff3);
// 00 10 01 11 02 12 03 13
// 20 30 21 31 22 32 23 33
const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2));
// a02 a12 a22 a32 a03 a13 a23 a33
// a00 a10 a20 a30 a01 a11 a21 a31
// a03 a13 a23 a33 a02 a12 a22 a32
}
const __m128i shuf01 = _mm_unpacklo_epi32(diff0, diff1);
const __m128i shuf23 = _mm_unpacklo_epi32(diff2, diff3);
// 00 01 10 11 02 03 12 13
// 20 21 30 31 22 23 32 33
const __m128i shuf01_p =
_mm_shufflehi_epi16(shuf01, _MM_SHUFFLE(2, 3, 0, 1));
const __m128i shuf23_p =
_mm_shufflehi_epi16(shuf23, _MM_SHUFFLE(2, 3, 0, 1));
// 00 01 10 11 03 02 13 12
// 20 21 30 31 23 22 33 32
const __m128i s01 = _mm_unpacklo_epi64(shuf01_p, shuf23_p);
const __m128i s32 = _mm_unpackhi_epi64(shuf01_p, shuf23_p);
// 00 01 10 11 20 21 30 31
// 03 02 13 12 23 22 33 32
const __m128i a01 = _mm_add_epi16(s01, s32);
const __m128i a32 = _mm_sub_epi16(s01, s32);
// [d0 + d3 | d1 + d2 | ...] = [a0 a1 | a0' a1' | ... ]
// [d0 - d3 | d1 - d2 | ...] = [a3 a2 | a3' a2' | ... ]
// First pass and subsequent transpose.
{
// Same operations are done on the (0,3) and (1,2) pairs.
// b0 = (a0 + a3) << 3
// b1 = (a1 + a2) << 3
// b3 = (a0 - a3) << 3
// b2 = (a1 - a2) << 3
const __m128i a01 = _mm_add_epi16(v01, v32);
const __m128i a32 = _mm_sub_epi16(v01, v32);
const __m128i b01 = _mm_slli_epi16(a01, 3);
const __m128i b32 = _mm_slli_epi16(a32, 3);
const __m128i b11 = _mm_unpackhi_epi64(b01, b01);
const __m128i b22 = _mm_unpackhi_epi64(b32, b32);
// e0 = b0 + b1
// e2 = b0 - b1
const __m128i e0 = _mm_add_epi16(b01, b11);
const __m128i e2 = _mm_sub_epi16(b01, b11);
const __m128i e02 = _mm_unpacklo_epi64(e0, e2);
// e1 = (b3 * 5352 + b2 * 2217 + 14500) >> 12
// e3 = (b3 * 2217 - b2 * 5352 + 7500) >> 12
const __m128i b23 = _mm_unpacklo_epi16(b22, b32);
const __m128i c1 = _mm_madd_epi16(b23, k5352_2217);
const __m128i c3 = _mm_madd_epi16(b23, k2217_5352);
const __m128i d1 = _mm_add_epi32(c1, k14500);
const __m128i d3 = _mm_add_epi32(c3, k7500);
const __m128i e1 = _mm_srai_epi32(d1, 12);
const __m128i e3 = _mm_srai_epi32(d3, 12);
const __m128i e13 = _mm_packs_epi32(e1, e3);
// Transpose.
// 00 01 02 03 20 21 22 23
// 10 11 12 13 30 31 32 33
const __m128i transpose0_0 = _mm_unpacklo_epi16(e02, e13);
const __m128i transpose0_1 = _mm_unpackhi_epi16(e02, e13);
// 00 10 01 11 02 12 03 13
// 20 30 21 31 22 32 23 33
const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2));
// 02 12 22 32 03 13 23 33
// 00 10 20 30 01 11 21 31
// 03 13 23 33 02 12 22 32
const __m128i tmp0 = _mm_madd_epi16(a01, k88p); // [ (a0 + a1) << 3, ... ]
const __m128i tmp2 = _mm_madd_epi16(a01, k88m); // [ (a0 - a1) << 3, ... ]
const __m128i tmp1_1 = _mm_madd_epi16(a32, k5352_2217p);
const __m128i tmp3_1 = _mm_madd_epi16(a32, k5352_2217m);
const __m128i tmp1_2 = _mm_add_epi32(tmp1_1, k1812);
const __m128i tmp3_2 = _mm_add_epi32(tmp3_1, k937);
const __m128i tmp1 = _mm_srai_epi32(tmp1_2, 9);
const __m128i tmp3 = _mm_srai_epi32(tmp3_2, 9);
const __m128i s03 = _mm_packs_epi32(tmp0, tmp2);
const __m128i s12 = _mm_packs_epi32(tmp1, tmp3);
const __m128i s_lo = _mm_unpacklo_epi16(s03, s12); // 0 1 0 1 0 1...
const __m128i s_hi = _mm_unpackhi_epi16(s03, s12); // 2 3 2 3 2 3
const __m128i v23 = _mm_unpackhi_epi32(s_lo, s_hi);
v01 = _mm_unpacklo_epi32(s_lo, s_hi);
v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2)); // 3 2 3 2 3 2..
}
// Second pass
@ -403,13 +418,12 @@ static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
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 b0 = _mm_add_epi16(a01, a11);
const __m128i b2 = _mm_sub_epi16(a01, a11);
const __m128i c0 = _mm_add_epi16(b0, seven);
const __m128i c2 = _mm_add_epi16(b2, seven);
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);
@ -427,6 +441,7 @@ static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
// f1 = 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)
const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero));
_mm_storel_epi64((__m128i*)&out[ 0], d0);
@ -436,13 +451,137 @@ static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
}
}
static void FTransformWHTSSE2(const int16_t* in, int16_t* out) {
int32_t tmp[16];
int i;
for (i = 0; i < 4; ++i, in += 64) {
const int a0 = (in[0 * 16] + in[2 * 16]);
const int a1 = (in[1 * 16] + in[3 * 16]);
const int a2 = (in[1 * 16] - in[3 * 16]);
const int a3 = (in[0 * 16] - in[2 * 16]);
tmp[0 + i * 4] = a0 + a1;
tmp[1 + i * 4] = a3 + a2;
tmp[2 + i * 4] = a3 - a2;
tmp[3 + i * 4] = a0 - a1;
}
{
const __m128i src0 = _mm_loadu_si128((__m128i*)&tmp[0]);
const __m128i src1 = _mm_loadu_si128((__m128i*)&tmp[4]);
const __m128i src2 = _mm_loadu_si128((__m128i*)&tmp[8]);
const __m128i src3 = _mm_loadu_si128((__m128i*)&tmp[12]);
const __m128i a0 = _mm_add_epi32(src0, src2);
const __m128i a1 = _mm_add_epi32(src1, src3);
const __m128i a2 = _mm_sub_epi32(src1, src3);
const __m128i a3 = _mm_sub_epi32(src0, src2);
const __m128i b0 = _mm_srai_epi32(_mm_add_epi32(a0, a1), 1);
const __m128i b1 = _mm_srai_epi32(_mm_add_epi32(a3, a2), 1);
const __m128i b2 = _mm_srai_epi32(_mm_sub_epi32(a3, a2), 1);
const __m128i b3 = _mm_srai_epi32(_mm_sub_epi32(a0, a1), 1);
const __m128i out0 = _mm_packs_epi32(b0, b1);
const __m128i out1 = _mm_packs_epi32(b2, b3);
_mm_storeu_si128((__m128i*)&out[0], out0);
_mm_storeu_si128((__m128i*)&out[8], out1);
}
}
//------------------------------------------------------------------------------
// Metric
static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
const __m128i zero = _mm_set1_epi16(0);
static int SSE_Nx4SSE2(const uint8_t* a, const uint8_t* b,
int num_quads, int do_16) {
const __m128i zero = _mm_setzero_si128();
__m128i sum1 = zero;
__m128i sum2 = zero;
// Load values.
while (num_quads-- > 0) {
// Note: for the !do_16 case, we read 16 pixels instead of 8 but that's ok,
// thanks to buffer over-allocation to that effect.
const __m128i a0 = _mm_loadu_si128((__m128i*)&a[BPS * 0]);
const __m128i a1 = _mm_loadu_si128((__m128i*)&a[BPS * 1]);
const __m128i a2 = _mm_loadu_si128((__m128i*)&a[BPS * 2]);
const __m128i a3 = _mm_loadu_si128((__m128i*)&a[BPS * 3]);
const __m128i b0 = _mm_loadu_si128((__m128i*)&b[BPS * 0]);
const __m128i b1 = _mm_loadu_si128((__m128i*)&b[BPS * 1]);
const __m128i b2 = _mm_loadu_si128((__m128i*)&b[BPS * 2]);
const __m128i b3 = _mm_loadu_si128((__m128i*)&b[BPS * 3]);
// compute clip0(a-b) and clip0(b-a)
const __m128i a0p = _mm_subs_epu8(a0, b0);
const __m128i a0m = _mm_subs_epu8(b0, a0);
const __m128i a1p = _mm_subs_epu8(a1, b1);
const __m128i a1m = _mm_subs_epu8(b1, a1);
const __m128i a2p = _mm_subs_epu8(a2, b2);
const __m128i a2m = _mm_subs_epu8(b2, a2);
const __m128i a3p = _mm_subs_epu8(a3, b3);
const __m128i a3m = _mm_subs_epu8(b3, a3);
// compute |a-b| with 8b arithmetic as clip0(a-b) | clip0(b-a)
const __m128i diff0 = _mm_or_si128(a0p, a0m);
const __m128i diff1 = _mm_or_si128(a1p, a1m);
const __m128i diff2 = _mm_or_si128(a2p, a2m);
const __m128i diff3 = _mm_or_si128(a3p, a3m);
// unpack (only four operations, instead of eight)
const __m128i low0 = _mm_unpacklo_epi8(diff0, zero);
const __m128i low1 = _mm_unpacklo_epi8(diff1, zero);
const __m128i low2 = _mm_unpacklo_epi8(diff2, zero);
const __m128i low3 = _mm_unpacklo_epi8(diff3, zero);
// multiply with self
const __m128i low_madd0 = _mm_madd_epi16(low0, low0);
const __m128i low_madd1 = _mm_madd_epi16(low1, low1);
const __m128i low_madd2 = _mm_madd_epi16(low2, low2);
const __m128i low_madd3 = _mm_madd_epi16(low3, low3);
// collect in a cascading way
const __m128i low_sum0 = _mm_add_epi32(low_madd0, low_madd1);
const __m128i low_sum1 = _mm_add_epi32(low_madd2, low_madd3);
sum1 = _mm_add_epi32(sum1, low_sum0);
sum2 = _mm_add_epi32(sum2, low_sum1);
if (do_16) { // if necessary, process the higher 8 bytes similarly
const __m128i hi0 = _mm_unpackhi_epi8(diff0, zero);
const __m128i hi1 = _mm_unpackhi_epi8(diff1, zero);
const __m128i hi2 = _mm_unpackhi_epi8(diff2, zero);
const __m128i hi3 = _mm_unpackhi_epi8(diff3, zero);
const __m128i hi_madd0 = _mm_madd_epi16(hi0, hi0);
const __m128i hi_madd1 = _mm_madd_epi16(hi1, hi1);
const __m128i hi_madd2 = _mm_madd_epi16(hi2, hi2);
const __m128i hi_madd3 = _mm_madd_epi16(hi3, hi3);
const __m128i hi_sum0 = _mm_add_epi32(hi_madd0, hi_madd1);
const __m128i hi_sum1 = _mm_add_epi32(hi_madd2, hi_madd3);
sum1 = _mm_add_epi32(sum1, hi_sum0);
sum2 = _mm_add_epi32(sum2, hi_sum1);
}
a += 4 * BPS;
b += 4 * BPS;
}
{
int32_t tmp[4];
const __m128i sum = _mm_add_epi32(sum1, sum2);
_mm_storeu_si128((__m128i*)tmp, sum);
return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
}
}
static int SSE16x16SSE2(const uint8_t* a, const uint8_t* b) {
return SSE_Nx4SSE2(a, b, 4, 1);
}
static int SSE16x8SSE2(const uint8_t* a, const uint8_t* b) {
return SSE_Nx4SSE2(a, b, 2, 1);
}
static int SSE8x8SSE2(const uint8_t* a, const uint8_t* b) {
return SSE_Nx4SSE2(a, b, 2, 0);
}
static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
const __m128i zero = _mm_setzero_si128();
// Load values. Note that we read 8 pixels instead of 4,
// but the a/b buffers are over-allocated to that effect.
const __m128i a0 = _mm_loadl_epi64((__m128i*)&a[BPS * 0]);
const __m128i a1 = _mm_loadl_epi64((__m128i*)&a[BPS * 1]);
const __m128i a2 = _mm_loadl_epi64((__m128i*)&a[BPS * 2]);
@ -480,6 +619,7 @@ static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
const __m128i sum0 = _mm_add_epi32(madd0, madd1);
const __m128i sum1 = _mm_add_epi32(madd2, madd3);
const __m128i sum2 = _mm_add_epi32(sum0, sum1);
int32_t tmp[4];
_mm_storeu_si128((__m128i*)tmp, sum2);
return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
@ -499,10 +639,8 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
int32_t sum[4];
__m128i tmp_0, tmp_1, tmp_2, tmp_3;
const __m128i zero = _mm_setzero_si128();
const __m128i one = _mm_set1_epi16(1);
const __m128i three = _mm_set1_epi16(3);
// Load, combine and tranpose inputs.
// Load, combine and transpose inputs.
{
const __m128i inA_0 = _mm_loadl_epi64((__m128i*)&inA[BPS * 0]);
const __m128i inA_1 = _mm_loadl_epi64((__m128i*)&inA[BPS * 1]);
@ -547,17 +685,14 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
// Horizontal pass and subsequent transpose.
{
// Calculate a and b (two 4x4 at once).
const __m128i a0 = _mm_slli_epi16(_mm_add_epi16(tmp_0, tmp_2), 2);
const __m128i a1 = _mm_slli_epi16(_mm_add_epi16(tmp_1, tmp_3), 2);
const __m128i a2 = _mm_slli_epi16(_mm_sub_epi16(tmp_1, tmp_3), 2);
const __m128i a3 = _mm_slli_epi16(_mm_sub_epi16(tmp_0, tmp_2), 2);
// b0_extra = (a0 != 0);
const __m128i b0_extra = _mm_andnot_si128(_mm_cmpeq_epi16 (a0, zero), one);
const __m128i b0_base = _mm_add_epi16(a0, a1);
const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2);
const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3);
const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3);
const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2);
const __m128i b0 = _mm_add_epi16(a0, a1);
const __m128i b1 = _mm_add_epi16(a3, a2);
const __m128i b2 = _mm_sub_epi16(a3, a2);
const __m128i b3 = _mm_sub_epi16(a0, a1);
const __m128i b0 = _mm_add_epi16(b0_base, b0_extra);
// a00 a01 a02 a03 b00 b01 b02 b03
// a10 a11 a12 a13 b10 b11 b12 b13
// a20 a21 a22 a23 b20 b21 b22 b23
@ -632,19 +767,6 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
B_b2 = _mm_sub_epi16(B_b2, sign_B_b2);
}
// b = abs(b) + 3
A_b0 = _mm_add_epi16(A_b0, three);
A_b2 = _mm_add_epi16(A_b2, three);
B_b0 = _mm_add_epi16(B_b0, three);
B_b2 = _mm_add_epi16(B_b2, three);
// abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3
// b = (abs(b) + 3) >> 3
A_b0 = _mm_srai_epi16(A_b0, 3);
A_b2 = _mm_srai_epi16(A_b2, 3);
B_b0 = _mm_srai_epi16(B_b0, 3);
B_b2 = _mm_srai_epi16(B_b2, 3);
// weighted sums
A_b0 = _mm_madd_epi16(A_b0, w_0);
A_b2 = _mm_madd_epi16(A_b2, w_8);
@ -663,7 +785,7 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
static int Disto4x4SSE2(const uint8_t* const a, const uint8_t* const b,
const uint16_t* const w) {
const int diff_sum = TTransformSSE2(a, b, w);
return (abs(diff_sum) + 8) >> 4;
return abs(diff_sum) >> 5;
}
static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
@ -678,7 +800,6 @@ static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
return D;
}
//------------------------------------------------------------------------------
// Quantization
//
@ -686,9 +807,8 @@ static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
// Simple quantization
static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
int n, const VP8Matrix* const mtx) {
const __m128i max_coeff_2047 = _mm_set1_epi16(2047);
const __m128i zero = _mm_set1_epi16(0);
__m128i sign0, sign8;
const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL);
const __m128i zero = _mm_setzero_si128();
__m128i coeff0, coeff8;
__m128i out0, out8;
__m128i packed_out;
@ -706,12 +826,10 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
const __m128i bias8 = _mm_loadu_si128((__m128i*)&mtx->bias_[8]);
const __m128i q0 = _mm_loadu_si128((__m128i*)&mtx->q_[0]);
const __m128i q8 = _mm_loadu_si128((__m128i*)&mtx->q_[8]);
const __m128i zthresh0 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[0]);
const __m128i zthresh8 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[8]);
// sign(in) = in >> 15 (0x0000 if positive, 0xffff if negative)
sign0 = _mm_srai_epi16(in0, 15);
sign8 = _mm_srai_epi16(in8, 15);
const __m128i sign0 = _mm_srai_epi16(in0, 15);
const __m128i sign8 = _mm_srai_epi16(in8, 15);
// coeff = abs(in) = (in ^ sign) - sign
coeff0 = _mm_xor_si128(in0, sign0);
@ -723,10 +841,6 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
coeff0 = _mm_add_epi16(coeff0, sharpen0);
coeff8 = _mm_add_epi16(coeff8, sharpen8);
// if (coeff > 2047) coeff = 2047
coeff0 = _mm_min_epi16(coeff0, max_coeff_2047);
coeff8 = _mm_min_epi16(coeff8, max_coeff_2047);
// out = (coeff * iQ + B) >> QFIX;
{
// doing calculations with 32b precision (QFIX=17)
@ -754,9 +868,14 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
out_04 = _mm_srai_epi32(out_04, QFIX);
out_08 = _mm_srai_epi32(out_08, QFIX);
out_12 = _mm_srai_epi32(out_12, QFIX);
// pack result as 16b
out0 = _mm_packs_epi32(out_00, out_04);
out8 = _mm_packs_epi32(out_08, out_12);
// if (coeff > 2047) coeff = 2047
out0 = _mm_min_epi16(out0, max_coeff_2047);
out8 = _mm_min_epi16(out8, max_coeff_2047);
}
// get sign back (if (sign[j]) out_n = -out_n)
@ -769,17 +888,8 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
in0 = _mm_mullo_epi16(out0, q0);
in8 = _mm_mullo_epi16(out8, q8);
// if (coeff <= mtx->zthresh_) {in=0; out=0;}
{
__m128i cmp0 = _mm_cmpgt_epi16(coeff0, zthresh0);
__m128i cmp8 = _mm_cmpgt_epi16(coeff8, zthresh8);
in0 = _mm_and_si128(in0, cmp0);
in8 = _mm_and_si128(in8, cmp8);
_mm_storeu_si128((__m128i*)&in[0], in0);
_mm_storeu_si128((__m128i*)&in[8], in8);
out0 = _mm_and_si128(out0, cmp0);
out8 = _mm_and_si128(out8, cmp8);
}
_mm_storeu_si128((__m128i*)&in[0], in0);
_mm_storeu_si128((__m128i*)&in[8], in8);
// zigzag the output before storing it.
//
@ -816,19 +926,32 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
}
}
static int QuantizeBlockWHTSSE2(int16_t in[16], int16_t out[16],
const VP8Matrix* const mtx) {
return QuantizeBlockSSE2(in, out, 0, mtx);
}
#endif // WEBP_USE_SSE2
//------------------------------------------------------------------------------
// Entry point
extern void VP8EncDspInitSSE2(void);
void VP8EncDspInitSSE2(void) {
#if defined(WEBP_USE_SSE2)
VP8CollectHistogram = CollectHistogramSSE2;
VP8EncQuantizeBlock = QuantizeBlockSSE2;
VP8EncQuantizeBlockWHT = QuantizeBlockWHTSSE2;
VP8ITransform = ITransformSSE2;
VP8FTransform = FTransformSSE2;
VP8FTransformWHT = FTransformWHTSSE2;
VP8SSE16x16 = SSE16x16SSE2;
VP8SSE16x8 = SSE16x8SSE2;
VP8SSE8x8 = SSE8x8SSE2;
VP8SSE4x4 = SSE4x4SSE2;
VP8TDisto4x4 = Disto4x4SSE2;
VP8TDisto16x16 = Disto16x16SSE2;
#endif // WEBP_USE_SSE2
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif //__SSE2__

1532
src/dsp/lossless.c Normal file

File diff suppressed because it is too large Load Diff

220
src/dsp/lossless.h Normal file
View File

@ -0,0 +1,220 @@
// 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)
#ifndef WEBP_DSP_LOSSLESS_H_
#define WEBP_DSP_LOSSLESS_H_
#include "../webp/types.h"
#include "../webp/decode.h"
#ifdef __cplusplus
extern "C" {
#endif
//------------------------------------------------------------------------------
//
typedef uint32_t (*VP8LPredClampedAddSubFunc)(uint32_t c0, uint32_t c1,
uint32_t c2);
typedef uint32_t (*VP8LPredSelectFunc)(uint32_t c0, uint32_t c1, uint32_t c2);
typedef void (*VP8LSubtractGreenFromBlueAndRedFunc)(uint32_t* argb_data,
int num_pixs);
typedef void (*VP8LAddGreenToBlueAndRedFunc)(uint32_t* data_start,
const uint32_t* data_end);
extern VP8LPredClampedAddSubFunc VP8LClampedAddSubtractFull;
extern VP8LPredClampedAddSubFunc VP8LClampedAddSubtractHalf;
extern VP8LPredSelectFunc VP8LSelect;
extern VP8LSubtractGreenFromBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
extern VP8LAddGreenToBlueAndRedFunc VP8LAddGreenToBlueAndRed;
// Must be called before calling any of the above methods.
void VP8LDspInit(void);
//------------------------------------------------------------------------------
// Image transforms.
struct VP8LTransform; // Defined in dec/vp8li.h.
// Performs inverse transform of data given transform information, start and end
// rows. Transform will be applied to rows [row_start, row_end[.
// The *in and *out pointers refer to source and destination data respectively
// corresponding to the intermediate row (row_start).
void VP8LInverseTransform(const struct VP8LTransform* const transform,
int row_start, int row_end,
const uint32_t* const in, uint32_t* const out);
// Similar to the static method ColorIndexInverseTransform() that is part of
// lossless.c, but used only for alpha decoding. It takes uint8_t (rather than
// uint32_t) arguments for 'src' and 'dst'.
void VP8LColorIndexInverseTransformAlpha(
const struct VP8LTransform* const transform, int y_start, int y_end,
const uint8_t* src, uint8_t* dst);
void VP8LResidualImage(int width, int height, int bits,
uint32_t* const argb, uint32_t* const argb_scratch,
uint32_t* const image);
void VP8LColorSpaceTransform(int width, int height, int bits, int step,
uint32_t* const argb, uint32_t* image);
//------------------------------------------------------------------------------
// Color space conversion.
// Converts from BGRA to other color spaces.
void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
WEBP_CSP_MODE out_colorspace, uint8_t* const rgba);
//------------------------------------------------------------------------------
// 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;
}
// Faster logarithm for integers. Small values use a look-up table.
#define LOG_LOOKUP_IDX_MAX 256
extern const float kLog2Table[LOG_LOOKUP_IDX_MAX];
extern const float kSLog2Table[LOG_LOOKUP_IDX_MAX];
float VP8LFastLog2Slow(int v);
float VP8LFastSLog2Slow(int v);
static WEBP_INLINE float VP8LFastLog2(int 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(int v) {
return (v < LOG_LOOKUP_IDX_MAX) ? kSLog2Table[v] : VP8LFastSLog2Slow(v);
}
// -----------------------------------------------------------------------------
// PrefixEncode()
// use GNU builtins where available.
#if defined(__GNUC__) && \
((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
return 31 ^ __builtin_clz(n);
}
#elif defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#include <intrin.h>
#pragma intrinsic(_BitScanReverse)
static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
unsigned long first_set_bit;
_BitScanReverse(&first_set_bit, n);
return first_set_bit;
}
#else
// Returns (int)floor(log2(n)). n must be > 0.
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;
}
#endif
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);
}
}
// In-place difference of each component with 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);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_DSP_LOSSLESS_H_

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// YUV to RGB upsampling functions.
@ -11,11 +13,8 @@
#include "./dsp.h"
#include "./yuv.h"
#include "../dec/webpi.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include <assert.h>
//------------------------------------------------------------------------------
// Fancy upsampler
@ -24,7 +23,6 @@ extern "C" {
// Fancy upsampling functions to convert YUV to RGB
WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_LAST];
// Given samples laid out in a square as:
// [a b]
@ -34,7 +32,7 @@ WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_LAST];
// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16
// We process u and v together stashed into 32bit (16bit each).
#define LOAD_UV(u,v) ((u) | ((v) << 16))
#define LOAD_UV(u, v) ((u) | ((v) << 16))
#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
@ -45,11 +43,12 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
const int last_pixel_pair = (len - 1) >> 1; \
uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \
uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \
if (top_y) { \
assert(top_y != NULL); \
{ \
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \
} \
if (bottom_y) { \
if (bottom_y != NULL) { \
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \
} \
@ -60,7 +59,7 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \
const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \
const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \
if (top_y) { \
{ \
const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \
const uint32_t uv1 = (diag_03 + t_uv) >> 1; \
FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
@ -68,7 +67,7 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \
top_dst + (2 * x - 0) * XSTEP); \
} \
if (bottom_y) { \
if (bottom_y != NULL) { \
const uint32_t uv0 = (diag_03 + l_uv) >> 1; \
const uint32_t uv1 = (diag_12 + uv) >> 1; \
FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
@ -80,12 +79,12 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
l_uv = uv; \
} \
if (!(len & 1)) { \
if (top_y) { \
{ \
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
top_dst + (len - 1) * XSTEP); \
} \
if (bottom_y) { \
if (bottom_y != NULL) { \
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
bottom_dst + (len - 1) * XSTEP); \
@ -101,11 +100,6 @@ UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
// These two don't erase the alpha value
UPSAMPLE_FUNC(UpsampleRgbKeepAlphaLinePair, VP8YuvToRgb, 4)
UPSAMPLE_FUNC(UpsampleBgrKeepAlphaLinePair, VP8YuvToBgr, 4)
UPSAMPLE_FUNC(UpsampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
UPSAMPLE_FUNC(UpsampleRgba4444KeepAlphaLinePair, VP8YuvToRgba4444KeepA, 2)
#undef LOAD_UV
#undef UPSAMPLE_FUNC
@ -156,9 +150,56 @@ const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = {
SampleBgraLinePair, // MODE_BGRA
SampleArgbLinePair, // MODE_ARGB
SampleRgba4444LinePair, // MODE_RGBA_4444
SampleRgb565LinePair // MODE_RGB_565
SampleRgb565LinePair, // MODE_RGB_565
SampleRgbaLinePair, // MODE_rgbA
SampleBgraLinePair, // MODE_bgrA
SampleArgbLinePair, // MODE_Argb
SampleRgba4444LinePair // MODE_rgbA_4444
};
//------------------------------------------------------------------------------
#if !defined(FANCY_UPSAMPLING)
#define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \
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* bot_u, const uint8_t* bot_v, \
uint8_t* top_dst, uint8_t* bot_dst, int len) { \
const int half_len = len >> 1; \
int x; \
assert(top_dst != NULL); \
{ \
for (x = 0; x < half_len; ++x) { \
FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x + 0); \
FUNC(top_y[2 * x + 1], top_u[x], top_v[x], top_dst + 8 * x + 4); \
} \
if (len & 1) FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x); \
} \
if (bot_dst != NULL) { \
for (x = 0; x < half_len; ++x) { \
FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x + 0); \
FUNC(bot_y[2 * x + 1], bot_u[x], bot_v[x], bot_dst + 8 * x + 4); \
} \
if (len & 1) FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x); \
} \
}
DUAL_SAMPLE_FUNC(DualLineSamplerBGRA, VP8YuvToBgra)
DUAL_SAMPLE_FUNC(DualLineSamplerARGB, VP8YuvToArgb)
#undef DUAL_SAMPLE_FUNC
#endif // !FANCY_UPSAMPLING
WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) {
WebPInitUpsamplers();
VP8YUVInit();
#ifdef FANCY_UPSAMPLING
return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB];
#else
return (alpha_is_last ? DualLineSamplerBGRA : DualLineSamplerARGB);
#endif
}
//------------------------------------------------------------------------------
// YUV444 converter
@ -186,9 +227,89 @@ const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = {
Yuv444ToBgra, // MODE_BGRA
Yuv444ToArgb, // MODE_ARGB
Yuv444ToRgba4444, // MODE_RGBA_4444
Yuv444ToRgb565 // MODE_RGB_565
Yuv444ToRgb565, // MODE_RGB_565
Yuv444ToRgba, // MODE_rgbA
Yuv444ToBgra, // MODE_bgrA
Yuv444ToArgb, // MODE_Argb
Yuv444ToRgba4444 // MODE_rgbA_4444
};
//------------------------------------------------------------------------------
// Premultiplied modes
// non dithered-modes
// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
#if 1 // (int)(x * a / 255.)
#define MULTIPLIER(a) ((a) * 32897UL)
#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
#else // (int)(x * a / 255. + .5)
#define MULTIPLIER(a) ((a) * 65793UL)
#define PREMULTIPLY(x, m) (((x) * (m) + (1UL << 23)) >> 24)
#endif
static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
int w, int h, int stride) {
while (h-- > 0) {
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
int i;
for (i = 0; i < w; ++i) {
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 MULTIPLIER
#undef PREMULTIPLY
// rgbA4444
#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
return (x & 0xf0) | (x >> 4);
}
static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
return (x & 0x0f) | (x << 4);
}
static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
return (x * m) >> 16;
}
static void ApplyAlphaMultiply4444(uint8_t* rgba4444,
int w, int h, int stride) {
while (h-- > 0) {
int i;
for (i = 0; i < w; ++i) {
const uint8_t a = (rgba4444[2 * i + 1] & 0x0f);
const uint32_t mult = MULTIPLIER(a);
const uint8_t r = multiply(dither_hi(rgba4444[2 * i + 0]), mult);
const uint8_t g = multiply(dither_lo(rgba4444[2 * i + 0]), mult);
const uint8_t b = multiply(dither_hi(rgba4444[2 * i + 1]), mult);
rgba4444[2 * i + 0] = (r & 0xf0) | ((g >> 4) & 0x0f);
rgba4444[2 * i + 1] = (b & 0xf0) | a;
}
rgba4444 += stride;
}
}
#undef MULTIPLIER
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int)
= ApplyAlphaMultiply;
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int)
= ApplyAlphaMultiply4444;
//------------------------------------------------------------------------------
// Main call
@ -202,25 +323,44 @@ void WebPInitUpsamplers(void) {
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
WebPUpsamplersKeepAlpha[MODE_RGB] = UpsampleRgbLinePair;
WebPUpsamplersKeepAlpha[MODE_RGBA] = UpsampleRgbKeepAlphaLinePair;
WebPUpsamplersKeepAlpha[MODE_BGR] = UpsampleBgrLinePair;
WebPUpsamplersKeepAlpha[MODE_BGRA] = UpsampleBgrKeepAlphaLinePair;
WebPUpsamplersKeepAlpha[MODE_ARGB] = UpsampleArgbKeepAlphaLinePair;
WebPUpsamplersKeepAlpha[MODE_RGBA_4444] = UpsampleRgba4444KeepAlphaLinePair;
WebPUpsamplersKeepAlpha[MODE_RGB_565] = UpsampleRgb565LinePair;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo) {
#if defined(__SSE2__) || defined(_MSC_VER)
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitUpsamplersSSE2();
}
#endif
#if defined(WEBP_USE_NEON)
if (VP8GetCPUInfo(kNEON)) {
WebPInitUpsamplersNEON();
}
#endif
}
#endif // FANCY_UPSAMPLING
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
void WebPInitPremultiply(void) {
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply4444;
#ifdef FANCY_UPSAMPLING
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitPremultiplySSE2();
}
#endif
#if defined(WEBP_USE_NEON)
if (VP8GetCPUInfo(kNEON)) {
WebPInitPremultiplyNEON();
}
#endif
}
#endif // FANCY_UPSAMPLING
}

265
src/dsp/upsampling_neon.c Normal file
View File

@ -0,0 +1,265 @@
// Copyright 2011 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 version of YUV to RGB upsampling functions.
//
// Author: mans@mansr.com (Mans Rullgard)
// Based on SSE code by: somnath@google.com (Somnath Banerjee)
#include "./dsp.h"
#if defined(WEBP_USE_NEON)
#include <assert.h>
#include <arm_neon.h>
#include <string.h>
#include "./yuv.h"
#ifdef FANCY_UPSAMPLING
//-----------------------------------------------------------------------------
// 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; \
\
/* 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 */ \
\
diag2 = vshrn_n_u16(al, 3); \
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 uint8x8x2_t a_b = {{ a, b }}; \
const uint8x8x2_t c_d = {{ c, d }}; \
vst2_u8(out, a_b); \
vst2_u8(out + 32, c_d); \
} \
}
// Turn the macro into a function for reducing code-size when non-critical
static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2,
uint8_t *out) {
UPSAMPLE_16PIXELS(r1, r2, out);
}
#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \
uint8_t r1[9], r2[9]; \
memcpy(r1, (tb), (num_pixels)); \
memcpy(r2, (bb), (num_pixels)); \
/* replicate last byte */ \
memset(r1 + (num_pixels), r1[(num_pixels) - 1], 9 - (num_pixels)); \
memset(r2 + (num_pixels), r2[(num_pixels) - 1], 9 - (num_pixels)); \
Upsample16Pixels(r1, r2, out); \
}
//-----------------------------------------------------------------------------
// YUV->RGB conversion
static const int16_t kCoeffs[4] = { kYScale, kVToR, kUToG, kVToG };
#define v255 vmov_n_u8(255)
#define STORE_Rgb(out, r, g, b) do { \
const uint8x8x3_t r_g_b = {{ r, g, b }}; \
vst3_u8(out, r_g_b); \
} while (0)
#define STORE_Bgr(out, r, g, b) do { \
const uint8x8x3_t b_g_r = {{ b, g, r }}; \
vst3_u8(out, b_g_r); \
} while (0)
#define STORE_Rgba(out, r, g, b) do { \
const uint8x8x4_t r_g_b_v255 = {{ r, g, b, v255 }}; \
vst4_u8(out, r_g_b_v255); \
} while (0)
#define STORE_Bgra(out, r, g, b) do { \
const uint8x8x4_t b_g_r_v255 = {{ b, g, r, v255 }}; \
vst4_u8(out, b_g_r_v255); \
} while (0)
#define CONVERT8(FMT, XSTEP, N, src_y, src_uv, out, cur_x) { \
int i; \
for (i = 0; i < N; i += 8) { \
const int off = ((cur_x) + i) * XSTEP; \
uint8x8_t y = vld1_u8((src_y) + (cur_x) + i); \
uint8x8_t u = vld1_u8((src_uv) + i); \
uint8x8_t v = vld1_u8((src_uv) + i + 16); \
const int16x8_t yy = vreinterpretq_s16_u16(vsubl_u8(y, u16)); \
const int16x8_t uu = vreinterpretq_s16_u16(vsubl_u8(u, u128)); \
const int16x8_t vv = vreinterpretq_s16_u16(vsubl_u8(v, u128)); \
int32x4_t yl = vmull_lane_s16(vget_low_s16(yy), cf16, 0); \
int32x4_t yh = vmull_lane_s16(vget_high_s16(yy), cf16, 0); \
const int32x4_t rl = vmlal_lane_s16(yl, vget_low_s16(vv), cf16, 1);\
const int32x4_t rh = vmlal_lane_s16(yh, vget_high_s16(vv), cf16, 1);\
int32x4_t gl = vmlsl_lane_s16(yl, vget_low_s16(uu), cf16, 2); \
int32x4_t gh = vmlsl_lane_s16(yh, vget_high_s16(uu), cf16, 2); \
const int32x4_t bl = vmovl_s16(vget_low_s16(uu)); \
const int32x4_t bh = vmovl_s16(vget_high_s16(uu)); \
gl = vmlsl_lane_s16(gl, vget_low_s16(vv), cf16, 3); \
gh = vmlsl_lane_s16(gh, vget_high_s16(vv), cf16, 3); \
yl = vmlaq_lane_s32(yl, bl, cf32, 0); \
yh = vmlaq_lane_s32(yh, bh, cf32, 0); \
/* vrshrn_n_s32() already incorporates the rounding constant */ \
y = vqmovun_s16(vcombine_s16(vrshrn_n_s32(rl, YUV_FIX2), \
vrshrn_n_s32(rh, YUV_FIX2))); \
u = vqmovun_s16(vcombine_s16(vrshrn_n_s32(gl, YUV_FIX2), \
vrshrn_n_s32(gh, YUV_FIX2))); \
v = vqmovun_s16(vcombine_s16(vrshrn_n_s32(yl, YUV_FIX2), \
vrshrn_n_s32(yh, YUV_FIX2))); \
STORE_ ## FMT(out + off, y, u, v); \
} \
}
#define CONVERT1(FUNC, XSTEP, N, src_y, src_uv, rgb, cur_x) { \
int i; \
for (i = 0; i < N; i++) { \
const int off = ((cur_x) + i) * XSTEP; \
const int y = src_y[(cur_x) + i]; \
const int u = (src_uv)[i]; \
const int v = (src_uv)[i + 16]; \
FUNC(y, u, v, rgb + off); \
} \
}
#define CONVERT2RGB_8(FMT, XSTEP, top_y, bottom_y, uv, \
top_dst, bottom_dst, cur_x, len) { \
CONVERT8(FMT, XSTEP, len, top_y, uv, top_dst, cur_x) \
if (bottom_y != NULL) { \
CONVERT8(FMT, XSTEP, len, bottom_y, (uv) + 32, bottom_dst, cur_x) \
} \
}
#define CONVERT2RGB_1(FUNC, XSTEP, top_y, bottom_y, uv, \
top_dst, bottom_dst, cur_x, len) { \
CONVERT1(FUNC, XSTEP, len, top_y, uv, top_dst, cur_x); \
if (bottom_y != NULL) { \
CONVERT1(FUNC, XSTEP, len, bottom_y, (uv) + 32, bottom_dst, cur_x); \
} \
}
#define NEON_UPSAMPLE_FUNC(FUNC_NAME, FMT, XSTEP) \
static void FUNC_NAME(const uint8_t *top_y, const uint8_t *bottom_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 *bottom_dst, int len) { \
int block; \
/* 16 byte aligned array to cache reconstructed u and v */ \
uint8_t uv_buf[2 * 32 + 15]; \
uint8_t *const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
const int uv_len = (len + 1) >> 1; \
/* 9 pixels must be read-able for each block */ \
const int num_blocks = (uv_len - 1) >> 3; \
const int leftover = uv_len - num_blocks * 8; \
const int last_pos = 1 + 16 * num_blocks; \
\
const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
\
const int16x4_t cf16 = vld1_s16(kCoeffs); \
const int32x2_t cf32 = vmov_n_s32(kUToB); \
const uint8x8_t u16 = vmov_n_u8(16); \
const uint8x8_t u128 = vmov_n_u8(128); \
\
/* Treat the first pixel in regular way */ \
assert(top_y != NULL); \
{ \
const int u0 = (top_u[0] + u_diag) >> 1; \
const int v0 = (top_v[0] + v_diag) >> 1; \
VP8YuvTo ## FMT(top_y[0], u0, v0, top_dst); \
} \
if (bottom_y != NULL) { \
const int u0 = (cur_u[0] + u_diag) >> 1; \
const int v0 = (cur_v[0] + v_diag) >> 1; \
VP8YuvTo ## FMT(bottom_y[0], u0, v0, bottom_dst); \
} \
\
for (block = 0; block < num_blocks; ++block) { \
UPSAMPLE_16PIXELS(top_u, cur_u, r_uv); \
UPSAMPLE_16PIXELS(top_v, cur_v, r_uv + 16); \
CONVERT2RGB_8(FMT, XSTEP, top_y, bottom_y, r_uv, \
top_dst, bottom_dst, 16 * block + 1, 16); \
top_u += 8; \
cur_u += 8; \
top_v += 8; \
cur_v += 8; \
} \
\
UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv); \
UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 16); \
CONVERT2RGB_1(VP8YuvTo ## FMT, XSTEP, top_y, bottom_y, r_uv, \
top_dst, bottom_dst, last_pos, len - last_pos); \
}
// NEON variants of the fancy upsampler.
NEON_UPSAMPLE_FUNC(UpsampleRgbLinePairNEON, Rgb, 3)
NEON_UPSAMPLE_FUNC(UpsampleBgrLinePairNEON, Bgr, 3)
NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePairNEON, Rgba, 4)
NEON_UPSAMPLE_FUNC(UpsampleBgraLinePairNEON, Bgra, 4)
#endif // FANCY_UPSAMPLING
#endif // WEBP_USE_NEON
//------------------------------------------------------------------------------
#ifdef FANCY_UPSAMPLING
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
void WebPInitUpsamplersNEON(void) {
#if defined(WEBP_USE_NEON)
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairNEON;
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairNEON;
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairNEON;
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairNEON;
#endif // WEBP_USE_NEON
}
void WebPInitPremultiplyNEON(void) {
#if defined(WEBP_USE_NEON)
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairNEON;
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairNEON;
#endif // WEBP_USE_NEON
}
#else
// this empty function is to avoid an empty .o
void WebPInitPremultiplyNEON(void) {}
#endif // FANCY_UPSAMPLING

View File

@ -1,26 +1,24 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// SSE2 version of YUV to RGB upsampling functions.
//
// Author: somnath@google.com (Somnath Banerjee)
#if defined(__SSE2__) || defined(_MSC_VER)
#include "./dsp.h"
#if defined(WEBP_USE_SSE2)
#include <assert.h>
#include <emmintrin.h>
#include <string.h>
#include "./dsp.h"
#include "./yuv.h"
#include "../dec/webpi.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#ifdef FANCY_UPSAMPLING
@ -49,14 +47,14 @@ extern "C" {
(out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \
} while (0)
// pack and store two alterning pixel rows
// pack and store two alternating pixel rows
#define PACK_AND_STORE(a, b, da, db, out) do { \
const __m128i ta = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \
const __m128i tb = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \
const __m128i t1 = _mm_unpacklo_epi8(ta, tb); \
const __m128i t2 = _mm_unpackhi_epi8(ta, tb); \
_mm_store_si128(((__m128i*)(out)) + 0, t1); \
_mm_store_si128(((__m128i*)(out)) + 1, t2); \
const __m128i t_a = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \
const __m128i t_b = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \
const __m128i t_1 = _mm_unpacklo_epi8(t_a, t_b); \
const __m128i t_2 = _mm_unpackhi_epi8(t_a, t_b); \
_mm_store_si128(((__m128i*)(out)) + 0, t_1); \
_mm_store_si128(((__m128i*)(out)) + 1, t_2); \
} while (0)
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
@ -85,8 +83,8 @@ extern "C" {
GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \
\
/* pack the alternate pixels */ \
PACK_AND_STORE(a, b, diag1, diag2, &(out)[0 * 32]); \
PACK_AND_STORE(c, d, diag2, diag1, &(out)[2 * 32]); \
PACK_AND_STORE(a, b, diag1, diag2, out + 0); /* store top */ \
PACK_AND_STORE(c, d, diag2, diag1, out + 2 * 32); /* store bottom */ \
}
// Turn the macro into a function for reducing code-size when non-critical
@ -106,69 +104,68 @@ static void Upsample32Pixels(const uint8_t r1[], const uint8_t r2[],
Upsample32Pixels(r1, r2, out); \
}
#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, uv, \
#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, \
top_dst, bottom_dst, cur_x, num_pixels) { \
int n; \
if (top_y) { \
for (n = 0; n < (num_pixels); ++n) { \
FUNC(top_y[(cur_x) + n], (uv)[n], (uv)[32 + n], \
top_dst + ((cur_x) + n) * XSTEP); \
} \
for (n = 0; n < (num_pixels); ++n) { \
FUNC(top_y[(cur_x) + n], r_u[n], r_v[n], \
top_dst + ((cur_x) + n) * XSTEP); \
} \
if (bottom_y) { \
if (bottom_y != NULL) { \
for (n = 0; n < (num_pixels); ++n) { \
FUNC(bottom_y[(cur_x) + n], (uv)[64 + n], (uv)[64 + 32 + n], \
FUNC(bottom_y[(cur_x) + n], r_u[64 + n], r_v[64 + n], \
bottom_dst + ((cur_x) + n) * XSTEP); \
} \
} \
}
#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \
top_dst, bottom_dst, cur_x) do { \
FUNC##32(top_y + (cur_x), r_u, r_v, top_dst + (cur_x) * XSTEP); \
if (bottom_y != NULL) { \
FUNC##32(bottom_y + (cur_x), r_u + 64, r_v + 64, \
bottom_dst + (cur_x) * XSTEP); \
} \
} while (0)
#define SSE2_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_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* bottom_dst, int len) { \
int b; \
/* 16 byte aligned array to cache reconstructed u and v */ \
int uv_pos, pos; \
/* 16byte-aligned array to cache reconstructed u and v */ \
uint8_t uv_buf[4 * 32 + 15]; \
uint8_t* const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
const int uv_len = (len + 1) >> 1; \
/* 17 pixels must be read-able for each block */ \
const int num_blocks = (uv_len - 1) >> 4; \
const int leftover = uv_len - num_blocks * 16; \
const int last_pos = 1 + 32 * num_blocks; \
uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
uint8_t* const r_v = r_u + 32; \
\
const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
\
assert(len > 0); \
/* Treat the first pixel in regular way */ \
if (top_y) { \
const int u0 = (top_u[0] + u_diag) >> 1; \
const int v0 = (top_v[0] + v_diag) >> 1; \
FUNC(top_y[0], u0, v0, top_dst); \
assert(top_y != NULL); \
{ /* Treat the first pixel in regular way */ \
const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
const int u0_t = (top_u[0] + u_diag) >> 1; \
const int v0_t = (top_v[0] + v_diag) >> 1; \
FUNC(top_y[0], u0_t, v0_t, top_dst); \
if (bottom_y != NULL) { \
const int u0_b = (cur_u[0] + u_diag) >> 1; \
const int v0_b = (cur_v[0] + v_diag) >> 1; \
FUNC(bottom_y[0], u0_b, v0_b, bottom_dst); \
} \
} \
if (bottom_y) { \
const int u0 = (cur_u[0] + u_diag) >> 1; \
const int v0 = (cur_v[0] + v_diag) >> 1; \
FUNC(bottom_y[0], u0, v0, bottom_dst); \
/* For UPSAMPLE_32PIXELS, 17 u/v values must be read-able for each block */ \
for (pos = 1, uv_pos = 0; pos + 32 + 1 <= len; pos += 32, uv_pos += 16) { \
UPSAMPLE_32PIXELS(top_u + uv_pos, cur_u + uv_pos, r_u); \
UPSAMPLE_32PIXELS(top_v + uv_pos, cur_v + uv_pos, r_v); \
CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, pos); \
} \
\
for (b = 0; b < num_blocks; ++b) { \
UPSAMPLE_32PIXELS(top_u, cur_u, r_uv + 0 * 32); \
UPSAMPLE_32PIXELS(top_v, cur_v, r_uv + 1 * 32); \
CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, r_uv, top_dst, bottom_dst, \
32 * b + 1, 32) \
top_u += 16; \
cur_u += 16; \
top_v += 16; \
cur_v += 16; \
if (len > 1) { \
const int left_over = ((len + 1) >> 1) - (pos >> 1); \
assert(left_over > 0); \
UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \
UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \
CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, \
pos, len - pos); \
} \
\
UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv + 0 * 32); \
UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 1 * 32); \
CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, r_uv, top_dst, bottom_dst, \
last_pos, len - last_pos); \
}
// SSE2 variants of the fancy upsampler.
@ -176,40 +173,46 @@ SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePairSSE2, VP8YuvToRgb, 3)
SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePairSSE2, VP8YuvToBgr, 3)
SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePairSSE2, VP8YuvToRgba, 4)
SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePairSSE2, VP8YuvToBgra, 4)
// These two don't erase the alpha value
SSE2_UPSAMPLE_FUNC(UpsampleRgbKeepAlphaLinePairSSE2, VP8YuvToRgb, 4)
SSE2_UPSAMPLE_FUNC(UpsampleBgrKeepAlphaLinePairSSE2, VP8YuvToBgr, 4)
#undef GET_M
#undef PACK_AND_STORE
#undef UPSAMPLE_32PIXELS
#undef UPSAMPLE_LAST_BLOCK
#undef CONVERT2RGB
#undef CONVERT2RGB_32
#undef SSE2_UPSAMPLE_FUNC
//------------------------------------------------------------------------------
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
extern WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[/* MODE_LAST */];
#endif // FANCY_UPSAMPLING
void WebPInitUpsamplersSSE2(void) {
#endif // WEBP_USE_SSE2
//------------------------------------------------------------------------------
#ifdef FANCY_UPSAMPLING
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
void WebPInitUpsamplersSSE2(void) {
#if defined(WEBP_USE_SSE2)
VP8YUVInitSSE2();
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairSSE2;
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairSSE2;
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairSSE2;
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairSSE2;
WebPUpsamplersKeepAlpha[MODE_RGB] = UpsampleRgbLinePairSSE2;
WebPUpsamplersKeepAlpha[MODE_RGBA] = UpsampleRgbKeepAlphaLinePairSSE2;
WebPUpsamplersKeepAlpha[MODE_BGR] = UpsampleBgrLinePairSSE2;
WebPUpsamplersKeepAlpha[MODE_BGRA] = UpsampleBgrKeepAlphaLinePairSSE2;
#endif // FANCY_UPSAMPLING
#endif // WEBP_USE_SSE2
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
void WebPInitPremultiplySSE2(void) {
#if defined(WEBP_USE_SSE2)
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairSSE2;
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairSSE2;
#endif // WEBP_USE_SSE2
}
#else
// this empty function is to avoid an empty .o
void WebPInitPremultiplySSE2(void) {}
#endif // FANCY_UPSAMPLING
#endif //__SSE2__ || _MSC_VER

View File

@ -1,8 +1,10 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// YUV->RGB conversion function
@ -11,28 +13,26 @@
#include "./yuv.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
enum { YUV_HALF = 1 << (YUV_FIX - 1) };
#if defined(WEBP_YUV_USE_TABLE)
static int done = 0;
static WEBP_INLINE uint8_t clip(int v, int max_value) {
return v < 0 ? 0 : v > max_value ? max_value : v;
}
int16_t VP8kVToR[256], VP8kUToB[256];
int32_t VP8kVToG[256], VP8kUToG[256];
uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
static int done = 0;
static inline uint8_t clip(int v, int max_value) {
return v < 0 ? 0 : v > max_value ? max_value : v;
}
void VP8YUVInit(void) {
int i;
if (done) {
return;
}
#ifndef USE_YUVj
for (i = 0; i < 256; ++i) {
VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
@ -44,9 +44,164 @@ void VP8YUVInit(void) {
VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
}
#else
for (i = 0; i < 256; ++i) {
VP8kVToR[i] = (91881 * (i - 128) + YUV_HALF) >> YUV_FIX;
VP8kUToG[i] = -22554 * (i - 128) + YUV_HALF;
VP8kVToG[i] = -46802 * (i - 128);
VP8kUToB[i] = (116130 * (i - 128) + YUV_HALF) >> YUV_FIX;
}
for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
const int k = i;
VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
}
#endif
done = 1;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#else
void VP8YUVInit(void) {}
#endif // WEBP_YUV_USE_TABLE
//-----------------------------------------------------------------------------
// SSE2 extras
#if defined(WEBP_USE_SSE2)
#ifdef FANCY_UPSAMPLING
#include <emmintrin.h>
#include <string.h> // for memcpy
typedef union { // handy struct for converting SSE2 registers
int32_t i32[4];
uint8_t u8[16];
__m128i m;
} VP8kCstSSE2;
static int done_sse2 = 0;
static VP8kCstSSE2 VP8kUtoRGBA[256], VP8kVtoRGBA[256], VP8kYtoRGBA[256];
void VP8YUVInitSSE2(void) {
if (!done_sse2) {
int i;
for (i = 0; i < 256; ++i) {
VP8kYtoRGBA[i].i32[0] =
VP8kYtoRGBA[i].i32[1] =
VP8kYtoRGBA[i].i32[2] = (i - 16) * kYScale + YUV_HALF2;
VP8kYtoRGBA[i].i32[3] = 0xff << YUV_FIX2;
VP8kUtoRGBA[i].i32[0] = 0;
VP8kUtoRGBA[i].i32[1] = -kUToG * (i - 128);
VP8kUtoRGBA[i].i32[2] = kUToB * (i - 128);
VP8kUtoRGBA[i].i32[3] = 0;
VP8kVtoRGBA[i].i32[0] = kVToR * (i - 128);
VP8kVtoRGBA[i].i32[1] = -kVToG * (i - 128);
VP8kVtoRGBA[i].i32[2] = 0;
VP8kVtoRGBA[i].i32[3] = 0;
}
done_sse2 = 1;
}
}
static WEBP_INLINE __m128i VP8GetRGBA32b(int y, int u, int v) {
const __m128i u_part = _mm_loadu_si128(&VP8kUtoRGBA[u].m);
const __m128i v_part = _mm_loadu_si128(&VP8kVtoRGBA[v].m);
const __m128i y_part = _mm_loadu_si128(&VP8kYtoRGBA[y].m);
const __m128i uv_part = _mm_add_epi32(u_part, v_part);
const __m128i rgba1 = _mm_add_epi32(y_part, uv_part);
const __m128i rgba2 = _mm_srai_epi32(rgba1, YUV_FIX2);
return rgba2;
}
static WEBP_INLINE void VP8YuvToRgbSSE2(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgb) {
const __m128i tmp0 = VP8GetRGBA32b(y, u, v);
const __m128i tmp1 = _mm_packs_epi32(tmp0, tmp0);
const __m128i tmp2 = _mm_packus_epi16(tmp1, tmp1);
// Note: we store 8 bytes at a time, not 3 bytes! -> memory stomp
_mm_storel_epi64((__m128i*)rgb, tmp2);
}
static WEBP_INLINE void VP8YuvToBgrSSE2(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const bgr) {
const __m128i tmp0 = VP8GetRGBA32b(y, u, v);
const __m128i tmp1 = _mm_shuffle_epi32(tmp0, _MM_SHUFFLE(3, 0, 1, 2));
const __m128i tmp2 = _mm_packs_epi32(tmp1, tmp1);
const __m128i tmp3 = _mm_packus_epi16(tmp2, tmp2);
// Note: we store 8 bytes at a time, not 3 bytes! -> memory stomp
_mm_storel_epi64((__m128i*)bgr, tmp3);
}
void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst) {
int n;
for (n = 0; n < 32; n += 4) {
const __m128i tmp0_1 = VP8GetRGBA32b(y[n + 0], u[n + 0], v[n + 0]);
const __m128i tmp0_2 = VP8GetRGBA32b(y[n + 1], u[n + 1], v[n + 1]);
const __m128i tmp0_3 = VP8GetRGBA32b(y[n + 2], u[n + 2], v[n + 2]);
const __m128i tmp0_4 = VP8GetRGBA32b(y[n + 3], u[n + 3], v[n + 3]);
const __m128i tmp1_1 = _mm_packs_epi32(tmp0_1, tmp0_2);
const __m128i tmp1_2 = _mm_packs_epi32(tmp0_3, tmp0_4);
const __m128i tmp2 = _mm_packus_epi16(tmp1_1, tmp1_2);
_mm_storeu_si128((__m128i*)dst, tmp2);
dst += 4 * 4;
}
}
void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst) {
int n;
for (n = 0; n < 32; n += 2) {
const __m128i tmp0_1 = VP8GetRGBA32b(y[n + 0], u[n + 0], v[n + 0]);
const __m128i tmp0_2 = VP8GetRGBA32b(y[n + 1], u[n + 1], v[n + 1]);
const __m128i tmp1_1 = _mm_shuffle_epi32(tmp0_1, _MM_SHUFFLE(3, 0, 1, 2));
const __m128i tmp1_2 = _mm_shuffle_epi32(tmp0_2, _MM_SHUFFLE(3, 0, 1, 2));
const __m128i tmp2_1 = _mm_packs_epi32(tmp1_1, tmp1_2);
const __m128i tmp3 = _mm_packus_epi16(tmp2_1, tmp2_1);
_mm_storel_epi64((__m128i*)dst, tmp3);
dst += 4 * 2;
}
}
void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst) {
int n;
uint8_t tmp0[2 * 3 + 5 + 15];
uint8_t* const tmp = (uint8_t*)((uintptr_t)(tmp0 + 15) & ~15); // align
for (n = 0; n < 30; ++n) { // we directly stomp the *dst memory
VP8YuvToRgbSSE2(y[n], u[n], v[n], dst + n * 3);
}
// Last two pixels are special: we write in a tmp buffer before sending
// to dst.
VP8YuvToRgbSSE2(y[n + 0], u[n + 0], v[n + 0], tmp + 0);
VP8YuvToRgbSSE2(y[n + 1], u[n + 1], v[n + 1], tmp + 3);
memcpy(dst + n * 3, tmp, 2 * 3);
}
void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst) {
int n;
uint8_t tmp0[2 * 3 + 5 + 15];
uint8_t* const tmp = (uint8_t*)((uintptr_t)(tmp0 + 15) & ~15); // align
for (n = 0; n < 30; ++n) {
VP8YuvToBgrSSE2(y[n], u[n], v[n], dst + n * 3);
}
VP8YuvToBgrSSE2(y[n + 0], u[n + 0], v[n + 0], tmp + 0);
VP8YuvToBgrSSE2(y[n + 1], u[n + 1], v[n + 1], tmp + 3);
memcpy(dst + n * 3, tmp, 2 * 3);
}
#else
void VP8YUVInitSSE2(void) {}
#endif // FANCY_UPSAMPLING
#endif // WEBP_USE_SSE2

View File

@ -1,34 +1,166 @@
// Copyright 2010 Google Inc.
// Copyright 2010 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// inline YUV->RGB conversion function
// inline YUV<->RGB conversion function
//
// The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
// More information at: http://en.wikipedia.org/wiki/YCbCr
// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
// We use 16bit fixed point operations for RGB->YUV conversion (YUV_FIX).
//
// For the Y'CbCr to RGB conversion, the BT.601 specification reads:
// R = 1.164 * (Y-16) + 1.596 * (V-128)
// G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128)
// B = 1.164 * (Y-16) + 2.018 * (U-128)
// where Y is in the [16,235] range, and U/V in the [16,240] range.
// In the table-lookup version (WEBP_YUV_USE_TABLE), the common factor
// "1.164 * (Y-16)" can be handled as an offset in the VP8kClip[] table.
// So in this case the formulae should read:
// R = 1.164 * [Y + 1.371 * (V-128) ] - 18.624
// G = 1.164 * [Y - 0.698 * (V-128) - 0.336 * (U-128)] - 18.624
// B = 1.164 * [Y + 1.733 * (U-128)] - 18.624
// once factorized.
// For YUV->RGB conversion, only 14bit fixed precision is used (YUV_FIX2).
// That's the maximum possible for a convenient ARM implementation.
//
// Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_DSP_YUV_H_
#define WEBP_DSP_YUV_H_
#include "../webp/decode_vp8.h"
#include "./dsp.h"
#include "../dec/decode_vp8.h"
#if defined(__cplusplus) || defined(c_plusplus)
// Define the following to use the LUT-based code:
// #define WEBP_YUV_USE_TABLE
#if defined(WEBP_EXPERIMENTAL_FEATURES)
// Do NOT activate this feature for real compression. This is only experimental!
// This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
// This colorspace is close to Rec.601's Y'CbCr model with the notable
// difference of allowing larger range for luma/chroma.
// See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its
// difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
// #define USE_YUVj
#endif
//------------------------------------------------------------------------------
// YUV -> RGB conversion
#ifdef __cplusplus
extern "C" {
#endif
enum { YUV_FIX = 16, // fixed-point precision
YUV_RANGE_MIN = -227, // min value of r/g/b output
YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output
enum {
YUV_FIX = 16, // fixed-point precision for RGB->YUV
YUV_HALF = 1 << (YUV_FIX - 1),
YUV_MASK = (256 << YUV_FIX) - 1,
YUV_RANGE_MIN = -227, // min value of r/g/b output
YUV_RANGE_MAX = 256 + 226, // max value of r/g/b output
YUV_FIX2 = 14, // fixed-point precision for YUV->RGB
YUV_HALF2 = 1 << (YUV_FIX2 - 1),
YUV_MASK2 = (256 << YUV_FIX2) - 1
};
// These constants are 14b fixed-point version of ITU-R BT.601 constants.
#define kYScale 19077 // 1.164 = 255 / 219
#define kVToR 26149 // 1.596 = 255 / 112 * 0.701
#define kUToG 6419 // 0.391 = 255 / 112 * 0.886 * 0.114 / 0.587
#define kVToG 13320 // 0.813 = 255 / 112 * 0.701 * 0.299 / 0.587
#define kUToB 33050 // 2.018 = 255 / 112 * 0.886
#define kRCst (-kYScale * 16 - kVToR * 128 + YUV_HALF2)
#define kGCst (-kYScale * 16 + kUToG * 128 + kVToG * 128 + YUV_HALF2)
#define kBCst (-kYScale * 16 - kUToB * 128 + YUV_HALF2)
//------------------------------------------------------------------------------
#if !defined(WEBP_YUV_USE_TABLE)
// slower on x86 by ~7-8%, but bit-exact with the SSE2 version
static WEBP_INLINE int VP8Clip8(int v) {
return ((v & ~YUV_MASK2) == 0) ? (v >> YUV_FIX2) : (v < 0) ? 0 : 255;
}
static WEBP_INLINE int VP8YUVToR(int y, int v) {
return VP8Clip8(kYScale * y + kVToR * v + kRCst);
}
static WEBP_INLINE int VP8YUVToG(int y, int u, int v) {
return VP8Clip8(kYScale * y - kUToG * u - kVToG * v + kGCst);
}
static WEBP_INLINE int VP8YUVToB(int y, int u) {
return VP8Clip8(kYScale * y + kUToB * u + kBCst);
}
static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
uint8_t* const rgb) {
rgb[0] = VP8YUVToR(y, v);
rgb[1] = VP8YUVToG(y, u, v);
rgb[2] = VP8YUVToB(y, u);
}
static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
uint8_t* const bgr) {
bgr[0] = VP8YUVToB(y, u);
bgr[1] = VP8YUVToG(y, u, v);
bgr[2] = VP8YUVToR(y, v);
}
static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
uint8_t* const rgb) {
const int r = VP8YUVToR(y, v); // 5 usable bits
const int g = VP8YUVToG(y, u, v); // 6 usable bits
const int b = VP8YUVToB(y, u); // 5 usable bits
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 WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
uint8_t* const argb) {
const int r = VP8YUVToR(y, v); // 4 usable bits
const int g = VP8YUVToG(y, u, v); // 4 usable bits
const int b = VP8YUVToB(y, u); // 4 usable bits
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
}
#else
// Table-based version, not totally equivalent to the SSE2 version.
// Rounding diff is only +/-1 though.
extern int16_t VP8kVToR[256], VP8kUToB[256];
extern int32_t VP8kVToG[256], VP8kUToG[256];
extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
static inline void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgb) {
static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
uint8_t* const rgb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
@ -37,48 +169,8 @@ static inline void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
}
static inline void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
rgb[0] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
(VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
rgb[1] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
(VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
}
static inline void VP8YuvToArgbKeepA(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
// Don't update Aplha (argb[0])
VP8YuvToRgb(y, u, v, argb + 1);
}
static inline void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
argb[0] = 0xff;
VP8YuvToArgbKeepA(y, u, v, argb);
}
static inline void VP8YuvToRgba4444KeepA(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
// Don't update Aplha (last 4 bits of argb[1])
argb[0] = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
argb[1] = (argb[1] & 0x0f) | (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4);
}
static inline void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
argb[1] = 0x0f;
VP8YuvToRgba4444KeepA(y, u, v, argb);
}
static inline void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const bgr) {
static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
uint8_t* const bgr) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
@ -87,14 +179,60 @@ static inline void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
}
static inline void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const bgra) {
static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
uint8_t* const rgb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
const int rg = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
(VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
const int gb = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
(VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
#ifdef WEBP_SWAP_16BIT_CSP
rgb[0] = gb;
rgb[1] = rg;
#else
rgb[0] = rg;
rgb[1] = gb;
#endif
}
static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
uint8_t* const argb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
const int rg = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
const int ba = (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4) | 0x0f;
#ifdef WEBP_SWAP_16BIT_CSP
argb[0] = ba;
argb[1] = rg;
#else
argb[0] = rg;
argb[1] = ba;
#endif
}
#endif // WEBP_YUV_USE_TABLE
//-----------------------------------------------------------------------------
// Alpha handling variants
static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
argb[0] = 0xff;
VP8YuvToRgb(y, u, v, argb + 1);
}
static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const bgra) {
VP8YuvToBgr(y, u, v, bgra);
bgra[3] = 0xff;
}
static inline void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgba) {
static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgba) {
VP8YuvToRgb(y, u, v, rgba);
rgba[3] = 0xff;
}
@ -102,7 +240,77 @@ static inline void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
// Must be called before everything, to initialize the tables.
void VP8YUVInit(void);
#if defined(__cplusplus) || defined(c_plusplus)
//-----------------------------------------------------------------------------
// SSE2 extra functions (mostly for upsampling_sse2.c)
#if defined(WEBP_USE_SSE2)
#if defined(FANCY_UPSAMPLING)
// Process 32 pixels and store the result (24b or 32b per pixel) in *dst.
void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst);
void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst);
void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst);
void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst);
#endif // FANCY_UPSAMPLING
// Must be called to initialize tables before using the functions.
void VP8YUVInitSSE2(void);
#endif // WEBP_USE_SSE2
//------------------------------------------------------------------------------
// RGB -> YUV conversion
// Stub functions that can be called with various rounding values:
static WEBP_INLINE int VP8ClipUV(int uv, int rounding) {
uv = (uv + rounding + (128 << (YUV_FIX + 2))) >> (YUV_FIX + 2);
return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
}
#ifndef USE_YUVj
static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
const int luma = 16839 * r + 33059 * g + 6420 * b;
return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX; // no need to clip
}
static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
const int u = -9719 * r - 19081 * g + 28800 * b;
return VP8ClipUV(u, rounding);
}
static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
const int v = +28800 * r - 24116 * g - 4684 * b;
return VP8ClipUV(v, rounding);
}
#else
// This JPEG-YUV colorspace, only for comparison!
// These are also 16bit precision coefficients from Rec.601, but with full
// [0..255] output range.
static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
const int luma = 19595 * r + 38470 * g + 7471 * b;
return (luma + rounding) >> YUV_FIX; // no need to clip
}
static WEBP_INLINE int VP8_RGB_TO_U(int r, int g, int b, int rounding) {
const int u = -11058 * r - 21710 * g + 32768 * b;
return VP8ClipUV(u, rounding);
}
static WEBP_INLINE int VP8_RGB_TO_V(int r, int g, int b, int rounding) {
const int v = 32768 * r - 27439 * g - 5329 * b;
return VP8ClipUV(v, rounding);
}
#endif // USE_YUVj
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,13 +1,33 @@
AM_CPPFLAGS = -I$(top_srcdir)/src
libwebpencode_la_SOURCES = analysis.c config.c cost.c cost.h filter.c \
frame.c iterator.c picture.c quant.c \
syntax.c tree.c vp8enci.h webpenc.c alpha.c \
layer.c
libwebpencode_la_LDFLAGS = -version-info 2:0:0 -lm
libwebpencode_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE)
libwebpencodeinclude_HEADERS = ../webp/encode.h ../webp/types.h
libwebpencodeincludedir = $(includedir)/webp
noinst_HEADERS = cost.h vp8enci.h
noinst_LTLIBRARIES = libwebpencode.la
libwebpencode_la_SOURCES =
libwebpencode_la_SOURCES += alpha.c
libwebpencode_la_SOURCES += analysis.c
libwebpencode_la_SOURCES += backward_references.c
libwebpencode_la_SOURCES += config.c
libwebpencode_la_SOURCES += cost.c
libwebpencode_la_SOURCES += cost.h
libwebpencode_la_SOURCES += filter.c
libwebpencode_la_SOURCES += frame.c
libwebpencode_la_SOURCES += histogram.c
libwebpencode_la_SOURCES += iterator.c
libwebpencode_la_SOURCES += layer.c
libwebpencode_la_SOURCES += picture.c
libwebpencode_la_SOURCES += quant.c
libwebpencode_la_SOURCES += syntax.c
libwebpencode_la_SOURCES += token.c
libwebpencode_la_SOURCES += tree.c
libwebpencode_la_SOURCES += vp8enci.h
libwebpencode_la_SOURCES += vp8l.c
libwebpencode_la_SOURCES += webpenc.c
libwebpencodeinclude_HEADERS =
libwebpencodeinclude_HEADERS += ../webp/encode.h
libwebpencodeinclude_HEADERS += ../webp/types.h
noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h
libwebpencode_la_LDFLAGS = -lm
libwebpencode_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE)
libwebpencodeincludedir = $(includedir)/webp

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Alpha-plane compression.
@ -11,104 +13,398 @@
#include <assert.h>
#include <stdlib.h>
#include "vp8enci.h"
#ifdef WEBP_EXPERIMENTAL_FEATURES
#include "zlib.h"
#endif
#include "./vp8enci.h"
#include "../utils/filters.h"
#include "../utils/quant_levels.h"
#include "../webp/format_constants.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
// -----------------------------------------------------------------------------
// Encodes the given alpha data via specified compression method 'method'.
// The pre-processing (quantization) is performed if 'quality' is less than 100.
// For such cases, the encoding is lossy. The valid range is [0, 100] for
// 'quality' and [0, 1] for 'method':
// 'method = 0' - No compression;
// 'method = 1' - Use lossless coder on the alpha plane only
// 'filter' values [0, 4] correspond to prediction modes none, horizontal,
// vertical & gradient filters. The prediction mode 4 will try all the
// prediction modes 0 to 3 and pick the best one.
// 'effort_level': specifies how much effort must be spent to try and reduce
// the compressed output size. In range 0 (quick) to 6 (slow).
//
// 'output' corresponds to the buffer containing compressed alpha data.
// This buffer is allocated by this method and caller should call
// free(*output) when done.
// 'output_size' corresponds to size of this compressed alpha buffer.
//
// Returns 1 on successfully encoding the alpha and
// 0 if either:
// invalid quality or method, or
// memory allocation for the compressed data fails.
#ifdef WEBP_EXPERIMENTAL_FEATURES
#include "../enc/vp8li.h"
#define CHUNK_SIZE 8192
static int EncodeLossless(const uint8_t* const data, int width, int height,
int effort_level, // in [0..6] range
VP8BitWriter* const bw,
WebPAuxStats* const stats) {
int ok = 0;
WebPConfig config;
WebPPicture picture;
VP8LBitWriter tmp_bw;
WebPPictureInit(&picture);
picture.width = width;
picture.height = height;
picture.use_argb = 1;
picture.stats = stats;
if (!WebPPictureAlloc(&picture)) return 0;
// Transfer the alpha values to the green channel.
{
int i, j;
uint32_t* dst = picture.argb;
const uint8_t* src = data;
for (j = 0; j < picture.height; ++j) {
for (i = 0; i < picture.width; ++i) {
dst[i] = src[i] << 8; // we leave A/R/B channels zero'd.
}
src += width;
dst += picture.argb_stride;
}
}
WebPConfigInit(&config);
config.lossless = 1;
config.method = effort_level; // impact is very small
// Set a low default quality for encoding alpha. Ensure that Alpha quality at
// lower methods (3 and below) is less than the threshold for triggering
// costly 'BackwardReferencesTraceBackwards'.
config.quality = 8.f * effort_level;
assert(config.quality >= 0 && config.quality <= 100.f);
ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3);
ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK);
WebPPictureFree(&picture);
if (ok) {
const uint8_t* const buffer = VP8LBitWriterFinish(&tmp_bw);
const size_t buffer_size = VP8LBitWriterNumBytes(&tmp_bw);
VP8BitWriterAppend(bw, buffer, buffer_size);
}
VP8LBitWriterDestroy(&tmp_bw);
return ok && !bw->error_;
}
// -----------------------------------------------------------------------------
// Small struct to hold the result of a filter mode compression attempt.
typedef struct {
size_t score;
VP8BitWriter bw;
WebPAuxStats stats;
} FilterTrial;
// This function always returns an initialized 'bw' object, even upon error.
static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
int method, int filter, int reduce_levels,
int effort_level, // in [0..6] range
uint8_t* const tmp_alpha,
FilterTrial* result) {
int ok = 0;
const uint8_t* alpha_src;
WebPFilterFunc filter_func;
uint8_t header;
size_t expected_size;
const size_t data_size = width * height;
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
assert(filter >= 0 && filter < WEBP_FILTER_LAST);
assert(method >= ALPHA_NO_COMPRESSION);
assert(method <= ALPHA_LOSSLESS_COMPRESSION);
assert(sizeof(header) == ALPHA_HEADER_LEN);
// TODO(skal): have a common function and #define's to validate alpha params.
expected_size =
(method == ALPHA_NO_COMPRESSION) ? (ALPHA_HEADER_LEN + data_size)
: (data_size >> 5);
header = method | (filter << 2);
if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
VP8BitWriterInit(&result->bw, expected_size);
VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
filter_func = WebPFilters[filter];
if (filter_func != NULL) {
filter_func(data, width, height, width, tmp_alpha);
alpha_src = tmp_alpha;
} else {
alpha_src = data;
}
if (method == ALPHA_NO_COMPRESSION) {
ok = VP8BitWriterAppend(&result->bw, alpha_src, width * height);
ok = ok && !result->bw.error_;
} else {
ok = EncodeLossless(alpha_src, width, height, effort_level,
&result->bw, &result->stats);
VP8BitWriterFinish(&result->bw);
}
result->score = VP8BitWriterSize(&result->bw);
return ok;
}
// -----------------------------------------------------------------------------
// TODO(skal): move to dsp/ ?
static void CopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride, int width, int height) {
while (height-- > 0) {
memcpy(dst, src, width);
src += src_stride;
dst += dst_stride;
}
}
static int GetNumColors(const uint8_t* data, int width, int height,
int stride) {
int j;
int colors = 0;
uint8_t color[256] = { 0 };
for (j = 0; j < height; ++j) {
int i;
const uint8_t* const p = data + j * stride;
for (i = 0; i < width; ++i) {
color[p[i]] = 1;
}
}
for (j = 0; j < 256; ++j) {
if (color[j] > 0) ++colors;
}
return colors;
}
#define FILTER_TRY_NONE (1 << WEBP_FILTER_NONE)
#define FILTER_TRY_ALL ((1 << WEBP_FILTER_LAST) - 1)
// Given the input 'filter' option, return an OR'd bit-set of filters to try.
static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height,
int filter, int effort_level) {
uint32_t bit_map = 0U;
if (filter == WEBP_FILTER_FAST) {
// Quick estimate of the best candidate.
int try_filter_none = (effort_level > 3);
const int kMinColorsForFilterNone = 16;
const int kMaxColorsForFilterNone = 192;
const int num_colors = GetNumColors(alpha, width, height, width);
// For low number of colors, NONE yields better compression.
filter = (num_colors <= kMinColorsForFilterNone) ? WEBP_FILTER_NONE :
EstimateBestFilter(alpha, width, height, width);
bit_map |= 1 << filter;
// For large number of colors, try FILTER_NONE in addition to the best
// filter as well.
if (try_filter_none || num_colors > kMaxColorsForFilterNone) {
bit_map |= FILTER_TRY_NONE;
}
} else if (filter == WEBP_FILTER_NONE) {
bit_map = FILTER_TRY_NONE;
} else { // WEBP_FILTER_BEST -> try all
bit_map = FILTER_TRY_ALL;
}
return bit_map;
}
static void InitFilterTrial(FilterTrial* const score) {
score->score = (size_t)~0U;
VP8BitWriterInit(&score->bw, 0);
}
static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height,
size_t data_size, int method, int filter,
int reduce_levels, int effort_level,
uint8_t** const output,
size_t* const output_size,
WebPAuxStats* const stats) {
int ok = 1;
FilterTrial best;
uint32_t try_map =
GetFilterMap(alpha, width, height, filter, effort_level);
InitFilterTrial(&best);
if (try_map != FILTER_TRY_NONE) {
uint8_t* filtered_alpha = (uint8_t*)malloc(data_size);
if (filtered_alpha == NULL) return 0;
for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) {
if (try_map & 1) {
FilterTrial trial;
ok = EncodeAlphaInternal(alpha, width, height, method, filter,
reduce_levels, effort_level, filtered_alpha,
&trial);
if (ok && trial.score < best.score) {
VP8BitWriterWipeOut(&best.bw);
best = trial;
} else {
VP8BitWriterWipeOut(&trial.bw);
}
}
}
free(filtered_alpha);
} else {
ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE,
reduce_levels, effort_level, NULL, &best);
}
if (ok) {
if (stats != NULL) *stats = best.stats;
*output_size = VP8BitWriterSize(&best.bw);
*output = VP8BitWriterBuf(&best.bw);
} else {
VP8BitWriterWipeOut(&best.bw);
}
return ok;
}
static int EncodeAlpha(VP8Encoder* const enc,
int quality, int method, int filter,
int effort_level,
uint8_t** const output, size_t* const output_size) {
const WebPPicture* const pic = enc->pic_;
const int width = pic->width;
const int height = pic->height;
uint8_t* quant_alpha = NULL;
const size_t data_size = width * height;
uint64_t sse = 0;
int ok = 1;
const int reduce_levels = (quality < 100);
// quick sanity checks
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
assert(enc != NULL && pic != NULL && pic->a != NULL);
assert(output != NULL && output_size != NULL);
assert(width > 0 && height > 0);
assert(pic->a_stride >= width);
assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST);
if (quality < 0 || quality > 100) {
return 0;
}
if (method < ALPHA_NO_COMPRESSION || method > ALPHA_LOSSLESS_COMPRESSION) {
return 0;
}
if (method == ALPHA_NO_COMPRESSION) {
// Don't filter, as filtering will make no impact on compressed size.
filter = WEBP_FILTER_NONE;
}
quant_alpha = (uint8_t*)malloc(data_size);
if (quant_alpha == NULL) {
return 0;
}
// Extract alpha data (width x height) from raw_data (stride x height).
CopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height);
if (reduce_levels) { // No Quantization required for 'quality = 100'.
// 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence
// mapped to moderate quality 70. Hence Quality:[0, 70] -> Levels:[2, 16]
// and Quality:]70, 100] -> Levels:]16, 256].
const int alpha_levels = (quality <= 70) ? (2 + quality / 5)
: (16 + (quality - 70) * 8);
ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse);
}
if (ok) {
ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method,
filter, reduce_levels, effort_level, output,
output_size, pic->stats);
if (pic->stats != NULL) { // need stats?
pic->stats->coded_size += (int)(*output_size);
enc->sse_[3] = sse;
}
}
free(quant_alpha);
return ok;
}
//------------------------------------------------------------------------------
// Main calls
static int CompressAlpha(const uint8_t* data, size_t data_size,
uint8_t** output, size_t* output_size,
int algo) {
int ret = Z_OK;
z_stream strm;
unsigned char chunk[CHUNK_SIZE];
*output = NULL;
*output_size = 0;
memset(&strm, 0, sizeof(strm));
if (deflateInit(&strm, algo ? Z_BEST_SPEED : Z_BEST_COMPRESSION) != Z_OK) {
static int CompressAlphaJob(VP8Encoder* const enc, void* dummy) {
const WebPConfig* config = enc->config_;
uint8_t* alpha_data = NULL;
size_t alpha_size = 0;
const int effort_level = config->method; // maps to [0..6]
const WEBP_FILTER_TYPE filter =
(config->alpha_filtering == 0) ? WEBP_FILTER_NONE :
(config->alpha_filtering == 1) ? WEBP_FILTER_FAST :
WEBP_FILTER_BEST;
if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression,
filter, effort_level, &alpha_data, &alpha_size)) {
return 0;
}
strm.next_in = (unsigned char*)data;
strm.avail_in = data_size;
do {
size_t size_out;
strm.next_out = chunk;
strm.avail_out = CHUNK_SIZE;
ret = deflate(&strm, Z_FINISH);
if (ret == Z_STREAM_ERROR) {
break;
}
size_out = CHUNK_SIZE - strm.avail_out;
if (size_out) {
size_t new_size = *output_size + size_out;
uint8_t* new_output = realloc(*output, new_size);
if (new_output == NULL) {
ret = Z_MEM_ERROR;
break;
}
memcpy(new_output + *output_size, chunk, size_out);
*output_size = new_size;
*output = new_output;
}
} while (ret != Z_STREAM_END || strm.avail_out == 0);
deflateEnd(&strm);
if (ret != Z_STREAM_END) {
free(*output);
output_size = 0;
if (alpha_size != (uint32_t)alpha_size) { // Sanity check.
free(alpha_data);
return 0;
}
enc->alpha_data_size_ = (uint32_t)alpha_size;
enc->alpha_data_ = alpha_data;
(void)dummy;
return 1;
}
#endif /* WEBP_EXPERIMENTAL_FEATURES */
void VP8EncInitAlpha(VP8Encoder* enc) {
enc->has_alpha_ = (enc->pic_->a != NULL);
void VP8EncInitAlpha(VP8Encoder* const enc) {
enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_);
enc->alpha_data_ = NULL;
enc->alpha_data_size_ = 0;
if (enc->thread_level_ > 0) {
WebPWorker* const worker = &enc->alpha_worker_;
WebPWorkerInit(worker);
worker->data1 = enc;
worker->data2 = NULL;
worker->hook = (WebPWorkerHook)CompressAlphaJob;
}
}
void VP8EncCodeAlphaBlock(VP8EncIterator* it) {
(void)it;
// Nothing for now. We just ZLIB-compress in the end.
}
int VP8EncFinishAlpha(VP8Encoder* enc) {
int VP8EncStartAlpha(VP8Encoder* const enc) {
if (enc->has_alpha_) {
#ifdef WEBP_EXPERIMENTAL_FEATURES
const WebPPicture* pic = enc->pic_;
assert(pic->a);
if (!CompressAlpha(pic->a, pic->width * pic->height,
&enc->alpha_data_, &enc->alpha_data_size_,
enc->config_->alpha_compression)) {
return 0;
if (enc->thread_level_ > 0) {
WebPWorker* const worker = &enc->alpha_worker_;
if (!WebPWorkerReset(worker)) { // Makes sure worker is good to go.
return 0;
}
WebPWorkerLaunch(worker);
return 1;
} else {
return CompressAlphaJob(enc, NULL); // just do the job right away
}
#endif
}
return 1;
}
void VP8EncDeleteAlpha(VP8Encoder* enc) {
int VP8EncFinishAlpha(VP8Encoder* const enc) {
if (enc->has_alpha_) {
if (enc->thread_level_ > 0) {
WebPWorker* const worker = &enc->alpha_worker_;
if (!WebPWorkerSync(worker)) return 0; // error
}
}
return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
}
int VP8EncDeleteAlpha(VP8Encoder* const enc) {
int ok = 1;
if (enc->thread_level_ > 0) {
WebPWorker* const worker = &enc->alpha_worker_;
ok = WebPWorkerSync(worker); // finish anything left in flight
WebPWorkerEnd(worker); // still need to end the worker, even if !ok
}
free(enc->alpha_data_);
enc->alpha_data_ = NULL;
enc->alpha_data_size_ = 0;
enc->has_alpha_ = 0;
return ok;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Macroblock analysis
@ -13,19 +15,12 @@
#include <string.h>
#include <assert.h>
#include "vp8enci.h"
#include "cost.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "./vp8enci.h"
#include "./cost.h"
#include "../utils/utils.h"
#define MAX_ITERS_K_MEANS 6
static int ClipAlpha(int alpha) {
return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
}
//------------------------------------------------------------------------------
// Smooth the segment map by replacing isolated block by the majority of its
// neighbours.
@ -35,7 +30,8 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
const int w = enc->mb_w_;
const int h = enc->mb_h_;
const int majority_cnt_3_x_3_grid = 5;
uint8_t* tmp = (uint8_t*)malloc(w * h * sizeof(uint8_t));
uint8_t* const tmp = (uint8_t*)WebPSafeMalloc((uint64_t)w * h, sizeof(*tmp));
assert((uint64_t)(w * h) == (uint64_t)w * h); // no overflow, as per spec
if (tmp == NULL) return;
for (y = 1; y < h - 1; ++y) {
@ -55,6 +51,7 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
if (cnt[n] >= majority_cnt_3_x_3_grid) {
majority_seg = n;
break;
}
}
tmp[x + y * w] = majority_seg;
@ -70,50 +67,10 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
}
//------------------------------------------------------------------------------
// Finalize Segment probability based on the coding tree
// set segment susceptibility alpha_ / beta_
static int GetProba(int a, int b) {
int proba;
const int total = a + b;
if (total == 0) return 255; // that's the default probability.
proba = (255 * a + total / 2) / total;
return proba;
}
static void SetSegmentProbas(VP8Encoder* const enc) {
int p[NUM_MB_SEGMENTS] = { 0 };
int n;
for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
const VP8MBInfo* const mb = &enc->mb_info_[n];
p[mb->segment_]++;
}
if (enc->pic_->stats) {
for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
enc->pic_->stats->segment_size[n] = p[n];
}
}
if (enc->segment_hdr_.num_segments_ > 1) {
uint8_t* const probas = enc->proba_.segments_;
probas[0] = GetProba(p[0] + p[1], p[2] + p[3]);
probas[1] = GetProba(p[0], p[1]);
probas[2] = GetProba(p[2], p[3]);
enc->segment_hdr_.update_map_ =
(probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255);
enc->segment_hdr_.size_ =
p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) +
p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) +
p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) +
p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2]));
} else {
enc->segment_hdr_.update_map_ = 0;
enc->segment_hdr_.size_ = 0;
}
}
static inline int clip(int v, int m, int M) {
return v < m ? m : v > M ? M : v;
static WEBP_INLINE int clip(int v, int m, int M) {
return (v < m) ? m : (v > M) ? M : v;
}
static void SetSegmentAlphas(VP8Encoder* const enc,
@ -139,29 +96,73 @@ static void SetSegmentAlphas(VP8Encoder* const enc,
}
}
//------------------------------------------------------------------------------
// Compute susceptibility based on DCT-coeff histograms:
// the higher, the "easier" the macroblock is to compress.
#define MAX_ALPHA 255 // 8b of precision for susceptibilities.
#define ALPHA_SCALE (2 * MAX_ALPHA) // scaling factor for alpha.
#define DEFAULT_ALPHA (-1)
#define IS_BETTER_ALPHA(alpha, best_alpha) ((alpha) > (best_alpha))
static int FinalAlphaValue(int alpha) {
alpha = MAX_ALPHA - alpha;
return clip(alpha, 0, MAX_ALPHA);
}
static int GetAlpha(const VP8Histogram* const histo) {
int max_value = 0, last_non_zero = 1;
int k;
int alpha;
for (k = 0; k <= MAX_COEFF_THRESH; ++k) {
const int value = histo->distribution[k];
if (value > 0) {
if (value > max_value) max_value = value;
last_non_zero = k;
}
}
// 'alpha' will later be clipped to [0..MAX_ALPHA] range, clamping outer
// values which happen to be mostly noise. This leaves the maximum precision
// for handling the useful small values which contribute most.
alpha = (max_value > 1) ? ALPHA_SCALE * last_non_zero / max_value : 0;
return alpha;
}
static void MergeHistograms(const VP8Histogram* const in,
VP8Histogram* const out) {
int i;
for (i = 0; i <= MAX_COEFF_THRESH; ++i) {
out->distribution[i] += in->distribution[i];
}
}
//------------------------------------------------------------------------------
// Simplified k-Means, to assign Nb segments based on alpha-histogram
static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
static void AssignSegments(VP8Encoder* const enc,
const int alphas[MAX_ALPHA + 1]) {
const int nb = enc->segment_hdr_.num_segments_;
int centers[NUM_MB_SEGMENTS];
int weighted_average;
int map[256];
int weighted_average = 0;
int map[MAX_ALPHA + 1];
int a, n, k;
int min_a = 0, max_a = 255, range_a;
int min_a = 0, max_a = MAX_ALPHA, range_a;
// 'int' type is ok for histo, and won't overflow
int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS];
assert(nb >= 1);
// bracket the input
for (n = 0; n < 256 && alphas[n] == 0; ++n) {}
for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {}
min_a = n;
for (n = 255; n > min_a && alphas[n] == 0; --n) {}
for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {}
max_a = n;
range_a = max_a - min_a;
// Spread initial centers evenly
for (n = 1, k = 0; n < 2 * nb; n += 2) {
centers[k++] = min_a + (n * range_a) / (2 * nb);
for (k = 0, n = 1; k < nb; ++k, n += 2) {
assert(n < 2 * nb);
centers[k] = min_a + (n * range_a) / (2 * nb);
}
for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough
@ -176,7 +177,7 @@ static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
n = 0; // track the nearest center for current 'a'
for (a = min_a; a <= max_a; ++a) {
if (alphas[a]) {
while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) {
while (n + 1 < nb && abs(a - centers[n + 1]) < abs(a - centers[n])) {
n++;
}
map[a] = n;
@ -206,9 +207,9 @@ static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
// Map each original value to the closest centroid
for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
VP8MBInfo* const mb = &enc->mb_info_[n];
const int a = mb->alpha_;
mb->segment_ = map[a];
mb->alpha_ = centers[map[a]]; // just for the record.
const int alpha = mb->alpha_;
mb->segment_ = map[alpha];
mb->alpha_ = centers[map[alpha]]; // for the record.
}
if (nb > 1) {
@ -216,7 +217,6 @@ static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
if (smooth) SmoothSegmentMap(enc);
}
SetSegmentProbas(enc); // Assign final proba
SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas.
}
@ -225,24 +225,32 @@ static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
// susceptibility and set best modes for this macroblock.
// Segment assignment is done later.
// Number of modes to inspect for alpha_ evaluation. For high-quality settings,
// we don't need to test all the possible modes during the analysis phase.
// Number of modes to inspect for alpha_ evaluation. For high-quality settings
// (method >= FAST_ANALYSIS_METHOD) we don't need to test all the possible modes
// during the analysis phase.
#define FAST_ANALYSIS_METHOD 4 // method above which we do partial analysis
#define MAX_INTRA16_MODE 2
#define MAX_INTRA4_MODE 2
#define MAX_UV_MODE 2
static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA16_MODE : 4;
const int max_mode =
(it->enc_->method_ >= FAST_ANALYSIS_METHOD) ? MAX_INTRA16_MODE
: NUM_PRED_MODES;
int mode;
int best_alpha = -1;
int best_alpha = DEFAULT_ALPHA;
int best_mode = 0;
VP8MakeLuma16Preds(it);
for (mode = 0; mode < max_mode; ++mode) {
const int alpha = VP8CollectHistogram(it->yuv_in_ + Y_OFF,
it->yuv_p_ + VP8I16ModeOffsets[mode],
0, 16);
if (alpha > best_alpha) {
VP8Histogram histo = { { 0 } };
int alpha;
VP8CollectHistogram(it->yuv_in_ + Y_OFF,
it->yuv_p_ + VP8I16ModeOffsets[mode],
0, 16, &histo);
alpha = GetAlpha(&histo);
if (IS_BETTER_ALPHA(alpha, best_alpha)) {
best_alpha = alpha;
best_mode = mode;
}
@ -253,47 +261,64 @@ static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it,
int best_alpha) {
int modes[16];
const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA4_MODE : NUM_BMODES;
int i4_alpha = 0;
uint8_t modes[16];
const int max_mode =
(it->enc_->method_ >= FAST_ANALYSIS_METHOD) ? MAX_INTRA4_MODE
: NUM_BMODES;
int i4_alpha;
VP8Histogram total_histo = { { 0 } };
int cur_histo = 0;
VP8IteratorStartI4(it);
do {
int mode;
int best_mode_alpha = -1;
int best_mode_alpha = DEFAULT_ALPHA;
VP8Histogram histos[2];
const uint8_t* const src = it->yuv_in_ + Y_OFF + VP8Scan[it->i4_];
VP8MakeIntra4Preds(it);
for (mode = 0; mode < max_mode; ++mode) {
const int alpha = VP8CollectHistogram(src,
it->yuv_p_ + VP8I4ModeOffsets[mode],
0, 1);
if (alpha > best_mode_alpha) {
int alpha;
memset(&histos[cur_histo], 0, sizeof(histos[cur_histo]));
VP8CollectHistogram(src, it->yuv_p_ + VP8I4ModeOffsets[mode],
0, 1, &histos[cur_histo]);
alpha = GetAlpha(&histos[cur_histo]);
if (IS_BETTER_ALPHA(alpha, best_mode_alpha)) {
best_mode_alpha = alpha;
modes[it->i4_] = mode;
cur_histo ^= 1; // keep track of best histo so far.
}
}
i4_alpha += best_mode_alpha;
// accumulate best histogram
MergeHistograms(&histos[cur_histo ^ 1], &total_histo);
// Note: we reuse the original samples for predictors
} while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF));
if (i4_alpha > best_alpha) {
i4_alpha = GetAlpha(&total_histo);
if (IS_BETTER_ALPHA(i4_alpha, best_alpha)) {
VP8SetIntra4Mode(it, modes);
best_alpha = ClipAlpha(i4_alpha);
best_alpha = i4_alpha;
}
return best_alpha;
}
static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
int best_alpha = -1;
int best_alpha = DEFAULT_ALPHA;
int best_mode = 0;
const int max_mode = (it->enc_->method_ >= 3) ? MAX_UV_MODE : 4;
const int max_mode =
(it->enc_->method_ >= FAST_ANALYSIS_METHOD) ? MAX_UV_MODE
: NUM_PRED_MODES;
int mode;
VP8MakeChroma8Preds(it);
for (mode = 0; mode < max_mode; ++mode) {
const int alpha = VP8CollectHistogram(it->yuv_in_ + U_OFF,
it->yuv_p_ + VP8UVModeOffsets[mode],
16, 16 + 4 + 4);
if (alpha > best_alpha) {
VP8Histogram histo = { { 0 } };
int alpha;
VP8CollectHistogram(it->yuv_in_ + U_OFF,
it->yuv_p_ + VP8UVModeOffsets[mode],
16, 16 + 4 + 4, &histo);
alpha = GetAlpha(&histo);
if (IS_BETTER_ALPHA(alpha, best_alpha)) {
best_alpha = alpha;
best_mode = mode;
}
@ -303,7 +328,8 @@ static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
}
static void MBAnalyze(VP8EncIterator* const it,
int alphas[256], int* const uv_alpha) {
int alphas[MAX_ALPHA + 1],
int* const alpha, int* const uv_alpha) {
const VP8Encoder* const enc = it->enc_;
int best_alpha, best_uv_alpha;
@ -312,7 +338,7 @@ static void MBAnalyze(VP8EncIterator* const it,
VP8SetSegment(it, 0); // default segment, spec-wise.
best_alpha = MBAnalyzeBestIntra16Mode(it);
if (enc->method_ != 3) {
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.
@ -322,10 +348,22 @@ static void MBAnalyze(VP8EncIterator* const it,
best_uv_alpha = MBAnalyzeBestUVMode(it);
// Final susceptibility mix
best_alpha = (best_alpha + best_uv_alpha + 1) / 2;
best_alpha = (3 * best_alpha + best_uv_alpha + 2) >> 2;
best_alpha = FinalAlphaValue(best_alpha);
alphas[best_alpha]++;
it->mb_->alpha_ = best_alpha; // for later remapping.
// Accumulate for later complexity analysis.
*alpha += best_alpha; // mixed susceptibility (not just luma)
*uv_alpha += best_uv_alpha;
it->mb_->alpha_ = best_alpha; // Informative only.
}
static void DefaultMBInfo(VP8MBInfo* const mb) {
mb->type_ = 1; // I16x16
mb->uv_mode_ = 0;
mb->skip_ = 0; // not skipped
mb->segment_ = 0; // default segment
mb->alpha_ = 0;
}
//------------------------------------------------------------------------------
@ -338,23 +376,122 @@ static void MBAnalyze(VP8EncIterator* const it,
// and decide intra4/intra16, but that's usually almost always a bad choice at
// this stage.
int VP8EncAnalyze(VP8Encoder* const enc) {
int alphas[256] = { 0 };
VP8EncIterator it;
VP8IteratorInit(enc, &it);
static void ResetAllMBInfo(VP8Encoder* const enc) {
int n;
for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
DefaultMBInfo(&enc->mb_info_[n]);
}
// Default susceptibilities.
enc->dqm_[0].alpha_ = 0;
enc->dqm_[0].beta_ = 0;
// Note: we can't compute this alpha_ / uv_alpha_ -> set to default value.
enc->alpha_ = 0;
enc->uv_alpha_ = 0;
do {
VP8IteratorImport(&it);
MBAnalyze(&it, alphas, &enc->uv_alpha_);
// Let's pretend we have perfect lossless reconstruction.
} while (VP8IteratorNext(&it, it.yuv_in_));
enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_;
AssignSegments(enc, alphas);
return 1;
WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
// struct used to collect job result
typedef struct {
WebPWorker worker;
int alphas[MAX_ALPHA + 1];
int alpha, uv_alpha;
VP8EncIterator it;
int delta_progress;
} SegmentJob;
// main work call
static int DoSegmentsJob(SegmentJob* const job, VP8EncIterator* const it) {
int ok = 1;
if (!VP8IteratorIsDone(it)) {
uint8_t tmp[32 + ALIGN_CST];
uint8_t* const scratch = (uint8_t*)DO_ALIGN(tmp);
do {
// Let's pretend we have perfect lossless reconstruction.
VP8IteratorImport(it, scratch);
MBAnalyze(it, job->alphas, &job->alpha, &job->uv_alpha);
ok = VP8IteratorProgress(it, job->delta_progress);
} while (ok && VP8IteratorNext(it));
}
return ok;
}
static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
int i;
for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i];
dst->alpha += src->alpha;
dst->uv_alpha += src->uv_alpha;
}
// initialize the job struct with some TODOs
static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
int start_row, int end_row) {
WebPWorkerInit(&job->worker);
job->worker.data1 = job;
job->worker.data2 = &job->it;
job->worker.hook = (WebPWorkerHook)DoSegmentsJob;
VP8IteratorInit(enc, &job->it);
VP8IteratorSetRow(&job->it, start_row);
VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_);
memset(job->alphas, 0, sizeof(job->alphas));
job->alpha = 0;
job->uv_alpha = 0;
// only one of both jobs can record the progress, since we don't
// expect the user's hook to be multi-thread safe
job->delta_progress = (start_row == 0) ? 20 : 0;
}
// main entry point
int VP8EncAnalyze(VP8Encoder* const enc) {
int ok = 1;
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.
if (do_segments) {
const int last_row = enc->mb_h_;
// We give a little more than a half work to the main thread.
const int split_row = (9 * last_row + 15) >> 4;
const int total_mb = last_row * enc->mb_w_;
#ifdef WEBP_USE_THREAD
const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it
const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow);
#else
const int do_mt = 0;
#endif
SegmentJob main_job;
if (do_mt) {
SegmentJob side_job;
// Note the use of '&' instead of '&&' because we must call the functions
// no matter what.
InitSegmentJob(enc, &main_job, 0, split_row);
InitSegmentJob(enc, &side_job, split_row, last_row);
// we don't need to call Reset() on main_job.worker, since we're calling
// WebPWorkerExecute() on it
ok &= WebPWorkerReset(&side_job.worker);
// launch the two jobs in parallel
if (ok) {
WebPWorkerLaunch(&side_job.worker);
WebPWorkerExecute(&main_job.worker);
ok &= WebPWorkerSync(&side_job.worker);
ok &= WebPWorkerSync(&main_job.worker);
}
WebPWorkerEnd(&side_job.worker);
if (ok) MergeJobs(&side_job, &main_job); // merge results together
} else {
// Even for single-thread case, we use the generic Worker tools.
InitSegmentJob(enc, &main_job, 0, last_row);
WebPWorkerExecute(&main_job.worker);
ok &= WebPWorkerSync(&main_job.worker);
}
WebPWorkerEnd(&main_job.worker);
if (ok) {
enc->alpha_ = main_job.alpha / total_mb;
enc->uv_alpha_ = main_job.uv_alpha / total_mb;
AssignSegments(enc, main_job.alphas);
}
} else { // Use only one default segment.
ResetAllMBInfo(enc);
}
return ok;
}

View File

@ -0,0 +1,894 @@
// 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.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
//
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include "./backward_references.h"
#include "./histogram.h"
#include "../dsp/lossless.h"
#include "../utils/color_cache.h"
#include "../utils/utils.h"
#define VALUES_IN_BYTE 256
#define HASH_BITS 18
#define HASH_SIZE (1 << HASH_BITS)
#define HASH_MULTIPLIER (0xc6a4a7935bd1e995ULL)
// 1M window (4M bytes) minus 120 special codes for short distances.
#define WINDOW_SIZE ((1 << 20) - 120)
// Bounds for the match length.
#define MIN_LENGTH 2
#define MAX_LENGTH 4096
typedef struct {
// Stores the most recently added position with the given hash value.
int32_t hash_to_first_index_[HASH_SIZE];
// chain_[pos] stores the previous position with the same hash value
// for every pixel in the image.
int32_t* chain_;
} HashChain;
// -----------------------------------------------------------------------------
static const uint8_t plane_to_code_lut[128] = {
96, 73, 55, 39, 23, 13, 5, 1, 255, 255, 255, 255, 255, 255, 255, 255,
101, 78, 58, 42, 26, 16, 8, 2, 0, 3, 9, 17, 27, 43, 59, 79,
102, 86, 62, 46, 32, 20, 10, 6, 4, 7, 11, 21, 33, 47, 63, 87,
105, 90, 70, 52, 37, 28, 18, 14, 12, 15, 19, 29, 38, 53, 71, 91,
110, 99, 82, 66, 48, 35, 30, 24, 22, 25, 31, 36, 49, 67, 83, 100,
115, 108, 94, 76, 64, 50, 44, 40, 34, 41, 45, 51, 65, 77, 95, 109,
118, 113, 103, 92, 80, 68, 60, 56, 54, 57, 61, 69, 81, 93, 104, 114,
119, 116, 111, 106, 97, 88, 84, 74, 72, 75, 85, 89, 98, 107, 112, 117
};
static int DistanceToPlaneCode(int xsize, int dist) {
const int yoffset = dist / xsize;
const int xoffset = dist - yoffset * xsize;
if (xoffset <= 8 && yoffset < 8) {
return plane_to_code_lut[yoffset * 16 + 8 - xoffset] + 1;
} else if (xoffset > xsize - 8 && yoffset < 7) {
return plane_to_code_lut[(yoffset + 1) * 16 + 8 + (xsize - xoffset)] + 1;
}
return dist + 120;
}
static WEBP_INLINE int FindMatchLength(const uint32_t* const array1,
const uint32_t* const array2,
const int max_limit) {
int match_len = 0;
while (match_len < max_limit && array1[match_len] == array2[match_len]) {
++match_len;
}
return match_len;
}
// -----------------------------------------------------------------------------
// VP8LBackwardRefs
void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs) {
if (refs != NULL) {
refs->refs = NULL;
refs->size = 0;
refs->max_size = 0;
}
}
void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) {
if (refs != NULL) {
free(refs->refs);
VP8LInitBackwardRefs(refs);
}
}
int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size) {
assert(refs != NULL);
refs->size = 0;
refs->max_size = 0;
refs->refs = (PixOrCopy*)WebPSafeMalloc((uint64_t)max_size,
sizeof(*refs->refs));
if (refs->refs == NULL) return 0;
refs->max_size = max_size;
return 1;
}
// -----------------------------------------------------------------------------
// Hash chains
static WEBP_INLINE uint64_t GetPixPairHash64(const uint32_t* const argb) {
uint64_t key = ((uint64_t)(argb[1]) << 32) | argb[0];
key = (key * HASH_MULTIPLIER) >> (64 - HASH_BITS);
return key;
}
static int HashChainInit(HashChain* const p, int size) {
int i;
p->chain_ = (int*)WebPSafeMalloc((uint64_t)size, sizeof(*p->chain_));
if (p->chain_ == NULL) {
return 0;
}
for (i = 0; i < size; ++i) {
p->chain_[i] = -1;
}
for (i = 0; i < HASH_SIZE; ++i) {
p->hash_to_first_index_[i] = -1;
}
return 1;
}
static void HashChainDelete(HashChain* const p) {
if (p != NULL) {
free(p->chain_);
free(p);
}
}
// Insertion of two pixels at a time.
static void HashChainInsert(HashChain* const p,
const uint32_t* const argb, int pos) {
const uint64_t hash_code = GetPixPairHash64(argb);
p->chain_[pos] = p->hash_to_first_index_[hash_code];
p->hash_to_first_index_[hash_code] = pos;
}
static void GetParamsForHashChainFindCopy(int quality, int xsize,
int cache_bits, int* window_size,
int* iter_pos, int* iter_limit) {
const int iter_mult = (quality < 27) ? 1 : 1 + ((quality - 27) >> 4);
const int iter_neg = -iter_mult * (quality >> 1);
// Limit the backward-ref window size for lower qualities.
const int max_window_size = (quality > 50) ? WINDOW_SIZE
: (quality > 25) ? (xsize << 8)
: (xsize << 4);
assert(xsize > 0);
*window_size = (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE
: max_window_size;
*iter_pos = 8 + (quality >> 3);
// For lower entropy images, the rigorous search loop in HashChainFindCopy
// can be relaxed.
*iter_limit = (cache_bits > 0) ? iter_neg : iter_neg / 2;
}
static int HashChainFindCopy(const HashChain* const p,
int base_position, int xsize_signed,
const uint32_t* const argb, int max_len,
int window_size, int iter_pos, int iter_limit,
int* const distance_ptr,
int* const length_ptr) {
const uint32_t* const argb_start = argb + base_position;
uint64_t best_val = 0;
uint32_t best_length = 1;
uint32_t best_distance = 0;
const uint32_t xsize = (uint32_t)xsize_signed;
const int min_pos =
(base_position > window_size) ? base_position - window_size : 0;
int pos;
assert(xsize > 0);
if (max_len > MAX_LENGTH) {
max_len = MAX_LENGTH;
}
for (pos = p->hash_to_first_index_[GetPixPairHash64(argb_start)];
pos >= min_pos;
pos = p->chain_[pos]) {
uint64_t val;
uint32_t curr_length;
uint32_t distance;
const uint64_t* const ptr1 =
(const uint64_t*)(argb + pos + best_length - 1);
const uint64_t* const ptr2 =
(const uint64_t*)(argb_start + best_length - 1);
if (iter_pos < 0) {
if (iter_pos < iter_limit || best_val >= 0xff0000) {
break;
}
}
--iter_pos;
// Before 'expensive' linear match, check if the two arrays match at the
// current best length index and also for the succeeding elements.
if (*ptr1 != *ptr2) continue;
curr_length = FindMatchLength(argb + pos, argb_start, max_len);
if (curr_length < best_length) continue;
distance = (uint32_t)(base_position - pos);
val = curr_length << 16;
// Favoring 2d locality here gives savings for certain images.
if (distance < 9 * xsize) {
const uint32_t y = distance / xsize;
uint32_t x = distance % xsize;
if (x > (xsize >> 1)) {
x = xsize - x;
}
if (x <= 7) {
val += 9 * 9 + 9 * 9;
val -= y * y + x * x;
}
}
if (best_val < val) {
best_val = val;
best_length = curr_length;
best_distance = distance;
if (curr_length >= (uint32_t)max_len) {
break;
}
if ((best_distance == 1 || distance == xsize) &&
best_length >= 128) {
break;
}
}
}
*distance_ptr = (int)best_distance;
*length_ptr = best_length;
return (best_length >= MIN_LENGTH);
}
static WEBP_INLINE void PushBackCopy(VP8LBackwardRefs* const refs, int length) {
int size = refs->size;
while (length >= MAX_LENGTH) {
refs->refs[size++] = PixOrCopyCreateCopy(1, MAX_LENGTH);
length -= MAX_LENGTH;
}
if (length > 0) {
refs->refs[size++] = PixOrCopyCreateCopy(1, length);
}
refs->size = size;
}
static void BackwardReferencesRle(int xsize, int ysize,
const uint32_t* const argb,
VP8LBackwardRefs* const refs) {
const int pix_count = xsize * ysize;
int match_len = 0;
int i;
refs->size = 0;
PushBackCopy(refs, match_len); // i=0 case
refs->refs[refs->size++] = PixOrCopyCreateLiteral(argb[0]);
for (i = 1; i < pix_count; ++i) {
if (argb[i] == argb[i - 1]) {
++match_len;
} else {
PushBackCopy(refs, match_len);
match_len = 0;
refs->refs[refs->size++] = PixOrCopyCreateLiteral(argb[i]);
}
}
PushBackCopy(refs, match_len);
}
static int BackwardReferencesHashChain(int xsize, int ysize,
const uint32_t* const argb,
int cache_bits, int quality,
VP8LBackwardRefs* const refs) {
int i;
int ok = 0;
int cc_init = 0;
const int use_color_cache = (cache_bits > 0);
const int pix_count = xsize * ysize;
HashChain* const hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
VP8LColorCache hashers;
int window_size = WINDOW_SIZE;
int iter_pos = 1;
int iter_limit = -1;
if (hash_chain == NULL) return 0;
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
}
if (!HashChainInit(hash_chain, pix_count)) goto Error;
refs->size = 0;
GetParamsForHashChainFindCopy(quality, xsize, cache_bits,
&window_size, &iter_pos, &iter_limit);
for (i = 0; i < pix_count; ) {
// Alternative#1: Code the pixels starting at 'i' using backward reference.
int offset = 0;
int len = 0;
if (i < pix_count - 1) { // FindCopy(i,..) reads pixels at [i] and [i + 1].
int max_len = pix_count - i;
HashChainFindCopy(hash_chain, i, xsize, argb, max_len,
window_size, iter_pos, iter_limit,
&offset, &len);
}
if (len >= MIN_LENGTH) {
// Alternative#2: Insert the pixel at 'i' as literal, and code the
// pixels starting at 'i + 1' using backward reference.
int offset2 = 0;
int len2 = 0;
int k;
HashChainInsert(hash_chain, &argb[i], i);
if (i < pix_count - 2) { // FindCopy(i+1,..) reads [i + 1] and [i + 2].
int max_len = pix_count - (i + 1);
HashChainFindCopy(hash_chain, i + 1, xsize, argb, max_len,
window_size, iter_pos, iter_limit,
&offset2, &len2);
if (len2 > len + 1) {
const uint32_t pixel = argb[i];
// Alternative#2 is a better match. So push pixel at 'i' as literal.
if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix);
} else {
if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel);
refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel);
}
++refs->size;
i++; // Backward reference to be done for next pixel.
len = len2;
offset = offset2;
}
}
if (len >= MAX_LENGTH) {
len = MAX_LENGTH - 1;
}
refs->refs[refs->size++] = PixOrCopyCreateCopy(offset, len);
if (use_color_cache) {
for (k = 0; k < len; ++k) {
VP8LColorCacheInsert(&hashers, argb[i + k]);
}
}
// Add to the hash_chain (but cannot add the last pixel).
{
const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i;
for (k = 1; k < last; ++k) {
HashChainInsert(hash_chain, &argb[i + k], i + k);
}
}
i += len;
} else {
const uint32_t pixel = argb[i];
if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
// push pixel as a PixOrCopyCreateCacheIdx pixel
const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix);
} else {
if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel);
refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel);
}
++refs->size;
if (i + 1 < pix_count) {
HashChainInsert(hash_chain, &argb[i], i);
}
++i;
}
}
ok = 1;
Error:
if (cc_init) VP8LColorCacheClear(&hashers);
HashChainDelete(hash_chain);
return ok;
}
// -----------------------------------------------------------------------------
typedef struct {
double alpha_[VALUES_IN_BYTE];
double red_[VALUES_IN_BYTE];
double literal_[PIX_OR_COPY_CODES_MAX];
double blue_[VALUES_IN_BYTE];
double distance_[NUM_DISTANCE_CODES];
} CostModel;
static int BackwardReferencesTraceBackwards(
int xsize, int ysize, int recursive_cost_model,
const uint32_t* const argb, int quality, int cache_bits,
VP8LBackwardRefs* const refs);
static void ConvertPopulationCountTableToBitEstimates(
int num_symbols, const int population_counts[], double output[]) {
int sum = 0;
int nonzeros = 0;
int i;
for (i = 0; i < num_symbols; ++i) {
sum += population_counts[i];
if (population_counts[i] > 0) {
++nonzeros;
}
}
if (nonzeros <= 1) {
memset(output, 0, num_symbols * sizeof(*output));
} else {
const double logsum = VP8LFastLog2(sum);
for (i = 0; i < num_symbols; ++i) {
output[i] = logsum - VP8LFastLog2(population_counts[i]);
}
}
}
static int CostModelBuild(CostModel* const m, int xsize, int ysize,
int recursion_level, const uint32_t* const argb,
int quality, int cache_bits) {
int ok = 0;
VP8LHistogram histo;
VP8LBackwardRefs refs;
if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize)) goto Error;
if (recursion_level > 0) {
if (!BackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1,
argb, quality, cache_bits, &refs)) {
goto Error;
}
} else {
if (!BackwardReferencesHashChain(xsize, ysize, argb, cache_bits, quality,
&refs)) {
goto Error;
}
}
VP8LHistogramCreate(&histo, &refs, cache_bits);
ConvertPopulationCountTableToBitEstimates(
VP8LHistogramNumCodes(&histo), histo.literal_, m->literal_);
ConvertPopulationCountTableToBitEstimates(
VALUES_IN_BYTE, histo.red_, m->red_);
ConvertPopulationCountTableToBitEstimates(
VALUES_IN_BYTE, histo.blue_, m->blue_);
ConvertPopulationCountTableToBitEstimates(
VALUES_IN_BYTE, histo.alpha_, m->alpha_);
ConvertPopulationCountTableToBitEstimates(
NUM_DISTANCE_CODES, histo.distance_, m->distance_);
ok = 1;
Error:
VP8LClearBackwardRefs(&refs);
return ok;
}
static WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) {
return m->alpha_[v >> 24] +
m->red_[(v >> 16) & 0xff] +
m->literal_[(v >> 8) & 0xff] +
m->blue_[v & 0xff];
}
static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx;
return m->literal_[literal_idx];
}
static WEBP_INLINE double GetLengthCost(const CostModel* const m,
uint32_t length) {
int code, extra_bits;
VP8LPrefixEncodeBits(length, &code, &extra_bits);
return m->literal_[VALUES_IN_BYTE + code] + extra_bits;
}
static WEBP_INLINE double GetDistanceCost(const CostModel* const m,
uint32_t distance) {
int code, extra_bits;
VP8LPrefixEncodeBits(distance, &code, &extra_bits);
return m->distance_[code] + extra_bits;
}
static int BackwardReferencesHashChainDistanceOnly(
int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb,
int quality, int cache_bits, uint32_t* const dist_array) {
int i;
int ok = 0;
int cc_init = 0;
const int pix_count = xsize * ysize;
const int use_color_cache = (cache_bits > 0);
float* const cost =
(float*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost));
CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model));
HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
VP8LColorCache hashers;
const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68;
const double mul1 = (recursive_cost_model != 0) ? 1.0 : 0.82;
const int min_distance_code = 2; // TODO(vikasa): tune as function of quality
int window_size = WINDOW_SIZE;
int iter_pos = 1;
int iter_limit = -1;
if (cost == NULL || cost_model == NULL || hash_chain == NULL) goto Error;
if (!HashChainInit(hash_chain, pix_count)) goto Error;
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
}
if (!CostModelBuild(cost_model, xsize, ysize, recursive_cost_model, argb,
quality, cache_bits)) {
goto Error;
}
for (i = 0; i < pix_count; ++i) cost[i] = 1e38f;
// We loop one pixel at a time, but store all currently best points to
// non-processed locations from this point.
dist_array[0] = 0;
GetParamsForHashChainFindCopy(quality, xsize, cache_bits,
&window_size, &iter_pos, &iter_limit);
for (i = 0; i < pix_count; ++i) {
double prev_cost = 0.0;
int shortmax;
if (i > 0) {
prev_cost = cost[i - 1];
}
for (shortmax = 0; shortmax < 2; ++shortmax) {
int offset = 0;
int len = 0;
if (i < pix_count - 1) { // FindCopy reads pixels at [i] and [i + 1].
int max_len = shortmax ? 2 : pix_count - i;
HashChainFindCopy(hash_chain, i, xsize, argb, max_len,
window_size, iter_pos, iter_limit,
&offset, &len);
}
if (len >= MIN_LENGTH) {
const int code = DistanceToPlaneCode(xsize, offset);
const double distance_cost =
prev_cost + GetDistanceCost(cost_model, code);
int k;
for (k = 1; k < len; ++k) {
const double cost_val = distance_cost + GetLengthCost(cost_model, k);
if (cost[i + k] > cost_val) {
cost[i + k] = (float)cost_val;
dist_array[i + k] = k + 1;
}
}
// This if is for speedup only. It roughly doubles the speed, and
// makes compression worse by .1 %.
if (len >= 128 && code <= min_distance_code) {
// Long copy for short distances, let's skip the middle
// lookups for better copies.
// 1) insert the hashes.
if (use_color_cache) {
for (k = 0; k < len; ++k) {
VP8LColorCacheInsert(&hashers, argb[i + k]);
}
}
// 2) Add to the hash_chain (but cannot add the last pixel)
{
const int last = (len + i < pix_count - 1) ? len + i
: pix_count - 1;
for (k = i; k < last; ++k) {
HashChainInsert(hash_chain, &argb[k], k);
}
}
// 3) jump.
i += len - 1; // for loop does ++i, thus -1 here.
goto next_symbol;
}
}
}
if (i < pix_count - 1) {
HashChainInsert(hash_chain, &argb[i], i);
}
{
// inserting a literal pixel
double cost_val = prev_cost;
if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]);
cost_val += GetCacheCost(cost_model, ix) * mul0;
} else {
if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
cost_val += GetLiteralCost(cost_model, argb[i]) * mul1;
}
if (cost[i] > cost_val) {
cost[i] = (float)cost_val;
dist_array[i] = 1; // only one is inserted.
}
}
next_symbol: ;
}
// Last pixel still to do, it can only be a single step if not reached
// through cheaper means already.
ok = 1;
Error:
if (cc_init) VP8LColorCacheClear(&hashers);
HashChainDelete(hash_chain);
free(cost_model);
free(cost);
return ok;
}
// We pack the path at the end of *dist_array and return
// a pointer to this part of the array. Example:
// dist_array = [1x2xx3x2] => packed [1x2x1232], chosen_path = [1232]
static void TraceBackwards(uint32_t* const dist_array,
int dist_array_size,
uint32_t** const chosen_path,
int* const chosen_path_size) {
uint32_t* path = dist_array + dist_array_size;
uint32_t* cur = dist_array + dist_array_size - 1;
while (cur >= dist_array) {
const int k = *cur;
--path;
*path = k;
cur -= k;
}
*chosen_path = path;
*chosen_path_size = (int)(dist_array + dist_array_size - path);
}
static int BackwardReferencesHashChainFollowChosenPath(
int xsize, int ysize, const uint32_t* const argb,
int quality, int cache_bits,
const uint32_t* const chosen_path, int chosen_path_size,
VP8LBackwardRefs* const refs) {
const int pix_count = xsize * ysize;
const int use_color_cache = (cache_bits > 0);
int size = 0;
int i = 0;
int k;
int ix;
int ok = 0;
int cc_init = 0;
int window_size = WINDOW_SIZE;
int iter_pos = 1;
int iter_limit = -1;
HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
VP8LColorCache hashers;
if (hash_chain == NULL || !HashChainInit(hash_chain, pix_count)) {
goto Error;
}
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
}
refs->size = 0;
GetParamsForHashChainFindCopy(quality, xsize, cache_bits,
&window_size, &iter_pos, &iter_limit);
for (ix = 0; ix < chosen_path_size; ++ix, ++size) {
int offset = 0;
int len = 0;
int max_len = chosen_path[ix];
if (max_len != 1) {
HashChainFindCopy(hash_chain, i, xsize, argb, max_len,
window_size, iter_pos, iter_limit,
&offset, &len);
assert(len == max_len);
refs->refs[size] = PixOrCopyCreateCopy(offset, len);
if (use_color_cache) {
for (k = 0; k < len; ++k) {
VP8LColorCacheInsert(&hashers, argb[i + k]);
}
}
{
const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i;
for (k = 0; k < last; ++k) {
HashChainInsert(hash_chain, &argb[i + k], i + k);
}
}
i += len;
} else {
if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
// push pixel as a color cache index
const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]);
refs->refs[size] = PixOrCopyCreateCacheIdx(idx);
} else {
if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
refs->refs[size] = PixOrCopyCreateLiteral(argb[i]);
}
if (i + 1 < pix_count) {
HashChainInsert(hash_chain, &argb[i], i);
}
++i;
}
}
assert(size <= refs->max_size);
refs->size = size;
ok = 1;
Error:
if (cc_init) VP8LColorCacheClear(&hashers);
HashChainDelete(hash_chain);
return ok;
}
// Returns 1 on success.
static int BackwardReferencesTraceBackwards(int xsize, int ysize,
int recursive_cost_model,
const uint32_t* const argb,
int quality, int cache_bits,
VP8LBackwardRefs* const refs) {
int ok = 0;
const int dist_array_size = xsize * ysize;
uint32_t* chosen_path = NULL;
int chosen_path_size = 0;
uint32_t* dist_array =
(uint32_t*)WebPSafeMalloc((uint64_t)dist_array_size, sizeof(*dist_array));
if (dist_array == NULL) goto Error;
if (!BackwardReferencesHashChainDistanceOnly(
xsize, ysize, recursive_cost_model, argb, quality, cache_bits,
dist_array)) {
goto Error;
}
TraceBackwards(dist_array, dist_array_size, &chosen_path, &chosen_path_size);
if (!BackwardReferencesHashChainFollowChosenPath(
xsize, ysize, argb, quality, cache_bits, chosen_path, chosen_path_size,
refs)) {
goto Error;
}
ok = 1;
Error:
free(dist_array);
return ok;
}
static void BackwardReferences2DLocality(int xsize,
VP8LBackwardRefs* const refs) {
int i;
for (i = 0; i < refs->size; ++i) {
if (PixOrCopyIsCopy(&refs->refs[i])) {
const int dist = refs->refs[i].argb_or_distance;
const int transformed_dist = DistanceToPlaneCode(xsize, dist);
refs->refs[i].argb_or_distance = transformed_dist;
}
}
}
int VP8LGetBackwardReferences(int width, int height,
const uint32_t* const argb,
int quality, int cache_bits, int use_2d_locality,
VP8LBackwardRefs* const best) {
int ok = 0;
int lz77_is_useful;
VP8LBackwardRefs refs_rle, refs_lz77;
const int num_pix = width * height;
VP8LBackwardRefsAlloc(&refs_rle, num_pix);
VP8LBackwardRefsAlloc(&refs_lz77, num_pix);
VP8LInitBackwardRefs(best);
if (refs_rle.refs == NULL || refs_lz77.refs == NULL) {
Error1:
VP8LClearBackwardRefs(&refs_rle);
VP8LClearBackwardRefs(&refs_lz77);
goto End;
}
if (!BackwardReferencesHashChain(width, height, argb, cache_bits, quality,
&refs_lz77)) {
goto End;
}
// Backward Reference using RLE only.
BackwardReferencesRle(width, height, argb, &refs_rle);
{
double bit_cost_lz77, bit_cost_rle;
VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
if (histo == NULL) goto Error1;
// Evaluate lz77 coding
VP8LHistogramCreate(histo, &refs_lz77, cache_bits);
bit_cost_lz77 = VP8LHistogramEstimateBits(histo);
// Evaluate RLE coding
VP8LHistogramCreate(histo, &refs_rle, cache_bits);
bit_cost_rle = VP8LHistogramEstimateBits(histo);
// Decide if LZ77 is useful.
lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
free(histo);
}
// Choose appropriate backward reference.
if (lz77_is_useful) {
// TraceBackwards is costly. Don't execute it at lower quality.
const int try_lz77_trace_backwards = (quality >= 25);
*best = refs_lz77; // default guess: lz77 is better
VP8LClearBackwardRefs(&refs_rle);
if (try_lz77_trace_backwards) {
// Set recursion level for large images using a color cache.
const int recursion_level =
(num_pix < 320 * 200) && (cache_bits > 0) ? 1 : 0;
VP8LBackwardRefs refs_trace;
if (!VP8LBackwardRefsAlloc(&refs_trace, num_pix)) {
goto End;
}
if (BackwardReferencesTraceBackwards(width, height, recursion_level, argb,
quality, cache_bits, &refs_trace)) {
VP8LClearBackwardRefs(&refs_lz77);
*best = refs_trace;
}
}
} else {
VP8LClearBackwardRefs(&refs_lz77);
*best = refs_rle;
}
if (use_2d_locality) BackwardReferences2DLocality(width, best);
ok = 1;
End:
if (!ok) {
VP8LClearBackwardRefs(best);
}
return ok;
}
// Returns 1 on success.
static int ComputeCacheHistogram(const uint32_t* const argb,
int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int cache_bits,
VP8LHistogram* const histo) {
int pixel_index = 0;
int i;
uint32_t k;
VP8LColorCache hashers;
const int use_color_cache = (cache_bits > 0);
int cc_init = 0;
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) return 0;
}
for (i = 0; i < refs->size; ++i) {
const PixOrCopy* const v = &refs->refs[i];
if (PixOrCopyIsLiteral(v)) {
if (use_color_cache &&
VP8LColorCacheContains(&hashers, argb[pixel_index])) {
// push pixel as a cache index
const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]);
const PixOrCopy token = PixOrCopyCreateCacheIdx(ix);
VP8LHistogramAddSinglePixOrCopy(histo, &token);
} else {
VP8LHistogramAddSinglePixOrCopy(histo, v);
}
} else {
VP8LHistogramAddSinglePixOrCopy(histo, v);
}
if (use_color_cache) {
for (k = 0; k < PixOrCopyLength(v); ++k) {
VP8LColorCacheInsert(&hashers, argb[pixel_index + k]);
}
}
pixel_index += PixOrCopyLength(v);
}
assert(pixel_index == xsize * ysize);
(void)xsize; // xsize is not used in non-debug compilations otherwise.
(void)ysize; // ysize is not used in non-debug compilations otherwise.
if (cc_init) VP8LColorCacheClear(&hashers);
return 1;
}
// Returns how many bits are to be used for a color cache.
int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
int xsize, int ysize,
int* const best_cache_bits) {
int ok = 0;
int cache_bits;
double lowest_entropy = 1e99;
VP8LBackwardRefs refs;
static const double kSmallPenaltyForLargeCache = 4.0;
static const int quality = 30;
if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize) ||
!BackwardReferencesHashChain(xsize, ysize, argb, 0, quality, &refs)) {
goto Error;
}
for (cache_bits = 0; cache_bits <= MAX_COLOR_CACHE_BITS; ++cache_bits) {
double cur_entropy;
VP8LHistogram histo;
VP8LHistogramInit(&histo, cache_bits);
ComputeCacheHistogram(argb, xsize, ysize, &refs, cache_bits, &histo);
cur_entropy = VP8LHistogramEstimateBits(&histo) +
kSmallPenaltyForLargeCache * cache_bits;
if (cache_bits == 0 || cur_entropy < lowest_entropy) {
*best_cache_bits = cache_bits;
lowest_entropy = cur_entropy;
}
}
ok = 1;
Error:
VP8LClearBackwardRefs(&refs);
return ok;
}

View File

@ -0,0 +1,152 @@
// 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.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
//
#ifndef WEBP_ENC_BACKWARD_REFERENCES_H_
#define WEBP_ENC_BACKWARD_REFERENCES_H_
#include <assert.h>
#include <stdlib.h>
#include "../webp/types.h"
#include "../webp/format_constants.h"
#ifdef __cplusplus
extern "C" {
#endif
// The spec allows 11, we use 9 bits to reduce memory consumption in encoding.
// Having 9 instead of 11 only removes about 0.25 % of compression density.
#define MAX_COLOR_CACHE_BITS 9
// Max ever number of codes we'll use:
#define PIX_OR_COPY_CODES_MAX \
(NUM_LITERAL_CODES + NUM_LENGTH_CODES + (1 << MAX_COLOR_CACHE_BITS))
// -----------------------------------------------------------------------------
// PixOrCopy
enum Mode {
kLiteral,
kCacheIdx,
kCopy,
kNone
};
typedef struct {
// mode as uint8_t to make the memory layout to be exactly 8 bytes.
uint8_t mode;
uint16_t len;
uint32_t argb_or_distance;
} PixOrCopy;
static WEBP_INLINE PixOrCopy PixOrCopyCreateCopy(uint32_t distance,
uint16_t len) {
PixOrCopy retval;
retval.mode = kCopy;
retval.argb_or_distance = distance;
retval.len = len;
return retval;
}
static WEBP_INLINE PixOrCopy PixOrCopyCreateCacheIdx(int idx) {
PixOrCopy retval;
assert(idx >= 0);
assert(idx < (1 << MAX_COLOR_CACHE_BITS));
retval.mode = kCacheIdx;
retval.argb_or_distance = idx;
retval.len = 1;
return retval;
}
static WEBP_INLINE PixOrCopy PixOrCopyCreateLiteral(uint32_t argb) {
PixOrCopy retval;
retval.mode = kLiteral;
retval.argb_or_distance = argb;
retval.len = 1;
return retval;
}
static WEBP_INLINE int PixOrCopyIsLiteral(const PixOrCopy* const p) {
return (p->mode == kLiteral);
}
static WEBP_INLINE int PixOrCopyIsCacheIdx(const PixOrCopy* const p) {
return (p->mode == kCacheIdx);
}
static WEBP_INLINE int PixOrCopyIsCopy(const PixOrCopy* const p) {
return (p->mode == kCopy);
}
static WEBP_INLINE uint32_t PixOrCopyLiteral(const PixOrCopy* const p,
int component) {
assert(p->mode == kLiteral);
return (p->argb_or_distance >> (component * 8)) & 0xff;
}
static WEBP_INLINE uint32_t PixOrCopyLength(const PixOrCopy* const p) {
return p->len;
}
static WEBP_INLINE uint32_t PixOrCopyArgb(const PixOrCopy* const p) {
assert(p->mode == kLiteral);
return p->argb_or_distance;
}
static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) {
assert(p->mode == kCacheIdx);
assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS));
return p->argb_or_distance;
}
static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) {
assert(p->mode == kCopy);
return p->argb_or_distance;
}
// -----------------------------------------------------------------------------
// VP8LBackwardRefs
typedef struct {
PixOrCopy* refs;
int size; // currently used
int max_size; // maximum capacity
} VP8LBackwardRefs;
// Initialize the object. Must be called first. 'refs' can be NULL.
void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs);
// Release memory and re-initialize the object. 'refs' can be NULL.
void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs);
// Allocate 'max_size' references. Returns false in case of memory error.
int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size);
// -----------------------------------------------------------------------------
// Main entry points
// Evaluates best possible backward references for specified quality.
// Further optimize for 2D locality if use_2d_locality flag is set.
int VP8LGetBackwardReferences(int width, int height,
const uint32_t* const argb,
int quality, int cache_bits, int use_2d_locality,
VP8LBackwardRefs* const best);
// Produce an estimate for a good color cache size for the image.
int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
int xsize, int ysize,
int* const best_cache_bits);
#ifdef __cplusplus
}
#endif
#endif // WEBP_ENC_BACKWARD_REFERENCES_H_

View File

@ -1,28 +1,25 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Coding tools configuration
//
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include "../webp/encode.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// WebPConfig
//------------------------------------------------------------------------------
int WebPConfigInitInternal(WebPConfig* const config,
int WebPConfigInitInternal(WebPConfig* config,
WebPPreset preset, float quality, int version) {
if (version != WEBP_ENCODER_ABI_VERSION) {
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
return 0; // caller/system version mismatch!
}
if (config == NULL) return 0;
@ -32,17 +29,24 @@ int WebPConfigInitInternal(WebPConfig* const config,
config->target_PSNR = 0.;
config->method = 4;
config->sns_strength = 50;
config->filter_strength = 20; // default: light filtering
config->filter_strength = 60; // mid-filtering
config->filter_sharpness = 0;
config->filter_type = 0; // default: simple
config->filter_type = 1; // default: strong (so U/V is filtered too)
config->partitions = 0;
config->segments = 4;
config->pass = 1;
config->show_compressed = 0;
config->preprocessing = 0;
config->autofilter = 0;
config->alpha_compression = 0;
config->partition_limit = 0;
config->alpha_compression = 1;
config->alpha_filtering = 1;
config->alpha_quality = 100;
config->lossless = 0;
config->image_hint = WEBP_HINT_DEFAULT;
config->emulate_jpeg_size = 0;
config->thread_level = 0;
config->low_memory = 0;
// TODO(skal): tune.
switch (preset) {
@ -50,11 +54,13 @@ int WebPConfigInitInternal(WebPConfig* const config,
config->sns_strength = 80;
config->filter_sharpness = 4;
config->filter_strength = 35;
config->preprocessing &= ~2; // no dithering
break;
case WEBP_PRESET_PHOTO:
config->sns_strength = 80;
config->filter_sharpness = 3;
config->filter_strength = 30;
config->preprocessing |= 2;
break;
case WEBP_PRESET_DRAWING:
config->sns_strength = 25;
@ -64,10 +70,12 @@ int WebPConfigInitInternal(WebPConfig* const config,
case WEBP_PRESET_ICON:
config->sns_strength = 0;
config->filter_strength = 0; // disable filtering to retain sharpness
config->preprocessing &= ~2; // no dithering
break;
case WEBP_PRESET_TEXT:
config->sns_strength = 0;
config->filter_strength = 0; // disable filtering to retain sharpness
config->preprocessing &= ~2; // no dithering
config->segments = 2;
break;
case WEBP_PRESET_DEFAULT:
@ -77,7 +85,7 @@ int WebPConfigInitInternal(WebPConfig* const config,
return WebPValidateConfig(config);
}
int WebPValidateConfig(const WebPConfig* const config) {
int WebPValidateConfig(const WebPConfig* config) {
if (config == NULL) return 0;
if (config->quality < 0 || config->quality > 100)
return 0;
@ -103,7 +111,7 @@ int WebPValidateConfig(const WebPConfig* const config) {
return 0;
if (config->show_compressed < 0 || config->show_compressed > 1)
return 0;
if (config->preprocessing < 0 || config->preprocessing > 1)
if (config->preprocessing < 0 || config->preprocessing > 3)
return 0;
if (config->partitions < 0 || config->partitions > 3)
return 0;
@ -111,11 +119,22 @@ int WebPValidateConfig(const WebPConfig* const config) {
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->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;
return 1;
}
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,21 +1,17 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Cost tables for level and modes
//
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include "cost.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "./cost.h"
//------------------------------------------------------------------------------
// Boolean-cost cost table
@ -52,9 +48,9 @@ const uint16_t VP8EntropyCost[256] = {
//------------------------------------------------------------------------------
// Level cost tables
// For each given level, the following table given the pattern of contexts
// to use for coding it (in [][0]) as well as the bit value to use for
// each context (in [][1]).
// For each given level, the following table gives the pattern of contexts to
// use for coding it (in [][0]) as well as the bit value to use for each
// context (in [][1]).
const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = {
{0x001, 0x000}, {0x007, 0x001}, {0x00f, 0x005},
{0x00f, 0x00d}, {0x033, 0x003}, {0x033, 0x003}, {0x033, 0x023},
@ -77,7 +73,7 @@ const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = {
// fixed costs for coding levels, deduce from the coding tree.
// This is only the part that doesn't depend on the probability state.
const uint16_t VP8LevelFixedCosts[2048] = {
const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1] = {
0, 256, 256, 256, 256, 432, 618, 630,
731, 640, 640, 828, 901, 948, 1021, 1101,
1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202,
@ -356,9 +352,12 @@ static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) {
void VP8CalculateLevelCosts(VP8Proba* const proba) {
int ctype, band, ctx;
if (!proba->dirty_) return; // nothing to do.
for (ctype = 0; ctype < NUM_TYPES; ++ctype) {
for (band = 0; band < NUM_BANDS; ++band) {
for(ctx = 0; ctx < NUM_CTX; ++ctx) {
for (ctx = 0; ctx < NUM_CTX; ++ctx) {
const uint8_t* const p = proba->coeffs_[ctype][band][ctx];
uint16_t* const table = proba->level_cost_[ctype][band][ctx];
const int cost_base = VP8BitCost(1, p[1]);
@ -372,6 +371,7 @@ void VP8CalculateLevelCosts(VP8Proba* const proba) {
}
}
}
proba->dirty_ = 0;
}
//------------------------------------------------------------------------------
@ -383,110 +383,107 @@ const uint16_t VP8FixedCostsUV[4] = { 302, 984, 439, 642 };
// note: these values include the fixed VP8BitCost(1, 145) mode selection cost.
const uint16_t VP8FixedCostsI16[4] = { 663, 919, 872, 919 };
const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES] = {
{ { 251, 1362, 1934, 2085, 2314, 2230, 1839, 1988, 2437, 2348 },
{ 403, 680, 1507, 1519, 2060, 2005, 1992, 1914, 1924, 1733 },
{ 353, 1121, 973, 1895, 2060, 1787, 1671, 1516, 2012, 1868 },
{ 770, 852, 1581, 632, 1393, 1780, 1823, 1936, 1074, 1218 },
{ 510, 1270, 1467, 1319, 847, 1279, 1792, 2094, 1080, 1353 },
{ 488, 1322, 918, 1573, 1300, 883, 1814, 1752, 1756, 1502 },
{ 425, 992, 1820, 1514, 1843, 2440, 937, 1771, 1924, 1129 },
{ 363, 1248, 1257, 1970, 2194, 2385, 1569, 953, 1951, 1601 },
{ 723, 1257, 1631, 964, 963, 1508, 1697, 1824, 671, 1418 },
{ 635, 1038, 1573, 930, 1673, 1413, 1410, 1687, 1410, 749 } },
{ { 451, 613, 1345, 1702, 1870, 1716, 1728, 1766, 2190, 2310 },
{ 678, 453, 1171, 1443, 1925, 1831, 2045, 1781, 1887, 1602 },
{ 711, 666, 674, 1718, 1910, 1493, 1775, 1193, 2325, 2325 },
{ 883, 854, 1583, 542, 1800, 1878, 1664, 2149, 1207, 1087 },
{ 669, 994, 1248, 1122, 949, 1179, 1376, 1729, 1070, 1244 },
{ 715, 1026, 715, 1350, 1430, 930, 1717, 1296, 1479, 1479 },
{ 544, 841, 1656, 1450, 2094, 3883, 1010, 1759, 2076, 809 },
{ 610, 855, 957, 1553, 2067, 1561, 1704, 824, 2066, 1226 },
{ 833, 960, 1416, 819, 1277, 1619, 1501, 1617, 757, 1182 },
{ 711, 964, 1252, 879, 1441, 1828, 1508, 1636, 1594, 734 } },
{ { 605, 764, 734, 1713, 1747, 1192, 1819, 1353, 1877, 2392 },
{ 866, 641, 586, 1622, 2072, 1431, 1888, 1346, 2189, 1764 },
{ 901, 851, 456, 2165, 2281, 1405, 1739, 1193, 2183, 2443 },
{ 770, 1045, 952, 1078, 1342, 1191, 1436, 1063, 1303, 995 },
{ 901, 1086, 727, 1170, 884, 1105, 1267, 1401, 1739, 1337 },
{ 951, 1162, 595, 1488, 1388, 703, 1790, 1366, 2057, 1724 },
{ 534, 986, 1273, 1987, 3273, 1485, 1024, 1399, 1583, 866 },
{ 699, 1182, 695, 1978, 1726, 1986, 1326, 714, 1750, 1672 },
{ 951, 1217, 1209, 920, 1062, 1441, 1548, 999, 952, 932 },
{ 733, 1284, 784, 1256, 1557, 1098, 1257, 1357, 1414, 908 } },
{ { 316, 1075, 1653, 1220, 2145, 2051, 1730, 2131, 1884, 1790 },
{ 745, 516, 1404, 894, 1599, 2375, 2013, 2105, 1475, 1381 },
{ 516, 729, 1088, 1319, 1637, 3426, 1636, 1275, 1531, 1453 },
{ 894, 943, 2138, 468, 1704, 2259, 2069, 1763, 1266, 1158 },
{ 605, 1025, 1235, 871, 1170, 1767, 1493, 1500, 1104, 1258 },
{ 739, 826, 1207, 1151, 1412, 846, 1305, 2726, 1014, 1569 },
{ 558, 825, 1820, 1398, 3344, 1556, 1218, 1550, 1228, 878 },
{ 429, 951, 1089, 1816, 3861, 3861, 1556, 969, 1568, 1828 },
{ 883, 961, 1752, 769, 1468, 1810, 2081, 2346, 613, 1298 },
{ 803, 895, 1372, 641, 1303, 1708, 1686, 1700, 1306, 1033 } },
{ { 439, 1267, 1270, 1579, 963, 1193, 1723, 1729, 1198, 1993 },
{ 705, 725, 1029, 1153, 1176, 1103, 1821, 1567, 1259, 1574 },
{ 723, 859, 802, 1253, 972, 1202, 1407, 1665, 1520, 1674 },
{ 894, 960, 1254, 887, 1052, 1607, 1344, 1349, 865, 1150 },
{ 833, 1312, 1337, 1205, 572, 1288, 1414, 1529, 1088, 1430 },
{ 842, 1279, 1068, 1861, 862, 688, 1861, 1630, 1039, 1381 },
{ 766, 938, 1279, 1546, 3338, 1550, 1031, 1542, 1288, 640 },
{ 715, 1090, 835, 1609, 1100, 1100, 1603, 1019, 1102, 1617 },
{ 894, 1813, 1500, 1188, 789, 1194, 1491, 1919, 617, 1333 },
{ 610, 1076, 1644, 1281, 1283, 975, 1179, 1688, 1434, 889 } },
{ { 544, 971, 1146, 1849, 1221, 740, 1857, 1621, 1683, 2430 },
{ 723, 705, 961, 1371, 1426, 821, 2081, 2079, 1839, 1380 },
{ 783, 857, 703, 2145, 1419, 814, 1791, 1310, 1609, 2206 },
{ 997, 1000, 1153, 792, 1229, 1162, 1810, 1418, 942, 979 },
{ 901, 1226, 883, 1289, 793, 715, 1904, 1649, 1319, 3108 },
{ 979, 1478, 782, 2216, 1454, 455, 3092, 1591, 1997, 1664 },
{ 663, 1110, 1504, 1114, 1522, 3311, 676, 1522, 1530, 1024 },
{ 605, 1138, 1153, 1314, 1569, 1315, 1157, 804, 1574, 1320 },
{ 770, 1216, 1218, 1227, 869, 1384, 1232, 1375, 834, 1239 },
{ 775, 1007, 843, 1216, 1225, 1074, 2527, 1479, 1149, 975 } },
{ { 477, 817, 1309, 1439, 1708, 1454, 1159, 1241, 1945, 1672 },
{ 577, 796, 1112, 1271, 1618, 1458, 1087, 1345, 1831, 1265 },
{ 663, 776, 753, 1940, 1690, 1690, 1227, 1097, 3149, 1361 },
{ 766, 1299, 1744, 1161, 1565, 1106, 1045, 1230, 1232, 707 },
{ 915, 1026, 1404, 1182, 1184, 851, 1428, 2425, 1043, 789 },
{ 883, 1456, 790, 1082, 1086, 985, 1083, 1484, 1238, 1160 },
{ 507, 1345, 2261, 1995, 1847, 3636, 653, 1761, 2287, 933 },
{ 553, 1193, 1470, 2057, 2059, 2059, 833, 779, 2058, 1263 },
{ 766, 1275, 1515, 1039, 957, 1554, 1286, 1540, 1289, 705 },
{ 499, 1378, 1496, 1385, 1850, 1850, 1044, 2465, 1515, 720 } },
{ { 553, 930, 978, 2077, 1968, 1481, 1457, 761, 1957, 2362 },
{ 694, 864, 905, 1720, 1670, 1621, 1429, 718, 2125, 1477 },
{ 699, 968, 658, 3190, 2024, 1479, 1865, 750, 2060, 2320 },
{ 733, 1308, 1296, 1062, 1576, 1322, 1062, 1112, 1172, 816 },
{ 920, 927, 1052, 939, 947, 1156, 1152, 1073, 3056, 1268 },
{ 723, 1534, 711, 1547, 1294, 892, 1553, 928, 1815, 1561 },
{ 663, 1366, 1583, 2111, 1712, 3501, 522, 1155, 2130, 1133 },
{ 614, 1731, 1188, 2343, 1944, 3733, 1287, 487, 3546, 1758 },
{ 770, 1585, 1312, 826, 884, 2673, 1185, 1006, 1195, 1195 },
{ 758, 1333, 1273, 1023, 1621, 1162, 1351, 833, 1479, 862 } },
{ { 376, 1193, 1446, 1149, 1545, 1577, 1870, 1789, 1175, 1823 },
{ 803, 633, 1136, 1058, 1350, 1323, 1598, 2247, 1072, 1252 },
{ 614, 1048, 943, 981, 1152, 1869, 1461, 1020, 1618, 1618 },
{ 1107, 1085, 1282, 592, 1779, 1933, 1648, 2403, 691, 1246 },
{ 851, 1309, 1223, 1243, 895, 1593, 1792, 2317, 627, 1076 },
{ 770, 1216, 1030, 1125, 921, 981, 1629, 1131, 1049, 1646 },
{ 626, 1469, 1456, 1081, 1489, 3278, 981, 1232, 1498, 733 },
{ 617, 1201, 812, 1220, 1476, 1476, 1478, 970, 1228, 1488 },
{ 1179, 1393, 1540, 999, 1243, 1503, 1916, 1925, 414, 1614 },
{ 943, 1088, 1490, 682, 1112, 1372, 1756, 1505, 966, 966 } },
{ { 322, 1142, 1589, 1396, 2144, 1859, 1359, 1925, 2084, 1518 },
{ 617, 625, 1241, 1234, 2121, 1615, 1524, 1858, 1720, 1004 },
{ 553, 851, 786, 1299, 1452, 1560, 1372, 1561, 1967, 1713 },
{ 770, 977, 1396, 568, 1893, 1639, 1540, 2108, 1430, 1013 },
{ 684, 1120, 1375, 982, 930, 2719, 1638, 1643, 933, 993 },
{ 553, 1103, 996, 1356, 1361, 1005, 1507, 1761, 1184, 1268 },
{ 419, 1247, 1537, 1554, 1817, 3606, 1026, 1666, 1829, 923 },
{ 439, 1139, 1101, 1257, 3710, 1922, 1205, 1040, 1931, 1529 },
{ 979, 935, 1269, 847, 1202, 1286, 1530, 1535, 827, 1036 },
{ 516, 1378, 1569, 1110, 1798, 1798, 1198, 2199, 1543, 712 } },
{ { 40, 1151, 1723, 1874, 2103, 2019, 1628, 1777, 2226, 2137 },
{ 192, 469, 1296, 1308, 1849, 1794, 1781, 1703, 1713, 1522 },
{ 142, 910, 762, 1684, 1849, 1576, 1460, 1305, 1801, 1657 },
{ 559, 641, 1370, 421, 1182, 1569, 1612, 1725, 863, 1007 },
{ 299, 1059, 1256, 1108, 636, 1068, 1581, 1883, 869, 1142 },
{ 277, 1111, 707, 1362, 1089, 672, 1603, 1541, 1545, 1291 },
{ 214, 781, 1609, 1303, 1632, 2229, 726, 1560, 1713, 918 },
{ 152, 1037, 1046, 1759, 1983, 2174, 1358, 742, 1740, 1390 },
{ 512, 1046, 1420, 753, 752, 1297, 1486, 1613, 460, 1207 },
{ 424, 827, 1362, 719, 1462, 1202, 1199, 1476, 1199, 538 } },
{ { 240, 402, 1134, 1491, 1659, 1505, 1517, 1555, 1979, 2099 },
{ 467, 242, 960, 1232, 1714, 1620, 1834, 1570, 1676, 1391 },
{ 500, 455, 463, 1507, 1699, 1282, 1564, 982, 2114, 2114 },
{ 672, 643, 1372, 331, 1589, 1667, 1453, 1938, 996, 876 },
{ 458, 783, 1037, 911, 738, 968, 1165, 1518, 859, 1033 },
{ 504, 815, 504, 1139, 1219, 719, 1506, 1085, 1268, 1268 },
{ 333, 630, 1445, 1239, 1883, 3672, 799, 1548, 1865, 598 },
{ 399, 644, 746, 1342, 1856, 1350, 1493, 613, 1855, 1015 },
{ 622, 749, 1205, 608, 1066, 1408, 1290, 1406, 546, 971 },
{ 500, 753, 1041, 668, 1230, 1617, 1297, 1425, 1383, 523 } },
{ { 394, 553, 523, 1502, 1536, 981, 1608, 1142, 1666, 2181 },
{ 655, 430, 375, 1411, 1861, 1220, 1677, 1135, 1978, 1553 },
{ 690, 640, 245, 1954, 2070, 1194, 1528, 982, 1972, 2232 },
{ 559, 834, 741, 867, 1131, 980, 1225, 852, 1092, 784 },
{ 690, 875, 516, 959, 673, 894, 1056, 1190, 1528, 1126 },
{ 740, 951, 384, 1277, 1177, 492, 1579, 1155, 1846, 1513 },
{ 323, 775, 1062, 1776, 3062, 1274, 813, 1188, 1372, 655 },
{ 488, 971, 484, 1767, 1515, 1775, 1115, 503, 1539, 1461 },
{ 740, 1006, 998, 709, 851, 1230, 1337, 788, 741, 721 },
{ 522, 1073, 573, 1045, 1346, 887, 1046, 1146, 1203, 697 } },
{ { 105, 864, 1442, 1009, 1934, 1840, 1519, 1920, 1673, 1579 },
{ 534, 305, 1193, 683, 1388, 2164, 1802, 1894, 1264, 1170 },
{ 305, 518, 877, 1108, 1426, 3215, 1425, 1064, 1320, 1242 },
{ 683, 732, 1927, 257, 1493, 2048, 1858, 1552, 1055, 947 },
{ 394, 814, 1024, 660, 959, 1556, 1282, 1289, 893, 1047 },
{ 528, 615, 996, 940, 1201, 635, 1094, 2515, 803, 1358 },
{ 347, 614, 1609, 1187, 3133, 1345, 1007, 1339, 1017, 667 },
{ 218, 740, 878, 1605, 3650, 3650, 1345, 758, 1357, 1617 },
{ 672, 750, 1541, 558, 1257, 1599, 1870, 2135, 402, 1087 },
{ 592, 684, 1161, 430, 1092, 1497, 1475, 1489, 1095, 822 } },
{ { 228, 1056, 1059, 1368, 752, 982, 1512, 1518, 987, 1782 },
{ 494, 514, 818, 942, 965, 892, 1610, 1356, 1048, 1363 },
{ 512, 648, 591, 1042, 761, 991, 1196, 1454, 1309, 1463 },
{ 683, 749, 1043, 676, 841, 1396, 1133, 1138, 654, 939 },
{ 622, 1101, 1126, 994, 361, 1077, 1203, 1318, 877, 1219 },
{ 631, 1068, 857, 1650, 651, 477, 1650, 1419, 828, 1170 },
{ 555, 727, 1068, 1335, 3127, 1339, 820, 1331, 1077, 429 },
{ 504, 879, 624, 1398, 889, 889, 1392, 808, 891, 1406 },
{ 683, 1602, 1289, 977, 578, 983, 1280, 1708, 406, 1122 },
{ 399, 865, 1433, 1070, 1072, 764, 968, 1477, 1223, 678 } },
{ { 333, 760, 935, 1638, 1010, 529, 1646, 1410, 1472, 2219 },
{ 512, 494, 750, 1160, 1215, 610, 1870, 1868, 1628, 1169 },
{ 572, 646, 492, 1934, 1208, 603, 1580, 1099, 1398, 1995 },
{ 786, 789, 942, 581, 1018, 951, 1599, 1207, 731, 768 },
{ 690, 1015, 672, 1078, 582, 504, 1693, 1438, 1108, 2897 },
{ 768, 1267, 571, 2005, 1243, 244, 2881, 1380, 1786, 1453 },
{ 452, 899, 1293, 903, 1311, 3100, 465, 1311, 1319, 813 },
{ 394, 927, 942, 1103, 1358, 1104, 946, 593, 1363, 1109 },
{ 559, 1005, 1007, 1016, 658, 1173, 1021, 1164, 623, 1028 },
{ 564, 796, 632, 1005, 1014, 863, 2316, 1268, 938, 764 } },
{ { 266, 606, 1098, 1228, 1497, 1243, 948, 1030, 1734, 1461 },
{ 366, 585, 901, 1060, 1407, 1247, 876, 1134, 1620, 1054 },
{ 452, 565, 542, 1729, 1479, 1479, 1016, 886, 2938, 1150 },
{ 555, 1088, 1533, 950, 1354, 895, 834, 1019, 1021, 496 },
{ 704, 815, 1193, 971, 973, 640, 1217, 2214, 832, 578 },
{ 672, 1245, 579, 871, 875, 774, 872, 1273, 1027, 949 },
{ 296, 1134, 2050, 1784, 1636, 3425, 442, 1550, 2076, 722 },
{ 342, 982, 1259, 1846, 1848, 1848, 622, 568, 1847, 1052 },
{ 555, 1064, 1304, 828, 746, 1343, 1075, 1329, 1078, 494 },
{ 288, 1167, 1285, 1174, 1639, 1639, 833, 2254, 1304, 509 } },
{ { 342, 719, 767, 1866, 1757, 1270, 1246, 550, 1746, 2151 },
{ 483, 653, 694, 1509, 1459, 1410, 1218, 507, 1914, 1266 },
{ 488, 757, 447, 2979, 1813, 1268, 1654, 539, 1849, 2109 },
{ 522, 1097, 1085, 851, 1365, 1111, 851, 901, 961, 605 },
{ 709, 716, 841, 728, 736, 945, 941, 862, 2845, 1057 },
{ 512, 1323, 500, 1336, 1083, 681, 1342, 717, 1604, 1350 },
{ 452, 1155, 1372, 1900, 1501, 3290, 311, 944, 1919, 922 },
{ 403, 1520, 977, 2132, 1733, 3522, 1076, 276, 3335, 1547 },
{ 559, 1374, 1101, 615, 673, 2462, 974, 795, 984, 984 },
{ 547, 1122, 1062, 812, 1410, 951, 1140, 622, 1268, 651 } },
{ { 165, 982, 1235, 938, 1334, 1366, 1659, 1578, 964, 1612 },
{ 592, 422, 925, 847, 1139, 1112, 1387, 2036, 861, 1041 },
{ 403, 837, 732, 770, 941, 1658, 1250, 809, 1407, 1407 },
{ 896, 874, 1071, 381, 1568, 1722, 1437, 2192, 480, 1035 },
{ 640, 1098, 1012, 1032, 684, 1382, 1581, 2106, 416, 865 },
{ 559, 1005, 819, 914, 710, 770, 1418, 920, 838, 1435 },
{ 415, 1258, 1245, 870, 1278, 3067, 770, 1021, 1287, 522 },
{ 406, 990, 601, 1009, 1265, 1265, 1267, 759, 1017, 1277 },
{ 968, 1182, 1329, 788, 1032, 1292, 1705, 1714, 203, 1403 },
{ 732, 877, 1279, 471, 901, 1161, 1545, 1294, 755, 755 } },
{ { 111, 931, 1378, 1185, 1933, 1648, 1148, 1714, 1873, 1307 },
{ 406, 414, 1030, 1023, 1910, 1404, 1313, 1647, 1509, 793 },
{ 342, 640, 575, 1088, 1241, 1349, 1161, 1350, 1756, 1502 },
{ 559, 766, 1185, 357, 1682, 1428, 1329, 1897, 1219, 802 },
{ 473, 909, 1164, 771, 719, 2508, 1427, 1432, 722, 782 },
{ 342, 892, 785, 1145, 1150, 794, 1296, 1550, 973, 1057 },
{ 208, 1036, 1326, 1343, 1606, 3395, 815, 1455, 1618, 712 },
{ 228, 928, 890, 1046, 3499, 1711, 994, 829, 1720, 1318 },
{ 768, 724, 1058, 636, 991, 1075, 1319, 1324, 616, 825 },
{ 305, 1167, 1358, 899, 1587, 1587, 987, 1988, 1332, 501 } }
};
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,8 +1,10 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Cost tables for level and modes.
@ -12,32 +14,27 @@
#ifndef WEBP_ENC_COST_H_
#define WEBP_ENC_COST_H_
#include "vp8enci.h"
#include "./vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
extern "C" {
#endif
extern const uint16_t VP8LevelFixedCosts[2048]; // approximate cost per level
// approximate cost per level:
extern const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1];
extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p)
// Cost of coding one event with probability 'proba'.
static inline int VP8BitCost(int bit, uint8_t proba) {
static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) {
return !bit ? VP8EntropyCost[proba] : VP8EntropyCost[255 - proba];
}
// Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability.
static inline uint64_t VP8BranchCost(uint64_t nb, uint64_t total,
uint8_t proba) {
return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba);
}
// Level cost calculations
extern const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2];
void VP8CalculateLevelCosts(VP8Proba* const proba);
static inline int VP8LevelCost(const uint16_t* const table, int level) {
static WEBP_INLINE int VP8LevelCost(const uint16_t* const table, int level) {
return VP8LevelFixedCosts[level]
+ table[level > MAX_VARIABLE_LEVEL ? MAX_VARIABLE_LEVEL : level];
+ table[(level > MAX_VARIABLE_LEVEL) ? MAX_VARIABLE_LEVEL : level];
}
// Mode costs
@ -47,7 +44,7 @@ extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,770 +0,0 @@
// Copyright 2011 Google Inc.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// speed-critical functions.
//
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include "vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// Compute susceptibility based on DCT-coeff histograms:
// the higher, the "easier" the macroblock is to compress.
static int ClipAlpha(int alpha) {
return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
}
int VP8GetAlpha(const int histo[MAX_COEFF_THRESH + 1]) {
int num = 0, den = 0, val = 0;
int k;
int alpha;
// note: changing this loop to avoid the numerous "k + 1" slows things down.
for (k = 0; k < MAX_COEFF_THRESH; ++k) {
if (histo[k + 1]) {
val += histo[k + 1];
num += val * (k + 1);
den += (k + 1) * (k + 1);
}
}
// we scale the value to a usable [0..255] range
alpha = den ? 10 * num / den - 5 : 0;
return ClipAlpha(alpha);
}
static int CollectHistogram(const uint8_t* ref, const uint8_t* pred,
int start_block, int end_block) {
int histo[MAX_COEFF_THRESH + 1] = { 0 };
int16_t out[16];
int j, k;
for (j = start_block; j < end_block; ++j) {
VP8FTransform(ref + VP8Scan[j], pred + VP8Scan[j], out);
// Convert coefficients to bin (within out[]).
for (k = 0; k < 16; ++k) {
const int v = abs(out[k]) >> 2;
out[k] = (v > MAX_COEFF_THRESH) ? MAX_COEFF_THRESH : v;
}
// Use bin to update histogram.
for (k = 0; k < 16; ++k) {
histo[out[k]]++;
}
}
return VP8GetAlpha(histo);
}
//------------------------------------------------------------------------------
// run-time tables (~4k)
static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
// We declare this variable 'volatile' to prevent instruction reordering
// and make sure it's set to true _last_ (so as to be thread-safe)
static volatile int tables_ok = 0;
static void InitTables(void) {
if (!tables_ok) {
int i;
for (i = -255; i <= 255 + 255; ++i) {
clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
}
tables_ok = 1;
}
}
static inline uint8_t clip_8b(int v) {
return (!(v & ~0xff)) ? v : v < 0 ? 0 : 255;
}
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
#define STORE(x, y, v) \
dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3))
static const int kC1 = 20091 + (1 << 16);
static const int kC2 = 35468;
#define MUL(a, b) (((a) * (b)) >> 16)
static inline void ITransformOne(const uint8_t* ref, const int16_t* in,
uint8_t* dst) {
int C[4 * 4], *tmp;
int i;
tmp = C;
for (i = 0; i < 4; ++i) { // vertical pass
const int a = in[0] + in[8];
const int b = in[0] - in[8];
const int c = MUL(in[4], kC2) - MUL(in[12], kC1);
const int d = MUL(in[4], kC1) + MUL(in[12], kC2);
tmp[0] = a + d;
tmp[1] = b + c;
tmp[2] = b - c;
tmp[3] = a - d;
tmp += 4;
in++;
}
tmp = C;
for (i = 0; i < 4; ++i) { // horizontal pass
const int dc = tmp[0] + 4;
const int a = dc + tmp[8];
const int b = dc - tmp[8];
const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1);
const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2);
STORE(0, i, a + d);
STORE(1, i, b + c);
STORE(2, i, b - c);
STORE(3, i, a - d);
tmp++;
}
}
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) {
int i;
int tmp[16];
for (i = 0; i < 4; ++i, src += BPS, ref += BPS) {
const int d0 = src[0] - ref[0];
const int d1 = src[1] - ref[1];
const int d2 = src[2] - ref[2];
const int d3 = src[3] - ref[3];
const int a0 = (d0 + d3) << 3;
const int a1 = (d1 + d2) << 3;
const int a2 = (d1 - d2) << 3;
const int a3 = (d0 - d3) << 3;
tmp[0 + i * 4] = (a0 + a1);
tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 14500) >> 12;
tmp[2 + i * 4] = (a0 - a1);
tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 7500) >> 12;
}
for (i = 0; i < 4; ++i) {
const int a0 = (tmp[0 + i] + tmp[12 + i]);
const int a1 = (tmp[4 + i] + tmp[ 8 + i]);
const int a2 = (tmp[4 + i] - tmp[ 8 + i]);
const int a3 = (tmp[0 + i] - tmp[12 + i]);
out[0 + i] = (a0 + a1 + 7) >> 4;
out[4 + i] = ((a2 * 2217 + a3 * 5352 + 12000) >> 16) + (a3 != 0);
out[8 + i] = (a0 - a1 + 7) >> 4;
out[12+ i] = ((a3 * 2217 - a2 * 5352 + 51000) >> 16);
}
}
static void ITransformWHT(const int16_t* in, int16_t* out) {
int tmp[16];
int i;
for (i = 0; i < 4; ++i) {
const int a0 = in[0 + i] + in[12 + i];
const int a1 = in[4 + i] + in[ 8 + i];
const int a2 = in[4 + i] - in[ 8 + i];
const int a3 = in[0 + i] - in[12 + i];
tmp[0 + i] = a0 + a1;
tmp[8 + i] = a0 - a1;
tmp[4 + i] = a3 + a2;
tmp[12 + i] = a3 - a2;
}
for (i = 0; i < 4; ++i) {
const int dc = tmp[0 + i * 4] + 3; // w/ rounder
const int a0 = dc + tmp[3 + i * 4];
const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4];
const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4];
const int a3 = dc - tmp[3 + i * 4];
out[ 0] = (a0 + a1) >> 3;
out[16] = (a3 + a2) >> 3;
out[32] = (a0 - a1) >> 3;
out[48] = (a3 - a2) >> 3;
out += 64;
}
}
static void FTransformWHT(const int16_t* in, int16_t* out) {
int tmp[16];
int i;
for (i = 0; i < 4; ++i, in += 64) {
const int a0 = (in[0 * 16] + in[2 * 16]) << 2;
const int a1 = (in[1 * 16] + in[3 * 16]) << 2;
const int a2 = (in[1 * 16] - in[3 * 16]) << 2;
const int a3 = (in[0 * 16] - in[2 * 16]) << 2;
tmp[0 + i * 4] = (a0 + a1) + (a0 != 0);
tmp[1 + i * 4] = a3 + a2;
tmp[2 + i * 4] = a3 - a2;
tmp[3 + i * 4] = a0 - a1;
}
for (i = 0; i < 4; ++i) {
const int a0 = (tmp[0 + i] + tmp[8 + i]);
const int a1 = (tmp[4 + i] + tmp[12+ i]);
const int a2 = (tmp[4 + i] - tmp[12+ i]);
const int a3 = (tmp[0 + i] - tmp[8 + i]);
const int b0 = a0 + a1;
const int b1 = a3 + a2;
const int b2 = a3 - a2;
const int b3 = a0 - a1;
out[ 0 + i] = (b0 + (b0 > 0) + 3) >> 3;
out[ 4 + i] = (b1 + (b1 > 0) + 3) >> 3;
out[ 8 + i] = (b2 + (b2 > 0) + 3) >> 3;
out[12 + i] = (b3 + (b3 > 0) + 3) >> 3;
}
}
#undef MUL
#undef STORE
//------------------------------------------------------------------------------
// Intra predictions
#define OUT(x, y) dst[(x) + (y) * BPS]
static inline void Fill(uint8_t* dst, int value, int size) {
int j;
for (j = 0; j < size; ++j) {
memset(dst + j * BPS, value, size);
}
}
static inline void VerticalPred(uint8_t* dst, const uint8_t* top, int size) {
int j;
if (top) {
for (j = 0; j < size; ++j) memcpy(dst + j * BPS, top, size);
} else {
Fill(dst, 127, size);
}
}
static inline void HorizontalPred(uint8_t* dst, const uint8_t* left, int size) {
if (left) {
int j;
for (j = 0; j < size; ++j) {
memset(dst + j * BPS, left[j], size);
}
} else {
Fill(dst, 129, size);
}
}
static inline void TrueMotion(uint8_t* dst, const uint8_t* left,
const uint8_t* top, int size) {
int y;
if (left) {
if (top) {
const uint8_t* const clip = clip1 + 255 - left[-1];
for (y = 0; y < size; ++y) {
const uint8_t* const clip_table = clip + left[y];
int x;
for (x = 0; x < size; ++x) {
dst[x] = clip_table[top[x]];
}
dst += BPS;
}
} else {
HorizontalPred(dst, left, size);
}
} else {
// true motion without left samples (hence: with default 129 value)
// is equivalent to VE prediction where you just copy the top samples.
// Note that if top samples are not available, the default value is
// then 129, and not 127 as in the VerticalPred case.
if (top) {
VerticalPred(dst, top, size);
} else {
Fill(dst, 129, size);
}
}
}
static inline void DCMode(uint8_t* dst, const uint8_t* left,
const uint8_t* top,
int size, int round, int shift) {
int DC = 0;
int j;
if (top) {
for (j = 0; j < size; ++j) DC += top[j];
if (left) { // top and left present
for (j = 0; j < size; ++j) DC += left[j];
} else { // top, but no left
DC += DC;
}
DC = (DC + round) >> shift;
} else if (left) { // left but no top
for (j = 0; j < size; ++j) DC += left[j];
DC += DC;
DC = (DC + round) >> shift;
} else { // no top, no left, nothing.
DC = 0x80;
}
Fill(dst, DC, size);
}
//------------------------------------------------------------------------------
// Chroma 8x8 prediction (paragraph 12.2)
static void IntraChromaPreds(uint8_t* dst, const uint8_t* left,
const uint8_t* top) {
// U block
DCMode(C8DC8 + dst, left, top, 8, 8, 4);
VerticalPred(C8VE8 + dst, top, 8);
HorizontalPred(C8HE8 + dst, left, 8);
TrueMotion(C8TM8 + dst, left, top, 8);
// V block
dst += 8;
if (top) top += 8;
if (left) left += 16;
DCMode(C8DC8 + dst, left, top, 8, 8, 4);
VerticalPred(C8VE8 + dst, top, 8);
HorizontalPred(C8HE8 + dst, left, 8);
TrueMotion(C8TM8 + dst, left, top, 8);
}
//------------------------------------------------------------------------------
// luma 16x16 prediction (paragraph 12.3)
static void Intra16Preds(uint8_t* dst,
const uint8_t* left, const uint8_t* top) {
DCMode(I16DC16 + dst, left, top, 16, 16, 5);
VerticalPred(I16VE16 + dst, top, 16);
HorizontalPred(I16HE16 + dst, left, 16);
TrueMotion(I16TM16 + dst, left, top, 16);
}
//------------------------------------------------------------------------------
// luma 4x4 prediction
#define AVG3(a, b, c) (((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
const uint8_t vals[4] = {
AVG3(top[-1], top[0], top[1]),
AVG3(top[ 0], top[1], top[2]),
AVG3(top[ 1], top[2], top[3]),
AVG3(top[ 2], top[3], top[4])
};
int i;
for (i = 0; i < 4; ++i) {
memcpy(dst + i * BPS, vals, 4);
}
}
static 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];
*(uint32_t*)(dst + 0 * BPS) = 0x01010101U * AVG3(X, I, J);
*(uint32_t*)(dst + 1 * BPS) = 0x01010101U * AVG3(I, J, K);
*(uint32_t*)(dst + 2 * BPS) = 0x01010101U * AVG3(J, K, L);
*(uint32_t*)(dst + 3 * BPS) = 0x01010101U * AVG3(K, L, L);
}
static 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];
Fill(dst, dc >> 3, 4);
}
static void RD4(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];
const int D = top[3];
OUT(0, 3) = AVG3(J, K, L);
OUT(0, 2) = OUT(1, 3) = AVG3(I, J, K);
OUT(0, 1) = OUT(1, 2) = OUT(2, 3) = AVG3(X, I, J);
OUT(0, 0) = OUT(1, 1) = OUT(2, 2) = OUT(3, 3) = AVG3(A, X, I);
OUT(1, 0) = OUT(2, 1) = OUT(3, 2) = AVG3(B, A, X);
OUT(2, 0) = OUT(3, 1) = AVG3(C, B, A);
OUT(3, 0) = AVG3(D, C, B);
}
static void LD4(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];
OUT(0, 0) = AVG3(A, B, C);
OUT(1, 0) = OUT(0, 1) = AVG3(B, C, D);
OUT(2, 0) = OUT(1, 1) = OUT(0, 2) = AVG3(C, D, E);
OUT(3, 0) = OUT(2, 1) = OUT(1, 2) = OUT(0, 3) = AVG3(D, E, F);
OUT(3, 1) = OUT(2, 2) = OUT(1, 3) = AVG3(E, F, G);
OUT(3, 2) = OUT(2, 3) = AVG3(F, G, H);
OUT(3, 3) = AVG3(G, H, H);
}
static 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];
OUT(0, 0) = OUT(1, 2) = AVG2(X, A);
OUT(1, 0) = OUT(2, 2) = AVG2(A, B);
OUT(2, 0) = OUT(3, 2) = AVG2(B, C);
OUT(3, 0) = AVG2(C, D);
OUT(0, 3) = AVG3(K, J, I);
OUT(0, 2) = AVG3(J, I, X);
OUT(0, 1) = OUT(1, 3) = AVG3(I, X, A);
OUT(1, 1) = OUT(2, 3) = AVG3(X, A, B);
OUT(2, 1) = OUT(3, 3) = AVG3(A, B, C);
OUT(3, 1) = AVG3(B, C, D);
}
static 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];
OUT(0, 0) = AVG2(A, B);
OUT(1, 0) = OUT(0, 2) = AVG2(B, C);
OUT(2, 0) = OUT(1, 2) = AVG2(C, D);
OUT(3, 0) = OUT(2, 2) = AVG2(D, E);
OUT(0, 1) = AVG3(A, B, C);
OUT(1, 1) = OUT(0, 3) = AVG3(B, C, D);
OUT(2, 1) = OUT(1, 3) = AVG3(C, D, E);
OUT(3, 1) = OUT(2, 3) = AVG3(D, E, F);
OUT(3, 2) = AVG3(E, F, G);
OUT(3, 3) = AVG3(F, G, H);
}
static 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];
OUT(0, 0) = AVG2(I, J);
OUT(2, 0) = OUT(0, 1) = AVG2(J, K);
OUT(2, 1) = OUT(0, 2) = AVG2(K, L);
OUT(1, 0) = AVG3(I, J, K);
OUT(3, 0) = OUT(1, 1) = AVG3(J, K, L);
OUT(3, 1) = OUT(1, 2) = AVG3(K, L, L);
OUT(3, 2) = OUT(2, 2) =
OUT(0, 3) = OUT(1, 3) = OUT(2, 3) = OUT(3, 3) = L;
}
static 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];
OUT(0, 0) = OUT(2, 1) = AVG2(I, X);
OUT(0, 1) = OUT(2, 2) = AVG2(J, I);
OUT(0, 2) = OUT(2, 3) = AVG2(K, J);
OUT(0, 3) = AVG2(L, K);
OUT(3, 0) = AVG3(A, B, C);
OUT(2, 0) = AVG3(X, A, B);
OUT(1, 0) = OUT(3, 1) = AVG3(I, X, A);
OUT(1, 1) = OUT(3, 2) = AVG3(J, I, X);
OUT(1, 2) = OUT(3, 3) = AVG3(K, J, I);
OUT(1, 3) = AVG3(L, K, J);
}
static void TM4(uint8_t* dst, const uint8_t* top) {
int x, y;
const uint8_t* const clip = clip1 + 255 - top[-1];
for (y = 0; y < 4; ++y) {
const uint8_t* const clip_table = clip + top[-2 - y];
for (x = 0; x < 4; ++x) {
dst[x] = clip_table[top[x]];
}
dst += BPS;
}
}
#undef AVG3
#undef AVG2
// Left samples are top[-5 .. -2], top_left is top[-1], top are
// located at top[0..3], and top right is top[4..7]
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);
}
//------------------------------------------------------------------------------
// Metric
static inline int GetSSE(const uint8_t* a, const uint8_t* b, int w, int h) {
int count = 0;
int y, x;
for (y = 0; y < h; ++y) {
for (x = 0; x < w; ++x) {
const int diff = (int)a[x] - b[x];
count += diff * diff;
}
a += BPS;
b += BPS;
}
return count;
}
static int SSE16x16(const uint8_t* a, const uint8_t* b) {
return GetSSE(a, b, 16, 16);
}
static int SSE16x8(const uint8_t* a, const uint8_t* b) {
return GetSSE(a, b, 16, 8);
}
static int SSE8x8(const uint8_t* a, const uint8_t* b) {
return GetSSE(a, b, 8, 8);
}
static int SSE4x4(const uint8_t* a, const uint8_t* b) {
return GetSSE(a, b, 4, 4);
}
//------------------------------------------------------------------------------
// Texture distortion
//
// We try to match the spectral content (weighted) between source and
// reconstructed samples.
// Hadamard transform
// Returns the weighted sum of the absolute value of transformed coefficients.
static int TTransform(const uint8_t* in, const uint16_t* w) {
int sum = 0;
int tmp[16];
int i;
// horizontal pass
for (i = 0; i < 4; ++i, in += BPS) {
const int a0 = (in[0] + in[2]) << 2;
const int a1 = (in[1] + in[3]) << 2;
const int a2 = (in[1] - in[3]) << 2;
const int a3 = (in[0] - in[2]) << 2;
tmp[0 + i * 4] = a0 + a1 + (a0 != 0);
tmp[1 + i * 4] = a3 + a2;
tmp[2 + i * 4] = a3 - a2;
tmp[3 + i * 4] = a0 - a1;
}
// vertical pass
for (i = 0; i < 4; ++i, ++w) {
const int a0 = (tmp[0 + i] + tmp[8 + i]);
const int a1 = (tmp[4 + i] + tmp[12+ i]);
const int a2 = (tmp[4 + i] - tmp[12+ i]);
const int a3 = (tmp[0 + i] - tmp[8 + i]);
const int b0 = a0 + a1;
const int b1 = a3 + a2;
const int b2 = a3 - a2;
const int b3 = a0 - a1;
// abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3
sum += w[ 0] * ((abs(b0) + 3) >> 3);
sum += w[ 4] * ((abs(b1) + 3) >> 3);
sum += w[ 8] * ((abs(b2) + 3) >> 3);
sum += w[12] * ((abs(b3) + 3) >> 3);
}
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) + 8) >> 4;
}
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;
}
//------------------------------------------------------------------------------
// Quantization
//
// Simple quantization
static int QuantizeBlock(int16_t in[16], int16_t out[16],
int n, const VP8Matrix* const mtx) {
int last = -1;
for (; n < 16; ++n) {
const int j = VP8Zigzag[n];
const int sign = (in[j] < 0);
int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
if (coeff > 2047) coeff = 2047;
if (coeff > mtx->zthresh_[j]) {
const int Q = mtx->q_[j];
const int iQ = mtx->iq_[j];
const int B = mtx->bias_[j];
out[n] = QUANTDIV(coeff, iQ, B);
if (sign) out[n] = -out[n];
in[j] = out[n] * Q;
if (out[n]) last = n;
} else {
out[n] = 0;
in[j] = 0;
}
}
return (last >= 0);
}
//------------------------------------------------------------------------------
// Block copy
static inline void Copy(const uint8_t* src, uint8_t* dst, int size) {
int y;
for (y = 0; y < size; ++y) {
memcpy(dst, src, size);
src += BPS;
dst += BPS;
}
}
static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); }
static void Copy8x8(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 8); }
static void Copy16x16(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 16); }
//------------------------------------------------------------------------------
// SSE2 detection.
//
#if defined(__pic__) && defined(__i386__)
static inline void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
"mov %%ebx, %%edi\n"
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type));
}
#elif defined(__i386__) || defined(__x86_64__)
static inline void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
"cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type));
}
#elif defined(_MSC_VER) // Visual C++
#define GetCPUInfo __cpuid
#endif
#if defined(__i386__) || defined(__x86_64__) || defined(_MSC_VER)
static int x86CPUInfo(CPUFeature feature) {
int cpu_info[4];
GetCPUInfo(cpu_info, 1);
if (feature == kSSE2) {
return 0 != (cpu_info[3] & 0x04000000);
}
if (feature == kSSE3) {
return 0 != (cpu_info[2] & 0x00000001);
}
return 0;
}
VP8CPUInfo VP8EncGetCPUInfo = x86CPUInfo;
#else
VP8CPUInfo VP8EncGetCPUInfo = NULL;
#endif
// Speed-critical function pointers. We have to initialize them to the default
// implementations within VP8EncDspInit().
VP8CHisto VP8CollectHistogram;
VP8Idct VP8ITransform;
VP8Fdct VP8FTransform;
VP8WHT VP8ITransformWHT;
VP8WHT VP8FTransformWHT;
VP8Intra4Preds VP8EncPredLuma4;
VP8IntraPreds VP8EncPredLuma16;
VP8IntraPreds VP8EncPredChroma8;
VP8Metric VP8SSE16x16;
VP8Metric VP8SSE8x8;
VP8Metric VP8SSE16x8;
VP8Metric VP8SSE4x4;
VP8WMetric VP8TDisto4x4;
VP8WMetric VP8TDisto16x16;
VP8QuantizeBlock VP8EncQuantizeBlock;
VP8BlockCopy VP8Copy4x4;
VP8BlockCopy VP8Copy8x8;
VP8BlockCopy VP8Copy16x16;
extern void VP8EncDspInitSSE2(void);
void VP8EncDspInit(void) {
InitTables();
// default C implementations
VP8CollectHistogram = CollectHistogram;
VP8ITransform = ITransform;
VP8FTransform = FTransform;
VP8ITransformWHT = ITransformWHT;
VP8FTransformWHT = FTransformWHT;
VP8EncPredLuma4 = Intra4Preds;
VP8EncPredLuma16 = Intra16Preds;
VP8EncPredChroma8 = IntraChromaPreds;
VP8SSE16x16 = SSE16x16;
VP8SSE8x8 = SSE8x8;
VP8SSE16x8 = SSE16x8;
VP8SSE4x4 = SSE4x4;
VP8TDisto4x4 = Disto4x4;
VP8TDisto16x16 = Disto16x16;
VP8EncQuantizeBlock = QuantizeBlock;
VP8Copy4x4 = Copy4x4;
VP8Copy8x8 = Copy8x8;
VP8Copy16x16 = Copy16x16;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8EncGetCPUInfo) {
if (VP8EncGetCPUInfo(kSSE2)) {
#if defined(__SSE2__) || defined(_MSC_VER)
VP8EncDspInitSSE2();
#endif
}
if (VP8EncGetCPUInfo(kSSE3)) {
// later we'll plug some SSE3 variant here
}
}
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,834 +0,0 @@
// Copyright 2011 Google Inc.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// SSE2 version of speed-critical functions.
//
// Author: Christian Duvivier (cduvivier@google.com)
#if defined(__SSE2__) || defined(_MSC_VER)
#include <emmintrin.h>
#include "vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// Compute susceptibility based on DCT-coeff histograms:
// the higher, the "easier" the macroblock is to compress.
static int CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
int start_block, int end_block) {
int histo[MAX_COEFF_THRESH + 1] = { 0 };
int16_t out[16];
int j, k;
const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH);
for (j = start_block; j < end_block; ++j) {
VP8FTransform(ref + VP8Scan[j], pred + VP8Scan[j], out);
// Convert coefficients to bin (within out[]).
{
// Load.
const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]);
const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]);
// sign(out) = out >> 15 (0x0000 if positive, 0xffff if negative)
const __m128i sign0 = _mm_srai_epi16(out0, 15);
const __m128i sign1 = _mm_srai_epi16(out1, 15);
// abs(out) = (out ^ sign) - sign
const __m128i xor0 = _mm_xor_si128(out0, sign0);
const __m128i xor1 = _mm_xor_si128(out1, sign1);
const __m128i abs0 = _mm_sub_epi16(xor0, sign0);
const __m128i abs1 = _mm_sub_epi16(xor1, sign1);
// v = abs(out) >> 2
const __m128i v0 = _mm_srai_epi16(abs0, 2);
const __m128i v1 = _mm_srai_epi16(abs1, 2);
// bin = min(v, MAX_COEFF_THRESH)
const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh);
const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh);
// Store.
_mm_storeu_si128((__m128i*)&out[0], bin0);
_mm_storeu_si128((__m128i*)&out[8], bin1);
}
// Use bin to update histogram.
for (k = 0; k < 16; ++k) {
histo[out[k]]++;
}
}
return VP8GetAlpha(histo);
}
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
// Does one or two inverse transforms.
static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
int do_two) {
// This implementation makes use of 16-bit fixed point versions of two
// multiply constants:
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
// K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16
//
// To be able to use signed 16-bit integers, we use the following trick to
// have constants within range:
// - Associated constants are obtained by subtracting the 16-bit fixed point
// version of one:
// k = K - (1 << 16) => K = k + (1 << 16)
// K1 = 85267 => k1 = 20091
// K2 = 35468 => k2 = -30068
// - The multiplication of a variable by a constant become the sum of the
// variable and the multiplication of that variable by the associated
// constant:
// (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x
const __m128i k1 = _mm_set1_epi16(20091);
const __m128i k2 = _mm_set1_epi16(-30068);
__m128i T0, T1, T2, T3;
// Load and concatenate the transform coefficients (we'll do two inverse
// transforms in parallel). In the case of only one inverse transform, the
// second half of the vectors will just contain random value we'll never
// use nor store.
__m128i in0, in1, in2, in3;
{
in0 = _mm_loadl_epi64((__m128i*)&in[0]);
in1 = _mm_loadl_epi64((__m128i*)&in[4]);
in2 = _mm_loadl_epi64((__m128i*)&in[8]);
in3 = _mm_loadl_epi64((__m128i*)&in[12]);
// a00 a10 a20 a30 x x x x
// a01 a11 a21 a31 x x x x
// a02 a12 a22 a32 x x x x
// a03 a13 a23 a33 x x x x
if (do_two) {
const __m128i inB0 = _mm_loadl_epi64((__m128i*)&in[16]);
const __m128i inB1 = _mm_loadl_epi64((__m128i*)&in[20]);
const __m128i inB2 = _mm_loadl_epi64((__m128i*)&in[24]);
const __m128i inB3 = _mm_loadl_epi64((__m128i*)&in[28]);
in0 = _mm_unpacklo_epi64(in0, inB0);
in1 = _mm_unpacklo_epi64(in1, inB1);
in2 = _mm_unpacklo_epi64(in2, inB2);
in3 = _mm_unpacklo_epi64(in3, inB3);
// a00 a10 a20 a30 b00 b10 b20 b30
// a01 a11 a21 a31 b01 b11 b21 b31
// a02 a12 a22 a32 b02 b12 b22 b32
// a03 a13 a23 a33 b03 b13 b23 b33
}
}
// Vertical pass and subsequent transpose.
{
// First pass, c and d calculations are longer because of the "trick"
// multiplications.
const __m128i a = _mm_add_epi16(in0, in2);
const __m128i b = _mm_sub_epi16(in0, in2);
// c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3
const __m128i c1 = _mm_mulhi_epi16(in1, k2);
const __m128i c2 = _mm_mulhi_epi16(in3, k1);
const __m128i c3 = _mm_sub_epi16(in1, in3);
const __m128i c4 = _mm_sub_epi16(c1, c2);
const __m128i c = _mm_add_epi16(c3, c4);
// d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3
const __m128i d1 = _mm_mulhi_epi16(in1, k1);
const __m128i d2 = _mm_mulhi_epi16(in3, k2);
const __m128i d3 = _mm_add_epi16(in1, in3);
const __m128i d4 = _mm_add_epi16(d1, d2);
const __m128i d = _mm_add_epi16(d3, d4);
// Second pass.
const __m128i tmp0 = _mm_add_epi16(a, d);
const __m128i tmp1 = _mm_add_epi16(b, c);
const __m128i tmp2 = _mm_sub_epi16(b, c);
const __m128i tmp3 = _mm_sub_epi16(a, d);
// Transpose the two 4x4.
// a00 a01 a02 a03 b00 b01 b02 b03
// a10 a11 a12 a13 b10 b11 b12 b13
// a20 a21 a22 a23 b20 b21 b22 b23
// a30 a31 a32 a33 b30 b31 b32 b33
const __m128i transpose0_0 = _mm_unpacklo_epi16(tmp0, tmp1);
const __m128i transpose0_1 = _mm_unpacklo_epi16(tmp2, tmp3);
const __m128i transpose0_2 = _mm_unpackhi_epi16(tmp0, tmp1);
const __m128i transpose0_3 = _mm_unpackhi_epi16(tmp2, tmp3);
// a00 a10 a01 a11 a02 a12 a03 a13
// a20 a30 a21 a31 a22 a32 a23 a33
// b00 b10 b01 b11 b02 b12 b03 b13
// b20 b30 b21 b31 b22 b32 b23 b33
const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
// a00 a10 a20 a30 a01 a11 a21 a31
// b00 b10 b20 b30 b01 b11 b21 b31
// a02 a12 a22 a32 a03 a13 a23 a33
// b02 b12 a22 b32 b03 b13 b23 b33
T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
// a00 a10 a20 a30 b00 b10 b20 b30
// a01 a11 a21 a31 b01 b11 b21 b31
// a02 a12 a22 a32 b02 b12 b22 b32
// a03 a13 a23 a33 b03 b13 b23 b33
}
// Horizontal pass and subsequent transpose.
{
// First pass, c and d calculations are longer because of the "trick"
// multiplications.
const __m128i four = _mm_set1_epi16(4);
const __m128i dc = _mm_add_epi16(T0, four);
const __m128i a = _mm_add_epi16(dc, T2);
const __m128i b = _mm_sub_epi16(dc, T2);
// c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3
const __m128i c1 = _mm_mulhi_epi16(T1, k2);
const __m128i c2 = _mm_mulhi_epi16(T3, k1);
const __m128i c3 = _mm_sub_epi16(T1, T3);
const __m128i c4 = _mm_sub_epi16(c1, c2);
const __m128i c = _mm_add_epi16(c3, c4);
// d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3
const __m128i d1 = _mm_mulhi_epi16(T1, k1);
const __m128i d2 = _mm_mulhi_epi16(T3, k2);
const __m128i d3 = _mm_add_epi16(T1, T3);
const __m128i d4 = _mm_add_epi16(d1, d2);
const __m128i d = _mm_add_epi16(d3, d4);
// Second pass.
const __m128i tmp0 = _mm_add_epi16(a, d);
const __m128i tmp1 = _mm_add_epi16(b, c);
const __m128i tmp2 = _mm_sub_epi16(b, c);
const __m128i tmp3 = _mm_sub_epi16(a, d);
const __m128i shifted0 = _mm_srai_epi16(tmp0, 3);
const __m128i shifted1 = _mm_srai_epi16(tmp1, 3);
const __m128i shifted2 = _mm_srai_epi16(tmp2, 3);
const __m128i shifted3 = _mm_srai_epi16(tmp3, 3);
// Transpose the two 4x4.
// a00 a01 a02 a03 b00 b01 b02 b03
// a10 a11 a12 a13 b10 b11 b12 b13
// a20 a21 a22 a23 b20 b21 b22 b23
// a30 a31 a32 a33 b30 b31 b32 b33
const __m128i transpose0_0 = _mm_unpacklo_epi16(shifted0, shifted1);
const __m128i transpose0_1 = _mm_unpacklo_epi16(shifted2, shifted3);
const __m128i transpose0_2 = _mm_unpackhi_epi16(shifted0, shifted1);
const __m128i transpose0_3 = _mm_unpackhi_epi16(shifted2, shifted3);
// a00 a10 a01 a11 a02 a12 a03 a13
// a20 a30 a21 a31 a22 a32 a23 a33
// b00 b10 b01 b11 b02 b12 b03 b13
// b20 b30 b21 b31 b22 b32 b23 b33
const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
// a00 a10 a20 a30 a01 a11 a21 a31
// b00 b10 b20 b30 b01 b11 b21 b31
// a02 a12 a22 a32 a03 a13 a23 a33
// b02 b12 a22 b32 b03 b13 b23 b33
T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
// a00 a10 a20 a30 b00 b10 b20 b30
// a01 a11 a21 a31 b01 b11 b21 b31
// a02 a12 a22 a32 b02 b12 b22 b32
// a03 a13 a23 a33 b03 b13 b23 b33
}
// Add inverse transform to 'ref' and store.
{
const __m128i zero = _mm_set1_epi16(0);
// Load the reference(s).
__m128i ref0, ref1, ref2, ref3;
if (do_two) {
// Load eight bytes/pixels per line.
ref0 = _mm_loadl_epi64((__m128i*)&ref[0 * BPS]);
ref1 = _mm_loadl_epi64((__m128i*)&ref[1 * BPS]);
ref2 = _mm_loadl_epi64((__m128i*)&ref[2 * BPS]);
ref3 = _mm_loadl_epi64((__m128i*)&ref[3 * BPS]);
} else {
// Load four bytes/pixels per line.
ref0 = _mm_cvtsi32_si128(*(int*)&ref[0 * BPS]);
ref1 = _mm_cvtsi32_si128(*(int*)&ref[1 * BPS]);
ref2 = _mm_cvtsi32_si128(*(int*)&ref[2 * BPS]);
ref3 = _mm_cvtsi32_si128(*(int*)&ref[3 * BPS]);
}
// Convert to 16b.
ref0 = _mm_unpacklo_epi8(ref0, zero);
ref1 = _mm_unpacklo_epi8(ref1, zero);
ref2 = _mm_unpacklo_epi8(ref2, zero);
ref3 = _mm_unpacklo_epi8(ref3, zero);
// Add the inverse transform(s).
ref0 = _mm_add_epi16(ref0, T0);
ref1 = _mm_add_epi16(ref1, T1);
ref2 = _mm_add_epi16(ref2, T2);
ref3 = _mm_add_epi16(ref3, T3);
// Unsigned saturate to 8b.
ref0 = _mm_packus_epi16(ref0, ref0);
ref1 = _mm_packus_epi16(ref1, ref1);
ref2 = _mm_packus_epi16(ref2, ref2);
ref3 = _mm_packus_epi16(ref3, ref3);
// Store the results.
if (do_two) {
// Store eight bytes/pixels per line.
_mm_storel_epi64((__m128i*)&dst[0 * BPS], ref0);
_mm_storel_epi64((__m128i*)&dst[1 * BPS], ref1);
_mm_storel_epi64((__m128i*)&dst[2 * BPS], ref2);
_mm_storel_epi64((__m128i*)&dst[3 * BPS], ref3);
} else {
// Store four bytes/pixels per line.
*((int32_t *)&dst[0 * BPS]) = _mm_cvtsi128_si32(ref0);
*((int32_t *)&dst[1 * BPS]) = _mm_cvtsi128_si32(ref1);
*((int32_t *)&dst[2 * BPS]) = _mm_cvtsi128_si32(ref2);
*((int32_t *)&dst[3 * BPS]) = _mm_cvtsi128_si32(ref3);
}
}
}
static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
int16_t* out) {
const __m128i zero = _mm_setzero_si128();
const __m128i seven = _mm_set1_epi16(7);
const __m128i k7500 = _mm_set1_epi32(7500);
const __m128i k14500 = _mm_set1_epi32(14500);
const __m128i k51000 = _mm_set1_epi32(51000);
const __m128i k12000_plus_one = _mm_set1_epi32(12000 + (1 << 16));
const __m128i k5352_2217 = _mm_set_epi16(5352, 2217, 5352, 2217,
5352, 2217, 5352, 2217);
const __m128i k2217_5352 = _mm_set_epi16(2217, -5352, 2217, -5352,
2217, -5352, 2217, -5352);
__m128i v01, v32;
// Difference between src and ref and initial transpose.
{
// Load src and convert to 16b.
const __m128i src0 = _mm_loadl_epi64((__m128i*)&src[0 * BPS]);
const __m128i src1 = _mm_loadl_epi64((__m128i*)&src[1 * BPS]);
const __m128i src2 = _mm_loadl_epi64((__m128i*)&src[2 * BPS]);
const __m128i src3 = _mm_loadl_epi64((__m128i*)&src[3 * BPS]);
const __m128i src_0 = _mm_unpacklo_epi8(src0, zero);
const __m128i src_1 = _mm_unpacklo_epi8(src1, zero);
const __m128i src_2 = _mm_unpacklo_epi8(src2, zero);
const __m128i src_3 = _mm_unpacklo_epi8(src3, zero);
// Load ref and convert to 16b.
const __m128i ref0 = _mm_loadl_epi64((__m128i*)&ref[0 * BPS]);
const __m128i ref1 = _mm_loadl_epi64((__m128i*)&ref[1 * BPS]);
const __m128i ref2 = _mm_loadl_epi64((__m128i*)&ref[2 * BPS]);
const __m128i ref3 = _mm_loadl_epi64((__m128i*)&ref[3 * BPS]);
const __m128i ref_0 = _mm_unpacklo_epi8(ref0, zero);
const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero);
const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero);
const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero);
// Compute difference.
const __m128i diff0 = _mm_sub_epi16(src_0, ref_0);
const __m128i diff1 = _mm_sub_epi16(src_1, ref_1);
const __m128i diff2 = _mm_sub_epi16(src_2, ref_2);
const __m128i diff3 = _mm_sub_epi16(src_3, ref_3);
// Transpose.
// 00 01 02 03 0 0 0 0
// 10 11 12 13 0 0 0 0
// 20 21 22 23 0 0 0 0
// 30 31 32 33 0 0 0 0
const __m128i transpose0_0 = _mm_unpacklo_epi16(diff0, diff1);
const __m128i transpose0_1 = _mm_unpacklo_epi16(diff2, diff3);
// 00 10 01 11 02 12 03 13
// 20 30 21 31 22 32 23 33
const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2));
// a02 a12 a22 a32 a03 a13 a23 a33
// a00 a10 a20 a30 a01 a11 a21 a31
// a03 a13 a23 a33 a02 a12 a22 a32
}
// First pass and subsequent transpose.
{
// Same operations are done on the (0,3) and (1,2) pairs.
// b0 = (a0 + a3) << 3
// b1 = (a1 + a2) << 3
// b3 = (a0 - a3) << 3
// b2 = (a1 - a2) << 3
const __m128i a01 = _mm_add_epi16(v01, v32);
const __m128i a32 = _mm_sub_epi16(v01, v32);
const __m128i b01 = _mm_slli_epi16(a01, 3);
const __m128i b32 = _mm_slli_epi16(a32, 3);
const __m128i b11 = _mm_unpackhi_epi64(b01, b01);
const __m128i b22 = _mm_unpackhi_epi64(b32, b32);
// e0 = b0 + b1
// e2 = b0 - b1
const __m128i e0 = _mm_add_epi16(b01, b11);
const __m128i e2 = _mm_sub_epi16(b01, b11);
const __m128i e02 = _mm_unpacklo_epi64(e0, e2);
// e1 = (b3 * 5352 + b2 * 2217 + 14500) >> 12
// e3 = (b3 * 2217 - b2 * 5352 + 7500) >> 12
const __m128i b23 = _mm_unpacklo_epi16(b22, b32);
const __m128i c1 = _mm_madd_epi16(b23, k5352_2217);
const __m128i c3 = _mm_madd_epi16(b23, k2217_5352);
const __m128i d1 = _mm_add_epi32(c1, k14500);
const __m128i d3 = _mm_add_epi32(c3, k7500);
const __m128i e1 = _mm_srai_epi32(d1, 12);
const __m128i e3 = _mm_srai_epi32(d3, 12);
const __m128i e13 = _mm_packs_epi32(e1, e3);
// Transpose.
// 00 01 02 03 20 21 22 23
// 10 11 12 13 30 31 32 33
const __m128i transpose0_0 = _mm_unpacklo_epi16(e02, e13);
const __m128i transpose0_1 = _mm_unpackhi_epi16(e02, e13);
// 00 10 01 11 02 12 03 13
// 20 30 21 31 22 32 23 33
const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2));
// 02 12 22 32 03 13 23 33
// 00 10 20 30 01 11 21 31
// 03 13 23 33 02 12 22 32
}
// Second pass
{
// 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);
// d0 = (a0 + a1 + 7) >> 4;
// d2 = (a0 - a1 + 7) >> 4;
const __m128i b0 = _mm_add_epi16(a01, a11);
const __m128i b2 = _mm_sub_epi16(a01, a11);
const __m128i c0 = _mm_add_epi16(b0, seven);
const __m128i c2 = _mm_add_epi16(b2, seven);
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);
const __m128i d1 = _mm_add_epi32(c1, k12000_plus_one);
const __m128i d3 = _mm_add_epi32(c3, k51000);
const __m128i e1 = _mm_srai_epi32(d1, 16);
const __m128i e3 = _mm_srai_epi32(d3, 16);
const __m128i f1 = _mm_packs_epi32(e1, e1);
const __m128i f3 = _mm_packs_epi32(e3, e3);
// f1 = 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.
const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero));
_mm_storel_epi64((__m128i*)&out[ 0], d0);
_mm_storel_epi64((__m128i*)&out[ 4], g1);
_mm_storel_epi64((__m128i*)&out[ 8], d2);
_mm_storel_epi64((__m128i*)&out[12], f3);
}
}
//------------------------------------------------------------------------------
// Metric
static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
const __m128i zero = _mm_set1_epi16(0);
// Load values.
const __m128i a0 = _mm_loadl_epi64((__m128i*)&a[BPS * 0]);
const __m128i a1 = _mm_loadl_epi64((__m128i*)&a[BPS * 1]);
const __m128i a2 = _mm_loadl_epi64((__m128i*)&a[BPS * 2]);
const __m128i a3 = _mm_loadl_epi64((__m128i*)&a[BPS * 3]);
const __m128i b0 = _mm_loadl_epi64((__m128i*)&b[BPS * 0]);
const __m128i b1 = _mm_loadl_epi64((__m128i*)&b[BPS * 1]);
const __m128i b2 = _mm_loadl_epi64((__m128i*)&b[BPS * 2]);
const __m128i b3 = _mm_loadl_epi64((__m128i*)&b[BPS * 3]);
// Combine pair of lines and convert to 16b.
const __m128i a01 = _mm_unpacklo_epi32(a0, a1);
const __m128i a23 = _mm_unpacklo_epi32(a2, a3);
const __m128i b01 = _mm_unpacklo_epi32(b0, b1);
const __m128i b23 = _mm_unpacklo_epi32(b2, b3);
const __m128i a01s = _mm_unpacklo_epi8(a01, zero);
const __m128i a23s = _mm_unpacklo_epi8(a23, zero);
const __m128i b01s = _mm_unpacklo_epi8(b01, zero);
const __m128i b23s = _mm_unpacklo_epi8(b23, zero);
// Compute differences; (a-b)^2 = (abs(a-b))^2 = (sat8(a-b) + sat8(b-a))^2
// TODO(cduvivier): Dissassemble and figure out why this is fastest. We don't
// need absolute values, there is no need to do calculation
// in 8bit as we are already in 16bit, ... Yet this is what
// benchmarks the fastest!
const __m128i d0 = _mm_subs_epu8(a01s, b01s);
const __m128i d1 = _mm_subs_epu8(b01s, a01s);
const __m128i d2 = _mm_subs_epu8(a23s, b23s);
const __m128i d3 = _mm_subs_epu8(b23s, a23s);
// Square and add them all together.
const __m128i madd0 = _mm_madd_epi16(d0, d0);
const __m128i madd1 = _mm_madd_epi16(d1, d1);
const __m128i madd2 = _mm_madd_epi16(d2, d2);
const __m128i madd3 = _mm_madd_epi16(d3, d3);
const __m128i sum0 = _mm_add_epi32(madd0, madd1);
const __m128i sum1 = _mm_add_epi32(madd2, madd3);
const __m128i sum2 = _mm_add_epi32(sum0, sum1);
int32_t tmp[4];
_mm_storeu_si128((__m128i*)tmp, sum2);
return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
}
//------------------------------------------------------------------------------
// Texture distortion
//
// We try to match the spectral content (weighted) between source and
// reconstructed samples.
// Hadamard transform
// Returns the difference between the weighted sum of the absolute value of
// transformed coefficients.
static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
const uint16_t* const w) {
int32_t sum[4];
__m128i tmp_0, tmp_1, tmp_2, tmp_3;
const __m128i zero = _mm_setzero_si128();
const __m128i one = _mm_set1_epi16(1);
const __m128i three = _mm_set1_epi16(3);
// Load, combine and tranpose inputs.
{
const __m128i inA_0 = _mm_loadl_epi64((__m128i*)&inA[BPS * 0]);
const __m128i inA_1 = _mm_loadl_epi64((__m128i*)&inA[BPS * 1]);
const __m128i inA_2 = _mm_loadl_epi64((__m128i*)&inA[BPS * 2]);
const __m128i inA_3 = _mm_loadl_epi64((__m128i*)&inA[BPS * 3]);
const __m128i inB_0 = _mm_loadl_epi64((__m128i*)&inB[BPS * 0]);
const __m128i inB_1 = _mm_loadl_epi64((__m128i*)&inB[BPS * 1]);
const __m128i inB_2 = _mm_loadl_epi64((__m128i*)&inB[BPS * 2]);
const __m128i inB_3 = _mm_loadl_epi64((__m128i*)&inB[BPS * 3]);
// Combine inA and inB (we'll do two transforms in parallel).
const __m128i inAB_0 = _mm_unpacklo_epi8(inA_0, inB_0);
const __m128i inAB_1 = _mm_unpacklo_epi8(inA_1, inB_1);
const __m128i inAB_2 = _mm_unpacklo_epi8(inA_2, inB_2);
const __m128i inAB_3 = _mm_unpacklo_epi8(inA_3, inB_3);
// a00 b00 a01 b01 a02 b03 a03 b03 0 0 0 0 0 0 0 0
// a10 b10 a11 b11 a12 b12 a13 b13 0 0 0 0 0 0 0 0
// a20 b20 a21 b21 a22 b22 a23 b23 0 0 0 0 0 0 0 0
// a30 b30 a31 b31 a32 b32 a33 b33 0 0 0 0 0 0 0 0
// Transpose the two 4x4, discarding the filling zeroes.
const __m128i transpose0_0 = _mm_unpacklo_epi8(inAB_0, inAB_2);
const __m128i transpose0_1 = _mm_unpacklo_epi8(inAB_1, inAB_3);
// a00 a20 b00 b20 a01 a21 b01 b21 a02 a22 b02 b22 a03 a23 b03 b23
// a10 a30 b10 b30 a11 a31 b11 b31 a12 a32 b12 b32 a13 a33 b13 b33
const __m128i transpose1_0 = _mm_unpacklo_epi8(transpose0_0, transpose0_1);
const __m128i transpose1_1 = _mm_unpackhi_epi8(transpose0_0, transpose0_1);
// a00 a10 a20 a30 b00 b10 b20 b30 a01 a11 a21 a31 b01 b11 b21 b31
// a02 a12 a22 a32 b02 b12 b22 b32 a03 a13 a23 a33 b03 b13 b23 b33
// Convert to 16b.
tmp_0 = _mm_unpacklo_epi8(transpose1_0, zero);
tmp_1 = _mm_unpackhi_epi8(transpose1_0, zero);
tmp_2 = _mm_unpacklo_epi8(transpose1_1, zero);
tmp_3 = _mm_unpackhi_epi8(transpose1_1, zero);
// a00 a10 a20 a30 b00 b10 b20 b30
// a01 a11 a21 a31 b01 b11 b21 b31
// a02 a12 a22 a32 b02 b12 b22 b32
// a03 a13 a23 a33 b03 b13 b23 b33
}
// Horizontal pass and subsequent transpose.
{
// Calculate a and b (two 4x4 at once).
const __m128i a0 = _mm_slli_epi16(_mm_add_epi16(tmp_0, tmp_2), 2);
const __m128i a1 = _mm_slli_epi16(_mm_add_epi16(tmp_1, tmp_3), 2);
const __m128i a2 = _mm_slli_epi16(_mm_sub_epi16(tmp_1, tmp_3), 2);
const __m128i a3 = _mm_slli_epi16(_mm_sub_epi16(tmp_0, tmp_2), 2);
// b0_extra = (a0 != 0);
const __m128i b0_extra = _mm_andnot_si128(_mm_cmpeq_epi16 (a0, zero), one);
const __m128i b0_base = _mm_add_epi16(a0, a1);
const __m128i b1 = _mm_add_epi16(a3, a2);
const __m128i b2 = _mm_sub_epi16(a3, a2);
const __m128i b3 = _mm_sub_epi16(a0, a1);
const __m128i b0 = _mm_add_epi16(b0_base, b0_extra);
// a00 a01 a02 a03 b00 b01 b02 b03
// a10 a11 a12 a13 b10 b11 b12 b13
// a20 a21 a22 a23 b20 b21 b22 b23
// a30 a31 a32 a33 b30 b31 b32 b33
// Transpose the two 4x4.
const __m128i transpose0_0 = _mm_unpacklo_epi16(b0, b1);
const __m128i transpose0_1 = _mm_unpacklo_epi16(b2, b3);
const __m128i transpose0_2 = _mm_unpackhi_epi16(b0, b1);
const __m128i transpose0_3 = _mm_unpackhi_epi16(b2, b3);
// a00 a10 a01 a11 a02 a12 a03 a13
// a20 a30 a21 a31 a22 a32 a23 a33
// b00 b10 b01 b11 b02 b12 b03 b13
// b20 b30 b21 b31 b22 b32 b23 b33
const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
// a00 a10 a20 a30 a01 a11 a21 a31
// b00 b10 b20 b30 b01 b11 b21 b31
// a02 a12 a22 a32 a03 a13 a23 a33
// b02 b12 a22 b32 b03 b13 b23 b33
tmp_0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
tmp_1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
tmp_2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
tmp_3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
// a00 a10 a20 a30 b00 b10 b20 b30
// a01 a11 a21 a31 b01 b11 b21 b31
// a02 a12 a22 a32 b02 b12 b22 b32
// a03 a13 a23 a33 b03 b13 b23 b33
}
// Vertical pass and difference of weighted sums.
{
// Load all inputs.
// TODO(cduvivier): Make variable declarations and allocations aligned so
// we can use _mm_load_si128 instead of _mm_loadu_si128.
const __m128i w_0 = _mm_loadu_si128((__m128i*)&w[0]);
const __m128i w_8 = _mm_loadu_si128((__m128i*)&w[8]);
// Calculate a and b (two 4x4 at once).
const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2);
const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3);
const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3);
const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2);
const __m128i b0 = _mm_add_epi16(a0, a1);
const __m128i b1 = _mm_add_epi16(a3, a2);
const __m128i b2 = _mm_sub_epi16(a3, a2);
const __m128i b3 = _mm_sub_epi16(a0, a1);
// Separate the transforms of inA and inB.
__m128i A_b0 = _mm_unpacklo_epi64(b0, b1);
__m128i A_b2 = _mm_unpacklo_epi64(b2, b3);
__m128i B_b0 = _mm_unpackhi_epi64(b0, b1);
__m128i B_b2 = _mm_unpackhi_epi64(b2, b3);
{
// sign(b) = b >> 15 (0x0000 if positive, 0xffff if negative)
const __m128i sign_A_b0 = _mm_srai_epi16(A_b0, 15);
const __m128i sign_A_b2 = _mm_srai_epi16(A_b2, 15);
const __m128i sign_B_b0 = _mm_srai_epi16(B_b0, 15);
const __m128i sign_B_b2 = _mm_srai_epi16(B_b2, 15);
// b = abs(b) = (b ^ sign) - sign
A_b0 = _mm_xor_si128(A_b0, sign_A_b0);
A_b2 = _mm_xor_si128(A_b2, sign_A_b2);
B_b0 = _mm_xor_si128(B_b0, sign_B_b0);
B_b2 = _mm_xor_si128(B_b2, sign_B_b2);
A_b0 = _mm_sub_epi16(A_b0, sign_A_b0);
A_b2 = _mm_sub_epi16(A_b2, sign_A_b2);
B_b0 = _mm_sub_epi16(B_b0, sign_B_b0);
B_b2 = _mm_sub_epi16(B_b2, sign_B_b2);
}
// b = abs(b) + 3
A_b0 = _mm_add_epi16(A_b0, three);
A_b2 = _mm_add_epi16(A_b2, three);
B_b0 = _mm_add_epi16(B_b0, three);
B_b2 = _mm_add_epi16(B_b2, three);
// abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3
// b = (abs(b) + 3) >> 3
A_b0 = _mm_srai_epi16(A_b0, 3);
A_b2 = _mm_srai_epi16(A_b2, 3);
B_b0 = _mm_srai_epi16(B_b0, 3);
B_b2 = _mm_srai_epi16(B_b2, 3);
// weighted sums
A_b0 = _mm_madd_epi16(A_b0, w_0);
A_b2 = _mm_madd_epi16(A_b2, w_8);
B_b0 = _mm_madd_epi16(B_b0, w_0);
B_b2 = _mm_madd_epi16(B_b2, w_8);
A_b0 = _mm_add_epi32(A_b0, A_b2);
B_b0 = _mm_add_epi32(B_b0, B_b2);
// difference of weighted sums
A_b0 = _mm_sub_epi32(A_b0, B_b0);
_mm_storeu_si128((__m128i*)&sum[0], A_b0);
}
return sum[0] + sum[1] + sum[2] + sum[3];
}
static int Disto4x4SSE2(const uint8_t* const a, const uint8_t* const b,
const uint16_t* const w) {
const int diff_sum = TTransformSSE2(a, b, w);
return (abs(diff_sum) + 8) >> 4;
}
static int Disto16x16SSE2(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 += Disto4x4SSE2(a + x + y, b + x + y, w);
}
}
return D;
}
//------------------------------------------------------------------------------
// Quantization
//
// Simple quantization
static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
int n, const VP8Matrix* const mtx) {
const __m128i max_coeff_2047 = _mm_set1_epi16(2047);
const __m128i zero = _mm_set1_epi16(0);
__m128i sign0, sign8;
__m128i coeff0, coeff8;
__m128i out0, out8;
__m128i packed_out;
// Load all inputs.
// TODO(cduvivier): Make variable declarations and allocations aligned so that
// we can use _mm_load_si128 instead of _mm_loadu_si128.
__m128i in0 = _mm_loadu_si128((__m128i*)&in[0]);
__m128i in8 = _mm_loadu_si128((__m128i*)&in[8]);
const __m128i sharpen0 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[0]);
const __m128i sharpen8 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[8]);
const __m128i iq0 = _mm_loadu_si128((__m128i*)&mtx->iq_[0]);
const __m128i iq8 = _mm_loadu_si128((__m128i*)&mtx->iq_[8]);
const __m128i bias0 = _mm_loadu_si128((__m128i*)&mtx->bias_[0]);
const __m128i bias8 = _mm_loadu_si128((__m128i*)&mtx->bias_[8]);
const __m128i q0 = _mm_loadu_si128((__m128i*)&mtx->q_[0]);
const __m128i q8 = _mm_loadu_si128((__m128i*)&mtx->q_[8]);
const __m128i zthresh0 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[0]);
const __m128i zthresh8 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[8]);
// sign(in) = in >> 15 (0x0000 if positive, 0xffff if negative)
sign0 = _mm_srai_epi16(in0, 15);
sign8 = _mm_srai_epi16(in8, 15);
// coeff = abs(in) = (in ^ sign) - sign
coeff0 = _mm_xor_si128(in0, sign0);
coeff8 = _mm_xor_si128(in8, sign8);
coeff0 = _mm_sub_epi16(coeff0, sign0);
coeff8 = _mm_sub_epi16(coeff8, sign8);
// coeff = abs(in) + sharpen
coeff0 = _mm_add_epi16(coeff0, sharpen0);
coeff8 = _mm_add_epi16(coeff8, sharpen8);
// if (coeff > 2047) coeff = 2047
coeff0 = _mm_min_epi16(coeff0, max_coeff_2047);
coeff8 = _mm_min_epi16(coeff8, max_coeff_2047);
// out = (coeff * iQ + B) >> QFIX;
{
// doing calculations with 32b precision (QFIX=17)
// out = (coeff * iQ)
__m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0);
__m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0);
__m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8);
__m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8);
__m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H);
__m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H);
__m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H);
__m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H);
// expand bias from 16b to 32b
__m128i bias_00 = _mm_unpacklo_epi16(bias0, zero);
__m128i bias_04 = _mm_unpackhi_epi16(bias0, zero);
__m128i bias_08 = _mm_unpacklo_epi16(bias8, zero);
__m128i bias_12 = _mm_unpackhi_epi16(bias8, zero);
// out = (coeff * iQ + B)
out_00 = _mm_add_epi32(out_00, bias_00);
out_04 = _mm_add_epi32(out_04, bias_04);
out_08 = _mm_add_epi32(out_08, bias_08);
out_12 = _mm_add_epi32(out_12, bias_12);
// out = (coeff * iQ + B) >> QFIX;
out_00 = _mm_srai_epi32(out_00, QFIX);
out_04 = _mm_srai_epi32(out_04, QFIX);
out_08 = _mm_srai_epi32(out_08, QFIX);
out_12 = _mm_srai_epi32(out_12, QFIX);
// pack result as 16b
out0 = _mm_packs_epi32(out_00, out_04);
out8 = _mm_packs_epi32(out_08, out_12);
}
// get sign back (if (sign[j]) out_n = -out_n)
out0 = _mm_xor_si128(out0, sign0);
out8 = _mm_xor_si128(out8, sign8);
out0 = _mm_sub_epi16(out0, sign0);
out8 = _mm_sub_epi16(out8, sign8);
// in = out * Q
in0 = _mm_mullo_epi16(out0, q0);
in8 = _mm_mullo_epi16(out8, q8);
// if (coeff <= mtx->zthresh_) {in=0; out=0;}
{
__m128i cmp0 = _mm_cmpgt_epi16(coeff0, zthresh0);
__m128i cmp8 = _mm_cmpgt_epi16(coeff8, zthresh8);
in0 = _mm_and_si128(in0, cmp0);
in8 = _mm_and_si128(in8, cmp8);
_mm_storeu_si128((__m128i*)&in[0], in0);
_mm_storeu_si128((__m128i*)&in[8], in8);
out0 = _mm_and_si128(out0, cmp0);
out8 = _mm_and_si128(out8, cmp8);
}
// zigzag the output before storing it.
//
// The zigzag pattern can almost be reproduced with a small sequence of
// shuffles. After it, we only need to swap the 7th (ending up in third
// position instead of twelfth) and 8th values.
{
__m128i outZ0, outZ8;
outZ0 = _mm_shufflehi_epi16(out0, _MM_SHUFFLE(2, 1, 3, 0));
outZ0 = _mm_shuffle_epi32 (outZ0, _MM_SHUFFLE(3, 1, 2, 0));
outZ0 = _mm_shufflehi_epi16(outZ0, _MM_SHUFFLE(3, 1, 0, 2));
outZ8 = _mm_shufflelo_epi16(out8, _MM_SHUFFLE(3, 0, 2, 1));
outZ8 = _mm_shuffle_epi32 (outZ8, _MM_SHUFFLE(3, 1, 2, 0));
outZ8 = _mm_shufflelo_epi16(outZ8, _MM_SHUFFLE(1, 3, 2, 0));
_mm_storeu_si128((__m128i*)&out[0], outZ0);
_mm_storeu_si128((__m128i*)&out[8], outZ8);
packed_out = _mm_packs_epi16(outZ0, outZ8);
}
{
const int16_t outZ_12 = out[12];
const int16_t outZ_3 = out[3];
out[3] = outZ_12;
out[12] = outZ_3;
}
// detect if all 'out' values are zeroes or not
{
int32_t tmp[4];
_mm_storeu_si128((__m128i*)tmp, packed_out);
if (n) {
tmp[0] &= ~0xff;
}
return (tmp[3] || tmp[2] || tmp[1] || tmp[0]);
}
}
extern void VP8EncDspInitSSE2(void);
void VP8EncDspInitSSE2(void) {
VP8CollectHistogram = CollectHistogramSSE2;
VP8EncQuantizeBlock = QuantizeBlockSSE2;
VP8ITransform = ITransformSSE2;
VP8FTransform = FTransformSSE2;
VP8SSE4x4 = SSE4x4SSE2;
VP8TDisto4x4 = Disto4x4SSE2;
VP8TDisto16x16 = Disto16x16SSE2;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif //__SSE2__

View File

@ -1,21 +1,67 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Selecting filter level
//
// Author: somnath@google.com (Somnath Banerjee)
#include <math.h>
#include "vp8enci.h"
#include <assert.h>
#include "./vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
// This table gives, for a given sharpness, the filtering strength to be
// used (at least) in order to filter a given edge step delta.
// This is constructed by brute force inspection: for all delta, we iterate
// over all possible filtering strength / thresh until needs_filter() returns
// true.
#define MAX_DELTA_SIZE 64
static const uint8_t kLevelsFromDelta[8][MAX_DELTA_SIZE] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 17, 18,
20, 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42,
44, 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 19,
20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43,
44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19,
21, 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43,
45, 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20,
21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44,
45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 20,
22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44,
46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21,
22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, 45,
46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
{ 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21,
23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45,
47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }
};
int VP8FilterStrengthFromDelta(int sharpness, int delta) {
const int pos = (delta < MAX_DELTA_SIZE) ? delta : MAX_DELTA_SIZE - 1;
assert(sharpness >= 0 && sharpness <= 7);
return kLevelsFromDelta[sharpness][pos];
}
// -----------------------------------------------------------------------------
// NOTE: clip1, tables and InitTables are repeated entries of dsp.c
static uint8_t abs0[255 + 255 + 1]; // abs(i)
static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1
@ -49,7 +95,7 @@ static void InitTables(void) {
// Edge filtering functions
// 4 pixels in, 2 pixels out
static inline void do_filter2(uint8_t* p, int step) {
static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1];
const int a1 = sclip2[112 + ((a + 4) >> 3)];
@ -59,7 +105,7 @@ static inline void do_filter2(uint8_t* p, int step) {
}
// 4 pixels in, 4 pixels out
static inline void do_filter4(uint8_t* p, int step) {
static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
const int a = 3 * (q0 - p0);
const int a1 = sclip2[112 + ((a + 4) >> 3)];
@ -72,17 +118,18 @@ static inline void do_filter4(uint8_t* p, int step) {
}
// high edge-variance
static inline int hev(const uint8_t* p, int step, int thresh) {
static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh);
}
static inline int needs_filter(const uint8_t* p, int step, int thresh) {
static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh;
}
static inline int needs_filter2(const uint8_t* p, int step, int t, int it) {
static WEBP_INLINE int needs_filter2(const uint8_t* p,
int step, int t, int it) {
const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step];
if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t)
@ -132,8 +179,9 @@ static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
//------------------------------------------------------------------------------
// Complex In-loop filtering (Paragraph 15.3)
static inline void FilterLoop24(uint8_t* p, int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
static WEBP_INLINE void FilterLoop24(uint8_t* p,
int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
while (size-- > 0) {
if (needs_filter2(p, hstride, thresh, ithresh)) {
if (hev(p, hstride, hev_thresh)) {
@ -233,14 +281,21 @@ static void DoFilter(const VP8EncIterator* const it, int level) {
// SSIM metric
enum { KERNEL = 3 };
typedef struct {
double w, xm, ym, xxm, xym, yym;
} SSIMStats;
static const double kMinValue = 1.e-10; // minimal threshold
static void Accumulate(const uint8_t* src1, int stride1,
const uint8_t* src2, int stride2,
int xo, int yo, int W, int H,
SSIMStats* const stats) {
void VP8SSIMAddStats(const DistoStats* const src, DistoStats* 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;
}
static void VP8SSIMAccumulate(const uint8_t* src1, int stride1,
const uint8_t* src2, int stride2,
int xo, int yo, int W, int H,
DistoStats* const stats) {
const int ymin = (yo - KERNEL < 0) ? 0 : yo - KERNEL;
const int ymax = (yo + KERNEL > H - 1) ? H - 1 : yo + KERNEL;
const int xmin = (xo - KERNEL < 0) ? 0 : xo - KERNEL;
@ -262,7 +317,7 @@ static void Accumulate(const uint8_t* src1, int stride1,
}
}
static double GetSSIM(const SSIMStats* const stats) {
double VP8SSIMGet(const DistoStats* const stats) {
const double xmxm = stats->xm * stats->xm;
const double ymym = stats->ym * stats->ym;
const double xmym = stats->xm * stats->ym;
@ -280,26 +335,49 @@ static double GetSSIM(const SSIMStats* const stats) {
C2 = 58.5225 * w2;
fnum = (2 * xmym + C1) * (2 * sxy + C2);
fden = (xmxm + ymym + C1) * (sxx + syy + C2);
return (fden != 0) ? fnum / fden : 0.;
return (fden != 0.) ? fnum / fden : kMinValue;
}
double VP8SSIMGetSquaredError(const DistoStats* 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;
}
void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1,
const uint8_t* src2, int stride2,
int W, int H, DistoStats* const stats) {
int x, y;
for (y = 0; y < H; ++y) {
for (x = 0; x < W; ++x) {
VP8SSIMAccumulate(src1, stride1, src2, stride2, x, y, W, H, stats);
}
}
}
static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) {
int x, y;
SSIMStats s = { .0, .0, .0, .0, .0, .0 };
DistoStats s = { .0, .0, .0, .0, .0, .0 };
// compute SSIM in a 10 x 10 window
for (x = 3; x < 13; x++) {
for (y = 3; y < 13; y++) {
Accumulate(yuv1 + Y_OFF, BPS, yuv2 + Y_OFF, BPS, x, y, 16, 16, &s);
VP8SSIMAccumulate(yuv1 + Y_OFF, BPS, yuv2 + Y_OFF, BPS, x, y, 16, 16, &s);
}
}
for (x = 1; x < 7; x++) {
for (y = 1; y < 7; y++) {
Accumulate(yuv1 + U_OFF, BPS, yuv2 + U_OFF, BPS, x, y, 8, 8, &s);
Accumulate(yuv1 + V_OFF, BPS, yuv2 + V_OFF, BPS, x, y, 8, 8, &s);
VP8SSIMAccumulate(yuv1 + U_OFF, BPS, yuv2 + U_OFF, BPS, x, y, 8, 8, &s);
VP8SSIMAccumulate(yuv1 + V_OFF, BPS, yuv2 + V_OFF, BPS, x, y, 8, 8, &s);
}
}
return GetSSIM(&s);
return VP8SSIMGet(&s);
}
//------------------------------------------------------------------------------
@ -307,28 +385,29 @@ static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) {
// loop filter strength
void VP8InitFilter(VP8EncIterator* const it) {
int s, i;
if (!it->lf_stats_) return;
InitTables();
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
for (i = 0; i < MAX_LF_LEVELS; i++) {
(*it->lf_stats_)[s][i] = 0;
if (it->lf_stats_ != NULL) {
int s, i;
InitTables();
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
for (i = 0; i < MAX_LF_LEVELS; i++) {
(*it->lf_stats_)[s][i] = 0;
}
}
}
}
void VP8StoreFilterStats(VP8EncIterator* const it) {
int d;
VP8Encoder* const enc = it->enc_;
const int s = it->mb_->segment_;
const int level0 = it->enc_->dqm_[s].fstrength_; // TODO: ref_lf_delta[]
const int level0 = enc->dqm_[s].fstrength_; // TODO: ref_lf_delta[]
// explore +/-quant range of values around level0
const int delta_min = -it->enc_->dqm_[s].quant_;
const int delta_max = it->enc_->dqm_[s].quant_;
const int delta_min = -enc->dqm_[s].quant_;
const int delta_max = enc->dqm_[s].quant_;
const int step_size = (delta_max - delta_min >= 4) ? 4 : 1;
if (!it->lf_stats_) return;
if (it->lf_stats_ == NULL) return;
// NOTE: Currently we are applying filter only across the sublock edges
// There are two reasons for that.
@ -352,27 +431,41 @@ void VP8StoreFilterStats(VP8EncIterator* const it) {
}
void VP8AdjustFilterStrength(VP8EncIterator* const it) {
int s;
VP8Encoder* const enc = it->enc_;
if (!it->lf_stats_) {
return;
}
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
int i, best_level = 0;
// Improvement over filter level 0 should be at least 1e-5 (relatively)
double best_v = 1.00001 * (*it->lf_stats_)[s][0];
for (i = 1; i < MAX_LF_LEVELS; i++) {
const double v = (*it->lf_stats_)[s][i];
if (v > best_v) {
best_v = v;
best_level = i;
if (it->lf_stats_ != NULL) {
int s;
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
int i, best_level = 0;
// Improvement over filter level 0 should be at least 1e-5 (relatively)
double best_v = 1.00001 * (*it->lf_stats_)[s][0];
for (i = 1; i < MAX_LF_LEVELS; i++) {
const double v = (*it->lf_stats_)[s][i];
if (v > best_v) {
best_v = v;
best_level = i;
}
}
enc->dqm_[s].fstrength_ = best_level;
}
} else if (enc->config_->filter_strength > 0) {
int max_level = 0;
int s;
for (s = 0; s < NUM_MB_SEGMENTS; s++) {
VP8SegmentInfo* const dqm = &enc->dqm_[s];
// this '>> 3' accounts for some inverse WHT scaling
const int delta = (dqm->max_edge_ * dqm->y2_.q_[1]) >> 3;
const int level =
VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, delta);
if (level > dqm->fstrength_) {
dqm->fstrength_ = level;
}
if (max_level < dqm->fstrength_) {
max_level = dqm->fstrength_;
}
}
enc->dqm_[s].fstrength_ = best_level;
enc->filter_hdr_.level_ = max_level;
}
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
// -----------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

512
src/enc/histogram.c Normal file
View File

@ -0,0 +1,512 @@
// 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.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <stdio.h>
#include "./backward_references.h"
#include "./histogram.h"
#include "../dsp/lossless.h"
#include "../utils/utils.h"
static void HistogramClear(VP8LHistogram* const p) {
memset(p->literal_, 0, sizeof(p->literal_));
memset(p->red_, 0, sizeof(p->red_));
memset(p->blue_, 0, sizeof(p->blue_));
memset(p->alpha_, 0, sizeof(p->alpha_));
memset(p->distance_, 0, sizeof(p->distance_));
p->bit_cost_ = 0;
}
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
VP8LHistogram* const histo) {
int i;
for (i = 0; i < refs->size; ++i) {
VP8LHistogramAddSinglePixOrCopy(histo, &refs->refs[i]);
}
}
void VP8LHistogramCreate(VP8LHistogram* const p,
const VP8LBackwardRefs* const refs,
int palette_code_bits) {
if (palette_code_bits >= 0) {
p->palette_code_bits_ = palette_code_bits;
}
HistogramClear(p);
VP8LHistogramStoreRefs(refs, p);
}
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) {
p->palette_code_bits_ = palette_code_bits;
HistogramClear(p);
}
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
int i;
VP8LHistogramSet* set;
VP8LHistogram* bulk;
const uint64_t total_size = sizeof(*set)
+ (uint64_t)size * sizeof(*set->histograms)
+ (uint64_t)size * sizeof(**set->histograms);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
if (memory == NULL) return NULL;
set = (VP8LHistogramSet*)memory;
memory += sizeof(*set);
set->histograms = (VP8LHistogram**)memory;
memory += size * sizeof(*set->histograms);
bulk = (VP8LHistogram*)memory;
set->max_size = size;
set->size = size;
for (i = 0; i < size; ++i) {
set->histograms[i] = bulk + i;
VP8LHistogramInit(set->histograms[i], cache_bits);
}
return set;
}
// -----------------------------------------------------------------------------
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
const PixOrCopy* const v) {
if (PixOrCopyIsLiteral(v)) {
++histo->alpha_[PixOrCopyLiteral(v, 3)];
++histo->red_[PixOrCopyLiteral(v, 2)];
++histo->literal_[PixOrCopyLiteral(v, 1)];
++histo->blue_[PixOrCopyLiteral(v, 0)];
} else if (PixOrCopyIsCacheIdx(v)) {
int literal_ix = 256 + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
++histo->literal_[literal_ix];
} else {
int code, extra_bits;
VP8LPrefixEncodeBits(PixOrCopyLength(v), &code, &extra_bits);
++histo->literal_[256 + code];
VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits);
++histo->distance_[code];
}
}
static double BitsEntropy(const int* const array, int n) {
double retval = 0.;
int sum = 0;
int nonzeros = 0;
int max_val = 0;
int i;
double mix;
for (i = 0; i < n; ++i) {
if (array[i] != 0) {
sum += array[i];
++nonzeros;
retval -= VP8LFastSLog2(array[i]);
if (max_val < array[i]) {
max_val = array[i];
}
}
}
retval += VP8LFastSLog2(sum);
if (nonzeros < 5) {
if (nonzeros <= 1) {
return 0;
}
// Two symbols, they will be 0 and 1 in a Huffman code.
// Let's mix in a bit of entropy to favor good clustering when
// distributions of these are combined.
if (nonzeros == 2) {
return 0.99 * sum + 0.01 * retval;
}
// No matter what the entropy says, we cannot be better than min_limit
// with Huffman coding. I am mixing a bit of entropy into the
// min_limit since it produces much better (~0.5 %) compression results
// perhaps because of better entropy clustering.
if (nonzeros == 3) {
mix = 0.95;
} else {
mix = 0.7; // nonzeros == 4.
}
} else {
mix = 0.627;
}
{
double min_limit = 2 * sum - max_val;
min_limit = mix * min_limit + (1.0 - mix) * retval;
return (retval < min_limit) ? min_limit : retval;
}
}
// Returns the cost encode the rle-encoded entropy code.
// The constants in this function are experimental.
static double HuffmanCost(const int* const population, int length) {
// Small bias because Huffman code length is typically not stored in
// full length.
static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3;
static const double kSmallBias = 9.1;
double retval = kHuffmanCodeOfHuffmanCodeSize - kSmallBias;
int streak = 0;
int i = 0;
for (; i < length - 1; ++i) {
++streak;
if (population[i] == population[i + 1]) {
continue;
}
last_streak_hack:
// population[i] points now to the symbol in the streak of same values.
if (streak > 3) {
if (population[i] == 0) {
retval += 1.5625 + 0.234375 * streak;
} else {
retval += 2.578125 + 0.703125 * streak;
}
} else {
if (population[i] == 0) {
retval += 1.796875 * streak;
} else {
retval += 3.28125 * streak;
}
}
streak = 0;
}
if (i == length - 1) {
++streak;
goto last_streak_hack;
}
return retval;
}
static double PopulationCost(const int* const population, int length) {
return BitsEntropy(population, length) + HuffmanCost(population, length);
}
static double ExtraCost(const int* const population, int length) {
int i;
double cost = 0.;
for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
return cost;
}
// Estimates the Entropy + Huffman + other block overhead size cost.
double VP8LHistogramEstimateBits(const VP8LHistogram* const p) {
return PopulationCost(p->literal_, VP8LHistogramNumCodes(p))
+ PopulationCost(p->red_, 256)
+ PopulationCost(p->blue_, 256)
+ PopulationCost(p->alpha_, 256)
+ PopulationCost(p->distance_, NUM_DISTANCE_CODES)
+ ExtraCost(p->literal_ + 256, NUM_LENGTH_CODES)
+ ExtraCost(p->distance_, NUM_DISTANCE_CODES);
}
double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
return BitsEntropy(p->literal_, VP8LHistogramNumCodes(p))
+ BitsEntropy(p->red_, 256)
+ BitsEntropy(p->blue_, 256)
+ BitsEntropy(p->alpha_, 256)
+ BitsEntropy(p->distance_, NUM_DISTANCE_CODES)
+ ExtraCost(p->literal_ + 256, NUM_LENGTH_CODES)
+ ExtraCost(p->distance_, NUM_DISTANCE_CODES);
}
// -----------------------------------------------------------------------------
// Various histogram combine/cost-eval functions
// Adds 'in' histogram to 'out'
static void HistogramAdd(const VP8LHistogram* const in,
VP8LHistogram* const out) {
int i;
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
out->literal_[i] += in->literal_[i];
}
for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
out->distance_[i] += in->distance_[i];
}
for (i = 0; i < 256; ++i) {
out->red_[i] += in->red_[i];
out->blue_[i] += in->blue_[i];
out->alpha_[i] += in->alpha_[i];
}
}
// 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.
// Since the previous score passed is 'cost_threshold', we only need to compare
// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out
// early.
static double HistogramAddEval(const VP8LHistogram* const a,
const VP8LHistogram* const b,
VP8LHistogram* const out,
double cost_threshold) {
double cost = 0;
const double sum_cost = a->bit_cost_ + b->bit_cost_;
int i;
cost_threshold += sum_cost;
// palette_code_bits_ is part of the cost evaluation for literal_.
// TODO(skal): remove/simplify this palette_code_bits_?
out->palette_code_bits_ =
(a->palette_code_bits_ > b->palette_code_bits_) ? a->palette_code_bits_ :
b->palette_code_bits_;
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
out->literal_[i] = a->literal_[i] + b->literal_[i];
}
cost += PopulationCost(out->literal_, VP8LHistogramNumCodes(out));
cost += ExtraCost(out->literal_ + 256, NUM_LENGTH_CODES);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) out->red_[i] = a->red_[i] + b->red_[i];
cost += PopulationCost(out->red_, 256);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) out->blue_[i] = a->blue_[i] + b->blue_[i];
cost += PopulationCost(out->blue_, 256);
if (cost > cost_threshold) return cost;
for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
out->distance_[i] = a->distance_[i] + b->distance_[i];
}
cost += PopulationCost(out->distance_, NUM_DISTANCE_CODES);
cost += ExtraCost(out->distance_, NUM_DISTANCE_CODES);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) out->alpha_[i] = a->alpha_[i] + b->alpha_[i];
cost += PopulationCost(out->alpha_, 256);
out->bit_cost_ = cost;
return cost - sum_cost;
}
// Same as HistogramAddEval(), except that the resulting histogram
// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit
// the term C(b) which is constant over all the evaluations.
static double HistogramAddThresh(const VP8LHistogram* const a,
const VP8LHistogram* const b,
double cost_threshold) {
int tmp[PIX_OR_COPY_CODES_MAX]; // <= max storage we'll need
int i;
double cost = -a->bit_cost_;
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
tmp[i] = a->literal_[i] + b->literal_[i];
}
// note that the tests are ordered so that the usually largest
// cost shares come first.
cost += PopulationCost(tmp, VP8LHistogramNumCodes(a));
cost += ExtraCost(tmp + 256, NUM_LENGTH_CODES);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) tmp[i] = a->red_[i] + b->red_[i];
cost += PopulationCost(tmp, 256);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) tmp[i] = a->blue_[i] + b->blue_[i];
cost += PopulationCost(tmp, 256);
if (cost > cost_threshold) return cost;
for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
tmp[i] = a->distance_[i] + b->distance_[i];
}
cost += PopulationCost(tmp, NUM_DISTANCE_CODES);
cost += ExtraCost(tmp, NUM_DISTANCE_CODES);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) tmp[i] = a->alpha_[i] + b->alpha_[i];
cost += PopulationCost(tmp, 256);
return cost;
}
// -----------------------------------------------------------------------------
static void HistogramBuildImage(int xsize, int histo_bits,
const VP8LBackwardRefs* const backward_refs,
VP8LHistogramSet* const image) {
int i;
int x = 0, y = 0;
const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits);
VP8LHistogram** const histograms = image->histograms;
assert(histo_bits > 0);
for (i = 0; i < backward_refs->size; ++i) {
const PixOrCopy* const v = &backward_refs->refs[i];
const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
VP8LHistogramAddSinglePixOrCopy(histograms[ix], v);
x += PixOrCopyLength(v);
while (x >= xsize) {
x -= xsize;
++y;
}
}
}
static uint32_t MyRand(uint32_t *seed) {
*seed *= 16807U;
if (*seed == 0) {
*seed = 1;
}
return *seed;
}
static int HistogramCombine(const VP8LHistogramSet* const in,
VP8LHistogramSet* const out, int iter_mult,
int num_pairs, int num_tries_no_success) {
int ok = 0;
int i, iter;
uint32_t seed = 0;
int tries_with_no_success = 0;
int out_size = in->size;
const int outer_iters = in->size * iter_mult;
const int min_cluster_size = 2;
VP8LHistogram* const histos = (VP8LHistogram*)malloc(2 * sizeof(*histos));
VP8LHistogram* cur_combo = histos + 0; // trial merged histogram
VP8LHistogram* best_combo = histos + 1; // best merged histogram so far
if (histos == NULL) goto End;
// Copy histograms from in[] to out[].
assert(in->size <= out->size);
for (i = 0; i < in->size; ++i) {
in->histograms[i]->bit_cost_ = VP8LHistogramEstimateBits(in->histograms[i]);
*out->histograms[i] = *in->histograms[i];
}
// Collapse similar histograms in 'out'.
for (iter = 0; iter < outer_iters && out_size >= min_cluster_size; ++iter) {
double best_cost_diff = 0.;
int best_idx1 = -1, best_idx2 = 1;
int j;
const int num_tries = (num_pairs < out_size) ? num_pairs : out_size;
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) % out_size;
const uint32_t tmp = (j & 7) + 1;
const uint32_t diff = (tmp < 3) ? tmp : MyRand(&seed) % (out_size - 1);
const uint32_t idx2 = (idx1 + diff + 1) % out_size;
if (idx1 == idx2) {
continue;
}
// Calculate cost reduction on combining.
curr_cost_diff = HistogramAddEval(out->histograms[idx1],
out->histograms[idx2],
cur_combo, best_cost_diff);
if (curr_cost_diff < best_cost_diff) { // found a better pair?
{ // swap cur/best combo histograms
VP8LHistogram* const tmp_histo = cur_combo;
cur_combo = best_combo;
best_combo = tmp_histo;
}
best_cost_diff = curr_cost_diff;
best_idx1 = idx1;
best_idx2 = idx2;
}
}
if (best_idx1 >= 0) {
*out->histograms[best_idx1] = *best_combo;
// swap best_idx2 slot with last one (which is now unused)
--out_size;
if (best_idx2 != out_size) {
out->histograms[best_idx2] = out->histograms[out_size];
out->histograms[out_size] = NULL; // just for sanity check.
}
tries_with_no_success = 0;
}
if (++tries_with_no_success >= num_tries_no_success) {
break;
}
}
out->size = out_size;
ok = 1;
End:
free(histos);
return ok;
}
// -----------------------------------------------------------------------------
// Histogram refinement
// What is the bit cost of moving square_histogram from cur_symbol to candidate.
static double HistogramDistance(const VP8LHistogram* const square_histogram,
const VP8LHistogram* const candidate,
double cost_threshold) {
return HistogramAddThresh(candidate, square_histogram, cost_threshold);
}
// Find the best 'out' histogram for each of the 'in' histograms.
// Note: we assume that out[]->bit_cost_ is already up-to-date.
static void HistogramRemap(const VP8LHistogramSet* const in,
const VP8LHistogramSet* const out,
uint16_t* const symbols) {
int i;
for (i = 0; i < in->size; ++i) {
int best_out = 0;
double best_bits =
HistogramDistance(in->histograms[i], out->histograms[0], 1.e38);
int k;
for (k = 1; k < out->size; ++k) {
const double cur_bits =
HistogramDistance(in->histograms[i], out->histograms[k], best_bits);
if (cur_bits < best_bits) {
best_bits = cur_bits;
best_out = k;
}
}
symbols[i] = best_out;
}
// Recompute each out based on raw and symbols.
for (i = 0; i < out->size; ++i) {
HistogramClear(out->histograms[i]);
}
for (i = 0; i < in->size; ++i) {
HistogramAdd(in->histograms[i], out->histograms[symbols[i]]);
}
}
int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int quality, int histo_bits, int cache_bits,
VP8LHistogramSet* const image_in,
uint16_t* const histogram_symbols) {
int ok = 0;
const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1;
const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1;
const int histo_image_raw_size = histo_xsize * histo_ysize;
// Heuristic params for HistogramCombine().
const int num_tries_no_success = 8 + (quality >> 1);
const int iter_mult = (quality < 27) ? 1 : 1 + ((quality - 27) >> 4);
const int num_pairs = (quality < 25) ? 10 : (5 * quality) >> 3;
VP8LHistogramSet* const image_out =
VP8LAllocateHistogramSet(histo_image_raw_size, cache_bits);
if (image_out == NULL) return 0;
// Build histogram image.
HistogramBuildImage(xsize, histo_bits, refs, image_out);
// Collapse similar histograms.
if (!HistogramCombine(image_out, image_in, iter_mult, num_pairs,
num_tries_no_success)) {
goto Error;
}
// Find the optimal map from original histograms to the final ones.
HistogramRemap(image_out, image_in, histogram_symbols);
ok = 1;
Error:
free(image_out);
return ok;
}

101
src/enc/histogram.h Normal file
View File

@ -0,0 +1,101 @@
// 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.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
//
// Models the histograms of literal and distance codes.
#ifndef WEBP_ENC_HISTOGRAM_H_
#define WEBP_ENC_HISTOGRAM_H_
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "./backward_references.h"
#include "../webp/format_constants.h"
#include "../webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
// A simple container for histograms of data.
typedef struct {
// literal_ contains green literal, palette-code and
// copy-length-prefix histogram
int literal_[PIX_OR_COPY_CODES_MAX];
int red_[256];
int blue_[256];
int alpha_[256];
// Backward reference prefix-code histogram.
int distance_[NUM_DISTANCE_CODES];
int palette_code_bits_;
double bit_cost_; // cached value of VP8LHistogramEstimateBits(this)
} VP8LHistogram;
// Collection of histograms with fixed capacity, allocated as one
// big memory chunk. Can be destroyed by simply calling 'free()'.
typedef struct {
int size; // number of slots currently in use
int max_size; // maximum capacity
VP8LHistogram** histograms;
} VP8LHistogramSet;
// Create the histogram.
//
// The input data is the PixOrCopy data, which models the literals, stop
// codes and backward references (both distances and lengths). Also: if
// palette_code_bits is >= 0, initialize the histogram with this value.
void VP8LHistogramCreate(VP8LHistogram* const p,
const VP8LBackwardRefs* const refs,
int palette_code_bits);
// Set the palette_code_bits and reset the stats.
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
// Collect all the references into a histogram (without reset)
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
VP8LHistogram* const histo);
// Allocate an array of pointer to histograms, allocated and initialized
// using 'cache_bits'. Return NULL in case of memory error.
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
// Accumulate a token 'v' into a histogram.
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
const PixOrCopy* const v);
// Estimate how many bits the combined entropy of literals and distance
// approximately maps to.
double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
// This function estimates the cost in bits excluding the bits needed to
// represent the entropy code itself.
double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p);
static WEBP_INLINE int VP8LHistogramNumCodes(const VP8LHistogram* const p) {
return 256 + NUM_LENGTH_CODES +
((p->palette_code_bits_ > 0) ? (1 << p->palette_code_bits_) : 0);
}
// Builds the histogram image.
int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int quality, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_in,
uint16_t* const histogram_symbols);
#ifdef __cplusplus
}
#endif
#endif // WEBP_ENC_HISTOGRAM_H_

View File

@ -1,130 +1,186 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// VP8Iterator: block iterator
//
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
#include <string.h>
#include "vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "./vp8enci.h"
//------------------------------------------------------------------------------
// VP8Iterator
//------------------------------------------------------------------------------
static void InitLeft(VP8EncIterator* const it) {
const VP8Encoder* const enc = it->enc_;
enc->y_left_[-1] = enc->u_left_[-1] = enc->v_left_[-1] =
(it->y_) > 0 ? 129 : 127;
memset(enc->y_left_, 129, 16);
memset(enc->u_left_, 129, 8);
memset(enc->v_left_, 129, 8);
it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] =
(it->y_ > 0) ? 129 : 127;
memset(it->y_left_, 129, 16);
memset(it->u_left_, 129, 8);
memset(it->v_left_, 129, 8);
it->left_nz_[8] = 0;
}
static void InitTop(VP8EncIterator* const it) {
const VP8Encoder* const enc = it->enc_;
const int top_size = enc->mb_w_ * 16;
const size_t top_size = enc->mb_w_ * 16;
memset(enc->y_top_, 127, 2 * top_size);
memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_));
}
void VP8IteratorReset(VP8EncIterator* const it) {
void VP8IteratorSetRow(VP8EncIterator* const it, int y) {
VP8Encoder* const enc = it->enc_;
it->x_ = 0;
it->y_ = 0;
it->y_offset_ = 0;
it->uv_offset_ = 0;
it->mb_ = enc->mb_info_;
it->preds_ = enc->preds_;
it->y_ = y;
it->bw_ = &enc->parts_[y & (enc->num_parts_ - 1)];
it->preds_ = enc->preds_ + y * 4 * enc->preds_w_;
it->nz_ = enc->nz_;
it->bw_ = &enc->parts_[0];
it->done_ = enc->mb_w_* enc->mb_h_;
it->mb_ = enc->mb_info_ + y * enc->mb_w_;
it->y_top_ = enc->y_top_;
it->uv_top_ = enc->uv_top_;
InitLeft(it);
}
void VP8IteratorReset(VP8EncIterator* const it) {
VP8Encoder* const enc = it->enc_;
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;
}
void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down) {
it->count_down_ = it->count_down0_ = count_down;
}
int VP8IteratorIsDone(const VP8EncIterator* const it) {
return (it->count_down_ <= 0);
}
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;
// TODO(later): for multithreading, these should be owned by 'it'.
it->yuv_in_ = enc->yuv_in_;
it->yuv_out_ = enc->yuv_out_;
it->yuv_out2_ = enc->yuv_out2_;
it->yuv_p_ = enc->yuv_p_;
it->yuv_in_ = (uint8_t*)DO_ALIGN(it->yuv_mem_);
it->yuv_out_ = it->yuv_in_ + YUV_SIZE;
it->yuv_out2_ = it->yuv_out_ + YUV_SIZE;
it->yuv_p_ = it->yuv_out2_ + YUV_SIZE;
it->lf_stats_ = enc->lf_stats_;
it->percent0_ = enc->percent_;
it->y_left_ = (uint8_t*)DO_ALIGN(it->yuv_left_mem_ + 1);
it->u_left_ = it->y_left_ + 16 + 16;
it->v_left_ = it->u_left_ + 16;
VP8IteratorReset(it);
}
int VP8IteratorProgress(const VP8EncIterator* const it, int delta) {
VP8Encoder* const enc = it->enc_;
if (delta && enc->pic_->progress_hook != NULL) {
const int done = it->count_down0_ - it->count_down_;
const int percent = (it->count_down0_ <= 0)
? it->percent0_
: it->percent0_ + delta * done / it->count_down0_;
return WebPReportProgress(enc->pic_, percent, &enc->percent_);
}
return 1;
}
//------------------------------------------------------------------------------
// Import the source samples into the cache. Takes care of replicating
// boundary pixels if necessary.
void VP8IteratorImport(const VP8EncIterator* const it) {
static WEBP_INLINE int MinSize(int a, int b) { return (a < b) ? a : b; }
static void ImportBlock(const uint8_t* src, int src_stride,
uint8_t* dst, int w, int h, int size) {
int i;
for (i = 0; i < h; ++i) {
memcpy(dst, src, w);
if (w < size) {
memset(dst + w, dst[w - 1], size - w);
}
dst += BPS;
src += src_stride;
}
for (i = h; i < size; ++i) {
memcpy(dst, dst - BPS, size);
dst += BPS;
}
}
static void ImportLine(const uint8_t* src, int src_stride,
uint8_t* dst, int len, int total_len) {
int i;
for (i = 0; i < len; ++i, src += src_stride) dst[i] = *src;
for (; i < total_len; ++i) dst[i] = dst[len - 1];
}
void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32) {
const VP8Encoder* const enc = it->enc_;
const int x = it->x_, y = it->y_;
const WebPPicture* const pic = enc->pic_;
const uint8_t* ysrc = pic->y + (y * pic->y_stride + x) * 16;
const uint8_t* usrc = pic->u + (y * pic->uv_stride + x) * 8;
const uint8_t* vsrc = pic->v + (y * pic->uv_stride + x) * 8;
uint8_t* ydst = it->yuv_in_ + Y_OFF;
uint8_t* udst = it->yuv_in_ + U_OFF;
uint8_t* vdst = it->yuv_in_ + V_OFF;
int w = (pic->width - x * 16);
int h = (pic->height - y * 16);
int i;
const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16;
const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8;
const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8;
const int w = MinSize(pic->width - x * 16, 16);
const int h = MinSize(pic->height - y * 16, 16);
const int uv_w = (w + 1) >> 1;
const int uv_h = (h + 1) >> 1;
if (w > 16) w = 16;
if (h > 16) h = 16;
// Luma plane
for (i = 0; i < h; ++i) {
memcpy(ydst, ysrc, w);
if (w < 16) memset(ydst + w, ydst[w - 1], 16 - w);
ydst += BPS;
ysrc += pic->y_stride;
}
for (i = h; i < 16; ++i) {
memcpy(ydst, ydst - BPS, 16);
ydst += BPS;
}
// U/V plane
w = (w + 1) / 2;
h = (h + 1) / 2;
for (i = 0; i < h; ++i) {
memcpy(udst, usrc, w);
memcpy(vdst, vsrc, w);
if (w < 8) {
memset(udst + w, udst[w - 1], 8 - w);
memset(vdst + w, vdst[w - 1], 8 - w);
ImportBlock(ysrc, pic->y_stride, it->yuv_in_ + Y_OFF, w, h, 16);
ImportBlock(usrc, pic->uv_stride, it->yuv_in_ + U_OFF, uv_w, uv_h, 8);
ImportBlock(vsrc, pic->uv_stride, it->yuv_in_ + V_OFF, uv_w, uv_h, 8);
if (tmp_32 == NULL) return;
// Import source (uncompressed) samples into boundary.
if (x == 0) {
InitLeft(it);
} else {
if (y == 0) {
it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = 127;
} else {
it->y_left_[-1] = ysrc[- 1 - pic->y_stride];
it->u_left_[-1] = usrc[- 1 - pic->uv_stride];
it->v_left_[-1] = vsrc[- 1 - pic->uv_stride];
}
udst += BPS;
vdst += BPS;
usrc += pic->uv_stride;
vsrc += pic->uv_stride;
ImportLine(ysrc - 1, pic->y_stride, it->y_left_, h, 16);
ImportLine(usrc - 1, pic->uv_stride, it->u_left_, uv_h, 8);
ImportLine(vsrc - 1, pic->uv_stride, it->v_left_, uv_h, 8);
}
for (i = h; i < 8; ++i) {
memcpy(udst, udst - BPS, 8);
memcpy(vdst, vdst - BPS, 8);
udst += BPS;
vdst += BPS;
it->y_top_ = tmp_32 + 0;
it->uv_top_ = tmp_32 + 16;
if (y == 0) {
memset(tmp_32, 127, 32 * sizeof(*tmp_32));
} else {
ImportLine(ysrc - pic->y_stride, 1, tmp_32, w, 16);
ImportLine(usrc - pic->uv_stride, 1, tmp_32 + 16, uv_w, 8);
ImportLine(vsrc - pic->uv_stride, 1, tmp_32 + 16 + 8, uv_w, 8);
}
}
//------------------------------------------------------------------------------
// Copy back the compressed samples into user space if requested.
static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride,
int w, int h) {
while (h-- > 0) {
memcpy(dst, src, w);
dst += dst_stride;
src += BPS;
}
}
void VP8IteratorExport(const VP8EncIterator* const it) {
const VP8Encoder* const enc = it->enc_;
if (enc->config_->show_compressed) {
@ -133,28 +189,23 @@ void VP8IteratorExport(const VP8EncIterator* const it) {
const uint8_t* const usrc = it->yuv_out_ + U_OFF;
const uint8_t* const vsrc = it->yuv_out_ + V_OFF;
const WebPPicture* const pic = enc->pic_;
uint8_t* ydst = pic->y + (y * pic->y_stride + x) * 16;
uint8_t* udst = pic->u + (y * pic->uv_stride + x) * 8;
uint8_t* vdst = pic->v + (y * pic->uv_stride + x) * 8;
uint8_t* const ydst = pic->y + (y * pic->y_stride + x) * 16;
uint8_t* const udst = pic->u + (y * pic->uv_stride + x) * 8;
uint8_t* const vdst = pic->v + (y * pic->uv_stride + x) * 8;
int w = (pic->width - x * 16);
int h = (pic->height - y * 16);
int i;
if (w > 16) w = 16;
if (h > 16) h = 16;
// Luma plane
for (i = 0; i < h; ++i) {
memcpy(ydst + i * pic->y_stride, ysrc + i * BPS, w);
}
// U/V plane
{
const int uv_w = (w + 1) / 2;
const int uv_h = (h + 1) / 2;
for (i = 0; i < uv_h; ++i) {
memcpy(udst + i * pic->uv_stride, usrc + i * BPS, uv_w);
memcpy(vdst + i * pic->uv_stride, vsrc + i * BPS, uv_w);
}
ExportBlock(ysrc, ydst, pic->y_stride, w, h);
{ // U/V planes
const int uv_w = (w + 1) >> 1;
const int uv_h = (h + 1) >> 1;
ExportBlock(usrc, udst, pic->uv_stride, uv_w, uv_h);
ExportBlock(vsrc, vdst, pic->uv_stride, uv_w, uv_h);
}
}
}
@ -178,47 +229,51 @@ void VP8IteratorExport(const VP8EncIterator* const it) {
void VP8IteratorNzToBytes(VP8EncIterator* const it) {
const int tnz = it->nz_[0], lnz = it->nz_[-1];
int* const top_nz = it->top_nz_;
int* const left_nz = it->left_nz_;
// Top-Y
it->top_nz_[0] = BIT(tnz, 12);
it->top_nz_[1] = BIT(tnz, 13);
it->top_nz_[2] = BIT(tnz, 14);
it->top_nz_[3] = BIT(tnz, 15);
top_nz[0] = BIT(tnz, 12);
top_nz[1] = BIT(tnz, 13);
top_nz[2] = BIT(tnz, 14);
top_nz[3] = BIT(tnz, 15);
// Top-U
it->top_nz_[4] = BIT(tnz, 18);
it->top_nz_[5] = BIT(tnz, 19);
top_nz[4] = BIT(tnz, 18);
top_nz[5] = BIT(tnz, 19);
// Top-V
it->top_nz_[6] = BIT(tnz, 22);
it->top_nz_[7] = BIT(tnz, 23);
top_nz[6] = BIT(tnz, 22);
top_nz[7] = BIT(tnz, 23);
// DC
it->top_nz_[8] = BIT(tnz, 24);
top_nz[8] = BIT(tnz, 24);
// left-Y
it->left_nz_[0] = BIT(lnz, 3);
it->left_nz_[1] = BIT(lnz, 7);
it->left_nz_[2] = BIT(lnz, 11);
it->left_nz_[3] = BIT(lnz, 15);
left_nz[0] = BIT(lnz, 3);
left_nz[1] = BIT(lnz, 7);
left_nz[2] = BIT(lnz, 11);
left_nz[3] = BIT(lnz, 15);
// left-U
it->left_nz_[4] = BIT(lnz, 17);
it->left_nz_[5] = BIT(lnz, 19);
left_nz[4] = BIT(lnz, 17);
left_nz[5] = BIT(lnz, 19);
// left-V
it->left_nz_[6] = BIT(lnz, 21);
it->left_nz_[7] = BIT(lnz, 23);
left_nz[6] = BIT(lnz, 21);
left_nz[7] = BIT(lnz, 23);
// left-DC is special, iterated separately
}
void VP8IteratorBytesToNz(VP8EncIterator* const it) {
uint32_t nz = 0;
const int* const top_nz = it->top_nz_;
const int* const left_nz = it->left_nz_;
// top
nz |= (it->top_nz_[0] << 12) | (it->top_nz_[1] << 13);
nz |= (it->top_nz_[2] << 14) | (it->top_nz_[3] << 15);
nz |= (it->top_nz_[4] << 18) | (it->top_nz_[5] << 19);
nz |= (it->top_nz_[6] << 22) | (it->top_nz_[7] << 23);
nz |= (it->top_nz_[8] << 24); // we propagate the _top_ bit, esp. for intra4
nz |= (top_nz[0] << 12) | (top_nz[1] << 13);
nz |= (top_nz[2] << 14) | (top_nz[3] << 15);
nz |= (top_nz[4] << 18) | (top_nz[5] << 19);
nz |= (top_nz[6] << 22) | (top_nz[7] << 23);
nz |= (top_nz[8] << 24); // we propagate the _top_ bit, esp. for intra4
// left
nz |= (it->left_nz_[0] << 3) | (it->left_nz_[1] << 7);
nz |= (it->left_nz_[2] << 11);
nz |= (it->left_nz_[4] << 17) | (it->left_nz_[6] << 21);
nz |= (left_nz[0] << 3) | (left_nz[1] << 7);
nz |= (left_nz[2] << 11);
nz |= (left_nz[4] << 17) | (left_nz[6] << 21);
*it->nz_ = nz;
}
@ -226,56 +281,52 @@ void VP8IteratorBytesToNz(VP8EncIterator* const it) {
#undef BIT
//------------------------------------------------------------------------------
// Advance to the next position, doing the bookeeping.
// Advance to the next position, doing the bookkeeping.
int VP8IteratorNext(VP8EncIterator* const it,
const uint8_t* const block_to_save) {
void VP8IteratorSaveBoundary(VP8EncIterator* const it) {
VP8Encoder* const enc = it->enc_;
if (block_to_save) {
const int x = it->x_, y = it->y_;
const uint8_t* const ysrc = block_to_save + Y_OFF;
const uint8_t* const usrc = block_to_save + U_OFF;
if (x < enc->mb_w_ - 1) { // left
int i;
for (i = 0; i < 16; ++i) {
enc->y_left_[i] = ysrc[15 + i * BPS];
}
for (i = 0; i < 8; ++i) {
enc->u_left_[i] = usrc[7 + i * BPS];
enc->v_left_[i] = usrc[15 + i * BPS];
}
// top-left (before 'top'!)
enc->y_left_[-1] = enc->y_top_[x * 16 + 15];
enc->u_left_[-1] = enc->uv_top_[x * 16 + 0 + 7];
enc->v_left_[-1] = enc->uv_top_[x * 16 + 8 + 7];
const int x = it->x_, y = it->y_;
const uint8_t* const ysrc = it->yuv_out_ + Y_OFF;
const uint8_t* const uvsrc = it->yuv_out_ + U_OFF;
if (x < enc->mb_w_ - 1) { // left
int i;
for (i = 0; i < 16; ++i) {
it->y_left_[i] = ysrc[15 + i * BPS];
}
if (y < enc->mb_h_ - 1) { // top
memcpy(enc->y_top_ + x * 16, ysrc + 15 * BPS, 16);
memcpy(enc->uv_top_ + x * 16, usrc + 7 * BPS, 8 + 8);
for (i = 0; i < 8; ++i) {
it->u_left_[i] = uvsrc[7 + i * BPS];
it->v_left_[i] = uvsrc[15 + i * BPS];
}
// top-left (before 'top'!)
it->y_left_[-1] = it->y_top_[15];
it->u_left_[-1] = it->uv_top_[0 + 7];
it->v_left_[-1] = it->uv_top_[8 + 7];
}
if (y < enc->mb_h_ - 1) { // top
memcpy(it->y_top_, ysrc + 15 * BPS, 16);
memcpy(it->uv_top_, uvsrc + 7 * BPS, 8 + 8);
}
}
it->mb_++;
int VP8IteratorNext(VP8EncIterator* const it) {
it->preds_ += 4;
it->nz_++;
it->x_++;
if (it->x_ == enc->mb_w_) {
it->x_ = 0;
it->y_++;
it->bw_ = &enc->parts_[it->y_ & (enc->num_parts_ - 1)];
it->preds_ = enc->preds_ + it->y_ * 4 * enc->preds_w_;
it->nz_ = enc->nz_;
InitLeft(it);
it->mb_ += 1;
it->nz_ += 1;
it->y_top_ += 16;
it->uv_top_ += 16;
it->x_ += 1;
if (it->x_ == it->enc_->mb_w_) {
VP8IteratorSetRow(it, ++it->y_);
}
return (0 < --it->done_);
return (0 < --it->count_down_);
}
//------------------------------------------------------------------------------
// Helper function to set mode properties
void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) {
int y;
uint8_t* preds = it->preds_;
int y;
for (y = 0; y < 4; ++y) {
memset(preds, mode, 4);
preds += it->enc_->preds_w_;
@ -283,14 +334,13 @@ void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) {
it->mb_->type_ = 1;
}
void VP8SetIntra4Mode(const VP8EncIterator* const it, int modes[16]) {
int x, y;
void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes) {
uint8_t* preds = it->preds_;
for (y = 0; y < 4; ++y) {
for (x = 0; x < 4; ++x) {
preds[x] = modes[x + y * 4];
}
int y;
for (y = 4; y > 0; --y) {
memcpy(preds, modes, 4 * sizeof(*modes));
preds += it->enc_->preds_w_;
modes += 4;
}
it->mb_->type_ = 0;
}
@ -347,7 +397,7 @@ static const uint8_t VP8TopLeftI4[16] = {
};
void VP8IteratorStartI4(VP8EncIterator* const it) {
VP8Encoder* const enc = it->enc_;
const VP8Encoder* const enc = it->enc_;
int i;
it->i4_ = 0; // first 4x4 sub-block
@ -355,15 +405,15 @@ void VP8IteratorStartI4(VP8EncIterator* const it) {
// Import the boundary samples
for (i = 0; i < 17; ++i) { // left
it->i4_boundary_[i] = enc->y_left_[15 - i];
it->i4_boundary_[i] = it->y_left_[15 - i];
}
for (i = 0; i < 16; ++i) { // top
it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i];
it->i4_boundary_[17 + i] = it->y_top_[i];
}
// top-right samples have a special case on the far right of the picture
if (it->x_ < enc->mb_w_ - 1) {
for (i = 16; i < 16 + 4; ++i) {
it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i];
it->i4_boundary_[17 + i] = it->y_top_[i];
}
} else { // else, replicate the last valid pixel four times
for (i = 16; i < 16 + 4; ++i) {
@ -393,7 +443,7 @@ int VP8IteratorRotateI4(VP8EncIterator* const it,
}
}
// move pointers to next sub-block
it->i4_++;
++it->i4_;
if (it->i4_ == 16) { // we're done
return 0;
}
@ -404,6 +454,3 @@ int VP8IteratorRotateI4(VP8EncIterator* const it,
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,25 +1,19 @@
// Copyright 2011 Google Inc.
// Copyright 2011 Google Inc. All Rights Reserved.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// 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.
// -----------------------------------------------------------------------------
//
// Enhancement layer (for YUV444/422)
//
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include <stdlib.h>
#include "vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#ifdef WEBP_EXPERIMENTAL_FEATURES
#endif /* WEBP_EXPERIMENTAL_FEATURES */
#include "./vp8enci.h"
//------------------------------------------------------------------------------
@ -34,8 +28,6 @@ void VP8EncInitLayer(VP8Encoder* const enc) {
void VP8EncCodeLayerBlock(VP8EncIterator* it) {
(void)it; // remove a warning
#ifdef WEBP_EXPERIMENTAL_FEATURES
#endif /* WEBP_EXPERIMENTAL_FEATURES */
}
int VP8EncFinishLayer(VP8Encoder* const enc) {
@ -50,6 +42,3 @@ void VP8EncDeleteLayer(VP8Encoder* enc) {
free(enc->layer_data_);
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

File diff suppressed because it is too large Load Diff

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