diff --git a/demo/camera.c b/demo/camera.c index 56b524e..5173991 100644 --- a/demo/camera.c +++ b/demo/camera.c @@ -1,5 +1,5 @@ /* quirc -- QR-code recognition library - * Copyright (C) 2010-2012 Daniel Beer + * Copyright (C) 2010-2014 Daniel Beer * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,208 +14,574 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include #include -#include -#include #include -#include +#include +#include +#include #include -#include - +#include +#include +#include #include "camera.h" -static int set_video_format(struct camera *cam, uint32_t format, - int w, int h, camera_format_t my_fmt) +/************************************************************************ + * Fraction arithmetic + */ + +static int gcd(int a, int b) +{ + if (a < 0) + a = -a; + if (b < 0) + b = -b; + + for (;;) { + if (a < b) { + const int t = a; + + a = b; + b = t; + } + + if (!b) + break; + + a %= b; + } + + return a; +} + +static void frac_reduce(const struct v4l2_fract *f, struct v4l2_fract *g) +{ + const int x = gcd(f->numerator, f->denominator); + int n = f->numerator; + int d = f->denominator; + + if (d < 0) { + n = -n; + d = -d; + } + + g->numerator = n / x; + g->denominator = d / x; +} + +static void frac_add(const struct v4l2_fract *a, const struct v4l2_fract *b, + struct v4l2_fract *r) +{ + r->numerator = a->numerator * b->denominator + + b->numerator * b->denominator; + r->denominator = a->denominator * b->denominator; + + frac_reduce(r, r); +} + +static void frac_sub(const struct v4l2_fract *a, const struct v4l2_fract *b, + struct v4l2_fract *r) +{ + r->numerator = a->numerator * b->denominator - + b->numerator * b->denominator; + r->denominator = a->denominator * b->denominator; + + frac_reduce(r, r); +} + +static int frac_cmp(const struct v4l2_fract *a, const struct v4l2_fract *b) +{ + return a->numerator * b->denominator - b->numerator * b->denominator; +} + +static void frac_mul(const struct v4l2_fract *a, const struct v4l2_fract *b, + struct v4l2_fract *r) +{ + r->numerator = a->numerator * b->numerator; + r->denominator = a->denominator * b->denominator; + + frac_reduce(r, r); +} + +static void frac_div(const struct v4l2_fract *a, const struct v4l2_fract *b, + struct v4l2_fract *r) +{ + r->numerator = a->numerator * b->denominator; + r->denominator = a->denominator * b->numerator; + + frac_reduce(r, r); +} + +static int frac_cmp_ref(const struct v4l2_fract *ref, + const struct v4l2_fract *a, + const struct v4l2_fract *b) +{ + struct v4l2_fract da; + struct v4l2_fract db; + + frac_sub(a, ref, &da); + frac_sub(b, ref, &db); + + if (da.numerator < 0) + da.numerator = -da.numerator; + if (db.numerator < 0) + db.numerator = -db.numerator; + + return frac_cmp(&da, &db); +} + +/************************************************************************ + * Parameter searching and choosing + */ + +static camera_format_t map_fmt(uint32_t pf) +{ + if (pf == V4L2_PIX_FMT_YUYV) + return CAMERA_FORMAT_YUYV; + + if (pf == V4L2_PIX_FMT_MJPEG) + return CAMERA_FORMAT_MJPEG; + + return CAMERA_FORMAT_UNKNOWN; +} + +static int find_best_format(int fd, uint32_t *fmt_ret) +{ + struct v4l2_fmtdesc best; + int i = 1; + + memset(&best, 0, sizeof(best)); + best.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + best.index = 0; + + if (ioctl(fd, VIDIOC_ENUM_FMT, &best) < 0) + return -1; + + for (;;) { + struct v4l2_fmtdesc f; + + memset(&f, 0, sizeof(f)); + f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f.index = ++i; + + if (ioctl(fd, VIDIOC_ENUM_FMT, &f) < 0) + break; + + if (map_fmt(f.pixelformat) > map_fmt(best.pixelformat)) + memcpy(&best, &f, sizeof(best)); + } + + if (fmt_ret) + *fmt_ret = best.pixelformat; + + return 0; +} + +static int step_to_discrete(int min, int max, int step, int target) +{ + int offset; + + if (target < min) + return min; + + if (target > max) + return max; + + offset = (target - min) % step; + if ((offset * 2 > step) && (target + step <= max)) + target += step; + + return target - offset; +} + +static int score_discrete(const struct v4l2_frmsizeenum *f, int w, int h) +{ + const int dw = f->discrete.width - w; + const int dh = f->discrete.height - h; + + return dw * dw + dh * dh; +} + +static int find_best_size(int fd, uint32_t pixel_format, + int target_w, int target_h, + int *ret_w, int *ret_h) +{ + struct v4l2_frmsizeenum best; + int i = 1; + + memset(&best, 0, sizeof(best)); + best.index = 0; + best.pixel_format = pixel_format; + + if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &best) < 0) + return -1; + + if (best.type != V4L2_FRMSIZE_TYPE_DISCRETE) { + *ret_w = step_to_discrete(best.stepwise.min_width, + best.stepwise.max_width, + best.stepwise.step_width, + target_w); + *ret_h = step_to_discrete(best.stepwise.min_height, + best.stepwise.max_height, + best.stepwise.step_height, + target_h); + return 0; + } + + for (;;) { + struct v4l2_frmsizeenum f; + + memset(&f, 0, sizeof(f)); + f.index = ++i; + f.pixel_format = pixel_format; + + if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &f) < 0) + break; + + if (score_discrete(&f, target_w, target_h) < + score_discrete(&best, target_w, target_h)) + memcpy(&best, &f, sizeof(best)); + } + + *ret_w = best.discrete.width; + *ret_h = best.discrete.height; + + return 0; +} + +static int find_best_rate(int fd, uint32_t pixel_format, + int w, int h, int target_n, int target_d, + int *ret_n, int *ret_d) +{ + const struct v4l2_fract target = { + .numerator = target_n, + .denominator = target_d + }; + struct v4l2_frmivalenum best; + int i = 1; + + memset(&best, 0, sizeof(best)); + best.index = 0; + best.pixel_format = pixel_format; + best.width = w; + best.height = h; + + if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &best) < 0) + return -1; + + if (best.type != V4L2_FRMIVAL_TYPE_DISCRETE) { + struct v4l2_fract t; + + if (frac_cmp(&target, &best.stepwise.min) < 0) { + *ret_n = best.stepwise.min.numerator; + *ret_d = best.stepwise.min.denominator; + } + + if (frac_cmp(&target, &best.stepwise.max) > 0) { + *ret_n = best.stepwise.max.numerator; + *ret_d = best.stepwise.max.denominator; + } + + frac_sub(&target, &best.stepwise.min, &t); + frac_div(&t, &best.stepwise.step, &t); + if (t.numerator * 2 >= t.denominator) + t.numerator += t.denominator; + t.numerator /= t.denominator; + t.denominator = 1; + frac_mul(&t, &best.stepwise.step, &t); + frac_add(&t, &best.stepwise.max, &t); + + if (frac_cmp(&t, &best.stepwise.max) > 0) { + *ret_n = best.stepwise.max.numerator; + *ret_d = best.stepwise.max.denominator; + } else { + *ret_n = t.numerator; + *ret_d = t.denominator; + } + + return 0; + } + + for (;;) { + struct v4l2_frmivalenum f; + + memset(&f, 0, sizeof(f)); + f.index = ++i; + f.pixel_format = pixel_format; + f.width = w; + f.height = h; + + if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &f) < 0) + break; + + if (frac_cmp_ref(&target, &f.discrete, &best.discrete) < 0) + memcpy(&best, &f, sizeof(best)); + } + + *ret_n = best.discrete.numerator; + *ret_d = best.discrete.denominator; + + return 0; +} + +/************************************************************************ + * Public interface + */ + +void camera_init(struct camera *c) +{ + c->fd = -1; + c->buf_count = 0; + c->s_on = 0; +} + +void camera_destroy(struct camera *c) +{ + camera_close(c); +} + +int camera_open(struct camera *c, const char *path, + int target_w, int target_h, + int tr_n, int tr_d) { struct v4l2_format fmt; + struct v4l2_streamparm parm; + uint32_t pf; + int w, h; + int n, d; + if (c->fd >= 0) + camera_close(c); + + /* Open device and get basic properties */ + c->fd = open(path, O_RDWR); + if (c->fd < 0) + return -1; + + /* Find a pixel format from the list */ + if (find_best_format(c->fd, &pf) < 0) + goto fail; + + /* Find a frame size */ + if (find_best_size(c->fd, pf, target_w, target_h, &w, &h) < 0) + goto fail; + + /* Find a frame rate */ + if (find_best_rate(c->fd, pf, w, h, tr_n, tr_d, &n, &d) < 0) + goto fail; + + /* Set format */ memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = w; fmt.fmt.pix.height = h; - fmt.fmt.pix.pixelformat = format; - fmt.fmt.pix.field = V4L2_FIELD_ANY; - - if (ioctl(cam->fd, VIDIOC_S_FMT, &fmt) < 0) - return -1; - - /* Note that the size obtained may not match what was requested. */ - cam->format = my_fmt; - cam->width = fmt.fmt.pix.width; - cam->height = fmt.fmt.pix.height; - - return 0; -} - -int camera_set_gain(struct camera *cam, int value) -{ - struct v4l2_queryctrl query; - struct v4l2_control ctrl; - - query.id = V4L2_CID_GAIN; - if (ioctl(cam->fd, VIDIOC_QUERYCTRL, &query) < 0) { - perror("ioctl: VIDIOC_QUERYCTRL"); - return -1; - } - - ctrl.id = V4L2_CID_GAIN; - - if (value < 0) - ctrl.value = query.default_value; - else - ctrl.value = value; - - if (ioctl(cam->fd, VIDIOC_S_CTRL, &ctrl) < 0) { - perror("ioctl: VIDIOC_S_CTRL"); - return -1; - } - - return 0; -} - -int camera_init(struct camera *cam, const char *path, int width, int height) -{ - struct v4l2_streamparm fps; - struct v4l2_requestbuffers rb; - int type; - int i; - - cam->fd = open(path, O_RDONLY); - if (cam->fd < 0) { - fprintf(stderr, "%s: can't open camera device: %s\n", path, - strerror(errno)); - return -1; - } - - /* Set the video format */ - if (set_video_format(cam, V4L2_PIX_FMT_MJPEG, - width, height, CAMERA_FORMAT_MJPEG) < 0 && - set_video_format(cam, V4L2_PIX_FMT_YUYV, - width, height, CAMERA_FORMAT_YUYV) < 0) { - fprintf(stderr, "%s: can't find a supported video format\n", - path); + fmt.fmt.pix.pixelformat = pf; + if (ioctl(c->fd, VIDIOC_S_FMT, &fmt) < 0) goto fail; - } - /* Set the frame rate */ - memset(&fps, 0, sizeof(fps)); - fps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fps.parm.capture.timeperframe.numerator = 1; - fps.parm.capture.timeperframe.denominator = 20; - - if (ioctl(cam->fd, VIDIOC_S_PARM, &fps) < 0) { - fprintf(stderr, "%s: can't set video frame rate: %s\n", path, - strerror(errno)); + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(c->fd, VIDIOC_G_FMT, &fmt) < 0) goto fail; - } - /* Request buffer */ - memset(&rb, 0, sizeof(rb)); - rb.count = CAMERA_BUFFERS; - rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - rb.memory = V4L2_MEMORY_MMAP; - - if (ioctl(cam->fd, VIDIOC_REQBUFS, &rb) < 0) { - fprintf(stderr, "%s: can't request buffers: %s\n", path, - strerror(errno)); + /* Set frame interval */ + memset(&parm, 0, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + parm.parm.capture.timeperframe.numerator = n; + parm.parm.capture.timeperframe.denominator = d; + if (ioctl(c->fd, VIDIOC_S_PARM, &parm) < 0) goto fail; - } - /* Map buffers and submit them */ - for (i = 0; i < CAMERA_BUFFERS; i++) { - struct v4l2_buffer buf; - - memset(&buf, 0, sizeof(buf)); - buf.index = i; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - if (ioctl(cam->fd, VIDIOC_QUERYBUF, &buf) < 0) { - fprintf(stderr, "%s: can't query buffer: %s\n", path, - strerror(errno)); - goto fail; - } - - cam->buffer_maps[i] = mmap(0, buf.length, - PROT_READ, MAP_SHARED, cam->fd, buf.m.offset); - if (cam->buffer_maps[i] == MAP_FAILED) { - fprintf(stderr, "%s: can't map buffer memory: %s\n", - path, strerror(errno)); - goto fail; - } - - cam->buffer_lens[i] = buf.length; - } - - /* Switch on streaming */ - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (ioctl(cam->fd, VIDIOC_STREAMON, &type) < 0) { - fprintf(stderr, "%s: can't enable streaming: %s\n", path, - strerror(errno)); + memset(&parm, 0, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(c->fd, VIDIOC_G_PARM, &parm) < 0) goto fail; - } - /* Queue the buffers */ - for (i = 0; i < CAMERA_BUFFERS; i++) { - struct v4l2_buffer buf; + c->parms.format = map_fmt(fmt.fmt.pix.pixelformat); + c->parms.width = fmt.fmt.pix.width; + c->parms.height = fmt.fmt.pix.height; + c->parms.pitch_bytes = fmt.fmt.pix.bytesperline; + c->parms.interval_n = parm.parm.capture.timeperframe.numerator; + c->parms.interval_d = parm.parm.capture.timeperframe.denominator; - memset(&buf, 0, sizeof(buf)); - buf.index = i; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - - if (ioctl(cam->fd, VIDIOC_QBUF, &buf) < 0) { - perror("can't start buffer queue"); - return -1; - } - } - - cam->mem_index = -1; return 0; fail: - close(cam->fd); + { + const int e = errno; + + close(c->fd); + c->fd = -1; + errno = e; + } + return -1; } -void camera_free(struct camera *cam) +void camera_close(struct camera *c) { - int i; + camera_off(c); + camera_unmap(c); - for (i = 0; i < CAMERA_BUFFERS; i++) - munmap(cam->buffer_maps[i], cam->buffer_lens[i]); - close(cam->fd); + if (c->fd < 0) + return; + + close(c->fd); + c->fd = -1; } -int camera_update(struct camera *cam) +int camera_map(struct camera *c, int buf_count) { - struct v4l2_buffer buf; - int last_index = cam->mem_index; + struct v4l2_requestbuffers reqbuf; + int count; + int i; - /* De-queue a buffer */ - memset(&buf, 0, sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - if (ioctl(cam->fd, VIDIOC_DQBUF, &buf) < 0) { - perror("can't de-queue buffer"); + if (buf_count > CAMERA_MAX_BUFFERS) + buf_count = CAMERA_MAX_BUFFERS; + + if (buf_count <= 0) { + errno = EINVAL; return -1; } - cam->mem_index = buf.index; - cam->mem = cam->buffer_maps[cam->mem_index]; - cam->mem_len = cam->buffer_lens[cam->mem_index]; + if (c->fd < 0) { + errno = EBADF; + return -1; + } + + if (c->buf_count) + camera_unmap(c); + + memset(&reqbuf, 0, sizeof(reqbuf)); + reqbuf.count = buf_count; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf.memory = V4L2_MEMORY_MMAP; + + if (ioctl(c->fd, VIDIOC_REQBUFS, &reqbuf) < 0) + return -1; + + count = reqbuf.count; + if (count > CAMERA_MAX_BUFFERS) + count = CAMERA_MAX_BUFFERS; + + /* Query all buffers */ + for (i = 0; i < count; i++) { + struct v4l2_buffer buf; + struct camera_buffer *cb = &c->buf_desc[i]; - /* Re-queue the last buffer */ - if (last_index >= 0) { memset(&buf, 0, sizeof(buf)); - buf.index = last_index; + buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; - if (ioctl(cam->fd, VIDIOC_QBUF, &buf) < 0) { - perror("can't queue buffer"); + if (ioctl(c->fd, VIDIOC_QUERYBUF, &buf) < 0) + return -1; + + cb->offset = buf.m.offset; + cb->size = buf.length; + cb->addr = mmap(NULL, cb->size, PROT_READ, + MAP_SHARED, c->fd, cb->offset); + + if (cb->addr == MAP_FAILED) { + const int save = errno; + + i--; + while (i >= 0) { + cb = &c->buf_desc[i--]; + munmap(cb->addr, cb->size); + } + + errno = save; return -1; } } + c->buf_count = count; + return 0; +} + +void camera_unmap(struct camera *c) +{ + int i; + + for (i = 0; i < c->buf_count; i++) { + struct camera_buffer *cb = &c->buf_desc[i]; + + munmap(cb->addr, cb->size); + } + + c->buf_count = 0; +} + +int camera_on(struct camera *c) +{ + int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (c->s_on) + return 0; + + if (c->fd < 0) { + errno = EBADF; + return -1; + } + + if (ioctl(c->fd, VIDIOC_STREAMON, &type) < 0) + return -1; + + c->s_on = 1; + c->s_qc = 0; + c->s_qhead = 0; + return 0; +} + +void camera_off(struct camera *c) +{ + int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (!c->s_on) + return; + + ioctl(c->fd, VIDIOC_STREAMOFF, &type); + c->s_on = 0; +} + +int camera_enqueue_all(struct camera *c) +{ + while (c->s_qc < c->buf_count) { + struct v4l2_buffer buf; + + memset(&buf, 0, sizeof(buf)); + buf.index = (c->s_qc + c->s_qhead) % c->buf_count; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + if (ioctl(c->fd, VIDIOC_QBUF, &buf) < 0) + return -1; + + c->s_qc++; + } + + return 0; +} + +int camera_dequeue_one(struct camera *c) +{ + struct v4l2_buffer buf; + + if (!c->s_qc) { + errno = EINVAL; + return -1; + } + + memset(&buf, 0, sizeof(buf)); + buf.memory = V4L2_MEMORY_MMAP; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (ioctl(c->fd, VIDIOC_DQBUF, &buf) < 0) + return -1; + + c->s_qc--; + if (++c->s_qhead >= c->buf_count) + c->s_qhead = 0; + return 0; } diff --git a/demo/camera.h b/demo/camera.h index e91ea44..511b5bd 100644 --- a/demo/camera.h +++ b/demo/camera.h @@ -1,5 +1,5 @@ /* quirc -- QR-code recognition library - * Copyright (C) 2010-2012 Daniel Beer + * Copyright (C) 2010-2014 Daniel Beer * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,54 +17,88 @@ #ifndef CAMERA_H_ #define CAMERA_H_ -#include +#include -#define CAMERA_BUFFERS 8 +#define CAMERA_MAX_BUFFERS 32 typedef enum { + CAMERA_FORMAT_UNKNOWN = 0, CAMERA_FORMAT_MJPEG, CAMERA_FORMAT_YUYV } camera_format_t; -struct camera { - /* File descriptor for camera device. */ - int fd; - - /* Width, height and frame pixel format. Once initialized, - * these values will not change. - */ +struct camera_parms { + camera_format_t format; int width; int height; - camera_format_t format; - - /* Buffer information for the current frame. If mem_index < 0, - * then no frame is currently available. - */ - uint8_t *mem; - int mem_len; - int mem_index; - - /* Pointers and sizes of memory-mapped buffers. */ - uint8_t *buffer_maps[CAMERA_BUFFERS]; - int buffer_lens[CAMERA_BUFFERS]; + int pitch_bytes; + int interval_n; + int interval_d; }; -/* Set up a camera driver. This opens the video device and configures for - * the given resolution. Streaming is started immediately. - * - * Returns 0 on success or -1 if an error occurs. - */ -int camera_init(struct camera *cam, const char *path, int width, int height); +struct camera_buffer { + void *addr; + size_t size; + unsigned long offset; +}; -/* Set the gain control for the camera device. */ -int camera_set_gain(struct camera *cam, int gain); +struct camera { + int fd; -/* Shut down the camera device and free allocated memory. */ -void camera_free(struct camera *cam); + struct camera_parms parms; -/* Retrieve the latest frame from the video queue and fill out the mem and - * mem_len fields in the camera struct. - */ -int camera_update(struct camera *cam); + struct camera_buffer buf_desc[CAMERA_MAX_BUFFERS]; + int buf_count; + + /* Stream state */ + int s_on; + int s_qc; + int s_qhead; +}; + +/* Initialize/destroy a camera. No resources are allocated. */ +void camera_init(struct camera *c); +void camera_destroy(struct camera *c); + +/* Open/close the camera device */ +int camera_open(struct camera *c, const char *path, + int target_w, int target_h, + int tr_n, int tr_d); +void camera_close(struct camera *c); + +static inline int camera_get_fd(const struct camera *c) +{ + return c->fd; +} + +static inline const struct camera_parms *camera_get_parms + (const struct camera *c) +{ + return &c->parms; +} + +/* Map buffers */ +int camera_map(struct camera *c, int buf_count); +void camera_unmap(struct camera *c); + +static inline int camera_get_buf_count(const struct camera *c) +{ + return c->buf_count; +} + +/* Switch streaming on/off */ +int camera_on(struct camera *c); +void camera_off(struct camera *c); + +/* Enqueue/dequeue buffers (count = 0 means enqueue all) */ +int camera_enqueue_all(struct camera *c); +int camera_dequeue_one(struct camera *c); + +/* Fetch the oldest dequeued buffer */ +static inline const struct camera_buffer *camera_get_head + (const struct camera *c) +{ + return &c->buf_desc[(c->s_qhead + c->buf_count - 1) % c->buf_count]; +} #endif diff --git a/demo/demo.c b/demo/demo.c index 0922c85..903df2b 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -33,7 +33,6 @@ static int video_width = 640; static int video_height = 480; static int want_frame_rate = 0; static int want_verbose = 0; -static int gain_request = -1; static int printer_timeout = 2; static void fat_text(SDL_Surface *screen, int x, int y, const char *text) @@ -122,23 +121,38 @@ static int main_loop(struct camera *cam, SDL_Surface *screen, for (;;) { time_t now = time(NULL); + const struct camera_buffer *head; + const struct camera_parms *parms = camera_get_parms(cam); - if (camera_update(cam) < 0) + if (camera_dequeue_one(cam) < 0) { + perror("camera_dequeue_one"); return -1; + } + + head = camera_get_head(cam); SDL_LockSurface(screen); - switch (cam->format) { + switch (parms->format) { case CAMERA_FORMAT_MJPEG: - mjpeg_decode_rgb32(mj, cam->mem, cam->mem_len, + mjpeg_decode_rgb32(mj, head->addr, head->size, screen->pixels, screen->pitch, screen->w, screen->h); break; case CAMERA_FORMAT_YUYV: - yuyv_to_rgb32(cam->mem, cam->width * 2, - cam->width, cam->height, + yuyv_to_rgb32(head->addr, parms->width * 2, + parms->width, parms->height, screen->pixels, screen->pitch); break; + + default: + fprintf(stderr, "Unknown frame format\n"); + return -1; + } + + if (camera_enqueue_all(cam) < 0) { + perror("camera_enqueue_all"); + return -1; } rgb32_to_luma(screen->pixels, screen->pitch, @@ -177,13 +191,32 @@ static int run_demo(void) struct quirc *qr; struct camera cam; struct mjpeg_decoder mj; + const struct camera_parms *parms; SDL_Surface *screen; - int ret; - if (camera_init(&cam, camera_path, video_width, video_height) < 0) - return -1; + camera_init(&cam); + if (camera_open(&cam, camera_path, video_width, video_height, + 25, 1) < 0) { + perror("camera_open"); + goto fail_qr; + } - camera_set_gain(&cam, gain_request); + if (camera_map(&cam, 8) < 0) { + perror("camera_map"); + goto fail_qr; + } + + if (camera_on(&cam) < 0) { + perror("camera_on"); + goto fail_qr; + } + + if (camera_enqueue_all(&cam) < 0) { + perror("camera_enqueue_all"); + goto fail_qr; + } + + parms = camera_get_parms(&cam); qr = quirc_new(); if (!qr) { @@ -191,7 +224,7 @@ static int run_demo(void) goto fail_qr; } - if (quirc_resize(qr, cam.width, cam.height) < 0) { + if (quirc_resize(qr, parms->width, parms->height) < 0) { perror("couldn't allocate QR buffer"); goto fail_qr_resize; } @@ -201,7 +234,7 @@ static int run_demo(void) goto fail_sdl_init; } - screen = SDL_SetVideoMode(cam.width, cam.height, 32, + screen = SDL_SetVideoMode(parms->width, parms->height, 32, SDL_SWSURFACE | SDL_DOUBLEBUF); if (!screen) { perror("couldn't init video mode"); @@ -209,24 +242,27 @@ static int run_demo(void) } mjpeg_init(&mj); - ret = main_loop(&cam, screen, qr, &mj); + if (main_loop(&cam, screen, qr, &mj) < 0) + goto fail_main_loop; mjpeg_free(&mj); SDL_Quit(); quirc_destroy(qr); - camera_free(&cam); + camera_destroy(&cam); return 0; +fail_main_loop: + mjpeg_free(&mj); fail_video_mode: SDL_Quit(); fail_qr_resize: fail_sdl_init: quirc_destroy(qr); fail_qr: - camera_free(&cam); + camera_destroy(&cam); - return 0; + return -1; } static void usage(const char *progname) @@ -237,7 +273,6 @@ static void usage(const char *progname) " -v Show extra data for detected codes.\n" " -d Specify camera device path.\n" " -s Specify video dimensions.\n" -" -g Set camera gain.\n" " -p Set printer timeout (seconds).\n" " --help Show this information.\n" " --version Show library version information.\n", @@ -254,7 +289,7 @@ int main(int argc, char **argv) int opt; printf("quirc demo\n"); - printf("Copyright (C) 2010-2012 Daniel Beer \n"); + printf("Copyright (C) 2010-2014 Daniel Beer \n"); printf("\n"); while ((opt = getopt_long(argc, argv, "d:s:fvg:p:", @@ -289,10 +324,6 @@ int main(int argc, char **argv) camera_path = optarg; break; - case 'g': - gain_request = atoi(optarg); - break; - case '?': fprintf(stderr, "Try --help for usage information\n"); return -1; diff --git a/demo/scanner.c b/demo/scanner.c index 5d7877f..d2afe3f 100644 --- a/demo/scanner.c +++ b/demo/scanner.c @@ -32,7 +32,6 @@ static const char *camera_path = "/dev/video0"; static int video_width = 640; static int video_height = 480; static int want_verbose = 0; -static int gain_request = -1; static int printer_timeout = 2; static int main_loop(struct camera *cam, @@ -46,19 +45,34 @@ static int main_loop(struct camera *cam, int w, h; int i, count; uint8_t *buf = quirc_begin(q, &w, &h); + const struct camera_buffer *head; + const struct camera_parms *parms = camera_get_parms(cam); - if (camera_update(cam) < 0) + if (camera_dequeue_one(cam) < 0) { + perror("camera_dequeue_one"); return -1; + } - switch (cam->format) { + head = camera_get_head(cam); + + switch (parms->format) { case CAMERA_FORMAT_MJPEG: - mjpeg_decode_gray(mj, cam->mem, cam->mem_len, + mjpeg_decode_gray(mj, head->addr, head->size, buf, w, w, h); break; case CAMERA_FORMAT_YUYV: - yuyv_to_luma(cam->mem, w * 2, w, h, buf, w); + yuyv_to_luma(head->addr, w * 2, w, h, buf, w); break; + + default: + fprintf(stderr, "Unknown frame format\n"); + return -1; + } + + if (camera_enqueue_all(cam) < 0) { + perror("camera_enqueue_all"); + return -1; } quirc_end(q); @@ -80,12 +94,31 @@ static int run_scanner(void) struct quirc *qr; struct camera cam; struct mjpeg_decoder mj; - int ret; + const struct camera_parms *parms; - if (camera_init(&cam, camera_path, video_width, video_height) < 0) - return -1; + camera_init(&cam); + if (camera_open(&cam, camera_path, video_width, video_height, + 25, 1) < 0) { + perror("camera_open"); + goto fail_qr; + } - camera_set_gain(&cam, gain_request); + if (camera_map(&cam, 8) < 0) { + perror("camera_map"); + goto fail_qr; + } + + if (camera_on(&cam) < 0) { + perror("camera_on"); + goto fail_qr; + } + + if (camera_enqueue_all(&cam) < 0) { + perror("camera_enqueue_all"); + goto fail_qr; + } + + parms = camera_get_parms(&cam); qr = quirc_new(); if (!qr) { @@ -93,26 +126,29 @@ static int run_scanner(void) goto fail_qr; } - if (quirc_resize(qr, cam.width, cam.height) < 0) { + if (quirc_resize(qr, parms->width, parms->height) < 0) { perror("couldn't allocate QR buffer"); goto fail_qr_resize; } mjpeg_init(&mj); - ret = main_loop(&cam, qr, &mj); + if (main_loop(&cam, qr, &mj) < 0) + goto fail_main_loop; mjpeg_free(&mj); quirc_destroy(qr); - camera_free(&cam); + camera_destroy(&cam); return 0; +fail_main_loop: + mjpeg_free(&mj); fail_qr_resize: quirc_destroy(qr); fail_qr: - camera_free(&cam); + camera_destroy(&cam); - return 0; + return -1; } static void usage(const char *progname) @@ -122,7 +158,6 @@ static void usage(const char *progname) " -v Show extra data for detected codes.\n" " -d Specify camera device path.\n" " -s Specify video dimensions.\n" -" -g Set camera gain.\n" " -p Set printer timeout (seconds).\n" " --help Show this information.\n" " --version Show library version information.\n", @@ -170,10 +205,6 @@ int main(int argc, char **argv) camera_path = optarg; break; - case 'g': - gain_request = atoi(optarg); - break; - case '?': fprintf(stderr, "Try --help for usage information\n"); return -1;