Patch Detail
Show a patch.
GET /api/1.1/patches/21728/?format=api
{ "id": 21728, "url": "https://patchwork.libcamera.org/api/1.1/patches/21728/?format=api", "web_url": "https://patchwork.libcamera.org/patch/21728/", "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": "<20241022074544.3790451-5-chenghaoyang@chromium.org>", "date": "2024-10-22T07:43:40", "name": "[v16,4/7] libcamera: pipeline: Add test pattern for VirtualPipelineHandler", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "8c1e7081613acd5e96c39dfce02d0d6835957ffe", "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/21728/mbox/", "series": [ { "id": 4733, "url": "https://patchwork.libcamera.org/api/1.1/series/4733/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4733", "date": "2024-10-22T07:43:36", "name": "Add VirtualPipelineHandler", "version": 16, "mbox": "https://patchwork.libcamera.org/series/4733/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/21728/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/21728/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 6963DC3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 22 Oct 2024 07:46:05 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id F3346653A1;\n\tTue, 22 Oct 2024 09:46:04 +0200 (CEST)", "from mail-pf1-x42f.google.com (mail-pf1-x42f.google.com\n\t[IPv6:2607:f8b0:4864:20::42f])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 10C9D6053E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 22 Oct 2024 09:45:59 +0200 (CEST)", "by mail-pf1-x42f.google.com with SMTP id\n\td2e1a72fcca58-718e9c8bd83so4336762b3a.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 22 Oct 2024 00:45:58 -0700 (PDT)", "from chenghaoyang-low.c.googlers.com.com\n\t(27.247.221.35.bc.googleusercontent.com. [35.221.247.27])\n\tby smtp.gmail.com with ESMTPSA id\n\td2e1a72fcca58-71ec13d75aesm4091024b3a.124.2024.10.22.00.45.55\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 22 Oct 2024 00:45:56 -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=\"fLRuPvjy\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=chromium.org; s=google; t=1729583157; x=1730187957;\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=Jm1h203Uh/V37355xdknOjAvs+JmwDXrPT0yDbd78Gk=;\n\tb=fLRuPvjyllMvpnEUk/Er9eUfp0qT8dIMjIBdrtgIiJZ+10ov9Pykjg1HeMoQq9figJ\n\telITg2hJZ4iZw5LFsf5RgH4hXEpt0zfrdASljVaffQuQHUdIOhU6tkfFTYV8gKtmard8\n\tLhiJg+IuvR3JK+1x7ok5TbXB0gtLgafxGE/9k=", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1729583157; x=1730187957;\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=Jm1h203Uh/V37355xdknOjAvs+JmwDXrPT0yDbd78Gk=;\n\tb=HmD7+3tFl2lfh8DdxujMR0Su6ai/Yhtmndo+Ij86Cgh8TWnCHFxXC5CGHUOwYiruqd\n\tskyuviHWMwJTb6o8wwDbPPs1/htWAdPVN+WcrCJLm8woMIJEZMYLjo0uaTbIXVbMamLm\n\tXTxgBzWOxPZzskX43ch/Kfj1s0IzSa4AyUI+Q81NLDIG92glLf6lqQ2FWfOd/Z9lEly7\n\tKg+xGOHmMhLYWgPbhfVS9MYoPeiHoB3CuFTVTwiAJHTb6j+DPzU/OGoVSGKV4rzf/k85\n\tOcP8MAwdswfbaOY0Czpdauw217XwYMNtl3/hWnbat0Wl9Gy8Ys4kQv4jFooHl35kHrZ+\n\ttO4A==", "X-Gm-Message-State": "AOJu0YyQ+tcrxRGGvwhZNSPh9G0BJL22WP/cgKkR1INVM7btoDHLbbBg\n\tLJygHQJr9PKCrGLNr1BP/jk9iMwzI/LXq5MEtWPiv24g3GgmN29P4AkvykP1LJAYPGG8y3/X85M\n\t=", "X-Google-Smtp-Source": "AGHT+IHD6RTqV8u+y6aYHighCn8RIDzFtqHP82q2K3GtQdVvUHbbBb8aXYWCZmunWxHT9OKyyYgo7w==", "X-Received": "by 2002:a05:6a00:b1f:b0:71e:44f6:690f with SMTP id\n\td2e1a72fcca58-71edc176923mr3290486b3a.8.1729583157083; \n\tTue, 22 Oct 2024 00:45:57 -0700 (PDT)", "From": "Harvey Yang <chenghaoyang@chromium.org>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Harvey Yang <chenghaoyang@chromium.org>, Konami Shu <konamiz@google.com>,\n\tYunke Cao <yunkec@chromium.org>, Tomasz Figa <tfiga@chromium.org>,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>", "Subject": "[PATCH v16 4/7] libcamera: pipeline: Add test pattern for\n\tVirtualPipelineHandler", "Date": "Tue, 22 Oct 2024 07:43:40 +0000", "Message-ID": "<20241022074544.3790451-5-chenghaoyang@chromium.org>", "X-Mailer": "git-send-email 2.47.0.105.g07ac214952-goog", "In-Reply-To": "<20241022074544.3790451-1-chenghaoyang@chromium.org>", "References": "<20241022074544.3790451-1-chenghaoyang@chromium.org>", "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": "Add a test pattern generator class hierarchy for the Virtual\npipeline handler.\n\nImplement two types of test patterns: color bars and diagonal lines\ngenerator and use them in the Virtual pipeline handler.\n\nA shifting mechanism is enabled. For each frame, the image is shifted to\nthe left by 1 pixel. It drops FPS though.\n\nAdd a dependency for libyuv to the build system to generate images\nin NV12 format from the test pattern.\n\nSigned-off-by: Konami Shu <konamiz@google.com>\nCo-developed-by: Harvey Yang <chenghaoyang@chromium.org>\nSigned-off-by: Harvey Yang <chenghaoyang@chromium.org>\nCo-developed-by: Yunke Cao <yunkec@chromium.org>\nSigned-off-by: Yunke Cao <yunkec@chromium.org>\nCo-developed-by: Tomasz Figa <tfiga@chromium.org>\nSigned-off-by: Tomasz Figa <tfiga@chromium.org>\nReviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\nReviewed-by: Kieran Bingham <kieran.bingham@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 | 136 ++++++++++++++++++\n .../pipeline/virtual/test_pattern_generator.h | 52 +++++++\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, 282 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", "diff": "diff --git a/src/android/meson.build b/src/android/meson.build\nindex 68646120a..6341ee8b0 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([\ndiff --git a/src/libcamera/pipeline/virtual/frame_generator.h b/src/libcamera/pipeline/virtual/frame_generator.h\nnew file mode 100644\nindex 000000000..a0658c45c\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+ * 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+\tvirtual void configure(const Size &size) = 0;\n+\n+\tvirtual int 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 ada1b3358..0c537777f 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]\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..7bc2b338c\n--- /dev/null\n+++ b/src/libcamera/pipeline/virtual/test_pattern_generator.cpp\n@@ -0,0 +1,136 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Google Inc.\n+ *\n+ * Derived class of FrameGenerator for 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+\t\t\t\t\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+\tshiftLeft(size);\n+\n+\t/* Convert the template_ to the frame buffer */\n+\tint ret = libyuv::ARGBToNV12(template_.get(), size.width * kARGBSize,\n+\t\t\t\t planes[0].begin(), size.width,\n+\t\t\t\t planes[1].begin(), size.width,\n+\t\t\t\t size.width, size.height);\n+\tif (ret != 0)\n+\t\tLOG(Virtual, Error) << \"ARGBToNV12() failed with \" << ret;\n+\n+\treturn ret;\n+}\n+\n+void TestPatternGenerator::shiftLeft(const Size &size)\n+{\n+\t/* Store the first column temporarily */\n+\tauto firstColumn = std::make_unique<uint8_t[]>(size.height * kARGBSize);\n+\tfor (size_t h = 0; h < size.height; h++) {\n+\t\tunsigned int index = h * size.width * kARGBSize;\n+\t\tunsigned int index1 = h * kARGBSize;\n+\t\tfirstColumn[index1] = template_[index];\n+\t\tfirstColumn[index1 + 1] = template_[index + 1];\n+\t\tfirstColumn[index1 + 2] = template_[index + 2];\n+\t\tfirstColumn[index1 + 3] = 0x00;\n+\t}\n+\n+\t/* Overwrite template_ */\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 - 1; w++) {\n+\t\t\t/* Overwrite with the pixel on the right */\n+\t\t\tunsigned int index = (h * size.width + w + 1) * kARGBSize;\n+\t\t\t*buf++ = template_[index]; /* B */\n+\t\t\t*buf++ = template_[index + 1]; /* G */\n+\t\t\t*buf++ = template_[index + 2]; /* R */\n+\t\t\t*buf++ = 0x00; /* A */\n+\t\t}\n+\t\t/* Overwrite the new last column with the original first column */\n+\t\tunsigned int index1 = h * kARGBSize;\n+\t\t*buf++ = firstColumn[index1]; /* B */\n+\t\t*buf++ = firstColumn[index1 + 1]; /* G */\n+\t\t*buf++ = firstColumn[index1 + 2]; /* R */\n+\t\t*buf++ = 0x00; /* A */\n+\t}\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\tunsigned int 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+void DiagonalLinesGenerator::configure(const Size &size)\n+{\n+\tconstexpr uint8_t kColorBar[2][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..05f4ab7a7\n--- /dev/null\n+++ b/src/libcamera/pipeline/virtual/test_pattern_generator.h\n@@ -0,0 +1,52 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Google Inc.\n+ *\n+ * Derived class of FrameGenerator for 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+public:\n+\tint generateFrame(const Size &size, const FrameBuffer *buffer) override;\n+\n+protected:\n+\t/* Buffer of test pattern template */\n+\tstd::unique_ptr<uint8_t[]> template_;\n+\n+private:\n+\t/* Shift the buffer by 1 pixel left each frame */\n+\tvoid shiftLeft(const Size &size);\n+};\n+\n+class ColorBarsGenerator : public TestPatternGenerator\n+{\n+public:\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+\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 13107874a..04fb08bb2 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@@ -94,6 +95,8 @@ private:\n \t\treturn static_cast<VirtualCameraData *>(camera->_d());\n \t}\n \n+\tvoid initFrameGenerator(Camera *camera);\n+\n \tDmaBufAllocator dmaBufAllocator_;\n \n \tbool resetCreated_ = false;\n@@ -241,8 +244,10 @@ int PipelineHandlerVirtual::configure(Camera *camera,\n \t\t\t\t CameraConfiguration *config)\n {\n \tVirtualCameraData *data = cameraData(camera);\n-\tfor (auto [i, c] : utils::enumerate(*config))\n+\tfor (auto [i, c] : utils::enumerate(*config)) {\n \t\tc.setStream(&data->streamConfigs_[i].stream);\n+\t\tdata->streamConfigs_[i].frameGenerator->configure(c.size);\n+\t}\n \n \treturn 0;\n }\n@@ -278,8 +283,24 @@ 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-\tfor (auto it : request->buffers())\n-\t\tcompleteBuffer(request, it.second);\n+\tVirtualCameraData *data = cameraData(camera);\n+\n+\tfor (auto const &[stream, buffer] : request->buffers()) {\n+\t\tbool found = false;\n+\t\t/* map buffer and fill test patterns */\n+\t\tfor (auto &streamConfig : data->streamConfigs_) {\n+\t\t\tif (stream == &streamConfig.stream) {\n+\t\t\t\tfound = true;\n+\t\t\t\tif (streamConfig.frameGenerator->generateFrame(\n+\t\t\t\t\t stream->configuration().size, buffer))\n+\t\t\t\t\tbuffer->_d()->cancel();\n+\n+\t\t\t\tcompleteBuffer(request, buffer);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tASSERT(found);\n+\t}\n \n \trequest->metadata().set(controls::SensorTimestamp, currentTimestamp());\n \tcompleteRequest(request);\n@@ -325,6 +346,9 @@ bool PipelineHandlerVirtual::match([[maybe_unused]] DeviceEnumerator *enumerator\n \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 \tresetCreated_ = true;\n@@ -332,6 +356,17 @@ bool PipelineHandlerVirtual::match([[maybe_unused]] DeviceEnumerator *enumerator\n \treturn true;\n }\n \n+void PipelineHandlerVirtual::initFrameGenerator(Camera *camera)\n+{\n+\tauto data = cameraData(camera);\n+\tfor (auto &streamConfig : data->streamConfigs_) {\n+\t\tif (data->testPattern_ == TestPattern::DiagonalLines)\n+\t\t\tstreamConfig.frameGenerator = std::make_unique<DiagonalLinesGenerator>();\n+\t\telse\n+\t\t\tstreamConfig.frameGenerator = std::make_unique<ColorBarsGenerator>();\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 f6cacd277..297b6b672 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 \t};\n \tstruct StreamConfig {\n \t\tStream stream;\n+\t\tstd::unique_ptr<FrameGenerator> frameGenerator;\n \t};\n \n \tVirtualCameraData(PipelineHandler *pipe,\n@@ -35,6 +38,8 @@ public:\n \n \t~VirtualCameraData() = default;\n \n+\tTestPattern testPattern_ = TestPattern::ColorBars;\n+\n \tconst std::vector<Resolution> supportedResolutions_;\n \tSize maxResolutionSize_;\n \tSize minResolutionSize_;\ndiff --git a/src/meson.build b/src/meson.build\nindex 165a77bb9..91bea7753 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 # libcamera must be built first as a dependency to the other components.\n subdir('libcamera')\n \n", "prefixes": [ "v16", "4/7" ] }