On 3/4/19 8:25 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 <[email protected]>
> ---
> drivers/media/v4l2-core/v4l2-common.c | 186 ++++++++++++++++++++++++++
> include/media/v4l2-common.h | 32 +++++
> 2 files changed, 218 insertions(+)
>
> diff --git a/drivers/media/v4l2-core/v4l2-common.c
> b/drivers/media/v4l2-core/v4l2-common.c
> index 663730f088cd..11a16bb3efda 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>
> @@ -445,3 +446,188 @@ 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);
This function isn't re-entrant, but it should be. Multiple threads may be
calling it at the same time.
It is probably best to pass the buffer pointer as an argument.
I would also prefer to split this patch into two: the first adding
v4l2_format_info, the second adding v4l2_get_fourcc_name. This in case
that the v4l2_get_fourcc_name() function needs more work.
Regards,
Hans
> +
> +const struct v4l2_format_info *v4l2_format_info(u32 format)
> +{
> + static const struct v4l2_format_info formats[] = {
> + /* RGB formats */
> + { .format = V4L2_PIX_FMT_BGR24, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_RGB24, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_HSV24, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_BGR32, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_XBGR32, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_RGB32, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_XRGB32, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_HSV32, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_ARGB32, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_ABGR32, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_GREY, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> +
> + /* YUV packed formats */
> + { .format = V4L2_PIX_FMT_YUYV, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_YVYU, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_UYVY, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_VYUY, .mem_planes = 1, .comp_planes
> = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
> +
> + /* YUV planar formats */
> + { .format = V4L2_PIX_FMT_NV12, .mem_planes = 1, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
> + { .format = V4L2_PIX_FMT_NV21, .mem_planes = 1, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
> + { .format = V4L2_PIX_FMT_NV16, .mem_planes = 1, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_NV61, .mem_planes = 1, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_NV24, .mem_planes = 1, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_NV42, .mem_planes = 1, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
> +
> + { .format = V4L2_PIX_FMT_YUV410, .mem_planes = 1, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
> + { .format = V4L2_PIX_FMT_YVU410, .mem_planes = 1, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
> + { .format = V4L2_PIX_FMT_YUV411P, .mem_planes = 1, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_YUV420, .mem_planes = 1, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
> + { .format = V4L2_PIX_FMT_YVU420, .mem_planes = 1, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
> + { .format = V4L2_PIX_FMT_YUV422P, .mem_planes = 1, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 },
> +
> + /* YUV planar formats, non contiguous variant */
> + { .format = V4L2_PIX_FMT_YUV420M, .mem_planes = 3, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
> + { .format = V4L2_PIX_FMT_YVU420M, .mem_planes = 3, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
> + { .format = V4L2_PIX_FMT_YUV422M, .mem_planes = 3, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_YVU422M, .mem_planes = 3, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_YUV444M, .mem_planes = 3, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_YVU444M, .mem_planes = 3, .comp_planes
> = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 },
> +
> + { .format = V4L2_PIX_FMT_NV12M, .mem_planes = 2, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
> + { .format = V4L2_PIX_FMT_NV21M, .mem_planes = 2, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
> + { .format = V4L2_PIX_FMT_NV16M, .mem_planes = 2, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
> + { .format = V4L2_PIX_FMT_NV61M, .mem_planes = 2, .comp_planes
> = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 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);
> +
> +static inline unsigned int v4l2_format_block_width(const struct
> v4l2_format_info *info, int plane)
> +{
> + if (!info->block_w[plane])
> + return 1;
> + return info->block_w[plane];
> +}
> +
> +static inline unsigned int v4l2_format_block_height(const struct
> v4l2_format_info *info, int plane)
> +{
> + if (!info->block_h[plane])
> + return 1;
> + return info->block_h[plane];
> +}
> +
> +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;
> + pixfmt->num_planes = info->mem_planes;
> +
> + if (info->mem_planes == 1) {
> + plane = &pixfmt->plane_fmt[0];
> + plane->bytesperline = ALIGN(width,
> v4l2_format_block_width(info, 0)) * info->bpp[0];
> + plane->sizeimage = 0;
> +
> + for (i = 0; i < info->comp_planes; i++) {
> + unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
> + unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
> + unsigned int aligned_width;
> + unsigned int aligned_height;
> +
> + aligned_width = ALIGN(width,
> v4l2_format_block_width(info, i));
> + aligned_height = ALIGN(height,
> v4l2_format_block_height(info, i));
> +
> + plane->sizeimage += info->bpp[i] *
> + DIV_ROUND_UP(aligned_width, hdiv) *
> + DIV_ROUND_UP(aligned_height, vdiv);
> + }
> + } else {
> + for (i = 0; i < info->comp_planes; i++) {
> + unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
> + unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
> + unsigned int aligned_width;
> + unsigned int aligned_height;
> +
> + aligned_width = ALIGN(width,
> v4l2_format_block_width(info, i));
> + aligned_height = ALIGN(height,
> v4l2_format_block_height(info, i));
> +
> + plane = &pixfmt->plane_fmt[i];
> + plane->bytesperline =
> + info->bpp[i] * DIV_ROUND_UP(aligned_width,
> hdiv);
> + plane->sizeimage =
> + plane->bytesperline *
> DIV_ROUND_UP(aligned_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;
> +
> + /* Single planar API cannot be used for multi plane formats. */
> + if (info->mem_planes > 1)
> + return -EINVAL;
> +
> + pixfmt->width = width;
> + pixfmt->height = height;
> + pixfmt->pixelformat = pixelformat;
> + pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) *
> info->bpp[0];
> + pixfmt->sizeimage = 0;
> +
> + for (i = 0; i < info->comp_planes; i++) {
> + unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
> + unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
> + unsigned int aligned_width;
> + unsigned int aligned_height;
> +
> + aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
> + aligned_height = ALIGN(height, v4l2_format_block_height(info,
> i));
> +
> + pixfmt->sizeimage += info->bpp[i] *
> + DIV_ROUND_UP(aligned_width, hdiv) *
> + DIV_ROUND_UP(aligned_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 2b93cb281fa5..937b74a946cd 100644
> --- a/include/media/v4l2-common.h
> +++ b/include/media/v4l2-common.h
> @@ -392,4 +392,36 @@ 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_*)
> + * @mem_planes: Number of memory planes, which includes the alpha plane (1
> to 4).
> + * @comp_planes: Number of component 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
> + */
> +struct v4l2_format_info {
> + u32 format;
> + u8 mem_planes;
> + u8 comp_planes;
> + u8 bpp[4];
> + u8 hdiv;
> + u8 vdiv;
> + u8 block_w[4];
> + u8 block_h[4];
> +};
> +
> +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_ */
>