From patchwork Tue Apr 22 21:59:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bryan O'Donoghue X-Patchwork-Id: 23221 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 75CF2C327D for ; Tue, 22 Apr 2025 21:59:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E4F8F68B2D; Tue, 22 Apr 2025 23:59:37 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="FXKRirtz"; dkim-atps=neutral Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2421768ADB for ; Tue, 22 Apr 2025 23:59:31 +0200 (CEST) Received: by mail-wm1-x335.google.com with SMTP id 5b1f17b1804b1-43ede096d73so41972645e9.2 for ; Tue, 22 Apr 2025 14:59:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1745359170; x=1745963970; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=2WyL2xMXY/h3W3raFwPBVRPThikL44NlUcetTPcUj1c=; b=FXKRirtz1oDqwiOACQTdBdoflW3IHlNcnmu31yJ3NpDyctDMN6nDkuvOCtOiKYfzie iffrGk33Np+uHZpNIMQG4aYgO9lQ8ZUqGepKFyGV6T6dG5KOf0C+gVYD6Lm//9ePdBMm 7CZ3ND2t/DCNrFPIXIY1PJMyiCad/YOiBTJ74LbPmhjkaRMyrX5DCnxjsbNcvR8/xCqI MolPCewpKp4Rhbx1avP3PaXLvDW5gjRxiswfLzvLmM7NyO4LQuMqnwXPkI2F1CESSJd/ gK0bNnh0Z3ToMzLH4WObIfBcBJ+WEM2gQlHAVJlH+WMKhgFNji58lN1Q2CBrUeHOTWEs 9kug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745359170; x=1745963970; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2WyL2xMXY/h3W3raFwPBVRPThikL44NlUcetTPcUj1c=; b=xSmGoBSFpEJGDLKEWC55t4ScdVG4ZVPMOvcVPr+cEqZtDA9rApMap8Iy4qoAh6rPki vEpVi+j7zZ4WXquLWvdGBX7uYpSEWhlD8dDEuDD5RqQfrfXAN/F91x+8bFpG4hf3HtEG 9/VYmggzmiDjzlMG3fFqOWs8t+MldxovGGfuhQ8pvhGsvY03JWom5qhyjxdj+Yjrnnw5 /soDydt89j5A6Z2Fp3fBtMpM8LUKHgcVODSj0VW/r4hmbmRCIMpakAt6WsN20nemn0s2 HjAnwafx1wirEuLO2/Srbvb1q105Al5feJLZRdX1dKToqu1CIwbz0NNx3dLqqJHTHLu2 1MGQ== X-Gm-Message-State: AOJu0YzLoBLGDBovKKh2dvJNppQMEu4vQZSvMbfDXFhfupl8qfxoeCRq YKG9HgOmzuvfG4HeBGUuw2IePpvWv3LStPX/zXj4ZqfaRgoz5WgjW9Z9mmn10KYAxzctGc7S+Ot LZrE= X-Gm-Gg: ASbGnctphSIWFsGzwps47H/lJT+thkKrLW7ic9SRdJj2IKWaDMP714nJ4kgzGG5VYKN M9Oad46ug+X4bM1qq2kOkK2UR4cxXwoIPpAgMBGZIfUZYEYgcxPcG3jsqCz3h4Q3P7uN9cUGpNl HcMbCHDENB6JrRw/JLjr1lChbFiRaBavfiG11zELtzTln9DUw6dxgVK7R5py824TayPlef1AWCd zfdClcYpvso5gkg9lg8Y9RLtxg+n7JmvwKKtMQAJpyz5IuH496dxGT+ZsLLlouDkMzrjdrOZmUy J4gdpmR3av04pQst8SohOAc1P5YhQIBwmZM4g7CVRXbwGVKAoQHUw709K+9tldzgBS95qY0y0tJ wUUo0IcwpiwQkimwxWphi X-Google-Smtp-Source: AGHT+IGXu9D/E6Y8htk5I6VD7HQ+l0EEcucqsKaG1t6kZBbUDJj2SggbN6uYn0qilGr2V8knEwVrLA== X-Received: by 2002:a05:600c:3d14:b0:43d:ed:acd5 with SMTP id 5b1f17b1804b1-4406ab97abbmr190953805e9.10.1745359170470; Tue, 22 Apr 2025 14:59:30 -0700 (PDT) Received: from inspiron14p-linux.ht.home (188-141-3-146.dynamic.upc.ie. [188.141.3.146]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-44092d2eccesm2726615e9.20.2025.04.22.14.59.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Apr 2025 14:59:29 -0700 (PDT) From: Bryan O'Donoghue To: libcamera-devel@lists.libcamera.org Cc: hdegoede@redhat.com, mzamazal@redhat.com, bryan.odonoghue@linaro.org, bod.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 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Hans de Goede Add support for processing YUV420 data. Signed-off-by: Hans de Goede Signed-off-by: Bryan O'Donoghue --- src/libcamera/software_isp/swstats_cpu.cpp | 89 ++++++++++++++++++++++ src/libcamera/software_isp/swstats_cpu.h | 6 ++ 2 files changed, 95 insertions(+) diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index af407b4d..3ec9656c 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -13,6 +13,7 @@ #include +#include #include #include "libcamera/internal/bayer_format.h" @@ -288,6 +289,40 @@ void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src[]) SWSTATS_FINISH_LINE_STATS() } +void SwStatsCpu::statsYUV420Line0(const uint8_t *src[]) +{ + uint64_t sumY = 0; + uint64_t sumU = 0; + uint64_t sumV = 0; + uint8_t y, u, v; + + /* Adjust src[] for starting at window_.x */ + src[0] += window_.x; + src[1] += window_.x / 2; + src[2] += window_.x / 2; + + /* x += 4 sample every other 2x2 block */ + for (int x = 0; x < (int)window_.width; x += 4) { + /* + * Take y from the top left corner of the 2x2 block instead + * of averaging 4 y-s. + */ + y = src[0][x]; + u = src[1][x]; + v = src[2][x]; + + sumY += y; + sumU += u; + sumV += v; + + stats_.yHistogram[y * SwIspStats::kYHistogramSize / 256]++; + } + + stats_.sumR_ += sumY; + stats_.sumG_ += sumU; + stats_.sumB_ += sumV; +} + /** * \brief Reset state to start statistics gathering for a new frame * @@ -313,6 +348,9 @@ void SwStatsCpu::startFrame(void) */ void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId) { + if (finishFrame_) + (this->*finishFrame_)(); + *sharedStats_ = stats_; statsReady.emit(frame, bufferId); } @@ -362,6 +400,20 @@ int SwStatsCpu::setupStandardBayerOrder(BayerFormat::Order order) int SwStatsCpu::configure(const StreamConfiguration &inputCfg) { stride_ = inputCfg.stride; + finishFrame_ = NULL; + + if (inputCfg.pixelFormat == formats::YUV420) { + patternSize_.height = 2; + patternSize_.width = 2; + /* Skip every 3th and 4th line, sample every other 2x2 block */ + ySkipMask_ = 0x02; + xShift_ = 0; + swapLines_ = false; + stats0_ = &SwStatsCpu::statsYUV420Line0; + processFrame_ = &SwStatsCpu::processYUV420Frame; + finishFrame_ = &SwStatsCpu::finishYUV420Frame; + return 0; + } BayerFormat bayerFormat = BayerFormat::fromPixelFormat(inputCfg.pixelFormat); @@ -430,6 +482,43 @@ void SwStatsCpu::setWindow(const Rectangle &window) window_.height &= ~(patternSize_.height - 1); } +void SwStatsCpu::processYUV420Frame(MappedFrameBuffer &in) +{ + const uint8_t *linePointers[3]; + + linePointers[0] = in.planes()[0].data(); + linePointers[1] = in.planes()[1].data(); + linePointers[2] = in.planes()[2].data(); + + /* Adjust linePointers for starting at window_.y */ + linePointers[0] += window_.y * stride_; + linePointers[1] += window_.y * stride_ / 4; + linePointers[2] += window_.y * stride_ / 4; + + for (unsigned int y = 0; y < window_.height; y += 2) { + if (!(y & ySkipMask_)) + (this->*stats0_)(linePointers); + + linePointers[0] += stride_ * 2; + linePointers[1] += stride_ / 2; + linePointers[2] += stride_ / 2; + } +} + +void SwStatsCpu::finishYUV420Frame() +{ + /* sumR_ / G_ / B_ contain Y / U / V sums convert this */ + double divider = (uint64_t)window_.width * window_.height * 256 / 16; + double Y = (double)stats_.sumR_ / divider; + /* U and V 0 - 255 values represent -128 - 127 range */ + double U = (double)stats_.sumG_ / divider - 0.5; + double V = (double)stats_.sumB_ / divider - 0.5; + + stats_.sumR_ = (Y + 1.140 * V) * divider; + stats_.sumG_ = (Y - 0.395 * U - 0.581 * V) * divider; + stats_.sumB_ = (Y + 2.032 * U) * divider; +} + void SwStatsCpu::processBayerFrame2(MappedFrameBuffer &in) { const uint8_t *src = in.planes()[0].data(); diff --git a/src/libcamera/software_isp/swstats_cpu.h b/src/libcamera/software_isp/swstats_cpu.h index fa47cec9..a043861c 100644 --- a/src/libcamera/software_isp/swstats_cpu.h +++ b/src/libcamera/software_isp/swstats_cpu.h @@ -71,6 +71,7 @@ public: private: using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[]); using processFrameFn = void (SwStatsCpu::*)(MappedFrameBuffer &in); + using finishFrameFn = void (SwStatsCpu::*)(); int setupStandardBayerOrder(BayerFormat::Order order); /* Bayer 8 bpp unpacked */ @@ -82,10 +83,15 @@ private: /* Bayer 10 bpp packed */ void statsBGGR10PLine0(const uint8_t *src[]); void statsGBRG10PLine0(const uint8_t *src[]); + /* YUV420 3 planes */ + void statsYUV420Line0(const uint8_t *src[]); void processBayerFrame2(MappedFrameBuffer &in); + void processYUV420Frame(MappedFrameBuffer &in); + void finishYUV420Frame(); processFrameFn processFrame_; + finishFrameFn finishFrame_; /* Variables set by configure(), used every line */ statsProcessFn stats0_;