/// <summary> /// Even-Rodeh code /// /// Encode a non-negative integer N : /// 1. If N is less than 4 then output N in 3 bits and stop. /// 2. If N is less than 8 then prepend the coded value with 3 bits containing the value of N and stop. /// 3. Prepend the coded value with the binary representation of N. /// 4. Store the number of bits prepended in step 3 as the new value of N. /// 5. Go back to step 2 /// 6. Output a single 0 bit. /// /// </summary> /// <returns></returns> public static void Encode(Bitstream bitstream, uint value) { if (value < 4) { bitstream.Write(value, 3); return; } var stack = new Stack <uint>(); uint n = value; while (true) { if (n < 8) { stack.Push(n); break; } stack.Push(n); n = CodecBase.BitsRequired(n); } while (stack.Any()) { uint val = stack.Pop(); if (val < 8) { bitstream.Write(val, 3); } else { bitstream.Write(val); } } bitstream.Write(0, 1); }
/// <summary> /// Compress stream of numbers: /// Store length+1 using EliasDelta (to avoid 0 case) /// First number x0 requires b0 bits. Write b0 in EliasDelta. Write x0 in b0 bits. /// Each subsequent number xi requires bi bits. If bi leq b(i-1) then /// write a 0 bit, then xi in b(i-1) bits. Else write (bi-b(i-1)) 1 bits, then a 0, /// then the least sig bi - 1 bits of xi (the leading 1 in xi is implied, xi>0). /// TODO - alternatives - allow the bi to change slowly, removes some hiccups for odd data points, set b to avg of some prev values /// </summary> /// <param name="bitstream"></param> /// <param name="data"></param> /// <param name="universalCoder">How to encode/decode a data length and first bitlength items. Elias.EncodeDelta is useful</param> public static void BinaryAdaptiveSequentialEncode(Bitstream bitstream, Datastream data, Action <Bitstream, uint> universalCoder) { universalCoder(bitstream, (uint)data.Count + 1); if (data.Count == 0) { return; } uint b1 = CodecBase.BitsRequired(data[0]); universalCoder(bitstream, b1); bitstream.Write(data[0]); for (var i = 1; i < data.Count; ++i) { uint d = data[i]; uint b2 = CodecBase.BitsRequired(d); if (b2 <= b1) { // b1 is enough bits bitstream.Write(0); bitstream.Write(d, b1); } else { // b2 requires more bits, tell how many Trace.Assert(d > 0); for (var ik = 0; ik < b2 - b1; ++ik) { bitstream.Write(1); } bitstream.Write(0, 1); // end of bit count bitstream.Write(d, b2 - 1); // strip off leading '1' } b1 = CodecBase.BitsRequired(d); // for next pass } }
/// <summary> /// Encode integer N via Sk(N) 0 B(N,floor(log_2 N)+1) /// /// Recursively define: for fixed integer k > 1 /// Sk(n) = B(n,l) if n in [0,2^k-1], else = Sk(Floor[Log_2 n]-k) B(n,Floor[Log_2 n]+1) /// where B(n,l) writes n in k bits /// Note the final B value is 0 prefixed, which lets the decoder know this is the last block. /// </summary> public static void Encode(Bitstream bitstream, uint value, uint k) { uint bitLength = CodecBase.BitsRequired(value); Recurse(bitstream, bitLength, k); bitstream.Write(0); bitstream.Write(value); }
/// <summary> /// L = bits needed to store value /// Write L-1 zero bits, then the value in binary (which necessarily starts with one) /// </summary> /// <param name="bitstream"></param> /// <param name="value32"></param> public static void EncodeGamma(Bitstream bitstream, uint value32) { Trace.Assert(value32 >= 1); uint n = CodecBase.BitsRequired(value32); for (var i = 0; i < n - 1; ++i) { bitstream.Write(0); } bitstream.Write(value32, n); }
/// <summary> /// Write the value to the bitstream in the minimum number of bits. /// Writes 0 using 1 bit. /// </summary> /// <param name="value"></param> public void Write(uint value) { if (value != 0) { Write(value, CodecBase.BitsRequired(value)); } else { Write(0, 1); } }
/// <summary> /// Encode a 32 bit value into the bitstream using Lomont method 3 /// </summary> /// <param name="bitstream"></param> /// <param name="value32"></param> public static void EncodeLomont3(Bitstream bitstream, uint value32) { Trace.Assert(value32 > 0); uint n = CodecBase.BitsRequired(value32); for (var i = 0; i < n - 1; ++i) { bitstream.Write(0, 1); // n-1 of these } bitstream.Write(1, 1); // end of n count bitstream.Write(value32, n - 1); // remove leading 1 }
/// <summary> /// Encode a 32 bit value into the bitstream using Elias Delta coding /// To encode a number X greater than 0: /// 1. N = number of bits needed to store X. N >=1 /// 2. L = number of bits needed to store N. L >= 1 /// 3. Write L-1 zeroes. /// 4. Write the L bit representation of N (which starts with a 1) /// 5. Write all but the leading 1 bit of X (i.e., the last N-1 bits) /// </summary> /// <param name="bitstream"></param> /// <param name="value32"></param> public static void EncodeDelta(Bitstream bitstream, uint value32) { Trace.Assert(value32 >= 1); uint n = CodecBase.BitsRequired(value32); uint l = CodecBase.BitsRequired(n); for (var i = 1; i <= l - 1; ++i) { bitstream.Write(0, 1); } bitstream.Write(n, l); bitstream.Write(value32, n - 1); }
/// <summary> /// Decodes truncated code item /// </summary> /// <param name="bitstream"></param> /// <param name="n"></param> /// <returns></returns> public static uint Decode(Bitstream bitstream, uint n) { uint k = CodecBase.BitsRequired(n); uint u = (1U << (int)k) - n; // u = number of unused codewords uint x = bitstream.Read(k - 1); if (x >= u) { // need another bit x = 2 * x + bitstream.Read(1); x -= u; } return(x); }
/// <summary> /// Write a universal compression header /// </summary> /// <param name="bitstream"></param> /// <param name="data"></param> /// <param name="headerFlags"></param> public static void WriteUniversalHeader(Bitstream bitstream, Datastream data, HeaderFlags headerFlags) { if (headerFlags.HasFlag(HeaderFlags.SymbolCount)) { UniversalCodec.Lomont.EncodeLomont1(bitstream, (uint)data.Count, 6, 0); } if (headerFlags.HasFlag(HeaderFlags.BitsPerSymbol)) { var max = data.Any() ? data.Max() : 0; var bitsPerSymbol = CodecBase.BitsRequired(max); UniversalCodec.Lomont.EncodeLomont1(bitstream, bitsPerSymbol - 1, 3, 0); } }
static void Recurse(Bitstream bitstream, uint n, uint k) { Trace.Assert(k > 1); if (n < (1U << (int)k)) { bitstream.Write(n, k); } else { uint m = CodecBase.FloorLog2(n); Recurse(bitstream, m - k, k); bitstream.Write(n, m + 1); } }
/// <summary> /// Exponential Golumb code for x geq 0 /// 1. Write (x+1) in binary in n bits /// 2. Prepend n-1 zero bits /// /// Order k > 0, do above to Floor[x/2^k] /// Then x mod 2^k in binary /// </summary> /// <param name="bitstream"></param> /// <param name="value"></param> /// <param name="k"></param> public static void EncodeExp(Bitstream bitstream, uint value, uint k) { if (k > 0) { EncodeExp(bitstream, value >> (int)k, 0); uint mask = (1U << (int)k) - 1; bitstream.Write(value & mask, k); } else { uint n = CodecBase.BitsRequired(value + 1); bitstream.Write(0, n - 1); bitstream.Write(value + 1, n); } }
/// <summary> /// Useful for encoding a value in [0,N). /// k = bit length N, k > 0 /// If N is a power of 2, uses k bits. /// If N is not a power of two, encodes some choices in k-1 bits, others in k bits /// </summary> public static void Encode(Bitstream bitstream, uint value, uint n) { Trace.Assert(value < n); uint k = CodecBase.BitsRequired(n); uint u = (1U << (int)k) - n; // u = number of unused codewords if (value < u) { bitstream.Write(value, k - 1); } else { bitstream.Write(value + u, k); } }
public static void EncodeOmega(Bitstream bitstream, uint value32) { Trace.Assert(value32 >= 1); var stack = new Stack <uint>(); while (value32 != 1) { stack.Push(value32); value32 = CodecBase.BitsRequired(value32) - 1; } while (stack.Any()) { bitstream.Write(stack.Pop()); } bitstream.Write(0); }
/// <summary> /// /// </summary> /// <param name="bitstream"></param> /// <param name="universalDecoder">The same encoder/decoder pair used to encode this</param> /// <returns></returns> public static List <uint> BinaryAdaptiveSequentialDecode(Bitstream bitstream, Func <Bitstream, uint> universalDecoder) { var list = new List <uint>(); uint length = universalDecoder(bitstream) - 1; if (length == 0) { return(list); } uint b1 = universalDecoder(bitstream); uint xi = bitstream.Read(b1); list.Add(xi); while (list.Count < length) { var decision = bitstream.Read(1); if (decision == 0) { // bi is <= b(i-1), so enough bits xi = bitstream.Read(b1); } else { // bi is bigger than b(i-1), must increase it uint delta = 0; do { decision = bitstream.Read(1); delta++; } while (decision != 0); b1 += delta; xi = bitstream.Read(b1 - 1); // xi has implied leading 1 xi |= 1U << (int)(b1 - 1); } list.Add(xi); b1 = CodecBase.BitsRequired(xi); } return(list); }