摄像头读取出现VIDIOC_STREAMON: No space left on device 错误

先说下原因,linux中为usb camera提供了一个标准的V4L2的驱动以方便使用,只要符合驱动规范就可以实现即插即用usb camera设备,即免驱动安装。 但市面上的USB 摄像头都是2.0的。usb bus的 bandwidth是有限的,而V4L2驱动采用的是贪心原则,即camera会要求获取最大带宽;因此将两个camera接入一路usb bus,打开第二个camera(尤其是采用YUV格式打开)就会出现”No space left on device”的错误。

如果是QT读取USB摄像头出现如下错误,请先看解决方法四。

解决方法一:

接在不同的usb bus上,使用lsusb 命令查看bus信息, 类似“Linux Foundation 2.0 root hub”表示该总线为usb 2.0;

解决方法二:

降低打开视频流的分辨率,改为320x240;并对uvcvideo驱动设置参数,强制为camera分配带宽时计算所需带宽而非申请全部带宽;(只对YUYV格式有效,对有些camera此方法可以支持640x480分辨率)

sudo rmmod uvcvideo
sudo modprobe uvcvideo quirks=128

或者添加 etc/modprobe.d/uvccamera0508.conf 文件,内容如下:

options uvcvideo quirks=128

重启设备,设置低分辨率访问即可。

解决方法三:

修改驱动,重新编译源码,但这种工作费时费力。所有最终并没有这么搞,但我还是从其它博客中拷贝了一给解决办法已供参考:

 

下载kernel源码
这个可能会很慢,我实在官网下载的,为此还给git配置了代理=-=
看造化了,不过好像去github上下载会好很多。。。

切换版本


#查看现在运行系统内核版本

uname -r

#切换到相应版本,我的是4.2.0-27-generic

git checkout v4.2

拷贝UVC Driver源码

cp linux/drivers/media/usb/uvc .

修改Makefile

cd uvc
vim Makefile
     obj-m += uvcvideo.o
     uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o     \
                    uvc_status.o uvc_isight.o uvc_debugfs.o
     ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
     uvcvideo-objs  += uvc_entity.o 
     endif
     obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
     all:
          make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
     clean:      
          make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

修改UVC Driver

cd uvc
vim uvc_video.c

#跳转到函数uvc_fixup_video_ctrl(),在该函数最后添加下代码

if (format->flags & UVC_FMT_FLAG_COMPRESSED) {
    ctrl->dwMaxPayloadTransferSize = 0x400;
  }

编译修改后的驱动并移除原本的uvcvideo驱动和装载修改后的驱动

make
sudo rmmod uvcvideo
sudo insmod ./uvcvideo.ko quirks=128

到这里基本上就成功了,我在ubuntu14.04上就可以了,实现一路usb bus打开两个camera,运行3个也是可以的,但在Ubuntu16.04上却没有装成功,这是属于开发驱动一块遇到的问题了,会后续另写一篇博客写一下自己的解决过程。

Debug过程中用到的一些命令记在另一篇博客中,有兴趣可以看一下:
http://blog.csdn.net/zhangwu1241/article/details/60871000

使用lsusb命令查看当前系统的USB总线信息,而使用lsusb -t命令,则可以看到具体挂在情况:

这里写图片描述

方法四:

以上三种都是google和百度到的绝大部分的解决方法,但都不能解决我的问题,尤其是第二种,直接就找不到uvcvideo驱动。

最终自己摸索出另外一种方法,那就是修改数据采集方式。现在好多数据采集都是从网上照搬例程,复制粘贴过来的。所以很多人也不考虑例程含义。


    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = SOUWIDTH;
    fmt.fmt.pix.height = SOUHIGH;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;//V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

    if(-1 == ioctl(fd, VIDIOC_S_FMT, &fmt))
    {
        qDebug() << QString(strerror(errno)) << __LINE__;
        emit display_error(tr("VIDIOC_S_FMT").arg(QString(strerror(errno))));
        return -1;
    }
 

上面是我修改的例程的核心部分,即将读取方式由V4L2_PIX_FMT_YUYV修改为V4L2_PIX_FMT_MJPEG方式读取。

但如上方式有两个缺陷

一、摄像头必须支持MJPEG方式读取才可以。

二、将MJPEG转换成可显示的RGB图像需要外部库。百度的例程中有很多将YUV转换成RGB的,没有将MJPEG转换成RGB的。但有的开发工具是支持直接将MJPEG数据源转换成RGB格式的,如QT。我用的是QT,可以直接转换


PS:

市面上的摄像头参差不齐,例如我用过两款摄像头,都支持MJPEG格式,都通过外接HUB去连接两个USB摄像头的格式,但一款却始终不能修改分辨率,并且第二路摄像头分辨率被设置成了很诡异的数值。所以当出现此错误的时候适当考虑一下摄像头的问题也是可以的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章