Merge branch '0.3.0'

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

Conflicts:
	src/webp/format_constants.h

Change-Id: Ie659644d3ea5592cde64ec3af90a00cd17838247
This commit is contained in:
James Zern 2013-04-01 19:11:52 -07:00
commit df4a406d8d
59 changed files with 1492 additions and 583 deletions

View File

@ -1,2 +1,6 @@
<johann.koenig@duck.com> <johannkoenig@google.com>
Mikołaj Zalewski <mikolajz@google.com> Mikołaj Zalewski <mikolajz@google.com>
Pascal Massimino <pascal.massimino@gmail.com> Pascal Massimino <pascal.massimino@gmail.com>
Vikas Arora <vikasa@google.com>
<vikasa@google.com> <vikasa@gmail.com>
<vikasa@google.com> <vikaas.arora@gmail.com>

View File

@ -1,9 +1,10 @@
Contributors: Contributors:
- James Zern (jzern at google dot com) - James Zern (jzern at google dot com)
- Jan Engelhardt (jengelh at medozas dot de) - Jan Engelhardt (jengelh at medozas dot de)
- Johann (johannkoenig at google dot com) - Johann (johann dot koenig at duck dot com)
- Jyrki Alakuijala (jyrki at google dot com) - Jyrki Alakuijala (jyrki at google dot com)
- Lou Quillio (louquillio at google dot com) - Lou Quillio (louquillio at google dot com)
- Mans Rullgard (mans at mansr dot com)
- Martin Olsson (mnemo at minimum dot se) - Martin Olsson (mnemo at minimum dot se)
- Mikołaj Zalewski (mikolajz at google dot com) - Mikołaj Zalewski (mikolajz at google dot com)
- Noel Chromium (noel at chromium dot org) - Noel Chromium (noel at chromium dot org)

383
ChangeLog
View File

@ -1,3 +1,333 @@
d52b405 Cosmetic fixes
6cb4a61 misc style fix
68111ab add missing YUVA->ARGB automatic conversion in WebPEncode()
403bfe8 Container spec: Clarify frame disposal
3e7a13a Merge "Container spec: clarify the background color field" into 0.3.0
14af774 container doc: add a note about the 'ANMF' payload
cc635ef Container spec: clarify the background color field
e3e3394 container doc: move RIFF description to own section
4299f39 libwebp/mux: fix double free
33f9a69 Merge "demux: keep a frame tail pointer; used in AddFrame" into 0.3.0
a2a7b95 use WebPDataCopy() instead of re-coding it.
6f18f12 demux: keep a frame tail pointer; used in AddFrame
e5af49e add doc precision about WebPParseHeaders() return codes
db46daa Merge "Makefile.vc: fix dynamic builds" into 0.3.0
53c77af Merge "gif2webp: Bgcolor fix for a special case" into 0.3.0
a5ebd14 gif2webp: Bgcolor fix for a special case
6378f23 Merge "vwebp/animation: fix background dispose" into 0.3.0
3c8eb9a fix bad saturation order in QuantizeBlock
04c7a2e vwebp/animation: fix background dispose
81a5069 Makefile.vc: fix dynamic builds
5f25c39 update ChangeLog
14d42af examples: don't use C99 %zu
5ccf1fe update ChangeLog
2560c24 update NEWS
f43bafc Merge changes Iecccb09c,If5ee9fd2,I3e181ce4 into 0.3.0
a788644 dwebp: warn when decoding animated webp's
302efcd Decode: return more meaningful error for animation
ad45273 WebPBitstreamFeatures: add has_animation field
783dfa4 disable FRGM decoding for good in libwebpmux
4b956be Update ChangeLog
ad8b86d update NEWS
3e084f6 Merge "demux cosmetics: comments/rename internal function" into 0.3.0
d3f8c62 Merge "move WebPFeatureFlags declaration" into 0.3.0
7386fe5 Merge "libwebp{demux,mux}: install mux_types.h" into 0.3.0
d6cd4e9 Merge "bump decode abi" into 0.3.0
17f8da5 bump decode abi
97684ae Merge "add doc precision about WebPDemuxPartial()" into 0.3.0
f933fd2 move WebPFeatureFlags declaration
289bc47 libwebp{demux,mux}: install mux_types.h
224e8d4 add doc precision about WebPDemuxPartial()
4c18e80 demux cosmetics: comments/rename internal function
7cfd1bf update AUTHORS
401f7b8 Merge "speed-up lossless (~3%) with ad-hoc histogram cost evaluation" into 0.3.0
1fc8ffc Merge "makefile.unix: dist related changes" into 0.3.0
8a89c6e Merge changes I466c377f,Ib761ebd3,I694857fc into 0.3.0
f4ffb2d speed-up lossless (~3%) with ad-hoc histogram cost evaluation
723847d gif2webp: only write error messages to stderr
701b9e2 makefile.unix: dist related changes
bb85b43 Merge "update NEWS" into 0.3.0
59423a2 gif2webp: fix crash on open failure with libgif5
9acb17d gif2webp: silence a unused param warning
7d9fdc2 Merge "README updates" into 0.3.0
5621934 Merge "build: fix install race on shared headers" into 0.3.0
70809d8 Merge "bump version to 0.3.0" into 0.3.0
d851cd1 demux: make the parse a bit more strict
28bb410 update NEWS
cef9388 bump version to 0.3.0
9048494 build: fix install race on shared headers
1e67e8e README updates
42b611a Merge "configure: drop experimental from mux/demux" into 0.3.0
096a8e3 Merge "vwebp: add color profile support" into 0.3.0
ddfee5d vwebp: add color profile support
0d6927d Merge "Mark fragment options as experimental in webpmux" into 0.3.0
5dbd403 Mark fragment options as experimental in webpmux
a0a6648 configure: drop experimental from mux/demux
ee65bad Merge "add support for BITS > 32" into 0.3.0
744930d add support for BITS > 32
7dd288f cwebp: fix build
19a8dd0 Merge "Makefile.vc: add vwebp.exe target" into 0.3.0
50eedda Merge "examples: normalize icc related program arguments" into 0.3.0
757f637 Merge "Makefile.vc: add libwebpdecoder target" into 0.3.0
b65c4b7 Makefile.vc: add libwebpdecoder target
f8db7b4 Merge "vwebp: replace doubles w/floats where appropriate" into 0.3.0
d99aa56 Makefile.vc: add vwebp.exe target
013023e vwebp: replace doubles w/floats where appropriate
9b3db89 README.mux: add version reference
7b6a26c Merge "cwebp: output metadata statistics" into 0.3.0
d8dc72a examples: normalize icc related program arguments
7bfc905 Merge "make alpha unfilter work in-place" into 0.3.0
0037b2d Merge "add LUT-free reference code for YUV->RGB conversion." into 0.3.0
166bf74 Merge "demux: disable fragment parsing" into 0.3.0
126974b add LUT-free reference code for YUV->RGB conversion.
0aef3eb make alpha unfilter work in-place
14ef500 Merge "Remove 'status: experimental' from container spec" into 0.3.0
d40c98e Merge "webpmux binary: tiny style fix" into 0.3.0
0bc4268 cwebp: output metadata statistics
bc03980 Merge "autoconf: normalize experimental define" into 0.3.0
d1e21b1 Remove 'status: experimental' from container spec
7681bb9 webpmux binary: tiny style fix
a3dd3d0 avoid installing example_util.h
252320e demux: disable fragment parsing
537bde0 autoconf: normalize experimental define
5e338e0 Merge changes I33e8a613,I8e8a7b44 into 0.3.0
d9d0ea1 Merge changes If21e3ec7,I991fc30b into 0.3.0
627f5ca automake: add reference to libwebp for mux/demux
eef73d0 don't consolidate proba stats too often
05ec4cc libwebp{,decoder}.pc: add pthread flags
1bfcf5b add libwebpmux.pc
26ca843 add libwebpdemux.pc
69e2590 Merge "Tune Lossless compression for lower qualities."
0478b5d Tune Lossless compression for lower qualities.
39f7586 add a mention of parallel alpha encoding in the NEWS
5a21d96 Merge "1.5x-2x faster encoding for method 3 and up"
9bfbdd1 1.5x-2x faster encoding for method 3 and up
27dc741 Correct frame options order in README.mux
be2fd17 Mux: fix a scenario with bad ANMF/FRGM size
19eb012 Merge "Demux: Add option to get frame count using GetI()"
7368b8c Merge "WebPGetFeatures() out of if condition for clarity."
f604c9a Merge "fix windows build"
153f94e fix windows build
847b492 Merge "vwebp: use magenta for 'i'nfo display"
25ea46b Merge "vwebp: add keyboard shortcuts to help output"
bea7cca vwebp: use magenta for 'i'nfo display
8fab161 webpmux: correct -frame param order in help output
03cc23d vwebp: add keyboard shortcuts to help output
068eba8 Demux: Add option to get frame count using GetI()
988b8f5 WebPGetFeatures() out of if condition for clarity.
6933d91 Merge "gif2webp: Be lenient about background color index."
4d0f7c5 Merge "WebPGetFeatures() behavior change:"
fdeeb01 gif2webp: Be lenient about background color index.
ad25032 Merge "multi-threaded alpha encoding for lossy"
4e32d3e Merge "fix compilation of token.c"
f817930 multi-threaded alpha encoding for lossy
8805035 fix compilation of token.c
fc81621 code using the actual values for num_parts_, not the ones from config
7265535 Merge "move the config check from .c to .h"
dd9e76f move the config check from .c to .h
956b217 WebPGetFeatures() behavior change:
df02e4c WebPDemuxGetI behavior change:
633c004 Merge "rebalance method tools (-m) for methods [0..4]"
58ca6f6 rebalance method tools (-m) for methods [0..4]
7648c3c Merge "describe rd-opt levels introduce VP8RDLevel enum"
67fb100 Merge "autoconf: enable silent-rules by default"
a5042a3 GetVersion() methods for mux and demux
5189957 describe rd-opt levels introduce VP8RDLevel enum
4e094ac autoconf: enable silent-rules by default
b7eaa85 inline VP8LFastLog2() and VP8LFastSLog2 for small values
5cf7792 split quant_levels.c into decoder and encoder version
e5d3ffe Merge "Update code example in README.mux"
ac5a915 Update code example in README.mux
38a91e9 Add example code snippet for demux API
5f557f3 README.mux: add info about Demux API and vwebp
c0ba090 backward_references: avoid signed integer overflow
943386d disable SSE2 for now
9479fb7 lossless encoding speedup
ec2030a merge two lines together
b67956c Merge "Remove ReadOneBit() and ReadSymbolUnsafe()"
1667bde Remove ReadOneBit() and ReadSymbolUnsafe()
3151669 wicdec + dwebp cosmetics: normalize formatting
92668da change default filtering parameters: * type is now 'strong' * strength is now '60'
b7490f8 introduce WEBP_REFERENCE_IMPLEMENTATION compile option
3383885 faster decoding (3%-6%)
5c3e381 Merge "add a -jpeg_like option"
c231104 remove unused declaration of VP8Zigzag
3615295 Merge "wicdec: add alpha support for paletted formats"
c9f1649 wicdec: add alpha support for paletted formats
1262f81 Merge "wicdec: silence some warnings"
e7ea61e wicdec: silence some warnings
23c0f35 fix missing intptr_t->int cast for MSVC
e895059 add a -jpeg_like option
1f803f6 Merge "Tune alpha quality mapping to more reasonable values."
1267d49 Tune alpha quality mapping to more reasonable values.
043076e Merge "speed-up lossless in BackwardTrace"
f3a44dc remove one malloc from TraceBackwards()
0fc1a3a speed-up lossless in BackwardTrace
7c732e5 cwebp: centralize WebPCleanupTransparentArea()
7381254 Merge "wicdec: add ICC profile extraction"
e83ff7d wicdec: add ICC profile extraction
146c6e3 Merge "cosmetics: pngdec: normalize default label location"
a8f549d Merge "manpages: italicize option parameters"
e118db8 Merge "encode.h: note the need to free() WebPMemoryWriter"
1dfee6d cosmetics: pngdec: normalize default label location
14c3820 manpages: italicize option parameters
7defbfa encode.h: note the need to free() WebPMemoryWriter
88d382a cwebp: cleanup after memory_writer
12d6cec fix extra space in dwebp.1 man
b01681a Fix for demuxer frame iteration:
56c12aa Demuxer creation fix:
66c810b add a -yuv option to dwebp (very similar to -pgm)
841a3ba Merge "Remove -Wshadow warnings."
8fd0252 Merge "upsampling_neon.c: fix build"
6efed26 Remove -Wshadow warnings.
60904aa Merge "allow WebPINewRGB/YUVA to be passed a NULL output buffer."
b7adf37 allow WebPINewRGB/YUVA to be passed a NULL output buffer.
27f8f74 upsampling_neon.c: fix build
06b9cdf gitignore: add IOS related directories
f112221 Merge "Fix more comments for iobuild.sh"
fe4d25d Fix more comments for iobuild.sh
1de3e25 Merge "NEON optimised yuv to rgb conversion"
090b708 NEON optimised yuv to rgb conversion
daa0647 Merge "Add ios build script for building iOS library."
79fe39e Add ios build script for building iOS library.
126c035 remove some more -Wshadow warnings
522e9d6 Merge "cwebp: enable '-metadata'"
76ec5fa cwebp: enable '-metadata'
aeb91a9 Merge "cosmetics: break a few long lines"
be7c96b cosmetics: break a few long lines
cff8ddb Merge "add libwebpdecoder.pc"
93148ab Merge "libwebp.pc.in: detab"
6477f95 Merge "Makefile.vc: normalize path separator"
bed1ed7 add libwebpdecoder.pc
46168b2 libwebp.pc.in: detab
a941a34 Fixed few nits in the build files.
dd7a49b Makefile.vc: normalize path separator
9161be8 Merge "cwebp: extract WIC decoding to its own module"
08e7c58 Merge "Provide an option to build decoder library."
0aeba52 Provide an option to build decoder library.
757ebcb catch malloc(0)/calloc(0) with an assert
152ec3d Merge "handle malloc(0) and calloc(0) uniformly on all platforms"
a452a55 cwebp: extract WIC decoding to its own module
2b252a5 Merge "Provide option to swap bytes for 16 bit colormodes"
94a48b4 Provide option to swap bytes for 16 bit colormodes
42f8f93 handle malloc(0) and calloc(0) uniformly on all platforms
8b2152c Merge "add an extra assert to check memory bounds"
0d19fbf remove some -Wshadow warnings
cd22f65 add an extra assert to check memory bounds
8189fed Merge "Add details and reference about the YUV->RGB conversion"
1d2702b Merge "Formatting fixes in lossless bitstream spec"
8425aae Formatting fixes in lossless bitstream spec
a556cb1 Add details and reference about the YUV->RGB conversion
d8f21e0 add link to SSIM description on Wikipedia
18e9167 Merge "WebP-lossless spec clarifications:"
98e25b9 Merge "cwebp: add -metadata option"
f01c2a5 WebP-lossless spec clarifications:
f4a9797 Merge "Disto4x4 and Disto16x16 in NEON"
47b7b0b Disto4x4 and Disto16x16 in NEON
7eaee9f cwebp: add -metadata option
36c52c2 tiffdec: use toff_t for exif ifd offset
7c8111e Merge "cwebp/tiffdec: add TIFF metadata extraction"
e6409ad Remove redundant include from dsp/lossless code.
1ab5b3a Merge "configure: fix --with-gifincludedir"
03c749e configure: fix --with-gifincludedir
8b65063 multiple libgif versions support for gif2webp
476e293 gif2webp: Use DGifOpenFileName()
b50f277 tiffdec: correct format string
2b9048e Merge "tiffdec: check error returns for width/height"
a1b5a9a Merge "cwebp/tiff: use the first image directory"
079423f tiffdec: check error returns for width/height
d62824a Merge "cwebp/jpegdec: add JPEG metadata extraction"
03afaca Merge "cwebp: add PNG metadata extraction"
2c72496 cwebp/jpegdec: add JPEG metadata extraction
dba64d9 cwebp: add PNG metadata extraction
1f075f8 Lossless spec corrections/rewording/clarifications
2914ecf cwebp/tiffdec: add TIFF metadata extraction
d82a3e3 More corrections/clarifications in lossless spec:
bd00255 cwebp/tiff: use the first image directory
df7aa07 Merge "Cleanup around jpegdec"
0f57dcc decoding speed-up (~1%)
bcec339 Lossless bitstream clarification:
6bf2087 add examples/metadata.c
207f89c Merge "configure: add libwebpdemux status to summary"
1bd287a Cleanup around jpegdec
9145567 Merge "cosmetics: use '== 0' in size checks"
d6b88b7 cosmetics: use '== 0' in size checks
d3dace2 cosmetics: jpegdec
2f69af7 configure: add libwebpdemux status to summary
1c1c564 cwebp: extract tiff decoding to its own module
6a871d6 cwebp: extract jpeg decoding to its own module
2ee228f cwebp: extract png decoding to its own module
4679db0 Merge "cwebp: add metadata framework"
63aba3a cwebp: add metadata framework
931bd51 lossless bitstream: block size bits correction
e4fc4c1 lossless bitstream: block size bits correction
d65ec67 fix build, move token.c to src/enc/
657f5c9 move token buffer to its own file (token.c)
c34a375 introduce GetLargeValue() to slim-fast GetCoeffs().
d5838cd faster non-transposing SSE2 4x4 FTransform
f76191f speed up GetResidualCost()
ba2aa0f Add support for BITS=24 case
2e7f6e8 makefile.unix: Dependency on libraries
dca8421 Merge "Separate out mux and demux code and libraries:"
23782f9 Separate out mux and demux code and libraries:
bd56a01 configure: add summary output
90e5e31 dwebp manual: point to webpmux, gif2webp.
540790c gif2webp.c: add a note about prerequisites
d1edf69 cwebp man page: meaning of '-q' for lossy/lossless
79efa1d Add man page for gif2webp utility
2243e40 Merge "gif2webp build support with autoconf tools"
c40efca gif2webp build support with autoconf tools
6523e2d WebP Container:
4da788d Merge "simplify the fwd transform"
42c3b55 simplify the fwd transform
41a6ced user GLfloat instead of float
b542611 fix indentation
68f282f * handle offset in anim viewer 'vwebp' * fix gif2webp to handle disposal method and odd offset correctly
118cb31 Merge "add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case"
8a7c3cc Merge "Change the order of -frame argument to be more natural"
99e0a70 Merge "Simplify the texture evaluation Disto4x4()"
0f923c3 make the bundling work in a tmp buffer
e5c3b3f Simplify the texture evaluation Disto4x4()
4860008 Change the order of -frame argument to be more natural
35bfd4c add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case
a7305c2 Clarification for unknown chunks
4c4398e Refine WebP Container Spec wrt unknown chunks.
2ca642e Rectify WebPMuxGetFeatures:
7caab1d Some cosmetic/comment fixes.
60b2651 Merge "Write a GIF to WebP converter based on libgif."
c7127a4 Merge "Add NEON version of FTransformWHT"
11b2721 Write a GIF to WebP converter based on libgif.
e9a15a3 ExUtilWriteFile() to write memory segment to file
74356eb Add a simple cleanup step in mux assembly:
51bb1e5 mux.h: correct WebPDemuxSelectFragment() prototype
22a0fd9 Add NEON version of FTransformWHT
fa30c86 Update mux code to match the spec wrt animation
d9c5fbe by-pass Analysis pass in case segments=1
d2ad445 Merge changes Ibeccffc3,Id1585b16
5c8be25 Merge "Chunk fourCCs for XMP/EXIF"
a00a3da Use 'frgm' instead of 'tile' in webpmux parameters
81b8a74 Design change in ANMF and FRGM chunks:
f903cba Chunk fourCCs for XMP/EXIF
812933d Tune performance of HistogramCombine
52ad197 Animation specification in container spec
001b930 Image fragment specification in container spec
391f9db Ordering of description of bits in container spec
d573577 Metadata specification in container spec
1c4609b Merge commit 'v0.2.1'
0ca584c Merge "Color profile specification in container spec"
e8b41ad add NEON asm version for WHT inverse transform
af6f0db Color profile specification in container spec
a61a824 Merge "Add NULL check in chunk APIs"
0e8b7ee fix WebPPictureView() unassigned strides
75e5f17 ARM/NEON: 30% encoding speed-up
02b4356 Add NULL check in chunk APIs
a077072 mux struct naming
6c66dde Merge "Tune Lossless encoder"
ab5ea21 Tune Lossless encoder
74fefc8 Update ChangeLog (v0.2.1, origin/0.2.0)
92f8059 Rename some chunks:
3bb4bbe Merge "Mux API change:"
d0c79f0 Mux API change:
abc0604 Merge "update NEWS" into 0.2.0 abc0604 Merge "update NEWS" into 0.2.0
57cf313 update NEWS 57cf313 update NEWS
25f585c bump version to 0.2.1 25f585c bump version to 0.2.1
@ -15,6 +345,55 @@ b30add2 EncodeImageInternal: fix uninitialized free
e5970bd Make *InitSSE2() functions be empty on non-SSE2 platform e5970bd Make *InitSSE2() functions be empty on non-SSE2 platform
ef5cc47 make *InitSSE2() functions be empty on non-SSE2 platform ef5cc47 make *InitSSE2() functions be empty on non-SSE2 platform
c4ea259 make VP8DspInitNEON() public c4ea259 make VP8DspInitNEON() public
8344ead Merge "libwebp: validate chunk size in ParseOptionalChunks"
4828bb9 Merge "cwebp (windows): fix alpha image import on XP"
3076333 libwebp: validate chunk size in ParseOptionalChunks
7048189 AccumulateLSIM: fix double -> float warnings
eda8ee4 cwebp (windows): fix alpha image import on XP
c6e9865 Merge "add EXPERIMENTAL code for YUV-JPEG colorspace"
f0360b4 add EXPERIMENTAL code for YUV-JPEG colorspace
f86e6ab add LSIM metric to WebPPictureDistortion()
c3aa215 Speed up HistogramCombine for lower qualities.
1765cb1 Merge "autoconf/libwebp: enable dll builds for mingw"
a13562e autoconf/libwebp: enable dll builds for mingw
9f469b5 typo: no_fancy -> no_fancy_upsampling
1a27f2f Merge "fix double to float conversion warning"
cf1e90d Merge "cwebp: fix jpg encodes on XP"
f2b5d19 [cd]webp: always output windows errors
e855208 fix double to float conversion warning
ecd66f7 cwebp: fix jpg encodes on XP
7b3eb37 Tune lossless compression to get better gains.
ce8bff4 Merge "VP8LAllocateHistogramSet: fix overflow in size calculation"
ab5b67a Merge "EncodeImageInternal: fix uninitialized free"
7fee5d1 Merge "GetHistoBits: fix integer overflow"
a6ae04d VP8LAllocateHistogramSet: fix overflow in size calculation
80237c4 GetHistoBits: fix integer overflow
8a99723 EncodeImageInternal: fix uninitialized free
0b9e682 minor cosmetics
a792b91 fix the -g/O3 discrepancy for 32bit compile
73ba435 Merge "detect and merge similar segments"
fee6627 detect and merge similar segments
0c44f41 src/webp/*.h: don't forward declare enums in C++
d7a5ac8 vwebp: use demux interface
931e0ea Merge "replace 'typedef struct {} X;" by "typedef struct X X; struct X {};""
8f216f7 remove cases of equal comparison for qsort()
28d25c8 replace 'typedef struct {} X;" by "typedef struct X X; struct X {};"
2afee60 speed up for ARM using 8bit for boolean decoder
5725cab new segmentation algorithm
2cf1f81 Merge "fix the BITS=8 case"
12f78ae fix the BITS=8 case
6920c71 fix MSVC warnings regarding implicit uint64 to uint32 conversions
f6c096a webpmux binary: Rename 'xmp' option to 'meta'
ddfe871 webpmux help correction
b7c5544 Merge "Make *InitSSE2() functions be empty on non-SSE2 platform"
1c04a0d Common APIs for chunks metadata and color profile.
2a3117a Merge "Create WebPMuxFrameInfo struct for Mux APIs"
5c3a723 Make *InitSSE2() functions be empty on non-SSE2 platform
7c6e60f make *InitSSE2() functions be empty on non-SSE2 platform
c7eb457 make VP8DspInitNEON() public
ab3234a Create WebPMuxFrameInfo struct for Mux APIs
e3990fd Alignment fixes
e55fbd6 Merge branch '0.2.0'
4238bc0 Update ChangeLog (v0.2.0) 4238bc0 Update ChangeLog (v0.2.0)
c655380 dec/io.c: cosmetics c655380 dec/io.c: cosmetics
fe1958f RGBA4444: harmonize lossless/lossy alpha values fe1958f RGBA4444: harmonize lossless/lossy alpha values
@ -135,7 +514,7 @@ f0b5def bump versions
05108f6 Merge "More spec/code matching in mux:" 05108f6 Merge "More spec/code matching in mux:"
6808e69 More spec/code matching in mux: 6808e69 More spec/code matching in mux:
bd2b46f Merge "doc/webp-container-spec: light cosmetics" bd2b46f Merge "doc/webp-container-spec: light cosmetics"
20ead32 doc/webp-container-spec: light cosmetics (full) 20ead32 doc/webp-container-spec: light cosmetics
1d40a8b configure: add pthread detection 1d40a8b configure: add pthread detection
b5e9067 fix some int <-> size_t mix for buffer sizes b5e9067 fix some int <-> size_t mix for buffer sizes
e41a759 build: remove libwebpmux from default targets/config e41a759 build: remove libwebpmux from default targets/config
@ -258,7 +637,7 @@ f8f9408 libwebp: add WebPDemux stub functions
fb47bb5 Merge "NumNamedElements() should take an enum param." fb47bb5 Merge "NumNamedElements() should take an enum param."
7c68980 Fix asserts in Palette and BackwardReference code. 7c68980 Fix asserts in Palette and BackwardReference code.
fbdcb7e NumNamedElements() should take an enum param. fbdcb7e NumNamedElements() should take an enum param.
fb4943b modify WebPParseHeaders to allow reuse by GetFeatures (old-decode-alph-3) fb4943b modify WebPParseHeaders to allow reuse by GetFeatures
3697b5c write an ad-hoc EncodeImageInternal variant 3697b5c write an ad-hoc EncodeImageInternal variant
eaee9e7 Bug-Fix: Decode small (less than 32 bytes) images. eaee9e7 Bug-Fix: Decode small (less than 32 bytes) images.
0bceae4 Merge "cwebp: fix alpha reporting in stats output" 0bceae4 Merge "cwebp: fix alpha reporting in stats output"

View File

@ -1,6 +1,7 @@
# #
# Stem for static libs and DLLs # Stem for static libs and DLLs
# #
LIBWEBPDECODER_BASENAME = libwebpdecoder
LIBWEBP_BASENAME = libwebp LIBWEBP_BASENAME = libwebp
LIBWEBPMUX_BASENAME = libwebpmux LIBWEBPMUX_BASENAME = libwebpmux
LIBWEBPDEMUX_BASENAME = libwebpdemux LIBWEBPDEMUX_BASENAME = libwebpdemux
@ -75,6 +76,7 @@ STATICLIBBUILD = TRUE
CC = $(CCDEBUG) CC = $(CCDEBUG)
RTLIB = $(RTLIBD) RTLIB = $(RTLIBD)
STATICLIBBUILD = TRUE STATICLIBBUILD = TRUE
LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
@ -85,6 +87,7 @@ DLLBUILD = TRUE
CC = $(CCDEBUG) CC = $(CCDEBUG)
RTLIB = $(RTLIBD) RTLIB = $(RTLIBD)
DLLBUILD = TRUE DLLBUILD = TRUE
LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
@ -93,17 +96,19 @@ LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
!IF "$(STATICLIBBUILD)" == "TRUE" !IF "$(STATICLIBBUILD)" == "TRUE"
CC = $(CC) $(RTLIB) CC = $(CC) $(RTLIB)
CFGSET = TRUE CFGSET = TRUE
LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME).lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib
!ELSE IF "$(DLLBUILD)" == "TRUE" !ELSE IF "$(DLLBUILD)" == "TRUE"
DLLC = webp_dll.c DLLC = webp_dll.c
DLLINC = webp_dll.h DLLINC = webp_dll.h
DLL_OBJS = $(DIROBJ)\$(DLLC:.c=.obj)
CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL
LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPMDEMUX_BASENAME)_dll.lib LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPMDEMUX_BASENAME)_dll.lib
LIBWEBP_OBJS = $(DIROBJ)\$(DLLC:.c=.obj)
LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb
CFGSET = TRUE CFGSET = TRUE
!ENDIF !ENDIF
@ -160,17 +165,22 @@ DEC_OBJS = \
DEMUX_OBJS = \ DEMUX_OBJS = \
$(DIROBJ)\demux\demux.obj \ $(DIROBJ)\demux\demux.obj \
DSP_OBJS = \ DSP_DEC_OBJS = \
$(DIROBJ)\dsp\cpu.obj \ $(DIROBJ)\dsp\cpu.obj \
$(DIROBJ)\dsp\dec.obj \ $(DIROBJ)\dsp\dec.obj \
$(DIROBJ)\dsp\dec_neon.obj \
$(DIROBJ)\dsp\dec_sse2.obj \ $(DIROBJ)\dsp\dec_sse2.obj \
$(DIROBJ)\dsp\enc.obj \
$(DIROBJ)\dsp\enc_sse2.obj \
$(DIROBJ)\dsp\lossless.obj \ $(DIROBJ)\dsp\lossless.obj \
$(DIROBJ)\dsp\upsampling.obj \ $(DIROBJ)\dsp\upsampling.obj \
$(DIROBJ)\dsp\upsampling_neon.obj \
$(DIROBJ)\dsp\upsampling_sse2.obj \ $(DIROBJ)\dsp\upsampling_sse2.obj \
$(DIROBJ)\dsp\yuv.obj \ $(DIROBJ)\dsp\yuv.obj \
DSP_ENC_OBJS = \
$(DIROBJ)\dsp\enc.obj \
$(DIROBJ)\dsp\enc_neon.obj \
$(DIROBJ)\dsp\enc_sse2.obj \
EX_FORMAT_DEC_OBJS = \ EX_FORMAT_DEC_OBJS = \
$(DIROBJ)\examples\jpegdec.obj \ $(DIROBJ)\examples\jpegdec.obj \
$(DIROBJ)\examples\metadata.obj \ $(DIROBJ)\examples\metadata.obj \
@ -205,29 +215,35 @@ MUX_OBJS = \
$(DIROBJ)\mux\muxinternal.obj \ $(DIROBJ)\mux\muxinternal.obj \
$(DIROBJ)\mux\muxread.obj \ $(DIROBJ)\mux\muxread.obj \
UTILS_OBJS = \ UTILS_DEC_OBJS = \
$(DIROBJ)\utils\bit_reader.obj \ $(DIROBJ)\utils\bit_reader.obj \
$(DIROBJ)\utils\bit_writer.obj \
$(DIROBJ)\utils\color_cache.obj \ $(DIROBJ)\utils\color_cache.obj \
$(DIROBJ)\utils\filters.obj \ $(DIROBJ)\utils\filters.obj \
$(DIROBJ)\utils\huffman.obj \ $(DIROBJ)\utils\huffman.obj \
$(DIROBJ)\utils\huffman_encode.obj \
$(DIROBJ)\utils\quant_levels.obj \
$(DIROBJ)\utils\quant_levels_dec.obj \ $(DIROBJ)\utils\quant_levels_dec.obj \
$(DIROBJ)\utils\rescaler.obj \ $(DIROBJ)\utils\rescaler.obj \
$(DIROBJ)\utils\thread.obj \ $(DIROBJ)\utils\thread.obj \
$(DIROBJ)\utils\utils.obj \ $(DIROBJ)\utils\utils.obj \
LIBWEBP_OBJS = $(DEC_OBJS) $(DSP_OBJS) $(ENC_OBJS) $(UTILS_OBJS) $(LIBWEBP_OBJS) UTILS_ENC_OBJS = \
$(DIROBJ)\utils\bit_writer.obj \
$(DIROBJ)\utils\huffman_encode.obj \
$(DIROBJ)\utils\quant_levels.obj \
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
$(UTILS_ENC_OBJS) $(DLL_OBJS)
LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS) LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS)
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS) LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS)
OUT_LIBS = $(LIBWEBP) OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP)
OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe
all: $(OUT_LIBS) $(OUT_EXAMPLES) all: $(OUT_LIBS) $(OUT_EXAMPLES)
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(EX_FORMAT_DEC_OBJS) $(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(EX_FORMAT_DEC_OBJS)
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj
$(DIRBIN)\vwebp.exe: $(EX_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX) $(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX)
$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(LIBWEBP) $(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(LIBWEBP)
$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP) $(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP)
@ -237,6 +253,7 @@ experimental:
CFG=$(CFG) \ CFG=$(CFG) \
CFLAGS="$(CFLAGS) /DWEBP_EXPERIMENTAL_FEATURES" /$(MAKEFLAGS) CFLAGS="$(CFLAGS) /DWEBP_EXPERIMENTAL_FEATURES" /$(MAKEFLAGS)
$(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS)
$(LIBWEBP): $(LIBWEBP_OBJS) $(LIBWEBP): $(LIBWEBP_OBJS)
$(LIBWEBPMUX): $(LIBWEBPMUX_OBJS) $(LIBWEBPMUX): $(LIBWEBPMUX_OBJS)
$(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS) $(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS)
@ -244,8 +261,8 @@ $(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS)
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(OUTPUT_DIRS) $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(OUTPUT_DIRS)
!IF "$(DLLBUILD)" == "TRUE" !IF "$(DLLBUILD)" == "TRUE"
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
$(DIROBJ)\$(DLLINC) $(DIROBJ)\$(DLLC) $(DIROBJ)\$(DLLINC) $(DIROBJ)\$(DLLC)
{$(DIROBJ)}.c{$(DIROBJ)}.obj: {$(DIROBJ)}.c{$(DIROBJ)}.obj:
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $< $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
@ -253,14 +270,14 @@ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS):
$(LIBWEBPMUX): $(LIBWEBP) $(LIBWEBPMUX): $(LIBWEBP)
$(LIBWEBPDEMUX): $(LIBWEBP) $(LIBWEBPDEMUX): $(LIBWEBP)
$(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX): $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $** $(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
clean:: clean::
@-erase /s $(DIROBJ)\$(DLLC) $(DIROBJ)\$(DLLINC) 2> NUL @-erase /s $(DIROBJ)\$(DLLC) $(DIROBJ)\$(DLLINC) 2> NUL
!ELSE !ELSE
$(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX): $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LNKLIB) /out:$@ $(LFLAGS) $** $(LNKLIB) /out:$@ $(LFLAGS) $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
!ENDIF !ENDIF

10
NEWS
View File

@ -1,9 +1,17 @@
- next version: - 3/20/13: version 0.3.0
This is a binary compatible release.
* WebPINewRGB/WebPINewYUVA accept being passed a NULL output buffer * WebPINewRGB/WebPINewYUVA accept being passed a NULL output buffer
and will perform auto-allocation. and will perform auto-allocation.
* default filter option is now '-strong -f 60' * default filter option is now '-strong -f 60'
* encoding speed-up for lossy methods 3 to 6 * encoding speed-up for lossy methods 3 to 6
* alpha encoding can be done in parallel to lossy using 'cwebp -mt ...' * alpha encoding can be done in parallel to lossy using 'cwebp -mt ...'
* color profile, metadata (XMP/EXIF) and animation support finalized in the
container.
* various NEON assembly additions
Tool updates / additions:
* gif2webp added
* vwebp given color profile & animation support
* cwebp can preserve color profile / metadata with '-metadata'
- 10/30/12: version 0.2.1 - 10/30/12: version 0.2.1
* Various security related fixes * Various security related fixes

62
README
View File

@ -4,7 +4,7 @@
\__\__/\____/\_____/__/ ____ ___ \__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/ / _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__ / \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v0.2.1 \____/____/\_____/_____/____/v0.3.0
Description: Description:
============ ============
@ -49,7 +49,7 @@ will build the binaries examples/cwebp and examples/dwebp, along
with the static library src/libwebp.a. No system-wide installation with the static library src/libwebp.a. No system-wide installation
is supplied, as this is a simple alternative to the full installation is supplied, as this is a simple alternative to the full installation
system based on the autoconf tools (see below). system based on the autoconf tools (see below).
Please refer to the makefile.unix for additional details and customizations. Please refer to makefile.unix for additional details and customizations.
Using autoconf tools: Using autoconf tools:
--------------------- ---------------------
@ -71,10 +71,11 @@ should be all you need to have the following files
installed. installed.
Note: The encoding and decoding libraries are compiled separately Note: A decode-only library, libwebpdecoder, is available using the
(as src/dec/libwebpdecode.* and src/dec/libwebpencode.*). They '--enable-libwebpdecoder' flag. The encode library is built separately and can
can be installed independently using a minor modification in the be installed independently using a minor modification in the corresponding
corresponding Makefile.am configure files (see comments there). Makefile.am configure files (see comments there). See './configure --help' for
more options.
SWIG bindings: SWIG bindings:
-------------- --------------
@ -176,7 +177,7 @@ options:
-metadata <string> ..... comma separated list of metadata to -metadata <string> ..... comma separated list of metadata to
copy from the input to the output if present. copy from the input to the output if present.
Valid values: all, none (default), exif, iccp, xmp Valid values: all, none (default), exif, icc, xmp
-short ................. condense printed message -short ................. condense printed message
-quiet ................. don't print anything. -quiet ................. don't print anything.
@ -263,12 +264,51 @@ Visualization tool:
There's a little self-serve visualization tool called 'vwebp' under the There's a little self-serve visualization tool called 'vwebp' under the
examples/ directory. It uses OpenGL to open a simple drawing window and show examples/ directory. It uses OpenGL to open a simple drawing window and show
a decoded WebP file. It's not yet integrated in the automake or makefile.unix a decoded WebP file. It's not yet integrated in the automake build system, but
build system, but you can try to manually compile it using the recommendations you can try to manually compile it using the recommendations below.
at the top of the source file.
Usage: 'vwebp my_picture.webp' Usage: vwebp in_file [options]
Decodes the WebP image file and visualize it using OpenGL
Options are:
-version .... print version number and exit.
-noicc ....... don't use the icc profile if present.
-nofancy ..... don't use the fancy YUV420 upscaler.
-nofilter .... disable in-loop filtering.
-mt .......... use multi-threading.
-info ........ print info.
-h ....... this help message.
Keyboard shortcuts:
'c' ................ toggle use of color profile.
'i' ................ overlay file information.
'q' / 'Q' / ESC .... quit.
Building:
---------
Prerequisites:
1) OpenGL & OpenGL Utility Toolkit (GLUT)
Linux:
$ sudo apt-get install freeglut3-dev mesa-common-dev
Mac + XCode:
- These libraries should be available in the OpenGL / GLUT frameworks.
Windows:
http://freeglut.sourceforge.net/index.php#download
2) (Optional) qcms (Quick Color Management System)
i. Download qcms from Mozilla / Chromium:
http://hg.mozilla.org/mozilla-central/file/0e7639e3bdfb/gfx/qcms
http://src.chromium.org/viewvc/chrome/trunk/src/third_party/qcms
ii. Build and archive the source files as libqcms.a / qcms.lib
iii. Update makefile.unix / Makefile.vc
a) Define WEBP_HAVE_QCMS
b) Update include / library paths to reference the qcms directory.
Build using makefile.unix / Makefile.vc:
$ make -f makefile.unix examples/vwebp
> nmake /f Makefile.vc CFG=release-static \
../obj/x64/release-static/bin/vwebp.exe
Encoding API: Encoding API:
============= =============

View File

@ -1,7 +1,7 @@
 __ __ ____ ____ ____ __ __ _ __ __  __ __ ____ ____ ____ __ __ _ __ __
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\ / \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
\ / __/ _ \ __/ / / (_/ /__ \ / __/ _ \ __/ / / (_/ /__
\__\__/\_____/_____/__/ \__//_/\_____/__/___/ \__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.1.0
Description: Description:
@ -9,9 +9,9 @@ Description:
WebPMux: set of two libraries 'Mux' and 'Demux' for creation, extraction and WebPMux: set of two libraries 'Mux' and 'Demux' for creation, extraction and
manipulation of an extended format WebP file, which can have features like manipulation of an extended format WebP file, which can have features like
color profile, metadata, animation and fragmented images. Reference color profile, metadata and animation. Reference command-line tools 'webpmux'
command-line tools 'webpmux' and 'vwebp' as well as the WebP container and 'vwebp' as well as the WebP container specification
specification 'doc/webp-container-spec.txt' are also provided in this package. 'doc/webp-container-spec.txt' are also provided in this package.
WebP Mux tool: WebP Mux tool:
============== ==============
@ -26,7 +26,6 @@ A list of options is available using the -help command line flag:
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 -strip STRIP_OPTIONS INPUT -o OUTPUT webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT
webpmux -frgm FRAGMENT_OPTIONS [-frgm...] -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
webpmux -info INPUT webpmux -info INPUT
@ -38,7 +37,6 @@ GET_OPTIONS:
icc Get ICC profile. icc Get ICC profile.
exif Get EXIF metadata. exif Get EXIF metadata.
xmp Get XMP metadata. xmp Get XMP metadata.
frgm n Get nth fragment.
frame n Get nth frame. frame n Get nth frame.
SET_OPTIONS: SET_OPTIONS:
@ -47,7 +45,7 @@ SET_OPTIONS:
exif file.exif Set EXIF metadata. exif file.exif Set EXIF metadata.
xmp file.xmp Set XMP metadata. xmp file.xmp Set XMP metadata.
where: 'file.icc' contains the ICC profile to be set, where: 'file.icc' contains the ICC profile to be set,
'file.exif' contains the EXIF metadata to be set and '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
STRIP_OPTIONS: STRIP_OPTIONS:
@ -56,12 +54,6 @@ STRIP_OPTIONS:
exif Strip EXIF metadata. exif Strip EXIF metadata.
xmp Strip XMP metadata. xmp Strip XMP metadata.
FRAGMENT_OPTIONS(i):
Create fragmented image.
file_i +xi+yi
where: 'file_i' is the i'th fragment (WebP format),
'xi','yi' specify the image offset for this fragment.
FRAME_OPTIONS(i): FRAME_OPTIONS(i):
Create animation. Create animation.
file_i +di+xi+yi+mi file_i +di+xi+yi+mi
@ -86,29 +78,18 @@ INPUT & OUTPUT are in WebP format.
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
valid. valid.
WebP viewer tool: Visualization tool:
================ ===================
The examples/ directory also contains a tool (vwebp) for viewing WebP files. The examples/ directory also contains a tool (vwebp) for viewing WebP files.
It decodes the image and visualizes it using OpenGL. It decodes the image and visualizes it using OpenGL. See the libwebp README
for details on building and running this program.
A list of options is available using the -h command line flag:
> vwebp -h
Decodes the WebP image file and visualize it using OpenGL
Options are:
-version .... print version number and exit.
-nofancy ..... don't use the fancy YUV420 upscaler.
-nofilter .... disable in-loop filtering.
-mt .......... use multi-threading
-info ........ print info.
-h ....... this help message.
Mux API: Mux API:
======== ========
The Mux API contains methods for adding data to and reading data from WebP The Mux API contains methods for adding data to and reading data from WebP
files. This API currently supports XMP/EXIF metadata, ICC profile, animation files. This API currently supports XMP/EXIF metadata, ICC profile and animation.
and fragmented images. Other features may be added in subsequent releases. Other features may be added in subsequent releases.
Example#1 (pseudo code): Creating a WebPMux object with image data, color Example#1 (pseudo code): Creating a WebPMux object with image data, color
profile and XMP metadata. profile and XMP metadata.
@ -145,11 +126,11 @@ For a detailed Mux API reference, please refer to the header file
(src/webp/mux.h). (src/webp/mux.h).
Demux API: Demux API:
========= ==========
The Demux API enables extraction of images and extended format data from The Demux API enables extraction of images and extended format data from
WebP files. This API currently supports reading of XMP/EXIF metadata, ICC WebP files. This API currently supports reading of XMP/EXIF metadata, ICC
profile, animation and fragmented images. Other features may be added in profile and animated images. Other features may be added in subsequent
subsequent releases. releases.
Code Example: Demuxing WebP data to extract all the frames, ICC profile Code Example: Demuxing WebP data to extract all the frames, ICC profile
and EXIF/XMP metadata. and EXIF/XMP metadata.

View File

@ -1,4 +1,4 @@
AC_INIT([libwebp], [0.2.1], AC_INIT([libwebp], [0.3.0],
[http://code.google.com/p/webp/issues],, [http://code.google.com/p/webp/issues],,
[http://developers.google.com/speed/webp]) [http://developers.google.com/speed/webp])
AC_CANONICAL_TARGET AC_CANONICAL_TARGET
@ -176,7 +176,7 @@ CPPFLAGS=$SAVED_CPPFLAGS
LIBS=$SAVED_LIBS LIBS=$SAVED_LIBS
if test "$gif_support" = "yes" -a \ if test "$gif_support" = "yes" -a \
"$enable_experimental_libwebpmux" = "yes"; then "$enable_libwebpmux" = "yes"; then
build_gif2webp=yes build_gif2webp=yes
fi fi
AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"]) AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
@ -244,27 +244,27 @@ AC_MSG_CHECKING(if --enable-experimental option is specified)
AC_ARG_ENABLE([experimental], AS_HELP_STRING([--enable-experimental], AC_ARG_ENABLE([experimental], AS_HELP_STRING([--enable-experimental],
[Activate experimental features])) [Activate experimental features]))
if test "$enable_experimental" = "yes"; then if test "$enable_experimental" = "yes"; then
AC_DEFINE(EXPERIMENTAL,,[Enable experimental code]) AC_DEFINE(WEBP_EXPERIMENTAL_FEATURES, [1], [Enable experimental code])
USE_EXPERIMENTAL_CODE="-DWEBP_EXPERIMENTAL_FEATURES" USE_EXPERIMENTAL_CODE="-DWEBP_EXPERIMENTAL_FEATURES"
fi fi
AC_MSG_RESULT(${enable_experimental-no}) AC_MSG_RESULT(${enable_experimental-no})
AC_SUBST(USE_EXPERIMENTAL_CODE) AC_SUBST(USE_EXPERIMENTAL_CODE)
dnl === Check whether libwebpmux should be built dnl === Check whether libwebpmux should be built
AC_MSG_CHECKING(whether libwebpmux is to be built) AC_MSG_CHECKING(whether libwebpmux is to be built)
AC_ARG_ENABLE([experimental-libwebpmux], AC_ARG_ENABLE([libwebpmux],
AS_HELP_STRING([--enable-experimental-libwebpmux], AS_HELP_STRING([--enable-libwebpmux],
[Build libwebpmux @<:@default=no@:>@])) [Build libwebpmux @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_experimental_libwebpmux-no}) AC_MSG_RESULT(${enable_libwebpmux-no})
AM_CONDITIONAL([WANT_MUX], [test "$enable_experimental_libwebpmux" = "yes"]) AM_CONDITIONAL([WANT_MUX], [test "$enable_libwebpmux" = "yes"])
dnl === Check whether libwebpdemux should be built dnl === Check whether libwebpdemux should be built
AC_MSG_CHECKING(whether libwebpdemux is to be built) AC_MSG_CHECKING(whether libwebpdemux is to be built)
AC_ARG_ENABLE([experimental-libwebpdemux], AC_ARG_ENABLE([libwebpdemux],
AS_HELP_STRING([--enable-experimental-libwebpdemux], AS_HELP_STRING([--enable-libwebpdemux],
[Build libwebpdemux @<:@default=no@:>@])) [Build libwebpdemux @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_experimental_libwebpdemux-no}) AC_MSG_RESULT(${enable_libwebpdemux-no})
AM_CONDITIONAL([WANT_DEMUX], [test "$enable_experimental_libwebpdemux" = "yes"]) AM_CONDITIONAL([WANT_DEMUX], [test "$enable_libwebpdemux" = "yes"])
dnl === Check whether decoder library should be built. dnl === Check whether decoder library should be built.
AC_MSG_CHECKING(whether decoder library is to be built) AC_MSG_CHECKING(whether decoder library is to be built)
@ -283,7 +283,8 @@ AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
src/enc/Makefile src/dsp/Makefile \ src/enc/Makefile src/dsp/Makefile \
src/demux/Makefile src/mux/Makefile \ src/demux/Makefile src/mux/Makefile \
src/utils/Makefile \ src/utils/Makefile \
src/libwebp.pc src/libwebpdecoder.pc]) src/libwebp.pc src/libwebpdecoder.pc \
src/demux/libwebpdemux.pc src/mux/libwebpmux.pc])
AC_OUTPUT AC_OUTPUT
@ -297,8 +298,8 @@ Static libraries: ${enable_static}
Threaded decode: ${enable_threading-no} Threaded decode: ${enable_threading-no}
libwebp: yes libwebp: yes
libwebpdecoder: ${enable_libwebpdecoder-no} libwebpdecoder: ${enable_libwebpdecoder-no}
libwebpdemux: ${enable_experimental_libwebpdemux-no} libwebpdemux: ${enable_libwebpdemux-no}
libwebpmux: ${enable_experimental_libwebpmux-no} libwebpmux: ${enable_libwebpmux-no}
Tools: Tools:
cwebp: yes cwebp: yes
@ -314,5 +315,5 @@ dwebp: yes
PNG : ${png_support-no} PNG : ${png_support-no}
WIC : ${wic_support-no} WIC : ${wic_support-no}
gif2webp: ${build_gif2webp-no} gif2webp: ${build_gif2webp-no}
webpmux: ${enable_experimental_libwebpmux-no} webpmux: ${enable_libwebpmux-no}
]) ])

View File

@ -60,9 +60,9 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
document are to be interpreted as described in [RFC 2119][]. document are to be interpreted as described in [RFC 2119][].
**Note:** Out of the features mentioned above, lossy compression, lossless **Note:** Out of the features mentioned above, lossy compression, lossless
compression and transparency are finalized and are to be considered stable. compression, transparency, metadata, color profile and animation are finalized
On the other hand, metadata, color profile, animation and image fragmentation and are to be considered stable. On the other hand, image fragmentation is
are experimental as of now, and are open to discussion, feedback and comments. experimental as of now, and is open to discussion, feedback and comments.
The same is indicated using annotation "_status: experimental_" in the relevant The same is indicated using annotation "_status: experimental_" in the relevant
sections of this document. sections of this document.
@ -93,11 +93,21 @@ _uint32_
: A 32-bit, little-endian, unsigned integer. : A 32-bit, little-endian, unsigned integer.
_FourCC_
: A _FourCC_ (four-character code) is a _uint32_ created by concatenating four
ASCII characters in little-endian order.
_1-based_ _1-based_
: An unsigned integer field storing values offset by `-1`. e.g., Such a field : An unsigned integer field storing values offset by `-1`. e.g., Such a field
would store value _25_ as _24_. would store value _25_ as _24_.
RIFF file format
----------------
The WebP file format is based on the RIFF (resource interchange file format)
document format.
The basic element of a RIFF file is a _chunk_. It consists of: The basic element of a RIFF file is a _chunk_. It consists of:
0 1 2 3 0 1 2 3
@ -112,12 +122,12 @@ The basic element of a RIFF file is a _chunk_. It consists of:
Chunk FourCC: 32 bits Chunk FourCC: 32 bits
: ASCII four character code or _chunk tag_ used for chunk identification. : ASCII four-character code used for chunk identification.
Chunk Size: 32 bits (_uint32_) Chunk Size: 32 bits (_uint32_)
: The size of the chunk (_ckSize_) not including this field, the chunk : The size of the chunk not including this field, the chunk identifier or
identifier and padding. padding.
Chunk Payload: _Chunk Size_ bytes Chunk Payload: _Chunk Size_ bytes
@ -126,43 +136,13 @@ Chunk Payload: _Chunk Size_ bytes
_ChunkHeader('ABCD')_ _ChunkHeader('ABCD')_
: This is used to describe the fourcc and size header of individual : This is used to describe the _FourCC_ and _Chunk Size_ header of individual
chunks, where 'ABCD' is the fourcc for the chunk. This element's chunks, where 'ABCD' is the FourCC for the chunk. This element's
size is 8 bytes. size is 8 bytes.
: Note that, in this specification, all chunk tag characters are in **Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard
file order, not in byte order of a uint32 of any particular chunks that apply to any RIFF file format, while FourCCs specific to a file
architecture. format are all lowercase. WebP does not follow this convention.
_list of chunks_
: A concatenation of multiple chunks.
: We will refer to the first chunk as having _position_ 0, the second
as position 1, etc. By _chunk with index 0 among "ABCD"_ we mean
the first chunk among the chunks of type "ABCD" in the list, the
_chunk with index 1 among "ABCD"_ is the second such chunk, etc.
A WebP file MUST begin with a single chunk with a tag 'RIFF'. All
other defined chunks are contained within this chunk. The file SHOULD
NOT contain anything after it.
The maximum size of RIFF's _ckSize_ is 2^32 minus 10 bytes. The size
of the whole file is at most 4GiB minus 2 bytes.
**Note:** some RIFF libraries are said to have bugs when handling files
larger than 1GiB or 2GiB. If you are using an existing library, check
that it handles large files correctly.
The first four bytes of the RIFF chunk contents (i.e., bytes 8-11 of the file)
MUST be the ASCII string "WEBP". They are followed by a list of chunks. As the
size of any chunk is even, the size of the RIFF chunk is also even. The
contents of the chunks in that list will be described in the following sections.
**Note:** RIFF has a convention that all-uppercase chunks are standard
chunks that apply to any RIFF file format, while chunks specific to a
file format are all lowercase. WebP does not follow this convention.
WebP file header WebP file header
---------------- ----------------
@ -183,12 +163,20 @@ WebP file header
File Size: 32 bits (_uint32_) File Size: 32 bits (_uint32_)
: The size of the file in bytes starting at offset 8. : The size of the file in bytes starting at offset 8. The maximum value of
this field is 2^32 minus 10 bytes and thus the size of the whole file is at
most 4GiB minus 2 bytes.
'WEBP': 32 bits 'WEBP': 32 bits
: The ASCII characters 'W' 'E' 'B' 'P'. : The ASCII characters 'W' 'E' 'B' 'P'.
A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size
in the header is the total size of the chunks that follow plus `4` bytes for
the 'WEBP' FourCC. The file SHOULD NOT contain anything after it. As the size
of any chunk is even, the size given by the RIFF header is also even. The
contents of individual chunks will be described in the following sections.
Simple file format (lossy) Simple file format (lossy)
-------------------------- --------------------------
@ -274,15 +262,15 @@ An extended format file consists of:
* A 'VP8X' chunk with information about features used in the file. * A 'VP8X' chunk with information about features used in the file.
* An optional 'ICCP' chunk with color profile. _\[status: experimental\]_ * An optional 'ICCP' chunk with color profile.
* An optional 'ANIM' chunk with animation control data. _\[status: experimental\]_ * An optional 'ANIM' chunk with animation control data.
* Image data. * Image data.
* An optional 'EXIF' chunk with EXIF metadata. _\[status: experimental\]_ * An optional 'EXIF' chunk with EXIF metadata.
* An optional 'XMP ' chunk with XMP metadata. _\[status: experimental\]_ * An optional 'XMP ' chunk with XMP metadata.
* An optional list of [unknown chunks](#unknown-chunks). _\[status: experimental\]_ * An optional list of [unknown chunks](#unknown-chunks). _\[status: experimental\]_
@ -325,7 +313,7 @@ Reserved (Rsv): 2 bits
: SHOULD be `0`. : SHOULD be `0`.
ICC profile (I): 1 bit _\[status: experimental\]_ ICC profile (I): 1 bit
: Set if the file contains an ICC profile. : Set if the file contains an ICC profile.
@ -334,15 +322,15 @@ Alpha (L): 1 bit
: Set if any of the frames of the image contain transparency information : Set if any of the frames of the image contain transparency information
("alpha"). ("alpha").
EXIF metadata (E): 1 bit _\[status: experimental\]_ EXIF metadata (E): 1 bit
: Set if the file contains EXIF metadata. : Set if the file contains EXIF metadata.
XMP metadata (X): 1 bit _\[status: experimental\]_ XMP metadata (X): 1 bit
: Set if the file contains XMP metadata. : Set if the file contains XMP metadata.
Animation (A): 1 bit _\[status: experimental\]_ Animation (A): 1 bit
: Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be : Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be
used to control the animation. used to control the animation.
@ -371,11 +359,12 @@ Future specifications MAY add more fields.
### Chunks ### Chunks
#### Animation _\[status: experimental\]_ #### Animation
An animation is controlled by ANIM and ANMF chunks. An animation is controlled by ANIM and ANMF chunks.
ANIM Chunk: ANIM Chunk:
{:#anim_chunk}
For an animated image, this chunk contains the _global parameters_ of the For an animated image, this chunk contains the _global parameters_ of the
animation. animation.
@ -392,10 +381,14 @@ animation.
Background Color: 32 bits (_uint32_) Background Color: 32 bits (_uint32_)
: The background color of the canvas in \[Blue, Green, Red, Alpha\] byte order. : The default background color of the canvas in \[Blue, Green, Red, Alpha\]
The background color is the color used for those pixels of the canvas that are byte order. This color is used to fill the unused space on the canvas around the
not covered by a frame. Background color is also used when disposal method is frames, as well as the transparent pixels of the first frame. Background color
`1`. is also used when disposal method is `1`.
**Note**: Viewers that have a preferred background against which to present the
images (web browsers, for example) should ignore this value and use their
preferred background color instead.
Loop Count: 16 bits (_uint16_) Loop Count: 16 bits (_uint16_)
@ -457,14 +450,45 @@ Reserved: 7 bits
Disposal method (D): 1 bit Disposal method (D): 1 bit
: Indicates how the area used by this frame is to be treated before rendering : Indicates how _the current frame_ is to be treated after it has been displayed
the next frame on canvas: (before rendering the next frame) on the canvas:
* `0`: Do not dispose. Keep the area used by this frame as it is and render * `0`: Do not dispose. Leave the canvas as is.
the next frame on top of it.
* `1`: Dispose to background color (also part of this chunk). Restore the * `1`: Dispose to background color. Fill the _rectangle_ on the canvas covered
area used by this frame to background color before rendering the next frame. by the _current frame_ with background color specified in the
[ANIM chunk](#anim_chunk).
After disposing the current frame, render the next frame on the canvas using
[alpha-blending](#alpha-blending). If the next frame does not have an alpha
channel, assume alpha value of 255, effectively replacing the rectangle.
**Notes**:
* The frame disposal only applies to the _frame rectangle_, that is, the
rectangle defined by _Frame X_, _Frame Y_, _frame width_ and _frame height_.
It may or may not cover the whole canvas.
{:#alpha-blending}
* **Alpha-blending**:
Given that each of the R, G, B and A channels is 8-bit, and the RGB
channels are _not premultiplied_ by alpha, the formula for blending
'dst' onto 'src' is:
~~~~~
blend.A = src.A + dst.A * (1 - src.A / 255)
if blend.A = 0 then
blend.RGB = 0
else
blend.RGB = (src.RGB * src.A +
dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
~~~~~
* Alpha-blending SHOULD be done in linear color space, by taking into account
the [color profile](#color-profile) of the image. If the color profile is
not present, sRGB is to be assumed. (Note that sRGB also needs to be
linearized due to a gamma of ~2.2).
Frame Data: _Chunk Size_ - `16` bytes Frame Data: _Chunk Size_ - `16` bytes
@ -478,6 +502,9 @@ Frame Data: _Chunk Size_ - `16` bytes
* An optional list of [unknown chunks](#unknown-chunks). * An optional list of [unknown chunks](#unknown-chunks).
**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual
_padded_ chunks as described by the [RIFF file format](#riff-file-format).
#### Fragments _\[status: experimental\]_ #### Fragments _\[status: experimental\]_
For images that are represented by fragments, this chunk contains data for For images that are represented by fragments, this chunk contains data for
@ -644,7 +671,7 @@ The formats of VP8 and VP8L chunks are as described in sections
[Simple file format (lossy)](#simple-file-format-lossy) [Simple file format (lossy)](#simple-file-format-lossy)
and [Simple file format (lossless)](#simple-file-format-lossless) respectively. and [Simple file format (lossless)](#simple-file-format-lossless) respectively.
#### Color profile _\[status: experimental\]_ #### Color profile
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@ -666,7 +693,7 @@ See the [ICC Specification][iccspec] for details.
If this chunk is not present, sRGB SHOULD be assumed. If this chunk is not present, sRGB SHOULD be assumed.
#### Metadata _\[status: experimental\]_ #### Metadata
Metadata can be stored in 'EXIF' or 'XMP ' chunks. Metadata can be stored in 'EXIF' or 'XMP ' chunks.
@ -727,14 +754,14 @@ A file MAY contain unknown chunks:
Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their
original order (unless they specifically intend to modify these chunks). original order (unless they specifically intend to modify these chunks).
### Assembling the Canvas from fragments/frames _\[status: experimental\]_ ### Assembling the Canvas from fragments/frames
Here we provide an overview of how a reader should assemble a canvas in case Here we provide an overview of how a reader should assemble a canvas in case
of a fragmented-image and in case of an animated image. The notation of a fragmented-image and in case of an animated image. The notation
_VP8X.field_ means the field in the 'VP8X' chunk with the same description. _VP8X.field_ means the field in the 'VP8X' chunk with the same description.
Displaying a _fragmented image_ canvas MUST be equivalent to the following Displaying a _fragmented image_ canvas MUST be equivalent to the following
pseudocode: pseudocode: _\[status: experimental\]_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assert VP8X.flags.hasFragments assert VP8X.flags.hasFragments

View File

@ -11,9 +11,7 @@ endif
noinst_LTLIBRARIES = libexampleutil.la noinst_LTLIBRARIES = libexampleutil.la
libexampleutil_la_SOURCES = example_util.c libexampleutil_la_SOURCES = example_util.c example_util.h
libexampleutilinclude_HEADERS = example_util.h
libexampleutilincludedir =
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)

View File

@ -366,14 +366,30 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
enum { enum {
METADATA_EXIF = (1 << 0), METADATA_EXIF = (1 << 0),
METADATA_ICCP = (1 << 1), METADATA_ICC = (1 << 1),
METADATA_XMP = (1 << 2), METADATA_XMP = (1 << 2),
METADATA_ALL = METADATA_EXIF | METADATA_ICCP | METADATA_XMP METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP
}; };
static const int kChunkHeaderSize = 8; static const int kChunkHeaderSize = 8;
static const int kTagSize = 4; static const int kTagSize = 4;
static void PrintMetadataInfo(const Metadata* const metadata,
int metadata_written) {
if (metadata == NULL || metadata_written == 0) return;
fprintf(stderr, "Metadata:\n");
if (metadata_written & METADATA_ICC) {
fprintf(stderr, " * ICC profile: %6d bytes\n", (int)metadata->iccp.size);
}
if (metadata_written & METADATA_EXIF) {
fprintf(stderr, " * EXIF data: %6d bytes\n", (int)metadata->exif.size);
}
if (metadata_written & METADATA_XMP) {
fprintf(stderr, " * XMP data: %6d bytes\n", (int)metadata->xmp.size);
}
}
// Outputs, in little endian, 'num' bytes from 'val' to 'out'. // Outputs, in little endian, 'num' bytes from 'val' to 'out'.
static int WriteLE(FILE* const out, uint32_t val, int num) { static int WriteLE(FILE* const out, uint32_t val, int num) {
uint8_t buf[4]; uint8_t buf[4];
@ -424,7 +440,8 @@ static int WriteWebPWithMetadata(FILE* const out,
const WebPPicture* const picture, const WebPPicture* const picture,
const WebPMemoryWriter* const memory_writer, const WebPMemoryWriter* const memory_writer,
const Metadata* const metadata, const Metadata* const metadata,
int keep_metadata) { int keep_metadata,
int* const metadata_written) {
const char kVP8XHeader[] = "VP8X\x0a\x00\x00\x00"; const char kVP8XHeader[] = "VP8X\x0a\x00\x00\x00";
const int kAlphaFlag = 0x10; const int kAlphaFlag = 0x10;
const int kEXIFFlag = 0x08; const int kEXIFFlag = 0x08;
@ -439,13 +456,16 @@ static int WriteWebPWithMetadata(FILE* const out,
!!(keep_metadata & METADATA_EXIF), !!(keep_metadata & METADATA_EXIF),
kEXIFFlag, &flags, &metadata_size); kEXIFFlag, &flags, &metadata_size);
const int write_iccp = UpdateFlagsAndSize(&metadata->iccp, const int write_iccp = UpdateFlagsAndSize(&metadata->iccp,
!!(keep_metadata & METADATA_ICCP), !!(keep_metadata & METADATA_ICC),
kICCPFlag, &flags, &metadata_size); kICCPFlag, &flags, &metadata_size);
const int write_xmp = UpdateFlagsAndSize(&metadata->xmp, const int write_xmp = UpdateFlagsAndSize(&metadata->xmp,
!!(keep_metadata & METADATA_XMP), !!(keep_metadata & METADATA_XMP),
kXMPFlag, &flags, &metadata_size); kXMPFlag, &flags, &metadata_size);
uint8_t* webp = memory_writer->mem; uint8_t* webp = memory_writer->mem;
size_t webp_size = memory_writer->size; size_t webp_size = memory_writer->size;
*metadata_written = 0;
if (webp_size < kMinSize) return 0; if (webp_size < kMinSize) return 0;
if (webp_size - kChunkHeaderSize + metadata_size > kMaxChunkPayload) { if (webp_size - kChunkHeaderSize + metadata_size > kMaxChunkPayload) {
fprintf(stderr, "Error! Addition of metadata would exceed " fprintf(stderr, "Error! Addition of metadata would exceed "
@ -482,11 +502,20 @@ static int WriteWebPWithMetadata(FILE* const out,
ok = ok && WriteLE24(out, picture->width - 1); ok = ok && WriteLE24(out, picture->width - 1);
ok = ok && WriteLE24(out, picture->height - 1); ok = ok && WriteLE24(out, picture->height - 1);
} }
if (write_iccp) ok = ok && WriteMetadataChunk(out, "ICCP", &metadata->iccp); if (write_iccp) {
ok = ok && WriteMetadataChunk(out, "ICCP", &metadata->iccp);
*metadata_written |= METADATA_ICC;
}
// Image // Image
ok = ok && (fwrite(webp, webp_size, 1, out) == 1); ok = ok && (fwrite(webp, webp_size, 1, out) == 1);
if (write_exif) ok = ok && WriteMetadataChunk(out, "EXIF", &metadata->exif); if (write_exif) {
if (write_xmp) ok = ok && WriteMetadataChunk(out, "XMP ", &metadata->xmp); ok = ok && WriteMetadataChunk(out, "EXIF", &metadata->exif);
*metadata_written |= METADATA_EXIF;
}
if (write_xmp) {
ok = ok && WriteMetadataChunk(out, "XMP ", &metadata->xmp);
*metadata_written |= METADATA_XMP;
}
return ok; return ok;
} else { } else {
// No metadata, just write the original image file. // No metadata, just write the original image file.
@ -575,7 +604,7 @@ static void HelpLong(void) {
printf(" "); printf(" ");
printf("copy from the input to the output if present.\n"); printf("copy from the input to the output if present.\n");
printf(" " printf(" "
"Valid values: all, none (default), exif, iccp, xmp\n"); "Valid values: all, none (default), exif, icc, xmp\n");
printf("\n"); printf("\n");
printf(" -short ................. condense printed message\n"); printf(" -short ................. condense printed message\n");
@ -631,6 +660,7 @@ int main(int argc, const char *argv[]) {
int resize_w = 0, resize_h = 0; int resize_w = 0, resize_h = 0;
int show_progress = 0; int show_progress = 0;
int keep_metadata = 0; int keep_metadata = 0;
int metadata_written = 0;
WebPPicture picture; WebPPicture picture;
int print_distortion = -1; // -1=off, 0=PSNR, 1=SSIM, 2=LSIM int print_distortion = -1; // -1=off, 0=PSNR, 1=SSIM, 2=LSIM
WebPPicture original_picture; // when PSNR or SSIM is requested WebPPicture original_picture; // when PSNR or SSIM is requested
@ -812,7 +842,7 @@ int main(int argc, const char *argv[]) {
{ "all", METADATA_ALL }, { "all", METADATA_ALL },
{ "none", 0 }, { "none", 0 },
{ "exif", METADATA_EXIF }, { "exif", METADATA_EXIF },
{ "iccp", METADATA_ICCP }, { "icc", METADATA_ICC },
{ "xmp", METADATA_XMP }, { "xmp", METADATA_XMP },
}; };
const size_t kNumTokens = sizeof(kTokens) / sizeof(kTokens[0]); const size_t kNumTokens = sizeof(kTokens) / sizeof(kTokens[0]);
@ -844,7 +874,7 @@ int main(int argc, const char *argv[]) {
start = token + 1; start = token + 1;
} }
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H
if (keep_metadata != 0 && keep_metadata != METADATA_ICCP) { if (keep_metadata != 0 && keep_metadata != METADATA_ICC) {
// TODO(jzern): remove when -metadata is supported on all platforms. // TODO(jzern): remove when -metadata is supported on all platforms.
fprintf(stderr, "Warning: only ICC profile extraction is currently" fprintf(stderr, "Warning: only ICC profile extraction is currently"
" supported on this platform!\n"); " supported on this platform!\n");
@ -978,7 +1008,7 @@ int main(int argc, const char *argv[]) {
if (keep_metadata != 0 && out != NULL) { if (keep_metadata != 0 && out != NULL) {
if (!WriteWebPWithMetadata(out, &picture, &memory_writer, if (!WriteWebPWithMetadata(out, &picture, &memory_writer,
&metadata, keep_metadata)) { &metadata, keep_metadata, &metadata_written)) {
fprintf(stderr, "Error writing WebP file with metadata!\n"); fprintf(stderr, "Error writing WebP file with metadata!\n");
goto Error; goto Error;
} }
@ -990,6 +1020,9 @@ int main(int argc, const char *argv[]) {
} else { } else {
PrintExtraInfoLossy(&picture, short_output, config.low_memory, in_file); PrintExtraInfoLossy(&picture, short_output, config.low_memory, in_file);
} }
if (!short_output) {
PrintMetadataInfo(&metadata, metadata_written);
}
} }
if (!quiet && !short_output && print_distortion >= 0) { // print distortion if (!quiet && !short_output && print_distortion >= 0) { // print distortion
static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" }; static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" };

View File

@ -460,6 +460,13 @@ int main(int argc, const char *argv[]) {
goto end; goto end;
} }
if (bitstream->has_animation) {
fprintf(stderr,
"Error! Decoding of an animated WebP file is not supported.\n"
" Use webpmux to extract the individual frames or\n"
" vwebp to view this image.\n");
}
switch (format) { switch (format) {
case PNG: case PNG:
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H

View File

@ -44,8 +44,8 @@ int ExUtilReadFile(const char* const file_name,
fclose(in); fclose(in);
if (!ok) { if (!ok) {
fprintf(stderr, "Could not read %zu bytes of data from file %s\n", fprintf(stderr, "Could not read %d bytes of data from file %s\n",
file_size, file_name); (int)file_size, file_name);
free(file_data); free(file_data);
return 0; return 0;
} }

View File

@ -117,36 +117,42 @@ static int ReadSubImage(GifFileType* gif, WebPPicture* pic, WebPPicture* view) {
return ok; return ok;
} }
static int GetColorFromIndex(const ColorMapObject* const color_map, GifWord idx, static int GetBackgroundColor(const ColorMapObject* const color_map,
uint32_t* const argb) { GifWord bgcolor_idx, uint32_t* const bgcolor) {
assert(color_map != NULL && color_map->Colors != NULL); if (transparent_index != -1 && bgcolor_idx == transparent_index) {
if (idx >= color_map->ColorCount) { *bgcolor = TRANSPARENT_COLOR; // Special case.
return 0; // Invalid index. return 1;
} else if (color_map == NULL || color_map->Colors == NULL
|| bgcolor_idx >= color_map->ColorCount) {
return 0; // Invalid color map or index.
} else { } else {
const GifColorType color = color_map->Colors[idx]; const GifColorType color = color_map->Colors[bgcolor_idx];
*argb = (0xff << 24) *bgcolor = (0xff << 24)
| (color.Red << 16) | (color.Red << 16)
| (color.Green << 8) | (color.Green << 8)
| (color.Blue << 0); | (color.Blue << 0);
return 1; return 1;
} }
} }
static void DisplayGifError(const GifFileType* const gif) { static void DisplayGifError(const GifFileType* const gif, int gif_error) {
// GIFLIB_MAJOR is only defined in libgif >= 4.2.0. // GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
// libgif 4.2.0 has retired PrintGifError() and added GifErrorString(). // libgif 4.2.0 has retired PrintGifError() and added GifErrorString().
#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) && \ #if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) && \
((GIFLIB_MAJOR == 4 && GIFLIB_MINOR >= 2) || GIFLIB_MAJOR > 4) ((GIFLIB_MAJOR == 4 && GIFLIB_MINOR >= 2) || GIFLIB_MAJOR > 4)
#if GIFLIB_MAJOR >= 5 #if GIFLIB_MAJOR >= 5
// Static string actually, hence the const char* cast. // Static string actually, hence the const char* cast.
const char* error_str = (const char*)GifErrorString(gif->Error); const char* error_str = (const char*)GifErrorString(
(gif == NULL) ? gif_error : gif->Error);
#else #else
const char* error_str = (const char*)GifErrorString(); const char* error_str = (const char*)GifErrorString();
(void)gif;
#endif #endif
if (error_str == NULL) error_str = "Unknown error"; if (error_str == NULL) error_str = "Unknown error";
fprintf(stderr, "GIFLib Error: %s\n", error_str); fprintf(stderr, "GIFLib Error %d: %s\n", gif_error, error_str);
#else #else
fprintf(stderr, "GIFLib Error: "); (void)gif;
fprintf(stderr, "GIFLib Error %d: ", gif_error);
PrintGifError(); PrintGifError();
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #endif
@ -184,7 +190,7 @@ static void Help(void) {
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
int verbose = 0; int verbose = 0;
int gif_error = -1; int gif_error = GIF_ERROR;
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
int ok = 0; int ok = 0;
const char *in_file = NULL, *out_file = NULL; const char *in_file = NULL, *out_file = NULL;
@ -196,6 +202,7 @@ int main(int argc, const char *argv[]) {
WebPMuxFrameInfo frame; WebPMuxFrameInfo frame;
WebPMuxAnimParams anim = { WHITE_COLOR, 0 }; WebPMuxAnimParams anim = { WHITE_COLOR, 0 };
int is_first_frame = 1;
int done; int done;
int c; int c;
int quiet = 0; int quiet = 0;
@ -280,14 +287,6 @@ int main(int argc, const char *argv[]) {
picture.custom_ptr = &memory; picture.custom_ptr = &memory;
if (!WebPPictureAlloc(&picture)) goto End; if (!WebPPictureAlloc(&picture)) goto End;
if (gif->SColorMap != NULL &&
!GetColorFromIndex(gif->SColorMap, gif->SBackGroundColor,
&anim.bgcolor)) {
fprintf(stderr, "GIF decode warning: invalid background color index. "
"Assuming white background.\n");
}
ClearPicture(&picture, anim.bgcolor);
mux = WebPMuxNew(); mux = WebPMuxNew();
if (mux == NULL) { if (mux == NULL) {
fprintf(stderr, "ERROR: could not create a mux object.\n"); fprintf(stderr, "ERROR: could not create a mux object.\n");
@ -340,11 +339,11 @@ int main(int argc, const char *argv[]) {
goto End; goto End;
} }
if (verbose) { if (verbose) {
fprintf(stderr, "Added frame %dx%d (offset:%d,%d duration:%d) ", printf("Added frame %dx%d (offset:%d,%d duration:%d) ",
view.width, view.height, frame.x_offset, frame.y_offset, view.width, view.height, frame.x_offset, frame.y_offset,
frame.duration); frame.duration);
fprintf(stderr, "dispose:%d transparent index:%d\n", printf("dispose:%d transparent index:%d\n",
frame.dispose_method, transparent_index); frame.dispose_method, transparent_index);
} }
WebPDataClear(&frame.bitstream); WebPDataClear(&frame.bitstream);
break; break;
@ -376,6 +375,15 @@ int main(int argc, const char *argv[]) {
: WEBP_MUX_DISPOSE_NONE; : WEBP_MUX_DISPOSE_NONE;
} }
transparent_index = (flags & GIF_TRANSPARENT_MASK) ? data[4] : -1; transparent_index = (flags & GIF_TRANSPARENT_MASK) ? data[4] : -1;
if (is_first_frame) {
if (!GetBackgroundColor(gif->SColorMap, gif->SBackGroundColor,
&anim.bgcolor)) {
fprintf(stderr, "GIF decode warning: invalid background color "
"index. Assuming white background.\n");
}
ClearPicture(&picture, anim.bgcolor);
is_first_frame = 0;
}
break; break;
} }
case PLAINTEXT_EXT_FUNC_CODE: { case PLAINTEXT_EXT_FUNC_CODE: {
@ -389,7 +397,7 @@ int main(int argc, const char *argv[]) {
if (data == NULL) goto End; // Loop count sub-block missing. if (data == NULL) goto End; // Loop count sub-block missing.
if (data[0] != 3 && data[1] != 1) break; // wrong size/marker if (data[0] != 3 && data[1] != 1) break; // wrong size/marker
anim.loop_count = data[2] | (data[3] << 8); anim.loop_count = data[2] | (data[3] << 8);
if (verbose) fprintf(stderr, "Loop count: %d\n", anim.loop_count); if (verbose) printf("Loop count: %d\n", anim.loop_count);
} else if (!memcmp(data + 1, "XMP dataXMP", 11)) { } else if (!memcmp(data + 1, "XMP dataXMP", 11)) {
// Read XMP metadata. // Read XMP metadata.
WebPData xmp; WebPData xmp;
@ -398,7 +406,7 @@ int main(int argc, const char *argv[]) {
xmp.bytes = (uint8_t*)data; xmp.bytes = (uint8_t*)data;
xmp.size = data[0] + 1; xmp.size = data[0] + 1;
WebPMuxSetChunk(mux, "XMP ", &xmp, 1); WebPMuxSetChunk(mux, "XMP ", &xmp, 1);
if (verbose) fprintf(stderr, "XMP size: %zu\n", xmp.size); if (verbose) printf("XMP size: %d\n", (int)xmp.size);
} else if (!memcmp(data + 1, "ICCRGBG1012", 11)) { } else if (!memcmp(data + 1, "ICCRGBG1012", 11)) {
// Read ICC profile. // Read ICC profile.
WebPData icc; WebPData icc;
@ -407,7 +415,7 @@ int main(int argc, const char *argv[]) {
icc.bytes = (uint8_t*)data; icc.bytes = (uint8_t*)data;
icc.size = data[0] + 1; icc.size = data[0] + 1;
WebPMuxSetChunk(mux, "ICCP", &icc, 1); WebPMuxSetChunk(mux, "ICCP", &icc, 1);
if (verbose) fprintf(stderr, "ICC size: %zu\n", icc.size); if (verbose) printf("ICC size: %d\n", (int)icc.size);
} }
break; break;
} }
@ -451,12 +459,18 @@ int main(int argc, const char *argv[]) {
fprintf(stderr, "Error writing output file: %s\n", out_file); fprintf(stderr, "Error writing output file: %s\n", out_file);
goto End; goto End;
} }
if (!quiet) fprintf(stderr, "Saved output file: %s\n", out_file); if (!quiet) {
printf("Saved output file: %s\n", out_file);
}
} else {
if (!quiet) {
printf("Nothing written; use -o flag to save the result.\n");
}
} }
// All OK. // All OK.
ok = 1; ok = 1;
gif_error = 0; gif_error = GIF_OK;
End: End:
WebPDataClear(&webp_data); WebPDataClear(&webp_data);
@ -464,8 +478,8 @@ int main(int argc, const char *argv[]) {
WebPPictureFree(&picture); WebPPictureFree(&picture);
if (out != NULL && out_file != NULL) fclose(out); if (out != NULL && out_file != NULL) fclose(out);
if (gif_error != 0) { if (gif_error != GIF_OK) {
DisplayGifError(gif); DisplayGifError(gif, gif_error);
} }
if (gif != NULL) { if (gif != NULL) {
DGifCloseFile(gif); DGifCloseFile(gif);

View File

@ -79,9 +79,9 @@ static int StoreICCP(j_decompress_ptr dinfo, MetadataPayload* const iccp) {
ICCPSegment* segment; ICCPSegment* segment;
if (segment_size == 0 || count == 0 || seq == 0) { if (segment_size == 0 || count == 0 || seq == 0) {
fprintf(stderr, "[ICCP] size (%zu) / count (%d) / sequence number (%d)" fprintf(stderr, "[ICCP] size (%d) / count (%d) / sequence number (%d)"
" cannot be 0!\n", " cannot be 0!\n",
segment_size, seq, count); (int)segment_size, seq, count);
return 0; return 0;
} }

View File

@ -8,7 +8,7 @@
// Simple WebP file viewer. // Simple WebP file viewer.
// //
// Compiling on linux: // Compiling on linux:
// sudo apt-get install libglut3-dev mesa-common-dev // sudo apt-get install freeglut3-dev mesa-common-dev
// gcc -o vwebp vwebp.c -O3 -lwebp -lwebpmux -lglut -lGL -lpthread -lm // gcc -o vwebp vwebp.c -O3 -lwebp -lwebpmux -lglut -lGL -lpthread -lm
// Compiling on Mac + XCode: // Compiling on Mac + XCode:
// gcc -o vwebp vwebp.c -lwebp -lwebpmux -framework GLUT -framework OpenGL // gcc -o vwebp vwebp.c -lwebp -lwebpmux -framework GLUT -framework OpenGL
@ -19,9 +19,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "webp/decode.h"
#include "webp/demux.h"
#ifdef __APPLE__ #ifdef __APPLE__
#include <GLUT/glut.h> #include <GLUT/glut.h>
#else #else
@ -31,6 +28,13 @@
#endif #endif
#endif #endif
#ifdef WEBP_HAVE_QCMS
#include <qcms.h>
#endif
#include "webp/decode.h"
#include "webp/demux.h"
#include "./example_util.h" #include "./example_util.h"
#ifdef _MSC_VER #ifdef _MSC_VER
@ -42,9 +46,11 @@ static void Help(void);
// Unfortunate global variables. Gathered into a struct for comfort. // Unfortunate global variables. Gathered into a struct for comfort.
static struct { static struct {
int has_animation; int has_animation;
int has_color_profile;
int done; int done;
int decoding_error; int decoding_error;
int print_info; int print_info;
int use_color_profile;
int canvas_width, canvas_height; int canvas_width, canvas_height;
int loop_count; int loop_count;
@ -56,6 +62,12 @@ static struct {
const WebPDecBuffer* pic; const WebPDecBuffer* pic;
WebPDemuxer* dmux; WebPDemuxer* dmux;
WebPIterator frameiter; WebPIterator frameiter;
struct {
int width, height;
int x_offset, y_offset;
enum WebPMuxAnimDispose dispose_method;
} prev_frame;
WebPChunkIterator iccp;
} kParams; } kParams;
static void ClearPreviousPic(void) { static void ClearPreviousPic(void) {
@ -67,10 +79,128 @@ static void ClearParams(void) {
ClearPreviousPic(); ClearPreviousPic();
WebPDataClear(&kParams.data); WebPDataClear(&kParams.data);
WebPDemuxReleaseIterator(&kParams.frameiter); WebPDemuxReleaseIterator(&kParams.frameiter);
WebPDemuxReleaseChunkIterator(&kParams.iccp);
WebPDemuxDelete(kParams.dmux); WebPDemuxDelete(kParams.dmux);
kParams.dmux = NULL; kParams.dmux = NULL;
} }
// -----------------------------------------------------------------------------
// Color profile handling
static int ApplyColorProfile(const WebPData* const profile,
WebPDecBuffer* const rgba) {
#ifdef WEBP_HAVE_QCMS
int i, ok = 0;
uint8_t* line;
uint8_t major_revision;
qcms_profile* input_profile = NULL;
qcms_profile* output_profile = NULL;
qcms_transform* transform = NULL;
const qcms_data_type input_type = QCMS_DATA_RGBA_8;
const qcms_data_type output_type = QCMS_DATA_RGBA_8;
const qcms_intent intent = QCMS_INTENT_DEFAULT;
if (profile == NULL || rgba == NULL) return 0;
if (profile->bytes == NULL || profile->size < 10) return 1;
major_revision = profile->bytes[8];
qcms_enable_iccv4();
input_profile = qcms_profile_from_memory(profile->bytes, profile->size);
// qcms_profile_is_bogus() is broken with ICCv4.
if (input_profile == NULL ||
(major_revision < 4 && qcms_profile_is_bogus(input_profile))) {
fprintf(stderr, "Color profile is bogus!\n");
goto Error;
}
output_profile = qcms_profile_sRGB();
if (output_profile == NULL) {
fprintf(stderr, "Error creating output color profile!\n");
goto Error;
}
qcms_profile_precache_output_transform(output_profile);
transform = qcms_transform_create(input_profile, input_type,
output_profile, output_type,
intent);
if (transform == NULL) {
fprintf(stderr, "Error creating color transform!\n");
goto Error;
}
line = rgba->u.RGBA.rgba;
for (i = 0; i < rgba->height; ++i, line += rgba->u.RGBA.stride) {
qcms_transform_data(transform, line, line, rgba->width);
}
ok = 1;
Error:
if (input_profile != NULL) qcms_profile_release(input_profile);
if (output_profile != NULL) qcms_profile_release(output_profile);
if (transform != NULL) qcms_transform_release(transform);
return ok;
#else
(void)profile;
(void)rgba;
return 1;
#endif // WEBP_HAVE_QCMS
}
//------------------------------------------------------------------------------
// File decoding
static int Decode(void) { // Fills kParams.frameiter
const WebPIterator* const iter = &kParams.frameiter;
WebPDecoderConfig* const config = kParams.config;
WebPDecBuffer* const output_buffer = &config->output;
int ok = 0;
ClearPreviousPic();
output_buffer->colorspace = MODE_RGBA;
ok = (WebPDecode(iter->fragment.bytes, iter->fragment.size,
config) == VP8_STATUS_OK);
if (!ok) {
fprintf(stderr, "Decoding of frame #%d failed!\n", iter->frame_num);
} else {
kParams.pic = output_buffer;
if (kParams.use_color_profile) {
ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer);
if (!ok) {
fprintf(stderr, "Applying color profile to frame #%d failed!\n",
iter->frame_num);
}
}
}
return ok;
}
static void decode_callback(int what) {
if (what == 0 && !kParams.done) {
int duration = 0;
if (kParams.dmux != NULL) {
WebPIterator* const iter = &kParams.frameiter;
if (!WebPDemuxNextFrame(iter)) {
WebPDemuxReleaseIterator(iter);
if (WebPDemuxGetFrame(kParams.dmux, 1, iter)) {
--kParams.loop_count;
kParams.done = (kParams.loop_count == 0);
} else {
kParams.decoding_error = 1;
kParams.done = 1;
return;
}
}
duration = iter->duration;
}
if (!Decode()) {
kParams.decoding_error = 1;
kParams.done = 1;
} else {
glutPostRedisplay();
glutTimerFunc(duration, decode_callback, what);
}
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Callbacks // Callbacks
@ -84,6 +214,24 @@ static void HandleKey(unsigned char key, int pos_x, int pos_y) {
ClearParams(); ClearParams();
exit(0); exit(0);
#endif #endif
} else if (key == 'c') {
if (kParams.has_color_profile && !kParams.decoding_error) {
kParams.use_color_profile = 1 - kParams.use_color_profile;
if (kParams.has_animation) {
// Restart the completed animation to pickup the color profile change.
if (kParams.done && kParams.loop_count == 0) {
kParams.loop_count =
(int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT) + 1;
kParams.done = 0;
// Start the decode loop immediately.
glutTimerFunc(0, decode_callback, 0);
}
} else {
Decode();
glutPostRedisplay();
}
}
} else if (key == 'i') { } else if (key == 'i') {
kParams.print_info = 1 - kParams.print_info; kParams.print_info = 1 - kParams.print_info;
glutPostRedisplay(); glutPostRedisplay();
@ -141,24 +289,46 @@ static void HandleDisplay(void) {
glPixelZoom(1, -1); glPixelZoom(1, -1);
xoff = (GLfloat)(2. * iter->x_offset / kParams.canvas_width); xoff = (GLfloat)(2. * iter->x_offset / kParams.canvas_width);
yoff = (GLfloat)(2. * iter->y_offset / kParams.canvas_height); yoff = (GLfloat)(2. * iter->y_offset / kParams.canvas_height);
glRasterPos2f(-1. + xoff, 1. - 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 (iter->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
if (kParams.prev_frame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
// 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).
const int window_x = kParams.prev_frame.x_offset;
const int window_y = kParams.canvas_height -
kParams.prev_frame.y_offset -
kParams.prev_frame.height;
glEnable(GL_SCISSOR_TEST);
// Only updated the requested area, not the whole canvas.
glScissor(window_x, window_y,
kParams.prev_frame.width, kParams.prev_frame.height);
glClear(GL_COLOR_BUFFER_BIT); // use clear color glClear(GL_COLOR_BUFFER_BIT); // use clear color
DrawCheckerBoard();
glDisable(GL_SCISSOR_TEST);
} }
kParams.prev_frame.width = iter->width;
kParams.prev_frame.height = iter->height;
kParams.prev_frame.x_offset = iter->x_offset;
kParams.prev_frame.y_offset = iter->y_offset;
kParams.prev_frame.dispose_method = iter->dispose_method;
glDrawPixels(pic->width, pic->height, glDrawPixels(pic->width, pic->height,
GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA, GL_UNSIGNED_BYTE,
(GLvoid*)pic->u.RGBA.rgba); (GLvoid*)pic->u.RGBA.rgba);
if (kParams.print_info) { if (kParams.print_info) {
char tmp[32]; char tmp[32];
glColor4f(0.90, 0.0, 0.90, 1.0); glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
glRasterPos2f(-0.95f, 0.90f); glRasterPos2f(-0.95f, 0.90f);
PrintString(kParams.file_name); PrintString(kParams.file_name);
snprintf(tmp, sizeof(tmp), "Dimension:%d x %d", pic->width, pic->height); snprintf(tmp, sizeof(tmp), "Dimension:%d x %d", pic->width, pic->height);
glColor4f(0.90, 0.0, 0.90, 1.0); glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
glRasterPos2f(-0.95f, 0.80f); glRasterPos2f(-0.95f, 0.80f);
PrintString(tmp); PrintString(tmp);
if (iter->x_offset != 0 || iter->y_offset != 0) { if (iter->x_offset != 0 || iter->y_offset != 0) {
@ -192,55 +362,6 @@ static void StartDisplay(void) {
DrawCheckerBoard(); DrawCheckerBoard();
} }
//------------------------------------------------------------------------------
// File decoding
static int Decode(void) { // Fills kParams.frameiter
const WebPIterator* const iter = &kParams.frameiter;
WebPDecoderConfig* const config = kParams.config;
WebPDecBuffer* const output_buffer = &config->output;
int ok = 0;
ClearPreviousPic();
output_buffer->colorspace = MODE_RGBA;
ok = (WebPDecode(iter->fragment.bytes, iter->fragment.size,
config) == VP8_STATUS_OK);
if (!ok) {
fprintf(stderr, "Decoding of frame #%d failed!\n", iter->frame_num);
} else {
kParams.pic = output_buffer;
}
return ok;
}
static void decode_callback(int what) {
if (what == 0 && !kParams.done) {
int duration = 0;
if (kParams.dmux != NULL) {
WebPIterator* const iter = &kParams.frameiter;
if (!WebPDemuxNextFrame(iter)) {
WebPDemuxReleaseIterator(iter);
if (WebPDemuxGetFrame(kParams.dmux, 1, iter)) {
--kParams.loop_count;
kParams.done = (kParams.loop_count == 0);
} else {
kParams.decoding_error = 1;
kParams.done = 1;
return;
}
}
duration = iter->duration;
}
if (!Decode()) {
kParams.decoding_error = 1;
kParams.done = 1;
} else {
glutPostRedisplay();
glutTimerFunc(duration, decode_callback, what);
}
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main // Main
@ -249,6 +370,7 @@ static void Help(void) {
"Decodes the WebP image file and visualize it using OpenGL\n" "Decodes the WebP image file and visualize it using OpenGL\n"
"Options are:\n" "Options are:\n"
" -version .... print version number and exit.\n" " -version .... print version number and exit.\n"
" -noicc ....... don't use the icc profile if present.\n"
" -nofancy ..... don't use the fancy YUV420 upscaler.\n" " -nofancy ..... don't use the fancy YUV420 upscaler.\n"
" -nofilter .... disable in-loop filtering.\n" " -nofilter .... disable in-loop filtering.\n"
" -mt .......... use multi-threading.\n" " -mt .......... use multi-threading.\n"
@ -256,6 +378,7 @@ static void Help(void) {
" -h ....... this help message.\n" " -h ....... this help message.\n"
"\n" "\n"
"Keyboard shortcuts:\n" "Keyboard shortcuts:\n"
" 'c' ................ toggle use of color profile.\n"
" 'i' ................ overlay file information.\n" " 'i' ................ overlay file information.\n"
" 'q' / 'Q' / ESC .... quit.\n" " 'q' / 'Q' / ESC .... quit.\n"
); );
@ -270,11 +393,14 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
kParams.config = &config; kParams.config = &config;
kParams.use_color_profile = 1;
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
return 0; return 0;
} else if (!strcmp(argv[c], "-noicc")) {
kParams.use_color_profile = 0;
} else if (!strcmp(argv[c], "-nofancy")) { } else if (!strcmp(argv[c], "-nofancy")) {
config.options.no_fancy_upsampling = 1; config.options.no_fancy_upsampling = 1;
} else if (!strcmp(argv[c], "-nofilter")) { } else if (!strcmp(argv[c], "-nofilter")) {
@ -327,6 +453,25 @@ int main(int argc, char *argv[]) {
printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height); printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height);
} }
kParams.prev_frame.width = kParams.canvas_width;
kParams.prev_frame.height = kParams.canvas_height;
kParams.prev_frame.x_offset = kParams.prev_frame.y_offset = 0;
kParams.prev_frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
memset(&kParams.iccp, 0, sizeof(kParams.iccp));
kParams.has_color_profile =
!!(WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & ICCP_FLAG);
if (kParams.has_color_profile) {
#ifdef WEBP_HAVE_QCMS
if (!WebPDemuxGetChunk(kParams.dmux, "ICCP", 1, &kParams.iccp)) goto Error;
printf("VP8X: Found color profile\n");
#else
fprintf(stderr, "Warning: color profile present, but qcms is unavailable!\n"
"Build libqcms from Mozilla or Chromium and define WEBP_HAVE_QCMS "
"before building.\n");
#endif
}
if (!WebPDemuxGetFrame(kParams.dmux, 1, &kParams.frameiter)) goto Error; if (!WebPDemuxGetFrame(kParams.dmux, 1, &kParams.frameiter)) goto Error;
kParams.has_animation = (kParams.frameiter.num_frames > 1); kParams.has_animation = (kParams.frameiter.num_frames > 1);

View File

@ -17,12 +17,6 @@
/* Usage examples: /* Usage examples:
Create container WebP file: Create container WebP file:
webpmux -frgm fragment_1.webp +0+0 \
-frgm fragment_2.webp +960+0 \
-frgm fragment_3.webp +0+576 \
-frgm fragment_4.webp +960+576 \
-o out_fragment_container.webp
webpmux -frame anim_1.webp +100+10+10 \ webpmux -frame anim_1.webp +100+10+10 \
-frame anim_2.webp +100+25+25+1 \ -frame anim_2.webp +100+25+25+1 \
-frame anim_3.webp +100+50+50+1 \ -frame anim_3.webp +100+50+50+1 \
@ -52,6 +46,10 @@
webpmux -version webpmux -version
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -185,6 +183,9 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
uint32_t flag; uint32_t flag;
WebPMuxError err = WebPMuxGetFeatures(mux, &flag); WebPMuxError err = WebPMuxGetFeatures(mux, &flag);
#ifndef WEBP_EXPERIMENTAL_FEATURES
if (flag & FRAGMENTS_FLAG) err = WEBP_MUX_INVALID_ARGUMENT;
#endif
RETURN_IF_ERROR("Failed to retrieve features\n"); RETURN_IF_ERROR("Failed to retrieve features\n");
if (flag == 0) { if (flag == 0) {
@ -196,7 +197,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
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 & 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");
@ -231,7 +232,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i); RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i);
printf("%3d: %8d %8d ", i, frame.x_offset, frame.y_offset); printf("%3d: %8d %8d ", i, frame.x_offset, frame.y_offset);
if (is_anim) printf("%8d %7d ", frame.duration, frame.dispose_method); if (is_anim) printf("%8d %7d ", frame.duration, frame.dispose_method);
printf("%10zu\n", frame.bitstream.size); printf("%10d\n", (int)frame.bitstream.size);
WebPDataClear(&frame.bitstream); WebPDataClear(&frame.bitstream);
} }
} }
@ -241,28 +242,28 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
WebPData icc_profile; WebPData icc_profile;
err = WebPMuxGetChunk(mux, "ICCP", &icc_profile); err = WebPMuxGetChunk(mux, "ICCP", &icc_profile);
RETURN_IF_ERROR("Failed to retrieve the ICC profile\n"); RETURN_IF_ERROR("Failed to retrieve the ICC profile\n");
printf("Size of the ICC profile data: %zu\n", icc_profile.size); printf("Size of the ICC profile data: %d\n", (int)icc_profile.size);
} }
if (flag & EXIF_FLAG) { if (flag & EXIF_FLAG) {
WebPData exif; WebPData exif;
err = WebPMuxGetChunk(mux, "EXIF", &exif); err = WebPMuxGetChunk(mux, "EXIF", &exif);
RETURN_IF_ERROR("Failed to retrieve the EXIF metadata\n"); RETURN_IF_ERROR("Failed to retrieve the EXIF metadata\n");
printf("Size of the EXIF metadata: %zu\n", exif.size); printf("Size of the EXIF metadata: %d\n", (int)exif.size);
} }
if (flag & XMP_FLAG) { if (flag & XMP_FLAG) {
WebPData xmp; WebPData xmp;
err = WebPMuxGetChunk(mux, "XMP ", &xmp); err = WebPMuxGetChunk(mux, "XMP ", &xmp);
RETURN_IF_ERROR("Failed to retrieve the XMP metadata\n"); RETURN_IF_ERROR("Failed to retrieve the XMP metadata\n");
printf("Size of the XMP metadata: %zu\n", 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 | FRAGMENTS_FLAG))) {
WebPMuxFrameInfo image; WebPMuxFrameInfo image;
err = WebPMuxGetFrame(mux, 1, &image); err = WebPMuxGetFrame(mux, 1, &image);
RETURN_IF_ERROR("Failed to retrieve the image\n"); RETURN_IF_ERROR("Failed to retrieve the image\n");
printf("Size of the image (with alpha): %zu\n", image.bitstream.size); printf("Size of the image (with alpha): %d\n", (int)image.bitstream.size);
} }
return WEBP_MUX_OK; return WEBP_MUX_OK;
@ -272,7 +273,9 @@ 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 -strip STRIP_OPTIONS INPUT -o OUTPUT\n"); printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n");
#ifdef WEBP_EXPERIMENTAL_FEATURES
printf(" webpmux -frgm FRAGMENT_OPTIONS [-frgm...] -o OUTPUT\n"); printf(" webpmux -frgm FRAGMENT_OPTIONS [-frgm...] -o OUTPUT\n");
#endif
printf(" webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]" printf(" webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]"
"\n"); "\n");
printf(" [-bgcolor BACKGROUND_COLOR] -o OUTPUT\n"); printf(" [-bgcolor BACKGROUND_COLOR] -o OUTPUT\n");
@ -286,7 +289,9 @@ static void PrintHelp(void) {
printf(" icc Get ICC profile.\n"); printf(" icc Get ICC profile.\n");
printf(" exif Get EXIF metadata.\n"); printf(" exif Get EXIF metadata.\n");
printf(" xmp Get XMP metadata.\n"); printf(" xmp Get XMP metadata.\n");
#ifdef WEBP_EXPERIMENTAL_FEATURES
printf(" frgm n Get nth fragment.\n"); printf(" frgm n Get nth fragment.\n");
#endif
printf(" frame n Get nth frame.\n"); printf(" frame n Get nth frame.\n");
printf("\n"); printf("\n");
@ -306,6 +311,7 @@ static void PrintHelp(void) {
printf(" exif Strip EXIF metadata.\n"); printf(" exif Strip EXIF metadata.\n");
printf(" xmp Strip XMP metadata.\n"); printf(" xmp Strip XMP metadata.\n");
#ifdef WEBP_EXPERIMENTAL_FEATURES
printf("\n"); printf("\n");
printf("FRAGMENT_OPTIONS(i):\n"); printf("FRAGMENT_OPTIONS(i):\n");
printf(" Create fragmented image.\n"); printf(" Create fragmented image.\n");
@ -313,6 +319,7 @@ static void PrintHelp(void) {
printf(" where: 'file_i' is the i'th fragment (WebP format),\n"); printf(" where: 'file_i' is the i'th fragment (WebP format),\n");
printf(" 'xi','yi' specify the image offset for this fragment." printf(" 'xi','yi' specify the image offset for this fragment."
"\n"); "\n");
#endif
printf("\n"); printf("\n");
printf("FRAME_OPTIONS(i):\n"); printf("FRAME_OPTIONS(i):\n");
@ -375,7 +382,8 @@ static int WriteData(const char* filename, const WebPData* const webpdata) {
if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) { if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) {
fprintf(stderr, "Error writing file %s!\n", filename); fprintf(stderr, "Error writing file %s!\n", filename);
} else { } else {
fprintf(stderr, "Saved file %s (%zu bytes)\n", filename, webpdata->size); fprintf(stderr, "Saved file %s (%d bytes)\n",
filename, (int)webpdata->size);
ok = 1; ok = 1;
} }
if (fout != stdout) fclose(fout); if (fout != stdout) fclose(fout);
@ -596,6 +604,7 @@ static int ParseCommandLine(int argc, const char* argv[],
arg->params_ = argv[i + 1]; arg->params_ = argv[i + 1];
++feature_arg_index; ++feature_arg_index;
i += 2; i += 2;
#ifdef WEBP_EXPERIMENTAL_FEATURES
} else if (!strcmp(argv[i], "-frgm")) { } else if (!strcmp(argv[i], "-frgm")) {
CHECK_NUM_ARGS_LESS(3, ErrParse); CHECK_NUM_ARGS_LESS(3, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) { if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
@ -612,6 +621,7 @@ static int ParseCommandLine(int argc, const char* argv[],
arg->params_ = argv[i + 2]; arg->params_ = argv[i + 2];
++feature_arg_index; ++feature_arg_index;
i += 3; i += 3;
#endif
} else if (!strcmp(argv[i], "-o")) { } else if (!strcmp(argv[i], "-o")) {
CHECK_NUM_ARGS_LESS(2, ErrParse); CHECK_NUM_ARGS_LESS(2, ErrParse);
config->output_ = argv[i + 1]; config->output_ = argv[i + 1];
@ -660,8 +670,12 @@ static int ParseCommandLine(int argc, const char* argv[],
} else { } else {
++i; ++i;
} }
#ifdef WEBP_EXPERIMENTAL_FEATURES
} else if ((!strcmp(argv[i], "frame") || } else if ((!strcmp(argv[i], "frame") ||
!strcmp(argv[i], "frgm")) && !strcmp(argv[i], "frgm")) &&
#else
} else if (!strcmp(argv[i], "frame") &&
#endif
(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_ = (!strcmp(argv[i], "frame")) ? FEATURE_ANMF :
@ -763,12 +777,12 @@ static int InitializeConfig(int argc, const char* argv[],
// Processing. // Processing.
static int GetFrameFragment(const WebPMux* mux, static int GetFrameFragment(const WebPMux* mux,
const WebPMuxConfig* config, int isFrame) { const WebPMuxConfig* config, int is_frame) {
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
WebPMux* mux_single = NULL; WebPMux* mux_single = NULL;
long num = 0; long num = 0;
int ok = 1; int ok = 1;
const WebPChunkId id = isFrame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM; const WebPChunkId id = is_frame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
WebPMuxFrameInfo info; WebPMuxFrameInfo info;
WebPDataInit(&info.bitstream); WebPDataInit(&info.bitstream);

View File

@ -168,7 +168,10 @@ LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS)
HDRS_INSTALLED = \ HDRS_INSTALLED = \
src/webp/decode.h \ src/webp/decode.h \
src/webp/demux.h \
src/webp/encode.h \ src/webp/encode.h \
src/webp/mux.h \
src/webp/mux_types.h \
src/webp/types.h \ src/webp/types.h \
HDRS = \ HDRS = \
@ -191,22 +194,21 @@ HDRS = \
src/utils/quant_levels_dec.h \ src/utils/quant_levels_dec.h \
src/utils/rescaler.h \ src/utils/rescaler.h \
src/utils/thread.h \ src/utils/thread.h \
src/webp/demux.h \
src/webp/format_constants.h \ src/webp/format_constants.h \
src/webp/mux.h \
src/webp/mux_types.h \
$(HDRS_INSTALLED) \ $(HDRS_INSTALLED) \
OUT_LIBS = examples/libexample_util.a src/libwebpdecoder.a src/libwebp.a OUT_LIBS = examples/libexample_util.a src/libwebpdecoder.a src/libwebp.a
OUT_EXAMPLES = examples/cwebp examples/dwebp OUT_EXAMPLES = examples/cwebp examples/dwebp
EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux
OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES) OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES)
ifeq ($(MAKECMDGOALS),clean) ifeq ($(MAKECMDGOALS),clean)
OUTPUT += examples/gif2webp examples/vwebp examples/webpmux OUTPUT += $(EXTRA_EXAMPLES)
OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a
endif endif
all: ex ex: $(OUT_EXAMPLES)
all: ex $(EXTRA_EXAMPLES)
$(EX_FORMAT_DEC_OBJS): %.o: %.h $(EX_FORMAT_DEC_OBJS): %.o: %.h
@ -222,8 +224,6 @@ src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
%.a: %.a:
$(AR) $(ARFLAGS) $@ $^ $(AR) $(ARFLAGS) $@ $^
ex: $(OUT_EXAMPLES)
examples/cwebp: examples/cwebp.o $(EX_FORMAT_DEC_OBJS) examples/cwebp: examples/cwebp.o $(EX_FORMAT_DEC_OBJS)
examples/dwebp: examples/dwebp.o examples/dwebp: examples/dwebp.o
examples/gif2webp: examples/gif2webp.o examples/gif2webp: examples/gif2webp.o
@ -242,18 +242,21 @@ examples/vwebp: EXTRA_LIBS += $(GL_LIBS)
examples/webpmux: examples/libexample_util.a src/mux/libwebpmux.a examples/webpmux: examples/libexample_util.a src/mux/libwebpmux.a
examples/webpmux: src/libwebpdecoder.a examples/webpmux: src/libwebpdecoder.a
$(OUT_EXAMPLES) examples/gif2webp examples/vwebp examples/webpmux: $(OUT_EXAMPLES) $(EXTRA_EXAMPLES):
$(CC) -o $@ $^ $(LDFLAGS) $(CC) -o $@ $^ $(LDFLAGS)
dist: DESTDIR := dist dist: DESTDIR := dist
dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES)
dist: all dist: all
$(INSTALL) -m755 -d $(DESTDIR)/include/webp \ $(INSTALL) -m755 -d $(DESTDIR)/include/webp \
$(DESTDIR)/doc $(DESTDIR)/lib $(DESTDIR)/doc $(DESTDIR)/lib
$(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR) $(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)
$(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp $(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp
$(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib $(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
umask 022; \ umask 022; \
for m in man/[cd]webp.1; do \ for m in man/[cd]webp.1 man/gif2webp.1 man/webpmux.1; do \
basenam=$$(basename $$m .1); \ 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; \

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH CWEBP 1 "March 8, 2013" .TH CWEBP 1 "March 13, 2013"
.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
@ -200,7 +200,7 @@ Specify the hint about input image type. Possible values are:
.BI \-metadata " string .BI \-metadata " string
A comma separated list of metadata to copy from the input to the output if A comma separated list of metadata to copy from the input to the output if
present. present.
Valid values: \fBall\fP, \fBnone\fP, \fBexif\fP, \fBiccp\fP, \fBxmp\fP. Valid values: \fBall\fP, \fBnone\fP, \fBexif\fP, \fBicc\fP, \fBxmp\fP.
The default is \fBnone\fP. The default is \fBnone\fP.
Note: each input format may not support all combinations. Note: each input format may not support all combinations.

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH WEBPMUX 1 "February 26, 2013" .TH WEBPMUX 1 "March 16, 2013"
.SH NAME .SH NAME
webpmux \- command line tool to create WebP Mux/container file. webpmux \- command line tool to create WebP Mux/container file.
.SH SYNOPSIS .SH SYNOPSIS
@ -21,11 +21,6 @@ webpmux \- command line tool to create WebP Mux/container file.
.B \-o .B \-o
.I OUTPUT .I OUTPUT
.br .br
.B webpmux \-frgm
.I FRAGMENT_OPTIONS
.B [ \-frgm ... ] \-o
.I OUTPUT
.br
.B webpmux \-frame .B webpmux \-frame
.I FRAME_OPTIONS .I FRAME_OPTIONS
.B [ \-frame ... ] [ \-loop .B [ \-frame ... ] [ \-loop
@ -64,9 +59,6 @@ Get EXIF metadata.
.B xmp .B xmp
Get XMP metadata. Get XMP metadata.
.TP .TP
.BI frgm " n
Get nth fragment.
.TP
.BI frame " n .BI frame " n
Get nth frame. Get nth frame.
@ -98,12 +90,6 @@ Strip EXIF metadata.
.B xmp .B xmp
Strip XMP metadata. Strip XMP metadata.
.SS FRAGMENT_OPTIONS (\-frgm)
.TP
.I file_i +xi+yi
Where: 'file_i' is the i'th fragment (WebP format) and 'xi','yi' specify the
image offset for this fragment.
.SS FRAME_OPTIONS (\-frame) .SS FRAME_OPTIONS (\-frame)
.TP .TP
.I file_i +di[+xi+yi[+mi]] .I file_i +di[+xi+yi[+mi]]
@ -163,18 +149,13 @@ webpmux \-get exif exif_container.webp \-o image_metadata.exif
.br .br
webpmux \-strip exif exif_container.webp \-o without_exif.webp webpmux \-strip exif exif_container.webp \-o without_exif.webp
.br .br
webpmux \-frame anim_1.webp +0+0+0 \-frame anim_2.webp +50+50+0 \-loop 10 webpmux \-frame anim_1.webp +100 \-frame anim_2.webp +100+50+50 \-loop 10
.br .br
.RS 8 .RS 8
\-bgcolor 255,255,255,255 \-o anim_container.webp \-bgcolor 255,255,255,255 \-o anim_container.webp
.RE .RE
.br .br
webpmux \-get frame 2 anim_container.webp \-o frame_2.webp webpmux \-get frame 2 anim_container.webp \-o frame_2.webp
.br
webpmux \-tile tile_1.webp +0+0 \-tile tile_2.webp +960+0 \-tile tile_3.webp
+0+576 \-tile tile_4.webp +960+576 \-o tile_container.webp
.br
webpmux \-get tile 2 tile_container.webp \-o tile_2.webp
.SH AUTHORS .SH AUTHORS
\fBwebpmux\fP is written by the WebP team. \fBwebpmux\fP is written by the WebP team.

View File

@ -1,4 +1,6 @@
SUBDIRS = dec enc dsp utils # The mux and demux libraries depend on libwebp, thus the '.' to force the
# build order so it's available to them.
SUBDIRS = dec enc dsp utils .
if WANT_MUX if WANT_MUX
SUBDIRS += mux SUBDIRS += mux
endif endif
@ -13,11 +15,14 @@ if BUILD_LIBWEBPDECODER
lib_LTLIBRARIES += libwebpdecoder.la lib_LTLIBRARIES += libwebpdecoder.la
endif endif
common_HEADERS =
common_HEADERS += webp/decode.h
common_HEADERS += webp/types.h
commondir = $(includedir)/webp
libwebp_la_SOURCES = libwebp_la_SOURCES =
libwebpinclude_HEADERS = libwebpinclude_HEADERS =
libwebpinclude_HEADERS += webp/decode.h
libwebpinclude_HEADERS += webp/encode.h libwebpinclude_HEADERS += webp/encode.h
libwebpinclude_HEADERS += webp/types.h
noinst_HEADERS = noinst_HEADERS =
noinst_HEADERS += webp/format_constants.h noinst_HEADERS += webp/format_constants.h
@ -31,15 +36,12 @@ 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 4:1:0 libwebp_la_LDFLAGS = -no-undefined -version-info 4:2:0
libwebpincludedir = $(includedir)/webp libwebpincludedir = $(includedir)/webp
pkgconfig_DATA = libwebp.pc pkgconfig_DATA = libwebp.pc
if BUILD_LIBWEBPDECODER if BUILD_LIBWEBPDECODER
libwebpdecoder_la_SOURCES = libwebpdecoder_la_SOURCES =
libwebpdecoderinclude_HEADERS =
libwebpdecoderinclude_HEADERS += webp/decode.h
libwebpdecoderinclude_HEADERS += webp/types.h
libwebpdecoder_la_LIBADD = libwebpdecoder_la_LIBADD =
libwebpdecoder_la_LIBADD += dec/libwebpdecode.la libwebpdecoder_la_LIBADD += dec/libwebpdecode.la
@ -47,7 +49,6 @@ if BUILD_LIBWEBPDECODER
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 0:0:0 libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 0:0:0
libwebpdecoderincludedir = $(includedir)/webp
pkgconfig_DATA += libwebpdecoder.pc pkgconfig_DATA += libwebpdecoder.pc
endif endif

View File

@ -44,7 +44,6 @@ static int DecodeAlpha(const uint8_t* data, size_t data_size,
int width, int height, int stride, uint8_t* output) { int width, int height, int stride, uint8_t* output) {
uint8_t* decoded_data = NULL; uint8_t* decoded_data = NULL;
const size_t decoded_size = height * width; const size_t decoded_size = height * width;
uint8_t* unfiltered_data = NULL;
WEBP_FILTER_TYPE filter; WEBP_FILTER_TYPE filter;
int pre_processing; int pre_processing;
int rsrv; int rsrv;
@ -83,29 +82,19 @@ static int DecodeAlpha(const uint8_t* data, size_t data_size,
} }
if (ok) { if (ok) {
WebPFilterFunc unfilter_func = WebPUnfilters[filter]; WebPUnfilterFunc unfilter_func = WebPUnfilters[filter];
if (unfilter_func != NULL) { if (unfilter_func != NULL) {
unfiltered_data = (uint8_t*)malloc(decoded_size);
if (unfiltered_data == NULL) {
ok = 0;
goto Error;
}
// TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode
// and apply filter per image-row. // and apply filter per image-row.
unfilter_func(decoded_data, width, height, 1, width, unfiltered_data); unfilter_func(width, height, width, decoded_data);
// Construct raw_data (height x stride) from alpha data (height x width).
CopyPlane(unfiltered_data, width, output, stride, width, height);
free(unfiltered_data);
} else {
// Construct raw_data (height x stride) from alpha data (height x width).
CopyPlane(decoded_data, width, output, stride, width, height);
} }
// Construct raw_data (height x stride) from alpha data (height x width).
CopyPlane(decoded_data, width, output, stride, width, height);
if (pre_processing == ALPHA_PREPROCESSED_LEVELS) { if (pre_processing == ALPHA_PREPROCESSED_LEVELS) {
ok = DequantizeLevels(decoded_data, width, height); ok = DequantizeLevels(decoded_data, width, height);
} }
} }
Error:
if (method != ALPHA_NO_COMPRESSION) { if (method != ALPHA_NO_COMPRESSION) {
free(decoded_data); free(decoded_data);
} }

View File

@ -27,8 +27,8 @@ extern "C" {
// version numbers // version numbers
#define DEC_MAJ_VERSION 0 #define DEC_MAJ_VERSION 0
#define DEC_MIN_VERSION 2 #define DEC_MIN_VERSION 3
#define DEC_REV_VERSION 1 #define DEC_REV_VERSION 0
#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames #define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames

View File

@ -14,7 +14,7 @@
#include "./vp8i.h" #include "./vp8i.h"
#include "./vp8li.h" #include "./vp8li.h"
#include "./webpi.h" #include "./webpi.h"
#include "../webp/format_constants.h" #include "../webp/mux_types.h" // ALPHA_FLAG
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
@ -276,6 +276,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
int* const width, int* const width,
int* const height, int* const height,
int* const has_alpha, int* const has_alpha,
int* const has_animation,
WebPHeaderStructure* const headers) { WebPHeaderStructure* const headers) {
int found_riff = 0; int found_riff = 0;
int found_vp8x = 0; int found_vp8x = 0;
@ -309,6 +310,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
return VP8_STATUS_BITSTREAM_ERROR; return VP8_STATUS_BITSTREAM_ERROR;
} }
if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG); if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG);
if (has_animation != NULL) *has_animation = !!(flags & ANIMATION_FLAG);
if (found_vp8x && headers == NULL) { if (found_vp8x && headers == NULL) {
return VP8_STATUS_OK; // Return features from VP8X header. return VP8_STATUS_OK; // Return features from VP8X header.
} }
@ -370,10 +372,19 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
} }
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) { VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
VP8StatusCode status;
int has_animation = 0;
assert(headers != NULL); assert(headers != NULL);
// fill out headers, ignore width/height/has_alpha. // fill out headers, ignore width/height/has_alpha.
return ParseHeadersInternal(headers->data, headers->data_size, status = ParseHeadersInternal(headers->data, headers->data_size,
NULL, NULL, NULL, headers); NULL, NULL, NULL, &has_animation, headers);
if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
// TODO(jzern): full support of animation frames will require API additions.
if (has_animation) {
status = VP8_STATUS_UNSUPPORTED_FEATURE;
}
}
return status;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -625,10 +636,11 @@ static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
} }
DefaultFeatures(features); DefaultFeatures(features);
// Only parse enough of the data to retrieve width/height/has_alpha. // Only parse enough of the data to retrieve the features.
return ParseHeadersInternal(data, data_size, return ParseHeadersInternal(data, data_size,
&features->width, &features->height, &features->width, &features->height,
&features->has_alpha, NULL); &features->has_alpha, &features->has_animation,
NULL);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -61,10 +61,10 @@ typedef struct {
} WebPHeaderStructure; } WebPHeaderStructure;
// Skips over all valid chunks prior to the first VP8/VP8L frame header. // Skips over all valid chunks prior to the first VP8/VP8L frame header.
// Returns VP8_STATUS_OK on success, // Returns: VP8_STATUS_OK, VP8_STATUS_BITSTREAM_ERROR (invalid header/chunk),
// VP8_STATUS_BITSTREAM_ERROR if an invalid header/chunk is found, and // VP8_STATUS_NOT_ENOUGH_DATA (partial input) or VP8_STATUS_UNSUPPORTED_FEATURE
// VP8_STATUS_NOT_ENOUGH_DATA if case of insufficient data. // in the case of non-decodable features (animation for instance).
// In 'headers', compressed_size, offset, alpha_data, alpha_size and lossless // In 'headers', compressed_size, offset, alpha_data, alpha_size, and lossless
// fields are updated appropriately upon success. // fields are updated appropriately upon success.
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers); VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);

View File

@ -6,7 +6,10 @@ libwebpdemux_la_SOURCES += demux.c
libwebpdemuxinclude_HEADERS = libwebpdemuxinclude_HEADERS =
libwebpdemuxinclude_HEADERS += ../webp/demux.h libwebpdemuxinclude_HEADERS += ../webp/demux.h
libwebpdemuxinclude_HEADERS += ../webp/mux_types.h
libwebpdemuxinclude_HEADERS += ../webp/types.h libwebpdemuxinclude_HEADERS += ../webp/types.h
libwebpdemux_la_LDFLAGS = -version-info 0:0:0 libwebpdemux_la_LIBADD = ../libwebp.la
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 0:0:0
libwebpdemuxincludedir = $(includedir)/webp libwebpdemuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpdemux.pc

View File

@ -8,6 +8,10 @@
// WebP container demux. // WebP container demux.
// //
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -65,6 +69,7 @@ struct WebPDemuxer {
uint32_t bgcolor_; uint32_t bgcolor_;
int num_frames_; int num_frames_;
Frame* frames_; Frame* frames_;
Frame** frames_tail_;
Chunk* chunks_; // non-image chunks Chunk* chunks_; // non-image chunks
}; };
@ -179,15 +184,12 @@ static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) {
// Add a frame to the end of the list, ensuring the last frame is complete. // Add a frame to the end of the list, ensuring the last frame is complete.
// Returns true on success, false otherwise. // Returns true on success, false otherwise.
static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
const Frame* last_frame = NULL; const Frame* const last_frame = *dmux->frames_tail_;
Frame** f = &dmux->frames_;
while (*f != NULL) {
last_frame = *f;
f = &(*f)->next_;
}
if (last_frame != NULL && !last_frame->complete_) return 0; if (last_frame != NULL && !last_frame->complete_) return 0;
*f = frame;
*dmux->frames_tail_ = frame;
frame->next_ = NULL; frame->next_ = NULL;
dmux->frames_tail_ = &frame->next_;
return 1; return 1;
} }
@ -231,8 +233,10 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
goto Done; goto Done;
} }
break; break;
case MKFOURCC('V', 'P', '8', ' '):
case MKFOURCC('V', 'P', '8', 'L'): case MKFOURCC('V', 'P', '8', 'L'):
if (alpha_chunks > 0) return PARSE_ERROR; // VP8L has its own alpha
// fall through
case MKFOURCC('V', 'P', '8', ' '):
if (image_chunks == 0) { if (image_chunks == 0) {
// Extract the bitstream features, tolerating failures when the data // Extract the bitstream features, tolerating failures when the data
// is incomplete. // is incomplete.
@ -295,7 +299,7 @@ static ParseStatus NewFrame(const MemBuffer* const mem,
// Parse a 'ANMF' chunk and any image bearing chunks that immediately follow. // Parse a 'ANMF' chunk and any image bearing chunks that immediately follow.
// 'frame_chunk_size' is the previously validated, padded chunk size. // 'frame_chunk_size' is the previously validated, padded chunk size.
static ParseStatus ParseFrame( static ParseStatus ParseAnimationFrame(
WebPDemuxer* const dmux, uint32_t frame_chunk_size) { WebPDemuxer* const dmux, uint32_t frame_chunk_size) {
const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE; const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
@ -316,8 +320,8 @@ static ParseStatus ParseFrame(
return PARSE_ERROR; return PARSE_ERROR;
} }
// Store a frame only if the animation flag is set and all data for this frame // Store a frame only if the animation flag is set there is some data for
// is available. // this frame is available.
status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame, status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame,
NULL); NULL);
if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) { if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) {
@ -333,6 +337,7 @@ static ParseStatus ParseFrame(
return status; return status;
} }
#ifdef WEBP_EXPERIMENTAL_FEATURES
// Parse a 'FRGM' chunk and any image bearing chunks that immediately follow. // Parse a 'FRGM' chunk and any image bearing chunks that immediately follow.
// 'fragment_chunk_size' is the previously validated, padded chunk size. // 'fragment_chunk_size' is the previously validated, padded chunk size.
static ParseStatus ParseFragment(WebPDemuxer* const dmux, static ParseStatus ParseFragment(WebPDemuxer* const dmux,
@ -347,12 +352,12 @@ static ParseStatus ParseFragment(WebPDemuxer* const dmux,
NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame); NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame);
if (status != PARSE_OK) return status; if (status != PARSE_OK) return status;
frame->is_fragment_ = 1; frame->is_fragment_ = 1;
frame->x_offset_ = 2 * ReadLE24s(mem); frame->x_offset_ = 2 * ReadLE24s(mem);
frame->y_offset_ = 2 * ReadLE24s(mem); frame->y_offset_ = 2 * ReadLE24s(mem);
// Store a fragment only if the fragments flag is set and all data for this // Store a fragment only if the fragments flag is set there is some data for
// fragment is available. // this fragment is available.
status = StoreFrame(frame_num, frgm_payload_size, mem, frame, NULL); status = StoreFrame(frame_num, frgm_payload_size, mem, frame, NULL);
if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) { if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) {
added_fragment = AddFrame(dmux, frame); added_fragment = AddFrame(dmux, frame);
@ -366,8 +371,9 @@ static ParseStatus ParseFragment(WebPDemuxer* const dmux,
if (!added_fragment) free(frame); if (!added_fragment) free(frame);
return status; return status;
} }
#endif // WEBP_EXPERIMENTAL_FEATURES
// General chunk storage starting with the header at 'start_offset' allowing // General chunk storage, starting with the header at 'start_offset', allowing
// the user to request the payload via a fourcc string. 'size' includes the // the user to request the payload via a fourcc string. 'size' includes the
// header and the unpadded payload size. // header and the unpadded payload size.
// Returns true on success, false otherwise. // Returns true on success, false otherwise.
@ -424,7 +430,7 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
frame = (Frame*)calloc(1, sizeof(*frame)); frame = (Frame*)calloc(1, sizeof(*frame));
if (frame == NULL) return PARSE_ERROR; if (frame == NULL) return PARSE_ERROR;
// For the single image case, we allow parsing of a partial frame. But we need // For the single image case we allow parsing of a partial frame, but we need
// at least CHUNK_HEADER_SIZE for parsing. // at least CHUNK_HEADER_SIZE for parsing.
status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame, status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame,
&has_vp8l_alpha); &has_vp8l_alpha);
@ -500,6 +506,9 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
case MKFOURCC('A', 'L', 'P', 'H'): case MKFOURCC('A', 'L', 'P', 'H'):
case MKFOURCC('V', 'P', '8', ' '): case MKFOURCC('V', 'P', '8', ' '):
case MKFOURCC('V', 'P', '8', 'L'): { case MKFOURCC('V', 'P', '8', 'L'): {
// check that this isn't an animation (all frames should be in an ANMF).
if (anim_chunks > 0) return PARSE_ERROR;
Rewind(mem, CHUNK_HEADER_SIZE); Rewind(mem, CHUNK_HEADER_SIZE);
status = ParseSingleImage(dmux); status = ParseSingleImage(dmux);
break; break;
@ -521,13 +530,16 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
break; break;
} }
case MKFOURCC('A', 'N', 'M', 'F'): { case MKFOURCC('A', 'N', 'M', 'F'): {
status = ParseFrame(dmux, chunk_size_padded); if (anim_chunks == 0) return PARSE_ERROR; // 'ANIM' precedes frames.
status = ParseAnimationFrame(dmux, chunk_size_padded);
break; break;
} }
#ifdef WEBP_EXPERIMENTAL_FEATURES
case MKFOURCC('F', 'R', 'G', 'M'): { case MKFOURCC('F', 'R', 'G', 'M'): {
status = ParseFragment(dmux, chunk_size_padded); status = ParseFragment(dmux, chunk_size_padded);
break; break;
} }
#endif
case MKFOURCC('I', 'C', 'C', 'P'): { case MKFOURCC('I', 'C', 'C', 'P'): {
store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG);
goto Skip; goto Skip;
@ -615,6 +627,9 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
if (f->width_ <= 0 || f->height_ <= 0) return 0; if (f->width_ <= 0 || f->height_ <= 0) return 0;
} else { } else {
// There shouldn't be a partial frame in a complete file.
if (dmux->state_ == WEBP_DEMUX_DONE) return 0;
// Ensure alpha precedes image bitstream. // Ensure alpha precedes image bitstream.
if (alpha->size_ > 0 && image->size_ > 0 && if (alpha->size_ > 0 && image->size_ > 0 &&
alpha->offset_ > image->offset_) { alpha->offset_ > image->offset_) {
@ -643,6 +658,7 @@ static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
dmux->bgcolor_ = 0xFFFFFFFF; // White background by default. dmux->bgcolor_ = 0xFFFFFFFF; // White background by default.
dmux->canvas_width_ = -1; dmux->canvas_width_ = -1;
dmux->canvas_height_ = -1; dmux->canvas_height_ = -1;
dmux->frames_tail_ = &dmux->frames_;
dmux->mem_ = *mem; dmux->mem_ = *mem;
} }

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libwebpdemux
Description: Library for parsing the WebP graphics format container
Version: @PACKAGE_VERSION@
Requires: libwebp >= 0.2.0
Cflags: -I${includedir}
Libs: -L${libdir} -lwebpdemux

View File

@ -5,7 +5,10 @@ if BUILD_LIBWEBPDECODER
noinst_LTLIBRARIES += libwebpdspdecode.la noinst_LTLIBRARIES += libwebpdspdecode.la
endif endif
COMMON_SOURCES = common_HEADERS = ../webp/types.h
commondir = $(includedir)/webp
COMMON_SOURCES =
COMMON_SOURCES += cpu.c COMMON_SOURCES += cpu.c
COMMON_SOURCES += dec.c COMMON_SOURCES += dec.c
COMMON_SOURCES += dec_neon.c COMMON_SOURCES += dec_neon.c
@ -19,13 +22,12 @@ COMMON_SOURCES += upsampling_sse2.c
COMMON_SOURCES += yuv.c COMMON_SOURCES += yuv.c
COMMON_SOURCES += yuv.h COMMON_SOURCES += yuv.h
ENC_SOURCES = ENC_SOURCES =
ENC_SOURCES += enc.c ENC_SOURCES += enc.c
ENC_SOURCES += enc_neon.c ENC_SOURCES += enc_neon.c
ENC_SOURCES += enc_sse2.c ENC_SOURCES += enc_sse2.c
libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES) libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES)
libwebpdspinclude_HEADERS = ../webp/types.h
noinst_HEADERS = noinst_HEADERS =
noinst_HEADERS += ../dec/decode_vp8.h noinst_HEADERS += ../dec/decode_vp8.h
@ -33,13 +35,10 @@ noinst_HEADERS += ../webp/decode.h
libwebpdsp_la_LDFLAGS = -lm libwebpdsp_la_LDFLAGS = -lm
libwebpdsp_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE) $(USE_SWAP_16BIT_CSP) libwebpdsp_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE) $(USE_SWAP_16BIT_CSP)
libwebpdspincludedir = $(includedir)/webp
if BUILD_LIBWEBPDECODER if BUILD_LIBWEBPDECODER
libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES) libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES)
libwebpdspdecodeinclude_HEADERS = $(libwebpdspinclude_HEADERS)
libwebpdspdecode_la_LDFLAGS = $(libwebpdsp_la_LDFLAGS) libwebpdspdecode_la_LDFLAGS = $(libwebpdsp_la_LDFLAGS)
libwebpdspdecode_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) libwebpdspdecode_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
libwebpdspdecodeincludedir = $(libwebpdspincludedir)
endif endif

View File

@ -631,13 +631,13 @@ static int QuantizeBlock(int16_t in[16], int16_t out[16],
for (; n < 16; ++n) { for (; n < 16; ++n) {
const int j = kZigzag[n]; const int j = kZigzag[n];
const int sign = (in[j] < 0); const int sign = (in[j] < 0);
int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; const int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
if (coeff > 2047) coeff = 2047;
if (coeff > mtx->zthresh_[j]) { if (coeff > mtx->zthresh_[j]) {
const int Q = mtx->q_[j]; const int Q = mtx->q_[j];
const int iQ = mtx->iq_[j]; const int iQ = mtx->iq_[j];
const int B = mtx->bias_[j]; const int B = mtx->bias_[j];
out[n] = QUANTDIV(coeff, iQ, B); out[n] = QUANTDIV(coeff, iQ, B);
if (out[n] > MAX_LEVEL) out[n] = MAX_LEVEL;
if (sign) out[n] = -out[n]; if (sign) out[n] = -out[n];
in[j] = out[n] * Q; in[j] = out[n] * Q;
if (out[n]) last = n; if (out[n]) last = n;

View File

@ -776,7 +776,7 @@ static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
// Simple quantization // Simple quantization
static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16], static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
int n, const VP8Matrix* const mtx) { int n, const VP8Matrix* const mtx) {
const __m128i max_coeff_2047 = _mm_set1_epi16(2047); const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL);
const __m128i zero = _mm_setzero_si128(); const __m128i zero = _mm_setzero_si128();
__m128i coeff0, coeff8; __m128i coeff0, coeff8;
__m128i out0, out8; __m128i out0, out8;
@ -812,10 +812,6 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
coeff0 = _mm_add_epi16(coeff0, sharpen0); coeff0 = _mm_add_epi16(coeff0, sharpen0);
coeff8 = _mm_add_epi16(coeff8, sharpen8); coeff8 = _mm_add_epi16(coeff8, sharpen8);
// if (coeff > 2047) coeff = 2047
coeff0 = _mm_min_epi16(coeff0, max_coeff_2047);
coeff8 = _mm_min_epi16(coeff8, max_coeff_2047);
// out = (coeff * iQ + B) >> QFIX; // out = (coeff * iQ + B) >> QFIX;
{ {
// doing calculations with 32b precision (QFIX=17) // doing calculations with 32b precision (QFIX=17)
@ -843,9 +839,14 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
out_04 = _mm_srai_epi32(out_04, QFIX); out_04 = _mm_srai_epi32(out_04, QFIX);
out_08 = _mm_srai_epi32(out_08, QFIX); out_08 = _mm_srai_epi32(out_08, QFIX);
out_12 = _mm_srai_epi32(out_12, QFIX); out_12 = _mm_srai_epi32(out_12, QFIX);
// pack result as 16b // pack result as 16b
out0 = _mm_packs_epi32(out_00, out_04); out0 = _mm_packs_epi32(out_00, out_04);
out8 = _mm_packs_epi32(out_08, out_12); out8 = _mm_packs_epi32(out_08, out_12);
// if (coeff > 2047) coeff = 2047
out0 = _mm_min_epi16(out0, max_coeff_2047);
out8 = _mm_min_epi16(out8, max_coeff_2047);
} }
// get sign back (if (sign[j]) out_n = -out_n) // get sign back (if (sign[j]) out_n = -out_n)

View File

@ -15,7 +15,7 @@
extern "C" { extern "C" {
#endif #endif
enum { YUV_HALF = 1 << (YUV_FIX - 1) }; #ifdef WEBP_YUV_USE_TABLE
int16_t VP8kVToR[256], VP8kUToB[256]; int16_t VP8kVToR[256], VP8kUToB[256];
int32_t VP8kVToG[256], VP8kUToG[256]; int32_t VP8kVToG[256], VP8kUToG[256];
@ -62,6 +62,12 @@ void VP8YUVInit(void) {
done = 1; done = 1;
} }
#else
void VP8YUVInit(void) {}
#endif // WEBP_YUV_USE_TABLE
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"
#endif #endif

View File

@ -19,8 +19,9 @@
// G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128) // G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128)
// B = 1.164 * (Y-16) + 2.018 * (U-128) // B = 1.164 * (Y-16) + 2.018 * (U-128)
// where Y is in the [16,235] range, and U/V in the [16,240] range. // where Y is in the [16,235] range, and U/V in the [16,240] range.
// But the common term 1.164 * (Y-16) can be handled as an offset in the // In the table-lookup version (WEBP_YUV_USE_TABLE), the common factor
// VP8kClip[] table. So the formulae should be read as: // "1.164 * (Y-16)" can be handled as an offset in the VP8kClip[] table.
// So in this case the formulae should be read as:
// R = 1.164 * [Y + 1.371 * (V-128) ] - 18.624 // R = 1.164 * [Y + 1.371 * (V-128) ] - 18.624
// G = 1.164 * [Y - 0.698 * (V-128) - 0.336 * (U-128)] - 18.624 // G = 1.164 * [Y - 0.698 * (V-128) - 0.336 * (U-128)] - 18.624
// B = 1.164 * [Y + 1.733 * (U-128)] - 18.624 // B = 1.164 * [Y + 1.733 * (U-128)] - 18.624
@ -33,6 +34,9 @@
#include "../dec/decode_vp8.h" #include "../dec/decode_vp8.h"
// Define the following to use the LUT-based code:
#define WEBP_YUV_USE_TABLE
#if defined(WEBP_EXPERIMENTAL_FEATURES) #if defined(WEBP_EXPERIMENTAL_FEATURES)
// Do NOT activate this feature for real compression. This is only experimental! // Do NOT activate this feature for real compression. This is only experimental!
// This flag is for comparison purpose against JPEG's "YUVj" natural colorspace. // This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
@ -51,9 +55,14 @@ extern "C" {
#endif #endif
enum { YUV_FIX = 16, // fixed-point precision enum { YUV_FIX = 16, // fixed-point precision
YUV_HALF = 1 << (YUV_FIX - 1),
YUV_MASK = (256 << YUV_FIX) - 1,
YUV_RANGE_MIN = -227, // min value of r/g/b output YUV_RANGE_MIN = -227, // min value of r/g/b output
YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output
}; };
#ifdef WEBP_YUV_USE_TABLE
extern int16_t VP8kVToR[256], VP8kUToB[256]; extern int16_t VP8kVToR[256], VP8kUToB[256];
extern int32_t VP8kVToG[256], VP8kUToG[256]; extern int32_t VP8kVToG[256], VP8kUToG[256];
extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN]; extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
@ -69,6 +78,16 @@ static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN]; rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
} }
static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const bgr) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
}
static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v, static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgb) { uint8_t* const rgb) {
const int r_off = VP8kVToR[v]; const int r_off = VP8kVToR[v];
@ -87,12 +106,6 @@ static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
#endif #endif
} }
static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
argb[0] = 0xff;
VP8YuvToRgb(y, u, v, argb + 1);
}
static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v, static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) { uint8_t* const argb) {
const int r_off = VP8kVToR[v]; const int r_off = VP8kVToR[v];
@ -110,14 +123,92 @@ static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v,
#endif #endif
} }
#else // Table-free version (slower on x86)
// These constants are 16b fixed-point version of ITU-R BT.601 constants
#define kYScale 76309 // 1.164 = 255 / 219
#define kVToR 104597 // 1.596 = 255 / 112 * 0.701
#define kUToG 25674 // 0.391 = 255 / 112 * 0.886 * 0.114 / 0.587
#define kVToG 53278 // 0.813 = 255 / 112 * 0.701 * 0.299 / 0.587
#define kUToB 132201 // 2.018 = 255 / 112 * 0.886
#define kRCst (-kYScale * 16 - kVToR * 128 + YUV_HALF)
#define kGCst (-kYScale * 16 + kUToG * 128 + kVToG * 128 + YUV_HALF)
#define kBCst (-kYScale * 16 - kUToB * 128 + YUV_HALF)
static WEBP_INLINE uint8_t VP8Clip8(int v) {
return ((v & ~YUV_MASK) == 0) ? (uint8_t)(v >> YUV_FIX)
: (v < 0) ? 0u : 255u;
}
static WEBP_INLINE uint8_t VP8ClipN(int v, int N) { // clip to N bits
return ((v & ~YUV_MASK) == 0) ? (uint8_t)(v >> (YUV_FIX + (8 - N)))
: (v < 0) ? 0u : (255u >> (8 - N));
}
static WEBP_INLINE int VP8YUVToR(int y, int v) {
return kYScale * y + kVToR * v + kRCst;
}
static WEBP_INLINE int VP8YUVToG(int y, int u, int v) {
return kYScale * y - kUToG * u - kVToG * v + kGCst;
}
static WEBP_INLINE int VP8YUVToB(int y, int u) {
return kYScale * y + kUToB * u + kBCst;
}
static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgb) {
rgb[0] = VP8Clip8(VP8YUVToR(y, v));
rgb[1] = VP8Clip8(VP8YUVToG(y, u, v));
rgb[2] = VP8Clip8(VP8YUVToB(y, u));
}
static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v, static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const bgr) { uint8_t* const bgr) {
const int r_off = VP8kVToR[v]; bgr[0] = VP8Clip8(VP8YUVToB(y, u));
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; bgr[1] = VP8Clip8(VP8YUVToG(y, u, v));
const int b_off = VP8kUToB[u]; bgr[2] = VP8Clip8(VP8YUVToR(y, v));
bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN]; }
bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN]; static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgb) {
const int r = VP8Clip8(VP8YUVToR(y, u));
const int g = VP8ClipN(VP8YUVToG(y, u, v), 6);
const int b = VP8ClipN(VP8YUVToB(y, v), 5);
const uint8_t rg = (r & 0xf8) | (g >> 3);
const uint8_t gb = (g << 5) | b;
#ifdef WEBP_SWAP_16BIT_CSP
rgb[0] = gb;
rgb[1] = rg;
#else
rgb[0] = rg;
rgb[1] = gb;
#endif
}
static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
const int r = VP8Clip8(VP8YUVToR(y, u));
const int g = VP8ClipN(VP8YUVToG(y, u, v), 4);
const int b = VP8Clip8(VP8YUVToB(y, v));
const uint8_t rg = (r & 0xf0) | g;
const uint8_t ba = b | 0x0f; // overwrite the lower 4 bits
#ifdef WEBP_SWAP_16BIT_CSP
argb[0] = ba;
argb[1] = rg;
#else
argb[0] = rg;
argb[1] = ba;
#endif
}
#endif // WEBP_YUV_USE_TABLE
static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
argb[0] = 0xff;
VP8YuvToRgb(y, u, v, argb + 1);
} }
static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v, static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,

View File

@ -127,8 +127,8 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN); VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN);
filter_func = WebPFilters[filter]; filter_func = WebPFilters[filter];
if (filter_func) { if (filter_func != NULL) {
filter_func(data, width, height, 1, width, tmp_alpha); filter_func(data, width, height, width, tmp_alpha);
alpha_src = tmp_alpha; alpha_src = tmp_alpha;
} else { } else {
alpha_src = data; alpha_src = data;

View File

@ -75,7 +75,7 @@ const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = {
// fixed costs for coding levels, deduce from the coding tree. // fixed costs for coding levels, deduce from the coding tree.
// This is only the part that doesn't depend on the probability state. // This is only the part that doesn't depend on the probability state.
const uint16_t VP8LevelFixedCosts[2048] = { const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1] = {
0, 256, 256, 256, 256, 432, 618, 630, 0, 256, 256, 256, 256, 432, 618, 630,
731, 640, 640, 828, 901, 948, 1021, 1101, 731, 640, 640, 828, 901, 948, 1021, 1101,
1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202, 1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202,

View File

@ -18,7 +18,8 @@
extern "C" { extern "C" {
#endif #endif
extern const uint16_t VP8LevelFixedCosts[2048]; // approximate cost per level // approximate cost per level:
extern const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1];
extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p) extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p)
// Cost of coding one event with probability 'proba'. // Cost of coding one event with probability 'proba'.

View File

@ -901,15 +901,21 @@ int VP8EncLoop(VP8Encoder* const enc) {
// Single pass using Token Buffer. // Single pass using Token Buffer.
#if !defined(DISABLE_TOKEN_BUFFER) #if !defined(DISABLE_TOKEN_BUFFER)
#define MIN_COUNT 96 // minimum number of macroblocks before updating stats
int VP8EncTokenLoop(VP8Encoder* const enc) { int VP8EncTokenLoop(VP8Encoder* const enc) {
int ok; int ok;
// refresh the proba 8 times per pass // Roughly refresh the proba height times per pass
const int max_count = (enc->mb_w_ * enc->mb_h_) >> 3; int max_count = (enc->mb_w_ * enc->mb_h_) >> 3;
int cnt = max_count; int cnt;
VP8EncIterator it; VP8EncIterator it;
VP8Proba* const proba = &enc->proba_; VP8Proba* const proba = &enc->proba_;
const VP8RDLevel rd_opt = enc->rd_opt_level_; const VP8RDLevel rd_opt = enc->rd_opt_level_;
if (max_count < MIN_COUNT) max_count = MIN_COUNT;
cnt = max_count;
assert(enc->num_parts_ == 1); assert(enc->num_parts_ == 1);
assert(enc->use_tokens_); assert(enc->use_tokens_);
assert(proba->use_skip_proba_ == 0); assert(proba->use_skip_proba_ == 0);

View File

@ -98,8 +98,6 @@ void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
} }
} }
static double BitsEntropy(const int* const array, int n) { static double BitsEntropy(const int* const array, int n) {
double retval = 0.; double retval = 0.;
int sum = 0; int sum = 0;
@ -149,25 +147,6 @@ static double BitsEntropy(const int* const array, int n) {
} }
} }
double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p))
+ BitsEntropy(&p->red_[0], 256)
+ BitsEntropy(&p->blue_[0], 256)
+ BitsEntropy(&p->alpha_[0], 256)
+ BitsEntropy(&p->distance_[0], NUM_DISTANCE_CODES);
// Compute the extra bits cost.
int i;
for (i = 2; i < NUM_LENGTH_CODES - 2; ++i) {
retval +=
(i >> 1) * p->literal_[256 + i + 2];
}
for (i = 2; i < NUM_DISTANCE_CODES - 2; ++i) {
retval += (i >> 1) * p->distance_[i + 2];
}
return retval;
}
// Returns the cost encode the rle-encoded entropy code. // Returns the cost encode the rle-encoded entropy code.
// The constants in this function are experimental. // The constants in this function are experimental.
static double HuffmanCost(const int* const population, int length) { static double HuffmanCost(const int* const population, int length) {
@ -207,19 +186,150 @@ static double HuffmanCost(const int* const population, int length) {
return retval; return retval;
} }
// Estimates the Huffman dictionary + other block overhead size. static double PopulationCost(const int* const population, int length) {
static double HistogramEstimateBitsHeader(const VP8LHistogram* const p) { return BitsEntropy(population, length) + HuffmanCost(population, length);
return HuffmanCost(&p->alpha_[0], 256) +
HuffmanCost(&p->red_[0], 256) +
HuffmanCost(&p->literal_[0], VP8LHistogramNumCodes(p)) +
HuffmanCost(&p->blue_[0], 256) +
HuffmanCost(&p->distance_[0], NUM_DISTANCE_CODES);
} }
double VP8LHistogramEstimateBits(const VP8LHistogram* const p) { static double ExtraCost(const int* const population, int length) {
return HistogramEstimateBitsHeader(p) + VP8LHistogramEstimateBitsBulk(p); int i;
double cost = 0.;
for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
return cost;
} }
// Estimates the Entropy + Huffman + other block overhead size cost.
double VP8LHistogramEstimateBits(const VP8LHistogram* const p) {
return PopulationCost(p->literal_, VP8LHistogramNumCodes(p))
+ PopulationCost(p->red_, 256)
+ PopulationCost(p->blue_, 256)
+ PopulationCost(p->alpha_, 256)
+ PopulationCost(p->distance_, NUM_DISTANCE_CODES)
+ ExtraCost(p->literal_ + 256, NUM_LENGTH_CODES)
+ ExtraCost(p->distance_, NUM_DISTANCE_CODES);
}
double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
return BitsEntropy(p->literal_, VP8LHistogramNumCodes(p))
+ BitsEntropy(p->red_, 256)
+ BitsEntropy(p->blue_, 256)
+ BitsEntropy(p->alpha_, 256)
+ BitsEntropy(p->distance_, NUM_DISTANCE_CODES)
+ ExtraCost(p->literal_ + 256, NUM_LENGTH_CODES)
+ ExtraCost(p->distance_, NUM_DISTANCE_CODES);
}
// -----------------------------------------------------------------------------
// Various histogram combine/cost-eval functions
// Adds 'in' histogram to 'out'
static void HistogramAdd(const VP8LHistogram* const in,
VP8LHistogram* const out) {
int i;
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
out->literal_[i] += in->literal_[i];
}
for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
out->distance_[i] += in->distance_[i];
}
for (i = 0; i < 256; ++i) {
out->red_[i] += in->red_[i];
out->blue_[i] += in->blue_[i];
out->alpha_[i] += in->alpha_[i];
}
}
// Performs out = a + b, computing the cost C(a+b) - C(a) - C(b) while comparing
// to the threshold value 'cost_threshold'. The score returned is
// Score = C(a+b) - C(a) - C(b), where C(a) + C(b) is known and fixed.
// Since the previous score passed is 'cost_threshold', we only need to compare
// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out
// early.
static double HistogramAddEval(const VP8LHistogram* const a,
const VP8LHistogram* const b,
VP8LHistogram* const out,
double cost_threshold) {
double cost = 0;
const double sum_cost = a->bit_cost_ + b->bit_cost_;
int i;
cost_threshold += sum_cost;
// palette_code_bits_ is part of the cost evaluation for literal_.
// TODO(skal): remove/simplify this palette_code_bits_?
out->palette_code_bits_ =
(a->palette_code_bits_ > b->palette_code_bits_) ? a->palette_code_bits_ :
b->palette_code_bits_;
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
out->literal_[i] = a->literal_[i] + b->literal_[i];
}
cost += PopulationCost(out->literal_, VP8LHistogramNumCodes(out));
cost += ExtraCost(out->literal_ + 256, NUM_LENGTH_CODES);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) out->red_[i] = a->red_[i] + b->red_[i];
cost += PopulationCost(out->red_, 256);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) out->blue_[i] = a->blue_[i] + b->blue_[i];
cost += PopulationCost(out->blue_, 256);
if (cost > cost_threshold) return cost;
for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
out->distance_[i] = a->distance_[i] + b->distance_[i];
}
cost += PopulationCost(out->distance_, NUM_DISTANCE_CODES);
cost += ExtraCost(out->distance_, NUM_DISTANCE_CODES);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) out->alpha_[i] = a->alpha_[i] + b->alpha_[i];
cost += PopulationCost(out->alpha_, 256);
out->bit_cost_ = cost;
return cost - sum_cost;
}
// Same as HistogramAddEval(), except that the resulting histogram
// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit
// the term C(b) which is constant over all the evaluations.
static double HistogramAddThresh(const VP8LHistogram* const a,
const VP8LHistogram* const b,
double cost_threshold) {
int tmp[PIX_OR_COPY_CODES_MAX]; // <= max storage we'll need
int i;
double cost = -a->bit_cost_;
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
tmp[i] = a->literal_[i] + b->literal_[i];
}
// note that the tests are ordered so that the usually largest
// cost shares come first.
cost += PopulationCost(tmp, VP8LHistogramNumCodes(a));
cost += ExtraCost(tmp + 256, NUM_LENGTH_CODES);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) tmp[i] = a->red_[i] + b->red_[i];
cost += PopulationCost(tmp, 256);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) tmp[i] = a->blue_[i] + b->blue_[i];
cost += PopulationCost(tmp, 256);
if (cost > cost_threshold) return cost;
for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
tmp[i] = a->distance_[i] + b->distance_[i];
}
cost += PopulationCost(tmp, NUM_DISTANCE_CODES);
cost += ExtraCost(tmp, NUM_DISTANCE_CODES);
if (cost > cost_threshold) return cost;
for (i = 0; i < 256; ++i) tmp[i] = a->alpha_[i] + b->alpha_[i];
cost += PopulationCost(tmp, 256);
return cost;
}
// -----------------------------------------------------------------------------
static void HistogramBuildImage(int xsize, int histo_bits, static void HistogramBuildImage(int xsize, int histo_bits,
const VP8LBackwardRefs* const backward_refs, const VP8LBackwardRefs* const backward_refs,
VP8LHistogramSet* const image) { VP8LHistogramSet* const image) {
@ -273,7 +383,7 @@ static int HistogramCombine(const VP8LHistogramSet* const in,
// Collapse similar histograms in 'out'. // Collapse similar histograms in 'out'.
for (iter = 0; iter < outer_iters && out_size >= min_cluster_size; ++iter) { for (iter = 0; iter < outer_iters && out_size >= min_cluster_size; ++iter) {
double best_cost_diff = 0.; double best_cost_diff = 0.;
int best_idx1 = 0, best_idx2 = 1; int best_idx1 = -1, best_idx2 = 1;
int j; int j;
const int num_tries = (num_pairs < out_size) ? num_pairs : out_size; const int num_tries = (num_pairs < out_size) ? num_pairs : out_size;
seed += iter; seed += iter;
@ -281,20 +391,17 @@ static int HistogramCombine(const VP8LHistogramSet* const in,
double curr_cost_diff; double curr_cost_diff;
// Choose two histograms at random and try to combine them. // Choose two histograms at random and try to combine them.
const uint32_t idx1 = MyRand(&seed) % out_size; const uint32_t idx1 = MyRand(&seed) % out_size;
const uint32_t tmp = ((j & 7) + 1) % (out_size - 1); const uint32_t tmp = (j & 7) + 1;
const uint32_t diff = (tmp < 3) ? tmp : MyRand(&seed) % (out_size - 1); const uint32_t diff = (tmp < 3) ? tmp : MyRand(&seed) % (out_size - 1);
const uint32_t idx2 = (idx1 + diff + 1) % out_size; const uint32_t idx2 = (idx1 + diff + 1) % out_size;
if (idx1 == idx2) { if (idx1 == idx2) {
continue; continue;
} }
*cur_combo = *out->histograms[idx1];
VP8LHistogramAdd(cur_combo, out->histograms[idx2]);
cur_combo->bit_cost_ = VP8LHistogramEstimateBits(cur_combo);
// Calculate cost reduction on combining. // Calculate cost reduction on combining.
curr_cost_diff = cur_combo->bit_cost_ curr_cost_diff = HistogramAddEval(out->histograms[idx1],
- out->histograms[idx1]->bit_cost_ out->histograms[idx2],
- out->histograms[idx2]->bit_cost_; cur_combo, best_cost_diff);
if (best_cost_diff > curr_cost_diff) { // found a better pair? if (curr_cost_diff < best_cost_diff) { // found a better pair?
{ // swap cur/best combo histograms { // swap cur/best combo histograms
VP8LHistogram* const tmp_histo = cur_combo; VP8LHistogram* const tmp_histo = cur_combo;
cur_combo = best_combo; cur_combo = best_combo;
@ -306,7 +413,7 @@ static int HistogramCombine(const VP8LHistogramSet* const in,
} }
} }
if (best_cost_diff < 0.0) { if (best_idx1 >= 0) {
*out->histograms[best_idx1] = *best_combo; *out->histograms[best_idx1] = *best_combo;
// swap best_idx2 slot with last one (which is now unused) // swap best_idx2 slot with last one (which is now unused)
--out_size; --out_size;
@ -331,20 +438,11 @@ static int HistogramCombine(const VP8LHistogramSet* const in,
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Histogram refinement // Histogram refinement
// What is the bit cost of moving square_histogram from // What is the bit cost of moving square_histogram from cur_symbol to candidate.
// cur_symbol to candidate_symbol.
// TODO(skal): we don't really need to copy the histogram and Add(). Instead
// we just need VP8LDualHistogramEstimateBits(A, B) estimation function.
static double HistogramDistance(const VP8LHistogram* const square_histogram, static double HistogramDistance(const VP8LHistogram* const square_histogram,
const VP8LHistogram* const candidate) { const VP8LHistogram* const candidate,
const double previous_bit_cost = candidate->bit_cost_; double cost_threshold) {
double new_bit_cost; return HistogramAddThresh(candidate, square_histogram, cost_threshold);
VP8LHistogram modified_histo;
modified_histo = *candidate;
VP8LHistogramAdd(&modified_histo, square_histogram);
new_bit_cost = VP8LHistogramEstimateBits(&modified_histo);
return new_bit_cost - previous_bit_cost;
} }
// Find the best 'out' histogram for each of the 'in' histograms. // Find the best 'out' histogram for each of the 'in' histograms.
@ -355,11 +453,12 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
int i; int i;
for (i = 0; i < in->size; ++i) { for (i = 0; i < in->size; ++i) {
int best_out = 0; int best_out = 0;
double best_bits = HistogramDistance(in->histograms[i], out->histograms[0]); double best_bits =
HistogramDistance(in->histograms[i], out->histograms[0], 1.e38);
int k; int k;
for (k = 1; k < out->size; ++k) { for (k = 1; k < out->size; ++k) {
const double cur_bits = const double cur_bits =
HistogramDistance(in->histograms[i], out->histograms[k]); HistogramDistance(in->histograms[i], out->histograms[k], best_bits);
if (cur_bits < best_bits) { if (cur_bits < best_bits) {
best_bits = cur_bits; best_bits = cur_bits;
best_out = k; best_out = k;
@ -373,7 +472,7 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
HistogramClear(out->histograms[i]); HistogramClear(out->histograms[i]);
} }
for (i = 0; i < in->size; ++i) { for (i = 0; i < in->size; ++i) {
VP8LHistogramAdd(out->histograms[symbols[i]], in->histograms[i]); HistogramAdd(in->histograms[i], out->histograms[symbols[i]]);
} }
} }

View File

@ -80,22 +80,6 @@ double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
// represent the entropy code itself. // represent the entropy code itself.
double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p); double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p);
static WEBP_INLINE void VP8LHistogramAdd(VP8LHistogram* const p,
const VP8LHistogram* const a) {
int i;
for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
p->literal_[i] += a->literal_[i];
}
for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
p->distance_[i] += a->distance_[i];
}
for (i = 0; i < 256; ++i) {
p->red_[i] += a->red_[i];
p->blue_[i] += a->blue_[i];
p->alpha_[i] += a->alpha_[i];
}
}
static WEBP_INLINE int VP8LHistogramNumCodes(const VP8LHistogram* const p) { static WEBP_INLINE int VP8LHistogramNumCodes(const VP8LHistogram* const p) {
return 256 + NUM_LENGTH_CODES + return 256 + NUM_LENGTH_CODES +
((p->palette_code_bits_ > 0) ? (1 << p->palette_code_bits_) : 0); ((p->palette_code_bits_ > 0) ? (1 << p->palette_code_bits_) : 0);

View File

@ -12,7 +12,8 @@
#include <assert.h> #include <assert.h>
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../webp/format_constants.h" #include "../webp/format_constants.h" // RIFF constants
#include "../webp/mux_types.h" // ALPHA_FLAG
#include "./vp8enci.h" #include "./vp8enci.h"
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)

View File

@ -27,8 +27,8 @@ extern "C" {
// version numbers // version numbers
#define ENC_MAJ_VERSION 0 #define ENC_MAJ_VERSION 0
#define ENC_MIN_VERSION 2 #define ENC_MIN_VERSION 3
#define ENC_REV_VERSION 1 #define ENC_REV_VERSION 0
// intra prediction modes // intra prediction modes
enum { B_DC_PRED = 0, // 4x4 modes enum { B_DC_PRED = 0, // 4x4 modes
@ -55,8 +55,9 @@ enum { NUM_MB_SEGMENTS = 4,
NUM_BANDS = 8, NUM_BANDS = 8,
NUM_CTX = 3, NUM_CTX = 3,
NUM_PROBAS = 11, NUM_PROBAS = 11,
MAX_LF_LEVELS = 64, // Maximum loop filter level MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67 // last (inclusive) level with variable cost MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
MAX_LEVEL = 2047 // max level (note: max codable is 2047 + 67)
}; };
typedef enum { // Rate-distortion optimization levels typedef enum { // Rate-distortion optimization levels

View File

@ -563,6 +563,9 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
goto Error; goto Error;
} }
// Free combined histograms.
free(histogram_image);
histogram_image = NULL;
// Color Cache parameters. // Color Cache parameters.
VP8LWriteBits(bw, 1, use_color_cache); VP8LWriteBits(bw, 1, use_color_cache);
@ -609,9 +612,6 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
ClearHuffmanTreeIfOnlyOneSymbol(codes); ClearHuffmanTreeIfOnlyOneSymbol(codes);
} }
} }
// Free combined histograms.
free(histogram_image);
histogram_image = NULL;
// Store actual literals. // Store actual literals.
StoreImageToBitMask(bw, width, histogram_bits, &refs, StoreImageToBitMask(bw, width, histogram_bits, &refs,
@ -619,7 +619,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
ok = 1; ok = 1;
Error: Error:
if (!ok) free(histogram_image); free(histogram_image);
VP8LClearBackwardRefs(&refs); VP8LClearBackwardRefs(&refs);
if (huffman_codes != NULL) { if (huffman_codes != NULL) {

View File

@ -8,4 +8,4 @@ Description: Library for the WebP graphics format
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Cflags: -I${includedir} Cflags: -I${includedir}
Libs: -L${libdir} -lwebp Libs: -L${libdir} -lwebp
Libs.private: -lm Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@

View File

@ -8,4 +8,4 @@ Description: Library for the WebP graphics format (decode only)
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Cflags: -I${includedir} Cflags: -I${includedir}
Libs: -L${libdir} -lwebpdecoder Libs: -L${libdir} -lwebpdecoder
Libs.private: -lm Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@

View File

@ -9,7 +9,10 @@ libwebpmux_la_SOURCES += muxread.c
libwebpmuxinclude_HEADERS = libwebpmuxinclude_HEADERS =
libwebpmuxinclude_HEADERS += ../webp/mux.h libwebpmuxinclude_HEADERS += ../webp/mux.h
libwebpmuxinclude_HEADERS += ../webp/mux_types.h
libwebpmuxinclude_HEADERS += ../webp/types.h libwebpmuxinclude_HEADERS += ../webp/types.h
libwebpmux_la_LDFLAGS = -version-info 0:0:0 libwebpmux_la_LIBADD = ../libwebp.la
libwebpmux_la_LDFLAGS = -no-undefined -version-info 0:0:0
libwebpmuxincludedir = $(includedir)/webp libwebpmuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpmux.pc

11
src/mux/libwebpmux.pc.in Normal file
View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libwebpmux
Description: Library for manipulating the WebP graphics format container
Version: @PACKAGE_VERSION@
Requires: libwebp >= 0.2.0
Cflags: -I${includedir}
Libs: -L${libdir} -lwebpmux

View File

@ -306,6 +306,11 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame,
if (!(is_frame || (frame->id == WEBP_CHUNK_FRGM))) { if (!(is_frame || (frame->id == WEBP_CHUNK_FRGM))) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
#ifndef WEBP_EXPERIMENTAL_FEATURES
if (frame->id == WEBP_CHUNK_FRGM) { // disabled for now.
return WEBP_MUX_INVALID_ARGUMENT;
}
#endif
if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) { if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;

View File

@ -121,7 +121,8 @@ WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
// Sets 'chunk' at nth position in the 'chunk_list'. // Sets 'chunk' at nth position in the 'chunk_list'.
// nth = 0 has the special meaning "last of the list". // nth = 0 has the special meaning "last of the list".
WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list, // On success ownership is transferred from 'chunk' to the 'chunk_list'.
WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
uint32_t nth); uint32_t nth);
// Releases chunk and returns chunk->next_. // Releases chunk and returns chunk->next_.

View File

@ -96,7 +96,7 @@ CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]) {
// Returns next chunk in the chunk list with the given tag. // Returns next chunk in the chunk list with the given tag.
static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) { static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) {
while (chunk && chunk->tag_ != tag) { while (chunk != NULL && chunk->tag_ != tag) {
chunk = chunk->next_; chunk = chunk->next_;
} }
return chunk; return chunk;
@ -105,7 +105,7 @@ static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) {
WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) { WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) {
uint32_t iter = nth; uint32_t iter = nth;
first = ChunkSearchNextInList(first, tag); first = ChunkSearchNextInList(first, tag);
if (!first) return NULL; if (first == NULL) return NULL;
while (--iter != 0) { while (--iter != 0) {
WebPChunk* next_chunk = ChunkSearchNextInList(first->next_, tag); WebPChunk* next_chunk = ChunkSearchNextInList(first->next_, tag);
@ -121,10 +121,10 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) {
static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth, static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth,
WebPChunk*** const location) { WebPChunk*** const location) {
uint32_t count = 0; uint32_t count = 0;
assert(chunk_list); assert(chunk_list != NULL);
*location = chunk_list; *location = chunk_list;
while (*chunk_list) { while (*chunk_list != NULL) {
WebPChunk* const cur_chunk = *chunk_list; WebPChunk* const cur_chunk = *chunk_list;
++count; ++count;
if (count == nth) return 1; // Found. if (count == nth) return 1; // Found.
@ -149,27 +149,18 @@ WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
ChunkRelease(chunk); ChunkRelease(chunk);
if (data != NULL) { if (data != NULL) {
if (copy_data) { if (copy_data) { // Copy data.
// Copy data. if (!WebPDataCopy(data, &chunk->data_)) return WEBP_MUX_MEMORY_ERROR;
chunk->data_.bytes = (uint8_t*)malloc(data->size); chunk->owner_ = 1; // Chunk is owner of data.
if (chunk->data_.bytes == NULL) return WEBP_MUX_MEMORY_ERROR; } else { // Don't copy data.
memcpy((uint8_t*)chunk->data_.bytes, data->bytes, data->size);
chunk->data_.size = data->size;
// Chunk is owner of data.
chunk->owner_ = 1;
} else {
// Don't copy data.
chunk->data_ = *data; chunk->data_ = *data;
} }
} }
chunk->tag_ = tag; chunk->tag_ = tag;
return WEBP_MUX_OK; return WEBP_MUX_OK;
} }
WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list, WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
uint32_t nth) { uint32_t nth) {
WebPChunk* new_chunk; WebPChunk* new_chunk;
@ -180,6 +171,7 @@ WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk)); new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk));
if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR; if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR;
*new_chunk = *chunk; *new_chunk = *chunk;
chunk->owner_ = 0;
new_chunk->next_ = *chunk_list; new_chunk->next_ = *chunk_list;
*chunk_list = new_chunk; *chunk_list = new_chunk;
return WEBP_MUX_OK; return WEBP_MUX_OK;
@ -199,7 +191,7 @@ WebPChunk* ChunkDelete(WebPChunk* const chunk) {
size_t ChunksListDiskSize(const WebPChunk* chunk_list) { size_t ChunksListDiskSize(const WebPChunk* chunk_list) {
size_t size = 0; size_t size = 0;
while (chunk_list) { while (chunk_list != NULL) {
size += ChunkDiskSize(chunk_list); size += ChunkDiskSize(chunk_list);
chunk_list = chunk_list->next_; chunk_list = chunk_list->next_;
} }
@ -220,7 +212,7 @@ static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) {
} }
uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) { uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) {
while (chunk_list) { while (chunk_list != NULL) {
dst = ChunkEmit(chunk_list, dst); dst = ChunkEmit(chunk_list, dst);
chunk_list = chunk_list->next_; chunk_list = chunk_list->next_;
} }
@ -281,7 +273,7 @@ static int SearchImageToGetOrDelete(WebPMuxImage** wpi_list, uint32_t nth,
if (nth == 0) return 0; // Not found. if (nth == 0) return 0; // Not found.
} }
while (*wpi_list) { while (*wpi_list != NULL) {
WebPMuxImage* const cur_wpi = *wpi_list; WebPMuxImage* const cur_wpi = *wpi_list;
++count; ++count;
if (count == nth) return 1; // Found. if (count == nth) return 1; // Found.
@ -327,7 +319,7 @@ WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) {
} }
void MuxImageDeleteAll(WebPMuxImage** const wpi_list) { void MuxImageDeleteAll(WebPMuxImage** const wpi_list) {
while (*wpi_list) { while (*wpi_list != NULL) {
*wpi_list = MuxImageDelete(*wpi_list); *wpi_list = MuxImageDelete(*wpi_list);
} }
} }
@ -370,7 +362,7 @@ size_t MuxImageDiskSize(const WebPMuxImage* const wpi) {
size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list) { size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list) {
size_t size = 0; size_t size = 0;
while (wpi_list) { while (wpi_list != NULL) {
size += MuxImageDiskSize(wpi_list); size += MuxImageDiskSize(wpi_list);
wpi_list = wpi_list->next_; wpi_list = wpi_list->next_;
} }
@ -409,7 +401,7 @@ uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) {
} }
uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) { uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) {
while (wpi_list) { while (wpi_list != NULL) {
dst = MuxImageEmit(wpi_list, dst); dst = MuxImageEmit(wpi_list, dst);
wpi_list = wpi_list->next_; wpi_list = wpi_list->next_;
} }

View File

@ -223,7 +223,9 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
MuxImageInit(wpi); // Reset for reading next image. MuxImageInit(wpi); // Reset for reading next image.
break; break;
case WEBP_CHUNK_ANMF: case WEBP_CHUNK_ANMF:
#ifdef WEBP_EXPERIMENTAL_FEATURES
case WEBP_CHUNK_FRGM: case WEBP_CHUNK_FRGM:
#endif
if (wpi->is_partial_) goto Err; // Previous wpi is still incomplete. if (wpi->is_partial_) goto Err; // Previous wpi is still incomplete.
if (!MuxImageParse(&chunk, copy_data, wpi)) goto Err; if (!MuxImageParse(&chunk, copy_data, wpi)) goto Err;
ChunkRelease(&chunk); ChunkRelease(&chunk);
@ -378,6 +380,9 @@ static WebPMuxError MuxGetFrameFragmentInternal(const WebPMuxImage* const wpi,
const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag); const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag);
const CHUNK_INDEX idx = is_frame ? IDX_ANMF : IDX_FRGM; const CHUNK_INDEX idx = is_frame ? IDX_ANMF : IDX_FRGM;
const WebPData* frame_frgm_data; const WebPData* frame_frgm_data;
#ifndef WEBP_EXPERIMENTAL_FEATURES
if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT;
#endif
assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame(). assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame().
// Get frame/fragment chunk. // Get frame/fragment chunk.
frame_frgm_data = &wpi->header_->data_; frame_frgm_data = &wpi->header_->data_;

View File

@ -5,7 +5,10 @@ if BUILD_LIBWEBPDECODER
noinst_LTLIBRARIES += libwebputilsdecode.la noinst_LTLIBRARIES += libwebputilsdecode.la
endif endif
COMMON_SOURCES = common_HEADERS = ../webp/types.h
commondir = $(includedir)/webp
COMMON_SOURCES =
COMMON_SOURCES += bit_reader.c COMMON_SOURCES += bit_reader.c
COMMON_SOURCES += bit_reader.h COMMON_SOURCES += bit_reader.h
COMMON_SOURCES += color_cache.c COMMON_SOURCES += color_cache.c
@ -23,7 +26,7 @@ COMMON_SOURCES += thread.h
COMMON_SOURCES += utils.c COMMON_SOURCES += utils.c
COMMON_SOURCES += utils.h COMMON_SOURCES += utils.h
ENC_SOURCES = ENC_SOURCES =
ENC_SOURCES += bit_writer.c ENC_SOURCES += bit_writer.c
ENC_SOURCES += bit_writer.h ENC_SOURCES += bit_writer.h
ENC_SOURCES += huffman_encode.c ENC_SOURCES += huffman_encode.c
@ -31,15 +34,8 @@ ENC_SOURCES += huffman_encode.h
ENC_SOURCES += quant_levels.c ENC_SOURCES += quant_levels.c
ENC_SOURCES += quant_levels.h ENC_SOURCES += quant_levels.h
libwebputils_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES) libwebputils_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES)
libwebputilsinclude_HEADERS = ../webp/types.h
libwebputilsincludedir = $(includedir)/webp
if BUILD_LIBWEBPDECODER if BUILD_LIBWEBPDECODER
libwebputilsdecode_la_SOURCES = $(COMMON_SOURCES) libwebputilsdecode_la_SOURCES = $(COMMON_SOURCES)
libwebputilsdecodeinclude_HEADERS = $(libwebputilsinclude_HEADERS)
libwebputilsdecodeincludedir = $(libwebputilsincludedir)
endif endif

View File

@ -59,7 +59,7 @@ extern "C" {
// The right-justify strategy tends to use less shifts and is often faster. // The right-justify strategy tends to use less shifts and is often faster.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// BITS can be either 32, 24, 16 or 8. // BITS can be any multiple of 8 from 8 to 56 (inclusive).
// Pick values that fit natural register size. // Pick values that fit natural register size.
#if !defined(WEBP_REFERENCE_IMPLEMENTATION) #if !defined(WEBP_REFERENCE_IMPLEMENTATION)
@ -68,7 +68,9 @@ extern "C" {
#if defined(__i386__) || defined(_M_IX86) // x86 32bit #if defined(__i386__) || defined(_M_IX86) // x86 32bit
#define BITS 16 #define BITS 16
#elif defined(__arm__) || defined(_M_ARM) // ARM #elif defined(__x86_64__) || defined(_M_X64) // x86 64bit
#define BITS 56
#elif defined(__arm__) || defined(_M_ARM) // ARM
#define BITS 24 #define BITS 24
#else // reasonable default #else // reasonable default
#define BITS 24 #define BITS 24
@ -84,9 +86,15 @@ extern "C" {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Derived types and constants // Derived types and constants
#if (BITS == 32) // bit_t = natural register type
typedef uint64_t bit_t; // natural register type // lbit_t = natural type for memory I/O
typedef uint32_t lbit_t; // natural type for memory I/O
#if (BITS > 32)
typedef uint64_t bit_t;
typedef uint64_t lbit_t;
#elif (BITS == 32)
typedef uint64_t bit_t;
typedef uint32_t lbit_t;
#elif (BITS == 24) #elif (BITS == 24)
typedef uint32_t bit_t; typedef uint32_t bit_t;
typedef uint32_t lbit_t; typedef uint32_t lbit_t;
@ -148,19 +156,36 @@ static WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* const br) {
lbit_t in_bits = *(lbit_t*)br->buf_; lbit_t in_bits = *(lbit_t*)br->buf_;
br->buf_ += (BITS) >> 3; br->buf_ += (BITS) >> 3;
#if !defined(__BIG_ENDIAN__) #if !defined(__BIG_ENDIAN__)
#if (BITS == 32) || (BITS == 24) #if (BITS > 32)
// gcc 4.3 has builtin functions for swap32/swap64
#if defined(__GNUC__) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
bits = (bit_t)__builtin_bswap64(in_bits);
#elif defined(_MSC_VER)
bits = (bit_t)_byteswap_uint64(in_bits);
#elif defined(__x86_64__)
__asm__ volatile("bswapq %0" : "=r"(bits) : "0"(in_bits));
#else // generic code for swapping 64-bit values (suggested by bdb@)
bits = (bit_t)in_bits;
bits = ((bits & 0xffffffff00000000ull) >> 32) |
((bits & 0x00000000ffffffffull) << 32);
bits = ((bits & 0xffff0000ffff0000ull) >> 16) |
((bits & 0x0000ffff0000ffffull) << 16);
bits = ((bits & 0xff00ff00ff00ff00ull) >> 8) |
((bits & 0x00ff00ff00ff00ffull) << 8);
#endif
bits >>= 64 - BITS;
#elif (BITS >= 24)
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
__asm__ volatile("bswap %k0" : "=r"(in_bits) : "0"(in_bits)); __asm__ volatile("bswap %k0" : "=r"(in_bits) : "0"(in_bits));
bits = (bit_t)in_bits; // 24b/32b -> 32b/64b zero-extension bits = (bit_t)in_bits; // 24b/32b -> 32b/64b zero-extension
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
bits = _byteswap_ulong(in_bits); bits = (bit_t)_byteswap_ulong(in_bits);
#else #else
bits = (bit_t)(in_bits >> 24) | ((in_bits >> 8) & 0xff00) bits = (bit_t)(in_bits >> 24) | ((in_bits >> 8) & 0xff00)
| ((in_bits << 8) & 0xff0000) | (in_bits << 24); | ((in_bits << 8) & 0xff0000) | (in_bits << 24);
#endif // x86 #endif // x86
#if (BITS == 24) bits >>= (32 - BITS);
bits >>= 8;
#endif
#elif (BITS == 16) #elif (BITS == 16)
// gcc will recognize a 'rorw $8, ...' here: // gcc will recognize a 'rorw $8, ...' here:
bits = (bit_t)(in_bits >> 8) | ((in_bits & 0xff) << 8); bits = (bit_t)(in_bits >> 8) | ((in_bits & 0xff) << 8);
@ -248,7 +273,7 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
} }
static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) { static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) {
const bit_t split = (br->range_ >> 1); const range_t split = (br->range_ >> 1);
const int bit = VP8BitUpdate(br, split); const int bit = VP8BitUpdate(br, split);
VP8Shift(br); VP8Shift(br);
return bit ? -v : v; return bit ? -v : v;

View File

@ -26,8 +26,7 @@ extern "C" {
assert(out != NULL); \ assert(out != NULL); \
assert(width > 0); \ assert(width > 0); \
assert(height > 0); \ assert(height > 0); \
assert(bpp > 0); \ assert(stride >= width);
assert(stride >= width * bpp);
static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred, static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
uint8_t* dst, int length, int inverse) { uint8_t* dst, int length, int inverse) {
@ -43,7 +42,8 @@ static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
// Horizontal filter. // Horizontal filter.
static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in, static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
int width, int height, int bpp, int stride, int inverse, uint8_t* out) { int width, int height, int stride,
int inverse, uint8_t* out) {
int h; int h;
const uint8_t* preds = (inverse ? out : in); const uint8_t* preds = (inverse ? out : in);
SANITY_CHECK(in, out); SANITY_CHECK(in, out);
@ -52,11 +52,11 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
for (h = 0; h < height; ++h) { for (h = 0; h < height; ++h) {
// Leftmost pixel is predicted from above (except for topmost scanline). // Leftmost pixel is predicted from above (except for topmost scanline).
if (h == 0) { if (h == 0) {
memcpy((void*)out, (const void*)in, bpp); out[0] = in[0];
} else { } else {
PredictLine(in, preds - stride, out, bpp, inverse); PredictLine(in, preds - stride, out, 1, inverse);
} }
PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); PredictLine(in + 1, preds, out + 1, width - 1, inverse);
preds += stride; preds += stride;
in += stride; in += stride;
out += stride; out += stride;
@ -64,46 +64,46 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
} }
static void HorizontalFilter(const uint8_t* data, int width, int height, static void HorizontalFilter(const uint8_t* data, int width, int height,
int bpp, int stride, uint8_t* filtered_data) { int stride, uint8_t* filtered_data) {
DoHorizontalFilter(data, width, height, bpp, stride, 0, filtered_data); DoHorizontalFilter(data, width, height, stride, 0, filtered_data);
} }
static void HorizontalUnfilter(const uint8_t* data, int width, int height, static void HorizontalUnfilter(int width, int height, int stride,
int bpp, int stride, uint8_t* recon_data) { uint8_t* data) {
DoHorizontalFilter(data, width, height, bpp, stride, 1, recon_data); DoHorizontalFilter(data, width, height, stride, 1, data);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Vertical filter. // Vertical filter.
static WEBP_INLINE void DoVerticalFilter(const uint8_t* in, static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
int width, int height, int bpp, int stride, int inverse, uint8_t* out) { int width, int height, int stride,
int inverse, uint8_t* out) {
int h; int h;
const uint8_t* preds = (inverse ? out : in); const uint8_t* preds = (inverse ? out : in);
SANITY_CHECK(in, out); SANITY_CHECK(in, out);
// Very first top-left pixel is copied. // Very first top-left pixel is copied.
memcpy((void*)out, (const void*)in, bpp); out[0] = in[0];
// Rest of top scan-line is left-predicted. // Rest of top scan-line is left-predicted.
PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); PredictLine(in + 1, preds, out + 1, width - 1, inverse);
// Filter line-by-line. // Filter line-by-line.
for (h = 1; h < height; ++h) { for (h = 1; h < height; ++h) {
in += stride; in += stride;
out += stride; out += stride;
PredictLine(in, preds, out, bpp * width, inverse); PredictLine(in, preds, out, width, inverse);
preds += stride; preds += stride;
} }
} }
static void VerticalFilter(const uint8_t* data, int width, int height, static void VerticalFilter(const uint8_t* data, int width, int height,
int bpp, int stride, uint8_t* filtered_data) { int stride, uint8_t* filtered_data) {
DoVerticalFilter(data, width, height, bpp, stride, 0, filtered_data); DoVerticalFilter(data, width, height, stride, 0, filtered_data);
} }
static void VerticalUnfilter(const uint8_t* data, int width, int height, static void VerticalUnfilter(int width, int height, int stride, uint8_t* data) {
int bpp, int stride, uint8_t* recon_data) { DoVerticalFilter(data, width, height, stride, 1, data);
DoVerticalFilter(data, width, height, bpp, stride, 1, recon_data);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -111,19 +111,19 @@ static void VerticalUnfilter(const uint8_t* data, int width, int height,
static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
const int g = a + b - c; const int g = a + b - c;
return (g < 0) ? 0 : (g > 255) ? 255 : g; return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
} }
static WEBP_INLINE static WEBP_INLINE
void DoGradientFilter(const uint8_t* in, int width, int height, void DoGradientFilter(const uint8_t* in, int width, int height,
int bpp, int stride, int inverse, uint8_t* out) { int stride, int inverse, uint8_t* out) {
const uint8_t* preds = (inverse ? out : in); const uint8_t* preds = (inverse ? out : in);
int h; int h;
SANITY_CHECK(in, out); SANITY_CHECK(in, out);
// left prediction for top scan-line // left prediction for top scan-line
memcpy((void*)out, (const void*)in, bpp); out[0] = in[0];
PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); PredictLine(in + 1, preds, out + 1, width - 1, inverse);
// Filter line-by-line. // Filter line-by-line.
for (h = 1; h < height; ++h) { for (h = 1; h < height; ++h) {
@ -132,24 +132,23 @@ void DoGradientFilter(const uint8_t* in, int width, int height,
in += stride; in += stride;
out += stride; out += stride;
// leftmost pixel: predict from above. // leftmost pixel: predict from above.
PredictLine(in, preds - stride, out, bpp, inverse); PredictLine(in, preds - stride, out, 1, inverse);
for (w = bpp; w < width * bpp; ++w) { for (w = 1; w < width; ++w) {
const int pred = GradientPredictor(preds[w - bpp], const int pred = GradientPredictor(preds[w - 1],
preds[w - stride], preds[w - stride],
preds[w - stride - bpp]); preds[w - stride - 1]);
out[w] = in[w] + (inverse ? pred : -pred); out[w] = in[w] + (inverse ? pred : -pred);
} }
} }
} }
static void GradientFilter(const uint8_t* data, int width, int height, static void GradientFilter(const uint8_t* data, int width, int height,
int bpp, int stride, uint8_t* filtered_data) { int stride, uint8_t* filtered_data) {
DoGradientFilter(data, width, height, bpp, stride, 0, filtered_data); DoGradientFilter(data, width, height, stride, 0, filtered_data);
} }
static void GradientUnfilter(const uint8_t* data, int width, int height, static void GradientUnfilter(int width, int height, int stride, uint8_t* data) {
int bpp, int stride, uint8_t* recon_data) { DoGradientFilter(data, width, height, stride, 1, data);
DoGradientFilter(data, width, height, bpp, stride, 1, recon_data);
} }
#undef SANITY_CHECK #undef SANITY_CHECK
@ -215,7 +214,7 @@ const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = {
GradientFilter // WEBP_FILTER_GRADIENT GradientFilter // WEBP_FILTER_GRADIENT
}; };
const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = { const WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST] = {
NULL, // WEBP_FILTER_NONE NULL, // WEBP_FILTER_NONE
HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL
VerticalUnfilter, // WEBP_FILTER_VERTICAL VerticalUnfilter, // WEBP_FILTER_VERTICAL

View File

@ -30,18 +30,19 @@ typedef enum {
} WEBP_FILTER_TYPE; } WEBP_FILTER_TYPE;
typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height, typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height,
int bpp, int stride, uint8_t* out); int stride, uint8_t* out);
typedef void (*WebPUnfilterFunc)(int width, int height, int stride,
uint8_t* data);
// Filter the given data using the given predictor. // Filter the given data using the given predictor.
// 'in' corresponds to a 2-dimensional pixel array of size (stride * height) // 'in' corresponds to a 2-dimensional pixel array of size (stride * height)
// in raster order. // in raster order.
// 'bpp' is number of bytes per pixel, and
// 'stride' is number of bytes per scan line (with possible padding). // 'stride' is number of bytes per scan line (with possible padding).
// 'out' should be pre-allocated. // 'out' should be pre-allocated.
extern const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; extern const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
// Reconstruct the original data from the given filtered data. // In-place reconstruct the original data from the given filtered data.
extern const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST]; extern const WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
// Fast estimate of a potentially good filter. // Fast estimate of a potentially good filter.
extern WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data, extern WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,

View File

@ -18,7 +18,7 @@
extern "C" { extern "C" {
#endif #endif
#define WEBP_DECODER_ABI_VERSION 0x0200 // MAJOR(8b) + MINOR(8b) #define WEBP_DECODER_ABI_VERSION 0x0201 // MAJOR(8b) + MINOR(8b)
typedef struct WebPRGBABuffer WebPRGBABuffer; typedef struct WebPRGBABuffer WebPRGBABuffer;
typedef struct WebPYUVABuffer WebPYUVABuffer; typedef struct WebPYUVABuffer WebPYUVABuffer;
@ -392,9 +392,10 @@ WEBP_EXTERN(const WebPDecBuffer*) WebPIDecodedArea(
// Features gathered from the bitstream // Features gathered from the bitstream
struct WebPBitstreamFeatures { struct WebPBitstreamFeatures {
int width; // Width in pixels, as read from the bitstream. int width; // Width in pixels, as read from the bitstream.
int height; // Height in pixels, as read from the bitstream. int height; // Height in pixels, as read from the bitstream.
int has_alpha; // True if the bitstream contains an alpha channel. int has_alpha; // True if the bitstream contains an alpha channel.
int has_animation; // True if the bitstream is an animation.
// Unused for now: // Unused for now:
int bitstream_version; // should be 0 for now. TODO(later) int bitstream_version; // should be 0 for now. TODO(later)
@ -402,7 +403,7 @@ struct WebPBitstreamFeatures {
// recommended. // recommended.
int rotate; // TODO(later) int rotate; // TODO(later)
int uv_sampling; // should be 0 for now. TODO(later) int uv_sampling; // should be 0 for now. TODO(later)
uint32_t pad[3]; // padding for later use uint32_t pad[2]; // padding for later use
}; };
// Internal, version-checked, entry point // Internal, version-checked, entry point

View File

@ -45,7 +45,6 @@
#ifndef WEBP_WEBP_DEMUX_H_ #ifndef WEBP_WEBP_DEMUX_H_
#define WEBP_WEBP_DEMUX_H_ #define WEBP_WEBP_DEMUX_H_
#include "./format_constants.h"
#include "./mux_types.h" #include "./mux_types.h"
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
@ -81,14 +80,13 @@ enum WebPDemuxState {
WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal( WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal(
const WebPData*, int, WebPDemuxState*, int); const WebPData*, int, WebPDemuxState*, int);
// Parses the WebP file given by 'data'. // Parses the full WebP file given by 'data'.
// A complete WebP file must be present in 'data' for the function to succeed.
// Returns a WebPDemuxer object on successful parse, NULL otherwise. // Returns a WebPDemuxer object on successful parse, NULL otherwise.
static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) { static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION); return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION);
} }
// Parses the WebP file given by 'data'. // Parses the possibly incomplete WebP file given by 'data'.
// If 'state' is non-NULL it will be set to indicate the status of the demuxer. // If 'state' is non-NULL it will be set to indicate the status of the demuxer.
// Returns a WebPDemuxer object on successful parse, NULL otherwise. // Returns a WebPDemuxer object on successful parse, NULL otherwise.
static WEBP_INLINE WebPDemuxer* WebPDemuxPartial( static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(

View File

@ -12,6 +12,9 @@
#ifndef WEBP_WEBP_FORMAT_CONSTANTS_H_ #ifndef WEBP_WEBP_FORMAT_CONSTANTS_H_
#define WEBP_WEBP_FORMAT_CONSTANTS_H_ #define WEBP_WEBP_FORMAT_CONSTANTS_H_
// Create fourcc of the chunk from the chunk tag characters.
#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24)
// VP8 related constants. // VP8 related constants.
#define VP8_SIGNATURE 0x9d012a // Signature in VP8 data. #define VP8_SIGNATURE 0x9d012a // Signature in VP8 data.
#define VP8_MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition #define VP8_MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition
@ -70,19 +73,6 @@ typedef enum {
#define FRGM_CHUNK_SIZE 6 // Size of a FRGM chunk. #define FRGM_CHUNK_SIZE 6 // Size of a FRGM chunk.
#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk. #define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk.
// VP8X Feature Flags.
#if !(defined(__cplusplus) || defined(c_plusplus))
typedef enum WebPFeatureFlags WebPFeatureFlags;
#endif
enum WebPFeatureFlags {
FRAGMENTS_FLAG = 0x00000001,
ANIMATION_FLAG = 0x00000002,
XMP_FLAG = 0x00000004,
EXIF_FLAG = 0x00000008,
ALPHA_FLAG = 0x00000010,
ICCP_FLAG = 0x00000020
};
#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height. #define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. #define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height.
#define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count #define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count

View File

@ -45,7 +45,6 @@
#ifndef WEBP_WEBP_MUX_H_ #ifndef WEBP_WEBP_MUX_H_
#define WEBP_WEBP_MUX_H_ #define WEBP_WEBP_MUX_H_
#include "./format_constants.h"
#include "./mux_types.h" #include "./mux_types.h"
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)

View File

@ -5,7 +5,7 @@
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// //
// Internal header for some common data-types used by mux and demux libraries. // Data-types common to the mux and demux libraries.
// //
// Author: Urvang (urvang@google.com) // Author: Urvang (urvang@google.com)
@ -20,14 +20,23 @@
extern "C" { extern "C" {
#endif #endif
// Create fourcc of the chunk from the chunk tag characters. #if !(defined(__cplusplus) || defined(c_plusplus))
#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24) typedef enum WebPFeatureFlags WebPFeatureFlags;
typedef enum WebPMuxAnimDispose WebPMuxAnimDispose;
#endif
// VP8X Feature Flags.
enum WebPFeatureFlags {
FRAGMENTS_FLAG = 0x00000001,
ANIMATION_FLAG = 0x00000002,
XMP_FLAG = 0x00000004,
EXIF_FLAG = 0x00000008,
ALPHA_FLAG = 0x00000010,
ICCP_FLAG = 0x00000020
};
// Dispose method (animation only). Indicates how the area used by the current // Dispose method (animation only). Indicates how the area used by the current
// frame is to be treated before rendering the next frame on the canvas. // frame is to be treated before rendering the next frame on the canvas.
#if !(defined(__cplusplus) || defined(c_plusplus))
typedef enum WebPMuxAnimDispose WebPMuxAnimDispose;
#endif
enum WebPMuxAnimDispose { enum WebPMuxAnimDispose {
WEBP_MUX_DISPOSE_NONE, // Do not dispose. WEBP_MUX_DISPOSE_NONE, // Do not dispose.
WEBP_MUX_DISPOSE_BACKGROUND // Dispose to background color. WEBP_MUX_DISPOSE_BACKGROUND // Dispose to background color.