mirror of
https://github.com/webmproject/libwebp.git
synced 2025-12-24 14:06:27 +01:00
Compare commits
380 Commits
v0.5.1
...
sandbox/jz
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86c756929c | ||
|
|
50d1a848bc | ||
|
|
20a7fea064 | ||
|
|
415f3ffe3d | ||
|
|
3c6d1224b4 | ||
|
|
ee4a4141f5 | ||
|
|
32ed856f60 | ||
|
|
f4dc56fd77 | ||
|
|
0d8e05880c | ||
|
|
b045013970 | ||
|
|
0ad3b4efa8 | ||
|
|
6451709e72 | ||
|
|
92504d214c | ||
|
|
c3e4b3a946 | ||
|
|
3363eb6d68 | ||
|
|
4d1312f2d5 | ||
|
|
36c42ea415 | ||
|
|
bb498a51e2 | ||
|
|
84cef16f47 | ||
|
|
919f9e2fd6 | ||
|
|
f1ae8af42f | ||
|
|
4689ce1635 | ||
|
|
79bf46f120 | ||
|
|
eb1dc89a5f | ||
|
|
c85b0dde6e | ||
|
|
43d3f01a2f | ||
|
|
668e1dd44f | ||
|
|
0e6b7f33ab | ||
|
|
29ed6f9a0b | ||
|
|
71c53f1aeb | ||
|
|
73f567ea8b | ||
|
|
9e14276f4c | ||
|
|
99965bac02 | ||
|
|
d4912238f7 | ||
|
|
ea4824097e | ||
|
|
2ede5a198a | ||
|
|
a345068aba | ||
|
|
1dc82a6bba | ||
|
|
8074b89eb3 | ||
|
|
749a45a520 | ||
|
|
74c053b57d | ||
|
|
0a3aeff75b | ||
|
|
1de931c669 | ||
|
|
9b3aca404d | ||
|
|
1c07a3c639 | ||
|
|
9ed5e3e5dd | ||
|
|
db013a8d5c | ||
|
|
fcd4784dcd | ||
|
|
fbb5c473b4 | ||
|
|
8fda56126e | ||
|
|
86bbd24552 | ||
|
|
7c2779e95a | ||
|
|
250c358662 | ||
|
|
c0648ac2ae | ||
|
|
0d55f60c91 | ||
|
|
49d0280df1 | ||
|
|
48b1e85fbe | ||
|
|
e3b8abbc9b | ||
|
|
28fe054e73 | ||
|
|
f44acd253b | ||
|
|
527844fee0 | ||
|
|
be0ef6395f | ||
|
|
8874b16275 | ||
|
|
d712e20de0 | ||
|
|
ecff04f625 | ||
|
|
259e98286a | ||
|
|
00b08c88c0 | ||
|
|
0e7f444702 | ||
|
|
b016cb91c5 | ||
|
|
1cb638010c | ||
|
|
875fafc191 | ||
|
|
3674d49e63 | ||
|
|
f04eb37603 | ||
|
|
341d711c43 | ||
|
|
abb5482731 | ||
|
|
ece9684f52 | ||
|
|
aa7744ca38 | ||
|
|
d9120271e7 | ||
|
|
24eb39401b | ||
|
|
a4a8e5f32c | ||
|
|
67c25ad5b4 | ||
|
|
a4bbe4b38b | ||
|
|
31ca2a8098 | ||
|
|
b2f77b57a9 | ||
|
|
5ab6d9de1f | ||
|
|
f29bf582df | ||
|
|
3ebe1c0003 | ||
|
|
df780e0eac | ||
|
|
58fc507842 | ||
|
|
9cc421675b | ||
|
|
0aa1f35c0f | ||
|
|
cb9ec84b54 | ||
|
|
dc0c01fbd3 | ||
|
|
827d3c5038 | ||
|
|
1e2e25b0d4 | ||
|
|
218460cdd7 | ||
|
|
de7d654d0d | ||
|
|
273367c130 | ||
|
|
76bbcf2ed6 | ||
|
|
8ac1abfe13 | ||
|
|
cb215aed5c | ||
|
|
2423017a28 | ||
|
|
74a12b10d9 | ||
|
|
a9cc762196 | ||
|
|
fbba5bc2c1 | ||
|
|
9ae0b3f65a | ||
|
|
c1f97bd758 | ||
|
|
ea664b8995 | ||
|
|
be7dcc088c | ||
|
|
408858308a | ||
|
|
1d5046d1f9 | ||
|
|
cec7201447 | ||
|
|
8f38c72e11 | ||
|
|
33ca93f909 | ||
|
|
76e190735b | ||
|
|
f91ba96306 | ||
|
|
25d74e652e | ||
|
|
03f1c00877 | ||
|
|
58410cd6dc | ||
|
|
e168af8c6c | ||
|
|
ed9dec41a5 | ||
|
|
3c49178f7d | ||
|
|
9595f29010 | ||
|
|
7ec9552c22 | ||
|
|
b3fb8bb602 | ||
|
|
9871335fc8 | ||
|
|
0ae32226ce | ||
|
|
ab4c8056e0 | ||
|
|
eec5fa3a95 | ||
|
|
004d569086 | ||
|
|
4fe5d588bf | ||
|
|
bd63a31aab | ||
|
|
363a568131 | ||
|
|
a0d2753fcb | ||
|
|
31fe11a57a | ||
|
|
532215dd29 | ||
|
|
9c75dbd39c | ||
|
|
af2e05cbdf | ||
|
|
26ffa2962b | ||
|
|
7416280d75 | ||
|
|
13cf1d2e41 | ||
|
|
eb9a4b97c5 | ||
|
|
42ebe3b783 | ||
|
|
76ebbfff28 | ||
|
|
95b12a08ae | ||
|
|
54ab2e758f | ||
|
|
fe12330c81 | ||
|
|
fbfb3bef7b | ||
|
|
d4b7d801db | ||
|
|
a5e3b22574 | ||
|
|
58a1f124c2 | ||
|
|
906c3b6392 | ||
|
|
d23abe4e9f | ||
|
|
2e6cb6f34e | ||
|
|
28e0bb7088 | ||
|
|
647045305a | ||
|
|
bded7848ea | ||
|
|
0e61a5134a | ||
|
|
1cc79e92ac | ||
|
|
03f40955a3 | ||
|
|
ea72cd60cb | ||
|
|
67879e6d48 | ||
|
|
34aee99026 | ||
|
|
a41296aef5 | ||
|
|
c85adb33d2 | ||
|
|
4239a1489c | ||
|
|
bc18ebad2e | ||
|
|
71e2f5cadf | ||
|
|
7474d46e45 | ||
|
|
67748b41db | ||
|
|
16951b1905 | ||
|
|
6540cd0eeb | ||
|
|
de568abfdb | ||
|
|
3c2a61b099 | ||
|
|
9ac063c37f | ||
|
|
22efabddb4 | ||
|
|
1d6e7bf39f | ||
|
|
0a3838ca77 | ||
|
|
c0699515af | ||
|
|
83cbfa09a1 | ||
|
|
a1ade40ed8 | ||
|
|
fd4d090fd1 | ||
|
|
9daad4598b | ||
|
|
f90c60d129 | ||
|
|
3f182d36f4 | ||
|
|
342e15f0ce | ||
|
|
1147ab4ee7 | ||
|
|
e4cd4daf74 | ||
|
|
e715285611 | ||
|
|
de9fa5074e | ||
|
|
deb1b83199 | ||
|
|
c284780f0a | ||
|
|
e375080d8f | ||
|
|
c222a053af | ||
|
|
bb2336170b | ||
|
|
883d41fb40 | ||
|
|
cac9a36a23 | ||
|
|
4595e01fd0 | ||
|
|
fb52d4432a | ||
|
|
f048d38d38 | ||
|
|
31b1e34342 | ||
|
|
2f51b614b0 | ||
|
|
0104d730bf | ||
|
|
265abbe9b2 | ||
|
|
f7601aa686 | ||
|
|
ce8733209d | ||
|
|
2a2773ea29 | ||
|
|
9f5c8eca79 | ||
|
|
4eb5df28d1 | ||
|
|
11bc423ae5 | ||
|
|
273d035a44 | ||
|
|
4db82a178f | ||
|
|
e2affacc35 | ||
|
|
dc789ada44 | ||
|
|
539f5a688f | ||
|
|
aaf2a6a698 | ||
|
|
20ef99159e | ||
|
|
bc86b7a8a1 | ||
|
|
806f6279ae | ||
|
|
68ae5b671f | ||
|
|
28ce304344 | ||
|
|
b34abcb8b1 | ||
|
|
ba843a92e7 | ||
|
|
51b71fd295 | ||
|
|
fb01743a53 | ||
|
|
bfab894739 | ||
|
|
9310d19258 | ||
|
|
f79450ca02 | ||
|
|
cfdda7c6bf | ||
|
|
e36396ba75 | ||
|
|
18a9a0ab57 | ||
|
|
30d43706d3 | ||
|
|
36aa087b6d | ||
|
|
86a84b3598 | ||
|
|
b8384b53d6 | ||
|
|
1c36440094 | ||
|
|
eee0cce158 | ||
|
|
5f1caf2987 | ||
|
|
1effde7bcd | ||
|
|
a2fe9bf404 | ||
|
|
573cce270e | ||
|
|
21e7537abe | ||
|
|
053a1565c8 | ||
|
|
1377ac2ec1 | ||
|
|
7c1fb7d0ff | ||
|
|
bfff0bf329 | ||
|
|
64577de8ae | ||
|
|
a7be73280b | ||
|
|
50c3d7da9a | ||
|
|
d6228aed6a | ||
|
|
dd538b192d | ||
|
|
6cc48b1728 | ||
|
|
78363e9e51 | ||
|
|
ffd01929f1 | ||
|
|
c4f6d9c939 | ||
|
|
c27d821096 | ||
|
|
0779529616 | ||
|
|
c9b45863e2 | ||
|
|
490ae5b13d | ||
|
|
894232be56 | ||
|
|
8de08483b6 | ||
|
|
41cab7fe0f | ||
|
|
82c91c708e | ||
|
|
af1ad3e2dd | ||
|
|
dd7309e30c | ||
|
|
6105777e8c | ||
|
|
13ae011e4c | ||
|
|
4bda0cfba4 | ||
|
|
6029c7fe68 | ||
|
|
545c147fd8 | ||
|
|
5b46f7fc80 | ||
|
|
9e478f808e | ||
|
|
43bd895879 | ||
|
|
0887fc2d85 | ||
|
|
0de48e187d | ||
|
|
0a57ad0dc5 | ||
|
|
0a4699bcc9 | ||
|
|
29fedbf58b | ||
|
|
32dead4ee3 | ||
|
|
85cd5d061c | ||
|
|
6585075f8a | ||
|
|
c0a27fd2af | ||
|
|
57a5e3b6a5 | ||
|
|
7f1b897bee | ||
|
|
48c810b85c | ||
|
|
3884972e3f | ||
|
|
485cac1a88 | ||
|
|
005e15b10a | ||
|
|
6ab496ed22 | ||
|
|
8a4ebc6ab0 | ||
|
|
9d4f209f80 | ||
|
|
e44f5248ff | ||
|
|
27b5d991e2 | ||
|
|
74f6f9e793 | ||
|
|
aaf2530cc3 | ||
|
|
1269dc7cfb | ||
|
|
40872fb2e6 | ||
|
|
7b54e26bac | ||
|
|
d2223d8d6c | ||
|
|
bf16a4b4f8 | ||
|
|
ee1057e3b1 | ||
|
|
b551e587b3 | ||
|
|
d2e4484ef3 | ||
|
|
c7f66c82b3 | ||
|
|
98d8f295b1 | ||
|
|
39f4ffbcdc | ||
|
|
a86ce2b1e2 | ||
|
|
6fa9fe2482 | ||
|
|
0b2c58a91c | ||
|
|
d7ce4a2e3e | ||
|
|
386e4ba2f0 | ||
|
|
7b87e8485b | ||
|
|
d3ddacb625 | ||
|
|
eb98d8d87c | ||
|
|
ebee57f4d1 | ||
|
|
99542bbf3e | ||
|
|
da573cf490 | ||
|
|
bdda5bd4bf | ||
|
|
15ed462b2d | ||
|
|
7be5748963 | ||
|
|
57020525ed | ||
|
|
e8ab6a825a | ||
|
|
fee7b3d6ca | ||
|
|
1e7d4401dc | ||
|
|
4cecab63bd | ||
|
|
259f0434a5 | ||
|
|
ed34c39bfc | ||
|
|
33d8d0d4d3 | ||
|
|
c960b82e5c | ||
|
|
fe3cd28a53 | ||
|
|
45fbeba5cd | ||
|
|
4f33c82098 | ||
|
|
c379b55a93 | ||
|
|
5108d9aa00 | ||
|
|
ad497fbce3 | ||
|
|
0c0fb83211 | ||
|
|
9ac74f922e | ||
|
|
cb19dbc1a4 | ||
|
|
3f4042b52a | ||
|
|
5e2eb89e1f | ||
|
|
5b60db5c9d | ||
|
|
567e697776 | ||
|
|
c54ab8dd1a | ||
|
|
ec6f68c51e | ||
|
|
2a5c417c68 | ||
|
|
91b59e886b | ||
|
|
fe57273736 | ||
|
|
6b53ca876e | ||
|
|
b15d00d996 | ||
|
|
afe3cec813 | ||
|
|
fc8cad9f29 | ||
|
|
7b4b05e0dc | ||
|
|
c18787a0e9 | ||
|
|
479d19085d | ||
|
|
a80e8cfdf2 | ||
|
|
6c62841076 | ||
|
|
bbb6ecd9b0 | ||
|
|
7915396f40 | ||
|
|
652e944f69 | ||
|
|
c0991a141f | ||
|
|
48bf5ed134 | ||
|
|
bfef6c9f82 | ||
|
|
435308e029 | ||
|
|
dce64bfa1b | ||
|
|
429120d0af | ||
|
|
55b2fede7f | ||
|
|
701c772eed | ||
|
|
f918cb1013 | ||
|
|
6a19793777 | ||
|
|
293d786f31 | ||
|
|
0afa0ce2ff | ||
|
|
a6621bacf3 | ||
|
|
1ebf193c2c | ||
|
|
9ad2352d0d | ||
|
|
607510967f | ||
|
|
8ec7032bc2 | ||
|
|
472a049b4e | ||
|
|
a977b4b513 | ||
|
|
3591ba6684 | ||
|
|
e6ac450cbd |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -22,6 +22,7 @@ Makefile.in
|
|||||||
examples/anim_diff
|
examples/anim_diff
|
||||||
examples/[cdv]webp
|
examples/[cdv]webp
|
||||||
examples/gif2webp
|
examples/gif2webp
|
||||||
|
examples/img2webp
|
||||||
examples/webpmux
|
examples/webpmux
|
||||||
src/webp/config.h*
|
src/webp/config.h*
|
||||||
src/webp/stamp-h1
|
src/webp/stamp-h1
|
||||||
@@ -34,3 +35,7 @@ src/webp/stamp-h1
|
|||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CMakeFiles/
|
CMakeFiles/
|
||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
|
.gradle
|
||||||
|
/build
|
||||||
|
extras/get_disto
|
||||||
|
extras/webp_quality
|
||||||
|
|||||||
1
.mailmap
1
.mailmap
@@ -9,3 +9,4 @@ Vikas Arora <vikasa@google.com>
|
|||||||
<vrabaud@google.com> <vincent.rabaud@gmail.com>
|
<vrabaud@google.com> <vincent.rabaud@gmail.com>
|
||||||
Tamar Levy <tamar.levy@intel.com>
|
Tamar Levy <tamar.levy@intel.com>
|
||||||
<qrczak@google.com> <qrczak>
|
<qrczak@google.com> <qrczak>
|
||||||
|
Hui Su <huisu@google.com>
|
||||||
|
|||||||
3
AUTHORS
3
AUTHORS
@@ -2,8 +2,10 @@ Contributors:
|
|||||||
- Charles Munger (clm at google dot com)
|
- Charles Munger (clm at google dot com)
|
||||||
- Christian Duvivier (cduvivier at google dot com)
|
- Christian Duvivier (cduvivier at google dot com)
|
||||||
- Djordje Pesut (djordje dot pesut at imgtec dot com)
|
- Djordje Pesut (djordje dot pesut at imgtec dot com)
|
||||||
|
- Hui Su (huisu at google dot com)
|
||||||
- James Zern (jzern at google dot com)
|
- James Zern (jzern at google dot com)
|
||||||
- Jan Engelhardt (jengelh at medozas dot de)
|
- Jan Engelhardt (jengelh at medozas dot de)
|
||||||
|
- Jehan (jehan at girinstud dot io)
|
||||||
- Johann (johann dot koenig at duck dot com)
|
- Johann (johann dot koenig at duck dot com)
|
||||||
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
|
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
|
||||||
- Jyrki Alakuijala (jyrki at google dot com)
|
- Jyrki Alakuijala (jyrki at google dot com)
|
||||||
@@ -16,6 +18,7 @@ Contributors:
|
|||||||
- Mislav Bradac (mislavm at google dot com)
|
- Mislav Bradac (mislavm at google dot com)
|
||||||
- Nico Weber (thakis at chromium dot org)
|
- Nico Weber (thakis at chromium dot org)
|
||||||
- Noel Chromium (noel at chromium dot org)
|
- Noel Chromium (noel at chromium dot org)
|
||||||
|
- Owen Rodley (orodley at google dot com)
|
||||||
- Parag Salasakar (img dot mips1 at gmail dot com)
|
- Parag Salasakar (img dot mips1 at gmail dot com)
|
||||||
- Pascal Massimino (pascal dot massimino at gmail dot com)
|
- Pascal Massimino (pascal dot massimino at gmail dot com)
|
||||||
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
|
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
|
||||||
|
|||||||
100
Android.mk
100
Android.mk
@@ -1,6 +1,7 @@
|
|||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD
|
WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD
|
||||||
|
WEBP_CFLAGS += -fvisibility=hidden
|
||||||
|
|
||||||
ifeq ($(APP_OPTIM),release)
|
ifeq ($(APP_OPTIM),release)
|
||||||
WEBP_CFLAGS += -finline-functions -ffast-math \
|
WEBP_CFLAGS += -finline-functions -ffast-math \
|
||||||
@@ -21,16 +22,16 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
dec_srcs := \
|
dec_srcs := \
|
||||||
src/dec/alpha.c \
|
src/dec/alpha_dec.c \
|
||||||
src/dec/buffer.c \
|
src/dec/buffer_dec.c \
|
||||||
src/dec/frame.c \
|
src/dec/frame_dec.c \
|
||||||
src/dec/idec.c \
|
src/dec/idec_dec.c \
|
||||||
src/dec/io.c \
|
src/dec/io_dec.c \
|
||||||
src/dec/quant.c \
|
src/dec/quant_dec.c \
|
||||||
src/dec/tree.c \
|
src/dec/tree_dec.c \
|
||||||
src/dec/vp8.c \
|
src/dec/vp8_dec.c \
|
||||||
src/dec/vp8l.c \
|
src/dec/vp8l_dec.c \
|
||||||
src/dec/webp.c \
|
src/dec/webp_dec.c \
|
||||||
|
|
||||||
demux_srcs := \
|
demux_srcs := \
|
||||||
src/demux/anim_decode.c \
|
src/demux/anim_decode.c \
|
||||||
@@ -39,6 +40,7 @@ demux_srcs := \
|
|||||||
dsp_dec_srcs := \
|
dsp_dec_srcs := \
|
||||||
src/dsp/alpha_processing.c \
|
src/dsp/alpha_processing.c \
|
||||||
src/dsp/alpha_processing_mips_dsp_r2.c \
|
src/dsp/alpha_processing_mips_dsp_r2.c \
|
||||||
|
src/dsp/alpha_processing_neon.$(NEON) \
|
||||||
src/dsp/alpha_processing_sse2.c \
|
src/dsp/alpha_processing_sse2.c \
|
||||||
src/dsp/alpha_processing_sse41.c \
|
src/dsp/alpha_processing_sse41.c \
|
||||||
src/dsp/argb.c \
|
src/dsp/argb.c \
|
||||||
@@ -55,18 +57,23 @@ dsp_dec_srcs := \
|
|||||||
src/dsp/dec_sse41.c \
|
src/dsp/dec_sse41.c \
|
||||||
src/dsp/filters.c \
|
src/dsp/filters.c \
|
||||||
src/dsp/filters_mips_dsp_r2.c \
|
src/dsp/filters_mips_dsp_r2.c \
|
||||||
|
src/dsp/filters_msa.c \
|
||||||
|
src/dsp/filters_neon.$(NEON) \
|
||||||
src/dsp/filters_sse2.c \
|
src/dsp/filters_sse2.c \
|
||||||
src/dsp/lossless.c \
|
src/dsp/lossless.c \
|
||||||
src/dsp/lossless_mips_dsp_r2.c \
|
src/dsp/lossless_mips_dsp_r2.c \
|
||||||
|
src/dsp/lossless_msa.c \
|
||||||
src/dsp/lossless_neon.$(NEON) \
|
src/dsp/lossless_neon.$(NEON) \
|
||||||
src/dsp/lossless_sse2.c \
|
src/dsp/lossless_sse2.c \
|
||||||
src/dsp/rescaler.c \
|
src/dsp/rescaler.c \
|
||||||
src/dsp/rescaler_mips32.c \
|
src/dsp/rescaler_mips32.c \
|
||||||
src/dsp/rescaler_mips_dsp_r2.c \
|
src/dsp/rescaler_mips_dsp_r2.c \
|
||||||
|
src/dsp/rescaler_msa.c \
|
||||||
src/dsp/rescaler_neon.$(NEON) \
|
src/dsp/rescaler_neon.$(NEON) \
|
||||||
src/dsp/rescaler_sse2.c \
|
src/dsp/rescaler_sse2.c \
|
||||||
src/dsp/upsampling.c \
|
src/dsp/upsampling.c \
|
||||||
src/dsp/upsampling_mips_dsp_r2.c \
|
src/dsp/upsampling_mips_dsp_r2.c \
|
||||||
|
src/dsp/upsampling_msa.c \
|
||||||
src/dsp/upsampling_neon.$(NEON) \
|
src/dsp/upsampling_neon.$(NEON) \
|
||||||
src/dsp/upsampling_sse2.c \
|
src/dsp/upsampling_sse2.c \
|
||||||
src/dsp/yuv.c \
|
src/dsp/yuv.c \
|
||||||
@@ -83,39 +90,42 @@ dsp_enc_srcs := \
|
|||||||
src/dsp/enc_avx2.c \
|
src/dsp/enc_avx2.c \
|
||||||
src/dsp/enc_mips32.c \
|
src/dsp/enc_mips32.c \
|
||||||
src/dsp/enc_mips_dsp_r2.c \
|
src/dsp/enc_mips_dsp_r2.c \
|
||||||
|
src/dsp/enc_msa.c \
|
||||||
src/dsp/enc_neon.$(NEON) \
|
src/dsp/enc_neon.$(NEON) \
|
||||||
src/dsp/enc_sse2.c \
|
src/dsp/enc_sse2.c \
|
||||||
src/dsp/enc_sse41.c \
|
src/dsp/enc_sse41.c \
|
||||||
src/dsp/lossless_enc.c \
|
src/dsp/lossless_enc.c \
|
||||||
src/dsp/lossless_enc_mips32.c \
|
src/dsp/lossless_enc_mips32.c \
|
||||||
src/dsp/lossless_enc_mips_dsp_r2.c \
|
src/dsp/lossless_enc_mips_dsp_r2.c \
|
||||||
|
src/dsp/lossless_enc_msa.c \
|
||||||
src/dsp/lossless_enc_neon.$(NEON) \
|
src/dsp/lossless_enc_neon.$(NEON) \
|
||||||
src/dsp/lossless_enc_sse2.c \
|
src/dsp/lossless_enc_sse2.c \
|
||||||
src/dsp/lossless_enc_sse41.c \
|
src/dsp/lossless_enc_sse41.c \
|
||||||
|
|
||||||
enc_srcs := \
|
enc_srcs := \
|
||||||
src/enc/alpha.c \
|
src/enc/alpha_enc.c \
|
||||||
src/enc/analysis.c \
|
src/enc/analysis_enc.c \
|
||||||
src/enc/backward_references.c \
|
src/enc/backward_references_enc.c \
|
||||||
src/enc/config.c \
|
src/enc/config_enc.c \
|
||||||
src/enc/cost.c \
|
src/enc/cost_enc.c \
|
||||||
src/enc/delta_palettization.c \
|
src/enc/delta_palettization_enc.c \
|
||||||
src/enc/filter.c \
|
src/enc/filter_enc.c \
|
||||||
src/enc/frame.c \
|
src/enc/frame_enc.c \
|
||||||
src/enc/histogram.c \
|
src/enc/histogram_enc.c \
|
||||||
src/enc/iterator.c \
|
src/enc/iterator_enc.c \
|
||||||
src/enc/near_lossless.c \
|
src/enc/near_lossless_enc.c \
|
||||||
src/enc/picture.c \
|
src/enc/picture_enc.c \
|
||||||
src/enc/picture_csp.c \
|
src/enc/picture_csp_enc.c \
|
||||||
src/enc/picture_psnr.c \
|
src/enc/picture_psnr_enc.c \
|
||||||
src/enc/picture_rescale.c \
|
src/enc/picture_rescale_enc.c \
|
||||||
src/enc/picture_tools.c \
|
src/enc/picture_tools_enc.c \
|
||||||
src/enc/quant.c \
|
src/enc/predictor_enc.c \
|
||||||
src/enc/syntax.c \
|
src/enc/quant_enc.c \
|
||||||
src/enc/token.c \
|
src/enc/syntax_enc.c \
|
||||||
src/enc/tree.c \
|
src/enc/token_enc.c \
|
||||||
src/enc/vp8l.c \
|
src/enc/tree_enc.c \
|
||||||
src/enc/webpenc.c \
|
src/enc/vp8l_enc.c \
|
||||||
|
src/enc/webp_enc.c \
|
||||||
|
|
||||||
mux_srcs := \
|
mux_srcs := \
|
||||||
src/mux/anim_encode.c \
|
src/mux/anim_encode.c \
|
||||||
@@ -124,20 +134,20 @@ mux_srcs := \
|
|||||||
src/mux/muxread.c \
|
src/mux/muxread.c \
|
||||||
|
|
||||||
utils_dec_srcs := \
|
utils_dec_srcs := \
|
||||||
src/utils/bit_reader.c \
|
src/utils/bit_reader_utils.c \
|
||||||
src/utils/color_cache.c \
|
src/utils/color_cache_utils.c \
|
||||||
src/utils/filters.c \
|
src/utils/filters_utils.c \
|
||||||
src/utils/huffman.c \
|
src/utils/huffman_utils.c \
|
||||||
src/utils/quant_levels_dec.c \
|
src/utils/quant_levels_dec_utils.c \
|
||||||
src/utils/random.c \
|
src/utils/random_utils.c \
|
||||||
src/utils/rescaler.c \
|
src/utils/rescaler_utils.c \
|
||||||
src/utils/thread.c \
|
src/utils/thread_utils.c \
|
||||||
src/utils/utils.c \
|
src/utils/utils.c \
|
||||||
|
|
||||||
utils_enc_srcs := \
|
utils_enc_srcs := \
|
||||||
src/utils/bit_writer.c \
|
src/utils/bit_writer_utils.c \
|
||||||
src/utils/huffman_encode.c \
|
src/utils/huffman_encode_utils.c \
|
||||||
src/utils/quant_levels.c \
|
src/utils/quant_levels_utils.c \
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# libwebpdecoder
|
# libwebpdecoder
|
||||||
@@ -247,7 +257,9 @@ endif
|
|||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
include $(LOCAL_PATH)/examples/Android.mk
|
WEBP_SRC_PATH := $(LOCAL_PATH)
|
||||||
|
include $(WEBP_SRC_PATH)/imageio/Android.mk
|
||||||
|
include $(WEBP_SRC_PATH)/examples/Android.mk
|
||||||
|
|
||||||
ifeq ($(USE_CPUFEATURES),yes)
|
ifeq ($(USE_CPUFEATURES),yes)
|
||||||
$(call import-module,android/cpufeatures)
|
$(call import-module,android/cpufeatures)
|
||||||
|
|||||||
332
CMakeLists.txt
332
CMakeLists.txt
@@ -5,8 +5,10 @@ project(libwebp C)
|
|||||||
# Options for coder / decoder executables.
|
# Options for coder / decoder executables.
|
||||||
option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." OFF)
|
option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." OFF)
|
||||||
option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." OFF)
|
option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." OFF)
|
||||||
|
option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." OFF)
|
||||||
|
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." OFF)
|
||||||
option(WEBP_EXPERIMENTAL_FEATURES "Build with experimental features." OFF)
|
option(WEBP_EXPERIMENTAL_FEATURES "Build with experimental features." OFF)
|
||||||
option(WEBP_FORCE_ALIGNED "Force aligned memory operations." OFF)
|
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." OFF)
|
||||||
|
|
||||||
set(WEBP_DEP_LIBRARIES)
|
set(WEBP_DEP_LIBRARIES)
|
||||||
set(WEBP_DEP_INCLUDE_DIRS)
|
set(WEBP_DEP_INCLUDE_DIRS)
|
||||||
@@ -17,222 +19,38 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
include(cmake/config.h.cmake)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Generate the config.h to compile with specific intrinsics / libs.
|
# Options.
|
||||||
|
if(WEBP_ENABLE_SWAP_16BIT_CSP)
|
||||||
|
add_definitions(-DWEBP_SWAP_16BIT_CSP)
|
||||||
|
endif()
|
||||||
|
|
||||||
## Check for compiler options.
|
################################################################################
|
||||||
include(CheckCSourceCompiles)
|
# Android only.
|
||||||
check_c_source_compiles("
|
if(ANDROID)
|
||||||
int main(void) {
|
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
|
||||||
(void)__builtin_bswap16(0);
|
add_library(cpufeatures STATIC
|
||||||
return 0;
|
${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c
|
||||||
}
|
|
||||||
"
|
|
||||||
HAVE_BUILTIN_BSWAP16
|
|
||||||
)
|
|
||||||
check_c_source_compiles("
|
|
||||||
int main(void) {
|
|
||||||
(void)__builtin_bswap32(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
"
|
|
||||||
HAVE_BUILTIN_BSWAP32
|
|
||||||
)
|
|
||||||
check_c_source_compiles("
|
|
||||||
int main(void) {
|
|
||||||
(void)__builtin_bswap64(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
"
|
|
||||||
HAVE_BUILTIN_BSWAP64
|
|
||||||
)
|
|
||||||
|
|
||||||
## Check for libraries.
|
|
||||||
find_package(Threads)
|
|
||||||
if(Threads_FOUND)
|
|
||||||
if(CMAKE_USE_PTHREADS_INIT)
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
|
||||||
endif()
|
|
||||||
foreach(PTHREAD_TEST HAVE_PTHREAD_PRIO_INHERIT PTHREAD_CREATE_UNDETACHED)
|
|
||||||
check_c_source_compiles("
|
|
||||||
#include <pthread.h>
|
|
||||||
int main (void) {
|
|
||||||
int attr = ${PTHREAD_TEST};
|
|
||||||
return attr;
|
|
||||||
}
|
|
||||||
" ${PTHREAD_TEST}
|
|
||||||
)
|
)
|
||||||
endforeach()
|
target_link_libraries(cpufeatures dl)
|
||||||
list(APPEND WEBP_DEP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} cpufeatures)
|
||||||
endif()
|
set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS}
|
||||||
set(WEBP_USE_THREAD ${Threads_FOUND})
|
${ANDROID_NDK}/sources/android/cpufeatures
|
||||||
|
|
||||||
# TODO: this seems unused, check with autotools.
|
|
||||||
set(LT_OBJDIR ".libs/")
|
|
||||||
|
|
||||||
# Only useful for vwebp, so useless for now.
|
|
||||||
# find_package(OpenGL)
|
|
||||||
# set(WEBP_HAVE_GL ${OPENGL_FOUND})
|
|
||||||
# set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIRS})
|
|
||||||
# set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} ${OPENGL_LIBRARIES})
|
|
||||||
|
|
||||||
# Find the standard C math library.
|
|
||||||
find_library(MATH_LIBRARY NAMES m)
|
|
||||||
if(MATH_LIBRARY)
|
|
||||||
list(APPEND WEBP_DEP_LIBRARIES ${MATH_LIBRARY})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Find the standard image libraries.
|
|
||||||
set(WEBP_DEP_IMG_LIBRARIES)
|
|
||||||
set(WEBP_DEP_IMG_INCLUDE_DIRS)
|
|
||||||
foreach(I_LIB PNG JPEG TIFF GIF)
|
|
||||||
find_package(${I_LIB})
|
|
||||||
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
|
|
||||||
if(${I_LIB}_FOUND)
|
|
||||||
list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
|
|
||||||
list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIRS})
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
## Check for specific headers.
|
|
||||||
include(CheckIncludeFiles)
|
|
||||||
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
|
|
||||||
check_include_files(dlfcn.h HAVE_DLFCN_H)
|
|
||||||
check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
|
|
||||||
check_include_files(GL/glut.h HAVE_GL_GLUT_H)
|
|
||||||
check_include_files(inttypes.h HAVE_INTTYPES_H)
|
|
||||||
check_include_files(memory.h HAVE_MEMORY_H)
|
|
||||||
check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
|
|
||||||
check_include_files(shlwapi.h HAVE_SHLWAPI_H)
|
|
||||||
check_include_files(stdint.h HAVE_STDINT_H)
|
|
||||||
check_include_files(stdlib.h HAVE_STDLIB_H)
|
|
||||||
check_include_files(strings.h HAVE_STRINGS_H)
|
|
||||||
check_include_files(string.h HAVE_STRING_H)
|
|
||||||
check_include_files(sys/stat.h HAVE_SYS_STAT_H)
|
|
||||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
|
||||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
|
||||||
check_include_files(wincodec.h HAVE_WINCODEC_H)
|
|
||||||
check_include_files(windows.h HAVE_WINDOWS_H)
|
|
||||||
|
|
||||||
# Windows specifics
|
|
||||||
if(HAVE_WINCODEC_H)
|
|
||||||
list(APPEND WEBP_DEP_LIBRARIES shlwapi ole32 windowscodecs)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
## Check for SIMD extensions.
|
|
||||||
set(WEBP_SIMD_FLAGS "SSE2;SSE41;AVX2")
|
|
||||||
set(WEBP_SIMD_FILE_EXTENSIONS "_sse2.c;_sse41.c;_avx2.c")
|
|
||||||
if(MSVC)
|
|
||||||
# MSVC does not have a SSE4 flag but AVX2 support implies
|
|
||||||
# SSE4 support.
|
|
||||||
set(SIMD_ENABLE_FLAGS "/arch:SSE2;/arch:AVX2;/arch:AVX2")
|
|
||||||
set(SIMD_DISABLE_FLAGS)
|
|
||||||
else()
|
|
||||||
set(SIMD_ENABLE_FLAGS "-msse2;-msse4.1;-mavx2")
|
|
||||||
set(SIMD_DISABLE_FLAGS "-mno-sse2;-mno-sse4.1;-mno-avx2")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(WEBP_SIMD_FILES_TO_NOT_INCLUDE)
|
|
||||||
set(WEBP_SIMD_FILES_TO_INCLUDE)
|
|
||||||
set(WEBP_SIMD_FLAGS_TO_INCLUDE)
|
|
||||||
|
|
||||||
list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH)
|
|
||||||
math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
|
|
||||||
|
|
||||||
foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
|
||||||
list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG)
|
|
||||||
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
|
||||||
set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG})
|
|
||||||
check_c_source_compiles("
|
|
||||||
#include \"${CMAKE_CURRENT_LIST_DIR}/src/dsp/dsp.h\"
|
|
||||||
int main(void) {
|
|
||||||
#if !defined(WEBP_USE_${WEBP_SIMD_FLAG})
|
|
||||||
this is not valid code
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
"
|
|
||||||
WEBP_HAVE_${WEBP_SIMD_FLAG}
|
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
# Check which files we should include or not.
|
|
||||||
list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
|
|
||||||
file(GLOB SIMD_FILES RELATIVE ${CMAKE_CURRENT_LIST_DIR}
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/dsp/*${WEBP_SIMD_FILE_EXTENSION}"
|
|
||||||
)
|
|
||||||
if(WEBP_HAVE_${WEBP_SIMD_FLAG})
|
|
||||||
# Memorize the file and flags.
|
|
||||||
foreach(FILE ${SIMD_FILES})
|
|
||||||
list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE})
|
|
||||||
list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${SIMD_COMPILE_FLAG})
|
|
||||||
endforeach()
|
|
||||||
else()
|
|
||||||
# Remove the file from the list.
|
|
||||||
foreach(FILE ${SIMD_FILES})
|
|
||||||
list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE})
|
|
||||||
endforeach()
|
|
||||||
# Explicitly disable SIMD.
|
|
||||||
if(SIMD_DISABLE_FLAGS)
|
|
||||||
list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
|
||||||
include(CheckCCompilerFlag)
|
|
||||||
check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
|
|
||||||
if(HAS_COMPILE_FLAG)
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
## Define extra info.
|
|
||||||
set(PACKAGE ${PROJECT_NAME})
|
|
||||||
set(PACKAGE_NAME ${PROJECT_NAME})
|
|
||||||
|
|
||||||
# Read from configure.ac.
|
|
||||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC)
|
|
||||||
string(REGEX MATCHALL "\\[([0-9a-z\\.:/]*)\\]"
|
|
||||||
CONFIGURE_AC_PACKAGE_INFO ${CONFIGURE_AC}
|
|
||||||
)
|
|
||||||
function(strip_bracket VAR)
|
|
||||||
string(LENGTH ${${VAR}} TMP_LEN)
|
|
||||||
math(EXPR TMP_LEN ${TMP_LEN}-2)
|
|
||||||
string(SUBSTRING ${${VAR}} 1 ${TMP_LEN} TMP_SUB)
|
|
||||||
set(${VAR} ${TMP_SUB} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
list(GET CONFIGURE_AC_PACKAGE_INFO 1 PACKAGE_VERSION)
|
|
||||||
strip_bracket(PACKAGE_VERSION)
|
|
||||||
list(GET CONFIGURE_AC_PACKAGE_INFO 2 PACKAGE_BUGREPORT)
|
|
||||||
strip_bracket(PACKAGE_BUGREPORT)
|
|
||||||
list(GET CONFIGURE_AC_PACKAGE_INFO 3 PACKAGE_URL)
|
|
||||||
strip_bracket(PACKAGE_URL)
|
|
||||||
|
|
||||||
# Build more info.
|
|
||||||
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
|
||||||
set(PACKAGE_TARNAME ${PACKAGE_NAME})
|
|
||||||
set(VERSION ${PACKAGE_VERSION})
|
|
||||||
|
|
||||||
## Generate the config.h header.
|
|
||||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/config.h.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/include/webp/config.h)
|
|
||||||
add_definitions(-DHAVE_CONFIG_H)
|
|
||||||
# The webp folder is included as we reference config.h as
|
|
||||||
# ../webp/config.h or webp/config.h
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/include/webp
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# WebP source files.
|
# WebP source files.
|
||||||
# Read the Makefile.am to get the source files.
|
# Read the Makefile.am to get the source files.
|
||||||
set(WEBP_SRCS)
|
|
||||||
|
|
||||||
function(parse_Makefile_am FOLDER WEBP_SRCS)
|
function(parse_Makefile_am FOLDER VAR)
|
||||||
file(READ ${FOLDER}/Makefile.am MAKEFILE_AM)
|
file(READ ${FOLDER}/Makefile.am MAKEFILE_AM)
|
||||||
string(REGEX MATCHALL "_SOURCES \\+= [^\n]*"
|
string(REGEX MATCHALL "_SOURCES \\+= [^\n]*"
|
||||||
FILES_PER_LINE ${MAKEFILE_AM}
|
FILES_PER_LINE ${MAKEFILE_AM}
|
||||||
)
|
)
|
||||||
set(SRCS ${WEBP_SRCS})
|
set(SRCS ${${VAR}})
|
||||||
foreach(FILES ${FILES_PER_LINE})
|
foreach(FILES ${FILES_PER_LINE})
|
||||||
string(SUBSTRING ${FILES} 12 -1 FILES)
|
string(SUBSTRING ${FILES} 12 -1 FILES)
|
||||||
string(REGEX MATCHALL "[0-9a-z\\._]+"
|
string(REGEX MATCHALL "[0-9a-z\\._]+"
|
||||||
@@ -242,16 +60,17 @@ function(parse_Makefile_am FOLDER WEBP_SRCS)
|
|||||||
list(APPEND SRCS ${FOLDER}/${FILE})
|
list(APPEND SRCS ${FOLDER}/${FILE})
|
||||||
endforeach()
|
endforeach()
|
||||||
endforeach()
|
endforeach()
|
||||||
set(WEBP_SRCS ${SRCS} PARENT_SCOPE)
|
set(${VAR} ${SRCS} PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/dec "${WEBP_SRCS}")
|
set(WEBP_SRCS)
|
||||||
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/demux "${WEBP_SRCS}")
|
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/dec "WEBP_SRCS")
|
||||||
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/dsp "${WEBP_SRCS}")
|
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/demux "WEBP_SRCS")
|
||||||
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/enc "${WEBP_SRCS}")
|
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/dsp "WEBP_SRCS")
|
||||||
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/utils "${WEBP_SRCS}")
|
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/enc "WEBP_SRCS")
|
||||||
|
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/utils "WEBP_SRCS")
|
||||||
|
|
||||||
# Remove the files specific to SIMD we don't user.
|
# Remove the files specific to SIMD we don't use.
|
||||||
foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE})
|
foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE})
|
||||||
list(REMOVE_ITEM WEBP_SRCS ${FILE})
|
list(REMOVE_ITEM WEBP_SRCS ${FILE})
|
||||||
endforeach()
|
endforeach()
|
||||||
@@ -277,36 +96,51 @@ foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
|
|||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Build the executables if asked for.
|
# Build the executables if asked for.
|
||||||
if(WEBP_BUILD_CWEBP OR WEBP_BUILD_DWEBP)
|
if(WEBP_BUILD_CWEBP OR WEBP_BUILD_DWEBP OR
|
||||||
|
WEBP_BUILD_GIF2WEBP OR WEBP_BUILD_IMG2WEBP)
|
||||||
# Example utility library.
|
# Example utility library.
|
||||||
set(exampleutil_SRCS
|
set(exampleutil_SRCS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/example_util.c
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/example_util.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/example_util.h
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/example_util.h)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
|
|
||||||
add_library(exampleutil ${exampleutil_SRCS})
|
add_library(exampleutil ${exampleutil_SRCS})
|
||||||
target_link_libraries(exampleutil webp ${WEBP_DEP_LIBRARIES})
|
target_link_libraries(exampleutil webp ${WEBP_DEP_LIBRARIES})
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WEBP_BUILD_CWEBP)
|
set(imageioutil_SRCS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/imageio_util.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/imageio_util.h)
|
||||||
|
add_library(imageioutil ${imageioutil_SRCS})
|
||||||
|
target_link_libraries(imageioutil ${WEBP_DEP_LIBRARIES})
|
||||||
|
|
||||||
# Image-decoding utility library.
|
# Image-decoding utility library.
|
||||||
set(exampledec_SRCS
|
set(imagedec_SRCS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/image_dec.c
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/gifdec.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/image_dec.h
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/gifdec.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/jpegdec.c
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/image_dec.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/jpegdec.h
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/image_dec.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/metadata.c
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/jpegdec.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/metadata.h
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/jpegdec.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/pngdec.c
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/metadata.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/pngdec.h
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/metadata.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/tiffdec.c
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/pngdec.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/tiffdec.h
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/pngdec.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/webpdec.c
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/tiffdec.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/webpdec.h
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/tiffdec.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/wicdec.c
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/webpdec.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/wicdec.h)
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/webpdec.h
|
||||||
add_library(exampledec ${exampledec_SRCS})
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/wicdec.c
|
||||||
target_link_libraries(exampledec webp ${WEBP_DEP_LIBRARIES}
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/wicdec.h)
|
||||||
|
add_library(imagedec ${imagedec_SRCS})
|
||||||
|
target_link_libraries(imagedec webp ${WEBP_DEP_LIBRARIES}
|
||||||
${WEBP_DEP_IMG_LIBRARIES})
|
${WEBP_DEP_IMG_LIBRARIES})
|
||||||
|
|
||||||
|
# Image-encoding utility library.
|
||||||
|
set(imageenc_SRCS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/image_enc.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/imageio/image_enc.h)
|
||||||
|
add_library(imageenc ${imageenc_SRCS})
|
||||||
|
target_link_libraries(imageenc webp imageioutil
|
||||||
|
${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WEBP_BUILD_DWEBP)
|
if(WEBP_BUILD_DWEBP)
|
||||||
@@ -314,10 +148,10 @@ if(WEBP_BUILD_DWEBP)
|
|||||||
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
|
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
|
||||||
add_executable(dwebp
|
add_executable(dwebp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/dwebp.c
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/dwebp.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
|
||||||
)
|
target_link_libraries(dwebp imagedec imageenc webp
|
||||||
target_link_libraries(dwebp webp exampleutil ${WEBP_DEP_LIBRARIES}
|
exampleutil imageioutil
|
||||||
${WEBP_DEP_IMG_LIBRARIES}
|
${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -327,7 +161,29 @@ if(WEBP_BUILD_CWEBP)
|
|||||||
add_executable(cwebp
|
add_executable(cwebp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/cwebp.c
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/cwebp.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
|
${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
|
||||||
target_link_libraries(cwebp exampledec webp exampleutil
|
target_link_libraries(cwebp imagedec webp exampleutil imageioutil
|
||||||
|
${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WEBP_BUILD_GIF2WEBP)
|
||||||
|
# gif2webp
|
||||||
|
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
|
||||||
|
set(GIF2WEBP_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/gif2webp.c)
|
||||||
|
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "GIF2WEBP_SRCS")
|
||||||
|
add_executable(gif2webp ${GIF2WEBP_SRCS})
|
||||||
|
target_link_libraries(gif2webp imagedec webp exampleutil imageioutil
|
||||||
|
${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WEBP_BUILD_IMG2WEBP)
|
||||||
|
# img2webp
|
||||||
|
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
|
||||||
|
set(IMG2WEBP_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/img2webp.c)
|
||||||
|
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "IMG2WEBP_SRCS")
|
||||||
|
add_executable(img2webp ${IMG2WEBP_SRCS})
|
||||||
|
target_link_libraries(img2webp imagedec webp exampleutil imageioutil
|
||||||
${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
|
${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
SUBDIRS = src examples man
|
SUBDIRS = src imageio man
|
||||||
EXTRA_DIST = COPYING autogen.sh
|
EXTRA_DIST = COPYING autogen.sh
|
||||||
|
|
||||||
|
if WANT_EXTRAS
|
||||||
|
SUBDIRS += extras
|
||||||
|
endif
|
||||||
|
|
||||||
|
SUBDIRS += examples
|
||||||
|
|||||||
185
Makefile.vc
185
Makefile.vc
@@ -37,6 +37,8 @@ LNKDLL = link.exe /DLL $(NOLOGO)
|
|||||||
LNKEXE = link.exe $(NOLOGO)
|
LNKEXE = link.exe $(NOLOGO)
|
||||||
LNKLIB = lib.exe $(NOLOGO)
|
LNKLIB = lib.exe $(NOLOGO)
|
||||||
MT = mt.exe $(NOLOGO)
|
MT = mt.exe $(NOLOGO)
|
||||||
|
RCNODBG = rc.exe $(NOLOGO) /l"0x0409" # 0x409 = U.S. English
|
||||||
|
RCDEBUG = $(RCNODBG) /D_DEBUG
|
||||||
|
|
||||||
!IF "$(ARCH)" == "ARM"
|
!IF "$(ARCH)" == "ARM"
|
||||||
CFLAGS = $(CFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP /DWEBP_USE_THREAD
|
CFLAGS = $(CFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP /DWEBP_USE_THREAD
|
||||||
@@ -82,6 +84,8 @@ OUTPUT_DIRS = $(DIRBIN) $(DIRINC) $(DIRLIB) \
|
|||||||
$(DIROBJ)\dsp \
|
$(DIROBJ)\dsp \
|
||||||
$(DIROBJ)\enc \
|
$(DIROBJ)\enc \
|
||||||
$(DIROBJ)\examples \
|
$(DIROBJ)\examples \
|
||||||
|
$(DIROBJ)\extras \
|
||||||
|
$(DIROBJ)\imageio \
|
||||||
$(DIROBJ)\mux \
|
$(DIROBJ)\mux \
|
||||||
$(DIROBJ)\utils \
|
$(DIROBJ)\utils \
|
||||||
|
|
||||||
@@ -99,9 +103,11 @@ LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
|
|||||||
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
|
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
|
||||||
!ELSE IF "$(CFG)" == "release-dynamic"
|
!ELSE IF "$(CFG)" == "release-dynamic"
|
||||||
CC = $(CCNODBG)
|
CC = $(CCNODBG)
|
||||||
|
RC = $(RCNODBG)
|
||||||
DLLBUILD = TRUE
|
DLLBUILD = TRUE
|
||||||
!ELSE IF "$(CFG)" == "debug-dynamic"
|
!ELSE IF "$(CFG)" == "debug-dynamic"
|
||||||
CC = $(CCDEBUG)
|
CC = $(CCDEBUG)
|
||||||
|
RC = $(RCDEBUG)
|
||||||
RTLIB = $(RTLIBD)
|
RTLIB = $(RTLIBD)
|
||||||
DLLBUILD = TRUE
|
DLLBUILD = TRUE
|
||||||
LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
|
LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
|
||||||
@@ -169,16 +175,16 @@ CFGSET = TRUE
|
|||||||
#
|
#
|
||||||
|
|
||||||
DEC_OBJS = \
|
DEC_OBJS = \
|
||||||
$(DIROBJ)\dec\alpha.obj \
|
$(DIROBJ)\dec\alpha_dec.obj \
|
||||||
$(DIROBJ)\dec\buffer.obj \
|
$(DIROBJ)\dec\buffer_dec.obj \
|
||||||
$(DIROBJ)\dec\frame.obj \
|
$(DIROBJ)\dec\frame_dec.obj \
|
||||||
$(DIROBJ)\dec\idec.obj \
|
$(DIROBJ)\dec\idec_dec.obj \
|
||||||
$(DIROBJ)\dec\io.obj \
|
$(DIROBJ)\dec\io_dec.obj \
|
||||||
$(DIROBJ)\dec\quant.obj \
|
$(DIROBJ)\dec\quant_dec.obj \
|
||||||
$(DIROBJ)\dec\tree.obj \
|
$(DIROBJ)\dec\tree_dec.obj \
|
||||||
$(DIROBJ)\dec\vp8.obj \
|
$(DIROBJ)\dec\vp8_dec.obj \
|
||||||
$(DIROBJ)\dec\vp8l.obj \
|
$(DIROBJ)\dec\vp8l_dec.obj \
|
||||||
$(DIROBJ)\dec\webp.obj \
|
$(DIROBJ)\dec\webp_dec.obj \
|
||||||
|
|
||||||
DEMUX_OBJS = \
|
DEMUX_OBJS = \
|
||||||
$(DIROBJ)\demux\anim_decode.obj \
|
$(DIROBJ)\demux\anim_decode.obj \
|
||||||
@@ -187,6 +193,7 @@ DEMUX_OBJS = \
|
|||||||
DSP_DEC_OBJS = \
|
DSP_DEC_OBJS = \
|
||||||
$(DIROBJ)\dsp\alpha_processing.obj \
|
$(DIROBJ)\dsp\alpha_processing.obj \
|
||||||
$(DIROBJ)\dsp\alpha_processing_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\alpha_processing_mips_dsp_r2.obj \
|
||||||
|
$(DIROBJ)\dsp\alpha_processing_neon.obj \
|
||||||
$(DIROBJ)\dsp\alpha_processing_sse2.obj \
|
$(DIROBJ)\dsp\alpha_processing_sse2.obj \
|
||||||
$(DIROBJ)\dsp\alpha_processing_sse41.obj \
|
$(DIROBJ)\dsp\alpha_processing_sse41.obj \
|
||||||
$(DIROBJ)\dsp\cpu.obj \
|
$(DIROBJ)\dsp\cpu.obj \
|
||||||
@@ -200,18 +207,23 @@ DSP_DEC_OBJS = \
|
|||||||
$(DIROBJ)\dsp\dec_sse41.obj \
|
$(DIROBJ)\dsp\dec_sse41.obj \
|
||||||
$(DIROBJ)\dsp\filters.obj \
|
$(DIROBJ)\dsp\filters.obj \
|
||||||
$(DIROBJ)\dsp\filters_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\filters_mips_dsp_r2.obj \
|
||||||
|
$(DIROBJ)\dsp\filters_msa.obj \
|
||||||
|
$(DIROBJ)\dsp\filters_neon.obj \
|
||||||
$(DIROBJ)\dsp\filters_sse2.obj \
|
$(DIROBJ)\dsp\filters_sse2.obj \
|
||||||
$(DIROBJ)\dsp\lossless.obj \
|
$(DIROBJ)\dsp\lossless.obj \
|
||||||
$(DIROBJ)\dsp\lossless_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\lossless_mips_dsp_r2.obj \
|
||||||
|
$(DIROBJ)\dsp\lossless_msa.obj \
|
||||||
$(DIROBJ)\dsp\lossless_neon.obj \
|
$(DIROBJ)\dsp\lossless_neon.obj \
|
||||||
$(DIROBJ)\dsp\lossless_sse2.obj \
|
$(DIROBJ)\dsp\lossless_sse2.obj \
|
||||||
$(DIROBJ)\dsp\rescaler.obj \
|
$(DIROBJ)\dsp\rescaler.obj \
|
||||||
$(DIROBJ)\dsp\rescaler_mips32.obj \
|
$(DIROBJ)\dsp\rescaler_mips32.obj \
|
||||||
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
|
||||||
|
$(DIROBJ)\dsp\rescaler_msa.obj \
|
||||||
$(DIROBJ)\dsp\rescaler_neon.obj \
|
$(DIROBJ)\dsp\rescaler_neon.obj \
|
||||||
$(DIROBJ)\dsp\rescaler_sse2.obj \
|
$(DIROBJ)\dsp\rescaler_sse2.obj \
|
||||||
$(DIROBJ)\dsp\upsampling.obj \
|
$(DIROBJ)\dsp\upsampling.obj \
|
||||||
$(DIROBJ)\dsp\upsampling_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\upsampling_mips_dsp_r2.obj \
|
||||||
|
$(DIROBJ)\dsp\upsampling_msa.obj \
|
||||||
$(DIROBJ)\dsp\upsampling_neon.obj \
|
$(DIROBJ)\dsp\upsampling_neon.obj \
|
||||||
$(DIROBJ)\dsp\upsampling_sse2.obj \
|
$(DIROBJ)\dsp\upsampling_sse2.obj \
|
||||||
$(DIROBJ)\dsp\yuv.obj \
|
$(DIROBJ)\dsp\yuv.obj \
|
||||||
@@ -231,12 +243,14 @@ DSP_ENC_OBJS = \
|
|||||||
$(DIROBJ)\dsp\enc_avx2.obj \
|
$(DIROBJ)\dsp\enc_avx2.obj \
|
||||||
$(DIROBJ)\dsp\enc_mips32.obj \
|
$(DIROBJ)\dsp\enc_mips32.obj \
|
||||||
$(DIROBJ)\dsp\enc_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\enc_mips_dsp_r2.obj \
|
||||||
|
$(DIROBJ)\dsp\enc_msa.obj \
|
||||||
$(DIROBJ)\dsp\enc_neon.obj \
|
$(DIROBJ)\dsp\enc_neon.obj \
|
||||||
$(DIROBJ)\dsp\enc_sse2.obj \
|
$(DIROBJ)\dsp\enc_sse2.obj \
|
||||||
$(DIROBJ)\dsp\enc_sse41.obj \
|
$(DIROBJ)\dsp\enc_sse41.obj \
|
||||||
$(DIROBJ)\dsp\lossless_enc.obj \
|
$(DIROBJ)\dsp\lossless_enc.obj \
|
||||||
$(DIROBJ)\dsp\lossless_enc_mips32.obj \
|
$(DIROBJ)\dsp\lossless_enc_mips32.obj \
|
||||||
$(DIROBJ)\dsp\lossless_enc_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\lossless_enc_mips_dsp_r2.obj \
|
||||||
|
$(DIROBJ)\dsp\lossless_enc_msa.obj \
|
||||||
$(DIROBJ)\dsp\lossless_enc_neon.obj \
|
$(DIROBJ)\dsp\lossless_enc_neon.obj \
|
||||||
$(DIROBJ)\dsp\lossless_enc_sse2.obj \
|
$(DIROBJ)\dsp\lossless_enc_sse2.obj \
|
||||||
$(DIROBJ)\dsp\lossless_enc_sse41.obj \
|
$(DIROBJ)\dsp\lossless_enc_sse41.obj \
|
||||||
@@ -244,14 +258,17 @@ DSP_ENC_OBJS = \
|
|||||||
EX_ANIM_UTIL_OBJS = \
|
EX_ANIM_UTIL_OBJS = \
|
||||||
$(DIROBJ)\examples\anim_util.obj \
|
$(DIROBJ)\examples\anim_util.obj \
|
||||||
|
|
||||||
EX_FORMAT_DEC_OBJS = \
|
IMAGEIO_DEC_OBJS = \
|
||||||
$(DIROBJ)\examples\image_dec.obj \
|
$(DIROBJ)\imageio\image_dec.obj \
|
||||||
$(DIROBJ)\examples\jpegdec.obj \
|
$(DIROBJ)\imageio\jpegdec.obj \
|
||||||
$(DIROBJ)\examples\metadata.obj \
|
$(DIROBJ)\imageio\metadata.obj \
|
||||||
$(DIROBJ)\examples\pngdec.obj \
|
$(DIROBJ)\imageio\pngdec.obj \
|
||||||
$(DIROBJ)\examples\tiffdec.obj \
|
$(DIROBJ)\imageio\tiffdec.obj \
|
||||||
$(DIROBJ)\examples\webpdec.obj \
|
$(DIROBJ)\imageio\webpdec.obj \
|
||||||
$(DIROBJ)\examples\wicdec.obj \
|
$(DIROBJ)\imageio\wicdec.obj \
|
||||||
|
|
||||||
|
IMAGEIO_ENC_OBJS = \
|
||||||
|
$(DIROBJ)\imageio\image_enc.obj \
|
||||||
|
|
||||||
EX_GIF_DEC_OBJS = \
|
EX_GIF_DEC_OBJS = \
|
||||||
$(DIROBJ)\examples\gifdec.obj \
|
$(DIROBJ)\examples\gifdec.obj \
|
||||||
@@ -260,28 +277,36 @@ EX_UTIL_OBJS = \
|
|||||||
$(DIROBJ)\examples\example_util.obj \
|
$(DIROBJ)\examples\example_util.obj \
|
||||||
|
|
||||||
ENC_OBJS = \
|
ENC_OBJS = \
|
||||||
$(DIROBJ)\enc\alpha.obj \
|
$(DIROBJ)\enc\alpha_enc.obj \
|
||||||
$(DIROBJ)\enc\analysis.obj \
|
$(DIROBJ)\enc\analysis_enc.obj \
|
||||||
$(DIROBJ)\enc\backward_references.obj \
|
$(DIROBJ)\enc\backward_references_enc.obj \
|
||||||
$(DIROBJ)\enc\config.obj \
|
$(DIROBJ)\enc\config_enc.obj \
|
||||||
$(DIROBJ)\enc\cost.obj \
|
$(DIROBJ)\enc\cost_enc.obj \
|
||||||
$(DIROBJ)\enc\delta_palettization.obj \
|
$(DIROBJ)\enc\delta_palettization_enc.obj \
|
||||||
$(DIROBJ)\enc\filter.obj \
|
$(DIROBJ)\enc\filter_enc.obj \
|
||||||
$(DIROBJ)\enc\frame.obj \
|
$(DIROBJ)\enc\frame_enc.obj \
|
||||||
$(DIROBJ)\enc\histogram.obj \
|
$(DIROBJ)\enc\histogram_enc.obj \
|
||||||
$(DIROBJ)\enc\iterator.obj \
|
$(DIROBJ)\enc\iterator_enc.obj \
|
||||||
$(DIROBJ)\enc\near_lossless.obj \
|
$(DIROBJ)\enc\near_lossless_enc.obj \
|
||||||
$(DIROBJ)\enc\picture.obj \
|
$(DIROBJ)\enc\picture_enc.obj \
|
||||||
$(DIROBJ)\enc\picture_csp.obj \
|
$(DIROBJ)\enc\picture_csp_enc.obj \
|
||||||
$(DIROBJ)\enc\picture_psnr.obj \
|
$(DIROBJ)\enc\picture_psnr_enc.obj \
|
||||||
$(DIROBJ)\enc\picture_rescale.obj \
|
$(DIROBJ)\enc\picture_rescale_enc.obj \
|
||||||
$(DIROBJ)\enc\picture_tools.obj \
|
$(DIROBJ)\enc\picture_tools_enc.obj \
|
||||||
$(DIROBJ)\enc\quant.obj \
|
$(DIROBJ)\enc\predictor_enc.obj \
|
||||||
$(DIROBJ)\enc\syntax.obj \
|
$(DIROBJ)\enc\quant_enc.obj \
|
||||||
$(DIROBJ)\enc\token.obj \
|
$(DIROBJ)\enc\syntax_enc.obj \
|
||||||
$(DIROBJ)\enc\tree.obj \
|
$(DIROBJ)\enc\token_enc.obj \
|
||||||
$(DIROBJ)\enc\vp8l.obj \
|
$(DIROBJ)\enc\tree_enc.obj \
|
||||||
$(DIROBJ)\enc\webpenc.obj \
|
$(DIROBJ)\enc\vp8l_enc.obj \
|
||||||
|
$(DIROBJ)\enc\webp_enc.obj \
|
||||||
|
|
||||||
|
EXTRAS_OBJS = \
|
||||||
|
$(DIROBJ)\extras\extras.obj \
|
||||||
|
$(DIROBJ)\extras\quality_estimate.obj \
|
||||||
|
|
||||||
|
IMAGEIO_UTIL_OBJS = \
|
||||||
|
$(DIROBJ)\imageio\imageio_util.obj \
|
||||||
|
|
||||||
MUX_OBJS = \
|
MUX_OBJS = \
|
||||||
$(DIROBJ)\mux\anim_encode.obj \
|
$(DIROBJ)\mux\anim_encode.obj \
|
||||||
@@ -290,20 +315,20 @@ MUX_OBJS = \
|
|||||||
$(DIROBJ)\mux\muxread.obj \
|
$(DIROBJ)\mux\muxread.obj \
|
||||||
|
|
||||||
UTILS_DEC_OBJS = \
|
UTILS_DEC_OBJS = \
|
||||||
$(DIROBJ)\utils\bit_reader.obj \
|
$(DIROBJ)\utils\bit_reader_utils.obj \
|
||||||
$(DIROBJ)\utils\color_cache.obj \
|
$(DIROBJ)\utils\color_cache_utils.obj \
|
||||||
$(DIROBJ)\utils\filters.obj \
|
$(DIROBJ)\utils\filters_utils.obj \
|
||||||
$(DIROBJ)\utils\huffman.obj \
|
$(DIROBJ)\utils\huffman_utils.obj \
|
||||||
$(DIROBJ)\utils\quant_levels_dec.obj \
|
$(DIROBJ)\utils\quant_levels_dec_utils.obj \
|
||||||
$(DIROBJ)\utils\rescaler.obj \
|
$(DIROBJ)\utils\rescaler_utils.obj \
|
||||||
$(DIROBJ)\utils\random.obj \
|
$(DIROBJ)\utils\random_utils.obj \
|
||||||
$(DIROBJ)\utils\thread.obj \
|
$(DIROBJ)\utils\thread_utils.obj \
|
||||||
$(DIROBJ)\utils\utils.obj \
|
$(DIROBJ)\utils\utils.obj \
|
||||||
|
|
||||||
UTILS_ENC_OBJS = \
|
UTILS_ENC_OBJS = \
|
||||||
$(DIROBJ)\utils\bit_writer.obj \
|
$(DIROBJ)\utils\bit_writer_utils.obj \
|
||||||
$(DIROBJ)\utils\huffman_encode.obj \
|
$(DIROBJ)\utils\huffman_encode_utils.obj \
|
||||||
$(DIROBJ)\utils\quant_levels.obj \
|
$(DIROBJ)\utils\quant_levels_utils.obj \
|
||||||
|
|
||||||
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
||||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
|
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
|
||||||
@@ -317,7 +342,9 @@ ex: $(OUT_LIBS)
|
|||||||
all: ex
|
all: ex
|
||||||
!ELSE
|
!ELSE
|
||||||
OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe
|
OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe
|
||||||
EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe
|
EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe \
|
||||||
|
$(DIRBIN)\img2webp.exe $(DIRBIN)\get_disto.exe \
|
||||||
|
$(DIRBIN)\webp_quality.exe
|
||||||
|
|
||||||
ex: $(OUT_LIBS) $(OUT_EXAMPLES)
|
ex: $(OUT_LIBS) $(OUT_EXAMPLES)
|
||||||
all: ex $(EXTRA_EXAMPLES)
|
all: ex $(EXTRA_EXAMPLES)
|
||||||
@@ -327,18 +354,33 @@ gif2webp: $(DIRBIN)\gif2webp.exe
|
|||||||
anim_diff: $(DIRBIN)\anim_diff.exe
|
anim_diff: $(DIRBIN)\anim_diff.exe
|
||||||
|
|
||||||
$(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS)
|
$(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS)
|
||||||
$(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS)
|
$(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
|
||||||
$(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
|
$(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
|
||||||
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(EX_FORMAT_DEC_OBJS)
|
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS)
|
||||||
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj
|
$(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS)
|
||||||
|
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS)
|
||||||
|
$(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS)
|
||||||
|
$(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS)
|
||||||
$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS)
|
$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS)
|
||||||
$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(LIBWEBPMUX) $(LIBWEBP)
|
$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX)
|
||||||
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj
|
$(DIRBIN)\gif2webp.exe: $(LIBWEBP)
|
||||||
$(DIRBIN)\vwebp.exe: $(EX_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
|
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS)
|
||||||
|
$(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
|
||||||
$(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX)
|
$(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX)
|
||||||
$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(LIBWEBP)
|
$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
|
||||||
|
$(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX)
|
||||||
|
$(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS)
|
||||||
|
$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
|
||||||
|
$(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj
|
||||||
|
$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
|
||||||
|
|
||||||
|
$(DIRBIN)\webp_quality.exe: $(DIROBJ)\extras\webp_quality.obj
|
||||||
|
$(DIRBIN)\webp_quality.exe: $(IMAGEIO_UTIL_OBJS)
|
||||||
|
$(DIRBIN)\webp_quality.exe: $(EXTRAS_OBJS) $(LIBWEBP)
|
||||||
|
|
||||||
$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP)
|
$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP)
|
||||||
$(EX_UTIL_OBJS) $(EX_FORMAT_DEC_OBJS): $(OUTPUT_DIRS)
|
$(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS): $(OUTPUT_DIRS)
|
||||||
|
$(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(EXTRAS_OBJS): $(OUTPUT_DIRS)
|
||||||
!ENDIF # ARCH == ARM
|
!ENDIF # ARCH == ARM
|
||||||
|
|
||||||
experimental:
|
experimental:
|
||||||
@@ -360,8 +402,17 @@ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
|
|||||||
{$(DIROBJ)}.c{$(DIROBJ)}.obj:
|
{$(DIROBJ)}.c{$(DIROBJ)}.obj:
|
||||||
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
|
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
|
||||||
|
|
||||||
$(LIBWEBPMUX): $(LIBWEBP)
|
{src}.rc{$(DIROBJ)}.res:
|
||||||
$(LIBWEBPDEMUX): $(LIBWEBP)
|
$(RC) /fo$@ $<
|
||||||
|
{src\demux}.rc{$(DIROBJ)\demux}.res:
|
||||||
|
$(RC) /fo$@ $<
|
||||||
|
{src\mux}.rc{$(DIROBJ)\mux}.res:
|
||||||
|
$(RC) /fo$@ $<
|
||||||
|
|
||||||
|
$(LIBWEBP): $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
|
||||||
|
$(LIBWEBPDECODER): $(DIROBJ)\$(LIBWEBPDECODER_BASENAME:_debug=).res
|
||||||
|
$(LIBWEBPMUX): $(LIBWEBP) $(DIROBJ)\mux\$(LIBWEBPMUX_BASENAME:_debug=).res
|
||||||
|
$(LIBWEBPDEMUX): $(LIBWEBP) $(DIROBJ)\demux\$(LIBWEBPDEMUX_BASENAME:_debug=).res
|
||||||
|
|
||||||
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
|
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
|
||||||
$(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
|
$(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
|
||||||
@@ -406,6 +457,10 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
|
|||||||
# Batch rules
|
# Batch rules
|
||||||
{examples}.c{$(DIROBJ)\examples}.obj::
|
{examples}.c{$(DIROBJ)\examples}.obj::
|
||||||
$(CC) $(CFLAGS) /Fd$(DIROBJ)\examples\ /Fo$(DIROBJ)\examples\ $<
|
$(CC) $(CFLAGS) /Fd$(DIROBJ)\examples\ /Fo$(DIROBJ)\examples\ $<
|
||||||
|
{extras}.c{$(DIROBJ)\extras}.obj::
|
||||||
|
$(CC) $(CFLAGS) /Fd$(DIROBJ)\extras\ /Fo$(DIROBJ)\extras\ $<
|
||||||
|
{imageio}.c{$(DIROBJ)\imageio}.obj::
|
||||||
|
$(CC) $(CFLAGS) /Fd$(DIROBJ)\imageio\ /Fo$(DIROBJ)\imageio\ $<
|
||||||
{src\dec}.c{$(DIROBJ)\dec}.obj::
|
{src\dec}.c{$(DIROBJ)\dec}.obj::
|
||||||
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $<
|
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $<
|
||||||
{src\demux}.c{$(DIROBJ)\demux}.obj::
|
{src\demux}.c{$(DIROBJ)\demux}.obj::
|
||||||
@@ -425,6 +480,12 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
|
|||||||
$(MT) -manifest $@.manifest -outputresource:$@;1
|
$(MT) -manifest $@.manifest -outputresource:$@;1
|
||||||
del $@.manifest
|
del $@.manifest
|
||||||
|
|
||||||
|
{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
|
||||||
|
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
|
||||||
|
ole32.lib windowscodecs.lib shlwapi.lib
|
||||||
|
$(MT) -manifest $@.manifest -outputresource:$@;1
|
||||||
|
del $@.manifest
|
||||||
|
|
||||||
clean::
|
clean::
|
||||||
@-erase /s $(DIROBJ)\*.dll 2> NUL
|
@-erase /s $(DIROBJ)\*.dll 2> NUL
|
||||||
@-erase /s $(DIROBJ)\*.exp 2> NUL
|
@-erase /s $(DIROBJ)\*.exp 2> NUL
|
||||||
|
|||||||
28
NEWS
28
NEWS
@@ -1,3 +1,31 @@
|
|||||||
|
- 1/26/2017: version 0.6.0
|
||||||
|
* lossless performance and compression improvements
|
||||||
|
* miscellaneous performance improvements (SSE2, NEON, MSA)
|
||||||
|
* webpmux gained a -duration option allowing for frame timing modification
|
||||||
|
* new img2webp utility allowing a sequence of images to be converted to
|
||||||
|
animated webp
|
||||||
|
* API changes:
|
||||||
|
- libwebp:
|
||||||
|
WebPPictureSharpARGBToYUVA
|
||||||
|
WebPPlaneDistortion
|
||||||
|
- libwebpmux / gif2webp:
|
||||||
|
WebPAnimEncoderOptions: kmax <= 0 now disables keyframes, kmax == 1
|
||||||
|
forces all keyframes. See mux.h and the gif2webp
|
||||||
|
manpage for details.
|
||||||
|
|
||||||
|
- 12/13/2016: version 0.5.2
|
||||||
|
This is a binary compatible release.
|
||||||
|
This release covers CVE-2016-8888 and CVE-2016-9085.
|
||||||
|
* further security related hardening in the tools; fixes to
|
||||||
|
gif2webp/AnimEncoder (issues #310, #314, #316, #322), cwebp/libwebp (issue
|
||||||
|
#312)
|
||||||
|
* full libwebp (encoder & decoder) iOS framework; libwebpdecoder
|
||||||
|
WebP.framework renamed to WebPDecoder.framework (issue #307)
|
||||||
|
* CMake support for Android Studio (2.2)
|
||||||
|
* miscellaneous build related fixes (issue #306, #313)
|
||||||
|
* miscellaneous documentation improvements (issue #225)
|
||||||
|
* minor lossy encoder fixes and improvements
|
||||||
|
|
||||||
- 6/14/2016: version 0.5.1
|
- 6/14/2016: version 0.5.1
|
||||||
This is a binary compatible release.
|
This is a binary compatible release.
|
||||||
* miscellaneous bug fixes (issues #280, #289)
|
* miscellaneous bug fixes (issues #280, #289)
|
||||||
|
|||||||
58
README
58
README
@@ -4,7 +4,7 @@
|
|||||||
\__\__/\____/\_____/__/ ____ ___
|
\__\__/\____/\_____/__/ ____ ___
|
||||||
/ _/ / \ \ / _ \/ _/
|
/ _/ / \ \ / _ \/ _/
|
||||||
/ \_/ / / \ \ __/ \__
|
/ \_/ / / \ \ __/ \__
|
||||||
\____/____/\_____/_____/____/v0.5.1
|
\____/____/\_____/_____/____/v0.6.0
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
============
|
============
|
||||||
@@ -220,8 +220,9 @@ assumed to be a PNG, JPEG, TIFF or WebP file.
|
|||||||
Options:
|
Options:
|
||||||
-h / -help ............. short help
|
-h / -help ............. short help
|
||||||
-H / -longhelp ......... long help
|
-H / -longhelp ......... long help
|
||||||
-q <float> ............. quality factor (0:small..100:big)
|
-q <float> ............. quality factor (0:small..100:big), default=75
|
||||||
-alpha_q <int> ......... transparency-compression quality (0..100)
|
-alpha_q <int> ......... transparency-compression quality (0..100),
|
||||||
|
default=100
|
||||||
-preset <string> ....... preset setting, one of:
|
-preset <string> ....... preset setting, one of:
|
||||||
default, photo, picture,
|
default, photo, picture,
|
||||||
drawing, icon, text
|
drawing, icon, text
|
||||||
@@ -229,17 +230,18 @@ Options:
|
|||||||
-z <int> ............... activates lossless preset with given
|
-z <int> ............... activates lossless preset with given
|
||||||
level in [0:fast, ..., 9:slowest]
|
level in [0:fast, ..., 9:slowest]
|
||||||
|
|
||||||
-m <int> ............... compression method (0=fast, 6=slowest)
|
-m <int> ............... compression method (0=fast, 6=slowest), default=4
|
||||||
-segments <int> ........ number of segments to use (1..4)
|
-segments <int> ........ number of segments to use (1..4), default=4
|
||||||
-size <int> ............ target size (in bytes)
|
-size <int> ............ target size (in bytes)
|
||||||
-psnr <float> .......... target PSNR (in dB. typically: 42)
|
-psnr <float> .......... target PSNR (in dB. typically: 42)
|
||||||
|
|
||||||
-s <int> <int> ......... input size (width x height) for YUV
|
-s <int> <int> ......... input size (width x height) for YUV
|
||||||
-sns <int> ............. spatial noise shaping (0:off, 100:max)
|
-sns <int> ............. spatial noise shaping (0:off, 100:max), default=50
|
||||||
-f <int> ............... filter strength (0=off..100)
|
-f <int> ............... filter strength (0=off..100), default=60
|
||||||
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp)
|
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp), default=0
|
||||||
-strong ................ use strong filter instead of simple (default)
|
-strong ................ use strong filter instead of simple (default)
|
||||||
-nostrong .............. use simple filter instead of strong
|
-nostrong .............. use simple filter instead of strong
|
||||||
|
-sharp_yuv ............. use sharper (and slower) RGB->YUV conversion
|
||||||
-partition_limit <int> . limit quality to fit the 512k limit on
|
-partition_limit <int> . limit quality to fit the 512k limit on
|
||||||
the first partition (0=no degradation ... 100=full)
|
the first partition (0=no degradation ... 100=full)
|
||||||
-pass <int> ............ analysis pass number (1..10)
|
-pass <int> ............ analysis pass number (1..10)
|
||||||
@@ -252,18 +254,18 @@ Options:
|
|||||||
-print_ssim ............ prints averaged SSIM distortion
|
-print_ssim ............ prints averaged SSIM distortion
|
||||||
-print_lsim ............ prints local-similarity distortion
|
-print_lsim ............ prints local-similarity distortion
|
||||||
-d <file.pgm> .......... dump the compressed output (PGM file)
|
-d <file.pgm> .......... dump the compressed output (PGM file)
|
||||||
-alpha_method <int> .... transparency-compression method (0..1)
|
-alpha_method <int> .... transparency-compression method (0..1), default=1
|
||||||
-alpha_filter <string> . predictive filtering for alpha plane,
|
-alpha_filter <string> . predictive filtering for alpha plane,
|
||||||
one of: none, fast (default) or best
|
one of: none, fast (default) or best
|
||||||
-exact ................. preserve RGB values in transparent area
|
-exact ................. preserve RGB values in transparent area, default=off
|
||||||
-blend_alpha <hex> ..... blend colors against background color
|
-blend_alpha <hex> ..... blend colors against background color
|
||||||
expressed as RGB values written in
|
expressed as RGB values written in
|
||||||
hexadecimal, e.g. 0xc0e0d0 for red=0xc0
|
hexadecimal, e.g. 0xc0e0d0 for red=0xc0
|
||||||
green=0xe0 and blue=0xd0
|
green=0xe0 and blue=0xd0
|
||||||
-noalpha ............... discard any transparency information
|
-noalpha ............... discard any transparency information
|
||||||
-lossless .............. encode image losslessly
|
-lossless .............. encode image losslessly, default=off
|
||||||
-near_lossless <int> ... use near-lossless image
|
-near_lossless <int> ... use near-lossless image
|
||||||
preprocessing (0..100=off)
|
preprocessing (0..100=off), default=100
|
||||||
-hint <string> ......... specify image characteristics hint,
|
-hint <string> ......... specify image characteristics hint,
|
||||||
one of: photo, picture or graph
|
one of: photo, picture or graph
|
||||||
|
|
||||||
@@ -383,6 +385,7 @@ Options are:
|
|||||||
Keyboard shortcuts:
|
Keyboard shortcuts:
|
||||||
'c' ................ toggle use of color profile
|
'c' ................ toggle use of color profile
|
||||||
'i' ................ overlay file information
|
'i' ................ overlay file information
|
||||||
|
'd' ................ disable blending & disposal (debug)
|
||||||
'q' / 'Q' / ESC .... quit
|
'q' / 'Q' / ESC .... quit
|
||||||
|
|
||||||
Building:
|
Building:
|
||||||
@@ -411,6 +414,37 @@ $ make -f makefile.unix examples/vwebp
|
|||||||
> nmake /f Makefile.vc CFG=release-static \
|
> nmake /f Makefile.vc CFG=release-static \
|
||||||
../obj/x64/release-static/bin/vwebp.exe
|
../obj/x64/release-static/bin/vwebp.exe
|
||||||
|
|
||||||
|
Animation creation tool:
|
||||||
|
========================
|
||||||
|
The utility 'img2webp' can turn a sequence of input images (PNG, JPEG, ...)
|
||||||
|
into an animated WebP file. It offers fine control over duration, encoding
|
||||||
|
modes, etc.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
img2webp [file-level options] [image files...] [per-frame options...]
|
||||||
|
|
||||||
|
File-level options (only used at the start of compression):
|
||||||
|
-min_size ............ minimize size
|
||||||
|
-loop <int> .......... loop count (default: 0, = infinite loop)
|
||||||
|
-kmax <int> .......... maximum number of frame between key-frames
|
||||||
|
(0=only keyframes)
|
||||||
|
-kmin <int> .......... minimum number of frame between key-frames
|
||||||
|
(0=disable key-frames altogether)
|
||||||
|
-mixed ............... use mixed lossy/lossless automatic mode
|
||||||
|
-v ................... verbose mode
|
||||||
|
-h ................... this help
|
||||||
|
|
||||||
|
Per-frame options (only used for subsequent images input):
|
||||||
|
-d <int> ............. frame duration in ms (default: 100)
|
||||||
|
-lossless ........... use lossless mode (default)
|
||||||
|
-lossy ... ........... use lossy mode
|
||||||
|
-q <float> ........... quality
|
||||||
|
-m <int> ............. method to use
|
||||||
|
|
||||||
|
example: img2webp -loop 2 in0.png -lossy in1.jpg
|
||||||
|
-d 80 in2.tiff -o out.webp
|
||||||
|
|
||||||
Animated GIF conversion:
|
Animated GIF conversion:
|
||||||
========================
|
========================
|
||||||
Animated GIF files can be converted to WebP files with animation using the
|
Animated GIF files can be converted to WebP files with animation using the
|
||||||
|
|||||||
15
README.mux
15
README.mux
@@ -1,7 +1,7 @@
|
|||||||
__ __ ____ ____ ____ __ __ _ __ __
|
__ __ ____ ____ ____ __ __ _ __ __
|
||||||
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
|
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
|
||||||
\ / __/ _ \ __/ / / (_/ /__
|
\ / __/ _ \ __/ / / (_/ /__
|
||||||
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.3.1
|
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.4.0
|
||||||
|
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
@@ -25,6 +25,8 @@ A list of options is available using the -help command line flag:
|
|||||||
> webpmux -help
|
> webpmux -help
|
||||||
Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
|
Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
|
||||||
webpmux -set SET_OPTIONS INPUT -o OUTPUT
|
webpmux -set SET_OPTIONS INPUT -o OUTPUT
|
||||||
|
webpmux -duration DURATION_OPTIONS [-duration ...]
|
||||||
|
INPUT -o OUTPUT
|
||||||
webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT
|
webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT
|
||||||
webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]
|
webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]
|
||||||
[-bgcolor BACKGROUND_COLOR] -o OUTPUT
|
[-bgcolor BACKGROUND_COLOR] -o OUTPUT
|
||||||
@@ -48,6 +50,17 @@ SET_OPTIONS:
|
|||||||
'file.exif' contains the EXIF metadata to be set
|
'file.exif' contains the EXIF metadata to be set
|
||||||
'file.xmp' contains the XMP metadata to be set
|
'file.xmp' contains the XMP metadata to be set
|
||||||
|
|
||||||
|
DURATION_OPTIONS:
|
||||||
|
Set duration of selected frames:
|
||||||
|
duration set duration for each frames
|
||||||
|
duration,frame set duration of a particular frame
|
||||||
|
duration,start,end set duration of frames in the
|
||||||
|
interval [start,end])
|
||||||
|
where: 'duration' is the duration in milliseconds
|
||||||
|
'start' is the start frame index
|
||||||
|
'end' is the inclusive end frame index
|
||||||
|
The special 'end' value '0' means: last frame.
|
||||||
|
|
||||||
STRIP_OPTIONS:
|
STRIP_OPTIONS:
|
||||||
Strip color profile/metadata:
|
Strip color profile/metadata:
|
||||||
icc strip ICC profile
|
icc strip ICC profile
|
||||||
|
|||||||
161
build.gradle
161
build.gradle
@@ -96,19 +96,20 @@ model {
|
|||||||
c {
|
c {
|
||||||
source {
|
source {
|
||||||
srcDir "src/dec"
|
srcDir "src/dec"
|
||||||
include "alpha.c"
|
include "alpha_dec.c"
|
||||||
include "buffer.c"
|
include "buffer_dec.c"
|
||||||
include "frame.c"
|
include "frame_dec.c"
|
||||||
include "idec.c"
|
include "idec_dec.c"
|
||||||
include "io.c"
|
include "io_dec.c"
|
||||||
include "quant.c"
|
include "quant_dec.c"
|
||||||
include "tree.c"
|
include "tree_dec.c"
|
||||||
include "vp8.c"
|
include "vp8_dec.c"
|
||||||
include "vp8l.c"
|
include "vp8l_dec.c"
|
||||||
include "webp.c"
|
include "webp_dec.c"
|
||||||
srcDir "src/dsp"
|
srcDir "src/dsp"
|
||||||
include "alpha_processing.c"
|
include "alpha_processing.c"
|
||||||
include "alpha_processing_mips_dsp_r2.c"
|
include "alpha_processing_mips_dsp_r2.c"
|
||||||
|
include "alpha_processing_neon.$NEON"
|
||||||
include "alpha_processing_sse2.c"
|
include "alpha_processing_sse2.c"
|
||||||
include "alpha_processing_sse41.c"
|
include "alpha_processing_sse41.c"
|
||||||
include "argb.c"
|
include "argb.c"
|
||||||
@@ -125,18 +126,23 @@ model {
|
|||||||
include "dec_sse41.c"
|
include "dec_sse41.c"
|
||||||
include "filters.c"
|
include "filters.c"
|
||||||
include "filters_mips_dsp_r2.c"
|
include "filters_mips_dsp_r2.c"
|
||||||
|
include "filters_msa.c"
|
||||||
|
include "filters_neon.$NEON"
|
||||||
include "filters_sse2.c"
|
include "filters_sse2.c"
|
||||||
include "lossless.c"
|
include "lossless.c"
|
||||||
include "lossless_mips_dsp_r2.c"
|
include "lossless_mips_dsp_r2.c"
|
||||||
|
include "lossless_msa.c"
|
||||||
include "lossless_neon.$NEON"
|
include "lossless_neon.$NEON"
|
||||||
include "lossless_sse2.c"
|
include "lossless_sse2.c"
|
||||||
include "rescaler.c"
|
include "rescaler.c"
|
||||||
include "rescaler_mips32.c"
|
include "rescaler_mips32.c"
|
||||||
include "rescaler_mips_dsp_r2.c"
|
include "rescaler_mips_dsp_r2.c"
|
||||||
|
include "rescaler_msa.c"
|
||||||
include "rescaler_neon.$NEON"
|
include "rescaler_neon.$NEON"
|
||||||
include "rescaler_sse2.c"
|
include "rescaler_sse2.c"
|
||||||
include "upsampling.c"
|
include "upsampling.c"
|
||||||
include "upsampling_mips_dsp_r2.c"
|
include "upsampling_mips_dsp_r2.c"
|
||||||
|
include "upsampling_msa.c"
|
||||||
include "upsampling_neon.$NEON"
|
include "upsampling_neon.$NEON"
|
||||||
include "upsampling_sse2.c"
|
include "upsampling_sse2.c"
|
||||||
include "yuv.c"
|
include "yuv.c"
|
||||||
@@ -144,15 +150,14 @@ model {
|
|||||||
include "yuv_mips_dsp_r2.c"
|
include "yuv_mips_dsp_r2.c"
|
||||||
include "yuv_sse2.c"
|
include "yuv_sse2.c"
|
||||||
srcDir "src/utils"
|
srcDir "src/utils"
|
||||||
include "ans.c"
|
include "bit_reader_utils.c"
|
||||||
include "bit_reader.c"
|
include "color_cache_utils.c"
|
||||||
include "color_cache.c"
|
include "filters_utils.c"
|
||||||
include "filters.c"
|
include "huffman_utils.c"
|
||||||
include "huffman.c"
|
include "quant_levels_dec_utils.c"
|
||||||
include "quant_levels_dec.c"
|
include "random_utils.c"
|
||||||
include "random.c"
|
include "rescaler_utils.c"
|
||||||
include "rescaler.c"
|
include "thread_utils.c"
|
||||||
include "thread.c"
|
|
||||||
include "utils.c"
|
include "utils.c"
|
||||||
srcDir "src/dsp"
|
srcDir "src/dsp"
|
||||||
include "cost.c"
|
include "cost.c"
|
||||||
@@ -163,42 +168,45 @@ model {
|
|||||||
include "enc_avx2.c"
|
include "enc_avx2.c"
|
||||||
include "enc_mips32.c"
|
include "enc_mips32.c"
|
||||||
include "enc_mips_dsp_r2.c"
|
include "enc_mips_dsp_r2.c"
|
||||||
|
include "enc_msa.c"
|
||||||
include "enc_neon.$NEON"
|
include "enc_neon.$NEON"
|
||||||
include "enc_sse2.c"
|
include "enc_sse2.c"
|
||||||
include "enc_sse41.c"
|
include "enc_sse41.c"
|
||||||
include "lossless_enc.c"
|
include "lossless_enc.c"
|
||||||
include "lossless_enc_mips32.c"
|
include "lossless_enc_mips32.c"
|
||||||
include "lossless_enc_mips_dsp_r2.c"
|
include "lossless_enc_mips_dsp_r2.c"
|
||||||
|
include "lossless_enc_msa.c"
|
||||||
include "lossless_enc_neon.$NEON"
|
include "lossless_enc_neon.$NEON"
|
||||||
include "lossless_enc_sse2.c"
|
include "lossless_enc_sse2.c"
|
||||||
include "lossless_enc_sse41.c"
|
include "lossless_enc_sse41.c"
|
||||||
srcDir "src/enc"
|
srcDir "src/enc"
|
||||||
include "alpha.c"
|
include "alpha_enc.c"
|
||||||
include "analysis.c"
|
include "analysis_enc.c"
|
||||||
include "backward_references.c"
|
include "backward_references_enc.c"
|
||||||
include "config.c"
|
include "config_enc.c"
|
||||||
include "cost.c"
|
include "cost_enc.c"
|
||||||
include "delta_palettization.c"
|
include "delta_palettization_enc.c"
|
||||||
include "filter.c"
|
include "filter_enc.c"
|
||||||
include "frame.c"
|
include "frame_enc.c"
|
||||||
include "histogram.c"
|
include "histogram_enc.c"
|
||||||
include "iterator.c"
|
include "iterator_enc.c"
|
||||||
include "near_lossless.c"
|
include "near_lossless_enc.c"
|
||||||
include "picture.c"
|
include "picture_enc.c"
|
||||||
include "picture_csp.c"
|
include "picture_csp_enc.c"
|
||||||
include "picture_psnr.c"
|
include "picture_psnr_enc.c"
|
||||||
include "picture_rescale.c"
|
include "picture_rescale_enc.c"
|
||||||
include "picture_tools.c"
|
include "picture_tools_enc.c"
|
||||||
include "quant.c"
|
include "predictor_enc.c"
|
||||||
include "syntax.c"
|
include "quant_enc.c"
|
||||||
include "token.c"
|
include "syntax_enc.c"
|
||||||
include "tree.c"
|
include "token_enc.c"
|
||||||
include "vp8l.c"
|
include "tree_enc.c"
|
||||||
include "webpenc.c"
|
include "vp8l_enc.c"
|
||||||
|
include "webp_enc.c"
|
||||||
srcDir "src/utils"
|
srcDir "src/utils"
|
||||||
include "bit_writer.c"
|
include "bit_writer_utils.c"
|
||||||
include "huffman_encode.c"
|
include "huffman_encode_utils.c"
|
||||||
include "quant_levels.c"
|
include "quant_levels_utils.c"
|
||||||
}
|
}
|
||||||
exportedHeaders {
|
exportedHeaders {
|
||||||
srcDir "src"
|
srcDir "src"
|
||||||
@@ -250,7 +258,7 @@ model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
example_dec(NativeLibrarySpec) {
|
imageio_util(NativeLibrarySpec) {
|
||||||
binaries {
|
binaries {
|
||||||
all {
|
all {
|
||||||
lib library: "webp", linkage: "static"
|
lib library: "webp", linkage: "static"
|
||||||
@@ -259,7 +267,23 @@ model {
|
|||||||
sources {
|
sources {
|
||||||
c {
|
c {
|
||||||
source {
|
source {
|
||||||
srcDir "./examples"
|
srcDir "./imageio"
|
||||||
|
include "imageio_util.c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imagedec(NativeLibrarySpec) {
|
||||||
|
binaries {
|
||||||
|
all {
|
||||||
|
lib library: "webp", linkage: "static"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sources {
|
||||||
|
c {
|
||||||
|
source {
|
||||||
|
srcDir "./imageio"
|
||||||
include "image_dec.c"
|
include "image_dec.c"
|
||||||
include "jpegdec.c"
|
include "jpegdec.c"
|
||||||
include "metadata.c"
|
include "metadata.c"
|
||||||
@@ -270,11 +294,30 @@ model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imageenc(NativeLibrarySpec) {
|
||||||
|
binaries {
|
||||||
|
all {
|
||||||
|
lib library: "webp", linkage: "static"
|
||||||
|
lib library: "imageio_util", linkage: "static"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sources {
|
||||||
|
c {
|
||||||
|
source {
|
||||||
|
srcDir "./imageio"
|
||||||
|
include "image_enc.c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cwebp(NativeExecutableSpec) {
|
cwebp(NativeExecutableSpec) {
|
||||||
binaries {
|
binaries {
|
||||||
all {
|
all {
|
||||||
lib library: "example_util", linkage: "static"
|
lib library: "example_util", linkage: "static"
|
||||||
lib library: "example_dec", linkage: "static"
|
lib library: "imagedec", linkage: "static"
|
||||||
|
lib library: "imageio_util", linkage: "static"
|
||||||
lib library: "webp", linkage: "static"
|
lib library: "webp", linkage: "static"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,6 +335,9 @@ model {
|
|||||||
binaries {
|
binaries {
|
||||||
all {
|
all {
|
||||||
lib library: "example_util", linkage: "static"
|
lib library: "example_util", linkage: "static"
|
||||||
|
lib library: "imagedec", linkage: "static"
|
||||||
|
lib library: "imageenc", linkage: "static"
|
||||||
|
lib library: "imageio_util", linkage: "static"
|
||||||
lib library: "webp"
|
lib library: "webp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,6 +355,7 @@ model {
|
|||||||
binaries {
|
binaries {
|
||||||
all {
|
all {
|
||||||
lib library: "example_util", linkage: "static"
|
lib library: "example_util", linkage: "static"
|
||||||
|
lib library: "imageio_util", linkage: "static"
|
||||||
lib library: "webpmux", linkage: "static"
|
lib library: "webpmux", linkage: "static"
|
||||||
lib library: "webp"
|
lib library: "webp"
|
||||||
}
|
}
|
||||||
@@ -322,6 +369,26 @@ model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img2webp_example(NativeExecutableSpec) {
|
||||||
|
binaries {
|
||||||
|
all {
|
||||||
|
lib library: "example_util", linkage: "static"
|
||||||
|
lib library: "imagedec", linkage: "static"
|
||||||
|
lib library: "imageio_util", linkage: "static"
|
||||||
|
lib library: "webpmux", linkage: "static"
|
||||||
|
lib library: "webp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sources {
|
||||||
|
c {
|
||||||
|
source {
|
||||||
|
srcDir "./examples"
|
||||||
|
include "img2webp.c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tasks {
|
tasks {
|
||||||
// Task to test all possible configurations.
|
// Task to test all possible configurations.
|
||||||
|
|||||||
141
cmake/config.h.cmake
Normal file
141
cmake/config.h.cmake
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
# Generate the config.h to compile with specific intrinsics / libs.
|
||||||
|
|
||||||
|
## Check for compiler options.
|
||||||
|
include(CheckCSourceCompiles)
|
||||||
|
check_c_source_compiles("
|
||||||
|
int main(void) {
|
||||||
|
(void)__builtin_bswap16(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
HAVE_BUILTIN_BSWAP16
|
||||||
|
)
|
||||||
|
check_c_source_compiles("
|
||||||
|
int main(void) {
|
||||||
|
(void)__builtin_bswap32(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
HAVE_BUILTIN_BSWAP32
|
||||||
|
)
|
||||||
|
check_c_source_compiles("
|
||||||
|
int main(void) {
|
||||||
|
(void)__builtin_bswap64(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
HAVE_BUILTIN_BSWAP64
|
||||||
|
)
|
||||||
|
|
||||||
|
## Check for libraries.
|
||||||
|
find_package(Threads)
|
||||||
|
if(Threads_FOUND)
|
||||||
|
if(CMAKE_USE_PTHREADS_INIT)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||||
|
endif()
|
||||||
|
foreach(PTHREAD_TEST HAVE_PTHREAD_PRIO_INHERIT PTHREAD_CREATE_UNDETACHED)
|
||||||
|
check_c_source_compiles("
|
||||||
|
#include <pthread.h>
|
||||||
|
int main (void) {
|
||||||
|
int attr = ${PTHREAD_TEST};
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
" ${PTHREAD_TEST}
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
list(APPEND WEBP_DEP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
endif()
|
||||||
|
set(WEBP_USE_THREAD ${Threads_FOUND})
|
||||||
|
|
||||||
|
# TODO: this seems unused, check with autotools.
|
||||||
|
set(LT_OBJDIR ".libs/")
|
||||||
|
|
||||||
|
# Only useful for vwebp, so useless for now.
|
||||||
|
# find_package(OpenGL)
|
||||||
|
# set(WEBP_HAVE_GL ${OPENGL_FOUND})
|
||||||
|
# set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIRS})
|
||||||
|
# set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} ${OPENGL_LIBRARIES})
|
||||||
|
|
||||||
|
# Find the standard C math library.
|
||||||
|
find_library(MATH_LIBRARY NAMES m)
|
||||||
|
if(MATH_LIBRARY)
|
||||||
|
list(APPEND WEBP_DEP_LIBRARIES ${MATH_LIBRARY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Find the standard image libraries.
|
||||||
|
set(WEBP_DEP_IMG_LIBRARIES)
|
||||||
|
set(WEBP_DEP_IMG_INCLUDE_DIRS)
|
||||||
|
foreach(I_LIB PNG JPEG TIFF GIF)
|
||||||
|
find_package(${I_LIB})
|
||||||
|
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
|
||||||
|
if(${I_LIB}_FOUND)
|
||||||
|
list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
|
||||||
|
list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIRS})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
## Check for specific headers.
|
||||||
|
include(CheckIncludeFiles)
|
||||||
|
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
|
||||||
|
check_include_files(dlfcn.h HAVE_DLFCN_H)
|
||||||
|
check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
|
||||||
|
check_include_files(GL/glut.h HAVE_GL_GLUT_H)
|
||||||
|
check_include_files(inttypes.h HAVE_INTTYPES_H)
|
||||||
|
check_include_files(memory.h HAVE_MEMORY_H)
|
||||||
|
check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
|
||||||
|
check_include_files(shlwapi.h HAVE_SHLWAPI_H)
|
||||||
|
check_include_files(stdint.h HAVE_STDINT_H)
|
||||||
|
check_include_files(stdlib.h HAVE_STDLIB_H)
|
||||||
|
check_include_files(strings.h HAVE_STRINGS_H)
|
||||||
|
check_include_files(string.h HAVE_STRING_H)
|
||||||
|
check_include_files(sys/stat.h HAVE_SYS_STAT_H)
|
||||||
|
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||||
|
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||||
|
check_include_files(wincodec.h HAVE_WINCODEC_H)
|
||||||
|
check_include_files(windows.h HAVE_WINDOWS_H)
|
||||||
|
|
||||||
|
# Windows specifics
|
||||||
|
if(HAVE_WINCODEC_H)
|
||||||
|
list(APPEND WEBP_DEP_LIBRARIES shlwapi ole32 windowscodecs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
## Check for SIMD extensions.
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/cpu.cmake)
|
||||||
|
|
||||||
|
## Define extra info.
|
||||||
|
set(PACKAGE ${PROJECT_NAME})
|
||||||
|
set(PACKAGE_NAME ${PROJECT_NAME})
|
||||||
|
|
||||||
|
# Read from configure.ac.
|
||||||
|
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC)
|
||||||
|
string(REGEX MATCHALL "\\[([0-9a-z\\.:/]*)\\]"
|
||||||
|
CONFIGURE_AC_PACKAGE_INFO ${CONFIGURE_AC}
|
||||||
|
)
|
||||||
|
function(strip_bracket VAR)
|
||||||
|
string(LENGTH ${${VAR}} TMP_LEN)
|
||||||
|
math(EXPR TMP_LEN ${TMP_LEN}-2)
|
||||||
|
string(SUBSTRING ${${VAR}} 1 ${TMP_LEN} TMP_SUB)
|
||||||
|
set(${VAR} ${TMP_SUB} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
list(GET CONFIGURE_AC_PACKAGE_INFO 1 PACKAGE_VERSION)
|
||||||
|
strip_bracket(PACKAGE_VERSION)
|
||||||
|
list(GET CONFIGURE_AC_PACKAGE_INFO 2 PACKAGE_BUGREPORT)
|
||||||
|
strip_bracket(PACKAGE_BUGREPORT)
|
||||||
|
list(GET CONFIGURE_AC_PACKAGE_INFO 3 PACKAGE_URL)
|
||||||
|
strip_bracket(PACKAGE_URL)
|
||||||
|
|
||||||
|
# Build more info.
|
||||||
|
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
||||||
|
set(PACKAGE_TARNAME ${PACKAGE_NAME})
|
||||||
|
set(VERSION ${PACKAGE_VERSION})
|
||||||
|
|
||||||
|
## Generate the config.h header.
|
||||||
|
configure_file(${CMAKE_CURRENT_LIST_DIR}/config.h.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/include/webp/config.h)
|
||||||
|
add_definitions(-DHAVE_CONFIG_H)
|
||||||
|
# The webp folder is included as we reference config.h as
|
||||||
|
# ../webp/config.h or webp/config.h
|
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/include/webp
|
||||||
|
)
|
||||||
@@ -103,9 +103,6 @@
|
|||||||
/* Enable experimental code */
|
/* Enable experimental code */
|
||||||
#cmakedefine WEBP_EXPERIMENTAL_FEATURES 1
|
#cmakedefine WEBP_EXPERIMENTAL_FEATURES 1
|
||||||
|
|
||||||
/* Define to 1 to force aligned memory operations */
|
|
||||||
#cmakedefine WEBP_FORCE_ALIGNED 1
|
|
||||||
|
|
||||||
/* Set to 1 if AVX2 is supported */
|
/* Set to 1 if AVX2 is supported */
|
||||||
#cmakedefine WEBP_HAVE_AVX2 1
|
#cmakedefine WEBP_HAVE_AVX2 1
|
||||||
|
|
||||||
|
|||||||
113
cmake/cpu.cmake
Normal file
113
cmake/cpu.cmake
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
## Check for SIMD extensions.
|
||||||
|
|
||||||
|
function(webp_check_compiler_flag WEBP_SIMD_FLAG)
|
||||||
|
unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE)
|
||||||
|
check_c_source_compiles("
|
||||||
|
#include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\"
|
||||||
|
int main(void) {
|
||||||
|
#if !defined(WEBP_USE_${WEBP_SIMD_FLAG})
|
||||||
|
this is not valid code
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
" WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}
|
||||||
|
)
|
||||||
|
if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
|
||||||
|
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# those are included in the names of WEBP_USE_* in c++ code.
|
||||||
|
set(WEBP_SIMD_FLAGS "SSE2;SSE41;AVX2;MIPS32;MIPS_DSP_R2;NEON;MSA")
|
||||||
|
set(WEBP_SIMD_FILE_EXTENSIONS "_sse2.c;_sse41.c;_avx2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
|
||||||
|
if(MSVC)
|
||||||
|
# MSVC does not have a SSE4 flag but AVX2 support implies
|
||||||
|
# SSE4 support.
|
||||||
|
set(SIMD_ENABLE_FLAGS "/arch:SSE2;/arch:AVX2;/arch:AVX2;;;;")
|
||||||
|
set(SIMD_DISABLE_FLAGS)
|
||||||
|
else()
|
||||||
|
set(SIMD_ENABLE_FLAGS "-msse2;-msse4.1;-mavx2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
|
||||||
|
set(SIMD_DISABLE_FLAGS "-mno-sse2;-mno-sse4.1;-mno-avx2;;-mno-dspr2;;-mno-msa")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(WEBP_SIMD_FILES_TO_NOT_INCLUDE)
|
||||||
|
set(WEBP_SIMD_FILES_TO_INCLUDE)
|
||||||
|
set(WEBP_SIMD_FLAGS_TO_INCLUDE)
|
||||||
|
|
||||||
|
if(${ANDROID})
|
||||||
|
if(${ANDROID_ABI} STREQUAL "armeabi-v7a")
|
||||||
|
# This is because Android studio uses the configuration
|
||||||
|
# "-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"
|
||||||
|
# that does not trigger neon optimizations but should
|
||||||
|
# (as this configuration does not exist anymore).
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH)
|
||||||
|
math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
|
||||||
|
|
||||||
|
foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
||||||
|
list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG)
|
||||||
|
|
||||||
|
# First try with no extra flag added as the compiler might have default flags
|
||||||
|
# (especially on Android).
|
||||||
|
unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS)
|
||||||
|
webp_check_compiler_flag(${WEBP_SIMD_FLAG})
|
||||||
|
if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG})
|
||||||
|
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG})
|
||||||
|
webp_check_compiler_flag(${WEBP_SIMD_FLAG})
|
||||||
|
else()
|
||||||
|
set(SIMD_COMPILE_FLAG " ")
|
||||||
|
endif()
|
||||||
|
# Check which files we should include or not.
|
||||||
|
list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
|
||||||
|
file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
|
||||||
|
"src/dsp/*${WEBP_SIMD_FILE_EXTENSION}"
|
||||||
|
)
|
||||||
|
if(WEBP_HAVE_${WEBP_SIMD_FLAG})
|
||||||
|
# Memorize the file and flags.
|
||||||
|
foreach(FILE ${SIMD_FILES})
|
||||||
|
list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE})
|
||||||
|
list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${SIMD_COMPILE_FLAG})
|
||||||
|
endforeach()
|
||||||
|
else()
|
||||||
|
# Remove the file from the list.
|
||||||
|
foreach(FILE ${SIMD_FILES})
|
||||||
|
list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE})
|
||||||
|
endforeach()
|
||||||
|
# Explicitly disable SIMD.
|
||||||
|
if(SIMD_DISABLE_FLAGS)
|
||||||
|
list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
||||||
|
include(CheckCCompilerFlag)
|
||||||
|
if(SIMD_COMPILE_FLAG)
|
||||||
|
unset(HAS_COMPILE_FLAG CACHE)
|
||||||
|
check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
|
||||||
|
if(HAS_COMPILE_FLAG)
|
||||||
|
# Do one more check for Clang to circumvent CMake issue 13194.
|
||||||
|
if(COMMAND check_compiler_flag_common_patterns)
|
||||||
|
# Only in CMake 3.0 and above.
|
||||||
|
check_compiler_flag_common_patterns(COMMON_PATTERNS)
|
||||||
|
else()
|
||||||
|
set(COMMON_PATTERNS)
|
||||||
|
endif()
|
||||||
|
set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG})
|
||||||
|
check_c_source_compiles("int main(void) {return 0;}" FLAG2
|
||||||
|
FAIL_REGEX "warning: argument unused during compilation:"
|
||||||
|
${COMMON_PATTERNS}
|
||||||
|
)
|
||||||
|
if(NOT FLAG2)
|
||||||
|
unset(HAS_COMPILE_FLAG CACHE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(HAS_COMPILE_FLAG)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
90
configure.ac
90
configure.ac
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([libwebp], [0.5.1],
|
AC_INIT([libwebp], [0.6.0],
|
||||||
[https://bugs.chromium.org/p/webp],,
|
[https://bugs.chromium.org/p/webp],,
|
||||||
[http://developers.google.com/speed/webp])
|
[http://developers.google.com/speed/webp])
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_HOST
|
||||||
@@ -10,6 +10,7 @@ dnl === it must occur before LT_INIT (AC_PROG_LIBTOOL).
|
|||||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||||
|
|
||||||
AC_PROG_LIBTOOL
|
AC_PROG_LIBTOOL
|
||||||
|
AC_PROG_SED
|
||||||
AM_PROG_CC_C_O
|
AM_PROG_CC_C_O
|
||||||
|
|
||||||
dnl === Enable less verbose output when building.
|
dnl === Enable less verbose output when building.
|
||||||
@@ -195,40 +196,51 @@ AC_ARG_ENABLE([neon_rtcd],
|
|||||||
AS_IF([test "x$enable_neon" != "xno"], [
|
AS_IF([test "x$enable_neon" != "xno"], [
|
||||||
case "$host_cpu" in
|
case "$host_cpu" in
|
||||||
arm|armv7*)
|
arm|armv7*)
|
||||||
dnl Test for NEON support with no flags.
|
# Test for NEON support without flags before falling back to -mfpu=neon
|
||||||
AC_CHECK_HEADER([arm_neon.h],
|
for flag in '' '-mfpu=neon'; do
|
||||||
[AC_DEFINE(WEBP_HAVE_NEON, [1],
|
LOCAL_NEON_FLAGS="$INTRINSICS_CFLAGS $NEON_FLAGS"
|
||||||
[Set to 1 if NEON is supported])],
|
TEST_AND_ADD_CFLAGS([LOCAL_NEON_FLAGS], [$flag])
|
||||||
dnl Test for NEON support using -mfpu=neon
|
|
||||||
[unset ac_cv_header_arm_neon_h
|
|
||||||
NEON_FLAGS="$INTRINSICS_CFLAGS $NEON_FLAGS"
|
|
||||||
TEST_AND_ADD_CFLAGS([NEON_FLAGS], [-mfpu=neon])
|
|
||||||
AS_IF([test -n "$NEON_FLAGS"], [
|
|
||||||
SAVED_CFLAGS=$CFLAGS
|
SAVED_CFLAGS=$CFLAGS
|
||||||
CFLAGS="$CFLAGS $NEON_FLAGS"
|
CFLAGS="$CFLAGS $LOCAL_NEON_FLAGS"
|
||||||
AC_CHECK_HEADER([arm_neon.h],
|
|
||||||
[AS_IF([test "${host_os%%-*}" = "linux" -o \
|
dnl Note AC_LANG_PROGRAM([]) uses an old-style main definition.
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||||
|
#include <arm_neon.h>
|
||||||
|
int main(void) {
|
||||||
|
int8x8_t v = vdup_n_s8(0);
|
||||||
|
(void)v;
|
||||||
|
return 0;
|
||||||
|
}])],
|
||||||
|
[NEON_FLAGS="$(echo $LOCAL_NEON_FLAGS | $SED 's/^ *//')"
|
||||||
|
AS_IF([test -n "$NEON_FLAGS"], [
|
||||||
|
AS_IF([test "${host_os%%-*}" = "linux" -o \
|
||||||
"x$enable_neon_rtcd" = "xno"], [
|
"x$enable_neon_rtcd" = "xno"], [
|
||||||
AC_DEFINE(WEBP_HAVE_NEON, [1],
|
CFLAGS=$SAVED_CFLAGS
|
||||||
[Set to 1 if NEON is supported])],
|
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
|
||||||
[AC_MSG_WARN(m4_normalize([NEON runtime
|
break
|
||||||
cpu-detection is unavailble for
|
],[
|
||||||
${host_os%%-*}. Force with
|
AC_MSG_WARN(m4_normalize([NEON runtime cpu-detection is
|
||||||
CFLAGS=-mfpu=neon or
|
unavailable for ${host_os%%-*}. Force
|
||||||
|
with CFLAGS=-mfpu=neon or
|
||||||
--disable-neon-rtcd.]))
|
--disable-neon-rtcd.]))
|
||||||
enable_neon_rtcd=no
|
enable_neon_rtcd=no
|
||||||
NEON_FLAGS=""])],
|
NEON_FLAGS=""
|
||||||
[NEON_FLAGS=""])
|
])
|
||||||
|
],[
|
||||||
CFLAGS=$SAVED_CFLAGS
|
CFLAGS=$SAVED_CFLAGS
|
||||||
|
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
|
||||||
|
break
|
||||||
|
])])
|
||||||
|
CFLAGS=$SAVED_CFLAGS
|
||||||
|
done
|
||||||
|
|
||||||
AS_IF([test -n "$NEON_FLAGS"], [
|
AS_IF([test -n "$NEON_FLAGS"], [
|
||||||
dnl If NEON is available and rtcd is disabled apply
|
# If NEON is available and rtcd is disabled apply NEON_FLAGS globally.
|
||||||
dnl NEON_FLAGS globally.
|
|
||||||
AS_IF([test "x$enable_neon_rtcd" = "xno"], [
|
AS_IF([test "x$enable_neon_rtcd" = "xno"], [
|
||||||
AM_CFLAGS="$AM_CFLAGS $NEON_FLAGS"
|
AM_CFLAGS="$AM_CFLAGS $NEON_FLAGS"
|
||||||
NEON_FLAGS=""],
|
NEON_FLAGS=""],
|
||||||
[AC_DEFINE(WEBP_HAVE_NEON_RTCD, [1],
|
[AC_DEFINE(WEBP_HAVE_NEON_RTCD, [1],
|
||||||
[Set to 1 if runtime detection of NEON
|
[Set to 1 if runtime detection of NEON is enabled])])])
|
||||||
is enabled])])])])])
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
AC_SUBST([NEON_FLAGS])])
|
AC_SUBST([NEON_FLAGS])])
|
||||||
@@ -544,6 +556,11 @@ AS_IF([test "x$enable_gif" != "xno"], [
|
|||||||
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_animdiff}" = "yes"])
|
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_animdiff}" = "yes"])
|
||||||
AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
|
AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
|
||||||
|
|
||||||
|
if test "$enable_libwebpmux" = "yes"; then
|
||||||
|
build_img2webp=yes
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL([BUILD_IMG2WEBP], [test "${build_img2webp}" = "yes"])
|
||||||
|
|
||||||
dnl === check for WIC support ===
|
dnl === check for WIC support ===
|
||||||
|
|
||||||
AC_ARG_ENABLE([wic],
|
AC_ARG_ENABLE([wic],
|
||||||
@@ -596,19 +613,6 @@ if test "$enable_wic" = "yes"; then
|
|||||||
fi
|
fi
|
||||||
esac
|
esac
|
||||||
|
|
||||||
dnl === If --enable-aligned is defined, define WEBP_FORCE_ALIGNED
|
|
||||||
|
|
||||||
AC_MSG_CHECKING(if --enable-aligned option is specified)
|
|
||||||
AC_ARG_ENABLE([aligned],
|
|
||||||
AS_HELP_STRING([--enable-aligned],
|
|
||||||
[Force aligned memory operations in non-dsp code
|
|
||||||
(may be slower)]))
|
|
||||||
if test "$enable_aligned" = "yes"; then
|
|
||||||
AC_DEFINE(WEBP_FORCE_ALIGNED, [1],
|
|
||||||
[Define to 1 to force aligned memory operations])
|
|
||||||
fi
|
|
||||||
AC_MSG_RESULT(${enable_aligned-no})
|
|
||||||
|
|
||||||
dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP
|
dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP
|
||||||
|
|
||||||
USE_SWAP_16BIT_CSP=""
|
USE_SWAP_16BIT_CSP=""
|
||||||
@@ -672,13 +676,12 @@ dnl =========================
|
|||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AC_CONFIG_HEADERS([src/webp/config.h])
|
AC_CONFIG_HEADERS([src/webp/config.h])
|
||||||
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
|
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
|
||||||
examples/Makefile src/dec/Makefile \
|
examples/Makefile extras/Makefile imageio/Makefile \
|
||||||
src/enc/Makefile src/dsp/Makefile \
|
src/dec/Makefile src/enc/Makefile src/dsp/Makefile \
|
||||||
src/demux/Makefile src/mux/Makefile \
|
src/demux/Makefile src/mux/Makefile \
|
||||||
src/utils/Makefile src/extras/Makefile \
|
src/utils/Makefile \
|
||||||
src/libwebp.pc src/libwebpdecoder.pc \
|
src/libwebp.pc src/libwebpdecoder.pc \
|
||||||
src/demux/libwebpdemux.pc src/mux/libwebpmux.pc \
|
src/demux/libwebpdemux.pc src/mux/libwebpmux.pc])
|
||||||
src/extras/libwebpextras.pc])
|
|
||||||
|
|
||||||
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
@@ -712,6 +715,7 @@ dwebp : yes
|
|||||||
GIF support : ${gif_support-no}
|
GIF support : ${gif_support-no}
|
||||||
anim_diff : ${build_animdiff-no}
|
anim_diff : ${build_animdiff-no}
|
||||||
gif2webp : ${build_gif2webp-no}
|
gif2webp : ${build_gif2webp-no}
|
||||||
|
img2webp : ${build_img2webp-no}
|
||||||
webpmux : ${enable_libwebpmux-no}
|
webpmux : ${enable_libwebpmux-no}
|
||||||
vwebp : ${build_vwebp-no}
|
vwebp : ${build_vwebp-no}
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -429,6 +429,11 @@ int8 ColorTransformDelta(int8 t, int8 c) {
|
|||||||
}
|
}
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A conversion from the 8-bit unsigned representation (uint8) to the 8-bit
|
||||||
|
signed one (int8) is required before calling ColorTransformDelta().
|
||||||
|
It should be performed using 8-bit two's complement (that is: uint8 range
|
||||||
|
\[128-255\] is mapped to the \[-128, -1\] range of its converted int8 value).
|
||||||
|
|
||||||
The multiplication is to be done using more precision (with at least
|
The multiplication is to be done using more precision (with at least
|
||||||
16-bit dynamics). The sign extension property of the shift operation
|
16-bit dynamics). The sign extension property of the shift operation
|
||||||
does not matter here: only the lowest 8 bits are used from the result,
|
does not matter here: only the lowest 8 bits are used from the result,
|
||||||
|
|||||||
@@ -15,27 +15,6 @@ LOCAL_MODULE := example_util
|
|||||||
|
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# libexample_dec
|
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
|
||||||
image_dec.c \
|
|
||||||
jpegdec.c \
|
|
||||||
metadata.c \
|
|
||||||
pngdec.c \
|
|
||||||
tiffdec.c \
|
|
||||||
webpdec.c \
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
|
||||||
|
|
||||||
LOCAL_MODULE := example_dec
|
|
||||||
|
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# cwebp
|
# cwebp
|
||||||
|
|
||||||
@@ -48,7 +27,7 @@ LOCAL_SRC_FILES := \
|
|||||||
|
|
||||||
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||||
LOCAL_STATIC_LIBRARIES := example_util example_dec webp
|
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webp
|
||||||
|
|
||||||
LOCAL_MODULE := cwebp
|
LOCAL_MODULE := cwebp
|
||||||
|
|
||||||
@@ -64,7 +43,7 @@ LOCAL_SRC_FILES := \
|
|||||||
|
|
||||||
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||||
LOCAL_STATIC_LIBRARIES := example_util webp
|
LOCAL_STATIC_LIBRARIES := example_util imagedec imageenc webp
|
||||||
|
|
||||||
LOCAL_MODULE := dwebp
|
LOCAL_MODULE := dwebp
|
||||||
|
|
||||||
@@ -80,8 +59,24 @@ LOCAL_SRC_FILES := \
|
|||||||
|
|
||||||
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||||
LOCAL_STATIC_LIBRARIES := example_util webpmux webp
|
LOCAL_STATIC_LIBRARIES := example_util imageio_util webpmux webp
|
||||||
|
|
||||||
LOCAL_MODULE := webpmux_example
|
LOCAL_MODULE := webpmux_example
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# img2webp
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
img2webp.c \
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||||
|
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpmux webp
|
||||||
|
|
||||||
|
LOCAL_MODULE := img2webp_example
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|||||||
@@ -1,70 +1,75 @@
|
|||||||
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
|
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
|
||||||
|
|
||||||
bin_PROGRAMS = dwebp cwebp
|
bin_PROGRAMS = dwebp cwebp
|
||||||
if BUILD_VWEBP
|
if BUILD_ANIMDIFF
|
||||||
bin_PROGRAMS += vwebp
|
noinst_PROGRAMS = anim_diff
|
||||||
|
endif
|
||||||
|
if BUILD_GIF2WEBP
|
||||||
|
bin_PROGRAMS += gif2webp
|
||||||
|
endif
|
||||||
|
if BUILD_IMG2WEBP
|
||||||
|
bin_PROGRAMS += img2webp
|
||||||
endif
|
endif
|
||||||
if WANT_MUX
|
if WANT_MUX
|
||||||
bin_PROGRAMS += webpmux
|
bin_PROGRAMS += webpmux
|
||||||
endif
|
endif
|
||||||
|
if BUILD_VWEBP
|
||||||
if BUILD_GIF2WEBP
|
bin_PROGRAMS += vwebp
|
||||||
bin_PROGRAMS += gif2webp
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libexampleutil.la libexampledec.la
|
noinst_LTLIBRARIES = libexample_util.la
|
||||||
|
|
||||||
libexampleutil_la_SOURCES = example_util.c example_util.h stopwatch.h
|
libexample_util_la_SOURCES = example_util.c example_util.h
|
||||||
|
libexample_util_la_LIBADD = ../src/libwebp.la
|
||||||
libexampledec_la_SOURCES = image_dec.c image_dec.h
|
|
||||||
libexampledec_la_SOURCES += jpegdec.c jpegdec.h
|
|
||||||
libexampledec_la_SOURCES += metadata.c metadata.h
|
|
||||||
libexampledec_la_SOURCES += pngdec.c pngdec.h
|
|
||||||
libexampledec_la_SOURCES += tiffdec.c tiffdec.h
|
|
||||||
libexampledec_la_SOURCES += webpdec.c webpdec.h
|
|
||||||
libexampledec_la_SOURCES += wicdec.c wicdec.h
|
|
||||||
libexampledec_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
|
|
||||||
libexampledec_la_CPPFLAGS += $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
|
||||||
|
|
||||||
if BUILD_ANIMDIFF
|
|
||||||
noinst_PROGRAMS = anim_diff
|
|
||||||
endif
|
|
||||||
|
|
||||||
anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h
|
anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h
|
||||||
anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
|
anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
|
||||||
anim_diff_LDADD = ../src/demux/libwebpdemux.la
|
anim_diff_LDADD = ../src/demux/libwebpdemux.la
|
||||||
anim_diff_LDADD += libexampleutil.la
|
anim_diff_LDADD += libexample_util.la ../imageio/libimageio_util.la
|
||||||
anim_diff_LDADD += $(GIF_LIBS) -lm
|
anim_diff_LDADD += $(GIF_LIBS) -lm
|
||||||
|
|
||||||
|
cwebp_SOURCES = cwebp.c stopwatch.h
|
||||||
|
cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||||
|
cwebp_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||||
|
cwebp_LDADD += ../imageio/libimagedec.la ../src/libwebp.la
|
||||||
|
cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS)
|
||||||
|
|
||||||
dwebp_SOURCES = dwebp.c stopwatch.h
|
dwebp_SOURCES = dwebp.c stopwatch.h
|
||||||
dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||||
dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES)
|
dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES)
|
||||||
dwebp_LDADD = libexampleutil.la $(PNG_LIBS) $(JPEG_LIBS)
|
dwebp_LDADD = libexample_util.la
|
||||||
|
dwebp_LDADD += ../imageio/libimagedec.la
|
||||||
cwebp_SOURCES = cwebp.c stopwatch.h
|
dwebp_LDADD += ../imageio/libimageenc.la
|
||||||
cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
dwebp_LDADD += ../imageio/libimageio_util.la
|
||||||
cwebp_LDADD = libexampleutil.la libexampledec.la ../src/libwebp.la
|
dwebp_LDADD += ../src/libwebp.la
|
||||||
cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS)
|
dwebp_LDADD +=$(PNG_LIBS) $(JPEG_LIBS)
|
||||||
|
|
||||||
gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h
|
gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h
|
||||||
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
|
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
|
||||||
gif2webp_LDADD = libexampleutil.la ../src/mux/libwebpmux.la ../src/libwebp.la
|
gif2webp_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||||
gif2webp_LDADD += $(GIF_LIBS)
|
gif2webp_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la $(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_SOURCES = vwebp.c
|
||||||
vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GL_INCLUDES)
|
vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GL_INCLUDES)
|
||||||
vwebp_LDADD = libexampleutil.la ../src/demux/libwebpdemux.la $(GL_LIBS)
|
vwebp_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||||
|
vwebp_LDADD += ../src/demux/libwebpdemux.la $(GL_LIBS)
|
||||||
|
|
||||||
|
webpmux_SOURCES = webpmux.c
|
||||||
|
webpmux_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||||
|
webpmux_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||||
|
webpmux_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la
|
||||||
|
|
||||||
|
img2webp_SOURCES = img2webp.c
|
||||||
|
img2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||||
|
img2webp_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||||
|
img2webp_LDADD += ../imageio/libimagedec.la
|
||||||
|
img2webp_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la
|
||||||
|
img2webp_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
|
||||||
|
|
||||||
if BUILD_LIBWEBPDECODER
|
if BUILD_LIBWEBPDECODER
|
||||||
anim_diff_LDADD += ../src/libwebpdecoder.la
|
anim_diff_LDADD += ../src/libwebpdecoder.la
|
||||||
dwebp_LDADD += ../src/libwebpdecoder.la
|
|
||||||
vwebp_LDADD += ../src/libwebpdecoder.la
|
vwebp_LDADD += ../src/libwebpdecoder.la
|
||||||
else
|
else
|
||||||
anim_diff_LDADD += ../src/libwebp.la
|
anim_diff_LDADD += ../src/libwebp.la
|
||||||
dwebp_LDADD += ../src/libwebp.la
|
|
||||||
vwebp_LDADD += ../src/libwebp.la
|
vwebp_LDADD += ../src/libwebp.la
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -110,6 +110,20 @@ static int CompareValues(uint32_t a, uint32_t b, const char* output_str) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CompareBackgroundColor(uint32_t bg1, uint32_t bg2, int premultiply) {
|
||||||
|
if (premultiply) {
|
||||||
|
const int alpha1 = (bg1 >> 24) & 0xff;
|
||||||
|
const int alpha2 = (bg2 >> 24) & 0xff;
|
||||||
|
if (alpha1 == 0 && alpha2 == 0) return 1;
|
||||||
|
}
|
||||||
|
if (bg1 != bg2) {
|
||||||
|
fprintf(stderr, "Background color mismatch: 0x%08x vs 0x%08x\n",
|
||||||
|
bg1, bg2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Note: As long as frame durations and reconstructed frames are identical, it
|
// Note: As long as frame durations and reconstructed frames are identical, it
|
||||||
// is OK for other aspects like offsets, dispose/blend method to vary.
|
// is OK for other aspects like offsets, dispose/blend method to vary.
|
||||||
static int CompareAnimatedImagePair(const AnimatedImage* const img1,
|
static int CompareAnimatedImagePair(const AnimatedImage* const img1,
|
||||||
@@ -131,8 +145,8 @@ static int CompareAnimatedImagePair(const AnimatedImage* const img1,
|
|||||||
if (is_multi_frame_image) { // Checks relevant for multi-frame images only.
|
if (is_multi_frame_image) { // Checks relevant for multi-frame images only.
|
||||||
ok = CompareValues(img1->loop_count, img2->loop_count,
|
ok = CompareValues(img1->loop_count, img2->loop_count,
|
||||||
"Loop count mismatch") && ok;
|
"Loop count mismatch") && ok;
|
||||||
ok = CompareValues(img1->bgcolor, img2->bgcolor,
|
ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor,
|
||||||
"Background color mismatch") && ok;
|
premultiply) && ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < img1->num_frames; ++i) {
|
for (i = 0; i < img1->num_frames; ++i) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
#include "webp/format_constants.h"
|
#include "webp/format_constants.h"
|
||||||
#include "webp/decode.h"
|
#include "webp/decode.h"
|
||||||
#include "webp/demux.h"
|
#include "webp/demux.h"
|
||||||
#include "./example_util.h"
|
#include "../imageio/imageio_util.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@@ -39,13 +39,24 @@ static int IsFullFrame(int width, int height,
|
|||||||
return (width == canvas_width && height == canvas_height);
|
return (width == canvas_width && height == canvas_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CheckSizeForOverflow(uint64_t size) {
|
||||||
|
return (size == (size_t)size);
|
||||||
|
}
|
||||||
|
|
||||||
static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) {
|
static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
const size_t rgba_size =
|
uint8_t* mem = NULL;
|
||||||
image->canvas_width * kNumChannels * image->canvas_height;
|
DecodedFrame* frames = NULL;
|
||||||
uint8_t* const mem = (uint8_t*)malloc(num_frames * rgba_size * sizeof(*mem));
|
const uint64_t rgba_size =
|
||||||
DecodedFrame* const frames =
|
(uint64_t)image->canvas_width * kNumChannels * image->canvas_height;
|
||||||
(DecodedFrame*)malloc(num_frames * sizeof(*frames));
|
const uint64_t total_size = (uint64_t)num_frames * rgba_size * sizeof(*mem);
|
||||||
|
const uint64_t total_frame_size = (uint64_t)num_frames * sizeof(*frames);
|
||||||
|
if (!CheckSizeForOverflow(total_size) ||
|
||||||
|
!CheckSizeForOverflow(total_frame_size)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
mem = (uint8_t*)malloc((size_t)total_size);
|
||||||
|
frames = (DecodedFrame*)malloc((size_t)total_frame_size);
|
||||||
|
|
||||||
if (mem == NULL || frames == NULL) {
|
if (mem == NULL || frames == NULL) {
|
||||||
free(mem);
|
free(mem);
|
||||||
@@ -139,6 +150,7 @@ static int DumpFrame(const char filename[], const char dump_folder[],
|
|||||||
const char* base_name = NULL;
|
const char* base_name = NULL;
|
||||||
char* file_name = NULL;
|
char* file_name = NULL;
|
||||||
FILE* f = NULL;
|
FILE* f = NULL;
|
||||||
|
const char* row;
|
||||||
|
|
||||||
base_name = strrchr(filename, '/');
|
base_name = strrchr(filename, '/');
|
||||||
base_name = (base_name == NULL) ? filename : base_name + 1;
|
base_name = (base_name == NULL) ? filename : base_name + 1;
|
||||||
@@ -165,12 +177,13 @@ static int DumpFrame(const char filename[], const char dump_folder[],
|
|||||||
fprintf(stderr, "Write error for file %s\n", file_name);
|
fprintf(stderr, "Write error for file %s\n", file_name);
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
row = (const char*)rgba;
|
||||||
for (y = 0; y < canvas_height; ++y) {
|
for (y = 0; y < canvas_height; ++y) {
|
||||||
if (fwrite((const char*)(rgba) + y * canvas_width * kNumChannels,
|
if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) {
|
||||||
canvas_width * kNumChannels, 1, f) != 1) {
|
|
||||||
fprintf(stderr, "Error writing to file: %s\n", file_name);
|
fprintf(stderr, "Error writing to file: %s\n", file_name);
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
row += canvas_width * kNumChannels;
|
||||||
}
|
}
|
||||||
ok = 1;
|
ok = 1;
|
||||||
End:
|
End:
|
||||||
@@ -265,6 +278,8 @@ static int ReadAnimatedWebP(const char filename[],
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// GIF Decoding.
|
// GIF Decoding.
|
||||||
|
|
||||||
|
#ifdef WEBP_HAVE_GIF
|
||||||
|
|
||||||
// Returns true if this is a valid GIF bitstream.
|
// Returns true if this is a valid GIF bitstream.
|
||||||
static int IsGIF(const WebPData* const data) {
|
static int IsGIF(const WebPData* const data) {
|
||||||
return data->size > GIF_STAMP_LEN &&
|
return data->size > GIF_STAMP_LEN &&
|
||||||
@@ -273,8 +288,6 @@ static int IsGIF(const WebPData* const data) {
|
|||||||
!memcmp(GIF89_STAMP, data->bytes, GIF_STAMP_LEN));
|
!memcmp(GIF89_STAMP, data->bytes, GIF_STAMP_LEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WEBP_HAVE_GIF
|
|
||||||
|
|
||||||
// GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
|
// GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
|
||||||
#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR)
|
#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR)
|
||||||
# define LOCAL_GIF_VERSION ((GIFLIB_MAJOR << 8) | GIFLIB_MINOR)
|
# define LOCAL_GIF_VERSION ((GIFLIB_MAJOR << 8) | GIFLIB_MINOR)
|
||||||
@@ -396,7 +409,7 @@ static uint32_t GetBackgroundColorGIF(GifFileType* gif) {
|
|||||||
const ColorMapObject* const color_map = gif->SColorMap;
|
const ColorMapObject* const color_map = gif->SColorMap;
|
||||||
if (transparent_index != NO_TRANSPARENT_COLOR &&
|
if (transparent_index != NO_TRANSPARENT_COLOR &&
|
||||||
gif->SBackGroundColor == transparent_index) {
|
gif->SBackGroundColor == transparent_index) {
|
||||||
return 0x00ffffff; // Special case: transparent white.
|
return 0x00000000; // Special case: transparent black.
|
||||||
} else if (color_map == NULL || color_map->Colors == NULL
|
} else if (color_map == NULL || color_map->Colors == NULL
|
||||||
|| gif->SBackGroundColor >= color_map->ColorCount) {
|
|| gif->SBackGroundColor >= color_map->ColorCount) {
|
||||||
return 0xffffffff; // Invalid: assume white.
|
return 0xffffffff; // Invalid: assume white.
|
||||||
@@ -665,6 +678,11 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
static int IsGIF(const WebPData* const data) {
|
||||||
|
(void)data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
||||||
int dump_frames, const char dump_folder[]) {
|
int dump_frames, const char dump_folder[]) {
|
||||||
(void)filename;
|
(void)filename;
|
||||||
@@ -688,7 +706,7 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
|
|||||||
WebPDataInit(&webp_data);
|
WebPDataInit(&webp_data);
|
||||||
memset(image, 0, sizeof(*image));
|
memset(image, 0, sizeof(*image));
|
||||||
|
|
||||||
if (!ExUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) {
|
if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) {
|
||||||
fprintf(stderr, "Error reading file: %s\n", filename);
|
fprintf(stderr, "Error reading file: %s\n", filename);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -727,7 +745,7 @@ void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
|
|||||||
for (y = 0; y < height; ++y) {
|
for (y = 0; y < height; ++y) {
|
||||||
for (x = 0; x < stride; x += kNumChannels) {
|
for (x = 0; x < stride; x += kNumChannels) {
|
||||||
int k;
|
int k;
|
||||||
const size_t offset = y * stride + x;
|
const size_t offset = (size_t)y * stride + x;
|
||||||
const int alpha1 = rgba1[offset + kAlphaChannel];
|
const int alpha1 = rgba1[offset + kAlphaChannel];
|
||||||
const int alpha2 = rgba2[offset + kAlphaChannel];
|
const int alpha2 = rgba2[offset + kAlphaChannel];
|
||||||
Accumulate(alpha1, alpha2, &f_max_diff, &sse);
|
Accumulate(alpha1, alpha2, &f_max_diff, &sse);
|
||||||
|
|||||||
110
examples/cwebp.c
110
examples/cwebp.c
@@ -20,8 +20,9 @@
|
|||||||
#include "webp/config.h"
|
#include "webp/config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "./example_util.h"
|
#include "../examples/example_util.h"
|
||||||
#include "./image_dec.h"
|
#include "../imageio/image_dec.h"
|
||||||
|
#include "../imageio/imageio_util.h"
|
||||||
#include "./stopwatch.h"
|
#include "./stopwatch.h"
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
|
|
||||||
@@ -59,11 +60,11 @@ static int ReadYUV(const uint8_t* const data, size_t data_size,
|
|||||||
|
|
||||||
pic->use_argb = 0;
|
pic->use_argb = 0;
|
||||||
if (!WebPPictureAlloc(pic)) return 0;
|
if (!WebPPictureAlloc(pic)) return 0;
|
||||||
ExUtilCopyPlane(data, pic->width, pic->y, pic->y_stride,
|
ImgIoUtilCopyPlane(data, pic->width, pic->y, pic->y_stride,
|
||||||
pic->width, pic->height);
|
pic->width, pic->height);
|
||||||
ExUtilCopyPlane(data + y_plane_size, uv_width,
|
ImgIoUtilCopyPlane(data + y_plane_size, uv_width,
|
||||||
pic->u, pic->uv_stride, uv_width, uv_height);
|
pic->u, pic->uv_stride, uv_width, uv_height);
|
||||||
ExUtilCopyPlane(data + y_plane_size + uv_plane_size, uv_width,
|
ImgIoUtilCopyPlane(data + y_plane_size + uv_plane_size, uv_width,
|
||||||
pic->v, pic->uv_stride, uv_width, uv_height);
|
pic->v, pic->uv_stride, uv_width, uv_height);
|
||||||
return use_argb ? WebPPictureYUVAToARGB(pic) : 1;
|
return use_argb ? WebPPictureYUVAToARGB(pic) : 1;
|
||||||
}
|
}
|
||||||
@@ -76,13 +77,13 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
|||||||
const uint8_t* data = NULL;
|
const uint8_t* data = NULL;
|
||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
if (pic->width != 0 && pic->height != 0) {
|
if (pic->width != 0 && pic->height != 0) {
|
||||||
ok = ExUtilReadFile(filename, &data, &data_size);
|
ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||||
ok = ok && ReadYUV(data, data_size, pic);
|
ok = ok && ReadYUV(data, data_size, pic);
|
||||||
} else {
|
} else {
|
||||||
// If no size specified, try to decode it using WIC.
|
// If no size specified, try to decode it using WIC.
|
||||||
ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata);
|
ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
ok = ExUtilReadFile(filename, &data, &data_size);
|
ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||||
ok = ok && ReadWebP(data, data_size, pic, keep_alpha, metadata);
|
ok = ok && ReadWebP(data, data_size, pic, keep_alpha, metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,12 +102,12 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
|||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
||||||
ok = ExUtilReadFile(filename, &data, &data_size);
|
ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||||
if (!ok) goto End;
|
if (!ok) goto End;
|
||||||
|
|
||||||
if (pic->width == 0 || pic->height == 0) {
|
if (pic->width == 0 || pic->height == 0) {
|
||||||
WebPImageReader reader = WebPGuessImageReader(data, data_size);
|
WebPImageReader reader = WebPGuessImageReader(data, data_size);
|
||||||
ok = (reader != NULL) && reader(data, data_size, pic, keep_alpha, metadata);
|
ok = reader(data, data_size, pic, keep_alpha, metadata);
|
||||||
} else {
|
} else {
|
||||||
// If image size is specified, infer it as YUV format.
|
// If image size is specified, infer it as YUV format.
|
||||||
ok = ReadYUV(data, data_size, pic);
|
ok = ReadYUV(data, data_size, pic);
|
||||||
@@ -296,6 +297,10 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
|
|||||||
const int uv_width = (picture->width + 1) / 2;
|
const int uv_width = (picture->width + 1) / 2;
|
||||||
const int uv_height = (picture->height + 1) / 2;
|
const int uv_height = (picture->height + 1) / 2;
|
||||||
const int stride = (picture->width + 1) & ~1;
|
const int stride = (picture->width + 1) & ~1;
|
||||||
|
const uint8_t* src_y = picture->y;
|
||||||
|
const uint8_t* src_u = picture->u;
|
||||||
|
const uint8_t* src_v = picture->v;
|
||||||
|
const uint8_t* src_a = picture->a;
|
||||||
const int alpha_height =
|
const int alpha_height =
|
||||||
WebPPictureHasTransparency(picture) ? picture->height : 0;
|
WebPPictureHasTransparency(picture) ? picture->height : 0;
|
||||||
const int height = picture->height + uv_height + alpha_height;
|
const int height = picture->height + uv_height + alpha_height;
|
||||||
@@ -303,20 +308,20 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
|
|||||||
if (f == NULL) return 0;
|
if (f == NULL) return 0;
|
||||||
fprintf(f, "P5\n%d %d\n255\n", stride, height);
|
fprintf(f, "P5\n%d %d\n255\n", stride, height);
|
||||||
for (y = 0; y < picture->height; ++y) {
|
for (y = 0; y < picture->height; ++y) {
|
||||||
if (fwrite(picture->y + y * picture->y_stride, picture->width, 1, f) != 1)
|
if (fwrite(src_y, picture->width, 1, f) != 1) return 0;
|
||||||
return 0;
|
|
||||||
if (picture->width & 1) fputc(0, f); // pad
|
if (picture->width & 1) fputc(0, f); // pad
|
||||||
|
src_y += picture->y_stride;
|
||||||
}
|
}
|
||||||
for (y = 0; y < uv_height; ++y) {
|
for (y = 0; y < uv_height; ++y) {
|
||||||
if (fwrite(picture->u + y * picture->uv_stride, uv_width, 1, f) != 1)
|
if (fwrite(src_u, uv_width, 1, f) != 1) return 0;
|
||||||
return 0;
|
if (fwrite(src_v, uv_width, 1, f) != 1) return 0;
|
||||||
if (fwrite(picture->v + y * picture->uv_stride, uv_width, 1, f) != 1)
|
src_u += picture->uv_stride;
|
||||||
return 0;
|
src_v += picture->uv_stride;
|
||||||
}
|
}
|
||||||
for (y = 0; y < alpha_height; ++y) {
|
for (y = 0; y < alpha_height; ++y) {
|
||||||
if (fwrite(picture->a + y * picture->a_stride, picture->width, 1, f) != 1)
|
if (fwrite(src_a, picture->width, 1, f) != 1) return 0;
|
||||||
return 0;
|
|
||||||
if (picture->width & 1) fputc(0, f); // pad
|
if (picture->width & 1) fputc(0, f); // pad
|
||||||
|
src_a += picture->a_stride;
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -516,9 +521,10 @@ static void HelpLong(void) {
|
|||||||
printf("\nOptions:\n");
|
printf("\nOptions:\n");
|
||||||
printf(" -h / -help ............. short help\n");
|
printf(" -h / -help ............. short help\n");
|
||||||
printf(" -H / -longhelp ......... long help\n");
|
printf(" -H / -longhelp ......... long help\n");
|
||||||
printf(" -q <float> ............. quality factor (0:small..100:big)\n");
|
printf(" -q <float> ............. quality factor (0:small..100:big), "
|
||||||
printf(" -alpha_q <int> ......... transparency-compression quality "
|
"default=75\n");
|
||||||
"(0..100)\n");
|
printf(" -alpha_q <int> ......... transparency-compression quality (0..100),"
|
||||||
|
"\n default=100\n");
|
||||||
printf(" -preset <string> ....... preset setting, one of:\n");
|
printf(" -preset <string> ....... preset setting, one of:\n");
|
||||||
printf(" default, photo, picture,\n");
|
printf(" default, photo, picture,\n");
|
||||||
printf(" drawing, icon, text\n");
|
printf(" drawing, icon, text\n");
|
||||||
@@ -526,19 +532,25 @@ static void HelpLong(void) {
|
|||||||
printf(" -z <int> ............... activates lossless preset with given\n"
|
printf(" -z <int> ............... activates lossless preset with given\n"
|
||||||
" level in [0:fast, ..., 9:slowest]\n");
|
" level in [0:fast, ..., 9:slowest]\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n");
|
printf(" -m <int> ............... compression method (0=fast, 6=slowest), "
|
||||||
printf(" -segments <int> ........ number of segments to use (1..4)\n");
|
"default=4\n");
|
||||||
|
printf(" -segments <int> ........ number of segments to use (1..4), "
|
||||||
|
"default=4\n");
|
||||||
printf(" -size <int> ............ target size (in bytes)\n");
|
printf(" -size <int> ............ target size (in bytes)\n");
|
||||||
printf(" -psnr <float> .......... target PSNR (in dB. typically: 42)\n");
|
printf(" -psnr <float> .......... target PSNR (in dB. typically: 42)\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" -s <int> <int> ......... input size (width x height) for YUV\n");
|
printf(" -s <int> <int> ......... input size (width x height) for YUV\n");
|
||||||
printf(" -sns <int> ............. spatial noise shaping (0:off, 100:max)\n");
|
printf(" -sns <int> ............. spatial noise shaping (0:off, 100:max), "
|
||||||
printf(" -f <int> ............... filter strength (0=off..100)\n");
|
"default=50\n");
|
||||||
|
printf(" -f <int> ............... filter strength (0=off..100), "
|
||||||
|
"default=60\n");
|
||||||
printf(" -sharpness <int> ....... "
|
printf(" -sharpness <int> ....... "
|
||||||
"filter sharpness (0:most .. 7:least sharp)\n");
|
"filter sharpness (0:most .. 7:least sharp), default=0\n");
|
||||||
printf(" -strong ................ use strong filter instead "
|
printf(" -strong ................ use strong filter instead "
|
||||||
"of simple (default)\n");
|
"of simple (default)\n");
|
||||||
printf(" -nostrong .............. use simple filter instead of strong\n");
|
printf(" -nostrong .............. use simple filter instead of strong\n");
|
||||||
|
printf(" -sharp_yuv ............. use sharper (and slower) RGB->YUV "
|
||||||
|
"conversion\n");
|
||||||
printf(" -partition_limit <int> . limit quality to fit the 512k limit on\n");
|
printf(" -partition_limit <int> . limit quality to fit the 512k limit on\n");
|
||||||
printf(" "
|
printf(" "
|
||||||
"the first partition (0=no degradation ... 100=full)\n");
|
"the first partition (0=no degradation ... 100=full)\n");
|
||||||
@@ -552,21 +564,23 @@ static void HelpLong(void) {
|
|||||||
printf(" -print_ssim ............ prints averaged SSIM distortion\n");
|
printf(" -print_ssim ............ prints averaged SSIM distortion\n");
|
||||||
printf(" -print_lsim ............ prints local-similarity distortion\n");
|
printf(" -print_lsim ............ prints local-similarity distortion\n");
|
||||||
printf(" -d <file.pgm> .......... dump the compressed output (PGM file)\n");
|
printf(" -d <file.pgm> .......... dump the compressed output (PGM file)\n");
|
||||||
printf(" -alpha_method <int> .... transparency-compression method (0..1)\n");
|
printf(" -alpha_method <int> .... transparency-compression method (0..1), "
|
||||||
|
"default=1\n");
|
||||||
printf(" -alpha_filter <string> . predictive filtering for alpha plane,\n");
|
printf(" -alpha_filter <string> . predictive filtering for alpha plane,\n");
|
||||||
printf(" one of: none, fast (default) or best\n");
|
printf(" one of: none, fast (default) or best\n");
|
||||||
printf(" -exact ................. preserve RGB values in transparent area"
|
printf(" -exact ................. preserve RGB values in transparent area, "
|
||||||
"\n");
|
"default=off\n");
|
||||||
printf(" -blend_alpha <hex> ..... blend colors against background color\n"
|
printf(" -blend_alpha <hex> ..... blend colors against background color\n"
|
||||||
" expressed as RGB values written in\n"
|
" expressed as RGB values written in\n"
|
||||||
" hexadecimal, e.g. 0xc0e0d0 for red=0xc0\n"
|
" hexadecimal, e.g. 0xc0e0d0 for red=0xc0\n"
|
||||||
" green=0xe0 and blue=0xd0\n");
|
" green=0xe0 and blue=0xd0\n");
|
||||||
printf(" -noalpha ............... discard any transparency information\n");
|
printf(" -noalpha ............... discard any transparency information\n");
|
||||||
printf(" -lossless .............. encode image losslessly\n");
|
printf(" -lossless .............. encode image losslessly, default=off\n");
|
||||||
printf(" -near_lossless <int> ... use near-lossless image\n"
|
printf(" -near_lossless <int> ... use near-lossless image\n"
|
||||||
" preprocessing (0..100=off)\n");
|
" preprocessing (0..100=off), "
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
"default=100\n");
|
||||||
printf(" -delta_palettization ... use delta palettization\n");
|
#ifdef WEBP_EXPERIMENTAL_FEATURES /* not documented yet */
|
||||||
|
printf(" -delta_palette ......... use delta palettization\n");
|
||||||
#endif // WEBP_EXPERIMENTAL_FEATURES
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
printf(" -hint <string> ......... specify image characteristics hint,\n");
|
printf(" -hint <string> ......... specify image characteristics hint,\n");
|
||||||
printf(" one of: photo, picture or graph\n");
|
printf(" one of: photo, picture or graph\n");
|
||||||
@@ -737,9 +751,9 @@ int main(int argc, const char *argv[]) {
|
|||||||
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
|
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
config.lossless = 1; // use near-lossless only with lossless
|
config.lossless = 1; // use near-lossless only with lossless
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
} else if (!strcmp(argv[c], "-delta_palettization")) {
|
} else if (!strcmp(argv[c], "-delta_palette")) {
|
||||||
config.delta_palettization = 1;
|
config.use_delta_palette = 1;
|
||||||
config.lossless = 1; // use delta-palettization only with lossless
|
config.lossless = 1; // delta-palette is for lossless only
|
||||||
#endif // WEBP_EXPERIMENTAL_FEATURES
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
||||||
} else if (!strcmp(argv[c], "-hint") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-hint") && c < argc - 1) {
|
||||||
++c;
|
++c;
|
||||||
@@ -775,6 +789,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
config.filter_type = 0;
|
config.filter_type = 0;
|
||||||
} else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) {
|
||||||
config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error);
|
config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
|
} else if (!strcmp(argv[c], "-sharp_yuv")) {
|
||||||
|
config.use_sharp_yuv = 1;
|
||||||
} else if (!strcmp(argv[c], "-pass") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-pass") && c < argc - 1) {
|
||||||
config.pass = ExUtilGetInt(argv[++c], 0, &parse_error);
|
config.pass = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
} else if (!strcmp(argv[c], "-pre") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-pre") && c < argc - 1) {
|
||||||
@@ -933,7 +949,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
// Read the input. We need to decide if we prefer ARGB or YUVA
|
// Read the input. We need to decide if we prefer ARGB or YUVA
|
||||||
// samples, depending on the expected compression mode (this saves
|
// samples, depending on the expected compression mode (this saves
|
||||||
// some conversion steps).
|
// some conversion steps).
|
||||||
picture.use_argb = (config.lossless || config.preprocessing > 0 ||
|
picture.use_argb = (config.lossless || config.use_sharp_yuv ||
|
||||||
|
config.preprocessing > 0 ||
|
||||||
crop || (resize_w | resize_h) > 0);
|
crop || (resize_w | resize_h) > 0);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
StopwatchReset(&stop_watch);
|
StopwatchReset(&stop_watch);
|
||||||
@@ -957,7 +974,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
// Open the output
|
// Open the output
|
||||||
if (out_file != NULL) {
|
if (out_file != NULL) {
|
||||||
const int use_stdout = !strcmp(out_file, "-");
|
const int use_stdout = !strcmp(out_file, "-");
|
||||||
out = use_stdout ? ExUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
|
out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
|
||||||
if (out == NULL) {
|
if (out == NULL) {
|
||||||
fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
|
fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
|
||||||
goto Error;
|
goto Error;
|
||||||
@@ -1081,20 +1098,6 @@ int main(int argc, const char *argv[]) {
|
|||||||
if (print_distortion >= 0) { // print distortion
|
if (print_distortion >= 0) { // print distortion
|
||||||
static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" };
|
static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" };
|
||||||
float values[5];
|
float values[5];
|
||||||
if (picture.use_argb != original_picture.use_argb) {
|
|
||||||
// Somehow, the WebPEncode() call converted the original picture.
|
|
||||||
// We need to make both match before calling WebPPictureDistortion().
|
|
||||||
int ok = 0;
|
|
||||||
if (picture.use_argb) {
|
|
||||||
ok = WebPPictureYUVAToARGB(&original_picture);
|
|
||||||
} else {
|
|
||||||
ok = WebPPictureARGBToYUVA(&original_picture, WEBP_YUV420A);
|
|
||||||
}
|
|
||||||
if (!ok) {
|
|
||||||
fprintf(stderr, "Error while converting original picture.\n");
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!WebPPictureDistortion(&picture, &original_picture,
|
if (!WebPPictureDistortion(&picture, &original_picture,
|
||||||
print_distortion, values)) {
|
print_distortion, values)) {
|
||||||
fprintf(stderr, "Error while computing the distortion.\n");
|
fprintf(stderr, "Error while computing the distortion.\n");
|
||||||
@@ -1102,13 +1105,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
if (!short_output) {
|
if (!short_output) {
|
||||||
fprintf(stderr, "%s: ", distortion_names[print_distortion]);
|
fprintf(stderr, "%s: ", distortion_names[print_distortion]);
|
||||||
if (picture.use_argb) {
|
|
||||||
fprintf(stderr, "B:%.2f G:%.2f R:%.2f A:%.2f Total:%.2f\n",
|
fprintf(stderr, "B:%.2f G:%.2f R:%.2f A:%.2f Total:%.2f\n",
|
||||||
values[0], values[1], values[2], values[3], values[4]);
|
values[0], values[1], values[2], values[3], values[4]);
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Y:%.2f U:%.2f V:%.2f A:%.2f Total:%.2f\n",
|
|
||||||
values[0], values[1], values[2], values[3], values[4]);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%7d %.4f\n", picture.stats->coded_size, values[4]);
|
fprintf(stderr, "%7d %.4f\n", picture.stats->coded_size, values[4]);
|
||||||
}
|
}
|
||||||
|
|||||||
519
examples/dwebp.c
519
examples/dwebp.c
@@ -20,27 +20,9 @@
|
|||||||
#include "webp/config.h"
|
#include "webp/config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WEBP_HAVE_PNG
|
#include "../examples/example_util.h"
|
||||||
#include <png.h>
|
#include "../imageio/image_enc.h"
|
||||||
#include <setjmp.h> // note: this must be included *after* png.h
|
#include "../imageio/webpdec.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#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 <ole2.h> // CreateStreamOnHGlobal()
|
|
||||||
#include <shlwapi.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <wincodec.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webp/decode.h"
|
|
||||||
#include "./example_util.h"
|
|
||||||
#include "./stopwatch.h"
|
#include "./stopwatch.h"
|
||||||
|
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
@@ -57,486 +39,18 @@ extern void* VP8GetCPUInfo; // opaque forward declaration.
|
|||||||
#endif
|
#endif
|
||||||
#endif // WEBP_DLL
|
#endif // WEBP_DLL
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Output types
|
|
||||||
typedef enum {
|
|
||||||
PNG = 0,
|
|
||||||
PAM,
|
|
||||||
PPM,
|
|
||||||
PGM,
|
|
||||||
BMP,
|
|
||||||
TIFF,
|
|
||||||
RAW_YUV,
|
|
||||||
ALPHA_PLANE_ONLY, // this is for experimenting only
|
|
||||||
// forced colorspace output (for testing, mostly)
|
|
||||||
RGB, RGBA, BGR, BGRA, ARGB,
|
|
||||||
RGBA_4444, RGB_565,
|
|
||||||
rgbA, bgrA, Argb, rgbA_4444,
|
|
||||||
YUV, YUVA
|
|
||||||
} OutputFileFormat;
|
|
||||||
|
|
||||||
#ifdef HAVE_WINCODEC_H
|
|
||||||
|
|
||||||
#define IFS(fn) \
|
|
||||||
do { \
|
|
||||||
if (SUCCEEDED(hr)) { \
|
|
||||||
hr = (fn); \
|
|
||||||
if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define MAKE_REFGUID(x) (x)
|
|
||||||
#else
|
|
||||||
#define MAKE_REFGUID(x) &(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static HRESULT CreateOutputStream(const char* out_file_name,
|
|
||||||
int write_to_mem, IStream** stream) {
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
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, 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* 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*)&factory));
|
|
||||||
if (hr == REGDB_E_CLASSNOTREG) {
|
|
||||||
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, use_stdout, &stream));
|
|
||||||
IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL,
|
|
||||||
&encoder));
|
|
||||||
IFS(IWICBitmapEncoder_Initialize(encoder, stream,
|
|
||||||
WICBitmapEncoderNoCache));
|
|
||||||
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 (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, int use_stdout,
|
|
||||||
const WebPDecBuffer* const buffer) {
|
|
||||||
const uint32_t width = buffer->width;
|
|
||||||
const uint32_t height = buffer->height;
|
|
||||||
uint8_t* const rgb = buffer->u.RGBA.rgba;
|
|
||||||
const int stride = buffer->u.RGBA.stride;
|
|
||||||
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
|
||||||
|
|
||||||
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 PNGErrorFunction(png_structp png, png_const_charp dummy) {
|
|
||||||
(void)dummy; // remove variable-unused warning
|
|
||||||
longjmp(png_jmpbuf(png), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
|
|
||||||
const uint32_t width = buffer->width;
|
|
||||||
const uint32_t height = buffer->height;
|
|
||||||
uint8_t* const rgb = buffer->u.RGBA.rgba;
|
|
||||||
const int stride = buffer->u.RGBA.stride;
|
|
||||||
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
|
||||||
volatile png_structp png;
|
|
||||||
volatile png_infop info;
|
|
||||||
png_uint_32 y;
|
|
||||||
|
|
||||||
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
|
||||||
NULL, PNGErrorFunction, NULL);
|
|
||||||
if (png == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
info = png_create_info_struct(png);
|
|
||||||
if (info == NULL) {
|
|
||||||
png_destroy_write_struct((png_structpp)&png, NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (setjmp(png_jmpbuf(png))) {
|
|
||||||
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
png_init_io(png, out_file);
|
|
||||||
png_set_IHDR(png, info, width, height, 8,
|
|
||||||
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
|
||||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
|
||||||
PNG_FILTER_TYPE_DEFAULT);
|
|
||||||
png_write_info(png, info);
|
|
||||||
for (y = 0; y < height; ++y) {
|
|
||||||
png_bytep row = rgb + y * stride;
|
|
||||||
png_write_rows(png, &row, 1);
|
|
||||||
}
|
|
||||||
png_write_end(png, info);
|
|
||||||
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#else // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG
|
|
||||||
static int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
|
|
||||||
(void)out_file;
|
|
||||||
(void)buffer;
|
|
||||||
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, int alpha) {
|
|
||||||
const uint32_t width = buffer->width;
|
|
||||||
const uint32_t height = buffer->height;
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (alpha) {
|
|
||||||
fprintf(fout, "P7\nWIDTH %u\nHEIGHT %u\nDEPTH 4\nMAXVAL 255\n"
|
|
||||||
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
|
|
||||||
} else {
|
|
||||||
fprintf(fout, "P6\n%u %u\n255\n", width, height);
|
|
||||||
}
|
|
||||||
for (y = 0; y < height; ++y) {
|
|
||||||
if (fwrite(rgb + y * stride, width, bytes_per_px, fout) != bytes_per_px) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
|
|
||||||
static int Write16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
|
|
||||||
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 = 2;
|
|
||||||
uint32_t y;
|
|
||||||
|
|
||||||
fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height);
|
|
||||||
for (y = 0; y < height; ++y) {
|
|
||||||
if (fwrite(rgba + 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 = WebPIsAlphaMode(buffer->colorspace);
|
|
||||||
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 = WebPIsAlphaMode(buffer->colorspace);
|
|
||||||
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 uint8_t* const a = buffer->u.YUVA.a;
|
|
||||||
const int a_stride = buffer->u.YUVA.a_stride;
|
|
||||||
uint32_t y;
|
|
||||||
assert(a != NULL);
|
|
||||||
fprintf(fout, "P5\n%u %u\n255\n", width, height);
|
|
||||||
for (y = 0; y < height; ++y) {
|
|
||||||
if (fwrite(a + y * a_stride, width, 1, fout) != 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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=RAW_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;
|
|
||||||
int ok = 1;
|
|
||||||
int y;
|
|
||||||
const int pad = (format == RAW_YUV) ? 0 : 1;
|
|
||||||
const int uv_width = (width + 1) / 2;
|
|
||||||
const int uv_height = (height + 1) / 2;
|
|
||||||
const int out_stride = (width + pad) & ~pad;
|
|
||||||
const int a_height = yuv->a ? height : 0;
|
|
||||||
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 (format == PGM) {
|
|
||||||
if (width & 1) fputc(0, fout); // padding byte
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 (format == PGM) {
|
|
||||||
if (width & 1) fputc(0, fout); // padding byte
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int SaveOutput(const WebPDecBuffer* const buffer,
|
static int SaveOutput(const WebPDecBuffer* const buffer,
|
||||||
OutputFileFormat format, const char* const out_file) {
|
WebPOutputFileFormat format, const char* const out_file) {
|
||||||
FILE* fout = NULL;
|
const int use_stdout = (out_file != NULL) && !strcmp(out_file, "-");
|
||||||
int needs_open_file = 1;
|
|
||||||
const int use_stdout = !strcmp(out_file, "-");
|
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
Stopwatch stop_watch;
|
Stopwatch stop_watch;
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
StopwatchReset(&stop_watch);
|
StopwatchReset(&stop_watch);
|
||||||
}
|
}
|
||||||
|
ok = WebPSaveImage(buffer, format, out_file);
|
||||||
|
|
||||||
#ifdef HAVE_WINCODEC_H
|
|
||||||
needs_open_file = (format != PNG);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (needs_open_file) {
|
|
||||||
fout = use_stdout ? ExUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
|
|
||||||
if (fout == NULL) {
|
|
||||||
fprintf(stderr, "Error opening output file %s\n", out_file);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (format == PNG ||
|
|
||||||
format == RGBA || format == BGRA || format == ARGB ||
|
|
||||||
format == rgbA || format == bgrA || format == Argb) {
|
|
||||||
#ifdef HAVE_WINCODEC_H
|
|
||||||
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 || format == RGB || format == BGR) {
|
|
||||||
ok &= WritePPM(fout, buffer, 0);
|
|
||||||
} else if (format == RGBA_4444 || format == RGB_565 || format == rgbA_4444) {
|
|
||||||
ok &= Write16bAsPGM(fout, buffer);
|
|
||||||
} else if (format == BMP) {
|
|
||||||
ok &= WriteBMP(fout, buffer);
|
|
||||||
} else if (format == TIFF) {
|
|
||||||
ok &= WriteTIFF(fout, buffer);
|
|
||||||
} else if (format == PGM || format == RAW_YUV ||
|
|
||||||
format == YUV || format == YUVA) {
|
|
||||||
ok &= WritePGMOrYUV(fout, buffer, format == RAW_YUV ? RAW_YUV : PGM);
|
|
||||||
} else if (format == ALPHA_PLANE_ONLY) {
|
|
||||||
ok &= WriteAlphaPlane(fout, buffer);
|
|
||||||
}
|
|
||||||
if (fout != NULL && fout != stdout) {
|
|
||||||
fclose(fout);
|
|
||||||
}
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
if (use_stdout) {
|
if (use_stdout) {
|
||||||
@@ -598,7 +112,7 @@ static const char* const kFormatType[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
|
static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
|
||||||
OutputFileFormat format,
|
WebPOutputFileFormat format,
|
||||||
int use_external_memory) {
|
int use_external_memory) {
|
||||||
uint8_t* external_buffer = NULL;
|
uint8_t* external_buffer = NULL;
|
||||||
WebPDecBuffer* const output_buffer = &config->output;
|
WebPDecBuffer* const output_buffer = &config->output;
|
||||||
@@ -669,7 +183,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
WebPDecoderConfig config;
|
WebPDecoderConfig config;
|
||||||
WebPDecBuffer* const output_buffer = &config.output;
|
WebPDecBuffer* const output_buffer = &config.output;
|
||||||
WebPBitstreamFeatures* const bitstream = &config.input;
|
WebPBitstreamFeatures* const bitstream = &config.input;
|
||||||
OutputFileFormat format = PNG;
|
WebPOutputFileFormat format = PNG;
|
||||||
uint8_t* external_buffer = NULL;
|
uint8_t* external_buffer = NULL;
|
||||||
int use_external_memory = 0;
|
int use_external_memory = 0;
|
||||||
const uint8_t* data = NULL;
|
const uint8_t* data = NULL;
|
||||||
@@ -797,7 +311,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
{
|
{
|
||||||
VP8StatusCode status = VP8_STATUS_OK;
|
VP8StatusCode status = VP8_STATUS_OK;
|
||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
if (!ExUtilLoadWebP(in_file, &data, &data_size, bitstream)) {
|
if (!LoadWebP(in_file, &data, &data_size, bitstream)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -852,15 +366,24 @@ int main(int argc, const char *argv[]) {
|
|||||||
if (external_buffer == NULL) goto Exit;
|
if (external_buffer == NULL) goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Stopwatch stop_watch;
|
||||||
|
if (verbose) StopwatchReset(&stop_watch);
|
||||||
|
|
||||||
if (incremental) {
|
if (incremental) {
|
||||||
status = ExUtilDecodeWebPIncremental(data, data_size, verbose, &config);
|
status = DecodeWebPIncremental(data, data_size, &config);
|
||||||
} else {
|
} else {
|
||||||
status = ExUtilDecodeWebP(data, data_size, verbose, &config);
|
status = DecodeWebP(data, data_size, &config);
|
||||||
|
}
|
||||||
|
if (verbose) {
|
||||||
|
const double decode_time = StopwatchReadAndReset(&stop_watch);
|
||||||
|
fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = (status == VP8_STATUS_OK);
|
ok = (status == VP8_STATUS_OK);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
ExUtilPrintWebPError(in_file, status);
|
PrintWebPError(in_file, status);
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,17 +12,10 @@
|
|||||||
|
|
||||||
#include "./example_util.h"
|
#include "./example_util.h"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <fcntl.h> // for _O_BINARY
|
|
||||||
#include <io.h> // for _setmode()
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "webp/decode.h"
|
|
||||||
#include "./stopwatch.h"
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// String parsing
|
// String parsing
|
||||||
|
|
||||||
@@ -41,6 +34,18 @@ int ExUtilGetInt(const char* const v, int base, int* const error) {
|
|||||||
return (int)ExUtilGetUInt(v, base, error);
|
return (int)ExUtilGetUInt(v, base, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ExUtilGetInts(const char* v, int base, int max_output, int output[]) {
|
||||||
|
int n, error = 0;
|
||||||
|
for (n = 0; v != NULL && n < max_output; ++n) {
|
||||||
|
const int value = ExUtilGetInt(v, base, &error);
|
||||||
|
if (error) return -1;
|
||||||
|
output[n] = value;
|
||||||
|
v = strchr(v, ',');
|
||||||
|
if (v != NULL) ++v; // skip over the trailing ','
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
float ExUtilGetFloat(const char* const v, int* const error) {
|
float ExUtilGetFloat(const char* const v, int* const error) {
|
||||||
char* end = NULL;
|
char* end = NULL;
|
||||||
const float f = (v != NULL) ? (float)strtod(v, &end) : 0.f;
|
const float f = (v != NULL) ? (float)strtod(v, &end) : 0.f;
|
||||||
@@ -51,231 +56,3 @@ float ExUtilGetFloat(const char* const v, int* const error) {
|
|||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// File I/O
|
|
||||||
|
|
||||||
FILE* ExUtilSetBinaryMode(FILE* file) {
|
|
||||||
#if defined(_WIN32)
|
|
||||||
if (_setmode(_fileno(file), _O_BINARY) == -1) {
|
|
||||||
fprintf(stderr, "Failed to reopen file in O_BINARY mode.\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
|
|
||||||
static const size_t kBlockSize = 16384; // default initial size
|
|
||||||
size_t max_size = 0;
|
|
||||||
size_t size = 0;
|
|
||||||
uint8_t* input = NULL;
|
|
||||||
|
|
||||||
if (data == NULL || data_size == NULL) return 0;
|
|
||||||
*data = NULL;
|
|
||||||
*data_size = 0;
|
|
||||||
|
|
||||||
if (!ExUtilSetBinaryMode(stdin)) return 0;
|
|
||||||
|
|
||||||
while (!feof(stdin)) {
|
|
||||||
// We double the buffer size each time and read as much as possible.
|
|
||||||
const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
|
|
||||||
void* const new_data = realloc(input, max_size + extra_size);
|
|
||||||
if (new_data == NULL) goto Error;
|
|
||||||
input = (uint8_t*)new_data;
|
|
||||||
max_size += extra_size;
|
|
||||||
size += fread(input + size, 1, extra_size, stdin);
|
|
||||||
if (size < max_size) break;
|
|
||||||
}
|
|
||||||
if (ferror(stdin)) goto Error;
|
|
||||||
*data = input;
|
|
||||||
*data_size = size;
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
Error:
|
|
||||||
free(input);
|
|
||||||
fprintf(stderr, "Could not read from stdin\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
|
|
||||||
|
|
||||||
if (from_stdin) return ExUtilReadFromStdin(data, data_size);
|
|
||||||
|
|
||||||
if (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;
|
|
||||||
const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
|
|
||||||
|
|
||||||
if (data == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
out = to_stdout ? stdout : 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);
|
|
||||||
if (out != stdout) fclose(out);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// WebP decoding
|
|
||||||
|
|
||||||
static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
|
|
||||||
"OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
|
|
||||||
"UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
|
|
||||||
};
|
|
||||||
|
|
||||||
static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
|
|
||||||
if (config->input.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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExUtilPrintWebPError(const char* const in_file, int status) {
|
|
||||||
fprintf(stderr, "Decoding of %s failed.\n", in_file);
|
|
||||||
fprintf(stderr, "Status: %d", status);
|
|
||||||
if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
|
|
||||||
fprintf(stderr, "(%s)", kStatusMessages[status]);
|
|
||||||
}
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int ExUtilLoadWebP(const char* const in_file,
|
|
||||||
const uint8_t** data, size_t* data_size,
|
|
||||||
WebPBitstreamFeatures* bitstream) {
|
|
||||||
VP8StatusCode status;
|
|
||||||
WebPBitstreamFeatures local_features;
|
|
||||||
if (!ExUtilReadFile(in_file, data, data_size)) return 0;
|
|
||||||
|
|
||||||
if (bitstream == NULL) {
|
|
||||||
bitstream = &local_features;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = WebPGetFeatures(*data, *data_size, bitstream);
|
|
||||||
if (status != VP8_STATUS_OK) {
|
|
||||||
free((void*)*data);
|
|
||||||
*data = NULL;
|
|
||||||
*data_size = 0;
|
|
||||||
ExUtilPrintWebPError(in_file, status);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
|
|
||||||
int verbose, WebPDecoderConfig* const config) {
|
|
||||||
Stopwatch stop_watch;
|
|
||||||
VP8StatusCode status = VP8_STATUS_OK;
|
|
||||||
if (config == NULL) return VP8_STATUS_INVALID_PARAM;
|
|
||||||
|
|
||||||
PrintAnimationWarning(config);
|
|
||||||
|
|
||||||
StopwatchReset(&stop_watch);
|
|
||||||
|
|
||||||
// Decoding call.
|
|
||||||
status = WebPDecode(data, data_size, config);
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
const double decode_time = StopwatchReadAndReset(&stop_watch);
|
|
||||||
fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
VP8StatusCode ExUtilDecodeWebPIncremental(
|
|
||||||
const uint8_t* const data, size_t data_size,
|
|
||||||
int verbose, WebPDecoderConfig* const config) {
|
|
||||||
Stopwatch stop_watch;
|
|
||||||
VP8StatusCode status = VP8_STATUS_OK;
|
|
||||||
if (config == NULL) return VP8_STATUS_INVALID_PARAM;
|
|
||||||
|
|
||||||
PrintAnimationWarning(config);
|
|
||||||
|
|
||||||
StopwatchReset(&stop_watch);
|
|
||||||
|
|
||||||
// Decoding call.
|
|
||||||
{
|
|
||||||
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
|
|
||||||
if (idec == NULL) {
|
|
||||||
fprintf(stderr, "Failed during WebPINewDecoder().\n");
|
|
||||||
return VP8_STATUS_OUT_OF_MEMORY;
|
|
||||||
} else {
|
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
|
||||||
size_t size = 0;
|
|
||||||
const size_t incr = 2 + (data_size / 20);
|
|
||||||
while (size < data_size) {
|
|
||||||
size_t next_size = size + (rand() % incr);
|
|
||||||
if (next_size > data_size) next_size = data_size;
|
|
||||||
status = WebPIUpdate(idec, data, next_size);
|
|
||||||
if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) break;
|
|
||||||
size = next_size;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
status = WebPIUpdate(idec, data, data_size);
|
|
||||||
#endif
|
|
||||||
WebPIDelete(idec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
const double decode_time = StopwatchReadAndReset(&stop_watch);
|
|
||||||
fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void ExUtilCopyPlane(const uint8_t* src, int src_stride,
|
|
||||||
uint8_t* dst, int dst_stride, int width, int height) {
|
|
||||||
while (height-- > 0) {
|
|
||||||
memcpy(dst, src, width * sizeof(*dst));
|
|
||||||
src += src_stride;
|
|
||||||
dst += dst_stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|||||||
@@ -13,8 +13,7 @@
|
|||||||
#ifndef WEBP_EXAMPLES_EXAMPLE_UTIL_H_
|
#ifndef WEBP_EXAMPLES_EXAMPLE_UTIL_H_
|
||||||
#define WEBP_EXAMPLES_EXAMPLE_UTIL_H_
|
#define WEBP_EXAMPLES_EXAMPLE_UTIL_H_
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "webp/types.h"
|
||||||
#include "webp/decode.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -30,63 +29,11 @@ uint32_t ExUtilGetUInt(const char* const v, int base, int* const error);
|
|||||||
int ExUtilGetInt(const char* const v, int base, int* const error);
|
int ExUtilGetInt(const char* const v, int base, int* const error);
|
||||||
float ExUtilGetFloat(const char* const v, int* const error);
|
float ExUtilGetFloat(const char* const v, int* const error);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
// This variant of ExUtilGetInt() will parse multiple integers from a
|
||||||
// File I/O
|
// comma-separated list. Up to 'max_output' integers are parsed.
|
||||||
|
// The result is placed in the output[] array, and the number of integers
|
||||||
// Reopen file in binary (O_BINARY) mode.
|
// actually parsed is returned, or -1 if an error occurred.
|
||||||
// Returns 'file' on success, NULL otherwise.
|
int ExUtilGetInts(const char* v, int base, int max_output, int output[]);
|
||||||
FILE* ExUtilSetBinaryMode(FILE* file);
|
|
||||||
|
|
||||||
// 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().
|
|
||||||
// If 'file_name' is NULL or equal to "-", input is read from stdin by calling
|
|
||||||
// the function ExUtilReadFromStdin().
|
|
||||||
int ExUtilReadFile(const char* const file_name,
|
|
||||||
const uint8_t** data, size_t* data_size);
|
|
||||||
|
|
||||||
// Same as ExUtilReadFile(), but reads until EOF from stdin instead.
|
|
||||||
int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size);
|
|
||||||
|
|
||||||
// Write a data segment into a file named 'file_name'. Returns true if ok.
|
|
||||||
// If 'file_name' is NULL or equal to "-", output is written to stdout.
|
|
||||||
int ExUtilWriteFile(const char* const file_name,
|
|
||||||
const uint8_t* data, size_t data_size);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Copy width x height pixels from 'src' to 'dst' honoring the strides.
|
|
||||||
void ExUtilCopyPlane(const uint8_t* src, int src_stride,
|
|
||||||
uint8_t* dst, int dst_stride, int width, int height);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// WebP decoding
|
|
||||||
|
|
||||||
// Prints an informative error message regarding decode failure of 'in_file'.
|
|
||||||
// 'status' is treated as a VP8StatusCode and if valid will be printed as a
|
|
||||||
// text string.
|
|
||||||
void ExUtilPrintWebPError(const char* const in_file, int status);
|
|
||||||
|
|
||||||
// Reads a WebP from 'in_file', returning the contents and size in 'data' and
|
|
||||||
// 'data_size'. If not NULL, 'bitstream' is populated using WebPGetFeatures().
|
|
||||||
// Returns true on success.
|
|
||||||
int ExUtilLoadWebP(const char* const in_file,
|
|
||||||
const uint8_t** data, size_t* data_size,
|
|
||||||
WebPBitstreamFeatures* bitstream);
|
|
||||||
|
|
||||||
// Decodes the WebP contained in 'data'.
|
|
||||||
// 'config' is a structure previously initialized by WebPInitDecoderConfig().
|
|
||||||
// 'config->output' should have the desired colorspace selected. 'verbose' will
|
|
||||||
// cause decode timing to be reported.
|
|
||||||
// Returns the decoder status. On success 'config->output' will contain the
|
|
||||||
// decoded picture.
|
|
||||||
VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
|
|
||||||
int verbose, WebPDecoderConfig* const config);
|
|
||||||
|
|
||||||
// Same as ExUtilDecodeWebP(), but using the incremental decoder.
|
|
||||||
VP8StatusCode ExUtilDecodeWebPIncremental(
|
|
||||||
const uint8_t* const data, size_t data_size,
|
|
||||||
int verbose, WebPDecoderConfig* const config);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
#include <gif_lib.h>
|
#include <gif_lib.h>
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
#include "webp/mux.h"
|
#include "webp/mux.h"
|
||||||
#include "./example_util.h"
|
#include "../examples/example_util.h"
|
||||||
|
#include "../imageio/imageio_util.h"
|
||||||
#include "./gifdec.h"
|
#include "./gifdec.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -359,6 +360,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
if (DGifGetExtension(gif, &extension, &data) == GIF_ERROR) {
|
if (DGifGetExtension(gif, &extension, &data) == GIF_ERROR) {
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
if (data == NULL) continue;
|
||||||
|
|
||||||
switch (extension) {
|
switch (extension) {
|
||||||
case COMMENT_EXT_FUNC_CODE: {
|
case COMMENT_EXT_FUNC_CODE: {
|
||||||
break; // Do nothing for now.
|
break; // Do nothing for now.
|
||||||
@@ -499,7 +502,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out_file != NULL) {
|
if (out_file != NULL) {
|
||||||
if (!ExUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) {
|
if (!ImgIoUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) {
|
||||||
fprintf(stderr, "Error writing output file: %s\n", out_file);
|
fprintf(stderr, "Error writing output file: %s\n", out_file);
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
#include "webp/mux_types.h"
|
#include "webp/mux_types.h"
|
||||||
|
|
||||||
#define GIF_TRANSPARENT_COLOR 0x00ffffff
|
#define GIF_TRANSPARENT_COLOR 0x00000000u
|
||||||
#define GIF_WHITE_COLOR 0xffffffff
|
#define GIF_WHITE_COLOR 0xffffffffu
|
||||||
#define GIF_TRANSPARENT_MASK 0x01
|
#define GIF_TRANSPARENT_MASK 0x01
|
||||||
#define GIF_DISPOSE_MASK 0x07
|
#define GIF_DISPOSE_MASK 0x07
|
||||||
#define GIF_DISPOSE_SHIFT 2
|
#define GIF_DISPOSE_SHIFT 2
|
||||||
@@ -48,7 +48,7 @@ void GIFGetBackgroundColor(const ColorMapObject* const color_map,
|
|||||||
"white background.\n");
|
"white background.\n");
|
||||||
} else {
|
} else {
|
||||||
const GifColorType color = color_map->Colors[bgcolor_index];
|
const GifColorType color = color_map->Colors[bgcolor_index];
|
||||||
*bgcolor = (0xff << 24)
|
*bgcolor = (0xffu << 24)
|
||||||
| (color.Red << 16)
|
| (color.Red << 16)
|
||||||
| (color.Green << 8)
|
| (color.Green << 8)
|
||||||
| (color.Blue << 0);
|
| (color.Blue << 0);
|
||||||
@@ -81,20 +81,27 @@ int GIFReadGraphicsExtension(const GifByteType* const buf, int* const duration,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Remap(const GifFileType* const gif, const uint8_t* const src,
|
static int Remap(const GifFileType* const gif, const uint8_t* const src,
|
||||||
int len, int transparent_index, uint32_t* dst) {
|
int len, int transparent_index, uint32_t* dst) {
|
||||||
int i;
|
int i;
|
||||||
const GifColorType* colors;
|
const GifColorType* colors;
|
||||||
const ColorMapObject* const cmap =
|
const ColorMapObject* const cmap =
|
||||||
gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
|
gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
|
||||||
if (cmap == NULL) return;
|
if (cmap == NULL) return 1;
|
||||||
|
if (cmap->Colors == NULL || cmap->ColorCount <= 0) return 0;
|
||||||
colors = cmap->Colors;
|
colors = cmap->Colors;
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
|
if (src[i] == transparent_index) {
|
||||||
|
dst[i] = GIF_TRANSPARENT_COLOR;
|
||||||
|
} else if (src[i] < cmap->ColorCount) {
|
||||||
const GifColorType c = colors[src[i]];
|
const GifColorType c = colors[src[i]];
|
||||||
dst[i] = (src[i] == transparent_index) ? GIF_TRANSPARENT_COLOR
|
dst[i] = c.Blue | (c.Green << 8) | (c.Red << 16) | (0xffu << 24);
|
||||||
: c.Blue | (c.Green << 8) | (c.Red << 16) | (0xff << 24);
|
} else {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GIFReadFrame(GifFileType* const gif, int transparent_index,
|
int GIFReadFrame(GifFileType* const gif, int transparent_index,
|
||||||
@@ -103,12 +110,18 @@ int GIFReadFrame(GifFileType* const gif, int transparent_index,
|
|||||||
const GifImageDesc* const image_desc = &gif->Image;
|
const GifImageDesc* const image_desc = &gif->Image;
|
||||||
uint32_t* dst = NULL;
|
uint32_t* dst = NULL;
|
||||||
uint8_t* tmp = NULL;
|
uint8_t* tmp = NULL;
|
||||||
int ok = 0;
|
const GIFFrameRect rect = {
|
||||||
GIFFrameRect rect = {
|
|
||||||
image_desc->Left, image_desc->Top, image_desc->Width, image_desc->Height
|
image_desc->Left, image_desc->Top, image_desc->Width, image_desc->Height
|
||||||
};
|
};
|
||||||
|
const uint64_t memory_needed = 4 * rect.width * (uint64_t)rect.height;
|
||||||
|
int ok = 0;
|
||||||
*gif_rect = rect;
|
*gif_rect = rect;
|
||||||
|
|
||||||
|
if (memory_needed != (size_t)memory_needed || memory_needed > (4ULL << 32)) {
|
||||||
|
fprintf(stderr, "Image is too large (%d x %d).", rect.width, rect.height);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Use a view for the sub-picture:
|
// Use a view for the sub-picture:
|
||||||
if (!WebPPictureView(picture, rect.x_offset, rect.y_offset,
|
if (!WebPPictureView(picture, rect.x_offset, rect.y_offset,
|
||||||
rect.width, rect.height, &sub_image)) {
|
rect.width, rect.height, &sub_image)) {
|
||||||
@@ -127,20 +140,21 @@ int GIFReadFrame(GifFileType* const gif, int transparent_index,
|
|||||||
const int interlace_jumps[] = { 8, 8, 4, 2 };
|
const int interlace_jumps[] = { 8, 8, 4, 2 };
|
||||||
int pass;
|
int pass;
|
||||||
for (pass = 0; pass < 4; ++pass) {
|
for (pass = 0; pass < 4; ++pass) {
|
||||||
int y;
|
const size_t stride = (size_t)sub_image.argb_stride;
|
||||||
for (y = interlace_offsets[pass]; y < rect.height;
|
int y = interlace_offsets[pass];
|
||||||
y += interlace_jumps[pass]) {
|
uint32_t* row = dst + y * stride;
|
||||||
|
const size_t jump = interlace_jumps[pass] * stride;
|
||||||
|
for (; y < rect.height; y += interlace_jumps[pass], row += jump) {
|
||||||
if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End;
|
if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End;
|
||||||
Remap(gif, tmp, rect.width, transparent_index,
|
if (!Remap(gif, tmp, rect.width, transparent_index, row)) goto End;
|
||||||
dst + y * sub_image.argb_stride);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Non-interlaced image.
|
} else { // Non-interlaced image.
|
||||||
int y;
|
int y;
|
||||||
for (y = 0; y < rect.height; ++y) {
|
uint32_t* ptr = dst;
|
||||||
|
for (y = 0; y < rect.height; ++y, ptr += sub_image.argb_stride) {
|
||||||
if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End;
|
if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End;
|
||||||
Remap(gif, tmp, rect.width, transparent_index,
|
if (!Remap(gif, tmp, rect.width, transparent_index, ptr)) goto End;
|
||||||
dst + y * sub_image.argb_stride);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ok = 1;
|
ok = 1;
|
||||||
@@ -216,13 +230,11 @@ int GIFReadMetadata(GifFileType* const gif, GifByteType** const buf,
|
|||||||
|
|
||||||
static void ClearRectangle(WebPPicture* const picture,
|
static void ClearRectangle(WebPPicture* const picture,
|
||||||
int left, int top, int width, int height) {
|
int left, int top, int width, int height) {
|
||||||
int j;
|
int i, j;
|
||||||
for (j = top; j < top + height; ++j) {
|
const size_t stride = picture->argb_stride;
|
||||||
uint32_t* const dst = picture->argb + j * picture->argb_stride;
|
uint32_t* dst = picture->argb + top * stride + left;
|
||||||
int i;
|
for (j = 0; j < height; ++j, dst += stride) {
|
||||||
for (i = left; i < left + width; ++i) {
|
for (i = 0; i < width; ++i) dst[i] = GIF_TRANSPARENT_COLOR;
|
||||||
dst[i] = GIF_TRANSPARENT_COLOR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,29 +258,31 @@ void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect,
|
|||||||
if (dispose == GIF_DISPOSE_BACKGROUND) {
|
if (dispose == GIF_DISPOSE_BACKGROUND) {
|
||||||
GIFClearPic(curr_canvas, rect);
|
GIFClearPic(curr_canvas, rect);
|
||||||
} else if (dispose == GIF_DISPOSE_RESTORE_PREVIOUS) {
|
} else if (dispose == GIF_DISPOSE_RESTORE_PREVIOUS) {
|
||||||
const int src_stride = prev_canvas->argb_stride;
|
const size_t src_stride = prev_canvas->argb_stride;
|
||||||
const uint32_t* const src =
|
const uint32_t* const src = prev_canvas->argb + rect->x_offset
|
||||||
prev_canvas->argb + rect->x_offset + rect->y_offset * src_stride;
|
+ rect->y_offset * src_stride;
|
||||||
const int dst_stride = curr_canvas->argb_stride;
|
const size_t dst_stride = curr_canvas->argb_stride;
|
||||||
uint32_t* const dst =
|
uint32_t* const dst = curr_canvas->argb + rect->x_offset
|
||||||
curr_canvas->argb + rect->x_offset + rect->y_offset * dst_stride;
|
+ rect->y_offset * dst_stride;
|
||||||
assert(prev_canvas != NULL);
|
assert(prev_canvas != NULL);
|
||||||
WebPCopyPlane((uint8_t*)src, 4 * src_stride, (uint8_t*)dst, 4 * dst_stride,
|
WebPCopyPlane((uint8_t*)src, (int)(4 * src_stride),
|
||||||
|
(uint8_t*)dst, (int)(4 * dst_stride),
|
||||||
4 * rect->width, rect->height);
|
4 * rect->width, rect->height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GIFBlendFrames(const WebPPicture* const src,
|
void GIFBlendFrames(const WebPPicture* const src,
|
||||||
const GIFFrameRect* const rect, WebPPicture* const dst) {
|
const GIFFrameRect* const rect, WebPPicture* const dst) {
|
||||||
int j;
|
int i, j;
|
||||||
|
const size_t src_stride = src->argb_stride;
|
||||||
|
const size_t dst_stride = dst->argb_stride;
|
||||||
assert(src->width == dst->width && src->height == dst->height);
|
assert(src->width == dst->width && src->height == dst->height);
|
||||||
for (j = rect->y_offset; j < rect->y_offset + rect->height; ++j) {
|
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) {
|
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 uint32_t src_pixel = src->argb[j * src_stride + i];
|
||||||
const int src_alpha = src_pixel >> 24;
|
const int src_alpha = src_pixel >> 24;
|
||||||
if (src_alpha != 0) {
|
if (src_alpha != 0) {
|
||||||
dst->argb[j * dst->argb_stride + i] = src_pixel;
|
dst->argb[j * dst_stride + i] = src_pixel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
300
examples/img2webp.c
Normal file
300
examples/img2webp.c
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// generate an animated WebP out of a sequence of images
|
||||||
|
// (PNG, JPEG, ...)
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
// img2webp -o out.webp -q 40 -mixed -duration 40 input??.png
|
||||||
|
//
|
||||||
|
// Author: skal@google.com (Pascal Massimino)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "webp/config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../examples/example_util.h"
|
||||||
|
#include "../imageio/image_dec.h"
|
||||||
|
#include "../imageio/imageio_util.h"
|
||||||
|
#include "./stopwatch.h"
|
||||||
|
#include "webp/encode.h"
|
||||||
|
#include "webp/mux.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void Help(void) {
|
||||||
|
printf("Usage:\n\n");
|
||||||
|
printf(" img2webp [file-level options] [image files...] "
|
||||||
|
"[per-frame options...]\n");
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("File-level options (only used at the start of compression):\n");
|
||||||
|
printf(" -min_size ............ minimize size\n");
|
||||||
|
printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
|
||||||
|
printf(" -kmax <int> .......... maximum number of frame between key-frames\n"
|
||||||
|
" (0=only keyframes)\n");
|
||||||
|
printf(" -kmin <int> .......... minimum number of frame between key-frames\n"
|
||||||
|
" (0=disable key-frames altogether)\n");
|
||||||
|
printf(" -mixed ............... use mixed lossy/lossless automatic mode\n");
|
||||||
|
printf(" -v ................... verbose mode\n");
|
||||||
|
printf(" -h ................... this help\n");
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("Per-frame options (only used for subsequent images input):\n");
|
||||||
|
printf(" -d <int> ............. frame duration in ms (default: 100)\n");
|
||||||
|
printf(" -lossless ........... use lossless mode (default)\n");
|
||||||
|
printf(" -lossy ... ........... use lossy mode\n");
|
||||||
|
printf(" -q <float> ........... quality\n");
|
||||||
|
printf(" -m <int> ............. method to use\n");
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("example: img2webp -loop 2 in0.png -lossy in1.jpg\n"
|
||||||
|
" -d 80 in2.tiff -o out.webp\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int ReadImage(const char filename[], WebPPicture* const pic) {
|
||||||
|
const uint8_t* data = NULL;
|
||||||
|
size_t data_size = 0;
|
||||||
|
WebPImageReader reader;
|
||||||
|
int ok;
|
||||||
|
#ifdef HAVE_WINCODEC_H
|
||||||
|
// Try to decode the file using WIC falling back to the other readers for
|
||||||
|
// e.g., WebP.
|
||||||
|
ok = ReadPictureWithWIC(filename, pic, 1, NULL);
|
||||||
|
if (ok) return 1;
|
||||||
|
#endif
|
||||||
|
if (!ImgIoUtilReadFile(filename, &data, &data_size)) return 0;
|
||||||
|
reader = WebPGuessImageReader(data, data_size);
|
||||||
|
ok = reader(data, data_size, pic, 1, NULL);
|
||||||
|
free((void*)data);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SetLoopCount(int loop_count, WebPData* const webp_data) {
|
||||||
|
int ok = 1;
|
||||||
|
WebPMuxError err;
|
||||||
|
uint32_t features;
|
||||||
|
WebPMuxAnimParams new_params;
|
||||||
|
WebPMux* const mux = WebPMuxCreate(webp_data, 1);
|
||||||
|
if (mux == NULL) return 0;
|
||||||
|
|
||||||
|
err = WebPMuxGetFeatures(mux, &features);
|
||||||
|
ok = (err == WEBP_MUX_OK);
|
||||||
|
if (!ok || !(features & ANIMATION_FLAG)) goto End;
|
||||||
|
|
||||||
|
err = WebPMuxGetAnimationParams(mux, &new_params);
|
||||||
|
ok = (err == WEBP_MUX_OK);
|
||||||
|
if (ok) {
|
||||||
|
new_params.loop_count = loop_count;
|
||||||
|
err = WebPMuxSetAnimationParams(mux, &new_params);
|
||||||
|
ok = (err == WEBP_MUX_OK);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
WebPDataClear(webp_data);
|
||||||
|
err = WebPMuxAssemble(mux, webp_data);
|
||||||
|
ok = (err == WEBP_MUX_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
End:
|
||||||
|
WebPMuxDelete(mux);
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Error during loop-count setting\n");
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
const char* output = NULL;
|
||||||
|
WebPAnimEncoder* enc = NULL;
|
||||||
|
int verbose = 0;
|
||||||
|
int pic_num = 0;
|
||||||
|
int duration = 100;
|
||||||
|
int timestamp_ms = 0;
|
||||||
|
int ok = 1;
|
||||||
|
int loop_count = 0;
|
||||||
|
int width = 0, height = 0;
|
||||||
|
WebPAnimEncoderOptions anim_config;
|
||||||
|
WebPConfig config;
|
||||||
|
WebPPicture pic;
|
||||||
|
WebPData webp_data;
|
||||||
|
int c;
|
||||||
|
int have_input = 0;
|
||||||
|
|
||||||
|
WebPDataInit(&webp_data);
|
||||||
|
if (!WebPAnimEncoderOptionsInit(&anim_config) ||
|
||||||
|
!WebPConfigInit(&config) ||
|
||||||
|
!WebPPictureInit(&pic)) {
|
||||||
|
fprintf(stderr, "Library version mismatch!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1st pass of option parsing
|
||||||
|
for (c = 1; ok && c < argc; ++c) {
|
||||||
|
if (argv[c][0] == '-') {
|
||||||
|
int parse_error = 0;
|
||||||
|
if (!strcmp(argv[c], "-o") && c + 1 < argc) {
|
||||||
|
argv[c] = NULL;
|
||||||
|
output = argv[++c];
|
||||||
|
} else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) {
|
||||||
|
argv[c] = NULL;
|
||||||
|
anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
|
} else if (!strcmp(argv[c], "-kmax") && c + 1 < argc) {
|
||||||
|
argv[c] = NULL;
|
||||||
|
anim_config.kmax = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
|
} else if (!strcmp(argv[c], "-loop") && c + 1 < argc) {
|
||||||
|
argv[c] = NULL;
|
||||||
|
loop_count = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
|
if (loop_count < 0) {
|
||||||
|
fprintf(stderr, "Invalid non-positive loop-count (%d)\n", loop_count);
|
||||||
|
parse_error = 1;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(argv[c], "-min_size")) {
|
||||||
|
anim_config.minimize_size = 1;
|
||||||
|
} else if (!strcmp(argv[c], "-mixed")) {
|
||||||
|
anim_config.allow_mixed = 1;
|
||||||
|
config.lossless = 0;
|
||||||
|
} else if (!strcmp(argv[c], "-v")) {
|
||||||
|
verbose = 1;
|
||||||
|
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
|
Help();
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ok = !parse_error;
|
||||||
|
if (!ok) goto End;
|
||||||
|
argv[c] = NULL; // mark option as 'parsed' during 1st pass
|
||||||
|
} else {
|
||||||
|
have_input |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!have_input) {
|
||||||
|
fprintf(stderr, "No input file(s) for generating animation!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// image-reading pass
|
||||||
|
pic_num = 0;
|
||||||
|
config.lossless = 1;
|
||||||
|
for (c = 1; ok && c < argc; ++c) {
|
||||||
|
if (argv[c] == NULL) continue;
|
||||||
|
if (argv[c][0] == '-') { // parse local options
|
||||||
|
int parse_error = 0;
|
||||||
|
if (!strcmp(argv[c], "-lossy")) {
|
||||||
|
if (!anim_config.allow_mixed) config.lossless = 0;
|
||||||
|
} else if (!strcmp(argv[c], "-lossless")) {
|
||||||
|
if (!anim_config.allow_mixed) config.lossless = 1;
|
||||||
|
} else if (!strcmp(argv[c], "-q") && c + 1 < argc) {
|
||||||
|
config.quality = ExUtilGetFloat(argv[++c], &parse_error);
|
||||||
|
} else if (!strcmp(argv[c], "-m") && c + 1 < argc) {
|
||||||
|
config.method = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
|
} else if (!strcmp(argv[c], "-d") && c + 1 < argc) {
|
||||||
|
duration = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
|
if (duration <= 0) {
|
||||||
|
fprintf(stderr, "Invalid negative duration (%d)\n", duration);
|
||||||
|
parse_error = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parse_error = 1; // shouldn't be here.
|
||||||
|
fprintf(stderr, "Unknown option [%s]\n", argv[c]);
|
||||||
|
}
|
||||||
|
ok = !parse_error;
|
||||||
|
if (!ok) goto End;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
ok = WebPValidateConfig(&config);
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Invalid configuration.\n");
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read next input image
|
||||||
|
pic.use_argb = 1;
|
||||||
|
ok = ReadImage(argv[c], &pic);
|
||||||
|
if (!ok) goto End;
|
||||||
|
|
||||||
|
if (enc == NULL) {
|
||||||
|
width = pic.width;
|
||||||
|
height = pic.height;
|
||||||
|
enc = WebPAnimEncoderNew(width, height, &anim_config);
|
||||||
|
ok = (enc != NULL);
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Could not create WebPAnimEncoder object.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
ok = (width == pic.width && height == pic.height);
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Frame #%d dimension mismatched! "
|
||||||
|
"Got %d x %d. Was expecting %d x %d.\n",
|
||||||
|
pic_num, pic.width, pic.height, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
ok = WebPAnimEncoderAdd(enc, &pic, timestamp_ms, &config);
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Error while adding frame #%d\n", pic_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WebPPictureFree(&pic);
|
||||||
|
if (!ok) goto End;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
fprintf(stderr, "Added frame #%3d at time %4d (file: %s)\n",
|
||||||
|
pic_num, timestamp_ms, argv[c]);
|
||||||
|
}
|
||||||
|
timestamp_ms += duration;
|
||||||
|
++pic_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a last fake frame to signal the last duration
|
||||||
|
ok = ok && WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL);
|
||||||
|
ok = ok && WebPAnimEncoderAssemble(enc, &webp_data);
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Error during final animation assembly.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
End:
|
||||||
|
// free resources
|
||||||
|
WebPAnimEncoderDelete(enc);
|
||||||
|
|
||||||
|
if (ok && loop_count > 0) { // Re-mux to add loop count.
|
||||||
|
ok = SetLoopCount(loop_count, &webp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
if (output != NULL) {
|
||||||
|
ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size);
|
||||||
|
if (ok) fprintf(stderr, "output file: %s ", output);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "[no output file specified] ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
fprintf(stderr, "[%d frames, %u bytes].\n",
|
||||||
|
pic_num, (unsigned int)webp_data.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPDataClear(&webp_data);
|
||||||
|
return ok ? 0 : 1;
|
||||||
|
}
|
||||||
@@ -14,6 +14,10 @@
|
|||||||
#include "webp/config.h"
|
#include "webp/config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__unix__) || defined(__CYGWIN__)
|
||||||
|
#define _POSIX_C_SOURCE 200112L // for setenv
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -36,7 +40,8 @@
|
|||||||
#include "webp/decode.h"
|
#include "webp/decode.h"
|
||||||
#include "webp/demux.h"
|
#include "webp/demux.h"
|
||||||
|
|
||||||
#include "./example_util.h"
|
#include "../examples/example_util.h"
|
||||||
|
#include "../imageio/imageio_util.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@@ -49,6 +54,7 @@ static struct {
|
|||||||
int done;
|
int done;
|
||||||
int decoding_error;
|
int decoding_error;
|
||||||
int print_info;
|
int print_info;
|
||||||
|
int only_deltas;
|
||||||
int use_color_profile;
|
int use_color_profile;
|
||||||
|
|
||||||
int canvas_width, canvas_height;
|
int canvas_width, canvas_height;
|
||||||
@@ -63,6 +69,7 @@ static struct {
|
|||||||
WebPIterator curr_frame;
|
WebPIterator curr_frame;
|
||||||
WebPIterator prev_frame;
|
WebPIterator prev_frame;
|
||||||
WebPChunkIterator iccp;
|
WebPChunkIterator iccp;
|
||||||
|
int viewport_width, viewport_height;
|
||||||
} kParams;
|
} kParams;
|
||||||
|
|
||||||
static void ClearPreviousPic(void) {
|
static void ClearPreviousPic(void) {
|
||||||
@@ -242,18 +249,27 @@ static void HandleKey(unsigned char key, int pos_x, int pos_y) {
|
|||||||
}
|
}
|
||||||
} else if (key == 'i') {
|
} else if (key == 'i') {
|
||||||
kParams.print_info = 1 - kParams.print_info;
|
kParams.print_info = 1 - kParams.print_info;
|
||||||
|
// TODO(skal): handle refresh of animation's last-frame too. It's quite
|
||||||
|
// more involved though (need to save the previous frame).
|
||||||
|
if (!kParams.has_animation) ClearPreviousFrame();
|
||||||
|
glutPostRedisplay();
|
||||||
|
} else if (key == 'd') {
|
||||||
|
kParams.only_deltas = 1 - kParams.only_deltas;
|
||||||
glutPostRedisplay();
|
glutPostRedisplay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleReshape(int width, int height) {
|
static void HandleReshape(int width, int height) {
|
||||||
// TODO(skal): proper handling of resize, esp. for large pictures.
|
// TODO(skal): should we preserve aspect ratio?
|
||||||
// + key control of the zoom.
|
// Also: handle larger-than-screen pictures correctly.
|
||||||
glViewport(0, 0, width, height);
|
glViewport(0, 0, width, height);
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
kParams.viewport_width = width;
|
||||||
|
kParams.viewport_height = height;
|
||||||
|
if (!kParams.has_animation) ClearPreviousFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintString(const char* const text) {
|
static void PrintString(const char* const text) {
|
||||||
@@ -295,17 +311,18 @@ static void HandleDisplay(void) {
|
|||||||
GLfloat xoff, yoff;
|
GLfloat xoff, yoff;
|
||||||
if (pic == NULL) return;
|
if (pic == NULL) return;
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glPixelZoom(1, -1);
|
glPixelZoom((GLfloat)(+1. / kParams.canvas_width * kParams.viewport_width),
|
||||||
|
(GLfloat)(-1. / kParams.canvas_height * kParams.viewport_height));
|
||||||
xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width);
|
xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width);
|
||||||
yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height);
|
yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height);
|
||||||
glRasterPos2f(-1.f + xoff, 1.f - yoff);
|
glRasterPos2f(-1.f + xoff, 1.f - yoff);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
|
||||||
|
|
||||||
if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
|
if (kParams.only_deltas) {
|
||||||
|
DrawCheckerBoard();
|
||||||
|
} else if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
|
||||||
curr->blend_method == WEBP_MUX_NO_BLEND) {
|
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).
|
// glScissor() takes window coordinates (0,0 at bottom left).
|
||||||
int window_x, window_y;
|
int window_x, window_y;
|
||||||
int frame_w, frame_h;
|
int frame_w, frame_h;
|
||||||
@@ -325,6 +342,10 @@ static void HandleDisplay(void) {
|
|||||||
}
|
}
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
// Only update the requested area, not the whole canvas.
|
// Only update the requested area, not the whole canvas.
|
||||||
|
window_x = window_x * kParams.viewport_width / kParams.canvas_width;
|
||||||
|
window_y = window_y * kParams.viewport_height / kParams.canvas_height;
|
||||||
|
frame_w = frame_w * kParams.viewport_width / kParams.canvas_width;
|
||||||
|
frame_h = frame_h * kParams.viewport_height / kParams.canvas_height;
|
||||||
glScissor(window_x, window_y, frame_w, frame_h);
|
glScissor(window_x, window_y, frame_w, frame_h);
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT); // use clear color
|
glClear(GL_COLOR_BUFFER_BIT); // use clear color
|
||||||
@@ -367,6 +388,7 @@ static void StartDisplay(void) {
|
|||||||
glutInitWindowSize(width, height);
|
glutInitWindowSize(width, height);
|
||||||
glutCreateWindow("WebP viewer");
|
glutCreateWindow("WebP viewer");
|
||||||
glutDisplayFunc(HandleDisplay);
|
glutDisplayFunc(HandleDisplay);
|
||||||
|
glutReshapeFunc(HandleReshape);
|
||||||
glutIdleFunc(NULL);
|
glutIdleFunc(NULL);
|
||||||
glutKeyboardFunc(HandleKey);
|
glutKeyboardFunc(HandleKey);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
@@ -375,7 +397,6 @@ static void StartDisplay(void) {
|
|||||||
GetColorf(kParams.bg_color, 8),
|
GetColorf(kParams.bg_color, 8),
|
||||||
GetColorf(kParams.bg_color, 16),
|
GetColorf(kParams.bg_color, 16),
|
||||||
GetColorf(kParams.bg_color, 24));
|
GetColorf(kParams.bg_color, 24));
|
||||||
HandleReshape(width, height);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
DrawCheckerBoard();
|
DrawCheckerBoard();
|
||||||
}
|
}
|
||||||
@@ -400,6 +421,7 @@ static void Help(void) {
|
|||||||
"Keyboard shortcuts:\n"
|
"Keyboard shortcuts:\n"
|
||||||
" 'c' ................ toggle use of color profile\n"
|
" 'c' ................ toggle use of color profile\n"
|
||||||
" 'i' ................ overlay file information\n"
|
" 'i' ................ overlay file information\n"
|
||||||
|
" 'd' ................ disable blending & disposal (debug)\n"
|
||||||
" 'q' / 'Q' / ESC .... quit\n"
|
" 'q' / 'Q' / ESC .... quit\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -468,7 +490,7 @@ int main(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ExUtilReadFile(kParams.file_name,
|
if (!ImgIoUtilReadFile(kParams.file_name,
|
||||||
&kParams.data.bytes, &kParams.data.size)) {
|
&kParams.data.bytes, &kParams.data.size)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
@@ -484,10 +506,6 @@ int main(int argc, char *argv[]) {
|
|||||||
goto Error;
|
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_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH);
|
||||||
kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT);
|
kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT);
|
||||||
if (kParams.print_info) {
|
if (kParams.print_info) {
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Use of this source code is governed by a BSD-style license
|
|
||||||
// that can be found in the COPYING file in the root of the source
|
|
||||||
// tree. An additional intellectual property rights grant can be found
|
|
||||||
// in the file PATENTS. All contributing project authors may
|
|
||||||
// be found in the AUTHORS file in the root of the source tree.
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// WebP decode.
|
|
||||||
|
|
||||||
#include "./webpdec.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "webp/decode.h"
|
|
||||||
#include "webp/encode.h"
|
|
||||||
#include "./example_util.h"
|
|
||||||
#include "./metadata.h"
|
|
||||||
|
|
||||||
int ReadWebP(const uint8_t* const data, size_t data_size,
|
|
||||||
WebPPicture* const pic,
|
|
||||||
int keep_alpha, Metadata* const metadata) {
|
|
||||||
int ok = 0;
|
|
||||||
VP8StatusCode status = VP8_STATUS_OK;
|
|
||||||
WebPDecoderConfig config;
|
|
||||||
WebPDecBuffer* const output_buffer = &config.output;
|
|
||||||
WebPBitstreamFeatures* const bitstream = &config.input;
|
|
||||||
|
|
||||||
// TODO(jzern): add Exif/XMP/ICC extraction.
|
|
||||||
if (metadata != NULL) {
|
|
||||||
fprintf(stderr, "Warning: metadata extraction from WebP is unsupported.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!WebPInitDecoderConfig(&config)) {
|
|
||||||
fprintf(stderr, "Library version mismatch!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = WebPGetFeatures(data, data_size, bitstream);
|
|
||||||
if (status != VP8_STATUS_OK) {
|
|
||||||
ExUtilPrintWebPError("input data", status);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const int has_alpha = keep_alpha && bitstream->has_alpha;
|
|
||||||
if (pic->use_argb) {
|
|
||||||
output_buffer->colorspace = has_alpha ? MODE_RGBA : MODE_RGB;
|
|
||||||
} else {
|
|
||||||
output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = ExUtilDecodeWebP(data, data_size, 0, &config);
|
|
||||||
if (status == VP8_STATUS_OK) {
|
|
||||||
pic->width = output_buffer->width;
|
|
||||||
pic->height = output_buffer->height;
|
|
||||||
if (pic->use_argb) {
|
|
||||||
const uint8_t* const rgba = output_buffer->u.RGBA.rgba;
|
|
||||||
const int stride = output_buffer->u.RGBA.stride;
|
|
||||||
ok = has_alpha ? WebPPictureImportRGBA(pic, rgba, stride)
|
|
||||||
: WebPPictureImportRGB(pic, rgba, stride);
|
|
||||||
} else {
|
|
||||||
pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
|
|
||||||
ok = WebPPictureAlloc(pic);
|
|
||||||
if (!ok) {
|
|
||||||
status = VP8_STATUS_OUT_OF_MEMORY;
|
|
||||||
} else {
|
|
||||||
const WebPYUVABuffer* const yuva = &output_buffer->u.YUVA;
|
|
||||||
const int uv_width = (pic->width + 1) >> 1;
|
|
||||||
const int uv_height = (pic->height + 1) >> 1;
|
|
||||||
ExUtilCopyPlane(yuva->y, yuva->y_stride,
|
|
||||||
pic->y, pic->y_stride, pic->width, pic->height);
|
|
||||||
ExUtilCopyPlane(yuva->u, yuva->u_stride,
|
|
||||||
pic->u, pic->uv_stride, uv_width, uv_height);
|
|
||||||
ExUtilCopyPlane(yuva->v, yuva->v_stride,
|
|
||||||
pic->v, pic->uv_stride, uv_width, uv_height);
|
|
||||||
if (has_alpha) {
|
|
||||||
ExUtilCopyPlane(yuva->a, yuva->a_stride,
|
|
||||||
pic->a, pic->a_stride, pic->width, pic->height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != VP8_STATUS_OK) {
|
|
||||||
ExUtilPrintWebPError("input data", status);
|
|
||||||
}
|
|
||||||
|
|
||||||
WebPFreeDecBuffer(output_buffer);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Use of this source code is governed by a BSD-style license
|
|
||||||
// that can be found in the COPYING file in the root of the source
|
|
||||||
// tree. An additional intellectual property rights grant can be found
|
|
||||||
// in the file PATENTS. All contributing project authors may
|
|
||||||
// be found in the AUTHORS file in the root of the source tree.
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// WebP decode.
|
|
||||||
|
|
||||||
#ifndef WEBP_EXAMPLES_WEBPDEC_H_
|
|
||||||
#define WEBP_EXAMPLES_WEBPDEC_H_
|
|
||||||
|
|
||||||
#include "webp/types.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct Metadata;
|
|
||||||
struct WebPPicture;
|
|
||||||
|
|
||||||
// Reads a WebP from 'in_file', returning the decoded output in 'pic'.
|
|
||||||
// Output is RGBA or YUVA, depending on pic->use_argb value.
|
|
||||||
// If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA
|
|
||||||
// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.
|
|
||||||
// Returns true on success.
|
|
||||||
int ReadWebP(const uint8_t* const data, size_t data_size,
|
|
||||||
struct WebPPicture* const pic,
|
|
||||||
int keep_alpha, struct Metadata* const metadata);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // WEBP_EXAMPLES_WEBPDEC_H_
|
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
|
webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
|
||||||
|
|
||||||
Extract relevant data from WebP container file:
|
Extract relevant data from WebP container file:
|
||||||
webpmux -get frgm n in.webp -o out_fragment.webp
|
|
||||||
webpmux -get frame n in.webp -o out_frame.webp
|
webpmux -get frame n in.webp -o out_frame.webp
|
||||||
webpmux -get icc in.webp -o image_profile.icc
|
webpmux -get icc in.webp -o image_profile.icc
|
||||||
webpmux -get exif in.webp -o image_metadata.exif
|
webpmux -get exif in.webp -o image_metadata.exif
|
||||||
@@ -39,6 +38,11 @@
|
|||||||
webpmux -strip exif in.webp -o out.webp
|
webpmux -strip exif in.webp -o out.webp
|
||||||
webpmux -strip xmp in.webp -o out.webp
|
webpmux -strip xmp in.webp -o out.webp
|
||||||
|
|
||||||
|
Change duration of frame intervals:
|
||||||
|
webpmux -duration 150 in.webp -o out.webp
|
||||||
|
webpmux -duration 33,2 in.webp -o out.webp
|
||||||
|
webpmux -duration 200,10,0 -duration 150,6,50 in.webp -o out.webp
|
||||||
|
|
||||||
Misc:
|
Misc:
|
||||||
webpmux -info in.webp
|
webpmux -info in.webp
|
||||||
webpmux [ -h | -help ]
|
webpmux [ -h | -help ]
|
||||||
@@ -55,7 +59,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "webp/decode.h"
|
#include "webp/decode.h"
|
||||||
#include "webp/mux.h"
|
#include "webp/mux.h"
|
||||||
#include "./example_util.h"
|
#include "../examples/example_util.h"
|
||||||
|
#include "../imageio/imageio_util.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Config object to parse command-line arguments.
|
// Config object to parse command-line arguments.
|
||||||
@@ -66,7 +71,8 @@ typedef enum {
|
|||||||
ACTION_SET,
|
ACTION_SET,
|
||||||
ACTION_STRIP,
|
ACTION_STRIP,
|
||||||
ACTION_INFO,
|
ACTION_INFO,
|
||||||
ACTION_HELP
|
ACTION_HELP,
|
||||||
|
ACTION_DURATION
|
||||||
} ActionType;
|
} ActionType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -88,17 +94,17 @@ typedef enum {
|
|||||||
FEATURE_XMP,
|
FEATURE_XMP,
|
||||||
FEATURE_ICCP,
|
FEATURE_ICCP,
|
||||||
FEATURE_ANMF,
|
FEATURE_ANMF,
|
||||||
FEATURE_FRGM,
|
FEATURE_DURATION,
|
||||||
LAST_FEATURE
|
LAST_FEATURE
|
||||||
} FeatureType;
|
} FeatureType;
|
||||||
|
|
||||||
static const char* const kFourccList[LAST_FEATURE] = {
|
static const char* const kFourccList[LAST_FEATURE] = {
|
||||||
NULL, "EXIF", "XMP ", "ICCP", "ANMF", "FRGM"
|
NULL, "EXIF", "XMP ", "ICCP", "ANMF"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* const kDescriptions[LAST_FEATURE] = {
|
static const char* const kDescriptions[LAST_FEATURE] = {
|
||||||
NULL, "EXIF metadata", "XMP metadata", "ICC profile",
|
NULL, "EXIF metadata", "XMP metadata", "ICC profile",
|
||||||
"Animation frame", "Image fragment"
|
"Animation frame"
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -182,7 +188,6 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
printf("Canvas size: %d x %d\n", width, height);
|
printf("Canvas size: %d x %d\n", width, height);
|
||||||
|
|
||||||
err = WebPMuxGetFeatures(mux, &flag);
|
err = WebPMuxGetFeatures(mux, &flag);
|
||||||
if (flag & FRAGMENTS_FLAG) err = WEBP_MUX_INVALID_ARGUMENT;
|
|
||||||
RETURN_IF_ERROR("Failed to retrieve features\n");
|
RETURN_IF_ERROR("Failed to retrieve features\n");
|
||||||
|
|
||||||
if (flag == 0) {
|
if (flag == 0) {
|
||||||
@@ -193,26 +198,22 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
// Print the features present.
|
// Print the features present.
|
||||||
printf("Features present:");
|
printf("Features present:");
|
||||||
if (flag & ANIMATION_FLAG) printf(" animation");
|
if (flag & ANIMATION_FLAG) printf(" animation");
|
||||||
if (flag & FRAGMENTS_FLAG) printf(" image fragments");
|
|
||||||
if (flag & ICCP_FLAG) printf(" ICC profile");
|
if (flag & ICCP_FLAG) printf(" ICC profile");
|
||||||
if (flag & EXIF_FLAG) printf(" EXIF metadata");
|
if (flag & EXIF_FLAG) printf(" EXIF metadata");
|
||||||
if (flag & XMP_FLAG) printf(" XMP metadata");
|
if (flag & XMP_FLAG) printf(" XMP metadata");
|
||||||
if (flag & ALPHA_FLAG) printf(" transparency");
|
if (flag & ALPHA_FLAG) printf(" transparency");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if ((flag & ANIMATION_FLAG) || (flag & FRAGMENTS_FLAG)) {
|
if (flag & ANIMATION_FLAG) {
|
||||||
const int is_anim = !!(flag & ANIMATION_FLAG);
|
const WebPChunkId id = WEBP_CHUNK_ANMF;
|
||||||
const WebPChunkId id = is_anim ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
|
const char* const type_str = "frame";
|
||||||
const char* const type_str = is_anim ? "frame" : "fragment";
|
|
||||||
int nFrames;
|
int nFrames;
|
||||||
|
|
||||||
if (is_anim) {
|
|
||||||
WebPMuxAnimParams params;
|
WebPMuxAnimParams params;
|
||||||
err = WebPMuxGetAnimationParams(mux, ¶ms);
|
err = WebPMuxGetAnimationParams(mux, ¶ms);
|
||||||
assert(err == WEBP_MUX_OK);
|
assert(err == WEBP_MUX_OK);
|
||||||
printf("Background color : 0x%.8X Loop Count : %d\n",
|
printf("Background color : 0x%.8X Loop Count : %d\n",
|
||||||
params.bgcolor, params.loop_count);
|
params.bgcolor, params.loop_count);
|
||||||
}
|
|
||||||
|
|
||||||
err = WebPMuxNumChunks(mux, id, &nFrames);
|
err = WebPMuxNumChunks(mux, id, &nFrames);
|
||||||
assert(err == WEBP_MUX_OK);
|
assert(err == WEBP_MUX_OK);
|
||||||
@@ -221,8 +222,8 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
if (nFrames > 0) {
|
if (nFrames > 0) {
|
||||||
int i;
|
int i;
|
||||||
printf("No.: width height alpha x_offset y_offset ");
|
printf("No.: width height alpha x_offset y_offset ");
|
||||||
if (is_anim) printf("duration dispose blend ");
|
printf("duration dispose blend ");
|
||||||
printf("image_size\n");
|
printf("image_size compression\n");
|
||||||
for (i = 1; i <= nFrames; i++) {
|
for (i = 1; i <= nFrames; i++) {
|
||||||
WebPMuxFrameInfo frame;
|
WebPMuxFrameInfo frame;
|
||||||
err = WebPMuxGetFrame(mux, i, &frame);
|
err = WebPMuxGetFrame(mux, i, &frame);
|
||||||
@@ -235,7 +236,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
printf("%3d: %5d %5d %5s %8d %8d ", i, features.width,
|
printf("%3d: %5d %5d %5s %8d %8d ", i, features.width,
|
||||||
features.height, features.has_alpha ? "yes" : "no",
|
features.height, features.has_alpha ? "yes" : "no",
|
||||||
frame.x_offset, frame.y_offset);
|
frame.x_offset, frame.y_offset);
|
||||||
if (is_anim) {
|
{
|
||||||
const char* const dispose =
|
const char* const dispose =
|
||||||
(frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none"
|
(frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none"
|
||||||
: "background";
|
: "background";
|
||||||
@@ -243,7 +244,10 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
(frame.blend_method == WEBP_MUX_BLEND) ? "yes" : "no";
|
(frame.blend_method == WEBP_MUX_BLEND) ? "yes" : "no";
|
||||||
printf("%8d %10s %5s ", frame.duration, dispose, blend);
|
printf("%8d %10s %5s ", frame.duration, dispose, blend);
|
||||||
}
|
}
|
||||||
printf("%10d\n", (int)frame.bitstream.size);
|
printf("%10d %11s\n", (int)frame.bitstream.size,
|
||||||
|
(features.format == 1) ? "lossy" :
|
||||||
|
(features.format == 2) ? "lossless" :
|
||||||
|
"undefined");
|
||||||
}
|
}
|
||||||
WebPDataClear(&frame.bitstream);
|
WebPDataClear(&frame.bitstream);
|
||||||
RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i);
|
RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i);
|
||||||
@@ -272,7 +276,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
printf("Size of the XMP metadata: %d\n", (int)xmp.size);
|
printf("Size of the XMP metadata: %d\n", (int)xmp.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | FRAGMENTS_FLAG))) {
|
if ((flag & ALPHA_FLAG) && !(flag & ANIMATION_FLAG)) {
|
||||||
WebPMuxFrameInfo image;
|
WebPMuxFrameInfo image;
|
||||||
err = WebPMuxGetFrame(mux, 1, &image);
|
err = WebPMuxGetFrame(mux, 1, &image);
|
||||||
if (err == WEBP_MUX_OK) {
|
if (err == WEBP_MUX_OK) {
|
||||||
@@ -288,6 +292,8 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
|||||||
static void PrintHelp(void) {
|
static void PrintHelp(void) {
|
||||||
printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n");
|
printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n");
|
||||||
printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n");
|
printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n");
|
||||||
|
printf(" webpmux -duration DURATION_OPTIONS [-duration ...]\n");
|
||||||
|
printf(" INPUT -o OUTPUT\n");
|
||||||
printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n");
|
printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n");
|
||||||
printf(" webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]"
|
printf(" webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]"
|
||||||
"\n");
|
"\n");
|
||||||
@@ -314,6 +320,18 @@ static void PrintHelp(void) {
|
|||||||
printf(" 'file.exif' contains the EXIF metadata to be set\n");
|
printf(" 'file.exif' contains the EXIF metadata to be set\n");
|
||||||
printf(" 'file.xmp' contains the XMP metadata to be set\n");
|
printf(" 'file.xmp' contains the XMP metadata to be set\n");
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("DURATION_OPTIONS:\n");
|
||||||
|
printf(" Set duration of selected frames:\n");
|
||||||
|
printf(" duration set duration for each frames\n");
|
||||||
|
printf(" duration,frame set duration of a particular frame\n");
|
||||||
|
printf(" duration,start,end set duration of frames in the\n");
|
||||||
|
printf(" interval [start,end])\n");
|
||||||
|
printf(" where: 'duration' is the duration in milliseconds\n");
|
||||||
|
printf(" 'start' is the start frame index\n");
|
||||||
|
printf(" 'end' is the inclusive end frame index\n");
|
||||||
|
printf(" The special 'end' value '0' means: last frame.\n");
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("STRIP_OPTIONS:\n");
|
printf("STRIP_OPTIONS:\n");
|
||||||
printf(" Strip color profile/metadata:\n");
|
printf(" Strip color profile/metadata:\n");
|
||||||
@@ -365,7 +383,7 @@ static int ReadFileToWebPData(const char* const filename,
|
|||||||
WebPData* const webp_data) {
|
WebPData* const webp_data) {
|
||||||
const uint8_t* data;
|
const uint8_t* data;
|
||||||
size_t size;
|
size_t size;
|
||||||
if (!ExUtilReadFile(filename, &data, &size)) return 0;
|
if (!ImgIoUtilReadFile(filename, &data, &size)) return 0;
|
||||||
webp_data->bytes = data;
|
webp_data->bytes = data;
|
||||||
webp_data->size = size;
|
webp_data->size = size;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -385,7 +403,7 @@ static int CreateMux(const char* const filename, WebPMux** mux) {
|
|||||||
static int WriteData(const char* filename, const WebPData* const webpdata) {
|
static int WriteData(const char* filename, const WebPData* const webpdata) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb")
|
FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb")
|
||||||
: ExUtilSetBinaryMode(stdout);
|
: ImgIoUtilSetBinaryMode(stdout);
|
||||||
if (fout == NULL) {
|
if (fout == NULL) {
|
||||||
fprintf(stderr, "Error opening output WebP file %s!\n", filename);
|
fprintf(stderr, "Error opening output WebP file %s!\n", filename);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -414,6 +432,45 @@ static int WriteWebP(WebPMux* const mux, const char* filename) {
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
|
||||||
|
WebPMux* new_mux = WebPMuxNew();
|
||||||
|
WebPMuxAnimParams p;
|
||||||
|
WebPMuxError err;
|
||||||
|
int i;
|
||||||
|
int ok = 1;
|
||||||
|
|
||||||
|
if (new_mux == NULL) return NULL;
|
||||||
|
|
||||||
|
err = WebPMuxGetAnimationParams(mux, &p);
|
||||||
|
if (err == WEBP_MUX_OK) {
|
||||||
|
err = WebPMuxSetAnimationParams(new_mux, &p);
|
||||||
|
if (err != WEBP_MUX_OK) {
|
||||||
|
ERROR_GOTO2("Error (%s) handling animation params.\n",
|
||||||
|
ErrorString(err), End);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* it might not be an animation. Just keep moving. */
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1; i <= 3; ++i) {
|
||||||
|
WebPData metadata;
|
||||||
|
err = WebPMuxGetChunk(mux, kFourccList[i], &metadata);
|
||||||
|
if (err == WEBP_MUX_OK && metadata.size > 0) {
|
||||||
|
err = WebPMuxSetChunk(new_mux, kFourccList[i], &metadata, 1);
|
||||||
|
if (err != WEBP_MUX_OK) {
|
||||||
|
ERROR_GOTO1("Error transferring metadata in DuplicateMux().", End);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
End:
|
||||||
|
if (!ok) {
|
||||||
|
WebPMuxDelete(new_mux);
|
||||||
|
new_mux = NULL;
|
||||||
|
}
|
||||||
|
return new_mux;
|
||||||
|
}
|
||||||
|
|
||||||
static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
||||||
int dispose_method, dummy;
|
int dispose_method, dummy;
|
||||||
char plus_minus, blend_method;
|
char plus_minus, blend_method;
|
||||||
@@ -449,13 +506,6 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ParseFragmentArgs(const char* args, WebPMuxFrameInfo* const info) {
|
|
||||||
const int ok =
|
|
||||||
(sscanf(args, "+%d+%d", &info->x_offset, &info->y_offset) == 2);
|
|
||||||
if (ok) WarnAboutOddOffset(info);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
|
static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
|
||||||
uint32_t a, r, g, b;
|
uint32_t a, r, g, b;
|
||||||
if (sscanf(args, "%u,%u,%u,%u", &a, &r, &g, &b) != 4) return 0;
|
if (sscanf(args, "%u,%u,%u,%u", &a, &r, &g, &b) != 4) return 0;
|
||||||
@@ -484,9 +534,9 @@ static void DeleteConfig(WebPMuxConfig* config) {
|
|||||||
static int ValidateCommandLine(int argc, const char* argv[],
|
static int ValidateCommandLine(int argc, const char* argv[],
|
||||||
int* num_feature_args) {
|
int* num_feature_args) {
|
||||||
int num_frame_args;
|
int num_frame_args;
|
||||||
int num_frgm_args;
|
|
||||||
int num_loop_args;
|
int num_loop_args;
|
||||||
int num_bgcolor_args;
|
int num_bgcolor_args;
|
||||||
|
int num_durations_args;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
|
|
||||||
assert(num_feature_args != NULL);
|
assert(num_feature_args != NULL);
|
||||||
@@ -511,9 +561,9 @@ static int ValidateCommandLine(int argc, const char* argv[],
|
|||||||
|
|
||||||
// Compound checks.
|
// Compound checks.
|
||||||
num_frame_args = CountOccurrences(argv, argc, "-frame");
|
num_frame_args = CountOccurrences(argv, argc, "-frame");
|
||||||
num_frgm_args = CountOccurrences(argv, argc, "-frgm");
|
|
||||||
num_loop_args = CountOccurrences(argv, argc, "-loop");
|
num_loop_args = CountOccurrences(argv, argc, "-loop");
|
||||||
num_bgcolor_args = CountOccurrences(argv, argc, "-bgcolor");
|
num_bgcolor_args = CountOccurrences(argv, argc, "-bgcolor");
|
||||||
|
num_durations_args = CountOccurrences(argv, argc, "-duration");
|
||||||
|
|
||||||
if (num_loop_args > 1) {
|
if (num_loop_args > 1) {
|
||||||
ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
|
ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
|
||||||
@@ -526,22 +576,20 @@ static int ValidateCommandLine(int argc, const char* argv[],
|
|||||||
ERROR_GOTO1("ERROR: Loop count and background color are relevant only in "
|
ERROR_GOTO1("ERROR: Loop count and background color are relevant only in "
|
||||||
"case of animation.\n", ErrValidate);
|
"case of animation.\n", ErrValidate);
|
||||||
}
|
}
|
||||||
if (num_frame_args > 0 && num_frgm_args > 0) {
|
if (num_durations_args > 0 && num_frame_args != 0) {
|
||||||
ERROR_GOTO1("ERROR: Only one of frames & fragments can be specified at a "
|
ERROR_GOTO1("ERROR: Can not combine -duration and -frame commands.\n",
|
||||||
"time.\n", ErrValidate);
|
ErrValidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(ok == 1);
|
assert(ok == 1);
|
||||||
if (num_frame_args == 0 && num_frgm_args == 0) {
|
if (num_durations_args > 0) {
|
||||||
|
*num_feature_args = num_durations_args;
|
||||||
|
} else if (num_frame_args == 0) {
|
||||||
// Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action).
|
// Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action).
|
||||||
*num_feature_args = 1;
|
*num_feature_args = 1;
|
||||||
} else {
|
} else {
|
||||||
// Multiple arguments ('set' action for animation or fragmented image).
|
// Multiple arguments ('set' action for animation)
|
||||||
if (num_frame_args > 0) {
|
|
||||||
*num_feature_args = num_frame_args + num_loop_args + num_bgcolor_args;
|
*num_feature_args = num_frame_args + num_loop_args + num_bgcolor_args;
|
||||||
} else {
|
|
||||||
*num_feature_args = num_frgm_args;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrValidate:
|
ErrValidate:
|
||||||
@@ -583,6 +631,21 @@ static int ParseCommandLine(int argc, const char* argv[],
|
|||||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
|
} else if (!strcmp(argv[i], "-duration")) {
|
||||||
|
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
||||||
|
if (ACTION_IS_NIL || config->action_type_ == ACTION_DURATION) {
|
||||||
|
config->action_type_ = ACTION_DURATION;
|
||||||
|
} else {
|
||||||
|
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||||
|
}
|
||||||
|
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_DURATION) {
|
||||||
|
feature->type_ = FEATURE_DURATION;
|
||||||
|
} else {
|
||||||
|
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||||
|
}
|
||||||
|
arg->params_ = argv[i + 1];
|
||||||
|
++feature_arg_index;
|
||||||
|
i += 2;
|
||||||
} else if (!strcmp(argv[i], "-get")) {
|
} else if (!strcmp(argv[i], "-get")) {
|
||||||
if (ACTION_IS_NIL) {
|
if (ACTION_IS_NIL) {
|
||||||
config->action_type_ = ACTION_GET;
|
config->action_type_ = ACTION_GET;
|
||||||
@@ -694,8 +757,7 @@ static int ParseCommandLine(int argc, const char* argv[],
|
|||||||
} else if (!strcmp(argv[i], "frame") &&
|
} else if (!strcmp(argv[i], "frame") &&
|
||||||
(config->action_type_ == ACTION_GET)) {
|
(config->action_type_ == ACTION_GET)) {
|
||||||
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
||||||
feature->type_ = (!strcmp(argv[i], "frame")) ? FEATURE_ANMF :
|
feature->type_ = FEATURE_ANMF;
|
||||||
FEATURE_FRGM;
|
|
||||||
arg->params_ = argv[i + 1];
|
arg->params_ = argv[i + 1];
|
||||||
++feature_arg_index;
|
++feature_arg_index;
|
||||||
i += 2;
|
i += 2;
|
||||||
@@ -733,8 +795,7 @@ static int ValidateConfig(WebPMuxConfig* config) {
|
|||||||
if (config->input_ == NULL) {
|
if (config->input_ == NULL) {
|
||||||
if (config->action_type_ != ACTION_SET) {
|
if (config->action_type_ != ACTION_SET) {
|
||||||
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
||||||
} else if (feature->type_ != FEATURE_ANMF &&
|
} else if (feature->type_ != FEATURE_ANMF) {
|
||||||
feature->type_ != FEATURE_FRGM) {
|
|
||||||
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -786,14 +847,13 @@ static int InitializeConfig(int argc, const char* argv[],
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Processing.
|
// Processing.
|
||||||
|
|
||||||
static int GetFrameFragment(const WebPMux* mux,
|
static int GetFrame(const WebPMux* mux, const WebPMuxConfig* config) {
|
||||||
const WebPMuxConfig* config, int is_frame) {
|
|
||||||
WebPMuxError err = WEBP_MUX_OK;
|
WebPMuxError err = WEBP_MUX_OK;
|
||||||
WebPMux* mux_single = NULL;
|
WebPMux* mux_single = NULL;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
const WebPChunkId id = is_frame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
|
const WebPChunkId id = WEBP_CHUNK_ANMF;
|
||||||
WebPMuxFrameInfo info;
|
WebPMuxFrameInfo info;
|
||||||
WebPDataInit(&info.bitstream);
|
WebPDataInit(&info.bitstream);
|
||||||
|
|
||||||
@@ -844,9 +904,7 @@ static int Process(const WebPMuxConfig* config) {
|
|||||||
if (!ok) goto Err2;
|
if (!ok) goto Err2;
|
||||||
switch (feature->type_) {
|
switch (feature->type_) {
|
||||||
case FEATURE_ANMF:
|
case FEATURE_ANMF:
|
||||||
case FEATURE_FRGM:
|
ok = GetFrame(mux, config);
|
||||||
ok = GetFrameFragment(mux, config,
|
|
||||||
(feature->type_ == FEATURE_ANMF) ? 1 : 0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FEATURE_ICCP:
|
case FEATURE_ICCP:
|
||||||
@@ -938,35 +996,6 @@ static int Process(const WebPMuxConfig* config) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FEATURE_FRGM: {
|
|
||||||
int i;
|
|
||||||
mux = WebPMuxNew();
|
|
||||||
if (mux == NULL) {
|
|
||||||
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
|
|
||||||
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
|
|
||||||
}
|
|
||||||
for (i = 0; i < feature->arg_count_; ++i) {
|
|
||||||
WebPMuxFrameInfo frgm;
|
|
||||||
frgm.id = WEBP_CHUNK_FRGM;
|
|
||||||
ok = ReadFileToWebPData(feature->args_[i].filename_,
|
|
||||||
&frgm.bitstream);
|
|
||||||
if (!ok) goto Err2;
|
|
||||||
ok = ParseFragmentArgs(feature->args_[i].params_, &frgm);
|
|
||||||
if (!ok) {
|
|
||||||
WebPDataClear(&frgm.bitstream);
|
|
||||||
ERROR_GOTO1("ERROR: Could not parse fragment properties.\n",
|
|
||||||
Err2);
|
|
||||||
}
|
|
||||||
err = WebPMuxPushFrame(mux, &frgm, 1);
|
|
||||||
WebPDataClear(&frgm.bitstream);
|
|
||||||
if (err != WEBP_MUX_OK) {
|
|
||||||
ERROR_GOTO3("ERROR (%s): Could not add a fragment at index %d.\n",
|
|
||||||
ErrorString(err), i, Err2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case FEATURE_ICCP:
|
case FEATURE_ICCP:
|
||||||
case FEATURE_EXIF:
|
case FEATURE_EXIF:
|
||||||
case FEATURE_XMP: {
|
case FEATURE_XMP: {
|
||||||
@@ -990,6 +1019,89 @@ static int Process(const WebPMuxConfig* config) {
|
|||||||
ok = WriteWebP(mux, config->output_);
|
ok = WriteWebP(mux, config->output_);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ACTION_DURATION: {
|
||||||
|
int num_frames;
|
||||||
|
ok = CreateMux(config->input_, &mux);
|
||||||
|
if (!ok) goto Err2;
|
||||||
|
err = WebPMuxNumChunks(mux, WEBP_CHUNK_ANMF, &num_frames);
|
||||||
|
ok = (err == WEBP_MUX_OK);
|
||||||
|
if (!ok) {
|
||||||
|
ERROR_GOTO1("ERROR: can not parse the number of frames.\n", Err2);
|
||||||
|
}
|
||||||
|
if (num_frames == 0) {
|
||||||
|
fprintf(stderr, "Doesn't look like the source is animated. "
|
||||||
|
"Skipping duration setting.\n");
|
||||||
|
ok = WriteWebP(mux, config->output_);
|
||||||
|
if (!ok) goto Err2;
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
int* durations = NULL;
|
||||||
|
WebPMux* new_mux = DuplicateMuxHeader(mux);
|
||||||
|
if (new_mux == NULL) goto Err2;
|
||||||
|
durations = (int*)malloc((size_t)num_frames * sizeof(*durations));
|
||||||
|
if (durations == NULL) goto Err2;
|
||||||
|
for (i = 0; i < num_frames; ++i) durations[i] = -1;
|
||||||
|
|
||||||
|
// Parse intervals to process.
|
||||||
|
for (i = 0; i < feature->arg_count_; ++i) {
|
||||||
|
int k;
|
||||||
|
int args[3];
|
||||||
|
int duration, start, end;
|
||||||
|
const int nb_args = ExUtilGetInts(feature->args_[i].params_,
|
||||||
|
10, 3, args);
|
||||||
|
ok = (nb_args >= 1);
|
||||||
|
if (!ok) goto Err3;
|
||||||
|
duration = args[0];
|
||||||
|
if (duration < 0) {
|
||||||
|
ERROR_GOTO1("ERROR: duration must be strictly positive.\n", Err3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nb_args == 1) { // only duration is present -> use full interval
|
||||||
|
start = 1;
|
||||||
|
end = num_frames;
|
||||||
|
} else {
|
||||||
|
start = args[1];
|
||||||
|
if (start <= 0) {
|
||||||
|
start = 1;
|
||||||
|
} else if (start > num_frames) {
|
||||||
|
start = num_frames;
|
||||||
|
}
|
||||||
|
end = (nb_args >= 3) ? args[2] : start;
|
||||||
|
if (end == 0 || end > num_frames) end = num_frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (k = start; k <= end; ++k) {
|
||||||
|
assert(k >= 1 && k <= num_frames);
|
||||||
|
durations[k - 1] = duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply non-negative durations to their destination frames.
|
||||||
|
for (i = 1; i <= num_frames; ++i) {
|
||||||
|
WebPMuxFrameInfo frame;
|
||||||
|
err = WebPMuxGetFrame(mux, i, &frame);
|
||||||
|
if (err != WEBP_MUX_OK || frame.id != WEBP_CHUNK_ANMF) {
|
||||||
|
ERROR_GOTO2("ERROR: can not retrieve frame #%d.\n", i, Err3);
|
||||||
|
}
|
||||||
|
if (durations[i - 1] >= 0) frame.duration = durations[i - 1];
|
||||||
|
err = WebPMuxPushFrame(new_mux, &frame, 1);
|
||||||
|
if (err != WEBP_MUX_OK) {
|
||||||
|
ERROR_GOTO2("ERROR: error push frame data #%d\n", i, Err3);
|
||||||
|
}
|
||||||
|
WebPDataClear(&frame.bitstream);
|
||||||
|
}
|
||||||
|
WebPMuxDelete(mux);
|
||||||
|
ok = WriteWebP(new_mux, config->output_);
|
||||||
|
mux = new_mux; // transfer for the WebPMuxDelete() call
|
||||||
|
new_mux = NULL;
|
||||||
|
|
||||||
|
Err3:
|
||||||
|
free(durations);
|
||||||
|
WebPMuxDelete(new_mux);
|
||||||
|
if (!ok) goto Err2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ACTION_STRIP: {
|
case ACTION_STRIP: {
|
||||||
ok = CreateMux(config->input_, &mux);
|
ok = CreateMux(config->input_, &mux);
|
||||||
if (!ok) goto Err2;
|
if (!ok) goto Err2;
|
||||||
|
|||||||
26
extras/Makefile.am
Normal file
26
extras/Makefile.am
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
|
||||||
|
noinst_LTLIBRARIES = libwebpextras.la
|
||||||
|
|
||||||
|
noinst_HEADERS =
|
||||||
|
noinst_HEADERS += ../src/webp/types.h
|
||||||
|
|
||||||
|
libwebpextras_la_SOURCES =
|
||||||
|
libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c
|
||||||
|
|
||||||
|
libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
libwebpextras_la_LDFLAGS = -lm
|
||||||
|
libwebpextras_la_LIBADD = ../src/libwebp.la
|
||||||
|
|
||||||
|
noinst_PROGRAMS = get_disto webp_quality
|
||||||
|
|
||||||
|
get_disto_SOURCES = get_disto.c
|
||||||
|
get_disto_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
get_disto_LDADD = ../imageio/libimageio_util.la ../imageio/libimagedec.la
|
||||||
|
get_disto_LDADD += ../src/libwebp.la
|
||||||
|
get_disto_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
|
||||||
|
|
||||||
|
webp_quality_SOURCES = webp_quality.c
|
||||||
|
webp_quality_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||||
|
webp_quality_LDADD = ../imageio/libimageio_util.la
|
||||||
|
webp_quality_LDADD += libwebpextras.la
|
||||||
|
webp_quality_LDADD += ../src/libwebp.la
|
||||||
@@ -10,12 +10,14 @@
|
|||||||
// Additional WebP utilities.
|
// Additional WebP utilities.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "../webp/extras.h"
|
#include "./extras.h"
|
||||||
|
#include "webp/format_constants.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define XTRA_MAJ_VERSION 0
|
#define XTRA_MAJ_VERSION 0
|
||||||
#define XTRA_MIN_VERSION 0
|
#define XTRA_MIN_VERSION 1
|
||||||
#define XTRA_REV_VERSION 0
|
#define XTRA_REV_VERSION 0
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -108,4 +110,33 @@ int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
|
||||||
|
const uint32_t palette[], int palette_size,
|
||||||
|
WebPPicture* pic) {
|
||||||
|
int x, y;
|
||||||
|
uint32_t* dst;
|
||||||
|
// 256 as the input buffer is uint8_t.
|
||||||
|
assert(MAX_PALETTE_SIZE <= 256);
|
||||||
|
if (pic == NULL || indexed == NULL || indexed_stride < pic->width ||
|
||||||
|
palette == NULL || palette_size > MAX_PALETTE_SIZE || palette_size <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pic->use_argb = 1;
|
||||||
|
if (!WebPPictureAlloc(pic)) return 0;
|
||||||
|
dst = pic->argb;
|
||||||
|
for (y = 0; y < pic->height; ++y) {
|
||||||
|
for (x = 0; x < pic->width; ++x) {
|
||||||
|
// Make sure we are within the palette.
|
||||||
|
if (indexed[x] >= palette_size) {
|
||||||
|
WebPPictureFree(pic);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dst[x] = palette[indexed[x]];
|
||||||
|
}
|
||||||
|
indexed += indexed_stride;
|
||||||
|
dst += pic->argb_stride;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -8,18 +8,18 @@
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef WEBP_WEBP_EXTRAS_H_
|
#ifndef WEBP_EXTRAS_EXTRAS_H_
|
||||||
#define WEBP_WEBP_EXTRAS_H_
|
#define WEBP_EXTRAS_EXTRAS_H_
|
||||||
|
|
||||||
#include "./types.h"
|
#include "webp/types.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "./encode.h"
|
#include "webp/encode.h"
|
||||||
|
|
||||||
#define WEBP_EXTRAS_ABI_VERSION 0x0000 // MAJOR(8b) + MINOR(8b)
|
#define WEBP_EXTRAS_ABI_VERSION 0x0001 // MAJOR(8b) + MINOR(8b)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -42,10 +42,29 @@ WEBP_EXTERN(int) WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic);
|
|||||||
// width and height must be set prior to calling this function.
|
// width and height must be set prior to calling this function.
|
||||||
WEBP_EXTERN(int) WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
|
WEBP_EXTERN(int) WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
|
||||||
|
|
||||||
|
// Import a color mapped image. The number of colors is less or equal to
|
||||||
|
// MAX_PALETTE_SIZE. 'pic' must have been initialized. Its content, if any,
|
||||||
|
// will be discarded. Returns 'false' in case of error, or if indexed[] contains
|
||||||
|
// invalid indices.
|
||||||
|
WEBP_EXTERN(int)
|
||||||
|
WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
|
||||||
|
const uint32_t palette[], int palette_size,
|
||||||
|
WebPPicture* pic);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Parse a bitstream, search for VP8 (lossy) header and report a
|
||||||
|
// rough estimation of the quality factor used for compressing the bitstream.
|
||||||
|
// If the bitstream is in lossless format, the special value '101' is returned.
|
||||||
|
// Otherwise (lossy bitstream), the returned value is in the range [0..100].
|
||||||
|
// Any error (invalid bitstream, animated WebP, incomplete header, etc.)
|
||||||
|
// will return a value of -1.
|
||||||
|
WEBP_EXTERN(int) VP8EstimateQuality(const uint8_t* const data, size_t size);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_WEBP_EXTRAS_H_ */
|
#endif /* WEBP_EXTRAS_EXTRAS_H_ */
|
||||||
343
extras/get_disto.c
Normal file
343
extras/get_disto.c
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Simple tool to load two webp/png/jpg/tiff files and compute PSNR/SSIM.
|
||||||
|
// This is mostly a wrapper around WebPPictureDistortion().
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
gcc -o get_disto get_disto.c -O3 -I../ -L../examples -L../imageio \
|
||||||
|
-lexample_util -limageio_util -limagedec -lwebp -L/opt/local/lib \
|
||||||
|
-lpng -lz -ljpeg -ltiff -lm -lpthread
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "webp/encode.h"
|
||||||
|
#include "../imageio/image_dec.h"
|
||||||
|
#include "../imageio/imageio_util.h"
|
||||||
|
|
||||||
|
static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||||
|
int keep_alpha) {
|
||||||
|
const uint8_t* data = NULL;
|
||||||
|
size_t data_size = 0;
|
||||||
|
WebPImageReader reader = NULL;
|
||||||
|
int ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||||
|
if (!ok) goto End;
|
||||||
|
|
||||||
|
pic->use_argb = 1; // force ARGB
|
||||||
|
|
||||||
|
#ifdef HAVE_WINCODEC_H
|
||||||
|
// Try to decode the file using WIC falling back to the other readers for
|
||||||
|
// e.g., WebP.
|
||||||
|
ok = ReadPictureWithWIC(filename, pic, keep_alpha, NULL);
|
||||||
|
if (ok) goto End;
|
||||||
|
#endif
|
||||||
|
reader = WebPGuessImageReader(data, data_size);
|
||||||
|
ok = reader(data, data_size, pic, keep_alpha, NULL);
|
||||||
|
|
||||||
|
End:
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Error! Could not process file %s\n", filename);
|
||||||
|
}
|
||||||
|
free((void*)data);
|
||||||
|
return ok ? data_size : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RescalePlane(uint8_t* plane, int width, int height,
|
||||||
|
int x_stride, int y_stride, int max) {
|
||||||
|
const uint32_t factor = (max > 0) ? (255u << 16) / max : 0;
|
||||||
|
int x, y;
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
uint8_t* const ptr = plane + y * y_stride;
|
||||||
|
for (x = 0; x < width * x_stride; x += x_stride) {
|
||||||
|
const uint32_t diff = (ptr[x] * factor + (1 << 15)) >> 16;
|
||||||
|
ptr[x] = diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the max absolute difference.
|
||||||
|
static int DiffScaleChannel(uint8_t* src1, int stride1,
|
||||||
|
const uint8_t* src2, int stride2,
|
||||||
|
int x_stride, int w, int h, int do_scaling) {
|
||||||
|
int x, y;
|
||||||
|
int max = 0;
|
||||||
|
for (y = 0; y < h; ++y) {
|
||||||
|
uint8_t* const ptr1 = src1 + y * stride1;
|
||||||
|
const uint8_t* const ptr2 = src2 + y * stride2;
|
||||||
|
for (x = 0; x < w * x_stride; x += x_stride) {
|
||||||
|
const int diff = abs(ptr1[x] - ptr2[x]);
|
||||||
|
if (diff > max) max = diff;
|
||||||
|
ptr1[x] = diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_scaling) RescalePlane(src1, w, h, x_stride, stride1, max);
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SSIM calculation. We re-implement these functions here, out of dsp/, to avoid
|
||||||
|
// breaking the library's hidden visibility. This code duplication avoids the
|
||||||
|
// bigger annoyance of having to open up internal details of libdsp...
|
||||||
|
|
||||||
|
#define SSIM_KERNEL 3 // total size of the kernel: 2 * SSIM_KERNEL + 1
|
||||||
|
|
||||||
|
// struct for accumulating statistical moments
|
||||||
|
typedef struct {
|
||||||
|
uint32_t w; // sum(w_i) : sum of weights
|
||||||
|
uint32_t xm, ym; // sum(w_i * x_i), sum(w_i * y_i)
|
||||||
|
uint32_t xxm, xym, yym; // sum(w_i * x_i * x_i), etc.
|
||||||
|
} DistoStats;
|
||||||
|
|
||||||
|
// hat-shaped filter. Sum of coefficients is equal to 16.
|
||||||
|
static const uint32_t kWeight[2 * SSIM_KERNEL + 1] = { 1, 2, 3, 4, 3, 2, 1 };
|
||||||
|
|
||||||
|
static WEBP_INLINE double SSIMCalculation(const DistoStats* const stats) {
|
||||||
|
const uint32_t N = stats->w;
|
||||||
|
const uint32_t w2 = N * N;
|
||||||
|
const uint32_t C1 = 20 * w2;
|
||||||
|
const uint32_t C2 = 60 * w2;
|
||||||
|
const uint32_t C3 = 8 * 8 * w2; // 'dark' limit ~= 6
|
||||||
|
const uint64_t xmxm = (uint64_t)stats->xm * stats->xm;
|
||||||
|
const uint64_t ymym = (uint64_t)stats->ym * stats->ym;
|
||||||
|
if (xmxm + ymym >= C3) {
|
||||||
|
const int64_t xmym = (int64_t)stats->xm * stats->ym;
|
||||||
|
const int64_t sxy = (int64_t)stats->xym * N - xmym; // can be negative
|
||||||
|
const uint64_t sxx = (uint64_t)stats->xxm * N - xmxm;
|
||||||
|
const uint64_t syy = (uint64_t)stats->yym * N - ymym;
|
||||||
|
// we descale by 8 to prevent overflow during the fnum/fden multiply.
|
||||||
|
const uint64_t num_S = (2 * (uint64_t)(sxy < 0 ? 0 : sxy) + C2) >> 8;
|
||||||
|
const uint64_t den_S = (sxx + syy + C2) >> 8;
|
||||||
|
const uint64_t fnum = (2 * xmym + C1) * num_S;
|
||||||
|
const uint64_t fden = (xmxm + ymym + C1) * den_S;
|
||||||
|
const double r = (double)fnum / fden;
|
||||||
|
assert(r >= 0. && r <= 1.0);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return 1.; // area is too dark to contribute meaningfully
|
||||||
|
}
|
||||||
|
|
||||||
|
static double SSIMGetClipped(const uint8_t* src1, int stride1,
|
||||||
|
const uint8_t* src2, int stride2,
|
||||||
|
int xo, int yo, int W, int H) {
|
||||||
|
DistoStats stats = { 0, 0, 0, 0, 0, 0 };
|
||||||
|
const int ymin = (yo - SSIM_KERNEL < 0) ? 0 : yo - SSIM_KERNEL;
|
||||||
|
const int ymax = (yo + SSIM_KERNEL > H - 1) ? H - 1 : yo + SSIM_KERNEL;
|
||||||
|
const int xmin = (xo - SSIM_KERNEL < 0) ? 0 : xo - SSIM_KERNEL;
|
||||||
|
const int xmax = (xo + SSIM_KERNEL > W - 1) ? W - 1 : xo + SSIM_KERNEL;
|
||||||
|
int x, y;
|
||||||
|
src1 += ymin * stride1;
|
||||||
|
src2 += ymin * stride2;
|
||||||
|
for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) {
|
||||||
|
for (x = xmin; x <= xmax; ++x) {
|
||||||
|
const uint32_t w = kWeight[SSIM_KERNEL + x - xo]
|
||||||
|
* kWeight[SSIM_KERNEL + y - yo];
|
||||||
|
const uint32_t s1 = src1[x];
|
||||||
|
const uint32_t s2 = src2[x];
|
||||||
|
stats.w += w;
|
||||||
|
stats.xm += w * s1;
|
||||||
|
stats.ym += w * s2;
|
||||||
|
stats.xxm += w * s1 * s1;
|
||||||
|
stats.xym += w * s1 * s2;
|
||||||
|
stats.yym += w * s2 * s2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SSIMCalculation(&stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute SSIM-score map. Return -1 in case of error, max diff otherwise.
|
||||||
|
static int SSIMScaleChannel(uint8_t* src1, int stride1,
|
||||||
|
const uint8_t* src2, int stride2,
|
||||||
|
int x_stride, int w, int h, int do_scaling) {
|
||||||
|
int x, y;
|
||||||
|
int max = 0;
|
||||||
|
uint8_t* const plane1 = (uint8_t*)malloc(2 * w * h * sizeof(*plane1));
|
||||||
|
uint8_t* const plane2 = plane1 + w * h;
|
||||||
|
if (plane1 == NULL) return -1;
|
||||||
|
|
||||||
|
// extract plane
|
||||||
|
for (y = 0; y < h; ++y) {
|
||||||
|
for (x = 0; x < w; ++x) {
|
||||||
|
plane1[x + y * w] = src1[x * x_stride + y * stride1];
|
||||||
|
plane2[x + y * w] = src2[x * x_stride + y * stride2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (y = 0; y < h; ++y) {
|
||||||
|
for (x = 0; x < w; ++x) {
|
||||||
|
const double ssim = SSIMGetClipped(plane1, w, plane2, w, x, y, w, h);
|
||||||
|
int diff = (int)(255 * (1. - ssim));
|
||||||
|
if (diff < 0) {
|
||||||
|
diff = 0;
|
||||||
|
} else if (diff > max) {
|
||||||
|
max = diff;
|
||||||
|
}
|
||||||
|
src1[x * x_stride + y * stride1] = (diff > 255) ? 255u : (uint8_t)diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(plane1);
|
||||||
|
|
||||||
|
if (do_scaling) RescalePlane(src1, w, h, x_stride, stride1, max);
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert an argb picture to luminance.
|
||||||
|
static void ConvertToGray(WebPPicture* const pic) {
|
||||||
|
int x, y;
|
||||||
|
assert(pic != NULL);
|
||||||
|
assert(pic->use_argb);
|
||||||
|
for (y = 0; y < pic->height; ++y) {
|
||||||
|
uint32_t* const row = &pic->argb[y * pic->argb_stride];
|
||||||
|
for (x = 0; x < pic->width; ++x) {
|
||||||
|
const uint32_t argb = row[x];
|
||||||
|
const uint32_t r = (argb >> 16) & 0xff;
|
||||||
|
const uint32_t g = (argb >> 8) & 0xff;
|
||||||
|
const uint32_t b = (argb >> 0) & 0xff;
|
||||||
|
// We use BT.709 for converting to luminance.
|
||||||
|
const uint32_t Y = (uint32_t)(0.2126 * r + 0.7152 * g + 0.0722 * b + .5);
|
||||||
|
row[x] = (argb & 0xff000000u) | (Y * 0x010101u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Help(void) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Usage: get_disto [-ssim][-psnr][-alpha] compressed.webp orig.webp\n"
|
||||||
|
" -ssim ..... print SSIM distortion\n"
|
||||||
|
" -psnr ..... print PSNR distortion (default)\n"
|
||||||
|
" -alpha .... preserve alpha plane\n"
|
||||||
|
" -h ........ this message\n"
|
||||||
|
" -o <file> . save the diff map as a WebP lossless file\n"
|
||||||
|
" -scale .... scale the difference map to fit [0..255] range\n"
|
||||||
|
" -gray ..... use grayscale for difference map (-scale)\n"
|
||||||
|
" Also handles PNG, JPG and TIFF files, in addition to WebP.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
WebPPicture pic1, pic2;
|
||||||
|
size_t size1 = 0, size2 = 0;
|
||||||
|
int ret = 1;
|
||||||
|
float disto[5];
|
||||||
|
int type = 0;
|
||||||
|
int c;
|
||||||
|
int help = 0;
|
||||||
|
int keep_alpha = 0;
|
||||||
|
int scale = 0;
|
||||||
|
int use_gray = 0;
|
||||||
|
const char* name1 = NULL;
|
||||||
|
const char* name2 = NULL;
|
||||||
|
const char* output = NULL;
|
||||||
|
|
||||||
|
if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) {
|
||||||
|
fprintf(stderr, "Can't init pictures\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (c = 1; c < argc; ++c) {
|
||||||
|
if (!strcmp(argv[c], "-ssim")) {
|
||||||
|
type = 1;
|
||||||
|
} else if (!strcmp(argv[c], "-psnr")) {
|
||||||
|
type = 0;
|
||||||
|
} else if (!strcmp(argv[c], "-alpha")) {
|
||||||
|
keep_alpha = 1;
|
||||||
|
} else if (!strcmp(argv[c], "-scale")) {
|
||||||
|
scale = 1;
|
||||||
|
} else if (!strcmp(argv[c], "-gray")) {
|
||||||
|
use_gray = 1;
|
||||||
|
} else if (!strcmp(argv[c], "-h")) {
|
||||||
|
help = 1;
|
||||||
|
ret = 0;
|
||||||
|
} else if (!strcmp(argv[c], "-o")) {
|
||||||
|
if (++c == argc) {
|
||||||
|
fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]);
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
output = argv[c];
|
||||||
|
} else if (name1 == NULL) {
|
||||||
|
name1 = argv[c];
|
||||||
|
} else {
|
||||||
|
name2 = argv[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (help || name1 == NULL || name2 == NULL) {
|
||||||
|
if (!help) {
|
||||||
|
fprintf(stderr, "Error: missing arguments.\n");
|
||||||
|
}
|
||||||
|
Help();
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
size1 = ReadPicture(name1, &pic1, 1);
|
||||||
|
size2 = ReadPicture(name1, &pic2, 1);
|
||||||
|
if (size1 == 0 || size2 == 0) goto End;
|
||||||
|
|
||||||
|
if (!keep_alpha) {
|
||||||
|
WebPBlendAlpha(&pic1, 0x00000000);
|
||||||
|
WebPBlendAlpha(&pic2, 0x00000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WebPPictureDistortion(&pic1, &pic2, type, disto)) {
|
||||||
|
fprintf(stderr, "Error while computing the distortion.\n");
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
printf("%u %.2f %.2f %.2f %.2f %.2f\n",
|
||||||
|
(unsigned int)size1,
|
||||||
|
disto[4], disto[0], disto[1], disto[2], disto[3]);
|
||||||
|
|
||||||
|
if (output != NULL) {
|
||||||
|
uint8_t* data = NULL;
|
||||||
|
size_t data_size = 0;
|
||||||
|
if (pic1.use_argb != pic2.use_argb) {
|
||||||
|
fprintf(stderr, "Pictures are not in the same argb format. "
|
||||||
|
"Can't save the difference map.\n");
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
if (pic1.use_argb) {
|
||||||
|
int n;
|
||||||
|
fprintf(stderr, "max differences per channel: ");
|
||||||
|
for (n = 0; n < 3; ++n) { // skip the alpha channel
|
||||||
|
const int range = (type == 1) ?
|
||||||
|
SSIMScaleChannel((uint8_t*)pic1.argb + n, pic1.argb_stride * 4,
|
||||||
|
(const uint8_t*)pic2.argb + n, pic2.argb_stride * 4,
|
||||||
|
4, pic1.width, pic1.height, scale) :
|
||||||
|
DiffScaleChannel((uint8_t*)pic1.argb + n, pic1.argb_stride * 4,
|
||||||
|
(const uint8_t*)pic2.argb + n, pic2.argb_stride * 4,
|
||||||
|
4, pic1.width, pic1.height, scale);
|
||||||
|
if (range < 0) fprintf(stderr, "\nError computing diff map\n");
|
||||||
|
fprintf(stderr, "[%d]", range);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
if (use_gray) ConvertToGray(&pic1);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Can only compute the difference map in ARGB format.\n");
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
data_size = WebPEncodeLosslessBGRA((const uint8_t*)pic1.argb,
|
||||||
|
pic1.width, pic1.height,
|
||||||
|
pic1.argb_stride * 4,
|
||||||
|
&data);
|
||||||
|
if (data_size == 0) {
|
||||||
|
fprintf(stderr, "Error during lossless encoding.\n");
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1;
|
||||||
|
WebPFree(data);
|
||||||
|
if (ret) goto End;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
End:
|
||||||
|
WebPPictureFree(&pic1);
|
||||||
|
WebPPictureFree(&pic2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
129
extras/quality_estimate.c
Normal file
129
extras/quality_estimate.c
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// VP8EstimateQuality(): rough encoding quality estimate
|
||||||
|
//
|
||||||
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
|
#include "./extras.h"
|
||||||
|
#include "webp/decode.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define INVALID_BIT_POS (1ull << 63)
|
||||||
|
|
||||||
|
// In most cases, we don't need to use a full arithmetic decoder, since
|
||||||
|
// all the header's bits are written using a uniform probability of 128.
|
||||||
|
// We can just parse the header as if it was bits (works in 99.999% cases).
|
||||||
|
static WEBP_INLINE uint32_t GetBit(const uint8_t* const data, size_t nb,
|
||||||
|
uint64_t max_size, uint64_t* const bit_pos) {
|
||||||
|
uint32_t val = 0;
|
||||||
|
if (*bit_pos + nb <= 8 * max_size) {
|
||||||
|
while (nb-- > 0) {
|
||||||
|
const uint64_t p = (*bit_pos)++;
|
||||||
|
const int bit = !!(data[p >> 3] & (128 >> ((p & 7))));
|
||||||
|
val = (val << 1) | bit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*bit_pos = INVALID_BIT_POS;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GET_BIT(n) GetBit(data, (n), size, &bit_pos)
|
||||||
|
#define CONDITIONAL_SKIP(n) (GET_BIT(1) ? GET_BIT((n)) : 0)
|
||||||
|
|
||||||
|
int VP8EstimateQuality(const uint8_t* const data, size_t size) {
|
||||||
|
size_t pos = 0;
|
||||||
|
uint64_t bit_pos;
|
||||||
|
uint64_t sig = 0x00;
|
||||||
|
int ok = 0;
|
||||||
|
int Q = -1;
|
||||||
|
WebPBitstreamFeatures features;
|
||||||
|
|
||||||
|
if (data == NULL) return -1;
|
||||||
|
|
||||||
|
if (WebPGetFeatures(data, size, &features) != VP8_STATUS_OK) {
|
||||||
|
return -1; // invalid file
|
||||||
|
}
|
||||||
|
if (features.format == 2) return 101; // lossless
|
||||||
|
if (features.format == 0 || features.has_animation) return -1; // mixed
|
||||||
|
|
||||||
|
while (pos < size) {
|
||||||
|
sig = (sig >> 8) | ((uint64_t)data[pos++] << 40);
|
||||||
|
if ((sig >> 24) == 0x2a019dull) {
|
||||||
|
ok = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok) return -1;
|
||||||
|
if (pos + 4 > size) return -1;
|
||||||
|
|
||||||
|
// Skip main Header
|
||||||
|
// width = (data[pos + 0] | (data[pos + 1] << 8)) & 0x3fff;
|
||||||
|
// height = (data[pos + 2] | (data[pos + 3] << 8)) & 0x3fff;
|
||||||
|
pos += 4;
|
||||||
|
bit_pos = pos * 8;
|
||||||
|
|
||||||
|
GET_BIT(2); // color_space + clamp type
|
||||||
|
|
||||||
|
// Segment header
|
||||||
|
if (GET_BIT(1)) { // use_segment_
|
||||||
|
int s;
|
||||||
|
const int update_map = GET_BIT(1);
|
||||||
|
if (GET_BIT(1)) { // update data
|
||||||
|
const int absolute_delta = GET_BIT(1);
|
||||||
|
int q[4] = { 0, 0, 0, 0 };
|
||||||
|
for (s = 0; s < 4; ++s) {
|
||||||
|
if (GET_BIT(1)) {
|
||||||
|
q[s] = GET_BIT(7);
|
||||||
|
if (GET_BIT(1)) q[s] = -q[s]; // sign
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (absolute_delta) Q = q[0]; // just use the first segment's quantizer
|
||||||
|
for (s = 0; s < 4; ++s) CONDITIONAL_SKIP(7); // filter strength
|
||||||
|
}
|
||||||
|
if (update_map) {
|
||||||
|
for (s = 0; s < 3; ++s) CONDITIONAL_SKIP(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Filter header
|
||||||
|
GET_BIT(1 + 6 + 3); // simple + level + sharpness
|
||||||
|
if (GET_BIT(1)) { // use_lf_delta
|
||||||
|
if (GET_BIT(1)) { // update lf_delta?
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 4 + 4; ++n) CONDITIONAL_SKIP(6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// num partitions
|
||||||
|
GET_BIT(2);
|
||||||
|
|
||||||
|
// ParseQuant
|
||||||
|
{
|
||||||
|
const int base_q = GET_BIT(7);
|
||||||
|
/* dqy1_dc = */ CONDITIONAL_SKIP(5);
|
||||||
|
/* dqy2_dc = */ CONDITIONAL_SKIP(5);
|
||||||
|
/* dqy2_ac = */ CONDITIONAL_SKIP(5);
|
||||||
|
/* dquv_dc = */ CONDITIONAL_SKIP(5);
|
||||||
|
/* dquv_ac = */ CONDITIONAL_SKIP(5);
|
||||||
|
|
||||||
|
if (Q < 0) Q = base_q;
|
||||||
|
}
|
||||||
|
if (bit_pos == INVALID_BIT_POS) return -1;
|
||||||
|
|
||||||
|
// base mapping
|
||||||
|
Q = (127 - Q) * 100 / 127;
|
||||||
|
// correction for power-law behavior in low range
|
||||||
|
if (Q < 80) {
|
||||||
|
Q = (int)(pow(Q / 80., 1. / 0.38) * 80);
|
||||||
|
}
|
||||||
|
return Q;
|
||||||
|
}
|
||||||
50
extras/webp_quality.c
Normal file
50
extras/webp_quality.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Simple tool to roughly evaluate the quality encoding of a webp bitstream
|
||||||
|
//
|
||||||
|
// Result is a *rough* estimation of the quality. You should just consider
|
||||||
|
// the bucket it's in (q > 80? > 50? > 20?) and not take it for face value.
|
||||||
|
/*
|
||||||
|
gcc -o webp_quality webp_quality.c -O3 -I../ -L. -L../imageio \
|
||||||
|
-limageio_util -lwebpextras -lwebp -lm -lpthread
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "./extras.h"
|
||||||
|
#include "../imageio/imageio_util.h"
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
int c;
|
||||||
|
int quiet = 0;
|
||||||
|
int ok = 1;
|
||||||
|
for (c = 1; ok && c < argc; ++c) {
|
||||||
|
if (!strcmp(argv[c], "-quiet")) {
|
||||||
|
quiet = 1;
|
||||||
|
} else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
|
||||||
|
printf("webp_quality [-h][-quiet] webp_files...\n");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
const char* const filename = argv[c];
|
||||||
|
const uint8_t* data = NULL;
|
||||||
|
size_t data_size = 0;
|
||||||
|
int q;
|
||||||
|
ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||||
|
if (!ok) break;
|
||||||
|
q = VP8EstimateQuality(data, data_size);
|
||||||
|
if (!quiet) printf("[%s] ", filename);
|
||||||
|
if (q < 0) {
|
||||||
|
fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n");
|
||||||
|
ok = 0;
|
||||||
|
} else {
|
||||||
|
if (!quiet) {
|
||||||
|
printf("Estimated quality factor: %d\n", q);
|
||||||
|
} else {
|
||||||
|
printf("%d\n", q); // just print the number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free((void*)data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok ? 0 : 1;
|
||||||
|
}
|
||||||
53
imageio/Android.mk
Normal file
53
imageio/Android.mk
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# libimageio_util
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
imageio_util.c \
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||||
|
|
||||||
|
LOCAL_MODULE := imageio_util
|
||||||
|
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# libimagedec
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
image_dec.c \
|
||||||
|
jpegdec.c \
|
||||||
|
metadata.c \
|
||||||
|
pngdec.c \
|
||||||
|
tiffdec.c \
|
||||||
|
webpdec.c \
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||||
|
LOCAL_STATIC_LIBRARIES := imageio_util
|
||||||
|
|
||||||
|
LOCAL_MODULE := imagedec
|
||||||
|
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# libimageenc
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
image_enc.c \
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||||
|
LOCAL_STATIC_LIBRARIES := imageio_util
|
||||||
|
|
||||||
|
LOCAL_MODULE := imageenc
|
||||||
|
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
22
imageio/Makefile.am
Normal file
22
imageio/Makefile.am
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
|
||||||
|
noinst_LTLIBRARIES = libimageio_util.la libimagedec.la libimageenc.la
|
||||||
|
|
||||||
|
noinst_HEADERS =
|
||||||
|
noinst_HEADERS += ../src/webp/decode.h
|
||||||
|
noinst_HEADERS += ../src/webp/types.h
|
||||||
|
|
||||||
|
libimageio_util_la_SOURCES = imageio_util.c imageio_util.h
|
||||||
|
|
||||||
|
libimagedec_la_SOURCES = image_dec.c image_dec.h
|
||||||
|
libimagedec_la_SOURCES += jpegdec.c jpegdec.h
|
||||||
|
libimagedec_la_SOURCES += metadata.c metadata.h
|
||||||
|
libimagedec_la_SOURCES += pngdec.c pngdec.h
|
||||||
|
libimagedec_la_SOURCES += tiffdec.c tiffdec.h
|
||||||
|
libimagedec_la_SOURCES += webpdec.c webpdec.h
|
||||||
|
libimagedec_la_SOURCES += wicdec.c wicdec.h
|
||||||
|
libimagedec_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
|
||||||
|
libimagedec_la_CPPFLAGS += $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||||
|
|
||||||
|
libimageenc_la_SOURCES = image_enc.c image_enc.h
|
||||||
|
libimageenc_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
|
||||||
|
libimageenc_la_CPPFLAGS += $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||||
@@ -34,13 +34,28 @@ WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
|
|||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPImageReader WebPGuessImageReader(const uint8_t* const data,
|
static int FailReader(const uint8_t* const data, size_t data_size,
|
||||||
size_t data_size) {
|
struct WebPPicture* const pic,
|
||||||
switch (WebPGuessImageType(data, data_size)) {
|
int keep_alpha, struct Metadata* const metadata) {
|
||||||
|
(void)data;
|
||||||
|
(void)data_size;
|
||||||
|
(void)pic;
|
||||||
|
(void)keep_alpha;
|
||||||
|
(void)metadata;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPImageReader WebPGetImageReader(WebPInputFileFormat format) {
|
||||||
|
switch (format) {
|
||||||
case WEBP_PNG_FORMAT: return ReadPNG;
|
case WEBP_PNG_FORMAT: return ReadPNG;
|
||||||
case WEBP_JPEG_FORMAT: return ReadJPEG;
|
case WEBP_JPEG_FORMAT: return ReadJPEG;
|
||||||
case WEBP_TIFF_FORMAT: return ReadTIFF;
|
case WEBP_TIFF_FORMAT: return ReadTIFF;
|
||||||
case WEBP_WEBP_FORMAT: return ReadWebP;
|
case WEBP_WEBP_FORMAT: return ReadWebP;
|
||||||
default: return NULL;
|
default: return FailReader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebPImageReader WebPGuessImageReader(const uint8_t* const data,
|
||||||
|
size_t data_size) {
|
||||||
|
return WebPGetImageReader(WebPGuessImageType(data, data_size));
|
||||||
|
}
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_EXAMPLES_IMAGE_DEC_H_
|
#ifndef WEBP_IMAGEIO_IMAGE_DEC_H_
|
||||||
#define WEBP_EXAMPLES_IMAGE_DEC_H_
|
#define WEBP_IMAGEIO_IMAGE_DEC_H_
|
||||||
|
|
||||||
#include "webp/types.h"
|
#include "webp/types.h"
|
||||||
|
|
||||||
@@ -49,8 +49,12 @@ typedef int (*WebPImageReader)(const uint8_t* const data, size_t data_size,
|
|||||||
struct WebPPicture* const pic,
|
struct WebPPicture* const pic,
|
||||||
int keep_alpha, struct Metadata* const metadata);
|
int keep_alpha, struct Metadata* const metadata);
|
||||||
|
|
||||||
|
// Return the reader associated to a given file format.
|
||||||
|
WebPImageReader WebPGetImageReader(WebPInputFileFormat format);
|
||||||
|
|
||||||
// This function is similar to WebPGuessImageType(), but returns a
|
// This function is similar to WebPGuessImageType(), but returns a
|
||||||
// suitable reader function. Or NULL if the image can't be guessed.
|
// suitable reader function. The returned reader is never NULL, but
|
||||||
|
// unknown formats will return an always-failing valid reader.
|
||||||
WebPImageReader WebPGuessImageReader(const uint8_t* const data,
|
WebPImageReader WebPGuessImageReader(const uint8_t* const data,
|
||||||
size_t data_size);
|
size_t data_size);
|
||||||
|
|
||||||
@@ -58,4 +62,4 @@ WebPImageReader WebPGuessImageReader(const uint8_t* const data,
|
|||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_EXAMPLES_IMAGE_DEC_H_
|
#endif // WEBP_IMAGEIO_IMAGE_DEC_H_
|
||||||
591
imageio/image_enc.c
Normal file
591
imageio/image_enc.c
Normal file
@@ -0,0 +1,591 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Save image
|
||||||
|
|
||||||
|
#include "./image_enc.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef WEBP_HAVE_PNG
|
||||||
|
#include <png.h>
|
||||||
|
#include <setjmp.h> // note: this must be included *after* png.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 <ole2.h> // CreateStreamOnHGlobal()
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <wincodec.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "./imageio_util.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// PNG
|
||||||
|
|
||||||
|
#ifdef HAVE_WINCODEC_H
|
||||||
|
|
||||||
|
#define IFS(fn) \
|
||||||
|
do { \
|
||||||
|
if (SUCCEEDED(hr)) { \
|
||||||
|
hr = (fn); \
|
||||||
|
if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define MAKE_REFGUID(x) (x)
|
||||||
|
#else
|
||||||
|
#define MAKE_REFGUID(x) &(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static HRESULT CreateOutputStream(const char* out_file_name,
|
||||||
|
int write_to_mem, IStream** stream) {
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
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, 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* factory = NULL;
|
||||||
|
IWICBitmapFrameEncode* frame = NULL;
|
||||||
|
IWICBitmapEncoder* encoder = NULL;
|
||||||
|
IStream* stream = NULL;
|
||||||
|
WICPixelFormatGUID pixel_format = has_alpha ? GUID_WICPixelFormat32bppBGRA
|
||||||
|
: GUID_WICPixelFormat24bppBGR;
|
||||||
|
|
||||||
|
if (out_file_name == NULL || rgb == NULL) return E_INVALIDARG;
|
||||||
|
|
||||||
|
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?). PNG support not available. "
|
||||||
|
"Use -ppm or -pgm for available PPM and PGM formats.\n");
|
||||||
|
}
|
||||||
|
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(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 (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebPWritePNG(const char* out_file_name, int use_stdout,
|
||||||
|
const WebPDecBuffer* const buffer) {
|
||||||
|
const uint32_t width = buffer->width;
|
||||||
|
const uint32_t height = buffer->height;
|
||||||
|
uint8_t* const rgb = buffer->u.RGBA.rgba;
|
||||||
|
const int stride = buffer->u.RGBA.stride;
|
||||||
|
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||||
|
|
||||||
|
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 PNGErrorFunction(png_structp png, png_const_charp dummy) {
|
||||||
|
(void)dummy; // remove variable-unused warning
|
||||||
|
longjmp(png_jmpbuf(png), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
|
||||||
|
const uint32_t width = buffer->width;
|
||||||
|
const uint32_t height = buffer->height;
|
||||||
|
png_bytep row = buffer->u.RGBA.rgba;
|
||||||
|
const int stride = buffer->u.RGBA.stride;
|
||||||
|
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||||
|
volatile png_structp png;
|
||||||
|
volatile png_infop info;
|
||||||
|
png_uint_32 y;
|
||||||
|
|
||||||
|
if (out_file == NULL || buffer == NULL) return 0;
|
||||||
|
|
||||||
|
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||||
|
NULL, PNGErrorFunction, NULL);
|
||||||
|
if (png == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
info = png_create_info_struct(png);
|
||||||
|
if (info == NULL) {
|
||||||
|
png_destroy_write_struct((png_structpp)&png, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (setjmp(png_jmpbuf(png))) {
|
||||||
|
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
png_init_io(png, out_file);
|
||||||
|
png_set_IHDR(png, info, width, height, 8,
|
||||||
|
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
||||||
|
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
||||||
|
PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
png_write_info(png, info);
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
png_write_rows(png, &row, 1);
|
||||||
|
row += stride;
|
||||||
|
}
|
||||||
|
png_write_end(png, info);
|
||||||
|
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#else // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG
|
||||||
|
int WebPWritePNG(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
if (fout == NULL || buffer == NULL) return 0;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// PPM / PAM
|
||||||
|
|
||||||
|
static int WritePPMPAM(FILE* fout, const WebPDecBuffer* const buffer,
|
||||||
|
int alpha) {
|
||||||
|
if (fout == NULL || buffer == NULL) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
const uint32_t width = buffer->width;
|
||||||
|
const uint32_t height = buffer->height;
|
||||||
|
const uint8_t* row = buffer->u.RGBA.rgba;
|
||||||
|
const int stride = buffer->u.RGBA.stride;
|
||||||
|
const size_t bytes_per_px = alpha ? 4 : 3;
|
||||||
|
uint32_t y;
|
||||||
|
|
||||||
|
if (row == NULL) return 0;
|
||||||
|
|
||||||
|
if (alpha) {
|
||||||
|
fprintf(fout, "P7\nWIDTH %u\nHEIGHT %u\nDEPTH 4\nMAXVAL 255\n"
|
||||||
|
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
|
||||||
|
} else {
|
||||||
|
fprintf(fout, "P6\n%u %u\n255\n", width, height);
|
||||||
|
}
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
if (fwrite(row, width, bytes_per_px, fout) != bytes_per_px) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
row += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebPWritePPM(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
return WritePPMPAM(fout, buffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebPWritePAM(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
return WritePPMPAM(fout, buffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Raw PGM
|
||||||
|
|
||||||
|
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
|
||||||
|
int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
const uint32_t width = buffer->width;
|
||||||
|
const uint32_t height = buffer->height;
|
||||||
|
const uint8_t* rgba = buffer->u.RGBA.rgba;
|
||||||
|
const int stride = buffer->u.RGBA.stride;
|
||||||
|
const uint32_t bytes_per_px = 2;
|
||||||
|
uint32_t y;
|
||||||
|
|
||||||
|
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
|
||||||
|
|
||||||
|
fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height);
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
if (fwrite(rgba, width, bytes_per_px, fout) != bytes_per_px) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rgba += stride;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// BMP
|
||||||
|
|
||||||
|
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
|
||||||
|
int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||||
|
const uint32_t width = buffer->width;
|
||||||
|
const uint32_t height = buffer->height;
|
||||||
|
const uint8_t* 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 };
|
||||||
|
|
||||||
|
if (fout == NULL || buffer == NULL || rgba == NULL) return 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, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rgba += stride;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#undef BMP_HEADER_SIZE
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// TIFF
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||||
|
const uint32_t width = buffer->width;
|
||||||
|
const uint32_t height = buffer->height;
|
||||||
|
const uint8_t* 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;
|
||||||
|
|
||||||
|
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
|
||||||
|
|
||||||
|
// 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, bytes_per_px, width, fout) != width) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rgba += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef TIFF_HEADER_SIZE
|
||||||
|
#undef EXTRA_DATA_OFFSET
|
||||||
|
#undef EXTRA_DATA_SIZE
|
||||||
|
#undef NUM_IFD_ENTRIES
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Raw Alpha
|
||||||
|
|
||||||
|
int WebPWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
if (fout == NULL || buffer == NULL) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
const uint32_t width = buffer->width;
|
||||||
|
const uint32_t height = buffer->height;
|
||||||
|
const uint8_t* a = buffer->u.YUVA.a;
|
||||||
|
const int a_stride = buffer->u.YUVA.a_stride;
|
||||||
|
uint32_t y;
|
||||||
|
|
||||||
|
if (a == NULL) return 0;
|
||||||
|
|
||||||
|
fprintf(fout, "P5\n%u %u\n255\n", width, height);
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
if (fwrite(a, width, 1, fout) != 1) return 0;
|
||||||
|
a += a_stride;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// PGM with IMC4 layout
|
||||||
|
|
||||||
|
int WebPWritePGM(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
if (fout == NULL || buffer == NULL) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
const int width = buffer->width;
|
||||||
|
const int height = buffer->height;
|
||||||
|
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
|
||||||
|
const uint8_t* src_y = yuv->y;
|
||||||
|
const uint8_t* src_u = yuv->u;
|
||||||
|
const uint8_t* src_v = yuv->v;
|
||||||
|
const uint8_t* src_a = yuv->a;
|
||||||
|
const int uv_width = (width + 1) / 2;
|
||||||
|
const int uv_height = (height + 1) / 2;
|
||||||
|
const int a_height = (src_a != NULL) ? height : 0;
|
||||||
|
int ok = 1;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
if (src_y == NULL || src_u == NULL || src_v == NULL) return 0;
|
||||||
|
|
||||||
|
fprintf(fout, "P5\n%d %d\n255\n",
|
||||||
|
(width + 1) & ~1, height + uv_height + a_height);
|
||||||
|
for (y = 0; ok && y < height; ++y) {
|
||||||
|
ok &= (fwrite(src_y, width, 1, fout) == 1);
|
||||||
|
if (width & 1) fputc(0, fout); // padding byte
|
||||||
|
src_y += yuv->y_stride;
|
||||||
|
}
|
||||||
|
for (y = 0; ok && y < uv_height; ++y) {
|
||||||
|
ok &= (fwrite(src_u, uv_width, 1, fout) == 1);
|
||||||
|
ok &= (fwrite(src_v, uv_width, 1, fout) == 1);
|
||||||
|
src_u += yuv->u_stride;
|
||||||
|
src_v += yuv->v_stride;
|
||||||
|
}
|
||||||
|
for (y = 0; ok && y < a_height; ++y) {
|
||||||
|
ok &= (fwrite(src_a, width, 1, fout) == 1);
|
||||||
|
if (width & 1) fputc(0, fout); // padding byte
|
||||||
|
src_a += yuv->a_stride;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Raw YUV(A) planes
|
||||||
|
|
||||||
|
int WebPWriteYUV(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
|
if (fout == NULL || buffer == NULL) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
const int width = buffer->width;
|
||||||
|
const int height = buffer->height;
|
||||||
|
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
|
||||||
|
const uint8_t* src_y = yuv->y;
|
||||||
|
const uint8_t* src_u = yuv->u;
|
||||||
|
const uint8_t* src_v = yuv->v;
|
||||||
|
const uint8_t* src_a = yuv->a;
|
||||||
|
const int uv_width = (width + 1) / 2;
|
||||||
|
const int uv_height = (height + 1) / 2;
|
||||||
|
const int a_height = (src_a != NULL) ? height : 0;
|
||||||
|
int ok = 1;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
if (src_y == NULL || src_u == NULL || src_v == NULL) return 0;
|
||||||
|
|
||||||
|
for (y = 0; ok && y < height; ++y) {
|
||||||
|
ok &= (fwrite(src_y, width, 1, fout) == 1);
|
||||||
|
src_y += yuv->y_stride;
|
||||||
|
}
|
||||||
|
for (y = 0; ok && y < uv_height; ++y) {
|
||||||
|
ok &= (fwrite(src_u, uv_width, 1, fout) == 1);
|
||||||
|
src_u += yuv->u_stride;
|
||||||
|
}
|
||||||
|
for (y = 0; ok && y < uv_height; ++y) {
|
||||||
|
ok &= (fwrite(src_v, uv_width, 1, fout) == 1);
|
||||||
|
src_v += yuv->v_stride;
|
||||||
|
}
|
||||||
|
for (y = 0; ok && y < a_height; ++y) {
|
||||||
|
ok &= (fwrite(src_a, width, 1, fout) == 1);
|
||||||
|
src_a += yuv->a_stride;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Generic top-level call
|
||||||
|
|
||||||
|
int WebPSaveImage(const WebPDecBuffer* const buffer,
|
||||||
|
WebPOutputFileFormat format, const char* const out_file) {
|
||||||
|
FILE* fout = NULL;
|
||||||
|
int needs_open_file = 1;
|
||||||
|
const int use_stdout = (out_file != NULL) && !strcmp(out_file, "-");
|
||||||
|
int ok = 1;
|
||||||
|
|
||||||
|
if (buffer == NULL || out_file == NULL) return 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_WINCODEC_H
|
||||||
|
needs_open_file = (format != PNG);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (needs_open_file) {
|
||||||
|
fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
|
||||||
|
if (fout == NULL) {
|
||||||
|
fprintf(stderr, "Error opening output file %s\n", out_file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == PNG ||
|
||||||
|
format == RGBA || format == BGRA || format == ARGB ||
|
||||||
|
format == rgbA || format == bgrA || format == Argb) {
|
||||||
|
#ifdef HAVE_WINCODEC_H
|
||||||
|
ok &= WebPWritePNG(out_file, use_stdout, buffer);
|
||||||
|
#else
|
||||||
|
ok &= WebPWritePNG(fout, buffer);
|
||||||
|
#endif
|
||||||
|
} else if (format == PAM) {
|
||||||
|
ok &= WebPWritePAM(fout, buffer);
|
||||||
|
} else if (format == PPM || format == RGB || format == BGR) {
|
||||||
|
ok &= WebPWritePPM(fout, buffer);
|
||||||
|
} else if (format == RGBA_4444 || format == RGB_565 || format == rgbA_4444) {
|
||||||
|
ok &= WebPWrite16bAsPGM(fout, buffer);
|
||||||
|
} else if (format == BMP) {
|
||||||
|
ok &= WebPWriteBMP(fout, buffer);
|
||||||
|
} else if (format == TIFF) {
|
||||||
|
ok &= WebPWriteTIFF(fout, buffer);
|
||||||
|
} else if (format == RAW_YUV) {
|
||||||
|
ok &= WebPWriteYUV(fout, buffer);
|
||||||
|
} else if (format == PGM || format == YUV || format == YUVA) {
|
||||||
|
ok &= WebPWritePGM(fout, buffer);
|
||||||
|
} else if (format == ALPHA_PLANE_ONLY) {
|
||||||
|
ok &= WebPWriteAlphaPlane(fout, buffer);
|
||||||
|
}
|
||||||
|
if (fout != NULL && fout != stdout) {
|
||||||
|
fclose(fout);
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
96
imageio/image_enc.h
Normal file
96
imageio/image_enc.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// All-in-one library to save PNG/JPEG/WebP/TIFF/WIC images.
|
||||||
|
//
|
||||||
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
|
#ifndef WEBP_IMAGEIO_IMAGE_ENC_H_
|
||||||
|
#define WEBP_IMAGEIO_IMAGE_ENC_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "webp/config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "webp/types.h"
|
||||||
|
#include "webp/decode.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Output types
|
||||||
|
typedef enum {
|
||||||
|
PNG = 0,
|
||||||
|
PAM,
|
||||||
|
PPM,
|
||||||
|
PGM,
|
||||||
|
BMP,
|
||||||
|
TIFF,
|
||||||
|
RAW_YUV,
|
||||||
|
ALPHA_PLANE_ONLY, // this is for experimenting only
|
||||||
|
// forced colorspace output (for testing, mostly)
|
||||||
|
RGB, RGBA, BGR, BGRA, ARGB,
|
||||||
|
RGBA_4444, RGB_565,
|
||||||
|
rgbA, bgrA, Argb, rgbA_4444,
|
||||||
|
YUV, YUVA
|
||||||
|
} WebPOutputFileFormat;
|
||||||
|
|
||||||
|
// General all-purpose call.
|
||||||
|
// Most formats expect a 'buffer' containing RGBA-like samples, except
|
||||||
|
// RAW_YUV, YUV and YUVA formats.
|
||||||
|
// If 'out_file_name' is "-", data is saved to stdout.
|
||||||
|
// Returns false if an error occurred, true otherwise.
|
||||||
|
int WebPSaveImage(const WebPDecBuffer* const buffer,
|
||||||
|
WebPOutputFileFormat format, const char* const out_file_name);
|
||||||
|
|
||||||
|
// Save to PNG.
|
||||||
|
#ifdef HAVE_WINCODEC_H
|
||||||
|
int WebPWritePNG(const char* out_file_name, int use_stdout,
|
||||||
|
const struct WebPDecBuffer* const buffer);
|
||||||
|
#else
|
||||||
|
int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Save to PPM format (RGB, no alpha)
|
||||||
|
int WebPWritePPM(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
// Save to PAM format (= PPM + alpha)
|
||||||
|
int WebPWritePAM(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purposes.
|
||||||
|
int WebPWrite16bAsPGM(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
// Save as BMP
|
||||||
|
int WebPWriteBMP(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
// Save as TIFF
|
||||||
|
int WebPWriteTIFF(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
// Save the ALPHA plane (only) as a PGM
|
||||||
|
int WebPWriteAlphaPlane(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
// Save as YUV samples as PGM format (using IMC4 layout).
|
||||||
|
// See: http://www.fourcc.org/yuv.php#IMC4.
|
||||||
|
// (very convenient format for viewing the samples, esp. for odd dimensions).
|
||||||
|
int WebPWritePGM(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
// Save YUV(A) planes sequentially (raw dump)
|
||||||
|
int WebPWriteYUV(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
// Save 16b mode (RGBA4444, RGB565, ...) as PGM format, for debugging purposes.
|
||||||
|
int WebPWrite16bAsPGM(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WEBP_IMAGEIO_IMAGE_ENC_H_
|
||||||
143
imageio/imageio_util.c
Normal file
143
imageio/imageio_util.c
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Utility functions used by the image decoders.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "./imageio_util.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <fcntl.h> // for _O_BINARY
|
||||||
|
#include <io.h> // for _setmode()
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File I/O
|
||||||
|
|
||||||
|
FILE* ImgIoUtilSetBinaryMode(FILE* file) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (_setmode(_fileno(file), _O_BINARY) == -1) {
|
||||||
|
fprintf(stderr, "Failed to reopen file in O_BINARY mode.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
|
||||||
|
static const size_t kBlockSize = 16384; // default initial size
|
||||||
|
size_t max_size = 0;
|
||||||
|
size_t size = 0;
|
||||||
|
uint8_t* input = NULL;
|
||||||
|
|
||||||
|
if (data == NULL || data_size == NULL) return 0;
|
||||||
|
*data = NULL;
|
||||||
|
*data_size = 0;
|
||||||
|
|
||||||
|
if (!ImgIoUtilSetBinaryMode(stdin)) return 0;
|
||||||
|
|
||||||
|
while (!feof(stdin)) {
|
||||||
|
// We double the buffer size each time and read as much as possible.
|
||||||
|
const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
|
||||||
|
void* const new_data = realloc(input, max_size + extra_size);
|
||||||
|
if (new_data == NULL) goto Error;
|
||||||
|
input = (uint8_t*)new_data;
|
||||||
|
max_size += extra_size;
|
||||||
|
size += fread(input + size, 1, extra_size, stdin);
|
||||||
|
if (size < max_size) break;
|
||||||
|
}
|
||||||
|
if (ferror(stdin)) goto Error;
|
||||||
|
*data = input;
|
||||||
|
*data_size = size;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
Error:
|
||||||
|
free(input);
|
||||||
|
fprintf(stderr, "Could not read from stdin\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImgIoUtilReadFile(const char* const file_name,
|
||||||
|
const uint8_t** data, size_t* data_size) {
|
||||||
|
int ok;
|
||||||
|
void* file_data;
|
||||||
|
size_t file_size;
|
||||||
|
FILE* in;
|
||||||
|
const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
|
||||||
|
|
||||||
|
if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size);
|
||||||
|
|
||||||
|
if (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 ImgIoUtilWriteFile(const char* const file_name,
|
||||||
|
const uint8_t* data, size_t data_size) {
|
||||||
|
int ok;
|
||||||
|
FILE* out;
|
||||||
|
const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
out = to_stdout ? stdout : 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);
|
||||||
|
if (out != stdout) fclose(out);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
|
||||||
|
uint8_t* dst, int dst_stride, int width, int height) {
|
||||||
|
while (height-- > 0) {
|
||||||
|
memcpy(dst, src, width * sizeof(*dst));
|
||||||
|
src += src_stride;
|
||||||
|
dst += dst_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
|
||||||
|
const uint64_t total_size = nmemb * size;
|
||||||
|
return (total_size == (size_t)total_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
61
imageio/imageio_util.h
Normal file
61
imageio/imageio_util.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Utility functions used by the image decoders.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef WEBP_IMAGEIO_IMAGEIO_UTIL_H_
|
||||||
|
#define WEBP_IMAGEIO_IMAGEIO_UTIL_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "webp/types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// File I/O
|
||||||
|
|
||||||
|
// Reopen file in binary (O_BINARY) mode.
|
||||||
|
// Returns 'file' on success, NULL otherwise.
|
||||||
|
FILE* ImgIoUtilSetBinaryMode(FILE* file);
|
||||||
|
|
||||||
|
// 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().
|
||||||
|
// If 'file_name' is NULL or equal to "-", input is read from stdin by calling
|
||||||
|
// the function ImgIoUtilReadFromStdin().
|
||||||
|
int ImgIoUtilReadFile(const char* const file_name,
|
||||||
|
const uint8_t** data, size_t* data_size);
|
||||||
|
|
||||||
|
// Same as ImgIoUtilReadFile(), but reads until EOF from stdin instead.
|
||||||
|
int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size);
|
||||||
|
|
||||||
|
// Write a data segment into a file named 'file_name'. Returns true if ok.
|
||||||
|
// If 'file_name' is NULL or equal to "-", output is written to stdout.
|
||||||
|
int ImgIoUtilWriteFile(const char* const file_name,
|
||||||
|
const uint8_t* data, size_t data_size);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Copy width x height pixels from 'src' to 'dst' honoring the strides.
|
||||||
|
void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
|
||||||
|
uint8_t* dst, int dst_stride, int width, int height);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Returns 0 in case of overflow of nmemb * size.
|
||||||
|
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WEBP_IMAGEIO_IMAGEIO_UTIL_H_
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
#include "./example_util.h"
|
#include "./imageio_util.h"
|
||||||
#include "./metadata.h"
|
#include "./metadata.h"
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -222,10 +222,10 @@ static void ContextInit(j_decompress_ptr cinfo) {
|
|||||||
ctx->pub.bytes_in_buffer = ctx->data_size;
|
ctx->pub.bytes_in_buffer = ctx->data_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ContextFill(j_decompress_ptr cinfo) {
|
static boolean ContextFill(j_decompress_ptr cinfo) {
|
||||||
// we shouldn't get here.
|
// we shouldn't get here.
|
||||||
ERREXIT(cinfo, JERR_FILE_READ);
|
ERREXIT(cinfo, JERR_FILE_READ);
|
||||||
return 0;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ContextSkip(j_decompress_ptr cinfo, long jump_size) {
|
static void ContextSkip(j_decompress_ptr cinfo, long jump_size) {
|
||||||
@@ -258,13 +258,16 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
|||||||
WebPPicture* const pic, int keep_alpha,
|
WebPPicture* const pic, int keep_alpha,
|
||||||
Metadata* const metadata) {
|
Metadata* const metadata) {
|
||||||
volatile int ok = 0;
|
volatile int ok = 0;
|
||||||
int stride, width, height;
|
int width, height;
|
||||||
|
int64_t stride;
|
||||||
volatile struct jpeg_decompress_struct dinfo;
|
volatile struct jpeg_decompress_struct dinfo;
|
||||||
struct my_error_mgr jerr;
|
struct my_error_mgr jerr;
|
||||||
uint8_t* volatile rgb = NULL;
|
uint8_t* volatile rgb = NULL;
|
||||||
JSAMPROW buffer[1];
|
JSAMPROW buffer[1];
|
||||||
JPEGReadContext ctx;
|
JPEGReadContext ctx;
|
||||||
|
|
||||||
|
if (data == NULL || data_size == 0 || pic == NULL) return 0;
|
||||||
|
|
||||||
(void)keep_alpha;
|
(void)keep_alpha;
|
||||||
memset(&ctx, 0, sizeof(ctx));
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
ctx.data = data;
|
ctx.data = data;
|
||||||
@@ -297,9 +300,14 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
|||||||
|
|
||||||
width = dinfo.output_width;
|
width = dinfo.output_width;
|
||||||
height = dinfo.output_height;
|
height = dinfo.output_height;
|
||||||
stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb);
|
stride = (int64_t)dinfo.output_width * dinfo.output_components * sizeof(*rgb);
|
||||||
|
|
||||||
rgb = (uint8_t*)malloc(stride * height);
|
if (stride != (int)stride ||
|
||||||
|
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb = (uint8_t*)malloc((size_t)stride * height);
|
||||||
if (rgb == NULL) {
|
if (rgb == NULL) {
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
@@ -326,7 +334,7 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
|||||||
// WebP conversion.
|
// WebP conversion.
|
||||||
pic->width = width;
|
pic->width = width;
|
||||||
pic->height = height;
|
pic->height = height;
|
||||||
ok = WebPPictureImportRGB(pic, rgb, stride);
|
ok = WebPPictureImportRGB(pic, rgb, (int)stride);
|
||||||
if (!ok) goto Error;
|
if (!ok) goto Error;
|
||||||
|
|
||||||
End:
|
End:
|
||||||
@@ -9,10 +9,9 @@
|
|||||||
//
|
//
|
||||||
// JPEG decode.
|
// JPEG decode.
|
||||||
|
|
||||||
#ifndef WEBP_EXAMPLES_JPEGDEC_H_
|
#ifndef WEBP_IMAGEIO_JPEGDEC_H_
|
||||||
#define WEBP_EXAMPLES_JPEGDEC_H_
|
#define WEBP_IMAGEIO_JPEGDEC_H_
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "webp/types.h"
|
#include "webp/types.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -35,4 +34,4 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
|||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_EXAMPLES_JPEGDEC_H_
|
#endif // WEBP_IMAGEIO_JPEGDEC_H_
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
// Metadata types and functions.
|
// Metadata types and functions.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef WEBP_EXAMPLES_METADATA_H_
|
#ifndef WEBP_IMAGEIO_METADATA_H_
|
||||||
#define WEBP_EXAMPLES_METADATA_H_
|
#define WEBP_IMAGEIO_METADATA_H_
|
||||||
|
|
||||||
#include "webp/types.h"
|
#include "webp/types.h"
|
||||||
|
|
||||||
@@ -44,4 +44,4 @@ int MetadataCopy(const char* metadata, size_t metadata_len,
|
|||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_EXAMPLES_METADATA_H_
|
#endif // WEBP_IMAGEIO_METADATA_H_
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
#include "./example_util.h"
|
#include "./imageio_util.h"
|
||||||
#include "./metadata.h"
|
#include "./metadata.h"
|
||||||
|
|
||||||
static void PNGAPI error_function(png_structp png, png_const_charp error) {
|
static void PNGAPI error_function(png_structp png, png_const_charp error) {
|
||||||
@@ -217,9 +217,11 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
|||||||
int p;
|
int p;
|
||||||
volatile int ok = 0;
|
volatile int ok = 0;
|
||||||
png_uint_32 width, height, y;
|
png_uint_32 width, height, y;
|
||||||
png_uint_32 stride;
|
int64_t stride;
|
||||||
uint8_t* volatile rgb = NULL;
|
uint8_t* volatile rgb = NULL;
|
||||||
|
|
||||||
|
if (data == NULL || data_size == 0 || pic == NULL) return 0;
|
||||||
|
|
||||||
context.data = data;
|
context.data = data;
|
||||||
context.data_size = data_size;
|
context.data_size = data_size;
|
||||||
|
|
||||||
@@ -270,13 +272,20 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
|||||||
|
|
||||||
num_passes = png_set_interlace_handling(png);
|
num_passes = png_set_interlace_handling(png);
|
||||||
png_read_update_info(png, info);
|
png_read_update_info(png, info);
|
||||||
stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
|
|
||||||
rgb = (uint8_t*)malloc(stride * height);
|
stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb);
|
||||||
|
if (stride != (int)stride ||
|
||||||
|
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb = (uint8_t*)malloc((size_t)stride * height);
|
||||||
if (rgb == NULL) goto Error;
|
if (rgb == NULL) goto Error;
|
||||||
for (p = 0; p < num_passes; ++p) {
|
for (p = 0; p < num_passes; ++p) {
|
||||||
|
png_bytep row = rgb;
|
||||||
for (y = 0; y < height; ++y) {
|
for (y = 0; y < height; ++y) {
|
||||||
png_bytep row = (png_bytep)(rgb + y * stride);
|
|
||||||
png_read_rows(png, &row, NULL, 1);
|
png_read_rows(png, &row, NULL, 1);
|
||||||
|
row += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
png_read_end(png, end_info);
|
png_read_end(png, end_info);
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
//
|
//
|
||||||
// PNG decode.
|
// PNG decode.
|
||||||
|
|
||||||
#ifndef WEBP_EXAMPLES_PNGDEC_H_
|
#ifndef WEBP_IMAGEIO_PNGDEC_H_
|
||||||
#define WEBP_EXAMPLES_PNGDEC_H_
|
#define WEBP_IMAGEIO_PNGDEC_H_
|
||||||
|
|
||||||
#include "webp/types.h"
|
#include "webp/types.h"
|
||||||
|
|
||||||
@@ -34,4 +34,4 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
|||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_EXAMPLES_PNGDEC_H_
|
#endif // WEBP_IMAGEIO_PNGDEC_H_
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <tiffio.h>
|
#include <tiffio.h>
|
||||||
|
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
|
#include "./imageio_util.h"
|
||||||
#include "./metadata.h"
|
#include "./metadata.h"
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -119,14 +120,18 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
|||||||
WebPPicture* const pic, int keep_alpha,
|
WebPPicture* const pic, int keep_alpha,
|
||||||
Metadata* const metadata) {
|
Metadata* const metadata) {
|
||||||
MyData my_data = { data, (toff_t)data_size, 0 };
|
MyData my_data = { data, (toff_t)data_size, 0 };
|
||||||
TIFF* const tif = TIFFClientOpen("Memory", "r", &my_data,
|
TIFF* tif;
|
||||||
MyRead, MyRead, MySeek, MyClose,
|
|
||||||
MySize, MyMapFile, MyUnmapFile);
|
|
||||||
uint32 width, height;
|
uint32 width, height;
|
||||||
uint32* raster;
|
uint32* raster;
|
||||||
|
int64_t alloc_size;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
tdir_t dircount;
|
tdir_t dircount;
|
||||||
|
|
||||||
|
if (data == NULL || data_size == 0 || pic == NULL) return 0;
|
||||||
|
|
||||||
|
tif = TIFFClientOpen("Memory", "r", &my_data,
|
||||||
|
MyRead, MyRead, MySeek, MyClose,
|
||||||
|
MySize, MyMapFile, MyUnmapFile);
|
||||||
if (tif == NULL) {
|
if (tif == NULL) {
|
||||||
fprintf(stderr, "Error! Cannot parse TIFF file\n");
|
fprintf(stderr, "Error! Cannot parse TIFF file\n");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -144,7 +149,16 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
|||||||
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
|
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster));
|
|
||||||
|
if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)width * height,
|
||||||
|
sizeof(*raster))) {
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
// _Tiffmalloc uses a signed type for size.
|
||||||
|
alloc_size = (int64_t)((uint64_t)width * height * sizeof(*raster));
|
||||||
|
if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
|
||||||
|
|
||||||
|
raster = (uint32*)_TIFFmalloc((tsize_t)alloc_size);
|
||||||
if (raster != NULL) {
|
if (raster != NULL) {
|
||||||
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
|
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
|
||||||
ORIENTATION_TOPLEFT, 1)) {
|
ORIENTATION_TOPLEFT, 1)) {
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
//
|
//
|
||||||
// TIFF decode.
|
// TIFF decode.
|
||||||
|
|
||||||
#ifndef WEBP_EXAMPLES_TIFFDEC_H_
|
#ifndef WEBP_IMAGEIO_TIFFDEC_H_
|
||||||
#define WEBP_EXAMPLES_TIFFDEC_H_
|
#define WEBP_IMAGEIO_TIFFDEC_H_
|
||||||
|
|
||||||
#include "webp/types.h"
|
#include "webp/types.h"
|
||||||
|
|
||||||
@@ -34,4 +34,4 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
|||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_EXAMPLES_TIFFDEC_H_
|
#endif // WEBP_IMAGEIO_TIFFDEC_H_
|
||||||
190
imageio/webpdec.c
Normal file
190
imageio/webpdec.c
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// WebP decode.
|
||||||
|
|
||||||
|
#include "./webpdec.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "webp/decode.h"
|
||||||
|
#include "webp/encode.h"
|
||||||
|
#include "./imageio_util.h"
|
||||||
|
#include "./metadata.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// WebP decoding
|
||||||
|
|
||||||
|
static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
|
||||||
|
"OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
|
||||||
|
"UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
|
||||||
|
};
|
||||||
|
|
||||||
|
static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
|
||||||
|
if (config->input.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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintWebPError(const char* const in_file, int status) {
|
||||||
|
fprintf(stderr, "Decoding of %s failed.\n", in_file);
|
||||||
|
fprintf(stderr, "Status: %d", status);
|
||||||
|
if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
|
||||||
|
fprintf(stderr, "(%s)", kStatusMessages[status]);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int LoadWebP(const char* const in_file,
|
||||||
|
const uint8_t** data, size_t* data_size,
|
||||||
|
WebPBitstreamFeatures* bitstream) {
|
||||||
|
VP8StatusCode status;
|
||||||
|
WebPBitstreamFeatures local_features;
|
||||||
|
if (!ImgIoUtilReadFile(in_file, data, data_size)) return 0;
|
||||||
|
|
||||||
|
if (bitstream == NULL) {
|
||||||
|
bitstream = &local_features;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = WebPGetFeatures(*data, *data_size, bitstream);
|
||||||
|
if (status != VP8_STATUS_OK) {
|
||||||
|
free((void*)*data);
|
||||||
|
*data = NULL;
|
||||||
|
*data_size = 0;
|
||||||
|
PrintWebPError(in_file, status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
|
||||||
|
WebPDecoderConfig* const config) {
|
||||||
|
if (config == NULL) return VP8_STATUS_INVALID_PARAM;
|
||||||
|
PrintAnimationWarning(config);
|
||||||
|
return WebPDecode(data, data_size, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
VP8StatusCode DecodeWebPIncremental(
|
||||||
|
const uint8_t* const data, size_t data_size,
|
||||||
|
WebPDecoderConfig* const config) {
|
||||||
|
VP8StatusCode status = VP8_STATUS_OK;
|
||||||
|
if (config == NULL) return VP8_STATUS_INVALID_PARAM;
|
||||||
|
|
||||||
|
PrintAnimationWarning(config);
|
||||||
|
|
||||||
|
// Decoding call.
|
||||||
|
{
|
||||||
|
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
|
||||||
|
if (idec == NULL) {
|
||||||
|
fprintf(stderr, "Failed during WebPINewDecoder().\n");
|
||||||
|
return VP8_STATUS_OUT_OF_MEMORY;
|
||||||
|
} else {
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
size_t size = 0;
|
||||||
|
const size_t incr = 2 + (data_size / 20);
|
||||||
|
while (size < data_size) {
|
||||||
|
size_t next_size = size + (rand() % incr);
|
||||||
|
if (next_size > data_size) next_size = data_size;
|
||||||
|
status = WebPIUpdate(idec, data, next_size);
|
||||||
|
if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) break;
|
||||||
|
size = next_size;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
status = WebPIUpdate(idec, data, data_size);
|
||||||
|
#endif
|
||||||
|
WebPIDelete(idec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int ReadWebP(const uint8_t* const data, size_t data_size,
|
||||||
|
WebPPicture* const pic,
|
||||||
|
int keep_alpha, Metadata* const metadata) {
|
||||||
|
int ok = 0;
|
||||||
|
VP8StatusCode status = VP8_STATUS_OK;
|
||||||
|
WebPDecoderConfig config;
|
||||||
|
WebPDecBuffer* const output_buffer = &config.output;
|
||||||
|
WebPBitstreamFeatures* const bitstream = &config.input;
|
||||||
|
|
||||||
|
if (data == NULL || data_size == 0 || pic == NULL) return 0;
|
||||||
|
|
||||||
|
// TODO(jzern): add Exif/XMP/ICC extraction.
|
||||||
|
if (metadata != NULL) {
|
||||||
|
fprintf(stderr, "Warning: metadata extraction from WebP is unsupported.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WebPInitDecoderConfig(&config)) {
|
||||||
|
fprintf(stderr, "Library version mismatch!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = WebPGetFeatures(data, data_size, bitstream);
|
||||||
|
if (status != VP8_STATUS_OK) {
|
||||||
|
PrintWebPError("input data", status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const int has_alpha = keep_alpha && bitstream->has_alpha;
|
||||||
|
if (pic->use_argb) {
|
||||||
|
output_buffer->colorspace = has_alpha ? MODE_RGBA : MODE_RGB;
|
||||||
|
} else {
|
||||||
|
output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = DecodeWebP(data, data_size, &config);
|
||||||
|
if (status == VP8_STATUS_OK) {
|
||||||
|
pic->width = output_buffer->width;
|
||||||
|
pic->height = output_buffer->height;
|
||||||
|
if (pic->use_argb) {
|
||||||
|
const uint8_t* const rgba = output_buffer->u.RGBA.rgba;
|
||||||
|
const int stride = output_buffer->u.RGBA.stride;
|
||||||
|
ok = has_alpha ? WebPPictureImportRGBA(pic, rgba, stride)
|
||||||
|
: WebPPictureImportRGB(pic, rgba, stride);
|
||||||
|
} else {
|
||||||
|
pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
|
||||||
|
ok = WebPPictureAlloc(pic);
|
||||||
|
if (!ok) {
|
||||||
|
status = VP8_STATUS_OUT_OF_MEMORY;
|
||||||
|
} else {
|
||||||
|
const WebPYUVABuffer* const yuva = &output_buffer->u.YUVA;
|
||||||
|
const int uv_width = (pic->width + 1) >> 1;
|
||||||
|
const int uv_height = (pic->height + 1) >> 1;
|
||||||
|
ImgIoUtilCopyPlane(yuva->y, yuva->y_stride,
|
||||||
|
pic->y, pic->y_stride, pic->width, pic->height);
|
||||||
|
ImgIoUtilCopyPlane(yuva->u, yuva->u_stride,
|
||||||
|
pic->u, pic->uv_stride, uv_width, uv_height);
|
||||||
|
ImgIoUtilCopyPlane(yuva->v, yuva->v_stride,
|
||||||
|
pic->v, pic->uv_stride, uv_width, uv_height);
|
||||||
|
if (has_alpha) {
|
||||||
|
ImgIoUtilCopyPlane(yuva->a, yuva->a_stride,
|
||||||
|
pic->a, pic->a_stride, pic->width, pic->height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != VP8_STATUS_OK) {
|
||||||
|
PrintWebPError("input data", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPFreeDecBuffer(output_buffer);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
67
imageio/webpdec.h
Normal file
67
imageio/webpdec.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// WebP decode.
|
||||||
|
|
||||||
|
#ifndef WEBP_IMAGEIO_WEBPDEC_H_
|
||||||
|
#define WEBP_IMAGEIO_WEBPDEC_H_
|
||||||
|
|
||||||
|
#include "webp/decode.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Metadata;
|
||||||
|
struct WebPPicture;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// WebP decoding
|
||||||
|
|
||||||
|
// Prints an informative error message regarding decode failure of 'in_file'.
|
||||||
|
// 'status' is treated as a VP8StatusCode and if valid will be printed as a
|
||||||
|
// text string.
|
||||||
|
void PrintWebPError(const char* const in_file, int status);
|
||||||
|
|
||||||
|
// Reads a WebP from 'in_file', returning the contents and size in 'data' and
|
||||||
|
// 'data_size'. If not NULL, 'bitstream' is populated using WebPGetFeatures().
|
||||||
|
// Returns true on success.
|
||||||
|
int LoadWebP(const char* const in_file,
|
||||||
|
const uint8_t** data, size_t* data_size,
|
||||||
|
WebPBitstreamFeatures* bitstream);
|
||||||
|
|
||||||
|
// Decodes the WebP contained in 'data'.
|
||||||
|
// 'config' is a structure previously initialized by WebPInitDecoderConfig().
|
||||||
|
// 'config->output' should have the desired colorspace selected.
|
||||||
|
// Returns the decoder status. On success 'config->output' will contain the
|
||||||
|
// decoded picture.
|
||||||
|
VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
|
||||||
|
WebPDecoderConfig* const config);
|
||||||
|
|
||||||
|
// Same as DecodeWebP(), but using the incremental decoder.
|
||||||
|
VP8StatusCode DecodeWebPIncremental(
|
||||||
|
const uint8_t* const data, size_t data_size,
|
||||||
|
WebPDecoderConfig* const config);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Reads a WebP from 'in_file', returning the decoded output in 'pic'.
|
||||||
|
// Output is RGBA or YUVA, depending on pic->use_argb value.
|
||||||
|
// If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA
|
||||||
|
// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.
|
||||||
|
// Returns true on success.
|
||||||
|
int ReadWebP(const uint8_t* const data, size_t data_size,
|
||||||
|
struct WebPPicture* const pic,
|
||||||
|
int keep_alpha, struct Metadata* const metadata);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WEBP_IMAGEIO_WEBPDEC_H_
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
#include <wincodec.h>
|
#include <wincodec.h>
|
||||||
|
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
#include "./example_util.h"
|
#include "./imageio_util.h"
|
||||||
#include "./metadata.h"
|
#include "./metadata.h"
|
||||||
|
|
||||||
#define IFS(fn) \
|
#define IFS(fn) \
|
||||||
@@ -88,7 +88,7 @@ static HRESULT OpenInputStream(const char* filename, IStream** stream) {
|
|||||||
if (!strcmp(filename, "-")) {
|
if (!strcmp(filename, "-")) {
|
||||||
const uint8_t* data = NULL;
|
const uint8_t* data = NULL;
|
||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
const int ok = ExUtilReadFile(filename, &data, &data_size);
|
const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size);
|
HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size);
|
||||||
if (image != NULL) {
|
if (image != NULL) {
|
||||||
@@ -274,7 +274,9 @@ int ReadPictureWithWIC(const char* const filename,
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
int has_alpha = 0;
|
int has_alpha = 0;
|
||||||
int stride;
|
int64_t stride;
|
||||||
|
|
||||||
|
if (filename == NULL || pic == NULL) return 0;
|
||||||
|
|
||||||
IFS(CoInitialize(NULL));
|
IFS(CoInitialize(NULL));
|
||||||
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
|
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
|
||||||
@@ -334,14 +336,19 @@ int ReadPictureWithWIC(const char* const filename,
|
|||||||
|
|
||||||
// Decode.
|
// Decode.
|
||||||
IFS(IWICFormatConverter_GetSize(converter, &width, &height));
|
IFS(IWICFormatConverter_GetSize(converter, &width, &height));
|
||||||
stride = importer->bytes_per_pixel * width * sizeof(*rgb);
|
stride = (int64_t)importer->bytes_per_pixel * width * sizeof(*rgb);
|
||||||
|
if (stride != (int)stride ||
|
||||||
|
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
|
||||||
|
hr = E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
rgb = (BYTE*)malloc(stride * height);
|
rgb = (BYTE*)malloc((size_t)stride * height);
|
||||||
if (rgb == NULL)
|
if (rgb == NULL)
|
||||||
hr = E_OUTOFMEMORY;
|
hr = E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
IFS(IWICFormatConverter_CopyPixels(converter, NULL,
|
IFS(IWICFormatConverter_CopyPixels(converter, NULL,
|
||||||
stride, stride * height, rgb));
|
(UINT)stride, (UINT)stride * height, rgb));
|
||||||
|
|
||||||
// WebP conversion.
|
// WebP conversion.
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
@@ -349,7 +356,7 @@ int ReadPictureWithWIC(const char* const filename,
|
|||||||
pic->width = width;
|
pic->width = width;
|
||||||
pic->height = height;
|
pic->height = height;
|
||||||
pic->use_argb = 1; // For WIC, we always force to argb
|
pic->use_argb = 1; // For WIC, we always force to argb
|
||||||
ok = importer->import(pic, rgb, stride);
|
ok = importer->import(pic, rgb, (int)stride);
|
||||||
if (!ok) hr = E_FAIL;
|
if (!ok) hr = E_FAIL;
|
||||||
}
|
}
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
//
|
//
|
||||||
// Windows Imaging Component (WIC) decode.
|
// Windows Imaging Component (WIC) decode.
|
||||||
|
|
||||||
#ifndef WEBP_EXAMPLES_WICDEC_H_
|
#ifndef WEBP_IMAGEIO_WICDEC_H_
|
||||||
#define WEBP_EXAMPLES_WICDEC_H_
|
#define WEBP_IMAGEIO_WICDEC_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -31,4 +31,4 @@ int ReadPictureWithWIC(const char* const filename,
|
|||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_EXAMPLES_WICDEC_H_
|
#endif // WEBP_IMAGEIO_WICDEC_H_
|
||||||
27
iosbuild.sh
27
iosbuild.sh
@@ -1,10 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# This script generates 'WebP.framework'. An iOS app can decode WebP images
|
# This script generates 'WebP.framework' and 'WebPDecoder.framework'. An iOS
|
||||||
# by including 'WebP.framework'.
|
# app can decode WebP images by including 'WebPDecoder.framework' and both
|
||||||
|
# encode and decode WebP images by including 'WebP.framework'.
|
||||||
#
|
#
|
||||||
# Run ./iosbuild.sh to generate 'WebP.framework' under the current directory
|
# Run ./iosbuild.sh to generate the frameworks under the current directory
|
||||||
# (previous build will be erased if it exists).
|
# (the previous build will be erased if it exists).
|
||||||
#
|
#
|
||||||
# This script is inspired by the build script written by Carson McDonald.
|
# 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/).
|
# (http://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
|
||||||
@@ -33,10 +34,12 @@ readonly SRCDIR=$(dirname $0)
|
|||||||
readonly TOPDIR=$(pwd)
|
readonly TOPDIR=$(pwd)
|
||||||
readonly BUILDDIR="${TOPDIR}/iosbuild"
|
readonly BUILDDIR="${TOPDIR}/iosbuild"
|
||||||
readonly TARGETDIR="${TOPDIR}/WebP.framework"
|
readonly TARGETDIR="${TOPDIR}/WebP.framework"
|
||||||
|
readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework"
|
||||||
readonly DEVELOPER=$(xcode-select --print-path)
|
readonly DEVELOPER=$(xcode-select --print-path)
|
||||||
readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
|
readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
|
||||||
readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
|
readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
|
||||||
LIBLIST=''
|
LIBLIST=''
|
||||||
|
DECLIBLIST=''
|
||||||
|
|
||||||
if [[ -z "${SDK}" ]]; then
|
if [[ -z "${SDK}" ]]; then
|
||||||
echo "iOS SDK not available"
|
echo "iOS SDK not available"
|
||||||
@@ -50,10 +53,8 @@ else
|
|||||||
echo "iOS SDK Version ${SDK}"
|
echo "iOS SDK Version ${SDK}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf ${BUILDDIR}
|
rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR}
|
||||||
rm -rf ${TARGETDIR}
|
mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/
|
||||||
mkdir -p ${BUILDDIR}
|
|
||||||
mkdir -p ${TARGETDIR}/Headers/
|
|
||||||
|
|
||||||
if [[ ! -e ${SRCDIR}/configure ]]; then
|
if [[ ! -e ${SRCDIR}/configure ]]; then
|
||||||
if ! (cd ${SRCDIR} && sh autogen.sh); then
|
if ! (cd ${SRCDIR} && sh autogen.sh); then
|
||||||
@@ -107,12 +108,13 @@ for PLATFORM in ${PLATFORMS}; do
|
|||||||
CFLAGS="${CFLAGS}"
|
CFLAGS="${CFLAGS}"
|
||||||
set +x
|
set +x
|
||||||
|
|
||||||
# run make only in the src/ directory to create libwebpdecoder.a
|
# run make only in the src/ directory to create libwebp.a/libwebpdecoder.a
|
||||||
cd src/
|
cd src/
|
||||||
make V=0
|
make V=0
|
||||||
make install
|
make install
|
||||||
|
|
||||||
LIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
|
LIBLIST+=" ${ROOTDIR}/lib/libwebp.a"
|
||||||
|
DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
cd ..
|
cd ..
|
||||||
@@ -120,5 +122,8 @@ for PLATFORM in ${PLATFORMS}; do
|
|||||||
export PATH=${OLDPATH}
|
export PATH=${OLDPATH}
|
||||||
done
|
done
|
||||||
|
|
||||||
cp -a ${SRCDIR}/src/webp/*.h ${TARGETDIR}/Headers/
|
cp -a ${SRCDIR}/src/webp/{decode,encode,types}.h ${TARGETDIR}/Headers/
|
||||||
${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP
|
${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP
|
||||||
|
|
||||||
|
cp -a ${SRCDIR}/src/webp/{decode,types}.h ${DECTARGETDIR}/Headers/
|
||||||
|
${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder
|
||||||
|
|||||||
250
makefile.unix
250
makefile.unix
@@ -3,7 +3,7 @@
|
|||||||
# It will not install the libraries system-wide, but just create the 'cwebp'
|
# It will not install the libraries system-wide, but just create the 'cwebp'
|
||||||
# and 'dwebp' tools in the examples/ directory, along with the static
|
# and 'dwebp' tools in the examples/ directory, along with the static
|
||||||
# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a',
|
# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a',
|
||||||
# 'src/demux/libwebpdemux.a' and 'src/libwebpextras.a'.
|
# 'src/demux/libwebpdemux.a' and 'extras/libwebpextras.a'.
|
||||||
#
|
#
|
||||||
# To build the library and examples, use:
|
# To build the library and examples, use:
|
||||||
# make -f makefile.unix
|
# make -f makefile.unix
|
||||||
@@ -113,16 +113,16 @@ ANIM_UTIL_OBJS = \
|
|||||||
examples/anim_util.o \
|
examples/anim_util.o \
|
||||||
|
|
||||||
DEC_OBJS = \
|
DEC_OBJS = \
|
||||||
src/dec/alpha.o \
|
src/dec/alpha_dec.o \
|
||||||
src/dec/buffer.o \
|
src/dec/buffer_dec.o \
|
||||||
src/dec/frame.o \
|
src/dec/frame_dec.o \
|
||||||
src/dec/idec.o \
|
src/dec/idec_dec.o \
|
||||||
src/dec/io.o \
|
src/dec/io_dec.o \
|
||||||
src/dec/quant.o \
|
src/dec/quant_dec.o \
|
||||||
src/dec/tree.o \
|
src/dec/tree_dec.o \
|
||||||
src/dec/vp8.o \
|
src/dec/vp8_dec.o \
|
||||||
src/dec/vp8l.o \
|
src/dec/vp8l_dec.o \
|
||||||
src/dec/webp.o \
|
src/dec/webp_dec.o \
|
||||||
|
|
||||||
DEMUX_OBJS = \
|
DEMUX_OBJS = \
|
||||||
src/demux/anim_decode.o \
|
src/demux/anim_decode.o \
|
||||||
@@ -131,6 +131,7 @@ DEMUX_OBJS = \
|
|||||||
DSP_DEC_OBJS = \
|
DSP_DEC_OBJS = \
|
||||||
src/dsp/alpha_processing.o \
|
src/dsp/alpha_processing.o \
|
||||||
src/dsp/alpha_processing_mips_dsp_r2.o \
|
src/dsp/alpha_processing_mips_dsp_r2.o \
|
||||||
|
src/dsp/alpha_processing_neon.o \
|
||||||
src/dsp/alpha_processing_sse2.o \
|
src/dsp/alpha_processing_sse2.o \
|
||||||
src/dsp/alpha_processing_sse41.o \
|
src/dsp/alpha_processing_sse41.o \
|
||||||
src/dsp/cpu.o \
|
src/dsp/cpu.o \
|
||||||
@@ -144,18 +145,23 @@ DSP_DEC_OBJS = \
|
|||||||
src/dsp/dec_sse41.o \
|
src/dsp/dec_sse41.o \
|
||||||
src/dsp/filters.o \
|
src/dsp/filters.o \
|
||||||
src/dsp/filters_mips_dsp_r2.o \
|
src/dsp/filters_mips_dsp_r2.o \
|
||||||
|
src/dsp/filters_msa.o \
|
||||||
|
src/dsp/filters_neon.o \
|
||||||
src/dsp/filters_sse2.o \
|
src/dsp/filters_sse2.o \
|
||||||
src/dsp/lossless.o \
|
src/dsp/lossless.o \
|
||||||
src/dsp/lossless_mips_dsp_r2.o \
|
src/dsp/lossless_mips_dsp_r2.o \
|
||||||
|
src/dsp/lossless_msa.o \
|
||||||
src/dsp/lossless_neon.o \
|
src/dsp/lossless_neon.o \
|
||||||
src/dsp/lossless_sse2.o \
|
src/dsp/lossless_sse2.o \
|
||||||
src/dsp/rescaler.o \
|
src/dsp/rescaler.o \
|
||||||
src/dsp/rescaler_mips32.o \
|
src/dsp/rescaler_mips32.o \
|
||||||
src/dsp/rescaler_mips_dsp_r2.o \
|
src/dsp/rescaler_mips_dsp_r2.o \
|
||||||
|
src/dsp/rescaler_msa.o \
|
||||||
src/dsp/rescaler_neon.o \
|
src/dsp/rescaler_neon.o \
|
||||||
src/dsp/rescaler_sse2.o \
|
src/dsp/rescaler_sse2.o \
|
||||||
src/dsp/upsampling.o \
|
src/dsp/upsampling.o \
|
||||||
src/dsp/upsampling_mips_dsp_r2.o \
|
src/dsp/upsampling_mips_dsp_r2.o \
|
||||||
|
src/dsp/upsampling_msa.o \
|
||||||
src/dsp/upsampling_neon.o \
|
src/dsp/upsampling_neon.o \
|
||||||
src/dsp/upsampling_sse2.o \
|
src/dsp/upsampling_sse2.o \
|
||||||
src/dsp/yuv.o \
|
src/dsp/yuv.o \
|
||||||
@@ -175,47 +181,53 @@ DSP_ENC_OBJS = \
|
|||||||
src/dsp/enc_avx2.o \
|
src/dsp/enc_avx2.o \
|
||||||
src/dsp/enc_mips32.o \
|
src/dsp/enc_mips32.o \
|
||||||
src/dsp/enc_mips_dsp_r2.o \
|
src/dsp/enc_mips_dsp_r2.o \
|
||||||
|
src/dsp/enc_msa.o \
|
||||||
src/dsp/enc_neon.o \
|
src/dsp/enc_neon.o \
|
||||||
src/dsp/enc_sse2.o \
|
src/dsp/enc_sse2.o \
|
||||||
src/dsp/enc_sse41.o \
|
src/dsp/enc_sse41.o \
|
||||||
src/dsp/lossless_enc.o \
|
src/dsp/lossless_enc.o \
|
||||||
src/dsp/lossless_enc_mips32.o \
|
src/dsp/lossless_enc_mips32.o \
|
||||||
src/dsp/lossless_enc_mips_dsp_r2.o \
|
src/dsp/lossless_enc_mips_dsp_r2.o \
|
||||||
|
src/dsp/lossless_enc_msa.o \
|
||||||
src/dsp/lossless_enc_neon.o \
|
src/dsp/lossless_enc_neon.o \
|
||||||
src/dsp/lossless_enc_sse2.o \
|
src/dsp/lossless_enc_sse2.o \
|
||||||
src/dsp/lossless_enc_sse41.o \
|
src/dsp/lossless_enc_sse41.o \
|
||||||
|
|
||||||
ENC_OBJS = \
|
ENC_OBJS = \
|
||||||
src/enc/alpha.o \
|
src/enc/alpha_enc.o \
|
||||||
src/enc/analysis.o \
|
src/enc/analysis_enc.o \
|
||||||
src/enc/backward_references.o \
|
src/enc/backward_references_enc.o \
|
||||||
src/enc/config.o \
|
src/enc/config_enc.o \
|
||||||
src/enc/cost.o \
|
src/enc/cost_enc.o \
|
||||||
src/enc/delta_palettization.o \
|
src/enc/delta_palettization_enc.o \
|
||||||
src/enc/filter.o \
|
src/enc/filter_enc.o \
|
||||||
src/enc/frame.o \
|
src/enc/frame_enc.o \
|
||||||
src/enc/histogram.o \
|
src/enc/histogram_enc.o \
|
||||||
src/enc/iterator.o \
|
src/enc/iterator_enc.o \
|
||||||
src/enc/near_lossless.o \
|
src/enc/near_lossless_enc.o \
|
||||||
src/enc/picture.o \
|
src/enc/picture_enc.o \
|
||||||
src/enc/picture_csp.o \
|
src/enc/picture_csp_enc.o \
|
||||||
src/enc/picture_psnr.o \
|
src/enc/picture_psnr_enc.o \
|
||||||
src/enc/picture_rescale.o \
|
src/enc/picture_rescale_enc.o \
|
||||||
src/enc/picture_tools.o \
|
src/enc/picture_tools_enc.o \
|
||||||
src/enc/quant.o \
|
src/enc/predictor_enc.o \
|
||||||
src/enc/syntax.o \
|
src/enc/quant_enc.o \
|
||||||
src/enc/token.o \
|
src/enc/syntax_enc.o \
|
||||||
src/enc/tree.o \
|
src/enc/token_enc.o \
|
||||||
src/enc/vp8l.o \
|
src/enc/tree_enc.o \
|
||||||
src/enc/webpenc.o \
|
src/enc/vp8l_enc.o \
|
||||||
|
src/enc/webp_enc.o \
|
||||||
|
|
||||||
EX_FORMAT_DEC_OBJS = \
|
EX_FORMAT_DEC_OBJS = \
|
||||||
examples/image_dec.o \
|
imageio/image_dec.o \
|
||||||
examples/jpegdec.o \
|
imageio/jpegdec.o \
|
||||||
examples/metadata.o \
|
imageio/metadata.o \
|
||||||
examples/pngdec.o \
|
imageio/pngdec.o \
|
||||||
examples/tiffdec.o \
|
imageio/tiffdec.o \
|
||||||
examples/webpdec.o \
|
imageio/webpdec.o \
|
||||||
|
|
||||||
|
EX_FORMAT_ENC_OBJS = \
|
||||||
|
imageio/image_enc.o \
|
||||||
|
|
||||||
EX_UTIL_OBJS = \
|
EX_UTIL_OBJS = \
|
||||||
examples/example_util.o \
|
examples/example_util.o \
|
||||||
@@ -223,6 +235,9 @@ EX_UTIL_OBJS = \
|
|||||||
GIFDEC_OBJS = \
|
GIFDEC_OBJS = \
|
||||||
examples/gifdec.o \
|
examples/gifdec.o \
|
||||||
|
|
||||||
|
IMAGE_UTIL_OBJS = \
|
||||||
|
imageio/imageio_util.o \
|
||||||
|
|
||||||
MUX_OBJS = \
|
MUX_OBJS = \
|
||||||
src/mux/anim_encode.o \
|
src/mux/anim_encode.o \
|
||||||
src/mux/muxedit.o \
|
src/mux/muxedit.o \
|
||||||
@@ -230,23 +245,24 @@ MUX_OBJS = \
|
|||||||
src/mux/muxread.o \
|
src/mux/muxread.o \
|
||||||
|
|
||||||
UTILS_DEC_OBJS = \
|
UTILS_DEC_OBJS = \
|
||||||
src/utils/bit_reader.o \
|
src/utils/bit_reader_utils.o \
|
||||||
src/utils/color_cache.o \
|
src/utils/color_cache_utils.o \
|
||||||
src/utils/filters.o \
|
src/utils/filters_utils.o \
|
||||||
src/utils/huffman.o \
|
src/utils/huffman_utils.o \
|
||||||
src/utils/quant_levels_dec.o \
|
src/utils/quant_levels_dec_utils.o \
|
||||||
src/utils/random.o \
|
src/utils/random_utils.o \
|
||||||
src/utils/rescaler.o \
|
src/utils/rescaler_utils.o \
|
||||||
src/utils/thread.o \
|
src/utils/thread_utils.o \
|
||||||
src/utils/utils.o \
|
src/utils/utils.o \
|
||||||
|
|
||||||
UTILS_ENC_OBJS = \
|
UTILS_ENC_OBJS = \
|
||||||
src/utils/bit_writer.o \
|
src/utils/bit_writer_utils.o \
|
||||||
src/utils/huffman_encode.o \
|
src/utils/huffman_encode_utils.o \
|
||||||
src/utils/quant_levels.o \
|
src/utils/quant_levels_utils.o \
|
||||||
|
|
||||||
EXTRA_OBJS = \
|
EXTRA_OBJS = \
|
||||||
src/extras/extras.o \
|
extras/extras.o \
|
||||||
|
extras/quality_estimate.o \
|
||||||
|
|
||||||
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
||||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
|
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
|
||||||
@@ -264,82 +280,95 @@ HDRS_INSTALLED = \
|
|||||||
src/webp/types.h \
|
src/webp/types.h \
|
||||||
|
|
||||||
HDRS = \
|
HDRS = \
|
||||||
src/dec/alphai.h \
|
src/dec/alphai_dec.h \
|
||||||
src/dec/common.h \
|
src/dec/common_dec.h \
|
||||||
src/dec/decode_vp8.h \
|
src/dec/vp8_dec.h \
|
||||||
src/dec/vp8i.h \
|
src/dec/vp8i_dec.h \
|
||||||
src/dec/vp8li.h \
|
src/dec/vp8li_dec.h \
|
||||||
src/dec/webpi.h \
|
src/dec/webpi_dec.h \
|
||||||
src/dsp/common_sse2.h \
|
src/dsp/common_sse2.h \
|
||||||
src/dsp/dsp.h \
|
src/dsp/dsp.h \
|
||||||
src/dsp/lossless.h \
|
src/dsp/lossless.h \
|
||||||
|
src/dsp/lossless_common.h \
|
||||||
src/dsp/mips_macro.h \
|
src/dsp/mips_macro.h \
|
||||||
src/dsp/msa_macro.h \
|
src/dsp/msa_macro.h \
|
||||||
src/dsp/neon.h \
|
src/dsp/neon.h \
|
||||||
src/dsp/yuv.h \
|
src/dsp/yuv.h \
|
||||||
src/enc/backward_references.h \
|
src/enc/backward_references_enc.h \
|
||||||
src/enc/cost.h \
|
src/enc/cost_enc.h \
|
||||||
src/enc/delta_palettization.h \
|
src/enc/delta_palettization_enc.h \
|
||||||
src/enc/histogram.h \
|
src/enc/histogram_enc.h \
|
||||||
src/enc/vp8enci.h \
|
src/enc/vp8i_enc.h \
|
||||||
src/enc/vp8li.h \
|
src/enc/vp8li_enc.h \
|
||||||
|
src/mux/animi.h \
|
||||||
src/mux/muxi.h \
|
src/mux/muxi.h \
|
||||||
src/utils/bit_reader.h \
|
src/utils/bit_reader_utils.h \
|
||||||
src/utils/bit_reader_inl.h \
|
src/utils/bit_reader_inl_utils.h \
|
||||||
src/utils/bit_writer.h \
|
src/utils/bit_writer_utils.h \
|
||||||
src/utils/color_cache.h \
|
src/utils/color_cache_utils.h \
|
||||||
src/utils/endian_inl.h \
|
src/utils/endian_inl_utils.h \
|
||||||
src/utils/filters.h \
|
src/utils/filters_utils.h \
|
||||||
src/utils/huffman.h \
|
src/utils/huffman_utils.h \
|
||||||
src/utils/huffman_encode.h \
|
src/utils/huffman_encode_utils.h \
|
||||||
src/utils/quant_levels.h \
|
src/utils/quant_levels_utils.h \
|
||||||
src/utils/quant_levels_dec.h \
|
src/utils/quant_levels_dec_utils.h \
|
||||||
src/utils/random.h \
|
src/utils/random_utils.h \
|
||||||
src/utils/rescaler.h \
|
src/utils/rescaler_utils.h \
|
||||||
src/utils/thread.h \
|
src/utils/thread_utils.h \
|
||||||
src/utils/utils.h \
|
src/utils/utils.h \
|
||||||
src/webp/format_constants.h \
|
src/webp/format_constants.h \
|
||||||
$(HDRS_INSTALLED) \
|
$(HDRS_INSTALLED) \
|
||||||
|
|
||||||
OUT_LIBS = examples/libexample_util.a src/libwebpdecoder.a src/libwebp.a
|
OUT_LIBS = examples/libexample_util.a
|
||||||
EXTRA_LIB = src/libwebpextras.a
|
OUT_LIBS += imageio/libimageio_util.a
|
||||||
|
OUT_LIBS += imageio/libimagedec.a
|
||||||
|
OUT_LIBS += imageio/libimageenc.a
|
||||||
|
OUT_LIBS += src/libwebpdecoder.a
|
||||||
|
OUT_LIBS += src/libwebp.a
|
||||||
|
EXTRA_LIB = extras/libwebpextras.a
|
||||||
OUT_EXAMPLES = examples/cwebp examples/dwebp
|
OUT_EXAMPLES = examples/cwebp examples/dwebp
|
||||||
EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \
|
EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \
|
||||||
examples/anim_diff
|
examples/anim_diff examples/img2webp
|
||||||
|
OTHER_EXAMPLES = extras/get_disto extras/webp_quality
|
||||||
|
|
||||||
OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES)
|
OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES)
|
||||||
ifeq ($(MAKECMDGOALS),clean)
|
ifeq ($(MAKECMDGOALS),clean)
|
||||||
OUTPUT += $(EXTRA_EXAMPLES)
|
OUTPUT += $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES)
|
||||||
OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a $(EXTRA_LIB)
|
OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a $(EXTRA_LIB)
|
||||||
OUTPUT += examples/libgifdec.a examples/libanim_util.a
|
OUTPUT += examples/libgifdec.a examples/libanim_util.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ex: $(OUT_EXAMPLES)
|
ex: $(OUT_EXAMPLES)
|
||||||
all: ex $(EXTRA_EXAMPLES)
|
all: ex $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES)
|
||||||
extras: $(EXTRA_LIB)
|
extras: $(EXTRA_LIB)
|
||||||
|
|
||||||
$(EX_FORMAT_DEC_OBJS): %.o: %.h
|
$(EX_FORMAT_DEC_OBJS): %.o: %.h
|
||||||
|
|
||||||
# special dependencies:
|
# special dependencies:
|
||||||
# tree.c/vp8.c/bit_reader.c <-> bit_reader_inl.h, endian_inl.h
|
# tree_dec.c/vp8_dec.c/bit_reader_utils.c <->
|
||||||
# bit_writer.c <-> endian_inl.h
|
# bit_reader_inl_utils.h, endian_inl_utils.h
|
||||||
src/dec/tree.o: src/utils/bit_reader_inl.h src/utils/endian_inl.h
|
# bit_writer_utils.c <-> endian_inl_utils.h
|
||||||
src/dec/vp8.o: src/utils/bit_reader_inl.h src/utils/endian_inl.h
|
src/dec/tree_dec.o: src/utils/bit_reader_inl_utils.h
|
||||||
src/utils/bit_reader.o: src/utils/bit_reader_inl.h src/utils/endian_inl.h
|
src/dec/tree_dec.o: src/utils/endian_inl_utils.h
|
||||||
src/utils/bit_writer.o: src/utils/endian_inl.h
|
src/dec/vp8_dec.o: src/utils/bit_reader_inl_utils.h src/utils/endian_inl_utils.h
|
||||||
|
src/utils/bit_reader_utils.o: src/utils/bit_reader_inl_utils.h
|
||||||
|
src/utils/bit_reader_utils.o: src/utils/endian_inl_utils.h
|
||||||
|
src/utils/bit_writer_utils.o: src/utils/endian_inl_utils.h
|
||||||
|
|
||||||
%.o: %.c $(HDRS)
|
%.o: %.c $(HDRS)
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||||
|
|
||||||
examples/libanim_util.a: $(ANIM_UTIL_OBJS)
|
examples/libanim_util.a: $(ANIM_UTIL_OBJS)
|
||||||
examples/libexample_dec.a: $(EX_FORMAT_DEC_OBJS)
|
|
||||||
examples/libexample_util.a: $(EX_UTIL_OBJS)
|
examples/libexample_util.a: $(EX_UTIL_OBJS)
|
||||||
examples/libgifdec.a: $(GIFDEC_OBJS)
|
examples/libgifdec.a: $(GIFDEC_OBJS)
|
||||||
|
extras/libwebpextras.a: $(LIBWEBPEXTRA_OBJS)
|
||||||
|
imageio/libimagedec.a: $(EX_FORMAT_DEC_OBJS)
|
||||||
|
imageio/libimageenc.a: $(EX_FORMAT_ENC_OBJS)
|
||||||
|
imageio/libimageio_util.a: $(IMAGE_UTIL_OBJS)
|
||||||
src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS)
|
src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS)
|
||||||
src/libwebp.a: $(LIBWEBP_OBJS)
|
src/libwebp.a: $(LIBWEBP_OBJS)
|
||||||
src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS)
|
src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS)
|
||||||
src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
|
src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
|
||||||
src/libwebpextras.a: $(LIBWEBPEXTRA_OBJS)
|
|
||||||
|
|
||||||
%.a:
|
%.a:
|
||||||
$(AR) $(ARFLAGS) $@ $^
|
$(AR) $(ARFLAGS) $@ $^
|
||||||
@@ -350,29 +379,48 @@ examples/dwebp: examples/dwebp.o
|
|||||||
examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS)
|
examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS)
|
||||||
examples/vwebp: examples/vwebp.o
|
examples/vwebp: examples/vwebp.o
|
||||||
examples/webpmux: examples/webpmux.o
|
examples/webpmux: examples/webpmux.o
|
||||||
|
examples/img2webp: examples/img2webp.o
|
||||||
|
|
||||||
examples/anim_diff: examples/libanim_util.a examples/libgifdec.a
|
examples/anim_diff: examples/libanim_util.a examples/libgifdec.a
|
||||||
examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a
|
examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a
|
||||||
examples/anim_diff: src/libwebp.a
|
examples/anim_diff: imageio/libimageio_util.a src/libwebp.a
|
||||||
examples/anim_diff: EXTRA_LIBS += $(GIF_LIBS)
|
examples/anim_diff: EXTRA_LIBS += $(GIF_LIBS)
|
||||||
examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF
|
examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF
|
||||||
examples/cwebp: examples/libexample_util.a examples/libexample_dec.a
|
examples/cwebp: examples/libexample_util.a
|
||||||
|
examples/cwebp: imageio/libimagedec.a
|
||||||
|
examples/cwebp: imageio/libimageio_util.a
|
||||||
examples/cwebp: src/libwebp.a
|
examples/cwebp: src/libwebp.a
|
||||||
examples/cwebp: EXTRA_LIBS += $(CWEBP_LIBS)
|
examples/cwebp: EXTRA_LIBS += $(CWEBP_LIBS)
|
||||||
examples/dwebp: examples/libexample_util.a src/libwebpdecoder.a
|
examples/dwebp: examples/libexample_util.a
|
||||||
|
examples/dwebp: imageio/libimagedec.a
|
||||||
|
examples/dwebp: imageio/libimageenc.a
|
||||||
|
examples/dwebp: imageio/libimageio_util.a
|
||||||
|
examples/dwebp: src/libwebp.a
|
||||||
examples/dwebp: EXTRA_LIBS += $(DWEBP_LIBS)
|
examples/dwebp: EXTRA_LIBS += $(DWEBP_LIBS)
|
||||||
examples/gif2webp: examples/libexample_util.a examples/libgifdec.a
|
examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a
|
||||||
examples/gif2webp: src/mux/libwebpmux.a src/libwebp.a
|
examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a
|
||||||
examples/gif2webp: EXTRA_LIBS += $(GIF_LIBS)
|
examples/gif2webp: EXTRA_LIBS += $(GIF_LIBS)
|
||||||
examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF
|
examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF
|
||||||
examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a
|
examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a
|
||||||
examples/vwebp: src/libwebp.a
|
examples/vwebp: imageio/libimageio_util.a src/libwebp.a
|
||||||
examples/vwebp: EXTRA_LIBS += $(GL_LIBS)
|
examples/vwebp: EXTRA_LIBS += $(GL_LIBS)
|
||||||
examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL
|
examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL
|
||||||
examples/webpmux: examples/libexample_util.a src/mux/libwebpmux.a
|
examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a
|
||||||
examples/webpmux: src/libwebpdecoder.a
|
examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a
|
||||||
|
examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a
|
||||||
|
examples/img2webp: imageio/libimagedec.a
|
||||||
|
examples/img2webp: src/mux/libwebpmux.a src/libwebp.a
|
||||||
|
examples/img2webp: EXTRA_LIBS += $(CWEBP_LIBS)
|
||||||
|
|
||||||
$(OUT_EXAMPLES) $(EXTRA_EXAMPLES):
|
extras/get_disto: extras/get_disto.o
|
||||||
|
extras/get_disto: imageio/libimagedec.a imageio/libimageio_util.a src/libwebp.a
|
||||||
|
extras/get_disto: EXTRA_LIBS += $(CWEBP_LIBS)
|
||||||
|
|
||||||
|
extras/webp_quality: extras/webp_quality.o
|
||||||
|
extras/webp_quality: imageio/libimageio_util.a
|
||||||
|
extras/webp_quality: $(EXTRA_LIB) src/libwebp.a
|
||||||
|
|
||||||
|
$(OUT_EXAMPLES) $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES):
|
||||||
$(CC) -o $@ $^ $(LDFLAGS)
|
$(CC) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
dist: DESTDIR := dist
|
dist: DESTDIR := dist
|
||||||
@@ -386,7 +434,8 @@ dist: all
|
|||||||
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
|
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
|
||||||
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
|
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
|
||||||
umask 022; \
|
umask 022; \
|
||||||
for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1; do \
|
for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \
|
||||||
|
man/img2webp.1; do \
|
||||||
basenam=$$(basename $$m .1); \
|
basenam=$$(basename $$m .1); \
|
||||||
$(GROFF) -t -e -man -T utf8 $$m \
|
$(GROFF) -t -e -man -T utf8 $$m \
|
||||||
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \
|
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \
|
||||||
@@ -397,11 +446,12 @@ dist: all
|
|||||||
clean:
|
clean:
|
||||||
$(RM) $(OUTPUT) *~ \
|
$(RM) $(OUTPUT) *~ \
|
||||||
examples/*.o examples/*~ \
|
examples/*.o examples/*~ \
|
||||||
|
extras/*.o extras/*~ \
|
||||||
|
imageio/*.o imageio/*~ \
|
||||||
src/dec/*.o src/dec/*~ \
|
src/dec/*.o src/dec/*~ \
|
||||||
src/demux/*.o src/demux/*~ \
|
src/demux/*.o src/demux/*~ \
|
||||||
src/dsp/*.o src/dsp/*~ \
|
src/dsp/*.o src/dsp/*~ \
|
||||||
src/enc/*.o src/enc/*~ \
|
src/enc/*.o src/enc/*~ \
|
||||||
src/extras/*.o src/extras/*~ \
|
|
||||||
src/mux/*.o src/mux/*~ \
|
src/mux/*.o src/mux/*~ \
|
||||||
src/utils/*.o src/utils/*~ \
|
src/utils/*.o src/utils/*~ \
|
||||||
src/webp/*~ man/*~ doc/*~ swig/*~ \
|
src/webp/*~ man/*~ doc/*~ swig/*~ \
|
||||||
|
|||||||
18
man/cwebp.1
18
man/cwebp.1
@@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH CWEBP 1 "June 23, 2016"
|
.TH CWEBP 1 "January 20, 2017"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
cwebp \- compress an image file to a WebP file
|
cwebp \- compress an image file to a WebP file
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -117,15 +117,15 @@ or without alpha).
|
|||||||
.TP
|
.TP
|
||||||
.BI \-size " int
|
.BI \-size " int
|
||||||
Specify a target size (in bytes) to try and reach for the compressed output.
|
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
|
The compressor will make several passes of partial encoding in order to get as
|
||||||
close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP
|
close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP
|
||||||
as used, \fB\-size\fP value will prevail.
|
are used, \fB\-size\fP value will prevail.
|
||||||
.TP
|
.TP
|
||||||
.BI \-psnr " float
|
.BI \-psnr " float
|
||||||
Specify a target PSNR (in dB) to try and reach for the compressed output.
|
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
|
The compressor will make several passes of partial encoding in order to get as
|
||||||
close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP
|
close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP
|
||||||
as used, \fB\-size\fP value will prevail.
|
are used, \fB\-size\fP value will prevail.
|
||||||
.TP
|
.TP
|
||||||
.BI \-pass " int
|
.BI \-pass " int
|
||||||
Set a maximum number of passes to use during the dichotomy used by
|
Set a maximum number of passes to use during the dichotomy used by
|
||||||
@@ -166,12 +166,16 @@ Use strong filtering (if filtering is being used thanks to the
|
|||||||
Disable strong filtering (if filtering is being used thanks to the
|
Disable strong filtering (if filtering is being used thanks to the
|
||||||
\fB\-f\fP option) and use simple filtering instead.
|
\fB\-f\fP option) and use simple filtering instead.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-sharp_yuv
|
||||||
|
Use more accurate and sharper RGB->YUV conversion if needed. Note that this
|
||||||
|
process is slower than the default 'fast' RGB->YUV conversion.
|
||||||
|
.TP
|
||||||
.BI \-sns " int
|
.BI \-sns " int
|
||||||
Specify the amplitude of the spatial noise shaping. Spatial noise shaping
|
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
|
(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,
|
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
|
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.
|
0 (algorithm is off) to 100 (the maximal effect). The default value is 50.
|
||||||
.TP
|
.TP
|
||||||
.BI \-segments " int
|
.BI \-segments " int
|
||||||
Change the number of partitions to use during the segmentation of the
|
Change the number of partitions to use during the segmentation of the
|
||||||
@@ -222,7 +226,7 @@ Report encoding progress in percent.
|
|||||||
Do not print anything.
|
Do not print anything.
|
||||||
.TP
|
.TP
|
||||||
.B \-short
|
.B \-short
|
||||||
Only print brief information (output file size and PSNR) for testing purpose.
|
Only print brief information (output file size and PSNR) for testing purposes.
|
||||||
.TP
|
.TP
|
||||||
.BI \-map " int
|
.BI \-map " int
|
||||||
Output additional ASCII\-map of encoding information. Possible map values
|
Output additional ASCII\-map of encoding information. Possible map values
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH GIF2WEBP 1 "June 23, 2016"
|
.TH GIF2WEBP 1 "January 25, 2017"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
gif2webp \- Convert a GIF image to WebP
|
gif2webp \- Convert a GIF image to WebP
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -68,8 +68,9 @@ Specify the minimum and maximum distance between consecutive key frames
|
|||||||
some key frames into the output animation as needed so that this criteria is
|
some key frames into the output animation as needed so that this criteria is
|
||||||
satisfied.
|
satisfied.
|
||||||
.br
|
.br
|
||||||
A 'kmin' value of 0 will turn off insertion of key frames. A 'kmax' value of 0
|
A 'kmax' value of 0 will turn off insertion of key frames. A 'kmax' value of 1
|
||||||
will result in all frames being key frames.
|
will result in all frames being key frames. 'kmin' value is not taken into
|
||||||
|
account in both these special cases.
|
||||||
Typical values are in the range 3 to 30. Default values are kmin = 9,
|
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.
|
kmax = 17 for lossless compression and kmin = 3, kmax = 5 for lossy compression.
|
||||||
.br
|
.br
|
||||||
|
|||||||
97
man/img2webp.1
Normal file
97
man/img2webp.1
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
|
.TH IMG2WEBP 1 "January 23, 2017"
|
||||||
|
.SH NAME
|
||||||
|
img2webp \- create animated WebP file from a sequence of input images.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B img2webp
|
||||||
|
[file_level_options] [files] [per_frame_options...]
|
||||||
|
.br
|
||||||
|
.SH DESCRIPTION
|
||||||
|
This manual page documents the
|
||||||
|
.B img2webp
|
||||||
|
command.
|
||||||
|
.PP
|
||||||
|
\fBimg2webp\fP compresses a sequence of images using the animated WebP format.
|
||||||
|
Input images can either be PNG, JPEG, TIFF or WebP.
|
||||||
|
.SH FILE-LEVEL OPTIONS
|
||||||
|
The file-level options are applied at the beginning of the compression process,
|
||||||
|
before the input frames are read.
|
||||||
|
.TP
|
||||||
|
.BI \-o " string
|
||||||
|
Specify the name of the output WebP file.
|
||||||
|
.TP
|
||||||
|
.BI \-min_size
|
||||||
|
Encode images to achieve smallest size. This disables key frame insertion and
|
||||||
|
picks the parameters resulting in smallest output for each frame. It uses
|
||||||
|
lossless compression by default, but can be combined with \-q, \-m, \-lossy or
|
||||||
|
\-mixed options.
|
||||||
|
.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
|
||||||
|
.B \-mixed
|
||||||
|
Mixed compression mode: optimize compression of the image by picking either
|
||||||
|
lossy or lossless compression for each frame heuristically. This global
|
||||||
|
option disables the local option \fB-lossy\fP and \fB-lossless\fP .
|
||||||
|
.TP
|
||||||
|
.BI \-loop " int
|
||||||
|
Specifies the number of times the animation should loop. Using '0' means
|
||||||
|
'loop indefinitely'.
|
||||||
|
.TP
|
||||||
|
.BI \-v
|
||||||
|
Be more verbose.
|
||||||
|
.TP
|
||||||
|
.B \-h, \-help
|
||||||
|
A short usage summary.
|
||||||
|
|
||||||
|
.SH PER-FRAME OPTIONS
|
||||||
|
The per-frame options are applied for the images following as arguments in the
|
||||||
|
command line. They can be modified any number of times preceding each particular
|
||||||
|
input image.
|
||||||
|
.TP
|
||||||
|
.BI \-d " int
|
||||||
|
Specify the image duration in milliseconds.
|
||||||
|
.TP
|
||||||
|
.B \-lossless, \-lossy
|
||||||
|
Compress the next image(s) using lossless or lossy compression mode. The
|
||||||
|
default mode is lossless.
|
||||||
|
.TP
|
||||||
|
.BI \-q " float
|
||||||
|
Specify the compression factor between 0 and 100. The default is 75.
|
||||||
|
.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.
|
||||||
|
|
||||||
|
.SH EXAMPLE
|
||||||
|
img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp
|
||||||
|
.br
|
||||||
|
|
||||||
|
.SH BUGS
|
||||||
|
Please report all bugs to the issue tracker:
|
||||||
|
https://bugs.chromium.org/p/webp
|
||||||
|
.br
|
||||||
|
Patches welcome! See this page to get started:
|
||||||
|
http://www.webmproject.org/code/contribute/submitting\-patches/
|
||||||
|
|
||||||
|
.SH AUTHORS
|
||||||
|
\fBimg2webp\fP is a part of libwebp and was written by the WebP team.
|
||||||
|
.br
|
||||||
|
The latest source tree is available at
|
||||||
|
https://chromium.googlesource.com/webm/libwebp
|
||||||
|
.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 webpmux (1),
|
||||||
|
.BR gif2webp (1)
|
||||||
|
.br
|
||||||
|
Please refer to http://developers.google.com/speed/webp/ for additional
|
||||||
|
information.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH VWEBP 1 "June 23, 2016"
|
.TH VWEBP 1 "November 25, 2016"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
vwebp \- decompress a WebP file and display it in a window
|
vwebp \- decompress a WebP file and display it in a window
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -59,6 +59,9 @@ Toggle use of color profile.
|
|||||||
.B 'i'
|
.B 'i'
|
||||||
Overlay file information.
|
Overlay file information.
|
||||||
.TP
|
.TP
|
||||||
|
.B 'd'
|
||||||
|
Disable blending and disposal process, for debugging purposes.
|
||||||
|
.TP
|
||||||
.B 'q' / 'Q' / ESC
|
.B 'q' / 'Q' / ESC
|
||||||
Quit.
|
Quit.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH WEBPMUX 1 "June 23, 2016"
|
.TH WEBPMUX 1 "November 10, 2016"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
webpmux \- create animated WebP files from non\-animated WebP images, extract
|
webpmux \- create animated WebP files from non\-animated WebP images, extract
|
||||||
frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
|
frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
|
||||||
@@ -35,6 +35,13 @@ frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
|
|||||||
.I OUTPUT
|
.I OUTPUT
|
||||||
.RE
|
.RE
|
||||||
.br
|
.br
|
||||||
|
.B webpmux \-duration
|
||||||
|
.I DURATION OPTIONS
|
||||||
|
.B [ \-duration ... ]
|
||||||
|
.I INPUT
|
||||||
|
.B \-o
|
||||||
|
.I OUTPUT
|
||||||
|
.br
|
||||||
.B webpmux \-info
|
.B webpmux \-info
|
||||||
.I INPUT
|
.I INPUT
|
||||||
.br
|
.br
|
||||||
@@ -91,6 +98,42 @@ Strip EXIF metadata.
|
|||||||
.B xmp
|
.B xmp
|
||||||
Strip XMP metadata.
|
Strip XMP metadata.
|
||||||
|
|
||||||
|
.SS DURATION_OPTIONS (\-duration)
|
||||||
|
Amend the duration of a specific interval of frames. This option is only
|
||||||
|
effective on animated WebP and has no effect on a single-frame file.
|
||||||
|
.TP
|
||||||
|
.I duration[,start[,end]]
|
||||||
|
Where:
|
||||||
|
.br
|
||||||
|
.B duration
|
||||||
|
is the duration for the interval in milliseconds (mandatory).
|
||||||
|
Must be non-negative.
|
||||||
|
.br
|
||||||
|
.B start
|
||||||
|
is the starting frame index of the interval (optional).
|
||||||
|
.br
|
||||||
|
.B end
|
||||||
|
is the ending frame index (inclusive) of the interval (optional).
|
||||||
|
.TP
|
||||||
|
The three typical usages of this option are:
|
||||||
|
.br
|
||||||
|
.B -duration d
|
||||||
|
set the duration to 'd' for the whole animation.
|
||||||
|
.br
|
||||||
|
.B -duration d,f
|
||||||
|
set the duration of frame 'f' to 'd'.
|
||||||
|
.br
|
||||||
|
.B -duration d,start,end
|
||||||
|
set the duration to 'd' for the whole [start,end] interval.
|
||||||
|
.TP
|
||||||
|
.P
|
||||||
|
Note that the frames outside of the [start, end] interval will remain untouched.
|
||||||
|
The 'end' value '0' has the special meaning 'last frame of the animation'.
|
||||||
|
.TP
|
||||||
|
.I Reminder:
|
||||||
|
frame indexing starts at '1'.
|
||||||
|
.br
|
||||||
|
|
||||||
.SS FRAME_OPTIONS (\-frame)
|
.SS FRAME_OPTIONS (\-frame)
|
||||||
Create an animated WebP file from multiple (non\-animated) WebP images.
|
Create an animated WebP file from multiple (non\-animated) WebP images.
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# The mux, demux and extras libraries depend on libwebp, thus the '.' to force
|
# The mux and demux libraries depend on libwebp, thus the '.' to force
|
||||||
# the build order so it's available to them.
|
# the build order so it's available to them.
|
||||||
SUBDIRS = dec enc dsp utils .
|
SUBDIRS = dec enc dsp utils .
|
||||||
if WANT_MUX
|
if WANT_MUX
|
||||||
@@ -7,9 +7,6 @@ endif
|
|||||||
if WANT_DEMUX
|
if WANT_DEMUX
|
||||||
SUBDIRS += demux
|
SUBDIRS += demux
|
||||||
endif
|
endif
|
||||||
if WANT_EXTRAS
|
|
||||||
SUBDIRS += extras
|
|
||||||
endif
|
|
||||||
|
|
||||||
lib_LTLIBRARIES = libwebp.la
|
lib_LTLIBRARIES = libwebp.la
|
||||||
|
|
||||||
@@ -38,7 +35,7 @@ libwebp_la_LIBADD += utils/libwebputils.la
|
|||||||
# other than the ones listed on the command line, i.e., after linking, it will
|
# 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
|
# not have unresolved symbols. Some platforms (Windows among them) require all
|
||||||
# symbols in shared libraries to be resolved at library creation.
|
# symbols in shared libraries to be resolved at library creation.
|
||||||
libwebp_la_LDFLAGS = -no-undefined -version-info 6:1:0
|
libwebp_la_LDFLAGS = -no-undefined -version-info 7:0:0
|
||||||
libwebpincludedir = $(includedir)/webp
|
libwebpincludedir = $(includedir)/webp
|
||||||
pkgconfig_DATA = libwebp.pc
|
pkgconfig_DATA = libwebp.pc
|
||||||
|
|
||||||
@@ -50,7 +47,7 @@ if BUILD_LIBWEBPDECODER
|
|||||||
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
|
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
|
||||||
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
|
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
|
||||||
|
|
||||||
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 2:1:0
|
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 3:0:0
|
||||||
pkgconfig_DATA += libwebpdecoder.pc
|
pkgconfig_DATA += libwebpdecoder.pc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
noinst_LTLIBRARIES = libwebpdecode.la
|
noinst_LTLIBRARIES = libwebpdecode.la
|
||||||
|
|
||||||
libwebpdecode_la_SOURCES =
|
libwebpdecode_la_SOURCES =
|
||||||
libwebpdecode_la_SOURCES += alpha.c
|
libwebpdecode_la_SOURCES += alpha_dec.c
|
||||||
libwebpdecode_la_SOURCES += alphai.h
|
libwebpdecode_la_SOURCES += alphai_dec.h
|
||||||
libwebpdecode_la_SOURCES += buffer.c
|
libwebpdecode_la_SOURCES += buffer_dec.c
|
||||||
libwebpdecode_la_SOURCES += common.h
|
libwebpdecode_la_SOURCES += common_dec.h
|
||||||
libwebpdecode_la_SOURCES += decode_vp8.h
|
libwebpdecode_la_SOURCES += vp8_dec.h
|
||||||
libwebpdecode_la_SOURCES += frame.c
|
libwebpdecode_la_SOURCES += frame_dec.c
|
||||||
libwebpdecode_la_SOURCES += idec.c
|
libwebpdecode_la_SOURCES += idec_dec.c
|
||||||
libwebpdecode_la_SOURCES += io.c
|
libwebpdecode_la_SOURCES += io_dec.c
|
||||||
libwebpdecode_la_SOURCES += quant.c
|
libwebpdecode_la_SOURCES += quant_dec.c
|
||||||
libwebpdecode_la_SOURCES += tree.c
|
libwebpdecode_la_SOURCES += tree_dec.c
|
||||||
libwebpdecode_la_SOURCES += vp8.c
|
libwebpdecode_la_SOURCES += vp8_dec.c
|
||||||
libwebpdecode_la_SOURCES += vp8i.h
|
libwebpdecode_la_SOURCES += vp8i_dec.h
|
||||||
libwebpdecode_la_SOURCES += vp8l.c
|
libwebpdecode_la_SOURCES += vp8l_dec.c
|
||||||
libwebpdecode_la_SOURCES += vp8li.h
|
libwebpdecode_la_SOURCES += vp8li_dec.h
|
||||||
libwebpdecode_la_SOURCES += webp.c
|
libwebpdecode_la_SOURCES += webp_dec.c
|
||||||
libwebpdecode_la_SOURCES += webpi.h
|
libwebpdecode_la_SOURCES += webpi_dec.h
|
||||||
|
|
||||||
libwebpdecodeinclude_HEADERS =
|
libwebpdecodeinclude_HEADERS =
|
||||||
libwebpdecodeinclude_HEADERS += ../webp/decode.h
|
libwebpdecodeinclude_HEADERS += ../webp/decode.h
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "./alphai.h"
|
#include "./alphai_dec.h"
|
||||||
#include "./vp8i.h"
|
#include "./vp8i_dec.h"
|
||||||
#include "./vp8li.h"
|
#include "./vp8li_dec.h"
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../utils/quant_levels_dec.h"
|
#include "../utils/quant_levels_dec_utils.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../webp/format_constants.h"
|
#include "../webp/format_constants.h"
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
dec->method_ = (data[0] >> 0) & 0x03;
|
dec->method_ = (data[0] >> 0) & 0x03;
|
||||||
dec->filter_ = (data[0] >> 2) & 0x03;
|
dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
|
||||||
dec->pre_processing_ = (data[0] >> 4) & 0x03;
|
dec->pre_processing_ = (data[0] >> 4) & 0x03;
|
||||||
rsrv = (data[0] >> 6) & 0x03;
|
rsrv = (data[0] >> 6) & 0x03;
|
||||||
if (dec->method_ < ALPHA_NO_COMPRESSION ||
|
if (dec->method_ < ALPHA_NO_COMPRESSION ||
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
#ifndef WEBP_DEC_ALPHAI_H_
|
#ifndef WEBP_DEC_ALPHAI_H_
|
||||||
#define WEBP_DEC_ALPHAI_H_
|
#define WEBP_DEC_ALPHAI_H_
|
||||||
|
|
||||||
#include "./webpi.h"
|
#include "./webpi_dec.h"
|
||||||
#include "../utils/filters.h"
|
#include "../utils/filters_utils.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./vp8i.h"
|
#include "./vp8i_dec.h"
|
||||||
#include "./webpi.h"
|
#include "./webpi_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "./vp8i.h"
|
#include "./vp8i_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -723,7 +723,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
|
|||||||
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
|
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
|
||||||
"no memory during frame initialization.");
|
"no memory during frame initialization.");
|
||||||
}
|
}
|
||||||
// down-cast is ok, thanks to WebPSafeAlloc() above.
|
// down-cast is ok, thanks to WebPSafeMalloc() above.
|
||||||
dec->mem_size_ = (size_t)needed;
|
dec->mem_size_ = (size_t)needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,9 +15,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./alphai.h"
|
#include "./alphai_dec.h"
|
||||||
#include "./webpi.h"
|
#include "./webpi_dec.h"
|
||||||
#include "./vp8i.h"
|
#include "./vp8i_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
// In append mode, buffer allocations increase as multiples of this value.
|
// In append mode, buffer allocations increase as multiples of this value.
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "../dec/vp8i.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "./webpi.h"
|
#include "./webpi_dec.h"
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../dsp/yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
@@ -256,7 +256,7 @@ static int Rescale(const uint8_t* src, int src_stride,
|
|||||||
static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
|
static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
|
||||||
const int mb_h = io->mb_h;
|
const int mb_h = io->mb_h;
|
||||||
const int uv_mb_h = (mb_h + 1) >> 1;
|
const int uv_mb_h = (mb_h + 1) >> 1;
|
||||||
WebPRescaler* const scaler = &p->scaler_y;
|
WebPRescaler* const scaler = p->scaler_y;
|
||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
|
if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
|
||||||
// Before rescaling, we premultiply the luma directly into the io->y
|
// Before rescaling, we premultiply the luma directly into the io->y
|
||||||
@@ -267,29 +267,28 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
io->a, io->width, io->mb_w, mb_h, 0);
|
io->a, io->width, io->mb_w, mb_h, 0);
|
||||||
}
|
}
|
||||||
num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);
|
num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);
|
||||||
Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
|
Rescale(io->u, io->uv_stride, uv_mb_h, p->scaler_u);
|
||||||
Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
|
Rescale(io->v, io->uv_stride, uv_mb_h, p->scaler_v);
|
||||||
return num_lines_out;
|
return num_lines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
|
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
|
||||||
int expected_num_lines_out) {
|
int expected_num_lines_out) {
|
||||||
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
|
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
|
||||||
|
uint8_t* const dst_a = buf->a + p->last_y * buf->a_stride;
|
||||||
if (io->a != NULL) {
|
if (io->a != NULL) {
|
||||||
uint8_t* dst_y = buf->y + p->last_y * buf->y_stride;
|
uint8_t* const dst_y = buf->y + p->last_y * buf->y_stride;
|
||||||
const uint8_t* src_a = buf->a + p->last_y * buf->a_stride;
|
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a);
|
||||||
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
|
|
||||||
(void)expected_num_lines_out;
|
|
||||||
assert(expected_num_lines_out == num_lines_out);
|
assert(expected_num_lines_out == num_lines_out);
|
||||||
if (num_lines_out > 0) { // unmultiply the Y
|
if (num_lines_out > 0) { // unmultiply the Y
|
||||||
WebPMultRows(dst_y, buf->y_stride, src_a, buf->a_stride,
|
WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride,
|
||||||
p->scaler_a.dst_width, num_lines_out, 1);
|
p->scaler_a->dst_width, num_lines_out, 1);
|
||||||
}
|
}
|
||||||
} else if (buf->a != NULL) {
|
} else if (buf->a != NULL) {
|
||||||
// the user requested alpha, but there is none, set it to opaque.
|
// the user requested alpha, but there is none, set it to opaque.
|
||||||
assert(p->last_y + expected_num_lines_out <= io->scaled_height);
|
assert(p->last_y + expected_num_lines_out <= io->scaled_height);
|
||||||
FillAlphaPlane(buf->a + p->last_y * buf->a_stride,
|
FillAlphaPlane(dst_a, io->scaled_width, expected_num_lines_out,
|
||||||
io->scaled_width, expected_num_lines_out, buf->a_stride);
|
buf->a_stride);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -305,31 +304,42 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
const int uv_in_height = (io->mb_h + 1) >> 1;
|
const int uv_in_height = (io->mb_h + 1) >> 1;
|
||||||
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
|
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
|
||||||
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
|
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
|
||||||
size_t tmp_size;
|
size_t tmp_size, rescaler_size;
|
||||||
rescaler_t* work;
|
rescaler_t* work;
|
||||||
|
WebPRescaler* scalers;
|
||||||
|
const int num_rescalers = has_alpha ? 4 : 3;
|
||||||
|
|
||||||
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
|
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
tmp_size += work_size * sizeof(*work);
|
tmp_size += work_size * sizeof(*work);
|
||||||
}
|
}
|
||||||
p->memory = WebPSafeMalloc(1ULL, tmp_size);
|
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
|
||||||
|
|
||||||
|
p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size);
|
||||||
if (p->memory == NULL) {
|
if (p->memory == NULL) {
|
||||||
return 0; // memory error
|
return 0; // memory error
|
||||||
}
|
}
|
||||||
work = (rescaler_t*)p->memory;
|
work = (rescaler_t*)p->memory;
|
||||||
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
|
|
||||||
|
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size);
|
||||||
|
p->scaler_y = &scalers[0];
|
||||||
|
p->scaler_u = &scalers[1];
|
||||||
|
p->scaler_v = &scalers[2];
|
||||||
|
p->scaler_a = has_alpha ? &scalers[3] : NULL;
|
||||||
|
|
||||||
|
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
||||||
buf->y, out_width, out_height, buf->y_stride, 1,
|
buf->y, out_width, out_height, buf->y_stride, 1,
|
||||||
work);
|
work);
|
||||||
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
|
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
||||||
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
|
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
|
||||||
work + work_size);
|
work + work_size);
|
||||||
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
|
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
||||||
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
|
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
|
||||||
work + work_size + uv_work_size);
|
work + work_size + uv_work_size);
|
||||||
p->emit = EmitRescaledYUV;
|
p->emit = EmitRescaledYUV;
|
||||||
|
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
|
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
||||||
buf->a, out_width, out_height, buf->a_stride, 1,
|
buf->a, out_width, out_height, buf->a_stride, 1,
|
||||||
work + work_size + 2 * uv_work_size);
|
work + work_size + 2 * uv_work_size);
|
||||||
p->emit_alpha = EmitRescaledAlphaYUV;
|
p->emit_alpha = EmitRescaledAlphaYUV;
|
||||||
@@ -349,15 +359,15 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
|
|||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
// For RGB rescaling, because of the YUV420, current scan position
|
// 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.
|
// U/V can be +1/-1 line from the Y one. Hence the double test.
|
||||||
while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
|
while (WebPRescalerHasPendingOutput(p->scaler_y) &&
|
||||||
WebPRescalerHasPendingOutput(&p->scaler_u)) {
|
WebPRescalerHasPendingOutput(p->scaler_u)) {
|
||||||
assert(y_pos + num_lines_out < p->output->height);
|
assert(y_pos + num_lines_out < p->output->height);
|
||||||
assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
|
assert(p->scaler_u->y_accum == p->scaler_v->y_accum);
|
||||||
WebPRescalerExportRow(&p->scaler_y);
|
WebPRescalerExportRow(p->scaler_y);
|
||||||
WebPRescalerExportRow(&p->scaler_u);
|
WebPRescalerExportRow(p->scaler_u);
|
||||||
WebPRescalerExportRow(&p->scaler_v);
|
WebPRescalerExportRow(p->scaler_v);
|
||||||
convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
|
convert(p->scaler_y->dst, p->scaler_u->dst, p->scaler_v->dst,
|
||||||
dst, p->scaler_y.dst_width);
|
dst, p->scaler_y->dst_width);
|
||||||
dst += buf->stride;
|
dst += buf->stride;
|
||||||
++num_lines_out;
|
++num_lines_out;
|
||||||
}
|
}
|
||||||
@@ -371,15 +381,15 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
while (j < mb_h) {
|
while (j < mb_h) {
|
||||||
const int y_lines_in =
|
const int y_lines_in =
|
||||||
WebPRescalerImport(&p->scaler_y, mb_h - j,
|
WebPRescalerImport(p->scaler_y, mb_h - j,
|
||||||
io->y + j * io->y_stride, io->y_stride);
|
io->y + j * io->y_stride, io->y_stride);
|
||||||
j += y_lines_in;
|
j += y_lines_in;
|
||||||
if (WebPRescaleNeededLines(&p->scaler_u, uv_mb_h - uv_j)) {
|
if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) {
|
||||||
const int u_lines_in =
|
const int u_lines_in =
|
||||||
WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j,
|
WebPRescalerImport(p->scaler_u, uv_mb_h - uv_j,
|
||||||
io->u + uv_j * io->uv_stride, io->uv_stride);
|
io->u + uv_j * io->uv_stride, io->uv_stride);
|
||||||
const int v_lines_in =
|
const int v_lines_in =
|
||||||
WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
|
WebPRescalerImport(p->scaler_v, uv_mb_h - uv_j,
|
||||||
io->v + uv_j * io->uv_stride, io->uv_stride);
|
io->v + uv_j * io->uv_stride, io->uv_stride);
|
||||||
(void)v_lines_in; // remove a gcc warning
|
(void)v_lines_in; // remove a gcc warning
|
||||||
assert(u_lines_in == v_lines_in);
|
assert(u_lines_in == v_lines_in);
|
||||||
@@ -400,13 +410,13 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
|
|||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
|
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
|
||||||
uint32_t non_opaque = 0;
|
uint32_t non_opaque = 0;
|
||||||
const int width = p->scaler_a.dst_width;
|
const int width = p->scaler_a->dst_width;
|
||||||
|
|
||||||
while (WebPRescalerHasPendingOutput(&p->scaler_a) &&
|
while (WebPRescalerHasPendingOutput(p->scaler_a) &&
|
||||||
num_lines_out < max_lines_out) {
|
num_lines_out < max_lines_out) {
|
||||||
assert(y_pos + num_lines_out < p->output->height);
|
assert(y_pos + num_lines_out < p->output->height);
|
||||||
WebPRescalerExportRow(&p->scaler_a);
|
WebPRescalerExportRow(p->scaler_a);
|
||||||
non_opaque |= WebPDispatchAlpha(p->scaler_a.dst, 0, width, 1, dst, 0);
|
non_opaque |= WebPDispatchAlpha(p->scaler_a->dst, 0, width, 1, dst, 0);
|
||||||
dst += buf->stride;
|
dst += buf->stride;
|
||||||
++num_lines_out;
|
++num_lines_out;
|
||||||
}
|
}
|
||||||
@@ -428,18 +438,18 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
|
|||||||
#endif
|
#endif
|
||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
const WEBP_CSP_MODE colorspace = p->output->colorspace;
|
const WEBP_CSP_MODE colorspace = p->output->colorspace;
|
||||||
const int width = p->scaler_a.dst_width;
|
const int width = p->scaler_a->dst_width;
|
||||||
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
|
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
|
||||||
uint32_t alpha_mask = 0x0f;
|
uint32_t alpha_mask = 0x0f;
|
||||||
|
|
||||||
while (WebPRescalerHasPendingOutput(&p->scaler_a) &&
|
while (WebPRescalerHasPendingOutput(p->scaler_a) &&
|
||||||
num_lines_out < max_lines_out) {
|
num_lines_out < max_lines_out) {
|
||||||
int i;
|
int i;
|
||||||
assert(y_pos + num_lines_out < p->output->height);
|
assert(y_pos + num_lines_out < p->output->height);
|
||||||
WebPRescalerExportRow(&p->scaler_a);
|
WebPRescalerExportRow(p->scaler_a);
|
||||||
for (i = 0; i < width; ++i) {
|
for (i = 0; i < width; ++i) {
|
||||||
// Fill in the alpha value (converted to 4 bits).
|
// Fill in the alpha value (converted to 4 bits).
|
||||||
const uint32_t alpha_value = p->scaler_a.dst[i] >> 4;
|
const uint32_t alpha_value = p->scaler_a->dst[i] >> 4;
|
||||||
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
|
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
|
||||||
alpha_mask &= alpha_value;
|
alpha_mask &= alpha_value;
|
||||||
}
|
}
|
||||||
@@ -455,7 +465,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
|
|||||||
static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
|
static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
|
||||||
int expected_num_out_lines) {
|
int expected_num_out_lines) {
|
||||||
if (io->a != NULL) {
|
if (io->a != NULL) {
|
||||||
WebPRescaler* const scaler = &p->scaler_a;
|
WebPRescaler* const scaler = p->scaler_a;
|
||||||
int lines_left = expected_num_out_lines;
|
int lines_left = expected_num_out_lines;
|
||||||
const int y_end = p->last_y + lines_left;
|
const int y_end = p->last_y + lines_left;
|
||||||
while (lines_left > 0) {
|
while (lines_left > 0) {
|
||||||
@@ -477,7 +487,9 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
const size_t work_size = 2 * out_width; // scratch memory for one rescaler
|
const size_t work_size = 2 * out_width; // scratch memory for one rescaler
|
||||||
rescaler_t* work; // rescalers work area
|
rescaler_t* work; // rescalers work area
|
||||||
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
|
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
|
||||||
size_t tmp_size1, tmp_size2, total_size;
|
size_t tmp_size1, tmp_size2, total_size, rescaler_size;
|
||||||
|
WebPRescaler* scalers;
|
||||||
|
const int num_rescalers = has_alpha ? 4 : 3;
|
||||||
|
|
||||||
tmp_size1 = 3 * work_size;
|
tmp_size1 = 3 * work_size;
|
||||||
tmp_size2 = 3 * out_width;
|
tmp_size2 = 3 * out_width;
|
||||||
@@ -486,26 +498,35 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
tmp_size2 += out_width;
|
tmp_size2 += out_width;
|
||||||
}
|
}
|
||||||
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
|
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
|
||||||
p->memory = WebPSafeMalloc(1ULL, total_size);
|
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
|
||||||
|
|
||||||
|
p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size);
|
||||||
if (p->memory == NULL) {
|
if (p->memory == NULL) {
|
||||||
return 0; // memory error
|
return 0; // memory error
|
||||||
}
|
}
|
||||||
work = (rescaler_t*)p->memory;
|
work = (rescaler_t*)p->memory;
|
||||||
tmp = (uint8_t*)(work + tmp_size1);
|
tmp = (uint8_t*)(work + tmp_size1);
|
||||||
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
|
|
||||||
|
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size);
|
||||||
|
p->scaler_y = &scalers[0];
|
||||||
|
p->scaler_u = &scalers[1];
|
||||||
|
p->scaler_v = &scalers[2];
|
||||||
|
p->scaler_a = has_alpha ? &scalers[3] : NULL;
|
||||||
|
|
||||||
|
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
||||||
tmp + 0 * out_width, out_width, out_height, 0, 1,
|
tmp + 0 * out_width, out_width, out_height, 0, 1,
|
||||||
work + 0 * work_size);
|
work + 0 * work_size);
|
||||||
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
|
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
||||||
tmp + 1 * out_width, out_width, out_height, 0, 1,
|
tmp + 1 * out_width, out_width, out_height, 0, 1,
|
||||||
work + 1 * work_size);
|
work + 1 * work_size);
|
||||||
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
|
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
||||||
tmp + 2 * out_width, out_width, out_height, 0, 1,
|
tmp + 2 * out_width, out_width, out_height, 0, 1,
|
||||||
work + 2 * work_size);
|
work + 2 * work_size);
|
||||||
p->emit = EmitRescaledRGB;
|
p->emit = EmitRescaledRGB;
|
||||||
WebPInitYUV444Converters();
|
WebPInitYUV444Converters();
|
||||||
|
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
|
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
||||||
tmp + 3 * out_width, out_width, out_height, 0, 1,
|
tmp + 3 * out_width, out_width, out_height, 0, 1,
|
||||||
work + 3 * work_size);
|
work + 3 * work_size);
|
||||||
p->emit_alpha = EmitRescaledAlphaRGB;
|
p->emit_alpha = EmitRescaledAlphaRGB;
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./vp8i.h"
|
#include "./vp8i_dec.h"
|
||||||
|
|
||||||
static WEBP_INLINE int clip(int v, int M) {
|
static WEBP_INLINE int clip(int v, int M) {
|
||||||
return v < 0 ? 0 : v > M ? M : v;
|
return v < 0 ? 0 : v > M ? M : v;
|
||||||
@@ -11,10 +11,13 @@
|
|||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./vp8i.h"
|
#include "./vp8i_dec.h"
|
||||||
#include "../utils/bit_reader_inl.h"
|
#include "../utils/bit_reader_inl_utils.h"
|
||||||
|
|
||||||
|
#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
|
||||||
|
// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then.
|
||||||
#define USE_GENERIC_TREE
|
#define USE_GENERIC_TREE
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_GENERIC_TREE
|
#ifdef USE_GENERIC_TREE
|
||||||
static const int8_t kYModesIntra4[18] = {
|
static const int8_t kYModesIntra4[18] = {
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./alphai.h"
|
#include "./alphai_dec.h"
|
||||||
#include "./vp8i.h"
|
#include "./vp8i_dec.h"
|
||||||
#include "./vp8li.h"
|
#include "./vp8li_dec.h"
|
||||||
#include "./webpi.h"
|
#include "./webpi_dec.h"
|
||||||
#include "../utils/bit_reader_inl.h"
|
#include "../utils/bit_reader_inl_utils.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -26,6 +26,16 @@ int WebPGetDecoderVersion(void) {
|
|||||||
return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION;
|
return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Signature and pointer-to-function for GetCoeffs() variants below.
|
||||||
|
|
||||||
|
typedef int (*GetCoeffsFunc)(VP8BitReader* const br,
|
||||||
|
const VP8BandProbas* const prob[],
|
||||||
|
int ctx, const quant_t dq, int n, int16_t* out);
|
||||||
|
static volatile GetCoeffsFunc GetCoeffs = NULL;
|
||||||
|
|
||||||
|
static void InitGetCoeffs(void);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// VP8Decoder
|
// VP8Decoder
|
||||||
|
|
||||||
@@ -51,6 +61,7 @@ VP8Decoder* VP8New(void) {
|
|||||||
WebPGetWorkerInterface()->Init(&dec->worker_);
|
WebPGetWorkerInterface()->Init(&dec->worker_);
|
||||||
dec->ready_ = 0;
|
dec->ready_ = 0;
|
||||||
dec->num_parts_minus_one_ = 0;
|
dec->num_parts_minus_one_ = 0;
|
||||||
|
InitGetCoeffs();
|
||||||
}
|
}
|
||||||
return dec;
|
return dec;
|
||||||
}
|
}
|
||||||
@@ -273,12 +284,14 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
frm_hdr->profile_ = (bits >> 1) & 7;
|
frm_hdr->profile_ = (bits >> 1) & 7;
|
||||||
frm_hdr->show_ = (bits >> 4) & 1;
|
frm_hdr->show_ = (bits >> 4) & 1;
|
||||||
frm_hdr->partition_length_ = (bits >> 5);
|
frm_hdr->partition_length_ = (bits >> 5);
|
||||||
if (frm_hdr->profile_ > 3)
|
if (frm_hdr->profile_ > 3) {
|
||||||
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
"Incorrect keyframe parameters.");
|
"Incorrect keyframe parameters.");
|
||||||
if (!frm_hdr->show_)
|
}
|
||||||
|
if (!frm_hdr->show_) {
|
||||||
return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
|
return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
|
||||||
"Frame not displayable.");
|
"Frame not displayable.");
|
||||||
|
}
|
||||||
buf += 3;
|
buf += 3;
|
||||||
buf_size -= 3;
|
buf_size -= 3;
|
||||||
}
|
}
|
||||||
@@ -420,7 +433,8 @@ static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the position of the last non-zero coeff plus one
|
// Returns the position of the last non-zero coeff plus one
|
||||||
static int GetCoeffs(VP8BitReader* const br, const VP8BandProbas* const prob[],
|
static int GetCoeffsFast(VP8BitReader* const br,
|
||||||
|
const VP8BandProbas* const prob[],
|
||||||
int ctx, const quant_t dq, int n, int16_t* out) {
|
int ctx, const quant_t dq, int n, int16_t* out) {
|
||||||
const uint8_t* p = prob[n]->probas_[ctx];
|
const uint8_t* p = prob[n]->probas_[ctx];
|
||||||
for (; n < 16; ++n) {
|
for (; n < 16; ++n) {
|
||||||
@@ -447,6 +461,46 @@ static int GetCoeffs(VP8BitReader* const br, const VP8BandProbas* const prob[],
|
|||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This version of GetCoeffs() uses VP8GetBitAlt() which is an alternate version
|
||||||
|
// of VP8GetBitAlt() targeting specific platforms.
|
||||||
|
static int GetCoeffsAlt(VP8BitReader* const br,
|
||||||
|
const VP8BandProbas* const prob[],
|
||||||
|
int ctx, const quant_t dq, int n, int16_t* out) {
|
||||||
|
const uint8_t* p = prob[n]->probas_[ctx];
|
||||||
|
for (; n < 16; ++n) {
|
||||||
|
if (!VP8GetBitAlt(br, p[0])) {
|
||||||
|
return n; // previous coeff was last non-zero coeff
|
||||||
|
}
|
||||||
|
while (!VP8GetBitAlt(br, p[1])) { // sequence of zero coeffs
|
||||||
|
p = prob[++n]->probas_[0];
|
||||||
|
if (n == 16) return 16;
|
||||||
|
}
|
||||||
|
{ // non zero coeff
|
||||||
|
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
|
||||||
|
int v;
|
||||||
|
if (!VP8GetBitAlt(br, p[2])) {
|
||||||
|
v = 1;
|
||||||
|
p = p_ctx[1];
|
||||||
|
} else {
|
||||||
|
v = GetLargeValue(br, p);
|
||||||
|
p = p_ctx[2];
|
||||||
|
}
|
||||||
|
out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION static void InitGetCoeffs(void) {
|
||||||
|
if (GetCoeffs == NULL) {
|
||||||
|
if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
|
||||||
|
GetCoeffs = GetCoeffsAlt;
|
||||||
|
} else {
|
||||||
|
GetCoeffs = GetCoeffsFast;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) {
|
static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) {
|
||||||
nz_coeffs <<= 2;
|
nz_coeffs <<= 2;
|
||||||
nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz;
|
nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz;
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
#define WEBP_DEC_VP8I_H_
|
#define WEBP_DEC_VP8I_H_
|
||||||
|
|
||||||
#include <string.h> // for memcpy()
|
#include <string.h> // for memcpy()
|
||||||
#include "./common.h"
|
#include "./common_dec.h"
|
||||||
#include "./vp8li.h"
|
#include "./vp8li_dec.h"
|
||||||
#include "../utils/bit_reader.h"
|
#include "../utils/bit_reader_utils.h"
|
||||||
#include "../utils/random.h"
|
#include "../utils/random_utils.h"
|
||||||
#include "../utils/thread.h"
|
#include "../utils/thread_utils.h"
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -31,8 +31,8 @@ extern "C" {
|
|||||||
|
|
||||||
// version numbers
|
// version numbers
|
||||||
#define DEC_MAJ_VERSION 0
|
#define DEC_MAJ_VERSION 0
|
||||||
#define DEC_MIN_VERSION 5
|
#define DEC_MIN_VERSION 6
|
||||||
#define DEC_REV_VERSION 1
|
#define DEC_REV_VERSION 0
|
||||||
|
|
||||||
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
||||||
// Constraints are: We need to store one 16x16 block of luma samples (y),
|
// Constraints are: We need to store one 16x16 block of luma samples (y),
|
||||||
@@ -14,13 +14,14 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./alphai.h"
|
#include "./alphai_dec.h"
|
||||||
#include "./vp8li.h"
|
#include "./vp8li_dec.h"
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../dsp/lossless.h"
|
#include "../dsp/lossless.h"
|
||||||
|
#include "../dsp/lossless_common.h"
|
||||||
#include "../dsp/yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
#include "../utils/endian_inl.h"
|
#include "../utils/endian_inl_utils.h"
|
||||||
#include "../utils/huffman.h"
|
#include "../utils/huffman_utils.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
#define NUM_ARGB_CACHE_ROWS 16
|
#define NUM_ARGB_CACHE_ROWS 16
|
||||||
@@ -547,11 +548,14 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
|
|||||||
uint8_t* const row_out = out + num_lines_out * out_stride;
|
uint8_t* const row_out = out + num_lines_out * out_stride;
|
||||||
const int lines_left = mb_h - num_lines_in;
|
const int lines_left = mb_h - num_lines_in;
|
||||||
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
|
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
|
||||||
|
int lines_imported;
|
||||||
assert(needed_lines > 0 && needed_lines <= lines_left);
|
assert(needed_lines > 0 && needed_lines <= lines_left);
|
||||||
WebPMultARGBRows(row_in, in_stride,
|
WebPMultARGBRows(row_in, in_stride,
|
||||||
dec->rescaler->src_width, needed_lines, 0);
|
dec->rescaler->src_width, needed_lines, 0);
|
||||||
|
lines_imported =
|
||||||
WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride);
|
WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride);
|
||||||
num_lines_in += needed_lines;
|
assert(lines_imported == needed_lines);
|
||||||
|
num_lines_in += lines_imported;
|
||||||
num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out);
|
num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out);
|
||||||
}
|
}
|
||||||
return num_lines_out;
|
return num_lines_out;
|
||||||
@@ -623,9 +627,12 @@ static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec,
|
|||||||
while (num_lines_in < mb_h) {
|
while (num_lines_in < mb_h) {
|
||||||
const int lines_left = mb_h - num_lines_in;
|
const int lines_left = mb_h - num_lines_in;
|
||||||
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
|
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
|
||||||
|
int lines_imported;
|
||||||
WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0);
|
WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0);
|
||||||
|
lines_imported =
|
||||||
WebPRescalerImport(dec->rescaler, lines_left, in, in_stride);
|
WebPRescalerImport(dec->rescaler, lines_left, in, in_stride);
|
||||||
num_lines_in += needed_lines;
|
assert(lines_imported == needed_lines);
|
||||||
|
num_lines_in += lines_imported;
|
||||||
in += needed_lines * in_stride;
|
in += needed_lines * in_stride;
|
||||||
y_pos += ExportYUVA(dec, y_pos);
|
y_pos += ExportYUVA(dec, y_pos);
|
||||||
}
|
}
|
||||||
@@ -705,13 +712,15 @@ static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
|
|||||||
uint32_t* const rows_out = dec->argb_cache_;
|
uint32_t* const rows_out = dec->argb_cache_;
|
||||||
|
|
||||||
// Inverse transforms.
|
// Inverse transforms.
|
||||||
// TODO: most transforms only need to operate on the cropped region only.
|
|
||||||
memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
|
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
VP8LTransform* const transform = &dec->transforms_[n];
|
VP8LTransform* const transform = &dec->transforms_[n];
|
||||||
VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
|
VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
|
||||||
rows_in = rows_out;
|
rows_in = rows_out;
|
||||||
}
|
}
|
||||||
|
if (rows_in != rows_out) {
|
||||||
|
// No transform called, hence just copy.
|
||||||
|
memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes (transforms, scales & color-converts) the rows decoded after the
|
// Processes (transforms, scales & color-converts) the rows decoded after the
|
||||||
@@ -1210,8 +1219,9 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
|
|||||||
// Equivalent to AddPixelEq(), on a byte-basis.
|
// Equivalent to AddPixelEq(), on a byte-basis.
|
||||||
new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
|
new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
|
||||||
}
|
}
|
||||||
for (; i < 4 * final_num_colors; ++i)
|
for (; i < 4 * final_num_colors; ++i) {
|
||||||
new_data[i] = 0; // black tail.
|
new_data[i] = 0; // black tail.
|
||||||
|
}
|
||||||
WebPSafeFree(transform->data_);
|
WebPSafeFree(transform->data_);
|
||||||
transform->data_ = new_color_map;
|
transform->data_ = new_color_map;
|
||||||
}
|
}
|
||||||
@@ -1482,9 +1492,8 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) {
|
|||||||
const int cache_pixs = width * num_rows_to_process;
|
const int cache_pixs = width * num_rows_to_process;
|
||||||
uint8_t* const dst = output + width * cur_row;
|
uint8_t* const dst = output + width * cur_row;
|
||||||
const uint32_t* const src = dec->argb_cache_;
|
const uint32_t* const src = dec->argb_cache_;
|
||||||
int i;
|
|
||||||
ApplyInverseTransforms(dec, num_rows_to_process, in);
|
ApplyInverseTransforms(dec, num_rows_to_process, in);
|
||||||
for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff;
|
WebPExtractGreen(src, dst, cache_pixs);
|
||||||
AlphaApplyFilter(alph_dec,
|
AlphaApplyFilter(alph_dec,
|
||||||
cur_row, cur_row + num_rows_to_process, dst, width);
|
cur_row, cur_row + num_rows_to_process, dst, width);
|
||||||
num_rows -= num_rows_to_process;
|
num_rows -= num_rows_to_process;
|
||||||
@@ -1552,6 +1561,8 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
|
|||||||
return 1; // done
|
return 1; // done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!alph_dec->use_8b_decode_) WebPInitAlphaProcessing();
|
||||||
|
|
||||||
// Decode (with special row processing).
|
// Decode (with special row processing).
|
||||||
return alph_dec->use_8b_decode_ ?
|
return alph_dec->use_8b_decode_ ?
|
||||||
DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
|
DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
#define WEBP_DEC_VP8LI_H_
|
#define WEBP_DEC_VP8LI_H_
|
||||||
|
|
||||||
#include <string.h> // for memcpy()
|
#include <string.h> // for memcpy()
|
||||||
#include "./webpi.h"
|
#include "./webpi_dec.h"
|
||||||
#include "../utils/bit_reader.h"
|
#include "../utils/bit_reader_utils.h"
|
||||||
#include "../utils/color_cache.h"
|
#include "../utils/color_cache_utils.h"
|
||||||
#include "../utils/huffman.h"
|
#include "../utils/huffman_utils.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./vp8i.h"
|
#include "./vp8i_dec.h"
|
||||||
#include "./vp8li.h"
|
#include "./vp8li_dec.h"
|
||||||
#include "./webpi.h"
|
#include "./webpi_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../webp/mux_types.h" // ALPHA_FLAG
|
#include "../webp/mux_types.h" // ALPHA_FLAG
|
||||||
|
|
||||||
@@ -39,8 +39,8 @@
|
|||||||
// 20..23 VP8X flags bit-map corresponding to the chunk-types present.
|
// 20..23 VP8X flags bit-map corresponding to the chunk-types present.
|
||||||
// 24..26 Width of the Canvas Image.
|
// 24..26 Width of the Canvas Image.
|
||||||
// 27..29 Height of the Canvas Image.
|
// 27..29 Height of the Canvas Image.
|
||||||
// There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8,
|
// There can be extra chunks after the "VP8X" chunk (ICCP, ANMF, VP8, VP8L,
|
||||||
// VP8L, XMP, EXIF ...)
|
// XMP, EXIF ...)
|
||||||
// All sizes are in little-endian order.
|
// All sizes are in little-endian order.
|
||||||
// Note: chunk data size must be padded to multiple of 2 when written.
|
// Note: chunk data size must be padded to multiple of 2 when written.
|
||||||
|
|
||||||
@@ -289,7 +289,6 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
|
|||||||
int found_riff = 0;
|
int found_riff = 0;
|
||||||
int found_vp8x = 0;
|
int found_vp8x = 0;
|
||||||
int animation_present = 0;
|
int animation_present = 0;
|
||||||
int fragments_present = 0;
|
|
||||||
const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
|
const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
|
||||||
|
|
||||||
VP8StatusCode status;
|
VP8StatusCode status;
|
||||||
@@ -318,7 +317,6 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
|
|||||||
return status; // Wrong VP8X / insufficient data.
|
return status; // Wrong VP8X / insufficient data.
|
||||||
}
|
}
|
||||||
animation_present = !!(flags & ANIMATION_FLAG);
|
animation_present = !!(flags & ANIMATION_FLAG);
|
||||||
fragments_present = !!(flags & FRAGMENTS_FLAG);
|
|
||||||
if (!found_riff && found_vp8x) {
|
if (!found_riff && found_vp8x) {
|
||||||
// Note: This restriction may be removed in the future, if it becomes
|
// Note: This restriction may be removed in the future, if it becomes
|
||||||
// necessary to send VP8X chunk to the decoder.
|
// necessary to send VP8X chunk to the decoder.
|
||||||
@@ -330,8 +328,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
|
|||||||
|
|
||||||
image_width = canvas_width;
|
image_width = canvas_width;
|
||||||
image_height = canvas_height;
|
image_height = canvas_height;
|
||||||
if (found_vp8x && (animation_present || fragments_present) &&
|
if (found_vp8x && animation_present && headers == NULL) {
|
||||||
headers == NULL) {
|
|
||||||
status = VP8_STATUS_OK;
|
status = VP8_STATUS_OK;
|
||||||
goto ReturnWidthHeight; // Just return features from VP8X header.
|
goto ReturnWidthHeight; // Just return features from VP8X header.
|
||||||
}
|
}
|
||||||
@@ -362,7 +359,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
|
|||||||
return VP8_STATUS_BITSTREAM_ERROR;
|
return VP8_STATUS_BITSTREAM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format != NULL && !(animation_present || fragments_present)) {
|
if (format != NULL && !animation_present) {
|
||||||
*format = hdrs.is_lossless ? 2 : 1;
|
*format = hdrs.is_lossless ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,8 +18,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../utils/rescaler.h"
|
#include "../utils/rescaler_utils.h"
|
||||||
#include "./decode_vp8.h"
|
#include "./vp8_dec.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// WebPDecParams: Decoding output parameters. Transient internal object.
|
// WebPDecParams: Decoding output parameters. Transient internal object.
|
||||||
@@ -38,27 +38,18 @@ struct WebPDecParams {
|
|||||||
|
|
||||||
int last_y; // coordinate of the line that was last output
|
int last_y; // coordinate of the line that was last output
|
||||||
const WebPDecoderOptions* options; // if not NULL, use alt decoding features
|
const WebPDecoderOptions* options; // if not NULL, use alt decoding features
|
||||||
// rescalers
|
|
||||||
WebPRescaler scaler_y, scaler_u, scaler_v, scaler_a;
|
WebPRescaler* scaler_y, *scaler_u, *scaler_v, *scaler_a; // rescalers
|
||||||
void* memory; // overall scratch memory for the output work.
|
void* memory; // overall scratch memory for the output work.
|
||||||
|
|
||||||
OutputFunc emit; // output RGB or YUV samples
|
OutputFunc emit; // output RGB or YUV samples
|
||||||
OutputAlphaFunc emit_alpha; // output alpha channel
|
OutputAlphaFunc emit_alpha; // output alpha channel
|
||||||
OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values
|
OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values
|
||||||
|
|
||||||
WebPDecBuffer* final_output; // In case the user supplied a slow-memory
|
|
||||||
// output, we decode image in temporary buffer
|
|
||||||
// (this::output) and copy it here.
|
|
||||||
WebPDecBuffer tmp_buffer; // this::output will point to this one in case
|
|
||||||
// of slow memory.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Should be called first, before any use of the WebPDecParams object.
|
// Should be called first, before any use of the WebPDecParams object.
|
||||||
void WebPResetDecParams(WebPDecParams* const params);
|
void WebPResetDecParams(WebPDecParams* const params);
|
||||||
|
|
||||||
// Delete all memory (after an error occurred, for instance)
|
|
||||||
void WebPFreeDecParams(WebPDecParams* const params);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Header parsing helpers
|
// Header parsing helpers
|
||||||
|
|
||||||
@@ -9,6 +9,6 @@ libwebpdemuxinclude_HEADERS += ../webp/mux_types.h
|
|||||||
libwebpdemuxinclude_HEADERS += ../webp/types.h
|
libwebpdemuxinclude_HEADERS += ../webp/types.h
|
||||||
|
|
||||||
libwebpdemux_la_LIBADD = ../libwebp.la
|
libwebpdemux_la_LIBADD = ../libwebp.la
|
||||||
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:0:0
|
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:2:0
|
||||||
libwebpdemuxincludedir = $(includedir)/webp
|
libwebpdemuxincludedir = $(includedir)/webp
|
||||||
pkgconfig_DATA = libwebpdemux.pc
|
pkgconfig_DATA = libwebpdemux.pc
|
||||||
|
|||||||
@@ -112,18 +112,15 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
|
|||||||
dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR);
|
dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR);
|
||||||
dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT);
|
dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT);
|
||||||
|
|
||||||
{
|
|
||||||
const int canvas_bytes =
|
|
||||||
dec->info_.canvas_width * NUM_CHANNELS * dec->info_.canvas_height;
|
|
||||||
// Note: calloc() because we fill frame with zeroes as well.
|
// Note: calloc() because we fill frame with zeroes as well.
|
||||||
dec->curr_frame_ = WebPSafeCalloc(1ULL, canvas_bytes);
|
dec->curr_frame_ = (uint8_t*)WebPSafeCalloc(
|
||||||
|
dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height);
|
||||||
if (dec->curr_frame_ == NULL) goto Error;
|
if (dec->curr_frame_ == NULL) goto Error;
|
||||||
dec->prev_frame_disposed_ = WebPSafeCalloc(1ULL, canvas_bytes);
|
dec->prev_frame_disposed_ = (uint8_t*)WebPSafeCalloc(
|
||||||
|
dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height);
|
||||||
if (dec->prev_frame_disposed_ == NULL) goto Error;
|
if (dec->prev_frame_disposed_ == NULL) goto Error;
|
||||||
}
|
|
||||||
|
|
||||||
WebPAnimDecoderReset(dec);
|
WebPAnimDecoderReset(dec);
|
||||||
|
|
||||||
return dec;
|
return dec;
|
||||||
|
|
||||||
Error:
|
Error:
|
||||||
@@ -144,9 +141,13 @@ static int IsFullFrame(int width, int height, int canvas_width,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear the canvas to transparent.
|
// Clear the canvas to transparent.
|
||||||
static void ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
|
static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
|
||||||
uint32_t canvas_height) {
|
uint32_t canvas_height) {
|
||||||
memset(buf, 0, canvas_width * NUM_CHANNELS * canvas_height);
|
const uint64_t size =
|
||||||
|
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
|
||||||
|
if (size != (size_t)size) return 0;
|
||||||
|
memset(buf, 0, (size_t)size);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear given frame rectangle to transparent.
|
// Clear given frame rectangle to transparent.
|
||||||
@@ -162,10 +163,13 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy width * height pixels from 'src' to 'dst'.
|
// Copy width * height pixels from 'src' to 'dst'.
|
||||||
static void CopyCanvas(const uint8_t* src, uint8_t* dst,
|
static int CopyCanvas(const uint8_t* src, uint8_t* dst,
|
||||||
uint32_t width, uint32_t height) {
|
uint32_t width, uint32_t height) {
|
||||||
|
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
|
||||||
|
if (size != (size_t)size) return 0;
|
||||||
assert(src != NULL && dst != NULL);
|
assert(src != NULL && dst != NULL);
|
||||||
memcpy(dst, src, width * NUM_CHANNELS * height);
|
memcpy(dst, src, (size_t)size);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the current frame is a key-frame.
|
// Returns true if the current frame is a key-frame.
|
||||||
@@ -328,9 +332,14 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
|||||||
is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_,
|
is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_,
|
||||||
dec->prev_frame_was_keyframe_, width, height);
|
dec->prev_frame_was_keyframe_, width, height);
|
||||||
if (is_key_frame) {
|
if (is_key_frame) {
|
||||||
ZeroFillCanvas(dec->curr_frame_, width, height);
|
if (!ZeroFillCanvas(dec->curr_frame_, width, height)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_, width, height);
|
if (!CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_,
|
||||||
|
width, height)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode.
|
// Decode.
|
||||||
@@ -393,6 +402,7 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
|||||||
|
|
||||||
// Update info of the previous frame and dispose it for the next iteration.
|
// Update info of the previous frame and dispose it for the next iteration.
|
||||||
dec->prev_frame_timestamp_ = timestamp;
|
dec->prev_frame_timestamp_ = timestamp;
|
||||||
|
WebPDemuxReleaseIterator(&dec->prev_iter_);
|
||||||
dec->prev_iter_ = iter;
|
dec->prev_iter_ = iter;
|
||||||
dec->prev_frame_was_keyframe_ = is_key_frame;
|
dec->prev_frame_was_keyframe_ = is_key_frame;
|
||||||
CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height);
|
CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height);
|
||||||
@@ -421,6 +431,7 @@ int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) {
|
|||||||
void WebPAnimDecoderReset(WebPAnimDecoder* dec) {
|
void WebPAnimDecoderReset(WebPAnimDecoder* dec) {
|
||||||
if (dec != NULL) {
|
if (dec != NULL) {
|
||||||
dec->prev_frame_timestamp_ = 0;
|
dec->prev_frame_timestamp_ = 0;
|
||||||
|
WebPDemuxReleaseIterator(&dec->prev_iter_);
|
||||||
memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_));
|
memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_));
|
||||||
dec->prev_frame_was_keyframe_ = 0;
|
dec->prev_frame_was_keyframe_ = 0;
|
||||||
dec->next_frame_ = 1;
|
dec->next_frame_ = 1;
|
||||||
@@ -434,6 +445,7 @@ const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) {
|
|||||||
|
|
||||||
void WebPAnimDecoderDelete(WebPAnimDecoder* dec) {
|
void WebPAnimDecoderDelete(WebPAnimDecoder* dec) {
|
||||||
if (dec != NULL) {
|
if (dec != NULL) {
|
||||||
|
WebPDemuxReleaseIterator(&dec->prev_iter_);
|
||||||
WebPDemuxDelete(dec->demux_);
|
WebPDemuxDelete(dec->demux_);
|
||||||
WebPSafeFree(dec->curr_frame_);
|
WebPSafeFree(dec->curr_frame_);
|
||||||
WebPSafeFree(dec->prev_frame_disposed_);
|
WebPSafeFree(dec->prev_frame_disposed_);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#define DMUX_MAJ_VERSION 0
|
#define DMUX_MAJ_VERSION 0
|
||||||
#define DMUX_MIN_VERSION 3
|
#define DMUX_MIN_VERSION 3
|
||||||
#define DMUX_REV_VERSION 0
|
#define DMUX_REV_VERSION 2
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t start_; // start location of the data
|
size_t start_; // start location of the data
|
||||||
@@ -590,7 +590,6 @@ static int CheckFrameBounds(const Frame* const frame, int exact,
|
|||||||
|
|
||||||
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
||||||
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
|
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
|
||||||
const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
|
|
||||||
const Frame* f = dmux->frames_;
|
const Frame* f = dmux->frames_;
|
||||||
|
|
||||||
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
|
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
|
||||||
@@ -598,7 +597,7 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
|||||||
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
|
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
|
||||||
if (dmux->loop_count_ < 0) return 0;
|
if (dmux->loop_count_ < 0) return 0;
|
||||||
if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
|
if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
|
||||||
if (is_fragmented) return 0;
|
if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream
|
||||||
|
|
||||||
while (f != NULL) {
|
while (f != NULL) {
|
||||||
const int cur_frame_set = f->frame_num_;
|
const int cur_frame_set = f->frame_num_;
|
||||||
|
|||||||
41
src/demux/libwebpdemux.rc
Normal file
41
src/demux/libwebpdemux.rc
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#define APSTUDIO_READONLY_SYMBOLS
|
||||||
|
#include "winres.h"
|
||||||
|
#undef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
|
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||||
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 0,3,0,2
|
||||||
|
PRODUCTVERSION 0,3,0,2
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x40004L
|
||||||
|
FILETYPE 0x2L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "Google, Inc."
|
||||||
|
VALUE "FileDescription", "libwebpdemux DLL"
|
||||||
|
VALUE "FileVersion", "0.3.2"
|
||||||
|
VALUE "InternalName", "libwebpdemux.dll"
|
||||||
|
VALUE "LegalCopyright", "Copyright (C) 2017"
|
||||||
|
VALUE "OriginalFilename", "libwebpdemux.dll"
|
||||||
|
VALUE "ProductName", "WebP Image Demuxer"
|
||||||
|
VALUE "ProductVersion", "0.3.2"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
||||||
|
#endif // English (United States) resources
|
||||||
@@ -2,7 +2,7 @@ noinst_LTLIBRARIES = libwebpdsp.la libwebpdsp_avx2.la
|
|||||||
noinst_LTLIBRARIES += libwebpdsp_sse2.la libwebpdspdecode_sse2.la
|
noinst_LTLIBRARIES += libwebpdsp_sse2.la libwebpdspdecode_sse2.la
|
||||||
noinst_LTLIBRARIES += libwebpdsp_sse41.la libwebpdspdecode_sse41.la
|
noinst_LTLIBRARIES += libwebpdsp_sse41.la libwebpdspdecode_sse41.la
|
||||||
noinst_LTLIBRARIES += libwebpdsp_neon.la libwebpdspdecode_neon.la
|
noinst_LTLIBRARIES += libwebpdsp_neon.la libwebpdspdecode_neon.la
|
||||||
noinst_LTLIBRARIES += libwebpdspdecode_msa.la
|
noinst_LTLIBRARIES += libwebpdsp_msa.la libwebpdspdecode_msa.la
|
||||||
|
|
||||||
if BUILD_LIBWEBPDECODER
|
if BUILD_LIBWEBPDECODER
|
||||||
noinst_LTLIBRARIES += libwebpdspdecode.la
|
noinst_LTLIBRARIES += libwebpdspdecode.la
|
||||||
@@ -25,6 +25,7 @@ COMMON_SOURCES += filters.c
|
|||||||
COMMON_SOURCES += filters_mips_dsp_r2.c
|
COMMON_SOURCES += filters_mips_dsp_r2.c
|
||||||
COMMON_SOURCES += lossless.c
|
COMMON_SOURCES += lossless.c
|
||||||
COMMON_SOURCES += lossless.h
|
COMMON_SOURCES += lossless.h
|
||||||
|
COMMON_SOURCES += lossless_common.h
|
||||||
COMMON_SOURCES += lossless_mips_dsp_r2.c
|
COMMON_SOURCES += lossless_mips_dsp_r2.c
|
||||||
COMMON_SOURCES += mips_macro.h
|
COMMON_SOURCES += mips_macro.h
|
||||||
COMMON_SOURCES += rescaler.c
|
COMMON_SOURCES += rescaler.c
|
||||||
@@ -73,7 +74,9 @@ libwebpdspdecode_sse2_la_CPPFLAGS = $(libwebpdsp_sse2_la_CPPFLAGS)
|
|||||||
libwebpdspdecode_sse2_la_CFLAGS = $(libwebpdsp_sse2_la_CFLAGS)
|
libwebpdspdecode_sse2_la_CFLAGS = $(libwebpdsp_sse2_la_CFLAGS)
|
||||||
|
|
||||||
libwebpdspdecode_neon_la_SOURCES =
|
libwebpdspdecode_neon_la_SOURCES =
|
||||||
|
libwebpdspdecode_neon_la_SOURCES += alpha_processing_neon.c
|
||||||
libwebpdspdecode_neon_la_SOURCES += dec_neon.c
|
libwebpdspdecode_neon_la_SOURCES += dec_neon.c
|
||||||
|
libwebpdspdecode_neon_la_SOURCES += filters_neon.c
|
||||||
libwebpdspdecode_neon_la_SOURCES += lossless_neon.c
|
libwebpdspdecode_neon_la_SOURCES += lossless_neon.c
|
||||||
libwebpdspdecode_neon_la_SOURCES += neon.h
|
libwebpdspdecode_neon_la_SOURCES += neon.h
|
||||||
libwebpdspdecode_neon_la_SOURCES += rescaler_neon.c
|
libwebpdspdecode_neon_la_SOURCES += rescaler_neon.c
|
||||||
@@ -83,9 +86,13 @@ libwebpdspdecode_neon_la_CFLAGS = $(libwebpdsp_neon_la_CFLAGS)
|
|||||||
|
|
||||||
libwebpdspdecode_msa_la_SOURCES =
|
libwebpdspdecode_msa_la_SOURCES =
|
||||||
libwebpdspdecode_msa_la_SOURCES += dec_msa.c
|
libwebpdspdecode_msa_la_SOURCES += dec_msa.c
|
||||||
|
libwebpdspdecode_msa_la_SOURCES += filters_msa.c
|
||||||
|
libwebpdspdecode_msa_la_SOURCES += lossless_msa.c
|
||||||
libwebpdspdecode_msa_la_SOURCES += msa_macro.h
|
libwebpdspdecode_msa_la_SOURCES += msa_macro.h
|
||||||
libwebpdspdecode_msa_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
|
libwebpdspdecode_msa_la_SOURCES += rescaler_msa.c
|
||||||
libwebpdspdecode_msa_la_CFLAGS = $(AM_CFLAGS)
|
libwebpdspdecode_msa_la_SOURCES += upsampling_msa.c
|
||||||
|
libwebpdspdecode_msa_la_CPPFLAGS = $(libwebpdsp_msa_la_CPPFLAGS)
|
||||||
|
libwebpdspdecode_msa_la_CFLAGS = $(libwebpdsp_msa_la_CFLAGS)
|
||||||
|
|
||||||
libwebpdsp_sse2_la_SOURCES =
|
libwebpdsp_sse2_la_SOURCES =
|
||||||
libwebpdsp_sse2_la_SOURCES += argb_sse2.c
|
libwebpdsp_sse2_la_SOURCES += argb_sse2.c
|
||||||
@@ -110,10 +117,17 @@ libwebpdsp_neon_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
|
|||||||
libwebpdsp_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS)
|
libwebpdsp_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS)
|
||||||
libwebpdsp_neon_la_LIBADD = libwebpdspdecode_neon.la
|
libwebpdsp_neon_la_LIBADD = libwebpdspdecode_neon.la
|
||||||
|
|
||||||
|
libwebpdsp_msa_la_SOURCES =
|
||||||
|
libwebpdsp_msa_la_SOURCES += enc_msa.c
|
||||||
|
libwebpdsp_msa_la_SOURCES += lossless_enc_msa.c
|
||||||
|
libwebpdsp_msa_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
|
||||||
|
libwebpdsp_msa_la_CFLAGS = $(AM_CFLAGS)
|
||||||
|
libwebpdsp_msa_la_LIBADD = libwebpdspdecode_msa.la
|
||||||
|
|
||||||
libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES)
|
libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES)
|
||||||
|
|
||||||
noinst_HEADERS =
|
noinst_HEADERS =
|
||||||
noinst_HEADERS += ../dec/decode_vp8.h
|
noinst_HEADERS += ../dec/vp8_dec.h
|
||||||
noinst_HEADERS += ../webp/decode.h
|
noinst_HEADERS += ../webp/decode.h
|
||||||
|
|
||||||
libwebpdsp_la_CPPFLAGS =
|
libwebpdsp_la_CPPFLAGS =
|
||||||
@@ -124,7 +138,7 @@ libwebpdsp_la_LIBADD =
|
|||||||
libwebpdsp_la_LIBADD += libwebpdsp_avx2.la libwebpdsp_sse2.la
|
libwebpdsp_la_LIBADD += libwebpdsp_avx2.la libwebpdsp_sse2.la
|
||||||
libwebpdsp_la_LIBADD += libwebpdsp_sse41.la
|
libwebpdsp_la_LIBADD += libwebpdsp_sse41.la
|
||||||
libwebpdsp_la_LIBADD += libwebpdsp_neon.la
|
libwebpdsp_la_LIBADD += libwebpdsp_neon.la
|
||||||
libwebpdsp_la_LIBADD += libwebpdspdecode_msa.la
|
libwebpdsp_la_LIBADD += libwebpdsp_msa.la
|
||||||
|
|
||||||
if BUILD_LIBWEBPDECODER
|
if BUILD_LIBWEBPDECODER
|
||||||
libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES)
|
libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES)
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ static void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
|
static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* dst, int dst_stride) {
|
uint8_t* dst, int dst_stride) {
|
||||||
uint32_t alpha_mask = 0xff;
|
uint32_t alpha_mask = 0xff;
|
||||||
@@ -303,7 +303,7 @@ static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
|
|||||||
return (alpha_mask != 0xff);
|
return (alpha_mask != 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
|
static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint32_t* dst, int dst_stride) {
|
uint32_t* dst, int dst_stride) {
|
||||||
int i, j;
|
int i, j;
|
||||||
@@ -316,7 +316,7 @@ static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ExtractAlpha(const uint8_t* argb, int argb_stride,
|
static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* alpha, int alpha_stride) {
|
uint8_t* alpha, int alpha_stride) {
|
||||||
uint8_t alpha_mask = 0xff;
|
uint8_t alpha_mask = 0xff;
|
||||||
@@ -334,11 +334,17 @@ static int ExtractAlpha(const uint8_t* argb, int argb_stride,
|
|||||||
return (alpha_mask == 0xff);
|
return (alpha_mask == 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
||||||
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
||||||
int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
||||||
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
|
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
|
||||||
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
||||||
|
void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Init function
|
// Init function
|
||||||
@@ -346,6 +352,7 @@ int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
|||||||
extern void WebPInitAlphaProcessingMIPSdspR2(void);
|
extern void WebPInitAlphaProcessingMIPSdspR2(void);
|
||||||
extern void WebPInitAlphaProcessingSSE2(void);
|
extern void WebPInitAlphaProcessingSSE2(void);
|
||||||
extern void WebPInitAlphaProcessingSSE41(void);
|
extern void WebPInitAlphaProcessingSSE41(void);
|
||||||
|
extern void WebPInitAlphaProcessingNEON(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used =
|
static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used =
|
||||||
(VP8CPUInfo)&alpha_processing_last_cpuinfo_used;
|
(VP8CPUInfo)&alpha_processing_last_cpuinfo_used;
|
||||||
@@ -357,9 +364,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) {
|
|||||||
WebPMultRow = WebPMultRowC;
|
WebPMultRow = WebPMultRowC;
|
||||||
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
|
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
|
||||||
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
|
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
|
||||||
WebPDispatchAlpha = DispatchAlpha;
|
|
||||||
WebPDispatchAlphaToGreen = DispatchAlphaToGreen;
|
WebPDispatchAlpha = DispatchAlpha_C;
|
||||||
WebPExtractAlpha = ExtractAlpha;
|
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_C;
|
||||||
|
WebPExtractAlpha = ExtractAlpha_C;
|
||||||
|
WebPExtractGreen = ExtractGreen_C;
|
||||||
|
|
||||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
@@ -373,6 +382,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (VP8GetCPUInfo(kNEON)) {
|
||||||
|
WebPInitAlphaProcessingNEON();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if defined(WEBP_USE_MIPS_DSP_R2)
|
#if defined(WEBP_USE_MIPS_DSP_R2)
|
||||||
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
||||||
WebPInitAlphaProcessingMIPSdspR2();
|
WebPInitAlphaProcessingMIPSdspR2();
|
||||||
|
|||||||
191
src/dsp/alpha_processing_neon.c
Normal file
191
src/dsp/alpha_processing_neon.c
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Utilities for processing transparent channel, NEON version.
|
||||||
|
//
|
||||||
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
|
#include "./dsp.h"
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
|
||||||
|
#include "./neon.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define MULTIPLIER(a) ((a) * 0x8081)
|
||||||
|
#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
|
||||||
|
|
||||||
|
#define MULTIPLY_BY_ALPHA(V, ALPHA, OTHER) do { \
|
||||||
|
const uint8x8_t alpha = (V).val[(ALPHA)]; \
|
||||||
|
const uint16x8_t r1 = vmull_u8((V).val[1], alpha); \
|
||||||
|
const uint16x8_t g1 = vmull_u8((V).val[2], alpha); \
|
||||||
|
const uint16x8_t b1 = vmull_u8((V).val[(OTHER)], alpha); \
|
||||||
|
/* we use: v / 255 = (v + 1 + (v >> 8)) >> 8 */ \
|
||||||
|
const uint16x8_t r2 = vsraq_n_u16(r1, r1, 8); \
|
||||||
|
const uint16x8_t g2 = vsraq_n_u16(g1, g1, 8); \
|
||||||
|
const uint16x8_t b2 = vsraq_n_u16(b1, b1, 8); \
|
||||||
|
const uint16x8_t r3 = vaddq_u16(r2, kOne); \
|
||||||
|
const uint16x8_t g3 = vaddq_u16(g2, kOne); \
|
||||||
|
const uint16x8_t b3 = vaddq_u16(b2, kOne); \
|
||||||
|
(V).val[1] = vshrn_n_u16(r3, 8); \
|
||||||
|
(V).val[2] = vshrn_n_u16(g3, 8); \
|
||||||
|
(V).val[(OTHER)] = vshrn_n_u16(b3, 8); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
|
||||||
|
int w, int h, int stride) {
|
||||||
|
const uint16x8_t kOne = vdupq_n_u16(1u);
|
||||||
|
while (h-- > 0) {
|
||||||
|
uint32_t* const rgbx = (uint32_t*)rgba;
|
||||||
|
int i = 0;
|
||||||
|
if (alpha_first) {
|
||||||
|
for (; i + 8 <= w; i += 8) {
|
||||||
|
// load aaaa...|rrrr...|gggg...|bbbb...
|
||||||
|
uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i));
|
||||||
|
MULTIPLY_BY_ALPHA(RGBX, 0, 3);
|
||||||
|
vst4_u8((uint8_t*)(rgbx + i), RGBX);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (; i + 8 <= w; i += 8) {
|
||||||
|
uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i));
|
||||||
|
MULTIPLY_BY_ALPHA(RGBX, 3, 0);
|
||||||
|
vst4_u8((uint8_t*)(rgbx + i), RGBX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Finish with left-overs.
|
||||||
|
for (; i < w; ++i) {
|
||||||
|
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
|
||||||
|
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
|
||||||
|
const uint32_t a = alpha[4 * i];
|
||||||
|
if (a != 0xff) {
|
||||||
|
const uint32_t mult = MULTIPLIER(a);
|
||||||
|
rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
|
||||||
|
rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
|
||||||
|
rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rgba += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef MULTIPLY_BY_ALPHA
|
||||||
|
#undef MULTIPLIER
|
||||||
|
#undef PREMULTIPLY
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
|
||||||
|
int width, int height,
|
||||||
|
uint8_t* dst, int dst_stride) {
|
||||||
|
uint32_t alpha_mask = 0xffffffffu;
|
||||||
|
uint8x8_t mask8 = vdup_n_u8(0xff);
|
||||||
|
uint32_t tmp[2];
|
||||||
|
int i, j;
|
||||||
|
for (j = 0; j < height; ++j) {
|
||||||
|
// We don't know if alpha is first or last in dst[] (depending on rgbA/Argb
|
||||||
|
// mode). So we must be sure dst[4*i + 8 - 1] is writable for the store.
|
||||||
|
// Hence the test with 'width - 1' instead of just 'width'.
|
||||||
|
for (i = 0; i + 8 <= width - 1; i += 8) {
|
||||||
|
uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(dst + 4 * i));
|
||||||
|
const uint8x8_t alphas = vld1_u8(alpha + i);
|
||||||
|
rgbX.val[0] = alphas;
|
||||||
|
vst4_u8((uint8_t*)(dst + 4 * i), rgbX);
|
||||||
|
mask8 = vand_u8(mask8, alphas);
|
||||||
|
}
|
||||||
|
for (; i < width; ++i) {
|
||||||
|
const uint32_t alpha_value = alpha[i];
|
||||||
|
dst[4 * i] = alpha_value;
|
||||||
|
alpha_mask &= alpha_value;
|
||||||
|
}
|
||||||
|
alpha += alpha_stride;
|
||||||
|
dst += dst_stride;
|
||||||
|
}
|
||||||
|
vst1_u8((uint8_t*)tmp, mask8);
|
||||||
|
alpha_mask &= tmp[0];
|
||||||
|
alpha_mask &= tmp[1];
|
||||||
|
return (alpha_mask != 0xffffffffu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
|
||||||
|
int width, int height,
|
||||||
|
uint32_t* dst, int dst_stride) {
|
||||||
|
int i, j;
|
||||||
|
uint8x8x4_t greens; // leave A/R/B channels zero'd.
|
||||||
|
greens.val[0] = vdup_n_u8(0);
|
||||||
|
greens.val[2] = vdup_n_u8(0);
|
||||||
|
greens.val[3] = vdup_n_u8(0);
|
||||||
|
for (j = 0; j < height; ++j) {
|
||||||
|
for (i = 0; i + 8 <= width; i += 8) {
|
||||||
|
greens.val[1] = vld1_u8(alpha + i);
|
||||||
|
vst4_u8((uint8_t*)(dst + i), greens);
|
||||||
|
}
|
||||||
|
for (; i < width; ++i) dst[i] = alpha[i] << 8;
|
||||||
|
alpha += alpha_stride;
|
||||||
|
dst += dst_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
|
||||||
|
int width, int height,
|
||||||
|
uint8_t* alpha, int alpha_stride) {
|
||||||
|
uint32_t alpha_mask = 0xffffffffu;
|
||||||
|
uint8x8_t mask8 = vdup_n_u8(0xff);
|
||||||
|
uint32_t tmp[2];
|
||||||
|
int i, j;
|
||||||
|
for (j = 0; j < height; ++j) {
|
||||||
|
// We don't know if alpha is first or last in dst[] (depending on rgbA/Argb
|
||||||
|
// mode). So we must be sure dst[4*i + 8 - 1] is writable for the store.
|
||||||
|
// Hence the test with 'width - 1' instead of just 'width'.
|
||||||
|
for (i = 0; i + 8 <= width - 1; i += 8) {
|
||||||
|
const uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(argb + 4 * i));
|
||||||
|
const uint8x8_t alphas = rgbX.val[0];
|
||||||
|
vst1_u8((uint8_t*)(alpha + i), alphas);
|
||||||
|
mask8 = vand_u8(mask8, alphas);
|
||||||
|
}
|
||||||
|
for (; i < width; ++i) {
|
||||||
|
alpha[i] = argb[4 * i];
|
||||||
|
alpha_mask &= alpha[i];
|
||||||
|
}
|
||||||
|
argb += argb_stride;
|
||||||
|
alpha += alpha_stride;
|
||||||
|
}
|
||||||
|
vst1_u8((uint8_t*)tmp, mask8);
|
||||||
|
alpha_mask &= tmp[0];
|
||||||
|
alpha_mask &= tmp[1];
|
||||||
|
return (alpha_mask == 0xffffffffu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ExtractGreen_NEON(const uint32_t* argb,
|
||||||
|
uint8_t* alpha, int size) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i + 16 <= size; i += 16) {
|
||||||
|
const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));
|
||||||
|
const uint8x16_t greens = rgbX.val[1];
|
||||||
|
vst1q_u8(alpha + i, greens);
|
||||||
|
}
|
||||||
|
for (; i < size; ++i) alpha[i] = (argb[i] >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern void WebPInitAlphaProcessingNEON(void);
|
||||||
|
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingNEON(void) {
|
||||||
|
WebPApplyAlphaMultiply = ApplyAlphaMultiply_NEON;
|
||||||
|
WebPDispatchAlpha = DispatchAlpha_NEON;
|
||||||
|
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_NEON;
|
||||||
|
WebPExtractAlpha = ExtractAlpha_NEON;
|
||||||
|
WebPExtractGreen = ExtractGreen_NEON;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !WEBP_USE_NEON
|
||||||
|
|
||||||
|
WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingNEON)
|
||||||
|
|
||||||
|
#endif // WEBP_USE_NEON
|
||||||
@@ -150,46 +150,46 @@ static int ExtractAlpha(const uint8_t* argb, int argb_stride,
|
|||||||
#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
|
#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
|
||||||
|
|
||||||
// We can't use a 'const int' for the SHUFFLE value, because it has to be an
|
// We can't use a 'const int' for the SHUFFLE value, because it has to be an
|
||||||
// immediate in the _mm_shufflexx_epi16() instruction. We really a macro here.
|
// immediate in the _mm_shufflexx_epi16() instruction. We really need a macro.
|
||||||
#define APPLY_ALPHA(RGBX, SHUFFLE, MASK, MULT) do { \
|
// We use: v / 255 = (v * 0x8081) >> 23, where v = alpha * {r,g,b} is a 16bit
|
||||||
const __m128i argb0 = _mm_loadl_epi64((__m128i*)&(RGBX)); \
|
// value.
|
||||||
const __m128i argb1 = _mm_unpacklo_epi8(argb0, zero); \
|
#define APPLY_ALPHA(RGBX, SHUFFLE) do { \
|
||||||
const __m128i alpha0 = _mm_and_si128(argb1, MASK); \
|
const __m128i argb0 = _mm_loadu_si128((const __m128i*)&(RGBX)); \
|
||||||
const __m128i alpha1 = _mm_shufflelo_epi16(alpha0, SHUFFLE); \
|
const __m128i argb1_lo = _mm_unpacklo_epi8(argb0, zero); \
|
||||||
const __m128i alpha2 = _mm_shufflehi_epi16(alpha1, SHUFFLE); \
|
const __m128i argb1_hi = _mm_unpackhi_epi8(argb0, zero); \
|
||||||
/* alpha2 = [0 a0 a0 a0][0 a1 a1 a1] */ \
|
const __m128i alpha0_lo = _mm_or_si128(argb1_lo, kMask); \
|
||||||
const __m128i scale0 = _mm_mullo_epi16(alpha2, MULT); \
|
const __m128i alpha0_hi = _mm_or_si128(argb1_hi, kMask); \
|
||||||
const __m128i scale1 = _mm_mulhi_epu16(alpha2, MULT); \
|
const __m128i alpha1_lo = _mm_shufflelo_epi16(alpha0_lo, SHUFFLE); \
|
||||||
const __m128i argb2 = _mm_mulhi_epu16(argb1, scale0); \
|
const __m128i alpha1_hi = _mm_shufflelo_epi16(alpha0_hi, SHUFFLE); \
|
||||||
const __m128i argb3 = _mm_mullo_epi16(argb1, scale1); \
|
const __m128i alpha2_lo = _mm_shufflehi_epi16(alpha1_lo, SHUFFLE); \
|
||||||
const __m128i argb4 = _mm_adds_epu16(argb2, argb3); \
|
const __m128i alpha2_hi = _mm_shufflehi_epi16(alpha1_hi, SHUFFLE); \
|
||||||
const __m128i argb5 = _mm_srli_epi16(argb4, 7); \
|
/* alpha2 = [ff a0 a0 a0][ff a1 a1 a1] */ \
|
||||||
const __m128i argb6 = _mm_or_si128(argb5, alpha0); \
|
const __m128i A0_lo = _mm_mullo_epi16(alpha2_lo, argb1_lo); \
|
||||||
const __m128i argb7 = _mm_packus_epi16(argb6, zero); \
|
const __m128i A0_hi = _mm_mullo_epi16(alpha2_hi, argb1_hi); \
|
||||||
_mm_storel_epi64((__m128i*)&(RGBX), argb7); \
|
const __m128i A1_lo = _mm_mulhi_epu16(A0_lo, kMult); \
|
||||||
|
const __m128i A1_hi = _mm_mulhi_epu16(A0_hi, kMult); \
|
||||||
|
const __m128i A2_lo = _mm_srli_epi16(A1_lo, 7); \
|
||||||
|
const __m128i A2_hi = _mm_srli_epi16(A1_hi, 7); \
|
||||||
|
const __m128i A3 = _mm_packus_epi16(A2_lo, A2_hi); \
|
||||||
|
_mm_storeu_si128((__m128i*)&(RGBX), A3); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
|
static void ApplyAlphaMultiply_SSE2(uint8_t* rgba, int alpha_first,
|
||||||
int w, int h, int stride) {
|
int w, int h, int stride) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const int kSpan = 2;
|
const __m128i kMult = _mm_set1_epi16(0x8081u);
|
||||||
const int w2 = w & ~(kSpan - 1);
|
const __m128i kMask = _mm_set_epi16(0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0);
|
||||||
|
const int kSpan = 4;
|
||||||
while (h-- > 0) {
|
while (h-- > 0) {
|
||||||
uint32_t* const rgbx = (uint32_t*)rgba;
|
uint32_t* const rgbx = (uint32_t*)rgba;
|
||||||
int i;
|
int i;
|
||||||
if (!alpha_first) {
|
if (!alpha_first) {
|
||||||
const __m128i kMask = _mm_set_epi16(0xff, 0, 0, 0, 0xff, 0, 0, 0);
|
for (i = 0; i + kSpan <= w; i += kSpan) {
|
||||||
const __m128i kMult =
|
APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(2, 3, 3, 3));
|
||||||
_mm_set_epi16(0, 0x8081, 0x8081, 0x8081, 0, 0x8081, 0x8081, 0x8081);
|
|
||||||
for (i = 0; i < w2; i += kSpan) {
|
|
||||||
APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 3, 3, 3), kMask, kMult);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const __m128i kMask = _mm_set_epi16(0, 0, 0, 0xff, 0, 0, 0, 0xff);
|
for (i = 0; i + kSpan <= w; i += kSpan) {
|
||||||
const __m128i kMult =
|
APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 0, 0, 1));
|
||||||
_mm_set_epi16(0x8081, 0x8081, 0x8081, 0, 0x8081, 0x8081, 0x8081, 0);
|
|
||||||
for (i = 0; i < w2; i += kSpan) {
|
|
||||||
APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 0, 0, 3), kMask, kMult);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Finish with left-overs.
|
// Finish with left-overs.
|
||||||
@@ -213,64 +213,51 @@ static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Apply alpha value to rows
|
// Apply alpha value to rows
|
||||||
|
|
||||||
// We use: kINV255 = (1 << 24) / 255 = 0x010101
|
static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) {
|
||||||
// So: a * kINV255 = (a << 16) | [(a << 8) | a]
|
|
||||||
// -> _mm_mulhi_epu16() takes care of the (a<<16) part,
|
|
||||||
// and _mm_mullo_epu16(a * 0x0101,...) takes care of the "(a << 8) | a" one.
|
|
||||||
|
|
||||||
static void MultARGBRow(uint32_t* const ptr, int width, int inverse) {
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
if (!inverse) {
|
if (!inverse) {
|
||||||
const int kSpan = 2;
|
const int kSpan = 2;
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i kRound =
|
const __m128i k128 = _mm_set1_epi16(128);
|
||||||
_mm_set_epi16(0, 1 << 7, 1 << 7, 1 << 7, 0, 1 << 7, 1 << 7, 1 << 7);
|
const __m128i kMult = _mm_set1_epi16(0x0101);
|
||||||
const __m128i kMult =
|
const __m128i kMask = _mm_set_epi16(0, 0xff, 0, 0, 0, 0xff, 0, 0);
|
||||||
_mm_set_epi16(0, 0x0101, 0x0101, 0x0101, 0, 0x0101, 0x0101, 0x0101);
|
for (x = 0; x + kSpan <= width; x += kSpan) {
|
||||||
const __m128i kOne64 = _mm_set_epi16(1u << 8, 0, 0, 0, 1u << 8, 0, 0, 0);
|
// To compute 'result = (int)(a * x / 255. + .5)', we use:
|
||||||
const int w2 = width & ~(kSpan - 1);
|
// tmp = a * v + 128, result = (tmp * 0x0101u) >> 16
|
||||||
for (x = 0; x < w2; x += kSpan) {
|
const __m128i A0 = _mm_loadl_epi64((const __m128i*)&ptr[x]);
|
||||||
const __m128i argb0 = _mm_loadl_epi64((__m128i*)&ptr[x]);
|
const __m128i A1 = _mm_unpacklo_epi8(A0, zero);
|
||||||
const __m128i argb1 = _mm_unpacklo_epi8(argb0, zero);
|
const __m128i A2 = _mm_or_si128(A1, kMask);
|
||||||
const __m128i tmp0 = _mm_shufflelo_epi16(argb1, _MM_SHUFFLE(3, 3, 3, 3));
|
const __m128i A3 = _mm_shufflelo_epi16(A2, _MM_SHUFFLE(2, 3, 3, 3));
|
||||||
const __m128i tmp1 = _mm_shufflehi_epi16(tmp0, _MM_SHUFFLE(3, 3, 3, 3));
|
const __m128i A4 = _mm_shufflehi_epi16(A3, _MM_SHUFFLE(2, 3, 3, 3));
|
||||||
const __m128i tmp2 = _mm_srli_epi64(tmp1, 16);
|
// here, A4 = [ff a0 a0 a0][ff a1 a1 a1]
|
||||||
const __m128i scale0 = _mm_mullo_epi16(tmp1, kMult);
|
const __m128i A5 = _mm_mullo_epi16(A4, A1);
|
||||||
const __m128i scale1 = _mm_or_si128(tmp2, kOne64);
|
const __m128i A6 = _mm_add_epi16(A5, k128);
|
||||||
const __m128i argb2 = _mm_mulhi_epu16(argb1, scale0);
|
const __m128i A7 = _mm_mulhi_epu16(A6, kMult);
|
||||||
const __m128i argb3 = _mm_mullo_epi16(argb1, scale1);
|
const __m128i A10 = _mm_packus_epi16(A7, zero);
|
||||||
const __m128i argb4 = _mm_adds_epu16(argb2, argb3);
|
_mm_storel_epi64((__m128i*)&ptr[x], A10);
|
||||||
const __m128i argb5 = _mm_adds_epu16(argb4, kRound);
|
|
||||||
const __m128i argb6 = _mm_srli_epi16(argb5, 8);
|
|
||||||
const __m128i argb7 = _mm_packus_epi16(argb6, zero);
|
|
||||||
_mm_storel_epi64((__m128i*)&ptr[x], argb7);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width -= x;
|
width -= x;
|
||||||
if (width > 0) WebPMultARGBRowC(ptr + x, width, inverse);
|
if (width > 0) WebPMultARGBRowC(ptr + x, width, inverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MultRow(uint8_t* const ptr, const uint8_t* const alpha,
|
static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
|
||||||
int width, int inverse) {
|
int width, int inverse) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
if (!inverse) {
|
if (!inverse) {
|
||||||
const int kSpan = 8;
|
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i kRound = _mm_set1_epi16(1 << 7);
|
const __m128i k128 = _mm_set1_epi16(128);
|
||||||
const int w2 = width & ~(kSpan - 1);
|
const __m128i kMult = _mm_set1_epi16(0x0101);
|
||||||
for (x = 0; x < w2; x += kSpan) {
|
for (x = 0; x + 8 <= width; x += 8) {
|
||||||
const __m128i v0 = _mm_loadl_epi64((__m128i*)&ptr[x]);
|
const __m128i v0 = _mm_loadl_epi64((__m128i*)&ptr[x]);
|
||||||
|
const __m128i a0 = _mm_loadl_epi64((const __m128i*)&alpha[x]);
|
||||||
const __m128i v1 = _mm_unpacklo_epi8(v0, zero);
|
const __m128i v1 = _mm_unpacklo_epi8(v0, zero);
|
||||||
const __m128i alpha0 = _mm_loadl_epi64((const __m128i*)&alpha[x]);
|
const __m128i a1 = _mm_unpacklo_epi8(a0, zero);
|
||||||
const __m128i alpha1 = _mm_unpacklo_epi8(alpha0, zero);
|
const __m128i v2 = _mm_mullo_epi16(v1, a1);
|
||||||
const __m128i alpha2 = _mm_unpacklo_epi8(alpha0, alpha0);
|
const __m128i v3 = _mm_add_epi16(v2, k128);
|
||||||
const __m128i v2 = _mm_mulhi_epu16(v1, alpha2);
|
const __m128i v4 = _mm_mulhi_epu16(v3, kMult);
|
||||||
const __m128i v3 = _mm_mullo_epi16(v1, alpha1);
|
const __m128i v5 = _mm_packus_epi16(v4, zero);
|
||||||
const __m128i v4 = _mm_adds_epu16(v2, v3);
|
_mm_storel_epi64((__m128i*)&ptr[x], v5);
|
||||||
const __m128i v5 = _mm_adds_epu16(v4, kRound);
|
|
||||||
const __m128i v6 = _mm_srli_epi16(v5, 8);
|
|
||||||
const __m128i v7 = _mm_packus_epi16(v6, zero);
|
|
||||||
_mm_storel_epi64((__m128i*)&ptr[x], v7);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width -= x;
|
width -= x;
|
||||||
@@ -283,9 +270,9 @@ static void MultRow(uint8_t* const ptr, const uint8_t* const alpha,
|
|||||||
extern void WebPInitAlphaProcessingSSE2(void);
|
extern void WebPInitAlphaProcessingSSE2(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) {
|
||||||
WebPMultARGBRow = MultARGBRow;
|
WebPMultARGBRow = MultARGBRow_SSE2;
|
||||||
WebPMultRow = MultRow;
|
WebPMultRow = MultRow_SSE2;
|
||||||
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
|
WebPApplyAlphaMultiply = ApplyAlphaMultiply_SSE2;
|
||||||
WebPDispatchAlpha = DispatchAlpha;
|
WebPDispatchAlpha = DispatchAlpha;
|
||||||
WebPDispatchAlphaToGreen = DispatchAlphaToGreen;
|
WebPDispatchAlphaToGreen = DispatchAlphaToGreen;
|
||||||
WebPExtractAlpha = ExtractAlpha;
|
WebPExtractAlpha = ExtractAlpha;
|
||||||
|
|||||||
@@ -100,6 +100,91 @@ static WEBP_INLINE void VP8Transpose_2_4x4_16b(
|
|||||||
// a03 a13 a23 a33 b03 b13 b23 b33
|
// a03 a13 a23 a33 b03 b13 b23 b33
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Channel mixing.
|
||||||
|
|
||||||
|
// Function used several times in VP8PlanarTo24b.
|
||||||
|
// It samples the in buffer as follows: one every two unsigned char is stored
|
||||||
|
// at the beginning of the buffer, while the other half is stored at the end.
|
||||||
|
#define VP8PlanarTo24bHelper(IN, OUT) \
|
||||||
|
do { \
|
||||||
|
const __m128i v_mask = _mm_set1_epi16(0x00ff); \
|
||||||
|
/* Take one every two upper 8b values.*/ \
|
||||||
|
(OUT##0) = _mm_packus_epi16(_mm_and_si128((IN##0), v_mask), \
|
||||||
|
_mm_and_si128((IN##1), v_mask)); \
|
||||||
|
(OUT##1) = _mm_packus_epi16(_mm_and_si128((IN##2), v_mask), \
|
||||||
|
_mm_and_si128((IN##3), v_mask)); \
|
||||||
|
(OUT##2) = _mm_packus_epi16(_mm_and_si128((IN##4), v_mask), \
|
||||||
|
_mm_and_si128((IN##5), v_mask)); \
|
||||||
|
/* Take one every two lower 8b values.*/ \
|
||||||
|
(OUT##3) = _mm_packus_epi16(_mm_srli_epi16((IN##0), 8), \
|
||||||
|
_mm_srli_epi16((IN##1), 8)); \
|
||||||
|
(OUT##4) = _mm_packus_epi16(_mm_srli_epi16((IN##2), 8), \
|
||||||
|
_mm_srli_epi16((IN##3), 8)); \
|
||||||
|
(OUT##5) = _mm_packus_epi16(_mm_srli_epi16((IN##4), 8), \
|
||||||
|
_mm_srli_epi16((IN##5), 8)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// Pack the planar buffers
|
||||||
|
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
||||||
|
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
|
||||||
|
static WEBP_INLINE void VP8PlanarTo24b(__m128i* const in0, __m128i* const in1,
|
||||||
|
__m128i* const in2, __m128i* const in3,
|
||||||
|
__m128i* const in4, __m128i* const in5) {
|
||||||
|
// The input is 6 registers of sixteen 8b but for the sake of explanation,
|
||||||
|
// let's take 6 registers of four 8b values.
|
||||||
|
// To pack, we will keep taking one every two 8b integer and move it
|
||||||
|
// around as follows:
|
||||||
|
// Input:
|
||||||
|
// r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7
|
||||||
|
// Split the 6 registers in two sets of 3 registers: the first set as the even
|
||||||
|
// 8b bytes, the second the odd ones:
|
||||||
|
// r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7
|
||||||
|
// Repeat the same permutations twice more:
|
||||||
|
// r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
|
||||||
|
// r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
|
||||||
|
__m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
|
||||||
|
VP8PlanarTo24bHelper(*in, tmp);
|
||||||
|
VP8PlanarTo24bHelper(tmp, *in);
|
||||||
|
VP8PlanarTo24bHelper(*in, tmp);
|
||||||
|
// We need to do it two more times than the example as we have sixteen bytes.
|
||||||
|
{
|
||||||
|
__m128i out0, out1, out2, out3, out4, out5;
|
||||||
|
VP8PlanarTo24bHelper(tmp, out);
|
||||||
|
VP8PlanarTo24bHelper(out, *in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef VP8PlanarTo24bHelper
|
||||||
|
|
||||||
|
// Convert four packed four-channel buffers like argbargbargbargb... into the
|
||||||
|
// split channels aaaaa ... rrrr ... gggg .... bbbbb ......
|
||||||
|
static WEBP_INLINE void VP8L32bToPlanar(__m128i* const in0,
|
||||||
|
__m128i* const in1,
|
||||||
|
__m128i* const in2,
|
||||||
|
__m128i* const in3) {
|
||||||
|
// Column-wise transpose.
|
||||||
|
const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1);
|
||||||
|
const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1);
|
||||||
|
const __m128i A2 = _mm_unpacklo_epi8(*in2, *in3);
|
||||||
|
const __m128i A3 = _mm_unpackhi_epi8(*in2, *in3);
|
||||||
|
const __m128i B0 = _mm_unpacklo_epi8(A0, A1);
|
||||||
|
const __m128i B1 = _mm_unpackhi_epi8(A0, A1);
|
||||||
|
const __m128i B2 = _mm_unpacklo_epi8(A2, A3);
|
||||||
|
const __m128i B3 = _mm_unpackhi_epi8(A2, A3);
|
||||||
|
// C0 = g7 g6 ... g1 g0 | b7 b6 ... b1 b0
|
||||||
|
// C1 = a7 a6 ... a1 a0 | r7 r6 ... r1 r0
|
||||||
|
const __m128i C0 = _mm_unpacklo_epi8(B0, B1);
|
||||||
|
const __m128i C1 = _mm_unpackhi_epi8(B0, B1);
|
||||||
|
const __m128i C2 = _mm_unpacklo_epi8(B2, B3);
|
||||||
|
const __m128i C3 = _mm_unpackhi_epi8(B2, B3);
|
||||||
|
// Gather the channels.
|
||||||
|
*in0 = _mm_unpackhi_epi64(C1, C3);
|
||||||
|
*in1 = _mm_unpacklo_epi64(C1, C3);
|
||||||
|
*in2 = _mm_unpackhi_epi64(C0, C2);
|
||||||
|
*in3 = _mm_unpacklo_epi64(C0, C2);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // WEBP_USE_SSE2
|
#endif // WEBP_USE_SSE2
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "./dsp.h"
|
||||||
#include "../enc/cost.h"
|
#include "../enc/cost_enc.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Boolean-cost cost table
|
// Boolean-cost cost table
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#if defined(WEBP_USE_MIPS32)
|
#if defined(WEBP_USE_MIPS32)
|
||||||
|
|
||||||
#include "../enc/cost.h"
|
#include "../enc/cost_enc.h"
|
||||||
|
|
||||||
static int GetResidualCost(int ctx0, const VP8Residual* const res) {
|
static int GetResidualCost(int ctx0, const VP8Residual* const res) {
|
||||||
int temp0, temp1;
|
int temp0, temp1;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#if defined(WEBP_USE_MIPS_DSP_R2)
|
#if defined(WEBP_USE_MIPS_DSP_R2)
|
||||||
|
|
||||||
#include "../enc/cost.h"
|
#include "../enc/cost_enc.h"
|
||||||
|
|
||||||
static int GetResidualCost(int ctx0, const VP8Residual* const res) {
|
static int GetResidualCost(int ctx0, const VP8Residual* const res) {
|
||||||
int temp0, temp1;
|
int temp0, temp1;
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
#include "../enc/cost.h"
|
#include "../enc/cost_enc.h"
|
||||||
#include "../enc/vp8enci.h"
|
#include "../enc/vp8i_enc.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -95,26 +95,62 @@ static WEBP_INLINE uint64_t xgetbv(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2)
|
#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2)
|
||||||
|
|
||||||
|
// helper function for run-time detection of slow SSSE3 platforms
|
||||||
|
static int CheckSlowModel(int info) {
|
||||||
|
// Table listing display models with longer latencies for the bsr instruction
|
||||||
|
// (ie 2 cycles vs 10/16 cycles) and some SSSE3 instructions like pshufb.
|
||||||
|
// Refer to Intel 64 and IA-32 Architectures Optimization Reference Manual.
|
||||||
|
static const uint8_t kSlowModels[] = {
|
||||||
|
0x37, 0x4a, 0x4d, // Silvermont Microarchitecture
|
||||||
|
0x1c, 0x26, 0x27 // Atom Microarchitecture
|
||||||
|
};
|
||||||
|
const uint32_t model = ((info & 0xf0000) >> 12) | ((info >> 4) & 0xf);
|
||||||
|
const uint32_t family = (info >> 8) & 0xf;
|
||||||
|
if (family == 0x06) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < sizeof(kSlowModels) / sizeof(kSlowModels[0]); ++i) {
|
||||||
|
if (model == kSlowModels[i]) return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int x86CPUInfo(CPUFeature feature) {
|
static int x86CPUInfo(CPUFeature feature) {
|
||||||
int max_cpuid_value;
|
int max_cpuid_value;
|
||||||
int cpu_info[4];
|
int cpu_info[4];
|
||||||
|
int is_intel = 0;
|
||||||
|
|
||||||
// get the highest feature value cpuid supports
|
// get the highest feature value cpuid supports
|
||||||
GetCPUInfo(cpu_info, 0);
|
GetCPUInfo(cpu_info, 0);
|
||||||
max_cpuid_value = cpu_info[0];
|
max_cpuid_value = cpu_info[0];
|
||||||
if (max_cpuid_value < 1) {
|
if (max_cpuid_value < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
} else {
|
||||||
|
const int VENDOR_ID_INTEL_EBX = 0x756e6547; // uneG
|
||||||
|
const int VENDOR_ID_INTEL_EDX = 0x49656e69; // Ieni
|
||||||
|
const int VENDOR_ID_INTEL_ECX = 0x6c65746e; // letn
|
||||||
|
is_intel = (cpu_info[1] == VENDOR_ID_INTEL_EBX &&
|
||||||
|
cpu_info[2] == VENDOR_ID_INTEL_ECX &&
|
||||||
|
cpu_info[3] == VENDOR_ID_INTEL_EDX); // genuine Intel?
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCPUInfo(cpu_info, 1);
|
GetCPUInfo(cpu_info, 1);
|
||||||
if (feature == kSSE2) {
|
if (feature == kSSE2) {
|
||||||
return 0 != (cpu_info[3] & 0x04000000);
|
return !!(cpu_info[3] & (1 << 26));
|
||||||
}
|
}
|
||||||
if (feature == kSSE3) {
|
if (feature == kSSE3) {
|
||||||
return 0 != (cpu_info[2] & 0x00000001);
|
return !!(cpu_info[2] & (1 << 0));
|
||||||
}
|
}
|
||||||
|
if (feature == kSlowSSSE3) {
|
||||||
|
if (is_intel && (cpu_info[2] & (1 << 0))) { // SSSE3?
|
||||||
|
return CheckSlowModel(cpu_info[0]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (feature == kSSE4_1) {
|
if (feature == kSSE4_1) {
|
||||||
return 0 != (cpu_info[2] & 0x00080000);
|
return !!(cpu_info[2] & (1 << 19));
|
||||||
}
|
}
|
||||||
if (feature == kAVX) {
|
if (feature == kAVX) {
|
||||||
// bits 27 (OSXSAVE) & 28 (256-bit AVX)
|
// bits 27 (OSXSAVE) & 28 (256-bit AVX)
|
||||||
@@ -126,7 +162,7 @@ static int x86CPUInfo(CPUFeature feature) {
|
|||||||
if (feature == kAVX2) {
|
if (feature == kAVX2) {
|
||||||
if (x86CPUInfo(kAVX) && max_cpuid_value >= 7) {
|
if (x86CPUInfo(kAVX) && max_cpuid_value >= 7) {
|
||||||
GetCPUInfo(cpu_info, 7);
|
GetCPUInfo(cpu_info, 7);
|
||||||
return ((cpu_info[1] & 0x00000020) == 0x00000020);
|
return !!(cpu_info[1] & (1 << 5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -184,4 +220,3 @@ VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo;
|
|||||||
#else
|
#else
|
||||||
VP8CPUInfo VP8GetCPUInfo = NULL;
|
VP8CPUInfo VP8GetCPUInfo = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "./dsp.h"
|
||||||
#include "../dec/vp8i.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -239,7 +239,7 @@ VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// 4x4
|
// 4x4
|
||||||
|
|
||||||
#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
|
#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2))
|
||||||
#define AVG2(a, b) (((a) + (b) + 1) >> 1)
|
#define AVG2(a, b) (((a) + (b) + 1) >> 1)
|
||||||
|
|
||||||
static void VE4(uint8_t* dst) { // vertical
|
static void VE4(uint8_t* dst) { // vertical
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ static const uint8_t abs0[255 + 255 + 1] = {
|
|||||||
0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int8_t sclip1[1020 + 1020 + 1] = {
|
static const uint8_t sclip1[1020 + 1020 + 1] = {
|
||||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
@@ -236,7 +236,7 @@ static const int8_t sclip1[1020 + 1020 + 1] = {
|
|||||||
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int8_t sclip2[112 + 112 + 1] = {
|
static const uint8_t sclip2[112 + 112 + 1] = {
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||||
@@ -339,8 +339,8 @@ static volatile int tables_ok = 0;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const int8_t* const VP8ksclip1 = &sclip1[1020];
|
const int8_t* const VP8ksclip1 = (const int8_t*)&sclip1[1020];
|
||||||
const int8_t* const VP8ksclip2 = &sclip2[112];
|
const int8_t* const VP8ksclip2 = (const int8_t*)&sclip2[112];
|
||||||
const uint8_t* const VP8kclip1 = &clip1[255];
|
const uint8_t* const VP8kclip1 = &clip1[255];
|
||||||
const uint8_t* const VP8kabs0 = &abs0[255];
|
const uint8_t* const VP8kabs0 = &abs0[255];
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,820 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
|
|||||||
ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS);
|
ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Edge filtering functions
|
||||||
|
|
||||||
|
#define FLIP_SIGN2(in0, in1, out0, out1) { \
|
||||||
|
out0 = (v16i8)__msa_xori_b(in0, 0x80); \
|
||||||
|
out1 = (v16i8)__msa_xori_b(in1, 0x80); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FLIP_SIGN4(in0, in1, in2, in3, out0, out1, out2, out3) { \
|
||||||
|
FLIP_SIGN2(in0, in1, out0, out1); \
|
||||||
|
FLIP_SIGN2(in2, in3, out2, out3); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FILT_VAL(q0_m, p0_m, mask, filt) do { \
|
||||||
|
v16i8 q0_sub_p0; \
|
||||||
|
q0_sub_p0 = __msa_subs_s_b(q0_m, p0_m); \
|
||||||
|
filt = __msa_adds_s_b(filt, q0_sub_p0); \
|
||||||
|
filt = __msa_adds_s_b(filt, q0_sub_p0); \
|
||||||
|
filt = __msa_adds_s_b(filt, q0_sub_p0); \
|
||||||
|
filt = filt & mask; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define FILT2(q_m, p_m, q, p) do { \
|
||||||
|
u_r = SRAI_H(temp1, 7); \
|
||||||
|
u_r = __msa_sat_s_h(u_r, 7); \
|
||||||
|
u_l = SRAI_H(temp3, 7); \
|
||||||
|
u_l = __msa_sat_s_h(u_l, 7); \
|
||||||
|
u = __msa_pckev_b((v16i8)u_l, (v16i8)u_r); \
|
||||||
|
q_m = __msa_subs_s_b(q_m, u); \
|
||||||
|
p_m = __msa_adds_s_b(p_m, u); \
|
||||||
|
q = __msa_xori_b((v16u8)q_m, 0x80); \
|
||||||
|
p = __msa_xori_b((v16u8)p_m, 0x80); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev) do { \
|
||||||
|
v16i8 p1_m, p0_m, q0_m, q1_m; \
|
||||||
|
v16i8 filt, t1, t2; \
|
||||||
|
const v16i8 cnst4b = __msa_ldi_b(4); \
|
||||||
|
const v16i8 cnst3b = __msa_ldi_b(3); \
|
||||||
|
\
|
||||||
|
FLIP_SIGN4(p1, p0, q0, q1, p1_m, p0_m, q0_m, q1_m); \
|
||||||
|
filt = __msa_subs_s_b(p1_m, q1_m); \
|
||||||
|
filt = filt & hev; \
|
||||||
|
FILT_VAL(q0_m, p0_m, mask, filt); \
|
||||||
|
t1 = __msa_adds_s_b(filt, cnst4b); \
|
||||||
|
t1 = SRAI_B(t1, 3); \
|
||||||
|
t2 = __msa_adds_s_b(filt, cnst3b); \
|
||||||
|
t2 = SRAI_B(t2, 3); \
|
||||||
|
q0_m = __msa_subs_s_b(q0_m, t1); \
|
||||||
|
q0 = __msa_xori_b((v16u8)q0_m, 0x80); \
|
||||||
|
p0_m = __msa_adds_s_b(p0_m, t2); \
|
||||||
|
p0 = __msa_xori_b((v16u8)p0_m, 0x80); \
|
||||||
|
filt = __msa_srari_b(t1, 1); \
|
||||||
|
hev = __msa_xori_b(hev, 0xff); \
|
||||||
|
filt = filt & hev; \
|
||||||
|
q1_m = __msa_subs_s_b(q1_m, filt); \
|
||||||
|
q1 = __msa_xori_b((v16u8)q1_m, 0x80); \
|
||||||
|
p1_m = __msa_adds_s_b(p1_m, filt); \
|
||||||
|
p1 = __msa_xori_b((v16u8)p1_m, 0x80); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev) do { \
|
||||||
|
v16i8 p2_m, p1_m, p0_m, q2_m, q1_m, q0_m; \
|
||||||
|
v16i8 u, filt, t1, t2, filt_sign; \
|
||||||
|
v8i16 filt_r, filt_l, u_r, u_l; \
|
||||||
|
v8i16 temp0, temp1, temp2, temp3; \
|
||||||
|
const v16i8 cnst4b = __msa_ldi_b(4); \
|
||||||
|
const v16i8 cnst3b = __msa_ldi_b(3); \
|
||||||
|
const v8i16 cnst9h = __msa_ldi_h(9); \
|
||||||
|
\
|
||||||
|
FLIP_SIGN4(p1, p0, q0, q1, p1_m, p0_m, q0_m, q1_m); \
|
||||||
|
filt = __msa_subs_s_b(p1_m, q1_m); \
|
||||||
|
FILT_VAL(q0_m, p0_m, mask, filt); \
|
||||||
|
FLIP_SIGN2(p2, q2, p2_m, q2_m); \
|
||||||
|
t2 = filt & hev; \
|
||||||
|
/* filt_val &= ~hev */ \
|
||||||
|
hev = __msa_xori_b(hev, 0xff); \
|
||||||
|
filt = filt & hev; \
|
||||||
|
t1 = __msa_adds_s_b(t2, cnst4b); \
|
||||||
|
t1 = SRAI_B(t1, 3); \
|
||||||
|
t2 = __msa_adds_s_b(t2, cnst3b); \
|
||||||
|
t2 = SRAI_B(t2, 3); \
|
||||||
|
q0_m = __msa_subs_s_b(q0_m, t1); \
|
||||||
|
p0_m = __msa_adds_s_b(p0_m, t2); \
|
||||||
|
filt_sign = __msa_clti_s_b(filt, 0); \
|
||||||
|
ILVRL_B2_SH(filt_sign, filt, filt_r, filt_l); \
|
||||||
|
/* update q2/p2 */ \
|
||||||
|
temp0 = filt_r * cnst9h; \
|
||||||
|
temp1 = ADDVI_H(temp0, 63); \
|
||||||
|
temp2 = filt_l * cnst9h; \
|
||||||
|
temp3 = ADDVI_H(temp2, 63); \
|
||||||
|
FILT2(q2_m, p2_m, q2, p2); \
|
||||||
|
/* update q1/p1 */ \
|
||||||
|
temp1 = temp1 + temp0; \
|
||||||
|
temp3 = temp3 + temp2; \
|
||||||
|
FILT2(q1_m, p1_m, q1, p1); \
|
||||||
|
/* update q0/p0 */ \
|
||||||
|
temp1 = temp1 + temp0; \
|
||||||
|
temp3 = temp3 + temp2; \
|
||||||
|
FILT2(q0_m, p0_m, q0, p0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LPF_MASK_HEV(p3_in, p2_in, p1_in, p0_in, \
|
||||||
|
q0_in, q1_in, q2_in, q3_in, \
|
||||||
|
limit_in, b_limit_in, thresh_in, \
|
||||||
|
hev_out, mask_out) do { \
|
||||||
|
v16u8 p3_asub_p2_m, p2_asub_p1_m, p1_asub_p0_m, q1_asub_q0_m; \
|
||||||
|
v16u8 p1_asub_q1_m, p0_asub_q0_m, q3_asub_q2_m, q2_asub_q1_m; \
|
||||||
|
v16u8 flat_out; \
|
||||||
|
\
|
||||||
|
/* absolute subtraction of pixel values */ \
|
||||||
|
p3_asub_p2_m = __msa_asub_u_b(p3_in, p2_in); \
|
||||||
|
p2_asub_p1_m = __msa_asub_u_b(p2_in, p1_in); \
|
||||||
|
p1_asub_p0_m = __msa_asub_u_b(p1_in, p0_in); \
|
||||||
|
q1_asub_q0_m = __msa_asub_u_b(q1_in, q0_in); \
|
||||||
|
q2_asub_q1_m = __msa_asub_u_b(q2_in, q1_in); \
|
||||||
|
q3_asub_q2_m = __msa_asub_u_b(q3_in, q2_in); \
|
||||||
|
p0_asub_q0_m = __msa_asub_u_b(p0_in, q0_in); \
|
||||||
|
p1_asub_q1_m = __msa_asub_u_b(p1_in, q1_in); \
|
||||||
|
/* calculation of hev */ \
|
||||||
|
flat_out = __msa_max_u_b(p1_asub_p0_m, q1_asub_q0_m); \
|
||||||
|
hev_out = (thresh_in < flat_out); \
|
||||||
|
/* calculation of mask */ \
|
||||||
|
p0_asub_q0_m = __msa_adds_u_b(p0_asub_q0_m, p0_asub_q0_m); \
|
||||||
|
p1_asub_q1_m = SRAI_B(p1_asub_q1_m, 1); \
|
||||||
|
p0_asub_q0_m = __msa_adds_u_b(p0_asub_q0_m, p1_asub_q1_m); \
|
||||||
|
mask_out = (b_limit_in < p0_asub_q0_m); \
|
||||||
|
mask_out = __msa_max_u_b(flat_out, mask_out); \
|
||||||
|
p3_asub_p2_m = __msa_max_u_b(p3_asub_p2_m, p2_asub_p1_m); \
|
||||||
|
mask_out = __msa_max_u_b(p3_asub_p2_m, mask_out); \
|
||||||
|
q2_asub_q1_m = __msa_max_u_b(q2_asub_q1_m, q3_asub_q2_m); \
|
||||||
|
mask_out = __msa_max_u_b(q2_asub_q1_m, mask_out); \
|
||||||
|
mask_out = (limit_in < mask_out); \
|
||||||
|
mask_out = __msa_xori_b(mask_out, 0xff); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ST6x1_UB(in0, in0_idx, in1, in1_idx, pdst, stride) do { \
|
||||||
|
const uint16_t tmp0_h = __msa_copy_s_h((v8i16)in1, in1_idx); \
|
||||||
|
const uint32_t tmp0_w = __msa_copy_s_w((v4i32)in0, in0_idx); \
|
||||||
|
SW(tmp0_w, pdst); \
|
||||||
|
SH(tmp0_h, pdst + stride); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ST6x4_UB(in0, start_in0_idx, in1, start_in1_idx, pdst, stride) do { \
|
||||||
|
uint8_t* ptmp1 = (uint8_t*)pdst; \
|
||||||
|
ST6x1_UB(in0, start_in0_idx, in1, start_in1_idx, ptmp1, 4); \
|
||||||
|
ptmp1 += stride; \
|
||||||
|
ST6x1_UB(in0, start_in0_idx + 1, in1, start_in1_idx + 1, ptmp1, 4); \
|
||||||
|
ptmp1 += stride; \
|
||||||
|
ST6x1_UB(in0, start_in0_idx + 2, in1, start_in1_idx + 2, ptmp1, 4); \
|
||||||
|
ptmp1 += stride; \
|
||||||
|
ST6x1_UB(in0, start_in0_idx + 3, in1, start_in1_idx + 3, ptmp1, 4); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LPF_SIMPLE_FILT(p1_in, p0_in, q0_in, q1_in, mask) do { \
|
||||||
|
v16i8 p1_m, p0_m, q0_m, q1_m, filt, filt1, filt2; \
|
||||||
|
const v16i8 cnst4b = __msa_ldi_b(4); \
|
||||||
|
const v16i8 cnst3b = __msa_ldi_b(3); \
|
||||||
|
\
|
||||||
|
FLIP_SIGN4(p1_in, p0_in, q0_in, q1_in, p1_m, p0_m, q0_m, q1_m); \
|
||||||
|
filt = __msa_subs_s_b(p1_m, q1_m); \
|
||||||
|
FILT_VAL(q0_m, p0_m, mask, filt); \
|
||||||
|
filt1 = __msa_adds_s_b(filt, cnst4b); \
|
||||||
|
filt1 = SRAI_B(filt1, 3); \
|
||||||
|
filt2 = __msa_adds_s_b(filt, cnst3b); \
|
||||||
|
filt2 = SRAI_B(filt2, 3); \
|
||||||
|
q0_m = __msa_subs_s_b(q0_m, filt1); \
|
||||||
|
p0_m = __msa_adds_s_b(p0_m, filt2); \
|
||||||
|
q0_in = __msa_xori_b((v16u8)q0_m, 0x80); \
|
||||||
|
p0_in = __msa_xori_b((v16u8)p0_m, 0x80); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask) do { \
|
||||||
|
v16u8 p1_a_sub_q1, p0_a_sub_q0; \
|
||||||
|
\
|
||||||
|
p0_a_sub_q0 = __msa_asub_u_b(p0, q0); \
|
||||||
|
p1_a_sub_q1 = __msa_asub_u_b(p1, q1); \
|
||||||
|
p1_a_sub_q1 = (v16u8)__msa_srli_b((v16i8)p1_a_sub_q1, 1); \
|
||||||
|
p0_a_sub_q0 = __msa_adds_u_b(p0_a_sub_q0, p0_a_sub_q0); \
|
||||||
|
mask = __msa_adds_u_b(p0_a_sub_q0, p1_a_sub_q1); \
|
||||||
|
mask = (mask <= b_limit); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void VFilter16(uint8_t* src, int stride,
|
||||||
|
int b_limit_in, int limit_in, int thresh_in) {
|
||||||
|
uint8_t* ptemp = src - 4 * stride;
|
||||||
|
v16u8 p3, p2, p1, p0, q3, q2, q1, q0;
|
||||||
|
v16u8 mask, hev;
|
||||||
|
const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in);
|
||||||
|
const v16u8 limit = (v16u8)__msa_fill_b(limit_in);
|
||||||
|
const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in);
|
||||||
|
|
||||||
|
LD_UB8(ptemp, stride, p3, p2, p1, p0, q0, q1, q2, q3);
|
||||||
|
LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh,
|
||||||
|
hev, mask);
|
||||||
|
LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev);
|
||||||
|
ptemp = src - 3 * stride;
|
||||||
|
ST_UB4(p2, p1, p0, q0, ptemp, stride);
|
||||||
|
ptemp += (4 * stride);
|
||||||
|
ST_UB2(q1, q2, ptemp, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HFilter16(uint8_t* src, int stride,
|
||||||
|
int b_limit_in, int limit_in, int thresh_in) {
|
||||||
|
uint8_t* ptmp = src - 4;
|
||||||
|
v16u8 p3, p2, p1, p0, q3, q2, q1, q0;
|
||||||
|
v16u8 mask, hev;
|
||||||
|
v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8;
|
||||||
|
v16u8 row9, row10, row11, row12, row13, row14, row15;
|
||||||
|
v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||||
|
const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in);
|
||||||
|
const v16u8 limit = (v16u8)__msa_fill_b(limit_in);
|
||||||
|
const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in);
|
||||||
|
|
||||||
|
LD_UB8(ptmp, stride, row0, row1, row2, row3, row4, row5, row6, row7);
|
||||||
|
ptmp += (8 * stride);
|
||||||
|
LD_UB8(ptmp, stride, row8, row9, row10, row11, row12, row13, row14, row15);
|
||||||
|
TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15,
|
||||||
|
p3, p2, p1, p0, q0, q1, q2, q3);
|
||||||
|
LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh,
|
||||||
|
hev, mask);
|
||||||
|
LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev);
|
||||||
|
ILVR_B2_SH(p1, p2, q0, p0, tmp0, tmp1);
|
||||||
|
ILVRL_H2_SH(tmp1, tmp0, tmp3, tmp4);
|
||||||
|
ILVL_B2_SH(p1, p2, q0, p0, tmp0, tmp1);
|
||||||
|
ILVRL_H2_SH(tmp1, tmp0, tmp6, tmp7);
|
||||||
|
ILVRL_B2_SH(q2, q1, tmp2, tmp5);
|
||||||
|
ptmp = src - 3;
|
||||||
|
ST6x1_UB(tmp3, 0, tmp2, 0, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp3, 1, tmp2, 1, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp3, 2, tmp2, 2, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp3, 3, tmp2, 3, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp4, 0, tmp2, 4, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp4, 1, tmp2, 5, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp4, 2, tmp2, 6, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp4, 3, tmp2, 7, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp6, 0, tmp5, 0, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp6, 1, tmp5, 1, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp6, 2, tmp5, 2, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp6, 3, tmp5, 3, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp7, 0, tmp5, 4, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp7, 1, tmp5, 5, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp7, 2, tmp5, 6, ptmp, 4);
|
||||||
|
ptmp += stride;
|
||||||
|
ST6x1_UB(tmp7, 3, tmp5, 7, ptmp, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// on three inner edges
|
||||||
|
static void VFilterHorEdge16i(uint8_t* src, int stride,
|
||||||
|
int b_limit, int limit, int thresh) {
|
||||||
|
v16u8 mask, hev;
|
||||||
|
v16u8 p3, p2, p1, p0, q3, q2, q1, q0;
|
||||||
|
const v16u8 thresh0 = (v16u8)__msa_fill_b(thresh);
|
||||||
|
const v16u8 b_limit0 = (v16u8)__msa_fill_b(b_limit);
|
||||||
|
const v16u8 limit0 = (v16u8)__msa_fill_b(limit);
|
||||||
|
|
||||||
|
LD_UB8((src - 4 * stride), stride, p3, p2, p1, p0, q0, q1, q2, q3);
|
||||||
|
LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit0, b_limit0, thresh0,
|
||||||
|
hev, mask);
|
||||||
|
LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev);
|
||||||
|
ST_UB4(p1, p0, q0, q1, (src - 2 * stride), stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VFilter16i(uint8_t* src_y, int stride,
|
||||||
|
int b_limit, int limit, int thresh) {
|
||||||
|
VFilterHorEdge16i(src_y + 4 * stride, stride, b_limit, limit, thresh);
|
||||||
|
VFilterHorEdge16i(src_y + 8 * stride, stride, b_limit, limit, thresh);
|
||||||
|
VFilterHorEdge16i(src_y + 12 * stride, stride, b_limit, limit, thresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HFilterVertEdge16i(uint8_t* src, int stride,
|
||||||
|
int b_limit, int limit, int thresh) {
|
||||||
|
v16u8 mask, hev;
|
||||||
|
v16u8 p3, p2, p1, p0, q3, q2, q1, q0;
|
||||||
|
v16u8 row0, row1, row2, row3, row4, row5, row6, row7;
|
||||||
|
v16u8 row8, row9, row10, row11, row12, row13, row14, row15;
|
||||||
|
v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
|
||||||
|
const v16u8 thresh0 = (v16u8)__msa_fill_b(thresh);
|
||||||
|
const v16u8 b_limit0 = (v16u8)__msa_fill_b(b_limit);
|
||||||
|
const v16u8 limit0 = (v16u8)__msa_fill_b(limit);
|
||||||
|
|
||||||
|
LD_UB8(src - 4, stride, row0, row1, row2, row3, row4, row5, row6, row7);
|
||||||
|
LD_UB8(src - 4 + (8 * stride), stride,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15);
|
||||||
|
TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15,
|
||||||
|
p3, p2, p1, p0, q0, q1, q2, q3);
|
||||||
|
LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit0, b_limit0, thresh0,
|
||||||
|
hev, mask);
|
||||||
|
LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev);
|
||||||
|
ILVR_B2_SH(p0, p1, q1, q0, tmp0, tmp1);
|
||||||
|
ILVRL_H2_SH(tmp1, tmp0, tmp2, tmp3);
|
||||||
|
ILVL_B2_SH(p0, p1, q1, q0, tmp0, tmp1);
|
||||||
|
ILVRL_H2_SH(tmp1, tmp0, tmp4, tmp5);
|
||||||
|
src -= 2;
|
||||||
|
ST4x8_UB(tmp2, tmp3, src, stride);
|
||||||
|
src += (8 * stride);
|
||||||
|
ST4x8_UB(tmp4, tmp5, src, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HFilter16i(uint8_t* src_y, int stride,
|
||||||
|
int b_limit, int limit, int thresh) {
|
||||||
|
HFilterVertEdge16i(src_y + 4, stride, b_limit, limit, thresh);
|
||||||
|
HFilterVertEdge16i(src_y + 8, stride, b_limit, limit, thresh);
|
||||||
|
HFilterVertEdge16i(src_y + 12, stride, b_limit, limit, thresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8-pixels wide variants, for chroma filtering
|
||||||
|
static void VFilter8(uint8_t* src_u, uint8_t* src_v, int stride,
|
||||||
|
int b_limit_in, int limit_in, int thresh_in) {
|
||||||
|
uint8_t* ptmp_src_u = src_u - 4 * stride;
|
||||||
|
uint8_t* ptmp_src_v = src_v - 4 * stride;
|
||||||
|
uint64_t p2_d, p1_d, p0_d, q0_d, q1_d, q2_d;
|
||||||
|
v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev;
|
||||||
|
v16u8 p3_u, p2_u, p1_u, p0_u, q3_u, q2_u, q1_u, q0_u;
|
||||||
|
v16u8 p3_v, p2_v, p1_v, p0_v, q3_v, q2_v, q1_v, q0_v;
|
||||||
|
const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in);
|
||||||
|
const v16u8 limit = (v16u8)__msa_fill_b(limit_in);
|
||||||
|
const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in);
|
||||||
|
|
||||||
|
LD_UB8(ptmp_src_u, stride, p3_u, p2_u, p1_u, p0_u, q0_u, q1_u, q2_u, q3_u);
|
||||||
|
LD_UB8(ptmp_src_v, stride, p3_v, p2_v, p1_v, p0_v, q0_v, q1_v, q2_v, q3_v);
|
||||||
|
ILVR_D4_UB(p3_v, p3_u, p2_v, p2_u, p1_v, p1_u, p0_v, p0_u, p3, p2, p1, p0);
|
||||||
|
ILVR_D4_UB(q0_v, q0_u, q1_v, q1_u, q2_v, q2_u, q3_v, q3_u, q0, q1, q2, q3);
|
||||||
|
LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh,
|
||||||
|
hev, mask);
|
||||||
|
LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev);
|
||||||
|
p2_d = __msa_copy_s_d((v2i64)p2, 0);
|
||||||
|
p1_d = __msa_copy_s_d((v2i64)p1, 0);
|
||||||
|
p0_d = __msa_copy_s_d((v2i64)p0, 0);
|
||||||
|
q0_d = __msa_copy_s_d((v2i64)q0, 0);
|
||||||
|
q1_d = __msa_copy_s_d((v2i64)q1, 0);
|
||||||
|
q2_d = __msa_copy_s_d((v2i64)q2, 0);
|
||||||
|
ptmp_src_u += stride;
|
||||||
|
SD4(p2_d, p1_d, p0_d, q0_d, ptmp_src_u, stride);
|
||||||
|
ptmp_src_u += (4 * stride);
|
||||||
|
SD(q1_d, ptmp_src_u);
|
||||||
|
ptmp_src_u += stride;
|
||||||
|
SD(q2_d, ptmp_src_u);
|
||||||
|
p2_d = __msa_copy_s_d((v2i64)p2, 1);
|
||||||
|
p1_d = __msa_copy_s_d((v2i64)p1, 1);
|
||||||
|
p0_d = __msa_copy_s_d((v2i64)p0, 1);
|
||||||
|
q0_d = __msa_copy_s_d((v2i64)q0, 1);
|
||||||
|
q1_d = __msa_copy_s_d((v2i64)q1, 1);
|
||||||
|
q2_d = __msa_copy_s_d((v2i64)q2, 1);
|
||||||
|
ptmp_src_v += stride;
|
||||||
|
SD4(p2_d, p1_d, p0_d, q0_d, ptmp_src_v, stride);
|
||||||
|
ptmp_src_v += (4 * stride);
|
||||||
|
SD(q1_d, ptmp_src_v);
|
||||||
|
ptmp_src_v += stride;
|
||||||
|
SD(q2_d, ptmp_src_v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HFilter8(uint8_t* src_u, uint8_t* src_v, int stride,
|
||||||
|
int b_limit_in, int limit_in, int thresh_in) {
|
||||||
|
uint8_t* ptmp_src_u = src_u - 4;
|
||||||
|
uint8_t* ptmp_src_v = src_v - 4;
|
||||||
|
v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev;
|
||||||
|
v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8;
|
||||||
|
v16u8 row9, row10, row11, row12, row13, row14, row15;
|
||||||
|
v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||||
|
const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in);
|
||||||
|
const v16u8 limit = (v16u8)__msa_fill_b(limit_in);
|
||||||
|
const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in);
|
||||||
|
|
||||||
|
LD_UB8(ptmp_src_u, stride, row0, row1, row2, row3, row4, row5, row6, row7);
|
||||||
|
LD_UB8(ptmp_src_v, stride,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15);
|
||||||
|
TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15,
|
||||||
|
p3, p2, p1, p0, q0, q1, q2, q3);
|
||||||
|
LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh,
|
||||||
|
hev, mask);
|
||||||
|
LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev);
|
||||||
|
ILVR_B2_SH(p1, p2, q0, p0, tmp0, tmp1);
|
||||||
|
ILVRL_H2_SH(tmp1, tmp0, tmp3, tmp4);
|
||||||
|
ILVL_B2_SH(p1, p2, q0, p0, tmp0, tmp1);
|
||||||
|
ILVRL_H2_SH(tmp1, tmp0, tmp6, tmp7);
|
||||||
|
ILVRL_B2_SH(q2, q1, tmp2, tmp5);
|
||||||
|
ptmp_src_u += 1;
|
||||||
|
ST6x4_UB(tmp3, 0, tmp2, 0, ptmp_src_u, stride);
|
||||||
|
ptmp_src_u += 4 * stride;
|
||||||
|
ST6x4_UB(tmp4, 0, tmp2, 4, ptmp_src_u, stride);
|
||||||
|
ptmp_src_v += 1;
|
||||||
|
ST6x4_UB(tmp6, 0, tmp5, 0, ptmp_src_v, stride);
|
||||||
|
ptmp_src_v += 4 * stride;
|
||||||
|
ST6x4_UB(tmp7, 0, tmp5, 4, ptmp_src_v, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VFilter8i(uint8_t* src_u, uint8_t* src_v, int stride,
|
||||||
|
int b_limit_in, int limit_in, int thresh_in) {
|
||||||
|
uint64_t p1_d, p0_d, q0_d, q1_d;
|
||||||
|
v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev;
|
||||||
|
v16u8 p3_u, p2_u, p1_u, p0_u, q3_u, q2_u, q1_u, q0_u;
|
||||||
|
v16u8 p3_v, p2_v, p1_v, p0_v, q3_v, q2_v, q1_v, q0_v;
|
||||||
|
const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in);
|
||||||
|
const v16u8 limit = (v16u8)__msa_fill_b(limit_in);
|
||||||
|
const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in);
|
||||||
|
|
||||||
|
LD_UB8(src_u, stride, p3_u, p2_u, p1_u, p0_u, q0_u, q1_u, q2_u, q3_u);
|
||||||
|
src_u += (5 * stride);
|
||||||
|
LD_UB8(src_v, stride, p3_v, p2_v, p1_v, p0_v, q0_v, q1_v, q2_v, q3_v);
|
||||||
|
src_v += (5 * stride);
|
||||||
|
ILVR_D4_UB(p3_v, p3_u, p2_v, p2_u, p1_v, p1_u, p0_v, p0_u, p3, p2, p1, p0);
|
||||||
|
ILVR_D4_UB(q0_v, q0_u, q1_v, q1_u, q2_v, q2_u, q3_v, q3_u, q0, q1, q2, q3);
|
||||||
|
LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh,
|
||||||
|
hev, mask);
|
||||||
|
LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev);
|
||||||
|
p1_d = __msa_copy_s_d((v2i64)p1, 0);
|
||||||
|
p0_d = __msa_copy_s_d((v2i64)p0, 0);
|
||||||
|
q0_d = __msa_copy_s_d((v2i64)q0, 0);
|
||||||
|
q1_d = __msa_copy_s_d((v2i64)q1, 0);
|
||||||
|
SD4(q1_d, q0_d, p0_d, p1_d, src_u, -stride);
|
||||||
|
p1_d = __msa_copy_s_d((v2i64)p1, 1);
|
||||||
|
p0_d = __msa_copy_s_d((v2i64)p0, 1);
|
||||||
|
q0_d = __msa_copy_s_d((v2i64)q0, 1);
|
||||||
|
q1_d = __msa_copy_s_d((v2i64)q1, 1);
|
||||||
|
SD4(q1_d, q0_d, p0_d, p1_d, src_v, -stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HFilter8i(uint8_t* src_u, uint8_t* src_v, int stride,
|
||||||
|
int b_limit_in, int limit_in, int thresh_in) {
|
||||||
|
v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev;
|
||||||
|
v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8;
|
||||||
|
v16u8 row9, row10, row11, row12, row13, row14, row15;
|
||||||
|
v4i32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
|
||||||
|
const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in);
|
||||||
|
const v16u8 limit = (v16u8)__msa_fill_b(limit_in);
|
||||||
|
const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in);
|
||||||
|
|
||||||
|
LD_UB8(src_u, stride, row0, row1, row2, row3, row4, row5, row6, row7);
|
||||||
|
LD_UB8(src_v, stride,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15);
|
||||||
|
TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15,
|
||||||
|
p3, p2, p1, p0, q0, q1, q2, q3);
|
||||||
|
LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh,
|
||||||
|
hev, mask);
|
||||||
|
LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev);
|
||||||
|
ILVR_B2_SW(p0, p1, q1, q0, tmp0, tmp1);
|
||||||
|
ILVRL_H2_SW(tmp1, tmp0, tmp2, tmp3);
|
||||||
|
ILVL_B2_SW(p0, p1, q1, q0, tmp0, tmp1);
|
||||||
|
ILVRL_H2_SW(tmp1, tmp0, tmp4, tmp5);
|
||||||
|
src_u += 2;
|
||||||
|
ST4x4_UB(tmp2, tmp2, 0, 1, 2, 3, src_u, stride);
|
||||||
|
src_u += 4 * stride;
|
||||||
|
ST4x4_UB(tmp3, tmp3, 0, 1, 2, 3, src_u, stride);
|
||||||
|
src_v += 2;
|
||||||
|
ST4x4_UB(tmp4, tmp4, 0, 1, 2, 3, src_v, stride);
|
||||||
|
src_v += 4 * stride;
|
||||||
|
ST4x4_UB(tmp5, tmp5, 0, 1, 2, 3, src_v, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SimpleVFilter16(uint8_t* src, int stride, int b_limit_in) {
|
||||||
|
v16u8 p1, p0, q1, q0, mask;
|
||||||
|
const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in);
|
||||||
|
|
||||||
|
LD_UB4(src - 2 * stride, stride, p1, p0, q0, q1);
|
||||||
|
LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask);
|
||||||
|
LPF_SIMPLE_FILT(p1, p0, q0, q1, mask);
|
||||||
|
ST_UB2(p0, q0, src - stride, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SimpleHFilter16(uint8_t* src, int stride, int b_limit_in) {
|
||||||
|
v16u8 p1, p0, q1, q0, mask, row0, row1, row2, row3, row4, row5, row6, row7;
|
||||||
|
v16u8 row8, row9, row10, row11, row12, row13, row14, row15;
|
||||||
|
v8i16 tmp0, tmp1;
|
||||||
|
const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in);
|
||||||
|
uint8_t* ptemp_src = src - 2;
|
||||||
|
|
||||||
|
LD_UB8(ptemp_src, stride, row0, row1, row2, row3, row4, row5, row6, row7);
|
||||||
|
LD_UB8(ptemp_src + 8 * stride, stride,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15);
|
||||||
|
TRANSPOSE16x4_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7,
|
||||||
|
row8, row9, row10, row11, row12, row13, row14, row15,
|
||||||
|
p1, p0, q0, q1);
|
||||||
|
LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask);
|
||||||
|
LPF_SIMPLE_FILT(p1, p0, q0, q1, mask);
|
||||||
|
ILVRL_B2_SH(q0, p0, tmp1, tmp0);
|
||||||
|
ptemp_src += 1;
|
||||||
|
ST2x4_UB(tmp1, 0, ptemp_src, stride);
|
||||||
|
ptemp_src += 4 * stride;
|
||||||
|
ST2x4_UB(tmp1, 4, ptemp_src, stride);
|
||||||
|
ptemp_src += 4 * stride;
|
||||||
|
ST2x4_UB(tmp0, 0, ptemp_src, stride);
|
||||||
|
ptemp_src += 4 * stride;
|
||||||
|
ST2x4_UB(tmp0, 4, ptemp_src, stride);
|
||||||
|
ptemp_src += 4 * stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SimpleVFilter16i(uint8_t* src_y, int stride, int b_limit_in) {
|
||||||
|
SimpleVFilter16(src_y + 4 * stride, stride, b_limit_in);
|
||||||
|
SimpleVFilter16(src_y + 8 * stride, stride, b_limit_in);
|
||||||
|
SimpleVFilter16(src_y + 12 * stride, stride, b_limit_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SimpleHFilter16i(uint8_t* src_y, int stride, int b_limit_in) {
|
||||||
|
SimpleHFilter16(src_y + 4, stride, b_limit_in);
|
||||||
|
SimpleHFilter16(src_y + 8, stride, b_limit_in);
|
||||||
|
SimpleHFilter16(src_y + 12, stride, b_limit_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Intra predictions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 4x4
|
||||||
|
|
||||||
|
static void DC4(uint8_t* dst) { // DC
|
||||||
|
uint32_t dc = 4;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS];
|
||||||
|
dc >>= 3;
|
||||||
|
dc = dc | (dc << 8) | (dc << 16) | (dc << 24);
|
||||||
|
SW4(dc, dc, dc, dc, dst, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TM4(uint8_t* dst) {
|
||||||
|
const uint8_t* const ptemp = dst - BPS - 1;
|
||||||
|
v8i16 T, d, r0, r1, r2, r3;
|
||||||
|
const v16i8 zero = { 0 };
|
||||||
|
const v8i16 TL = (v8i16)__msa_fill_h(ptemp[0 * BPS]);
|
||||||
|
const v8i16 L0 = (v8i16)__msa_fill_h(ptemp[1 * BPS]);
|
||||||
|
const v8i16 L1 = (v8i16)__msa_fill_h(ptemp[2 * BPS]);
|
||||||
|
const v8i16 L2 = (v8i16)__msa_fill_h(ptemp[3 * BPS]);
|
||||||
|
const v8i16 L3 = (v8i16)__msa_fill_h(ptemp[4 * BPS]);
|
||||||
|
const v16u8 T1 = LD_UB(ptemp + 1);
|
||||||
|
|
||||||
|
T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1);
|
||||||
|
d = T - TL;
|
||||||
|
ADD4(d, L0, d, L1, d, L2, d, L3, r0, r1, r2, r3);
|
||||||
|
CLIP_SH4_0_255(r0, r1, r2, r3);
|
||||||
|
PCKEV_ST4x4_UB(r0, r1, r2, r3, dst, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VE4(uint8_t* dst) { // vertical
|
||||||
|
const uint8_t* const ptop = dst - BPS - 1;
|
||||||
|
const uint32_t val0 = LW(ptop + 0);
|
||||||
|
const uint32_t val1 = LW(ptop + 4);
|
||||||
|
uint32_t out;
|
||||||
|
v16u8 A, B, C, AC, B2, R;
|
||||||
|
|
||||||
|
INSERT_W2_UB(val0, val1, A);
|
||||||
|
B = SLDI_UB(A, A, 1);
|
||||||
|
C = SLDI_UB(A, A, 2);
|
||||||
|
AC = __msa_ave_u_b(A, C);
|
||||||
|
B2 = __msa_ave_u_b(B, B);
|
||||||
|
R = __msa_aver_u_b(AC, B2);
|
||||||
|
out = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
SW4(out, out, out, out, dst, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RD4(uint8_t* dst) { // Down-right
|
||||||
|
const uint8_t* const ptop = dst - 1 - BPS;
|
||||||
|
uint32_t val0 = LW(ptop + 0);
|
||||||
|
uint32_t val1 = LW(ptop + 4);
|
||||||
|
uint32_t val2, val3;
|
||||||
|
v16u8 A, B, C, AC, B2, R, A1;
|
||||||
|
|
||||||
|
INSERT_W2_UB(val0, val1, A1);
|
||||||
|
A = SLDI_UB(A1, A1, 12);
|
||||||
|
A = (v16u8)__msa_insert_b((v16i8)A, 3, ptop[1 * BPS]);
|
||||||
|
A = (v16u8)__msa_insert_b((v16i8)A, 2, ptop[2 * BPS]);
|
||||||
|
A = (v16u8)__msa_insert_b((v16i8)A, 1, ptop[3 * BPS]);
|
||||||
|
A = (v16u8)__msa_insert_b((v16i8)A, 0, ptop[4 * BPS]);
|
||||||
|
B = SLDI_UB(A, A, 1);
|
||||||
|
C = SLDI_UB(A, A, 2);
|
||||||
|
AC = __msa_ave_u_b(A, C);
|
||||||
|
B2 = __msa_ave_u_b(B, B);
|
||||||
|
R = __msa_aver_u_b(AC, B2);
|
||||||
|
val3 = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
R = SLDI_UB(R, R, 1);
|
||||||
|
val2 = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
R = SLDI_UB(R, R, 1);
|
||||||
|
val1 = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
R = SLDI_UB(R, R, 1);
|
||||||
|
val0 = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
SW4(val0, val1, val2, val3, dst, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LD4(uint8_t* dst) { // Down-Left
|
||||||
|
const uint8_t* const ptop = dst - BPS;
|
||||||
|
uint32_t val0 = LW(ptop + 0);
|
||||||
|
uint32_t val1 = LW(ptop + 4);
|
||||||
|
uint32_t val2, val3;
|
||||||
|
v16u8 A, B, C, AC, B2, R;
|
||||||
|
|
||||||
|
INSERT_W2_UB(val0, val1, A);
|
||||||
|
B = SLDI_UB(A, A, 1);
|
||||||
|
C = SLDI_UB(A, A, 2);
|
||||||
|
C = (v16u8)__msa_insert_b((v16i8)C, 6, ptop[7]);
|
||||||
|
AC = __msa_ave_u_b(A, C);
|
||||||
|
B2 = __msa_ave_u_b(B, B);
|
||||||
|
R = __msa_aver_u_b(AC, B2);
|
||||||
|
val0 = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
R = SLDI_UB(R, R, 1);
|
||||||
|
val1 = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
R = SLDI_UB(R, R, 1);
|
||||||
|
val2 = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
R = SLDI_UB(R, R, 1);
|
||||||
|
val3 = __msa_copy_s_w((v4i32)R, 0);
|
||||||
|
SW4(val0, val1, val2, val3, dst, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 16x16
|
||||||
|
|
||||||
|
static void DC16(uint8_t* dst) { // DC
|
||||||
|
uint32_t dc = 16;
|
||||||
|
int i;
|
||||||
|
const v16u8 rtop = LD_UB(dst - BPS);
|
||||||
|
const v8u16 dctop = __msa_hadd_u_h(rtop, rtop);
|
||||||
|
v16u8 out;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; ++i) {
|
||||||
|
dc += dst[-1 + i * BPS];
|
||||||
|
}
|
||||||
|
dc += HADD_UH_U32(dctop);
|
||||||
|
out = (v16u8)__msa_fill_b(dc >> 5);
|
||||||
|
ST_UB8(out, out, out, out, out, out, out, out, dst, BPS);
|
||||||
|
ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TM16(uint8_t* dst) {
|
||||||
|
int j;
|
||||||
|
v8i16 d1, d2;
|
||||||
|
const v16i8 zero = { 0 };
|
||||||
|
const v8i16 TL = (v8i16)__msa_fill_h(dst[-1 - BPS]);
|
||||||
|
const v16i8 T = LD_SB(dst - BPS);
|
||||||
|
|
||||||
|
ILVRL_B2_SH(zero, T, d1, d2);
|
||||||
|
SUB2(d1, TL, d2, TL, d1, d2);
|
||||||
|
for (j = 0; j < 16; j += 4) {
|
||||||
|
v16i8 t0, t1, t2, t3;
|
||||||
|
v8i16 r0, r1, r2, r3, r4, r5, r6, r7;
|
||||||
|
const v8i16 L0 = (v8i16)__msa_fill_h(dst[-1 + 0 * BPS]);
|
||||||
|
const v8i16 L1 = (v8i16)__msa_fill_h(dst[-1 + 1 * BPS]);
|
||||||
|
const v8i16 L2 = (v8i16)__msa_fill_h(dst[-1 + 2 * BPS]);
|
||||||
|
const v8i16 L3 = (v8i16)__msa_fill_h(dst[-1 + 3 * BPS]);
|
||||||
|
ADD4(d1, L0, d1, L1, d1, L2, d1, L3, r0, r1, r2, r3);
|
||||||
|
ADD4(d2, L0, d2, L1, d2, L2, d2, L3, r4, r5, r6, r7);
|
||||||
|
CLIP_SH4_0_255(r0, r1, r2, r3);
|
||||||
|
CLIP_SH4_0_255(r4, r5, r6, r7);
|
||||||
|
PCKEV_B4_SB(r4, r0, r5, r1, r6, r2, r7, r3, t0, t1, t2, t3);
|
||||||
|
ST_SB4(t0, t1, t2, t3, dst, BPS);
|
||||||
|
dst += 4 * BPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VE16(uint8_t* dst) { // vertical
|
||||||
|
const v16u8 rtop = LD_UB(dst - BPS);
|
||||||
|
ST_UB8(rtop, rtop, rtop, rtop, rtop, rtop, rtop, rtop, dst, BPS);
|
||||||
|
ST_UB8(rtop, rtop, rtop, rtop, rtop, rtop, rtop, rtop, dst + 8 * BPS, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HE16(uint8_t* dst) { // horizontal
|
||||||
|
int j;
|
||||||
|
for (j = 16; j > 0; j -= 4) {
|
||||||
|
const v16u8 L0 = (v16u8)__msa_fill_b(dst[-1 + 0 * BPS]);
|
||||||
|
const v16u8 L1 = (v16u8)__msa_fill_b(dst[-1 + 1 * BPS]);
|
||||||
|
const v16u8 L2 = (v16u8)__msa_fill_b(dst[-1 + 2 * BPS]);
|
||||||
|
const v16u8 L3 = (v16u8)__msa_fill_b(dst[-1 + 3 * BPS]);
|
||||||
|
ST_UB4(L0, L1, L2, L3, dst, BPS);
|
||||||
|
dst += 4 * BPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
|
||||||
|
int j;
|
||||||
|
uint32_t dc = 8;
|
||||||
|
v16u8 out;
|
||||||
|
|
||||||
|
for (j = 0; j < 16; ++j) {
|
||||||
|
dc += dst[-1 + j * BPS];
|
||||||
|
}
|
||||||
|
out = (v16u8)__msa_fill_b(dc >> 4);
|
||||||
|
ST_UB8(out, out, out, out, out, out, out, out, dst, BPS);
|
||||||
|
ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
|
||||||
|
uint32_t dc = 8;
|
||||||
|
const v16u8 rtop = LD_UB(dst - BPS);
|
||||||
|
const v8u16 dctop = __msa_hadd_u_h(rtop, rtop);
|
||||||
|
v16u8 out;
|
||||||
|
|
||||||
|
dc += HADD_UH_U32(dctop);
|
||||||
|
out = (v16u8)__msa_fill_b(dc >> 4);
|
||||||
|
ST_UB8(out, out, out, out, out, out, out, out, dst, BPS);
|
||||||
|
ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DC16NoTopLeft(uint8_t* dst) { // DC with nothing
|
||||||
|
const v16u8 out = (v16u8)__msa_fill_b(0x80);
|
||||||
|
ST_UB8(out, out, out, out, out, out, out, out, dst, BPS);
|
||||||
|
ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chroma
|
||||||
|
|
||||||
|
#define STORE8x8(out, dst) do { \
|
||||||
|
SD4(out, out, out, out, dst + 0 * BPS, BPS); \
|
||||||
|
SD4(out, out, out, out, dst + 4 * BPS, BPS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void DC8uv(uint8_t* dst) { // DC
|
||||||
|
uint32_t dc = 8;
|
||||||
|
int i;
|
||||||
|
uint64_t out;
|
||||||
|
const v16u8 rtop = LD_UB(dst - BPS);
|
||||||
|
const v8u16 temp0 = __msa_hadd_u_h(rtop, rtop);
|
||||||
|
const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0);
|
||||||
|
const v2u64 temp2 = __msa_hadd_u_d(temp1, temp1);
|
||||||
|
v16u8 dctemp;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
dc += dst[-1 + i * BPS];
|
||||||
|
}
|
||||||
|
dc += __msa_copy_s_w((v4i32)temp2, 0);
|
||||||
|
dctemp = (v16u8)__msa_fill_b(dc >> 4);
|
||||||
|
out = __msa_copy_s_d((v2i64)dctemp, 0);
|
||||||
|
STORE8x8(out, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TM8uv(uint8_t* dst) {
|
||||||
|
int j;
|
||||||
|
const v16i8 T1 = LD_SB(dst - BPS);
|
||||||
|
const v16i8 zero = { 0 };
|
||||||
|
const v8i16 T = (v8i16)__msa_ilvr_b(zero, T1);
|
||||||
|
const v8i16 TL = (v8i16)__msa_fill_h(dst[-1 - BPS]);
|
||||||
|
const v8i16 d = T - TL;
|
||||||
|
|
||||||
|
for (j = 0; j < 8; j += 4) {
|
||||||
|
v16i8 t0, t1;
|
||||||
|
v8i16 r0 = (v8i16)__msa_fill_h(dst[-1 + 0 * BPS]);
|
||||||
|
v8i16 r1 = (v8i16)__msa_fill_h(dst[-1 + 1 * BPS]);
|
||||||
|
v8i16 r2 = (v8i16)__msa_fill_h(dst[-1 + 2 * BPS]);
|
||||||
|
v8i16 r3 = (v8i16)__msa_fill_h(dst[-1 + 3 * BPS]);
|
||||||
|
ADD4(d, r0, d, r1, d, r2, d, r3, r0, r1, r2, r3);
|
||||||
|
CLIP_SH4_0_255(r0, r1, r2, r3);
|
||||||
|
PCKEV_B2_SB(r1, r0, r3, r2, t0, t1);
|
||||||
|
ST4x4_UB(t0, t1, 0, 2, 0, 2, dst, BPS);
|
||||||
|
ST4x4_UB(t0, t1, 1, 3, 1, 3, dst + 4, BPS);
|
||||||
|
dst += 4 * BPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VE8uv(uint8_t* dst) { // vertical
|
||||||
|
const v16u8 rtop = LD_UB(dst - BPS);
|
||||||
|
const uint64_t out = __msa_copy_s_d((v2i64)rtop, 0);
|
||||||
|
STORE8x8(out, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HE8uv(uint8_t* dst) { // horizontal
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < 8; j += 4) {
|
||||||
|
const v16u8 L0 = (v16u8)__msa_fill_b(dst[-1 + 0 * BPS]);
|
||||||
|
const v16u8 L1 = (v16u8)__msa_fill_b(dst[-1 + 1 * BPS]);
|
||||||
|
const v16u8 L2 = (v16u8)__msa_fill_b(dst[-1 + 2 * BPS]);
|
||||||
|
const v16u8 L3 = (v16u8)__msa_fill_b(dst[-1 + 3 * BPS]);
|
||||||
|
const uint64_t out0 = __msa_copy_s_d((v2i64)L0, 0);
|
||||||
|
const uint64_t out1 = __msa_copy_s_d((v2i64)L1, 0);
|
||||||
|
const uint64_t out2 = __msa_copy_s_d((v2i64)L2, 0);
|
||||||
|
const uint64_t out3 = __msa_copy_s_d((v2i64)L3, 0);
|
||||||
|
SD4(out0, out1, out2, out3, dst, BPS);
|
||||||
|
dst += 4 * BPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
|
||||||
|
const uint32_t dc = 4;
|
||||||
|
const v16u8 rtop = LD_UB(dst - BPS);
|
||||||
|
const v8u16 temp0 = __msa_hadd_u_h(rtop, rtop);
|
||||||
|
const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0);
|
||||||
|
const v2u64 temp2 = __msa_hadd_u_d(temp1, temp1);
|
||||||
|
const uint32_t sum_m = __msa_copy_s_w((v4i32)temp2, 0);
|
||||||
|
const v16u8 dcval = (v16u8)__msa_fill_b((dc + sum_m) >> 3);
|
||||||
|
const uint64_t out = __msa_copy_s_d((v2i64)dcval, 0);
|
||||||
|
STORE8x8(out, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
|
||||||
|
uint32_t dc = 4;
|
||||||
|
int i;
|
||||||
|
uint64_t out;
|
||||||
|
v16u8 dctemp;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
dc += dst[-1 + i * BPS];
|
||||||
|
}
|
||||||
|
dctemp = (v16u8)__msa_fill_b(dc >> 3);
|
||||||
|
out = __msa_copy_s_d((v2i64)dctemp, 0);
|
||||||
|
STORE8x8(out, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
|
||||||
|
const uint64_t out = 0x8080808080808080ULL;
|
||||||
|
STORE8x8(out, dst);
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Entry point
|
// Entry point
|
||||||
|
|
||||||
@@ -163,6 +977,39 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitMSA(void) {
|
|||||||
VP8Transform = TransformTwo;
|
VP8Transform = TransformTwo;
|
||||||
VP8TransformDC = TransformDC;
|
VP8TransformDC = TransformDC;
|
||||||
VP8TransformAC3 = TransformAC3;
|
VP8TransformAC3 = TransformAC3;
|
||||||
|
|
||||||
|
VP8VFilter16 = VFilter16;
|
||||||
|
VP8HFilter16 = HFilter16;
|
||||||
|
VP8VFilter16i = VFilter16i;
|
||||||
|
VP8HFilter16i = HFilter16i;
|
||||||
|
VP8VFilter8 = VFilter8;
|
||||||
|
VP8HFilter8 = HFilter8;
|
||||||
|
VP8VFilter8i = VFilter8i;
|
||||||
|
VP8HFilter8i = HFilter8i;
|
||||||
|
VP8SimpleVFilter16 = SimpleVFilter16;
|
||||||
|
VP8SimpleHFilter16 = SimpleHFilter16;
|
||||||
|
VP8SimpleVFilter16i = SimpleVFilter16i;
|
||||||
|
VP8SimpleHFilter16i = SimpleHFilter16i;
|
||||||
|
|
||||||
|
VP8PredLuma4[0] = DC4;
|
||||||
|
VP8PredLuma4[1] = TM4;
|
||||||
|
VP8PredLuma4[2] = VE4;
|
||||||
|
VP8PredLuma4[4] = RD4;
|
||||||
|
VP8PredLuma4[6] = LD4;
|
||||||
|
VP8PredLuma16[0] = DC16;
|
||||||
|
VP8PredLuma16[1] = TM16;
|
||||||
|
VP8PredLuma16[2] = VE16;
|
||||||
|
VP8PredLuma16[3] = HE16;
|
||||||
|
VP8PredLuma16[4] = DC16NoTop;
|
||||||
|
VP8PredLuma16[5] = DC16NoLeft;
|
||||||
|
VP8PredLuma16[6] = DC16NoTopLeft;
|
||||||
|
VP8PredChroma8[0] = DC8uv;
|
||||||
|
VP8PredChroma8[1] = TM8uv;
|
||||||
|
VP8PredChroma8[2] = VE8uv;
|
||||||
|
VP8PredChroma8[3] = HE8uv;
|
||||||
|
VP8PredChroma8[4] = DC8uvNoTop;
|
||||||
|
VP8PredChroma8[5] = DC8uvNoLeft;
|
||||||
|
VP8PredChroma8[6] = DC8uvNoTopLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_MSA
|
#else // !WEBP_USE_MSA
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user