diff --git a/media/libwebp/AUTHORS b/media/libwebp/AUTHORS --- a/media/libwebp/AUTHORS +++ b/media/libwebp/AUTHORS @@ -8,13 +8,15 @@ - Charles Munger (clm at google dot com) - Cheng Yi (cyi at google dot com) - Christian Duvivier (cduvivier at google dot com) - Christopher Degawa (ccom at randomderp dot com) - Clement Courbet (courbet at google dot com) +- devtools-clrobot at google dot com (devtools-clrobot@google dot com) - Djordje Pesut (djordje dot pesut at imgtec dot com) - Frank (1433351828 at qq dot com) - Frank Barchard (fbarchard at google dot com) +- Henner Zeller (hzeller at google dot com) - Hui Su (huisu at google dot com) - H. Vetinari (h dot vetinari at gmx dot com) - Ilya Kurdyukov (jpegqs at gmail dot com) - Ingvar Stepanyan (rreverser at google dot com) - Istvan Stefan (Istvan dot Stefan at arm dot com) diff --git a/media/libwebp/NEWS b/media/libwebp/NEWS --- a/media/libwebp/NEWS +++ b/media/libwebp/NEWS @@ -1,5 +1,18 @@ +- 6/30/2025 version 1.6.0 + This is a binary compatible release. + API changes: + - libwebp: WebPValidateDecoderConfig + * additional x86 (AVX2, SSE2), general optimizations and compression + improvements for lossless + * `-mt` returns same results as single-threaded lossless (regressed in + 1.5.0, #426506716) + * miscellaneous warning, bug & build fixes (#393104377, #397130631, + #398288323, #398066379, #427503509) + Tool updates: + * cwebp can restrict the use of `-resize` with `-resize_mode` (#405437935) + - 12/19/2024 version 1.5.0 This is a binary compatible release. API changes: - `cross_color_transform_bits` added to WebPAuxStats * minor lossless encoder speed and compression improvements diff --git a/media/libwebp/README.md b/media/libwebp/README.md --- a/media/libwebp/README.md +++ b/media/libwebp/README.md @@ -5,11 +5,11 @@ / \\/ \/ _ \/ _ )/ _ \ \ / __/ _ \ __/ \__\__/\____/\_____/__/ ____ ___ / _/ / \ \ / _ \/ _/ / \_/ / / \ \ __/ \__ - \____/____/\_____/_____/____/v1.5.0 + \____/____/\_____/_____/____/v1.6.0 ``` WebP codec is a library to encode and decode images in WebP format. This package contains the library that can be used in other programs to add WebP support, as well as the command line tools 'cwebp' and 'dwebp' to compress and decompress diff --git a/media/libwebp/moz.yaml b/media/libwebp/moz.yaml --- a/media/libwebp/moz.yaml +++ b/media/libwebp/moz.yaml @@ -9,11 +9,11 @@ description: "WebP codec library" url: "https://chromium.googlesource.com/webm/libwebp" license: BSD-3-Clause - release: v1.5.0 (2024-12-19T17:17:50-08:00). + release: v1.6.0 (2025-07-07T17:20:00-07:00). revision: "v1.3.0" license-file: COPYING diff --git a/media/libwebp/sharpyuv/sharpyuv.h b/media/libwebp/sharpyuv/sharpyuv.h --- a/media/libwebp/sharpyuv/sharpyuv.h +++ b/media/libwebp/sharpyuv/sharpyuv.h @@ -50,11 +50,11 @@ #endif /* SHARPYUV_INLINE */ // SharpYUV API version following the convention from semver.org #define SHARPYUV_VERSION_MAJOR 0 #define SHARPYUV_VERSION_MINOR 4 -#define SHARPYUV_VERSION_PATCH 1 +#define SHARPYUV_VERSION_PATCH 2 // Version as a uint32_t. The major number is the high 8 bits. // The minor number is the middle 8 bits. The patch number is the low 16 bits. #define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \ (((MAJOR) << 24) | ((MINOR) << 16) | (PATCH)) #define SHARPYUV_VERSION \ diff --git a/media/libwebp/sharpyuv/sharpyuv.c b/media/libwebp/sharpyuv/sharpyuv.c --- a/media/libwebp/sharpyuv/sharpyuv.c +++ b/media/libwebp/sharpyuv/sharpyuv.c @@ -17,14 +17,14 @@ #include #include #include #include -#include "src/webp/types.h" #include "sharpyuv/sharpyuv_cpu.h" #include "sharpyuv/sharpyuv_dsp.h" #include "sharpyuv/sharpyuv_gamma.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ int SharpYuvGetVersion(void) { return SHARPYUV_VERSION; diff --git a/media/libwebp/sharpyuv/sharpyuv_csp.c b/media/libwebp/sharpyuv/sharpyuv_csp.c --- a/media/libwebp/sharpyuv/sharpyuv_csp.c +++ b/media/libwebp/sharpyuv/sharpyuv_csp.c @@ -13,10 +13,12 @@ #include #include #include +#include "sharpyuv/sharpyuv.h" + static int ToFixed16(float f) { return (int)floor(f * (1 << 16) + 0.5f); } void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space, SharpYuvConversionMatrix* matrix) { const float kr = yuv_color_space->kr; diff --git a/media/libwebp/sharpyuv/sharpyuv_dsp.c b/media/libwebp/sharpyuv/sharpyuv_dsp.c --- a/media/libwebp/sharpyuv/sharpyuv_dsp.c +++ b/media/libwebp/sharpyuv/sharpyuv_dsp.c @@ -15,10 +15,11 @@ #include #include #include "sharpyuv/sharpyuv_cpu.h" +#include "src/dsp/cpu.h" #include "src/webp/types.h" //----------------------------------------------------------------------------- #if !WEBP_NEON_OMIT_C_CODE diff --git a/media/libwebp/sharpyuv/sharpyuv_gamma.c b/media/libwebp/sharpyuv/sharpyuv_gamma.c --- a/media/libwebp/sharpyuv/sharpyuv_gamma.c +++ b/media/libwebp/sharpyuv/sharpyuv_gamma.c @@ -13,10 +13,11 @@ #include #include #include +#include "sharpyuv/sharpyuv.h" #include "src/webp/types.h" // Gamma correction compensates loss of resolution during chroma subsampling. // Size of pre-computed table for converting from gamma to linear. #define GAMMA_TO_LINEAR_TAB_BITS 10 diff --git a/media/libwebp/sharpyuv/sharpyuv_sse2.c b/media/libwebp/sharpyuv/sharpyuv_sse2.c --- a/media/libwebp/sharpyuv/sharpyuv_sse2.c +++ b/media/libwebp/sharpyuv/sharpyuv_sse2.c @@ -12,12 +12,16 @@ // Author: Skal (pascal.massimino@gmail.com) #include "sharpyuv/sharpyuv_dsp.h" #if defined(WEBP_USE_SSE2) +#include + #include -#include + +#include "src/dsp/cpu.h" +#include "src/webp/types.h" static uint16_t clip_SSE2(int v, int max) { return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; } diff --git a/media/libwebp/src/dec/alpha_dec.c b/media/libwebp/src/dec/alpha_dec.c --- a/media/libwebp/src/dec/alpha_dec.c +++ b/media/libwebp/src/dec/alpha_dec.c @@ -9,18 +9,22 @@ // // Alpha-plane decompression. // // Author: Skal (pascal.massimino@gmail.com) +#include #include + #include "src/dec/alphai_dec.h" #include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" #include "src/dsp/dsp.h" #include "src/utils/quant_levels_dec_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" #include "src/webp/format_constants.h" #include "src/webp/types.h" //------------------------------------------------------------------------------ // ALPHDecoder object. @@ -32,12 +36,12 @@ } // Clears and deallocates an alpha decoder instance. static void ALPHDelete(ALPHDecoder* const dec) { if (dec != NULL) { - VP8LDelete(dec->vp8l_dec_); - dec->vp8l_dec_ = NULL; + VP8LDelete(dec->vp8l_dec); + dec->vp8l_dec = NULL; WebPSafeFree(dec); } } //------------------------------------------------------------------------------ @@ -52,32 +56,32 @@ uint8_t* output) { int ok = 0; const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN; const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN; int rsrv; - VP8Io* const io = &dec->io_; + VP8Io* const io = &dec->io; assert(data != NULL && output != NULL && src_io != NULL); VP8FiltersInit(); - dec->output_ = output; - dec->width_ = src_io->width; - dec->height_ = src_io->height; - assert(dec->width_ > 0 && dec->height_ > 0); + dec->output = output; + dec->width = src_io->width; + dec->height = src_io->height; + assert(dec->width > 0 && dec->height > 0); if (data_size <= ALPHA_HEADER_LEN) { return 0; } - dec->method_ = (data[0] >> 0) & 0x03; - dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03); - dec->pre_processing_ = (data[0] >> 4) & 0x03; + dec->method = (data[0] >> 0) & 0x03; + dec->filter = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03); + dec->pre_processing = (data[0] >> 4) & 0x03; rsrv = (data[0] >> 6) & 0x03; - if (dec->method_ < ALPHA_NO_COMPRESSION || - dec->method_ > ALPHA_LOSSLESS_COMPRESSION || - dec->filter_ >= WEBP_FILTER_LAST || - dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS || + if (dec->method < ALPHA_NO_COMPRESSION || + dec->method > ALPHA_LOSSLESS_COMPRESSION || + dec->filter >= WEBP_FILTER_LAST || + dec->pre_processing > ALPHA_PREPROCESSED_LEVELS || rsrv != 0) { return 0; } // Copy the necessary parameters from src_io to io @@ -94,15 +98,15 @@ io->crop_right = src_io->crop_right; io->crop_top = src_io->crop_top; io->crop_bottom = src_io->crop_bottom; // No need to copy the scaling parameters. - if (dec->method_ == ALPHA_NO_COMPRESSION) { - const size_t alpha_decoded_size = dec->width_ * dec->height_; + if (dec->method == ALPHA_NO_COMPRESSION) { + const size_t alpha_decoded_size = dec->width * dec->height; ok = (alpha_data_size >= alpha_decoded_size); } else { - assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION); + assert(dec->method == ALPHA_LOSSLESS_COMPRESSION); ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size); } return ok; } @@ -111,64 +115,64 @@ // starting from row number 'row'. It assumes that rows up to (row - 1) have // already been decoded. // Returns false in case of bitstream error. WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) { - ALPHDecoder* const alph_dec = dec->alph_dec_; - const int width = alph_dec->width_; - const int height = alph_dec->io_.crop_bottom; - if (alph_dec->method_ == ALPHA_NO_COMPRESSION) { + ALPHDecoder* const alph_dec = dec->alph_dec; + const int width = alph_dec->width; + const int height = alph_dec->io.crop_bottom; + if (alph_dec->method == ALPHA_NO_COMPRESSION) { int y; - const uint8_t* prev_line = dec->alpha_prev_line_; - const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width; - uint8_t* dst = dec->alpha_plane_ + row * width; - assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]); - assert(WebPUnfilters[alph_dec->filter_] != NULL); + const uint8_t* prev_line = dec->alpha_prev_line; + const uint8_t* deltas = dec->alpha_data + ALPHA_HEADER_LEN + row * width; + uint8_t* dst = dec->alpha_plane + row * width; + assert(deltas <= &dec->alpha_data[dec->alpha_data_size]); + assert(WebPUnfilters[alph_dec->filter] != NULL); for (y = 0; y < num_rows; ++y) { - WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width); + WebPUnfilters[alph_dec->filter](prev_line, deltas, dst, width); prev_line = dst; dst += width; deltas += width; } - dec->alpha_prev_line_ = prev_line; - } else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION - assert(alph_dec->vp8l_dec_ != NULL); + dec->alpha_prev_line = prev_line; + } else { // alph_dec->method == ALPHA_LOSSLESS_COMPRESSION + assert(alph_dec->vp8l_dec != NULL); if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) { return 0; } } if (row + num_rows >= height) { - dec->is_alpha_decoded_ = 1; + dec->is_alpha_decoded = 1; } return 1; } WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) { const int stride = io->width; const int height = io->crop_bottom; const uint64_t alpha_size = (uint64_t)stride * height; - assert(dec->alpha_plane_mem_ == NULL); - dec->alpha_plane_mem_ = - (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_)); - if (dec->alpha_plane_mem_ == NULL) { + assert(dec->alpha_plane_mem == NULL); + dec->alpha_plane_mem = + (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane)); + if (dec->alpha_plane_mem == NULL) { return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "Alpha decoder initialization failed."); } - dec->alpha_plane_ = dec->alpha_plane_mem_; - dec->alpha_prev_line_ = NULL; + dec->alpha_plane = dec->alpha_plane_mem; + dec->alpha_prev_line = NULL; return 1; } void WebPDeallocateAlphaMemory(VP8Decoder* const dec) { assert(dec != NULL); - WebPSafeFree(dec->alpha_plane_mem_); - dec->alpha_plane_mem_ = NULL; - dec->alpha_plane_ = NULL; - ALPHDelete(dec->alph_dec_); - dec->alph_dec_ = NULL; + WebPSafeFree(dec->alpha_plane_mem); + dec->alpha_plane_mem = NULL; + dec->alpha_plane = NULL; + ALPHDelete(dec->alph_dec); + dec->alph_dec = NULL; } //------------------------------------------------------------------------------ // Main entry point. @@ -182,58 +186,58 @@ if (row < 0 || num_rows <= 0 || row + num_rows > height) { return NULL; } - if (!dec->is_alpha_decoded_) { - if (dec->alph_dec_ == NULL) { // Initialize decoder. - dec->alph_dec_ = ALPHNew(); - if (dec->alph_dec_ == NULL) { + if (!dec->is_alpha_decoded) { + if (dec->alph_dec == NULL) { // Initialize decoder. + dec->alph_dec = ALPHNew(); + if (dec->alph_dec == NULL) { VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "Alpha decoder initialization failed."); return NULL; } if (!AllocateAlphaPlane(dec, io)) goto Error; - if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_, - io, dec->alpha_plane_)) { - VP8LDecoder* const vp8l_dec = dec->alph_dec_->vp8l_dec_; + if (!ALPHInit(dec->alph_dec, dec->alpha_data, dec->alpha_data_size, + io, dec->alpha_plane)) { + VP8LDecoder* const vp8l_dec = dec->alph_dec->vp8l_dec; VP8SetError(dec, (vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY - : vp8l_dec->status_, + : vp8l_dec->status, "Alpha decoder initialization failed."); goto Error; } // if we allowed use of alpha dithering, check whether it's needed at all - if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) { - dec->alpha_dithering_ = 0; // disable dithering + if (dec->alph_dec->pre_processing != ALPHA_PREPROCESSED_LEVELS) { + dec->alpha_dithering = 0; // disable dithering } else { num_rows = height - row; // decode everything in one pass } } - assert(dec->alph_dec_ != NULL); + assert(dec->alph_dec != NULL); assert(row + num_rows <= height); if (!ALPHDecode(dec, row, num_rows)) goto Error; - if (dec->is_alpha_decoded_) { // finished? - ALPHDelete(dec->alph_dec_); - dec->alph_dec_ = NULL; - if (dec->alpha_dithering_ > 0) { - uint8_t* const alpha = dec->alpha_plane_ + io->crop_top * width + if (dec->is_alpha_decoded) { // finished? + ALPHDelete(dec->alph_dec); + dec->alph_dec = NULL; + if (dec->alpha_dithering > 0) { + uint8_t* const alpha = dec->alpha_plane + io->crop_top * width + io->crop_left; if (!WebPDequantizeLevels(alpha, io->crop_right - io->crop_left, io->crop_bottom - io->crop_top, - width, dec->alpha_dithering_)) { + width, dec->alpha_dithering)) { goto Error; } } } } // Return a pointer to the current decoded row. - return dec->alpha_plane_ + row * width; + return dec->alpha_plane + row * width; Error: WebPDeallocateAlphaMemory(dec); return NULL; } diff --git a/media/libwebp/src/dec/alphai_dec.h b/media/libwebp/src/dec/alphai_dec.h --- a/media/libwebp/src/dec/alphai_dec.h +++ b/media/libwebp/src/dec/alphai_dec.h @@ -12,39 +12,42 @@ // Author: Urvang (urvang@google.com) #ifndef WEBP_DEC_ALPHAI_DEC_H_ #define WEBP_DEC_ALPHAI_DEC_H_ +#include "src/dec/vp8_dec.h" +#include "src/webp/types.h" #include "src/dec/webpi_dec.h" +#include "src/dsp/dsp.h" #include "src/utils/filters_utils.h" #ifdef __cplusplus extern "C" { #endif struct VP8LDecoder; // Defined in dec/vp8li.h. typedef struct ALPHDecoder ALPHDecoder; struct ALPHDecoder { - int width_; - int height_; - int method_; - WEBP_FILTER_TYPE filter_; - int pre_processing_; - struct VP8LDecoder* vp8l_dec_; - VP8Io io_; - int use_8b_decode_; // Although alpha channel requires only 1 byte per + int width; + int height; + int method; + WEBP_FILTER_TYPE filter; + int pre_processing; + struct VP8LDecoder* vp8l_dec; + VP8Io io; + int use_8b_decode; // Although alpha channel requires only 1 byte per // pixel, sometimes VP8LDecoder may need to allocate // 4 bytes per pixel internally during decode. - uint8_t* output_; - const uint8_t* prev_line_; // last output row (or NULL) + uint8_t* output; + const uint8_t* prev_line; // last output row (or NULL) }; //------------------------------------------------------------------------------ // internal functions. Not public. -// Deallocate memory associated to dec->alpha_plane_ decoding +// Deallocate memory associated to dec->alpha_plane decoding void WebPDeallocateAlphaMemory(VP8Decoder* const dec); //------------------------------------------------------------------------------ #ifdef __cplusplus diff --git a/media/libwebp/src/dec/buffer_dec.c b/media/libwebp/src/dec/buffer_dec.c --- a/media/libwebp/src/dec/buffer_dec.c +++ b/media/libwebp/src/dec/buffer_dec.c @@ -9,29 +9,33 @@ // // Everything about WebPDecBuffer // // Author: Skal (pascal.massimino@gmail.com) +#include #include +#include #include "src/dec/vp8i_dec.h" #include "src/dec/webpi_dec.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // WebPDecBuffer // Number of bytes per pixel for the different color-spaces. static const uint8_t kModeBpp[MODE_LAST] = { 3, 4, 3, 4, 4, 2, 2, 4, 4, 4, 2, // pre-multiplied modes 1, 1 }; -// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE. // Convert to an integer to handle both the unsigned/signed enum cases // without the need for casting to remove type limit warnings. -static int IsValidColorspace(int webp_csp_mode) { +int IsValidColorspace(int webp_csp_mode) { return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST); } // strictly speaking, the very last (or first, if flipped) row // doesn't require padding. diff --git a/media/libwebp/src/dec/common_dec.h b/media/libwebp/src/dec/common_dec.h --- a/media/libwebp/src/dec/common_dec.h +++ b/media/libwebp/src/dec/common_dec.h @@ -49,6 +49,9 @@ NUM_BANDS = 8, NUM_CTX = 3, NUM_PROBAS = 11 }; +// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE. +int IsValidColorspace(int webp_csp_mode); + #endif // WEBP_DEC_COMMON_DEC_H_ diff --git a/media/libwebp/src/dec/frame_dec.c b/media/libwebp/src/dec/frame_dec.c --- a/media/libwebp/src/dec/frame_dec.c +++ b/media/libwebp/src/dec/frame_dec.c @@ -9,13 +9,24 @@ // // Frame-reconstruction function. Memory allocation. // // Author: Skal (pascal.massimino@gmail.com) +#include #include +#include + +#include "src/dec/common_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/dsp/dsp.h" +#include "src/utils/random_utils.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Main reconstruction function. static const uint16_t kScan[16] = { @@ -70,15 +81,15 @@ static void ReconstructRow(const VP8Decoder* const dec, const VP8ThreadContext* ctx) { int j; int mb_x; - const int mb_y = ctx->mb_y_; - const int cache_id = ctx->id_; - uint8_t* const y_dst = dec->yuv_b_ + Y_OFF; - uint8_t* const u_dst = dec->yuv_b_ + U_OFF; - uint8_t* const v_dst = dec->yuv_b_ + V_OFF; + const int mb_y = ctx->mb_y; + const int cache_id = ctx->id; + uint8_t* const y_dst = dec->yuv_b + Y_OFF; + uint8_t* const u_dst = dec->yuv_b + U_OFF; + uint8_t* const v_dst = dec->yuv_b + V_OFF; // Initialize left-most block. for (j = 0; j < 16; ++j) { y_dst[j * BPS - 1] = 129; } @@ -97,12 +108,12 @@ memset(u_dst - BPS - 1, 127, 8 + 1); memset(v_dst - BPS - 1, 127, 8 + 1); } // Reconstruct one row. - for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) { - const VP8MBData* const block = ctx->mb_data_ + mb_x; + for (mb_x = 0; mb_x < dec->mb_w; ++mb_x) { + const VP8MBData* const block = ctx->mb_data + mb_x; // Rotate in the left samples from previously decoded block. We move four // pixels at a time for alignment reason, and because of in-loop filter. if (mb_x > 0) { for (j = -1; j < 16; ++j) { @@ -113,27 +124,27 @@ Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]); } } { // bring top samples into the cache - VP8TopSamples* const top_yuv = dec->yuv_t_ + mb_x; - const int16_t* const coeffs = block->coeffs_; - uint32_t bits = block->non_zero_y_; + VP8TopSamples* const top_yuv = dec->yuv_t + mb_x; + const int16_t* const coeffs = block->coeffs; + uint32_t bits = block->non_zero_y; int n; if (mb_y > 0) { memcpy(y_dst - BPS, top_yuv[0].y, 16); memcpy(u_dst - BPS, top_yuv[0].u, 8); memcpy(v_dst - BPS, top_yuv[0].v, 8); } // predict and add residuals - if (block->is_i4x4_) { // 4x4 + if (block->is_i4x4) { // 4x4 uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16); if (mb_y > 0) { - if (mb_x >= dec->mb_w_ - 1) { // on rightmost border + if (mb_x >= dec->mb_w - 1) { // on rightmost border memset(top_right, top_yuv[0].y[15], sizeof(*top_right)); } else { memcpy(top_right, top_yuv[1].y, sizeof(*top_right)); } } @@ -141,52 +152,52 @@ top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0]; // predict and add residuals for all 4x4 blocks in turn. for (n = 0; n < 16; ++n, bits <<= 2) { uint8_t* const dst = y_dst + kScan[n]; - VP8PredLuma4[block->imodes_[n]](dst); + VP8PredLuma4[block->imodes[n]](dst); DoTransform(bits, coeffs + n * 16, dst); } } else { // 16x16 - const int pred_func = CheckMode(mb_x, mb_y, block->imodes_[0]); + const int pred_func = CheckMode(mb_x, mb_y, block->imodes[0]); VP8PredLuma16[pred_func](y_dst); if (bits != 0) { for (n = 0; n < 16; ++n, bits <<= 2) { DoTransform(bits, coeffs + n * 16, y_dst + kScan[n]); } } } { // Chroma - const uint32_t bits_uv = block->non_zero_uv_; - const int pred_func = CheckMode(mb_x, mb_y, block->uvmode_); + const uint32_t bits_uv = block->non_zero_uv; + const int pred_func = CheckMode(mb_x, mb_y, block->uvmode); VP8PredChroma8[pred_func](u_dst); VP8PredChroma8[pred_func](v_dst); DoUVTransform(bits_uv >> 0, coeffs + 16 * 16, u_dst); DoUVTransform(bits_uv >> 8, coeffs + 20 * 16, v_dst); } // stash away top samples for next block - if (mb_y < dec->mb_h_ - 1) { + if (mb_y < dec->mb_h - 1) { memcpy(top_yuv[0].y, y_dst + 15 * BPS, 16); memcpy(top_yuv[0].u, u_dst + 7 * BPS, 8); memcpy(top_yuv[0].v, v_dst + 7 * BPS, 8); } } - // Transfer reconstructed samples from yuv_b_ cache to final destination. + // Transfer reconstructed samples from yuv_b cache to final destination. { - const int y_offset = cache_id * 16 * dec->cache_y_stride_; - const int uv_offset = cache_id * 8 * dec->cache_uv_stride_; - uint8_t* const y_out = dec->cache_y_ + mb_x * 16 + y_offset; - uint8_t* const u_out = dec->cache_u_ + mb_x * 8 + uv_offset; - uint8_t* const v_out = dec->cache_v_ + mb_x * 8 + uv_offset; + const int y_offset = cache_id * 16 * dec->cache_y_stride; + const int uv_offset = cache_id * 8 * dec->cache_uv_stride; + uint8_t* const y_out = dec->cache_y + mb_x * 16 + y_offset; + uint8_t* const u_out = dec->cache_u + mb_x * 8 + uv_offset; + uint8_t* const v_out = dec->cache_v + mb_x * 8 + uv_offset; for (j = 0; j < 16; ++j) { - memcpy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16); + memcpy(y_out + j * dec->cache_y_stride, y_dst + j * BPS, 16); } for (j = 0; j < 8; ++j) { - memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8); - memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8); + memcpy(u_out + j * dec->cache_uv_stride, u_dst + j * BPS, 8); + memcpy(v_out + j * dec->cache_uv_stride, v_dst + j * BPS, 8); } } } } @@ -199,117 +210,117 @@ // Complex filter: up to 4 luma samples are read and 3 are written. Same for // U/V, so it's 8 samples total (because of the 2x upsampling). static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 }; static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) { - const VP8ThreadContext* const ctx = &dec->thread_ctx_; - const int cache_id = ctx->id_; - const int y_bps = dec->cache_y_stride_; - const VP8FInfo* const f_info = ctx->f_info_ + mb_x; - uint8_t* const y_dst = dec->cache_y_ + cache_id * 16 * y_bps + mb_x * 16; - const int ilevel = f_info->f_ilevel_; - const int limit = f_info->f_limit_; + const VP8ThreadContext* const ctx = &dec->thread_ctx; + const int cache_id = ctx->id; + const int y_bps = dec->cache_y_stride; + const VP8FInfo* const f_info = ctx->f_info + mb_x; + uint8_t* const y_dst = dec->cache_y + cache_id * 16 * y_bps + mb_x * 16; + const int ilevel = f_info->f_ilevel; + const int limit = f_info->f_limit; if (limit == 0) { return; } assert(limit >= 3); - if (dec->filter_type_ == 1) { // simple + if (dec->filter_type == 1) { // simple if (mb_x > 0) { VP8SimpleHFilter16(y_dst, y_bps, limit + 4); } - if (f_info->f_inner_) { + if (f_info->f_inner) { VP8SimpleHFilter16i(y_dst, y_bps, limit); } if (mb_y > 0) { VP8SimpleVFilter16(y_dst, y_bps, limit + 4); } - if (f_info->f_inner_) { + if (f_info->f_inner) { VP8SimpleVFilter16i(y_dst, y_bps, limit); } } else { // complex - const int uv_bps = dec->cache_uv_stride_; - uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8; - uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8; - const int hev_thresh = f_info->hev_thresh_; + const int uv_bps = dec->cache_uv_stride; + uint8_t* const u_dst = dec->cache_u + cache_id * 8 * uv_bps + mb_x * 8; + uint8_t* const v_dst = dec->cache_v + cache_id * 8 * uv_bps + mb_x * 8; + const int hev_thresh = f_info->hev_thresh; if (mb_x > 0) { VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh); VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh); } - if (f_info->f_inner_) { + if (f_info->f_inner) { VP8HFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh); VP8HFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh); } if (mb_y > 0) { VP8VFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh); VP8VFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh); } - if (f_info->f_inner_) { + if (f_info->f_inner) { VP8VFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh); VP8VFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh); } } } // Filter the decoded macroblock row (if needed) static void FilterRow(const VP8Decoder* const dec) { int mb_x; - const int mb_y = dec->thread_ctx_.mb_y_; - assert(dec->thread_ctx_.filter_row_); - for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { + const int mb_y = dec->thread_ctx.mb_y; + assert(dec->thread_ctx.filter_row); + for (mb_x = dec->tl_mb_x; mb_x < dec->br_mb_x; ++mb_x) { DoFilter(dec, mb_x, mb_y); } } //------------------------------------------------------------------------------ // Precompute the filtering strength for each segment and each i4x4/i16x16 mode. static void PrecomputeFilterStrengths(VP8Decoder* const dec) { - if (dec->filter_type_ > 0) { + if (dec->filter_type > 0) { int s; - const VP8FilterHeader* const hdr = &dec->filter_hdr_; + const VP8FilterHeader* const hdr = &dec->filter_hdr; for (s = 0; s < NUM_MB_SEGMENTS; ++s) { int i4x4; // First, compute the initial level int base_level; - if (dec->segment_hdr_.use_segment_) { - base_level = dec->segment_hdr_.filter_strength_[s]; - if (!dec->segment_hdr_.absolute_delta_) { - base_level += hdr->level_; + if (dec->segment_hdr.use_segment) { + base_level = dec->segment_hdr.filter_strength[s]; + if (!dec->segment_hdr.absolute_delta) { + base_level += hdr->level; } } else { - base_level = hdr->level_; + base_level = hdr->level; } for (i4x4 = 0; i4x4 <= 1; ++i4x4) { - VP8FInfo* const info = &dec->fstrengths_[s][i4x4]; + VP8FInfo* const info = &dec->fstrengths[s][i4x4]; int level = base_level; - if (hdr->use_lf_delta_) { - level += hdr->ref_lf_delta_[0]; + if (hdr->use_lf_delta) { + level += hdr->ref_lf_delta[0]; if (i4x4) { - level += hdr->mode_lf_delta_[0]; + level += hdr->mode_lf_delta[0]; } } level = (level < 0) ? 0 : (level > 63) ? 63 : level; if (level > 0) { int ilevel = level; - if (hdr->sharpness_ > 0) { - if (hdr->sharpness_ > 4) { + if (hdr->sharpness > 0) { + if (hdr->sharpness > 4) { ilevel >>= 2; } else { ilevel >>= 1; } - if (ilevel > 9 - hdr->sharpness_) { - ilevel = 9 - hdr->sharpness_; + if (ilevel > 9 - hdr->sharpness) { + ilevel = 9 - hdr->sharpness; } } if (ilevel < 1) ilevel = 1; - info->f_ilevel_ = ilevel; - info->f_limit_ = 2 * level + ilevel; - info->hev_thresh_ = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; + info->f_ilevel = ilevel; + info->f_limit = 2 * level + ilevel; + info->hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; } else { - info->f_limit_ = 0; // no filtering + info->f_limit = 0; // no filtering } - info->f_inner_ = i4x4; + info->f_inner = i4x4; } } } } @@ -319,11 +330,11 @@ // minimal amp that will provide a non-zero dithering effect #define MIN_DITHER_AMP 4 #define DITHER_AMP_TAB_SIZE 12 static const uint8_t kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = { - // roughly, it's dqm->uv_mat_[1] + // roughly, it's dqm->uv_mat[1] 8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1 }; void VP8InitDithering(const WebPDecoderOptions* const options, VP8Decoder* const dec) { @@ -334,28 +345,28 @@ const int f = (d < 0) ? 0 : (d > 100) ? max_amp : (d * max_amp / 100); if (f > 0) { int s; int all_amp = 0; for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - VP8QuantMatrix* const dqm = &dec->dqm_[s]; - if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) { - const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_; - dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3; + VP8QuantMatrix* const dqm = &dec->dqm[s]; + if (dqm->uv_quant < DITHER_AMP_TAB_SIZE) { + const int idx = (dqm->uv_quant < 0) ? 0 : dqm->uv_quant; + dqm->dither = (f * kQuantToDitherAmp[idx]) >> 3; } - all_amp |= dqm->dither_; + all_amp |= dqm->dither; } if (all_amp != 0) { - VP8InitRandom(&dec->dithering_rg_, 1.0f); - dec->dither_ = 1; + VP8InitRandom(&dec->dithering_rg, 1.0f); + dec->dither = 1; } } // potentially allow alpha dithering - dec->alpha_dithering_ = options->alpha_dithering_strength; - if (dec->alpha_dithering_ > 100) { - dec->alpha_dithering_ = 100; - } else if (dec->alpha_dithering_ < 0) { - dec->alpha_dithering_ = 0; + dec->alpha_dithering = options->alpha_dithering_strength; + if (dec->alpha_dithering > 100) { + dec->alpha_dithering = 100; + } else if (dec->alpha_dithering < 0) { + dec->alpha_dithering = 0; } } } // Convert to range: [-2,2] for dither=50, [-4,4] for dither=100 @@ -368,21 +379,21 @@ VP8DitherCombine8x8(dither, dst, bps); } static void DitherRow(VP8Decoder* const dec) { int mb_x; - assert(dec->dither_); - for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { - const VP8ThreadContext* const ctx = &dec->thread_ctx_; - const VP8MBData* const data = ctx->mb_data_ + mb_x; - const int cache_id = ctx->id_; - const int uv_bps = dec->cache_uv_stride_; - if (data->dither_ >= MIN_DITHER_AMP) { - uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8; - uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8; - Dither8x8(&dec->dithering_rg_, u_dst, uv_bps, data->dither_); - Dither8x8(&dec->dithering_rg_, v_dst, uv_bps, data->dither_); + assert(dec->dither); + for (mb_x = dec->tl_mb_x; mb_x < dec->br_mb_x; ++mb_x) { + const VP8ThreadContext* const ctx = &dec->thread_ctx; + const VP8MBData* const data = ctx->mb_data + mb_x; + const int cache_id = ctx->id; + const int uv_bps = dec->cache_uv_stride; + if (data->dither >= MIN_DITHER_AMP) { + uint8_t* const u_dst = dec->cache_u + cache_id * 8 * uv_bps + mb_x * 8; + uint8_t* const v_dst = dec->cache_v + cache_id * 8 * uv_bps + mb_x * 8; + Dither8x8(&dec->dithering_rg, u_dst, uv_bps, data->dither); + Dither8x8(&dec->dithering_rg, v_dst, uv_bps, data->dither); } } } //------------------------------------------------------------------------------ @@ -401,33 +412,33 @@ // Finalize and transmit a complete row. Return false in case of user-abort. static int FinishRow(void* arg1, void* arg2) { VP8Decoder* const dec = (VP8Decoder*)arg1; VP8Io* const io = (VP8Io*)arg2; int ok = 1; - const VP8ThreadContext* const ctx = &dec->thread_ctx_; - const int cache_id = ctx->id_; - const int extra_y_rows = kFilterExtraRows[dec->filter_type_]; - const int ysize = extra_y_rows * dec->cache_y_stride_; - const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_; - const int y_offset = cache_id * 16 * dec->cache_y_stride_; - const int uv_offset = cache_id * 8 * dec->cache_uv_stride_; - uint8_t* const ydst = dec->cache_y_ - ysize + y_offset; - uint8_t* const udst = dec->cache_u_ - uvsize + uv_offset; - uint8_t* const vdst = dec->cache_v_ - uvsize + uv_offset; - const int mb_y = ctx->mb_y_; + const VP8ThreadContext* const ctx = &dec->thread_ctx; + const int cache_id = ctx->id; + const int extra_y_rows = kFilterExtraRows[dec->filter_type]; + const int ysize = extra_y_rows * dec->cache_y_stride; + const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride; + const int y_offset = cache_id * 16 * dec->cache_y_stride; + const int uv_offset = cache_id * 8 * dec->cache_uv_stride; + uint8_t* const ydst = dec->cache_y - ysize + y_offset; + uint8_t* const udst = dec->cache_u - uvsize + uv_offset; + uint8_t* const vdst = dec->cache_v - uvsize + uv_offset; + const int mb_y = ctx->mb_y; const int is_first_row = (mb_y == 0); - const int is_last_row = (mb_y >= dec->br_mb_y_ - 1); + const int is_last_row = (mb_y >= dec->br_mb_y - 1); - if (dec->mt_method_ == 2) { + if (dec->mt_method == 2) { ReconstructRow(dec, ctx); } - if (ctx->filter_row_) { + if (ctx->filter_row) { FilterRow(dec); } - if (dec->dither_) { + if (dec->dither) { DitherRow(dec); } if (io->put != NULL) { int y_start = MACROBLOCK_VPOS(mb_y); @@ -436,37 +447,37 @@ y_start -= extra_y_rows; io->y = ydst; io->u = udst; io->v = vdst; } else { - io->y = dec->cache_y_ + y_offset; - io->u = dec->cache_u_ + uv_offset; - io->v = dec->cache_v_ + uv_offset; + io->y = dec->cache_y + y_offset; + io->u = dec->cache_u + uv_offset; + io->v = dec->cache_v + uv_offset; } if (!is_last_row) { y_end -= extra_y_rows; } if (y_end > io->crop_bottom) { y_end = io->crop_bottom; // make sure we don't overflow on last row. } - // If dec->alpha_data_ is not NULL, we have some alpha plane present. + // If dec->alpha_data is not NULL, we have some alpha plane present. io->a = NULL; - if (dec->alpha_data_ != NULL && y_start < y_end) { + if (dec->alpha_data != NULL && y_start < y_end) { io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start); if (io->a == NULL) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Could not decode alpha data."); } } if (y_start < io->crop_top) { const int delta_y = io->crop_top - y_start; y_start = io->crop_top; assert(!(delta_y & 1)); - io->y += dec->cache_y_stride_ * delta_y; - io->u += dec->cache_uv_stride_ * (delta_y >> 1); - io->v += dec->cache_uv_stride_ * (delta_y >> 1); + io->y += dec->cache_y_stride * delta_y; + io->u += dec->cache_uv_stride * (delta_y >> 1); + io->v += dec->cache_uv_stride * (delta_y >> 1); if (io->a != NULL) { io->a += io->width * delta_y; } } if (y_start < y_end) { @@ -481,15 +492,15 @@ io->mb_h = y_end - y_start; ok = io->put(io); } } // rotate top samples if needed - if (cache_id + 1 == dec->num_caches_) { + if (cache_id + 1 == dec->num_caches) { if (!is_last_row) { - memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize); - memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize); - memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize); + memcpy(dec->cache_y - ysize, ydst + 16 * dec->cache_y_stride, ysize); + memcpy(dec->cache_u - uvsize, udst + 8 * dec->cache_uv_stride, uvsize); + memcpy(dec->cache_v - uvsize, vdst + 8 * dec->cache_uv_stride, uvsize); } } return ok; } @@ -498,47 +509,47 @@ //------------------------------------------------------------------------------ int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) { int ok = 1; - VP8ThreadContext* const ctx = &dec->thread_ctx_; + VP8ThreadContext* const ctx = &dec->thread_ctx; const int filter_row = - (dec->filter_type_ > 0) && - (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_); - if (dec->mt_method_ == 0) { - // ctx->id_ and ctx->f_info_ are already set - ctx->mb_y_ = dec->mb_y_; - ctx->filter_row_ = filter_row; + (dec->filter_type > 0) && + (dec->mb_y >= dec->tl_mb_y) && (dec->mb_y <= dec->br_mb_y); + if (dec->mt_method == 0) { + // ctx->id and ctx->f_info are already set + ctx->mb_y = dec->mb_y; + ctx->filter_row = filter_row; ReconstructRow(dec, ctx); ok = FinishRow(dec, io); } else { - WebPWorker* const worker = &dec->worker_; + WebPWorker* const worker = &dec->worker; // Finish previous job *before* updating context ok &= WebPGetWorkerInterface()->Sync(worker); - assert(worker->status_ == OK); + assert(worker->status == OK); if (ok) { // spawn a new deblocking/output job - ctx->io_ = *io; - ctx->id_ = dec->cache_id_; - ctx->mb_y_ = dec->mb_y_; - ctx->filter_row_ = filter_row; - if (dec->mt_method_ == 2) { // swap macroblock data - VP8MBData* const tmp = ctx->mb_data_; - ctx->mb_data_ = dec->mb_data_; - dec->mb_data_ = tmp; + ctx->io = *io; + ctx->id = dec->cache_id; + ctx->mb_y = dec->mb_y; + ctx->filter_row = filter_row; + if (dec->mt_method == 2) { // swap macroblock data + VP8MBData* const tmp = ctx->mb_data; + ctx->mb_data = dec->mb_data; + dec->mb_data = tmp; } else { // perform reconstruction directly in main thread ReconstructRow(dec, ctx); } if (filter_row) { // swap filter info - VP8FInfo* const tmp = ctx->f_info_; - ctx->f_info_ = dec->f_info_; - dec->f_info_ = tmp; + VP8FInfo* const tmp = ctx->f_info; + ctx->f_info = dec->f_info; + dec->f_info = tmp; } // (reconstruct)+filter in parallel WebPGetWorkerInterface()->Launch(worker); - if (++dec->cache_id_ == dec->num_caches_) { - dec->cache_id_ = 0; + if (++dec->cache_id == dec->num_caches) { + dec->cache_id = 0; } } } return ok; } @@ -549,16 +560,16 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) { // Call setup() first. This may trigger additional decoding features on 'io'. // Note: Afterward, we must call teardown() no matter what. if (io->setup != NULL && !io->setup(io)) { VP8SetError(dec, VP8_STATUS_USER_ABORT, "Frame setup failed"); - return dec->status_; + return dec->status; } // Disable filtering per user request if (io->bypass_filtering) { - dec->filter_type_ = 0; + dec->filter_type = 0; } // Define the area where we can skip in-loop filtering, in case of cropping. // // 'Simple' filter reads two luma samples outside of the macroblock @@ -567,43 +578,43 @@ // For the 'Complex' filter, 3 samples are read and up to 3 are filtered. // Means: there's a dependency chain that goes all the way up to the // top-left corner of the picture (MB #0). We must filter all the previous // macroblocks. { - const int extra_pixels = kFilterExtraRows[dec->filter_type_]; - if (dec->filter_type_ == 2) { + const int extra_pixels = kFilterExtraRows[dec->filter_type]; + if (dec->filter_type == 2) { // For complex filter, we need to preserve the dependency chain. - dec->tl_mb_x_ = 0; - dec->tl_mb_y_ = 0; + dec->tl_mb_x = 0; + dec->tl_mb_y = 0; } else { // For simple filter, we can filter only the cropped region. // We include 'extra_pixels' on the other side of the boundary, since // vertical or horizontal filtering of the previous macroblock can // modify some abutting pixels. - dec->tl_mb_x_ = (io->crop_left - extra_pixels) >> 4; - dec->tl_mb_y_ = (io->crop_top - extra_pixels) >> 4; - if (dec->tl_mb_x_ < 0) dec->tl_mb_x_ = 0; - if (dec->tl_mb_y_ < 0) dec->tl_mb_y_ = 0; + dec->tl_mb_x = (io->crop_left - extra_pixels) >> 4; + dec->tl_mb_y = (io->crop_top - extra_pixels) >> 4; + if (dec->tl_mb_x < 0) dec->tl_mb_x = 0; + if (dec->tl_mb_y < 0) dec->tl_mb_y = 0; } // We need some 'extra' pixels on the right/bottom. - dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4; - dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4; - if (dec->br_mb_x_ > dec->mb_w_) { - dec->br_mb_x_ = dec->mb_w_; + dec->br_mb_y = (io->crop_bottom + 15 + extra_pixels) >> 4; + dec->br_mb_x = (io->crop_right + 15 + extra_pixels) >> 4; + if (dec->br_mb_x > dec->mb_w) { + dec->br_mb_x = dec->mb_w; } - if (dec->br_mb_y_ > dec->mb_h_) { - dec->br_mb_y_ = dec->mb_h_; + if (dec->br_mb_y > dec->mb_h) { + dec->br_mb_y = dec->mb_h; } } PrecomputeFilterStrengths(dec); return VP8_STATUS_OK; } int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { int ok = 1; - if (dec->mt_method_ > 0) { - ok = WebPGetWorkerInterface()->Sync(&dec->worker_); + if (dec->mt_method > 0) { + ok = WebPGetWorkerInterface()->Sync(&dec->worker); } if (io->teardown != NULL) { io->teardown(io); } @@ -637,24 +648,24 @@ #define MT_CACHE_LINES 3 #define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case // Initialize multi/single-thread worker static int InitThreadContext(VP8Decoder* const dec) { - dec->cache_id_ = 0; - if (dec->mt_method_ > 0) { - WebPWorker* const worker = &dec->worker_; + dec->cache_id = 0; + if (dec->mt_method > 0) { + WebPWorker* const worker = &dec->worker; if (!WebPGetWorkerInterface()->Reset(worker)) { return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "thread initialization failed."); } worker->data1 = dec; - worker->data2 = (void*)&dec->thread_ctx_.io_; + worker->data2 = (void*)&dec->thread_ctx.io; worker->hook = FinishRow; - dec->num_caches_ = - (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; + dec->num_caches = + (dec->filter_type > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; } else { - dec->num_caches_ = ST_CACHE_LINES; + dec->num_caches = ST_CACHE_LINES; } return 1; } int VP8GetThreadMethod(const WebPDecoderOptions* const options, @@ -678,124 +689,124 @@ //------------------------------------------------------------------------------ // Memory setup static int AllocateMemory(VP8Decoder* const dec) { - const int num_caches = dec->num_caches_; - const int mb_w = dec->mb_w_; + const int num_caches = dec->num_caches; + const int mb_w = dec->mb_w; // Note: we use 'size_t' when there's no overflow risk, uint64_t otherwise. const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t); const size_t top_size = sizeof(VP8TopSamples) * mb_w; const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB); const size_t f_info_size = - (dec->filter_type_ > 0) ? - mb_w * (dec->mt_method_ > 0 ? 2 : 1) * sizeof(VP8FInfo) + (dec->filter_type > 0) ? + mb_w * (dec->mt_method > 0 ? 2 : 1) * sizeof(VP8FInfo) : 0; - const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_); + const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b); const size_t mb_data_size = - (dec->mt_method_ == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data_); + (dec->mt_method == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data); const size_t cache_height = (16 * num_caches - + kFilterExtraRows[dec->filter_type_]) * 3 / 2; + + kFilterExtraRows[dec->filter_type]) * 3 / 2; const size_t cache_size = top_size * cache_height; // alpha_size is the only one that scales as width x height. - const uint64_t alpha_size = (dec->alpha_data_ != NULL) ? - (uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL; + const uint64_t alpha_size = (dec->alpha_data != NULL) ? + (uint64_t)dec->pic_hdr.width * dec->pic_hdr.height : 0ULL; const uint64_t needed = (uint64_t)intra_pred_mode_size + top_size + mb_info_size + f_info_size + yuv_size + mb_data_size + cache_size + alpha_size + WEBP_ALIGN_CST; uint8_t* mem; if (!CheckSizeOverflow(needed)) return 0; // check for overflow - if (needed > dec->mem_size_) { - WebPSafeFree(dec->mem_); - dec->mem_size_ = 0; - dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t)); - if (dec->mem_ == NULL) { + if (needed > dec->mem_size) { + WebPSafeFree(dec->mem); + dec->mem_size = 0; + dec->mem = WebPSafeMalloc(needed, sizeof(uint8_t)); + if (dec->mem == NULL) { return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "no memory during frame initialization."); } // down-cast is ok, thanks to WebPSafeMalloc() above. - dec->mem_size_ = (size_t)needed; + dec->mem_size = (size_t)needed; } - mem = (uint8_t*)dec->mem_; - dec->intra_t_ = mem; + mem = (uint8_t*)dec->mem; + dec->intra_t = mem; mem += intra_pred_mode_size; - dec->yuv_t_ = (VP8TopSamples*)mem; + dec->yuv_t = (VP8TopSamples*)mem; mem += top_size; - dec->mb_info_ = ((VP8MB*)mem) + 1; + dec->mb_info = ((VP8MB*)mem) + 1; mem += mb_info_size; - dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL; + dec->f_info = f_info_size ? (VP8FInfo*)mem : NULL; mem += f_info_size; - dec->thread_ctx_.id_ = 0; - dec->thread_ctx_.f_info_ = dec->f_info_; - if (dec->filter_type_ > 0 && dec->mt_method_ > 0) { + dec->thread_ctx.id = 0; + dec->thread_ctx.f_info = dec->f_info; + if (dec->filter_type > 0 && dec->mt_method > 0) { // secondary cache line. The deblocking process need to make use of the // filtering strength from previous macroblock row, while the new ones // are being decoded in parallel. We'll just swap the pointers. - dec->thread_ctx_.f_info_ += mb_w; + dec->thread_ctx.f_info += mb_w; } mem = (uint8_t*)WEBP_ALIGN(mem); assert((yuv_size & WEBP_ALIGN_CST) == 0); - dec->yuv_b_ = mem; + dec->yuv_b = mem; mem += yuv_size; - dec->mb_data_ = (VP8MBData*)mem; - dec->thread_ctx_.mb_data_ = (VP8MBData*)mem; - if (dec->mt_method_ == 2) { - dec->thread_ctx_.mb_data_ += mb_w; + dec->mb_data = (VP8MBData*)mem; + dec->thread_ctx.mb_data = (VP8MBData*)mem; + if (dec->mt_method == 2) { + dec->thread_ctx.mb_data += mb_w; } mem += mb_data_size; - dec->cache_y_stride_ = 16 * mb_w; - dec->cache_uv_stride_ = 8 * mb_w; + dec->cache_y_stride = 16 * mb_w; + dec->cache_uv_stride = 8 * mb_w; { - const int extra_rows = kFilterExtraRows[dec->filter_type_]; - const int extra_y = extra_rows * dec->cache_y_stride_; - const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_; - dec->cache_y_ = mem + extra_y; - dec->cache_u_ = dec->cache_y_ - + 16 * num_caches * dec->cache_y_stride_ + extra_uv; - dec->cache_v_ = dec->cache_u_ - + 8 * num_caches * dec->cache_uv_stride_ + extra_uv; - dec->cache_id_ = 0; + const int extra_rows = kFilterExtraRows[dec->filter_type]; + const int extra_y = extra_rows * dec->cache_y_stride; + const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride; + dec->cache_y = mem + extra_y; + dec->cache_u = dec->cache_y + + 16 * num_caches * dec->cache_y_stride + extra_uv; + dec->cache_v = dec->cache_u + + 8 * num_caches * dec->cache_uv_stride + extra_uv; + dec->cache_id = 0; } mem += cache_size; // alpha plane - dec->alpha_plane_ = alpha_size ? mem : NULL; + dec->alpha_plane = alpha_size ? mem : NULL; mem += alpha_size; - assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_); + assert(mem <= (uint8_t*)dec->mem + dec->mem_size); // note: left/top-info is initialized once for all. - memset(dec->mb_info_ - 1, 0, mb_info_size); + memset(dec->mb_info - 1, 0, mb_info_size); VP8InitScanline(dec); // initialize left too. // initialize top - memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size); + memset(dec->intra_t, B_DC_PRED, intra_pred_mode_size); return 1; } static void InitIo(VP8Decoder* const dec, VP8Io* io) { // prepare 'io' io->mb_y = 0; - io->y = dec->cache_y_; - io->u = dec->cache_u_; - io->v = dec->cache_v_; - io->y_stride = dec->cache_y_stride_; - io->uv_stride = dec->cache_uv_stride_; + io->y = dec->cache_y; + io->u = dec->cache_u; + io->v = dec->cache_v; + io->y_stride = dec->cache_y_stride; + io->uv_stride = dec->cache_uv_stride; io->a = NULL; } int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io) { - if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_. + if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches. if (!AllocateMemory(dec)) return 0; InitIo(dec, io); VP8DspInit(); // Init critical function pointers and look-up tables. return 1; } diff --git a/media/libwebp/src/dec/idec_dec.c b/media/libwebp/src/dec/idec_dec.c --- a/media/libwebp/src/dec/idec_dec.c +++ b/media/libwebp/src/dec/idec_dec.c @@ -10,19 +10,24 @@ // Incremental decoding // // Author: somnath@google.com (Somnath Banerjee) #include +#include #include -#include #include "src/dec/alphai_dec.h" -#include "src/dec/webpi_dec.h" #include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" +#include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" #include "src/webp/decode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" // In append mode, buffer allocations increase as multiples of this value. // Needs to be a power of 2. #define CHUNK_SIZE 4096 #define MAX_MB_SIZE 4096 @@ -52,271 +57,277 @@ MEM_MODE_MAP } MemBufferMode; // storage for partition #0 and partial data (in a rolling fashion) typedef struct { - MemBufferMode mode_; // Operation mode - size_t start_; // start location of the data to be decoded - size_t end_; // end location - size_t buf_size_; // size of the allocated buffer - uint8_t* buf_; // We don't own this buffer in case WebPIUpdate() + MemBufferMode mode; // Operation mode + size_t start; // start location of the data to be decoded + size_t end; // end location + size_t buf_size; // size of the allocated buffer + uint8_t* buf; // We don't own this buffer in case WebPIUpdate() - size_t part0_size_; // size of partition #0 - const uint8_t* part0_buf_; // buffer to store partition #0 + size_t part0_size; // size of partition #0 + const uint8_t* part0_buf; // buffer to store partition #0 } MemBuffer; struct WebPIDecoder { - DecState state_; // current decoding state - WebPDecParams params_; // Params to store output info - int is_lossless_; // for down-casting 'dec_'. - void* dec_; // either a VP8Decoder or a VP8LDecoder instance - VP8Io io_; + DecState state; // current decoding state + WebPDecParams params; // Params to store output info + int is_lossless; // for down-casting 'dec'. + void* dec; // either a VP8Decoder or a VP8LDecoder instance + VP8Io io; - MemBuffer mem_; // input memory buffer. - WebPDecBuffer output_; // output buffer (when no external one is supplied, - // or if the external one has slow-memory) - WebPDecBuffer* final_output_; // Slow-memory output to copy to eventually. - size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header. + MemBuffer mem; // input memory buffer. + WebPDecBuffer output; // output buffer (when no external one is supplied, + // or if the external one has slow-memory) + WebPDecBuffer* final_output; // Slow-memory output to copy to eventually. + size_t chunk_size; // Compressed VP8/VP8L size extracted from Header. - int last_mb_y_; // last row reached for intra-mode decoding + int last_mb_y; // last row reached for intra-mode decoding }; // MB context to restore in case VP8DecodeMB() fails typedef struct { - VP8MB left_; - VP8MB info_; - VP8BitReader token_br_; + VP8MB left; + VP8MB info; + VP8BitReader token_br; } MBContext; //------------------------------------------------------------------------------ // MemBuffer: incoming data handling static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { - return (mem->end_ - mem->start_); + return (mem->end - mem->start); } // Check if we need to preserve the compressed alpha data, as it may not have // been decoded yet. static int NeedCompressedAlpha(const WebPIDecoder* const idec) { - if (idec->state_ == STATE_WEBP_HEADER) { + if (idec->state == STATE_WEBP_HEADER) { // We haven't parsed the headers yet, so we don't know whether the image is // lossy or lossless. This also means that we haven't parsed the ALPH chunk. return 0; } - if (idec->is_lossless_) { + if (idec->is_lossless) { return 0; // ALPH chunk is not present for lossless images. } else { - const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - assert(dec != NULL); // Must be true as idec->state_ != STATE_WEBP_HEADER. - return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_; + const VP8Decoder* const dec = (VP8Decoder*)idec->dec; + assert(dec != NULL); // Must be true as idec->state != STATE_WEBP_HEADER. + return (dec->alpha_data != NULL) && !dec->is_alpha_decoded; } } static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { - MemBuffer* const mem = &idec->mem_; - const uint8_t* const new_base = mem->buf_ + mem->start_; - // note: for VP8, setting up idec->io_ is only really needed at the beginning + MemBuffer* const mem = &idec->mem; + const uint8_t* const new_base = mem->buf + mem->start; + // note: for VP8, setting up idec->io is only really needed at the beginning // of the decoding, till partition #0 is complete. - idec->io_.data = new_base; - idec->io_.data_size = MemDataSize(mem); + idec->io.data = new_base; + idec->io.data_size = MemDataSize(mem); - if (idec->dec_ != NULL) { - if (!idec->is_lossless_) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - const uint32_t last_part = dec->num_parts_minus_one_; + if (idec->dec != NULL) { + if (!idec->is_lossless) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + const uint32_t last_part = dec->num_parts_minus_one; if (offset != 0) { uint32_t p; for (p = 0; p <= last_part; ++p) { - VP8RemapBitReader(dec->parts_ + p, offset); + VP8RemapBitReader(dec->parts + p, offset); } // Remap partition #0 data pointer to new offset, but only in MAP // mode (in APPEND mode, partition #0 is copied into a fixed memory). - if (mem->mode_ == MEM_MODE_MAP) { - VP8RemapBitReader(&dec->br_, offset); + if (mem->mode == MEM_MODE_MAP) { + VP8RemapBitReader(&dec->br, offset); } } { - const uint8_t* const last_start = dec->parts_[last_part].buf_; - VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start, - mem->buf_ + mem->end_ - last_start); + const uint8_t* const last_start = dec->parts[last_part].buf; + // 'last_start' will be NULL when 'idec->state' is < STATE_VP8_PARTS0 + // and through a portion of that state (when there isn't enough data to + // parse the partitions). The bitreader is only used meaningfully when + // there is enough data to begin parsing partition 0. + if (last_start != NULL) { + VP8BitReaderSetBuffer(&dec->parts[last_part], last_start, + mem->buf + mem->end - last_start); + } } if (NeedCompressedAlpha(idec)) { - ALPHDecoder* const alph_dec = dec->alph_dec_; - dec->alpha_data_ += offset; - if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) { - if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { - VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; - assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN); - VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_, - dec->alpha_data_ + ALPHA_HEADER_LEN, - dec->alpha_data_size_ - ALPHA_HEADER_LEN); - } else { // alph_dec->method_ == ALPHA_NO_COMPRESSION + ALPHDecoder* const alph_dec = dec->alph_dec; + dec->alpha_data += offset; + if (alph_dec != NULL && alph_dec->vp8l_dec != NULL) { + if (alph_dec->method == ALPHA_LOSSLESS_COMPRESSION) { + VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec; + assert(dec->alpha_data_size >= ALPHA_HEADER_LEN); + VP8LBitReaderSetBuffer(&alph_vp8l_dec->br, + dec->alpha_data + ALPHA_HEADER_LEN, + dec->alpha_data_size - ALPHA_HEADER_LEN); + } else { // alph_dec->method == ALPHA_NO_COMPRESSION // Nothing special to do in this case. } } } } else { // Resize lossless bitreader - VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; - VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem)); + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec; + VP8LBitReaderSetBuffer(&dec->br, new_base, MemDataSize(mem)); } } } -// 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. WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec, const uint8_t* const data, size_t data_size) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - MemBuffer* const mem = &idec->mem_; + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + MemBuffer* const mem = &idec->mem; const int need_compressed_alpha = NeedCompressedAlpha(idec); const uint8_t* const old_start = - (mem->buf_ == NULL) ? NULL : mem->buf_ + mem->start_; + (mem->buf == NULL) ? NULL : mem->buf + mem->start; const uint8_t* const old_base = - need_compressed_alpha ? dec->alpha_data_ : old_start; - assert(mem->buf_ != NULL || mem->start_ == 0); - assert(mem->mode_ == MEM_MODE_APPEND); + need_compressed_alpha ? dec->alpha_data : old_start; + assert(mem->buf != NULL || mem->start == 0); + assert(mem->mode == MEM_MODE_APPEND); if (data_size > MAX_CHUNK_PAYLOAD) { // security safeguard: trying to allocate more than what the format // allows for a chunk should be considered a smoke smell. return 0; } - if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory + if (mem->end + data_size > mem->buf_size) { // Need some free memory const size_t new_mem_start = old_start - old_base; const size_t current_size = MemDataSize(mem) + new_mem_start; const uint64_t new_size = (uint64_t)current_size + data_size; const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1); uint8_t* const new_buf = (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); if (new_buf == NULL) return 0; if (old_base != NULL) memcpy(new_buf, old_base, current_size); - WebPSafeFree(mem->buf_); - mem->buf_ = new_buf; - mem->buf_size_ = (size_t)extra_size; - mem->start_ = new_mem_start; - mem->end_ = current_size; + WebPSafeFree(mem->buf); + mem->buf = new_buf; + mem->buf_size = (size_t)extra_size; + mem->start = new_mem_start; + mem->end = current_size; } - assert(mem->buf_ != NULL); - memcpy(mem->buf_ + mem->end_, data, data_size); - mem->end_ += data_size; - assert(mem->end_ <= mem->buf_size_); + assert(mem->buf != NULL); + memcpy(mem->buf + mem->end, data, data_size); + mem->end += data_size; + assert(mem->end <= mem->buf_size); - DoRemap(idec, mem->buf_ + mem->start_ - old_start); + DoRemap(idec, mem->buf + mem->start - old_start); return 1; } WEBP_NODISCARD static int RemapMemBuffer(WebPIDecoder* const idec, const uint8_t* const data, size_t data_size) { - MemBuffer* const mem = &idec->mem_; - const uint8_t* const old_buf = mem->buf_; + MemBuffer* const mem = &idec->mem; + const uint8_t* const old_buf = mem->buf; const uint8_t* const old_start = - (old_buf == NULL) ? NULL : old_buf + mem->start_; - assert(old_buf != NULL || mem->start_ == 0); - assert(mem->mode_ == MEM_MODE_MAP); + (old_buf == NULL) ? NULL : old_buf + mem->start; + assert(old_buf != NULL || mem->start == 0); + assert(mem->mode == MEM_MODE_MAP); - if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer! + if (data_size < mem->buf_size) return 0; // can't remap to a shorter buffer! - mem->buf_ = (uint8_t*)data; - mem->end_ = mem->buf_size_ = data_size; + mem->buf = (uint8_t*)data; + mem->end = mem->buf_size = data_size; - DoRemap(idec, mem->buf_ + mem->start_ - old_start); + DoRemap(idec, mem->buf + mem->start - old_start); return 1; } static void InitMemBuffer(MemBuffer* const mem) { - mem->mode_ = MEM_MODE_NONE; - mem->buf_ = NULL; - mem->buf_size_ = 0; - mem->part0_buf_ = NULL; - mem->part0_size_ = 0; + mem->mode = MEM_MODE_NONE; + mem->buf = NULL; + mem->buf_size = 0; + mem->part0_buf = NULL; + mem->part0_size = 0; } static void ClearMemBuffer(MemBuffer* const mem) { assert(mem); - if (mem->mode_ == MEM_MODE_APPEND) { - WebPSafeFree(mem->buf_); - WebPSafeFree((void*)mem->part0_buf_); + if (mem->mode == MEM_MODE_APPEND) { + WebPSafeFree(mem->buf); + WebPSafeFree((void*)mem->part0_buf); } } WEBP_NODISCARD static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) { - if (mem->mode_ == MEM_MODE_NONE) { - mem->mode_ = expected; // switch to the expected mode - } else if (mem->mode_ != expected) { + if (mem->mode == MEM_MODE_NONE) { + mem->mode = expected; // switch to the expected mode + } else if (mem->mode != expected) { return 0; // we mixed the modes => error } - assert(mem->mode_ == expected); // mode is ok + assert(mem->mode == expected); // mode is ok return 1; } // To be called last. WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { - const WebPDecoderOptions* const options = idec->params_.options; - WebPDecBuffer* const output = idec->params_.output; + const WebPDecoderOptions* const options = idec->params.options; + WebPDecBuffer* const output = idec->params.output; - idec->state_ = STATE_DONE; + idec->state = STATE_DONE; if (options != NULL && options->flip) { const VP8StatusCode status = WebPFlipBuffer(output); if (status != VP8_STATUS_OK) return status; } - if (idec->final_output_ != NULL) { + if (idec->final_output != NULL) { const VP8StatusCode status = WebPCopyDecBufferPixels( - output, idec->final_output_); // do the slow-copy - WebPFreeDecBuffer(&idec->output_); + output, idec->final_output); // do the slow-copy + WebPFreeDecBuffer(&idec->output); if (status != VP8_STATUS_OK) return status; - *output = *idec->final_output_; - idec->final_output_ = NULL; + *output = *idec->final_output; + idec->final_output = NULL; } return VP8_STATUS_OK; } //------------------------------------------------------------------------------ // Macroblock-decoding contexts static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, MBContext* const context) { - context->left_ = dec->mb_info_[-1]; - context->info_ = dec->mb_info_[dec->mb_x_]; - context->token_br_ = *token_br; + context->left = dec->mb_info[-1]; + context->info = dec->mb_info[dec->mb_x]; + context->token_br = *token_br; } static void RestoreContext(const MBContext* context, VP8Decoder* const dec, VP8BitReader* const token_br) { - dec->mb_info_[-1] = context->left_; - dec->mb_info_[dec->mb_x_] = context->info_; - *token_br = context->token_br_; + dec->mb_info[-1] = context->left; + dec->mb_info[dec->mb_x] = context->info; + *token_br = context->token_br; } //------------------------------------------------------------------------------ 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. - (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); + (void)VP8ExitCritical((VP8Decoder*)idec->dec, &idec->io); } - idec->state_ = STATE_ERROR; + idec->state = STATE_ERROR; return error; } static void ChangeState(WebPIDecoder* const idec, DecState new_state, size_t consumed_bytes) { - MemBuffer* const mem = &idec->mem_; - idec->state_ = new_state; - mem->start_ += consumed_bytes; - assert(mem->start_ <= mem->end_); - idec->io_.data = mem->buf_ + mem->start_; - idec->io_.data_size = MemDataSize(mem); + MemBuffer* const mem = &idec->mem; + idec->state = new_state; + mem->start += consumed_bytes; + assert(mem->start <= mem->end); + idec->io.data = mem->buf + mem->start; + idec->io.data_size = MemDataSize(mem); } // Headers static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) { - MemBuffer* const mem = &idec->mem_; - const uint8_t* data = mem->buf_ + mem->start_; + MemBuffer* const mem = &idec->mem; + const uint8_t* data = mem->buf + mem->start; size_t curr_size = MemDataSize(mem); VP8StatusCode status; WebPHeaderStructure headers; headers.data = data; @@ -327,180 +338,180 @@ return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet. } else if (status != VP8_STATUS_OK) { return IDecError(idec, status); } - idec->chunk_size_ = headers.compressed_size; - idec->is_lossless_ = headers.is_lossless; - if (!idec->is_lossless_) { + idec->chunk_size = headers.compressed_size; + idec->is_lossless = headers.is_lossless; + if (!idec->is_lossless) { VP8Decoder* const dec = VP8New(); if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } - dec->incremental_ = 1; - idec->dec_ = dec; - dec->alpha_data_ = headers.alpha_data; - dec->alpha_data_size_ = headers.alpha_data_size; + dec->incremental = 1; + idec->dec = dec; + dec->alpha_data = headers.alpha_data; + dec->alpha_data_size = headers.alpha_data_size; ChangeState(idec, STATE_VP8_HEADER, headers.offset); } else { VP8LDecoder* const dec = VP8LNew(); if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } - idec->dec_ = dec; + idec->dec = dec; ChangeState(idec, STATE_VP8L_HEADER, headers.offset); } return VP8_STATUS_OK; } static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { - const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; - const size_t curr_size = MemDataSize(&idec->mem_); + const uint8_t* data = idec->mem.buf + idec->mem.start; + const size_t curr_size = MemDataSize(&idec->mem); int width, height; uint32_t bits; if (curr_size < VP8_FRAME_HEADER_SIZE) { // Not enough data bytes to extract VP8 Frame Header. return VP8_STATUS_SUSPENDED; } - if (!VP8GetInfo(data, curr_size, idec->chunk_size_, &width, &height)) { + if (!VP8GetInfo(data, curr_size, idec->chunk_size, &width, &height)) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } bits = data[0] | (data[1] << 8) | (data[2] << 16); - idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE; + idec->mem.part0_size = (bits >> 5) + VP8_FRAME_HEADER_SIZE; - idec->io_.data = data; - idec->io_.data_size = curr_size; - idec->state_ = STATE_VP8_PARTS0; + idec->io.data = data; + idec->io.data_size = curr_size; + idec->state = STATE_VP8_PARTS0; return VP8_STATUS_OK; } // Partition #0 static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - VP8BitReader* const br = &dec->br_; - const size_t part_size = br->buf_end_ - br->buf_; - MemBuffer* const mem = &idec->mem_; - assert(!idec->is_lossless_); - assert(mem->part0_buf_ == NULL); + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + VP8BitReader* const br = &dec->br; + const size_t part_size = br->buf_end - br->buf; + MemBuffer* const mem = &idec->mem; + assert(!idec->is_lossless); + assert(mem->part0_buf == NULL); // the following is a format limitation, no need for runtime check: - assert(part_size <= mem->part0_size_); + assert(part_size <= mem->part0_size); if (part_size == 0) { // can't have zero-size partition #0 return VP8_STATUS_BITSTREAM_ERROR; } - if (mem->mode_ == MEM_MODE_APPEND) { + if (mem->mode == MEM_MODE_APPEND) { // We copy and grab ownership of the partition #0 data. uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size); if (part0_buf == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } - memcpy(part0_buf, br->buf_, part_size); - mem->part0_buf_ = part0_buf; + memcpy(part0_buf, br->buf, part_size); + mem->part0_buf = part0_buf; VP8BitReaderSetBuffer(br, part0_buf, part_size); } else { - // Else: just keep pointers to the partition #0's data in dec_->br_. + // Else: just keep pointers to the partition #0's data in dec->br. } - mem->start_ += part_size; + mem->start += part_size; return VP8_STATUS_OK; } static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - VP8Io* const io = &idec->io_; - const WebPDecParams* const params = &idec->params_; + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + VP8Io* const io = &idec->io; + const WebPDecParams* const params = &idec->params; WebPDecBuffer* const output = params->output; // Wait till we have enough data for the whole partition #0 - if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) { + if (MemDataSize(&idec->mem) < idec->mem.part0_size) { return VP8_STATUS_SUSPENDED; } if (!VP8GetHeaders(dec, io)) { - const VP8StatusCode status = dec->status_; + const VP8StatusCode status = dec->status; if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) { // treating NOT_ENOUGH_DATA as SUSPENDED state return VP8_STATUS_SUSPENDED; } return IDecError(idec, status); } // Allocate/Verify output buffer now - dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, - output); - if (dec->status_ != VP8_STATUS_OK) { - return IDecError(idec, dec->status_); + dec->status = WebPAllocateDecBuffer(io->width, io->height, params->options, + output); + if (dec->status != VP8_STATUS_OK) { + return IDecError(idec, dec->status); } // This change must be done before calling VP8InitFrame() - dec->mt_method_ = VP8GetThreadMethod(params->options, NULL, - io->width, io->height); + dec->mt_method = VP8GetThreadMethod(params->options, NULL, + io->width, io->height); VP8InitDithering(params->options, dec); - dec->status_ = CopyParts0Data(idec); - if (dec->status_ != VP8_STATUS_OK) { - return IDecError(idec, dec->status_); + dec->status = CopyParts0Data(idec); + if (dec->status != VP8_STATUS_OK) { + return IDecError(idec, dec->status); } // Finish setting up the decoding parameters. Will call io->setup(). if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) { - return IDecError(idec, dec->status_); + return IDecError(idec, dec->status); } // Note: past this point, teardown() must always be called // in case of error. - idec->state_ = STATE_VP8_DATA; + idec->state = STATE_VP8_DATA; // Allocate memory and prepare everything. if (!VP8InitFrame(dec, io)) { - return IDecError(idec, dec->status_); + return IDecError(idec, dec->status); } return VP8_STATUS_OK; } // Remaining partitions static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - VP8Io* const io = &idec->io_; + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + VP8Io* const io = &idec->io; - // Make sure partition #0 has been read before, to set dec to ready_. - if (!dec->ready_) { + // Make sure partition #0 has been read before, to set dec to ready. + if (!dec->ready) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } - for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { - if (idec->last_mb_y_ != dec->mb_y_) { - if (!VP8ParseIntraModeRow(&dec->br_, dec)) { + for (; dec->mb_y < dec->mb_h; ++dec->mb_y) { + if (idec->last_mb_y != dec->mb_y) { + if (!VP8ParseIntraModeRow(&dec->br, dec)) { // note: normally, error shouldn't occur since we already have the whole // partition0 available here in DecodeRemaining(). Reaching EOF while // reading intra modes really means a BITSTREAM_ERROR. return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } - idec->last_mb_y_ = dec->mb_y_; + idec->last_mb_y = dec->mb_y; } - for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { + for (; dec->mb_x < dec->mb_w; ++dec->mb_x) { VP8BitReader* const token_br = - &dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_]; + &dec->parts[dec->mb_y & dec->num_parts_minus_one]; MBContext context; SaveContext(dec, token_br, &context); if (!VP8DecodeMB(dec, token_br)) { // We shouldn't fail when MAX_MB data was available - if (dec->num_parts_minus_one_ == 0 && - MemDataSize(&idec->mem_) > MAX_MB_SIZE) { + if (dec->num_parts_minus_one == 0 && + MemDataSize(&idec->mem) > MAX_MB_SIZE) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } // Synchronize the threads. - if (dec->mt_method_ > 0) { - if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) { + if (dec->mt_method > 0) { + if (!WebPGetWorkerInterface()->Sync(&dec->worker)) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } } RestoreContext(&context, dec, token_br); return VP8_STATUS_SUSPENDED; } // Release buffer only if there is only one partition - if (dec->num_parts_minus_one_ == 0) { - idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_; - assert(idec->mem_.start_ <= idec->mem_.end_); + if (dec->num_parts_minus_one == 0) { + idec->mem.start = token_br->buf - idec->mem.buf; + assert(idec->mem.start <= idec->mem.end); } } VP8InitScanline(dec); // Prepare for next scanline // Reconstruct, filter and emit the row. @@ -508,14 +519,14 @@ return IDecError(idec, VP8_STATUS_USER_ABORT); } } // Synchronize the thread and check for errors. if (!VP8ExitCritical(dec, io)) { - idec->state_ = STATE_ERROR; // prevent re-entry in IDecError + idec->state = STATE_ERROR; // prevent re-entry in IDecError return IDecError(idec, VP8_STATUS_USER_ABORT); } - dec->ready_ = 0; + dec->ready = 0; return FinishDecoding(idec); } static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) { @@ -524,85 +535,85 @@ } return IDecError(idec, status); } static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) { - VP8Io* const io = &idec->io_; - VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; - const WebPDecParams* const params = &idec->params_; + VP8Io* const io = &idec->io; + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec; + const WebPDecParams* const params = &idec->params; WebPDecBuffer* const output = params->output; - size_t curr_size = MemDataSize(&idec->mem_); - assert(idec->is_lossless_); + size_t curr_size = MemDataSize(&idec->mem); + assert(idec->is_lossless); // Wait until there's enough data for decoding header. - if (curr_size < (idec->chunk_size_ >> 3)) { - dec->status_ = VP8_STATUS_SUSPENDED; - return ErrorStatusLossless(idec, dec->status_); + if (curr_size < (idec->chunk_size >> 3)) { + dec->status = VP8_STATUS_SUSPENDED; + return ErrorStatusLossless(idec, dec->status); } if (!VP8LDecodeHeader(dec, io)) { - if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && - curr_size < idec->chunk_size_) { - dec->status_ = VP8_STATUS_SUSPENDED; + if (dec->status == VP8_STATUS_BITSTREAM_ERROR && + curr_size < idec->chunk_size) { + dec->status = VP8_STATUS_SUSPENDED; } - return ErrorStatusLossless(idec, dec->status_); + return ErrorStatusLossless(idec, dec->status); } // Allocate/verify output buffer now. - dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, - output); - if (dec->status_ != VP8_STATUS_OK) { - return IDecError(idec, dec->status_); + dec->status = WebPAllocateDecBuffer(io->width, io->height, params->options, + output); + if (dec->status != VP8_STATUS_OK) { + return IDecError(idec, dec->status); } - idec->state_ = STATE_VP8L_DATA; + idec->state = STATE_VP8L_DATA; return VP8_STATUS_OK; } static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) { - VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; - const size_t curr_size = MemDataSize(&idec->mem_); - assert(idec->is_lossless_); + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec; + const size_t curr_size = MemDataSize(&idec->mem); + assert(idec->is_lossless); // Switch to incremental decoding if we don't have all the bytes available. - dec->incremental_ = (curr_size < idec->chunk_size_); + dec->incremental = (curr_size < idec->chunk_size); if (!VP8LDecodeImage(dec)) { - return ErrorStatusLossless(idec, dec->status_); + return ErrorStatusLossless(idec, dec->status); } - assert(dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED); - return (dec->status_ == VP8_STATUS_SUSPENDED) ? dec->status_ - : FinishDecoding(idec); + assert(dec->status == VP8_STATUS_OK || dec->status == VP8_STATUS_SUSPENDED); + return (dec->status == VP8_STATUS_SUSPENDED) ? dec->status + : FinishDecoding(idec); } // Main decoding loop static VP8StatusCode IDecode(WebPIDecoder* idec) { VP8StatusCode status = VP8_STATUS_SUSPENDED; - if (idec->state_ == STATE_WEBP_HEADER) { + if (idec->state == STATE_WEBP_HEADER) { status = DecodeWebPHeaders(idec); } else { - if (idec->dec_ == NULL) { + if (idec->dec == NULL) { return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. } } - if (idec->state_ == STATE_VP8_HEADER) { + if (idec->state == STATE_VP8_HEADER) { status = DecodeVP8FrameHeader(idec); } - if (idec->state_ == STATE_VP8_PARTS0) { + if (idec->state == STATE_VP8_PARTS0) { status = DecodePartition0(idec); } - if (idec->state_ == STATE_VP8_DATA) { - const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + if (idec->state == STATE_VP8_DATA) { + const VP8Decoder* const dec = (VP8Decoder*)idec->dec; if (dec == NULL) { return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. } status = DecodeRemaining(idec); } - if (idec->state_ == STATE_VP8L_HEADER) { + if (idec->state == STATE_VP8L_HEADER) { status = DecodeVP8LHeader(idec); } - if (idec->state_ == STATE_VP8L_DATA) { + if (idec->state == STATE_VP8L_DATA) { status = DecodeVP8LData(idec); } return status; } @@ -615,33 +626,33 @@ WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec)); if (idec == NULL) { return NULL; } - idec->state_ = STATE_WEBP_HEADER; - idec->chunk_size_ = 0; + idec->state = STATE_WEBP_HEADER; + idec->chunk_size = 0; - idec->last_mb_y_ = -1; + idec->last_mb_y = -1; - InitMemBuffer(&idec->mem_); - if (!WebPInitDecBuffer(&idec->output_) || !VP8InitIo(&idec->io_)) { + InitMemBuffer(&idec->mem); + if (!WebPInitDecBuffer(&idec->output) || !VP8InitIo(&idec->io)) { WebPSafeFree(idec); return NULL; } - WebPResetDecParams(&idec->params_); + WebPResetDecParams(&idec->params); if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) { - idec->params_.output = &idec->output_; - idec->final_output_ = output_buffer; + idec->params.output = &idec->output; + idec->final_output = output_buffer; if (output_buffer != NULL) { - idec->params_.output->colorspace = output_buffer->colorspace; + idec->params.output->colorspace = output_buffer->colorspace; } } else { - idec->params_.output = output_buffer; - idec->final_output_ = NULL; + idec->params.output = output_buffer; + idec->final_output = NULL; } - WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. + WebPInitCustomIo(&idec->params, &idec->io); // Plug the I/O functions. return idec; } //------------------------------------------------------------------------------ @@ -672,31 +683,31 @@ if (idec == NULL) { return NULL; } // Finish initialization if (config != NULL) { - idec->params_.options = &config->options; + idec->params.options = &config->options; } return idec; } void WebPIDelete(WebPIDecoder* idec) { if (idec == NULL) return; - if (idec->dec_ != NULL) { - if (!idec->is_lossless_) { - if (idec->state_ == STATE_VP8_DATA) { + if (idec->dec != NULL) { + if (!idec->is_lossless) { + if (idec->state == STATE_VP8_DATA) { // Synchronize the thread, clean-up and check for errors. // TODO(vrabaud) do we care about the return result? - (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); + (void)VP8ExitCritical((VP8Decoder*)idec->dec, &idec->io); } - VP8Delete((VP8Decoder*)idec->dec_); + VP8Delete((VP8Decoder*)idec->dec); } else { - VP8LDelete((VP8LDecoder*)idec->dec_); + VP8LDelete((VP8LDecoder*)idec->dec); } } - ClearMemBuffer(&idec->mem_); - WebPFreeDecBuffer(&idec->output_); + ClearMemBuffer(&idec->mem); + WebPFreeDecBuffer(&idec->output); WebPSafeFree(idec); } //------------------------------------------------------------------------------ // Wrapper toward WebPINewDecoder @@ -715,15 +726,15 @@ return NULL; // invalid parameter. } } idec = WebPINewDecoder(NULL); if (idec == NULL) return NULL; - idec->output_.colorspace = csp; - idec->output_.is_external_memory = is_external_memory; - idec->output_.u.RGBA.rgba = output_buffer; - idec->output_.u.RGBA.stride = output_stride; - idec->output_.u.RGBA.size = output_buffer_size; + idec->output.colorspace = csp; + idec->output.is_external_memory = is_external_memory; + idec->output.u.RGBA.rgba = output_buffer; + idec->output.u.RGBA.stride = output_stride; + idec->output.u.RGBA.size = output_buffer_size; return idec; } WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* u, size_t u_size, int u_stride, @@ -749,24 +760,24 @@ } idec = WebPINewDecoder(NULL); if (idec == NULL) return NULL; - idec->output_.colorspace = colorspace; - idec->output_.is_external_memory = is_external_memory; - idec->output_.u.YUVA.y = luma; - idec->output_.u.YUVA.y_stride = luma_stride; - idec->output_.u.YUVA.y_size = luma_size; - idec->output_.u.YUVA.u = u; - idec->output_.u.YUVA.u_stride = u_stride; - idec->output_.u.YUVA.u_size = u_size; - idec->output_.u.YUVA.v = v; - idec->output_.u.YUVA.v_stride = v_stride; - idec->output_.u.YUVA.v_size = v_size; - idec->output_.u.YUVA.a = a; - idec->output_.u.YUVA.a_stride = a_stride; - idec->output_.u.YUVA.a_size = a_size; + idec->output.colorspace = colorspace; + idec->output.is_external_memory = is_external_memory; + idec->output.u.YUVA.y = luma; + idec->output.u.YUVA.y_stride = luma_stride; + idec->output.u.YUVA.y_size = luma_size; + idec->output.u.YUVA.u = u; + idec->output.u.YUVA.u_stride = u_stride; + idec->output.u.YUVA.u_size = u_size; + idec->output.u.YUVA.v = v; + idec->output.u.YUVA.v_stride = v_stride; + idec->output.u.YUVA.v_size = v_size; + idec->output.u.YUVA.a = a; + idec->output.u.YUVA.a_stride = a_stride; + idec->output.u.YUVA.a_size = a_size; return idec; } WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* u, size_t u_size, int u_stride, @@ -779,14 +790,14 @@ //------------------------------------------------------------------------------ static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) { assert(idec); - if (idec->state_ == STATE_ERROR) { + if (idec->state == STATE_ERROR) { return VP8_STATUS_BITSTREAM_ERROR; } - if (idec->state_ == STATE_DONE) { + if (idec->state == STATE_DONE) { return VP8_STATUS_OK; } return VP8_STATUS_SUSPENDED; } @@ -799,11 +810,11 @@ status = IDecCheckStatus(idec); if (status != VP8_STATUS_SUSPENDED) { return status; } // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. - if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) { + if (!CheckMemBufferMode(&idec->mem, MEM_MODE_APPEND)) { return VP8_STATUS_INVALID_PARAM; } // Append data to memory buffer if (!AppendToMemBuffer(idec, data, data_size)) { return VP8_STATUS_OUT_OF_MEMORY; @@ -820,11 +831,11 @@ status = IDecCheckStatus(idec); if (status != VP8_STATUS_SUSPENDED) { return status; } // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. - if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) { + if (!CheckMemBufferMode(&idec->mem, MEM_MODE_MAP)) { return VP8_STATUS_INVALID_PARAM; } // Make the memory buffer point to the new buffer if (!RemapMemBuffer(idec, data, data_size)) { return VP8_STATUS_INVALID_PARAM; @@ -833,31 +844,31 @@ } //------------------------------------------------------------------------------ static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) { - if (idec == NULL || idec->dec_ == NULL) { + if (idec == NULL || idec->dec == NULL) { return NULL; } - if (idec->state_ <= STATE_VP8_PARTS0) { + if (idec->state <= STATE_VP8_PARTS0) { return NULL; } - if (idec->final_output_ != NULL) { + if (idec->final_output != NULL) { return NULL; // not yet slow-copied } - return idec->params_.output; + return idec->params.output; } const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, int* left, int* top, int* width, int* height) { const WebPDecBuffer* const src = GetOutputBuffer(idec); if (left != NULL) *left = 0; if (top != NULL) *top = 0; if (src != NULL) { if (width != NULL) *width = src->width; - if (height != NULL) *height = idec->params_.last_y; + if (height != NULL) *height = idec->params.last_y; } else { if (width != NULL) *width = 0; if (height != NULL) *height = 0; } return src; @@ -869,11 +880,11 @@ if (src == NULL) return NULL; if (src->colorspace >= MODE_YUV) { return NULL; } - if (last_y != NULL) *last_y = idec->params_.last_y; + if (last_y != NULL) *last_y = idec->params.last_y; if (width != NULL) *width = src->width; if (height != NULL) *height = src->height; if (stride != NULL) *stride = src->u.RGBA.stride; return src->u.RGBA.rgba; @@ -887,11 +898,11 @@ if (src == NULL) return NULL; if (src->colorspace < MODE_YUV) { return NULL; } - if (last_y != NULL) *last_y = idec->params_.last_y; + if (last_y != NULL) *last_y = idec->params.last_y; if (u != NULL) *u = src->u.YUVA.u; if (v != NULL) *v = src->u.YUVA.v; if (a != NULL) *a = src->u.YUVA.a; if (width != NULL) *width = src->width; if (height != NULL) *height = src->height; @@ -905,16 +916,16 @@ int WebPISetIOHooks(WebPIDecoder* const idec, VP8IoPutHook put, VP8IoSetupHook setup, VP8IoTeardownHook teardown, void* user_data) { - if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) { + if (idec == NULL || idec->state > STATE_WEBP_HEADER) { return 0; } - idec->io_.put = put; - idec->io_.setup = setup; - idec->io_.teardown = teardown; - idec->io_.opaque = user_data; + idec->io.put = put; + idec->io.setup = setup; + idec->io.teardown = teardown; + idec->io.opaque = user_data; return 1; } diff --git a/media/libwebp/src/dec/io_dec.c b/media/libwebp/src/dec/io_dec.c --- a/media/libwebp/src/dec/io_dec.c +++ b/media/libwebp/src/dec/io_dec.c @@ -10,26 +10,34 @@ // functions for sample output. // // Author: Skal (pascal.massimino@gmail.com) #include +#include #include +#include + +#include "src/dec/vp8_dec.h" +#include "src/webp/types.h" #include "src/dec/vp8i_dec.h" #include "src/dec/webpi_dec.h" +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" #include "src/dsp/yuv.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" //------------------------------------------------------------------------------ // Main YUV<->RGB conversion functions static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { WebPDecBuffer* output = p->output; const WebPYUVABuffer* const buf = &output->u.YUVA; - uint8_t* const y_dst = buf->y + (size_t)io->mb_y * buf->y_stride; - uint8_t* const u_dst = buf->u + (size_t)(io->mb_y >> 1) * buf->u_stride; - uint8_t* const v_dst = buf->v + (size_t)(io->mb_y >> 1) * buf->v_stride; + uint8_t* const y_dst = buf->y + (ptrdiff_t)io->mb_y * buf->y_stride; + uint8_t* const u_dst = buf->u + (ptrdiff_t)(io->mb_y >> 1) * buf->u_stride; + uint8_t* const v_dst = buf->v + (ptrdiff_t)(io->mb_y >> 1) * buf->v_stride; const int mb_w = io->mb_w; const int mb_h = io->mb_h; const int uv_w = (mb_w + 1) / 2; const int uv_h = (mb_h + 1) / 2; WebPCopyPlane(io->y, io->y_stride, y_dst, buf->y_stride, mb_w, mb_h); @@ -40,11 +48,11 @@ // Point-sampling U/V sampler. static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) { WebPDecBuffer* const output = p->output; WebPRGBABuffer* const buf = &output->u.RGBA; - uint8_t* const dst = buf->rgba + (size_t)io->mb_y * buf->stride; + uint8_t* const dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride; WebPSamplerProcessPlane(io->y, io->y_stride, io->u, io->v, io->uv_stride, dst, buf->stride, io->mb_w, io->mb_h, WebPSamplers[output->colorspace]); return io->mb_h; @@ -55,11 +63,11 @@ #ifdef FANCY_UPSAMPLING static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) { int num_lines_out = io->mb_h; // a priori guess const WebPRGBABuffer* const buf = &p->output->u.RGBA; - uint8_t* dst = buf->rgba + (size_t)io->mb_y * buf->stride; + uint8_t* dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride; WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace]; const uint8_t* cur_y = io->y; const uint8_t* cur_u = io->u; const uint8_t* cur_v = io->v; const uint8_t* top_u = p->tmp_u; @@ -126,11 +134,11 @@ int expected_num_lines_out) { const uint8_t* alpha = io->a; const WebPYUVABuffer* const buf = &p->output->u.YUVA; const int mb_w = io->mb_w; const int mb_h = io->mb_h; - uint8_t* dst = buf->a + (size_t)io->mb_y * buf->a_stride; + uint8_t* dst = buf->a + (ptrdiff_t)io->mb_y * buf->a_stride; int j; (void)expected_num_lines_out; assert(expected_num_lines_out == mb_h); if (alpha != NULL) { for (j = 0; j < mb_h; ++j) { @@ -179,12 +187,12 @@ const WEBP_CSP_MODE colorspace = p->output->colorspace; const int alpha_first = (colorspace == MODE_ARGB || colorspace == MODE_Argb); const WebPRGBABuffer* const buf = &p->output->u.RGBA; int num_rows; - const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows); - uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; + const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); + uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride; uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3); const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w, num_rows, dst, buf->stride); (void)expected_num_lines_out; assert(expected_num_lines_out == num_rows); @@ -203,12 +211,12 @@ if (alpha != NULL) { const int mb_w = io->mb_w; const WEBP_CSP_MODE colorspace = p->output->colorspace; const WebPRGBABuffer* const buf = &p->output->u.RGBA; int num_rows; - const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows); - uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; + const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); + uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride; #if (WEBP_SWAP_16BIT_CSP == 1) uint8_t* alpha_dst = base_rgba; #else uint8_t* alpha_dst = base_rgba + 1; #endif @@ -255,11 +263,11 @@ WebPRescaler* const scaler = p->scaler_y; int num_lines_out = 0; if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { // Before rescaling, we premultiply the luma directly into the io->y // internal buffer. This is OK since these samples are not used for - // intra-prediction (the top samples are saved in cache_y_/u_/v_). + // intra-prediction (the top samples are saved in cache_y/u/v). // But we need to cast the const away, though. WebPMultRows((uint8_t*)io->y, io->y_stride, io->a, io->width, io->mb_w, mb_h, 0); } num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler); @@ -269,13 +277,13 @@ } static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, int expected_num_lines_out) { const WebPYUVABuffer* const buf = &p->output->u.YUVA; - uint8_t* const dst_a = buf->a + (size_t)p->last_y * buf->a_stride; + uint8_t* const dst_a = buf->a + (ptrdiff_t)p->last_y * buf->a_stride; if (io->a != NULL) { - uint8_t* const dst_y = buf->y + (size_t)p->last_y * buf->y_stride; + uint8_t* const dst_y = buf->y + (ptrdiff_t)p->last_y * buf->y_stride; const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a); assert(expected_num_lines_out == num_lines_out); if (num_lines_out > 0) { // unmultiply the Y WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride, p->scaler_a->dst_width, num_lines_out, 1); @@ -360,11 +368,11 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) { const WebPYUV444Converter convert = WebPYUV444Converters[p->output->colorspace]; const WebPRGBABuffer* const buf = &p->output->u.RGBA; - uint8_t* dst = buf->rgba + (size_t)y_pos * buf->stride; + uint8_t* dst = buf->rgba + (ptrdiff_t)y_pos * buf->stride; int num_lines_out = 0; // For RGB rescaling, because of the YUV420, current scan position // U/V can be +1/-1 line from the Y one. Hence the double test. while (WebPRescalerHasPendingOutput(p->scaler_y) && WebPRescalerHasPendingOutput(p->scaler_u)) { @@ -387,18 +395,18 @@ int j = 0, uv_j = 0; int num_lines_out = 0; while (j < mb_h) { const int y_lines_in = WebPRescalerImport(p->scaler_y, mb_h - j, - io->y + (size_t)j * io->y_stride, io->y_stride); + io->y + (ptrdiff_t)j * io->y_stride, io->y_stride); j += y_lines_in; if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) { const int u_lines_in = WebPRescalerImport( - p->scaler_u, uv_mb_h - uv_j, io->u + (size_t)uv_j * io->uv_stride, + p->scaler_u, uv_mb_h - uv_j, io->u + (ptrdiff_t)uv_j * io->uv_stride, io->uv_stride); const int v_lines_in = WebPRescalerImport( - p->scaler_v, uv_mb_h - uv_j, io->v + (size_t)uv_j * io->uv_stride, + p->scaler_v, uv_mb_h - uv_j, io->v + (ptrdiff_t)uv_j * io->uv_stride, io->uv_stride); (void)v_lines_in; // remove a gcc warning assert(u_lines_in == v_lines_in); uv_j += u_lines_in; } @@ -407,11 +415,11 @@ return num_lines_out; } static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { const WebPRGBABuffer* const buf = &p->output->u.RGBA; - uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride; + uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride; const WEBP_CSP_MODE colorspace = p->output->colorspace; const int alpha_first = (colorspace == MODE_ARGB || colorspace == MODE_Argb); uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); int num_lines_out = 0; @@ -435,11 +443,11 @@ } static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, int max_lines_out) { const WebPRGBABuffer* const buf = &p->output->u.RGBA; - uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride; + uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride; #if (WEBP_SWAP_16BIT_CSP == 1) uint8_t* alpha_dst = base_rgba; #else uint8_t* alpha_dst = base_rgba + 1; #endif @@ -474,11 +482,11 @@ if (io->a != NULL) { WebPRescaler* const scaler = p->scaler_a; int lines_left = expected_num_out_lines; const int y_end = p->last_y + lines_left; while (lines_left > 0) { - const int64_t row_offset = (int64_t)scaler->src_y - io->mb_y; + const int64_t row_offset = (ptrdiff_t)scaler->src_y - io->mb_y; WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y, io->a + row_offset * io->width, io->width); lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left); } } diff --git a/media/libwebp/src/dec/quant_dec.c b/media/libwebp/src/dec/quant_dec.c --- a/media/libwebp/src/dec/quant_dec.c +++ b/media/libwebp/src/dec/quant_dec.c @@ -9,11 +9,15 @@ // // Quantizer initialization // // Author: Skal (pascal.massimino@gmail.com) +#include "src/dec/common_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" +#include "src/utils/bit_reader_utils.h" +#include "src/webp/types.h" static WEBP_INLINE int clip(int v, int M) { return v < 0 ? 0 : v > M ? M : v; } @@ -58,11 +62,11 @@ //------------------------------------------------------------------------------ // Paragraph 9.6 void VP8ParseQuant(VP8Decoder* const dec) { - VP8BitReader* const br = &dec->br_; + VP8BitReader* const br = &dec->br; const int base_q0 = VP8GetValue(br, 7, "global-header"); const int dqy1_dc = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 4, "global-header") : 0; const int dqy2_dc = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 4, "global-header") : 0; @@ -71,45 +75,44 @@ const int dquv_dc = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 4, "global-header") : 0; const int dquv_ac = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 4, "global-header") : 0; - const VP8SegmentHeader* const hdr = &dec->segment_hdr_; + const VP8SegmentHeader* const hdr = &dec->segment_hdr; int i; for (i = 0; i < NUM_MB_SEGMENTS; ++i) { int q; - if (hdr->use_segment_) { - q = hdr->quantizer_[i]; - if (!hdr->absolute_delta_) { + if (hdr->use_segment) { + q = hdr->quantizer[i]; + if (!hdr->absolute_delta) { q += base_q0; } } else { if (i > 0) { - dec->dqm_[i] = dec->dqm_[0]; + dec->dqm[i] = dec->dqm[0]; continue; } else { q = base_q0; } } { - VP8QuantMatrix* const m = &dec->dqm_[i]; - m->y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)]; - m->y1_mat_[1] = kAcTable[clip(q + 0, 127)]; + VP8QuantMatrix* const m = &dec->dqm[i]; + m->y1_mat[0] = kDcTable[clip(q + dqy1_dc, 127)]; + m->y1_mat[1] = kAcTable[clip(q + 0, 127)]; - m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2; + m->y2_mat[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2; // For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16. // The smallest precision for that is '(x*6349) >> 12' but 16 is a good // word size. - m->y2_mat_[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16; - if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8; + m->y2_mat[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16; + if (m->y2_mat[1] < 8) m->y2_mat[1] = 8; - m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)]; - m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)]; + m->uv_mat[0] = kDcTable[clip(q + dquv_dc, 117)]; + m->uv_mat[1] = kAcTable[clip(q + dquv_ac, 127)]; - m->uv_quant_ = q + dquv_ac; // for dithering strength evaluation + m->uv_quant = q + dquv_ac; // for dithering strength evaluation } } } //------------------------------------------------------------------------------ - diff --git a/media/libwebp/src/dec/tree_dec.c b/media/libwebp/src/dec/tree_dec.c --- a/media/libwebp/src/dec/tree_dec.c +++ b/media/libwebp/src/dec/tree_dec.c @@ -9,13 +9,19 @@ // // Coding trees and probas // // Author: Skal (pascal.massimino@gmail.com) +#include + +#include "src/dec/common_dec.h" +#include "src/webp/types.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dsp/cpu.h" #include "src/utils/bit_reader_inl_utils.h" +#include "src/utils/bit_reader_utils.h" #if !defined(USE_GENERIC_TREE) #if !defined(__arm__) && !defined(_M_ARM) && !WEBP_AARCH64 && \ !defined(__wasm__) // using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then. @@ -282,44 +288,44 @@ { 32, 41, 20, 117, 151, 142, 20, 21, 163 }, { 112, 19, 12, 61, 195, 128, 48, 4, 24 } } }; void VP8ResetProba(VP8Proba* const proba) { - memset(proba->segments_, 255u, sizeof(proba->segments_)); - // proba->bands_[][] is initialized later + memset(proba->segments, 255u, sizeof(proba->segments)); + // proba->bands[][] is initialized later } static void ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec, int mb_x) { - uint8_t* const top = dec->intra_t_ + 4 * mb_x; - uint8_t* const left = dec->intra_l_; - VP8MBData* const block = dec->mb_data_ + mb_x; + uint8_t* const top = dec->intra_t + 4 * mb_x; + uint8_t* const left = dec->intra_l; + VP8MBData* const block = dec->mb_data + mb_x; // Note: we don't save segment map (yet), as we don't expect // to decode more than 1 keyframe. - if (dec->segment_hdr_.update_map_) { + if (dec->segment_hdr.update_map) { // Hardcoded tree parsing - block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0], "segments") - ? VP8GetBit(br, dec->proba_.segments_[1], "segments") - : VP8GetBit(br, dec->proba_.segments_[2], "segments") + 2; + block->segment = !VP8GetBit(br, dec->proba.segments[0], "segments") + ? VP8GetBit(br, dec->proba.segments[1], "segments") + : VP8GetBit(br, dec->proba.segments[2], "segments") + 2; } else { - block->segment_ = 0; // default for intra + block->segment = 0; // default for intra } - if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_, "skip"); + if (dec->use_skip_proba) block->skip = VP8GetBit(br, dec->skip_p, "skip"); - block->is_i4x4_ = !VP8GetBit(br, 145, "block-size"); - if (!block->is_i4x4_) { + block->is_i4x4 = !VP8GetBit(br, 145, "block-size"); + if (!block->is_i4x4) { // Hardcoded 16x16 intra-mode decision tree. const int ymode = VP8GetBit(br, 156, "pred-modes") ? (VP8GetBit(br, 128, "pred-modes") ? TM_PRED : H_PRED) : (VP8GetBit(br, 163, "pred-modes") ? V_PRED : DC_PRED); - block->imodes_[0] = ymode; + block->imodes[0] = ymode; memset(top, ymode, 4 * sizeof(*top)); memset(left, ymode, 4 * sizeof(*left)); } else { - uint8_t* modes = block->imodes_; + uint8_t* modes = block->imodes; int y; for (y = 0; y < 4; ++y) { int ymode = left[y]; int x; for (x = 0; x < 4; ++x) { @@ -352,21 +358,21 @@ modes += 4; left[y] = ymode; } } // Hardcoded UVMode decision tree - block->uvmode_ = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED - : !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED - : VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED; + block->uvmode = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED + : !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED + : VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED; } int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) { int mb_x; - for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) { + for (mb_x = 0; mb_x < dec->mb_w; ++mb_x) { ParseIntraMode(br, dec, mb_x); } - return !dec->br_.eof_; + return !dec->br.eof; } //------------------------------------------------------------------------------ // Paragraph 13 @@ -512,28 +518,28 @@ 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0 // extra entry as sentinel }; void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) { - VP8Proba* const proba = &dec->proba_; + VP8Proba* const proba = &dec->proba; int t, b, c, p; for (t = 0; t < NUM_TYPES; ++t) { for (b = 0; b < NUM_BANDS; ++b) { for (c = 0; c < NUM_CTX; ++c) { for (p = 0; p < NUM_PROBAS; ++p) { const int v = VP8GetBit(br, CoeffsUpdateProba[t][b][c][p], "global-header") ? VP8GetValue(br, 8, "global-header") : CoeffsProba0[t][b][c][p]; - proba->bands_[t][b].probas_[c][p] = v; + proba->bands[t][b].probas[c][p] = v; } } } for (b = 0; b < 16 + 1; ++b) { - proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]]; + proba->bands_ptr[t][b] = &proba->bands[t][kBands[b]]; } } - dec->use_skip_proba_ = VP8Get(br, "global-header"); - if (dec->use_skip_proba_) { - dec->skip_p_ = VP8GetValue(br, 8, "global-header"); + dec->use_skip_proba = VP8Get(br, "global-header"); + if (dec->use_skip_proba) { + dec->skip_p = VP8GetValue(br, 8, "global-header"); } } diff --git a/media/libwebp/src/dec/vp8_dec.h b/media/libwebp/src/dec/vp8_dec.h --- a/media/libwebp/src/dec/vp8_dec.h +++ b/media/libwebp/src/dec/vp8_dec.h @@ -12,10 +12,12 @@ // Author: Skal (pascal.massimino@gmail.com) #ifndef WEBP_DEC_VP8_DEC_H_ #define WEBP_DEC_VP8_DEC_H_ +#include + #include "src/webp/decode.h" #include "src/webp/types.h" #ifdef __cplusplus extern "C" { diff --git a/media/libwebp/src/dec/vp8_dec.c b/media/libwebp/src/dec/vp8_dec.c --- a/media/libwebp/src/dec/vp8_dec.c +++ b/media/libwebp/src/dec/vp8_dec.c @@ -9,18 +9,29 @@ // // main entry for the decoder // // Author: Skal (pascal.massimino@gmail.com) +#include #include +#include #include "src/dec/alphai_dec.h" +#include "src/dec/common_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dec/vp8li_dec.h" #include "src/dec/webpi_dec.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/utils/bit_reader_inl_utils.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ int WebPGetDecoderVersion(void) { return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION; @@ -38,12 +49,12 @@ //------------------------------------------------------------------------------ // VP8Decoder static void SetOk(VP8Decoder* const dec) { - dec->status_ = VP8_STATUS_OK; - dec->error_msg_ = "OK"; + dec->status = VP8_STATUS_OK; + dec->error_msg = "OK"; } int VP8InitIoInternal(VP8Io* const io, int version) { if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { return 0; // mismatch error @@ -56,27 +67,27 @@ VP8Decoder* VP8New(void) { VP8Decoder* const dec = (VP8Decoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); if (dec != NULL) { SetOk(dec); - WebPGetWorkerInterface()->Init(&dec->worker_); - dec->ready_ = 0; - dec->num_parts_minus_one_ = 0; + WebPGetWorkerInterface()->Init(&dec->worker); + dec->ready = 0; + dec->num_parts_minus_one = 0; InitGetCoeffs(); } return dec; } VP8StatusCode VP8Status(VP8Decoder* const dec) { if (!dec) return VP8_STATUS_INVALID_PARAM; - return dec->status_; + return dec->status; } const char* VP8StatusMessage(VP8Decoder* const dec) { if (dec == NULL) return "no object"; - if (!dec->error_msg_) return "OK"; - return dec->error_msg_; + if (!dec->error_msg) return "OK"; + return dec->error_msg; } void VP8Delete(VP8Decoder* const dec) { if (dec != NULL) { VP8Clear(dec); @@ -85,16 +96,16 @@ } int VP8SetError(VP8Decoder* const dec, VP8StatusCode error, const char* const msg) { // VP8_STATUS_SUSPENDED is only meaningful in incremental decoding. - assert(dec->incremental_ || error != VP8_STATUS_SUSPENDED); + assert(dec->incremental || error != VP8_STATUS_SUSPENDED); // The oldest error reported takes precedence over the new one. - if (dec->status_ == VP8_STATUS_OK) { - dec->status_ = error; - dec->error_msg_ = msg; - dec->ready_ = 0; + if (dec->status == VP8_STATUS_OK) { + dec->status = error; + dec->error_msg = msg; + dec->ready = 0; } return 0; } //------------------------------------------------------------------------------ @@ -149,48 +160,48 @@ //------------------------------------------------------------------------------ // Header parsing static void ResetSegmentHeader(VP8SegmentHeader* const hdr) { assert(hdr != NULL); - hdr->use_segment_ = 0; - hdr->update_map_ = 0; - hdr->absolute_delta_ = 1; - memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_)); - memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_)); + hdr->use_segment = 0; + hdr->update_map = 0; + hdr->absolute_delta = 1; + memset(hdr->quantizer, 0, sizeof(hdr->quantizer)); + memset(hdr->filter_strength, 0, sizeof(hdr->filter_strength)); } // Paragraph 9.3 static int ParseSegmentHeader(VP8BitReader* br, VP8SegmentHeader* hdr, VP8Proba* proba) { assert(br != NULL); assert(hdr != NULL); - hdr->use_segment_ = VP8Get(br, "global-header"); - if (hdr->use_segment_) { - hdr->update_map_ = VP8Get(br, "global-header"); + hdr->use_segment = VP8Get(br, "global-header"); + if (hdr->use_segment) { + hdr->update_map = VP8Get(br, "global-header"); if (VP8Get(br, "global-header")) { // update data int s; - hdr->absolute_delta_ = VP8Get(br, "global-header"); + hdr->absolute_delta = VP8Get(br, "global-header"); for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - hdr->quantizer_[s] = VP8Get(br, "global-header") ? + hdr->quantizer[s] = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 7, "global-header") : 0; } for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - hdr->filter_strength_[s] = VP8Get(br, "global-header") ? + hdr->filter_strength[s] = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 6, "global-header") : 0; } } - if (hdr->update_map_) { + if (hdr->update_map) { int s; for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) { - proba->segments_[s] = VP8Get(br, "global-header") ? + proba->segments[s] = VP8Get(br, "global-header") ? VP8GetValue(br, 8, "global-header") : 255u; } } } else { - hdr->update_map_ = 0; + hdr->update_map = 0; } - return !br->eof_; + return !br->eof; } // Paragraph 9.5 // If we don't have all the necessary data in 'buf', this function returns // VP8_STATUS_SUSPENDED in incremental decoding, VP8_STATUS_NOT_ENOUGH_DATA @@ -200,65 +211,65 @@ // If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA // is returned, and this is an unrecoverable error. // If the partitions were positioned ok, VP8_STATUS_OK is returned. static VP8StatusCode ParsePartitions(VP8Decoder* const dec, const uint8_t* buf, size_t size) { - VP8BitReader* const br = &dec->br_; + VP8BitReader* const br = &dec->br; const uint8_t* sz = buf; const uint8_t* buf_end = buf + size; const uint8_t* part_start; size_t size_left = size; size_t last_part; size_t p; - dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2, "global-header")) - 1; - last_part = dec->num_parts_minus_one_; + dec->num_parts_minus_one = (1 << VP8GetValue(br, 2, "global-header")) - 1; + last_part = dec->num_parts_minus_one; if (size < 3 * last_part) { // we can't even read the sizes with sz[]! That's a failure. return VP8_STATUS_NOT_ENOUGH_DATA; } part_start = buf + last_part * 3; size_left -= last_part * 3; for (p = 0; p < last_part; ++p) { size_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16); if (psize > size_left) psize = size_left; - VP8InitBitReader(dec->parts_ + p, part_start, psize); + VP8InitBitReader(dec->parts + p, part_start, psize); part_start += psize; size_left -= psize; sz += 3; } - VP8InitBitReader(dec->parts_ + last_part, part_start, size_left); + VP8InitBitReader(dec->parts + last_part, part_start, size_left); if (part_start < buf_end) return VP8_STATUS_OK; - return dec->incremental_ + return dec->incremental ? VP8_STATUS_SUSPENDED // Init is ok, but there's not enough data : VP8_STATUS_NOT_ENOUGH_DATA; } // Paragraph 9.4 static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) { - VP8FilterHeader* const hdr = &dec->filter_hdr_; - hdr->simple_ = VP8Get(br, "global-header"); - hdr->level_ = VP8GetValue(br, 6, "global-header"); - hdr->sharpness_ = VP8GetValue(br, 3, "global-header"); - hdr->use_lf_delta_ = VP8Get(br, "global-header"); - if (hdr->use_lf_delta_) { + VP8FilterHeader* const hdr = &dec->filter_hdr; + hdr->simple = VP8Get(br, "global-header"); + hdr->level = VP8GetValue(br, 6, "global-header"); + hdr->sharpness = VP8GetValue(br, 3, "global-header"); + hdr->use_lf_delta = VP8Get(br, "global-header"); + if (hdr->use_lf_delta) { if (VP8Get(br, "global-header")) { // update lf-delta? int i; for (i = 0; i < NUM_REF_LF_DELTAS; ++i) { if (VP8Get(br, "global-header")) { - hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header"); + hdr->ref_lf_delta[i] = VP8GetSignedValue(br, 6, "global-header"); } } for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) { if (VP8Get(br, "global-header")) { - hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header"); + hdr->mode_lf_delta[i] = VP8GetSignedValue(br, 6, "global-header"); } } } } - dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2; - return !br->eof_; + dec->filter_type = (hdr->level == 0) ? 0 : hdr->simple ? 1 : 2; + return !br->eof; } // Topmost call int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { const uint8_t* buf; @@ -284,52 +295,52 @@ } // Paragraph 9.1 { const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16); - frm_hdr = &dec->frm_hdr_; - frm_hdr->key_frame_ = !(bits & 1); - frm_hdr->profile_ = (bits >> 1) & 7; - frm_hdr->show_ = (bits >> 4) & 1; - frm_hdr->partition_length_ = (bits >> 5); - if (frm_hdr->profile_ > 3) { + frm_hdr = &dec->frm_hdr; + frm_hdr->key_frame = !(bits & 1); + frm_hdr->profile = (bits >> 1) & 7; + frm_hdr->show = (bits >> 4) & 1; + frm_hdr->partition_length = (bits >> 5); + if (frm_hdr->profile > 3) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Incorrect keyframe parameters."); } - if (!frm_hdr->show_) { + if (!frm_hdr->show) { return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, "Frame not displayable."); } buf += 3; buf_size -= 3; } - pic_hdr = &dec->pic_hdr_; - if (frm_hdr->key_frame_) { + pic_hdr = &dec->pic_hdr; + if (frm_hdr->key_frame) { // Paragraph 9.2 if (buf_size < 7) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "cannot parse picture header"); } if (!VP8CheckSignature(buf, buf_size)) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Bad code word"); } - pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff; - pic_hdr->xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2 - pic_hdr->height_ = ((buf[6] << 8) | buf[5]) & 0x3fff; - pic_hdr->yscale_ = buf[6] >> 6; + pic_hdr->width = ((buf[4] << 8) | buf[3]) & 0x3fff; + pic_hdr->xscale = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2 + pic_hdr->height = ((buf[6] << 8) | buf[5]) & 0x3fff; + pic_hdr->yscale = buf[6] >> 6; buf += 7; buf_size -= 7; - dec->mb_w_ = (pic_hdr->width_ + 15) >> 4; - dec->mb_h_ = (pic_hdr->height_ + 15) >> 4; + dec->mb_w = (pic_hdr->width + 15) >> 4; + dec->mb_h = (pic_hdr->height + 15) >> 4; // Setup default output area (can be later modified during io->setup()) - io->width = pic_hdr->width_; - io->height = pic_hdr->height_; - // IMPORTANT! use some sane dimensions in crop_* and scaled_* fields. + io->width = pic_hdr->width; + io->height = pic_hdr->height; + // IMPORTANT! use some sane dimensions in crop* and scaled* fields. // So they can be used interchangeably without always testing for // 'use_cropping'. io->use_cropping = 0; io->crop_top = 0; io->crop_left = 0; @@ -340,31 +351,31 @@ io->scaled_height = io->height; io->mb_w = io->width; // for soundness io->mb_h = io->height; // ditto - VP8ResetProba(&dec->proba_); - ResetSegmentHeader(&dec->segment_hdr_); + VP8ResetProba(&dec->proba); + ResetSegmentHeader(&dec->segment_hdr); } - // Check if we have all the partition #0 available, and initialize dec->br_ + // Check if we have all the partition #0 available, and initialize dec->br // to read this partition (and this partition only). - if (frm_hdr->partition_length_ > buf_size) { + if (frm_hdr->partition_length > buf_size) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "bad partition length"); } - br = &dec->br_; - VP8InitBitReader(br, buf, frm_hdr->partition_length_); - buf += frm_hdr->partition_length_; - buf_size -= frm_hdr->partition_length_; + br = &dec->br; + VP8InitBitReader(br, buf, frm_hdr->partition_length); + buf += frm_hdr->partition_length; + buf_size -= frm_hdr->partition_length; - if (frm_hdr->key_frame_) { - pic_hdr->colorspace_ = VP8Get(br, "global-header"); - pic_hdr->clamp_type_ = VP8Get(br, "global-header"); + if (frm_hdr->key_frame) { + pic_hdr->colorspace = VP8Get(br, "global-header"); + pic_hdr->clamp_type = VP8Get(br, "global-header"); } - if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) { + if (!ParseSegmentHeader(br, &dec->segment_hdr, &dec->proba)) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "cannot parse segment header"); } // Filter specs if (!ParseFilterHeader(br, dec)) { @@ -378,21 +389,21 @@ // quantizer change VP8ParseQuant(dec); // Frame buffer marking - if (!frm_hdr->key_frame_) { + if (!frm_hdr->key_frame) { return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, "Not a key frame."); } - VP8Get(br, "global-header"); // ignore the value of update_proba_ + VP8Get(br, "global-header"); // ignore the value of 'update_proba' VP8ParseProba(br, dec); // sanitized state - dec->ready_ = 1; + dec->ready = 1; return 1; } //------------------------------------------------------------------------------ // Residual decoding (Paragraph 13.2 / 13.3) @@ -441,21 +452,21 @@ // Returns the position of the last non-zero coeff plus one static int GetCoeffsFast(VP8BitReader* const br, const VP8BandProbas* const prob[], int ctx, const quant_t dq, int n, int16_t* out) { - const uint8_t* p = prob[n]->probas_[ctx]; + const uint8_t* p = prob[n]->probas[ctx]; for (; n < 16; ++n) { if (!VP8GetBit(br, p[0], "coeffs")) { return n; // previous coeff was last non-zero coeff } while (!VP8GetBit(br, p[1], "coeffs")) { // sequence of zero coeffs - p = prob[++n]->probas_[0]; + p = prob[++n]->probas[0]; if (n == 16) return 16; } { // non zero coeff - const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; + const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas[0]; int v; if (!VP8GetBit(br, p[2], "coeffs")) { v = 1; p = p_ctx[1]; } else { @@ -471,21 +482,21 @@ // This version of GetCoeffs() uses VP8GetBitAlt() which is an alternate version // of VP8GetBitAlt() targeting specific platforms. static int GetCoeffsAlt(VP8BitReader* const br, const VP8BandProbas* const prob[], int ctx, const quant_t dq, int n, int16_t* out) { - const uint8_t* p = prob[n]->probas_[ctx]; + const uint8_t* p = prob[n]->probas[ctx]; for (; n < 16; ++n) { if (!VP8GetBitAlt(br, p[0], "coeffs")) { return n; // previous coeff was last non-zero coeff } while (!VP8GetBitAlt(br, p[1], "coeffs")) { // sequence of zero coeffs - p = prob[++n]->probas_[0]; + p = prob[++n]->probas[0]; if (n == 16) return 16; } { // non zero coeff - const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; + const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas[0]; int v; if (!VP8GetBitAlt(br, p[2], "coeffs")) { v = 1; p = p_ctx[1]; } else { @@ -514,29 +525,29 @@ return nz_coeffs; } static int ParseResiduals(VP8Decoder* const dec, VP8MB* const mb, VP8BitReader* const token_br) { - const VP8BandProbas* (* const bands)[16 + 1] = dec->proba_.bands_ptr_; + const VP8BandProbas* (* const bands)[16 + 1] = dec->proba.bands_ptr; const VP8BandProbas* const * ac_proba; - VP8MBData* const block = dec->mb_data_ + dec->mb_x_; - const VP8QuantMatrix* const q = &dec->dqm_[block->segment_]; - int16_t* dst = block->coeffs_; - VP8MB* const left_mb = dec->mb_info_ - 1; + VP8MBData* const block = dec->mb_data + dec->mb_x; + const VP8QuantMatrix* const q = &dec->dqm[block->segment]; + int16_t* dst = block->coeffs; + VP8MB* const left_mb = dec->mb_info - 1; uint8_t tnz, lnz; uint32_t non_zero_y = 0; uint32_t non_zero_uv = 0; int x, y, ch; uint32_t out_t_nz, out_l_nz; int first; memset(dst, 0, 384 * sizeof(*dst)); - if (!block->is_i4x4_) { // parse DC + if (!block->is_i4x4) { // parse DC int16_t dc[16] = { 0 }; - const int ctx = mb->nz_dc_ + left_mb->nz_dc_; - const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat_, 0, dc); - mb->nz_dc_ = left_mb->nz_dc_ = (nz > 0); + const int ctx = mb->nz_dc + left_mb->nz_dc; + const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat, 0, dc); + mb->nz_dc = left_mb->nz_dc = (nz > 0); if (nz > 1) { // more than just the DC -> perform the full transform VP8TransformWHT(dc, dst); } else { // only DC is non-zero -> inlined simplified transform int i; const int dc0 = (dc[0] + 3) >> 3; @@ -547,18 +558,18 @@ } else { first = 0; ac_proba = bands[3]; } - tnz = mb->nz_ & 0x0f; - lnz = left_mb->nz_ & 0x0f; + tnz = mb->nz & 0x0f; + lnz = left_mb->nz & 0x0f; for (y = 0; y < 4; ++y) { int l = lnz & 1; uint32_t nz_coeffs = 0; for (x = 0; x < 4; ++x) { const int ctx = l + (tnz & 1); - const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat_, first, dst); + const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat, first, dst); l = (nz > first); tnz = (tnz >> 1) | (l << 7); nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0); dst += 16; } @@ -569,17 +580,17 @@ out_t_nz = tnz; out_l_nz = lnz >> 4; for (ch = 0; ch < 4; ch += 2) { uint32_t nz_coeffs = 0; - tnz = mb->nz_ >> (4 + ch); - lnz = left_mb->nz_ >> (4 + ch); + tnz = mb->nz >> (4 + ch); + lnz = left_mb->nz >> (4 + ch); for (y = 0; y < 2; ++y) { int l = lnz & 1; for (x = 0; x < 2; ++x) { const int ctx = l + (tnz & 1); - const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat_, 0, dst); + const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat, 0, dst); l = (nz > 0); tnz = (tnz >> 1) | (l << 3); nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0); dst += 16; } @@ -589,72 +600,72 @@ // Note: we don't really need the per-4x4 details for U/V blocks. non_zero_uv |= nz_coeffs << (4 * ch); out_t_nz |= (tnz << 4) << ch; out_l_nz |= (lnz & 0xf0) << ch; } - mb->nz_ = out_t_nz; - left_mb->nz_ = out_l_nz; + mb->nz = out_t_nz; + left_mb->nz = out_l_nz; - block->non_zero_y_ = non_zero_y; - block->non_zero_uv_ = non_zero_uv; + block->non_zero_y = non_zero_y; + block->non_zero_uv = non_zero_uv; // We look at the mode-code of each block and check if some blocks have less // than three non-zero coeffs (code < 2). This is to avoid dithering flat and // empty blocks. - block->dither_ = (non_zero_uv & 0xaaaa) ? 0 : q->dither_; + block->dither = (non_zero_uv & 0xaaaa) ? 0 : q->dither; return !(non_zero_y | non_zero_uv); // will be used for further optimization } //------------------------------------------------------------------------------ // Main loop int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) { - VP8MB* const left = dec->mb_info_ - 1; - VP8MB* const mb = dec->mb_info_ + dec->mb_x_; - VP8MBData* const block = dec->mb_data_ + dec->mb_x_; - int skip = dec->use_skip_proba_ ? block->skip_ : 0; + VP8MB* const left = dec->mb_info - 1; + VP8MB* const mb = dec->mb_info + dec->mb_x; + VP8MBData* const block = dec->mb_data + dec->mb_x; + int skip = dec->use_skip_proba ? block->skip : 0; if (!skip) { skip = ParseResiduals(dec, mb, token_br); } else { - left->nz_ = mb->nz_ = 0; - if (!block->is_i4x4_) { - left->nz_dc_ = mb->nz_dc_ = 0; + left->nz = mb->nz = 0; + if (!block->is_i4x4) { + left->nz_dc = mb->nz_dc = 0; } - block->non_zero_y_ = 0; - block->non_zero_uv_ = 0; - block->dither_ = 0; + block->non_zero_y = 0; + block->non_zero_uv = 0; + block->dither = 0; } - if (dec->filter_type_ > 0) { // store filter info - VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_; - *finfo = dec->fstrengths_[block->segment_][block->is_i4x4_]; - finfo->f_inner_ |= !skip; + if (dec->filter_type > 0) { // store filter info + VP8FInfo* const finfo = dec->f_info + dec->mb_x; + *finfo = dec->fstrengths[block->segment][block->is_i4x4]; + finfo->f_inner |= !skip; } - return !token_br->eof_; + return !token_br->eof; } void VP8InitScanline(VP8Decoder* const dec) { - VP8MB* const left = dec->mb_info_ - 1; - left->nz_ = 0; - left->nz_dc_ = 0; - memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_)); - dec->mb_x_ = 0; + VP8MB* const left = dec->mb_info - 1; + left->nz = 0; + left->nz_dc = 0; + memset(dec->intra_l, B_DC_PRED, sizeof(dec->intra_l)); + dec->mb_x = 0; } static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { - for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) { + for (dec->mb_y = 0; dec->mb_y < dec->br_mb_y; ++dec->mb_y) { // Parse bitstream for this row. VP8BitReader* const token_br = - &dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_]; - if (!VP8ParseIntraModeRow(&dec->br_, dec)) { + &dec->parts[dec->mb_y & dec->num_parts_minus_one]; + if (!VP8ParseIntraModeRow(&dec->br, dec)) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Premature end-of-partition0 encountered."); } - for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { + for (; dec->mb_x < dec->mb_w; ++dec->mb_x) { if (!VP8DecodeMB(dec, token_br)) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Premature end-of-file encountered."); } } @@ -663,12 +674,12 @@ // Reconstruct, filter and emit the row. if (!VP8ProcessRow(dec, io)) { return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted."); } } - if (dec->mt_method_ > 0) { - if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) return 0; + if (dec->mt_method > 0) { + if (!WebPGetWorkerInterface()->Sync(&dec->worker)) return 0; } return 1; } @@ -681,16 +692,16 @@ if (io == NULL) { return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, "NULL VP8Io parameter in VP8Decode()."); } - if (!dec->ready_) { + if (!dec->ready) { if (!VP8GetHeaders(dec, io)) { return 0; } } - assert(dec->ready_); + assert(dec->ready); // Finish setting up the decoding parameter. Will call io->setup(). ok = (VP8EnterCritical(dec, io) == VP8_STATUS_OK); if (ok) { // good to go. // Will allocate memory and prepare everything. @@ -706,23 +717,23 @@ if (!ok) { VP8Clear(dec); return 0; } - dec->ready_ = 0; + dec->ready = 0; return ok; } void VP8Clear(VP8Decoder* const dec) { if (dec == NULL) { return; } - WebPGetWorkerInterface()->End(&dec->worker_); + WebPGetWorkerInterface()->End(&dec->worker); WebPDeallocateAlphaMemory(dec); - WebPSafeFree(dec->mem_); - dec->mem_ = NULL; - dec->mem_size_ = 0; - memset(&dec->br_, 0, sizeof(dec->br_)); - dec->ready_ = 0; + WebPSafeFree(dec->mem); + dec->mem = NULL; + dec->mem_size = 0; + memset(&dec->br, 0, sizeof(dec->br)); + dec->ready = 0; } //------------------------------------------------------------------------------ diff --git a/media/libwebp/src/dec/vp8i_dec.h b/media/libwebp/src/dec/vp8i_dec.h --- a/media/libwebp/src/dec/vp8i_dec.h +++ b/media/libwebp/src/dec/vp8i_dec.h @@ -13,16 +13,20 @@ #ifndef WEBP_DEC_VP8I_DEC_H_ #define WEBP_DEC_VP8I_DEC_H_ #include // for memcpy() + #include "src/dec/common_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/dsp/dsp.h" #include "src/utils/bit_reader_utils.h" #include "src/utils/random_utils.h" #include "src/utils/thread_utils.h" -#include "src/dsp/dsp.h" +#include "src/webp/decode.h" #include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif @@ -30,11 +34,11 @@ //------------------------------------------------------------------------------ // Various defines and enums // version numbers #define DEC_MAJ_VERSION 1 -#define DEC_MIN_VERSION 5 +#define DEC_MIN_VERSION 6 #define DEC_REV_VERSION 0 // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // Constraints are: We need to store one 16x16 block of luma samples (y), // and two 8x8 chroma blocks (u/v). These are better be 16-bytes aligned, @@ -67,111 +71,111 @@ //------------------------------------------------------------------------------ // Headers typedef struct { - uint8_t key_frame_; - uint8_t profile_; - uint8_t show_; - uint32_t partition_length_; + uint8_t key_frame; + uint8_t profile; + uint8_t show; + uint32_t partition_length; } VP8FrameHeader; typedef struct { - uint16_t width_; - uint16_t height_; - uint8_t xscale_; - uint8_t yscale_; - uint8_t colorspace_; // 0 = YCbCr - uint8_t clamp_type_; + uint16_t width; + uint16_t height; + uint8_t xscale; + uint8_t yscale; + uint8_t colorspace; // 0 = YCbCr + uint8_t clamp_type; } VP8PictureHeader; // segment features typedef struct { - int use_segment_; - int update_map_; // whether to update the segment map or not - int absolute_delta_; // absolute or delta values for quantizer and filter - int8_t quantizer_[NUM_MB_SEGMENTS]; // quantization changes - int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments + int use_segment; + int update_map; // whether to update the segment map or not + int absolute_delta; // absolute or delta values for quantizer and filter + int8_t quantizer[NUM_MB_SEGMENTS]; // quantization changes + int8_t filter_strength[NUM_MB_SEGMENTS]; // filter strength for segments } VP8SegmentHeader; // probas associated to one of the contexts typedef uint8_t VP8ProbaArray[NUM_PROBAS]; typedef struct { // all the probas associated to one band - VP8ProbaArray probas_[NUM_CTX]; + VP8ProbaArray probas[NUM_CTX]; } VP8BandProbas; // Struct collecting all frame-persistent probabilities. typedef struct { - uint8_t segments_[MB_FEATURE_TREE_PROBS]; + uint8_t segments[MB_FEATURE_TREE_PROBS]; // Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4 - VP8BandProbas bands_[NUM_TYPES][NUM_BANDS]; - const VP8BandProbas* bands_ptr_[NUM_TYPES][16 + 1]; + VP8BandProbas bands[NUM_TYPES][NUM_BANDS]; + const VP8BandProbas* bands_ptr[NUM_TYPES][16 + 1]; } VP8Proba; // Filter parameters typedef struct { - int simple_; // 0=complex, 1=simple - int level_; // [0..63] - int sharpness_; // [0..7] - int use_lf_delta_; - int ref_lf_delta_[NUM_REF_LF_DELTAS]; - int mode_lf_delta_[NUM_MODE_LF_DELTAS]; + int simple; // 0=complex, 1=simple + int level; // [0..63] + int sharpness; // [0..7] + int use_lf_delta; + int ref_lf_delta[NUM_REF_LF_DELTAS]; + int mode_lf_delta[NUM_MODE_LF_DELTAS]; } VP8FilterHeader; //------------------------------------------------------------------------------ // Informations about the macroblocks. typedef struct { // filter specs - uint8_t f_limit_; // filter limit in [3..189], or 0 if no filtering - uint8_t f_ilevel_; // inner limit in [1..63] - uint8_t f_inner_; // do inner filtering? - uint8_t hev_thresh_; // high edge variance threshold in [0..2] + uint8_t f_limit; // filter limit in [3..189], or 0 if no filtering + uint8_t f_ilevel; // inner limit in [1..63] + uint8_t f_inner; // do inner filtering? + uint8_t hev_thresh; // high edge variance threshold in [0..2] } VP8FInfo; typedef struct { // Top/Left Contexts used for syntax-parsing - uint8_t nz_; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma) - uint8_t nz_dc_; // non-zero DC coeff (1bit) + uint8_t nz; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma) + uint8_t nz_dc; // non-zero DC coeff (1bit) } VP8MB; // Dequantization matrices typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower). typedef struct { - quant_t y1_mat_, y2_mat_, uv_mat_; + quant_t y1_mat, y2_mat, uv_mat; - int uv_quant_; // U/V quantizer value - int dither_; // dithering amplitude (0 = off, max=255) + int uv_quant; // U/V quantizer value + int dither; // dithering amplitude (0 = off, max=255) } VP8QuantMatrix; // Data needed to reconstruct a macroblock typedef struct { - int16_t coeffs_[384]; // 384 coeffs = (16+4+4) * 4*4 - uint8_t is_i4x4_; // true if intra4x4 - uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes - uint8_t uvmode_; // chroma prediction mode + int16_t coeffs[384]; // 384 coeffs = (16+4+4) * 4*4 + uint8_t is_i4x4; // true if intra4x4 + uint8_t imodes[16]; // one 16x16 mode (#0) or sixteen 4x4 modes + uint8_t uvmode; // chroma prediction mode // bit-wise info about the content of each sub-4x4 blocks (in decoding order). // Each of the 4x4 blocks for y/u/v is associated with a 2b code according to: // code=0 -> no coefficient // code=1 -> only DC // code=2 -> first three coefficients are non-zero // code=3 -> more than three coefficients are non-zero // This allows to call specialized transform functions. - uint32_t non_zero_y_; - uint32_t non_zero_uv_; - uint8_t dither_; // local dithering strength (deduced from non_zero_*) - uint8_t skip_; - uint8_t segment_; + uint32_t non_zero_y; + uint32_t non_zero_uv; + uint8_t dither; // local dithering strength (deduced from non_zero*) + uint8_t skip; + uint8_t segment; } VP8MBData; // Persistent information needed by the parallel processing typedef struct { - int id_; // cache row to process (in [0..2]) - int mb_y_; // macroblock position of the row - int filter_row_; // true if row-filtering is needed - VP8FInfo* f_info_; // filter strengths (swapped with dec->f_info_) - VP8MBData* mb_data_; // reconstruction data (swapped with dec->mb_data_) - VP8Io io_; // copy of the VP8Io to pass to put() + int id; // cache row to process (in [0..2]) + int mb_y; // macroblock position of the row + int filter_row; // true if row-filtering is needed + VP8FInfo* f_info; // filter strengths (swapped with dec->f_info) + VP8MBData* mb_data; // reconstruction data (swapped with dec->mb_data) + VP8Io io; // copy of the VP8Io to pass to put() } VP8ThreadContext; // Saved top samples, per macroblock. Fits into a cache-line. typedef struct { uint8_t y[16], u[8], v[8]; @@ -179,93 +183,93 @@ //------------------------------------------------------------------------------ // VP8Decoder: the main opaque structure handed over to user struct VP8Decoder { - VP8StatusCode status_; - int ready_; // true if ready to decode a picture with VP8Decode() - const char* error_msg_; // set when status_ is not OK. + VP8StatusCode status; + int ready; // true if ready to decode a picture with VP8Decode() + const char* error_msg; // set when status is not OK. // Main data source - VP8BitReader br_; - int incremental_; // if true, incremental decoding is expected + VP8BitReader br; + int incremental; // if true, incremental decoding is expected // headers - VP8FrameHeader frm_hdr_; - VP8PictureHeader pic_hdr_; - VP8FilterHeader filter_hdr_; - VP8SegmentHeader segment_hdr_; + VP8FrameHeader frm_hdr; + VP8PictureHeader pic_hdr; + VP8FilterHeader filter_hdr; + VP8SegmentHeader segment_hdr; // Worker - WebPWorker worker_; - int mt_method_; // multi-thread method: 0=off, 1=[parse+recon][filter] - // 2=[parse][recon+filter] - int cache_id_; // current cache row - int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3) - VP8ThreadContext thread_ctx_; // Thread context + WebPWorker worker; + int mt_method; // multi-thread method: 0=off, 1=[parse+recon][filter] + // 2=[parse][recon+filter] + int cache_id; // current cache row + int num_caches; // number of cached rows of 16 pixels (1, 2 or 3) + VP8ThreadContext thread_ctx; // Thread context // dimension, in macroblock units. - int mb_w_, mb_h_; + int mb_w, mb_h; // Macroblock to process/filter, depending on cropping and filter_type. - int tl_mb_x_, tl_mb_y_; // top-left MB that must be in-loop filtered - int br_mb_x_, br_mb_y_; // last bottom-right MB that must be decoded + int tl_mb_x, tl_mb_y; // top-left MB that must be in-loop filtered + int br_mb_x, br_mb_y; // last bottom-right MB that must be decoded // number of partitions minus one. - uint32_t num_parts_minus_one_; + uint32_t num_parts_minus_one; // per-partition boolean decoders. - VP8BitReader parts_[MAX_NUM_PARTITIONS]; + VP8BitReader parts[MAX_NUM_PARTITIONS]; // Dithering strength, deduced from decoding options - int dither_; // whether to use dithering or not - VP8Random dithering_rg_; // random generator for dithering + int dither; // whether to use dithering or not + VP8Random dithering_rg; // random generator for dithering // dequantization (one set of DC/AC dequant factor per segment) - VP8QuantMatrix dqm_[NUM_MB_SEGMENTS]; + VP8QuantMatrix dqm[NUM_MB_SEGMENTS]; // probabilities - VP8Proba proba_; - int use_skip_proba_; - uint8_t skip_p_; + VP8Proba proba; + int use_skip_proba; + uint8_t skip_p; // Boundary data cache and persistent buffers. - uint8_t* intra_t_; // top intra modes values: 4 * mb_w_ - uint8_t intra_l_[4]; // left intra modes values + uint8_t* intra_t; // top intra modes values: 4 * mb_w + uint8_t intra_l[4]; // left intra modes values - VP8TopSamples* yuv_t_; // top y/u/v samples + VP8TopSamples* yuv_t; // top y/u/v samples - VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1) - VP8FInfo* f_info_; // filter strength info - uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE) + VP8MB* mb_info; // contextual macroblock info (mb_w + 1) + VP8FInfo* f_info; // filter strength info + uint8_t* yuv_b; // main block for Y/U/V (size = YUV_SIZE) - uint8_t* cache_y_; // macroblock row for storing unfiltered samples - uint8_t* cache_u_; - uint8_t* cache_v_; - int cache_y_stride_; - int cache_uv_stride_; + uint8_t* cache_y; // macroblock row for storing unfiltered samples + uint8_t* cache_u; + uint8_t* cache_v; + int cache_y_stride; + int cache_uv_stride; // main memory chunk for the above data. Persistent. - void* mem_; - size_t mem_size_; + void* mem; + size_t mem_size; // Per macroblock non-persistent infos. - int mb_x_, mb_y_; // current position, in macroblock units - VP8MBData* mb_data_; // parsed reconstruction data + int mb_x, mb_y; // current position, in macroblock units + VP8MBData* mb_data; // parsed reconstruction data // Filtering side-info - int filter_type_; // 0=off, 1=simple, 2=complex - VP8FInfo fstrengths_[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type + int filter_type; // 0=off, 1=simple, 2=complex + VP8FInfo fstrengths[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type // Alpha - struct ALPHDecoder* alph_dec_; // alpha-plane decoder object - const uint8_t* alpha_data_; // compressed alpha data (if present) - size_t alpha_data_size_; - int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_ - uint8_t* alpha_plane_mem_; // memory allocated for alpha_plane_ - uint8_t* alpha_plane_; // output. Persistent, contains the whole data. - const uint8_t* alpha_prev_line_; // last decoded alpha row (or NULL) - int alpha_dithering_; // derived from decoding options (0=off, 100=full) + struct ALPHDecoder* alph_dec; // alpha-plane decoder object + const uint8_t* alpha_data; // compressed alpha data (if present) + size_t alpha_data_size; + int is_alpha_decoded; // true if alpha_data is decoded in alpha_plane + uint8_t* alpha_plane_mem; // memory allocated for alpha_plane + uint8_t* alpha_plane; // output. Persistent, contains the whole data. + const uint8_t* alpha_prev_line; // last decoded alpha row (or NULL) + int alpha_dithering; // derived from decoding options (0=off, 100=full) }; //------------------------------------------------------------------------------ // internal functions. Not public. diff --git a/media/libwebp/src/dec/vp8l_dec.c b/media/libwebp/src/dec/vp8l_dec.c --- a/media/libwebp/src/dec/vp8l_dec.c +++ b/media/libwebp/src/dec/vp8l_dec.c @@ -11,20 +11,29 @@ // // Authors: Vikas Arora (vikaas.arora@gmail.com) // Jyrki Alakuijala (jyrki@google.com) #include +#include #include +#include #include "src/dec/alphai_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" #include "src/dsp/dsp.h" #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/color_cache_utils.h" #include "src/utils/huffman_utils.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" #include "src/webp/format_constants.h" +#include "src/webp/types.h" #define NUM_ARGB_CACHE_ROWS 16 static const int kCodeLengthLiterals = 16; static const int kCodeLengthRepeatCode = 16; @@ -101,12 +110,12 @@ FIXED_TABLE_SIZE + 2704 }; static int VP8LSetError(VP8LDecoder* const dec, VP8StatusCode error) { // The oldest error reported takes precedence over the new one. - if (dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED) { - dec->status_ = error; + if (dec->status == VP8_STATUS_OK || dec->status == VP8_STATUS_SUSPENDED) { + dec->status = error; } return 0; } static int DecodeImageStream(int xsize, int ysize, @@ -128,11 +137,11 @@ if (VP8LReadBits(br, 8) != VP8L_MAGIC_BYTE) return 0; *width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; *height = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; *has_alpha = VP8LReadBits(br, 1); if (VP8LReadBits(br, VP8L_VERSION_BITS) != 0) return 0; - return !br->eos_; + return !br->eos; } int VP8LGetInfo(const uint8_t* data, size_t data_size, int* const width, int* const height, int* const has_alpha) { if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) { @@ -193,16 +202,16 @@ int nbits; uint32_t val = VP8LPrefetchBits(br); table += val & HUFFMAN_TABLE_MASK; nbits = table->bits - HUFFMAN_TABLE_BITS; if (nbits > 0) { - VP8LSetBitPos(br, br->bit_pos_ + HUFFMAN_TABLE_BITS); + VP8LSetBitPos(br, br->bit_pos + HUFFMAN_TABLE_BITS); val = VP8LPrefetchBits(br); table += table->value; table += val & ((1 << nbits) - 1); } - VP8LSetBitPos(br, br->bit_pos_ + table->bits); + VP8LSetBitPos(br, br->bit_pos + table->bits); return table->value; } // Reads packed symbol depending on GREEN channel #define BITS_SPECIAL_MARKER 0x100 // something large enough (and a bit-mask) @@ -212,15 +221,15 @@ uint32_t* const dst) { const uint32_t val = VP8LPrefetchBits(br) & (HUFFMAN_PACKED_TABLE_SIZE - 1); const HuffmanCode32 code = group->packed_table[val]; assert(group->use_packed_table); if (code.bits < BITS_SPECIAL_MARKER) { - VP8LSetBitPos(br, br->bit_pos_ + code.bits); + VP8LSetBitPos(br, br->bit_pos + code.bits); *dst = code.value; return PACKED_NON_LITERAL_CODE; } else { - VP8LSetBitPos(br, br->bit_pos_ + code.bits - BITS_SPECIAL_MARKER); + VP8LSetBitPos(br, br->bit_pos + code.bits - BITS_SPECIAL_MARKER); assert(code.value >= NUM_LITERAL_CODES); return code.value; } } @@ -255,11 +264,11 @@ static int ReadHuffmanCodeLengths( VP8LDecoder* const dec, const int* const code_length_code_lengths, int num_symbols, int* const code_lengths) { int ok = 0; - VP8LBitReader* const br = &dec->br_; + VP8LBitReader* const br = &dec->br; int symbol; int max_symbol; int prev_code_len = DEFAULT_CODE_LENGTH; HuffmanTables tables; @@ -284,11 +293,11 @@ const HuffmanCode* p; int code_len; if (max_symbol-- == 0) break; VP8LFillBitWindow(br); p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; - VP8LSetBitPos(br, br->bit_pos_ + p->bits); + VP8LSetBitPos(br, br->bit_pos + p->bits); code_len = p->value; if (code_len < kCodeLengthLiterals) { code_lengths[symbol++] = code_len; if (code_len != 0) prev_code_len = code_len; } else { @@ -318,11 +327,11 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, int* const code_lengths, HuffmanTables* const table) { int ok = 0; int size = 0; - VP8LBitReader* const br = &dec->br_; + VP8LBitReader* const br = &dec->br; const int simple_code = VP8LReadBits(br, 1); memset(code_lengths, 0, alphabet_size * sizeof(*code_lengths)); if (simple_code) { // Read symbols, codes & code lengths directly. @@ -348,11 +357,11 @@ } ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size, code_lengths); } - ok = ok && !br->eos_; + ok = ok && !br->eos; if (ok) { size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS, code_lengths, alphabet_size); } if (!ok || size == 0) { @@ -362,15 +371,15 @@ } static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, int color_cache_bits, int allow_recursion) { int i; - VP8LBitReader* const br = &dec->br_; - VP8LMetadata* const hdr = &dec->hdr_; + VP8LBitReader* const br = &dec->br; + VP8LMetadata* const hdr = &dec->hdr; uint32_t* huffman_image = NULL; HTreeGroup* htree_groups = NULL; - HuffmanTables* huffman_tables = &hdr->huffman_tables_; + HuffmanTables* huffman_tables = &hdr->huffman_tables; int num_htree_groups = 1; int num_htree_groups_max = 1; int* mapping = NULL; int ok = 0; @@ -387,11 +396,11 @@ const int huffman_pixs = huffman_xsize * huffman_ysize; if (!DecodeImageStream(huffman_xsize, huffman_ysize, /*is_level0=*/0, dec, &huffman_image)) { goto Error; } - hdr->huffman_subsample_bits_ = huffman_precision; + hdr->huffman_subsample_bits = huffman_precision; for (i = 0; i < huffman_pixs; ++i) { // The huffman data is stored in red and green bytes. const int group = (huffman_image[i] >> 8) & 0xffff; huffman_image[i] = group; if (group >= num_htree_groups_max) { @@ -424,23 +433,23 @@ } else { num_htree_groups = num_htree_groups_max; } } - if (br->eos_) goto Error; + if (br->eos) goto Error; if (!ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups, num_htree_groups_max, mapping, dec, huffman_tables, &htree_groups)) { goto Error; } ok = 1; // All OK. Finalize pointers. - hdr->huffman_image_ = huffman_image; - hdr->num_htree_groups_ = num_htree_groups; - hdr->htree_groups_ = htree_groups; + hdr->huffman_image = huffman_image; + hdr->num_htree_groups = num_htree_groups; + hdr->htree_groups = htree_groups; Error: WebPSafeFree(mapping); if (!ok) { WebPSafeFree(huffman_image); @@ -618,16 +627,16 @@ // Emit scaled rows. static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec, uint8_t* in, int in_stride, int mb_h, uint8_t* const out, int out_stride) { - const WEBP_CSP_MODE colorspace = dec->output_->colorspace; + const WEBP_CSP_MODE colorspace = dec->output->colorspace; int num_lines_in = 0; int num_lines_out = 0; while (num_lines_in < mb_h) { - uint8_t* const row_in = in + (uint64_t)num_lines_in * in_stride; - uint8_t* const row_out = out + (uint64_t)num_lines_out * out_stride; + uint8_t* const row_in = in + (ptrdiff_t)num_lines_in * in_stride; + uint8_t* const row_out = out + (ptrdiff_t)num_lines_out * out_stride; const int lines_left = mb_h - num_lines_in; const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); int lines_imported; assert(needed_lines > 0 && needed_lines <= lines_left); WebPMultARGBRows(row_in, in_stride, @@ -693,21 +702,21 @@ const int dst_width = rescaler->dst_width; int num_lines_out = 0; while (WebPRescalerHasPendingOutput(rescaler)) { WebPRescalerExportRow(rescaler); WebPMultARGBRow(src, dst_width, 1); - ConvertToYUVA(src, dst_width, y_pos, dec->output_); + ConvertToYUVA(src, dst_width, y_pos, dec->output); ++y_pos; ++num_lines_out; } return num_lines_out; } static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec, uint8_t* in, int in_stride, int mb_h) { int num_lines_in = 0; - int y_pos = dec->last_out_row_; + int y_pos = dec->last_out_row; while (num_lines_in < mb_h) { const int lines_left = mb_h - num_lines_in; const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); int lines_imported; WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0); @@ -722,13 +731,13 @@ } static int EmitRowsYUVA(const VP8LDecoder* const dec, const uint8_t* in, int in_stride, int mb_w, int num_rows) { - int y_pos = dec->last_out_row_; + int y_pos = dec->last_out_row; while (num_rows-- > 0) { - ConvertToYUVA((const uint32_t*)in, mb_w, y_pos, dec->output_); + ConvertToYUVA((const uint32_t*)in, mb_w, y_pos, dec->output); in += in_stride; ++y_pos; } return y_pos; } @@ -771,33 +780,33 @@ return image[xsize * (y >> bits) + (x >> bits)]; } static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr, int x, int y) { - const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_, - hdr->huffman_subsample_bits_, x, y); - assert(meta_index < hdr->num_htree_groups_); - return hdr->htree_groups_ + meta_index; + const int meta_index = GetMetaIndex(hdr->huffman_image, hdr->huffman_xsize, + hdr->huffman_subsample_bits, x, y); + assert(meta_index < hdr->num_htree_groups); + return hdr->htree_groups + meta_index; } //------------------------------------------------------------------------------ // Main loop, with custom row-processing function typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row); static void ApplyInverseTransforms(VP8LDecoder* const dec, int start_row, int num_rows, const uint32_t* const rows) { - int n = dec->next_transform_; - const int cache_pixs = dec->width_ * num_rows; + int n = dec->next_transform; + const int cache_pixs = dec->width * num_rows; const int end_row = start_row + num_rows; const uint32_t* rows_in = rows; - uint32_t* const rows_out = dec->argb_cache_; + uint32_t* const rows_out = dec->argb_cache; // Inverse transforms. while (n-- > 0) { - VP8LTransform* const transform = &dec->transforms_[n]; + VP8LTransform* const transform = &dec->transforms[n]; VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); rows_in = rows_out; } if (rows_in != rows_out) { // No transform called, hence just copy. @@ -806,110 +815,110 @@ } // Processes (transforms, scales & color-converts) the rows decoded after the // last call. static void ProcessRows(VP8LDecoder* const dec, int row) { - const uint32_t* const rows = dec->pixels_ + dec->width_ * dec->last_row_; - const int num_rows = row - dec->last_row_; + const uint32_t* const rows = dec->pixels + dec->width * dec->last_row; + const int num_rows = row - dec->last_row; - assert(row <= dec->io_->crop_bottom); + assert(row <= dec->io->crop_bottom); // We can't process more than NUM_ARGB_CACHE_ROWS at a time (that's the size - // of argb_cache_), but we currently don't need more than that. + // of argb_cache), but we currently don't need more than that. assert(num_rows <= NUM_ARGB_CACHE_ROWS); if (num_rows > 0) { // Emit output. - VP8Io* const io = dec->io_; - uint8_t* rows_data = (uint8_t*)dec->argb_cache_; + VP8Io* const io = dec->io; + uint8_t* rows_data = (uint8_t*)dec->argb_cache; const int in_stride = io->width * sizeof(uint32_t); // in unit of RGBA - ApplyInverseTransforms(dec, dec->last_row_, num_rows, rows); - if (!SetCropWindow(io, dec->last_row_, row, &rows_data, in_stride)) { + ApplyInverseTransforms(dec, dec->last_row, num_rows, rows); + if (!SetCropWindow(io, dec->last_row, row, &rows_data, in_stride)) { // Nothing to output (this time). } else { - const WebPDecBuffer* const output = dec->output_; + const WebPDecBuffer* const output = dec->output; if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA const WebPRGBABuffer* const buf = &output->u.RGBA; uint8_t* const rgba = - buf->rgba + (int64_t)dec->last_out_row_ * buf->stride; + buf->rgba + (ptrdiff_t)dec->last_out_row * buf->stride; const int num_rows_out = #if !defined(WEBP_REDUCE_SIZE) io->use_scaling ? EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h, rgba, buf->stride) : #endif // WEBP_REDUCE_SIZE EmitRows(output->colorspace, rows_data, in_stride, io->mb_w, io->mb_h, rgba, buf->stride); - // Update 'last_out_row_'. - dec->last_out_row_ += num_rows_out; + // Update 'last_out_row'. + dec->last_out_row += num_rows_out; } else { // convert to YUVA - dec->last_out_row_ = io->use_scaling ? + dec->last_out_row = io->use_scaling ? EmitRescaledRowsYUVA(dec, rows_data, in_stride, io->mb_h) : EmitRowsYUVA(dec, rows_data, in_stride, io->mb_w, io->mb_h); } - assert(dec->last_out_row_ <= output->height); + assert(dec->last_out_row <= output->height); } } - // Update 'last_row_'. - dec->last_row_ = row; - assert(dec->last_row_ <= dec->height_); + // Update 'last_row'. + dec->last_row = row; + assert(dec->last_row <= dec->height); } // Row-processing for the special case when alpha data contains only one // transform (color indexing), and trivial non-green literals. static int Is8bOptimizable(const VP8LMetadata* const hdr) { int i; - if (hdr->color_cache_size_ > 0) return 0; + if (hdr->color_cache_size > 0) return 0; // When the Huffman tree contains only one symbol, we can skip the // call to ReadSymbol() for red/blue/alpha channels. - for (i = 0; i < hdr->num_htree_groups_; ++i) { - HuffmanCode** const htrees = hdr->htree_groups_[i].htrees; + for (i = 0; i < hdr->num_htree_groups; ++i) { + HuffmanCode** const htrees = hdr->htree_groups[i].htrees; if (htrees[RED][0].bits > 0) return 0; if (htrees[BLUE][0].bits > 0) return 0; if (htrees[ALPHA][0].bits > 0) return 0; } return 1; } static void AlphaApplyFilter(ALPHDecoder* const alph_dec, int first_row, int last_row, uint8_t* out, int stride) { - if (alph_dec->filter_ != WEBP_FILTER_NONE) { + if (alph_dec->filter != WEBP_FILTER_NONE) { int y; - const uint8_t* prev_line = alph_dec->prev_line_; - assert(WebPUnfilters[alph_dec->filter_] != NULL); + const uint8_t* prev_line = alph_dec->prev_line; + assert(WebPUnfilters[alph_dec->filter] != NULL); for (y = first_row; y < last_row; ++y) { - WebPUnfilters[alph_dec->filter_](prev_line, out, out, stride); + WebPUnfilters[alph_dec->filter](prev_line, out, out, stride); prev_line = out; out += stride; } - alph_dec->prev_line_ = prev_line; + alph_dec->prev_line = prev_line; } } static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int last_row) { // For vertical and gradient filtering, we need to decode the part above the // crop_top row, in order to have the correct spatial predictors. - ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque; + ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io->opaque; const int top_row = - (alph_dec->filter_ == WEBP_FILTER_NONE || - alph_dec->filter_ == WEBP_FILTER_HORIZONTAL) ? dec->io_->crop_top - : dec->last_row_; - const int first_row = (dec->last_row_ < top_row) ? top_row : dec->last_row_; - assert(last_row <= dec->io_->crop_bottom); + (alph_dec->filter == WEBP_FILTER_NONE || + alph_dec->filter == WEBP_FILTER_HORIZONTAL) ? dec->io->crop_top + : dec->last_row; + const int first_row = (dec->last_row < top_row) ? top_row : dec->last_row; + assert(last_row <= dec->io->crop_bottom); if (last_row > first_row) { // Special method for paletted alpha data. We only process the cropped area. - const int width = dec->io_->width; - uint8_t* out = alph_dec->output_ + width * first_row; + const int width = dec->io->width; + uint8_t* out = alph_dec->output + width * first_row; const uint8_t* const in = - (uint8_t*)dec->pixels_ + dec->width_ * first_row; - VP8LTransform* const transform = &dec->transforms_[0]; - assert(dec->next_transform_ == 1); - assert(transform->type_ == COLOR_INDEXING_TRANSFORM); + (uint8_t*)dec->pixels + dec->width * first_row; + VP8LTransform* const transform = &dec->transforms[0]; + assert(dec->next_transform == 1); + assert(transform->type == COLOR_INDEXING_TRANSFORM); VP8LColorIndexInverseTransformAlpha(transform, first_row, last_row, in, out); AlphaApplyFilter(alph_dec, first_row, last_row, out, width); } - dec->last_row_ = dec->last_out_row_ = last_row; + dec->last_row = dec->last_out_row = last_row; } //------------------------------------------------------------------------------ // Helper functions for fast pattern copy (8b and 32b) @@ -1033,26 +1042,26 @@ //------------------------------------------------------------------------------ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data, int width, int height, int last_row) { int ok = 1; - int row = dec->last_pixel_ / width; - int col = dec->last_pixel_ % width; - VP8LBitReader* const br = &dec->br_; - VP8LMetadata* const hdr = &dec->hdr_; - int pos = dec->last_pixel_; // current position + int row = dec->last_pixel / width; + int col = dec->last_pixel % width; + VP8LBitReader* const br = &dec->br; + VP8LMetadata* const hdr = &dec->hdr; + int pos = dec->last_pixel; // current position const int end = width * height; // End of data const int last = width * last_row; // Last pixel to decode const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; - const int mask = hdr->huffman_mask_; + const int mask = hdr->huffman_mask; const HTreeGroup* htree_group = (pos < last) ? GetHtreeGroupForPos(hdr, col, row) : NULL; assert(pos <= end); assert(last_row <= height); assert(Is8bOptimizable(hdr)); - while (!br->eos_ && pos < last) { + while (!br->eos && pos < last) { int code; // Only update when changing tile. if ((col & mask) == 0) { htree_group = GetHtreeGroupForPos(hdr, col, row); } @@ -1098,65 +1107,65 @@ } } else { // Not reached ok = 0; goto End; } - br->eos_ = VP8LIsEndOfStream(br); + br->eos = VP8LIsEndOfStream(br); } // Process the remaining rows corresponding to last row-block. ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row); End: - br->eos_ = VP8LIsEndOfStream(br); - if (!ok || (br->eos_ && pos < end)) { + br->eos = VP8LIsEndOfStream(br); + if (!ok || (br->eos && pos < end)) { return VP8LSetError( - dec, br->eos_ ? VP8_STATUS_SUSPENDED : VP8_STATUS_BITSTREAM_ERROR); + dec, br->eos ? VP8_STATUS_SUSPENDED : VP8_STATUS_BITSTREAM_ERROR); } - dec->last_pixel_ = pos; + dec->last_pixel = pos; return ok; } static void SaveState(VP8LDecoder* const dec, int last_pixel) { - assert(dec->incremental_); - dec->saved_br_ = dec->br_; - dec->saved_last_pixel_ = last_pixel; - if (dec->hdr_.color_cache_size_ > 0) { - VP8LColorCacheCopy(&dec->hdr_.color_cache_, &dec->hdr_.saved_color_cache_); + assert(dec->incremental); + dec->saved_br = dec->br; + dec->saved_last_pixel = last_pixel; + if (dec->hdr.color_cache_size > 0) { + VP8LColorCacheCopy(&dec->hdr.color_cache, &dec->hdr.saved_color_cache); } } static void RestoreState(VP8LDecoder* const dec) { - assert(dec->br_.eos_); - dec->status_ = VP8_STATUS_SUSPENDED; - dec->br_ = dec->saved_br_; - dec->last_pixel_ = dec->saved_last_pixel_; - if (dec->hdr_.color_cache_size_ > 0) { - VP8LColorCacheCopy(&dec->hdr_.saved_color_cache_, &dec->hdr_.color_cache_); + assert(dec->br.eos); + dec->status = VP8_STATUS_SUSPENDED; + dec->br = dec->saved_br; + dec->last_pixel = dec->saved_last_pixel; + if (dec->hdr.color_cache_size > 0) { + VP8LColorCacheCopy(&dec->hdr.saved_color_cache, &dec->hdr.color_cache); } } #define SYNC_EVERY_N_ROWS 8 // minimum number of rows between check-points static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data, int width, int height, int last_row, ProcessRowsFunc process_func) { - int row = dec->last_pixel_ / width; - int col = dec->last_pixel_ % width; - VP8LBitReader* const br = &dec->br_; - VP8LMetadata* const hdr = &dec->hdr_; - uint32_t* src = data + dec->last_pixel_; + int row = dec->last_pixel / width; + int col = dec->last_pixel % width; + VP8LBitReader* const br = &dec->br; + VP8LMetadata* const hdr = &dec->hdr; + uint32_t* src = data + dec->last_pixel; uint32_t* last_cached = src; uint32_t* const src_end = data + width * height; // End of data uint32_t* const src_last = data + width * last_row; // Last pixel to decode const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; - const int color_cache_limit = len_code_limit + hdr->color_cache_size_; - int next_sync_row = dec->incremental_ ? row : 1 << 24; + const int color_cache_limit = len_code_limit + hdr->color_cache_size; + int next_sync_row = dec->incremental ? row : 1 << 24; VP8LColorCache* const color_cache = - (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL; - const int mask = hdr->huffman_mask_; + (hdr->color_cache_size > 0) ? &hdr->color_cache : NULL; + const int mask = hdr->huffman_mask; const HTreeGroup* htree_group = (src < src_last) ? GetHtreeGroupForPos(hdr, col, row) : NULL; - assert(dec->last_row_ < last_row); + assert(dec->last_row < last_row); assert(src_last <= src_end); while (src < src_last) { int code; if (row >= next_sync_row) { @@ -1258,33 +1267,33 @@ } else { // Not reached goto Error; } } - br->eos_ = VP8LIsEndOfStream(br); + br->eos = VP8LIsEndOfStream(br); // In incremental decoding: - // br->eos_ && src < src_last: if 'br' reached the end of the buffer and + // br->eos && src < src_last: if 'br' reached the end of the buffer and // 'src_last' has not been reached yet, there is not enough data. 'dec' has to // be reset until there is more data. - // !br->eos_ && src < src_last: this cannot happen as either the buffer is + // !br->eos && src < src_last: this cannot happen as either the buffer is // fully read, either enough has been read to reach 'src_last'. // src >= src_last: 'src_last' is reached, all is fine. 'src' can actually go // beyond 'src_last' in case the image is cropped and an LZ77 goes further. - // The buffer might have been enough or there is some left. 'br->eos_' does + // The buffer might have been enough or there is some left. 'br->eos' does // not matter. - assert(!dec->incremental_ || (br->eos_ && src < src_last) || src >= src_last); - if (dec->incremental_ && br->eos_ && src < src_last) { + assert(!dec->incremental || (br->eos && src < src_last) || src >= src_last); + if (dec->incremental && br->eos && src < src_last) { RestoreState(dec); - } else if ((dec->incremental_ && src >= src_last) || !br->eos_) { + } else if ((dec->incremental && src >= src_last) || !br->eos) { // Process the remaining rows corresponding to last row-block. if (process_func != NULL) { process_func(dec, row > last_row ? last_row : row); } - dec->status_ = VP8_STATUS_OK; - dec->last_pixel_ = (int)(src - data); // end-of-scan marker + dec->status = VP8_STATUS_OK; + dec->last_pixel = (int)(src - data); // end-of-scan marker } else { - // if not incremental, and we are past the end of buffer (eos_=1), then this + // if not incremental, and we are past the end of buffer (eos=1), then this // is a real bitstream error. goto Error; } return 1; @@ -1294,83 +1303,83 @@ // ----------------------------------------------------------------------------- // VP8LTransform static void ClearTransform(VP8LTransform* const transform) { - WebPSafeFree(transform->data_); - transform->data_ = NULL; + WebPSafeFree(transform->data); + transform->data = NULL; } // For security reason, we need to remap the color map to span // the total possible bundled values, and not just the num_colors. static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { int i; - const int final_num_colors = 1 << (8 >> transform->bits_); + const int final_num_colors = 1 << (8 >> transform->bits); uint32_t* const new_color_map = (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors, sizeof(*new_color_map)); if (new_color_map == NULL) { return 0; } else { - uint8_t* const data = (uint8_t*)transform->data_; + uint8_t* const data = (uint8_t*)transform->data; uint8_t* const new_data = (uint8_t*)new_color_map; - new_color_map[0] = transform->data_[0]; + new_color_map[0] = transform->data[0]; for (i = 4; i < 4 * num_colors; ++i) { // Equivalent to VP8LAddPixels(), on a byte-basis. new_data[i] = (data[i] + new_data[i - 4]) & 0xff; } for (; i < 4 * final_num_colors; ++i) { new_data[i] = 0; // black tail. } - WebPSafeFree(transform->data_); - transform->data_ = new_color_map; + WebPSafeFree(transform->data); + transform->data = new_color_map; } return 1; } static int ReadTransform(int* const xsize, int const* ysize, VP8LDecoder* const dec) { int ok = 1; - VP8LBitReader* const br = &dec->br_; - VP8LTransform* transform = &dec->transforms_[dec->next_transform_]; + VP8LBitReader* const br = &dec->br; + VP8LTransform* transform = &dec->transforms[dec->next_transform]; const VP8LImageTransformType type = (VP8LImageTransformType)VP8LReadBits(br, 2); // Each transform type can only be present once in the stream. - if (dec->transforms_seen_ & (1U << type)) { + if (dec->transforms_seen & (1U << type)) { return 0; // Already there, let's not accept the second same transform. } - dec->transforms_seen_ |= (1U << type); + dec->transforms_seen |= (1U << type); - transform->type_ = type; - transform->xsize_ = *xsize; - transform->ysize_ = *ysize; - transform->data_ = NULL; - ++dec->next_transform_; - assert(dec->next_transform_ <= NUM_TRANSFORMS); + transform->type = type; + transform->xsize = *xsize; + transform->ysize = *ysize; + transform->data = NULL; + ++dec->next_transform; + assert(dec->next_transform <= NUM_TRANSFORMS); switch (type) { case PREDICTOR_TRANSFORM: case CROSS_COLOR_TRANSFORM: - transform->bits_ = + transform->bits = MIN_TRANSFORM_BITS + VP8LReadBits(br, NUM_TRANSFORM_BITS); - ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize_, - transform->bits_), - VP8LSubSampleSize(transform->ysize_, - transform->bits_), - /*is_level0=*/0, dec, &transform->data_); + ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize, + transform->bits), + VP8LSubSampleSize(transform->ysize, + transform->bits), + /*is_level0=*/0, dec, &transform->data); break; case COLOR_INDEXING_TRANSFORM: { const int num_colors = VP8LReadBits(br, 8) + 1; const int bits = (num_colors > 16) ? 0 : (num_colors > 4) ? 1 : (num_colors > 2) ? 2 : 3; - *xsize = VP8LSubSampleSize(transform->xsize_, bits); - transform->bits_ = bits; + *xsize = VP8LSubSampleSize(transform->xsize, bits); + transform->bits = bits; ok = DecodeImageStream(num_colors, /*ysize=*/1, /*is_level0=*/0, dec, - &transform->data_); + &transform->data); if (ok && !ExpandColorMap(num_colors, transform)) { return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); } break; } @@ -1393,79 +1402,79 @@ } static void ClearMetadata(VP8LMetadata* const hdr) { assert(hdr != NULL); - WebPSafeFree(hdr->huffman_image_); - VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_); - VP8LHtreeGroupsFree(hdr->htree_groups_); - VP8LColorCacheClear(&hdr->color_cache_); - VP8LColorCacheClear(&hdr->saved_color_cache_); + WebPSafeFree(hdr->huffman_image); + VP8LHuffmanTablesDeallocate(&hdr->huffman_tables); + VP8LHtreeGroupsFree(hdr->htree_groups); + VP8LColorCacheClear(&hdr->color_cache); + VP8LColorCacheClear(&hdr->saved_color_cache); InitMetadata(hdr); } // ----------------------------------------------------------------------------- // VP8LDecoder VP8LDecoder* VP8LNew(void) { VP8LDecoder* const dec = (VP8LDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); if (dec == NULL) return NULL; - dec->status_ = VP8_STATUS_OK; - dec->state_ = READ_DIM; + dec->status = VP8_STATUS_OK; + dec->state = READ_DIM; VP8LDspInit(); // Init critical function pointers. return dec; } // Resets the decoder in its initial state, reclaiming memory. -// Preserves the dec->status_ value. +// Preserves the dec->status value. static void VP8LClear(VP8LDecoder* const dec) { int i; if (dec == NULL) return; - ClearMetadata(&dec->hdr_); + ClearMetadata(&dec->hdr); - WebPSafeFree(dec->pixels_); - dec->pixels_ = NULL; - for (i = 0; i < dec->next_transform_; ++i) { - ClearTransform(&dec->transforms_[i]); + WebPSafeFree(dec->pixels); + dec->pixels = NULL; + for (i = 0; i < dec->next_transform; ++i) { + ClearTransform(&dec->transforms[i]); } - dec->next_transform_ = 0; - dec->transforms_seen_ = 0; + dec->next_transform = 0; + dec->transforms_seen = 0; WebPSafeFree(dec->rescaler_memory); dec->rescaler_memory = NULL; - dec->output_ = NULL; // leave no trace behind + dec->output = NULL; // leave no trace behind } void VP8LDelete(VP8LDecoder* const dec) { if (dec != NULL) { VP8LClear(dec); WebPSafeFree(dec); } } static void UpdateDecoder(VP8LDecoder* const dec, int width, int height) { - VP8LMetadata* const hdr = &dec->hdr_; - const int num_bits = hdr->huffman_subsample_bits_; - dec->width_ = width; - dec->height_ = height; + VP8LMetadata* const hdr = &dec->hdr; + const int num_bits = hdr->huffman_subsample_bits; + dec->width = width; + dec->height = height; - hdr->huffman_xsize_ = VP8LSubSampleSize(width, num_bits); - hdr->huffman_mask_ = (num_bits == 0) ? ~0 : (1 << num_bits) - 1; + hdr->huffman_xsize = VP8LSubSampleSize(width, num_bits); + hdr->huffman_mask = (num_bits == 0) ? ~0 : (1 << num_bits) - 1; } static int DecodeImageStream(int xsize, int ysize, int is_level0, VP8LDecoder* const dec, uint32_t** const decoded_data) { int ok = 1; int transform_xsize = xsize; int transform_ysize = ysize; - VP8LBitReader* const br = &dec->br_; - VP8LMetadata* const hdr = &dec->hdr_; + VP8LBitReader* const br = &dec->br; + VP8LMetadata* const hdr = &dec->hdr; uint32_t* data = NULL; int color_cache_bits = 0; // Read the transforms (may recurse). if (is_level0) { @@ -1492,22 +1501,22 @@ goto End; } // Finish setting up the color-cache if (color_cache_bits > 0) { - hdr->color_cache_size_ = 1 << color_cache_bits; - if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) { + hdr->color_cache_size = 1 << color_cache_bits; + if (!VP8LColorCacheInit(&hdr->color_cache, color_cache_bits)) { ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); goto End; } } else { - hdr->color_cache_size_ = 0; + hdr->color_cache_size = 0; } UpdateDecoder(dec, transform_xsize, transform_ysize); if (is_level0) { // level 0 complete - dec->state_ = READ_HDR; + dec->state = READ_HDR; goto End; } { const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize; @@ -1519,11 +1528,11 @@ } // Use the Huffman trees to decode the LZ77 encoded data. ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, transform_ysize, NULL); - ok = ok && !br->eos_; + ok = ok && !br->eos; End: if (!ok) { WebPSafeFree(data); ClearMetadata(hdr); @@ -1534,77 +1543,77 @@ // We allocate image data in this function only for transforms. At level 0 // (that is: not the transforms), we shouldn't have allocated anything. assert(data == NULL); assert(is_level0); } - dec->last_pixel_ = 0; // Reset for future DECODE_DATA_FUNC() calls. + dec->last_pixel = 0; // Reset for future DECODE_DATA_FUNC() calls. if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind. } return ok; } //------------------------------------------------------------------------------ -// Allocate internal buffers dec->pixels_ and dec->argb_cache_. +// Allocate internal buffers dec->pixels and dec->argb_cache. static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) { - const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_; + const uint64_t num_pixels = (uint64_t)dec->width * dec->height; // Scratch buffer corresponding to top-prediction row for transforming the // first row in the row-blocks. Not needed for paletted alpha. const uint64_t cache_top_pixels = (uint16_t)final_width; // Scratch buffer for temporary BGRA storage. Not needed for paletted alpha. const uint64_t cache_pixels = (uint64_t)final_width * NUM_ARGB_CACHE_ROWS; const uint64_t total_num_pixels = num_pixels + cache_top_pixels + cache_pixels; - assert(dec->width_ <= final_width); - dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t)); - if (dec->pixels_ == NULL) { - dec->argb_cache_ = NULL; // for soundness + assert(dec->width <= final_width); + dec->pixels = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t)); + if (dec->pixels == NULL) { + dec->argb_cache = NULL; // for soundness return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); } - dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels; + dec->argb_cache = dec->pixels + num_pixels + cache_top_pixels; return 1; } static int AllocateInternalBuffers8b(VP8LDecoder* const dec) { - const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_; - dec->argb_cache_ = NULL; // for soundness - dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t)); - if (dec->pixels_ == NULL) { + const uint64_t total_num_pixels = (uint64_t)dec->width * dec->height; + dec->argb_cache = NULL; // for soundness + dec->pixels = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t)); + if (dec->pixels == NULL) { return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); } return 1; } //------------------------------------------------------------------------------ // Special row-processing that only stores the alpha data. static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) { - int cur_row = dec->last_row_; + int cur_row = dec->last_row; int num_rows = last_row - cur_row; - const uint32_t* in = dec->pixels_ + dec->width_ * cur_row; + const uint32_t* in = dec->pixels + dec->width * cur_row; - assert(last_row <= dec->io_->crop_bottom); + assert(last_row <= dec->io->crop_bottom); while (num_rows > 0) { const int num_rows_to_process = (num_rows > NUM_ARGB_CACHE_ROWS) ? NUM_ARGB_CACHE_ROWS : num_rows; // Extract alpha (which is stored in the green plane). - ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque; - uint8_t* const output = alph_dec->output_; - const int width = dec->io_->width; // the final width (!= dec->width_) + ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io->opaque; + uint8_t* const output = alph_dec->output; + const int width = dec->io->width; // the final width (!= dec->width) const int cache_pixs = width * num_rows_to_process; uint8_t* const dst = output + width * cur_row; - const uint32_t* const src = dec->argb_cache_; + const uint32_t* const src = dec->argb_cache; ApplyInverseTransforms(dec, cur_row, num_rows_to_process, in); WebPExtractGreen(src, dst, cache_pixs); AlphaApplyFilter(alph_dec, cur_row, cur_row + num_rows_to_process, dst, width); num_rows -= num_rows_to_process; - in += num_rows_to_process * dec->width_; + in += num_rows_to_process * dec->width; cur_row += num_rows_to_process; } assert(cur_row == last_row); - dec->last_row_ = dec->last_out_row_ = last_row; + dec->last_row = dec->last_out_row = last_row; } int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, const uint8_t* const data, size_t data_size) { int ok = 0; @@ -1612,66 +1621,66 @@ if (dec == NULL) return 0; assert(alph_dec != NULL); - dec->width_ = alph_dec->width_; - dec->height_ = alph_dec->height_; - dec->io_ = &alph_dec->io_; - dec->io_->opaque = alph_dec; - dec->io_->width = alph_dec->width_; - dec->io_->height = alph_dec->height_; + dec->width = alph_dec->width; + dec->height = alph_dec->height; + dec->io = &alph_dec->io; + dec->io->opaque = alph_dec; + dec->io->width = alph_dec->width; + dec->io->height = alph_dec->height; - dec->status_ = VP8_STATUS_OK; - VP8LInitBitReader(&dec->br_, data, data_size); + dec->status = VP8_STATUS_OK; + VP8LInitBitReader(&dec->br, data, data_size); - if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, /*is_level0=*/1, + if (!DecodeImageStream(alph_dec->width, alph_dec->height, /*is_level0=*/1, dec, /*decoded_data=*/NULL)) { goto Err; } // Special case: if alpha data uses only the color indexing transform and // doesn't use color cache (a frequent case), we will use DecodeAlphaData() // method that only needs allocation of 1 byte per pixel (alpha channel). - if (dec->next_transform_ == 1 && - dec->transforms_[0].type_ == COLOR_INDEXING_TRANSFORM && - Is8bOptimizable(&dec->hdr_)) { - alph_dec->use_8b_decode_ = 1; + if (dec->next_transform == 1 && + dec->transforms[0].type == COLOR_INDEXING_TRANSFORM && + Is8bOptimizable(&dec->hdr)) { + alph_dec->use_8b_decode = 1; ok = AllocateInternalBuffers8b(dec); } else { - // Allocate internal buffers (note that dec->width_ may have changed here). - alph_dec->use_8b_decode_ = 0; - ok = AllocateInternalBuffers32b(dec, alph_dec->width_); + // Allocate internal buffers (note that dec->width may have changed here). + alph_dec->use_8b_decode = 0; + ok = AllocateInternalBuffers32b(dec, alph_dec->width); } if (!ok) goto Err; // Only set here, once we are sure it is valid (to avoid thread races). - alph_dec->vp8l_dec_ = dec; + alph_dec->vp8l_dec = dec; return 1; Err: VP8LDelete(dec); return 0; } int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) { - VP8LDecoder* const dec = alph_dec->vp8l_dec_; + VP8LDecoder* const dec = alph_dec->vp8l_dec; assert(dec != NULL); - assert(last_row <= dec->height_); + assert(last_row <= dec->height); - if (dec->last_row_ >= last_row) { + if (dec->last_row >= last_row) { return 1; // done } - if (!alph_dec->use_8b_decode_) WebPInitAlphaProcessing(); + if (!alph_dec->use_8b_decode) WebPInitAlphaProcessing(); // Decode (with special row processing). - return alph_dec->use_8b_decode_ ? - DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_, + return alph_dec->use_8b_decode ? + DecodeAlphaData(dec, (uint8_t*)dec->pixels, dec->width, dec->height, last_row) : - DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_, + DecodeImageData(dec, dec->pixels, dec->width, dec->height, last_row, ExtractAlphaRows); } //------------------------------------------------------------------------------ @@ -1681,18 +1690,18 @@ if (dec == NULL) return 0; if (io == NULL) { return VP8LSetError(dec, VP8_STATUS_INVALID_PARAM); } - dec->io_ = io; - dec->status_ = VP8_STATUS_OK; - VP8LInitBitReader(&dec->br_, io->data, io->data_size); - if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) { + dec->io = io; + dec->status = VP8_STATUS_OK; + VP8LInitBitReader(&dec->br, io->data, io->data_size); + if (!ReadImageInfo(&dec->br, &width, &height, &has_alpha)) { VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); goto Error; } - dec->state_ = READ_DIM; + dec->state = READ_DIM; io->width = width; io->height = height; if (!DecodeImageStream(width, height, /*is_level0=*/1, dec, /*decoded_data=*/NULL)) { @@ -1700,33 +1709,33 @@ } return 1; Error: VP8LClear(dec); - assert(dec->status_ != VP8_STATUS_OK); + assert(dec->status != VP8_STATUS_OK); return 0; } int VP8LDecodeImage(VP8LDecoder* const dec) { VP8Io* io = NULL; WebPDecParams* params = NULL; if (dec == NULL) return 0; - assert(dec->hdr_.huffman_tables_.root.start != NULL); - assert(dec->hdr_.htree_groups_ != NULL); - assert(dec->hdr_.num_htree_groups_ > 0); + assert(dec->hdr.huffman_tables.root.start != NULL); + assert(dec->hdr.htree_groups != NULL); + assert(dec->hdr.num_htree_groups > 0); - io = dec->io_; + io = dec->io; assert(io != NULL); params = (WebPDecParams*)io->opaque; assert(params != NULL); // Initialization. - if (dec->state_ != READ_DATA) { - dec->output_ = params->output; - assert(dec->output_ != NULL); + if (dec->state != READ_DATA) { + dec->output = params->output; + assert(dec->output != NULL); if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) { VP8LSetError(dec, VP8_STATUS_INVALID_PARAM); goto Err; } @@ -1739,43 +1748,43 @@ if (io->use_scaling) { VP8LSetError(dec, VP8_STATUS_INVALID_PARAM); goto Err; } #endif - if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) { + if (io->use_scaling || WebPIsPremultipliedMode(dec->output->colorspace)) { // need the alpha-multiply functions for premultiplied output or rescaling WebPInitAlphaProcessing(); } - if (!WebPIsRGBMode(dec->output_->colorspace)) { + if (!WebPIsRGBMode(dec->output->colorspace)) { WebPInitConvertARGBToYUV(); - if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing(); + if (dec->output->u.YUVA.a != NULL) WebPInitAlphaProcessing(); } - if (dec->incremental_) { - if (dec->hdr_.color_cache_size_ > 0 && - dec->hdr_.saved_color_cache_.colors_ == NULL) { - if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_, - dec->hdr_.color_cache_.hash_bits_)) { + if (dec->incremental) { + if (dec->hdr.color_cache_size > 0 && + dec->hdr.saved_color_cache.colors == NULL) { + if (!VP8LColorCacheInit(&dec->hdr.saved_color_cache, + dec->hdr.color_cache.hash_bits)) { VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); goto Err; } } } - dec->state_ = READ_DATA; + dec->state = READ_DATA; } // Decode. - if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_, + if (!DecodeImageData(dec, dec->pixels, dec->width, dec->height, io->crop_bottom, ProcessRows)) { goto Err; } - params->last_y = dec->last_out_row_; + params->last_y = dec->last_out_row; return 1; Err: VP8LClear(dec); - assert(dec->status_ != VP8_STATUS_OK); + assert(dec->status != VP8_STATUS_OK); return 0; } //------------------------------------------------------------------------------ diff --git a/media/libwebp/src/dec/vp8li_dec.h b/media/libwebp/src/dec/vp8li_dec.h --- a/media/libwebp/src/dec/vp8li_dec.h +++ b/media/libwebp/src/dec/vp8li_dec.h @@ -14,14 +14,19 @@ #ifndef WEBP_DEC_VP8LI_DEC_H_ #define WEBP_DEC_VP8LI_DEC_H_ #include // for memcpy() + +#include "src/dec/vp8_dec.h" #include "src/dec/webpi_dec.h" #include "src/utils/bit_reader_utils.h" #include "src/utils/color_cache_utils.h" #include "src/utils/huffman_utils.h" +#include "src/utils/rescaler_utils.h" +#include "src/webp/decode.h" +#include "src/webp/format_constants.h" #include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif @@ -32,62 +37,62 @@ READ_DIM = 2 } VP8LDecodeState; typedef struct VP8LTransform VP8LTransform; struct VP8LTransform { - VP8LImageTransformType type_; // transform type. - int bits_; // subsampling bits defining transform window. - int xsize_; // transform window X index. - int ysize_; // transform window Y index. - uint32_t* data_; // transform data. + VP8LImageTransformType type; // transform type. + int bits; // subsampling bits defining transform window. + int xsize; // transform window X index. + int ysize; // transform window Y index. + uint32_t* data; // transform data. }; typedef struct { - int color_cache_size_; - VP8LColorCache color_cache_; - VP8LColorCache saved_color_cache_; // for incremental + int color_cache_size; + VP8LColorCache color_cache; + VP8LColorCache saved_color_cache; // for incremental - int huffman_mask_; - int huffman_subsample_bits_; - int huffman_xsize_; - uint32_t* huffman_image_; - int num_htree_groups_; - HTreeGroup* htree_groups_; - HuffmanTables huffman_tables_; + int huffman_mask; + int huffman_subsample_bits; + int huffman_xsize; + uint32_t* huffman_image; + int num_htree_groups; + HTreeGroup* htree_groups; + HuffmanTables huffman_tables; } VP8LMetadata; typedef struct VP8LDecoder VP8LDecoder; struct VP8LDecoder { - VP8StatusCode status_; - VP8LDecodeState state_; - VP8Io* io_; + VP8StatusCode status; + VP8LDecodeState state; + VP8Io* io; - const WebPDecBuffer* output_; // shortcut to io->opaque->output + const WebPDecBuffer* output; // shortcut to io->opaque->output - uint32_t* pixels_; // Internal data: either uint8_t* for alpha - // or uint32_t* for BGRA. - uint32_t* argb_cache_; // Scratch buffer for temporary BGRA storage. + uint32_t* pixels; // Internal data: either uint8_t* for alpha + // or uint32_t* for BGRA. + uint32_t* argb_cache; // Scratch buffer for temporary BGRA storage. - VP8LBitReader br_; - int incremental_; // if true, incremental decoding is expected - VP8LBitReader saved_br_; // note: could be local variables too - int saved_last_pixel_; + VP8LBitReader br; + int incremental; // if true, incremental decoding is expected + VP8LBitReader saved_br; // note: could be local variables too + int saved_last_pixel; - int width_; - int height_; - int last_row_; // last input row decoded so far. - int last_pixel_; // last pixel decoded so far. However, it may - // not be transformed, scaled and - // color-converted yet. - int last_out_row_; // last row output so far. + int width; + int height; + int last_row; // last input row decoded so far. + int last_pixel; // last pixel decoded so far. However, it may + // not be transformed, scaled and + // color-converted yet. + int last_out_row; // last row output so far. - VP8LMetadata hdr_; + VP8LMetadata hdr; - int next_transform_; - VP8LTransform transforms_[NUM_TRANSFORMS]; + int next_transform; + VP8LTransform transforms[NUM_TRANSFORMS]; // or'd bitset storing the transforms types. - uint32_t transforms_seen_; + uint32_t transforms_seen; uint8_t* rescaler_memory; // Working memory for rescaling work. WebPRescaler* rescaler; // Common rescaler for all channels. }; @@ -116,11 +121,11 @@ // Decodes the image header. Returns false in case of error. WEBP_NODISCARD int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io); // 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. WEBP_NODISCARD int VP8LDecodeImage(VP8LDecoder* const dec); // Clears and deallocate a lossless decoder instance. void VP8LDelete(VP8LDecoder* const dec); diff --git a/media/libwebp/src/dec/webp_dec.c b/media/libwebp/src/dec/webp_dec.c --- a/media/libwebp/src/dec/webp_dec.c +++ b/media/libwebp/src/dec/webp_dec.c @@ -9,19 +9,24 @@ // // Main decoding functions for WEBP images. // // Author: Skal (pascal.massimino@gmail.com) +#include #include +#include +#include "src/dec/common_dec.h" #include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dec/vp8li_dec.h" #include "src/dec/webpi_dec.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/format_constants.h" #include "src/webp/mux_types.h" // ALPHA_FLAG -#include "src/webp/decode.h" #include "src/webp/types.h" //------------------------------------------------------------------------------ // RIFF layout is: // Offset tag @@ -473,45 +478,45 @@ if (!headers.is_lossless) { VP8Decoder* const dec = VP8New(); if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } - dec->alpha_data_ = headers.alpha_data; - dec->alpha_data_size_ = headers.alpha_data_size; + dec->alpha_data = headers.alpha_data; + dec->alpha_data_size = headers.alpha_data_size; // Decode bitstream header, update io->width/io->height. if (!VP8GetHeaders(dec, &io)) { - status = dec->status_; // An error occurred. Grab error status. + status = dec->status; // An error occurred. Grab error status. } else { // Allocate/check output buffers. status = WebPAllocateDecBuffer(io.width, io.height, params->options, params->output); if (status == VP8_STATUS_OK) { // Decode // This change must be done before calling VP8Decode() - dec->mt_method_ = VP8GetThreadMethod(params->options, &headers, - io.width, io.height); + dec->mt_method = VP8GetThreadMethod(params->options, &headers, + io.width, io.height); VP8InitDithering(params->options, dec); if (!VP8Decode(dec, &io)) { - status = dec->status_; + status = dec->status; } } } VP8Delete(dec); } else { VP8LDecoder* const dec = VP8LNew(); if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } if (!VP8LDecodeHeader(dec, &io)) { - status = dec->status_; // An error occurred. Grab error status. + status = dec->status; // An error occurred. Grab error status. } else { // Allocate/check output buffers. status = WebPAllocateDecBuffer(io.width, io.height, params->options, params->output); if (status == VP8_STATUS_OK) { // Decode if (!VP8LDecodeImage(dec)) { - status = dec->status_; + status = dec->status; } } } VP8LDelete(dec); } @@ -745,10 +750,65 @@ return 0; } return 1; } +static int WebPCheckCropDimensionsBasic(int x, int y, int w, int h) { + return !(x < 0 || y < 0 || w <= 0 || h <= 0); +} + +int WebPValidateDecoderConfig(const WebPDecoderConfig* config) { + const WebPDecoderOptions* options; + if (config == NULL) return 0; + if (!IsValidColorspace(config->output.colorspace)) { + return 0; + } + + options = &config->options; + // bypass_filtering, no_fancy_upsampling, use_cropping, use_scaling, + // use_threads, flip can be any integer and are interpreted as boolean. + + // Check for cropping. + if (options->use_cropping && !WebPCheckCropDimensionsBasic( + options->crop_left, options->crop_top, + options->crop_width, options->crop_height)) { + return 0; + } + // Check for scaling. + if (options->use_scaling && + (options->scaled_width < 0 || options->scaled_height < 0 || + (options->scaled_width == 0 && options->scaled_height == 0))) { + return 0; + } + + // In case the WebPBitstreamFeatures has been filled in, check further. + if (config->input.width > 0 || config->input.height > 0) { + int scaled_width = options->scaled_width; + int scaled_height = options->scaled_height; + if (options->use_cropping && + !WebPCheckCropDimensions(config->input.width, config->input.height, + options->crop_left, options->crop_top, + options->crop_width, options->crop_height)) { + return 0; + } + if (options->use_scaling && !WebPRescalerGetScaledDimensions( + config->input.width, config->input.height, + &scaled_width, &scaled_height)) { + return 0; + } + } + + // Check for dithering. + if (options->dithering_strength < 0 || options->dithering_strength > 100 || + options->alpha_dithering_strength < 0 || + options->alpha_dithering_strength > 100) { + return 0; + } + + return 1; +} + VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, WebPBitstreamFeatures* features, int version) { if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { return VP8_STATUS_INVALID_PARAM; // version mismatch @@ -804,12 +864,12 @@ //------------------------------------------------------------------------------ // Cropping and rescaling. int WebPCheckCropDimensions(int image_width, int image_height, int x, int y, int w, int h) { - return !(x < 0 || y < 0 || w <= 0 || h <= 0 || - x >= image_width || w > image_width || w > image_width - x || + return WebPCheckCropDimensionsBasic(x, y, w, h) && + !(x >= image_width || w > image_width || w > image_width - x || y >= image_height || h > image_height || h > image_height - y); } int WebPIoInitFromOptions(const WebPDecoderOptions* const options, VP8Io* const io, WEBP_CSP_MODE src_colorspace) { diff --git a/media/libwebp/src/dec/webpi_dec.h b/media/libwebp/src/dec/webpi_dec.h --- a/media/libwebp/src/dec/webpi_dec.h +++ b/media/libwebp/src/dec/webpi_dec.h @@ -16,13 +16,16 @@ #ifdef __cplusplus extern "C" { #endif -#include "src/utils/rescaler_utils.h" +#include + #include "src/dec/vp8_dec.h" +#include "src/utils/rescaler_utils.h" #include "src/webp/decode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // WebPDecParams: Decoding output parameters. Transient internal object. typedef struct WebPDecParams WebPDecParams; diff --git a/media/libwebp/src/demux/demux.c b/media/libwebp/src/demux/demux.c --- a/media/libwebp/src/demux/demux.c +++ b/media/libwebp/src/demux/demux.c @@ -20,59 +20,62 @@ #include "src/utils/utils.h" #include "src/webp/decode.h" // WebPGetFeatures #include "src/webp/demux.h" #include "src/webp/format_constants.h" +#include "src/webp/mux.h" +#include "src/webp/mux_types.h" +#include "src/webp/types.h" #define DMUX_MAJ_VERSION 1 -#define DMUX_MIN_VERSION 5 +#define DMUX_MIN_VERSION 6 #define DMUX_REV_VERSION 0 typedef struct { - size_t start_; // start location of the data - size_t end_; // end location - size_t riff_end_; // riff chunk end location, can be > end_. - size_t buf_size_; // size of the buffer - const uint8_t* buf_; + size_t start; // start location of the data + size_t end; // end location + size_t riff_end; // riff chunk end location, can be > end. + size_t buf_size; // size of the buffer + const uint8_t* buf; } MemBuffer; typedef struct { - size_t offset_; - size_t size_; + size_t offset; + size_t size; } ChunkData; typedef struct Frame { - int x_offset_, y_offset_; - int width_, height_; - int has_alpha_; - int duration_; - WebPMuxAnimDispose dispose_method_; - WebPMuxAnimBlend blend_method_; - int frame_num_; - int complete_; // img_components_ contains a full image. - ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH - struct Frame* next_; + int x_offset, y_offset; + int width, height; + int has_alpha; + int duration; + WebPMuxAnimDispose dispose_method; + WebPMuxAnimBlend blend_method; + int frame_num; + int complete; // img_components contains a full image. + ChunkData img_components[2]; // 0=VP8{,L} 1=ALPH + struct Frame* next; } Frame; typedef struct Chunk { - ChunkData data_; - struct Chunk* next_; + ChunkData data; + struct Chunk* next; } Chunk; struct WebPDemuxer { - MemBuffer mem_; - WebPDemuxState state_; - int is_ext_format_; - uint32_t feature_flags_; - int canvas_width_, canvas_height_; - int loop_count_; - uint32_t bgcolor_; - int num_frames_; - Frame* frames_; - Frame** frames_tail_; - Chunk* chunks_; // non-image chunks - Chunk** chunks_tail_; + MemBuffer mem; + WebPDemuxState state; + int is_ext_format; + uint32_t feature_flags; + int canvas_width, canvas_height; + int loop_count; + uint32_t bgcolor; + int num_frames; + Frame* frames; + Frame** frames_tail; + Chunk* chunks; // non-image chunks + Chunk** chunks_tail; }; typedef enum { PARSE_OK, PARSE_NEED_MORE_DATA, @@ -106,14 +109,14 @@ // ----------------------------------------------------------------------------- // MemBuffer static int RemapMemBuffer(MemBuffer* const mem, const uint8_t* data, size_t size) { - if (size < mem->buf_size_) return 0; // can't remap to a shorter buffer! + if (size < mem->buf_size) return 0; // can't remap to a shorter buffer! - mem->buf_ = data; - mem->end_ = mem->buf_size_ = size; + mem->buf = data; + mem->end = mem->buf_size = size; return 1; } static int InitMemBuffer(MemBuffer* const mem, const uint8_t* data, size_t size) { @@ -121,90 +124,90 @@ return RemapMemBuffer(mem, data, size); } // Return the remaining data size available in 'mem'. static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) { - return (mem->end_ - mem->start_); + return (mem->end - mem->start); } // Return true if 'size' exceeds the end of the RIFF chunk. static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) { - return (size > mem->riff_end_ - mem->start_); + return (size > mem->riff_end - mem->start); } static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) { - mem->start_ += size; + mem->start += size; } static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) { - mem->start_ -= size; + mem->start -= size; } static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) { - return mem->buf_ + mem->start_; + return mem->buf + mem->start; } // Read from 'mem' and skip the read bytes. static WEBP_INLINE uint8_t ReadByte(MemBuffer* const mem) { - const uint8_t byte = mem->buf_[mem->start_]; + const uint8_t byte = mem->buf[mem->start]; Skip(mem, 1); return byte; } static WEBP_INLINE int ReadLE16s(MemBuffer* const mem) { - const uint8_t* const data = mem->buf_ + mem->start_; + const uint8_t* const data = mem->buf + mem->start; const int val = GetLE16(data); Skip(mem, 2); return val; } static WEBP_INLINE int ReadLE24s(MemBuffer* const mem) { - const uint8_t* const data = mem->buf_ + mem->start_; + const uint8_t* const data = mem->buf + mem->start; const int val = GetLE24(data); Skip(mem, 3); return val; } static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) { - const uint8_t* const data = mem->buf_ + mem->start_; + const uint8_t* const data = mem->buf + mem->start; const uint32_t val = GetLE32(data); Skip(mem, 4); return val; } // ----------------------------------------------------------------------------- // Secondary chunk parsing static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) { - *dmux->chunks_tail_ = chunk; - chunk->next_ = NULL; - dmux->chunks_tail_ = &chunk->next_; + *dmux->chunks_tail = chunk; + chunk->next = NULL; + dmux->chunks_tail = &chunk->next; } // Add a frame to the end of the list, ensuring the last frame is complete. // Returns true on success, false otherwise. static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { - const Frame* const last_frame = *dmux->frames_tail_; - if (last_frame != NULL && !last_frame->complete_) return 0; + const Frame* const last_frame = *dmux->frames_tail; + if (last_frame != NULL && !last_frame->complete) return 0; - *dmux->frames_tail_ = frame; - frame->next_ = NULL; - dmux->frames_tail_ = &frame->next_; + *dmux->frames_tail = frame; + frame->next = NULL; + dmux->frames_tail = &frame->next; return 1; } static void SetFrameInfo(size_t start_offset, size_t size, int frame_num, int complete, const WebPBitstreamFeatures* const features, Frame* const frame) { - frame->img_components_[0].offset_ = start_offset; - frame->img_components_[0].size_ = size; - frame->width_ = features->width; - frame->height_ = features->height; - frame->has_alpha_ |= features->has_alpha; - frame->frame_num_ = frame_num; - frame->complete_ = complete; + frame->img_components[0].offset = start_offset; + frame->img_components[0].size = size; + frame->width = features->width; + frame->height = features->height; + frame->has_alpha |= features->has_alpha; + frame->frame_num = frame_num; + frame->complete = complete; } // Store image bearing chunks to 'frame'. 'min_size' is an optional size // requirement, it may be zero. static ParseStatus StoreFrame(int frame_num, uint32_t min_size, @@ -216,11 +219,11 @@ ParseStatus status = PARSE_OK; if (done) return PARSE_NEED_MORE_DATA; do { - const size_t chunk_start_offset = mem->start_; + const size_t chunk_start_offset = mem->start; const uint32_t fourcc = ReadLE32(mem); const uint32_t payload_size = ReadLE32(mem); uint32_t payload_size_padded; size_t payload_available; size_t chunk_size; @@ -236,14 +239,14 @@ switch (fourcc) { case MKFOURCC('A', 'L', 'P', 'H'): if (alpha_chunks == 0) { ++alpha_chunks; - frame->img_components_[1].offset_ = chunk_start_offset; - frame->img_components_[1].size_ = chunk_size; - frame->has_alpha_ = 1; - frame->frame_num_ = frame_num; + frame->img_components[1].offset = chunk_start_offset; + frame->img_components[1].size = chunk_size; + frame->has_alpha = 1; + frame->frame_num = frame_num; Skip(mem, payload_available); } else { goto Done; } break; @@ -254,11 +257,11 @@ if (image_chunks == 0) { // Extract the bitstream features, tolerating failures when the data // is incomplete. WebPBitstreamFeatures features; const VP8StatusCode vp8_status = - WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size, + WebPGetFeatures(mem->buf + chunk_start_offset, chunk_size, &features); if (status == PARSE_NEED_MORE_DATA && vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) { return PARSE_NEED_MORE_DATA; } else if (vp8_status != VP8_STATUS_OK) { @@ -279,11 +282,11 @@ Rewind(mem, CHUNK_HEADER_SIZE); done = 1; break; } - if (mem->start_ == mem->riff_end_) { + if (mem->start == mem->riff_end) { done = 1; } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { status = PARSE_NEED_MORE_DATA; } } while (!done && status == PARSE_OK); @@ -308,46 +311,46 @@ // Parse a 'ANMF' chunk and any image bearing chunks that immediately follow. // 'frame_chunk_size' is the previously validated, padded chunk size. static ParseStatus ParseAnimationFrame( WebPDemuxer* const dmux, uint32_t frame_chunk_size) { - const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); + const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG); const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE; int added_frame = 0; int bits; - MemBuffer* const mem = &dmux->mem_; + MemBuffer* const mem = &dmux->mem; Frame* frame; size_t start_offset; ParseStatus status = NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame); if (status != PARSE_OK) return status; - frame->x_offset_ = 2 * ReadLE24s(mem); - frame->y_offset_ = 2 * ReadLE24s(mem); - frame->width_ = 1 + ReadLE24s(mem); - frame->height_ = 1 + ReadLE24s(mem); - frame->duration_ = ReadLE24s(mem); + frame->x_offset = 2 * ReadLE24s(mem); + frame->y_offset = 2 * ReadLE24s(mem); + frame->width = 1 + ReadLE24s(mem); + frame->height = 1 + ReadLE24s(mem); + frame->duration = ReadLE24s(mem); bits = ReadByte(mem); - frame->dispose_method_ = + frame->dispose_method = (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; - frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; - if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { + frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; + if (frame->width * (uint64_t)frame->height >= MAX_IMAGE_AREA) { WebPSafeFree(frame); return PARSE_ERROR; } // Store a frame only if the animation flag is set there is some data for // this frame is available. - start_offset = mem->start_; - status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame); - if (status != PARSE_ERROR && mem->start_ - start_offset > anmf_payload_size) { + start_offset = mem->start; + status = StoreFrame(dmux->num_frames + 1, anmf_payload_size, mem, frame); + if (status != PARSE_ERROR && mem->start - start_offset > anmf_payload_size) { status = PARSE_ERROR; } - if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) { + if (status != PARSE_ERROR && is_animation && frame->frame_num > 0) { added_frame = AddFrame(dmux, frame); if (added_frame) { - ++dmux->num_frames_; + ++dmux->num_frames; } else { status = PARSE_ERROR; } } @@ -362,12 +365,12 @@ static int StoreChunk(WebPDemuxer* const dmux, size_t start_offset, uint32_t size) { Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk)); if (chunk == NULL) return 0; - chunk->data_.offset_ = start_offset; - chunk->data_.size_ = size; + chunk->data.offset = start_offset; + chunk->data.size = size; AddChunk(dmux, chunk); return 1; } // ----------------------------------------------------------------------------- @@ -387,74 +390,74 @@ riff_size = GetLE32(GetBuffer(mem) + TAG_SIZE); if (riff_size < CHUNK_HEADER_SIZE) return PARSE_ERROR; if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; // There's no point in reading past the end of the RIFF chunk - mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE; - if (mem->buf_size_ > mem->riff_end_) { - mem->buf_size_ = mem->end_ = mem->riff_end_; + mem->riff_end = riff_size + CHUNK_HEADER_SIZE; + if (mem->buf_size > mem->riff_end) { + mem->buf_size = mem->end = mem->riff_end; } Skip(mem, RIFF_HEADER_SIZE); return PARSE_OK; } static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { const size_t min_size = CHUNK_HEADER_SIZE; - MemBuffer* const mem = &dmux->mem_; + MemBuffer* const mem = &dmux->mem; Frame* frame; ParseStatus status; int image_added = 0; - if (dmux->frames_ != NULL) return PARSE_ERROR; + if (dmux->frames != NULL) return PARSE_ERROR; if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame)); if (frame == NULL) return PARSE_ERROR; // For the single image case we allow parsing of a partial frame, so no // minimum size is imposed here. - status = StoreFrame(1, 0, &dmux->mem_, frame); + status = StoreFrame(1, 0, &dmux->mem, frame); if (status != PARSE_ERROR) { - const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); + const int has_alpha = !!(dmux->feature_flags & ALPHA_FLAG); // Clear any alpha when the alpha flag is missing. - if (!has_alpha && frame->img_components_[1].size_ > 0) { - frame->img_components_[1].offset_ = 0; - frame->img_components_[1].size_ = 0; - frame->has_alpha_ = 0; + if (!has_alpha && frame->img_components[1].size > 0) { + frame->img_components[1].offset = 0; + frame->img_components[1].size = 0; + frame->has_alpha = 0; } // Use the frame width/height as the canvas values for non-vp8x files. // Also, set ALPHA_FLAG if this is a lossless image with alpha. - if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { - dmux->state_ = WEBP_DEMUX_PARSED_HEADER; - dmux->canvas_width_ = frame->width_; - dmux->canvas_height_ = frame->height_; - dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0; + if (!dmux->is_ext_format && frame->width > 0 && frame->height > 0) { + dmux->state = WEBP_DEMUX_PARSED_HEADER; + dmux->canvas_width = frame->width; + dmux->canvas_height = frame->height; + dmux->feature_flags |= frame->has_alpha ? ALPHA_FLAG : 0; } if (!AddFrame(dmux, frame)) { status = PARSE_ERROR; // last frame was left incomplete } else { image_added = 1; - dmux->num_frames_ = 1; + dmux->num_frames = 1; } } if (!image_added) WebPSafeFree(frame); return status; } static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { - const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); - MemBuffer* const mem = &dmux->mem_; + const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG); + MemBuffer* const mem = &dmux->mem; int anim_chunks = 0; ParseStatus status = PARSE_OK; do { int store_chunk = 1; - const size_t chunk_start_offset = mem->start_; + const size_t chunk_start_offset = mem->start; const uint32_t fourcc = ReadLE32(mem); const uint32_t chunk_size = ReadLE32(mem); uint32_t chunk_size_padded; if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; @@ -481,12 +484,12 @@ if (MemDataSize(mem) < chunk_size_padded) { status = PARSE_NEED_MORE_DATA; } else if (anim_chunks == 0) { ++anim_chunks; - dmux->bgcolor_ = ReadLE32(mem); - dmux->loop_count_ = ReadLE16s(mem); + dmux->bgcolor = ReadLE32(mem); + dmux->loop_count = ReadLE16s(mem); Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE); } else { store_chunk = 0; goto Skip; } @@ -496,19 +499,19 @@ if (anim_chunks == 0) return PARSE_ERROR; // 'ANIM' precedes frames. status = ParseAnimationFrame(dmux, chunk_size_padded); break; } case MKFOURCC('I', 'C', 'C', 'P'): { - store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); + store_chunk = !!(dmux->feature_flags & ICCP_FLAG); goto Skip; } case MKFOURCC('E', 'X', 'I', 'F'): { - store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG); + store_chunk = !!(dmux->feature_flags & EXIF_FLAG); goto Skip; } case MKFOURCC('X', 'M', 'P', ' '): { - store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); + store_chunk = !!(dmux->feature_flags & XMP_FLAG); goto Skip; } Skip: default: { if (chunk_size_padded <= MemDataSize(mem)) { @@ -525,44 +528,44 @@ status = PARSE_NEED_MORE_DATA; } } } - if (mem->start_ == mem->riff_end_) { + if (mem->start == mem->riff_end) { break; } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { status = PARSE_NEED_MORE_DATA; } } while (status == PARSE_OK); return status; } static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { - MemBuffer* const mem = &dmux->mem_; + MemBuffer* const mem = &dmux->mem; uint32_t vp8x_size; if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; - dmux->is_ext_format_ = 1; + dmux->is_ext_format = 1; Skip(mem, TAG_SIZE); // VP8X vp8x_size = ReadLE32(mem); if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR; vp8x_size += vp8x_size & 1; if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR; if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA; - dmux->feature_flags_ = ReadByte(mem); + dmux->feature_flags = ReadByte(mem); Skip(mem, 3); // Reserved. - dmux->canvas_width_ = 1 + ReadLE24s(mem); - dmux->canvas_height_ = 1 + ReadLE24s(mem); - if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) { + dmux->canvas_width = 1 + ReadLE24s(mem); + dmux->canvas_height = 1 + ReadLE24s(mem); + if (dmux->canvas_width * (uint64_t)dmux->canvas_height >= MAX_IMAGE_AREA) { return PARSE_ERROR; // image final dimension is too large } Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. - dmux->state_ = WEBP_DEMUX_PARSED_HEADER; + dmux->state = WEBP_DEMUX_PARSED_HEADER; if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR; if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; return ParseVP8XChunks(dmux); @@ -570,84 +573,84 @@ // ----------------------------------------------------------------------------- // Format validation static int IsValidSimpleFormat(const WebPDemuxer* const dmux) { - const Frame* const frame = dmux->frames_; - if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; + const Frame* const frame = dmux->frames; + if (dmux->state == WEBP_DEMUX_PARSING_HEADER) return 1; - if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; - if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0; + if (dmux->canvas_width <= 0 || dmux->canvas_height <= 0) return 0; + if (dmux->state == WEBP_DEMUX_DONE && frame == NULL) return 0; - if (frame->width_ <= 0 || frame->height_ <= 0) return 0; + if (frame->width <= 0 || frame->height <= 0) return 0; return 1; } // If 'exact' is true, check that the image resolution matches the canvas. // If 'exact' is false, check that the x/y offsets do not exceed the canvas. static int CheckFrameBounds(const Frame* const frame, int exact, int canvas_width, int canvas_height) { if (exact) { - if (frame->x_offset_ != 0 || frame->y_offset_ != 0) { + if (frame->x_offset != 0 || frame->y_offset != 0) { return 0; } - if (frame->width_ != canvas_width || frame->height_ != canvas_height) { + if (frame->width != canvas_width || frame->height != canvas_height) { return 0; } } else { - if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0; - if (frame->width_ + frame->x_offset_ > canvas_width) return 0; - if (frame->height_ + frame->y_offset_ > canvas_height) return 0; + if (frame->x_offset < 0 || frame->y_offset < 0) return 0; + if (frame->width + frame->x_offset > canvas_width) return 0; + if (frame->height + frame->y_offset > canvas_height) return 0; } return 1; } static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { - const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); - const Frame* f = dmux->frames_; + const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG); + const Frame* f = dmux->frames; - if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; + if (dmux->state == WEBP_DEMUX_PARSING_HEADER) return 1; - if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; - if (dmux->loop_count_ < 0) return 0; - if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; - if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream + if (dmux->canvas_width <= 0 || dmux->canvas_height <= 0) return 0; + if (dmux->loop_count < 0) return 0; + if (dmux->state == WEBP_DEMUX_DONE && dmux->frames == NULL) return 0; + if (dmux->feature_flags & ~ALL_VALID_FLAGS) return 0; // invalid bitstream while (f != NULL) { - const int cur_frame_set = f->frame_num_; + const int cur_frame_set = f->frame_num; // Check frame properties. - for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { - const ChunkData* const image = f->img_components_; - const ChunkData* const alpha = f->img_components_ + 1; + for (; f != NULL && f->frame_num == cur_frame_set; f = f->next) { + const ChunkData* const image = f->img_components; + const ChunkData* const alpha = f->img_components + 1; - if (!is_animation && f->frame_num_ > 1) return 0; + if (!is_animation && f->frame_num > 1) return 0; - if (f->complete_) { - if (alpha->size_ == 0 && image->size_ == 0) return 0; + if (f->complete) { + if (alpha->size == 0 && image->size == 0) return 0; // Ensure alpha precedes image bitstream. - if (alpha->size_ > 0 && alpha->offset_ > image->offset_) { + if (alpha->size > 0 && alpha->offset > image->offset) { return 0; } - if (f->width_ <= 0 || f->height_ <= 0) return 0; + if (f->width <= 0 || f->height <= 0) return 0; } else { // There shouldn't be a partial frame in a complete file. - if (dmux->state_ == WEBP_DEMUX_DONE) return 0; + if (dmux->state == WEBP_DEMUX_DONE) return 0; // Ensure alpha precedes image bitstream. - if (alpha->size_ > 0 && image->size_ > 0 && - alpha->offset_ > image->offset_) { + if (alpha->size > 0 && image->size > 0 && + alpha->offset > image->offset) { return 0; } // There shouldn't be any frames after an incomplete one. - if (f->next_ != NULL) return 0; + if (f->next != NULL) return 0; } - if (f->width_ > 0 && f->height_ > 0 && + if (f->width > 0 && f->height > 0 && !CheckFrameBounds(f, !is_animation, - dmux->canvas_width_, dmux->canvas_height_)) { + dmux->canvas_width, dmux->canvas_height)) { return 0; } } } return 1; @@ -655,25 +658,25 @@ // ----------------------------------------------------------------------------- // WebPDemuxer object static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) { - dmux->state_ = WEBP_DEMUX_PARSING_HEADER; - dmux->loop_count_ = 1; - dmux->bgcolor_ = 0xFFFFFFFF; // White background by default. - dmux->canvas_width_ = -1; - dmux->canvas_height_ = -1; - dmux->frames_tail_ = &dmux->frames_; - dmux->chunks_tail_ = &dmux->chunks_; - dmux->mem_ = *mem; + dmux->state = WEBP_DEMUX_PARSING_HEADER; + dmux->loop_count = 1; + dmux->bgcolor = 0xFFFFFFFF; // White background by default. + dmux->canvas_width = -1; + dmux->canvas_height = -1; + dmux->frames_tail = &dmux->frames; + dmux->chunks_tail = &dmux->chunks; + dmux->mem = *mem; } static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem, WebPDemuxer** demuxer) { WebPBitstreamFeatures features; const VP8StatusCode status = - WebPGetFeatures(mem->buf_, mem->buf_size_, &features); + WebPGetFeatures(mem->buf, mem->buf_size, &features); *demuxer = NULL; if (status != VP8_STATUS_OK) { return (status == VP8_STATUS_NOT_ENOUGH_DATA) ? PARSE_NEED_MORE_DATA : PARSE_ERROR; } @@ -681,18 +684,18 @@ { WebPDemuxer* const dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux)); Frame* const frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame)); if (dmux == NULL || frame == NULL) goto Error; InitDemux(dmux, mem); - SetFrameInfo(0, mem->buf_size_, 1 /*frame_num*/, 1 /*complete*/, &features, + SetFrameInfo(0, mem->buf_size, 1 /*frame_num*/, 1 /*complete*/, &features, frame); if (!AddFrame(dmux, frame)) goto Error; - dmux->state_ = WEBP_DEMUX_DONE; - dmux->canvas_width_ = frame->width_; - dmux->canvas_height_ = frame->height_; - dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0; - dmux->num_frames_ = 1; + dmux->state = WEBP_DEMUX_DONE; + dmux->canvas_width = frame->width; + dmux->canvas_height = frame->height; + dmux->feature_flags |= frame->has_alpha ? ALPHA_FLAG : 0; + dmux->num_frames = 1; assert(IsValidSimpleFormat(dmux)); *demuxer = dmux; return PARSE_OK; Error: @@ -732,29 +735,29 @@ : WEBP_DEMUX_PARSE_ERROR; } return NULL; } - partial = (mem.buf_size_ < mem.riff_end_); + partial = (mem.buf_size < mem.riff_end); if (!allow_partial && partial) return NULL; dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux)); if (dmux == NULL) return NULL; InitDemux(dmux, &mem); status = PARSE_ERROR; for (parser = kMasterChunks; parser->parse != NULL; ++parser) { - if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) { + if (!memcmp(parser->id, GetBuffer(&dmux->mem), TAG_SIZE)) { status = parser->parse(dmux); - if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE; + if (status == PARSE_OK) dmux->state = WEBP_DEMUX_DONE; if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR; if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR; - if (status == PARSE_ERROR) dmux->state_ = WEBP_DEMUX_PARSE_ERROR; + if (status == PARSE_ERROR) dmux->state = WEBP_DEMUX_PARSE_ERROR; break; } } - if (state != NULL) *state = dmux->state_; + if (state != NULL) *state = dmux->state; if (status == PARSE_ERROR) { WebPDemuxDelete(dmux); return NULL; } @@ -764,18 +767,18 @@ void WebPDemuxDelete(WebPDemuxer* dmux) { Chunk* c; Frame* f; if (dmux == NULL) return; - for (f = dmux->frames_; f != NULL;) { + for (f = dmux->frames; f != NULL;) { Frame* const cur_frame = f; - f = f->next_; + f = f->next; WebPSafeFree(cur_frame); } - for (c = dmux->chunks_; c != NULL;) { + for (c = dmux->chunks; c != NULL;) { Chunk* const cur_chunk = c; - c = c->next_; + c = c->next; WebPSafeFree(cur_chunk); } WebPSafeFree(dmux); } @@ -783,87 +786,87 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) { if (dmux == NULL) return 0; switch (feature) { - case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags_; - case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width_; - case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height_; - case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_; - case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor_; - case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames_; + case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags; + case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width; + case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height; + case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count; + case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor; + case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames; } return 0; } // ----------------------------------------------------------------------------- // Frame iteration static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) { const Frame* f; - for (f = dmux->frames_; f != NULL; f = f->next_) { - if (frame_num == f->frame_num_) break; + for (f = dmux->frames; f != NULL; f = f->next) { + if (frame_num == f->frame_num) break; } return f; } static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, const Frame* const frame, size_t* const data_size) { *data_size = 0; if (frame != NULL) { - const ChunkData* const image = frame->img_components_; - const ChunkData* const alpha = frame->img_components_ + 1; - size_t start_offset = image->offset_; - *data_size = image->size_; + const ChunkData* const image = frame->img_components; + const ChunkData* const alpha = frame->img_components + 1; + size_t start_offset = image->offset; + *data_size = image->size; // if alpha exists it precedes image, update the size allowing for // intervening chunks. - if (alpha->size_ > 0) { - const size_t inter_size = (image->offset_ > 0) - ? image->offset_ - (alpha->offset_ + alpha->size_) + if (alpha->size > 0) { + const size_t inter_size = (image->offset > 0) + ? image->offset - (alpha->offset + alpha->size) : 0; - start_offset = alpha->offset_; - *data_size += alpha->size_ + inter_size; + start_offset = alpha->offset; + *data_size += alpha->size + inter_size; } return mem_buf + start_offset; } return NULL; } // Create a whole 'frame' from VP8 (+ alpha) or lossless. static int SynthesizeFrame(const WebPDemuxer* const dmux, const Frame* const frame, WebPIterator* const iter) { - const uint8_t* const mem_buf = dmux->mem_.buf_; + const uint8_t* const mem_buf = dmux->mem.buf; size_t payload_size = 0; const uint8_t* const payload = GetFramePayload(mem_buf, frame, &payload_size); if (payload == NULL) return 0; assert(frame != NULL); - iter->frame_num = frame->frame_num_; - iter->num_frames = dmux->num_frames_; - iter->x_offset = frame->x_offset_; - iter->y_offset = frame->y_offset_; - iter->width = frame->width_; - iter->height = frame->height_; - iter->has_alpha = frame->has_alpha_; - iter->duration = frame->duration_; - iter->dispose_method = frame->dispose_method_; - iter->blend_method = frame->blend_method_; - iter->complete = frame->complete_; + iter->frame_num = frame->frame_num; + iter->num_frames = dmux->num_frames; + iter->x_offset = frame->x_offset; + iter->y_offset = frame->y_offset; + iter->width = frame->width; + iter->height = frame->height; + iter->has_alpha = frame->has_alpha; + iter->duration = frame->duration; + iter->dispose_method = frame->dispose_method; + iter->blend_method = frame->blend_method; + iter->complete = frame->complete; iter->fragment.bytes = payload; iter->fragment.size = payload_size; return 1; } static int SetFrame(int frame_num, WebPIterator* const iter) { const Frame* frame; const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; if (dmux == NULL || frame_num < 0) return 0; - if (frame_num > dmux->num_frames_) return 0; - if (frame_num == 0) frame_num = dmux->num_frames_; + if (frame_num > dmux->num_frames) return 0; + if (frame_num == 0) frame_num = dmux->num_frames; frame = GetFrame(dmux, frame_num); if (frame == NULL) return 0; return SynthesizeFrame(dmux, frame, iter); @@ -894,27 +897,27 @@ // ----------------------------------------------------------------------------- // Chunk iteration static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) { - const uint8_t* const mem_buf = dmux->mem_.buf_; + const uint8_t* const mem_buf = dmux->mem.buf; const Chunk* c; int count = 0; - for (c = dmux->chunks_; c != NULL; c = c->next_) { - const uint8_t* const header = mem_buf + c->data_.offset_; + for (c = dmux->chunks; c != NULL; c = c->next) { + const uint8_t* const header = mem_buf + c->data.offset; if (!memcmp(header, fourcc, TAG_SIZE)) ++count; } return count; } static const Chunk* GetChunk(const WebPDemuxer* const dmux, const char fourcc[4], int chunk_num) { - const uint8_t* const mem_buf = dmux->mem_.buf_; + const uint8_t* const mem_buf = dmux->mem.buf; const Chunk* c; int count = 0; - for (c = dmux->chunks_; c != NULL; c = c->next_) { - const uint8_t* const header = mem_buf + c->data_.offset_; + for (c = dmux->chunks; c != NULL; c = c->next) { + const uint8_t* const header = mem_buf + c->data.offset; if (!memcmp(header, fourcc, TAG_SIZE)) ++count; if (count == chunk_num) break; } return c; } @@ -928,14 +931,14 @@ count = ChunkCount(dmux, fourcc); if (count == 0) return 0; if (chunk_num == 0) chunk_num = count; if (chunk_num <= count) { - const uint8_t* const mem_buf = dmux->mem_.buf_; + const uint8_t* const mem_buf = dmux->mem.buf; const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num); - iter->chunk.bytes = mem_buf + chunk->data_.offset_ + CHUNK_HEADER_SIZE; - iter->chunk.size = chunk->data_.size_ - CHUNK_HEADER_SIZE; + iter->chunk.bytes = mem_buf + chunk->data.offset + CHUNK_HEADER_SIZE; + iter->chunk.size = chunk->data.size - CHUNK_HEADER_SIZE; iter->num_chunks = count; iter->chunk_num = chunk_num; return 1; } return 0; @@ -970,6 +973,5 @@ } void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) { (void)iter; } - diff --git a/media/libwebp/src/dsp/alpha_processing.c b/media/libwebp/src/dsp/alpha_processing.c --- a/media/libwebp/src/dsp/alpha_processing.c +++ b/media/libwebp/src/dsp/alpha_processing.c @@ -10,11 +10,15 @@ // Utilities for processing transparent channel. // // Author: Skal (pascal.massimino@gmail.com) #include +#include + +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" +#include "src/webp/types.h" // Tables can be faster on some platform but incur some extra binary size (~2k). #if !defined(USE_TABLES_FOR_ALPHA_MULT) #define USE_TABLES_FOR_ALPHA_MULT 0 // ALTERNATE_CODE #endif diff --git a/media/libwebp/src/dsp/alpha_processing_sse2.c b/media/libwebp/src/dsp/alpha_processing_sse2.c --- a/media/libwebp/src/dsp/alpha_processing_sse2.c +++ b/media/libwebp/src/dsp/alpha_processing_sse2.c @@ -14,64 +14,74 @@ #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE2) #include +#include "src/webp/types.h" +#include "src/dsp/cpu.h" + //------------------------------------------------------------------------------ static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride, int width, int height, uint8_t* WEBP_RESTRICT dst, int dst_stride) { // alpha_and stores an 'and' operation of all the alpha[] values. The final // value is not 0xff if any of the alpha[] is not equal to 0xff. uint32_t alpha_and = 0xff; int i, j; const __m128i zero = _mm_setzero_si128(); - const __m128i rgb_mask = _mm_set1_epi32((int)0xffffff00); // to preserve RGB - const __m128i all_0xff = _mm_set_epi32(0, 0, ~0, ~0); - __m128i all_alphas = all_0xff; + const __m128i alpha_mask = _mm_set1_epi32((int)0xff); // to preserve A + const __m128i all_0xff = _mm_set1_epi8((char)0xff); + __m128i all_alphas16 = all_0xff; + __m128i all_alphas8 = all_0xff; // We must be able to access 3 extra bytes after the last written byte // 'dst[4 * width - 4]', because we don't know if alpha is the first or the // last byte of the quadruplet. - const int limit = (width - 1) & ~7; - for (j = 0; j < height; ++j) { - __m128i* out = (__m128i*)dst; - for (i = 0; i < limit; i += 8) { + char* ptr = (char*)dst; + for (i = 0; i + 16 <= width - 1; i += 16) { + // load 16 alpha bytes + const __m128i a0 = _mm_loadu_si128((const __m128i*)&alpha[i]); + const __m128i a1_lo = _mm_unpacklo_epi8(a0, zero); + const __m128i a1_hi = _mm_unpackhi_epi8(a0, zero); + const __m128i a2_lo_lo = _mm_unpacklo_epi16(a1_lo, zero); + const __m128i a2_lo_hi = _mm_unpackhi_epi16(a1_lo, zero); + const __m128i a2_hi_lo = _mm_unpacklo_epi16(a1_hi, zero); + const __m128i a2_hi_hi = _mm_unpackhi_epi16(a1_hi, zero); + _mm_maskmoveu_si128(a2_lo_lo, alpha_mask, ptr + 0); + _mm_maskmoveu_si128(a2_lo_hi, alpha_mask, ptr + 16); + _mm_maskmoveu_si128(a2_hi_lo, alpha_mask, ptr + 32); + _mm_maskmoveu_si128(a2_hi_hi, alpha_mask, ptr + 48); + // accumulate 16 alpha 'and' in parallel + all_alphas16 = _mm_and_si128(all_alphas16, a0); + ptr += 64; + } + if (i + 8 <= width - 1) { // load 8 alpha bytes const __m128i a0 = _mm_loadl_epi64((const __m128i*)&alpha[i]); const __m128i a1 = _mm_unpacklo_epi8(a0, zero); const __m128i a2_lo = _mm_unpacklo_epi16(a1, zero); const __m128i a2_hi = _mm_unpackhi_epi16(a1, zero); - // load 8 dst pixels (32 bytes) - const __m128i b0_lo = _mm_loadu_si128(out + 0); - const __m128i b0_hi = _mm_loadu_si128(out + 1); - // mask dst alpha values - const __m128i b1_lo = _mm_and_si128(b0_lo, rgb_mask); - const __m128i b1_hi = _mm_and_si128(b0_hi, rgb_mask); - // combine - const __m128i b2_lo = _mm_or_si128(b1_lo, a2_lo); - const __m128i b2_hi = _mm_or_si128(b1_hi, a2_hi); - // store - _mm_storeu_si128(out + 0, b2_lo); - _mm_storeu_si128(out + 1, b2_hi); - // accumulate eight alpha 'and' in parallel - all_alphas = _mm_and_si128(all_alphas, a0); - out += 2; + _mm_maskmoveu_si128(a2_lo, alpha_mask, ptr); + _mm_maskmoveu_si128(a2_hi, alpha_mask, ptr + 16); + // accumulate 8 alpha 'and' in parallel + all_alphas8 = _mm_and_si128(all_alphas8, a0); + i += 8; } for (; i < width; ++i) { const uint32_t alpha_value = alpha[i]; dst[4 * i] = alpha_value; alpha_and &= alpha_value; } alpha += alpha_stride; dst += dst_stride; } // Combine the eight alpha 'and' into a 8-bit mask. - alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff)); - return (alpha_and != 0xff); + alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas8, all_0xff)) & 0xff; + return (alpha_and != 0xff || + _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas16, all_0xff)) != 0xffff); } static void DispatchAlphaToGreen_SSE2(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride, int width, int height, uint32_t* WEBP_RESTRICT dst, diff --git a/media/libwebp/src/dsp/alpha_processing_sse41.c b/media/libwebp/src/dsp/alpha_processing_sse41.c --- a/media/libwebp/src/dsp/alpha_processing_sse41.c +++ b/media/libwebp/src/dsp/alpha_processing_sse41.c @@ -9,14 +9,16 @@ // // Utilities for processing transparent channel, SSE4.1 variant. // // Author: Skal (pascal.massimino@gmail.com) +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) - +#include #include //------------------------------------------------------------------------------ static int ExtractAlpha_SSE41(const uint8_t* WEBP_RESTRICT argb, diff --git a/media/libwebp/src/dsp/cost.c b/media/libwebp/src/dsp/cost.c --- a/media/libwebp/src/dsp/cost.c +++ b/media/libwebp/src/dsp/cost.c @@ -7,12 +7,19 @@ // be found in the AUTHORS file in the root of the source tree. // ----------------------------------------------------------------------------- // // Author: Skal (pascal.massimino@gmail.com) +#include +#include +#include + +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" #include "src/enc/cost_enc.h" +#include "src/enc/vp8i_enc.h" //------------------------------------------------------------------------------ // Boolean-cost cost table const uint16_t VP8EntropyCost[256] = { diff --git a/media/libwebp/src/dsp/cost_sse2.c b/media/libwebp/src/dsp/cost_sse2.c --- a/media/libwebp/src/dsp/cost_sse2.c +++ b/media/libwebp/src/dsp/cost_sse2.c @@ -14,10 +14,14 @@ #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE2) #include +#include + +#include "src/webp/types.h" +#include "src/dsp/cpu.h" #include "src/enc/cost_enc.h" #include "src/enc/vp8i_enc.h" #include "src/utils/utils.h" //------------------------------------------------------------------------------ diff --git a/media/libwebp/src/dsp/cpu.h b/media/libwebp/src/dsp/cpu.h --- a/media/libwebp/src/dsp/cpu.h +++ b/media/libwebp/src/dsp/cpu.h @@ -54,10 +54,15 @@ #if defined(_MSC_VER) && _MSC_VER >= 1500 && \ (defined(_M_X64) || defined(_M_IX86)) #define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets #endif + +#if defined(_MSC_VER) && _MSC_VER >= 1700 && \ + (defined(_M_X64) || defined(_M_IX86)) +#define WEBP_MSC_AVX2 // Visual C++ AVX2 targets +#endif #endif // WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp // files without intrinsics, allowing the corresponding Init() to be called. // Files containing intrinsics will need to be built targeting the instruction @@ -78,10 +83,20 @@ #if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41) #define WEBP_HAVE_SSE41 #endif +#if (defined(__AVX2__) || defined(WEBP_MSC_AVX2)) && \ + (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_AVX2)) +#define WEBP_USE_AVX2 +#endif + +#if defined(WEBP_USE_AVX2) && !defined(WEBP_HAVE_AVX2) +#define WEBP_HAVE_AVX2 +#endif + +#undef WEBP_MSC_AVX2 #undef WEBP_MSC_SSE41 #undef WEBP_MSC_SSE2 //------------------------------------------------------------------------------ // Arm defines. diff --git a/media/libwebp/src/dsp/dec.c b/media/libwebp/src/dsp/dec.c --- a/media/libwebp/src/dsp/dec.c +++ b/media/libwebp/src/dsp/dec.c @@ -10,14 +10,19 @@ // Speed-critical decoding functions, default plain-C implementations. // // Author: Skal (pascal.massimino@gmail.com) #include +#include +#include +#include "src/dec/common_dec.h" +#include "src/dec/vp8i_dec.h" +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" -#include "src/dec/vp8i_dec.h" #include "src/utils/utils.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ static WEBP_INLINE uint8_t clip_8b(int v) { return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; diff --git a/media/libwebp/src/dsp/dec_clip_tables.c b/media/libwebp/src/dsp/dec_clip_tables.c --- a/media/libwebp/src/dsp/dec_clip_tables.c +++ b/media/libwebp/src/dsp/dec_clip_tables.c @@ -9,10 +9,12 @@ // // Clipping tables for filtering // // Author: Skal (pascal.massimino@gmail.com) +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" // define to 0 to have run-time table initialization #if !defined(USE_STATIC_TABLES) #define USE_STATIC_TABLES 1 // ALTERNATE_CODE diff --git a/media/libwebp/src/dsp/dec_sse2.c b/media/libwebp/src/dsp/dec_sse2.c --- a/media/libwebp/src/dsp/dec_sse2.c +++ b/media/libwebp/src/dsp/dec_sse2.c @@ -21,13 +21,16 @@ #if !defined(USE_TRANSFORM_AC3) #define USE_TRANSFORM_AC3 0 // ALTERNATE_CODE #endif #include -#include "src/dsp/common_sse2.h" + #include "src/dec/vp8i_dec.h" +#include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" #include "src/utils/utils.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Transforms (Paragraph 14.4) static void Transform_SSE2(const int16_t* WEBP_RESTRICT in, diff --git a/media/libwebp/src/dsp/dec_sse41.c b/media/libwebp/src/dsp/dec_sse41.c --- a/media/libwebp/src/dsp/dec_sse41.c +++ b/media/libwebp/src/dsp/dec_sse41.c @@ -12,13 +12,16 @@ // Author: Skal (pascal.massimino@gmail.com) #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) - +#include #include + +#include "src/webp/types.h" #include "src/dec/vp8i_dec.h" +#include "src/dsp/cpu.h" #include "src/utils/utils.h" static void HE16_SSE41(uint8_t* dst) { // horizontal int j; const __m128i kShuffle3 = _mm_set1_epi8(3); diff --git a/media/libwebp/src/dsp/enc.c b/media/libwebp/src/dsp/enc.c --- a/media/libwebp/src/dsp/enc.c +++ b/media/libwebp/src/dsp/enc.c @@ -11,13 +11,17 @@ // // Author: Skal (pascal.massimino@gmail.com) #include #include // for abs() +#include +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" #include "src/enc/vp8i_enc.h" +#include "src/utils/utils.h" +#include "src/webp/types.h" static WEBP_INLINE uint8_t clip_8b(int v) { return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; } @@ -686,15 +690,15 @@ int last = -1; int n; for (n = 0; n < 16; ++n) { const int j = kZigzag[n]; const int sign = (in[j] < 0); - const uint32_t coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; - if (coeff > mtx->zthresh_[j]) { - const uint32_t Q = mtx->q_[j]; - const uint32_t iQ = mtx->iq_[j]; - const uint32_t B = mtx->bias_[j]; + const uint32_t coeff = (sign ? -in[j] : in[j]) + mtx->sharpen[j]; + if (coeff > mtx->zthresh[j]) { + const uint32_t Q = mtx->q[j]; + const uint32_t iQ = mtx->iq[j]; + const uint32_t B = mtx->bias[j]; int level = QUANTDIV(coeff, iQ, B); if (level > MAX_LEVEL) level = MAX_LEVEL; if (sign) level = -level; in[j] = level * (int)Q; out[n] = level; diff --git a/media/libwebp/src/dsp/enc_mips32.c b/media/libwebp/src/dsp/enc_mips32.c --- a/media/libwebp/src/dsp/enc_mips32.c +++ b/media/libwebp/src/dsp/enc_mips32.c @@ -191,15 +191,15 @@ int sign, coeff, level, i; int max_level = MAX_LEVEL; int16_t* ppin = &in[0]; int16_t* pout = &out[0]; - const uint16_t* ppsharpen = &mtx->sharpen_[0]; - const uint32_t* ppzthresh = &mtx->zthresh_[0]; - const uint16_t* ppq = &mtx->q_[0]; - const uint16_t* ppiq = &mtx->iq_[0]; - const uint32_t* ppbias = &mtx->bias_[0]; + const uint16_t* ppsharpen = &mtx->sharpen[0]; + const uint32_t* ppzthresh = &mtx->zthresh[0]; + const uint16_t* ppq = &mtx->q[0]; + const uint16_t* ppiq = &mtx->iq[0]; + const uint32_t* ppbias = &mtx->bias[0]; __asm__ volatile( QUANTIZE_ONE( 0, 0, 0) QUANTIZE_ONE( 2, 4, 2) QUANTIZE_ONE( 8, 16, 4) diff --git a/media/libwebp/src/dsp/enc_mips_dsp_r2.c b/media/libwebp/src/dsp/enc_mips_dsp_r2.c --- a/media/libwebp/src/dsp/enc_mips_dsp_r2.c +++ b/media/libwebp/src/dsp/enc_mips_dsp_r2.c @@ -1294,15 +1294,15 @@ int max_level1 = max_level << 16 | max_level; int ret = 0; int16_t* ppin = &in[0]; int16_t* pout = &out[0]; - const uint16_t* ppsharpen = &mtx->sharpen_[0]; - const uint32_t* ppzthresh = &mtx->zthresh_[0]; - const uint16_t* ppq = &mtx->q_[0]; - const uint16_t* ppiq = &mtx->iq_[0]; - const uint32_t* ppbias = &mtx->bias_[0]; + const uint16_t* ppsharpen = &mtx->sharpen[0]; + const uint32_t* ppzthresh = &mtx->zthresh[0]; + const uint16_t* ppq = &mtx->q[0]; + const uint16_t* ppiq = &mtx->iq[0]; + const uint32_t* ppbias = &mtx->bias[0]; __asm__ volatile ( QUANTIZE_ONE( 0, 0, 0, 2) QUANTIZE_ONE( 4, 8, 10, 12) QUANTIZE_ONE( 8, 16, 4, 8) diff --git a/media/libwebp/src/dsp/enc_msa.c b/media/libwebp/src/dsp/enc_msa.c --- a/media/libwebp/src/dsp/enc_msa.c +++ b/media/libwebp/src/dsp/enc_msa.c @@ -843,22 +843,22 @@ const v8i16 zigzag0 = { 0, 1, 4, 8, 5, 2, 3, 6 }; const v8i16 zigzag1 = { 9, 12, 13, 10, 7, 11, 14, 15 }; const v8i16 maxlevel = __msa_fill_h(MAX_LEVEL); LD_SH2(&in[0], 8, in0, in1); - LD_SH2(&mtx->sharpen_[0], 8, sh0, sh1); + LD_SH2(&mtx->sharpen[0], 8, sh0, sh1); tmp4 = __msa_add_a_h(in0, zero); tmp5 = __msa_add_a_h(in1, zero); ILVRL_H2_SH(sh0, tmp4, tmp0, tmp1); ILVRL_H2_SH(sh1, tmp5, tmp2, tmp3); HADD_SH4_SW(tmp0, tmp1, tmp2, tmp3, s0, s1, s2, s3); sign0 = (in0 < zero); sign1 = (in1 < zero); // sign - LD_SH2(&mtx->iq_[0], 8, tmp0, tmp1); // iq + LD_SH2(&mtx->iq[0], 8, tmp0, tmp1); // iq ILVRL_H2_SW(zero, tmp0, t0, t1); ILVRL_H2_SW(zero, tmp1, t2, t3); - LD_SW4(&mtx->bias_[0], 4, b0, b1, b2, b3); // bias + LD_SW4(&mtx->bias[0], 4, b0, b1, b2, b3); // bias MUL4(t0, s0, t1, s1, t2, s2, t3, s3, t0, t1, t2, t3); ADD4(b0, t0, b1, t1, b2, t2, b3, t3, b0, b1, b2, b3); SRAI_W4_SW(b0, b1, b2, b3, 17); PCKEV_H2_SH(b1, b0, b3, b2, tmp2, tmp3); tmp0 = (tmp2 > maxlevel); @@ -866,19 +866,19 @@ tmp2 = (v8i16)__msa_bmnz_v((v16u8)tmp2, (v16u8)maxlevel, (v16u8)tmp0); tmp3 = (v8i16)__msa_bmnz_v((v16u8)tmp3, (v16u8)maxlevel, (v16u8)tmp1); SUB2(zero, tmp2, zero, tmp3, tmp0, tmp1); tmp2 = (v8i16)__msa_bmnz_v((v16u8)tmp2, (v16u8)tmp0, (v16u8)sign0); tmp3 = (v8i16)__msa_bmnz_v((v16u8)tmp3, (v16u8)tmp1, (v16u8)sign1); - LD_SW4(&mtx->zthresh_[0], 4, t0, t1, t2, t3); // zthresh + LD_SW4(&mtx->zthresh[0], 4, t0, t1, t2, t3); // zthresh t0 = (s0 > t0); t1 = (s1 > t1); t2 = (s2 > t2); t3 = (s3 > t3); PCKEV_H2_SH(t1, t0, t3, t2, tmp0, tmp1); tmp4 = (v8i16)__msa_bmnz_v((v16u8)zero, (v16u8)tmp2, (v16u8)tmp0); tmp5 = (v8i16)__msa_bmnz_v((v16u8)zero, (v16u8)tmp3, (v16u8)tmp1); - LD_SH2(&mtx->q_[0], 8, tmp0, tmp1); + LD_SH2(&mtx->q[0], 8, tmp0, tmp1); MUL2(tmp4, tmp0, tmp5, tmp1, in0, in1); VSHF_H2_SH(tmp4, tmp5, tmp4, tmp5, zigzag0, zigzag1, out0, out1); ST_SH2(in0, in1, &in[0], 8); ST_SH2(out0, out1, &out[0], 8); out0 = __msa_add_a_h(out0, out1); diff --git a/media/libwebp/src/dsp/enc_neon.c b/media/libwebp/src/dsp/enc_neon.c --- a/media/libwebp/src/dsp/enc_neon.c +++ b/media/libwebp/src/dsp/enc_neon.c @@ -839,15 +839,15 @@ #if !defined(WORK_AROUND_GCC) static int16x8_t Quantize_NEON(int16_t* WEBP_RESTRICT const in, const VP8Matrix* WEBP_RESTRICT const mtx, int offset) { - const uint16x8_t sharp = vld1q_u16(&mtx->sharpen_[offset]); - const uint16x8_t q = vld1q_u16(&mtx->q_[offset]); - const uint16x8_t iq = vld1q_u16(&mtx->iq_[offset]); - const uint32x4_t bias0 = vld1q_u32(&mtx->bias_[offset + 0]); - const uint32x4_t bias1 = vld1q_u32(&mtx->bias_[offset + 4]); + const uint16x8_t sharp = vld1q_u16(&mtx->sharpen[offset]); + const uint16x8_t q = vld1q_u16(&mtx->q[offset]); + const uint16x8_t iq = vld1q_u16(&mtx->iq[offset]); + const uint32x4_t bias0 = vld1q_u32(&mtx->bias[offset + 0]); + const uint32x4_t bias1 = vld1q_u32(&mtx->bias[offset + 4]); const int16x8_t a = vld1q_s16(in + offset); // in const uint16x8_t b = vreinterpretq_u16_s16(vabsq_s16(a)); // coeff = abs(in) const int16x8_t sign = vshrq_n_s16(a, 15); // sign const uint16x8_t c = vaddq_u16(b, sharp); // + sharpen @@ -943,10 +943,32 @@ uint8x16_t r; \ r = vqtbl2q_u8(qcombined, tbl); \ vst1q_u8(dst, r); \ } while (0) +static WEBP_INLINE uint8x8x2_t Vld1U8x2(const uint8_t* ptr) { +#if LOCAL_CLANG_PREREQ(3, 4) || LOCAL_GCC_PREREQ(8, 5) || defined(_MSC_VER) + return vld1_u8_x2(ptr); +#else + uint8x8x2_t res; + INIT_VECTOR2(res, vld1_u8(ptr + 0 * 8), vld1_u8(ptr + 1 * 8)); + return res; +#endif +} + +static WEBP_INLINE uint8x16x4_t Vld1qU8x4(const uint8_t* ptr) { +#if LOCAL_CLANG_PREREQ(3, 4) || LOCAL_GCC_PREREQ(9, 4) || defined(_MSC_VER) + return vld1q_u8_x4(ptr); +#else + uint8x16x4_t res; + INIT_VECTOR4(res, + vld1q_u8(ptr + 0 * 16), vld1q_u8(ptr + 1 * 16), + vld1q_u8(ptr + 2 * 16), vld1q_u8(ptr + 3 * 16)); + return res; +#endif +} + static void Intra4Preds_NEON(uint8_t* WEBP_RESTRICT dst, const uint8_t* WEBP_RESTRICT top) { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 // L K J I X A B C D E F G H // -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 @@ -969,13 +991,13 @@ 30, 30, 30, 30, 0, 0, 0, 0, 21, 22, 23, 24, 18, 18, 18, 18, 30, 30, 30, 30, 0, 0, 0, 0, 21, 22, 23, 24, 17, 17, 17, 17, 30, 30, 30, 30, 0, 0, 0, 0, 21, 22, 23, 24, 16, 16, 16, 16 }; - const uint8x16x4_t lookup_avgs1 = vld1q_u8_x4(kLookupTbl1); - const uint8x16x4_t lookup_avgs2 = vld1q_u8_x4(kLookupTbl2); - const uint8x16x4_t lookup_avgs3 = vld1q_u8_x4(kLookupTbl3); + const uint8x16x4_t lookup_avgs1 = Vld1qU8x4(kLookupTbl1); + const uint8x16x4_t lookup_avgs2 = Vld1qU8x4(kLookupTbl2); + const uint8x16x4_t lookup_avgs3 = Vld1qU8x4(kLookupTbl3); const uint8x16_t preload = vld1q_u8(top - 5); uint8x16x2_t qcombined; uint8x16_t result0, result1; @@ -1165,11 +1187,11 @@ return; } // Neither left nor top are NULL. a = vdupq_n_u16(left[-1]); - inner = vld1_u8_x2(top); + inner = Vld1U8x2(top); for (i = 0; i < 4; i++) { const uint8x8x4_t outer = vld4_dup_u8(&left[i * 4]); TrueMotionHelper_NEON(dst, outer.val[0], inner, a, i, 0); diff --git a/media/libwebp/src/dsp/enc_sse2.c b/media/libwebp/src/dsp/enc_sse2.c --- a/media/libwebp/src/dsp/enc_sse2.c +++ b/media/libwebp/src/dsp/enc_sse2.c @@ -12,17 +12,22 @@ // Author: Christian Duvivier (cduvivier@google.com) #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE2) -#include -#include // for abs() #include +#include +#include // for abs() +#include + #include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" #include "src/enc/cost_enc.h" #include "src/enc/vp8i_enc.h" +#include "src/utils/utils.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Transforms (Paragraph 14.4) // Does one inverse transform. @@ -1408,14 +1413,14 @@ __m128i packed_out; // Load all inputs. __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]); __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]); - const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq_[0]); - const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq_[8]); - const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q_[0]); - const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q_[8]); + const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq[0]); + const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq[8]); + const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q[0]); + const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q[8]); // extract sign(in) (0x0000 if positive, 0xffff if negative) const __m128i sign0 = _mm_cmpgt_epi16(zero, in0); const __m128i sign8 = _mm_cmpgt_epi16(zero, in8); @@ -1444,14 +1449,14 @@ __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H); __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H); __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H); __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H); // out = (coeff * iQ + B) - const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias_[0]); - const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias_[4]); - const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias_[8]); - const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias_[12]); + const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias[0]); + const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias[4]); + const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias[8]); + const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias[12]); out_00 = _mm_add_epi32(out_00, bias_00); out_04 = _mm_add_epi32(out_04, bias_04); out_08 = _mm_add_epi32(out_08, bias_08); out_12 = _mm_add_epi32(out_12, bias_12); // out = QUANTDIV(coeff, iQ, B, QFIX) @@ -1510,22 +1515,22 @@ return (_mm_movemask_epi8(_mm_cmpeq_epi8(packed_out, zero)) != 0xffff); } static int QuantizeBlock_SSE2(int16_t in[16], int16_t out[16], const VP8Matrix* WEBP_RESTRICT const mtx) { - return DoQuantizeBlock_SSE2(in, out, &mtx->sharpen_[0], mtx); + return DoQuantizeBlock_SSE2(in, out, &mtx->sharpen[0], mtx); } static int QuantizeBlockWHT_SSE2(int16_t in[16], int16_t out[16], const VP8Matrix* WEBP_RESTRICT const mtx) { return DoQuantizeBlock_SSE2(in, out, NULL, mtx); } static int Quantize2Blocks_SSE2(int16_t in[32], int16_t out[32], const VP8Matrix* WEBP_RESTRICT const mtx) { int nz; - const uint16_t* const sharpen = &mtx->sharpen_[0]; + const uint16_t* const sharpen = &mtx->sharpen[0]; nz = DoQuantizeBlock_SSE2(in + 0 * 16, out + 0 * 16, sharpen, mtx) << 0; nz |= DoQuantizeBlock_SSE2(in + 1 * 16, out + 1 * 16, sharpen, mtx) << 1; return nz; } diff --git a/media/libwebp/src/dsp/enc_sse41.c b/media/libwebp/src/dsp/enc_sse41.c --- a/media/libwebp/src/dsp/enc_sse41.c +++ b/media/libwebp/src/dsp/enc_sse41.c @@ -12,15 +12,19 @@ // Author: Skal (pascal.massimino@gmail.com) #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) +#include #include + #include // for abs() #include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" #include "src/enc/vp8i_enc.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Compute susceptibility based on DCT-coeff histograms. static void CollectHistogram_SSE41(const uint8_t* WEBP_RESTRICT ref, @@ -209,14 +213,14 @@ __m128i packed_out; // Load all inputs. __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]); __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]); - const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq_[0]); - const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq_[8]); - const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q_[0]); - const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q_[8]); + const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq[0]); + const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq[8]); + const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q[0]); + const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q[8]); // coeff = abs(in) __m128i coeff0 = _mm_abs_epi16(in0); __m128i coeff8 = _mm_abs_epi16(in8); @@ -239,14 +243,14 @@ __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H); __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H); __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H); __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H); // out = (coeff * iQ + B) - const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias_[0]); - const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias_[4]); - const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias_[8]); - const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias_[12]); + const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias[0]); + const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias[4]); + const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias[8]); + const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias[12]); out_00 = _mm_add_epi32(out_00, bias_00); out_04 = _mm_add_epi32(out_04, bias_04); out_08 = _mm_add_epi32(out_08, bias_08); out_12 = _mm_add_epi32(out_12, bias_12); // out = QUANTDIV(coeff, iQ, B, QFIX) @@ -303,22 +307,22 @@ #undef PSHUFB_CST static int QuantizeBlock_SSE41(int16_t in[16], int16_t out[16], const VP8Matrix* WEBP_RESTRICT const mtx) { - return DoQuantizeBlock_SSE41(in, out, &mtx->sharpen_[0], mtx); + return DoQuantizeBlock_SSE41(in, out, &mtx->sharpen[0], mtx); } static int QuantizeBlockWHT_SSE41(int16_t in[16], int16_t out[16], const VP8Matrix* WEBP_RESTRICT const mtx) { return DoQuantizeBlock_SSE41(in, out, NULL, mtx); } static int Quantize2Blocks_SSE41(int16_t in[32], int16_t out[32], const VP8Matrix* WEBP_RESTRICT const mtx) { int nz; - const uint16_t* const sharpen = &mtx->sharpen_[0]; + const uint16_t* const sharpen = &mtx->sharpen[0]; nz = DoQuantizeBlock_SSE41(in + 0 * 16, out + 0 * 16, sharpen, mtx) << 0; nz |= DoQuantizeBlock_SSE41(in + 1 * 16, out + 1 * 16, sharpen, mtx) << 1; return nz; } diff --git a/media/libwebp/src/dsp/filters.c b/media/libwebp/src/dsp/filters.c --- a/media/libwebp/src/dsp/filters.c +++ b/media/libwebp/src/dsp/filters.c @@ -9,15 +9,18 @@ // // Spatial prediction using various filters // // Author: Urvang (urvang@google.com) -#include "src/dsp/dsp.h" #include #include #include +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" +#include "src/webp/types.h" + //------------------------------------------------------------------------------ // Helpful macro. #define DCHECK(in, out) \ do { \ diff --git a/media/libwebp/src/dsp/filters_sse2.c b/media/libwebp/src/dsp/filters_sse2.c --- a/media/libwebp/src/dsp/filters_sse2.c +++ b/media/libwebp/src/dsp/filters_sse2.c @@ -18,10 +18,13 @@ #include #include #include #include +#include "src/dsp/cpu.h" +#include "src/webp/types.h" + //------------------------------------------------------------------------------ // Helpful macro. #define DCHECK(in, out) \ do { \ diff --git a/media/libwebp/src/dsp/lossless.h b/media/libwebp/src/dsp/lossless.h --- a/media/libwebp/src/dsp/lossless.h +++ b/media/libwebp/src/dsp/lossless.h @@ -13,17 +13,14 @@ // Jyrki Alakuijala (jyrki@google.com) #ifndef WEBP_DSP_LOSSLESS_H_ #define WEBP_DSP_LOSSLESS_H_ +#include "src/dsp/dsp.h" #include "src/webp/types.h" #include "src/webp/decode.h" -#include "src/dsp/dsp.h" -#include "src/enc/histogram_enc.h" -#include "src/utils/utils.h" - #ifdef __cplusplus extern "C" { #endif //------------------------------------------------------------------------------ @@ -62,26 +59,29 @@ typedef void (*VP8LPredictorAddSubFunc)(const uint32_t* in, const uint32_t* upper, int num_pixels, uint32_t* WEBP_RESTRICT out); extern VP8LPredictorAddSubFunc VP8LPredictorsAdd[16]; extern VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16]; +extern VP8LPredictorAddSubFunc VP8LPredictorsAdd_SSE[16]; typedef void (*VP8LProcessDecBlueAndRedFunc)(const uint32_t* src, int num_pixels, uint32_t* dst); extern VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed; +extern VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed_SSE; typedef struct { // Note: the members are uint8_t, so that any negative values are // automatically converted to "mod 256" values. - uint8_t green_to_red_; - uint8_t green_to_blue_; - uint8_t red_to_blue_; + uint8_t green_to_red; + uint8_t green_to_blue; + uint8_t red_to_blue; } VP8LMultipliers; typedef void (*VP8LTransformColorInverseFunc)(const VP8LMultipliers* const m, const uint32_t* src, int num_pixels, uint32_t* dst); extern VP8LTransformColorInverseFunc VP8LTransformColorInverse; +extern VP8LTransformColorInverseFunc VP8LTransformColorInverse_SSE; struct VP8LTransform; // Defined in dec/vp8li.h. // Performs inverse transform of data given transform information, start and end // rows. Transform will be applied to rows [row_start, row_end[. @@ -97,10 +97,12 @@ extern VP8LConvertFunc VP8LConvertBGRAToRGB; extern VP8LConvertFunc VP8LConvertBGRAToRGBA; extern VP8LConvertFunc VP8LConvertBGRAToRGBA4444; extern VP8LConvertFunc VP8LConvertBGRAToRGB565; extern VP8LConvertFunc VP8LConvertBGRAToBGR; +extern VP8LConvertFunc VP8LConvertBGRAToRGB_SSE; +extern VP8LConvertFunc VP8LConvertBGRAToRGBA_SSE; // Converts from BGRA to other color spaces. void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, WEBP_CSP_MODE out_colorspace, uint8_t* const rgba); @@ -147,25 +149,29 @@ //------------------------------------------------------------------------------ // Encoding typedef void (*VP8LProcessEncBlueAndRedFunc)(uint32_t* dst, int num_pixels); extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; +extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed_SSE; typedef void (*VP8LTransformColorFunc)( const VP8LMultipliers* WEBP_RESTRICT const m, uint32_t* WEBP_RESTRICT dst, int num_pixels); extern VP8LTransformColorFunc VP8LTransformColor; +extern VP8LTransformColorFunc VP8LTransformColor_SSE; typedef void (*VP8LCollectColorBlueTransformsFunc)( const uint32_t* WEBP_RESTRICT argb, int stride, int tile_width, int tile_height, int green_to_blue, int red_to_blue, uint32_t histo[]); extern VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms; +extern VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms_SSE; typedef void (*VP8LCollectColorRedTransformsFunc)( const uint32_t* WEBP_RESTRICT argb, int stride, int tile_width, int tile_height, int green_to_red, uint32_t histo[]); extern VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms; +extern VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms_SSE; // Expose some C-only fallback functions void VP8LTransformColor_C(const VP8LMultipliers* WEBP_RESTRICT const m, uint32_t* WEBP_RESTRICT data, int num_pixels); void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels); @@ -179,24 +185,21 @@ int green_to_blue, int red_to_blue, uint32_t histo[]); extern VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; +extern VP8LPredictorAddSubFunc VP8LPredictorsSub_SSE[16]; // ----------------------------------------------------------------------------- // Huffman-cost related functions. typedef uint32_t (*VP8LCostFunc)(const uint32_t* population, int length); -typedef uint32_t (*VP8LCostCombinedFunc)(const uint32_t* WEBP_RESTRICT X, - const uint32_t* WEBP_RESTRICT Y, - int length); typedef uint64_t (*VP8LCombinedShannonEntropyFunc)(const uint32_t X[256], const uint32_t Y[256]); typedef uint64_t (*VP8LShannonEntropyFunc)(const uint32_t* X, int length); extern VP8LCostFunc VP8LExtraCost; -extern VP8LCostCombinedFunc VP8LExtraCostCombined; extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; extern VP8LShannonEntropyFunc VP8LShannonEntropy; typedef struct { // small struct to hold counters int counts[2]; // index: 0=zero streak, 1=non-zero streak @@ -237,13 +240,10 @@ uint32_t* WEBP_RESTRICT out, int size); extern VP8LAddVectorFunc VP8LAddVector; typedef void (*VP8LAddVectorEqFunc)(const uint32_t* WEBP_RESTRICT a, uint32_t* WEBP_RESTRICT out, int size); extern VP8LAddVectorEqFunc VP8LAddVectorEq; -void VP8LHistogramAdd(const VP8LHistogram* WEBP_RESTRICT const a, - const VP8LHistogram* WEBP_RESTRICT const b, - VP8LHistogram* WEBP_RESTRICT const out); // ----------------------------------------------------------------------------- // PrefixEncode() typedef int (*VP8LVectorMismatchFunc)(const uint32_t* const array1, @@ -253,10 +253,11 @@ typedef void (*VP8LBundleColorMapFunc)(const uint8_t* WEBP_RESTRICT const row, int width, int xbits, uint32_t* WEBP_RESTRICT dst); extern VP8LBundleColorMapFunc VP8LBundleColorMap; +extern VP8LBundleColorMapFunc VP8LBundleColorMap_SSE; void VP8LBundleColorMap_C(const uint8_t* WEBP_RESTRICT const row, int width, int xbits, uint32_t* WEBP_RESTRICT dst); // Must be called before calling any of the above methods. void VP8LEncDspInit(void); diff --git a/media/libwebp/src/dsp/lossless.c b/media/libwebp/src/dsp/lossless.c --- a/media/libwebp/src/dsp/lossless.c +++ b/media/libwebp/src/dsp/lossless.c @@ -11,19 +11,25 @@ // // Authors: Vikas Arora (vikaas.arora@gmail.com) // Jyrki Alakuijala (jyrki@google.com) // Urvang Joshi (urvang@google.com) -#include "src/dsp/dsp.h" +#include "src/dsp/lossless.h" #include -#include #include +#include + #include "src/dec/vp8li_dec.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" +#include "src/dsp/lossless_common.h" #include "src/utils/endian_inl_utils.h" -#include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" +#include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Image transforms. static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) { @@ -213,26 +219,26 @@ // Inverse prediction. static void PredictorInverseTransform_C(const VP8LTransform* const transform, int y_start, int y_end, const uint32_t* in, uint32_t* out) { - const int width = transform->xsize_; + const int width = transform->xsize; if (y_start == 0) { // First Row follows the L (mode=1) mode. PredictorAdd0_C(in, NULL, 1, out); PredictorAdd1_C(in + 1, NULL, width - 1, out + 1); in += width; out += width; ++y_start; } { int y = y_start; - const int tile_width = 1 << transform->bits_; + const int tile_width = 1 << transform->bits; const int mask = tile_width - 1; - const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); + const int tiles_per_row = VP8LSubSampleSize(width, transform->bits); const uint32_t* pred_mode_base = - transform->data_ + (y >> transform->bits_) * tiles_per_row; + transform->data + (y >> transform->bits) * tiles_per_row; while (y < y_end) { const uint32_t* pred_mode_src = pred_mode_base; int x = 1; // First pixel follows the T (mode=2) mode. @@ -276,13 +282,13 @@ return ((int)color_pred * color) >> 5; } static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, VP8LMultipliers* const m) { - m->green_to_red_ = (color_code >> 0) & 0xff; - m->green_to_blue_ = (color_code >> 8) & 0xff; - m->red_to_blue_ = (color_code >> 16) & 0xff; + m->green_to_red = (color_code >> 0) & 0xff; + m->green_to_blue = (color_code >> 8) & 0xff; + m->red_to_blue = (color_code >> 16) & 0xff; } void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, const uint32_t* src, int num_pixels, uint32_t* dst) { @@ -291,32 +297,32 @@ const uint32_t argb = src[i]; const int8_t green = (int8_t)(argb >> 8); const uint32_t red = argb >> 16; int new_red = red & 0xff; int new_blue = argb & 0xff; - new_red += ColorTransformDelta((int8_t)m->green_to_red_, green); + new_red += ColorTransformDelta((int8_t)m->green_to_red, green); new_red &= 0xff; - new_blue += ColorTransformDelta((int8_t)m->green_to_blue_, green); - new_blue += ColorTransformDelta((int8_t)m->red_to_blue_, (int8_t)new_red); + new_blue += ColorTransformDelta((int8_t)m->green_to_blue, green); + new_blue += ColorTransformDelta((int8_t)m->red_to_blue, (int8_t)new_red); new_blue &= 0xff; dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); } } // Color space inverse transform. static void ColorSpaceInverseTransform_C(const VP8LTransform* const transform, int y_start, int y_end, const uint32_t* src, uint32_t* dst) { - const int width = transform->xsize_; - const int tile_width = 1 << transform->bits_; + const int width = transform->xsize; + const int tile_width = 1 << transform->bits; const int mask = tile_width - 1; const int safe_width = width & ~mask; const int remaining_width = width - safe_width; - const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); + const int tiles_per_row = VP8LSubSampleSize(width, transform->bits); int y = y_start; const uint32_t* pred_row = - transform->data_ + (y >> transform->bits_) * tiles_per_row; + transform->data + (y >> transform->bits) * tiles_per_row; while (y < y_end) { const uint32_t* pred = pred_row; VP8LMultipliers m = { 0, 0, 0 }; const uint32_t* const src_safe_end = src + safe_width; @@ -354,15 +360,15 @@ } \ STATIC_DECL void FUNC_NAME(const VP8LTransform* const transform, \ int y_start, int y_end, const TYPE* src, \ TYPE* dst) { \ int y; \ - const int bits_per_pixel = 8 >> transform->bits_; \ - const int width = transform->xsize_; \ - const uint32_t* const color_map = transform->data_; \ + const int bits_per_pixel = 8 >> transform->bits; \ + const int width = transform->xsize; \ + const uint32_t* const color_map = transform->data; \ if (bits_per_pixel < 8) { \ - const int pixels_per_byte = 1 << transform->bits_; \ + const int pixels_per_byte = 1 << transform->bits; \ const int count_mask = pixels_per_byte - 1; \ const uint32_t bit_mask = (1 << bits_per_pixel) - 1; \ for (y = y_start; y < y_end; ++y) { \ uint32_t packed_pixels = 0; \ int x; \ @@ -389,39 +395,39 @@ #undef COLOR_INDEX_INVERSE void VP8LInverseTransform(const VP8LTransform* const transform, int row_start, int row_end, const uint32_t* const in, uint32_t* const out) { - const int width = transform->xsize_; + const int width = transform->xsize; assert(row_start < row_end); - assert(row_end <= transform->ysize_); - switch (transform->type_) { + assert(row_end <= transform->ysize); + switch (transform->type) { case SUBTRACT_GREEN_TRANSFORM: VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out); break; case PREDICTOR_TRANSFORM: PredictorInverseTransform_C(transform, row_start, row_end, in, out); - if (row_end != transform->ysize_) { + if (row_end != transform->ysize) { // The last predicted row in this iteration will be the top-pred row // for the first row in next iteration. memcpy(out - width, out + (row_end - row_start - 1) * width, width * sizeof(*out)); } break; case CROSS_COLOR_TRANSFORM: ColorSpaceInverseTransform_C(transform, row_start, row_end, in, out); break; case COLOR_INDEXING_TRANSFORM: - if (in == out && transform->bits_ > 0) { + if (in == out && transform->bits > 0) { // Move packed pixels to the end of unpacked region, so that unpacking // can occur seamlessly. // Also, note that this is the only transform that applies on - // the effective width of VP8LSubSampleSize(xsize_, bits_). All other - // transforms work on effective width of xsize_. + // the effective width of VP8LSubSampleSize(xsize, bits). All other + // transforms work on effective width of 'xsize'. const int out_stride = (row_end - row_start) * width; const int in_stride = (row_end - row_start) * - VP8LSubSampleSize(transform->xsize_, transform->bits_); + VP8LSubSampleSize(transform->xsize, transform->bits); uint32_t* const src = out + out_stride - in_stride; memmove(src, out, in_stride * sizeof(*src)); ColorIndexInverseTransform_C(transform, row_start, row_end, src, out); } else { ColorIndexInverseTransform_C(transform, row_start, row_end, in, out); @@ -569,30 +575,36 @@ } //------------------------------------------------------------------------------ VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed; +VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed_SSE; VP8LPredictorAddSubFunc VP8LPredictorsAdd[16]; +VP8LPredictorAddSubFunc VP8LPredictorsAdd_SSE[16]; VP8LPredictorFunc VP8LPredictors[16]; // exposed plain-C implementations VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16]; VP8LTransformColorInverseFunc VP8LTransformColorInverse; +VP8LTransformColorInverseFunc VP8LTransformColorInverse_SSE; VP8LConvertFunc VP8LConvertBGRAToRGB; +VP8LConvertFunc VP8LConvertBGRAToRGB_SSE; VP8LConvertFunc VP8LConvertBGRAToRGBA; +VP8LConvertFunc VP8LConvertBGRAToRGBA_SSE; VP8LConvertFunc VP8LConvertBGRAToRGBA4444; VP8LConvertFunc VP8LConvertBGRAToRGB565; VP8LConvertFunc VP8LConvertBGRAToBGR; VP8LMapARGBFunc VP8LMapColor32b; VP8LMapAlphaFunc VP8LMapColor8b; extern VP8CPUInfo VP8GetCPUInfo; extern void VP8LDspInitSSE2(void); extern void VP8LDspInitSSE41(void); +extern void VP8LDspInitAVX2(void); extern void VP8LDspInitNEON(void); extern void VP8LDspInitMIPSdspR2(void); extern void VP8LDspInitMSA(void); #define COPY_PREDICTOR_ARRAY(IN, OUT) do { \ @@ -641,10 +653,15 @@ if (VP8GetCPUInfo(kSSE2)) { VP8LDspInitSSE2(); #if defined(WEBP_HAVE_SSE41) if (VP8GetCPUInfo(kSSE4_1)) { VP8LDspInitSSE41(); +#if defined(WEBP_HAVE_AVX2) + if (VP8GetCPUInfo(kAVX2)) { + VP8LDspInitAVX2(); + } +#endif } #endif } #endif #if defined(WEBP_USE_MIPS_DSP_R2) diff --git a/media/libwebp/src/dsp/lossless_avx2.c b/media/libwebp/src/dsp/lossless_avx2.c new file mode 100644 --- /dev/null +++ b/media/libwebp/src/dsp/lossless_avx2.c @@ -0,0 +1,443 @@ +// Copyright 2025 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// AVX2 variant of methods for lossless decoder +// +// Author: Vincent Rabaud (vrabaud@google.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_AVX2) + +#include +#include + +#include "src/dsp/cpu.h" +#include "src/dsp/lossless.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" + +//------------------------------------------------------------------------------ +// Predictor Transform + +static WEBP_INLINE void Average2_m256i(const __m256i* const a0, + const __m256i* const a1, + __m256i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m256i ones = _mm256_set1_epi8(1); + const __m256i avg1 = _mm256_avg_epu8(*a0, *a1); + const __m256i one = _mm256_and_si256(_mm256_xor_si256(*a0, *a1), ones); + *avg = _mm256_sub_epi8(avg1, one); +} + +// Batch versions of those functions. + +// Predictor0: ARGB_BLACK. +static void PredictorAdd0_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + const __m256i black = _mm256_set1_epi32((int)ARGB_BLACK); + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + const __m256i res = _mm256_add_epi8(src, black); + _mm256_storeu_si256((__m256i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[0](in + i, NULL, num_pixels - i, out + i); + } + (void)upper; +} + +// Predictor1: left. +static void PredictorAdd1_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + __m256i prev = _mm256_set1_epi32((int)out[-1]); + for (i = 0; i + 8 <= num_pixels; i += 8) { + // h | g | f | e | d | c | b | a + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + // g | f | e | 0 | c | b | a | 0 + const __m256i shift0 = _mm256_slli_si256(src, 4); + // g + h | f + g | e + f | e | c + d | b + c | a + b | a + const __m256i sum0 = _mm256_add_epi8(src, shift0); + // e + f | e | 0 | 0 | a + b | a | 0 | 0 + const __m256i shift1 = _mm256_slli_si256(sum0, 8); + // e + f + g + h | e + f + g | e + f | e | a + b + c + d | a + b + c | a + b + // | a + const __m256i sum1 = _mm256_add_epi8(sum0, shift1); + // Add a + b + c + d to the upper lane. + const int32_t sum_abcd = _mm256_extract_epi32(sum1, 3); + const __m256i sum2 = _mm256_add_epi8( + sum1, + _mm256_set_epi32(sum_abcd, sum_abcd, sum_abcd, sum_abcd, 0, 0, 0, 0)); + + const __m256i res = _mm256_add_epi8(sum2, prev); + _mm256_storeu_si256((__m256i*)&out[i], res); + // replicate last res output in prev. + prev = _mm256_permutevar8x32_epi32( + res, _mm256_set_epi32(7, 7, 7, 7, 7, 7, 7, 7)); + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[1](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Macro that adds 32-bit integers from IN using mod 256 arithmetic +// per 8 bit channel. +#define GENERATE_PREDICTOR_1(X, IN) \ + static void PredictorAdd##X##_AVX2(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* WEBP_RESTRICT out) { \ + int i; \ + for (i = 0; i + 8 <= num_pixels; i += 8) { \ + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); \ + const __m256i other = _mm256_loadu_si256((const __m256i*)&(IN)); \ + const __m256i res = _mm256_add_epi8(src, other); \ + _mm256_storeu_si256((__m256i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ + } + +// Predictor2: Top. +GENERATE_PREDICTOR_1(2, upper[i]) +// Predictor3: Top-right. +GENERATE_PREDICTOR_1(3, upper[i + 1]) +// Predictor4: Top-left. +GENERATE_PREDICTOR_1(4, upper[i - 1]) +#undef GENERATE_PREDICTOR_1 + +// Due to averages with integers, values cannot be accumulated in parallel for +// predictors 5 to 7. + +#define GENERATE_PREDICTOR_2(X, IN) \ + static void PredictorAdd##X##_AVX2(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* WEBP_RESTRICT out) { \ + int i; \ + for (i = 0; i + 8 <= num_pixels; i += 8) { \ + const __m256i Tother = _mm256_loadu_si256((const __m256i*)&(IN)); \ + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); \ + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); \ + __m256i avg, res; \ + Average2_m256i(&T, &Tother, &avg); \ + res = _mm256_add_epi8(avg, src); \ + _mm256_storeu_si256((__m256i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ + } +// Predictor8: average TL T. +GENERATE_PREDICTOR_2(8, upper[i - 1]) +// Predictor9: average T TR. +GENERATE_PREDICTOR_2(9, upper[i + 1]) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: average of (average of (L,TL), average of (T, TR)). +#define DO_PRED10(OUT) \ + do { \ + __m256i avgLTL, avg; \ + Average2_m256i(&L, &TL, &avgLTL); \ + Average2_m256i(&avgTTR, &avgLTL, &avg); \ + L = _mm256_add_epi8(avg, src); \ + out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(L); \ + } while (0) + +#define DO_PRED10_SHIFT \ + do { \ + /* Rotate the pre-computed values for the next iteration.*/ \ + avgTTR = _mm256_srli_si256(avgTTR, 4); \ + TL = _mm256_srli_si256(TL, 4); \ + src = _mm256_srli_si256(src, 4); \ + } while (0) + +static void PredictorAdd10_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i, j; + __m256i L = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0); + for (i = 0; i + 8 <= num_pixels; i += 8) { + __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i TR = _mm256_loadu_si256((const __m256i*)&upper[i + 1]); + __m256i avgTTR; + Average2_m256i(&T, &TR, &avgTTR); + { + const __m256i avgTTR_bak = avgTTR; + const __m256i TL_bak = TL; + const __m256i src_bak = src; + for (j = 0; j < 4; ++j) { + DO_PRED10(j); + DO_PRED10_SHIFT; + } + avgTTR = _mm256_permute2x128_si256(avgTTR_bak, avgTTR_bak, 1); + TL = _mm256_permute2x128_si256(TL_bak, TL_bak, 1); + src = _mm256_permute2x128_si256(src_bak, src_bak, 1); + for (; j < 8; ++j) { + DO_PRED10(j); + DO_PRED10_SHIFT; + } + } + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[10](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED10 +#undef DO_PRED10_SHIFT + +// Predictor11: select. +#define DO_PRED11(OUT) \ + do { \ + const __m256i L_lo = _mm256_unpacklo_epi32(L, T); \ + const __m256i TL_lo = _mm256_unpacklo_epi32(TL, T); \ + const __m256i pb = _mm256_sad_epu8(L_lo, TL_lo); /* pb = sum |L-TL|*/ \ + const __m256i mask = _mm256_cmpgt_epi32(pb, pa); \ + const __m256i A = _mm256_and_si256(mask, L); \ + const __m256i B = _mm256_andnot_si256(mask, T); \ + const __m256i pred = _mm256_or_si256(A, B); /* pred = (pa > b)? L : T*/ \ + L = _mm256_add_epi8(src, pred); \ + out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(L); \ + } while (0) + +#define DO_PRED11_SHIFT \ + do { \ + /* Shift the pre-computed value for the next iteration.*/ \ + T = _mm256_srli_si256(T, 4); \ + TL = _mm256_srli_si256(TL, 4); \ + src = _mm256_srli_si256(src, 4); \ + pa = _mm256_srli_si256(pa, 4); \ + } while (0) + +static void PredictorAdd11_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i, j; + __m256i pa; + __m256i L = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0); + for (i = 0; i + 8 <= num_pixels; i += 8) { + __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + { + // We can unpack with any value on the upper 32 bits, provided it's the + // same on both operands (so that their sum of abs diff is zero). Here we + // use T. + const __m256i T_lo = _mm256_unpacklo_epi32(T, T); + const __m256i TL_lo = _mm256_unpacklo_epi32(TL, T); + const __m256i T_hi = _mm256_unpackhi_epi32(T, T); + const __m256i TL_hi = _mm256_unpackhi_epi32(TL, T); + const __m256i s_lo = _mm256_sad_epu8(T_lo, TL_lo); + const __m256i s_hi = _mm256_sad_epu8(T_hi, TL_hi); + pa = _mm256_packs_epi32(s_lo, s_hi); // pa = sum |T-TL| + } + { + const __m256i T_bak = T; + const __m256i TL_bak = TL; + const __m256i src_bak = src; + const __m256i pa_bak = pa; + for (j = 0; j < 4; ++j) { + DO_PRED11(j); + DO_PRED11_SHIFT; + } + T = _mm256_permute2x128_si256(T_bak, T_bak, 1); + TL = _mm256_permute2x128_si256(TL_bak, TL_bak, 1); + src = _mm256_permute2x128_si256(src_bak, src_bak, 1); + pa = _mm256_permute2x128_si256(pa_bak, pa_bak, 1); + for (; j < 8; ++j) { + DO_PRED11(j); + DO_PRED11_SHIFT; + } + } + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[11](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED11 +#undef DO_PRED11_SHIFT + +// Predictor12: ClampedAddSubtractFull. +#define DO_PRED12(DIFF, OUT) \ + do { \ + const __m256i all = _mm256_add_epi16(L, (DIFF)); \ + const __m256i alls = _mm256_packus_epi16(all, all); \ + const __m256i res = _mm256_add_epi8(src, alls); \ + out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(res); \ + L = _mm256_unpacklo_epi8(res, zero); \ + } while (0) + +#define DO_PRED12_SHIFT(DIFF, LANE) \ + do { \ + /* Shift the pre-computed value for the next iteration.*/ \ + if ((LANE) == 0) (DIFF) = _mm256_srli_si256(DIFF, 8); \ + src = _mm256_srli_si256(src, 4); \ + } while (0) + +static void PredictorAdd12_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + const __m256i zero = _mm256_setzero_si256(); + const __m256i L8 = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0); + __m256i L = _mm256_unpacklo_epi8(L8, zero); + for (i = 0; i + 8 <= num_pixels; i += 8) { + // Load 8 pixels at a time. + __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i T_lo = _mm256_unpacklo_epi8(T, zero); + const __m256i T_hi = _mm256_unpackhi_epi8(T, zero); + const __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + const __m256i TL_lo = _mm256_unpacklo_epi8(TL, zero); + const __m256i TL_hi = _mm256_unpackhi_epi8(TL, zero); + __m256i diff_lo = _mm256_sub_epi16(T_lo, TL_lo); + __m256i diff_hi = _mm256_sub_epi16(T_hi, TL_hi); + const __m256i diff_lo_bak = diff_lo; + const __m256i diff_hi_bak = diff_hi; + const __m256i src_bak = src; + DO_PRED12(diff_lo, 0); + DO_PRED12_SHIFT(diff_lo, 0); + DO_PRED12(diff_lo, 1); + DO_PRED12_SHIFT(diff_lo, 0); + DO_PRED12(diff_hi, 2); + DO_PRED12_SHIFT(diff_hi, 0); + DO_PRED12(diff_hi, 3); + DO_PRED12_SHIFT(diff_hi, 0); + + // Process the upper lane. + diff_lo = _mm256_permute2x128_si256(diff_lo_bak, diff_lo_bak, 1); + diff_hi = _mm256_permute2x128_si256(diff_hi_bak, diff_hi_bak, 1); + src = _mm256_permute2x128_si256(src_bak, src_bak, 1); + + DO_PRED12(diff_lo, 4); + DO_PRED12_SHIFT(diff_lo, 0); + DO_PRED12(diff_lo, 5); + DO_PRED12_SHIFT(diff_lo, 1); + DO_PRED12(diff_hi, 6); + DO_PRED12_SHIFT(diff_hi, 0); + DO_PRED12(diff_hi, 7); + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[12](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED12 +#undef DO_PRED12_SHIFT + +// Due to averages with integers, values cannot be accumulated in parallel for +// predictors 13. + +//------------------------------------------------------------------------------ +// Subtract-Green Transform + +static void AddGreenToBlueAndRed_AVX2(const uint32_t* const src, int num_pixels, + uint32_t* dst) { + int i; + const __m256i kCstShuffle = _mm256_set_epi8( + -1, 29, -1, 29, -1, 25, -1, 25, -1, 21, -1, 21, -1, 17, -1, 17, -1, 13, + -1, 13, -1, 9, -1, 9, -1, 5, -1, 5, -1, 1, -1, 1); + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i in = _mm256_loadu_si256((const __m256i*)&src[i]); // argb + const __m256i in_0g0g = _mm256_shuffle_epi8(in, kCstShuffle); // 0g0g + const __m256i out = _mm256_add_epi8(in, in_0g0g); + _mm256_storeu_si256((__m256i*)&dst[i], out); + } + // fallthrough and finish off with SSE. + if (i != num_pixels) { + VP8LAddGreenToBlueAndRed_SSE(src + i, num_pixels - i, dst + i); + } +} + +//------------------------------------------------------------------------------ +// Color Transform + +static void TransformColorInverse_AVX2(const VP8LMultipliers* const m, + const uint32_t* const src, + int num_pixels, uint32_t* dst) { +// sign-extended multiplying constants, pre-shifted by 5. +#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend + const __m256i mults_rb = + _mm256_set1_epi32((int)((uint32_t)CST(green_to_red) << 16 | + (CST(green_to_blue) & 0xffff))); + const __m256i mults_b2 = _mm256_set1_epi32(CST(red_to_blue)); +#undef CST + const __m256i mask_ag = _mm256_set1_epi32((int)0xff00ff00); + const __m256i perm1 = _mm256_setr_epi8( + -1, 1, -1, 1, -1, 5, -1, 5, -1, 9, -1, 9, -1, 13, -1, 13, -1, 17, -1, 17, + -1, 21, -1, 21, -1, 25, -1, 25, -1, 29, -1, 29); + const __m256i perm2 = _mm256_setr_epi8( + -1, 2, -1, -1, -1, 6, -1, -1, -1, 10, -1, -1, -1, 14, -1, -1, -1, 18, -1, + -1, -1, 22, -1, -1, -1, 26, -1, -1, -1, 30, -1, -1); + int i; + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i A = _mm256_loadu_si256((const __m256i*)(src + i)); + const __m256i B = _mm256_shuffle_epi8(A, perm1); // argb -> g0g0 + const __m256i C = _mm256_mulhi_epi16(B, mults_rb); + const __m256i D = _mm256_add_epi8(A, C); + const __m256i E = _mm256_shuffle_epi8(D, perm2); + const __m256i F = _mm256_mulhi_epi16(E, mults_b2); + const __m256i G = _mm256_add_epi8(D, F); + const __m256i out = _mm256_blendv_epi8(G, A, mask_ag); + _mm256_storeu_si256((__m256i*)&dst[i], out); + } + // Fall-back to SSE-version for left-overs. + if (i != num_pixels) { + VP8LTransformColorInverse_SSE(m, src + i, num_pixels - i, dst + i); + } +} + +//------------------------------------------------------------------------------ +// Color-space conversion functions + +static void ConvertBGRAToRGBA_AVX2(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { + const __m256i* in = (const __m256i*)src; + __m256i* out = (__m256i*)dst; + while (num_pixels >= 8) { + const __m256i A = _mm256_loadu_si256(in++); + const __m256i B = _mm256_shuffle_epi8( + A, + _mm256_set_epi8(15, 12, 13, 14, 11, 8, 9, 10, 7, 4, 5, 6, 3, 0, 1, 2, + 15, 12, 13, 14, 11, 8, 9, 10, 7, 4, 5, 6, 3, 0, 1, 2)); + _mm256_storeu_si256(out++, B); + num_pixels -= 8; + } + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToRGBA_SSE((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LDspInitAVX2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitAVX2(void) { + VP8LPredictorsAdd[0] = PredictorAdd0_AVX2; + VP8LPredictorsAdd[1] = PredictorAdd1_AVX2; + VP8LPredictorsAdd[2] = PredictorAdd2_AVX2; + VP8LPredictorsAdd[3] = PredictorAdd3_AVX2; + VP8LPredictorsAdd[4] = PredictorAdd4_AVX2; + VP8LPredictorsAdd[8] = PredictorAdd8_AVX2; + VP8LPredictorsAdd[9] = PredictorAdd9_AVX2; + VP8LPredictorsAdd[10] = PredictorAdd10_AVX2; + VP8LPredictorsAdd[11] = PredictorAdd11_AVX2; + VP8LPredictorsAdd[12] = PredictorAdd12_AVX2; + + VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_AVX2; + VP8LTransformColorInverse = TransformColorInverse_AVX2; + VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_AVX2; +} + +#else // !WEBP_USE_AVX2 + +WEBP_DSP_INIT_STUB(VP8LDspInitAVX2) + +#endif // WEBP_USE_AVX2 diff --git a/media/libwebp/src/dsp/lossless_common.h b/media/libwebp/src/dsp/lossless_common.h --- a/media/libwebp/src/dsp/lossless_common.h +++ b/media/libwebp/src/dsp/lossless_common.h @@ -14,10 +14,13 @@ // Vincent Rabaud (vrabaud@google.com) #ifndef WEBP_DSP_LOSSLESS_COMMON_H_ #define WEBP_DSP_LOSSLESS_COMMON_H_ +#include +#include + #include "src/dsp/cpu.h" #include "src/utils/utils.h" #include "src/webp/types.h" #ifdef __cplusplus @@ -135,35 +138,35 @@ *code = 2 * highest_bit + second_highest_bit; } #define PREFIX_LOOKUP_IDX_MAX 512 typedef struct { - int8_t code_; - int8_t extra_bits_; + int8_t code; + int8_t extra_bits; } VP8LPrefixCode; // These tables are derived using VP8LPrefixEncodeNoLUT. extern const VP8LPrefixCode kPrefixEncodeCode[PREFIX_LOOKUP_IDX_MAX]; extern const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX]; static WEBP_INLINE void VP8LPrefixEncodeBits(int distance, int* const code, int* const extra_bits) { if (distance < PREFIX_LOOKUP_IDX_MAX) { const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; - *code = prefix_code.code_; - *extra_bits = prefix_code.extra_bits_; + *code = prefix_code.code; + *extra_bits = prefix_code.extra_bits; } else { VP8LPrefixEncodeBitsNoLUT(distance, code, extra_bits); } } static WEBP_INLINE void VP8LPrefixEncode(int distance, int* const code, int* const extra_bits, int* const extra_bits_value) { if (distance < PREFIX_LOOKUP_IDX_MAX) { const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; - *code = prefix_code.code_; - *extra_bits = prefix_code.extra_bits_; + *code = prefix_code.code; + *extra_bits = prefix_code.extra_bits; *extra_bits_value = kPrefixEncodeExtraBitsValue[distance]; } else { VP8LPrefixEncodeNoLUT(distance, code, extra_bits, extra_bits_value); } } diff --git a/media/libwebp/src/dsp/lossless_enc.c b/media/libwebp/src/dsp/lossless_enc.c --- a/media/libwebp/src/dsp/lossless_enc.c +++ b/media/libwebp/src/dsp/lossless_enc.c @@ -11,20 +11,23 @@ // // Authors: Vikas Arora (vikaas.arora@gmail.com) // Jyrki Alakuijala (jyrki@google.com) // Urvang Joshi (urvang@google.com) -#include "src/dsp/dsp.h" - #include #include #include -#include "src/dec/vp8li_dec.h" -#include "src/utils/endian_inl_utils.h" +#include + +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" -#include "src/dsp/yuv.h" +#include "src/enc/histogram_enc.h" +#include "src/utils/utils.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" // lookup table for small values of log2(int) * (1 << LOG_2_PRECISION_BITS). // Obtained in Python with: // a = [ str(round((1<<23)*math.log2(i))) if i else "0" for i in range(256)] // print(',\n'.join([' '+','.join(v) @@ -477,14 +480,14 @@ const uint32_t argb = data[i]; const int8_t green = U32ToS8(argb >> 8); const int8_t red = U32ToS8(argb >> 16); int new_red = red & 0xff; int new_blue = argb & 0xff; - new_red -= ColorTransformDelta((int8_t)m->green_to_red_, green); + new_red -= ColorTransformDelta((int8_t)m->green_to_red, green); new_red &= 0xff; - new_blue -= ColorTransformDelta((int8_t)m->green_to_blue_, green); - new_blue -= ColorTransformDelta((int8_t)m->red_to_blue_, red); + new_blue -= ColorTransformDelta((int8_t)m->green_to_blue, green); + new_blue -= ColorTransformDelta((int8_t)m->red_to_blue, red); new_blue &= 0xff; data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); } } @@ -578,24 +581,10 @@ cost += i * (population[2 * i + 2] + population[2 * i + 3]); } return cost; } -static uint32_t ExtraCostCombined_C(const uint32_t* WEBP_RESTRICT X, - const uint32_t* WEBP_RESTRICT Y, - int length) { - int i; - uint32_t cost = X[4] + Y[4] + X[5] + Y[5]; - assert(length % 2 == 0); - for (i = 2; i < length / 2 - 1; ++i) { - const int xy0 = X[2 * i + 2] + Y[2 * i + 2]; - const int xy1 = X[2 * i + 3] + Y[2 * i + 3]; - cost += i * (xy0 + xy1); - } - return cost; -} - //------------------------------------------------------------------------------ static void AddVector_C(const uint32_t* WEBP_RESTRICT a, const uint32_t* WEBP_RESTRICT b, uint32_t* WEBP_RESTRICT out, int size) { @@ -607,62 +596,10 @@ uint32_t* WEBP_RESTRICT out, int size) { int i; for (i = 0; i < size; ++i) out[i] += a[i]; } -#define ADD(X, ARG, LEN) do { \ - if (a->is_used_[X]) { \ - if (b->is_used_[X]) { \ - VP8LAddVector(a->ARG, b->ARG, out->ARG, (LEN)); \ - } else { \ - memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \ - } \ - } else if (b->is_used_[X]) { \ - memcpy(&out->ARG[0], &b->ARG[0], (LEN) * sizeof(out->ARG[0])); \ - } else { \ - memset(&out->ARG[0], 0, (LEN) * sizeof(out->ARG[0])); \ - } \ -} while (0) - -#define ADD_EQ(X, ARG, LEN) do { \ - if (a->is_used_[X]) { \ - if (out->is_used_[X]) { \ - VP8LAddVectorEq(a->ARG, out->ARG, (LEN)); \ - } else { \ - memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \ - } \ - } \ -} while (0) - -void VP8LHistogramAdd(const VP8LHistogram* WEBP_RESTRICT const a, - const VP8LHistogram* WEBP_RESTRICT const b, - VP8LHistogram* WEBP_RESTRICT const out) { - int i; - const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_); - assert(a->palette_code_bits_ == b->palette_code_bits_); - - if (b != out) { - ADD(0, literal_, literal_size); - ADD(1, red_, NUM_LITERAL_CODES); - ADD(2, blue_, NUM_LITERAL_CODES); - ADD(3, alpha_, NUM_LITERAL_CODES); - ADD(4, distance_, NUM_DISTANCE_CODES); - for (i = 0; i < 5; ++i) { - out->is_used_[i] = (a->is_used_[i] | b->is_used_[i]); - } - } else { - ADD_EQ(0, literal_, literal_size); - ADD_EQ(1, red_, NUM_LITERAL_CODES); - ADD_EQ(2, blue_, NUM_LITERAL_CODES); - ADD_EQ(3, alpha_, NUM_LITERAL_CODES); - ADD_EQ(4, distance_, NUM_DISTANCE_CODES); - for (i = 0; i < 5; ++i) out->is_used_[i] |= a->is_used_[i]; - } -} -#undef ADD -#undef ADD_EQ - //------------------------------------------------------------------------------ // Image transforms. static void PredictorSub0_C(const uint32_t* in, const uint32_t* upper, int num_pixels, uint32_t* WEBP_RESTRICT out) { @@ -708,21 +645,24 @@ GENERATE_PREDICTOR_SUB(13) //------------------------------------------------------------------------------ VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; +VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed_SSE; VP8LTransformColorFunc VP8LTransformColor; +VP8LTransformColorFunc VP8LTransformColor_SSE; VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms; +VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms_SSE; VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms; +VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms_SSE; VP8LFastLog2SlowFunc VP8LFastLog2Slow; VP8LFastSLog2SlowFunc VP8LFastSLog2Slow; VP8LCostFunc VP8LExtraCost; -VP8LCostCombinedFunc VP8LExtraCostCombined; VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; VP8LShannonEntropyFunc VP8LShannonEntropy; VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined; @@ -730,17 +670,20 @@ VP8LAddVectorFunc VP8LAddVector; VP8LAddVectorEqFunc VP8LAddVectorEq; VP8LVectorMismatchFunc VP8LVectorMismatch; VP8LBundleColorMapFunc VP8LBundleColorMap; +VP8LBundleColorMapFunc VP8LBundleColorMap_SSE; VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; +VP8LPredictorAddSubFunc VP8LPredictorsSub_SSE[16]; extern VP8CPUInfo VP8GetCPUInfo; extern void VP8LEncDspInitSSE2(void); extern void VP8LEncDspInitSSE41(void); +extern void VP8LEncDspInitAVX2(void); extern void VP8LEncDspInitNEON(void); extern void VP8LEncDspInitMIPS32(void); extern void VP8LEncDspInitMIPSdspR2(void); extern void VP8LEncDspInitMSA(void); @@ -758,11 +701,10 @@ VP8LFastLog2Slow = FastLog2Slow_C; VP8LFastSLog2Slow = FastSLog2Slow_C; VP8LExtraCost = ExtraCost_C; - VP8LExtraCostCombined = ExtraCostCombined_C; VP8LCombinedShannonEntropy = CombinedShannonEntropy_C; VP8LShannonEntropy = ShannonEntropy_C; VP8LGetEntropyUnrefined = GetEntropyUnrefined_C; VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_C; @@ -813,10 +755,15 @@ if (VP8GetCPUInfo(kSSE2)) { VP8LEncDspInitSSE2(); #if defined(WEBP_HAVE_SSE41) if (VP8GetCPUInfo(kSSE4_1)) { VP8LEncDspInitSSE41(); +#if defined(WEBP_HAVE_AVX2) + if (VP8GetCPUInfo(kAVX2)) { + VP8LEncDspInitAVX2(); + } +#endif } #endif } #endif #if defined(WEBP_USE_MIPS32) @@ -848,11 +795,10 @@ assert(VP8LCollectColorBlueTransforms != NULL); assert(VP8LCollectColorRedTransforms != NULL); assert(VP8LFastLog2Slow != NULL); assert(VP8LFastSLog2Slow != NULL); assert(VP8LExtraCost != NULL); - assert(VP8LExtraCostCombined != NULL); assert(VP8LCombinedShannonEntropy != NULL); assert(VP8LShannonEntropy != NULL); assert(VP8LGetEntropyUnrefined != NULL); assert(VP8LGetCombinedEntropyUnrefined != NULL); assert(VP8LAddVector != NULL); diff --git a/media/libwebp/src/dsp/lossless_enc_avx2.c b/media/libwebp/src/dsp/lossless_enc_avx2.c new file mode 100644 --- /dev/null +++ b/media/libwebp/src/dsp/lossless_enc_avx2.c @@ -0,0 +1,736 @@ +// Copyright 2025 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// AVX2 variant of methods for lossless encoder +// +// Author: Vincent Rabaud (vrabaud@google.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_AVX2) +#include +#include + +#include +#include + +#include "src/dsp/cpu.h" +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" +#include "src/utils/utils.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" + +//------------------------------------------------------------------------------ +// Subtract-Green Transform + +static void SubtractGreenFromBlueAndRed_AVX2(uint32_t* argb_data, + int num_pixels) { + int i; + const __m256i kCstShuffle = _mm256_set_epi8( + -1, 29, -1, 29, -1, 25, -1, 25, -1, 21, -1, 21, -1, 17, -1, 17, -1, 13, + -1, 13, -1, 9, -1, 9, -1, 5, -1, 5, -1, 1, -1, 1); + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i in = _mm256_loadu_si256((__m256i*)&argb_data[i]); // argb + const __m256i in_0g0g = _mm256_shuffle_epi8(in, kCstShuffle); + const __m256i out = _mm256_sub_epi8(in, in_0g0g); + _mm256_storeu_si256((__m256i*)&argb_data[i], out); + } + // fallthrough and finish off with plain-SSE + if (i != num_pixels) { + VP8LSubtractGreenFromBlueAndRed_SSE(argb_data + i, num_pixels - i); + } +} + +//------------------------------------------------------------------------------ +// Color Transform + +// For sign-extended multiplying constants, pre-shifted by 5: +#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5) + +#define MK_CST_16(HI, LO) \ + _mm256_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) + +static void TransformColor_AVX2(const VP8LMultipliers* WEBP_RESTRICT const m, + uint32_t* WEBP_RESTRICT argb_data, + int num_pixels) { + const __m256i mults_rb = + MK_CST_16(CST_5b(m->green_to_red), CST_5b(m->green_to_blue)); + const __m256i mults_b2 = MK_CST_16(CST_5b(m->red_to_blue), 0); + const __m256i mask_rb = _mm256_set1_epi32(0x00ff00ff); // red-blue masks + const __m256i kCstShuffle = _mm256_set_epi8( + 29, -1, 29, -1, 25, -1, 25, -1, 21, -1, 21, -1, 17, -1, 17, -1, 13, -1, + 13, -1, 9, -1, 9, -1, 5, -1, 5, -1, 1, -1, 1, -1); + int i; + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i in = _mm256_loadu_si256((__m256i*)&argb_data[i]); // argb + const __m256i A = _mm256_shuffle_epi8(in, kCstShuffle); // g0g0 + const __m256i B = _mm256_mulhi_epi16(A, mults_rb); // x dr x db1 + const __m256i C = _mm256_slli_epi16(in, 8); // r 0 b 0 + const __m256i D = _mm256_mulhi_epi16(C, mults_b2); // x db2 0 0 + const __m256i E = _mm256_srli_epi32(D, 16); // 0 0 x db2 + const __m256i F = _mm256_add_epi8(E, B); // x dr x db + const __m256i G = _mm256_and_si256(F, mask_rb); // 0 dr 0 db + const __m256i out = _mm256_sub_epi8(in, G); + _mm256_storeu_si256((__m256i*)&argb_data[i], out); + } + // fallthrough and finish off with plain-C + if (i != num_pixels) { + VP8LTransformColor_SSE(m, argb_data + i, num_pixels - i); + } +} + +//------------------------------------------------------------------------------ +#define SPAN 16 +static void CollectColorBlueTransforms_AVX2(const uint32_t* WEBP_RESTRICT argb, + int stride, int tile_width, + int tile_height, int green_to_blue, + int red_to_blue, uint32_t histo[]) { + const __m256i mult = + MK_CST_16(CST_5b(red_to_blue) + 256, CST_5b(green_to_blue)); + const __m256i perm = _mm256_setr_epi8( + -1, 1, -1, 2, -1, 5, -1, 6, -1, 9, -1, 10, -1, 13, -1, 14, -1, 17, -1, 18, + -1, 21, -1, 22, -1, 25, -1, 26, -1, 29, -1, 30); + if (tile_width >= 8) { + int y, i; + for (y = 0; y < tile_height; ++y) { + uint8_t values[32]; + const uint32_t* const src = argb + y * stride; + const __m256i A1 = _mm256_loadu_si256((const __m256i*)src); + const __m256i B1 = _mm256_shuffle_epi8(A1, perm); + const __m256i C1 = _mm256_mulhi_epi16(B1, mult); + const __m256i D1 = _mm256_sub_epi16(A1, C1); + __m256i E = _mm256_add_epi16(_mm256_srli_epi32(D1, 16), D1); + int x; + for (x = 8; x + 8 <= tile_width; x += 8) { + const __m256i A2 = _mm256_loadu_si256((const __m256i*)(src + x)); + __m256i B2, C2, D2; + _mm256_storeu_si256((__m256i*)values, E); + for (i = 0; i < 32; i += 4) ++histo[values[i]]; + B2 = _mm256_shuffle_epi8(A2, perm); + C2 = _mm256_mulhi_epi16(B2, mult); + D2 = _mm256_sub_epi16(A2, C2); + E = _mm256_add_epi16(_mm256_srli_epi32(D2, 16), D2); + } + _mm256_storeu_si256((__m256i*)values, E); + for (i = 0; i < 32; i += 4) ++histo[values[i]]; + } + } + { + const int left_over = tile_width & 7; + if (left_over > 0) { + VP8LCollectColorBlueTransforms_SSE(argb + tile_width - left_over, stride, + left_over, tile_height, green_to_blue, + red_to_blue, histo); + } + } +} + +static void CollectColorRedTransforms_AVX2(const uint32_t* WEBP_RESTRICT argb, + int stride, int tile_width, + int tile_height, int green_to_red, + uint32_t histo[]) { + const __m256i mult = MK_CST_16(0, CST_5b(green_to_red)); + const __m256i mask_g = _mm256_set1_epi32(0x0000ff00); + if (tile_width >= 8) { + int y, i; + for (y = 0; y < tile_height; ++y) { + uint8_t values[32]; + const uint32_t* const src = argb + y * stride; + const __m256i A1 = _mm256_loadu_si256((const __m256i*)src); + const __m256i B1 = _mm256_and_si256(A1, mask_g); + const __m256i C1 = _mm256_madd_epi16(B1, mult); + __m256i D = _mm256_sub_epi16(A1, C1); + int x; + for (x = 8; x + 8 <= tile_width; x += 8) { + const __m256i A2 = _mm256_loadu_si256((const __m256i*)(src + x)); + __m256i B2, C2; + _mm256_storeu_si256((__m256i*)values, D); + for (i = 2; i < 32; i += 4) ++histo[values[i]]; + B2 = _mm256_and_si256(A2, mask_g); + C2 = _mm256_madd_epi16(B2, mult); + D = _mm256_sub_epi16(A2, C2); + } + _mm256_storeu_si256((__m256i*)values, D); + for (i = 2; i < 32; i += 4) ++histo[values[i]]; + } + } + { + const int left_over = tile_width & 7; + if (left_over > 0) { + VP8LCollectColorRedTransforms_SSE(argb + tile_width - left_over, stride, + left_over, tile_height, green_to_red, + histo); + } + } +} +#undef SPAN +#undef MK_CST_16 + +//------------------------------------------------------------------------------ + +// Note we are adding uint32_t's as *signed* int32's (using _mm256_add_epi32). +// But that's ok since the histogram values are less than 1<<28 (max picture +// size). +static void AddVector_AVX2(const uint32_t* WEBP_RESTRICT a, + const uint32_t* WEBP_RESTRICT b, + uint32_t* WEBP_RESTRICT out, int size) { + int i = 0; + int aligned_size = size & ~31; + // Size is, at minimum, NUM_DISTANCE_CODES (40) and may be as large as + // NUM_LITERAL_CODES (256) + NUM_LENGTH_CODES (24) + (0 or a non-zero power of + // 2). See the usage in VP8LHistogramAdd(). + assert(size >= 32); + assert(size % 2 == 0); + + do { + const __m256i a0 = _mm256_loadu_si256((const __m256i*)&a[i + 0]); + const __m256i a1 = _mm256_loadu_si256((const __m256i*)&a[i + 8]); + const __m256i a2 = _mm256_loadu_si256((const __m256i*)&a[i + 16]); + const __m256i a3 = _mm256_loadu_si256((const __m256i*)&a[i + 24]); + const __m256i b0 = _mm256_loadu_si256((const __m256i*)&b[i + 0]); + const __m256i b1 = _mm256_loadu_si256((const __m256i*)&b[i + 8]); + const __m256i b2 = _mm256_loadu_si256((const __m256i*)&b[i + 16]); + const __m256i b3 = _mm256_loadu_si256((const __m256i*)&b[i + 24]); + _mm256_storeu_si256((__m256i*)&out[i + 0], _mm256_add_epi32(a0, b0)); + _mm256_storeu_si256((__m256i*)&out[i + 8], _mm256_add_epi32(a1, b1)); + _mm256_storeu_si256((__m256i*)&out[i + 16], _mm256_add_epi32(a2, b2)); + _mm256_storeu_si256((__m256i*)&out[i + 24], _mm256_add_epi32(a3, b3)); + i += 32; + } while (i != aligned_size); + + if ((size & 16) != 0) { + const __m256i a0 = _mm256_loadu_si256((const __m256i*)&a[i + 0]); + const __m256i a1 = _mm256_loadu_si256((const __m256i*)&a[i + 8]); + const __m256i b0 = _mm256_loadu_si256((const __m256i*)&b[i + 0]); + const __m256i b1 = _mm256_loadu_si256((const __m256i*)&b[i + 8]); + _mm256_storeu_si256((__m256i*)&out[i + 0], _mm256_add_epi32(a0, b0)); + _mm256_storeu_si256((__m256i*)&out[i + 8], _mm256_add_epi32(a1, b1)); + i += 16; + } + + size &= 15; + if (size == 8) { + const __m256i a0 = _mm256_loadu_si256((const __m256i*)&a[i]); + const __m256i b0 = _mm256_loadu_si256((const __m256i*)&b[i]); + _mm256_storeu_si256((__m256i*)&out[i], _mm256_add_epi32(a0, b0)); + } else { + for (; size--; ++i) { + out[i] = a[i] + b[i]; + } + } +} + +static void AddVectorEq_AVX2(const uint32_t* WEBP_RESTRICT a, + uint32_t* WEBP_RESTRICT out, int size) { + int i = 0; + int aligned_size = size & ~31; + // Size is, at minimum, NUM_DISTANCE_CODES (40) and may be as large as + // NUM_LITERAL_CODES (256) + NUM_LENGTH_CODES (24) + (0 or a non-zero power of + // 2). See the usage in VP8LHistogramAdd(). + assert(size >= 32); + assert(size % 2 == 0); + + do { + const __m256i a0 = _mm256_loadu_si256((const __m256i*)&a[i + 0]); + const __m256i a1 = _mm256_loadu_si256((const __m256i*)&a[i + 8]); + const __m256i a2 = _mm256_loadu_si256((const __m256i*)&a[i + 16]); + const __m256i a3 = _mm256_loadu_si256((const __m256i*)&a[i + 24]); + const __m256i b0 = _mm256_loadu_si256((const __m256i*)&out[i + 0]); + const __m256i b1 = _mm256_loadu_si256((const __m256i*)&out[i + 8]); + const __m256i b2 = _mm256_loadu_si256((const __m256i*)&out[i + 16]); + const __m256i b3 = _mm256_loadu_si256((const __m256i*)&out[i + 24]); + _mm256_storeu_si256((__m256i*)&out[i + 0], _mm256_add_epi32(a0, b0)); + _mm256_storeu_si256((__m256i*)&out[i + 8], _mm256_add_epi32(a1, b1)); + _mm256_storeu_si256((__m256i*)&out[i + 16], _mm256_add_epi32(a2, b2)); + _mm256_storeu_si256((__m256i*)&out[i + 24], _mm256_add_epi32(a3, b3)); + i += 32; + } while (i != aligned_size); + + if ((size & 16) != 0) { + const __m256i a0 = _mm256_loadu_si256((const __m256i*)&a[i + 0]); + const __m256i a1 = _mm256_loadu_si256((const __m256i*)&a[i + 8]); + const __m256i b0 = _mm256_loadu_si256((const __m256i*)&out[i + 0]); + const __m256i b1 = _mm256_loadu_si256((const __m256i*)&out[i + 8]); + _mm256_storeu_si256((__m256i*)&out[i + 0], _mm256_add_epi32(a0, b0)); + _mm256_storeu_si256((__m256i*)&out[i + 8], _mm256_add_epi32(a1, b1)); + i += 16; + } + + size &= 15; + if (size == 8) { + const __m256i a0 = _mm256_loadu_si256((const __m256i*)&a[i]); + const __m256i b0 = _mm256_loadu_si256((const __m256i*)&out[i]); + _mm256_storeu_si256((__m256i*)&out[i], _mm256_add_epi32(a0, b0)); + } else { + for (; size--; ++i) { + out[i] += a[i]; + } + } +} + +//------------------------------------------------------------------------------ +// Entropy + +#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ) + +static uint64_t CombinedShannonEntropy_AVX2(const uint32_t X[256], + const uint32_t Y[256]) { + int i; + uint64_t retval = 0; + uint32_t sumX = 0, sumXY = 0; + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < 256; i += 32) { + const __m256i x0 = _mm256_loadu_si256((const __m256i*)(X + i + 0)); + const __m256i y0 = _mm256_loadu_si256((const __m256i*)(Y + i + 0)); + const __m256i x1 = _mm256_loadu_si256((const __m256i*)(X + i + 8)); + const __m256i y1 = _mm256_loadu_si256((const __m256i*)(Y + i + 8)); + const __m256i x2 = _mm256_loadu_si256((const __m256i*)(X + i + 16)); + const __m256i y2 = _mm256_loadu_si256((const __m256i*)(Y + i + 16)); + const __m256i x3 = _mm256_loadu_si256((const __m256i*)(X + i + 24)); + const __m256i y3 = _mm256_loadu_si256((const __m256i*)(Y + i + 24)); + const __m256i x4 = _mm256_packs_epi16(_mm256_packs_epi32(x0, x1), + _mm256_packs_epi32(x2, x3)); + const __m256i y4 = _mm256_packs_epi16(_mm256_packs_epi32(y0, y1), + _mm256_packs_epi32(y2, y3)); + // Packed pixels are actually in order: ... 17 16 12 11 10 9 8 3 2 1 0 + const __m256i x5 = _mm256_permutevar8x32_epi32( + x4, _mm256_set_epi32(7, 3, 6, 2, 5, 1, 4, 0)); + const __m256i y5 = _mm256_permutevar8x32_epi32( + y4, _mm256_set_epi32(7, 3, 6, 2, 5, 1, 4, 0)); + const uint32_t mx = + (uint32_t)_mm256_movemask_epi8(_mm256_cmpgt_epi8(x5, zero)); + uint32_t my = + (uint32_t)_mm256_movemask_epi8(_mm256_cmpgt_epi8(y5, zero)) | mx; + while (my) { + const int32_t j = BitsCtz(my); + uint32_t xy; + if ((mx >> j) & 1) { + const int x = X[i + j]; + sumXY += x; + retval += VP8LFastSLog2(x); + } + xy = X[i + j] + Y[i + j]; + sumX += xy; + retval += VP8LFastSLog2(xy); + my &= my - 1; + } + } + retval = VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY) - retval; + return retval; +} + +#else + +#define DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC // won't be faster + +#endif + +//------------------------------------------------------------------------------ + +static int VectorMismatch_AVX2(const uint32_t* const array1, + const uint32_t* const array2, int length) { + int match_len; + + if (length >= 24) { + __m256i A0 = _mm256_loadu_si256((const __m256i*)&array1[0]); + __m256i A1 = _mm256_loadu_si256((const __m256i*)&array2[0]); + match_len = 0; + do { + // Loop unrolling and early load both provide a speedup of 10% for the + // current function. Also, max_limit can be MAX_LENGTH=4096 at most. + const __m256i cmpA = _mm256_cmpeq_epi32(A0, A1); + const __m256i B0 = + _mm256_loadu_si256((const __m256i*)&array1[match_len + 8]); + const __m256i B1 = + _mm256_loadu_si256((const __m256i*)&array2[match_len + 8]); + if ((uint32_t)_mm256_movemask_epi8(cmpA) != 0xffffffff) break; + match_len += 8; + + { + const __m256i cmpB = _mm256_cmpeq_epi32(B0, B1); + A0 = _mm256_loadu_si256((const __m256i*)&array1[match_len + 8]); + A1 = _mm256_loadu_si256((const __m256i*)&array2[match_len + 8]); + if ((uint32_t)_mm256_movemask_epi8(cmpB) != 0xffffffff) break; + match_len += 8; + } + } while (match_len + 24 < length); + } else { + match_len = 0; + // Unroll the potential first two loops. + if (length >= 8 && + (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi32( + _mm256_loadu_si256((const __m256i*)&array1[0]), + _mm256_loadu_si256((const __m256i*)&array2[0]))) == 0xffffffff) { + match_len = 8; + if (length >= 16 && + (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi32( + _mm256_loadu_si256((const __m256i*)&array1[8]), + _mm256_loadu_si256((const __m256i*)&array2[8]))) == 0xffffffff) { + match_len = 16; + } + } + } + + while (match_len < length && array1[match_len] == array2[match_len]) { + ++match_len; + } + return match_len; +} + +// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. +static void BundleColorMap_AVX2(const uint8_t* WEBP_RESTRICT const row, + int width, int xbits, + uint32_t* WEBP_RESTRICT dst) { + int x = 0; + assert(xbits >= 0); + assert(xbits <= 3); + switch (xbits) { + case 0: { + const __m256i ff = _mm256_set1_epi16((short)0xff00); + const __m256i zero = _mm256_setzero_si256(); + // Store 0xff000000 | (row[x] << 8). + for (x = 0; x + 32 <= width; x += 32, dst += 32) { + const __m256i in = _mm256_loadu_si256((const __m256i*)&row[x]); + const __m256i in_lo = _mm256_unpacklo_epi8(zero, in); + const __m256i dst0 = _mm256_unpacklo_epi16(in_lo, ff); + const __m256i dst1 = _mm256_unpackhi_epi16(in_lo, ff); + const __m256i in_hi = _mm256_unpackhi_epi8(zero, in); + const __m256i dst2 = _mm256_unpacklo_epi16(in_hi, ff); + const __m256i dst3 = _mm256_unpackhi_epi16(in_hi, ff); + _mm256_storeu2_m128i((__m128i*)&dst[16], (__m128i*)&dst[0], dst0); + _mm256_storeu2_m128i((__m128i*)&dst[20], (__m128i*)&dst[4], dst1); + _mm256_storeu2_m128i((__m128i*)&dst[24], (__m128i*)&dst[8], dst2); + _mm256_storeu2_m128i((__m128i*)&dst[28], (__m128i*)&dst[12], dst3); + } + break; + } + case 1: { + const __m256i ff = _mm256_set1_epi16((short)0xff00); + const __m256i mul = _mm256_set1_epi16(0x110); + for (x = 0; x + 32 <= width; x += 32, dst += 16) { + // 0a0b | (where a/b are 4 bits). + const __m256i in = _mm256_loadu_si256((const __m256i*)&row[x]); + const __m256i tmp = _mm256_mullo_epi16(in, mul); // aba0 + const __m256i pack = _mm256_and_si256(tmp, ff); // ab00 + const __m256i dst0 = _mm256_unpacklo_epi16(pack, ff); + const __m256i dst1 = _mm256_unpackhi_epi16(pack, ff); + _mm256_storeu2_m128i((__m128i*)&dst[8], (__m128i*)&dst[0], dst0); + _mm256_storeu2_m128i((__m128i*)&dst[12], (__m128i*)&dst[4], dst1); + } + break; + } + case 2: { + const __m256i mask_or = _mm256_set1_epi32((int)0xff000000); + const __m256i mul_cst = _mm256_set1_epi16(0x0104); + const __m256i mask_mul = _mm256_set1_epi16(0x0f00); + for (x = 0; x + 32 <= width; x += 32, dst += 8) { + // 000a000b000c000d | (where a/b/c/d are 2 bits). + const __m256i in = _mm256_loadu_si256((const __m256i*)&row[x]); + const __m256i mul = + _mm256_mullo_epi16(in, mul_cst); // 00ab00b000cd00d0 + const __m256i tmp = + _mm256_and_si256(mul, mask_mul); // 00ab000000cd0000 + const __m256i shift = _mm256_srli_epi32(tmp, 12); // 00000000ab000000 + const __m256i pack = _mm256_or_si256(shift, tmp); // 00000000abcd0000 + // Convert to 0xff00**00. + const __m256i res = _mm256_or_si256(pack, mask_or); + _mm256_storeu_si256((__m256i*)dst, res); + } + break; + } + default: { + assert(xbits == 3); + for (x = 0; x + 32 <= width; x += 32, dst += 4) { + // 0000000a00000000b... | (where a/b are 1 bit). + const __m256i in = _mm256_loadu_si256((const __m256i*)&row[x]); + const __m256i shift = _mm256_slli_epi64(in, 7); + const uint32_t move = _mm256_movemask_epi8(shift); + dst[0] = 0xff000000 | ((move & 0xff) << 8); + dst[1] = 0xff000000 | (move & 0xff00); + dst[2] = 0xff000000 | ((move & 0xff0000) >> 8); + dst[3] = 0xff000000 | ((move & 0xff000000) >> 16); + } + break; + } + } + if (x != width) { + VP8LBundleColorMap_SSE(row + x, width - x, xbits, dst); + } +} + +//------------------------------------------------------------------------------ +// Batch version of Predictor Transform subtraction + +static WEBP_INLINE void Average2_m256i(const __m256i* const a0, + const __m256i* const a1, + __m256i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m256i ones = _mm256_set1_epi8(1); + const __m256i avg1 = _mm256_avg_epu8(*a0, *a1); + const __m256i one = _mm256_and_si256(_mm256_xor_si256(*a0, *a1), ones); + *avg = _mm256_sub_epi8(avg1, one); +} + +// Predictor0: ARGB_BLACK. +static void PredictorSub0_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + const __m256i black = _mm256_set1_epi32((int)ARGB_BLACK); + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + const __m256i res = _mm256_sub_epi8(src, black); + _mm256_storeu_si256((__m256i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_SSE[0](in + i, NULL, num_pixels - i, out + i); + } + (void)upper; +} + +#define GENERATE_PREDICTOR_1(X, IN) \ + static void PredictorSub##X##_AVX2( \ + const uint32_t* const in, const uint32_t* const upper, int num_pixels, \ + uint32_t* WEBP_RESTRICT const out) { \ + int i; \ + for (i = 0; i + 8 <= num_pixels; i += 8) { \ + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); \ + const __m256i pred = _mm256_loadu_si256((const __m256i*)&(IN)); \ + const __m256i res = _mm256_sub_epi8(src, pred); \ + _mm256_storeu_si256((__m256i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsSub_SSE[(X)](in + i, WEBP_OFFSET_PTR(upper, i), \ + num_pixels - i, out + i); \ + } \ + } + +GENERATE_PREDICTOR_1(1, in[i - 1]) // Predictor1: L +GENERATE_PREDICTOR_1(2, upper[i]) // Predictor2: T +GENERATE_PREDICTOR_1(3, upper[i + 1]) // Predictor3: TR +GENERATE_PREDICTOR_1(4, upper[i - 1]) // Predictor4: TL +#undef GENERATE_PREDICTOR_1 + +// Predictor5: avg2(avg2(L, TR), T) +static void PredictorSub5_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i L = _mm256_loadu_si256((const __m256i*)&in[i - 1]); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i TR = _mm256_loadu_si256((const __m256i*)&upper[i + 1]); + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + __m256i avg, pred, res; + Average2_m256i(&L, &TR, &avg); + Average2_m256i(&avg, &T, &pred); + res = _mm256_sub_epi8(src, pred); + _mm256_storeu_si256((__m256i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_SSE[5](in + i, upper + i, num_pixels - i, out + i); + } +} + +#define GENERATE_PREDICTOR_2(X, A, B) \ + static void PredictorSub##X##_AVX2(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* WEBP_RESTRICT out) { \ + int i; \ + for (i = 0; i + 8 <= num_pixels; i += 8) { \ + const __m256i tA = _mm256_loadu_si256((const __m256i*)&(A)); \ + const __m256i tB = _mm256_loadu_si256((const __m256i*)&(B)); \ + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); \ + __m256i pred, res; \ + Average2_m256i(&tA, &tB, &pred); \ + res = _mm256_sub_epi8(src, pred); \ + _mm256_storeu_si256((__m256i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsSub_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ + } + +GENERATE_PREDICTOR_2(6, in[i - 1], upper[i - 1]) // Predictor6: avg(L, TL) +GENERATE_PREDICTOR_2(7, in[i - 1], upper[i]) // Predictor7: avg(L, T) +GENERATE_PREDICTOR_2(8, upper[i - 1], upper[i]) // Predictor8: avg(TL, T) +GENERATE_PREDICTOR_2(9, upper[i], upper[i + 1]) // Predictor9: average(T, TR) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: avg(avg(L,TL), avg(T, TR)). +static void PredictorSub10_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i L = _mm256_loadu_si256((const __m256i*)&in[i - 1]); + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + const __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i TR = _mm256_loadu_si256((const __m256i*)&upper[i + 1]); + __m256i avgTTR, avgLTL, avg, res; + Average2_m256i(&T, &TR, &avgTTR); + Average2_m256i(&L, &TL, &avgLTL); + Average2_m256i(&avgTTR, &avgLTL, &avg); + res = _mm256_sub_epi8(src, avg); + _mm256_storeu_si256((__m256i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_SSE[10](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor11: select. +static void GetSumAbsDiff32_AVX2(const __m256i* const A, const __m256i* const B, + __m256i* const out) { + // We can unpack with any value on the upper 32 bits, provided it's the same + // on both operands (to that their sum of abs diff is zero). Here we use *A. + const __m256i A_lo = _mm256_unpacklo_epi32(*A, *A); + const __m256i B_lo = _mm256_unpacklo_epi32(*B, *A); + const __m256i A_hi = _mm256_unpackhi_epi32(*A, *A); + const __m256i B_hi = _mm256_unpackhi_epi32(*B, *A); + const __m256i s_lo = _mm256_sad_epu8(A_lo, B_lo); + const __m256i s_hi = _mm256_sad_epu8(A_hi, B_hi); + *out = _mm256_packs_epi32(s_lo, s_hi); +} + +static void PredictorSub11_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i L = _mm256_loadu_si256((const __m256i*)&in[i - 1]); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + __m256i pa, pb; + GetSumAbsDiff32_AVX2(&T, &TL, &pa); // pa = sum |T-TL| + GetSumAbsDiff32_AVX2(&L, &TL, &pb); // pb = sum |L-TL| + { + const __m256i mask = _mm256_cmpgt_epi32(pb, pa); + const __m256i A = _mm256_and_si256(mask, L); + const __m256i B = _mm256_andnot_si256(mask, T); + const __m256i pred = _mm256_or_si256(A, B); // pred = (L > T)? L : T + const __m256i res = _mm256_sub_epi8(src, pred); + _mm256_storeu_si256((__m256i*)&out[i], res); + } + } + if (i != num_pixels) { + VP8LPredictorsSub_SSE[11](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor12: ClampedSubSubtractFull. +static void PredictorSub12_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + const __m256i zero = _mm256_setzero_si256(); + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + const __m256i L = _mm256_loadu_si256((const __m256i*)&in[i - 1]); + const __m256i L_lo = _mm256_unpacklo_epi8(L, zero); + const __m256i L_hi = _mm256_unpackhi_epi8(L, zero); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i T_lo = _mm256_unpacklo_epi8(T, zero); + const __m256i T_hi = _mm256_unpackhi_epi8(T, zero); + const __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + const __m256i TL_lo = _mm256_unpacklo_epi8(TL, zero); + const __m256i TL_hi = _mm256_unpackhi_epi8(TL, zero); + const __m256i diff_lo = _mm256_sub_epi16(T_lo, TL_lo); + const __m256i diff_hi = _mm256_sub_epi16(T_hi, TL_hi); + const __m256i pred_lo = _mm256_add_epi16(L_lo, diff_lo); + const __m256i pred_hi = _mm256_add_epi16(L_hi, diff_hi); + const __m256i pred = _mm256_packus_epi16(pred_lo, pred_hi); + const __m256i res = _mm256_sub_epi8(src, pred); + _mm256_storeu_si256((__m256i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_SSE[12](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictors13: ClampedAddSubtractHalf +static void PredictorSub13_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + const __m256i zero = _mm256_setzero_si256(); + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i L = _mm256_loadu_si256((const __m256i*)&in[i - 1]); + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + // lo. + const __m256i L_lo = _mm256_unpacklo_epi8(L, zero); + const __m256i T_lo = _mm256_unpacklo_epi8(T, zero); + const __m256i TL_lo = _mm256_unpacklo_epi8(TL, zero); + const __m256i sum_lo = _mm256_add_epi16(T_lo, L_lo); + const __m256i avg_lo = _mm256_srli_epi16(sum_lo, 1); + const __m256i A1_lo = _mm256_sub_epi16(avg_lo, TL_lo); + const __m256i bit_fix_lo = _mm256_cmpgt_epi16(TL_lo, avg_lo); + const __m256i A2_lo = _mm256_sub_epi16(A1_lo, bit_fix_lo); + const __m256i A3_lo = _mm256_srai_epi16(A2_lo, 1); + const __m256i A4_lo = _mm256_add_epi16(avg_lo, A3_lo); + // hi. + const __m256i L_hi = _mm256_unpackhi_epi8(L, zero); + const __m256i T_hi = _mm256_unpackhi_epi8(T, zero); + const __m256i TL_hi = _mm256_unpackhi_epi8(TL, zero); + const __m256i sum_hi = _mm256_add_epi16(T_hi, L_hi); + const __m256i avg_hi = _mm256_srli_epi16(sum_hi, 1); + const __m256i A1_hi = _mm256_sub_epi16(avg_hi, TL_hi); + const __m256i bit_fix_hi = _mm256_cmpgt_epi16(TL_hi, avg_hi); + const __m256i A2_hi = _mm256_sub_epi16(A1_hi, bit_fix_hi); + const __m256i A3_hi = _mm256_srai_epi16(A2_hi, 1); + const __m256i A4_hi = _mm256_add_epi16(avg_hi, A3_hi); + + const __m256i pred = _mm256_packus_epi16(A4_lo, A4_hi); + const __m256i res = _mm256_sub_epi8(src, pred); + _mm256_storeu_si256((__m256i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_SSE[13](in + i, upper + i, num_pixels - i, out + i); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LEncDspInitAVX2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitAVX2(void) { + VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_AVX2; + VP8LTransformColor = TransformColor_AVX2; + VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_AVX2; + VP8LCollectColorRedTransforms = CollectColorRedTransforms_AVX2; + VP8LAddVector = AddVector_AVX2; + VP8LAddVectorEq = AddVectorEq_AVX2; + VP8LCombinedShannonEntropy = CombinedShannonEntropy_AVX2; + VP8LVectorMismatch = VectorMismatch_AVX2; + VP8LBundleColorMap = BundleColorMap_AVX2; + + VP8LPredictorsSub[0] = PredictorSub0_AVX2; + VP8LPredictorsSub[1] = PredictorSub1_AVX2; + VP8LPredictorsSub[2] = PredictorSub2_AVX2; + VP8LPredictorsSub[3] = PredictorSub3_AVX2; + VP8LPredictorsSub[4] = PredictorSub4_AVX2; + VP8LPredictorsSub[5] = PredictorSub5_AVX2; + VP8LPredictorsSub[6] = PredictorSub6_AVX2; + VP8LPredictorsSub[7] = PredictorSub7_AVX2; + VP8LPredictorsSub[8] = PredictorSub8_AVX2; + VP8LPredictorsSub[9] = PredictorSub9_AVX2; + VP8LPredictorsSub[10] = PredictorSub10_AVX2; + VP8LPredictorsSub[11] = PredictorSub11_AVX2; + VP8LPredictorsSub[12] = PredictorSub12_AVX2; + VP8LPredictorsSub[13] = PredictorSub13_AVX2; + VP8LPredictorsSub[14] = PredictorSub0_AVX2; // <- padding security sentinels + VP8LPredictorsSub[15] = PredictorSub0_AVX2; +} + +#else // !WEBP_USE_AVX2 + +WEBP_DSP_INIT_STUB(VP8LEncDspInitAVX2) + +#endif // WEBP_USE_AVX2 diff --git a/media/libwebp/src/dsp/lossless_enc_mips32.c b/media/libwebp/src/dsp/lossless_enc_mips32.c --- a/media/libwebp/src/dsp/lossless_enc_mips32.c +++ b/media/libwebp/src/dsp/lossless_enc_mips32.c @@ -131,64 +131,10 @@ ); return ((int64_t)temp0 << 32 | temp1); } -// C version of this function: -// int i = 0; -// int64_t cost = 0; -// const uint32_t* pX = &X[4]; -// const uint32_t* pY = &Y[4]; -// const uint32_t* LoopEnd = &X[length]; -// while (pX != LoopEnd) { -// const uint32_t xy0 = *pX + *pY; -// const uint32_t xy1 = *(pX + 1) + *(pY + 1); -// ++i; -// cost += i * xy0; -// cost += i * xy1; -// pX += 2; -// pY += 2; -// } -// return cost; -static uint32_t ExtraCostCombined_MIPS32(const uint32_t* WEBP_RESTRICT const X, - const uint32_t* WEBP_RESTRICT const Y, - int length) { - int i, temp0, temp1, temp2, temp3; - const uint32_t* pX = &X[4]; - const uint32_t* pY = &Y[4]; - const uint32_t* const LoopEnd = &X[length]; - - __asm__ volatile( - "mult $zero, $zero \n\t" - "xor %[i], %[i], %[i] \n\t" - "beq %[pX], %[LoopEnd], 2f \n\t" - "1: \n\t" - "lw %[temp0], 0(%[pX]) \n\t" - "lw %[temp1], 0(%[pY]) \n\t" - "lw %[temp2], 4(%[pX]) \n\t" - "lw %[temp3], 4(%[pY]) \n\t" - "addiu %[i], %[i], 1 \n\t" - "addu %[temp0], %[temp0], %[temp1] \n\t" - "addu %[temp2], %[temp2], %[temp3] \n\t" - "addiu %[pX], %[pX], 8 \n\t" - "addiu %[pY], %[pY], 8 \n\t" - "madd %[i], %[temp0] \n\t" - "madd %[i], %[temp2] \n\t" - "bne %[pX], %[LoopEnd], 1b \n\t" - "2: \n\t" - "mfhi %[temp0] \n\t" - "mflo %[temp1] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [i]"=&r"(i), [pX]"+r"(pX), [pY]"+r"(pY) - : [LoopEnd]"r"(LoopEnd) - : "memory", "hi", "lo" - ); - - return ((int64_t)temp0 << 32 | temp1); -} - #define HUFFMAN_COST_PASS \ __asm__ volatile( \ "sll %[temp1], %[temp0], 3 \n\t" \ "addiu %[temp3], %[streak], -3 \n\t" \ "addu %[temp2], %[pstreaks], %[temp1] \n\t" \ @@ -297,11 +243,11 @@ // P2 = P0 + P1 // A..D - offsets // E - temp variable to tell macro // if pointer should be incremented -// literal_ and successive histograms could be unaligned +// 'literal' and successive histograms could be unaligned // so we must use ulw and usw #define ADD_TO_OUT(A, B, C, D, E, P0, P1, P2) \ "ulw %[temp0], " #A "(%[" #P0 "]) \n\t" \ "ulw %[temp1], " #B "(%[" #P0 "]) \n\t" \ "ulw %[temp2], " #C "(%[" #P0 "]) \n\t" \ @@ -386,11 +332,10 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPS32(void) { VP8LFastSLog2Slow = FastSLog2Slow_MIPS32; VP8LFastLog2Slow = FastLog2Slow_MIPS32; VP8LExtraCost = ExtraCost_MIPS32; - VP8LExtraCostCombined = ExtraCostCombined_MIPS32; VP8LGetEntropyUnrefined = GetEntropyUnrefined_MIPS32; VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_MIPS32; VP8LAddVector = AddVector_MIPS32; VP8LAddVectorEq = AddVectorEq_MIPS32; } diff --git a/media/libwebp/src/dsp/lossless_enc_mips_dsp_r2.c b/media/libwebp/src/dsp/lossless_enc_mips_dsp_r2.c --- a/media/libwebp/src/dsp/lossless_enc_mips_dsp_r2.c +++ b/media/libwebp/src/dsp/lossless_enc_mips_dsp_r2.c @@ -81,13 +81,13 @@ static void TransformColor_MIPSdspR2( const VP8LMultipliers* WEBP_RESTRICT const m, uint32_t* WEBP_RESTRICT data, int num_pixels) { int temp0, temp1, temp2, temp3, temp4, temp5; uint32_t argb, argb1, new_red, new_red1; - const uint32_t G_to_R = m->green_to_red_; - const uint32_t G_to_B = m->green_to_blue_; - const uint32_t R_to_B = m->red_to_blue_; + const uint32_t G_to_R = m->green_to_red; + const uint32_t G_to_B = m->green_to_blue; + const uint32_t R_to_B = m->red_to_blue; uint32_t* const p_loop_end = data + (num_pixels & ~1); __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" "beq %[data], %[p_loop_end], 1f \n\t" @@ -150,14 +150,14 @@ const uint32_t argb_ = data[0]; const uint32_t green = argb_ >> 8; const uint32_t red = argb_ >> 16; uint32_t new_blue = argb_; new_red = red; - new_red -= ColorTransformDelta(m->green_to_red_, green); + new_red -= ColorTransformDelta(m->green_to_red, green); new_red &= 0xff; - new_blue -= ColorTransformDelta(m->green_to_blue_, green); - new_blue -= ColorTransformDelta(m->red_to_blue_, red); + new_blue -= ColorTransformDelta(m->green_to_blue, green); + new_blue -= ColorTransformDelta(m->red_to_blue, red); new_blue &= 0xff; data[0] = (argb_ & 0xff00ff00u) | (new_red << 16) | (new_blue); } } diff --git a/media/libwebp/src/dsp/lossless_enc_msa.c b/media/libwebp/src/dsp/lossless_enc_msa.c --- a/media/libwebp/src/dsp/lossless_enc_msa.c +++ b/media/libwebp/src/dsp/lossless_enc_msa.c @@ -49,13 +49,13 @@ } while (0) static void TransformColor_MSA(const VP8LMultipliers* WEBP_RESTRICT const m, uint32_t* WEBP_RESTRICT data, int num_pixels) { v16u8 src0, dst0; - const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue_ | - (m->green_to_red_ << 16)); - const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue_); + const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue | + (m->green_to_red << 16)); + const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue); const v16u8 mask0 = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255 }; const v16u8 mask1 = { 16, 1, 18, 3, 20, 5, 22, 7, 24, 9, 26, 11, 28, 13, 30, 15 }; diff --git a/media/libwebp/src/dsp/lossless_enc_neon.c b/media/libwebp/src/dsp/lossless_enc_neon.c --- a/media/libwebp/src/dsp/lossless_enc_neon.c +++ b/media/libwebp/src/dsp/lossless_enc_neon.c @@ -76,19 +76,19 @@ uint32_t* WEBP_RESTRICT argb_data, int num_pixels) { // sign-extended multiplying constants, pre-shifted by 6. #define CST(X) (((int16_t)(m->X << 8)) >> 6) const int16_t rb[8] = { - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_) + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red) }; const int16x8_t mults_rb = vld1q_s16(rb); const int16_t b2[8] = { - 0, CST(red_to_blue_), 0, CST(red_to_blue_), - 0, CST(red_to_blue_), 0, CST(red_to_blue_), + 0, CST(red_to_blue), 0, CST(red_to_blue), + 0, CST(red_to_blue), 0, CST(red_to_blue), }; const int16x8_t mults_b2 = vld1q_s16(b2); #undef CST #ifdef USE_VTBLQ static const uint8_t kg0g0[16] = { diff --git a/media/libwebp/src/dsp/lossless_enc_sse2.c b/media/libwebp/src/dsp/lossless_enc_sse2.c --- a/media/libwebp/src/dsp/lossless_enc_sse2.c +++ b/media/libwebp/src/dsp/lossless_enc_sse2.c @@ -12,15 +12,21 @@ // Author: Skal (pascal.massimino@gmail.com) #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE2) +#include + #include -#include +#include + +#include "src/dsp/cpu.h" #include "src/dsp/lossless.h" -#include "src/dsp/common_sse2.h" #include "src/dsp/lossless_common.h" +#include "src/utils/utils.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" // For sign-extended multiplying constants, pre-shifted by 5: #define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5) //------------------------------------------------------------------------------ @@ -50,13 +56,13 @@ _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) static void TransformColor_SSE2(const VP8LMultipliers* WEBP_RESTRICT const m, uint32_t* WEBP_RESTRICT argb_data, int num_pixels) { - const __m128i mults_rb = MK_CST_16(CST_5b(m->green_to_red_), - CST_5b(m->green_to_blue_)); - const __m128i mults_b2 = MK_CST_16(CST_5b(m->red_to_blue_), 0); + const __m128i mults_rb = MK_CST_16(CST_5b(m->green_to_red), + CST_5b(m->green_to_blue)); + const __m128i mults_b2 = MK_CST_16(CST_5b(m->red_to_blue), 0); const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); // alpha-green masks const __m128i mask_rb = _mm_set1_epi32(0x00ff00ff); // red-blue masks int i; for (i = 0; i + 4 <= num_pixels; i += 4) { const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb @@ -643,29 +649,47 @@ // Predictors13: ClampedAddSubtractHalf static void PredictorSub13_SSE2(const uint32_t* in, const uint32_t* upper, int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; const __m128i zero = _mm_setzero_si128(); - for (i = 0; i + 2 <= num_pixels; i += 2) { - // we can only process two pixels at a time - const __m128i L = _mm_loadl_epi64((const __m128i*)&in[i - 1]); - const __m128i src = _mm_loadl_epi64((const __m128i*)&in[i]); - const __m128i T = _mm_loadl_epi64((const __m128i*)&upper[i]); - const __m128i TL = _mm_loadl_epi64((const __m128i*)&upper[i - 1]); - const __m128i L_lo = _mm_unpacklo_epi8(L, zero); - const __m128i T_lo = _mm_unpacklo_epi8(T, zero); - const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); - const __m128i sum = _mm_add_epi16(T_lo, L_lo); - const __m128i avg = _mm_srli_epi16(sum, 1); - const __m128i A1 = _mm_sub_epi16(avg, TL_lo); - const __m128i bit_fix = _mm_cmpgt_epi16(TL_lo, avg); - const __m128i A2 = _mm_sub_epi16(A1, bit_fix); - const __m128i A3 = _mm_srai_epi16(A2, 1); - const __m128i A4 = _mm_add_epi16(avg, A3); - const __m128i pred = _mm_packus_epi16(A4, A4); - const __m128i res = _mm_sub_epi8(src, pred); - _mm_storel_epi64((__m128i*)&out[i], res); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + __m128i A4_lo, A4_hi; + // lo. + { + const __m128i L_lo = _mm_unpacklo_epi8(L, zero); + const __m128i T_lo = _mm_unpacklo_epi8(T, zero); + const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); + const __m128i sum_lo = _mm_add_epi16(T_lo, L_lo); + const __m128i avg_lo = _mm_srli_epi16(sum_lo, 1); + const __m128i A1_lo = _mm_sub_epi16(avg_lo, TL_lo); + const __m128i bit_fix_lo = _mm_cmpgt_epi16(TL_lo, avg_lo); + const __m128i A2_lo = _mm_sub_epi16(A1_lo, bit_fix_lo); + const __m128i A3_lo = _mm_srai_epi16(A2_lo, 1); + A4_lo = _mm_add_epi16(avg_lo, A3_lo); + } + // hi. + { + const __m128i L_hi = _mm_unpackhi_epi8(L, zero); + const __m128i T_hi = _mm_unpackhi_epi8(T, zero); + const __m128i TL_hi = _mm_unpackhi_epi8(TL, zero); + const __m128i sum_hi = _mm_add_epi16(T_hi, L_hi); + const __m128i avg_hi = _mm_srli_epi16(sum_hi, 1); + const __m128i A1_hi = _mm_sub_epi16(avg_hi, TL_hi); + const __m128i bit_fix_hi = _mm_cmpgt_epi16(TL_hi, avg_hi); + const __m128i A2_hi = _mm_sub_epi16(A1_hi, bit_fix_hi); + const __m128i A3_hi = _mm_srai_epi16(A2_hi, 1); + A4_hi = _mm_add_epi16(avg_hi, A3_hi); + } + { + const __m128i pred = _mm_packus_epi16(A4_lo, A4_hi); + const __m128i res = _mm_sub_epi8(src, pred); + _mm_storeu_si128((__m128i*)&out[i], res); + } } if (i != num_pixels) { VP8LPredictorsSub_C[13](in + i, upper + i, num_pixels - i, out + i); } } @@ -702,10 +726,19 @@ VP8LPredictorsSub[11] = PredictorSub11_SSE2; VP8LPredictorsSub[12] = PredictorSub12_SSE2; VP8LPredictorsSub[13] = PredictorSub13_SSE2; VP8LPredictorsSub[14] = PredictorSub0_SSE2; // <- padding security sentinels VP8LPredictorsSub[15] = PredictorSub0_SSE2; + + // SSE exports for AVX and above. + VP8LSubtractGreenFromBlueAndRed_SSE = SubtractGreenFromBlueAndRed_SSE2; + VP8LTransformColor_SSE = TransformColor_SSE2; + VP8LCollectColorBlueTransforms_SSE = CollectColorBlueTransforms_SSE2; + VP8LCollectColorRedTransforms_SSE = CollectColorRedTransforms_SSE2; + VP8LBundleColorMap_SSE = BundleColorMap_SSE2; + + memcpy(VP8LPredictorsSub_SSE, VP8LPredictorsSub, sizeof(VP8LPredictorsSub)); } #else // !WEBP_USE_SSE2 WEBP_DSP_INIT_STUB(VP8LEncDspInitSSE2) diff --git a/media/libwebp/src/dsp/lossless_enc_sse41.c b/media/libwebp/src/dsp/lossless_enc_sse41.c --- a/media/libwebp/src/dsp/lossless_enc_sse41.c +++ b/media/libwebp/src/dsp/lossless_enc_sse41.c @@ -12,13 +12,18 @@ // Author: Skal (pascal.massimino@gmail.com) #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) -#include +#include #include + +#include + +#include "src/dsp/cpu.h" #include "src/dsp/lossless.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Cost operations. static WEBP_INLINE uint32_t HorizontalSum_SSE41(__m128i cost) { @@ -42,33 +47,10 @@ cost = _mm_add_epi32(mul, cost); } return HorizontalSum_SSE41(cost); } -static uint32_t ExtraCostCombined_SSE41(const uint32_t* WEBP_RESTRICT const a, - const uint32_t* WEBP_RESTRICT const b, - int length) { - int i; - __m128i cost = _mm_add_epi32(_mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]), - _mm_set_epi32(2 * b[7], 2 * b[6], b[5], b[4])); - assert(length % 8 == 0); - - for (i = 8; i + 8 <= length; i += 8) { - const int j = (i - 2) >> 1; - const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]); - const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); - const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[i]); - const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[i + 4]); - const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j); - const __m128i a2 = _mm_hadd_epi32(a0, a1); - const __m128i b2 = _mm_hadd_epi32(b0, b1); - const __m128i mul = _mm_mullo_epi32(_mm_add_epi32(a2, b2), w); - cost = _mm_add_epi32(mul, cost); - } - return HorizontalSum_SSE41(cost); -} - //------------------------------------------------------------------------------ // Subtract-Green Transform static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data, int num_pixels) { @@ -193,14 +175,18 @@ extern void VP8LEncDspInitSSE41(void); WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE41(void) { VP8LExtraCost = ExtraCost_SSE41; - VP8LExtraCostCombined = ExtraCostCombined_SSE41; VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_SSE41; VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE41; VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE41; + + // SSE exports for AVX and above. + VP8LSubtractGreenFromBlueAndRed_SSE = SubtractGreenFromBlueAndRed_SSE41; + VP8LCollectColorBlueTransforms_SSE = CollectColorBlueTransforms_SSE41; + VP8LCollectColorRedTransforms_SSE = CollectColorRedTransforms_SSE41; } #else // !WEBP_USE_SSE41 WEBP_DSP_INIT_STUB(VP8LEncDspInitSSE41) diff --git a/media/libwebp/src/dsp/lossless_mips_dsp_r2.c b/media/libwebp/src/dsp/lossless_mips_dsp_r2.c --- a/media/libwebp/src/dsp/lossless_mips_dsp_r2.c +++ b/media/libwebp/src/dsp/lossless_mips_dsp_r2.c @@ -297,13 +297,13 @@ static void TransformColorInverse_MIPSdspR2(const VP8LMultipliers* const m, const uint32_t* src, int num_pixels, uint32_t* dst) { int temp0, temp1, temp2, temp3, temp4, temp5; uint32_t argb, argb1, new_red; - const uint32_t G_to_R = m->green_to_red_; - const uint32_t G_to_B = m->green_to_blue_; - const uint32_t R_to_B = m->red_to_blue_; + const uint32_t G_to_R = m->green_to_red; + const uint32_t G_to_B = m->green_to_blue; + const uint32_t R_to_B = m->red_to_blue; const uint32_t* const p_loop_end = src + (num_pixels & ~1); __asm__ volatile ( ".set push \n\t" ".set noreorder \n\t" "beq %[src], %[p_loop_end], 1f \n\t" diff --git a/media/libwebp/src/dsp/lossless_msa.c b/media/libwebp/src/dsp/lossless_msa.c --- a/media/libwebp/src/dsp/lossless_msa.c +++ b/media/libwebp/src/dsp/lossless_msa.c @@ -288,13 +288,13 @@ static void TransformColorInverse_MSA(const VP8LMultipliers* const m, const uint32_t* src, int num_pixels, uint32_t* dst) { v16u8 src0, dst0; - const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue_ | - (m->green_to_red_ << 16)); - const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue_); + const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue | + (m->green_to_red << 16)); + const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue); const v16u8 mask0 = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255 }; const v16u8 mask1 = { 16, 1, 18, 3, 20, 5, 22, 7, 24, 9, 26, 11, 28, 13, 30, 15 }; diff --git a/media/libwebp/src/dsp/lossless_neon.c b/media/libwebp/src/dsp/lossless_neon.c --- a/media/libwebp/src/dsp/lossless_neon.c +++ b/media/libwebp/src/dsp/lossless_neon.c @@ -17,10 +17,11 @@ #include #include "src/dsp/lossless.h" #include "src/dsp/neon.h" +#include "src/webp/format_constants.h" //------------------------------------------------------------------------------ // Colorspace conversion functions #if !defined(WORK_AROUND_GCC) @@ -549,19 +550,19 @@ const uint32_t* const src, int num_pixels, uint32_t* dst) { // sign-extended multiplying constants, pre-shifted by 6. #define CST(X) (((int16_t)(m->X << 8)) >> 6) const int16_t rb[8] = { - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_) + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red) }; const int16x8_t mults_rb = vld1q_s16(rb); const int16_t b2[8] = { - 0, CST(red_to_blue_), 0, CST(red_to_blue_), - 0, CST(red_to_blue_), 0, CST(red_to_blue_), + 0, CST(red_to_blue), 0, CST(red_to_blue), + 0, CST(red_to_blue), 0, CST(red_to_blue), }; const int16x8_t mults_b2 = vld1q_s16(b2); #undef CST #ifdef USE_VTBLQ static const uint8_t kg0g0[16] = { diff --git a/media/libwebp/src/dsp/lossless_sse2.c b/media/libwebp/src/dsp/lossless_sse2.c --- a/media/libwebp/src/dsp/lossless_sse2.c +++ b/media/libwebp/src/dsp/lossless_sse2.c @@ -13,14 +13,19 @@ #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE2) +#include +#include + #include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" -#include +#include "src/webp/format_constants.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Predictor Transform static WEBP_INLINE uint32_t ClampedAddSubtractFull_SSE2(uint32_t c0, @@ -460,12 +465,12 @@ int num_pixels, uint32_t* dst) { // sign-extended multiplying constants, pre-shifted by 5. #define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend #define MK_CST_16(HI, LO) \ _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) - const __m128i mults_rb = MK_CST_16(CST(green_to_red_), CST(green_to_blue_)); - const __m128i mults_b2 = MK_CST_16(CST(red_to_blue_), 0); + const __m128i mults_rb = MK_CST_16(CST(green_to_red), CST(green_to_blue)); + const __m128i mults_b2 = MK_CST_16(CST(red_to_blue), 0); #undef MK_CST_16 #undef CST const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); // alpha-green masks int i; for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -705,10 +710,19 @@ VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE2; VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_SSE2; VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444_SSE2; VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565_SSE2; VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE2; + + // SSE exports for AVX and above. + memcpy(VP8LPredictorsAdd_SSE, VP8LPredictorsAdd, sizeof(VP8LPredictorsAdd)); + + VP8LAddGreenToBlueAndRed_SSE = AddGreenToBlueAndRed_SSE2; + VP8LTransformColorInverse_SSE = TransformColorInverse_SSE2; + + VP8LConvertBGRAToRGB_SSE = ConvertBGRAToRGB_SSE2; + VP8LConvertBGRAToRGBA_SSE = ConvertBGRAToRGBA_SSE2; } #else // !WEBP_USE_SSE2 WEBP_DSP_INIT_STUB(VP8LDspInitSSE2) diff --git a/media/libwebp/src/dsp/lossless_sse41.c b/media/libwebp/src/dsp/lossless_sse41.c --- a/media/libwebp/src/dsp/lossless_sse41.c +++ b/media/libwebp/src/dsp/lossless_sse41.c @@ -10,27 +10,29 @@ // SSE41 variant of methods for lossless decoder #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) +#include +#include -#include "src/dsp/common_sse41.h" +#include "src/webp/types.h" +#include "src/dsp/cpu.h" #include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" //------------------------------------------------------------------------------ // Color-space conversion functions static void TransformColorInverse_SSE41(const VP8LMultipliers* const m, const uint32_t* const src, int num_pixels, uint32_t* dst) { // sign-extended multiplying constants, pre-shifted by 5. #define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend const __m128i mults_rb = - _mm_set1_epi32((int)((uint32_t)CST(green_to_red_) << 16 | - (CST(green_to_blue_) & 0xffff))); - const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue_)); + _mm_set1_epi32((int)((uint32_t)CST(green_to_red) << 16 | + (CST(green_to_blue) & 0xffff))); + const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue)); #undef CST const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); const __m128i perm1 = _mm_setr_epi8(-1, 1, -1, 1, -1, 5, -1, 5, -1, 9, -1, 9, -1, 13, -1, 13); const __m128i perm2 = _mm_setr_epi8(-1, 2, -1, -1, -1, 6, -1, -1, @@ -122,10 +124,14 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE41(void) { VP8LTransformColorInverse = TransformColorInverse_SSE41; VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE41; VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE41; + + // SSE exports for AVX and above. + VP8LTransformColorInverse_SSE = TransformColorInverse_SSE41; + VP8LConvertBGRAToRGB_SSE = ConvertBGRAToRGB_SSE41; } #else // !WEBP_USE_SSE41 WEBP_DSP_INIT_STUB(VP8LDspInitSSE41) diff --git a/media/libwebp/src/dsp/moz.build b/media/libwebp/src/dsp/moz.build --- a/media/libwebp/src/dsp/moz.build +++ b/media/libwebp/src/dsp/moz.build @@ -90,10 +90,12 @@ 'dec_mips32.c', 'dec_mips_dsp_r2.c', 'enc_mips32.c', 'enc_mips_dsp_r2.c', 'filters_mips_dsp_r2.c', + 'lossless_avx2.c', + 'lossless_enc_avx2.c', 'lossless_enc_mips32.c', 'lossless_enc_mips_dsp_r2.c', 'lossless_mips_dsp_r2.c', 'lossless_msa.c', 'rescaler_mips32.c', diff --git a/media/libwebp/src/dsp/rescaler.c b/media/libwebp/src/dsp/rescaler.c --- a/media/libwebp/src/dsp/rescaler.c +++ b/media/libwebp/src/dsp/rescaler.c @@ -10,11 +10,14 @@ // Rescaling functions // // Author: Skal (pascal.massimino@gmail.com) #include +#include +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" #include "src/utils/rescaler_utils.h" //------------------------------------------------------------------------------ // Implementations of critical functions ImportRow / ExportRow diff --git a/media/libwebp/src/dsp/rescaler_sse2.c b/media/libwebp/src/dsp/rescaler_sse2.c --- a/media/libwebp/src/dsp/rescaler_sse2.c +++ b/media/libwebp/src/dsp/rescaler_sse2.c @@ -15,12 +15,16 @@ #if defined(WEBP_USE_SSE2) && !defined(WEBP_REDUCE_SIZE) #include #include +#include + +#include "src/dsp/cpu.h" #include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Implementations of critical functions ImportRow / ExportRow #define ROUNDER (WEBP_RESCALER_ONE >> 1) diff --git a/media/libwebp/src/dsp/ssim.c b/media/libwebp/src/dsp/ssim.c --- a/media/libwebp/src/dsp/ssim.c +++ b/media/libwebp/src/dsp/ssim.c @@ -12,11 +12,13 @@ // Author: Skal (pascal.massimino@gmail.com) #include #include // for abs() +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" +#include "src/webp/types.h" #if !defined(WEBP_REDUCE_SIZE) //------------------------------------------------------------------------------ // SSIM / PSNR diff --git a/media/libwebp/src/dsp/ssim_sse2.c b/media/libwebp/src/dsp/ssim_sse2.c --- a/media/libwebp/src/dsp/ssim_sse2.c +++ b/media/libwebp/src/dsp/ssim_sse2.c @@ -12,15 +12,17 @@ // Author: Skal (pascal.massimino@gmail.com) #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE2) +#include #include -#include #include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #if !defined(WEBP_DISABLE_STATS) // Helper function static WEBP_INLINE void SubtractAndSquare_SSE2(const __m128i a, const __m128i b, diff --git a/media/libwebp/src/dsp/upsampling.c b/media/libwebp/src/dsp/upsampling.c --- a/media/libwebp/src/dsp/upsampling.c +++ b/media/libwebp/src/dsp/upsampling.c @@ -9,14 +9,18 @@ // // YUV to RGB upsampling functions. // // Author: somnath@google.com (Somnath Banerjee) +#include +#include + +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" #include "src/dsp/yuv.h" - -#include +#include "src/webp/decode.h" //------------------------------------------------------------------------------ // Fancy upsampler #ifdef FANCY_UPSAMPLING diff --git a/media/libwebp/src/dsp/upsampling_sse2.c b/media/libwebp/src/dsp/upsampling_sse2.c --- a/media/libwebp/src/dsp/upsampling_sse2.c +++ b/media/libwebp/src/dsp/upsampling_sse2.c @@ -12,15 +12,19 @@ // Author: somnath@google.com (Somnath Banerjee) #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE2) +#include #include -#include #include + +#include "src/webp/types.h" +#include "src/dsp/cpu.h" #include "src/dsp/yuv.h" +#include "src/webp/decode.h" #ifdef FANCY_UPSAMPLING // We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows // u = (9*a + 3*b + 3*c + d + 8) / 16 diff --git a/media/libwebp/src/dsp/upsampling_sse41.c b/media/libwebp/src/dsp/upsampling_sse41.c --- a/media/libwebp/src/dsp/upsampling_sse41.c +++ b/media/libwebp/src/dsp/upsampling_sse41.c @@ -12,15 +12,19 @@ // Author: somnath@google.com (Somnath Banerjee) #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) +#include #include -#include #include + +#include "src/webp/types.h" +#include "src/dsp/cpu.h" #include "src/dsp/yuv.h" +#include "src/webp/decode.h" #ifdef FANCY_UPSAMPLING #if !defined(WEBP_REDUCE_CSP) diff --git a/media/libwebp/src/dsp/yuv.h b/media/libwebp/src/dsp/yuv.h --- a/media/libwebp/src/dsp/yuv.h +++ b/media/libwebp/src/dsp/yuv.h @@ -33,12 +33,14 @@ // Author: Skal (pascal.massimino@gmail.com) #ifndef WEBP_DSP_YUV_H_ #define WEBP_DSP_YUV_H_ +#include "src/dec/vp8_dec.h" +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" -#include "src/dec/vp8_dec.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // YUV -> RGB conversion #ifdef __cplusplus diff --git a/media/libwebp/src/dsp/yuv.c b/media/libwebp/src/dsp/yuv.c --- a/media/libwebp/src/dsp/yuv.c +++ b/media/libwebp/src/dsp/yuv.c @@ -9,15 +9,19 @@ // // YUV->RGB conversion functions // // Author: Skal (pascal.massimino@gmail.com) -#include "src/dsp/yuv.h" - #include #include +#include "src/dsp/cpu.h" +#include "src/webp/types.h" +#include "src/dsp/dsp.h" +#include "src/dsp/yuv.h" +#include "src/webp/decode.h" + //----------------------------------------------------------------------------- // Plain-C version #define ROW_FUNC(FUNC_NAME, FUNC, XSTEP) \ static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ diff --git a/media/libwebp/src/dsp/yuv_neon.c b/media/libwebp/src/dsp/yuv_neon.c --- a/media/libwebp/src/dsp/yuv_neon.c +++ b/media/libwebp/src/dsp/yuv_neon.c @@ -16,10 +16,11 @@ #if defined(WEBP_USE_NEON) #include #include +#include "src/dsp/dsp.h" #include "src/dsp/neon.h" //----------------------------------------------------------------------------- static uint8x8_t ConvertRGBToY_NEON(const uint8x8_t R, diff --git a/media/libwebp/src/dsp/yuv_sse2.c b/media/libwebp/src/dsp/yuv_sse2.c --- a/media/libwebp/src/dsp/yuv_sse2.c +++ b/media/libwebp/src/dsp/yuv_sse2.c @@ -12,16 +12,20 @@ // Author: Skal (pascal.massimino@gmail.com) #include "src/dsp/yuv.h" #if defined(WEBP_USE_SSE2) +#include #include -#include #include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/types.h" //----------------------------------------------------------------------------- // Convert spans of 32 pixels to various RGB formats for the fancy upsampler. // These constants are 14b fixed-point version of ITU-R BT.601 constants. diff --git a/media/libwebp/src/dsp/yuv_sse41.c b/media/libwebp/src/dsp/yuv_sse41.c --- a/media/libwebp/src/dsp/yuv_sse41.c +++ b/media/libwebp/src/dsp/yuv_sse41.c @@ -12,16 +12,21 @@ // Author: Skal (pascal.massimino@gmail.com) #include "src/dsp/yuv.h" #if defined(WEBP_USE_SSE41) +#include +#include #include -#include #include "src/dsp/common_sse41.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/types.h" //----------------------------------------------------------------------------- // Convert spans of 32 pixels to various RGB formats for the fancy upsampler. // These constants are 14b fixed-point version of ITU-R BT.601 constants. diff --git a/media/libwebp/src/enc/alpha_enc.c b/media/libwebp/src/enc/alpha_enc.c --- a/media/libwebp/src/enc/alpha_enc.c +++ b/media/libwebp/src/enc/alpha_enc.c @@ -13,14 +13,17 @@ #include #include #include +#include "src/dsp/dsp.h" +#include "src/webp/types.h" #include "src/enc/vp8i_enc.h" -#include "src/dsp/dsp.h" +#include "src/utils/bit_writer_utils.h" #include "src/utils/filters_utils.h" #include "src/utils/quant_levels_utils.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" #include "src/webp/encode.h" #include "src/webp/format_constants.h" // ----------------------------------------------------------------------------- @@ -84,11 +87,11 @@ (use_quality_100 && effort_level == 6) ? 100 : 8.f * effort_level; assert(config.quality >= 0 && config.quality <= 100.f); ok = VP8LEncodeStream(&config, &picture, bw); WebPPictureFree(&picture); - ok = ok && !bw->error_; + ok = ok && !bw->error; if (!ok) { VP8LBitWriterWipeOut(bw); return 0; } return 1; @@ -136,11 +139,11 @@ ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3); ok = ok && EncodeLossless(alpha_src, width, height, effort_level, !reduce_levels, &tmp_bw, &result->stats); if (ok) { output = VP8LBitWriterFinish(&tmp_bw); - if (tmp_bw.error_) { + if (tmp_bw.error) { VP8LBitWriterWipeOut(&tmp_bw); memset(&result->bw, 0, sizeof(result->bw)); return 0; } output_size = VP8LBitWriterNumBytes(&tmp_bw); @@ -171,11 +174,11 @@ ok = ok && VP8BitWriterAppend(&result->bw, output, output_size); if (method != ALPHA_NO_COMPRESSION) { VP8LBitWriterWipeOut(&tmp_bw); } - ok = ok && !result->bw.error_; + ok = ok && !result->bw.error; result->score = VP8BitWriterSize(&result->bw); return ok; } // ----------------------------------------------------------------------------- @@ -296,11 +299,11 @@ static int EncodeAlpha(VP8Encoder* const enc, int quality, int method, int filter, int effort_level, uint8_t** const output, size_t* const output_size) { - const WebPPicture* const pic = enc->pic_; + const WebPPicture* const pic = enc->pic; const int width = pic->width; const int height = pic->height; uint8_t* quant_alpha = NULL; const size_t data_size = width * height; @@ -355,11 +358,11 @@ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); // imprecise } #if !defined(WEBP_DISABLE_STATS) if (pic->stats != NULL) { // need stats? pic->stats->coded_size += (int)(*output_size); - enc->sse_[3] = sse; + enc->sse[3] = sse; } #endif } WebPSafeFree(quant_alpha); @@ -369,11 +372,11 @@ //------------------------------------------------------------------------------ // Main calls static int CompressAlphaJob(void* arg1, void* unused) { VP8Encoder* const enc = (VP8Encoder*)arg1; - const WebPConfig* config = enc->config_; + const WebPConfig* config = enc->config; uint8_t* alpha_data = NULL; size_t alpha_size = 0; const int effort_level = config->method; // maps to [0..6] const WEBP_FILTER_TYPE filter = (config->alpha_filtering == 0) ? WEBP_FILTER_NONE : @@ -385,37 +388,37 @@ } if (alpha_size != (uint32_t)alpha_size) { // Soundness check. WebPSafeFree(alpha_data); return 0; } - enc->alpha_data_size_ = (uint32_t)alpha_size; - enc->alpha_data_ = alpha_data; + enc->alpha_data_size = (uint32_t)alpha_size; + enc->alpha_data = alpha_data; (void)unused; return 1; } void VP8EncInitAlpha(VP8Encoder* const enc) { WebPInitAlphaProcessing(); - enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_); - enc->alpha_data_ = NULL; - enc->alpha_data_size_ = 0; - if (enc->thread_level_ > 0) { - WebPWorker* const worker = &enc->alpha_worker_; + enc->has_alpha = WebPPictureHasTransparency(enc->pic); + enc->alpha_data = NULL; + enc->alpha_data_size = 0; + if (enc->thread_level > 0) { + WebPWorker* const worker = &enc->alpha_worker; WebPGetWorkerInterface()->Init(worker); worker->data1 = enc; worker->data2 = NULL; worker->hook = CompressAlphaJob; } } int VP8EncStartAlpha(VP8Encoder* const enc) { - if (enc->has_alpha_) { - if (enc->thread_level_ > 0) { - WebPWorker* const worker = &enc->alpha_worker_; + if (enc->has_alpha) { + if (enc->thread_level > 0) { + WebPWorker* const worker = &enc->alpha_worker; // Makes sure worker is good to go. if (!WebPGetWorkerInterface()->Reset(worker)) { - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); } WebPGetWorkerInterface()->Launch(worker); return 1; } else { return CompressAlphaJob(enc, NULL); // just do the job right away @@ -423,29 +426,29 @@ } return 1; } int VP8EncFinishAlpha(VP8Encoder* const enc) { - if (enc->has_alpha_) { - if (enc->thread_level_ > 0) { - WebPWorker* const worker = &enc->alpha_worker_; + if (enc->has_alpha) { + if (enc->thread_level > 0) { + WebPWorker* const worker = &enc->alpha_worker; if (!WebPGetWorkerInterface()->Sync(worker)) return 0; // error } } - return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); + return WebPReportProgress(enc->pic, enc->percent + 20, &enc->percent); } int VP8EncDeleteAlpha(VP8Encoder* const enc) { int ok = 1; - if (enc->thread_level_ > 0) { - WebPWorker* const worker = &enc->alpha_worker_; + if (enc->thread_level > 0) { + WebPWorker* const worker = &enc->alpha_worker; // finish anything left in flight ok = WebPGetWorkerInterface()->Sync(worker); // still need to end the worker, even if !ok WebPGetWorkerInterface()->End(worker); } - WebPSafeFree(enc->alpha_data_); - enc->alpha_data_ = NULL; - enc->alpha_data_size_ = 0; - enc->has_alpha_ = 0; + WebPSafeFree(enc->alpha_data); + enc->alpha_data = NULL; + enc->alpha_data_size = 0; + enc->has_alpha = 0; return ok; } diff --git a/media/libwebp/src/enc/analysis_enc.c b/media/libwebp/src/enc/analysis_enc.c --- a/media/libwebp/src/enc/analysis_enc.c +++ b/media/libwebp/src/enc/analysis_enc.c @@ -9,47 +9,51 @@ // // Macroblock analysis // // Author: Skal (pascal.massimino@gmail.com) +#include #include #include -#include +#include "src/dec/common_dec.h" +#include "src/dsp/dsp.h" #include "src/enc/vp8i_enc.h" -#include "src/enc/cost_enc.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" +#include "src/webp/encode.h" +#include "src/webp/types.h" #define MAX_ITERS_K_MEANS 6 //------------------------------------------------------------------------------ // Smooth the segment map by replacing isolated block by the majority of its // neighbours. static void SmoothSegmentMap(VP8Encoder* const enc) { int n, x, y; - const int w = enc->mb_w_; - const int h = enc->mb_h_; + const int w = enc->mb_w; + const int h = enc->mb_h; const int majority_cnt_3_x_3_grid = 5; uint8_t* const tmp = (uint8_t*)WebPSafeMalloc(w * h, sizeof(*tmp)); assert((uint64_t)(w * h) == (uint64_t)w * h); // no overflow, as per spec if (tmp == NULL) return; for (y = 1; y < h - 1; ++y) { for (x = 1; x < w - 1; ++x) { int cnt[NUM_MB_SEGMENTS] = { 0 }; - const VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; - int majority_seg = mb->segment_; + const VP8MBInfo* const mb = &enc->mb_info[x + w * y]; + int majority_seg = mb->segment; // Check the 8 neighbouring segment values. - cnt[mb[-w - 1].segment_]++; // top-left - cnt[mb[-w + 0].segment_]++; // top - cnt[mb[-w + 1].segment_]++; // top-right - cnt[mb[ - 1].segment_]++; // left - cnt[mb[ + 1].segment_]++; // right - cnt[mb[ w - 1].segment_]++; // bottom-left - cnt[mb[ w + 0].segment_]++; // bottom - cnt[mb[ w + 1].segment_]++; // bottom-right + cnt[mb[-w - 1].segment]++; // top-left + cnt[mb[-w + 0].segment]++; // top + cnt[mb[-w + 1].segment]++; // top-right + cnt[mb[ - 1].segment]++; // left + cnt[mb[ + 1].segment]++; // right + cnt[mb[ w - 1].segment]++; // bottom-left + cnt[mb[ w + 0].segment]++; // bottom + cnt[mb[ w + 1].segment]++; // bottom-right for (n = 0; n < NUM_MB_SEGMENTS; ++n) { if (cnt[n] >= majority_cnt_3_x_3_grid) { majority_seg = n; break; } @@ -57,28 +61,28 @@ tmp[x + y * w] = majority_seg; } } for (y = 1; y < h - 1; ++y) { for (x = 1; x < w - 1; ++x) { - VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; - mb->segment_ = tmp[x + y * w]; + VP8MBInfo* const mb = &enc->mb_info[x + w * y]; + mb->segment = tmp[x + y * w]; } } WebPSafeFree(tmp); } //------------------------------------------------------------------------------ -// set segment susceptibility alpha_ / beta_ +// set segment susceptibility 'alpha' / 'beta' static WEBP_INLINE int clip(int v, int m, int M) { return (v < m) ? m : (v > M) ? M : v; } static void SetSegmentAlphas(VP8Encoder* const enc, const int centers[NUM_MB_SEGMENTS], int mid) { - const int nb = enc->segment_hdr_.num_segments_; + const int nb = enc->segment_hdr.num_segments; int min = centers[0], max = centers[0]; int n; if (nb > 1) { for (n = 0; n < nb; ++n) { @@ -89,12 +93,12 @@ if (max == min) max = min + 1; assert(mid <= max && mid >= min); for (n = 0; n < nb; ++n) { const int alpha = 255 * (centers[n] - mid) / (max - min); const int beta = 255 * (centers[n] - min) / (max - min); - enc->dqm_[n].alpha_ = clip(alpha, -127, 127); - enc->dqm_[n].beta_ = clip(beta, 0, 255); + enc->dqm[n].alpha = clip(alpha, -127, 127); + enc->dqm[n].beta = clip(beta, 0, 255); } } //------------------------------------------------------------------------------ // Compute susceptibility based on DCT-coeff histograms: @@ -129,15 +133,15 @@ //------------------------------------------------------------------------------ // Simplified k-Means, to assign Nb segments based on alpha-histogram static void AssignSegments(VP8Encoder* const enc, const int alphas[MAX_ALPHA + 1]) { - // 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an + // 'num_segments' is previously validated and <= NUM_MB_SEGMENTS, but an // explicit check is needed to avoid spurious warning about 'n + 1' exceeding // array bounds of 'centers' with some compilers (noticed with gcc-4.9). - const int nb = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) ? - enc->segment_hdr_.num_segments_ : NUM_MB_SEGMENTS; + const int nb = (enc->segment_hdr.num_segments < NUM_MB_SEGMENTS) ? + enc->segment_hdr.num_segments : NUM_MB_SEGMENTS; int centers[NUM_MB_SEGMENTS]; int weighted_average = 0; int map[MAX_ALPHA + 1]; int a, n, k; int min_a = 0, max_a = MAX_ALPHA, range_a; @@ -198,19 +202,19 @@ weighted_average = (weighted_average + total_weight / 2) / total_weight; if (displaced < 5) break; // no need to keep on looping... } // Map each original value to the closest centroid - for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { - VP8MBInfo* const mb = &enc->mb_info_[n]; - const int alpha = mb->alpha_; - mb->segment_ = map[alpha]; - mb->alpha_ = centers[map[alpha]]; // for the record. + for (n = 0; n < enc->mb_w * enc->mb_h; ++n) { + VP8MBInfo* const mb = &enc->mb_info[n]; + const int alpha = mb->alpha; + mb->segment = map[alpha]; + mb->alpha = centers[map[alpha]]; // for the record. } if (nb > 1) { - const int smooth = (enc->config_->preprocessing & 1); + const int smooth = (enc->config->preprocessing & 1); if (smooth) SmoothSegmentMap(enc); } SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas. } @@ -218,11 +222,11 @@ //------------------------------------------------------------------------------ // Macroblock analysis: collect histogram for each mode, deduce the maximal // susceptibility and set best modes for this macroblock. // Segment assignment is done later. -// Number of modes to inspect for alpha_ evaluation. We don't need to test all +// Number of modes to inspect for 'alpha' evaluation. We don't need to test all // the possible modes during the analysis phase: we risk falling into a local // optimum, or be subject to boundary effect #define MAX_INTRA16_MODE 2 #define MAX_INTRA4_MODE 2 #define MAX_UV_MODE 2 @@ -237,12 +241,12 @@ for (mode = 0; mode < max_mode; ++mode) { VP8Histogram histo; int alpha; InitHistogram(&histo); - VP8CollectHistogram(it->yuv_in_ + Y_OFF_ENC, - it->yuv_p_ + VP8I16ModeOffsets[mode], + VP8CollectHistogram(it->yuv_in + Y_OFF_ENC, + it->yuv_p + VP8I16ModeOffsets[mode], 0, 16, &histo); alpha = GetAlpha(&histo); if (IS_BETTER_ALPHA(alpha, best_alpha)) { best_alpha = alpha; best_mode = mode; @@ -253,16 +257,16 @@ } static int FastMBAnalyze(VP8EncIterator* const it) { // Empirical cut-off value, should be around 16 (~=block size). We use the // [8-17] range and favor intra4 at high quality, intra16 for low quality. - const int q = (int)it->enc_->config_->quality; + const int q = (int)it->enc->config->quality; const uint32_t kThreshold = 8 + (17 - 8) * q / 100; int k; uint32_t dc[16], m, m2; for (k = 0; k < 16; k += 4) { - VP8Mean16x4(it->yuv_in_ + Y_OFF_ENC + k * BPS, &dc[k]); + VP8Mean16x4(it->yuv_in + Y_OFF_ENC + k * BPS, &dc[k]); } for (m = 0, m2 = 0, k = 0; k < 16; ++k) { m += dc[k]; m2 += dc[k] * dc[k]; } @@ -285,12 +289,12 @@ VP8MakeChroma8Preds(it); for (mode = 0; mode < max_mode; ++mode) { VP8Histogram histo; int alpha; InitHistogram(&histo); - VP8CollectHistogram(it->yuv_in_ + U_OFF_ENC, - it->yuv_p_ + VP8UVModeOffsets[mode], + VP8CollectHistogram(it->yuv_in + U_OFF_ENC, + it->yuv_p + VP8UVModeOffsets[mode], 16, 16 + 4 + 4, &histo); alpha = GetAlpha(&histo); if (IS_BETTER_ALPHA(alpha, best_alpha)) { best_alpha = alpha; } @@ -305,41 +309,41 @@ } static void MBAnalyze(VP8EncIterator* const it, int alphas[MAX_ALPHA + 1], int* const alpha, int* const uv_alpha) { - const VP8Encoder* const enc = it->enc_; + const VP8Encoder* const enc = it->enc; int best_alpha, best_uv_alpha; VP8SetIntra16Mode(it, 0); // default: Intra16, DC_PRED VP8SetSkip(it, 0); // not skipped VP8SetSegment(it, 0); // default segment, spec-wise. - if (enc->method_ <= 1) { + if (enc->method <= 1) { best_alpha = FastMBAnalyze(it); } else { best_alpha = MBAnalyzeBestIntra16Mode(it); } best_uv_alpha = MBAnalyzeBestUVMode(it); // Final susceptibility mix best_alpha = (3 * best_alpha + best_uv_alpha + 2) >> 2; best_alpha = FinalAlphaValue(best_alpha); alphas[best_alpha]++; - it->mb_->alpha_ = best_alpha; // for later remapping. + it->mb->alpha = best_alpha; // for later remapping. // Accumulate for later complexity analysis. *alpha += best_alpha; // mixed susceptibility (not just luma) *uv_alpha += best_uv_alpha; } static void DefaultMBInfo(VP8MBInfo* const mb) { - mb->type_ = 1; // I16x16 - mb->uv_mode_ = 0; - mb->skip_ = 0; // not skipped - mb->segment_ = 0; // default segment - mb->alpha_ = 0; + mb->type = 1; // I16x16 + mb->uv_mode = 0; + mb->skip = 0; // not skipped + mb->segment = 0; // default segment + mb->alpha = 0; } //------------------------------------------------------------------------------ // Main analysis loop: // Collect all susceptibilities for each macroblock and record their @@ -350,20 +354,20 @@ // and decide intra4/intra16, but that's usually almost always a bad choice at // this stage. static void ResetAllMBInfo(VP8Encoder* const enc) { int n; - for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { - DefaultMBInfo(&enc->mb_info_[n]); + for (n = 0; n < enc->mb_w * enc->mb_h; ++n) { + DefaultMBInfo(&enc->mb_info[n]); } // Default susceptibilities. - enc->dqm_[0].alpha_ = 0; - enc->dqm_[0].beta_ = 0; - // Note: we can't compute this alpha_ / uv_alpha_ -> set to default value. - enc->alpha_ = 0; - enc->uv_alpha_ = 0; - WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); + enc->dqm[0].alpha = 0; + enc->dqm[0].beta = 0; + // Note: we can't compute this 'alpha' / 'uv_alpha' -> set to default value. + enc->alpha = 0; + enc->uv_alpha = 0; + WebPReportProgress(enc->pic, enc->percent + 20, &enc->percent); } // struct used to collect job result typedef struct { WebPWorker worker; @@ -407,11 +411,11 @@ job->worker.data1 = job; job->worker.data2 = &job->it; job->worker.hook = DoSegmentsJob; VP8IteratorInit(enc, &job->it); VP8IteratorSetRow(&job->it, start_row); - VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_); + VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w); memset(job->alphas, 0, sizeof(job->alphas)); job->alpha = 0; job->uv_alpha = 0; // only one of both jobs can record the progress, since we don't // expect the user's hook to be multi-thread safe @@ -420,21 +424,21 @@ // main entry point int VP8EncAnalyze(VP8Encoder* const enc) { int ok = 1; const int do_segments = - enc->config_->emulate_jpeg_size || // We need the complexity evaluation. - (enc->segment_hdr_.num_segments_ > 1) || - (enc->method_ <= 1); // for method 0 - 1, we need preds_[] to be filled. + enc->config->emulate_jpeg_size || // We need the complexity evaluation. + (enc->segment_hdr.num_segments > 1) || + (enc->method <= 1); // for method 0 - 1, we need preds[] to be filled. if (do_segments) { - const int last_row = enc->mb_h_; - const int total_mb = last_row * enc->mb_w_; + const int last_row = enc->mb_h; + const int total_mb = last_row * enc->mb_w; #ifdef WEBP_USE_THREAD // We give a little more than a half work to the main thread. const int split_row = (9 * last_row + 15) >> 4; const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it - const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow); + const int do_mt = (enc->thread_level > 0) && (split_row >= kMinSplitRow); #else const int do_mt = 0; #endif const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface(); @@ -465,19 +469,18 @@ worker_interface->Execute(&main_job.worker); ok &= worker_interface->Sync(&main_job.worker); } worker_interface->End(&main_job.worker); if (ok) { - enc->alpha_ = main_job.alpha / total_mb; - enc->uv_alpha_ = main_job.uv_alpha / total_mb; + enc->alpha = main_job.alpha / total_mb; + enc->uv_alpha = main_job.uv_alpha / total_mb; AssignSegments(enc, main_job.alphas); } } else { // Use only one default segment. ResetAllMBInfo(enc); } if (!ok) { - return WebPEncodingSetError(enc->pic_, + return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); // imprecise } return ok; } - diff --git a/media/libwebp/src/enc/backward_references_cost_enc.c b/media/libwebp/src/enc/backward_references_cost_enc.c --- a/media/libwebp/src/enc/backward_references_cost_enc.c +++ b/media/libwebp/src/enc/backward_references_cost_enc.c @@ -20,24 +20,26 @@ #include "src/dsp/lossless_common.h" #include "src/enc/backward_references_enc.h" #include "src/enc/histogram_enc.h" #include "src/utils/color_cache_utils.h" #include "src/utils/utils.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" #define VALUES_IN_BYTE 256 extern void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs); extern int VP8LDistanceToPlaneCode(int xsize, int dist); extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, const PixOrCopy v); typedef struct { - uint32_t alpha_[VALUES_IN_BYTE]; - uint32_t red_[VALUES_IN_BYTE]; - uint32_t blue_[VALUES_IN_BYTE]; - uint32_t distance_[NUM_DISTANCE_CODES]; - uint32_t* literal_; + uint32_t alpha[VALUES_IN_BYTE]; + uint32_t red[VALUES_IN_BYTE]; + uint32_t blue[VALUES_IN_BYTE]; + uint32_t distance[NUM_DISTANCE_CODES]; + uint32_t* literal; } CostModel; static void ConvertPopulationCountTableToBitEstimates( int num_symbols, const uint32_t population_counts[], uint32_t output[]) { uint32_t sum = 0; @@ -60,66 +62,61 @@ } static int CostModelBuild(CostModel* const m, int xsize, int cache_bits, const VP8LBackwardRefs* const refs) { int ok = 0; - VP8LRefsCursor c = VP8LRefsCursorInit(refs); VP8LHistogram* const histo = VP8LAllocateHistogram(cache_bits); if (histo == NULL) goto Error; // The following code is similar to VP8LHistogramCreate but converts the // distance to plane code. VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 1); - while (VP8LRefsCursorOk(&c)) { - VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode, - xsize); - VP8LRefsCursorNext(&c); - } + VP8LHistogramStoreRefs(refs, VP8LDistanceToPlaneCode, xsize, histo); ConvertPopulationCountTableToBitEstimates( - VP8LHistogramNumCodes(histo->palette_code_bits_), histo->literal_, - m->literal_); + VP8LHistogramNumCodes(histo->palette_code_bits), histo->literal, + m->literal); ConvertPopulationCountTableToBitEstimates( - VALUES_IN_BYTE, histo->red_, m->red_); + VALUES_IN_BYTE, histo->red, m->red); ConvertPopulationCountTableToBitEstimates( - VALUES_IN_BYTE, histo->blue_, m->blue_); + VALUES_IN_BYTE, histo->blue, m->blue); ConvertPopulationCountTableToBitEstimates( - VALUES_IN_BYTE, histo->alpha_, m->alpha_); + VALUES_IN_BYTE, histo->alpha, m->alpha); ConvertPopulationCountTableToBitEstimates( - NUM_DISTANCE_CODES, histo->distance_, m->distance_); + NUM_DISTANCE_CODES, histo->distance, m->distance); ok = 1; Error: VP8LFreeHistogram(histo); return ok; } static WEBP_INLINE int64_t GetLiteralCost(const CostModel* const m, uint32_t v) { - return (int64_t)m->alpha_[v >> 24] + m->red_[(v >> 16) & 0xff] + - m->literal_[(v >> 8) & 0xff] + m->blue_[v & 0xff]; + return (int64_t)m->alpha[v >> 24] + m->red[(v >> 16) & 0xff] + + m->literal[(v >> 8) & 0xff] + m->blue[v & 0xff]; } static WEBP_INLINE int64_t GetCacheCost(const CostModel* const m, uint32_t idx) { const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx; - return (int64_t)m->literal_[literal_idx]; + return (int64_t)m->literal[literal_idx]; } static WEBP_INLINE int64_t GetLengthCost(const CostModel* const m, uint32_t length) { int code, extra_bits; VP8LPrefixEncodeBits(length, &code, &extra_bits); - return (int64_t)m->literal_[VALUES_IN_BYTE + code] + + return (int64_t)m->literal[VALUES_IN_BYTE + code] + ((int64_t)extra_bits << LOG_2_PRECISION_BITS); } static WEBP_INLINE int64_t GetDistanceCost(const CostModel* const m, uint32_t distance) { int code, extra_bits; VP8LPrefixEncodeBits(distance, &code, &extra_bits); - return (int64_t)m->distance_[code] + + return (int64_t)m->distance[code] + ((int64_t)extra_bits << LOG_2_PRECISION_BITS); } static WEBP_INLINE void AddSingleLiteralWithCostModel( const uint32_t* const argb, VP8LColorCache* const hashers, @@ -145,184 +142,184 @@ // CostManager and interval handling // Empirical value to avoid high memory consumption but good for performance. #define COST_CACHE_INTERVAL_SIZE_MAX 500 -// To perform backward reference every pixel at index index_ is considered and +// To perform backward reference every pixel at index 'index' is considered and // the cost for the MAX_LENGTH following pixels computed. Those following pixels -// at index index_ + k (k from 0 to MAX_LENGTH) have a cost of: -// cost_ = distance cost at index + GetLengthCost(cost_model, k) +// at index 'index' + k (k from 0 to MAX_LENGTH) have a cost of: +// cost = distance cost at index + GetLengthCost(cost_model, k) // and the minimum value is kept. GetLengthCost(cost_model, k) is cached in an // array of size MAX_LENGTH. // Instead of performing MAX_LENGTH comparisons per pixel, we keep track of the // minimal values using intervals of constant cost. -// An interval is defined by the index_ of the pixel that generated it and -// is only useful in a range of indices from start_ to end_ (exclusive), i.e. -// it contains the minimum value for pixels between start_ and end_. -// Intervals are stored in a linked list and ordered by start_. When a new +// An interval is defined by the 'index' of the pixel that generated it and +// is only useful in a range of indices from 'start' to 'end' (exclusive), i.e. +// it contains the minimum value for pixels between start and end. +// Intervals are stored in a linked list and ordered by 'start'. When a new // interval has a better value, old intervals are split or removed. There are // therefore no overlapping intervals. typedef struct CostInterval CostInterval; struct CostInterval { - int64_t cost_; - int start_; - int end_; - int index_; - CostInterval* previous_; - CostInterval* next_; + int64_t cost; + int start; + int end; + int index; + CostInterval* previous; + CostInterval* next; }; // The GetLengthCost(cost_model, k) are cached in a CostCacheInterval. typedef struct { - int64_t cost_; - int start_; - int end_; // Exclusive. + int64_t cost; + int start; + int end; // Exclusive. } CostCacheInterval; // This structure is in charge of managing intervals and costs. // It caches the different CostCacheInterval, caches the different -// GetLengthCost(cost_model, k) in cost_cache_ and the CostInterval's (whose -// count_ is limited by COST_CACHE_INTERVAL_SIZE_MAX). +// GetLengthCost(cost_model, k) in cost_cache and the CostInterval's (whose +// 'count' is limited by COST_CACHE_INTERVAL_SIZE_MAX). #define COST_MANAGER_MAX_FREE_LIST 10 typedef struct { - CostInterval* head_; - int count_; // The number of stored intervals. - CostCacheInterval* cache_intervals_; - size_t cache_intervals_size_; + CostInterval* head; + int count; // The number of stored intervals. + CostCacheInterval* cache_intervals; + size_t cache_intervals_size; // Contains the GetLengthCost(cost_model, k). - int64_t cost_cache_[MAX_LENGTH]; - int64_t* costs_; - uint16_t* dist_array_; + int64_t cost_cache[MAX_LENGTH]; + int64_t* costs; + uint16_t* dist_array; // Most of the time, we only need few intervals -> use a free-list, to avoid // fragmentation with small allocs in most common cases. - CostInterval intervals_[COST_MANAGER_MAX_FREE_LIST]; - CostInterval* free_intervals_; + CostInterval intervals[COST_MANAGER_MAX_FREE_LIST]; + CostInterval* free_intervals; // These are regularly malloc'd remains. This list can't grow larger than than // size COST_CACHE_INTERVAL_SIZE_MAX - COST_MANAGER_MAX_FREE_LIST, note. - CostInterval* recycled_intervals_; + CostInterval* recycled_intervals; } CostManager; static void CostIntervalAddToFreeList(CostManager* const manager, CostInterval* const interval) { - interval->next_ = manager->free_intervals_; - manager->free_intervals_ = interval; + interval->next = manager->free_intervals; + manager->free_intervals = interval; } static int CostIntervalIsInFreeList(const CostManager* const manager, const CostInterval* const interval) { - return (interval >= &manager->intervals_[0] && - interval <= &manager->intervals_[COST_MANAGER_MAX_FREE_LIST - 1]); + return (interval >= &manager->intervals[0] && + interval <= &manager->intervals[COST_MANAGER_MAX_FREE_LIST - 1]); } static void CostManagerInitFreeList(CostManager* const manager) { int i; - manager->free_intervals_ = NULL; + manager->free_intervals = NULL; for (i = 0; i < COST_MANAGER_MAX_FREE_LIST; ++i) { - CostIntervalAddToFreeList(manager, &manager->intervals_[i]); + CostIntervalAddToFreeList(manager, &manager->intervals[i]); } } static void DeleteIntervalList(CostManager* const manager, const CostInterval* interval) { while (interval != NULL) { - const CostInterval* const next = interval->next_; + const CostInterval* const next = interval->next; if (!CostIntervalIsInFreeList(manager, interval)) { WebPSafeFree((void*)interval); } // else: do nothing interval = next; } } static void CostManagerClear(CostManager* const manager) { if (manager == NULL) return; - WebPSafeFree(manager->costs_); - WebPSafeFree(manager->cache_intervals_); + WebPSafeFree(manager->costs); + WebPSafeFree(manager->cache_intervals); // Clear the interval lists. - DeleteIntervalList(manager, manager->head_); - manager->head_ = NULL; - DeleteIntervalList(manager, manager->recycled_intervals_); - manager->recycled_intervals_ = NULL; + DeleteIntervalList(manager, manager->head); + manager->head = NULL; + DeleteIntervalList(manager, manager->recycled_intervals); + manager->recycled_intervals = NULL; - // Reset pointers, count_ and cache_intervals_size_. + // Reset pointers, 'count' and 'cache_intervals_size'. memset(manager, 0, sizeof(*manager)); CostManagerInitFreeList(manager); } static int CostManagerInit(CostManager* const manager, uint16_t* const dist_array, int pix_count, const CostModel* const cost_model) { int i; const int cost_cache_size = (pix_count > MAX_LENGTH) ? MAX_LENGTH : pix_count; - manager->costs_ = NULL; - manager->cache_intervals_ = NULL; - manager->head_ = NULL; - manager->recycled_intervals_ = NULL; - manager->count_ = 0; - manager->dist_array_ = dist_array; + manager->costs = NULL; + manager->cache_intervals = NULL; + manager->head = NULL; + manager->recycled_intervals = NULL; + manager->count = 0; + manager->dist_array = dist_array; CostManagerInitFreeList(manager); - // Fill in the cost_cache_. + // Fill in the 'cost_cache'. // Has to be done in two passes due to a GCC bug on i686 // related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for (i = 0; i < cost_cache_size; ++i) { - manager->cost_cache_[i] = GetLengthCost(cost_model, i); + manager->cost_cache[i] = GetLengthCost(cost_model, i); } - manager->cache_intervals_size_ = 1; + manager->cache_intervals_size = 1; for (i = 1; i < cost_cache_size; ++i) { // Get the number of bound intervals. - if (manager->cost_cache_[i] != manager->cost_cache_[i - 1]) { - ++manager->cache_intervals_size_; + if (manager->cost_cache[i] != manager->cost_cache[i - 1]) { + ++manager->cache_intervals_size; } } // With the current cost model, we usually have below 20 intervals. // The worst case scenario with a cost model would be if every length has a // different cost, hence MAX_LENGTH but that is impossible with the current // implementation that spirals around a pixel. - assert(manager->cache_intervals_size_ <= MAX_LENGTH); - manager->cache_intervals_ = (CostCacheInterval*)WebPSafeMalloc( - manager->cache_intervals_size_, sizeof(*manager->cache_intervals_)); - if (manager->cache_intervals_ == NULL) { + assert(manager->cache_intervals_size <= MAX_LENGTH); + manager->cache_intervals = (CostCacheInterval*)WebPSafeMalloc( + manager->cache_intervals_size, sizeof(*manager->cache_intervals)); + if (manager->cache_intervals == NULL) { CostManagerClear(manager); return 0; } - // Fill in the cache_intervals_. + // Fill in the 'cache_intervals'. { - CostCacheInterval* cur = manager->cache_intervals_; + CostCacheInterval* cur = manager->cache_intervals; - // Consecutive values in cost_cache_ are compared and if a big enough + // Consecutive values in 'cost_cache' are compared and if a big enough // difference is found, a new interval is created and bounded. - cur->start_ = 0; - cur->end_ = 1; - cur->cost_ = manager->cost_cache_[0]; + cur->start = 0; + cur->end = 1; + cur->cost = manager->cost_cache[0]; for (i = 1; i < cost_cache_size; ++i) { - const int64_t cost_val = manager->cost_cache_[i]; - if (cost_val != cur->cost_) { + const int64_t cost_val = manager->cost_cache[i]; + if (cost_val != cur->cost) { ++cur; // Initialize an interval. - cur->start_ = i; - cur->cost_ = cost_val; + cur->start = i; + cur->cost = cost_val; } - cur->end_ = i + 1; + cur->end = i + 1; } - assert((size_t)(cur - manager->cache_intervals_) + 1 == - manager->cache_intervals_size_); + assert((size_t)(cur - manager->cache_intervals) + 1 == + manager->cache_intervals_size); } - manager->costs_ = - (int64_t*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_)); - if (manager->costs_ == NULL) { + manager->costs = + (int64_t*)WebPSafeMalloc(pix_count, sizeof(*manager->costs)); + if (manager->costs == NULL) { CostManagerClear(manager); return 0; } - // Set the initial costs_ to INT64_MAX for every pixel as we will keep the + // Set the initial 'costs' to INT64_MAX for every pixel as we will keep the // minimum. - for (i = 0; i < pix_count; ++i) manager->costs_[i] = WEBP_INT64_MAX; + for (i = 0; i < pix_count; ++i) manager->costs[i] = WEBP_INT64_MAX; return 1; } // Given the cost and the position that define an interval, update the cost at @@ -330,13 +327,13 @@ static WEBP_INLINE void UpdateCost(CostManager* const manager, int i, int position, int64_t cost) { const int k = i - position; assert(k >= 0 && k < MAX_LENGTH); - if (manager->costs_[i] > cost) { - manager->costs_[i] = cost; - manager->dist_array_[i] = k + 1; + if (manager->costs[i] > cost) { + manager->costs[i] = cost; + manager->dist_array[i] = k + 1; } } // Given the cost and the position that define an interval, update the cost for // all the pixels between 'start' and 'end' excluded. @@ -350,219 +347,219 @@ // Given two intervals, make 'prev' be the previous one of 'next' in 'manager'. static WEBP_INLINE void ConnectIntervals(CostManager* const manager, CostInterval* const prev, CostInterval* const next) { if (prev != NULL) { - prev->next_ = next; + prev->next = next; } else { - manager->head_ = next; + manager->head = next; } - if (next != NULL) next->previous_ = prev; + if (next != NULL) next->previous = prev; } // Pop an interval in the manager. static WEBP_INLINE void PopInterval(CostManager* const manager, CostInterval* const interval) { if (interval == NULL) return; - ConnectIntervals(manager, interval->previous_, interval->next_); + ConnectIntervals(manager, interval->previous, interval->next); if (CostIntervalIsInFreeList(manager, interval)) { CostIntervalAddToFreeList(manager, interval); } else { // recycle regularly malloc'd intervals too - interval->next_ = manager->recycled_intervals_; - manager->recycled_intervals_ = interval; + interval->next = manager->recycled_intervals; + manager->recycled_intervals = interval; } - --manager->count_; - assert(manager->count_ >= 0); + --manager->count; + assert(manager->count >= 0); } // Update the cost at index i by going over all the stored intervals that // overlap with i. // If 'do_clean_intervals' is set to something different than 0, intervals that // end before 'i' will be popped. static WEBP_INLINE void UpdateCostAtIndex(CostManager* const manager, int i, int do_clean_intervals) { - CostInterval* current = manager->head_; + CostInterval* current = manager->head; - while (current != NULL && current->start_ <= i) { - CostInterval* const next = current->next_; - if (current->end_ <= i) { + while (current != NULL && current->start <= i) { + CostInterval* const next = current->next; + if (current->end <= i) { if (do_clean_intervals) { // We have an outdated interval, remove it. PopInterval(manager, current); } } else { - UpdateCost(manager, i, current->index_, current->cost_); + UpdateCost(manager, i, current->index, current->cost); } current = next; } } // Given a current orphan interval and its previous interval, before // it was orphaned (which can be NULL), set it at the right place in the list -// of intervals using the start_ ordering and the previous interval as a hint. +// of intervals using the 'start' ordering and the previous interval as a hint. static WEBP_INLINE void PositionOrphanInterval(CostManager* const manager, CostInterval* const current, CostInterval* previous) { assert(current != NULL); - if (previous == NULL) previous = manager->head_; - while (previous != NULL && current->start_ < previous->start_) { - previous = previous->previous_; + if (previous == NULL) previous = manager->head; + while (previous != NULL && current->start < previous->start) { + previous = previous->previous; } - while (previous != NULL && previous->next_ != NULL && - previous->next_->start_ < current->start_) { - previous = previous->next_; + while (previous != NULL && previous->next != NULL && + previous->next->start < current->start) { + previous = previous->next; } if (previous != NULL) { - ConnectIntervals(manager, current, previous->next_); + ConnectIntervals(manager, current, previous->next); } else { - ConnectIntervals(manager, current, manager->head_); + ConnectIntervals(manager, current, manager->head); } ConnectIntervals(manager, previous, current); } // Insert an interval in the list contained in the manager by starting at -// interval_in as a hint. The intervals are sorted by start_ value. +// 'interval_in' as a hint. The intervals are sorted by 'start' value. static WEBP_INLINE void InsertInterval(CostManager* const manager, CostInterval* const interval_in, int64_t cost, int position, int start, int end) { CostInterval* interval_new; if (start >= end) return; - if (manager->count_ >= COST_CACHE_INTERVAL_SIZE_MAX) { + if (manager->count >= COST_CACHE_INTERVAL_SIZE_MAX) { // Serialize the interval if we cannot store it. UpdateCostPerInterval(manager, start, end, position, cost); return; } - if (manager->free_intervals_ != NULL) { - interval_new = manager->free_intervals_; - manager->free_intervals_ = interval_new->next_; - } else if (manager->recycled_intervals_ != NULL) { - interval_new = manager->recycled_intervals_; - manager->recycled_intervals_ = interval_new->next_; + if (manager->free_intervals != NULL) { + interval_new = manager->free_intervals; + manager->free_intervals = interval_new->next; + } else if (manager->recycled_intervals != NULL) { + interval_new = manager->recycled_intervals; + manager->recycled_intervals = interval_new->next; } else { // malloc for good interval_new = (CostInterval*)WebPSafeMalloc(1, sizeof(*interval_new)); if (interval_new == NULL) { // Write down the interval if we cannot create it. UpdateCostPerInterval(manager, start, end, position, cost); return; } } - interval_new->cost_ = cost; - interval_new->index_ = position; - interval_new->start_ = start; - interval_new->end_ = end; + interval_new->cost = cost; + interval_new->index = position; + interval_new->start = start; + interval_new->end = end; PositionOrphanInterval(manager, interval_new, interval_in); - ++manager->count_; + ++manager->count; } // Given a new cost interval defined by its start at position, its length value // and distance_cost, add its contributions to the previous intervals and costs. // If handling the interval or one of its subintervals becomes to heavy, its // contribution is added to the costs right away. static WEBP_INLINE void PushInterval(CostManager* const manager, int64_t distance_cost, int position, int len) { size_t i; - CostInterval* interval = manager->head_; + CostInterval* interval = manager->head; CostInterval* interval_next; const CostCacheInterval* const cost_cache_intervals = - manager->cache_intervals_; + manager->cache_intervals; // If the interval is small enough, no need to deal with the heavy // interval logic, just serialize it right away. This constant is empirical. const int kSkipDistance = 10; if (len < kSkipDistance) { int j; for (j = position; j < position + len; ++j) { const int k = j - position; int64_t cost_tmp; assert(k >= 0 && k < MAX_LENGTH); - cost_tmp = distance_cost + manager->cost_cache_[k]; + cost_tmp = distance_cost + manager->cost_cache[k]; - if (manager->costs_[j] > cost_tmp) { - manager->costs_[j] = cost_tmp; - manager->dist_array_[j] = k + 1; + if (manager->costs[j] > cost_tmp) { + manager->costs[j] = cost_tmp; + manager->dist_array[j] = k + 1; } } return; } - for (i = 0; i < manager->cache_intervals_size_ && - cost_cache_intervals[i].start_ < len; + for (i = 0; i < manager->cache_intervals_size && + cost_cache_intervals[i].start < len; ++i) { // Define the intersection of the ith interval with the new one. - int start = position + cost_cache_intervals[i].start_; - const int end = position + (cost_cache_intervals[i].end_ > len + int start = position + cost_cache_intervals[i].start; + const int end = position + (cost_cache_intervals[i].end > len ? len - : cost_cache_intervals[i].end_); - const int64_t cost = distance_cost + cost_cache_intervals[i].cost_; + : cost_cache_intervals[i].end); + const int64_t cost = distance_cost + cost_cache_intervals[i].cost; - for (; interval != NULL && interval->start_ < end; + for (; interval != NULL && interval->start < end; interval = interval_next) { - interval_next = interval->next_; + interval_next = interval->next; // Make sure we have some overlap - if (start >= interval->end_) continue; + if (start >= interval->end) continue; - if (cost >= interval->cost_) { + if (cost >= interval->cost) { // When intervals are represented, the lower, the better. // [**********************************************************[ // start end // [----------------------------------[ - // interval->start_ interval->end_ + // interval->start interval->end // If we are worse than what we already have, add whatever we have so // far up to interval. - const int start_new = interval->end_; + const int start_new = interval->end; InsertInterval(manager, interval, cost, position, start, - interval->start_); + interval->start); start = start_new; if (start >= end) break; continue; } - if (start <= interval->start_) { - if (interval->end_ <= end) { + if (start <= interval->start) { + if (interval->end <= end) { // [----------------------------------[ - // interval->start_ interval->end_ + // interval->start interval->end // [**************************************************************[ // start end // We can safely remove the old interval as it is fully included. PopInterval(manager, interval); } else { // [------------------------------------[ - // interval->start_ interval->end_ + // interval->start interval->end // [*****************************[ // start end - interval->start_ = end; + interval->start = end; break; } } else { - if (end < interval->end_) { + if (end < interval->end) { // [--------------------------------------------------------------[ - // interval->start_ interval->end_ + // interval->start interval->end // [*****************************[ // start end // We have to split the old interval as it fully contains the new one. - const int end_original = interval->end_; - interval->end_ = start; - InsertInterval(manager, interval, interval->cost_, interval->index_, + const int end_original = interval->end; + interval->end = start; + InsertInterval(manager, interval, interval->cost, interval->index, end, end_original); - interval = interval->next_; + interval = interval->next; break; } else { // [------------------------------------[ - // interval->start_ interval->end_ + // interval->start interval->end // [*****************************[ // start end - interval->end_ = start; + interval->end = start; } } } // Insert the remaining interval from start to end. InsertInterval(manager, interval, cost, position, start, end); @@ -577,11 +574,11 @@ int ok = 0; int cc_init = 0; const int pix_count = xsize * ysize; const int use_color_cache = (cache_bits > 0); const size_t literal_array_size = - sizeof(*((CostModel*)NULL)->literal_) * VP8LHistogramNumCodes(cache_bits); + sizeof(*((CostModel*)NULL)->literal) * VP8LHistogramNumCodes(cache_bits); const size_t cost_model_size = sizeof(CostModel) + literal_array_size; CostModel* const cost_model = (CostModel*)WebPSafeCalloc(1ULL, cost_model_size); VP8LColorCache hashers; CostManager* cost_manager = @@ -591,11 +588,11 @@ int first_offset_is_constant = -1; // initialized with 'impossible' value int reach = 0; if (cost_model == NULL || cost_manager == NULL) goto Error; - cost_model->literal_ = (uint32_t*)(cost_model + 1); + cost_model->literal = (uint32_t*)(cost_model + 1); if (use_color_cache) { cc_init = VP8LColorCacheInit(&hashers, cache_bits); if (!cc_init) goto Error; } @@ -611,21 +608,21 @@ // non-processed locations from this point. dist_array[0] = 0; // Add first pixel as literal. AddSingleLiteralWithCostModel(argb, &hashers, cost_model, /*idx=*/0, use_color_cache, /*prev_cost=*/0, - cost_manager->costs_, dist_array); + cost_manager->costs, dist_array); for (i = 1; i < pix_count; ++i) { - const int64_t prev_cost = cost_manager->costs_[i - 1]; + const int64_t prev_cost = cost_manager->costs[i - 1]; int offset, len; VP8LHashChainFindCopy(hash_chain, i, &offset, &len); // Try adding the pixel as a literal. AddSingleLiteralWithCostModel(argb, &hashers, cost_model, i, use_color_cache, prev_cost, - cost_manager->costs_, dist_array); + cost_manager->costs, dist_array); // If we are dealing with a non-literal. if (len >= 2) { if (offset != offset_prev) { const int code = VP8LDistanceToPlaneCode(xsize, offset); @@ -669,11 +666,11 @@ } // Update the cost at j - 1 and j. UpdateCostAtIndex(cost_manager, j - 1, 0); UpdateCostAtIndex(cost_manager, j, 0); - PushInterval(cost_manager, cost_manager->costs_[j - 1] + offset_cost, + PushInterval(cost_manager, cost_manager->costs[j - 1] + offset_cost, j, len_j); reach = j + len_j - 1; } } } @@ -681,11 +678,11 @@ UpdateCostAtIndex(cost_manager, i, 1); offset_prev = offset; len_prev = len; } - ok = !refs->error_; + ok = !refs->error; Error: if (cc_init) VP8LColorCacheClear(&hashers); CostManagerClear(cost_manager); WebPSafeFree(cost_model); WebPSafeFree(cost_manager); @@ -754,11 +751,11 @@ } VP8LBackwardRefsCursorAdd(refs, v); ++i; } } - ok = !refs->error_; + ok = !refs->error; Error: if (cc_init) VP8LColorCacheClear(&hashers); return ok; } diff --git a/media/libwebp/src/enc/backward_references_enc.h b/media/libwebp/src/enc/backward_references_enc.h --- a/media/libwebp/src/enc/backward_references_enc.h +++ b/media/libwebp/src/enc/backward_references_enc.h @@ -13,13 +13,14 @@ #ifndef WEBP_ENC_BACKWARD_REFERENCES_ENC_H_ #define WEBP_ENC_BACKWARD_REFERENCES_ENC_H_ #include #include -#include "src/webp/types.h" + #include "src/webp/encode.h" #include "src/webp/format_constants.h" +#include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif @@ -124,14 +125,14 @@ // The 20 most significant bits contain the offset at which the best match // is found. These 20 bits are the limit defined by GetWindowSizeForHashChain // (through WINDOW_SIZE = 1<<20). // The lower 12 bits contain the length of the match. The 12 bit limit is // defined in MaxFindCopyLength with MAX_LENGTH=4096. - uint32_t* offset_length_; + uint32_t* offset_length; // This is the maximum size of the hash_chain that can be constructed. // Typically this is the pixel count (width x height) for a given image. - int size_; + int size; }; // Must be called first, to set size. int VP8LHashChainInit(VP8LHashChain* const p, int size); // Pre-compute the best matches for argb. pic and percent are for progress. @@ -141,16 +142,16 @@ int percent_range, int* const percent); void VP8LHashChainClear(VP8LHashChain* const p); // release memory static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p, const int base_position) { - return p->offset_length_[base_position] >> MAX_LENGTH_BITS; + return p->offset_length[base_position] >> MAX_LENGTH_BITS; } static WEBP_INLINE int VP8LHashChainFindLength(const VP8LHashChain* const p, const int base_position) { - return p->offset_length_[base_position] & ((1U << MAX_LENGTH_BITS) - 1); + return p->offset_length[base_position] & ((1U << MAX_LENGTH_BITS) - 1); } static WEBP_INLINE void VP8LHashChainFindCopy(const VP8LHashChain* const p, int base_position, int* const offset_ptr, @@ -168,16 +169,16 @@ typedef struct PixOrCopyBlock PixOrCopyBlock; // forward declaration typedef struct VP8LBackwardRefs VP8LBackwardRefs; // Container for blocks chain struct VP8LBackwardRefs { - int block_size_; // common block-size - int error_; // set to true if some memory error occurred - PixOrCopyBlock* refs_; // list of currently used blocks - PixOrCopyBlock** tail_; // for list recycling - PixOrCopyBlock* free_blocks_; // free-list - PixOrCopyBlock* last_block_; // used for adding new refs (internal) + int block_size; // common block-size + int error; // set to true if some memory error occurred + PixOrCopyBlock* refs; // list of currently used blocks + PixOrCopyBlock** tail; // for list recycling + PixOrCopyBlock* free_blocks; // free-list + PixOrCopyBlock* last_block; // used for adding new refs (internal) }; // Initialize the object. 'block_size' is the common block size to store // references (typically, width * height / MAX_REFS_BLOCK_PER_IMAGE). void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size); @@ -187,12 +188,12 @@ // Cursor for iterating on references content typedef struct { // public: PixOrCopy* cur_pos; // current position // private: - PixOrCopyBlock* cur_block_; // current block in the refs list - const PixOrCopy* last_pos_; // sentinel for switching to next block + PixOrCopyBlock* cur_block; // current block in the refs list + const PixOrCopy* last_pos; // sentinel for switching to next block } VP8LRefsCursor; // Returns a cursor positioned at the beginning of the references list. VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs); // Returns true if cursor is pointing at a valid position. @@ -203,11 +204,11 @@ void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c); // Move to next position, or NULL. Should not be called if !VP8LRefsCursorOk(). static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) { assert(c != NULL); assert(VP8LRefsCursorOk(c)); - if (++c->cur_pos == c->last_pos_) VP8LRefsCursorNextBlock(c); + if (++c->cur_pos == c->last_pos) VP8LRefsCursorNextBlock(c); } // ----------------------------------------------------------------------------- // Main entry points diff --git a/media/libwebp/src/enc/backward_references_enc.c b/media/libwebp/src/enc/backward_references_enc.c --- a/media/libwebp/src/enc/backward_references_enc.c +++ b/media/libwebp/src/enc/backward_references_enc.c @@ -11,19 +11,22 @@ // #include "src/enc/backward_references_enc.h" #include +#include -#include "src/dsp/dsp.h" +#include "src/dsp/cpu.h" #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" #include "src/enc/histogram_enc.h" #include "src/enc/vp8i_enc.h" #include "src/utils/color_cache_utils.h" #include "src/utils/utils.h" #include "src/webp/encode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" #define MIN_BLOCK_SIZE 256 // minimum block size for backward references // 1M window (4M bytes) minus 120 special codes for short distances. #define WINDOW_SIZE ((1 << WINDOW_SIZE_BITS) - 120) @@ -74,151 +77,151 @@ // ----------------------------------------------------------------------------- // VP8LBackwardRefs struct PixOrCopyBlock { - PixOrCopyBlock* next_; // next block (or NULL) - PixOrCopy* start_; // data start - int size_; // currently used size + PixOrCopyBlock* next; // next block (or NULL) + PixOrCopy* start; // data start + int size; // currently used size }; extern void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs); void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) { assert(refs != NULL); - if (refs->tail_ != NULL) { - *refs->tail_ = refs->free_blocks_; // recycle all blocks at once + if (refs->tail != NULL) { + *refs->tail = refs->free_blocks; // recycle all blocks at once } - refs->free_blocks_ = refs->refs_; - refs->tail_ = &refs->refs_; - refs->last_block_ = NULL; - refs->refs_ = NULL; + refs->free_blocks = refs->refs; + refs->tail = &refs->refs; + refs->last_block = NULL; + refs->refs = NULL; } void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) { assert(refs != NULL); VP8LClearBackwardRefs(refs); - while (refs->free_blocks_ != NULL) { - PixOrCopyBlock* const next = refs->free_blocks_->next_; - WebPSafeFree(refs->free_blocks_); - refs->free_blocks_ = next; + while (refs->free_blocks != NULL) { + PixOrCopyBlock* const next = refs->free_blocks->next; + WebPSafeFree(refs->free_blocks); + refs->free_blocks = next; } } // Swaps the content of two VP8LBackwardRefs. static void BackwardRefsSwap(VP8LBackwardRefs* const refs1, VP8LBackwardRefs* const refs2) { const int point_to_refs1 = - (refs1->tail_ != NULL && refs1->tail_ == &refs1->refs_); + (refs1->tail != NULL && refs1->tail == &refs1->refs); const int point_to_refs2 = - (refs2->tail_ != NULL && refs2->tail_ == &refs2->refs_); + (refs2->tail != NULL && refs2->tail == &refs2->refs); const VP8LBackwardRefs tmp = *refs1; *refs1 = *refs2; *refs2 = tmp; - if (point_to_refs2) refs1->tail_ = &refs1->refs_; - if (point_to_refs1) refs2->tail_ = &refs2->refs_; + if (point_to_refs2) refs1->tail = &refs1->refs; + if (point_to_refs1) refs2->tail = &refs2->refs; } void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size) { assert(refs != NULL); memset(refs, 0, sizeof(*refs)); - refs->tail_ = &refs->refs_; - refs->block_size_ = + refs->tail = &refs->refs; + refs->block_size = (block_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : block_size; } VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs) { VP8LRefsCursor c; - c.cur_block_ = refs->refs_; - if (refs->refs_ != NULL) { - c.cur_pos = c.cur_block_->start_; - c.last_pos_ = c.cur_pos + c.cur_block_->size_; + c.cur_block = refs->refs; + if (refs->refs != NULL) { + c.cur_pos = c.cur_block->start; + c.last_pos = c.cur_pos + c.cur_block->size; } else { c.cur_pos = NULL; - c.last_pos_ = NULL; + c.last_pos = NULL; } return c; } void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c) { - PixOrCopyBlock* const b = c->cur_block_->next_; - c->cur_pos = (b == NULL) ? NULL : b->start_; - c->last_pos_ = (b == NULL) ? NULL : b->start_ + b->size_; - c->cur_block_ = b; + PixOrCopyBlock* const b = c->cur_block->next; + c->cur_pos = (b == NULL) ? NULL : b->start; + c->last_pos = (b == NULL) ? NULL : b->start + b->size; + c->cur_block = b; } // Create a new block, either from the free list or allocated static PixOrCopyBlock* BackwardRefsNewBlock(VP8LBackwardRefs* const refs) { - PixOrCopyBlock* b = refs->free_blocks_; + PixOrCopyBlock* b = refs->free_blocks; if (b == NULL) { // allocate new memory chunk const size_t total_size = - sizeof(*b) + refs->block_size_ * sizeof(*b->start_); + sizeof(*b) + refs->block_size * sizeof(*b->start); b = (PixOrCopyBlock*)WebPSafeMalloc(1ULL, total_size); if (b == NULL) { - refs->error_ |= 1; + refs->error |= 1; return NULL; } - b->start_ = (PixOrCopy*)((uint8_t*)b + sizeof(*b)); // not always aligned + b->start = (PixOrCopy*)((uint8_t*)b + sizeof(*b)); // not always aligned } else { // recycle from free-list - refs->free_blocks_ = b->next_; + refs->free_blocks = b->next; } - *refs->tail_ = b; - refs->tail_ = &b->next_; - refs->last_block_ = b; - b->next_ = NULL; - b->size_ = 0; + *refs->tail = b; + refs->tail = &b->next; + refs->last_block = b; + b->next = NULL; + b->size = 0; return b; } // Return 1 on success, 0 on error. static int BackwardRefsClone(const VP8LBackwardRefs* const from, VP8LBackwardRefs* const to) { - const PixOrCopyBlock* block_from = from->refs_; + const PixOrCopyBlock* block_from = from->refs; VP8LClearBackwardRefs(to); while (block_from != NULL) { PixOrCopyBlock* const block_to = BackwardRefsNewBlock(to); if (block_to == NULL) return 0; - memcpy(block_to->start_, block_from->start_, - block_from->size_ * sizeof(PixOrCopy)); - block_to->size_ = block_from->size_; - block_from = block_from->next_; + memcpy(block_to->start, block_from->start, + block_from->size * sizeof(PixOrCopy)); + block_to->size = block_from->size; + block_from = block_from->next; } return 1; } extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, const PixOrCopy v); void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, const PixOrCopy v) { - PixOrCopyBlock* b = refs->last_block_; - if (b == NULL || b->size_ == refs->block_size_) { + PixOrCopyBlock* b = refs->last_block; + if (b == NULL || b->size == refs->block_size) { b = BackwardRefsNewBlock(refs); - if (b == NULL) return; // refs->error_ is set + if (b == NULL) return; // refs->error is set } - b->start_[b->size_++] = v; + b->start[b->size++] = v; } // ----------------------------------------------------------------------------- // Hash chains int VP8LHashChainInit(VP8LHashChain* const p, int size) { - assert(p->size_ == 0); - assert(p->offset_length_ == NULL); + assert(p->size == 0); + assert(p->offset_length == NULL); assert(size > 0); - p->offset_length_ = - (uint32_t*)WebPSafeMalloc(size, sizeof(*p->offset_length_)); - if (p->offset_length_ == NULL) return 0; - p->size_ = size; + p->offset_length = + (uint32_t*)WebPSafeMalloc(size, sizeof(*p->offset_length)); + if (p->offset_length == NULL) return 0; + p->size = size; return 1; } void VP8LHashChainClear(VP8LHashChain* const p) { assert(p != NULL); - WebPSafeFree(p->offset_length_); + WebPSafeFree(p->offset_length); - p->size_ = 0; - p->offset_length_ = NULL; + p->size = 0; + p->offset_length = NULL; } // ----------------------------------------------------------------------------- static const uint32_t kHashMultiplierHi = 0xc6a4a793u; @@ -263,18 +266,18 @@ int percent_start = *percent; int pos; int argb_comp; uint32_t base_position; int32_t* hash_to_first_index; - // Temporarily use the p->offset_length_ as a hash chain. - int32_t* chain = (int32_t*)p->offset_length_; + // Temporarily use the p->offset_length as a hash chain. + int32_t* chain = (int32_t*)p->offset_length; assert(size > 0); - assert(p->size_ != 0); - assert(p->offset_length_ != NULL); + assert(p->size != 0); + assert(p->offset_length != NULL); if (size <= 2) { - p->offset_length_[0] = p->offset_length_[size - 1] = 0; + p->offset_length[0] = p->offset_length[size - 1] = 0; return 1; } hash_to_first_index = (int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index)); @@ -349,11 +352,11 @@ // Find the best match interval at each pixel, defined by an offset to the // pixel and a length. The right-most pixel cannot match anything to the right // (hence a best length of 0) and the left-most pixel nothing to the left // (hence an offset of 0). assert(size > 2); - p->offset_length_[0] = p->offset_length_[size - 1] = 0; + p->offset_length[0] = p->offset_length[size - 1] = 0; for (base_position = size - 2; base_position > 0;) { const int max_len = MaxFindCopyLength(size - 1 - base_position); const uint32_t* const argb_start = argb + base_position; int iter = iter_max; int best_length = 0; @@ -409,11 +412,11 @@ // to the left, we have the best matches for the left-extended pixels. max_base_position = base_position; while (1) { assert(best_length <= MAX_LENGTH); assert(best_distance <= WINDOW_SIZE); - p->offset_length_[base_position] = + p->offset_length[base_position] = (best_distance << MAX_LENGTH_BITS) | (uint32_t)best_length; --base_position; // Stop if we don't have a match or if we are out of bounds. if (best_distance == 0 || base_position == 0) break; // Stop if we cannot extend the matching intervals to the left. @@ -503,11 +506,11 @@ AddSingleLiteral(argb[i], use_color_cache, &hashers, refs); i++; } } if (use_color_cache) VP8LColorCacheClear(&hashers); - return !refs->error_; + return !refs->error; } static int BackwardReferencesLz77(int xsize, int ysize, const uint32_t* const argb, int cache_bits, const VP8LHashChain* const hash_chain, @@ -568,11 +571,11 @@ } } i += len; } - ok = !refs->error_; + ok = !refs->error; Error: if (cc_init) VP8LColorCacheClear(&hashers); return ok; } @@ -643,11 +646,11 @@ ++window_offsets_new_size; } } } - hash_chain->offset_length_[0] = 0; + hash_chain->offset_length[0] = 0; for (i = 1; i < pix_count; ++i) { int ind; int best_length = VP8LHashChainFindLength(hash_chain_best, i); int best_offset; int do_compute = 1; @@ -710,21 +713,21 @@ } assert(i + best_length <= pix_count); assert(best_length <= MAX_LENGTH); if (best_length <= MIN_LENGTH) { - hash_chain->offset_length_[i] = 0; + hash_chain->offset_length[i] = 0; best_offset_prev = 0; best_length_prev = 0; } else { - hash_chain->offset_length_[i] = + hash_chain->offset_length[i] = (best_offset << MAX_LENGTH_BITS) | (uint32_t)best_length; best_offset_prev = best_offset; best_length_prev = best_length; } } - hash_chain->offset_length_[0] = 0; + hash_chain->offset_length[0] = 0; WebPSafeFree(counts_ini); return BackwardReferencesLz77(xsize, ysize, argb, cache_bits, hash_chain, refs); } @@ -791,46 +794,46 @@ const uint32_t g = (pix >> 8) & 0xff; const uint32_t b = (pix >> 0) & 0xff; // The keys of the caches can be derived from the longest one. int key = VP8LHashPix(pix, 32 - cache_bits_max); // Do not use the color cache for cache_bits = 0. - ++histos[0]->blue_[b]; - ++histos[0]->literal_[g]; - ++histos[0]->red_[r]; - ++histos[0]->alpha_[a]; + ++histos[0]->blue[b]; + ++histos[0]->literal[g]; + ++histos[0]->red[r]; + ++histos[0]->alpha[a]; // Deal with cache_bits > 0. for (i = cache_bits_max; i >= 1; --i, key >>= 1) { if (VP8LColorCacheLookup(&hashers[i], key) == pix) { - ++histos[i]->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key]; + ++histos[i]->literal[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key]; } else { VP8LColorCacheSet(&hashers[i], key, pix); - ++histos[i]->blue_[b]; - ++histos[i]->literal_[g]; - ++histos[i]->red_[r]; - ++histos[i]->alpha_[a]; + ++histos[i]->blue[b]; + ++histos[i]->literal[g]; + ++histos[i]->red[r]; + ++histos[i]->alpha[a]; } } } else { int code, extra_bits, extra_bits_value; // We should compute the contribution of the (distance,length) // histograms but those are the same independently from the cache size. // As those constant contributions are in the end added to the other // histogram contributions, we can ignore them, except for the length - // prefix that is part of the literal_ histogram. + // prefix that is part of the 'literal' histogram. int len = PixOrCopyLength(v); uint32_t argb_prev = *argb ^ 0xffffffffu; VP8LPrefixEncode(len, &code, &extra_bits, &extra_bits_value); for (i = 0; i <= cache_bits_max; ++i) { - ++histos[i]->literal_[NUM_LITERAL_CODES + code]; + ++histos[i]->literal[NUM_LITERAL_CODES + code]; } // Update the color caches. do { if (*argb != argb_prev) { // Efficiency: insert only if the color changes. int key = VP8LHashPix(*argb, 32 - cache_bits_max); for (i = cache_bits_max; i >= 1; --i, key >>= 1) { - hashers[i].colors_[key] = *argb; + hashers[i].colors[key] = *argb; } argb_prev = *argb; } argb++; } while (--len != 0); diff --git a/media/libwebp/src/enc/config_enc.c b/media/libwebp/src/enc/config_enc.c --- a/media/libwebp/src/enc/config_enc.c +++ b/media/libwebp/src/enc/config_enc.c @@ -13,11 +13,14 @@ #ifdef HAVE_CONFIG_H #include "src/webp/config.h" #endif +#include + #include "src/webp/encode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // WebPConfig //------------------------------------------------------------------------------ @@ -133,21 +136,21 @@ #define MAX_LEVEL 9 // Mapping between -z level and -m / -q parameter settings. static const struct { - uint8_t method_; - uint8_t quality_; + uint8_t method; + uint8_t quality; } kLosslessPresets[MAX_LEVEL + 1] = { { 0, 0 }, { 1, 20 }, { 2, 25 }, { 3, 30 }, { 3, 50 }, { 4, 50 }, { 4, 75 }, { 4, 90 }, { 5, 90 }, { 6, 100 } }; int WebPConfigLosslessPreset(WebPConfig* config, int level) { if (config == NULL || level < 0 || level > MAX_LEVEL) return 0; config->lossless = 1; - config->method = kLosslessPresets[level].method_; - config->quality = kLosslessPresets[level].quality_; + config->method = kLosslessPresets[level].method; + config->quality = kLosslessPresets[level].quality; return 1; } //------------------------------------------------------------------------------ diff --git a/media/libwebp/src/enc/cost_enc.h b/media/libwebp/src/enc/cost_enc.h --- a/media/libwebp/src/enc/cost_enc.h +++ b/media/libwebp/src/enc/cost_enc.h @@ -14,11 +14,15 @@ #ifndef WEBP_ENC_COST_ENC_H_ #define WEBP_ENC_COST_ENC_H_ #include #include + +#include "src/dec/common_dec.h" +#include "src/dsp/dsp.h" #include "src/enc/vp8i_enc.h" +#include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif diff --git a/media/libwebp/src/enc/cost_enc.c b/media/libwebp/src/enc/cost_enc.c --- a/media/libwebp/src/enc/cost_enc.c +++ b/media/libwebp/src/enc/cost_enc.c @@ -9,11 +9,17 @@ // // Cost tables for level and modes // // Author: Skal (pascal.massimino@gmail.com) +#include + +#include "src/dec/common_dec.h" +#include "src/webp/types.h" +#include "src/dsp/dsp.h" #include "src/enc/cost_enc.h" +#include "src/enc/vp8i_enc.h" //------------------------------------------------------------------------------ // Level cost tables // For each given level, the following table gives the pattern of contexts to @@ -58,18 +64,18 @@ // Pre-calc level costs once for all void VP8CalculateLevelCosts(VP8EncProba* const proba) { int ctype, band, ctx; - if (!proba->dirty_) return; // nothing to do. + if (!proba->dirty) return; // nothing to do. for (ctype = 0; ctype < NUM_TYPES; ++ctype) { int n; for (band = 0; band < NUM_BANDS; ++band) { for (ctx = 0; ctx < NUM_CTX; ++ctx) { - const uint8_t* const p = proba->coeffs_[ctype][band][ctx]; - uint16_t* const table = proba->level_cost_[ctype][band][ctx]; + const uint8_t* const p = proba->coeffs[ctype][band][ctx]; + uint16_t* const table = proba->level_cost[ctype][band][ctx]; const int cost0 = (ctx > 0) ? VP8BitCost(1, p[0]) : 0; const int cost_base = VP8BitCost(1, p[1]) + cost0; int v; table[0] = VP8BitCost(0, p[1]) + cost0; for (v = 1; v <= MAX_VARIABLE_LEVEL; ++v) { @@ -79,16 +85,16 @@ // actually constant. } } for (n = 0; n < 16; ++n) { // replicate bands. We don't need to sentinel. for (ctx = 0; ctx < NUM_CTX; ++ctx) { - proba->remapped_costs_[ctype][n][ctx] = - proba->level_cost_[ctype][VP8EncBands[n]][ctx]; + proba->remapped_costs[ctype][n][ctx] = + proba->level_cost[ctype][VP8EncBands[n]][ctx]; } } } - proba->dirty_ = 0; + proba->dirty = 0; } //------------------------------------------------------------------------------ // Mode cost tables. @@ -204,75 +210,75 @@ // helper functions for residuals struct VP8Residual. void VP8InitResidual(int first, int coeff_type, VP8Encoder* const enc, VP8Residual* const res) { res->coeff_type = coeff_type; - res->prob = enc->proba_.coeffs_[coeff_type]; - res->stats = enc->proba_.stats_[coeff_type]; - res->costs = enc->proba_.remapped_costs_[coeff_type]; + res->prob = enc->proba.coeffs[coeff_type]; + res->stats = enc->proba.stats[coeff_type]; + res->costs = enc->proba.remapped_costs[coeff_type]; res->first = first; } //------------------------------------------------------------------------------ // Mode costs int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) { - const int x = (it->i4_ & 3), y = (it->i4_ >> 2); + const int x = (it->i4 & 3), y = (it->i4 >> 2); VP8Residual res; - VP8Encoder* const enc = it->enc_; + VP8Encoder* const enc = it->enc; int R = 0; int ctx; VP8InitResidual(0, 3, enc, &res); - ctx = it->top_nz_[x] + it->left_nz_[y]; + ctx = it->top_nz[x] + it->left_nz[y]; VP8SetResidualCoeffs(levels, &res); R += VP8GetResidualCost(ctx, &res); return R; } int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) { VP8Residual res; - VP8Encoder* const enc = it->enc_; + VP8Encoder* const enc = it->enc; int x, y; int R = 0; VP8IteratorNzToBytes(it); // re-import the non-zero context // DC VP8InitResidual(0, 1, enc, &res); VP8SetResidualCoeffs(rd->y_dc_levels, &res); - R += VP8GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res); + R += VP8GetResidualCost(it->top_nz[8] + it->left_nz[8], &res); // AC VP8InitResidual(1, 0, enc, &res); for (y = 0; y < 4; ++y) { for (x = 0; x < 4; ++x) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; + const int ctx = it->top_nz[x] + it->left_nz[y]; VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); R += VP8GetResidualCost(ctx, &res); - it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0); + it->top_nz[x] = it->left_nz[y] = (res.last >= 0); } } return R; } int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) { VP8Residual res; - VP8Encoder* const enc = it->enc_; + VP8Encoder* const enc = it->enc; int ch, x, y; int R = 0; VP8IteratorNzToBytes(it); // re-import the non-zero context VP8InitResidual(0, 2, enc, &res); for (ch = 0; ch <= 2; ch += 2) { for (y = 0; y < 2; ++y) { for (x = 0; x < 2; ++x) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + const int ctx = it->top_nz[4 + ch + x] + it->left_nz[4 + ch + y]; VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); R += VP8GetResidualCost(ctx, &res); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0); + it->top_nz[4 + ch + x] = it->left_nz[4 + ch + y] = (res.last >= 0); } } } return R; } diff --git a/media/libwebp/src/enc/filter_enc.c b/media/libwebp/src/enc/filter_enc.c --- a/media/libwebp/src/enc/filter_enc.c +++ b/media/libwebp/src/enc/filter_enc.c @@ -10,12 +10,17 @@ // Selecting filter level // // Author: somnath@google.com (Somnath Banerjee) #include +#include +#include + +#include "src/dec/common_dec.h" +#include "src/webp/types.h" +#include "src/dsp/dsp.h" #include "src/enc/vp8i_enc.h" -#include "src/dsp/dsp.h" // This table gives, for a given sharpness, the filtering strength to be // used (at least) in order to filter a given edge step delta. // This is constructed by brute force inspection: for all delta, we iterate // over all possible filtering strength / thresh until needs_filter() returns @@ -81,22 +86,22 @@ if (level < 1) level = 1; return level; } static void DoFilter(const VP8EncIterator* const it, int level) { - const VP8Encoder* const enc = it->enc_; - const int ilevel = GetILevel(enc->config_->filter_sharpness, level); + const VP8Encoder* const enc = it->enc; + const int ilevel = GetILevel(enc->config->filter_sharpness, level); const int limit = 2 * level + ilevel; - uint8_t* const y_dst = it->yuv_out2_ + Y_OFF_ENC; - uint8_t* const u_dst = it->yuv_out2_ + U_OFF_ENC; - uint8_t* const v_dst = it->yuv_out2_ + V_OFF_ENC; + uint8_t* const y_dst = it->yuv_out2 + Y_OFF_ENC; + uint8_t* const u_dst = it->yuv_out2 + U_OFF_ENC; + uint8_t* const v_dst = it->yuv_out2 + V_OFF_ENC; - // copy current block to yuv_out2_ - memcpy(y_dst, it->yuv_out_, YUV_SIZE_ENC * sizeof(uint8_t)); + // copy current block to yuv_out2 + memcpy(y_dst, it->yuv_out, YUV_SIZE_ENC * sizeof(uint8_t)); - if (enc->filter_hdr_.simple_ == 1) { // simple + if (enc->filter_hdr.simple == 1) { // simple VP8SimpleHFilter16i(y_dst, BPS, limit); VP8SimpleVFilter16i(y_dst, BPS, limit); } else { // complex const int hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; VP8HFilter16i(y_dst, BPS, limit, ilevel, hev_thresh); @@ -137,15 +142,15 @@ // Exposed APIs: Encoder should call the following 3 functions to adjust // loop filter strength void VP8InitFilter(VP8EncIterator* const it) { #if !defined(WEBP_REDUCE_SIZE) - if (it->lf_stats_ != NULL) { + if (it->lf_stats != NULL) { int s, i; for (s = 0; s < NUM_MB_SEGMENTS; s++) { for (i = 0; i < MAX_LF_LEVELS; i++) { - (*it->lf_stats_)[s][i] = 0; + (*it->lf_stats)[s][i] = 0; } } VP8SSIMDspInit(); } #else @@ -154,82 +159,82 @@ } void VP8StoreFilterStats(VP8EncIterator* const it) { #if !defined(WEBP_REDUCE_SIZE) int d; - VP8Encoder* const enc = it->enc_; - const int s = it->mb_->segment_; - const int level0 = enc->dqm_[s].fstrength_; + VP8Encoder* const enc = it->enc; + const int s = it->mb->segment; + const int level0 = enc->dqm[s].fstrength; // explore +/-quant range of values around level0 - const int delta_min = -enc->dqm_[s].quant_; - const int delta_max = enc->dqm_[s].quant_; + const int delta_min = -enc->dqm[s].quant; + const int delta_max = enc->dqm[s].quant; const int step_size = (delta_max - delta_min >= 4) ? 4 : 1; - if (it->lf_stats_ == NULL) return; + if (it->lf_stats == NULL) return; // NOTE: Currently we are applying filter only across the sublock edges // There are two reasons for that. // 1. Applying filter on macro block edges will change the pixels in // the left and top macro blocks. That will be hard to restore // 2. Macro Blocks on the bottom and right are not yet compressed. So we // cannot apply filter on the right and bottom macro block edges. - if (it->mb_->type_ == 1 && it->mb_->skip_) return; + if (it->mb->type == 1 && it->mb->skip) return; // Always try filter level zero - (*it->lf_stats_)[s][0] += GetMBSSIM(it->yuv_in_, it->yuv_out_); + (*it->lf_stats)[s][0] += GetMBSSIM(it->yuv_in, it->yuv_out); for (d = delta_min; d <= delta_max; d += step_size) { const int level = level0 + d; if (level <= 0 || level >= MAX_LF_LEVELS) { continue; } DoFilter(it, level); - (*it->lf_stats_)[s][level] += GetMBSSIM(it->yuv_in_, it->yuv_out2_); + (*it->lf_stats)[s][level] += GetMBSSIM(it->yuv_in, it->yuv_out2); } #else // defined(WEBP_REDUCE_SIZE) (void)it; #endif // !defined(WEBP_REDUCE_SIZE) } void VP8AdjustFilterStrength(VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; + VP8Encoder* const enc = it->enc; #if !defined(WEBP_REDUCE_SIZE) - if (it->lf_stats_ != NULL) { + if (it->lf_stats != NULL) { int s; for (s = 0; s < NUM_MB_SEGMENTS; s++) { int i, best_level = 0; // Improvement over filter level 0 should be at least 1e-5 (relatively) - double best_v = 1.00001 * (*it->lf_stats_)[s][0]; + double best_v = 1.00001 * (*it->lf_stats)[s][0]; for (i = 1; i < MAX_LF_LEVELS; i++) { - const double v = (*it->lf_stats_)[s][i]; + const double v = (*it->lf_stats)[s][i]; if (v > best_v) { best_v = v; best_level = i; } } - enc->dqm_[s].fstrength_ = best_level; + enc->dqm[s].fstrength = best_level; } return; } #endif // !defined(WEBP_REDUCE_SIZE) - if (enc->config_->filter_strength > 0) { + if (enc->config->filter_strength > 0) { int max_level = 0; int s; for (s = 0; s < NUM_MB_SEGMENTS; s++) { - VP8SegmentInfo* const dqm = &enc->dqm_[s]; + VP8SegmentInfo* const dqm = &enc->dqm[s]; // this '>> 3' accounts for some inverse WHT scaling - const int delta = (dqm->max_edge_ * dqm->y2_.q_[1]) >> 3; + const int delta = (dqm->max_edge * dqm->y2.q[1]) >> 3; const int level = - VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, delta); - if (level > dqm->fstrength_) { - dqm->fstrength_ = level; + VP8FilterStrengthFromDelta(enc->filter_hdr.sharpness, delta); + if (level > dqm->fstrength) { + dqm->fstrength = level; } - if (max_level < dqm->fstrength_) { - max_level = dqm->fstrength_; + if (max_level < dqm->fstrength) { + max_level = dqm->fstrength; } } - enc->filter_hdr_.level_ = max_level; + enc->filter_hdr.level = max_level; } } // ----------------------------------------------------------------------------- diff --git a/media/libwebp/src/enc/frame_enc.c b/media/libwebp/src/enc/frame_enc.c --- a/media/libwebp/src/enc/frame_enc.c +++ b/media/libwebp/src/enc/frame_enc.c @@ -9,16 +9,21 @@ // // frame coding and analysis // // Author: Skal (pascal.massimino@gmail.com) -#include +#include #include +#include +#include "src/dec/common_dec.h" +#include "src/webp/types.h" +#include "src/dsp/dsp.h" #include "src/enc/cost_enc.h" #include "src/enc/vp8i_enc.h" -#include "src/dsp/dsp.h" +#include "src/utils/bit_writer_utils.h" +#include "src/webp/encode.h" #include "src/webp/format_constants.h" // RIFF constants #define SEGMENT_VISU 0 #define DEBUG_SEARCH 0 // useful to track search convergence @@ -44,19 +49,19 @@ double target; int do_size_search; } PassStats; static int InitPassStats(const VP8Encoder* const enc, PassStats* const s) { - const uint64_t target_size = (uint64_t)enc->config_->target_size; + const uint64_t target_size = (uint64_t)enc->config->target_size; const int do_size_search = (target_size != 0); - const float target_PSNR = enc->config_->target_PSNR; + const float target_PSNR = enc->config->target_PSNR; s->is_first = 1; s->dq = 10.f; - s->qmin = 1.f * enc->config_->qmin; - s->qmax = 1.f * enc->config_->qmax; - s->q = s->last_q = Clamp(enc->config_->quality, s->qmin, s->qmax); + s->qmin = 1.f * enc->config->qmin; + s->qmax = 1.f * enc->config->qmax; + s->q = s->last_q = Clamp(enc->config->quality, s->qmin, s->qmax); s->target = do_size_search ? (double)target_size : (target_PSNR > 0.) ? target_PSNR : 40.; // default, just in case s->value = s->last_value = 0.; s->do_size_search = do_size_search; @@ -93,13 +98,13 @@ //------------------------------------------------------------------------------ // Reset the statistics about: number of skips, token proba, level cost,... static void ResetStats(VP8Encoder* const enc) { - VP8EncProba* const proba = &enc->proba_; + VP8EncProba* const proba = &enc->proba; VP8CalculateLevelCosts(proba); - proba->nb_skip_ = 0; + proba->nb_skip = 0; } //------------------------------------------------------------------------------ // Skip decision probability @@ -109,21 +114,21 @@ return (int)(total ? (total - nb) * 255 / total : 255); } // Returns the bit-cost for coding the skip probability. static int FinalizeSkipProba(VP8Encoder* const enc) { - VP8EncProba* const proba = &enc->proba_; - const int nb_mbs = enc->mb_w_ * enc->mb_h_; - const int nb_events = proba->nb_skip_; + VP8EncProba* const proba = &enc->proba; + const int nb_mbs = enc->mb_w * enc->mb_h; + const int nb_events = proba->nb_skip; int size; - proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); - proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD); + proba->skip_proba = CalcSkipProba(nb_events, nb_mbs); + proba->use_skip_proba = (proba->skip_proba < SKIP_PROBA_THRESHOLD); size = 256; // 'use_skip_proba' bit - if (proba->use_skip_proba_) { - size += nb_events * VP8BitCost(1, proba->skip_proba_) - + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); - size += 8 * 256; // cost of signaling the skip_proba_ itself. + if (proba->use_skip_proba) { + size += nb_events * VP8BitCost(1, proba->skip_proba) + + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba); + size += 8 * 256; // cost of signaling the 'skip_proba' itself. } return size; } // Collect statistics and deduce probabilities for next coding pass. @@ -137,23 +142,23 @@ static int BranchCost(int nb, int total, int proba) { return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba); } static void ResetTokenStats(VP8Encoder* const enc) { - VP8EncProba* const proba = &enc->proba_; - memset(proba->stats_, 0, sizeof(proba->stats_)); + VP8EncProba* const proba = &enc->proba; + memset(proba->stats, 0, sizeof(proba->stats)); } static int FinalizeTokenProbas(VP8EncProba* const proba) { int has_changed = 0; int size = 0; int t, b, c, p; for (t = 0; t < NUM_TYPES; ++t) { for (b = 0; b < NUM_BANDS; ++b) { for (c = 0; c < NUM_CTX; ++c) { for (p = 0; p < NUM_PROBAS; ++p) { - const proba_t stats = proba->stats_[t][b][c][p]; + const proba_t stats = proba->stats[t][b][c][p]; const int nb = (stats >> 0) & 0xffff; const int total = (stats >> 16) & 0xffff; const int update_proba = VP8CoeffsUpdateProba[t][b][c][p]; const int old_p = VP8CoeffsProba0[t][b][c][p]; const int new_p = CalcTokenProba(nb, total); @@ -163,21 +168,21 @@ + VP8BitCost(1, update_proba) + 8 * 256; const int use_new_p = (old_cost > new_cost); size += VP8BitCost(use_new_p, update_proba); if (use_new_p) { // only use proba that seem meaningful enough. - proba->coeffs_[t][b][c][p] = new_p; + proba->coeffs[t][b][c][p] = new_p; has_changed |= (new_p != old_p); size += 8 * 256; } else { - proba->coeffs_[t][b][c][p] = old_p; + proba->coeffs[t][b][c][p] = old_p; } } } } } - proba->dirty_ = has_changed; + proba->dirty = has_changed; return size; } //------------------------------------------------------------------------------ // Finalize Segment probability based on the coding tree @@ -188,47 +193,47 @@ : (255 * a + total / 2) / total; // rounded proba } static void ResetSegments(VP8Encoder* const enc) { int n; - for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { - enc->mb_info_[n].segment_ = 0; + for (n = 0; n < enc->mb_w * enc->mb_h; ++n) { + enc->mb_info[n].segment = 0; } } static void SetSegmentProbas(VP8Encoder* const enc) { int p[NUM_MB_SEGMENTS] = { 0 }; int n; - for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { - const VP8MBInfo* const mb = &enc->mb_info_[n]; - ++p[mb->segment_]; + for (n = 0; n < enc->mb_w * enc->mb_h; ++n) { + const VP8MBInfo* const mb = &enc->mb_info[n]; + ++p[mb->segment]; } #if !defined(WEBP_DISABLE_STATS) - if (enc->pic_->stats != NULL) { + if (enc->pic->stats != NULL) { for (n = 0; n < NUM_MB_SEGMENTS; ++n) { - enc->pic_->stats->segment_size[n] = p[n]; + enc->pic->stats->segment_size[n] = p[n]; } } #endif - if (enc->segment_hdr_.num_segments_ > 1) { - uint8_t* const probas = enc->proba_.segments_; + if (enc->segment_hdr.num_segments > 1) { + uint8_t* const probas = enc->proba.segments; probas[0] = GetProba(p[0] + p[1], p[2] + p[3]); probas[1] = GetProba(p[0], p[1]); probas[2] = GetProba(p[2], p[3]); - enc->segment_hdr_.update_map_ = + enc->segment_hdr.update_map = (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255); - if (!enc->segment_hdr_.update_map_) ResetSegments(enc); - enc->segment_hdr_.size_ = + if (!enc->segment_hdr.update_map) ResetSegments(enc); + enc->segment_hdr.size = p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) + p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) + p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) + p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2])); } else { - enc->segment_hdr_.update_map_ = 0; - enc->segment_hdr_.size_ = 0; + enc->segment_hdr.update_map = 0; + enc->segment_hdr.size = 0; } } //------------------------------------------------------------------------------ // Coefficient coding @@ -309,94 +314,94 @@ static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it, const VP8ModeScore* const rd) { int x, y, ch; VP8Residual res; uint64_t pos1, pos2, pos3; - const int i16 = (it->mb_->type_ == 1); - const int segment = it->mb_->segment_; - VP8Encoder* const enc = it->enc_; + const int i16 = (it->mb->type == 1); + const int segment = it->mb->segment; + VP8Encoder* const enc = it->enc; VP8IteratorNzToBytes(it); pos1 = VP8BitWriterPos(bw); if (i16) { VP8InitResidual(0, 1, enc, &res); VP8SetResidualCoeffs(rd->y_dc_levels, &res); - it->top_nz_[8] = it->left_nz_[8] = - PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res); + it->top_nz[8] = it->left_nz[8] = + PutCoeffs(bw, it->top_nz[8] + it->left_nz[8], &res); VP8InitResidual(1, 0, enc, &res); } else { VP8InitResidual(0, 3, enc, &res); } // luma-AC for (y = 0; y < 4; ++y) { for (x = 0; x < 4; ++x) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; + const int ctx = it->top_nz[x] + it->left_nz[y]; VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); - it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res); + it->top_nz[x] = it->left_nz[y] = PutCoeffs(bw, ctx, &res); } } pos2 = VP8BitWriterPos(bw); // U/V VP8InitResidual(0, 2, enc, &res); for (ch = 0; ch <= 2; ch += 2) { for (y = 0; y < 2; ++y) { for (x = 0; x < 2; ++x) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + const int ctx = it->top_nz[4 + ch + x] + it->left_nz[4 + ch + y]; VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + it->top_nz[4 + ch + x] = it->left_nz[4 + ch + y] = PutCoeffs(bw, ctx, &res); } } } pos3 = VP8BitWriterPos(bw); - it->luma_bits_ = pos2 - pos1; - it->uv_bits_ = pos3 - pos2; - it->bit_count_[segment][i16] += it->luma_bits_; - it->bit_count_[segment][2] += it->uv_bits_; + it->luma_bits = pos2 - pos1; + it->uv_bits = pos3 - pos2; + it->bit_count[segment][i16] += it->luma_bits; + it->bit_count[segment][2] += it->uv_bits; VP8IteratorBytesToNz(it); } // Same as CodeResiduals, but doesn't actually write anything. // Instead, it just records the event distribution. static void RecordResiduals(VP8EncIterator* const it, const VP8ModeScore* const rd) { int x, y, ch; VP8Residual res; - VP8Encoder* const enc = it->enc_; + VP8Encoder* const enc = it->enc; VP8IteratorNzToBytes(it); - if (it->mb_->type_ == 1) { // i16x16 + if (it->mb->type == 1) { // i16x16 VP8InitResidual(0, 1, enc, &res); VP8SetResidualCoeffs(rd->y_dc_levels, &res); - it->top_nz_[8] = it->left_nz_[8] = - VP8RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res); + it->top_nz[8] = it->left_nz[8] = + VP8RecordCoeffs(it->top_nz[8] + it->left_nz[8], &res); VP8InitResidual(1, 0, enc, &res); } else { VP8InitResidual(0, 3, enc, &res); } // luma-AC for (y = 0; y < 4; ++y) { for (x = 0; x < 4; ++x) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; + const int ctx = it->top_nz[x] + it->left_nz[y]; VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); - it->top_nz_[x] = it->left_nz_[y] = VP8RecordCoeffs(ctx, &res); + it->top_nz[x] = it->left_nz[y] = VP8RecordCoeffs(ctx, &res); } } // U/V VP8InitResidual(0, 2, enc, &res); for (ch = 0; ch <= 2; ch += 2) { for (y = 0; y < 2; ++y) { for (x = 0; x < 2; ++x) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + const int ctx = it->top_nz[4 + ch + x] + it->left_nz[4 + ch + y]; VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + it->top_nz[4 + ch + x] = it->left_nz[4 + ch + y] = VP8RecordCoeffs(ctx, &res); } } } @@ -410,48 +415,48 @@ static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd, VP8TBuffer* const tokens) { int x, y, ch; VP8Residual res; - VP8Encoder* const enc = it->enc_; + VP8Encoder* const enc = it->enc; VP8IteratorNzToBytes(it); - if (it->mb_->type_ == 1) { // i16x16 - const int ctx = it->top_nz_[8] + it->left_nz_[8]; + if (it->mb->type == 1) { // i16x16 + const int ctx = it->top_nz[8] + it->left_nz[8]; VP8InitResidual(0, 1, enc, &res); VP8SetResidualCoeffs(rd->y_dc_levels, &res); - it->top_nz_[8] = it->left_nz_[8] = + it->top_nz[8] = it->left_nz[8] = VP8RecordCoeffTokens(ctx, &res, tokens); VP8InitResidual(1, 0, enc, &res); } else { VP8InitResidual(0, 3, enc, &res); } // luma-AC for (y = 0; y < 4; ++y) { for (x = 0; x < 4; ++x) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; + const int ctx = it->top_nz[x] + it->left_nz[y]; VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); - it->top_nz_[x] = it->left_nz_[y] = + it->top_nz[x] = it->left_nz[y] = VP8RecordCoeffTokens(ctx, &res, tokens); } } // U/V VP8InitResidual(0, 2, enc, &res); for (ch = 0; ch <= 2; ch += 2) { for (y = 0; y < 2; ++y) { for (x = 0; x < 2; ++x) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + const int ctx = it->top_nz[4 + ch + x] + it->left_nz[4 + ch + y]; VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + it->top_nz[4 + ch + x] = it->left_nz[4 + ch + y] = VP8RecordCoeffTokens(ctx, &res, tokens); } } } VP8IteratorBytesToNz(it); - return !tokens->error_; + return !tokens->error; } #endif // !DISABLE_TOKEN_BUFFER //------------------------------------------------------------------------------ @@ -468,82 +473,82 @@ } } #endif static void ResetSSE(VP8Encoder* const enc) { - enc->sse_[0] = 0; - enc->sse_[1] = 0; - enc->sse_[2] = 0; - // Note: enc->sse_[3] is managed by alpha.c - enc->sse_count_ = 0; + enc->sse[0] = 0; + enc->sse[1] = 0; + enc->sse[2] = 0; + // Note: enc->sse[3] is managed by alpha.c + enc->sse_count = 0; } static void StoreSSE(const VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - const uint8_t* const in = it->yuv_in_; - const uint8_t* const out = it->yuv_out_; + VP8Encoder* const enc = it->enc; + const uint8_t* const in = it->yuv_in; + const uint8_t* const out = it->yuv_out; // Note: not totally accurate at boundary. And doesn't include in-loop filter. - enc->sse_[0] += VP8SSE16x16(in + Y_OFF_ENC, out + Y_OFF_ENC); - enc->sse_[1] += VP8SSE8x8(in + U_OFF_ENC, out + U_OFF_ENC); - enc->sse_[2] += VP8SSE8x8(in + V_OFF_ENC, out + V_OFF_ENC); - enc->sse_count_ += 16 * 16; + enc->sse[0] += VP8SSE16x16(in + Y_OFF_ENC, out + Y_OFF_ENC); + enc->sse[1] += VP8SSE8x8(in + U_OFF_ENC, out + U_OFF_ENC); + enc->sse[2] += VP8SSE8x8(in + V_OFF_ENC, out + V_OFF_ENC); + enc->sse_count += 16 * 16; } static void StoreSideInfo(const VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - const VP8MBInfo* const mb = it->mb_; - WebPPicture* const pic = enc->pic_; + VP8Encoder* const enc = it->enc; + const VP8MBInfo* const mb = it->mb; + WebPPicture* const pic = enc->pic; if (pic->stats != NULL) { StoreSSE(it); - enc->block_count_[0] += (mb->type_ == 0); - enc->block_count_[1] += (mb->type_ == 1); - enc->block_count_[2] += (mb->skip_ != 0); + enc->block_count[0] += (mb->type == 0); + enc->block_count[1] += (mb->type == 1); + enc->block_count[2] += (mb->skip != 0); } if (pic->extra_info != NULL) { - uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_]; + uint8_t* const info = &pic->extra_info[it->x + it->y * enc->mb_w]; switch (pic->extra_info_type) { - case 1: *info = mb->type_; break; - case 2: *info = mb->segment_; break; - case 3: *info = enc->dqm_[mb->segment_].quant_; break; - case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break; - case 5: *info = mb->uv_mode_; break; + case 1: *info = mb->type; break; + case 2: *info = mb->segment; break; + case 3: *info = enc->dqm[mb->segment].quant; break; + case 4: *info = (mb->type == 1) ? it->preds[0] : 0xff; break; + case 5: *info = mb->uv_mode; break; case 6: { - const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); + const int b = (int)((it->luma_bits + it->uv_bits + 7) >> 3); *info = (b > 255) ? 255 : b; break; } - case 7: *info = mb->alpha_; break; + case 7: *info = mb->alpha; break; default: *info = 0; break; } } #if SEGMENT_VISU // visualize segments and prediction modes - SetBlock(it->yuv_out_ + Y_OFF_ENC, mb->segment_ * 64, 16); - SetBlock(it->yuv_out_ + U_OFF_ENC, it->preds_[0] * 64, 8); - SetBlock(it->yuv_out_ + V_OFF_ENC, mb->uv_mode_ * 64, 8); + SetBlock(it->yuv_out + Y_OFF_ENC, mb->segment * 64, 16); + SetBlock(it->yuv_out + U_OFF_ENC, it->preds[0] * 64, 8); + SetBlock(it->yuv_out + V_OFF_ENC, mb->uv_mode * 64, 8); #endif } static void ResetSideInfo(const VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - WebPPicture* const pic = enc->pic_; + VP8Encoder* const enc = it->enc; + WebPPicture* const pic = enc->pic; if (pic->stats != NULL) { - memset(enc->block_count_, 0, sizeof(enc->block_count_)); + memset(enc->block_count, 0, sizeof(enc->block_count)); } ResetSSE(enc); } #else // defined(WEBP_DISABLE_STATS) static void ResetSSE(VP8Encoder* const enc) { (void)enc; } static void StoreSideInfo(const VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - WebPPicture* const pic = enc->pic_; + VP8Encoder* const enc = it->enc; + WebPPicture* const pic = enc->pic; if (pic->extra_info != NULL) { - if (it->x_ == 0 && it->y_ == 0) { // only do it once, at start + if (it->x == 0 && it->y == 0) { // only do it once, at start memset(pic->extra_info, 0, - enc->mb_w_ * enc->mb_h_ * sizeof(*pic->extra_info)); + enc->mb_w * enc->mb_h * sizeof(*pic->extra_info)); } } } static void ResetSideInfo(const VP8EncIterator* const it) { @@ -585,11 +590,11 @@ do { VP8ModeScore info; VP8IteratorImport(&it, NULL); if (VP8Decimate(&it, &info, rd_opt)) { // Just record the number of skips and act like skip_proba is not used. - ++enc->proba_.nb_skip_; + ++enc->proba.nb_skip; } RecordResiduals(&it, &info); size += info.R + info.H; size_p0 += info.H; distortion += info.D; @@ -597,34 +602,34 @@ return 0; } VP8IteratorSaveBoundary(&it); } while (VP8IteratorNext(&it) && --nb_mbs > 0); - size_p0 += enc->segment_hdr_.size_; + size_p0 += enc->segment_hdr.size; if (s->do_size_search) { size += FinalizeSkipProba(enc); - size += FinalizeTokenProbas(&enc->proba_); + size += FinalizeTokenProbas(&enc->proba); size = ((size + size_p0 + 1024) >> 11) + HEADER_SIZE_ESTIMATE; s->value = (double)size; } else { s->value = GetPSNR(distortion, pixel_count); } return size_p0; } static int StatLoop(VP8Encoder* const enc) { - const int method = enc->method_; - const int do_search = enc->do_search_; + const int method = enc->method; + const int do_search = enc->do_search; const int fast_probe = ((method == 0 || method == 3) && !do_search); - int num_pass_left = enc->config_->pass; + int num_pass_left = enc->config->pass; const int task_percent = 20; const int percent_per_pass = (task_percent + num_pass_left / 2) / num_pass_left; - const int final_percent = enc->percent_ + task_percent; + const int final_percent = enc->percent + task_percent; const VP8RDLevel rd_opt = (method >= 3 || do_search) ? RD_OPT_BASIC : RD_OPT_NONE; - int nb_mbs = enc->mb_w_ * enc->mb_h_; + int nb_mbs = enc->mb_w * enc->mb_h; PassStats stats; InitPassStats(enc, &stats); ResetTokenStats(enc); @@ -638,21 +643,21 @@ } while (num_pass_left-- > 0) { const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) || (num_pass_left == 0) || - (enc->max_i4_header_bits_ == 0); + (enc->max_i4_header_bits == 0); const uint64_t size_p0 = OneStatPass(enc, rd_opt, nb_mbs, percent_per_pass, &stats); if (size_p0 == 0) return 0; #if (DEBUG_SEARCH > 0) printf("#%d value:%.1lf -> %.1lf q:%.2f -> %.2f\n", num_pass_left, stats.last_value, stats.value, stats.last_q, stats.q); #endif - if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { + if (enc->max_i4_header_bits > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { ++num_pass_left; - enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation... + enc->max_i4_header_bits >>= 1; // strengthen header bit limitation... continue; // ...and start over } if (is_last_pass) { break; } @@ -663,14 +668,14 @@ } } if (!do_search || !stats.do_size_search) { // Need to finalize probas now, since it wasn't done during the search. FinalizeSkipProba(enc); - FinalizeTokenProbas(&enc->proba_); + FinalizeTokenProbas(&enc->proba); } - VP8CalculateLevelCosts(&enc->proba_); // finalize costs - return WebPReportProgress(enc->pic_, final_percent, &enc->percent_); + VP8CalculateLevelCosts(&enc->proba); // finalize costs + return WebPReportProgress(enc->pic, final_percent, &enc->percent); } //------------------------------------------------------------------------------ // Main loops // @@ -678,63 +683,63 @@ static const uint8_t kAverageBytesPerMB[8] = { 50, 24, 16, 9, 7, 5, 3, 2 }; static int PreLoopInitialize(VP8Encoder* const enc) { int p; int ok = 1; - const int average_bytes_per_MB = kAverageBytesPerMB[enc->base_quant_ >> 4]; + const int average_bytes_per_MB = kAverageBytesPerMB[enc->base_quant >> 4]; const int bytes_per_parts = - enc->mb_w_ * enc->mb_h_ * average_bytes_per_MB / enc->num_parts_; + enc->mb_w * enc->mb_h * average_bytes_per_MB / enc->num_parts; // Initialize the bit-writers - for (p = 0; ok && p < enc->num_parts_; ++p) { - ok = VP8BitWriterInit(enc->parts_ + p, bytes_per_parts); + for (p = 0; ok && p < enc->num_parts; ++p) { + ok = VP8BitWriterInit(enc->parts + p, bytes_per_parts); } if (!ok) { VP8EncFreeBitWriters(enc); // malloc error occurred - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); } return ok; } static int PostLoopFinalize(VP8EncIterator* const it, int ok) { - VP8Encoder* const enc = it->enc_; + VP8Encoder* const enc = it->enc; if (ok) { // Finalize the partitions, check for extra errors. int p; - for (p = 0; p < enc->num_parts_; ++p) { - VP8BitWriterFinish(enc->parts_ + p); - ok &= !enc->parts_[p].error_; + for (p = 0; p < enc->num_parts; ++p) { + VP8BitWriterFinish(enc->parts + p); + ok &= !enc->parts[p].error; } } if (ok) { // All good. Finish up. #if !defined(WEBP_DISABLE_STATS) - if (enc->pic_->stats != NULL) { // finalize byte counters... + if (enc->pic->stats != NULL) { // finalize byte counters... int i, s; for (i = 0; i <= 2; ++i) { for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - enc->residual_bytes_[i][s] = (int)((it->bit_count_[s][i] + 7) >> 3); + enc->residual_bytes[i][s] = (int)((it->bit_count[s][i] + 7) >> 3); } } } #endif VP8AdjustFilterStrength(it); // ...and store filter stats. } else { // Something bad happened -> need to do some memory cleanup. VP8EncFreeBitWriters(enc); - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); } return ok; } //------------------------------------------------------------------------------ // VP8EncLoop(): does the final bitstream coding. static void ResetAfterSkip(VP8EncIterator* const it) { - if (it->mb_->type_ == 1) { - *it->nz_ = 0; // reset all predictors - it->left_nz_[8] = 0; + if (it->mb->type == 1) { + *it->nz = 0; // reset all predictors + it->left_nz[8] = 0; } else { - *it->nz_ &= (1 << 24); // preserve the dc_nz bit + *it->nz &= (1 << 24); // preserve the dc_nz bit } } int VP8EncLoop(VP8Encoder* const enc) { VP8EncIterator it; @@ -745,20 +750,20 @@ VP8IteratorInit(enc, &it); VP8InitFilter(&it); do { VP8ModeScore info; - const int dont_use_skip = !enc->proba_.use_skip_proba_; - const VP8RDLevel rd_opt = enc->rd_opt_level_; + const int dont_use_skip = !enc->proba.use_skip_proba; + const VP8RDLevel rd_opt = enc->rd_opt_level; VP8IteratorImport(&it, NULL); // Warning! order is important: first call VP8Decimate() and // *then* decide how to code the skip decision if there's one. if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) { - CodeResiduals(it.bw_, &it, &info); - if (it.bw_->error_) { - // enc->pic_->error_code is set in PostLoopFinalize(). + CodeResiduals(it.bw, &it, &info); + if (it.bw->error) { + // enc->pic->error_code is set in PostLoopFinalize(). ok = 0; break; } } else { // reset predictors after a skip ResetAfterSkip(&it); @@ -780,37 +785,37 @@ #define MIN_COUNT 96 // minimum number of macroblocks before updating stats int VP8EncTokenLoop(VP8Encoder* const enc) { // Roughly refresh the proba eight times per pass - int max_count = (enc->mb_w_ * enc->mb_h_) >> 3; - int num_pass_left = enc->config_->pass; + int max_count = (enc->mb_w * enc->mb_h) >> 3; + int num_pass_left = enc->config->pass; int remaining_progress = 40; // percents - const int do_search = enc->do_search_; + const int do_search = enc->do_search; VP8EncIterator it; - VP8EncProba* const proba = &enc->proba_; - const VP8RDLevel rd_opt = enc->rd_opt_level_; - const uint64_t pixel_count = (uint64_t)enc->mb_w_ * enc->mb_h_ * 384; + VP8EncProba* const proba = &enc->proba; + const VP8RDLevel rd_opt = enc->rd_opt_level; + const uint64_t pixel_count = (uint64_t)enc->mb_w * enc->mb_h * 384; PassStats stats; int ok; InitPassStats(enc, &stats); ok = PreLoopInitialize(enc); if (!ok) return 0; if (max_count < MIN_COUNT) max_count = MIN_COUNT; - assert(enc->num_parts_ == 1); - assert(enc->use_tokens_); - assert(proba->use_skip_proba_ == 0); + assert(enc->num_parts == 1); + assert(enc->use_tokens); + assert(proba->use_skip_proba == 0); assert(rd_opt >= RD_OPT_BASIC); // otherwise, token-buffer won't be useful assert(num_pass_left > 0); while (ok && num_pass_left-- > 0) { const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) || (num_pass_left == 0) || - (enc->max_i4_header_bits_ == 0); + (enc->max_i4_header_bits == 0); uint64_t size_p0 = 0; uint64_t distortion = 0; int cnt = max_count; // The final number of passes is not trivial to know in advance. const int pass_progress = remaining_progress / (2 + num_pass_left); @@ -819,23 +824,23 @@ SetLoopParams(enc, stats.q); if (is_last_pass) { ResetTokenStats(enc); VP8InitFilter(&it); // don't collect stats until last pass (too costly) } - VP8TBufferClear(&enc->tokens_); + VP8TBufferClear(&enc->tokens); do { VP8ModeScore info; VP8IteratorImport(&it, NULL); if (--cnt < 0) { FinalizeTokenProbas(proba); VP8CalculateLevelCosts(proba); // refresh cost tables for rd-opt cnt = max_count; } VP8Decimate(&it, &info, rd_opt); - ok = RecordTokens(&it, &info, &enc->tokens_); + ok = RecordTokens(&it, &info, &enc->tokens); if (!ok) { - WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); break; } size_p0 += info.H; distortion += info.D; if (is_last_pass) { @@ -846,15 +851,15 @@ } VP8IteratorSaveBoundary(&it); } while (ok && VP8IteratorNext(&it)); if (!ok) break; - size_p0 += enc->segment_hdr_.size_; + size_p0 += enc->segment_hdr.size; if (stats.do_size_search) { - uint64_t size = FinalizeTokenProbas(&enc->proba_); - size += VP8EstimateTokenSize(&enc->tokens_, - (const uint8_t*)proba->coeffs_); + uint64_t size = FinalizeTokenProbas(&enc->proba); + size += VP8EstimateTokenSize(&enc->tokens, + (const uint8_t*)proba->coeffs); size = (size + size_p0 + 1024) >> 11; // -> size in bytes size += HEADER_SIZE_ESTIMATE; stats.value = (double)size; } else { // compute and store PSNR stats.value = GetPSNR(distortion, pixel_count); @@ -864,13 +869,13 @@ printf("#%2d metric:%.1lf -> %.1lf last_q=%.2lf q=%.2lf dq=%.2lf " " range:[%.1f, %.1f]\n", num_pass_left, stats.last_value, stats.value, stats.last_q, stats.q, stats.dq, stats.qmin, stats.qmax); #endif - if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { + if (enc->max_i4_header_bits > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { ++num_pass_left; - enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation... + enc->max_i4_header_bits >>= 1; // strengthen header bit limitation... if (is_last_pass) { ResetSideInfo(&it); } continue; // ...and start over } @@ -881,17 +886,17 @@ ComputeNextQ(&stats); // Adjust q } } if (ok) { if (!stats.do_size_search) { - FinalizeTokenProbas(&enc->proba_); + FinalizeTokenProbas(&enc->proba); } - ok = VP8EmitTokens(&enc->tokens_, enc->parts_ + 0, - (const uint8_t*)proba->coeffs_, 1); + ok = VP8EmitTokens(&enc->tokens, enc->parts + 0, + (const uint8_t*)proba->coeffs, 1); } - ok = ok && WebPReportProgress(enc->pic_, enc->percent_ + remaining_progress, - &enc->percent_); + ok = ok && WebPReportProgress(enc->pic, enc->percent + remaining_progress, + &enc->percent); return PostLoopFinalize(&it, ok); } #else diff --git a/media/libwebp/src/enc/histogram_enc.h b/media/libwebp/src/enc/histogram_enc.h --- a/media/libwebp/src/enc/histogram_enc.h +++ b/media/libwebp/src/enc/histogram_enc.h @@ -12,41 +12,43 @@ // Models the histograms of literal and distance codes. #ifndef WEBP_ENC_HISTOGRAM_ENC_H_ #define WEBP_ENC_HISTOGRAM_ENC_H_ -#include - #include "src/enc/backward_references_enc.h" +#include "src/webp/encode.h" #include "src/webp/format_constants.h" #include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif // Not a trivial literal symbol. -#define VP8L_NON_TRIVIAL_SYM (0xffffffff) +#define VP8L_NON_TRIVIAL_SYM ((uint16_t)(0xffff)) // A simple container for histograms of data. typedef struct { - // literal_ contains green literal, palette-code and + // 'literal' contains green literal, palette-code and // copy-length-prefix histogram - uint32_t* literal_; // Pointer to the allocated buffer for literal. - uint32_t red_[NUM_LITERAL_CODES]; - uint32_t blue_[NUM_LITERAL_CODES]; - uint32_t alpha_[NUM_LITERAL_CODES]; + uint32_t* literal; // Pointer to the allocated buffer for literal. + uint32_t red[NUM_LITERAL_CODES]; + uint32_t blue[NUM_LITERAL_CODES]; + uint32_t alpha[NUM_LITERAL_CODES]; // Backward reference prefix-code histogram. - uint32_t distance_[NUM_DISTANCE_CODES]; - int palette_code_bits_; - uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha - // literal symbols are single valued. - uint64_t bit_cost_; // cached value of bit cost. - uint64_t literal_cost_; // Cached values of dominant entropy costs: - uint64_t red_cost_; // literal, red & blue. - uint64_t blue_cost_; - uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance + uint32_t distance[NUM_DISTANCE_CODES]; + int palette_code_bits; + // The following members are only used within VP8LGetHistoImageSymbols. + + // Index of the unique value of a histogram if any, VP8L_NON_TRIVIAL_SYM + // otherwise. + uint16_t trivial_symbol[5]; + uint64_t bit_cost; // Cached value of total bit cost. + // Cached values of entropy costs: literal, red, blue, alpha, distance + uint64_t costs[5]; + uint8_t is_used[5]; // 5 for literal, red, blue, alpha, distance + uint16_t bin_id; // entropy bin index. } VP8LHistogram; // Collection of histograms with fixed capacity, allocated as one // big memory chunk. Can be destroyed by calling WebPSafeFree(). typedef struct { @@ -58,21 +60,25 @@ // Create the histogram. // // The input data is the PixOrCopy data, which models the literals, stop // codes and backward references (both distances and lengths). Also: if // palette_code_bits is >= 0, initialize the histogram with this value. -void VP8LHistogramCreate(VP8LHistogram* const p, +void VP8LHistogramCreate(VP8LHistogram* const h, const VP8LBackwardRefs* const refs, int palette_code_bits); // Set the palette_code_bits and reset the stats. // If init_arrays is true, the arrays are also filled with 0's. -void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits, +void VP8LHistogramInit(VP8LHistogram* const h, int palette_code_bits, int init_arrays); // Collect all the references into a histogram (without reset) +// The distance modifier function is applied to the distance before +// the histogram is updated. It can be NULL. void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, + int (*const distance_modifier)(int, int), + int distance_modifier_arg0, VP8LHistogram* const histo); // Free the memory allocated for the histogram. void VP8LFreeHistogram(VP8LHistogram* const histo); @@ -89,16 +95,10 @@ // Allocate and initialize histogram object with specified 'cache_bits'. // Returns NULL in case of memory error. // Special case of VP8LAllocateHistogramSet, with size equals 1. VP8LHistogram* VP8LAllocateHistogram(int cache_bits); -// Accumulate a token 'v' into a histogram. -void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, - const PixOrCopy* const v, - int (*const distance_modifier)(int, int), - int distance_modifier_arg0); - static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) { return NUM_LITERAL_CODES + NUM_LENGTH_CODES + ((palette_code_bits > 0) ? (1 << palette_code_bits) : 0); } @@ -116,11 +116,11 @@ // Returns the entropy for the symbols in the input array. uint64_t VP8LBitsEntropy(const uint32_t* const array, int n); // Estimate how many bits the combined entropy of literals and distance // approximately maps to. -uint64_t VP8LHistogramEstimateBits(VP8LHistogram* const p); +uint64_t VP8LHistogramEstimateBits(const VP8LHistogram* const h); #ifdef __cplusplus } #endif diff --git a/media/libwebp/src/enc/histogram_enc.c b/media/libwebp/src/enc/histogram_enc.c --- a/media/libwebp/src/enc/histogram_enc.c +++ b/media/libwebp/src/enc/histogram_enc.c @@ -11,113 +11,124 @@ // #ifdef HAVE_CONFIG_H #include "src/webp/config.h" #endif +#include +#include #include #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" #include "src/enc/backward_references_enc.h" #include "src/enc/histogram_enc.h" #include "src/enc/vp8i_enc.h" #include "src/utils/utils.h" +#include "src/webp/encode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" // Number of partitions for the three dominant (literal, red and blue) symbol // costs. #define NUM_PARTITIONS 4 // The size of the bin-hash corresponding to the three dominant costs. #define BIN_SIZE (NUM_PARTITIONS * NUM_PARTITIONS * NUM_PARTITIONS) // Maximum number of histograms allowed in greedy combining algorithm. #define MAX_HISTO_GREEDY 100 +// Enum to meaningfully access the elements of the Histogram arrays. +typedef enum { + LITERAL = 0, + RED, + BLUE, + ALPHA, + DISTANCE +} HistogramIndex; + // Return the size of the histogram for a given cache_bits. static int GetHistogramSize(int cache_bits) { const int literal_size = VP8LHistogramNumCodes(cache_bits); const size_t total_size = sizeof(VP8LHistogram) + sizeof(int) * literal_size; assert(total_size <= (size_t)0x7fffffff); return (int)total_size; } -static void HistogramClear(VP8LHistogram* const p) { - uint32_t* const literal = p->literal_; - const int cache_bits = p->palette_code_bits_; +static void HistogramStatsClear(VP8LHistogram* const h) { + int i; + for (i = 0; i < 5; ++i) { + h->trivial_symbol[i] = VP8L_NON_TRIVIAL_SYM; + // By default, the histogram is assumed to be used. + h->is_used[i] = 1; + } + h->bit_cost = 0; + memset(h->costs, 0, sizeof(h->costs)); +} + +static void HistogramClear(VP8LHistogram* const h) { + uint32_t* const literal = h->literal; + const int cache_bits = h->palette_code_bits; const int histo_size = GetHistogramSize(cache_bits); - memset(p, 0, histo_size); - p->palette_code_bits_ = cache_bits; - p->literal_ = literal; + memset(h, 0, histo_size); + h->palette_code_bits = cache_bits; + h->literal = literal; + HistogramStatsClear(h); } // Swap two histogram pointers. -static void HistogramSwap(VP8LHistogram** const A, VP8LHistogram** const B) { - VP8LHistogram* const tmp = *A; - *A = *B; - *B = tmp; +static void HistogramSwap(VP8LHistogram** const h1, VP8LHistogram** const h2) { + VP8LHistogram* const tmp = *h1; + *h1 = *h2; + *h2 = tmp; } static void HistogramCopy(const VP8LHistogram* const src, VP8LHistogram* const dst) { - uint32_t* const dst_literal = dst->literal_; - const int dst_cache_bits = dst->palette_code_bits_; + uint32_t* const dst_literal = dst->literal; + const int dst_cache_bits = dst->palette_code_bits; const int literal_size = VP8LHistogramNumCodes(dst_cache_bits); const int histo_size = GetHistogramSize(dst_cache_bits); - assert(src->palette_code_bits_ == dst_cache_bits); + assert(src->palette_code_bits == dst_cache_bits); memcpy(dst, src, histo_size); - dst->literal_ = dst_literal; - memcpy(dst->literal_, src->literal_, literal_size * sizeof(*dst->literal_)); -} - -void VP8LFreeHistogram(VP8LHistogram* const histo) { - WebPSafeFree(histo); + dst->literal = dst_literal; + memcpy(dst->literal, src->literal, literal_size * sizeof(*dst->literal)); } -void VP8LFreeHistogramSet(VP8LHistogramSet* const histo) { - WebPSafeFree(histo); +void VP8LFreeHistogram(VP8LHistogram* const h) { WebPSafeFree(h); } + +void VP8LFreeHistogramSet(VP8LHistogramSet* const histograms) { + WebPSafeFree(histograms); } -void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, - VP8LHistogram* const histo) { - VP8LRefsCursor c = VP8LRefsCursorInit(refs); - while (VP8LRefsCursorOk(&c)) { - VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, NULL, 0); - VP8LRefsCursorNext(&c); - } -} - -void VP8LHistogramCreate(VP8LHistogram* const p, +void VP8LHistogramCreate(VP8LHistogram* const h, const VP8LBackwardRefs* const refs, int palette_code_bits) { if (palette_code_bits >= 0) { - p->palette_code_bits_ = palette_code_bits; + h->palette_code_bits = palette_code_bits; } - HistogramClear(p); - VP8LHistogramStoreRefs(refs, p); + HistogramClear(h); + VP8LHistogramStoreRefs(refs, /*distance_modifier=*/NULL, + /*distance_modifier_arg0=*/0, h); } -void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits, +void VP8LHistogramInit(VP8LHistogram* const h, int palette_code_bits, int init_arrays) { - p->palette_code_bits_ = palette_code_bits; + h->palette_code_bits = palette_code_bits; if (init_arrays) { - HistogramClear(p); + HistogramClear(h); } else { - p->trivial_symbol_ = 0; - p->bit_cost_ = 0; - p->literal_cost_ = 0; - p->red_cost_ = 0; - p->blue_cost_ = 0; - memset(p->is_used_, 0, sizeof(p->is_used_)); + HistogramStatsClear(h); } } VP8LHistogram* VP8LAllocateHistogram(int cache_bits) { VP8LHistogram* histo = NULL; const int total_size = GetHistogramSize(cache_bits); uint8_t* const memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); if (memory == NULL) return NULL; histo = (VP8LHistogram*)memory; - // literal_ won't necessary be aligned. - histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); + // 'literal' won't necessary be aligned. + histo->literal = (uint32_t*)(memory + sizeof(VP8LHistogram)); VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0); return histo; } // Resets the pointers of the histograms to point to the bit buffer in the set. @@ -128,12 +139,12 @@ uint8_t* memory = (uint8_t*) (set->histograms); memory += set->max_size * sizeof(*set->histograms); for (i = 0; i < set->max_size; ++i) { memory = (uint8_t*) WEBP_ALIGN(memory); set->histograms[i] = (VP8LHistogram*) memory; - // literal_ won't necessary be aligned. - set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); + // 'literal' won't necessary be aligned. + set->histograms[i]->literal = (uint32_t*)(memory + sizeof(VP8LHistogram)); memory += histo_size; } } // Returns the total size of the VP8LHistogramSet. @@ -162,11 +173,11 @@ return set; } void VP8LHistogramSetClear(VP8LHistogramSet* const set) { int i; - const int cache_bits = set->histograms[0]->palette_code_bits_; + const int cache_bits = set->histograms[0]->palette_code_bits; const int size = set->max_size; const size_t total_size = HistogramSetTotalSize(size, cache_bits); uint8_t* memory = (uint8_t*)set; memset(memory, 0, total_size); @@ -174,56 +185,60 @@ set->histograms = (VP8LHistogram**)memory; set->max_size = size; set->size = size; HistogramSetResetPointers(set, cache_bits); for (i = 0; i < size; ++i) { - set->histograms[i]->palette_code_bits_ = cache_bits; + set->histograms[i]->palette_code_bits = cache_bits; } } -// Removes the histogram 'i' from 'set' by setting it to NULL. -static void HistogramSetRemoveHistogram(VP8LHistogramSet* const set, int i, - int* const num_used) { - assert(set->histograms[i] != NULL); - set->histograms[i] = NULL; - --*num_used; - // If we remove the last valid one, shrink until the next valid one. - if (i == set->size - 1) { - while (set->size >= 1 && set->histograms[set->size - 1] == NULL) { - --set->size; - } - } +// Removes the histogram 'i' from 'set'. +static void HistogramSetRemoveHistogram(VP8LHistogramSet* const set, int i) { + set->histograms[i] = set->histograms[set->size - 1]; + --set->size; + assert(set->size > 0); } // ----------------------------------------------------------------------------- -void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, - const PixOrCopy* const v, - int (*const distance_modifier)(int, int), - int distance_modifier_arg0) { +static void HistogramAddSinglePixOrCopy( + VP8LHistogram* const histo, const PixOrCopy* const v, + int (*const distance_modifier)(int, int), int distance_modifier_arg0) { if (PixOrCopyIsLiteral(v)) { - ++histo->alpha_[PixOrCopyLiteral(v, 3)]; - ++histo->red_[PixOrCopyLiteral(v, 2)]; - ++histo->literal_[PixOrCopyLiteral(v, 1)]; - ++histo->blue_[PixOrCopyLiteral(v, 0)]; + ++histo->alpha[PixOrCopyLiteral(v, 3)]; + ++histo->red[PixOrCopyLiteral(v, 2)]; + ++histo->literal[PixOrCopyLiteral(v, 1)]; + ++histo->blue[PixOrCopyLiteral(v, 0)]; } else if (PixOrCopyIsCacheIdx(v)) { const int literal_ix = NUM_LITERAL_CODES + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v); - assert(histo->palette_code_bits_ != 0); - ++histo->literal_[literal_ix]; + assert(histo->palette_code_bits != 0); + ++histo->literal[literal_ix]; } else { int code, extra_bits; VP8LPrefixEncodeBits(PixOrCopyLength(v), &code, &extra_bits); - ++histo->literal_[NUM_LITERAL_CODES + code]; + ++histo->literal[NUM_LITERAL_CODES + code]; if (distance_modifier == NULL) { VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits); } else { VP8LPrefixEncodeBits( distance_modifier(distance_modifier_arg0, PixOrCopyDistance(v)), &code, &extra_bits); } - ++histo->distance_[code]; + ++histo->distance[code]; + } +} + +void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, + int (*const distance_modifier)(int, int), + int distance_modifier_arg0, + VP8LHistogram* const histo) { + VP8LRefsCursor c = VP8LRefsCursorInit(refs); + while (VP8LRefsCursorOk(&c)) { + HistogramAddSinglePixOrCopy(histo, c.cur_pos, distance_modifier, + distance_modifier_arg0); + VP8LRefsCursorNext(&c); } } // ----------------------------------------------------------------------------- // Entropy-related functions. @@ -300,82 +315,100 @@ } // Get the symbol entropy for the distribution 'population'. // Set 'trivial_sym', if there's only one symbol present in the distribution. static uint64_t PopulationCost(const uint32_t* const population, int length, - uint32_t* const trivial_sym, + uint16_t* const trivial_sym, uint8_t* const is_used) { VP8LBitEntropy bit_entropy; VP8LStreaks stats; VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats); if (trivial_sym != NULL) { *trivial_sym = (bit_entropy.nonzeros == 1) ? bit_entropy.nonzero_code : VP8L_NON_TRIVIAL_SYM; } - // The histogram is used if there is at least one non-zero streak. - *is_used = (stats.streaks[1][0] != 0 || stats.streaks[1][1] != 0); + if (is_used != NULL) { + // The histogram is used if there is at least one non-zero streak. + *is_used = (stats.streaks[1][0] != 0 || stats.streaks[1][1] != 0); + } return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); } +static WEBP_INLINE void GetPopulationInfo(const VP8LHistogram* const histo, + HistogramIndex index, + const uint32_t** population, + int* length) { + switch (index) { + case LITERAL: + *population = histo->literal; + *length = VP8LHistogramNumCodes(histo->palette_code_bits); + break; + case RED: + *population = histo->red; + *length = NUM_LITERAL_CODES; + break; + case BLUE: + *population = histo->blue; + *length = NUM_LITERAL_CODES; + break; + case ALPHA: + *population = histo->alpha; + *length = NUM_LITERAL_CODES; + break; + case DISTANCE: + *population = histo->distance; + *length = NUM_DISTANCE_CODES; + break; + } +} + // trivial_at_end is 1 if the two histograms only have one element that is // non-zero: both the zero-th one, or both the last one. -static WEBP_INLINE uint64_t GetCombinedEntropy(const uint32_t* const X, - const uint32_t* const Y, - int length, int is_X_used, - int is_Y_used, - int trivial_at_end) { +// 'index' is the index of the symbol in the histogram (literal, red, blue, +// alpha, distance). +static WEBP_INLINE uint64_t GetCombinedEntropy(const VP8LHistogram* const h1, + const VP8LHistogram* const h2, + HistogramIndex index) { + const uint32_t* X; + const uint32_t* Y; + int length; VP8LStreaks stats; - if (trivial_at_end) { - // This configuration is due to palettization that transforms an indexed - // pixel into 0xff000000 | (pixel << 8) in VP8LBundleColorMap. - // BitsEntropyRefine is 0 for histograms with only one non-zero value. - // Only FinalHuffmanCost needs to be evaluated. - memset(&stats, 0, sizeof(stats)); - // Deal with the non-zero value at index 0 or length-1. - stats.streaks[1][0] = 1; - // Deal with the following/previous zero streak. - stats.counts[0] = 1; - stats.streaks[0][1] = length - 1; - return FinalHuffmanCost(&stats); - } else { - VP8LBitEntropy bit_entropy; - if (is_X_used) { - if (is_Y_used) { - VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats); - } else { - VP8LGetEntropyUnrefined(X, length, &bit_entropy, &stats); - } - } else { - if (is_Y_used) { - VP8LGetEntropyUnrefined(Y, length, &bit_entropy, &stats); - } else { - memset(&stats, 0, sizeof(stats)); - stats.counts[0] = 1; - stats.streaks[0][length > 3] = length; - VP8LBitEntropyInit(&bit_entropy); - } - } + VP8LBitEntropy bit_entropy; + const int is_h1_used = h1->is_used[index]; + const int is_h2_used = h2->is_used[index]; + const int is_trivial = h1->trivial_symbol[index] != VP8L_NON_TRIVIAL_SYM && + h1->trivial_symbol[index] == h2->trivial_symbol[index]; - return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); + if (is_trivial || !is_h1_used || !is_h2_used) { + if (is_h1_used) return h1->costs[index]; + return h2->costs[index]; } + assert(is_h1_used && is_h2_used); + + GetPopulationInfo(h1, index, &X, &length); + GetPopulationInfo(h2, index, &Y, &length); + VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats); + return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); } // Estimates the Entropy + Huffman + other block overhead size cost. -uint64_t VP8LHistogramEstimateBits(VP8LHistogram* const p) { - return PopulationCost(p->literal_, - VP8LHistogramNumCodes(p->palette_code_bits_), NULL, - &p->is_used_[0]) + - PopulationCost(p->red_, NUM_LITERAL_CODES, NULL, &p->is_used_[1]) + - PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL, &p->is_used_[2]) + - PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL, &p->is_used_[3]) + - PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL, - &p->is_used_[4]) + - ((uint64_t)(VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES, - NUM_LENGTH_CODES) + - VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES)) - << LOG_2_PRECISION_BITS); +uint64_t VP8LHistogramEstimateBits(const VP8LHistogram* const h) { + int i; + uint64_t cost = 0; + for (i = 0; i < 5; ++i) { + int length; + const uint32_t* population; + GetPopulationInfo(h, (HistogramIndex)i, &population, &length); + cost += PopulationCost(population, length, /*trivial_sym=*/NULL, + /*is_used=*/NULL); + } + cost += ((uint64_t)(VP8LExtraCost(h->literal + NUM_LITERAL_CODES, + NUM_LENGTH_CODES) + + VP8LExtraCost(h->distance, NUM_DISTANCE_CODES)) + << LOG_2_PRECISION_BITS); + return cost; } // ----------------------------------------------------------------------------- // Various histogram combine/cost-eval functions @@ -390,67 +423,80 @@ // Returns 1 if the cost of the combined histogram is less than the threshold. // Otherwise returns 0 and the cost is invalid due to early bail-out. WEBP_NODISCARD static int GetCombinedHistogramEntropy( const VP8LHistogram* const a, const VP8LHistogram* const b, - int64_t cost_threshold_in, uint64_t* cost) { - const int palette_code_bits = a->palette_code_bits_; - int trivial_at_end = 0; + int64_t cost_threshold_in, uint64_t* cost, uint64_t costs[5]) { + int i; const uint64_t cost_threshold = (uint64_t)cost_threshold_in; - assert(a->palette_code_bits_ == b->palette_code_bits_); + assert(a->palette_code_bits == b->palette_code_bits); if (cost_threshold_in <= 0) return 0; - *cost = GetCombinedEntropy(a->literal_, b->literal_, - VP8LHistogramNumCodes(palette_code_bits), - a->is_used_[0], b->is_used_[0], 0); - *cost += (uint64_t)VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES, - b->literal_ + NUM_LITERAL_CODES, - NUM_LENGTH_CODES) - << LOG_2_PRECISION_BITS; - if (*cost >= cost_threshold) return 0; + *cost = 0; - if (a->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM && - a->trivial_symbol_ == b->trivial_symbol_) { - // A, R and B are all 0 or 0xff. - const uint32_t color_a = (a->trivial_symbol_ >> 24) & 0xff; - const uint32_t color_r = (a->trivial_symbol_ >> 16) & 0xff; - const uint32_t color_b = (a->trivial_symbol_ >> 0) & 0xff; - if ((color_a == 0 || color_a == 0xff) && - (color_r == 0 || color_r == 0xff) && - (color_b == 0 || color_b == 0xff)) { - trivial_at_end = 1; - } + // No need to add the extra cost for length and distance as it is a constant + // that does not influence the histograms. + for (i = 0; i < 5; ++i) { + costs[i] = GetCombinedEntropy(a, b, (HistogramIndex)i); + *cost += costs[i]; + if (*cost >= cost_threshold) return 0; } - *cost += GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES, - a->is_used_[1], b->is_used_[1], trivial_at_end); - if (*cost >= cost_threshold) return 0; - - *cost += GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES, - a->is_used_[2], b->is_used_[2], trivial_at_end); - if (*cost >= cost_threshold) return 0; - - *cost += GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES, - a->is_used_[3], b->is_used_[3], trivial_at_end); - if (*cost >= cost_threshold) return 0; - - *cost += GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES, - a->is_used_[4], b->is_used_[4], 0); - *cost += (uint64_t)VP8LExtraCostCombined(a->distance_, b->distance_, - NUM_DISTANCE_CODES) - << LOG_2_PRECISION_BITS; - if (*cost >= cost_threshold) return 0; - return 1; } -static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const a, - const VP8LHistogram* const b, - VP8LHistogram* const out) { - VP8LHistogramAdd(a, b, out); - out->trivial_symbol_ = (a->trivial_symbol_ == b->trivial_symbol_) - ? a->trivial_symbol_ - : VP8L_NON_TRIVIAL_SYM; +static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const h1, + const VP8LHistogram* const h2, + VP8LHistogram* const hout) { + int i; + assert(h1->palette_code_bits == h2->palette_code_bits); + + for (i = 0; i < 5; ++i) { + int length; + const uint32_t *p1, *p2, *pout_const; + uint32_t* pout; + GetPopulationInfo(h1, (HistogramIndex)i, &p1, &length); + GetPopulationInfo(h2, (HistogramIndex)i, &p2, &length); + GetPopulationInfo(hout, (HistogramIndex)i, &pout_const, &length); + pout = (uint32_t*)pout_const; + if (h2 == hout) { + if (h1->is_used[i]) { + if (hout->is_used[i]) { + VP8LAddVectorEq(p1, pout, length); + } else { + memcpy(pout, p1, length * sizeof(pout[0])); + } + } + } else { + if (h1->is_used[i]) { + if (h2->is_used[i]) { + VP8LAddVector(p1, p2, pout, length); + } else { + memcpy(pout, p1, length * sizeof(pout[0])); + } + } else if (h2->is_used[i]) { + memcpy(pout, p2, length * sizeof(pout[0])); + } else { + memset(pout, 0, length * sizeof(pout[0])); + } + } + } + + for (i = 0; i < 5; ++i) { + hout->trivial_symbol[i] = h1->trivial_symbol[i] == h2->trivial_symbol[i] + ? h1->trivial_symbol[i] + : VP8L_NON_TRIVIAL_SYM; + hout->is_used[i] = h1->is_used[i] || h2->is_used[i]; + } +} + +static void UpdateHistogramCost(uint64_t bit_cost, uint64_t costs[5], + VP8LHistogram* const h) { + int i; + h->bit_cost = bit_cost; + for (i = 0; i < 5; ++i) { + h->costs[i] = costs[i]; + } } // Performs out = a + b, computing the cost C(a+b) - C(a) - C(b) while comparing // to the threshold value 'cost_threshold'. The score returned is // Score = C(a+b) - C(a) - C(b), where C(a) + C(b) is known and fixed. @@ -461,18 +507,19 @@ // Otherwise returns 0 and the cost is invalid due to early bail-out. WEBP_NODISCARD static int HistogramAddEval(const VP8LHistogram* const a, const VP8LHistogram* const b, VP8LHistogram* const out, int64_t cost_threshold) { - uint64_t cost; - const uint64_t sum_cost = a->bit_cost_ + b->bit_cost_; + const uint64_t sum_cost = a->bit_cost + b->bit_cost; + uint64_t bit_cost, costs[5]; SaturateAdd(sum_cost, &cost_threshold); - if (!GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) return 0; + if (!GetCombinedHistogramEntropy(a, b, cost_threshold, &bit_cost, costs)) { + return 0; + } HistogramAdd(a, b, out); - out->bit_cost_ = cost; - out->palette_code_bits_ = a->palette_code_bits_; + UpdateHistogramCost(bit_cost, costs, out); return 1; } // Same as HistogramAddEval(), except that the resulting histogram // is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit @@ -481,77 +528,66 @@ // Otherwise returns 0 and the cost is invalid due to early bail-out. WEBP_NODISCARD static int HistogramAddThresh(const VP8LHistogram* const a, const VP8LHistogram* const b, int64_t cost_threshold, int64_t* cost_out) { - uint64_t cost; + uint64_t cost, costs[5]; assert(a != NULL && b != NULL); - SaturateAdd(a->bit_cost_, &cost_threshold); - if (!GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) return 0; + SaturateAdd(a->bit_cost, &cost_threshold); + if (!GetCombinedHistogramEntropy(a, b, cost_threshold, &cost, costs)) { + return 0; + } - *cost_out = (int64_t)cost - (int64_t)a->bit_cost_; + *cost_out = (int64_t)cost - (int64_t)a->bit_cost; return 1; } // ----------------------------------------------------------------------------- // The structure to keep track of cost range for the three dominant entropy // symbols. typedef struct { - uint64_t literal_max_; - uint64_t literal_min_; - uint64_t red_max_; - uint64_t red_min_; - uint64_t blue_max_; - uint64_t blue_min_; + uint64_t literal_max; + uint64_t literal_min; + uint64_t red_max; + uint64_t red_min; + uint64_t blue_max; + uint64_t blue_min; } DominantCostRange; static void DominantCostRangeInit(DominantCostRange* const c) { - c->literal_max_ = 0; - c->literal_min_ = WEBP_UINT64_MAX; - c->red_max_ = 0; - c->red_min_ = WEBP_UINT64_MAX; - c->blue_max_ = 0; - c->blue_min_ = WEBP_UINT64_MAX; + c->literal_max = 0; + c->literal_min = WEBP_UINT64_MAX; + c->red_max = 0; + c->red_min = WEBP_UINT64_MAX; + c->blue_max = 0; + c->blue_min = WEBP_UINT64_MAX; } static void UpdateDominantCostRange( const VP8LHistogram* const h, DominantCostRange* const c) { - if (c->literal_max_ < h->literal_cost_) c->literal_max_ = h->literal_cost_; - if (c->literal_min_ > h->literal_cost_) c->literal_min_ = h->literal_cost_; - if (c->red_max_ < h->red_cost_) c->red_max_ = h->red_cost_; - if (c->red_min_ > h->red_cost_) c->red_min_ = h->red_cost_; - if (c->blue_max_ < h->blue_cost_) c->blue_max_ = h->blue_cost_; - if (c->blue_min_ > h->blue_cost_) c->blue_min_ = h->blue_cost_; + if (c->literal_max < h->costs[LITERAL]) c->literal_max = h->costs[LITERAL]; + if (c->literal_min > h->costs[LITERAL]) c->literal_min = h->costs[LITERAL]; + if (c->red_max < h->costs[RED]) c->red_max = h->costs[RED]; + if (c->red_min > h->costs[RED]) c->red_min = h->costs[RED]; + if (c->blue_max < h->costs[BLUE]) c->blue_max = h->costs[BLUE]; + if (c->blue_min > h->costs[BLUE]) c->blue_min = h->costs[BLUE]; } -static void UpdateHistogramCost(VP8LHistogram* const h) { - uint32_t alpha_sym, red_sym, blue_sym; - const uint64_t alpha_cost = - PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]); - const uint64_t distance_cost = - PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) + - ((uint64_t)VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES) - << LOG_2_PRECISION_BITS); - const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_); - h->literal_cost_ = - PopulationCost(h->literal_, num_codes, NULL, &h->is_used_[0]) + - ((uint64_t)VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES, - NUM_LENGTH_CODES) - << LOG_2_PRECISION_BITS); - h->red_cost_ = - PopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym, &h->is_used_[1]); - h->blue_cost_ = - PopulationCost(h->blue_, NUM_LITERAL_CODES, &blue_sym, &h->is_used_[2]); - h->bit_cost_ = h->literal_cost_ + h->red_cost_ + h->blue_cost_ + - alpha_cost + distance_cost; - if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) { - h->trivial_symbol_ = VP8L_NON_TRIVIAL_SYM; - } else { - h->trivial_symbol_ = - ((uint32_t)alpha_sym << 24) | (red_sym << 16) | (blue_sym << 0); +static void ComputeHistogramCost(VP8LHistogram* const h) { + int i; + // No need to add the extra cost for length and distance as it is a constant + // that does not influence the histograms. + for (i = 0; i < 5; ++i) { + const uint32_t* population; + int length; + GetPopulationInfo(h, i, &population, &length); + h->costs[i] = PopulationCost(population, length, &h->trivial_symbol[i], + &h->is_used[i]); } + h->bit_cost = h->costs[LITERAL] + h->costs[RED] + h->costs[BLUE] + + h->costs[ALPHA] + h->costs[DISTANCE]; } static int GetBinIdForEntropy(uint64_t min, uint64_t max, uint64_t val) { const uint64_t range = max - min; if (range > 0) { @@ -562,18 +598,18 @@ } } static int GetHistoBinIndex(const VP8LHistogram* const h, const DominantCostRange* const c, int low_effort) { - int bin_id = GetBinIdForEntropy(c->literal_min_, c->literal_max_, - h->literal_cost_); + int bin_id = + GetBinIdForEntropy(c->literal_min, c->literal_max, h->costs[LITERAL]); assert(bin_id < NUM_PARTITIONS); if (!low_effort) { - bin_id = bin_id * NUM_PARTITIONS - + GetBinIdForEntropy(c->red_min_, c->red_max_, h->red_cost_); - bin_id = bin_id * NUM_PARTITIONS - + GetBinIdForEntropy(c->blue_min_, c->blue_max_, h->blue_cost_); + bin_id = bin_id * NUM_PARTITIONS + + GetBinIdForEntropy(c->red_min, c->red_max, h->costs[RED]); + bin_id = bin_id * NUM_PARTITIONS + + GetBinIdForEntropy(c->blue_min, c->blue_max, h->costs[BLUE]); assert(bin_id < BIN_SIZE); } return bin_id; } @@ -588,90 +624,78 @@ assert(histo_bits > 0); VP8LHistogramSetClear(image_histo); while (VP8LRefsCursorOk(&c)) { const PixOrCopy* const v = c.cur_pos; const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits); - VP8LHistogramAddSinglePixOrCopy(histograms[ix], v, NULL, 0); + HistogramAddSinglePixOrCopy(histograms[ix], v, NULL, 0); x += PixOrCopyLength(v); while (x >= xsize) { x -= xsize; ++y; } VP8LRefsCursorNext(&c); } } // Copies the histograms and computes its bit_cost. -static const uint32_t kInvalidHistogramSymbol = (uint32_t)(-1); static void HistogramCopyAndAnalyze(VP8LHistogramSet* const orig_histo, - VP8LHistogramSet* const image_histo, - int* const num_used, - uint32_t* const histogram_symbols) { - int i, cluster_id; - int num_used_orig = *num_used; + VP8LHistogramSet* const image_histo) { + int i; VP8LHistogram** const orig_histograms = orig_histo->histograms; VP8LHistogram** const histograms = image_histo->histograms; assert(image_histo->max_size == orig_histo->max_size); - for (cluster_id = 0, i = 0; i < orig_histo->max_size; ++i) { + image_histo->size = 0; + for (i = 0; i < orig_histo->max_size; ++i) { VP8LHistogram* const histo = orig_histograms[i]; - UpdateHistogramCost(histo); + ComputeHistogramCost(histo); // Skip the histogram if it is completely empty, which can happen for tiles // with no information (when they are skipped because of LZ77). - if (!histo->is_used_[0] && !histo->is_used_[1] && !histo->is_used_[2] - && !histo->is_used_[3] && !histo->is_used_[4]) { - // The first histogram is always used. If an histogram is empty, we set - // its id to be the same as the previous one: this will improve - // compressibility for later LZ77. + if (!histo->is_used[LITERAL] && !histo->is_used[RED] && + !histo->is_used[BLUE] && !histo->is_used[ALPHA] && + !histo->is_used[DISTANCE]) { + // The first histogram is always used. assert(i > 0); - HistogramSetRemoveHistogram(image_histo, i, num_used); - HistogramSetRemoveHistogram(orig_histo, i, &num_used_orig); - histogram_symbols[i] = kInvalidHistogramSymbol; + orig_histograms[i] = NULL; } else { // Copy histograms from orig_histo[] to image_histo[]. - HistogramCopy(histo, histograms[i]); - histogram_symbols[i] = cluster_id++; - assert(cluster_id <= image_histo->max_size); + HistogramCopy(histo, histograms[image_histo->size]); + ++image_histo->size; } } } // Partition histograms to different entropy bins for three dominant (literal, // red and blue) symbol costs and compute the histogram aggregate bit_cost. static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo, - uint16_t* const bin_map, int low_effort) { int i; VP8LHistogram** const histograms = image_histo->histograms; const int histo_size = image_histo->size; DominantCostRange cost_range; DominantCostRangeInit(&cost_range); // Analyze the dominant (literal, red and blue) entropy costs. for (i = 0; i < histo_size; ++i) { - if (histograms[i] == NULL) continue; UpdateDominantCostRange(histograms[i], &cost_range); } // bin-hash histograms on three of the dominant (literal, red and blue) // symbol costs and store the resulting bin_id for each histogram. for (i = 0; i < histo_size; ++i) { - // bin_map[i] is not set to a special value as its use will later be guarded - // by another (histograms[i] == NULL). - if (histograms[i] == NULL) continue; - bin_map[i] = GetHistoBinIndex(histograms[i], &cost_range, low_effort); + histograms[i]->bin_id = + GetHistoBinIndex(histograms[i], &cost_range, low_effort); } } // Merges some histograms with same bin_id together if it's advantageous. // Sets the remaining histograms to NULL. // 'combine_cost_factor' has to be divided by 100. -static void HistogramCombineEntropyBin( - VP8LHistogramSet* const image_histo, int* num_used, - const uint32_t* const clusters, uint16_t* const cluster_mappings, - VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins, - int32_t combine_cost_factor, int low_effort) { +static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo, + VP8LHistogram* cur_combo, int num_bins, + int32_t combine_cost_factor, + int low_effort) { VP8LHistogram** const histograms = image_histo->histograms; int idx; struct { int16_t first; // position of the histogram that accumulates all // histograms with the same bin_id @@ -682,57 +706,64 @@ for (idx = 0; idx < num_bins; ++idx) { bin_info[idx].first = -1; bin_info[idx].num_combine_failures = 0; } - // By default, a cluster matches itself. - for (idx = 0; idx < *num_used; ++idx) cluster_mappings[idx] = idx; - for (idx = 0; idx < image_histo->size; ++idx) { - int bin_id, first; - if (histograms[idx] == NULL) continue; - bin_id = bin_map[idx]; - first = bin_info[bin_id].first; + for (idx = 0; idx < image_histo->size;) { + const int bin_id = histograms[idx]->bin_id; + const int first = bin_info[bin_id].first; if (first == -1) { bin_info[bin_id].first = idx; + ++idx; } else if (low_effort) { HistogramAdd(histograms[idx], histograms[first], histograms[first]); - HistogramSetRemoveHistogram(image_histo, idx, num_used); - cluster_mappings[clusters[idx]] = clusters[first]; + HistogramSetRemoveHistogram(image_histo, idx); } else { // try to merge #idx into #first (both share the same bin_id) - const uint64_t bit_cost = histograms[idx]->bit_cost_; + const uint64_t bit_cost = histograms[idx]->bit_cost; const int64_t bit_cost_thresh = -DivRound((int64_t)bit_cost * combine_cost_factor, 100); if (HistogramAddEval(histograms[first], histograms[idx], cur_combo, bit_cost_thresh)) { + const int max_combine_failures = 32; // Try to merge two histograms only if the combo is a trivial one or // the two candidate histograms are already non-trivial. // For some images, 'try_combine' turns out to be false for a lot of // histogram pairs. In that case, we fallback to combining // histograms as usual to avoid increasing the header size. - const int try_combine = - (cur_combo->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM) || - ((histograms[idx]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM) && - (histograms[first]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM)); - const int max_combine_failures = 32; + int try_combine = + cur_combo->trivial_symbol[RED] != VP8L_NON_TRIVIAL_SYM && + cur_combo->trivial_symbol[BLUE] != VP8L_NON_TRIVIAL_SYM && + cur_combo->trivial_symbol[ALPHA] != VP8L_NON_TRIVIAL_SYM; + if (!try_combine) { + try_combine = + histograms[idx]->trivial_symbol[RED] == VP8L_NON_TRIVIAL_SYM || + histograms[idx]->trivial_symbol[BLUE] == VP8L_NON_TRIVIAL_SYM || + histograms[idx]->trivial_symbol[ALPHA] == VP8L_NON_TRIVIAL_SYM; + try_combine &= + histograms[first]->trivial_symbol[RED] == VP8L_NON_TRIVIAL_SYM || + histograms[first]->trivial_symbol[BLUE] == VP8L_NON_TRIVIAL_SYM || + histograms[first]->trivial_symbol[ALPHA] == VP8L_NON_TRIVIAL_SYM; + } if (try_combine || bin_info[bin_id].num_combine_failures >= max_combine_failures) { // move the (better) merged histogram to its final slot HistogramSwap(&cur_combo, &histograms[first]); - HistogramSetRemoveHistogram(image_histo, idx, num_used); - cluster_mappings[clusters[idx]] = clusters[first]; + HistogramSetRemoveHistogram(image_histo, idx); } else { ++bin_info[bin_id].num_combine_failures; + ++idx; } + } else { + ++idx; } } } if (low_effort) { // for low_effort case, update the final cost when everything is merged for (idx = 0; idx < image_histo->size; ++idx) { - if (histograms[idx] == NULL) continue; - UpdateHistogramCost(histograms[idx]); + ComputeHistogramCost(histograms[idx]); } } } // Implement a Lehmer random number generator with a multiplicative constant of @@ -750,10 +781,11 @@ typedef struct { int idx1; int idx2; int64_t cost_diff; uint64_t cost_combo; + uint64_t costs[5]; } HistogramPair; typedef struct { HistogramPair* queue; int size; @@ -801,21 +833,34 @@ histo_queue->queue[0] = *pair; *pair = tmp; } } +// Replaces the bad_id with good_id in the pair. +static void HistoQueueFixPair(int bad_id, int good_id, + HistogramPair* const pair) { + if (pair->idx1 == bad_id) pair->idx1 = good_id; + if (pair->idx2 == bad_id) pair->idx2 = good_id; + if (pair->idx1 > pair->idx2) { + const int tmp = pair->idx1; + pair->idx1 = pair->idx2; + pair->idx2 = tmp; + } +} + // Update the cost diff and combo of a pair of histograms. This needs to be // called when the histograms have been merged with a third one. // Returns 1 if the cost diff is less than the threshold. // Otherwise returns 0 and the cost is invalid due to early bail-out. WEBP_NODISCARD static int HistoQueueUpdatePair(const VP8LHistogram* const h1, const VP8LHistogram* const h2, int64_t cost_threshold, HistogramPair* const pair) { - const int64_t sum_cost = h1->bit_cost_ + h2->bit_cost_; + const int64_t sum_cost = h1->bit_cost + h2->bit_cost; SaturateAdd(sum_cost, &cost_threshold); - if (!GetCombinedHistogramEntropy(h1, h2, cost_threshold, &pair->cost_combo)) { + if (!GetCombinedHistogramEntropy(h1, h2, cost_threshold, &pair->cost_combo, + pair->costs)) { return 0; } pair->cost_diff = (int64_t)pair->cost_combo - sum_cost; return 1; } @@ -854,12 +899,11 @@ // ----------------------------------------------------------------------------- // Combines histograms by continuously choosing the one with the highest cost // reduction. -static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo, - int* const num_used) { +static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) { int ok = 0; const int image_histo_size = image_histo->size; int i, j; VP8LHistogram** const histograms = image_histo->histograms; // Priority queue of histogram pairs. @@ -874,43 +918,43 @@ // therefore image_histo_size*(image_histo_size-1)/2 overall too if (!HistoQueueInit(&histo_queue, image_histo_size * image_histo_size)) { goto End; } + // Initialize the queue. for (i = 0; i < image_histo_size; ++i) { - if (image_histo->histograms[i] == NULL) continue; for (j = i + 1; j < image_histo_size; ++j) { - // Initialize queue. - if (image_histo->histograms[j] == NULL) continue; HistoQueuePush(&histo_queue, histograms, i, j, 0); } } while (histo_queue.size > 0) { const int idx1 = histo_queue.queue[0].idx1; const int idx2 = histo_queue.queue[0].idx2; HistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]); - histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; + UpdateHistogramCost(histo_queue.queue[0].cost_combo, + histo_queue.queue[0].costs, histograms[idx1]); // Remove merged histogram. - HistogramSetRemoveHistogram(image_histo, idx2, num_used); + HistogramSetRemoveHistogram(image_histo, idx2); // Remove pairs intersecting the just combined best pair. for (i = 0; i < histo_queue.size;) { HistogramPair* const p = histo_queue.queue + i; if (p->idx1 == idx1 || p->idx2 == idx1 || p->idx1 == idx2 || p->idx2 == idx2) { HistoQueuePopPair(&histo_queue, p); } else { + HistoQueueFixPair(image_histo->size, idx2, p); HistoQueueUpdateHead(&histo_queue, p); ++i; } } // Push new pairs formed with combined histogram to the queue. for (i = 0; i < image_histo->size; ++i) { - if (i == idx1 || image_histo->histograms[i] == NULL) continue; + if (i == idx1) continue; HistoQueuePush(&histo_queue, image_histo->histograms, idx1, i, 0); } } ok = 1; @@ -921,72 +965,53 @@ } // Perform histogram aggregation using a stochastic approach. // 'do_greedy' is set to 1 if a greedy approach needs to be performed // afterwards, 0 otherwise. -static int PairComparison(const void* idx1, const void* idx2) { - // To be used with bsearch: <0 when *idx1<*idx2, >0 if >, 0 when ==. - return (*(int*) idx1 - *(int*) idx2); -} static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo, - int* const num_used, int min_cluster_size, + int min_cluster_size, int* const do_greedy) { int j, iter; uint32_t seed = 1; int tries_with_no_success = 0; - const int outer_iters = *num_used; + const int outer_iters = image_histo->size; const int num_tries_no_success = outer_iters / 2; VP8LHistogram** const histograms = image_histo->histograms; // Priority queue of histogram pairs. Its size of 'kHistoQueueSize' // impacts the quality of the compression and the speed: the smaller the // faster but the worse for the compression. HistoQueue histo_queue; const int kHistoQueueSize = 9; int ok = 0; - // mapping from an index in image_histo with no NULL histogram to the full - // blown image_histo. - int* mappings; - if (*num_used < min_cluster_size) { + if (image_histo->size < min_cluster_size) { *do_greedy = 1; return 1; } - mappings = (int*) WebPSafeMalloc(*num_used, sizeof(*mappings)); - if (mappings == NULL) return 0; if (!HistoQueueInit(&histo_queue, kHistoQueueSize)) goto End; - // Fill the initial mapping. - for (j = 0, iter = 0; iter < image_histo->size; ++iter) { - if (histograms[iter] == NULL) continue; - mappings[j++] = iter; - } - assert(j == *num_used); // Collapse similar histograms in 'image_histo'. - for (iter = 0; - iter < outer_iters && *num_used >= min_cluster_size && - ++tries_with_no_success < num_tries_no_success; - ++iter) { - int* mapping_index; + for (iter = 0; iter < outer_iters && image_histo->size >= min_cluster_size && + ++tries_with_no_success < num_tries_no_success; + ++iter) { int64_t best_cost = (histo_queue.size == 0) ? 0 : histo_queue.queue[0].cost_diff; int best_idx1 = -1, best_idx2 = 1; - const uint32_t rand_range = (*num_used - 1) * (*num_used); - // (*num_used) / 2 was chosen empirically. Less means faster but worse - // compression. - const int num_tries = (*num_used) / 2; + const uint32_t rand_range = (image_histo->size - 1) * (image_histo->size); + // (image_histo->size) / 2 was chosen empirically. Less means faster but + // worse compression. + const int num_tries = (image_histo->size) / 2; // Pick random samples. - for (j = 0; *num_used >= 2 && j < num_tries; ++j) { + for (j = 0; image_histo->size >= 2 && j < num_tries; ++j) { int64_t curr_cost; // Choose two different histograms at random and try to combine them. const uint32_t tmp = MyRand(&seed) % rand_range; - uint32_t idx1 = tmp / (*num_used - 1); - uint32_t idx2 = tmp % (*num_used - 1); + uint32_t idx1 = tmp / (image_histo->size - 1); + uint32_t idx2 = tmp % (image_histo->size - 1); if (idx2 >= idx1) ++idx2; - idx1 = mappings[idx1]; - idx2 = mappings[idx2]; // Calculate cost reduction on combination. curr_cost = HistoQueuePush(&histo_queue, histograms, idx1, idx2, best_cost); if (curr_cost < 0) { // found a better pair? @@ -999,77 +1024,59 @@ // Get the best histograms. best_idx1 = histo_queue.queue[0].idx1; best_idx2 = histo_queue.queue[0].idx2; assert(best_idx1 < best_idx2); - // Pop best_idx2 from mappings. - mapping_index = (int*) bsearch(&best_idx2, mappings, *num_used, - sizeof(best_idx2), &PairComparison); - assert(mapping_index != NULL); - memmove(mapping_index, mapping_index + 1, sizeof(*mapping_index) * - ((*num_used) - (mapping_index - mappings) - 1)); // Merge the histograms and remove best_idx2 from the queue. HistogramAdd(histograms[best_idx2], histograms[best_idx1], histograms[best_idx1]); - histograms[best_idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; - HistogramSetRemoveHistogram(image_histo, best_idx2, num_used); + UpdateHistogramCost(histo_queue.queue[0].cost_combo, + histo_queue.queue[0].costs, histograms[best_idx1]); + HistogramSetRemoveHistogram(image_histo, best_idx2); // Parse the queue and update each pair that deals with best_idx1, // best_idx2 or image_histo_size. for (j = 0; j < histo_queue.size;) { HistogramPair* const p = histo_queue.queue + j; const int is_idx1_best = p->idx1 == best_idx1 || p->idx1 == best_idx2; const int is_idx2_best = p->idx2 == best_idx1 || p->idx2 == best_idx2; - int do_eval = 0; // The front pair could have been duplicated by a random pick so // check for it all the time nevertheless. if (is_idx1_best && is_idx2_best) { HistoQueuePopPair(&histo_queue, p); continue; } // Any pair containing one of the two best indices should only refer to // best_idx1. Its cost should also be updated. - if (is_idx1_best) { - p->idx1 = best_idx1; - do_eval = 1; - } else if (is_idx2_best) { - p->idx2 = best_idx1; - do_eval = 1; - } - // Make sure the index order is respected. - if (p->idx1 > p->idx2) { - const int tmp = p->idx2; - p->idx2 = p->idx1; - p->idx1 = tmp; - } - if (do_eval) { + if (is_idx1_best || is_idx2_best) { + HistoQueueFixPair(best_idx2, best_idx1, p); // Re-evaluate the cost of an updated pair. if (!HistoQueueUpdatePair(histograms[p->idx1], histograms[p->idx2], 0, p)) { HistoQueuePopPair(&histo_queue, p); continue; } } + HistoQueueFixPair(image_histo->size, best_idx2, p); HistoQueueUpdateHead(&histo_queue, p); ++j; } tries_with_no_success = 0; } - *do_greedy = (*num_used <= min_cluster_size); + *do_greedy = (image_histo->size <= min_cluster_size); ok = 1; End: HistoQueueClear(&histo_queue); - WebPSafeFree(mappings); return ok; } // ----------------------------------------------------------------------------- // Histogram refinement // Find the best 'out' histogram for each of the 'in' histograms. // At call-time, 'out' contains the histograms of the clusters. -// Note: we assume that out[]->bit_cost_ is already up-to-date. +// Note: we assume that out[]->bit_cost is already up-to-date. static void HistogramRemap(const VP8LHistogramSet* const in, VP8LHistogramSet* const out, uint32_t* const symbols) { int i; VP8LHistogram** const in_histo = in->histograms; @@ -1124,74 +1131,10 @@ if (quality <= 50) combine_cost_factor /= 2; } return combine_cost_factor; } -// Given a HistogramSet 'set', the mapping of clusters 'cluster_mapping' and the -// current assignment of the cells in 'symbols', merge the clusters and -// assign the smallest possible clusters values. -static void OptimizeHistogramSymbols(const VP8LHistogramSet* const set, - uint16_t* const cluster_mappings, - uint32_t num_clusters, - uint16_t* const cluster_mappings_tmp, - uint32_t* const symbols) { - uint32_t i, cluster_max; - int do_continue = 1; - // First, assign the lowest cluster to each pixel. - while (do_continue) { - do_continue = 0; - for (i = 0; i < num_clusters; ++i) { - int k; - k = cluster_mappings[i]; - while (k != cluster_mappings[k]) { - cluster_mappings[k] = cluster_mappings[cluster_mappings[k]]; - k = cluster_mappings[k]; - } - if (k != cluster_mappings[i]) { - do_continue = 1; - cluster_mappings[i] = k; - } - } - } - // Create a mapping from a cluster id to its minimal version. - cluster_max = 0; - memset(cluster_mappings_tmp, 0, - set->max_size * sizeof(*cluster_mappings_tmp)); - assert(cluster_mappings[0] == 0); - // Re-map the ids. - for (i = 0; i < (uint32_t)set->max_size; ++i) { - int cluster; - if (symbols[i] == kInvalidHistogramSymbol) continue; - cluster = cluster_mappings[symbols[i]]; - assert(symbols[i] < num_clusters); - if (cluster > 0 && cluster_mappings_tmp[cluster] == 0) { - ++cluster_max; - cluster_mappings_tmp[cluster] = cluster_max; - } - symbols[i] = cluster_mappings_tmp[cluster]; - } - - // Make sure all cluster values are used. - cluster_max = 0; - for (i = 0; i < (uint32_t)set->max_size; ++i) { - if (symbols[i] == kInvalidHistogramSymbol) continue; - if (symbols[i] <= cluster_max) continue; - ++cluster_max; - assert(symbols[i] == cluster_max); - } -} - -static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) { - uint32_t size; - int i; - for (i = 0, size = 0; i < image_histo->size; ++i) { - if (image_histo->histograms[i] == NULL) continue; - image_histo->histograms[size++] = image_histo->histograms[i]; - } - image_histo->size = size; -} - int VP8LGetHistoImageSymbols(int xsize, int ysize, const VP8LBackwardRefs* const refs, int quality, int low_effort, int histogram_bits, int cache_bits, VP8LHistogramSet* const image_histo, VP8LHistogram* const tmp_histo, @@ -1208,74 +1151,57 @@ // Don't attempt linear bin-partition heuristic for // histograms of small sizes (as bin_map will be very sparse) and // maximum quality q==100 (to preserve the compression gains at that level). const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE; int entropy_combine; - uint16_t* const map_tmp = - (uint16_t*)WebPSafeMalloc(2 * image_histo_raw_size, sizeof(*map_tmp)); - uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size; - int num_used = image_histo_raw_size; - if (orig_histo == NULL || map_tmp == NULL) { + if (orig_histo == NULL) { WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } // Construct the histograms from backward references. HistogramBuild(xsize, histogram_bits, refs, orig_histo); - // Copies the histograms and computes its bit_cost. - // histogram_symbols is optimized - HistogramCopyAndAnalyze(orig_histo, image_histo, &num_used, - histogram_symbols); - + HistogramCopyAndAnalyze(orig_histo, image_histo); entropy_combine = - (num_used > entropy_combine_num_bins * 2) && (quality < 100); + (image_histo->size > entropy_combine_num_bins * 2) && (quality < 100); if (entropy_combine) { - uint16_t* const bin_map = map_tmp; const int32_t combine_cost_factor = GetCombineCostFactor(image_histo_raw_size, quality); - const uint32_t num_clusters = num_used; - HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort); + HistogramAnalyzeEntropyBin(image_histo, low_effort); // Collapse histograms with similar entropy. - HistogramCombineEntropyBin( - image_histo, &num_used, histogram_symbols, cluster_mappings, tmp_histo, - bin_map, entropy_combine_num_bins, combine_cost_factor, low_effort); - OptimizeHistogramSymbols(image_histo, cluster_mappings, num_clusters, - map_tmp, histogram_symbols); + HistogramCombineEntropyBin(image_histo, tmp_histo, entropy_combine_num_bins, + combine_cost_factor, low_effort); } // Don't combine the histograms using stochastic and greedy heuristics for // low-effort compression mode. if (!low_effort || !entropy_combine) { // cubic ramp between 1 and MAX_HISTO_GREEDY: const int threshold_size = (int)(1 + DivRound(quality * quality * quality * (MAX_HISTO_GREEDY - 1), 100 * 100 * 100)); int do_greedy; - if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size, - &do_greedy)) { + if (!HistogramCombineStochastic(image_histo, threshold_size, &do_greedy)) { WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } if (do_greedy) { - RemoveEmptyHistograms(image_histo); - if (!HistogramCombineGreedy(image_histo, &num_used)) { + if (!HistogramCombineGreedy(image_histo)) { WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } } } // Find the optimal map from original histograms to the final ones. - RemoveEmptyHistograms(image_histo); HistogramRemap(orig_histo, image_histo, histogram_symbols); if (!WebPReportProgress(pic, *percent + percent_range, percent)) { goto Error; } Error: VP8LFreeHistogramSet(orig_histo); - WebPSafeFree(map_tmp); return (pic->error_code == VP8_ENC_OK); } diff --git a/media/libwebp/src/enc/iterator_enc.c b/media/libwebp/src/enc/iterator_enc.c --- a/media/libwebp/src/enc/iterator_enc.c +++ b/media/libwebp/src/enc/iterator_enc.c @@ -12,92 +12,95 @@ // Author: Skal (pascal.massimino@gmail.com) #include #include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/enc/vp8i_enc.h" +#include "src/utils/utils.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // VP8Iterator //------------------------------------------------------------------------------ static void InitLeft(VP8EncIterator* const it) { - it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = - (it->y_ > 0) ? 129 : 127; - memset(it->y_left_, 129, 16); - memset(it->u_left_, 129, 8); - memset(it->v_left_, 129, 8); - it->left_nz_[8] = 0; - if (it->top_derr_ != NULL) { - memset(&it->left_derr_, 0, sizeof(it->left_derr_)); + it->y_left[-1] = it->u_left[-1] = it->v_left[-1] = + (it->y > 0) ? 129 : 127; + memset(it->y_left, 129, 16); + memset(it->u_left, 129, 8); + memset(it->v_left, 129, 8); + it->left_nz[8] = 0; + if (it->top_derr != NULL) { + memset(&it->left_derr, 0, sizeof(it->left_derr)); } } static void InitTop(VP8EncIterator* const it) { - const VP8Encoder* const enc = it->enc_; - const size_t top_size = enc->mb_w_ * 16; - memset(enc->y_top_, 127, 2 * top_size); - memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_)); - if (enc->top_derr_ != NULL) { - memset(enc->top_derr_, 0, enc->mb_w_ * sizeof(*enc->top_derr_)); + const VP8Encoder* const enc = it->enc; + const size_t top_size = enc->mb_w * 16; + memset(enc->y_top, 127, 2 * top_size); + memset(enc->nz, 0, enc->mb_w * sizeof(*enc->nz)); + if (enc->top_derr != NULL) { + memset(enc->top_derr, 0, enc->mb_w * sizeof(*enc->top_derr)); } } void VP8IteratorSetRow(VP8EncIterator* const it, int y) { - VP8Encoder* const enc = it->enc_; - it->x_ = 0; - it->y_ = y; - it->bw_ = &enc->parts_[y & (enc->num_parts_ - 1)]; - it->preds_ = enc->preds_ + y * 4 * enc->preds_w_; - it->nz_ = enc->nz_; - it->mb_ = enc->mb_info_ + y * enc->mb_w_; - it->y_top_ = enc->y_top_; - it->uv_top_ = enc->uv_top_; + VP8Encoder* const enc = it->enc; + it->x = 0; + it->y = y; + it->bw = &enc->parts[y & (enc->num_parts - 1)]; + it->preds = enc->preds + y * 4 * enc->preds_w; + it->nz = enc->nz; + it->mb = enc->mb_info + y * enc->mb_w; + it->y_top = enc->y_top; + it->uv_top = enc->uv_top; InitLeft(it); } // restart a scan static void VP8IteratorReset(VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; + VP8Encoder* const enc = it->enc; VP8IteratorSetRow(it, 0); - VP8IteratorSetCountDown(it, enc->mb_w_ * enc->mb_h_); // default + VP8IteratorSetCountDown(it, enc->mb_w * enc->mb_h); // default InitTop(it); - memset(it->bit_count_, 0, sizeof(it->bit_count_)); - it->do_trellis_ = 0; + memset(it->bit_count, 0, sizeof(it->bit_count)); + it->do_trellis = 0; } void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down) { - it->count_down_ = it->count_down0_ = count_down; + it->count_down = it->count_down0 = count_down; } int VP8IteratorIsDone(const VP8EncIterator* const it) { - return (it->count_down_ <= 0); + return (it->count_down <= 0); } void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) { - it->enc_ = enc; - it->yuv_in_ = (uint8_t*)WEBP_ALIGN(it->yuv_mem_); - it->yuv_out_ = it->yuv_in_ + YUV_SIZE_ENC; - it->yuv_out2_ = it->yuv_out_ + YUV_SIZE_ENC; - it->yuv_p_ = it->yuv_out2_ + YUV_SIZE_ENC; - it->lf_stats_ = enc->lf_stats_; - it->percent0_ = enc->percent_; - it->y_left_ = (uint8_t*)WEBP_ALIGN(it->yuv_left_mem_ + 1); - it->u_left_ = it->y_left_ + 16 + 16; - it->v_left_ = it->u_left_ + 16; - it->top_derr_ = enc->top_derr_; + it->enc = enc; + it->yuv_in = (uint8_t*)WEBP_ALIGN(it->yuv_mem); + it->yuv_out = it->yuv_in + YUV_SIZE_ENC; + it->yuv_out2 = it->yuv_out + YUV_SIZE_ENC; + it->yuv_p = it->yuv_out2 + YUV_SIZE_ENC; + it->lf_stats = enc->lf_stats; + it->percent0 = enc->percent; + it->y_left = (uint8_t*)WEBP_ALIGN(it->yuv_left_mem + 1); + it->u_left = it->y_left + 16 + 16; + it->v_left = it->u_left + 16; + it->top_derr = enc->top_derr; VP8IteratorReset(it); } int VP8IteratorProgress(const VP8EncIterator* const it, int delta) { - VP8Encoder* const enc = it->enc_; - if (delta && enc->pic_->progress_hook != NULL) { - const int done = it->count_down0_ - it->count_down_; - const int percent = (it->count_down0_ <= 0) - ? it->percent0_ - : it->percent0_ + delta * done / it->count_down0_; - return WebPReportProgress(enc->pic_, percent, &enc->percent_); + VP8Encoder* const enc = it->enc; + if (delta && enc->pic->progress_hook != NULL) { + const int done = it->count_down0 - it->count_down; + const int percent = (it->count_down0 <= 0) + ? it->percent0 + : it->percent0 + delta * done / it->count_down0; + return WebPReportProgress(enc->pic, percent, &enc->percent); } return 1; } //------------------------------------------------------------------------------ @@ -129,45 +132,45 @@ for (i = 0; i < len; ++i, src += src_stride) dst[i] = *src; for (; i < total_len; ++i) dst[i] = dst[len - 1]; } void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32) { - const VP8Encoder* const enc = it->enc_; - const int x = it->x_, y = it->y_; - const WebPPicture* const pic = enc->pic_; + const VP8Encoder* const enc = it->enc; + const int x = it->x, y = it->y; + const WebPPicture* const pic = enc->pic; const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16; const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8; const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8; const int w = MinSize(pic->width - x * 16, 16); const int h = MinSize(pic->height - y * 16, 16); const int uv_w = (w + 1) >> 1; const int uv_h = (h + 1) >> 1; - ImportBlock(ysrc, pic->y_stride, it->yuv_in_ + Y_OFF_ENC, w, h, 16); - ImportBlock(usrc, pic->uv_stride, it->yuv_in_ + U_OFF_ENC, uv_w, uv_h, 8); - ImportBlock(vsrc, pic->uv_stride, it->yuv_in_ + V_OFF_ENC, uv_w, uv_h, 8); + ImportBlock(ysrc, pic->y_stride, it->yuv_in + Y_OFF_ENC, w, h, 16); + ImportBlock(usrc, pic->uv_stride, it->yuv_in + U_OFF_ENC, uv_w, uv_h, 8); + ImportBlock(vsrc, pic->uv_stride, it->yuv_in + V_OFF_ENC, uv_w, uv_h, 8); if (tmp_32 == NULL) return; // Import source (uncompressed) samples into boundary. if (x == 0) { InitLeft(it); } else { if (y == 0) { - it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = 127; + it->y_left[-1] = it->u_left[-1] = it->v_left[-1] = 127; } else { - it->y_left_[-1] = ysrc[- 1 - pic->y_stride]; - it->u_left_[-1] = usrc[- 1 - pic->uv_stride]; - it->v_left_[-1] = vsrc[- 1 - pic->uv_stride]; + it->y_left[-1] = ysrc[- 1 - pic->y_stride]; + it->u_left[-1] = usrc[- 1 - pic->uv_stride]; + it->v_left[-1] = vsrc[- 1 - pic->uv_stride]; } - ImportLine(ysrc - 1, pic->y_stride, it->y_left_, h, 16); - ImportLine(usrc - 1, pic->uv_stride, it->u_left_, uv_h, 8); - ImportLine(vsrc - 1, pic->uv_stride, it->v_left_, uv_h, 8); + ImportLine(ysrc - 1, pic->y_stride, it->y_left, h, 16); + ImportLine(usrc - 1, pic->uv_stride, it->u_left, uv_h, 8); + ImportLine(vsrc - 1, pic->uv_stride, it->v_left, uv_h, 8); } - it->y_top_ = tmp_32 + 0; - it->uv_top_ = tmp_32 + 16; + it->y_top = tmp_32 + 0; + it->uv_top = tmp_32 + 16; if (y == 0) { memset(tmp_32, 127, 32 * sizeof(*tmp_32)); } else { ImportLine(ysrc - pic->y_stride, 1, tmp_32, w, 16); ImportLine(usrc - pic->uv_stride, 1, tmp_32 + 16, uv_w, 8); @@ -186,17 +189,17 @@ src += BPS; } } void VP8IteratorExport(const VP8EncIterator* const it) { - const VP8Encoder* const enc = it->enc_; - if (enc->config_->show_compressed) { - const int x = it->x_, y = it->y_; - const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC; - const uint8_t* const usrc = it->yuv_out_ + U_OFF_ENC; - const uint8_t* const vsrc = it->yuv_out_ + V_OFF_ENC; - const WebPPicture* const pic = enc->pic_; + const VP8Encoder* const enc = it->enc; + if (enc->config->show_compressed) { + const int x = it->x, y = it->y; + const uint8_t* const ysrc = it->yuv_out + Y_OFF_ENC; + const uint8_t* const usrc = it->yuv_out + U_OFF_ENC; + const uint8_t* const vsrc = it->yuv_out + V_OFF_ENC; + const WebPPicture* const pic = enc->pic; uint8_t* const ydst = pic->y + (y * pic->y_stride + x) * 16; uint8_t* const udst = pic->u + (y * pic->uv_stride + x) * 8; uint8_t* const vdst = pic->v + (y * pic->uv_stride + x) * 8; int w = (pic->width - x * 16); int h = (pic->height - y * 16); @@ -232,13 +235,13 @@ // Convert packed context to byte array #define BIT(nz, n) (!!((nz) & (1 << (n)))) void VP8IteratorNzToBytes(VP8EncIterator* const it) { - const int tnz = it->nz_[0], lnz = it->nz_[-1]; - int* const top_nz = it->top_nz_; - int* const left_nz = it->left_nz_; + const int tnz = it->nz[0], lnz = it->nz[-1]; + int* const top_nz = it->top_nz; + int* const left_nz = it->left_nz; // Top-Y top_nz[0] = BIT(tnz, 12); top_nz[1] = BIT(tnz, 13); top_nz[2] = BIT(tnz, 14); @@ -266,12 +269,12 @@ // left-DC is special, iterated separately } void VP8IteratorBytesToNz(VP8EncIterator* const it) { uint32_t nz = 0; - const int* const top_nz = it->top_nz_; - const int* const left_nz = it->left_nz_; + const int* const top_nz = it->top_nz; + const int* const left_nz = it->left_nz; // top nz |= (top_nz[0] << 12) | (top_nz[1] << 13); nz |= (top_nz[2] << 14) | (top_nz[3] << 15); nz |= (top_nz[4] << 18) | (top_nz[5] << 19); nz |= (top_nz[6] << 22) | (top_nz[7] << 23); @@ -279,90 +282,90 @@ // left nz |= (left_nz[0] << 3) | (left_nz[1] << 7); nz |= (left_nz[2] << 11); nz |= (left_nz[4] << 17) | (left_nz[6] << 21); - *it->nz_ = nz; + *it->nz = nz; } #undef BIT //------------------------------------------------------------------------------ // Advance to the next position, doing the bookkeeping. void VP8IteratorSaveBoundary(VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - const int x = it->x_, y = it->y_; - const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC; - const uint8_t* const uvsrc = it->yuv_out_ + U_OFF_ENC; - if (x < enc->mb_w_ - 1) { // left + VP8Encoder* const enc = it->enc; + const int x = it->x, y = it->y; + const uint8_t* const ysrc = it->yuv_out + Y_OFF_ENC; + const uint8_t* const uvsrc = it->yuv_out + U_OFF_ENC; + if (x < enc->mb_w - 1) { // left int i; for (i = 0; i < 16; ++i) { - it->y_left_[i] = ysrc[15 + i * BPS]; + it->y_left[i] = ysrc[15 + i * BPS]; } for (i = 0; i < 8; ++i) { - it->u_left_[i] = uvsrc[7 + i * BPS]; - it->v_left_[i] = uvsrc[15 + i * BPS]; + it->u_left[i] = uvsrc[7 + i * BPS]; + it->v_left[i] = uvsrc[15 + i * BPS]; } // top-left (before 'top'!) - it->y_left_[-1] = it->y_top_[15]; - it->u_left_[-1] = it->uv_top_[0 + 7]; - it->v_left_[-1] = it->uv_top_[8 + 7]; + it->y_left[-1] = it->y_top[15]; + it->u_left[-1] = it->uv_top[0 + 7]; + it->v_left[-1] = it->uv_top[8 + 7]; } - if (y < enc->mb_h_ - 1) { // top - memcpy(it->y_top_, ysrc + 15 * BPS, 16); - memcpy(it->uv_top_, uvsrc + 7 * BPS, 8 + 8); + if (y < enc->mb_h - 1) { // top + memcpy(it->y_top, ysrc + 15 * BPS, 16); + memcpy(it->uv_top, uvsrc + 7 * BPS, 8 + 8); } } int VP8IteratorNext(VP8EncIterator* const it) { - if (++it->x_ == it->enc_->mb_w_) { - VP8IteratorSetRow(it, ++it->y_); + if (++it->x == it->enc->mb_w) { + VP8IteratorSetRow(it, ++it->y); } else { - it->preds_ += 4; - it->mb_ += 1; - it->nz_ += 1; - it->y_top_ += 16; - it->uv_top_ += 16; + it->preds += 4; + it->mb += 1; + it->nz += 1; + it->y_top += 16; + it->uv_top += 16; } - return (0 < --it->count_down_); + return (0 < --it->count_down); } //------------------------------------------------------------------------------ // Helper function to set mode properties void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) { - uint8_t* preds = it->preds_; + uint8_t* preds = it->preds; int y; for (y = 0; y < 4; ++y) { memset(preds, mode, 4); - preds += it->enc_->preds_w_; + preds += it->enc->preds_w; } - it->mb_->type_ = 1; + it->mb->type = 1; } void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes) { - uint8_t* preds = it->preds_; + uint8_t* preds = it->preds; int y; for (y = 4; y > 0; --y) { memcpy(preds, modes, 4 * sizeof(*modes)); - preds += it->enc_->preds_w_; + preds += it->enc->preds_w; modes += 4; } - it->mb_->type_ = 0; + it->mb->type = 0; } void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode) { - it->mb_->uv_mode_ = mode; + it->mb->uv_mode = mode; } void VP8SetSkip(const VP8EncIterator* const it, int skip) { - it->mb_->skip_ = skip; + it->mb->skip = skip; } void VP8SetSegment(const VP8EncIterator* const it, int segment) { - it->mb_->segment_ = segment; + it->mb->segment = segment; } //------------------------------------------------------------------------------ // Intra4x4 sub-blocks iteration // @@ -401,70 +404,70 @@ 9, 13, 17, 21, 5, 9, 13, 17 }; void VP8IteratorStartI4(VP8EncIterator* const it) { - const VP8Encoder* const enc = it->enc_; + const VP8Encoder* const enc = it->enc; int i; - it->i4_ = 0; // first 4x4 sub-block - it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[0]; + it->i4 = 0; // first 4x4 sub-block + it->i4_top = it->i4_boundary + VP8TopLeftI4[0]; // Import the boundary samples for (i = 0; i < 17; ++i) { // left - it->i4_boundary_[i] = it->y_left_[15 - i]; + it->i4_boundary[i] = it->y_left[15 - i]; } for (i = 0; i < 16; ++i) { // top - it->i4_boundary_[17 + i] = it->y_top_[i]; + it->i4_boundary[17 + i] = it->y_top[i]; } // top-right samples have a special case on the far right of the picture - if (it->x_ < enc->mb_w_ - 1) { + if (it->x < enc->mb_w - 1) { for (i = 16; i < 16 + 4; ++i) { - it->i4_boundary_[17 + i] = it->y_top_[i]; + it->i4_boundary[17 + i] = it->y_top[i]; } } else { // else, replicate the last valid pixel four times for (i = 16; i < 16 + 4; ++i) { - it->i4_boundary_[17 + i] = it->i4_boundary_[17 + 15]; + it->i4_boundary[17 + i] = it->i4_boundary[17 + 15]; } } #if WEBP_AARCH64 && BPS == 32 && defined(WEBP_MSAN) - // Intra4Preds_NEON() reads 3 uninitialized bytes from i4_boundary_ when top + // Intra4Preds_NEON() reads 3 uninitialized bytes from 'i4_boundary' when top // is positioned at offset 29 (VP8TopLeftI4[3]). The values are not used // meaningfully, but due to limitations in MemorySanitizer related to // modeling of tbl instructions, a warning will be issued. This can be // removed if MSan is updated to support the instructions. See // https://issues.webmproject.org/372109644. - memset(it->i4_boundary_ + sizeof(it->i4_boundary_) - 3, 0xaa, 3); + memset(it->i4_boundary + sizeof(it->i4_boundary) - 3, 0xaa, 3); #endif VP8IteratorNzToBytes(it); // import the non-zero context } int VP8IteratorRotateI4(VP8EncIterator* const it, const uint8_t* const yuv_out) { - const uint8_t* const blk = yuv_out + VP8Scan[it->i4_]; - uint8_t* const top = it->i4_top_; + const uint8_t* const blk = yuv_out + VP8Scan[it->i4]; + uint8_t* const top = it->i4_top; int i; // Update the cache with 7 fresh samples for (i = 0; i <= 3; ++i) { top[-4 + i] = blk[i + 3 * BPS]; // store future top samples } - if ((it->i4_ & 3) != 3) { // if not on the right sub-blocks #3, #7, #11, #15 + if ((it->i4 & 3) != 3) { // if not on the right sub-blocks #3, #7, #11, #15 for (i = 0; i <= 2; ++i) { // store future left samples top[i] = blk[3 + (2 - i) * BPS]; } } else { // else replicate top-right samples, as says the specs. for (i = 0; i <= 3; ++i) { top[i] = top[i + 4]; } } // move pointers to next sub-block - ++it->i4_; - if (it->i4_ == 16) { // we're done + ++it->i4; + if (it->i4 == 16) { // we're done return 0; } - it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[it->i4_]; + it->i4_top = it->i4_boundary + VP8TopLeftI4[it->i4]; return 1; } //------------------------------------------------------------------------------ diff --git a/media/libwebp/src/enc/near_lossless_enc.c b/media/libwebp/src/enc/near_lossless_enc.c --- a/media/libwebp/src/enc/near_lossless_enc.c +++ b/media/libwebp/src/enc/near_lossless_enc.c @@ -14,14 +14,17 @@ // Author: Jyrki Alakuijala (jyrki@google.com) // Converted to C by Aleksander Kramarz (akramarz@google.com) #include #include +#include #include "src/dsp/lossless_common.h" +#include "src/webp/types.h" +#include "src/enc/vp8li_enc.h" #include "src/utils/utils.h" -#include "src/enc/vp8li_enc.h" +#include "src/webp/encode.h" #if (WEBP_NEAR_LOSSLESS == 1) #define MIN_DIM_FOR_NEAR_LOSSLESS 64 #define MAX_LIMIT_BITS 5 diff --git a/media/libwebp/src/enc/picture_csp_enc.c b/media/libwebp/src/enc/picture_csp_enc.c --- a/media/libwebp/src/enc/picture_csp_enc.c +++ b/media/libwebp/src/enc/picture_csp_enc.c @@ -10,22 +10,25 @@ // WebPPicture utils for colorspace conversion // // Author: Skal (pascal.massimino@gmail.com) #include +#include #include -#include +#include #include "sharpyuv/sharpyuv.h" #include "sharpyuv/sharpyuv_csp.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" +#include "src/dsp/lossless.h" +#include "src/dsp/yuv.h" #include "src/enc/vp8i_enc.h" #include "src/utils/random_utils.h" #include "src/utils/utils.h" -#include "src/dsp/dsp.h" -#include "src/dsp/lossless.h" -#include "src/dsp/yuv.h" -#include "src/dsp/cpu.h" +#include "src/webp/encode.h" +#include "src/webp/types.h" #if defined(WEBP_USE_THREAD) && !defined(_WIN32) #include #endif diff --git a/media/libwebp/src/enc/picture_enc.c b/media/libwebp/src/enc/picture_enc.c --- a/media/libwebp/src/enc/picture_enc.c +++ b/media/libwebp/src/enc/picture_enc.c @@ -12,13 +12,16 @@ // Author: Skal (pascal.massimino@gmail.com) #include #include #include +#include #include "src/enc/vp8i_enc.h" #include "src/utils/utils.h" +#include "src/webp/encode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // WebPPicture //------------------------------------------------------------------------------ @@ -224,13 +227,11 @@ } void WebPMemoryWriterClear(WebPMemoryWriter* writer) { if (writer != NULL) { WebPSafeFree(writer->mem); - writer->mem = NULL; - writer->size = 0; - writer->max_size = 0; + WebPMemoryWriterInit(writer); } } //------------------------------------------------------------------------------ // Simplest high-level calls: diff --git a/media/libwebp/src/enc/picture_psnr_enc.c b/media/libwebp/src/enc/picture_psnr_enc.c --- a/media/libwebp/src/enc/picture_psnr_enc.c +++ b/media/libwebp/src/enc/picture_psnr_enc.c @@ -16,10 +16,11 @@ #if !(defined(WEBP_DISABLE_STATS) || defined(WEBP_REDUCE_SIZE)) #include #include +#include "src/webp/types.h" #include "src/dsp/dsp.h" #include "src/enc/vp8i_enc.h" #include "src/utils/utils.h" typedef double (*AccumulateFunc)(const uint8_t* src, int src_stride, diff --git a/media/libwebp/src/enc/picture_rescale_enc.c b/media/libwebp/src/enc/picture_rescale_enc.c --- a/media/libwebp/src/enc/picture_rescale_enc.c +++ b/media/libwebp/src/enc/picture_rescale_enc.c @@ -14,10 +14,12 @@ #include "src/webp/encode.h" #include #include +#include "src/webp/types.h" +#include "src/dsp/dsp.h" #include "src/enc/vp8i_enc.h" #if !defined(WEBP_REDUCE_SIZE) #include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" diff --git a/media/libwebp/src/enc/picture_tools_enc.c b/media/libwebp/src/enc/picture_tools_enc.c --- a/media/libwebp/src/enc/picture_tools_enc.c +++ b/media/libwebp/src/enc/picture_tools_enc.c @@ -10,13 +10,18 @@ // WebPPicture tools: alpha handling, etc. // // Author: Skal (pascal.massimino@gmail.com) #include +#include +#include +#include "src/dsp/dsp.h" +#include "src/dsp/yuv.h" #include "src/enc/vp8i_enc.h" -#include "src/dsp/yuv.h" +#include "src/webp/encode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Helper: clean up fully transparent area to help compressibility. #define SIZE 8 diff --git a/media/libwebp/src/enc/predictor_enc.c b/media/libwebp/src/enc/predictor_enc.c --- a/media/libwebp/src/enc/predictor_enc.c +++ b/media/libwebp/src/enc/predictor_enc.c @@ -829,28 +829,28 @@ //------------------------------------------------------------------------------ // Color transform functions. static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) { - m->green_to_red_ = 0; - m->green_to_blue_ = 0; - m->red_to_blue_ = 0; + m->green_to_red = 0; + m->green_to_blue = 0; + m->red_to_blue = 0; } static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, VP8LMultipliers* const m) { - m->green_to_red_ = (color_code >> 0) & 0xff; - m->green_to_blue_ = (color_code >> 8) & 0xff; - m->red_to_blue_ = (color_code >> 16) & 0xff; + m->green_to_red = (color_code >> 0) & 0xff; + m->green_to_blue = (color_code >> 8) & 0xff; + m->red_to_blue = (color_code >> 16) & 0xff; } static WEBP_INLINE uint32_t MultipliersToColorCode( const VP8LMultipliers* const m) { return 0xff000000u | - ((uint32_t)(m->red_to_blue_) << 16) | - ((uint32_t)(m->green_to_blue_) << 8) | - m->green_to_red_; + ((uint32_t)(m->red_to_blue) << 16) | + ((uint32_t)(m->green_to_blue) << 8) | + m->green_to_red; } static int64_t PredictionCostCrossColor(const uint32_t accumulated[256], const uint32_t counts[256]) { // Favor low entropy, locally and globally. @@ -869,15 +869,15 @@ VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height, green_to_red, histo); cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo); - if ((uint8_t)green_to_red == prev_x.green_to_red_) { + if ((uint8_t)green_to_red == prev_x.green_to_red) { // favor keeping the areas locally similar cur_diff -= 3ll << LOG_2_PRECISION_BITS; } - if ((uint8_t)green_to_red == prev_y.green_to_red_) { + if ((uint8_t)green_to_red == prev_y.green_to_red) { // favor keeping the areas locally similar cur_diff -= 3ll << LOG_2_PRECISION_BITS; } if (green_to_red == 0) { cur_diff -= 3ll << LOG_2_PRECISION_BITS; @@ -911,11 +911,11 @@ best_diff = cur_diff; green_to_red_best = green_to_red_cur; } } } - best_tx->green_to_red_ = (green_to_red_best & 0xff); + best_tx->green_to_red = (green_to_red_best & 0xff); } static int64_t GetPredictionCostCrossColorBlue( const uint32_t* argb, int stride, int tile_width, int tile_height, VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_blue, @@ -925,23 +925,23 @@ VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height, green_to_blue, red_to_blue, histo); cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo); - if ((uint8_t)green_to_blue == prev_x.green_to_blue_) { + if ((uint8_t)green_to_blue == prev_x.green_to_blue) { // favor keeping the areas locally similar cur_diff -= 3ll << LOG_2_PRECISION_BITS; } - if ((uint8_t)green_to_blue == prev_y.green_to_blue_) { + if ((uint8_t)green_to_blue == prev_y.green_to_blue) { // favor keeping the areas locally similar cur_diff -= 3ll << LOG_2_PRECISION_BITS; } - if ((uint8_t)red_to_blue == prev_x.red_to_blue_) { + if ((uint8_t)red_to_blue == prev_x.red_to_blue) { // favor keeping the areas locally similar cur_diff -= 3ll << LOG_2_PRECISION_BITS; } - if ((uint8_t)red_to_blue == prev_y.red_to_blue_) { + if ((uint8_t)red_to_blue == prev_y.red_to_blue) { // favor keeping the areas locally similar cur_diff -= 3ll << LOG_2_PRECISION_BITS; } if (green_to_blue == 0) { cur_diff -= 3ll << LOG_2_PRECISION_BITS; @@ -995,12 +995,12 @@ if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) { // Further iterations would not help. break; // out of iter-loop. } } - best_tx->green_to_blue_ = green_to_blue_best & 0xff; - best_tx->red_to_blue_ = red_to_blue_best & 0xff; + best_tx->green_to_blue = green_to_blue_best & 0xff; + best_tx->red_to_blue = red_to_blue_best & 0xff; } #undef kGreenRedToBlueMaxIters #undef kGreenRedToBlueNumAxis static VP8LMultipliers GetBestColorTransformForTile( diff --git a/media/libwebp/src/enc/quant_enc.c b/media/libwebp/src/enc/quant_enc.c --- a/media/libwebp/src/enc/quant_enc.c +++ b/media/libwebp/src/enc/quant_enc.c @@ -12,14 +12,18 @@ // Author: Skal (pascal.massimino@gmail.com) #include #include #include // for abs() +#include +#include "src/dec/common_dec.h" +#include "src/dsp/dsp.h" #include "src/dsp/quant.h" +#include "src/enc/cost_enc.h" #include "src/enc/vp8i_enc.h" -#include "src/enc/cost_enc.h" +#include "src/webp/types.h" #define DO_TRELLIS_I4 1 #define DO_TRELLIS_I16 1 // not a huge gain, but ok at low bitrate. #define DO_TRELLIS_UV 0 // disable trellis for UV. Risky. Not worth. #define USE_TDISTO 1 @@ -52,15 +56,15 @@ #include static void PrintBlockInfo(const VP8EncIterator* const it, const VP8ModeScore* const rd) { int i, j; - const int is_i16 = (it->mb_->type_ == 1); - const uint8_t* const y_in = it->yuv_in_ + Y_OFF_ENC; - const uint8_t* const y_out = it->yuv_out_ + Y_OFF_ENC; - const uint8_t* const uv_in = it->yuv_in_ + U_OFF_ENC; - const uint8_t* const uv_out = it->yuv_out_ + U_OFF_ENC; + const int is_i16 = (it->mb->type == 1); + const uint8_t* const y_in = it->yuv_in + Y_OFF_ENC; + const uint8_t* const y_out = it->yuv_out + Y_OFF_ENC; + const uint8_t* const uv_in = it->yuv_in + U_OFF_ENC; + const uint8_t* const uv_out = it->yuv_out + U_OFF_ENC; printf("SOURCE / OUTPUT / ABS DELTA\n"); for (j = 0; j < 16; ++j) { for (i = 0; i < 16; ++i) printf("%3d ", y_in[i + j * BPS]); printf(" "); for (i = 0; i < 16; ++i) printf("%3d ", y_out[i + j * BPS]); @@ -209,82 +213,82 @@ static int ExpandMatrix(VP8Matrix* const m, int type) { int i, sum; for (i = 0; i < 2; ++i) { const int is_ac_coeff = (i > 0); const int bias = kBiasMatrices[type][is_ac_coeff]; - m->iq_[i] = (1 << QFIX) / m->q_[i]; - m->bias_[i] = BIAS(bias); - // zthresh_ is the exact value such that QUANTDIV(coeff, iQ, B) is: + m->iq[i] = (1 << QFIX) / m->q[i]; + m->bias[i] = BIAS(bias); + // zthresh is the exact value such that QUANTDIV(coeff, iQ, B) is: // * zero if coeff <= zthresh // * non-zero if coeff > zthresh - m->zthresh_[i] = ((1 << QFIX) - 1 - m->bias_[i]) / m->iq_[i]; + m->zthresh[i] = ((1 << QFIX) - 1 - m->bias[i]) / m->iq[i]; } for (i = 2; i < 16; ++i) { - m->q_[i] = m->q_[1]; - m->iq_[i] = m->iq_[1]; - m->bias_[i] = m->bias_[1]; - m->zthresh_[i] = m->zthresh_[1]; + m->q[i] = m->q[1]; + m->iq[i] = m->iq[1]; + m->bias[i] = m->bias[1]; + m->zthresh[i] = m->zthresh[1]; } for (sum = 0, i = 0; i < 16; ++i) { if (type == 0) { // we only use sharpening for AC luma coeffs - m->sharpen_[i] = (kFreqSharpening[i] * m->q_[i]) >> SHARPEN_BITS; + m->sharpen[i] = (kFreqSharpening[i] * m->q[i]) >> SHARPEN_BITS; } else { - m->sharpen_[i] = 0; + m->sharpen[i] = 0; } - sum += m->q_[i]; + sum += m->q[i]; } return (sum + 8) >> 4; } static void CheckLambdaValue(int* const v) { if (*v < 1) *v = 1; } static void SetupMatrices(VP8Encoder* enc) { int i; const int tlambda_scale = - (enc->method_ >= 4) ? enc->config_->sns_strength + (enc->method >= 4) ? enc->config->sns_strength : 0; - const int num_segments = enc->segment_hdr_.num_segments_; + const int num_segments = enc->segment_hdr.num_segments; for (i = 0; i < num_segments; ++i) { - VP8SegmentInfo* const m = &enc->dqm_[i]; - const int q = m->quant_; + VP8SegmentInfo* const m = &enc->dqm[i]; + const int q = m->quant; int q_i4, q_i16, q_uv; - m->y1_.q_[0] = kDcTable[clip(q + enc->dq_y1_dc_, 0, 127)]; - m->y1_.q_[1] = kAcTable[clip(q, 0, 127)]; + m->y1.q[0] = kDcTable[clip(q + enc->dq_y1_dc, 0, 127)]; + m->y1.q[1] = kAcTable[clip(q, 0, 127)]; - m->y2_.q_[0] = kDcTable[ clip(q + enc->dq_y2_dc_, 0, 127)] * 2; - m->y2_.q_[1] = kAcTable2[clip(q + enc->dq_y2_ac_, 0, 127)]; + m->y2.q[0] = kDcTable[ clip(q + enc->dq_y2_dc, 0, 127)] * 2; + m->y2.q[1] = kAcTable2[clip(q + enc->dq_y2_ac, 0, 127)]; - m->uv_.q_[0] = kDcTable[clip(q + enc->dq_uv_dc_, 0, 117)]; - m->uv_.q_[1] = kAcTable[clip(q + enc->dq_uv_ac_, 0, 127)]; + m->uv.q[0] = kDcTable[clip(q + enc->dq_uv_dc, 0, 117)]; + m->uv.q[1] = kAcTable[clip(q + enc->dq_uv_ac, 0, 127)]; - q_i4 = ExpandMatrix(&m->y1_, 0); - q_i16 = ExpandMatrix(&m->y2_, 1); - q_uv = ExpandMatrix(&m->uv_, 2); + q_i4 = ExpandMatrix(&m->y1, 0); + q_i16 = ExpandMatrix(&m->y2, 1); + q_uv = ExpandMatrix(&m->uv, 2); - m->lambda_i4_ = (3 * q_i4 * q_i4) >> 7; - m->lambda_i16_ = (3 * q_i16 * q_i16); - m->lambda_uv_ = (3 * q_uv * q_uv) >> 6; - m->lambda_mode_ = (1 * q_i4 * q_i4) >> 7; - m->lambda_trellis_i4_ = (7 * q_i4 * q_i4) >> 3; - m->lambda_trellis_i16_ = (q_i16 * q_i16) >> 2; - m->lambda_trellis_uv_ = (q_uv * q_uv) << 1; - m->tlambda_ = (tlambda_scale * q_i4) >> 5; + m->lambda_i4 = (3 * q_i4 * q_i4) >> 7; + m->lambda_i16 = (3 * q_i16 * q_i16); + m->lambda_uv = (3 * q_uv * q_uv) >> 6; + m->lambda_mode = (1 * q_i4 * q_i4) >> 7; + m->lambda_trellis_i4 = (7 * q_i4 * q_i4) >> 3; + m->lambda_trellis_i16 = (q_i16 * q_i16) >> 2; + m->lambda_trellis_uv = (q_uv * q_uv) << 1; + m->tlambda = (tlambda_scale * q_i4) >> 5; // none of these constants should be < 1 - CheckLambdaValue(&m->lambda_i4_); - CheckLambdaValue(&m->lambda_i16_); - CheckLambdaValue(&m->lambda_uv_); - CheckLambdaValue(&m->lambda_mode_); - CheckLambdaValue(&m->lambda_trellis_i4_); - CheckLambdaValue(&m->lambda_trellis_i16_); - CheckLambdaValue(&m->lambda_trellis_uv_); - CheckLambdaValue(&m->tlambda_); + CheckLambdaValue(&m->lambda_i4); + CheckLambdaValue(&m->lambda_i16); + CheckLambdaValue(&m->lambda_uv); + CheckLambdaValue(&m->lambda_mode); + CheckLambdaValue(&m->lambda_trellis_i4); + CheckLambdaValue(&m->lambda_trellis_i16); + CheckLambdaValue(&m->lambda_trellis_uv); + CheckLambdaValue(&m->tlambda); - m->min_disto_ = 20 * m->y1_.q_[0]; // quantization-aware min disto - m->max_edge_ = 0; + m->min_disto = 20 * m->y1.q[0]; // quantization-aware min disto + m->max_edge = 0; - m->i4_penalty_ = 1000 * q_i4 * q_i4; + m->i4_penalty = 1000 * q_i4 * q_i4; } } //------------------------------------------------------------------------------ // Initialize filtering parameters @@ -294,25 +298,25 @@ #define FSTRENGTH_CUTOFF 2 static void SetupFilterStrength(VP8Encoder* const enc) { int i; // level0 is in [0..500]. Using '-f 50' as filter_strength is mid-filtering. - const int level0 = 5 * enc->config_->filter_strength; + const int level0 = 5 * enc->config->filter_strength; for (i = 0; i < NUM_MB_SEGMENTS; ++i) { - VP8SegmentInfo* const m = &enc->dqm_[i]; + VP8SegmentInfo* const m = &enc->dqm[i]; // We focus on the quantization of AC coeffs. - const int qstep = kAcTable[clip(m->quant_, 0, 127)] >> 2; + const int qstep = kAcTable[clip(m->quant, 0, 127)] >> 2; const int base_strength = - VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, qstep); + VP8FilterStrengthFromDelta(enc->filter_hdr.sharpness, qstep); // Segments with lower complexity ('beta') will be less filtered. - const int f = base_strength * level0 / (256 + m->beta_); - m->fstrength_ = (f < FSTRENGTH_CUTOFF) ? 0 : (f > 63) ? 63 : f; + const int f = base_strength * level0 / (256 + m->beta); + m->fstrength = (f < FSTRENGTH_CUTOFF) ? 0 : (f > 63) ? 63 : f; } // We record the initial strength (mainly for the case of 1-segment only). - enc->filter_hdr_.level_ = enc->dqm_[0].fstrength_; - enc->filter_hdr_.simple_ = (enc->config_->filter_type == 0); - enc->filter_hdr_.sharpness_ = enc->config_->filter_sharpness; + enc->filter_hdr.level = enc->dqm[0].fstrength; + enc->filter_hdr.simple = (enc->config->filter_type == 0); + enc->filter_hdr.sharpness = enc->config->filter_sharpness; } //------------------------------------------------------------------------------ // Note: if you change the values below, remember that the max range @@ -354,100 +358,100 @@ return v; } static int SegmentsAreEquivalent(const VP8SegmentInfo* const S1, const VP8SegmentInfo* const S2) { - return (S1->quant_ == S2->quant_) && (S1->fstrength_ == S2->fstrength_); + return (S1->quant == S2->quant) && (S1->fstrength == S2->fstrength); } static void SimplifySegments(VP8Encoder* const enc) { int map[NUM_MB_SEGMENTS] = { 0, 1, 2, 3 }; - // 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an + // 'num_segments' is previously validated and <= NUM_MB_SEGMENTS, but an // explicit check is needed to avoid a spurious warning about 'i' exceeding - // array bounds of 'dqm_' with some compilers (noticed with gcc-4.9). - const int num_segments = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) - ? enc->segment_hdr_.num_segments_ + // array bounds of 'dqm' with some compilers (noticed with gcc-4.9). + const int num_segments = (enc->segment_hdr.num_segments < NUM_MB_SEGMENTS) + ? enc->segment_hdr.num_segments : NUM_MB_SEGMENTS; int num_final_segments = 1; int s1, s2; for (s1 = 1; s1 < num_segments; ++s1) { // find similar segments - const VP8SegmentInfo* const S1 = &enc->dqm_[s1]; + const VP8SegmentInfo* const S1 = &enc->dqm[s1]; int found = 0; // check if we already have similar segment for (s2 = 0; s2 < num_final_segments; ++s2) { - const VP8SegmentInfo* const S2 = &enc->dqm_[s2]; + const VP8SegmentInfo* const S2 = &enc->dqm[s2]; if (SegmentsAreEquivalent(S1, S2)) { found = 1; break; } } map[s1] = s2; if (!found) { if (num_final_segments != s1) { - enc->dqm_[num_final_segments] = enc->dqm_[s1]; + enc->dqm[num_final_segments] = enc->dqm[s1]; } ++num_final_segments; } } if (num_final_segments < num_segments) { // Remap - int i = enc->mb_w_ * enc->mb_h_; - while (i-- > 0) enc->mb_info_[i].segment_ = map[enc->mb_info_[i].segment_]; - enc->segment_hdr_.num_segments_ = num_final_segments; + int i = enc->mb_w * enc->mb_h; + while (i-- > 0) enc->mb_info[i].segment = map[enc->mb_info[i].segment]; + enc->segment_hdr.num_segments = num_final_segments; // Replicate the trailing segment infos (it's mostly cosmetics) for (i = num_final_segments; i < num_segments; ++i) { - enc->dqm_[i] = enc->dqm_[num_final_segments - 1]; + enc->dqm[i] = enc->dqm[num_final_segments - 1]; } } } void VP8SetSegmentParams(VP8Encoder* const enc, float quality) { int i; int dq_uv_ac, dq_uv_dc; - const int num_segments = enc->segment_hdr_.num_segments_; - const double amp = SNS_TO_DQ * enc->config_->sns_strength / 100. / 128.; + const int num_segments = enc->segment_hdr.num_segments; + const double amp = SNS_TO_DQ * enc->config->sns_strength / 100. / 128.; const double Q = quality / 100.; - const double c_base = enc->config_->emulate_jpeg_size ? - QualityToJPEGCompression(Q, enc->alpha_ / 255.) : + const double c_base = enc->config->emulate_jpeg_size ? + QualityToJPEGCompression(Q, enc->alpha / 255.) : QualityToCompression(Q); for (i = 0; i < num_segments; ++i) { // We modulate the base coefficient to accommodate for the quantization // susceptibility and allow denser segments to be quantized more. - const double expn = 1. - amp * enc->dqm_[i].alpha_; + const double expn = 1. - amp * enc->dqm[i].alpha; const double c = pow(c_base, expn); const int q = (int)(127. * (1. - c)); assert(expn > 0.); - enc->dqm_[i].quant_ = clip(q, 0, 127); + enc->dqm[i].quant = clip(q, 0, 127); } // purely indicative in the bitstream (except for the 1-segment case) - enc->base_quant_ = enc->dqm_[0].quant_; + enc->base_quant = enc->dqm[0].quant; // fill-in values for the unused segments (required by the syntax) for (i = num_segments; i < NUM_MB_SEGMENTS; ++i) { - enc->dqm_[i].quant_ = enc->base_quant_; + enc->dqm[i].quant = enc->base_quant; } - // uv_alpha_ is normally spread around ~60. The useful range is + // uv_alpha is normally spread around ~60. The useful range is // typically ~30 (quite bad) to ~100 (ok to decimate UV more). // We map it to the safe maximal range of MAX/MIN_DQ_UV for dq_uv. - dq_uv_ac = (enc->uv_alpha_ - MID_ALPHA) * (MAX_DQ_UV - MIN_DQ_UV) - / (MAX_ALPHA - MIN_ALPHA); + dq_uv_ac = (enc->uv_alpha - MID_ALPHA) * (MAX_DQ_UV - MIN_DQ_UV) + / (MAX_ALPHA - MIN_ALPHA); // we rescale by the user-defined strength of adaptation - dq_uv_ac = dq_uv_ac * enc->config_->sns_strength / 100; + dq_uv_ac = dq_uv_ac * enc->config->sns_strength / 100; // and make it safe. dq_uv_ac = clip(dq_uv_ac, MIN_DQ_UV, MAX_DQ_UV); // We also boost the dc-uv-quant a little, based on sns-strength, since // U/V channels are quite more reactive to high quants (flat DC-blocks // tend to appear, and are unpleasant). - dq_uv_dc = -4 * enc->config_->sns_strength / 100; + dq_uv_dc = -4 * enc->config->sns_strength / 100; dq_uv_dc = clip(dq_uv_dc, -15, 15); // 4bit-signed max allowed - enc->dq_y1_dc_ = 0; // TODO(skal): dq-lum - enc->dq_y2_dc_ = 0; - enc->dq_y2_ac_ = 0; - enc->dq_uv_dc_ = dq_uv_dc; - enc->dq_uv_ac_ = dq_uv_ac; + enc->dq_y1_dc = 0; // TODO(skal): dq-lum + enc->dq_y2_dc = 0; + enc->dq_y2_ac = 0; + enc->dq_uv_dc = dq_uv_dc; + enc->dq_uv_ac = dq_uv_ac; SetupFilterStrength(enc); // initialize segments' filtering, eventually if (num_segments > 1) SimplifySegments(enc); @@ -465,25 +469,25 @@ static const uint16_t VP8I4ModeOffsets[NUM_BMODES] = { I4DC4, I4TM4, I4VE4, I4HE4, I4RD4, I4VR4, I4LD4, I4VL4, I4HD4, I4HU4 }; void VP8MakeLuma16Preds(const VP8EncIterator* const it) { - const uint8_t* const left = it->x_ ? it->y_left_ : NULL; - const uint8_t* const top = it->y_ ? it->y_top_ : NULL; - VP8EncPredLuma16(it->yuv_p_, left, top); + const uint8_t* const left = it->x ? it->y_left : NULL; + const uint8_t* const top = it->y ? it->y_top : NULL; + VP8EncPredLuma16(it->yuv_p, left, top); } void VP8MakeChroma8Preds(const VP8EncIterator* const it) { - const uint8_t* const left = it->x_ ? it->u_left_ : NULL; - const uint8_t* const top = it->y_ ? it->uv_top_ : NULL; - VP8EncPredChroma8(it->yuv_p_, left, top); + const uint8_t* const left = it->x ? it->u_left : NULL; + const uint8_t* const top = it->y ? it->uv_top : NULL; + VP8EncPredChroma8(it->yuv_p, left, top); } -// Form all the ten Intra4x4 predictions in the yuv_p_ cache -// for the 4x4 block it->i4_ +// Form all the ten Intra4x4 predictions in the 'yuv_p' cache +// for the 4x4 block it->i4 static void MakeIntra4Preds(const VP8EncIterator* const it) { - VP8EncPredLuma4(it->yuv_p_, it->i4_top_); + VP8EncPredLuma4(it->yuv_p, it->i4_top); } //------------------------------------------------------------------------------ // Quantize @@ -595,13 +599,13 @@ static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc, int16_t in[16], int16_t out[16], int ctx0, int coeff_type, const VP8Matrix* WEBP_RESTRICT const mtx, int lambda) { - const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type]; + const ProbaArray* const probas = enc->proba.coeffs[coeff_type]; CostArrayPtr const costs = - (CostArrayPtr)enc->proba_.remapped_costs_[coeff_type]; + (CostArrayPtr)enc->proba.remapped_costs[coeff_type]; const int first = (coeff_type == TYPE_I16_AC) ? 1 : 0; Node nodes[16][NUM_NODES]; ScoreState score_states[2][NUM_NODES]; ScoreState* ss_cur = &SCORE_STATE(0, MIN_DELTA); ScoreState* ss_prev = &SCORE_STATE(1, MIN_DELTA); @@ -609,11 +613,11 @@ score_t best_score; int n, m, p, last; { score_t cost; - const int thresh = mtx->q_[1] * mtx->q_[1] / 4; + const int thresh = mtx->q[1] * mtx->q[1] / 4; const int last_proba = probas[VP8EncBands[first]][ctx0][0]; // compute the position of the last interesting coefficient last = first - 1; for (n = 15; n >= first; --n) { @@ -641,17 +645,17 @@ } // traverse trellis. for (n = first; n <= last; ++n) { const int j = kZigzag[n]; - const uint32_t Q = mtx->q_[j]; - const uint32_t iQ = mtx->iq_[j]; + const uint32_t Q = mtx->q[j]; + const uint32_t iQ = mtx->iq[j]; const uint32_t B = BIAS(0x00); // neutral bias // note: it's important to take sign of the _original_ coeff, // so we don't have to consider level < 0 afterward. const int sign = (in[j] < 0); - const uint32_t coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; + const uint32_t coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen[j]; int level0 = QUANTDIV(coeff0, iQ, B); int thresh_level = QUANTDIV(coeff0, iQ, BIAS(0x80)); if (thresh_level > MAX_LEVEL) thresh_level = MAX_LEVEL; if (level0 > MAX_LEVEL) level0 = MAX_LEVEL; @@ -755,11 +759,11 @@ for (; n >= first; --n) { const Node* const node = &NODE(n, best_node); const int j = kZigzag[n]; out[n] = node->sign ? -node->level : node->level; nz |= node->level; - in[j] = out[n] * mtx->q_[j]; + in[j] = out[n] * mtx->q[j]; best_node = node->prev; } return (nz != 0); } } @@ -773,44 +777,44 @@ static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it, VP8ModeScore* WEBP_RESTRICT const rd, uint8_t* WEBP_RESTRICT const yuv_out, int mode) { - const VP8Encoder* const enc = it->enc_; - const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode]; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; - const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + const VP8Encoder* const enc = it->enc; + const uint8_t* const ref = it->yuv_p + VP8I16ModeOffsets[mode]; + const uint8_t* const src = it->yuv_in + Y_OFF_ENC; + const VP8SegmentInfo* const dqm = &enc->dqm[it->mb->segment]; int nz = 0; int n; int16_t tmp[16][16], dc_tmp[16]; for (n = 0; n < 16; n += 2) { VP8FTransform2(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]); } VP8FTransformWHT(tmp[0], dc_tmp); - nz |= VP8EncQuantizeBlockWHT(dc_tmp, rd->y_dc_levels, &dqm->y2_) << 24; + nz |= VP8EncQuantizeBlockWHT(dc_tmp, rd->y_dc_levels, &dqm->y2) << 24; - if (DO_TRELLIS_I16 && it->do_trellis_) { + if (DO_TRELLIS_I16 && it->do_trellis) { int x, y; VP8IteratorNzToBytes(it); for (y = 0, n = 0; y < 4; ++y) { for (x = 0; x < 4; ++x, ++n) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; + const int ctx = it->top_nz[x] + it->left_nz[y]; const int non_zero = TrellisQuantizeBlock( - enc, tmp[n], rd->y_ac_levels[n], ctx, TYPE_I16_AC, &dqm->y1_, - dqm->lambda_trellis_i16_); - it->top_nz_[x] = it->left_nz_[y] = non_zero; + enc, tmp[n], rd->y_ac_levels[n], ctx, TYPE_I16_AC, &dqm->y1, + dqm->lambda_trellis_i16); + it->top_nz[x] = it->left_nz[y] = non_zero; rd->y_ac_levels[n][0] = 0; nz |= non_zero << n; } } } else { for (n = 0; n < 16; n += 2) { // Zero-out the first coeff, so that: a) nz is correct below, and // b) finding 'last' non-zero coeffs in SetResidualCoeffs() is simplified. tmp[n][0] = tmp[n + 1][0] = 0; - nz |= VP8EncQuantize2Blocks(tmp[n], rd->y_ac_levels[n], &dqm->y1_) << n; + nz |= VP8EncQuantize2Blocks(tmp[n], rd->y_ac_levels[n], &dqm->y1) << n; assert(rd->y_ac_levels[n + 0][0] == 0); assert(rd->y_ac_levels[n + 1][0] == 0); } } @@ -826,24 +830,24 @@ static int ReconstructIntra4(VP8EncIterator* WEBP_RESTRICT const it, int16_t levels[16], const uint8_t* WEBP_RESTRICT const src, uint8_t* WEBP_RESTRICT const yuv_out, int mode) { - const VP8Encoder* const enc = it->enc_; - const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode]; - const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + const VP8Encoder* const enc = it->enc; + const uint8_t* const ref = it->yuv_p + VP8I4ModeOffsets[mode]; + const VP8SegmentInfo* const dqm = &enc->dqm[it->mb->segment]; int nz = 0; int16_t tmp[16]; VP8FTransform(src, ref, tmp); - if (DO_TRELLIS_I4 && it->do_trellis_) { - const int x = it->i4_ & 3, y = it->i4_ >> 2; - const int ctx = it->top_nz_[x] + it->left_nz_[y]; - nz = TrellisQuantizeBlock(enc, tmp, levels, ctx, TYPE_I4_AC, &dqm->y1_, - dqm->lambda_trellis_i4_); + if (DO_TRELLIS_I4 && it->do_trellis) { + const int x = it->i4 & 3, y = it->i4 >> 2; + const int ctx = it->top_nz[x] + it->left_nz[y]; + nz = TrellisQuantizeBlock(enc, tmp, levels, ctx, TYPE_I4_AC, &dqm->y1, + dqm->lambda_trellis_i4); } else { - nz = VP8EncQuantizeBlock(tmp, levels, &dqm->y1_); + nz = VP8EncQuantizeBlock(tmp, levels, &dqm->y1); } VP8ITransform(ref, tmp, yuv_out, 0); return nz; } @@ -862,12 +866,12 @@ static int QuantizeSingle(int16_t* WEBP_RESTRICT const v, const VP8Matrix* WEBP_RESTRICT const mtx) { int V = *v; const int sign = (V < 0); if (sign) V = -V; - if (V > (int)mtx->zthresh_[0]) { - const int qV = QUANTDIV(V, mtx->iq_[0], mtx->bias_[0]) * mtx->q_[0]; + if (V > (int)mtx->zthresh[0]) { + const int qV = QUANTDIV(V, mtx->iq[0], mtx->bias[0]) * mtx->q[0]; const int err = (V - qV); *v = sign ? -qV : qV; return (sign ? -err : err) >> DSCALE; } *v = 0; @@ -885,23 +889,23 @@ // // Final errors {err1,err2,err3} are preserved and later restored // as top[]/left[] on the next block. int ch; for (ch = 0; ch <= 1; ++ch) { - const int8_t* const top = it->top_derr_[it->x_][ch]; - const int8_t* const left = it->left_derr_[ch]; + const int8_t* const top = it->top_derr[it->x][ch]; + const int8_t* const left = it->left_derr[ch]; int16_t (* const c)[16] = &tmp[ch * 4]; int err0, err1, err2, err3; c[0][0] += (C1 * top[0] + C2 * left[0]) >> (DSHIFT - DSCALE); err0 = QuantizeSingle(&c[0][0], mtx); c[1][0] += (C1 * top[1] + C2 * err0) >> (DSHIFT - DSCALE); err1 = QuantizeSingle(&c[1][0], mtx); c[2][0] += (C1 * err0 + C2 * left[1]) >> (DSHIFT - DSCALE); err2 = QuantizeSingle(&c[2][0], mtx); c[3][0] += (C1 * err1 + C2 * err2) >> (DSHIFT - DSCALE); err3 = QuantizeSingle(&c[3][0], mtx); - // error 'err' is bounded by mtx->q_[0] which is 132 at max. Hence + // error 'err' is bounded by mtx->q[0] which is 132 at max. Hence // err >> DSCALE will fit in an int8_t type if DSCALE>=1. assert(abs(err1) <= 127 && abs(err2) <= 127 && abs(err3) <= 127); rd->derr[ch][0] = (int8_t)err1; rd->derr[ch][1] = (int8_t)err2; rd->derr[ch][2] = (int8_t)err3; @@ -910,12 +914,12 @@ static void StoreDiffusionErrors(VP8EncIterator* WEBP_RESTRICT const it, const VP8ModeScore* WEBP_RESTRICT const rd) { int ch; for (ch = 0; ch <= 1; ++ch) { - int8_t* const top = it->top_derr_[it->x_][ch]; - int8_t* const left = it->left_derr_[ch]; + int8_t* const top = it->top_derr[it->x][ch]; + int8_t* const left = it->left_derr[ch]; left[0] = rd->derr[ch][0]; // restore err1 left[1] = 3 * rd->derr[ch][2] >> 2; // ... 3/4th of err3 top[0] = rd->derr[ch][1]; // ... err2 top[1] = rd->derr[ch][2] - left[1]; // ... 1/4th of err3. } @@ -929,40 +933,40 @@ //------------------------------------------------------------------------------ static int ReconstructUV(VP8EncIterator* WEBP_RESTRICT const it, VP8ModeScore* WEBP_RESTRICT const rd, uint8_t* WEBP_RESTRICT const yuv_out, int mode) { - const VP8Encoder* const enc = it->enc_; - const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode]; - const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; - const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + const VP8Encoder* const enc = it->enc; + const uint8_t* const ref = it->yuv_p + VP8UVModeOffsets[mode]; + const uint8_t* const src = it->yuv_in + U_OFF_ENC; + const VP8SegmentInfo* const dqm = &enc->dqm[it->mb->segment]; int nz = 0; int n; int16_t tmp[8][16]; for (n = 0; n < 8; n += 2) { VP8FTransform2(src + VP8ScanUV[n], ref + VP8ScanUV[n], tmp[n]); } - if (it->top_derr_ != NULL) CorrectDCValues(it, &dqm->uv_, tmp, rd); + if (it->top_derr != NULL) CorrectDCValues(it, &dqm->uv, tmp, rd); - if (DO_TRELLIS_UV && it->do_trellis_) { + if (DO_TRELLIS_UV && it->do_trellis) { int ch, x, y; for (ch = 0, n = 0; ch <= 2; ch += 2) { for (y = 0; y < 2; ++y) { for (x = 0; x < 2; ++x, ++n) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + const int ctx = it->top_nz[4 + ch + x] + it->left_nz[4 + ch + y]; const int non_zero = TrellisQuantizeBlock( - enc, tmp[n], rd->uv_levels[n], ctx, TYPE_CHROMA_A, &dqm->uv_, - dqm->lambda_trellis_uv_); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = non_zero; + enc, tmp[n], rd->uv_levels[n], ctx, TYPE_CHROMA_A, &dqm->uv, + dqm->lambda_trellis_uv); + it->top_nz[4 + ch + x] = it->left_nz[4 + ch + y] = non_zero; nz |= non_zero << n; } } } } else { for (n = 0; n < 8; n += 2) { - nz |= VP8EncQuantize2Blocks(tmp[n], rd->uv_levels[n], &dqm->uv_) << n; + nz |= VP8EncQuantize2Blocks(tmp[n], rd->uv_levels[n], &dqm->uv) << n; } } for (n = 0; n < 8; n += 2) { VP8ITransform(ref + VP8ScanUV[n], tmp[n], yuv_out + VP8ScanUV[n], 1); @@ -980,11 +984,11 @@ const int v0 = abs(DCs[1]); const int v1 = abs(DCs[2]); const int v2 = abs(DCs[4]); int max_v = (v1 > v0) ? v1 : v0; max_v = (v2 > max_v) ? v2 : max_v; - if (max_v > dqm->max_edge_) dqm->max_edge_ = max_v; + if (max_v > dqm->max_edge) dqm->max_edge = max_v; } static void SwapModeScore(VP8ModeScore** a, VP8ModeScore** b) { VP8ModeScore* const tmp = *a; *a = *b; @@ -996,29 +1000,29 @@ *a = *b; *b = tmp; } static void SwapOut(VP8EncIterator* const it) { - SwapPtr(&it->yuv_out_, &it->yuv_out2_); + SwapPtr(&it->yuv_out, &it->yuv_out2); } static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it, VP8ModeScore* WEBP_RESTRICT rd) { const int kNumBlocks = 16; - VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; - const int lambda = dqm->lambda_i16_; - const int tlambda = dqm->tlambda_; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; + VP8SegmentInfo* const dqm = &it->enc->dqm[it->mb->segment]; + const int lambda = dqm->lambda_i16; + const int tlambda = dqm->tlambda; + const uint8_t* const src = it->yuv_in + Y_OFF_ENC; VP8ModeScore rd_tmp; VP8ModeScore* rd_cur = &rd_tmp; VP8ModeScore* rd_best = rd; int mode; - int is_flat = IsFlatSource16(it->yuv_in_ + Y_OFF_ENC); + int is_flat = IsFlatSource16(it->yuv_in + Y_OFF_ENC); rd->mode_i16 = -1; for (mode = 0; mode < NUM_PRED_MODES; ++mode) { - uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF_ENC; // scratch buffer + uint8_t* const tmp_dst = it->yuv_out2 + Y_OFF_ENC; // scratch buffer rd_cur->mode_i16 = mode; // Reconstruct rd_cur->nz = ReconstructIntra16(it, rd_cur, tmp_dst, mode); @@ -1046,71 +1050,71 @@ } } if (rd_best != rd) { memcpy(rd, rd_best, sizeof(*rd)); } - SetRDScore(dqm->lambda_mode_, rd); // finalize score for mode decision. + SetRDScore(dqm->lambda_mode, rd); // finalize score for mode decision. VP8SetIntra16Mode(it, rd->mode_i16); // we have a blocky macroblock (only DCs are non-zero) with fairly high // distortion, record max delta so we can later adjust the minimal filtering // strength needed to smooth these blocks out. - if ((rd->nz & 0x100ffff) == 0x1000000 && rd->D > dqm->min_disto_) { + if ((rd->nz & 0x100ffff) == 0x1000000 && rd->D > dqm->min_disto) { StoreMaxDelta(dqm, rd->y_dc_levels); } } //------------------------------------------------------------------------------ // return the cost array corresponding to the surrounding prediction modes. static const uint16_t* GetCostModeI4(VP8EncIterator* WEBP_RESTRICT const it, const uint8_t modes[16]) { - const int preds_w = it->enc_->preds_w_; - const int x = (it->i4_ & 3), y = it->i4_ >> 2; - const int left = (x == 0) ? it->preds_[y * preds_w - 1] : modes[it->i4_ - 1]; - const int top = (y == 0) ? it->preds_[-preds_w + x] : modes[it->i4_ - 4]; + const int preds_w = it->enc->preds_w; + const int x = (it->i4 & 3), y = it->i4 >> 2; + const int left = (x == 0) ? it->preds[y * preds_w - 1] : modes[it->i4 - 1]; + const int top = (y == 0) ? it->preds[-preds_w + x] : modes[it->i4 - 4]; return VP8FixedCostsI4[top][left]; } static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it, VP8ModeScore* WEBP_RESTRICT const rd) { - const VP8Encoder* const enc = it->enc_; - const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; - const int lambda = dqm->lambda_i4_; - const int tlambda = dqm->tlambda_; - const uint8_t* const src0 = it->yuv_in_ + Y_OFF_ENC; - uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF_ENC; + const VP8Encoder* const enc = it->enc; + const VP8SegmentInfo* const dqm = &enc->dqm[it->mb->segment]; + const int lambda = dqm->lambda_i4; + const int tlambda = dqm->tlambda; + const uint8_t* const src0 = it->yuv_in + Y_OFF_ENC; + uint8_t* const best_blocks = it->yuv_out2 + Y_OFF_ENC; int total_header_bits = 0; VP8ModeScore rd_best; - if (enc->max_i4_header_bits_ == 0) { + if (enc->max_i4_header_bits == 0) { return 0; } InitScore(&rd_best); rd_best.H = 211; // '211' is the value of VP8BitCost(0, 145) - SetRDScore(dqm->lambda_mode_, &rd_best); + SetRDScore(dqm->lambda_mode, &rd_best); VP8IteratorStartI4(it); do { const int kNumBlocks = 1; VP8ModeScore rd_i4; int mode; int best_mode = -1; - const uint8_t* const src = src0 + VP8Scan[it->i4_]; + const uint8_t* const src = src0 + VP8Scan[it->i4]; const uint16_t* const mode_costs = GetCostModeI4(it, rd->modes_i4); - uint8_t* best_block = best_blocks + VP8Scan[it->i4_]; - uint8_t* tmp_dst = it->yuv_p_ + I4TMP; // scratch buffer. + uint8_t* best_block = best_blocks + VP8Scan[it->i4]; + uint8_t* tmp_dst = it->yuv_p + I4TMP; // scratch buffer. InitScore(&rd_i4); MakeIntra4Preds(it); for (mode = 0; mode < NUM_BMODES; ++mode) { VP8ModeScore rd_tmp; int16_t tmp_levels[16]; // Reconstruct rd_tmp.nz = - ReconstructIntra4(it, tmp_levels, src, tmp_dst, mode) << it->i4_; + ReconstructIntra4(it, tmp_levels, src, tmp_dst, mode) << it->i4; // Compute RD-score rd_tmp.D = VP8SSE4x4(src, tmp_dst); rd_tmp.SD = tlambda ? MULT_8B(tlambda, VP8TDisto4x4(src, tmp_dst, kWeightY)) @@ -1135,29 +1139,29 @@ if (best_mode < 0 || rd_tmp.score < rd_i4.score) { CopyScore(&rd_i4, &rd_tmp); best_mode = mode; SwapPtr(&tmp_dst, &best_block); - memcpy(rd_best.y_ac_levels[it->i4_], tmp_levels, - sizeof(rd_best.y_ac_levels[it->i4_])); + memcpy(rd_best.y_ac_levels[it->i4], tmp_levels, + sizeof(rd_best.y_ac_levels[it->i4])); } } - SetRDScore(dqm->lambda_mode_, &rd_i4); + SetRDScore(dqm->lambda_mode, &rd_i4); AddScore(&rd_best, &rd_i4); if (rd_best.score >= rd->score) { return 0; } total_header_bits += (int)rd_i4.H; // <- equal to mode_costs[best_mode]; - if (total_header_bits > enc->max_i4_header_bits_) { + if (total_header_bits > enc->max_i4_header_bits) { return 0; } // Copy selected samples if not in the right place already. - if (best_block != best_blocks + VP8Scan[it->i4_]) { - VP8Copy4x4(best_block, best_blocks + VP8Scan[it->i4_]); + if (best_block != best_blocks + VP8Scan[it->i4]) { + VP8Copy4x4(best_block, best_blocks + VP8Scan[it->i4]); } - rd->modes_i4[it->i4_] = best_mode; - it->top_nz_[it->i4_ & 3] = it->left_nz_[it->i4_ >> 2] = (rd_i4.nz ? 1 : 0); + rd->modes_i4[it->i4] = best_mode; + it->top_nz[it->i4 & 3] = it->left_nz[it->i4 >> 2] = (rd_i4.nz ? 1 : 0); } while (VP8IteratorRotateI4(it, best_blocks)); // finalize state CopyScore(rd, &rd_best); VP8SetIntra4Mode(it, rd->modes_i4); @@ -1169,15 +1173,15 @@ //------------------------------------------------------------------------------ static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it, VP8ModeScore* WEBP_RESTRICT const rd) { const int kNumBlocks = 8; - const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; - const int lambda = dqm->lambda_uv_; - const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; - uint8_t* tmp_dst = it->yuv_out2_ + U_OFF_ENC; // scratch buffer - uint8_t* dst0 = it->yuv_out_ + U_OFF_ENC; + const VP8SegmentInfo* const dqm = &it->enc->dqm[it->mb->segment]; + const int lambda = dqm->lambda_uv; + const uint8_t* const src = it->yuv_in + U_OFF_ENC; + uint8_t* tmp_dst = it->yuv_out2 + U_OFF_ENC; // scratch buffer + uint8_t* dst0 = it->yuv_out + U_OFF_ENC; uint8_t* dst = dst0; VP8ModeScore rd_best; int mode; rd->mode_uv = -1; @@ -1200,78 +1204,78 @@ SetRDScore(lambda, &rd_uv); if (mode == 0 || rd_uv.score < rd_best.score) { CopyScore(&rd_best, &rd_uv); rd->mode_uv = mode; memcpy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels)); - if (it->top_derr_ != NULL) { + if (it->top_derr != NULL) { memcpy(rd->derr, rd_uv.derr, sizeof(rd_uv.derr)); } SwapPtr(&dst, &tmp_dst); } } VP8SetIntraUVMode(it, rd->mode_uv); AddScore(rd, &rd_best); if (dst != dst0) { // copy 16x8 block if needed VP8Copy16x8(dst, dst0); } - if (it->top_derr_ != NULL) { // store diffusion errors for next block + if (it->top_derr != NULL) { // store diffusion errors for next block StoreDiffusionErrors(it, rd); } } //------------------------------------------------------------------------------ // Final reconstruction and quantization. static void SimpleQuantize(VP8EncIterator* WEBP_RESTRICT const it, VP8ModeScore* WEBP_RESTRICT const rd) { - const VP8Encoder* const enc = it->enc_; - const int is_i16 = (it->mb_->type_ == 1); + const VP8Encoder* const enc = it->enc; + const int is_i16 = (it->mb->type == 1); int nz = 0; if (is_i16) { - nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF_ENC, it->preds_[0]); + nz = ReconstructIntra16(it, rd, it->yuv_out + Y_OFF_ENC, it->preds[0]); } else { VP8IteratorStartI4(it); do { const int mode = - it->preds_[(it->i4_ & 3) + (it->i4_ >> 2) * enc->preds_w_]; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_]; - uint8_t* const dst = it->yuv_out_ + Y_OFF_ENC + VP8Scan[it->i4_]; + it->preds[(it->i4 & 3) + (it->i4 >> 2) * enc->preds_w]; + const uint8_t* const src = it->yuv_in + Y_OFF_ENC + VP8Scan[it->i4]; + uint8_t* const dst = it->yuv_out + Y_OFF_ENC + VP8Scan[it->i4]; MakeIntra4Preds(it); - nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_], - src, dst, mode) << it->i4_; - } while (VP8IteratorRotateI4(it, it->yuv_out_ + Y_OFF_ENC)); + nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4], + src, dst, mode) << it->i4; + } while (VP8IteratorRotateI4(it, it->yuv_out + Y_OFF_ENC)); } - nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF_ENC, it->mb_->uv_mode_); + nz |= ReconstructUV(it, rd, it->yuv_out + U_OFF_ENC, it->mb->uv_mode); rd->nz = nz; } // Refine intra16/intra4 sub-modes based on distortion only (not rate). static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it, int try_both_modes, int refine_uv_mode, VP8ModeScore* WEBP_RESTRICT const rd) { score_t best_score = MAX_COST; int nz = 0; int mode; - int is_i16 = try_both_modes || (it->mb_->type_ == 1); + int is_i16 = try_both_modes || (it->mb->type == 1); - const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; + const VP8SegmentInfo* const dqm = &it->enc->dqm[it->mb->segment]; // Some empiric constants, of approximate order of magnitude. const int lambda_d_i16 = 106; const int lambda_d_i4 = 11; const int lambda_d_uv = 120; - score_t score_i4 = dqm->i4_penalty_; + score_t score_i4 = dqm->i4_penalty; score_t i4_bit_sum = 0; - const score_t bit_limit = try_both_modes ? it->enc_->mb_header_limit_ + const score_t bit_limit = try_both_modes ? it->enc->mb_header_limit : MAX_COST; // no early-out allowed if (is_i16) { // First, evaluate Intra16 distortion int best_mode = -1; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; + const uint8_t* const src = it->yuv_in + Y_OFF_ENC; for (mode = 0; mode < NUM_PRED_MODES; ++mode) { - const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode]; + const uint8_t* const ref = it->yuv_p + VP8I16ModeOffsets[mode]; const score_t score = (score_t)VP8SSE16x16(src, ref) * RD_DISTO_MULT + VP8FixedCostsI16[mode] * lambda_d_i16; if (mode > 0 && VP8FixedCostsI16[mode] > bit_limit) { continue; } @@ -1279,14 +1283,14 @@ if (score < best_score) { best_mode = mode; best_score = score; } } - if (it->x_ == 0 || it->y_ == 0) { + if (it->x == 0 || it->y == 0) { // avoid starting a checkerboard resonance from the border. See bug #432. if (IsFlatSource16(src)) { - best_mode = (it->x_ == 0) ? 0 : 2; + best_mode = (it->x == 0) ? 0 : 2; try_both_modes = 0; // stick to i16 } } VP8SetIntra16Mode(it, best_mode); // we'll reconstruct later, if i16 mode actually gets selected @@ -1299,64 +1303,64 @@ is_i16 = 0; VP8IteratorStartI4(it); do { int best_i4_mode = -1; score_t best_i4_score = MAX_COST; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_]; + const uint8_t* const src = it->yuv_in + Y_OFF_ENC + VP8Scan[it->i4]; const uint16_t* const mode_costs = GetCostModeI4(it, rd->modes_i4); MakeIntra4Preds(it); for (mode = 0; mode < NUM_BMODES; ++mode) { - const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode]; + const uint8_t* const ref = it->yuv_p + VP8I4ModeOffsets[mode]; const score_t score = VP8SSE4x4(src, ref) * RD_DISTO_MULT + mode_costs[mode] * lambda_d_i4; if (score < best_i4_score) { best_i4_mode = mode; best_i4_score = score; } } i4_bit_sum += mode_costs[best_i4_mode]; - rd->modes_i4[it->i4_] = best_i4_mode; + rd->modes_i4[it->i4] = best_i4_mode; score_i4 += best_i4_score; if (score_i4 >= best_score || i4_bit_sum > bit_limit) { // Intra4 won't be better than Intra16. Bail out and pick Intra16. is_i16 = 1; break; - } else { // reconstruct partial block inside yuv_out2_ buffer - uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF_ENC + VP8Scan[it->i4_]; - nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_], - src, tmp_dst, best_i4_mode) << it->i4_; + } else { // reconstruct partial block inside yuv_out2 buffer + uint8_t* const tmp_dst = it->yuv_out2 + Y_OFF_ENC + VP8Scan[it->i4]; + nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4], + src, tmp_dst, best_i4_mode) << it->i4; } - } while (VP8IteratorRotateI4(it, it->yuv_out2_ + Y_OFF_ENC)); + } while (VP8IteratorRotateI4(it, it->yuv_out2 + Y_OFF_ENC)); } // Final reconstruction, depending on which mode is selected. if (!is_i16) { VP8SetIntra4Mode(it, rd->modes_i4); SwapOut(it); best_score = score_i4; } else { - nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF_ENC, it->preds_[0]); + nz = ReconstructIntra16(it, rd, it->yuv_out + Y_OFF_ENC, it->preds[0]); } // ... and UV! if (refine_uv_mode) { int best_mode = -1; score_t best_uv_score = MAX_COST; - const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; + const uint8_t* const src = it->yuv_in + U_OFF_ENC; for (mode = 0; mode < NUM_PRED_MODES; ++mode) { - const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode]; + const uint8_t* const ref = it->yuv_p + VP8UVModeOffsets[mode]; const score_t score = VP8SSE16x8(src, ref) * RD_DISTO_MULT + VP8FixedCostsUV[mode] * lambda_d_uv; if (score < best_uv_score) { best_mode = mode; best_uv_score = score; } } VP8SetIntraUVMode(it, best_mode); } - nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF_ENC, it->mb_->uv_mode_); + nz |= ReconstructUV(it, rd, it->yuv_out + U_OFF_ENC, it->mb->uv_mode); rd->nz = nz; rd->score = best_score; } @@ -1365,28 +1369,28 @@ int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it, VP8ModeScore* WEBP_RESTRICT const rd, VP8RDLevel rd_opt) { int is_skipped; - const int method = it->enc_->method_; + const int method = it->enc->method; InitScore(rd); // We can perform predictions for Luma16x16 and Chroma8x8 already. // Luma4x4 predictions needs to be done as-we-go. VP8MakeLuma16Preds(it); VP8MakeChroma8Preds(it); if (rd_opt > RD_OPT_NONE) { - it->do_trellis_ = (rd_opt >= RD_OPT_TRELLIS_ALL); + it->do_trellis = (rd_opt >= RD_OPT_TRELLIS_ALL); PickBestIntra16(it, rd); if (method >= 2) { PickBestIntra4(it, rd); } PickBestUV(it, rd); if (rd_opt == RD_OPT_TRELLIS) { // finish off with trellis-optim now - it->do_trellis_ = 1; + it->do_trellis = 1; SimpleQuantize(it, rd); } } else { // At this point we have heuristically decided intra16 / intra4. // For method >= 2, pick the best intra4/intra16 based on SSE (~tad slower). diff --git a/media/libwebp/src/enc/syntax_enc.c b/media/libwebp/src/enc/syntax_enc.c --- a/media/libwebp/src/enc/syntax_enc.c +++ b/media/libwebp/src/enc/syntax_enc.c @@ -10,22 +10,27 @@ // Header syntax writing // // Author: Skal (pascal.massimino@gmail.com) #include +#include +#include "src/dec/common_dec.h" +#include "src/webp/types.h" +#include "src/enc/vp8i_enc.h" +#include "src/utils/bit_writer_utils.h" #include "src/utils/utils.h" +#include "src/webp/encode.h" #include "src/webp/format_constants.h" // RIFF constants #include "src/webp/mux_types.h" // ALPHA_FLAG -#include "src/enc/vp8i_enc.h" //------------------------------------------------------------------------------ // Helper functions static int IsVP8XNeeded(const VP8Encoder* const enc) { - return !!enc->has_alpha_; // Currently the only case when VP8X is needed. - // This could change in the future. + return !!enc->has_alpha; // Currently the only case when VP8X is needed. + // This could change in the future. } static int PutPaddingByte(const WebPPicture* const pic) { const uint8_t pad_byte[1] = { 0 }; return !!pic->writer(pad_byte, 1, pic); @@ -34,11 +39,11 @@ //------------------------------------------------------------------------------ // Writers for header's various pieces (in order of appearance) static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc, size_t riff_size) { - const WebPPicture* const pic = enc->pic_; + const WebPPicture* const pic = enc->pic; uint8_t riff[RIFF_HEADER_SIZE] = { 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P' }; assert(riff_size == (uint32_t)riff_size); PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); @@ -47,21 +52,21 @@ } return VP8_ENC_OK; } static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) { - const WebPPicture* const pic = enc->pic_; + const WebPPicture* const pic = enc->pic; uint8_t vp8x[CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE] = { 'V', 'P', '8', 'X' }; uint32_t flags = 0; assert(IsVP8XNeeded(enc)); assert(pic->width >= 1 && pic->height >= 1); assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE); - if (enc->has_alpha_) { + if (enc->has_alpha) { flags |= ALPHA_FLAG; } PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE); PutLE32(vp8x + CHUNK_HEADER_SIZE, flags); @@ -72,30 +77,30 @@ } return VP8_ENC_OK; } static WebPEncodingError PutAlphaChunk(const VP8Encoder* const enc) { - const WebPPicture* const pic = enc->pic_; + const WebPPicture* const pic = enc->pic; uint8_t alpha_chunk_hdr[CHUNK_HEADER_SIZE] = { 'A', 'L', 'P', 'H' }; - assert(enc->has_alpha_); + assert(enc->has_alpha); // Alpha chunk header. - PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size_); + PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size); if (!pic->writer(alpha_chunk_hdr, sizeof(alpha_chunk_hdr), pic)) { return VP8_ENC_ERROR_BAD_WRITE; } // Alpha chunk data. - if (!pic->writer(enc->alpha_data_, enc->alpha_data_size_, pic)) { + if (!pic->writer(enc->alpha_data, enc->alpha_data_size, pic)) { return VP8_ENC_ERROR_BAD_WRITE; } // Padding. - if ((enc->alpha_data_size_ & 1) && !PutPaddingByte(pic)) { + if ((enc->alpha_data_size & 1) && !PutPaddingByte(pic)) { return VP8_ENC_ERROR_BAD_WRITE; } return VP8_ENC_OK; } @@ -146,11 +151,11 @@ } // WebP Headers. static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0, size_t vp8_size, size_t riff_size) { - WebPPicture* const pic = enc->pic_; + WebPPicture* const pic = enc->pic; WebPEncodingError err = VP8_ENC_OK; // RIFF header. err = PutRIFFHeader(enc, riff_size); if (err != VP8_ENC_OK) goto Error; @@ -160,21 +165,21 @@ err = PutVP8XHeader(enc); if (err != VP8_ENC_OK) goto Error; } // Alpha. - if (enc->has_alpha_) { + if (enc->has_alpha) { err = PutAlphaChunk(enc); if (err != VP8_ENC_OK) goto Error; } // VP8 header. err = PutVP8Header(pic, vp8_size); if (err != VP8_ENC_OK) goto Error; // VP8 frame header. - err = PutVP8FrameHeader(pic, enc->profile_, size0); + err = PutVP8FrameHeader(pic, enc->profile, size0); if (err != VP8_ENC_OK) goto Error; // All OK. return 1; @@ -184,75 +189,75 @@ } // Segmentation header static void PutSegmentHeader(VP8BitWriter* const bw, const VP8Encoder* const enc) { - const VP8EncSegmentHeader* const hdr = &enc->segment_hdr_; - const VP8EncProba* const proba = &enc->proba_; - if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) { + const VP8EncSegmentHeader* const hdr = &enc->segment_hdr; + const VP8EncProba* const proba = &enc->proba; + if (VP8PutBitUniform(bw, (hdr->num_segments > 1))) { // We always 'update' the quant and filter strength values const int update_data = 1; int s; - VP8PutBitUniform(bw, hdr->update_map_); + VP8PutBitUniform(bw, hdr->update_map); if (VP8PutBitUniform(bw, update_data)) { // we always use absolute values, not relative ones VP8PutBitUniform(bw, 1); // (segment_feature_mode = 1. Paragraph 9.3.) for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - VP8PutSignedBits(bw, enc->dqm_[s].quant_, 7); + VP8PutSignedBits(bw, enc->dqm[s].quant, 7); } for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - VP8PutSignedBits(bw, enc->dqm_[s].fstrength_, 6); + VP8PutSignedBits(bw, enc->dqm[s].fstrength, 6); } } - if (hdr->update_map_) { + if (hdr->update_map) { for (s = 0; s < 3; ++s) { - if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) { - VP8PutBits(bw, proba->segments_[s], 8); + if (VP8PutBitUniform(bw, (proba->segments[s] != 255u))) { + VP8PutBits(bw, proba->segments[s], 8); } } } } } // Filtering parameters header static void PutFilterHeader(VP8BitWriter* const bw, const VP8EncFilterHeader* const hdr) { - const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0); - VP8PutBitUniform(bw, hdr->simple_); - VP8PutBits(bw, hdr->level_, 6); - VP8PutBits(bw, hdr->sharpness_, 3); + const int use_lf_delta = (hdr->i4x4_lf_delta != 0); + VP8PutBitUniform(bw, hdr->simple); + VP8PutBits(bw, hdr->level, 6); + VP8PutBits(bw, hdr->sharpness, 3); if (VP8PutBitUniform(bw, use_lf_delta)) { - // '0' is the default value for i4x4_lf_delta_ at frame #0. - const int need_update = (hdr->i4x4_lf_delta_ != 0); + // '0' is the default value for i4x4_lf_delta at frame #0. + const int need_update = (hdr->i4x4_lf_delta != 0); if (VP8PutBitUniform(bw, need_update)) { // we don't use ref_lf_delta => emit four 0 bits VP8PutBits(bw, 0, 4); // we use mode_lf_delta for i4x4 - VP8PutSignedBits(bw, hdr->i4x4_lf_delta_, 6); + VP8PutSignedBits(bw, hdr->i4x4_lf_delta, 6); VP8PutBits(bw, 0, 3); // all others unused } } } // Nominal quantization parameters static void PutQuant(VP8BitWriter* const bw, const VP8Encoder* const enc) { - VP8PutBits(bw, enc->base_quant_, 7); - VP8PutSignedBits(bw, enc->dq_y1_dc_, 4); - VP8PutSignedBits(bw, enc->dq_y2_dc_, 4); - VP8PutSignedBits(bw, enc->dq_y2_ac_, 4); - VP8PutSignedBits(bw, enc->dq_uv_dc_, 4); - VP8PutSignedBits(bw, enc->dq_uv_ac_, 4); + VP8PutBits(bw, enc->base_quant, 7); + VP8PutSignedBits(bw, enc->dq_y1_dc, 4); + VP8PutSignedBits(bw, enc->dq_y2_dc, 4); + VP8PutSignedBits(bw, enc->dq_y2_ac, 4); + VP8PutSignedBits(bw, enc->dq_uv_dc, 4); + VP8PutSignedBits(bw, enc->dq_uv_ac, 4); } // Partition sizes static int EmitPartitionsSize(const VP8Encoder* const enc, WebPPicture* const pic) { uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)]; int p; - for (p = 0; p < enc->num_parts_ - 1; ++p) { - const size_t part_size = VP8BitWriterSize(enc->parts_ + p); + for (p = 0; p < enc->num_parts - 1; ++p) { + const size_t part_size = VP8BitWriterSize(enc->parts + p); if (part_size >= VP8_MAX_PARTITION_SIZE) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW); } buf[3 * p + 0] = (part_size >> 0) & 0xff; buf[3 * p + 1] = (part_size >> 8) & 0xff; @@ -265,66 +270,66 @@ } //------------------------------------------------------------------------------ static int GeneratePartition0(VP8Encoder* const enc) { - VP8BitWriter* const bw = &enc->bw_; - const int mb_size = enc->mb_w_ * enc->mb_h_; + VP8BitWriter* const bw = &enc->bw; + const int mb_size = enc->mb_w * enc->mb_h; uint64_t pos1, pos2, pos3; pos1 = VP8BitWriterPos(bw); if (!VP8BitWriterInit(bw, mb_size * 7 / 8)) { // ~7 bits per macroblock - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); } VP8PutBitUniform(bw, 0); // colorspace VP8PutBitUniform(bw, 0); // clamp type PutSegmentHeader(bw, enc); - PutFilterHeader(bw, &enc->filter_hdr_); - VP8PutBits(bw, enc->num_parts_ == 8 ? 3 : - enc->num_parts_ == 4 ? 2 : - enc->num_parts_ == 2 ? 1 : 0, 2); + PutFilterHeader(bw, &enc->filter_hdr); + VP8PutBits(bw, enc->num_parts == 8 ? 3 : + enc->num_parts == 4 ? 2 : + enc->num_parts == 2 ? 1 : 0, 2); PutQuant(bw, enc); VP8PutBitUniform(bw, 0); // no proba update - VP8WriteProbas(bw, &enc->proba_); + VP8WriteProbas(bw, &enc->proba); pos2 = VP8BitWriterPos(bw); VP8CodeIntraModes(enc); VP8BitWriterFinish(bw); pos3 = VP8BitWriterPos(bw); #if !defined(WEBP_DISABLE_STATS) - if (enc->pic_->stats) { - enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3); - enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3); - enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_; + if (enc->pic->stats) { + enc->pic->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3); + enc->pic->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3); + enc->pic->stats->alpha_data_size = (int)enc->alpha_data_size; } #else (void)pos1; (void)pos2; (void)pos3; #endif - if (bw->error_) { - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + if (bw->error) { + return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); } return 1; } void VP8EncFreeBitWriters(VP8Encoder* const enc) { int p; - VP8BitWriterWipeOut(&enc->bw_); - for (p = 0; p < enc->num_parts_; ++p) { - VP8BitWriterWipeOut(enc->parts_ + p); + VP8BitWriterWipeOut(&enc->bw); + for (p = 0; p < enc->num_parts; ++p) { + VP8BitWriterWipeOut(enc->parts + p); } } int VP8EncWrite(VP8Encoder* const enc) { - WebPPicture* const pic = enc->pic_; - VP8BitWriter* const bw = &enc->bw_; + WebPPicture* const pic = enc->pic; + VP8BitWriter* const bw = &enc->bw; const int task_percent = 19; - const int percent_per_part = task_percent / enc->num_parts_; - const int final_percent = enc->percent_ + task_percent; + const int percent_per_part = task_percent / enc->num_parts; + const int final_percent = enc->percent + task_percent; int ok = 0; size_t vp8_size, pad, riff_size; int p; // Partition #0 with header and partition sizes @@ -332,26 +337,26 @@ if (!ok) return 0; // Compute VP8 size vp8_size = VP8_FRAME_HEADER_SIZE + VP8BitWriterSize(bw) + - 3 * (enc->num_parts_ - 1); - for (p = 0; p < enc->num_parts_; ++p) { - vp8_size += VP8BitWriterSize(enc->parts_ + p); + 3 * (enc->num_parts - 1); + for (p = 0; p < enc->num_parts; ++p) { + vp8_size += VP8BitWriterSize(enc->parts + p); } pad = vp8_size & 1; vp8_size += pad; // Compute RIFF size // At the minimum it is: "WEBPVP8 nnnn" + VP8 data size. riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8_size; if (IsVP8XNeeded(enc)) { // Add size for: VP8X header + data. riff_size += CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; } - if (enc->has_alpha_) { // Add size for: ALPH header + data. - const uint32_t padded_alpha_size = enc->alpha_data_size_ + - (enc->alpha_data_size_ & 1); + if (enc->has_alpha) { // Add size for: ALPH header + data. + const uint32_t padded_alpha_size = enc->alpha_data_size + + (enc->alpha_data_size & 1); riff_size += CHUNK_HEADER_SIZE + padded_alpha_size; } // RIFF size should fit in 32-bits. if (riff_size > 0xfffffffeU) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG); @@ -366,27 +371,26 @@ && EmitPartitionsSize(enc, pic); VP8BitWriterWipeOut(bw); // will free the internal buffer. } // Token partitions - for (p = 0; p < enc->num_parts_; ++p) { - const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p); - const size_t size = VP8BitWriterSize(enc->parts_ + p); + for (p = 0; p < enc->num_parts; ++p) { + const uint8_t* const buf = VP8BitWriterBuf(enc->parts + p); + const size_t size = VP8BitWriterSize(enc->parts + p); if (size) ok = ok && pic->writer(buf, size, pic); - VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer. - ok = ok && WebPReportProgress(pic, enc->percent_ + percent_per_part, - &enc->percent_); + VP8BitWriterWipeOut(enc->parts + p); // will free the internal buffer. + ok = ok && WebPReportProgress(pic, enc->percent + percent_per_part, + &enc->percent); } // Padding byte if (ok && pad) { ok = PutPaddingByte(pic); } - enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size); - ok = ok && WebPReportProgress(pic, final_percent, &enc->percent_); + enc->coded_size = (int)(CHUNK_HEADER_SIZE + riff_size); + ok = ok && WebPReportProgress(pic, final_percent, &enc->percent); if (!ok) WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); return ok; } //------------------------------------------------------------------------------ - diff --git a/media/libwebp/src/enc/token_enc.c b/media/libwebp/src/enc/token_enc.c --- a/media/libwebp/src/enc/token_enc.c +++ b/media/libwebp/src/enc/token_enc.c @@ -18,13 +18,17 @@ #include #include #include +#include "src/dec/common_dec.h" +#include "src/dsp/dsp.h" #include "src/enc/cost_enc.h" #include "src/enc/vp8i_enc.h" +#include "src/utils/bit_writer_utils.h" #include "src/utils/utils.h" +#include "src/webp/types.h" #if !defined(DISABLE_TOKEN_BUFFER) // we use pages to reduce the number of memcpy() #define MIN_PAGE_SIZE 8192 // minimum number of token per page @@ -32,55 +36,55 @@ typedef uint16_t token_t; // bit #15: bit value // bit #14: flags for constant proba or idx // bits #0..13: slot or constant proba struct VP8Tokens { - VP8Tokens* next_; // pointer to next page + VP8Tokens* next; // pointer to next page }; -// Token data is located in memory just after the next_ field. +// Token data is located in memory just after the 'next' field. // This macro is used to return their address and hide the trick. #define TOKEN_DATA(p) ((const token_t*)&(p)[1]) //------------------------------------------------------------------------------ void VP8TBufferInit(VP8TBuffer* const b, int page_size) { - b->tokens_ = NULL; - b->pages_ = NULL; - b->last_page_ = &b->pages_; - b->left_ = 0; - b->page_size_ = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size; - b->error_ = 0; + b->tokens = NULL; + b->pages = NULL; + b->last_page = &b->pages; + b->left = 0; + b->page_size = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size; + b->error = 0; } void VP8TBufferClear(VP8TBuffer* const b) { if (b != NULL) { - VP8Tokens* p = b->pages_; + VP8Tokens* p = b->pages; while (p != NULL) { - VP8Tokens* const next = p->next_; + VP8Tokens* const next = p->next; WebPSafeFree(p); p = next; } - VP8TBufferInit(b, b->page_size_); + VP8TBufferInit(b, b->page_size); } } static int TBufferNewPage(VP8TBuffer* const b) { VP8Tokens* page = NULL; - if (!b->error_) { - const size_t size = sizeof(*page) + b->page_size_ * sizeof(token_t); + if (!b->error) { + const size_t size = sizeof(*page) + b->page_size * sizeof(token_t); page = (VP8Tokens*)WebPSafeMalloc(1ULL, size); } if (page == NULL) { - b->error_ = 1; + b->error = 1; return 0; } - page->next_ = NULL; + page->next = NULL; - *b->last_page_ = page; - b->last_page_ = &page->next_; - b->left_ = b->page_size_; - b->tokens_ = (token_t*)TOKEN_DATA(page); + *b->last_page = page; + b->last_page = &page->next; + b->left = b->page_size; + b->tokens = (token_t*)TOKEN_DATA(page); return 1; } //------------------------------------------------------------------------------ @@ -90,25 +94,25 @@ static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, uint32_t bit, uint32_t proba_idx, proba_t* const stats) { assert(proba_idx < FIXED_PROBA_BIT); assert(bit <= 1); - if (b->left_ > 0 || TBufferNewPage(b)) { - const int slot = --b->left_; - b->tokens_[slot] = (bit << 15) | proba_idx; + if (b->left > 0 || TBufferNewPage(b)) { + const int slot = --b->left; + b->tokens[slot] = (bit << 15) | proba_idx; } VP8RecordStats(bit, stats); return bit; } static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b, uint32_t bit, uint32_t proba) { assert(proba < 256); assert(bit <= 1); - if (b->left_ > 0 || TBufferNewPage(b)) { - const int slot = --b->left_; - b->tokens_[slot] = (bit << 15) | FIXED_PROBA_BIT | proba; + if (b->left > 0 || TBufferNewPage(b)) { + const int slot = --b->left; + b->tokens[slot] = (bit << 15) | FIXED_PROBA_BIT | proba; } } int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res, VP8TBuffer* const tokens) { @@ -197,16 +201,16 @@ //------------------------------------------------------------------------------ // Final coding pass, with known probabilities int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw, const uint8_t* const probas, int final_pass) { - const VP8Tokens* p = b->pages_; - assert(!b->error_); + const VP8Tokens* p = b->pages; + assert(!b->error); while (p != NULL) { - const VP8Tokens* const next = p->next_; - const int N = (next == NULL) ? b->left_ : 0; - int n = b->page_size_; + const VP8Tokens* const next = p->next; + const int N = (next == NULL) ? b->left : 0; + int n = b->page_size; const token_t* const tokens = TOKEN_DATA(p); while (n-- > N) { const token_t token = tokens[n]; const int bit = (token >> 15) & 1; if (token & FIXED_PROBA_BIT) { @@ -216,23 +220,23 @@ } } if (final_pass) WebPSafeFree((void*)p); p = next; } - if (final_pass) b->pages_ = NULL; + if (final_pass) b->pages = NULL; return 1; } // Size estimation size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) { size_t size = 0; - const VP8Tokens* p = b->pages_; - assert(!b->error_); + const VP8Tokens* p = b->pages; + assert(!b->error); while (p != NULL) { - const VP8Tokens* const next = p->next_; - const int N = (next == NULL) ? b->left_ : 0; - int n = b->page_size_; + const VP8Tokens* const next = p->next; + const int N = (next == NULL) ? b->left : 0; + int n = b->page_size; const token_t* const tokens = TOKEN_DATA(p); while (n-- > N) { const token_t token = tokens[n]; const int bit = token & (1 << 15); if (token & FIXED_PROBA_BIT) { @@ -257,6 +261,5 @@ void VP8TBufferClear(VP8TBuffer* const b) { (void)b; } #endif // !DISABLE_TOKEN_BUFFER - diff --git a/media/libwebp/src/enc/tree_enc.c b/media/libwebp/src/enc/tree_enc.c --- a/media/libwebp/src/enc/tree_enc.c +++ b/media/libwebp/src/enc/tree_enc.c @@ -9,11 +9,16 @@ // // Coding of token probabilities, intra modes and segments. // // Author: Skal (pascal.massimino@gmail.com) +#include + +#include "src/dec/common_dec.h" +#include "src/webp/types.h" #include "src/enc/vp8i_enc.h" +#include "src/utils/bit_writer_utils.h" //------------------------------------------------------------------------------ // Default probabilities // Paragraph 13.5 @@ -152,17 +157,17 @@ } } }; void VP8DefaultProbas(VP8Encoder* const enc) { - VP8EncProba* const probas = &enc->proba_; - probas->use_skip_proba_ = 0; - memset(probas->segments_, 255u, sizeof(probas->segments_)); - memcpy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0)); - // Note: we could hard-code the level_costs_ corresponding to VP8CoeffsProba0, + VP8EncProba* const probas = &enc->proba; + probas->use_skip_proba = 0; + memset(probas->segments, 255u, sizeof(probas->segments)); + memcpy(probas->coeffs, VP8CoeffsProba0, sizeof(VP8CoeffsProba0)); + // Note: we could hard-code the level_costs corresponding to VP8CoeffsProba0, // but that's ~11k of static data. Better call VP8CalculateLevelCosts() later. - probas->dirty_ = 1; + probas->dirty = 1; } // Paragraph 11.5. 900bytes. static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = { { { 231, 120, 48, 89, 115, 113, 120, 152, 112 }, @@ -309,26 +314,26 @@ if (VP8PutBit(bw, s >= 2, p[0])) p += 1; VP8PutBit(bw, s & 1, p[1]); } void VP8CodeIntraModes(VP8Encoder* const enc) { - VP8BitWriter* const bw = &enc->bw_; + VP8BitWriter* const bw = &enc->bw; VP8EncIterator it; VP8IteratorInit(enc, &it); do { - const VP8MBInfo* const mb = it.mb_; - const uint8_t* preds = it.preds_; - if (enc->segment_hdr_.update_map_) { - PutSegment(bw, mb->segment_, enc->proba_.segments_); + const VP8MBInfo* const mb = it.mb; + const uint8_t* preds = it.preds; + if (enc->segment_hdr.update_map) { + PutSegment(bw, mb->segment, enc->proba.segments); } - if (enc->proba_.use_skip_proba_) { - VP8PutBit(bw, mb->skip_, enc->proba_.skip_proba_); + if (enc->proba.use_skip_proba) { + VP8PutBit(bw, mb->skip, enc->proba.skip_proba); } - if (VP8PutBit(bw, (mb->type_ != 0), 145)) { // i16x16 + if (VP8PutBit(bw, (mb->type != 0), 145)) { // i16x16 PutI16Mode(bw, preds[0]); } else { - const int preds_w = enc->preds_w_; + const int preds_w = enc->preds_w; const uint8_t* top_pred = preds - preds_w; int x, y; for (y = 0; y < 4; ++y) { int left = preds[-1]; for (x = 0; x < 4; ++x) { @@ -337,11 +342,11 @@ } top_pred = preds; preds += preds_w; } } - PutUVMode(bw, mb->uv_mode_); + PutUVMode(bw, mb->uv_mode); } while (VP8IteratorNext(&it)); } //------------------------------------------------------------------------------ // Paragraph 13 @@ -486,19 +491,18 @@ int t, b, c, p; for (t = 0; t < NUM_TYPES; ++t) { for (b = 0; b < NUM_BANDS; ++b) { for (c = 0; c < NUM_CTX; ++c) { for (p = 0; p < NUM_PROBAS; ++p) { - const uint8_t p0 = probas->coeffs_[t][b][c][p]; + const uint8_t p0 = probas->coeffs[t][b][c][p]; const int update = (p0 != VP8CoeffsProba0[t][b][c][p]); if (VP8PutBit(bw, update, VP8CoeffsUpdateProba[t][b][c][p])) { VP8PutBits(bw, p0, 8); } } } } } - if (VP8PutBitUniform(bw, probas->use_skip_proba_)) { - VP8PutBits(bw, probas->skip_proba_, 8); + if (VP8PutBitUniform(bw, probas->use_skip_proba)) { + VP8PutBits(bw, probas->skip_proba, 8); } } - diff --git a/media/libwebp/src/enc/vp8i_enc.h b/media/libwebp/src/enc/vp8i_enc.h --- a/media/libwebp/src/enc/vp8i_enc.h +++ b/media/libwebp/src/enc/vp8i_enc.h @@ -13,28 +13,30 @@ #ifndef WEBP_ENC_VP8I_ENC_H_ #define WEBP_ENC_VP8I_ENC_H_ #include // for memcpy() + #include "src/dec/common_dec.h" #include "src/dsp/cpu.h" #include "src/dsp/dsp.h" #include "src/utils/bit_writer_utils.h" #include "src/utils/thread_utils.h" #include "src/utils/utils.h" #include "src/webp/encode.h" +#include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif //------------------------------------------------------------------------------ // Various defines and enums // version numbers #define ENC_MAJ_VERSION 1 -#define ENC_MIN_VERSION 5 +#define ENC_MIN_VERSION 6 #define ENC_REV_VERSION 0 enum { MAX_LF_LEVELS = 64, // Maximum loop filter level MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost MAX_LEVEL = 2047 // max level (note: max codable is 2047 + 67) @@ -47,22 +49,22 @@ RD_OPT_TRELLIS_ALL = 3 // trellis-quant for every scoring (much slower) } VP8RDLevel; // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // The original or reconstructed samples can be accessed using VP8Scan[]. -// The predicted blocks can be accessed using offsets to yuv_p_ and +// The predicted blocks can be accessed using offsets to 'yuv_p' and // the arrays VP8*ModeOffsets[]. -// * YUV Samples area (yuv_in_/yuv_out_/yuv_out2_) +// * YUV Samples area ('yuv_in'/'yuv_out'/'yuv_out2') // (see VP8Scan[] for accessing the blocks, along with // Y_OFF_ENC/U_OFF_ENC/V_OFF_ENC): // +----+----+ // Y_OFF_ENC |YYYY|UUVV| // U_OFF_ENC |YYYY|UUVV| // V_OFF_ENC |YYYY|....| <- 25% wasted U/V area // |YYYY|....| // +----+----+ -// * Prediction area ('yuv_p_', size = PRED_SIZE_ENC) +// * Prediction area ('yuv_p', size = PRED_SIZE_ENC) // Intra16 predictions (16x16 block each, two per row): // |I16DC16|I16TM16| // |I16VE16|I16HE16| // Chroma U/V predictions (16x8 block each, two per row): // |C8DC8|C8TM8| @@ -136,74 +138,74 @@ typedef struct VP8Encoder VP8Encoder; // segment features typedef struct { - int num_segments_; // Actual number of segments. 1 segment only = unused. - int update_map_; // whether to update the segment map or not. + int num_segments; // Actual number of segments. 1 segment only = unused. + int update_map; // whether to update the segment map or not. // must be 0 if there's only 1 segment. - int size_; // bit-cost for transmitting the segment map + int size; // bit-cost for transmitting the segment map } VP8EncSegmentHeader; // Struct collecting all frame-persistent probabilities. typedef struct { - uint8_t segments_[3]; // probabilities for segment tree - uint8_t skip_proba_; // final probability of being skipped. - ProbaArray coeffs_[NUM_TYPES][NUM_BANDS]; // 1056 bytes - StatsArray stats_[NUM_TYPES][NUM_BANDS]; // 4224 bytes - CostArray level_cost_[NUM_TYPES][NUM_BANDS]; // 13056 bytes - CostArrayMap remapped_costs_[NUM_TYPES]; // 1536 bytes - int dirty_; // if true, need to call VP8CalculateLevelCosts() - int use_skip_proba_; // Note: we always use skip_proba for now. - int nb_skip_; // number of skipped blocks + uint8_t segments[3]; // probabilities for segment tree + uint8_t skip_proba; // final probability of being skipped. + ProbaArray coeffs[NUM_TYPES][NUM_BANDS]; // 1056 bytes + StatsArray stats[NUM_TYPES][NUM_BANDS]; // 4224 bytes + CostArray level_cost[NUM_TYPES][NUM_BANDS]; // 13056 bytes + CostArrayMap remapped_costs[NUM_TYPES]; // 1536 bytes + int dirty; // if true, need to call VP8CalculateLevelCosts() + int use_skip_proba; // Note: we always use skip_proba for now. + int nb_skip; // number of skipped blocks } VP8EncProba; // Filter parameters. Not actually used in the code (we don't perform // the in-loop filtering), but filled from user's config typedef struct { - int simple_; // filtering type: 0=complex, 1=simple - int level_; // base filter level [0..63] - int sharpness_; // [0..7] - int i4x4_lf_delta_; // delta filter level for i4x4 relative to i16x16 + int simple; // filtering type: 0=complex, 1=simple + int level; // base filter level [0..63] + int sharpness; // [0..7] + int i4x4_lf_delta; // delta filter level for i4x4 relative to i16x16 } VP8EncFilterHeader; //------------------------------------------------------------------------------ // Informations about the macroblocks. typedef struct { // block type - unsigned int type_:2; // 0=i4x4, 1=i16x16 - unsigned int uv_mode_:2; - unsigned int skip_:1; - unsigned int segment_:2; - uint8_t alpha_; // quantization-susceptibility + unsigned int type:2; // 0=i4x4, 1=i16x16 + unsigned int uv_mode:2; + unsigned int skip:1; + unsigned int segment:2; + uint8_t alpha; // quantization-susceptibility } VP8MBInfo; typedef struct VP8Matrix { - uint16_t q_[16]; // quantizer steps - uint16_t iq_[16]; // reciprocals, fixed point. - uint32_t bias_[16]; // rounding bias - uint32_t zthresh_[16]; // value below which a coefficient is zeroed - uint16_t sharpen_[16]; // frequency boosters for slight sharpening + uint16_t q[16]; // quantizer steps + uint16_t iq[16]; // reciprocals, fixed point. + uint32_t bias[16]; // rounding bias + uint32_t zthresh[16]; // value below which a coefficient is zeroed + uint16_t sharpen[16]; // frequency boosters for slight sharpening } VP8Matrix; typedef struct { - VP8Matrix y1_, y2_, uv_; // quantization matrices - int alpha_; // quant-susceptibility, range [-127,127]. Zero is neutral. + VP8Matrix y1, y2, uv; // quantization matrices + int alpha; // quant-susceptibility, range [-127,127]. Zero is neutral. // Lower values indicate a lower risk of blurriness. - int beta_; // filter-susceptibility, range [0,255]. - int quant_; // final segment quantizer. - int fstrength_; // final in-loop filtering strength - int max_edge_; // max edge delta (for filtering strength) - int min_disto_; // minimum distortion required to trigger filtering record + int beta; // filter-susceptibility, range [0,255]. + int quant; // final segment quantizer. + int fstrength; // final in-loop filtering strength + int max_edge; // max edge delta (for filtering strength) + int min_disto; // minimum distortion required to trigger filtering record // reactivities - int lambda_i16_, lambda_i4_, lambda_uv_; - int lambda_mode_, lambda_trellis_, tlambda_; - int lambda_trellis_i16_, lambda_trellis_i4_, lambda_trellis_uv_; + int lambda_i16, lambda_i4, lambda_uv; + int lambda_mode, lambda_trellis, tlambda; + int lambda_trellis_i16, lambda_trellis_i4, lambda_trellis_uv; // lambda values for distortion-based evaluation - score_t i4_penalty_; // penalty for using Intra4 + score_t i4_penalty; // penalty for using Intra4 } VP8SegmentInfo; typedef int8_t DError[2 /* u/v */][2 /* top or left */]; // Handy transient struct to accumulate score and info during RD-optimization @@ -222,52 +224,52 @@ } VP8ModeScore; // Iterator structure to iterate through macroblocks, pointing to the // right neighbouring data (samples, predictions, contexts, ...) typedef struct { - int x_, y_; // current macroblock - uint8_t* yuv_in_; // input samples - uint8_t* yuv_out_; // output samples - uint8_t* yuv_out2_; // secondary buffer swapped with yuv_out_. - uint8_t* yuv_p_; // scratch buffer for prediction - VP8Encoder* enc_; // back-pointer - VP8MBInfo* mb_; // current macroblock - VP8BitWriter* bw_; // current bit-writer - uint8_t* preds_; // intra mode predictors (4x4 blocks) - uint32_t* nz_; // non-zero pattern + int x, y; // current macroblock + uint8_t* yuv_in; // input samples + uint8_t* yuv_out; // output samples + uint8_t* yuv_out2; // secondary buffer swapped with yuv_out. + uint8_t* yuv_p; // scratch buffer for prediction + VP8Encoder* enc; // back-pointer + VP8MBInfo* mb; // current macroblock + VP8BitWriter* bw; // current bit-writer + uint8_t* preds; // intra mode predictors (4x4 blocks) + uint32_t* nz; // non-zero pattern #if WEBP_AARCH64 && BPS == 32 - uint8_t i4_boundary_[40]; // 32+8 boundary samples needed by intra4x4 + uint8_t i4_boundary[40]; // 32+8 boundary samples needed by intra4x4 #else - uint8_t i4_boundary_[37]; // 32+5 boundary samples needed by intra4x4 + uint8_t i4_boundary[37]; // 32+5 boundary samples needed by intra4x4 #endif - uint8_t* i4_top_; // pointer to the current top boundary sample - int i4_; // current intra4x4 mode being tested - int top_nz_[9]; // top-non-zero context. - int left_nz_[9]; // left-non-zero. left_nz[8] is independent. - uint64_t bit_count_[4][3]; // bit counters for coded levels. - uint64_t luma_bits_; // macroblock bit-cost for luma - uint64_t uv_bits_; // macroblock bit-cost for chroma - LFStats* lf_stats_; // filter stats (borrowed from enc_) - int do_trellis_; // if true, perform extra level optimisation - int count_down_; // number of mb still to be processed - int count_down0_; // starting counter value (for progress) - int percent0_; // saved initial progress percent + uint8_t* i4_top; // pointer to the current top boundary sample + int i4; // current intra4x4 mode being tested + int top_nz[9]; // top-non-zero context. + int left_nz[9]; // left-non-zero. left_nz[8] is independent. + uint64_t bit_count[4][3]; // bit counters for coded levels. + uint64_t luma_bits; // macroblock bit-cost for luma + uint64_t uv_bits; // macroblock bit-cost for chroma + LFStats* lf_stats; // filter stats (borrowed from enc) + int do_trellis; // if true, perform extra level optimisation + int count_down; // number of mb still to be processed + int count_down0; // starting counter value (for progress) + int percent0; // saved initial progress percent - DError left_derr_; // left error diffusion (u/v) - DError* top_derr_; // top diffusion error - NULL if disabled + DError left_derr; // left error diffusion (u/v) + DError* top_derr; // top diffusion error - NULL if disabled - uint8_t* y_left_; // left luma samples (addressable from index -1 to 15). - uint8_t* u_left_; // left u samples (addressable from index -1 to 7) - uint8_t* v_left_; // left v samples (addressable from index -1 to 7) + uint8_t* y_left; // left luma samples (addressable from index -1 to 15). + uint8_t* u_left; // left u samples (addressable from index -1 to 7) + uint8_t* v_left; // left v samples (addressable from index -1 to 7) - uint8_t* y_top_; // top luma samples at position 'x_' - uint8_t* uv_top_; // top u/v samples at position 'x_', packed as 16 bytes + uint8_t* y_top; // top luma samples at position 'x' + uint8_t* uv_top; // top u/v samples at position 'x', packed as 16 bytes - // memory for storing y/u/v_left_ - uint8_t yuv_left_mem_[17 + 16 + 16 + 8 + WEBP_ALIGN_CST]; - // memory for yuv_* - uint8_t yuv_mem_[3 * YUV_SIZE_ENC + PRED_SIZE_ENC + WEBP_ALIGN_CST]; + // memory for storing y/u/v_left + uint8_t yuv_left_mem[17 + 16 + 16 + 8 + WEBP_ALIGN_CST]; + // memory for yuv* + uint8_t yuv_mem[3 * YUV_SIZE_ENC + PRED_SIZE_ENC + WEBP_ALIGN_CST]; } VP8EncIterator; // in iterator.c // must be called first void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it); @@ -283,11 +285,12 @@ void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32); // export decimated samples void VP8IteratorExport(const VP8EncIterator* const it); // go to next macroblock. Returns false if not finished. int VP8IteratorNext(VP8EncIterator* const it); -// save the yuv_out_ boundary values to top_/left_ arrays for next iterations. +// save the 'yuv_out' boundary values to 'top'/'left' arrays for next +// iterations. void VP8IteratorSaveBoundary(VP8EncIterator* const it); // Report progression based on macroblock rows. Return 0 for user-abort request. int VP8IteratorProgress(const VP8EncIterator* const it, int delta); // Intra4x4 iterations void VP8IteratorStartI4(VP8EncIterator* const it); @@ -311,17 +314,17 @@ typedef struct VP8Tokens VP8Tokens; // struct details in token.c typedef struct { #if !defined(DISABLE_TOKEN_BUFFER) - VP8Tokens* pages_; // first page - VP8Tokens** last_page_; // last page - uint16_t* tokens_; // set to (*last_page_)->tokens_ - int left_; // how many free tokens left before the page is full - int page_size_; // number of tokens per page + VP8Tokens* pages; // first page + VP8Tokens** last_page; // last page + uint16_t* tokens; // set to (*last_page)->tokens + int left; // how many free tokens left before the page is full + int page_size; // number of tokens per page #endif - int error_; // true in case of malloc error + int error; // true in case of malloc error } VP8TBuffer; // initialize an empty buffer void VP8TBufferInit(VP8TBuffer* const b, int page_size); void VP8TBufferClear(VP8TBuffer* const b); // de-allocate pages memory @@ -344,76 +347,76 @@ //------------------------------------------------------------------------------ // VP8Encoder struct VP8Encoder { - const WebPConfig* config_; // user configuration and parameters - WebPPicture* pic_; // input / output picture + const WebPConfig* config; // user configuration and parameters + WebPPicture* pic; // input / output picture // headers - VP8EncFilterHeader filter_hdr_; // filtering information - VP8EncSegmentHeader segment_hdr_; // segment information + VP8EncFilterHeader filter_hdr; // filtering information + VP8EncSegmentHeader segment_hdr; // segment information - int profile_; // VP8's profile, deduced from Config. + int profile; // VP8's profile, deduced from Config. // dimension, in macroblock units. - int mb_w_, mb_h_; - int preds_w_; // stride of the *preds_ prediction plane (=4*mb_w + 1) + int mb_w, mb_h; + int preds_w; // stride of the *preds prediction plane (=4*mb_w + 1) // number of partitions (1, 2, 4 or 8 = MAX_NUM_PARTITIONS) - int num_parts_; + int num_parts; // per-partition boolean decoders. - VP8BitWriter bw_; // part0 - VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions - VP8TBuffer tokens_; // token buffer + VP8BitWriter bw; // part0 + VP8BitWriter parts[MAX_NUM_PARTITIONS]; // token partitions + VP8TBuffer tokens; // token buffer - int percent_; // for progress + int percent; // for progress // transparency blob - int has_alpha_; - uint8_t* alpha_data_; // non-NULL if transparency is present - uint32_t alpha_data_size_; - WebPWorker alpha_worker_; + int has_alpha; + uint8_t* alpha_data; // non-NULL if transparency is present + uint32_t alpha_data_size; + WebPWorker alpha_worker; // quantization info (one set of DC/AC dequant factor per segment) - VP8SegmentInfo dqm_[NUM_MB_SEGMENTS]; - int base_quant_; // nominal quantizer value. Only used + VP8SegmentInfo dqm[NUM_MB_SEGMENTS]; + int base_quant; // nominal quantizer value. Only used // for relative coding of segments' quant. - int alpha_; // global susceptibility (<=> complexity) - int uv_alpha_; // U/V quantization susceptibility + int alpha; // global susceptibility (<=> complexity) + int uv_alpha; // U/V quantization susceptibility // global offset of quantizers, shared by all segments - int dq_y1_dc_; - int dq_y2_dc_, dq_y2_ac_; - int dq_uv_dc_, dq_uv_ac_; + int dq_y1_dc; + int dq_y2_dc, dq_y2_ac; + int dq_uv_dc, dq_uv_ac; // probabilities and statistics - VP8EncProba proba_; - uint64_t sse_[4]; // sum of Y/U/V/A squared errors for all macroblocks - uint64_t sse_count_; // pixel count for the sse_[] stats - int coded_size_; - int residual_bytes_[3][4]; - int block_count_[3]; + VP8EncProba proba; + uint64_t sse[4]; // sum of Y/U/V/A squared errors for all macroblocks + uint64_t sse_count; // pixel count for the sse[] stats + int coded_size; + int residual_bytes[3][4]; + int block_count[3]; // quality/speed settings - int method_; // 0=fastest, 6=best/slowest. - VP8RDLevel rd_opt_level_; // Deduced from method_. - int max_i4_header_bits_; // partition #0 safeness factor - int mb_header_limit_; // rough limit for header bits per MB - int thread_level_; // derived from config->thread_level - int do_search_; // derived from config->target_XXX - int use_tokens_; // if true, use token buffer + int method; // 0=fastest, 6=best/slowest. + VP8RDLevel rd_opt_level; // Deduced from method. + int max_i4_header_bits; // partition #0 safeness factor + int mb_header_limit; // rough limit for header bits per MB + int thread_level; // derived from config->thread_level + int do_search; // derived from config->target_XXX + int use_tokens; // if true, use token buffer // Memory - VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1) - uint8_t* preds_; // predictions modes: (4*mb_w+1) * (4*mb_h+1) - uint32_t* nz_; // non-zero bit context: mb_w+1 - uint8_t* y_top_; // top luma samples. - uint8_t* uv_top_; // top u/v samples. - // U and V are packed into 16 bytes (8 U + 8 V) - LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off) - DError* top_derr_; // diffusion error (NULL if disabled) + VP8MBInfo* mb_info; // contextual macroblock infos (mb_w + 1) + uint8_t* preds; // predictions modes: (4*mb_w+1) * (4*mb_h+1) + uint32_t* nz; // non-zero bit context: mb_w+1 + uint8_t* y_top; // top luma samples. + uint8_t* uv_top; // top u/v samples. + // U and V are packed into 16 bytes (8 U + 8 V) + LFStats* lf_stats; // autofilter stats (if NULL, autofilter is off) + DError* top_derr; // diffusion error (NULL if disabled) }; //------------------------------------------------------------------------------ // internal functions. Not public. @@ -440,13 +443,13 @@ extern const uint8_t VP8Cat3[]; extern const uint8_t VP8Cat4[]; extern const uint8_t VP8Cat5[]; extern const uint8_t VP8Cat6[]; -// Form all the four Intra16x16 predictions in the yuv_p_ cache +// Form all the four Intra16x16 predictions in the 'yuv_p' cache void VP8MakeLuma16Preds(const VP8EncIterator* const it); -// Form all the four Chroma8x8 predictions in the yuv_p_ cache +// Form all the four Chroma8x8 predictions in the 'yuv_p' cache void VP8MakeChroma8Preds(const VP8EncIterator* const it); // Rate calculation int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd); int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]); int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd); @@ -460,15 +463,15 @@ int WebPReportProgress(const WebPPicture* const pic, int percent, int* const percent_store); // in analysis.c // Main analysis loop. Decides the segmentations and complexity. -// Assigns a first guess for Intra16 and uvmode_ prediction modes. +// Assigns a first guess for Intra16 and 'uvmode' prediction modes. int VP8EncAnalyze(VP8Encoder* const enc); // in quant.c -// Sets up segment's quantization values, base_quant_ and filter strengths. +// Sets up segment's quantization values, 'base_quant' and filter strengths. void VP8SetSegmentParams(VP8Encoder* const enc, float quality); // Pick best modes and fills the levels. Returns true if skipped. int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it, VP8ModeScore* WEBP_RESTRICT const rd, VP8RDLevel rd_opt); diff --git a/media/libwebp/src/enc/vp8l_enc.c b/media/libwebp/src/enc/vp8l_enc.c --- a/media/libwebp/src/enc/vp8l_enc.c +++ b/media/libwebp/src/enc/vp8l_enc.c @@ -12,23 +12,26 @@ // Author: Vikas Arora (vikaas.arora@gmail.com) // #include #include +#include #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" #include "src/enc/backward_references_enc.h" #include "src/enc/histogram_enc.h" #include "src/enc/vp8i_enc.h" #include "src/enc/vp8li_enc.h" #include "src/utils/bit_writer_utils.h" #include "src/utils/huffman_encode_utils.h" #include "src/utils/palette.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" #include "src/webp/encode.h" #include "src/webp/format_constants.h" +#include "src/webp/types.h" // Maximum number of histogram images (sub-blocks). #define MAX_HUFF_IMAGE_SIZE 2600 #define MAX_HUFFMAN_BITS (MIN_HUFFMAN_BITS + (1 << NUM_HUFFMAN_BITS) - 1) // Empirical value for which it becomes too computationally expensive to @@ -64,27 +67,39 @@ kHistoBluePredSubGreen, kHistoPalette, kHistoTotal // Must be last. } HistoIx; + +#define NUM_BUCKETS 256 + +typedef uint32_t HistogramBuckets[NUM_BUCKETS]; + +// Keeping track of histograms, indexed by HistoIx. +// Ideally, this would just be a struct with meaningful fields, but the +// calculation of `entropy_comp` uses the index. One refactoring at a time :) +typedef struct { + HistogramBuckets category[kHistoTotal]; +} Histograms; + static void AddSingleSubGreen(uint32_t p, - uint32_t* const r, uint32_t* const b) { + HistogramBuckets r, HistogramBuckets b) { const int green = (int)p >> 8; // The upper bits are masked away later. ++r[(((int)p >> 16) - green) & 0xff]; ++b[(((int)p >> 0) - green) & 0xff]; } static void AddSingle(uint32_t p, - uint32_t* const a, uint32_t* const r, - uint32_t* const g, uint32_t* const b) { + HistogramBuckets a, HistogramBuckets r, + HistogramBuckets g, HistogramBuckets b) { ++a[(p >> 24) & 0xff]; ++r[(p >> 16) & 0xff]; ++g[(p >> 8) & 0xff]; ++b[(p >> 0) & 0xff]; } -static WEBP_INLINE uint32_t HashPix(uint32_t pix) { +static WEBP_INLINE uint8_t HashPix(uint32_t pix) { // Note that masking with 0xffffffffu is for preventing an // 'unsigned int overflow' warning. Doesn't impact the compiled code. return ((((uint64_t)pix + (pix >> 19)) * 0x39c5fba7ull) & 0xffffffffu) >> 24; } @@ -92,21 +107,21 @@ int width, int height, int argb_stride, int use_palette, int palette_size, int transform_bits, EntropyIx* const min_entropy_ix, int* const red_and_blue_always_zero) { - // Allocate histogram set with cache_bits = 0. - uint32_t* histo; + Histograms* histo; if (use_palette && palette_size <= 16) { // In the case of small palettes, we pack 2, 4 or 8 pixels together. In // practice, small palettes are better than any other transform. *min_entropy_ix = kPalette; *red_and_blue_always_zero = 1; return 1; } - histo = (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256); + + histo = (Histograms*)WebPSafeCalloc(1, sizeof(*histo)); if (histo != NULL) { int i, x, y; const uint32_t* prev_row = NULL; const uint32_t* curr_row = argb; uint32_t pix_prev = argb[0]; // Skip the first pixel. @@ -117,29 +132,29 @@ pix_prev = pix; if ((pix_diff == 0) || (prev_row != NULL && pix == prev_row[x])) { continue; } AddSingle(pix, - &histo[kHistoAlpha * 256], - &histo[kHistoRed * 256], - &histo[kHistoGreen * 256], - &histo[kHistoBlue * 256]); + histo->category[kHistoAlpha], + histo->category[kHistoRed], + histo->category[kHistoGreen], + histo->category[kHistoBlue]); AddSingle(pix_diff, - &histo[kHistoAlphaPred * 256], - &histo[kHistoRedPred * 256], - &histo[kHistoGreenPred * 256], - &histo[kHistoBluePred * 256]); + histo->category[kHistoAlphaPred], + histo->category[kHistoRedPred], + histo->category[kHistoGreenPred], + histo->category[kHistoBluePred]); AddSingleSubGreen(pix, - &histo[kHistoRedSubGreen * 256], - &histo[kHistoBlueSubGreen * 256]); + histo->category[kHistoRedSubGreen], + histo->category[kHistoBlueSubGreen]); AddSingleSubGreen(pix_diff, - &histo[kHistoRedPredSubGreen * 256], - &histo[kHistoBluePredSubGreen * 256]); + histo->category[kHistoRedPredSubGreen], + histo->category[kHistoBluePredSubGreen]); { // Approximate the palette by the entropy of the multiplicative hash. - const uint32_t hash = HashPix(pix); - ++histo[kHistoPalette * 256 + hash]; + const uint8_t hash = HashPix(pix); + ++histo->category[kHistoPalette][hash]; } } prev_row = curr_row; curr_row += argb_stride; } @@ -150,19 +165,19 @@ int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen; int j; // Let's add one zero to the predicted histograms. The zeros are removed // too efficiently by the pix_diff == 0 comparison, at least one of the // zeros is likely to exist. - ++histo[kHistoRedPredSubGreen * 256]; - ++histo[kHistoBluePredSubGreen * 256]; - ++histo[kHistoRedPred * 256]; - ++histo[kHistoGreenPred * 256]; - ++histo[kHistoBluePred * 256]; - ++histo[kHistoAlphaPred * 256]; + ++histo->category[kHistoRedPredSubGreen][0]; + ++histo->category[kHistoBluePredSubGreen][0]; + ++histo->category[kHistoRedPred][0]; + ++histo->category[kHistoGreenPred][0]; + ++histo->category[kHistoBluePred][0]; + ++histo->category[kHistoAlphaPred][0]; for (j = 0; j < kHistoTotal; ++j) { - entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256); + entropy_comp[j] = VP8LBitsEntropy(histo->category[j], NUM_BUCKETS); } entropy[kDirect] = entropy_comp[kHistoAlpha] + entropy_comp[kHistoRed] + entropy_comp[kHistoGreen] + entropy_comp[kHistoBlue]; @@ -214,16 +229,16 @@ { kHistoRedPred, kHistoBluePred }, { kHistoRedSubGreen, kHistoBlueSubGreen }, { kHistoRedPredSubGreen, kHistoBluePredSubGreen }, { kHistoRed, kHistoBlue } }; - const uint32_t* const red_histo = - &histo[256 * kHistoPairs[*min_entropy_ix][0]]; - const uint32_t* const blue_histo = - &histo[256 * kHistoPairs[*min_entropy_ix][1]]; - for (i = 1; i < 256; ++i) { - if ((red_histo[i] | blue_histo[i]) != 0) { + const HistogramBuckets* const red_histo = + &histo->category[kHistoPairs[*min_entropy_ix][0]]; + const HistogramBuckets* const blue_histo = + &histo->category[kHistoPairs[*min_entropy_ix][1]]; + for (i = 1; i < NUM_BUCKETS; ++i) { + if (((*red_histo)[i] | (*blue_histo)[i]) != 0) { *red_and_blue_always_zero = 0; break; } } } @@ -273,32 +288,32 @@ } // Set of parameters to be used in each iteration of the cruncher. #define CRUNCH_SUBCONFIGS_MAX 2 typedef struct { - int lz77_; - int do_no_cache_; + int lz77; + int do_no_cache; } CrunchSubConfig; typedef struct { - int entropy_idx_; - PaletteSorting palette_sorting_type_; - CrunchSubConfig sub_configs_[CRUNCH_SUBCONFIGS_MAX]; - int sub_configs_size_; + int entropy_idx; + PaletteSorting palette_sorting_type; + CrunchSubConfig sub_configs[CRUNCH_SUBCONFIGS_MAX]; + int sub_configs_size; } CrunchConfig; // +2 because we add a palette sorting configuration for kPalette and // kPaletteAndSpatial. #define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2 * kPaletteSortingNum) static int EncoderAnalyze(VP8LEncoder* const enc, CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX], int* const crunch_configs_size, int* const red_and_blue_always_zero) { - const WebPPicture* const pic = enc->pic_; + const WebPPicture* const pic = enc->pic; const int width = pic->width; const int height = pic->height; - const WebPConfig* const config = enc->config_; + const WebPConfig* const config = enc->config; const int method = config->method; const int low_effort = (config->method == 0); int i; int use_palette, transform_bits; int n_lz77s; @@ -306,36 +321,36 @@ // analyze with no-cache. int do_no_cache = 0; assert(pic != NULL && pic->argb != NULL); // Check whether a palette is possible. - enc->palette_size_ = GetColorPalette(pic, enc->palette_sorted_); - use_palette = (enc->palette_size_ <= MAX_PALETTE_SIZE); + enc->palette_size = GetColorPalette(pic, enc->palette_sorted); + use_palette = (enc->palette_size <= MAX_PALETTE_SIZE); if (!use_palette) { - enc->palette_size_ = 0; + enc->palette_size = 0; } // Empirical bit sizes. - enc->histo_bits_ = GetHistoBits(method, use_palette, - pic->width, pic->height); - transform_bits = GetTransformBits(method, enc->histo_bits_); - enc->predictor_transform_bits_ = transform_bits; - enc->cross_color_transform_bits_ = transform_bits; + enc->histo_bits = GetHistoBits(method, use_palette, + pic->width, pic->height); + transform_bits = GetTransformBits(method, enc->histo_bits); + enc->predictor_transform_bits = transform_bits; + enc->cross_color_transform_bits = transform_bits; if (low_effort) { // AnalyzeEntropy is somewhat slow. - crunch_configs[0].entropy_idx_ = use_palette ? kPalette : kSpatialSubGreen; - crunch_configs[0].palette_sorting_type_ = + crunch_configs[0].entropy_idx = use_palette ? kPalette : kSpatialSubGreen; + crunch_configs[0].palette_sorting_type = use_palette ? kSortedDefault : kUnusedPalette; n_lz77s = 1; *crunch_configs_size = 1; } else { EntropyIx min_entropy_ix; // Try out multiple LZ77 on images with few colors. - n_lz77s = (enc->palette_size_ > 0 && enc->palette_size_ <= 16) ? 2 : 1; + n_lz77s = (enc->palette_size > 0 && enc->palette_size <= 16) ? 2 : 1; if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, use_palette, - enc->palette_size_, transform_bits, &min_entropy_ix, + enc->palette_size, transform_bits, &min_entropy_ix, red_and_blue_always_zero)) { return 0; } if (method == 6 && config->quality == 100) { do_no_cache = 1; @@ -356,68 +371,68 @@ // for now for backward compatibility. if (typed_sorting_method == kUnusedPalette || typed_sorting_method == kSortedDefault) { continue; } - crunch_configs[(*crunch_configs_size)].entropy_idx_ = i; - crunch_configs[(*crunch_configs_size)].palette_sorting_type_ = + crunch_configs[(*crunch_configs_size)].entropy_idx = i; + crunch_configs[(*crunch_configs_size)].palette_sorting_type = typed_sorting_method; ++*crunch_configs_size; } } else { - crunch_configs[(*crunch_configs_size)].entropy_idx_ = i; - crunch_configs[(*crunch_configs_size)].palette_sorting_type_ = + crunch_configs[(*crunch_configs_size)].entropy_idx = i; + crunch_configs[(*crunch_configs_size)].palette_sorting_type = kUnusedPalette; ++*crunch_configs_size; } } } } else { // Only choose the guessed best transform. *crunch_configs_size = 1; - crunch_configs[0].entropy_idx_ = min_entropy_ix; - crunch_configs[0].palette_sorting_type_ = + crunch_configs[0].entropy_idx = min_entropy_ix; + crunch_configs[0].palette_sorting_type = use_palette ? kMinimizeDelta : kUnusedPalette; if (config->quality >= 75 && method == 5) { // Test with and without color cache. do_no_cache = 1; // If we have a palette, also check in combination with spatial. if (min_entropy_ix == kPalette) { *crunch_configs_size = 2; - crunch_configs[1].entropy_idx_ = kPaletteAndSpatial; - crunch_configs[1].palette_sorting_type_ = kMinimizeDelta; + crunch_configs[1].entropy_idx = kPaletteAndSpatial; + crunch_configs[1].palette_sorting_type = kMinimizeDelta; } } } } // Fill in the different LZ77s. assert(n_lz77s <= CRUNCH_SUBCONFIGS_MAX); for (i = 0; i < *crunch_configs_size; ++i) { int j; for (j = 0; j < n_lz77s; ++j) { assert(j < CRUNCH_SUBCONFIGS_MAX); - crunch_configs[i].sub_configs_[j].lz77_ = + crunch_configs[i].sub_configs[j].lz77 = (j == 0) ? kLZ77Standard | kLZ77RLE : kLZ77Box; - crunch_configs[i].sub_configs_[j].do_no_cache_ = do_no_cache; + crunch_configs[i].sub_configs[j].do_no_cache = do_no_cache; } - crunch_configs[i].sub_configs_size_ = n_lz77s; + crunch_configs[i].sub_configs_size = n_lz77s; } return 1; } static int EncoderInit(VP8LEncoder* const enc) { - const WebPPicture* const pic = enc->pic_; + const WebPPicture* const pic = enc->pic; const int width = pic->width; const int height = pic->height; const int pix_cnt = width * height; // we round the block size up, so we're guaranteed to have // at most MAX_REFS_BLOCK_PER_IMAGE blocks used: const int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1; int i; - if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0; + if (!VP8LHashChainInit(&enc->hash_chain, pix_cnt)) return 0; - for (i = 0; i < 4; ++i) VP8LBackwardRefsInit(&enc->refs_[i], refs_block_size); + for (i = 0; i < 4; ++i) VP8LBackwardRefsInit(&enc->refs[i], refs_block_size); return 1; } // Returns false in case of memory error. @@ -438,11 +453,11 @@ const VP8LHistogram* const histo = histogram_image->histograms[i]; HuffmanTreeCode* const codes = &huffman_codes[5 * i]; assert(histo != NULL); for (k = 0; k < 5; ++k) { const int num_symbols = - (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) : + (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits) : (k == 4) ? NUM_DISTANCE_CODES : 256; codes[k].num_symbols = num_symbols; total_length_size += num_symbols; } } @@ -476,15 +491,15 @@ // Create Huffman trees. for (i = 0; i < histogram_image_size; ++i) { HuffmanTreeCode* const codes = &huffman_codes[5 * i]; VP8LHistogram* const histo = histogram_image->histograms[i]; - VP8LCreateHuffmanTree(histo->literal_, 15, buf_rle, huff_tree, codes + 0); - VP8LCreateHuffmanTree(histo->red_, 15, buf_rle, huff_tree, codes + 1); - VP8LCreateHuffmanTree(histo->blue_, 15, buf_rle, huff_tree, codes + 2); - VP8LCreateHuffmanTree(histo->alpha_, 15, buf_rle, huff_tree, codes + 3); - VP8LCreateHuffmanTree(histo->distance_, 15, buf_rle, huff_tree, codes + 4); + VP8LCreateHuffmanTree(histo->literal, 15, buf_rle, huff_tree, codes + 0); + VP8LCreateHuffmanTree(histo->red, 15, buf_rle, huff_tree, codes + 1); + VP8LCreateHuffmanTree(histo->blue, 15, buf_rle, huff_tree, codes + 2); + VP8LCreateHuffmanTree(histo->alpha, 15, buf_rle, huff_tree, codes + 3); + VP8LCreateHuffmanTree(histo->distance, 15, buf_rle, huff_tree, codes + 4); } ok = 1; End: WebPSafeFree(huff_tree); WebPSafeFree(buf_rle); @@ -741,11 +756,11 @@ x -= width; ++y; } VP8LRefsCursorNext(&c); } - if (bw->error_) { + if (bw->error) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); } return 1; } @@ -792,11 +807,13 @@ goto Error; } VP8LHistogramSetClear(histogram_image); // Build histogram image and symbols from backward references. - VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]); + VP8LHistogramStoreRefs(refs, /*distance_modifier=*/NULL, + /*distance_modifier_arg0=*/0, + histogram_image->histograms[0]); // Create Huffman bit lengths and codes for each histogram image. assert(histogram_image->size == 1); if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); @@ -898,33 +915,33 @@ // If the value is different from zero, it has been set during the palette // analysis. cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits; // 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)) { WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } - for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size_; + for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size; ++sub_configs_idx) { const CrunchSubConfig* const sub_config = - &config->sub_configs_[sub_configs_idx]; + &config->sub_configs[sub_configs_idx]; int cache_bits_best, i_cache; - int i_remaining_percent = remaining_percent / config->sub_configs_size_; + int i_remaining_percent = remaining_percent / config->sub_configs_size; int i_percent_range = i_remaining_percent / 4; i_remaining_percent -= i_percent_range; if (!VP8LGetBackwardReferences( - width, height, argb, quality, low_effort, sub_config->lz77_, - cache_bits_init, sub_config->do_no_cache_, hash_chain, + width, height, argb, quality, low_effort, sub_config->lz77, + cache_bits_init, sub_config->do_no_cache, hash_chain, &refs_array[0], &cache_bits_best, pic, i_percent_range, percent)) { goto Error; } - for (i_cache = 0; i_cache < (sub_config->do_no_cache_ ? 2 : 1); ++i_cache) { + for (i_cache = 0; i_cache < (sub_config->do_no_cache ? 2 : 1); ++i_cache) { const int cache_bits_tmp = (i_cache == 0) ? cache_bits_best : 0; int histogram_bits = histogram_bits_in; // Speed-up: no need to study the no-cache case if it was already studied // in i_cache == 0. if (i_cache == 1 && cache_bits_best == 0) break; @@ -1075,69 +1092,66 @@ static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height, VP8LBitWriter* const bw) { VP8LPutBits(bw, TRANSFORM_PRESENT, 1); VP8LPutBits(bw, SUBTRACT_GREEN_TRANSFORM, 2); - VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height); + VP8LSubtractGreenFromBlueAndRed(enc->argb, width * height); } static int ApplyPredictFilter(VP8LEncoder* const enc, int width, int height, int quality, int low_effort, int used_subtract_green, VP8LBitWriter* const bw, - int percent_range, int* const percent) { - int best_bits; + int percent_range, int* const percent, + int* const best_bits) { const int near_lossless_strength = - enc->use_palette_ ? 100 : enc->config_->near_lossless; - const int max_bits = ClampBits(width, height, enc->predictor_transform_bits_, + enc->use_palette ? 100 : enc->config->near_lossless; + const int max_bits = ClampBits(width, height, enc->predictor_transform_bits, MIN_TRANSFORM_BITS, MAX_TRANSFORM_BITS, MAX_PREDICTOR_IMAGE_SIZE); const int min_bits = ClampBits( width, height, - max_bits - 2 * (enc->config_->method > 4 ? enc->config_->method - 4 : 0), + max_bits - 2 * (enc->config->method > 4 ? enc->config->method - 4 : 0), MIN_TRANSFORM_BITS, MAX_TRANSFORM_BITS, MAX_PREDICTOR_IMAGE_SIZE); if (!VP8LResidualImage(width, height, min_bits, max_bits, low_effort, - enc->argb_, enc->argb_scratch_, enc->transform_data_, - near_lossless_strength, enc->config_->exact, - used_subtract_green, enc->pic_, percent_range / 2, - percent, &best_bits)) { + enc->argb, enc->argb_scratch, enc->transform_data, + near_lossless_strength, enc->config->exact, + used_subtract_green, enc->pic, percent_range / 2, + percent, best_bits)) { return 0; } VP8LPutBits(bw, TRANSFORM_PRESENT, 1); VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); - assert(best_bits >= MIN_TRANSFORM_BITS && best_bits <= MAX_TRANSFORM_BITS); - VP8LPutBits(bw, best_bits - MIN_TRANSFORM_BITS, NUM_TRANSFORM_BITS); - enc->predictor_transform_bits_ = best_bits; + assert(*best_bits >= MIN_TRANSFORM_BITS && *best_bits <= MAX_TRANSFORM_BITS); + VP8LPutBits(bw, *best_bits - MIN_TRANSFORM_BITS, NUM_TRANSFORM_BITS); return EncodeImageNoHuffman( - bw, enc->transform_data_, &enc->hash_chain_, &enc->refs_[0], - VP8LSubSampleSize(width, best_bits), VP8LSubSampleSize(height, best_bits), - quality, low_effort, enc->pic_, percent_range - percent_range / 2, - percent); + bw, enc->transform_data, &enc->hash_chain, &enc->refs[0], + VP8LSubSampleSize(width, *best_bits), + VP8LSubSampleSize(height, *best_bits), quality, low_effort, enc->pic, + percent_range - percent_range / 2, percent); } static int ApplyCrossColorFilter(VP8LEncoder* const enc, int width, int height, int quality, int low_effort, VP8LBitWriter* const bw, int percent_range, - int* const percent) { - const int min_bits = enc->cross_color_transform_bits_; - int best_bits; + int* const percent, int* const best_bits) { + const int min_bits = enc->cross_color_transform_bits; - if (!VP8LColorSpaceTransform(width, height, min_bits, quality, enc->argb_, - enc->transform_data_, enc->pic_, - percent_range / 2, percent, &best_bits)) { + if (!VP8LColorSpaceTransform(width, height, min_bits, quality, enc->argb, + enc->transform_data, enc->pic, percent_range / 2, + percent, best_bits)) { return 0; } VP8LPutBits(bw, TRANSFORM_PRESENT, 1); VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2); - assert(best_bits >= MIN_TRANSFORM_BITS && best_bits <= MAX_TRANSFORM_BITS); - VP8LPutBits(bw, best_bits - MIN_TRANSFORM_BITS, NUM_TRANSFORM_BITS); - enc->cross_color_transform_bits_ = best_bits; + assert(*best_bits >= MIN_TRANSFORM_BITS && *best_bits <= MAX_TRANSFORM_BITS); + VP8LPutBits(bw, *best_bits - MIN_TRANSFORM_BITS, NUM_TRANSFORM_BITS); return EncodeImageNoHuffman( - bw, enc->transform_data_, &enc->hash_chain_, &enc->refs_[0], - VP8LSubSampleSize(width, best_bits), VP8LSubSampleSize(height, best_bits), - quality, low_effort, enc->pic_, percent_range - percent_range / 2, - percent); + bw, enc->transform_data, &enc->hash_chain, &enc->refs[0], + VP8LSubSampleSize(width, *best_bits), + VP8LSubSampleSize(height, *best_bits), quality, low_effort, enc->pic, + percent_range - percent_range / 2, percent); } // ----------------------------------------------------------------------------- static int WriteRiffHeader(const WebPPicture* const pic, size_t riff_size, @@ -1157,17 +1171,17 @@ const int height = pic->height - 1; assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION); VP8LPutBits(bw, width, VP8L_IMAGE_SIZE_BITS); VP8LPutBits(bw, height, VP8L_IMAGE_SIZE_BITS); - return !bw->error_; + return !bw->error; } static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) { VP8LPutBits(bw, has_alpha, 1); VP8LPutBits(bw, VP8L_VERSION, VP8L_VERSION_BITS); - return !bw->error_; + return !bw->error; } static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw, size_t* const coded_size) { const uint8_t* const webpll_data = VP8LBitWriterFinish(bw); @@ -1175,11 +1189,11 @@ const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size; const size_t pad = vp8l_size & 1; const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad; *coded_size = 0; - if (bw->error_) { + if (bw->error) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); } if (!WriteRiffHeader(pic, riff_size, vp8l_size) || !pic->writer(webpll_data, webpll_size, pic)) { @@ -1197,81 +1211,81 @@ } // ----------------------------------------------------------------------------- static void ClearTransformBuffer(VP8LEncoder* const enc) { - WebPSafeFree(enc->transform_mem_); - enc->transform_mem_ = NULL; - enc->transform_mem_size_ = 0; + WebPSafeFree(enc->transform_mem); + enc->transform_mem = NULL; + enc->transform_mem_size = 0; } // Allocates the memory for argb (W x H) buffer, 2 rows of context for // prediction and transform data. // Flags influencing the memory allocated: -// enc->transform_bits_ -// enc->use_predict_, enc->use_cross_color_ +// enc->transform_bits +// enc->use_predict, enc->use_cross_color static int AllocateTransformBuffer(VP8LEncoder* const enc, int width, int height) { const uint64_t image_size = (uint64_t)width * height; // VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra // pixel in each, plus 2 regular scanlines of bytes. // TODO(skal): Clean up by using arithmetic in bytes instead of words. const uint64_t argb_scratch_size = - enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) / - sizeof(uint32_t) + enc->use_predict ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) / + sizeof(uint32_t) : 0; const uint64_t transform_data_size = - (enc->use_predict_ || enc->use_cross_color_) + (enc->use_predict || enc->use_cross_color) ? (uint64_t)VP8LSubSampleSize(width, MIN_TRANSFORM_BITS) * VP8LSubSampleSize(height, MIN_TRANSFORM_BITS) : 0; const uint64_t max_alignment_in_words = (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t); const uint64_t mem_size = image_size + max_alignment_in_words + argb_scratch_size + max_alignment_in_words + transform_data_size; - uint32_t* mem = enc->transform_mem_; - if (mem == NULL || mem_size > enc->transform_mem_size_) { + uint32_t* mem = enc->transform_mem; + if (mem == NULL || mem_size > enc->transform_mem_size) { ClearTransformBuffer(enc); mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem)); if (mem == NULL) { - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); } - enc->transform_mem_ = mem; - enc->transform_mem_size_ = (size_t)mem_size; - enc->argb_content_ = kEncoderNone; + enc->transform_mem = mem; + enc->transform_mem_size = (size_t)mem_size; + enc->argb_content = kEncoderNone; } - enc->argb_ = mem; + enc->argb = mem; mem = (uint32_t*)WEBP_ALIGN(mem + image_size); - enc->argb_scratch_ = mem; + enc->argb_scratch = mem; mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size); - enc->transform_data_ = mem; + enc->transform_data = mem; - enc->current_width_ = width; + enc->current_width = width; return 1; } static int MakeInputImageCopy(VP8LEncoder* const enc) { - const WebPPicture* const picture = enc->pic_; + const WebPPicture* const picture = enc->pic; const int width = picture->width; const int height = picture->height; if (!AllocateTransformBuffer(enc, width, height)) return 0; - if (enc->argb_content_ == kEncoderARGB) return 1; + if (enc->argb_content == kEncoderARGB) return 1; { - uint32_t* dst = enc->argb_; + uint32_t* dst = enc->argb; const uint32_t* src = picture->argb; int y; for (y = 0; y < height; ++y) { memcpy(dst, src, width * sizeof(*dst)); dst += width; src += picture->argb_stride; } } - enc->argb_content_ = kEncoderARGB; - assert(enc->current_width_ == width); + enc->argb_content = kEncoderARGB; + assert(enc->current_width == width); return 1; } // ----------------------------------------------------------------------------- @@ -1393,17 +1407,17 @@ #undef APPLY_PALETTE_FOR #undef PALETTE_INV_SIZE_BITS #undef PALETTE_INV_SIZE #undef APPLY_PALETTE_GREEDY_MAX -// Note: Expects "enc->palette_" to be set properly. +// Note: Expects "enc->palette" to be set properly. static int MapImageFromPalette(VP8LEncoder* const enc) { - const WebPPicture* const pic = enc->pic_; + const WebPPicture* const pic = enc->pic; const int width = pic->width; const int height = pic->height; - const uint32_t* const palette = enc->palette_; - const int palette_size = enc->palette_size_; + const uint32_t* const palette = enc->palette; + const int palette_size = enc->palette_size; int xbits; // Replace each input pixel by corresponding palette index. // This is done line by line. if (palette_size <= 4) { @@ -1413,32 +1427,32 @@ } if (!AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height)) { return 0; } - if (!ApplyPalette(pic->argb, pic->argb_stride, enc->argb_, - enc->current_width_, palette, palette_size, width, height, + if (!ApplyPalette(pic->argb, pic->argb_stride, enc->argb, + enc->current_width, palette, palette_size, width, height, xbits, pic)) { return 0; } - enc->argb_content_ = kEncoderPalette; + enc->argb_content = kEncoderPalette; return 1; } -// Save palette_[] to bitstream. +// Save palette[] to bitstream. static int EncodePalette(VP8LBitWriter* const bw, int low_effort, VP8LEncoder* const enc, int percent_range, int* const percent) { int i; uint32_t tmp_palette[MAX_PALETTE_SIZE]; - const int palette_size = enc->palette_size_; - const uint32_t* const palette = enc->palette_; + const int palette_size = enc->palette_size; + const uint32_t* const palette = enc->palette; // If the last element is 0, do not store it and count on automatic palette // 0-filling. This can only happen if there is no pixel packing, hence if // there are strictly more than 16 colors (after 0 is removed). const uint32_t encoded_palette_size = - (enc->palette_[palette_size - 1] == 0 && palette_size > 17) + (enc->palette[palette_size - 1] == 0 && palette_size > 17) ? palette_size - 1 : palette_size; VP8LPutBits(bw, TRANSFORM_PRESENT, 1); VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2); assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE); @@ -1446,12 +1460,12 @@ for (i = encoded_palette_size - 1; i >= 1; --i) { tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]); } tmp_palette[0] = palette[0]; return EncodeImageNoHuffman( - bw, tmp_palette, &enc->hash_chain_, &enc->refs_[0], encoded_palette_size, - 1, /*quality=*/20, low_effort, enc->pic_, percent_range, percent); + bw, tmp_palette, &enc->hash_chain, &enc->refs[0], encoded_palette_size, + 1, /*quality=*/20, low_effort, enc->pic, percent_range, percent); } // ----------------------------------------------------------------------------- // VP8LEncoder @@ -1460,54 +1474,54 @@ VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc)); if (enc == NULL) { WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); return NULL; } - enc->config_ = config; - enc->pic_ = picture; - enc->argb_content_ = kEncoderNone; + enc->config = config; + enc->pic = picture; + enc->argb_content = kEncoderNone; VP8LEncDspInit(); return enc; } static void VP8LEncoderDelete(VP8LEncoder* enc) { if (enc != NULL) { int i; - VP8LHashChainClear(&enc->hash_chain_); - for (i = 0; i < 4; ++i) VP8LBackwardRefsClear(&enc->refs_[i]); + VP8LHashChainClear(&enc->hash_chain); + for (i = 0; i < 4; ++i) VP8LBackwardRefsClear(&enc->refs[i]); ClearTransformBuffer(enc); WebPSafeFree(enc); } } // ----------------------------------------------------------------------------- // Main call typedef struct { - const WebPConfig* config_; - const WebPPicture* picture_; - VP8LBitWriter* bw_; - VP8LEncoder* enc_; - CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX]; - int num_crunch_configs_; - int red_and_blue_always_zero_; - WebPAuxStats* stats_; + const WebPConfig* config; + const WebPPicture* picture; + VP8LBitWriter* bw; + VP8LEncoder* enc; + CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX]; + int num_crunch_configs; + int red_and_blue_always_zero; + WebPAuxStats* stats; } StreamEncodeContext; static int EncodeStreamHook(void* input, void* data2) { StreamEncodeContext* const params = (StreamEncodeContext*)input; - const WebPConfig* const config = params->config_; - const WebPPicture* const picture = params->picture_; - VP8LBitWriter* const bw = params->bw_; - VP8LEncoder* const enc = params->enc_; - const CrunchConfig* const crunch_configs = params->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 WebPConfig* const config = params->config; + const WebPPicture* const picture = params->picture; + VP8LBitWriter* const bw = params->bw; + VP8LEncoder* const enc = params->enc; + const CrunchConfig* const crunch_configs = params->crunch_configs; + const int num_crunch_configs = params->num_crunch_configs; + const int red_and_blue_always_zero = params->red_and_blue_always_zero; #if !defined(WEBP_DISABLE_STATS) - WebPAuxStats* const stats = params->stats_; + WebPAuxStats* const stats = params->stats; #endif const int quality = (int)config->quality; const int low_effort = (config->method == 0); #if (WEBP_NEAR_LOSSLESS == 1) const int width = picture->width; @@ -1530,109 +1544,112 @@ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } for (idx = 0; idx < num_crunch_configs; ++idx) { - const int entropy_idx = crunch_configs[idx].entropy_idx_; + const int entropy_idx = crunch_configs[idx].entropy_idx; int remaining_percent = 97 / num_crunch_configs, percent_range; - enc->use_palette_ = + int predictor_transform_bits = 0, cross_color_transform_bits = 0; + enc->use_palette = (entropy_idx == kPalette) || (entropy_idx == kPaletteAndSpatial); - enc->use_subtract_green_ = + enc->use_subtract_green = (entropy_idx == kSubGreen) || (entropy_idx == kSpatialSubGreen); - enc->use_predict_ = (entropy_idx == kSpatial) || - (entropy_idx == kSpatialSubGreen) || - (entropy_idx == kPaletteAndSpatial); + enc->use_predict = (entropy_idx == kSpatial) || + (entropy_idx == kSpatialSubGreen) || + (entropy_idx == kPaletteAndSpatial); // When using a palette, R/B==0, hence no need to test for cross-color. - if (low_effort || enc->use_palette_) { - enc->use_cross_color_ = 0; + if (low_effort || enc->use_palette) { + enc->use_cross_color = 0; } else { - enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_; + enc->use_cross_color = red_and_blue_always_zero ? 0 : enc->use_predict; } // Reset any parameter in the encoder that is set in the previous iteration. - enc->cache_bits_ = 0; - VP8LBackwardRefsClear(&enc->refs_[0]); - VP8LBackwardRefsClear(&enc->refs_[1]); + enc->cache_bits = 0; + VP8LBackwardRefsClear(&enc->refs[0]); + VP8LBackwardRefsClear(&enc->refs[1]); #if (WEBP_NEAR_LOSSLESS == 1) // Apply near-lossless preprocessing. - use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ && - !enc->use_predict_; + use_near_lossless = (config->near_lossless < 100) && !enc->use_palette && + !enc->use_predict; if (use_near_lossless) { if (!AllocateTransformBuffer(enc, width, height)) goto Error; - if ((enc->argb_content_ != kEncoderNearLossless) && - !VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) { + if ((enc->argb_content != kEncoderNearLossless) && + !VP8ApplyNearLossless(picture, config->near_lossless, enc->argb)) { WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } - enc->argb_content_ = kEncoderNearLossless; + enc->argb_content = kEncoderNearLossless; } else { - enc->argb_content_ = kEncoderNone; + enc->argb_content = kEncoderNone; } #else - enc->argb_content_ = kEncoderNone; + enc->argb_content = kEncoderNone; #endif // Encode palette - if (enc->use_palette_) { - if (!PaletteSort(crunch_configs[idx].palette_sorting_type_, enc->pic_, - enc->palette_sorted_, enc->palette_size_, - enc->palette_)) { - WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + if (enc->use_palette) { + if (!PaletteSort(crunch_configs[idx].palette_sorting_type, enc->pic, + enc->palette_sorted, enc->palette_size, + enc->palette)) { + WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } percent_range = remaining_percent / 4; if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) { goto Error; } remaining_percent -= percent_range; if (!MapImageFromPalette(enc)) goto Error; // If using a color cache, do not have it bigger than the number of // colors. - if (enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { - enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1; + if (enc->palette_size < (1 << MAX_COLOR_CACHE_BITS)) { + enc->cache_bits = BitsLog2Floor(enc->palette_size) + 1; } } // In case image is not packed. - if (enc->argb_content_ != kEncoderNearLossless && - enc->argb_content_ != kEncoderPalette) { + if (enc->argb_content != kEncoderNearLossless && + enc->argb_content != kEncoderPalette) { if (!MakeInputImageCopy(enc)) goto Error; } // ------------------------------------------------------------------------- // Apply transforms and write transform data. - if (enc->use_subtract_green_) { - ApplySubtractGreen(enc, enc->current_width_, height, bw); + if (enc->use_subtract_green) { + ApplySubtractGreen(enc, enc->current_width, height, bw); } - if (enc->use_predict_) { + if (enc->use_predict) { percent_range = remaining_percent / 3; - if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, - low_effort, enc->use_subtract_green_, bw, - percent_range, &percent)) { + if (!ApplyPredictFilter(enc, enc->current_width, height, quality, + low_effort, enc->use_subtract_green, bw, + percent_range, &percent, + &predictor_transform_bits)) { goto Error; } remaining_percent -= percent_range; } - if (enc->use_cross_color_) { + if (enc->use_cross_color) { percent_range = remaining_percent / 2; - if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, - low_effort, bw, percent_range, &percent)) { + if (!ApplyCrossColorFilter(enc, enc->current_width, height, quality, + low_effort, bw, percent_range, &percent, + &cross_color_transform_bits)) { goto Error; } remaining_percent -= percent_range; } VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms. // ------------------------------------------------------------------------- // Encode and write the transformed image. 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, &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)) { goto Error; } // If we are better than what we already have. @@ -1642,19 +1659,19 @@ VP8LBitWriterSwap(bw, &bw_best); #if !defined(WEBP_DISABLE_STATS) // Update the stats. if (stats != NULL) { stats->lossless_features = 0; - if (enc->use_predict_) stats->lossless_features |= 1; - if (enc->use_cross_color_) stats->lossless_features |= 2; - if (enc->use_subtract_green_) stats->lossless_features |= 4; - if (enc->use_palette_) stats->lossless_features |= 8; - stats->histogram_bits = enc->histo_bits_; - stats->transform_bits = enc->predictor_transform_bits_; - stats->cross_color_transform_bits = enc->cross_color_transform_bits_; - stats->cache_bits = enc->cache_bits_; - stats->palette_size = enc->palette_size_; + if (enc->use_predict) stats->lossless_features |= 1; + if (enc->use_cross_color) stats->lossless_features |= 2; + if (enc->use_subtract_green) stats->lossless_features |= 4; + if (enc->use_palette) stats->lossless_features |= 8; + stats->histogram_bits = enc->histo_bits; + stats->transform_bits = predictor_transform_bits; + stats->cross_color_transform_bits = cross_color_transform_bits; + stats->cache_bits = enc->cache_bits; + stats->palette_size = enc->palette_size; stats->lossless_size = (int)(best_size - byte_position); stats->lossless_hdr_size = hdr_size; stats->lossless_data_size = data_size; } #endif @@ -1665,11 +1682,11 @@ VP8LBitWriterSwap(&bw_best, bw); Error: VP8LBitWriterWipeOut(&bw_best); // The hook should return false in case of error. - return (params->picture_->error_code == VP8_ENC_OK); + return (params->picture->error_code == VP8_ENC_OK); } int VP8LEncodeStream(const WebPConfig* const config, const WebPPicture* const picture, VP8LBitWriter* const bw_main) { @@ -1708,70 +1725,70 @@ // Split the configs between the main and side threads (if any). if (config->thread_level > 0) { num_crunch_configs_side = num_crunch_configs_main / 2; for (idx = 0; idx < num_crunch_configs_side; ++idx) { - params_side.crunch_configs_[idx] = + params_side.crunch_configs[idx] = crunch_configs[num_crunch_configs_main - num_crunch_configs_side + idx]; } - params_side.num_crunch_configs_ = num_crunch_configs_side; + params_side.num_crunch_configs = num_crunch_configs_side; } num_crunch_configs_main -= num_crunch_configs_side; for (idx = 0; idx < num_crunch_configs_main; ++idx) { - params_main.crunch_configs_[idx] = crunch_configs[idx]; + params_main.crunch_configs[idx] = crunch_configs[idx]; } - params_main.num_crunch_configs_ = num_crunch_configs_main; + params_main.num_crunch_configs = num_crunch_configs_main; // Fill in the parameters for the thread workers. { const int params_size = (num_crunch_configs_side > 0) ? 2 : 1; for (idx = 0; idx < params_size; ++idx) { // Create the parameters for each worker. WebPWorker* const worker = (idx == 0) ? &worker_main : &worker_side; StreamEncodeContext* const param = (idx == 0) ? ¶ms_main : ¶ms_side; - param->config_ = config; - param->red_and_blue_always_zero_ = red_and_blue_always_zero; + param->config = config; + param->red_and_blue_always_zero = red_and_blue_always_zero; if (idx == 0) { - param->picture_ = picture; - param->stats_ = picture->stats; - param->bw_ = bw_main; - param->enc_ = enc_main; + param->picture = picture; + param->stats = picture->stats; + param->bw = bw_main; + param->enc = enc_main; } else { // Create a side picture (error_code is not thread-safe). if (!WebPPictureView(picture, /*left=*/0, /*top=*/0, picture->width, picture->height, &picture_side)) { assert(0); } picture_side.progress_hook = NULL; // Progress hook is not thread-safe. - param->picture_ = &picture_side; // No need to free a view afterwards. - param->stats_ = (picture->stats == NULL) ? NULL : &stats_side; + param->picture = &picture_side; // No need to free a view afterwards. + param->stats = (picture->stats == NULL) ? NULL : &stats_side; // Create a side bit writer. if (!VP8LBitWriterClone(bw_main, &bw_side)) { WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } - param->bw_ = &bw_side; + param->bw = &bw_side; // Create a side encoder. enc_side = VP8LEncoderNew(config, &picture_side); if (enc_side == NULL || !EncoderInit(enc_side)) { WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } // Copy the values that were computed for the main encoder. - enc_side->histo_bits_ = enc_main->histo_bits_; - enc_side->predictor_transform_bits_ = - enc_main->predictor_transform_bits_; - enc_side->cross_color_transform_bits_ = - enc_main->cross_color_transform_bits_; - enc_side->palette_size_ = enc_main->palette_size_; - memcpy(enc_side->palette_, enc_main->palette_, - sizeof(enc_main->palette_)); - memcpy(enc_side->palette_sorted_, enc_main->palette_sorted_, - sizeof(enc_main->palette_sorted_)); - param->enc_ = enc_side; + enc_side->histo_bits = enc_main->histo_bits; + enc_side->predictor_transform_bits = + enc_main->predictor_transform_bits; + enc_side->cross_color_transform_bits = + enc_main->cross_color_transform_bits; + enc_side->palette_size = enc_main->palette_size; + memcpy(enc_side->palette, enc_main->palette, + sizeof(enc_main->palette)); + memcpy(enc_side->palette_sorted, enc_main->palette_sorted, + sizeof(enc_main->palette_sorted)); + param->enc = enc_side; } // Create the workers. worker_interface->Init(worker); worker->data1 = param; worker->data2 = NULL; @@ -1909,11 +1926,11 @@ const int mb_h = (height + 15) >> 4; memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info)); } Error: - if (bw.error_) { + if (bw.error) { WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); } VP8LBitWriterWipeOut(&bw); return (picture->error_code == VP8_ENC_OK); } diff --git a/media/libwebp/src/enc/vp8li_enc.h b/media/libwebp/src/enc/vp8li_enc.h --- a/media/libwebp/src/enc/vp8li_enc.h +++ b/media/libwebp/src/enc/vp8li_enc.h @@ -15,70 +15,74 @@ #define WEBP_ENC_VP8LI_ENC_H_ #ifdef HAVE_CONFIG_H #include "src/webp/config.h" #endif + +#include + // Either WEBP_NEAR_LOSSLESS is defined as 0 in config.h when compiling to // disable near-lossless, or it is enabled by default. #ifndef WEBP_NEAR_LOSSLESS #define WEBP_NEAR_LOSSLESS 1 #endif +#include "src/webp/types.h" #include "src/enc/backward_references_enc.h" #include "src/enc/histogram_enc.h" #include "src/utils/bit_writer_utils.h" #include "src/webp/encode.h" #include "src/webp/format_constants.h" #ifdef __cplusplus extern "C" { #endif -// maximum value of transform_bits_ in VP8LEncoder. +// maximum value of 'transform_bits' in VP8LEncoder. #define MAX_TRANSFORM_BITS (MIN_TRANSFORM_BITS + (1 << NUM_TRANSFORM_BITS) - 1) typedef enum { kEncoderNone = 0, kEncoderARGB, kEncoderNearLossless, kEncoderPalette } VP8LEncoderARGBContent; typedef struct { - const WebPConfig* config_; // user configuration and parameters - const WebPPicture* pic_; // input picture. + const WebPConfig* config; // user configuration and parameters + const WebPPicture* pic; // input picture. - uint32_t* argb_; // Transformed argb image data. - VP8LEncoderARGBContent argb_content_; // Content type of the argb buffer. - uint32_t* argb_scratch_; // Scratch memory for argb rows - // (used for prediction). - uint32_t* transform_data_; // Scratch memory for transform data. - uint32_t* transform_mem_; // Currently allocated memory. - size_t transform_mem_size_; // Currently allocated memory size. + uint32_t* argb; // Transformed argb image data. + VP8LEncoderARGBContent argb_content; // Content type of the argb buffer. + uint32_t* argb_scratch; // Scratch memory for argb rows + // (used for prediction). + uint32_t* transform_data; // Scratch memory for transform data. + uint32_t* transform_mem; // Currently allocated memory. + size_t transform_mem_size; // Currently allocated memory size. - int current_width_; // Corresponds to packed image width. + int current_width; // Corresponds to packed image width. // Encoding parameters derived from quality parameter. - int histo_bits_; - int predictor_transform_bits_; // <= MAX_TRANSFORM_BITS - int cross_color_transform_bits_; // <= MAX_TRANSFORM_BITS - int cache_bits_; // If equal to 0, don't use color cache. + int histo_bits; + int predictor_transform_bits; // <= MAX_TRANSFORM_BITS + int cross_color_transform_bits; // <= MAX_TRANSFORM_BITS + int cache_bits; // If equal to 0, don't use color cache. // Encoding parameters derived from image characteristics. - int use_cross_color_; - int use_subtract_green_; - int use_predict_; - int use_palette_; - int palette_size_; - uint32_t palette_[MAX_PALETTE_SIZE]; - // Sorted version of palette_ for cache purposes. - uint32_t palette_sorted_[MAX_PALETTE_SIZE]; + int use_cross_color; + int use_subtract_green; + int use_predict; + int use_palette; + int palette_size; + uint32_t palette[MAX_PALETTE_SIZE]; + // Sorted version of palette for cache purposes. + uint32_t palette_sorted[MAX_PALETTE_SIZE]; // Some 'scratch' (potentially large) objects. - struct VP8LBackwardRefs refs_[4]; // Backward Refs array for temporaries. - VP8LHashChain hash_chain_; // HashChain data for constructing - // backward references. + struct VP8LBackwardRefs refs[4]; // Backward Refs array for temporaries. + VP8LHashChain hash_chain; // HashChain data for constructing + // backward references. } VP8LEncoder; //------------------------------------------------------------------------------ // internal functions. Not public. diff --git a/media/libwebp/src/enc/webp_enc.c b/media/libwebp/src/enc/webp_enc.c --- a/media/libwebp/src/enc/webp_enc.c +++ b/media/libwebp/src/enc/webp_enc.c @@ -10,18 +10,22 @@ // WebP encoder: main entry point // // Author: Skal (pascal.massimino@gmail.com) #include +#include #include #include -#include +#include "src/dec/common_dec.h" +#include "src/webp/types.h" +#include "src/dsp/dsp.h" #include "src/enc/cost_enc.h" #include "src/enc/vp8i_enc.h" #include "src/enc/vp8li_enc.h" #include "src/utils/utils.h" +#include "src/webp/encode.h" // #define PRINT_MEMORY_INFO #ifdef PRINT_MEMORY_INFO #include @@ -36,40 +40,40 @@ //------------------------------------------------------------------------------ // VP8Encoder //------------------------------------------------------------------------------ static void ResetSegmentHeader(VP8Encoder* const enc) { - VP8EncSegmentHeader* const hdr = &enc->segment_hdr_; - hdr->num_segments_ = enc->config_->segments; - hdr->update_map_ = (hdr->num_segments_ > 1); - hdr->size_ = 0; + VP8EncSegmentHeader* const hdr = &enc->segment_hdr; + hdr->num_segments = enc->config->segments; + hdr->update_map = (hdr->num_segments > 1); + hdr->size = 0; } static void ResetFilterHeader(VP8Encoder* const enc) { - VP8EncFilterHeader* const hdr = &enc->filter_hdr_; - hdr->simple_ = 1; - hdr->level_ = 0; - hdr->sharpness_ = 0; - hdr->i4x4_lf_delta_ = 0; + VP8EncFilterHeader* const hdr = &enc->filter_hdr; + hdr->simple = 1; + hdr->level = 0; + hdr->sharpness = 0; + hdr->i4x4_lf_delta = 0; } static void ResetBoundaryPredictions(VP8Encoder* const enc) { // init boundary values once for all - // Note: actually, initializing the preds_[] is only needed for intra4. + // Note: actually, initializing the 'preds[]' is only needed for intra4. int i; - uint8_t* const top = enc->preds_ - enc->preds_w_; - uint8_t* const left = enc->preds_ - 1; - for (i = -1; i < 4 * enc->mb_w_; ++i) { + uint8_t* const top = enc->preds - enc->preds_w; + uint8_t* const left = enc->preds - 1; + for (i = -1; i < 4 * enc->mb_w; ++i) { top[i] = B_DC_PRED; } - for (i = 0; i < 4 * enc->mb_h_; ++i) { - left[i * enc->preds_w_] = B_DC_PRED; + for (i = 0; i < 4 * enc->mb_h; ++i) { + left[i * enc->preds_w] = B_DC_PRED; } - enc->nz_[-1] = 0; // constant + enc->nz[-1] = 0; // constant } -// Mapping from config->method_ to coding tools used. +// Mapping from config->method to coding tools used. //-------------------+---+---+---+---+---+---+---+ // Method | 0 | 1 | 2 | 3 |(4)| 5 | 6 | //-------------------+---+---+---+---+---+---+---+ // fast probe | x | | | x | | | | //-------------------+---+---+---+---+---+---+---+ @@ -91,35 +95,35 @@ //-------------------+---+---+---+---+---+---+---+ // full-SNS | | | | | x | x | x | //-------------------+---+---+---+---+---+---+---+ static void MapConfigToTools(VP8Encoder* const enc) { - const WebPConfig* const config = enc->config_; + const WebPConfig* const config = enc->config; const int method = config->method; const int limit = 100 - config->partition_limit; - enc->method_ = method; - enc->rd_opt_level_ = (method >= 6) ? RD_OPT_TRELLIS_ALL - : (method >= 5) ? RD_OPT_TRELLIS - : (method >= 3) ? RD_OPT_BASIC - : RD_OPT_NONE; - enc->max_i4_header_bits_ = + enc->method = method; + enc->rd_opt_level = (method >= 6) ? RD_OPT_TRELLIS_ALL + : (method >= 5) ? RD_OPT_TRELLIS + : (method >= 3) ? RD_OPT_BASIC + : RD_OPT_NONE; + enc->max_i4_header_bits = 256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block (limit * limit) / (100 * 100); // ... modulated with a quadratic curve. // partition0 = 512k max. - enc->mb_header_limit_ = - (score_t)256 * 510 * 8 * 1024 / (enc->mb_w_ * enc->mb_h_); + enc->mb_header_limit = + (score_t)256 * 510 * 8 * 1024 / (enc->mb_w * enc->mb_h); - enc->thread_level_ = config->thread_level; + enc->thread_level = config->thread_level; - enc->do_search_ = (config->target_size > 0 || config->target_PSNR > 0); + enc->do_search = (config->target_size > 0 || config->target_PSNR > 0); if (!config->low_memory) { #if !defined(DISABLE_TOKEN_BUFFER) - enc->use_tokens_ = (enc->rd_opt_level_ >= RD_OPT_BASIC); // need rd stats + enc->use_tokens = (enc->rd_opt_level >= RD_OPT_BASIC); // need rd stats #endif - if (enc->use_tokens_) { - enc->num_parts_ = 1; // doesn't work with multi-partition + if (enc->use_tokens) { + enc->num_parts = 1; // doesn't work with multi-partition } } } // Memory scaling with dimensions: @@ -148,22 +152,22 @@ (config->filter_strength > 0) || (config->autofilter > 0); const int mb_w = (picture->width + 15) >> 4; const int mb_h = (picture->height + 15) >> 4; const int preds_w = 4 * mb_w + 1; const int preds_h = 4 * mb_h + 1; - const size_t preds_size = preds_w * preds_h * sizeof(*enc->preds_); + const size_t preds_size = preds_w * preds_h * sizeof(*enc->preds); const int top_stride = mb_w * 16; - const size_t nz_size = (mb_w + 1) * sizeof(*enc->nz_) + WEBP_ALIGN_CST; - const size_t info_size = mb_w * mb_h * sizeof(*enc->mb_info_); + const size_t nz_size = (mb_w + 1) * sizeof(*enc->nz) + WEBP_ALIGN_CST; + const size_t info_size = mb_w * mb_h * sizeof(*enc->mb_info); const size_t samples_size = - 2 * top_stride * sizeof(*enc->y_top_) // top-luma/u/v + 2 * top_stride * sizeof(*enc->y_top) // top-luma/u/v + WEBP_ALIGN_CST; // align all const size_t lf_stats_size = - config->autofilter ? sizeof(*enc->lf_stats_) + WEBP_ALIGN_CST : 0; + config->autofilter ? sizeof(*enc->lf_stats) + WEBP_ALIGN_CST : 0; const size_t top_derr_size = (config->quality <= ERROR_DIFFUSION_QUALITY || config->pass > 1) ? - mb_w * sizeof(*enc->top_derr_) : 0; + mb_w * sizeof(*enc->top_derr) : 0; uint8_t* mem; const uint64_t size = (uint64_t)sizeof(*enc) // main struct + WEBP_ALIGN_CST // cache alignment + info_size // modes info + preds_size // prediction modes @@ -204,36 +208,36 @@ return NULL; } enc = (VP8Encoder*)mem; mem = (uint8_t*)WEBP_ALIGN(mem + sizeof(*enc)); memset(enc, 0, sizeof(*enc)); - enc->num_parts_ = 1 << config->partitions; - enc->mb_w_ = mb_w; - enc->mb_h_ = mb_h; - enc->preds_w_ = preds_w; - enc->mb_info_ = (VP8MBInfo*)mem; + enc->num_parts = 1 << config->partitions; + enc->mb_w = mb_w; + enc->mb_h = mb_h; + enc->preds_w = preds_w; + enc->mb_info = (VP8MBInfo*)mem; mem += info_size; - enc->preds_ = mem + 1 + enc->preds_w_; + enc->preds = mem + 1 + enc->preds_w; mem += preds_size; - enc->nz_ = 1 + (uint32_t*)WEBP_ALIGN(mem); + enc->nz = 1 + (uint32_t*)WEBP_ALIGN(mem); mem += nz_size; - enc->lf_stats_ = lf_stats_size ? (LFStats*)WEBP_ALIGN(mem) : NULL; + enc->lf_stats = lf_stats_size ? (LFStats*)WEBP_ALIGN(mem) : NULL; mem += lf_stats_size; // top samples (all 16-aligned) mem = (uint8_t*)WEBP_ALIGN(mem); - enc->y_top_ = mem; - enc->uv_top_ = enc->y_top_ + top_stride; + enc->y_top = mem; + enc->uv_top = enc->y_top + top_stride; mem += 2 * top_stride; - enc->top_derr_ = top_derr_size ? (DError*)mem : NULL; + enc->top_derr = top_derr_size ? (DError*)mem : NULL; mem += top_derr_size; assert(mem <= (uint8_t*)enc + size); - enc->config_ = config; - enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2; - enc->pic_ = picture; - enc->percent_ = 0; + enc->config = config; + enc->profile = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2; + enc->pic = picture; + enc->percent = 0; MapConfigToTools(enc); VP8EncDspInit(); VP8DefaultProbas(enc); ResetSegmentHeader(enc); @@ -244,20 +248,20 @@ // lower quality means smaller output -> we modulate a little the page // size based on quality. This is just a crude 1rst-order prediction. { const float scale = 1.f + config->quality * 5.f / 100.f; // in [1,6] - VP8TBufferInit(&enc->tokens_, (int)(mb_w * mb_h * 4 * scale)); + VP8TBufferInit(&enc->tokens, (int)(mb_w * mb_h * 4 * scale)); } return enc; } static int DeleteVP8Encoder(VP8Encoder* enc) { int ok = 1; if (enc != NULL) { ok = VP8EncDeleteAlpha(enc); - VP8TBufferClear(&enc->tokens_); + VP8TBufferClear(&enc->tokens); WebPSafeFree(enc); } return ok; } @@ -267,41 +271,41 @@ static double GetPSNR(uint64_t err, uint64_t size) { return (err > 0 && size > 0) ? 10. * log10(255. * 255. * size / err) : 99.; } static void FinalizePSNR(const VP8Encoder* const enc) { - WebPAuxStats* stats = enc->pic_->stats; - const uint64_t size = enc->sse_count_; - const uint64_t* const sse = enc->sse_; + WebPAuxStats* stats = enc->pic->stats; + const uint64_t size = enc->sse_count; + const uint64_t* const sse = enc->sse; stats->PSNR[0] = (float)GetPSNR(sse[0], size); stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4); stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4); stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2); stats->PSNR[4] = (float)GetPSNR(sse[3], size); } #endif // !defined(WEBP_DISABLE_STATS) static void StoreStats(VP8Encoder* const enc) { #if !defined(WEBP_DISABLE_STATS) - WebPAuxStats* const stats = enc->pic_->stats; + WebPAuxStats* const stats = enc->pic->stats; if (stats != NULL) { int i, s; for (i = 0; i < NUM_MB_SEGMENTS; ++i) { - stats->segment_level[i] = enc->dqm_[i].fstrength_; - stats->segment_quant[i] = enc->dqm_[i].quant_; + stats->segment_level[i] = enc->dqm[i].fstrength; + stats->segment_quant[i] = enc->dqm[i].quant; for (s = 0; s <= 2; ++s) { - stats->residual_bytes[s][i] = enc->residual_bytes_[s][i]; + stats->residual_bytes[s][i] = enc->residual_bytes[s][i]; } } FinalizePSNR(enc); - stats->coded_size = enc->coded_size_; + stats->coded_size = enc->coded_size; for (i = 0; i < 3; ++i) { - stats->block_count[i] = enc->block_count_[i]; + stats->block_count[i] = enc->block_count[i]; } } #else // defined(WEBP_DISABLE_STATS) - WebPReportProgress(enc->pic_, 100, &enc->percent_); // done! + WebPReportProgress(enc->pic, 100, &enc->percent); // done! #endif // !defined(WEBP_DISABLE_STATS) } int WebPEncodingSetError(const WebPPicture* const pic, WebPEncodingError error) { @@ -378,11 +382,11 @@ // Note: each of the tasks below account for 20% in the progress report. ok = VP8EncAnalyze(enc); // Analysis is done, proceed to actual coding. ok = ok && VP8EncStartAlpha(enc); // possibly done in parallel - if (!enc->use_tokens_) { + if (!enc->use_tokens) { ok = ok && VP8EncLoop(enc); } else { ok = ok && VP8EncTokenLoop(enc); } ok = ok && VP8EncFinishAlpha(enc); diff --git a/media/libwebp/src/utils/bit_reader_inl_utils.h b/media/libwebp/src/utils/bit_reader_inl_utils.h --- a/media/libwebp/src/utils/bit_reader_inl_utils.h +++ b/media/libwebp/src/utils/bit_reader_inl_utils.h @@ -18,16 +18,19 @@ #ifdef HAVE_CONFIG_H #include "src/webp/config.h" #endif +#include #include // for memcpy +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" #include "src/utils/bit_reader_utils.h" #include "src/utils/endian_inl_utils.h" #include "src/utils/utils.h" +#include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif @@ -51,37 +54,37 @@ void VP8LoadFinalBytes(VP8BitReader* const br); //------------------------------------------------------------------------------ // Inlined critical functions -// makes sure br->value_ has at least BITS bits worth of data +// makes sure br->value has at least BITS bits worth of data static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) { - assert(br != NULL && br->buf_ != NULL); + assert(br != NULL && br->buf != NULL); // Read 'BITS' bits at a time if possible. - if (br->buf_ < br->buf_max_) { + if (br->buf < br->buf_max) { // convert memory type to register type (with some zero'ing!) bit_t bits; #if defined(WEBP_USE_MIPS32) // This is needed because of un-aligned read. lbit_t in_bits; - lbit_t* p_buf_ = (lbit_t*)br->buf_; + lbit_t* p_buf = (lbit_t*)br->buf; __asm__ volatile( ".set push \n\t" ".set at \n\t" ".set macro \n\t" - "ulw %[in_bits], 0(%[p_buf_]) \n\t" + "ulw %[in_bits], 0(%[p_buf]) \n\t" ".set pop \n\t" : [in_bits]"=r"(in_bits) - : [p_buf_]"r"(p_buf_) + : [p_buf]"r"(p_buf) : "memory", "at" ); #else lbit_t in_bits; - memcpy(&in_bits, br->buf_, sizeof(in_bits)); + memcpy(&in_bits, br->buf, sizeof(in_bits)); #endif - br->buf_ += BITS >> 3; + br->buf += BITS >> 3; #if !defined(WORDS_BIGENDIAN) #if (BITS > 32) bits = BSwap64(in_bits); bits >>= 64 - BITS; #elif (BITS >= 24) @@ -94,98 +97,98 @@ #endif // BITS > 32 #else // WORDS_BIGENDIAN bits = (bit_t)in_bits; if (BITS != 8 * sizeof(bit_t)) bits >>= (8 * sizeof(bit_t) - BITS); #endif - br->value_ = bits | (br->value_ << BITS); - br->bits_ += BITS; + br->value = bits | (br->value << BITS); + br->bits += BITS; } else { VP8LoadFinalBytes(br); // no need to be inlined } } // Read a bit with proba 'prob'. Speed-critical function! static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br, int prob, const char label[]) { // Don't move this declaration! It makes a big speed difference to store // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't - // alter br->range_ value. - range_t range = br->range_; - if (br->bits_ < 0) { + // alter br->range value. + range_t range = br->range; + if (br->bits < 0) { VP8LoadNewBytes(br); } { - const int pos = br->bits_; + const int pos = br->bits; const range_t split = (range * prob) >> 8; - const range_t value = (range_t)(br->value_ >> pos); + const range_t value = (range_t)(br->value >> pos); const int bit = (value > split); if (bit) { range -= split; - br->value_ -= (bit_t)(split + 1) << pos; + br->value -= (bit_t)(split + 1) << pos; } else { range = split + 1; } { const int shift = 7 ^ BitsLog2Floor(range); range <<= shift; - br->bits_ -= shift; + br->bits -= shift; } - br->range_ = range - 1; + br->range = range - 1; BT_TRACK(br); return bit; } } // simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here) static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE int VP8GetSigned(VP8BitReader* WEBP_RESTRICT const br, int v, const char label[]) { - if (br->bits_ < 0) { + if (br->bits < 0) { VP8LoadNewBytes(br); } { - const int pos = br->bits_; - const range_t split = br->range_ >> 1; - const range_t value = (range_t)(br->value_ >> pos); + const int pos = br->bits; + const range_t split = br->range >> 1; + const range_t value = (range_t)(br->value >> pos); const int32_t mask = (int32_t)(split - value) >> 31; // -1 or 0 - br->bits_ -= 1; - br->range_ += (range_t)mask; - br->range_ |= 1; - br->value_ -= (bit_t)((split + 1) & (uint32_t)mask) << pos; + br->bits -= 1; + br->range += (range_t)mask; + br->range |= 1; + br->value -= (bit_t)((split + 1) & (uint32_t)mask) << pos; BT_TRACK(br); return (v ^ mask) - mask; } } static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* WEBP_RESTRICT const br, int prob, const char label[]) { // Don't move this declaration! It makes a big speed difference to store // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't - // alter br->range_ value. - range_t range = br->range_; - if (br->bits_ < 0) { + // alter br->range value. + range_t range = br->range; + if (br->bits < 0) { VP8LoadNewBytes(br); } { - const int pos = br->bits_; + const int pos = br->bits; const range_t split = (range * prob) >> 8; - const range_t value = (range_t)(br->value_ >> pos); + const range_t value = (range_t)(br->value >> pos); int bit; // Don't use 'const int bit = (value > split);", it's slower. if (value > split) { range -= split + 1; - br->value_ -= (bit_t)(split + 1) << pos; + br->value -= (bit_t)(split + 1) << pos; bit = 1; } else { range = split; bit = 0; } if (range <= (range_t)0x7e) { const int shift = kVP8Log2Range[range]; range = kVP8NewRange[range]; - br->bits_ -= shift; + br->bits -= shift; } - br->range_ = range; + br->range = range; BT_TRACK(br); return bit; } } diff --git a/media/libwebp/src/utils/bit_reader_utils.h b/media/libwebp/src/utils/bit_reader_utils.h --- a/media/libwebp/src/utils/bit_reader_utils.h +++ b/media/libwebp/src/utils/bit_reader_utils.h @@ -14,10 +14,12 @@ #ifndef WEBP_UTILS_BIT_READER_UTILS_H_ #define WEBP_UTILS_BIT_READER_UTILS_H_ #include +#include + #ifdef _MSC_VER #include // _byteswap_ulong #endif #include "src/dsp/cpu.h" #include "src/webp/types.h" @@ -45,18 +47,18 @@ #ifdef __cplusplus extern "C" { #endif -// The Boolean decoder needs to maintain infinite precision on the value_ field. -// However, since range_ is only 8bit, we only need an active window of 8 bits -// for value_. Left bits (MSB) gets zeroed and shifted away when value_ falls -// below 128, range_ is updated, and fresh bits read from the bitstream are -// brought in as LSB. To avoid reading the fresh bits one by one (slow), we -// cache BITS of them ahead. The total of (BITS + 8) bits must fit into a -// natural register (with type bit_t). To fetch BITS bits from bitstream we -// use a type lbit_t. +// The Boolean decoder needs to maintain infinite precision on the 'value' +// field. However, since 'range' is only 8bit, we only need an active window of +// 8 bits for 'value". Left bits (MSB) gets zeroed and shifted away when +// 'value' falls below 128, 'range' is updated, and fresh bits read from the +// bitstream are brought in as LSB. To avoid reading the fresh bits one by one +// (slow), we cache BITS of them ahead. The total of (BITS + 8) bits must fit +// into a natural register (with type bit_t). To fetch BITS bits from bitstream +// we use a type lbit_t. // // BITS can be any multiple of 8 from 8 to 56 (inclusive). // Pick values that fit natural register size. #if defined(__i386__) || defined(_M_IX86) // x86 32bit @@ -75,12 +77,12 @@ #define BITS 24 #endif //------------------------------------------------------------------------------ // Derived types and constants: -// bit_t = natural register type for storing 'value_' (which is BITS+8 bits) -// range_t = register for 'range_' (which is 8bits only) +// bit_t = natural register type for storing 'value' (which is BITS+8 bits) +// range_t = register for 'range' (which is 8bits only) #if (BITS > 24) typedef uint64_t bit_t; #else typedef uint32_t bit_t; @@ -92,18 +94,18 @@ // Bitreader typedef struct VP8BitReader VP8BitReader; struct VP8BitReader { // boolean decoder (keep the field ordering as is!) - bit_t value_; // current value - range_t range_; // current range minus 1. In [127, 254] interval. - int bits_; // number of valid bits left + bit_t value; // current value + range_t range; // current range minus 1. In [127, 254] interval. + int bits; // number of valid bits left // read buffer - const uint8_t* buf_; // next byte to be read - const uint8_t* buf_end_; // end of read buffer - const uint8_t* buf_max_; // max packed-read position on buffer - int eof_; // true if input is exhausted + const uint8_t* buf; // next byte to be read + const uint8_t* buf_end; // end of read buffer + const uint8_t* buf_max; // max packed-read position on buffer + int eof; // true if input is exhausted }; // Initialize the bit reader and the boolean decoder. void VP8InitBitReader(VP8BitReader* const br, const uint8_t* const start, size_t size); @@ -139,16 +141,16 @@ #define VP8L_WBITS 32 // Minimum number of bytes ready after VP8LFillBitWindow. typedef uint64_t vp8l_val_t; // right now, this bit-reader can only use 64bit. typedef struct { - vp8l_val_t val_; // pre-fetched bits - const uint8_t* buf_; // input byte buffer - size_t len_; // buffer length - size_t pos_; // byte position in buf_ - int bit_pos_; // current bit-reading position in val_ - int eos_; // true if a bit was read past the end of buffer + vp8l_val_t val; // pre-fetched bits + const uint8_t* buf; // input byte buffer + size_t len; // buffer length + size_t pos; // byte position in buf + int bit_pos; // current bit-reading position in val + int eos; // true if a bit was read past the end of buffer } VP8LBitReader; void VP8LInitBitReader(VP8LBitReader* const br, const uint8_t* const start, size_t length); @@ -158,38 +160,38 @@ const uint8_t* const buffer, size_t length); // Reads the specified number of bits from read buffer. // Flags an error in case end_of_stream or n_bits is more than the allowed limit // of VP8L_MAX_NUM_BIT_READ (inclusive). -// Flags eos_ if this read attempt is going to cross the read buffer. +// Flags 'eos' if this read attempt is going to cross the read buffer. uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits); // Return the prefetched bits, so they can be looked up. static WEBP_INLINE uint32_t VP8LPrefetchBits(VP8LBitReader* const br) { - return (uint32_t)(br->val_ >> (br->bit_pos_ & (VP8L_LBITS - 1))); + return (uint32_t)(br->val >> (br->bit_pos & (VP8L_LBITS - 1))); } // Returns true if there was an attempt at reading bit past the end of -// the buffer. Doesn't set br->eos_ flag. +// the buffer. Doesn't set br->eos flag. static WEBP_INLINE int VP8LIsEndOfStream(const VP8LBitReader* const br) { - assert(br->pos_ <= br->len_); - return br->eos_ || ((br->pos_ == br->len_) && (br->bit_pos_ > VP8L_LBITS)); + assert(br->pos <= br->len); + return br->eos || ((br->pos == br->len) && (br->bit_pos > VP8L_LBITS)); } // For jumping over a number of bits in the bit stream when accessed with // VP8LPrefetchBits and VP8LFillBitWindow. -// This function does *not* set br->eos_, since it's speed-critical. +// This function does *not* set br->eos, since it's speed-critical. // Use with extreme care! static WEBP_INLINE void VP8LSetBitPos(VP8LBitReader* const br, int val) { - br->bit_pos_ = val; + br->bit_pos = val; } // Advances the read buffer by 4 bytes to make room for reading next 32 bits. // Speed critical, but infrequent part of the code can be non-inlined. extern void VP8LDoFillBitWindow(VP8LBitReader* const br); static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) { - if (br->bit_pos_ >= VP8L_WBITS) VP8LDoFillBitWindow(br); + if (br->bit_pos >= VP8L_WBITS) VP8LDoFillBitWindow(br); } #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libwebp/src/utils/bit_reader_utils.c b/media/libwebp/src/utils/bit_reader_utils.c --- a/media/libwebp/src/utils/bit_reader_utils.c +++ b/media/libwebp/src/utils/bit_reader_utils.c @@ -13,45 +13,51 @@ #ifdef HAVE_CONFIG_H #include "src/webp/config.h" #endif +#include +#include + +#include "src/webp/types.h" #include "src/dsp/cpu.h" #include "src/utils/bit_reader_inl_utils.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/endian_inl_utils.h" #include "src/utils/utils.h" //------------------------------------------------------------------------------ // VP8BitReader void VP8BitReaderSetBuffer(VP8BitReader* const br, const uint8_t* const start, size_t size) { - br->buf_ = start; - br->buf_end_ = start + size; - br->buf_max_ = - (size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1 - : start; + assert(start != NULL); + br->buf = start; + br->buf_end = start + size; + br->buf_max = + (size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1 : start; } void VP8InitBitReader(VP8BitReader* const br, const uint8_t* const start, size_t size) { assert(br != NULL); assert(start != NULL); assert(size < (1u << 31)); // limit ensured by format and upstream checks - br->range_ = 255 - 1; - br->value_ = 0; - br->bits_ = -8; // to load the very first 8bits - br->eof_ = 0; + br->range = 255 - 1; + br->value = 0; + br->bits = -8; // to load the very first 8bits + br->eof = 0; VP8BitReaderSetBuffer(br, start, size); VP8LoadNewBytes(br); } void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) { - if (br->buf_ != NULL) { - br->buf_ += offset; - br->buf_end_ += offset; - br->buf_max_ += offset; + if (br->buf != NULL) { + br->buf += offset; + br->buf_end += offset; + br->buf_max += offset; } } const uint8_t kVP8Log2Range[128] = { 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, @@ -84,21 +90,21 @@ 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 127 }; void VP8LoadFinalBytes(VP8BitReader* const br) { - assert(br != NULL && br->buf_ != NULL); + assert(br != NULL && br->buf != NULL); // Only read 8bits at a time - if (br->buf_ < br->buf_end_) { - br->bits_ += 8; - br->value_ = (bit_t)(*br->buf_++) | (br->value_ << 8); - } else if (!br->eof_) { - br->value_ <<= 8; - br->bits_ += 8; - br->eof_ = 1; + if (br->buf < br->buf_end) { + br->bits += 8; + br->value = (bit_t)(*br->buf++) | (br->value << 8); + } else if (!br->eof) { + br->value <<= 8; + br->bits += 8; + br->eof = 1; } else { - br->bits_ = 0; // This is to avoid undefined behaviour with shifts. + br->bits = 0; // This is to avoid undefined behaviour with shifts. } } //------------------------------------------------------------------------------ // Higher-level calls @@ -145,77 +151,77 @@ vp8l_val_t value = 0; assert(br != NULL); assert(start != NULL); assert(length < 0xfffffff8u); // can't happen with a RIFF chunk. - br->len_ = length; - br->val_ = 0; - br->bit_pos_ = 0; - br->eos_ = 0; + br->len = length; + br->val = 0; + br->bit_pos = 0; + br->eos = 0; - if (length > sizeof(br->val_)) { - length = sizeof(br->val_); + if (length > sizeof(br->val)) { + length = sizeof(br->val); } for (i = 0; i < length; ++i) { value |= (vp8l_val_t)start[i] << (8 * i); } - br->val_ = value; - br->pos_ = length; - br->buf_ = start; + br->val = value; + br->pos = length; + br->buf = start; } void VP8LBitReaderSetBuffer(VP8LBitReader* const br, const uint8_t* const buf, size_t len) { assert(br != NULL); assert(buf != NULL); assert(len < 0xfffffff8u); // can't happen with a RIFF chunk. - br->buf_ = buf; - br->len_ = len; - // pos_ > len_ should be considered a param error. - br->eos_ = (br->pos_ > br->len_) || VP8LIsEndOfStream(br); + br->buf = buf; + br->len = len; + // 'pos' > 'len' should be considered a param error. + br->eos = (br->pos > br->len) || VP8LIsEndOfStream(br); } static void VP8LSetEndOfStream(VP8LBitReader* const br) { - br->eos_ = 1; - br->bit_pos_ = 0; // To avoid undefined behaviour with shifts. + br->eos = 1; + br->bit_pos = 0; // To avoid undefined behaviour with shifts. } // If not at EOS, reload up to VP8L_LBITS byte-by-byte static void ShiftBytes(VP8LBitReader* const br) { - while (br->bit_pos_ >= 8 && br->pos_ < br->len_) { - br->val_ >>= 8; - br->val_ |= ((vp8l_val_t)br->buf_[br->pos_]) << (VP8L_LBITS - 8); - ++br->pos_; - br->bit_pos_ -= 8; + while (br->bit_pos >= 8 && br->pos < br->len) { + br->val >>= 8; + br->val |= ((vp8l_val_t)br->buf[br->pos]) << (VP8L_LBITS - 8); + ++br->pos; + br->bit_pos -= 8; } if (VP8LIsEndOfStream(br)) { VP8LSetEndOfStream(br); } } void VP8LDoFillBitWindow(VP8LBitReader* const br) { - assert(br->bit_pos_ >= VP8L_WBITS); + assert(br->bit_pos >= VP8L_WBITS); #if defined(VP8L_USE_FAST_LOAD) - if (br->pos_ + sizeof(br->val_) < br->len_) { - br->val_ >>= VP8L_WBITS; - br->bit_pos_ -= VP8L_WBITS; - br->val_ |= (vp8l_val_t)HToLE32(WebPMemToUint32(br->buf_ + br->pos_)) << - (VP8L_LBITS - VP8L_WBITS); - br->pos_ += VP8L_LOG8_WBITS; + if (br->pos + sizeof(br->val) < br->len) { + br->val >>= VP8L_WBITS; + br->bit_pos -= VP8L_WBITS; + br->val |= (vp8l_val_t)HToLE32(WebPMemToUint32(br->buf + br->pos)) << + (VP8L_LBITS - VP8L_WBITS); + br->pos += VP8L_LOG8_WBITS; return; } #endif ShiftBytes(br); // Slow path. } uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) { assert(n_bits >= 0); // Flag an error if end_of_stream or n_bits is more than allowed limit. - if (!br->eos_ && n_bits <= VP8L_MAX_NUM_BIT_READ) { + if (!br->eos && n_bits <= VP8L_MAX_NUM_BIT_READ) { const uint32_t val = VP8LPrefetchBits(br) & kBitMask[n_bits]; - const int new_bits = br->bit_pos_ + n_bits; - br->bit_pos_ = new_bits; + const int new_bits = br->bit_pos + n_bits; + br->bit_pos = new_bits; ShiftBytes(br); return val; } else { VP8LSetEndOfStream(br); return 0; @@ -271,21 +277,21 @@ void BitTrace(const struct VP8BitReader* const br, const char label[]) { int i, pos; if (!init_done) { memset(kLabels, 0, sizeof(kLabels)); atexit(PrintBitTraces); - buf_start = br->buf_; + buf_start = br->buf; init_done = 1; } - pos = (int)(br->buf_ - buf_start) * 8 - br->bits_; + pos = (int)(br->buf - buf_start) * 8 - br->bits; // if there's a too large jump, we've changed partition -> reset counter if (abs(pos - last_pos) > 32) { - buf_start = br->buf_; + buf_start = br->buf; pos = 0; last_pos = 0; } - if (br->range_ >= 0x7f) pos += kVP8Log2Range[br->range_ - 0x7f]; + if (br->range >= 0x7f) pos += kVP8Log2Range[br->range - 0x7f]; for (i = 0; i < last_label; ++i) { if (!strcmp(label, kLabels[i].label)) break; } if (i == MAX_NUM_LABELS) abort(); // overflow! kLabels[i].label = label; diff --git a/media/libwebp/src/utils/bit_writer_utils.h b/media/libwebp/src/utils/bit_writer_utils.h --- a/media/libwebp/src/utils/bit_writer_utils.h +++ b/media/libwebp/src/utils/bit_writer_utils.h @@ -12,10 +12,12 @@ // Author: Skal (pascal.massimino@gmail.com) #ifndef WEBP_UTILS_BIT_WRITER_UTILS_H_ #define WEBP_UTILS_BIT_WRITER_UTILS_H_ +#include + #include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif @@ -23,18 +25,18 @@ //------------------------------------------------------------------------------ // Bit-writing typedef struct VP8BitWriter VP8BitWriter; struct VP8BitWriter { - int32_t range_; // range-1 - int32_t value_; - int run_; // number of outstanding bits - int nb_bits_; // number of pending bits - uint8_t* buf_; // internal buffer. Re-allocated regularly. Not owned. - size_t pos_; - size_t max_pos_; - int error_; // true in case of error + int32_t range; // range-1 + int32_t value; + int run; // number of outstanding bits + int nb_bits; // number of pending bits + uint8_t* buf; // internal buffer. Re-allocated regularly. Not owned. + size_t pos; + size_t max_pos; + int error; // true in case of error }; // Initialize the object. Allocates some initial memory based on expected_size. int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size); // Finalize the bitstream coding. Returns a pointer to the internal buffer. @@ -52,21 +54,21 @@ int VP8BitWriterAppend(VP8BitWriter* const bw, const uint8_t* data, size_t size); // return approximate write position (in bits) static WEBP_INLINE uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) { - const uint64_t nb_bits = 8 + bw->nb_bits_; // bw->nb_bits_ is <= 0, note - return (bw->pos_ + bw->run_) * 8 + nb_bits; + const uint64_t nb_bits = 8 + bw->nb_bits; // bw->nb_bits is <= 0, note + return (bw->pos + bw->run) * 8 + nb_bits; } // Returns a pointer to the internal buffer. static WEBP_INLINE uint8_t* VP8BitWriterBuf(const VP8BitWriter* const bw) { - return bw->buf_; + return bw->buf; } // Returns the size of the internal buffer. static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) { - return bw->pos_; + return bw->pos; } //------------------------------------------------------------------------------ // VP8LBitWriter @@ -85,25 +87,25 @@ #define VP8L_WRITER_BITS 16 #define VP8L_WRITER_MAX_BITS 32 #endif typedef struct { - vp8l_atype_t bits_; // bit accumulator - int used_; // number of bits used in accumulator - uint8_t* buf_; // start of buffer - uint8_t* cur_; // current write position - uint8_t* end_; // end of buffer + vp8l_atype_t bits; // bit accumulator + int used; // number of bits used in accumulator + uint8_t* buf; // start of buffer + uint8_t* cur; // current write position + uint8_t* end; // end of buffer // After all bits are written (VP8LBitWriterFinish()), the caller must observe - // the state of error_. A value of 1 indicates that a memory allocation + // the state of 'error'. A value of 1 indicates that a memory allocation // failure has happened during bit writing. A value of 0 indicates successful // writing of bits. - int error_; + int error; } VP8LBitWriter; static WEBP_INLINE size_t VP8LBitWriterNumBytes(const VP8LBitWriter* const bw) { - return (bw->cur_ - bw->buf_) + ((bw->used_ + 7) >> 3); + return (bw->cur - bw->buf) + ((bw->used + 7) >> 3); } // Returns false in case of memory allocation error. int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size); // Returns false in case of memory allocation error. @@ -127,20 +129,20 @@ // This function writes bits into bytes in increasing addresses (little endian), // and within a byte least-significant-bit first. // This function can write up to 32 bits in one go, but VP8LBitReader can only // read 24 bits max (VP8L_MAX_NUM_BIT_READ). -// VP8LBitWriter's error_ flag is set in case of memory allocation error. +// VP8LBitWriter's 'error' flag is set in case of memory allocation error. static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw, uint32_t bits, int n_bits) { if (sizeof(vp8l_wtype_t) == 4) { if (n_bits > 0) { - if (bw->used_ >= 32) { + if (bw->used >= 32) { VP8LPutBitsFlushBits(bw); } - bw->bits_ |= (vp8l_atype_t)bits << bw->used_; - bw->used_ += n_bits; + bw->bits |= (vp8l_atype_t)bits << bw->used; + bw->used += n_bits; } } else { VP8LPutBitsInternal(bw, bits, n_bits); } } diff --git a/media/libwebp/src/utils/bit_writer_utils.c b/media/libwebp/src/utils/bit_writer_utils.c --- a/media/libwebp/src/utils/bit_writer_utils.c +++ b/media/libwebp/src/utils/bit_writer_utils.c @@ -11,71 +11,72 @@ // // Author: Skal (pascal.massimino@gmail.com) // Vikas Arora (vikaas.arora@gmail.com) #include +#include #include // for memcpy() -#include #include "src/utils/bit_writer_utils.h" +#include "src/webp/types.h" #include "src/utils/endian_inl_utils.h" #include "src/utils/utils.h" //------------------------------------------------------------------------------ // VP8BitWriter static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) { uint8_t* new_buf; size_t new_size; - const uint64_t needed_size_64b = (uint64_t)bw->pos_ + extra_size; + const uint64_t needed_size_64b = (uint64_t)bw->pos + extra_size; const size_t needed_size = (size_t)needed_size_64b; if (needed_size_64b != needed_size) { - bw->error_ = 1; + bw->error = 1; return 0; } - if (needed_size <= bw->max_pos_) return 1; + if (needed_size <= bw->max_pos) return 1; // If the following line wraps over 32bit, the test just after will catch it. - new_size = 2 * bw->max_pos_; + new_size = 2 * bw->max_pos; if (new_size < needed_size) new_size = needed_size; if (new_size < 1024) new_size = 1024; new_buf = (uint8_t*)WebPSafeMalloc(1ULL, new_size); if (new_buf == NULL) { - bw->error_ = 1; + bw->error = 1; return 0; } - if (bw->pos_ > 0) { - assert(bw->buf_ != NULL); - memcpy(new_buf, bw->buf_, bw->pos_); + if (bw->pos > 0) { + assert(bw->buf != NULL); + memcpy(new_buf, bw->buf, bw->pos); } - WebPSafeFree(bw->buf_); - bw->buf_ = new_buf; - bw->max_pos_ = new_size; + WebPSafeFree(bw->buf); + bw->buf = new_buf; + bw->max_pos = new_size; return 1; } static void Flush(VP8BitWriter* const bw) { - const int s = 8 + bw->nb_bits_; - const int32_t bits = bw->value_ >> s; - assert(bw->nb_bits_ >= 0); - bw->value_ -= bits << s; - bw->nb_bits_ -= 8; + const int s = 8 + bw->nb_bits; + const int32_t bits = bw->value >> s; + assert(bw->nb_bits >= 0); + bw->value -= bits << s; + bw->nb_bits -= 8; if ((bits & 0xff) != 0xff) { - size_t pos = bw->pos_; - if (!BitWriterResize(bw, bw->run_ + 1)) { + size_t pos = bw->pos; + if (!BitWriterResize(bw, bw->run + 1)) { return; } if (bits & 0x100) { // overflow -> propagate carry over pending 0xff's - if (pos > 0) bw->buf_[pos - 1]++; + if (pos > 0) bw->buf[pos - 1]++; } - if (bw->run_ > 0) { + if (bw->run > 0) { const int value = (bits & 0x100) ? 0x00 : 0xff; - for (; bw->run_ > 0; --bw->run_) bw->buf_[pos++] = value; + for (; bw->run > 0; --bw->run) bw->buf[pos++] = value; } - bw->buf_[pos++] = bits & 0xff; - bw->pos_ = pos; + bw->buf[pos++] = bits & 0xff; + bw->pos = pos; } else { - bw->run_++; // delay writing of bytes 0xff, pending eventual carry. + bw->run++; // delay writing of bytes 0xff, pending eventual carry. } } //------------------------------------------------------------------------------ // renormalization @@ -104,40 +105,40 @@ 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 127 }; int VP8PutBit(VP8BitWriter* const bw, int bit, int prob) { - const int split = (bw->range_ * prob) >> 8; + const int split = (bw->range * prob) >> 8; if (bit) { - bw->value_ += split + 1; - bw->range_ -= split + 1; + bw->value += split + 1; + bw->range -= split + 1; } else { - bw->range_ = split; + bw->range = split; } - if (bw->range_ < 127) { // emit 'shift' bits out and renormalize - const int shift = kNorm[bw->range_]; - bw->range_ = kNewRange[bw->range_]; - bw->value_ <<= shift; - bw->nb_bits_ += shift; - if (bw->nb_bits_ > 0) Flush(bw); + if (bw->range < 127) { // emit 'shift' bits out and renormalize + const int shift = kNorm[bw->range]; + bw->range = kNewRange[bw->range]; + bw->value <<= shift; + bw->nb_bits += shift; + if (bw->nb_bits > 0) Flush(bw); } return bit; } int VP8PutBitUniform(VP8BitWriter* const bw, int bit) { - const int split = bw->range_ >> 1; + const int split = bw->range >> 1; if (bit) { - bw->value_ += split + 1; - bw->range_ -= split + 1; + bw->value += split + 1; + bw->range -= split + 1; } else { - bw->range_ = split; + bw->range = split; } - if (bw->range_ < 127) { - bw->range_ = kNewRange[bw->range_]; - bw->value_ <<= 1; - bw->nb_bits_ += 1; - if (bw->nb_bits_ > 0) Flush(bw); + if (bw->range < 127) { + bw->range = kNewRange[bw->range]; + bw->value <<= 1; + bw->nb_bits += 1; + if (bw->nb_bits > 0) Flush(bw); } return bit; } void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits) { @@ -158,41 +159,41 @@ } //------------------------------------------------------------------------------ int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size) { - bw->range_ = 255 - 1; - bw->value_ = 0; - bw->run_ = 0; - bw->nb_bits_ = -8; - bw->pos_ = 0; - bw->max_pos_ = 0; - bw->error_ = 0; - bw->buf_ = NULL; + bw->range = 255 - 1; + bw->value = 0; + bw->run = 0; + bw->nb_bits = -8; + bw->pos = 0; + bw->max_pos = 0; + bw->error = 0; + bw->buf = NULL; return (expected_size > 0) ? BitWriterResize(bw, expected_size) : 1; } uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) { - VP8PutBits(bw, 0, 9 - bw->nb_bits_); - bw->nb_bits_ = 0; // pad with zeroes + VP8PutBits(bw, 0, 9 - bw->nb_bits); + bw->nb_bits = 0; // pad with zeroes Flush(bw); - return bw->buf_; + return bw->buf; } int VP8BitWriterAppend(VP8BitWriter* const bw, const uint8_t* data, size_t size) { assert(data != NULL); - if (bw->nb_bits_ != -8) return 0; // Flush() must have been called + if (bw->nb_bits != -8) return 0; // Flush() must have been called if (!BitWriterResize(bw, size)) return 0; - memcpy(bw->buf_ + bw->pos_, data, size); - bw->pos_ += size; + memcpy(bw->buf + bw->pos, data, size); + bw->pos += size; return 1; } void VP8BitWriterWipeOut(VP8BitWriter* const bw) { if (bw != NULL) { - WebPSafeFree(bw->buf_); + WebPSafeFree(bw->buf); memset(bw, 0, sizeof(*bw)); } } //------------------------------------------------------------------------------ @@ -204,102 +205,102 @@ // Returns 1 on success. static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) { uint8_t* allocated_buf; size_t allocated_size; - const size_t max_bytes = bw->end_ - bw->buf_; - const size_t current_size = bw->cur_ - bw->buf_; + const size_t max_bytes = bw->end - bw->buf; + const size_t current_size = bw->cur - bw->buf; const uint64_t size_required_64b = (uint64_t)current_size + extra_size; const size_t size_required = (size_t)size_required_64b; if (size_required != size_required_64b) { - bw->error_ = 1; + bw->error = 1; return 0; } if (max_bytes > 0 && size_required <= max_bytes) return 1; allocated_size = (3 * max_bytes) >> 1; if (allocated_size < size_required) allocated_size = size_required; // make allocated size multiple of 1k allocated_size = (((allocated_size >> 10) + 1) << 10); allocated_buf = (uint8_t*)WebPSafeMalloc(1ULL, allocated_size); if (allocated_buf == NULL) { - bw->error_ = 1; + bw->error = 1; return 0; } if (current_size > 0) { - memcpy(allocated_buf, bw->buf_, current_size); + memcpy(allocated_buf, bw->buf, current_size); } - WebPSafeFree(bw->buf_); - bw->buf_ = allocated_buf; - bw->cur_ = bw->buf_ + current_size; - bw->end_ = bw->buf_ + allocated_size; + WebPSafeFree(bw->buf); + bw->buf = allocated_buf; + bw->cur = bw->buf + current_size; + bw->end = bw->buf + allocated_size; return 1; } int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) { memset(bw, 0, sizeof(*bw)); return VP8LBitWriterResize(bw, expected_size); } int VP8LBitWriterClone(const VP8LBitWriter* const src, VP8LBitWriter* const dst) { - const size_t current_size = src->cur_ - src->buf_; - assert(src->cur_ >= src->buf_ && src->cur_ <= src->end_); + const size_t current_size = src->cur - src->buf; + assert(src->cur >= src->buf && src->cur <= src->end); if (!VP8LBitWriterResize(dst, current_size)) return 0; - memcpy(dst->buf_, src->buf_, current_size); - dst->bits_ = src->bits_; - dst->used_ = src->used_; - dst->error_ = src->error_; - dst->cur_ = dst->buf_ + current_size; + memcpy(dst->buf, src->buf, current_size); + dst->bits = src->bits; + dst->used = src->used; + dst->error = src->error; + dst->cur = dst->buf + current_size; return 1; } void VP8LBitWriterWipeOut(VP8LBitWriter* const bw) { if (bw != NULL) { - WebPSafeFree(bw->buf_); + WebPSafeFree(bw->buf); memset(bw, 0, sizeof(*bw)); } } void VP8LBitWriterReset(const VP8LBitWriter* const bw_init, VP8LBitWriter* const bw) { - bw->bits_ = bw_init->bits_; - bw->used_ = bw_init->used_; - bw->cur_ = bw->buf_ + (bw_init->cur_ - bw_init->buf_); - assert(bw->cur_ <= bw->end_); - bw->error_ = bw_init->error_; + bw->bits = bw_init->bits; + bw->used = bw_init->used; + bw->cur = bw->buf + (bw_init->cur - bw_init->buf); + assert(bw->cur <= bw->end); + bw->error = bw_init->error; } void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst) { const VP8LBitWriter tmp = *src; *src = *dst; *dst = tmp; } void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) { // If needed, make some room by flushing some bits out. - if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { - const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE; + if (bw->cur + VP8L_WRITER_BYTES > bw->end) { + const uint64_t extra_size = (bw->end - bw->buf) + MIN_EXTRA_SIZE; if (!CheckSizeOverflow(extra_size) || !VP8LBitWriterResize(bw, (size_t)extra_size)) { - bw->cur_ = bw->buf_; - bw->error_ = 1; + bw->cur = bw->buf; + bw->error = 1; return; } } - *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)bw->bits_); - bw->cur_ += VP8L_WRITER_BYTES; - bw->bits_ >>= VP8L_WRITER_BITS; - bw->used_ -= VP8L_WRITER_BITS; + *(vp8l_wtype_t*)bw->cur = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)bw->bits); + bw->cur += VP8L_WRITER_BYTES; + bw->bits >>= VP8L_WRITER_BITS; + bw->used -= VP8L_WRITER_BITS; } void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) { assert(n_bits <= 32); // That's the max we can handle: assert(sizeof(vp8l_wtype_t) == 2); if (n_bits > 0) { - vp8l_atype_t lbits = bw->bits_; - int used = bw->used_; + vp8l_atype_t lbits = bw->bits; + int used = bw->used; // Special case of overflow handling for 32bit accumulator (2-steps flush). #if VP8L_WRITER_BITS == 16 if (used + n_bits >= VP8L_WRITER_MAX_BITS) { // Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below. const int shift = VP8L_WRITER_MAX_BITS - used; @@ -310,38 +311,38 @@ assert(n_bits <= VP8L_WRITER_MAX_BITS); } #endif // If needed, make some room by flushing some bits out. while (used >= VP8L_WRITER_BITS) { - if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { - const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE; + if (bw->cur + VP8L_WRITER_BYTES > bw->end) { + const uint64_t extra_size = (bw->end - bw->buf) + MIN_EXTRA_SIZE; if (!CheckSizeOverflow(extra_size) || !VP8LBitWriterResize(bw, (size_t)extra_size)) { - bw->cur_ = bw->buf_; - bw->error_ = 1; + bw->cur = bw->buf; + bw->error = 1; return; } } - *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)lbits); - bw->cur_ += VP8L_WRITER_BYTES; + *(vp8l_wtype_t*)bw->cur = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)lbits); + bw->cur += VP8L_WRITER_BYTES; lbits >>= VP8L_WRITER_BITS; used -= VP8L_WRITER_BITS; } - bw->bits_ = lbits | ((vp8l_atype_t)bits << used); - bw->used_ = used + n_bits; + bw->bits = lbits | ((vp8l_atype_t)bits << used); + bw->used = used + n_bits; } } uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) { // flush leftover bits - if (VP8LBitWriterResize(bw, (bw->used_ + 7) >> 3)) { - while (bw->used_ > 0) { - *bw->cur_++ = (uint8_t)bw->bits_; - bw->bits_ >>= 8; - bw->used_ -= 8; + if (VP8LBitWriterResize(bw, (bw->used + 7) >> 3)) { + while (bw->used > 0) { + *bw->cur++ = (uint8_t)bw->bits; + bw->bits >>= 8; + bw->used -= 8; } - bw->used_ = 0; + bw->used = 0; } - return bw->buf_; + return bw->buf; } //------------------------------------------------------------------------------ diff --git a/media/libwebp/src/utils/color_cache_utils.h b/media/libwebp/src/utils/color_cache_utils.h --- a/media/libwebp/src/utils/color_cache_utils.h +++ b/media/libwebp/src/utils/color_cache_utils.h @@ -15,22 +15,23 @@ #ifndef WEBP_UTILS_COLOR_CACHE_UTILS_H_ #define WEBP_UTILS_COLOR_CACHE_UTILS_H_ #include +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" #include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif // Main color cache struct. typedef struct { - uint32_t* colors_; // color entries - int hash_shift_; // Hash shift: 32 - hash_bits_. - int hash_bits_; + uint32_t* colors; // color entries + int hash_shift; // Hash shift: 32 - 'hash_bits'. + int hash_bits; } VP8LColorCache; static const uint32_t kHashMul = 0x1e35a7bdu; static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE @@ -38,36 +39,36 @@ return (int)((argb * kHashMul) >> shift); } static WEBP_INLINE uint32_t VP8LColorCacheLookup( const VP8LColorCache* const cc, uint32_t key) { - assert((key >> cc->hash_bits_) == 0u); - return cc->colors_[key]; + assert((key >> cc->hash_bits) == 0u); + return cc->colors[key]; } static WEBP_INLINE void VP8LColorCacheSet(const VP8LColorCache* const cc, uint32_t key, uint32_t argb) { - assert((key >> cc->hash_bits_) == 0u); - cc->colors_[key] = argb; + assert((key >> cc->hash_bits) == 0u); + cc->colors[key] = argb; } static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc, uint32_t argb) { - const int key = VP8LHashPix(argb, cc->hash_shift_); - cc->colors_[key] = argb; + const int key = VP8LHashPix(argb, cc->hash_shift); + cc->colors[key] = argb; } static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc, uint32_t argb) { - return VP8LHashPix(argb, cc->hash_shift_); + return VP8LHashPix(argb, cc->hash_shift); } // Return the key if cc contains argb, and -1 otherwise. static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc, uint32_t argb) { - const int key = VP8LHashPix(argb, cc->hash_shift_); - return (cc->colors_[key] == argb) ? key : -1; + const int key = VP8LHashPix(argb, cc->hash_shift); + return (cc->colors[key] == argb) ? key : -1; } //------------------------------------------------------------------------------ // Initializes the color cache with 'hash_bits' bits for the keys. diff --git a/media/libwebp/src/utils/color_cache_utils.c b/media/libwebp/src/utils/color_cache_utils.c --- a/media/libwebp/src/utils/color_cache_utils.c +++ b/media/libwebp/src/utils/color_cache_utils.c @@ -12,38 +12,40 @@ // Author: Jyrki Alakuijala (jyrki@google.com) #include #include #include + #include "src/utils/color_cache_utils.h" +#include "src/webp/types.h" #include "src/utils/utils.h" //------------------------------------------------------------------------------ // VP8LColorCache. int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits) { const int hash_size = 1 << hash_bits; assert(color_cache != NULL); assert(hash_bits > 0); - color_cache->colors_ = (uint32_t*)WebPSafeCalloc( - (uint64_t)hash_size, sizeof(*color_cache->colors_)); - if (color_cache->colors_ == NULL) return 0; - color_cache->hash_shift_ = 32 - hash_bits; - color_cache->hash_bits_ = hash_bits; + color_cache->colors = (uint32_t*)WebPSafeCalloc( + (uint64_t)hash_size, sizeof(*color_cache->colors)); + if (color_cache->colors == NULL) return 0; + color_cache->hash_shift = 32 - hash_bits; + color_cache->hash_bits = hash_bits; return 1; } void VP8LColorCacheClear(VP8LColorCache* const color_cache) { if (color_cache != NULL) { - WebPSafeFree(color_cache->colors_); - color_cache->colors_ = NULL; + WebPSafeFree(color_cache->colors); + color_cache->colors = NULL; } } void VP8LColorCacheCopy(const VP8LColorCache* const src, VP8LColorCache* const dst) { assert(src != NULL); assert(dst != NULL); - assert(src->hash_bits_ == dst->hash_bits_); - memcpy(dst->colors_, src->colors_, - ((size_t)1u << dst->hash_bits_) * sizeof(*dst->colors_)); + assert(src->hash_bits == dst->hash_bits); + memcpy(dst->colors, src->colors, + ((size_t)1u << dst->hash_bits) * sizeof(*dst->colors)); } diff --git a/media/libwebp/src/utils/filters_utils.h b/media/libwebp/src/utils/filters_utils.h --- a/media/libwebp/src/utils/filters_utils.h +++ b/media/libwebp/src/utils/filters_utils.h @@ -12,12 +12,12 @@ // Author: Urvang (urvang@google.com) #ifndef WEBP_UTILS_FILTERS_UTILS_H_ #define WEBP_UTILS_FILTERS_UTILS_H_ +#include "src/dsp/dsp.h" #include "src/webp/types.h" -#include "src/dsp/dsp.h" #ifdef __cplusplus extern "C" { #endif diff --git a/media/libwebp/src/utils/filters_utils.c b/media/libwebp/src/utils/filters_utils.c --- a/media/libwebp/src/utils/filters_utils.c +++ b/media/libwebp/src/utils/filters_utils.c @@ -9,14 +9,17 @@ // // filter estimation // // Author: Urvang (urvang@google.com) -#include "src/utils/filters_utils.h" #include #include +#include "src/dsp/dsp.h" +#include "src/webp/types.h" +#include "src/utils/filters_utils.h" + // ----------------------------------------------------------------------------- // Quick estimate of a potentially interesting filter mode to try. #define SMAX 16 #define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX) diff --git a/media/libwebp/src/utils/huffman_encode_utils.h b/media/libwebp/src/utils/huffman_encode_utils.h --- a/media/libwebp/src/utils/huffman_encode_utils.h +++ b/media/libwebp/src/utils/huffman_encode_utils.h @@ -33,14 +33,14 @@ uint16_t* codes; // Symbol Codes. } HuffmanTreeCode; // Struct to represent the Huffman tree. typedef struct { - uint32_t total_count_; // Symbol frequency. - int value_; // Symbol value. - int pool_index_left_; // Index for the left sub-tree. - int pool_index_right_; // Index for the right sub-tree. + uint32_t total_count; // Symbol frequency. + int value; // Symbol value. + int pool_index_left; // Index for the left sub-tree. + int pool_index_right; // Index for the right sub-tree. } HuffmanTree; // Turn the Huffman tree into a token sequence. // Returns the number of tokens used. int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, diff --git a/media/libwebp/src/utils/huffman_encode_utils.c b/media/libwebp/src/utils/huffman_encode_utils.c --- a/media/libwebp/src/utils/huffman_encode_utils.c +++ b/media/libwebp/src/utils/huffman_encode_utils.c @@ -12,11 +12,13 @@ // Entropy encoding (Huffman) for webp lossless. #include #include #include + #include "src/utils/huffman_encode_utils.h" +#include "src/webp/types.h" #include "src/utils/utils.h" #include "src/webp/format_constants.h" // ----------------------------------------------------------------------------- // Util function to optimize the symbol map for RLE coding @@ -120,28 +122,28 @@ // A comparer function for two Huffman trees: sorts first by 'total count' // (more comes first), and then by 'value' (more comes first). static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) { const HuffmanTree* const t1 = (const HuffmanTree*)ptr1; const HuffmanTree* const t2 = (const HuffmanTree*)ptr2; - if (t1->total_count_ > t2->total_count_) { + if (t1->total_count > t2->total_count) { return -1; - } else if (t1->total_count_ < t2->total_count_) { + } else if (t1->total_count < t2->total_count) { return 1; } else { - assert(t1->value_ != t2->value_); - return (t1->value_ < t2->value_) ? -1 : 1; + assert(t1->value != t2->value); + return (t1->value < t2->value) ? -1 : 1; } } static void SetBitDepths(const HuffmanTree* const tree, const HuffmanTree* const pool, uint8_t* const bit_depths, int level) { - if (tree->pool_index_left_ >= 0) { - SetBitDepths(&pool[tree->pool_index_left_], pool, bit_depths, level + 1); - SetBitDepths(&pool[tree->pool_index_right_], pool, bit_depths, level + 1); + if (tree->pool_index_left >= 0) { + SetBitDepths(&pool[tree->pool_index_left], pool, bit_depths, level + 1); + SetBitDepths(&pool[tree->pool_index_right], pool, bit_depths, level + 1); } else { - bit_depths[tree->value_] = level; + bit_depths[tree->value] = level; } } // Create an optimal Huffman tree. // @@ -196,14 +198,14 @@ int j; for (j = 0; j < histogram_size; ++j) { if (histogram[j] != 0) { const uint32_t count = (histogram[j] < count_min) ? count_min : histogram[j]; - tree[idx].total_count_ = count; - tree[idx].value_ = j; - tree[idx].pool_index_left_ = -1; - tree[idx].pool_index_right_ = -1; + tree[idx].total_count = count; + tree[idx].value = j; + tree[idx].pool_index_left = -1; + tree[idx].pool_index_right = -1; ++idx; } } // Build the Huffman tree. @@ -213,33 +215,33 @@ int tree_pool_size = 0; while (tree_size > 1) { // Finish when we have only one root. uint32_t count; tree_pool[tree_pool_size++] = tree[tree_size - 1]; tree_pool[tree_pool_size++] = tree[tree_size - 2]; - count = tree_pool[tree_pool_size - 1].total_count_ + - tree_pool[tree_pool_size - 2].total_count_; + count = tree_pool[tree_pool_size - 1].total_count + + tree_pool[tree_pool_size - 2].total_count; tree_size -= 2; { // Search for the insertion point. int k; for (k = 0; k < tree_size; ++k) { - if (tree[k].total_count_ <= count) { + if (tree[k].total_count <= count) { break; } } memmove(tree + (k + 1), tree + k, (tree_size - k) * sizeof(*tree)); - tree[k].total_count_ = count; - tree[k].value_ = -1; + tree[k].total_count = count; + tree[k].value = -1; - tree[k].pool_index_left_ = tree_pool_size - 1; - tree[k].pool_index_right_ = tree_pool_size - 2; + tree[k].pool_index_left = tree_pool_size - 1; + tree[k].pool_index_right = tree_pool_size - 2; tree_size = tree_size + 1; } } SetBitDepths(&tree[0], tree_pool, bit_depths, 0); } else if (tree_size == 1) { // Trivial case: only one element. - bit_depths[tree[0].value_] = 1; + bit_depths[tree[0].value] = 1; } { // Test if this Huffman tree satisfies our 'tree_depth_limit' criteria. int max_depth = bit_depths[0]; diff --git a/media/libwebp/src/utils/huffman_utils.h b/media/libwebp/src/utils/huffman_utils.h --- a/media/libwebp/src/utils/huffman_utils.h +++ b/media/libwebp/src/utils/huffman_utils.h @@ -13,10 +13,11 @@ #ifndef WEBP_UTILS_HUFFMAN_UTILS_H_ #define WEBP_UTILS_HUFFMAN_UTILS_H_ #include + #include "src/webp/format_constants.h" #include "src/webp/types.h" #ifdef __cplusplus extern "C" { diff --git a/media/libwebp/src/utils/huffman_utils.c b/media/libwebp/src/utils/huffman_utils.c --- a/media/libwebp/src/utils/huffman_utils.c +++ b/media/libwebp/src/utils/huffman_utils.c @@ -12,13 +12,15 @@ // Author: Urvang Joshi (urvang@google.com) #include #include #include + #include "src/utils/huffman_utils.h" #include "src/utils/utils.h" #include "src/webp/format_constants.h" +#include "src/webp/types.h" // Huffman data read via DecodeImageStream is represented in two (red and green) // bytes. #define MAX_HTREE_GROUPS 0x10000 diff --git a/media/libwebp/src/utils/palette.c b/media/libwebp/src/utils/palette.c --- a/media/libwebp/src/utils/palette.c +++ b/media/libwebp/src/utils/palette.c @@ -13,16 +13,18 @@ #include "src/utils/palette.h" #include #include +#include #include "src/dsp/lossless_common.h" #include "src/utils/color_cache_utils.h" #include "src/utils/utils.h" #include "src/webp/encode.h" #include "src/webp/format_constants.h" +#include "src/webp/types.h" // ----------------------------------------------------------------------------- // Palette reordering for smaller sum of deltas (and for smaller storage). diff --git a/media/libwebp/src/utils/quant_levels_dec_utils.c b/media/libwebp/src/utils/quant_levels_dec_utils.c --- a/media/libwebp/src/utils/quant_levels_dec_utils.c +++ b/media/libwebp/src/utils/quant_levels_dec_utils.c @@ -17,10 +17,11 @@ #include "src/utils/quant_levels_dec_utils.h" #include // for memset #include "src/utils/utils.h" +#include "src/webp/types.h" // #define USE_DITHERING // uncomment to enable ordered dithering (not vital) #define FIX 16 // fix-point precision for averaging #define LFIX 2 // extra precision for look-up table @@ -41,34 +42,34 @@ #else #define DFIX 0 #endif typedef struct { - int width_, height_; // dimension - int stride_; // stride in bytes - int row_; // current input row being processed - uint8_t* src_; // input pointer - uint8_t* dst_; // output pointer + int width, height; // dimension + int stride; // stride in bytes + int row; // current input row being processed + uint8_t* src; // input pointer + uint8_t* dst; // output pointer - int radius_; // filter radius (=delay) - int scale_; // normalization factor, in FIX bits precision + int radius; // filter radius (=delay) + int scale; // normalization factor, in FIX bits precision - void* mem_; // all memory + void* mem; // all memory // various scratch buffers - uint16_t* start_; - uint16_t* cur_; - uint16_t* end_; - uint16_t* top_; - uint16_t* average_; + uint16_t* start; + uint16_t* cur; + uint16_t* end; + uint16_t* top; + uint16_t* average; // input levels distribution - int num_levels_; // number of quantized levels - int min_, max_; // min and max level values - int min_level_dist_; // smallest distance between two consecutive levels + int num_levels; // number of quantized levels + int min, max; // min and max level values + int min_level_dist; // smallest distance between two consecutive levels - int16_t* correction_; // size = 1 + 2*LUT_SIZE -> ~4k memory + int16_t* correction; // size = 1 + 2*LUT_SIZE -> ~4k memory } SmoothParams; //------------------------------------------------------------------------------ #define CLIP_8b_MASK (int)(~0U << (8 + DFIX)) @@ -77,15 +78,15 @@ } #undef CLIP_8b_MASK // vertical accumulation static void VFilter(SmoothParams* const p) { - const uint8_t* src = p->src_; - const int w = p->width_; - uint16_t* const cur = p->cur_; - const uint16_t* const top = p->top_; - uint16_t* const out = p->end_; + const uint8_t* src = p->src; + const int w = p->width; + uint16_t* const cur = p->cur; + const uint16_t* const top = p->top; + uint16_t* const out = p->end; uint16_t sum = 0; // all arithmetic is modulo 16bit int x; for (x = 0; x < w; ++x) { uint16_t new_value; @@ -93,28 +94,28 @@ new_value = top[x] + sum; out[x] = new_value - cur[x]; // vertical sum of 'r' pixels. cur[x] = new_value; } // move input pointers one row down - p->top_ = p->cur_; - p->cur_ += w; - if (p->cur_ == p->end_) p->cur_ = p->start_; // roll-over + p->top = p->cur; + p->cur += w; + if (p->cur == p->end) p->cur = p->start; // roll-over // We replicate edges, as it's somewhat easier as a boundary condition. // That's why we don't update the 'src' pointer on top/bottom area: - if (p->row_ >= 0 && p->row_ < p->height_ - 1) { - p->src_ += p->stride_; + if (p->row >= 0 && p->row < p->height - 1) { + p->src += p->stride; } } // horizontal accumulation. We use mirror replication of missing pixels, as it's // a little easier to implement (surprisingly). static void HFilter(SmoothParams* const p) { - const uint16_t* const in = p->end_; - uint16_t* const out = p->average_; - const uint32_t scale = p->scale_; - const int w = p->width_; - const int r = p->radius_; + const uint16_t* const in = p->end; + uint16_t* const out = p->average; + const uint32_t scale = p->scale; + const int w = p->width; + const int r = p->radius; int x; for (x = 0; x <= r; ++x) { // left mirroring const uint16_t delta = in[x + r - 1] + in[r - x]; out[x] = (delta * scale) >> FIX; @@ -130,30 +131,30 @@ } } // emit one filtered output row static void ApplyFilter(SmoothParams* const p) { - const uint16_t* const average = p->average_; - const int w = p->width_; - const int16_t* const correction = p->correction_; + const uint16_t* const average = p->average; + const int w = p->width; + const int16_t* const correction = p->correction; #if defined(USE_DITHERING) - const uint8_t* const dither = kOrderedDither[p->row_ % DSIZE]; + const uint8_t* const dither = kOrderedDither[p->row % DSIZE]; #endif - uint8_t* const dst = p->dst_; + uint8_t* const dst = p->dst; int x; for (x = 0; x < w; ++x) { const int v = dst[x]; - if (v < p->max_ && v > p->min_) { + if (v < p->max && v > p->min) { const int c = (v << DFIX) + correction[average[x] - (v << LFIX)]; #if defined(USE_DITHERING) dst[x] = clip_8b(c + dither[x % DSIZE]); #else dst[x] = clip_8b(c); #endif } } - p->dst_ += p->stride_; // advance output pointer + p->dst += p->stride; // advance output pointer } //------------------------------------------------------------------------------ // Initialize correction table @@ -181,32 +182,32 @@ } static void CountLevels(SmoothParams* const p) { int i, j, last_level; uint8_t used_levels[256] = { 0 }; - const uint8_t* data = p->src_; - p->min_ = 255; - p->max_ = 0; - for (j = 0; j < p->height_; ++j) { - for (i = 0; i < p->width_; ++i) { + const uint8_t* data = p->src; + p->min = 255; + p->max = 0; + for (j = 0; j < p->height; ++j) { + for (i = 0; i < p->width; ++i) { const int v = data[i]; - if (v < p->min_) p->min_ = v; - if (v > p->max_) p->max_ = v; + if (v < p->min) p->min = v; + if (v > p->max) p->max = v; used_levels[v] = 1; } - data += p->stride_; + data += p->stride; } // Compute the mininum distance between two non-zero levels. - p->min_level_dist_ = p->max_ - p->min_; + p->min_level_dist = p->max - p->min; last_level = -1; for (i = 0; i < 256; ++i) { if (used_levels[i]) { - ++p->num_levels_; + ++p->num_levels; if (last_level >= 0) { const int level_dist = i - last_level; - if (level_dist < p->min_level_dist_) { - p->min_level_dist_ = level_dist; + if (level_dist < p->min_level_dist) { + p->min_level_dist = level_dist; } } last_level = i; } } @@ -215,50 +216,50 @@ // Initialize all params. static int InitParams(uint8_t* const data, int width, int height, int stride, int radius, SmoothParams* const p) { const int R = 2 * radius + 1; // total size of the kernel - const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start_); - const size_t size_m = width * sizeof(*p->average_); - const size_t size_lut = (1 + 2 * LUT_SIZE) * sizeof(*p->correction_); + const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start); + const size_t size_m = width * sizeof(*p->average); + const size_t size_lut = (1 + 2 * LUT_SIZE) * sizeof(*p->correction); const size_t total_size = size_scratch_m + size_m + size_lut; uint8_t* mem = (uint8_t*)WebPSafeMalloc(1U, total_size); if (mem == NULL) return 0; - p->mem_ = (void*)mem; + p->mem = (void*)mem; - p->start_ = (uint16_t*)mem; - p->cur_ = p->start_; - p->end_ = p->start_ + R * width; - p->top_ = p->end_ - width; - memset(p->top_, 0, width * sizeof(*p->top_)); + p->start = (uint16_t*)mem; + p->cur = p->start; + p->end = p->start + R * width; + p->top = p->end - width; + memset(p->top, 0, width * sizeof(*p->top)); mem += size_scratch_m; - p->average_ = (uint16_t*)mem; + p->average = (uint16_t*)mem; mem += size_m; - p->width_ = width; - p->height_ = height; - p->stride_ = stride; - p->src_ = data; - p->dst_ = data; - p->radius_ = radius; - p->scale_ = (1 << (FIX + LFIX)) / (R * R); // normalization constant - p->row_ = -radius; + p->width = width; + p->height = height; + p->stride = stride; + p->src = data; + p->dst = data; + p->radius = radius; + p->scale = (1 << (FIX + LFIX)) / (R * R); // normalization constant + p->row = -radius; // analyze the input distribution so we can best-fit the threshold CountLevels(p); // correction table - p->correction_ = ((int16_t*)mem) + LUT_SIZE; - InitCorrectionLUT(p->correction_, p->min_level_dist_); + p->correction = ((int16_t*)mem) + LUT_SIZE; + InitCorrectionLUT(p->correction, p->min_level_dist); return 1; } static void CleanupParams(SmoothParams* const p) { - WebPSafeFree(p->mem_); + WebPSafeFree(p->mem); } int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride, int strength) { int radius = 4 * strength / 100; @@ -272,16 +273,16 @@ if (radius > 0) { SmoothParams p; memset(&p, 0, sizeof(p)); if (!InitParams(data, width, height, stride, radius, &p)) return 0; - if (p.num_levels_ > 2) { - for (; p.row_ < p.height_; ++p.row_) { + if (p.num_levels > 2) { + for (; p.row < p.height; ++p.row) { VFilter(&p); // accumulate average of input // Need to wait few rows in order to prime the filter, // before emitting some output. - if (p.row_ >= p.radius_) { + if (p.row >= p.radius) { HFilter(&p); ApplyFilter(&p); } } } diff --git a/media/libwebp/src/utils/quant_levels_utils.c b/media/libwebp/src/utils/quant_levels_utils.c --- a/media/libwebp/src/utils/quant_levels_utils.c +++ b/media/libwebp/src/utils/quant_levels_utils.c @@ -11,11 +11,13 @@ // Min and max values are preserved (usual 0 and 255 for alpha plane). // // Author: Skal (pascal.massimino@gmail.com) #include +#include +#include "src/webp/types.h" #include "src/utils/quant_levels_utils.h" #define NUM_SYMBOLS 256 #define MAX_ITER 6 // Maximum number of convergence steps. @@ -135,6 +137,5 @@ // Store sum of squared error if needed. if (sse != NULL) *sse = (uint64_t)err; return 1; } - diff --git a/media/libwebp/src/utils/random_utils.h b/media/libwebp/src/utils/random_utils.h --- a/media/libwebp/src/utils/random_utils.h +++ b/media/libwebp/src/utils/random_utils.h @@ -13,23 +13,24 @@ #ifndef WEBP_UTILS_RANDOM_UTILS_H_ #define WEBP_UTILS_RANDOM_UTILS_H_ #include + #include "src/webp/types.h" #ifdef __cplusplus extern "C" { #endif #define VP8_RANDOM_DITHER_FIX 8 // fixed-point precision for dithering #define VP8_RANDOM_TABLE_SIZE 55 typedef struct { - int index1_, index2_; - uint32_t tab_[VP8_RANDOM_TABLE_SIZE]; - int amp_; + int index1, index2; + uint32_t tab[VP8_RANDOM_TABLE_SIZE]; + int amp; } VP8Random; // Initializes random generator with an amplitude 'dithering' in range [0..1]. void VP8InitRandom(VP8Random* const rg, float dithering); @@ -38,24 +39,24 @@ // 'amp' is in VP8_RANDOM_DITHER_FIX fixed-point precision. static WEBP_INLINE int VP8RandomBits2(VP8Random* const rg, int num_bits, int amp) { int diff; assert(num_bits + VP8_RANDOM_DITHER_FIX <= 31); - diff = rg->tab_[rg->index1_] - rg->tab_[rg->index2_]; + diff = rg->tab[rg->index1] - rg->tab[rg->index2]; if (diff < 0) diff += (1u << 31); - rg->tab_[rg->index1_] = diff; - if (++rg->index1_ == VP8_RANDOM_TABLE_SIZE) rg->index1_ = 0; - if (++rg->index2_ == VP8_RANDOM_TABLE_SIZE) rg->index2_ = 0; + rg->tab[rg->index1] = diff; + if (++rg->index1 == VP8_RANDOM_TABLE_SIZE) rg->index1 = 0; + if (++rg->index2 == VP8_RANDOM_TABLE_SIZE) rg->index2 = 0; // sign-extend, 0-center diff = (int)((uint32_t)diff << 1) >> (32 - num_bits); diff = (diff * amp) >> VP8_RANDOM_DITHER_FIX; // restrict range diff += 1 << (num_bits - 1); // shift back to 0.5-center return diff; } static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) { - return VP8RandomBits2(rg, num_bits, rg->amp_); + return VP8RandomBits2(rg, num_bits, rg->amp); } #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libwebp/src/utils/random_utils.c b/media/libwebp/src/utils/random_utils.c --- a/media/libwebp/src/utils/random_utils.c +++ b/media/libwebp/src/utils/random_utils.c @@ -10,10 +10,12 @@ // Pseudo-random utilities // // Author: Skal (pascal.massimino@gmail.com) #include + +#include "src/webp/types.h" #include "src/utils/random_utils.h" //------------------------------------------------------------------------------ // 31b-range values @@ -29,15 +31,14 @@ 0x35db3b68, 0x2b081e83, 0x77ce6b95, 0x5181e5f0, 0x78853bbc, 0x009f9494, 0x27e5ed3c }; void VP8InitRandom(VP8Random* const rg, float dithering) { - memcpy(rg->tab_, kRandomTable, sizeof(rg->tab_)); - rg->index1_ = 0; - rg->index2_ = 31; - rg->amp_ = (dithering < 0.0) ? 0 - : (dithering > 1.0) ? (1 << VP8_RANDOM_DITHER_FIX) - : (uint32_t)((1 << VP8_RANDOM_DITHER_FIX) * dithering); + memcpy(rg->tab, kRandomTable, sizeof(rg->tab)); + rg->index1 = 0; + rg->index2 = 31; + rg->amp = (dithering < 0.0) ? 0 + : (dithering > 1.0) ? (1 << VP8_RANDOM_DITHER_FIX) + : (uint32_t)((1 << VP8_RANDOM_DITHER_FIX) * dithering); } //------------------------------------------------------------------------------ - diff --git a/media/libwebp/src/utils/rescaler_utils.c b/media/libwebp/src/utils/rescaler_utils.c --- a/media/libwebp/src/utils/rescaler_utils.c +++ b/media/libwebp/src/utils/rescaler_utils.c @@ -13,11 +13,13 @@ #include #include #include #include + #include "src/dsp/dsp.h" +#include "src/webp/types.h" #include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" //------------------------------------------------------------------------------ diff --git a/media/libwebp/src/utils/thread_utils.h b/media/libwebp/src/utils/thread_utils.h --- a/media/libwebp/src/utils/thread_utils.h +++ b/media/libwebp/src/utils/thread_utils.h @@ -35,12 +35,12 @@ // arguments (data1 and data2), and should return false in case of error. typedef int (*WebPWorkerHook)(void*, void*); // Synchronization object used to launch job in the worker thread typedef struct { - void* impl_; // platform-dependent implementation worker details - WebPWorkerStatus status_; + void* impl; // platform-dependent implementation worker details + WebPWorkerStatus status; WebPWorkerHook hook; // hook to call void* data1; // first argument passed to 'hook' void* data2; // second argument passed to 'hook' int had_error; // return value of the last call to 'hook' } WebPWorker; diff --git a/media/libwebp/src/utils/thread_utils.c b/media/libwebp/src/utils/thread_utils.c --- a/media/libwebp/src/utils/thread_utils.c +++ b/media/libwebp/src/utils/thread_utils.c @@ -11,10 +11,11 @@ // // Author: Skal (pascal.massimino@gmail.com) #include #include // for memset() + #include "src/utils/thread_utils.h" #include "src/utils/utils.h" #ifdef WEBP_USE_THREAD @@ -27,13 +28,13 @@ #if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater #define USE_WINDOWS_CONDITION_VARIABLE typedef CONDITION_VARIABLE pthread_cond_t; #else typedef struct { - HANDLE waiting_sem_; - HANDLE received_sem_; - HANDLE signal_event_; + HANDLE waiting_sem; + HANDLE received_sem; + HANDLE signal_event; } pthread_cond_t; #endif // _WIN32_WINNT >= 0x600 #ifndef WINAPI_FAMILY_PARTITION #define WINAPI_PARTITION_DESKTOP 1 @@ -49,13 +50,13 @@ #include #endif // _WIN32 typedef struct { - pthread_mutex_t mutex_; - pthread_cond_t condition_; - pthread_t thread_; + pthread_mutex_t mutex; + pthread_cond_t condition; + pthread_t thread; } WebPWorkerImpl; #if defined(_WIN32) //------------------------------------------------------------------------------ @@ -131,28 +132,28 @@ static int pthread_cond_destroy(pthread_cond_t* const condition) { int ok = 1; #ifdef USE_WINDOWS_CONDITION_VARIABLE (void)condition; #else - ok &= (CloseHandle(condition->waiting_sem_) != 0); - ok &= (CloseHandle(condition->received_sem_) != 0); - ok &= (CloseHandle(condition->signal_event_) != 0); + ok &= (CloseHandle(condition->waiting_sem) != 0); + ok &= (CloseHandle(condition->received_sem) != 0); + ok &= (CloseHandle(condition->signal_event) != 0); #endif return !ok; } static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) { (void)cond_attr; #ifdef USE_WINDOWS_CONDITION_VARIABLE InitializeConditionVariable(condition); #else - condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL); - condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL); - condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); - if (condition->waiting_sem_ == NULL || - condition->received_sem_ == NULL || - condition->signal_event_ == NULL) { + condition->waiting_sem = CreateSemaphore(NULL, 0, 1, NULL); + condition->received_sem = CreateSemaphore(NULL, 0, 1, NULL); + condition->signal_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (condition->waiting_sem == NULL || + condition->received_sem == NULL || + condition->signal_event == NULL) { pthread_cond_destroy(condition); return 1; } #endif return 0; @@ -161,16 +162,16 @@ static int pthread_cond_signal(pthread_cond_t* const condition) { int ok = 1; #ifdef USE_WINDOWS_CONDITION_VARIABLE WakeConditionVariable(condition); #else - if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { + if (WaitForSingleObject(condition->waiting_sem, 0) == WAIT_OBJECT_0) { // a thread is waiting in pthread_cond_wait: allow it to be notified - ok = SetEvent(condition->signal_event_); + ok = SetEvent(condition->signal_event); // wait until the event is consumed so the signaler cannot consume // the event via its own pthread_cond_wait. - ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != + ok &= (WaitForSingleObject(condition->received_sem, INFINITE) != WAIT_OBJECT_0); } #endif return !ok; } @@ -181,16 +182,16 @@ #ifdef USE_WINDOWS_CONDITION_VARIABLE ok = SleepConditionVariableCS(condition, mutex, INFINITE); #else // note that there is a consumer available so the signal isn't dropped in // pthread_cond_signal - if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) return 1; + if (!ReleaseSemaphore(condition->waiting_sem, 1, NULL)) return 1; // now unlock the mutex so pthread_cond_signal may be issued pthread_mutex_unlock(mutex); - ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == + ok = (WaitForSingleObject(condition->signal_event, INFINITE) == WAIT_OBJECT_0); - ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); + ok &= ReleaseSemaphore(condition->received_sem, 1, NULL); pthread_mutex_lock(mutex); #endif return !ok; } @@ -201,117 +202,117 @@ //------------------------------------------------------------------------------ static THREADFN ThreadLoop(void* ptr) { WebPWorker* const worker = (WebPWorker*)ptr; - WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl; int done = 0; while (!done) { - pthread_mutex_lock(&impl->mutex_); - while (worker->status_ == OK) { // wait in idling mode - pthread_cond_wait(&impl->condition_, &impl->mutex_); + pthread_mutex_lock(&impl->mutex); + while (worker->status == OK) { // wait in idling mode + pthread_cond_wait(&impl->condition, &impl->mutex); } - if (worker->status_ == WORK) { + if (worker->status == WORK) { WebPGetWorkerInterface()->Execute(worker); - worker->status_ = OK; - } else if (worker->status_ == NOT_OK) { // finish the worker + worker->status = OK; + } else if (worker->status == NOT_OK) { // finish the worker done = 1; } // signal to the main thread that we're done (for Sync()) // Note the associated mutex does not need to be held when signaling the // condition. Unlocking the mutex first may improve performance in some // implementations, avoiding the case where the waiting thread can't // reacquire the mutex when woken. - pthread_mutex_unlock(&impl->mutex_); - pthread_cond_signal(&impl->condition_); + pthread_mutex_unlock(&impl->mutex); + pthread_cond_signal(&impl->condition); } return THREAD_RETURN(NULL); // Thread is finished } // main thread state control static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) { // No-op when attempting to change state on a thread that didn't come up. - // Checking status_ without acquiring the lock first would result in a data + // Checking 'status' without acquiring the lock first would result in a data // race. - WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl; if (impl == NULL) return; - pthread_mutex_lock(&impl->mutex_); - if (worker->status_ >= OK) { + pthread_mutex_lock(&impl->mutex); + if (worker->status >= OK) { // wait for the worker to finish - while (worker->status_ != OK) { - pthread_cond_wait(&impl->condition_, &impl->mutex_); + while (worker->status != OK) { + pthread_cond_wait(&impl->condition, &impl->mutex); } // assign new status and release the working thread if needed if (new_status != OK) { - worker->status_ = new_status; + worker->status = new_status; // Note the associated mutex does not need to be held when signaling the // condition. Unlocking the mutex first may improve performance in some // implementations, avoiding the case where the waiting thread can't // reacquire the mutex when woken. - pthread_mutex_unlock(&impl->mutex_); - pthread_cond_signal(&impl->condition_); + pthread_mutex_unlock(&impl->mutex); + pthread_cond_signal(&impl->condition); return; } } - pthread_mutex_unlock(&impl->mutex_); + pthread_mutex_unlock(&impl->mutex); } #endif // WEBP_USE_THREAD //------------------------------------------------------------------------------ static void Init(WebPWorker* const worker) { memset(worker, 0, sizeof(*worker)); - worker->status_ = NOT_OK; + worker->status = NOT_OK; } static int Sync(WebPWorker* const worker) { #ifdef WEBP_USE_THREAD ChangeState(worker, OK); #endif - assert(worker->status_ <= OK); + assert(worker->status <= OK); return !worker->had_error; } static int Reset(WebPWorker* const worker) { int ok = 1; worker->had_error = 0; - if (worker->status_ < OK) { + if (worker->status < OK) { #ifdef WEBP_USE_THREAD WebPWorkerImpl* const impl = (WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(WebPWorkerImpl)); - worker->impl_ = (void*)impl; - if (worker->impl_ == NULL) { + worker->impl = (void*)impl; + if (worker->impl == NULL) { return 0; } - if (pthread_mutex_init(&impl->mutex_, NULL)) { + if (pthread_mutex_init(&impl->mutex, NULL)) { goto Error; } - if (pthread_cond_init(&impl->condition_, NULL)) { - pthread_mutex_destroy(&impl->mutex_); + if (pthread_cond_init(&impl->condition, NULL)) { + pthread_mutex_destroy(&impl->mutex); goto Error; } - pthread_mutex_lock(&impl->mutex_); - ok = !pthread_create(&impl->thread_, NULL, ThreadLoop, worker); - if (ok) worker->status_ = OK; - pthread_mutex_unlock(&impl->mutex_); + pthread_mutex_lock(&impl->mutex); + ok = !pthread_create(&impl->thread, NULL, ThreadLoop, worker); + if (ok) worker->status = OK; + pthread_mutex_unlock(&impl->mutex); if (!ok) { - pthread_mutex_destroy(&impl->mutex_); - pthread_cond_destroy(&impl->condition_); + pthread_mutex_destroy(&impl->mutex); + pthread_cond_destroy(&impl->condition); Error: WebPSafeFree(impl); - worker->impl_ = NULL; + worker->impl = NULL; return 0; } #else - worker->status_ = OK; + worker->status = OK; #endif - } else if (worker->status_ > OK) { + } else if (worker->status > OK) { ok = Sync(worker); } - assert(!ok || (worker->status_ == OK)); + assert(!ok || (worker->status == OK)); return ok; } static void Execute(WebPWorker* const worker) { if (worker->hook != NULL) { @@ -327,24 +328,24 @@ #endif } static void End(WebPWorker* const worker) { #ifdef WEBP_USE_THREAD - if (worker->impl_ != NULL) { - WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + if (worker->impl != NULL) { + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl; ChangeState(worker, NOT_OK); - pthread_join(impl->thread_, NULL); - pthread_mutex_destroy(&impl->mutex_); - pthread_cond_destroy(&impl->condition_); + pthread_join(impl->thread, NULL); + pthread_mutex_destroy(&impl->mutex); + pthread_cond_destroy(&impl->condition); WebPSafeFree(impl); - worker->impl_ = NULL; + worker->impl = NULL; } #else - worker->status_ = NOT_OK; - assert(worker->impl_ == NULL); + worker->status = NOT_OK; + assert(worker->impl == NULL); #endif - assert(worker->status_ == NOT_OK); + assert(worker->status == NOT_OK); } //------------------------------------------------------------------------------ static WebPWorkerInterface g_worker_interface = { diff --git a/media/libwebp/src/utils/utils.c b/media/libwebp/src/utils/utils.c --- a/media/libwebp/src/utils/utils.c +++ b/media/libwebp/src/utils/utils.c @@ -11,13 +11,15 @@ // // Author: Skal (pascal.massimino@gmail.com) #include "src/utils/utils.h" +#include #include #include // for memcpy() +#include "src/webp/types.h" #include "src/utils/palette.h" #include "src/webp/encode.h" // If PRINT_MEM_INFO is defined, extra info (like total memory used, number of // alloc/free etc) is printed. For debugging/tuning purpose only (it's slow, @@ -58,13 +60,13 @@ static int num_free_calls = 0; static int countdown_to_fail = 0; // 0 = off typedef struct MemBlock MemBlock; struct MemBlock { - void* ptr_; - size_t size_; - MemBlock* next_; + void* ptr; + size_t size; + MemBlock* next; }; static MemBlock* all_blocks = NULL; static size_t total_mem = 0; static size_t total_mem_allocated = 0; @@ -81,11 +83,11 @@ fprintf(stderr, "total_mem: %u\n", (uint32_t)total_mem); fprintf(stderr, "total_mem allocated: %u\n", (uint32_t)total_mem_allocated); fprintf(stderr, "high-water mark: %u\n", (uint32_t)high_water_mark); while (all_blocks != NULL) { MemBlock* b = all_blocks; - all_blocks = b->next_; + all_blocks = b->next; free(b); } } static void Increment(int* const v) { @@ -119,14 +121,14 @@ static void AddMem(void* ptr, size_t size) { if (ptr != NULL) { MemBlock* const b = (MemBlock*)malloc(sizeof(*b)); if (b == NULL) abort(); - b->next_ = all_blocks; + b->next = all_blocks; all_blocks = b; - b->ptr_ = ptr; - b->size_ = size; + b->ptr = ptr; + b->size = size; total_mem += size; total_mem_allocated += size; #if defined(PRINT_MEM_TRAFFIC) #if defined(MALLOC_FAIL_AT) fprintf(stderr, "fail-count: %5d [mem=%u]\n", @@ -141,22 +143,22 @@ static void SubMem(void* ptr) { if (ptr != NULL) { MemBlock** b = &all_blocks; // Inefficient search, but that's just for debugging. - while (*b != NULL && (*b)->ptr_ != ptr) b = &(*b)->next_; + while (*b != NULL && (*b)->ptr != ptr) b = &(*b)->next; if (*b == NULL) { fprintf(stderr, "Invalid pointer free! (%p)\n", ptr); abort(); } { MemBlock* const block = *b; - *b = block->next_; - total_mem -= block->size_; + *b = block->next; + total_mem -= block->size; #if defined(PRINT_MEM_TRAFFIC) fprintf(stderr, "Mem: %u (-%u)\n", - (uint32_t)total_mem, (uint32_t)block->size_); + (uint32_t)total_mem, (uint32_t)block->size); #endif free(block); } } } diff --git a/media/libwebp/src/webp/decode.h b/media/libwebp/src/webp/decode.h --- a/media/libwebp/src/webp/decode.h +++ b/media/libwebp/src/webp/decode.h @@ -12,17 +12,19 @@ // Author: Skal (pascal.massimino@gmail.com) #ifndef WEBP_WEBP_DECODE_H_ #define WEBP_WEBP_DECODE_H_ +#include + #include "./types.h" #ifdef __cplusplus extern "C" { #endif -#define WEBP_DECODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b) +#define WEBP_DECODER_ABI_VERSION 0x0210 // MAJOR(8b) + MINOR(8b) // Note: forward declaring enumerations is not allowed in (strict) C and C++, // the types are left here for reference. // typedef enum VP8StatusCode VP8StatusCode; // typedef enum WEBP_CSP_MODE WEBP_CSP_MODE; @@ -449,11 +451,13 @@ int use_cropping; // if true, cropping is applied _first_ int crop_left, crop_top; // top-left position for cropping. // Will be snapped to even values. int crop_width, crop_height; // dimension of the cropping area int use_scaling; // if true, scaling is applied _afterward_ - int scaled_width, scaled_height; // final resolution + int scaled_width, scaled_height; // final resolution. if one is 0, it is + // guessed from the other one to keep the + // original ratio. int use_threads; // if true, use multi-threaded decoding int dithering_strength; // dithering strength (0=Off, 100=full) int flip; // if true, flip output vertically int alpha_dithering_strength; // alpha dithering strength in [0..100] @@ -477,10 +481,15 @@ WEBP_NODISCARD static WEBP_INLINE int WebPInitDecoderConfig( WebPDecoderConfig* config) { return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION); } +// Returns true if 'config' is non-NULL and all configuration parameters are +// within their valid ranges. +WEBP_NODISCARD WEBP_EXTERN int WebPValidateDecoderConfig( + const WebPDecoderConfig* config); + // Instantiate a new incremental decoder object with the requested // configuration. The bitstream can be passed using 'data' and 'data_size' // parameter, in which case the features will be parsed and stored into // config->input. Otherwise, 'data' can be NULL and no parsing will occur. // Note that 'config' can be NULL too, in which case a default configuration diff --git a/media/libwebp/src/webp/demux.h b/media/libwebp/src/webp/demux.h --- a/media/libwebp/src/webp/demux.h +++ b/media/libwebp/src/webp/demux.h @@ -46,10 +46,12 @@ */ #ifndef WEBP_WEBP_DEMUX_H_ #define WEBP_WEBP_DEMUX_H_ +#include + #include "./decode.h" // for WEBP_CSP_MODE #include "./mux_types.h" #include "./types.h" #ifdef __cplusplus diff --git a/media/libwebp/src/webp/encode.h b/media/libwebp/src/webp/encode.h --- a/media/libwebp/src/webp/encode.h +++ b/media/libwebp/src/webp/encode.h @@ -12,10 +12,12 @@ // Author: Skal (pascal.massimino@gmail.com) #ifndef WEBP_WEBP_ENCODE_H_ #define WEBP_WEBP_ENCODE_H_ +#include + #include "./types.h" #ifdef __cplusplus extern "C" { #endif diff --git a/media/libwebp/src/webp/mux_types.h b/media/libwebp/src/webp/mux_types.h --- a/media/libwebp/src/webp/mux_types.h +++ b/media/libwebp/src/webp/mux_types.h @@ -13,10 +13,11 @@ #ifndef WEBP_WEBP_MUX_TYPES_H_ #define WEBP_WEBP_MUX_TYPES_H_ #include // memset() + #include "./types.h" #ifdef __cplusplus extern "C" { #endif diff --git a/media/libwebp/src/webp/types.h b/media/libwebp/src/webp/types.h --- a/media/libwebp/src/webp/types.h +++ b/media/libwebp/src/webp/types.h @@ -12,14 +12,14 @@ // Author: Skal (pascal.massimino@gmail.com) #ifndef WEBP_WEBP_TYPES_H_ #define WEBP_WEBP_TYPES_H_ -#include // for size_t +#include // IWYU pragma: export for size_t #ifndef _MSC_VER -#include +#include // IWYU pragma: export #if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) #define WEBP_INLINE inline #else #define WEBP_INLINE