{{{#!html
The Linux Video4Linux2 (v4l2) API is the kernel's video input and output interface.
The v4l2-ctl userspace application can be used to query or configure a v4l2 device. For complete information, including output resolutions etc , use the following:
root@ventana:~# v4l2-ctl --device /dev/video3 --all # query all details about /dev/video3
See Also:
Analog video v4l2 capture devices will support one or more of the various analog video standards used throughout the world. For example the ADV7180 supports NTSC, PAL, and SECAM standards.
You can use the Video4Linux API to determine if an input is detected and what mode by using the v4l2-ctl --get-standard command which reports one of the following:
Example:
v4l2-ctl --device /dev/video0 --get-standard
v4l2-ctl --device /devivideo0 --get-standard
Some capture devices have multiple video inputs. The v4l2-ctl application can be used to get or set the current input.
Examples:
v4l2-ctl --device /dev/video3 --get-input
v4l2-ctl --device /dev/video3 --set-input=1
You can use v4l2-ctl to show what pixel formats a video device supports and select a desired format. Note that v4l2 devices support one or more pixel formats, and various resolutions and framerates for each format. You must ask what resolutions are supported for a particular format, and what framerates are supported for a particular resolution/format.
Examples:
v4l2-ctl --device /dev/video3 --list-formats-ext
v4l2-ctl --device /dev/video3 --list-framesizes=UYVY
v4l2-ctl --device /dev/video3 --list-frameintervals=width=640,height=480,pixelformat=UYVY
v4l2-ctl --device /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=UYVY
It is not uncommon for a v4l2 driver to not properly support the enumeration of various formats, resolutions, and framerates. If you find that a device is not returning anything useful for --list-formats --list-formats-ext --list-framesizes --list-framerates then you can try --all to get the default configuration of the device.
Examples:
root@ventana:~# v4l2-ctl --device /dev/video0 --all Driver Info (not using libv4l2): Driver name : mxc_v4l2 Card type : Bus info : Driver version: 0.1.11 Capabilities : 0x05000005 Video Capture Video Overlay Read/Write Streaming Video input : 0 (CSI IC MEM: ok) Video output: 0 (DISP3 BG) Video Standard = 0x00000000 Format Video Capture: Width/Height : 288/352 Pixel Format : 'UYVY' Field : Any Bytes per Line: 432 Size Image : 152064 Colorspace : Unknown (00000000) Format Video Overlay: Left/Top : 0/0 Width/Height: 160/160 Field : Any Chroma Key : 0x00000000 Global Alpha: 0x00 Clip Count : 0 Clip Bitmap : No Framebuffer Format: Capability : Extern Overlay Flags : Overlay Matches Capture/Output Size Width : 0 Height : 0 Pixel Format : '' Crop Capability Video Capture: Bounds : Left 0, Top 0, Width 1920, Height 1080 Default : Left 0, Top 0, Width 1920, Height 1080 Pixel Aspect: 0/0 Crop: Left 0, Top 0, Width 1920, Height 1080 Streaming Parameters Video Capture: Frames per second: 60.000 (60/1) Read buffers : 0 Streaming Parameters Video Output: Frames per second: invalid (0/0) Write buffers : 0
root@ventana:~# v4l2-ctl --device /dev/video1 --all Driver Info (not using libv4l2):[ 1863.994275] ERROR: unrecognized std! ffffff (PAL=ff, NTSC=b000 Driver name : mxc_v4l2 Card type : Bus info : Driver version: 0.1.11 Capabilities : 0x05000005 Video Capture Video Overlay Read/Write Streaming Video input : 0 (CSI IC MEM: ok) Video output: 0 (DISP3 BG) Video Standard = 0x00ffffff PAL-B/B1/G/H/I/D/D1/K/M/N/Nc/60 NTSC-M/M-JP/443/M-KR SECAM-B/D/G/H/K/K1/L/Lc Format Video Capture: Width/Height : 288/352 Pixel Format : 'YU12' Field : Any Bytes per Line: 432 Size Image : 152064 Colorspace : Unknown (00000000) Format Video Overlay: Left/Top : 0/0 Width/Height: 160/160 Field : Any Chroma Key : 0x00000000 Global Alpha: 0x00 Clip Count : 0 Clip Bitmap : No Framebuffer Format: Capability : Extern Overlay Flags : Overlay Matches Capture/Output Size Width : 0 Height : 0 Pixel Format : '' Crop Capability Video Capture: Bounds : Left 0, Top 0, Width 720, Height 625 Default : Left 0, Top 0, Width 720, Height 625 Pixel Aspect: 0/0 Crop: Left 0, Top 0, Width 720, Height 576 Streaming Parameters Video Capture: Frames per second: 30.000 (30/1) Read buffers : 0 Streaming Parameters Video Output: Frames per second: invalid (0/0) Write buffers : 0
You can use v4l2-ctl to capture frames as well.
Examples:
v4l2-ctl --device /dev/video0 --stream-mmap --stream-to=frame.raw --stream-count=1
Note that the convert tool from the ImageMagick package is useful for image format conversions as long as you know the specific details of the raw image.
Examples:
convert -size 640x480 -depth 16 uyvy:frame.raw frame.png
For an example v4l2 application for capturing frames see here
For capturing video we recommend using more full-featured applications such as GStreamer
If you are coding an application that uses the v4l2 API the best examples are the v4l2-util application. You can find its source at https://git.linuxtv.org/v4l-utils.git/tree/
The API documentation can be found at:
Examples:
As a rule of thumb it is best to configure all aspects of a device within your code to eliminate any dependence on the initial state of a video device and/or requiring configuring a device outside of your application with something like v4l2-ctl. For completeness set the following:
Be aware that the ioctl syscall can return a -1 result with errno = EINTR to indicate the syscall was interrupted in which case it should be tried again. Because of this you should consider providing a wrapper for ioctl such as:
static int xioctl(int fh, int request, void *arg) { int r; do { r = ioctl(fh, request, arg); } while (-1 == r && EINTR == errno); return r; }
The Ventana product family based on the Freescale IMX6 System On Chip (SoC) has a Freescale provided capture driver (mxc_v4l2_capture) that is present in the Gateworks downstream vendor kernel used for the Yocto BSP.
This capture device driver implements two video inputs which represent different pipelines in the SoC:
If capturing frames be sure to skip the first frame as the CSI has not fully synchronized on its capture input.
To demonstrate a capture of a raw frame you can use the v4l2_ctl application:
# configure input 1 for CSI -> MEM (raw image capture) v4l2-ctl --device /dev/video0 --set-input=1 # configure format v4l2-ctl --device /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=UYVY # capture 2nd frame v4l2-ctl --device /dev/video0 --stream-mmap --stream-skip=1 --stream-to=frame.raw --stream-count=1 # Use ImageMagick to convert it from raw 16-bit UYVY to PNG convert -size 1920x1080 -depth 16 uyvy:frame.raw frame.png
Notes:
Code Example:
/* * V4L2 video capture example * * This program can be used and distributed without restrictions. * * This program is provided with the V4L2 API * see http://linuxtv.org/docs.php for more information */ #include <byteswap.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <assert.h> #include <fcntl.h> /* low-level i/o */ #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <linux/videodev2.h> #define CLEAR(x) memset(&(x), 0, sizeof(x)) struct buffer { void *start; size_t length; }; static void errno_exit(const char *s) { fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno)); exit(EXIT_FAILURE); } static int xioctl(int fh, int request, void *arg) { int r; do { r = ioctl(fh, request, arg); } while (-1 == r && EINTR == errno); return r; } /* 16bit/pixel interleaved YUV */ static void process_image(const void *_p, struct v4l2_pix_format *fmt) { const uint8_t *p = _p; int8_t u; uint8_t y1; int8_t v; uint8_t y2; int r, g, b, c, d ,e; int red, i, x, y; int size = fmt->sizeimage; printf("Processing Frame: %dx%d %c%c%c%c\n", fmt->width, fmt->height, (fmt->pixelformat >> 0) & 0xff, (fmt->pixelformat >> 8) & 0xff, (fmt->pixelformat >> 16) & 0xff, (fmt->pixelformat >> 24) & 0xff); red = 0; for (i = 0; i < size; i += 4) { u = p[i+0]; y1 = p[i+1]; v = p[i+2]; y2 = p[i+3]; u -= 128; v -= 128; r = y1 + v + (v>>2) + (v>>3) + (v>>5); g = y1 - ((u>>2) + (u>>4) + (u>>5)) - ((v>>1) + (v>>3) + (v>>4) + (v>>5)); b = y1 + u + (u>>1) + (u>>2) + (u>>6); if (r > 100 && g < 60 && b < 60) red++; r = y2 + v + (v>>2) + (v>>3) + (v>>5); g = y2 - ((u>>2) + (u>>4) + (u>>5)) - ((v>>1) + (v>>3) + (v>>4) + (v>>5)); b = y2 + u + (u>>1) + (u>>2) + (u>>6); if (r > 100 && g < 60 && b < 60) red++; /* describe pixels on first line every 250 pixels * (colorbars) */ x = (i>>1) % fmt->width; y = (i>>1) / fmt->height; if (y == 0 && !(x % 250)) { printf("[%4d,%4d] YUYV:0x%02x%02x%02x%02x ", x,y,y1,(uint8_t)u,y2,(uint8_t)v); printf("RGB:0x%02x%02x%02x\n", r,g,b); } } printf("red pixel count=%d\n", red); } static void save_frame(const char *path, const void *p, int size) { int fd, rz; fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0755); if (fd < 0) perror("open"); else { rz = write(fd, p, size); printf("Wrote %d of %d bytes to %s\n", rz, size, path); close(fd); } } int main(int argc, char **argv) { static char *dev_name; int width, height; static int fd = -1; struct stat st; struct buffer *buffers; static unsigned int n_buffers; enum v4l2_buf_type type; struct v4l2_capability cap; struct v4l2_format fmt; struct v4l2_requestbuffers req; struct v4l2_streamparm parm; struct v4l2_input input; v4l2_std_id std_id; struct v4l2_buffer buf; unsigned int count; unsigned int i; char filename[32]; /* parse args */ if (argc < 5) { fprintf(stderr, "usage: %s <device> <width> <height> <count>\n", argv[0]); exit(1); } dev_name = argv[1]; width = atoi(argv[2]); height = atoi(argv[3]); count = atoi(argv[4]); /* open device */ fd = open(dev_name, O_RDWR | O_NONBLOCK, 0); if (-1 == fd) { fprintf(stderr, "Cannot open '%s': %d, %s\n", dev_name, errno, strerror(errno)); exit(EXIT_FAILURE); } /* get standard (wait for it to be locked onto a signal) */ if (-1 == xioctl(fd, VIDIOC_G_STD, &std_id)) perror("VIDIOC_G_STD"); for (i = 0; std_id == V4L2_STD_ALL && i < 10; i++) { usleep(100000); xioctl(fd, VIDIOC_G_STD, &std_id); } /* set the standard to the detected standard (this is critical for autodetect) */ if (std_id != V4L2_STD_UNKNOWN) { if (-1 == xioctl(fd, VIDIOC_S_STD, &std_id)) perror("VIDIOC_S_STD"); if (std_id & V4L2_STD_NTSC) printf("found NTSC TV decoder\n"); if (std_id & V4L2_STD_SECAM) printf("found SECAM TV decoder\n"); if (std_id & V4L2_STD_PAL) printf("found PAL TV decoder\n"); } /* ensure device has video capture capability */ if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { if (EINVAL == errno) { fprintf(stderr, "%s is no V4L2 device\n", dev_name); exit(EXIT_FAILURE); } else { errno_exit("VIDIOC_QUERYCAP"); } } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { fprintf(stderr, "%s is no video capture device\n", dev_name); exit(EXIT_FAILURE); } if (!(cap.capabilities & V4L2_CAP_STREAMING)) { fprintf(stderr, "%s does not support streaming i/o\n", dev_name); exit(EXIT_FAILURE); } /* set video input */ CLEAR(input); input.index = 1; /* IMX6 v4l2 driver: input1 is CSI<->MEM */ if (-1 == xioctl(fd, VIDIOC_S_INPUT, &input)) perror("VIDIOC_S_INPUT"); /* set framerate */ CLEAR(parm); parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_S_PARM, &parm)) perror("VIDIOC_S_PARM"); /* get framerate */ CLEAR(parm); parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_G_PARM, &parm)) perror("VIDIOC_G_PARM"); /* set format */ CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = width; fmt.fmt.pix.height = height; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; fmt.fmt.pix.field = V4L2_FIELD_ANY; if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) errno_exit("VIDIOC_S_FMT"); /* get and display format */ CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt)) errno_exit("VIDIOC_G_FMT"); printf("%s: %dx%d %c%c%c%c %2.2ffps\n", dev_name, fmt.fmt.pix.width, fmt.fmt.pix.height, (fmt.fmt.pix.pixelformat >> 0) & 0xff, (fmt.fmt.pix.pixelformat >> 8) & 0xff, (fmt.fmt.pix.pixelformat >> 16) & 0xff, (fmt.fmt.pix.pixelformat >> 24) & 0xff, (float)parm.parm.capture.timeperframe.denominator / (float)parm.parm.capture.timeperframe.numerator ); /* request buffers */ CLEAR(req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf(stderr, "%s does not support " "memory mapping\n", dev_name); exit(EXIT_FAILURE); } else { errno_exit("VIDIOC_REQBUFS"); } } if (req.count < 2) { fprintf(stderr, "Insufficient buffer memory on %s\n", dev_name); exit(EXIT_FAILURE); } /* allocate buffers */ buffers = calloc(req.count, sizeof(*buffers)); if (!buffers) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } /* mmap buffers */ for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) errno_exit("VIDIOC_QUERYBUF"); buffers[n_buffers].length = buf.length; buffers[n_buffers].start = mmap(NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset); if (MAP_FAILED == buffers[n_buffers].start) errno_exit("mmap"); } /* queue buffers */ for (i = 0; i < n_buffers; ++i) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); } /* start capture */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) errno_exit("VIDIOC_STREAMON"); /* capture frame(s) (we throw away first incomplete frame ) */ for (i = 0; i < count + 1; i++) { for (;;) { fd_set fds; struct timeval tv; int r; FD_ZERO(&fds); FD_SET(fd, &fds); /* Timeout. */ tv.tv_sec = 2; tv.tv_usec = 0; r = select(fd + 1, &fds, NULL, NULL, &tv); if (-1 == r) { if (EINTR == errno) continue; errno_exit("select"); } if (0 == r) { fprintf(stderr, "select timeout\n"); exit(EXIT_FAILURE); } /* dequeue captured buffer */ CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { if (errno == EAGAIN) continue; errno_exit("VIDIOC_DQBUF"); } assert(buf.index < n_buffers); /* skip first image as it may not be sync'd */ if (i > 0) { process_image(buffers[buf.index].start, &fmt.fmt.pix); sprintf(filename, "frame%d.raw", i); save_frame(filename, buffers[buf.index].start, buf.bytesused); } /* queue buffer */ if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); break; } } /* stop capture */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) errno_exit("VIDIOC_STREAMOFF"); /* unmap and free buffers */ for (i = 0; i < n_buffers; ++i) if (-1 == munmap(buffers[i].start, buffers[i].length)) errno_exit("munmap"); free(buffers); /* close device */ if (-1 == close(fd)) errno_exit("close"); fprintf(stderr, "\n"); return 0; }
Example usage:
$ ./capture /dev/video0 1920 1080 1 /dev/video0: 1920x1080 UYVY 60.00fps Processing Frame: 1920x1080 UYVY [ 0, 0] YUYV:0xeb00eb00 RGB:0xebebeb [ 250, 0] YUYV:0x9dad9d0d RGB:0xaeb409 [ 500, 0] YUYV:0x801b80ae RGB:0x0bb6ae [ 750, 0] YUYV:0x6dc96dbb RGB:0x0ab50b [1000, 0] YUYV:0x52365244 RGB:0xb111b0 red pixel count=259200 Wrote 4147200 of 4147200 bytes to frame.raw ./convert -size 1920x1080 -depth 16 uyvy:frame.raw frame.png # convert to png via imagemagick
$ ./capture /dev/video1 720 480 1 /dev/video1: 720x520 UYVY 30.00fps Processing Frame: 720x520 UYVY [ 0, 0] YUYV:0x1eff1c00 RGB:0x1c1f18 [ 250, 0] YUYV:0x1dfd1d01 RGB:0x1e2016 [ 500, 0] YUYV:0x28fa2aff RGB:0x26321e red pixel count=27 Wrote 748800 of 748800 bytes to frame.raw ./convert -size 720x480 -depth 16 uyvy:frame.raw frame.png # convert to png via imagemagick