[libcamera-devel,v1,2/2] gstreamer: Add multiple colorimetry support
diff mbox series

Message ID 20220807121233.18353-3-rishikeshdonadkar@gmail.com
State Superseded
Headers show
Series
  • Multiple colorimetry support for libcamerasrc.
Related show

Commit Message

Rishikesh Donadkar Aug. 7, 2022, 12:12 p.m. UTC
This patch aims to add support for multiple colorimetry.

Create a fresh new caps which will contain a copy of the structure
with the best resolutions. Normalize the caps using gst_caps_normalize().
This will return caps where the colorimetry list is expanded.
The ncaps will contain as many structures as the number of
colorimetry specified in the gstreamer pipeline.

Iterate over each structure in the ncaps, retrieve the colorimetry string,
convert to colorspace and validate the camera configuration.
Retrieve the colorspace after validation, convert to colorimetry and check
if it is same as the colorimetry requested.

If none of the colorimetry requested is supported by the camera (ie not
the same after validation) then set the stream_cfg to the previous configuration
that was present before trying new colorimetry.
---
 src/gstreamer/gstlibcamera-utils.cpp | 65 ++++++++++++++++++++++++++--
 src/gstreamer/gstlibcamera-utils.h   |  4 +-
 src/gstreamer/gstlibcamerasrc.cpp    |  3 +-
 3 files changed, 66 insertions(+), 6 deletions(-)

Patch
diff mbox series

diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
index 24d8d035..06ab5bf9 100644
--- a/src/gstreamer/gstlibcamera-utils.cpp
+++ b/src/gstreamer/gstlibcamera-utils.cpp
@@ -302,13 +302,47 @@  gst_libcamera_stream_configuration_to_caps(const StreamConfiguration &stream_cfg
 	return caps;
 }
 
+static void
+configure_colorspace_from_caps(StreamConfiguration &stream_cfg,
+			       GstStructure *s)
+{
+	if (gst_structure_has_field(s, "colorimetry")) {
+		const gchar *colorimetry_str = gst_structure_get_string(s, "colorimetry");
+		GstVideoColorimetry colorimetry;
+
+		if (!gst_video_colorimetry_from_string(&colorimetry, colorimetry_str))
+			g_critical("Invalid colorimetry %s", colorimetry_str);
+
+		stream_cfg.colorSpace = colorspace_from_colorimetry(colorimetry);
+		/* Check if colorimetry had any identifiers which did not map */
+		if (colorimetry.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
+		    stream_cfg.colorSpace == ColorSpace::Raw) {
+			GST_ERROR("One or more identifiers could not be mapped for %s colorimetry",
+				  colorimetry_str);
+			stream_cfg.colorSpace = std::nullopt;
+		}
+	}
+}
+
+static gboolean
+check_colorspace(const ColorSpace colorSpace, const gchar *colorimetry_old)
+{
+	GstVideoColorimetry colorimetry = colorimetry_from_colorspace(colorSpace);
+	g_autofree gchar *colorimetry_new = gst_video_colorimetry_to_string(&colorimetry);
+	if (!g_strcmp0(colorimetry_old, colorimetry_new)) {
+		return true;
+	}
+	return false;
+}
+
 void
-gst_libcamera_configure_stream_from_caps(StreamConfiguration &stream_cfg,
+gst_libcamera_configure_stream_from_caps(CameraConfiguration &cam_cfg,
+					 StreamConfiguration &stream_cfg,
 					 GstCaps *caps)
 {
 	GstVideoFormat gst_format = pixel_format_to_gst_format(stream_cfg.pixelFormat);
 	guint i;
-	gint best_fixed = -1, best_in_range = -1;
+	gint best_fixed = -1, best_in_range = -1, colorimetry_index = -1;
 	GstStructure *s;
 
 	/*
@@ -354,10 +388,13 @@  gst_libcamera_configure_stream_from_caps(StreamConfiguration &stream_cfg,
 	}
 
 	/* Prefer reliable fixed value over ranges */
-	if (best_fixed >= 0)
+	if (best_fixed >= 0) {
 		s = gst_caps_get_structure(caps, best_fixed);
-	else
+		colorimetry_index = best_fixed;
+	} else {
 		s = gst_caps_get_structure(caps, best_in_range);
+		colorimetry_index = best_in_range;
+	}
 
 	if (gst_structure_has_name(s, "video/x-raw")) {
 		const gchar *format = gst_video_format_to_string(gst_format);
@@ -380,6 +417,26 @@  gst_libcamera_configure_stream_from_caps(StreamConfiguration &stream_cfg,
 	gst_structure_get_int(s, "height", &height);
 	stream_cfg.size.width = width;
 	stream_cfg.size.height = height;
+
+	/* Create new caps, copy the structure with best resolutions
+	 * and normalize the caps.
+	 */
+	GstCaps *ncaps = gst_caps_copy_nth(caps, colorimetry_index);
+	ncaps = gst_caps_normalize(ncaps);
+
+	/* Configure Colorimetry */
+	StreamConfiguration dup_stream_cfg = stream_cfg;
+	for (i = 0; i < gst_caps_get_size(ncaps); i++) {
+		GstStructure *ns = gst_caps_get_structure(ncaps, i);
+		configure_colorspace_from_caps(stream_cfg, ns);
+		g_autofree const gchar *colorimetry_old = gst_structure_get_string(ns, "colorimetry");
+		if (cam_cfg.validate() != CameraConfiguration::Invalid) {
+			if (check_colorspace(stream_cfg.colorSpace.value(), colorimetry_old))
+				break;
+			else
+				stream_cfg = dup_stream_cfg;
+		}
+	}
 }
 
 #if !GST_CHECK_VERSION(1, 17, 1)
diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h
index 164189a2..90be6abe 100644
--- a/src/gstreamer/gstlibcamera-utils.h
+++ b/src/gstreamer/gstlibcamera-utils.h
@@ -8,6 +8,7 @@ 
 
 #pragma once
 
+#include <libcamera/camera.h>
 #include <libcamera/camera_manager.h>
 #include <libcamera/stream.h>
 
@@ -16,7 +17,8 @@ 
 
 GstCaps *gst_libcamera_stream_formats_to_caps(const libcamera::StreamFormats &formats);
 GstCaps *gst_libcamera_stream_configuration_to_caps(const libcamera::StreamConfiguration &stream_cfg);
-void gst_libcamera_configure_stream_from_caps(libcamera::StreamConfiguration &stream_cfg,
+void gst_libcamera_configure_stream_from_caps(libcamera::CameraConfiguration &cam_cfg,
+					      libcamera::StreamConfiguration &stream_cfg,
 					      GstCaps *caps);
 #if !GST_CHECK_VERSION(1, 17, 1)
 gboolean gst_task_resume(GstTask *task);
diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 16d70fea..3617170e 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -492,6 +492,7 @@  gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,
 	for (gsize i = 0; i < state->srcpads_.size(); i++) {
 		GstPad *srcpad = state->srcpads_[i];
 		StreamConfiguration &stream_cfg = state->config_->at(i);
+		CameraConfiguration &cam_cfg = *(state->config_);
 
 		/* Retrieve the supported caps. */
 		g_autoptr(GstCaps) filter = gst_libcamera_stream_formats_to_caps(stream_cfg.formats());
@@ -503,7 +504,7 @@  gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,
 
 		/* Fixate caps and configure the stream. */
 		caps = gst_caps_make_writable(caps);
-		gst_libcamera_configure_stream_from_caps(stream_cfg, caps);
+		gst_libcamera_configure_stream_from_caps(cam_cfg, stream_cfg, caps);
 	}
 
 	if (flow_ret != GST_FLOW_OK)