Patch Detail
Show a patch.
GET /api/1.1/patches/20972/?format=api
{ "id": 20972, "url": "https://patchwork.libcamera.org/api/1.1/patches/20972/?format=api", "web_url": "https://patchwork.libcamera.org/patch/20972/", "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": "<20240820172202.526547-5-chenghaoyang@google.com>", "date": "2024-08-20T16:23:35", "name": "[v9,4/8] libcamera: pipeline: Add test pattern for VirtualPipelineHandler", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "5c913eb23b29b7ac85617df676e753758abbaf20", "submitter": { "id": 117, "url": "https://patchwork.libcamera.org/api/1.1/people/117/?format=api", "name": "Cheng-Hao Yang", "email": "chenghaoyang@chromium.org" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/20972/mbox/", "series": [ { "id": 4529, "url": "https://patchwork.libcamera.org/api/1.1/series/4529/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4529", "date": "2024-08-20T16:23:31", "name": "Add VirtualPipelineHandler", "version": 9, "mbox": "https://patchwork.libcamera.org/series/4529/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/20972/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/20972/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 076F4C32A9\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 20 Aug 2024 17:22:30 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1130C633CE;\n\tTue, 20 Aug 2024 19:22:29 +0200 (CEST)", "from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com\n\t[IPv6:2a00:1450:4864:20::42b])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A0EFF633D1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 20 Aug 2024 19:22:17 +0200 (CEST)", "by mail-wr1-x42b.google.com with SMTP id\n\tffacd0b85a97d-3718706cf8aso3572107f8f.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 20 Aug 2024 10:22:17 -0700 (PDT)", "from chenghaoyang-germany.c.googlers.com.com\n\t(161.126.77.34.bc.googleusercontent.com. [34.77.126.161])\n\tby smtp.gmail.com with ESMTPSA id\n\t5b1f17b1804b1-42ab6e90db5sm30328575e9.0.2024.08.20.10.22.16\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 20 Aug 2024 10:22:16 -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=\"Bt2gJQwL\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=chromium.org; s=google; t=1724174537; x=1724779337;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=0zBA+T2Bn4jMOL2ggU7WXrBRpoKtYkDL3N71bwwLyho=;\n\tb=Bt2gJQwLPzy0DOcHfCY+2+be3KeSZ1Rf31zh4zdARiB5lj4wcZsQIVZWiew3j0K85d\n\tQFqseXaaoyBhw6YPikgOn8+YoAT3Ca/QwkNSSqSf3JvgHngEp8gxYi0HM9NOgeU4ZeoL\n\tMULMDyLJoSRzGXmqgx+LOO51wRT600WUc2/Cs=", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1724174537; x=1724779337;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=0zBA+T2Bn4jMOL2ggU7WXrBRpoKtYkDL3N71bwwLyho=;\n\tb=XsASpSXYRuIJbno4nhr4JXv7tVZJe24Z9dYO40PkCxfOZM5iNfkhQjFicRS85j/WVm\n\tTY1JTVKA0emg3tLOZQg5b9fTyQuzpO6f7bU10aiW8rlsVKYdpKevjwklyHYPuiF5/m6X\n\tWuYPuDJzN7qGLnVEZdSXMpe+cfgIlyUfkFkd7qhDVNiqAjMw5qwCSv26ZqSNVDvKHT2K\n\t/gYDkzKuk8GhCFC3z6keWWmGvqL1nwUHmb2E7ewoEYFkxpS1o6C/8HyujIFKqHuX0ErY\n\tJId//pX02TPajKVbmVrySNPTZXWAGZSqDAyV5Pm9743XF7aC8TnoqhWSttF4HueFihrc\n\tnpLA==", "X-Gm-Message-State": "AOJu0Yy2j9IbFWbqNhg3sazHB0MkT8DjtD+uRXJyP2L2uoBt8cnvcVFp\n\tmhJwNVPlqnys+QT0KeoW5rn0gooaX7aJvRT5cjHEQWOSauQ5n7sAo0KawpVVOkwHiZVc2UzkDZN\n\tVpNm+Hgg=", "X-Google-Smtp-Source": "AGHT+IGq742r/AyS2YSBP3a78zY+h7g7dDV+2PVTyMB5IsMX7RDuE1YvOp6H/F8bOeF7wjKlSvtfJw==", "X-Received": "by 2002:adf:f6c6:0:b0:371:899b:5c5 with SMTP id\n\tffacd0b85a97d-37194659e95mr8696910f8f.27.1724174536753; \n\tTue, 20 Aug 2024 10:22:16 -0700 (PDT)", "From": "Harvey Yang <chenghaoyang@chromium.org>", "X-Google-Original-From": "Harvey Yang <chenghaoyang@google.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Konami Shu <konamiz@google.com>, Harvey Yang <chenghaoyang@chromium.org>,\n\tYunke Cao <yunkec@chromium.org>, Tomasz Figa <tfiga@chromium.org>", "Subject": "[PATCH v9 4/8] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler", "Date": "Tue, 20 Aug 2024 16:23:35 +0000", "Message-ID": "<20240820172202.526547-5-chenghaoyang@google.com>", "X-Mailer": "git-send-email 2.46.0.184.g6999bdac58-goog", "In-Reply-To": "<20240820172202.526547-1-chenghaoyang@google.com>", "References": "<20240820172202.526547-1-chenghaoyang@google.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "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>" }, "content": "From: Konami Shu <konamiz@google.com>\n\n- There are two test patterns: color bars and diagonal lines\n- Add class for generating test patterns\n- Add libyuv to build dependencies\n- Make VirtualPipelineHandler show the test pattern\n- Format the code\n\n- Rename test_pattern to frame_generator\n- reflect comment\n\t- Fix const variable name\n\t- Use #pragma once\n\t- Make configure() private\n\nSigned-off-by: Konami Shu <konamiz@google.com>\nCo-developed-by: Harvey Yang <chenghaoyang@chromium.org>\nCo-developed-by: Yunke Cao <yunkec@chromium.org>\nCo-developed-by: Tomasz Figa <tfiga@chromium.org>\n---\n .../pipeline/virtual/frame_generator.h | 33 ++++++\n src/libcamera/pipeline/virtual/meson.build | 22 ++++\n .../virtual/test_pattern_generator.cpp | 112 ++++++++++++++++++\n .../pipeline/virtual/test_pattern_generator.h | 58 +++++++++\n src/libcamera/pipeline/virtual/virtual.cpp | 28 ++++-\n src/libcamera/pipeline/virtual/virtual.h | 8 ++\n 6 files changed, 258 insertions(+), 3 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", "diff": "diff --git a/src/libcamera/pipeline/virtual/frame_generator.h b/src/libcamera/pipeline/virtual/frame_generator.h\nnew file mode 100644\nindex 000000000..9699af7a4\n--- /dev/null\n+++ b/src/libcamera/pipeline/virtual/frame_generator.h\n@@ -0,0 +1,33 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2023, 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+\tvirtual ~FrameGenerator() = default;\n+\n+\t/* Create buffers for using them in `generateFrame` */\n+\tvirtual void configure(const Size &size) = 0;\n+\n+\t/** Fill the output frame buffer.\n+\t * Use the frame at the frameCount of image frames\n+\t */\n+\tvirtual void generateFrame(const Size &size,\n+\t\t\t\t const FrameBuffer *buffer) = 0;\n+\n+protected:\n+\tFrameGenerator() {}\n+};\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/pipeline/virtual/meson.build b/src/libcamera/pipeline/virtual/meson.build\nindex ba7ff754e..e1e65e68d 100644\n--- a/src/libcamera/pipeline/virtual/meson.build\n+++ b/src/libcamera/pipeline/virtual/meson.build\n@@ -2,4 +2,26 @@\n \n libcamera_sources += files([\n 'virtual.cpp',\n+ 'test_pattern_generator.cpp',\n ])\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+libcamera_deps += [libyuv_dep]\ndiff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.cpp b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\nnew file mode 100644\nindex 000000000..8dfe626e5\n--- /dev/null\n+++ b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n@@ -0,0 +1,112 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2023, 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+namespace libcamera {\n+\n+LOG_DECLARE_CATEGORY(Virtual)\n+\n+static const unsigned int kARGBSize = 4;\n+\n+void TestPatternGenerator::generateFrame(\n+\tconst Size &size,\n+\tconst FrameBuffer *buffer)\n+{\n+\tMappedFrameBuffer mappedFrameBuffer(buffer,\n+\t\t\t\t\t MappedFrameBuffer::MapFlag::Write);\n+\n+\tauto planes = mappedFrameBuffer.planes();\n+\n+\t/* Convert the template_ to the frame buffer */\n+\tint ret = libyuv::ARGBToNV12(\n+\t\ttemplate_.get(), /*src_stride_argb=*/size.width * kARGBSize,\n+\t\tplanes[0].begin(), size.width,\n+\t\tplanes[1].begin(), size.width,\n+\t\tsize.width, size.height);\n+\tif (ret != 0) {\n+\t\tLOG(Virtual, Error) << \"ARGBToNV12() failed with \" << ret;\n+\t}\n+}\n+\n+std::unique_ptr<ColorBarsGenerator> ColorBarsGenerator::create()\n+{\n+\treturn std::make_unique<ColorBarsGenerator>();\n+}\n+\n+void ColorBarsGenerator::configure(const Size &size)\n+{\n+\tconstexpr uint8_t kColorBar[8][3] = {\n+\t\t// R, G, B\n+\t\t{ 0xff, 0xff, 0xff }, // White\n+\t\t{ 0xff, 0xff, 0x00 }, // Yellow\n+\t\t{ 0x00, 0xff, 0xff }, // Cyan\n+\t\t{ 0x00, 0xff, 0x00 }, // Green\n+\t\t{ 0xff, 0x00, 0xff }, // Magenta\n+\t\t{ 0xff, 0x00, 0x00 }, // Red\n+\t\t{ 0x00, 0x00, 0xff }, // Blue\n+\t\t{ 0x00, 0x00, 0x00 }, // Black\n+\t};\n+\n+\ttemplate_ = std::make_unique<uint8_t[]>(\n+\t\tsize.width * size.height * kARGBSize);\n+\n+\tunsigned int colorBarWidth = size.width / std::size(kColorBar);\n+\n+\tuint8_t *buf = template_.get();\n+\tfor (size_t h = 0; h < size.height; h++) {\n+\t\tfor (size_t w = 0; w < size.width; w++) {\n+\t\t\t// repeat when the width is exceed\n+\t\t\tint index = (w / colorBarWidth) % std::size(kColorBar);\n+\n+\t\t\t*buf++ = kColorBar[index][2]; // B\n+\t\t\t*buf++ = kColorBar[index][1]; // G\n+\t\t\t*buf++ = kColorBar[index][0]; // R\n+\t\t\t*buf++ = 0x00; // A\n+\t\t}\n+\t}\n+}\n+\n+std::unique_ptr<DiagonalLinesGenerator> DiagonalLinesGenerator::create()\n+{\n+\treturn std::make_unique<DiagonalLinesGenerator>();\n+}\n+\n+void DiagonalLinesGenerator::configure(const Size &size)\n+{\n+\tconstexpr uint8_t kColorBar[8][3] = {\n+\t\t// R, G, B\n+\t\t{ 0xff, 0xff, 0xff }, // White\n+\t\t{ 0x00, 0x00, 0x00 }, // Black\n+\t};\n+\n+\ttemplate_ = std::make_unique<uint8_t[]>(\n+\t\tsize.width * size.height * kARGBSize);\n+\n+\tunsigned int lineWidth = size.width / 10;\n+\n+\tuint8_t *buf = template_.get();\n+\tfor (size_t h = 0; h < size.height; h++) {\n+\t\tfor (size_t w = 0; w < size.width; w++) {\n+\t\t\t// repeat when the width is exceed\n+\t\t\tint index = ((w + h) / lineWidth) % 2;\n+\n+\t\t\t*buf++ = kColorBar[index][2]; // B\n+\t\t\t*buf++ = kColorBar[index][1]; // G\n+\t\t\t*buf++ = kColorBar[index][0]; // R\n+\t\t\t*buf++ = 0x00; // A\n+\t\t}\n+\t}\n+}\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/pipeline/virtual/test_pattern_generator.h b/src/libcamera/pipeline/virtual/test_pattern_generator.h\nnew file mode 100644\nindex 000000000..ed8d4e43b\n--- /dev/null\n+++ b/src/libcamera/pipeline/virtual/test_pattern_generator.h\n@@ -0,0 +1,58 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2023, 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+\tColorBars = 0,\n+\tDiagonalLines = 1,\n+};\n+\n+class TestPatternGenerator : public FrameGenerator\n+{\n+private:\n+\tvoid generateFrame(const Size &size,\n+\t\t\t const FrameBuffer *buffer) override;\n+\n+protected:\n+\t/* Shift the buffer by 1 pixel left each frame */\n+\tvoid shiftLeft(const Size &size);\n+\t/* Buffer of test pattern template */\n+\tstd::unique_ptr<uint8_t[]> template_;\n+};\n+\n+class ColorBarsGenerator : public TestPatternGenerator\n+{\n+public:\n+\tstatic std::unique_ptr<ColorBarsGenerator> create();\n+\n+private:\n+\t/* Generate a template buffer of the color bar test pattern. */\n+\tvoid configure(const Size &size) override;\n+};\n+\n+class DiagonalLinesGenerator : public TestPatternGenerator\n+{\n+public:\n+\tstatic std::unique_ptr<DiagonalLinesGenerator> create();\n+\n+private:\n+\t/* Generate a template buffer of the diagonal lines test pattern. */\n+\tvoid configure(const Size &size) override;\n+};\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\nindex 74eb8c7ad..357fdd035 100644\n--- a/src/libcamera/pipeline/virtual/virtual.cpp\n+++ b/src/libcamera/pipeline/virtual/virtual.cpp\n@@ -192,10 +192,14 @@ int PipelineHandlerVirtual::exportFrameBuffers(\n \treturn dmaBufAllocator_.exportBuffers(config.bufferCount, planeSizes, buffers);\n }\n \n-int PipelineHandlerVirtual::start([[maybe_unused]] Camera *camera,\n+int PipelineHandlerVirtual::start(Camera *camera,\n \t\t\t\t [[maybe_unused]] const ControlList *controls)\n {\n \t/* \\todo Start reading the virtual video if any. */\n+\tVirtualCameraData *data = cameraData(camera);\n+\n+\tdata->frameGenerator_->configure(data->stream_.configuration().size);\n+\n \treturn 0;\n }\n \n@@ -207,9 +211,14 @@ void PipelineHandlerVirtual::stopDevice([[maybe_unused]] Camera *camera)\n int PipelineHandlerVirtual::queueRequestDevice([[maybe_unused]] Camera *camera,\n \t\t\t\t\t Request *request)\n {\n+\tVirtualCameraData *data = cameraData(camera);\n+\n \t/* \\todo Read from the virtual video if any. */\n-\tfor (auto it : request->buffers())\n-\t\tcompleteBuffer(request, it.second);\n+\tfor (auto const &[stream, buffer] : request->buffers()) {\n+\t\t/* map buffer and fill test patterns */\n+\t\tdata->frameGenerator_->generateFrame(stream->configuration().size, buffer);\n+\t\tcompleteBuffer(request, buffer);\n+\t}\n \n \trequest->metadata().set(controls::SensorTimestamp, currentTimestamp());\n \tcompleteRequest(request);\n@@ -241,11 +250,24 @@ bool PipelineHandlerVirtual::match([[maybe_unused]] DeviceEnumerator *enumerator\n \tstd::set<Stream *> streams{ &data->stream_ };\n \tconst std::string id = \"Virtual0\";\n \tstd::shared_ptr<Camera> camera = Camera::create(std::move(data), id, streams);\n+\n+\tinitFrameGenerator(camera.get());\n+\n \tregisterCamera(std::move(camera));\n \n \treturn false; // Prevent infinite loops for now\n }\n \n+void PipelineHandlerVirtual::initFrameGenerator(Camera *camera)\n+{\n+\tauto data = cameraData(camera);\n+\tif (data->testPattern_ == TestPattern::DiagonalLines) {\n+\t\tdata->frameGenerator_ = DiagonalLinesGenerator::create();\n+\t} else {\n+\t\tdata->frameGenerator_ = ColorBarsGenerator::create();\n+\t}\n+}\n+\n REGISTER_PIPELINE_HANDLER(PipelineHandlerVirtual, \"virtual\")\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/pipeline/virtual/virtual.h b/src/libcamera/pipeline/virtual/virtual.h\nindex 6fc6b34d8..fecd9fa6f 100644\n--- a/src/libcamera/pipeline/virtual/virtual.h\n+++ b/src/libcamera/pipeline/virtual/virtual.h\n@@ -13,6 +13,8 @@\n #include \"libcamera/internal/dma_buf_allocator.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@@ -29,9 +31,13 @@ public:\n \n \t~VirtualCameraData() = default;\n \n+\tTestPattern testPattern_;\n+\n \tstd::vector<Resolution> supportedResolutions_;\n \n \tStream stream_;\n+\n+\tstd::unique_ptr<FrameGenerator> frameGenerator_;\n };\n \n class VirtualCameraConfiguration : public CameraConfiguration\n@@ -72,6 +78,8 @@ private:\n \t\treturn static_cast<VirtualCameraData *>(camera->_d());\n \t}\n \n+\tvoid initFrameGenerator(Camera *camera);\n+\n \tDmaBufAllocator dmaBufAllocator_;\n };\n \n", "prefixes": [ "v9", "4/8" ] }