-
Notifications
You must be signed in to change notification settings - Fork 107
Expand file tree
/
Copy pathArithmeticEncoder.java
More file actions
106 lines (82 loc) · 3.22 KB
/
Copy pathArithmeticEncoder.java
File metadata and controls
106 lines (82 loc) · 3.22 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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
* Reference arithmetic coding
*
* Copyright (c) Project Nayuki
* MIT License. See readme file.
* https://www.nayuki.io/page/reference-arithmetic-coding
*/
import java.io.IOException;
import java.util.Objects;
/**
* Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe.
* @see ArithmeticDecoder
*/
public final class ArithmeticEncoder extends ArithmeticCoderBase {
/*---- Fields ----*/
// The underlying bit output stream (not null).
private BitOutputStream output;
// Number of saved underflow bits. This value can grow without bound,
// so a truly correct implementation would use a BigInteger.
private int numUnderflow;
/*---- Constructor ----*/
/**
* Constructs an arithmetic coding encoder based on the specified bit output stream.
* @param numBits the number of bits for the arithmetic coding range
* @param out the bit output stream to write to
* @throws NullPointerException if the output stream is {@code null}
* @throws IllegalArgumentException if stateSize is outside the range [1, 62]
*/
public ArithmeticEncoder(int numBits, BitOutputStream out) {
super(numBits);
output = Objects.requireNonNull(out);
numUnderflow = 0;
}
/*---- Methods ----*/
/**
* Encodes the specified symbol based on the specified frequency table.
* This updates this arithmetic coder's state and may write out some bits.
* @param freqs the frequency table to use
* @param symbol the symbol to encode
* @throws NullPointerException if the frequency table is {@code null}
* @throws IllegalArgumentException if the symbol has zero frequency
* or the frequency table's total is too large
* @throws IOException if an I/O exception occurred
*/
public void write(FrequencyTable freqs, int symbol) throws IOException {
write(new CheckedFrequencyTable(freqs), symbol);
}
/**
* Encodes the specified symbol based on the specified frequency table.
* Also updates this arithmetic coder's state and may write out some bits.
* @param freqs the frequency table to use
* @param symbol the symbol to encode
* @throws NullPointerException if the frequency table is {@code null}
* @throws IllegalArgumentException if the symbol has zero frequency
* or the frequency table's total is too large
* @throws IOException if an I/O exception occurred
*/
public void write(CheckedFrequencyTable freqs, int symbol) throws IOException {
update(freqs, symbol);
}
/**
* Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly.
* It is important that this method must be called at the end of the each encoding process.
* <p>Note that this method merely writes data to the underlying output stream but does not close it.</p>
* @throws IOException if an I/O exception occurred
*/
public void finish() throws IOException {
output.write(1);
}
protected void shift() throws IOException {
int bit = (int)(low >>> (numStateBits - 1));
output.write(bit);
// Write out the saved underflow bits
for (; numUnderflow > 0; numUnderflow--)
output.write(bit ^ 1);
}
protected void underflow() {
if (numUnderflow == Integer.MAX_VALUE)
throw new ArithmeticException("Maximum underflow reached");
numUnderflow++;
}
}