c2140b8af1
Changes 'The VP8 project' to 'The WebM project', for consistency with other webmproject.org repositories. Fixes issue #97. Change-Id: I37c13ed5fbdb9d334ceef71c6350e9febed9bbba
571 lines
14 KiB
C++
571 lines
14 KiB
C++
/*
|
|
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
|
|
#ifndef bool_coder_h
|
|
#define bool_coder_h 1
|
|
|
|
/* Arithmetic bool coder with largish probability range.
|
|
Timothy S Murphy 6 August 2004 */
|
|
|
|
/* So as not to force users to drag in too much of my idiosyncratic C++ world,
|
|
I avoid fancy storage management. */
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
|
|
typedef unsigned char vp8bc_index_t; // probability index
|
|
|
|
/* There are a couple of slight variants in the details of finite-precision
|
|
arithmetic coding. May be safely ignored by most users. */
|
|
|
|
enum vp8bc_rounding
|
|
{
|
|
vp8bc_down = 0, // just like VP8
|
|
vp8bc_down_full = 1, // handles minimum probability correctly
|
|
vp8bc_up = 2
|
|
};
|
|
|
|
#if _MSC_VER
|
|
|
|
/* Note that msvc by default does not inline _anything_ (regardless of the
|
|
setting of inline_depth) and that a command-line option (-Ob1 or -Ob2)
|
|
is required to inline even the smallest functions. */
|
|
|
|
# pragma inline_depth( 255) // I mean it when I inline something
|
|
# pragma warning( disable : 4099) // No class vs. struct harassment
|
|
# pragma warning( disable : 4250) // dominance complaints
|
|
# pragma warning( disable : 4284) // operator-> in templates
|
|
# pragma warning( disable : 4800) // bool conversion
|
|
|
|
// don't let prefix ++,-- stand in for postfix, disaster would ensue
|
|
|
|
# pragma warning( error : 4620 4621)
|
|
|
|
#endif // _MSC_VER
|
|
|
|
|
|
#if __cplusplus
|
|
|
|
// Sometimes one wishes to be definite about integer lengths.
|
|
|
|
struct int_types
|
|
{
|
|
typedef const bool cbool;
|
|
typedef const signed char cchar;
|
|
typedef const short cshort;
|
|
typedef const int cint;
|
|
typedef const int clong;
|
|
|
|
typedef const double cdouble;
|
|
typedef const size_t csize_t;
|
|
|
|
typedef unsigned char uchar; // 8 bits
|
|
typedef const uchar cuchar;
|
|
|
|
typedef short int16;
|
|
typedef unsigned short uint16;
|
|
typedef const int16 cint16;
|
|
typedef const uint16 cuint16;
|
|
|
|
typedef int int32;
|
|
typedef unsigned int uint32;
|
|
typedef const int32 cint32;
|
|
typedef const uint32 cuint32;
|
|
|
|
typedef unsigned int uint;
|
|
typedef unsigned int ulong;
|
|
typedef const uint cuint;
|
|
typedef const ulong culong;
|
|
|
|
|
|
// All structs consume space, may as well have a vptr.
|
|
|
|
virtual ~int_types();
|
|
};
|
|
|
|
|
|
struct bool_coder_spec;
|
|
struct bool_coder;
|
|
struct bool_writer;
|
|
struct bool_reader;
|
|
|
|
|
|
struct bool_coder_namespace : int_types
|
|
{
|
|
typedef vp8bc_index_t Index;
|
|
typedef bool_coder_spec Spec;
|
|
typedef const Spec c_spec;
|
|
|
|
enum Rounding
|
|
{
|
|
Down = vp8bc_down,
|
|
down_full = vp8bc_down_full,
|
|
Up = vp8bc_up
|
|
};
|
|
};
|
|
|
|
|
|
// Archivable specification of a bool coder includes rounding spec
|
|
// and probability mapping table. The latter replaces a uchar j
|
|
// (0 <= j < 256) with an arbitrary uint16 tbl[j] = p.
|
|
// p/65536 is then the probability of a zero.
|
|
|
|
struct bool_coder_spec : bool_coder_namespace
|
|
{
|
|
friend struct bool_coder;
|
|
friend struct bool_writer;
|
|
friend struct bool_reader;
|
|
friend struct bool_coder_spec_float;
|
|
friend struct bool_coder_spec_explicit_table;
|
|
friend struct bool_coder_spec_exponential_table;
|
|
friend struct BPsrc;
|
|
private:
|
|
uint w; // precision
|
|
Rounding r;
|
|
|
|
uint ebits, mbits, ebias;
|
|
uint32 mmask;
|
|
|
|
Index max_index, half_index;
|
|
|
|
uint32 mantissa(Index i) const
|
|
{
|
|
assert(i < half_index);
|
|
return (1 << mbits) + (i & mmask);
|
|
}
|
|
uint exponent(Index i) const
|
|
{
|
|
assert(i < half_index);
|
|
return ebias - (i >> mbits);
|
|
}
|
|
|
|
uint16 Ptbl[256]; // kinda clunky, but so is storage management.
|
|
|
|
/* Cost in bits of encoding a zero at every probability, scaled by 2^20.
|
|
Assumes that index is at most 8 bits wide. */
|
|
|
|
uint32 Ctbl[256];
|
|
|
|
uint32 split(Index i, uint32 R) const // 1 <= split <= max( 1, R-1)
|
|
{
|
|
if (!ebias)
|
|
return 1 + (((R - 1) * Ptbl[i]) >> 16);
|
|
|
|
if (i >= half_index)
|
|
return R - split(max_index - i, R);
|
|
|
|
return 1 + (((R - 1) * mantissa(i)) >> exponent(i));
|
|
}
|
|
|
|
uint32 max_range() const
|
|
{
|
|
return (1 << w) - (r == down_full ? 0 : 1);
|
|
}
|
|
uint32 min_range() const
|
|
{
|
|
return (1 << (w - 1)) + (r == down_full ? 1 : 0);
|
|
}
|
|
uint32 Rinc() const
|
|
{
|
|
return r == Up ? 1 : 0;
|
|
}
|
|
|
|
void check_prec() const;
|
|
|
|
bool float_init(uint Ebits, uint Mbits);
|
|
|
|
void cost_init();
|
|
|
|
bool_coder_spec(
|
|
uint prec, Rounding rr, uint Ebits = 0, uint Mbits = 0
|
|
)
|
|
: w(prec), r(rr)
|
|
{
|
|
float_init(Ebits, Mbits);
|
|
}
|
|
public:
|
|
// Read complete spec from file.
|
|
bool_coder_spec(FILE *);
|
|
|
|
// Write spec to file.
|
|
void dump(FILE *) const;
|
|
|
|
// return probability index best approximating prob.
|
|
Index operator()(double prob) const;
|
|
|
|
// probability corresponding to index
|
|
double operator()(Index i) const;
|
|
|
|
Index complement(Index i) const
|
|
{
|
|
return max_index - i;
|
|
}
|
|
|
|
Index max_index() const
|
|
{
|
|
return max_index;
|
|
}
|
|
Index half_index() const
|
|
{
|
|
return half_index;
|
|
}
|
|
|
|
uint32 cost_zero(Index i) const
|
|
{
|
|
return Ctbl[i];
|
|
}
|
|
uint32 cost_one(Index i) const
|
|
{
|
|
return Ctbl[ max_index - i];
|
|
}
|
|
uint32 cost_bit(Index i, bool b) const
|
|
{
|
|
return Ctbl[b? max_index-i:i];
|
|
}
|
|
};
|
|
|
|
|
|
/* Pseudo floating-point probability specification.
|
|
|
|
At least one of Ebits and Mbits must be nonzero.
|
|
|
|
Since all arithmetic is done at 32 bits, Ebits is at most 5.
|
|
|
|
Total significant bits in index is Ebits + Mbits + 1.
|
|
|
|
Below the halfway point (i.e. when the top significant bit is 0),
|
|
the index is (e << Mbits) + m.
|
|
|
|
The exponent e is between 0 and (2**Ebits) - 1,
|
|
the mantissa m is between 0 and (2**Mbits) - 1.
|
|
|
|
Prepending an implicit 1 to the mantissa, the probability is then
|
|
|
|
(2**Mbits + m) >> (e - 2**Ebits - 1 - Mbits),
|
|
|
|
which has (1/2)**(2**Ebits + 1) as a minimum
|
|
and (1/2) * [1 - 2**(Mbits + 1)] as a maximum.
|
|
|
|
When the index is above the halfway point, the probability is the
|
|
complement of the probability associated to the complement of the index.
|
|
|
|
Note that the probability increases with the index and that, because of
|
|
the symmetry, we cannot encode probability exactly 1/2; though we
|
|
can get as close to 1/2 as we like, provided we have enough Mbits.
|
|
|
|
The latter is of course not a problem in practice, one never has
|
|
exact probabilities and entropy errors are second order, that is, the
|
|
"overcoding" of a zero will be largely compensated for by the
|
|
"undercoding" of a one (or vice-versa).
|
|
|
|
Compared to arithmetic probability specs (a la VP8), this will do better
|
|
at very high and low probabilities and worse at probabilities near 1/2,
|
|
as well as facilitating the usage of wider or narrower probability indices.
|
|
*/
|
|
|
|
struct bool_coder_spec_float : bool_coder_spec
|
|
{
|
|
bool_coder_spec_float(
|
|
uint Ebits = 3, uint Mbits = 4, Rounding rr = down_full, uint prec = 12
|
|
)
|
|
: bool_coder_spec(prec, rr, Ebits, Mbits)
|
|
{
|
|
cost_init();
|
|
}
|
|
};
|
|
|
|
|
|
struct bool_coder_spec_explicit_table : bool_coder_spec
|
|
{
|
|
bool_coder_spec_explicit_table(
|
|
cuint16 probability_table[256] = 0, // default is tbl[i] = i << 8.
|
|
Rounding = down_full,
|
|
uint precision = 16
|
|
);
|
|
};
|
|
|
|
// Contruct table via multiplicative interpolation between
|
|
// p[128] = 1/2 and p[0] = (1/2)^x.
|
|
// Since we are working with 16-bit precision, x is at most 16.
|
|
// For probabilities to increase with i, we must have x > 1.
|
|
// For 0 <= i <= 128, p[i] = (1/2)^{ 1 + [1 - (i/128)]*[x-1] }.
|
|
// Finally, p[128+i] = 1 - p[128 - i].
|
|
|
|
struct bool_coder_spec_exponential_table : bool_coder_spec
|
|
{
|
|
bool_coder_spec_exponential_table(uint x, Rounding = down_full, uint prec = 16);
|
|
};
|
|
|
|
|
|
// Commonalities between writer and reader.
|
|
|
|
struct bool_coder : bool_coder_namespace
|
|
{
|
|
friend struct bool_writer;
|
|
friend struct bool_reader;
|
|
friend struct BPsrc;
|
|
private:
|
|
uint32 Low, Range;
|
|
cuint32 min_range;
|
|
cuint32 rinc;
|
|
c_spec spec;
|
|
|
|
void _reset()
|
|
{
|
|
Low = 0;
|
|
Range = spec.max_range();
|
|
}
|
|
|
|
bool_coder(c_spec &s)
|
|
: min_range(s.min_range()),
|
|
rinc(s.Rinc()),
|
|
spec(s)
|
|
{
|
|
_reset();
|
|
}
|
|
|
|
uint32 half() const
|
|
{
|
|
return 1 + ((Range - 1) >> 1);
|
|
}
|
|
public:
|
|
c_spec &Spec() const
|
|
{
|
|
return spec;
|
|
}
|
|
};
|
|
|
|
|
|
struct bool_writer : bool_coder
|
|
{
|
|
friend struct BPsrc;
|
|
private:
|
|
uchar *Bstart, *Bend, *B;
|
|
int bit_lag;
|
|
bool is_toast;
|
|
void carry();
|
|
void reset()
|
|
{
|
|
_reset();
|
|
bit_lag = 32 - spec.w;
|
|
is_toast = 0;
|
|
}
|
|
void raw(bool value, uint32 split);
|
|
public:
|
|
bool_writer(c_spec &, uchar *Dest, size_t Len);
|
|
virtual ~bool_writer();
|
|
|
|
void operator()(Index p, bool v)
|
|
{
|
|
raw(v, spec.split(p, Range));
|
|
}
|
|
|
|
uchar *buf() const
|
|
{
|
|
return Bstart;
|
|
}
|
|
size_t bytes_written() const
|
|
{
|
|
return B - Bstart;
|
|
}
|
|
|
|
// Call when done with input, flushes internal state.
|
|
// DO NOT write any more data after calling this.
|
|
|
|
bool_writer &flush();
|
|
|
|
void write_bits(int n, uint val)
|
|
{
|
|
if (n)
|
|
{
|
|
uint m = 1 << (n - 1);
|
|
|
|
do
|
|
{
|
|
raw((bool)(val & m), half());
|
|
}
|
|
while (m >>= 1);
|
|
}
|
|
}
|
|
|
|
# if 0
|
|
// We are agnostic about storage management.
|
|
// By default, overflows throw an assert but user can
|
|
// override to provide an expanding buffer using ...
|
|
|
|
virtual void overflow(uint Len) const;
|
|
|
|
// ... this function copies already-written data into new buffer
|
|
// and retains new buffer location.
|
|
|
|
void new_buffer(uchar *dest, uint Len);
|
|
|
|
// Note that storage management is the user's responsibility.
|
|
# endif
|
|
};
|
|
|
|
|
|
// This could be adjusted to use a little less lookahead.
|
|
|
|
struct bool_reader : bool_coder
|
|
{
|
|
friend struct BPsrc;
|
|
private:
|
|
cuchar *const Bstart; // for debugging
|
|
cuchar *B;
|
|
cuchar *const Bend;
|
|
cuint shf;
|
|
uint bct;
|
|
bool raw(uint32 split);
|
|
public:
|
|
bool_reader(c_spec &s, cuchar *src, size_t Len);
|
|
|
|
bool operator()(Index p)
|
|
{
|
|
return raw(spec.split(p, Range));
|
|
}
|
|
|
|
uint read_bits(int num_bits)
|
|
{
|
|
uint v = 0;
|
|
|
|
while (--num_bits >= 0)
|
|
v += v + (raw(half()) ? 1 : 0);
|
|
|
|
return v;
|
|
}
|
|
};
|
|
|
|
extern "C" {
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
/* C interface */
|
|
|
|
typedef struct bool_coder_spec bool_coder_spec;
|
|
typedef struct bool_writer bool_writer;
|
|
typedef struct bool_reader bool_reader;
|
|
|
|
typedef const bool_coder_spec c_bool_coder_spec;
|
|
typedef const bool_writer c_bool_writer;
|
|
typedef const bool_reader c_bool_reader;
|
|
|
|
|
|
/* Optionally override default precision when constructing coder_specs.
|
|
Just pass a zero pointer if you don't care.
|
|
Precision is at most 16 bits for table specs, at most 23 otherwise. */
|
|
|
|
struct vp8bc_prec
|
|
{
|
|
enum vp8bc_rounding r; /* see top header file for def */
|
|
unsigned int prec; /* range precision in bits */
|
|
};
|
|
|
|
typedef const struct vp8bc_prec vp8bc_c_prec;
|
|
|
|
/* bool_coder_spec contains mapping of uchars to actual probabilities
|
|
(16 bit uints) as well as (usually immaterial) selection of
|
|
exact finite-precision algorithm used (for now, the latter can only
|
|
be overridden using the C++ interface).
|
|
See comments above the corresponding C++ constructors for discussion,
|
|
especially of exponential probability table generation. */
|
|
|
|
bool_coder_spec *vp8bc_vp8spec(); // just like vp8
|
|
|
|
bool_coder_spec *vp8bc_literal_spec(
|
|
const unsigned short prob_map[256], // 0 is like vp8 w/more precision
|
|
vp8bc_c_prec*
|
|
);
|
|
|
|
bool_coder_spec *vp8bc_float_spec(
|
|
unsigned int exponent_bits, unsigned int mantissa_bits, vp8bc_c_prec*
|
|
);
|
|
|
|
bool_coder_spec *vp8bc_exponential_spec(unsigned int min_exp, vp8bc_c_prec *);
|
|
|
|
bool_coder_spec *vp8bc_spec_from_file(FILE *);
|
|
|
|
|
|
void vp8bc_destroy_spec(c_bool_coder_spec *);
|
|
|
|
void vp8bc_spec_to_file(c_bool_coder_spec *, FILE *);
|
|
|
|
|
|
/* Nearest index to supplied probability of zero, 0 <= prob <= 1. */
|
|
|
|
vp8bc_index_t vp8bc_index(c_bool_coder_spec *, double prob);
|
|
|
|
vp8bc_index_t vp8bc_index_from_counts(
|
|
c_bool_coder_spec *p, unsigned int zero_ct, unsigned int one_ct
|
|
);
|
|
|
|
/* In case you want to look */
|
|
|
|
double vp8bc_probability(c_bool_coder_spec *, vp8bc_index_t);
|
|
|
|
/* Opposite index */
|
|
|
|
vp8bc_index_t vp8bc_complement(c_bool_coder_spec *, vp8bc_index_t);
|
|
|
|
/* Cost in bits of encoding a zero at given probability, scaled by 2^20.
|
|
(assumes that an int holds at least 32 bits). */
|
|
|
|
unsigned int vp8bc_cost_zero(c_bool_coder_spec *, vp8bc_index_t);
|
|
|
|
unsigned int vp8bc_cost_one(c_bool_coder_spec *, vp8bc_index_t);
|
|
unsigned int vp8bc_cost_bit(c_bool_coder_spec *, vp8bc_index_t, int);
|
|
|
|
|
|
/* bool_writer interface */
|
|
|
|
/* Length = 0 disables checking for writes beyond buffer end. */
|
|
|
|
bool_writer *vp8bc_create_writer(
|
|
c_bool_coder_spec *, unsigned char *Destination, size_t Length
|
|
);
|
|
|
|
/* Flushes out any buffered data and returns total # of bytes written. */
|
|
|
|
size_t vp8bc_destroy_writer(bool_writer *);
|
|
|
|
void vp8bc_write_bool(bool_writer *, int boolean_val, vp8bc_index_t false_prob);
|
|
|
|
void vp8bc_write_bits(
|
|
bool_writer *, unsigned int integer_value, int number_of_bits
|
|
);
|
|
|
|
c_bool_coder_spec *vp8bc_writer_spec(c_bool_writer *);
|
|
|
|
|
|
/* bool_reader interface */
|
|
|
|
/* Length = 0 disables checking for reads beyond buffer end. */
|
|
|
|
bool_reader *vp8bc_create_reader(
|
|
c_bool_coder_spec *, const unsigned char *Source, size_t Length
|
|
);
|
|
void vp8bc_destroy_reader(bool_reader *);
|
|
|
|
int vp8bc_read_bool(bool_reader *, vp8bc_index_t false_prob);
|
|
|
|
unsigned int vp8bc_read_bits(bool_reader *, int number_of_bits);
|
|
|
|
c_bool_coder_spec *vp8bc_reader_spec(c_bool_reader *);
|
|
|
|
#if __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* bool_coder_h */
|