您的位置:首页 > 移动开发 > Android开发

android摄像头(camera)之 V4L2编程中用到的各种结构体

2014-01-15 17:54 429 查看
转自:http://blog.csdn.net/ldswfun/article/details/8745355

在移植android中camrea中间件时候,v4l2是必须要掌握的,实际上很多人在移植过程中对v4l2的结构都是似懂非懂,所以在此对v4l2中所涉及到的一些结构体做个详细讲解。

v4l2的api在其官方网站上文档,大家可以下载,大部分的接口都是通过系统调用ioctl来完成,第一个参数是通过open打开的设备节点,一般都是/dev/videox,x为一个数字,比如/dev/video0, 第二参数为cmd,我们也叫命令,第三个参数就是各种结构体,我们着重讲的就是cmd和各个结构体

==================================================================

所有的结构体的定义都在#include <linux/videodev2.h>中定义:

struct v4l2_input input;

原型:

struct v4l2_input

{

__u32 index; // 视频输入设备的索引

__u8 name[32]; // 视频输入设备的名字

__u32 type;

__u32 audioset;

__u32 tuner;

v4l2_std_id std;

__u32 status;

__u32 reserved[4];

};

用于获取当前接入的video输入设备的属性和设备的编号, 一般对应命令VIDIOC_ENUMINPUT

该结构体对应的命令为:

VIDIOC_G_INPUT: 获取当前设备在系统中的索引编号,通过index返回

VIDIOC_ENUMINPUT: 根据index,查询获取video设备的信息,一般通过struct v4l2_input的内容

VIDIOC_S_INPUT::设置当前的video输入设备的index编号

例子:

struct v4l2_input input;

int index;

if (-1 == ioctl (fd, VIDIOC_G_INPUT, &index)) {

perror ("VIDIOC_G_INPUT");

exit (EXIT_FAILURE);

}

memset (&input, 0, sizeof (input));

input.index = index;

if (-1 == ioctl (fd, VIDIOC_ENUMINPUT, &input)) {

//在根据index,通过查询获取struct v4l2_input的内容

perror ("VIDIOC_ENUMINPUT");

exit (EXIT_FAILURE);

}

printf ("Current input: %s\n", input.name);

当然也可以将当前的video输入设备的index编号进行更改为第一个:

//Switching to the first video input

int index;

index = 0;

if (-1 == ioctl (fd, VIDIOC_S_INPUT, &index)) {

perror ("VIDIOC_S_INPUT");

exit (EXIT_FAILURE);

}

===========================================================

struct v4l2_format my_format;

原型:

struct v4l2_format

{

enum v4l2_buf_type type; // 对于摄像头,一定是V4L2_BUF_TYPE_VIDEO_CAPTURE

union

{

struct v4l2_pix_format pix;

// 对于摄像头输入输出,我们只关注这个就可以啦

struct v4l2_window win; //用于overlay

struct v4l2_vbi_format vbi; //原始VBI摄像输入和输出参数

struct v4l2_sliced_vbi_format sliced;

__u8 raw_data[200];

} fmt;

};

用于协商驱动和应用程序之间的video输出帧的格式,比如:宽,高,格式,帧图像大小,宽,高的选择需要问驱动工程师,一般支持哪种大小(一般称作为分辨率),或者有数据手册,也可以产看camera的数据手册,在编程中非常重要

该结构体一般用于以下命令:

VIDIOC_G_FMT, // 获取帧图像格式

VIDIOC_S_FMT, //设置帧图像格式

例子:

struct v4l2_format my_format;

bzero(&my_format, sizeof(my_format));

my_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

//设定struct v4l2_pix_format

my_format.fmt.pix.height = 640; // 图像输出高

my_format.fmt.pix.width = 480; // 图像输出宽

my_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;

// 图像输出格式,现在的cmos摄像头一般都是会有几种选择:

//yuv420===>V4L2_PIX_FMT_YUYV,或者是V4L2_PIX_FMT_YUV420,

//可以跟驱动工程师获取到

//yuv422==》V4L2_PIX_FMT_YUV422P

//jpeg ==>V4L2_PIX_FMT_JPEG/V4L2_PIX_FMT_MJPEG

ret = ioctl(dev_fd, VIDIOC_S_FMT, &my_format);

当然你也可以去获取图像的默认参数或者设置后的参数:

实例代码:

struct v4l2_format my_fmt;

my_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

ret = ioctl(dev_fd, VIDIOC_G_FMT, &my_fmt);

LOGD(" Width = %d\n", my_fmt.fmt.pix.width);

LOGD(" Height = %d \n", my_fmt.fmt.pix.height);

LOGD(" Image size = %d\n", my_fmt.fmt.pix.sizeimage);

==============================================================================

struct v4l2_buffer buf;

原型:

struct v4l2_buffer

{

__u32 index; //需要使用的buffer个数,非常重要,一般都是3-4个,需要咨询驱动工程师

enum v4l2_buf_type type;

// buffer的类型:如果是video输入输出,

//就和上面的struct v4l2_format保持一致,

//为V4L2_BUF_TYPE_VIDEO_CAPTURE

__u32 bytesused; // buffer中已经被图像填充的数据大小:bytes单位

__u32 flags;

enum v4l2_field field; // 在video输入输出中一般不用到

struct timeval timestamp;

struct v4l2_timecode timecode;

__u32 sequence;

enum v4l2_memory memory; // video的I/O方式:通常是选择:

//V4L2_MEMORY_MMAP:通过mmap的方式将数据送给用户层

union {

__u32 offset;

unsigned long userptr;

} m; // 用于指示buffer的起始位置,当用mmap的时候,我们会用offset成员

__u32 length; // buffer的大小

__u32 input;

__u32 reserved;

};

用于控制驱动,向dma申请,查询,调度内存buffer

一般都会对应如下几个命令:

VIDIOC_REQBUFS : 向dma申请内存buffer

VIDIOC_QUERYBUF: 查询已经申请好的内存buffer信息,比如buffer的起始位置,大小

VIDIOC_QBUF: 调度空buffer进队列,用于buffer准备填充图像数据

VIDIOC_DQBUF: 调度填充完图像数据buffer出队列,可以交给应用程序使用啦

实例:

1,申请buffer:

struct v4l2_requestbuffers

{

__u32 count;

enum v4l2_buf_type type;

//内存的类型,一般为V4L2_BUF_TYPE_VIDEO_CAPTURE;

enum v4l2_memory memory;

//一般都是V4L2_MEMORY_MMAP

__u32 reserved[2];

};

struct v4l2_requestbuffers reqbuf;

bzero(&reqbuf, sizeof(reqbuf));

reqbuf.count = 3; // 申请3个buffer

reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

reqbuf.memory = V4L2_MEMORY_MMAP;// must be this

ret = ioctl(dev_fd, VIDIOC_REQBUFS, &reqbuf)

//to allocate buffer with dma in kernel space

注意啦,在向内核申请buffer的时候,我们用的

结构体是struct v4l2_requestbuffers

2,查询buffer信息:

struct v4l2_buffer buf

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.index = 2; //查询第二个buffer的信息

ret = ioctl(dev_fd, VIDIOC_QUERYBUF, &buf);

LOGD("buf.m.offset = 0x%x\n", buf.m.offset);

LOGD("buf.length; = 0x%x\n", buf.length);

3,将buffer放入工作队列中,准备调度:

struct v4l2_buffer buf;

memset(&buf, 0 ,sizeof(struct v4l2_buffer));

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_MMAP;

buf.index = 2; //将第二个buffer放入队列

ret = ioctl(dev_fd, VIDIOC_QBUF, &buf);

4,将已经填充图形数据的buffer出队列:

struct v4l2_buffer dq_buf;

memset(&dq_buf, 0 ,sizeof(struct v4l2_buffer));

dq_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

dq_buf.memory = V4L2_MEMORY_MMAP;

ret = ioctl(dev_fd, VIDIOC_DQBUF, &dq_buf);

return dq_buf.index ;

ioctl返回时dq_buf中,内核应经告知到底是哪个buffer出了队列

===================================================================================

开始抓取图片:

int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //为1

ioctl(dev_fd, VIDIOC_STREAMOFF, &type);

第三个采参数时就是给一个整型指针

停止获取图像

int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

ioctl(dev_fd, VIDIOC_STREAMON, &type);

================================================================================

到此基本上需要用到的结构体都在这里啦,当然不同cpu的camera hal中v4l2的编程会有些许不同,但是以上几个接口肯定是会用到的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: