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

转自: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的编程会有些许不同,但是以上几个接口肯定是会用到的


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值