[{"id":31553,"web_url":"https://patchwork.libcamera.org/comment/31553/","msgid":"<172794995331.1619946.6467404915728462370@ping.linuxembedded.co.uk>","date":"2024-10-03T10:05:53","subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Harvey Yang (2024-09-30 07:29:45)\n> From: Konami Shu <konamiz@google.com>\n> \n> Add a test pattern generator class hierarchy for the Virtual\n> pipeline handler.\n> \n> Implement two types of test patterns: color bars and diagonal lines\n> generator and use them in the Virtual pipeline handler.\n> \n> A shifting mechanism is enabled. For each frame, the image is shifted to\n> the left by 1 pixel. It drops FPS though.\n\nI guess we could solve the throughput here by generating a double width\nimage, handling the stride accordingly and just changing the offset when\ncalling ARGBtoNV12 ...\n\nBut no need for that now. I guess other implementations here could be\ndone on top.\n\n> Add a dependency for libyuv to the build system to generate images\n> in NV12 format from the test pattern.\n> \n> Signed-off-by: Konami Shu <konamiz@google.com>\n> Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>\n> Co-developed-by: Yunke Cao <yunkec@chromium.org>\n> Co-developed-by: Tomasz Figa <tfiga@chromium.org>\n> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> ---\n>  src/android/meson.build                       |  19 ---\n>  .../pipeline/virtual/frame_generator.h        |  29 ++++\n>  src/libcamera/pipeline/virtual/meson.build    |   3 +\n>  .../virtual/test_pattern_generator.cpp        | 137 ++++++++++++++++++\n>  .../pipeline/virtual/test_pattern_generator.h |  53 +++++++\n>  src/libcamera/pipeline/virtual/virtual.cpp    |  41 +++++-\n>  src/libcamera/pipeline/virtual/virtual.h      |   5 +\n>  src/meson.build                               |  19 +++\n>  8 files changed, 284 insertions(+), 22 deletions(-)\n>  create mode 100644 src/libcamera/pipeline/virtual/frame_generator.h\n>  create mode 100644 src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n>  create mode 100644 src/libcamera/pipeline/virtual/test_pattern_generator.h\n> \n> diff --git a/src/android/meson.build b/src/android/meson.build\n> index 68646120..6341ee8b 100644\n> --- a/src/android/meson.build\n> +++ b/src/android/meson.build\n> @@ -15,25 +15,6 @@ foreach dep : android_deps\n>      endif\n>  endforeach\n>  \n> -libyuv_dep = dependency('libyuv', required : false)\n> -\n> -# Fallback to a subproject if libyuv isn't found, as it's typically not\n> -# provided by distributions.\n> -if not libyuv_dep.found()\n> -    cmake = import('cmake')\n> -\n> -    libyuv_vars = cmake.subproject_options()\n> -    libyuv_vars.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'})\n> -    libyuv_vars.set_override_option('cpp_std', 'c++17')\n> -    libyuv_vars.append_compile_args('cpp',\n> -         '-Wno-sign-compare',\n> -         '-Wno-unused-variable',\n> -         '-Wno-unused-parameter')\n> -    libyuv_vars.append_link_args('-ljpeg')\n> -    libyuv = cmake.subproject('libyuv', options : libyuv_vars)\n> -    libyuv_dep = libyuv.dependency('yuv')\n> -endif\n> -\n>  android_deps += [libyuv_dep]\n>  \n>  android_hal_sources = files([\n> diff --git a/src/libcamera/pipeline/virtual/frame_generator.h b/src/libcamera/pipeline/virtual/frame_generator.h\n> new file mode 100644\n> index 00000000..4ff41dd8\n> --- /dev/null\n> +++ b/src/libcamera/pipeline/virtual/frame_generator.h\n> @@ -0,0 +1,29 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024, Google Inc.\n> + *\n> + * frame_generator.h - Virtual cameras helper to generate frames\n> + */\n> +\n> +#pragma once\n> +\n> +#include <libcamera/framebuffer.h>\n> +#include <libcamera/geometry.h>\n> +\n> +namespace libcamera {\n> +\n> +class FrameGenerator\n> +{\n> +public:\n> +       virtual ~FrameGenerator() = default;\n> +\n> +       virtual void configure(const Size &size) = 0;\n> +\n> +       virtual int generateFrame(const Size &size,\n> +                                 const FrameBuffer *buffer) = 0;\n> +\n> +protected:\n> +       FrameGenerator() {}\n> +};\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/virtual/meson.build b/src/libcamera/pipeline/virtual/meson.build\n> index ada1b335..0c537777 100644\n> --- a/src/libcamera/pipeline/virtual/meson.build\n> +++ b/src/libcamera/pipeline/virtual/meson.build\n> @@ -1,5 +1,8 @@\n>  # SPDX-License-Identifier: CC0-1.0\n>  \n>  libcamera_internal_sources += files([\n> +    'test_pattern_generator.cpp',\n>      'virtual.cpp',\n>  ])\n> +\n> +libcamera_deps += [libyuv_dep]\n> diff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.cpp b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n> new file mode 100644\n> index 00000000..c5a93d37\n> --- /dev/null\n> +++ b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n> @@ -0,0 +1,137 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024, Google Inc.\n> + *\n> + * test_pattern_generator.cpp - Derived class of FrameGenerator for\n> + * generating test patterns\n> + */\n> +\n> +#include \"test_pattern_generator.h\"\n> +\n> +#include <libcamera/base/log.h>\n> +\n> +#include \"libcamera/internal/mapped_framebuffer.h\"\n> +\n> +#include <libyuv/convert_from_argb.h>\n> +\n> +namespace libcamera {\n> +\n> +LOG_DECLARE_CATEGORY(Virtual)\n> +\n> +static const unsigned int kARGBSize = 4;\n> +\n> +int TestPatternGenerator::generateFrame(const Size &size,\n> +                                       const FrameBuffer *buffer)\n> +{\n> +       MappedFrameBuffer mappedFrameBuffer(buffer,\n> +                                           MappedFrameBuffer::MapFlag::Write);\n> +\n> +       auto planes = mappedFrameBuffer.planes();\n> +\n> +       shiftLeft(size);\n> +\n> +       /* Convert the template_ to the frame buffer */\n> +       int ret = libyuv::ARGBToNV12(template_.get(), size.width * kARGBSize,\n\nDo we need to do anything here to make sure we match the stride of the\noutput buffer if it comes from an external source?\n\nMaybe that's not something we need to deal with currently.\n\n> +                                    planes[0].begin(), size.width,\n> +                                    planes[1].begin(), size.width,\n> +                                    size.width, size.height);\n> +       if (ret != 0)\n> +               LOG(Virtual, Error) << \"ARGBToNV12() failed with \" << ret;\n> +\n> +       return ret;\n> +}\n> +\n> +void TestPatternGenerator::shiftLeft(const Size &size)\n> +{\n> +       /* Store the first column temporarily */\n> +       auto firstColumn = std::make_unique<uint8_t[]>(size.height * kARGBSize);\n> +       for (size_t h = 0; h < size.height; h++) {\n> +               unsigned int index = h * size.width * kARGBSize;\n> +               unsigned int index1 = h * kARGBSize;\n> +               firstColumn[index1] = template_[index];\n> +               firstColumn[index1 + 1] = template_[index + 1];\n> +               firstColumn[index1 + 2] = template_[index + 2];\n> +               firstColumn[index1 + 3] = 0x00;\n> +       }\n> +\n> +       /* Overwrite template_ */\n> +       uint8_t *buf = template_.get();\n> +       for (size_t h = 0; h < size.height; h++) {\n> +               for (size_t w = 0; w < size.width - 1; w++) {\n> +                       /* Overwrite with the pixel on the right */\n> +                       unsigned int index = (h * size.width + w + 1) * kARGBSize;\n> +                       *buf++ = template_[index]; /* B */\n> +                       *buf++ = template_[index + 1]; /* G */\n> +                       *buf++ = template_[index + 2]; /* R */\n> +                       *buf++ = 0x00; /* A */\n> +               }\n> +               /* Overwrite the new last column with the original first column */\n> +               unsigned int index1 = h * kARGBSize;\n> +               *buf++ = firstColumn[index1]; /* B */\n> +               *buf++ = firstColumn[index1 + 1]; /* G */\n> +               *buf++ = firstColumn[index1 + 2]; /* R */\n> +               *buf++ = 0x00; /* A */\n> +       }\n\nI could imagine ways we could try to optimise this or do different\nthings - but I don't think performance is key here right away - so I'm\nfine with the above.\n\n> +}\n> +\n> +void ColorBarsGenerator::configure(const Size &size)\n> +{\n> +       constexpr uint8_t kColorBar[8][3] = {\n> +               /*  R,    G,    B */\n> +               { 0xff, 0xff, 0xff }, /* White */\n> +               { 0xff, 0xff, 0x00 }, /* Yellow */\n> +               { 0x00, 0xff, 0xff }, /* Cyan */\n> +               { 0x00, 0xff, 0x00 }, /* Green */\n> +               { 0xff, 0x00, 0xff }, /* Magenta */\n> +               { 0xff, 0x00, 0x00 }, /* Red */\n> +               { 0x00, 0x00, 0xff }, /* Blue */\n> +               { 0x00, 0x00, 0x00 }, /* Black */\n> +       };\n> +\n> +       template_ = std::make_unique<uint8_t[]>(\n> +               size.width * size.height * kARGBSize);\n> +\n> +       unsigned int colorBarWidth = size.width / std::size(kColorBar);\n> +\n> +       uint8_t *buf = template_.get();\n> +       for (size_t h = 0; h < size.height; h++) {\n> +               for (size_t w = 0; w < size.width; w++) {\n> +                       /* Repeat when the width is exceed */\n> +                       unsigned int index = (w / colorBarWidth) % std::size(kColorBar);\n> +\n> +                       *buf++ = kColorBar[index][2]; /* B */\n> +                       *buf++ = kColorBar[index][1]; /* G */\n> +                       *buf++ = kColorBar[index][0]; /* R */\n> +                       *buf++ = 0x00; /* A */\n> +               }\n> +       }\n> +}\n> +\n> +void DiagonalLinesGenerator::configure(const Size &size)\n> +{\n> +       constexpr uint8_t kColorBar[8][3] = {\n\n[8][3] ?\n\n> +               /*  R,    G,    B */\n> +               { 0xff, 0xff, 0xff }, /* White */\n> +               { 0x00, 0x00, 0x00 }, /* Black */\n> +       };\n> +\n> +       template_ = std::make_unique<uint8_t[]>(\n> +               size.width * size.height * kARGBSize);\n> +\n> +       unsigned int lineWidth = size.width / 10;\n> +\n> +       uint8_t *buf = template_.get();\n> +       for (size_t h = 0; h < size.height; h++) {\n> +               for (size_t w = 0; w < size.width; w++) {\n> +                       /* Repeat when the width is exceed */\n> +                       int index = ((w + h) / lineWidth) % 2;\n> +\n> +                       *buf++ = kColorBar[index][2]; /* B */\n> +                       *buf++ = kColorBar[index][1]; /* G */\n> +                       *buf++ = kColorBar[index][0]; /* R */\n> +                       *buf++ = 0x00; /* A */\n> +               }\n> +       }\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.h b/src/libcamera/pipeline/virtual/test_pattern_generator.h\n> new file mode 100644\n> index 00000000..2ff1e40e\n> --- /dev/null\n> +++ b/src/libcamera/pipeline/virtual/test_pattern_generator.h\n> @@ -0,0 +1,53 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024, Google Inc.\n> + *\n> + * test_pattern_generator.h - Derived class of FrameGenerator for\n> + * generating test patterns\n> + */\n> +\n> +#pragma once\n> +\n> +#include <memory>\n> +\n> +#include <libcamera/framebuffer.h>\n> +#include <libcamera/geometry.h>\n> +\n> +#include \"frame_generator.h\"\n> +\n> +namespace libcamera {\n> +\n> +enum class TestPattern : char {\n> +       ColorBars = 0,\n> +       DiagonalLines = 1,\n> +};\n> +\n> +class TestPatternGenerator : public FrameGenerator\n> +{\n> +public:\n> +       int generateFrame(const Size &size, const FrameBuffer *buffer) override;\n> +\n> +protected:\n> +       /* Buffer of test pattern template */\n> +       std::unique_ptr<uint8_t[]> template_;\n> +\n> +private:\n> +       /* Shift the buffer by 1 pixel left each frame */\n> +       void shiftLeft(const Size &size);\n> +};\n> +\n> +class ColorBarsGenerator : public TestPatternGenerator\n> +{\n> +public:\n> +       /* Generate a template buffer of the color bar test pattern. */\n> +       void configure(const Size &size) override;\n> +};\n> +\n> +class DiagonalLinesGenerator : public TestPatternGenerator\n> +{\n> +public:\n> +       /* Generate a template buffer of the diagonal lines test pattern. */\n> +       void configure(const Size &size) override;\n> +};\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\n> index d1584f59..2b258492 100644\n> --- a/src/libcamera/pipeline/virtual/virtual.cpp\n> +++ b/src/libcamera/pipeline/virtual/virtual.cpp\n> @@ -34,6 +34,7 @@\n>  #include \"libcamera/internal/camera.h\"\n>  #include \"libcamera/internal/dma_buf_allocator.h\"\n>  #include \"libcamera/internal/formats.h\"\n> +#include \"libcamera/internal/framebuffer.h\"\n>  #include \"libcamera/internal/pipeline_handler.h\"\n>  \n>  namespace libcamera {\n> @@ -93,6 +94,8 @@ private:\n>                 return static_cast<VirtualCameraData *>(camera->_d());\n>         }\n>  \n> +       void initFrameGenerator(Camera *camera);\n> +\n>         DmaBufAllocator dmaBufAllocator_;\n>  };\n>  \n> @@ -227,8 +230,10 @@ int PipelineHandlerVirtual::configure(Camera *camera,\n>                                       CameraConfiguration *config)\n>  {\n>         VirtualCameraData *data = cameraData(camera);\n> -       for (auto [i, c] : utils::enumerate(*config))\n> +       for (auto [i, c] : utils::enumerate(*config)) {\n>                 c.setStream(&data->streamConfigs_[i].stream);\n> +               data->streamConfigs_[i].frameGenerator->configure(c.size);\n> +       }\n>  \n>         return 0;\n>  }\n> @@ -264,8 +269,24 @@ void PipelineHandlerVirtual::stopDevice([[maybe_unused]] Camera *camera)\n>  int PipelineHandlerVirtual::queueRequestDevice([[maybe_unused]] Camera *camera,\n>                                                Request *request)\n>  {\n> -       for (auto it : request->buffers())\n> -               completeBuffer(request, it.second);\n> +       VirtualCameraData *data = cameraData(camera);\n> +\n> +       for (auto const &[stream, buffer] : request->buffers()) {\n> +               bool found = false;\n> +               /* map buffer and fill test patterns */\n> +               for (auto &streamConfig : data->streamConfigs_) {\n> +                       if (stream == &streamConfig.stream) {\n> +                               found = true;\n> +                               if (streamConfig.frameGenerator->generateFrame(\n> +                                           stream->configuration().size, buffer))\n> +                                       buffer->_d()->cancel();\n> +\n> +                               completeBuffer(request, buffer);\n> +                               break;\n> +                       }\n> +               }\n> +               ASSERT(found);\n> +       }\n>  \n>         request->metadata().set(controls::SensorTimestamp, currentTimestamp());\n>         completeRequest(request);\n> @@ -307,11 +328,25 @@ bool PipelineHandlerVirtual::match([[maybe_unused]] DeviceEnumerator *enumerator\n>  \n>         const std::string id = \"Virtual0\";\n>         std::shared_ptr<Camera> camera = Camera::create(std::move(data), id, streams);\n> +\n> +       initFrameGenerator(camera.get());\n> +\n>         registerCamera(std::move(camera));\n>  \n>         return true;\n>  }\n>  \n> +void PipelineHandlerVirtual::initFrameGenerator(Camera *camera)\n> +{\n> +       auto data = cameraData(camera);\n> +       for (auto &streamConfig : data->streamConfigs_) {\n> +               if (data->testPattern_ == TestPattern::DiagonalLines)\n> +                       streamConfig.frameGenerator = std::make_unique<DiagonalLinesGenerator>();\n> +               else\n> +                       streamConfig.frameGenerator = std::make_unique<ColorBarsGenerator>();\n> +       }\n> +}\n> +\n>  REGISTER_PIPELINE_HANDLER(PipelineHandlerVirtual, \"virtual\")\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/virtual/virtual.h b/src/libcamera/pipeline/virtual/virtual.h\n> index 4df70a13..9b79ac09 100644\n> --- a/src/libcamera/pipeline/virtual/virtual.h\n> +++ b/src/libcamera/pipeline/virtual/virtual.h\n> @@ -15,6 +15,8 @@\n>  #include \"libcamera/internal/camera.h\"\n>  #include \"libcamera/internal/pipeline_handler.h\"\n>  \n> +#include \"test_pattern_generator.h\"\n> +\n>  namespace libcamera {\n>  \n>  class VirtualCameraData : public Camera::Private\n> @@ -28,6 +30,7 @@ public:\n>         };\n>         struct StreamConfig {\n>                 Stream stream;\n> +               std::unique_ptr<FrameGenerator> frameGenerator;\n>         };\n>  \n>         VirtualCameraData(PipelineHandler *pipe,\n> @@ -35,6 +38,8 @@ public:\n>  \n>         ~VirtualCameraData() = default;\n>  \n> +       TestPattern testPattern_ = TestPattern::ColorBars;\n> +\n>         const std::vector<Resolution> supportedResolutions_;\n>         Size maxResolutionSize_;\n>         Size minResolutionSize_;\n> diff --git a/src/meson.build b/src/meson.build\n> index 165a77bb..91bea775 100644\n> --- a/src/meson.build\n> +++ b/src/meson.build\n> @@ -27,6 +27,25 @@ else\n>      ipa_sign_module = false\n>  endif\n>  \n> +libyuv_dep = dependency('libyuv', required : false)\n> +\n> +# Fallback to a subproject if libyuv isn't found, as it's typically not\n> +# provided by distributions.\n> +if not libyuv_dep.found()\n> +    cmake = import('cmake')\n> +\n> +    libyuv_vars = cmake.subproject_options()\n> +    libyuv_vars.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'})\n> +    libyuv_vars.set_override_option('cpp_std', 'c++17')\n> +    libyuv_vars.append_compile_args('cpp',\n> +         '-Wno-sign-compare',\n> +         '-Wno-unused-variable',\n> +         '-Wno-unused-parameter')\n> +    libyuv_vars.append_link_args('-ljpeg')\n> +    libyuv = cmake.subproject('libyuv', options : libyuv_vars)\n> +    libyuv_dep = libyuv.dependency('yuv')\n> +endif\n> +\n\nI'm not yet sure in my mind if this should be in the top level where\nother dependencies are handled, or if here is fine. As this is the\nhighest common layer for both android and libcamera - I think this is\nfine.\n\nIt would have been nicer to split this meson change out to a distinct\npatch but it's fine now.\n\nI'm going to say it's fine to move here, and if we decide differently\nlater - it's easy to move.\n\n\nWith at least that [8][3] fixed, which I think is the only 'incorrect'\nthing, then you can add:\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n\n>  # libcamera must be built first as a dependency to the other components.\n>  subdir('libcamera')\n>  \n> -- \n> 2.46.1.824.gd892dcdcdd-goog\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 DF040BD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  3 Oct 2024 10:05:59 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E19CE63524;\n\tThu,  3 Oct 2024 12:05:58 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F34E962C92\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  3 Oct 2024 12:05:56 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 587444C7;\n\tThu,  3 Oct 2024 12:04:23 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"G9fvTVgf\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1727949863;\n\tbh=nNGzZo7Og29t/c5GZCkPfLoKLBsAjaU3PG/lJ6Gs9qQ=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=G9fvTVgf8gbVqxizNYwIMeUgxn9qiWzrLF72s1Xqhik9MUCok5+jbUBvo+qnGuU/Z\n\tzC1qTtv0drpYOx4AYTlK6ebBjz2UxJDiZ5DKr0H4Y87HclpeV3xheCYiHqjHA4V6vM\n\th4MTAk3Jx2oKQQz1i8ONnFTq5zg1mePHlP+gHxbE=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20240930063342.3014837-5-chenghaoyang@google.com>","References":"<20240930063342.3014837-1-chenghaoyang@google.com>\n\t<20240930063342.3014837-5-chenghaoyang@google.com>","Subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Konami Shu <konamiz@google.com>, Harvey Yang <chenghaoyang@chromium.org>,\n\tYunke Cao <yunkec@chromium.org>, Tomasz Figa <tfiga@chromium.org>,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Harvey Yang <chenghaoyang@chromium.org>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Thu, 03 Oct 2024 11:05:53 +0100","Message-ID":"<172794995331.1619946.6467404915728462370@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":31559,"web_url":"https://patchwork.libcamera.org/comment/31559/","msgid":"<172795159143.1619946.18177695661760631243@ping.linuxembedded.co.uk>","date":"2024-10-03T10:33:11","subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Harvey Yang (2024-09-30 07:29:45)\n> From: Konami Shu <konamiz@google.com>\n\nI'm getting email bounces that konamiz@google.com is not a valid email\naddress.\n\n--\nKieran","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 8A2C1BD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  3 Oct 2024 10:33:16 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 29FC963524;\n\tThu,  3 Oct 2024 12:33:16 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E1FCF63522\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  3 Oct 2024 12:33:13 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E6A664C7;\n\tThu,  3 Oct 2024 12:31:40 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"HUhNXioo\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1727951501;\n\tbh=Wgnt7sU3qo+4ubBLkx+u7ONZWxAg8QSBGWAX/BLsi3Y=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=HUhNXioo5rYrBMtRWNwxnIxLmiviKMjEA19cQdYgc/ZEKV5e6EZEkqNE5V1Ct6ELp\n\tIXRFeCAXw06qcs3Urw/BGhdfDhxiHSFDkDkpkeraR3XBVnPJEYrnJclNUZE+us+SQj\n\t9DhrN7OKxb2d0HNkJXx0sJbPOhU2fgD00ccq2cvY=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20240930063342.3014837-5-chenghaoyang@google.com>","References":"<20240930063342.3014837-1-chenghaoyang@google.com>\n\t<20240930063342.3014837-5-chenghaoyang@google.com>","Subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Konami Shu <konamiz@google.com>, Harvey Yang <chenghaoyang@chromium.org>,\n\tYunke Cao <yunkec@chromium.org>, Tomasz Figa <tfiga@chromium.org>,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Harvey Yang <chenghaoyang@chromium.org>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Thu, 03 Oct 2024 11:33:11 +0100","Message-ID":"<172795159143.1619946.18177695661760631243@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":31586,"web_url":"https://patchwork.libcamera.org/comment/31586/","msgid":"<CAEB1ahtMQHBqnBpgp8BN8oeBiPZY8Aw0i7_nQ+5EieKuOh3obQ@mail.gmail.com>","date":"2024-10-04T09:49:15","subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","submitter":{"id":117,"url":"https://patchwork.libcamera.org/api/people/117/","name":"Cheng-Hao Yang","email":"chenghaoyang@chromium.org"},"content":"Hi Kieran,\n\nOn Thu, Oct 3, 2024 at 6:33 PM Kieran Bingham\n<kieran.bingham@ideasonboard.com> wrote:\n>\n> Quoting Harvey Yang (2024-09-30 07:29:45)\n> > From: Konami Shu <konamiz@google.com>\n>\n> I'm getting email bounces that konamiz@google.com is not a valid email\n> address.\n\nYeah Konami was our intern last year, and after she left the email address\nis invalid... (Until she comes back one day perhaps haha)\n\nI'd like to keep her credit though.\n\nBR,\nHarvey\n\n>\n> --\n> Kieran","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 20F3BBD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  4 Oct 2024 09:49:30 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6755063524;\n\tFri,  4 Oct 2024 11:49:29 +0200 (CEST)","from mail-lj1-x22f.google.com (mail-lj1-x22f.google.com\n\t[IPv6:2a00:1450:4864:20::22f])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 89ED863512\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  4 Oct 2024 11:49:27 +0200 (CEST)","by mail-lj1-x22f.google.com with SMTP id\n\t38308e7fff4ca-2fabd2c4ac0so23030181fa.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 04 Oct 2024 02:49:27 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=chromium.org header.i=@chromium.org\n\theader.b=\"Fdi2l2WO\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=chromium.org; s=google; t=1728035367; x=1728640167;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=5p5xKrxm/L4XCwZZ5jnx7tdfBrtOYHWOMiB+vehjXxY=;\n\tb=Fdi2l2WOUtlvyMTFk9i8uAku+VULCx2aU+fM89JhA6+FzSBqubhcGnv99cvXk1giXR\n\tujrMAQ1BgCePKRnKcOtEGglwYmzftw8mhX9TGr/v7/agXdoO5c8fhqwMnkyEH7tCxBWx\n\ttel5G4Md7zg8ID1Wr/xr/oORl0NO56zw8Zqz4=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1728035367; x=1728640167;\n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=5p5xKrxm/L4XCwZZ5jnx7tdfBrtOYHWOMiB+vehjXxY=;\n\tb=Kl8mPA9M7tea4smOcxtbyoGosYQTgCHzQt+p+haGGvQ6zULRW8hdsYubTIG9XrnTMK\n\t7rvLUi3Fc2U9ToKJwB+XV8qMgK484pYQBZKQA7s6SrokOuvKy1JvL+aN6Uop/QJWRrfq\n\tU1MoMbVj5Bfzc1j7/S5+gkqp5IQCbQgaKKFLxMBwlUR0Fo701a+KNMuQnNeq/hSbl1y9\n\twlg9ZPOpptC4vvk8RuMSXUAlON9H0nKxl+ef4NF9qc2r9FtGxKSr1+oJ1I86zfLceWD2\n\tuKksmq4IYKpTeu/AKokeut4LTxMmirXM+y0t4GML9eaCxXzjHyk1huRyVCWuUtLbbMmr\n\t6pZA==","X-Gm-Message-State":"AOJu0YzOGQ8KwwYeZU1uSdZ2iQXV36XLyhUtAGMsGkdr7P8Fo67py4H6\n\taOFq6bo8el/fz+Ne5kEz6fme9M5XAEUE1dvBC3tFzF6KPbmTq30YXSHqy6vrfofzcumuo4kLhs0\n\tPI3NV/OfTrq0APN+nUaPu+HJTqanH131sBeHQ","X-Google-Smtp-Source":"AGHT+IEPUAR9BY9l7xHivqsdR0FmXsrdfLLaqUoLjDliBXFeyUy8HFfJA22Ut26/bV0jJmkYHGoUiGL8P4qhp7mLG3o=","X-Received":"by 2002:a2e:b806:0:b0:2f5:487:e87a with SMTP id\n\t38308e7fff4ca-2faf3c5f806mr8355921fa.18.1728035366519;\n\tFri, 04 Oct 2024 02:49:26 -0700 (PDT)","MIME-Version":"1.0","References":"<20240930063342.3014837-1-chenghaoyang@google.com>\n\t<20240930063342.3014837-5-chenghaoyang@google.com>\n\t<172795159143.1619946.18177695661760631243@ping.linuxembedded.co.uk>","In-Reply-To":"<172795159143.1619946.18177695661760631243@ping.linuxembedded.co.uk>","From":"Cheng-Hao Yang <chenghaoyang@chromium.org>","Date":"Fri, 4 Oct 2024 17:49:15 +0800","Message-ID":"<CAEB1ahtMQHBqnBpgp8BN8oeBiPZY8Aw0i7_nQ+5EieKuOh3obQ@mail.gmail.com>","Subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, Konami Shu <konamiz@google.com>, \n\tYunke Cao <yunkec@chromium.org>, Tomasz Figa <tfiga@chromium.org>, \n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":31587,"web_url":"https://patchwork.libcamera.org/comment/31587/","msgid":"<172803591695.877857.11081916017015109566@ping.linuxembedded.co.uk>","date":"2024-10-04T09:58:36","subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Cheng-Hao Yang (2024-10-04 10:49:15)\n> Hi Kieran,\n> \n> On Thu, Oct 3, 2024 at 6:33 PM Kieran Bingham\n> <kieran.bingham@ideasonboard.com> wrote:\n> >\n> > Quoting Harvey Yang (2024-09-30 07:29:45)\n> > > From: Konami Shu <konamiz@google.com>\n> >\n> > I'm getting email bounces that konamiz@google.com is not a valid email\n> > address.\n> \n> Yeah Konami was our intern last year, and after she left the email address\n> is invalid... (Until she comes back one day perhaps haha)\n> \n> I'd like to keep her credit though.\n\nCertainly! That's fine with me.\n--\nKieran\n\n\n> \n> BR,\n> Harvey\n> \n> >\n> > --\n> > Kieran","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 3212BC3257\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  4 Oct 2024 09:58:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id F32E56352B;\n\tFri,  4 Oct 2024 11:58:41 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3A2ED63512\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  4 Oct 2024 11:58:40 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 3CC6B59C;\n\tFri,  4 Oct 2024 11:57:06 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"LqL36PS2\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1728035826;\n\tbh=seIPjCag5Yn31T9tM58bLHBcUujO3iZdf0irPuiSTnM=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=LqL36PS2hpzk+3Ba4hCGMP2Elem6WJ0RYildf9wXZtS4TVs7MyTBVDhxPntabfZzy\n\tLI5ZkDalNfqOc1mQsxqh+ImuCFwaAALR/dbw0L8okxdk4uKaG7UHyWlhLQfe/GN9a/\n\tZ8z/stdJA5gHG3zVzUIOHsrmPIlhdfLfivlutpi0=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<CAEB1ahtMQHBqnBpgp8BN8oeBiPZY8Aw0i7_nQ+5EieKuOh3obQ@mail.gmail.com>","References":"<20240930063342.3014837-1-chenghaoyang@google.com>\n\t<20240930063342.3014837-5-chenghaoyang@google.com>\n\t<172795159143.1619946.18177695661760631243@ping.linuxembedded.co.uk>\n\t<CAEB1ahtMQHBqnBpgp8BN8oeBiPZY8Aw0i7_nQ+5EieKuOh3obQ@mail.gmail.com>","Subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, Konami Shu <konamiz@google.com>,\n\tYunke Cao <yunkec@chromium.org>, Tomasz Figa <tfiga@chromium.org>,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Cheng-Hao Yang <chenghaoyang@chromium.org>","Date":"Fri, 04 Oct 2024 10:58:36 +0100","Message-ID":"<172803591695.877857.11081916017015109566@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":31589,"web_url":"https://patchwork.libcamera.org/comment/31589/","msgid":"<CAEB1ahtfnkXm4ta5wi6nw-YBvqx5SfXMUJdCOcUjGxHzfwFFjA@mail.gmail.com>","date":"2024-10-04T10:00:30","subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","submitter":{"id":117,"url":"https://patchwork.libcamera.org/api/people/117/","name":"Cheng-Hao Yang","email":"chenghaoyang@chromium.org"},"content":"Hi Kieran,\n\nOn Thu, Oct 3, 2024 at 6:05 PM Kieran Bingham\n<kieran.bingham@ideasonboard.com> wrote:\n>\n> Quoting Harvey Yang (2024-09-30 07:29:45)\n> > From: Konami Shu <konamiz@google.com>\n> >\n> > Add a test pattern generator class hierarchy for the Virtual\n> > pipeline handler.\n> >\n> > Implement two types of test patterns: color bars and diagonal lines\n> > generator and use them in the Virtual pipeline handler.\n> >\n> > A shifting mechanism is enabled. For each frame, the image is shifted to\n> > the left by 1 pixel. It drops FPS though.\n>\n> I guess we could solve the throughput here by generating a double width\n> image, handling the stride accordingly and just changing the offset when\n> calling ARGBtoNV12 ...\n>\n> But no need for that now. I guess other implementations here could be\n> done on top.\n>\n> > Add a dependency for libyuv to the build system to generate images\n> > in NV12 format from the test pattern.\n> >\n> > Signed-off-by: Konami Shu <konamiz@google.com>\n> > Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>\n> > Co-developed-by: Yunke Cao <yunkec@chromium.org>\n> > Co-developed-by: Tomasz Figa <tfiga@chromium.org>\n> > Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > ---\n> >  src/android/meson.build                       |  19 ---\n> >  .../pipeline/virtual/frame_generator.h        |  29 ++++\n> >  src/libcamera/pipeline/virtual/meson.build    |   3 +\n> >  .../virtual/test_pattern_generator.cpp        | 137 ++++++++++++++++++\n> >  .../pipeline/virtual/test_pattern_generator.h |  53 +++++++\n> >  src/libcamera/pipeline/virtual/virtual.cpp    |  41 +++++-\n> >  src/libcamera/pipeline/virtual/virtual.h      |   5 +\n> >  src/meson.build                               |  19 +++\n> >  8 files changed, 284 insertions(+), 22 deletions(-)\n> >  create mode 100644 src/libcamera/pipeline/virtual/frame_generator.h\n> >  create mode 100644 src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n> >  create mode 100644 src/libcamera/pipeline/virtual/test_pattern_generator.h\n> >\n> > diff --git a/src/android/meson.build b/src/android/meson.build\n> > index 68646120..6341ee8b 100644\n> > --- a/src/android/meson.build\n> > +++ b/src/android/meson.build\n> > @@ -15,25 +15,6 @@ foreach dep : android_deps\n> >      endif\n> >  endforeach\n> >\n> > -libyuv_dep = dependency('libyuv', required : false)\n> > -\n> > -# Fallback to a subproject if libyuv isn't found, as it's typically not\n> > -# provided by distributions.\n> > -if not libyuv_dep.found()\n> > -    cmake = import('cmake')\n> > -\n> > -    libyuv_vars = cmake.subproject_options()\n> > -    libyuv_vars.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'})\n> > -    libyuv_vars.set_override_option('cpp_std', 'c++17')\n> > -    libyuv_vars.append_compile_args('cpp',\n> > -         '-Wno-sign-compare',\n> > -         '-Wno-unused-variable',\n> > -         '-Wno-unused-parameter')\n> > -    libyuv_vars.append_link_args('-ljpeg')\n> > -    libyuv = cmake.subproject('libyuv', options : libyuv_vars)\n> > -    libyuv_dep = libyuv.dependency('yuv')\n> > -endif\n> > -\n> >  android_deps += [libyuv_dep]\n> >\n> >  android_hal_sources = files([\n> > diff --git a/src/libcamera/pipeline/virtual/frame_generator.h b/src/libcamera/pipeline/virtual/frame_generator.h\n> > new file mode 100644\n> > index 00000000..4ff41dd8\n> > --- /dev/null\n> > +++ b/src/libcamera/pipeline/virtual/frame_generator.h\n> > @@ -0,0 +1,29 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2024, Google Inc.\n> > + *\n> > + * frame_generator.h - Virtual cameras helper to generate frames\n> > + */\n> > +\n> > +#pragma once\n> > +\n> > +#include <libcamera/framebuffer.h>\n> > +#include <libcamera/geometry.h>\n> > +\n> > +namespace libcamera {\n> > +\n> > +class FrameGenerator\n> > +{\n> > +public:\n> > +       virtual ~FrameGenerator() = default;\n> > +\n> > +       virtual void configure(const Size &size) = 0;\n> > +\n> > +       virtual int generateFrame(const Size &size,\n> > +                                 const FrameBuffer *buffer) = 0;\n> > +\n> > +protected:\n> > +       FrameGenerator() {}\n> > +};\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/src/libcamera/pipeline/virtual/meson.build b/src/libcamera/pipeline/virtual/meson.build\n> > index ada1b335..0c537777 100644\n> > --- a/src/libcamera/pipeline/virtual/meson.build\n> > +++ b/src/libcamera/pipeline/virtual/meson.build\n> > @@ -1,5 +1,8 @@\n> >  # SPDX-License-Identifier: CC0-1.0\n> >\n> >  libcamera_internal_sources += files([\n> > +    'test_pattern_generator.cpp',\n> >      'virtual.cpp',\n> >  ])\n> > +\n> > +libcamera_deps += [libyuv_dep]\n> > diff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.cpp b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n> > new file mode 100644\n> > index 00000000..c5a93d37\n> > --- /dev/null\n> > +++ b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n> > @@ -0,0 +1,137 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2024, Google Inc.\n> > + *\n> > + * test_pattern_generator.cpp - Derived class of FrameGenerator for\n> > + * generating test patterns\n> > + */\n> > +\n> > +#include \"test_pattern_generator.h\"\n> > +\n> > +#include <libcamera/base/log.h>\n> > +\n> > +#include \"libcamera/internal/mapped_framebuffer.h\"\n> > +\n> > +#include <libyuv/convert_from_argb.h>\n> > +\n> > +namespace libcamera {\n> > +\n> > +LOG_DECLARE_CATEGORY(Virtual)\n> > +\n> > +static const unsigned int kARGBSize = 4;\n> > +\n> > +int TestPatternGenerator::generateFrame(const Size &size,\n> > +                                       const FrameBuffer *buffer)\n> > +{\n> > +       MappedFrameBuffer mappedFrameBuffer(buffer,\n> > +                                           MappedFrameBuffer::MapFlag::Write);\n> > +\n> > +       auto planes = mappedFrameBuffer.planes();\n> > +\n> > +       shiftLeft(size);\n> > +\n> > +       /* Convert the template_ to the frame buffer */\n> > +       int ret = libyuv::ARGBToNV12(template_.get(), size.width * kARGBSize,\n>\n> Do we need to do anything here to make sure we match the stride of the\n> output buffer if it comes from an external source?\n>\n> Maybe that's not something we need to deal with currently.\n>\n> > +                                    planes[0].begin(), size.width,\n> > +                                    planes[1].begin(), size.width,\n> > +                                    size.width, size.height);\n> > +       if (ret != 0)\n> > +               LOG(Virtual, Error) << \"ARGBToNV12() failed with \" << ret;\n> > +\n> > +       return ret;\n> > +}\n> > +\n> > +void TestPatternGenerator::shiftLeft(const Size &size)\n> > +{\n> > +       /* Store the first column temporarily */\n> > +       auto firstColumn = std::make_unique<uint8_t[]>(size.height * kARGBSize);\n> > +       for (size_t h = 0; h < size.height; h++) {\n> > +               unsigned int index = h * size.width * kARGBSize;\n> > +               unsigned int index1 = h * kARGBSize;\n> > +               firstColumn[index1] = template_[index];\n> > +               firstColumn[index1 + 1] = template_[index + 1];\n> > +               firstColumn[index1 + 2] = template_[index + 2];\n> > +               firstColumn[index1 + 3] = 0x00;\n> > +       }\n> > +\n> > +       /* Overwrite template_ */\n> > +       uint8_t *buf = template_.get();\n> > +       for (size_t h = 0; h < size.height; h++) {\n> > +               for (size_t w = 0; w < size.width - 1; w++) {\n> > +                       /* Overwrite with the pixel on the right */\n> > +                       unsigned int index = (h * size.width + w + 1) * kARGBSize;\n> > +                       *buf++ = template_[index]; /* B */\n> > +                       *buf++ = template_[index + 1]; /* G */\n> > +                       *buf++ = template_[index + 2]; /* R */\n> > +                       *buf++ = 0x00; /* A */\n> > +               }\n> > +               /* Overwrite the new last column with the original first column */\n> > +               unsigned int index1 = h * kARGBSize;\n> > +               *buf++ = firstColumn[index1]; /* B */\n> > +               *buf++ = firstColumn[index1 + 1]; /* G */\n> > +               *buf++ = firstColumn[index1 + 2]; /* R */\n> > +               *buf++ = 0x00; /* A */\n> > +       }\n>\n> I could imagine ways we could try to optimise this or do different\n> things - but I don't think performance is key here right away - so I'm\n> fine with the above.\n>\n> > +}\n> > +\n> > +void ColorBarsGenerator::configure(const Size &size)\n> > +{\n> > +       constexpr uint8_t kColorBar[8][3] = {\n> > +               /*  R,    G,    B */\n> > +               { 0xff, 0xff, 0xff }, /* White */\n> > +               { 0xff, 0xff, 0x00 }, /* Yellow */\n> > +               { 0x00, 0xff, 0xff }, /* Cyan */\n> > +               { 0x00, 0xff, 0x00 }, /* Green */\n> > +               { 0xff, 0x00, 0xff }, /* Magenta */\n> > +               { 0xff, 0x00, 0x00 }, /* Red */\n> > +               { 0x00, 0x00, 0xff }, /* Blue */\n> > +               { 0x00, 0x00, 0x00 }, /* Black */\n> > +       };\n> > +\n> > +       template_ = std::make_unique<uint8_t[]>(\n> > +               size.width * size.height * kARGBSize);\n> > +\n> > +       unsigned int colorBarWidth = size.width / std::size(kColorBar);\n> > +\n> > +       uint8_t *buf = template_.get();\n> > +       for (size_t h = 0; h < size.height; h++) {\n> > +               for (size_t w = 0; w < size.width; w++) {\n> > +                       /* Repeat when the width is exceed */\n> > +                       unsigned int index = (w / colorBarWidth) % std::size(kColorBar);\n> > +\n> > +                       *buf++ = kColorBar[index][2]; /* B */\n> > +                       *buf++ = kColorBar[index][1]; /* G */\n> > +                       *buf++ = kColorBar[index][0]; /* R */\n> > +                       *buf++ = 0x00; /* A */\n> > +               }\n> > +       }\n> > +}\n> > +\n> > +void DiagonalLinesGenerator::configure(const Size &size)\n> > +{\n> > +       constexpr uint8_t kColorBar[8][3] = {\n>\n> [8][3] ?\n\nAh, updated to [2][3].\n\n>\n> > +               /*  R,    G,    B */\n> > +               { 0xff, 0xff, 0xff }, /* White */\n> > +               { 0x00, 0x00, 0x00 }, /* Black */\n> > +       };\n> > +\n> > +       template_ = std::make_unique<uint8_t[]>(\n> > +               size.width * size.height * kARGBSize);\n> > +\n> > +       unsigned int lineWidth = size.width / 10;\n> > +\n> > +       uint8_t *buf = template_.get();\n> > +       for (size_t h = 0; h < size.height; h++) {\n> > +               for (size_t w = 0; w < size.width; w++) {\n> > +                       /* Repeat when the width is exceed */\n> > +                       int index = ((w + h) / lineWidth) % 2;\n> > +\n> > +                       *buf++ = kColorBar[index][2]; /* B */\n> > +                       *buf++ = kColorBar[index][1]; /* G */\n> > +                       *buf++ = kColorBar[index][0]; /* R */\n> > +                       *buf++ = 0x00; /* A */\n> > +               }\n> > +       }\n> > +}\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.h b/src/libcamera/pipeline/virtual/test_pattern_generator.h\n> > new file mode 100644\n> > index 00000000..2ff1e40e\n> > --- /dev/null\n> > +++ b/src/libcamera/pipeline/virtual/test_pattern_generator.h\n> > @@ -0,0 +1,53 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2024, Google Inc.\n> > + *\n> > + * test_pattern_generator.h - Derived class of FrameGenerator for\n> > + * generating test patterns\n> > + */\n> > +\n> > +#pragma once\n> > +\n> > +#include <memory>\n> > +\n> > +#include <libcamera/framebuffer.h>\n> > +#include <libcamera/geometry.h>\n> > +\n> > +#include \"frame_generator.h\"\n> > +\n> > +namespace libcamera {\n> > +\n> > +enum class TestPattern : char {\n> > +       ColorBars = 0,\n> > +       DiagonalLines = 1,\n> > +};\n> > +\n> > +class TestPatternGenerator : public FrameGenerator\n> > +{\n> > +public:\n> > +       int generateFrame(const Size &size, const FrameBuffer *buffer) override;\n> > +\n> > +protected:\n> > +       /* Buffer of test pattern template */\n> > +       std::unique_ptr<uint8_t[]> template_;\n> > +\n> > +private:\n> > +       /* Shift the buffer by 1 pixel left each frame */\n> > +       void shiftLeft(const Size &size);\n> > +};\n> > +\n> > +class ColorBarsGenerator : public TestPatternGenerator\n> > +{\n> > +public:\n> > +       /* Generate a template buffer of the color bar test pattern. */\n> > +       void configure(const Size &size) override;\n> > +};\n> > +\n> > +class DiagonalLinesGenerator : public TestPatternGenerator\n> > +{\n> > +public:\n> > +       /* Generate a template buffer of the diagonal lines test pattern. */\n> > +       void configure(const Size &size) override;\n> > +};\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\n> > index d1584f59..2b258492 100644\n> > --- a/src/libcamera/pipeline/virtual/virtual.cpp\n> > +++ b/src/libcamera/pipeline/virtual/virtual.cpp\n> > @@ -34,6 +34,7 @@\n> >  #include \"libcamera/internal/camera.h\"\n> >  #include \"libcamera/internal/dma_buf_allocator.h\"\n> >  #include \"libcamera/internal/formats.h\"\n> > +#include \"libcamera/internal/framebuffer.h\"\n> >  #include \"libcamera/internal/pipeline_handler.h\"\n> >\n> >  namespace libcamera {\n> > @@ -93,6 +94,8 @@ private:\n> >                 return static_cast<VirtualCameraData *>(camera->_d());\n> >         }\n> >\n> > +       void initFrameGenerator(Camera *camera);\n> > +\n> >         DmaBufAllocator dmaBufAllocator_;\n> >  };\n> >\n> > @@ -227,8 +230,10 @@ int PipelineHandlerVirtual::configure(Camera *camera,\n> >                                       CameraConfiguration *config)\n> >  {\n> >         VirtualCameraData *data = cameraData(camera);\n> > -       for (auto [i, c] : utils::enumerate(*config))\n> > +       for (auto [i, c] : utils::enumerate(*config)) {\n> >                 c.setStream(&data->streamConfigs_[i].stream);\n> > +               data->streamConfigs_[i].frameGenerator->configure(c.size);\n> > +       }\n> >\n> >         return 0;\n> >  }\n> > @@ -264,8 +269,24 @@ void PipelineHandlerVirtual::stopDevice([[maybe_unused]] Camera *camera)\n> >  int PipelineHandlerVirtual::queueRequestDevice([[maybe_unused]] Camera *camera,\n> >                                                Request *request)\n> >  {\n> > -       for (auto it : request->buffers())\n> > -               completeBuffer(request, it.second);\n> > +       VirtualCameraData *data = cameraData(camera);\n> > +\n> > +       for (auto const &[stream, buffer] : request->buffers()) {\n> > +               bool found = false;\n> > +               /* map buffer and fill test patterns */\n> > +               for (auto &streamConfig : data->streamConfigs_) {\n> > +                       if (stream == &streamConfig.stream) {\n> > +                               found = true;\n> > +                               if (streamConfig.frameGenerator->generateFrame(\n> > +                                           stream->configuration().size, buffer))\n> > +                                       buffer->_d()->cancel();\n> > +\n> > +                               completeBuffer(request, buffer);\n> > +                               break;\n> > +                       }\n> > +               }\n> > +               ASSERT(found);\n> > +       }\n> >\n> >         request->metadata().set(controls::SensorTimestamp, currentTimestamp());\n> >         completeRequest(request);\n> > @@ -307,11 +328,25 @@ bool PipelineHandlerVirtual::match([[maybe_unused]] DeviceEnumerator *enumerator\n> >\n> >         const std::string id = \"Virtual0\";\n> >         std::shared_ptr<Camera> camera = Camera::create(std::move(data), id, streams);\n> > +\n> > +       initFrameGenerator(camera.get());\n> > +\n> >         registerCamera(std::move(camera));\n> >\n> >         return true;\n> >  }\n> >\n> > +void PipelineHandlerVirtual::initFrameGenerator(Camera *camera)\n> > +{\n> > +       auto data = cameraData(camera);\n> > +       for (auto &streamConfig : data->streamConfigs_) {\n> > +               if (data->testPattern_ == TestPattern::DiagonalLines)\n> > +                       streamConfig.frameGenerator = std::make_unique<DiagonalLinesGenerator>();\n> > +               else\n> > +                       streamConfig.frameGenerator = std::make_unique<ColorBarsGenerator>();\n> > +       }\n> > +}\n> > +\n> >  REGISTER_PIPELINE_HANDLER(PipelineHandlerVirtual, \"virtual\")\n> >\n> >  } /* namespace libcamera */\n> > diff --git a/src/libcamera/pipeline/virtual/virtual.h b/src/libcamera/pipeline/virtual/virtual.h\n> > index 4df70a13..9b79ac09 100644\n> > --- a/src/libcamera/pipeline/virtual/virtual.h\n> > +++ b/src/libcamera/pipeline/virtual/virtual.h\n> > @@ -15,6 +15,8 @@\n> >  #include \"libcamera/internal/camera.h\"\n> >  #include \"libcamera/internal/pipeline_handler.h\"\n> >\n> > +#include \"test_pattern_generator.h\"\n> > +\n> >  namespace libcamera {\n> >\n> >  class VirtualCameraData : public Camera::Private\n> > @@ -28,6 +30,7 @@ public:\n> >         };\n> >         struct StreamConfig {\n> >                 Stream stream;\n> > +               std::unique_ptr<FrameGenerator> frameGenerator;\n> >         };\n> >\n> >         VirtualCameraData(PipelineHandler *pipe,\n> > @@ -35,6 +38,8 @@ public:\n> >\n> >         ~VirtualCameraData() = default;\n> >\n> > +       TestPattern testPattern_ = TestPattern::ColorBars;\n> > +\n> >         const std::vector<Resolution> supportedResolutions_;\n> >         Size maxResolutionSize_;\n> >         Size minResolutionSize_;\n> > diff --git a/src/meson.build b/src/meson.build\n> > index 165a77bb..91bea775 100644\n> > --- a/src/meson.build\n> > +++ b/src/meson.build\n> > @@ -27,6 +27,25 @@ else\n> >      ipa_sign_module = false\n> >  endif\n> >\n> > +libyuv_dep = dependency('libyuv', required : false)\n> > +\n> > +# Fallback to a subproject if libyuv isn't found, as it's typically not\n> > +# provided by distributions.\n> > +if not libyuv_dep.found()\n> > +    cmake = import('cmake')\n> > +\n> > +    libyuv_vars = cmake.subproject_options()\n> > +    libyuv_vars.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'})\n> > +    libyuv_vars.set_override_option('cpp_std', 'c++17')\n> > +    libyuv_vars.append_compile_args('cpp',\n> > +         '-Wno-sign-compare',\n> > +         '-Wno-unused-variable',\n> > +         '-Wno-unused-parameter')\n> > +    libyuv_vars.append_link_args('-ljpeg')\n> > +    libyuv = cmake.subproject('libyuv', options : libyuv_vars)\n> > +    libyuv_dep = libyuv.dependency('yuv')\n> > +endif\n> > +\n>\n> I'm not yet sure in my mind if this should be in the top level where\n> other dependencies are handled, or if here is fine. As this is the\n> highest common layer for both android and libcamera - I think this is\n> fine.\n>\n> It would have been nicer to split this meson change out to a distinct\n> patch but it's fine now.\n>\n> I'm going to say it's fine to move here, and if we decide differently\n> later - it's easy to move.\n>\n>\n> With at least that [8][3] fixed, which I think is the only 'incorrect'\n> thing, then you can add:\n>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nThanks Kieran, true that there are some optimization that we\ncan work on, while maybe save the work for now, until we\nreally need them.\n\n\n\n>\n>\n> >  # libcamera must be built first as a dependency to the other components.\n> >  subdir('libcamera')\n> >\n> > --\n> > 2.46.1.824.gd892dcdcdd-goog\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 264E4BD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  4 Oct 2024 10:00:44 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C025763533;\n\tFri,  4 Oct 2024 12:00:43 +0200 (CEST)","from mail-lj1-x232.google.com (mail-lj1-x232.google.com\n\t[IPv6:2a00:1450:4864:20::232])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 63C0763523\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  4 Oct 2024 12:00:42 +0200 (CEST)","by mail-lj1-x232.google.com with SMTP id\n\t38308e7fff4ca-2facf481587so18557481fa.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 04 Oct 2024 03:00:42 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=chromium.org header.i=@chromium.org\n\theader.b=\"TQIgq6Ag\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=chromium.org; s=google; t=1728036042; x=1728640842;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=nf7CDRj7bIM8td5OMGHVwk8d/NzDEa7YcxA5OCnhX2Q=;\n\tb=TQIgq6AgP13soSdE3rdH3EUi8y7eY9aucznWtidNd9Q+yhXNsRBBhebCfqz1HqX8hP\n\tIMqngAog9yR4Iyq0ba2fFJDeheuYF3PA8+l5yUEyFfg+QsAOHJ4pPJz4wTIE/rTtZFeJ\n\tv7UWuB+KiNoSOgHEEUlc2iQJq5nsG331lW3Tk=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1728036042; x=1728640842;\n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=nf7CDRj7bIM8td5OMGHVwk8d/NzDEa7YcxA5OCnhX2Q=;\n\tb=q+ERurHNMupSXbScnig15na3KDttA7D7RHLno6fhCfWkF7s78d/hBOAfjmQKdtuNXL\n\tvFUGOnI2wRkdoDQC8tC+ESrEKi4cvuvD5e7vEM2b7k8aJzU6Rr5IzfLSWt+fA/bn4hjS\n\tBuSxM+h57nqYcJZzpTuuPFNjmX9CSvRC75RmTzzf3T81ZsvlT+ubD3hKVABGdmyU1LYa\n\tIvWiDfPPg2rEGjxPkzP8drjKWm9WiFOpslFiLtHvBXnAM3pLcoFDnkA4OlMKpCQ84fun\n\tiizoJg10XyxO7/OPAG/YuIsLLJvav034wdGgwDWxu2l2yD9ly0+vum2CSC0jWtNHoBJ9\n\tqNKw==","X-Gm-Message-State":"AOJu0YyxcwISeakm8+C262+1FlagemUZfIMgXbkcL4XR+Hls4+QNMmkL\n\t9dC5yuNpmjkTAxb+0MQnKcQo2DqXZxOpcVfRD5lRRf4UYXAnk86+63ODD1QAi4yA8wBcMNnsN+J\n\tLSzY5pNVDG2CEIgX/3FNFvVru/7Bb2jmaH2yygVz+3lqV+9A=","X-Google-Smtp-Source":"AGHT+IHOfBc/rooKRO41uYeh7sjRSJBBAoFBPv8JcL2jTAaRsEQjfwd1eU/ZiGsD26yz+mPQASh4nDFjAq6i+qGftJQ=","X-Received":"by 2002:a2e:be8c:0:b0:2fa:d40f:559 with SMTP id\n\t38308e7fff4ca-2faf3c1e6c3mr11647351fa.18.1728036041403;\n\tFri, 04 Oct 2024 03:00:41 -0700 (PDT)","MIME-Version":"1.0","References":"<20240930063342.3014837-1-chenghaoyang@google.com>\n\t<20240930063342.3014837-5-chenghaoyang@google.com>\n\t<172794995331.1619946.6467404915728462370@ping.linuxembedded.co.uk>","In-Reply-To":"<172794995331.1619946.6467404915728462370@ping.linuxembedded.co.uk>","From":"Cheng-Hao Yang <chenghaoyang@chromium.org>","Date":"Fri, 4 Oct 2024 18:00:30 +0800","Message-ID":"<CAEB1ahtfnkXm4ta5wi6nw-YBvqx5SfXMUJdCOcUjGxHzfwFFjA@mail.gmail.com>","Subject":"Re: [PATCH v14 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, Konami Shu <konamiz@google.com>, \n\tYunke Cao <yunkec@chromium.org>, Tomasz Figa <tfiga@chromium.org>, \n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]