UsbCamera V4L2自动适配分辨率720和480p

最近在写UsbCamera(android)发现一个博客十分有用,因为是百度排在前面的(http://blog.csdn.net/u010164190/article/details/53205079)。
但是实测下来是有些问题的(为了技术)。
根据他的代码我写的如下:

char v4l2_ioctl_supported_framesize(int fd) {  //调试中,错误的代码
    int idx = 0;  
    char retChar = 'e'; //error  
    if (-1 != fd) {  
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
        struct v4l2_fmtdesc fmtdesc;  
        struct v4l2_frmivalenum frmival;  
        struct v4l2_frmsizeenum frmsize;  
        fmtdesc.index = 0;  
        fmtdesc.type = type;  
        LOGE("allan-1= pixelformat %x",fmtdesc.pixelformat);  
        while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {  
            LOGE("allan0= pixelformat %x",fmtdesc.pixelformat);  
            frmsize.pixel_format = fmtdesc.pixelformat;  
            frmsize.index = 0;  
            while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) {  
                if(frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {  
                    LOGE("allan1= %dx%d\n", frmsize.discrete.width, frmsize.discrete.height);  
                    retChar = 'n';
                }else if(frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE){  
       printf("allan2:%dx%d\n",frmsize.discrete.width, frmsize.discrete.height);  
     }  
                frmsize.index++;  
                LOGE("doubt it...");  
            }     
            fmtdesc.index++;  
        }     
    }     
    return retChar;  
}  

会发现log如下:

 WebCam  : allan-1= pixelformat e33706c4
WebCam  : allan0= pixelformat 56595559
WebCam  : allan1= 1280x720
WebCam  : doubt it...
WebCam  : allan1= 1280x480
WebCam  : doubt it...
WebCam  : allan1= 640x480
 WebCam  : doubt it...
WebCam  : allan1= 352x288
WebCam  : doubt it...
WebCam  : allan1= 320x240
WebCam  : doubt it...
WebCam  : allan1= 176x144
WebCam  : doubt it...
WebCam  : allan1= 160x120
WebCam  : doubt it...
WebCam  : allan0= pixelformat 47504a4d
WebCam  : allan1= 1280x720
WebCam  : doubt it...
WebCam  : allan1= 1280x480
WebCam  : doubt it...
WebCam  : allan1= 640x480
WebCam  : doubt it...
WebCam  : allan1= 352x288
WebCam  : doubt it...
WebCam  : allan1= 320x240
WebCam  : doubt it...
WebCam  : allan1= 176x144
WebCam  : doubt it...
WebCam  : allan1= 160x120
WebCam  : doubt it...

会发现allan2是不会打印的。因为我们给v4l2_frmsizeenum frmsize赋值了type为V4L2_BUF_TYPE_VIDEO_CAPTURE,于是allan2的V4L2_FRMSIZE_TYPE_STEPWISE可以去掉。同时循环很多数值也不正确,是因为ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)的循环体frmsize.index++。这个时候,同时也已经意识到支持的分辨率这里列出这么多是不对的,而只有第一个是对的。我们直接break就好了。

但是原理上,这里有表述

http://blog.sina.com.cn/s/blog_602f87700101bf36.html 枚举设备所支持的image
format: VIDIOC_ENUM_FMT
struct v4l2_fmtdesc fmtdesc;
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(Handle, VIDIOC_ENUM_FMT, &fmtdesc);

使用ioctl VIDIOC_ENUM_FMT 依次询问,
type为:V4L2_BUF_TYPE_VIDEO_CAPTURE。
index从0开始,依次增加,直到返回. Driver会填充结构体struct
v4l2_fmtdesc的其它内容,如果index超出范围,则返回-1。
struct v4l2_fmtdesc
{
__u32 index; // 需要填充,从0开始,依次上升。
enum v4l2_buf_type type; //Camera,则填写V4L2_BUF_TYPE_VIDEO_CAPTURE
__u32 flags; // 如果压缩的,则Driver 填写:V4L2_FMT_FLAG_COMPRESSED,否则为0
__u8 description[32]; // image format的描述,如:YUV 4:2:2 (YUYV)
__u32 pixelformat; //所支持的格式。 如:V4L2_PIX_FMT_UYVY
__u32 reserved[4];
};

这样,则知道当前硬件支持什么样的image format.

所以,我们不需要对v4l2_frmsizeenum进行index++。只需要对fmtdesc.index++即可。
这样修改以后,是否就OK了呢?
还是不行,又发现,

 WebCam  : allan-1= pixelformat e36bc6c4
 WebCam  : allan0= pixelformat 56595559
 WebCam  : allan1= 1280x720
 WebCam  : allan0= pixelformat 47504a4d
 WebCam  : allan1= 1280x720

循环还是有2次,为什么,最后我们聚焦到frmdesc.flags这个参数上,很容易加log知道了,其中有一次是fmtdesc.flags=V4L2_FMT_FLAG_COMPRESSED打印出来的。
所以,我们需要对V4L2_FMT_FLAG_COMPRESSED的flag进行一次过滤。
因此,我们的最终代码改成,

char v4l2_ioctl_supported_framesize(int fd) {
    int idx = 0;
    char retChar = 'e'; //error
    if (-1 != fd) {
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        struct v4l2_fmtdesc fmtdesc;
        struct v4l2_frmivalenum frmival;
        struct v4l2_frmsizeenum frmsize;
        fmtdesc.index = 0;
        fmtdesc.type = type;
        while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
            frmsize.pixel_format = fmtdesc.pixelformat;
            frmsize.index = 0;
            //fmtdesc.flags = 0, V4L2_FMT_FLAG_COMPRESSED = 1
            if(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0 && frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE && fmtdesc.flags == 0) {
                //LOGE("allan= %dx%d\n", frmsize.discrete.width, frmsize.discrete.height);
                //TODO 自行修改返回结构体,或者传入指针地址来赋值
                retChar = 'n';
            }   
            fmtdesc.index++;
        }   
    }   
    return retChar;
}

总结:网上找答案要不断找到真相,结合自己的测试。同时还要站在巨人的肩膀上有一点小进步。比如这里,第一个帖子,指出了方法;第二个帖子讲了一些原理;我这边又进一步整合和发现循环体的问题和flags参数的问题。
好了今天到这里。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Ubuntu是一个基于Linux的操作系统,它提供了许多强大的功能和工具用于开发各种应用程序。v4l2是Linux提供的一个用于操作视频设备的接口,它能够访问和控制电脑上连接的USB摄像头。 在Ubuntu上使用USB摄像头可以通过v4l2接口来实现。首先,你需要安装相应的驱动程序,这样系统才能识别并与USB摄像头进行通信。一般来说,大多数常见的USB摄像头都会自动被Ubuntu识别并安装相应的驱动程序。 一旦你的USB摄像头被成功安装和识别,你就可以使用v4l2接口来访问它。Qt是一个跨平台的应用开发框架,它提供了丰富的功能和工具用于开发图形用户界面(GUI)应用程序。你可以使用Qt来编写一个应用程序,通过v4l2接口实时获取USB摄像头的图像,并在Qt的界面上显示出来。 在编写Qt应用程序时,你需要使用相关的API和库函数来实现与v4l2接口的通信。首先,你需要打开USB摄像头设备,然后设置相关的参数,如图像分辨率、帧率等。接下来,你可以使用v4l2接口读取摄像头的图像帧,并通过Qt的图像显示控件将获取的图像渲染在界面上。 除了实时显示USB摄像头的图像,你还可以利用v4l2接口进行其他操作,如录制视频、拍摄照片、调整摄像头的设置等等。通过Qt的界面,你可以方便地提供用户界面来控制这些功能。 总结来说,Ubuntu提供了v4l2接口来操作USB摄像头,而Qt框架可以方便地集成这些功能并实现交互界面,从而实现USB摄像头的图像显示和其他操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值