encode.c 22.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
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

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
    {                                                           \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
89 90 91 92
        /**                                                     \
           Emit the k LSB of a whole block of input data.       \
        */                                                      \
                                                                \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
93 94
        int b;                                                  \
        uint64_t a;                                             \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
95
        struct internal_state *state = strm->state;             \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
96 97
        uint32_t *in = state->block + ref;                      \
        uint32_t *in_end = state->block + strm->block_size;     \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
98
        uint64_t mask = (1ULL << k) - 1;                        \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
99 100
        uint8_t *o = state->cds;                                \
        int p = state->bits;                                    \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
101 102 103
                                                                \
        a = *o;                                                 \
                                                                \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
104
        while(in < in_end) {                                    \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
105 106 107
            a <<= 56;                                           \
            p = (p % 8) + 56;                                   \
                                                                \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
108
            while (p > k && in < in_end) {                      \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
109 110 111 112 113 114 115 116 117 118
                p -= k;                                         \
                a += ((uint64_t)(*in++) & mask) << p;           \
            }                                                   \
                                                                \
            for (b = 56; b > (p & ~7); b -= 8)                  \
                *o++ = a >> b;                                  \
            a >>= b;                                            \
        }                                                       \
                                                                \
        *o = a;                                                 \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
119 120
        state->cds = o;                                         \
        state->bits = p % 8;                                    \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
121 122 123 124 125
    }

EMITBLOCK(0);
EMITBLOCK(1);

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
126
static void preprocess_unsigned(struct aec_stream *strm)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
127
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
128 129 130 131
    /**
       Preprocess RSI of unsigned samples.
    */

132
    int64_t D;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
133
    struct internal_state *state = strm->state;
134 135
    const uint32_t *x = state->data_raw;
    uint32_t *d = state->data_pp;
136 137
    uint32_t xmax = state->xmax;
    uint32_t rsi = strm->rsi * strm->block_size - 1;
138

139
    *d++ = x[0];
140
    while (rsi--) {
141 142 143 144
        if (x[1] >= x[0]) {
            D = x[1] - x[0];
            if (D <= x[0]) {
                *d = 2 * D;
145
            } else {
146
                *d = x[1];
147
            }
148
        } else {
149 150 151
            D = x[0] - x[1];
            if (D <= xmax - x[0]) {
                *d = 2 * D - 1;
152
            } else {
153
                *d = xmax - x[1];
154
            }
155
        }
156
        d++;
157
        x++;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
158 159 160
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
161
static void preprocess_signed(struct aec_stream *strm)
162
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
163 164 165 166
    /**
       Preprocess RSI of signed samples.
    */

167
    int64_t D;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
168
    struct internal_state *state = strm->state;
169 170 171
    uint32_t *d = state->data_pp;
    int32_t *x = (int32_t *)state->data_raw;
    uint64_t m = 1ULL << (strm->bit_per_sample - 1);
172 173 174
    int64_t xmax = state->xmax;
    int64_t xmin = state->xmin;
    uint32_t rsi = strm->rsi * strm->block_size - 1;
175

176 177 178
    *d++ = (uint32_t)x[0];
    x[0] = (x[0] ^ m) - m;

179
    while (rsi--) {
180 181 182 183 184
        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;
185
            else
186
                *d = xmax - x[1];
187
        } else {
188 189 190
            D = (int64_t)x[1] - x[0];
            if (D <= x[0] - xmin)
                *d = 2 * D;
191
            else
192
                *d = x[1] - xmin;
193
        }
194 195
        x++;
        d++;
196
    }
197
}
198

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
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;
}

348 349 350 351 352 353
/*
 *
 * FSM functions
 *
 */

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
354
static int m_get_block(struct aec_stream *strm)
355
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
356 357 358 359 360 361 362
    /**
       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
363
    struct internal_state *state = strm->state;
364

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
365 366
    if (strm->avail_out > state->cds_len) {
        if (!state->direct_out) {
367
            state->direct_out = 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
368 369
            *strm->next_out = *state->cds;
            state->cds = strm->next_out;
370
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
371 372
    } else {
        if (state->zero_blocks == 0 || state->direct_out) {
373
            /* copy leftover from last block */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
374 375
            *state->cds_buf = *state->cds;
            state->cds = state->cds_buf;
376
        }
377
        state->direct_out = 0;
378
    }
379

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
380
    if (state->blocks_avail == 0) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
381
        state->block = state->data_pp;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
382

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
383
        if (strm->avail_in >= state->block_len * strm->rsi) {
384
            state->get_rsi(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
385
            state->blocks_avail = strm->rsi - 1;
386

387
            if (strm->flags & AEC_DATA_PREPROCESS) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
388
                state->preprocess(strm);
389 390
                state->ref = 1;
            }
391
            return m_check_zero_block(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
392
        } else {
393
            state->i = 0;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
394
            state->mode = m_get_rsi_resumable;
395
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
396
    } else {
397
        state->ref = 0;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
398
        state->block += strm->block_size;
399 400
        state->blocks_avail--;
        return m_check_zero_block(strm);
401
    }
402
    return M_CONTINUE;
403 404
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
405
static int m_get_rsi_resumable(struct aec_stream *strm)
406
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
407 408 409 410 411 412 413
    /**
       Get RSI while input buffer is short.

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

414
    int j;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
415 416
    struct internal_state *state = strm->state;

417 418
    do {
        if (strm->avail_in > 0) {
419
            state->data_raw[state->i] = state->get_sample(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
420
        } else {
421 422 423
            if (state->flush == AEC_FLUSH) {
                if (state->i > 0) {
                    for (j = state->i; j < strm->rsi * strm->block_size; j++)
424
                        state->data_raw[j] = state->data_raw[state->i - 1];
425 426 427 428 429 430 431
                    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
432
                    emit(state, 0, state->bits);
433
                    if (state->direct_out == 0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
434
                        *strm->next_out++ = *state->cds;
435 436 437 438 439 440 441
                    strm->avail_out--;
                    strm->total_out++;

                    return M_EXIT;
                }
            } else {
                return M_EXIT;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
442
            }
443
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
444
    } while (++state->i < strm->rsi * strm->block_size);
445

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
446
    state->blocks_avail = strm->rsi - 1;
447
    if (strm->flags & AEC_DATA_PREPROCESS) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
448
        state->preprocess(strm);
449 450
        state->ref = 1;
    }
451 452

    return m_check_zero_block(strm);
453 454
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
455
static int m_check_zero_block(struct aec_stream *strm)
456
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
457 458 459 460 461 462 463
    /**
       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
464
    struct internal_state *state = strm->state;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
465 466
    uint32_t *p = state->block + state->ref;
    uint32_t *end = state->block + strm->block_size;
467

468
    while(p < end && *p == 0)
469 470 471 472 473 474 475 476
        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
477
            state->block -= strm->block_size;
478 479 480 481 482 483 484 485 486
            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) {
487
            state->zero_ref = state->ref;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
488
            state->zero_ref_sample = state->block[0];
489
        }
490 491
        if (state->blocks_avail == 0
            || (strm->rsi - state->blocks_avail) % 64 == 0) {
492 493 494 495 496 497 498
            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
499 500 501
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
502
static int m_select_code_option(struct aec_stream *strm)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
503
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
504
    /**
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
505 506
       Decide which code option to use.
    */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
507

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
508 509 510
    uint64_t uncomp_len;
    uint64_t split_len;
    uint64_t se_len;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
511
    struct internal_state *state = strm->state;
512

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
513 514
    uncomp_len = (strm->block_size - state->ref)
        * strm->bit_per_sample;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
515 516
    split_len = assess_splitting_option(strm);
    se_len = assess_se_option(split_len, strm);
517

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
518 519
    if (split_len < uncomp_len) {
        if (split_len < se_len)
520 521 522
            return m_encode_splitting(strm);
        else
            return m_encode_se(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
523
    } else {
524 525 526 527 528 529
        if (uncomp_len <= se_len)
            return m_encode_uncomp(strm);
        else
            return m_encode_se(strm);
    }
}
530

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
531
static int m_encode_splitting(struct aec_stream *strm)
532 533
{
    int i;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
534
    struct internal_state *state = strm->state;
535
    int k = state->k;
536

537
    emit(state, k + 1, state->id_len);
538

539
    if (state->ref)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
540
    {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
541
        emit(state, state->block[0], strm->bit_per_sample);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
542
        for (i = 1; i < strm->block_size; i++)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
543
            emitfs(state, state->block[i] >> k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
544 545
        if (k)
            emitblock_1(strm, k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
546 547 548 549
    }
    else
    {
        for (i = 0; i < strm->block_size; i++)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
550
            emitfs(state, state->block[i] >> k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
551 552
        if (k)
            emitblock_0(strm, k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
553
    }
554

555 556
    return m_flush_block(strm);
}
557

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
558
static int m_encode_uncomp(struct aec_stream *strm)
559
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
560
    struct internal_state *state = strm->state;
561

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
562
    emit(state, (1U << state->id_len) - 1, state->id_len);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
563
    emitblock_0(strm, strm->bit_per_sample);
564

565 566
    return m_flush_block(strm);
}
567

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
568
static int m_encode_se(struct aec_stream *strm)
569 570
{
    int i;
571
    uint32_t d;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
572
    struct internal_state *state = strm->state;
573

574 575
    emit(state, 1, state->id_len + 1);
    if (state->ref)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
576
        emit(state, state->block[0], strm->bit_per_sample);
577

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
578
    for (i = 0; i < strm->block_size; i+= 2) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
579 580
        d = state->block[i] + state->block[i + 1];
        emitfs(state, d * (d + 1) / 2 + state->block[i + 1]);
581
    }
582

583 584
    return m_flush_block(strm);
}
585

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
586
static int m_encode_zero(struct aec_stream *strm)
587
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
588
    struct internal_state *state = strm->state;
589

590
    emit(state, 0, state->id_len + 1);
591

592 593
    if (state->zero_ref)
        emit(state, state->zero_ref_sample, strm->bit_per_sample);
594

595 596 597 598 599 600
    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);
601

602 603 604
    state->zero_blocks = 0;
    return m_flush_block(strm);
}
605

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
606
static int m_flush_block(struct aec_stream *strm)
607
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
608 609 610 611 612
    /**
       Flush block in direct_out mode by updating counters.

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
616
    if (state->direct_out) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
617
        n = state->cds - strm->next_out;
618 619 620 621 622 623
        strm->next_out += n;
        strm->avail_out -= n;
        strm->total_out += n;
        state->mode = m_get_block;
        return M_CONTINUE;
    }
624

625
    state->i = 0;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
626
    state->mode = m_flush_block_resumable;
627 628 629
    return M_CONTINUE;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
630
static int m_flush_block_resumable(struct aec_stream *strm)
631
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
632 633 634 635
    /**
       Slow and restartable flushing
    */
    struct internal_state *state = strm->state;
636

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
637
    while(state->cds_buf + state->i < state->cds) {
638 639 640
        if (strm->avail_out == 0)
            return M_EXIT;

641
        *strm->next_out++ = state->cds_buf[state->i];
642 643 644 645 646 647 648 649 650 651 652 653 654
        strm->avail_out--;
        strm->total_out++;
        state->i++;
    }
    state->mode = m_get_block;
    return M_CONTINUE;
}

/*
 *
 * API functions
 *
 */
655

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
656
int aec_encode_init(struct aec_stream *strm)
657
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
658
    struct internal_state *state;
659 660

    if (strm->bit_per_sample > 32 || strm->bit_per_sample == 0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
661
        return AEC_CONF_ERROR;
662 663 664 665 666

    if (strm->block_size != 8
        && strm->block_size != 16
        && strm->block_size != 32
        && strm->block_size != 64)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
667
        return AEC_CONF_ERROR;
668 669

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
672
    state = (struct internal_state *)malloc(sizeof(struct internal_state));
673
    if (state == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
674
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
675 676

    memset(state, 0, sizeof(struct internal_state));
677 678
    strm->state = state;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
679
    if (strm->bit_per_sample > 16) {
680
        /* 24/32 input bit settings */
681 682
        state->id_len = 5;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
683 684
        if (strm->bit_per_sample <= 24
            && strm->flags & AEC_DATA_3BYTE) {
685
            state->block_len = 3 * strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
686
            if (strm->flags & AEC_DATA_MSB) {
687
                state->get_sample = get_msb_24;
688
                state->get_rsi = get_rsi_msb_24;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
689
            } else {
690
                state->get_sample = get_lsb_24;
691
                state->get_rsi = get_rsi_lsb_24;
692
            }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
693
        } else {
694
            state->block_len = 4 * strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
695
            if (strm->flags & AEC_DATA_MSB) {
696
                state->get_sample = get_msb_32;
697
                state->get_rsi = get_rsi_msb_32;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
698
            } else {
699
                state->get_sample = get_lsb_32;
700
                state->get_rsi = get_rsi_lsb_32;
701 702
            }
        }
703
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
704
    else if (strm->bit_per_sample > 8) {
705 706
        /* 16 bit settings */
        state->id_len = 4;
707
        state->block_len = 2 * strm->block_size;
708

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
709
        if (strm->flags & AEC_DATA_MSB) {
710
            state->get_sample = get_msb_16;
711
            state->get_rsi = get_rsi_msb_16;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
712
        } else {
713
            state->get_sample = get_lsb_16;
714
            state->get_rsi = get_rsi_lsb_16;
715
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
716
    } else {
717 718
        /* 8 bit settings */
        state->id_len = 3;
719
        state->block_len = strm->block_size;
720 721

        state->get_sample = get_8;
722
        state->get_rsi = get_rsi_8;
723 724
    }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
725
    if (strm->flags & AEC_DATA_SIGNED) {
726 727
        state->xmin = -(1ULL << (strm->bit_per_sample - 1));
        state->xmax = (1ULL << (strm->bit_per_sample - 1)) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
728
        state->preprocess = preprocess_signed;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
729
    } else {
730 731
        state->xmin = 0;
        state->xmax = (1ULL << strm->bit_per_sample) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
732
        state->preprocess = preprocess_unsigned;
733 734
    }

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

737
    state->data_pp = (uint32_t *)malloc(strm->rsi
738 739
                                         * strm->block_size
                                         * sizeof(uint32_t));
740
    if (state->data_pp == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
741
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
742

743 744 745 746 747 748 749 750 751 752
    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
753
    state->block = state->data_pp;
754

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
755
    /* Largest possible CDS according to specs */
756 757 758
    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
759
        return AEC_MEM_ERROR;
760

761 762 763
    strm->total_in = 0;
    strm->total_out = 0;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
764 765 766
    state->cds = state->cds_buf;
    *state->cds = 0;
    state->bits = 8;
767 768
    state->mode = m_get_block;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
769
    return AEC_OK;
770 771
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
772
int aec_encode(struct aec_stream *strm, int flush)
773 774 775 776 777
{
    /**
       Finite-state machine implementation of the adaptive entropy
       encoder.
    */
778
    int n;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
779
    struct internal_state *state;
780 781 782 783 784
    state = strm->state;
    state->flush = flush;

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
785
    if (state->direct_out) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
786
        n = state->cds - strm->next_out;
787 788 789 790
        strm->next_out += n;
        strm->avail_out -= n;
        strm->total_out += n;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
791 792
        *state->cds_buf = *state->cds;
        state->cds = state->cds_buf;
793
        state->direct_out = 0;
794
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
795
    return AEC_OK;
796 797
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
798
int aec_encode_end(struct aec_stream *strm)
799
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
800
    struct internal_state *state = strm->state;
801

802 803 804
    if (strm->flags & AEC_DATA_PREPROCESS)
        free(state->data_raw);
    free(state->data_pp);
805
    free(state->cds_buf);
806
    free(state);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
807
    return AEC_OK;
808
}
809

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
810
int aec_buffer_encode(struct aec_stream *strm)
811 812 813 814 815 816 817 818 819 820 821 822 823
{
    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;
}