/* separate thread to handle non-pollable video (v4l1) */ static void *proc_video_thread (void *arg) { zebra_processor_t *proc = arg; proc_block_sigs(); (void)proc_lock(proc); while(1) { /* wait for active to be set */ assert(!proc->sem); assert(pthread_equal(proc->sem_owner, pthread_self())); pthread_mutex_lock(&proc->mutex); proc->sem++; pthread_cond_signal(&proc->cond); pthread_cleanup_push(proc_mutex_unlock, &proc->mutex); while(!proc->active) pthread_cond_wait(&proc->event, &proc->mutex); pthread_cleanup_pop(1); /* unlocked blocking image input */ zebra_image_t *img = zebra_video_next_image(proc->video); if(!img) return(NULL); (void)proc_lock(proc); if(proc->active) process_image(proc, img); zebra_image_destroy(img); } }
/* used by poll interface. lock is already held */ static int proc_video_handler (zebra_processor_t *proc, int i) { if(!proc->active) return(0); /* not expected to block */ zebra_image_t *img = zebra_video_next_image(proc->video); if(!img) return(-1); int rc = process_image(proc, img); zebra_image_destroy(img); return(rc); }
static inline int proc_event_wait_unthreaded (zebra_processor_t *proc, unsigned event, int timeout, struct timespec *abstime) { int blocking = proc->active && zebra_video_get_fd(proc->video) < 0; proc->events &= ~event; /* unthreaded, poll here for window input */ while(!(proc->events & event)) { if(blocking) { zebra_image_t *img = zebra_video_next_image(proc->video); if(!img) return(-1); process_image(proc, img); zebra_image_destroy(img); } int reltime = timeout; if(reltime >= 0) { struct timespec now; #if _POSIX_TIMERS > 0 clock_gettime(CLOCK_REALTIME, &now); #else struct timeval ustime; gettimeofday(&ustime, NULL); now.tv_nsec = ustime.tv_usec * 1000; now.tv_sec = ustime.tv_sec; #endif reltime = ((abstime->tv_sec - now.tv_sec) * 1000 + (abstime->tv_nsec - now.tv_nsec) / 1000000); if(reltime <= 0) return(0); } if(blocking && (reltime < 0 || reltime > 10)) reltime = 10; if(proc->polling.num) proc_poll_inputs(proc, (poll_desc_t*)&proc->polling, reltime); else if(!blocking) { proc_unlock(proc); struct timespec sleepns, remns; sleepns.tv_sec = timeout / 1000; sleepns.tv_nsec = (timeout % 1000) * 1000000; while(nanosleep(&sleepns, &remns) && errno == EINTR) sleepns = remns; (void)proc_lock(proc); return(0); } } return(1); }
/* lock is already held */ static inline int process_image (zebra_processor_t *proc, zebra_image_t *img) { if(img) { uint32_t format = zebra_image_get_format(img); zprintf(16, "processing: %.4s(%08" PRIx32 ") %dx%d @%p\n", (char*)&format, format, zebra_image_get_width(img), zebra_image_get_height(img), zebra_image_get_data(img)); /* FIXME locking all other interfaces while processing is conservative * but easier for now and we don't expect this to take long... */ int nsyms = zebra_scan_image(proc->scanner, img); if(nsyms < 0) return(err_capture(proc, SEV_ERROR, ZEBRA_ERR_UNSUPPORTED, __func__, "unknown image format")); if(_zebra_verbosity >= 8) { const zebra_symbol_t *sym = zebra_image_first_symbol(img); while(sym) { zebra_symbol_type_t type = zebra_symbol_get_type(sym); int count = zebra_symbol_get_count(sym); zprintf(8, "%s%s: %s (%s)\n", zebra_get_symbol_name(type), zebra_get_addon_name(type), zebra_symbol_get_data(sym), (count < 0) ? "uncertain" : (count > 0) ? "duplicate" : "new"); sym = zebra_symbol_next(sym); } } if(nsyms) { emit(proc, EVENT_OUTPUT); if(proc->handler) /* FIXME only call after filtering (unlocked...?) */ proc->handler(img, proc->userdata); } if(proc->force_output) { img = zebra_image_convert(img, proc->force_output); if(!img) return(err_capture(proc, SEV_ERROR, ZEBRA_ERR_UNSUPPORTED, __func__, "unknown image format")); } } /* display to window if enabled */ if(proc->window && (zebra_window_draw(proc->window, img) || _zebra_window_invalidate(proc->window))) return(err_copy(proc, proc->window)); #if 0 /* FIXME still don't understand why we need this */ if(proc->window && _zebra_window_handle_events(proc, 0)) return(-1); #endif if(proc->force_output && img) zebra_image_destroy(img); return(0); }
int zebra_scan_image (zebra_image_scanner_t *iscn, zebra_image_t *img) { recycle_syms(iscn, img); /* get grayscale image, convert if necessary */ /*img = zebra_image_convert(img, fourcc('Y','8','0','0'));*/ if(!img) return(-1); unsigned w = zebra_image_get_width(img); unsigned h = zebra_image_get_height(img); const uint8_t *data = zebra_image_get_data(img); const uint8_t *p = data; int x = 0, y = 0; #ifdef DEBUG_IMG_SCANNER movedelta(0, (h + 1) / 2); #else movedelta(0, 8); #endif if(zebra_scanner_new_scan(iscn->scn)) symbol_handler(iscn, x, y); /* FIXME add density config api */ /* FIXME less arbitrary lead-out default */ int quiet = w / 32; if(quiet < 8) quiet = 8; while(y < h) { zprintf(32, "img_x+: %03x,%03x @%p\n", x, y, p); while(x < w) { ASSERT_POS; if(zebra_scan_y(iscn->scn, *p)) symbol_handler(iscn, x, y); movedelta(1, 0); } quiet_border(iscn, quiet, x, y); movedelta(-1, 16); if(y >= h) break; zprintf(32, "img_x-: %03x,%03x @%p\n", x, y, p); while(x > 0) { ASSERT_POS; if(zebra_scan_y(iscn->scn, *p)) symbol_handler(iscn, x, y); movedelta(-1, 0); } quiet_border(iscn, quiet, x, y); movedelta(1, 16); #ifdef DEBUG_IMG_SCANNER break; #endif } #ifndef DEBUG_IMG_SCANNER x = y = 0; p = data; movedelta(8, 0); while(x < w) { zprintf(32, "img_y+: %03x,%03x @%p\n", x, y, p); while(y < h) { ASSERT_POS; if(zebra_scan_y(iscn->scn, *p)) symbol_handler(iscn, x, y); movedelta(0, 1); } quiet_border(iscn, quiet, x, y); movedelta(16, -1); if(x >= w) break; zprintf(32, "img_y-: %03x,%03x @%p\n", x, y, p); while(y >= 0) { ASSERT_POS; if(zebra_scan_y(iscn->scn, *p)) symbol_handler(iscn, x, y); movedelta(0, -1); } quiet_border(iscn, quiet, x, y); movedelta(16, 1); } #endif /* flush scanner pipe */ if(zebra_scanner_new_scan(iscn->scn)) symbol_handler(iscn, x, y); /* release reference */ zebra_image_destroy(img); return(iscn->img->nsyms); }