Blog Source Address: http://www.embedu.org/Column/Column514.htm
Introduction: The code attached to this article is based on V4L2 official documents and demo (CAPTURE.C) modified, purely for the purpose of learning communication, do not use in commercial situations.
Address: Because the official network domain name has the sensitive vocabulary, so please google a bit.
First, the operation process Simple look
Second, the module summary analysis
The following is the accompanying code related to the global variables, put it for reference only, the specific changes, please make your own arrangements.
#define CLEAR (x) memset (& (x), 0, sizeof (x))
typedef enum {
#ifdef io_read
io_method_read,
#endif c4/> #ifdef io_mmap
io_method_mmap,
#endif
#ifdef io_userptr
io_method_userptr,
#endif
} Io_method;
struct Buffer {
void * start;
size_t length;
};
static Io_method io = Io_method_mmap;
static int fd =-1;
struct buffer * buffers = NULL;
static unsigned int n_buffers = 0;
Global settings
static unsigned int width = 640;
static unsigned int height = 480;
static unsigned char jpegquality =;
static char* jpegfilename = NULL;
static char* devicename = "/dev/video0";
1.deviceOpen
The main thing is to open your device files, in general,/dev/vedio0 depends on the number of devices you have. The above-mentioned stat of this structure is mainly to record the basic information of the file. This is the point by which you can verify the file's open permissions.
2.deviceInit This module is slightly more complex, it mainly uses 4 kinds of related data structures defined in V4L2. The specific properties of each structure are listed below.
struct V4l2_cropcap {enum v4l2_buf_type type;
struct v4l2_rect bounds;
struct V4l2_rect defrect;
struct V4l2_fract pixelaspect;
};
struct V4l2_crop {enum v4l2_buf_type type;
struct V4l2_rect C;
}; struct V4l2_capability {__u8 driver[16];/* i.e. "BTTV" */__u8 CARD[32];/* i.e. "Haupp Auge WinTV "*/__u8 bus_info[32]; /* "PCI:" + pci_name (Pci_dev) */__U32 version; /* should use kernel_version () */__U32 capabilities;
/* Device capabilities */__u32 reserved[4];
};
struct V4l2_format {enum v4l2_buf_type type; Union {struct V4l2_pix_format pix;/* v4l2_buf_type_video_capture */Stru CT V4l2_window win; /* V4l2_buf_type_video_overlay */struct V4l2_vbi_format Vbi; /* v4l2_buf_type_vbi_capture */struct V4l2_sliced_vbi_format sliced; /* v4l2_buf_type_sliced_vbi_capture */__u8 raw_data[200];
/* user-defined */} FMT; };
It has to be reminded that, usually USB camera driver, will provide 3 different data transmission methods, 1,read IO 2,mmap Memory Mapping 3,userptr (This is a test method, specifically can be queried)
This article discusses only common methods of operation, that is, the mmap memory mapping method. Through a period of study, only then know why only support mmap, in fact, we use the architecture is based on UVC. In the UVC architecture, Read/write IO mode and user extension mode are not supported.
static void DeviceInit (void) {struct v4l2_capability cap;
struct V4l2_cropcap cropcap;
struct V4l2_crop crop;
struct V4l2_format fmt;
unsigned int min;
if ( -1 = = Xioctl (FD, Vidioc_querycap, &cap)) {//get the capab info about if (EINVAL = = errno) {
fprintf (stderr, "%s is no v4l2 device\n", devicename);
Exit (Exit_failure);
} else {errno_exit ("Vidioc_querycap"); }} if (! (
Cap.capabilities & V4l2_cap_video_capture)) {//check are IT support CAPTURE mode?
fprintf (stderr, "%s is no video capture device\n", devicename);
Exit (Exit_failure); } if (! ( Cap.capabilities & v4l2_cap_streaming) {fprintf (stderr, "%s does not support streaming i/o\n", device
Name);
Exit (Exit_failure);
} /* Select video input, video standard and tune here. */CLEAR (CROPCAP);//init-0 It is a initialize func about set 0 to parameter Cropcap.type = V4l2_buf_type
_video_capture;
if (0 = = Xioctl (FD, Vidioc_cropcap, &cropcap)) {crop.type = V4l2_buf_type_video_capture; CROP.C = Cropcap.defrect; /* Reset to Default */if ( -1 = = Xioctl (FD, Vidioc_s_crop, &crop)) {switch (
errno) {case EINVAL:/* Cropping not supported. */
Break Default:/* Errors ignored.
*/break;
}}} CLEAR (FMT); V4l2_format fmt.type = v4l2_buf_type_video_capture; Mode is capture fmt.fmt.pix.width = width; Define Pixee width fmt.fmt.pix.height = height;
Define pixel height Fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
Define pixel format Fmt.fmt.pix.field = v4l2_field_interlaced;
if ( -1 = = Xioctl (FD, VIDIOC_S_FMT, &fmt))//set FMT errno_exit ("vidioc_s_fmt"); /* Note vidioc_s_fmt may change width and height.
*/if (width = fmt.fmt.pix.width) {width = fmt.fmt.pix.width;
fprintf (stderr, "Image width set to%i by device%s.\n", width,devicename);
} if (height! = fmt.fmt.pix.height) {height = fmt.fmt.pix.height;
fprintf (stderr, "Image height set to%i by device%s.\n", height,devicename); }/* Buggy driver paranoia.
*/min = fmt.fmt.pix.width * 2;
if (Fmt.fmt.pix.bytesperline < min) fmt.fmt.pix.bytesperline = min;
Min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
if (Fmt.fmt.pix.sizeimage < min) fmt.fmt.pix.sizeimage = min; This function is important to init mmap pre_work mmapinit (); }
You can see the above is mainly the initialization work, the specific parameter meaning, please see V4L2 specification.
static void Mmapinit (void) {struct v4l2_requestbuffers req;//apply for frame buffer
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", devicename);
Exit (Exit_failure);
} else {errno_exit ("Vidioc_reqbufs"); }} if (Req.count < 2) {fprintf (stderr, "Insufficient buffer memory on%s\n", Devicena
ME);
Exit (Exit_failure);
} buffers = Calloc (req.count, sizeof (*buffers));
if (!buffers) {fprintf (stderr, "Out of memory\n");
Exit (Exit_failure); } 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"); }
}
3.capture_start
After initialization, you can get to the point, which is the so-called capture data. But before you do, you should open the data Flow channel, which focuses on the parameters of the last IOCTL function: Vidioc_streamon
static void Capturestart (void)//grap after initialize
{
unsigned int i;
Enum V4l2_buf_type type; page-68
#ifdef Io_mmap 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");
}
Type = V4l2_buf_type_video_capture;
if ( -1 = = Xioctl (FD, Vidioc_streamon, &type))
errno_exit ("Vidioc_streamon");
#endif
The two structures that appear above are defined as follows:
Enum V4l2_buf_type {v4l2_buf_type_video_capture = 1, v4l2_buf_type_video_output = 2, v4l2_buf_ty Pe_video_overlay = 3, v4l2_buf_type_vbi_capture = 4, V4l2_buf_type_vbi_output = 5, v4l2_buf_type_s Liced_vbi_capture = 6, V4l2_buf_type_sliced_vbi_output = 7, #if 1/* experimental */v4l2_
Buf_type_video_output_overlay = 8, #endif v4l2_buf_type_private = 0x80,};
struct V4l2_buffer {__u32 index;
Enum V4l2_buf_type type;
__u32 bytesused;
__U32 flags;
enum V4l2_field field;
struct Timeval timestamp;
struct V4l2_timecode timecode;
__U32 sequence;
/* Memory location */enum v4l2_memory memory;
Union {__u32 offset;
unsigned long userptr; } m;
__u32 length;
__U32 input;
__U32 reserved; };
V4L2 Official documentation and demo (CAPTURE.C)