~1% improvement of alpha compression

by packing the symbol map more efficiently.

This is mainly useful in making it harder to generate invalid bitstream:
before this change, one could code the same symbol twice. Now, it's
impossible, since we code the position using empty symbol slots, instead
of total position.

* Fix the HasOnlyLeftChild() naming while at it.

Change-Id: I63c56c80a4f04a86ac83eded1e3306329815b6c9
This commit is contained in:
Pascal Massimino 2012-02-24 18:36:57 +00:00 committed by James Zern
parent 3bc1b14191
commit 0a7102ba60

View File

@ -188,8 +188,8 @@ static WEBP_INLINE int IsLeaf(const TCoder* const c, int pos) {
return (2 * pos > c->num_symbols_);
}
// Returns true if node has no child.
static WEBP_INLINE int HasOnlyRightChild(const TCoder* const c, int pos) {
// Returns true if node has no right child.
static WEBP_INLINE int HasOnlyLeftChild(const TCoder* const c, int pos) {
return (2 * pos == c->num_symbols_);
}
@ -202,6 +202,8 @@ static int NewNode(TCoder* const c, int s) {
const int pos = 1 + c->num_symbols_;
assert(c);
assert(c->num_symbols_ < c->num_nodes_);
assert(c->symbols_[s] == INVALID_POS);
assert(c->nodes_[pos].symbol_ == INVALID_SYMBOL);
c->symbols_[s] = pos;
ResetNode(&c->nodes_[pos], s);
++c->num_symbols_;
@ -319,6 +321,7 @@ static WEBP_INLINE void CodeSymbol(VP8BitWriter* const bw, int s,
int max_value) {
int i, up = 1;
assert(bw);
assert(s < max_value);
for (i = 0; up < max_value; up <<= 1, ++i) {
int den = (max_value >> 1) & ~(up - 1);
if (max_value & up) den |= max_value & (up - 1);
@ -361,7 +364,11 @@ void TCoderEncode(TCoder* const c, int s, VP8BitWriter* const bw) {
}
if (is_new_symbol) {
if (bw != NULL) {
CodeSymbol(bw, s, c->num_nodes_);
int k, count = 0;
for (k = 0; k < s; ++k) {
count += (c->symbols_[k] == INVALID_POS);
}
CodeSymbol(bw, count, c->num_nodes_ - c->num_symbols_);
}
pos = NewNode(c, s);
} else {
@ -376,7 +383,7 @@ void TCoderEncode(TCoder* const c, int s, VP8BitWriter* const bw) {
const int is_stop = (i == length);
if (VP8PutBit(bw, is_stop, symbol_proba)) {
break;
} else if (!HasOnlyRightChild(c, parent)) {
} else if (!HasOnlyLeftChild(c, parent)) {
const int left_proba = node->probaL_;
const int is_right =
(pos >> (length - 1 - i)) & 1; // extract bits #i
@ -414,10 +421,16 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) {
}
// Code either the raw value, or the path downward to its node.
if (is_new_symbol) {
s = DecodeSymbol(br, c->num_nodes_);
if (s >= c->num_nodes_) {
br->eof_ = 1; // will make decoding abort.
return 0;
int count = DecodeSymbol(br, c->num_nodes_ - c->num_symbols_);
// The 'count' value specifies the number of empty slots to jump
// over. We skip the already-used ones.
for (s = 0; s < c->num_nodes_; ++s) {
if (c->symbols_[s] == INVALID_POS) {
if (count-- == 0) break;
}
}
if (s == c->num_nodes_) {
goto Error;
}
pos = NewNode(c, s);
} else {
@ -431,7 +444,7 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) {
break; // reached the stopping node for the coded symbol.
} else {
// Not yet done, keep traversing and branching.
if (!HasOnlyRightChild(c, pos)) {
if (!HasOnlyLeftChild(c, pos)) {
const int left_proba = node->probaL_;
const int is_right = VP8GetBit(br, left_proba);
pos = (pos << 1) | is_right;
@ -442,12 +455,17 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) {
assert(pos <= c->num_nodes_);
}
}
assert(pos <= c->num_symbols_);
s = c->nodes_[pos].symbol_;
assert(pos == SymbolToNode(c, s));
}
assert(pos <= c->num_nodes_);
assert(pos <= c->num_symbols_);
UpdateTree(c, pos);
return s;
Error:
br->eof_ = 1; // will make decoding abort.
return 0;
}
// -----------------------------------------------------------------------------