News Archive (1999-2012) | 2013-current at LinuxGizmos | Current Tech News Portal |    About   

Intro to V4L2 (Part 2)

Apr 15, 2009 — by LinuxDevices Staff — from the LinuxDevices Archive — 317 views

Foreword — This is the second of two articles describing the V4L2 (Video for Linux 2) interface, along with the first steps toward developing a device driver that uses the interface. It is based on Linux 2.6.28, and may not apply to other kernel versions.

Like the first article on V4L2, this article was contributed by Vladimir Davydov, an engineer with Promwad, an embedded development services company located in Minsk, Belarus. Promwad has used the V4L2 interface in several development projects, Davydov reports. Enjoy . . . !


Structures and helper functions in the V4L interface for buffering: Intro to V4L2 (Part 2)
by Vladimir Davydov

Buffering Management Functions

One of the most important tasks of the V4L driver is managing capture buffers. Most often this part is very complex to implement, as the V4L2 interface provides a possibility to retrieve captured video in several ways.

Fortunately, the kernel provides a set of structures and helper functions with the following functionalities:

  • Allocating memory for capture buffers
  • Initializing capture buffers and queues
  • Processing mmap, read, poll system calls
  • Processing main commands of ioctl system call
  • Using DMA
These functionalities are made available via certain kernel modules:
  • videobuf-core - provides general buffering functions
  • video-dma-sg - contains low-level functions for managing Scatter-Gather DMA buffers
  • video-dma-config - contains helper functions for physically contiguous buffers
  • videobuf-vmalloc - contains helper functions for buffers without DMA support
videobuf-dma-sg, videobuf-dma-contig, videobuf-vmalloc modules implement the same functionality for buffers of different type. We will dwell upon buffer types later.

Important Buffering Structures

The videobuf_buffer structure is used to represent capture buffers and is declared in the media/videobuf-core.h> header file.

The fields of this structure are quite well described in comments. Usually, drivers need to associate some specific information with a buffer. In such case, the driver must declare new structure for the buffer and include videobuf_buffer as the first field.

The VIVI driver demonstrates well how to do that correctly:

/* buffer for one video frame */
struct vivi_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;

struct vivi_fmt *fmt;
};

Here the pointer to the vivi_fmt structure array was added to the standard videobuf_buffer structure fields and contains the list of video formats supported by VIVI driver.

The next important structure is videobuf_queue designed for organizing a queue of capture buffers. The declaration of this structure is also located in the media/videobuf-core.h> file. You can find out about definitions of structure fields either from comments or by thoroughly studying the code of videobuf-core.c.

Types of Capture Buffers

Before use of buffering you have to define what type of capture buffers you need. This mostly depends on the device, for which the driver is developed.

At the present moment V4L, provides three types of capture buffers:

  1. Buffers used in devices that support transmission of video data by Scatter-Gather DMA (SG DMA). The buffer is not located linearly in physical memory, but it is split into fragments. The sizes of these fragments correspond to the size of memory page (PAGE_SIZE). This type of buffer uses such device drivers as cx88, bttv, saa7134.

    Low-level functions for managing SG DMA buffers are located in the drivers/media/video/videobuf-dma-sg.c file.

    To use this buffer type you have to load the videobuf-dma-sg module.

  2. Buffers representing contiguous area of physical memory and used in devices supporting DMA but without Scatter-Gather support.

    Low-level functions for managing this buffer type are located in the drivers/media/video/videobuf-dma-contig.c file.

  3. Buffers without built-in DMA support. This buffer type is usually used in devices, which don't support data transmission via DMA or if the driver uses its own code for DMA processing.

    In SG DMA this buffer also represents non-linear area of physical memory and is split into fragments of page's size (PAGE_SIZE).

    One of the drivers using this buffer type is VIVI. Source codes of functions for working with such buffers are located in the drivers/media/video/videobuf-vmalloc.c file.

Initializing Capture Buffers

Before calling the function for initializing buffers it is necessary to fill the video_queue_ops structure, defined in the media/videobuf-core.h> header file. This structure contains pointers to the functions working with buffers and which must be implemented in the driver:

int (*buf_setup)(struct videobuf_queue *q,
unsigned int *count, unsigned int *size);

The buf_setup method sets a number of buffers (count) and the size of each buffer (size).

int (*buf_prepare)(struct videobuf_queue *q,
struct videobuf_buffer *vb,
enum v4l2_field field);

The buf_prepare function prepares the buffer. In VIVI this function specifies general buffer parameters: size, width, height, field type.

void (*buf_queue)(struct videobuf_queue *q,
struct videobuf_buffer *vb);

The buf_queue function is called when capture buffer is put into a queue. A typical variant of this function implementation is given in VIVI driver.

void (*buf_release)(struct videobuf_queue *q,
struct videobuf_buffer *vb);

The buf_release method is called to release the buffer.

Below is an example of the videobuf_queue_ops structure initialization in VIVI:

static struct videobuf_queue_ops vivi_video_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
};

After the videobuf_queue_ops structure is filled, you have to call initialization function according to the capture buffer type.

  1. Initialization function for SG DMA capture buffers:

    void videobuf_queue_sg_init(struct videobuf_queue* q,
    struct videobuf_queue_ops *ops,
    struct device *dev,
    spinlock_t *irqlock,
    enum v4l2_buf_type type,
    enum v4l2_field field,
    unsigned int msize,
    void *priv);

  2. DMA for physically contiguous capture buffers:

    void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
    struct videobuf_queue_ops *ops,
    struct device *dev,
    spinlock_t *irqlock,
    enum v4l2_buf_type type,
    enum v4l2_field field,
    unsigned int msize,
    void *priv);

  3. For capture buffers without built-in DMA support:

    void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
    struct videobuf_queue_ops *ops,
    void *dev,
    spinlock_t *irqlock,
    enum v4l2_buf_type type,
    enum v4l2_field field,
    unsigned int msize,
    void *priv);

To use these functions you have to connect the corresponding header files:

The parameters in these functions are the same. The first parameter (q) is the pointer to capture buffer queue. The ops parameter points to the previously filled videobuf_queue_ops structure. The irqlock parameter points to the spinlock required for synchronization.

The type parameter defines capture buffer type. The list of available types is located in the media/videodev2.h> header file. In VIVI this parameter is set to V4L2_BUF_TYPE_VIDEO_CAPTURE. It means that buffers will be used to capture video.

The field parameter sets the order of video image fields. The definition of enum v4l2_field is located in the linux/videodev2.h> file. The following values are allowed:

  • V4L2_FIELD_ANY - driver can independently select the order of video image fields
  • V4L2_FIELD_NONE - the device doesn't support image splitting to fields
  • V4L2_FIELD_TOP - top field only
  • V4L2_FIELD_BOTTOM - bottom field only
  • V4L2_FIELD_INTERLACED - both fields are in interlaced condition
  • V4L2_FIELD_SEQ_TB - both fields are sequentially joined in the buffer; first the top field and then the bottom
  • V4L2_FIELD_SEQ_BT - the same as for V4L2_FIELD_SEQ_TB, but the fields order is the opposite
  • V4L2_FIELD_ALTERNATE - Sequential alternating of fields (top/bottom). The fields are saved to separate buffers
  • V4L2_FIELD_INTERLACED_TB - both fields are interlaced, the top field is the first in the image and the top field is passed first
  • V4L2_FIELD_INTERLACED_BT - both fields are interlaced, the top field is the first in the image, and the bottom field is passed first

The necessary value is usually selected depending on device capabilities.

The msize parameter specifies the size of capture buffer structure. In VIVI it is sizeof(struct vivi_buffer).

The last parameter - priv - specifies the value of the priv_data field in the videobuf_queue structure.

Releasing Capture Buffers

The functions for releasing the buffer, as a rule, are called in the method code, available by the buf_release pointer in the videobuf_queue_ops structure. In analogy to initialization functions, releasing functions depend on buffer type.

The following function is used for SG DMA buffers:

int videobuf_dma_free(struct videobuf_dmabuf *dma);

For physically contiguous buffers with DMA support:

void videobuf_dma_contig_free(struct videobuf_queue *q, 
struct videobuf_buffer *buf);

For capture buffers without DMA support:

void videobuf_vmalloc_free (struct videobuf_buffer *buf);

Processing the mmap System Call

In V4L the mmap system call is used as a method for accessing capture buffers from user application side by mapping memory allocated to buffers into user process area.

Through using buffering functions, the processing of the mmap system call resolves into calling function:

int videobuf_mmap_mapper(struct videobuf_queue *q,
struct vm_area_struct *vma);

Below is an example on how processing of the mmap call is implemented in VIVI driver:

static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
{
struct vivi_fh *fh = file->private_data;
struct vivi_dev *dev = fh->dev;
int ret;

dprintk(dev, 1, "mmap called, vma=0x%08lxn", (unsigned long)vma);

ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);

dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%dn",
(unsigned long)vma->vm_start,
(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
ret);

return ret;
}

Processing the read System Call

In mmap buffering functions save a driver developer from writing his/her own code as it is enough to call the following function:

ssize_t videobuf_read_stream(struct videobuf_queue *q,
char __user *data, size_t count, loff_t *ppos,
int vbihack, int nonblocking);

Below is an example on how the read call is processed in VIVI driver:

static ssize_t
vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
struct vivi_fh *fh = file->private_data;

if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
file->f_flags & O_NONBLOCK);
}
return 0;
}

Processing the poll System Call

With the help of the poll call the application can pause the execution until the driver receives the captured data. A more detailed description of how to use the poll call you can find in the official specification of V4L2.

By using helper buffering functions the processing of the poll call won't bring any difficulties and is done by using the following function:


unsigned int videobuf_poll_stream(struct file *file,
struct videobuf_queue *q,
poll_table *wait);

Below is an example on how the poll call is processed in VIVI driver:


static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait)
{
struct vivi_fh *fh = file->private_data;
struct vivi_dev *dev = fh->dev;
struct videobuf_queue *q = &fh->vb_vidq;

dprintk(dev, 1, "%sn", __func__);

if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
return POLLERR;

return videobuf_poll_stream(file, q, wait);
}

Processing Commands of ioctl System Call

To process ioctl buffering commands the following functions are available:

VIDIOC_REQBUFS:

int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req);

VIDIOC_QUERYBUF:
int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b);

VIDIOC_QBUF:
int videobuf_qbuf(struct videobuf_queue *q,  struct v4l2_buffer *b);

VIDIOC_DQBUF:
int videobuf_dqbuf(struct videobuf_queue *q, struct v4l2_buffer *b, int nonblocking);

VIDIOC_STREAMON:
int videobuf_streamon(struct videobuf_queue *q);

VIDIOC_STREAMOFF:
int videobuf_streamoff(struct videobuf_queue *q);
The examples of using these functions can be found in VIVI driver code.

Accessing Capture Buffer Video Data

As a rule, V4L driver doesn't need direct access to video data received from a video device. The driver just receives this data from the device and transmits it to a user process. Though, sometimes there appears a necessity to grant direct access to this data in driver code. For example, VIVI driver independently generates video data as the real video device is missing.

Depending on buffer type the access to video data is provided via the following functions:

  1. SG DMA:
    struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf);
  2. DMA for physically contiguous capture buffers:
    dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
  3. For capture buffers without built-in DMA support:
    void *videobuf_to_vmalloc (struct videobuf_buffer *buf);Quick Reference

    This section contains short description of structures and functions covered in the article.

    #include linux/fs.h>
    This header file defines the most important functions and structures for working with file system and required for developing device drivers.

    struct file_operations;

    struct file;

    struct inode;

    These are three important data structures used by the majority of device drivers. The file_operations structure contains methods for processing system calls for character device. The file structure describes open file in the system. The inode structure represents a file on the disk.

    #include  media/v4l2-dev.h>
    This structure contains helper functions and structures required by all V4L drivers.

    struct video_device;

    This is the main structure that describes a video device.

    int  video_register_device(struct video_device *vfd, int type, int nr);

    void video_unregister_device(struct video_device *vfd);

    These functions register a video device in the system and remove it from the system.

    struct video_device * video_device_alloc(void);

    void video_device_release(struct video_device *vfd);

    These helper functions allocate and release memory occupied by the video_device structure.

    #include media/v4l2-ioctl.h>

    This structure contains declarations of structures and functions required for processing ioctl commands.

    struct v4l2_ioctl_ops;

    This structure contains pointers to handlers of V4L2 ioctl commands.

    int video_ioctl2(struct inode *inode, struct file *file,
    unsigned int cmd, unsigned long arg);

    This method processes the ioctl system call, analyzes V4L2 command code and calls the corresponding handler from the v4l2_ioctl_ops structure.

    #include linux/videodev2.h>

    The main header file of V4L2 interface. This file contains the main definitions of all data types used both by applications and their drivers.

    #include media/videobuf-core.h>

    This structure contains the main functions for managing capture buffers.

    struct videobuf_buffer;

    This structure describes general attributes of capture buffer.

    struct videobuf_queue_ops;

    This structure contains pointers to capture buffer processing methods.

    struct videobuf_queue;

    This structure is designed for organizing buffer queue.

    int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req);

    int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b);

    int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b);

    int videobuf_dqbuf(struct videobuf_queue *q, struct v4l2_buffer *b, int nonblocking);

    int videobuf_streamon(struct videobuf_queue *q);

    int videobuf_streamoff(struct videobuf_queue *q);

    These functions process main commands of the ioctl system call connected with buffering.

    int videobuf_mmap_mapper(struct videobuf_queue *q,
    struct vm_area_struct *vma);

    This function processes the mmap system call.

    ssize_t videobuf_read_stream(struct videobuf_queue *q,
    char __user *data, size_t count, loff_t *ppos,
    int vbihack, int nonblocking);

    This function processes the read system call.

    unsigned int videobuf_poll_stream(struct file *file,
    struct videobuf_queue *q,
    poll_table *wait);This function processes the poll system call.

    #include media/videobuf-vmalloc.h>This header file contains helper functions for working with capture buffers without built-in DMA support.

    void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
    struct videobuf_queue_ops *ops,
    void *dev,
    spinlock_t *irqlock,
    enum v4l2_buf_type type,
    enum v4l2_field field,
    unsigned int msize,
    void *priv);

    This function initializes buffering system for capture buffers without built-in DMA support.

    void *videobuf_to_vmalloc (struct videobuf_buffer *buf);

    This function grants the access to video data contained in the capture buffer.

    void videobuf_vmalloc_free (struct videobuf_buffer *buf);

    This function releases capture buffer.

    #include media/videobuf-dma-contig.h>

    This header file contains helper functions and structures for working with capture buffers with DMA support.

    void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
    struct videobuf_queue_ops *ops,
    struct device *dev,
    spinlock_t *irqlock,
    enum v4l2_buf_type type,
    enum v4l2_field field,
    unsigned int msize,
    void *priv);

    These functions initialize buffering system for capture buffers with built-in DMA support.

    #include media/videobuf-dma-sg.h>

    This title file contains helper functions and structures for working with capture buffers with Scatter-Gather DMA support.

    void videobuf_queue_sg_init(struct videobuf_queue* q,
    struct videobuf_queue_ops *ops,
    struct device *dev,
    spinlock_t *irqlock,
    enum v4l2_buf_type type,
    enum v4l2_field field,
    unsigned int msize,
    void *priv);

    This function initializes buffering system for capture buffers with built-in SG DMA support.

    Conclusion

    The V4L2 API provides a convenient and modern interface for working with video capturing devices. Excellent documentation on V4L2 API, and availability of a great number of ready drivers and applications with open source code, allows significantly decreasing the development time.


    Useful links

    V4L2 home

    V4L2 API specification

    FFmpeg tools and libraries

    Xawtv TV application

    Tvtime TV application

    Video for Linux Two – Driver Writer's Guide

    MPlayer and MEncoder home

    The VIVI driver; a great starting point for V4L2 driver writers

    Linux Device Drivers, Third Edition


    About the author — Vladimir Davydov works as an engineer at Promwad Innovation Company. He has more than seven years experience in network programming and Linux kernel development for multimedia applications. In 2002, he graduated from Belarusian State University of Informatics and Radioelectronics (Minsk, Belarus) with a Bachelor of Science in Computer Science, and main specialization in compute machines, complexes, systems, and networks.


     
    This article was originally published on LinuxDevices.com and has been donated to the open source community by QuinStreet Inc. Please visit LinuxToday.com for up-to-date news and articles about Linux and open source.



Comments are closed.