Cosmetics
[rawv.git] / capture.cpp
blob1f8a9ec0bd562bff78bbf7437b4f5cb7a994dfa6
1 /* video capture for rawv
2 * Copyright (C) 2010 Kirill Smelkov <kirr@navytux.spb.ru>
3 * Copyright (C) 2011 Marine Bridge and Navigation Systems (http://mns.spb.ru/)
5 * This library is free software: you can Use, Study, Modify and Redistribute
6 * it under the terms of the GNU Lesser General Public License version 2.1, or
7 * any later version. This library is distributed WITHOUT ANY WARRANTY. See
8 * COPYING.LIB file for full License terms.
10 * V4L2 stuff, based on
11 * http://v4l2spec.bytesex.org/spec/capture-example.html
13 #include "rawv.h"
15 #include <linux/videodev2.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <sys/ioctl.h>
19 #include <sys/mman.h>
20 #include <unistd.h>
21 #include <fcntl.h> /* low-level i/o */
22 #include <errno.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <byteswap.h>
27 #include <stdio.h>
29 #define CLEAR(x) memset (&(x), 0, sizeof (x))
31 namespace rawv {
33 /******** VideoCapture ********/
35 VideoCapture::VideoCapture(const char *dev_name, int width, int height, int interlace_tb_swapped, int queue_len)
37 struct v4l2_capability cap;
38 struct v4l2_format fmt;
39 struct v4l2_requestbuffers req;
40 unsigned i;
41 char *p;
43 vcapture_on = 0;
45 fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
46 if (-1 == fd)
47 die ("Cannot open '%s': %d, %s", dev_name, errno, strerror (errno));
49 if (-1 == ioctl (fd, VIDIOC_QUERYCAP, &cap))
50 die_errno ("VIDIOC_QUERYCAP");
52 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
53 die ("%s is no video capture device", dev_name);
55 if (!(cap.capabilities & V4L2_CAP_STREAMING))
56 die ("%s does not support streaming i/o", dev_name);
59 /* Select video input, video standard and tune here. */
60 CLEAR (fmt);
62 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
63 fmt.fmt.pix.width = width;
64 fmt.fmt.pix.height = height;
65 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
66 fmt.fmt.pix.field = V4L2_FIELD_NONE /*i.e. progressive*/;
68 if (-1 == ioctl (fd, VIDIOC_S_FMT, &fmt)) {
69 warn_errno ("VIDIOC_S_FMT(..., progressive) failed -- will try interlaced...");
71 /* FIXME - better query dev capabilities in the first place */
72 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
73 if (-1 == ioctl (fd, VIDIOC_S_FMT, &fmt))
74 die_errno ("VIDIOC_S_FMT(..., interlaced)");
79 /* Note VIDIOC_S_FMT may change width and height. */
80 width = fmt.fmt.pix.width;
81 height = fmt.fmt.pix.height;
83 p = (char *)&fmt.fmt.pix.pixelformat;
84 fprintf(stderr, "Capturing '%c%c%c%c' h: %i w: %i stride: %i bt: %i\n",
85 p[0], p[1], p[2], p[3],
86 fmt.fmt.pix.height, fmt.fmt.pix.width, fmt.fmt.pix.bytesperline,
87 interlace_tb_swapped);
90 /* setup mmap capture */
91 CLEAR (req);
93 req.count = queue_len;
94 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
95 req.memory = V4L2_MEMORY_MMAP;
97 if (-1 == ioctl (fd, VIDIOC_REQBUFS, &req))
98 die_errno("VIDIOC_REQBUFS");
100 if (req.count < 2)
101 die("Insufficient buffer memory on %s", dev_name);
104 buffers.resize(req.count);
106 for (i = 0; i < req.count; ++i) {
107 struct v4l2_buffer buf;
109 CLEAR (buf);
111 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
112 buf.memory = V4L2_MEMORY_MMAP;
113 buf.index = i;
115 if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf))
116 die_errno ("VIDIOC_QUERYBUF");
118 buffers[i].width = fmt.fmt.pix.width;
119 buffers[i].height = fmt.fmt.pix.height;
120 buffers[i].bytesperline = fmt.fmt.pix.bytesperline;
123 * NOTE V4L2 constructs fourcc code for LE byteorder (see v4l2_fourcc
124 * in linux/videodev2.h), so in order to transform pixfmt into
125 * canonical order, we have to swap bytes on BE machines.
127 buffers[i].pixfmt_4cc = fmt.fmt.pix.pixelformat;
128 #if __BYTE_ORDER == __BIG_ENDIAN
129 buffers[i].pixfmt_4cc = bswap_32(buffers[i].pixfmt_4cc);
130 #endif
132 buffers[i].sequence = -1UL;
134 buffers[i].interlace_tb_swapped = interlace_tb_swapped;
136 buffers[i].length = buf.length;
137 buffers[i].start = (uint8_t *)
138 mmap (NULL /* start anywhere */,
139 buf.length,
140 PROT_READ | PROT_WRITE /* required */,
141 MAP_SHARED /* recommended */,
142 fd, buf.m.offset);
144 if (MAP_FAILED == buffers[i].start)
145 die_errno ("mmap");
151 VideoCapture::~VideoCapture()
153 unsigned int i;
155 /* munmap */
156 for (i = 0; i < buffers.size(); ++i)
157 if (-1 == munmap (buffers[i].start, buffers[i].length))
158 die_errno ("munmap");
161 if (-1 == close (fd))
162 die_errno ("close");
164 fd = -1;
169 void VideoCapture::v_start_capture()
171 unsigned int i;
172 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
174 if (vcapture_on)
175 return; /* already started */
177 for (i = 0; i < buffers.size(); ++i) {
178 struct v4l2_buffer buf;
180 CLEAR (buf);
182 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
183 buf.memory = V4L2_MEMORY_MMAP;
184 buf.index = i;
186 if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))
187 die_errno ("VIDIOC_QBUF (v_start_capture)");
190 if (-1 == ioctl (fd, VIDIOC_STREAMON, &type))
191 die_errno ("VIDIOC_STREAMON");
193 vcapture_on = 1;
197 void VideoCapture::v_stop_capture()
199 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
201 if (!vcapture_on)
202 return; /* already stopped */
204 if (-1 == ioctl (fd, VIDIOC_STREAMOFF, &type))
205 die_errno ("VIDIOC_STREAMOFF");
207 vcapture_on = 0;
212 int VideoCapture::read_frame(void)
214 struct v4l2_buffer buf;
216 CLEAR (buf);
218 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
219 buf.memory = V4L2_MEMORY_MMAP;
221 if (-1 == ioctl (fd, VIDIOC_DQBUF, &buf))
222 switch (errno) {
223 case EAGAIN:
224 return 0;
226 case EIO:
227 /* Could ignore EIO, see spec. */
229 /* fall through */
231 default:
232 die_errno ("VIDIOC_DQBUF");
235 assert (buf.index < buffers.size());
237 buffers[buf.index].sequence = buf.sequence;
239 /* notify subscribers */
240 notify_v_subscribers(&buffers[buf.index]);
242 if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))
243 die_errno ("VIDIOC_QBUF (read_frame)");
245 return 1;
248 } // rawv::