[libcamera-devel] Add enable_auto_focus option to the GStreamer plugin
diff mbox series

Message ID CAM6JzGDQMvPaOJfvUGy286PhM5oUvyxSkWWq8YFvmKoW1T0Rfw@mail.gmail.com
State Changes Requested
Headers show
Series
  • [libcamera-devel] Add enable_auto_focus option to the GStreamer plugin
Related show

Commit Message

Cedric Nugteren May 26, 2023, 12:34 p.m. UTC
Cameras such as the PiCam 3 support auto-focus, but the GStreamer plugin
for libcamera does not enable auto-focus. With this patch auto-focus can
be enabled for cameras that support it. By default it is disabled, which
means default behaviour remains unchanged. For cameras that do not
support auto-focus, an error message shows up if it auto-focus is
enabled.

This was tested on cameras that do not support auto-focus (e.g. PiCam2)
and was tested on a camera that does support auto-focus (PiCam3) by
enabling it, observing auto-focus, and by disabling it or by not setting
the option, both resulting in auto-focus being disabled.

Signed-off-by: Cedric Nugteren <web@cedricnugteren.nl>
---
 src/gstreamer/gstlibcameraprovider.cpp | 13 ++++++++++++
 src/gstreamer/gstlibcamerasrc.cpp      | 29 +++++++++++++++++++++++++-
 2 files changed, 41 insertions(+), 1 deletion(-)

GST_TYPE_ELEMENT,
@@ -577,6 +579,18 @@ gst_libcamera_src_task_enter(GstTask *task,
[[maybe_unused]] GThread *thread,
  gst_flow_combiner_add_pad(self->flow_combiner, srcpad);
  }

+ if (self->enable_auto_focus) {
+ const ControlInfoMap &infoMap = state->cam_->controls();
+ if (infoMap.find(&controls::AfMode) != infoMap.end()) {
+ state->initControls_.set(controls::AfMode, controls::AfModeContinuous);
+ } else {
+ GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
+ ("Failed to enable auto focus"),
+ ("AfMode not found in camera controls, "
+ "please retry with 'enable-auto-focus=false'"));
+ }
+ }
+
  ret = state->cam_->start(&state->initControls_);
  if (ret) {
  GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
@@ -659,6 +673,9 @@ gst_libcamera_src_set_property(GObject *object, guint
prop_id,
  g_free(self->camera_name);
  self->camera_name = g_value_dup_string(value);
  break;
+ case PROP_ENABLE_AUTO_FOCUS:
+ self->enable_auto_focus = g_value_get_boolean(value);
+ break;
  default:
  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  break;
@@ -676,6 +693,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_ENABLE_AUTO_FOCUS:
+ g_value_set_boolean(value, self->enable_auto_focus);
+ break;
  default:
  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  break;
@@ -844,4 +864,11 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass
*klass)
      | G_PARAM_READWRITE
      | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
+ GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
+                        "Enable auto-focus",
+                        "Enable auto-focus if set to true, "
+                        "disable it if set to false",
+                         FALSE, G_PARAM_WRITABLE);
+ g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS,
spec2);
+
 }

Comments

Nicolas Dufresne May 29, 2023, 6:09 p.m. UTC | #1
Hi,

Le vendredi 26 mai 2023 à 14:34 +0200, Cedric Nugteren via libcamera-devel a
écrit :
> Cameras such as the PiCam 3 support auto-focus, but the GStreamer plugin
> for libcamera does not enable auto-focus. With this patch auto-focus can
> be enabled for cameras that support it. By default it is disabled, which
> means default behaviour remains unchanged. For cameras that do not
> support auto-focus, an error message shows up if it auto-focus is
> enabled.

I'm not sure this default behaviour make sense. I would rather have it enabled
by default, since there is not other offered mean at the moment to obtain this
focus.

That being said, I haven't looked at the auto-focus feature, I was expecting
there would be different type of it, which would endup with different default
behaviour.

> 
> This was tested on cameras that do not support auto-focus (e.g. PiCam2)
> and was tested on a camera that does support auto-focus (PiCam3) by
> enabling it, observing auto-focus, and by disabling it or by not setting
> the option, both resulting in auto-focus being disabled.
> 
> Signed-off-by: Cedric Nugteren <web@cedricnugteren.nl>
> ---
>  src/gstreamer/gstlibcameraprovider.cpp | 13 ++++++++++++
>  src/gstreamer/gstlibcamerasrc.cpp      | 29 +++++++++++++++++++++++++-
>  2 files changed, 41 insertions(+), 1 deletion(-)
> 
> diff --git a/src/gstreamer/gstlibcameraprovider.cpp
> b/src/gstreamer/gstlibcameraprovider.cpp
> index 6eb0a0eb..86fa2542 100644
> --- a/src/gstreamer/gstlibcameraprovider.cpp
> +++ b/src/gstreamer/gstlibcameraprovider.cpp
> @@ -31,6 +31,7 @@ GST_DEBUG_CATEGORY_STATIC(provider_debug);
>  
>  enum {
>   PROP_DEVICE_NAME = 1,
> + PROP_ENABLE_AUTO_FOCUS = 2,
>  };
>  
>  #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
> @@ -40,6 +41,7 @@ G_DECLARE_FINAL_TYPE(GstLibcameraDevice,
> gst_libcamera_device,
>  struct _GstLibcameraDevice {
>   GstDevice parent;
>   gchar *name;
> + gboolean enable_auto_focus = false;
>  };
>  
>  G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
> @@ -56,6 +58,7 @@ gst_libcamera_device_create_element(GstDevice *device, const
> gchar *name)
>   g_assert(source);
>  
>   g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> nullptr);
> + g_object_set(source, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> >enable_auto_focus, nullptr);
>  
>   return source;
>  }
> @@ -68,6 +71,7 @@ gst_libcamera_device_reconfigure_element(GstDevice *device,
>   return FALSE;
>  
>   g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> nullptr);
> + g_object_set(element, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> >enable_auto_focus, nullptr);

That is strange, unlike camera-name, this information is not discovered at run-
time, hence does not require a notify callback. I'd simply set the default at
construction time, and avoid this here.

>  
>   return TRUE;
>  }
> @@ -82,6 +86,9 @@ gst_libcamera_device_set_property(GObject *object, guint
> prop_id,
>   case PROP_DEVICE_NAME:
>   device->name = g_value_dup_string(value);
>   break;
> + case PROP_ENABLE_AUTO_FOCUS:
> + device->enable_auto_focus = g_value_get_boolean(value);
> + break;
>   default:
>   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
>   break;
> @@ -121,6 +128,12 @@ gst_libcamera_device_class_init(GstLibcameraDeviceClass
> *klass)
>   (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
>        G_PARAM_CONSTRUCT_ONLY));
>   g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
> + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",

Why a new one ? just reuse spec here, its just temporary pointer with no
ownership in it. It was only added to be able to fit into the maximum line
length.

> +                        "Enable auto-focus",
> +                        "Enable auto-focus if set to true, "
> +                        "disable it if set to false",
> +                         FALSE, G_PARAM_WRITABLE);
> + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS,
> spec2);

Note, if you feel like it, you could make it more obvious by using
g_steal_pointer() here, which is similar to std::move (but works for non C++
pointers).

>  }
>  
>  static GstDevice *
> diff --git a/src/gstreamer/gstlibcamerasrc.cpp
> b/src/gstreamer/gstlibcamerasrc.cpp
> index a10cbd4f..672ea38a 100644
> --- a/src/gstreamer/gstlibcamerasrc.cpp
> +++ b/src/gstreamer/gstlibcamerasrc.cpp
> @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {
>   GstTask *task;
>  
>   gchar *camera_name;
> + gboolean enable_auto_focus = false;

I guess I've been thinking C a lot so far, thanks for making me noticed we can
do that. Note a little inconstancy, gboolean is an in. So I'd suggest:

+ bool enable_auto_focus = false;

>  
>   GstLibcameraSrcState *state;
>   GstLibcameraAllocator *allocator;
> @@ -154,7 +155,8 @@ struct _GstLibcameraSrc {
>  
>  enum {
>   PROP_0,
> - PROP_CAMERA_NAME
> + PROP_CAMERA_NAME,
> + PROP_ENABLE_AUTO_FOCUS,
>  };
>  
>  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
> @@ -577,6 +579,18 @@ gst_libcamera_src_task_enter(GstTask *task,
> [[maybe_unused]] GThread *thread,
>   gst_flow_combiner_add_pad(self->flow_combiner, srcpad);
>   }
>  
> + if (self->enable_auto_focus) {
> + const ControlInfoMap &infoMap = state->cam_->controls();
> + if (infoMap.find(&controls::AfMode) != infoMap.end()) {
> + state->initControls_.set(controls::AfMode, controls::AfModeContinuous);
> + } else {
> + GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> + ("Failed to enable auto focus"),
> + ("AfMode not found in camera controls, "
> + "please retry with 'enable-auto-focus=false'"));
> + }
> + }
> +

Please resend in text form as you are suppose to (I recommend using git send-
email). This will ensure we don't smash the indentation completely. I'll stop my
review here, as its too hard to read without indentation.

regards,
Nicolas

>   ret = state->cam_->start(&state->initControls_);
>   if (ret) {
>   GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> @@ -659,6 +673,9 @@ gst_libcamera_src_set_property(GObject *object, guint
> prop_id,
>   g_free(self->camera_name);
>   self->camera_name = g_value_dup_string(value);
>   break;
> + case PROP_ENABLE_AUTO_FOCUS:
> + self->enable_auto_focus = g_value_get_boolean(value);
> + break;
>   default:
>   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
>   break;
> @@ -676,6 +693,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_ENABLE_AUTO_FOCUS:
> + g_value_set_boolean(value, self->enable_auto_focus);
> + break;
>   default:
>   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
>   break;
> @@ -844,4 +864,11 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
>       | G_PARAM_READWRITE
>       | G_PARAM_STATIC_STRINGS));
>   g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
> + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> +                        "Enable auto-focus",
> +                        "Enable auto-focus if set to true, "
> +                        "disable it if set to false",
> +                         FALSE, G_PARAM_WRITABLE);
> + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS,
> spec2);
> +
>  }
Laurent Pinchart May 31, 2023, 3:06 p.m. UTC | #2
Hello,

(CC'ing Naush and David)

On Mon, May 29, 2023 at 02:09:39PM -0400, Nicolas Dufresne via libcamera-devel wrote:
> Le vendredi 26 mai 2023 à 14:34 +0200, Cedric Nugteren via libcamera-devel a
> écrit :
> > Cameras such as the PiCam 3 support auto-focus, but the GStreamer plugin
> > for libcamera does not enable auto-focus. With this patch auto-focus can
> > be enabled for cameras that support it. By default it is disabled, which
> > means default behaviour remains unchanged. For cameras that do not
> > support auto-focus, an error message shows up if it auto-focus is
> > enabled.
> 
> I'm not sure this default behaviour make sense. I would rather have it enabled
> by default, since there is not other offered mean at the moment to obtain this
> focus.
> 
> That being said, I haven't looked at the auto-focus feature, I was expecting
> there would be different type of it, which would endup with different default
> behaviour.

I think enabling it by default makes sense, but that leads me to another
question: why is auto-focus not enabled by defaut (for cameras that
support it) in the Raspberry Pi IPA module ?

> > This was tested on cameras that do not support auto-focus (e.g. PiCam2)
> > and was tested on a camera that does support auto-focus (PiCam3) by
> > enabling it, observing auto-focus, and by disabling it or by not setting
> > the option, both resulting in auto-focus being disabled.
> > 
> > Signed-off-by: Cedric Nugteren <web@cedricnugteren.nl>
> > ---
> >  src/gstreamer/gstlibcameraprovider.cpp | 13 ++++++++++++
> >  src/gstreamer/gstlibcamerasrc.cpp      | 29 +++++++++++++++++++++++++-
> >  2 files changed, 41 insertions(+), 1 deletion(-)
> > 
> > diff --git a/src/gstreamer/gstlibcameraprovider.cpp
> > b/src/gstreamer/gstlibcameraprovider.cpp
> > index 6eb0a0eb..86fa2542 100644
> > --- a/src/gstreamer/gstlibcameraprovider.cpp
> > +++ b/src/gstreamer/gstlibcameraprovider.cpp
> > @@ -31,6 +31,7 @@ GST_DEBUG_CATEGORY_STATIC(provider_debug);
> >  
> >  enum {
> >   PROP_DEVICE_NAME = 1,
> > + PROP_ENABLE_AUTO_FOCUS = 2,
> >  };
> >  
> >  #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
> > @@ -40,6 +41,7 @@ G_DECLARE_FINAL_TYPE(GstLibcameraDevice,
> > gst_libcamera_device,
> >  struct _GstLibcameraDevice {
> >   GstDevice parent;
> >   gchar *name;
> > + gboolean enable_auto_focus = false;
> >  };
> >  
> >  G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
> > @@ -56,6 +58,7 @@ gst_libcamera_device_create_element(GstDevice *device, const
> > gchar *name)
> >   g_assert(source);
> >  
> >   g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > nullptr);
> > + g_object_set(source, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > >enable_auto_focus, nullptr);
> >  
> >   return source;
> >  }
> > @@ -68,6 +71,7 @@ gst_libcamera_device_reconfigure_element(GstDevice *device,
> >   return FALSE;
> >  
> >   g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > nullptr);
> > + g_object_set(element, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > >enable_auto_focus, nullptr);
> 
> That is strange, unlike camera-name, this information is not discovered at run-
> time, hence does not require a notify callback. I'd simply set the default at
> construction time, and avoid this here.
> 
> >   return TRUE;
> >  }
> > @@ -82,6 +86,9 @@ gst_libcamera_device_set_property(GObject *object, guint
> > prop_id,
> >   case PROP_DEVICE_NAME:
> >   device->name = g_value_dup_string(value);
> >   break;
> > + case PROP_ENABLE_AUTO_FOCUS:
> > + device->enable_auto_focus = g_value_get_boolean(value);
> > + break;
> >   default:
> >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> >   break;
> > @@ -121,6 +128,12 @@ gst_libcamera_device_class_init(GstLibcameraDeviceClass
> > *klass)
> >   (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
> >        G_PARAM_CONSTRUCT_ONLY));
> >   g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
> > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> 
> Why a new one ? just reuse spec here, its just temporary pointer with no
> ownership in it. It was only added to be able to fit into the maximum line
> length.
> 
> > +                        "Enable auto-focus",
> > +                        "Enable auto-focus if set to true, "
> > +                        "disable it if set to false",
> > +                         FALSE, G_PARAM_WRITABLE);
> > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> 
> Note, if you feel like it, you could make it more obvious by using
> g_steal_pointer() here, which is similar to std::move (but works for non C++
> pointers).
> 
> >  }
> >  
> >  static GstDevice *
> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp
> > b/src/gstreamer/gstlibcamerasrc.cpp
> > index a10cbd4f..672ea38a 100644
> > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {
> >   GstTask *task;
> >  
> >   gchar *camera_name;
> > + gboolean enable_auto_focus = false;
> 
> I guess I've been thinking C a lot so far, thanks for making me noticed we can
> do that. Note a little inconstancy, gboolean is an in. So I'd suggest:
> 
> + bool enable_auto_focus = false;
> 
> >   GstLibcameraSrcState *state;
> >   GstLibcameraAllocator *allocator;
> > @@ -154,7 +155,8 @@ struct _GstLibcameraSrc {
> >  
> >  enum {
> >   PROP_0,
> > - PROP_CAMERA_NAME
> > + PROP_CAMERA_NAME,
> > + PROP_ENABLE_AUTO_FOCUS,
> >  };
> >  
> >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
> > @@ -577,6 +579,18 @@ gst_libcamera_src_task_enter(GstTask *task,
> > [[maybe_unused]] GThread *thread,
> >   gst_flow_combiner_add_pad(self->flow_combiner, srcpad);
> >   }
> >  
> > + if (self->enable_auto_focus) {
> > + const ControlInfoMap &infoMap = state->cam_->controls();
> > + if (infoMap.find(&controls::AfMode) != infoMap.end()) {
> > + state->initControls_.set(controls::AfMode, controls::AfModeContinuous);
> > + } else {
> > + GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > + ("Failed to enable auto focus"),
> > + ("AfMode not found in camera controls, "
> > + "please retry with 'enable-auto-focus=false'"));
> > + }
> > + }
> > +
> 
> Please resend in text form as you are suppose to (I recommend using git send-
> email). This will ensure we don't smash the indentation completely. I'll stop my
> review here, as its too hard to read without indentation.

I strongly recommend using git-send-email to send patches as well.
Instructions are available at
https://libcamera.org/contributing.html#submitting-patches, which links
to the very nice https://git-send-email.io/ helper to setup
git-send-email.

> >   ret = state->cam_->start(&state->initControls_);
> >   if (ret) {
> >   GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > @@ -659,6 +673,9 @@ gst_libcamera_src_set_property(GObject *object, guint
> > prop_id,
> >   g_free(self->camera_name);
> >   self->camera_name = g_value_dup_string(value);
> >   break;
> > + case PROP_ENABLE_AUTO_FOCUS:
> > + self->enable_auto_focus = g_value_get_boolean(value);
> > + break;
> >   default:
> >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> >   break;
> > @@ -676,6 +693,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_ENABLE_AUTO_FOCUS:
> > + g_value_set_boolean(value, self->enable_auto_focus);
> > + break;
> >   default:
> >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> >   break;
> > @@ -844,4 +864,11 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
> >       | G_PARAM_READWRITE
> >       | G_PARAM_STATIC_STRINGS));
> >   g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
> > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > +                        "Enable auto-focus",
> > +                        "Enable auto-focus if set to true, "
> > +                        "disable it if set to false",
> > +                         FALSE, G_PARAM_WRITABLE);
> > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > +
> >  }
Naushir Patuck May 31, 2023, 3:16 p.m. UTC | #3
Hi all,

On Wed, 31 May 2023 at 16:06, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hello,
>
> (CC'ing Naush and David)
>
> On Mon, May 29, 2023 at 02:09:39PM -0400, Nicolas Dufresne via libcamera-devel wrote:
> > Le vendredi 26 mai 2023 à 14:34 +0200, Cedric Nugteren via libcamera-devel a
> > écrit :
> > > Cameras such as the PiCam 3 support auto-focus, but the GStreamer plugin
> > > for libcamera does not enable auto-focus. With this patch auto-focus can
> > > be enabled for cameras that support it. By default it is disabled, which
> > > means default behaviour remains unchanged. For cameras that do not
> > > support auto-focus, an error message shows up if it auto-focus is
> > > enabled.
> >
> > I'm not sure this default behaviour make sense. I would rather have it enabled
> > by default, since there is not other offered mean at the moment to obtain this
> > focus.
> >
> > That being said, I haven't looked at the auto-focus feature, I was expecting
> > there would be different type of it, which would endup with different default
> > behaviour.
>
> I think enabling it by default makes sense, but that leads me to another
> question: why is auto-focus not enabled by defaut (for cameras that
> support it) in the Raspberry Pi IPA module ?

Believe it or not, this has been asked a few times now :-)

The RPi IPA does not want to assume or trigger any particular behaviour based on
the specific sensor used.  We feel it's up to applications to decide this
unconditionally. In the case of a focus lens available, the application ought to
choose what it wants to do, e.g. hyperfocal fixed position, AF cycle then fixed
position, CAF, etc.  We don't really want to choose a default that may not be
what is needed as this is highly use case dependent.

So we essentially do nothing and leave the lens where it last was in the absence
of any AF control.

Regards,
Naush

>
> > > This was tested on cameras that do not support auto-focus (e.g. PiCam2)
> > > and was tested on a camera that does support auto-focus (PiCam3) by
> > > enabling it, observing auto-focus, and by disabling it or by not setting
> > > the option, both resulting in auto-focus being disabled.
> > >
> > > Signed-off-by: Cedric Nugteren <web@cedricnugteren.nl>
> > > ---
> > >  src/gstreamer/gstlibcameraprovider.cpp | 13 ++++++++++++
> > >  src/gstreamer/gstlibcamerasrc.cpp      | 29 +++++++++++++++++++++++++-
> > >  2 files changed, 41 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/src/gstreamer/gstlibcameraprovider.cpp
> > > b/src/gstreamer/gstlibcameraprovider.cpp
> > > index 6eb0a0eb..86fa2542 100644
> > > --- a/src/gstreamer/gstlibcameraprovider.cpp
> > > +++ b/src/gstreamer/gstlibcameraprovider.cpp
> > > @@ -31,6 +31,7 @@ GST_DEBUG_CATEGORY_STATIC(provider_debug);
> > >
> > >  enum {
> > >   PROP_DEVICE_NAME = 1,
> > > + PROP_ENABLE_AUTO_FOCUS = 2,
> > >  };
> > >
> > >  #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
> > > @@ -40,6 +41,7 @@ G_DECLARE_FINAL_TYPE(GstLibcameraDevice,
> > > gst_libcamera_device,
> > >  struct _GstLibcameraDevice {
> > >   GstDevice parent;
> > >   gchar *name;
> > > + gboolean enable_auto_focus = false;
> > >  };
> > >
> > >  G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
> > > @@ -56,6 +58,7 @@ gst_libcamera_device_create_element(GstDevice *device, const
> > > gchar *name)
> > >   g_assert(source);
> > >
> > >   g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > nullptr);
> > > + g_object_set(source, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > >enable_auto_focus, nullptr);
> > >
> > >   return source;
> > >  }
> > > @@ -68,6 +71,7 @@ gst_libcamera_device_reconfigure_element(GstDevice *device,
> > >   return FALSE;
> > >
> > >   g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > nullptr);
> > > + g_object_set(element, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > >enable_auto_focus, nullptr);
> >
> > That is strange, unlike camera-name, this information is not discovered at run-
> > time, hence does not require a notify callback. I'd simply set the default at
> > construction time, and avoid this here.
> >
> > >   return TRUE;
> > >  }
> > > @@ -82,6 +86,9 @@ gst_libcamera_device_set_property(GObject *object, guint
> > > prop_id,
> > >   case PROP_DEVICE_NAME:
> > >   device->name = g_value_dup_string(value);
> > >   break;
> > > + case PROP_ENABLE_AUTO_FOCUS:
> > > + device->enable_auto_focus = g_value_get_boolean(value);
> > > + break;
> > >   default:
> > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > >   break;
> > > @@ -121,6 +128,12 @@ gst_libcamera_device_class_init(GstLibcameraDeviceClass
> > > *klass)
> > >   (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
> > >        G_PARAM_CONSTRUCT_ONLY));
> > >   g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
> > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> >
> > Why a new one ? just reuse spec here, its just temporary pointer with no
> > ownership in it. It was only added to be able to fit into the maximum line
> > length.
> >
> > > +                        "Enable auto-focus",
> > > +                        "Enable auto-focus if set to true, "
> > > +                        "disable it if set to false",
> > > +                         FALSE, G_PARAM_WRITABLE);
> > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> >
> > Note, if you feel like it, you could make it more obvious by using
> > g_steal_pointer() here, which is similar to std::move (but works for non C++
> > pointers).
> >
> > >  }
> > >
> > >  static GstDevice *
> > > diff --git a/src/gstreamer/gstlibcamerasrc.cpp
> > > b/src/gstreamer/gstlibcamerasrc.cpp
> > > index a10cbd4f..672ea38a 100644
> > > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {
> > >   GstTask *task;
> > >
> > >   gchar *camera_name;
> > > + gboolean enable_auto_focus = false;
> >
> > I guess I've been thinking C a lot so far, thanks for making me noticed we can
> > do that. Note a little inconstancy, gboolean is an in. So I'd suggest:
> >
> > + bool enable_auto_focus = false;
> >
> > >   GstLibcameraSrcState *state;
> > >   GstLibcameraAllocator *allocator;
> > > @@ -154,7 +155,8 @@ struct _GstLibcameraSrc {
> > >
> > >  enum {
> > >   PROP_0,
> > > - PROP_CAMERA_NAME
> > > + PROP_CAMERA_NAME,
> > > + PROP_ENABLE_AUTO_FOCUS,
> > >  };
> > >
> > >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
> > > @@ -577,6 +579,18 @@ gst_libcamera_src_task_enter(GstTask *task,
> > > [[maybe_unused]] GThread *thread,
> > >   gst_flow_combiner_add_pad(self->flow_combiner, srcpad);
> > >   }
> > >
> > > + if (self->enable_auto_focus) {
> > > + const ControlInfoMap &infoMap = state->cam_->controls();
> > > + if (infoMap.find(&controls::AfMode) != infoMap.end()) {
> > > + state->initControls_.set(controls::AfMode, controls::AfModeContinuous);
> > > + } else {
> > > + GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > + ("Failed to enable auto focus"),
> > > + ("AfMode not found in camera controls, "
> > > + "please retry with 'enable-auto-focus=false'"));
> > > + }
> > > + }
> > > +
> >
> > Please resend in text form as you are suppose to (I recommend using git send-
> > email). This will ensure we don't smash the indentation completely. I'll stop my
> > review here, as its too hard to read without indentation.
>
> I strongly recommend using git-send-email to send patches as well.
> Instructions are available at
> https://libcamera.org/contributing.html#submitting-patches, which links
> to the very nice https://git-send-email.io/ helper to setup
> git-send-email.
>
> > >   ret = state->cam_->start(&state->initControls_);
> > >   if (ret) {
> > >   GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > @@ -659,6 +673,9 @@ gst_libcamera_src_set_property(GObject *object, guint
> > > prop_id,
> > >   g_free(self->camera_name);
> > >   self->camera_name = g_value_dup_string(value);
> > >   break;
> > > + case PROP_ENABLE_AUTO_FOCUS:
> > > + self->enable_auto_focus = g_value_get_boolean(value);
> > > + break;
> > >   default:
> > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > >   break;
> > > @@ -676,6 +693,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_ENABLE_AUTO_FOCUS:
> > > + g_value_set_boolean(value, self->enable_auto_focus);
> > > + break;
> > >   default:
> > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > >   break;
> > > @@ -844,4 +864,11 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
> > >       | G_PARAM_READWRITE
> > >       | G_PARAM_STATIC_STRINGS));
> > >   g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
> > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > > +                        "Enable auto-focus",
> > > +                        "Enable auto-focus if set to true, "
> > > +                        "disable it if set to false",
> > > +                         FALSE, G_PARAM_WRITABLE);
> > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > > +
> > >  }
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart May 31, 2023, 3:52 p.m. UTC | #4
Hi Naush,

On Wed, May 31, 2023 at 04:16:28PM +0100, Naushir Patuck wrote:
> On Wed, 31 May 2023 at 16:06, Laurent Pinchart wrote:
> > On Mon, May 29, 2023 at 02:09:39PM -0400, Nicolas Dufresne via libcamera-devel wrote:
> > > Le vendredi 26 mai 2023 à 14:34 +0200, Cedric Nugteren via libcamera-devel a
> > > écrit :
> > > > Cameras such as the PiCam 3 support auto-focus, but the GStreamer plugin
> > > > for libcamera does not enable auto-focus. With this patch auto-focus can
> > > > be enabled for cameras that support it. By default it is disabled, which
> > > > means default behaviour remains unchanged. For cameras that do not
> > > > support auto-focus, an error message shows up if it auto-focus is
> > > > enabled.
> > >
> > > I'm not sure this default behaviour make sense. I would rather have it enabled
> > > by default, since there is not other offered mean at the moment to obtain this
> > > focus.
> > >
> > > That being said, I haven't looked at the auto-focus feature, I was expecting
> > > there would be different type of it, which would endup with different default
> > > behaviour.
> >
> > I think enabling it by default makes sense, but that leads me to another
> > question: why is auto-focus not enabled by defaut (for cameras that
> > support it) in the Raspberry Pi IPA module ?
> 
> Believe it or not, this has been asked a few times now :-)
> 
> The RPi IPA does not want to assume or trigger any particular behaviour based on
> the specific sensor used.  We feel it's up to applications to decide this
> unconditionally. In the case of a focus lens available, the application ought to
> choose what it wants to do, e.g. hyperfocal fixed position, AF cycle then fixed
> position, CAF, etc.  We don't really want to choose a default that may not be
> what is needed as this is highly use case dependent.
> 
> So we essentially do nothing and leave the lens where it last was in the absence
> of any AF control.

Thank you for the explanation.

I'm not totally sure I would have reached the same conclusion when it
comes to the default behaviour, but that's fine, your rationale
regarding AF mode selection makes sense. What I dislike, however, is
leaving the lens where it last was. Generally speaking, libcamera should
ensure a consistent and fully-defined camera state when starting, and
shouldn't depend on previous capture sessions.

I would also favour consistent behaviour across different cameras
regarding the default value of controls, and the AF mode in this case.
This means I would be fine disabling AF by default for IPU3 (and rkisp1,
one we merge AF support for that platform).

This leaves open the question of what to do in the GStreamer element by
default. Does it make sense for libcamera to default to disabling
autofocus, and enabling it by default in libcamerasrc ?

> > > > This was tested on cameras that do not support auto-focus (e.g. PiCam2)
> > > > and was tested on a camera that does support auto-focus (PiCam3) by
> > > > enabling it, observing auto-focus, and by disabling it or by not setting
> > > > the option, both resulting in auto-focus being disabled.
> > > >
> > > > Signed-off-by: Cedric Nugteren <web@cedricnugteren.nl>
> > > > ---
> > > >  src/gstreamer/gstlibcameraprovider.cpp | 13 ++++++++++++
> > > >  src/gstreamer/gstlibcamerasrc.cpp      | 29 +++++++++++++++++++++++++-
> > > >  2 files changed, 41 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/src/gstreamer/gstlibcameraprovider.cpp
> > > > b/src/gstreamer/gstlibcameraprovider.cpp
> > > > index 6eb0a0eb..86fa2542 100644
> > > > --- a/src/gstreamer/gstlibcameraprovider.cpp
> > > > +++ b/src/gstreamer/gstlibcameraprovider.cpp
> > > > @@ -31,6 +31,7 @@ GST_DEBUG_CATEGORY_STATIC(provider_debug);
> > > >
> > > >  enum {
> > > >   PROP_DEVICE_NAME = 1,
> > > > + PROP_ENABLE_AUTO_FOCUS = 2,
> > > >  };
> > > >
> > > >  #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
> > > > @@ -40,6 +41,7 @@ G_DECLARE_FINAL_TYPE(GstLibcameraDevice,
> > > > gst_libcamera_device,
> > > >  struct _GstLibcameraDevice {
> > > >   GstDevice parent;
> > > >   gchar *name;
> > > > + gboolean enable_auto_focus = false;
> > > >  };
> > > >
> > > >  G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
> > > > @@ -56,6 +58,7 @@ gst_libcamera_device_create_element(GstDevice *device, const
> > > > gchar *name)
> > > >   g_assert(source);
> > > >
> > > >   g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > > nullptr);
> > > > + g_object_set(source, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > > >enable_auto_focus, nullptr);
> > > >
> > > >   return source;
> > > >  }
> > > > @@ -68,6 +71,7 @@ gst_libcamera_device_reconfigure_element(GstDevice *device,
> > > >   return FALSE;
> > > >
> > > >   g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > > nullptr);
> > > > + g_object_set(element, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > > >enable_auto_focus, nullptr);
> > >
> > > That is strange, unlike camera-name, this information is not discovered at run-
> > > time, hence does not require a notify callback. I'd simply set the default at
> > > construction time, and avoid this here.
> > >
> > > >   return TRUE;
> > > >  }
> > > > @@ -82,6 +86,9 @@ gst_libcamera_device_set_property(GObject *object, guint
> > > > prop_id,
> > > >   case PROP_DEVICE_NAME:
> > > >   device->name = g_value_dup_string(value);
> > > >   break;
> > > > + case PROP_ENABLE_AUTO_FOCUS:
> > > > + device->enable_auto_focus = g_value_get_boolean(value);
> > > > + break;
> > > >   default:
> > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > >   break;
> > > > @@ -121,6 +128,12 @@ gst_libcamera_device_class_init(GstLibcameraDeviceClass
> > > > *klass)
> > > >   (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
> > > >        G_PARAM_CONSTRUCT_ONLY));
> > > >   g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
> > > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > >
> > > Why a new one ? just reuse spec here, its just temporary pointer with no
> > > ownership in it. It was only added to be able to fit into the maximum line
> > > length.
> > >
> > > > +                        "Enable auto-focus",
> > > > +                        "Enable auto-focus if set to true, "
> > > > +                        "disable it if set to false",
> > > > +                         FALSE, G_PARAM_WRITABLE);
> > > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > >
> > > Note, if you feel like it, you could make it more obvious by using
> > > g_steal_pointer() here, which is similar to std::move (but works for non C++
> > > pointers).
> > >
> > > >  }
> > > >
> > > >  static GstDevice *
> > > > diff --git a/src/gstreamer/gstlibcamerasrc.cpp
> > > > b/src/gstreamer/gstlibcamerasrc.cpp
> > > > index a10cbd4f..672ea38a 100644
> > > > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > > > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > > > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {
> > > >   GstTask *task;
> > > >
> > > >   gchar *camera_name;
> > > > + gboolean enable_auto_focus = false;
> > >
> > > I guess I've been thinking C a lot so far, thanks for making me noticed we can
> > > do that. Note a little inconstancy, gboolean is an in. So I'd suggest:
> > >
> > > + bool enable_auto_focus = false;
> > >
> > > >   GstLibcameraSrcState *state;
> > > >   GstLibcameraAllocator *allocator;
> > > > @@ -154,7 +155,8 @@ struct _GstLibcameraSrc {
> > > >
> > > >  enum {
> > > >   PROP_0,
> > > > - PROP_CAMERA_NAME
> > > > + PROP_CAMERA_NAME,
> > > > + PROP_ENABLE_AUTO_FOCUS,
> > > >  };
> > > >
> > > >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
> > > > @@ -577,6 +579,18 @@ gst_libcamera_src_task_enter(GstTask *task,
> > > > [[maybe_unused]] GThread *thread,
> > > >   gst_flow_combiner_add_pad(self->flow_combiner, srcpad);
> > > >   }
> > > >
> > > > + if (self->enable_auto_focus) {
> > > > + const ControlInfoMap &infoMap = state->cam_->controls();
> > > > + if (infoMap.find(&controls::AfMode) != infoMap.end()) {
> > > > + state->initControls_.set(controls::AfMode, controls::AfModeContinuous);
> > > > + } else {
> > > > + GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > > + ("Failed to enable auto focus"),
> > > > + ("AfMode not found in camera controls, "
> > > > + "please retry with 'enable-auto-focus=false'"));
> > > > + }
> > > > + }
> > > > +
> > >
> > > Please resend in text form as you are suppose to (I recommend using git send-
> > > email). This will ensure we don't smash the indentation completely. I'll stop my
> > > review here, as its too hard to read without indentation.
> >
> > I strongly recommend using git-send-email to send patches as well.
> > Instructions are available at
> > https://libcamera.org/contributing.html#submitting-patches, which links
> > to the very nice https://git-send-email.io/ helper to setup
> > git-send-email.
> >
> > > >   ret = state->cam_->start(&state->initControls_);
> > > >   if (ret) {
> > > >   GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > > @@ -659,6 +673,9 @@ gst_libcamera_src_set_property(GObject *object, guint
> > > > prop_id,
> > > >   g_free(self->camera_name);
> > > >   self->camera_name = g_value_dup_string(value);
> > > >   break;
> > > > + case PROP_ENABLE_AUTO_FOCUS:
> > > > + self->enable_auto_focus = g_value_get_boolean(value);
> > > > + break;
> > > >   default:
> > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > >   break;
> > > > @@ -676,6 +693,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_ENABLE_AUTO_FOCUS:
> > > > + g_value_set_boolean(value, self->enable_auto_focus);
> > > > + break;
> > > >   default:
> > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > >   break;
> > > > @@ -844,4 +864,11 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
> > > >       | G_PARAM_READWRITE
> > > >       | G_PARAM_STATIC_STRINGS));
> > > >   g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
> > > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > > > +                        "Enable auto-focus",
> > > > +                        "Enable auto-focus if set to true, "
> > > > +                        "disable it if set to false",
> > > > +                         FALSE, G_PARAM_WRITABLE);
> > > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > > > +
> > > >  }
Naushir Patuck June 1, 2023, 7:21 a.m. UTC | #5
Hi Laurent,

On Wed, 31 May 2023 at 16:52, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Naush,
>
> On Wed, May 31, 2023 at 04:16:28PM +0100, Naushir Patuck wrote:
> > On Wed, 31 May 2023 at 16:06, Laurent Pinchart wrote:
> > > On Mon, May 29, 2023 at 02:09:39PM -0400, Nicolas Dufresne via libcamera-devel wrote:
> > > > Le vendredi 26 mai 2023 à 14:34 +0200, Cedric Nugteren via libcamera-devel a
> > > > écrit :
> > > > > Cameras such as the PiCam 3 support auto-focus, but the GStreamer plugin
> > > > > for libcamera does not enable auto-focus. With this patch auto-focus can
> > > > > be enabled for cameras that support it. By default it is disabled, which
> > > > > means default behaviour remains unchanged. For cameras that do not
> > > > > support auto-focus, an error message shows up if it auto-focus is
> > > > > enabled.
> > > >
> > > > I'm not sure this default behaviour make sense. I would rather have it enabled
> > > > by default, since there is not other offered mean at the moment to obtain this
> > > > focus.
> > > >
> > > > That being said, I haven't looked at the auto-focus feature, I was expecting
> > > > there would be different type of it, which would endup with different default
> > > > behaviour.
> > >
> > > I think enabling it by default makes sense, but that leads me to another
> > > question: why is auto-focus not enabled by defaut (for cameras that
> > > support it) in the Raspberry Pi IPA module ?
> >
> > Believe it or not, this has been asked a few times now :-)
> >
> > The RPi IPA does not want to assume or trigger any particular behaviour based on
> > the specific sensor used.  We feel it's up to applications to decide this
> > unconditionally. In the case of a focus lens available, the application ought to
> > choose what it wants to do, e.g. hyperfocal fixed position, AF cycle then fixed
> > position, CAF, etc.  We don't really want to choose a default that may not be
> > what is needed as this is highly use case dependent.
> >
> > So we essentially do nothing and leave the lens where it last was in the absence
> > of any AF control.
>
> Thank you for the explanation.
>
> I'm not totally sure I would have reached the same conclusion when it
> comes to the default behaviour, but that's fine, your rationale
> regarding AF mode selection makes sense. What I dislike, however, is
> leaving the lens where it last was. Generally speaking, libcamera should
> ensure a consistent and fully-defined camera state when starting, and
> shouldn't depend on previous capture sessions.

Yes, I do agree with this.

The problem is choosing a default behaviour - CAF would not really be a nice
default experience on a non-PDAF sensor.  Perhaps doing a move to hyperfocal is
a good compromise and will provide a consistent experience across platforms and
sensor modules?

Regards,
Naush

>
> I would also favour consistent behaviour across different cameras
> regarding the default value of controls, and the AF mode in this case.
> This means I would be fine disabling AF by default for IPU3 (and rkisp1,
> one we merge AF support for that platform).
>
> This leaves open the question of what to do in the GStreamer element by
> default. Does it make sense for libcamera to default to disabling
> autofocus, and enabling it by default in libcamerasrc ?
>
> > > > > This was tested on cameras that do not support auto-focus (e.g. PiCam2)
> > > > > and was tested on a camera that does support auto-focus (PiCam3) by
> > > > > enabling it, observing auto-focus, and by disabling it or by not setting
> > > > > the option, both resulting in auto-focus being disabled.
> > > > >
> > > > > Signed-off-by: Cedric Nugteren <web@cedricnugteren.nl>
> > > > > ---
> > > > >  src/gstreamer/gstlibcameraprovider.cpp | 13 ++++++++++++
> > > > >  src/gstreamer/gstlibcamerasrc.cpp      | 29 +++++++++++++++++++++++++-
> > > > >  2 files changed, 41 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/src/gstreamer/gstlibcameraprovider.cpp
> > > > > b/src/gstreamer/gstlibcameraprovider.cpp
> > > > > index 6eb0a0eb..86fa2542 100644
> > > > > --- a/src/gstreamer/gstlibcameraprovider.cpp
> > > > > +++ b/src/gstreamer/gstlibcameraprovider.cpp
> > > > > @@ -31,6 +31,7 @@ GST_DEBUG_CATEGORY_STATIC(provider_debug);
> > > > >
> > > > >  enum {
> > > > >   PROP_DEVICE_NAME = 1,
> > > > > + PROP_ENABLE_AUTO_FOCUS = 2,
> > > > >  };
> > > > >
> > > > >  #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
> > > > > @@ -40,6 +41,7 @@ G_DECLARE_FINAL_TYPE(GstLibcameraDevice,
> > > > > gst_libcamera_device,
> > > > >  struct _GstLibcameraDevice {
> > > > >   GstDevice parent;
> > > > >   gchar *name;
> > > > > + gboolean enable_auto_focus = false;
> > > > >  };
> > > > >
> > > > >  G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
> > > > > @@ -56,6 +58,7 @@ gst_libcamera_device_create_element(GstDevice *device, const
> > > > > gchar *name)
> > > > >   g_assert(source);
> > > > >
> > > > >   g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > > > nullptr);
> > > > > + g_object_set(source, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > > > >enable_auto_focus, nullptr);
> > > > >
> > > > >   return source;
> > > > >  }
> > > > > @@ -68,6 +71,7 @@ gst_libcamera_device_reconfigure_element(GstDevice *device,
> > > > >   return FALSE;
> > > > >
> > > > >   g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > > > nullptr);
> > > > > + g_object_set(element, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > > > >enable_auto_focus, nullptr);
> > > >
> > > > That is strange, unlike camera-name, this information is not discovered at run-
> > > > time, hence does not require a notify callback. I'd simply set the default at
> > > > construction time, and avoid this here.
> > > >
> > > > >   return TRUE;
> > > > >  }
> > > > > @@ -82,6 +86,9 @@ gst_libcamera_device_set_property(GObject *object, guint
> > > > > prop_id,
> > > > >   case PROP_DEVICE_NAME:
> > > > >   device->name = g_value_dup_string(value);
> > > > >   break;
> > > > > + case PROP_ENABLE_AUTO_FOCUS:
> > > > > + device->enable_auto_focus = g_value_get_boolean(value);
> > > > > + break;
> > > > >   default:
> > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > >   break;
> > > > > @@ -121,6 +128,12 @@ gst_libcamera_device_class_init(GstLibcameraDeviceClass
> > > > > *klass)
> > > > >   (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
> > > > >        G_PARAM_CONSTRUCT_ONLY));
> > > > >   g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
> > > > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > > >
> > > > Why a new one ? just reuse spec here, its just temporary pointer with no
> > > > ownership in it. It was only added to be able to fit into the maximum line
> > > > length.
> > > >
> > > > > +                        "Enable auto-focus",
> > > > > +                        "Enable auto-focus if set to true, "
> > > > > +                        "disable it if set to false",
> > > > > +                         FALSE, G_PARAM_WRITABLE);
> > > > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > > >
> > > > Note, if you feel like it, you could make it more obvious by using
> > > > g_steal_pointer() here, which is similar to std::move (but works for non C++
> > > > pointers).
> > > >
> > > > >  }
> > > > >
> > > > >  static GstDevice *
> > > > > diff --git a/src/gstreamer/gstlibcamerasrc.cpp
> > > > > b/src/gstreamer/gstlibcamerasrc.cpp
> > > > > index a10cbd4f..672ea38a 100644
> > > > > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > > > > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > > > > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {
> > > > >   GstTask *task;
> > > > >
> > > > >   gchar *camera_name;
> > > > > + gboolean enable_auto_focus = false;
> > > >
> > > > I guess I've been thinking C a lot so far, thanks for making me noticed we can
> > > > do that. Note a little inconstancy, gboolean is an in. So I'd suggest:
> > > >
> > > > + bool enable_auto_focus = false;
> > > >
> > > > >   GstLibcameraSrcState *state;
> > > > >   GstLibcameraAllocator *allocator;
> > > > > @@ -154,7 +155,8 @@ struct _GstLibcameraSrc {
> > > > >
> > > > >  enum {
> > > > >   PROP_0,
> > > > > - PROP_CAMERA_NAME
> > > > > + PROP_CAMERA_NAME,
> > > > > + PROP_ENABLE_AUTO_FOCUS,
> > > > >  };
> > > > >
> > > > >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
> > > > > @@ -577,6 +579,18 @@ gst_libcamera_src_task_enter(GstTask *task,
> > > > > [[maybe_unused]] GThread *thread,
> > > > >   gst_flow_combiner_add_pad(self->flow_combiner, srcpad);
> > > > >   }
> > > > >
> > > > > + if (self->enable_auto_focus) {
> > > > > + const ControlInfoMap &infoMap = state->cam_->controls();
> > > > > + if (infoMap.find(&controls::AfMode) != infoMap.end()) {
> > > > > + state->initControls_.set(controls::AfMode, controls::AfModeContinuous);
> > > > > + } else {
> > > > > + GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > > > + ("Failed to enable auto focus"),
> > > > > + ("AfMode not found in camera controls, "
> > > > > + "please retry with 'enable-auto-focus=false'"));
> > > > > + }
> > > > > + }
> > > > > +
> > > >
> > > > Please resend in text form as you are suppose to (I recommend using git send-
> > > > email). This will ensure we don't smash the indentation completely. I'll stop my
> > > > review here, as its too hard to read without indentation.
> > >
> > > I strongly recommend using git-send-email to send patches as well.
> > > Instructions are available at
> > > https://libcamera.org/contributing.html#submitting-patches, which links
> > > to the very nice https://git-send-email.io/ helper to setup
> > > git-send-email.
> > >
> > > > >   ret = state->cam_->start(&state->initControls_);
> > > > >   if (ret) {
> > > > >   GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > > > @@ -659,6 +673,9 @@ gst_libcamera_src_set_property(GObject *object, guint
> > > > > prop_id,
> > > > >   g_free(self->camera_name);
> > > > >   self->camera_name = g_value_dup_string(value);
> > > > >   break;
> > > > > + case PROP_ENABLE_AUTO_FOCUS:
> > > > > + self->enable_auto_focus = g_value_get_boolean(value);
> > > > > + break;
> > > > >   default:
> > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > >   break;
> > > > > @@ -676,6 +693,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_ENABLE_AUTO_FOCUS:
> > > > > + g_value_set_boolean(value, self->enable_auto_focus);
> > > > > + break;
> > > > >   default:
> > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > >   break;
> > > > > @@ -844,4 +864,11 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
> > > > >       | G_PARAM_READWRITE
> > > > >       | G_PARAM_STATIC_STRINGS));
> > > > >   g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
> > > > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > > > > +                        "Enable auto-focus",
> > > > > +                        "Enable auto-focus if set to true, "
> > > > > +                        "disable it if set to false",
> > > > > +                         FALSE, G_PARAM_WRITABLE);
> > > > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > > > > +
> > > > >  }
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart June 1, 2023, 7:28 a.m. UTC | #6
Hi Naush,

On Thu, Jun 01, 2023 at 08:21:22AM +0100, Naushir Patuck wrote:
> On Wed, 31 May 2023 at 16:52, Laurent Pinchart wrote:
> > On Wed, May 31, 2023 at 04:16:28PM +0100, Naushir Patuck wrote:
> > > On Wed, 31 May 2023 at 16:06, Laurent Pinchart wrote:
> > > > On Mon, May 29, 2023 at 02:09:39PM -0400, Nicolas Dufresne via libcamera-devel wrote:
> > > > > Le vendredi 26 mai 2023 à 14:34 +0200, Cedric Nugteren via libcamera-devel a
> > > > > écrit :
> > > > > > Cameras such as the PiCam 3 support auto-focus, but the GStreamer plugin
> > > > > > for libcamera does not enable auto-focus. With this patch auto-focus can
> > > > > > be enabled for cameras that support it. By default it is disabled, which
> > > > > > means default behaviour remains unchanged. For cameras that do not
> > > > > > support auto-focus, an error message shows up if it auto-focus is
> > > > > > enabled.
> > > > >
> > > > > I'm not sure this default behaviour make sense. I would rather have it enabled
> > > > > by default, since there is not other offered mean at the moment to obtain this
> > > > > focus.
> > > > >
> > > > > That being said, I haven't looked at the auto-focus feature, I was expecting
> > > > > there would be different type of it, which would endup with different default
> > > > > behaviour.
> > > >
> > > > I think enabling it by default makes sense, but that leads me to another
> > > > question: why is auto-focus not enabled by defaut (for cameras that
> > > > support it) in the Raspberry Pi IPA module ?
> > >
> > > Believe it or not, this has been asked a few times now :-)
> > >
> > > The RPi IPA does not want to assume or trigger any particular behaviour based on
> > > the specific sensor used.  We feel it's up to applications to decide this
> > > unconditionally. In the case of a focus lens available, the application ought to
> > > choose what it wants to do, e.g. hyperfocal fixed position, AF cycle then fixed
> > > position, CAF, etc.  We don't really want to choose a default that may not be
> > > what is needed as this is highly use case dependent.
> > >
> > > So we essentially do nothing and leave the lens where it last was in the absence
> > > of any AF control.
> >
> > Thank you for the explanation.
> >
> > I'm not totally sure I would have reached the same conclusion when it
> > comes to the default behaviour, but that's fine, your rationale
> > regarding AF mode selection makes sense. What I dislike, however, is
> > leaving the lens where it last was. Generally speaking, libcamera should
> > ensure a consistent and fully-defined camera state when starting, and
> > shouldn't depend on previous capture sessions.
> 
> Yes, I do agree with this.
> 
> The problem is choosing a default behaviour - CAF would not really be a nice
> default experience on a non-PDAF sensor.  Perhaps doing a move to hyperfocal is
> a good compromise and will provide a consistent experience across platforms and
> sensor modules?

This works for me. Would you send a patch to do so in the Raspberry Pi
IPA module ?

If you have any idea what the default should be in the GStreamer
element, please feel free to chime in :-)

> > I would also favour consistent behaviour across different cameras
> > regarding the default value of controls, and the AF mode in this case.
> > This means I would be fine disabling AF by default for IPU3 (and rkisp1,
> > one we merge AF support for that platform).
> >
> > This leaves open the question of what to do in the GStreamer element by
> > default. Does it make sense for libcamera to default to disabling
> > autofocus, and enabling it by default in libcamerasrc ?
> >
> > > > > > This was tested on cameras that do not support auto-focus (e.g. PiCam2)
> > > > > > and was tested on a camera that does support auto-focus (PiCam3) by
> > > > > > enabling it, observing auto-focus, and by disabling it or by not setting
> > > > > > the option, both resulting in auto-focus being disabled.
> > > > > >
> > > > > > Signed-off-by: Cedric Nugteren <web@cedricnugteren.nl>
> > > > > > ---
> > > > > >  src/gstreamer/gstlibcameraprovider.cpp | 13 ++++++++++++
> > > > > >  src/gstreamer/gstlibcamerasrc.cpp      | 29 +++++++++++++++++++++++++-
> > > > > >  2 files changed, 41 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/src/gstreamer/gstlibcameraprovider.cpp
> > > > > > b/src/gstreamer/gstlibcameraprovider.cpp
> > > > > > index 6eb0a0eb..86fa2542 100644
> > > > > > --- a/src/gstreamer/gstlibcameraprovider.cpp
> > > > > > +++ b/src/gstreamer/gstlibcameraprovider.cpp
> > > > > > @@ -31,6 +31,7 @@ GST_DEBUG_CATEGORY_STATIC(provider_debug);
> > > > > >
> > > > > >  enum {
> > > > > >   PROP_DEVICE_NAME = 1,
> > > > > > + PROP_ENABLE_AUTO_FOCUS = 2,
> > > > > >  };
> > > > > >
> > > > > >  #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
> > > > > > @@ -40,6 +41,7 @@ G_DECLARE_FINAL_TYPE(GstLibcameraDevice,
> > > > > > gst_libcamera_device,
> > > > > >  struct _GstLibcameraDevice {
> > > > > >   GstDevice parent;
> > > > > >   gchar *name;
> > > > > > + gboolean enable_auto_focus = false;
> > > > > >  };
> > > > > >
> > > > > >  G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
> > > > > > @@ -56,6 +58,7 @@ gst_libcamera_device_create_element(GstDevice *device, const
> > > > > > gchar *name)
> > > > > >   g_assert(source);
> > > > > >
> > > > > >   g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > > > > nullptr);
> > > > > > + g_object_set(source, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > > > > >enable_auto_focus, nullptr);
> > > > > >
> > > > > >   return source;
> > > > > >  }
> > > > > > @@ -68,6 +71,7 @@ gst_libcamera_device_reconfigure_element(GstDevice *device,
> > > > > >   return FALSE;
> > > > > >
> > > > > >   g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > > > > nullptr);
> > > > > > + g_object_set(element, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > > > > >enable_auto_focus, nullptr);
> > > > >
> > > > > That is strange, unlike camera-name, this information is not discovered at run-
> > > > > time, hence does not require a notify callback. I'd simply set the default at
> > > > > construction time, and avoid this here.
> > > > >
> > > > > >   return TRUE;
> > > > > >  }
> > > > > > @@ -82,6 +86,9 @@ gst_libcamera_device_set_property(GObject *object, guint
> > > > > > prop_id,
> > > > > >   case PROP_DEVICE_NAME:
> > > > > >   device->name = g_value_dup_string(value);
> > > > > >   break;
> > > > > > + case PROP_ENABLE_AUTO_FOCUS:
> > > > > > + device->enable_auto_focus = g_value_get_boolean(value);
> > > > > > + break;
> > > > > >   default:
> > > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > > >   break;
> > > > > > @@ -121,6 +128,12 @@ gst_libcamera_device_class_init(GstLibcameraDeviceClass
> > > > > > *klass)
> > > > > >   (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
> > > > > >        G_PARAM_CONSTRUCT_ONLY));
> > > > > >   g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
> > > > > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > > > >
> > > > > Why a new one ? just reuse spec here, its just temporary pointer with no
> > > > > ownership in it. It was only added to be able to fit into the maximum line
> > > > > length.
> > > > >
> > > > > > +                        "Enable auto-focus",
> > > > > > +                        "Enable auto-focus if set to true, "
> > > > > > +                        "disable it if set to false",
> > > > > > +                         FALSE, G_PARAM_WRITABLE);
> > > > > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > > > >
> > > > > Note, if you feel like it, you could make it more obvious by using
> > > > > g_steal_pointer() here, which is similar to std::move (but works for non C++
> > > > > pointers).
> > > > >
> > > > > >  }
> > > > > >
> > > > > >  static GstDevice *
> > > > > > diff --git a/src/gstreamer/gstlibcamerasrc.cpp
> > > > > > b/src/gstreamer/gstlibcamerasrc.cpp
> > > > > > index a10cbd4f..672ea38a 100644
> > > > > > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > > > > > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > > > > > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {
> > > > > >   GstTask *task;
> > > > > >
> > > > > >   gchar *camera_name;
> > > > > > + gboolean enable_auto_focus = false;
> > > > >
> > > > > I guess I've been thinking C a lot so far, thanks for making me noticed we can
> > > > > do that. Note a little inconstancy, gboolean is an in. So I'd suggest:
> > > > >
> > > > > + bool enable_auto_focus = false;
> > > > >
> > > > > >   GstLibcameraSrcState *state;
> > > > > >   GstLibcameraAllocator *allocator;
> > > > > > @@ -154,7 +155,8 @@ struct _GstLibcameraSrc {
> > > > > >
> > > > > >  enum {
> > > > > >   PROP_0,
> > > > > > - PROP_CAMERA_NAME
> > > > > > + PROP_CAMERA_NAME,
> > > > > > + PROP_ENABLE_AUTO_FOCUS,
> > > > > >  };
> > > > > >
> > > > > >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
> > > > > > @@ -577,6 +579,18 @@ gst_libcamera_src_task_enter(GstTask *task,
> > > > > > [[maybe_unused]] GThread *thread,
> > > > > >   gst_flow_combiner_add_pad(self->flow_combiner, srcpad);
> > > > > >   }
> > > > > >
> > > > > > + if (self->enable_auto_focus) {
> > > > > > + const ControlInfoMap &infoMap = state->cam_->controls();
> > > > > > + if (infoMap.find(&controls::AfMode) != infoMap.end()) {
> > > > > > + state->initControls_.set(controls::AfMode, controls::AfModeContinuous);
> > > > > > + } else {
> > > > > > + GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > > > > + ("Failed to enable auto focus"),
> > > > > > + ("AfMode not found in camera controls, "
> > > > > > + "please retry with 'enable-auto-focus=false'"));
> > > > > > + }
> > > > > > + }
> > > > > > +
> > > > >
> > > > > Please resend in text form as you are suppose to (I recommend using git send-
> > > > > email). This will ensure we don't smash the indentation completely. I'll stop my
> > > > > review here, as its too hard to read without indentation.
> > > >
> > > > I strongly recommend using git-send-email to send patches as well.
> > > > Instructions are available at
> > > > https://libcamera.org/contributing.html#submitting-patches, which links
> > > > to the very nice https://git-send-email.io/ helper to setup
> > > > git-send-email.
> > > >
> > > > > >   ret = state->cam_->start(&state->initControls_);
> > > > > >   if (ret) {
> > > > > >   GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > > > > @@ -659,6 +673,9 @@ gst_libcamera_src_set_property(GObject *object, guint
> > > > > > prop_id,
> > > > > >   g_free(self->camera_name);
> > > > > >   self->camera_name = g_value_dup_string(value);
> > > > > >   break;
> > > > > > + case PROP_ENABLE_AUTO_FOCUS:
> > > > > > + self->enable_auto_focus = g_value_get_boolean(value);
> > > > > > + break;
> > > > > >   default:
> > > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > > >   break;
> > > > > > @@ -676,6 +693,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_ENABLE_AUTO_FOCUS:
> > > > > > + g_value_set_boolean(value, self->enable_auto_focus);
> > > > > > + break;
> > > > > >   default:
> > > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > > >   break;
> > > > > > @@ -844,4 +864,11 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
> > > > > >       | G_PARAM_READWRITE
> > > > > >       | G_PARAM_STATIC_STRINGS));
> > > > > >   g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
> > > > > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > > > > > +                        "Enable auto-focus",
> > > > > > +                        "Enable auto-focus if set to true, "
> > > > > > +                        "disable it if set to false",
> > > > > > +                         FALSE, G_PARAM_WRITABLE);
> > > > > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > > > > > +
> > > > > >  }
Naushir Patuck June 1, 2023, 7:39 a.m. UTC | #7
Hi Laurent,

On Thu, 1 Jun 2023 at 08:29, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Naush,
>
> On Thu, Jun 01, 2023 at 08:21:22AM +0100, Naushir Patuck wrote:
> > On Wed, 31 May 2023 at 16:52, Laurent Pinchart wrote:
> > > On Wed, May 31, 2023 at 04:16:28PM +0100, Naushir Patuck wrote:
> > > > On Wed, 31 May 2023 at 16:06, Laurent Pinchart wrote:
> > > > > On Mon, May 29, 2023 at 02:09:39PM -0400, Nicolas Dufresne via libcamera-devel wrote:
> > > > > > Le vendredi 26 mai 2023 à 14:34 +0200, Cedric Nugteren via libcamera-devel a
> > > > > > écrit :
> > > > > > > Cameras such as the PiCam 3 support auto-focus, but the GStreamer plugin
> > > > > > > for libcamera does not enable auto-focus. With this patch auto-focus can
> > > > > > > be enabled for cameras that support it. By default it is disabled, which
> > > > > > > means default behaviour remains unchanged. For cameras that do not
> > > > > > > support auto-focus, an error message shows up if it auto-focus is
> > > > > > > enabled.
> > > > > >
> > > > > > I'm not sure this default behaviour make sense. I would rather have it enabled
> > > > > > by default, since there is not other offered mean at the moment to obtain this
> > > > > > focus.
> > > > > >
> > > > > > That being said, I haven't looked at the auto-focus feature, I was expecting
> > > > > > there would be different type of it, which would endup with different default
> > > > > > behaviour.
> > > > >
> > > > > I think enabling it by default makes sense, but that leads me to another
> > > > > question: why is auto-focus not enabled by defaut (for cameras that
> > > > > support it) in the Raspberry Pi IPA module ?
> > > >
> > > > Believe it or not, this has been asked a few times now :-)
> > > >
> > > > The RPi IPA does not want to assume or trigger any particular behaviour based on
> > > > the specific sensor used.  We feel it's up to applications to decide this
> > > > unconditionally. In the case of a focus lens available, the application ought to
> > > > choose what it wants to do, e.g. hyperfocal fixed position, AF cycle then fixed
> > > > position, CAF, etc.  We don't really want to choose a default that may not be
> > > > what is needed as this is highly use case dependent.
> > > >
> > > > So we essentially do nothing and leave the lens where it last was in the absence
> > > > of any AF control.
> > >
> > > Thank you for the explanation.
> > >
> > > I'm not totally sure I would have reached the same conclusion when it
> > > comes to the default behaviour, but that's fine, your rationale
> > > regarding AF mode selection makes sense. What I dislike, however, is
> > > leaving the lens where it last was. Generally speaking, libcamera should
> > > ensure a consistent and fully-defined camera state when starting, and
> > > shouldn't depend on previous capture sessions.
> >
> > Yes, I do agree with this.
> >
> > The problem is choosing a default behaviour - CAF would not really be a nice
> > default experience on a non-PDAF sensor.  Perhaps doing a move to hyperfocal is
> > a good compromise and will provide a consistent experience across platforms and
> > sensor modules?
>
> This works for me. Would you send a patch to do so in the Raspberry Pi
> IPA module ?

Yes I can do that.  We should also possibly document this as the expected
default somewhere, maybe in the LensPosition control description?

>
> If you have any idea what the default should be in the GStreamer
> element, please feel free to chime in :-)

Perhaps GStreamer should do nothing with focus by default and rely on the IPA
default behaviour (i.e. go to hyperfocal)?  This then relies on the application
to choose what it wants to do on startup, just like any other application that
directly uses libcamera.

Regards,
Naush


>
> > > I would also favour consistent behaviour across different cameras
> > > regarding the default value of controls, and the AF mode in this case.
> > > This means I would be fine disabling AF by default for IPU3 (and rkisp1,
> > > one we merge AF support for that platform).
> > >
> > > This leaves open the question of what to do in the GStreamer element by
> > > default. Does it make sense for libcamera to default to disabling
> > > autofocus, and enabling it by default in libcamerasrc ?
> > >
> > > > > > > This was tested on cameras that do not support auto-focus (e.g. PiCam2)
> > > > > > > and was tested on a camera that does support auto-focus (PiCam3) by
> > > > > > > enabling it, observing auto-focus, and by disabling it or by not setting
> > > > > > > the option, both resulting in auto-focus being disabled.
> > > > > > >
> > > > > > > Signed-off-by: Cedric Nugteren <web@cedricnugteren.nl>
> > > > > > > ---
> > > > > > >  src/gstreamer/gstlibcameraprovider.cpp | 13 ++++++++++++
> > > > > > >  src/gstreamer/gstlibcamerasrc.cpp      | 29 +++++++++++++++++++++++++-
> > > > > > >  2 files changed, 41 insertions(+), 1 deletion(-)
> > > > > > >
> > > > > > > diff --git a/src/gstreamer/gstlibcameraprovider.cpp
> > > > > > > b/src/gstreamer/gstlibcameraprovider.cpp
> > > > > > > index 6eb0a0eb..86fa2542 100644
> > > > > > > --- a/src/gstreamer/gstlibcameraprovider.cpp
> > > > > > > +++ b/src/gstreamer/gstlibcameraprovider.cpp
> > > > > > > @@ -31,6 +31,7 @@ GST_DEBUG_CATEGORY_STATIC(provider_debug);
> > > > > > >
> > > > > > >  enum {
> > > > > > >   PROP_DEVICE_NAME = 1,
> > > > > > > + PROP_ENABLE_AUTO_FOCUS = 2,
> > > > > > >  };
> > > > > > >
> > > > > > >  #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
> > > > > > > @@ -40,6 +41,7 @@ G_DECLARE_FINAL_TYPE(GstLibcameraDevice,
> > > > > > > gst_libcamera_device,
> > > > > > >  struct _GstLibcameraDevice {
> > > > > > >   GstDevice parent;
> > > > > > >   gchar *name;
> > > > > > > + gboolean enable_auto_focus = false;
> > > > > > >  };
> > > > > > >
> > > > > > >  G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
> > > > > > > @@ -56,6 +58,7 @@ gst_libcamera_device_create_element(GstDevice *device, const
> > > > > > > gchar *name)
> > > > > > >   g_assert(source);
> > > > > > >
> > > > > > >   g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > > > > > nullptr);
> > > > > > > + g_object_set(source, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > > > > > >enable_auto_focus, nullptr);
> > > > > > >
> > > > > > >   return source;
> > > > > > >  }
> > > > > > > @@ -68,6 +71,7 @@ gst_libcamera_device_reconfigure_element(GstDevice *device,
> > > > > > >   return FALSE;
> > > > > > >
> > > > > > >   g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
> > > > > > > nullptr);
> > > > > > > + g_object_set(element, "enable-auto-focus", GST_LIBCAMERA_DEVICE(device)-
> > > > > > > >enable_auto_focus, nullptr);
> > > > > >
> > > > > > That is strange, unlike camera-name, this information is not discovered at run-
> > > > > > time, hence does not require a notify callback. I'd simply set the default at
> > > > > > construction time, and avoid this here.
> > > > > >
> > > > > > >   return TRUE;
> > > > > > >  }
> > > > > > > @@ -82,6 +86,9 @@ gst_libcamera_device_set_property(GObject *object, guint
> > > > > > > prop_id,
> > > > > > >   case PROP_DEVICE_NAME:
> > > > > > >   device->name = g_value_dup_string(value);
> > > > > > >   break;
> > > > > > > + case PROP_ENABLE_AUTO_FOCUS:
> > > > > > > + device->enable_auto_focus = g_value_get_boolean(value);
> > > > > > > + break;
> > > > > > >   default:
> > > > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > > > >   break;
> > > > > > > @@ -121,6 +128,12 @@ gst_libcamera_device_class_init(GstLibcameraDeviceClass
> > > > > > > *klass)
> > > > > > >   (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
> > > > > > >        G_PARAM_CONSTRUCT_ONLY));
> > > > > > >   g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
> > > > > > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > > > > >
> > > > > > Why a new one ? just reuse spec here, its just temporary pointer with no
> > > > > > ownership in it. It was only added to be able to fit into the maximum line
> > > > > > length.
> > > > > >
> > > > > > > +                        "Enable auto-focus",
> > > > > > > +                        "Enable auto-focus if set to true, "
> > > > > > > +                        "disable it if set to false",
> > > > > > > +                         FALSE, G_PARAM_WRITABLE);
> > > > > > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > > > > >
> > > > > > Note, if you feel like it, you could make it more obvious by using
> > > > > > g_steal_pointer() here, which is similar to std::move (but works for non C++
> > > > > > pointers).
> > > > > >
> > > > > > >  }
> > > > > > >
> > > > > > >  static GstDevice *
> > > > > > > diff --git a/src/gstreamer/gstlibcamerasrc.cpp
> > > > > > > b/src/gstreamer/gstlibcamerasrc.cpp
> > > > > > > index a10cbd4f..672ea38a 100644
> > > > > > > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > > > > > > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > > > > > > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {
> > > > > > >   GstTask *task;
> > > > > > >
> > > > > > >   gchar *camera_name;
> > > > > > > + gboolean enable_auto_focus = false;
> > > > > >
> > > > > > I guess I've been thinking C a lot so far, thanks for making me noticed we can
> > > > > > do that. Note a little inconstancy, gboolean is an in. So I'd suggest:
> > > > > >
> > > > > > + bool enable_auto_focus = false;
> > > > > >
> > > > > > >   GstLibcameraSrcState *state;
> > > > > > >   GstLibcameraAllocator *allocator;
> > > > > > > @@ -154,7 +155,8 @@ struct _GstLibcameraSrc {
> > > > > > >
> > > > > > >  enum {
> > > > > > >   PROP_0,
> > > > > > > - PROP_CAMERA_NAME
> > > > > > > + PROP_CAMERA_NAME,
> > > > > > > + PROP_ENABLE_AUTO_FOCUS,
> > > > > > >  };
> > > > > > >
> > > > > > >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
> > > > > > > @@ -577,6 +579,18 @@ gst_libcamera_src_task_enter(GstTask *task,
> > > > > > > [[maybe_unused]] GThread *thread,
> > > > > > >   gst_flow_combiner_add_pad(self->flow_combiner, srcpad);
> > > > > > >   }
> > > > > > >
> > > > > > > + if (self->enable_auto_focus) {
> > > > > > > + const ControlInfoMap &infoMap = state->cam_->controls();
> > > > > > > + if (infoMap.find(&controls::AfMode) != infoMap.end()) {
> > > > > > > + state->initControls_.set(controls::AfMode, controls::AfModeContinuous);
> > > > > > > + } else {
> > > > > > > + GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > > > > > + ("Failed to enable auto focus"),
> > > > > > > + ("AfMode not found in camera controls, "
> > > > > > > + "please retry with 'enable-auto-focus=false'"));
> > > > > > > + }
> > > > > > > + }
> > > > > > > +
> > > > > >
> > > > > > Please resend in text form as you are suppose to (I recommend using git send-
> > > > > > email). This will ensure we don't smash the indentation completely. I'll stop my
> > > > > > review here, as its too hard to read without indentation.
> > > > >
> > > > > I strongly recommend using git-send-email to send patches as well.
> > > > > Instructions are available at
> > > > > https://libcamera.org/contributing.html#submitting-patches, which links
> > > > > to the very nice https://git-send-email.io/ helper to setup
> > > > > git-send-email.
> > > > >
> > > > > > >   ret = state->cam_->start(&state->initControls_);
> > > > > > >   if (ret) {
> > > > > > >   GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> > > > > > > @@ -659,6 +673,9 @@ gst_libcamera_src_set_property(GObject *object, guint
> > > > > > > prop_id,
> > > > > > >   g_free(self->camera_name);
> > > > > > >   self->camera_name = g_value_dup_string(value);
> > > > > > >   break;
> > > > > > > + case PROP_ENABLE_AUTO_FOCUS:
> > > > > > > + self->enable_auto_focus = g_value_get_boolean(value);
> > > > > > > + break;
> > > > > > >   default:
> > > > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > > > >   break;
> > > > > > > @@ -676,6 +693,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_ENABLE_AUTO_FOCUS:
> > > > > > > + g_value_set_boolean(value, self->enable_auto_focus);
> > > > > > > + break;
> > > > > > >   default:
> > > > > > >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> > > > > > >   break;
> > > > > > > @@ -844,4 +864,11 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
> > > > > > >       | G_PARAM_READWRITE
> > > > > > >       | G_PARAM_STATIC_STRINGS));
> > > > > > >   g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);
> > > > > > > + GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
> > > > > > > +                        "Enable auto-focus",
> > > > > > > +                        "Enable auto-focus if set to true, "
> > > > > > > +                        "disable it if set to false",
> > > > > > > +                         FALSE, G_PARAM_WRITABLE);
> > > > > > > + g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS, spec2);
> > > > > > > +
> > > > > > >  }
>
> --
> Regards,
>
> Laurent Pinchart
Nicolas Dufresne June 1, 2023, 4:24 p.m. UTC | #8
Le jeudi 01 juin 2023 à 08:39 +0100, Naushir Patuck a écrit :
> > If you have any idea what the default should be in the GStreamer
> > element, please feel free to chime in :-)
> 
> Perhaps GStreamer should do nothing with focus by default and rely on the IPA
> default behaviour (i.e. go to hyperfocal)?  This then relies on the
> application
> to choose what it wants to do on startup, just like any other application that
> directly uses libcamera.

To reassure you, it can't be worse then what most UVC camera do today. Having a
default matching this would help consistency though (or being similarly bad from
some point of view). Later, on top, there should be ways to move to a more
manual control in focus aware Gst applications.

Nicolas
Laurent Pinchart June 2, 2023, 5:19 a.m. UTC | #9
On Thu, Jun 01, 2023 at 12:24:22PM -0400, Nicolas Dufresne wrote:
> Le jeudi 01 juin 2023 à 08:39 +0100, Naushir Patuck a écrit :
> > > If you have any idea what the default should be in the GStreamer
> > > element, please feel free to chime in :-)
> > 
> > Perhaps GStreamer should do nothing with focus by default and rely on the IPA
> > default behaviour (i.e. go to hyperfocal)?  This then relies on the application
> > to choose what it wants to do on startup, just like any other application that
> > directly uses libcamera.
> 
> To reassure you, it can't be worse then what most UVC camera do today. Having a
> default matching this would help consistency though (or being similarly bad from
> some point of view). Later, on top, there should be ways to move to a more
> manual control in focus aware Gst applications.

Hmmmm... I'm really in two minds here.

First of all, we can't expect the same default behaviour for all cameras
when it comes to auto-focus, simply because many cameras don't have a
controllable focus lens, and some (I'm thinking about UVC devices here)
may not have the ability to turn auto-focus on. Still, implementing
consistent defaults where possible is a goal I highly value, in order to
maximize application portability.

When it comes to the libcamera core, setting the focus lens to the
hyperfocal distance and disabling auto-focus seems like a good default
to me. Different use cases would favour different defaults, and I don't
think there's one particular use case that could be considered so
prevalent that it would call for enabling continuous auto-focus by
default. Different defaults could however be implemented in different
layers. For instance, I could imagine PipeWire deciding to enabling
continuous auto-focus by default on desktop or mobile systems.

For libcamerasrc, I don't know if the same reasoning should lead to the
same result, or if we should consider that the vast majority of use
cases for the GStreamer element call for enabling auto-focus by default.
I currently side towards doing the same as in the libcamera core, as I
believe it would be confusing for users to have different default
behaviours when using libcamera through different adaptation layers.
However, I could also imagine enabling auto-focus by default in the V4L2
adaptation layer for instance, as that layer is mostly meant to expose
libcamera-based cameras as webcams.
Cedric Nugteren June 2, 2023, 1:53 p.m. UTC | #10
I have fixed the review comments and have installed and configured git
send-email. However, apparently it started a new thread, I don't think that
is what it should have done:
https://lists.libcamera.org/pipermail/libcamera-devel/2023-May/037925.html
(I used "git send-email --in-reply-to=037947 --to=
libcamera-devel@lists.libcamera.org patch_file.patch")

Also, you mentioned that would like to see the original patch better
formatted. Should I just create a whole new patch altogether?

Finally, about the default/non-default discussion, I was trying to be
conservative here, because when I opened the original bug (#188), the reply
I got sounded like you thought it was a missing feature rather than a bug.
For me this is a blocking bug: I can't use the PiCamV3 at all due to random
focus behaviour. So therefore I opted for keeping the default behaviour as
it was before to make it more likely that this patch will be accepted.

On Fri, Jun 2, 2023 at 7:19 AM Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> On Thu, Jun 01, 2023 at 12:24:22PM -0400, Nicolas Dufresne wrote:
> > Le jeudi 01 juin 2023 à 08:39 +0100, Naushir Patuck a écrit :
> > > > If you have any idea what the default should be in the GStreamer
> > > > element, please feel free to chime in :-)
> > >
> > > Perhaps GStreamer should do nothing with focus by default and rely on
> the IPA
> > > default behaviour (i.e. go to hyperfocal)?  This then relies on the
> application
> > > to choose what it wants to do on startup, just like any other
> application that
> > > directly uses libcamera.
> >
> > To reassure you, it can't be worse then what most UVC camera do today.
> Having a
> > default matching this would help consistency though (or being similarly
> bad from
> > some point of view). Later, on top, there should be ways to move to a
> more
> > manual control in focus aware Gst applications.
>
> Hmmmm... I'm really in two minds here.
>
> First of all, we can't expect the same default behaviour for all cameras
> when it comes to auto-focus, simply because many cameras don't have a
> controllable focus lens, and some (I'm thinking about UVC devices here)
> may not have the ability to turn auto-focus on. Still, implementing
> consistent defaults where possible is a goal I highly value, in order to
> maximize application portability.
>
> When it comes to the libcamera core, setting the focus lens to the
> hyperfocal distance and disabling auto-focus seems like a good default
> to me. Different use cases would favour different defaults, and I don't
> think there's one particular use case that could be considered so
> prevalent that it would call for enabling continuous auto-focus by
> default. Different defaults could however be implemented in different
> layers. For instance, I could imagine PipeWire deciding to enabling
> continuous auto-focus by default on desktop or mobile systems.
>
> For libcamerasrc, I don't know if the same reasoning should lead to the
> same result, or if we should consider that the vast majority of use
> cases for the GStreamer element call for enabling auto-focus by default.
> I currently side towards doing the same as in the libcamera core, as I
> believe it would be confusing for users to have different default
> behaviours when using libcamera through different adaptation layers.
> However, I could also imagine enabling auto-focus by default in the V4L2
> adaptation layer for instance, as that layer is mostly meant to expose
> libcamera-based cameras as webcams.
>
> --
> Regards,
>
> Laurent Pinchart
>
Nicolas Dufresne June 2, 2023, 4:10 p.m. UTC | #11
Hi Laurent,

Le vendredi 02 juin 2023 à 08:19 +0300, Laurent Pinchart a écrit :
> For libcamerasrc, I don't know if the same reasoning should lead to the
> same result, or if we should consider that the vast majority of use
> cases for the GStreamer element call for enabling auto-focus by default.
> I currently side towards doing the same as in the libcamera core, as I
> believe it would be confusing for users to have different default
> behaviours when using libcamera through different adaptation layers.
> However, I could also imagine enabling auto-focus by default in the V4L2
> adaptation layer for instance, as that layer is mostly meant to expose
> libcamera-based cameras as webcams.
> 

I like to decide based on what the users get by default. A mimic of what a
webcam usually do seems logical. What do you get in the simplest form of usage
of the software (in GStreamer this means if you just plug and start the element:
libcamerasrc ! ...).

Not enabling it (or not setting the lense to a decent default position) on HW
that needs to be focused means most of the time you'll just get a bad output.
This impose more complexity on the application. Being a low level library does
not imply it have to be difficult across multiple type of cameras. Its no more
effort to disable then to enable it either.

Of course, this can either happen in libcamera or in libcamerasrc element, that
I don't care so much. I don't have the full portrait on auto-focus quality atm
to judge if now is the time either, and which type of auto focus we should
enable vs which one we should definitely avoid as it would make things worst. I
would certainly not rush into "getting something" for that reason. But for sure,
the design principle for the gstreamer element (and same will apply for the
pipewire one) is that it goes from really simple to full control, and nothing
special should be done to get a good image. This is mostly the reason why the
element assume you can always use the cameras with a single stream (hopefully
this will stay true ;-P). So assuming auto-focus feature actually works (I have
no mean to verify), enabling it would mean it behaves similar to what webcam do.

Nicolas
Laurent Pinchart June 5, 2023, 7:33 a.m. UTC | #12
Hi Cedric,

On Fri, Jun 02, 2023 at 03:53:03PM +0200, Cedric Nugteren wrote:
> I have fixed the review comments and have installed and configured git
> send-email.

Thank you. That appears to have gone well as your new version hasn't
been mangled by mail clients and/or servers :-)

> However, apparently it started a new thread, I don't think that
> is what it should have done:
> https://lists.libcamera.org/pipermail/libcamera-devel/2023-May/037925.html
> (I used "git send-email --in-reply-to=037947 --to=
> libcamera-devel@lists.libcamera.org patch_file.patch")

The --in-reply-to argument takes a Message-ID. The 037947 number you've
used is the index from the mailing list archives. The Message-ID of your
original e-mail was
CAM6JzGDQMvPaOJfvUGy286PhM5oUvyxSkWWq8YFvmKoW1T0Rfw@mail.gmail.com (you
can find it by checking the mail headers in your sent folder, or in
patchwork at https://patchwork.libcamera.org/patch/18651/).

This being said, new versions of a patch or patch series are not
supposed to be sent as a replies to the previous version, so all is fine
:-)

> Also, you mentioned that would like to see the original patch better
> formatted. Should I just create a whole new patch altogether?

When submitting a new version of a patch, you should, well, submit a new
version of the patch :-) The patch you have sent, titled "[PATCH] Apply
review suggestions" is not a new version of the original patch, but a
set of changes that apply on top. As the original patch won't be merged,
you should instead send a v2 stemming from v1 and incorporating the
changes requested during review.

In git's terms, that means that the changes you've made to v1 should be
squashed into the original commit (`git commit --amend`), not committed
as a separate commit. When generating the patch with git-format-patch,
you can pass the `-v2` argument to record the version number in the
subject line (you can also do so manually by editing the patch file, but
that's more error-prone).

A nice thing to do when sending new versions is to include a changelog.
See https://patchwork.libcamera.org/patch/18699/ for instance, and note
the 'Changes since v1:' section under the '---'. This is something you
can include directly in the commit message in your git tree, by adding a
'---' marker below the tags (Signed-off-by & co.), and recording the
changelog there. This helps reviewers understanding what has changed
between patch versions.

I've marked "[PATCH] Apply review suggestions" as "changes requested" in
patchwork. Could you submit a real v2 of this patch ?

> Finally, about the default/non-default discussion, I was trying to be
> conservative here, because when I opened the original bug (#188), the reply
> I got sounded like you thought it was a missing feature rather than a bug.
> For me this is a blocking bug: I can't use the PiCamV3 at all due to random
> focus behaviour. So therefore I opted for keeping the default behaviour as
> it was before to make it more likely that this patch will be accepted.

I'm tempted to default to disabling auto-focus. The discussion is still
ongoing though, but that shouldn't block you. You can send a v2 with
auto-focus disabled by default, and we can easily switch the default on
top if desired.

> On Fri, Jun 2, 2023 at 7:19 AM Laurent Pinchart wrote:
> > On Thu, Jun 01, 2023 at 12:24:22PM -0400, Nicolas Dufresne wrote:
> > > Le jeudi 01 juin 2023 à 08:39 +0100, Naushir Patuck a écrit :
> > > > > If you have any idea what the default should be in the GStreamer
> > > > > element, please feel free to chime in :-)
> > > >
> > > > Perhaps GStreamer should do nothing with focus by default and rely on the IPA
> > > > default behaviour (i.e. go to hyperfocal)?  This then relies on the application
> > > > to choose what it wants to do on startup, just like any other application that
> > > > directly uses libcamera.
> > >
> > > To reassure you, it can't be worse then what most UVC camera do today. Having a
> > > default matching this would help consistency though (or being similarly bad from
> > > some point of view). Later, on top, there should be ways to move to a more
> > > manual control in focus aware Gst applications.
> >
> > Hmmmm... I'm really in two minds here.
> >
> > First of all, we can't expect the same default behaviour for all cameras
> > when it comes to auto-focus, simply because many cameras don't have a
> > controllable focus lens, and some (I'm thinking about UVC devices here)
> > may not have the ability to turn auto-focus on. Still, implementing
> > consistent defaults where possible is a goal I highly value, in order to
> > maximize application portability.
> >
> > When it comes to the libcamera core, setting the focus lens to the
> > hyperfocal distance and disabling auto-focus seems like a good default
> > to me. Different use cases would favour different defaults, and I don't
> > think there's one particular use case that could be considered so
> > prevalent that it would call for enabling continuous auto-focus by
> > default. Different defaults could however be implemented in different
> > layers. For instance, I could imagine PipeWire deciding to enabling
> > continuous auto-focus by default on desktop or mobile systems.
> >
> > For libcamerasrc, I don't know if the same reasoning should lead to the
> > same result, or if we should consider that the vast majority of use
> > cases for the GStreamer element call for enabling auto-focus by default.
> > I currently side towards doing the same as in the libcamera core, as I
> > believe it would be confusing for users to have different default
> > behaviours when using libcamera through different adaptation layers.
> > However, I could also imagine enabling auto-focus by default in the V4L2
> > adaptation layer for instance, as that layer is mostly meant to expose
> > libcamera-based cameras as webcams.

Patch
diff mbox series

diff --git a/src/gstreamer/gstlibcameraprovider.cpp
b/src/gstreamer/gstlibcameraprovider.cpp
index 6eb0a0eb..86fa2542 100644
--- a/src/gstreamer/gstlibcameraprovider.cpp
+++ b/src/gstreamer/gstlibcameraprovider.cpp
@@ -31,6 +31,7 @@  GST_DEBUG_CATEGORY_STATIC(provider_debug);

 enum {
  PROP_DEVICE_NAME = 1,
+ PROP_ENABLE_AUTO_FOCUS = 2,
 };

 #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
@@ -40,6 +41,7 @@  G_DECLARE_FINAL_TYPE(GstLibcameraDevice,
gst_libcamera_device,
 struct _GstLibcameraDevice {
  GstDevice parent;
  gchar *name;
+ gboolean enable_auto_focus = false;
 };

 G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
@@ -56,6 +58,7 @@  gst_libcamera_device_create_element(GstDevice *device,
const gchar *name)
  g_assert(source);

  g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
nullptr);
+ g_object_set(source, "enable-auto-focus",
GST_LIBCAMERA_DEVICE(device)->enable_auto_focus, nullptr);

  return source;
 }
@@ -68,6 +71,7 @@  gst_libcamera_device_reconfigure_element(GstDevice
*device,
  return FALSE;

  g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name,
nullptr);
+ g_object_set(element, "enable-auto-focus",
GST_LIBCAMERA_DEVICE(device)->enable_auto_focus, nullptr);

  return TRUE;
 }
@@ -82,6 +86,9 @@  gst_libcamera_device_set_property(GObject *object, guint
prop_id,
  case PROP_DEVICE_NAME:
  device->name = g_value_dup_string(value);
  break;
+ case PROP_ENABLE_AUTO_FOCUS:
+ device->enable_auto_focus = g_value_get_boolean(value);
+ break;
  default:
  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  break;
@@ -121,6 +128,12 @@ 
gst_libcamera_device_class_init(GstLibcameraDeviceClass *klass)
  (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE |
       G_PARAM_CONSTRUCT_ONLY));
  g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec);
+ GParamSpec *spec2 = g_param_spec_boolean("enable-auto-focus",
+                        "Enable auto-focus",
+                        "Enable auto-focus if set to true, "
+                        "disable it if set to false",
+                         FALSE, G_PARAM_WRITABLE);
+ g_object_class_install_property(object_class, PROP_ENABLE_AUTO_FOCUS,
spec2);
 }

 static GstDevice *
diff --git a/src/gstreamer/gstlibcamerasrc.cpp
b/src/gstreamer/gstlibcamerasrc.cpp
index a10cbd4f..672ea38a 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -146,6 +146,7 @@  struct _GstLibcameraSrc {
  GstTask *task;

  gchar *camera_name;
+ gboolean enable_auto_focus = false;

  GstLibcameraSrcState *state;
  GstLibcameraAllocator *allocator;
@@ -154,7 +155,8 @@  struct _GstLibcameraSrc {

 enum {
  PROP_0,
- PROP_CAMERA_NAME
+ PROP_CAMERA_NAME,
+ PROP_ENABLE_AUTO_FOCUS,
 };

 G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src,