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;
|
const int num_nodes = max_symbol + 1;
|
||||||
TCoder* c;
|
TCoder* c;
|
||||||
uint8_t* memory;
|
uint8_t* memory;
|
||||||
const int size = sizeof(*c)
|
int size;
|
||||||
+ num_nodes * sizeof(*c->nodes_)
|
if (max_symbol < 0 || max_symbol >= TCODER_MAX_SYMBOL) {
|
||||||
+ num_nodes * sizeof(*c->symbols_);
|
return NULL;
|
||||||
if (max_symbol < 0) return NULL;
|
}
|
||||||
|
size = sizeof(*c) + num_nodes * sizeof(*c->nodes_)
|
||||||
|
+ num_nodes * sizeof(*c->symbols_);
|
||||||
memory = (uint8_t*)malloc(size);
|
memory = (uint8_t*)malloc(size);
|
||||||
if (memory == NULL) return NULL;
|
if (memory == NULL) return NULL;
|
||||||
|
|
||||||
@ -142,7 +144,6 @@ static void ResetTree(TCoder* const c) {
|
|||||||
assert(c);
|
assert(c);
|
||||||
c->num_symbols_ = 0;
|
c->num_symbols_ = 0;
|
||||||
c->total_coded_ = 0;
|
c->total_coded_ = 0;
|
||||||
c->probaN_ = HALF_PROBA;
|
|
||||||
for (pos = 1; pos <= c->num_nodes_; ++pos) {
|
for (pos = 1; pos <= c->num_nodes_; ++pos) {
|
||||||
ResetNode(&c->nodes_[pos], INVALID_SYMBOL);
|
ResetNode(&c->nodes_[pos], INVALID_SYMBOL);
|
||||||
}
|
}
|
||||||
@ -154,7 +155,6 @@ static void ResetSymbolMap(TCoder* const c) {
|
|||||||
Symbol_t s;
|
Symbol_t s;
|
||||||
assert(c);
|
assert(c);
|
||||||
c->num_symbols_ = 0;
|
c->num_symbols_ = 0;
|
||||||
c->probaN_ = HALF_PROBA;
|
|
||||||
for (s = 0; s < c->num_nodes_; ++s) {
|
for (s = 0; s < c->num_nodes_; ++s) {
|
||||||
c->symbols_[s] = INVALID_POS;
|
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) {
|
static WEBP_INLINE void UpdateNodeProbas(TCoder* const c, int pos) {
|
||||||
Node* const node = &c->nodes_[pos];
|
Node* const node = &c->nodes_[pos];
|
||||||
const Count_t total = TotalCount(node);
|
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)) {
|
if (!IsLeaf(c, pos)) {
|
||||||
const Count_t total_count = node->count_;
|
const Count_t total_count = node->count_;
|
||||||
const Count_t left_count = TotalCount(&c->nodes_[2 * pos]);
|
if (total_count < COUNTER_CUT_OFF) {
|
||||||
node->probaL_ =
|
const Count_t left_count = TotalCount(&c->nodes_[2 * pos]);
|
||||||
MAX_PROBA - CalcProba(left_count, total_count, MAX_PROBA, 0);
|
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) {
|
for ( ; pos >= 1; pos >>= 1) {
|
||||||
UpdateNodeProbas(c, pos);
|
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];
|
Node* node = &c->nodes_[pos];
|
||||||
const int is_fresh_new_symbol = (node->countS_ == 0);
|
const int is_fresh_new_symbol = (node->countS_ == 0);
|
||||||
assert(c);
|
assert(c);
|
||||||
assert(pos >= 1 && pos <= c->num_nodes_);
|
assert(pos >= 1 && pos <= c->num_nodes_);
|
||||||
assert(node->symbol_ != INVALID_SYMBOL);
|
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
|
const int starting_pos = pos; // save for later
|
||||||
// Update the counters up the tree, possibly exchanging some nodes
|
// Update the counters up the tree, possibly exchanging some nodes
|
||||||
node->countS_ += incr;
|
++node->countS_;
|
||||||
while (pos > 1) {
|
while (pos > 1) {
|
||||||
Node* const parent = &c->nodes_[pos >> 1];
|
Node* const parent = &c->nodes_[pos >> 1];
|
||||||
parent->count_ += incr;
|
++parent->count_;
|
||||||
if (parent->countS_ < node->countS_) {
|
if (parent->countS_ < node->countS_) {
|
||||||
ExchangeSymbol(c, pos);
|
ExchangeSymbol(c, pos);
|
||||||
}
|
}
|
||||||
pos >>= 1;
|
pos >>= 1;
|
||||||
node = parent;
|
node = parent;
|
||||||
}
|
}
|
||||||
c->total_coded_ += incr;
|
++c->total_coded_;
|
||||||
UpdateProbas(c, starting_pos); // Update the probas along the modified path
|
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;
|
int pos;
|
||||||
const int is_new_symbol = (c->symbols_[s] == INVALID_POS);
|
const int is_new_symbol = (c->symbols_[s] == INVALID_POS);
|
||||||
assert(c);
|
assert(c);
|
||||||
|
assert(s >= 0 && s < c->num_nodes_);
|
||||||
if (!c->fixed_symbols_ && c->num_symbols_ < c->num_nodes_) {
|
if (!c->fixed_symbols_ && c->num_symbols_ < c->num_nodes_) {
|
||||||
if (c->num_symbols_ > 0) {
|
if (c->num_symbols_ > 0) {
|
||||||
if (bw != NULL) {
|
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 {
|
} else {
|
||||||
assert(is_new_symbol);
|
assert(is_new_symbol);
|
||||||
@ -381,7 +387,7 @@ void TCoderEncode(TCoder* const c, int s, VP8BitWriter* const bw) {
|
|||||||
assert(parent == pos);
|
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
|
// Check if we need to transmit the new symbol's value
|
||||||
if (!c->fixed_symbols_ && c->num_symbols_ < c->num_nodes_) {
|
if (!c->fixed_symbols_ && c->num_symbols_ < c->num_nodes_) {
|
||||||
if (c->num_symbols_ > 0) {
|
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 {
|
} else {
|
||||||
is_new_symbol = 1;
|
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.
|
// 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_);
|
s = DecodeSymbol(br, c->num_nodes_);
|
||||||
|
if (s >= c->num_nodes_) {
|
||||||
|
br->eof_ = 1; // will make decoding abort.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
pos = NewNode(c, s);
|
pos = NewNode(c, s);
|
||||||
} else {
|
} else {
|
||||||
pos = 1;
|
pos = 1;
|
||||||
@ -431,7 +443,7 @@ int TCoderDecode(TCoder* const c, VP8BitReader* const br) {
|
|||||||
assert(pos == SymbolToNode(c, s));
|
assert(pos == SymbolToNode(c, s));
|
||||||
}
|
}
|
||||||
assert(pos <= c->num_nodes_);
|
assert(pos <= c->num_nodes_);
|
||||||
UpdateTree(c, pos, 1);
|
UpdateTree(c, pos);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,8 @@ typedef struct TCoder TCoder;
|
|||||||
|
|
||||||
// Creates a tree-coder capable of coding symbols in
|
// Creates a tree-coder capable of coding symbols in
|
||||||
// the [0, max_symbol] range. Returns NULL in case of memory error.
|
// 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);
|
TCoder* TCoderNew(int max_symbol);
|
||||||
// Re-initialize an existing object, make it ready for a new encoding or
|
// Re-initialize an existing object, make it ready for a new encoding or
|
||||||
// decoding cycle.
|
// decoding cycle.
|
||||||
|
@ -37,6 +37,11 @@ typedef uint32_t Count_t; // TODO(skal): check overflow during coding.
|
|||||||
#define MAX_PROBA 255
|
#define MAX_PROBA 255
|
||||||
#define HALF_PROBA 128
|
#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.
|
typedef struct { // ternary node.
|
||||||
Symbol_t symbol_;
|
Symbol_t symbol_;
|
||||||
// Note: theoretically, one of this three field is redundant and could be
|
// 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
|
Count_t total_coded_; // total number of coded symbols
|
||||||
int frozen_; // if true, frequencies are not updated
|
int frozen_; // if true, frequencies are not updated
|
||||||
int fixed_symbols_; // if true, symbols are not updated
|
int fixed_symbols_; // if true, symbols are not updated
|
||||||
int probaN_; // cached new-symbol probability
|
|
||||||
|
|
||||||
// constants:
|
// constants:
|
||||||
int num_nodes_; // max number of symbols or nodes. Constant, > 0.
|
int num_nodes_; // max number of symbols or nodes. Constant, > 0.
|
||||||
|
Loading…
Reference in New Issue
Block a user