mirror of
https://github.com/webmproject/libwebp.git
synced 2025-04-04 16:06:49 +02:00
BitTrace: if BITTRACE is > 0, record and print syntax bits used
* Bittrace decoding is ~3x slower. * Binary is the same byte-wise if BITTRACE=0 * Example output: === Bit traces === global-header : 174 bytes [ 0.69%] [count: 1850] segments : 246 bytes [ 0.98%] [count: 3072] block-size : 170 bytes [ 0.68%] [count: 1536] pred-modes : 3829 bytes [15.27%] [count: 51458] pred-modes-uv : 279 bytes [ 1.11%] [count: 2329] coeffs : 20370 bytes [81.27%] [count: 212914] Total: 25065 bytes Change-Id: Ie32569c4e54a7ec13264e68d2dae2ce45c8536cb
This commit is contained in:
parent
067031eaed
commit
fcfd9c71b4
@ -118,6 +118,10 @@ GROFF = /usr/bin/groff
|
|||||||
COL = /usr/bin/col
|
COL = /usr/bin/col
|
||||||
LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm
|
LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm
|
||||||
|
|
||||||
|
ifdef BITTRACE
|
||||||
|
CFLAGS += -DBITTRACE=$(BITTRACE)
|
||||||
|
endif
|
||||||
|
|
||||||
ANIM_UTIL_OBJS = \
|
ANIM_UTIL_OBJS = \
|
||||||
examples/anim_util.o \
|
examples/anim_util.o \
|
||||||
|
|
||||||
|
@ -61,12 +61,17 @@ static const uint16_t kAcTable[128] = {
|
|||||||
|
|
||||||
void VP8ParseQuant(VP8Decoder* const dec) {
|
void VP8ParseQuant(VP8Decoder* const dec) {
|
||||||
VP8BitReader* const br = &dec->br_;
|
VP8BitReader* const br = &dec->br_;
|
||||||
const int base_q0 = VP8GetValue(br, 7);
|
const int base_q0 = VP8GetValue(br, 7, "global-header");
|
||||||
const int dqy1_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
const int dqy1_dc = VP8Get(br, "global-header") ?
|
||||||
const int dqy2_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||||
const int dqy2_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
const int dqy2_dc = VP8Get(br, "global-header") ?
|
||||||
const int dquv_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||||
const int dquv_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
const int dqy2_ac = VP8Get(br, "global-header") ?
|
||||||
|
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||||
|
const int dquv_dc = VP8Get(br, "global-header") ?
|
||||||
|
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||||
|
const int dquv_ac = VP8Get(br, "global-header") ?
|
||||||
|
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||||
|
|
||||||
const VP8SegmentHeader* const hdr = &dec->segment_hdr_;
|
const VP8SegmentHeader* const hdr = &dec->segment_hdr_;
|
||||||
int i;
|
int i;
|
||||||
|
@ -296,20 +296,21 @@ static void ParseIntraMode(VP8BitReader* const br,
|
|||||||
// to decode more than 1 keyframe.
|
// to decode more than 1 keyframe.
|
||||||
if (dec->segment_hdr_.update_map_) {
|
if (dec->segment_hdr_.update_map_) {
|
||||||
// Hardcoded tree parsing
|
// Hardcoded tree parsing
|
||||||
block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0])
|
block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0], "segments")
|
||||||
? VP8GetBit(br, dec->proba_.segments_[1])
|
? VP8GetBit(br, dec->proba_.segments_[1], "segments")
|
||||||
: 2 + VP8GetBit(br, dec->proba_.segments_[2]);
|
: VP8GetBit(br, dec->proba_.segments_[2], "segments") + 2;
|
||||||
} else {
|
} else {
|
||||||
block->segment_ = 0; // default for intra
|
block->segment_ = 0; // default for intra
|
||||||
}
|
}
|
||||||
if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_);
|
if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_, "skip");
|
||||||
|
|
||||||
block->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
|
block->is_i4x4_ = !VP8GetBit(br, 145, "block-size");
|
||||||
if (!block->is_i4x4_) {
|
if (!block->is_i4x4_) {
|
||||||
// Hardcoded 16x16 intra-mode decision tree.
|
// Hardcoded 16x16 intra-mode decision tree.
|
||||||
const int ymode =
|
const int ymode =
|
||||||
VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED)
|
VP8GetBit(br, 156, "pred-modes") ?
|
||||||
: (VP8GetBit(br, 163) ? V_PRED : DC_PRED);
|
(VP8GetBit(br, 128, "pred-modes") ? TM_PRED : H_PRED) :
|
||||||
|
(VP8GetBit(br, 163, "pred-modes") ? V_PRED : DC_PRED);
|
||||||
block->imodes_[0] = ymode;
|
block->imodes_[0] = ymode;
|
||||||
memset(top, ymode, 4 * sizeof(*top));
|
memset(top, ymode, 4 * sizeof(*top));
|
||||||
memset(left, ymode, 4 * sizeof(*left));
|
memset(left, ymode, 4 * sizeof(*left));
|
||||||
@ -323,22 +324,25 @@ static void ParseIntraMode(VP8BitReader* const br,
|
|||||||
const uint8_t* const prob = kBModesProba[top[x]][ymode];
|
const uint8_t* const prob = kBModesProba[top[x]][ymode];
|
||||||
#if (USE_GENERIC_TREE == 1)
|
#if (USE_GENERIC_TREE == 1)
|
||||||
// Generic tree-parsing
|
// Generic tree-parsing
|
||||||
int i = kYModesIntra4[VP8GetBit(br, prob[0])];
|
int i = kYModesIntra4[VP8GetBit(br, prob[0], "pred-modes")];
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])];
|
i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i], "pred-modes")];
|
||||||
}
|
}
|
||||||
ymode = -i;
|
ymode = -i;
|
||||||
#else
|
#else
|
||||||
// Hardcoded tree parsing
|
// Hardcoded tree parsing
|
||||||
ymode = !VP8GetBit(br, prob[0]) ? B_DC_PRED :
|
ymode = !VP8GetBit(br, prob[0], "pred-modes") ? B_DC_PRED :
|
||||||
!VP8GetBit(br, prob[1]) ? B_TM_PRED :
|
!VP8GetBit(br, prob[1], "pred-modes") ? B_TM_PRED :
|
||||||
!VP8GetBit(br, prob[2]) ? B_VE_PRED :
|
!VP8GetBit(br, prob[2], "pred-modes") ? B_VE_PRED :
|
||||||
!VP8GetBit(br, prob[3]) ?
|
!VP8GetBit(br, prob[3], "pred-modes") ?
|
||||||
(!VP8GetBit(br, prob[4]) ? B_HE_PRED :
|
(!VP8GetBit(br, prob[4], "pred-modes") ? B_HE_PRED :
|
||||||
(!VP8GetBit(br, prob[5]) ? B_RD_PRED : B_VR_PRED)) :
|
(!VP8GetBit(br, prob[5], "pred-modes") ? B_RD_PRED
|
||||||
(!VP8GetBit(br, prob[6]) ? B_LD_PRED :
|
: B_VR_PRED)) :
|
||||||
(!VP8GetBit(br, prob[7]) ? B_VL_PRED :
|
(!VP8GetBit(br, prob[6], "pred-modes") ? B_LD_PRED :
|
||||||
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
|
(!VP8GetBit(br, prob[7], "pred-modes") ? B_VL_PRED :
|
||||||
|
(!VP8GetBit(br, prob[8], "pred-modes") ? B_HD_PRED
|
||||||
|
: B_HU_PRED))
|
||||||
|
);
|
||||||
#endif // USE_GENERIC_TREE
|
#endif // USE_GENERIC_TREE
|
||||||
top[x] = ymode;
|
top[x] = ymode;
|
||||||
}
|
}
|
||||||
@ -348,9 +352,9 @@ static void ParseIntraMode(VP8BitReader* const br,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Hardcoded UVMode decision tree
|
// Hardcoded UVMode decision tree
|
||||||
block->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
|
block->uvmode_ = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED
|
||||||
: !VP8GetBit(br, 114) ? V_PRED
|
: !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED
|
||||||
: VP8GetBit(br, 183) ? TM_PRED : H_PRED;
|
: VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) {
|
int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) {
|
||||||
@ -514,8 +518,10 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
|
|||||||
for (b = 0; b < NUM_BANDS; ++b) {
|
for (b = 0; b < NUM_BANDS; ++b) {
|
||||||
for (c = 0; c < NUM_CTX; ++c) {
|
for (c = 0; c < NUM_CTX; ++c) {
|
||||||
for (p = 0; p < NUM_PROBAS; ++p) {
|
for (p = 0; p < NUM_PROBAS; ++p) {
|
||||||
const int v = VP8GetBit(br, CoeffsUpdateProba[t][b][c][p]) ?
|
const int v =
|
||||||
VP8GetValue(br, 8) : CoeffsProba0[t][b][c][p];
|
VP8GetBit(br, CoeffsUpdateProba[t][b][c][p], "global-header") ?
|
||||||
|
VP8GetValue(br, 8, "global-header") :
|
||||||
|
CoeffsProba0[t][b][c][p];
|
||||||
proba->bands_[t][b].probas_[c][p] = v;
|
proba->bands_[t][b].probas_[c][p] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -524,9 +530,8 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
|
|||||||
proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]];
|
proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dec->use_skip_proba_ = VP8Get(br);
|
dec->use_skip_proba_ = VP8Get(br, "global-header");
|
||||||
if (dec->use_skip_proba_) {
|
if (dec->use_skip_proba_) {
|
||||||
dec->skip_p_ = VP8GetValue(br, 8);
|
dec->skip_p_ = VP8GetValue(br, 8, "global-header");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,23 +161,26 @@ static int ParseSegmentHeader(VP8BitReader* br,
|
|||||||
VP8SegmentHeader* hdr, VP8Proba* proba) {
|
VP8SegmentHeader* hdr, VP8Proba* proba) {
|
||||||
assert(br != NULL);
|
assert(br != NULL);
|
||||||
assert(hdr != NULL);
|
assert(hdr != NULL);
|
||||||
hdr->use_segment_ = VP8Get(br);
|
hdr->use_segment_ = VP8Get(br, "global-header");
|
||||||
if (hdr->use_segment_) {
|
if (hdr->use_segment_) {
|
||||||
hdr->update_map_ = VP8Get(br);
|
hdr->update_map_ = VP8Get(br, "global-header");
|
||||||
if (VP8Get(br)) { // update data
|
if (VP8Get(br, "global-header")) { // update data
|
||||||
int s;
|
int s;
|
||||||
hdr->absolute_delta_ = VP8Get(br);
|
hdr->absolute_delta_ = VP8Get(br, "global-header");
|
||||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||||
hdr->quantizer_[s] = VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
|
hdr->quantizer_[s] = VP8Get(br, "global-header") ?
|
||||||
|
VP8GetSignedValue(br, 7, "global-header") : 0;
|
||||||
}
|
}
|
||||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||||
hdr->filter_strength_[s] = VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
|
hdr->filter_strength_[s] = VP8Get(br, "global-header") ?
|
||||||
|
VP8GetSignedValue(br, 6, "global-header") : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hdr->update_map_) {
|
if (hdr->update_map_) {
|
||||||
int s;
|
int s;
|
||||||
for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
|
for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
|
||||||
proba->segments_[s] = VP8Get(br) ? VP8GetValue(br, 8) : 255u;
|
proba->segments_[s] = VP8Get(br, "global-header") ?
|
||||||
|
VP8GetValue(br, 8, "global-header") : 255u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -205,7 +208,7 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
|
|||||||
size_t last_part;
|
size_t last_part;
|
||||||
size_t p;
|
size_t p;
|
||||||
|
|
||||||
dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2)) - 1;
|
dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2, "global-header")) - 1;
|
||||||
last_part = dec->num_parts_minus_one_;
|
last_part = dec->num_parts_minus_one_;
|
||||||
if (size < 3 * last_part) {
|
if (size < 3 * last_part) {
|
||||||
// we can't even read the sizes with sz[]! That's a failure.
|
// we can't even read the sizes with sz[]! That's a failure.
|
||||||
@ -229,21 +232,21 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
|
|||||||
// Paragraph 9.4
|
// Paragraph 9.4
|
||||||
static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
|
static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
|
||||||
VP8FilterHeader* const hdr = &dec->filter_hdr_;
|
VP8FilterHeader* const hdr = &dec->filter_hdr_;
|
||||||
hdr->simple_ = VP8Get(br);
|
hdr->simple_ = VP8Get(br, "global-header");
|
||||||
hdr->level_ = VP8GetValue(br, 6);
|
hdr->level_ = VP8GetValue(br, 6, "global-header");
|
||||||
hdr->sharpness_ = VP8GetValue(br, 3);
|
hdr->sharpness_ = VP8GetValue(br, 3, "global-header");
|
||||||
hdr->use_lf_delta_ = VP8Get(br);
|
hdr->use_lf_delta_ = VP8Get(br, "global-header");
|
||||||
if (hdr->use_lf_delta_) {
|
if (hdr->use_lf_delta_) {
|
||||||
if (VP8Get(br)) { // update lf-delta?
|
if (VP8Get(br, "global-header")) { // update lf-delta?
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
|
for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
|
||||||
if (VP8Get(br)) {
|
if (VP8Get(br, "global-header")) {
|
||||||
hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6);
|
hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
|
for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
|
||||||
if (VP8Get(br)) {
|
if (VP8Get(br, "global-header")) {
|
||||||
hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6);
|
hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,8 +355,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
buf_size -= frm_hdr->partition_length_;
|
buf_size -= frm_hdr->partition_length_;
|
||||||
|
|
||||||
if (frm_hdr->key_frame_) {
|
if (frm_hdr->key_frame_) {
|
||||||
pic_hdr->colorspace_ = VP8Get(br);
|
pic_hdr->colorspace_ = VP8Get(br, "global-header");
|
||||||
pic_hdr->clamp_type_ = VP8Get(br);
|
pic_hdr->clamp_type_ = VP8Get(br, "global-header");
|
||||||
}
|
}
|
||||||
if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) {
|
if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) {
|
||||||
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
@ -378,7 +381,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
"Not a key frame.");
|
"Not a key frame.");
|
||||||
}
|
}
|
||||||
|
|
||||||
VP8Get(br); // ignore the value of update_proba_
|
VP8Get(br, "global-header"); // ignore the value of update_proba_
|
||||||
|
|
||||||
VP8ParseProba(br, dec);
|
VP8ParseProba(br, dec);
|
||||||
|
|
||||||
@ -403,28 +406,28 @@ static const uint8_t kZigzag[16] = {
|
|||||||
// See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2
|
// See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2
|
||||||
static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
|
static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
|
||||||
int v;
|
int v;
|
||||||
if (!VP8GetBit(br, p[3])) {
|
if (!VP8GetBit(br, p[3], "coeffs")) {
|
||||||
if (!VP8GetBit(br, p[4])) {
|
if (!VP8GetBit(br, p[4], "coeffs")) {
|
||||||
v = 2;
|
v = 2;
|
||||||
} else {
|
} else {
|
||||||
v = 3 + VP8GetBit(br, p[5]);
|
v = 3 + VP8GetBit(br, p[5], "coeffs");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!VP8GetBit(br, p[6])) {
|
if (!VP8GetBit(br, p[6], "coeffs")) {
|
||||||
if (!VP8GetBit(br, p[7])) {
|
if (!VP8GetBit(br, p[7], "coeffs")) {
|
||||||
v = 5 + VP8GetBit(br, 159);
|
v = 5 + VP8GetBit(br, 159, "coeffs");
|
||||||
} else {
|
} else {
|
||||||
v = 7 + 2 * VP8GetBit(br, 165);
|
v = 7 + 2 * VP8GetBit(br, 165, "coeffs");
|
||||||
v += VP8GetBit(br, 145);
|
v += VP8GetBit(br, 145, "coeffs");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const uint8_t* tab;
|
const uint8_t* tab;
|
||||||
const int bit1 = VP8GetBit(br, p[8]);
|
const int bit1 = VP8GetBit(br, p[8], "coeffs");
|
||||||
const int bit0 = VP8GetBit(br, p[9 + bit1]);
|
const int bit0 = VP8GetBit(br, p[9 + bit1], "coeffs");
|
||||||
const int cat = 2 * bit1 + bit0;
|
const int cat = 2 * bit1 + bit0;
|
||||||
v = 0;
|
v = 0;
|
||||||
for (tab = kCat3456[cat]; *tab; ++tab) {
|
for (tab = kCat3456[cat]; *tab; ++tab) {
|
||||||
v += v + VP8GetBit(br, *tab);
|
v += v + VP8GetBit(br, *tab, "coeffs");
|
||||||
}
|
}
|
||||||
v += 3 + (8 << cat);
|
v += 3 + (8 << cat);
|
||||||
}
|
}
|
||||||
@ -438,24 +441,24 @@ static int GetCoeffsFast(VP8BitReader* const br,
|
|||||||
int ctx, const quant_t dq, int n, int16_t* out) {
|
int ctx, const quant_t dq, int n, int16_t* out) {
|
||||||
const uint8_t* p = prob[n]->probas_[ctx];
|
const uint8_t* p = prob[n]->probas_[ctx];
|
||||||
for (; n < 16; ++n) {
|
for (; n < 16; ++n) {
|
||||||
if (!VP8GetBit(br, p[0])) {
|
if (!VP8GetBit(br, p[0], "coeffs")) {
|
||||||
return n; // previous coeff was last non-zero coeff
|
return n; // previous coeff was last non-zero coeff
|
||||||
}
|
}
|
||||||
while (!VP8GetBit(br, p[1])) { // sequence of zero coeffs
|
while (!VP8GetBit(br, p[1], "coeffs")) { // sequence of zero coeffs
|
||||||
p = prob[++n]->probas_[0];
|
p = prob[++n]->probas_[0];
|
||||||
if (n == 16) return 16;
|
if (n == 16) return 16;
|
||||||
}
|
}
|
||||||
{ // non zero coeff
|
{ // non zero coeff
|
||||||
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
|
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
|
||||||
int v;
|
int v;
|
||||||
if (!VP8GetBit(br, p[2])) {
|
if (!VP8GetBit(br, p[2], "coeffs")) {
|
||||||
v = 1;
|
v = 1;
|
||||||
p = p_ctx[1];
|
p = p_ctx[1];
|
||||||
} else {
|
} else {
|
||||||
v = GetLargeValue(br, p);
|
v = GetLargeValue(br, p);
|
||||||
p = p_ctx[2];
|
p = p_ctx[2];
|
||||||
}
|
}
|
||||||
out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
|
out[kZigzag[n]] = VP8GetSigned(br, v, "coeffs") * dq[n > 0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 16;
|
return 16;
|
||||||
@ -468,24 +471,24 @@ static int GetCoeffsAlt(VP8BitReader* const br,
|
|||||||
int ctx, const quant_t dq, int n, int16_t* out) {
|
int ctx, const quant_t dq, int n, int16_t* out) {
|
||||||
const uint8_t* p = prob[n]->probas_[ctx];
|
const uint8_t* p = prob[n]->probas_[ctx];
|
||||||
for (; n < 16; ++n) {
|
for (; n < 16; ++n) {
|
||||||
if (!VP8GetBitAlt(br, p[0])) {
|
if (!VP8GetBitAlt(br, p[0], "coeffs")) {
|
||||||
return n; // previous coeff was last non-zero coeff
|
return n; // previous coeff was last non-zero coeff
|
||||||
}
|
}
|
||||||
while (!VP8GetBitAlt(br, p[1])) { // sequence of zero coeffs
|
while (!VP8GetBitAlt(br, p[1], "coeffs")) { // sequence of zero coeffs
|
||||||
p = prob[++n]->probas_[0];
|
p = prob[++n]->probas_[0];
|
||||||
if (n == 16) return 16;
|
if (n == 16) return 16;
|
||||||
}
|
}
|
||||||
{ // non zero coeff
|
{ // non zero coeff
|
||||||
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
|
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
|
||||||
int v;
|
int v;
|
||||||
if (!VP8GetBitAlt(br, p[2])) {
|
if (!VP8GetBitAlt(br, p[2], "coeffs")) {
|
||||||
v = 1;
|
v = 1;
|
||||||
p = p_ctx[1];
|
p = p_ctx[1];
|
||||||
} else {
|
} else {
|
||||||
v = GetLargeValue(br, p);
|
v = GetLargeValue(br, p);
|
||||||
p = p_ctx[2];
|
p = p_ctx[2];
|
||||||
}
|
}
|
||||||
out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
|
out[kZigzag[n]] = VP8GetSigned(br, v, "coeffs") * dq[n > 0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 16;
|
return 16;
|
||||||
|
@ -104,7 +104,8 @@ void VP8LoadNewBytes(VP8BitReader* const br) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read a bit with proba 'prob'. Speed-critical function!
|
// Read a bit with proba 'prob'. Speed-critical function!
|
||||||
static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
|
static WEBP_INLINE int VP8GetBit(VP8BitReader* const br,
|
||||||
|
int prob, const char label[]) {
|
||||||
// Don't move this declaration! It makes a big speed difference to store
|
// Don't move this declaration! It makes a big speed difference to store
|
||||||
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
|
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
|
||||||
// alter br->range_ value.
|
// alter br->range_ value.
|
||||||
@ -129,13 +130,14 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
|
|||||||
br->bits_ -= shift;
|
br->bits_ -= shift;
|
||||||
}
|
}
|
||||||
br->range_ = range - 1;
|
br->range_ = range - 1;
|
||||||
|
BT_TRACK(br);
|
||||||
return bit;
|
return bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
|
// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
|
||||||
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
|
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
|
||||||
int VP8GetSigned(VP8BitReader* const br, int v) {
|
int VP8GetSigned(VP8BitReader* const br, int v, const char label[]) {
|
||||||
if (br->bits_ < 0) {
|
if (br->bits_ < 0) {
|
||||||
VP8LoadNewBytes(br);
|
VP8LoadNewBytes(br);
|
||||||
}
|
}
|
||||||
@ -148,11 +150,13 @@ int VP8GetSigned(VP8BitReader* const br, int v) {
|
|||||||
br->range_ += mask;
|
br->range_ += mask;
|
||||||
br->range_ |= 1;
|
br->range_ |= 1;
|
||||||
br->value_ -= (bit_t)((split + 1) & mask) << pos;
|
br->value_ -= (bit_t)((split + 1) & mask) << pos;
|
||||||
|
BT_TRACK(br);
|
||||||
return (v ^ mask) - mask;
|
return (v ^ mask) - mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
|
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br,
|
||||||
|
int prob, const char label[]) {
|
||||||
// Don't move this declaration! It makes a big speed difference to store
|
// Don't move this declaration! It makes a big speed difference to store
|
||||||
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
|
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
|
||||||
// alter br->range_ value.
|
// alter br->range_ value.
|
||||||
@ -179,6 +183,7 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
|
|||||||
br->bits_ -= shift;
|
br->bits_ -= shift;
|
||||||
}
|
}
|
||||||
br->range_ = range;
|
br->range_ = range;
|
||||||
|
BT_TRACK(br);
|
||||||
return bit;
|
return bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,17 +102,18 @@ void VP8LoadFinalBytes(VP8BitReader* const br) {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Higher-level calls
|
// Higher-level calls
|
||||||
|
|
||||||
uint32_t VP8GetValue(VP8BitReader* const br, int bits) {
|
uint32_t VP8GetValue(VP8BitReader* const br, int bits, const char label[]) {
|
||||||
uint32_t v = 0;
|
uint32_t v = 0;
|
||||||
while (bits-- > 0) {
|
while (bits-- > 0) {
|
||||||
v |= VP8GetBit(br, 0x80) << bits;
|
v |= VP8GetBit(br, 0x80, label) << bits;
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
|
int32_t VP8GetSignedValue(VP8BitReader* const br, int bits,
|
||||||
const int value = VP8GetValue(br, bits);
|
const char label[]) {
|
||||||
return VP8Get(br) ? -value : value;
|
const int value = VP8GetValue(br, bits, label);
|
||||||
|
return VP8Get(br, label) ? -value : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -220,3 +221,78 @@ uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
// Bit-tracing tool
|
||||||
|
|
||||||
|
#if (BITTRACE > 0)
|
||||||
|
|
||||||
|
#include <stdlib.h> // for atexit()
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MAX_NUM_LABELS 32
|
||||||
|
static struct {
|
||||||
|
const char* label;
|
||||||
|
int size;
|
||||||
|
int count;
|
||||||
|
} kLabels[MAX_NUM_LABELS];
|
||||||
|
|
||||||
|
static int last_label = 0;
|
||||||
|
static int last_pos = 0;
|
||||||
|
static const uint8_t* buf_start = NULL;
|
||||||
|
static int init_done = 0;
|
||||||
|
|
||||||
|
static void PrintBitTraces(void) {
|
||||||
|
int i;
|
||||||
|
int scale = 1;
|
||||||
|
int total = 0;
|
||||||
|
const char* units = "bits";
|
||||||
|
#if (BITTRACE == 2)
|
||||||
|
scale = 8;
|
||||||
|
units = "bytes";
|
||||||
|
#endif
|
||||||
|
for (i = 0; i < last_label; ++i) total += kLabels[i].size;
|
||||||
|
if (total < 1) total = 1; // avoid rounding errors
|
||||||
|
printf("=== Bit traces ===\n");
|
||||||
|
for (i = 0; i < last_label; ++i) {
|
||||||
|
const int skip = 16 - (int)strlen(kLabels[i].label);
|
||||||
|
const int value = (kLabels[i].size + scale - 1) / scale;
|
||||||
|
assert(skip > 0);
|
||||||
|
printf("%s \%*s: %6d %s \t[%5.2f%%] [count: %7d]\n",
|
||||||
|
kLabels[i].label, skip, "", value, units,
|
||||||
|
100.f * kLabels[i].size / total,
|
||||||
|
kLabels[i].count);
|
||||||
|
}
|
||||||
|
total = (total + scale - 1) / scale;
|
||||||
|
printf("Total: %d %s\n", total, units);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitTrace(const struct VP8BitReader* const br, const char label[]) {
|
||||||
|
int i, pos;
|
||||||
|
if (!init_done) {
|
||||||
|
memset(kLabels, 0, sizeof(kLabels));
|
||||||
|
atexit(PrintBitTraces);
|
||||||
|
buf_start = br->buf_;
|
||||||
|
init_done = 1;
|
||||||
|
}
|
||||||
|
pos = (int)(br->buf_ - buf_start) * 8 - br->bits_;
|
||||||
|
// if there's a too large jump, we've changed partition -> reset counter
|
||||||
|
if (abs(pos - last_pos) > 32) {
|
||||||
|
buf_start = br->buf_;
|
||||||
|
pos = 0;
|
||||||
|
last_pos = 0;
|
||||||
|
}
|
||||||
|
if (br->range_ >= 0x7f) pos += kVP8Log2Range[br->range_ - 0x7f];
|
||||||
|
for (i = 0; i < last_label; ++i) {
|
||||||
|
if (!strcmp(label, kLabels[i].label)) break;
|
||||||
|
}
|
||||||
|
if (i == MAX_NUM_LABELS) abort(); // overflow!
|
||||||
|
kLabels[i].label = label;
|
||||||
|
kLabels[i].size += pos - last_pos;
|
||||||
|
kLabels[i].count += 1;
|
||||||
|
if (i == last_label) ++last_label;
|
||||||
|
last_pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BITTRACE > 0
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
@ -21,6 +21,27 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "src/webp/types.h"
|
#include "src/webp/types.h"
|
||||||
|
|
||||||
|
// Warning! This macro triggers quite some MACRO wizardry around func signature!
|
||||||
|
#if !defined(BITTRACE)
|
||||||
|
#define BITTRACE 0 // 0 = off, 1 = print bits, 2 = print bytes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (BITTRACE > 0)
|
||||||
|
struct VP8BitReader;
|
||||||
|
extern void BitTrace(const struct VP8BitReader* const br, const char label[]);
|
||||||
|
#define BT_TRACK(br) BitTrace(br, label)
|
||||||
|
#define VP8Get(BR, L) VP8GetValue(BR, 1, L)
|
||||||
|
#else
|
||||||
|
#define BT_TRACK(br)
|
||||||
|
// We'll REMOVE the 'const char label[]' from all signatures and calls (!!):
|
||||||
|
#define VP8GetValue(BR, N, L) VP8GetValue(BR, N)
|
||||||
|
#define VP8Get(BR, L) VP8GetValue(BR, 1, L)
|
||||||
|
#define VP8GetSignedValue(BR, N, L) VP8GetSignedValue(BR, N)
|
||||||
|
#define VP8GetBit(BR, P, L) VP8GetBit(BR, P)
|
||||||
|
#define VP8GetBitAlt(BR, P, L) VP8GetBitAlt(BR, P)
|
||||||
|
#define VP8GetSigned(BR, V, L) VP8GetSigned(BR, V)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -92,17 +113,15 @@ void VP8BitReaderSetBuffer(VP8BitReader* const br,
|
|||||||
void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset);
|
void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset);
|
||||||
|
|
||||||
// return the next value made of 'num_bits' bits
|
// return the next value made of 'num_bits' bits
|
||||||
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
|
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits, const char label[]);
|
||||||
static WEBP_INLINE uint32_t VP8Get(VP8BitReader* const br) {
|
|
||||||
return VP8GetValue(br, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the next value with sign-extension.
|
// return the next value with sign-extension.
|
||||||
int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits);
|
int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits,
|
||||||
|
const char label[]);
|
||||||
|
|
||||||
// bit_reader_inl.h will implement the following methods:
|
// bit_reader_inl.h will implement the following methods:
|
||||||
// static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob)
|
// static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob, ...)
|
||||||
// static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v)
|
// static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v, ...)
|
||||||
// and should be included by the .c files that actually need them.
|
// and should be included by the .c files that actually need them.
|
||||||
// This is to avoid recompiling the whole library whenever this file is touched,
|
// This is to avoid recompiling the whole library whenever this file is touched,
|
||||||
// and also allowing platform-specific ad-hoc hacks.
|
// and also allowing platform-specific ad-hoc hacks.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user