summaryrefslogtreecommitdiffstats
path: root/ipecamera/data.c
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-12-12 05:45:35 +0100
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-12-12 05:45:35 +0100
commit2e4e8a00b27182a155cb10f0a00e44977bfcd5cf (patch)
tree86afd1b7ceb834dbb3cedf8d55c3ac0734947333 /ipecamera/data.c
parent7a4cfb9e546c496792d3fe0c61c822c66ad0128f (diff)
downloadipecamera-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.c270
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;
+}