step1: 打开视频设备
static int video_open(const char *devname)
{
struct v4l2_capability cap;
int dev, ret;
dev = open(devname, O_RDWR);
if (dev < 0) {
TestAp_Printf(TESTAP_DBG_ERR, "Error opening device %s: %d.\n", devname, errno);
return dev;
}
memset(&cap, 0, sizeof cap);
ret = ioctl(dev, VIDIOC_QUERYCAP, &cap);
if (ret < 0) {
TestAp_Printf(TESTAP_DBG_ERR, "Error opening device %s: unable to query device.\n",
devname);
close(dev);
return ret;
}
}
step2: Set the video format
static int video_set_format(int dev, unsigned int w, unsigned int h, unsigned int format)
{
struct v4l2_format fmt;
int ret;
memset(&fmt, 0, sizeof fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = w;
fmt.fmt.pix.height = h;
fmt.fmt.pix.pixelformat = format;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
ret = ioctl(dev, VIDIOC_S_FMT, &fmt);
if (ret < 0) {
TestAp_Printf(TESTAP_DBG_ERR, "Unable to set format: %d.\n", errno);
return ret;
}
TestAp_Printf(TESTAP_DBG_FLOW, "Video format set: width: %u height: %u buffer size: %u\n",
fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.sizeimage);
return 0;
}
step3: Set the frame rate
static int video_set_framerate(int dev, int framerate)
{
struct v4l2_streamparm parm;
int ret;
memset(&parm, 0, sizeof parm);
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(dev, VIDIOC_G_PARM, &parm);
if (ret < 0) {
TestAp_Printf(TESTAP_DBG_ERR, "Unable to get frame rate: %d.\n", errno);
return ret;
}
TestAp_Printf(TESTAP_DBG_FLOW, "Current frame rate: %u/%u\n",
parm.parm.capture.timeperframe.numerator,
parm.parm.capture.timeperframe.denominator);
parm.parm.capture.timeperframe.numerator = 1;
parm.parm.capture.timeperframe.denominator = framerate;
ret = ioctl(dev, VIDIOC_S_PARM, &parm);
if (ret < 0) {
TestAp_Printf(TESTAP_DBG_ERR, "Unable to set frame rate: %d.\n", errno);
return ret;
}
ret = ioctl(dev, VIDIOC_G_PARM, &parm);
if (ret < 0) {
TestAp_Printf(TESTAP_DBG_ERR, "Unable to get frame rate: %d.\n", errno);
return ret;
}
TestAp_Printf(TESTAP_DBG_FLOW, "Frame rate set: %u/%u\n",
parm.parm.capture.timeperframe.numerator,
parm.parm.capture.timeperframe.denominator);
return 0;
}
step4:Allocate buffers.
static int video_reqbufs(int dev, int nbufs)
{
struct v4l2_requestbuffers rb;
int ret;
memset(&rb, 0, sizeof rb);
rb.count = nbufs;
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
rb.memory = V4L2_MEMORY_MMAP;
ret = ioctl(dev, VIDIOC_REQBUFS, &rb);
if (ret < 0) {
TestAp_Printf(TESTAP_DBG_ERR, "Unable to allocate buffers: %d.\n", errno);
return ret;
}
TestAp_Printf(TESTAP_DBG_FLOW, "%u buffers allocated.\n", rb.count);
return rb.count;
}
对应的内核处理流程如下:
主要的工作,就是通过vb2_vmalloc_alloc函数中的vmalloc_user函数分配内核虚拟地址连续的内存(虚拟地址空间属于(VMALLOC_START, VMALLOC_END)空间,并建立
相应的内核映射),每个这样的内存块(请求中,总共有nbufs个视频buf),都通过struct vb2_buffer *vb结构体来表示,并