Linux下V4l2接口摄像头图像数据采集问题

时间:2021-10-17 16:09:33
  最近在忙基于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];
};

5 个解决方案

#1


该回复于2010-12-06 16:17:28被版主删除

#2


该回复于2010-12-06 16:17:28被版主删除

#3


我最近也在研究在linux下如何采集USB摄像头的信息!我实在虚拟机下进行调试的!但是遇到一个问题ioctl(video_dev,VIDIOCGCHAN,&video_chan)这个代码调用用来获得视频设备的通道信息,但是调用失败!不知道该如何解决!能不能帮帮忙啊?

#4


楼主解决了没?一样的问题啊,那个大小是怎么设置的呢?
我的USB摄像头支持MJPEG格式,设置640*480的分辨率。
但是buf.length 的大小为640*480*3!怎么和RGB的一样?
不知道这个buf.length怎么来的- -

采集的MJPEG保存为JPG格式,大小也是640*480*3!按理说jpg应该小的多啊。
但是用十六进制方式打开图片,里边却有大量的无用数据段全是0。
去掉无用数据段保存后,图片还是正常显示的。

#5


好吧,我查了一下文档。
Before applications can access the buffers they must map them into their address space with the mmap() function. The location of the buffers in device memory can be determined with the VIDIOC_QUERYBUF ioctl. The m.offset and length returned in a struct v4l2_buffer are passed as sixth and second parameter to the mmap() function. The offset and length values must not be modified. Remember the buffers are allocated in physical memory, as opposed to virtual memory which can be swapped out to disk. Applications should free the buffers as soon as possible with the munmap() function.

m.offset 和 length 是 v4l2_buffer结构体返回的。并且不能修改。因为是物理内存而非虚拟内存。
length 貌似是从v4l2_format 的fmt.pix.sizeimage取得值。
而sizeimage通常情况下是fmt.pix.bytesperline乘以fmt.pix.height得到的。
但如果是JPEG压缩的格式,驱动通常会分配一个足够大的buff。就像我那种情况,buff是640*480*3

英语水平差,看的挺费力。以上请勿当真,有没有有空的老师帮研究一下啊?
我就想获得一个实际大小的jpg图片,而不是有很多没用数据的640*480*3个字节大小的图片。

#1


该回复于2010-12-06 16:17:28被版主删除

#2


该回复于2010-12-06 16:17:28被版主删除

#3


我最近也在研究在linux下如何采集USB摄像头的信息!我实在虚拟机下进行调试的!但是遇到一个问题ioctl(video_dev,VIDIOCGCHAN,&video_chan)这个代码调用用来获得视频设备的通道信息,但是调用失败!不知道该如何解决!能不能帮帮忙啊?

#4


楼主解决了没?一样的问题啊,那个大小是怎么设置的呢?
我的USB摄像头支持MJPEG格式,设置640*480的分辨率。
但是buf.length 的大小为640*480*3!怎么和RGB的一样?
不知道这个buf.length怎么来的- -

采集的MJPEG保存为JPG格式,大小也是640*480*3!按理说jpg应该小的多啊。
但是用十六进制方式打开图片,里边却有大量的无用数据段全是0。
去掉无用数据段保存后,图片还是正常显示的。

#5


好吧,我查了一下文档。
Before applications can access the buffers they must map them into their address space with the mmap() function. The location of the buffers in device memory can be determined with the VIDIOC_QUERYBUF ioctl. The m.offset and length returned in a struct v4l2_buffer are passed as sixth and second parameter to the mmap() function. The offset and length values must not be modified. Remember the buffers are allocated in physical memory, as opposed to virtual memory which can be swapped out to disk. Applications should free the buffers as soon as possible with the munmap() function.

m.offset 和 length 是 v4l2_buffer结构体返回的。并且不能修改。因为是物理内存而非虚拟内存。
length 貌似是从v4l2_format 的fmt.pix.sizeimage取得值。
而sizeimage通常情况下是fmt.pix.bytesperline乘以fmt.pix.height得到的。
但如果是JPEG压缩的格式,驱动通常会分配一个足够大的buff。就像我那种情况,buff是640*480*3

英语水平差,看的挺费力。以上请勿当真,有没有有空的老师帮研究一下啊?
我就想获得一个实际大小的jpg图片,而不是有很多没用数据的640*480*3个字节大小的图片。