mirror of
https://github.com/webmproject/libwebp.git
synced 2025-02-13 15:32:53 +01:00
~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:
parent
3bc1b14191
commit
0a7102ba60
@ -188,8 +188,8 @@ static WEBP_INLINE int IsLeaf(const TCoder* const c, int pos) {
|
|||||||
return (2 * pos > c->num_symbols_);
|
return (2 * pos > c->num_symbols_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if node has no child.
|
// Returns true if node has no right child.
|
||||||
static WEBP_INLINE int HasOnlyRightChild(const TCoder* const c, int pos) {
|
static WEBP_INLINE int HasOnlyLeftChild(const TCoder* const c, int pos) {
|
||||||
return (2 * pos == c->num_symbols_);
|
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_;
|
const int pos = 1 + c->num_symbols_;
|
||||||
assert(c);
|
assert(c);
|
||||||
assert(c->num_symbols_ < c->num_nodes_);
|
assert(c->num_symbols_ < c->num_nodes_);
|
||||||
|
assert(c->symbols_[s] == INVALID_POS);
|
||||||
|
assert(c->nodes_[pos].symbol_ == INVALID_SYMBOL);
|
||||||
c->symbols_[s] = pos;
|
c->symbols_[s] = pos;
|
||||||
ResetNode(&c->nodes_[pos], s);
|
ResetNode(&c->nodes_[pos], s);
|
||||||
++c->num_symbols_;
|
++c->num_symbols_;
|
||||||
@ -319,6 +321,7 @@ static WEBP_INLINE void CodeSymbol(VP8BitWriter* const bw, int s,
|
|||||||
int max_value) {
|
int max_value) {
|
||||||
int i, up = 1;
|
int i, up = 1;
|
||||||
assert(bw);
|
assert(bw);
|
||||||
|
assert(s < max_value);
|
||||||
for (i = 0; up < max_value; up <<= 1, ++i) {
|
for (i = 0; up < max_value; up <<= 1, ++i) {
|
||||||
int den = (max_value >> 1) & ~(up - 1);
|
int den = (max_value >> 1) & ~(up - 1);
|
||||||
if (max_value & up) den |= max_value & (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 (is_new_symbol) {
|
||||||
if (bw != NULL) {
|
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);
|
pos = NewNode(c, s);
|
||||||
} else {
|
} else {
|
||||||
@ -376,7 +383,7 @@ void TCoderEncode(TCoder* const c, int s, VP8BitWriter* const bw) {
|
|||||||
const int is_stop = (i == length);
|
const int is_stop = (i == length);
|
||||||
if (VP8PutBit(bw, is_stop, symbol_proba)) {
|
if (VP8PutBit(bw, is_stop, symbol_proba)) {
|
||||||
break;
|
break;
|
||||||
} else if (!HasOnlyRightChild(c, parent)) {
|
} else if (!HasOnlyLeftChild(c, parent)) {
|
||||||
const int left_proba = node->probaL_;
|
const int left_proba = node->probaL_;
|
||||||
const int is_right =
|
const int is_right =
|
||||||
(pos >> (length - 1 - i)) & 1; // extract bits #i
|
(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.
|
// Code either the raw value, or the path downward to its node.
|
||||||
if (is_new_symbol) {
|
if (is_new_symbol) {
|
||||||
s = DecodeSymbol(br, c->num_nodes_);
|
int count = DecodeSymbol(br, c->num_nodes_ - c->num_symbols_);
|
||||||
if (s >= c->num_nodes_) {
|
// The 'count' value specifies the number of empty slots to jump
|
||||||
br->eof_ = 1; // will make decoding abort.
|
// over. We skip the already-used ones.
|
||||||
return 0;
|
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);
|
pos = NewNode(c, s);
|
||||||
} else {
|
} else {
|
||||||
@ -431,7 +444,7 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) {
|
|||||||
break; // reached the stopping node for the coded symbol.
|
break; // reached the stopping node for the coded symbol.
|
||||||
} else {
|
} else {
|
||||||
// Not yet done, keep traversing and branching.
|
// Not yet done, keep traversing and branching.
|
||||||
if (!HasOnlyRightChild(c, pos)) {
|
if (!HasOnlyLeftChild(c, pos)) {
|
||||||
const int left_proba = node->probaL_;
|
const int left_proba = node->probaL_;
|
||||||
const int is_right = VP8GetBit(br, left_proba);
|
const int is_right = VP8GetBit(br, left_proba);
|
||||||
pos = (pos << 1) | is_right;
|
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_nodes_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert(pos <= c->num_symbols_);
|
||||||
s = c->nodes_[pos].symbol_;
|
s = c->nodes_[pos].symbol_;
|
||||||
assert(pos == SymbolToNode(c, s));
|
assert(pos == SymbolToNode(c, s));
|
||||||
}
|
}
|
||||||
assert(pos <= c->num_nodes_);
|
assert(pos <= c->num_symbols_);
|
||||||
UpdateTree(c, pos);
|
UpdateTree(c, pos);
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
|
Error:
|
||||||
|
br->eof_ = 1; // will make decoding abort.
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user