Commit f44b969a authored by Ezequiel Garcia's avatar Ezequiel Garcia Committed by Mauro Carvalho Chehab
Browse files

media: Introduce helpers to fill pixel format structs



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: default avatarEzequiel Garcia <ezequiel@collabora.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 9fb10beb
Loading
Loading
Loading
Loading
+164 −0
Original line number Diff line number Diff line
@@ -445,3 +445,167 @@ int v4l2_s_parm_cap(struct video_device *vdev,
	return ret;
}
EXPORT_SYMBOL_GPL(v4l2_s_parm_cap);

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);
+33 −0
Original line number Diff line number Diff line
@@ -392,4 +392,37 @@ 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
 * @block_w: Per-plane macroblock pixel width (optional)
 * @block_h: Per-plane macroblock pixel height (optional)
 */
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);

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_ */