Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] vimc: cap: Support several image formats

Allow user space to change the image format as the frame size, the
pixel format, colorspace, quantization, field YCbCr encoding
and the transfer function

Signed-off-by: Helen Koike <helen.koike@collabora.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Helen Fornazier and committed by
Mauro Carvalho Chehab
535d296f 88ad71aa

+102 -17
+102 -17
drivers/media/platform/vimc/vimc-capture.c
··· 40 40 struct media_pipeline pipe; 41 41 }; 42 42 43 + static const struct v4l2_pix_format fmt_default = { 44 + .width = 640, 45 + .height = 480, 46 + .pixelformat = V4L2_PIX_FMT_RGB24, 47 + .field = V4L2_FIELD_NONE, 48 + .colorspace = V4L2_COLORSPACE_DEFAULT, 49 + }; 50 + 43 51 struct vimc_cap_buffer { 44 52 /* 45 53 * struct vb2_v4l2_buffer must be the first element ··· 81 73 *fmt = vcap->format; 82 74 } 83 75 84 - static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, 76 + static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv, 85 77 struct v4l2_format *f) 86 78 { 87 79 struct vimc_cap_device *vcap = video_drvdata(file); ··· 91 83 return 0; 92 84 } 93 85 94 - static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, 95 - struct v4l2_fmtdesc *f) 86 + static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, 87 + struct v4l2_format *f) 88 + { 89 + struct v4l2_pix_format *format = &f->fmt.pix; 90 + const struct vimc_pix_map *vpix; 91 + 92 + format->width = clamp_t(u32, format->width, VIMC_FRAME_MIN_WIDTH, 93 + VIMC_FRAME_MAX_WIDTH) & ~1; 94 + format->height = clamp_t(u32, format->height, VIMC_FRAME_MIN_HEIGHT, 95 + VIMC_FRAME_MAX_HEIGHT) & ~1; 96 + 97 + /* Don't accept a pixelformat that is not on the table */ 98 + vpix = vimc_pix_map_by_pixelformat(format->pixelformat); 99 + if (!vpix) { 100 + format->pixelformat = fmt_default.pixelformat; 101 + vpix = vimc_pix_map_by_pixelformat(format->pixelformat); 102 + } 103 + /* TODO: Add support for custom bytesperline values */ 104 + format->bytesperline = format->width * vpix->bpp; 105 + format->sizeimage = format->bytesperline * format->height; 106 + 107 + if (format->field == V4L2_FIELD_ANY) 108 + format->field = fmt_default.field; 109 + 110 + vimc_colorimetry_clamp(format); 111 + 112 + return 0; 113 + } 114 + 115 + static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, 116 + struct v4l2_format *f) 96 117 { 97 118 struct vimc_cap_device *vcap = video_drvdata(file); 98 119 99 - if (f->index > 0) 120 + /* Do not change the format while stream is on */ 121 + if (vb2_is_busy(&vcap->queue)) 122 + return -EBUSY; 123 + 124 + vimc_cap_try_fmt_vid_cap(file, priv, f); 125 + 126 + dev_dbg(vcap->vdev.v4l2_dev->dev, "%s: format update: " 127 + "old:%dx%d (0x%x, %d, %d, %d, %d) " 128 + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, 129 + /* old */ 130 + vcap->format.width, vcap->format.height, 131 + vcap->format.pixelformat, vcap->format.colorspace, 132 + vcap->format.quantization, vcap->format.xfer_func, 133 + vcap->format.ycbcr_enc, 134 + /* new */ 135 + f->fmt.pix.width, f->fmt.pix.height, 136 + f->fmt.pix.pixelformat, f->fmt.pix.colorspace, 137 + f->fmt.pix.quantization, f->fmt.pix.xfer_func, 138 + f->fmt.pix.ycbcr_enc); 139 + 140 + vcap->format = f->fmt.pix; 141 + 142 + return 0; 143 + } 144 + 145 + static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, 146 + struct v4l2_fmtdesc *f) 147 + { 148 + const struct vimc_pix_map *vpix = vimc_pix_map_by_index(f->index); 149 + 150 + if (!vpix) 100 151 return -EINVAL; 101 152 102 - /* We only support one format for now */ 103 - f->pixelformat = vcap->format.pixelformat; 153 + f->pixelformat = vpix->pixelformat; 154 + 155 + return 0; 156 + } 157 + 158 + static int vimc_cap_enum_framesizes(struct file *file, void *fh, 159 + struct v4l2_frmsizeenum *fsize) 160 + { 161 + const struct vimc_pix_map *vpix; 162 + 163 + if (fsize->index) 164 + return -EINVAL; 165 + 166 + /* Only accept code in the pix map table */ 167 + vpix = vimc_pix_map_by_code(fsize->pixel_format); 168 + if (!vpix) 169 + return -EINVAL; 170 + 171 + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; 172 + fsize->stepwise.min_width = VIMC_FRAME_MIN_WIDTH; 173 + fsize->stepwise.max_width = VIMC_FRAME_MAX_WIDTH; 174 + fsize->stepwise.min_height = VIMC_FRAME_MIN_HEIGHT; 175 + fsize->stepwise.max_height = VIMC_FRAME_MAX_HEIGHT; 176 + fsize->stepwise.step_width = 2; 177 + fsize->stepwise.step_height = 2; 104 178 105 179 return 0; 106 180 } ··· 200 110 static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { 201 111 .vidioc_querycap = vimc_cap_querycap, 202 112 203 - .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap, 204 - .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap, 205 - .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap, 113 + .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, 114 + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, 115 + .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, 206 116 .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, 117 + .vidioc_enum_framesizes = vimc_cap_enum_framesizes, 207 118 208 119 .vidioc_reqbufs = vb2_ioctl_reqbufs, 209 120 .vidioc_create_bufs = vb2_ioctl_create_bufs, ··· 451 360 INIT_LIST_HEAD(&vcap->buf_list); 452 361 spin_lock_init(&vcap->qlock); 453 362 454 - /* Set the frame format (this is hardcoded for now) */ 455 - vcap->format.width = 640; 456 - vcap->format.height = 480; 457 - vcap->format.pixelformat = V4L2_PIX_FMT_RGB24; 458 - vcap->format.field = V4L2_FIELD_NONE; 459 - vcap->format.colorspace = V4L2_COLORSPACE_SRGB; 460 - 363 + /* Set default frame format */ 364 + vcap->format = fmt_default; 461 365 vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat); 462 - 463 366 vcap->format.bytesperline = vcap->format.width * vpix->bpp; 464 367 vcap->format.sizeimage = vcap->format.bytesperline * 465 368 vcap->format.height;