mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
split StoreHuffmanCode() into smaller functions
Change-Id: Iaa715f4997505eebabee1e92e964a5d7ee6f3e7d
This commit is contained in:
parent
d0d88990d8
commit
e8d3d6a018
168
src/enc/vp8l.c
168
src/enc/vp8l.c
@ -432,9 +432,11 @@ static void ClearHuffmanTreeIfOnlyOneSymbol(const int num_symbols,
|
|||||||
int k;
|
int k;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (k = 0; k < num_symbols; ++k) {
|
for (k = 0; k < num_symbols; ++k) {
|
||||||
if (lengths[k] != 0) ++count;
|
if (lengths[k] != 0) {
|
||||||
|
++count;
|
||||||
if (count > 1) return;
|
if (count > 1) return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for (k = 0; k < num_symbols; ++k) {
|
for (k = 0; k < num_symbols; ++k) {
|
||||||
lengths[k] = 0;
|
lengths[k] = 0;
|
||||||
symbols[k] = 0;
|
symbols[k] = 0;
|
||||||
@ -490,34 +492,105 @@ static void StoreHuffmanTreeToBitMask(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int StoreFullHuffmanCode(VP8LBitWriter* const bw,
|
||||||
|
const uint8_t* const bit_lengths,
|
||||||
|
int bit_lengths_size) {
|
||||||
|
int ok = 0;
|
||||||
|
int huffman_tree_size = 0;
|
||||||
|
uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
|
||||||
|
uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
|
||||||
|
uint8_t* huffman_tree_extra_bits;
|
||||||
|
uint8_t* const huffman_tree =
|
||||||
|
(uint8_t*)malloc(bit_lengths_size * sizeof(*huffman_tree) +
|
||||||
|
bit_lengths_size * sizeof(*huffman_tree_extra_bits));
|
||||||
|
|
||||||
|
if (huffman_tree == NULL) return 0;
|
||||||
|
huffman_tree_extra_bits =
|
||||||
|
huffman_tree + bit_lengths_size * sizeof(*huffman_tree);
|
||||||
|
|
||||||
|
VP8LWriteBits(bw, 1, 0);
|
||||||
|
VP8LCreateCompressedHuffmanTree(bit_lengths, bit_lengths_size,
|
||||||
|
&huffman_tree_size, huffman_tree,
|
||||||
|
huffman_tree_extra_bits);
|
||||||
|
{
|
||||||
|
int histogram[CODE_LENGTH_CODES] = { 0 };
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < huffman_tree_size; ++i) {
|
||||||
|
++histogram[huffman_tree[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!VP8LCreateHuffmanTree(histogram, CODE_LENGTH_CODES,
|
||||||
|
7, code_length_bitdepth)) {
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VP8LConvertBitDepthsToSymbols(code_length_bitdepth, CODE_LENGTH_CODES,
|
||||||
|
code_length_bitdepth_symbols);
|
||||||
|
StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
|
||||||
|
ClearHuffmanTreeIfOnlyOneSymbol(CODE_LENGTH_CODES,
|
||||||
|
code_length_bitdepth,
|
||||||
|
code_length_bitdepth_symbols);
|
||||||
|
{
|
||||||
|
int trailing_zero_bits = 0;
|
||||||
|
int trimmed_length = huffman_tree_size;
|
||||||
|
int write_trimmed_length;
|
||||||
|
int length;
|
||||||
|
int i = huffman_tree_size;
|
||||||
|
while (i-- > 0) {
|
||||||
|
const int ix = huffman_tree[i];
|
||||||
|
if (ix == 0 || ix == 17 || ix == 18) {
|
||||||
|
--trimmed_length; // discount trailing zeros
|
||||||
|
trailing_zero_bits += code_length_bitdepth[ix];
|
||||||
|
if (ix == 17) {
|
||||||
|
trailing_zero_bits += 3;
|
||||||
|
} else if (ix == 18) {
|
||||||
|
trailing_zero_bits += 7;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
|
||||||
|
length = write_trimmed_length ? trimmed_length : huffman_tree_size;
|
||||||
|
VP8LWriteBits(bw, 1, write_trimmed_length);
|
||||||
|
if (write_trimmed_length) {
|
||||||
|
const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
|
||||||
|
const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
|
||||||
|
VP8LWriteBits(bw, 3, nbitpairs - 1);
|
||||||
|
VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2);
|
||||||
|
}
|
||||||
|
StoreHuffmanTreeToBitMask(bw, huffman_tree, huffman_tree_extra_bits,
|
||||||
|
length, code_length_bitdepth,
|
||||||
|
code_length_bitdepth_symbols);
|
||||||
|
}
|
||||||
|
ok = 1;
|
||||||
|
End:
|
||||||
|
free(huffman_tree);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
static int StoreHuffmanCode(VP8LBitWriter* const bw,
|
static int StoreHuffmanCode(VP8LBitWriter* const bw,
|
||||||
const uint8_t* const bit_lengths,
|
const uint8_t* const bit_lengths,
|
||||||
int bit_lengths_size) {
|
int bit_lengths_size) {
|
||||||
int i;
|
int i;
|
||||||
int ok = 0;
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int symbols[2] = { 0, 0 };
|
int symbols[2] = { 0, 0 };
|
||||||
int huffman_tree_size = 0;
|
const int kMaxBits = 8;
|
||||||
uint8_t code_length_bitdepth[CODE_LENGTH_CODES];
|
const int kMaxSymbol = 1 << kMaxBits;
|
||||||
uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES];
|
|
||||||
int huffman_tree_histogram[CODE_LENGTH_CODES];
|
|
||||||
uint8_t* huffman_tree_extra_bits;
|
|
||||||
uint8_t* huffman_tree = (uint8_t*)malloc(bit_lengths_size *
|
|
||||||
(sizeof(*huffman_tree) +
|
|
||||||
sizeof(*huffman_tree_extra_bits)));
|
|
||||||
|
|
||||||
if (huffman_tree == NULL) goto End;
|
// Check whether it's a small tree.
|
||||||
huffman_tree_extra_bits =
|
for (i = 0; i < bit_lengths_size && count < 3; ++i) {
|
||||||
huffman_tree + (bit_lengths_size * sizeof(*huffman_tree));
|
|
||||||
|
|
||||||
for (i = 0; i < bit_lengths_size; ++i) {
|
|
||||||
if (bit_lengths[i] != 0) {
|
if (bit_lengths[i] != 0) {
|
||||||
if (count < 2) symbols[count] = i;
|
if (count < 2) symbols[count] = i;
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count == 0) count = 1;
|
|
||||||
if (count <= 2 && symbols[0] < 256 && symbols[1] < 256) {
|
if (count == 0) { // emit minimal tree for empty cases
|
||||||
|
// bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
|
||||||
|
VP8LWriteBits(bw, 4, 0x01);
|
||||||
|
return 1;
|
||||||
|
} else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
|
||||||
VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols.
|
VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols.
|
||||||
VP8LWriteBits(bw, 1, count - 1);
|
VP8LWriteBits(bw, 1, count - 1);
|
||||||
if (symbols[0] <= 1) {
|
if (symbols[0] <= 1) {
|
||||||
@ -530,68 +603,11 @@ static int StoreHuffmanCode(VP8LBitWriter* const bw,
|
|||||||
if (count == 2) {
|
if (count == 2) {
|
||||||
VP8LWriteBits(bw, 8, symbols[1]);
|
VP8LWriteBits(bw, 8, symbols[1]);
|
||||||
}
|
}
|
||||||
ok = 1;
|
return 1;
|
||||||
goto End;
|
|
||||||
}
|
|
||||||
|
|
||||||
VP8LWriteBits(bw, 1, 0);
|
|
||||||
VP8LCreateCompressedHuffmanTree(bit_lengths, bit_lengths_size,
|
|
||||||
&huffman_tree_size, huffman_tree,
|
|
||||||
huffman_tree_extra_bits);
|
|
||||||
memset(huffman_tree_histogram, 0, sizeof(huffman_tree_histogram));
|
|
||||||
for (i = 0; i < huffman_tree_size; ++i) {
|
|
||||||
++huffman_tree_histogram[huffman_tree[i]];
|
|
||||||
}
|
|
||||||
memset(code_length_bitdepth, 0, sizeof(code_length_bitdepth));
|
|
||||||
memset(code_length_bitdepth_symbols, 0, sizeof(code_length_bitdepth_symbols));
|
|
||||||
|
|
||||||
if (!VP8LCreateHuffmanTree(huffman_tree_histogram, CODE_LENGTH_CODES,
|
|
||||||
7, code_length_bitdepth)) {
|
|
||||||
goto End;
|
|
||||||
}
|
|
||||||
VP8LConvertBitDepthsToSymbols(code_length_bitdepth, CODE_LENGTH_CODES,
|
|
||||||
code_length_bitdepth_symbols);
|
|
||||||
StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
|
|
||||||
ClearHuffmanTreeIfOnlyOneSymbol(CODE_LENGTH_CODES,
|
|
||||||
code_length_bitdepth,
|
|
||||||
code_length_bitdepth_symbols);
|
|
||||||
{
|
|
||||||
int num_trailing_zeros = 0;
|
|
||||||
int trailing_zero_bits = 0;
|
|
||||||
int trimmed_length;
|
|
||||||
int write_length;
|
|
||||||
int length;
|
|
||||||
for (i = huffman_tree_size; i > 0; --i) {
|
|
||||||
int ix = huffman_tree[i - 1];
|
|
||||||
if (ix == 0 || ix == 17 || ix == 18) {
|
|
||||||
++num_trailing_zeros;
|
|
||||||
trailing_zero_bits += code_length_bitdepth[ix];
|
|
||||||
if (ix == 17) trailing_zero_bits += 3;
|
|
||||||
if (ix == 18) trailing_zero_bits += 7;
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
return StoreFullHuffmanCode(bw, bit_lengths, bit_lengths_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trimmed_length = huffman_tree_size - num_trailing_zeros;
|
|
||||||
write_length = (trimmed_length > 1 && trailing_zero_bits > 12);
|
|
||||||
length = write_length ? trimmed_length : huffman_tree_size;
|
|
||||||
VP8LWriteBits(bw, 1, write_length);
|
|
||||||
if (write_length) {
|
|
||||||
const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
|
|
||||||
const int nbitpairs = nbits == 0 ? 1 : (nbits + 1) / 2;
|
|
||||||
VP8LWriteBits(bw, 3, nbitpairs - 1);
|
|
||||||
VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2);
|
|
||||||
}
|
|
||||||
StoreHuffmanTreeToBitMask(bw, huffman_tree, huffman_tree_extra_bits,
|
|
||||||
length, code_length_bitdepth,
|
|
||||||
code_length_bitdepth_symbols);
|
|
||||||
}
|
|
||||||
ok = 1;
|
|
||||||
|
|
||||||
End:
|
|
||||||
free(huffman_tree);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void StoreImageToBitMask(
|
static void StoreImageToBitMask(
|
||||||
VP8LBitWriter* const bw, int width, int histo_bits,
|
VP8LBitWriter* const bw, int width, int histo_bits,
|
||||||
|
Loading…
Reference in New Issue
Block a user