[libcamera-devel] gstreamer: Add 'list-cameras' property
diff mbox series

Message ID 20230703195725.193585-1-umang.jain@ideasonboard.com
State Rejected
Headers show
Series
  • [libcamera-devel] gstreamer: Add 'list-cameras' property
Related show

Commit Message

Umang Jain July 3, 2023, 7:57 p.m. UTC
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@ideasonboard.com>
---
 src/gstreamer/gstlibcamerasrc.cpp | 46 +++++++++++++++++++++++++++++++
 test/gstreamer/gstreamer_test.cpp | 30 ++++++++++++++++++++
 test/gstreamer/gstreamer_test.h   |  2 ++
 3 files changed, 78 insertions(+)

Comments

Nicolas Dufresne July 3, 2023, 8:22 p.m. UTC | #1
Hi Ujain,

Le lundi 03 juillet 2023 à 21:57 +0200, Umang Jain a écrit :
> 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@ideasonboard.com>

I'm sorry, but I have to reject this. This is the job of the device provider. If
some information is missing in the provider, just add it there.

NAK

> ---
>  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);
>  };
Kieran Bingham July 3, 2023, 8:27 p.m. UTC | #2
Quoting Umang Jain via libcamera-devel (2023-07-03 20:57:25)
> 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.
> 

Having a way to list the available camera names sounds good - I don't
know if there is a better way to tie this into the gstreamer components.

How would you see this used?

is it something like 
  'gst-launch gstlibcamerasrc list-cameras' ?


Should this list be reported in gst-inspect or such ?

--
Kieran


> Signed-off-by: Umang Jain <umang.jain@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
>
Nicolas Dufresne July 3, 2023, 8:34 p.m. UTC | #3
Le lundi 03 juillet 2023 à 21:27 +0100, Kieran Bingham a écrit :
> Quoting Umang Jain via libcamera-devel (2023-07-03 20:57:25)
> > 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.
> > 
> 
> Having a way to list the available camera names sounds good - I don't
> know if there is a better way to tie this into the gstreamer components.
> 
> How would you see this used?
> 
> is it something like 
>   'gst-launch gstlibcamerasrc list-cameras' ?
> 
> 
> Should this list be reported in gst-inspect or such ?

Listing cameras should go through the device monitor, and implemented by
libcamera already with a device provider. We should add some human readable
names in the properties, here's what it currently look like. Note that the
returned device can be used in replacement for gst_element_factory_make() to get
a preconfigured libcamerasrc for the selected camera.

$> GST_PLUGIN_PATH=build/src/gstreamer/ gst-device-monitor-1.0 Video/Source
Device found:

	name  : \_SB_.PCI0.GP17.XHC0.RHUB.SS04-4.1:1.0-046d:0893
	class : Source/Video
	caps  : video/x-raw, format=NV12, width=640, height=360
	        video/x-raw, format=NV12, width=640, height=480
	        video/x-raw, format=NV12, width=1280, height=720
	        video/x-raw, format=NV12, width=1920, height=1080
	        image/jpeg, width=176, height=144
	        image/jpeg, width=320, height=240
	        image/jpeg, width=424, height=240
	        image/jpeg, width=640, height=360
	        image/jpeg, width=640, height=480
	        image/jpeg, width=848, height=480
	        image/jpeg, width=960, height=540
	        image/jpeg, width=1280, height=720
	        image/jpeg, width=1600, height=896
	        image/jpeg, width=1920, height=1080
	        video/x-raw, format=YUY2, width=176, height=144
	        video/x-raw, format=YUY2, width=320, height=240
	        video/x-raw, format=YUY2, width=424, height=240
	        video/x-raw, format=YUY2, width=640, height=360
	        video/x-raw, format=YUY2, width=640, height=480
	        video/x-raw, format=YUY2, width=848, height=480
	        video/x-raw, format=YUY2, width=960, height=540
	        video/x-raw, format=YUY2, width=1280, height=720
	        video/x-raw, format=YUY2, width=1600, height=896
	        video/x-raw, format=YUY2, width=1920, height=1080
	        video/x-raw, format=YUY2, width=2304, height=1296
	gst-launch-1.0 libcamerasrc camera-
name="\\_SB_.PCI0.GP17.XHC0.RHUB.SS04-4.1:1.0-046d:0893" ! ...


Device found:

	name  : \_SB_.PCI0.GP17.XHC0.RHUB.SS04-4.2.3:1.0-2997:0004
	class : Source/Video
	caps  : video/x-raw, format=I420, width=640, height=480
	        video/x-raw, format=I420, width=720, height=480
	        video/x-raw, format=I420, width=720, height=576
	        video/x-raw, format=I420, width=800, height=600
	        video/x-raw, format=I420, width=1024, height=768
	        video/x-raw, format=I420, width=1280, height=720
	        video/x-raw, format=I420, width=1280, height=768
	        video/x-raw, format=I420, width=1280, height=800
	        video/x-raw, format=I420, width=1360, height=768
	        video/x-raw, format=I420, width=1280, height=960
	        video/x-raw, format=I420, width=1280, height=1024
	        video/x-raw, format=I420, width=1600, height=1200
	        video/x-raw, format=I420, width=1920, height=1080
	        video/x-raw, format=I420, width=1920, height=1200
	        video/x-raw, format=I420, width=2560, height=1440
	        video/x-raw, format=I420, width=3840, height=2160
	        video/x-raw, format=I420, width=4096, height=2160
	        video/x-raw, format=NV12, width=640, height=480
	        video/x-raw, format=NV12, width=720, height=480
	        video/x-raw, format=NV12, width=720, height=576
	        video/x-raw, format=NV12, width=800, height=600
	        video/x-raw, format=NV12, width=1024, height=768
	        video/x-raw, format=NV12, width=1280, height=720
	        video/x-raw, format=NV12, width=1280, height=768
	        video/x-raw, format=NV12, width=1280, height=800
	        video/x-raw, format=NV12, width=1360, height=768
	        video/x-raw, format=NV12, width=1280, height=960
	        video/x-raw, format=NV12, width=1280, height=1024
	        video/x-raw, format=NV12, width=1600, height=1200
	        video/x-raw, format=NV12, width=1920, height=1080
	        video/x-raw, format=NV12, width=1920, height=1200
	        video/x-raw, format=NV12, width=2560, height=1440
	        video/x-raw, format=NV12, width=3840, height=2160
	        video/x-raw, format=NV12, width=4096, height=2160
	        video/x-raw, format=YV12, width=640, height=480
	        video/x-raw, format=YV12, width=720, height=480
	        video/x-raw, format=YV12, width=720, height=576
	        video/x-raw, format=YV12, width=800, height=600
	        video/x-raw, format=YV12, width=1024, height=768
	        video/x-raw, format=YV12, width=1280, height=720
	        video/x-raw, format=YV12, width=1280, height=768
	        video/x-raw, format=YV12, width=1280, height=800
	        video/x-raw, format=YV12, width=1360, height=768
	        video/x-raw, format=YV12, width=1280, height=960
	        video/x-raw, format=YV12, width=1280, height=1024
	        video/x-raw, format=YV12, width=1600, height=1200
	        video/x-raw, format=YV12, width=1920, height=1080
	        video/x-raw, format=YV12, width=1920, height=1200
	        video/x-raw, format=YV12, width=2560, height=1440
	        video/x-raw, format=YV12, width=3840, height=2160
	        video/x-raw, format=YV12, width=4096, height=2160
	        video/x-raw, format=YUY2, width=640, height=480
	        video/x-raw, format=YUY2, width=720, height=480
	        video/x-raw, format=YUY2, width=720, height=576
	        video/x-raw, format=YUY2, width=800, height=600
	        video/x-raw, format=YUY2, width=1024, height=768
	        video/x-raw, format=YUY2, width=1280, height=720
	        video/x-raw, format=YUY2, width=1280, height=768
	        video/x-raw, format=YUY2, width=1280, height=800
	        video/x-raw, format=YUY2, width=1360, height=768
	        video/x-raw, format=YUY2, width=1280, height=960
	        video/x-raw, format=YUY2, width=1280, height=1024
	        video/x-raw, format=YUY2, width=1400, height=1050
	        video/x-raw, format=YUY2, width=1680, height=1050
	        video/x-raw, format=YUY2, width=1600, height=1200
	        video/x-raw, format=YUY2, width=1920, height=1080
	        video/x-raw, format=YUY2, width=1920, height=1200
	gst-launch-1.0 libcamerasrc camera-
name="\\_SB_.PCI0.GP17.XHC0.RHUB.SS04-4.2.3:1.0-2997:0004" ! ...


Device found:

	name  : \_SB_.PCI0.GP17.XHC1.RHUB.PRT2.PR21-2.1:1.0-04ca:7070
	class : Source/Video
	caps  : image/jpeg, width=320, height=180
	        image/jpeg, width=320, height=240
	        image/jpeg, width=352, height=288
	        image/jpeg, width=424, height=240
	        image/jpeg, width=640, height=360
	        image/jpeg, width=640, height=480
	        image/jpeg, width=848, height=480
	        image/jpeg, width=960, height=540
	        image/jpeg, width=1280, height=720
	        video/x-raw, format=YUY2, width=320, height=180
	        video/x-raw, format=YUY2, width=320, height=240
	        video/x-raw, format=YUY2, width=352, height=288
	        video/x-raw, format=YUY2, width=424, height=240
	        video/x-raw, format=YUY2, width=640, height=360
	        video/x-raw, format=YUY2, width=640, height=480
	        video/x-raw, format=YUY2, width=848, height=480
	        video/x-raw, format=YUY2, width=960, height=540
	        video/x-raw, format=YUY2, width=1280, height=720
	gst-launch-1.0 libcamerasrc camera-
name="\\_SB_.PCI0.GP17.XHC1.RHUB.PRT2.PR21-2.1:1.0-04ca:7070" ! ...

> 
> --
> Kieran
> 
> 
> > Signed-off-by: Umang Jain <umang.jain@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
> >
Umang Jain July 4, 2023, 6:31 a.m. UTC | #4
Hi Nicolas

On 7/3/23 10:22 PM, Nicolas Dufresne wrote:
> Hi Ujain,
>
> Le lundi 03 juillet 2023 à 21:57 +0200, Umang Jain a écrit :
>> 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@ideasonboard.com>
> I'm sorry, but I have to reject this. This is the job of the device provider. If
> some information is missing in the provider, just add it there.

Makes sense. I'll try writing a test to enumerate cameras on the device 
provider and using a pre-configured libcamerasrc.

For the missing information, does the camera-supported controls be a 
good candidate to get added to device-provider as well?  I see we are 
already enumerating streams in there but I understand those are part of 
the capabilities.
>
> NAK
>
>> ---
>>   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);
>>   };
Nicolas Dufresne July 4, 2023, 3:14 p.m. UTC | #5
Le mardi 04 juillet 2023 à 08:31 +0200, Umang Jain a écrit :
> Hi Nicolas
> 
> On 7/3/23 10:22 PM, Nicolas Dufresne wrote:
> > Hi Ujain,
> > 
> > Le lundi 03 juillet 2023 à 21:57 +0200, Umang Jain a écrit :
> > > 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@ideasonboard.com>
> > I'm sorry, but I have to reject this. This is the job of the device provider. If
> > some information is missing in the provider, just add it there.
> 
> Makes sense. I'll try writing a test to enumerate cameras on the device 
> provider and using a pre-configured libcamerasrc.
> 
> For the missing information, does the camera-supported controls be a 
> good candidate to get added to device-provider as well?  I see we are 
> already enumerating streams in there but I understand those are part of 
> the capabilities.

As discussed on IRC, I'd aim maybe for a set of supported features. We can
probably simply use G_TYPE_FLAGS property (shared on both the provided and the
libcamerasrc). Each flag would state which features are to be expected, and the
doc will say for each flags which controls are going to exist, or which "mode"
if a feature (like auto-focus) can support multiple mode which imply different
set of controls.

The idea is that libcamera controls don't match 1:1 to features, but some
controls works in tandem, e.g. if you didn't select a specific "mode" a specific
control may have no effect.

> > 
> > NAK
> > 
> > > ---
> > >   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);
> > >   };
>

Patch
diff mbox series

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);
 };