Hello André, On Mon, 2019-02-11 at 17:11 -0200, André Almeida wrote: > On 2/6/19 7:29 PM, Ezequiel Garcia wrote: > > Add two new API helpers, v4l2_fill_pixfmt and v4l2_fill_pixfmt_mp, > > to be used by drivers to calculate plane sizes and bytes per lines. > > > > Note that driver-specific padding and alignment are not > > taken into account, and must be done by drivers using this API. > > > > Signed-off-by: Ezequiel Garcia <ezequiel@xxxxxxxxxxxxx> > > I've used the function v4l2_fill_pixfmt_mp in vimc to set multiplanar > formats in vidioc_s_fmt and worked correctly. > > Tested-by: André Almeida<andre.almeida@xxxxxxxxxxxxx> Thanks for the test! For next time, please make sure you avoid HTML mails on mailing lists. > > --- > > This patch depends on "[PATCH 1/2] rockchip/vpu: Rename pixel format helpers" > > so avoid name collisions. > > > > Other than that, I've addressed all the feedback provided by Hans on v1, > > and tested with the MPEG-2 RK3399 decoder. > > > > drivers/media/v4l2-core/v4l2-common.c | 154 ++++++++++++++++++++++++++ > > include/media/v4l2-common.h | 30 +++++ > > 2 files changed, 184 insertions(+) > > > > diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c > > index 50763fb42a1b..93030d1bc87f 100644 > > --- a/drivers/media/v4l2-core/v4l2-common.c > > +++ b/drivers/media/v4l2-core/v4l2-common.c > > @@ -44,6 +44,7 @@ > > * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman) > > */ > > > > +#include <linux/ctype.h> > > #include <linux/module.h> > > #include <linux/types.h> > > #include <linux/kernel.h> > > @@ -455,3 +456,156 @@ int v4l2_s_parm_cap(struct video_device *vdev, > > return ret; > > } > > EXPORT_SYMBOL_GPL(v4l2_s_parm_cap); > > + > > +static char printable_char(int c) > > +{ > > + return isascii(c) && isprint(c) ? c : '?'; > > +} > > + > > +const char *v4l2_get_fourcc_name(uint32_t format) > > +{ > > + static char buf[8]; > > + > > + snprintf(buf, 8, > > + "%c%c%c%c%s", > > + printable_char(format & 0xff), > > + printable_char((format >> 8) & 0xff), > > + printable_char((format >> 16) & 0xff), > > + printable_char((format >> 24) & 0x7f), > > + (format & BIT(31)) ? "-BE" : ""); > > + > > + return buf; > > +} > > +EXPORT_SYMBOL(v4l2_get_fourcc_name); > > + > > +const struct v4l2_format_info *v4l2_format_info(u32 format) > > +{ > > + static const struct v4l2_format_info formats[] = { > > + /* RGB formats */ > > + { .format = V4L2_PIX_FMT_BGR24, .num_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_RGB24, .num_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_HSV24, .num_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_BGR32, .num_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_XBGR32, .num_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_RGB32, .num_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_XRGB32, .num_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_HSV32, .num_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_ARGB32, .num_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_ABGR32, .num_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_GREY, .num_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + > > + /* YUV formats */ > > + { .format = V4L2_PIX_FMT_YUYV, .num_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_YVYU, .num_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_UYVY, .num_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_VYUY, .num_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, > > + > > + { .format = V4L2_PIX_FMT_NV12, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, > > + { .format = V4L2_PIX_FMT_NV21, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, > > + { .format = V4L2_PIX_FMT_NV16, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_NV61, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_NV24, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_NV42, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, > > + > > + { .format = V4L2_PIX_FMT_YUV410, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, > > + { .format = V4L2_PIX_FMT_YVU410, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, > > + { .format = V4L2_PIX_FMT_YUV411P, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 }, > > + { .format = V4L2_PIX_FMT_YUV420, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, > > + { .format = V4L2_PIX_FMT_YVU420, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, > > + { .format = V4L2_PIX_FMT_YUV422P, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, > > + > > + /* Non-contiguous, aka multiplanar formats */ > > + { .format = V4L2_PIX_FMT_YUV420M, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2, .non_contiguous = 1 }, > > + { .format = V4L2_PIX_FMT_YVU420M, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2, .non_contiguous = 1 }, > > + { .format = V4L2_PIX_FMT_YUV422M, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1, .non_contiguous = 1 }, > > + { .format = V4L2_PIX_FMT_YVU422M, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1, .non_contiguous = 1 }, > > + { .format = V4L2_PIX_FMT_YUV444M, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1, .non_contiguous = 1 }, > > + { .format = V4L2_PIX_FMT_YVU444M, .num_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1, .non_contiguous = 1 }, > > + > > + { .format = V4L2_PIX_FMT_NV12M, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2, .non_contiguous = 1 }, > > + { .format = V4L2_PIX_FMT_NV21M, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2, .non_contiguous = 1 }, > > + { .format = V4L2_PIX_FMT_NV16M, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1, .non_contiguous = 1 }, > > + { .format = V4L2_PIX_FMT_NV61M, .num_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1, .non_contiguous = 1 }, > > + }; > > + unsigned int i; > > + > > + for (i = 0; i < ARRAY_SIZE(formats); ++i) > > + if (formats[i].format == format) > > + return &formats[i]; > > + return NULL; > > +} > > +EXPORT_SYMBOL(v4l2_format_info); > > + > > +int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, > > + int pixelformat, int width, int height) > > +{ > > + const struct v4l2_format_info *info; > > + struct v4l2_plane_pix_format *plane; > > + int i; > > + > > + info = v4l2_format_info(pixelformat); > > + if (!info) > > + return -EINVAL; > > + > > + pixfmt->width = width; > > + pixfmt->height = height; > > + pixfmt->pixelformat = pixelformat; > > + > > + if (!info->non_contiguous) { > > + pixfmt->num_planes = 1; > > + plane = &pixfmt->plane_fmt[0]; > > + plane->bytesperline = width * info->bpp[0]; > > + plane->sizeimage = 0; > > + for (i = 0; i < info->num_planes; i++) { > > + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; > > + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; > > + > > + plane->sizeimage += info->bpp[i] * > > + DIV_ROUND_UP(width, hdiv) * > > + DIV_ROUND_UP(height, vdiv); > > + } > > + } else { > > + pixfmt->num_planes = info->num_planes; > > + for (i = 0; i < info->num_planes; i++) { > > + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; > > + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; > > + > > + plane = &pixfmt->plane_fmt[i]; > > + plane->bytesperline = > > + info->bpp[i] * DIV_ROUND_UP(width, hdiv); > > + plane->sizeimage = > > + plane->bytesperline * DIV_ROUND_UP(height, vdiv); > > + } > > + } > > + return 0; > > +} > > +EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp); > > + > > +int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, int width, int height) > > +{ > > + const struct v4l2_format_info *info; > > + int i; > > + > > + info = v4l2_format_info(pixelformat); > > + if (!info) > > + return -EINVAL; > > + if (info->non_contiguous) > > + return -EINVAL; > > + > > + pixfmt->width = width; > > + pixfmt->height = height; > > + pixfmt->pixelformat = pixelformat; > > + pixfmt->bytesperline = width * info->bpp[0]; > > + pixfmt->sizeimage = 0; > > + > > + for (i = 0; i < info->num_planes; i++) { > > + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; > > + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; > > + > > + pixfmt->sizeimage += info->bpp[i] * > > + DIV_ROUND_UP(width, hdiv) * > > + DIV_ROUND_UP(height, vdiv); > > + } > > + return 0; > > +} > > +EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); > > diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h > > index 0c511ed8ffb0..977879dc2e76 100644 > > --- a/include/media/v4l2-common.h > > +++ b/include/media/v4l2-common.h > > @@ -401,4 +401,34 @@ int v4l2_s_parm_cap(struct video_device *vdev, > > ((u64)(a).numerator * (b).denominator OP \ > > (u64)(b).numerator * (a).denominator) > > > > +/* ------------------------------------------------------------------------- */ > > + > > +/* Pixel format and FourCC helpers */ > > + > > +/** > > + * struct v4l2_format_info - information about a V4L2 format > > + * @format: 4CC format identifier (V4L2_PIX_FMT_*) > > + * @num_planes: Number of planes, which includes the alpha plane (1 to 4). > > + * @bpp: Array of per-plane bytes per pixel > > + * @hdiv: Horizontal chroma subsampling factor > > + * @vdiv: Vertical chroma subsampling factor > > + * @non_contiguous: Is it a multiplane non-contiguous variant format? (e.g. NV12M) > > + */ > > +struct v4l2_format_info { > > + u32 format; > > + u8 num_planes; > > + u8 bpp[4]; > > + u8 hdiv; > > + u8 vdiv; > > + u8 non_contiguous; > > +}; > > + > > +const struct v4l2_format_info *v4l2_format_info(u32 format); > > +const char *v4l2_get_fourcc_name(u32 format); > > + > > +int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, > > + int width, int height); > > +int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, int pixelformat, > > + int width, int height); > > + > > #endif /* V4L2_COMMON_H_ */