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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
|
/*! @file codebooks.c
*
* @brief Implementation of the routines for computing the encoding tables from a codebook.
*
* (C) Copyright 2018 GoPro Inc (http://gopro.com/).
*
* Licensed under either:
* - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
* - MIT license, http://opensource.org/licenses/MIT
* at your option.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "headers.h"
#include "table17.inc"
//! Length of the codebook for runs of zeros
#define RUNS_TABLE_LENGTH 3072
/*!
@brief Define the codeset used by the reference codec
The baseline codec only supports codebook #17.
Codebook #17 is intended to be used with cubic companding
(see @ref FillMagnitudeEncodingTable and @ref ComputeCubicTable).
*/
ENCODER_CODESET encoder_codeset_17 = {
"Codebook set 17 from data by David Newman with tables automatically generated for the FSM decoder",
(const CODEBOOK *)&table17,
CODESET_FLAGS_COMPANDING_CUBIC,
NULL,
NULL,
};
/*!
@brief Initialize the codeset by creating more efficient tables for encoding
This routine takes the original codebook in the codeset and creates a table
of codewords for runs of zeros, indexed by the run length, and a table for
coefficient magnitudes, indexed by the coefficient magnitude. This allows
runs of zeros and non-zero coefficients to be entropy coded using a simple
table lookup.
*/
CODEC_ERROR PrepareCodebooks(const gpr_allocator *allocator, ENCODER_CODESET *cs)
{
CODEC_ERROR error = CODEC_ERROR_OKAY;
// Create a new table for runs of zeros with the default length
const int runs_table_length = RUNS_TABLE_LENGTH;
// Initialize the indexable table of run length codes
RLV *old_codes = (RLV *)(((uint8_t *)cs->codebook) + sizeof(CODEBOOK));
int old_length = cs->codebook->length;
size_t runs_table_size = runs_table_length * sizeof(RLC) + sizeof(RUNS_TABLE);
RUNS_TABLE *runs_table = allocator->Alloc(runs_table_size);
RLC *new_codes = (RLC *)(((uint8_t *)runs_table) + sizeof(RUNS_TABLE));
int new_length = runs_table_length;
// Set the length of the table for encoding coefficient magnitudes
int mags_table_shift = 8;
int mags_table_length;
size_t mags_table_size;
MAGS_TABLE *mags_table;
VLE *mags_table_entries;
// Use a larger table if companding
if (CompandingParameter() > 0) {
//mags_table_shift = 11;
mags_table_shift = 10;
}
// Allocate the table for encoding coefficient magnitudes
mags_table_length = (1 << mags_table_shift);
mags_table_size = mags_table_length * sizeof(VLE) + sizeof(MAGS_TABLE);
mags_table = allocator->Alloc(mags_table_size);
if (mags_table == NULL) {
allocator->Free( (void *)runs_table);
return CODEC_ERROR_OUTOFMEMORY;
}
mags_table_entries = (VLE *)(((uint8_t *)mags_table) + sizeof(MAGS_TABLE));
// Create a more efficient codebook for encoding runs of zeros
error = ComputeRunLengthCodeTable(allocator,
old_codes, old_length, new_codes, new_length);
if (error != CODEC_ERROR_OKAY) {
allocator->Free( (void *)runs_table);
return error;
}
// Store the new table for runs of zeros in the codeset
runs_table->length = runs_table_length;
cs->runs_table = runs_table;
error = FillMagnitudeEncodingTable(cs->codebook, mags_table_entries, mags_table_length, cs->flags);
if (error != CODEC_ERROR_OKAY) {
allocator->Free( (void *)runs_table);
return error;
}
mags_table->length = mags_table_length;
cs->mags_table = mags_table;
// The codebooks have been initialized successfully
return CODEC_ERROR_OKAY;
}
/*!
@brief Free all data structures allocated for the codebooks
*/
CODEC_ERROR ReleaseCodebooks(gpr_allocator *allocator, ENCODER_CODESET *cs)
{
allocator->Free( (void *)cs->runs_table );
allocator->Free( (void *)cs->mags_table);
return CODEC_ERROR_OKAY;
}
/*!
@brief Compute a table of codewords for runs of zeros
The table is indexed by the length of the run of zeros.
*/
CODEC_ERROR ComputeRunLengthCodeTable(const gpr_allocator *allocator,
RLV *input_codes, int input_length,
RLC *output_codes, int output_length)
{
// Need enough space for the codebook and the code for a single value
int runs_codebook_length = input_length + 1;
size_t runs_codebook_size = runs_codebook_length * sizeof(RLC);
RLC *runs_codebook = (RLC *)allocator->Alloc(runs_codebook_size);
bool single_zero_run_flag = false;
int input_index;
int runs_codebook_count = 0;
CODEC_ERROR return_code = CODEC_ERROR_OKAY;
// Copy the codes for runs of zeros into the temporary codebook for sorting
for (input_index = 0; input_index < input_length; input_index++)
{
uint32_t count = input_codes[input_index].count;
int32_t value = input_codes[input_index].value;
// Is this code for a run of zeros?
if (value != 0 || count == 0) {
// Skip codebook entries for coefficient magnitudes and special codes
continue;
}
// Is this code for a single zero
if (count == 1 && value == 0) {
single_zero_run_flag = true;
}
// Check that the temporary runs codebook is not full
assert(runs_codebook_count < runs_codebook_length);
// Copy the code into the temporary runs codebook
runs_codebook[runs_codebook_count].size = input_codes[input_index].size;
runs_codebook[runs_codebook_count].bits = input_codes[input_index].bits;
runs_codebook[runs_codebook_count].count = count;
// Check the codebook entry
assert(runs_codebook[runs_codebook_count].size > 0);
assert(runs_codebook[runs_codebook_count].count > 0);
// Increment the count of codes in the temporary runs codebook
runs_codebook_count++;
}
// Check that the runs codebook includes a run of a single zero
if( single_zero_run_flag == false )
{
assert(false);
return_code = CODEC_ERROR_UNEXPECTED;
}
// Sort the codewords into decreasing run length
SortDecreasingRunLength(runs_codebook, runs_codebook_count);
// The last code must be for a single run
assert(runs_codebook[runs_codebook_count - 1].count == 1);
// Fill the lookup table with codes for runs indexed by the run length
FillRunLengthEncodingTable(runs_codebook, runs_codebook_count, output_codes, output_length);
// Free the space used for the sorted codewords
allocator->Free(runs_codebook);
return return_code;
}
/*!
@brief Sort the codebook into decreasing length of the run
*/
CODEC_ERROR SortDecreasingRunLength(RLC *codebook, int length)
{
int i;
int j;
// Perform a simple bubble sort since the codebook may already be sorted
for (i = 0; i < length; i++)
{
for (j = i+1; j < length; j++)
{
// Should not have more than one codebook entry with the same run length
assert(codebook[i].count != codebook[j].count);
// Exchange codebook entries if the current entry is smaller
if (codebook[i].count < codebook[j].count)
{
int size = codebook[i].size;
uint32_t bits = codebook[i].bits;
int count = codebook[i].count;
codebook[i].size = codebook[j].size;
codebook[i].bits = codebook[j].bits;
codebook[i].count = codebook[j].count;
codebook[j].size = size;
codebook[j].bits = bits;
codebook[j].count = count;
}
}
// After two iterations that last two items should be in the proper order
assert(i == 0 || codebook[i-1].count > codebook[i].count);
}
return CODEC_ERROR_OKAY;
}
/*!
@brief Use a sparse run length code table to create an indexable table for faster encoding
*/
CODEC_ERROR FillRunLengthEncodingTable(RLC *codebook, int codebook_length, RLC *table, int table_length)
{
int i; // Index into the lookup table
int j; // Index into the codebook
// Use all of the bits except the sign bit for the codewords
int max_code_size = bit_word_count - 1;
// Check that the input codes are sorted into decreasing run length
for (j = 1; j < codebook_length; j++)
{
RLC *previous = &codebook[j-1];
RLC *current = &codebook[j];
assert(previous->count > current->count);
if (! (previous->count > current->count)) {
return CODEC_ERROR_UNEXPECTED;
}
}
// The last input code should be the code for a single zero
assert(codebook[codebook_length - 1].count == 1);
// Create the shortest codeword for each table entry
for (i = 0; i < table_length; i++)
{
int length = i; // Length of the run for this table entry
uint32_t codeword = 0; // Composite codeword for this run length
int codesize = 0; // Number of bits in the composite codeword
int remaining; // Remaining run length not covered by the codeword
remaining = length;
for (j = 0; j < codebook_length; j++)
{
int repetition; // Number of times the codeword is used
int k;
// Nothing to do if the remaining run length is zero
if (remaining == 0) break;
// The number of times that the codeword is used is the number
// of times that it divides evenly into the remaining run length
repetition = remaining / codebook[j].count;
// Append the codes to the end of the composite codeword
for (k = 0; k < repetition; k++)
{
// Terminate the loop if the codeword will not fit
if (codebook[j].size > (max_code_size - codesize))
{
if (codesize)
{
remaining -= (k * codebook[j].count);
goto next;
}
else
{
break;
}
}
// Shift the codeword to make room for the appended codes
codeword <<= codebook[j].size;
// Insert the codeword from the codebook at the end of the composite codeword
codeword |= codebook[j].bits;
// Increment the number of bits in the composite codeword
codesize += codebook[j].size;
}
// Reduce the run length by the amount that was consumed by the repeated codeword
remaining -= (k * codebook[j].count);
}
next:
// Should have covered the entire run if the last codeword would fit
//assert(remaining == 0 || (max_code_size - codesize) < codebook[codebook_length - 1].size);
// Store the composite run length in the lookup table
table[i].bits = codeword;
table[i].size = codesize;
table[i].count = length - remaining;
}
return CODEC_ERROR_OKAY;
}
/*!
@brief Fill lookup table for encoding coefficient magnitudes
The table for encoding coefficient magnitudes is indexed by the magnitude.
Each entry is a codeword and the size in bits.
@todo Implement cubic companding
*/
CODEC_ERROR FillMagnitudeEncodingTable(const CODEBOOK *codebook, VLE *mags_table_entry, int mags_table_length, uint32_t flags)
{
// Get the length of the codebook and a pointer to the entries
//int codebook_length = codebook->length;
RLV *codebook_entry = (RLV *)((uint8_t *)codebook + sizeof(CODEBOOK));
int32_t maximum_magnitude_value = 0;
uint32_t codebook_index;
int16_t cubic_table[1025];
int cubic_table_length = sizeof(cubic_table) / sizeof(cubic_table[0]);
int mags_table_index;
// Find the maximum coefficient magnitude in the codebook
for (codebook_index = 0; codebook_index < codebook->length; codebook_index++)
{
// Does this codebook entry correspond to a coefficient magnitude?
if (codebook_entry[codebook_index].count == 1)
{
int32_t codebook_value = codebook_entry[codebook_index].value;
if (maximum_magnitude_value < codebook_value) {
maximum_magnitude_value = codebook_value;
}
}
}
assert(maximum_magnitude_value > 0);
if (flags & CODESET_FLAGS_COMPANDING_CUBIC)
{
ComputeCubicTable(cubic_table, cubic_table_length, maximum_magnitude_value);
}
// Fill each table entry with the codeword for that (signed) value
for (mags_table_index = 0; mags_table_index < mags_table_length; mags_table_index++)
{
// Compute the magnitude that corresponds to this index
int32_t magnitude = mags_table_index;
uint32_t codeword;
int codesize;
// Apply the companding curve
if (flags & CODESET_FLAGS_COMPANDING_CUBIC)
{
// Apply a cubic companding curve
assert(magnitude < cubic_table_length);
magnitude = cubic_table[magnitude];
}
else if (flags & CODESET_FLAGS_COMPANDING_NONE)
{
// Do not apply a companding curve
}
else
{
// Apply an old-style companding curve
magnitude = CompandedValue(magnitude);
}
// Is the magnitude larger than the number of entries in the codebook?
if (magnitude > maximum_magnitude_value) {
magnitude = maximum_magnitude_value;
}
// Find the codebook entry corresponding to this coefficient magnitude
codeword = 0;
codesize = 0;
for (codebook_index = 0; codebook_index < codebook->length; codebook_index++)
{
if (codebook_entry[codebook_index].value == magnitude)
{
assert(codebook_entry[codebook_index].count == 1);
codeword = codebook_entry[codebook_index].bits;
codesize = codebook_entry[codebook_index].size;
break;
}
}
assert(0 < codesize && codesize <= 32);
mags_table_entry[mags_table_index].bits = codeword;
mags_table_entry[mags_table_index].size = codesize;
}
return CODEC_ERROR_OKAY;
}
|