/alps/ufodecode

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/ufodecode
4 by Matthias Vogelgesang
Make ipedec a lib and executable
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <errno.h>
9 by Matthias Vogelgesang
Rename to `ufodecode`
5
#include "ufodecode.h"
6
#include "ufodecode-private.h"
4 by Matthias Vogelgesang
Make ipedec a lib and executable
7
#include "config.h"
9 by Matthias Vogelgesang
Rename to `ufodecode`
8
9
#ifdef HAVE_SSE
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
10
#include <xmmintrin.h>
9 by Matthias Vogelgesang
Rename to `ufodecode`
11
#endif
4 by Matthias Vogelgesang
Make ipedec a lib and executable
12
11.1.7 by Suren A. Chilingaryan
Introduce quiete checking of frame consistencies
13
#define CHECKS
14
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
15
#ifdef DEBUG
16
# define SLOW_CHECKS
17
# define ALL_CHECKS
18
# define VERBOSE
19
#endif /* DEBUG */
20
21
#ifdef ALL_CHECKS
22
# undef HAVE_SSE
23
#endif /* ALL_CHECKS */
24
25
31 by Matthias Vogelgesang
Clean up source a bit
26
#define IPECAMERA_NUM_ROWS              1088
27
#define IPECAMERA_NUM_CHANNELS          16      /**< Number of channels per row */
28
#define IPECAMERA_PIXELS_PER_CHANNEL    128     /**< Number of pixels per channel */
10 by Matthias Vogelgesang
Add documentation and split CMakeLists
29
#define IPECAMERA_WIDTH (IPECAMERA_NUM_CHANNELS * IPECAMERA_PIXELS_PER_CHANNEL) /**< Total pixel width of row */
30
41 by Suren A. Chilingaryan
Black magick from Michele
31
#define IPECAMERA_MODE_16_CHAN_IO	0
32
#define IPECAMERA_MODE_4_CHAN_IO	2
33
34
#define IPECAMERA_MODE_12_BIT_ADC	2
35
#define IPECAMERA_MODE_11_BIT_ADC	1
36
#define IPECAMERA_MODE_10_BIT_ADC	0
37
18 by Matthias Vogelgesang
Implement frame version 5
38
typedef struct {
39
    unsigned int pixel_number : 8;
40
    unsigned int row_number : 12;
41
    unsigned int pixel_size : 4;
42
    unsigned int magic : 8;
43
} payload_header_v5;
44
10 by Matthias Vogelgesang
Add documentation and split CMakeLists
45
46
/**
47
 * Check if value matches expected input.
48
 */
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
49
#ifdef VERBOSE
11.1.7 by Suren A. Chilingaryan
Introduce quiete checking of frame consistencies
50
# define CHECK_VALUE(value, expected) \
4 by Matthias Vogelgesang
Make ipedec a lib and executable
51
    if (value != expected) { \
52
        fprintf(stderr, "<%s:%i> 0x%x != 0x%x\n", __FILE__, __LINE__, value, expected); \
53
        err = 1; \
54
    }
11.1.7 by Suren A. Chilingaryan
Introduce quiete checking of frame consistencies
55
#else
56
# define CHECK_VALUE(value, expected) \
57
    if (value != expected) { \
58
        err = 1; \
59
    }
60
#endif
4 by Matthias Vogelgesang
Make ipedec a lib and executable
61
10 by Matthias Vogelgesang
Add documentation and split CMakeLists
62
/**
63
 * Check that flag evaluates to non-zero.
64
 */
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
65
#ifdef VERBOSE
11.1.7 by Suren A. Chilingaryan
Introduce quiete checking of frame consistencies
66
# define CHECK_FLAG(flag, check, ...) \
4 by Matthias Vogelgesang
Make ipedec a lib and executable
67
    if (!(check)) { \
68
        fprintf(stderr, "<%s:%i> Unexpected value 0x%x of " flag "\n", __FILE__, __LINE__,  __VA_ARGS__); \
69
        err = 1; \
70
    }
11.1.7 by Suren A. Chilingaryan
Introduce quiete checking of frame consistencies
71
#else
72
# define CHECK_FLAG(flag, check, ...) \
73
    if (!(check)) { \
74
        err = 1; \
75
    }
76
#endif
4 by Matthias Vogelgesang
Make ipedec a lib and executable
77
78
/**
79
 * \brief Setup a new decoder instance
80
 *
16 by Matthias Vogelgesang
Add version 4 frame decoding
81
 * \param height Number of rows that are expected in the data stream. Set this
82
 *      smaller 0 to let the decoder figure out the number of rows.
4 by Matthias Vogelgesang
Make ipedec a lib and executable
83
 * \param raw The data stream from the camera or NULL if set later with
9 by Matthias Vogelgesang
Rename to `ufodecode`
84
 * ufo_decoder_set_raw_data.
4 by Matthias Vogelgesang
Make ipedec a lib and executable
85
 * \param num_bytes Size of the data stream buffer in bytes
86
 *
87
 * \return A new decoder instance that can be used to iterate over the frames
9 by Matthias Vogelgesang
Rename to `ufodecode`
88
 * using ufo_decoder_get_next_frame.
4 by Matthias Vogelgesang
Make ipedec a lib and executable
89
 */
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
90
UfoDecoder *
31 by Matthias Vogelgesang
Clean up source a bit
91
ufo_decoder_new (int32_t height, uint32_t width, uint32_t *raw, size_t num_bytes)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
92
{
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
93
    if (width % IPECAMERA_PIXELS_PER_CHANNEL)
94
        return NULL;
11.1.1 by Suren A. Chilingaryan
Add width support and few consistency checks
95
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
96
    UfoDecoder *decoder = malloc(sizeof(UfoDecoder));
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
97
4 by Matthias Vogelgesang
Make ipedec a lib and executable
98
    if (decoder == NULL)
99
        return NULL;
100
11.1.1 by Suren A. Chilingaryan
Add width support and few consistency checks
101
    decoder->width = width;
4 by Matthias Vogelgesang
Make ipedec a lib and executable
102
    decoder->height = height;
9 by Matthias Vogelgesang
Rename to `ufodecode`
103
    ufo_decoder_set_raw_data(decoder, raw, num_bytes);
4 by Matthias Vogelgesang
Make ipedec a lib and executable
104
    return decoder;
105
}
106
107
/**
108
 * \brief Release decoder instance
109
 *
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
110
 * \param decoder An UfoDecoder instance
4 by Matthias Vogelgesang
Make ipedec a lib and executable
111
 */
31 by Matthias Vogelgesang
Clean up source a bit
112
void
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
113
ufo_decoder_free(UfoDecoder *decoder)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
114
{
115
    free(decoder);
116
}
117
118
/**
119
 * \brief Set raw data stream
120
 *
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
121
 * \param decoder An UfoDecoder instance
4 by Matthias Vogelgesang
Make ipedec a lib and executable
122
 * \param raw Raw data stream
123
 * \param num_bytes Size of data stream buffer in bytes
124
 */
31 by Matthias Vogelgesang
Clean up source a bit
125
void
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
126
ufo_decoder_set_raw_data(UfoDecoder *decoder, uint32_t *raw, size_t num_bytes)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
127
{
128
    decoder->raw = raw;
129
    decoder->num_bytes = num_bytes;
130
    decoder->current_pos = 0;
131
}
132
31 by Matthias Vogelgesang
Clean up source a bit
133
static int
41 by Suren A. Chilingaryan
Black magick from Michele
134
ufo_decode_frame_channels_v0(UfoDecoder     *decoder,
135
                             uint16_t       *pixel_buffer,
136
                             uint32_t       *raw,
137
                             size_t          num_words,
31 by Matthias Vogelgesang
Clean up source a bit
138
                             size_t         *offset)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
139
{
140
    static int channel_order[IPECAMERA_NUM_CHANNELS] = { 15, 13, 14, 12, 10, 8, 11, 7, 9, 6, 5, 2, 4, 3, 0, 1 };
11.1.1 by Suren A. Chilingaryan
Add width support and few consistency checks
141
    static int channel_size = (2 + IPECAMERA_PIXELS_PER_CHANNEL / 3);
4 by Matthias Vogelgesang
Make ipedec a lib and executable
142
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
143
    const int bytes = channel_size - 1;
144
    const int num_rows = decoder->height;
145
    const size_t cpl = (decoder->width / IPECAMERA_PIXELS_PER_CHANNEL);
11.1.1 by Suren A. Chilingaryan
Add width support and few consistency checks
146
    const size_t cpi = num_rows * cpl;
4 by Matthias Vogelgesang
Make ipedec a lib and executable
147
    int pos = 0;
148
    uint32_t data;
149
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
150
#ifdef HAVE_SSE
9 by Matthias Vogelgesang
Rename to `ufodecode`
151
    __m128i mask = _mm_set_epi32(0x3FF, 0x3FF, 0x3FF, 0x3FF);
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
152
    __m128i packed;
153
    __m128i tmp1, tmp2;
154
    uint32_t result[4] __attribute__ ((aligned (16))) = {0};
155
#endif
156
11.1.4 by Suren A. Chilingaryan
Support new footer
157
    if (cpi * channel_size > num_words) {
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
158
#ifdef VERBOSE
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
159
        fprintf(stderr, "Not enough data to decode frame, expected %lu bytes, but received %lu\n", cpi * channel_size * sizeof(uint32_t), num_words * sizeof(uint32_t));
11.1.4 by Suren A. Chilingaryan
Support new footer
160
#endif
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
161
        return EILSEQ;
11.1.4 by Suren A. Chilingaryan
Support new footer
162
    }
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
163
164
    for (size_t c = 0; c < cpi; c++) {
165
        const int info = raw[0];
166
        int row = (info >> 4) & 0x7FF;
167
        int channel = info & 0x0F;
168
        int pixels = (info >> 20) & 0xFF;
11.1.1 by Suren A. Chilingaryan
Add width support and few consistency checks
169
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
170
#ifdef SLOW_CHECKS
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
171
        int header = (info >> 30) & 0x03;
172
        const int bpp = (info >> 16) & 0x0F;
39.1.8 by Matthias Vogelgesang
Undo last commit
173
        int err;
11.1.4 by Suren A. Chilingaryan
Support new footer
174
        CHECK_FLAG("raw header magick", header == 2, header);
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
175
        CHECK_FLAG("row number, only %i rows requested", row < num_rows, row, num_rows);
11.1.4 by Suren A. Chilingaryan
Support new footer
176
        CHECK_FLAG("pixel size, only 10 bits are supported", bpp == 10, bpp);
11.1.8 by Suren A. Chilingaryan
Fix printf type
177
        CHECK_FLAG("channel, limited by %zu output channels", channel < cpl, channel, cpl);
11.1.4 by Suren A. Chilingaryan
Support new footer
178
#endif
179
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
180
        if ((row > num_rows) || (channel > cpl) || (pixels > IPECAMERA_PIXELS_PER_CHANNEL))
181
            return EILSEQ;
182
11.1.7 by Suren A. Chilingaryan
Introduce quiete checking of frame consistencies
183
        channel = channel_order[channel];
4 by Matthias Vogelgesang
Make ipedec a lib and executable
184
        int base = row * IPECAMERA_WIDTH + channel * IPECAMERA_PIXELS_PER_CHANNEL;
185
186
        /* "Correct" missing pixel */
187
        if ((row < 2) && (pixels == (IPECAMERA_PIXELS_PER_CHANNEL - 1))) {
188
            pixel_buffer[base] = 0;
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
189
            /* base++; */
190
        }
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
191
#ifdef SLOW_CHECKS
41 by Suren A. Chilingaryan
Black magick from Michele
192
        else
4 by Matthias Vogelgesang
Make ipedec a lib and executable
193
            CHECK_FLAG("number of pixels, %i is expected", pixels == IPECAMERA_PIXELS_PER_CHANNEL, pixels, IPECAMERA_PIXELS_PER_CHANNEL);
194
#endif
195
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
196
#ifdef HAVE_SSE
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
197
        for (int i = 1 ; i < bytes-4; i += 4, base += 12) {
198
            packed = _mm_set_epi32(raw[i], raw[i+1], raw[i+2], raw[i+3]);
199
200
            tmp1 = _mm_srli_epi32(packed, 20);
9 by Matthias Vogelgesang
Rename to `ufodecode`
201
            tmp2 = _mm_and_si128(tmp1, mask);
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
202
            _mm_storeu_si128((__m128i*) result, tmp2);
12 by Matthias Vogelgesang
Fix: wrong order of pixels when using SSE
203
204
            pixel_buffer[base+0] = result[3];
205
            pixel_buffer[base+3] = result[2];
206
            pixel_buffer[base+6] = result[1];
207
            pixel_buffer[base+9] = result[0];
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
208
209
            tmp1 = _mm_srli_epi32(packed, 10);
9 by Matthias Vogelgesang
Rename to `ufodecode`
210
            tmp2 = _mm_and_si128(tmp1, mask);
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
211
            _mm_storeu_si128((__m128i*) result, tmp2);
12 by Matthias Vogelgesang
Fix: wrong order of pixels when using SSE
212
            pixel_buffer[base+1] = result[3];
213
            pixel_buffer[base+4] = result[2];
214
            pixel_buffer[base+7] = result[1];
215
            pixel_buffer[base+10] = result[0];
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
216
9 by Matthias Vogelgesang
Rename to `ufodecode`
217
            tmp1 = _mm_and_si128(packed, mask);
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
218
            _mm_storeu_si128((__m128i*) result, tmp1);
12 by Matthias Vogelgesang
Fix: wrong order of pixels when using SSE
219
            pixel_buffer[base+2] = result[3];
220
            pixel_buffer[base+5] = result[2];
221
            pixel_buffer[base+8] = result[1];
222
            pixel_buffer[base+11] = result[0];
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
223
        }
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
224
12 by Matthias Vogelgesang
Fix: wrong order of pixels when using SSE
225
        /* Compute last pixels by hand */
226
        data = raw[41];
227
        pixel_buffer[base++] = (data >> 20) & 0x3FF;
228
        pixel_buffer[base++] = (data >> 10) & 0x3FF;
229
        pixel_buffer[base++] = data & 0x3FF;
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
230
12 by Matthias Vogelgesang
Fix: wrong order of pixels when using SSE
231
        data = raw[42];
232
        pixel_buffer[base++] = (data >> 20) & 0x3FF;
233
        pixel_buffer[base++] = (data >> 10) & 0x3FF;
234
        pixel_buffer[base++] = data & 0x3FF;
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
235
#else
8 by Matthias Vogelgesang
Add: optional SSE intrinsics
236
        for (int i = 1 ; i < bytes; i++) {
237
            data = raw[i];
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
238
# ifdef SLOW_CHECKS
41 by Suren A. Chilingaryan
Black magick from Michele
239
            header = (data >> 30) & 0x03;
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
240
            CHECK_FLAG("raw data magic", header == 3, header);
41 by Suren A. Chilingaryan
Black magick from Michele
241
            if (err)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
242
                return err;
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
243
# endif
4 by Matthias Vogelgesang
Make ipedec a lib and executable
244
            pixel_buffer[base++] = (data >> 20) & 0x3FF;
245
            pixel_buffer[base++] = (data >> 10) & 0x3FF;
246
            pixel_buffer[base++] = data & 0x3FF;
247
        }
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
248
#endif
4 by Matthias Vogelgesang
Make ipedec a lib and executable
249
250
        data = raw[bytes];
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
251
#ifdef SLOW_CHECKS
4 by Matthias Vogelgesang
Make ipedec a lib and executable
252
        header = (data >> 30) & 0x03;
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
253
        CHECK_FLAG("raw data magic", header == 3, header);
254
        CHECK_FLAG("raw footer magic", (data & 0x3FF) == 0x55, (data & 0x3FF));
41 by Suren A. Chilingaryan
Black magick from Michele
255
        if (err)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
256
            return err;
257
#endif
258
259
        int ppw = pixels >> 6;
260
        for (int j = 0; j < ppw; j++)
261
            pixel_buffer[base++] = (data >> (10 * (ppw - j))) & 0x3FF;
262
11.1.1 by Suren A. Chilingaryan
Add width support and few consistency checks
263
        pos += channel_size;
264
        raw += channel_size;
265
    }
4 by Matthias Vogelgesang
Make ipedec a lib and executable
266
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
267
    *offset += pos;
4 by Matthias Vogelgesang
Make ipedec a lib and executable
268
    return 0;
269
}
270
31 by Matthias Vogelgesang
Clean up source a bit
271
static int
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
272
ufo_decode_frame_channels_v4(UfoDecoder     *decoder,
41 by Suren A. Chilingaryan
Black magick from Michele
273
                             uint16_t       *pixel_buffer,
274
                             uint32_t       *raw,
275
                             size_t          num_words,
276
                             size_t          num_rows,
31 by Matthias Vogelgesang
Clean up source a bit
277
                             size_t         *offset)
16 by Matthias Vogelgesang
Add version 4 frame decoding
278
{
279
    static const int channel_order[IPECAMERA_NUM_CHANNELS] = { 15, 13, 14, 12, 10, 8, 11, 7, 9, 6, 5, 2, 4, 3, 0, 1 };
280
    static const int channel_size = (2 + IPECAMERA_PIXELS_PER_CHANNEL / 3);
281
282
    const int bytes = channel_size - 1;
283
    const size_t channels_per_row = (decoder->width / IPECAMERA_PIXELS_PER_CHANNEL);
284
    const size_t cpi = num_rows * channels_per_row;
285
    int pos = 0;
286
    uint32_t data;
287
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
288
#ifdef HAVE_SSE
16 by Matthias Vogelgesang
Add version 4 frame decoding
289
    __m128i mask = _mm_set_epi32(0x3FF, 0x3FF, 0x3FF, 0x3FF);
290
    __m128i packed;
291
    __m128i tmp1, tmp2;
292
    uint32_t result[4] __attribute__ ((aligned (16))) = {0};
293
#endif
294
295
    if (cpi * channel_size > num_words) {
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
296
#ifdef VERBOSE
16 by Matthias Vogelgesang
Add version 4 frame decoding
297
        fprintf(stderr, "Not enough data to decode frame, expected %lu bytes, but received %lu\n", cpi * channel_size * sizeof(uint32_t), num_words * sizeof(uint32_t));
298
#endif
299
        return EILSEQ;
300
    }
301
302
    for (size_t c = 0; c < cpi; c++) {
303
        int err = 0;
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
304
        const int info = raw[0];
305
        int row = (info >> 4) & 0x7FF;
306
        int channel = info & 0x0F;
307
        int pixels = (info >> 20) & 0xFF;
308
309
#ifdef SLOW_CHECKS
16 by Matthias Vogelgesang
Add version 4 frame decoding
310
        int header = (info >> 30) & 0x03;
311
        const int bpp = (info >> 16) & 0x0F;
312
        CHECK_FLAG("raw header magick", header == 2, header);
313
        CHECK_FLAG("pixel size, only 10 bits are supported", bpp == 10, bpp);
314
#endif
315
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
316
        CHECK_FLAG("pixels, only %u pixels per channel (offset: %zx)", pixels <= IPECAMERA_PIXELS_PER_CHANNEL, pixels, IPECAMERA_PIXELS_PER_CHANNEL, (*offset + pos));
317
        CHECK_FLAG("channel, limited by %zu output channels (offset: %zx)", channel <= channels_per_row, channel, channels_per_row, (*offset + pos));
318
        if (err)
16 by Matthias Vogelgesang
Add version 4 frame decoding
319
            return EILSEQ;
320
321
        channel = channel_order[channel];
322
        int base = row * IPECAMERA_WIDTH + channel * IPECAMERA_PIXELS_PER_CHANNEL;
323
324
        /* "Correct" missing pixel */
325
        if ((row < 2) && (pixels == (IPECAMERA_PIXELS_PER_CHANNEL - 1))) {
326
            pixel_buffer[base] = 0;
327
            /* base++; */
328
        }
329
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
330
#ifdef HAVE_SSE
16 by Matthias Vogelgesang
Add version 4 frame decoding
331
        for (int i = 1 ; i < bytes-4; i += 4, base += 12) {
332
            packed = _mm_set_epi32(raw[i], raw[i+1], raw[i+2], raw[i+3]);
333
334
            tmp1 = _mm_srli_epi32(packed, 20);
335
            tmp2 = _mm_and_si128(tmp1, mask);
336
            _mm_storeu_si128((__m128i*) result, tmp2);
337
338
            pixel_buffer[base+0] = result[3];
339
            pixel_buffer[base+3] = result[2];
340
            pixel_buffer[base+6] = result[1];
341
            pixel_buffer[base+9] = result[0];
342
343
            tmp1 = _mm_srli_epi32(packed, 10);
344
            tmp2 = _mm_and_si128(tmp1, mask);
345
            _mm_storeu_si128((__m128i*) result, tmp2);
346
            pixel_buffer[base+1] = result[3];
347
            pixel_buffer[base+4] = result[2];
348
            pixel_buffer[base+7] = result[1];
349
            pixel_buffer[base+10] = result[0];
350
351
            tmp1 = _mm_and_si128(packed, mask);
352
            _mm_storeu_si128((__m128i*) result, tmp1);
353
            pixel_buffer[base+2] = result[3];
354
            pixel_buffer[base+5] = result[2];
355
            pixel_buffer[base+8] = result[1];
356
            pixel_buffer[base+11] = result[0];
357
        }
358
359
        /* Compute last pixels by hand */
360
        data = raw[41];
361
        pixel_buffer[base++] = (data >> 20) & 0x3FF;
362
        pixel_buffer[base++] = (data >> 10) & 0x3FF;
363
        pixel_buffer[base++] = data & 0x3FF;
364
365
        data = raw[42];
366
        pixel_buffer[base++] = (data >> 20) & 0x3FF;
367
        pixel_buffer[base++] = (data >> 10) & 0x3FF;
368
        pixel_buffer[base++] = data & 0x3FF;
369
#else
370
        for (int i = 1 ; i < bytes; i++) {
371
            data = raw[i];
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
372
# ifdef SLOW_CHECKS
41 by Suren A. Chilingaryan
Black magick from Michele
373
            header = (data >> 30) & 0x03;
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
374
            CHECK_FLAG("raw data magic (offset: 0x%zx, expected: 0x02)", header == 3, header, (*offset + pos + i)*sizeof(uint32_t));
41 by Suren A. Chilingaryan
Black magick from Michele
375
            if (err)
16 by Matthias Vogelgesang
Add version 4 frame decoding
376
                return err;
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
377
# endif
16 by Matthias Vogelgesang
Add version 4 frame decoding
378
            pixel_buffer[base++] = (data >> 20) & 0x3FF;
379
            pixel_buffer[base++] = (data >> 10) & 0x3FF;
380
            pixel_buffer[base++] = data & 0x3FF;
381
        }
382
#endif
383
384
        data = raw[bytes];
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
385
#ifdef SLOW_CHECKS
16 by Matthias Vogelgesang
Add version 4 frame decoding
386
        header = (data >> 30) & 0x03;
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
387
        CHECK_FLAG("raw data magic (offset: 0x%zx, expected: 0x03)", header == 3, header, (*offset + pos + bytes)*sizeof(uint32_t));
388
        CHECK_FLAG("raw footer magic (offset: 0x%zx, expected: 0x55)", (data & 0x3FF) == 0x55, (data & 0x3FF), (*offset + pos + bytes)*sizeof(uint32_t));
41 by Suren A. Chilingaryan
Black magick from Michele
389
        if (err)
16 by Matthias Vogelgesang
Add version 4 frame decoding
390
            return err;
391
#endif
392
393
        int ppw = pixels >> 6;
394
        for (int j = 0; j < ppw; j++)
395
            pixel_buffer[base++] = (data >> (10 * (ppw - j))) & 0x3FF;
396
397
        pos += channel_size;
398
        raw += channel_size;
399
    }
400
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
401
    *offset += pos;
16 by Matthias Vogelgesang
Add version 4 frame decoding
402
    return 0;
403
}
404
31 by Matthias Vogelgesang
Clean up source a bit
405
static int
41 by Suren A. Chilingaryan
Black magick from Michele
406
ufo_decode_frame_channels_v5(UfoDecoder     *decoder,
407
                             uint16_t       *pixel_buffer,
408
                             uint32_t       *raw,
409
                             size_t          num_rows,
410
                             size_t         *offset,
411
                             uint8_t         output_mode)
18 by Matthias Vogelgesang
Implement frame version 5
412
{
35 by Matthias Vogelgesang
Correctly implement 12 bit mode
413
    payload_header_v5 *header;
18 by Matthias Vogelgesang
Implement frame version 5
414
    size_t base = 0, index = 0;
35 by Matthias Vogelgesang
Correctly implement 12 bit mode
415
416
    header = (payload_header_v5 *) &raw[base];
417
41 by Suren A. Chilingaryan
Black magick from Michele
418
    if (output_mode == IPECAMERA_MODE_4_CHAN_IO) {
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
419
        size_t off = 0;
420
35 by Matthias Vogelgesang
Correctly implement 12 bit mode
421
        while (raw[base] != 0xAAAAAAA) {
422
            header = (payload_header_v5 *) &raw[base];
18 by Matthias Vogelgesang
Implement frame version 5
423
            index = header->row_number * IPECAMERA_WIDTH + header->pixel_number;
30 by Matthias Vogelgesang
Update for 12 bits
424
35 by Matthias Vogelgesang
Correctly implement 12 bit mode
425
            /* Skip header + one zero-filled words */
426
            base += 2;
427
428
            if ((header->magic != 0xe0) && (header->magic != 0xc0)) {
39 by Matthias Vogelgesang
Fix 12 bit decoding
429
                pixel_buffer[index +  (0+off)*IPECAMERA_PIXELS_PER_CHANNEL] = 0xfff & (raw[base+5] >> 12);
430
                pixel_buffer[index +  (4+off)*IPECAMERA_PIXELS_PER_CHANNEL] = 0xfff & (raw[base+4] >> 4);
35 by Matthias Vogelgesang
Correctly implement 12 bit mode
431
                pixel_buffer[index +  (8+off)*IPECAMERA_PIXELS_PER_CHANNEL] = ((0xf & raw[base+1]) << 8) | (raw[base+2] >> 24);
39 by Matthias Vogelgesang
Fix 12 bit decoding
432
                pixel_buffer[index + (12+off)*IPECAMERA_PIXELS_PER_CHANNEL] = 0xfff & (raw[base+1] >> 16);
30 by Matthias Vogelgesang
Update for 12 bits
433
            }
434
            else {
41 by Suren A. Chilingaryan
Black magick from Michele
435
                off++;
35 by Matthias Vogelgesang
Correctly implement 12 bit mode
436
437
                if (header->magic == 0xc0)
438
                    off = 0;
30 by Matthias Vogelgesang
Update for 12 bits
439
            }
440
35 by Matthias Vogelgesang
Correctly implement 12 bit mode
441
            base += 6;
442
        }
443
    }
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
444
    else {
35 by Matthias Vogelgesang
Correctly implement 12 bit mode
445
        while (raw[base] != 0xAAAAAAA) {
446
            header = (payload_header_v5 *) &raw[base];
447
            index = header->row_number * IPECAMERA_WIDTH + header->pixel_number;
448
449
            /* Skip header + two zero-filled words */
41 by Suren A. Chilingaryan
Black magick from Michele
450
            base += 2;
451
452
            if (header->magic != 0xc0) {
453
                pixel_buffer[index + 15*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base] >> 20);
454
                pixel_buffer[index + 13*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base] >> 8);
39.1.6 by Matthias Vogelgesang
Fix 10 bit decoding
455
                pixel_buffer[index + 14*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (((0xff & raw[base]) << 4) | (raw[base+1] >> 28));
41 by Suren A. Chilingaryan
Black magick from Michele
456
                pixel_buffer[index + 12*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+1] >> 16);
457
                pixel_buffer[index + 10*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+1] >> 4);
39.1.6 by Matthias Vogelgesang
Fix 10 bit decoding
458
                pixel_buffer[index +  8*IPECAMERA_PIXELS_PER_CHANNEL] = ((0x3 & raw[base+1]) << 8) | (raw[base+2] >> 24);
41 by Suren A. Chilingaryan
Black magick from Michele
459
                pixel_buffer[index + 11*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+2] >> 12);
460
                pixel_buffer[index +  7*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & raw[base+2];
461
                pixel_buffer[index +  9*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+3] >> 20);
462
                pixel_buffer[index +  6*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+3] >> 8);
39.1.6 by Matthias Vogelgesang
Fix 10 bit decoding
463
                pixel_buffer[index +  5*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (((0xff & raw[base+3]) << 4) | (raw[base+4] >> 28));
41 by Suren A. Chilingaryan
Black magick from Michele
464
                pixel_buffer[index +  2*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+4] >> 16);
465
                pixel_buffer[index +  4*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+4] >> 4);
39.1.6 by Matthias Vogelgesang
Fix 10 bit decoding
466
                pixel_buffer[index +  3*IPECAMERA_PIXELS_PER_CHANNEL] = ((0x3 & raw[base+4]) << 8) | (raw[base+5] >> 24);
41 by Suren A. Chilingaryan
Black magick from Michele
467
                pixel_buffer[index +  0*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+5] >> 12);
468
                pixel_buffer[index +  1*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & raw[base+5];
469
            }
470
471
            base += 6;
18 by Matthias Vogelgesang
Implement frame version 5
472
        }
473
    }
474
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
475
    *offset += base;
18 by Matthias Vogelgesang
Implement frame version 5
476
    return 0;
477
}
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
478
4 by Matthias Vogelgesang
Make ipedec a lib and executable
479
/**
480
 * \brief Deinterlace by interpolating between two rows
481
 *
482
 * \param in Input frame
483
 * \param out Destination of interpolated frame
484
 * \param width Width of frame in pixels
10 by Matthias Vogelgesang
Add documentation and split CMakeLists
485
 * \param height Height of frame in pixels
4 by Matthias Vogelgesang
Make ipedec a lib and executable
486
 */
9 by Matthias Vogelgesang
Rename to `ufodecode`
487
void ufo_deinterlace_interpolate(const uint16_t *in, uint16_t *out, int width, int height)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
488
{
489
    const size_t row_size_bytes = width * sizeof(uint16_t);
490
491
    for (int row = 0; row < height; row++) {
492
        /* Copy one line */
493
        memcpy(out, in + row*width, row_size_bytes);
494
        out += width;
495
41 by Suren A. Chilingaryan
Black magick from Michele
496
        /* Interpolate between source row and row+1 */
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
497
        for (int x = 0; x < width; x++)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
498
            out[x] = (int) (0.5 * in[row*width + x] + 0.5 * in[(row+1)*width + x]);
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
499
4 by Matthias Vogelgesang
Make ipedec a lib and executable
500
        out += width;
501
    }
502
503
    /* Copy last row */
504
    memcpy(out, in + width * (height - 1), row_size_bytes);
505
}
506
507
/**
508
 * \brief Deinterlace by "weaving" the rows of two frames
509
 *
510
 * \param in1 First frame
511
 * \param in2 Second frame
512
 * \param out Destination of weaved frame
513
 * \param width Width of frame in pixels
10 by Matthias Vogelgesang
Add documentation and split CMakeLists
514
 * \param height Height of frame in pixels
4 by Matthias Vogelgesang
Make ipedec a lib and executable
515
 */
9 by Matthias Vogelgesang
Rename to `ufodecode`
516
void ufo_deinterlace_weave(const uint16_t *in1, const uint16_t *in2, uint16_t *out, int width, int height)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
517
{
518
    const size_t row_size_bytes = width * sizeof(uint16_t);
519
    for (int row = 0; row < height; row++) {
41 by Suren A. Chilingaryan
Black magick from Michele
520
        memcpy(out, in1 + row*width, row_size_bytes);
4 by Matthias Vogelgesang
Make ipedec a lib and executable
521
        out += width;
41 by Suren A. Chilingaryan
Black magick from Michele
522
        memcpy(out, in2 + row*width, row_size_bytes);
4 by Matthias Vogelgesang
Make ipedec a lib and executable
523
        out += width;
524
    }
525
}
526
527
/**
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
528
 * \brief Decodes frame
4 by Matthias Vogelgesang
Make ipedec a lib and executable
529
 *
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
530
 * This function tries to decode the supplied data
4 by Matthias Vogelgesang
Make ipedec a lib and executable
531
 *
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
532
 * \param decoder An UfoDecoder instance
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
533
 * \param raw Raw data stream
534
 * \param num_bytes Size of data stream buffer in bytes
4 by Matthias Vogelgesang
Make ipedec a lib and executable
535
 * \param pixels If pointer with NULL content is passed, a new buffer is
536
 * allocated otherwise, this user-supplied buffer is used.
537
 * \param frame_number Frame number as reported in the header
538
 * \param time_stamp Time stamp of the frame as reported in the header
539
 *
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
540
 * \return number of decoded bytes or 0 in case of error
4 by Matthias Vogelgesang
Make ipedec a lib and executable
541
 */
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
542
size_t ufo_decoder_decode_frame(UfoDecoder      *decoder,
41 by Suren A. Chilingaryan
Black magick from Michele
543
                                uint32_t        *raw,
544
                                size_t           num_bytes,
545
                                uint16_t        *pixels,
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
546
                                UfoDecoderMeta  *meta)
4 by Matthias Vogelgesang
Make ipedec a lib and executable
547
{
548
    int err = 0;
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
549
    size_t pos = 0;
550
    const size_t num_words = num_bytes / 4;
551
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
552
    if ((pixels == NULL) || (num_words < 16)) {
553
#ifdef VERBOSE
554
	if (num_words < 16) 
555
	    fprintf(stderr, "Not enough frame data, only %zu bytes supplied \n", num_bytes);
556
#endif
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
557
        return 0;
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
558
    }
4 by Matthias Vogelgesang
Make ipedec a lib and executable
559
16 by Matthias Vogelgesang
Add version 4 frame decoding
560
    size_t rows_per_frame = decoder->height;
561
    const int version = (raw[pos+6] >> 24) & 0xF;
562
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
563
#ifdef CHECKS
4 by Matthias Vogelgesang
Make ipedec a lib and executable
564
    CHECK_VALUE(raw[pos++], 0x51111111);
565
    CHECK_VALUE(raw[pos++], 0x52222222);
566
    CHECK_VALUE(raw[pos++], 0x53333333);
567
    CHECK_VALUE(raw[pos++], 0x54444444);
568
    CHECK_VALUE(raw[pos++], 0x55555555);
16 by Matthias Vogelgesang
Add version 4 frame decoding
569
570
    switch (version) {
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
571
        case 0:
572
            CHECK_VALUE(raw[pos++], 0x56666666);
573
            CHECK_VALUE(raw[pos] >> 28, 0x5);
574
            meta->frame_number = raw[pos++] & 0xFFFFFFF;
575
            CHECK_VALUE(raw[pos] >> 28, 0x5);
576
            meta->time_stamp = raw[pos++] & 0xFFFFFFF;
577
            break;
578
579
        case 4:
580
        case 5:
581
            CHECK_VALUE(raw[pos] >> 28, 0x5);
582
            meta->cmosis_start_address = (raw[pos] >> 21) & 0x1FF;
583
            meta->n_skipped_rows = (raw[pos] >> 15) & 0x3F;
584
            meta->n_rows = rows_per_frame = raw[pos] & 0x7FF;
585
            pos++;
586
587
            meta->frame_number = raw[pos++] & 0x1FFFFFF;
588
            CHECK_VALUE(raw[pos] >> 28, 0x5);
589
            meta->time_stamp = raw[pos] & 0xFFFFFF;
590
            meta->output_mode = (raw[pos] >> 24) & 0x3;
591
            meta->adc_resolution = (raw[pos] >> 26) & 0x3;
592
            pos++;
593
39.1.3 by Matthias Vogelgesang
Output version number if wrong
594
            if ((meta->output_mode != IPECAMERA_MODE_4_CHAN_IO) && (meta->output_mode != IPECAMERA_MODE_16_CHAN_IO)) {
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
595
# ifdef VERBOSE
39.1.5 by Matthias Vogelgesang
Add --print-num-rows and fix debug output
596
                fprintf(stderr, "Output mode 0x%x is not supported\n", meta->output_mode);
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
597
# endif
598
                return 0;
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
599
            }
600
            break;
41 by Suren A. Chilingaryan
Black magick from Michele
601
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
602
        default:
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
603
# ifdef VERBOSE
39.1.3 by Matthias Vogelgesang
Output version number if wrong
604
            fprintf(stderr, "Unsupported data format version %i detected\n", version);
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
605
# endif
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
606
            return 0;
16 by Matthias Vogelgesang
Add version 4 frame decoding
607
    }
608
41 by Suren A. Chilingaryan
Black magick from Michele
609
    if (err)
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
610
        return 0;
4 by Matthias Vogelgesang
Make ipedec a lib and executable
611
#else
16 by Matthias Vogelgesang
Add version 4 frame decoding
612
    switch (version) {
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
613
        case 0:
614
            meta->frame_number = raw[pos + 6] & 0xFFFFFFF;
615
            meta->time_stamp = raw[pos + 7] & 0xFFFFFFF;
616
            break;
617
        case 4:
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
618
            meta->n_rows = rows_per_frame = raw[pos + 5] & 0x7FF;
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
619
        case 5:
620
            meta->frame_number = raw[pos + 6] & 0x1FFFFFF;
621
            meta->time_stamp = raw[pos + 7] & 0xFFFFFF;
622
            meta->output_mode = (raw[pos + 7] >> 24) & 0x3;
623
            meta->adc_resolution = (raw[pos + 7] >> 26) & 0x3;
41 by Suren A. Chilingaryan
Black magick from Michele
624
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
625
            break;
626
        default:
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
627
# ifdef VERBOSE
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
628
            fprintf(stderr, "Unsupported data format detected\n");
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
629
# endif
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
630
            return 0;
16 by Matthias Vogelgesang
Add version 4 frame decoding
631
    }
632
4 by Matthias Vogelgesang
Make ipedec a lib and executable
633
    pos += 8;
634
#endif
635
16 by Matthias Vogelgesang
Add version 4 frame decoding
636
    switch (version) {
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
637
        case 0:
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
638
            err = ufo_decode_frame_channels_v0(decoder, pixels, raw + pos, num_words - pos - 8, &pos);
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
639
            break;
640
        case 4:
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
641
            err = ufo_decode_frame_channels_v4(decoder, pixels, raw + pos, num_words - pos - 8, rows_per_frame, &pos);
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
642
            break;
643
        case 5:
45 by Suren A. Chilingaryan
Few bug fixes and more coherent debug flags
644
            err = ufo_decode_frame_channels_v5(decoder, pixels, raw + pos, rows_per_frame, &pos, meta->output_mode);
39.1.2 by Matthias Vogelgesang
Return errcode != 0 if frame could not be decoded
645
            break;
646
        default:
647
            break;
16 by Matthias Vogelgesang
Add version 4 frame decoding
648
    }
649
24 by Matthias Vogelgesang
Decode frames after encountering corrupted ones
650
    if (err)
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
651
        return 0;
4 by Matthias Vogelgesang
Make ipedec a lib and executable
652
11.1.7 by Suren A. Chilingaryan
Introduce quiete checking of frame consistencies
653
#ifdef CHECKS
4 by Matthias Vogelgesang
Make ipedec a lib and executable
654
    CHECK_VALUE(raw[pos++], 0x0AAAAAAA);
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
655
656
    meta->status1.bits = raw[pos++];
657
    meta->status2.bits = raw[pos++];
658
    meta->status3.bits = raw[pos++];
19 by Matthias Vogelgesang
Adapt tail
659
    pos++;
660
    pos++;
4 by Matthias Vogelgesang
Make ipedec a lib and executable
661
    CHECK_VALUE(raw[pos++], 0x00000000);
662
    CHECK_VALUE(raw[pos++], 0x01111111);
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
663
41 by Suren A. Chilingaryan
Black magick from Michele
664
    if (err)
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
665
        return 0;
4 by Matthias Vogelgesang
Make ipedec a lib and executable
666
#else
667
    pos += 8;
668
#endif
669
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
670
    return pos;
671
}
672
673
/**
674
 * \brief Iterate and decode next frame
675
 *
676
 * This function tries to decode the next frame in the currently set raw data
41 by Suren A. Chilingaryan
Black magick from Michele
677
 * stream.
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
678
 *
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
679
 * \param decoder An UfoDecoder instance
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
680
 * \param pixels If pointer with NULL content is passed, a new buffer is
681
 * allocated otherwise, this user-supplied buffer is used.
16 by Matthias Vogelgesang
Add version 4 frame decoding
682
 * \param num_rows Number of actual decoded rows
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
683
 * \param frame_number Frame number as reported in the header
684
 * \param time_stamp Time stamp of the frame as reported in the header
685
 *
24 by Matthias Vogelgesang
Decode frames after encountering corrupted ones
686
 * \return 0 in case of no error, EIO if end of stream was reached, ENOMEM if
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
687
 * NULL was passed but no memory could be allocated, EILSEQ if data stream is
688
 * corrupt and EFAULT if pixels is a NULL-pointer.
689
 */
41 by Suren A. Chilingaryan
Black magick from Michele
690
int ufo_decoder_get_next_frame(UfoDecoder     *decoder,
691
                               uint16_t      **pixels,
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
692
                               UfoDecoderMeta *meta)
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
693
{
694
    uint32_t *raw = decoder->raw;
695
    size_t pos = decoder->current_pos;
696
    size_t advance;
697
    const size_t num_words = decoder->num_bytes / 4;
698
699
    if (pixels == NULL)
700
        return 0;
701
702
    if (pos >= num_words)
41 by Suren A. Chilingaryan
Black magick from Michele
703
        return EIO;
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
704
705
    if (num_words < 16)
706
        return EILSEQ;
707
708
    if (*pixels == NULL) {
709
        *pixels = (uint16_t *) malloc(IPECAMERA_WIDTH * decoder->height * sizeof(uint16_t));
710
        if (*pixels == NULL)
711
            return ENOMEM;
712
    }
14 by Matthias Vogelgesang
Fix: formatting (whitespace, indentation)
713
24 by Matthias Vogelgesang
Decode frames after encountering corrupted ones
714
    while ((pos < num_words) && (raw[pos] != 0x51111111))
15 by Matthias Vogelgesang
Fix wrong address access and skip till first valid header
715
        pos++;
716
32 by Matthias Vogelgesang
Commit version 0.2 of libufodecode
717
    advance = ufo_decoder_decode_frame(decoder, raw + pos, decoder->num_bytes - pos, *pixels, meta);
16 by Matthias Vogelgesang
Add version 4 frame decoding
718
24 by Matthias Vogelgesang
Decode frames after encountering corrupted ones
719
    /*
720
     * On error, advance is 0 but we have to advance at least a bit to net get
721
     * caught in an infinite loop when trying to decode subsequent frames.
722
     */
723
    pos += advance == 0 ? 1 : advance;
11.1.6 by Suren A. Chilingaryan
Introduce thread-safe ufo_decoder_decode_frame function
724
4 by Matthias Vogelgesang
Make ipedec a lib and executable
725
    /* if bytes left and we see fill bytes, skip them */
11.1.1 by Suren A. Chilingaryan
Add width support and few consistency checks
726
    if (((pos + 2) < num_words) && ((raw[pos] == 0x0) && (raw[pos+1] == 0x1111111))) {
4 by Matthias Vogelgesang
Make ipedec a lib and executable
727
        pos += 2;
728
        while ((pos < num_words) && ((raw[pos] == 0x89abcdef) || (raw[pos] == 0x1234567)))
729
            pos++;
730
    }
731
732
    decoder->current_pos = pos;
24 by Matthias Vogelgesang
Decode frames after encountering corrupted ones
733
734
    if (!advance)
735
        return EILSEQ;
736
4 by Matthias Vogelgesang
Make ipedec a lib and executable
737
    return 0;
738
}
739