Patch Detail
Show a patch.
GET /api/1.1/patches/17307/?format=api
{ "id": 17307, "url": "https://patchwork.libcamera.org/api/1.1/patches/17307/?format=api", "web_url": "https://patchwork.libcamera.org/patch/17307/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20220907104711.87365-1-rishikeshdonadkar@gmail.com>", "date": "2022-09-07T10:47:11", "name": "[libcamera-devel,v3] gstreamer: Provide framerate support for libcamerasrc.", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "111181169ecac9609bf7a9e5e79af8b474e45b31", "submitter": { "id": 118, "url": "https://patchwork.libcamera.org/api/1.1/people/118/?format=api", "name": "Rishikesh Donadkar", "email": "rishikeshdonadkar@gmail.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/17307/mbox/", "series": [ { "id": 3474, "url": "https://patchwork.libcamera.org/api/1.1/series/3474/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3474", "date": "2022-09-07T10:47:11", "name": "[libcamera-devel,v3] gstreamer: Provide framerate support for libcamerasrc.", "version": 3, "mbox": "https://patchwork.libcamera.org/series/3474/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/17307/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/17307/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 5DCD8C3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 7 Sep 2022 10:47:51 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8089462089;\n\tWed, 7 Sep 2022 12:47:50 +0200 (CEST)", "from mail-pl1-x62a.google.com (mail-pl1-x62a.google.com\n\t[IPv6:2607:f8b0:4864:20::62a])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A319962054\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 7 Sep 2022 12:47:48 +0200 (CEST)", "by mail-pl1-x62a.google.com with SMTP id d12so14106438plr.6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 07 Sep 2022 03:47:48 -0700 (PDT)", "from localhost.localdomain ([49.36.97.234])\n\tby smtp.googlemail.com with ESMTPSA id\n\ti12-20020a17090a718c00b001fb53587166sm10740195pjk.28.2022.09.07.03.47.44\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 07 Sep 2022 03:47:46 -0700 (PDT)" ], "DKIM-Signature": [ "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1662547670;\n\tbh=MD6iEn/PzDOxiKbgw8pr9IsDc4/Ge8yrKofBx1o6f0k=;\n\th=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post:\n\tList-Help:List-Subscribe:From:Reply-To:Cc:From;\n\tb=0tRMt3RI/ff8LtP0fSjHBBZo6+mIxJ2HiWNYiLy8LM6sdmRVS8VskPzMBdeBUYVZg\n\t8R8wCsQ1ugdFVaVLX2WsbroVwzxWsX3DRmNHHDwHcYotxNlXSpHuTSf5WPBsgqpwda\n\tsBzql7xwXdctoNbdfkPHMXHG5KQHsD5wx3DXF3mWrBC0UtJN3497BrbnDN+gFHXKYF\n\tZQkSytAyr/9ngFAAZcvj675oLwH3iMxNQYpRkFOOo2uRVQFokh/8NJyRmflLo+Xjrw\n\tfaT7VsN2ogf6qSMisynNZZ41Vr8k7/bFlaiEWYbkDZbTbgM3PbFyu/KnH0apGf9uCl\n\tOlyv6NuJoIRbg==", "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;\n\th=content-transfer-encoding:mime-version:message-id:date:subject:cc\n\t:to:from:from:to:cc:subject:date;\n\tbh=p3UdO2wpyy8sTPCCVQ3jEp2DE7Vtjrn4FfUb3UR9EJk=;\n\tb=QJJEdmq82Nk8PZ7QTyVhKI6O94/MIIuO4k5c0xkqmj5JswVvtwQMKvHk8t6lUP0+Fj\n\tmteW3DB4RLpHFKRXaewSkS5So1IRSMMeyTZMZUJvRlNxMN6PvD/LS65kMPcRSyZClnoA\n\tuAs+xC3PX1kgTsMLf8ic+zBrwPtt9T6hLBdHxyXbb+qnLu06Xft8j/5J+exXDaWA/zfv\n\tLusZsigTYbzCMUrvflkBcHom4of24ptPqn7Wf22sq3CI91XRVn3mETaHcV1Rctji12WM\n\tmYXPfi5xYOOjMDbXJE8meUwzAvITDYsy2O+fQBVYnErl1s8cybbUJFW7DkCx19OeMzH3\n\tPyeg==" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"QJJEdmq8\"; dkim-atps=neutral", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20210112;\n\th=content-transfer-encoding:mime-version:message-id:date:subject:cc\n\t:to:from:x-gm-message-state:from:to:cc:subject:date;\n\tbh=p3UdO2wpyy8sTPCCVQ3jEp2DE7Vtjrn4FfUb3UR9EJk=;\n\tb=1hH5qqh53Dxfd8tEYleygh+87bryUNxizG5Fsf1Wv+EUvL53PCUXbDv0cdCUT7zQKW\n\t/28zOhEripv6VJ9wMRgMzimdb69M/bTEqEXpXhoPRRynIvOvB1ywqGI/3sSKlCwPTNLW\n\twR8v81B4xRetUjZzW1MeuPsQa1R7IRduQGK5GATKJLN09FjBTyoFJEBVK2gJF7zvnaoM\n\ttl6ZeT3OBY5uZ4i3wqFrgbu+8r6x/Fyv2DXnuc9Yt6QW5dBmFB3JuiS5aBBkQqSi+gnc\n\t2ldUPebRyYoyaRpSTg3gyU4U+w0u0I5HoiiChFzqpOm/MlwlwAVCw9GTB8ERHo4f+PLn\n\twP+Q==", "X-Gm-Message-State": "ACgBeo248NjZrH+83j0IljMoHDaLoI873umPgTRJo9bSy0NTz6QUwbeX\n\tMAeqZQ/gpxqr2VXtghbH6G2Fjhxsj6wyYQ==", "X-Google-Smtp-Source": "AA6agR42EQHZVBOKe3cGXV5OwLwubDT6t5XAOL8KSKLVy4Ddl6VvcYN3O8J/n1WM4gDGk0A5b+gHZg==", "X-Received": "by 2002:a17:902:9887:b0:172:7090:6485 with SMTP id\n\ts7-20020a170902988700b0017270906485mr3354103plp.63.1662547666714; \n\tWed, 07 Sep 2022 03:47:46 -0700 (PDT)", "To": "libcamera-devel@lists.libcamera.org", "Date": "Wed, 7 Sep 2022 16:17:11 +0530", "Message-Id": "<20220907104711.87365-1-rishikeshdonadkar@gmail.com>", "X-Mailer": "git-send-email 2.25.1", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v3] gstreamer: Provide framerate support\n\tfor libcamerasrc.", "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>", "From": "Rishikesh Donadkar via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>", "Reply-To": "Rishikesh Donadkar <rishikeshdonadkar@gmail.com>", "Cc": "Rishikesh Donadkar <rishikeshdonadkar@gmail.com>,\n\tnicolas.dufresne@collabora.com, vedantparanjape160201@gmail.com", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Add a field of the type ControlList to GstLibcameraSrcState.\n\nGet the framerate from the caps and convert it to FrameDuration.\nSet the FrameDurationLimits control in the initControls_\n\nPassing initControls_ at camera::start() doesn't tell us if the controls\nhave been applied to the camera successfully or not (or they have adjusted in\nsome fashion). Until that is introduced in camera::start() API,\nwe need to carry out such handling on the application side.\n\nCheck the frame_duration whether it is in-bound to the max / min\nframe-duration supported by the camera using the function\ngst_libcamera_bind_framerate().\n\nIf the frame_duartion is out of bounds, bind the frame_duration\nbetween the max and min FrameDuration that is supported by the camera.\n\nPass the initControls_ at the time of starting camera.\n\nSolve the complications in exposing the correct framerate due to loss in\nprecision as a result of casting the frameduration to int64_t(which is\nrequired in libcamera to set the FrameDurationLimits control).\n\nExample -\n\n* Suppose the framerate requested is 35/1. The framerate is read form\n the caps in the from of fraction that has a numerator and\n denominator.\n\n* Converting to FrameDuration (in microseconds)\n (1 * 10^6) / 35 = 28571.4286\n int64_t frame_duration = 28571\n (the precision here is lost.)\n* To expose the framerate in caps, Inverting the frame_duration to get\n back the framerate and converting to Seconds.\n double framerate = 10^6 / 28571\n and\n 10^6/28571 which is close but not equal to 35/1 will fail the negotiation.\n\nTo solve the above problem, Store the framerate requested through\nnegotiated caps in the GValue of the type GST_TYPE_FRACTION.\n\nTry to apply the framerate and check if the floor value of framerate that gets applied\nclosely matches with the floor value framerate requested in the negotiated caps. If\nthe value matches expose the framerate that is stored in the framerate_container, else expose\nthe framerate in the new caps as 0/1.\n\nPass the initControls_ at camera->start().\n\n---\nChanges from v1 to v2\n* Use GValue of the type GST_TYPE_FRACTION instead of std::pair to store the framerate.\n* Don't shift the call to camera->configure(), instead bound the framerate \n after the call to camera->configure().\n* Reset the FrameDurationLimits control only if it is out of bounds.\n* Expose the caps containing framerate information with a new CAPS event\n after the call to camera->configure().\n---\n\nSigned-off-by: Umang Jain <umang.jain@ideasonboard.com>\nSigned-off-by: Rishikesh Donadkar <rishikeshdonadkar@gmail.com>\n---\n src/gstreamer/gstlibcamera-utils.cpp | 116 +++++++++++++++++++++++++++\n src/gstreamer/gstlibcamera-utils.h | 8 ++\n src/gstreamer/gstlibcamerasrc.cpp | 28 ++++++-\n 3 files changed, 151 insertions(+), 1 deletion(-)", "diff": "diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\nindex 4df5dd6c..e862f7ea 100644\n--- a/src/gstreamer/gstlibcamera-utils.cpp\n+++ b/src/gstreamer/gstlibcamera-utils.cpp\n@@ -8,6 +8,7 @@\n \n #include \"gstlibcamera-utils.h\"\n \n+#include <libcamera/control_ids.h>\n #include <libcamera/formats.h>\n \n using namespace libcamera;\n@@ -405,6 +406,121 @@ gst_libcamera_configure_stream_from_caps(StreamConfiguration &stream_cfg,\n \t}\n }\n \n+void\n+gst_libcamera_get_init_controls_from_caps(ControlList &controls, [[maybe_unused]] GstCaps *caps,\n+\t\t\t\t\t GValue *framerate_container)\n+{\n+\tGstStructure *s = gst_caps_get_structure(caps, 0);\n+\tgint fps_n = -1, fps_d = -1;\n+\n+\tif (gst_structure_has_field_typed(s, \"framerate\", GST_TYPE_FRACTION)) {\n+\t\tif (!gst_structure_get_fraction(s, \"framerate\", &fps_n, &fps_d)) {\n+\t\t\tGST_WARNING(\"invalid framerate in the caps.\");\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\n+\tif (fps_n < 0 || fps_d < 0)\n+\t\treturn;\n+\n+\tgst_value_set_fraction(framerate_container, fps_n, fps_d);\n+\tint64_t frame_duration = (fps_d * 1000000.0) / fps_n;\n+\n+\tcontrols.set(controls::FrameDurationLimits,\n+\t\t Span<const int64_t, 2>({ frame_duration, frame_duration }));\n+}\n+\n+void\n+gst_libcamera_bind_framerate(const ControlInfoMap &camera_controls, ControlList &controls)\n+{\n+\tgboolean isBound = true;\n+\tauto iterFrameDuration = camera_controls.find(controls::FrameDurationLimits.id());\n+\n+\tif (!(iterFrameDuration != camera_controls.end() &&\n+\t controls.contains(controls::FRAME_DURATION_LIMITS)))\n+\t\treturn;\n+\n+\tint64_t frame_duration = controls.get(controls::FrameDurationLimits).value()[0];\n+\tint64_t min_frame_duration = iterFrameDuration->second.min().get<int64_t>();\n+\tint64_t max_frame_duration = iterFrameDuration->second.max().get<int64_t>();\n+\n+\tif (frame_duration < min_frame_duration) {\n+\t\tframe_duration = min_frame_duration;\n+\t} else if (frame_duration > max_frame_duration) {\n+\t\tframe_duration = max_frame_duration;\n+\t} else {\n+\t\tisBound = false;\n+\t}\n+\n+\tif (isBound)\n+\t\tcontrols.set(controls::FrameDurationLimits,\n+\t\t\t Span<const int64_t, 2>({ frame_duration, frame_duration }));\n+}\n+\n+gboolean\n+gst_libcamera_get_framerate_from_init_controls(const ControlList &controls, GValue *framerate,\n+\t\t\t\t\t GValue *framerate_container)\n+{\n+\tgint fps_caps_n, fps_caps_d, numerator, denominator;\n+\n+\tfps_caps_n = gst_value_get_fraction_numerator(framerate_container);\n+\tfps_caps_d = gst_value_get_fraction_denominator(framerate_container);\n+\n+\tif (!controls.contains(controls::FRAME_DURATION_LIMITS))\n+\t\treturn false;\n+\n+\tdouble framerate_ret = 1000000 / static_cast<double>(controls.get(controls::FrameDurationLimits).value()[0]);\n+\tgst_util_double_to_fraction(framerate_ret, &numerator, &denominator);\n+\tgst_value_set_fraction(framerate, numerator, denominator);\n+\n+\tif (fps_caps_n / fps_caps_d == numerator / denominator) {\n+\t\treturn true;\n+\t}\n+\treturn false;\n+}\n+\n+GstCaps *\n+gst_libcamera_init_controls_to_caps(const ControlList &controls, const StreamConfiguration &stream_cfg,\n+\t\t\t\t GValue *framerate_container)\n+{\n+\tGstCaps *caps = gst_caps_new_empty();\n+\tGstStructure *s = bare_structure_from_format(stream_cfg.pixelFormat);\n+\tgboolean ret;\n+\tGValue *framerate = g_new0(GValue, 1);\n+\tg_value_init(framerate, GST_TYPE_FRACTION);\n+\n+\tret = gst_libcamera_get_framerate_from_init_controls(controls, framerate, framerate_container);\n+\n+\tgst_structure_set(s,\n+\t\t\t \"width\", G_TYPE_INT, stream_cfg.size.width,\n+\t\t\t \"height\", G_TYPE_INT, stream_cfg.size.height,\n+\t\t\t nullptr);\n+\n+\tif (ret) {\n+\t\tgint numerator, denominator;\n+\t\tnumerator = gst_value_get_fraction_numerator(framerate_container);\n+\t\tdenominator = gst_value_get_fraction_denominator(framerate_container);\n+\t\tgst_structure_set(s, \"framerate\", GST_TYPE_FRACTION, numerator, denominator, nullptr);\n+\t} else {\n+\t\tgst_structure_set(s, \"framerate\", GST_TYPE_FRACTION, 0, 1, nullptr);\n+\t}\n+\n+\tif (stream_cfg.colorSpace) {\n+\t\tGstVideoColorimetry colorimetry = colorimetry_from_colorspace(stream_cfg.colorSpace.value());\n+\t\tgchar *colorimetry_str = gst_video_colorimetry_to_string(&colorimetry);\n+\n+\t\tif (colorimetry_str)\n+\t\t\tgst_structure_set(s, \"colorimetry\", G_TYPE_STRING, colorimetry_str, nullptr);\n+\t\telse\n+\t\t\tg_error(\"Got invalid colorimetry from ColorSpace: %s\",\n+\t\t\t\tColorSpace::toString(stream_cfg.colorSpace).c_str());\n+\t}\n+\n+\tgst_caps_append_structure(caps, s);\n+\tg_free(framerate);\n+\treturn caps;\n+}\n+\n #if !GST_CHECK_VERSION(1, 17, 1)\n gboolean\n gst_task_resume(GstTask *task)\ndiff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h\nindex 164189a2..955a717d 100644\n--- a/src/gstreamer/gstlibcamera-utils.h\n+++ b/src/gstreamer/gstlibcamera-utils.h\n@@ -9,6 +9,7 @@\n #pragma once\n \n #include <libcamera/camera_manager.h>\n+#include <libcamera/controls.h>\n #include <libcamera/stream.h>\n \n #include <gst/gst.h>\n@@ -18,6 +19,13 @@ GstCaps *gst_libcamera_stream_formats_to_caps(const libcamera::StreamFormats &fo\n GstCaps *gst_libcamera_stream_configuration_to_caps(const libcamera::StreamConfiguration &stream_cfg);\n void gst_libcamera_configure_stream_from_caps(libcamera::StreamConfiguration &stream_cfg,\n \t\t\t\t\t GstCaps *caps);\n+void gst_libcamera_get_init_controls_from_caps(libcamera::ControlList &controls,\n+\t\t\t\t\t GstCaps *caps, GValue *framerate_container);\n+void gst_libcamera_bind_framerate(const libcamera::ControlInfoMap &camera_controls,\n+\t\t\t\t libcamera::ControlList &controls);\n+GstCaps *gst_libcamera_init_controls_to_caps(const libcamera::ControlList &controls,\n+\t\t\t\t\t const libcamera::StreamConfiguration &streame_cfg, GValue *framerate_container);\n+\n #if !GST_CHECK_VERSION(1, 17, 1)\n gboolean gst_task_resume(GstTask *task);\n #endif\ndiff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\nindex 16d70fea..0c981357 100644\n--- a/src/gstreamer/gstlibcamerasrc.cpp\n+++ b/src/gstreamer/gstlibcamerasrc.cpp\n@@ -131,6 +131,7 @@ struct GstLibcameraSrcState {\n \tstd::queue<std::unique_ptr<RequestWrap>> completedRequests_\n \t\tLIBCAMERA_TSA_GUARDED_BY(lock_);\n \n+\tControlList initControls_;\n \tguint group_id_;\n \n \tint queueRequest();\n@@ -461,6 +462,8 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\n \tGstLibcameraSrcState *state = self->state;\n \tGstFlowReturn flow_ret = GST_FLOW_OK;\n \tgint ret;\n+\tGValue *framerate_container = g_new0(GValue, 1);\n+\tframerate_container = g_value_init(framerate_container, GST_TYPE_FRACTION);\n \n \tGST_DEBUG_OBJECT(self, \"Streaming thread has started\");\n \n@@ -496,6 +499,7 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\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+\n \t\tif (gst_caps_is_empty(caps)) {\n \t\t\tflow_ret = GST_FLOW_NOT_NEGOTIATED;\n \t\t\tbreak;\n@@ -504,6 +508,8 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\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\tgst_libcamera_get_init_controls_from_caps(state->initControls_, caps,\n+\t\t\t\t\t\t\t framerate_container);\n \t}\n \n \tif (flow_ret != GST_FLOW_OK)\n@@ -524,6 +530,7 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\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+\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@@ -544,6 +551,23 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\n \t\treturn;\n \t}\n \n+\t/* bind the framerate */\n+\tgst_libcamera_bind_framerate(state->cam_->controls(), state->initControls_);\n+\n+\t/* Expose the controls in initControls_ throught a new caps event. */\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_init_controls_to_caps(state->initControls_,\n+\t\t\t\t\t\t\t\t\t stream_cfg, framerate_container);\n+\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 \tself->allocator = gst_libcamera_allocator_new(state->cam_, state->config_.get());\n \tif (!self->allocator) {\n \t\tGST_ELEMENT_ERROR(self, RESOURCE, NO_SPACE_LEFT,\n@@ -566,7 +590,7 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\n \t\tgst_flow_combiner_add_pad(self->flow_combiner, srcpad);\n \t}\n \n-\tret = state->cam_->start();\n+\tret = state->cam_->start(&state->initControls_);\n \tif (ret) {\n \t\tGST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,\n \t\t\t\t (\"Failed to start the camera: %s\", g_strerror(-ret)),\n@@ -576,6 +600,8 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\n \t}\n \n done:\n+\tstate->initControls_.clear();\n+\tg_free(framerate_container);\n \tswitch (flow_ret) {\n \tcase GST_FLOW_NOT_NEGOTIATED:\n \t\tGST_ELEMENT_FLOW_ERROR(self, flow_ret);\n", "prefixes": [ "libcamera-devel", "v3" ] }