您的位置:首页 > 移动开发 > Android开发

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

2017-07-18 17:48 447 查看
最近在写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参数的问题。

好了今天到这里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android UsbCamera v4l2