[libcamera-devel] [PATCH] gstreamer: Add 'list-cameras' property

Umang Jain umang.jain at ideasonboard.com
Mon Jul 3 21:57:25 CEST 2023


Add a new property called 'list-cameras' on libcamerasrc to enumerate
and expose the cameras present on the system. The enumeration will help
appplications using libcamerasrc to know and set the 'camera-name'
property in order to use that camera with libcamerasrc.

Signed-off-by: Umang Jain <umang.jain at ideasonboard.com>
---
 src/gstreamer/gstlibcamerasrc.cpp | 46 +++++++++++++++++++++++++++++++
 test/gstreamer/gstreamer_test.cpp | 30 ++++++++++++++++++++
 test/gstreamer/gstreamer_test.h   |  2 ++
 3 files changed, 78 insertions(+)

diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 1f10136b..f337728a 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -152,6 +152,7 @@ struct _GstLibcameraSrc {
 enum {
 	PROP_0,
 	PROP_CAMERA_NAME,
+	PROP_LIST_CAMERAS,
 	PROP_AUTO_FOCUS_MODE,
 };
 
@@ -666,6 +667,39 @@ gst_libcamera_src_close(GstLibcameraSrc *self)
 	state->cm_.reset();
 }
 
+static gboolean
+gst_libcamera_src_set_cameras_list(GstLibcameraSrc *self, GValue *value)
+{
+	std::shared_ptr<CameraManager> cm;
+	GValue val = G_VALUE_INIT;
+	gint ret;
+
+	g_value_init(&val, G_TYPE_STRING);
+	g_value_reset(value);
+
+	cm = gst_libcamera_get_camera_manager(ret);
+	if (ret) {
+		GST_ELEMENT_ERROR(self, LIBRARY, INIT,
+				  ("Failed listing cameras."),
+				  ("libcamera::CameraMananger::start() failed: %s", g_strerror(-ret)));
+		return false;
+	}
+
+	if (cm->cameras().empty()) {
+		GST_ELEMENT_ERROR(self, RESOURCE, NOT_FOUND,
+				  ("Could not find any supported camera on this system."),
+				  ("libcamera::CameraMananger::cameras() is empty"));
+		return false;
+	}
+
+	for (const std::shared_ptr<Camera> &cam : cm->cameras()) {
+		g_value_set_string(&val, cam->id().c_str());
+		gst_value_array_append_value(value, &val);
+	}
+
+	return true;
+}
+
 static void
 gst_libcamera_src_set_property(GObject *object, guint prop_id,
 			       const GValue *value, GParamSpec *pspec)
@@ -699,6 +733,9 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,
 	case PROP_CAMERA_NAME:
 		g_value_set_string(value, self->camera_name);
 		break;
+	case PROP_LIST_CAMERAS:
+		gst_libcamera_src_set_cameras_list(self, value);
+		break;
 	case PROP_AUTO_FOCUS_MODE: {
 		auto auto_focus_mode = self->controls->get(controls::AfMode).value_or(controls::AfModeManual);
 		g_value_set_enum(value, auto_focus_mode);
@@ -879,6 +916,15 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
 							     | G_PARAM_STATIC_STRINGS));
 	g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
 
+	spec = gst_param_spec_array("list-cameras", "Cameras list",
+				    "Retrieve list of all cameras",
+				    g_param_spec_string("camera-name", "Camera name",
+							"Name of the camera", nullptr,
+							(GParamFlags)(G_PARAM_READABLE
+								      | G_PARAM_STATIC_STRINGS)),
+				    (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+	g_object_class_install_property(object_class, PROP_LIST_CAMERAS, spec);
+
 	spec = g_param_spec_enum("auto-focus-mode",
 				 "Set auto-focus mode",
 				 "Available options: AfModeManual, "
diff --git a/test/gstreamer/gstreamer_test.cpp b/test/gstreamer/gstreamer_test.cpp
index 6ad0c15c..7f3ccd2b 100644
--- a/test/gstreamer/gstreamer_test.cpp
+++ b/test/gstreamer/gstreamer_test.cpp
@@ -97,6 +97,9 @@ bool GstreamerTest::checkMinCameraStreamsAndSetCameraName(unsigned int numStream
 		break;
 	}
 
+	for (auto &camera : cm.cameras())
+		cameraNames_.push_back(strdup(camera->id().c_str()));
+
 	cm.stop();
 
 	return cameraFound;
@@ -112,6 +115,9 @@ GstreamerTest::~GstreamerTest()
 
 int GstreamerTest::createPipeline()
 {
+	GValue cameras_list_array = G_VALUE_INIT;
+	guint index, i;
+
 	libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera");
 	pipeline_ = gst_pipeline_new("test-pipeline");
 
@@ -125,6 +131,30 @@ int GstreamerTest::createPipeline()
 	g_object_set(libcameraSrc_, "camera-name", cameraName_.c_str(), NULL);
 	g_object_ref_sink(libcameraSrc_);
 
+	g_value_init(&cameras_list_array, GST_TYPE_ARRAY);
+	g_object_get_property(G_OBJECT(libcameraSrc_), "list-cameras", &cameras_list_array);
+	if (gst_value_array_get_size(&cameras_list_array) != cameraNames_.size()) {
+		g_printerr("libcamerasrc 'list-cameras' properties count does not match.\n");
+		return TestFail;
+	}
+
+	for (index = 0; index < cameraNames_.size(); index++) {
+		bool matched = false;
+
+		for (i = 0; i < gst_value_array_get_size(&cameras_list_array); i++) {
+			const char *cam = g_value_get_string(gst_value_array_get_value(&cameras_list_array, i));
+			if (strcmp(cam, cameraNames_[index]) == 0) {
+				matched = true;
+				break;
+			}
+		}
+
+		if (!matched) {
+			g_printerr("Camera %s not found in 'list-cameras' property.\n", cameraNames_[index]);
+			return TestFail;
+		}
+	}
+
 	return TestPass;
 }
 
diff --git a/test/gstreamer/gstreamer_test.h b/test/gstreamer/gstreamer_test.h
index aa2261e2..5d61bc2a 100644
--- a/test/gstreamer/gstreamer_test.h
+++ b/test/gstreamer/gstreamer_test.h
@@ -9,6 +9,7 @@
 
 #include <iostream>
 #include <unistd.h>
+#include <vector>
 
 #include <gst/gst.h>
 
@@ -29,6 +30,7 @@ protected:
 	GstElement *libcameraSrc_;
 	int status_;
 
+	std::vector<const char *> cameraNames_;
 private:
 	bool checkMinCameraStreamsAndSetCameraName(unsigned int numStreams);
 };
-- 
2.39.1



More information about the libcamera-devel mailing list