Compare commits

..

21 Commits

Author SHA1 Message Date
1e0d4b8c8b Update ChangeLog
Change-Id: I381ab93458df3d1851aec36161cc4b2cbd1265be
2013-03-29 15:55:16 -07:00
d52b405dbd Cosmetic fixes
Change-Id: Ia878115086edc3fdfee3f0ca76e5e74ea5906f21
(cherry picked from commit e9a7990bc5)
2013-03-29 15:49:15 -07:00
6cb4a61825 misc style fix
(cherry picked from commit 142c46291e)

Conflicts:
	src/webp/format_constants.h

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

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

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

Change-Id: I214787dd64453edf3b0cdaff3951015281a32ee4
2013-03-29 11:42:17 -07:00
3e7a13a008 Merge "Container spec: clarify the background color field" into 0.3.0 2013-03-26 17:38:07 -07:00
14af77452b container doc: add a note about the 'ANMF' payload
this consists of padded chunks, so ANMF should require none

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

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

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

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

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

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

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

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

addresses issue #145

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

also fixes transparent backgrounds with animated images

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

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

Change-Id: Ibb7a7f2c71ae63434a60d988ce15f0a4ed8fcaee
2013-03-21 19:30:34 -07:00
24 changed files with 233 additions and 157 deletions

View File

@ -1,3 +1,24 @@
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 14d42af examples: don't use C99 %zu
5ccf1fe update ChangeLog 5ccf1fe update ChangeLog
2560c24 update NEWS 2560c24 update NEWS

View File

@ -105,7 +105,7 @@ DLLC = webp_dll.c
DLLINC = webp_dll.h DLLINC = webp_dll.h
DLL_OBJS = $(DIROBJ)\$(DLLC:.c=.obj) DLL_OBJS = $(DIROBJ)\$(DLLC:.c=.obj)
CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL
LIBWEBP = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib 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
@ -261,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$@ $<

View File

@ -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)
-------------------------- --------------------------
@ -376,6 +364,7 @@ Future specifications MAY add more fields.
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

View File

@ -117,17 +117,20 @@ 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;
} }
} }
@ -199,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;
@ -283,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");
@ -379,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: {

View File

@ -62,6 +62,11 @@ 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; WebPChunkIterator iccp;
} kParams; } kParams;
@ -287,9 +292,31 @@ static void HandleDisplay(void) {
glRasterPos2f(-1.f + xoff, 1.f - yoff); glRasterPos2f(-1.f + xoff, 1.f - yoff);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4); glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
if (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);
@ -426,6 +453,11 @@ 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)); memset(&kParams.iccp, 0, sizeof(kParams.iccp));
kParams.has_color_profile = kParams.has_color_profile =
!!(WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & ICCP_FLAG); !!(WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & ICCP_FLAG);

View File

@ -58,18 +58,18 @@ static const uint8_t kCodeLengthCodeOrder[NUM_CODE_LENGTH_CODES] = {
#define CODE_TO_PLANE_CODES 120 #define CODE_TO_PLANE_CODES 120
static const uint8_t code_to_plane_lut[CODE_TO_PLANE_CODES] = { static const uint8_t code_to_plane_lut[CODE_TO_PLANE_CODES] = {
0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a, 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a, 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b, 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03, 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c, 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e, 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b, 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f, 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b, 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41, 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f, 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70
}; };
static int DecodeImageStream(int xsize, int ysize, static int DecodeImageStream(int xsize, int ysize,
@ -1137,9 +1137,9 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
return 1; return 1;
Error: Error:
VP8LClear(dec); VP8LClear(dec);
assert(dec->status_ != VP8_STATUS_OK); assert(dec->status_ != VP8_STATUS_OK);
return 0; return 0;
} }
int VP8LDecodeImage(VP8LDecoder* const dec) { int VP8LDecodeImage(VP8LDecoder* const dec) {

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

@ -69,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
}; };
@ -183,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;
} }
@ -660,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

@ -79,7 +79,7 @@ extern "C" {
"vld4.8 {" #c1"[6], " #c2"[6], " #c3"[6], " #c4"[6]}," #b1 "," #stride"\n" \ "vld4.8 {" #c1"[6], " #c2"[6], " #c3"[6], " #c4"[6]}," #b1 "," #stride"\n" \
"vld4.8 {" #c1"[7], " #c2"[7], " #c3"[7], " #c4"[7]}," #b2 "," #stride"\n" "vld4.8 {" #c1"[7], " #c2"[7], " #c3"[7], " #c4"[7]}," #b2 "," #stride"\n"
#define STORE8x2(c1, c2, p,stride) \ #define STORE8x2(c1, c2, p, stride) \
"vst2.8 {" #c1"[0], " #c2"[0]}," #p "," #stride " \n" \ "vst2.8 {" #c1"[0], " #c2"[0]}," #p "," #stride " \n" \
"vst2.8 {" #c1"[1], " #c2"[1]}," #p "," #stride " \n" \ "vst2.8 {" #c1"[1], " #c2"[1]}," #p "," #stride " \n" \
"vst2.8 {" #c1"[2], " #c2"[2]}," #p "," #stride " \n" \ "vst2.8 {" #c1"[2], " #c2"[2]}," #p "," #stride " \n" \
@ -315,8 +315,8 @@ static void TransformTwoNEON(const int16_t* in, uint8_t* dst, int do_two) {
} }
static void TransformWHT(const int16_t* in, int16_t* out) { static void TransformWHT(const int16_t* in, int16_t* out) {
const int kStep = 32; // The store is only incrementing the pointer as if we const int kStep = 32; // The store is only incrementing the pointer as if we
// had stored a single byte. // had stored a single byte.
__asm__ volatile ( __asm__ volatile (
// part 1 // part 1
// load data into q0, q1 // load data into q0, q1

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

@ -149,8 +149,8 @@ static void ITransform(const uint8_t* ref,
// Same code as dec_neon.c // Same code as dec_neon.c
static void ITransformWHT(const int16_t* in, int16_t* out) { static void ITransformWHT(const int16_t* in, int16_t* out) {
const int kStep = 32; // The store is only incrementing the pointer as if we const int kStep = 32; // The store is only incrementing the pointer as if we
// had stored a single byte. // had stored a single byte.
__asm__ volatile ( __asm__ volatile (
// part 1 // part 1
// load data into q0, q1 // load data into q0, q1

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

@ -32,7 +32,7 @@ WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16 // ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16
// We process u and v together stashed into 32bit (16bit each). // We process u and v together stashed into 32bit (16bit each).
#define LOAD_UV(u,v) ((u) | ((v) << 16)) #define LOAD_UV(u, v) ((u) | ((v) << 16))
#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ #define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \

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,
@ -359,7 +359,7 @@ void VP8CalculateLevelCosts(VP8Proba* const proba) {
for (ctype = 0; ctype < NUM_TYPES; ++ctype) { for (ctype = 0; ctype < NUM_TYPES; ++ctype) {
for (band = 0; band < NUM_BANDS; ++band) { for (band = 0; band < NUM_BANDS; ++band) {
for(ctx = 0; ctx < NUM_CTX; ++ctx) { for (ctx = 0; ctx < NUM_CTX; ++ctx) {
const uint8_t* const p = proba->coeffs_[ctype][band][ctx]; const uint8_t* const p = proba->coeffs_[ctype][band][ctx];
uint16_t* const table = proba->level_cost_[ctype][band][ctx]; uint16_t* const table = proba->level_cost_[ctype][band][ctx];
const int cost_base = VP8BitCost(1, p[1]); const int cost_base = VP8BitCost(1, p[1]);

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

@ -462,7 +462,6 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
(uint8_t*)tmp.argb, width, height, (uint8_t*)tmp.argb, width, height,
tmp.argb_stride * 4, tmp.argb_stride * 4,
work, 4); work, 4);
} }
WebPPictureFree(pic); WebPPictureFree(pic);
free(work); free(work);

View File

@ -29,7 +29,6 @@ static int IsVP8XNeeded(const VP8Encoder* const enc) {
} }
static int PutPaddingByte(const WebPPicture* const pic) { static int PutPaddingByte(const WebPPicture* const pic) {
const uint8_t pad_byte[1] = { 0 }; const uint8_t pad_byte[1] = { 0 };
return !!pic->writer(pad_byte, 1, pic); return !!pic->writer(pad_byte, 1, pic);
} }
@ -70,7 +69,7 @@ static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
PutLE32(vp8x + CHUNK_HEADER_SIZE, flags); PutLE32(vp8x + CHUNK_HEADER_SIZE, flags);
PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1); PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1);
PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1); PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1);
if(!pic->writer(vp8x, sizeof(vp8x), pic)) { if (!pic->writer(vp8x, sizeof(vp8x), pic)) {
return VP8_ENC_ERROR_BAD_WRITE; return VP8_ENC_ERROR_BAD_WRITE;
} }
return VP8_ENC_OK; return VP8_ENC_OK;

View File

@ -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

@ -374,11 +374,8 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
if (!config->lossless) { if (!config->lossless) {
VP8Encoder* enc = NULL; VP8Encoder* enc = NULL;
if (pic->y == NULL || pic->u == NULL || pic->v == NULL) { if (pic->y == NULL || pic->u == NULL || pic->v == NULL) {
if (pic->argb != NULL) { // Make sure we have YUVA samples.
if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0; if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0;
} else {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
}
} }
enc = InitVP8Encoder(config, pic); enc = InitVP8Encoder(config, pic);
@ -405,8 +402,10 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
} }
ok &= DeleteVP8Encoder(enc); // must always be called, even if !ok ok &= DeleteVP8Encoder(enc); // must always be called, even if !ok
} else { } else {
if (pic->argb == NULL) // Make sure we have ARGB samples.
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); if (pic->argb == NULL && !WebPPictureYUVAToARGB(pic)) {
return 0;
}
ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem. ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem.
} }

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

@ -20,7 +20,7 @@ extern "C" {
#endif #endif
#define RFIX 30 #define RFIX 30
#define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) #define MULT_FIX(x, y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX)
void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
uint8_t* const dst, int dst_width, int dst_height, uint8_t* const dst, int dst_width, int dst_height,

View File

@ -266,7 +266,6 @@ enum WebPEncodingError {
// Main exchange structure (input samples, output bytes, statistics) // Main exchange structure (input samples, output bytes, statistics)
struct WebPPicture { struct WebPPicture {
// INPUT // INPUT
////////////// //////////////
// Main flag for encoder selecting between ARGB or YUV input. // Main flag for encoder selecting between ARGB or YUV input.

View File

@ -73,11 +73,11 @@ 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.
#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
#define MAX_DURATION (1 << 24) // maximum duration #define MAX_DURATION (1 << 24) // maximum duration
#define MAX_POSITION_OFFSET (1 << 24) // maximum frame/fragment x/y offset #define MAX_POSITION_OFFSET (1 << 24) // maximum frame/fragment x/y offset
// Maximum chunk payload is such that adding the header and padding won't // Maximum chunk payload is such that adding the header and padding won't
// overflow a uint32_t. // overflow a uint32_t.