diff options
Diffstat (limited to 'src/common_v4l2.h')
-rw-r--r-- | src/common_v4l2.h | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/common_v4l2.h b/src/common_v4l2.h new file mode 100644 index 0000000..c3762b5 --- /dev/null +++ b/src/common_v4l2.h @@ -0,0 +1,141 @@ +#ifndef COMMON_V4L2_H +#define COMMON_V4L2_H + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/types.h> + +#include <libv4l2.h> +#include <linux/videodev2.h> + +#define COMMON_V4L2_CLEAR(x) memset(&(x), 0, sizeof(x)) + +typedef struct { + void *start; + size_t length; +} CommonV4l2_Buffer; + +typedef struct { + int fd; + CommonV4l2_Buffer *buffers; + struct v4l2_buffer buf; + unsigned int n_buffers; +} CommonV4l2; + +void CommonV4l2_xioctl(int fh, unsigned long int request, void *arg) +{ + int r; + do { + r = v4l2_ioctl(fh, request, arg); + } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); + if (r == -1) { + fprintf(stderr, "error %d, %s\n", errno, strerror(errno)); + exit(EXIT_FAILURE); + } +} + +void CommonV4l2_init(CommonV4l2 *this, char *dev_name, unsigned int x_res, unsigned int y_res) { + enum v4l2_buf_type type; + struct v4l2_format fmt; + struct v4l2_requestbuffers req; + unsigned int i; + + this->fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); + if (this->fd < 0) { + perror("Cannot open device"); + exit(EXIT_FAILURE); + } + COMMON_V4L2_CLEAR(fmt); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = x_res; + fmt.fmt.pix.height = y_res; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + CommonV4l2_xioctl(this->fd, VIDIOC_S_FMT, &fmt); + if ((fmt.fmt.pix.width != x_res) || (fmt.fmt.pix.height != y_res)) + printf("Warning: driver is sending image at %dx%d\n", + fmt.fmt.pix.width, fmt.fmt.pix.height); + COMMON_V4L2_CLEAR(req); + req.count = 2; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + CommonV4l2_xioctl(this->fd, VIDIOC_REQBUFS, &req); + this->buffers = calloc(req.count, sizeof(*this->buffers)); + for (this->n_buffers = 0; this->n_buffers < req.count; ++this->n_buffers) { + COMMON_V4L2_CLEAR(this->buf); + this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + this->buf.memory = V4L2_MEMORY_MMAP; + this->buf.index = this->n_buffers; + CommonV4l2_xioctl(this->fd, VIDIOC_QUERYBUF, &this->buf); + this->buffers[this->n_buffers].length = this->buf.length; + this->buffers[this->n_buffers].start = v4l2_mmap(NULL, this->buf.length, + PROT_READ | PROT_WRITE, MAP_SHARED, this->fd, this->buf.m.offset); + if (MAP_FAILED == this->buffers[this->n_buffers].start) { + perror("mmap"); + exit(EXIT_FAILURE); + } + } + for (i = 0; i < this->n_buffers; ++i) { + COMMON_V4L2_CLEAR(this->buf); + this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + this->buf.memory = V4L2_MEMORY_MMAP; + this->buf.index = i; + CommonV4l2_xioctl(this->fd, VIDIOC_QBUF, &this->buf); + } + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + CommonV4l2_xioctl(this->fd, VIDIOC_STREAMON, &type); +} + +void CommonV4l2_update_image(CommonV4l2 *this) { + fd_set fds; + int r; + struct timeval tv; + + do { + FD_ZERO(&fds); + FD_SET(this->fd, &fds); + + /* Timeout. */ + tv.tv_sec = 2; + tv.tv_usec = 0; + + r = select(this->fd + 1, &fds, NULL, NULL, &tv); + } while ((r == -1 && (errno == EINTR))); + if (r == -1) { + perror("select"); + exit(EXIT_FAILURE); + } + COMMON_V4L2_CLEAR(this->buf); + this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + this->buf.memory = V4L2_MEMORY_MMAP; + CommonV4l2_xioctl(this->fd, VIDIOC_DQBUF, &this->buf); + CommonV4l2_xioctl(this->fd, VIDIOC_QBUF, &this->buf); +} + +char * CommonV4l2_get_image(CommonV4l2 *this) { + return ((char *)this->buffers[this->buf.index].start); +} + +size_t CommonV4l2_get_image_size(CommonV4l2 *this) { + return this->buffers[this->buf.index].length; +} + +void CommonV4l2_deinit(CommonV4l2 *this) { + unsigned int i; + enum v4l2_buf_type type; + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + CommonV4l2_xioctl(this->fd, VIDIOC_STREAMOFF, &type); + for (i = 0; i < this->n_buffers; ++i) + v4l2_munmap(this->buffers[i].start, this->buffers[i].length); + v4l2_close(this->fd); + free(this->buffers); +} + +#endif |