/alps/ipecamera

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/ipecamera

« back to all changes in this revision

Viewing changes to ipecamera/data.c

  • Committer: Suren A. Chilingaryan
  • Date: 2011-12-12 04:45:35 UTC
  • Revision ID: csa@dside.dyndns.org-20111212044535-6no1q7g230i8uvlv
multithread preprocessing of ipecamera frames and code reorganization

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define _IPECAMERA_IMAGE_C
 
2
#define _BSD_SOURCE
 
3
#define _GNU_SOURCE
 
4
 
 
5
#include <stdio.h>
 
6
#include <stdlib.h>
 
7
#include <unistd.h>
 
8
#include <string.h>
 
9
#include <sys/time.h>
 
10
#include <pthread.h>
 
11
#include <assert.h>
 
12
 
 
13
#include <ufodecode.h>
 
14
 
 
15
#include "../tools.h"
 
16
#include "../error.h"
 
17
 
 
18
#include "pcilib.h"
 
19
#include "private.h"
 
20
#include "data.h"
 
21
 
 
22
// DS: Currently, on event_id overflow we are assuming the buffer is lost
 
23
static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) {
 
24
    pcilib_event_id_t diff;
 
25
 
 
26
    if (evid > ctx->event_id) {
 
27
        diff = (((pcilib_event_id_t)-1) - ctx->event_id) + evid;
 
28
        if (diff >= ctx->buffer_size) return -1;
 
29
    } else {
 
30
        diff = ctx->event_id - evid;
 
31
        if (diff >= ctx->buffer_size) return -1;
 
32
    }
 
33
    
 
34
        // DS: Request buffer_size to be power of 2 and replace to shifts (just recompute in set_buffer_size)
 
35
    return (evid - 1) % ctx->buffer_size;
 
36
}
 
37
 
 
38
inline static int ipecamera_decode_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
 
39
    int err = 0;
 
40
    uint32_t tmp;
 
41
    uint16_t *pixels;
 
42
    
 
43
    int buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
 
44
    if (buf_ptr < 0) return PCILIB_ERROR_TIMEOUT;
 
45
    
 
46
    if (ctx->frame[buf_ptr].event.image_ready) return 0;
 
47
    
 
48
    if (ctx->frame[buf_ptr].event.info.flags&PCILIB_EVENT_INFO_FLAG_BROKEN) {
 
49
        ctx->frame[buf_ptr].event.image_broken = 1;
 
50
        err = PCILIB_ERROR_INVALID_DATA;
 
51
        goto ready;
 
52
    }
 
53
        
 
54
                
 
55
    pixels = ctx->image + buf_ptr * ctx->image_size;
 
56
    memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t));
 
57
    err = ufo_decoder_decode_frame(ctx->ipedec, ctx->buffer + buf_ptr * ctx->padded_size, ctx->raw_size, pixels, &tmp, &tmp, ctx->cmask + ctx->buffer_pos * ctx->dim.height);
 
58
    if (err) {
 
59
        ctx->frame[buf_ptr].event.image_broken = 1;
 
60
        err = PCILIB_ERROR_FAILED;
 
61
        goto ready;
 
62
    }
 
63
            
 
64
    ctx->frame[buf_ptr].event.image_broken = 0;
 
65
 
 
66
ready:
 
67
    ctx->frame[buf_ptr].event.image_ready = 1;
 
68
 
 
69
    if (ipecamera_resolve_event_id(ctx, event_id) < 0) {
 
70
        ctx->frame[buf_ptr].event.image_ready = 0;
 
71
        return PCILIB_ERROR_TIMEOUT;
 
72
    }
 
73
    
 
74
    return err;
 
75
}
 
76
 
 
77
static int ipecamera_get_next_buffer_to_process(ipecamera_t *ctx, pcilib_event_id_t *evid) {
 
78
    int res;
 
79
 
 
80
    if (ctx->preproc_id == ctx->event_id) return -1;
 
81
    
 
82
    if (ctx->preproc) 
 
83
        pthread_mutex_lock(&ctx->preproc_mutex);
 
84
        
 
85
    if (ctx->preproc_id == ctx->event_id) {
 
86
        if (ctx->preproc)
 
87
            pthread_mutex_unlock(&ctx->preproc_mutex);
 
88
        return -1;
 
89
    }
 
90
 
 
91
    if ((ctx->event_id - ctx->preproc_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->preproc_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS - 1;
 
92
 
 
93
    res = ctx->preproc_id%ctx->buffer_size;
 
94
 
 
95
    if (pthread_rwlock_trywrlock(&ctx->frame[res].mutex)) {
 
96
        pthread_mutex_unlock(&ctx->preproc_mutex);
 
97
        return -1;
 
98
    }
 
99
    
 
100
    *evid = ++ctx->preproc_id;
 
101
 
 
102
    if (ctx->preproc)
 
103
        pthread_mutex_unlock(&ctx->preproc_mutex);
 
104
 
 
105
    return res;
 
106
}
 
107
 
 
108
 
 
109
void *ipecamera_preproc_thread(void *user) {
 
110
    int buf_ptr;
 
111
    pcilib_event_id_t evid;
 
112
    
 
113
    ipecamera_preprocessor_t *preproc = (ipecamera_preprocessor_t*)user;
 
114
    ipecamera_t *ctx = preproc->ipecamera;
 
115
    
 
116
    while (ctx->run_preprocessors) {
 
117
        buf_ptr = ipecamera_get_next_buffer_to_process(ctx, &evid);
 
118
        if (buf_ptr < 0) {
 
119
            usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
 
120
            continue;
 
121
        }
 
122
        
 
123
        ipecamera_decode_frame(ctx, evid);
 
124
        
 
125
        pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
 
126
    }
 
127
    
 
128
    return NULL;
 
129
}
 
130
 
 
131
static int ipecamera_get_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
 
132
    int err;
 
133
    int buf_ptr = (event_id - 1) % ctx->buffer_size;
 
134
    
 
135
    if (!ctx->preproc) {        
 
136
        pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
 
137
 
 
138
        err = ipecamera_decode_frame(ctx, event_id);
 
139
 
 
140
        if (err) {
 
141
            pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
 
142
            return err;
 
143
        }
 
144
        
 
145
        return 0;
 
146
    }
 
147
    
 
148
    
 
149
    while (!ctx->frame[buf_ptr].event.image_ready) {
 
150
        usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
 
151
 
 
152
        buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
 
153
        if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
 
154
    }   
 
155
 
 
156
    pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
 
157
    
 
158
    buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
 
159
    if ((buf_ptr < 0)||(!ctx->frame[buf_ptr].event.image_ready)) {
 
160
        pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
 
161
        return PCILIB_ERROR_OVERWRITTEN;
 
162
    }
 
163
    
 
164
    return 0;    
 
165
}
 
166
 
 
167
 
 
168
/*
 
169
 We will lock the data for non-raw data to prevent ocasional overwritting. The 
 
170
 raw data will be overwritten by the reader thread anyway and we can't do 
 
171
 anything to prevent it for performance reasons.
 
172
*/
 
173
int ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **ret) {
 
174
    int err;
 
175
    int buf_ptr;
 
176
    size_t raw_size;
 
177
    ipecamera_t *ctx = (ipecamera_t*)vctx;
 
178
 
 
179
    void *data = *ret;
 
180
 
 
181
    if (!ctx) {
 
182
        pcilib_error("IPECamera imaging is not initialized");
 
183
        return PCILIB_ERROR_NOTINITIALIZED;
 
184
    }
 
185
        
 
186
    buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
 
187
    if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
 
188
    
 
189
    switch ((ipecamera_data_type_t)data_type) {
 
190
        case IPECAMERA_RAW_DATA:
 
191
            raw_size = ctx->frame[buf_ptr].event.raw_size;
 
192
            if (data) {
 
193
                if ((!size)||(*size < raw_size)) return PCILIB_ERROR_TOOBIG;
 
194
                memcpy(data, ctx->buffer + buf_ptr * ctx->padded_size, raw_size);
 
195
                if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN;
 
196
                *size = raw_size;
 
197
                return 0;
 
198
            }
 
199
            if (size) *size = raw_size;
 
200
            *ret = ctx->buffer + buf_ptr * ctx->padded_size;
 
201
            return 0;
 
202
        case IPECAMERA_IMAGE_DATA:
 
203
            err = ipecamera_get_frame(ctx, event_id);
 
204
            if (err) return err;
 
205
 
 
206
            if (data) {
 
207
                if ((!size)||(*size < ctx->image_size * sizeof(ipecamera_pixel_t))) return PCILIB_ERROR_TOOBIG;
 
208
                memcpy(data, ctx->image + buf_ptr * ctx->image_size, ctx->image_size * sizeof(ipecamera_pixel_t));
 
209
                pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
 
210
                *size =  ctx->image_size * sizeof(ipecamera_pixel_t);
 
211
                return 0;
 
212
            }
 
213
        
 
214
            if (size) *size = ctx->image_size * sizeof(ipecamera_pixel_t);
 
215
            *ret = ctx->image + buf_ptr * ctx->image_size;
 
216
            return 0;
 
217
        case IPECAMERA_CHANGE_MASK:
 
218
            err = ipecamera_get_frame(ctx, event_id);
 
219
            if (err) return err;
 
220
 
 
221
            if (data) {
 
222
                if ((!size)||(*size < ctx->dim.height * sizeof(ipecamera_change_mask_t))) return PCILIB_ERROR_TOOBIG;
 
223
                memcpy(data, ctx->image + buf_ptr * ctx->dim.height, ctx->dim.height * sizeof(ipecamera_change_mask_t));
 
224
                pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
 
225
                *size =  ctx->dim.height * sizeof(ipecamera_change_mask_t);
 
226
                return 0;
 
227
            }
 
228
 
 
229
            if (size) *size = ctx->dim.height * sizeof(ipecamera_change_mask_t);
 
230
            *ret = ctx->cmask + buf_ptr * ctx->dim.height;
 
231
            return 0;
 
232
        case IPECAMERA_DIMENSIONS:
 
233
            if (size) *size = sizeof(ipecamera_image_dimensions_t);
 
234
            ret = (void*)&ctx->dim;
 
235
            return 0;
 
236
        case IPECAMERA_IMAGE_REGION:
 
237
        case IPECAMERA_PACKED_IMAGE:
 
238
            // Shall we return complete image or only changed parts?
 
239
        case IPECAMERA_PACKED_LINE:
 
240
        case IPECAMERA_PACKED_PAYLOAD:
 
241
            pcilib_error("Support for data type (%li) is not implemented yet", data_type);
 
242
            return PCILIB_ERROR_NOTSUPPORTED;
 
243
        default:
 
244
            pcilib_error("Unknown data type (%li) is requested", data_type);
 
245
            return PCILIB_ERROR_INVALID_REQUEST;
 
246
    }
 
247
}
 
248
 
 
249
 
 
250
/*
 
251
 We will unlock non-raw data and check if the raw data is not overwritten yet
 
252
*/
 
253
int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) {
 
254
    ipecamera_t *ctx = (ipecamera_t*)vctx;
 
255
 
 
256
    if (!ctx) {
 
257
        pcilib_error("IPECamera imaging is not initialized");
 
258
        return PCILIB_ERROR_NOTINITIALIZED;
 
259
 
 
260
    }
 
261
 
 
262
    if ((ipecamera_data_type_t)data_type == IPECAMERA_RAW_DATA) {
 
263
        if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN;
 
264
    } else {
 
265
        int buf_ptr = (event_id - 1) % ctx->buffer_size;
 
266
        pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
 
267
    }
 
268
 
 
269
    return 0;
 
270
}