mirror of
https://github.com/google/brotli.git
synced 2024-11-29 06:31:06 +00:00
Merge pull request #6 from szabadka/master
Move the block switch storing functions to the brotli_bit_stream library...
This commit is contained in:
commit
618ea06821
@ -301,7 +301,7 @@ void SplitByteVector(const std::vector<DataType>& data,
|
|||||||
const double block_switch_cost,
|
const double block_switch_cost,
|
||||||
BlockSplit* split) {
|
BlockSplit* split) {
|
||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
split->num_types_ = 0;
|
split->num_types_ = 1;
|
||||||
return;
|
return;
|
||||||
} else if (data.size() < kMinLengthForBlockSplitting) {
|
} else if (data.size() < kMinLengthForBlockSplitting) {
|
||||||
split->num_types_ = 1;
|
split->num_types_ = 1;
|
||||||
|
@ -29,8 +29,7 @@ namespace brotli {
|
|||||||
|
|
||||||
struct BlockSplit {
|
struct BlockSplit {
|
||||||
int num_types_;
|
int num_types_;
|
||||||
std::vector<uint8_t> types_;
|
std::vector<int> types_;
|
||||||
std::vector<int> type_codes_;
|
|
||||||
std::vector<int> lengths_;
|
std::vector<int> lengths_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "./entropy_encode.h"
|
#include "./entropy_encode.h"
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
|
#include "./prefix.h"
|
||||||
#include "./write_bits.h"
|
#include "./write_bits.h"
|
||||||
|
|
||||||
namespace brotli {
|
namespace brotli {
|
||||||
@ -305,6 +306,69 @@ void BuildAndStoreHuffmanTree(const int *histogram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StoreBlockSwitch(const BlockSplitCode& code,
|
||||||
|
const int block_ix,
|
||||||
|
int* storage_ix,
|
||||||
|
uint8_t* storage) {
|
||||||
|
if (block_ix > 0) {
|
||||||
|
int typecode = code.type_code[block_ix];
|
||||||
|
WriteBits(code.type_depths[typecode], code.type_bits[typecode],
|
||||||
|
storage_ix, storage);
|
||||||
|
}
|
||||||
|
int lencode = code.length_prefix[block_ix];
|
||||||
|
WriteBits(code.length_depths[lencode], code.length_bits[lencode],
|
||||||
|
storage_ix, storage);
|
||||||
|
WriteBits(code.length_nextra[block_ix], code.length_extra[block_ix],
|
||||||
|
storage_ix, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildAndStoreBlockSplitCode(const std::vector<int>& types,
|
||||||
|
const std::vector<int>& lengths,
|
||||||
|
const int num_types,
|
||||||
|
const int quality,
|
||||||
|
BlockSplitCode* code,
|
||||||
|
int* storage_ix,
|
||||||
|
uint8_t* storage) {
|
||||||
|
const int num_blocks = types.size();
|
||||||
|
std::vector<int> type_histo(num_types + 2);
|
||||||
|
std::vector<int> length_histo(26);
|
||||||
|
int last_type = 1;
|
||||||
|
int second_last_type = 0;
|
||||||
|
code->type_code.resize(num_blocks);
|
||||||
|
code->length_prefix.resize(num_blocks);
|
||||||
|
code->length_nextra.resize(num_blocks);
|
||||||
|
code->length_extra.resize(num_blocks);
|
||||||
|
code->type_depths.resize(num_types + 2);
|
||||||
|
code->type_bits.resize(num_types + 2);
|
||||||
|
code->length_depths.resize(26);
|
||||||
|
code->length_bits.resize(26);
|
||||||
|
for (int i = 0; i < num_blocks; ++i) {
|
||||||
|
int type = types[i];
|
||||||
|
int type_code = (type == last_type + 1 ? 1 :
|
||||||
|
type == second_last_type ? 0 :
|
||||||
|
type + 2);
|
||||||
|
second_last_type = last_type;
|
||||||
|
last_type = type;
|
||||||
|
code->type_code[i] = type_code;
|
||||||
|
if (i > 0) ++type_histo[type_code];
|
||||||
|
GetBlockLengthPrefixCode(lengths[i],
|
||||||
|
&code->length_prefix[i],
|
||||||
|
&code->length_nextra[i],
|
||||||
|
&code->length_extra[i]);
|
||||||
|
++length_histo[code->length_prefix[i]];
|
||||||
|
}
|
||||||
|
StoreVarLenUint8(num_types - 1, storage_ix, storage);
|
||||||
|
if (num_types > 1) {
|
||||||
|
BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, quality,
|
||||||
|
&code->type_depths[0], &code->type_bits[0],
|
||||||
|
storage_ix, storage);
|
||||||
|
BuildAndStoreHuffmanTree(&length_histo[0], 26, quality,
|
||||||
|
&code->length_depths[0], &code->length_bits[0],
|
||||||
|
storage_ix, storage);
|
||||||
|
StoreBlockSwitch(*code, 0, storage_ix, storage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void StoreTrivialContextMap(int num_types,
|
void StoreTrivialContextMap(int num_types,
|
||||||
int context_bits,
|
int context_bits,
|
||||||
int* storage_ix,
|
int* storage_ix,
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace brotli {
|
namespace brotli {
|
||||||
|
|
||||||
@ -62,6 +63,35 @@ void BuildAndStoreHuffmanTree(const int *histogram,
|
|||||||
int* storage_ix,
|
int* storage_ix,
|
||||||
uint8_t* storage);
|
uint8_t* storage);
|
||||||
|
|
||||||
|
// Data structure that stores everything that is needed to encode each block
|
||||||
|
// switch command.
|
||||||
|
struct BlockSplitCode {
|
||||||
|
std::vector<int> type_code;
|
||||||
|
std::vector<int> length_prefix;
|
||||||
|
std::vector<int> length_nextra;
|
||||||
|
std::vector<int> length_extra;
|
||||||
|
std::vector<uint8_t> type_depths;
|
||||||
|
std::vector<uint16_t> type_bits;
|
||||||
|
std::vector<uint8_t> length_depths;
|
||||||
|
std::vector<uint16_t> length_bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Builds a BlockSplitCode data structure from the block split given by the
|
||||||
|
// vector of block types and block lengths and stores it to the bit stream.
|
||||||
|
void BuildAndStoreBlockSplitCode(const std::vector<int>& types,
|
||||||
|
const std::vector<int>& lengths,
|
||||||
|
const int num_types,
|
||||||
|
const int quality,
|
||||||
|
BlockSplitCode* code,
|
||||||
|
int* storage_ix,
|
||||||
|
uint8_t* storage);
|
||||||
|
|
||||||
|
// Stores the block switch command with index block_ix to the bit stream.
|
||||||
|
void StoreBlockSwitch(const BlockSplitCode& code,
|
||||||
|
const int block_ix,
|
||||||
|
int* storage_ix,
|
||||||
|
uint8_t* storage);
|
||||||
|
|
||||||
} // namespace brotli
|
} // namespace brotli
|
||||||
|
|
||||||
#endif // BROTLI_ENC_BROTLI_BIT_STREAM_H_
|
#endif // BROTLI_ENC_BROTLI_BIT_STREAM_H_
|
||||||
|
101
enc/encode.cc
101
enc/encode.cc
@ -435,74 +435,6 @@ void EncodeContextMap(const std::vector<int>& context_map,
|
|||||||
WriteBits(1, 1, storage_ix, storage); // use move-to-front
|
WriteBits(1, 1, storage_ix, storage); // use move-to-front
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockSplitCode {
|
|
||||||
EntropyCodeBlockType block_type_code;
|
|
||||||
EntropyCodeBlockLength block_len_code;
|
|
||||||
};
|
|
||||||
|
|
||||||
void EncodeBlockLength(const EntropyCodeBlockLength& entropy,
|
|
||||||
int length,
|
|
||||||
int* storage_ix, uint8_t* storage) {
|
|
||||||
int len_code = BlockLengthPrefix(length);
|
|
||||||
int extra_bits = BlockLengthExtraBits(len_code);
|
|
||||||
int extra_bits_value = length - BlockLengthOffset(len_code);
|
|
||||||
WriteBits(entropy.depth_[len_code], entropy.bits_[len_code],
|
|
||||||
storage_ix, storage);
|
|
||||||
if (extra_bits > 0) {
|
|
||||||
WriteBits(extra_bits, extra_bits_value, storage_ix, storage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComputeBlockTypeShortCodes(BlockSplit* split) {
|
|
||||||
if (split->num_types_ <= 1) {
|
|
||||||
split->num_types_ = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int ringbuffer[2] = { 0, 1 };
|
|
||||||
size_t index = 0;
|
|
||||||
for (int i = 0; i < split->types_.size(); ++i) {
|
|
||||||
int type = split->types_[i];
|
|
||||||
int type_code;
|
|
||||||
if (type == ringbuffer[index & 1]) {
|
|
||||||
type_code = 0;
|
|
||||||
} else if (type == ringbuffer[(index - 1) & 1] + 1) {
|
|
||||||
type_code = 1;
|
|
||||||
} else {
|
|
||||||
type_code = type + 2;
|
|
||||||
}
|
|
||||||
ringbuffer[index & 1] = type;
|
|
||||||
++index;
|
|
||||||
split->type_codes_.push_back(type_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildAndEncodeBlockSplitCode(const BlockSplit& split,
|
|
||||||
BlockSplitCode* code,
|
|
||||||
int* storage_ix, uint8_t* storage) {
|
|
||||||
StoreVarLenUint8(split.num_types_ - 1, storage_ix, storage);
|
|
||||||
|
|
||||||
if (split.num_types_ == 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistogramBlockType type_histo;
|
|
||||||
for (int i = 1; i < split.type_codes_.size(); ++i) {
|
|
||||||
type_histo.Add(split.type_codes_[i]);
|
|
||||||
}
|
|
||||||
HistogramBlockLength length_histo;
|
|
||||||
for (int i = 0; i < split.lengths_.size(); ++i) {
|
|
||||||
length_histo.Add(BlockLengthPrefix(split.lengths_[i]));
|
|
||||||
}
|
|
||||||
BuildAndStoreEntropyCode(type_histo, 15, split.num_types_ + 2,
|
|
||||||
&code->block_type_code,
|
|
||||||
storage_ix, storage);
|
|
||||||
BuildAndStoreEntropyCode(length_histo, 15, kNumBlockLenPrefixes,
|
|
||||||
&code->block_len_code,
|
|
||||||
storage_ix, storage);
|
|
||||||
EncodeBlockLength(code->block_len_code, split.lengths_[0],
|
|
||||||
storage_ix, storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveAndEncode(const BlockSplitCode& code,
|
void MoveAndEncode(const BlockSplitCode& code,
|
||||||
BlockSplitIterator* it,
|
BlockSplitIterator* it,
|
||||||
int* storage_ix, uint8_t* storage) {
|
int* storage_ix, uint8_t* storage) {
|
||||||
@ -510,11 +442,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_];
|
||||||
int type_code = it->split_.type_codes_[it->idx_];
|
StoreBlockSwitch(code, it->idx_, storage_ix, storage);
|
||||||
WriteBits(code.block_type_code.depth_[type_code],
|
|
||||||
code.block_type_code.bits_[type_code],
|
|
||||||
storage_ix, storage);
|
|
||||||
EncodeBlockLength(code.block_len_code, it->length_, storage_ix, storage);
|
|
||||||
}
|
}
|
||||||
--it->length_;
|
--it->length_;
|
||||||
}
|
}
|
||||||
@ -558,9 +486,6 @@ void BuildMetaBlock(const EncodingParams& params,
|
|||||||
&mb->literal_split,
|
&mb->literal_split,
|
||||||
&mb->command_split,
|
&mb->command_split,
|
||||||
&mb->distance_split);
|
&mb->distance_split);
|
||||||
ComputeBlockTypeShortCodes(&mb->literal_split);
|
|
||||||
ComputeBlockTypeShortCodes(&mb->command_split);
|
|
||||||
ComputeBlockTypeShortCodes(&mb->distance_split);
|
|
||||||
|
|
||||||
mb->literal_context_modes.resize(mb->literal_split.num_types_,
|
mb->literal_context_modes.resize(mb->literal_split.num_types_,
|
||||||
mb->params.literal_context_mode);
|
mb->params.literal_context_mode);
|
||||||
@ -630,12 +555,24 @@ void StoreMetaBlock(const MetaBlock& mb,
|
|||||||
BlockSplitCode literal_split_code;
|
BlockSplitCode literal_split_code;
|
||||||
BlockSplitCode command_split_code;
|
BlockSplitCode command_split_code;
|
||||||
BlockSplitCode distance_split_code;
|
BlockSplitCode distance_split_code;
|
||||||
BuildAndEncodeBlockSplitCode(mb.literal_split, &literal_split_code,
|
BuildAndStoreBlockSplitCode(mb.literal_split.types_,
|
||||||
storage_ix, storage);
|
mb.literal_split.lengths_,
|
||||||
BuildAndEncodeBlockSplitCode(mb.command_split, &command_split_code,
|
mb.literal_split.num_types_,
|
||||||
storage_ix, storage);
|
9, // quality
|
||||||
BuildAndEncodeBlockSplitCode(mb.distance_split, &distance_split_code,
|
&literal_split_code,
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
|
BuildAndStoreBlockSplitCode(mb.command_split.types_,
|
||||||
|
mb.command_split.lengths_,
|
||||||
|
mb.command_split.num_types_,
|
||||||
|
9, // quality
|
||||||
|
&command_split_code,
|
||||||
|
storage_ix, storage);
|
||||||
|
BuildAndStoreBlockSplitCode(mb.distance_split.types_,
|
||||||
|
mb.distance_split.lengths_,
|
||||||
|
mb.distance_split.num_types_,
|
||||||
|
9, // quality
|
||||||
|
&distance_split_code,
|
||||||
|
storage_ix, storage);
|
||||||
WriteBits(2, mb.params.distance_postfix_bits, storage_ix, storage);
|
WriteBits(2, mb.params.distance_postfix_bits, storage_ix, storage);
|
||||||
WriteBits(4,
|
WriteBits(4,
|
||||||
mb.params.num_direct_distance_codes >>
|
mb.params.num_direct_distance_codes >>
|
||||||
|
@ -21,23 +21,6 @@
|
|||||||
|
|
||||||
namespace brotli {
|
namespace brotli {
|
||||||
|
|
||||||
// Represents the range of values belonging to a prefix code:
|
|
||||||
// [offset, offset + 2^nbits)
|
|
||||||
struct PrefixCodeRange {
|
|
||||||
int offset;
|
|
||||||
int nbits;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const PrefixCodeRange kBlockLengthPrefixCode[kNumBlockLenPrefixes] = {
|
|
||||||
{ 1, 2}, { 5, 2}, { 9, 2}, { 13, 2},
|
|
||||||
{ 17, 3}, { 25, 3}, { 33, 3}, { 41, 3},
|
|
||||||
{ 49, 4}, { 65, 4}, { 81, 4}, { 97, 4},
|
|
||||||
{ 113, 5}, { 145, 5}, { 177, 5}, { 209, 5},
|
|
||||||
{ 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
|
|
||||||
{ 753, 9}, { 1265, 10}, {2289, 11}, {4337, 12},
|
|
||||||
{8433, 13}, {16625, 24}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const PrefixCodeRange kInsertLengthPrefixCode[kNumInsertLenPrefixes] = {
|
static const PrefixCodeRange kInsertLengthPrefixCode[kNumInsertLenPrefixes] = {
|
||||||
{ 0, 0}, { 1, 0}, { 2, 0}, { 3, 0},
|
{ 0, 0}, { 1, 0}, { 2, 0}, { 3, 0},
|
||||||
{ 4, 0}, { 5, 0}, { 6, 1}, { 8, 1},
|
{ 4, 0}, { 5, 0}, { 6, 1}, { 8, 1},
|
||||||
@ -145,22 +128,4 @@ void PrefixEncodeCopyDistance(int distance_code,
|
|||||||
*extra_bits = (distance_code - offset) >> postfix_bits;
|
*extra_bits = (distance_code - offset) >> postfix_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BlockLengthPrefix(int length) {
|
|
||||||
for (int i = 0; i < kNumBlockLenPrefixes; ++i) {
|
|
||||||
const PrefixCodeRange& range = kBlockLengthPrefixCode[i];
|
|
||||||
if (length >= range.offset && length < range.offset + (1 << range.nbits)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BlockLengthExtraBits(int length_code) {
|
|
||||||
return kBlockLengthPrefixCode[length_code].nbits;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BlockLengthOffset(int length_code) {
|
|
||||||
return kBlockLengthPrefixCode[length_code].offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace brotli
|
} // namespace brotli
|
||||||
|
29
enc/prefix.h
29
enc/prefix.h
@ -29,6 +29,13 @@ static const int kNumBlockLenPrefixes = 26;
|
|||||||
static const int kNumDistanceShortCodes = 16;
|
static const int kNumDistanceShortCodes = 16;
|
||||||
static const int kNumDistancePrefixes = 520;
|
static const int kNumDistancePrefixes = 520;
|
||||||
|
|
||||||
|
// Represents the range of values belonging to a prefix code:
|
||||||
|
// [offset, offset + 2^nbits)
|
||||||
|
struct PrefixCodeRange {
|
||||||
|
int offset;
|
||||||
|
int nbits;
|
||||||
|
};
|
||||||
|
|
||||||
int CommandPrefix(int insert_length, int copy_length);
|
int CommandPrefix(int insert_length, int copy_length);
|
||||||
int InsertLengthExtraBits(int prefix);
|
int InsertLengthExtraBits(int prefix);
|
||||||
int InsertLengthOffset(int prefix);
|
int InsertLengthOffset(int prefix);
|
||||||
@ -42,9 +49,25 @@ void PrefixEncodeCopyDistance(int distance_code,
|
|||||||
int* nbits,
|
int* nbits,
|
||||||
uint32_t* extra_bits);
|
uint32_t* extra_bits);
|
||||||
|
|
||||||
int BlockLengthPrefix(int length);
|
static const PrefixCodeRange kBlockLengthPrefixCode[kNumBlockLenPrefixes] = {
|
||||||
int BlockLengthExtraBits(int prefix);
|
{ 1, 2}, { 5, 2}, { 9, 2}, { 13, 2},
|
||||||
int BlockLengthOffset(int prefix);
|
{ 17, 3}, { 25, 3}, { 33, 3}, { 41, 3},
|
||||||
|
{ 49, 4}, { 65, 4}, { 81, 4}, { 97, 4},
|
||||||
|
{ 113, 5}, { 145, 5}, { 177, 5}, { 209, 5},
|
||||||
|
{ 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
|
||||||
|
{ 753, 9}, { 1265, 10}, {2289, 11}, {4337, 12},
|
||||||
|
{8433, 13}, {16625, 24}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void GetBlockLengthPrefixCode(int len,
|
||||||
|
int* code, int* n_extra, int* extra) {
|
||||||
|
*code = 0;
|
||||||
|
while (*code < 25 && len >= kBlockLengthPrefixCode[*code + 1].offset) {
|
||||||
|
++(*code);
|
||||||
|
}
|
||||||
|
*n_extra = kBlockLengthPrefixCode[*code].nbits;
|
||||||
|
*extra = len - kBlockLengthPrefixCode[*code].offset;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace brotli
|
} // namespace brotli
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user