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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

EMITBLOCK(0);
EMITBLOCK(1);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return m_check_zero_block(strm);
278 279
}

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

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

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

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

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

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

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

    return fs;
}
351

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

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

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

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

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

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

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

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

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

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

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

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

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

    len = 1;

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

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

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

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

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

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

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

504 505
    return m_flush_block(strm);
}
506

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

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

514 515
    return m_flush_block(strm);
}
516

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

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

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

532 533
    return m_flush_block(strm);
}
534

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

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

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

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

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

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

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

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

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

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

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

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

/*
 *
 * API functions
 *
 */
604

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    state->block_p = state->data_pp;
703

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

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

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

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

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

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

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

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

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

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

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

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

    aec_encode_end(strm);
    return status;
}