mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
add cut-off to arith coder probability update.
This speeds things up for long message, while not damaging the stats too much for usual-sized cases Change-Id: I3f45e28b771d701e2e1da11eb800de18c4ed12fc
This commit is contained in:
parent
8666a93aae
commit
b361eca1c5
@ -107,10 +107,12 @@ TCoder* TCoderNew(int max_symbol) {
|
||||
const int num_nodes = max_symbol + 1;
|
||||
TCoder* c;
|
||||
uint8_t* memory;
|
||||
const int size = sizeof(*c)
|
||||
+ num_nodes * sizeof(*c->nodes_)
|
||||
+ num_nodes * sizeof(*c->symbols_);
|
||||
if (max_symbol < 0) return NULL;
|
||||
int size;
|
||||
if (max_symbol < 0 || max_symbol >= TCODER_MAX_SYMBOL) {
|
||||
return NULL;
|
||||
}
|
||||
size = sizeof(*c) + num_nodes * sizeof(*c->nodes_)
|
||||
+ num_nodes * sizeof(*c->symbols_);
|
||||
memory = (uint8_t*)malloc(size);
|
||||
if (memory == NULL) return NULL;
|
||||
|
||||
@ -142,7 +144,6 @@ static void ResetTree(TCoder* const c) {
|
||||
assert(c);
|
||||
c->num_symbols_ = 0;
|
||||
c->total_coded_ = 0;
|
||||
c->probaN_ = HALF_PROBA;
|
||||
for (pos = 1; pos <= c->num_nodes_; ++pos) {
|
||||
ResetNode(&c->nodes_[pos], INVALID_SYMBOL);
|
||||
}
|
||||
@ -154,7 +155,6 @@ static void ResetSymbolMap(TCoder* const c) {
|
||||
Symbol_t s;
|
||||
assert(c);
|
||||
c->num_symbols_ = 0;
|
||||
c->probaN_ = HALF_PROBA;
|
||||
for (s = 0; s < c->num_nodes_; ++s) {
|
||||
c->symbols_[s] = INVALID_POS;
|
||||
}
|
||||
@ -253,12 +253,15 @@ static WEBP_INLINE int CalcProba(Count_t num, Count_t total,
|
||||
static WEBP_INLINE void UpdateNodeProbas(TCoder* const c, int pos) {
|
||||
Node* const node = &c->nodes_[pos];
|
||||
const Count_t total = TotalCount(node);
|
||||
node->probaS_ = CalcProba(node->countS_, total, MAX_PROBA, 0);
|
||||
if (total < COUNTER_CUT_OFF)
|
||||
node->probaS_ = CalcProba(node->countS_, total, MAX_PROBA, 0);
|
||||
if (!IsLeaf(c, pos)) {
|
||||
const Count_t total_count = node->count_;
|
||||
const Count_t left_count = TotalCount(&c->nodes_[2 * pos]);
|
||||
node->probaL_ =
|
||||
MAX_PROBA - CalcProba(left_count, total_count, MAX_PROBA, 0);
|
||||
if (total_count < COUNTER_CUT_OFF) {
|
||||
const Count_t left_count = TotalCount(&c->nodes_[2 * pos]);
|
||||
node->probaL_ =
|
||||
MAX_PROBA - CalcProba(left_count, total_count, MAX_PROBA, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,31 +269,31 @@ static void UpdateProbas(TCoder* const c, int pos) {
|
||||
for ( ; pos >= 1; pos >>= 1) {
|
||||
UpdateNodeProbas(c, pos);
|
||||
}
|
||||
c->probaN_ = CalcProba(c->num_symbols_, c->total_coded_, HALF_PROBA - 1, 0);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static void UpdateTree(TCoder* const c, int pos, Count_t incr) {
|
||||
static void UpdateTree(TCoder* const c, int pos) {
|
||||
Node* node = &c->nodes_[pos];
|
||||
const int is_fresh_new_symbol = (node->countS_ == 0);
|
||||
assert(c);
|
||||
assert(pos >= 1 && pos <= c->num_nodes_);
|
||||
assert(node->symbol_ != INVALID_SYMBOL);
|
||||
if (!c->frozen_ || is_fresh_new_symbol) {
|
||||
if (!(c->frozen_ || node->countS_ >= COUNTER_CUT_OFF) ||
|
||||
is_fresh_new_symbol) {
|
||||
const int starting_pos = pos; // save for later
|
||||
// Update the counters up the tree, possibly exchanging some nodes
|
||||
node->countS_ += incr;
|
||||
++node->countS_;
|
||||
while (pos > 1) {
|
||||
Node* const parent = &c->nodes_[pos >> 1];
|
||||
parent->count_ += incr;
|
||||
++parent->count_;
|
||||
if (parent->countS_ < node->countS_) {
|
||||
ExchangeSymbol(c, pos);
|
||||
}
|
||||
pos >>= 1;
|
||||
node = parent;
|
||||
}
|
||||
c->total_coded_ += incr;
|
||||
++c->total_coded_;
|
||||
UpdateProbas(c, starting_pos); // Update the probas along the modified path
|
||||
}
|
||||
}
|
||||
@ -339,10 +342,13 @@ void TCoderEncode(TCoder* const c, int s, VP8BitWriter* const bw) {
|
||||
int pos;
|
||||
const int is_new_symbol = (c->symbols_[s] == INVALID_POS);
|
||||
assert(c);
|
||||
assert(s >= 0 && s < c->num_nodes_);
|
||||
if (!c->fixed_symbols_ && c->num_symbols_ < c->num_nodes_) {
|
||||
if (c->num_symbols_ > 0) {
|
||||
if (bw != NULL) {
|
||||
VP8PutBit(bw, is_new_symbol, c->probaN_);
|
||||
const int new_symbol_proba =
|
||||
CalcProba(c->num_symbols_, c->total_coded_, HALF_PROBA - 1, 0);
|
||||
VP8PutBit(bw, is_new_symbol, new_symbol_proba);
|
||||
}
|
||||
} else {
|
||||
assert(is_new_symbol);
|
||||
@ -381,7 +387,7 @@ void TCoderEncode(TCoder* const c, int s, VP8BitWriter* const bw) {
|
||||
assert(parent == pos);
|
||||
}
|
||||
}
|
||||
UpdateTree(c, pos, 1);
|
||||
UpdateTree(c, pos);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -396,7 +402,9 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) {
|
||||
// Check if we need to transmit the new symbol's value
|
||||
if (!c->fixed_symbols_ && c->num_symbols_ < c->num_nodes_) {
|
||||
if (c->num_symbols_ > 0) {
|
||||
is_new_symbol = VP8GetBit(br, c->probaN_);
|
||||
const int new_symbol_proba =
|
||||
CalcProba(c->num_symbols_, c->total_coded_, HALF_PROBA - 1, 0);
|
||||
is_new_symbol = VP8GetBit(br, new_symbol_proba);
|
||||
} else {
|
||||
is_new_symbol = 1;
|
||||
}
|
||||
@ -404,6 +412,10 @@ 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;
|
||||
}
|
||||
pos = NewNode(c, s);
|
||||
} else {
|
||||
pos = 1;
|
||||
@ -431,7 +443,7 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) {
|
||||
assert(pos == SymbolToNode(c, s));
|
||||
}
|
||||
assert(pos <= c->num_nodes_);
|
||||
UpdateTree(c, pos, 1);
|
||||
UpdateTree(c, pos);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,8 @@ typedef struct TCoder TCoder;
|
||||
|
||||
// Creates a tree-coder capable of coding symbols in
|
||||
// the [0, max_symbol] range. Returns NULL in case of memory error.
|
||||
// 'max_symbol' must be in the range [0, TCODER_MAX_SYMBOL)
|
||||
#define TCODER_MAX_SYMBOL (1 << 24)
|
||||
TCoder* TCoderNew(int max_symbol);
|
||||
// Re-initialize an existing object, make it ready for a new encoding or
|
||||
// decoding cycle.
|
||||
|
@ -37,6 +37,11 @@ typedef uint32_t Count_t; // TODO(skal): check overflow during coding.
|
||||
#define MAX_PROBA 255
|
||||
#define HALF_PROBA 128
|
||||
|
||||
// Limit the number of tree updates above which we freeze the probabilities.
|
||||
// Mainly for speed reason.
|
||||
// TODO(skal): could be a bitstream parameter?
|
||||
#define COUNTER_CUT_OFF 16383
|
||||
|
||||
typedef struct { // ternary node.
|
||||
Symbol_t symbol_;
|
||||
// Note: theoretically, one of this three field is redundant and could be
|
||||
@ -54,7 +59,6 @@ struct TCoder {
|
||||
Count_t total_coded_; // total number of coded symbols
|
||||
int frozen_; // if true, frequencies are not updated
|
||||
int fixed_symbols_; // if true, symbols are not updated
|
||||
int probaN_; // cached new-symbol probability
|
||||
|
||||
// constants:
|
||||
int num_nodes_; // max number of symbols or nodes. Constant, > 0.
|
||||
|
Loading…
Reference in New Issue
Block a user