dec/dsp/enc/utils,cosmetics: rm struct member '_' suffix

This is a follow up to:
ee8e8c62 Fix member naming for VP8LHistogram

This better matches Google style and clears some clang-tidy warnings.

This is the final change in this set. It is rather large due to the
shared dependencies between dec/enc.

Change-Id: I89de06b5653ae0bb627f904fa6060334831f7e3b
This commit is contained in:
James Zern 2025-04-11 12:48:18 -07:00
parent ed7cd6a7f3
commit ad52d5fc7e
66 changed files with 3054 additions and 3053 deletions

View File

@ -76,7 +76,7 @@ int VP8EstimateQuality(const uint8_t* const data, size_t size) {
GET_BIT(2); // colorspace + clamp type
// Segment header
if (GET_BIT(1)) { // use_segment_
if (GET_BIT(1)) { // use_segment
int s;
const int update_map = GET_BIT(1);
if (GET_BIT(1)) { // update data

View File

@ -34,8 +34,8 @@ WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {
// 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);
}
}
@ -54,28 +54,28 @@ WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
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;
}
@ -96,11 +96,11 @@ WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
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);
}
@ -113,32 +113,32 @@ WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
// 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;
}
@ -148,25 +148,25 @@ WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,
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;
}
//------------------------------------------------------------------------------
@ -184,46 +184,46 @@ WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
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;
}
}
@ -231,7 +231,7 @@ WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
}
// Return a pointer to the current decoded row.
return dec->alpha_plane_ + row * width;
return dec->alpha_plane + row * width;
Error:
WebPDeallocateAlphaMemory(dec);

View File

@ -25,24 +25,24 @@ 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);
//------------------------------------------------------------------------------

View File

@ -72,11 +72,11 @@ 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) {
@ -99,8 +99,8 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
// 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.
@ -115,9 +115,9 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
{
// 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) {
@ -127,11 +127,11 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
// 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));
@ -143,11 +143,11 @@ static void ReconstructRow(const VP8Decoder* const dec,
// 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) {
@ -157,8 +157,8 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
{
// 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);
@ -166,25 +166,25 @@ static void ReconstructRow(const VP8Decoder* const dec,
}
// 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);
}
}
}
@ -201,40 +201,40 @@ static void ReconstructRow(const VP8Decoder* const dec,
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);
}
@ -242,7 +242,7 @@ static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
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);
}
@ -252,9 +252,9 @@ static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
// 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);
}
}
@ -263,51 +263,51 @@ static void FilterRow(const VP8Decoder* const dec) {
// 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;
}
}
}
@ -321,7 +321,7 @@ static void PrecomputeFilterStrengths(VP8Decoder* const dec) {
#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
};
@ -336,24 +336,24 @@ void VP8InitDithering(const WebPDecoderOptions* const options,
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;
}
}
}
@ -370,17 +370,17 @@ static void Dither8x8(VP8Random* const rg, uint8_t* dst, int bps, int amp) {
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);
}
}
}
@ -403,29 +403,29 @@ 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);
}
@ -438,9 +438,9 @@ static int FinishRow(void* arg1, void* arg2) {
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) {
@ -449,9 +449,9 @@ static int FinishRow(void* arg1, void* arg2) {
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,
@ -462,9 +462,9 @@ static int FinishRow(void* arg1, void* arg2) {
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;
}
@ -483,11 +483,11 @@ static int FinishRow(void* arg1, void* arg2) {
}
}
// 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);
}
}
@ -500,43 +500,43 @@ static int FinishRow(void* arg1, void* arg2) {
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;
}
}
}
@ -551,12 +551,12 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const 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.
@ -569,29 +569,29 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
// 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);
@ -600,8 +600,8 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
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) {
@ -639,20 +639,20 @@ int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
// 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;
}
@ -680,25 +680,25 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
// 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
@ -706,77 +706,77 @@ static int AllocateMemory(VP8Decoder* const dec) {
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;
}
@ -784,16 +784,16 @@ static int AllocateMemory(VP8Decoder* const dec) {
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.

View File

@ -54,134 +54,134 @@ typedef enum {
// 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;
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;
@ -190,85 +190,85 @@ WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec,
(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;
}
@ -278,43 +278,43 @@ WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
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;
@ -329,32 +329,32 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
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;
@ -362,61 +362,61 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
// 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
@ -426,69 +426,69 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
}
// 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);
}
}
@ -496,9 +496,9 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
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
@ -510,10 +510,10 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
}
// 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);
}
@ -526,81 +526,81 @@ static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
}
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;
@ -617,29 +617,29 @@ WEBP_NODISCARD static WebPIDecoder* NewDecoder(
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;
}
@ -674,27 +674,27 @@ WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
}
// 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);
}
@ -717,11 +717,11 @@ WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
}
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;
}
@ -751,20 +751,20 @@ WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
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;
}
@ -781,10 +781,10 @@ WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
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;
@ -801,7 +801,7 @@ VP8StatusCode WebPIAppend(WebPIDecoder* idec,
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
@ -822,7 +822,7 @@ VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
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
@ -835,16 +835,16 @@ VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
//------------------------------------------------------------------------------
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,
@ -855,7 +855,7 @@ const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
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;
@ -871,7 +871,7 @@ WEBP_NODISCARD uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
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;
@ -889,7 +889,7 @@ WEBP_NODISCARD uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
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;
@ -907,14 +907,14 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
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;
}

View File

@ -259,7 +259,7 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
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);

View File

@ -60,7 +60,7 @@ static const uint16_t kAcTable[128] = {
// 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;
@ -73,40 +73,40 @@ void VP8ParseQuant(VP8Decoder* const dec) {
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
}
}
}

View File

@ -284,40 +284,40 @@ static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
};
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];
@ -354,17 +354,17 @@ static void ParseIntraMode(VP8BitReader* const br,
}
}
// 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;
}
//------------------------------------------------------------------------------
@ -514,7 +514,7 @@ static const uint8_t kBands[16 + 1] = {
};
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) {
@ -524,16 +524,16 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
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");
}
}

View File

@ -40,8 +40,8 @@ static void InitGetCoeffs(void);
// 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) {
@ -58,9 +58,9 @@ 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;
@ -68,13 +68,13 @@ VP8Decoder* VP8New(void) {
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) {
@ -87,12 +87,12 @@ void VP8Delete(VP8Decoder* const dec) {
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;
}
@ -151,11 +151,11 @@ int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
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
@ -163,32 +163,32 @@ 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
@ -202,7 +202,7 @@ static int ParseSegmentHeader(VP8BitReader* br,
// 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;
@ -210,8 +210,8 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
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;
@ -221,42 +221,42 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
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
@ -286,16 +286,16 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
// 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.");
}
@ -303,8 +303,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
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,
@ -314,20 +314,20 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
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;
@ -342,27 +342,27 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
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");
}
@ -380,17 +380,17 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
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;
}
@ -443,17 +443,17 @@ static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
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;
@ -473,17 +473,17 @@ static int GetCoeffsFast(VP8BitReader* const br,
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;
@ -516,12 +516,12 @@ static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) {
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;
@ -530,11 +530,11 @@ static int ParseResiduals(VP8Decoder* const dec,
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
@ -549,14 +549,14 @@ static int ParseResiduals(VP8Decoder* const dec,
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);
@ -571,13 +571,13 @@ static int ParseResiduals(VP8Decoder* const dec,
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);
@ -591,16 +591,16 @@ static int ParseResiduals(VP8Decoder* const dec,
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
}
@ -609,50 +609,50 @@ static int ParseResiduals(VP8Decoder* const dec,
// 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.");
@ -665,8 +665,8 @@ static int ParseFrame(VP8Decoder* const dec, VP8Io* 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;
@ -683,12 +683,12 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
"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);
@ -708,7 +708,7 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
return 0;
}
dec->ready_ = 0;
dec->ready = 0;
return ok;
}
@ -716,13 +716,13 @@ 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;
}
//------------------------------------------------------------------------------

View File

@ -69,85 +69,85 @@ extern "C" {
// 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
@ -155,21 +155,21 @@ typedef struct {
// 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.
@ -181,89 +181,89 @@ typedef struct {
// 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)
};
//------------------------------------------------------------------------------

View File

@ -104,8 +104,8 @@ static const uint16_t kTableSize[12] = {
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;
}
@ -131,7 +131,7 @@ static int ReadImageInfo(VP8LBitReader* const br,
*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,
@ -196,12 +196,12 @@ static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
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;
}
@ -215,11 +215,11 @@ static WEBP_INLINE int ReadPackedSymbols(const HTreeGroup* group,
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;
}
@ -258,7 +258,7 @@ 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;
@ -287,7 +287,7 @@ static int ReadHuffmanCodeLengths(
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;
@ -321,7 +321,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
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));
@ -351,7 +351,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
code_lengths);
}
ok = ok && !br->eos_;
ok = ok && !br->eos;
if (ok) {
size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS,
code_lengths, alphabet_size);
@ -365,11 +365,11 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
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;
@ -390,7 +390,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
&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;
@ -427,7 +427,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
}
if (br->eos_) goto Error;
if (br->eos) goto Error;
if (!ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups,
num_htree_groups_max, mapping, dec,
@ -437,9 +437,9 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
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);
@ -621,7 +621,7 @@ static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
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) {
@ -696,7 +696,7 @@ static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
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;
}
@ -706,7 +706,7 @@ static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
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);
@ -725,9 +725,9 @@ static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec,
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;
}
@ -774,10 +774,10 @@ static WEBP_INLINE int GetMetaIndex(
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;
}
//------------------------------------------------------------------------------
@ -788,15 +788,15 @@ 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;
}
@ -809,26 +809,26 @@ static void ApplyInverseTransforms(VP8LDecoder* const dec,
// 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 + (ptrdiff_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 ?
@ -837,31 +837,31 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
#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;
@ -872,43 +872,43 @@ static int Is8bOptimizable(const VP8LMetadata* const hdr) {
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;
}
//------------------------------------------------------------------------------
@ -1036,22 +1036,22 @@ static WEBP_INLINE void CopyBlock32b(uint32_t* const dst,
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) {
@ -1101,37 +1101,37 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
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);
}
}
@ -1139,23 +1139,23 @@ static void RestoreState(VP8LDecoder* const dec) {
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) {
@ -1261,29 +1261,29 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
}
}
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;
}
@ -1297,24 +1297,24 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
// 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;
@ -1322,8 +1322,8 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
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;
}
@ -1331,34 +1331,34 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
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;
@ -1366,10 +1366,10 @@ static int ReadTransform(int* const xsize, int const* ysize,
: (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);
}
@ -1396,11 +1396,11 @@ static void InitMetadata(VP8LMetadata* const hdr) {
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);
}
@ -1410,8 +1410,8 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
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.
@ -1419,24 +1419,24 @@ VP8LDecoder* VP8LNew(void) {
}
// 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) {
@ -1447,13 +1447,13 @@ void VP8LDelete(VP8LDecoder* const 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,
@ -1463,8 +1463,8 @@ static int DecodeImageStream(int xsize, int ysize,
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;
@ -1495,18 +1495,18 @@ static int DecodeImageStream(int xsize, int ysize,
// 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;
}
@ -1522,7 +1522,7 @@ static int DecodeImageStream(int xsize, int ysize,
// 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) {
@ -1537,16 +1537,16 @@ static int DecodeImageStream(int xsize, int ysize,
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;
@ -1555,21 +1555,21 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
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;
@ -1579,31 +1579,31 @@ static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
// 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,
@ -1615,17 +1615,17 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
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;
}
@ -1633,21 +1633,21 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
// 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:
@ -1656,21 +1656,21 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
}
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);
}
@ -1684,14 +1684,14 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
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;
@ -1703,7 +1703,7 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
Error:
VP8LClear(dec);
assert(dec->status_ != VP8_STATUS_OK);
assert(dec->status != VP8_STATUS_OK);
return 0;
}
@ -1713,19 +1713,19 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
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);
@ -1742,40 +1742,40 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
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;
}

View File

@ -34,58 +34,58 @@ typedef enum {
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.
@ -118,7 +118,7 @@ WEBP_NODISCARD VP8LDecoder* VP8LNew(void);
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.

View File

@ -477,23 +477,23 @@ WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
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;
}
}
}
@ -504,14 +504,14 @@ WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
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;
}
}
}

View File

@ -688,11 +688,11 @@ static int QuantizeBlock_C(int16_t in[16], int16_t out[16],
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;

View File

@ -193,11 +193,11 @@ static int QuantizeBlock_MIPS32(int16_t in[16], int16_t out[16],
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)

View File

@ -1296,11 +1296,11 @@ static int QuantizeBlock_MIPSdspR2(int16_t in[16], int16_t out[16],
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)

View File

@ -845,7 +845,7 @@ static int QuantizeBlock_MSA(int16_t in[16], int16_t out[16],
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);
@ -853,10 +853,10 @@ static int QuantizeBlock_MSA(int16_t in[16], int16_t out[16],
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);
@ -868,7 +868,7 @@ static int QuantizeBlock_MSA(int16_t in[16], int16_t out[16],
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);
@ -876,7 +876,7 @@ static int QuantizeBlock_MSA(int16_t in[16], int16_t out[16],
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);

View File

@ -841,11 +841,11 @@ static int SSE4x4_NEON(const uint8_t* WEBP_RESTRICT a,
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)

View File

@ -1410,10 +1410,10 @@ static WEBP_INLINE int DoQuantizeBlock_SSE2(
// 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);
@ -1446,10 +1446,10 @@ static WEBP_INLINE int DoQuantizeBlock_SSE2(
__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);
@ -1512,7 +1512,7 @@ static WEBP_INLINE int DoQuantizeBlock_SSE2(
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],
@ -1523,7 +1523,7 @@ static int QuantizeBlockWHT_SSE2(int16_t in[16], int16_t out[16],
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;

View File

@ -211,10 +211,10 @@ static WEBP_INLINE int DoQuantizeBlock_SSE41(int16_t in[16], int16_t out[16],
// 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);
@ -241,10 +241,10 @@ static WEBP_INLINE int DoQuantizeBlock_SSE41(int16_t in[16], int16_t out[16],
__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);
@ -305,7 +305,7 @@ static WEBP_INLINE int DoQuantizeBlock_SSE41(int16_t in[16], int16_t out[16],
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],
@ -316,7 +316,7 @@ static int QuantizeBlockWHT_SSE41(int16_t in[16], int16_t out[16],
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;

View File

@ -221,7 +221,7 @@ GENERATE_PREDICTOR_ADD(VP8LPredictor13_C, PredictorAdd13_C)
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);
@ -232,11 +232,11 @@ static void PredictorInverseTransform_C(const VP8LTransform* const transform,
{
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;
@ -284,9 +284,9 @@ static WEBP_INLINE int ColorTransformDelta(int8_t color_pred,
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,
@ -299,10 +299,10 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
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);
}
@ -312,15 +312,15 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
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;
@ -362,11 +362,11 @@ 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) { \
@ -397,16 +397,16 @@ COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha_C, ,
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,
@ -417,15 +417,15 @@ void VP8LInverseTransform(const VP8LTransform* const 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);

View File

@ -74,9 +74,9 @@ 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,

View File

@ -362,9 +362,9 @@ static void TransformColorInverse_AVX2(const VP8LMultipliers* const m,
// 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_));
_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(

View File

@ -137,8 +137,8 @@ static WEBP_INLINE void VP8LPrefixEncodeNoLUT(int distance, int* const code,
#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.
@ -148,8 +148,8 @@ 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);
}
@ -160,8 +160,8 @@ static WEBP_INLINE void VP8LPrefixEncode(int distance, int* const code,
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);

View File

@ -482,10 +482,10 @@ void VP8LTransformColor_C(const VP8LMultipliers* WEBP_RESTRICT const m,
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);
}

View File

@ -58,8 +58,8 @@ 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);
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,

View File

@ -245,7 +245,7 @@ static void GetCombinedEntropyUnrefined_MIPS32(
// 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" \

View File

@ -83,9 +83,9 @@ static void TransformColor_MIPSdspR2(
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"
@ -152,10 +152,10 @@ static void TransformColor_MIPSdspR2(
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);
}

View File

@ -51,9 +51,9 @@
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,

View File

@ -78,15 +78,15 @@ static void TransformColor_NEON(const VP8LMultipliers* WEBP_RESTRICT const m,
// 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

View File

@ -57,9 +57,9 @@ static void SubtractGreenFromBlueAndRed_SSE2(uint32_t* argb_data,
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;

View File

@ -299,9 +299,9 @@ static void TransformColorInverse_MIPSdspR2(const VP8LMultipliers* const m,
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"

View File

@ -290,9 +290,9 @@ 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,

View File

@ -551,15 +551,15 @@ static void TransformColorInverse_NEON(const VP8LMultipliers* const m,
// 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

View File

@ -466,8 +466,8 @@ static void TransformColorInverse_SSE2(const VP8LMultipliers* const m,
#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

View File

@ -27,9 +27,9 @@ static void TransformColorInverse_SSE41(const VP8LMultipliers* const m,
// 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,

View File

@ -86,7 +86,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
ok = VP8LEncodeStream(&config, &picture, bw);
WebPPictureFree(&picture);
ok = ok && !bw->error_;
ok = ok && !bw->error;
if (!ok) {
VP8LBitWriterWipeOut(bw);
return 0;
@ -138,7 +138,7 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
!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;
@ -173,7 +173,7 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
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;
}
@ -298,7 +298,7 @@ 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;
@ -357,7 +357,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
#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
}
@ -371,7 +371,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
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]
@ -387,19 +387,19 @@ static int CompressAlphaJob(void* arg1, void* unused) {
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;
@ -408,12 +408,12 @@ void VP8EncInitAlpha(VP8Encoder* const enc) {
}
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;
@ -425,27 +425,27 @@ int VP8EncStartAlpha(VP8Encoder* const enc) {
}
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;
}

View File

@ -27,8 +27,8 @@
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
@ -37,17 +37,17 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
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;
@ -59,15 +59,15 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
}
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;
@ -76,7 +76,7 @@ static WEBP_INLINE int clip(int v, int m, int M) {
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;
@ -91,8 +91,8 @@ static void SetSegmentAlphas(VP8Encoder* const enc,
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);
}
}
@ -131,11 +131,11 @@ static void InitHistogram(VP8Histogram* const histo) {
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];
@ -200,15 +200,15 @@ static void AssignSegments(VP8Encoder* const enc,
}
// 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);
}
@ -220,7 +220,7 @@ static void AssignSegments(VP8Encoder* const enc,
// 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
@ -239,8 +239,8 @@ static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
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)) {
@ -255,12 +255,12 @@ static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
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];
@ -287,8 +287,8 @@ static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
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)) {
@ -307,14 +307,14 @@ static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
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);
@ -325,7 +325,7 @@ static void MBAnalyze(VP8EncIterator* const it,
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)
@ -333,11 +333,11 @@ static void MBAnalyze(VP8EncIterator* const it,
}
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;
}
//------------------------------------------------------------------------------
@ -352,16 +352,16 @@ static void DefaultMBInfo(VP8MBInfo* const mb) {
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
@ -409,7 +409,7 @@ static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
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;
@ -422,17 +422,17 @@ static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
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
@ -467,15 +467,15 @@ int VP8EncAnalyze(VP8Encoder* const enc) {
}
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;

View File

@ -33,11 +33,11 @@ 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(
@ -74,15 +74,15 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
ConvertPopulationCountTableToBitEstimates(
VP8LHistogramNumCodes(histo->palette_code_bits), histo->literal,
m->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:
@ -92,21 +92,21 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
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);
}
@ -114,7 +114,7 @@ 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);
}
@ -144,84 +144,84 @@ static WEBP_INLINE void AddSingleLiteralWithCostModel(
// 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
@ -232,16 +232,16 @@ static void DeleteIntervalList(CostManager* const manager,
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);
}
@ -252,25 +252,25 @@ static int CostManagerInit(CostManager* const manager,
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;
}
}
@ -278,46 +278,46 @@ static int CostManagerInit(CostManager* const manager,
// 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;
}
@ -329,9 +329,9 @@ static WEBP_INLINE void UpdateCost(CostManager* const manager, int i,
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;
}
}
@ -349,12 +349,12 @@ 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.
@ -362,15 +362,15 @@ 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
@ -379,17 +379,17 @@ static WEBP_INLINE void PopInterval(CostManager* const manager,
// 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;
}
@ -397,31 +397,31 @@ static WEBP_INLINE void UpdateCostAtIndex(CostManager* const manager, int i,
// 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,
@ -429,17 +429,17 @@ static WEBP_INLINE void InsertInterval(CostManager* const manager,
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) {
@ -449,13 +449,13 @@ static WEBP_INLINE void InsertInterval(CostManager* const manager,
}
}
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
@ -466,10 +466,10 @@ 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;
@ -480,84 +480,84 @@ static WEBP_INLINE void PushInterval(CostManager* const manager,
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;
}
}
}
@ -576,7 +576,7 @@ static int BackwardReferencesHashChainDistanceOnly(
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);
@ -590,7 +590,7 @@ static int BackwardReferencesHashChainDistanceOnly(
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;
@ -610,17 +610,17 @@ static int BackwardReferencesHashChainDistanceOnly(
// 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) {
@ -668,7 +668,7 @@ static int BackwardReferencesHashChainDistanceOnly(
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;
}
@ -680,7 +680,7 @@ static int BackwardReferencesHashChainDistanceOnly(
len_prev = len;
}
ok = !refs->error_;
ok = !refs->error;
Error:
if (cc_init) VP8LColorCacheClear(&hashers);
CostManagerClear(cost_manager);
@ -753,7 +753,7 @@ static int BackwardReferencesHashChainFollowChosenPath(
++i;
}
}
ok = !refs->error_;
ok = !refs->error;
Error:
if (cc_init) VP8LColorCacheClear(&hashers);
return ok;

View File

@ -79,30 +79,30 @@ static WEBP_INLINE int FindMatchLength(const uint32_t* const array1,
// 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;
}
}
@ -110,79 +110,79 @@ void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) {
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;
}
@ -191,35 +191,35 @@ 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;
}
// -----------------------------------------------------------------------------
@ -268,14 +268,14 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
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;
}
@ -354,7 +354,7 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
// (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;
@ -414,7 +414,7 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
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.
@ -508,7 +508,7 @@ static int BackwardReferencesRle(int xsize, int ysize,
}
}
if (use_color_cache) VP8LColorCacheClear(&hashers);
return !refs->error_;
return !refs->error;
}
static int BackwardReferencesLz77(int xsize, int ysize,
@ -573,7 +573,7 @@ static int BackwardReferencesLz77(int xsize, int ysize,
i += len;
}
ok = !refs->error_;
ok = !refs->error;
Error:
if (cc_init) VP8LColorCacheClear(&hashers);
return ok;
@ -648,7 +648,7 @@ static int BackwardReferencesLz77Box(int xsize, int ysize,
}
}
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);
@ -715,17 +715,17 @@ static int BackwardReferencesLz77Box(int xsize, int ysize,
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,
@ -818,7 +818,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
// 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);
@ -831,7 +831,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
// 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;
}

View File

@ -126,10 +126,10 @@ struct VP8LHashChain {
// (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.
@ -143,12 +143,12 @@ 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,
@ -170,12 +170,12 @@ 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
@ -189,8 +189,8 @@ 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.
@ -205,7 +205,7 @@ void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c);
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);
}
// -----------------------------------------------------------------------------

View File

@ -60,14 +60,14 @@ static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) {
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;
@ -81,12 +81,12 @@ void VP8CalculateLevelCosts(VP8EncProba* const proba) {
}
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;
}
//------------------------------------------------------------------------------
@ -206,9 +206,9 @@ const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES] = {
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;
}
@ -216,14 +216,14 @@ void VP8InitResidual(int first, int coeff_type,
// 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;
@ -231,7 +231,7 @@ int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) {
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;
@ -240,16 +240,16 @@ int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) {
// 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;
@ -257,7 +257,7 @@ int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) {
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;
@ -267,10 +267,10 @@ int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) {
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);
}
}
}

View File

@ -83,18 +83,18 @@ static int GetILevel(int sharpness, int 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
@ -139,11 +139,11 @@ static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) {
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();
@ -156,16 +156,16 @@ void VP8InitFilter(VP8EncIterator* const it) {
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.
@ -173,10 +173,10 @@ void VP8StoreFilterStats(VP8EncIterator* const it) {
// 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;
@ -184,7 +184,7 @@ void VP8StoreFilterStats(VP8EncIterator* const it) {
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;
@ -192,43 +192,43 @@ void VP8StoreFilterStats(VP8EncIterator* const it) {
}
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;
}
}

View File

@ -46,15 +46,15 @@ typedef struct { // struct for organizing convergence in either size or PSNR
} 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
@ -95,9 +95,9 @@ const uint8_t VP8Cat6[] =
// 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;
}
//------------------------------------------------------------------------------
@ -111,17 +111,17 @@ static int CalcSkipProba(uint64_t nb, uint64_t total) {
// 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;
}
@ -139,8 +139,8 @@ static int BranchCost(int nb, int total, int 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) {
@ -151,7 +151,7 @@ static int FinalizeTokenProbas(VP8EncProba* const proba) {
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];
@ -165,17 +165,17 @@ static int FinalizeTokenProbas(VP8EncProba* const proba) {
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;
}
@ -190,8 +190,8 @@ static int GetProba(int a, int b) {
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;
}
}
@ -199,34 +199,34 @@ 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;
}
}
@ -311,9 +311,9 @@ static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it,
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);
@ -321,8 +321,8 @@ static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it,
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);
@ -331,9 +331,9 @@ static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it,
// 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);
@ -343,18 +343,18 @@ static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it,
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);
}
@ -364,15 +364,15 @@ 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);
@ -381,9 +381,9 @@ static void RecordResiduals(VP8EncIterator* const it,
// 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);
}
}
@ -392,9 +392,9 @@ static void RecordResiduals(VP8EncIterator* const it,
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);
}
}
@ -412,14 +412,14 @@ 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 {
@ -429,9 +429,9 @@ static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd,
// 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);
}
}
@ -441,15 +441,15 @@ static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd,
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
@ -470,64 +470,64 @@ static void SetBlock(uint8_t* p, int value, int size) {
#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);
}
@ -536,12 +536,12 @@ 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));
}
}
}
@ -587,7 +587,7 @@ static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt,
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;
@ -599,10 +599,10 @@ static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt,
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 {
@ -612,17 +612,17 @@ static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt,
}
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);
@ -640,7 +640,7 @@ static int StatLoop(VP8Encoder* const enc) {
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;
@ -648,9 +648,9 @@ static int StatLoop(VP8Encoder* const enc) {
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) {
@ -665,10 +665,10 @@ static int StatLoop(VP8Encoder* const enc) {
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);
}
//------------------------------------------------------------------------------
@ -680,37 +680,37 @@ 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);
}
}
}
@ -719,7 +719,7 @@ static int PostLoopFinalize(VP8EncIterator* const it, int ok) {
} 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;
}
@ -728,11 +728,11 @@ static int PostLoopFinalize(VP8EncIterator* const it, int 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
}
}
@ -747,16 +747,16 @@ int VP8EncLoop(VP8Encoder* const enc) {
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;
}
@ -782,14 +782,14 @@ int VP8EncLoop(VP8Encoder* const enc) {
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;
@ -799,16 +799,16 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
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;
@ -821,7 +821,7 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
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);
@ -831,9 +831,9 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
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;
@ -848,11 +848,11 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
} 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;
@ -866,9 +866,9 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
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);
}
@ -883,13 +883,13 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
}
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);
}

View File

@ -111,7 +111,7 @@ VP8LHistogram* VP8LAllocateHistogram(int 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.
// 'literal' won't necessary be aligned.
histo->literal = (uint32_t*)(memory + sizeof(VP8LHistogram));
VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0);
return histo;
@ -127,7 +127,7 @@ static void HistogramSetResetPointers(VP8LHistogramSet* const set,
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.
// 'literal' won't necessary be aligned.
set->histograms[i]->literal = (uint32_t*)(memory + sizeof(VP8LHistogram));
memory += histo_size;
}
@ -514,31 +514,31 @@ WEBP_NODISCARD static int HistogramAddThresh(const VP8LHistogram* const a,
// 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->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;
}
static void UpdateHistogramCost(VP8LHistogram* const h) {
@ -578,13 +578,13 @@ static int GetBinIdForEntropy(uint64_t min, uint64_t max, uint64_t val) {
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);
GetBinIdForEntropy(c->literal_min, c->literal_max, h->literal_cost);
assert(bin_id < NUM_PARTITIONS);
if (!low_effort) {
bin_id = bin_id * NUM_PARTITIONS
+ GetBinIdForEntropy(c->red_min_, c->red_max_, h->red_cost);
+ 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);
+ GetBinIdForEntropy(c->blue_min, c->blue_max, h->blue_cost);
assert(bin_id < BIN_SIZE);
}
return bin_id;
@ -1064,7 +1064,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
// 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) {

View File

@ -28,7 +28,7 @@ extern "C" {
// 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];

View File

@ -21,81 +21,81 @@
//------------------------------------------------------------------------------
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;
}
@ -131,9 +131,9 @@ static void ImportLine(const uint8_t* src, int src_stride,
}
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;
@ -142,9 +142,9 @@ void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32) {
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;
@ -153,19 +153,19 @@ void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32) {
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 {
@ -188,13 +188,13 @@ static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride,
}
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;
@ -234,9 +234,9 @@ void VP8IteratorExport(const VP8EncIterator* const it) {
#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);
@ -268,8 +268,8 @@ void VP8IteratorNzToBytes(VP8EncIterator* const it) {
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);
@ -281,7 +281,7 @@ void VP8IteratorBytesToNz(VP8EncIterator* const it) {
nz |= (left_nz[2] << 11);
nz |= (left_nz[4] << 17) | (left_nz[6] << 21);
*it->nz_ = nz;
*it->nz = nz;
}
#undef BIT
@ -290,77 +290,77 @@ void VP8IteratorBytesToNz(VP8EncIterator* const it) {
// 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;
}
//------------------------------------------------------------------------------
@ -403,52 +403,52 @@ static const uint8_t VP8TopLeftI4[16] = {
};
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];
}
@ -458,12 +458,12 @@ int VP8IteratorRotateI4(VP8EncIterator* const it,
}
}
// 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;
}

View File

@ -831,24 +831,24 @@ int VP8LResidualImage(int width, int height, int min_bits, int max_bits,
// 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],
@ -871,11 +871,11 @@ static int64_t GetPredictionCostCrossColorRed(
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;
}
@ -913,7 +913,7 @@ static void GetBestGreenToRed(const uint32_t* argb, int stride, int tile_width,
}
}
}
best_tx->green_to_red_ = (green_to_red_best & 0xff);
best_tx->green_to_red = (green_to_red_best & 0xff);
}
static int64_t GetPredictionCostCrossColorBlue(
@ -927,19 +927,19 @@ static int64_t GetPredictionCostCrossColorBlue(
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;
}
@ -997,8 +997,8 @@ static void GetBestGreenRedToBlue(const uint32_t* argb, int stride,
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

View File

@ -54,11 +54,11 @@
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]);
@ -211,26 +211,26 @@ static int ExpandMatrix(VP8Matrix* const m, int type) {
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;
}
@ -240,49 +240,49 @@ 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;
}
}
@ -296,21 +296,21 @@ static void SetupMatrices(VP8Encoder* enc) {
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;
}
//------------------------------------------------------------------------------
@ -356,25 +356,25 @@ static double QualityToJPEGCompression(double c, double alpha) {
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;
@ -383,18 +383,18 @@ static void SimplifySegments(VP8Encoder* const enc) {
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];
}
}
}
@ -402,50 +402,50 @@ static void SimplifySegments(VP8Encoder* const enc) {
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
@ -467,21 +467,21 @@ static const uint16_t VP8I4ModeOffsets[NUM_BMODES] = {
};
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);
}
//------------------------------------------------------------------------------
@ -597,9 +597,9 @@ static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc,
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];
@ -611,7 +611,7 @@ static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc,
{
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
@ -643,13 +643,13 @@ static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc,
// 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;
@ -757,7 +757,7 @@ static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc,
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);
@ -775,10 +775,10 @@ 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];
@ -787,18 +787,18 @@ static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it,
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;
}
@ -808,7 +808,7 @@ static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it,
// 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);
}
@ -828,20 +828,20 @@ static int ReconstructIntra4(VP8EncIterator* WEBP_RESTRICT const it,
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;
@ -864,8 +864,8 @@ static int QuantizeSingle(int16_t* WEBP_RESTRICT const v,
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;
@ -887,8 +887,8 @@ static void CorrectDCValues(const VP8EncIterator* WEBP_RESTRICT const it,
// 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);
@ -899,7 +899,7 @@ static void CorrectDCValues(const VP8EncIterator* WEBP_RESTRICT const it,
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;
@ -912,8 +912,8 @@ 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
@ -931,10 +931,10 @@ static void StoreDiffusionErrors(VP8EncIterator* WEBP_RESTRICT const it,
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];
@ -942,25 +942,25 @@ static int ReconstructUV(VP8EncIterator* WEBP_RESTRICT const it,
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;
}
}
@ -982,7 +982,7 @@ static void StoreMaxDelta(VP8SegmentInfo* const dqm, const int16_t DCs[16]) {
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) {
@ -998,25 +998,25 @@ static void SwapPtr(uint8_t** a, uint8_t** b) {
}
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
@ -1048,13 +1048,13 @@ static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it,
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);
}
}
@ -1064,41 +1064,41 @@ static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it,
// 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);
@ -1108,7 +1108,7 @@ static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it,
// 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);
@ -1137,25 +1137,25 @@ static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it,
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
@ -1171,11 +1171,11 @@ static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it,
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;
@ -1202,7 +1202,7 @@ static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it,
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);
@ -1213,7 +1213,7 @@ static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it,
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);
}
}
@ -1223,26 +1223,26 @@ static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it,
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;
}
@ -1253,23 +1253,23 @@ static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it,
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) {
@ -1281,10 +1281,10 @@ static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it,
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
}
}
@ -1301,12 +1301,12 @@ static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const 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) {
@ -1315,18 +1315,18 @@ static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it,
}
}
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.
@ -1335,16 +1335,16 @@ static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it,
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) {
@ -1354,7 +1354,7 @@ static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it,
}
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;
@ -1367,7 +1367,7 @@ 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);
@ -1377,14 +1377,14 @@ int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const 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 {

View File

@ -22,8 +22,8 @@
// 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) {
@ -36,7 +36,7 @@ static int PutPaddingByte(const WebPPicture* const pic) {
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'
};
@ -49,7 +49,7 @@ static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc,
}
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'
};
@ -59,7 +59,7 @@ static WebPEncodingError PutVP8XHeader(const VP8Encoder* const 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;
}
@ -74,26 +74,26 @@ static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
}
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;
@ -148,7 +148,7 @@ static WebPEncodingError PutVP8FrameHeader(const WebPPicture* const pic,
// 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.
@ -162,7 +162,7 @@ static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0,
}
// Alpha.
if (enc->has_alpha_) {
if (enc->has_alpha) {
err = PutAlphaChunk(enc);
if (err != VP8_ENC_OK) goto Error;
}
@ -172,7 +172,7 @@ static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0,
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.
@ -186,27 +186,27 @@ static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0,
// 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);
}
}
}
@ -216,18 +216,18 @@ static void PutSegmentHeader(VP8BitWriter* const bw,
// 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
}
}
@ -236,12 +236,12 @@ static void PutFilterHeader(VP8BitWriter* const bw,
// 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
@ -249,8 +249,8 @@ 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);
}
@ -267,25 +267,25 @@ static int EmitPartitionsSize(const VP8Encoder* const enc,
//------------------------------------------------------------------------------
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);
@ -293,36 +293,36 @@ static int GeneratePartition0(VP8Encoder* const enc) {
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;
@ -334,9 +334,9 @@ int VP8EncWrite(VP8Encoder* const enc) {
// 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;
@ -347,9 +347,9 @@ int VP8EncWrite(VP8Encoder* const enc) {
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.
@ -368,13 +368,13 @@ int VP8EncWrite(VP8Encoder* const enc) {
}
// 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
@ -382,8 +382,8 @@ int VP8EncWrite(VP8Encoder* const enc) {
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;
}

View File

@ -34,51 +34,51 @@ 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;
}
@ -92,9 +92,9 @@ static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, uint32_t bit,
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;
@ -104,9 +104,9 @@ 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;
}
}
@ -199,12 +199,12 @@ int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res,
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];
@ -218,19 +218,19 @@ int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
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];

View File

@ -154,13 +154,13 @@ const uint8_t
};
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.
@ -311,22 +311,22 @@ static void PutSegment(VP8BitWriter* const bw, int s, const uint8_t* p) {
}
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) {
@ -339,7 +339,7 @@ void VP8CodeIntraModes(VP8Encoder* const enc) {
preds += preds_w;
}
}
PutUVMode(bw, mb->uv_mode_);
PutUVMode(bw, mb->uv_mode);
} while (VP8IteratorNext(&it));
}
@ -488,7 +488,7 @@ void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas) {
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);
@ -497,8 +497,8 @@ void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas) {
}
}
}
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);
}
}

View File

@ -49,9 +49,9 @@ typedef enum { // Rate-distortion optimization levels
// 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):
// +----+----+
@ -60,7 +60,7 @@ typedef enum { // Rate-distortion optimization levels
// 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|
@ -138,32 +138,32 @@ 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;
//------------------------------------------------------------------------------
@ -171,37 +171,37 @@ typedef struct {
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 */];
@ -224,48 +224,48 @@ typedef struct {
// 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
@ -285,7 +285,8 @@ void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32);
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);
@ -313,13 +314,13 @@ 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
@ -346,72 +347,72 @@ size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas);
// 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)
};
//------------------------------------------------------------------------------
@ -442,9 +443,9 @@ 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);
@ -462,11 +463,11 @@ int WebPReportProgress(const WebPPicture* const pic,
// 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,

View File

@ -278,14 +278,14 @@ static int GetTransformBits(int method, int histo_bits) {
// 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
@ -296,10 +296,10 @@ 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;
@ -311,32 +311,32 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
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;
}
@ -361,14 +361,14 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
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;
}
@ -377,8 +377,8 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
} 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.
@ -386,8 +386,8 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
// 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;
}
}
}
@ -398,17 +398,17 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
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;
@ -416,9 +416,9 @@ static int EncoderInit(VP8LEncoder* const enc) {
// 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;
}
@ -746,7 +746,7 @@ static int StoreImageToBitMask(VP8LBitWriter* const bw, int width,
}
VP8LRefsCursorNext(&c);
}
if (bw->error_) {
if (bw->error) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
return 1;
@ -905,29 +905,29 @@ static int EncodeImageInternal(
// 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
@ -1082,7 +1082,7 @@ 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,
@ -1091,19 +1091,19 @@ static int ApplyPredictFilter(VP8LEncoder* const enc, int width, int height,
int percent_range, int* const percent) {
int 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,
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;
}
@ -1111,11 +1111,11 @@ static int ApplyPredictFilter(VP8LEncoder* const enc, int width, int height,
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;
enc->predictor_transform_bits = best_bits;
return EncodeImageNoHuffman(
bw, enc->transform_data_, &enc->hash_chain_, &enc->refs_[0],
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,
quality, low_effort, enc->pic, percent_range - percent_range / 2,
percent);
}
@ -1123,11 +1123,11 @@ 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_;
const int min_bits = enc->cross_color_transform_bits;
int best_bits;
if (!VP8LColorSpaceTransform(width, height, min_bits, quality, enc->argb_,
enc->transform_data_, enc->pic_,
if (!VP8LColorSpaceTransform(width, height, min_bits, quality, enc->argb,
enc->transform_data, enc->pic,
percent_range / 2, percent, &best_bits)) {
return 0;
}
@ -1135,11 +1135,11 @@ static int ApplyCrossColorFilter(VP8LEncoder* const enc, int width, int height,
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;
enc->cross_color_transform_bits = best_bits;
return EncodeImageNoHuffman(
bw, enc->transform_data_, &enc->hash_chain_, &enc->refs_[0],
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,
quality, low_effort, enc->pic, percent_range - percent_range / 2,
percent);
}
@ -1164,13 +1164,13 @@ static int WriteImageSize(const WebPPicture* const pic,
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,
@ -1182,7 +1182,7 @@ static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw,
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);
}
@ -1204,16 +1204,16 @@ static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw,
// -----------------------------------------------------------------------------
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;
@ -1221,11 +1221,11 @@ static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
// 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;
@ -1234,37 +1234,37 @@ static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
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) {
@ -1273,8 +1273,8 @@ static int MakeInputImageCopy(VP8LEncoder* const enc) {
src += picture->argb_stride;
}
}
enc->argb_content_ = kEncoderARGB;
assert(enc->current_width_ == width);
enc->argb_content = kEncoderARGB;
assert(enc->current_width == width);
return 1;
}
@ -1400,13 +1400,13 @@ static int ApplyPalette(const uint32_t* src, uint32_t src_stride, uint32_t* dst,
#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.
@ -1420,28 +1420,28 @@ static int MapImageFromPalette(VP8LEncoder* const enc) {
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);
@ -1453,8 +1453,8 @@ static int EncodePalette(VP8LBitWriter* const bw, int low_effort,
}
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);
}
// -----------------------------------------------------------------------------
@ -1467,9 +1467,9 @@ static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
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();
@ -1479,8 +1479,8 @@ static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
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);
}
@ -1490,27 +1490,27 @@ static void VP8LEncoderDelete(VP8LEncoder* 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);
@ -1537,51 +1537,51 @@ static int EncodeStreamHook(void* input, void* data2) {
}
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_ =
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;
@ -1592,36 +1592,36 @@ static int EncodeStreamHook(void* input, void* data2) {
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,
if (!ApplyPredictFilter(enc, enc->current_width, height, quality,
low_effort, enc->use_subtract_green, bw,
percent_range, &percent)) {
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,
if (!ApplyCrossColorFilter(enc, enc->current_width, height, quality,
low_effort, bw, percent_range, &percent)) {
goto Error;
}
@ -1633,9 +1633,9 @@ static int EncodeStreamHook(void* input, void* data2) {
// -------------------------------------------------------------------------
// 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;
}
@ -1649,15 +1649,15 @@ static int EncodeStreamHook(void* input, void* data2) {
// 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 = 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;
stats->lossless_size = (int)(best_size - byte_position);
stats->lossless_hdr_size = hdr_size;
stats->lossless_data_size = data_size;
@ -1672,7 +1672,7 @@ static int EncodeStreamHook(void* input, void* data2) {
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,
@ -1715,17 +1715,17 @@ int VP8LEncodeStream(const WebPConfig* const config,
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.
{
@ -1735,13 +1735,13 @@ int VP8LEncodeStream(const WebPConfig* const config,
WebPWorker* const worker = (idx == 0) ? &worker_main : &worker_side;
StreamEncodeContext* const param =
(idx == 0) ? &params_main : &params_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,
@ -1749,14 +1749,14 @@ int VP8LEncodeStream(const WebPConfig* const config,
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)) {
@ -1764,17 +1764,17 @@ int VP8LEncodeStream(const WebPConfig* const config,
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);
@ -1916,7 +1916,7 @@ int VP8LEncodeImage(const WebPConfig* const config,
}
Error:
if (bw.error_) {
if (bw.error) {
WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
VP8LBitWriterWipeOut(&bw);

View File

@ -33,7 +33,7 @@
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 {
@ -44,39 +44,39 @@ typedef enum {
} 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;
//------------------------------------------------------------------------------

View File

@ -38,36 +38,36 @@ int WebPGetEncoderVersion(void) {
//------------------------------------------------------------------------------
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 |
//-------------------+---+---+---+---+---+---+---+
@ -93,31 +93,31 @@ static void ResetBoundaryPredictions(VP8Encoder* const enc) {
//-------------------+---+---+---+---+---+---+---+
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
}
}
}
@ -150,18 +150,18 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
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
@ -206,32 +206,32 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
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();
@ -246,7 +246,7 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
// 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;
}
@ -255,7 +255,7 @@ static int DeleteVP8Encoder(VP8Encoder* enc) {
int ok = 1;
if (enc != NULL) {
ok = VP8EncDeleteAlpha(enc);
VP8TBufferClear(&enc->tokens_);
VP8TBufferClear(&enc->tokens);
WebPSafeFree(enc);
}
return ok;
@ -269,9 +269,9 @@ static double GetPSNR(uint64_t err, uint64_t size) {
}
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);
@ -282,24 +282,24 @@ static void FinalizePSNR(const VP8Encoder* const enc) {
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)
}
@ -380,7 +380,7 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
// 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);

View File

@ -53,33 +53,33 @@ 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);
@ -96,8 +96,8 @@ void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) {
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
}
@ -108,28 +108,28 @@ 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;
}
@ -139,18 +139,18 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br,
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;
}
@ -160,19 +160,19 @@ 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;
@ -181,9 +181,9 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* WEBP_RESTRICT const br,
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;
}

View File

@ -28,9 +28,9 @@ void VP8BitReaderSetBuffer(VP8BitReader* const br,
const uint8_t* const start,
size_t size) {
if (start != NULL) {
br->buf_ = start;
br->buf_end_ = start + size;
br->buf_max_ =
br->buf = start;
br->buf_end = start + size;
br->buf_max =
(size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1 : start;
}
}
@ -40,19 +40,19 @@ void VP8InitBitReader(VP8BitReader* const br,
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;
}
}
@ -89,17 +89,17 @@ const uint8_t kVP8NewRange[128] = {
};
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.
}
}
@ -150,20 +150,20 @@ void VP8LInitBitReader(VP8LBitReader* const br, const uint8_t* const start,
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,
@ -171,24 +171,24 @@ void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
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);
@ -196,14 +196,14 @@ static void ShiftBytes(VP8LBitReader* const 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
@ -213,10 +213,10 @@ void VP8LDoFillBitWindow(VP8LBitReader* const br) {
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 {
@ -276,17 +276,17 @@ void BitTrace(const struct VP8BitReader* const br, const char label[]) {
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;
}

View File

@ -47,14 +47,14 @@ extern void BitTrace(const struct VP8BitReader* const br, const char label[]);
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.
@ -77,8 +77,8 @@ extern "C" {
//------------------------------------------------------------------------------
// 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;
@ -94,14 +94,14 @@ typedef uint32_t range_t;
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.
@ -141,12 +141,12 @@ int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits,
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,
@ -160,34 +160,34 @@ void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
// 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

View File

@ -26,54 +26,54 @@
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.
}
}
@ -106,36 +106,36 @@ static const uint8_t kNewRange[128] = {
};
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;
}
@ -160,37 +160,37 @@ void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits) {
//------------------------------------------------------------------------------
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));
}
}
@ -206,12 +206,12 @@ void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
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;
@ -221,16 +221,16 @@ static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
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;
}
@ -241,31 +241,31 @@ int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t 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) {
@ -276,19 +276,19 @@ void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst) {
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) {
@ -296,8 +296,8 @@ void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) {
// 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) {
@ -312,36 +312,36 @@ void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_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;
}
//------------------------------------------------------------------------------

View File

@ -25,14 +25,14 @@ extern "C" {
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.
@ -54,17 +54,17 @@ int VP8BitWriterAppend(VP8BitWriter* const bw,
// 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;
}
//------------------------------------------------------------------------------
@ -87,21 +87,21 @@ typedef uint16_t vp8l_wtype_t;
#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.
@ -129,16 +129,16 @@ void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits);
// 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);

View File

@ -24,18 +24,18 @@ 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;
}
}
@ -43,7 +43,7 @@ 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));
}

View File

@ -26,9 +26,9 @@ extern "C" {
// 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;
@ -40,32 +40,32 @@ int VP8LHashPix(uint32_t argb, int 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;
}
//------------------------------------------------------------------------------

View File

@ -29,9 +29,9 @@ typedef CRITICAL_SECTION pthread_mutex_t;
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
@ -51,9 +51,9 @@ typedef struct {
#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)
@ -133,9 +133,9 @@ static int pthread_cond_destroy(pthread_cond_t* const condition) {
#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;
}
@ -145,12 +145,12 @@ static int pthread_cond_init(pthread_cond_t* const condition, 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;
}
@ -163,12 +163,12 @@ static int pthread_cond_signal(pthread_cond_t* const condition) {
#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
@ -183,12 +183,12 @@ static int pthread_cond_wait(pthread_cond_t* const condition,
#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;
@ -203,17 +203,17 @@ static int pthread_cond_wait(pthread_cond_t* const condition,
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())
@ -221,8 +221,8 @@ static THREADFN ThreadLoop(void* ptr) {
// 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
}
@ -230,30 +230,30 @@ static THREADFN ThreadLoop(void* ptr) {
// 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
@ -262,54 +262,54 @@ static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) {
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;
}
@ -329,20 +329,20 @@ static void Launch(WebPWorker* const worker) {
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);
}
//------------------------------------------------------------------------------

View File

@ -37,8 +37,8 @@ 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'

View File

@ -50,7 +50,7 @@ void HuffmanTest(std::string_view blob) {
VP8LBitReader* br;
VP8LDecoder* dec = VP8LNew();
if (dec == NULL) goto Error;
br = &dec->br_;
br = &dec->br;
VP8LInitBitReader(br, data, size);
color_cache_bits = VP8LReadBits(br, kColorCacheBitsBits);