Video driver development based on v4l2

Source: Internet
Author: User

V4l2 API and Data Structure

V4l2 is an upgraded version of v4l. It provides a set of interface specifications for Video device programs in Linux. Includes a set of data structures and underlying v4l2 driver interfaces.

1. Common structs are defined in the kernel directory include/Linux/videodev2.h.

Struct v4l2_requestbuffers // request frame buffering, corresponding to the command vidioc_reqbufs
Struct v4l2_capability // specifies the function of the Video device. The corresponding command is vidioc_querycap.
Struct v4l2_input // specifies the video input information, corresponding to the command vidioc_enuminput.
Struct v4l2_standard // specifies the video standard, such as PAL and NTSC. It corresponds to the vidioc_enumstd command.
Struct v4l2_format // frame format, corresponding to commands such as vidioc_g_fmt and vidioc_s_fmt
Struct v4l2_buffer // a frame of image cache in the driver, corresponding to the command vidioc_querybuf

Struct v4l2_crop // video signal rectangular border

V4l2_std_id // video standard

2. Common ioctl interface commands are also defined in include/Linux/videodev2.h.

Vidioc_reqbufs // allocate memory

Vidioc_querybuf // convert the data cache allocated in vidioc_reqbufs to a physical address

Vidioc_querycap // query driver Function

Vidioc_enum_fmt // obtain the video format supported by the current driver

Vidioc_s_fmt // sets the frequency capture format of the current driver.

Vidioc_g_fmt // read the current drive's frequency capture format

Vidioc_try_fmt // verify the display format of the current driver

Vidioc_cropcap // query driver pruning capability

Vidioc_s_crop // sets the rectangular border of the video signal.

Vidioc_g_crop // The rectangular border for reading Video Signals

Vidioc_qbuf // read data from the cache

Vidioc_dqbuf // put the data back into the cache queue

Vidioc_streamon // starts the video display function

Vidioc_streamoff // The function used to display the end video.

Vidioc_querystd // check the standards supported by the current video device, such as pal or NTSC.

3. Procedure

V4l2 provides many access interfaces. You can select an operation method as needed. Note that few drivers fully implement all interface functions. Therefore, you need to refer to the driver source code or carefully read the instructions for use by the driver provider.

The following describes an operation procedure for your reference.

(1) Open the Device File

Int FD = open (devicename, mode );

Devicename:/Dev/video0,/dev/video1 ......

Mode:O_rdwr [| o_nonblock]

If you use the non-blocking mode to call a video device, when there is no available video data, it does not block and returns immediately.

(2) obtain the capability of the device

Struct v4l2_capability capability;

Int ret = IOCTL (FD, vidioc_querycap, & capability );

Check whether a device has any functions, such as video input.

(3) Select Video Input

Struct v4l2_input input;

...... Initialize Input

Int ret = IOCTL (FD, vidioc_querycap, & input );

A video device can have multiple video inputs. This function is optional if there is only one input.

(4) detection of supported video formats

V4l2_std_id STD;

Do {

Ret = IOCTL (FD, vidioc_querystd, & STD );

} While (ret =-1 & errno = eagain );

Switch (STD ){

Case v4l2_std_ntsc:

//......

Case v4l2_std_pal:

//......

}

(5) set the video capture format

Struct v4l2_format FMT;

FMT. type = v4l2_buf_type_video_output;

FMT. FMT. pix. pixelformat = v4l2_pix_fmt_uyvy;

FMT. FMT. pix. Height = height;

FMT. FMT. pix. width = width;

FMT. FMT. pix. Field = v4l2_field_interlaced;

Ret = IOCTL (FD, vidioc_s_fmt, & FMT );

If (RET ){

Perror ("vidioc_s_fmt/N ");

Close (FD );

Return-1;

}

(6) apply for frame caching from the driver

Struct v4l2_requestbuffers req;

If (IOCTL (FD, vidioc_reqbufs, & req) =-1 ){

Return-1;

}

The v4l2_requestbuffers structure defines the number of caches, and the driver applies for the corresponding number of video caches accordingly. Multiple caches can be used to create a FIFO to improve video collection efficiency.

(7) obtain the information of each cache and map it to the user space.

Typedef struct videobuffer {

Void * start;

Size_t length;

} Videobuffer;

Videobuffer * buffers = calloc (req. Count, sizeof (* buffers ));

Struct v4l2_buffer Buf;

For (numbufs = 0; numbufs <Req. Count; numbufs ++) {// map all the caches

Memset (& Buf, 0, sizeof (BUF ));

Buf. type = v4l2_buf_type_video_capture;

Buf. Memory = v4l2_memory_mmap;

Buf. Index = numbufs;

If (IOCTL (FD, Vidioc_querybuf, & BUF) =-1 ){//Obtain the corresponding indexHere, we mainly use lengthInformation and offsetInformation to complete the subsequent MMAPOperation.

Return-1;

}

Buffers [numbufs]. Length = Buf. length;

// Convert to relative address

Buffers [numbufs]. Start = MMAP (null, Buf. length,

Prot_read | prot_write,

Map_shared,

FD, Buf. M. offset );

If (buffers [numbufs]. Start = map_failed ){

Return-1;

}

(8) Start video collection

Int buf_type = v4l2_buf_type_video_capture;

Int ret = IOCTL (FD, vidioc_streamon, & buf_type );

(9) retrieve the sampled frame cache in the FIFO Cache

Struct v4l2_buffer Buf;

Memset (& Buf, 0, sizeof (BUF ));

Buf. type = v4l2_buf_type_video_capture;

Buf. Memory = v4l2_memory_mmap;

Buf. Index = 0; // This value is returned by the following IOCTL

If (IOCTL (FD, vidioc_dqbuf, & BUF) =-1)

{

Return-1;

}

Find the corresponding MMAP ing cache based on the returned Buf. Index and retrieve the video data.

(10) re-import the buffer that has just been processed to the end of the queue so that it can be collected cyclically.

If (IOCTL (FD, vidioc_qbuf, & BUF) =-1 ){

Return-1;

}

(11) Stop video collection

Int ret = IOCTL (FD, vidioc_streamoff, & buf_type );

(12) disable the video device

Close (FD );

Iv. v4l2 driver framework

All operations of the above process must be supported by the underlying v4l2 driver. There are some very well-developed examples in the kernel.

For example, the zc301 video driver code in the linux-2.6.26 kernel directory/Drivers/Media/video // zc301/zc301_core.c. The functions involved in the above v4l2 operation process are all implemented in it.

1. v4l2 driver registration and function Cancellation

The Video Core layer (Drivers/Media/Video/videodev. c) provides registration functions.

Int video_register_device (struct video_device * VFD, int type, int nr)

Video_device: core data structure to be built

Type: indicates the device type. The base address of this device number is affected by this variable.

Nr: If end-base> Nr> 0: Sub-device number = base (baseline value, affected by type) + nR;

Otherwise, the system automatically assigns an appropriate device number.

The specific driver only needs to construct the video_device structure, and then call the registration function.

For example, in zc301_core.c

Err = video_register_device (cam-> v4ldev, vfl_type_grabber,

Video_nr [dev_nr]);

The Video Core layer (Drivers/Media/Video/videodev. c) provides the logout function.

Void video_unregister_device (struct video_device * VFD)

2. Construction of struct video_device

The video_device structure contains the attributes and operation methods of the Video device. See zc301_core.c

Strcpy (cam-> v4ldev-> name, "zc0301 [p] Pc camera ");

Cam-> v4ldev-> owner = this_module;

Cam-> v4ldev-> type = vid_type_capture | vid_type_scales;

Cam-> v4ldev-> fops = & zc0301_fops;

Cam-> v4ldev-> minor = video_nr [dev_nr];

Cam-> v4ldev-> release = video_device_release;

Video_set_drvdata (cam-> v4ldev, Cam );

DaJia found that the zc301 driver does not implement many operation functions in struct video_device, such as vidioc_querycap and vidioc_g_fmt_cap. The main reason is thatStruct file_operations zc0301_fopsZc0301_ioctl in implements all previous IOCTL operations. Therefore, you do not need to perform the operations in struct video_device again.

Another implementation method is as follows:

Static struct video_device camif_dev =

{

. Name = "S3C2440 camif ",

. Type = vid_type_capture | vid_type_scales | vid_type_subcapture,

. Fops = & camif_fops,

. Minor =-1,

. Release = camif_dev_release,

. Vidioc_querycap = vidioc_querycap,

. Vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,

. Vidioc_g_fmt_cap = vidioc_g_fmt_cap,

. Vidioc_s_fmt_cap = vidioc_s_fmt_cap,

. Vidioc_queryctrl = vidioc_queryctrl,

. Vidioc_g_ctrl = vidioc_g_ctrl,

. Vidioc_s_ctrl = vidioc_s_ctrl,

};

Static struct file_operations camif_fops =

{

. Owner = this_module,

. Open = camif_open,

. Release = camif_release,

. Read = camif_read,

. Poll = camif_poll,

. IOCTL = video_ioctl2,/* v4l2 IOCTL handler */

. MMAP = camif_mmap,

. Llseek = no_llseek,

};

Note: video_ioctl2 is implemented in videodev. C. In video_ioctl2, the command output varies with the ioctl.

Call the operation method in video_device.

3. Implementation of the Video Core Layer

See kernel/Drivers/Media/videodev. c

(1) Register 256 video devices

Static int _ init videodev_init (void)

{

Int ret;

If (Register_chrdev(Video_major, video_name, & video_fops )){

Return-EIO;

}

Ret = class_register (& video_class );

......

}

The above code registers 256 video devices and registers the video_class class. Video_fops is the common operation method for these 256 devices.

(2) Implementation of v4l2 driver registration function

Int video_register_device (struct video_device * VFD, int type, int nr)

{

Int I = 0;

Int base;

Int end;

Int ret;

Char * name_base;

Switch (type) // determine the device name and device number according to different types

{

Case vfl_type_grabber:

Base = minor_vfl_type_grabber_min;

End = minor_vfl_type_grabber_max + 1;

Name_base = "video ";

Break;

Case vfl_type_vtx:

Base = minor_vfl_type_vtx_min;

End = minor_vfl_type_vtx_max + 1;

Name_base = "vtx ";

Break;

Case vfl_type_vbi:

Base = minor_vfl_type_vbi_min;

End = minor_vfl_type_vbi_max + 1;

Name_base = "VBI ";

Break;

Case vfl_type_radio:

Base = minor_vfl_type_radio_min;

End = minor_vfl_type_radio_max + 1;

Name_base = "radio ";

Break;

Default:

Printk (kern_err "% s called with unknown type: % d/N ",

_ FUNC __, type );

Return-1;

}

/* Calculate the next device Number */

Mutex_lock (& videodev_lock );

If (NR> = 0 & Nr <End-base ){

/* Use the one the driver asked */

I = base + nR;

If (null! = Video_device [I]) {

Mutex_unlock (& videodev_lock );

Return-enfile;

}

} Else {

/* Use first free */

For (I = base; I <end; I ++)

If (null = video_device [I])

Break;

If (I = END ){

Mutex_unlock (& videodev_lock );

Return-enfile;

}

}

Video_device [I] = VFD ;//Save video_deviceStructure pointer to the system structure array, the final sub-device number and IRelated.

VFD-> minor = I;

Mutex_unlock (& videodev_lock );

Mutex_init (& VFD-> lock );

/* Sysfs class */

Memset (& VFD-> class_dev, 0x00, sizeof (VFD-> class_dev ));

If (VFD-> Dev)

VFD-> class_dev.parent = VFD-> dev;

VFD-> class_dev.class = & video_class;

VFD-> class_dev.devt = mkdev (video_major, VFD-> minor );

Sprintf (VFD-> class_dev.bus_id, "% S % d", name_base, I-base );//Finally, in/devDirectory Name

Ret = device_register (& VFD-> class_dev );//Combined with udevOr mdevIt can be automatically stored in/devCreate a device node under

......

}

From the above registration function, we can see that the registration of the v4l2 driver actually completes the creation of the device node, such as/dev/video0. And save the video_device structure pointer.

(3) video drive opening process

When the user space calls open to open the corresponding video file, such:

Int FD = open (/dev/video0, o_rdwr );

The operation structure of the corresponding/dev/video0 file is video_fops defined in/Drivers/Media/videodev. C.

Static const struct file_operations video_fops =

{

. Owner = this_module,

. Llseek = no_llseek,

. Open = video_open,

};

It is strange that only open operations are implemented here. What about other operations? Check video_open first.

Static int video_open (struct inode * inode, struct file * file)

{

Unsigned int minor = iminor (inode );

Int err = 0;

Struct video_device * VFL;

Const struct file_operations * old_fops;

If (minor> = video_num_devices)

Return-enodev;

Mutex_lock (& videodev_lock );

VFL = video_device [minor];

If (vfl = NULL ){

Mutex_unlock (& videodev_lock );

Request_module ("char-Major-% d", video_major, minor );

Mutex_lock (& videodev_lock );

VFL = video_device [minor]; //Retrieve according to device numberVideo_deviceStructure

If (vfl = NULL ){

Mutex_unlock (& videodev_lock );

Return-enodev;

}

}

Old_fops = file-> f_op;

File-> f_op = fops_get (vfl-> FoPs );//Replace the file_operation of the Open FileStructure. The subsequent operations on this file are the responsibility of the new structure. That is, each specificVideo_deviceFoPsResponsible.

If (file-> f_op-> open)

Err = file-> f_op-> open (inode, file );

If (ERR ){

Fops_put (file-> f_op );

File-> f_op = fops_get (old_fops );

}

......

}

I have some understanding of v4l2 and hope to help you understand v4l2!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.