|
@@ -0,0 +1,189 @@
|
|
|
+
|
|
|
+#include "vd.h"
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <sys/ioctl.h>
|
|
|
+#include <sys/mman.h>
|
|
|
+#include "sdl.h"
|
|
|
+#include "image.h"
|
|
|
+static void xioctl(int fh, 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);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int vd_init( vd_t* v, const char* dev, int w, int h, vd_cb cb)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ v->width=w;
|
|
|
+ v->height=h;
|
|
|
+ v->callback=cb;
|
|
|
+ strcpy(v->dev_name, dev);
|
|
|
+ v->fd = v4l2_open(v->dev_name, O_RDWR | O_NONBLOCK, 0);
|
|
|
+ if (v->fd < 0) {
|
|
|
+ perror("Cannot open device");
|
|
|
+ return -errno;
|
|
|
+ }
|
|
|
+ v->buffertmp=malloc(w*h*3);
|
|
|
+ CLEAR(v->fmt);
|
|
|
+ v->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ v->fmt.fmt.pix.width = w;
|
|
|
+ v->fmt.fmt.pix.height = h;
|
|
|
+ v->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
|
|
|
+ v->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
|
|
+ xioctl(v->fd, VIDIOC_S_FMT, &v->fmt);
|
|
|
+ if (v->fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
|
|
|
+ printf("Libv4l didn't accept RGB24 format. Can't proceed.\n");
|
|
|
+ return -errno;
|
|
|
+ }
|
|
|
+ if ((v->fmt.fmt.pix.width != w) || (v->fmt.fmt.pix.height != h))
|
|
|
+ printf("Warning: driver is sending image at %dx%d\n",
|
|
|
+ v->fmt.fmt.pix.width, v->fmt.fmt.pix.height);
|
|
|
+ v->width=v->fmt.fmt.pix.width;
|
|
|
+ v->height= v->fmt.fmt.pix.height;
|
|
|
+ CLEAR(v->req);
|
|
|
+ v->req.count = 2;
|
|
|
+ v->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ v->req.memory = V4L2_MEMORY_MMAP;
|
|
|
+ xioctl(v->fd, VIDIOC_REQBUFS, &v->req);
|
|
|
+ v->buffers = calloc(v->req.count, sizeof(*v->buffers));
|
|
|
+
|
|
|
+ for (v->n_buffers = 0; v->n_buffers < v->req.count; ++v->n_buffers) {
|
|
|
+ CLEAR(v->buf);
|
|
|
+
|
|
|
+ v->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ v->buf.memory = V4L2_MEMORY_MMAP;
|
|
|
+ v->buf.index = v->n_buffers;
|
|
|
+
|
|
|
+ xioctl(v->fd, VIDIOC_QUERYBUF, &v->buf);
|
|
|
+
|
|
|
+ v->buffers[v->n_buffers].length =v->buf.length;
|
|
|
+ v->buffers[v->n_buffers].start = v4l2_mmap(NULL, v->buf.length,
|
|
|
+ PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
|
+ v->fd, v->buf.m.offset);
|
|
|
+
|
|
|
+ if (MAP_FAILED == v->buffers[v->n_buffers].start) {
|
|
|
+ perror("mmap");
|
|
|
+ return -errno;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < v->n_buffers; ++i) {
|
|
|
+ CLEAR(v->buf);
|
|
|
+ v->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ v->buf.memory = V4L2_MEMORY_MMAP;
|
|
|
+ v->buf.index = i;
|
|
|
+ xioctl(v->fd, VIDIOC_QBUF, &v->buf);
|
|
|
+ }
|
|
|
+ v->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+
|
|
|
+ xioctl(v->fd, VIDIOC_STREAMON, &v->type);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int vd_close(vd_t* v)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ v->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ xioctl(v->fd, VIDIOC_STREAMOFF, &v->type);
|
|
|
+ for (i = 0; i < v->n_buffers; ++i)
|
|
|
+ v4l2_munmap(v->buffers[i].start, v->buffers[i].length);
|
|
|
+ v4l2_close(v->fd);
|
|
|
+ free(v->buffertmp);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int vd_callback(image_t* out, void* data)
|
|
|
+{
|
|
|
+ vd_t *vd = (vd_t*) data;
|
|
|
+ image_t in;
|
|
|
+
|
|
|
+ vd_shot(vd);
|
|
|
+ vd_image_current(vd, &in);
|
|
|
+ return vd->callback(vd, out, &in);
|
|
|
+}
|
|
|
+
|
|
|
+int vd_shot(vd_t* v)
|
|
|
+{
|
|
|
+ static int i=0, r;
|
|
|
+ do {
|
|
|
+ FD_ZERO(&v->fds);
|
|
|
+ FD_SET(v->fd, &v->fds);
|
|
|
+
|
|
|
+ /* Timeout. */
|
|
|
+ v->tv.tv_sec = 2;
|
|
|
+ v->tv.tv_usec = 0;
|
|
|
+
|
|
|
+ r = select(v->fd + 1, &v->fds, NULL, NULL, &v->tv);
|
|
|
+ } while ((r == -1 && (errno = EINTR)));
|
|
|
+ if (r == -1) {
|
|
|
+ perror("select");
|
|
|
+ return -errno;
|
|
|
+ }
|
|
|
+
|
|
|
+ CLEAR(v->buf);
|
|
|
+ v->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ v->buf.memory = V4L2_MEMORY_MMAP;
|
|
|
+ xioctl(v->fd, VIDIOC_DQBUF, &v->buf);
|
|
|
+/*
|
|
|
+ sprintf(v->out_name, "out%03d.ppm", i);
|
|
|
+ v->fout = fopen(v->out_name, "w");
|
|
|
+ if (!v->fout) {
|
|
|
+ perror("Cannot open image");
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
+ }
|
|
|
+
|
|
|
+ fprintf(v->fout, "P6\n%d %d 255\n",
|
|
|
+ v->fmt.fmt.pix.width, v->fmt.fmt.pix.height);
|
|
|
+ fwrite(v->buffers[v->buf.index].start, v->buf.bytesused, 1, v->fout);
|
|
|
+
|
|
|
+ fclose(v->fout);*/
|
|
|
+ xioctl(v->fd, VIDIOC_QBUF, &v->buf);
|
|
|
+
|
|
|
+ i++;
|
|
|
+
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int vd_get_relative_buffer_index(vd_t* v, int offset)
|
|
|
+{
|
|
|
+ offset+=v->buf.index;
|
|
|
+ offset%=v->n_buffers;
|
|
|
+ if(offset<0) offset+=v->n_buffers;
|
|
|
+ return offset;
|
|
|
+}
|
|
|
+
|
|
|
+image_t* vd_get_image (vd_t* v, image_t* im, int i)
|
|
|
+{
|
|
|
+ return image_set(im, v->width, v->height, (pixel_t*)v->buffers[vd_get_relative_buffer_index(v,i)].start);
|
|
|
+}
|
|
|
+
|
|
|
+image_t* vd_image_current (vd_t* v, image_t* im)
|
|
|
+{
|
|
|
+ return vd_get_image(v,im,0);
|
|
|
+}
|
|
|
+
|
|
|
+image_t* vd_image_prev (vd_t* v, image_t* im)
|
|
|
+{
|
|
|
+ return vd_get_image(v,im,-1);
|
|
|
+}
|
|
|
+
|
|
|
+image_t* vd_image_prev_prev (vd_t* v, image_t* im)
|
|
|
+{
|
|
|
+ return vd_get_image(v,im,-1);
|
|
|
+}
|