split StoreHuffmanCode() into smaller functions

Change-Id: Iaa715f4997505eebabee1e92e964a5d7ee6f3e7d
This commit is contained in:
Pascal Massimino 2012-05-03 17:04:32 +00:00 committed by James Zern
parent d0d88990d8
commit e8d3d6a018

View File

@ -432,8 +432,10 @@ 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) {
if (count > 1) return; ++count;
if (count > 1) return;
}
} }
for (k = 0; k < num_symbols; ++k) { for (k = 0; k < num_symbols; ++k) {
lengths[k] = 0; lengths[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,67 +603,10 @@ 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; } else {
return StoreFullHuffmanCode(bw, bit_lengths, bit_lengths_size);
} }
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 {
break;
}
}
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(