mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-15 13:29:54 +02:00
Compare commits
21 Commits
v0.3.0-rc6
...
v0.3.0
Author | SHA1 | Date | |
---|---|---|---|
1e0d4b8c8b | |||
d52b405dbd | |||
6cb4a61825 | |||
68111ab02f | |||
403bfe820c | |||
3e7a13a008 | |||
14af77452b | |||
cc635efa01 | |||
e3e339497e | |||
4299f39852 | |||
33f9a692d9 | |||
a2a7b95916 | |||
6f18f12f99 | |||
e5af49e9c0 | |||
db46daab97 | |||
53c77afc52 | |||
a5ebd143d6 | |||
6378f23876 | |||
3c8eb9a806 | |||
04c7a2ecf0 | |||
81a50695de |
21
ChangeLog
21
ChangeLog
@ -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
|
||||||
|
@ -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$@ $<
|
||||||
|
@ -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
|
||||||
|
@ -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: {
|
||||||
|
@ -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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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, \
|
||||||
|
@ -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]);
|
||||||
|
@ -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'.
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
}
|
}
|
||||||
|
@ -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_.
|
||||||
|
@ -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_;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
Reference in New Issue
Block a user