diff options
| author | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 | 
|---|---|---|
| committer | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 | 
| commit | 4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch) | |
| tree | 65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/lib/quirc/demo | |
| parent | 0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff) | |
add circuitpython code
Diffstat (limited to 'circuitpython/lib/quirc/demo')
| -rw-r--r-- | circuitpython/lib/quirc/demo/camera.c | 591 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/camera.h | 104 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/convert.c | 103 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/convert.h | 39 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/demo.c | 333 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/demo_opencv.cxx | 263 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/demoutil.c | 71 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/demoutil.h | 42 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/dthash.c | 139 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/dthash.h | 61 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/mjpeg.c | 284 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/mjpeg.h | 54 | ||||
| -rw-r--r-- | circuitpython/lib/quirc/demo/scanner.c | 214 | 
13 files changed, 2298 insertions, 0 deletions
| diff --git a/circuitpython/lib/quirc/demo/camera.c b/circuitpython/lib/quirc/demo/camera.c new file mode 100644 index 0000000..8e8de6b --- /dev/null +++ b/circuitpython/lib/quirc/demo/camera.c @@ -0,0 +1,591 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2014 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdint.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <unistd.h> +#ifdef __OpenBSD__ +#include <sys/videoio.h> +#else +#include <linux/videodev2.h> +#endif +#include "camera.h" + +/************************************************************************ + * 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 = pf; +	if (ioctl(c->fd, VIDIOC_S_FMT, &fmt) < 0) +		goto fail; + +	memset(&fmt, 0, sizeof(fmt)); +	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +	if (ioctl(c->fd, VIDIOC_G_FMT, &fmt) < 0) +		goto fail; + +	/* 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; + +	memset(&parm, 0, sizeof(parm)); +	parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +	if (ioctl(c->fd, VIDIOC_G_PARM, &parm) < 0) +		goto fail; + +	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; + +	return 0; + +fail: +	{ +		const int e = errno; + +		close(c->fd); +		c->fd = -1; +		errno = e; +	} + +	return -1; +} + +void camera_close(struct camera *c) +{ +	camera_off(c); +	camera_unmap(c); + +	if (c->fd < 0) +		return; + +	close(c->fd); +	c->fd = -1; +} + +int camera_map(struct camera *c, int buf_count) +{ +	struct v4l2_requestbuffers reqbuf; +	int count; +	int i; + +	if (buf_count > CAMERA_MAX_BUFFERS) +		buf_count = CAMERA_MAX_BUFFERS; + +	if (buf_count <= 0) { +		errno = EINVAL; +		return -1; +	} + +	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]; + +		memset(&buf, 0, sizeof(buf)); +		buf.index = i; +		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +		buf.memory = V4L2_MEMORY_MMAP; +		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/circuitpython/lib/quirc/demo/camera.h b/circuitpython/lib/quirc/demo/camera.h new file mode 100644 index 0000000..511b5bd --- /dev/null +++ b/circuitpython/lib/quirc/demo/camera.h @@ -0,0 +1,104 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2014 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CAMERA_H_ +#define CAMERA_H_ + +#include <stddef.h> + +#define CAMERA_MAX_BUFFERS	32 + +typedef enum { +	CAMERA_FORMAT_UNKNOWN = 0, +	CAMERA_FORMAT_MJPEG, +	CAMERA_FORMAT_YUYV +} camera_format_t; + +struct camera_parms { +	camera_format_t		format; +	int			width; +	int			height; +	int			pitch_bytes; +	int			interval_n; +	int			interval_d; +}; + +struct camera_buffer { +	void			*addr; +	size_t			size; +	unsigned long		offset; +}; + +struct camera { +	int			fd; + +	struct camera_parms	parms; + +	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/circuitpython/lib/quirc/demo/convert.c b/circuitpython/lib/quirc/demo/convert.c new file mode 100644 index 0000000..9e6f458 --- /dev/null +++ b/circuitpython/lib/quirc/demo/convert.c @@ -0,0 +1,103 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "convert.h" + +#define CHANNEL_CLAMP(dst, tmp, lum, chrom) \ +	(tmp) = ((lum) + (chrom)) >> 8; \ +	if ((tmp) < 0) \ +		(tmp) = 0; \ +	if ((tmp) > 255) \ +		(tmp) = 255; \ +	(dst) = (tmp); + +void yuyv_to_rgb32(const uint8_t *src, int src_pitch, +		   int w, int h, +		   uint8_t *dst, int dst_pitch) +{ +	int y; + +	for (y = 0; y < h; y++) { +		int x; +		const uint8_t *srow = src + y * src_pitch; +		uint8_t *drow = dst + y * dst_pitch; + +		for (x = 0; x < w; x += 2) { +			/* ITU-R colorspace assumed */ +			int y0 = (int)srow[0] * 256; +			int y1 = (int)srow[2] * 256; +			int cr = (int)srow[3] - 128; +			int cb = (int)srow[1] - 128; +			int r = cr * 359; +			int g = -cb * 88 - 128 * cr; +			int b = 454 * cb; +			int z; + +			CHANNEL_CLAMP(drow[0], z, y0, b); +			CHANNEL_CLAMP(drow[1], z, y0, g); +			CHANNEL_CLAMP(drow[2], z, y0, r); +			CHANNEL_CLAMP(drow[4], z, y1, b); +			CHANNEL_CLAMP(drow[5], z, y1, g); +			CHANNEL_CLAMP(drow[6], z, y1, r); + +			srow += 4; +			drow += 8; +		} +	} +} + +void yuyv_to_luma(const uint8_t *src, int src_pitch, +		  int w, int h, +		  uint8_t *dst, int dst_pitch) +{ +	int y; + +	for (y = 0; y < h; y++) { +		int x; +		const uint8_t *srow = src + y * src_pitch; +		uint8_t *drow = dst + y * dst_pitch; + +		for (x = 0; x < w; x += 2) { +			*(drow++) = srow[0]; +			*(drow++) = srow[2]; +			srow += 4; +		} +	} +} + +void rgb32_to_luma(const uint8_t *src, int src_pitch, +		   int w, int h, +		   uint8_t *dst, int dst_pitch) +{ +	int y; + +	for (y = 0; y < h; y++) { +		const uint8_t *rgb32 = src + src_pitch * y; +		uint8_t *gray = dst + y * dst_pitch; +		int i; + +		for (i = 0; i < w; i++) { +			/* ITU-R colorspace assumed */ +			int r = (int)rgb32[2]; +			int g = (int)rgb32[1]; +			int b = (int)rgb32[0]; +			int sum = r * 59 + g * 150 + b * 29; + +			*(gray++) = sum >> 8; +			rgb32 += 4; +		} +	} +} diff --git a/circuitpython/lib/quirc/demo/convert.h b/circuitpython/lib/quirc/demo/convert.h new file mode 100644 index 0000000..ec2a14e --- /dev/null +++ b/circuitpython/lib/quirc/demo/convert.h @@ -0,0 +1,39 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CONVERT_H_ +#define CONVERT_H_ + +#include <stdint.h> + +/* Convert 4:2:2 YUYV format to RGB32 format. The source and destination + * frames are expected to be the same size. + */ +void yuyv_to_rgb32(const uint8_t *src, int src_pitch, +		   int w, int h, +		   uint8_t *dst, int dst_pitch); + +/* Extract the luma channel from a 4:2:2 YUYV image. */ +void yuyv_to_luma(const uint8_t *src, int src_pitch, +		  int w, int h, +		  uint8_t *dst, int dst_pitch); + +/* Extract the luma channel from an RGB32 image. */ +void rgb32_to_luma(const uint8_t *src, int src_pitch, +		   int w, int h, +		   uint8_t *dst, int dst_pitch); + +#endif diff --git a/circuitpython/lib/quirc/demo/demo.c b/circuitpython/lib/quirc/demo/demo.c new file mode 100644 index 0000000..178fde8 --- /dev/null +++ b/circuitpython/lib/quirc/demo/demo.c @@ -0,0 +1,333 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <unistd.h> +#include <SDL.h> +#include <SDL_gfxPrimitives.h> +#include <quirc.h> +#include <time.h> +#include <getopt.h> + +#include "camera.h" +#include "mjpeg.h" +#include "convert.h" +#include "dthash.h" +#include "demoutil.h" + +/* Collected command-line arguments */ +static const char *camera_path = "/dev/video0"; +static int video_width = 640; +static int video_height = 480; +static int want_frame_rate = 0; +static int want_verbose = 0; +static int printer_timeout = 2; + +static void fat_text(SDL_Surface *screen, int x, int y, const char *text) +{ +	int i, j; + +	for (i = -1; i <= 1; i++) +		for (j = -1; j <= 1; j++) +			stringColor(screen, x + i, y + j, text, 0xffffffff); +	stringColor(screen, x, y, text, 0x008000ff); +} + +static void fat_text_cent(SDL_Surface *screen, int x, int y, const char *text) +{ +	x -= strlen(text) * 4; + +	fat_text(screen, x, y, text); +} + +static void draw_qr(SDL_Surface *screen, struct quirc *q, struct dthash *dt) +{ +	int count = quirc_count(q); +	int i; + +	for (i = 0; i < count; i++) { +		struct quirc_code code; +		struct quirc_data data; +		quirc_decode_error_t err; +		int j; +		int xc = 0; +		int yc = 0; +		char buf[128]; + +		quirc_extract(q, i, &code); + +		for (j = 0; j < 4; j++) { +			struct quirc_point *a = &code.corners[j]; +			struct quirc_point *b = &code.corners[(j + 1) % 4]; + +			xc += a->x; +			yc += a->y; +			lineColor(screen, a->x, a->y, b->x, b->y, 0x008000ff); +		} + +		xc /= 4; +		yc /= 4; + +		if (want_verbose) { +			snprintf(buf, sizeof(buf), "Code size: %d cells", +				 code.size); +			fat_text_cent(screen, xc, yc - 20, buf); +		} + +		err = quirc_decode(&code, &data); + +		if (err) { +			if (want_verbose) +				fat_text_cent(screen, xc, yc, +						quirc_strerror(err)); +		} else { +			fat_text_cent(screen, xc, yc, (char *)data.payload); +			print_data(&data, dt, want_verbose); + +			if (want_verbose) { +				snprintf(buf, sizeof(buf), +					 "Ver: %d, ECC: %c, Mask: %d, Type: %d", +					 data.version, "MLHQ"[data.ecc_level], +					 data.mask, data.data_type); +				fat_text_cent(screen, xc, yc + 20, buf); +			} +		} +	} +} + +static int main_loop(struct camera *cam, SDL_Surface *screen, +		     struct quirc *q, struct mjpeg_decoder *mj) +{ +	SDL_Event ev; +	time_t last_rate = 0; +	int frame_count = 0; +	char rate_text[64]; +	struct dthash dt; + +	rate_text[0] = 0; +	dthash_init(&dt, printer_timeout); + +	for (;;) { +		time_t now = time(NULL); +		const struct camera_buffer *head; +		const struct camera_parms *parms = camera_get_parms(cam); + +		if (camera_dequeue_one(cam) < 0) { +			perror("camera_dequeue_one"); +			return -1; +		} + +		head = camera_get_head(cam); + +		SDL_LockSurface(screen); +		switch (parms->format) { +		case CAMERA_FORMAT_MJPEG: +			mjpeg_decode_rgb32(mj, head->addr, head->size, +					   screen->pixels, screen->pitch, +					   screen->w, screen->h); +			break; + +		case CAMERA_FORMAT_YUYV: +			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, +			      screen->w, screen->h, +			      quirc_begin(q, NULL, NULL), +			      screen->w); +		quirc_end(q); +		SDL_UnlockSurface(screen); + +		draw_qr(screen, q, &dt); +		if (want_frame_rate) +			fat_text(screen, 5, 5, rate_text); +		SDL_Flip(screen); + +		while (SDL_PollEvent(&ev) > 0) { +			if (ev.type == SDL_QUIT) +				return 0; + +			if (ev.type == SDL_KEYDOWN && ev.key.keysym.sym == 'q') +				return 0; +		} + +		if (now != last_rate) { +			snprintf(rate_text, sizeof(rate_text), +				 "Frame rate: %d fps", frame_count); +			frame_count = 0; +			last_rate = now; +		} + +		frame_count++; +	} +} + +static int run_demo(void) +{ +	struct quirc *qr; +	struct camera cam; +	struct mjpeg_decoder mj; +	const struct camera_parms *parms; +	SDL_Surface *screen; + +	camera_init(&cam); +	if (camera_open(&cam, camera_path, video_width, video_height, +			25, 1) < 0) { +		perror("camera_open"); +		goto fail_qr; +	} + +	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) { +		perror("couldn't allocate QR decoder"); +		goto fail_qr; +	} + +	if (quirc_resize(qr, parms->width, parms->height) < 0) { +		perror("couldn't allocate QR buffer"); +		goto fail_qr_resize; +	} + +	if (SDL_Init(SDL_INIT_VIDEO) < 0) { +		perror("couldn't init SDL"); +		goto fail_sdl_init; +	} + +	screen = SDL_SetVideoMode(parms->width, parms->height, 32, +				  SDL_SWSURFACE | SDL_DOUBLEBUF); +	if (!screen) { +		perror("couldn't init video mode"); +		goto fail_video_mode; +	} + +	mjpeg_init(&mj); +	if (main_loop(&cam, screen, qr, &mj) < 0) +		goto fail_main_loop; +	mjpeg_free(&mj); + +	SDL_Quit(); +	quirc_destroy(qr); +	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_destroy(&cam); + +	return -1; +} + +static void usage(const char *progname) +{ +	printf("Usage: %s [options]\n\n" +"Valid options are:\n\n" +"    -f             Show frame rate on screen.\n" +"    -v             Show extra data for detected codes.\n" +"    -d <device>    Specify camera device path.\n" +"    -s <WxH>       Specify video dimensions.\n" +"    -p <timeout>   Set printer timeout (seconds).\n" +"    --help         Show this information.\n" +"    --version      Show library version information.\n", +	progname); +} + +int main(int argc, char **argv) +{ +	static const struct option longopts[] = { +		{"help",		0, 0, 'H'}, +		{"version",		0, 0, 'V'}, +		{NULL,			0, 0, 0} +	}; +	int opt; + +	printf("quirc demo\n"); +	printf("Copyright (C) 2010-2014 Daniel Beer <dlbeer@gmail.com>\n"); +	printf("\n"); + +	while ((opt = getopt_long(argc, argv, "d:s:fvg:p:", +				  longopts, NULL)) >= 0) +		switch (opt) { +		case 'V': +			printf("Library version: %s\n", quirc_version()); +			return 0; + +		case 'H': +			usage(argv[0]); +			return 0; + +		case 'v': +			want_verbose = 1; +			break; + +		case 'f': +			want_frame_rate = 1; +			break; + +		case 's': +			if (parse_size(optarg, &video_width, &video_height) < 0) +				return -1; +			break; + +		case 'p': +			printer_timeout = atoi(optarg); +			break; + +		case 'd': +			camera_path = optarg; +			break; + +		case '?': +			fprintf(stderr, "Try --help for usage information\n"); +			return -1; +		} + +	return run_demo(); +} diff --git a/circuitpython/lib/quirc/demo/demo_opencv.cxx b/circuitpython/lib/quirc/demo/demo_opencv.cxx new file mode 100644 index 0000000..d6dbe8b --- /dev/null +++ b/circuitpython/lib/quirc/demo/demo_opencv.cxx @@ -0,0 +1,263 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <unistd.h> +#include <quirc.h> +#include <time.h> +#include <getopt.h> + +#include <opencv2/videoio.hpp> +#include <opencv2/imgproc.hpp> +#include <opencv2/highgui.hpp> + +using namespace cv; + +#include "camera.h" +#include "convert.h" +#include "dthash.h" +#include "demoutil.h" + +/* Collected command-line arguments */ +static int want_frame_rate = 0; +static int want_verbose = 0; +static int printer_timeout = 2; + +static const int font = FONT_HERSHEY_PLAIN; +static const int thickness = 2; +static const double font_scale = 1.5; +static Scalar blue = Scalar(255, 0, 8); + +static void fat_text(Mat &screen, int x, int y, const char *text) +{ +	putText(screen, text, Point(x, y), font, font_scale, blue, thickness); +} + +static void fat_text_cent(Mat &screen, int x, int y, const char *text) +{ +	int baseline; + +	Size size = getTextSize(text, font, font_scale, thickness, &baseline); +	putText(screen, text, Point(x - size.width / 2, y - size.height /2), +		font, font_scale, blue, thickness); +} + +static void draw_qr(Mat &screen, struct quirc *q, struct dthash *dt) +{ +	int count = quirc_count(q); +	int i; + +	for (i = 0; i < count; i++) { +		struct quirc_code code; +		struct quirc_data data; +		quirc_decode_error_t err; +		int j; +		int xc = 0; +		int yc = 0; +		char buf[128]; + +		quirc_extract(q, i, &code); + +		for (j = 0; j < 4; j++) { +			struct quirc_point *a = &code.corners[j]; +			struct quirc_point *b = &code.corners[(j + 1) % 4]; + +			xc += a->x; +			yc += a->y; +			line(screen, Point(a->x, a->y), Point(b->x, b->y), blue, 8); +		} + +		xc /= 4; +		yc /= 4; + +		if (want_verbose) { +			snprintf(buf, sizeof(buf), "Code size: %d cells", +				 code.size); +			fat_text_cent(screen, xc, yc - 20, buf); +		} + +		err = quirc_decode(&code, &data); + +		if (err) { +			if (want_verbose) +				fat_text_cent(screen, xc, yc, quirc_strerror(err)); +		} else { +			fat_text_cent(screen, xc, yc, (const char *)data.payload); +			print_data(&data, dt, want_verbose); + +			if (want_verbose) { +				snprintf(buf, sizeof(buf), +					 "Ver: %d, ECC: %c, Mask: %d, Type: %d", +					 data.version, "MLHQ"[data.ecc_level], +					 data.mask, data.data_type); +				fat_text_cent(screen, xc, yc + 20, buf); +			} +		} +	} +} + +static int main_loop(VideoCapture &cap, struct quirc *q) +{ +	time_t last_rate = 0; +	int frame_count = 0; +	char rate_text[64]; +	struct dthash dt; + +	rate_text[0] = 0; +	dthash_init(&dt, printer_timeout); + +	Mat frame; +	for (;;) { +		time_t now = time(NULL); + +		cap.read(frame); +		if (frame.empty()) { +			perror("empty frame"); +			return 0; +		} + +		int w; +		int h; +		uint8_t *buf = quirc_begin(q, &w, &h); + +		/* convert frame into buf */ +		assert(frame.cols == w); +		assert(frame.rows == h); +		Mat gray; +		cvtColor(frame, gray, COLOR_BGR2GRAY, 0); +		for (int y = 0; y < gray.rows; y++) { +			for (int x = 0; x < gray.cols; x++) { +				buf[(y * w + x)] = gray.at<uint8_t>(y, x); +			} +		} + +		quirc_end(q); + +		draw_qr(frame, q, &dt); +		if (want_frame_rate) +			fat_text(frame, 20, 20, rate_text); + +		imshow("quirc-demo-opencv", frame); +		waitKey(5); + +		if (now != last_rate) { +			snprintf(rate_text, sizeof(rate_text), +				 "Frame rate: %d fps", frame_count); +			frame_count = 0; +			last_rate = now; +		} + +		frame_count++; +	} +} + +static int run_demo(void) +{ +	struct quirc *qr; +	VideoCapture cap(0); +	unsigned int width; +	unsigned int height; + +	if (!cap.isOpened()) { +		perror("camera_open"); +		goto fail_qr; +	} + +	width = cap.get(CAP_PROP_FRAME_WIDTH); +	height = cap.get(CAP_PROP_FRAME_HEIGHT); + +	qr = quirc_new(); +	if (!qr) { +		perror("couldn't allocate QR decoder"); +		goto fail_qr; +	} + +	if (quirc_resize(qr, width, height) < 0) { +		perror("couldn't allocate QR buffer"); +		goto fail_qr_resize; +	} + +	if (main_loop(cap, qr) < 0) { +		goto fail_main_loop; +	} + +	quirc_destroy(qr); + +	return 0; + +fail_main_loop: +fail_qr_resize: +	quirc_destroy(qr); +fail_qr: + +	return -1; +} + +static void usage(const char *progname) +{ +	printf("Usage: %s [options]\n\n" +"Valid options are:\n\n" +"    -f             Show frame rate on screen.\n" +"    -v             Show extra data for detected codes.\n" +"    -p <timeout>   Set printer timeout (seconds).\n" +"    --help         Show this information.\n" +"    --version      Show library version information.\n", +	progname); +} + +int main(int argc, char **argv) +{ +	static const struct option longopts[] = { +		{"help",		0, 0, 'H'}, +		{"version",		0, 0, 'V'}, +		{NULL,			0, 0, 0} +	}; +	int opt; + +	printf("quirc demo with OpenCV\n"); +	printf("Copyright (C) 2010-2014 Daniel Beer <dlbeer@gmail.com>\n"); +	printf("\n"); + +	while ((opt = getopt_long(argc, argv, "fvg:p:", +				  longopts, NULL)) >= 0) +		switch (opt) { +		case 'V': +			printf("Library version: %s\n", quirc_version()); +			return 0; + +		case 'H': +			usage(argv[0]); +			return 0; + +		case 'v': +			want_verbose = 1; +			break; + +		case 'f': +			want_frame_rate = 1; +			break; + +		case 'p': +			printer_timeout = atoi(optarg); +			break; + +		case '?': +			fprintf(stderr, "Try --help for usage information\n"); +			return -1; +		} + +	return run_demo(); +} diff --git a/circuitpython/lib/quirc/demo/demoutil.c b/circuitpython/lib/quirc/demo/demoutil.c new file mode 100644 index 0000000..857247a --- /dev/null +++ b/circuitpython/lib/quirc/demo/demoutil.c @@ -0,0 +1,71 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <ctype.h> + +#include "demoutil.h" + +void print_data(const struct quirc_data *data, struct dthash *dt, +		int want_verbose) +{ +	if (dthash_seen(dt, data)) +		return; + +	printf("==> %s\n", data->payload); + +	if (want_verbose) +		printf("    Version: %d, ECC: %c, Mask: %d, Type: %d\n\n", +		       data->version, "MLHQ"[data->ecc_level], +		       data->mask, data->data_type); +} + +int parse_size(const char *text, int *video_width, int *video_height) +{ +	int state = 0; +	int w = 0, h = 0; +	int i; + +	for (i = 0; text[i]; i++) { +		if (text[i] == 'x' || text[i] == 'X') { +			if (state == 0) { +				state = 1; +			} else { +				fprintf(stderr, "parse_size: expected WxH\n"); +				return -1; +			} +		} else if (isdigit(text[i])) { +			if (state == 0) +				w = w * 10 + text[i] - '0'; +			else +				h = h * 10 + text[i] - '0'; +		} else { +			fprintf(stderr, "Invalid character in size: %c\n", +				text[i]); +			return -1; +		} +	} + +	if (w <= 0 || w >= 10000 || h <= 0 || h >= 10000) { +		fprintf(stderr, "Invalid size: %dx%d\n", w, h); +		return -1; +	} + +	*video_width = w; +	*video_height = h; + +	return 0; +} diff --git a/circuitpython/lib/quirc/demo/demoutil.h b/circuitpython/lib/quirc/demo/demoutil.h new file mode 100644 index 0000000..888eddd --- /dev/null +++ b/circuitpython/lib/quirc/demo/demoutil.h @@ -0,0 +1,42 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DEMOUTIL_H_ +#define DEMOUTIL_H_ + +#include "dthash.h" +#include "quirc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Check if we've seen the given code, and if not, print it on stdout. + * Include version info if requested. + */ +void print_data(const struct quirc_data *data, struct dthash *dt, +		int want_verbose); + +/* Parse a string of the form "WxH" and return width and height as + * integers. Returns 0 on success or -1 if a parser error occurs. + */ +int parse_size(const char *text, int *video_width, int *video_height); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/circuitpython/lib/quirc/demo/dthash.c b/circuitpython/lib/quirc/demo/dthash.c new file mode 100644 index 0000000..888dc1f --- /dev/null +++ b/circuitpython/lib/quirc/demo/dthash.c @@ -0,0 +1,139 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <string.h> +#include "dthash.h" + +static const uint32_t crc32_tab[] = { +	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, +	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, +	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, +	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, +	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, +	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, +	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, +	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, +	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, +	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, +	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, +	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, +	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, +	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, +	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, +	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, +	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, +	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, +	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, +	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, +	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, +	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, +	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, +	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, +	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, +	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, +	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, +	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, +	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, +	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, +	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, +	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, +	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +static uint32_t calc_crc(uint32_t crc, const uint8_t *buf, int len) +{ +	while (len--) { +		crc = crc32_tab[(crc ^ *buf) & 0xff] ^ (crc >> 8); +		buf++; +	} + +	return crc; +} + +static uint32_t code_hash(const struct quirc_data *data) +{ +	uint8_t extra[4] = {data->version, data->ecc_level, +			    data->mask, data->data_type}; +	uint32_t crc = calc_crc(0xffffffff, extra, 4); + +	return calc_crc(crc, data->payload, data->payload_len); +} + +static void flush_old(struct dthash *d, time_t now) +{ +	int i; + +	for (i = 0; i < d->count; i++) { +		struct dthash_code *c = &d->codes[i]; + +		if (c->when + d->timeout <= now) { +			if (i + 1 < d->count) +				memcpy(c, &d->codes[d->count - 1], sizeof(*c)); +			d->count--; +		} +	} +} + +void dthash_init(struct dthash *d, int timeout) +{ +	d->count = 0; +	d->timeout = timeout; +} + +int dthash_seen(struct dthash *d, const struct quirc_data *data) +{ +	time_t now = time(NULL); +	uint32_t hash = code_hash(data); +	struct dthash_code *c; +	int i; + +	flush_old(d, now); + +	/* If the code is already seen, update its timestamp */ +	for (i = 0; i < d->count; i++) { +		c = &d->codes[i]; +		if (c->hash == hash) { +			c->when = now; +			return 1; +		} +	} + +	/* Otherwise, find a place to put it. If necessary, push the +	 * oldset code out of the table. +	 */ +	if (d->count + 1 < DTHASH_MAX_CODES) { +		c = &d->codes[d->count++]; +	} else { +		c = &d->codes[0]; +		for (i = 1; i < d->count; i++) +			if (d->codes[i].when < c->when) +				c = &d->codes[i]; +	} + +	c->hash = hash; +	c->when = now; +	return 0; +} diff --git a/circuitpython/lib/quirc/demo/dthash.h b/circuitpython/lib/quirc/demo/dthash.h new file mode 100644 index 0000000..431db1e --- /dev/null +++ b/circuitpython/lib/quirc/demo/dthash.h @@ -0,0 +1,61 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DTHASH_H_ +#define DTHASH_H_ + +#include <stdint.h> +#include <time.h> +#include "quirc.h" + +/* Detector hash. + * + * This structure keeps track of codes that have been seen within the + * last N seconds, and allows us to print out codes at a reasonable + * rate as we see them. + */ +#define DTHASH_MAX_CODES	32 + +struct dthash_code { +	uint32_t		hash; +	time_t			when; +}; + +struct dthash { +	struct dthash_code	codes[DTHASH_MAX_CODES]; +	int			count; +	int			timeout; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initialise a detector hash with the given timeout. */ +void dthash_init(struct dthash *d, int timeout); + +/* When a code is discovered, this function should be called to see if + * it should be printed. The hash will record having seen the code, and + * return non-zero if it's the first time we've seen it within the + * configured timeout period. + */ +int dthash_seen(struct dthash *d, const struct quirc_data *data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/circuitpython/lib/quirc/demo/mjpeg.c b/circuitpython/lib/quirc/demo/mjpeg.c new file mode 100644 index 0000000..09d2197 --- /dev/null +++ b/circuitpython/lib/quirc/demo/mjpeg.c @@ -0,0 +1,284 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <setjmp.h> +#include <jpeglib.h> +#include <assert.h> +#include "mjpeg.h" + +struct huffman_table { +	uint8_t		bits[17]; +	uint8_t		huffval[256]; +}; + +static const struct huffman_table dc_lum = { +	.bits = { +		0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, +		0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00 +	}, +	.huffval = { +		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +		0x08, 0x09, 0x0a, 0x0b +	} +}; + +static const struct huffman_table ac_lum = { +	.bits = { +		0x00, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, +		0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, +		0x7d +	}, +	.huffval = { +		0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, +		0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, +		0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, +		0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, +		0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, +		0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, +		0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, +		0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, +		0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, +		0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, +		0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, +		0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, +		0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, +		0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, +		0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, +		0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, +		0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, +		0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, +		0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, +		0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, +		0xf9, 0xfa +	} +}; + +static const struct huffman_table dc_chroma = { +	.bits = { +		0x00, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, +		0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, +		0x00 +	}, +	.huffval = { +		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +		0x08, 0x09, 0x0a, 0x0b +	} +}; + +static const struct huffman_table ac_chroma = { +	.bits = { +		0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, +		0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, +		0x77 +	}, +	.huffval = { +		0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, +		0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, +		0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, +		0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, +		0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, +		0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, +		0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, +		0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, +		0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, +		0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, +		0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, +		0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, +		0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, +		0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, +		0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, +		0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, +		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, +		0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, +		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, +		0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, +		0xf9, 0xfa +	} +}; + +static void init_source(j_decompress_ptr cinfo) +{ +} + +static boolean fill_input_buffer(j_decompress_ptr cinfo) +{ +	static const uint8_t eoi_marker[] = {0xff, 0xd9}; + +	cinfo->src->next_input_byte = eoi_marker; +	cinfo->src->bytes_in_buffer = 2; + +	return TRUE; +} + +static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ +	if (num_bytes < 0) +		return; +	if (num_bytes > cinfo->src->bytes_in_buffer) +		num_bytes = cinfo->src->bytes_in_buffer; + +	cinfo->src->bytes_in_buffer -= num_bytes; +	cinfo->src->next_input_byte += num_bytes; +} + +static void term_source(j_decompress_ptr cinfo) +{ +} + +struct my_jpeg_error { +	struct jpeg_error_mgr   base; +	jmp_buf                 env; +}; + +static void my_output_message(struct jpeg_common_struct *com) +{ +	struct mjpeg_decoder *mj = (struct mjpeg_decoder *)com->err; +	char buf[JMSG_LENGTH_MAX]; + +	mj->err.format_message(com, buf); +	fprintf(stderr, "MJPEG error: %s\n", buf); +} + +static void my_error_exit(struct jpeg_common_struct *com) +{ +	struct mjpeg_decoder *mj = (struct mjpeg_decoder *)com->err; + +	my_output_message(com); +	longjmp(mj->env, 0); +} + +static void setup_table(struct jpeg_decompress_struct *jpeg, +			JHUFF_TBL **tbl_ptr, const struct huffman_table *tab) +{ +	assert (*tbl_ptr == NULL); + +	*tbl_ptr = jpeg_alloc_huff_table((j_common_ptr)jpeg); +	memcpy((*tbl_ptr)->bits, tab->bits, 17); +	memcpy((*tbl_ptr)->huffval, tab->huffval, 256); +} + +void mjpeg_init(struct mjpeg_decoder *mj) +{ +	memset(mj, 0, sizeof(*mj)); + +	/* Set up error management */ +	mj->dinfo.err = jpeg_std_error(&mj->err); +	mj->err.error_exit = my_error_exit; +	mj->err.output_message = my_output_message; + +	mj->src.init_source = init_source; +	mj->src.fill_input_buffer = fill_input_buffer; +	mj->src.skip_input_data = skip_input_data; +	mj->src.resync_to_restart = jpeg_resync_to_restart; +	mj->src.term_source = term_source; + +	jpeg_create_decompress(&mj->dinfo); +	mj->dinfo.src = &mj->src; +	mj->dinfo.err = &mj->err; + +	setup_table(&mj->dinfo, &mj->dinfo.dc_huff_tbl_ptrs[0], &dc_lum); +	setup_table(&mj->dinfo, &mj->dinfo.ac_huff_tbl_ptrs[0], &ac_lum); +	setup_table(&mj->dinfo, &mj->dinfo.dc_huff_tbl_ptrs[1], &dc_chroma); +	setup_table(&mj->dinfo, &mj->dinfo.ac_huff_tbl_ptrs[1], &ac_chroma); +} + +void mjpeg_free(struct mjpeg_decoder *mj) +{ +	jpeg_destroy_decompress(&mj->dinfo); +} + +int mjpeg_decode_rgb32(struct mjpeg_decoder *mj, +		       const uint8_t *data, int datalen, +		       uint8_t *out, int pitch, int max_w, int max_h) +{ +	if (setjmp(mj->env)) +		return -1; + +	mj->dinfo.src->bytes_in_buffer = datalen; +	mj->dinfo.src->next_input_byte = data; + +	jpeg_read_header(&mj->dinfo, TRUE); +	mj->dinfo.output_components = 3; +	mj->dinfo.out_color_space = JCS_RGB; +	jpeg_start_decompress(&mj->dinfo); + +	if (mj->dinfo.image_height > max_h || +	    mj->dinfo.image_width > max_w) { +		fprintf(stderr, "MJPEG: frame too big\n"); +		return -1; +	} + +	uint8_t *rgb = calloc(mj->dinfo.image_width, 3); +	if (!rgb) { +		fprintf(stderr, "memory allocation failed\n"); +		return -1; +	} +	while (mj->dinfo.output_scanline < mj->dinfo.image_height) { +		uint8_t *scr = out + pitch * mj->dinfo.output_scanline; +		uint8_t *output = rgb; +		int i; + +		jpeg_read_scanlines(&mj->dinfo, &output, 1); +		for (i = 0; i < mj->dinfo.image_width; i++) { +			scr[0] = output[2]; +			scr[1] = output[1]; +			scr[2] = output[0]; +			scr += 4; +			output += 3; +		} +	} +	free(rgb); + +	jpeg_finish_decompress(&mj->dinfo); + +	return 0; +} + +int mjpeg_decode_gray(struct mjpeg_decoder *mj, +		      const uint8_t *data, int datalen, +		      uint8_t *out, int pitch, int max_w, int max_h) +{ +	if (setjmp(mj->env)) +		return -1; + +	mj->dinfo.src->bytes_in_buffer = datalen; +	mj->dinfo.src->next_input_byte = data; + +	jpeg_read_header(&mj->dinfo, TRUE); +	mj->dinfo.output_components = 1; +	mj->dinfo.out_color_space = JCS_GRAYSCALE; +	jpeg_start_decompress(&mj->dinfo); + +	if (mj->dinfo.image_height > max_h || +	    mj->dinfo.image_width > max_w) { +		fprintf(stderr, "MJPEG: frame too big\n"); +		return -1; +	} + +	while (mj->dinfo.output_scanline < mj->dinfo.image_height) { +		uint8_t *scr = out + pitch * mj->dinfo.output_scanline; + +		jpeg_read_scanlines(&mj->dinfo, &scr, 1); +	} + +	jpeg_finish_decompress(&mj->dinfo); + +	return 0; +} diff --git a/circuitpython/lib/quirc/demo/mjpeg.h b/circuitpython/lib/quirc/demo/mjpeg.h new file mode 100644 index 0000000..caac855 --- /dev/null +++ b/circuitpython/lib/quirc/demo/mjpeg.h @@ -0,0 +1,54 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MJPEG_H_ +#define MJPEG_H_ + +#include <stdint.h> +#include <stdio.h> +#include <jpeglib.h> +#include <setjmp.h> + +struct mjpeg_decoder { +	/* The error manager must be the first item in this struct */ +	struct jpeg_error_mgr			err; +	struct jpeg_decompress_struct		dinfo; +	struct jpeg_source_mgr			src; +	jmp_buf					env; +}; + +/* Construct an MJPEG decoder. */ +void mjpeg_init(struct mjpeg_decoder *mj); + +/* Free any memory allocated while decoding MJPEG frames. */ +void mjpeg_free(struct mjpeg_decoder *mj); + +/* Decode a single MJPEG image to the buffer given, in RGB format. + * Returns 0 on success, -1 if an error occurs (bad data, or image too + * big for buffer). + */ +int mjpeg_decode_rgb32(struct mjpeg_decoder *mj, +		       const uint8_t *data, int datalen, +		       uint8_t *out, int pitch, int max_w, int max_h); + +/* Decode a single MJPEG image to the buffer given in 8-bit grayscale. + * Returns 0 on success, -1 if an error occurs. + */ +int mjpeg_decode_gray(struct mjpeg_decoder *mj, +		      const uint8_t *data, int datalen, +		      uint8_t *out, int pitch, int max_w, int max_h); + +#endif diff --git a/circuitpython/lib/quirc/demo/scanner.c b/circuitpython/lib/quirc/demo/scanner.c new file mode 100644 index 0000000..7c6c38e --- /dev/null +++ b/circuitpython/lib/quirc/demo/scanner.c @@ -0,0 +1,214 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <quirc.h> +#include <time.h> +#include <getopt.h> + +#include "camera.h" +#include "mjpeg.h" +#include "convert.h" +#include "dthash.h" +#include "demoutil.h" + +/* Collected command-line arguments */ +static const char *camera_path = "/dev/video0"; +static int video_width = 640; +static int video_height = 480; +static int want_verbose = 0; +static int printer_timeout = 2; + +static int main_loop(struct camera *cam, +		     struct quirc *q, struct mjpeg_decoder *mj) +{ +	struct dthash dt; + +	dthash_init(&dt, printer_timeout); + +	for (;;) { +		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_dequeue_one(cam) < 0) { +			perror("camera_dequeue_one"); +			return -1; +		} + +		head = camera_get_head(cam); + +		switch (parms->format) { +		case CAMERA_FORMAT_MJPEG: +			mjpeg_decode_gray(mj, head->addr, head->size, +					  buf, w, w, h); +			break; + +		case CAMERA_FORMAT_YUYV: +			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); + +		count = quirc_count(q); +		for (i = 0; i < count; i++) { +			struct quirc_code code; +			struct quirc_data data; + +			quirc_extract(q, i, &code); +			if (!quirc_decode(&code, &data)) +				print_data(&data, &dt, want_verbose); +		} +	} +} + +static int run_scanner(void) +{ +	struct quirc *qr; +	struct camera cam; +	struct mjpeg_decoder mj; +	const struct camera_parms *parms; + +	camera_init(&cam); +	if (camera_open(&cam, camera_path, video_width, video_height, +			25, 1) < 0) { +		perror("camera_open"); +		goto fail_qr; +	} + +	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) { +		perror("couldn't allocate QR decoder"); +		goto fail_qr; +	} + +	if (quirc_resize(qr, parms->width, parms->height) < 0) { +		perror("couldn't allocate QR buffer"); +		goto fail_qr_resize; +	} + +	mjpeg_init(&mj); +	if (main_loop(&cam, qr, &mj) < 0) +		goto fail_main_loop; +	mjpeg_free(&mj); + +	quirc_destroy(qr); +	camera_destroy(&cam); + +	return 0; + +fail_main_loop: +	mjpeg_free(&mj); +fail_qr_resize: +	quirc_destroy(qr); +fail_qr: +	camera_destroy(&cam); + +	return -1; +} + +static void usage(const char *progname) +{ +	printf("Usage: %s [options]\n\n" +"Valid options are:\n\n" +"    -v             Show extra data for detected codes.\n" +"    -d <device>    Specify camera device path.\n" +"    -s <WxH>       Specify video dimensions.\n" +"    -p <timeout>   Set printer timeout (seconds).\n" +"    --help         Show this information.\n" +"    --version      Show library version information.\n", +	progname); +} + +int main(int argc, char **argv) +{ +	static const struct option longopts[] = { +		{"help",		0, 0, 'H'}, +		{"version",		0, 0, 'V'}, +		{NULL,			0, 0, 0} +	}; +	int opt; + +	printf("quirc scanner demo\n"); +	printf("Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>\n"); +	printf("\n"); + +	while ((opt = getopt_long(argc, argv, "d:s:vg:p:", +				  longopts, NULL)) >= 0) +		switch (opt) { +		case 'V': +			printf("Library version: %s\n", quirc_version()); +			return 0; + +		case 'H': +			usage(argv[0]); +			return 0; + +		case 'v': +			want_verbose = 1; +			break; + +		case 's': +			if (parse_size(optarg, &video_width, &video_height) < 0) +				return -1; +			break; + +		case 'p': +			printer_timeout = atoi(optarg); +			break; + +		case 'd': +			camera_path = optarg; +			break; + +		case '?': +			fprintf(stderr, "Try --help for usage information\n"); +			return -1; +		} + +	return run_scanner(); +} | 
