最近在忙基于Linux下的video for linux 2 接口的应用程序设计,程序已经能在PC机上跑通,并能顺利采集摄像头图像数据。但是,在移到板子上(S3C2440),出现了一些问题,前面部分问题已经被我自己解决好,但是还有一个问题搞不清楚。闲话少说,问题如下:
程序在调用ioctl()函数向驱动申请内存 如下:
struct v4l2_requestbuffers req;
if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
return -1;
}
可以看到,这里传给 ioctl() 函数的参数有:设备fd, 命令VIDIOC_REQBUFS , buffer的结构体req三个。我们知道,设备fd就是摄像头设备文件,命令VIDIOC_REQBUFS 是表示让ioctl这个系统调用函数分配缓存空间,结构体req里一般有3个成员:
1: 要申请buffer的数量count // 缓存数量,也就是说在缓存队列里保持多少张照片
2: 数据流类型 // 必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
3: memory的类型 // V4L2_MEMORY_MMAP 或 V4L2_MEMORY_USERPTR,这里用的mmap方式
这段程序没有传给其每个buffer的大小,程序分配给buffer的内存大小是根据什么来的呢?我在PC上之所以在这一点上能成功,是因为在PC下的,被ioctl()函数分配到的每个buffer大小 刚好是我的摄像头的图像的大小640×480×2,但是同样的程序,对于同样的摄像头,在板子上,被分配的buffer大小不是这个值,但也是定值,就这里弄不明白了。望前辈指导!
接下来是内存映射,将缓存映射到用户空间,但是缓存空间分配工作是上面的程序做的,下面的这段 ioctl(VIDIOC_QUERYBUF )只是根据上面分配的缓存个数来进行映射。学习下面的这段程序可以发现,下面的 ioctl() 函数根据传进来的type ,memory ,index 参数,返回缓存分配的其他信息到buf结构体其他成员变量中(如我最头痛的buf.length ),以给后面的mmap()函数用,进行映射。
for (numBufs = 0; numBufs < req.count; numBufs++) {
memset( &buf, 0, sizeof(buf) );
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = numBufs;
// 读取缓存
if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
return -1;
}
buffers[numBufs].length = buf.length;
// 转换成相对地址
buffers[numBufs].start = mmap(NULL, buf.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd, buf.m.offset);
我曾尝试在ioctl(VIDIOC_QUERYBUF )前,先给buf.length 赋值(如 buf.length = 640*480*2;),但是经过
ioctl(VIDIOC_QUERYBUF )后,buf.length 值被设成了其他值,这个值,也就是上面我的问题所在。
另附:(一些结构体)
struct v4l2_requestbuffers
{
__u32 count; // 缓存数量,也就是说在缓存队列里保持多少张照片
enum v4l2_buf_type type; // 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
enum v4l2_memory memory; // V4L2_MEMORY_MMAP 或 V4L2_MEMORY_USERPTR
__u32 reserved[2];
};