-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArithmeticDecoder.java
More file actions
89 lines (67 loc) · 2.26 KB
/
Copy pathArithmeticDecoder.java
File metadata and controls
89 lines (67 loc) · 2.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package nayuki.arithcode;
import java.io.IOException;
public final class ArithmeticDecoder extends ArithmeticCoderBase {
private BitInputStream input;
// The current code being read, which is always in the range [low, high].
private long code;
// Creates an arithmetic coding decoder.
public ArithmeticDecoder(BitInputStream in) throws IOException {
super();
if (in == null)
throw new NullPointerException();
input = in;
code = 0;
for (int i = 0; i < STATE_SIZE; i++)
code = code << 1 | readCodeBit();
}
// Decodes and returns a symbol.
public int read(FrequencyTable freq) throws IOException {
return read(new CheckedFrequencyTable(freq));
}
// Decodes and returns a symbol.
public int read(CheckedFrequencyTable freq) throws IOException {
// Translate from coding range scale to frequency table scale
long total = freq.getTotal();
if (total > MAX_TOTAL)
throw new IllegalArgumentException("Cannot decode symbol because total is too large");
long range = high - low + 1;
long offset = code - low;
long value = ((offset + 1) * total - 1) / range;
if (value * range / total > offset)
throw new AssertionError();
if (value < 0 || value >= freq.getTotal())
throw new AssertionError();
// A kind of binary search
int start = 0;
int end = freq.getSymbolLimit();
while (end - start > 1) {
int middle = (start + end) >>> 1;
if (freq.getLow(middle) > value)
end = middle;
else
start = middle;
}
if (start == end)
throw new AssertionError();
int symbol = start;
if (freq.getLow(symbol) * range / total > offset || freq.getHigh(symbol) * range / total <= offset)
throw new AssertionError();
update(freq, symbol);
if (code < low || code > high)
throw new AssertionError("Code out of range");
return symbol;
}
protected void shift() throws IOException {
code = ((code << 1) & MASK) | readCodeBit();
}
protected void underflow() throws IOException {
code = (code & TOP_MASK) | ((code << 1) & (MASK >>> 1)) | readCodeBit();
}
private int readCodeBit() throws IOException {
int temp = input.read(); // read one digit after freq in inputBitstream
if (temp != -1)
return temp;
else // Treat end of stream as an infinite number of trailing zeros
return 0;
}
}