-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathRiceEncoder.java
More file actions
227 lines (212 loc) · 8.39 KB
/
RiceEncoder.java
File metadata and controls
227 lines (212 loc) · 8.39 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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/*
* Copyright (C) 2010 Preston Lacey http://javaflacencoder.sourceforge.net/
* All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package javaFlacEncoder;
/**
* The RiceEncoder class is used to create FLAC-compliant rice-encoded
* residuals.
*
* @author Preston Lacey
*/
public class RiceEncoder {
/** For debugging: Higher values equals greater output, generally in
* increments of 10 */
public static int DEBUG_LEV = 0;
private static final int POSITIVE = 0;
private static final int NEGATIVE = 1;
private static final int STOP_BIT = 0xFFFFFFFF;
private static final int UNARY_BIT = 0;
private int[] _dataToEncode = null;
private int[] _bitsToEncode = null;
/**
* Constructor. A RiceEncoder object is used(as opposed to potentially
* faster static methods), for memory considerations; some temporary,
* dynamically created arrays are kept between calls to the encode methods
* to prevent frequently allocating and freeing similarly sized arrays.
*/
public RiceEncoder() {
}
/**
* Create the residual headers for a FLAC stream.
*
* @param useFiveBitParam Set TRUE if using a five-bit parameter size, FALSE
* for a four-bit parameter
* @param order Specify order of partitions to be used(actual number of
* partitions will be 2^order.
* @param ele EncodedElement to write header to.
* @return total written size of header.
*/
public static int beginResidual(boolean useFiveBitParam, byte order,
EncodedElement ele) {
ele = ele.getEnd();
int paramSize = (useFiveBitParam) ? 1:0;
ele.addInt(paramSize, 2);
ele.addInt(order, 4);
return 6;
}
public static int encodeRicePartitionEscaped(int[] values, int inputOffset,
int inputStep, int inputCount, EncodedElement destEle,
int bitParam, boolean fiveBitParam) {
if(DEBUG_LEV > 0)
System.err.println("RiceEncoder::encode : Begin");
/* Currently, we're passing in an EncodedElement with a set byte[], and
filling that array. We should therefore ensure that we're not writing
too much to it. We *can* add another element to the given one if need.*/
//write headers(i.e, write the parameter)
int bitsWritten = 0;
if(fiveBitParam) {
destEle.addInt(255, 5);
destEle.addInt(16,5);
bitsWritten += 10;
}
else {
destEle.addInt(255, 4);
destEle.addInt(16,5);
bitsWritten += 9;
}
for(int i = 0; i < inputCount; i++) {
destEle.addInt(values[i*inputStep+inputOffset], 16);
bitsWritten += 16;
}
if(DEBUG_LEV > 0)
System.err.println("RiceEncoder::encode : End");
return bitsWritten;
}
/**
* Rice-encode a set of values, adding necessary headers for FLAC format. This
* encodes a single rice-partition. In general, beginResidual(...) should be
* used before this method.
*
* @param values array of integer values to save
* @param inputOffset start index in input array
* @param inputStep number of values to skip between target values(for
* interleaved data.
* @param inputCount number of total values to encode
* @param bitParam rice-parameter to use. This value should be based upon
* the distribution of the input data(roughly speeking, each value
* will require at least bitParam+1 bits to save, so this value
* should reflect the average magnitude of input values.
* @param destEle EncodedElement to save result to.
* @param fiveBitParam Set true if this header should use a five-bit
* rice-parameter, false for a four bit parameter.
* @return total encoded size(including headers)
*/
public int encodeRicePartition(int[] values, int inputOffset,
int inputStep, int inputCount, EncodedElement destEle,
final int bitParam, boolean fiveBitParam) {
//Pack int version of encode partition
if(DEBUG_LEV > 0) {
System.err.println("RiceEncoder::encode : Begin");
System.err.println("-- bitParam: " + bitParam);
}
//write headers(i.e, write the parameter)
int startBits = destEle.getTotalBits();
if(fiveBitParam) {
destEle.addInt(bitParam, 5);
}
else {
destEle.addInt(bitParam, 4);
}
//encode each input value;
if(_dataToEncode == null || _bitsToEncode == null) {
_dataToEncode = new int[values.length*4];
_bitsToEncode = new int[values.length*4];
}
int[] dataToEncode = _dataToEncode;
int[] bitsToEncode = _bitsToEncode;
int nextToEncode = 0;
int maxToEncode = dataToEncode.length;
int inputIndex = inputOffset-inputStep;
final int stopbit = (bitParam >0) ? STOP_BIT << bitParam:STOP_BIT;
final int maskParam = (bitParam == 0) ? 0:0xFFFFFFFF>>>(32-bitParam);
for(int i = 0; i < inputCount; i++) {
inputIndex +=inputStep;
int value = values[inputIndex];
value = (value < 0) ? -2*value-1:2*value;
int upperBits = value >> bitParam;
//make sure we won't write to much. Handle if we will.
int dataToEncodeSpaceNeeded = (2+upperBits/32);
if(upperBits%32 != 0)
dataToEncodeSpaceNeeded++;
if(dataToEncodeSpaceNeeded+nextToEncode >= maxToEncode) {
//write everything we have:
destEle.packIntByBits(dataToEncode, bitsToEncode, 0, nextToEncode);
nextToEncode = 0;
}
//write unary upper bits:
int count = 0;
while(upperBits > 0) {
int tempVal = (upperBits > 32) ? 32:upperBits;//can only write 32 bits at a time.
dataToEncode[nextToEncode] = UNARY_BIT;
bitsToEncode[nextToEncode++] = tempVal;
upperBits -= tempVal;
count++;
}
dataToEncode[nextToEncode] = (value&maskParam) | stopbit ;
bitsToEncode[nextToEncode++] = bitParam+1;
}
//System.err.println("end loop");
//write remaining data to encode
if(nextToEncode > 0) {
destEle.packIntByBits(dataToEncode, bitsToEncode, 0, nextToEncode);
nextToEncode = 0;
}
int bitsWritten = destEle.getTotalBits() - startBits;
//System.err.println("RiceENcoder encode end:");
return bitsWritten;
}
/**
* Calculate how large a given set of values will be once it has been
* rice-encoded. While this method duplicates much of the process of
* rice-encoding, it is faster than an actual encode since the data is not
* actually written to the flac bitstream format(a rather costly write).
*
* @param values array of integer values to save
* @param inputOffset start index in input array
* @param inputStep number of values to skip between target values(for
* interleaved data.
* @param inputCount number of total values to encode
* @param bitParam rice-parameter to use. This value should be based upon
* the distribution of the input data(roughly speeking, each value
* will require at least bitParam+1 bits to save, so this value
* should reflect the average magnitude of input values.
* @return total encoded-size with given data and rice-parameter.
*/
public static int calculateEncodeSize(int[] values, int inputOffset,
int inputStep, int inputCount, int bitParam) {
//Pack int version of encode partition
if(DEBUG_LEV > 0) {
System.err.println("RiceEncoder::calculateEncodeSize : Begin");
System.err.println("-- bitParam: " + bitParam);
}
int totalEncodeLength = inputCount*(bitParam+1);
int index = inputOffset-inputStep;
for(int i = 0; i < inputCount; i++) {
index += inputStep;
int value = values[index];
value = (value < 0) ? -2*value-1:2*value;
int upperBits = value >> bitParam;
totalEncodeLength += upperBits;
}
if(bitParam > 14)
totalEncodeLength += 5+6;
else
totalEncodeLength += 4+6;
return totalEncodeLength;
}
}