123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- package brotli
- const fastOnePassCompressionQuality = 0
- const fastTwoPassCompressionQuality = 1
- const zopflificationQuality = 10
- const hqZopflificationQuality = 11
- const maxQualityForStaticEntropyCodes = 2
- const minQualityForBlockSplit = 4
- const minQualityForNonzeroDistanceParams = 4
- const minQualityForOptimizeHistograms = 4
- const minQualityForExtensiveReferenceSearch = 5
- const minQualityForContextModeling = 5
- const minQualityForHqContextModeling = 7
- const minQualityForHqBlockSplitting = 10
- /* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
- so we buffer at most this much literals and commands. */
- const maxNumDelayedSymbols = 0x2FFF
- /* Returns hash-table size for quality levels 0 and 1. */
- func maxHashTableSize(quality int) uint {
- if quality == fastOnePassCompressionQuality {
- return 1 << 15
- } else {
- return 1 << 17
- }
- }
- /* The maximum length for which the zopflification uses distinct distances. */
- const maxZopfliLenQuality10 = 150
- const maxZopfliLenQuality11 = 325
- /* Do not thoroughly search when a long copy is found. */
- const longCopyQuickStep = 16384
- func maxZopfliLen(params *encoderParams) uint {
- if params.quality <= 10 {
- return maxZopfliLenQuality10
- } else {
- return maxZopfliLenQuality11
- }
- }
- /* Number of best candidates to evaluate to expand Zopfli chain. */
- func maxZopfliCandidates(params *encoderParams) uint {
- if params.quality <= 10 {
- return 1
- } else {
- return 5
- }
- }
- func sanitizeParams(params *encoderParams) {
- params.quality = brotli_min_int(maxQuality, brotli_max_int(minQuality, params.quality))
- if params.quality <= maxQualityForStaticEntropyCodes {
- params.large_window = false
- }
- if params.lgwin < minWindowBits {
- params.lgwin = minWindowBits
- } else {
- var max_lgwin int
- if params.large_window {
- max_lgwin = largeMaxWindowBits
- } else {
- max_lgwin = maxWindowBits
- }
- if params.lgwin > uint(max_lgwin) {
- params.lgwin = uint(max_lgwin)
- }
- }
- }
- /* Returns optimized lg_block value. */
- func computeLgBlock(params *encoderParams) int {
- var lgblock int = params.lgblock
- if params.quality == fastOnePassCompressionQuality || params.quality == fastTwoPassCompressionQuality {
- lgblock = int(params.lgwin)
- } else if params.quality < minQualityForBlockSplit {
- lgblock = 14
- } else if lgblock == 0 {
- lgblock = 16
- if params.quality >= 9 && params.lgwin > uint(lgblock) {
- lgblock = brotli_min_int(18, int(params.lgwin))
- }
- } else {
- lgblock = brotli_min_int(maxInputBlockBits, brotli_max_int(minInputBlockBits, lgblock))
- }
- return lgblock
- }
- /* Returns log2 of the size of main ring buffer area.
- Allocate at least lgwin + 1 bits for the ring buffer so that the newly
- added block fits there completely and we still get lgwin bits and at least
- read_block_size_bits + 1 bits because the copy tail length needs to be
- smaller than ring-buffer size. */
- func computeRbBits(params *encoderParams) int {
- return 1 + brotli_max_int(int(params.lgwin), params.lgblock)
- }
- func maxMetablockSize(params *encoderParams) uint {
- var bits int = brotli_min_int(computeRbBits(params), maxInputBlockBits)
- return uint(1) << uint(bits)
- }
- /* When searching for backward references and have not seen matches for a long
- time, we can skip some match lookups. Unsuccessful match lookups are very
- expensive and this kind of a heuristic speeds up compression quite a lot.
- At first 8 byte strides are taken and every second byte is put to hasher.
- After 4x more literals stride by 16 bytes, every put 4-th byte to hasher.
- Applied only to qualities 2 to 9. */
- func literalSpreeLengthForSparseSearch(params *encoderParams) uint {
- if params.quality < 9 {
- return 64
- } else {
- return 512
- }
- }
- func chooseHasher(params *encoderParams, hparams *hasherParams) {
- if params.quality > 9 {
- hparams.type_ = 10
- } else if params.quality == 4 && params.size_hint >= 1<<20 {
- hparams.type_ = 54
- } else if params.quality < 5 {
- hparams.type_ = params.quality
- } else if params.lgwin <= 16 {
- if params.quality < 7 {
- hparams.type_ = 40
- } else if params.quality < 9 {
- hparams.type_ = 41
- } else {
- hparams.type_ = 42
- }
- } else if params.size_hint >= 1<<20 && params.lgwin >= 19 {
- hparams.type_ = 6
- hparams.block_bits = params.quality - 1
- hparams.bucket_bits = 15
- hparams.hash_len = 5
- if params.quality < 7 {
- hparams.num_last_distances_to_check = 4
- } else if params.quality < 9 {
- hparams.num_last_distances_to_check = 10
- } else {
- hparams.num_last_distances_to_check = 16
- }
- } else {
- hparams.type_ = 5
- hparams.block_bits = params.quality - 1
- if params.quality < 7 {
- hparams.bucket_bits = 14
- } else {
- hparams.bucket_bits = 15
- }
- if params.quality < 7 {
- hparams.num_last_distances_to_check = 4
- } else if params.quality < 9 {
- hparams.num_last_distances_to_check = 10
- } else {
- hparams.num_last_distances_to_check = 16
- }
- }
- if params.lgwin > 24 {
- /* Different hashers for large window brotli: not for qualities <= 2,
- these are too fast for large window. Not for qualities >= 10: their
- hasher already works well with large window. So the changes are:
- H3 --> H35: for quality 3.
- H54 --> H55: for quality 4 with size hint > 1MB
- H6 --> H65: for qualities 5, 6, 7, 8, 9. */
- if hparams.type_ == 3 {
- hparams.type_ = 35
- }
- if hparams.type_ == 54 {
- hparams.type_ = 55
- }
- if hparams.type_ == 6 {
- hparams.type_ = 65
- }
- }
- }
|