Linux v4l2架构学习总链接
step 4 : 设置图像格式
1.枚举支持的像素格式
struct v4l2_fmtdesc fmtdesc;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmtdesc.index = 0;
while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
{
//....
}
对应vivi驱动的vidioc_enum_fmt_vid_cap
static struct vivi_fmt formats[] = {
{
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
},
{
.name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
},
{
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
.depth = 16,
},
{
.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
.depth = 16,
},
{
.name = "RGB555 (LE)",
.fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
.depth = 16,
},
{
.name = "RGB555 (BE)",
.fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
.depth = 16,
},
};
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct vivi_fmt *fmt;
if (f->index >= ARRAY_SIZE(formats))
return -EINVAL;
fmt = &formats[f->index];
strlcpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
可以看到将name和forcc返回给用户空间了,应用代码测试如下
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
printf("fmt name: [%s]\n", fmtdesc.description);
printf("fmt pixelformat : '%c%c%c%c', description = '%s'\n",fmtdesc.pixelformat & 0xFF,
(fmtdesc.pixelformat >> 8) & 0xFF,(fmtdesc.pixelformat >> 16) & 0xFF,
(fmtdesc.pixelformat >> 24) & 0xFF,fmtdesc.description);
fmtdesc.index++;
}
打印如下
fmt name: [YUYV 4:2:2]
fmt pixelformat : 'YUYV', description = 'YUYV 4:2:2'
fmt name: [UYVY 4:2:2]
fmt pixelformat : 'UYVY', description = 'UYVY 4:2:2'
fmt name: [16-bit RGB 5-6-5]
fmt pixelformat : 'RGBP', description = '16-bit RGB 5-6-5'
fmt name: [16-bit RGB 5-6-5 BE]
fmt pixelformat : 'RGBR', description = '16-bit RGB 5-6-5 BE'
fmt name: [16-bit A/XRGB 1-5-5-5]
fmt pixelformat : 'RGBO', description = '16-bit A/XRGB 1-5-5-5'
fmt name: [16-bit A/XRGB 1-5-5-5 BE]
fmt pixelformat : 'RGBQ', description = '16-bit A/XRGB 1-5-5-5 BE'
可以看到列举出来支持的格式,这里我们选择格式 YUYV 4:2:2
2,设置图像格式
memset(&v4l2_fmt, 0, sizeof(struct v4l2_format));
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_fmt.fmt.pix.width = width; //宽度
v4l2_fmt.fmt.pix.height = height; //高度
v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //像素格式
v4l2_fmt.fmt.pix.field = V4L2_FIELD_ANY;
if (ioctl(fd, VIDIOC_S_FMT, &v4l2_fmt) < 0)
这里对应vivi驱动的vidioc_s_fmt_vid_cap
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_dev *dev = video_drvdata(file);
struct vb2_queue *q = &dev->vb_vidq;
int ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret < 0)
return ret;
/*
* vb2_is_streaming 判断vb2_is_streaming的值,后面的分析我们会看到这个值
* 的变化,这里认为值为0,if不满足
*/
if (vb2_is_streaming(q)) {
dprintk(dev, 1, "%s device busy\n", __func__);
return -EBUSY;
}
dev->fmt = get_format(f);
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
dev->field = f->fmt.pix.field;
return 0;
}
这里可以看到,vivi驱动中还有一个检查,另外将数据放到了dev相关成员中。
完整应用操作如下
memset(&fmt, 0, sizeof(struct v4l2_format));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 1920;
fmt.fmt.pix.height = 1080;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
printf("Set format fail\n");
goto err;
}
对于这里的field,可以去看这篇博客,写的很好。https://blog.csdn.net/kickxxx/article/details/6367669