[libcamera-devel] [PATCH v1 2/3] gstreamer: Fix concurrent access issues to CameraManager
Nicolas Dufresne
nicolas.dufresne at collabora.com
Thu Aug 26 15:21:00 CEST 2021
Le jeudi 26 août 2021 à 02:18 +0300, Laurent Pinchart a écrit :
> Hi Nicolas,
>
> Thank you for the patch.
>
> On Wed, Aug 25, 2021 at 05:18:51PM -0400, Nicolas Dufresne wrote:
> > From: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> >
> > It's not allowed to have multiple instances of CameraManager. This
> > requirement is not easy for GStreamer were the device monitor and
> > the camerasrc, or two camerasrc instances don't usually have any
> > interaction between each other. This this by implementing a minimalist
>
> s/This this/Fix this/ ?
>
> > singleton around CameraManager constructor and start()/stop()
> > operations.
> >
> > Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> > ---
> > src/gstreamer/gstlibcamera-utils.cpp | 31 ++++++++++++++++++++++++++
> > src/gstreamer/gstlibcamera-utils.h | 6 +++--
> > src/gstreamer/gstlibcameraprovider.cpp | 22 ++----------------
> > src/gstreamer/gstlibcamerasrc.cpp | 11 +++++----
> > 4 files changed, 42 insertions(+), 28 deletions(-)
> >
> > diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
> > index 007d6a64..34b64c4a 100644
> > --- a/src/gstreamer/gstlibcamera-utils.cpp
> > +++ b/src/gstreamer/gstlibcamera-utils.cpp
> > @@ -221,3 +221,34 @@ gst_libcamera_resume_task(GstTask *task)
> > GST_TASK_SIGNAL(task);
> > }
> > }
> > +
> > +G_LOCK_DEFINE_STATIC(cm_singleton_lock);
> > +std::weak_ptr<CameraManager> cm_singleton_ptr;
> > +
> > +void _cm_deleter(CameraManager *cm)
> > +{
> > + g_print("Delete CameraManager\n");
> > + cm->stop();
> > + delete cm;
>
> The CameraManager destructor calls stop(), so if you don't care much
> about the g_print(), you could drop this function.
>
> > +}
> > +
> > +std::shared_ptr<CameraManager>
> > +gst_libcamera_get_camera_mananger(int &ret)
> > +{
> > + std::shared_ptr<CameraManager> cm;
> > +
> > + G_LOCK(cm_singleton_lock);
> > +
> > + cm = cm_singleton_ptr.lock();
> > + if (cm_singleton_ptr.expired()) {
>
> I think you could write this
>
> cm = cm_singleton_ptr.lock();
> if (cm) {
With "if (!cm)" that works.
>
> as std::weak_ptr<>::lock() return a null std::shared_ptr<> if it has
> expired.
>
> > + std::shared_ptr<CameraManager> ptr(new CameraManager(), _cm_deleter);
> > + cm_singleton_ptr = cm = ptr;
>
> And there's no need for the local ptr variable here, you can write
>
> cm = std::shared_ptr<CameraManager>(new CameraManager(), _cm_deleter);
> cm_singleton_ptr = cm;
>
> If you don't care about the deleter, it could also become
I'll drop the deleter if I don't need to call stop() explicitly.
>
> cm = std::make_shared<CameraManager>();
> cm_singleton_ptr = cm;
>
> > + ret = cm->start();
> > + } else {
> > + ret = 0;
> > + }
> > +
> > + G_UNLOCK(cm_singleton_lock);
> > +
> > + return cm;
> > +}
> > diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h
> > index 2b3f26b6..67a06db3 100644
> > --- a/src/gstreamer/gstlibcamera-utils.h
> > +++ b/src/gstreamer/gstlibcamera-utils.h
> > @@ -9,16 +9,18 @@
> > #ifndef __GST_LIBCAMERA_UTILS_H__
> > #define __GST_LIBCAMERA_UTILS_H__
> >
> > +#include <libcamera/camera_manager.h>
> > +#include <libcamera/stream.h>
> > +
> > #include <gst/gst.h>
> > #include <gst/video/video.h>
> >
> > -#include <libcamera/stream.h>
> > -
> > 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,
> > GstCaps *caps);
> > void gst_libcamera_resume_task(GstTask *task);
> > +std::shared_ptr<libcamera::CameraManager> gst_libcamera_get_camera_mananger(int &ret);
> >
> > /**
> > * \class GLibLocker
> > diff --git a/src/gstreamer/gstlibcameraprovider.cpp b/src/gstreamer/gstlibcameraprovider.cpp
> > index 29da6c32..948ba0d1 100644
> > --- a/src/gstreamer/gstlibcameraprovider.cpp
> > +++ b/src/gstreamer/gstlibcameraprovider.cpp
> > @@ -158,7 +158,6 @@ gst_libcamera_device_new(const std::shared_ptr<Camera> &camera)
> >
> > struct _GstLibcameraProvider {
> > GstDeviceProvider parent;
> > - CameraManager *cm;
> > };
>
> Is this constructed on demand to call probe() and then immediately
> destroyed that it makes no sense anymore to cache the pointer ?
Correct, this is a bit of an intermediate. In this temporary implementation
(non-monitoring). I was doing start() enum stop(), so that each time probe is
called the list was fresh. This is as close as I can get using a singleton here.
But consider this a temporary state.
To support the new API, we need a C++ class to hold the shared ptr (like
libcamersrc). I'll introduce this while adding monitoring support. This is just
to keep the the thing minimally working and small.
>
> >
> > G_DEFINE_TYPE_WITH_CODE(GstLibcameraProvider, gst_libcamera_provider,
> > @@ -170,7 +169,7 @@ static GList *
> > gst_libcamera_provider_probe(GstDeviceProvider *provider)
> > {
> > GstLibcameraProvider *self = GST_LIBCAMERA_PROVIDER(provider);
> > - CameraManager *cm = self->cm;
> > + std::shared_ptr<CameraManager> cm;
> > GList *devices = nullptr;
> > gint ret;
> >
> > @@ -181,7 +180,7 @@ gst_libcamera_provider_probe(GstDeviceProvider *provider)
> > * gains monitoring support. Meanwhile we need to cycle start()/stop()
> > * to ensure every probe() calls return the latest list.
> > */
> > - ret = cm->start();
> > + cm = gst_libcamera_get_camera_mananger(ret);
> > if (ret) {
> > GST_ERROR_OBJECT(self, "Failed to retrieve device list: %s",
> > g_strerror(-ret));
> > @@ -194,8 +193,6 @@ gst_libcamera_provider_probe(GstDeviceProvider *provider)
> > g_object_ref_sink(gst_libcamera_device_new(camera)));
> > }
> >
> > - cm->stop();
> > -
> > return devices;
> > }
> >
> > @@ -204,31 +201,16 @@ 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_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",
> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
> > index 4c7b36ae..bdd9f88c 100644
> > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > @@ -104,7 +104,7 @@ GstBuffer *RequestWrap::detachBuffer(Stream *stream)
> > struct GstLibcameraSrcState {
> > GstLibcameraSrc *src_;
> >
> > - std::unique_ptr<CameraManager> cm_;
> > + std::shared_ptr<CameraManager> cm_;
> > std::shared_ptr<Camera> cam_;
> > std::unique_ptr<CameraConfiguration> config_;
> > std::vector<GstPad *> srcpads_;
> > @@ -198,13 +198,13 @@ GstLibcameraSrcState::requestCompleted(Request *request)
> > static bool
> > gst_libcamera_src_open(GstLibcameraSrc *self)
> > {
> > - std::unique_ptr<CameraManager> cm = std::make_unique<CameraManager>();
> > + std::shared_ptr<CameraManager> cm;
> > std::shared_ptr<Camera> cam;
> > - gint ret = 0;
> > + gint ret;
> >
> > GST_DEBUG_OBJECT(self, "Opening camera device ...");
> >
> > - ret = cm->start();
> > + cm = gst_libcamera_get_camera_mananger(ret);
> > if (ret) {
> > GST_ELEMENT_ERROR(self, LIBRARY, INIT,
> > ("Failed listing cameras."),
> > @@ -250,7 +250,7 @@ gst_libcamera_src_open(GstLibcameraSrc *self)
> > cam->requestCompleted.connect(self->state, &GstLibcameraSrcState::requestCompleted);
> >
> > /* No need to lock here, we didn't start our threads yet. */
> > - self->state->cm_ = std::move(cm);
> > + self->state->cm_ = cm;
> > self->state->cam_ = cam;
> >
> > return true;
> > @@ -517,7 +517,6 @@ gst_libcamera_src_close(GstLibcameraSrc *self)
> > }
> >
> > state->cam_.reset();
> > - state->cm_->stop();
> > state->cm_.reset();
> > }
> >
>
More information about the libcamera-devel
mailing list