github.com/andybalholm/brotli@v1.0.6/quality.go (about)

     1  package brotli
     2  
     3  const fastOnePassCompressionQuality = 0
     4  
     5  const fastTwoPassCompressionQuality = 1
     6  
     7  const zopflificationQuality = 10
     8  
     9  const hqZopflificationQuality = 11
    10  
    11  const maxQualityForStaticEntropyCodes = 2
    12  
    13  const minQualityForBlockSplit = 4
    14  
    15  const minQualityForNonzeroDistanceParams = 4
    16  
    17  const minQualityForOptimizeHistograms = 4
    18  
    19  const minQualityForExtensiveReferenceSearch = 5
    20  
    21  const minQualityForContextModeling = 5
    22  
    23  const minQualityForHqContextModeling = 7
    24  
    25  const minQualityForHqBlockSplitting = 10
    26  
    27  /* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
    28     so we buffer at most this much literals and commands. */
    29  const maxNumDelayedSymbols = 0x2FFF
    30  
    31  /* Returns hash-table size for quality levels 0 and 1. */
    32  func maxHashTableSize(quality int) uint {
    33  	if quality == fastOnePassCompressionQuality {
    34  		return 1 << 15
    35  	} else {
    36  		return 1 << 17
    37  	}
    38  }
    39  
    40  /* The maximum length for which the zopflification uses distinct distances. */
    41  const maxZopfliLenQuality10 = 150
    42  
    43  const maxZopfliLenQuality11 = 325
    44  
    45  /* Do not thoroughly search when a long copy is found. */
    46  const longCopyQuickStep = 16384
    47  
    48  func maxZopfliLen(params *encoderParams) uint {
    49  	if params.quality <= 10 {
    50  		return maxZopfliLenQuality10
    51  	} else {
    52  		return maxZopfliLenQuality11
    53  	}
    54  }
    55  
    56  /* Number of best candidates to evaluate to expand Zopfli chain. */
    57  func maxZopfliCandidates(params *encoderParams) uint {
    58  	if params.quality <= 10 {
    59  		return 1
    60  	} else {
    61  		return 5
    62  	}
    63  }
    64  
    65  func sanitizeParams(params *encoderParams) {
    66  	params.quality = brotli_min_int(maxQuality, brotli_max_int(minQuality, params.quality))
    67  	if params.quality <= maxQualityForStaticEntropyCodes {
    68  		params.large_window = false
    69  	}
    70  
    71  	if params.lgwin < minWindowBits {
    72  		params.lgwin = minWindowBits
    73  	} else {
    74  		var max_lgwin int
    75  		if params.large_window {
    76  			max_lgwin = largeMaxWindowBits
    77  		} else {
    78  			max_lgwin = maxWindowBits
    79  		}
    80  		if params.lgwin > uint(max_lgwin) {
    81  			params.lgwin = uint(max_lgwin)
    82  		}
    83  	}
    84  }
    85  
    86  /* Returns optimized lg_block value. */
    87  func computeLgBlock(params *encoderParams) int {
    88  	var lgblock int = params.lgblock
    89  	if params.quality == fastOnePassCompressionQuality || params.quality == fastTwoPassCompressionQuality {
    90  		lgblock = int(params.lgwin)
    91  	} else if params.quality < minQualityForBlockSplit {
    92  		lgblock = 14
    93  	} else if lgblock == 0 {
    94  		lgblock = 16
    95  		if params.quality >= 9 && params.lgwin > uint(lgblock) {
    96  			lgblock = brotli_min_int(18, int(params.lgwin))
    97  		}
    98  	} else {
    99  		lgblock = brotli_min_int(maxInputBlockBits, brotli_max_int(minInputBlockBits, lgblock))
   100  	}
   101  
   102  	return lgblock
   103  }
   104  
   105  /* Returns log2 of the size of main ring buffer area.
   106     Allocate at least lgwin + 1 bits for the ring buffer so that the newly
   107     added block fits there completely and we still get lgwin bits and at least
   108     read_block_size_bits + 1 bits because the copy tail length needs to be
   109     smaller than ring-buffer size. */
   110  func computeRbBits(params *encoderParams) int {
   111  	return 1 + brotli_max_int(int(params.lgwin), params.lgblock)
   112  }
   113  
   114  func maxMetablockSize(params *encoderParams) uint {
   115  	var bits int = brotli_min_int(computeRbBits(params), maxInputBlockBits)
   116  	return uint(1) << uint(bits)
   117  }
   118  
   119  /* When searching for backward references and have not seen matches for a long
   120     time, we can skip some match lookups. Unsuccessful match lookups are very
   121     expensive and this kind of a heuristic speeds up compression quite a lot.
   122     At first 8 byte strides are taken and every second byte is put to hasher.
   123     After 4x more literals stride by 16 bytes, every put 4-th byte to hasher.
   124     Applied only to qualities 2 to 9. */
   125  func literalSpreeLengthForSparseSearch(params *encoderParams) uint {
   126  	if params.quality < 9 {
   127  		return 64
   128  	} else {
   129  		return 512
   130  	}
   131  }
   132  
   133  func chooseHasher(params *encoderParams, hparams *hasherParams) {
   134  	if params.quality > 9 {
   135  		hparams.type_ = 10
   136  	} else if params.quality == 4 && params.size_hint >= 1<<20 {
   137  		hparams.type_ = 54
   138  	} else if params.quality < 5 {
   139  		hparams.type_ = params.quality
   140  	} else if params.lgwin <= 16 {
   141  		if params.quality < 7 {
   142  			hparams.type_ = 40
   143  		} else if params.quality < 9 {
   144  			hparams.type_ = 41
   145  		} else {
   146  			hparams.type_ = 42
   147  		}
   148  	} else if params.size_hint >= 1<<20 && params.lgwin >= 19 {
   149  		hparams.type_ = 6
   150  		hparams.block_bits = params.quality - 1
   151  		hparams.bucket_bits = 15
   152  		hparams.hash_len = 5
   153  		if params.quality < 7 {
   154  			hparams.num_last_distances_to_check = 4
   155  		} else if params.quality < 9 {
   156  			hparams.num_last_distances_to_check = 10
   157  		} else {
   158  			hparams.num_last_distances_to_check = 16
   159  		}
   160  	} else {
   161  		hparams.type_ = 5
   162  		hparams.block_bits = params.quality - 1
   163  		if params.quality < 7 {
   164  			hparams.bucket_bits = 14
   165  		} else {
   166  			hparams.bucket_bits = 15
   167  		}
   168  		if params.quality < 7 {
   169  			hparams.num_last_distances_to_check = 4
   170  		} else if params.quality < 9 {
   171  			hparams.num_last_distances_to_check = 10
   172  		} else {
   173  			hparams.num_last_distances_to_check = 16
   174  		}
   175  	}
   176  
   177  	if params.lgwin > 24 {
   178  		/* Different hashers for large window brotli: not for qualities <= 2,
   179  		   these are too fast for large window. Not for qualities >= 10: their
   180  		   hasher already works well with large window. So the changes are:
   181  		   H3 --> H35: for quality 3.
   182  		   H54 --> H55: for quality 4 with size hint > 1MB
   183  		   H6 --> H65: for qualities 5, 6, 7, 8, 9. */
   184  		if hparams.type_ == 3 {
   185  			hparams.type_ = 35
   186  		}
   187  
   188  		if hparams.type_ == 54 {
   189  			hparams.type_ = 55
   190  		}
   191  
   192  		if hparams.type_ == 6 {
   193  			hparams.type_ = 65
   194  		}
   195  	}
   196  }