Linux v4l2架构学习总链接
gitee源码
mmap
同样的先去看从应用调用vivi驱动分析v4l2 – 映射 mmap
这里看看怎么找到plane的
static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
unsigned int *_buffer, unsigned int *_plane)
{
struct vb2_buffer *vb;
unsigned int buffer, plane;
/*
* Go over all buffers and their planes, comparing the given offset
* with an offset assigned to each plane. If a match is found,
* return its buffer and plane numbers.
*/
for (buffer = 0; buffer < q->num_buffers; ++buffer) {
vb = q->bufs[buffer];
for (plane = 0; plane < vb->num_planes; ++plane) {
/* 可以看到通过offset的值,精确找到对应的plane
* 用于映射到应用空间
*/
if (vb->planes[plane].m.offset == off) {
*_buffer = buffer;
*_plane = plane;
return 0;
}
}
}
return -EINVAL;
}
编写对应的应用程序
struct plane_start {
void * start;
};
struct buffer {
struct plane_start* plane_start;
struct v4l2_plane* planes_buffer;
};
buffers = malloc(req.count * sizeof(*buffers));
for(i = 0; i < req.count; i++) {
memset(&buf, 0, sizeof(buf));
planes_buffer = calloc(num_planes, sizeof(*planes_buffer));
plane_start = calloc(num_planes, sizeof(*plane_start));
memset(planes_buffer, 0, sizeof(*planes_buffer));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_MMAP;
buf.m.planes = planes_buffer;
buf.length = num_planes;
buf.index = i;
if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf)) {
printf("Querybuf fail\n");
goto err;
}
(buffers + i)->planes_buffer = planes_buffer;
(buffers + i)->plane_start = plane_start;
for(j = 0; j < num_planes; j++) {
printf("plane[%d]: length = %d\n", j, (planes_buffer + j)->length);
printf("plane[%d]: offset = %d\n", j, (planes_buffer + j)->m.mem_offset);
/* 这里要记录每个plane的映射地址 */
(plane_start + j)->start = mmap (NULL /* start anywhere */,
(planes_buffer + j)->length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
fd,
(planes_buffer + j)->m.mem_offset);
if (MAP_FAILED == (plane_start +j)->start) {
printf ("mmap failed\n");
req.count = i;
goto unmmap;
}
}
}
可以看到和传统的方式对比,传统方式可以认为只有1个plane,所以只需要对没有buffer进行mmap就可以了。
对于mplane的情况,要对每个buffer的每个plane进行mmap