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

#include <stdio.h>
#include <stdlib.h>
13
#include <unistd.h>
14 15 16
#include <inttypes.h>
#include <string.h>

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
17 18 19
#include "libaec.h"
#include "encode.h"
#include "encode_accessors.h"
20

21
/* Marker for Remainder Of Segment condition in zero block encoding */
22
#define ROS -1
23 24 25

#define MIN(a, b) (((a) < (b))? (a): (b))

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
26 27 28 29 30 31 32 33 34 35 36 37 38
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
39
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
40 41 42 43 44
    /**
       Emit sequence of bits.
     */

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

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

56 57
        state->bit_p = 8 - bits;
        *state->cds_p = data << state->bit_p;
58
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
59 60
}

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

66 67
       fs zero bits followed by one 1 bit.
     */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
68

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
82
#define EMITBLOCK(ref)                                          \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
83 84
    static inline void emitblock_##ref(struct aec_stream *strm, \
                                       int k)                   \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
85 86 87
    {                                                           \
        int b;                                                  \
        uint64_t a;                                             \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
88
        struct internal_state *state = strm->state;             \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
89 90 91 92 93 94 95 96
        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
97
        while(in < in_end) {                                    \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
98 99 100
            a <<= 56;                                           \
            p = (p % 8) + 56;                                   \
                                                                \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
101
            while (p > k && in < in_end) {                      \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
102 103 104 105 106 107 108 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;                                                 \
        state->cds_p = o;                                       \
        state->bit_p = p % 8;                                   \
    }

EMITBLOCK(0);
EMITBLOCK(1);

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
119
static void preprocess_unsigned(struct aec_stream *strm)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
120 121
{
    int i;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
122
    int64_t theta, Delta, prev;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
123
    struct internal_state *state = strm->state;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
124

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
125
    prev = state->block_buf[0];
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
126

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
127
    for (i = 1; i < strm->rsi * strm->block_size; i++) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
128 129 130
        theta = MIN(prev, state->xmax - prev);
        Delta = (int64_t)state->block_buf[i] - prev;
        prev = state->block_buf[i];
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
131

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
132
        if (0 <= Delta && Delta <= theta) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
133
            state->block_buf[i] = 2 * Delta;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
134
        } else if (-theta <= Delta && Delta < 0) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
135 136
            state->block_buf[i] = 2
                * (Delta < 0 ? -(uint64_t)Delta : Delta) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
137
        } else {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
138 139
            state->block_buf[i] = theta
                + (Delta < 0 ? -(uint64_t)Delta : Delta);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
140 141 142 143
        }
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
144
static void preprocess_signed(struct aec_stream *strm)
145
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
146 147
    int i, m;
    int64_t theta, Delta, prev, sample;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
148
    struct internal_state *state = strm->state;
149

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
150 151
    m = 64 - strm->bit_per_sample;
    prev = ((int64_t)state->block_buf[0] << m) >> m;
152

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
153
    for (i = 1; i < strm->rsi * strm->block_size; i++) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
154 155 156 157 158
        theta = MIN(prev - state->xmin, state->xmax - prev);
        sample = ((int64_t)state->block_buf[i] << m) >> m;
        Delta = sample - prev;
        prev = sample;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
159
        if (0 <= Delta && Delta <= theta) {
160
            state->block_buf[i] = 2 * Delta;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
161
        } else if (-theta <= Delta && Delta < 0) {
162 163
            state->block_buf[i] = 2
                * (Delta < 0 ? -(uint64_t)Delta : Delta) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
164
        } else {
165 166
            state->block_buf[i] = theta
                + (Delta < 0 ? -(uint64_t)Delta : Delta);
167
        }
168
    }
169
}
170

171 172 173 174 175 176
/*
 *
 * FSM functions
 *
 */

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
177
static int m_get_block(struct aec_stream *strm)
178
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
179
    struct internal_state *state = strm->state;
180

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
181 182
    if (strm->avail_out > state->cds_len) {
        if (!state->direct_out) {
183 184 185
            state->direct_out = 1;
            *strm->next_out = *state->cds_p;
            state->cds_p = strm->next_out;
186
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
187 188
    } else {
        if (state->zero_blocks == 0 || state->direct_out) {
189
            /* copy leftover from last block */
190 191
            *state->cds_buf = *state->cds_p;
            state->cds_p = state->cds_buf;
192
        }
193
        state->direct_out = 0;
194
    }
195

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
196
    if (state->blocks_avail == 0) {
197 198 199
        state->ref = 1;
        state->blocks_avail = strm->rsi - 1;
        state->block_p = state->block_buf;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
200

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
201
        if (strm->avail_in >= state->block_len * strm->rsi) {
202
            state->get_block(strm);
203

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
204
            if (strm->flags & AEC_DATA_PREPROCESS)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
205
                state->preprocess(strm);
206

207
            return m_check_zero_block(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
208
        } else {
209 210 211
            state->i = 0;
            state->mode = m_get_block_cautious;
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
212
    } else {
213 214 215 216
        state->ref = 0;
        state->block_p += strm->block_size;
        state->blocks_avail--;
        return m_check_zero_block(strm);
217
    }
218
    return M_CONTINUE;
219 220
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
221
static int input_empty(struct aec_stream *strm)
222
{
223
    int j;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
224 225 226 227 228 229 230 231 232 233 234 235
    struct internal_state *state = strm->state;

    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;
            }
236

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
237 238 239 240 241
            emit(state, 0, state->bit_p);
            if (state->direct_out == 0)
                *strm->next_out++ = *state->cds_p;
            strm->avail_out--;
            strm->total_out++;
242

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
243
            return M_EXIT;
244 245
        }
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259

    return M_EXIT;
}

static int m_get_block_cautious(struct aec_stream *strm)
{
    struct internal_state *state = strm->state;

    do {
        if (strm->avail_in > 0)
            state->block_buf[state->i] = state->get_sample(strm);
        else
            return input_empty(strm);
    } while (++state->i < strm->rsi * strm->block_size);
260

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
261
    if (strm->flags & AEC_DATA_PREPROCESS)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
262
        state->preprocess(strm);
263 264

    return m_check_zero_block(strm);
265 266
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
267
static int m_check_zero_block(struct aec_stream *strm)
268
{
269
    int i;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
270
    struct internal_state *state = strm->state;
271 272

    i = state->ref;
273
    while(i < strm->block_size && state->block_p[i] == 0)
274 275
        i++;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
276 277
    if (i == strm->block_size) {
        if (state->zero_blocks == 0) {
278
            state->zero_ref = state->ref;
279
            state->zero_ref_sample = state->block_p[0];
280
        }
281

282
        state->zero_blocks++;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
283

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
284
        if ((strm->rsi - state->blocks_avail) % 64 == 0) {
285 286 287 288 289 290 291
            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
292
    } else if (state->zero_blocks) {
293 294 295 296
        /* The current block isn't zero but we have to emit a previous
         * zero block first. The current block will be handled
         * later.
         */
297 298
        state->block_p -= strm->block_size;
        state->blocks_avail++;
299 300
        state->mode = m_encode_zero;
        return M_CONTINUE;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
301
    }
302 303
    state->mode = m_select_code_option;
    return M_CONTINUE;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
304 305
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
306
static uint64_t block_fs(struct aec_stream *strm, int k)
307
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
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
    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;
}
337

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
338 339 340 341 342
static int count_splitting_option(struct aec_stream *strm)
{
    int i, k, this_bs, looked_bothways, direction;
    uint64_t len, len_min, fs_len;
    struct internal_state *state = strm->state;
343

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
344 345
    this_bs = strm->block_size - state->ref;
    len_min = UINT64_MAX;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
346
    i = k = state->k;
347 348
    direction = 1;
    looked_bothways = 0;
349

350
    /* Starting with splitting position of last block. Look left and
351 352
     * possibly right to find new minimum.
     */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
353 354 355 356 357 358
    for (;;) {
        fs_len = block_fs(strm, i);
        len = fs_len + this_bs * (i + 1);

        if (len < len_min) {
            if (len_min < UINT64_MAX) {
359
                /* We are moving towards the minimum so it cant be in
360 361
                 * the other direction.
                 */
362
                looked_bothways = 1;
363
            }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
364
            len_min = len;
365
            k = i;
366

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
367 368
            if (direction == 1) {
                if (fs_len < this_bs) {
369
                    /* Next can't get better because what we lose by
370 371 372 373
                     * additional uncompressed bits isn't compensated
                     * by a smaller FS part. Vice versa if we are
                     * coming from the other direction.
                     */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
374
                    if (looked_bothways) {
375
                        break;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
376
                    } else {
377 378 379
                        direction = -direction;
                        looked_bothways = 1;
                        i = state->k;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
380
                    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
381 382
                } else {
                    while (fs_len > 5 * this_bs) {
383 384 385
                        i++;
                        fs_len /= 5;
                    }
386
                }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
387
            } else if (fs_len > this_bs) {
388
                /* Since we started looking the other way there is no
389 390
                 * need to turn back.
                 */
391 392
                break;
            }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
393
        } else {
394 395 396
            /* Stop looking for better option if we don't see any
             * improvement.
             */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
397 398 399 400 401 402 403
            if (looked_bothways) {
                break;
            } else {
                direction = -direction;
                looked_bothways = 1;
                i = state->k;
            }
404 405
        }
        if (i + direction < 0
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
406
            || i + direction >= strm->bit_per_sample - 2) {
407 408
            if (looked_bothways)
                break;
409

410 411 412 413 414 415 416
            direction = -direction;
            looked_bothways = 1;
            i = state->k;
        }
        i += direction;
    }
    state->k = k;
417

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
418 419 420 421 422 423 424 425 426 427 428 429
    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
430 431
        d = (uint64_t)state->block_p[i]
            + (uint64_t)state->block_p[i + 1];
432
        /* we have to worry about overflow here */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
433 434
        if (d > limit) {
            len = UINT64_MAX;
435
            break;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
436 437 438
        } else {
            len += d * (d + 1) / 2
                + (uint64_t)state->block_p[i + 1];
439 440
        }
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
441 442 443 444 445 446 447
    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;
448

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
449 450 451 452
    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);
453

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
454 455
    if (split_len < uncomp_len) {
        if (split_len < se_len)
456 457 458
            return m_encode_splitting(strm);
        else
            return m_encode_se(strm);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
459
    } else {
460 461 462 463 464 465
        if (uncomp_len <= se_len)
            return m_encode_uncomp(strm);
        else
            return m_encode_se(strm);
    }
}
466

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
467
static int m_encode_splitting(struct aec_stream *strm)
468 469
{
    int i;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
470
    struct internal_state *state = strm->state;
471
    int k = state->k;
472

473
    emit(state, k + 1, state->id_len);
474

475
    if (state->ref)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
476
    {
477
        emit(state, state->block_p[0], strm->bit_per_sample);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
478 479 480 481 482 483 484 485 486 487
        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);
    }
488

489 490
    return m_flush_block(strm);
}
491

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
492
static int m_encode_uncomp(struct aec_stream *strm)
493
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
494
    struct internal_state *state = strm->state;
495

496
    emit(state, (1 << state->id_len) - 1, state->id_len);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
497
    emitblock_0(strm, strm->bit_per_sample);
498

499 500
    return m_flush_block(strm);
}
501

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
502
static int m_encode_se(struct aec_stream *strm)
503 504
{
    int i;
505
    uint32_t d;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
506
    struct internal_state *state = strm->state;
507

508 509
    emit(state, 1, state->id_len + 1);
    if (state->ref)
510
        emit(state, state->block_p[0], strm->bit_per_sample);
511

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
512
    for (i = 0; i < strm->block_size; i+= 2) {
513 514
        d = state->block_p[i] + state->block_p[i + 1];
        emitfs(state, d * (d + 1) / 2 + state->block_p[i + 1]);
515
    }
516

517 518
    return m_flush_block(strm);
}
519

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
520
static int m_encode_zero(struct aec_stream *strm)
521
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
522
    struct internal_state *state = strm->state;
523

524
    emit(state, 0, state->id_len + 1);
525

526 527
    if (state->zero_ref)
        emit(state, state->zero_ref_sample, strm->bit_per_sample);
528

529 530 531 532 533 534
    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);
535

536 537 538
    state->zero_blocks = 0;
    return m_flush_block(strm);
}
539

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
540
static int m_flush_block(struct aec_stream *strm)
541
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
542 543 544 545 546
    /**
       Flush block in direct_out mode by updating counters.

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
550
    if (state->direct_out) {
551
        n = state->cds_p - strm->next_out;
552 553 554 555 556 557
        strm->next_out += n;
        strm->avail_out -= n;
        strm->total_out += n;
        state->mode = m_get_block;
        return M_CONTINUE;
    }
558

559 560 561 562 563
    state->i = 0;
    state->mode = m_flush_block_cautious;
    return M_CONTINUE;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
564
static int m_flush_block_cautious(struct aec_stream *strm)
565
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
566 567 568 569
    /**
       Slow and restartable flushing
    */
    struct internal_state *state = strm->state;
570

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
571
    while(state->cds_buf + state->i < state->cds_p) {
572 573 574
        if (strm->avail_out == 0)
            return M_EXIT;

575
        *strm->next_out++ = state->cds_buf[state->i];
576 577 578 579 580 581 582 583 584 585 586 587 588
        strm->avail_out--;
        strm->total_out++;
        state->i++;
    }
    state->mode = m_get_block;
    return M_CONTINUE;
}

/*
 *
 * API functions
 *
 */
589

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
590
int aec_encode_init(struct aec_stream *strm)
591
{
592
    int bs, bsi;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
593
    struct internal_state *state;
594 595

    if (strm->bit_per_sample > 32 || strm->bit_per_sample == 0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
596
        return AEC_CONF_ERROR;
597 598 599 600 601

    if (strm->block_size != 8
        && strm->block_size != 16
        && strm->block_size != 32
        && strm->block_size != 64)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
602
        return AEC_CONF_ERROR;
603 604

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
607
    state = (struct internal_state *)malloc(sizeof(struct internal_state));
608
    if (state == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
609
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
610 611

    memset(state, 0, sizeof(struct internal_state));
612 613
    strm->state = state;

614 615 616 617 618
    bs = strm->block_size >> 3;
    bsi = 0;
    while (bs >>= 1)
        bsi++;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
619
    if (strm->bit_per_sample > 16) {
620
        /* 24/32 input bit settings */
621 622
        state->id_len = 5;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
623 624
        if (strm->bit_per_sample <= 24
            && strm->flags & AEC_DATA_3BYTE) {
625
            state->block_len = 3 * strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
626
            if (strm->flags & AEC_DATA_MSB) {
627 628
                state->get_sample = get_msb_24;
                state->get_block = get_block_funcs_msb_24[bsi];
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
629
            } else {
630 631
                state->get_sample = get_lsb_24;
                state->get_block = get_block_funcs_lsb_24[bsi];
632
            }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
633
        } else {
634
            state->block_len = 4 * strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
635
            if (strm->flags & AEC_DATA_MSB) {
636 637
                state->get_sample = get_msb_32;
                state->get_block = get_block_funcs_msb_32[bsi];
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
638
            } else {
639 640 641 642
                state->get_sample = get_lsb_32;
                state->get_block = get_block_funcs_lsb_32[bsi];
            }
        }
643
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
644
    else if (strm->bit_per_sample > 8) {
645 646
        /* 16 bit settings */
        state->id_len = 4;
647
        state->block_len = 2 * strm->block_size;
648

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
649
        if (strm->flags & AEC_DATA_MSB) {
650
            state->get_sample = get_msb_16;
651
            state->get_block = get_block_funcs_msb_16[bsi];
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
652
        } else {
653
            state->get_sample = get_lsb_16;
654 655
            state->get_block = get_block_funcs_lsb_16[bsi];
        }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
656
    } else {
657 658
        /* 8 bit settings */
        state->id_len = 3;
659
        state->block_len = strm->block_size;
660 661

        state->get_sample = get_8;
662
        state->get_block = get_block_funcs_8[bsi];
663 664
    }

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

675 676 677
    state->block_buf = (uint32_t *)malloc(strm->rsi
                                         * strm->block_size
                                         * sizeof(uint32_t));
678
    if (state->block_buf == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
679
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
680

681
    state->block_p = state->block_buf;
682

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
683
    /* Largest possible CDS according to specs */
684 685 686
    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
687
        return AEC_MEM_ERROR;
688

689 690 691
    strm->total_in = 0;
    strm->total_out = 0;

692 693 694
    state->cds_p = state->cds_buf;
    *state->cds_p = 0;
    state->bit_p = 8;
695 696
    state->mode = m_get_block;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
697
    return AEC_OK;
698 699
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
700
int aec_encode(struct aec_stream *strm, int flush)
701 702 703 704 705
{
    /**
       Finite-state machine implementation of the adaptive entropy
       encoder.
    */
706
    int n;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
707
    struct internal_state *state;
708 709 710 711 712
    state = strm->state;
    state->flush = flush;

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

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
713
    if (state->direct_out) {
714 715 716 717 718 719 720 721
        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;
722
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
723
    return AEC_OK;
724 725
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
726
int aec_encode_end(struct aec_stream *strm)
727
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
728
    struct internal_state *state = strm->state;
729

730 731
    free(state->block_buf);
    free(state->cds_buf);
732
    free(state);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
733
    return AEC_OK;
734
}