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

Nicolas Dufresne nicolas.dufresne at collabora.com
Mon Jul 3 22:34:53 CEST 2023


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 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