encode.c 20.6 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 125
    int64_t prev, d, t;
    uint32_t *buf;
126
    uint32_t xmax, s, rsi;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
127
    struct internal_state *state = strm->state;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
128

129 130 131 132 133 134 135
    buf = state->block_buf;
    prev = *buf++;
    xmax = state->xmax;
    rsi = strm->rsi * strm->block_size - 1;

    while (rsi--) {
        s = *buf < prev;
136
        if (s) {
137
            d = prev - *buf;
138 139
            t = xmax - prev;
        } else {
140
            d = *buf - prev;
141 142 143
            t = prev;
        }

144 145 146 147 148 149
        prev = *buf;
        if (d <= t)
            *buf = 2 * d - s;
        else
            *buf = t + d;
        buf++;
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 156 157
    int64_t prev, d, t, v, xmax, xmin;
    uint32_t *buf;
    uint32_t s, rsi, m;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
158
    struct internal_state *state = strm->state;
159

160
    buf = state->block_buf;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
161
    m = 64 - strm->bit_per_sample;
162 163 164 165 166 167 168 169
    prev = (((int64_t)*buf++) << m) >> m;
    xmax = state->xmax;
    xmin = state->xmin;
    rsi = strm->rsi * strm->block_size - 1;

    while (rsi--) {
        v = (((int64_t)*buf) << m) >> m;
        s = v < prev;
170
        if (s) {
171
            d = prev - v;
172 173
            t = xmax - prev;
        } else {
174
            d = v - prev;
175 176 177
            t = prev - xmin;
        }

178 179 180 181 182 183
        prev = v;
        if (d <= t)
            *buf = 2 * d - s;
        else
            *buf = t + d;
        buf++;
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 214
        state->ref = 1;
        state->block_p = state->block_buf;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
215

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
220
            if (strm->flags & AEC_DATA_PREPROCESS)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
221
                state->preprocess(strm);
222

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 244
    do {
        if (strm->avail_in > 0) {
            state->block_buf[state->i] = state->get_sample(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
245
        } else {
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
            if (state->flush == AEC_FLUSH) {
                if (state->i > 0) {
                    for (j = state->i; j < strm->rsi * strm->block_size; j++)
                        state->block_buf[j] = state->block_buf[state->i - 1];
                    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;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
272
    if (strm->flags & AEC_DATA_PREPROCESS)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
273
        state->preprocess(strm);
274 275

    return m_check_zero_block(strm);
276 277
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
278
static int m_check_zero_block(struct aec_stream *strm)
279
{
280
    int i;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
281
    struct internal_state *state = strm->state;
282 283

    i = state->ref;
284
    while(i < strm->block_size && state->block_p[i] == 0)
285 286
        i++;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
287 288
    if (i == strm->block_size) {
        if (state->zero_blocks == 0) {
289
            state->zero_ref = state->ref;
290
            state->zero_ref_sample = state->block_p[0];
291
        }
292

293
        state->zero_blocks++;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
294

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
295
        if ((strm->rsi - state->blocks_avail) % 64 == 0) {
296 297 298 299 300 301 302
            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
303
    } else if (state->zero_blocks) {
304 305 306 307
        /* The current block isn't zero but we have to emit a previous
         * zero block first. The current block will be handled
         * later.
         */
308 309
        state->block_p -= strm->block_size;
        state->blocks_avail++;
310 311
        state->mode = m_encode_zero;
        return M_CONTINUE;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
312
    }
313 314
    state->mode = m_select_code_option;
    return M_CONTINUE;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
315 316
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
317
static uint64_t block_fs(struct aec_stream *strm, int k)
318
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
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
    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)
        for (j = 1; j < strm->block_size / 8; j++)
            fs +=
                (uint64_t)(state->block_p[j * 8 + 0] >> k)
                + (uint64_t)(state->block_p[j * 8 + 1] >> k)
                + (uint64_t)(state->block_p[j * 8 + 2] >> k)
                + (uint64_t)(state->block_p[j * 8 + 3] >> k)
                + (uint64_t)(state->block_p[j * 8 + 4] >> k)
                + (uint64_t)(state->block_p[j * 8 + 5] >> k)
                + (uint64_t)(state->block_p[j * 8 + 6] >> k)
                + (uint64_t)(state->block_p[j * 8 + 7] >> k);

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

    return fs;
}
348

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
349 350
static int count_splitting_option(struct aec_stream *strm)
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
    /**
       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
366 367 368 369 370 371 372 373
       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
374 375 376 377
     */

    int k, k_min;
    int this_bs; /* Block size of current block */
378
    int no_turn; /* 1 if we shouldn't reverse */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
379 380 381 382 383
    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
384
    struct internal_state *state = strm->state;
385

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

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

        if (len < len_min) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
397
            if (len_min < UINT64_MAX)
398
                no_turn = 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
399

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
400
            len_min = len;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
401
            k_min = k;
402

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
428 429 430 431 432 433 434 435 436 437 438 439
    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
440 441
        d = (uint64_t)state->block_p[i]
            + (uint64_t)state->block_p[i + 1];
442
        /* we have to worry about overflow here */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
443 444
        if (d > limit) {
            len = UINT64_MAX;
445
            break;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
446 447 448
        } else {
            len += d * (d + 1) / 2
                + (uint64_t)state->block_p[i + 1];
449 450
        }
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
451 452 453 454 455 456 457
    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;
458

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
459 460 461 462
    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);
463

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

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

483
    emit(state, k + 1, state->id_len);
484

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

499 500
    return m_flush_block(strm);
}
501

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
502
static int m_encode_uncomp(struct aec_stream *strm)
503
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
504
    struct internal_state *state = strm->state;
505

506
    emit(state, (1 << state->id_len) - 1, state->id_len);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
507
    emitblock_0(strm, strm->bit_per_sample);
508

509 510
    return m_flush_block(strm);
}
511

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
512
static int m_encode_se(struct aec_stream *strm)
513 514
{
    int i;
515
    uint32_t d;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
516
    struct internal_state *state = strm->state;
517

518 519
    emit(state, 1, state->id_len + 1);
    if (state->ref)
520
        emit(state, state->block_p[0], strm->bit_per_sample);
521

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
522
    for (i = 0; i < strm->block_size; i+= 2) {
523 524
        d = state->block_p[i] + state->block_p[i + 1];
        emitfs(state, d * (d + 1) / 2 + state->block_p[i + 1]);
525
    }
526

527 528
    return m_flush_block(strm);
}
529

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
530
static int m_encode_zero(struct aec_stream *strm)
531
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
532
    struct internal_state *state = strm->state;
533

534
    emit(state, 0, state->id_len + 1);
535

536 537
    if (state->zero_ref)
        emit(state, state->zero_ref_sample, strm->bit_per_sample);
538

539 540 541 542 543 544
    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);
545

546 547 548
    state->zero_blocks = 0;
    return m_flush_block(strm);
}
549

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
550
static int m_flush_block(struct aec_stream *strm)
551
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
552 553 554 555 556
    /**
       Flush block in direct_out mode by updating counters.

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
560
    if (state->direct_out) {
561
        n = state->cds_p - strm->next_out;
562 563 564 565 566 567
        strm->next_out += n;
        strm->avail_out -= n;
        strm->total_out += n;
        state->mode = m_get_block;
        return M_CONTINUE;
    }
568

569 570 571 572 573
    state->i = 0;
    state->mode = m_flush_block_cautious;
    return M_CONTINUE;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
574
static int m_flush_block_cautious(struct aec_stream *strm)
575
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
576 577 578 579
    /**
       Slow and restartable flushing
    */
    struct internal_state *state = strm->state;
580

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
581
    while(state->cds_buf + state->i < state->cds_p) {
582 583 584
        if (strm->avail_out == 0)
            return M_EXIT;

585
        *strm->next_out++ = state->cds_buf[state->i];
586 587 588 589 590 591 592 593 594 595 596 597 598
        strm->avail_out--;
        strm->total_out++;
        state->i++;
    }
    state->mode = m_get_block;
    return M_CONTINUE;
}

/*
 *
 * API functions
 *
 */
599

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
600
int aec_encode_init(struct aec_stream *strm)
601
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
602
    struct internal_state *state;
603 604

    if (strm->bit_per_sample > 32 || strm->bit_per_sample == 0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
605
        return AEC_CONF_ERROR;
606 607 608 609 610

    if (strm->block_size != 8
        && strm->block_size != 16
        && strm->block_size != 32
        && strm->block_size != 64)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
611
        return AEC_CONF_ERROR;
612 613

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
616
    state = (struct internal_state *)malloc(sizeof(struct internal_state));
617
    if (state == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
618
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
619 620

    memset(state, 0, sizeof(struct internal_state));
621 622
    strm->state = state;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
623
    if (strm->bit_per_sample > 16) {
624
        /* 24/32 input bit settings */
625 626
        state->id_len = 5;

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

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

        state->get_sample = get_8;
666
        state->get_rsi = get_rsi_8;
667 668
    }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
669
    if (strm->flags & AEC_DATA_SIGNED) {
670 671
        state->xmin = -(1ULL << (strm->bit_per_sample - 1));
        state->xmax = (1ULL << (strm->bit_per_sample - 1)) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
672
        state->preprocess = preprocess_signed;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
673
    } else {
674 675
        state->xmin = 0;
        state->xmax = (1ULL << strm->bit_per_sample) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
676
        state->preprocess = preprocess_unsigned;
677 678
    }

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

681 682 683
    state->block_buf = (uint32_t *)malloc(strm->rsi
                                         * strm->block_size
                                         * sizeof(uint32_t));
684
    if (state->block_buf == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
685
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
686

687
    state->block_p = state->block_buf;
688

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
689
    /* Largest possible CDS according to specs */
690 691 692
    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
693
        return AEC_MEM_ERROR;
694

695 696 697
    strm->total_in = 0;
    strm->total_out = 0;

698 699 700
    state->cds_p = state->cds_buf;
    *state->cds_p = 0;
    state->bit_p = 8;
701 702
    state->mode = m_get_block;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
703
    return AEC_OK;
704 705
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
706
int aec_encode(struct aec_stream *strm, int flush)
707 708 709 710 711
{
    /**
       Finite-state machine implementation of the adaptive entropy
       encoder.
    */
712
    int n;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
713
    struct internal_state *state;
714 715 716 717 718
    state = strm->state;
    state->flush = flush;

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
719
    if (state->direct_out) {
720 721 722 723 724 725 726 727
        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;
728
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
729
    return AEC_OK;
730 731
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
732
int aec_encode_end(struct aec_stream *strm)
733
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
734
    struct internal_state *state = strm->state;
735

736 737
    free(state->block_buf);
    free(state->cds_buf);
738
    free(state);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
739
    return AEC_OK;
740
}