demo: rewrite camera driver.

New camera driver doesn't depend on obsolete headers (linux/videodev.h),
and should work on more types of cameras.
This commit is contained in:
Daniel Beer 2014-10-20 16:59:45 +13:00
parent 42c79481e7
commit 3a3df0d1d6
4 changed files with 699 additions and 237 deletions

View file

@ -1,5 +1,5 @@
/* quirc -- QR-code recognition library /* quirc -- QR-code recognition library
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> * Copyright (C) 2010-2014 Daniel Beer <dlbeer@gmail.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <stdio.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/mman.h> #include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/videodev.h> #include <sys/mman.h>
#include <unistd.h>
#include <linux/videodev2.h>
#include "camera.h" #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_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)); memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = w; fmt.fmt.pix.width = w;
fmt.fmt.pix.height = h; fmt.fmt.pix.height = h;
fmt.fmt.pix.pixelformat = format; fmt.fmt.pix.pixelformat = pf;
fmt.fmt.pix.field = V4L2_FIELD_ANY; if (ioctl(c->fd, VIDIOC_S_FMT, &fmt) < 0)
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);
goto fail; goto fail;
}
/* Set the frame rate */ memset(&fmt, 0, sizeof(fmt));
memset(&fps, 0, sizeof(fps)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(c->fd, VIDIOC_G_FMT, &fmt) < 0)
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));
goto fail; goto fail;
}
/* Request buffer */ /* Set frame interval */
memset(&rb, 0, sizeof(rb)); memset(&parm, 0, sizeof(parm));
rb.count = CAMERA_BUFFERS; parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; parm.parm.capture.timeperframe.numerator = n;
rb.memory = V4L2_MEMORY_MMAP; parm.parm.capture.timeperframe.denominator = d;
if (ioctl(c->fd, VIDIOC_S_PARM, &parm) < 0)
if (ioctl(cam->fd, VIDIOC_REQBUFS, &rb) < 0) {
fprintf(stderr, "%s: can't request buffers: %s\n", path,
strerror(errno));
goto fail; goto fail;
}
/* Map buffers and submit them */ memset(&parm, 0, sizeof(parm));
for (i = 0; i < CAMERA_BUFFERS; i++) { parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
struct v4l2_buffer buf; if (ioctl(c->fd, VIDIOC_G_PARM, &parm) < 0)
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));
goto fail; goto fail;
}
/* Queue the buffers */ c->parms.format = map_fmt(fmt.fmt.pix.pixelformat);
for (i = 0; i < CAMERA_BUFFERS; i++) { c->parms.width = fmt.fmt.pix.width;
struct v4l2_buffer buf; 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; return 0;
fail: fail:
close(cam->fd); {
const int e = errno;
close(c->fd);
c->fd = -1;
errno = e;
}
return -1; 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++) if (c->fd < 0)
munmap(cam->buffer_maps[i], cam->buffer_lens[i]); return;
close(cam->fd);
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; struct v4l2_requestbuffers reqbuf;
int last_index = cam->mem_index; int count;
int i;
/* De-queue a buffer */ if (buf_count > CAMERA_MAX_BUFFERS)
memset(&buf, 0, sizeof(buf)); buf_count = CAMERA_MAX_BUFFERS;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP; if (buf_count <= 0) {
if (ioctl(cam->fd, VIDIOC_DQBUF, &buf) < 0) { errno = EINVAL;
perror("can't de-queue buffer");
return -1; return -1;
} }
cam->mem_index = buf.index; if (c->fd < 0) {
cam->mem = cam->buffer_maps[cam->mem_index]; errno = EBADF;
cam->mem_len = cam->buffer_lens[cam->mem_index]; 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)); memset(&buf, 0, sizeof(buf));
buf.index = last_index; buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP; buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(cam->fd, VIDIOC_QBUF, &buf) < 0) { if (ioctl(c->fd, VIDIOC_QUERYBUF, &buf) < 0)
perror("can't queue buffer"); 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; 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; return 0;
} }

View file

@ -1,5 +1,5 @@
/* quirc -- QR-code recognition library /* quirc -- QR-code recognition library
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> * Copyright (C) 2010-2014 Daniel Beer <dlbeer@gmail.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -17,54 +17,88 @@
#ifndef CAMERA_H_ #ifndef CAMERA_H_
#define CAMERA_H_ #define CAMERA_H_
#include <stdint.h> #include <stddef.h>
#define CAMERA_BUFFERS 8 #define CAMERA_MAX_BUFFERS 32
typedef enum { typedef enum {
CAMERA_FORMAT_UNKNOWN = 0,
CAMERA_FORMAT_MJPEG, CAMERA_FORMAT_MJPEG,
CAMERA_FORMAT_YUYV CAMERA_FORMAT_YUYV
} camera_format_t; } camera_format_t;
struct camera { struct camera_parms {
/* File descriptor for camera device. */ camera_format_t format;
int fd;
/* Width, height and frame pixel format. Once initialized,
* these values will not change.
*/
int width; int width;
int height; int height;
camera_format_t format; int pitch_bytes;
int interval_n;
/* Buffer information for the current frame. If mem_index < 0, int interval_d;
* 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];
}; };
/* Set up a camera driver. This opens the video device and configures for struct camera_buffer {
* the given resolution. Streaming is started immediately. void *addr;
* size_t size;
* Returns 0 on success or -1 if an error occurs. unsigned long offset;
*/ };
int camera_init(struct camera *cam, const char *path, int width, int height);
/* Set the gain control for the camera device. */ struct camera {
int camera_set_gain(struct camera *cam, int gain); int fd;
/* Shut down the camera device and free allocated memory. */ struct camera_parms parms;
void camera_free(struct camera *cam);
/* Retrieve the latest frame from the video queue and fill out the mem and struct camera_buffer buf_desc[CAMERA_MAX_BUFFERS];
* mem_len fields in the camera struct. int buf_count;
*/
int camera_update(struct camera *cam); /* 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 #endif

View file

@ -33,7 +33,6 @@ static int video_width = 640;
static int video_height = 480; static int video_height = 480;
static int want_frame_rate = 0; static int want_frame_rate = 0;
static int want_verbose = 0; static int want_verbose = 0;
static int gain_request = -1;
static int printer_timeout = 2; static int printer_timeout = 2;
static void fat_text(SDL_Surface *screen, int x, int y, const char *text) 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 (;;) { for (;;) {
time_t now = time(NULL); 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; return -1;
}
head = camera_get_head(cam);
SDL_LockSurface(screen); SDL_LockSurface(screen);
switch (cam->format) { switch (parms->format) {
case CAMERA_FORMAT_MJPEG: 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->pixels, screen->pitch,
screen->w, screen->h); screen->w, screen->h);
break; break;
case CAMERA_FORMAT_YUYV: case CAMERA_FORMAT_YUYV:
yuyv_to_rgb32(cam->mem, cam->width * 2, yuyv_to_rgb32(head->addr, parms->width * 2,
cam->width, cam->height, parms->width, parms->height,
screen->pixels, screen->pitch); screen->pixels, screen->pitch);
break; 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, rgb32_to_luma(screen->pixels, screen->pitch,
@ -177,13 +191,32 @@ static int run_demo(void)
struct quirc *qr; struct quirc *qr;
struct camera cam; struct camera cam;
struct mjpeg_decoder mj; struct mjpeg_decoder mj;
const struct camera_parms *parms;
SDL_Surface *screen; SDL_Surface *screen;
int ret;
if (camera_init(&cam, camera_path, video_width, video_height) < 0) camera_init(&cam);
return -1; 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(); qr = quirc_new();
if (!qr) { if (!qr) {
@ -191,7 +224,7 @@ static int run_demo(void)
goto fail_qr; 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"); perror("couldn't allocate QR buffer");
goto fail_qr_resize; goto fail_qr_resize;
} }
@ -201,7 +234,7 @@ static int run_demo(void)
goto fail_sdl_init; goto fail_sdl_init;
} }
screen = SDL_SetVideoMode(cam.width, cam.height, 32, screen = SDL_SetVideoMode(parms->width, parms->height, 32,
SDL_SWSURFACE | SDL_DOUBLEBUF); SDL_SWSURFACE | SDL_DOUBLEBUF);
if (!screen) { if (!screen) {
perror("couldn't init video mode"); perror("couldn't init video mode");
@ -209,24 +242,27 @@ static int run_demo(void)
} }
mjpeg_init(&mj); 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); mjpeg_free(&mj);
SDL_Quit(); SDL_Quit();
quirc_destroy(qr); quirc_destroy(qr);
camera_free(&cam); camera_destroy(&cam);
return 0; return 0;
fail_main_loop:
mjpeg_free(&mj);
fail_video_mode: fail_video_mode:
SDL_Quit(); SDL_Quit();
fail_qr_resize: fail_qr_resize:
fail_sdl_init: fail_sdl_init:
quirc_destroy(qr); quirc_destroy(qr);
fail_qr: fail_qr:
camera_free(&cam); camera_destroy(&cam);
return 0; return -1;
} }
static void usage(const char *progname) static void usage(const char *progname)
@ -237,7 +273,6 @@ static void usage(const char *progname)
" -v Show extra data for detected codes.\n" " -v Show extra data for detected codes.\n"
" -d <device> Specify camera device path.\n" " -d <device> Specify camera device path.\n"
" -s <WxH> Specify video dimensions.\n" " -s <WxH> Specify video dimensions.\n"
" -g <value> Set camera gain.\n"
" -p <timeout> Set printer timeout (seconds).\n" " -p <timeout> Set printer timeout (seconds).\n"
" --help Show this information.\n" " --help Show this information.\n"
" --version Show library version information.\n", " --version Show library version information.\n",
@ -254,7 +289,7 @@ int main(int argc, char **argv)
int opt; int opt;
printf("quirc demo\n"); printf("quirc demo\n");
printf("Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>\n"); printf("Copyright (C) 2010-2014 Daniel Beer <dlbeer@gmail.com>\n");
printf("\n"); printf("\n");
while ((opt = getopt_long(argc, argv, "d:s:fvg:p:", while ((opt = getopt_long(argc, argv, "d:s:fvg:p:",
@ -289,10 +324,6 @@ int main(int argc, char **argv)
camera_path = optarg; camera_path = optarg;
break; break;
case 'g':
gain_request = atoi(optarg);
break;
case '?': case '?':
fprintf(stderr, "Try --help for usage information\n"); fprintf(stderr, "Try --help for usage information\n");
return -1; return -1;

View file

@ -32,7 +32,6 @@ static const char *camera_path = "/dev/video0";
static int video_width = 640; static int video_width = 640;
static int video_height = 480; static int video_height = 480;
static int want_verbose = 0; static int want_verbose = 0;
static int gain_request = -1;
static int printer_timeout = 2; static int printer_timeout = 2;
static int main_loop(struct camera *cam, static int main_loop(struct camera *cam,
@ -46,19 +45,34 @@ static int main_loop(struct camera *cam,
int w, h; int w, h;
int i, count; int i, count;
uint8_t *buf = quirc_begin(q, &w, &h); 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; return -1;
}
switch (cam->format) { head = camera_get_head(cam);
switch (parms->format) {
case CAMERA_FORMAT_MJPEG: 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); buf, w, w, h);
break; break;
case CAMERA_FORMAT_YUYV: 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; 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); quirc_end(q);
@ -80,12 +94,31 @@ static int run_scanner(void)
struct quirc *qr; struct quirc *qr;
struct camera cam; struct camera cam;
struct mjpeg_decoder mj; struct mjpeg_decoder mj;
int ret; const struct camera_parms *parms;
if (camera_init(&cam, camera_path, video_width, video_height) < 0) camera_init(&cam);
return -1; 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(); qr = quirc_new();
if (!qr) { if (!qr) {
@ -93,26 +126,29 @@ static int run_scanner(void)
goto fail_qr; 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"); perror("couldn't allocate QR buffer");
goto fail_qr_resize; goto fail_qr_resize;
} }
mjpeg_init(&mj); mjpeg_init(&mj);
ret = main_loop(&cam, qr, &mj); if (main_loop(&cam, qr, &mj) < 0)
goto fail_main_loop;
mjpeg_free(&mj); mjpeg_free(&mj);
quirc_destroy(qr); quirc_destroy(qr);
camera_free(&cam); camera_destroy(&cam);
return 0; return 0;
fail_main_loop:
mjpeg_free(&mj);
fail_qr_resize: fail_qr_resize:
quirc_destroy(qr); quirc_destroy(qr);
fail_qr: fail_qr:
camera_free(&cam); camera_destroy(&cam);
return 0; return -1;
} }
static void usage(const char *progname) static void usage(const char *progname)
@ -122,7 +158,6 @@ static void usage(const char *progname)
" -v Show extra data for detected codes.\n" " -v Show extra data for detected codes.\n"
" -d <device> Specify camera device path.\n" " -d <device> Specify camera device path.\n"
" -s <WxH> Specify video dimensions.\n" " -s <WxH> Specify video dimensions.\n"
" -g <value> Set camera gain.\n"
" -p <timeout> Set printer timeout (seconds).\n" " -p <timeout> Set printer timeout (seconds).\n"
" --help Show this information.\n" " --help Show this information.\n"
" --version Show library version information.\n", " --version Show library version information.\n",
@ -170,10 +205,6 @@ int main(int argc, char **argv)
camera_path = optarg; camera_path = optarg;
break; break;
case 'g':
gain_request = atoi(optarg);
break;
case '?': case '?':
fprintf(stderr, "Try --help for usage information\n"); fprintf(stderr, "Try --help for usage information\n");
return -1; return -1;