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 }