Adds ability to measure with a higher precision the number of bits read per symbol. Change-Id: I218abaa5172b769b66dba45050381c0212602668
diff --git a/aom_dsp/bitreader.h b/aom_dsp/bitreader.h index d2fd5f2..ee34275 100644 --- a/aom_dsp/bitreader.h +++ b/aom_dsp/bitreader.h
@@ -79,6 +79,7 @@ #endif } +// Returns the position in the bit reader in bits. static INLINE ptrdiff_t aom_reader_tell(const aom_reader *r) { #if CONFIG_ANS (void)r; @@ -91,6 +92,19 @@ #endif } +// Returns the position in the bit reader in 1/8th bits. +static INLINE ptrdiff_t aom_reader_tell_frac(const aom_reader *r) { +#if CONFIG_ANS + (void)r; + assert(0 && "aom_reader_tell_frac() is unimplemented for ANS"); + return 0; +#elif CONFIG_DAALA_EC + return aom_daala_reader_tell_frac(r); +#else + return aom_dk_reader_tell_frac(r); +#endif +} + static INLINE int aom_read(aom_reader *r, int prob) { #if CONFIG_ANS return uabs_read(r, prob);
diff --git a/aom_dsp/daalaboolreader.c b/aom_dsp/daalaboolreader.c index 8e1c782..65f9d50 100644 --- a/aom_dsp/daalaboolreader.c +++ b/aom_dsp/daalaboolreader.c
@@ -28,3 +28,7 @@ ptrdiff_t aom_daala_reader_tell(const daala_reader *r) { return od_ec_dec_tell(&r->ec); } + +ptrdiff_t aom_daala_reader_tell_frac(const daala_reader *r) { + return od_ec_dec_tell_frac(&r->ec); +}
diff --git a/aom_dsp/daalaboolreader.h b/aom_dsp/daalaboolreader.h index 4fc7ff4..896ec8b 100644 --- a/aom_dsp/daalaboolreader.h +++ b/aom_dsp/daalaboolreader.h
@@ -30,6 +30,7 @@ int aom_daala_reader_init(daala_reader *r, const uint8_t *buffer, int size); const uint8_t *aom_daala_reader_find_end(daala_reader *r); ptrdiff_t aom_daala_reader_tell(const daala_reader *r); +ptrdiff_t aom_daala_reader_tell_frac(const daala_reader *r); static INLINE int aom_daala_read(daala_reader *r, int prob) { if (prob == 128) {
diff --git a/aom_dsp/dkboolreader.h b/aom_dsp/dkboolreader.h index 2fd2b37..4d70c53 100644 --- a/aom_dsp/dkboolreader.h +++ b/aom_dsp/dkboolreader.h
@@ -65,7 +65,29 @@ const size_t bits_read = (r->buffer - r->buffer_start) * CHAR_BIT; const int count = (r->count < LOTS_OF_BITS) ? r->count : r->count - LOTS_OF_BITS; - return bits_read + BD_VALUE_SIZE - (count + CHAR_BIT); + return bits_read - (count + CHAR_BIT); +} + +/*The resolution of fractional-precision bit usage measurements, i.e., + 3 => 1/8th bits.*/ +#define DK_BITRES (3) + +static INLINE ptrdiff_t aom_dk_reader_tell_frac(const struct aom_dk_reader *r) { + uint32_t num_bits; + uint32_t range; + int l; + int i; + num_bits = aom_dk_reader_tell(r) << DK_BITRES; + range = r->range; + l = 0; + for (i = DK_BITRES; i-- > 0;) { + int b; + range = range * range >> 7; + b = (int)(range >> 8); + l = l << 1 | b; + range >>= b; + } + return num_bits - l; } static INLINE int aom_dk_reader_has_error(struct aom_dk_reader *r) {
diff --git a/test/boolcoder_test.cc b/test/boolcoder_test.cc index de9b6e4..f1bad33 100644 --- a/test/boolcoder_test.cc +++ b/test/boolcoder_test.cc
@@ -88,3 +88,54 @@ } } } + +#if CONFIG_DAALA_EC +#define FRAC_DIFF_TOTAL_ERROR 0.07 +#else +#define FRAC_DIFF_TOTAL_ERROR 0.2 +#endif + +TEST(AV1, TestTell) { + const int kBufferSize = 10000; + aom_writer bw; + uint8_t bw_buffer[kBufferSize]; + const int kSymbols = 1024; + // Coders are noisier at low probabilities, so we start at p = 4. + for (int p = 4; p <= 256; p++) { + double probability = p / 256.; + aom_start_encode(&bw, bw_buffer); + for (int i = 0; i < kSymbols; i++) { + aom_write(&bw, 0, p); + } + aom_stop_encode(&bw); + aom_reader br; + aom_reader_init(&br, bw_buffer, kBufferSize, NULL, NULL); + ptrdiff_t last_tell = aom_reader_tell(&br); + ptrdiff_t last_tell_frac = aom_reader_tell_frac(&br); + double frac_diff_total = 0; + GTEST_ASSERT_GE(aom_reader_tell(&br), 0); + GTEST_ASSERT_LE(aom_reader_tell(&br), 1); + for (int i = 0; i < kSymbols; i++) { + aom_read(&br, p); + ptrdiff_t tell = aom_reader_tell(&br); + ptrdiff_t tell_frac = aom_reader_tell_frac(&br); + GTEST_ASSERT_GE(tell, last_tell) << "tell: " << tell + << ", last_tell: " << last_tell; + GTEST_ASSERT_GE(tell_frac, last_tell_frac) + << "tell_frac: " << tell_frac + << ", last_tell_frac: " << last_tell_frac; + // Frac tell should round up to tell. + GTEST_ASSERT_EQ(tell, (tell_frac + 7) >> 3); + last_tell = tell; + frac_diff_total += + fabs(((tell_frac - last_tell_frac) / 8.0) + log2(probability)); + last_tell_frac = tell_frac; + } + const int expected = (int)(-kSymbols * log2(probability)); + // Last tell should be close to the expected value. + GTEST_ASSERT_LE(last_tell - expected, 20) << " last_tell: " << last_tell; + // The average frac_diff error should be pretty small. + GTEST_ASSERT_LE(frac_diff_total / kSymbols, FRAC_DIFF_TOTAL_ERROR) + << " frac_diff_total: " << frac_diff_total; + } +}