声明:
环境:linux或ubunt下
编辑器:vim
编译工具:gcc
设备:USB接口的摄像头
难点理解:
1.对于缓冲帧的解释:假设我们申请5个缓冲帧,那么这5个缓冲帧就相当于5个盘子,操作系统在内存中开辟5个缓存区队列来存放这5个盘子,当相机拍照后将数据放入盘子中,我们通过VIDIOC_DQBUF取数据可以理解为将盘子取出来,然后对数据操作,操作完成之后,要通过VIDIOC_QBUF将盘子放回去,以保证可以循环接收数据。
2.对于映射的解释:对于映射,可以理解为cpu在处理时会给你分配几个空间,然后把这几个空间的首地址返回给你,如果你有数据,那么他就会把数据放到这个空间内。
程序源码:(包含详细注释)
/*
@sun : 2017-8-18
email: 13045892482@163.com
csdn : Mr_sunp
abstract :
under linux,Get an image with v4l2.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#define NB_BUFFER 5
#define DBG_DIR "jpg/"
#define VIDEO_L_MASK 0x01
#define VIDEO_R_MASK 0x02
#if 1
/*
头文件 :<linux/videodev2.h>
函数 :int ioctl(intfd, int request, struct v4l2_capability *argp);
struct v4l2_capability 设备的功能
{
__u8 driver[16]; // 驱动名字
__u8 card[32]; // 设备名字
__u8 bus_info[32]; // 设备在系统中的位置
__u32 version; // 驱动版本号
__u32 capabilities;// 设备支持的操作
__u32 reserved[4]; // 保留字段
};
VIDIOC_QUERYCAP //查询驱动功能
*/
/* fd:文件描述符 */
int showCapability(int fd)
{
printf("-----------------------设备信息---------------------\n");
struct v4l2_capability cap;
if(ioctl(fd,VIDIOC_QUERYCAP,&cap) < 0) {
perror("error ioctl VIDIOC_QUERYCAP !");
return -1;
}
printf("DriverName :%s\nCard Name :%s\nBus info :%s\nDriverVersion:%u.%u.%u\n"
,cap.driver
,cap.card
,cap.bus_info
,(cap.version>>16)&0xff
,(cap.version>>8)&0xff
,cap.version&0xff);
return 0;
}
#endif
#if 1
/*
函数 :int ioctl(intfd, int request, struct v4l2_fmtdesc *argp);
struct v4l2_fmtdesc
{
__u32 index; // 要查询的格式序号,应用程序设置
enum v4l2_buf_type type; // 帧类型,应用程序设置
__u32 flags; // 是否为压缩格式
__u8 description[32]; // 格式名称
__u32 pixelformat; // 格式
__u32 reserved[4]; // 保留
};
VIDIOC_ENUM_FMT //指令含义:获取当前驱动支持的视频格式
*/
/* fd:文件描述符 */
int showFmtdesc(int fd)
{
printf("-----------------------支持格式---------------------\n");
struct v4l2_fmtdesc dis_fmtdesc;
dis_fmtdesc.