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:
		
							
								
								
									
										2
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								README
									
									
									
									
									
								
							@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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")) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								man/cwebp.1
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								man/cwebp.1
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -361,6 +361,7 @@ struct VP8Encoder {
 | 
			
		||||
  // quality/speed settings
 | 
			
		||||
  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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user