Updates to Brotli compression format, decoder and encoder

This commit contains a batch of changes that were made to the Brotli
compression algorithm in the last month. Most important changes:

   * Updated spec
   * Changed Huffman code length alphabet to use run length codes more
     efficiently, based on a suggestion by Robert Obryk
   * Changed encoding of the number of Huffman code lengths (HLEN)
   * Changed encoding of the number of Huffman trees (NTREES)
   * Added support for uncompressed meta-blocks
This commit is contained in:
Zoltan Szabadka
2013-12-12 13:18:04 +01:00
parent fe79fac8da
commit e70949119a
11 changed files with 411 additions and 263 deletions
+150 -75
View File
@@ -52,9 +52,8 @@ Abstract
such as Unix filters; such as Unix filters;
* Compresses data with efficiency comparable to the best * Compresses data with efficiency comparable to the best
currently available general-purpose compression methods, currently available general-purpose compression methods,
and in particular considerably better than the gzip and in particular considerably better than the gzip program;
program and decompresses much faster than the LZMA * Decompresses much faster than the LZMA implementations.
implementations.
The data format defined by this specification does not attempt to: The data format defined by this specification does not attempt to:
* Allow random access to compressed data; * Allow random access to compressed data;
@@ -196,23 +195,50 @@ Abstract
The sequence of each type of value in the representation of a command The sequence of each type of value in the representation of a command
(insert-and-copy lengths, literals and distances) within a meta- (insert-and-copy lengths, literals and distances) within a meta-
block is further divided into blocks. In other words, each meta-block block is further divided into blocks. In the "brotli" format, blocks
has a series of insert-and-copy length blocks, a series of literal are not contiguous chunks of compressed data, but rather the pieces
blocks and a series of distance blocks. These are also called the of compressed data belonging to a block are interleaved with pieces
three block categories: a meta-block has a series of blocks for each of data belonging to other blocks. Each meta-block can be logically
block category. The subsequent blocks within each block category have decomposed into a series of insert-and-copy length blocks, a series
different block types, but blocks further away in the block sequence of literal blocks and a series of distance blocks. These are also
can have the same types. The block types are numbered from 0 to the called the three block categories: a meta-block has a series of
maximum block type number of 253 and the first block of each block blocks for each block category. Note that the physical structure of
category has type 0. The block structure of a meta-block is the meta-block is a series of commands, while the three series of
represented by the sequence of block-switch commands for each block blocks is the logical structure. Consider the following example:
category, where a block-switch command is a pair <block type, block
length>. The block-switch commands are represented in the compressed (IaC0, L0, L1, L2, D0)(IaC1, D1)(IaC2, L3, L4, D2)(IaC3, L5, D3)
data before the start of each new block using a Huffman code tree for
The meta-block here has 4 commands, and each three types of symbols
within these commands can be rearranged into for example the
following logical block structure:
[IaC0, IaC1][IaC2, IaC3] <-- block types 0 and 1
[L0, L1][L2, L3, L4][L5] <-- block types 0, 1, and 0
[D0][D1, D2, D3] <-- block types 0 and 1
The subsequent blocks within each block category must have different
block types, but blocks further away in the block sequence can have
the same types. The block types are numbered from 0 to the maximum
block type number of 255 and the first block of each block category
must have type 0. The block structure of a meta-block is represented
by the sequence of block-switch commands for each block category,
where a block-switch command is a pair <block type, block length>.
The block-switch commands are represented in the compressed data
before the start of each new block using a Huffman code tree for
block types and a separate Huffman code tree for block lengths for block types and a separate Huffman code tree for block lengths for
each block category. The code trees for block types and lengths each block category. In the above example the physical layout of the
(total of six Huffman code trees) appear in a compact form in the meta-block is the following:
meta-block header.
IaC0 L0 L1 LBlockSwitch(1, 3) L2 D0 IaC1 DBlockSwitch(1, 1) D1
IaCBlockSwitch(1, 2) IaC2 L3 L4 D2 IaC3 LBlockSwitch(0, 1) D3
Note that the block switch commands for the first blocks are not part
of the meta-block compressed data part, they are encoded in the meta-
block header. The code trees for block types and lengths (total of
six Huffman code trees) appear in a compact form in the meta-block
header.
Each type of value (insert-and-copy lengths, literals and distances) Each type of value (insert-and-copy lengths, literals and distances)
can be encoded with any Huffman tree from a collection of Huffman can be encoded with any Huffman tree from a collection of Huffman
@@ -235,7 +261,7 @@ Abstract
and the context map), the meta-block header contains the number of and the context map), the meta-block header contains the number of
input bytes in the meta-block and two additional parameters used in input bytes in the meta-block and two additional parameters used in
the representation of copy distances (number of "postfix bits" and the representation of copy distances (number of "postfix bits" and
number of direct distance codes, see later). number of direct distance codes).
3. Compressed representation of Huffman codes 3. Compressed representation of Huffman codes
@@ -383,8 +409,7 @@ Abstract
length codes, the alphabet size is 704. For block length codes, length codes, the alphabet size is 704. For block length codes,
the alphabet size is 26. For distance codes, block type codes and the alphabet size is 26. For distance codes, block type codes and
the Huffman codes used in compressing the context map, the the Huffman codes used in compressing the context map, the
alphabet size is dynamic and is based on other parameters (see alphabet size is dynamic and is based on other parameters.
later).
3.4. Simple Huffman codes 3.4. Simple Huffman codes
@@ -446,13 +471,19 @@ Abstract
If this is the first code length, or all previous If this is the first code length, or all previous
code lengths are zero, a code length of 8 is code lengths are zero, a code length of 8 is
repeated 3 - 6 times repeated 3 - 6 times
Example: Codes 7, 16 (+2 bits 11), A repeated code length code of 16 modifies the
16 (+2 bits 10) will expand to repeat count of the previous one as follows:
12 code lengths of 7 (1 + 6 + 5) repeat count = (4 * (repeat count - 2)) +
(3 - 6 on the next 2 bits)
Example: Codes 7, 16 (+2 bits 11), 16 (+2 bits 10)
will expand to 22 code lengths of 7
(1 + 4 * (6 - 2) + 5)
17: Repeat a code length of 0 for 3 - 10 times. 17: Repeat a code length of 0 for 3 - 10 times.
(3 bits of length) (3 bits of length)
18: Repeat a code length of 0 for 11 - 138 times A repeated code length code of 17 modifies the
(7 bits of length) repeat count of the previous one as follows:
repeat count = (8 * (repeat count - 2)) +
(3 - 10 on the next 3 bits)
A code length of 0 indicates that the corresponding symbol in the A code length of 0 indicates that the corresponding symbol in the
alphabet will not occur in the compressed data, and should not alphabet will not occur in the compressed data, and should not
@@ -475,12 +506,12 @@ Abstract
follows: follows:
1 bit: 0, indicating a complex Huffman code 1 bit: 0, indicating a complex Huffman code
4 bits: HCLEN, # of code length codes - 4 4 bits: HCLEN, # of code length codes - 3
1 bit : HSKIP, if 1, skip over first two code length codes 1 bit : HSKIP, if 1, skip over first two code length codes
(HCLEN + 4 - 2 * HSKIP) code lengths for symbols in the code (HCLEN + 3 - 2 * HSKIP) code lengths for symbols in the code
length alphabet given just above, in the order: 1, 2, 3, length alphabet given just above, in the order: 1, 2, 3,
4, 0, 17, 18, 5, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 4, 0, 17, 5, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15
If HSKIP is 1, code lengths of code length symbols 1 and If HSKIP is 1, code lengths of code length symbols 1 and
2 are implicit zeros. Code lengths of code length symbols 2 are implicit zeros. Code lengths of code length symbols
@@ -495,19 +526,18 @@ Abstract
1 bit: HLENINC, if 1, the number of code length symbols is 1 bit: HLENINC, if 1, the number of code length symbols is
encoded next encoded next
3 bits: HNBITPAIRS, (# of bit pairs to represent HLEN) - 2, 7-8 bits: HLEN, # of code length symbols, with the following
appears only if HLENINC = 1 encoding: values 4 - 67 with bit pattern 0xxxxxx,
values 68 - 195 with bit pattern 1xxxxxxx, appears
2 * HNBITPAIRS + 2 bits: HLEN, # of code length symbols - 2, only if HLENINC = 1
appears only if HLENINC = 1
Sequence of code lengths symbols, encoded using the code Sequence of code lengths symbols, encoded using the code
length Huffman code. The number of code length symbols length Huffman code. The number of code length symbols
is either HLEN + 2 (in case of HLENINC = 1), or as many is either HLEN (in case of HLENINC = 1), or as many as is
as is needed to assign a code length to each symbol in needed to assign a code length to each symbol in the
the alphabet (i.e. the alphabet size minus the sum of all alphabet (i.e. the alphabet size minus the sum of all the
the repeat lengths defined by extra bits of code length repeat lengths defined by extra bits of code length
symbols 16 - 18). In case of HLENINC = 1, all symbols symbols 16 and 17). In case of HLENINC = 1, all symbols
not assigned a code length have implicit code length 0. not assigned a code length have implicit code length 0.
3.6. Validity of the Huffman code 3.6. Validity of the Huffman code
@@ -582,7 +612,7 @@ Abstract
the NDIRECT direct distance codes have any extra bits. the NDIRECT direct distance codes have any extra bits.
Distance codes 16 + NDIRECT and greater all have extra bits, the Distance codes 16 + NDIRECT and greater all have extra bits, the
number of extra bits for a distance code `dcode' is given by the number of extra bits for a distance code "dcode" is given by the
following formula: following formula:
ndistbits = 1 + ((dcode - NDIRECT - 16) >> (NPOSTFIX + 1)) ndistbits = 1 + ((dcode - NDIRECT - 16) >> (NPOSTFIX + 1))
@@ -590,8 +620,8 @@ Abstract
The maximum number of extra bits is 24, therefore the size of the The maximum number of extra bits is 24, therefore the size of the
distance code alphabet is (16 + NDIRECT + (48 << NPOSTFIX)). distance code alphabet is (16 + NDIRECT + (48 << NPOSTFIX)).
Given a distance code `dcode' (>= 16 + NDIRECT), and extra bits Given a distance code "dcode" (>= 16 + NDIRECT), and extra bits
`dextra', the backward distance is given by the following formula: "dextra", the backward distance is given by the following formula:
hcode = (dcode - NDIRECT - 16) >> NPOSTFIX hcode = (dcode - NDIRECT - 16) >> NPOSTFIX
lcode = (dcode - NDIRECT - 16) & POSTFIX_MASK lcode = (dcode - NDIRECT - 16) & POSTFIX_MASK
@@ -704,8 +734,8 @@ Abstract
alphabet. A block type code 0 means that the block type is the same alphabet. A block type code 0 means that the block type is the same
as the type of the second last block from the same block category, as the type of the second last block from the same block category,
while a block type code 1 means that the block type equals the last while a block type code 1 means that the block type equals the last
block type plus one. Block type codes 2 - 255 represent block types block type plus one. Block type codes 2 - 257 represent block types
0 - 253. The second last and last block types are initialized with 0 0 - 255. The second last and last block types are initialized with 0
and 1, respectively, at the beginning of each meta-block. and 1, respectively, at the beginning of each meta-block.
The first block type of each block category must be 0, and the block The first block type of each block category must be 0, and the block
@@ -851,10 +881,9 @@ Abstract
7.2. Context id for distances 7.2. Context id for distances
The context for encoding the next distance code is defined by the The context for encoding a distance code is defined by the copy
copy length corresponding to the distance. The context ids are length corresponding to the distance. The context ids are 0, 1, 2,
0, 1, 2, and 3 for copy lengths 2, 3, 4, and more than 4, and 3 for copy lengths 2, 3, 4, and more than 4, respectively.
respectively.
7.3. Encoding of the context map 7.3. Encoding of the context map
@@ -869,7 +898,7 @@ Abstract
CMAPL[0..(64 * NBLTYPESL - 1)] and CMAPD[0..(4 * NBLTYPESD - 1)]. CMAPL[0..(64 * NBLTYPESL - 1)] and CMAPD[0..(4 * NBLTYPESD - 1)].
The index of the Huffman tree for encoding a literal or distance The index of the Huffman tree for encoding a literal or distance
code with context id `cid' and block type `bltype' is code with context id "cid" and block type "bltype" is
index of literal Huffman tree = CMAPL[bltype * 64 + cid] index of literal Huffman tree = CMAPL[bltype * 64 + cid]
@@ -899,9 +928,6 @@ Abstract
now define the format of the context map (the same format is used now define the format of the context map (the same format is used
for literal and distance context maps): for literal and distance context maps):
8 bits: NTREES - 1, if NTREES = 1 all values in the context
map are zeros, and no further bits are needed for
the context map encoding. Otherwise,
1-5 bits: RLEMAX, 0 is encoded with one 0 bit, and values 1-5 bits: RLEMAX, 0 is encoded with one 0 bit, and values
1 - 16 are encoded with bit pattern 1xxxx 1 - 16 are encoded with bit pattern 1xxxx
@@ -914,7 +940,9 @@ Abstract
transform on the values in the context map to get transform on the values in the context map to get
the Huffman code indexes the Huffman code indexes
8. Language-based static dictionaries For the encoding of NTREES see Section 9.2.
8. Static dictionary
At any given point during decoding the compressed data, a reference At any given point during decoding the compressed data, a reference
to a duplicated string in the output produced so far has a maximum to a duplicated string in the output produced so far has a maximum
@@ -923,24 +951,44 @@ Abstract
from the input stream, as described in section 4, can produce from the input stream, as described in section 4, can produce
distances that are greater than this maximum allowed value. The distances that are greater than this maximum allowed value. The
difference between these distances and the first invalid distance difference between these distances and the first invalid distance
value is treated as reference to a word in one of the language-based value is treated as reference to a word in the static dictionary
static dictionaries given in Appendix A. The id of the static given in Appendix A. The maximum valid copy length for a static
dictionary is determined by the copy length of the command: dictionary reference is 24. The static dictionary has three parts:
dictionary id = copy length - 4 * DICT[0..DICTSIZE], an array of bytes
word id = distance - (max allowed distance + 1) * DOFFSET[0..24], an array of byte offset values for each length
* NDBITS[0..24], an array of bit-depth values for each length
If the copy length is less than 4, or the dictionary id is invalid, The number of static dictionary words for a given length is:
the compressed data set is invalid and must be discarded.
Each of the static dictionaries has 2^N words, and the index of the NWORDS[length] = 0 (if length < 3)
referenced word is formed by the N least significant bits of the word NWORDS[length] = (1 << NDBITS[lengths]) (if length >= 3)
id. The word id right-shifted by N gives the index to one of the word
transformations given in Appendix B. If this transformation index is DOFFSET and DICTSIZE are defined by the following recursion:
greater than the maximum transformation index, the compressed data
set is invalid and must be discarded. The string copied to the output DOFFSET[0] = 0
stream is computed by applying the transformation to the referenced DOFFSET[length + 1] = DOFFSET[length] + length * NWORDS[length]
static dictionary word. DICTSIZE = DOFFSET[24] + 24 * NWORDS[24]
The offset of a word within the DICT array for a given length and
index is:
offset(length, index) = DOFFSET[length] + index * length
Each static dictionary word has 64 different forms, given by applying
a word transformation to a base word in the DICT array. The list of
word transformations is given in Appendix B. The static dictionary
word for a <length, distance> pair can be reconstructed as follows:
word_id = distance - (max allowed distance + 1)
index = word_id % NWORDS[length]
base_word = DICT[offset(length, index)..offset(length, index+1))
transform_id = word_id >> NBITS[length]
The string copied to the output stream is computed by applying the
transformation to the base dictionary word. If transform_id is
greater than 63 or length is greater than 24, the compressed data set
is invalid and must be discarded.
9. Compressed data format 9. Compressed data format
@@ -979,6 +1027,11 @@ Abstract
(MNIBBLES + 4) x 4 bits: MLEN - 1, where MLEN is the length (MNIBBLES + 4) x 4 bits: MLEN - 1, where MLEN is the length
of the meta-block in the input data in bytes of the meta-block in the input data in bytes
1 bit: ISUNCOMPRESSED, if set to 1, any bits of input up to
the next byte boundary are ignored, and the rest of
the meta-block contains MLEN bytes of literal data;
this field is only present if ISLAST bit is not set
1-11 bits: NBLTYPESL, # of literal block types, encoded with 1-11 bits: NBLTYPESL, # of literal block types, encoded with
the following variable length code: the following variable length code:
@@ -1035,17 +1088,25 @@ Abstract
NBLTYPESL x 2 bits: context mode for each literal block type NBLTYPESL x 2 bits: context mode for each literal block type
1-11 bits: NTREESL, # of literal Huffman trees, encoded with
the same variable length code as NBLTYPESL
Literal context map, encoded as described in Paragraph 7.3, Literal context map, encoded as described in Paragraph 7.3,
the number of Huffman tree indexes is denoted by NHTREESL appears only if NTREESL >= 2, otherwise the context map
has only zero values
1-11 bits: NTREESD, # of distance Huffman trees, encoded with
the same variable length code as NBLTYPESD
Distance context map, encoded as described in Paragraph 7.3, Distance context map, encoded as described in Paragraph 7.3,
the number of Huffman tree indexes is denoted by NHTREESD appears only if NTREESD >= 2, otherwise the context map
has only zero values
NHTREESL Huffman codes for literals NTREESL Huffman codes for literals
NBLTYPESI Huffman codes for insert-and-copy lengths NBLTYPESI Huffman codes for insert-and-copy lengths
NHTREESD Huffman codes for distances NTREESD Huffman codes for distances
9.3. Format of the meta-block data 9.3. Format of the meta-block data
@@ -1109,6 +1170,12 @@ Abstract
if ISEMPTY if ISEMPTY
break from loop break from loop
read MLEN read MLEN
if not ISLAST
read ISUNCOMPRESSED bit
if ISUNCOMPRESSED
skip any bits up to the next byte boundary
copy MLEN bytes of input to the output stream
continue to the next meta-block
loop for each three block categories (i = L, I, D) loop for each three block categories (i = L, I, D)
read NBLTYPESi read NBLTYPESi
if NBLTYPESi >= 2 if NBLTYPESi >= 2
@@ -1122,8 +1189,16 @@ Abstract
set block length, BLEN_i to 268435456 set block length, BLEN_i to 268435456
read NPOSTFIX and NDIRECT read NPOSTFIX and NDIRECT
read array of literal context modes, CMODE[] read array of literal context modes, CMODE[]
read literal context map, CMAPL[] read NTREESL
read distance context map, CMAPD[] if NTREESL >= 2
read literal context map, CMAPL[]
else
fill CMAPL[] with zeros
read NTREESD
if NTREESD >= 2
read distance context map, CMAPD[]
else
fill CMAPD[] with zeros
read array of Huffman codes for literals, HTREEL[] read array of Huffman codes for literals, HTREEL[]
read array of Huffman codes for insert-and-copy, HTREEI[] read array of Huffman codes for insert-and-copy, HTREEI[]
read array of Huffman codes for distances, HTREED[] read array of Huffman codes for distances, HTREED[]
+10
View File
@@ -59,6 +59,12 @@ static BROTLI_INLINE uint32_t BrotliPrefetchBits(BrotliBitReader* const br) {
// For jumping over a number of bits in the bit stream when accessed with // For jumping over a number of bits in the bit stream when accessed with
// BrotliPrefetchBits and BrotliFillBitWindow. // BrotliPrefetchBits and BrotliFillBitWindow.
static BROTLI_INLINE void BrotliSetBitPos(BrotliBitReader* const br, int val) { static BROTLI_INLINE void BrotliSetBitPos(BrotliBitReader* const br, int val) {
#ifdef BROTLI_DECODE_DEBUG
int n_bits = val - br->bit_pos_;
const uint32_t bval = (uint32_t)(br->val_ >> br->bit_pos_) & kBitMask[n_bits];
printf("[BrotliReadBits] %010ld %2d val: %6x\n",
(br->pos_ << 3) + br->bit_pos_ - 64, n_bits, bval);
#endif
br->bit_pos_ = val; br->bit_pos_ = val;
} }
@@ -145,6 +151,10 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
BrotliBitReader* const br, int n_bits) { BrotliBitReader* const br, int n_bits) {
BrotliFillBitWindow(br); BrotliFillBitWindow(br);
const uint32_t val = (uint32_t)(br->val_ >> br->bit_pos_) & kBitMask[n_bits]; const uint32_t val = (uint32_t)(br->val_ >> br->bit_pos_) & kBitMask[n_bits];
#ifdef BROTLI_DECODE_DEBUG
printf("[BrotliReadBits] %010ld %2d val: %6x\n",
(br->pos_ << 3) + br->bit_pos_ - 64, n_bits, val);
#endif
br->bit_pos_ += n_bits; br->bit_pos_ += n_bits;
return val; return val;
} }
+74 -40
View File
@@ -38,20 +38,16 @@ extern "C" {
#endif #endif
static const int kDefaultCodeLength = 8; static const int kDefaultCodeLength = 8;
static const int kCodeLengthLiterals = 16;
static const int kCodeLengthRepeatCode = 16; static const int kCodeLengthRepeatCode = 16;
static const int kCodeLengthExtraBits[3] = { 2, 3, 7 };
static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
static const int kNumLiteralCodes = 256; static const int kNumLiteralCodes = 256;
static const int kNumInsertAndCopyCodes = 704; static const int kNumInsertAndCopyCodes = 704;
static const int kNumBlockLengthCodes = 26; static const int kNumBlockLengthCodes = 26;
static const int kLiteralContextBits = 6; static const int kLiteralContextBits = 6;
static const int kDistanceContextBits = 2; static const int kDistanceContextBits = 2;
#define CODE_LENGTH_CODES 19 #define CODE_LENGTH_CODES 18
static const uint8_t kCodeLengthCodeOrder[CODE_LENGTH_CODES] = { static const uint8_t kCodeLengthCodeOrder[CODE_LENGTH_CODES] = {
1, 2, 3, 4, 0, 17, 18, 5, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 1, 2, 3, 4, 0, 17, 5, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}; };
#define NUM_DISTANCE_SHORT_CODES 16 #define NUM_DISTANCE_SHORT_CODES 16
@@ -71,11 +67,26 @@ static BROTLI_INLINE int DecodeWindowBits(BrotliBitReader* br) {
} }
} }
// Decodes a number in the range [0..255], by reading 1 - 11 bits.
static BROTLI_INLINE int DecodeVarLenUint8(BrotliBitReader* br) {
if (BrotliReadBits(br, 1)) {
int nbits = BrotliReadBits(br, 3);
if (nbits == 0) {
return 1;
} else {
return BrotliReadBits(br, nbits) + (1 << nbits);
}
}
return 0;
}
static void DecodeMetaBlockLength(BrotliBitReader* br, static void DecodeMetaBlockLength(BrotliBitReader* br,
size_t* meta_block_length, size_t* meta_block_length,
int* input_end) { int* input_end,
int* is_uncompressed) {
*input_end = BrotliReadBits(br, 1); *input_end = BrotliReadBits(br, 1);
*meta_block_length = 0; *meta_block_length = 0;
*is_uncompressed = 0;
if (*input_end && BrotliReadBits(br, 1)) { if (*input_end && BrotliReadBits(br, 1)) {
return; return;
} }
@@ -85,6 +96,9 @@ static void DecodeMetaBlockLength(BrotliBitReader* br,
*meta_block_length |= BrotliReadBits(br, 4) << (i * 4); *meta_block_length |= BrotliReadBits(br, 4) << (i * 4);
} }
++(*meta_block_length); ++(*meta_block_length);
if (!*input_end) {
*is_uncompressed = BrotliReadBits(br, 1);
}
} }
// Decodes the next Huffman code from bit-stream. // Decodes the next Huffman code from bit-stream.
@@ -130,6 +144,8 @@ static int ReadHuffmanCodeLengths(
int max_symbol; int max_symbol;
int decode_number_of_code_length_codes; int decode_number_of_code_length_codes;
int prev_code_len = kDefaultCodeLength; int prev_code_len = kDefaultCodeLength;
int repeat = 0;
int repeat_length = 0;
HuffmanTree tree; HuffmanTree tree;
if (!BrotliHuffmanTreeBuildImplicit(&tree, code_length_code_lengths, if (!BrotliHuffmanTreeBuildImplicit(&tree, code_length_code_lengths,
@@ -146,9 +162,11 @@ static int ReadHuffmanCodeLengths(
decode_number_of_code_length_codes = BrotliReadBits(br, 1); decode_number_of_code_length_codes = BrotliReadBits(br, 1);
BROTLI_LOG_UINT(decode_number_of_code_length_codes); BROTLI_LOG_UINT(decode_number_of_code_length_codes);
if (decode_number_of_code_length_codes) { if (decode_number_of_code_length_codes) {
const int length_nbits = 2 + 2 * BrotliReadBits(br, 3); if (BrotliReadBits(br, 1)) {
max_symbol = 2 + BrotliReadBits(br, length_nbits); max_symbol = 68 + BrotliReadBits(br, 7);
BROTLI_LOG_UINT(length_nbits); } else {
max_symbol = 4 + BrotliReadBits(br, 6);
}
if (max_symbol > num_symbols) { if (max_symbol > num_symbols) {
printf("[ReadHuffmanCodeLengths] max_symbol > num_symbols (%d vs %d)\n", printf("[ReadHuffmanCodeLengths] max_symbol > num_symbols (%d vs %d)\n",
max_symbol, num_symbols); max_symbol, num_symbols);
@@ -160,7 +178,7 @@ static int ReadHuffmanCodeLengths(
BROTLI_LOG_UINT(max_symbol); BROTLI_LOG_UINT(max_symbol);
symbol = 0; symbol = 0;
while (symbol < num_symbols) { while (symbol + repeat < num_symbols) {
int code_len; int code_len;
if (max_symbol-- == 0) break; if (max_symbol-- == 0) break;
if (!BrotliReadMoreInput(br)) { if (!BrotliReadMoreInput(br)) {
@@ -169,30 +187,36 @@ static int ReadHuffmanCodeLengths(
} }
code_len = ReadSymbol(&tree, br); code_len = ReadSymbol(&tree, br);
BROTLI_LOG_UINT(symbol); BROTLI_LOG_UINT(symbol);
BROTLI_LOG_UINT(repeat);
BROTLI_LOG_UINT(repeat_length);
BROTLI_LOG_UINT(code_len); BROTLI_LOG_UINT(code_len);
if (code_len < kCodeLengthLiterals) { if ((code_len < kCodeLengthRepeatCode) ||
(code_len == kCodeLengthRepeatCode && repeat_length == 0) ||
(code_len > kCodeLengthRepeatCode && repeat_length > 0)) {
while (repeat > 0) {
code_lengths[symbol++] = repeat_length;
--repeat;
}
}
if (code_len < kCodeLengthRepeatCode) {
code_lengths[symbol++] = code_len; code_lengths[symbol++] = code_len;
if (code_len != 0) prev_code_len = code_len; if (code_len != 0) prev_code_len = code_len;
} else { } else {
const int use_prev = (code_len == kCodeLengthRepeatCode); const int extra_bits = code_len - 14;
const int slot = code_len - kCodeLengthLiterals; if (repeat > 0) {
const int extra_bits = kCodeLengthExtraBits[slot]; repeat -= 2;
const int repeat_offset = kCodeLengthRepeatOffsets[slot]; repeat <<= extra_bits;
const int length = use_prev ? prev_code_len : 0;
int repeat = BrotliReadBits(br, extra_bits) + repeat_offset;
BROTLI_LOG_UINT(repeat);
BROTLI_LOG_UINT(length);
if (symbol + repeat > num_symbols) {
printf("[ReadHuffmanCodeLengths] symbol + repeat > num_symbols "
"(%d + %d vs %d)\n", symbol, repeat, num_symbols);
goto End;
} else {
while (repeat-- > 0) {
code_lengths[symbol++] = length;
}
} }
repeat += BrotliReadBits(br, extra_bits) + 3;
repeat_length = (code_len == kCodeLengthRepeatCode ? prev_code_len : 0);
} }
} }
if (symbol + repeat > num_symbols) {
printf("[ReadHuffmanCodeLengths] symbol + repeat > num_symbols "
"(%d + %d vs %d)\n", symbol, repeat, num_symbols);
goto End;
}
while (repeat-- > 0) code_lengths[symbol++] = repeat_length;
while (symbol < num_symbols) code_lengths[symbol++] = 0; while (symbol < num_symbols) code_lengths[symbol++] = 0;
ok = 1; ok = 1;
@@ -256,7 +280,7 @@ static int ReadHuffmanCode(int alphabet_size,
} else { // Decode Huffman-coded code lengths. } else { // Decode Huffman-coded code lengths.
int i; int i;
uint8_t code_length_code_lengths[CODE_LENGTH_CODES] = { 0 }; uint8_t code_length_code_lengths[CODE_LENGTH_CODES] = { 0 };
const int num_codes = BrotliReadBits(br, 4) + 4; const int num_codes = BrotliReadBits(br, 4) + 3;
BROTLI_LOG_UINT(num_codes); BROTLI_LOG_UINT(num_codes);
if (num_codes > CODE_LENGTH_CODES) { if (num_codes > CODE_LENGTH_CODES) {
return 0; return 0;
@@ -434,7 +458,7 @@ static int DecodeContextMap(int context_map_size,
printf("[DecodeContextMap] Unexpected end of input.\n"); printf("[DecodeContextMap] Unexpected end of input.\n");
return 0; return 0;
} }
*num_htrees = BrotliReadBits(br, 8) + 1; *num_htrees = DecodeVarLenUint8(br) + 1;
BROTLI_LOG_UINT(context_map_size); BROTLI_LOG_UINT(context_map_size);
BROTLI_LOG_UINT(*num_htrees); BROTLI_LOG_UINT(*num_htrees);
@@ -569,7 +593,8 @@ int BrotliDecompressedSize(size_t encoded_size,
DecodeWindowBits(&br); DecodeWindowBits(&br);
size_t meta_block_len; size_t meta_block_len;
int input_end; int input_end;
DecodeMetaBlockLength(&br, &meta_block_len, &input_end); int is_uncompressed;
DecodeMetaBlockLength(&br, &meta_block_len, &input_end, &is_uncompressed);
if (!input_end) { if (!input_end) {
return 0; return 0;
} }
@@ -633,7 +658,8 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
while (!input_end && ok) { while (!input_end && ok) {
size_t meta_block_len = 0; size_t meta_block_len = 0;
size_t meta_block_end_pos; size_t meta_block_end_pos;
uint32_t block_length[3] = { UINT32_MAX, UINT32_MAX, UINT32_MAX }; int is_uncompressed;
uint32_t block_length[3] = { 1 << 28, 1 << 28, 1 << 28 };
int block_type[3] = { 0 }; int block_type[3] = { 0 };
int num_block_types[3] = { 1, 1, 1 }; int num_block_types[3] = { 1, 1, 1 };
int block_type_rb[6] = { 0, 1, 0, 1, 0, 1 }; int block_type_rb[6] = { 0, 1, 0, 1, 0, 1 };
@@ -672,22 +698,30 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
goto End; goto End;
} }
BROTLI_LOG_UINT(pos); BROTLI_LOG_UINT(pos);
DecodeMetaBlockLength(&br, &meta_block_len, &input_end); DecodeMetaBlockLength(&br, &meta_block_len, &input_end, &is_uncompressed);
BROTLI_LOG_UINT(meta_block_len); BROTLI_LOG_UINT(meta_block_len);
if (meta_block_len == 0) { if (meta_block_len == 0) {
goto End; goto End;
} }
meta_block_end_pos = pos + meta_block_len; meta_block_end_pos = pos + meta_block_len;
if (is_uncompressed) {
BrotliSetBitPos(&br, (br.bit_pos_ + 7) & ~7);
for (; pos < meta_block_end_pos; ++pos) {
ringbuffer[pos & ringbuffer_mask] = BrotliReadBits(&br, 8);
if ((pos & ringbuffer_mask) == ringbuffer_mask) {
if (BrotliWrite(output, ringbuffer, ringbuffer_size) < 0) {
ok = 0;
goto End;
}
}
}
goto End;
}
for (i = 0; i < 3; ++i) { for (i = 0; i < 3; ++i) {
block_type_trees[i].root_ = NULL; block_type_trees[i].root_ = NULL;
block_len_trees[i].root_ = NULL; block_len_trees[i].root_ = NULL;
if (BrotliReadBits(&br, 1)) { num_block_types[i] = DecodeVarLenUint8(&br) + 1;
int nbits = BrotliReadBits(&br, 3); if (num_block_types[i] >= 2) {
if (nbits == 0) {
num_block_types[i] = 2;
} else {
num_block_types[i] = BrotliReadBits(&br, nbits) + (1 << nbits) + 1;
}
if (!ReadHuffmanCode( if (!ReadHuffmanCode(
num_block_types[i] + 2, &block_type_trees[i], &br) || num_block_types[i] + 2, &block_type_trees[i], &br) ||
!ReadHuffmanCode(kNumBlockLengthCodes, &block_len_trees[i], &br)) { !ReadHuffmanCode(kNumBlockLengthCodes, &block_len_trees[i], &br)) {
+17 -35
View File
@@ -25,7 +25,7 @@
namespace brotli { namespace brotli {
static const int kHuffmanExtraBits[kCodeLengthCodes] = { static const int kHuffmanExtraBits[kCodeLengthCodes] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3,
}; };
static inline int HuffmanTreeBitCost(const int* counts, const uint8_t* depth) { static inline int HuffmanTreeBitCost(const int* counts, const uint8_t* depth) {
@@ -58,25 +58,29 @@ static inline int HuffmanBitCost(const uint8_t* depth, int length) {
} }
i += reps; i += reps;
if (value == 0) { if (value == 0) {
while (reps > 10) { if (reps < 3) {
++histogram[18];
reps -= 138;
}
if (reps > 2) {
++histogram[17];
} else if (reps > 0) {
histogram[0] += reps; histogram[0] += reps;
} else {
reps -= 3;
while (reps >= 0) {
++histogram[17];
reps >>= 3;
--reps;
}
} }
} else { } else {
tail_start = i; tail_start = i;
++histogram[value]; ++histogram[value];
--reps; --reps;
while (reps > 2) { if (reps < 3) {
++histogram[16];
reps -= 6;
}
if (reps > 0) {
histogram[value] += reps; histogram[value] += reps;
} else {
reps -= 3;
while (reps >= 0) {
++histogram[16];
reps >>= 2;
--reps;
}
} }
} }
} }
@@ -87,7 +91,6 @@ static inline int HuffmanBitCost(const uint8_t* depth, int length) {
// account for rle extra bits // account for rle extra bits
cost[16] += 2; cost[16] += 2;
cost[17] += 3; cost[17] += 3;
cost[18] += 7;
int tree_size = 0; int tree_size = 0;
int bits = 6 + 3 * max_depth; // huffman tree of huffman tree cost int bits = 6 + 3 * max_depth; // huffman tree of huffman tree cost
@@ -95,27 +98,6 @@ static inline int HuffmanBitCost(const uint8_t* depth, int length) {
bits += histogram[i] * cost[i]; // huffman tree bit cost bits += histogram[i] * cost[i]; // huffman tree bit cost
tree_size += histogram[i]; tree_size += histogram[i];
} }
// bit cost adjustment for long trailing zero sequence
int tail_size = length - tail_start;
int tail_bits = 0;
while (tail_size >= 1) {
if (tail_size < 3) {
tail_bits += tail_size * cost[0];
tree_size -= tail_size;
break;
} else if (tail_size < 11) {
tail_bits += cost[17];
--tree_size;
break;
} else {
tail_bits += cost[18];
tail_size -= 138;
--tree_size;
}
}
if (tail_bits > 12) {
bits += ((Log2Ceiling(tree_size - 1) + 1) & ~1) + 3 - tail_bits;
}
return bits; return bits;
} }
+2 -3
View File
@@ -282,9 +282,8 @@ void ClusterBlocks(const DataType* data, const size_t length,
} }
std::vector<HistogramType> clustered_histograms; std::vector<HistogramType> clustered_histograms;
std::vector<int> histogram_symbols; std::vector<int> histogram_symbols;
// Block ids need to fit in one byte and there are two ids reserved for // Block ids need to fit in one byte.
// indicating 'same as last' and 'last plus one'. static const int kMaxNumberOfBlockTypes = 256;
static const int kMaxNumberOfBlockTypes = 254;
ClusterHistograms(histograms, 1, histograms.size(), ClusterHistograms(histograms, 1, histograms.size(),
kMaxNumberOfBlockTypes, kMaxNumberOfBlockTypes,
&clustered_histograms, &clustered_histograms,
+1 -1
View File
@@ -30,7 +30,7 @@ namespace brotli {
struct BlockSplit { struct BlockSplit {
int num_types_; int num_types_;
std::vector<uint8_t> types_; std::vector<uint8_t> types_;
std::vector<uint8_t> type_codes_; std::vector<int> type_codes_;
std::vector<int> lengths_; std::vector<int> lengths_;
}; };
+104 -68
View File
@@ -64,21 +64,32 @@ double TotalBitCost(const std::vector<Histogram<kSize> >& histograms) {
return retval; return retval;
} }
void EncodeSize(size_t len, int* storage_ix, uint8_t* storage) { void EncodeVarLenUint8(int n, int* storage_ix, uint8_t* storage) {
std::vector<uint8_t> len_bytes; if (n == 0) {
do { WriteBits(1, 0, storage_ix, storage);
len_bytes.push_back(len & 0xff); } else {
len >>= 8; WriteBits(1, 1, storage_ix, storage);
} while (len > 0); int nbits = Log2Floor(n);
WriteBits(3, len_bytes.size(), storage_ix, storage); WriteBits(3, nbits, storage_ix, storage);
for (int i = 0; i < len_bytes.size(); ++i) { if (nbits > 0) {
WriteBits(8, len_bytes[i], storage_ix, storage); WriteBits(nbits, n - (1 << nbits), storage_ix, storage);
}
} }
} }
void EncodeMetaBlockLength(size_t meta_block_size, void EncodeMetaBlockLength(size_t meta_block_size,
bool is_last,
bool is_uncompressed,
int* storage_ix, uint8_t* storage) { int* storage_ix, uint8_t* storage) {
WriteBits(1, 0, storage_ix, storage); WriteBits(1, is_last, storage_ix, storage);
if (is_last) {
if (meta_block_size == 0) {
WriteBits(1, 1, storage_ix, storage);
return;
}
WriteBits(1, 0, storage_ix, storage);
}
--meta_block_size;
int num_bits = Log2Floor(meta_block_size) + 1; int num_bits = Log2Floor(meta_block_size) + 1;
if (num_bits < 16) { if (num_bits < 16) {
num_bits = 16; num_bits = 16;
@@ -89,6 +100,9 @@ void EncodeMetaBlockLength(size_t meta_block_size,
meta_block_size >>= 4; meta_block_size >>= 4;
num_bits -= 4; num_bits -= 4;
} }
if (!is_last) {
WriteBits(1, is_uncompressed, storage_ix, storage);
}
} }
template<int kSize> template<int kSize>
@@ -104,16 +118,16 @@ void StoreHuffmanTreeOfHuffmanTreeToBitMask(
const uint8_t* code_length_bitdepth, const uint8_t* code_length_bitdepth,
int* storage_ix, uint8_t* storage) { int* storage_ix, uint8_t* storage) {
static const uint8_t kStorageOrder[kCodeLengthCodes] = { static const uint8_t kStorageOrder[kCodeLengthCodes] = {
1, 2, 3, 4, 0, 17, 18, 5, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 1, 2, 3, 4, 0, 17, 5, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}; };
// Throw away trailing zeros: // Throw away trailing zeros:
int codes_to_store = kCodeLengthCodes; int codes_to_store = kCodeLengthCodes;
for (; codes_to_store > 4; --codes_to_store) { for (; codes_to_store > 3; --codes_to_store) {
if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) { if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
break; break;
} }
} }
WriteBits(4, codes_to_store - 4, storage_ix, storage); WriteBits(4, codes_to_store - 3, storage_ix, storage);
const int skip_two_first = const int skip_two_first =
code_length_bitdepth[kStorageOrder[0]] == 0 && code_length_bitdepth[kStorageOrder[0]] == 0 &&
code_length_bitdepth[kStorageOrder[1]] == 0; code_length_bitdepth[kStorageOrder[1]] == 0;
@@ -144,9 +158,6 @@ void StoreHuffmanTreeToBitMask(
case 17: case 17:
WriteBits(3, extra_bits, storage_ix, storage); WriteBits(3, extra_bits, storage_ix, storage);
break; break;
case 18:
WriteBits(7, extra_bits, storage_ix, storage);
break;
} }
} }
} }
@@ -225,16 +236,16 @@ void StoreHuffmanCode(const EntropyCode<kSize>& code, int alphabet_size,
} }
int trimmed_size = trimmed_histogram.total_count_; int trimmed_size = trimmed_histogram.total_count_;
bool write_length = false; bool write_length = false;
if (trimmed_size > 1 && trimmed_size < huffman_tree_size) { if (trimmed_size >= 4 && trimmed_size <= 195 &&
trimmed_size < huffman_tree_size) {
EntropyCode<kCodeLengthCodes> trimmed_entropy; EntropyCode<kCodeLengthCodes> trimmed_entropy;
BuildEntropyCode(trimmed_histogram, 5, kCodeLengthCodes, &trimmed_entropy); BuildEntropyCode(trimmed_histogram, 5, kCodeLengthCodes, &trimmed_entropy);
int huffman_bit_cost = HuffmanTreeBitCost(huffman_tree_histogram, int huffman_bit_cost = HuffmanTreeBitCost(huffman_tree_histogram,
huffman_tree_entropy); huffman_tree_entropy);
int trimmed_bit_cost = HuffmanTreeBitCost(trimmed_histogram, int trimmed_bit_cost = HuffmanTreeBitCost(trimmed_histogram,
trimmed_entropy);; trimmed_entropy);;
const int nbits = Log2Ceiling(trimmed_size - 1); trimmed_bit_cost += (trimmed_size < 68 ? 7 : 8);
const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2; if (trimmed_bit_cost < huffman_bit_cost) {
if (trimmed_bit_cost + 3 + 2 * nbitpairs < huffman_bit_cost) {
write_length = true; write_length = true;
huffman_tree_size = trimmed_size; huffman_tree_size = trimmed_size;
huffman_tree_entropy = trimmed_entropy; huffman_tree_entropy = trimmed_entropy;
@@ -245,10 +256,12 @@ void StoreHuffmanCode(const EntropyCode<kSize>& code, int alphabet_size,
&huffman_tree_entropy.depth_[0], storage_ix, storage); &huffman_tree_entropy.depth_[0], storage_ix, storage);
WriteBits(1, write_length, storage_ix, storage); WriteBits(1, write_length, storage_ix, storage);
if (write_length) { if (write_length) {
const int nbits = Log2Ceiling(huffman_tree_size - 1); WriteBits(1, huffman_tree_size >= 68, storage_ix, storage);
const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2; if (huffman_tree_size < 68) {
WriteBits(3, nbitpairs - 1, storage_ix, storage); WriteBits(6, huffman_tree_size - 4, storage_ix, storage);
WriteBits(nbitpairs * 2, huffman_tree_size - 2, storage_ix, storage); } else {
WriteBits(7, huffman_tree_size - 68, storage_ix, storage);
}
} }
StoreHuffmanTreeToBitMask(&huffman_tree[0], &huffman_tree_extra_bits[0], StoreHuffmanTreeToBitMask(&huffman_tree[0], &huffman_tree_extra_bits[0],
huffman_tree_size, huffman_tree_entropy, huffman_tree_size, huffman_tree_entropy,
@@ -464,7 +477,7 @@ int BestMaxZeroRunLengthPrefix(const std::vector<int>& v) {
void EncodeContextMap(const std::vector<int>& context_map, void EncodeContextMap(const std::vector<int>& context_map,
int num_clusters, int num_clusters,
int* storage_ix, uint8_t* storage) { int* storage_ix, uint8_t* storage) {
WriteBits(8, num_clusters - 1, storage_ix, storage); EncodeVarLenUint8(num_clusters - 1, storage_ix, storage);
if (num_clusters == 1) { if (num_clusters == 1) {
return; return;
@@ -476,11 +489,11 @@ void EncodeContextMap(const std::vector<int>& context_map,
int max_run_length_prefix = BestMaxZeroRunLengthPrefix(transformed_symbols); int max_run_length_prefix = BestMaxZeroRunLengthPrefix(transformed_symbols);
RunLengthCodeZeros(transformed_symbols, &max_run_length_prefix, RunLengthCodeZeros(transformed_symbols, &max_run_length_prefix,
&rle_symbols, &extra_bits); &rle_symbols, &extra_bits);
HistogramLiteral symbol_histogram; HistogramContextMap symbol_histogram;
for (int i = 0; i < rle_symbols.size(); ++i) { for (int i = 0; i < rle_symbols.size(); ++i) {
symbol_histogram.Add(rle_symbols[i]); symbol_histogram.Add(rle_symbols[i]);
} }
EntropyCodeLiteral symbol_code; EntropyCodeContextMap symbol_code;
BuildEntropyCode(symbol_histogram, 15, num_clusters + max_run_length_prefix, BuildEntropyCode(symbol_histogram, 15, num_clusters + max_run_length_prefix,
&symbol_code); &symbol_code);
bool use_rle = max_run_length_prefix > 0; bool use_rle = max_run_length_prefix > 0;
@@ -510,7 +523,7 @@ void BuildEntropyCodes(const std::vector<Histogram<kSize> >& histograms,
} }
struct BlockSplitCode { struct BlockSplitCode {
EntropyCodeLiteral block_type_code; EntropyCodeBlockType block_type_code;
EntropyCodeBlockLength block_len_code; EntropyCodeBlockLength block_len_code;
}; };
@@ -553,18 +566,12 @@ void ComputeBlockTypeShortCodes(BlockSplit* split) {
void BuildAndEncodeBlockSplitCode(const BlockSplit& split, void BuildAndEncodeBlockSplitCode(const BlockSplit& split,
BlockSplitCode* code, BlockSplitCode* code,
int* storage_ix, uint8_t* storage) { int* storage_ix, uint8_t* storage) {
if (split.num_types_ <= 1) { EncodeVarLenUint8(split.num_types_ - 1, storage_ix, storage);
WriteBits(1, 0, storage_ix, storage); if (split.num_types_ == 1) {
return; return;
} }
WriteBits(1, 1, storage_ix, storage);
int nbits = Log2Floor(split.num_types_ - 1);
WriteBits(3, nbits, storage_ix, storage);
if (nbits > 0) {
WriteBits(nbits, split.num_types_ - 1 - (1 << nbits), storage_ix, storage);
}
HistogramLiteral type_histo; HistogramBlockType type_histo;
for (int i = 0; i < split.type_codes_.size(); ++i) { for (int i = 0; i < split.type_codes_.size(); ++i) {
type_histo.Add(split.type_codes_[i]); type_histo.Add(split.type_codes_[i]);
} }
@@ -591,7 +598,7 @@ void MoveAndEncode(const BlockSplitCode& code,
++it->idx_; ++it->idx_;
it->type_ = it->split_.types_[it->idx_]; it->type_ = it->split_.types_[it->idx_];
it->length_ = it->split_.lengths_[it->idx_]; it->length_ = it->split_.lengths_[it->idx_];
uint8_t type_code = it->split_.type_codes_[it->idx_]; int type_code = it->split_.type_codes_[it->idx_];
EntropyEncode(type_code, code.block_type_code, storage_ix, storage); EntropyEncode(type_code, code.block_type_code, storage_ix, storage);
EncodeBlockLength(code.block_len_code, it->length_, storage_ix, storage); EncodeBlockLength(code.block_len_code, it->length_, storage_ix, storage);
} }
@@ -626,6 +633,9 @@ void BuildMetaBlock(const EncodingParams& params,
MetaBlock* mb) { MetaBlock* mb) {
mb->cmds = cmds; mb->cmds = cmds;
mb->params = params; mb->params = params;
if (cmds.empty()) {
return;
}
ComputeCommandPrefixes(&mb->cmds, ComputeCommandPrefixes(&mb->cmds,
mb->params.num_direct_distance_codes, mb->params.num_direct_distance_codes,
mb->params.distance_postfix_bits); mb->params.distance_postfix_bits);
@@ -661,9 +671,8 @@ void BuildMetaBlock(const EncodingParams& params,
&mb->command_histograms, &mb->command_histograms,
&distance_histograms); &distance_histograms);
// Histogram ids need to fit in one byte and there are 16 ids reserved for // Histogram ids need to fit in one byte.
// run length codes, which leaves a maximum number of 240 histograms. static const int kMaxNumberOfHistograms = 256;
static const int kMaxNumberOfHistograms = 240;
mb->literal_histograms = literal_histograms; mb->literal_histograms = literal_histograms;
ClusterHistograms(literal_histograms, ClusterHistograms(literal_histograms,
@@ -692,14 +701,20 @@ size_t MetaBlockLength(const std::vector<Command>& cmds) {
} }
void StoreMetaBlock(const MetaBlock& mb, void StoreMetaBlock(const MetaBlock& mb,
const bool is_last,
const uint8_t* ringbuffer, const uint8_t* ringbuffer,
const size_t mask, const size_t mask,
size_t* pos, size_t* pos,
int* storage_ix, uint8_t* storage) { int* storage_ix, uint8_t* storage) {
size_t length = MetaBlockLength(mb.cmds); size_t length = MetaBlockLength(mb.cmds);
const size_t end_pos = *pos + length; const size_t end_pos = *pos + length;
EncodeMetaBlockLength(length - 1, EncodeMetaBlockLength(length,
is_last,
false,
storage_ix, storage); storage_ix, storage);
if (length == 0) {
return;
}
BlockSplitCode literal_split_code; BlockSplitCode literal_split_code;
BlockSplitCode command_split_code; BlockSplitCode command_split_code;
BlockSplitCode distance_split_code; BlockSplitCode distance_split_code;
@@ -798,42 +813,65 @@ void BrotliCompressor::WriteStreamHeader() {
void BrotliCompressor::WriteMetaBlock(const size_t input_size, void BrotliCompressor::WriteMetaBlock(const size_t input_size,
const uint8_t* input_buffer, const uint8_t* input_buffer,
const bool is_last,
size_t* encoded_size, size_t* encoded_size,
uint8_t* encoded_buffer) { uint8_t* encoded_buffer) {
ringbuffer_.Write(input_buffer, input_size);
EstimateBitCostsForLiterals(input_pos_, input_size,
kRingBufferMask, ringbuffer_.start(),
&literal_cost_[0]);
std::vector<Command> commands; std::vector<Command> commands;
CreateBackwardReferences(input_size, input_pos_, if (input_size > 0) {
ringbuffer_.start(), ringbuffer_.Write(input_buffer, input_size);
&literal_cost_[0], EstimateBitCostsForLiterals(input_pos_, input_size,
kRingBufferMask, kMaxBackwardDistance, kRingBufferMask, ringbuffer_.start(),
hasher_, &literal_cost_[0]);
&commands); CreateBackwardReferences(input_size, input_pos_,
ComputeDistanceShortCodes(&commands, dist_ringbuffer_, ringbuffer_.start(),
&dist_ringbuffer_idx_); &literal_cost_[0],
kRingBufferMask, kMaxBackwardDistance,
hasher_,
&commands);
ComputeDistanceShortCodes(&commands, dist_ringbuffer_,
&dist_ringbuffer_idx_);
}
EncodingParams params; EncodingParams params;
params.num_direct_distance_codes = 12; params.num_direct_distance_codes = 12;
params.distance_postfix_bits = 1; params.distance_postfix_bits = 1;
params.literal_context_mode = CONTEXT_SIGNED; params.literal_context_mode = CONTEXT_SIGNED;
const int storage_ix0 = storage_ix_;
MetaBlock mb; MetaBlock mb;
BuildMetaBlock(params, commands, ringbuffer_.start(), input_pos_, BuildMetaBlock(params, commands, ringbuffer_.start(), input_pos_,
kRingBufferMask, &mb); kRingBufferMask, &mb);
StoreMetaBlock(mb, ringbuffer_.start(), kRingBufferMask, StoreMetaBlock(mb, is_last, ringbuffer_.start(), kRingBufferMask,
&input_pos_, &storage_ix_, storage_); &input_pos_, &storage_ix_, storage_);
size_t output_size = storage_ix_ >> 3; size_t output_size = is_last ? ((storage_ix_ + 7) >> 3) : (storage_ix_ >> 3);
memcpy(encoded_buffer, storage_, output_size); if (input_size + 4 < output_size) {
*encoded_size = output_size; storage_ix_ = storage_ix0;
storage_ix_ -= output_size << 3; storage_[storage_ix_ >> 3] &= (1 << (storage_ix_ & 7)) - 1;
storage_[storage_ix_ >> 3] = storage_[output_size]; EncodeMetaBlockLength(input_size, false, true, &storage_ix_, storage_);
size_t hdr_size = (storage_ix_ + 7) >> 3;
memcpy(encoded_buffer, storage_, hdr_size);
memcpy(encoded_buffer + hdr_size, input_buffer, input_size);
*encoded_size = hdr_size + input_size;
if (is_last) {
encoded_buffer[*encoded_size] = 0x3; // ISLAST, ISEMPTY
++(*encoded_size);
}
storage_ix_ = 0;
storage_[0] = 0;
} else {
memcpy(encoded_buffer, storage_, output_size);
*encoded_size = output_size;
if (is_last) {
storage_ix_ = 0;
storage_[0] = 0;
} else {
storage_ix_ -= output_size << 3;
storage_[storage_ix_ >> 3] = storage_[output_size];
}
}
} }
void BrotliCompressor::FinishStream( void BrotliCompressor::FinishStream(
size_t* encoded_size, uint8_t* encoded_buffer) { size_t* encoded_size, uint8_t* encoded_buffer) {
WriteBits(2, 0x3, &storage_ix_, storage_); WriteMetaBlock(0, NULL, true, encoded_size, encoded_buffer);
*encoded_size = (storage_ix_ + 7) >> 3;
memcpy(encoded_buffer, storage_, *encoded_size);
} }
@@ -857,21 +895,19 @@ int BrotliCompressBuffer(size_t input_size,
while (input_buffer < input_end) { while (input_buffer < input_end) {
int block_size = max_block_size; int block_size = max_block_size;
bool is_last = false;
if (block_size >= input_end - input_buffer) { if (block_size >= input_end - input_buffer) {
block_size = input_end - input_buffer; block_size = input_end - input_buffer;
is_last = true;
} }
size_t output_size = max_output_size; size_t output_size = max_output_size;
compressor.WriteMetaBlock(block_size, input_buffer, compressor.WriteMetaBlock(block_size, input_buffer, is_last,
&output_size, &encoded_buffer[*encoded_size]); &output_size, &encoded_buffer[*encoded_size]);
input_buffer += block_size; input_buffer += block_size;
*encoded_size += output_size; *encoded_size += output_size;
max_output_size -= output_size; max_output_size -= output_size;
} }
size_t output_size = max_output_size;
compressor.FinishStream(&output_size, &encoded_buffer[*encoded_size]);
*encoded_size += output_size;
return 1; return 1;
} }
+1
View File
@@ -39,6 +39,7 @@ class BrotliCompressor {
// written. // written.
void WriteMetaBlock(const size_t input_size, void WriteMetaBlock(const size_t input_size,
const uint8_t* input_buffer, const uint8_t* input_buffer,
const bool is_last,
size_t* encoded_size, size_t* encoded_size,
uint8_t* encoded_buffer); uint8_t* encoded_buffer);
+43 -40
View File
@@ -157,6 +157,17 @@ void CreateHuffmanTree(const int *data,
} }
} }
void Reverse(uint8_t* v, int start, int end) {
--end;
while (start < end) {
int tmp = v[start];
v[start] = v[end];
v[end] = tmp;
++start;
--end;
}
}
void WriteHuffmanTreeRepetitions( void WriteHuffmanTreeRepetitions(
const int previous_value, const int previous_value,
const int value, const int value,
@@ -170,26 +181,24 @@ void WriteHuffmanTreeRepetitions(
++(*tree_size); ++(*tree_size);
--repetitions; --repetitions;
} }
while (repetitions >= 1) { if (repetitions < 3) {
if (repetitions < 3) { for (int i = 0; i < repetitions; ++i) {
for (int i = 0; i < repetitions; ++i) { tree[*tree_size] = value;
tree[*tree_size] = value; extra_bits[*tree_size] = 0;
extra_bits[*tree_size] = 0;
++(*tree_size);
}
return;
} else if (repetitions < 7) {
// 3 to 6 left.
tree[*tree_size] = 16;
extra_bits[*tree_size] = repetitions - 3;
++(*tree_size); ++(*tree_size);
return;
} else {
tree[*tree_size] = 16;
extra_bits[*tree_size] = 3;
++(*tree_size);
repetitions -= 6;
} }
} else {
repetitions -= 3;
int start = *tree_size;
while (repetitions >= 0) {
tree[*tree_size] = 16;
extra_bits[*tree_size] = repetitions & 0x3;
++(*tree_size);
repetitions >>= 2;
--repetitions;
}
Reverse(tree, start, *tree_size);
Reverse(extra_bits, start, *tree_size);
} }
} }
@@ -198,30 +207,24 @@ void WriteHuffmanTreeRepetitionsZeros(
uint8_t* tree, uint8_t* tree,
uint8_t* extra_bits, uint8_t* extra_bits,
int* tree_size) { int* tree_size) {
while (repetitions >= 1) { if (repetitions < 3) {
if (repetitions < 3) { for (int i = 0; i < repetitions; ++i) {
for (int i = 0; i < repetitions; ++i) { tree[*tree_size] = 0;
tree[*tree_size] = 0; extra_bits[*tree_size] = 0;
extra_bits[*tree_size] = 0;
++(*tree_size);
}
return;
} else if (repetitions < 11) {
tree[*tree_size] = 17;
extra_bits[*tree_size] = repetitions - 3;
++(*tree_size); ++(*tree_size);
return;
} else if (repetitions < 139) {
tree[*tree_size] = 18;
extra_bits[*tree_size] = repetitions - 11;
++(*tree_size);
return;
} else {
tree[*tree_size] = 18;
extra_bits[*tree_size] = 0x7f; // 138 repeated 0s
++(*tree_size);
repetitions -= 138;
} }
} else {
repetitions -= 3;
int start = *tree_size;
while (repetitions >= 0) {
tree[*tree_size] = 17;
extra_bits[*tree_size] = repetitions & 0x7;
++(*tree_size);
repetitions >>= 3;
--repetitions;
}
Reverse(tree, start, *tree_size);
Reverse(extra_bits, start, *tree_size);
} }
} }
+5 -1
View File
@@ -98,7 +98,7 @@ void BuildEntropyCode(const Histogram<kSize>& histogram,
ConvertBitDepthsToSymbols(&code->depth_[0], alphabet_size, &code->bits_[0]); ConvertBitDepthsToSymbols(&code->depth_[0], alphabet_size, &code->bits_[0]);
} }
static const int kCodeLengthCodes = 19; static const int kCodeLengthCodes = 18;
// Literal entropy code. // Literal entropy code.
typedef EntropyCode<256> EntropyCodeLiteral; typedef EntropyCode<256> EntropyCodeLiteral;
@@ -106,6 +106,10 @@ typedef EntropyCode<256> EntropyCodeLiteral;
typedef EntropyCode<kNumCommandPrefixes> EntropyCodeCommand; typedef EntropyCode<kNumCommandPrefixes> EntropyCodeCommand;
typedef EntropyCode<kNumDistancePrefixes> EntropyCodeDistance; typedef EntropyCode<kNumDistancePrefixes> EntropyCodeDistance;
typedef EntropyCode<kNumBlockLenPrefixes> EntropyCodeBlockLength; typedef EntropyCode<kNumBlockLenPrefixes> EntropyCodeBlockLength;
// Context map entropy code, 256 Huffman tree indexes + 16 run length codes.
typedef EntropyCode<272> EntropyCodeContextMap;
// Block type entropy code, 256 block types + 2 special symbols.
typedef EntropyCode<258> EntropyCodeBlockType;
} // namespace brotli } // namespace brotli
+4
View File
@@ -78,6 +78,10 @@ typedef Histogram<256> HistogramLiteral;
typedef Histogram<kNumCommandPrefixes> HistogramCommand; typedef Histogram<kNumCommandPrefixes> HistogramCommand;
typedef Histogram<kNumDistancePrefixes> HistogramDistance; typedef Histogram<kNumDistancePrefixes> HistogramDistance;
typedef Histogram<kNumBlockLenPrefixes> HistogramBlockLength; typedef Histogram<kNumBlockLenPrefixes> HistogramBlockLength;
// Context map histogram, 256 Huffman tree indexes + 16 run length codes.
typedef Histogram<272> HistogramContextMap;
// Block type histogram, 256 block types + 2 special symbols.
typedef Histogram<258> HistogramBlockType;
static const int kLiteralContextBits = 6; static const int kLiteralContextBits = 6;
static const int kDistanceContextBits = 2; static const int kDistanceContextBits = 2;