mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	spa: v4l2: add colorimetry support
This commit is contained in:
		
							parent
							
								
									6294cbeb68
								
							
						
					
					
						commit
						41b831d0f8
					
				
					 1 changed files with 190 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
 | 
			
		||||
/* SPDX-License-Identifier: MIT */
 | 
			
		||||
 | 
			
		||||
#include <linux/videodev2.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -494,6 +495,162 @@ filter_framerate(struct v4l2_frmivalenum *frmival,
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct spa_video_colorimetry v4l2_colorimetry_map[] = {
 | 
			
		||||
	{ /* V4L2_COLORSPACE_DEFAULT */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_UNKNOWN,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_SMPTE170M */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_16_235,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_BT601,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_SMPTE170M,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_SMPTE240M */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_16_235,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_SMPTE240M,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_SMPTE240M,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_SMPTE240M,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_REC709 */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_16_235,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_BT709,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_BT709,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_BT709,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_BT878 (deprecated) */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_UNKNOWN,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_470_SYSTEM_M */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_16_235,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_BT709,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_BT470M,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_470_SYSTEM_BG */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_16_235,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_BT709,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_BT470BG,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_JPEG */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_0_255,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_SRGB,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_BT709,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_SRGB */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_16_235,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_SRGB,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_BT709,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_OPRGB */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_16_235,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_ADOBERGB,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_ADOBERGB,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_BT2020 */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_16_235,
 | 
			
		||||
		.matrix = SPA_VIDEO_COLOR_MATRIX_BT2020,
 | 
			
		||||
		.transfer = SPA_VIDEO_TRANSFER_BT2020_12,
 | 
			
		||||
		.primaries = SPA_VIDEO_COLOR_PRIMARIES_BT2020,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* V4L2_COLORSPACE_RAW */
 | 
			
		||||
		.range = SPA_VIDEO_COLOR_RANGE_UNKNOWN,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum spa_video_color_range v4l2_color_range_map[] = {
 | 
			
		||||
	SPA_VIDEO_COLOR_RANGE_UNKNOWN,
 | 
			
		||||
	SPA_VIDEO_COLOR_RANGE_0_255,
 | 
			
		||||
	SPA_VIDEO_COLOR_RANGE_16_235
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum spa_video_color_matrix v4l2_color_matrix_map[] = {
 | 
			
		||||
	/* V4L2_YCBCR_ENC_DEFAULT */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_UNKNOWN,
 | 
			
		||||
	/* V4L2_YCBCR_ENC_601 */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
	/* V4L2_YCBCR_ENC_709 */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_BT709,
 | 
			
		||||
	/* V4L2_YCBCR_ENC_XV601 */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
	/* V4L2_YCBCR_ENC_XV709 */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_BT709,
 | 
			
		||||
	/* V4L2_YCBCR_ENC_SYCC */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_BT601,
 | 
			
		||||
	/* V4L2_YCBCR_ENC_BT2020 */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_BT2020,
 | 
			
		||||
	/* V4L2_YCBCR_ENC_BT2020_CONST_LUM */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_BT2020,
 | 
			
		||||
	/* V4L2_YCBCR_ENC_SMPTE240M */
 | 
			
		||||
	SPA_VIDEO_COLOR_MATRIX_SMPTE240M
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum spa_video_transfer_function v4l2_transfer_function_map[] = {
 | 
			
		||||
	/* V4L2_XFER_FUNC_DEFAULT */
 | 
			
		||||
	SPA_VIDEO_TRANSFER_UNKNOWN,
 | 
			
		||||
	/* V4L2_XFER_FUNC_709 */
 | 
			
		||||
	SPA_VIDEO_TRANSFER_BT709,
 | 
			
		||||
	/* V4L2_XFER_FUNC_SRGB */
 | 
			
		||||
	SPA_VIDEO_TRANSFER_SRGB,
 | 
			
		||||
	/* V4L2_XFER_FUNC_OPRGB */
 | 
			
		||||
	SPA_VIDEO_TRANSFER_ADOBERGB,
 | 
			
		||||
	/* V4L2_XFER_FUNC_SMPTE240M */
 | 
			
		||||
	SPA_VIDEO_TRANSFER_SMPTE240M,
 | 
			
		||||
	/* V4L2_XFER_FUNC_NONE */
 | 
			
		||||
	SPA_VIDEO_TRANSFER_GAMMA10,
 | 
			
		||||
	/* V4L2_XFER_FUNC_DCI_P3 */
 | 
			
		||||
	SPA_VIDEO_TRANSFER_UNKNOWN,
 | 
			
		||||
	/* V4L2_XFER_FUNC_SMPTE2084 */
 | 
			
		||||
	SPA_VIDEO_TRANSFER_SMPTE2084
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
parse_colorimetry(struct impl *this, const struct v4l2_pix_format *pix, bool is_rgb,
 | 
			
		||||
		  struct spa_video_colorimetry *colorimetry)
 | 
			
		||||
{
 | 
			
		||||
	struct spa_video_colorimetry c = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (pix->colorspace < V4L2_COLORSPACE_RAW)
 | 
			
		||||
		c = v4l2_colorimetry_map[pix->colorspace];
 | 
			
		||||
 | 
			
		||||
	if (c.range == SPA_VIDEO_COLOR_RANGE_UNKNOWN)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	switch (pix->quantization) {
 | 
			
		||||
	case V4L2_QUANTIZATION_FULL_RANGE:
 | 
			
		||||
	case V4L2_QUANTIZATION_LIM_RANGE:
 | 
			
		||||
		c.range = v4l2_color_range_map[pix->quantization];
 | 
			
		||||
		break;
 | 
			
		||||
	case V4L2_QUANTIZATION_DEFAULT:
 | 
			
		||||
		if (is_rgb)
 | 
			
		||||
			c.range = SPA_VIDEO_COLOR_RANGE_0_255;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		spa_log_warn(this->log, "Unknown enum v4l2_quantization value %d",
 | 
			
		||||
				pix->quantization);
 | 
			
		||||
		c.range = SPA_VIDEO_COLOR_RANGE_UNKNOWN;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pix->ycbcr_enc >= V4L2_YCBCR_ENC_SMPTE240M)
 | 
			
		||||
		spa_log_warn(this->log, "Unknown enum v4l2_ycbcr_encoding value %d",
 | 
			
		||||
				pix->ycbcr_enc);
 | 
			
		||||
	else if (pix->ycbcr_enc > 0)
 | 
			
		||||
		c.matrix = v4l2_color_matrix_map[pix->ycbcr_enc];
 | 
			
		||||
 | 
			
		||||
	if (pix->xfer_func >= V4L2_XFER_FUNC_SMPTE2084)
 | 
			
		||||
		spa_log_warn(this->log, "Unknown enum v4l2_xfer_func value %d",
 | 
			
		||||
				pix->xfer_func);
 | 
			
		||||
	else if (pix->xfer_func > 0)
 | 
			
		||||
		c.transfer = v4l2_transfer_function_map[pix->xfer_func];
 | 
			
		||||
 | 
			
		||||
	*colorimetry = c;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define FOURCC_ARGS(f) (f)&0x7f,((f)>>8)&0x7f,((f)>>16)&0x7f,((f)>>24)&0x7f
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +669,8 @@ spa_v4l2_enum_format(struct impl *this, int seq,
 | 
			
		|||
	struct spa_pod_builder_state state;
 | 
			
		||||
	struct spa_pod_frame f[2];
 | 
			
		||||
	struct spa_result_node_params result;
 | 
			
		||||
	uint32_t count = 0;
 | 
			
		||||
	struct v4l2_format fmt;
 | 
			
		||||
	uint32_t count = 0, try_width = 0, try_height = 0;
 | 
			
		||||
	bool with_modifier;
 | 
			
		||||
 | 
			
		||||
	if ((res = spa_v4l2_open(dev, this->props.device)) < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -742,6 +900,8 @@ do_frmsize_filter:
 | 
			
		|||
		spa_pod_builder_rectangle(&b.b,
 | 
			
		||||
				port->frmsize.discrete.width,
 | 
			
		||||
				port->frmsize.discrete.height);
 | 
			
		||||
		try_width = port->frmsize.discrete.width;
 | 
			
		||||
		try_height = port->frmsize.discrete.height;
 | 
			
		||||
	} else if (port->frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS ||
 | 
			
		||||
		   port->frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
 | 
			
		||||
		spa_pod_builder_push_choice(&b.b, &f[1], SPA_CHOICE_None, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -766,6 +926,35 @@ do_frmsize_filter:
 | 
			
		|||
					port->frmsize.stepwise.max_height);
 | 
			
		||||
		}
 | 
			
		||||
		spa_pod_builder_pop(&b.b, &f[1]);
 | 
			
		||||
		try_width = port->frmsize.stepwise.min_width;
 | 
			
		||||
		try_height = port->frmsize.stepwise.min_height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spa_zero(fmt);
 | 
			
		||||
	fmt.type = port->fmtdesc.type;
 | 
			
		||||
	fmt.fmt.pix.pixelformat = info->fourcc;
 | 
			
		||||
	fmt.fmt.pix.field = V4L2_FIELD_ANY;
 | 
			
		||||
	fmt.fmt.pix.width = try_width;
 | 
			
		||||
	fmt.fmt.pix.height = try_height;
 | 
			
		||||
 | 
			
		||||
	if ((res = xioctl(dev->fd, VIDIOC_TRY_FMT, &fmt)) < 0) {
 | 
			
		||||
		spa_log_debug(this->log, "'%s' VIDIOC_TRY_FMT %08x: %m",
 | 
			
		||||
				this->props.device, info->fourcc);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct spa_video_colorimetry colorimetry;
 | 
			
		||||
		bool is_rgb = spa_format_video_is_rgb(info->format);
 | 
			
		||||
 | 
			
		||||
		if (parse_colorimetry(this, &fmt.fmt.pix, is_rgb, &colorimetry)) {
 | 
			
		||||
			spa_pod_builder_add(&b.b,
 | 
			
		||||
				SPA_FORMAT_VIDEO_colorRange,
 | 
			
		||||
				SPA_POD_Id(colorimetry.range),
 | 
			
		||||
				SPA_FORMAT_VIDEO_colorMatrix,
 | 
			
		||||
				SPA_POD_Id(colorimetry.matrix),
 | 
			
		||||
				SPA_FORMAT_VIDEO_transferFunction,
 | 
			
		||||
				SPA_POD_Id(colorimetry.transfer),
 | 
			
		||||
				SPA_FORMAT_VIDEO_colorPrimaries,
 | 
			
		||||
				SPA_POD_Id(colorimetry.primaries), 0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spa_pod_builder_prop(&b.b, SPA_FORMAT_VIDEO_framerate, 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue