encode.c 24.9 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
static int m_get_block(struct aec_stream *strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
30
static int m_get_rsi_resumable(struct aec_stream *strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
31
32
33
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);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
34
static int m_flush_block_resumable(struct aec_stream *strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
35
36
37
38
39
40
41
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
    /**
       Emit sequence of bits.
     */

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

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
59
60
        state->bits = 8 - bits;
        *state->cds = data << state->bits;
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
    for(;;) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
73
74
75
        if (fs < state->bits) {
            state->bits -= fs + 1;
            *state->cds += 1U << state->bits;
76
            break;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
77
        } else {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
78
79
80
            fs -= state->bits;
            *++state->cds = 0;
            state->bits = 8;
81
82
        }
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
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
static inline void copy64(uint8_t *dst, uint64_t src)
{
    dst[0] = src >> 56;
    dst[1] = src >> 48;
    dst[2] = src >> 40;
    dst[3] = src >> 32;
    dst[4] = src >> 24;
    dst[5] = src >> 16;
    dst[6] = src >> 8;
    dst[7] = src;
}

#define EMITBLOCK_FS(ref)                                           \
    static inline void emitblock_fs_##ref(struct aec_stream *strm,  \
                                          int k)                    \
    {                                                               \
        int i;                                                      \
        int used; /* used bits in 64 bit accumulator */             \
        uint64_t acc; /* accumulator */                             \
        struct internal_state *state = strm->state;                 \
                                                                    \
        acc = (uint64_t)*state->cds << 56;                          \
        used = 7 - state->bits;                                     \
                                                                    \
        for (i = ref; i < strm->block_size; i++) {                  \
            used += (state->block[i] >> k) + 1;                     \
            if (used > 63) {                                        \
                copy64(state->cds, acc);                            \
                state->cds += 8;                                    \
                acc = 0;                                            \
                used &= 0x3f;                                       \
            }                                                       \
            acc |= 1ULL << (63 - used);                             \
        }                                                           \
                                                                    \
        copy64(state->cds, acc);                                    \
        state->cds += used >> 3;                                    \
        state->bits = 7 - (used & 7);                               \
    }

EMITBLOCK_FS(0);
EMITBLOCK_FS(1);

#define EMITBLOCK(ref)                                              \
    static inline void emitblock_##ref(struct aec_stream *strm,     \
                                       int k)                       \
    {                                                               \
        /**                                                         \
           Emit the k LSB of a whole block of input data.           \
        */                                                          \
                                                                    \
        int b;                                                      \
        uint64_t a;                                                 \
        struct internal_state *state = strm->state;                 \
        uint32_t *in = state->block + ref;                          \
        uint32_t *in_end = state->block + strm->block_size;         \
        uint64_t mask = (1ULL << k) - 1;                            \
        uint8_t *o = state->cds;                                    \
        int p = state->bits;                                        \
                                                                    \
        a = *o;                                                     \
                                                                    \
        while(in < in_end) {                                        \
            a <<= 56;                                               \
            p = (p % 8) + 56;                                       \
                                                                    \
            while (p > k && in < in_end) {                          \
                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 = o;                                             \
        state->bits = p % 8;                                        \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
164
165
166
167
168
    }

EMITBLOCK(0);
EMITBLOCK(1);

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
169
static void preprocess_unsigned(struct aec_stream *strm)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
170
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
171
172
173
174
    /**
       Preprocess RSI of unsigned samples.
    */

175
    int64_t D;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
176
    struct internal_state *state = strm->state;
177
178
    const uint32_t *x = state->data_raw;
    uint32_t *d = state->data_pp;
179
180
    uint32_t xmax = state->xmax;
    uint32_t rsi = strm->rsi * strm->block_size - 1;
181

182
    *d++ = x[0];
183
    while (rsi--) {
184
185
186
187
        if (x[1] >= x[0]) {
            D = x[1] - x[0];
            if (D <= x[0]) {
                *d = 2 * D;
188
            } else {
189
                *d = x[1];
190
            }
191
        } else {
192
193
194
            D = x[0] - x[1];
            if (D <= xmax - x[0]) {
                *d = 2 * D - 1;
195
            } else {
196
                *d = xmax - x[1];
197
            }
198
        }
199
        d++;
200
        x++;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
201
202
203
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
204
static void preprocess_signed(struct aec_stream *strm)
205
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
206
207
208
209
    /**
       Preprocess RSI of signed samples.
    */

210
    int64_t D;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
211
    struct internal_state *state = strm->state;
212
213
214
    uint32_t *d = state->data_pp;
    int32_t *x = (int32_t *)state->data_raw;
    uint64_t m = 1ULL << (strm->bit_per_sample - 1);
215
216
217
    int64_t xmax = state->xmax;
    int64_t xmin = state->xmin;
    uint32_t rsi = strm->rsi * strm->block_size - 1;
218

219
220
221
    *d++ = (uint32_t)x[0];
    x[0] = (x[0] ^ m) - m;

222
    while (rsi--) {
223
224
225
226
227
        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;
228
            else
229
                *d = xmax - x[1];
230
        } else {
231
232
233
            D = (int64_t)x[1] - x[0];
            if (D <= x[0] - xmin)
                *d = 2 * D;
234
            else
235
                *d = x[1] - xmin;
236
        }
237
238
        x++;
        d++;
239
    }
240
}
241

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
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
static uint64_t block_fs(struct aec_stream *strm, int k)
{
    /**
       Sum FS of all samples in block for given splitting position.
    */

    int j;
    uint64_t fs;
    struct internal_state *state = strm->state;

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

    if (strm->block_size > 8)
        for (j = 8; j < strm->block_size; j += 8)
            fs +=
                (uint64_t)(state->block[j + 0] >> k)
                + (uint64_t)(state->block[j + 1] >> k)
                + (uint64_t)(state->block[j + 2] >> k)
                + (uint64_t)(state->block[j + 3] >> k)
                + (uint64_t)(state->block[j + 4] >> k)
                + (uint64_t)(state->block[j + 5] >> k)
                + (uint64_t)(state->block[j + 6] >> k)
                + (uint64_t)(state->block[j + 7] >> k);

    if (!state->ref)
        fs += (uint64_t)(state->block[0] >> k);

    return fs;
}

static int assess_splitting_option(struct aec_stream *strm)
{
    /**
       Length of CDS encoded with splitting option and optimal k.

       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
       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.
     */

    int k;
    int k_min;
    int this_bs; /* Block size of current block */
    int no_turn; /* 1 if we shouldn't reverse */
    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) */

    struct internal_state *state = strm->state;

    this_bs = strm->block_size - state->ref;
    len_min = UINT64_MAX;
    k = k_min = state->k;
    no_turn = (k == 0) ? 1 : 0;
    dir = 1;

    for (;;) {
        fs_len = block_fs(strm, k);
        len = fs_len + this_bs * (k + 1);

        if (len < len_min) {
            if (len_min < UINT64_MAX)
                no_turn = 1;

            len_min = len;
            k_min = k;

            if (dir) {
                if (fs_len < this_bs || k >= state->kmax) {
                    if (no_turn)
                        break;
                    k = state->k - 1;
                    dir = 0;
                    no_turn = 1;
                } else {
                    k++;
                }
            } else {
                if (fs_len >= this_bs || k == 0)
                    break;
                k--;
            }
        } else {
            if (no_turn)
                break;
            k = state->k - 1;
            dir = 0;
            no_turn = 1;
        }
    }
    state->k = k_min;

    return len_min;
}

static int assess_se_option(uint64_t limit, struct aec_stream *strm)
{
    /**
       Length of CDS encoded with Second Extension option.

       If length is above limit just return UINT64_MAX.
    */

    int i;
    uint64_t d;
    uint64_t len;
    struct internal_state *state = strm->state;

    len = 1;

    for (i = 0; i < strm->block_size; i+= 2) {
        d = (uint64_t)state->block[i]
            + (uint64_t)state->block[i + 1];
        /* we have to worry about overflow here */
        if (d > limit) {
            len = UINT64_MAX;
            break;
        } else {
            len += d * (d + 1) / 2
                + (uint64_t)state->block[i + 1];
        }
    }
    return len;
}

391
392
393
394
395
396
/*
 *
 * FSM functions
 *
 */

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
397
static int m_get_block(struct aec_stream *strm)
398
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
399
400
401
402
403
404
405
    /**
       Provide the next block of preprocessed input data.

       Pull in a whole Reference Sample Interval (RSI) of data if
       block buffer is empty.
    */

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
406
    struct internal_state *state = strm->state;
407

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
408
409
    if (strm->avail_out > state->cds_len) {
        if (!state->direct_out) {
410
            state->direct_out = 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
411
412
            *strm->next_out = *state->cds;
            state->cds = strm->next_out;
413
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
414
415
    } else {
        if (state->zero_blocks == 0 || state->direct_out) {
416
            /* copy leftover from last block */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
417
418
            *state->cds_buf = *state->cds;
            state->cds = state->cds_buf;
419
        }
420
        state->direct_out = 0;
421
    }
422

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
423
    if (state->blocks_avail == 0) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
424
        state->block = state->data_pp;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
425

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
426
        if (strm->avail_in >= state->block_len * strm->rsi) {
427
            state->get_rsi(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
428
            state->blocks_avail = strm->rsi - 1;
429

430
            if (strm->flags & AEC_DATA_PREPROCESS) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
431
                state->preprocess(strm);
432
433
                state->ref = 1;
            }
434
            return m_check_zero_block(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
435
        } else {
436
            state->i = 0;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
437
            state->mode = m_get_rsi_resumable;
438
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
439
    } else {
440
        state->ref = 0;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
441
        state->block += strm->block_size;
442
443
        state->blocks_avail--;
        return m_check_zero_block(strm);
444
    }
445
    return M_CONTINUE;
446
447
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
448
static int m_get_rsi_resumable(struct aec_stream *strm)
449
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
450
451
452
453
454
455
456
    /**
       Get RSI while input buffer is short.

       Let user provide more input. Once we got all input pad buffer
       to full RSI.
    */

457
    int j;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
458
459
    struct internal_state *state = strm->state;

460
461
    do {
        if (strm->avail_in > 0) {
462
            state->data_raw[state->i] = state->get_sample(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
463
        } else {
464
465
466
            if (state->flush == AEC_FLUSH) {
                if (state->i > 0) {
                    for (j = state->i; j < strm->rsi * strm->block_size; j++)
467
                        state->data_raw[j] = state->data_raw[state->i - 1];
468
469
470
471
472
473
474
                    state->i = strm->rsi * strm->block_size;
                } else {
                    if (state->zero_blocks) {
                        state->mode = m_encode_zero;
                        return M_CONTINUE;
                    }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
475
                    emit(state, 0, state->bits);
476
                    if (state->direct_out == 0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
477
                        *strm->next_out++ = *state->cds;
478
479
480
481
482
483
484
                    strm->avail_out--;
                    strm->total_out++;

                    return M_EXIT;
                }
            } else {
                return M_EXIT;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
485
            }
486
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
487
    } while (++state->i < strm->rsi * strm->block_size);
488

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
489
    state->blocks_avail = strm->rsi - 1;
490
    if (strm->flags & AEC_DATA_PREPROCESS) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
491
        state->preprocess(strm);
492
493
        state->ref = 1;
    }
494
495

    return m_check_zero_block(strm);
496
497
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
498
static int m_check_zero_block(struct aec_stream *strm)
499
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
500
501
502
503
504
505
506
    /**
       Check if input block is all zero.

       Aggregate consecutive zero blocks until we find !0 or reach the
       end of a segment or RSI.
    */

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
507
    struct internal_state *state = strm->state;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
508
509
    uint32_t *p = state->block + state->ref;
    uint32_t *end = state->block + strm->block_size;
510

511
    while(p < end && *p == 0)
512
513
514
515
516
517
518
519
        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.
             */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
520
            state->block -= strm->block_size;
521
522
523
524
525
526
527
528
529
            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) {
530
            state->zero_ref = state->ref;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
531
            state->zero_ref_sample = state->block[0];
532
        }
533
534
        if (state->blocks_avail == 0
            || (strm->rsi - state->blocks_avail) % 64 == 0) {
535
536
537
538
539
540
541
            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
542
543
544
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
545
static int m_select_code_option(struct aec_stream *strm)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
546
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
547
    /**
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
548
549
       Decide which code option to use.
    */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
550

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
551
552
553
    uint64_t uncomp_len;
    uint64_t split_len;
    uint64_t se_len;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
554
    struct internal_state *state = strm->state;
555

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
556
557
    uncomp_len = (strm->block_size - state->ref)
        * strm->bit_per_sample;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
558
559
    split_len = assess_splitting_option(strm);
    se_len = assess_se_option(split_len, strm);
560

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
561
562
    if (split_len < uncomp_len) {
        if (split_len < se_len)
563
564
565
            return m_encode_splitting(strm);
        else
            return m_encode_se(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
566
    } else {
567
568
569
570
571
572
        if (uncomp_len <= se_len)
            return m_encode_uncomp(strm);
        else
            return m_encode_se(strm);
    }
}
573

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
574
static int m_encode_splitting(struct aec_stream *strm)
575
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
576
    struct internal_state *state = strm->state;
577
    int k = state->k;
578

579
    emit(state, k + 1, state->id_len);
580

581
    if (state->ref)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
582
    {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
583
        emit(state, state->block[0], strm->bit_per_sample);
584
        emitblock_fs_1(strm, k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
585
586
        if (k)
            emitblock_1(strm, k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
587
588
589
    }
    else
    {
590
        emitblock_fs_0(strm, k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
591
592
        if (k)
            emitblock_0(strm, k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
593
    }
594

595
596
    return m_flush_block(strm);
}
597

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
598
static int m_encode_uncomp(struct aec_stream *strm)
599
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
600
    struct internal_state *state = strm->state;
601

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
602
    emit(state, (1U << state->id_len) - 1, state->id_len);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
603
    emitblock_0(strm, strm->bit_per_sample);
604

605
606
    return m_flush_block(strm);
}
607

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
608
static int m_encode_se(struct aec_stream *strm)
609
610
{
    int i;
611
    uint32_t d;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
612
    struct internal_state *state = strm->state;
613

614
615
    emit(state, 1, state->id_len + 1);
    if (state->ref)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
616
        emit(state, state->block[0], strm->bit_per_sample);
617

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
618
    for (i = 0; i < strm->block_size; i+= 2) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
619
620
        d = state->block[i] + state->block[i + 1];
        emitfs(state, d * (d + 1) / 2 + state->block[i + 1]);
621
    }
622

623
624
    return m_flush_block(strm);
}
625

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
626
static int m_encode_zero(struct aec_stream *strm)
627
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
628
    struct internal_state *state = strm->state;
629

630
    emit(state, 0, state->id_len + 1);
631

632
633
    if (state->zero_ref)
        emit(state, state->zero_ref_sample, strm->bit_per_sample);
634

635
636
637
638
639
640
    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);
641

642
643
644
    state->zero_blocks = 0;
    return m_flush_block(strm);
}
645

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
646
static int m_flush_block(struct aec_stream *strm)
647
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
648
649
650
651
652
    /**
       Flush block in direct_out mode by updating counters.

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
656
    if (state->direct_out) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
657
        n = state->cds - strm->next_out;
658
659
660
661
662
663
        strm->next_out += n;
        strm->avail_out -= n;
        strm->total_out += n;
        state->mode = m_get_block;
        return M_CONTINUE;
    }
664

665
    state->i = 0;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
666
    state->mode = m_flush_block_resumable;
667
668
669
    return M_CONTINUE;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
670
static int m_flush_block_resumable(struct aec_stream *strm)
671
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
672
673
674
675
    /**
       Slow and restartable flushing
    */
    struct internal_state *state = strm->state;
676

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
677
    while(state->cds_buf + state->i < state->cds) {
678
679
680
        if (strm->avail_out == 0)
            return M_EXIT;

681
        *strm->next_out++ = state->cds_buf[state->i];
682
683
684
685
686
687
688
689
690
691
692
693
694
        strm->avail_out--;
        strm->total_out++;
        state->i++;
    }
    state->mode = m_get_block;
    return M_CONTINUE;
}

/*
 *
 * API functions
 *
 */
695

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
696
int aec_encode_init(struct aec_stream *strm)
697
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
698
    struct internal_state *state;
699
700

    if (strm->bit_per_sample > 32 || strm->bit_per_sample == 0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
701
        return AEC_CONF_ERROR;
702
703
704
705
706

    if (strm->block_size != 8
        && strm->block_size != 16
        && strm->block_size != 32
        && strm->block_size != 64)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
707
        return AEC_CONF_ERROR;
708
709

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
712
    state = (struct internal_state *)malloc(sizeof(struct internal_state));
713
    if (state == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
714
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
715
716

    memset(state, 0, sizeof(struct internal_state));
717
718
    strm->state = state;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
719
    if (strm->bit_per_sample > 16) {
720
        /* 24/32 input bit settings */
721
722
        state->id_len = 5;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
723
724
        if (strm->bit_per_sample <= 24
            && strm->flags & AEC_DATA_3BYTE) {
725
            state->block_len = 3 * strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
726
            if (strm->flags & AEC_DATA_MSB) {
727
                state->get_sample = get_msb_24;
728
                state->get_rsi = get_rsi_msb_24;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
729
            } else {
730
                state->get_sample = get_lsb_24;
731
                state->get_rsi = get_rsi_lsb_24;
732
            }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
733
        } else {
734
            state->block_len = 4 * strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
735
            if (strm->flags & AEC_DATA_MSB) {
736
                state->get_sample = get_msb_32;
737
                state->get_rsi = get_rsi_msb_32;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
738
            } else {
739
                state->get_sample = get_lsb_32;
740
                state->get_rsi = get_rsi_lsb_32;
741
742
            }
        }
743
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
744
    else if (strm->bit_per_sample > 8) {
745
746
        /* 16 bit settings */
        state->id_len = 4;
747
        state->block_len = 2 * strm->block_size;
748

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
749
        if (strm->flags & AEC_DATA_MSB) {
750
            state->get_sample = get_msb_16;
751
            state->get_rsi = get_rsi_msb_16;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
752
        } else {
753
            state->get_sample = get_lsb_16;
754
            state->get_rsi = get_rsi_lsb_16;
755
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
756
    } else {
757
758
        /* 8 bit settings */
        state->id_len = 3;
759
        state->block_len = strm->block_size;
760
761

        state->get_sample = get_8;
762
        state->get_rsi = get_rsi_8;
763
764
    }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
765
    if (strm->flags & AEC_DATA_SIGNED) {
766
767
        state->xmin = -(1ULL << (strm->bit_per_sample - 1));
        state->xmax = (1ULL << (strm->bit_per_sample - 1)) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
768
        state->preprocess = preprocess_signed;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
769
    } else {
770
771
        state->xmin = 0;
        state->xmax = (1ULL << strm->bit_per_sample) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
772
        state->preprocess = preprocess_unsigned;
773
774
    }

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

777
    state->data_pp = (uint32_t *)malloc(strm->rsi
778
779
                                         * strm->block_size
                                         * sizeof(uint32_t));
780
    if (state->data_pp == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
781
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
782

783
784
785
786
787
788
789
790
791
792
    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;
    }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
793
    state->block = state->data_pp;
794

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
795
    /* Largest possible CDS according to specs */
796
797
798
    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
799
        return AEC_MEM_ERROR;
800

801
802
803
    strm->total_in = 0;
    strm->total_out = 0;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
804
805
806
    state->cds = state->cds_buf;
    *state->cds = 0;
    state->bits = 8;
807
808
    state->mode = m_get_block;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
809
    return AEC_OK;
810
811
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
812
int aec_encode(struct aec_stream *strm, int flush)
813
814
815
816
817
{
    /**
       Finite-state machine implementation of the adaptive entropy
       encoder.
    */
818
    int n;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
819
    struct internal_state *state;
820
821
822
823
824
    state = strm->state;
    state->flush = flush;

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
825
    if (state->direct_out) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
826
        n = state->cds - strm->next_out;
827
828
829
830
        strm->next_out += n;
        strm->avail_out -= n;
        strm->total_out += n;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
831
832
        *state->cds_buf = *state->cds;
        state->cds = state->cds_buf;
833
        state->direct_out = 0;
834
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
835
    return AEC_OK;
836
837
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
838
int aec_encode_end(struct aec_stream *strm)
839
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
840
    struct internal_state *state = strm->state;
841

842
843
844
    if (strm->flags & AEC_DATA_PREPROCESS)
        free(state->data_raw);
    free(state->data_pp);
845
    free(state->cds_buf);
846
    free(state);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
847
    return AEC_OK;
848
}
849

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
850
int aec_buffer_encode(struct aec_stream *strm)
851
852
853
854
855
856
857
858
859
860
861
862
863
{
    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;
}