记学习RK3566使用mipi摄像头ov8858的应用编程(一)

v4l2设备编程流程

  • open:打开设备节点/dev/videoX
  • ioctl VIDIOC_QUERYCAP:Query Capbility,查询能力,比如
    • 确认它是否是"捕获设备",因为有些节点是输出设备
    • 确认它是否支持mmap操作,还是仅支持read/write操作
  • ioctl VIDIOC_ENUM_FMT:枚举它支持的格式
  • ioctl VIDIOC_S_FMT:在上面枚举出来的格式里,选择一个来设置格式
  • ioctl VIDIOC_REQBUFS:申请buffer,APP可以申请很多个buffer,但是驱动程序不一定能申请到
  • ioctl VIDIOC_QUERYBUF和mmap:查询buffer信息、映射
    • 如果申请到了N个buffer,这个ioctl就应该执行N次
    • 执行mmap后,APP就可以直接读写这些buffer
  • ioctl VIDIOC_QBUF:把buffer放入"空闲链表"
    • 如果申请到了N个buffer,这个ioctl就应该执行N次
  • ioctl VIDIOC_STREAMON:启动摄像头
  • 这里是一个循环:使用poll/select监测buffer,然后从"完成链表"中取出buffer,处理后再放入"空闲链表"
    • poll/select
    • ioctl VIDIOC_DQBUF:从"完成链表"中取出buffer
    • 处理:前面使用mmap映射了每个buffer的地址,处理时就可以直接使用地址来访问buffer
    • ioclt VIDIOC_QBUF:把buffer放入"空闲链表"
  • ioctl VIDIOC_STREAMOFF:停止摄像头

获取摄像头类型以及摄像头所支持的格式

1.打开设备树

我所使用的是野火鲁班猫1开发板,通过命令sudo vi /boot/uEnv/uEnv.txt修改配置文件中对应型号的设备树插件,如下图:
配置文件
我的设备为ov8858,只要将对应名称的设备树插件前面的#去掉就可以开启摄像头。

记得修改完配置文件后需要reboot一下

2.通过v4l2-ctl命令来获取摄像头列表

列出摄像头设备

v4l2-ctl --list-devices

其中 /dev/video0 就是刚才打开的ov8858摄像头
摄像头列表

3.编写应用代码获取摄像头类型以及摄像头所支持的格式

首先文件描述符和定义结构体

int fd;
struct v4l2_fmtdesc fmtdesc;
struct v4l2_capability cap;

接下来是打开摄像头设备

fd = open("/dev/video0",O_RDWR);
    if(fd<0)
    {
        printf("can not open video0\n");
        return -1;
    }

获取摄像头类型
使用到VIDIOC_QUERYCAP命令来获得v4l2_capability结构体的描述
v4l2_capability结构体内容如下:
结构体原型

struct v4l2_capability {
	__u8         driver[16];  //name of the driver module
    __u8         card[32];    //name of the card
    __u8         bus_info[32];//name of the bus
    __u32   version;     //kernel version
    __u32       capabilities;//capabilities of the physical device as a whole
    __u32       device_caps; //capabilities aeccessed via this particular device
    __u32       reserved[3];
};

capabilities字段的值包括

#define V4L2_CAP_VIDEO_CAPTURE		0x00000001  /* Is a video capture device */
#define V4L2_CAP_VIDEO_OUTPUT		0x00000002  /* Is a video output device */
#define V4L2_CAP_VIDEO_OVERLAY		0x00000004  /* Can do video overlay */
#define V4L2_CAP_VBI_CAPTURE		0x00000010  /* Is a raw VBI capture device */
#define V4L2_CAP_VBI_OUTPUT		0x00000020  /* Is a raw VBI output device */
#define V4L2_CAP_SLICED_VBI_CAPTURE	0x00000040  /* Is a sliced VBI capture device */
#define V4L2_CAP_SLICED_VBI_OUTPUT	0x00000080  /* Is a sliced VBI output device */
#define V4L2_CAP_RDS_CAPTURE		0x00000100  /* RDS data capture */
#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY	0x00000200  /* Can do video output overlay */
#define V4L2_CAP_HW_FREQ_SEEK		0x00000400  /* Can do hardware frequency seek  */
#define V4L2_CAP_RDS_OUTPUT		0x00000800  /* Is an RDS encoder */

/* Is a video capture device that supports multiplanar formats */
#define V4L2_CAP_VIDEO_CAPTURE_MPLANE	0x00001000
/* Is a video output device that supports multiplanar formats */
#define V4L2_CAP_VIDEO_OUTPUT_MPLANE	0x00002000
/* Is a video mem-to-mem device that supports multiplanar formats */
#define V4L2_CAP_VIDEO_M2M_MPLANE	0x00004000
/* Is a video mem-to-mem device */
#define V4L2_CAP_VIDEO_M2M		0x00008000

#define V4L2_CAP_TUNER			0x00010000  /* has a tuner */
#define V4L2_CAP_AUDIO			0x00020000  /* has audio support */
#define V4L2_CAP_RADIO			0x00040000  /* is a radio device */
#define V4L2_CAP_MODULATOR		0x00080000  /* has a modulator */

#define V4L2_CAP_SDR_CAPTURE		0x00100000  /* Is a SDR capture device */
#define V4L2_CAP_EXT_PIX_FORMAT		0x00200000  /* Supports the extended pixel format */
#define V4L2_CAP_SDR_OUTPUT		0x00400000  /* Is a SDR output device */
#define V4L2_CAP_META_CAPTURE		0x00800000  /* Is a metadata capture device */

#define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
#define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
#define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
#define V4L2_CAP_META_OUTPUT		0x08000000  /* Is a metadata output device */

#define V4L2_CAP_TOUCH                  0x10000000  /* Is a touch device */

#define V4L2_CAP_DEVICE_CAPS            0x80000000  /* sets device capabilities field */

可以看到上面有许多类型,若要一个一个判断设备类型,那可太麻烦了,所以这里有一个办法,通过v4l2-ctl命令来查询摄像头类型:v4l2-ctl --list-formats-ext -d /dev/video0
1
可以看到我的摄像头类型是video capture multiplanar
接着回到代码中,验证是否正确
通过ioctl函数控制使用VIDIOC_QUERYCAP命令来获取摄像头类型

if(ioctl(fd,VIDIOC_QUERYCAP,&cap) !=0)
    {
        perror("FAIL to ioctl QIDIOC_QUERYCAP\n");   
    }
if(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
    printf("v4l2 dev support CAPTURE_MPLANE\n");

获取摄像头所支持的格式
所使用到的命令是VIDIOC_ENUM_FMT 作用是枚举设备支持的图像格式
通过该命令来获取struct v4l2_fmtdesc结构体的描述

struct v4l2_fmtdesc {
	__u32		    index;             /* Format number      */
	__u32		    type;              /* enum v4l2_buf_type */
	__u32               flags;
	__u8		    description[32];   /* Description string */
	__u32		    pixelformat;       /* Format fourcc      */
	__u32		    reserved[4];
};

获取当前格式

 	fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 	//需初始化该结构体变量否则会报错,在前面已经知道了摄像头的类型
    fmtdesc.index = 0;
	//从v4l2_fmtdesc结构体内容可知description是一个数组,通过遍历索引来获取格式内容
    while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
    {
        printf("[%d]fmt:%s\n",fmtdesc.index,fmtdesc.description);
        fmtdesc.index++;
    }

完整代码如下:

#include  <stdio.h>
#include  <string.h>
#include  <sys/types.h>
#include  <sys/stat.h>
#include  <fcntl.h>
#include  <sys/ioctl.h>
#include  <unistd.h>
#include  <errno.h>
#include  <linux/types.h>
#include  <linux/videodev2.h>

int main(int argc,char **argv)
{
    int fd;
    struct v4l2_fmtdesc fmtdesc;
    struct v4l2_capability cap;
    if(argc != 2)
    {
        printf("Usage: %s </dev/videoX>,print format detail for video device\n",argv[0]);
        return -1;
    }

    /*open*/
    fd = open(argv[1],O_RDWR);
    if(fd<0)
    {
        printf("can not open %s\n",argv[1]);
        return -1;
    }
    if(ioctl(fd,VIDIOC_QUERYCAP,&cap) !=0)
    {
        perror("FAIL to ioctl QIDIOC_QUERYCAP\n");   
    }
    
    if(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
    printf("v4l2 dev support CAPTURE_MPLANE\n");
    
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 	//需初始化该结构体变量否则会报错,在前面已经知道了摄像头的类型
    fmtdesc.index = 0;
	//从v4l2_fmtdesc结构体内容可知description是一个数组,通过遍历索引来获取格式内容
    while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
    {
        printf("[%d]fmt:%s\n",fmtdesc.index,fmtdesc.description);
        fmtdesc.index++;
    }

    return 0;
}

将代码文件上传至开发板,进行交叉编译后执行,执行结果如下:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值