36 #include <sys/ioctl.h>
37 #include <linux/videodev2.h>
46 #define CLEAR(x) memset(&(x), 0, sizeof (x))
60 struct v4l2_buffer buf;
66 FD_SET(
dev->fd, &fds);
73 int sr = select(
dev->fd + 1, &fds, NULL, NULL, &tv);
78 if (EINTR == errno) {
continue; }
79 printf(
"[v4l2-capture] Select error %d on %s: %s\n", errno,
dev->name, strerror(errno));
80 dev->thread = (pthread_t) NULL;
83 printf(
"[v4l2-capture] Select timeout on %s\n",
dev->name);
91 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
92 buf.memory = V4L2_MEMORY_MMAP;
93 if (ioctl(
dev->fd, VIDIOC_DQBUF, &buf) < 0) {
94 printf(
"[v4l2-capture] Dequeue of buffer failed for %s.\n",
dev->name);
95 dev->thread = (pthread_t) NULL;
98 assert(buf.index <
dev->buffers_cnt);
101 dev->buffers[buf.index].timestamp = buf.timestamp;
102 dev->buffers[buf.index].pprz_timestamp = now_ts;
106 pthread_mutex_lock(&
dev->mutex);
108 dev->buffers_deq_idx = buf.index;
109 pthread_mutex_unlock(&
dev->mutex);
115 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
116 buf.memory = V4L2_MEMORY_MMAP;
117 buf.index = prev_idx;
118 if (ioctl(
dev->fd, VIDIOC_QBUF, &buf) < 0) {
119 printf(
"[v4l2-capture] Could not enqueue %d for %s\n", prev_idx,
dev->name);
139 struct v4l2_subdev_format sfmt;
143 int fd = open(subdev_name, O_RDWR, 0);
145 printf(
"[v4l2] Cannot open subdevice '%s': %d, %s\n", subdev_name, errno, strerror(errno));
150 if (ioctl(
fd, VIDIOC_SUBDEV_G_FMT, &sfmt) < 0) {
151 printf(
"[v4l2] Could not get subdevice data format settings of %s\n", subdev_name);
158 sfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
159 sfmt.format.width = size.
w;
160 sfmt.format.height = size.
h;
161 sfmt.format.code = code;
162 sfmt.format.field = V4L2_FIELD_NONE;
163 sfmt.format.colorspace = 1;
165 if (ioctl(
fd, VIDIOC_SUBDEV_S_FMT, &sfmt) < 0) {
166 printf(
"[v4l2] Could not set subdevice data format settings of %s\n", subdev_name);
188 struct v4l2_capability cap;
189 struct v4l2_format fmt;
190 struct v4l2_requestbuffers req;
191 struct v4l2_fmtdesc fmtdesc;
192 struct v4l2_crop crp;
201 int fd = open(device_name, O_RDWR | O_NONBLOCK, 0);
203 printf(
"[v4l2] Cannot open '%s': %d, %s\n", device_name, errno, strerror(errno));
208 if (ioctl(
fd, VIDIOC_QUERYCAP, &cap) < 0) {
209 printf(
"[v4l2] %s is no V4L2 device\n", device_name);
215 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
216 printf(
"[v4l2] %s is no V4L2 video capturing device\n", device_name);
221 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
222 printf(
"[v4l2] %s isn't capable of streaming (TODO: support reading)\n", device_name);
227 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
228 while (ioctl(
fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
230 if(fmtdesc.pixelformat == _pixelformat)
235 if(fmtdesc.index != 0 && fmtdesc.pixelformat != _pixelformat) {
236 printf(
"[v4l2] Pixelformat not available on device %s (wanted: %4X)\r\n", device_name, _pixelformat);
241 crp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
244 crp.c.width = crop.
w;
245 crp.c.height = crop.
h;
248 if(crop.
x != 0 || crop.
y != 0 || crop.
w !=
size.w || crop.
h !=
size.h) {
249 if (ioctl(
fd, VIDIOC_S_CROP, &crp) < 0) {
250 printf(
"[v4l2] Could not set crop window of %s\n", device_name);
257 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
258 fmt.fmt.pix.width =
size.w;
259 fmt.fmt.pix.height =
size.h;
260 fmt.fmt.pix.pixelformat = _pixelformat;
261 fmt.fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
262 fmt.fmt.pix.field = V4L2_FIELD_NONE;
264 if (ioctl(
fd, VIDIOC_S_FMT, &fmt) < 0) {
265 printf(
"[v4l2] Could not set data format settings of %s\n", device_name);
271 req.count = buffers_cnt;
272 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
273 req.memory = V4L2_MEMORY_MMAP;
274 if (ioctl(
fd, VIDIOC_REQBUFS, &req) < 0) {
275 printf(
"[v4l2] %s Does not support memory mapping\n", device_name);
282 if (buffers == NULL) {
283 printf(
"[v4l2] Not enough memory for %s to initialize %d MMAP buffers\n", device_name, req.count);
289 for (i = 0; i < req.count; ++i) {
290 struct v4l2_buffer buf;
294 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
295 buf.memory = V4L2_MEMORY_MMAP;
297 if (ioctl(
fd, VIDIOC_QUERYBUF, &buf) < 0) {
298 printf(
"[v4l2] Querying buffer %d from %s failed\n", i, device_name);
305 buffers[i].
length = buf.length;
306 buffers[i].
buf = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, buf.m.offset);
307 if (MAP_FAILED == buffers[i].buf) {
308 printf(
"[v4l2] Mapping buffer %d with length %d from %s failed\n", i, buf.length, device_name);
314 if(
check_contiguity((
unsigned long)buffers[i].buf, getpid(), &pmem, buf.length)) {
315 printf(
"[v4l2] Physical memory %d is not contiguous with length %d from %s\n", i, buf.length, device_name);
327 dev->name = strdup(device_name);
331 dev->buffers_cnt = req.count;
352 pthread_mutex_lock(&
dev->mutex);
356 img_idx =
dev->buffers_deq_idx;
360 pthread_mutex_unlock(&
dev->mutex);
370 img->
buf =
dev->buffers[img_idx].buf;
371 img->
ts =
dev->buffers[img_idx].timestamp;
372 img->
pprz_ts =
dev->buffers[img_idx].pprz_timestamp;
388 pthread_mutex_lock(&
dev->mutex);
390 img_idx =
dev->buffers_deq_idx;
393 pthread_mutex_unlock(&
dev->mutex);
406 img->
buf =
dev->buffers[img_idx].buf;
407 img->
ts =
dev->buffers[img_idx].timestamp;
408 img->
pprz_ts =
dev->buffers[img_idx].pprz_timestamp;
420 struct v4l2_buffer buf;
424 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
425 buf.memory = V4L2_MEMORY_MMAP;
427 if (ioctl(
dev->fd, VIDIOC_QBUF, &buf) < 0) {
428 printf(
"[v4l2] Could not enqueue %d for %s\n", img->
buf_idx,
dev->name);
442 enum v4l2_buf_type type;
445 if (
dev->thread != (pthread_t)NULL) {
446 printf(
"[v4l2] There is already a capturing thread running for %s\n",
dev->name);
452 for (i = 0; i <
dev->buffers_cnt; ++i) {
453 struct v4l2_buffer buf;
456 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
457 buf.memory = V4L2_MEMORY_MMAP;
459 if (ioctl(
dev->fd, VIDIOC_QBUF, &buf) < 0) {
460 printf(
"[v4l2] Could not enqueue buffer %d during start capture for %s\n", i,
dev->name);
466 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
467 if (ioctl(
dev->fd, VIDIOC_STREAMON, &type) < 0) {
468 printf(
"[v4l2] Could not start stream of %s, %d %s\n",
dev->name, errno, strerror(errno));
475 printf(
"[v4l2] Could not start capturing thread for %s (return code: %d)\n",
dev->name, rc);
478 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
479 if (ioctl(
dev->fd, VIDIOC_STREAMOFF, &type) < 0) {
480 printf(
"[v4l2] Could not stop stream of %s\n",
dev->name);
484 dev->thread = (pthread_t) NULL;
489 pthread_setname_np(
dev->thread,
"v4l2");
504 enum v4l2_buf_type type;
507 if (
dev->thread == (pthread_t) NULL) {
508 printf(
"[v4l2] Already stopped capture for %s\n",
dev->name);
513 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
514 if (ioctl(
dev->fd, VIDIOC_STREAMOFF, &type) < 0) {
515 printf(
"[v4l2] Could not stop stream of %s\n",
dev->name);
520 if (pthread_cancel(
dev->thread) < 0) {
521 printf(
"[v4l2] Could not cancel thread for %s\n",
dev->name);
526 pthread_join(
dev->thread, NULL);
527 dev->thread = (pthread_t) NULL;
545 for (i = 0; i <
dev->buffers_cnt; ++i) {
546 if (munmap(
dev->buffers[i].buf,
dev->buffers[i].length) < 0) {
547 printf(
"[v4l2] Could not unmap buffer %d for %s\n", i,
dev->name);
uint32_t get_sys_time_usec(void)
Get the time in microseconds since startup.
uint16_t h
height of the cropped area
struct timeval ts
The timestamp of creation.
uint16_t w
Width of the cropped area.
uint32_t buf_size
The buffer size.
void * buf
Image buffer (depending on the image_type)
uint32_t pprz_ts
The timestamp in us since system startup.
uint16_t x
Start position x (horizontal)
uint16_t y
Start position y (vertical)
uint8_t buf_idx
Buffer index for V4L2 freeing.
enum image_type type
The image type.
@ IMAGE_YUV422
UYVY format (uint16 per pixel)
static const struct usb_device_descriptor dev
Architecture independent timing functions.
struct v4l2_device * v4l2_init(char *device_name, struct img_size_t size, struct crop_t crop, uint8_t buffers_cnt, uint32_t _pixelformat)
Initialize a V4L2(Video for Linux 2) device.
static void * v4l2_capture_thread(void *data)
The main capturing thread This thread handles the queue and dequeue of buffers, to make sure only the...
bool v4l2_init_subdev(char *subdev_name, uint8_t pad, uint16_t code, struct img_size_t size)
Initialize a V4L2 subdevice.
void v4l2_close(struct v4l2_device *dev)
Close the V4L2 device (Thread safe) This needs to be preformed to clean up all the buffers and close ...
bool v4l2_start_capture(struct v4l2_device *dev)
Start capturing images in streaming mode (Thread safe)
void v4l2_image_get(struct v4l2_device *dev, struct image_t *img)
Get the latest image buffer and lock it (Thread safe, BLOCKING) This functions blocks until image acc...
void v4l2_image_free(struct v4l2_device *dev, struct image_t *img)
Free the image and enqueue the buffer (Thread safe) This must be done after processing the image,...
bool v4l2_stop_capture(struct v4l2_device *dev)
Stop capturing of the image stream (Thread safe) This function is blocking until capturing thread is ...
bool v4l2_image_get_nonblock(struct v4l2_device *dev, struct image_t *img)
Get the latest image and lock it (Thread safe, NON BLOCKING) This function returns NULL if it can't g...
Capture images from a V4L2 device (Video for Linux 2)
void * buf
Pointer to the memory mapped buffer.
struct v4l2_img_buf * buffers
The memory mapped image buffers.
uint8_t buffers_cnt
The number of image buffers.
#define V4L2_IMG_NONE
There currently no image available.
uint32_t physp
Physical address pointer.
size_t length
The size of the buffer.
int check_contiguity(unsigned long vaddr, pid_t pid, struct physmem *pmem, size_t size)
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.