{"id":23221,"url":"https://patchwork.libcamera.org/api/1.1/patches/23221/?format=json","web_url":"https://patchwork.libcamera.org/patch/23221/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20250422215920.4297-9-bryan.odonoghue@linaro.org>","date":"2025-04-22T21:59:01","name":"[08/27] libcamera: swstats_cpu: Add support for YUV420","commit_ref":null,"pull_url":null,"state":"rfc","archived":false,"hash":"61451d97002e046bba9a925800f0b3cbdd72b7b4","submitter":{"id":175,"url":"https://patchwork.libcamera.org/api/1.1/people/175/?format=json","name":"Bryan O'Donoghue","email":"bryan.odonoghue@linaro.org"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/23221/mbox/","series":[{"id":5142,"url":"https://patchwork.libcamera.org/api/1.1/series/5142/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5142","date":"2025-04-22T21:58:53","name":"RFC: Add in a eGL based GPUISP in libcamera","version":1,"mbox":"https://patchwork.libcamera.org/series/5142/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/23221/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/23221/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 75CF2C327D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 22 Apr 2025 21:59:38 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E4F8F68B2D;\n\tTue, 22 Apr 2025 23:59:37 +0200 (CEST)","from mail-wm1-x335.google.com (mail-wm1-x335.google.com\n\t[IPv6:2a00:1450:4864:20::335])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2421768ADB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 22 Apr 2025 23:59:31 +0200 (CEST)","by mail-wm1-x335.google.com with SMTP id\n\t5b1f17b1804b1-43ede096d73so41972645e9.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 22 Apr 2025 14:59:31 -0700 (PDT)","from inspiron14p-linux.ht.home (188-141-3-146.dynamic.upc.ie.\n\t[188.141.3.146]) by smtp.gmail.com with ESMTPSA id\n\t5b1f17b1804b1-44092d2eccesm2726615e9.20.2025.04.22.14.59.29\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 22 Apr 2025 14:59:29 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=linaro.org header.i=@linaro.org\n\theader.b=\"FXKRirtz\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=linaro.org; s=google; t=1745359170; x=1745963970;\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=2WyL2xMXY/h3W3raFwPBVRPThikL44NlUcetTPcUj1c=;\n\tb=FXKRirtz1oDqwiOACQTdBdoflW3IHlNcnmu31yJ3NpDyctDMN6nDkuvOCtOiKYfzie\n\tiffrGk33Np+uHZpNIMQG4aYgO9lQ8ZUqGepKFyGV6T6dG5KOf0C+gVYD6Lm//9ePdBMm\n\t7CZ3ND2t/DCNrFPIXIY1PJMyiCad/YOiBTJ74LbPmhjkaRMyrX5DCnxjsbNcvR8/xCqI\n\tMolPCewpKp4Rhbx1avP3PaXLvDW5gjRxiswfLzvLmM7NyO4LQuMqnwXPkI2F1CESSJd/\n\tgK0bNnh0Z3ToMzLH4WObIfBcBJ+WEM2gQlHAVJlH+WMKhgFNji58lN1Q2CBrUeHOTWEs\n\t9kug==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1745359170; x=1745963970;\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=2WyL2xMXY/h3W3raFwPBVRPThikL44NlUcetTPcUj1c=;\n\tb=xSmGoBSFpEJGDLKEWC55t4ScdVG4ZVPMOvcVPr+cEqZtDA9rApMap8Iy4qoAh6rPki\n\tvEpVi+j7zZ4WXquLWvdGBX7uYpSEWhlD8dDEuDD5RqQfrfXAN/F91x+8bFpG4hf3HtEG\n\t9/VYmggzmiDjzlMG3fFqOWs8t+MldxovGGfuhQ8pvhGsvY03JWom5qhyjxdj+Yjrnnw5\n\t/soDydt89j5A6Z2Fp3fBtMpM8LUKHgcVODSj0VW/r4hmbmRCIMpakAt6WsN20nemn0s2\n\tHjAnwafx1wirEuLO2/Srbvb1q105Al5feJLZRdX1dKToqu1CIwbz0NNx3dLqqJHTHLu2\n\t1MGQ==","X-Gm-Message-State":"AOJu0YzLoBLGDBovKKh2dvJNppQMEu4vQZSvMbfDXFhfupl8qfxoeCRq\n\tYKG9HgOmzuvfG4HeBGUuw2IePpvWv3LStPX/zXj4ZqfaRgoz5WgjW9Z9mmn10KYAxzctGc7S+Ot\n\tLZrE=","X-Gm-Gg":"ASbGnctphSIWFsGzwps47H/lJT+thkKrLW7ic9SRdJj2IKWaDMP714nJ4kgzGG5VYKN\n\tM9Oad46ug+X4bM1qq2kOkK2UR4cxXwoIPpAgMBGZIfUZYEYgcxPcG3jsqCz3h4Q3P7uN9cUGpNl\n\tHcMbCHDENB6JrRw/JLjr1lChbFiRaBavfiG11zELtzTln9DUw6dxgVK7R5py824TayPlef1AWCd\n\tzfdClcYpvso5gkg9lg8Y9RLtxg+n7JmvwKKtMQAJpyz5IuH496dxGT+ZsLLlouDkMzrjdrOZmUy\n\tJ4gdpmR3av04pQst8SohOAc1P5YhQIBwmZM4g7CVRXbwGVKAoQHUw709K+9tldzgBS95qY0y0tJ\n\twUUo0IcwpiwQkimwxWphi","X-Google-Smtp-Source":"AGHT+IGXu9D/E6Y8htk5I6VD7HQ+l0EEcucqsKaG1t6kZBbUDJj2SggbN6uYn0qilGr2V8knEwVrLA==","X-Received":"by 2002:a05:600c:3d14:b0:43d:ed:acd5 with SMTP id\n\t5b1f17b1804b1-4406ab97abbmr190953805e9.10.1745359170470; \n\tTue, 22 Apr 2025 14:59:30 -0700 (PDT)","From":"Bryan O'Donoghue <bryan.odonoghue@linaro.org>","To":"libcamera-devel@lists.libcamera.org","Cc":"hdegoede@redhat.com, mzamazal@redhat.com, bryan.odonoghue@linaro.org,\n\tbod.linux@nxsw.ie","Subject":"[PATCH 08/27] libcamera: swstats_cpu: Add support for YUV420","Date":"Tue, 22 Apr 2025 22:59:01 +0100","Message-ID":"<20250422215920.4297-9-bryan.odonoghue@linaro.org>","X-Mailer":"git-send-email 2.49.0","In-Reply-To":"<20250422215920.4297-1-bryan.odonoghue@linaro.org>","References":"<20250422215920.4297-1-bryan.odonoghue@linaro.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":"From: Hans de Goede <hdegoede@redhat.com>\n\nAdd support for processing YUV420 data.\n\nSigned-off-by: Hans de Goede <hdegoede@redhat.com>\nSigned-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>\n---\n src/libcamera/software_isp/swstats_cpu.cpp | 89 ++++++++++++++++++++++\n src/libcamera/software_isp/swstats_cpu.h   |  6 ++\n 2 files changed, 95 insertions(+)","diff":"diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\nindex af407b4d..3ec9656c 100644\n--- a/src/libcamera/software_isp/swstats_cpu.cpp\n+++ b/src/libcamera/software_isp/swstats_cpu.cpp\n@@ -13,6 +13,7 @@\n \n #include <libcamera/base/log.h>\n \n+#include <libcamera/formats.h>\n #include <libcamera/stream.h>\n \n #include \"libcamera/internal/bayer_format.h\"\n@@ -288,6 +289,40 @@ void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src[])\n \tSWSTATS_FINISH_LINE_STATS()\n }\n \n+void SwStatsCpu::statsYUV420Line0(const uint8_t *src[])\n+{\n+\tuint64_t sumY = 0;\n+\tuint64_t sumU = 0;\n+\tuint64_t sumV = 0;\n+\tuint8_t y, u, v;\n+\n+\t/* Adjust src[] for starting at window_.x */\n+\tsrc[0] += window_.x;\n+\tsrc[1] += window_.x / 2;\n+\tsrc[2] += window_.x / 2;\n+\n+\t/* x += 4 sample every other 2x2 block */\n+\tfor (int x = 0; x < (int)window_.width; x += 4) {\n+\t\t/*\n+\t\t * Take y from the top left corner of the 2x2 block instead\n+\t\t * of averaging 4 y-s.\n+\t\t */\n+\t\ty = src[0][x];\n+\t\tu = src[1][x];\n+\t\tv = src[2][x];\n+\n+\t\tsumY += y;\n+\t\tsumU += u;\n+\t\tsumV += v;\n+\n+\t\tstats_.yHistogram[y * SwIspStats::kYHistogramSize / 256]++;\n+\t}\n+\n+\tstats_.sumR_ += sumY;\n+\tstats_.sumG_ += sumU;\n+\tstats_.sumB_ += sumV;\n+}\n+\n /**\n  * \\brief Reset state to start statistics gathering for a new frame\n  *\n@@ -313,6 +348,9 @@ void SwStatsCpu::startFrame(void)\n  */\n void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId)\n {\n+\tif (finishFrame_)\n+\t\t(this->*finishFrame_)();\n+\n \t*sharedStats_ = stats_;\n \tstatsReady.emit(frame, bufferId);\n }\n@@ -362,6 +400,20 @@ int SwStatsCpu::setupStandardBayerOrder(BayerFormat::Order order)\n int SwStatsCpu::configure(const StreamConfiguration &inputCfg)\n {\n \tstride_ = inputCfg.stride;\n+\tfinishFrame_ = NULL;\n+\n+\tif (inputCfg.pixelFormat == formats::YUV420) {\n+\t\tpatternSize_.height = 2;\n+\t\tpatternSize_.width = 2;\n+\t\t/* Skip every 3th and 4th line, sample every other 2x2 block */\n+\t\tySkipMask_ = 0x02;\n+\t\txShift_ = 0;\n+\t\tswapLines_ = false;\n+\t\tstats0_ = &SwStatsCpu::statsYUV420Line0;\n+\t\tprocessFrame_ = &SwStatsCpu::processYUV420Frame;\n+\t\tfinishFrame_ = &SwStatsCpu::finishYUV420Frame;\n+\t\treturn 0;\n+\t}\n \n \tBayerFormat bayerFormat =\n \t\tBayerFormat::fromPixelFormat(inputCfg.pixelFormat);\n@@ -430,6 +482,43 @@ void SwStatsCpu::setWindow(const Rectangle &window)\n \twindow_.height &= ~(patternSize_.height - 1);\n }\n \n+void SwStatsCpu::processYUV420Frame(MappedFrameBuffer &in)\n+{\n+\tconst uint8_t *linePointers[3];\n+\n+\tlinePointers[0] = in.planes()[0].data();\n+\tlinePointers[1] = in.planes()[1].data();\n+\tlinePointers[2] = in.planes()[2].data();\n+\n+\t/* Adjust linePointers for starting at window_.y */\n+\tlinePointers[0] += window_.y * stride_;\n+\tlinePointers[1] += window_.y * stride_ / 4;\n+\tlinePointers[2] += window_.y * stride_ / 4;\n+\n+\tfor (unsigned int y = 0; y < window_.height; y += 2) {\n+\t\tif (!(y & ySkipMask_))\n+\t\t\t(this->*stats0_)(linePointers);\n+\n+\t\tlinePointers[0] += stride_ * 2;\n+\t\tlinePointers[1] += stride_ / 2;\n+\t\tlinePointers[2] += stride_ / 2;\n+\t}\n+}\n+\n+void SwStatsCpu::finishYUV420Frame()\n+{\n+\t/* sumR_ / G_ / B_ contain Y / U / V sums convert this */\n+\tdouble divider = (uint64_t)window_.width * window_.height * 256 / 16;\n+\tdouble Y = (double)stats_.sumR_ / divider;\n+\t/* U and V 0 - 255 values represent -128 - 127 range */\n+\tdouble U = (double)stats_.sumG_ / divider - 0.5;\n+\tdouble V = (double)stats_.sumB_ / divider - 0.5;\n+\n+\tstats_.sumR_ = (Y + 1.140 * V) * divider;\n+\tstats_.sumG_ = (Y - 0.395 * U - 0.581 * V) * divider;\n+\tstats_.sumB_ = (Y + 2.032 * U) * divider;\n+}\n+\n void SwStatsCpu::processBayerFrame2(MappedFrameBuffer &in)\n {\n \tconst uint8_t *src = in.planes()[0].data();\ndiff --git a/src/libcamera/software_isp/swstats_cpu.h b/src/libcamera/software_isp/swstats_cpu.h\nindex fa47cec9..a043861c 100644\n--- a/src/libcamera/software_isp/swstats_cpu.h\n+++ b/src/libcamera/software_isp/swstats_cpu.h\n@@ -71,6 +71,7 @@ public:\n private:\n \tusing statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[]);\n \tusing processFrameFn = void (SwStatsCpu::*)(MappedFrameBuffer &in);\n+\tusing finishFrameFn = void (SwStatsCpu::*)();\n \n \tint setupStandardBayerOrder(BayerFormat::Order order);\n \t/* Bayer 8 bpp unpacked */\n@@ -82,10 +83,15 @@ private:\n \t/* Bayer 10 bpp packed */\n \tvoid statsBGGR10PLine0(const uint8_t *src[]);\n \tvoid statsGBRG10PLine0(const uint8_t *src[]);\n+\t/* YUV420 3 planes */\n+\tvoid statsYUV420Line0(const uint8_t *src[]);\n \n \tvoid processBayerFrame2(MappedFrameBuffer &in);\n+\tvoid processYUV420Frame(MappedFrameBuffer &in);\n+\tvoid finishYUV420Frame();\n \n \tprocessFrameFn processFrame_;\n+\tfinishFrameFn finishFrame_;\n \n \t/* Variables set by configure(), used every line */\n \tstatsProcessFn stats0_;\n","prefixes":["08/27"]}