https://www.cnblogs.com/emouse/archive/2013/03/04/2943243.htm
http://emb.hqyj.com/Column/Column320.html
http://blog.chinaunix.net/uid-11765716-id-2855735.html
https://my.oschina.net/u/1024767/blog/210801#OSC_h2_14
https://www.cnblogs.com/silence-hust/p/4464291.html
常用的IOCTRL命令
VIDIOC_QUERYCAP /* 获取设备支持的操作 */
VIDIOC_ENUM_FMT /*查询支持的格式*/
VIDIOC_G_FMT /* 获取设置支持的视频格式 */
VIDIOC_S_FMT /* 设置捕获视频的格式 */
VIDIOC_REQBUFS /* 向驱动提出申请内存的请求 */
VIDIOC_QUERYBUF /* 向驱动查询申请到的内存 */
VIDIOC_QBUF /* 将空闲的内存加入可捕获视频的队列 */
VIDIOC_DQBUF /* 将已经捕获好视频的内存拉出已捕获视频的队列 */
VIDIOC_STREAMON /* 打开视频流 */
VIDIOC_STREAMOFF /* 关闭视频流 */
VIDIOC_QUERYCTRL /* 查询驱动是否支持该命令 */
VIDIOC_G_CTRL /* 获取当前命令值 */
VIDIOC_S_CTRL /* 设置新的命令值 */
VIDIOC_G_TUNER /* 获取调谐器信息 */
VIDIOC_S_TUNER /* 设置调谐器信息 */
VIDIOC_G_FREQUENCY /* 获取调谐器频率 */
VIDIOC_S_FREQUENCY /* 设置调谐器频率 */
v4l2相关结构体设置
typedef __u64 v4l2_std_id;视频制式的设置;VIDIOC_G_STD,VIDIOC_S_STD
如:PALL制,NTSC
查询当前设备支持的所有格式 VIDIOC_ENUM_FMT
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];
};
while (!ioctl(fd_output_v4l, VIDIOC_ENUM_FMT, &fmtdesc)) {
printf("fmt %s: fourcc = 0x%08x\n",
fmtdesc.description,
fmtdesc.pixelformat);
fmtdesc.index++;
}
/**
* struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
*
* @driver: name of the driver module (e.g. "bttv")
* @card: name of the card (e.g. "Hauppauge WinTV")
* @bus_info: name of the bus (e.g. "PCI:" + pci_name(pci_dev) )
* @version: KERNEL_VERSION
* @capabilities: capabilities of the physical device as a whole
* @device_caps: capabilities accessed via this particular device (node)
* @reserved: reserved fields for future extensions
*/
struct v4l2_capability {
__u8 driver[16]; //
__u8 card[32];
__u8 bus_info[32];
__u32 version;
__u32 capabilities;
__u32 device_caps;
__u32 reserved[3];
};
查询video设备支持的属性 使用VIDIOC_QUERYCAP命令
#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls /
#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 / Is a video capture device /
#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 / Is a video output device */
对于摄像头是否支持流和capture属性
/*
* I N P U T I M A G E C R O P P I N G
*/
struct v4l2_cropcap {
__u32 type; /* enum v4l2_buf_type */
struct v4l2_rect bounds; //camera 极限分辨率大小,取景框的极限大小
struct v4l2_rect defrect; //camera 默认采集图像的分辨率,默认取景框的大小
struct v4l2_fract pixelaspect; //定义了图像的帧率采用
};
struct v4l2_crop {
__u32 type; /* enum v4l2_buf_type */
struct v4l2_rect c; //设置采集图像的尺寸
};
描述视频流的属性:使用VIDIOC_S_PARM,VIDIOC_G_PARM,设置和获取参数,帧率设置不一定成功,driver会根据硬件限制来设置这些参数,当前的帧率是由当前的视频标准来决定的,可以采用默认设置
struct v4l2_streamparm {
__u32 type; /* enum v4l2_buf_type */
union {
struct v4l2_captureparm capture;
struct v4l2_outputparm output;
__u8 raw_data[200]; /* user-defined */
} parm;
};
struct v4l2_captureparm {
__u32 capability; /* Supported modes */
__u32 capturemode; /* Current mode */
struct v4l2_fract timeperframe; /* Time per frame in seconds */
__u32 extendedmode; /* Driver-specific extensions */
__u32 readbuffers; /* # of buffers for read */
__u32 reserved[4];
};
capturemode:是否支持高清图像采集,0:表示一般模式;1:表示高清图像模式
timeperframe://表示视频采集帧率,帧率的值为numerator/denominator
struct v4l2_fract {
__u32 numerator; //numerator/denominator
__u32 denominator;
};
视频流数据格式设置
struct v4l2_format {
__u32 type;
union {
struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
__u8 raw_data[200]; /* user-defined */
} fmt;
};
struct v4l2_pix_format {
__u32 width;
__u32 height;
__u32 pixelformat;
__u32 field; /* enum v4l2_field */
__u32 bytesperline; /* for padding, zero if unused */
__u32 sizeimage;
__u32 colorspace; /* enum v4l2_colorspace */
__u32 priv; /* private data, depends on pixelformat */
};
pixelformat:设置像素格式比如:V4L2_PIX_FMT_YUYV
width,height;设置大小,设置发现不成功
field:设置场模式:V4L2_FIELD_INTERLACED
关于场的概念设置可以看:
(https://blog.csdn.net/kickxxx/article/details/6367669)
注册帧缓存buffer,使用VIDIOC_REQBUFS进行设置
struct v4l2_requestbuffers {
__u32 count;
__u32 type; /* enum v4l2_buf_type */
__u32 memory; /* enum v4l2_memory */
__u32 reserved[2];
};
count:帧缓存的个数
memory:V4L2_MEMORY_MMAP采用内存映射的方法读取数据
获取缓冲帧的地址长度
struct v4l2_buffer {
__u32 index;
__u32 type;
__u32 bytesused;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
/* memory location */
__u32 memory;
union {
__u32 offset;
unsigned long userptr;
struct v4l2_plane *planes;
__s32 fd;
} m;
__u32 length;
__u32 reserved2;
__u32 reserved;
};
index:缓存buffer的索引
offset:buffer的地址
length:数据长度
mmap (NULL, capture_buffers[i].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
fd_capture_v4l, capture_buffers[i].offset);
利用 mmap 将数据映射到用户空间
使用VIDIOC_QBUF将缓冲帧入队,使用VIDIOC_DQBUF将缓冲帧出队
一个video设备对应多个视频源输入选择;VIDIOC_G_INPUT,VIDIOC_S_INPUT设置,只有一个视频输入可以不设置;
struct v4l2_input {
__u32 index; /* Which input */
__u8 name[32]; /* Label */
__u32 type; /* Type of input */
__u32 audioset; /* Associated audios (bitfield) */
__u32 tuner; /* enum v4l2_tuner_type */
v4l2_std_id std;
__u32 status;
__u32 capabilities;
__u32 reserved[3];
};
camera采集设置流程
-
open打开一个video设备:
if ((fd_capture_v4l = open(CAPTURE_DEVICE, O_RDWR, 0)) < 0)
{
printf(“Unable to open %s\n”, CAPTURE_DEVICE);
return ERROR;
} -
获取video设备的capacity是否支持capture和stream
struct v4l2_capability cap;
ioctl (fd_capture_v4l, VIDIOC_QUERYCAP, &cap)
cap.capabilities & V4L2_CAP_VIDEO_CAPTURE
cap.capabilities & V4L2_CAP_STREAMING -
查询和设置camera取景框大小:
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
if (ioctl (fd_capture_v4l, VIDIOC_CROPCAP, &cropcap) < 0)
{
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; /* reset to default */
if (ioctl (fd_capture_v4l, VIDIOC_S_CROP, &crop) < 0) -
设置采集图像的格式:
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 0;
fmt.fmt.pix.height = 0;
fmt.fmt.pix.pixelformat = g_fmt;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;if (ioctl (fd_capture_v4l, VIDIOC_S_FMT, &fmt) < 0)
-
申请帧缓存:
struct v4l2_requestbuffers req;
req.count = g_capture_num_buffers;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl (fd_capture_v4l, VIDIOC_REQBUFS, &req) < 0) -
获取帧地址映射到用户空间
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (ioctl(fd_capture_v4l, VIDIOC_QUERYBUF, &buf) < 0)capture_buffers[i].length = buf.length; capture_buffers[i].offset = (size_t) buf.m.offset; capture_buffers[i].start = mmap (NULL, capture_buffers[i].length, PROT_READ | PROT_WRITE, MAP_SHARED, fd_capture_v4l, capture_buffers[i].offset);
-
将申请到的帧缓存入队
for (i = 0; i < g_capture_num_buffers; i++)
{
memset(&buf, 0, sizeof (buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
buf.m.offset = capture_buffers[i].offset;
if (ioctl (fd_capture_v4l, VIDIOC_QBUF, &buf) < 0) {
printf(“VIDIOC_QBUF error\n”);
return ERROR;
}
} -
开始采集视频:
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (fd_capture_v4l, VIDIOC_STREAMON, &type) < 0) {
printf(“VIDIOC_STREAMON error\n”);
return ERROR;
} -
取出采集到的数据帧:
capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
capture_buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd_capture_v4l, VIDIOC_DQBUF, &capture_buf) < 0) -
将取出的数据帧操作完成后重新入队列
if (ioctl(fd_capture_v4l, VIDIOC_QBUF, &capture_buf) < 0) {
printf(“VIDIOC_QBUF failed\n”);
return ERROR;
}