[{"id":3864,"web_url":"https://patchwork.libcamera.org/comment/3864/","msgid":"<20200229134321.GK18738@pendragon.ideasonboard.com>","date":"2020-02-29T13:43:21","subject":"Re: [libcamera-devel] [PATCH v2 09/27] gst: libcamerasrc: Implement\n\tselection and acquisition","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Nicolas,\n\nThank you for the patch.\n\nOn Thu, Feb 27, 2020 at 03:03:49PM -0500, Nicolas Dufresne wrote:\n> This add code to select and acquire a camera. With this, it is now\n\ns/add/adds/\n\n> possible to run pipeline like:\n\ns/pipeline/a pipeline/ or s/pipeline/pipelines/\n\n> \n>    gst-launch-1.0 libcamerasrc ! fakesink\n> \n> Though no buffer will be streamed yet. In this function, we implement the\n> change_state() virtual method to trigger actions on specific state transitions.\n> Note that we also return GST_STATE_CHANGE_NO_PREROLL in\n> GST_STATE_CHANGE_READY_TO_PAUSED and GST_STATE_CHANGE_PLAYING_TO_PAUSED\n> transitions as this is required for all live sources.\n> \n> Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> ---\n>  src/gstreamer/gstlibcamerasrc.cpp | 125 ++++++++++++++++++++++++++++++\n>  1 file changed, 125 insertions(+)\n> \n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index c993143..0c60478 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -10,13 +10,26 @@\n>  #include \"gstlibcamerapad.h\"\n>  #include \"gstlibcamerasrc.h\"\n>  \n> +#include <libcamera/camera.h>\n> +#include <libcamera/camera_manager.h>\n> +\n> +using namespace libcamera;\n> +\n>  GST_DEBUG_CATEGORY_STATIC(source_debug);\n>  #define GST_CAT_DEFAULT source_debug\n>  \n> +/* Used for C++ object with destructors. */\n> +struct GstLibcameraSrcState {\n> +\tstd::unique_ptr<CameraManager> cm;\n> +\tstd::shared_ptr<Camera> cam;\n> +};\n> +\n>  struct _GstLibcameraSrc {\n>  \tGstElement parent;\n>  \tGstPad *srcpad;\n>  \tgchar *camera_name;\n> +\n> +\tGstLibcameraSrcState *state;\n>  };\n>  \n>  enum {\n> @@ -40,6 +53,83 @@ GstStaticPadTemplate request_src_template = {\n>  \t\"src_%s\", GST_PAD_SRC, GST_PAD_REQUEST, TEMPLATE_CAPS\n>  };\n>  \n> +static bool\n> +gst_libcamera_src_open(GstLibcameraSrc *self)\n> +{\n> +\tstd::unique_ptr<CameraManager> cm = std::make_unique<CameraManager>();\n> +\tstd::shared_ptr<Camera> cam;\n> +\tgint ret = 0;\n> +\n> +\tGST_DEBUG_OBJECT(self, \"Opening camera device ...\");\n> +\n> +\tret = cm->start();\n> +\tif (ret) {\n> +\t\tGST_ELEMENT_ERROR(self, LIBRARY, INIT,\n> +\t\t\t\t  (\"Failed listing cameras.\"),\n> +\t\t\t\t  (\"libcamera::CameraMananger::start() failed: %s\", g_strerror(-ret)));\n> +\t\treturn false;\n> +\t}\n> +\n> +\tg_autofree gchar *camera_name = nullptr;\n> +\t{\n> +\t\tGLibLocker lock(GST_OBJECT(self));\n> +\t\tif (self->camera_name)\n> +\t\t\tcamera_name = g_strdup(self->camera_name);\n> +\t}\n> +\n> +\tif (camera_name) {\n> +\t\tcam = cm->get(self->camera_name);\n> +\t\tif (!cam) {\n> +\t\t\tGST_ELEMENT_ERROR(self, RESOURCE, NOT_FOUND,\n> +\t\t\t\t\t  (\"Could not find a camera named '%s'.\", self->camera_name),\n> +\t\t\t\t\t  (\"libcamera::CameraMananger::get() returned nullptr\"));\n> +\t\t\treturn false;\n> +\t\t}\n> +\t} else {\n> +\t\tif (cm->cameras().empty()) {\n> +\t\t\tGST_ELEMENT_ERROR(self, RESOURCE, NOT_FOUND,\n> +\t\t\t\t\t  (\"Could not find any supported camera on this system.\"),\n> +\t\t\t\t\t  (\"libcamera::CameraMananger::cameras() is empty\"));\n> +\t\t\treturn false;\n> +\t\t}\n> +\t\tcam = cm->cameras()[0];\n> +\t}\n> +\n> +\tGST_INFO_OBJECT(self, \"Using camera named '%s'\", cam->name().c_str());\n> +\n> +\tret = cam->acquire();\n> +\tif (ret) {\n> +\t\tGST_ELEMENT_ERROR(self, RESOURCE, BUSY,\n> +\t\t\t\t  (\"Camera name '%s' is already in use.\", cam->name().c_str()),\n> +\t\t\t\t  (\"libcamera::Camera::acquire() failed: %s\", g_strerror(ret)));\n> +\t\treturn false;\n> +\t}\n> +\n> +\t/* No need to lock here, we didn't start our threads yet. */\n> +\tself->state->cm = std::move(cm);\n> +\tself->state->cam = cam;\n> +\n> +\treturn true;\n> +}\n> +\n> +static void\n> +gst_libcamera_src_close(GstLibcameraSrc *self)\n> +{\n> +\tGstLibcameraSrcState *state = self->state;\n> +\tgint ret;\n> +\n> +\tret = state->cam->release();\n> +\tif (ret) {\n> +\t\tGST_ELEMENT_WARNING(self, RESOURCE, BUSY,\n> +\t\t\t\t    (\"Camera name '%s' is still in use.\", state->cam->name().c_str()),\n> +\t\t\t\t    (\"libcamera::Camera.release() failed: %s\", g_strerror(-ret)));\n> +\t}\n> +\n> +\tstate->cam.reset();\n> +\tstate->cm->stop();\n> +\tstate->cm.reset();\n> +}\n> +\n>  static void\n>  gst_libcamera_src_set_property(GObject *object, guint prop_id,\n>  \t\t\t       const GValue *value, GParamSpec *pspec)\n> @@ -75,6 +165,36 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,\n>  \t}\n>  }\n>  \n> +static GstStateChangeReturn\n> +gst_libcamera_src_change_state(GstElement *element, GstStateChange transition)\n> +{\n> +\tGstLibcameraSrc *self = GST_LIBCAMERA_SRC(element);\n> +\tGstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;\n> +\tGstElementClass *klass = GST_ELEMENT_CLASS(gst_libcamera_src_parent_class);\n> +\n> +\tret = klass->change_state(element, transition);\n> +\tif (ret == GST_STATE_CHANGE_FAILURE)\n> +\t\treturn ret;\n> +\n> +\tswitch (transition) {\n> +\tcase GST_STATE_CHANGE_NULL_TO_READY:\n> +\t\tif (!gst_libcamera_src_open(self))\n> +\t\t\treturn GST_STATE_CHANGE_FAILURE;\n> +\t\tbreak;\n> +\tcase GST_STATE_CHANGE_READY_TO_PAUSED:\n> +\tcase GST_STATE_CHANGE_PLAYING_TO_PAUSED:\n> +\t\tret = GST_STATE_CHANGE_NO_PREROLL;\n> +\t\tbreak;\n> +\tcase GST_STATE_CHANGE_READY_TO_NULL:\n> +\t\tgst_libcamera_src_close(self);\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tbreak;\n> +\t}\n> +\n> +\treturn ret;\n> +}\n> +\n>  static void\n>  gst_libcamera_src_finalize(GObject *object)\n>  {\n> @@ -82,6 +202,7 @@ gst_libcamera_src_finalize(GObject *object)\n>  \tGstLibcameraSrc *self = GST_LIBCAMERA_SRC(object);\n>  \n>  \tg_free(self->camera_name);\n> +\tdelete self->state;\n>  \n>  \treturn klass->finalize(object);\n>  }\n> @@ -89,10 +210,12 @@ gst_libcamera_src_finalize(GObject *object)\n>  static void\n>  gst_libcamera_src_init(GstLibcameraSrc *self)\n>  {\n> +\tGstLibcameraSrcState *state = new GstLibcameraSrcState();\n>  \tGstPadTemplate *templ = gst_element_get_pad_template(GST_ELEMENT(self), \"src\");\n>  \n>  \tself->srcpad = gst_pad_new_from_template(templ, \"src\");\n>  \tgst_element_add_pad(GST_ELEMENT(self), self->srcpad);\n> +\tself->state = state;\n>  }\n>  \n>  static void\n> @@ -105,6 +228,8 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>  \tobject_class->get_property = gst_libcamera_src_get_property;\n>  \tobject_class->finalize = gst_libcamera_src_finalize;\n>  \n> +\telement_class->change_state = gst_libcamera_src_change_state;\n> +\n>  \tgst_element_class_set_metadata(element_class,\n>  \t\t\t\t       \"libcamera Source\", \"Source/Video\",\n>  \t\t\t\t       \"Linux Camera source using libcamera\",","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 72D7662689\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 29 Feb 2020 14:43:45 +0100 (CET)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D41FE2AF;\n\tSat, 29 Feb 2020 14:43:44 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1582983825;\n\tbh=8JhAwK/3fqXz3SqgFgWRhSVYJg8zGn1Kb55QCJeNeaU=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=raSZtCH6gIchQRxn6ftUeXnKwdf4ElqVYvy+lXI0bvtIfT61yZDtPIdJPZlc9bF8U\n\tZv5G98+Z5nFjxHW8yBnDyJm7UFnIqHT5DGzhlqhQaTPQsxQtJuSmthdrFiu/yt2nnm\n\tgINYN4f3tiuJTyVlV9NPucVrwwoYiUwOItE7ZTz0=","Date":"Sat, 29 Feb 2020 15:43:21 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Nicolas Dufresne <nicolas.dufresne@collabora.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20200229134321.GK18738@pendragon.ideasonboard.com>","References":"<20200227200407.490616-1-nicolas.dufresne@collabora.com>\n\t<20200227200407.490616-10-nicolas.dufresne@collabora.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20200227200407.490616-10-nicolas.dufresne@collabora.com>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v2 09/27] gst: libcamerasrc: Implement\n\tselection and acquisition","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Sat, 29 Feb 2020 13:43:45 -0000"}}]