encode.c 21.8 KB
Newer Older
1
/**
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
2
 * @file encode.c
3
4
5
6
 * @author Mathis Rosenhauer, Deutsches Klimarechenzentrum
 * @section DESCRIPTION
 *
 * Adaptive Entropy Encoder
7
 * Based on CCSDS documents 121.0-B-2 and 120.0-G-2
8
9
 *
 */
10

11
12
13
14
15
16
#include <config.h>

#if HAVE_STDINT_H
# include <stdint.h>
#endif

17
18
#include <stdio.h>
#include <stdlib.h>
19
#include <unistd.h>
20
21
#include <string.h>

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
22
23
24
#include "libaec.h"
#include "encode.h"
#include "encode_accessors.h"
25

26
/* Marker for Remainder Of Segment condition in zero block encoding */
27
#define ROS -1
28

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
29
30
31
32
33
34
35
36
37
38
39
40
41
static int m_get_block(struct aec_stream *strm);
static int m_get_block_cautious(struct aec_stream *strm);
static int m_check_zero_block(struct aec_stream *strm);
static int m_select_code_option(struct aec_stream *strm);
static int m_flush_block(struct aec_stream *strm);
static int m_flush_block_cautious(struct aec_stream *strm);
static int m_encode_splitting(struct aec_stream *strm);
static int m_encode_uncomp(struct aec_stream *strm);
static int m_encode_se(struct aec_stream *strm);
static int m_encode_zero(struct aec_stream *strm);

static inline void emit(struct internal_state *state,
                        uint32_t data, int bits)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
42
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
43
44
45
46
47
    /**
       Emit sequence of bits.
     */

    if (bits <= state->bit_p) {
48
49
        state->bit_p -= bits;
        *state->cds_p += data << state->bit_p;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
50
    } else {
51
        bits -= state->bit_p;
52
        *state->cds_p++ += (uint64_t)data >> bits;
53

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
54
        while (bits & ~7) {
55
            bits -= 8;
56
            *state->cds_p++ = data >> bits;
57
        }
58

59
60
        state->bit_p = 8 - bits;
        *state->cds_p = data << state->bit_p;
61
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
62
63
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
64
static inline void emitfs(struct internal_state *state, int fs)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
65
{
66
67
    /**
       Emits a fundamental sequence.
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
68

69
70
       fs zero bits followed by one 1 bit.
     */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
71

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
72
73
    for(;;) {
        if (fs < state->bit_p) {
74
75
            state->bit_p -= fs + 1;
            *state->cds_p += 1 << state->bit_p;
76
            break;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
77
        } else {
78
79
80
            fs -= state->bit_p;
            *++state->cds_p = 0;
            state->bit_p = 8;
81
82
        }
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
83
}
84

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
85
#define EMITBLOCK(ref)                                          \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
86
87
    static inline void emitblock_##ref(struct aec_stream *strm, \
                                       int k)                   \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
88
89
90
    {                                                           \
        int b;                                                  \
        uint64_t a;                                             \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
91
        struct internal_state *state = strm->state;             \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
92
93
94
95
96
97
98
99
        uint32_t *in = state->block_p + ref;                    \
        uint32_t *in_end = state->block_p + strm->block_size;   \
        uint64_t mask = (1ULL << k) - 1;                        \
        uint8_t *o = state->cds_p;                              \
        int p = state->bit_p;                                   \
                                                                \
        a = *o;                                                 \
                                                                \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
100
        while(in < in_end) {                                    \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
101
102
103
            a <<= 56;                                           \
            p = (p % 8) + 56;                                   \
                                                                \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
104
            while (p > k && in < in_end) {                      \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
                p -= k;                                         \
                a += ((uint64_t)(*in++) & mask) << p;           \
            }                                                   \
                                                                \
            for (b = 56; b > (p & ~7); b -= 8)                  \
                *o++ = a >> b;                                  \
            a >>= b;                                            \
        }                                                       \
                                                                \
        *o = a;                                                 \
        state->cds_p = o;                                       \
        state->bit_p = p % 8;                                   \
    }

EMITBLOCK(0);
EMITBLOCK(1);

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
122
static void preprocess_unsigned(struct aec_stream *strm)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
123
{
124
    int64_t D;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
125
    struct internal_state *state = strm->state;
126
127
    const uint32_t *x = state->data_raw;
    uint32_t *d = state->data_pp;
128
129
    uint32_t xmax = state->xmax;
    uint32_t rsi = strm->rsi * strm->block_size - 1;
130

131
    *d++ = x[0];
132
    while (rsi--) {
133
134
135
136
        if (x[1] >= x[0]) {
            D = x[1] - x[0];
            if (D <= x[0]) {
                *d = 2 * D;
137
            } else {
138
                *d = x[1];
139
            }
140
        } else {
141
142
143
            D = x[0] - x[1];
            if (D <= xmax - x[0]) {
                *d = 2 * D - 1;
144
            } else {
145
                *d = xmax - x[1];
146
            }
147
        }
148
        d++;
149
        x++;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
150
151
152
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
153
static void preprocess_signed(struct aec_stream *strm)
154
{
155
    int64_t D;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
156
    struct internal_state *state = strm->state;
157
158
159
    uint32_t *d = state->data_pp;
    int32_t *x = (int32_t *)state->data_raw;
    uint64_t m = 1ULL << (strm->bit_per_sample - 1);
160
161
162
    int64_t xmax = state->xmax;
    int64_t xmin = state->xmin;
    uint32_t rsi = strm->rsi * strm->block_size - 1;
163

164
165
166
    *d++ = (uint32_t)x[0];
    x[0] = (x[0] ^ m) - m;

167
    while (rsi--) {
168
169
170
171
172
        x[1] = (x[1] ^ m) - m;
        if (x[1] < x[0]) {
            D = (int64_t)x[0] - x[1];
            if (D <= xmax - x[0])
                *d = 2 * D - 1;
173
            else
174
                *d = xmax - x[1];
175
        } else {
176
177
178
            D = (int64_t)x[1] - x[0];
            if (D <= x[0] - xmin)
                *d = 2 * D;
179
            else
180
                *d = x[1] - xmin;
181
        }
182
183
        x++;
        d++;
184
    }
185
}
186

187
188
189
190
191
192
/*
 *
 * FSM functions
 *
 */

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
193
static int m_get_block(struct aec_stream *strm)
194
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
195
    struct internal_state *state = strm->state;
196

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
197
198
    if (strm->avail_out > state->cds_len) {
        if (!state->direct_out) {
199
200
201
            state->direct_out = 1;
            *strm->next_out = *state->cds_p;
            state->cds_p = strm->next_out;
202
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
203
204
    } else {
        if (state->zero_blocks == 0 || state->direct_out) {
205
            /* copy leftover from last block */
206
207
            *state->cds_buf = *state->cds_p;
            state->cds_p = state->cds_buf;
208
        }
209
        state->direct_out = 0;
210
    }
211

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
212
    if (state->blocks_avail == 0) {
213
        state->block_p = state->data_pp;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
214

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
215
        if (strm->avail_in >= state->block_len * strm->rsi) {
216
            state->get_rsi(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
217
            state->blocks_avail = strm->rsi - 1;
218

219
            if (strm->flags & AEC_DATA_PREPROCESS) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
220
                state->preprocess(strm);
221
222
                state->ref = 1;
            }
223
            return m_check_zero_block(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
224
        } else {
225
226
227
            state->i = 0;
            state->mode = m_get_block_cautious;
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
228
    } else {
229
230
231
232
        state->ref = 0;
        state->block_p += strm->block_size;
        state->blocks_avail--;
        return m_check_zero_block(strm);
233
    }
234
    return M_CONTINUE;
235
236
}

237
static int m_get_block_cautious(struct aec_stream *strm)
238
{
239
    int j;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
240
241
    struct internal_state *state = strm->state;

242
243
    do {
        if (strm->avail_in > 0) {
244
            state->data_raw[state->i] = state->get_sample(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
245
        } else {
246
247
248
            if (state->flush == AEC_FLUSH) {
                if (state->i > 0) {
                    for (j = state->i; j < strm->rsi * strm->block_size; j++)
249
                        state->data_raw[j] = state->data_raw[state->i - 1];
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
                    state->i = strm->rsi * strm->block_size;
                } else {
                    if (state->zero_blocks) {
                        state->mode = m_encode_zero;
                        return M_CONTINUE;
                    }

                    emit(state, 0, state->bit_p);
                    if (state->direct_out == 0)
                        *strm->next_out++ = *state->cds_p;
                    strm->avail_out--;
                    strm->total_out++;

                    return M_EXIT;
                }
            } else {
                return M_EXIT;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
267
            }
268
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
269
    } while (++state->i < strm->rsi * strm->block_size);
270

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
271
    state->blocks_avail = strm->rsi - 1;
272
    if (strm->flags & AEC_DATA_PREPROCESS) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
273
        state->preprocess(strm);
274
275
        state->ref = 1;
    }
276
277

    return m_check_zero_block(strm);
278
279
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
280
static int m_check_zero_block(struct aec_stream *strm)
281
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
282
    struct internal_state *state = strm->state;
283
284
285
    uint32_t *p = state->block_p + state->ref;
    uint32_t *end = state->block_p + strm->block_size;

286
    while(p < end && *p == 0)
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
        p++;

    if (p < end) {
        if (state->zero_blocks) {
            /* The current block isn't zero but we have to emit a
             * previous zero block first. The current block will be
             * handled later.
             */
            state->block_p -= strm->block_size;
            state->blocks_avail++;
            state->mode = m_encode_zero;
            return M_CONTINUE;
        }
        state->mode = m_select_code_option;
        return M_CONTINUE;
    } else {
        state->zero_blocks++;
        if (state->zero_blocks == 1) {
305
            state->zero_ref = state->ref;
306
            state->zero_ref_sample = state->block_p[0];
307
        }
308
309
        if (state->blocks_avail == 0
            || (strm->rsi - state->blocks_avail) % 64 == 0) {
310
311
312
313
314
315
316
            if (state->zero_blocks > 4)
                state->zero_blocks = ROS;
            state->mode = m_encode_zero;
            return M_CONTINUE;
        }
        state->mode = m_get_block;
        return M_CONTINUE;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
317
318
319
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
320
static uint64_t block_fs(struct aec_stream *strm, int k)
321
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
322
323
324
325
326
327
328
329
330
331
332
333
334
    int j;
    uint64_t fs;
    struct internal_state *state = strm->state;

    fs = (uint64_t)(state->block_p[1] >> k)
        + (uint64_t)(state->block_p[2] >> k)
        + (uint64_t)(state->block_p[3] >> k)
        + (uint64_t)(state->block_p[4] >> k)
        + (uint64_t)(state->block_p[5] >> k)
        + (uint64_t)(state->block_p[6] >> k)
        + (uint64_t)(state->block_p[7] >> k);

    if (strm->block_size > 8)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
335
        for (j = 8; j < strm->block_size; j += 8)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
336
            fs +=
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
337
338
339
340
341
342
343
344
345
346
                (uint64_t)(state->block_p[j + 0] >> k)
                + (uint64_t)(state->block_p[j + 1] >> k)
                + (uint64_t)(state->block_p[j + 2] >> k)
                + (uint64_t)(state->block_p[j + 3] >> k)
                + (uint64_t)(state->block_p[j + 4] >> k)
                + (uint64_t)(state->block_p[j + 5] >> k)
                + (uint64_t)(state->block_p[j + 6] >> k)
                + (uint64_t)(state->block_p[j + 7] >> k);

    if (!state->ref)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
347
348
349
350
        fs += (uint64_t)(state->block_p[0] >> k);

    return fs;
}
351

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
352
353
static int count_splitting_option(struct aec_stream *strm)
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
    /**
       Find the best point for splitting samples in a block.

       In Rice coding each sample in a block of samples is split at
       the same position into k LSB and bit_per_sample - k MSB. The
       LSB part is left binary and the MSB part is coded as a
       fundamental sequence a.k.a. unary (see CCSDS 121.0-B-2). The
       function of the length of the Coded Data Set (CDS) depending on
       k has exactly one minimum (see A. Kiely, IPN Progress Report
       42-159).

       To find that minimum with only a few costly evaluations of the
       CDS length, we start with the k of the previous CDS. K is
       increased and the CDS length evaluated. If the CDS length gets
       smaller, then we are moving towards the minimum. If the length
369
370
371
372
373
374
375
376
       increases, then the minimum will be found with smaller k.

       For increasing k we know that we will gain block_size bits in
       length through the larger binary part. If the FS lenth is less
       than the block size then a reduced FS part can't compensate the
       larger binary part. So we know that the CDS for k+1 will be
       larger than for k without actually computing the length. An
       analogue check can be done for decreasing k.
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
377
378
379
380
     */

    int k, k_min;
    int this_bs; /* Block size of current block */
381
    int no_turn; /* 1 if we shouldn't reverse */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
382
383
384
385
386
    int dir; /* Direction, 1 means increasing k, 0 decreasing k */
    uint64_t len; /* CDS length for current k */
    uint64_t len_min; /* CDS length minimum so far */
    uint64_t fs_len; /* Length of FS part (not including 1s) */

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
387
    struct internal_state *state = strm->state;
388

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
389
390
    this_bs = strm->block_size - state->ref;
    len_min = UINT64_MAX;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
391
    k = k_min = state->k;
392
    no_turn = (k == 0) ? 1 : 0;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
393
    dir = 1;
394

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
395
    for (;;) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
396
397
        fs_len = block_fs(strm, k);
        len = fs_len + this_bs * (k + 1);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
398
399

        if (len < len_min) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
400
            if (len_min < UINT64_MAX)
401
                no_turn = 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
402

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
403
            len_min = len;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
404
            k_min = k;
405

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
406
            if (dir) {
407
408
409
410
411
412
                if (fs_len < this_bs || k >= state->kmax) {
                    if (no_turn)
                        break;
                    k = state->k - 1;
                    dir = 0;
                    no_turn = 1;
413
414
                } else {
                    k++;
415
                }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
416
            } else {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
417
418
419
                if (fs_len >= this_bs || k == 0)
                    break;
                k--;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
420
            }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
421
        } else {
422
423
424
425
426
            if (no_turn)
                break;
            k = state->k - 1;
            dir = 0;
            no_turn = 1;
427
428
        }
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
429
    state->k = k_min;
430

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
431
432
433
434
435
436
437
438
439
440
441
442
    return len_min;
}

static int count_se_option(uint64_t limit, struct aec_stream *strm)
{
    int i;
    uint64_t d, len;
    struct internal_state *state = strm->state;

    len = 1;

    for (i = 0; i < strm->block_size; i+= 2) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
443
444
        d = (uint64_t)state->block_p[i]
            + (uint64_t)state->block_p[i + 1];
445
        /* we have to worry about overflow here */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
446
447
        if (d > limit) {
            len = UINT64_MAX;
448
            break;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
449
450
451
        } else {
            len += d * (d + 1) / 2
                + (uint64_t)state->block_p[i + 1];
452
453
        }
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
454
455
456
457
458
459
460
    return len;
}

static int m_select_code_option(struct aec_stream *strm)
{
    uint64_t uncomp_len, split_len, se_len;
    struct internal_state *state = strm->state;
461

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
462
463
464
465
    uncomp_len = (strm->block_size - state->ref)
        * strm->bit_per_sample;
    split_len = count_splitting_option(strm);
    se_len = count_se_option(split_len, strm);
466

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
467
468
    if (split_len < uncomp_len) {
        if (split_len < se_len)
469
470
471
            return m_encode_splitting(strm);
        else
            return m_encode_se(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
472
    } else {
473
474
475
476
477
478
        if (uncomp_len <= se_len)
            return m_encode_uncomp(strm);
        else
            return m_encode_se(strm);
    }
}
479

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
480
static int m_encode_splitting(struct aec_stream *strm)
481
482
{
    int i;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
483
    struct internal_state *state = strm->state;
484
    int k = state->k;
485

486
    emit(state, k + 1, state->id_len);
487

488
    if (state->ref)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
489
    {
490
        emit(state, state->block_p[0], strm->bit_per_sample);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
491
492
        for (i = 1; i < strm->block_size; i++)
            emitfs(state, state->block_p[i] >> k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
493
494
        if (k)
            emitblock_1(strm, k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
495
496
497
498
499
    }
    else
    {
        for (i = 0; i < strm->block_size; i++)
            emitfs(state, state->block_p[i] >> k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
500
501
        if (k)
            emitblock_0(strm, k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
502
    }
503

504
505
    return m_flush_block(strm);
}
506

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
507
static int m_encode_uncomp(struct aec_stream *strm)
508
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
509
    struct internal_state *state = strm->state;
510

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
511
    emit(state, (1U << state->id_len) - 1, state->id_len);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
512
    emitblock_0(strm, strm->bit_per_sample);
513

514
515
    return m_flush_block(strm);
}
516

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
517
static int m_encode_se(struct aec_stream *strm)
518
519
{
    int i;
520
    uint32_t d;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
521
    struct internal_state *state = strm->state;
522

523
524
    emit(state, 1, state->id_len + 1);
    if (state->ref)
525
        emit(state, state->block_p[0], strm->bit_per_sample);
526

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
527
    for (i = 0; i < strm->block_size; i+= 2) {
528
529
        d = state->block_p[i] + state->block_p[i + 1];
        emitfs(state, d * (d + 1) / 2 + state->block_p[i + 1]);
530
    }
531

532
533
    return m_flush_block(strm);
}
534

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
535
static int m_encode_zero(struct aec_stream *strm)
536
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
537
    struct internal_state *state = strm->state;
538

539
    emit(state, 0, state->id_len + 1);
540

541
542
    if (state->zero_ref)
        emit(state, state->zero_ref_sample, strm->bit_per_sample);
543

544
545
546
547
548
549
    if (state->zero_blocks == ROS)
        emitfs(state, 4);
    else if (state->zero_blocks >= 5)
        emitfs(state, state->zero_blocks);
    else
        emitfs(state, state->zero_blocks - 1);
550

551
552
553
    state->zero_blocks = 0;
    return m_flush_block(strm);
}
554

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
555
static int m_flush_block(struct aec_stream *strm)
556
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
557
558
559
560
561
    /**
       Flush block in direct_out mode by updating counters.

       Fall back to slow flushing if in buffered mode.
    */
562
    int n;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
563
    struct internal_state *state = strm->state;
564

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
565
    if (state->direct_out) {
566
        n = state->cds_p - strm->next_out;
567
568
569
570
571
572
        strm->next_out += n;
        strm->avail_out -= n;
        strm->total_out += n;
        state->mode = m_get_block;
        return M_CONTINUE;
    }
573

574
575
576
577
578
    state->i = 0;
    state->mode = m_flush_block_cautious;
    return M_CONTINUE;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
579
static int m_flush_block_cautious(struct aec_stream *strm)
580
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
581
582
583
584
    /**
       Slow and restartable flushing
    */
    struct internal_state *state = strm->state;
585

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
586
    while(state->cds_buf + state->i < state->cds_p) {
587
588
589
        if (strm->avail_out == 0)
            return M_EXIT;

590
        *strm->next_out++ = state->cds_buf[state->i];
591
592
593
594
595
596
597
598
599
600
601
602
603
        strm->avail_out--;
        strm->total_out++;
        state->i++;
    }
    state->mode = m_get_block;
    return M_CONTINUE;
}

/*
 *
 * API functions
 *
 */
604

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
605
int aec_encode_init(struct aec_stream *strm)
606
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
607
    struct internal_state *state;
608
609

    if (strm->bit_per_sample > 32 || strm->bit_per_sample == 0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
610
        return AEC_CONF_ERROR;
611
612
613
614
615

    if (strm->block_size != 8
        && strm->block_size != 16
        && strm->block_size != 32
        && strm->block_size != 64)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
616
        return AEC_CONF_ERROR;
617
618

    if (strm->rsi > 4096)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
619
        return AEC_CONF_ERROR;
620

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
621
    state = (struct internal_state *)malloc(sizeof(struct internal_state));
622
    if (state == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
623
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
624
625

    memset(state, 0, sizeof(struct internal_state));
626
627
    strm->state = state;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
628
    if (strm->bit_per_sample > 16) {
629
        /* 24/32 input bit settings */
630
631
        state->id_len = 5;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
632
633
        if (strm->bit_per_sample <= 24
            && strm->flags & AEC_DATA_3BYTE) {
634
            state->block_len = 3 * strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
635
            if (strm->flags & AEC_DATA_MSB) {
636
                state->get_sample = get_msb_24;
637
                state->get_rsi = get_rsi_msb_24;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
638
            } else {
639
                state->get_sample = get_lsb_24;
640
                state->get_rsi = get_rsi_lsb_24;
641
            }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
642
        } else {
643
            state->block_len = 4 * strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
644
            if (strm->flags & AEC_DATA_MSB) {
645
                state->get_sample = get_msb_32;
646
                state->get_rsi = get_rsi_msb_32;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
647
            } else {
648
                state->get_sample = get_lsb_32;
649
                state->get_rsi = get_rsi_lsb_32;
650
651
            }
        }
652
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
653
    else if (strm->bit_per_sample > 8) {
654
655
        /* 16 bit settings */
        state->id_len = 4;
656
        state->block_len = 2 * strm->block_size;
657

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
658
        if (strm->flags & AEC_DATA_MSB) {
659
            state->get_sample = get_msb_16;
660
            state->get_rsi = get_rsi_msb_16;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
661
        } else {
662
            state->get_sample = get_lsb_16;
663
            state->get_rsi = get_rsi_lsb_16;
664
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
665
    } else {
666
667
        /* 8 bit settings */
        state->id_len = 3;
668
        state->block_len = strm->block_size;
669
670

        state->get_sample = get_8;
671
        state->get_rsi = get_rsi_8;
672
673
    }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
674
    if (strm->flags & AEC_DATA_SIGNED) {
675
676
        state->xmin = -(1ULL << (strm->bit_per_sample - 1));
        state->xmax = (1ULL << (strm->bit_per_sample - 1)) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
677
        state->preprocess = preprocess_signed;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
678
    } else {
679
680
        state->xmin = 0;
        state->xmax = (1ULL << strm->bit_per_sample) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
681
        state->preprocess = preprocess_unsigned;
682
683
    }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
684
685
    state->kmax = (1U << state->id_len) - 3;

686
    state->data_pp = (uint32_t *)malloc(strm->rsi
687
688
                                         * strm->block_size
                                         * sizeof(uint32_t));
689
    if (state->data_pp == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
690
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
691

692
693
694
695
696
697
698
699
700
701
702
    if (strm->flags & AEC_DATA_PREPROCESS) {
        state->data_raw = (uint32_t *)malloc(strm->rsi
                                             * strm->block_size
                                             * sizeof(uint32_t));
        if (state->data_raw == NULL)
            return AEC_MEM_ERROR;
    } else {
        state->data_raw = state->data_pp;
    }

    state->block_p = state->data_pp;
703

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
704
    /* Largest possible CDS according to specs */
705
706
707
    state->cds_len = (5 + 64 * 32) / 8 + 3;
    state->cds_buf = (uint8_t *)malloc(state->cds_len);
    if (state->cds_buf == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
708
        return AEC_MEM_ERROR;
709

710
711
712
    strm->total_in = 0;
    strm->total_out = 0;

713
714
715
    state->cds_p = state->cds_buf;
    *state->cds_p = 0;
    state->bit_p = 8;
716
717
    state->mode = m_get_block;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
718
    return AEC_OK;
719
720
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
721
int aec_encode(struct aec_stream *strm, int flush)
722
723
724
725
726
{
    /**
       Finite-state machine implementation of the adaptive entropy
       encoder.
    */
727
    int n;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
728
    struct internal_state *state;
729
730
731
732
733
    state = strm->state;
    state->flush = flush;

    while (state->mode(strm) == M_CONTINUE);

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
734
    if (state->direct_out) {
735
736
737
738
739
740
741
742
        n = state->cds_p - strm->next_out;
        strm->next_out += n;
        strm->avail_out -= n;
        strm->total_out += n;

        *state->cds_buf = *state->cds_p;
        state->cds_p = state->cds_buf;
        state->direct_out = 0;
743
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
744
    return AEC_OK;
745
746
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
747
int aec_encode_end(struct aec_stream *strm)
748
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
749
    struct internal_state *state = strm->state;
750

751
752
753
    if (strm->flags & AEC_DATA_PREPROCESS)
        free(state->data_raw);
    free(state->data_pp);
754
    free(state->cds_buf);
755
    free(state);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
756
    return AEC_OK;
757
}
758

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
759
int aec_buffer_encode(struct aec_stream *strm)
760
761
762
763
764
765
766
767
768
769
770
771
772
{
    int status;

    status = aec_encode_init(strm);
    if (status != AEC_OK)
        return status;
    status = aec_encode(strm, AEC_FLUSH);
    if (strm->avail_in > 0 || strm->avail_out == 0)
        status = AEC_DATA_ERROR;

    aec_encode_end(strm);
    return status;
}