quirc/demo/camera.c
2012-05-04 12:58:42 +12:00

221 lines
5.4 KiB
C

/* 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 <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev.h>
#include "camera.h"
static int set_video_format(struct camera *cam, uint32_t format,
int w, int h, camera_format_t my_fmt)
{
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = w;
fmt.fmt.pix.height = h;
fmt.fmt.pix.pixelformat = format;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
if (ioctl(cam->fd, VIDIOC_S_FMT, &fmt) < 0)
return -1;
/* Note that the size obtained may not match what was requested. */
cam->format = my_fmt;
cam->width = fmt.fmt.pix.width;
cam->height = fmt.fmt.pix.height;
return 0;
}
int camera_set_gain(struct camera *cam, int value)
{
struct v4l2_queryctrl query;
struct v4l2_control ctrl;
query.id = V4L2_CID_GAIN;
if (ioctl(cam->fd, VIDIOC_QUERYCTRL, &query) < 0) {
perror("ioctl: VIDIOC_QUERYCTRL");
return -1;
}
ctrl.id = V4L2_CID_GAIN;
if (value < 0)
ctrl.value = query.default_value;
else
ctrl.value = value;
if (ioctl(cam->fd, VIDIOC_S_CTRL, &ctrl) < 0) {
perror("ioctl: VIDIOC_S_CTRL");
return -1;
}
return 0;
}
int camera_init(struct camera *cam, const char *path, int width, int height)
{
struct v4l2_streamparm fps;
struct v4l2_requestbuffers rb;
int type;
int i;
cam->fd = open(path, O_RDONLY);
if (cam->fd < 0) {
fprintf(stderr, "%s: can't open camera device: %s\n", path,
strerror(errno));
return -1;
}
/* Set the video format */
if (set_video_format(cam, V4L2_PIX_FMT_MJPEG,
width, height, CAMERA_FORMAT_MJPEG) < 0 &&
set_video_format(cam, V4L2_PIX_FMT_YUYV,
width, height, CAMERA_FORMAT_YUYV) < 0) {
fprintf(stderr, "%s: can't find a supported video format\n",
path);
goto fail;
}
/* Set the frame rate */
memset(&fps, 0, sizeof(fps));
fps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fps.parm.capture.timeperframe.numerator = 1;
fps.parm.capture.timeperframe.denominator = 20;
if (ioctl(cam->fd, VIDIOC_S_PARM, &fps) < 0) {
fprintf(stderr, "%s: can't set video frame rate: %s\n", path,
strerror(errno));
goto fail;
}
/* Request buffer */
memset(&rb, 0, sizeof(rb));
rb.count = CAMERA_BUFFERS;
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
rb.memory = V4L2_MEMORY_MMAP;
if (ioctl(cam->fd, VIDIOC_REQBUFS, &rb) < 0) {
fprintf(stderr, "%s: can't request buffers: %s\n", path,
strerror(errno));
goto fail;
}
/* Map buffers and submit them */
for (i = 0; i < CAMERA_BUFFERS; i++) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(cam->fd, VIDIOC_QUERYBUF, &buf) < 0) {
fprintf(stderr, "%s: can't query buffer: %s\n", path,
strerror(errno));
goto fail;
}
cam->buffer_maps[i] = mmap(0, buf.length,
PROT_READ, MAP_SHARED, cam->fd, buf.m.offset);
if (cam->buffer_maps[i] == MAP_FAILED) {
fprintf(stderr, "%s: can't map buffer memory: %s\n",
path, strerror(errno));
goto fail;
}
cam->buffer_lens[i] = buf.length;
}
/* Switch on streaming */
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(cam->fd, VIDIOC_STREAMON, &type) < 0) {
fprintf(stderr, "%s: can't enable streaming: %s\n", path,
strerror(errno));
goto fail;
}
/* Queue the buffers */
for (i = 0; i < CAMERA_BUFFERS; i++) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(cam->fd, VIDIOC_QBUF, &buf) < 0) {
perror("can't start buffer queue");
return -1;
}
}
cam->mem_index = -1;
return 0;
fail:
close(cam->fd);
return -1;
}
void camera_free(struct camera *cam)
{
int i;
for (i = 0; i < CAMERA_BUFFERS; i++)
munmap(cam->buffer_maps[i], cam->buffer_lens[i]);
close(cam->fd);
}
int camera_update(struct camera *cam)
{
struct v4l2_buffer buf;
int last_index = cam->mem_index;
/* De-queue a buffer */
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(cam->fd, VIDIOC_DQBUF, &buf) < 0) {
perror("can't de-queue buffer");
return -1;
}
cam->mem_index = buf.index;
cam->mem = cam->buffer_maps[cam->mem_index];
cam->mem_len = cam->buffer_lens[cam->mem_index];
/* Re-queue the last buffer */
if (last_index >= 0) {
memset(&buf, 0, sizeof(buf));
buf.index = last_index;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(cam->fd, VIDIOC_QBUF, &buf) < 0) {
perror("can't queue buffer");
return -1;
}
}
return 0;
}