[145] | 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 | }
|
---|