rangecoding

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 1 Imported by: 0

Documentation

Overview

Package rangecoding provides a Range coder for the Opus bitstream

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

Decoder implements rfc6716#section-4.1 Opus uses an entropy coder based on range coding [RANGE-CODING] [MARTIN79], which is itself a rediscovery of the FIFO arithmetic code introduced by [CODING-THESIS]. It is very similar to arithmetic encoding, except that encoding is done with digits in any base instead of with bits, so it is faster when using larger bases (i.e., a byte). All of the calculations in the range coder must use bit- exact integer arithmetic.

Symbols may also be coded as "raw bits" packed directly into the bitstream, bypassing the range coder. These are packed backwards starting at the end of the frame, as illustrated in Figure 12. This reduces complexity and makes the stream more resilient to bit errors, as corruption in the raw bits will not desynchronize the decoding process, unlike corruption in the input to the range decoder. Raw bits are only used in the CELT layer.

          0                   1                   2                   3
          0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | Range coder data (packed MSB to LSB) ->                       :
         +                                                               +
         :                                                               :
         +     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         :     | <- Boundary occurs at an arbitrary bit position         :
         +-+-+-+                                                         +
         :                          <- Raw bits data (packed LSB to MSB) |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

	Legend:

	LSB = Least Significant Bit
	MSB = Most Significant Bit

	     Figure 12: Illustrative Example of Packing Range Coder
	                        and Raw Bits Data

Each symbol coded by the range coder is drawn from a finite alphabet and coded in a separate "context", which describes the size of the alphabet and the relative frequency of each symbol in that alphabet.

Suppose there is a context with n symbols, identified with an index that ranges from 0 to n-1. The parameters needed to encode or decode symbol k in this context are represented by a three-tuple (fl[k], fh[k], ft), all 16-bit unsigned integers, with 0 <= fl[k] < fh[k] <= ft <= 65535. The values of this tuple are derived from the probability model for the symbol, represented by traditional "frequency counts". Because Opus uses static contexts, those are not updated as symbols are decoded. Let f[i] be the frequency of symbol i. Then, the three-tuple corresponding to symbol k is given by the following:

        k-1                                   n-1
        __                                    __
fl[k] = \  f[i],  fh[k] = fl[k] + f[k],  ft = \  f[i]
        /_                                    /_
        i=0                                   i=0

The range decoder extracts the symbols and integers encoded using the range encoder in Section 5.1. The range decoder maintains an internal state vector composed of the two-tuple (val, rng), where val represents the difference between the high end of the current range and the actual coded value, minus one, and rng represents the size of the current range. Both val and rng are 32-bit unsigned integer values.

func (*Decoder) DecodeCumulative

func (r *Decoder) DecodeCumulative(total uint32) uint32

DecodeCumulative decodes the cumulative frequency index used by CELT's custom range-coded symbols. Call UpdateCumulative with the selected interval.

func (*Decoder) DecodeLaplace

func (r *Decoder) DecodeLaplace(fs0 uint32, decay uint32) int

DecodeLaplace decodes the ec_laplace_decode() symbol used by the CELT layer.

RFC 6716 Section 4.3.2.1 describes coarse energy deltas as Laplace-distributed prediction errors; the reference implementation decodes them with this helper.

func (*Decoder) DecodeRawBits

func (r *Decoder) DecodeRawBits(n uint) uint32

DecodeRawBits decodes raw bits packed from the end of the frame. RFC 6716 Section 4.1.4 defines this LSB-first tail packing for CELT.

func (*Decoder) DecodeSymbolLogP

func (r *Decoder) DecodeSymbolLogP(logp uint) uint32

DecodeSymbolLogP decodes a single binary symbol. The context is described by a single parameter, logp, which is the absolute value of the base-2 logarithm of the probability of a "1".

https://datatracker.ietf.org/doc/html/rfc6716#section-4.1.3.2

func (*Decoder) DecodeSymbolWithICDF

func (r *Decoder) DecodeSymbolWithICDF(cumulativeDistributionTable []uint) uint32

DecodeSymbolWithICDF decodes a single symbol with a table-based context of up to 8 bits.

https://datatracker.ietf.org/doc/html/rfc6716#section-4.1.3.3

func (*Decoder) DecodeUniform

func (r *Decoder) DecodeUniform(total uint32) (uint32, bool)

DecodeUniform decodes an RFC 6716 Section 4.1.5 ec_dec_uint() symbol.

It returns false when the decoded raw-bit suffix produces a value outside [0,total), in which case the saturated value matches the reference decoder.

func (*Decoder) FinalRange

func (r *Decoder) FinalRange() uint32

FinalRange exposes the current range coder range state for tests.

func (*Decoder) Init

func (r *Decoder) Init(data []byte)

Init sets the state of the Decoder Let b0 be an 8-bit unsigned integer containing first input byte (or containing zero if there are no bytes in this Opus frame). The decoder initializes rng to 128 and initializes val to (127 -

(b0>>1)), where (b0>>1) is the top 7 bits of the first input byte.

It saves the remaining bit, (b0&1), for use in the renormalization procedure described in Section 4.1.2.1, which the decoder invokes immediately after initialization to read additional bits and establish the invariant that rng > 2**23.

https://datatracker.ietf.org/doc/html/rfc6716#section-4.1.1

func (*Decoder) RemainingBits

func (r *Decoder) RemainingBits() int

RemainingBits reports a conservative estimate of the unread payload bits. RFC 6716 Section 4.1.4 allows range and raw-bit cursor overlap.

func (*Decoder) SetInternalValues

func (r *Decoder) SetInternalValues(data []byte, bitsRead uint, rangeSize uint32, highAndCodedDifference uint32)

SetInternalValues is used when using the RangeDecoder when testing.

func (*Decoder) SetStorageSize

func (r *Decoder) SetStorageSize(size int)

SetStorageSize adjusts the logical frame size without resetting decoder state. Opus hybrid redundancy removes tail bytes from the CELT range coder after the shared decoder has already consumed SILK symbols.

func (*Decoder) Tell

func (r *Decoder) Tell() uint

Tell returns a conservative upper bound, in whole bits, of how many bits have been consumed from the current frame, per RFC 6716 Section 4.1.6.1.

func (*Decoder) TellFrac

func (r *Decoder) TellFrac() uint

TellFrac returns a conservative upper bound in 1/8 bit units. This follows the ec_tell_frac() construction in RFC 6716 Section 4.1.6.2.

func (*Decoder) UpdateCumulative

func (r *Decoder) UpdateCumulative(low, high, total uint32)

UpdateCumulative commits a custom cumulative interval previously selected from DecodeCumulative.

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Encoder implements the range encoder defined in RFC 6716 Section 5.1.

The range coder acts as the bit-packer for Opus. It is used in three different ways: to encode

  • Entropy-coded symbols with a fixed probability model using ec_encode() (entenc.c),

  • Integers from 0 to (2**M - 1) using ec_enc_uint() or ec_enc_bits() (entenc.c),

  • Integers from 0 to (ft - 1) (where ft is not a power of two) using ec_enc_uint() (entenc.c).

The range encoder maintains an internal state vector composed of the four-tuple (val, rng, rem, ext) representing the low end of the current range, the size of the current range, a single buffered output byte, and a count of additional carry-propagating output bytes. Both val and rng are 32-bit unsigned integer values, rem is a byte value less than 255 or the special value -1, and ext is an unsigned integer with at least 11 bits. This state vector is initialized at the start of each frame to the value (0, 2**31, -1, 0). After encoding a sequence of symbols, the value of rng in the encoder should exactly match the value of rng in the decoder after decoding the same sequence of symbols. This is a powerful tool for detecting errors in either an encoder or decoder implementation. The value of val, on the other hand, represents different things in the encoder and decoder, and is not expected to match.

The decoder has no analog for rem and ext. These are used to perform carry propagation in the renormalization loop below. Each iteration of this loop produces 9 bits of output, consisting of 8 data bits and a carry flag. The encoder cannot determine the final value of the output bytes until it propagates these carry flags. Therefore, the reference implementation buffers a single non-propagating output byte (i.e., one less than 255) in rem and keeps a count of additional propagating (i.e., 255) output bytes in ext.

Symbols may also be coded as "raw bits" packed directly into the bitstream, bypassing the range coder. These are packed backwards starting at the end of the frame, as illustrated in Figure 12 of RFC 6716. This reduces complexity and makes the stream more resilient to bit errors. Raw bits are only used in the CELT layer.

          0                   1                   2                   3
          0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         | Range coder data (packed MSB to LSB) ->                       :
         +                                                               +
         :                                                               :
         +     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         :     | <- Boundary occurs at an arbitrary bit position         :
         +-+-+-+                                                         +
         :                          <- Raw bits data (packed LSB to MSB) |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Legend:

LSB = Least Significant Bit
MSB = Most Significant Bit

     Figure 12: Illustrative Example of Packing Range Coder
                        and Raw Bits Data

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1

func (*Encoder) Done

func (e *Encoder) Done() []byte

Done flushes the range coder and raw bits into a single output frame, implementing ec_enc_done() (entenc.c).

RFC 6716 Section 5.1.5 describes the finalization procedure:

  1. Find the unsigned integer end in [val, val+rng) with the largest number of trailing zero bits b such that (end + (1<<b) - 1) is also in [val, val+rng). Flush the remaining bytes of end through the carry buffer.

  2. If the buffered output byte rem is neither zero nor -1, or the carry count ext is greater than zero, flush 9 zero bits to drain the carry buffer.

  3. Merge the last range-coder byte and the first raw-bits byte into one byte if the range coder did not consume all bits in its final byte. Any space between the range coder data and the raw bits is zero-padded.

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1.5 Done finalizes the frame and returns the encoded bytes as a new slice. Use FlushInto when the caller can provide the destination buffer to avoid the allocation.

func (*Encoder) EncodeCumulative

func (e *Encoder) EncodeCumulative(low, high, total uint32)

EncodeCumulative encodes a pre-selected cumulative interval (low, high) out of total equally weighted bins.

This is the main encoding function ec_encode() (entenc.c) defined in RFC 6716 Section 5.1.1. It encodes symbol k described by the three-tuple (fl[k], fh[k], ft) using the same semantics as the decoder's ec_decode().

If fl[k] (low) is greater than zero:

val = val + rng - (rng / ft) * (ft - fl)
rng = (rng / ft) * (fh - fl)

Otherwise val is unchanged and:

rng = rng - (rng / ft) * (ft - fh)

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1.1

func (*Encoder) EncodeLaplace

func (e *Encoder) EncodeLaplace(fs0, decay uint32, value int) int

EncodeLaplace encodes a Laplace-distributed integer value using the same probability model as Decoder.DecodeLaplace.

RFC 6716 Section 4.3.2.1 describes coarse energy deltas as Laplace-distributed prediction errors. The distribution is parameterized by fs0 (the frequency of the zero symbol, in units of 1/32768) and decay (the geometric decay rate of adjacent-magnitude frequencies, Q15).

https://datatracker.ietf.org/doc/html/rfc6716#section-4.3.2.1 EncodeLaplace encodes a Laplace-distributed value and returns the value the decoder will recover, which differs from the input when the tail of the distribution cannot represent it (see laplaceInterval).

func (*Encoder) EncodeRawBits

func (e *Encoder) EncodeRawBits(n uint, value uint32)

EncodeRawBits appends n bits of value to the raw-bits region at the end of the frame, packed in LSB-first order.

RFC 6716 Section 5.1.3 specifies that raw bits used by the CELT layer are packed at the end of the buffer using ec_enc_bits() (entenc.c). Because the raw bits may continue into the last byte output by the range coder if there is room in the low-order bits, Done() merges the two regions into a single byte when they meet.

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1.3

func (*Encoder) EncodeSymbolLogP

func (e *Encoder) EncodeSymbolLogP(logp uint, symbol uint32)

EncodeSymbolLogP encodes a single binary symbol with probability 1/(1<<logp) for symbol 1.

This implements ec_enc_bit_logp() (entenc.c), which is mathematically equivalent to calling ec_encode() with the 3-tuple (fl[k] = 0, fh[k] = (1<<logp) - 1, ft = (1<<logp)) if k is 0 and with (fl[k] = (1<<logp) - 1, fh[k] = ft = (1<<logp)) if k is 1. The implementation requires no multiplications or divisions.

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1.2

func (*Encoder) EncodeSymbolWithICDF

func (e *Encoder) EncodeSymbolWithICDF(cumulativeDistributionTable []uint, symbol uint32)

EncodeSymbolWithICDF encodes a symbol using the same inverse cumulative distribution table format consumed by Decoder.DecodeSymbolWithICDF.

This implements ec_enc_icdf() (entenc.c), which is mathematically equivalent to calling ec_encode() with fl[k] = (1<<ftb) - icdf[k-1], fh[k] = (1<<ftb) - icdf[k], and ft = (1<<ftb). It allows the encoder to use the same icdf tables as the decoder.

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1.2

func (*Encoder) EncodeUniform

func (e *Encoder) EncodeUniform(total, symbol uint32)

EncodeUniform encodes one of ft equiprobable symbols in the range [0, ft), implementing ec_enc_uint() (entenc.c).

RFC 6716 Section 5.1.4 splits the value into a range-coded prefix of up to 8 high bits and, if ft requires more than 8 bits, a raw-bit suffix:

If ftb = ilog(ft - 1) <= 8, encode t directly via ec_encode().
If ftb > 8, encode t>>(ftb-8) via ec_encode() and the remaining
(ftb - 8) bits of t via ec_enc_bits().

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1.4

func (*Encoder) FinalRange

func (e *Encoder) FinalRange() uint32

FinalRange exposes the current range coder range state for tests.

RFC 6716 Section 5.1 states that after encoding a sequence of symbols the value of rng in the encoder should exactly match the value of rng in the decoder after decoding the same sequence of symbols. This is a powerful tool for detecting errors in either an encoder or decoder implementation.

func (*Encoder) FlushInto

func (e *Encoder) FlushInto(dst []byte) int

FlushInto finalizes the frame and writes the encoded bytes into dst without allocating. dst must have length >= frameBytes. Returns the number of bytes written.

func (*Encoder) FlushIntoPadded

func (e *Encoder) FlushIntoPadded(dst []byte, size int) int

FlushIntoPadded finalizes the frame into dst and zero-fills the result out to size bytes when the coded data is shorter.

CELT derives its bit allocation from the frame size the encoder was asked for, and the decoder re-derives it from the size of the packet it receives. Emitting a shorter packet makes the two sides compute different allocations, so they disagree on how many raw bits each band's fine energy occupies and the decoder reads that region at the wrong offsets. libopus avoids this by initializing the range coder with the target size up front and clearing the unused middle in ec_enc_done (celt/entenc.c).

func (*Encoder) Init

func (e *Encoder) Init()

Init resets the Encoder state for a new frame.

RFC 6716 Section 5.1 specifies that the encoder state vector (val, rng, rem, ext) is initialized at the start of each frame to (0, 2**31, -1, 0). nbitsTotal is set to codeBits + 1 so that Tell() returns 1 after initialization, matching the decoder's post-Init value (the decoder consumes one bit of bootstrap input during Init).

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1

func (*Encoder) PatchInitialBits

func (e *Encoder) PatchInitialBits(value uint32, bitCount uint) bool

PatchInitialBits replaces the first bitCount coded bits with the MSB-first bit pattern value. It is the Go equivalent of ec_enc_patch_initial_bits().

SILK delays its per-frame VAD/LBRR flags until the packet has been analyzed. Depending on how far encoding has progressed, the initial bits may already be in the first finalized byte, in the pending carry byte, or still in low. Patching must not change the current range or the bit count.

It reports whether the request is representable in the current state; patching zero bits is a successful no-op.

https://datatracker.ietf.org/doc/html/rfc6716#section-4.2.3

func (*Encoder) Restore

func (e *Encoder) Restore(s *State)

Restore rewinds to a state taken by SaveInto. Only states from the same frame are meaningful.

func (*Encoder) SaveInto

func (e *Encoder) SaveInto(dst *State)

SaveInto captures the encoder state so a speculative encode can be undone. It reuses dst's buffers, so a caller that snapshots in a loop allocates once.

func (*Encoder) Tell

func (e *Encoder) Tell() uint

Tell returns a conservative upper bound, in whole bits, of the number of bits encoded into the current frame so far.

This implements ec_tell() (entcode.h) from RFC 6716 Section 5.1.6. The bit allocation routines in Opus use this value to track budget consumption and prevent the range coder from overflowing the output buffer. After encoding the same symbols, the encoder and decoder must produce identical Tell() values.

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1.6

func (*Encoder) TellFrac

func (e *Encoder) TellFrac() uint

TellFrac returns a conservative upper bound in 1/8-bit units.

This implements ec_tell_frac() (entcode.c) from RFC 6716 Section 5.1.6. It refines the Tell() estimate by squaring down the fractional part of the range size three times to obtain three additional sub-bit fractions. The encoder and decoder must produce identical TellFrac() values after encoding and decoding the same symbols.

https://datatracker.ietf.org/doc/html/rfc6716#section-5.1.6

type State

type State struct {
	// contains filtered or unexported fields
}

State is a snapshot of the encoder taken mid-frame. Rewinding needs the output bytes as well as the scalars: a speculative encode that is rolled back leaves the next one writing over the same positions, so the first one's bytes are gone by the time we might want them again.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL