在v4l2中,有两种查询视频格式的方法,一个是遍历所有视频格式的
一个是查询出一种格式的
/*查询出一种格式*/
ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
/*遍历所有视频格式,查询驱动所支持的格式*/
VIDIOC_ENUM_FMT
[csharp] view plaincopy
驱动
static int s3c_fimc_v4l2_g_fmt_vid_cap(struct file *filp, void *fh,
struct v4l2_format *f)
{
struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
int size = sizeof(struct v4l2_pix_format);
memset(&f->fmt.pix, 0, size);
memcpy(&f->fmt.pix, &(ctrl->v4l2.frmbuf.fmt), size);
return 0;
}
应用
static int video_getfmt(int fd)
{
/***********get Stream data format********/
int ret= 0;
struct v4l2_format fmt;
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
if (ret < 0) {
perror("VIDIOC_G_FMT");
return ret;
}
printf("/n**********vidioc get stream format informations:****\n");
if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
printf("8-bit YUYVV pixel format\n");
printf("Size of the buffer = %d\n", fmt.fmt.pix.sizeimage);
printf("Line offset = %d\n", fmt.fmt.pix.bytesperline);
if (fmt.fmt.pix.field == V4L2_FIELD_INTERLACED)
printf("Storate format is interlaced frame format\n");
return 0;
}
[csharp] view plaincopy
结构体
struct v4l2_requestbuffers req;
ret = ioctl(fd, VIDIOC_REQBUFS, &req);
ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);//读取缓存
struct v4l2_requestbuffers {
__u32 count;
enum v4l2_buf_type type;
enum v4l2_memory memory;
__u32 reserved[2];
};
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;
};
使用VIDIOC_REQBUFS 我们获取了req.count个缓存,下一步通过
调用VIDIOC_QUERYBUF 命令来获取这些缓存的地址,然后使用
mmap函数转换成应用程序中的绝对地址,最后把这些缓存放入
缓存队列。
The main steps that the application must perform for buffer allocation are:
Allocating Memory
Getting Physical Address
Mapping Kernel Space Address to User Space
驱动支持
static int s3c_fimc_v4l2_reqbufs(struct file *filp, void *fh,
struct v4l2_requestbuffers *b)
{
if (b->memory != V4L2_MEMORY_MMAP) {
err("V4L2_MEMORY_MMAP is only supported\n");
return -EINVAL;
}
/* control user input */
if (b->count > 4)
b->count = 4;
else if (b->count < 1)
b->count = 1;
return 0;
}
static int s3c_fimc_v4l2_querybuf(struct file *filp, void *fh,
struct v4l2_buffer *b)
{
struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
if (b->type != V4L2_BUF_TYPE_VIDEO_OVERLAY && \
b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (b->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
b->length = ctrl->out_frame.buf_size;
/*
* NOTE: we use the m.offset as an index for multiple frames out.
* Because all frames are not contiguous, we cannot use it as
* original purpose.
* The index value used to find out which frame user wants to mmap.
*/
b->m.offset = b->index * PAGE_SIZE;
return 0;
}
static int s3c_fimc_v4l2_qbuf(struct file *filp, void *fh,
struct v4l2_buffer *b)
{
return 0;
}
应用层
static int video_mmap(int fd)
{
/*******step 1*****requestbuffers Allocating Memory *******/
int ret = 0;
struct v4l2_requestbuffers req;
CLEAR(req);
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ret = ioctl(fd, VIDIOC_REQBUFS, &req);
if (ret < 0) {
perror("VIDIOC_REQBUFS");
return ret;
}
if (req.count < 2)
printf("insufficient buffer memory\n");
printf("Number of buffers allocated = %d\n", req.count);
/*******step 2*****Getting Physical Address *******/
buffers = calloc(req.count, sizeof(*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;
ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);
if (ret < 0) {
perror("VIDIOC_QUERYBUF");
return ret;
}
/*******step 3*****Mapping Kernel Space Address to User Space*******/
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start =
mmap(NULL,
buf.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
buf.m.offset);
//if (MAP_FAILED == buffers[n_buffers].start)
//perror("mmap failed \n");
}
/************requestbuffers in queue***********/
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;
ret = ioctl(fd, VIDIOC_QBUF, &buf);//申请的缓冲进入队列
if (ret < 0) {
perror("VIDIOC_QBUF");
return ret;
}
}
return 0;
}
[csharp] view plaincopy
<pre name="code" class="csharp"><p>结构体</p><pre name="code" class="csharp">enum v4l2_buf_type type;//开始捕捉图像数据
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_STREAMON, &type);
enum v4l2_buf_type {
V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
V4L2_BUF_TYPE_VBI_CAPTURE = 4,
V4L2_BUF_TYPE_VBI_OUTPUT = 5,
V4L2_BUF_TYPE_SLICED_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,
};
驱动
static int s3c_fimc_v4l2_streamon(struct file *filp, void *fh,
enum v4l2_buf_type i)
{
struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
printk("s3c_fimc_v4l2_streamon is called\n");
if (ctrl->in_type != PATH_IN_DMA)
s3c_fimc_init_camera(ctrl);
ctrl->out_frame.skip_frames = 0;
FSET_CAPTURE(ctrl);
FSET_IRQ_NORMAL(ctrl);
s3c_fimc_start_dma(ctrl);
return 0;
}
硬件控制寄存器的配置
应用层
static int video_streamon(int fd)
{
int ret = 0;
/************start stream on***********/
enum v4l2_buf_type types;//开始捕捉图像数据
types = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_STREAMON, &types);
if (ret < 0) {
perror("VIDIOC_STREAMON");
return ret;
}
return 0;
}