Commit 06e82753 authored by jzern's avatar jzern Committed by Commit bot

libwebp: update to 0.4.4

bug fixes only.

from NEWS:
- 10/15/15: version 0.4.4
  This is a binary compatible release.
  * rescaling out-of-bounds read fix (issue #254)
  * various build fixes and improvements (issues #253, #259, #262, #267, #268)
  * container documentation update
  * gif2webp transparency fix (issue #245)

Review URL: https://codereview.chromium.org/1422493004

Cr-Commit-Position: refs/heads/master@{#357159}
parent 9afc6213
...@@ -47,7 +47,7 @@ or agree to the institution of patent litigation or any other patent ...@@ -47,7 +47,7 @@ or agree to the institution of patent litigation or any other patent
enforcement activity against any entity (including a cross-claim or enforcement activity against any entity (including a cross-claim or
counterclaim in a lawsuit) alleging that any of these implementations of WebM counterclaim in a lawsuit) alleging that any of these implementations of WebM
or any code incorporated within any of these implementations of WebM or any code incorporated within any of these implementations of WebM
constitutes direct or contributory patent infringement, or inducement of constitute direct or contributory patent infringement, or inducement of
patent infringement, then any patent rights granted to you under this License patent infringement, then any patent rights granted to you under this License
for these implementations of WebM shall terminate as of the date such for these implementations of WebM shall terminate as of the date such
litigation is filed. litigation is filed.
Name: WebP image encoder/decoder Name: WebP image encoder/decoder
Short Name: libwebp Short Name: libwebp
URL: http://developers.google.com/speed/webp URL: http://developers.google.com/speed/webp
Version: v0.4.3 Version: v0.4.4
License: BSD License: BSD
License File: LICENSE License File: LICENSE
Security Critical: Yes Security Critical: Yes
Description: Description:
Source archive: Source archive:
http://downloads.webmproject.org/releases/webp/libwebp-0.4.3.tar.gz http://downloads.webmproject.org/releases/webp/libwebp-0.4.4.tar.gz
WebP is an image format that does both lossy and lossless compression of WebP is an image format that does both lossy and lossless compression of
digital photographic images. WebP consists of a codec based on VP8, that Google digital photographic images. WebP consists of a codec based on VP8, that Google
...@@ -22,4 +22,3 @@ Local changes: ...@@ -22,4 +22,3 @@ Local changes:
* Merged COPYING/PATENTS to LICENSE * Merged COPYING/PATENTS to LICENSE
Cherry-picks: Cherry-picks:
Revert patch f7fc4bc: dec/webp.c: don't wait for data before reporting w/h Revert patch f7fc4bc: dec/webp.c: don't wait for data before reporting w/h
0250dfc msvc: fix pointer type warning in BitsLog2Floor
...@@ -33,6 +33,11 @@ static int IsValidColorspace(int webp_csp_mode) { ...@@ -33,6 +33,11 @@ static int IsValidColorspace(int webp_csp_mode) {
return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST); return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
} }
// strictly speaking, the very last (or first, if flipped) row
// doesn't require padding.
#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \
(uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH)
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) { static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
int ok = 1; int ok = 1;
const WEBP_CSP_MODE mode = buffer->colorspace; const WEBP_CSP_MODE mode = buffer->colorspace;
...@@ -42,20 +47,22 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) { ...@@ -42,20 +47,22 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
ok = 0; ok = 0;
} else if (!WebPIsRGBMode(mode)) { // YUV checks } else if (!WebPIsRGBMode(mode)) { // YUV checks
const WebPYUVABuffer* const buf = &buffer->u.YUVA; const WebPYUVABuffer* const buf = &buffer->u.YUVA;
const int uv_width = (width + 1) / 2;
const int uv_height = (height + 1) / 2;
const int y_stride = abs(buf->y_stride); const int y_stride = abs(buf->y_stride);
const int u_stride = abs(buf->u_stride); const int u_stride = abs(buf->u_stride);
const int v_stride = abs(buf->v_stride); const int v_stride = abs(buf->v_stride);
const int a_stride = abs(buf->a_stride); const int a_stride = abs(buf->a_stride);
const uint64_t y_size = (uint64_t)y_stride * height; const uint64_t y_size = MIN_BUFFER_SIZE(width, height, y_stride);
const uint64_t u_size = (uint64_t)u_stride * ((height + 1) / 2); const uint64_t u_size = MIN_BUFFER_SIZE(uv_width, uv_height, u_stride);
const uint64_t v_size = (uint64_t)v_stride * ((height + 1) / 2); const uint64_t v_size = MIN_BUFFER_SIZE(uv_width, uv_height, v_stride);
const uint64_t a_size = (uint64_t)a_stride * height; const uint64_t a_size = MIN_BUFFER_SIZE(width, height, a_stride);
ok &= (y_size <= buf->y_size); ok &= (y_size <= buf->y_size);
ok &= (u_size <= buf->u_size); ok &= (u_size <= buf->u_size);
ok &= (v_size <= buf->v_size); ok &= (v_size <= buf->v_size);
ok &= (y_stride >= width); ok &= (y_stride >= width);
ok &= (u_stride >= (width + 1) / 2); ok &= (u_stride >= uv_width);
ok &= (v_stride >= (width + 1) / 2); ok &= (v_stride >= uv_width);
ok &= (buf->y != NULL); ok &= (buf->y != NULL);
ok &= (buf->u != NULL); ok &= (buf->u != NULL);
ok &= (buf->v != NULL); ok &= (buf->v != NULL);
...@@ -67,13 +74,14 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) { ...@@ -67,13 +74,14 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
} else { // RGB checks } else { // RGB checks
const WebPRGBABuffer* const buf = &buffer->u.RGBA; const WebPRGBABuffer* const buf = &buffer->u.RGBA;
const int stride = abs(buf->stride); const int stride = abs(buf->stride);
const uint64_t size = (uint64_t)stride * height; const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
ok &= (size <= buf->size); ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]); ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL); ok &= (buf->rgba != NULL);
} }
return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM; return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
} }
#undef MIN_BUFFER_SIZE
static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) { static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
const int w = buffer->width; const int w = buffer->width;
......
...@@ -322,37 +322,31 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { ...@@ -322,37 +322,31 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
size_t tmp_size; size_t tmp_size;
int32_t* work; rescaler_t* work;
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work); tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
if (has_alpha) { if (has_alpha) {
tmp_size += work_size * sizeof(*work); tmp_size += work_size * sizeof(*work);
} }
p->memory = WebPSafeCalloc(1ULL, tmp_size); p->memory = WebPSafeMalloc(1ULL, tmp_size);
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error return 0; // memory error
} }
work = (int32_t*)p->memory; work = (rescaler_t*)p->memory;
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
buf->y, out_width, out_height, buf->y_stride, 1, buf->y, out_width, out_height, buf->y_stride, 1,
io->mb_w, out_width, io->mb_h, out_height,
work); work);
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
uv_in_width, uv_out_width,
uv_in_height, uv_out_height,
work + work_size); work + work_size);
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
uv_in_width, uv_out_width,
uv_in_height, uv_out_height,
work + work_size + uv_work_size); work + work_size + uv_work_size);
p->emit = EmitRescaledYUV; p->emit = EmitRescaledYUV;
if (has_alpha) { if (has_alpha) {
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
buf->a, out_width, out_height, buf->a_stride, 1, buf->a, out_width, out_height, buf->a_stride, 1,
io->mb_w, out_width, io->mb_h, out_height,
work + work_size + 2 * uv_work_size); work + work_size + 2 * uv_work_size);
p->emit_alpha = EmitRescaledAlphaYUV; p->emit_alpha = EmitRescaledAlphaYUV;
WebPInitAlphaProcessing(); WebPInitAlphaProcessing();
...@@ -375,9 +369,9 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) { ...@@ -375,9 +369,9 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
WebPRescalerHasPendingOutput(&p->scaler_u)) { WebPRescalerHasPendingOutput(&p->scaler_u)) {
assert(p->last_y + y_pos + num_lines_out < p->output->height); assert(p->last_y + y_pos + num_lines_out < p->output->height);
assert(p->scaler_u.y_accum == p->scaler_v.y_accum); assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
WebPRescalerExportRow(&p->scaler_y, 0); WebPRescalerExportRow(&p->scaler_y);
WebPRescalerExportRow(&p->scaler_u, 0); WebPRescalerExportRow(&p->scaler_u);
WebPRescalerExportRow(&p->scaler_v, 0); WebPRescalerExportRow(&p->scaler_v);
convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst, convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
dst, p->scaler_y.dst_width); dst, p->scaler_y.dst_width);
dst += buf->stride; dst += buf->stride;
...@@ -425,7 +419,7 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos) { ...@@ -425,7 +419,7 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos) {
while (WebPRescalerHasPendingOutput(&p->scaler_a)) { while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
int i; int i;
assert(p->last_y + y_pos + num_lines_out < p->output->height); assert(p->last_y + y_pos + num_lines_out < p->output->height);
WebPRescalerExportRow(&p->scaler_a, 0); WebPRescalerExportRow(&p->scaler_a);
for (i = 0; i < width; ++i) { for (i = 0; i < width; ++i) {
const uint32_t alpha_value = p->scaler_a.dst[i]; const uint32_t alpha_value = p->scaler_a.dst[i];
dst[4 * i] = alpha_value; dst[4 * i] = alpha_value;
...@@ -458,7 +452,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) { ...@@ -458,7 +452,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
while (WebPRescalerHasPendingOutput(&p->scaler_a)) { while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
int i; int i;
assert(p->last_y + y_pos + num_lines_out < p->output->height); assert(p->last_y + y_pos + num_lines_out < p->output->height);
WebPRescalerExportRow(&p->scaler_a, 0); WebPRescalerExportRow(&p->scaler_a);
for (i = 0; i < width; ++i) { for (i = 0; i < width; ++i) {
// Fill in the alpha value (converted to 4 bits). // Fill in the alpha value (converted to 4 bits).
const uint32_t alpha_value = p->scaler_a.dst[i] >> 4; const uint32_t alpha_value = p->scaler_a.dst[i] >> 4;
...@@ -495,7 +489,7 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { ...@@ -495,7 +489,7 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int uv_in_width = (io->mb_w + 1) >> 1; const int uv_in_width = (io->mb_w + 1) >> 1;
const int uv_in_height = (io->mb_h + 1) >> 1; const int uv_in_height = (io->mb_h + 1) >> 1;
const size_t work_size = 2 * out_width; // scratch memory for one rescaler const size_t work_size = 2 * out_width; // scratch memory for one rescaler
int32_t* work; // rescalers work area rescaler_t* work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
size_t tmp_size1, tmp_size2, total_size; size_t tmp_size1, tmp_size2, total_size;
...@@ -506,30 +500,26 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { ...@@ -506,30 +500,26 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
tmp_size2 += out_width; tmp_size2 += out_width;
} }
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp); total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
p->memory = WebPSafeCalloc(1ULL, total_size); p->memory = WebPSafeMalloc(1ULL, total_size);
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error return 0; // memory error
} }
work = (int32_t*)p->memory; work = (rescaler_t*)p->memory;
tmp = (uint8_t*)(work + tmp_size1); tmp = (uint8_t*)(work + tmp_size1);
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
tmp + 0 * out_width, out_width, out_height, 0, 1, tmp + 0 * out_width, out_width, out_height, 0, 1,
io->mb_w, out_width, io->mb_h, out_height,
work + 0 * work_size); work + 0 * work_size);
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
tmp + 1 * out_width, out_width, out_height, 0, 1, tmp + 1 * out_width, out_width, out_height, 0, 1,
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
work + 1 * work_size); work + 1 * work_size);
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
tmp + 2 * out_width, out_width, out_height, 0, 1, tmp + 2 * out_width, out_width, out_height, 0, 1,
io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
work + 2 * work_size); work + 2 * work_size);
p->emit = EmitRescaledRGB; p->emit = EmitRescaledRGB;
if (has_alpha) { if (has_alpha) {
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
tmp + 3 * out_width, out_width, out_height, 0, 1, tmp + 3 * out_width, out_width, out_height, 0, 1,
io->mb_w, out_width, io->mb_h, out_height,
work + 3 * work_size); work + 3 * work_size);
p->emit_alpha = EmitRescaledAlphaRGB; p->emit_alpha = EmitRescaledAlphaRGB;
if (p->output->colorspace == MODE_RGBA_4444 || if (p->output->colorspace == MODE_RGBA_4444 ||
......
...@@ -31,7 +31,7 @@ extern "C" { ...@@ -31,7 +31,7 @@ extern "C" {
// version numbers // version numbers
#define DEC_MAJ_VERSION 0 #define DEC_MAJ_VERSION 0
#define DEC_MIN_VERSION 4 #define DEC_MIN_VERSION 4
#define DEC_REV_VERSION 3 #define DEC_REV_VERSION 4
// intra prediction modes // intra prediction modes
enum { B_DC_PRED = 0, // 4x4 modes enum { B_DC_PRED = 0, // 4x4 modes
......
...@@ -390,13 +390,13 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) { ...@@ -390,13 +390,13 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
const int in_height = io->mb_h; const int in_height = io->mb_h;
const int out_height = io->scaled_height; const int out_height = io->scaled_height;
const uint64_t work_size = 2 * num_channels * (uint64_t)out_width; const uint64_t work_size = 2 * num_channels * (uint64_t)out_width;
int32_t* work; // Rescaler work area. rescaler_t* work; // Rescaler work area.
const uint64_t scaled_data_size = num_channels * (uint64_t)out_width; const uint64_t scaled_data_size = (uint64_t)out_width;
uint32_t* scaled_data; // Temporary storage for scaled BGRA data. uint32_t* scaled_data; // Temporary storage for scaled BGRA data.
const uint64_t memory_size = sizeof(*dec->rescaler) + const uint64_t memory_size = sizeof(*dec->rescaler) +
work_size * sizeof(*work) + work_size * sizeof(*work) +
scaled_data_size * sizeof(*scaled_data); scaled_data_size * sizeof(*scaled_data);
uint8_t* memory = (uint8_t*)WebPSafeCalloc(memory_size, sizeof(*memory)); uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
if (memory == NULL) { if (memory == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY; dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
return 0; return 0;
...@@ -406,13 +406,12 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) { ...@@ -406,13 +406,12 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
dec->rescaler = (WebPRescaler*)memory; dec->rescaler = (WebPRescaler*)memory;
memory += sizeof(*dec->rescaler); memory += sizeof(*dec->rescaler);
work = (int32_t*)memory; work = (rescaler_t*)memory;
memory += work_size * sizeof(*work); memory += work_size * sizeof(*work);
scaled_data = (uint32_t*)memory; scaled_data = (uint32_t*)memory;
WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data, WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
out_width, out_height, 0, num_channels, out_width, out_height, 0, num_channels, work);
in_width, out_width, in_height, out_height, work);
return 1; return 1;
} }
...@@ -427,7 +426,7 @@ static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace, ...@@ -427,7 +426,7 @@ static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
int num_lines_out = 0; int num_lines_out = 0;
while (WebPRescalerHasPendingOutput(rescaler)) { while (WebPRescalerHasPendingOutput(rescaler)) {
uint8_t* const dst = rgba + num_lines_out * rgba_stride; uint8_t* const dst = rgba + num_lines_out * rgba_stride;
WebPRescalerExportRow(rescaler, 0); WebPRescalerExportRow(rescaler);
WebPMultARGBRow(src, dst_width, 1); WebPMultARGBRow(src, dst_width, 1);
VP8LConvertFromBGRA(src, dst_width, colorspace, dst); VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
++num_lines_out; ++num_lines_out;
...@@ -545,7 +544,7 @@ static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) { ...@@ -545,7 +544,7 @@ static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
const int dst_width = rescaler->dst_width; const int dst_width = rescaler->dst_width;
int num_lines_out = 0; int num_lines_out = 0;
while (WebPRescalerHasPendingOutput(rescaler)) { while (WebPRescalerHasPendingOutput(rescaler)) {
WebPRescalerExportRow(rescaler, 0); WebPRescalerExportRow(rescaler);
WebPMultARGBRow(src, dst_width, 1); WebPMultARGBRow(src, dst_width, 1);
ConvertToYUVA(src, dst_width, y_pos, dec->output_); ConvertToYUVA(src, dst_width, y_pos, dec->output_);
++y_pos; ++y_pos;
......
...@@ -24,24 +24,24 @@ ...@@ -24,24 +24,24 @@
// Load/Store vertical edge // Load/Store vertical edge
#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \ #define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \
"vld4.8 {" #c1"[0], " #c2"[0], " #c3"[0], " #c4"[0]}," #b1 "," #stride"\n" \ "vld4.8 {" #c1 "[0]," #c2 "[0]," #c3 "[0]," #c4 "[0]}," #b1 "," #stride "\n" \
"vld4.8 {" #c1"[1], " #c2"[1], " #c3"[1], " #c4"[1]}," #b2 "," #stride"\n" \ "vld4.8 {" #c1 "[1]," #c2 "[1]," #c3 "[1]," #c4 "[1]}," #b2 "," #stride "\n" \
"vld4.8 {" #c1"[2], " #c2"[2], " #c3"[2], " #c4"[2]}," #b1 "," #stride"\n" \ "vld4.8 {" #c1 "[2]," #c2 "[2]," #c3 "[2]," #c4 "[2]}," #b1 "," #stride "\n" \
"vld4.8 {" #c1"[3], " #c2"[3], " #c3"[3], " #c4"[3]}," #b2 "," #stride"\n" \ "vld4.8 {" #c1 "[3]," #c2 "[3]," #c3 "[3]," #c4 "[3]}," #b2 "," #stride "\n" \
"vld4.8 {" #c1"[4], " #c2"[4], " #c3"[4], " #c4"[4]}," #b1 "," #stride"\n" \ "vld4.8 {" #c1 "[4]," #c2 "[4]," #c3 "[4]," #c4 "[4]}," #b1 "," #stride "\n" \
"vld4.8 {" #c1"[5], " #c2"[5], " #c3"[5], " #c4"[5]}," #b2 "," #stride"\n" \ "vld4.8 {" #c1 "[5]," #c2 "[5]," #c3 "[5]," #c4 "[5]}," #b2 "," #stride "\n" \
"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" \
"vst2.8 {" #c1"[3], " #c2"[3]}," #p "," #stride " \n" \ "vst2.8 {" #c1 "[3], " #c2 "[3]}," #p "," #stride " \n" \
"vst2.8 {" #c1"[4], " #c2"[4]}," #p "," #stride " \n" \ "vst2.8 {" #c1 "[4], " #c2 "[4]}," #p "," #stride " \n" \
"vst2.8 {" #c1"[5], " #c2"[5]}," #p "," #stride " \n" \ "vst2.8 {" #c1 "[5], " #c2 "[5]}," #p "," #stride " \n" \
"vst2.8 {" #c1"[6], " #c2"[6]}," #p "," #stride " \n" \ "vst2.8 {" #c1 "[6], " #c2 "[6]}," #p "," #stride " \n" \
"vst2.8 {" #c1"[7], " #c2"[7]}," #p "," #stride " \n" "vst2.8 {" #c1 "[7], " #c2 "[7]}," #p "," #stride " \n"
#if !defined(WORK_AROUND_GCC) #if !defined(WORK_AROUND_GCC)
......
...@@ -36,14 +36,9 @@ extern "C" { ...@@ -36,14 +36,9 @@ extern "C" {
# define LOCAL_GCC_PREREQ(maj, min) 0 # define LOCAL_GCC_PREREQ(maj, min) 0
#endif #endif
#ifdef __clang__ #ifndef __has_builtin
# define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__) # define __has_builtin(x) 0
# define LOCAL_CLANG_PREREQ(maj, min) \ #endif
(LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
#else
# define LOCAL_CLANG_VERSION 0
# define LOCAL_CLANG_PREREQ(maj, min) 0
#endif // __clang__
#if defined(_MSC_VER) && _MSC_VER > 1310 && \ #if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86)) (defined(_M_X64) || defined(_M_IX86))
...@@ -73,7 +68,8 @@ extern "C" { ...@@ -73,7 +68,8 @@ extern "C" {
#define WEBP_USE_NEON #define WEBP_USE_NEON
#endif #endif
#if defined(__mips__) && !defined(__mips64) && (__mips_isa_rev < 6) #if defined(__mips__) && !defined(__mips64) && \
defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
#define WEBP_USE_MIPS32 #define WEBP_USE_MIPS32
#if (__mips_isa_rev >= 2) #if (__mips_isa_rev >= 2)
#define WEBP_USE_MIPS32_R2 #define WEBP_USE_MIPS32_R2
......
This diff is collapsed.
...@@ -285,28 +285,28 @@ static VP8LStreaks HuffmanCostCombinedCount(const uint32_t* X, ...@@ -285,28 +285,28 @@ static VP8LStreaks HuffmanCostCombinedCount(const uint32_t* X,
// literal_ and successive histograms could be unaligned // literal_ and successive histograms could be unaligned
// so we must use ulw and usw // so we must use ulw and usw
#define ADD_TO_OUT(A, B, C, D, E, P0, P1, P2) \ #define ADD_TO_OUT(A, B, C, D, E, P0, P1, P2) \
"ulw %[temp0], "#A"(%["#P0"]) \n\t" \ "ulw %[temp0], " #A "(%[" #P0 "]) \n\t" \
"ulw %[temp1], "#B"(%["#P0"]) \n\t" \ "ulw %[temp1], " #B "(%[" #P0 "]) \n\t" \
"ulw %[temp2], "#C"(%["#P0"]) \n\t" \ "ulw %[temp2], " #C "(%[" #P0 "]) \n\t" \
"ulw %[temp3], "#D"(%["#P0"]) \n\t" \ "ulw %[temp3], " #D "(%[" #P0 "]) \n\t" \
"ulw %[temp4], "#A"(%["#P1"]) \n\t" \ "ulw %[temp4], " #A "(%[" #P1 "]) \n\t" \
"ulw %[temp5], "#B"(%["#P1"]) \n\t" \ "ulw %[temp5], " #B "(%[" #P1 "]) \n\t" \
"ulw %[temp6], "#C"(%["#P1"]) \n\t" \ "ulw %[temp6], " #C "(%[" #P1 "]) \n\t" \
"ulw %[temp7], "#D"(%["#P1"]) \n\t" \ "ulw %[temp7], " #D "(%[" #P1 "]) \n\t" \
"addu %[temp4], %[temp4], %[temp0] \n\t" \ "addu %[temp4], %[temp4], %[temp0] \n\t" \
"addu %[temp5], %[temp5], %[temp1] \n\t" \ "addu %[temp5], %[temp5], %[temp1] \n\t" \
"addu %[temp6], %[temp6], %[temp2] \n\t" \ "addu %[temp6], %[temp6], %[temp2] \n\t" \
"addu %[temp7], %[temp7], %[temp3] \n\t" \ "addu %[temp7], %[temp7], %[temp3] \n\t" \
"addiu %["#P0"], %["#P0"], 16 \n\t" \ "addiu %[" #P0 "], %[" #P0 "], 16 \n\t" \
".if "#E" == 1 \n\t" \ ".if " #E " == 1 \n\t" \
"addiu %["#P1"], %["#P1"], 16 \n\t" \ "addiu %[" #P1 "], %[" #P1 "], 16 \n\t" \
".endif \n\t" \ ".endif \n\t" \
"usw %[temp4], "#A"(%["#P2"]) \n\t" \ "usw %[temp4], " #A "(%[" #P2 "]) \n\t" \
"usw %[temp5], "#B"(%["#P2"]) \n\t" \ "usw %[temp5], " #B "(%[" #P2 "]) \n\t" \
"usw %[temp6], "#C"(%["#P2"]) \n\t" \ "usw %[temp6], " #C "(%[" #P2 "]) \n\t" \
"usw %[temp7], "#D"(%["#P2"]) \n\t" \ "usw %[temp7], " #D "(%[" #P2 "]) \n\t" \
"addiu %["#P2"], %["#P2"], 16 \n\t" \ "addiu %[" #P2 "], %[" #P2 "], 16 \n\t" \
"bne %["#P0"], %[LoopEnd], 1b \n\t" \ "bne %[" #P0 "], %[LoopEnd], 1b \n\t" \
".set pop \n\t" \ ".set pop \n\t" \
#define ASM_END_COMMON_0 \ #define ASM_END_COMMON_0 \
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include "../dsp/lossless.h" #include "../dsp/lossless.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#define ALIGN_CST 15
#define DO_ALIGN(PTR) ((uintptr_t)((PTR) + ALIGN_CST) & ~ALIGN_CST)
#define MAX_COST 1.e38 #define MAX_COST 1.e38
// Number of partitions for the three dominant (literal, red and blue) symbol // Number of partitions for the three dominant (literal, red and blue) symbol
...@@ -101,9 +104,9 @@ VP8LHistogram* VP8LAllocateHistogram(int cache_bits) { ...@@ -101,9 +104,9 @@ VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) { VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
int i; int i;
VP8LHistogramSet* set; VP8LHistogramSet* set;
const size_t total_size = sizeof(*set) const int histo_size = VP8LGetHistogramSize(cache_bits);
+ sizeof(*set->histograms) * size const size_t total_size =
+ (size_t)VP8LGetHistogramSize(cache_bits) * size; sizeof(*set) + size * (sizeof(*set->histograms) + histo_size + ALIGN_CST);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
if (memory == NULL) return NULL; if (memory == NULL) return NULL;
...@@ -114,12 +117,12 @@ VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) { ...@@ -114,12 +117,12 @@ VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
set->max_size = size; set->max_size = size;
set->size = size; set->size = size;
for (i = 0; i < size; ++i) { for (i = 0; i < size; ++i) {
memory = (uint8_t*)DO_ALIGN(memory);
set->histograms[i] = (VP8LHistogram*)memory; set->histograms[i] = (VP8LHistogram*)memory;
// literal_ won't necessary be aligned. // literal_ won't necessary be aligned.
set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
VP8LHistogramInit(set->histograms[i], cache_bits); VP8LHistogramInit(set->histograms[i], cache_bits);
// There's no padding/alignment between successive histograms. memory += histo_size;
memory += VP8LGetHistogramSize(cache_bits);
} }
return set; return set;
} }
......
...@@ -175,17 +175,13 @@ static void RescalePlane(const uint8_t* src, ...@@ -175,17 +175,13 @@ static void RescalePlane(const uint8_t* src,
int src_width, int src_height, int src_stride, int src_width, int src_height, int src_stride,
uint8_t* dst, uint8_t* dst,
int dst_width, int dst_height, int dst_stride, int dst_width, int dst_height, int dst_stride,
int32_t* const work, rescaler_t* const work,
int num_channels) { int num_channels) {
WebPRescaler rescaler; WebPRescaler rescaler;
int y = 0; int y = 0;
WebPRescalerInit(&rescaler, src_width, src_height, WebPRescalerInit(&rescaler, src_width, src_height,
dst, dst_width, dst_height, dst_stride, dst, dst_width, dst_height, dst_stride,
num_channels, num_channels, work);
src_width, dst_width,
src_height, dst_height,
work);
memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
while (y < src_height) { while (y < src_height) {
y += WebPRescalerImport(&rescaler, src_height - y, y += WebPRescalerImport(&rescaler, src_height - y,
src + y * src_stride, src_stride); src + y * src_stride, src_stride);
...@@ -209,7 +205,7 @@ static void AlphaMultiplyY(WebPPicture* const pic, int inverse) { ...@@ -209,7 +205,7 @@ static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
int WebPPictureRescale(WebPPicture* pic, int width, int height) { int WebPPictureRescale(WebPPicture* pic, int width, int height) {
WebPPicture tmp; WebPPicture tmp;
int prev_width, prev_height; int prev_width, prev_height;
int32_t* work; rescaler_t* work;
if (pic == NULL) return 0; if (pic == NULL) return 0;
prev_width = pic->width; prev_width = pic->width;
...@@ -231,7 +227,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) { ...@@ -231,7 +227,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
if (!WebPPictureAlloc(&tmp)) return 0; if (!WebPPictureAlloc(&tmp)) return 0;
if (!pic->use_argb) { if (!pic->use_argb) {
work = (int32_t*)WebPSafeMalloc(2ULL * width, sizeof(*work)); work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
if (work == NULL) { if (work == NULL) {
WebPPictureFree(&tmp); WebPPictureFree(&tmp);
return 0; return 0;
...@@ -259,7 +255,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) { ...@@ -259,7 +255,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
tmp.v, tmp.v,
HALVE(width), HALVE(height), tmp.uv_stride, work, 1); HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
} else { } else {
work = (int32_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work)); work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
if (work == NULL) { if (work == NULL) {
WebPPictureFree(&tmp); WebPPictureFree(&tmp);
return 0; return 0;
......
...@@ -30,7 +30,7 @@ extern "C" { ...@@ -30,7 +30,7 @@ extern "C" {
// version numbers // version numbers
#define ENC_MAJ_VERSION 0 #define ENC_MAJ_VERSION 0
#define ENC_MIN_VERSION 4 #define ENC_MIN_VERSION 4
#define ENC_REV_VERSION 3 #define ENC_REV_VERSION 4
// intra prediction modes // intra prediction modes
enum { B_DC_PRED = 0, // 4x4 modes enum { B_DC_PRED = 0, // 4x4 modes
......
...@@ -35,14 +35,14 @@ ...@@ -35,14 +35,14 @@
#endif #endif
#if !defined(HAVE_CONFIG_H) #if !defined(HAVE_CONFIG_H)
// clang-3.3 and gcc-4.3 have builtin functions for swap32/swap64 #if LOCAL_GCC_PREREQ(4,8) || __has_builtin(__builtin_bswap16)
#if LOCAL_GCC_PREREQ(4,3) || LOCAL_CLANG_PREREQ(3,3) #define HAVE_BUILTIN_BSWAP16
#endif
#if LOCAL_GCC_PREREQ(4,3) || __has_builtin(__builtin_bswap32)
#define HAVE_BUILTIN_BSWAP32 #define HAVE_BUILTIN_BSWAP32
#define HAVE_BUILTIN_BSWAP64
#endif #endif
// clang-3.3 and gcc-4.8 have a builtin function for swap16 #if LOCAL_GCC_PREREQ(4,3) || __has_builtin(__builtin_bswap64)
#if LOCAL_GCC_PREREQ(4,8) || LOCAL_CLANG_PREREQ(3,3) #define HAVE_BUILTIN_BSWAP64
#define HAVE_BUILTIN_BSWAP16
#endif #endif
#endif // !HAVE_CONFIG_H #endif // !HAVE_CONFIG_H
......
This diff is collapsed.
...@@ -21,20 +21,23 @@ extern "C" { ...@@ -21,20 +21,23 @@ extern "C" {
#include "../webp/types.h" #include "../webp/types.h"
// Structure used for on-the-fly rescaling // Structure used for on-the-fly rescaling
typedef uint32_t rescaler_t; // type for side-buffer
typedef struct { typedef struct {
int x_expand; // true if we're expanding in the x direction int x_expand; // true if we're expanding in the x direction
int y_expand; // true if we're expanding in the y direction
int num_channels; // bytes to jump between pixels int num_channels; // bytes to jump between pixels
int fy_scale, fx_scale; // fixed-point scaling factor uint32_t fx_scale; // fixed-point scaling factors
int64_t fxy_scale; // '' uint32_t fy_scale; // ''
// we need hpel-precise add/sub increments, for the downsampled U/V planes. uint32_t fxy_scale; // ''
int y_accum; // vertical accumulator int y_accum; // vertical accumulator
int y_add, y_sub; // vertical increments (add ~= src, sub ~= dst) int y_add, y_sub; // vertical increments
int x_add, x_sub; // horizontal increments (add ~= src, sub ~= dst) int x_add, x_sub; // horizontal increments
int src_width, src_height; // source dimensions int src_width, src_height; // source dimensions
int dst_width, dst_height; // destination dimensions int dst_width, dst_height; // destination dimensions
int src_y, dst_y; // row counters for input and output
uint8_t* dst; uint8_t* dst;
int dst_stride; int dst_stride;
int32_t* irow, *frow; // work buffer rescaler_t* irow, *frow; // work buffer
} WebPRescaler; } WebPRescaler;
// Initialize a rescaler given scratch area 'work' and dimensions of src & dst. // Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
...@@ -43,9 +46,7 @@ void WebPRescalerInit(WebPRescaler* const rescaler, ...@@ -43,9 +46,7 @@ void WebPRescalerInit(WebPRescaler* const rescaler,
uint8_t* const dst, uint8_t* const dst,
int dst_width, int dst_height, int dst_stride, int dst_width, int dst_height, int dst_stride,
int num_channels, int num_channels,
int x_add, int x_sub, rescaler_t* const work);
int y_add, int y_sub,
int32_t* const work);
// Returns the number of input lines needed next to produce one output line, // Returns the number of input lines needed next to produce one output line,
// considering that the maximum available input lines are 'max_num_lines'. // considering that the maximum available input lines are 'max_num_lines'.
...@@ -57,21 +58,29 @@ int WebPRescaleNeededLines(const WebPRescaler* const rescaler, ...@@ -57,21 +58,29 @@ int WebPRescaleNeededLines(const WebPRescaler* const rescaler,
int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows, int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows,
const uint8_t* src, int src_stride); const uint8_t* src, int src_stride);
// Import a row of data and save its contribution in the rescaler. // Export as many rows as possible. Return the numbers of rows written.
// 'channel' denotes the channel number to be imported. int WebPRescalerExport(WebPRescaler* const rescaler);
extern void (*WebPRescalerImportRow)(WebPRescaler* const wrk, void WebPRescalerImportRow(WebPRescaler* const wrk,
const uint8_t* const src, int channel); const uint8_t* src);
// Export one row (starting at x_out position) from rescaler. // Export one row (starting at x_out position) from rescaler.
extern void (*WebPRescalerExportRow)(WebPRescaler* const wrk, int x_out); void WebPRescalerExportRow(WebPRescaler* const wrk);
// Return true if there is pending output rows ready. // Return true if input is finished
static WEBP_INLINE static WEBP_INLINE
int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) { int WebPRescalerInputDone(const WebPRescaler* const rescaler) {
return (rescaler->y_accum <= 0); return (rescaler->src_y >= rescaler->src_height);
}
// Return true if output is finished
static WEBP_INLINE
int WebPRescalerOutputDone(const WebPRescaler* const rescaler) {
return (rescaler->dst_y >= rescaler->dst_height);
} }
// Export as many rows as possible. Return the numbers of rows written. // Return true if there are pending output rows ready.
int WebPRescalerExport(WebPRescaler* const rescaler); static WEBP_INLINE
int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
return !WebPRescalerOutputDone(rescaler) && (rescaler->y_accum <= 0);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment