{"id":2897,"url":"https://patchwork.libcamera.org/api/patches/2897/?format=json","web_url":"https://patchwork.libcamera.org/patch/2897/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20200227200407.490616-16-nicolas.dufresne@collabora.com>","date":"2020-02-27T20:03:55","name":"[libcamera-devel,v2,15/27] gst: libcamerasrc: Implement minimal caps negotiation","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"aa8eec9ad8edea7b5c584bc29322f10c67dcf5f0","submitter":{"id":31,"url":"https://patchwork.libcamera.org/api/people/31/?format=json","name":"Nicolas Dufresne","email":"nicolas.dufresne@collabora.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/2897/mbox/","series":[{"id":693,"url":"https://patchwork.libcamera.org/api/series/693/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=693","date":"2020-02-27T20:03:40","name":"GStreamer Element for libcamera","version":2,"mbox":"https://patchwork.libcamera.org/series/693/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/2897/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/2897/checks/","tags":{},"headers":{"Return-Path":"<nicolas.dufresne@collabora.com>","Received":["from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EC1A8626F6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 27 Feb 2020 21:04:24 +0100 (CET)","from [127.0.0.1] (localhost [127.0.0.1])\n\t(Authenticated sender: nicolas) with ESMTPSA id 81D9329654A"],"From":"Nicolas Dufresne <nicolas.dufresne@collabora.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Thu, 27 Feb 2020 15:03:55 -0500","Message-Id":"<20200227200407.490616-16-nicolas.dufresne@collabora.com>","X-Mailer":"git-send-email 2.24.1","In-Reply-To":"<20200227200407.490616-1-nicolas.dufresne@collabora.com>","References":"<20200227200407.490616-1-nicolas.dufresne@collabora.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v2 15/27] gst: libcamerasrc: Implement\n\tminimal caps negotiation","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":"Thu, 27 Feb 2020 20:04:25 -0000"},"content":"This is not expected to work in every possible cases, but should be sufficient as\nan initial implementation. What is does is that it turns the StreamFormats into\ncaps and queries downstream caps with that as a filter.\n\nThe result is the subset of caps that can be used. We then keep the first\nstructure in that result and fixate using the default values found in\nStreamConfiguration as a default in case a range is available.\n\nWe then validate this configuration and turn the potentially modified\nconfiguration into caps that we push downstream. Note that we trust the order\nin StreamFormats as being sorted best first, but this is not currently in\nlibcamera. A todo has been added in the head of this file as a reminder to fix\nthat in the core.\n\nSigned-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n---\n src/gstreamer/gstlibcamerasrc.cpp | 82 ++++++++++++++++++++++++++++++-\n 1 file changed, 81 insertions(+), 1 deletion(-)","diff":"diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\nindex e2c63d1..2c5c34c 100644\n--- a/src/gstreamer/gstlibcamerasrc.cpp\n+++ b/src/gstreamer/gstlibcamerasrc.cpp\n@@ -6,6 +6,12 @@\n  * gstlibcamerasrc.cpp - GStreamer Capture Element\n  */\n \n+/**\n+ * \\todo libcamera UVC drivers picks the lowest possible resolution first, this\n+ * should be fixed so that we get a decent resolution and framerate for the\n+ * role by default.\n+ */\n+\n #include \"gstlibcamera-utils.h\"\n #include \"gstlibcamerapad.h\"\n #include \"gstlibcamerasrc.h\"\n@@ -23,6 +29,7 @@ GST_DEBUG_CATEGORY_STATIC(source_debug);\n struct GstLibcameraSrcState {\n \tstd::unique_ptr<CameraManager> cm;\n \tstd::shared_ptr<Camera> cam;\n+\tstd::unique_ptr<CameraConfiguration> config;\n \tstd::vector<GstPad *> srcpads;\n };\n \n@@ -131,16 +138,89 @@ gst_libcamera_src_task_enter(GstTask *task, GThread *thread, gpointer user_data)\n \tGstLibcameraSrc *self = GST_LIBCAMERA_SRC(user_data);\n \tGLibRecLocker(&self->stream_lock);\n \tGstLibcameraSrcState *state = self->state;\n+\tGstFlowReturn flow_ret = GST_FLOW_OK;\n \n \tGST_DEBUG_OBJECT(self, \"Streaming thread has started\");\n \n \tguint group_id = gst_util_group_id_next();\n+\tStreamRoles roles;\n \tfor (GstPad *srcpad : state->srcpads) {\n-\t\t/* Create stream-id and push stream-start */\n+\t\t/* Create stream-id and push stream-start .*/\n \t\tg_autofree gchar *stream_id = gst_pad_create_stream_id(srcpad, GST_ELEMENT(self), nullptr);\n \t\tGstEvent *event = gst_event_new_stream_start(stream_id);\n \t\tgst_event_set_group_id(event, group_id);\n \t\tgst_pad_push_event(srcpad, event);\n+\n+\t\t/* Collect the streams roles for the next iteration .*/\n+\t\troles.push_back(gst_libcamera_pad_get_role(srcpad));\n+\t}\n+\n+\t/* Generate the stream configurations, there should be one per pad .*/\n+\tstate->config = state->cam->generateConfiguration(roles);\n+\t/* \\todo Check if camera may increase or decrease the number of streams\n+\t * regardless of the number of roles.*/\n+\tg_assert(state->config->size() == state->srcpads.size());\n+\n+\tfor (gsize i = 0; i < state->srcpads.size(); i++) {\n+\t\tGstPad *srcpad = state->srcpads[i];\n+\t\tStreamConfiguration &stream_cfg = state->config->at(i);\n+\n+\t\t/* Retrieve the supported caps. */\n+\t\tg_autoptr(GstCaps) filter = gst_libcamera_stream_formats_to_caps(stream_cfg.formats());\n+\t\tg_autoptr(GstCaps) caps = gst_pad_peer_query_caps(srcpad, filter);\n+\t\tif (gst_caps_is_empty(caps)) {\n+\t\t\tflow_ret = GST_FLOW_NOT_NEGOTIATED;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Fixate caps and configure the stream. */\n+\t\tcaps = gst_caps_make_writable(caps);\n+\t\tgst_libcamera_configure_stream_from_caps(stream_cfg, caps);\n+\t}\n+\n+\tif (flow_ret != GST_FLOW_OK)\n+\t\tgoto done;\n+\n+\t/* Validate the configuration. */\n+\tif (state->config->validate() == CameraConfiguration::Invalid) {\n+\t\tflow_ret = GST_FLOW_NOT_NEGOTIATED;\n+\t\tgoto done;\n+\t}\n+\n+\t/*\n+\t * Regardless if it has been modified, create clean caps and push the\n+\t * caps event. Downstream will decide if the caps are acceptable.\n+\t */\n+\tfor (gsize i = 0; i < state->srcpads.size(); i++) {\n+\t\tGstPad *srcpad = state->srcpads[i];\n+\t\tconst StreamConfiguration &stream_cfg = state->config->at(i);\n+\n+\t\tg_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg);\n+\t\tif (!gst_pad_push_event(srcpad, gst_event_new_caps(caps))) {\n+\t\t\tflow_ret = GST_FLOW_NOT_NEGOTIATED;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t{\n+\t\tgint ret = state->cam->configure(state->config.get());\n+\t\tif (ret) {\n+\t\t\tGST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,\n+\t\t\t\t\t  (\"Failed to configure camera: %s\", g_strerror(-ret)),\n+\t\t\t\t\t  (\"Camera::configure() failed with error code %i\", ret));\n+\t\t\tgst_task_stop(task);\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\n+done:\n+\tswitch (flow_ret) {\n+\tcase GST_FLOW_NOT_NEGOTIATED:\n+\t\tGST_ELEMENT_FLOW_ERROR(self, flow_ret);\n+\t\tgst_task_stop(task);\n+\t\treturn;\n+\tdefault:\n+\t\tbreak;\n \t}\n }\n \n","prefixes":["libcamera-devel","v2","15/27"]}