Bump libwebp to v1.4.0

This commit is contained in:
Vincent Rabaud 2024-04-17 14:36:44 +02:00
parent 05a54b1405
commit 85673afb47
52 changed files with 701 additions and 548 deletions

View File

@ -90,8 +90,8 @@ static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
int rgb_bit_depth, int rgb_bit_depth,
SharpYuvTransferFunctionType transfer_type) { SharpYuvTransferFunctionType transfer_type) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
int i; int i = 0;
for (i = 0; i < w; ++i) { do {
const uint32_t R = const uint32_t R =
SharpYuvGammaToLinear(src[0 * w + i], bit_depth, transfer_type); SharpYuvGammaToLinear(src[0 * w + i], bit_depth, transfer_type);
const uint32_t G = const uint32_t G =
@ -100,14 +100,14 @@ static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
SharpYuvGammaToLinear(src[2 * w + i], bit_depth, transfer_type); SharpYuvGammaToLinear(src[2 * w + i], bit_depth, transfer_type);
const uint32_t Y = RGBToGray(R, G, B); const uint32_t Y = RGBToGray(R, G, B);
dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth, transfer_type); dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth, transfer_type);
} } while (++i < w);
} }
static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2, static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
fixed_t* dst, int uv_w, int rgb_bit_depth, fixed_t* dst, int uv_w, int rgb_bit_depth,
SharpYuvTransferFunctionType transfer_type) { SharpYuvTransferFunctionType transfer_type) {
int i; int i = 0;
for (i = 0; i < uv_w; ++i) { do {
const int r = const int r =
ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0], ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0],
src2[0 * uv_w + 1], rgb_bit_depth, transfer_type); src2[0 * uv_w + 1], rgb_bit_depth, transfer_type);
@ -124,15 +124,15 @@ static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
dst += 1; dst += 1;
src1 += 2; src1 += 2;
src2 += 2; src2 += 2;
} } while (++i < uv_w);
} }
static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) { static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
int i; int i = 0;
assert(w > 0); assert(w > 0);
for (i = 0; i < w; ++i) { do {
y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]); y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
} } while (++i < w);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -158,9 +158,9 @@ static void ImportOneRow(const uint8_t* const r_ptr,
// Convert the rgb_step from a number of bytes to a number of uint8_t or // Convert the rgb_step from a number of bytes to a number of uint8_t or
// uint16_t values depending the bit depth. // uint16_t values depending the bit depth.
const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step; const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step;
int i; int i = 0;
const int w = (pic_width + 1) & ~1; const int w = (pic_width + 1) & ~1;
for (i = 0; i < pic_width; ++i) { do {
const int off = i * step; const int off = i * step;
const int shift = GetPrecisionShift(rgb_bit_depth); const int shift = GetPrecisionShift(rgb_bit_depth);
if (rgb_bit_depth == 8) { if (rgb_bit_depth == 8) {
@ -172,7 +172,7 @@ static void ImportOneRow(const uint8_t* const r_ptr,
dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift); dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift);
dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift); dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift);
} }
} } while (++i < pic_width);
if (pic_width & 1) { // replicate rightmost pixel if (pic_width & 1) { // replicate rightmost pixel
dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1]; dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1]; dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
@ -240,8 +240,11 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
const int sfix = GetPrecisionShift(rgb_bit_depth); const int sfix = GetPrecisionShift(rgb_bit_depth);
const int yuv_max = (1 << yuv_bit_depth) - 1; const int yuv_max = (1 << yuv_bit_depth) - 1;
for (best_uv = best_uv_base, j = 0; j < height; ++j) { best_uv = best_uv_base;
for (i = 0; i < width; ++i) { j = 0;
do {
i = 0;
do {
const int off = (i >> 1); const int off = (i >> 1);
const int W = best_y[i]; const int W = best_y[i];
const int r = best_uv[off + 0 * uv_w] + W; const int r = best_uv[off + 0 * uv_w] + W;
@ -253,19 +256,22 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
} else { } else {
((uint16_t*)y_ptr)[i] = clip(y, yuv_max); ((uint16_t*)y_ptr)[i] = clip(y, yuv_max);
} }
} } while (++i < width);
best_y += w; best_y += w;
best_uv += (j & 1) * 3 * uv_w; best_uv += (j & 1) * 3 * uv_w;
y_ptr += y_stride; y_ptr += y_stride;
} } while (++j < height);
for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
for (i = 0; i < uv_w; ++i) { best_uv = best_uv_base;
const int off = i; j = 0;
do {
i = 0;
do {
// Note r, g and b values here are off by W, but a constant offset on all // Note r, g and b values here are off by W, but a constant offset on all
// 3 components doesn't change the value of u and v with a YCbCr matrix. // 3 components doesn't change the value of u and v with a YCbCr matrix.
const int r = best_uv[off + 0 * uv_w]; const int r = best_uv[i + 0 * uv_w];
const int g = best_uv[off + 1 * uv_w]; const int g = best_uv[i + 1 * uv_w];
const int b = best_uv[off + 2 * uv_w]; const int b = best_uv[i + 2 * uv_w];
const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix); const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix);
const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix); const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix);
if (yuv_bit_depth <= 8) { if (yuv_bit_depth <= 8) {
@ -275,11 +281,11 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
((uint16_t*)u_ptr)[i] = clip(u, yuv_max); ((uint16_t*)u_ptr)[i] = clip(u, yuv_max);
((uint16_t*)v_ptr)[i] = clip(v, yuv_max); ((uint16_t*)v_ptr)[i] = clip(v, yuv_max);
} }
} } while (++i < uv_w);
best_uv += 3 * uv_w; best_uv += 3 * uv_w;
u_ptr += u_stride; u_ptr += u_stride;
v_ptr += v_stride; v_ptr += v_stride;
} } while (++j < uv_h);
return 1; return 1;
} }
@ -292,7 +298,7 @@ static void* SafeMalloc(uint64_t nmemb, size_t size) {
return malloc((size_t)total_size); return malloc((size_t)total_size);
} }
#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T))) #define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((uint64_t)(W) * (H), sizeof(T)))
static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr, static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
const uint8_t* b_ptr, int rgb_step, int rgb_stride, const uint8_t* b_ptr, int rgb_step, int rgb_stride,
@ -307,6 +313,7 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
const int h = (height + 1) & ~1; const int h = (height + 1) & ~1;
const int uv_w = w >> 1; const int uv_w = w >> 1;
const int uv_h = h >> 1; const int uv_h = h >> 1;
const int y_bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
uint64_t prev_diff_y_sum = ~0; uint64_t prev_diff_y_sum = ~0;
int j, iter; int j, iter;
@ -377,7 +384,8 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
best_uv = best_uv_base; best_uv = best_uv_base;
target_y = target_y_base; target_y = target_y_base;
target_uv = target_uv_base; target_uv = target_uv_base;
for (j = 0; j < h; j += 2) { j = 0;
do {
fixed_y_t* const src1 = tmp_buffer + 0 * w; fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w; fixed_y_t* const src2 = tmp_buffer + 3 * w;
{ {
@ -394,15 +402,15 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
// update two rows of Y and one row of RGB // update two rows of Y and one row of RGB
diff_y_sum += diff_y_sum +=
SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w, SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w, y_bit_depth);
rgb_bit_depth + GetPrecisionShift(rgb_bit_depth));
SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w); SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
best_y += 2 * w; best_y += 2 * w;
best_uv += 3 * uv_w; best_uv += 3 * uv_w;
target_y += 2 * w; target_y += 2 * w;
target_uv += 3 * uv_w; target_uv += 3 * uv_w;
} j += 2;
} while (j < h);
// test exit condition // test exit condition
if (iter > 0) { if (iter > 0) {
if (diff_y_sum < diff_y_threshold) break; if (diff_y_sum < diff_y_threshold) break;
@ -426,6 +434,7 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
free(tmp_buffer); free(tmp_buffer);
return ok; return ok;
} }
#undef SAFE_ALLOC #undef SAFE_ALLOC
#if defined(WEBP_USE_THREAD) && !defined(_WIN32) #if defined(WEBP_USE_THREAD) && !defined(_WIN32)
@ -524,7 +533,7 @@ int SharpYuvConvertWithOptions(const void* r_ptr, const void* g_ptr,
if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) { if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) {
return 0; return 0;
} }
if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) { if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride % 2 != 0)) {
// Step/stride should be even for uint16_t buffers. // Step/stride should be even for uint16_t buffers.
return 0; return 0;
} }

View File

@ -22,15 +22,13 @@ extern "C" {
#else #else
// This explicitly marks library functions and allows for changing the // This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds. // signature for e.g., Windows DLL builds.
#if defined(__GNUC__) && __GNUC__ >= 4 #if defined(_WIN32) && defined(WEBP_DLL)
#define SHARPYUV_EXTERN __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
#define SHARPYUV_EXTERN extern __attribute__((visibility("default"))) #define SHARPYUV_EXTERN extern __attribute__((visibility("default")))
#else #else
#if defined(_MSC_VER) && defined(WEBP_DLL)
#define SHARPYUV_EXTERN __declspec(dllexport)
#else
#define SHARPYUV_EXTERN extern #define SHARPYUV_EXTERN extern
#endif /* _MSC_VER && WEBP_DLL */ #endif /* defined(_WIN32) && defined(WEBP_DLL) */
#endif /* __GNUC__ >= 4 */
#endif /* WEBP_EXTERN */ #endif /* WEBP_EXTERN */
#endif /* SHARPYUV_EXTERN */ #endif /* SHARPYUV_EXTERN */

View File

@ -17,6 +17,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "sharpyuv/sharpyuv_cpu.h" #include "sharpyuv/sharpyuv_cpu.h"
#include "src/webp/types.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -69,8 +70,7 @@ uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst, void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst,
int len); int len);
void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out, const uint16_t* best_y, uint16_t* out, int bit_depth);
int bit_depth);
extern VP8CPUInfo SharpYuvGetCPUInfo; extern VP8CPUInfo SharpYuvGetCPUInfo;
extern void InitSharpYuvSSE2(void); extern void InitSharpYuvSSE2(void);

View File

@ -156,19 +156,19 @@ static float FromLinear709(float linear) {
} }
static float ToLinear470M(float gamma) { static float ToLinear470M(float gamma) {
return Powf(CLAMP(gamma, 0.f, 1.f), 1.f / 2.2f); return Powf(CLAMP(gamma, 0.f, 1.f), 2.2f);
} }
static float FromLinear470M(float linear) { static float FromLinear470M(float linear) {
return Powf(CLAMP(linear, 0.f, 1.f), 2.2f); return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.2f);
} }
static float ToLinear470Bg(float gamma) { static float ToLinear470Bg(float gamma) {
return Powf(CLAMP(gamma, 0.f, 1.f), 1.f / 2.8f); return Powf(CLAMP(gamma, 0.f, 1.f), 2.8f);
} }
static float FromLinear470Bg(float linear) { static float FromLinear470Bg(float linear) {
return Powf(CLAMP(linear, 0.f, 1.f), 2.8f); return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.8f);
} }
static float ToLinearSmpte240(float gamma) { static float ToLinearSmpte240(float gamma) {
@ -194,26 +194,26 @@ static float FromLinearSmpte240(float linear) {
} }
static float ToLinearLog100(float gamma) { static float ToLinearLog100(float gamma) {
return (gamma < 0.01f) ? 0.0f : 1.0f + Log10f(MIN(gamma, 1.f)) / 2.0f; // The function is non-bijective so choose the middle of [0, 0.01].
const float mid_interval = 0.01f / 2.f;
return (gamma <= 0.0f) ? mid_interval
: Powf(10.0f, 2.f * (MIN(gamma, 1.f) - 1.0f));
} }
static float FromLinearLog100(float linear) { static float FromLinearLog100(float linear) {
// The function is non-bijective so choose the middle of [0, 0.01]. return (linear < 0.01f) ? 0.0f : 1.0f + Log10f(MIN(linear, 1.f)) / 2.0f;
const float mid_interval = 0.01f / 2.f;
return (linear <= 0.0f) ? mid_interval
: Powf(10.0f, 2.f * (MIN(linear, 1.f) - 1.0f));
} }
static float ToLinearLog100Sqrt10(float gamma) { static float ToLinearLog100Sqrt10(float gamma) {
return (gamma < 0.00316227766f) ? 0.0f // The function is non-bijective so choose the middle of [0, 0.00316227766f[.
: 1.0f + Log10f(MIN(gamma, 1.f)) / 2.5f; const float mid_interval = 0.00316227766f / 2.f;
return (gamma <= 0.0f) ? mid_interval
: Powf(10.0f, 2.5f * (MIN(gamma, 1.f) - 1.0f));
} }
static float FromLinearLog100Sqrt10(float linear) { static float FromLinearLog100Sqrt10(float linear) {
// The function is non-bijective so choose the middle of [0, 0.00316227766f[. return (linear < 0.00316227766f) ? 0.0f
const float mid_interval = 0.00316227766f / 2.f; : 1.0f + Log10f(MIN(linear, 1.f)) / 2.5f;
return (linear < 0.0f) ? mid_interval
: Powf(10.0f, 2.5f * (MIN(linear, 1.f) - 1.0f));
} }
static float ToLinearIec61966(float gamma) { static float ToLinearIec61966(float gamma) {
@ -282,11 +282,11 @@ static float FromLinearPq(float linear) {
} }
static float ToLinearSmpte428(float gamma) { static float ToLinearSmpte428(float gamma) {
return Powf(0.91655527974030934f * MAX(gamma, 0.f), 1.f / 2.6f); return Powf(MAX(gamma, 0.f), 2.6f) / 0.91655527974030934f;
} }
static float FromLinearSmpte428(float linear) { static float FromLinearSmpte428(float linear) {
return Powf(MAX(linear, 0.f), 2.6f) / 0.91655527974030934f; return Powf(0.91655527974030934f * MAX(linear, 0.f), 1.f / 2.6f);
} }
// Conversion in BT.2100 requires RGB info. Simplify to gamma correction here. // Conversion in BT.2100 requires RGB info. Simplify to gamma correction here.

View File

@ -13,18 +13,20 @@
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/alphai_dec.h" #include "src/dec/alphai_dec.h"
#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h" #include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h" #include "src/dec/vp8li_dec.h"
#include "src/dsp/dsp.h" #include "src/dsp/dsp.h"
#include "src/utils/quant_levels_dec_utils.h" #include "src/utils/quant_levels_dec_utils.h"
#include "src/utils/utils.h" #include "src/utils/utils.h"
#include "src/webp/format_constants.h" #include "src/webp/format_constants.h"
#include "src/webp/types.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// ALPHDecoder object. // ALPHDecoder object.
// Allocates a new alpha decoder instance. // Allocates a new alpha decoder instance.
static ALPHDecoder* ALPHNew(void) { WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
return dec; return dec;
} }
@ -45,9 +47,9 @@ static void ALPHDelete(ALPHDecoder* const dec) {
// header for alpha data stored using lossless compression. // header for alpha data stored using lossless compression.
// Returns false in case of error in alpha header (data too short, invalid // Returns false in case of error in alpha header (data too short, invalid
// compression method or filter, error in lossless header data etc). // compression method or filter, error in lossless header data etc).
static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
size_t data_size, const VP8Io* const src_io, size_t data_size, const VP8Io* const src_io,
uint8_t* output) { uint8_t* output) {
int ok = 0; int ok = 0;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN; const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN; const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
@ -79,7 +81,9 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
} }
// Copy the necessary parameters from src_io to io // Copy the necessary parameters from src_io to io
VP8InitIo(io); if (!VP8InitIo(io)) {
return 0;
}
WebPInitCustomIo(NULL, io); WebPInitCustomIo(NULL, io);
io->opaque = dec; io->opaque = dec;
io->width = src_io->width; io->width = src_io->width;
@ -107,7 +111,8 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
// starting from row number 'row'. It assumes that rows up to (row - 1) have // starting from row number 'row'. It assumes that rows up to (row - 1) have
// already been decoded. // already been decoded.
// Returns false in case of bitstream error. // Returns false in case of bitstream error.
static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) { WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,
int num_rows) {
ALPHDecoder* const alph_dec = dec->alph_dec_; ALPHDecoder* const alph_dec = dec->alph_dec_;
const int width = alph_dec->width_; const int width = alph_dec->width_;
const int height = alph_dec->io_.crop_bottom; const int height = alph_dec->io_.crop_bottom;
@ -138,7 +143,8 @@ static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
return 1; return 1;
} }
static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) { WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,
const VP8Io* const io) {
const int stride = io->width; const int stride = io->width;
const int height = io->crop_bottom; const int height = io->crop_bottom;
const uint64_t alpha_size = (uint64_t)stride * height; const uint64_t alpha_size = (uint64_t)stride * height;
@ -166,9 +172,9 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main entry point. // Main entry point.
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
const VP8Io* const io, const VP8Io* const io,
int row, int num_rows) { int row, int num_rows) {
const int width = io->width; const int width = io->width;
const int height = io->crop_bottom; const int height = io->crop_bottom;

View File

@ -17,8 +17,10 @@
#include "src/dec/alphai_dec.h" #include "src/dec/alphai_dec.h"
#include "src/dec/webpi_dec.h" #include "src/dec/webpi_dec.h"
#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h" #include "src/dec/vp8i_dec.h"
#include "src/utils/utils.h" #include "src/utils/utils.h"
#include "src/webp/decode.h"
// In append mode, buffer allocations increase as multiples of this value. // In append mode, buffer allocations increase as multiples of this value.
// Needs to be a power of 2. // Needs to be a power of 2.
@ -161,8 +163,9 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
// Appends data to the end of MemBuffer->buf_. It expands the allocated memory // Appends data to the end of MemBuffer->buf_. It expands the allocated memory
// size if required and also updates VP8BitReader's if new memory is allocated. // size if required and also updates VP8BitReader's if new memory is allocated.
static int AppendToMemBuffer(WebPIDecoder* const idec, WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec,
const uint8_t* const data, size_t data_size) { const uint8_t* const data,
size_t data_size) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_; VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
MemBuffer* const mem = &idec->mem_; MemBuffer* const mem = &idec->mem_;
const int need_compressed_alpha = NeedCompressedAlpha(idec); const int need_compressed_alpha = NeedCompressedAlpha(idec);
@ -203,8 +206,9 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
return 1; return 1;
} }
static int RemapMemBuffer(WebPIDecoder* const idec, WEBP_NODISCARD static int RemapMemBuffer(WebPIDecoder* const idec,
const uint8_t* const data, size_t data_size) { const uint8_t* const data,
size_t data_size) {
MemBuffer* const mem = &idec->mem_; MemBuffer* const mem = &idec->mem_;
const uint8_t* const old_buf = mem->buf_; const uint8_t* const old_buf = mem->buf_;
const uint8_t* const old_start = const uint8_t* const old_start =
@ -237,7 +241,8 @@ static void ClearMemBuffer(MemBuffer* const mem) {
} }
} }
static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) { WEBP_NODISCARD static int CheckMemBufferMode(MemBuffer* const mem,
MemBufferMode expected) {
if (mem->mode_ == MEM_MODE_NONE) { if (mem->mode_ == MEM_MODE_NONE) {
mem->mode_ = expected; // switch to the expected mode mem->mode_ = expected; // switch to the expected mode
} else if (mem->mode_ != expected) { } else if (mem->mode_ != expected) {
@ -248,7 +253,7 @@ static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
} }
// To be called last. // To be called last.
static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
const WebPDecoderOptions* const options = idec->params_.options; const WebPDecoderOptions* const options = idec->params_.options;
WebPDecBuffer* const output = idec->params_.output; WebPDecBuffer* const output = idec->params_.output;
@ -258,8 +263,10 @@ static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
if (status != VP8_STATUS_OK) return status; if (status != VP8_STATUS_OK) return status;
} }
if (idec->final_output_ != NULL) { if (idec->final_output_ != NULL) {
WebPCopyDecBufferPixels(output, idec->final_output_); // do the slow-copy const VP8StatusCode status = WebPCopyDecBufferPixels(
output, idec->final_output_); // do the slow-copy
WebPFreeDecBuffer(&idec->output_); WebPFreeDecBuffer(&idec->output_);
if (status != VP8_STATUS_OK) return status;
*output = *idec->final_output_; *output = *idec->final_output_;
idec->final_output_ = NULL; idec->final_output_ = NULL;
} }
@ -288,7 +295,7 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) { static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) { if (idec->state_ == STATE_VP8_DATA) {
// Synchronize the thread, clean-up and check for errors. // Synchronize the thread, clean-up and check for errors.
VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
} }
idec->state_ = STATE_ERROR; idec->state_ = STATE_ERROR;
return error; return error;
@ -329,6 +336,7 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
if (dec == NULL) { if (dec == NULL) {
return VP8_STATUS_OUT_OF_MEMORY; return VP8_STATUS_OUT_OF_MEMORY;
} }
dec->incremental_ = 1;
idec->dec_ = dec; idec->dec_ = dec;
dec->alpha_data_ = headers.alpha_data; dec->alpha_data_ = headers.alpha_data;
dec->alpha_data_size_ = headers.alpha_data_size; dec->alpha_data_size_ = headers.alpha_data_size;
@ -601,8 +609,9 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Internal constructor // Internal constructor
static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer, WEBP_NODISCARD static WebPIDecoder* NewDecoder(
const WebPBitstreamFeatures* const features) { WebPDecBuffer* const output_buffer,
const WebPBitstreamFeatures* const features) {
WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec)); WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
if (idec == NULL) { if (idec == NULL) {
return NULL; return NULL;
@ -614,8 +623,10 @@ static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer,
idec->last_mb_y_ = -1; idec->last_mb_y_ = -1;
InitMemBuffer(&idec->mem_); InitMemBuffer(&idec->mem_);
WebPInitDecBuffer(&idec->output_); if (!WebPInitDecBuffer(&idec->output_) || !VP8InitIo(&idec->io_)) {
VP8InitIo(&idec->io_); WebPSafeFree(idec);
return NULL;
}
WebPResetDecParams(&idec->params_); WebPResetDecParams(&idec->params_);
if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) { if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) {
@ -674,7 +685,8 @@ void WebPIDelete(WebPIDecoder* idec) {
if (!idec->is_lossless_) { if (!idec->is_lossless_) {
if (idec->state_ == STATE_VP8_DATA) { if (idec->state_ == STATE_VP8_DATA) {
// Synchronize the thread, clean-up and check for errors. // Synchronize the thread, clean-up and check for errors.
VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); // TODO(vrabaud) do we care about the return result?
(void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
} }
VP8Delete((VP8Decoder*)idec->dec_); VP8Delete((VP8Decoder*)idec->dec_);
} else { } else {
@ -851,8 +863,8 @@ const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
return src; return src;
} }
uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y, WEBP_NODISCARD uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
int* width, int* height, int* stride) { int* width, int* height, int* stride) {
const WebPDecBuffer* const src = GetOutputBuffer(idec); const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (src == NULL) return NULL; if (src == NULL) return NULL;
if (src->colorspace >= MODE_YUV) { if (src->colorspace >= MODE_YUV) {
@ -867,10 +879,10 @@ uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
return src->u.RGBA.rgba; return src->u.RGBA.rgba;
} }
uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y, WEBP_NODISCARD uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
uint8_t** u, uint8_t** v, uint8_t** a, uint8_t** u, uint8_t** v, uint8_t** a,
int* width, int* height, int* width, int* height, int* stride,
int* stride, int* uv_stride, int* a_stride) { int* uv_stride, int* a_stride) {
const WebPDecBuffer* const src = GetOutputBuffer(idec); const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (src == NULL) return NULL; if (src == NULL) return NULL;
if (src->colorspace < MODE_YUV) { if (src->colorspace < MODE_YUV) {

View File

@ -86,6 +86,8 @@ void VP8Delete(VP8Decoder* const dec) {
int VP8SetError(VP8Decoder* const dec, int VP8SetError(VP8Decoder* const dec,
VP8StatusCode error, const char* const msg) { VP8StatusCode error, const char* const msg) {
// VP8_STATUS_SUSPENDED is only meaningful in incremental decoding.
assert(dec->incremental_ || error != VP8_STATUS_SUSPENDED);
// The oldest error reported takes precedence over the new one. // The oldest error reported takes precedence over the new one.
if (dec->status_ == VP8_STATUS_OK) { if (dec->status_ == VP8_STATUS_OK) {
dec->status_ = error; dec->status_ = error;
@ -190,12 +192,12 @@ static int ParseSegmentHeader(VP8BitReader* br,
} }
// Paragraph 9.5 // Paragraph 9.5
// This function returns VP8_STATUS_SUSPENDED if we don't have all the // If we don't have all the necessary data in 'buf', this function returns
// necessary data in 'buf'. // VP8_STATUS_SUSPENDED in incremental decoding, VP8_STATUS_NOT_ENOUGH_DATA
// This case is not necessarily an error (for incremental decoding). // otherwise.
// Still, no bitreader is ever initialized to make it possible to read // In incremental decoding, this case is not necessarily an error. Still, no
// unavailable memory. // bitreader is ever initialized to make it possible to read unavailable memory.
// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA // If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA
// is returned, and this is an unrecoverable error. // is returned, and this is an unrecoverable error.
// If the partitions were positioned ok, VP8_STATUS_OK is returned. // If the partitions were positioned ok, VP8_STATUS_OK is returned.
static VP8StatusCode ParsePartitions(VP8Decoder* const dec, static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
@ -225,8 +227,10 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
sz += 3; sz += 3;
} }
VP8InitBitReader(dec->parts_ + last_part, part_start, size_left); VP8InitBitReader(dec->parts_ + last_part, part_start, size_left);
return (part_start < buf_end) ? VP8_STATUS_OK : if (part_start < buf_end) return VP8_STATUS_OK;
VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data return dec->incremental_
? VP8_STATUS_SUSPENDED // Init is ok, but there's not enough data
: VP8_STATUS_NOT_ENOUGH_DATA;
} }
// Paragraph 9.4 // Paragraph 9.4

View File

@ -15,6 +15,7 @@
#define WEBP_DEC_VP8_DEC_H_ #define WEBP_DEC_VP8_DEC_H_
#include "src/webp/decode.h" #include "src/webp/decode.h"
#include "src/webp/types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -108,16 +109,14 @@ struct VP8Io {
}; };
// Internal, version-checked, entry point // Internal, version-checked, entry point
int VP8InitIoInternal(VP8Io* const, int); WEBP_NODISCARD int VP8InitIoInternal(VP8Io* const, int);
// Set the custom IO function pointers and user-data. The setter for IO hooks // Set the custom IO function pointers and user-data. The setter for IO hooks
// should be called before initiating incremental decoding. Returns true if // should be called before initiating incremental decoding. Returns true if
// WebPIDecoder object is successfully modified, false otherwise. // WebPIDecoder object is successfully modified, false otherwise.
int WebPISetIOHooks(WebPIDecoder* const idec, WEBP_NODISCARD int WebPISetIOHooks(WebPIDecoder* const idec, VP8IoPutHook put,
VP8IoPutHook put, VP8IoSetupHook setup,
VP8IoSetupHook setup, VP8IoTeardownHook teardown, void* user_data);
VP8IoTeardownHook teardown,
void* user_data);
// Main decoding object. This is an opaque structure. // Main decoding object. This is an opaque structure.
typedef struct VP8Decoder VP8Decoder; typedef struct VP8Decoder VP8Decoder;
@ -128,17 +127,17 @@ VP8Decoder* VP8New(void);
// Must be called to make sure 'io' is initialized properly. // Must be called to make sure 'io' is initialized properly.
// Returns false in case of version mismatch. Upon such failure, no other // Returns false in case of version mismatch. Upon such failure, no other
// decoding function should be called (VP8Decode, VP8GetHeaders, ...) // decoding function should be called (VP8Decode, VP8GetHeaders, ...)
static WEBP_INLINE int VP8InitIo(VP8Io* const io) { WEBP_NODISCARD static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION); return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
} }
// Decode the VP8 frame header. Returns true if ok. // Decode the VP8 frame header. Returns true if ok.
// Note: 'io->data' must be pointing to the start of the VP8 frame header. // Note: 'io->data' must be pointing to the start of the VP8 frame header.
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io); WEBP_NODISCARD int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Decode a picture. Will call VP8GetHeaders() if it wasn't done already. // Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
// Returns false in case of error. // Returns false in case of error.
int VP8Decode(VP8Decoder* const dec, VP8Io* const io); WEBP_NODISCARD int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
// Return current status of the decoder: // Return current status of the decoder:
VP8StatusCode VP8Status(VP8Decoder* const dec); VP8StatusCode VP8Status(VP8Decoder* const dec);

View File

@ -21,6 +21,7 @@
#include "src/utils/random_utils.h" #include "src/utils/random_utils.h"
#include "src/utils/thread_utils.h" #include "src/utils/thread_utils.h"
#include "src/dsp/dsp.h" #include "src/dsp/dsp.h"
#include "src/webp/types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -31,8 +32,8 @@ extern "C" {
// version numbers // version numbers
#define DEC_MAJ_VERSION 1 #define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 3 #define DEC_MIN_VERSION 4
#define DEC_REV_VERSION 1 #define DEC_REV_VERSION 0
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y), // Constraints are: We need to store one 16x16 block of luma samples (y),
@ -186,6 +187,7 @@ struct VP8Decoder {
// Main data source // Main data source
VP8BitReader br_; VP8BitReader br_;
int incremental_; // if true, incremental decoding is expected
// headers // headers
VP8FrameHeader frm_hdr_; VP8FrameHeader frm_hdr_;
@ -281,7 +283,7 @@ int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec);
void VP8ParseQuant(VP8Decoder* const dec); void VP8ParseQuant(VP8Decoder* const dec);
// in frame.c // in frame.c
int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io); WEBP_NODISCARD int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
// Call io->setup() and finish setting up scan parameters. // Call io->setup() and finish setting up scan parameters.
// After this call returns, one must always call VP8ExitCritical() with the // After this call returns, one must always call VP8ExitCritical() with the
// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK // same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK
@ -289,7 +291,7 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io); VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
// Must always be called in pair with VP8EnterCritical(). // Must always be called in pair with VP8EnterCritical().
// Returns false in case of error. // Returns false in case of error.
int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io); WEBP_NODISCARD int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
// Return the multi-threading method to use (0=off), depending // Return the multi-threading method to use (0=off), depending
// on options and bitstream size. Only for lossy decoding. // on options and bitstream size. Only for lossy decoding.
int VP8GetThreadMethod(const WebPDecoderOptions* const options, int VP8GetThreadMethod(const WebPDecoderOptions* const options,
@ -299,11 +301,12 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
void VP8InitDithering(const WebPDecoderOptions* const options, void VP8InitDithering(const WebPDecoderOptions* const options,
VP8Decoder* const dec); VP8Decoder* const dec);
// Process the last decoded row (filtering + output). // Process the last decoded row (filtering + output).
int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io); WEBP_NODISCARD int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
// To be called at the start of a new scanline, to initialize predictors. // To be called at the start of a new scanline, to initialize predictors.
void VP8InitScanline(VP8Decoder* const dec); void VP8InitScanline(VP8Decoder* const dec);
// Decode one macroblock. Returns false if there is not enough data. // Decode one macroblock. Returns false if there is not enough data.
int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br); WEBP_NODISCARD int VP8DecodeMB(VP8Decoder* const dec,
VP8BitReader* const token_br);
// in alpha.c // in alpha.c
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,

View File

@ -20,6 +20,7 @@
#include "src/utils/bit_reader_utils.h" #include "src/utils/bit_reader_utils.h"
#include "src/utils/color_cache_utils.h" #include "src/utils/color_cache_utils.h"
#include "src/utils/huffman_utils.h" #include "src/utils/huffman_utils.h"
#include "src/webp/types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -99,25 +100,26 @@ struct ALPHDecoder; // Defined in dec/alphai.h.
// Decodes image header for alpha data stored using lossless compression. // Decodes image header for alpha data stored using lossless compression.
// Returns false in case of error. // Returns false in case of error.
int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec, WEBP_NODISCARD int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
const uint8_t* const data, size_t data_size); const uint8_t* const data,
size_t data_size);
// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are // Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
// already decoded in previous call(s), it will resume decoding from where it // already decoded in previous call(s), it will resume decoding from where it
// was paused. // was paused.
// Returns false in case of bitstream error. // Returns false in case of bitstream error.
int VP8LDecodeAlphaImageStream(struct ALPHDecoder* const alph_dec, WEBP_NODISCARD int VP8LDecodeAlphaImageStream(
int last_row); struct ALPHDecoder* const alph_dec, int last_row);
// Allocates and initialize a new lossless decoder instance. // Allocates and initialize a new lossless decoder instance.
VP8LDecoder* VP8LNew(void); WEBP_NODISCARD VP8LDecoder* VP8LNew(void);
// Decodes the image header. Returns false in case of error. // Decodes the image header. Returns false in case of error.
int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io); WEBP_NODISCARD int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
// Decodes an image. It's required to decode the lossless header before calling // Decodes an image. It's required to decode the lossless header before calling
// this function. Returns false in case of error, with updated dec->status_. // this function. Returns false in case of error, with updated dec->status_.
int VP8LDecodeImage(VP8LDecoder* const dec); WEBP_NODISCARD int VP8LDecodeImage(VP8LDecoder* const dec);
// Resets the decoder in its initial state, reclaiming memory. // Resets the decoder in its initial state, reclaiming memory.
// Preserves the dec->status_ value. // Preserves the dec->status_ value.
@ -133,11 +135,10 @@ void VP8LDelete(VP8LDecoder* const dec);
// 'num_htree_groups' groups. If 'num_htree_groups_max' > 'num_htree_groups', // 'num_htree_groups' groups. If 'num_htree_groups_max' > 'num_htree_groups',
// some of those indices map to -1. This is used for non-balanced codes to // some of those indices map to -1. This is used for non-balanced codes to
// limit memory usage. // limit memory usage.
int ReadHuffmanCodesHelper(int color_cache_bits, int num_htree_groups, WEBP_NODISCARD int ReadHuffmanCodesHelper(
int num_htree_groups_max, const int* const mapping, int color_cache_bits, int num_htree_groups, int num_htree_groups_max,
VP8LDecoder* const dec, const int* const mapping, VP8LDecoder* const dec,
HuffmanTables* const huffman_tables, HuffmanTables* const huffman_tables, HTreeGroup** const htree_groups);
HTreeGroup** const htree_groups);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -13,11 +13,14 @@
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h" #include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h" #include "src/dec/vp8li_dec.h"
#include "src/dec/webpi_dec.h" #include "src/dec/webpi_dec.h"
#include "src/utils/utils.h" #include "src/utils/utils.h"
#include "src/webp/mux_types.h" // ALPHA_FLAG #include "src/webp/mux_types.h" // ALPHA_FLAG
#include "src/webp/decode.h"
#include "src/webp/types.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// RIFF layout is: // RIFF layout is:
@ -444,8 +447,9 @@ void WebPResetDecParams(WebPDecParams* const params) {
// "Into" decoding variants // "Into" decoding variants
// Main flow // Main flow
static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size, WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
WebPDecParams* const params) { size_t data_size,
WebPDecParams* const params) {
VP8StatusCode status; VP8StatusCode status;
VP8Io io; VP8Io io;
WebPHeaderStructure headers; WebPHeaderStructure headers;
@ -459,7 +463,9 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
} }
assert(params != NULL); assert(params != NULL);
VP8InitIo(&io); if (!VP8InitIo(&io)) {
return VP8_STATUS_INVALID_PARAM;
}
io.data = headers.data + headers.offset; io.data = headers.data + headers.offset;
io.data_size = headers.data_size - headers.offset; io.data_size = headers.data_size - headers.offset;
WebPInitCustomIo(params, &io); // Plug the I/O functions. WebPInitCustomIo(params, &io); // Plug the I/O functions.
@ -523,17 +529,16 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
} }
// Helpers // Helpers
static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace, WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
const uint8_t* const data, const uint8_t* const data,
size_t data_size, size_t data_size,
uint8_t* const rgba, uint8_t* const rgba,
int stride, size_t size) { int stride, size_t size) {
WebPDecParams params; WebPDecParams params;
WebPDecBuffer buf; WebPDecBuffer buf;
if (rgba == NULL) { if (rgba == NULL || !WebPInitDecBuffer(&buf)) {
return NULL; return NULL;
} }
WebPInitDecBuffer(&buf);
WebPResetDecParams(&params); WebPResetDecParams(&params);
params.output = &buf; params.output = &buf;
buf.colorspace = colorspace; buf.colorspace = colorspace;
@ -578,8 +583,7 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
uint8_t* v, size_t v_size, int v_stride) { uint8_t* v, size_t v_size, int v_stride) {
WebPDecParams params; WebPDecParams params;
WebPDecBuffer output; WebPDecBuffer output;
if (luma == NULL) return NULL; if (luma == NULL || !WebPInitDecBuffer(&output)) return NULL;
WebPInitDecBuffer(&output);
WebPResetDecParams(&params); WebPResetDecParams(&params);
params.output = &output; params.output = &output;
output.colorspace = MODE_YUV; output.colorspace = MODE_YUV;
@ -601,13 +605,17 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data, WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode,
size_t data_size, int* const width, int* const height, const uint8_t* const data,
WebPDecBuffer* const keep_info) { size_t data_size, int* const width,
int* const height,
WebPDecBuffer* const keep_info) {
WebPDecParams params; WebPDecParams params;
WebPDecBuffer output; WebPDecBuffer output;
WebPInitDecBuffer(&output); if (!WebPInitDecBuffer(&output)) {
return NULL;
}
WebPResetDecParams(&params); WebPResetDecParams(&params);
params.output = &output; params.output = &output;
output.colorspace = mode; output.colorspace = mode;
@ -733,7 +741,9 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
} }
memset(config, 0, sizeof(*config)); memset(config, 0, sizeof(*config));
DefaultFeatures(&config->input); DefaultFeatures(&config->input);
WebPInitDecBuffer(&config->output); if (!WebPInitDecBuffer(&config->output)) {
return 0;
}
return 1; return 1;
} }
@ -772,7 +782,9 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
if (WebPAvoidSlowMemory(params.output, &config->input)) { if (WebPAvoidSlowMemory(params.output, &config->input)) {
// decoding to slow memory: use a temporary in-mem buffer to decode into. // decoding to slow memory: use a temporary in-mem buffer to decode into.
WebPDecBuffer in_mem_buffer; WebPDecBuffer in_mem_buffer;
WebPInitDecBuffer(&in_mem_buffer); if (!WebPInitDecBuffer(&in_mem_buffer)) {
return VP8_STATUS_INVALID_PARAM;
}
in_mem_buffer.colorspace = config->output.colorspace; in_mem_buffer.colorspace = config->output.colorspace;
in_mem_buffer.width = config->input.width; in_mem_buffer.width = config->input.width;
in_mem_buffer.height = config->input.height; in_mem_buffer.height = config->input.height;

View File

@ -20,6 +20,7 @@ extern "C" {
#include "src/utils/rescaler_utils.h" #include "src/utils/rescaler_utils.h"
#include "src/dec/vp8_dec.h" #include "src/dec/vp8_dec.h"
#include "src/webp/decode.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// WebPDecParams: Decoding output parameters. Transient internal object. // WebPDecParams: Decoding output parameters. Transient internal object.
@ -87,8 +88,9 @@ void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers // Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers
// to the *compressed* format, not the output one. // to the *compressed* format, not the output one.
int WebPIoInitFromOptions(const WebPDecoderOptions* const options, WEBP_NODISCARD int WebPIoInitFromOptions(
VP8Io* const io, WEBP_CSP_MODE src_colorspace); const WebPDecoderOptions* const options, VP8Io* const io,
WEBP_CSP_MODE src_colorspace);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Internal functions regarding WebPDecBuffer memory (in buffer.c). // Internal functions regarding WebPDecBuffer memory (in buffer.c).

View File

@ -20,6 +20,7 @@
#include "src/utils/utils.h" #include "src/utils/utils.h"
#include "src/webp/decode.h" #include "src/webp/decode.h"
#include "src/webp/demux.h" #include "src/webp/demux.h"
#include "src/webp/types.h"
#define NUM_CHANNELS 4 #define NUM_CHANNELS 4
@ -68,8 +69,9 @@ int WebPAnimDecoderOptionsInitInternal(WebPAnimDecoderOptions* dec_options,
return 1; return 1;
} }
static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options, WEBP_NODISCARD static int ApplyDecoderOptions(
WebPAnimDecoder* const dec) { const WebPAnimDecoderOptions* const dec_options,
WebPAnimDecoder* const dec) {
WEBP_CSP_MODE mode; WEBP_CSP_MODE mode;
WebPDecoderConfig* config = &dec->config_; WebPDecoderConfig* config = &dec->config_;
assert(dec_options != NULL); assert(dec_options != NULL);
@ -82,7 +84,9 @@ static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA) dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA)
? &BlendPixelRowNonPremult ? &BlendPixelRowNonPremult
: &BlendPixelRowPremult; : &BlendPixelRowPremult;
WebPInitDecoderConfig(config); if (!WebPInitDecoderConfig(config)) {
return 0;
}
config->output.colorspace = mode; config->output.colorspace = mode;
config->output.is_external_memory = 1; config->output.is_external_memory = 1;
config->options.use_threads = dec_options->use_threads; config->options.use_threads = dec_options->use_threads;
@ -157,8 +161,8 @@ static int IsFullFrame(int width, int height, int canvas_width,
} }
// Clear the canvas to transparent. // Clear the canvas to transparent.
static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width, WEBP_NODISCARD static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
uint32_t canvas_height) { uint32_t canvas_height) {
const uint64_t size = const uint64_t size =
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf); (uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
if (!CheckSizeOverflow(size)) return 0; if (!CheckSizeOverflow(size)) return 0;
@ -179,8 +183,8 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
} }
// Copy width * height pixels from 'src' to 'dst'. // Copy width * height pixels from 'src' to 'dst'.
static int CopyCanvas(const uint8_t* src, uint8_t* dst, WEBP_NODISCARD static int CopyCanvas(const uint8_t* src, uint8_t* dst,
uint32_t width, uint32_t height) { uint32_t width, uint32_t height) {
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS; const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
if (!CheckSizeOverflow(size)) return 0; if (!CheckSizeOverflow(size)) return 0;
assert(src != NULL && dst != NULL); assert(src != NULL && dst != NULL);
@ -424,7 +428,9 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
WebPDemuxReleaseIterator(&dec->prev_iter_); WebPDemuxReleaseIterator(&dec->prev_iter_);
dec->prev_iter_ = iter; dec->prev_iter_ = iter;
dec->prev_frame_was_keyframe_ = is_key_frame; dec->prev_frame_was_keyframe_ = is_key_frame;
CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height); if (!CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height)) {
goto Error;
}
if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS, ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS,
dec->prev_iter_.x_offset, dec->prev_iter_.y_offset, dec->prev_iter_.x_offset, dec->prev_iter_.y_offset,

View File

@ -24,8 +24,8 @@
#include "src/webp/format_constants.h" #include "src/webp/format_constants.h"
#define DMUX_MAJ_VERSION 1 #define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 3 #define DMUX_MIN_VERSION 4
#define DMUX_REV_VERSION 1 #define DMUX_REV_VERSION 0
typedef struct { typedef struct {
size_t start_; // start location of the data size_t start_; // start location of the data

View File

@ -36,18 +36,6 @@ static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type), "c"(0)); : "a"(info_type), "c"(0));
} }
#elif defined(__x86_64__) && \
(defined(__code_model_medium__) || defined(__code_model_large__)) && \
defined(__PIC__)
static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
"xchg{q}\t{%%rbx}, %q1\n"
"cpuid\n"
"xchg{q}\t{%%rbx}, %q1\n"
: "=a"(cpu_info[0]), "=&r"(cpu_info[1]), "=c"(cpu_info[2]),
"=d"(cpu_info[3])
: "a"(info_type), "c"(0));
}
#elif defined(__i386__) || defined(__x86_64__) #elif defined(__i386__) || defined(__x86_64__)
static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) { static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile ( __asm__ volatile (

View File

@ -37,9 +37,6 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
STORE(3, y, DC - (d)); \ STORE(3, y, DC - (d)); \
} while (0) } while (0)
#define MUL1(a) ((((a) * 20091) >> 16) + (a))
#define MUL2(a) (((a) * 35468) >> 16)
#if !WEBP_NEON_OMIT_C_CODE #if !WEBP_NEON_OMIT_C_CODE
static void TransformOne_C(const int16_t* in, uint8_t* dst) { static void TransformOne_C(const int16_t* in, uint8_t* dst) {
int C[4 * 4], *tmp; int C[4 * 4], *tmp;
@ -48,8 +45,10 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
for (i = 0; i < 4; ++i) { // vertical pass for (i = 0; i < 4; ++i) { // vertical pass
const int a = in[0] + in[8]; // [-4096, 4094] const int a = in[0] + in[8]; // [-4096, 4094]
const int b = in[0] - in[8]; // [-4095, 4095] const int b = in[0] - in[8]; // [-4095, 4095]
const int c = MUL2(in[4]) - MUL1(in[12]); // [-3783, 3783] const int c = WEBP_TRANSFORM_AC3_MUL2(in[4]) -
const int d = MUL1(in[4]) + MUL2(in[12]); // [-3785, 3781] WEBP_TRANSFORM_AC3_MUL1(in[12]); // [-3783, 3783]
const int d = WEBP_TRANSFORM_AC3_MUL1(in[4]) +
WEBP_TRANSFORM_AC3_MUL2(in[12]); // [-3785, 3781]
tmp[0] = a + d; // [-7881, 7875] tmp[0] = a + d; // [-7881, 7875]
tmp[1] = b + c; // [-7878, 7878] tmp[1] = b + c; // [-7878, 7878]
tmp[2] = b - c; // [-7878, 7878] tmp[2] = b - c; // [-7878, 7878]
@ -69,8 +68,10 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
const int dc = tmp[0] + 4; const int dc = tmp[0] + 4;
const int a = dc + tmp[8]; const int a = dc + tmp[8];
const int b = dc - tmp[8]; const int b = dc - tmp[8];
const int c = MUL2(tmp[4]) - MUL1(tmp[12]); const int c =
const int d = MUL1(tmp[4]) + MUL2(tmp[12]); WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]);
const int d =
WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]);
STORE(0, 0, a + d); STORE(0, 0, a + d);
STORE(1, 0, b + c); STORE(1, 0, b + c);
STORE(2, 0, b - c); STORE(2, 0, b - c);
@ -83,17 +84,15 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
// Simplified transform when only in[0], in[1] and in[4] are non-zero // Simplified transform when only in[0], in[1] and in[4] are non-zero
static void TransformAC3_C(const int16_t* in, uint8_t* dst) { static void TransformAC3_C(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4; const int a = in[0] + 4;
const int c4 = MUL2(in[4]); const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
const int d4 = MUL1(in[4]); const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
const int c1 = MUL2(in[1]); const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
const int d1 = MUL1(in[1]); const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
STORE2(0, a + d4, d1, c1); STORE2(0, a + d4, d1, c1);
STORE2(1, a + c4, d1, c1); STORE2(1, a + c4, d1, c1);
STORE2(2, a - c4, d1, c1); STORE2(2, a - c4, d1, c1);
STORE2(3, a - d4, d1, c1); STORE2(3, a - d4, d1, c1);
} }
#undef MUL1
#undef MUL2
#undef STORE2 #undef STORE2
static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) { static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) {

View File

@ -18,8 +18,8 @@
#include "src/dsp/mips_macro.h" #include "src/dsp/mips_macro.h"
static const int kC1 = 20091 + (1 << 16); static const int kC1 = WEBP_TRANSFORM_AC3_C1;
static const int kC2 = 35468; static const int kC2 = WEBP_TRANSFORM_AC3_C2;
static WEBP_INLINE int abs_mips32(int x) { static WEBP_INLINE int abs_mips32(int x) {
const int sign = x >> 31; const int sign = x >> 31;
@ -219,7 +219,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
int temp0, temp1, temp2, temp3, temp4; int temp0, temp1, temp2, temp3, temp4;
int temp5, temp6, temp7, temp8, temp9; int temp5, temp6, temp7, temp8, temp9;
int temp10, temp11, temp12, temp13, temp14; int temp10, temp11, temp12, temp13, temp14;
int temp15, temp16, temp17, temp18; int temp15, temp16, temp17, temp18, temp19;
int16_t* p_in = (int16_t*)in; int16_t* p_in = (int16_t*)in;
// loops unrolled and merged to avoid usage of tmp buffer // loops unrolled and merged to avoid usage of tmp buffer
@ -233,16 +233,14 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp16], %[temp0], %[temp8] \n\t" "addu %[temp16], %[temp0], %[temp8] \n\t"
"subu %[temp0], %[temp0], %[temp8] \n\t" "subu %[temp0], %[temp0], %[temp8] \n\t"
"mul %[temp8], %[temp4], %[kC2] \n\t" "mul %[temp8], %[temp4], %[kC2] \n\t"
"mul %[temp17], %[temp12], %[kC1] \n\t" MUL_SHIFT_C1(temp17, temp12)
"mul %[temp4], %[temp4], %[kC1] \n\t" MUL_SHIFT_C1_IO(temp4, temp19)
"mul %[temp12], %[temp12], %[kC2] \n\t" "mul %[temp12], %[temp12], %[kC2] \n\t"
"lh %[temp1], 2(%[in]) \n\t" "lh %[temp1], 2(%[in]) \n\t"
"lh %[temp5], 10(%[in]) \n\t" "lh %[temp5], 10(%[in]) \n\t"
"lh %[temp9], 18(%[in]) \n\t" "lh %[temp9], 18(%[in]) \n\t"
"lh %[temp13], 26(%[in]) \n\t" "lh %[temp13], 26(%[in]) \n\t"
"sra %[temp8], %[temp8], 16 \n\t" "sra %[temp8], %[temp8], 16 \n\t"
"sra %[temp17], %[temp17], 16 \n\t"
"sra %[temp4], %[temp4], 16 \n\t"
"sra %[temp12], %[temp12], 16 \n\t" "sra %[temp12], %[temp12], 16 \n\t"
"lh %[temp2], 4(%[in]) \n\t" "lh %[temp2], 4(%[in]) \n\t"
"lh %[temp6], 12(%[in]) \n\t" "lh %[temp6], 12(%[in]) \n\t"
@ -261,49 +259,43 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp12], %[temp0], %[temp17] \n\t" "addu %[temp12], %[temp0], %[temp17] \n\t"
"subu %[temp0], %[temp0], %[temp17] \n\t" "subu %[temp0], %[temp0], %[temp17] \n\t"
"mul %[temp9], %[temp5], %[kC2] \n\t" "mul %[temp9], %[temp5], %[kC2] \n\t"
"mul %[temp17], %[temp13], %[kC1] \n\t" MUL_SHIFT_C1(temp17, temp13)
"mul %[temp5], %[temp5], %[kC1] \n\t" MUL_SHIFT_C1_IO(temp5, temp19)
"mul %[temp13], %[temp13], %[kC2] \n\t" "mul %[temp13], %[temp13], %[kC2] \n\t"
"sra %[temp9], %[temp9], 16 \n\t" "sra %[temp9], %[temp9], 16 \n\t"
"sra %[temp17], %[temp17], 16 \n\t"
"subu %[temp17], %[temp9], %[temp17] \n\t" "subu %[temp17], %[temp9], %[temp17] \n\t"
"sra %[temp5], %[temp5], 16 \n\t"
"sra %[temp13], %[temp13], 16 \n\t" "sra %[temp13], %[temp13], 16 \n\t"
"addu %[temp5], %[temp5], %[temp13] \n\t" "addu %[temp5], %[temp5], %[temp13] \n\t"
"addu %[temp13], %[temp1], %[temp17] \n\t" "addu %[temp13], %[temp1], %[temp17] \n\t"
"subu %[temp1], %[temp1], %[temp17] \n\t" "subu %[temp1], %[temp1], %[temp17] \n\t"
"mul %[temp17], %[temp14], %[kC1] \n\t" MUL_SHIFT_C1(temp17, temp14)
"mul %[temp14], %[temp14], %[kC2] \n\t" "mul %[temp14], %[temp14], %[kC2] \n\t"
"addu %[temp9], %[temp16], %[temp5] \n\t" "addu %[temp9], %[temp16], %[temp5] \n\t"
"subu %[temp5], %[temp16], %[temp5] \n\t" "subu %[temp5], %[temp16], %[temp5] \n\t"
"addu %[temp16], %[temp2], %[temp10] \n\t" "addu %[temp16], %[temp2], %[temp10] \n\t"
"subu %[temp2], %[temp2], %[temp10] \n\t" "subu %[temp2], %[temp2], %[temp10] \n\t"
"mul %[temp10], %[temp6], %[kC2] \n\t" "mul %[temp10], %[temp6], %[kC2] \n\t"
"mul %[temp6], %[temp6], %[kC1] \n\t" MUL_SHIFT_C1_IO(temp6, temp19)
"sra %[temp17], %[temp17], 16 \n\t"
"sra %[temp14], %[temp14], 16 \n\t" "sra %[temp14], %[temp14], 16 \n\t"
"sra %[temp10], %[temp10], 16 \n\t" "sra %[temp10], %[temp10], 16 \n\t"
"sra %[temp6], %[temp6], 16 \n\t"
"subu %[temp17], %[temp10], %[temp17] \n\t" "subu %[temp17], %[temp10], %[temp17] \n\t"
"addu %[temp6], %[temp6], %[temp14] \n\t" "addu %[temp6], %[temp6], %[temp14] \n\t"
"addu %[temp10], %[temp16], %[temp6] \n\t" "addu %[temp10], %[temp16], %[temp6] \n\t"
"subu %[temp6], %[temp16], %[temp6] \n\t" "subu %[temp6], %[temp16], %[temp6] \n\t"
"addu %[temp14], %[temp2], %[temp17] \n\t" "addu %[temp14], %[temp2], %[temp17] \n\t"
"subu %[temp2], %[temp2], %[temp17] \n\t" "subu %[temp2], %[temp2], %[temp17] \n\t"
"mul %[temp17], %[temp15], %[kC1] \n\t" MUL_SHIFT_C1(temp17, temp15)
"mul %[temp15], %[temp15], %[kC2] \n\t" "mul %[temp15], %[temp15], %[kC2] \n\t"
"addu %[temp16], %[temp3], %[temp11] \n\t" "addu %[temp16], %[temp3], %[temp11] \n\t"
"subu %[temp3], %[temp3], %[temp11] \n\t" "subu %[temp3], %[temp3], %[temp11] \n\t"
"mul %[temp11], %[temp7], %[kC2] \n\t" "mul %[temp11], %[temp7], %[kC2] \n\t"
"mul %[temp7], %[temp7], %[kC1] \n\t" MUL_SHIFT_C1_IO(temp7, temp19)
"addiu %[temp8], %[temp8], 4 \n\t" "addiu %[temp8], %[temp8], 4 \n\t"
"addiu %[temp12], %[temp12], 4 \n\t" "addiu %[temp12], %[temp12], 4 \n\t"
"addiu %[temp0], %[temp0], 4 \n\t" "addiu %[temp0], %[temp0], 4 \n\t"
"addiu %[temp4], %[temp4], 4 \n\t" "addiu %[temp4], %[temp4], 4 \n\t"
"sra %[temp17], %[temp17], 16 \n\t"
"sra %[temp15], %[temp15], 16 \n\t" "sra %[temp15], %[temp15], 16 \n\t"
"sra %[temp11], %[temp11], 16 \n\t" "sra %[temp11], %[temp11], 16 \n\t"
"sra %[temp7], %[temp7], 16 \n\t"
"subu %[temp17], %[temp11], %[temp17] \n\t" "subu %[temp17], %[temp11], %[temp17] \n\t"
"addu %[temp7], %[temp7], %[temp15] \n\t" "addu %[temp7], %[temp7], %[temp15] \n\t"
"addu %[temp15], %[temp3], %[temp17] \n\t" "addu %[temp15], %[temp3], %[temp17] \n\t"
@ -313,48 +305,40 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp16], %[temp8], %[temp10] \n\t" "addu %[temp16], %[temp8], %[temp10] \n\t"
"subu %[temp8], %[temp8], %[temp10] \n\t" "subu %[temp8], %[temp8], %[temp10] \n\t"
"mul %[temp10], %[temp9], %[kC2] \n\t" "mul %[temp10], %[temp9], %[kC2] \n\t"
"mul %[temp17], %[temp11], %[kC1] \n\t" MUL_SHIFT_C1(temp17, temp11)
"mul %[temp9], %[temp9], %[kC1] \n\t" MUL_SHIFT_C1_IO(temp9, temp19)
"mul %[temp11], %[temp11], %[kC2] \n\t" "mul %[temp11], %[temp11], %[kC2] \n\t"
"sra %[temp10], %[temp10], 16 \n\t" "sra %[temp10], %[temp10], 16 \n\t"
"sra %[temp17], %[temp17], 16 \n\t"
"sra %[temp9], %[temp9], 16 \n\t"
"sra %[temp11], %[temp11], 16 \n\t" "sra %[temp11], %[temp11], 16 \n\t"
"subu %[temp17], %[temp10], %[temp17] \n\t" "subu %[temp17], %[temp10], %[temp17] \n\t"
"addu %[temp11], %[temp9], %[temp11] \n\t" "addu %[temp11], %[temp9], %[temp11] \n\t"
"addu %[temp10], %[temp12], %[temp14] \n\t" "addu %[temp10], %[temp12], %[temp14] \n\t"
"subu %[temp12], %[temp12], %[temp14] \n\t" "subu %[temp12], %[temp12], %[temp14] \n\t"
"mul %[temp14], %[temp13], %[kC2] \n\t" "mul %[temp14], %[temp13], %[kC2] \n\t"
"mul %[temp9], %[temp15], %[kC1] \n\t" MUL_SHIFT_C1(temp9, temp15)
"mul %[temp13], %[temp13], %[kC1] \n\t" MUL_SHIFT_C1_IO(temp13, temp19)
"mul %[temp15], %[temp15], %[kC2] \n\t" "mul %[temp15], %[temp15], %[kC2] \n\t"
"sra %[temp14], %[temp14], 16 \n\t" "sra %[temp14], %[temp14], 16 \n\t"
"sra %[temp9], %[temp9], 16 \n\t"
"sra %[temp13], %[temp13], 16 \n\t"
"sra %[temp15], %[temp15], 16 \n\t" "sra %[temp15], %[temp15], 16 \n\t"
"subu %[temp9], %[temp14], %[temp9] \n\t" "subu %[temp9], %[temp14], %[temp9] \n\t"
"addu %[temp15], %[temp13], %[temp15] \n\t" "addu %[temp15], %[temp13], %[temp15] \n\t"
"addu %[temp14], %[temp0], %[temp2] \n\t" "addu %[temp14], %[temp0], %[temp2] \n\t"
"subu %[temp0], %[temp0], %[temp2] \n\t" "subu %[temp0], %[temp0], %[temp2] \n\t"
"mul %[temp2], %[temp1], %[kC2] \n\t" "mul %[temp2], %[temp1], %[kC2] \n\t"
"mul %[temp13], %[temp3], %[kC1] \n\t" MUL_SHIFT_C1(temp13, temp3)
"mul %[temp1], %[temp1], %[kC1] \n\t" MUL_SHIFT_C1_IO(temp1, temp19)
"mul %[temp3], %[temp3], %[kC2] \n\t" "mul %[temp3], %[temp3], %[kC2] \n\t"
"sra %[temp2], %[temp2], 16 \n\t" "sra %[temp2], %[temp2], 16 \n\t"
"sra %[temp13], %[temp13], 16 \n\t"
"sra %[temp1], %[temp1], 16 \n\t"
"sra %[temp3], %[temp3], 16 \n\t" "sra %[temp3], %[temp3], 16 \n\t"
"subu %[temp13], %[temp2], %[temp13] \n\t" "subu %[temp13], %[temp2], %[temp13] \n\t"
"addu %[temp3], %[temp1], %[temp3] \n\t" "addu %[temp3], %[temp1], %[temp3] \n\t"
"addu %[temp2], %[temp4], %[temp6] \n\t" "addu %[temp2], %[temp4], %[temp6] \n\t"
"subu %[temp4], %[temp4], %[temp6] \n\t" "subu %[temp4], %[temp4], %[temp6] \n\t"
"mul %[temp6], %[temp5], %[kC2] \n\t" "mul %[temp6], %[temp5], %[kC2] \n\t"
"mul %[temp1], %[temp7], %[kC1] \n\t" MUL_SHIFT_C1(temp1, temp7)
"mul %[temp5], %[temp5], %[kC1] \n\t" MUL_SHIFT_C1_IO(temp5, temp19)
"mul %[temp7], %[temp7], %[kC2] \n\t" "mul %[temp7], %[temp7], %[kC2] \n\t"
"sra %[temp6], %[temp6], 16 \n\t" "sra %[temp6], %[temp6], 16 \n\t"
"sra %[temp1], %[temp1], 16 \n\t"
"sra %[temp5], %[temp5], 16 \n\t"
"sra %[temp7], %[temp7], 16 \n\t" "sra %[temp7], %[temp7], 16 \n\t"
"subu %[temp1], %[temp6], %[temp1] \n\t" "subu %[temp1], %[temp6], %[temp1] \n\t"
"addu %[temp7], %[temp5], %[temp7] \n\t" "addu %[temp7], %[temp5], %[temp7] \n\t"
@ -542,7 +526,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
[temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11), [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
[temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14), [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
[temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17), [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
[temp18]"=&r"(temp18) [temp18]"=&r"(temp18), [temp19]"=&r"(temp19)
: [in]"r"(p_in), [kC1]"r"(kC1), [kC2]"r"(kC2), [dst]"r"(dst) : [in]"r"(p_in), [kC1]"r"(kC1), [kC2]"r"(kC2), [dst]"r"(dst)
: "memory", "hi", "lo" : "memory", "hi", "lo"
); );

View File

@ -18,10 +18,8 @@
#include "src/dsp/mips_macro.h" #include "src/dsp/mips_macro.h"
static const int kC1 = 20091 + (1 << 16); static const int kC1 = WEBP_TRANSFORM_AC3_C1;
static const int kC2 = 35468; static const int kC2 = WEBP_TRANSFORM_AC3_C2;
#define MUL(a, b) (((a) * (b)) >> 16)
static void TransformDC(const int16_t* in, uint8_t* dst) { static void TransformDC(const int16_t* in, uint8_t* dst) {
int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10; int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10;
@ -49,10 +47,10 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
static void TransformAC3(const int16_t* in, uint8_t* dst) { static void TransformAC3(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4; const int a = in[0] + 4;
int c4 = MUL(in[4], kC2); int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
const int d4 = MUL(in[4], kC1); const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
const int c1 = MUL(in[1], kC2); const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
const int d1 = MUL(in[1], kC1); const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18; int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18;
@ -479,8 +477,6 @@ static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
} }
#undef MUL
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Simple In-loop filtering (Paragraph 15.2) // Simple In-loop filtering (Paragraph 15.2)

View File

@ -37,8 +37,6 @@
d1_m = d_tmp1_m + d_tmp2_m; \ d1_m = d_tmp1_m + d_tmp2_m; \
BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \ BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \
} }
#define MULT1(a) ((((a) * 20091) >> 16) + (a))
#define MULT2(a) (((a) * 35468) >> 16)
static void TransformOne(const int16_t* in, uint8_t* dst) { static void TransformOne(const int16_t* in, uint8_t* dst) {
v8i16 input0, input1; v8i16 input0, input1;
@ -124,10 +122,10 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
static void TransformAC3(const int16_t* in, uint8_t* dst) { static void TransformAC3(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4; const int a = in[0] + 4;
const int c4 = MULT2(in[4]); const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
const int d4 = MULT1(in[4]); const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
const int in2 = MULT2(in[1]); const int in2 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
const int in3 = MULT1(in[1]); const int in3 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
v4i32 tmp0 = { 0 }; v4i32 tmp0 = { 0 };
v4i32 out0 = __msa_fill_w(a + d4); v4i32 out0 = __msa_fill_w(a + d4);
v4i32 out1 = __msa_fill_w(a + c4); v4i32 out1 = __msa_fill_w(a + c4);

View File

@ -1000,8 +1000,9 @@ static void HFilter8i_NEON(uint8_t* u, uint8_t* v, int stride,
// libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the // libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the
// same issue with kC1 and vqdmulh that we work around by down shifting kC2 // same issue with kC1 and vqdmulh that we work around by down shifting kC2
static const int16_t kC1 = 20091; static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1;
static const int16_t kC2 = 17734; // half of kC2, actually. See comment above. static const int16_t kC2 =
WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above.
#if defined(WEBP_USE_INTRINSICS) #if defined(WEBP_USE_INTRINSICS)
static WEBP_INLINE void Transpose8x2_NEON(const int16x8_t in0, static WEBP_INLINE void Transpose8x2_NEON(const int16x8_t in0,
@ -1255,15 +1256,12 @@ static void TransformWHT_NEON(const int16_t* in, int16_t* out) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#define MUL(a, b) (((a) * (b)) >> 16)
static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) { static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) {
static const int kC1_full = 20091 + (1 << 16);
static const int kC2_full = 35468;
const int16x4_t A = vld1_dup_s16(in); const int16x4_t A = vld1_dup_s16(in);
const int16x4_t c4 = vdup_n_s16(MUL(in[4], kC2_full)); const int16x4_t c4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL2(in[4]));
const int16x4_t d4 = vdup_n_s16(MUL(in[4], kC1_full)); const int16x4_t d4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL1(in[4]));
const int c1 = MUL(in[1], kC2_full); const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
const int d1 = MUL(in[1], kC1_full); const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
const uint64_t cd = (uint64_t)( d1 & 0xffff) << 0 | const uint64_t cd = (uint64_t)( d1 & 0xffff) << 0 |
(uint64_t)( c1 & 0xffff) << 16 | (uint64_t)( c1 & 0xffff) << 16 |
(uint64_t)(-c1 & 0xffff) << 32 | (uint64_t)(-c1 & 0xffff) << 32 |
@ -1274,7 +1272,6 @@ static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) {
const int16x8_t m2_m3 = vcombine_s16(vqsub_s16(B, c4), vqsub_s16(B, d4)); const int16x8_t m2_m3 = vcombine_s16(vqsub_s16(B, c4), vqsub_s16(B, d4));
Add4x4_NEON(m0_m1, m2_m3, dst); Add4x4_NEON(m0_m1, m2_m3, dst);
} }
#undef MUL
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// 4x4 // 4x4

View File

@ -196,15 +196,13 @@ static void Transform_SSE2(const int16_t* in, uint8_t* dst, int do_two) {
} }
#if (USE_TRANSFORM_AC3 == 1) #if (USE_TRANSFORM_AC3 == 1)
#define MUL(a, b) (((a) * (b)) >> 16)
static void TransformAC3(const int16_t* in, uint8_t* dst) { static void TransformAC3(const int16_t* in, uint8_t* dst) {
static const int kC1 = 20091 + (1 << 16);
static const int kC2 = 35468;
const __m128i A = _mm_set1_epi16(in[0] + 4); const __m128i A = _mm_set1_epi16(in[0] + 4);
const __m128i c4 = _mm_set1_epi16(MUL(in[4], kC2)); const __m128i c4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL2(in[4]));
const __m128i d4 = _mm_set1_epi16(MUL(in[4], kC1)); const __m128i d4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL1(in[4]));
const int c1 = MUL(in[1], kC2); const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
const int d1 = MUL(in[1], kC1); const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
const __m128i CD = _mm_set_epi16(0, 0, 0, 0, -d1, -c1, c1, d1); const __m128i CD = _mm_set_epi16(0, 0, 0, 0, -d1, -c1, c1, d1);
const __m128i B = _mm_adds_epi16(A, CD); const __m128i B = _mm_adds_epi16(A, CD);
const __m128i m0 = _mm_adds_epi16(B, d4); const __m128i m0 = _mm_adds_epi16(B, d4);
@ -238,7 +236,7 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2)); WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2));
WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3)); WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3));
} }
#undef MUL
#endif // USE_TRANSFORM_AC3 #endif // USE_TRANSFORM_AC3
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -259,15 +257,15 @@ static WEBP_INLINE void SignedShift8b_SSE2(__m128i* const x) {
*x = _mm_packs_epi16(lo_1, hi_1); *x = _mm_packs_epi16(lo_1, hi_1);
} }
#define FLIP_SIGN_BIT2(a, b) { \ #define FLIP_SIGN_BIT2(a, b) do { \
(a) = _mm_xor_si128(a, sign_bit); \ (a) = _mm_xor_si128(a, sign_bit); \
(b) = _mm_xor_si128(b, sign_bit); \ (b) = _mm_xor_si128(b, sign_bit); \
} } while (0)
#define FLIP_SIGN_BIT4(a, b, c, d) { \ #define FLIP_SIGN_BIT4(a, b, c, d) do { \
FLIP_SIGN_BIT2(a, b); \ FLIP_SIGN_BIT2(a, b); \
FLIP_SIGN_BIT2(c, d); \ FLIP_SIGN_BIT2(c, d); \
} } while (0)
// input/output is uint8_t // input/output is uint8_t
static WEBP_INLINE void GetNotHEV_SSE2(const __m128i* const p1, static WEBP_INLINE void GetNotHEV_SSE2(const __m128i* const p1,
@ -645,12 +643,12 @@ static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
(m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \ (m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \
} while (0) } while (0)
#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \ #define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) do { \
(e1) = _mm_loadu_si128((__m128i*)&(p)[0 * (stride)]); \ (e1) = _mm_loadu_si128((__m128i*)&(p)[0 * (stride)]); \
(e2) = _mm_loadu_si128((__m128i*)&(p)[1 * (stride)]); \ (e2) = _mm_loadu_si128((__m128i*)&(p)[1 * (stride)]); \
(e3) = _mm_loadu_si128((__m128i*)&(p)[2 * (stride)]); \ (e3) = _mm_loadu_si128((__m128i*)&(p)[2 * (stride)]); \
(e4) = _mm_loadu_si128((__m128i*)&(p)[3 * (stride)]); \ (e4) = _mm_loadu_si128((__m128i*)&(p)[3 * (stride)]); \
} } while (0)
#define LOADUV_H_EDGE(p, u, v, stride) do { \ #define LOADUV_H_EDGE(p, u, v, stride) do { \
const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \ const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
@ -658,18 +656,18 @@ static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
(p) = _mm_unpacklo_epi64(U, V); \ (p) = _mm_unpacklo_epi64(U, V); \
} while (0) } while (0)
#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \ #define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) do { \
LOADUV_H_EDGE(e1, u, v, 0 * (stride)); \ LOADUV_H_EDGE(e1, u, v, 0 * (stride)); \
LOADUV_H_EDGE(e2, u, v, 1 * (stride)); \ LOADUV_H_EDGE(e2, u, v, 1 * (stride)); \
LOADUV_H_EDGE(e3, u, v, 2 * (stride)); \ LOADUV_H_EDGE(e3, u, v, 2 * (stride)); \
LOADUV_H_EDGE(e4, u, v, 3 * (stride)); \ LOADUV_H_EDGE(e4, u, v, 3 * (stride)); \
} } while (0)
#define STOREUV(p, u, v, stride) { \ #define STOREUV(p, u, v, stride) do { \
_mm_storel_epi64((__m128i*)&(u)[(stride)], p); \ _mm_storel_epi64((__m128i*)&(u)[(stride)], p); \
(p) = _mm_srli_si128(p, 8); \ (p) = _mm_srli_si128(p, 8); \
_mm_storel_epi64((__m128i*)&(v)[(stride)], p); \ _mm_storel_epi64((__m128i*)&(v)[(stride)], p); \
} } while (0)
static WEBP_INLINE void ComplexMask_SSE2(const __m128i* const p1, static WEBP_INLINE void ComplexMask_SSE2(const __m128i* const p1,
const __m128i* const p0, const __m128i* const p0,

View File

@ -203,6 +203,11 @@ extern VP8DecIdct VP8TransformDC;
extern VP8DecIdct VP8TransformDCUV; extern VP8DecIdct VP8TransformDCUV;
extern VP8WHT VP8TransformWHT; extern VP8WHT VP8TransformWHT;
#define WEBP_TRANSFORM_AC3_C1 20091
#define WEBP_TRANSFORM_AC3_C2 35468
#define WEBP_TRANSFORM_AC3_MUL1(a) ((((a) * WEBP_TRANSFORM_AC3_C1) >> 16) + (a))
#define WEBP_TRANSFORM_AC3_MUL2(a) (((a) * WEBP_TRANSFORM_AC3_C2) >> 16)
// *dst is the destination block, with stride BPS. Boundary samples are // *dst is the destination block, with stride BPS. Boundary samples are
// assumed accessible when needed. // assumed accessible when needed.
typedef void (*VP8PredFunc)(uint8_t* dst); typedef void (*VP8PredFunc)(uint8_t* dst);

View File

@ -109,10 +109,6 @@ static WEBP_TSAN_IGNORE_FUNCTION void InitTables(void) {
#define STORE(x, y, v) \ #define STORE(x, y, v) \
dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3)) dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3))
static const int kC1 = 20091 + (1 << 16);
static const int kC2 = 35468;
#define MUL(a, b) (((a) * (b)) >> 16)
static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
uint8_t* dst) { uint8_t* dst) {
int C[4 * 4], *tmp; int C[4 * 4], *tmp;
@ -121,8 +117,10 @@ static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
for (i = 0; i < 4; ++i) { // vertical pass for (i = 0; i < 4; ++i) { // vertical pass
const int a = in[0] + in[8]; const int a = in[0] + in[8];
const int b = in[0] - in[8]; const int b = in[0] - in[8];
const int c = MUL(in[4], kC2) - MUL(in[12], kC1); const int c =
const int d = MUL(in[4], kC1) + MUL(in[12], kC2); WEBP_TRANSFORM_AC3_MUL2(in[4]) - WEBP_TRANSFORM_AC3_MUL1(in[12]);
const int d =
WEBP_TRANSFORM_AC3_MUL1(in[4]) + WEBP_TRANSFORM_AC3_MUL2(in[12]);
tmp[0] = a + d; tmp[0] = a + d;
tmp[1] = b + c; tmp[1] = b + c;
tmp[2] = b - c; tmp[2] = b - c;
@ -134,10 +132,12 @@ static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
tmp = C; tmp = C;
for (i = 0; i < 4; ++i) { // horizontal pass for (i = 0; i < 4; ++i) { // horizontal pass
const int dc = tmp[0] + 4; const int dc = tmp[0] + 4;
const int a = dc + tmp[8]; const int a = dc + tmp[8];
const int b = dc - tmp[8]; const int b = dc - tmp[8];
const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1); const int c =
const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2); WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]);
const int d =
WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]);
STORE(0, i, a + d); STORE(0, i, a + d);
STORE(1, i, b + c); STORE(1, i, b + c);
STORE(2, i, b - c); STORE(2, i, b - c);
@ -222,7 +222,6 @@ static void FTransformWHT_C(const int16_t* in, int16_t* out) {
} }
#endif // !WEBP_NEON_OMIT_C_CODE #endif // !WEBP_NEON_OMIT_C_CODE
#undef MUL
#undef STORE #undef STORE
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -21,8 +21,8 @@
#include "src/enc/vp8i_enc.h" #include "src/enc/vp8i_enc.h"
#include "src/enc/cost_enc.h" #include "src/enc/cost_enc.h"
static const int kC1 = 20091 + (1 << 16); static const int kC1 = WEBP_TRANSFORM_AC3_C1;
static const int kC2 = 35468; static const int kC2 = WEBP_TRANSFORM_AC3_C2;
// macro for one vertical pass in ITransformOne // macro for one vertical pass in ITransformOne
// MUL macro inlined // MUL macro inlined
@ -30,7 +30,7 @@ static const int kC2 = 35468;
// A..D - offsets in bytes to load from in buffer // A..D - offsets in bytes to load from in buffer
// TEMP0..TEMP3 - registers for corresponding tmp elements // TEMP0..TEMP3 - registers for corresponding tmp elements
// TEMP4..TEMP5 - temporary registers // TEMP4..TEMP5 - temporary registers
#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \ #define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \
"lh %[temp16], " #A "(%[temp20]) \n\t" \ "lh %[temp16], " #A "(%[temp20]) \n\t" \
"lh %[temp18], " #B "(%[temp20]) \n\t" \ "lh %[temp18], " #B "(%[temp20]) \n\t" \
"lh %[temp17], " #C "(%[temp20]) \n\t" \ "lh %[temp17], " #C "(%[temp20]) \n\t" \
@ -38,12 +38,10 @@ static const int kC2 = 35468;
"addu %[" #TEMP4 "], %[temp16], %[temp18] \n\t" \ "addu %[" #TEMP4 "], %[temp16], %[temp18] \n\t" \
"subu %[temp16], %[temp16], %[temp18] \n\t" \ "subu %[temp16], %[temp16], %[temp18] \n\t" \
"mul %[" #TEMP0 "], %[temp17], %[kC2] \n\t" \ "mul %[" #TEMP0 "], %[temp17], %[kC2] \n\t" \
"mul %[temp18], %[temp19], %[kC1] \n\t" \ MUL_SHIFT_C1_IO(temp17, temp18) \
"mul %[temp17], %[temp17], %[kC1] \n\t" \ MUL_SHIFT_C1(temp18, temp19) \
"mul %[temp19], %[temp19], %[kC2] \n\t" \ "mul %[temp19], %[temp19], %[kC2] \n\t" \
"sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\n" \ "sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\n" \
"sra %[temp18], %[temp18], 16 \n\n" \
"sra %[temp17], %[temp17], 16 \n\n" \
"sra %[temp19], %[temp19], 16 \n\n" \ "sra %[temp19], %[temp19], 16 \n\n" \
"subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp18] \n\t" \ "subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp18] \n\t" \
"addu %[" #TEMP3 "], %[temp17], %[temp19] \n\t" \ "addu %[" #TEMP3 "], %[temp17], %[temp19] \n\t" \
@ -58,17 +56,15 @@ static const int kC2 = 35468;
// temp0..temp15 holds tmp[0]..tmp[15] // temp0..temp15 holds tmp[0]..tmp[15]
// A - offset in bytes to load from ref and store to dst buffer // A - offset in bytes to load from ref and store to dst buffer
// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements // TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements
#define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \ #define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \
"addiu %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \ "addiu %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \
"addu %[temp16], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ "addu %[temp16], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"subu %[temp17], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ "subu %[temp17], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"mul %[" #TEMP0 "], %[" #TEMP4 "], %[kC2] \n\t" \ "mul %[" #TEMP0 "], %[" #TEMP4 "], %[kC2] \n\t" \
"mul %[" #TEMP8 "], %[" #TEMP12 "], %[kC1] \n\t" \ MUL_SHIFT_C1_IO(TEMP4, TEMP8) \
"mul %[" #TEMP4 "], %[" #TEMP4 "], %[kC1] \n\t" \ MUL_SHIFT_C1(TEMP8, TEMP12) \
"mul %[" #TEMP12 "], %[" #TEMP12 "], %[kC2] \n\t" \ "mul %[" #TEMP12 "], %[" #TEMP12 "], %[kC2] \n\t" \
"sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \ "sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \
"sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \
"sra %[" #TEMP4 "], %[" #TEMP4 "], 16 \n\t" \
"sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \ "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \
"subu %[temp18], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ "subu %[temp18], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"addu %[temp19], %[" #TEMP4 "], %[" #TEMP12 "] \n\t" \ "addu %[temp19], %[" #TEMP4 "], %[" #TEMP12 "] \n\t" \

View File

@ -20,8 +20,8 @@
#include "src/enc/cost_enc.h" #include "src/enc/cost_enc.h"
#include "src/enc/vp8i_enc.h" #include "src/enc/vp8i_enc.h"
static const int kC1 = 20091 + (1 << 16); static const int kC1 = WEBP_TRANSFORM_AC3_C1;
static const int kC2 = 35468; static const int kC2 = WEBP_TRANSFORM_AC3_C2;
// O - output // O - output
// I - input (macro doesn't change it) // I - input (macro doesn't change it)

View File

@ -27,8 +27,9 @@
// This code is pretty much the same as TransformOne in the dec_neon.c, except // This code is pretty much the same as TransformOne in the dec_neon.c, except
// for subtraction to *ref. See the comments there for algorithmic explanations. // for subtraction to *ref. See the comments there for algorithmic explanations.
static const int16_t kC1 = 20091; static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1;
static const int16_t kC2 = 17734; // half of kC2, actually. See comment above. static const int16_t kC2 =
WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above.
// This code works but is *slower* than the inlined-asm version below // This code works but is *slower* than the inlined-asm version below
// (with gcc-4.6). So we disable it for now. Later, it'll be conditional to // (with gcc-4.6). So we disable it for now. Later, it'll be conditional to

View File

@ -19,14 +19,16 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpful macro. // Helpful macro.
# define SANITY_CHECK(in, out) \ #define DCHECK(in, out) \
assert((in) != NULL); \ do { \
assert((out) != NULL); \ assert((in) != NULL); \
assert(width > 0); \ assert((out) != NULL); \
assert(height > 0); \ assert(width > 0); \
assert(stride >= width); \ assert(height > 0); \
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ assert(stride >= width); \
(void)height; // Silence unused warning. assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
(void)height; /* Silence unused warning. */ \
} while (0)
#if !WEBP_NEON_OMIT_C_CODE #if !WEBP_NEON_OMIT_C_CODE
static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred, static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred,
@ -49,7 +51,7 @@ static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in,
const uint8_t* preds; const uint8_t* preds;
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
preds = inverse ? out : in; preds = inverse ? out : in;
@ -86,7 +88,7 @@ static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* in,
const uint8_t* preds; const uint8_t* preds;
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
preds = inverse ? out : in; preds = inverse ? out : in;
@ -131,7 +133,7 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
const uint8_t* preds; const uint8_t* preds;
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
preds = inverse ? out : in; preds = inverse ? out : in;
@ -165,7 +167,7 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
} }
#endif // !WEBP_NEON_OMIT_C_CODE #endif // !WEBP_NEON_OMIT_C_CODE
#undef SANITY_CHECK #undef DCHECK
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -24,14 +24,16 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpful macro. // Helpful macro.
# define SANITY_CHECK(in, out) \ #define DCHECK(in, out) \
assert(in != NULL); \ do { \
assert(out != NULL); \ assert(in != NULL); \
assert(width > 0); \ assert(out != NULL); \
assert(height > 0); \ assert(width > 0); \
assert(stride >= width); \ assert(height > 0); \
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ assert(stride >= width); \
(void)height; // Silence unused warning. assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
(void)height; /* Silence unused warning. */ \
} while (0)
#define DO_PREDICT_LINE(SRC, DST, LENGTH, INVERSE) do { \ #define DO_PREDICT_LINE(SRC, DST, LENGTH, INVERSE) do { \
const uint8_t* psrc = (uint8_t*)(SRC); \ const uint8_t* psrc = (uint8_t*)(SRC); \
@ -200,7 +202,7 @@ static WEBP_INLINE void DoHorizontalFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds; const uint8_t* preds;
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
preds = in; preds = in;
@ -248,7 +250,7 @@ static WEBP_INLINE void DoVerticalFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds; const uint8_t* preds;
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
preds = in; preds = in;
@ -316,7 +318,7 @@ static void DoGradientFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds; const uint8_t* preds;
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
preds = in; preds = in;
@ -378,7 +380,7 @@ static void GradientUnfilter_MIPSdspR2(const uint8_t* prev, const uint8_t* in,
#undef DO_PREDICT_LINE_VERTICAL #undef DO_PREDICT_LINE_VERTICAL
#undef PREDICT_LINE_ONE_PASS #undef PREDICT_LINE_ONE_PASS
#undef DO_PREDICT_LINE #undef DO_PREDICT_LINE
#undef SANITY_CHECK #undef DCHECK
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Entry point // Entry point

View File

@ -56,12 +56,14 @@ static WEBP_INLINE void PredictLineInverse0(const uint8_t* src,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpful macro. // Helpful macro.
#define SANITY_CHECK(in, out) \ #define DCHECK(in, out) \
assert(in != NULL); \ do { \
assert(out != NULL); \ assert(in != NULL); \
assert(width > 0); \ assert(out != NULL); \
assert(height > 0); \ assert(width > 0); \
assert(stride >= width); assert(height > 0); \
assert(stride >= width); \
} while (0)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Horrizontal filter // Horrizontal filter
@ -72,7 +74,7 @@ static void HorizontalFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* in = data; const uint8_t* in = data;
uint8_t* out = filtered_data; uint8_t* out = filtered_data;
int row = 1; int row = 1;
SANITY_CHECK(in, out); DCHECK(in, out);
// Leftmost pixel is the same as input for topmost scanline. // Leftmost pixel is the same as input for topmost scanline.
out[0] = in[0]; out[0] = in[0];
@ -135,7 +137,7 @@ static void GradientFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* preds = data; const uint8_t* preds = data;
uint8_t* out = filtered_data; uint8_t* out = filtered_data;
int row = 1; int row = 1;
SANITY_CHECK(in, out); DCHECK(in, out);
// left prediction for top scan-line // left prediction for top scan-line
out[0] = in[0]; out[0] = in[0];
@ -163,7 +165,7 @@ static void VerticalFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* preds = data; const uint8_t* preds = data;
uint8_t* out = filtered_data; uint8_t* out = filtered_data;
int row = 1; int row = 1;
SANITY_CHECK(in, out); DCHECK(in, out);
// Very first top-left pixel is copied. // Very first top-left pixel is copied.
out[0] = in[0]; out[0] = in[0];
@ -182,7 +184,7 @@ static void VerticalFilter_MSA(const uint8_t* data, int width, int height,
} }
} }
#undef SANITY_CHECK #undef DCHECK
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Entry point // Entry point

View File

@ -21,14 +21,16 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpful macros. // Helpful macros.
# define SANITY_CHECK(in, out) \ #define DCHECK(in, out) \
assert(in != NULL); \ do { \
assert(out != NULL); \ assert(in != NULL); \
assert(width > 0); \ assert(out != NULL); \
assert(height > 0); \ assert(width > 0); \
assert(stride >= width); \ assert(height > 0); \
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ assert(stride >= width); \
(void)height; // Silence unused warning. assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
(void)height; /* Silence unused warning. */ \
} while (0)
// load eight u8 and widen to s16 // load eight u8 and widen to s16
#define U8_TO_S16(A) vreinterpretq_s16_u16(vmovl_u8(A)) #define U8_TO_S16(A) vreinterpretq_s16_u16(vmovl_u8(A))
@ -71,7 +73,7 @@ static WEBP_INLINE void DoHorizontalFilter_NEON(const uint8_t* in,
uint8_t* out) { uint8_t* out) {
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
@ -110,7 +112,7 @@ static WEBP_INLINE void DoVerticalFilter_NEON(const uint8_t* in,
uint8_t* out) { uint8_t* out) {
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
@ -172,7 +174,7 @@ static WEBP_INLINE void DoGradientFilter_NEON(const uint8_t* in,
uint8_t* out) { uint8_t* out) {
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
@ -201,7 +203,7 @@ static void GradientFilter_NEON(const uint8_t* data, int width, int height,
filtered_data); filtered_data);
} }
#undef SANITY_CHECK #undef DCHECK
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Inverse transforms // Inverse transforms

View File

@ -23,14 +23,16 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpful macro. // Helpful macro.
# define SANITY_CHECK(in, out) \ #define DCHECK(in, out) \
assert((in) != NULL); \ do { \
assert((out) != NULL); \ assert((in) != NULL); \
assert(width > 0); \ assert((out) != NULL); \
assert(height > 0); \ assert(width > 0); \
assert(stride >= width); \ assert(height > 0); \
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ assert(stride >= width); \
(void)height; // Silence unused warning. assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
(void)height; /* Silence unused warning. */ \
} while (0)
static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred, static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred,
uint8_t* dst, int length) { uint8_t* dst, int length) {
@ -78,7 +80,7 @@ static WEBP_INLINE void DoHorizontalFilter_SSE2(const uint8_t* in,
uint8_t* out) { uint8_t* out) {
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
@ -111,7 +113,7 @@ static WEBP_INLINE void DoVerticalFilter_SSE2(const uint8_t* in,
uint8_t* out) { uint8_t* out) {
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
@ -174,7 +176,7 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
uint8_t* out) { uint8_t* out) {
const size_t start_offset = row * stride; const size_t start_offset = row * stride;
const int last_row = row + num_rows; const int last_row = row + num_rows;
SANITY_CHECK(in, out); DCHECK(in, out);
in += start_offset; in += start_offset;
out += start_offset; out += start_offset;
@ -197,7 +199,7 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
} }
} }
#undef SANITY_CHECK #undef DCHECK
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -146,9 +146,9 @@ static void ConvertBGRAToRGB_NEON(const uint32_t* src,
#define LOAD_U32P_AS_U8(IN) vreinterpret_u8_u32(vld1_u32((IN))) #define LOAD_U32P_AS_U8(IN) vreinterpret_u8_u32(vld1_u32((IN)))
#define LOADQ_U32_AS_U8(IN) vreinterpretq_u8_u32(vdupq_n_u32((IN))) #define LOADQ_U32_AS_U8(IN) vreinterpretq_u8_u32(vdupq_n_u32((IN)))
#define LOADQ_U32P_AS_U8(IN) vreinterpretq_u8_u32(vld1q_u32((IN))) #define LOADQ_U32P_AS_U8(IN) vreinterpretq_u8_u32(vld1q_u32((IN)))
#define GET_U8_AS_U32(IN) vget_lane_u32(vreinterpret_u32_u8((IN)), 0); #define GET_U8_AS_U32(IN) vget_lane_u32(vreinterpret_u32_u8((IN)), 0)
#define GETQ_U8_AS_U32(IN) vgetq_lane_u32(vreinterpretq_u32_u8((IN)), 0); #define GETQ_U8_AS_U32(IN) vgetq_lane_u32(vreinterpretq_u32_u8((IN)), 0)
#define STOREQ_U8_AS_U32P(OUT, IN) vst1q_u32((OUT), vreinterpretq_u32_u8((IN))); #define STOREQ_U8_AS_U32P(OUT, IN) vst1q_u32((OUT), vreinterpretq_u32_u8((IN)))
#define ROTATE32_LEFT(L) vextq_u8((L), (L), 12) // D|C|B|A -> C|B|A|D #define ROTATE32_LEFT(L) vextq_u8((L), (L), 12) // D|C|B|A -> C|B|A|D
static WEBP_INLINE uint8x8_t Average2_u8_NEON(uint32_t a0, uint32_t a1) { static WEBP_INLINE uint8x8_t Average2_u8_NEON(uint32_t a0, uint32_t a1) {

View File

@ -45,28 +45,38 @@
"ulw %[" #O2 "], " #I3 "+" XSTR(I9) "*" #I7 "(%[" #I0 "]) \n\t" \ "ulw %[" #O2 "], " #I3 "+" XSTR(I9) "*" #I7 "(%[" #I0 "]) \n\t" \
"ulw %[" #O3 "], " #I4 "+" XSTR(I9) "*" #I8 "(%[" #I0 "]) \n\t" "ulw %[" #O3 "], " #I4 "+" XSTR(I9) "*" #I8 "(%[" #I0 "]) \n\t"
// O - output
// I - input (macro doesn't change it so it should be different from I)
#define MUL_SHIFT_C1(O, I) \
"mul %[" #O "], %[" #I "], %[kC1] \n\t" \
"sra %[" #O "], %[" #O "], 16 \n\t" \
"addu %[" #O "], %[" #O "], %[" #I "] \n\t"
#define MUL_SHIFT_C2(O, I) \
"mul %[" #O "], %[" #I "], %[kC2] \n\t" \
"sra %[" #O "], %[" #O "], 16 \n\t"
// Same as #define MUL_SHIFT_C1 but I and O are the same. It stores the
// intermediary result in TMP.
#define MUL_SHIFT_C1_IO(IO, TMP) \
"mul %[" #TMP "], %[" #IO "], %[kC1] \n\t" \
"sra %[" #TMP "], %[" #TMP "], 16 \n\t" \
"addu %[" #IO "], %[" #TMP "], %[" #IO "] \n\t"
// O - output // O - output
// IO - input/output // IO - input/output
// I - input (macro doesn't change it) // I - input (macro doesn't change it)
#define MUL_SHIFT_SUM(O0, O1, O2, O3, O4, O5, O6, O7, \ #define MUL_SHIFT_SUM(O0, O1, O2, O3, O4, O5, O6, O7, \
IO0, IO1, IO2, IO3, \ IO0, IO1, IO2, IO3, \
I0, I1, I2, I3, I4, I5, I6, I7) \ I0, I1, I2, I3, I4, I5, I6, I7) \
"mul %[" #O0 "], %[" #I0 "], %[kC2] \n\t" \ MUL_SHIFT_C2(O0, I0) \
"mul %[" #O1 "], %[" #I0 "], %[kC1] \n\t" \ MUL_SHIFT_C1(O1, I0) \
"mul %[" #O2 "], %[" #I1 "], %[kC2] \n\t" \ MUL_SHIFT_C2(O2, I1) \
"mul %[" #O3 "], %[" #I1 "], %[kC1] \n\t" \ MUL_SHIFT_C1(O3, I1) \
"mul %[" #O4 "], %[" #I2 "], %[kC2] \n\t" \ MUL_SHIFT_C2(O4, I2) \
"mul %[" #O5 "], %[" #I2 "], %[kC1] \n\t" \ MUL_SHIFT_C1(O5, I2) \
"mul %[" #O6 "], %[" #I3 "], %[kC2] \n\t" \ MUL_SHIFT_C2(O6, I3) \
"mul %[" #O7 "], %[" #I3 "], %[kC1] \n\t" \ MUL_SHIFT_C1(O7, I3) \
"sra %[" #O0 "], %[" #O0 "], 16 \n\t" \
"sra %[" #O1 "], %[" #O1 "], 16 \n\t" \
"sra %[" #O2 "], %[" #O2 "], 16 \n\t" \
"sra %[" #O3 "], %[" #O3 "], 16 \n\t" \
"sra %[" #O4 "], %[" #O4 "], 16 \n\t" \
"sra %[" #O5 "], %[" #O5 "], 16 \n\t" \
"sra %[" #O6 "], %[" #O6 "], 16 \n\t" \
"sra %[" #O7 "], %[" #O7 "], 16 \n\t" \
"addu %[" #IO0 "], %[" #IO0 "], %[" #I4 "] \n\t" \ "addu %[" #IO0 "], %[" #IO0 "], %[" #I4 "] \n\t" \
"addu %[" #IO1 "], %[" #IO1 "], %[" #I5 "] \n\t" \ "addu %[" #IO1 "], %[" #IO1 "], %[" #I5 "] \n\t" \
"subu %[" #IO2 "], %[" #IO2 "], %[" #I6 "] \n\t" \ "subu %[" #IO2 "], %[" #IO2 "], %[" #I6 "] \n\t" \

View File

@ -32,7 +32,7 @@
#define STORE_32x8(SRC0, SRC1, DST) do { \ #define STORE_32x8(SRC0, SRC1, DST) do { \
vst1q_u32((DST) + 0, SRC0); \ vst1q_u32((DST) + 0, SRC0); \
vst1q_u32((DST) + 4, SRC1); \ vst1q_u32((DST) + 4, SRC1); \
} while (0); } while (0)
#if (WEBP_RESCALER_RFIX == 32) #if (WEBP_RESCALER_RFIX == 32)
#define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1)) #define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1))

View File

@ -58,7 +58,7 @@
} while (0) } while (0)
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels. // Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
#define UPSAMPLE_32PIXELS(r1, r2, out) { \ #define UPSAMPLE_32PIXELS(r1, r2, out) do { \
const __m128i one = _mm_set1_epi8(1); \ const __m128i one = _mm_set1_epi8(1); \
const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \ const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \ const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
@ -85,7 +85,7 @@
/* pack the alternate pixels */ \ /* pack the alternate pixels */ \
PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \ PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \ PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
} } while (0)
// Turn the macro into a function for reducing code-size when non-critical // Turn the macro into a function for reducing code-size when non-critical
static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[], static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[],
@ -229,11 +229,11 @@ static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
} \ } \
} }
YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4); YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4)
YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4); YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4)
#if !defined(WEBP_REDUCE_CSP) #if !defined(WEBP_REDUCE_CSP)
YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3); YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3)
YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3); YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3)
YUV444_FUNC(Yuv444ToArgb_SSE2, VP8YuvToArgb32_SSE2, WebPYuv444ToArgb_C, 4) YUV444_FUNC(Yuv444ToArgb_SSE2, VP8YuvToArgb32_SSE2, WebPYuv444ToArgb_C, 4)
YUV444_FUNC(Yuv444ToRgba4444_SSE2, VP8YuvToRgba444432_SSE2, \ YUV444_FUNC(Yuv444ToRgba4444_SSE2, VP8YuvToRgba444432_SSE2, \
WebPYuv444ToRgba4444_C, 2) WebPYuv444ToRgba4444_C, 2)

View File

@ -60,7 +60,7 @@
} while (0) } while (0)
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels. // Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
#define UPSAMPLE_32PIXELS(r1, r2, out) { \ #define UPSAMPLE_32PIXELS(r1, r2, out) do { \
const __m128i one = _mm_set1_epi8(1); \ const __m128i one = _mm_set1_epi8(1); \
const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \ const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \ const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
@ -87,7 +87,7 @@
/* pack the alternate pixels */ \ /* pack the alternate pixels */ \
PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \ PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \ PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
} } while (0)
// Turn the macro into a function for reducing code-size when non-critical // Turn the macro into a function for reducing code-size when non-critical
static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[], static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[],
@ -217,8 +217,8 @@ static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
} }
#if !defined(WEBP_REDUCE_CSP) #if !defined(WEBP_REDUCE_CSP)
YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3); YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3)
YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3); YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3)
#endif // WEBP_REDUCE_CSP #endif // WEBP_REDUCE_CSP
WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE41(void) { WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE41(void) {

View File

@ -20,6 +20,7 @@
#include "src/utils/filters_utils.h" #include "src/utils/filters_utils.h"
#include "src/utils/quant_levels_utils.h" #include "src/utils/quant_levels_utils.h"
#include "src/utils/utils.h" #include "src/utils/utils.h"
#include "src/webp/encode.h"
#include "src/webp/format_constants.h" #include "src/webp/format_constants.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -66,7 +67,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
WebPDispatchAlphaToGreen(data, width, picture.width, picture.height, WebPDispatchAlphaToGreen(data, width, picture.width, picture.height,
picture.argb, picture.argb_stride); picture.argb, picture.argb_stride);
WebPConfigInit(&config); if (!WebPConfigInit(&config)) return 0;
config.lossless = 1; config.lossless = 1;
// Enable exact, or it would alter RGB values of transparent alpha, which is // Enable exact, or it would alter RGB values of transparent alpha, which is
// normally OK but not here since we are not encoding the input image but an // normally OK but not here since we are not encoding the input image but an
@ -83,11 +84,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
(use_quality_100 && effort_level == 6) ? 100 : 8.f * effort_level; (use_quality_100 && effort_level == 6) ? 100 : 8.f * effort_level;
assert(config.quality >= 0 && config.quality <= 100.f); assert(config.quality >= 0 && config.quality <= 100.f);
// TODO(urvang): Temporary fix to avoid generating images that trigger ok = VP8LEncodeStream(&config, &picture, bw);
// a decoder bug related to alpha with color cache.
// See: https://code.google.com/p/webp/issues/detail?id=239
// Need to re-enable this later.
ok = VP8LEncodeStream(&config, &picture, bw, /*use_cache=*/0);
WebPPictureFree(&picture); WebPPictureFree(&picture);
ok = ok && !bw->error_; ok = ok && !bw->error_;
if (!ok) { if (!ok) {

View File

@ -31,8 +31,8 @@ extern "C" {
// version numbers // version numbers
#define ENC_MAJ_VERSION 1 #define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 3 #define ENC_MIN_VERSION 4
#define ENC_REV_VERSION 1 #define ENC_REV_VERSION 0
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level enum { 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

View File

@ -820,10 +820,10 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
static int EncodeImageInternal( static int EncodeImageInternal(
VP8LBitWriter* const bw, const uint32_t* const argb, VP8LBitWriter* const bw, const uint32_t* const argb,
VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width, VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width,
int height, int quality, int low_effort, int use_cache, int height, int quality, int low_effort, const CrunchConfig* const config,
const CrunchConfig* const config, int* cache_bits, int histogram_bits, int* cache_bits, int histogram_bits, size_t init_byte_position,
size_t init_byte_position, int* const hdr_size, int* const data_size, int* const hdr_size, int* const data_size, const WebPPicture* const pic,
const WebPPicture* const pic, int percent_range, int* const percent) { int percent_range, int* const percent) {
const uint32_t histogram_image_xysize = const uint32_t histogram_image_xysize =
VP8LSubSampleSize(width, histogram_bits) * VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits); VP8LSubSampleSize(height, histogram_bits);
@ -871,13 +871,9 @@ static int EncodeImageInternal(
percent_start += percent_range; percent_start += percent_range;
remaining_percent -= percent_range; remaining_percent -= percent_range;
if (use_cache) { // If the value is different from zero, it has been set during the palette
// If the value is different from zero, it has been set during the // analysis.
// palette analysis. cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits;
cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits;
} else {
cache_bits_init = 0;
}
// If several iterations will happen, clone into bw_best. // If several iterations will happen, clone into bw_best.
if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) && if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) &&
!VP8LBitWriterClone(bw, &bw_best)) { !VP8LBitWriterClone(bw, &bw_best)) {
@ -1466,7 +1462,6 @@ typedef struct {
const WebPPicture* picture_; const WebPPicture* picture_;
VP8LBitWriter* bw_; VP8LBitWriter* bw_;
VP8LEncoder* enc_; VP8LEncoder* enc_;
int use_cache_;
CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX]; CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX];
int num_crunch_configs_; int num_crunch_configs_;
int red_and_blue_always_zero_; int red_and_blue_always_zero_;
@ -1479,7 +1474,6 @@ static int EncodeStreamHook(void* input, void* data2) {
const WebPPicture* const picture = params->picture_; const WebPPicture* const picture = params->picture_;
VP8LBitWriter* const bw = params->bw_; VP8LBitWriter* const bw = params->bw_;
VP8LEncoder* const enc = params->enc_; VP8LEncoder* const enc = params->enc_;
const int use_cache = params->use_cache_;
const CrunchConfig* const crunch_configs = params->crunch_configs_; const CrunchConfig* const crunch_configs = params->crunch_configs_;
const int num_crunch_configs = params->num_crunch_configs_; const int num_crunch_configs = params->num_crunch_configs_;
const int red_and_blue_always_zero = params->red_and_blue_always_zero_; const int red_and_blue_always_zero = params->red_and_blue_always_zero_;
@ -1567,7 +1561,7 @@ static int EncodeStreamHook(void* input, void* data2) {
if (!MapImageFromPalette(enc, use_delta_palette)) goto Error; if (!MapImageFromPalette(enc, use_delta_palette)) goto Error;
// If using a color cache, do not have it bigger than the number of // If using a color cache, do not have it bigger than the number of
// colors. // colors.
if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { if (enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1; enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1;
} }
} }
@ -1611,7 +1605,7 @@ static int EncodeStreamHook(void* input, void* data2) {
// Encode and write the transformed image. // Encode and write the transformed image.
if (!EncodeImageInternal( if (!EncodeImageInternal(
bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_, bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_,
height, quality, low_effort, use_cache, &crunch_configs[idx], height, quality, low_effort, &crunch_configs[idx],
&enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size, &enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size,
&data_size, picture, remaining_percent, &percent)) { &data_size, picture, remaining_percent, &percent)) {
goto Error; goto Error;
@ -1653,7 +1647,7 @@ static int EncodeStreamHook(void* input, void* data2) {
int VP8LEncodeStream(const WebPConfig* const config, int VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture, const WebPPicture* const picture,
VP8LBitWriter* const bw_main, int use_cache) { VP8LBitWriter* const bw_main) {
VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture); VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture);
VP8LEncoder* enc_side = NULL; VP8LEncoder* enc_side = NULL;
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX]; CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX];
@ -1675,7 +1669,9 @@ int VP8LEncodeStream(const WebPConfig* const config,
} }
// Avoid "garbage value" error from Clang's static analysis tool. // Avoid "garbage value" error from Clang's static analysis tool.
WebPPictureInit(&picture_side); if (!WebPPictureInit(&picture_side)) {
goto Error;
}
// Analyze image (entropy, num_palettes etc) // Analyze image (entropy, num_palettes etc)
if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
@ -1710,7 +1706,6 @@ int VP8LEncodeStream(const WebPConfig* const config,
StreamEncodeContext* const param = StreamEncodeContext* const param =
(idx == 0) ? &params_main : &params_side; (idx == 0) ? &params_main : &params_side;
param->config_ = config; param->config_ = config;
param->use_cache_ = use_cache;
param->red_and_blue_always_zero_ = red_and_blue_always_zero; param->red_and_blue_always_zero_ = red_and_blue_always_zero;
if (idx == 0) { if (idx == 0) {
param->picture_ = picture; param->picture_ = picture;
@ -1864,7 +1859,7 @@ int VP8LEncodeImage(const WebPConfig* const config,
if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort; if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort;
// Encode main image stream. // Encode main image stream.
if (!VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/)) goto Error; if (!VP8LEncodeStream(config, picture, &bw)) goto Error;
if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort; if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort;

View File

@ -88,11 +88,9 @@ int VP8LEncodeImage(const WebPConfig* const config,
const WebPPicture* const picture); const WebPPicture* const picture);
// Encodes the main image stream using the supplied bit writer. // Encodes the main image stream using the supplied bit writer.
// If 'use_cache' is false, disables the use of color cache.
// Returns false in case of error (stored in picture->error_code). // Returns false in case of error (stored in picture->error_code).
int VP8LEncodeStream(const WebPConfig* const config, int VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture, VP8LBitWriter* const bw, const WebPPicture* const picture, VP8LBitWriter* const bw);
int use_cache);
#if (WEBP_NEAR_LOSSLESS == 1) #if (WEBP_NEAR_LOSSLESS == 1)
// in near_lossless.c // in near_lossless.c

View File

@ -22,6 +22,7 @@
#include "src/webp/encode.h" #include "src/webp/encode.h"
#include "src/webp/format_constants.h" #include "src/webp/format_constants.h"
#include "src/webp/mux.h" #include "src/webp/mux.h"
#include "src/webp/types.h"
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf #define snprintf _snprintf
@ -1398,7 +1399,10 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
} }
config = *encoder_config; config = *encoder_config;
} else { } else {
WebPConfigInit(&config); if (!WebPConfigInit(&config)) {
MarkError(enc, "Cannot Init config");
return 0;
}
config.lossless = 1; config.lossless = 1;
} }
assert(enc->curr_canvas_ == NULL); assert(enc->curr_canvas_ == NULL);
@ -1419,12 +1423,14 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Bitstream assembly. // Bitstream assembly.
static int DecodeFrameOntoCanvas(const WebPMuxFrameInfo* const frame, WEBP_NODISCARD static int DecodeFrameOntoCanvas(
WebPPicture* const canvas) { const WebPMuxFrameInfo* const frame, WebPPicture* const canvas) {
const WebPData* const image = &frame->bitstream; const WebPData* const image = &frame->bitstream;
WebPPicture sub_image; WebPPicture sub_image;
WebPDecoderConfig config; WebPDecoderConfig config;
WebPInitDecoderConfig(&config); if (!WebPInitDecoderConfig(&config)) {
return 0;
}
WebPUtilClearPic(canvas, NULL); WebPUtilClearPic(canvas, NULL);
if (WebPGetFeatures(image->bytes, image->size, &config.input) != if (WebPGetFeatures(image->bytes, image->size, &config.input) !=
VP8_STATUS_OK) { VP8_STATUS_OK) {
@ -1583,4 +1589,23 @@ const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc) {
return enc->error_str_; return enc->error_str_;
} }
WebPMuxError WebPAnimEncoderSetChunk(
WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data,
int copy_data) {
if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
return WebPMuxSetChunk(enc->mux_, fourcc, chunk_data, copy_data);
}
WebPMuxError WebPAnimEncoderGetChunk(
const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data) {
if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
return WebPMuxGetChunk(enc->mux_, fourcc, chunk_data);
}
WebPMuxError WebPAnimEncoderDeleteChunk(
WebPAnimEncoder* enc, const char fourcc[4]) {
if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
return WebPMuxDeleteChunk(enc->mux_, fourcc);
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -66,14 +66,16 @@ void WebPMuxDelete(WebPMux* mux) {
// Handy MACRO, makes MuxSet() very symmetric to MuxGet(). // Handy MACRO, makes MuxSet() very symmetric to MuxGet().
#define SWITCH_ID_LIST(INDEX, LIST) \ #define SWITCH_ID_LIST(INDEX, LIST) \
if (idx == (INDEX)) { \ do { \
err = ChunkAssignData(&chunk, data, copy_data, tag); \ if (idx == (INDEX)) { \
if (err == WEBP_MUX_OK) { \ err = ChunkAssignData(&chunk, data, copy_data, tag); \
err = ChunkSetHead(&chunk, (LIST)); \ if (err == WEBP_MUX_OK) { \
if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \ err = ChunkSetHead(&chunk, (LIST)); \
if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \
} \
return err; \
} \ } \
return err; \ } while (0)
}
static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag,
const WebPData* const data, int copy_data) { const WebPData* const data, int copy_data) {

View File

@ -28,8 +28,8 @@ extern "C" {
// Defines and constants. // Defines and constants.
#define MUX_MAJ_VERSION 1 #define MUX_MAJ_VERSION 1
#define MUX_MIN_VERSION 3 #define MUX_MIN_VERSION 4
#define MUX_REV_VERSION 1 #define MUX_REV_VERSION 0
// Chunk object. // Chunk object.
typedef struct WebPChunk WebPChunk; typedef struct WebPChunk WebPChunk;

View File

@ -21,20 +21,23 @@
// Handy MACRO. // Handy MACRO.
#define SWITCH_ID_LIST(INDEX, LIST) \ #define SWITCH_ID_LIST(INDEX, LIST) \
if (idx == (INDEX)) { \ do { \
const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \ if (idx == (INDEX)) { \
kChunks[(INDEX)].tag); \ const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \
if (chunk) { \ kChunks[(INDEX)].tag); \
*data = chunk->data_; \ if (chunk) { \
return WEBP_MUX_OK; \ *data = chunk->data_; \
} else { \ return WEBP_MUX_OK; \
return WEBP_MUX_NOT_FOUND; \ } else { \
return WEBP_MUX_NOT_FOUND; \
} \
} \ } \
} } while (0)
static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx, static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
uint32_t nth, WebPData* const data) { uint32_t nth, WebPData* const data) {
assert(mux != NULL); assert(mux != NULL);
assert(idx != IDX_LAST_CHUNK);
assert(!IsWPI(kChunks[idx].id)); assert(!IsWPI(kChunks[idx].id));
WebPDataInit(data); WebPDataInit(data);
@ -429,6 +432,7 @@ WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4],
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
idx = ChunkGetIndexFromFourCC(fourcc); idx = ChunkGetIndexFromFourCC(fourcc);
assert(idx != IDX_LAST_CHUNK);
if (IsWPI(kChunks[idx].id)) { // An image chunk. if (IsWPI(kChunks[idx].id)) { // An image chunk.
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} else if (idx != IDX_UNKNOWN) { // A known chunk type. } else if (idx != IDX_UNKNOWN) { // A known chunk type.

View File

@ -122,6 +122,9 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
const int symbol_code_length = code_lengths[symbol]; const int symbol_code_length = code_lengths[symbol];
if (code_lengths[symbol] > 0) { if (code_lengths[symbol] > 0) {
if (sorted != NULL) { if (sorted != NULL) {
if(offset[symbol_code_length] >= code_lengths_size) {
return 0;
}
sorted[offset[symbol_code_length]++] = symbol; sorted[offset[symbol_code_length]++] = symbol;
} else { } else {
offset[symbol_code_length]++; offset[symbol_code_length]++;
@ -267,11 +270,11 @@ int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
// Have 'segment' point to the first segment for now, 'root'. // Have 'segment' point to the first segment for now, 'root'.
HuffmanTablesSegment* const root = &huffman_tables->root; HuffmanTablesSegment* const root = &huffman_tables->root;
huffman_tables->curr_segment = root; huffman_tables->curr_segment = root;
root->next = NULL;
// Allocate root. // Allocate root.
root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start)); root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
if (root->start == NULL) return 0; if (root->start == NULL) return 0;
root->curr_table = root->start; root->curr_table = root->start;
root->next = NULL;
root->size = size; root->size = size;
return 1; return 1;
} }

View File

@ -63,7 +63,8 @@ typedef struct HuffmanTables {
// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on // Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
// memory allocation error, 1 otherwise. // memory allocation error, 1 otherwise.
int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables); WEBP_NODISCARD int VP8LHuffmanTablesAllocate(int size,
HuffmanTables* huffman_tables);
void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables); void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
#define HUFFMAN_PACKED_BITS 6 #define HUFFMAN_PACKED_BITS 6
@ -91,7 +92,7 @@ struct HTreeGroup {
}; };
// Creates the instance of HTreeGroup with specified number of tree-groups. // Creates the instance of HTreeGroup with specified number of tree-groups.
HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups); WEBP_NODISCARD HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups);
// Releases the memory allocated for HTreeGroup. // Releases the memory allocated for HTreeGroup.
void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups); void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
@ -101,8 +102,10 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
// the huffman table. // the huffman table.
// Returns built table size or 0 in case of error (invalid tree or // Returns built table size or 0 in case of error (invalid tree or
// memory error). // memory error).
int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits, WEBP_NODISCARD int VP8LBuildHuffmanTable(HuffmanTables* const root_table,
const int code_lengths[], int code_lengths_size); int root_bits,
const int code_lengths[],
int code_lengths_size);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View File

@ -48,34 +48,33 @@ WEBP_EXTERN int WebPGetDecoderVersion(void);
// RIFF + VP8X + (optional chunks) + VP8(L) // RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo(
int* width, int* height); const uint8_t* data, size_t data_size, int* width, int* height);
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along // Decodes WebP images pointed to by 'data' and returns RGBA samples, along
// with the dimensions in *width and *height. The ordering of samples in // with the dimensions in *width and *height. The ordering of samples in
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent). // memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
// The returned pointer should be deleted calling WebPFree(). // The returned pointer should be deleted calling WebPFree().
// Returns NULL in case of error. // Returns NULL in case of error.
WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(
int* width, int* height); const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data. // Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
WEBP_EXTERN uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB(
int* width, int* height); const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data. // Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
WEBP_EXTERN uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA(
int* width, int* height); const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data. // Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
// If the bitstream contains transparency, it is ignored. // If the bitstream contains transparency, it is ignored.
WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(
int* width, int* height); const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data. // Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(
int* width, int* height); const uint8_t* data, size_t data_size, int* width, int* height);
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer // Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
// returned is the Y samples buffer. Upon return, *u and *v will point to // returned is the Y samples buffer. Upon return, *u and *v will point to
@ -87,10 +86,9 @@ WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
// 'width' and 'height' may be NULL, the other pointers must not be. // 'width' and 'height' may be NULL, the other pointers must not be.
// Returns NULL in case of error. // Returns NULL in case of error.
// (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr // (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr
WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(
int* width, int* height, const uint8_t* data, size_t data_size, int* width, int* height,
uint8_t** u, uint8_t** v, uint8_t** u, uint8_t** v, int* stride, int* uv_stride);
int* stride, int* uv_stride);
// These five functions are variants of the above ones, that decode the image // These five functions are variants of the above ones, that decode the image
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage // directly into a pre-allocated buffer 'output_buffer'. The maximum storage
@ -100,22 +98,22 @@ WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
// The parameter 'output_stride' specifies the distance (in bytes) // The parameter 'output_stride' specifies the distance (in bytes)
// between scanlines. Hence, output_buffer_size is expected to be at least // between scanlines. Hence, output_buffer_size is expected to be at least
// output_stride x picture-height. // output_stride x picture-height.
WEBP_EXTERN uint8_t* WebPDecodeRGBAInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
const uint8_t* data, size_t data_size, const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride); uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
WEBP_EXTERN uint8_t* WebPDecodeARGBInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
const uint8_t* data, size_t data_size, const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride); uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
WEBP_EXTERN uint8_t* WebPDecodeBGRAInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
const uint8_t* data, size_t data_size, const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride); uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
// RGB and BGR variants. Here too the transparency information, if present, // RGB and BGR variants. Here too the transparency information, if present,
// will be dropped and ignored. // will be dropped and ignored.
WEBP_EXTERN uint8_t* WebPDecodeRGBInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
const uint8_t* data, size_t data_size, const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride); uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
WEBP_EXTERN uint8_t* WebPDecodeBGRInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
const uint8_t* data, size_t data_size, const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride); uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
@ -126,7 +124,7 @@ WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
// 'u_size' and 'v_size' respectively. // 'u_size' and 'v_size' respectively.
// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred // Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
// during decoding (or because some buffers were found to be too small). // during decoding (or because some buffers were found to be too small).
WEBP_EXTERN uint8_t* WebPDecodeYUVInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
const uint8_t* data, size_t data_size, const uint8_t* data, size_t data_size,
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride, uint8_t* u, size_t u_size, int u_stride,
@ -217,11 +215,11 @@ struct WebPDecBuffer {
}; };
// Internal, version-checked, entry point // Internal, version-checked, entry point
WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int); WEBP_NODISCARD WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int);
// Initialize the structure as empty. Must be called before any other use. // Initialize the structure as empty. Must be called before any other use.
// Returns false in case of version mismatch // Returns false in case of version mismatch
static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) { WEBP_NODISCARD static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
return WebPInitDecBufferInternal(buffer, WEBP_DECODER_ABI_VERSION); return WebPInitDecBufferInternal(buffer, WEBP_DECODER_ABI_VERSION);
} }
@ -232,7 +230,7 @@ WEBP_EXTERN void WebPFreeDecBuffer(WebPDecBuffer* buffer);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Enumeration of the status codes // Enumeration of the status codes
typedef enum VP8StatusCode { typedef enum WEBP_NODISCARD VP8StatusCode {
VP8_STATUS_OK = 0, VP8_STATUS_OK = 0,
VP8_STATUS_OUT_OF_MEMORY, VP8_STATUS_OUT_OF_MEMORY,
VP8_STATUS_INVALID_PARAM, VP8_STATUS_INVALID_PARAM,
@ -282,7 +280,8 @@ typedef enum VP8StatusCode {
// within valid bounds. // within valid bounds.
// All other fields of WebPDecBuffer MUST remain constant between calls. // All other fields of WebPDecBuffer MUST remain constant between calls.
// Returns NULL if the allocation failed. // Returns NULL if the allocation failed.
WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer); WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewDecoder(
WebPDecBuffer* output_buffer);
// This function allocates and initializes an incremental-decoder object, which // This function allocates and initializes an incremental-decoder object, which
// will output the RGB/A samples specified by 'csp' into a preallocated // will output the RGB/A samples specified by 'csp' into a preallocated
@ -294,7 +293,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer);
// colorspace 'csp' is taken into account for allocating this buffer. All other // colorspace 'csp' is taken into account for allocating this buffer. All other
// parameters are ignored. // parameters are ignored.
// Returns NULL if the allocation failed, or if some parameters are invalid. // Returns NULL if the allocation failed, or if some parameters are invalid.
WEBP_EXTERN WebPIDecoder* WebPINewRGB( WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(
WEBP_CSP_MODE csp, WEBP_CSP_MODE csp,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride); uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
@ -309,7 +308,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewRGB(
// In this case, the output buffer will be automatically allocated (using // In this case, the output buffer will be automatically allocated (using
// MODE_YUVA) when decoding starts. All parameters are then ignored. // MODE_YUVA) when decoding starts. All parameters are then ignored.
// Returns NULL if the allocation failed or if a parameter is invalid. // Returns NULL if the allocation failed or if a parameter is invalid.
WEBP_EXTERN WebPIDecoder* WebPINewYUVA( WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride, uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride, uint8_t* v, size_t v_size, int v_stride,
@ -317,7 +316,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
// Deprecated version of the above, without the alpha plane. // Deprecated version of the above, without the alpha plane.
// Kept for backward compatibility. // Kept for backward compatibility.
WEBP_EXTERN WebPIDecoder* WebPINewYUV( WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUV(
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride, uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride); uint8_t* v, size_t v_size, int v_stride);
@ -347,21 +346,21 @@ WEBP_EXTERN VP8StatusCode WebPIUpdate(
// (*last_y, *width etc.) can be NULL if corresponding information is not // (*last_y, *width etc.) can be NULL if corresponding information is not
// needed. The values in these pointers are only valid on successful (non-NULL) // needed. The values in these pointers are only valid on successful (non-NULL)
// return. // return.
WEBP_EXTERN uint8_t* WebPIDecGetRGB( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPIDecGetRGB(
const WebPIDecoder* idec, int* last_y, const WebPIDecoder* idec, int* last_y,
int* width, int* height, int* stride); int* width, int* height, int* stride);
// Same as above function to get a YUVA image. Returns pointer to the luma // Same as above function to get a YUVA image. Returns pointer to the luma
// plane or NULL in case of error. If there is no alpha information // plane or NULL in case of error. If there is no alpha information
// the alpha pointer '*a' will be returned NULL. // the alpha pointer '*a' will be returned NULL.
WEBP_EXTERN uint8_t* WebPIDecGetYUVA( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPIDecGetYUVA(
const WebPIDecoder* idec, int* last_y, const WebPIDecoder* idec, int* last_y,
uint8_t** u, uint8_t** v, uint8_t** a, uint8_t** u, uint8_t** v, uint8_t** a,
int* width, int* height, int* stride, int* uv_stride, int* a_stride); int* width, int* height, int* stride, int* uv_stride, int* a_stride);
// Deprecated alpha-less version of WebPIDecGetYUVA(): it will ignore the // Deprecated alpha-less version of WebPIDecGetYUVA(): it will ignore the
// alpha information (if present). Kept for backward compatibility. // alpha information (if present). Kept for backward compatibility.
static WEBP_INLINE uint8_t* WebPIDecGetYUV( WEBP_NODISCARD static WEBP_INLINE uint8_t* WebPIDecGetYUV(
const WebPIDecoder* idec, int* last_y, uint8_t** u, uint8_t** v, const WebPIDecoder* idec, int* last_y, uint8_t** u, uint8_t** v,
int* width, int* height, int* stride, int* uv_stride) { int* width, int* height, int* stride, int* uv_stride) {
return WebPIDecGetYUVA(idec, last_y, u, v, NULL, width, height, return WebPIDecGetYUVA(idec, last_y, u, v, NULL, width, height,
@ -374,7 +373,7 @@ static WEBP_INLINE uint8_t* WebPIDecGetYUV(
// Returns NULL in case the incremental decoder object is in an invalid state. // Returns NULL in case the incremental decoder object is in an invalid state.
// Otherwise returns the pointer to the internal representation. This structure // Otherwise returns the pointer to the internal representation. This structure
// is read-only, tied to WebPIDecoder's lifespan and should not be modified. // is read-only, tied to WebPIDecoder's lifespan and should not be modified.
WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea( WEBP_NODISCARD WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
const WebPIDecoder* idec, int* left, int* top, int* width, int* height); const WebPIDecoder* idec, int* left, int* top, int* width, int* height);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -469,12 +468,14 @@ struct WebPDecoderConfig {
}; };
// Internal, version-checked, entry point // Internal, version-checked, entry point
WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*, int); WEBP_NODISCARD WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*,
int);
// Initialize the configuration as empty. This function must always be // Initialize the configuration as empty. This function must always be
// called first, unless WebPGetFeatures() is to be called. // called first, unless WebPGetFeatures() is to be called.
// Returns false in case of mismatched version. // Returns false in case of mismatched version.
static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) { WEBP_NODISCARD static WEBP_INLINE int WebPInitDecoderConfig(
WebPDecoderConfig* config) {
return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION); return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION);
} }
@ -489,8 +490,8 @@ static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
// The return WebPIDecoder object must always be deleted calling WebPIDelete(). // The return WebPIDecoder object must always be deleted calling WebPIDelete().
// Returns NULL in case of error (and config->status will then reflect // Returns NULL in case of error (and config->status will then reflect
// the error condition, if available). // the error condition, if available).
WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(
WebPDecoderConfig* config); const uint8_t* data, size_t data_size, WebPDecoderConfig* config);
// Non-incremental version. This version decodes the full data at once, taking // Non-incremental version. This version decodes the full data at once, taking
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK // 'config' into account. Returns decoding status (which should be VP8_STATUS_OK

View File

@ -50,6 +50,7 @@
#include "./decode.h" // for WEBP_CSP_MODE #include "./decode.h" // for WEBP_CSP_MODE
#include "./mux_types.h" #include "./mux_types.h"
#include "./types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -85,13 +86,13 @@ typedef enum WebPDemuxState {
} WebPDemuxState; } WebPDemuxState;
// Internal, version-checked, entry point // Internal, version-checked, entry point
WEBP_EXTERN WebPDemuxer* WebPDemuxInternal( WEBP_NODISCARD WEBP_EXTERN WebPDemuxer* WebPDemuxInternal(
const WebPData*, int, WebPDemuxState*, int); const WebPData*, int, WebPDemuxState*, int);
// Parses the full WebP file given by 'data'. For single images the WebP file // Parses the full WebP file given by 'data'. For single images the WebP file
// header alone or the file header and the chunk header may be absent. // header alone or the file header and the chunk header may be absent.
// Returns a WebPDemuxer object on successful parse, NULL otherwise. // Returns a WebPDemuxer object on successful parse, NULL otherwise.
static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) { WEBP_NODISCARD static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION); return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION);
} }
@ -103,7 +104,7 @@ static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
// If this data is volatile, the demuxer object should be deleted (by calling // If this data is volatile, the demuxer object should be deleted (by calling
// WebPDemuxDelete()) and WebPDemuxPartial() called again on the new data. // WebPDemuxDelete()) and WebPDemuxPartial() called again on the new data.
// This is usually an inexpensive operation. // This is usually an inexpensive operation.
static WEBP_INLINE WebPDemuxer* WebPDemuxPartial( WEBP_NODISCARD static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
const WebPData* data, WebPDemuxState* state) { const WebPData* data, WebPDemuxState* state) {
return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION); return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION);
} }
@ -164,14 +165,14 @@ struct WebPIterator {
// Returns false if 'dmux' is NULL or frame 'frame_number' is not present. // Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
// Call WebPDemuxReleaseIterator() when use of the iterator is complete. // Call WebPDemuxReleaseIterator() when use of the iterator is complete.
// NOTE: 'dmux' must persist for the lifetime of 'iter'. // NOTE: 'dmux' must persist for the lifetime of 'iter'.
WEBP_EXTERN int WebPDemuxGetFrame( WEBP_NODISCARD WEBP_EXTERN int WebPDemuxGetFrame(
const WebPDemuxer* dmux, int frame_number, WebPIterator* iter); const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or // Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
// previous ('iter->frame_num' - 1) frame. These functions do not loop. // previous ('iter->frame_num' - 1) frame. These functions do not loop.
// Returns true on success, false otherwise. // Returns true on success, false otherwise.
WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter); WEBP_NODISCARD WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter);
WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter); WEBP_NODISCARD WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter);
// Releases any memory associated with 'iter'. // Releases any memory associated with 'iter'.
// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same // Must be called before any subsequent calls to WebPDemuxGetChunk() on the same
@ -202,15 +203,16 @@ struct WebPChunkIterator {
// payloads are accessed through WebPDemuxGetFrame() and related functions. // payloads are accessed through WebPDemuxGetFrame() and related functions.
// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete. // Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
// NOTE: 'dmux' must persist for the lifetime of the iterator. // NOTE: 'dmux' must persist for the lifetime of the iterator.
WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux, WEBP_NODISCARD WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux,
const char fourcc[4], int chunk_number, const char fourcc[4],
WebPChunkIterator* iter); int chunk_number,
WebPChunkIterator* iter);
// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous // Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
// ('iter->chunk_num' - 1) chunk. These functions do not loop. // ('iter->chunk_num' - 1) chunk. These functions do not loop.
// Returns true on success, false otherwise. // Returns true on success, false otherwise.
WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter); WEBP_NODISCARD WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter);
WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter); WEBP_NODISCARD WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter);
// Releases any memory associated with 'iter'. // Releases any memory associated with 'iter'.
// Must be called before destroying the associated WebPDemuxer with // Must be called before destroying the associated WebPDemuxer with
@ -257,21 +259,21 @@ struct WebPAnimDecoderOptions {
}; };
// Internal, version-checked, entry point. // Internal, version-checked, entry point.
WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal( WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal(
WebPAnimDecoderOptions*, int); WebPAnimDecoderOptions*, int);
// Should always be called, to initialize a fresh WebPAnimDecoderOptions // Should always be called, to initialize a fresh WebPAnimDecoderOptions
// structure before modification. Returns false in case of version mismatch. // structure before modification. Returns false in case of version mismatch.
// WebPAnimDecoderOptionsInit() must have succeeded before using the // WebPAnimDecoderOptionsInit() must have succeeded before using the
// 'dec_options' object. // 'dec_options' object.
static WEBP_INLINE int WebPAnimDecoderOptionsInit( WEBP_NODISCARD static WEBP_INLINE int WebPAnimDecoderOptionsInit(
WebPAnimDecoderOptions* dec_options) { WebPAnimDecoderOptions* dec_options) {
return WebPAnimDecoderOptionsInitInternal(dec_options, return WebPAnimDecoderOptionsInitInternal(dec_options,
WEBP_DEMUX_ABI_VERSION); WEBP_DEMUX_ABI_VERSION);
} }
// Internal, version-checked, entry point. // Internal, version-checked, entry point.
WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal( WEBP_NODISCARD WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
const WebPData*, const WebPAnimDecoderOptions*, int); const WebPData*, const WebPAnimDecoderOptions*, int);
// Creates and initializes a WebPAnimDecoder object. // Creates and initializes a WebPAnimDecoder object.
@ -284,7 +286,7 @@ WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
// Returns: // Returns:
// A pointer to the newly created WebPAnimDecoder object, or NULL in case of // A pointer to the newly created WebPAnimDecoder object, or NULL in case of
// parsing error, invalid option or memory error. // parsing error, invalid option or memory error.
static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew( WEBP_NODISCARD static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew(
const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options) { const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options) {
return WebPAnimDecoderNewInternal(webp_data, dec_options, return WebPAnimDecoderNewInternal(webp_data, dec_options,
WEBP_DEMUX_ABI_VERSION); WEBP_DEMUX_ABI_VERSION);
@ -306,8 +308,8 @@ struct WebPAnimInfo {
// info - (out) global information fetched from the animation. // info - (out) global information fetched from the animation.
// Returns: // Returns:
// True on success. // True on success.
WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderGetInfo(
WebPAnimInfo* info); const WebPAnimDecoder* dec, WebPAnimInfo* info);
// Fetch the next frame from 'dec' based on options supplied to // Fetch the next frame from 'dec' based on options supplied to
// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size // WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size
@ -321,8 +323,9 @@ WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
// Returns: // Returns:
// False if any of the arguments are NULL, or if there is a parsing or // False if any of the arguments are NULL, or if there is a parsing or
// decoding error, or if there are no more frames. Otherwise, returns true. // decoding error, or if there are no more frames. Otherwise, returns true.
WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
uint8_t** buf, int* timestamp); uint8_t** buf,
int* timestamp);
// Check if there are more frames left to decode. // Check if there are more frames left to decode.
// Parameters: // Parameters:
@ -330,7 +333,8 @@ WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
// Returns: // Returns:
// True if 'dec' is not NULL and some frames are yet to be decoded. // True if 'dec' is not NULL and some frames are yet to be decoded.
// Otherwise, returns false. // Otherwise, returns false.
WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec); WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(
const WebPAnimDecoder* dec);
// Resets the WebPAnimDecoder object, so that next call to // Resets the WebPAnimDecoder object, so that next call to
// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be // WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be
@ -348,7 +352,7 @@ WEBP_EXTERN void WebPAnimDecoderReset(WebPAnimDecoder* dec);
// //
// Parameters: // Parameters:
// dec - (in) decoder instance from which the demuxer object is to be fetched. // dec - (in) decoder instance from which the demuxer object is to be fetched.
WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer( WEBP_NODISCARD WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer(
const WebPAnimDecoder* dec); const WebPAnimDecoder* dec);
// Deletes the WebPAnimDecoder object. // Deletes the WebPAnimDecoder object.

View File

@ -164,13 +164,14 @@ typedef enum WebPPreset {
} WebPPreset; } WebPPreset;
// Internal, version-checked, entry point // Internal, version-checked, entry point
WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int); WEBP_NODISCARD WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset,
float, int);
// Should always be called, to initialize a fresh WebPConfig structure before // Should always be called, to initialize a fresh WebPConfig structure before
// modification. Returns false in case of version mismatch. WebPConfigInit() // modification. Returns false in case of version mismatch. WebPConfigInit()
// must have succeeded before using the 'config' object. // must have succeeded before using the 'config' object.
// Note that the default values are lossless=0 and quality=75. // Note that the default values are lossless=0 and quality=75.
static WEBP_INLINE int WebPConfigInit(WebPConfig* config) { WEBP_NODISCARD static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f, return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f,
WEBP_ENCODER_ABI_VERSION); WEBP_ENCODER_ABI_VERSION);
} }
@ -179,8 +180,9 @@ static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
// set of parameters (referred to by 'preset') and a given quality factor. // set of parameters (referred to by 'preset') and a given quality factor.
// This function can be called as a replacement to WebPConfigInit(). Will // This function can be called as a replacement to WebPConfigInit(). Will
// return false in case of error. // return false in case of error.
static WEBP_INLINE int WebPConfigPreset(WebPConfig* config, WEBP_NODISCARD static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
WebPPreset preset, float quality) { WebPPreset preset,
float quality) {
return WebPConfigInitInternal(config, preset, quality, return WebPConfigInitInternal(config, preset, quality,
WEBP_ENCODER_ABI_VERSION); WEBP_ENCODER_ABI_VERSION);
} }
@ -191,11 +193,12 @@ static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
// speed and final compressed size. // speed and final compressed size.
// This function will overwrite several fields from config: 'method', 'quality' // This function will overwrite several fields from config: 'method', 'quality'
// and 'lossless'. Returns false in case of parameter error. // and 'lossless'. Returns false in case of parameter error.
WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config, int level); WEBP_NODISCARD WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config,
int level);
// Returns true if 'config' is non-NULL and all configuration parameters are // Returns true if 'config' is non-NULL and all configuration parameters are
// within their valid ranges. // within their valid ranges.
WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config); WEBP_NODISCARD WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Input / Output // Input / Output
@ -255,8 +258,8 @@ WEBP_EXTERN void WebPMemoryWriterClear(WebPMemoryWriter* writer);
// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon // The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
// completion, writer.mem and writer.size will hold the coded data. // completion, writer.mem and writer.size will hold the coded data.
// writer.mem must be freed by calling WebPMemoryWriterClear. // writer.mem must be freed by calling WebPMemoryWriterClear.
WEBP_EXTERN int WebPMemoryWrite(const uint8_t* data, size_t data_size, WEBP_NODISCARD WEBP_EXTERN int WebPMemoryWrite(
const WebPPicture* picture); const uint8_t* data, size_t data_size, const WebPPicture* picture);
// Progress hook, called from time to time to report progress. It can return // Progress hook, called from time to time to report progress. It can return
// false to request an abort of the encoding process, or true otherwise if // false to request an abort of the encoding process, or true otherwise if
@ -364,13 +367,13 @@ struct WebPPicture {
}; };
// Internal, version-checked, entry point // Internal, version-checked, entry point
WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int); WEBP_NODISCARD WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int);
// Should always be called, to initialize the structure. Returns false in case // Should always be called, to initialize the structure. Returns false in case
// of version mismatch. WebPPictureInit() must have succeeded before using the // of version mismatch. WebPPictureInit() must have succeeded before using the
// 'picture' object. // 'picture' object.
// Note that, by default, use_argb is false and colorspace is WEBP_YUV420. // Note that, by default, use_argb is false and colorspace is WEBP_YUV420.
static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) { WEBP_NODISCARD static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION); return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION);
} }
@ -381,7 +384,7 @@ static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
// Allocate y/u/v buffers as per colorspace/width/height specification. // Allocate y/u/v buffers as per colorspace/width/height specification.
// Note! This function will free the previous buffer if needed. // Note! This function will free the previous buffer if needed.
// Returns false in case of memory error. // Returns false in case of memory error.
WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture); WEBP_NODISCARD WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture);
// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*(). // Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
// Note that this function does _not_ free the memory used by the 'picture' // Note that this function does _not_ free the memory used by the 'picture'
@ -394,7 +397,8 @@ WEBP_EXTERN void WebPPictureFree(WebPPicture* picture);
// will fully own the copied pixels (this is not a view). The 'dst' picture need // will fully own the copied pixels (this is not a view). The 'dst' picture need
// not be initialized as its content is overwritten. // not be initialized as its content is overwritten.
// Returns false in case of memory allocation error. // Returns false in case of memory allocation error.
WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst); WEBP_NODISCARD WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src,
WebPPicture* dst);
// Compute the single distortion for packed planes of samples. // Compute the single distortion for packed planes of samples.
// 'src' will be compared to 'ref', and the raw distortion stored into // 'src' will be compared to 'ref', and the raw distortion stored into
@ -403,19 +407,18 @@ WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
// 'x_step' is the horizontal stride (in bytes) between samples. // 'x_step' is the horizontal stride (in bytes) between samples.
// 'src/ref_stride' is the byte distance between rows. // 'src/ref_stride' is the byte distance between rows.
// Returns false in case of error (bad parameter, memory allocation error, ...). // Returns false in case of error (bad parameter, memory allocation error, ...).
WEBP_EXTERN int WebPPlaneDistortion(const uint8_t* src, size_t src_stride, WEBP_NODISCARD WEBP_EXTERN int WebPPlaneDistortion(
const uint8_t* ref, size_t ref_stride, const uint8_t* src, size_t src_stride,
int width, int height, const uint8_t* ref, size_t ref_stride, int width, int height, size_t x_step,
size_t x_step, int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM float* distortion, float* result);
float* distortion, float* result);
// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results // Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results
// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is // are in dB, stored in result[] in the B/G/R/A/All order. The distortion is
// always performed using ARGB samples. Hence if the input is YUV(A), the // always performed using ARGB samples. Hence if the input is YUV(A), the
// picture will be internally converted to ARGB (just for the measurement). // picture will be internally converted to ARGB (just for the measurement).
// Warning: this function is rather CPU-intensive. // Warning: this function is rather CPU-intensive.
WEBP_EXTERN int WebPPictureDistortion( WEBP_NODISCARD WEBP_EXTERN int WebPPictureDistortion(
const WebPPicture* src, const WebPPicture* ref, const WebPPicture* src, const WebPPicture* ref,
int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
float result[5]); float result[5]);
@ -428,8 +431,8 @@ WEBP_EXTERN int WebPPictureDistortion(
// must be fully be comprised inside the 'src' source picture. If the source // must be fully be comprised inside the 'src' source picture. If the source
// picture uses the YUV420 colorspace, the top and left coordinates will be // picture uses the YUV420 colorspace, the top and left coordinates will be
// snapped to even values. // snapped to even values.
WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture, WEBP_NODISCARD WEBP_EXTERN int WebPPictureCrop(
int left, int top, int width, int height); WebPPicture* picture, int left, int top, int width, int height);
// Extracts a view from 'src' picture into 'dst'. The rectangle for the view // Extracts a view from 'src' picture into 'dst'. The rectangle for the view
// is defined by the top-left corner pixel coordinates (left, top) as well // is defined by the top-left corner pixel coordinates (left, top) as well
@ -442,9 +445,9 @@ WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
// with WebPPictureInit() if it is different from 'src', since its content will // with WebPPictureInit() if it is different from 'src', since its content will
// be overwritten. // be overwritten.
// Returns false in case of invalid parameters. // Returns false in case of invalid parameters.
WEBP_EXTERN int WebPPictureView(const WebPPicture* src, WEBP_NODISCARD WEBP_EXTERN int WebPPictureView(
int left, int top, int width, int height, const WebPPicture* src, int left, int top, int width, int height,
WebPPicture* dst); WebPPicture* dst);
// Returns true if the 'picture' is actually a view and therefore does // Returns true if the 'picture' is actually a view and therefore does
// not own the memory for pixels. // not own the memory for pixels.
@ -455,29 +458,30 @@ WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture);
// dimension will be calculated preserving the aspect ratio. // dimension will be calculated preserving the aspect ratio.
// No gamma correction is applied. // No gamma correction is applied.
// Returns false in case of error (invalid parameter or insufficient memory). // Returns false in case of error (invalid parameter or insufficient memory).
WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture, int width, int height); WEBP_NODISCARD WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture,
int width, int height);
// Colorspace conversion function to import RGB samples. // Colorspace conversion function to import RGB samples.
// Previous buffer will be free'd, if any. // Previous buffer will be free'd, if any.
// *rgb buffer should have a size of at least height * rgb_stride. // *rgb buffer should have a size of at least height * rgb_stride.
// Returns false in case of memory error. // Returns false in case of memory error.
WEBP_EXTERN int WebPPictureImportRGB( WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGB(
WebPPicture* picture, const uint8_t* rgb, int rgb_stride); WebPPicture* picture, const uint8_t* rgb, int rgb_stride);
// Same, but for RGBA buffer. // Same, but for RGBA buffer.
WEBP_EXTERN int WebPPictureImportRGBA( WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGBA(
WebPPicture* picture, const uint8_t* rgba, int rgba_stride); WebPPicture* picture, const uint8_t* rgba, int rgba_stride);
// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format // Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format
// input buffer ignoring the alpha channel. Avoids needing to copy the data // input buffer ignoring the alpha channel. Avoids needing to copy the data
// to a temporary 24-bit RGB buffer to import the RGB only. // to a temporary 24-bit RGB buffer to import the RGB only.
WEBP_EXTERN int WebPPictureImportRGBX( WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGBX(
WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride); WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride);
// Variants of the above, but taking BGR(A|X) input. // Variants of the above, but taking BGR(A|X) input.
WEBP_EXTERN int WebPPictureImportBGR( WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGR(
WebPPicture* picture, const uint8_t* bgr, int bgr_stride); WebPPicture* picture, const uint8_t* bgr, int bgr_stride);
WEBP_EXTERN int WebPPictureImportBGRA( WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGRA(
WebPPicture* picture, const uint8_t* bgra, int bgra_stride); WebPPicture* picture, const uint8_t* bgra, int bgra_stride);
WEBP_EXTERN int WebPPictureImportBGRX( WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGRX(
WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride); WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
// Converts picture->argb data to the YUV420A format. The 'colorspace' // Converts picture->argb data to the YUV420A format. The 'colorspace'
@ -486,24 +490,24 @@ WEBP_EXTERN int WebPPictureImportBGRX(
// non-opaque transparent values is detected, and 'colorspace' will be // non-opaque transparent values is detected, and 'colorspace' will be
// adjusted accordingly. Note that this method is lossy. // adjusted accordingly. Note that this method is lossy.
// Returns false in case of error. // Returns false in case of error.
WEBP_EXTERN int WebPPictureARGBToYUVA(WebPPicture* picture, WEBP_NODISCARD WEBP_EXTERN int WebPPictureARGBToYUVA(
WebPEncCSP /*colorspace = WEBP_YUV420*/); WebPPicture* picture, WebPEncCSP /*colorspace = WEBP_YUV420*/);
// Same as WebPPictureARGBToYUVA(), but the conversion is done using // Same as WebPPictureARGBToYUVA(), but the conversion is done using
// pseudo-random dithering with a strength 'dithering' between // pseudo-random dithering with a strength 'dithering' between
// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful // 0.0 (no dithering) and 1.0 (maximum dithering). This is useful
// for photographic picture. // for photographic picture.
WEBP_EXTERN int WebPPictureARGBToYUVADithered( WEBP_NODISCARD WEBP_EXTERN int WebPPictureARGBToYUVADithered(
WebPPicture* picture, WebPEncCSP colorspace, float dithering); WebPPicture* picture, WebPEncCSP colorspace, float dithering);
// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion. // Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion
// Downsampling is handled with extra care in case of color clipping. This // Downsampling is handled with extra care in case of color clipping. This
// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better // method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better
// and sharper YUV representation. // and sharper YUV representation.
// Returns false in case of error. // Returns false in case of error.
WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture); WEBP_NODISCARD WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture);
// kept for backward compatibility: // kept for backward compatibility:
WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture); WEBP_NODISCARD WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Converts picture->yuv to picture->argb and sets picture->use_argb to true. // Converts picture->yuv to picture->argb and sets picture->use_argb to true.
// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to // The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to
@ -511,7 +515,7 @@ WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Note that the use of this colorspace is discouraged if one has access to the // Note that the use of this colorspace is discouraged if one has access to the
// raw ARGB samples, since using YUV420 is comparatively lossy. // raw ARGB samples, since using YUV420 is comparatively lossy.
// Returns false in case of error. // Returns false in case of error.
WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture); WEBP_NODISCARD WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture);
// Helper function: given a width x height plane of RGBA or YUV(A) samples // Helper function: given a width x height plane of RGBA or YUV(A) samples
// clean-up or smoothen the YUV or RGB samples under fully transparent area, // clean-up or smoothen the YUV or RGB samples under fully transparent area,
@ -541,7 +545,8 @@ WEBP_EXTERN void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb);
// the former for lossy encoding, and the latter for lossless encoding // the former for lossy encoding, and the latter for lossless encoding
// (when config.lossless is true). Automatic conversion from one format to // (when config.lossless is true). Automatic conversion from one format to
// another is provided but they both incur some loss. // another is provided but they both incur some loss.
WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture); WEBP_NODISCARD WEBP_EXTERN int WebPEncode(const WebPConfig* config,
WebPPicture* picture);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -16,12 +16,13 @@
#define WEBP_WEBP_MUX_H_ #define WEBP_WEBP_MUX_H_
#include "./mux_types.h" #include "./mux_types.h"
#include "./types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#define WEBP_MUX_ABI_VERSION 0x0108 // MAJOR(8b) + MINOR(8b) #define WEBP_MUX_ABI_VERSION 0x0109 // MAJOR(8b) + MINOR(8b)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Mux API // Mux API
@ -70,7 +71,7 @@ typedef struct WebPMuxAnimParams WebPMuxAnimParams;
typedef struct WebPAnimEncoderOptions WebPAnimEncoderOptions; typedef struct WebPAnimEncoderOptions WebPAnimEncoderOptions;
// Error codes // Error codes
typedef enum WebPMuxError { typedef enum WEBP_NODISCARD WebPMuxError {
WEBP_MUX_OK = 1, WEBP_MUX_OK = 1,
WEBP_MUX_NOT_FOUND = 0, WEBP_MUX_NOT_FOUND = 0,
WEBP_MUX_INVALID_ARGUMENT = -1, WEBP_MUX_INVALID_ARGUMENT = -1,
@ -104,13 +105,13 @@ WEBP_EXTERN int WebPGetMuxVersion(void);
// Life of a Mux object // Life of a Mux object
// Internal, version-checked, entry point // Internal, version-checked, entry point
WEBP_EXTERN WebPMux* WebPNewInternal(int); WEBP_NODISCARD WEBP_EXTERN WebPMux* WebPNewInternal(int);
// Creates an empty mux object. // Creates an empty mux object.
// Returns: // Returns:
// A pointer to the newly created empty mux object. // A pointer to the newly created empty mux object.
// Or NULL in case of memory error. // Or NULL in case of memory error.
static WEBP_INLINE WebPMux* WebPMuxNew(void) { WEBP_NODISCARD static WEBP_INLINE WebPMux* WebPMuxNew(void) {
return WebPNewInternal(WEBP_MUX_ABI_VERSION); return WebPNewInternal(WEBP_MUX_ABI_VERSION);
} }
@ -123,18 +124,21 @@ WEBP_EXTERN void WebPMuxDelete(WebPMux* mux);
// Mux creation. // Mux creation.
// Internal, version-checked, entry point // Internal, version-checked, entry point
WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int, int); WEBP_NODISCARD WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int,
int);
// Creates a mux object from raw data given in WebP RIFF format. // Creates a mux object from raw data given in WebP RIFF format.
// Parameters: // Parameters:
// bitstream - (in) the bitstream data in WebP RIFF format // bitstream - (in) the bitstream data in WebP RIFF format
// copy_data - (in) value 1 indicates given data WILL be copied to the mux // copy_data - (in) value 1 indicates given data WILL be copied to the mux
// object and value 0 indicates data will NOT be copied. // object and value 0 indicates data will NOT be copied. If the
// data is not copied, it must exist for the lifetime of the
// mux object.
// Returns: // Returns:
// A pointer to the mux object created from given data - on success. // A pointer to the mux object created from given data - on success.
// NULL - In case of invalid data or memory error. // NULL - In case of invalid data or memory error.
static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream, WEBP_NODISCARD static WEBP_INLINE WebPMux* WebPMuxCreate(
int copy_data) { const WebPData* bitstream, int copy_data) {
return WebPMuxCreateInternal(bitstream, copy_data, WEBP_MUX_ABI_VERSION); return WebPMuxCreateInternal(bitstream, copy_data, WEBP_MUX_ABI_VERSION);
} }
@ -154,7 +158,9 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
// e.g., "ICCP", "XMP ", "EXIF" etc. // e.g., "ICCP", "XMP ", "EXIF" etc.
// chunk_data - (in) the chunk data to be added // chunk_data - (in) the chunk data to be added
// copy_data - (in) value 1 indicates given data WILL be copied to the mux // copy_data - (in) value 1 indicates given data WILL be copied to the mux
// object and value 0 indicates data will NOT be copied. // object and value 0 indicates data will NOT be copied. If the
// data is not copied, it must exist until a call to
// WebPMuxAssemble() is made.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL // WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL
// or if fourcc corresponds to an image chunk. // or if fourcc corresponds to an image chunk.
@ -217,7 +223,9 @@ struct WebPMuxFrameInfo {
// bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image // bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image
// WebP file (non-animated) // WebP file (non-animated)
// copy_data - (in) value 1 indicates given data WILL be copied to the mux // copy_data - (in) value 1 indicates given data WILL be copied to the mux
// object and value 0 indicates data will NOT be copied. // object and value 0 indicates data will NOT be copied. If the
// data is not copied, it must exist until a call to
// WebPMuxAssemble() is made.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL. // WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_MEMORY_ERROR - on memory allocation error.
@ -235,7 +243,9 @@ WEBP_EXTERN WebPMuxError WebPMuxSetImage(
// mux - (in/out) object to which the frame is to be added // mux - (in/out) object to which the frame is to be added
// frame - (in) frame data. // frame - (in) frame data.
// copy_data - (in) value 1 indicates given data WILL be copied to the mux // copy_data - (in) value 1 indicates given data WILL be copied to the mux
// object and value 0 indicates data will NOT be copied. // object and value 0 indicates data will NOT be copied. If the
// data is not copied, it must exist until a call to
// WebPMuxAssemble() is made.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL // WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL
// or if content of 'frame' is invalid. // or if content of 'frame' is invalid.
@ -449,7 +459,7 @@ WEBP_EXTERN int WebPAnimEncoderOptionsInitInternal(
// structure before modification. Returns false in case of version mismatch. // structure before modification. Returns false in case of version mismatch.
// WebPAnimEncoderOptionsInit() must have succeeded before using the // WebPAnimEncoderOptionsInit() must have succeeded before using the
// 'enc_options' object. // 'enc_options' object.
static WEBP_INLINE int WebPAnimEncoderOptionsInit( WEBP_NODISCARD static WEBP_INLINE int WebPAnimEncoderOptionsInit(
WebPAnimEncoderOptions* enc_options) { WebPAnimEncoderOptions* enc_options) {
return WebPAnimEncoderOptionsInitInternal(enc_options, WEBP_MUX_ABI_VERSION); return WebPAnimEncoderOptionsInitInternal(enc_options, WEBP_MUX_ABI_VERSION);
} }
@ -490,7 +500,7 @@ static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew(
// Returns: // Returns:
// On error, returns false and frame->error_code is set appropriately. // On error, returns false and frame->error_code is set appropriately.
// Otherwise, returns true. // Otherwise, returns true.
WEBP_EXTERN int WebPAnimEncoderAdd( WEBP_NODISCARD WEBP_EXTERN int WebPAnimEncoderAdd(
WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms, WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms,
const struct WebPConfig* config); const struct WebPConfig* config);
@ -503,8 +513,8 @@ WEBP_EXTERN int WebPAnimEncoderAdd(
// webp_data - (out) generated WebP bitstream. // webp_data - (out) generated WebP bitstream.
// Returns: // Returns:
// True on success. // True on success.
WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc, WEBP_NODISCARD WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
WebPData* webp_data); WebPData* webp_data);
// Get error string corresponding to the most recent call using 'enc'. The // Get error string corresponding to the most recent call using 'enc'. The
// returned string is owned by 'enc' and is valid only until the next call to // returned string is owned by 'enc' and is valid only until the next call to
@ -521,6 +531,57 @@ WEBP_EXTERN const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc);
// enc - (in/out) object to be deleted // enc - (in/out) object to be deleted
WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc); WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
//------------------------------------------------------------------------------
// Non-image chunks.
// Note: Only non-image related chunks should be managed through chunk APIs.
// (Image related chunks are: "ANMF", "VP8 ", "VP8L" and "ALPH").
// Adds a chunk with id 'fourcc' and data 'chunk_data' in the enc object.
// Any existing chunk(s) with the same id will be removed.
// Parameters:
// enc - (in/out) object to which the chunk is to be added
// fourcc - (in) a character array containing the fourcc of the given chunk;
// e.g., "ICCP", "XMP ", "EXIF", etc.
// chunk_data - (in) the chunk data to be added
// copy_data - (in) value 1 indicates given data WILL be copied to the enc
// object and value 0 indicates data will NOT be copied. If the
// data is not copied, it must exist until a call to
// WebPAnimEncoderAssemble() is made.
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if enc, fourcc or chunk_data is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
WEBP_EXTERN WebPMuxError WebPAnimEncoderSetChunk(
WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data,
int copy_data);
// Gets a reference to the data of the chunk with id 'fourcc' in the enc object.
// The caller should NOT free the returned data.
// Parameters:
// enc - (in) object from which the chunk data is to be fetched
// fourcc - (in) a character array containing the fourcc of the chunk;
// e.g., "ICCP", "XMP ", "EXIF", etc.
// chunk_data - (out) returned chunk data
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if enc, fourcc or chunk_data is NULL.
// WEBP_MUX_NOT_FOUND - If enc does not contain a chunk with the given id.
// WEBP_MUX_OK - on success.
WEBP_EXTERN WebPMuxError WebPAnimEncoderGetChunk(
const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data);
// Deletes the chunk with the given 'fourcc' from the enc object.
// Parameters:
// enc - (in/out) object from which the chunk is to be deleted
// fourcc - (in) a character array containing the fourcc of the chunk;
// e.g., "ICCP", "XMP ", "EXIF", etc.
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if enc or fourcc is NULL.
// WEBP_MUX_NOT_FOUND - If enc does not contain a chunk with the given fourcc.
// WEBP_MUX_OK - on success.
WEBP_EXTERN WebPMuxError WebPAnimEncoderDeleteChunk(
WebPAnimEncoder* enc, const char fourcc[4]);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -79,7 +79,8 @@ static WEBP_INLINE void WebPDataClear(WebPData* webp_data) {
// Allocates necessary storage for 'dst' and copies the contents of 'src'. // Allocates necessary storage for 'dst' and copies the contents of 'src'.
// Returns true on success. // Returns true on success.
static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) { WEBP_NODISCARD static WEBP_INLINE int WebPDataCopy(const WebPData* src,
WebPData* dst) {
if (src == NULL || dst == NULL) return 0; if (src == NULL || dst == NULL) return 0;
WebPDataInit(dst); WebPDataInit(dst);
if (src->bytes != NULL && src->size != 0) { if (src->bytes != NULL && src->size != 0) {

View File

@ -36,18 +36,39 @@ typedef long long int int64_t;
#define WEBP_INLINE __forceinline #define WEBP_INLINE __forceinline
#endif /* _MSC_VER */ #endif /* _MSC_VER */
#ifndef WEBP_NODISCARD
#if defined(WEBP_ENABLE_NODISCARD) && WEBP_ENABLE_NODISCARD
#if (defined(__cplusplus) && __cplusplus >= 201700L) || \
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
#define WEBP_NODISCARD [[nodiscard]]
#else
// gcc's __has_attribute does not work for enums.
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(warn_unused_result)
#define WEBP_NODISCARD __attribute__((warn_unused_result))
#else
#define WEBP_NODISCARD
#endif /* __has_attribute(warn_unused_result) */
#else
#define WEBP_NODISCARD
#endif /* defined(__clang__) && defined(__has_attribute) */
#endif /* (defined(__cplusplus) && __cplusplus >= 201700L) ||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) */
#else
#define WEBP_NODISCARD
#endif /* defined(WEBP_ENABLE_NODISCARD) && WEBP_ENABLE_NODISCARD */
#endif /* WEBP_NODISCARD */
#ifndef WEBP_EXTERN #ifndef WEBP_EXTERN
// This explicitly marks library functions and allows for changing the // This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds. // signature for e.g., Windows DLL builds.
# if defined(__GNUC__) && __GNUC__ >= 4 # if defined(_WIN32) && defined(WEBP_DLL)
# define WEBP_EXTERN __declspec(dllexport)
# elif defined(__GNUC__) && __GNUC__ >= 4
# define WEBP_EXTERN extern __attribute__ ((visibility ("default"))) # define WEBP_EXTERN extern __attribute__ ((visibility ("default")))
# else # else
# if defined(_MSC_VER) && defined(WEBP_DLL) # define WEBP_EXTERN extern
# define WEBP_EXTERN __declspec(dllexport) # endif /* defined(_WIN32) && defined(WEBP_DLL) */
# else
# define WEBP_EXTERN extern
# endif
# endif /* __GNUC__ >= 4 */
#endif /* WEBP_EXTERN */ #endif /* WEBP_EXTERN */
// Macro to check ABI compatibility (same major revision number) // Macro to check ABI compatibility (same major revision number)
@ -60,7 +81,7 @@ extern "C" {
// Allocates 'size' bytes of memory. Returns NULL upon error. Memory // Allocates 'size' bytes of memory. Returns NULL upon error. Memory
// must be deallocated by calling WebPFree(). This function is made available // must be deallocated by calling WebPFree(). This function is made available
// by the core 'libwebp' library. // by the core 'libwebp' library.
WEBP_EXTERN void* WebPMalloc(size_t size); WEBP_NODISCARD WEBP_EXTERN void* WebPMalloc(size_t size);
// Releases memory returned by the WebPDecode*() functions (from decode.h). // Releases memory returned by the WebPDecode*() functions (from decode.h).
WEBP_EXTERN void WebPFree(void* ptr); WEBP_EXTERN void WebPFree(void* ptr);