Encoder support for new empty meta-block format.

Changed the parallel implementation to sync meta-blocks
to byte boundary by emitting empty meta-blocks.
This commit is contained in:
Zoltan Szabadka 2015-04-23 15:43:37 +02:00
parent 098c928864
commit 2fd80cdc9a
5 changed files with 65 additions and 9 deletions

View File

@ -36,7 +36,7 @@ namespace brotli {
bool EncodeMlen(size_t length, int* bits, int* numbits, int* nibblesbits) {
length--; // MLEN - 1 is encoded
int lg = length == 0 ? 1 : Log2Floor(length) + 1;
if (lg > 28) return false;
if (lg > 24) return false;
int mnibbles = (lg < 16 ? 16 : (lg + 3)) / 4;
*nibblesbits = mnibbles - 4;
*numbits = mnibbles * 4;
@ -828,4 +828,15 @@ bool StoreUncompressedMetaBlock(bool final_block,
return true;
}
void StoreSyncMetaBlock(int * __restrict storage_ix,
uint8_t * __restrict storage) {
// Empty metadata meta-block bit pattern:
// 1 bit: is_last (0)
// 2 bits: num nibbles (3)
// 1 bit: reserved (0)
// 2 bits: metadata length bytes (0)
WriteBits(6, 6, storage_ix, storage);
JumpToByteBoundary(storage_ix, storage);
}
} // namespace brotli

View File

@ -130,6 +130,9 @@ bool StoreUncompressedMetaBlock(bool final_block,
int* storage_ix,
uint8_t* storage);
// Stores an empty metadata meta-block and syncs to a byte boundary.
void StoreSyncMetaBlock(int* storage_ix, uint8_t* storage);
} // namespace brotli
#endif // BROTLI_ENC_BROTLI_BIT_STREAM_H_

View File

@ -467,6 +467,39 @@ bool BrotliCompressor::WriteMetaBlock(const size_t input_size,
return true;
}
bool BrotliCompressor::WriteMetadata(const size_t input_size,
const uint8_t* input_buffer,
const bool is_last,
size_t* encoded_size,
uint8_t* encoded_buffer) {
if (input_size > (1 << 24) || input_size + 6 > *encoded_size) {
return false;
}
int storage_ix = last_byte_bits_;
encoded_buffer[0] = last_byte_;
WriteBits(1, 0, &storage_ix, encoded_buffer);
WriteBits(2, 3, &storage_ix, encoded_buffer);
WriteBits(1, 0, &storage_ix, encoded_buffer);
if (input_size == 0) {
WriteBits(2, 0, &storage_ix, encoded_buffer);
*encoded_size = (storage_ix + 7) >> 3;
} else {
size_t nbits = Log2Floor(input_size - 1) + 1;
size_t nbytes = (nbits + 7) / 8;
WriteBits(2, nbytes, &storage_ix, encoded_buffer);
WriteBits(8 * nbytes, input_size - 1, &storage_ix, encoded_buffer);
size_t hdr_size = (storage_ix + 7) >> 3;
memcpy(&encoded_buffer[hdr_size], input_buffer, input_size);
*encoded_size = hdr_size + input_size;
}
if (is_last) {
encoded_buffer[(*encoded_size)++] = 3;
}
last_byte_ = 0;
last_byte_bits_ = 0;
return true;
}
bool BrotliCompressor::FinishStream(
size_t* encoded_size, uint8_t* encoded_buffer) {
return WriteMetaBlock(0, NULL, true, encoded_size, encoded_buffer);

View File

@ -85,6 +85,18 @@ class BrotliCompressor {
size_t* encoded_size,
uint8_t* encoded_buffer);
// Writes a metadata meta-block containing the given input to encoded_buffer.
// *encoded_size should be set to the size of the encoded_buffer.
// Sets *encoded_size to the number of bytes that was written.
// Note that the given input data will not be part of the sliding window and
// thus no backward references can be made to this data from subsequent
// metablocks.
bool WriteMetadata(const size_t input_size,
const uint8_t* input_buffer,
const bool is_last,
size_t* encoded_size,
uint8_t* encoded_buffer);
// Writes a zero-length meta-block with end-of-input bit set to the
// internal output buffer and copies the output buffer to encoded_buffer
// (*encoded_size should be set to the size of encoded_buffer) and sets

View File

@ -129,10 +129,10 @@ bool WriteMetaBlockParallel(const BrotliParams& params,
const bool is_last,
size_t* encoded_size,
uint8_t* encoded_buffer) {
if (block_size == 0 || (!is_last && block_size == 1)) {
if (block_size == 0) {
return false;
}
const size_t input_size = is_last ? block_size : block_size - 1;
const size_t input_size = block_size;
// Copy prefix + next input block into a continuous area.
size_t input_pos = prefix_size;
@ -246,13 +246,10 @@ bool WriteMetaBlockParallel(const BrotliParams& params,
return false;
}
// If this is not the last meta-block, store a one-byte uncompressed
// If this is not the last meta-block, store an empty metadata
// meta-block so that the meta-block will end at a byte boundary.
if (!is_last &&
!StoreUncompressedMetaBlock(is_last, &input_buffer[input_size],
0, mask, 1,
&storage_ix, &storage[0])) {
return false;
if (!is_last) {
StoreSyncMetaBlock(&storage_ix, &storage[0]);
}
// If the compressed data is too large, fall back to an uncompressed