Allow transform_bits to be different during encoding.

The spec allows it but it is currently forced to the same value for simplicity.

Change-Id: I26197dbf3342f7a72115cc7f7805c154313a2afb
This commit is contained in:
Vincent Rabaud 2024-05-07 10:44:59 +02:00
parent 1e462ca80e
commit 1bf198a22b
5 changed files with 37 additions and 18 deletions

View File

@ -178,8 +178,14 @@ static void PrintFullLosslessInfo(const WebPAuxStats* const stats,
if (stats->lossless_features & 8) fprintf(stderr, " PALETTE"); if (stats->lossless_features & 8) fprintf(stderr, " PALETTE");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
fprintf(stderr, " * Precision Bits: histogram=%d transform=%d cache=%d\n", fprintf(stderr, " * Precision Bits: histogram=%d", stats->histogram_bits);
stats->histogram_bits, stats->transform_bits, stats->cache_bits); if (stats->lossless_features & 1) {
fprintf(stderr, " prediction=%d", stats->transform_bits);
}
if (stats->lossless_features & 2) {
fprintf(stderr, " cross-color=%d", stats->cross_color_transform_bits);
}
fprintf(stderr, " cache=%d\n", stats->cache_bits);
if (stats->palette_size > 0) { if (stats->palette_size > 0) {
fprintf(stderr, " * Palette size: %d\n", stats->palette_size); fprintf(stderr, " * Palette size: %d\n", stats->palette_size);
} }

View File

@ -276,6 +276,7 @@ static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height,
stats->lossless_features = best.stats.lossless_features; stats->lossless_features = best.stats.lossless_features;
stats->histogram_bits = best.stats.histogram_bits; stats->histogram_bits = best.stats.histogram_bits;
stats->transform_bits = best.stats.transform_bits; stats->transform_bits = best.stats.transform_bits;
stats->cross_color_transform_bits = best.stats.cross_color_transform_bits;
stats->cache_bits = best.stats.cache_bits; stats->cache_bits = best.stats.cache_bits;
stats->palette_size = best.stats.palette_size; stats->palette_size = best.stats.palette_size;
stats->lossless_size = best.stats.lossless_size; stats->lossless_size = best.stats.lossless_size;

View File

@ -281,7 +281,7 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
const int method = config->method; const int method = config->method;
const int low_effort = (config->method == 0); const int low_effort = (config->method == 0);
int i; int i;
int use_palette; int use_palette, transform_bits;
int n_lz77s; int n_lz77s;
// If set to 0, analyze the cache with the computed cache value. If 1, also // If set to 0, analyze the cache with the computed cache value. If 1, also
// analyze with no-cache. // analyze with no-cache.
@ -298,7 +298,9 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
// Empirical bit sizes. // Empirical bit sizes.
enc->histo_bits_ = GetHistoBits(method, use_palette, enc->histo_bits_ = GetHistoBits(method, use_palette,
pic->width, pic->height); pic->width, pic->height);
enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_); transform_bits = GetTransformBits(method, enc->histo_bits_);
enc->predictor_transform_bits_ = transform_bits;
enc->cross_color_transform_bits_ = transform_bits;
if (low_effort) { if (low_effort) {
// AnalyzeEntropy is somewhat slow. // AnalyzeEntropy is somewhat slow.
@ -312,8 +314,8 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
// Try out multiple LZ77 on images with few colors. // 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, if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, use_palette,
enc->palette_size_, enc->transform_bits_, enc->palette_size_, transform_bits, &min_entropy_ix,
&min_entropy_ix, red_and_blue_always_zero)) { red_and_blue_always_zero)) {
return 0; return 0;
} }
if (method == 6 && config->quality == 100) { if (method == 6 && config->quality == 100) {
@ -1069,7 +1071,7 @@ static int ApplyPredictFilter(VP8LEncoder* const enc, int width, int height,
int quality, int low_effort, int quality, int low_effort,
int used_subtract_green, VP8LBitWriter* const bw, int used_subtract_green, VP8LBitWriter* const bw,
int percent_range, int* const percent) { int percent_range, int* const percent) {
const int pred_bits = enc->transform_bits_; const int pred_bits = enc->predictor_transform_bits_;
const int transform_width = VP8LSubSampleSize(width, pred_bits); const int transform_width = VP8LSubSampleSize(width, pred_bits);
const int transform_height = VP8LSubSampleSize(height, pred_bits); const int transform_height = VP8LSubSampleSize(height, pred_bits);
// we disable near-lossless quantization if palette is used. // we disable near-lossless quantization if palette is used.
@ -1093,11 +1095,11 @@ static int ApplyPredictFilter(VP8LEncoder* const enc, int width, int height,
percent); percent);
} }
static int ApplyCrossColorFilter(const VP8LEncoder* const enc, int width, static int ApplyCrossColorFilter(VP8LEncoder* const enc, int width, int height,
int height, int quality, int low_effort, int quality, int low_effort,
VP8LBitWriter* const bw, int percent_range, VP8LBitWriter* const bw, int percent_range,
int* const percent) { int* const percent) {
const int ccolor_transform_bits = enc->transform_bits_; const int ccolor_transform_bits = enc->cross_color_transform_bits_;
const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
@ -1200,10 +1202,14 @@ static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) / enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) /
sizeof(uint32_t) sizeof(uint32_t)
: 0; : 0;
const int min_transform_bits =
(enc->predictor_transform_bits_ < enc->cross_color_transform_bits_)
? enc->predictor_transform_bits_
: enc->cross_color_transform_bits_;
const uint64_t transform_data_size = const uint64_t transform_data_size =
(enc->use_predict_ || enc->use_cross_color_) (enc->use_predict_ || enc->use_cross_color_)
? (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) * ? (uint64_t)VP8LSubSampleSize(width, min_transform_bits) *
VP8LSubSampleSize(height, enc->transform_bits_) VP8LSubSampleSize(height, min_transform_bits)
: 0; : 0;
const uint64_t max_alignment_in_words = const uint64_t max_alignment_in_words =
(WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t); (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t);
@ -1628,7 +1634,8 @@ static int EncodeStreamHook(void* input, void* data2) {
if (enc->use_subtract_green_) stats->lossless_features |= 4; if (enc->use_subtract_green_) stats->lossless_features |= 4;
if (enc->use_palette_) stats->lossless_features |= 8; if (enc->use_palette_) stats->lossless_features |= 8;
stats->histogram_bits = enc->histo_bits_; stats->histogram_bits = enc->histo_bits_;
stats->transform_bits = enc->transform_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->cache_bits = enc->cache_bits_;
stats->palette_size = enc->palette_size_; stats->palette_size = enc->palette_size_;
stats->lossless_size = (int)(best_size - byte_position); stats->lossless_size = (int)(best_size - byte_position);
@ -1738,7 +1745,10 @@ int VP8LEncodeStream(const WebPConfig* const config,
} }
// Copy the values that were computed for the main encoder. // Copy the values that were computed for the main encoder.
enc_side->histo_bits_ = enc_main->histo_bits_; enc_side->histo_bits_ = enc_main->histo_bits_;
enc_side->transform_bits_ = enc_main->transform_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_; enc_side->palette_size_ = enc_main->palette_size_;
memcpy(enc_side->palette_, enc_main->palette_, memcpy(enc_side->palette_, enc_main->palette_,
sizeof(enc_main->palette_)); sizeof(enc_main->palette_));

View File

@ -59,7 +59,8 @@ typedef struct {
// Encoding parameters derived from quality parameter. // Encoding parameters derived from quality parameter.
int histo_bits_; int histo_bits_;
int transform_bits_; // <= MAX_TRANSFORM_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 cache_bits_; // If equal to 0, don't use color cache.
// Encoding parameters derived from image characteristics. // Encoding parameters derived from image characteristics.

View File

@ -20,7 +20,7 @@
extern "C" { extern "C" {
#endif #endif
#define WEBP_ENCODER_ABI_VERSION 0x020f // MAJOR(8b) + MINOR(8b) #define WEBP_ENCODER_ABI_VERSION 0x0210 // MAJOR(8b) + MINOR(8b)
// Note: forward declaring enumerations is not allowed in (strict) C and C++, // Note: forward declaring enumerations is not allowed in (strict) C and C++,
// the types are left here for reference. // the types are left here for reference.
@ -224,14 +224,15 @@ struct WebPAuxStats {
uint32_t lossless_features; // bit0:predictor bit1:cross-color transform uint32_t lossless_features; // bit0:predictor bit1:cross-color transform
// bit2:subtract-green bit3:color indexing // bit2:subtract-green bit3:color indexing
int histogram_bits; // number of precision bits of histogram int histogram_bits; // number of precision bits of histogram
int transform_bits; // precision bits for transform int transform_bits; // precision bits for predictor transform
int cache_bits; // number of bits for color cache lookup int cache_bits; // number of bits for color cache lookup
int palette_size; // number of color in palette, if used int palette_size; // number of color in palette, if used
int lossless_size; // final lossless size int lossless_size; // final lossless size
int lossless_hdr_size; // lossless header (transform, huffman etc) size int lossless_hdr_size; // lossless header (transform, huffman etc) size
int lossless_data_size; // lossless image data size int lossless_data_size; // lossless image data size
int cross_color_transform_bits; // precision bits for cross-color transform
uint32_t pad[2]; // padding for later use uint32_t pad[1]; // padding for later use
}; };
// Signature for output function. Should return true if writing was successful. // Signature for output function. Should return true if writing was successful.