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
15 #include <linux/videodev2.h>
17 #include <sys/types.h>
18 #include <sys/ioctl.h>
21 #include <fcntl.h> /* low-level i/o */
29 #define CLEAR(x) memset (&(x), 0, sizeof (x))
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
;
45 fd
= open (dev_name
, O_RDWR
/* required */ | O_NONBLOCK
, 0);
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. */
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 */
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");
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
;
111 buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
112 buf
.memory
= V4L2_MEMORY_MMAP
;
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
);
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 */,
140 PROT_READ
| PROT_WRITE
/* required */,
141 MAP_SHARED
/* recommended */,
144 if (MAP_FAILED
== buffers
[i
].start
)
151 VideoCapture::~VideoCapture()
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
))
169 void VideoCapture::v_start_capture()
172 enum v4l2_buf_type type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
175 return; /* already started */
177 for (i
= 0; i
< buffers
.size(); ++i
) {
178 struct v4l2_buffer buf
;
182 buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
183 buf
.memory
= V4L2_MEMORY_MMAP
;
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");
197 void VideoCapture::v_stop_capture()
199 enum v4l2_buf_type type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
202 return; /* already stopped */
204 if (-1 == ioctl (fd
, VIDIOC_STREAMOFF
, &type
))
205 die_errno ("VIDIOC_STREAMOFF");
212 int VideoCapture::read_frame(void)
214 struct v4l2_buffer buf
;
218 buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
219 buf
.memory
= V4L2_MEMORY_MMAP
;
221 if (-1 == ioctl (fd
, VIDIOC_DQBUF
, &buf
))
227 /* Could ignore EIO, see spec. */
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)");