[libcamera-devel] [PATCH v2 03/27] gst: Add initial device provider

Laurent Pinchart laurent.pinchart at ideasonboard.com
Sat Feb 29 14:30:46 CET 2020


Hi Nicolas,

Thank you for the patch.

On Thu, Feb 27, 2020 at 03:03:43PM -0500, Nicolas Dufresne wrote:
> This feature is used with GstDeviceMonitor in order to enumerate
> and monitor devices to be used with the source element. The resulting
> GstDevice implementation is also used by application to abstract the
> configuration of the source element.
> 
> Implementation notes:
>   - libcamera does not support polling yet
>   - The device ID isn't unique in libcamera yet
>   - The "name" property does not yet exist in libcamerasrc yet
> 
> Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> ---
>  src/gstreamer/gstlibcamera.c           |  10 +-
>  src/gstreamer/gstlibcameraprovider.cpp | 235 +++++++++++++++++++++++++
>  src/gstreamer/gstlibcameraprovider.h   |  23 +++
>  src/gstreamer/meson.build              |   1 +
>  4 files changed, 267 insertions(+), 2 deletions(-)
>  create mode 100644 src/gstreamer/gstlibcameraprovider.cpp
>  create mode 100644 src/gstreamer/gstlibcameraprovider.h
> 
> diff --git a/src/gstreamer/gstlibcamera.c b/src/gstreamer/gstlibcamera.c
> index 7dd94ca..81c7bb1 100644
> --- a/src/gstreamer/gstlibcamera.c
> +++ b/src/gstreamer/gstlibcamera.c
> @@ -6,13 +6,19 @@
>   * gstlibcamera.c - GStreamer plugin
>   */
>  
> +#include "gstlibcameraprovider.h"
>  #include "gstlibcamerasrc.h"
>  
>  static gboolean
>  plugin_init(GstPlugin *plugin)
>  {
> -	return gst_element_register(plugin, "libcamerasrc", GST_RANK_PRIMARY,
> -				    GST_TYPE_LIBCAMERA_SRC);
> +	if (!gst_element_register(plugin, "libcamerasrc", GST_RANK_PRIMARY,
> +				  GST_TYPE_LIBCAMERA_SRC) ||
> +	    !gst_device_provider_register(plugin, "libcameraprovider",
> +					  GST_RANK_PRIMARY,
> +					  GST_TYPE_LIBCAMERA_PROVIDER))
> +		return FALSE;
> +
>  	return TRUE;
>  }
>  
> diff --git a/src/gstreamer/gstlibcameraprovider.cpp b/src/gstreamer/gstlibcameraprovider.cpp
> new file mode 100644
> index 0000000..3dcac59
> --- /dev/null
> +++ b/src/gstreamer/gstlibcameraprovider.cpp
> @@ -0,0 +1,235 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Collabora Ltd.
> + *     Author: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> + *
> + * gstlibcameraprovider.c - GStreamer Device Provider
> + */
> +
> +#include "gstlibcamera-utils.h"
> +#include "gstlibcameraprovider.h"
> +#include "gstlibcamerasrc.h"
> +
> +#include <libcamera/camera.h>
> +#include <libcamera/camera_manager.h>
> +
> +using namespace libcamera;
> +
> +GST_DEBUG_CATEGORY_STATIC(provider_debug);
> +#define GST_CAT_DEFAULT provider_debug
> +
> +/**
> + * \struct _GstLibcameraDevice
> + * \brief libcamera GstDevice implementation
> + *
> + * This object will be used by GstLibcameraProder to abstract a libcamera

s/GstLibcameraProder/GstLibcameraProvider/

I would already write "is used" instead of "will be used", otherwise
you'll have to change that later.

> + * device. It also provides helpers to create and configure the
> + * libcamerasrc GstElement to be used with this device. The implementation is
> + * private to the plugin.
> + */

Thanks for providing documentation for the structures, it's very useful.

> +
> +enum {
> +	PROP_DEVICE_NAME = 1,
> +};
> +
> +#define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
> +G_DECLARE_FINAL_TYPE(GstLibcameraDevice, gst_libcamera_device,
> +		     GST_LIBCAMERA, DEVICE, GstDevice);
> +
> +struct _GstLibcameraDevice {
> +	GstDevice parent;
> +	gchar *name;
> +};
> +
> +G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE);
> +
> +static GstElement *
> +gst_libcamera_device_create_element(GstDevice *device, const gchar *name)
> +{
> +	GstElement *source = gst_element_factory_make("libcamerasrc", name);
> +
> +	/* Provider and source lives in the same plugin, so making the source
> +	 * should never fail. */

The comment style should be

	/*
	 * Provider and source lives in the same plugin, so making the source
	 * should never fail.
	 */

I'll try to nerd-snipe Kieran again to add this to checkstyle.py :-)

> +	g_assert(source);
> +
> +	g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name, nullptr);
> +
> +	return source;
> +}
> +
> +static gboolean
> +gst_libcamera_device_reconfigure_element(GstDevice *device,
> +					 GstElement *element)
> +{
> +	if (!GST_LIBCAMERA_IS_SRC(element))
> +		return FALSE;
> +
> +	g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name, nullptr);
> +
> +	return TRUE;
> +}
> +
> +static void
> +gst_libcamera_device_set_property(GObject *object, guint prop_id,
> +				  const GValue *value, GParamSpec *pspec)
> +{
> +	GstLibcameraDevice *device = GST_LIBCAMERA_DEVICE(object);
> +
> +	switch (prop_id) {
> +	case PROP_DEVICE_NAME:
> +		device->name = g_value_dup_string(value);
> +		break;
> +	default:
> +		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> +		break;
> +	}
> +}
> +
> +static void
> +gst_libcamera_device_init(GstLibcameraDevice *self)
> +{
> +}
> +
> +static void
> +gst_libcamera_device_finalize(GObject *object)
> +{
> +	GstLibcameraDevice *self = GST_LIBCAMERA_DEVICE(object);
> +	gpointer klass = gst_libcamera_device_parent_class;
> +
> +	g_free(self->name);
> +
> +	G_OBJECT_GET_CLASS(klass)->finalize(object);
> +}
> +
> +static void
> +gst_libcamera_device_class_init(GstLibcameraDeviceClass *klass)
> +{
> +	GstDeviceClass *device_class = GST_DEVICE_CLASS(klass);
> +	GObjectClass *object_class = G_OBJECT_CLASS(klass);
> +
> +	device_class->create_element = gst_libcamera_device_create_element;
> +	device_class->reconfigure_element = gst_libcamera_device_reconfigure_element;
> +
> +	object_class->set_property = gst_libcamera_device_set_property;
> +	object_class->finalize = gst_libcamera_device_finalize;
> +
> +	GParamSpec *pspec = g_param_spec_string("name", "Name",
> +						"The name of the camera device", "",
> +						(GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
> +							      G_PARAM_CONSTRUCT_ONLY));
> +	g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
> +}
> +
> +static GstDevice *
> +gst_libcamera_device_new(const std::shared_ptr<Camera> &camera)
> +{
> +	g_autoptr(GstCaps) caps = gst_caps_new_empty();
> +	const gchar *name = camera->name().c_str();
> +	StreamRoles roles;
> +
> +	roles.push_back(StreamRole::VideoRecording);
> +	std::unique_ptr<CameraConfiguration> config = camera->generateConfiguration(roles);
> +
> +	for (const StreamConfiguration &stream_cfg : *config) {
> +		GstCaps *sub_caps = gst_libcamera_stream_formats_to_caps(stream_cfg.formats());
> +		if (sub_caps)
> +			gst_caps_append(caps, sub_caps);
> +	}
> +
> +	return GST_DEVICE(g_object_new(GST_TYPE_LIBCAMERA_DEVICE,
> +				       /* \todo Use a unique identifier instead of camera name. */
> +				       "name", name,
> +				       "display-name", name,
> +				       "caps", caps,
> +				       "device-class", "Source/Video",
> +				       nullptr));
> +}
> +
> +/**
> + * \struct _GstLibcameraProvider
> + * \brief libcamera GstDeviceProvider implementation
> + *
> + * This GstFeature will be used by GstDeviceMonitor to probe the available

s/will be used/is used/

> + * libcamera devices.  The implementation is private to the plugin.

s/  / /

> + */
> +
> +struct _GstLibcameraProvider {
> +	GstDeviceProvider parent;
> +	CameraManager *cm;
> +};
> +
> +G_DEFINE_TYPE_WITH_CODE(GstLibcameraProvider, gst_libcamera_provider,
> +			GST_TYPE_DEVICE_PROVIDER,
> +			GST_DEBUG_CATEGORY_INIT(provider_debug, "libcamera-provider", 0,
> +						"libcamera Device Provider"));
> +
> +static GList *
> +gst_libcamera_provider_probe(GstDeviceProvider *provider)
> +{
> +	GstLibcameraProvider *self = GST_LIBCAMERA_PROVIDER(provider);
> +	CameraManager *cm = self->cm;
> +	GList *devices = nullptr;
> +	gint ret;
> +
> +	GST_INFO_OBJECT(self, "Probing cameras using libcamera");
> +
> +	/* \todo Move the CameraMananger start()/stop() calls into
> +	 * GstDeviceProfiler start()/stop() virtual function when CameraMananger

s/GstDeviceProfiler/GstDeviceProvider/

With those small issues fixed,

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

> +	 * gains monitoring support. Meanwhile we need to cycle start()/stop()
> +	 * to ensure every probe() calls return the latest list.
> +	 */
> +	ret = cm->start();
> +	if (ret) {
> +		GST_ERROR_OBJECT(self, "Failed to retrieve device list: %s",
> +				 g_strerror(-ret));
> +		return nullptr;
> +	}
> +
> +	for (const std::shared_ptr<Camera> &camera : cm->cameras()) {
> +		GST_INFO_OBJECT(self, "Found camera '%s'", camera->name().c_str());
> +		devices = g_list_append(devices,
> +					g_object_ref_sink(gst_libcamera_device_new(camera)));
> +	}
> +
> +	cm->stop();
> +
> +	return devices;
> +}
> +
> +static void
> +gst_libcamera_provider_init(GstLibcameraProvider *self)
> +{
> +	GstDeviceProvider *provider = GST_DEVICE_PROVIDER(self);
> +
> +	self->cm = new CameraManager();
> +
> +	/* Avoid devices being duplicated. */
> +	gst_device_provider_hide_provider(provider, "v4l2deviceprovider");
> +}
> +
> +static void
> +gst_libcamera_provider_finalize(GObject *object)
> +{
> +	GstLibcameraProvider *self = GST_LIBCAMERA_PROVIDER(object);
> +	gpointer klass = gst_libcamera_provider_parent_class;
> +
> +	delete self->cm;
> +
> +	return G_OBJECT_GET_CLASS(klass)->finalize(object);
> +}
> +
> +static void
> +gst_libcamera_provider_class_init(GstLibcameraProviderClass *klass)
> +{
> +	GstDeviceProviderClass *provider_class = GST_DEVICE_PROVIDER_CLASS(klass);
> +	GObjectClass *object_class = G_OBJECT_CLASS(klass);
> +
> +	provider_class->probe = gst_libcamera_provider_probe;
> +	object_class->finalize = gst_libcamera_provider_finalize;
> +
> +	gst_device_provider_class_set_metadata(provider_class,
> +					       "libcamera Device Provider",
> +					       "Source/Video",
> +					       "List camera device using libcamera",
> +					       "Nicolas Dufresne <nicolas.dufresne at collabora.com>");
> +}
> diff --git a/src/gstreamer/gstlibcameraprovider.h b/src/gstreamer/gstlibcameraprovider.h
> new file mode 100644
> index 0000000..bdd19db
> --- /dev/null
> +++ b/src/gstreamer/gstlibcameraprovider.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Collabora Ltd.
> + *     Author: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> + *
> + * gstlibcameraprovider.h - GStreamer Device Provider
> + */
> +
> +#ifndef __GST_LIBCAMERA_PROVIDER_H__
> +#define __GST_LIBCAMERA_PROVIDER_H__
> +
> +#include <gst/gst.h>
> +
> +G_BEGIN_DECLS
> +
> +#define GST_TYPE_LIBCAMERA_PROVIDER gst_libcamera_provider_get_type()
> +G_DECLARE_FINAL_TYPE(GstLibcameraProvider, gst_libcamera_provider,
> +		     GST_LIBCAMERA, PROVIDER, GstDeviceProvider)
> +
> +G_END_DECLS
> +
> +#endif /* __GST_LIBCAMERA_PROVIDER_H__ */
> +
> diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build
> index f409107..a57dd85 100644
> --- a/src/gstreamer/meson.build
> +++ b/src/gstreamer/meson.build
> @@ -1,6 +1,7 @@
>  libcamera_gst_sources = [
>      'gstlibcamera-utils.cpp',
>      'gstlibcamera.c',
> +    'gstlibcameraprovider.cpp',
>      'gstlibcamerasrc.cpp',
>  ]
>  

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list