From c163250f0d4d661904717504243cf0a6dcbf28d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Zanelli?= Date: Thu, 1 Oct 2015 13:41:23 +0200 Subject: [PATCH] v4l2object: probe all colorspace supported by device A device can support more than one colorspace for a given image dimension and pixel format. So we have to probe all the supported colorspace and not only rely on the default one. Otherwise we could end up with negotiation failure if the caps colorimetry field don't match the v4l2 device default one even if the v4l2 could support such colorimetry. This patch enable probing if colorspace for both capture and output device. It really makes sense for output device since the colorspace shall be set by the application and a little less for capture device which, at the moment, shall provide the colorspace; ie: the v4l2 specification seems to not take into account the fact that a capture device could do colorspace conversion. As a side effet, probing takes some times and so sligthly delay v4l2 initialization. Note that this patch only probe colorspace and not all colorspace, matrix, transfer and range combination to avoid taking too much time, especially with low-speed devices as full probing do 1782 ioctl. https://bugzilla.gnome.org/show_bug.cgi?id=755937 --- sys/v4l2/gstv4l2object.c | 95 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index 21c16fae16..3622553f35 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -2137,13 +2137,43 @@ gst_v4l2_object_add_interlace_mode (GstV4l2Object * v4l2object, return; } +static void +gst_v4l2_object_fill_colorimetry_list (GValue * list, + GstVideoColorimetry * cinfo) +{ + GValue colorimetry = G_VALUE_INIT; + guint size; + guint i; + gboolean found = FALSE; + + g_value_init (&colorimetry, G_TYPE_STRING); + g_value_take_string (&colorimetry, gst_video_colorimetry_to_string (cinfo)); + + /* only insert if no duplicate */ + size = gst_value_list_get_size (list); + for (i = 0; i < size; i++) { + const GValue *tmp; + + tmp = gst_value_list_get_value (list, i); + if (gst_value_compare (&colorimetry, tmp) == GST_VALUE_EQUAL) { + found = TRUE; + break; + } + } + + if (!found) + gst_value_list_append_and_take_value (list, &colorimetry); +} + static void gst_v4l2_object_add_colorspace (GstV4l2Object * v4l2object, GstStructure * s, guint32 width, guint32 height, guint32 pixelformat) { struct v4l2_format fmt; - GValue colorimetry = G_VALUE_INIT; + GValue list = G_VALUE_INIT; GstVideoColorimetry cinfo; + enum v4l2_colorspace req_cspace; + gboolean is_rgb = gst_v4l2_object_v4l2fourcc_is_rgb (pixelformat); memset (&fmt, 0, sizeof (fmt)); fmt.type = v4l2object->type; @@ -2151,12 +2181,15 @@ gst_v4l2_object_add_colorspace (GstV4l2Object * v4l2object, GstStructure * s, fmt.fmt.pix.height = height; fmt.fmt.pix.pixelformat = pixelformat; + g_value_init (&list, GST_TYPE_LIST); + + /* step 1: get device default colorspace and insert it first as + * it should be the preferred one */ if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0) { enum v4l2_colorspace colorspace; enum v4l2_quantization range; enum v4l2_ycbcr_encoding matrix; enum v4l2_xfer_func transfer; - gboolean is_rgb = gst_v4l2_object_v4l2fourcc_is_rgb (pixelformat); if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) { colorspace = fmt.fmt.pix_mp.colorspace; @@ -2178,12 +2211,62 @@ gst_v4l2_object_add_colorspace (GstV4l2Object * v4l2object, GstStructure * s, if (is_rgb) cinfo.matrix = GST_VIDEO_COLOR_MATRIX_RGB; - g_value_init (&colorimetry, G_TYPE_STRING); - g_value_take_string (&colorimetry, - gst_video_colorimetry_to_string (&cinfo)); - gst_structure_take_value (s, "colorimetry", &colorimetry); + gst_v4l2_object_fill_colorimetry_list (&list, &cinfo); } } + + /* step 2: probe all colorspace other than default + * We don't probe all colorspace, range, matrix and transfer combination to + * avoid ioctl flooding which could greatly increase initialization time + * with low-speed devices (UVC...) */ + for (req_cspace = V4L2_COLORSPACE_SMPTE170M; + req_cspace <= V4L2_COLORSPACE_RAW; req_cspace++) { + /* V4L2_COLORSPACE_BT878 is deprecated and shall not be used, so skip */ + if (req_cspace == V4L2_COLORSPACE_BT878) + continue; + + if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) + fmt.fmt.pix_mp.colorspace = req_cspace; + else + fmt.fmt.pix.colorspace = req_cspace; + + if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0) { + enum v4l2_colorspace colorspace; + enum v4l2_quantization range; + enum v4l2_ycbcr_encoding matrix; + enum v4l2_xfer_func transfer; + + if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) { + colorspace = fmt.fmt.pix_mp.colorspace; + range = fmt.fmt.pix_mp.quantization; + matrix = fmt.fmt.pix_mp.ycbcr_enc; + transfer = fmt.fmt.pix_mp.xfer_func; + } else { + colorspace = fmt.fmt.pix.colorspace; + range = fmt.fmt.pix.quantization; + matrix = fmt.fmt.pix.ycbcr_enc; + transfer = fmt.fmt.pix.xfer_func; + } + + if (colorspace == req_cspace) { + if (gst_v4l2_object_get_colorspace (colorspace, range, matrix, transfer, + is_rgb, &cinfo)) { + /* Set identity matrix for R'G'B' formats to avoid creating + * confusion. This though is cosmetic as it's now properly ignored by + * the video info API and videoconvert. */ + if (is_rgb) + cinfo.matrix = GST_VIDEO_COLOR_MATRIX_RGB; + + gst_v4l2_object_fill_colorimetry_list (&list, &cinfo); + } + } + } + } + + if (gst_value_list_get_size (&list) > 0) + gst_structure_take_value (s, "colorimetry", &list); + + return; } /* The frame interval enumeration code first appeared in Linux 2.6.19. */