[{"id":13163,"web_url":"https://patchwork.libcamera.org/comment/13163/","msgid":"<20201011231605.GF3944@pendragon.ideasonboard.com>","date":"2020-10-11T23:16:05","subject":"Re: [libcamera-devel] [PATCH v2 1/3] android: camera_worker:\n\tIntroduce CameraWorker","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nThank you for the patch.\n\nOn Sat, Oct 10, 2020 at 11:58:28AM +0200, Jacopo Mondi wrote:\n> The Android camera framework provides for each buffer part of a capture\n> request an acquisition fence the camera HAL is supposed to wait on\n> before using the buffer. As the libcamera HAL runs in the camera service\n> thread, it is not possible to perform a synchronous wait there.\n> \n> Introduce a CameraWorker class that runs an internal thread to wait\n> on a set of fences before queueing a capture request to the\n> libcamera::Camera.\n> \n> Fences completion is handled through a simple poll, similar in\n> implementation to the sync_wait() function provided by libdrm.\n> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> ---\n>  src/android/camera_worker.cpp | 122 ++++++++++++++++++++++++++++++++++\n>  src/android/camera_worker.h   |  63 ++++++++++++++++++\n>  src/android/meson.build       |   1 +\n>  3 files changed, 186 insertions(+)\n>  create mode 100644 src/android/camera_worker.cpp\n>  create mode 100644 src/android/camera_worker.h\n> \n> diff --git a/src/android/camera_worker.cpp b/src/android/camera_worker.cpp\n> new file mode 100644\n> index 000000000000..682ad1a82386\n> --- /dev/null\n> +++ b/src/android/camera_worker.cpp\n> @@ -0,0 +1,122 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * camera_worker.cpp - Process capture requests on behalf of the Camera HAL\n> + */\n> +\n> +#include \"camera_worker.h\"\n> +\n> +#include <errno.h>\n> +#include <string.h>\n> +#include <sys/poll.h>\n> +\n> +#include \"camera_device.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DECLARE_CATEGORY(HAL);\n> +\n> +/*\n> + * \\class CaptureRequest\n> + * \\brief Wrap a libcamera::Request associated with buffers and fences\n> + *\n> + * A CaptureRequest is constructed by the CameraDevice, filled with\n> + * buffers and fences provided by the camera3 framework and then processed\n> + * by the CameraWorker which queues it to the libcamera::Camera after handling\n> + * fences.\n> + */\n> +CaptureRequest::CaptureRequest(libcamera::Camera *camera, uint64_t cookie)\n> +\t: camera_(camera)\n> +{\n> +\trequest_ = camera_->createRequest(cookie);\n> +}\n> +\n> +void CaptureRequest::addBuffer(Stream *stream, FrameBuffer *buffer, int fence)\n> +{\n> +\trequest_->addBuffer(stream, buffer);\n> +\tacquireFences_.push_back(fence);\n> +}\n> +\n> +void CaptureRequest::queue()\n> +{\n> +\tcamera_->queueRequest(request_.get());\n> +}\n> +\n> +/*\n> + * \\class CameraWorker\n> + * \\brief Process a CaptureRequest on an internal thread\n> + *\n> + * The CameraWorker class wraps a Worker that runs on an internal thread\n> + * and schedules processing of CaptureRequest through it.\n> + */\n> +CameraWorker::CameraWorker()\n> +{\n> +\tworker_.moveToThread(&thread_);\n> +}\n> +\n> +void CameraWorker::start()\n> +{\n> +\tthread_.start();\n> +}\n> +\n> +void CameraWorker::stop()\n> +{\n> +\tthread_.exit();\n> +\tthread_.wait();\n> +}\n> +\n> +void CameraWorker::queueRequest(CaptureRequest *request)\n> +{\n> +\t/* Async process the request on the worker which runs its own thread. */\n> +\tworker_.invokeMethod(&Worker::processRequest, ConnectionTypeQueued,\n> +\t\t\t     request);\n> +}\n> +\n> +/*\n> + * \\class CameraWorker::Worker\n> + * \\brief Process a CaptureRequest handling acquisition fences\n> + */\n> +int CameraWorker::Worker::waitFence(int fence)\n> +{\n> +\t/*\n> +\t * \\todo Better characterize the timeout. Currently equal to the one\n> +\t * used by the Rockchip Camera HAL on ChromeOS.\n> +\t */\n> +\tconstexpr unsigned int timeoutMs = 300;\n> +\tstruct pollfd fds = { fence, POLLIN, 0 };\n> +\n> +\tdo {\n> +\t\tint ret = poll(&fds, 1, timeoutMs);\n> +\t\tif (ret == 0)\n> +\t\t\treturn -ETIME;\n> +\n> +\t\tif (ret > 0) {\n> +\t\t\tif (fds.revents & (POLLERR | POLLNVAL))\n> +\t\t\t\treturn -EINVAL;\n> +\n> +\t\t\treturn 0;\n> +\t\t}\n> +\t} while (errno == EINTR || errno == EAGAIN);\n> +\n> +\treturn -errno;\n> +}\n> +\n> +void CameraWorker::Worker::processRequest(CaptureRequest *request)\n> +{\n> +\t/* Wait on all fences before queuing the Request. */\n> +\tfor (int fence : request->fences()) {\n> +\t\tif (fence == -1)\n> +\t\t\tcontinue;\n> +\n> +\t\tint ret = waitFence(fence);\n> +\t\tclose(fence);\n> +\t\tif (ret < 0) {\n> +\t\t\tLOG(HAL, Error) << \"Failed handling fence: \"\n\nMaybe \"Failed waiting for fence: \" or \"Waiting for fence failed: \" ?\n\n> +\t\t\t\t\t<< fence << \": \" << strerror(-ret);\n> +\t\t\treturn;\n> +\t\t}\n> +\t}\n> +\n> +\trequest->queue();\n> +}\n> diff --git a/src/android/camera_worker.h b/src/android/camera_worker.h\n> new file mode 100644\n> index 000000000000..fff5021708d7\n> --- /dev/null\n> +++ b/src/android/camera_worker.h\n> @@ -0,0 +1,63 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * camera_worker.h - Process capture requests on behalf of the Camera HAL\n> + */\n> +#ifndef __ANDROID_CAMERA_WORKER_H__\n> +#define __ANDROID_CAMERA_WORKER_H__\n> +\n> +#include <memory>\n> +\n> +#include <libcamera/buffer.h>\n> +#include <libcamera/camera.h>\n> +#include <libcamera/object.h>\n> +#include <libcamera/request.h>\n> +#include <libcamera/stream.h>\n> +\n> +#include \"libcamera/internal/thread.h\"\n> +\n> +class CameraDevice;\n> +\n> +class CaptureRequest\n> +{\n> +public:\n> +\tCaptureRequest(libcamera::Camera *camera, uint64_t cookie);\n> +\n> +\tconst std::vector<int> &fences() const { return acquireFences_; }\n> +\n> +\tvoid addBuffer(libcamera::Stream *stream,\n> +\t\t       libcamera::FrameBuffer *buffer, int fence);\n> +\tvoid queue();\n> +\n> +private:\n> +\tlibcamera::Camera *camera_;\n\nThis duplicates the camera pointer in every CaptureRequest instance, but\nthat's not a big deal as we'll rework this when moving fence handling to\nthe libcamera core.\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\tstd::vector<int> acquireFences_;\n> +\tstd::unique_ptr<libcamera::Request> request_;\n> +};\n> +\n> +class CameraWorker\n> +{\n> +public:\n> +\tCameraWorker();\n> +\n> +\tvoid start();\n> +\tvoid stop();\n> +\n> +\tvoid queueRequest(CaptureRequest *request);\n> +\n> +private:\n> +\tclass Worker : public libcamera::Object\n> +\t{\n> +\tpublic:\n> +\t\tvoid processRequest(CaptureRequest *request);\n> +\n> +\tprivate:\n> +\t\tint waitFence(int fence);\n> +\t};\n> +\n> +\tWorker worker_;\n> +\tlibcamera::Thread thread_;\n> +};\n> +\n> +#endif /* __ANDROID_CAMERA_WORKER_H__ */\n> diff --git a/src/android/meson.build b/src/android/meson.build\n> index 802bb89afe57..b2b2293cf62d 100644\n> --- a/src/android/meson.build\n> +++ b/src/android/meson.build\n> @@ -21,6 +21,7 @@ android_hal_sources = files([\n>      'camera_metadata.cpp',\n>      'camera_ops.cpp',\n>      'camera_stream.cpp',\n> +    'camera_worker.cpp',\n>      'jpeg/encoder_libjpeg.cpp',\n>      'jpeg/exif.cpp',\n>  ])","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 C8A96BEEDF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 11 Oct 2020 23:16:52 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3C89E60730;\n\tMon, 12 Oct 2020 01:16:52 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 022B360357\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 12 Oct 2020 01:16:50 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 6E3CF308;\n\tMon, 12 Oct 2020 01:16:50 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Xxk/ct1f\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1602458210;\n\tbh=wATgcI9V1b998YktQmVNnoSC/Aj0Ts/fWUCh4EMAdJ8=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=Xxk/ct1f9HGjVD7co9w/XmelWIzOHB9of/U9XbuvRSvw9cralPDVrn+QtHay89QUZ\n\tDywd9vM3HgVdyyLSnG/YERHsdgQusLb/0ZGZBPIolYKnDKldGIwqmlnSCPIZvEClo/\n\tIXDHEayGlyX/A9Vm1WyfW7k/4x6de2KjrMODGqMs=","Date":"Mon, 12 Oct 2020 02:16:05 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<20201011231605.GF3944@pendragon.ideasonboard.com>","References":"<20201010095830.134084-1-jacopo@jmondi.org>\n\t<20201010095830.134084-2-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20201010095830.134084-2-jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [PATCH v2 1/3] android: camera_worker:\n\tIntroduce CameraWorker","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>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":13192,"web_url":"https://patchwork.libcamera.org/comment/13192/","msgid":"<20201014115831.ryczukkyaqcb7yoy@oden.dyn.berto.se>","date":"2020-10-14T11:58:31","subject":"Re: [libcamera-devel] [PATCH v2 1/3] android: camera_worker:\n\tIntroduce CameraWorker","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Jacopo,\n\nThanks for your work.\n\nOn 2020-10-10 11:58:28 +0200, Jacopo Mondi wrote:\n> The Android camera framework provides for each buffer part of a capture\n> request an acquisition fence the camera HAL is supposed to wait on\n> before using the buffer. As the libcamera HAL runs in the camera service\n> thread, it is not possible to perform a synchronous wait there.\n> \n> Introduce a CameraWorker class that runs an internal thread to wait\n> on a set of fences before queueing a capture request to the\n> libcamera::Camera.\n> \n> Fences completion is handled through a simple poll, similar in\n> implementation to the sync_wait() function provided by libdrm.\n> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> ---\n>  src/android/camera_worker.cpp | 122 ++++++++++++++++++++++++++++++++++\n>  src/android/camera_worker.h   |  63 ++++++++++++++++++\n>  src/android/meson.build       |   1 +\n>  3 files changed, 186 insertions(+)\n>  create mode 100644 src/android/camera_worker.cpp\n>  create mode 100644 src/android/camera_worker.h\n> \n> diff --git a/src/android/camera_worker.cpp b/src/android/camera_worker.cpp\n> new file mode 100644\n> index 000000000000..682ad1a82386\n> --- /dev/null\n> +++ b/src/android/camera_worker.cpp\n> @@ -0,0 +1,122 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * camera_worker.cpp - Process capture requests on behalf of the Camera HAL\n> + */\n> +\n> +#include \"camera_worker.h\"\n> +\n> +#include <errno.h>\n> +#include <string.h>\n> +#include <sys/poll.h>\n> +\n> +#include \"camera_device.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DECLARE_CATEGORY(HAL);\n> +\n> +/*\n> + * \\class CaptureRequest\n> + * \\brief Wrap a libcamera::Request associated with buffers and fences\n> + *\n> + * A CaptureRequest is constructed by the CameraDevice, filled with\n> + * buffers and fences provided by the camera3 framework and then processed\n> + * by the CameraWorker which queues it to the libcamera::Camera after handling\n> + * fences.\n> + */\n> +CaptureRequest::CaptureRequest(libcamera::Camera *camera, uint64_t cookie)\n> +\t: camera_(camera)\n> +{\n> +\trequest_ = camera_->createRequest(cookie);\n> +}\n> +\n> +void CaptureRequest::addBuffer(Stream *stream, FrameBuffer *buffer, int fence)\n> +{\n> +\trequest_->addBuffer(stream, buffer);\n> +\tacquireFences_.push_back(fence);\n> +}\n> +\n> +void CaptureRequest::queue()\n> +{\n> +\tcamera_->queueRequest(request_.get());\n> +}\n> +\n> +/*\n> + * \\class CameraWorker\n> + * \\brief Process a CaptureRequest on an internal thread\n> + *\n> + * The CameraWorker class wraps a Worker that runs on an internal thread\n> + * and schedules processing of CaptureRequest through it.\n> + */\n> +CameraWorker::CameraWorker()\n> +{\n> +\tworker_.moveToThread(&thread_);\n> +}\n> +\n> +void CameraWorker::start()\n> +{\n> +\tthread_.start();\n> +}\n> +\n> +void CameraWorker::stop()\n> +{\n> +\tthread_.exit();\n> +\tthread_.wait();\n> +}\n> +\n> +void CameraWorker::queueRequest(CaptureRequest *request)\n> +{\n> +\t/* Async process the request on the worker which runs its own thread. */\n> +\tworker_.invokeMethod(&Worker::processRequest, ConnectionTypeQueued,\n> +\t\t\t     request);\n> +}\n> +\n> +/*\n> + * \\class CameraWorker::Worker\n> + * \\brief Process a CaptureRequest handling acquisition fences\n> + */\n> +int CameraWorker::Worker::waitFence(int fence)\n> +{\n> +\t/*\n> +\t * \\todo Better characterize the timeout. Currently equal to the one\n> +\t * used by the Rockchip Camera HAL on ChromeOS.\n> +\t */\n> +\tconstexpr unsigned int timeoutMs = 300;\n> +\tstruct pollfd fds = { fence, POLLIN, 0 };\n> +\n> +\tdo {\n> +\t\tint ret = poll(&fds, 1, timeoutMs);\n> +\t\tif (ret == 0)\n> +\t\t\treturn -ETIME;\n> +\n> +\t\tif (ret > 0) {\n> +\t\t\tif (fds.revents & (POLLERR | POLLNVAL))\n> +\t\t\t\treturn -EINVAL;\n> +\n> +\t\t\treturn 0;\n> +\t\t}\n> +\t} while (errno == EINTR || errno == EAGAIN);\n> +\n> +\treturn -errno;\n> +}\n> +\n> +void CameraWorker::Worker::processRequest(CaptureRequest *request)\n> +{\n> +\t/* Wait on all fences before queuing the Request. */\n> +\tfor (int fence : request->fences()) {\n> +\t\tif (fence == -1)\n> +\t\t\tcontinue;\n> +\n> +\t\tint ret = waitFence(fence);\n> +\t\tclose(fence);\n> +\t\tif (ret < 0) {\n> +\t\t\tLOG(HAL, Error) << \"Failed handling fence: \"\n> +\t\t\t\t\t<< fence << \": \" << strerror(-ret);\n> +\t\t\treturn;\n> +\t\t}\n> +\t}\n> +\n> +\trequest->queue();\n> +}\n> diff --git a/src/android/camera_worker.h b/src/android/camera_worker.h\n> new file mode 100644\n> index 000000000000..fff5021708d7\n> --- /dev/null\n> +++ b/src/android/camera_worker.h\n> @@ -0,0 +1,63 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * camera_worker.h - Process capture requests on behalf of the Camera HAL\n> + */\n> +#ifndef __ANDROID_CAMERA_WORKER_H__\n> +#define __ANDROID_CAMERA_WORKER_H__\n> +\n> +#include <memory>\n> +\n> +#include <libcamera/buffer.h>\n> +#include <libcamera/camera.h>\n> +#include <libcamera/object.h>\n> +#include <libcamera/request.h>\n> +#include <libcamera/stream.h>\n> +\n> +#include \"libcamera/internal/thread.h\"\n> +\n> +class CameraDevice;\n> +\n> +class CaptureRequest\n> +{\n> +public:\n> +\tCaptureRequest(libcamera::Camera *camera, uint64_t cookie);\n> +\n> +\tconst std::vector<int> &fences() const { return acquireFences_; }\n> +\n> +\tvoid addBuffer(libcamera::Stream *stream,\n> +\t\t       libcamera::FrameBuffer *buffer, int fence);\n> +\tvoid queue();\n> +\n> +private:\n> +\tlibcamera::Camera *camera_;\n> +\tstd::vector<int> acquireFences_;\n> +\tstd::unique_ptr<libcamera::Request> request_;\n> +};\n> +\n> +class CameraWorker\n> +{\n> +public:\n> +\tCameraWorker();\n> +\n> +\tvoid start();\n> +\tvoid stop();\n> +\n> +\tvoid queueRequest(CaptureRequest *request);\n> +\n> +private:\n> +\tclass Worker : public libcamera::Object\n> +\t{\n> +\tpublic:\n> +\t\tvoid processRequest(CaptureRequest *request);\n> +\n> +\tprivate:\n> +\t\tint waitFence(int fence);\n> +\t};\n> +\n> +\tWorker worker_;\n> +\tlibcamera::Thread thread_;\n> +};\n> +\n> +#endif /* __ANDROID_CAMERA_WORKER_H__ */\n> diff --git a/src/android/meson.build b/src/android/meson.build\n> index 802bb89afe57..b2b2293cf62d 100644\n> --- a/src/android/meson.build\n> +++ b/src/android/meson.build\n> @@ -21,6 +21,7 @@ android_hal_sources = files([\n>      'camera_metadata.cpp',\n>      'camera_ops.cpp',\n>      'camera_stream.cpp',\n> +    'camera_worker.cpp',\n>      'jpeg/encoder_libjpeg.cpp',\n>      'jpeg/exif.cpp',\n>  ])\n> -- \n> 2.28.0\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","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 0FD23BEEE0\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 14 Oct 2020 11:58:36 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 486BF60E79;\n\tWed, 14 Oct 2020 13:58:35 +0200 (CEST)","from mail-lj1-x241.google.com (mail-lj1-x241.google.com\n\t[IPv6:2a00:1450:4864:20::241])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1002B60354\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 14 Oct 2020 13:58:33 +0200 (CEST)","by mail-lj1-x241.google.com with SMTP id c21so2914674ljj.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 14 Oct 2020 04:58:33 -0700 (PDT)","from localhost (h-209-203.A463.priv.bahnhof.se. [155.4.209.203])\n\tby smtp.gmail.com with ESMTPSA id\n\tl9sm1128594ljc.86.2020.10.14.04.58.31\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 14 Oct 2020 04:58:32 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=ragnatech-se.20150623.gappssmtp.com\n\theader.i=@ragnatech-se.20150623.gappssmtp.com\n\theader.b=\"IXhsLO38\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to;\n\tbh=hkhtzDOWztOTuYoR8WX92nSZibNnzuegWvy9QRnsZy8=;\n\tb=IXhsLO3826+ceb15NBMCB3YK4fBZYqgk8CDfQF2DnThOedeTkqiPeq235k2Owm9Ttu\n\ttAv38HqNFsVg5mooKBMCjsh1H+6wGRqqi9SS1kvjKvpxh7+Hz+6gwiKGrvpsjmDH6Fe/\n\toQZgCIZLVfTyFkNL2vQAc0poM3soidG8jScABKebuJW39JxwMR6U4uOVO37kIP9uxLcS\n\tf7kz3NkPNhBYzG1JKVGP8DH6vp2QTs6bW3trxbrGq8UfI1ARV8RgUZFEj8jTXEtj/5lA\n\teoYDoEwb2RYMjpK2/7alaEa8DlFsCqPzurXGz2G+mXZAk1VNtdLDl2dDsnh0ysoJ7y6D\n\t4EjQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to;\n\tbh=hkhtzDOWztOTuYoR8WX92nSZibNnzuegWvy9QRnsZy8=;\n\tb=fTGSnHM00SrZ8pmGq0J1FrOHd1yKFnd5pusvGpb3lA+LVtOagm2RFfF7Wy9ZgMQPDG\n\tWfY80lwZCYmPOVDKSyIGa09GmXCYp88BL9yMrkos42+N9rZg0Z6gnxqzMO0GWS5NJoFw\n\tm9xbdBykvD4PtFdeCY9iKTpwZPt+e6NZ4LSFXJV5h6g5KGJ0/WLhZkWXtPbakk7021DM\n\tMQbW134POGJFPEGS9RMpFjfA56qS62pNMQudb3e4+ZhSQlnITFH+oY+fQDROc7U9+gPZ\n\tTGn+tJxr2p/izwWgJpV9FheNu9+Rc4C5Orh1nlAWCuy1yvPIjaYeivGk7ctSjqHgOMLr\n\tYcTw==","X-Gm-Message-State":"AOAM530vcXUoYdCgf6oBYJYLdIkvsxFuZVxTGjb4l0fYX/SdboDdqUSD\n\tm7jaFPfuzMFaIUTQxjowxpfc9Q==","X-Google-Smtp-Source":"ABdhPJwcArPfWuc4zNKQqcsR59DLBUWu+BNj5pvHTtg3GO4lhStgevrDI64Pl3GpszW6OBR5oCGtRA==","X-Received":"by 2002:a2e:6c15:: with SMTP id h21mr1770836ljc.45.1602676713044;\n\tWed, 14 Oct 2020 04:58:33 -0700 (PDT)","Date":"Wed, 14 Oct 2020 13:58:31 +0200","From":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<20201014115831.ryczukkyaqcb7yoy@oden.dyn.berto.se>","References":"<20201010095830.134084-1-jacopo@jmondi.org>\n\t<20201010095830.134084-2-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20201010095830.134084-2-jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [PATCH v2 1/3] android: camera_worker:\n\tIntroduce CameraWorker","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>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"iso-8859-1\"","Content-Transfer-Encoding":"quoted-printable","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]