Video for Linux (2.4)

References:
A. Cox,Video4Linux Programming, 2000, available on www.kernelnewbies.org

Video for Linux (V4L) is an abstract layer that presents a common interface for media devices, such as cameras, tvs, audios, and tuners. It sits in the drivers/media/video subdirectory of the kernel tree.
V4L is compiled in the kernel with the CONFIG_VIDEO_DEV option. proc filesystem support is further added with the CONFIG_VIDEO_PROC_FS option.
The main structure is video_device define in the header file include/linux/videodev.h. It contains as well as the pointers to the methods used by V4L to dispatch the user application calls: open(), close(), read(), write(), poll(), mmap(), ioctl, and initialize. This last one is called by V4L at initialization after it has finished with its own initializations.
A driver that want to export its functionalities to userland via V4L must call video_register_device(), which takes three args: a pointer to the driver's video_device, the type of the driver, and the requested minor (-1 for no request). When the driver wants to detach from V4L it calls video_unregister_device() with the pointer to its video_device structure. By registering with V4L the driver exposes to user processes only the function video_fops, ie, open(), release(), poll(), read(), write(), ioctl(), and mmap(). llseek() is no_llseek(). The others are forwarding to the driver's related functions.
The most complex API is probably ioctl.
Reading is possibble with the system call read(). V4L calls the driver's read() if there is one, otherwise returns an error (EINVAL), The video device may support also the write() system call. If not V4L return 0 on write().
Another way to read images from the device is through the mmap interface, which must first be set up with the mmap() system call. Next the application gets the size of the memory buffer and offset of each frame in the buffer with the ioctl VIDIOCMBUF call. The application issues acquisition commands with the ioctl VIDIOCMCAPTURE call, specifying the requested frame index. This call starts the acquisition and returns immediately. The application waits for the completion of the acquisition with the ioctl VIDIOCSYNC. Therefore the sequence of calls is something like
   int index = 0;
   int newindex;
   ioctl( fd, VIDIOCMCAPTURE, &index);
   while ( 1 ) {
     newindex = (index+1) % FRAME_NUMBER;
     ioctl( fd, VIDIOCMCAPTURE, &index);
     ioctl( fd, VIDIOCSYNC, &index);
     // process frame "index"
     index = newindex;
   }

Exercise

Write a memory-based video camera driver that registers with V4L subsystem. Check that the memory-based video camera operates properly, by writing a graphical program that displays the frames.
Here is a solution for the driver: mmvideo.c mmvideo.h and the Makefile. The driver provides images either through the read() system call, or the user application can mmap() the frame buffers. The driver policy is to try to serve the mmapped frames first, and then the reading processes.
Finally here is a simple application that loads an image onto the camera memory, and displays the frames generated by the camera: mmvideotest.cpp. It needs a few helper classes, mmvideoutil.tgz (the image comes from the source Documentation) and libjpeg and libX11, which you probably already have. Check /proc/video/mmvideo while the application is running. Enjoy!

Video for Linux 2 (2.6)

References:
http://linux.bytesex.org/v4l2/API.html

The interface to VideoForLinux2 has changed a little in the kernel 2.6. Mostly to keep into account the new driver class model, which offers a better support for managing components lifecycle.
A video device registers with the V4L2 core with video_register_device(video_device *, type, nr). The first parameter is apointer to the video device structure. The second is the type of the device, eg, VFL_TYPE_GRABBER.
The video_device struct describes a video device and is defined in videodev.h. It contains
Video Types

Video buffer types are listed in the enum v4l2_buf_type. For example, V4L2_BUF_TYPE_VIDEO_CAPTURE.
The types of memory are listed in the enum v4l2_memory: V4L2_MEMORY_MMAP, V4L2_MEMORY_USERPTR, and V4L2_MEMORY_OVERLAY.
Capabilities

Video capabilities are described with the struct v4l2_capability, which contains descriptive strings: the driver name, the card description, and the bus information bus_info. It has a version which should be set to the kernel version, and an integer for the device capabilities. The capabilities related to video are
The ioctl VIDIOC_QUERYCAP is used to query device capabilities.
Image format

The struct v4l2_pix_format contains the image width and height, the pixelformat, the bytesperline, the image size sizeimage, and field and colorspace. The field (of enum v4l2_field) describes how the frame fields are captured: for example V4L2_FIELD_NONE means that the device has no fields, V4L2_FIELD_TOP means that the driver capture only the top fields, etc. (see the include file videodev2.h for all the possibilities). colorspace (of enum v4l2_colorspace) describes the color-space, V4L2_COLORSPACE_SRGB is probably good start for RGB color-spaces.
Pixel format

Pixel formats are described by the struct v4l2_fmtdesc, which contains an index (the format number), the video buffer type, flags, a description string, and the four-char pixelformat. Several four-char formats are defined, eg, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_RGB565, etc.
Pixel format appear in the r/w ioctl VIDIOC_ENUM_FMT Controls

V4L2 defines structures and ioctl to support video controls (see videodev2.h). A v4l2_control has an id and a value.
The query-control struct, v4l2_queryctrl, contains the relevant information about a control, and is used in the ioctl VIDIOC_QUERYCTRL. It has
  • id the numerical id of the control;
  • type, the type of the control, for example V4L2_CTRL_TYPE_INTEGER. It can be integer, boolean, menu, or button;
  • name, the descriptive name of the control;
  • minimum, maximum, step and default_value;
  • flags, ???
  • and a reserved array of two elements.
Video specific control id's are V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST, V4L2_CID_SATURATION, V4L2_CID_HUE, V4L2_CID_BLACK_LEVEL, V4L2_CID_RED_BALANCE, V4L2_CID_BLUE_BALANCE (white balance is a combination of red and blue balances), V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CID_DO_WHITE_BALANCE, V4L2_CID_GAMMA, V4L2_CID_WHITENESS, V4L2_CID_EXPOSURE, V4L2_CID_AUTOGAIN, V4L2_CID_GAIN, V4L2_CID_HFLIP, V4L2_CID_VFLIP, V4L2_CID_HCENTER, and V4L2_CID_VCENTER. There are also audio related control id's.

ioctl

V4L2 has a large number of ioctl:
  • VIDIOC_QUERYCAP, the user process reads the device capability. The driver should fill the driver name, the capabilities, the kernel version, card, and bus_info.
  • VIODIOC_ENUMFMT,
  • VIDIOC_G_FTM, the driver fills in the format the buffer type (eg, V4L2_BUF_TYPE_VIDEO_CAPTURE), and the image format fmt.pix.
  • VIDIOC_S_FMT;
  • VIDIOC_REQBUFS, ...
  • VIDIOC_QUERYBUF, has argument a v4l2_buffer ...
  • VIDIOC_G_FBUF and VIDIOC_S_FBUF ...
  • VIDIOC_OVERLAY ...
  • VIDIOC_QBUF queue a v4l2_buffer
  • VIDIOC_DQBUF dequeue a v4l2_buffer
  • VIDIOC_STREAMON and VIDIOC_STREAMOFF ...
  • VIDIOC_G_PARM and VIDIOC_S_PARM
  • VIDIOC_G_STD and VIDIOC_S_STD
  • VIDIOC_ENUMSTD
  • VIDIOC_ENUMINPUT
  • VIDIOC_G_CTRL and VIDIOC_S_CTRL ...
  • VIDIOC_QUERYCTRL
  • VIDIOC_QUERYMENU
  • VIDIOC_CROPCAP
  • VIDIOC_G_CROP and VIDIOC_S_CROP
  • VIDIOC_QUERYSTD
  • VIDIOC_G_JPEGCOMP and VIDIOC_S_JPEGCOMP
There are also ioctl for the audio/tuner, and some odl ioctl temporarily kept for backward compatibility only.

The driver

This is a description of the actions of a driver, based on the meteor frame grabber. It is only an example and it does not mean that all the video grabber should be made in the same way.
Module init/exit

init() should
  • do all the hardware discovery (PCI) and initialization;
  • initialize the high memory for the video buffers
  • allocate and initialize the dynamic structures
  • allocate a videodev, video_device_alloc() for each device;
  • initialize it (name, type or type2, release, fops) and set the private data by calling video_set_drvdata(videodev *, void *)
  • register with V4L2, video_register_device(videodev *, type, -1)
  • complete the structure initialization (create workqueues).
exit() should
  • unregister from V4L2, v4l2_unregister_device(videodev *)
  • clear dynamic structures (destroy workqueue).
  • release the high memory
File operations

open()
  • retrieve the videodev from the file, using video_devdata(file), and its private data, video_get_drvdata()
  • find (or allocate and configure) an unused struct for the new open device; initialize it
  • if this is the first open device do the dynamic initialization of the driver: request IRQ, initialize lists, reset capture fields
close() (ie, file operation release())
  • retrieve the open device struct from the file
  • clear it
  • if this is the last close, release dynamic resourses: disable interrupts (and wake up waiting processes), release IRQ
write() returns EINVAL
lseek() returns ESPIPE
read()
  • retrieve the open device from the file
  • do some safety checks (status of the device, and the video decoder)
  • tell the hardware to capture a frame
  • wait for it (if not O_NONBLOCKING)
  • read the new frame to userspace
mmap()
  • retrieve the open device from the file
  • if the driver has already high memory buffers return them to high memory
  • get a high memory address and remap the vma to start at this address; set the vma_ops
poll()
  • retrieve the open device from the file
  • check the lists of streaming buffers to see if there is one ready
  • wait

Marco Corvi - 2003