quality.go 5.3 KB

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