mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-15 21:39:59 +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
|
||||
5ccf1fe update ChangeLog
|
||||
2560c24 update NEWS
|
||||
|
@ -105,7 +105,7 @@ DLLC = webp_dll.c
|
||||
DLLINC = webp_dll.h
|
||||
DLL_OBJS = $(DIROBJ)\$(DLLC:.c=.obj)
|
||||
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
|
||||
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib
|
||||
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPMDEMUX_BASENAME)_dll.lib
|
||||
@ -261,7 +261,7 @@ $(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS)
|
||||
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(OUTPUT_DIRS)
|
||||
|
||||
!IF "$(DLLBUILD)" == "TRUE"
|
||||
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS):
|
||||
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
|
||||
$(DIROBJ)\$(DLLINC) $(DIROBJ)\$(DLLC)
|
||||
|
||||
{$(DIROBJ)}.c{$(DIROBJ)}.obj:
|
||||
|
@ -93,11 +93,21 @@ _uint32_
|
||||
|
||||
: A 32-bit, little-endian, unsigned integer.
|
||||
|
||||
_FourCC_
|
||||
|
||||
: A _FourCC_ (four-character code) is a _uint32_ created by concatenating four
|
||||
ASCII characters in little-endian order.
|
||||
|
||||
_1-based_
|
||||
|
||||
: An unsigned integer field storing values offset by `-1`. e.g., Such a field
|
||||
would store value _25_ as _24_.
|
||||
|
||||
RIFF file format
|
||||
----------------
|
||||
The WebP file format is based on the RIFF (resource interchange file format)
|
||||
document format.
|
||||
|
||||
The basic element of a RIFF file is a _chunk_. It consists of:
|
||||
|
||||
0 1 2 3
|
||||
@ -112,12 +122,12 @@ The basic element of a RIFF file is a _chunk_. It consists of:
|
||||
|
||||
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_)
|
||||
|
||||
: The size of the chunk (_ckSize_) not including this field, the chunk
|
||||
identifier and padding.
|
||||
: The size of the chunk not including this field, the chunk identifier or
|
||||
padding.
|
||||
|
||||
Chunk Payload: _Chunk Size_ bytes
|
||||
|
||||
@ -126,43 +136,13 @@ Chunk Payload: _Chunk Size_ bytes
|
||||
|
||||
_ChunkHeader('ABCD')_
|
||||
|
||||
: This is used to describe the fourcc and size header of individual
|
||||
chunks, where 'ABCD' is the fourcc for the chunk. This element's
|
||||
: This is used to describe the _FourCC_ and _Chunk Size_ header of individual
|
||||
chunks, where 'ABCD' is the FourCC for the chunk. This element's
|
||||
size is 8 bytes.
|
||||
|
||||
: Note that, in this specification, all chunk tag characters are in
|
||||
file order, not in byte order of a uint32 of any particular
|
||||
architecture.
|
||||
|
||||
_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.
|
||||
|
||||
**Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard
|
||||
chunks that apply to any RIFF file format, while FourCCs specific to a file
|
||||
format are all lowercase. WebP does not follow this convention.
|
||||
|
||||
WebP file header
|
||||
----------------
|
||||
@ -183,12 +163,20 @@ WebP file header
|
||||
|
||||
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
|
||||
|
||||
: 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)
|
||||
--------------------------
|
||||
|
||||
@ -376,6 +364,7 @@ Future specifications MAY add more fields.
|
||||
An animation is controlled by ANIM and ANMF chunks.
|
||||
|
||||
ANIM Chunk:
|
||||
{:#anim_chunk}
|
||||
|
||||
For an animated image, this chunk contains the _global parameters_ of the
|
||||
animation.
|
||||
@ -392,10 +381,14 @@ animation.
|
||||
|
||||
Background Color: 32 bits (_uint32_)
|
||||
|
||||
: The background color of the canvas in \[Blue, Green, Red, Alpha\] byte order.
|
||||
The background color is the color used for those pixels of the canvas that are
|
||||
not covered by a frame. Background color is also used when disposal method is
|
||||
`1`.
|
||||
: The default background color of the canvas in \[Blue, Green, Red, Alpha\]
|
||||
byte order. This color is used to fill the unused space on the canvas around the
|
||||
frames, as well as the transparent pixels of the first frame. Background color
|
||||
is also used when disposal method is `1`.
|
||||
|
||||
**Note**: 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_)
|
||||
|
||||
@ -457,14 +450,45 @@ Reserved: 7 bits
|
||||
|
||||
Disposal method (D): 1 bit
|
||||
|
||||
: Indicates how the area used by this frame is to be treated before rendering
|
||||
the next frame on canvas:
|
||||
: Indicates how _the current frame_ is to be treated after it has been displayed
|
||||
(before rendering the next frame) on the canvas:
|
||||
|
||||
* `0`: Do not dispose. Keep the area used by this frame as it is and render
|
||||
the next frame on top of it.
|
||||
* `0`: Do not dispose. Leave the canvas as is.
|
||||
|
||||
* `1`: Dispose to background color (also part of this chunk). Restore the
|
||||
area used by this frame to background color before rendering the next frame.
|
||||
* `1`: Dispose to background color. Fill the _rectangle_ on the canvas covered
|
||||
by the _current frame_ with background color specified in the
|
||||
[ANIM chunk](#anim_chunk).
|
||||
|
||||
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
|
||||
|
||||
@ -478,6 +502,9 @@ Frame Data: _Chunk Size_ - `16` bytes
|
||||
|
||||
* An optional list of [unknown chunks](#unknown-chunks).
|
||||
|
||||
**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual
|
||||
_padded_ chunks as described by the [RIFF file format](#riff-file-format).
|
||||
|
||||
#### Fragments _\[status: experimental\]_
|
||||
|
||||
For images that are represented by fragments, this chunk contains data for
|
||||
|
@ -117,14 +117,17 @@ static int ReadSubImage(GifFileType* gif, WebPPicture* pic, WebPPicture* view) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int GetColorFromIndex(const ColorMapObject* const color_map, GifWord idx,
|
||||
uint32_t* const argb) {
|
||||
assert(color_map != NULL && color_map->Colors != NULL);
|
||||
if (idx >= color_map->ColorCount) {
|
||||
return 0; // Invalid index.
|
||||
static int GetBackgroundColor(const ColorMapObject* const color_map,
|
||||
GifWord bgcolor_idx, uint32_t* const bgcolor) {
|
||||
if (transparent_index != -1 && bgcolor_idx == transparent_index) {
|
||||
*bgcolor = TRANSPARENT_COLOR; // Special case.
|
||||
return 1;
|
||||
} else if (color_map == NULL || color_map->Colors == NULL
|
||||
|| bgcolor_idx >= color_map->ColorCount) {
|
||||
return 0; // Invalid color map or index.
|
||||
} else {
|
||||
const GifColorType color = color_map->Colors[idx];
|
||||
*argb = (0xff << 24)
|
||||
const GifColorType color = color_map->Colors[bgcolor_idx];
|
||||
*bgcolor = (0xff << 24)
|
||||
| (color.Red << 16)
|
||||
| (color.Green << 8)
|
||||
| (color.Blue << 0);
|
||||
@ -199,6 +202,7 @@ int main(int argc, const char *argv[]) {
|
||||
WebPMuxFrameInfo frame;
|
||||
WebPMuxAnimParams anim = { WHITE_COLOR, 0 };
|
||||
|
||||
int is_first_frame = 1;
|
||||
int done;
|
||||
int c;
|
||||
int quiet = 0;
|
||||
@ -283,14 +287,6 @@ int main(int argc, const char *argv[]) {
|
||||
picture.custom_ptr = &memory;
|
||||
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();
|
||||
if (mux == NULL) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
case PLAINTEXT_EXT_FUNC_CODE: {
|
||||
|
@ -62,6 +62,11 @@ static struct {
|
||||
const WebPDecBuffer* pic;
|
||||
WebPDemuxer* dmux;
|
||||
WebPIterator frameiter;
|
||||
struct {
|
||||
int width, height;
|
||||
int x_offset, y_offset;
|
||||
enum WebPMuxAnimDispose dispose_method;
|
||||
} prev_frame;
|
||||
WebPChunkIterator iccp;
|
||||
} kParams;
|
||||
|
||||
@ -287,9 +292,31 @@ static void HandleDisplay(void) {
|
||||
glRasterPos2f(-1.f + xoff, 1.f - yoff);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
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
|
||||
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,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
(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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -61,10 +61,10 @@ typedef struct {
|
||||
} WebPHeaderStructure;
|
||||
|
||||
// Skips over all valid chunks prior to the first VP8/VP8L frame header.
|
||||
// Returns VP8_STATUS_OK on success,
|
||||
// VP8_STATUS_BITSTREAM_ERROR if an invalid header/chunk is found, and
|
||||
// VP8_STATUS_NOT_ENOUGH_DATA if case of insufficient data.
|
||||
// In 'headers', compressed_size, offset, alpha_data, alpha_size and lossless
|
||||
// Returns: VP8_STATUS_OK, VP8_STATUS_BITSTREAM_ERROR (invalid header/chunk),
|
||||
// VP8_STATUS_NOT_ENOUGH_DATA (partial input) or VP8_STATUS_UNSUPPORTED_FEATURE
|
||||
// in the case of non-decodable features (animation for instance).
|
||||
// In 'headers', compressed_size, offset, alpha_data, alpha_size, and lossless
|
||||
// fields are updated appropriately upon success.
|
||||
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
|
||||
|
||||
|
@ -69,6 +69,7 @@ struct WebPDemuxer {
|
||||
uint32_t bgcolor_;
|
||||
int num_frames_;
|
||||
Frame* frames_;
|
||||
Frame** frames_tail_;
|
||||
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.
|
||||
// Returns true on success, false otherwise.
|
||||
static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
|
||||
const Frame* last_frame = NULL;
|
||||
Frame** f = &dmux->frames_;
|
||||
while (*f != NULL) {
|
||||
last_frame = *f;
|
||||
f = &(*f)->next_;
|
||||
}
|
||||
const Frame* const last_frame = *dmux->frames_tail_;
|
||||
if (last_frame != NULL && !last_frame->complete_) return 0;
|
||||
*f = frame;
|
||||
|
||||
*dmux->frames_tail_ = frame;
|
||||
frame->next_ = NULL;
|
||||
dmux->frames_tail_ = &frame->next_;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -660,6 +658,7 @@ static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
|
||||
dmux->bgcolor_ = 0xFFFFFFFF; // White background by default.
|
||||
dmux->canvas_width_ = -1;
|
||||
dmux->canvas_height_ = -1;
|
||||
dmux->frames_tail_ = &dmux->frames_;
|
||||
dmux->mem_ = *mem;
|
||||
}
|
||||
|
||||
|
@ -631,13 +631,13 @@ static int QuantizeBlock(int16_t in[16], int16_t out[16],
|
||||
for (; n < 16; ++n) {
|
||||
const int j = kZigzag[n];
|
||||
const int sign = (in[j] < 0);
|
||||
int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
|
||||
if (coeff > 2047) coeff = 2047;
|
||||
const int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
|
||||
if (coeff > mtx->zthresh_[j]) {
|
||||
const int Q = mtx->q_[j];
|
||||
const int iQ = mtx->iq_[j];
|
||||
const int B = mtx->bias_[j];
|
||||
out[n] = QUANTDIV(coeff, iQ, B);
|
||||
if (out[n] > MAX_LEVEL) out[n] = MAX_LEVEL;
|
||||
if (sign) out[n] = -out[n];
|
||||
in[j] = out[n] * Q;
|
||||
if (out[n]) last = n;
|
||||
|
@ -776,7 +776,7 @@ static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
|
||||
// Simple quantization
|
||||
static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
|
||||
int n, const VP8Matrix* const mtx) {
|
||||
const __m128i max_coeff_2047 = _mm_set1_epi16(2047);
|
||||
const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL);
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
__m128i coeff0, coeff8;
|
||||
__m128i out0, out8;
|
||||
@ -812,10 +812,6 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
|
||||
coeff0 = _mm_add_epi16(coeff0, sharpen0);
|
||||
coeff8 = _mm_add_epi16(coeff8, sharpen8);
|
||||
|
||||
// if (coeff > 2047) coeff = 2047
|
||||
coeff0 = _mm_min_epi16(coeff0, max_coeff_2047);
|
||||
coeff8 = _mm_min_epi16(coeff8, max_coeff_2047);
|
||||
|
||||
// out = (coeff * iQ + B) >> QFIX;
|
||||
{
|
||||
// doing calculations with 32b precision (QFIX=17)
|
||||
@ -843,9 +839,14 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
|
||||
out_04 = _mm_srai_epi32(out_04, QFIX);
|
||||
out_08 = _mm_srai_epi32(out_08, QFIX);
|
||||
out_12 = _mm_srai_epi32(out_12, QFIX);
|
||||
|
||||
// pack result as 16b
|
||||
out0 = _mm_packs_epi32(out_00, out_04);
|
||||
out8 = _mm_packs_epi32(out_08, out_12);
|
||||
|
||||
// if (coeff > 2047) coeff = 2047
|
||||
out0 = _mm_min_epi16(out0, max_coeff_2047);
|
||||
out8 = _mm_min_epi16(out8, max_coeff_2047);
|
||||
}
|
||||
|
||||
// get sign back (if (sign[j]) out_n = -out_n)
|
||||
|
@ -75,7 +75,7 @@ const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = {
|
||||
|
||||
// fixed costs for coding levels, deduce from the coding tree.
|
||||
// This is only the part that doesn't depend on the probability state.
|
||||
const uint16_t VP8LevelFixedCosts[2048] = {
|
||||
const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1] = {
|
||||
0, 256, 256, 256, 256, 432, 618, 630,
|
||||
731, 640, 640, 828, 901, 948, 1021, 1101,
|
||||
1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202,
|
||||
|
@ -18,7 +18,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const uint16_t VP8LevelFixedCosts[2048]; // approximate cost per level
|
||||
// approximate cost per level:
|
||||
extern const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1];
|
||||
extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p)
|
||||
|
||||
// Cost of coding one event with probability 'proba'.
|
||||
|
@ -462,7 +462,6 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
|
||||
(uint8_t*)tmp.argb, width, height,
|
||||
tmp.argb_stride * 4,
|
||||
work, 4);
|
||||
|
||||
}
|
||||
WebPPictureFree(pic);
|
||||
free(work);
|
||||
|
@ -29,7 +29,6 @@ static int IsVP8XNeeded(const VP8Encoder* const enc) {
|
||||
}
|
||||
|
||||
static int PutPaddingByte(const WebPPicture* const pic) {
|
||||
|
||||
const uint8_t pad_byte[1] = { 0 };
|
||||
return !!pic->writer(pad_byte, 1, pic);
|
||||
}
|
||||
|
@ -56,7 +56,8 @@ enum { NUM_MB_SEGMENTS = 4,
|
||||
NUM_CTX = 3,
|
||||
NUM_PROBAS = 11,
|
||||
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
|
||||
|
@ -374,11 +374,8 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
|
||||
if (!config->lossless) {
|
||||
VP8Encoder* enc = 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;
|
||||
} else {
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
} else {
|
||||
if (pic->argb == NULL)
|
||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
|
||||
// Make sure we have ARGB samples.
|
||||
if (pic->argb == NULL && !WebPPictureYUVAToARGB(pic)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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'.
|
||||
// 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);
|
||||
|
||||
// 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.
|
||||
static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) {
|
||||
while (chunk && chunk->tag_ != tag) {
|
||||
while (chunk != NULL && chunk->tag_ != tag) {
|
||||
chunk = chunk->next_;
|
||||
}
|
||||
return chunk;
|
||||
@ -105,7 +105,7 @@ static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) {
|
||||
WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) {
|
||||
uint32_t iter = nth;
|
||||
first = ChunkSearchNextInList(first, tag);
|
||||
if (!first) return NULL;
|
||||
if (first == NULL) return NULL;
|
||||
|
||||
while (--iter != 0) {
|
||||
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,
|
||||
WebPChunk*** const location) {
|
||||
uint32_t count = 0;
|
||||
assert(chunk_list);
|
||||
assert(chunk_list != NULL);
|
||||
*location = chunk_list;
|
||||
|
||||
while (*chunk_list) {
|
||||
while (*chunk_list != NULL) {
|
||||
WebPChunk* const cur_chunk = *chunk_list;
|
||||
++count;
|
||||
if (count == nth) return 1; // Found.
|
||||
@ -149,27 +149,18 @@ WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
|
||||
ChunkRelease(chunk);
|
||||
|
||||
if (data != NULL) {
|
||||
if (copy_data) {
|
||||
// Copy data.
|
||||
chunk->data_.bytes = (uint8_t*)malloc(data->size);
|
||||
if (chunk->data_.bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
|
||||
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.
|
||||
if (copy_data) { // Copy data.
|
||||
if (!WebPDataCopy(data, &chunk->data_)) return WEBP_MUX_MEMORY_ERROR;
|
||||
chunk->owner_ = 1; // Chunk is owner of data.
|
||||
} else { // Don't copy data.
|
||||
chunk->data_ = *data;
|
||||
}
|
||||
}
|
||||
|
||||
chunk->tag_ = tag;
|
||||
|
||||
return WEBP_MUX_OK;
|
||||
}
|
||||
|
||||
WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
|
||||
WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
|
||||
uint32_t nth) {
|
||||
WebPChunk* new_chunk;
|
||||
|
||||
@ -180,6 +171,7 @@ WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
|
||||
new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk));
|
||||
if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR;
|
||||
*new_chunk = *chunk;
|
||||
chunk->owner_ = 0;
|
||||
new_chunk->next_ = *chunk_list;
|
||||
*chunk_list = new_chunk;
|
||||
return WEBP_MUX_OK;
|
||||
@ -199,7 +191,7 @@ WebPChunk* ChunkDelete(WebPChunk* const chunk) {
|
||||
|
||||
size_t ChunksListDiskSize(const WebPChunk* chunk_list) {
|
||||
size_t size = 0;
|
||||
while (chunk_list) {
|
||||
while (chunk_list != NULL) {
|
||||
size += ChunkDiskSize(chunk_list);
|
||||
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) {
|
||||
while (chunk_list) {
|
||||
while (chunk_list != NULL) {
|
||||
dst = ChunkEmit(chunk_list, dst);
|
||||
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.
|
||||
}
|
||||
|
||||
while (*wpi_list) {
|
||||
while (*wpi_list != NULL) {
|
||||
WebPMuxImage* const cur_wpi = *wpi_list;
|
||||
++count;
|
||||
if (count == nth) return 1; // Found.
|
||||
@ -327,7 +319,7 @@ WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) {
|
||||
}
|
||||
|
||||
void MuxImageDeleteAll(WebPMuxImage** const wpi_list) {
|
||||
while (*wpi_list) {
|
||||
while (*wpi_list != NULL) {
|
||||
*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 size = 0;
|
||||
while (wpi_list) {
|
||||
while (wpi_list != NULL) {
|
||||
size += MuxImageDiskSize(wpi_list);
|
||||
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) {
|
||||
while (wpi_list) {
|
||||
while (wpi_list != NULL) {
|
||||
dst = MuxImageEmit(wpi_list, dst);
|
||||
wpi_list = wpi_list->next_;
|
||||
}
|
||||
|
@ -266,7 +266,6 @@ enum WebPEncodingError {
|
||||
|
||||
// Main exchange structure (input samples, output bytes, statistics)
|
||||
struct WebPPicture {
|
||||
|
||||
// INPUT
|
||||
//////////////
|
||||
// Main flag for encoder selecting between ARGB or YUV input.
|
||||
|
Reference in New Issue
Block a user