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:
Pascal Massimino 2011-08-23 15:58:22 -07:00
parent cd12b4b0ac
commit 900286e091
8 changed files with 56 additions and 8 deletions

2
README
View File

@ -140,6 +140,8 @@ options:
-f <int> ............... filter strength (0=off..100)
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp)
-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
-noalpha ............... discard any transparency information.
-pass <int> ............ analysis pass number (1..10)

View File

@ -676,6 +676,9 @@ static void HelpLong(void) {
printf(" -sharpness <int> ....... "
"filter sharpness (0:most .. 7:least sharp)\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(" -noalpha ............... discard any transparency information.\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",
"NULL_PARAMETER: NULL parameter passed to function",
"INVALID_CONFIGURATION: configuration is invalid",
"BAD_DIMENSION: Bad picture dimension",
"PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k",
"PARTITION_OVERFLOW: Partition is too big to fir 16M",
"BAD_WRITE: Picture writer returned an error"
"BAD_DIMENSION: Bad picture dimension. Maximum width and height "
"allowed is 16383 pixels.",
"PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k.\n"
"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);
} else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
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) {
config.alpha_compression = strtol(argv[++c], NULL, 0);
} else if (!strcmp(argv[c], "-noalpha")) {

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
.TH CWEBP 1 "June 20, 2011"
.TH CWEBP 1 "August 23, 2011"
.SH NAME
cwebp \- compress an image file to a WebP file
.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
sns algorithm. Segments should be in range 1 to 4. Default value is 4.
.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
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

View File

@ -42,6 +42,7 @@ int WebPConfigInitInternal(WebPConfig* const config,
config->preprocessing = 0;
config->autofilter = 0;
config->alpha_compression = 0;
config->partition_limit = 0;
// TODO(skal): tune.
switch (preset) {
@ -106,6 +107,8 @@ int WebPValidateConfig(const WebPConfig* const config) {
return 0;
if (config->partitions < 0 || config->partitions > 3)
return 0;
if (config->partition_limit < 0 || config->partition_limit > 100)
return 0;
if (config->alpha_compression < 0)
return 0;
return 1;

View File

@ -757,8 +757,13 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
const int tlambda = dqm->tlambda_;
const uint8_t* const src0 = it->yuv_in_ + Y_OFF;
uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF;
int total_header_bits = 0;
VP8ModeScore rd_best;
if (enc->max_i4_header_bits_ == 0) {
return 0;
}
InitScore(&rd_best);
rd_best.score = 211; // '211' is the value of VP8BitCost(0, 145)
VP8IteratorStartI4(it);
@ -799,7 +804,9 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
}
SetRDScore(dqm->lambda_mode_, &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;
}
// Copy selected samples if not in the right place already.

View File

@ -359,8 +359,9 @@ struct VP8Encoder {
int block_count_[3];
// quality/speed settings
int method_; // 0=fastest, 6=best/slowest.
int rd_opt_level_; // Deduced from method_.
int method_; // 0=fastest, 6=best/slowest.
int rd_opt_level_; // Deduced from method_.
int max_i4_header_bits_; // partition #0 safeness factor
// Memory
VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1)

View File

@ -112,11 +112,15 @@ static void ResetBoundaryPredictions(VP8Encoder* const enc) {
static void MapConfigToTools(VP8Encoder* const enc) {
const int method = enc->config_->method;
const int limit = 100 - enc->config_->partition_limit;
enc->method_ = method;
enc->rd_opt_level_ = (method >= 6) ? 3
: (method >= 5) ? 2
: (method >= 3) ? 1
: 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:

View File

@ -69,6 +69,8 @@ typedef struct {
int preprocessing; // preprocessing filter (0=none, 1=segment-smooth)
int partitions; // log2(number of token partitions) in [0..3]
// 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)
} WebPConfig;