mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01:00
add a -partition_limit option to limit the number of bits used by intra4x4
Although it degrades quality, this option is useful to avoid the 512k limit for partition #0. If not enough to reach the lower bound of 4bits per macroblock header, one should also limit the number of segments used (down to -segments 1) See the man file for extra details. Change-Id: Ia59ffac13176c85b809ddd6340d37b54ee9487ea
This commit is contained in:
parent
cd12b4b0ac
commit
900286e091
2
README
2
README
@ -140,6 +140,8 @@ options:
|
|||||||
-f <int> ............... filter strength (0=off..100)
|
-f <int> ............... filter strength (0=off..100)
|
||||||
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp)
|
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp)
|
||||||
-strong ................ use strong filter instead of simple.
|
-strong ................ use strong filter instead of simple.
|
||||||
|
-partition_limit <int> . limit quality to fit the 512k limit on
|
||||||
|
the first partition (0=no degradation ... 100=full)
|
||||||
-alpha_comp <int> ...... set the transparency-compression
|
-alpha_comp <int> ...... set the transparency-compression
|
||||||
-noalpha ............... discard any transparency information.
|
-noalpha ............... discard any transparency information.
|
||||||
-pass <int> ............ analysis pass number (1..10)
|
-pass <int> ............ analysis pass number (1..10)
|
||||||
|
@ -676,6 +676,9 @@ static void HelpLong(void) {
|
|||||||
printf(" -sharpness <int> ....... "
|
printf(" -sharpness <int> ....... "
|
||||||
"filter sharpness (0:most .. 7:least sharp)\n");
|
"filter sharpness (0:most .. 7:least sharp)\n");
|
||||||
printf(" -strong ................ use strong filter instead of simple.\n");
|
printf(" -strong ................ use strong filter instead of simple.\n");
|
||||||
|
printf(" -partition_limit <int> . limit quality to fit the 512k limit on\n");
|
||||||
|
printf(" "
|
||||||
|
"the first partition (0=no degradation ... 100=full)\n");
|
||||||
printf(" -alpha_comp <int> ...... set the transparency-compression\n");
|
printf(" -alpha_comp <int> ...... set the transparency-compression\n");
|
||||||
printf(" -noalpha ............... discard any transparency information.\n");
|
printf(" -noalpha ............... discard any transparency information.\n");
|
||||||
printf(" -pass <int> ............ analysis pass number (1..10)\n");
|
printf(" -pass <int> ............ analysis pass number (1..10)\n");
|
||||||
@ -712,10 +715,15 @@ static const char* const kErrorMessages[] = {
|
|||||||
"BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer",
|
"BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer",
|
||||||
"NULL_PARAMETER: NULL parameter passed to function",
|
"NULL_PARAMETER: NULL parameter passed to function",
|
||||||
"INVALID_CONFIGURATION: configuration is invalid",
|
"INVALID_CONFIGURATION: configuration is invalid",
|
||||||
"BAD_DIMENSION: Bad picture dimension",
|
"BAD_DIMENSION: Bad picture dimension. Maximum width and height "
|
||||||
"PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k",
|
"allowed is 16383 pixels.",
|
||||||
"PARTITION_OVERFLOW: Partition is too big to fir 16M",
|
"PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k.\n"
|
||||||
"BAD_WRITE: Picture writer returned an error"
|
"To reduce the size of this partition, try using less segments "
|
||||||
|
"with the -segments option, and eventually reduce the number of "
|
||||||
|
"header bits using -partition_limit. More details are available "
|
||||||
|
"in the manual (`man cwebp`)",
|
||||||
|
"PARTITION_OVERFLOW: Partition is too big to fit 16M",
|
||||||
|
"BAD_WRITE: Picture writer returned an I/O error"
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -789,6 +797,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
config.preprocessing = strtol(argv[++c], NULL, 0);
|
config.preprocessing = strtol(argv[++c], NULL, 0);
|
||||||
} else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
|
||||||
config.segments = strtol(argv[++c], NULL, 0);
|
config.segments = strtol(argv[++c], NULL, 0);
|
||||||
|
} else if (!strcmp(argv[c], "-partition_limit") && c < argc - 1) {
|
||||||
|
config.partition_limit = strtol(argv[++c], NULL, 0);
|
||||||
} else if (!strcmp(argv[c], "-alpha_comp") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-alpha_comp") && c < argc - 1) {
|
||||||
config.alpha_compression = strtol(argv[++c], NULL, 0);
|
config.alpha_compression = strtol(argv[++c], NULL, 0);
|
||||||
} else if (!strcmp(argv[c], "-noalpha")) {
|
} else if (!strcmp(argv[c], "-noalpha")) {
|
||||||
|
21
man/cwebp.1
21
man/cwebp.1
@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH CWEBP 1 "June 20, 2011"
|
.TH CWEBP 1 "August 23, 2011"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
cwebp \- compress an image file to a WebP file
|
cwebp \- compress an image file to a WebP file
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -86,6 +86,25 @@ used thanks to the \fB\-f\fP option). Strong filtering is off by default.
|
|||||||
Change the number of partitions to use during the segmentation of the
|
Change the number of partitions to use during the segmentation of the
|
||||||
sns algorithm. Segments should be in range 1 to 4. Default value is 4.
|
sns algorithm. Segments should be in range 1 to 4. Default value is 4.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-partition_limit int
|
||||||
|
Degrade quality by limiting the number of bits used by some macroblocks.
|
||||||
|
Range is 0 (no degradation, the default) to 100 (full degradation).
|
||||||
|
Useful values are usually around 30-70 for moderately large images.
|
||||||
|
In the VP8 format, the so-called control partition has a limit of 512k and
|
||||||
|
is used to store the following information: whether the macroblock is skipped,
|
||||||
|
which segment it belongs to, whether it is coded as intra 4x4 or intra 16x16
|
||||||
|
mode, and finally the prediction modes to use for each of the sub-blocks.
|
||||||
|
For a very large image, 512k only leaves room to few bits per 16x16 macroblock.
|
||||||
|
The absolute minimum is 4 bits per macroblock. Skip, segment, and mode
|
||||||
|
information can use up almost all these 4 bits (although the case is unlikely),
|
||||||
|
which is problematic for very large images. The partition_limit factor controls
|
||||||
|
how frequently the most bit-costly mode (intra 4x4) will be used. This is
|
||||||
|
useful in case the 512k limit is reached and the following message is displayed:
|
||||||
|
\fIError code: 6 (PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k)\fP.
|
||||||
|
If using \fB-partition_limit\fP is not enough to meet the 512k constraint, one
|
||||||
|
should use less segments in order to save more header bits per macroblock.
|
||||||
|
See the \fB-segments\fP option.
|
||||||
|
.TP
|
||||||
.B \-size int
|
.B \-size int
|
||||||
Specify a target size (in bytes) to try and reach for the compressed output.
|
Specify a target size (in bytes) to try and reach for the compressed output.
|
||||||
Compressor will make several pass of partial encoding in order to get as
|
Compressor will make several pass of partial encoding in order to get as
|
||||||
|
@ -42,6 +42,7 @@ int WebPConfigInitInternal(WebPConfig* const config,
|
|||||||
config->preprocessing = 0;
|
config->preprocessing = 0;
|
||||||
config->autofilter = 0;
|
config->autofilter = 0;
|
||||||
config->alpha_compression = 0;
|
config->alpha_compression = 0;
|
||||||
|
config->partition_limit = 0;
|
||||||
|
|
||||||
// TODO(skal): tune.
|
// TODO(skal): tune.
|
||||||
switch (preset) {
|
switch (preset) {
|
||||||
@ -106,6 +107,8 @@ int WebPValidateConfig(const WebPConfig* const config) {
|
|||||||
return 0;
|
return 0;
|
||||||
if (config->partitions < 0 || config->partitions > 3)
|
if (config->partitions < 0 || config->partitions > 3)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (config->partition_limit < 0 || config->partition_limit > 100)
|
||||||
|
return 0;
|
||||||
if (config->alpha_compression < 0)
|
if (config->alpha_compression < 0)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -757,8 +757,13 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
|
|||||||
const int tlambda = dqm->tlambda_;
|
const int tlambda = dqm->tlambda_;
|
||||||
const uint8_t* const src0 = it->yuv_in_ + Y_OFF;
|
const uint8_t* const src0 = it->yuv_in_ + Y_OFF;
|
||||||
uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF;
|
uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF;
|
||||||
|
int total_header_bits = 0;
|
||||||
VP8ModeScore rd_best;
|
VP8ModeScore rd_best;
|
||||||
|
|
||||||
|
if (enc->max_i4_header_bits_ == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
InitScore(&rd_best);
|
InitScore(&rd_best);
|
||||||
rd_best.score = 211; // '211' is the value of VP8BitCost(0, 145)
|
rd_best.score = 211; // '211' is the value of VP8BitCost(0, 145)
|
||||||
VP8IteratorStartI4(it);
|
VP8IteratorStartI4(it);
|
||||||
@ -799,7 +804,9 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
|
|||||||
}
|
}
|
||||||
SetRDScore(dqm->lambda_mode_, &rd_i4);
|
SetRDScore(dqm->lambda_mode_, &rd_i4);
|
||||||
AddScore(&rd_best, &rd_i4);
|
AddScore(&rd_best, &rd_i4);
|
||||||
if (rd_best.score >= rd->score) {
|
total_header_bits += mode_costs[best_mode];
|
||||||
|
if (rd_best.score >= rd->score ||
|
||||||
|
total_header_bits > enc->max_i4_header_bits_) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Copy selected samples if not in the right place already.
|
// Copy selected samples if not in the right place already.
|
||||||
|
@ -361,6 +361,7 @@ struct VP8Encoder {
|
|||||||
// quality/speed settings
|
// quality/speed settings
|
||||||
int method_; // 0=fastest, 6=best/slowest.
|
int method_; // 0=fastest, 6=best/slowest.
|
||||||
int rd_opt_level_; // Deduced from method_.
|
int rd_opt_level_; // Deduced from method_.
|
||||||
|
int max_i4_header_bits_; // partition #0 safeness factor
|
||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1)
|
VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1)
|
||||||
|
@ -112,11 +112,15 @@ static void ResetBoundaryPredictions(VP8Encoder* const enc) {
|
|||||||
|
|
||||||
static void MapConfigToTools(VP8Encoder* const enc) {
|
static void MapConfigToTools(VP8Encoder* const enc) {
|
||||||
const int method = enc->config_->method;
|
const int method = enc->config_->method;
|
||||||
|
const int limit = 100 - enc->config_->partition_limit;
|
||||||
enc->method_ = method;
|
enc->method_ = method;
|
||||||
enc->rd_opt_level_ = (method >= 6) ? 3
|
enc->rd_opt_level_ = (method >= 6) ? 3
|
||||||
: (method >= 5) ? 2
|
: (method >= 5) ? 2
|
||||||
: (method >= 3) ? 1
|
: (method >= 3) ? 1
|
||||||
: 0;
|
: 0;
|
||||||
|
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.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory scaling with dimensions:
|
// Memory scaling with dimensions:
|
||||||
|
@ -69,6 +69,8 @@ typedef struct {
|
|||||||
int preprocessing; // preprocessing filter (0=none, 1=segment-smooth)
|
int preprocessing; // preprocessing filter (0=none, 1=segment-smooth)
|
||||||
int partitions; // log2(number of token partitions) in [0..3]
|
int partitions; // log2(number of token partitions) in [0..3]
|
||||||
// Default is set to 0 for easier progressive decoding.
|
// Default is set to 0 for easier progressive decoding.
|
||||||
|
int partition_limit; // quality degradation allowed to fit the 512k limit on
|
||||||
|
// prediction modes coding (0=no degradation, 100=full)
|
||||||
int alpha_compression; // Algorithm for optimizing the alpha plane (0 = none)
|
int alpha_compression; // Algorithm for optimizing the alpha plane (0 = none)
|
||||||
} WebPConfig;
|
} WebPConfig;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user