diff options
author | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-12-12 05:45:35 +0100 |
---|---|---|
committer | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-12-12 05:45:35 +0100 |
commit | 2e4e8a00b27182a155cb10f0a00e44977bfcd5cf (patch) | |
tree | 86afd1b7ceb834dbb3cedf8d55c3ac0734947333 /ipecamera/data.c | |
parent | 7a4cfb9e546c496792d3fe0c61c822c66ad0128f (diff) | |
download | ipecamera-2e4e8a00b27182a155cb10f0a00e44977bfcd5cf.tar.gz ipecamera-2e4e8a00b27182a155cb10f0a00e44977bfcd5cf.tar.bz2 ipecamera-2e4e8a00b27182a155cb10f0a00e44977bfcd5cf.tar.xz ipecamera-2e4e8a00b27182a155cb10f0a00e44977bfcd5cf.zip |
multithread preprocessing of ipecamera frames and code reorganization
Diffstat (limited to 'ipecamera/data.c')
-rw-r--r-- | ipecamera/data.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/ipecamera/data.c b/ipecamera/data.c new file mode 100644 index 0000000..5de6617 --- /dev/null +++ b/ipecamera/data.c @@ -0,0 +1,270 @@ +#define _IPECAMERA_IMAGE_C +#define _BSD_SOURCE +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <pthread.h> +#include <assert.h> + +#include <ufodecode.h> + +#include "../tools.h" +#include "../error.h" + +#include "pcilib.h" +#include "private.h" +#include "data.h" + +// DS: Currently, on event_id overflow we are assuming the buffer is lost +static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) { + pcilib_event_id_t diff; + + if (evid > ctx->event_id) { + diff = (((pcilib_event_id_t)-1) - ctx->event_id) + evid; + if (diff >= ctx->buffer_size) return -1; + } else { + diff = ctx->event_id - evid; + if (diff >= ctx->buffer_size) return -1; + } + + // DS: Request buffer_size to be power of 2 and replace to shifts (just recompute in set_buffer_size) + return (evid - 1) % ctx->buffer_size; +} + +inline static int ipecamera_decode_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) { + int err = 0; + uint32_t tmp; + uint16_t *pixels; + + int buf_ptr = ipecamera_resolve_event_id(ctx, event_id); + if (buf_ptr < 0) return PCILIB_ERROR_TIMEOUT; + + if (ctx->frame[buf_ptr].event.image_ready) return 0; + + if (ctx->frame[buf_ptr].event.info.flags&PCILIB_EVENT_INFO_FLAG_BROKEN) { + ctx->frame[buf_ptr].event.image_broken = 1; + err = PCILIB_ERROR_INVALID_DATA; + goto ready; + } + + + pixels = ctx->image + buf_ptr * ctx->image_size; + memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t)); + 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); + if (err) { + ctx->frame[buf_ptr].event.image_broken = 1; + err = PCILIB_ERROR_FAILED; + goto ready; + } + + ctx->frame[buf_ptr].event.image_broken = 0; + +ready: + ctx->frame[buf_ptr].event.image_ready = 1; + + if (ipecamera_resolve_event_id(ctx, event_id) < 0) { + ctx->frame[buf_ptr].event.image_ready = 0; + return PCILIB_ERROR_TIMEOUT; + } + + return err; +} + +static int ipecamera_get_next_buffer_to_process(ipecamera_t *ctx, pcilib_event_id_t *evid) { + int res; + + if (ctx->preproc_id == ctx->event_id) return -1; + + if (ctx->preproc) + pthread_mutex_lock(&ctx->preproc_mutex); + + if (ctx->preproc_id == ctx->event_id) { + if (ctx->preproc) + pthread_mutex_unlock(&ctx->preproc_mutex); + return -1; + } + + 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; + + res = ctx->preproc_id%ctx->buffer_size; + + if (pthread_rwlock_trywrlock(&ctx->frame[res].mutex)) { + pthread_mutex_unlock(&ctx->preproc_mutex); + return -1; + } + + *evid = ++ctx->preproc_id; + + if (ctx->preproc) + pthread_mutex_unlock(&ctx->preproc_mutex); + + return res; +} + + +void *ipecamera_preproc_thread(void *user) { + int buf_ptr; + pcilib_event_id_t evid; + + ipecamera_preprocessor_t *preproc = (ipecamera_preprocessor_t*)user; + ipecamera_t *ctx = preproc->ipecamera; + + while (ctx->run_preprocessors) { + buf_ptr = ipecamera_get_next_buffer_to_process(ctx, &evid); + if (buf_ptr < 0) { + usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP); + continue; + } + + ipecamera_decode_frame(ctx, evid); + + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + } + + return NULL; +} + +static int ipecamera_get_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) { + int err; + int buf_ptr = (event_id - 1) % ctx->buffer_size; + + if (!ctx->preproc) { + pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex); + + err = ipecamera_decode_frame(ctx, event_id); + + if (err) { + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + return err; + } + + return 0; + } + + + while (!ctx->frame[buf_ptr].event.image_ready) { + usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP); + + buf_ptr = ipecamera_resolve_event_id(ctx, event_id); + if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN; + } + + pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex); + + buf_ptr = ipecamera_resolve_event_id(ctx, event_id); + if ((buf_ptr < 0)||(!ctx->frame[buf_ptr].event.image_ready)) { + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + return PCILIB_ERROR_OVERWRITTEN; + } + + return 0; +} + + +/* + We will lock the data for non-raw data to prevent ocasional overwritting. The + raw data will be overwritten by the reader thread anyway and we can't do + anything to prevent it for performance reasons. +*/ +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) { + int err; + int buf_ptr; + size_t raw_size; + ipecamera_t *ctx = (ipecamera_t*)vctx; + + void *data = *ret; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + buf_ptr = ipecamera_resolve_event_id(ctx, event_id); + if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN; + + switch ((ipecamera_data_type_t)data_type) { + case IPECAMERA_RAW_DATA: + raw_size = ctx->frame[buf_ptr].event.raw_size; + if (data) { + if ((!size)||(*size < raw_size)) return PCILIB_ERROR_TOOBIG; + memcpy(data, ctx->buffer + buf_ptr * ctx->padded_size, raw_size); + if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN; + *size = raw_size; + return 0; + } + if (size) *size = raw_size; + *ret = ctx->buffer + buf_ptr * ctx->padded_size; + return 0; + case IPECAMERA_IMAGE_DATA: + err = ipecamera_get_frame(ctx, event_id); + if (err) return err; + + if (data) { + if ((!size)||(*size < ctx->image_size * sizeof(ipecamera_pixel_t))) return PCILIB_ERROR_TOOBIG; + memcpy(data, ctx->image + buf_ptr * ctx->image_size, ctx->image_size * sizeof(ipecamera_pixel_t)); + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + *size = ctx->image_size * sizeof(ipecamera_pixel_t); + return 0; + } + + if (size) *size = ctx->image_size * sizeof(ipecamera_pixel_t); + *ret = ctx->image + buf_ptr * ctx->image_size; + return 0; + case IPECAMERA_CHANGE_MASK: + err = ipecamera_get_frame(ctx, event_id); + if (err) return err; + + if (data) { + if ((!size)||(*size < ctx->dim.height * sizeof(ipecamera_change_mask_t))) return PCILIB_ERROR_TOOBIG; + memcpy(data, ctx->image + buf_ptr * ctx->dim.height, ctx->dim.height * sizeof(ipecamera_change_mask_t)); + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + *size = ctx->dim.height * sizeof(ipecamera_change_mask_t); + return 0; + } + + if (size) *size = ctx->dim.height * sizeof(ipecamera_change_mask_t); + *ret = ctx->cmask + buf_ptr * ctx->dim.height; + return 0; + case IPECAMERA_DIMENSIONS: + if (size) *size = sizeof(ipecamera_image_dimensions_t); + ret = (void*)&ctx->dim; + return 0; + case IPECAMERA_IMAGE_REGION: + case IPECAMERA_PACKED_IMAGE: + // Shall we return complete image or only changed parts? + case IPECAMERA_PACKED_LINE: + case IPECAMERA_PACKED_PAYLOAD: + pcilib_error("Support for data type (%li) is not implemented yet", data_type); + return PCILIB_ERROR_NOTSUPPORTED; + default: + pcilib_error("Unknown data type (%li) is requested", data_type); + return PCILIB_ERROR_INVALID_REQUEST; + } +} + + +/* + We will unlock non-raw data and check if the raw data is not overwritten yet +*/ +int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) { + ipecamera_t *ctx = (ipecamera_t*)vctx; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + + } + + if ((ipecamera_data_type_t)data_type == IPECAMERA_RAW_DATA) { + if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN; + } else { + int buf_ptr = (event_id - 1) % ctx->buffer_size; + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + } + + return 0; +} |