package org.jcodec.codecs.vpx; import java.nio.ByteBuffer; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author The JCodec project * */ public class VPXBooleanDecoder { int bit_count; /* # of bits shifted out of value, at most 7 */ ByteBuffer input; int offset; /* pointer to next compressed data byte */ int range; /* always identical to encoder's range */ int value; /* contains at least 24 significant bits */ long callCounter=0; private String debugName; public VPXBooleanDecoder(ByteBuffer input, int offset) { this.input = input; this.offset = offset; initBoolDecoder(); } void initBoolDecoder() { value = 0; /* value = first 16 input bits */ // data.position(offset); value = (input.get() & 0xFF) << 8; // readUnsignedByte() << 8; // value = (data[offset]) << 8; offset++; range = 255; /* initial range is full */ bit_count = 0; /* have not yet shifted out any bits */ } public int decodeBit() { return decodeBool(128); } public int decodeBool(int probability) { int bit = 0; int range = this.range; int value = this.value; int split = 1 + (((range - 1) * probability) >> 8); int bigsplit = (split << 8); this.callCounter++; // System.out.println(); // System.out.println("this.range: " + this.range + " binary: " + Integer.toBinaryString(this.range)); // System.out.println("split: " + split + " binary: " + Integer.toBinaryString(split)); // System.out.println("SPLIT: " + bigsplit + " binary: " + Integer.toBinaryString(bigsplit)); // System.out.println("value: " + value + " binary: " + Integer.toBinaryString(value)); range = split; if (value >= bigsplit) { range = this.range - range; value = value - bigsplit; bit = 1; } int count = this.bit_count; int shift = leadingZeroCountInByte((byte)range); range <<= shift; value <<= shift; count -= shift; if (count <= 0) { value |= (input.get() & 0xFF) << (-count); // System.out.println("read value: " + value + " binary: " + Integer.toBinaryString(value)); offset++; count += 8; } this.bit_count = count; this.value = value; this.range = range; return bit; } /* * Convenience function reads a "literal", that is, a "num_bits" wide unsigned value whose bits come high- to low-order, with each bit encoded at probability 128 (i.e., 1/2). */ public int decodeInt(int sizeInBits) { int v = 0; while (sizeInBits-- > 0) v = (v << 1) | decodeBool(128); return v; } /* root: "0", "1" subtrees */ /* "00" = 0th value, "01" = 1st value */ /* "10" = 2nd value, "11" = 3rd value */ /** * * General formula in VP8 trees. * <ul> * <li> if tree element is a positive number it is treated as index of the child elements <pre>tree[i] > 0</pre> * <ul> * <li> left child is assumed to have index <pre>i</pre> and value <pre>tree[i]</pre> </li> * <li> right child is assumed to have index <pre>i+1</pre> and value <pre>tree[i+1]</pre></li> * </ul> * </li> * <li> a negative tree value means a leaf node was reached and it's negated value should be returned <pre>-tree[i]</pre></li> * </ul> * * Here's a real example of a tree coded according to this formula in VP8 spec. * <pre> * const tree_index mb_segment_tree [2 * (4-1)] = * // +-------+---+ * // | | | * { 2, 4, -0, -1, -2, -3 }; * // | | | * // +-----------+---+ * </pre> * * If presented in hierarchical form this tree would look like: * <pre> * +---------------+ * | root | * | / \ | * | 2 4 | * | / \ / \ | * | -0 -1 -2 -3 | * +---------------+ * <pre> * * On the other hand probabilities are coded only for non-leaf nodes. * Thus tree array has twice as many nodes as probabilities array * Consider (3>>1) == 1 == (2>>1), and (0>>1) == 0 == (1>>1) * Thus single probability element refers to single parent element in tree. * if (using that probability) a '0' is coded, algorithm goes to the left * branch, correspondingly if '1' is coded, algorithm goes to * the right branch (see tree structure above). * * The process is repeated until a negative tree element is found. * */ public int readTree(int tree[],int probability[]) { int i = 0; /* * 1. pick corresponding probability probability[i >> 1] * 2. pick left or right branch from coded info decodeBool(probability) * 3. tree[i+decodedBool] get corresponding (left of right) value * 4. repeat until tree[i+decodedBool] is positive */ while ((i = tree[i + decodeBool(probability[i >> 1])]) > 0) { } return -i; /* negate the return value */ } public int readTreeSkip(int t[], /* tree specification */ int p[], /* corresponding interior node probabilities */ int skip_branches) { int i = skip_branches * 2; /* begin at root */ /* Descend tree until leaf is reached */ while ((i = t[i + decodeBool(p[i >> 1])]) > 0) { } return -i; /* return value is negation of nonpositive index */ } public void seek() { input.position(offset); } public String toString() { return "bc: " + value; } public static int getBitInBytes(byte[] bs, int i) { int byteIndex = i >> 3; int bitIndex = i & 0x07; return (bs[byteIndex] >> (0x07 - bitIndex)) & 0x01; } public static int getBitsInBytes(byte[] bytes, int idx, int len){ int val = 0; for(int i=0;i<len;i++){ val = (val << 1) | getBitInBytes(bytes, idx+i); } return val; } public static int leadingZeroCountInByte(byte b) { int i = b&0xFF; if (i>=128 || i == 0) return 0; return Integer.numberOfLeadingZeros(b)-24; /* * if-less alternative: * http://aggregate.ee.engr.uky.edu/MAGIC/#Leading Zero Count */ } }