From patchwork Sun Nov 3 15:22:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 21803 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 340DDC330D for ; Sun, 3 Nov 2024 15:22:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4DD4A653CA; Sun, 3 Nov 2024 16:22:26 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="amxk7oST"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 177F8653CF for ; Sun, 3 Nov 2024 16:22:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1730647343; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IXNsfpbzqKwKq9ekhT0U9ueoSskyeTqir9T4wT5jxiw=; b=amxk7oSTc1fGQ0wiZF5+juAk4HLjPk6DxU1yk9k+DQE6unS1LTWCjQs7T3rGC2Ct8rZbLY 8nJ0QchwhnlTkeXZVzHopwmlLrwD0P8f8uerXlMfd/ZKQIofZX0OLTb3eNFbnC8WW/NUZ9 2yNOfuOtBUc9/IVWp2LdXXxn14JySqs= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-161-07NtK2A2MqSbyMYNelvKbw-1; Sun, 03 Nov 2024 10:22:21 -0500 X-MC-Unique: 07NtK2A2MqSbyMYNelvKbw-1 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C306B19560B8 for ; Sun, 3 Nov 2024 15:22:20 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.192.77]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4FF151956086; Sun, 3 Nov 2024 15:22:19 +0000 (UTC) From: Hans de Goede To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Maxime Ripard , Hans de Goede Subject: [PATCH 6/8] libcamera: swstats_cpu: Add support for YUV420 Date: Sun, 3 Nov 2024 16:22:03 +0100 Message-ID: <20241103152205.29219-7-hdegoede@redhat.com> In-Reply-To: <20241103152205.29219-1-hdegoede@redhat.com> References: <20241103152205.29219-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com 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" Add support for processing YUV420 data. Signed-off-by: Hans de Goede --- .../internal/software_isp/swstats_cpu.h | 6 ++ src/libcamera/software_isp/swstats_cpu.cpp | 89 +++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h index fa47cec9..a043861c 100644 --- a/include/libcamera/internal/software_isp/swstats_cpu.h +++ b/include/libcamera/internal/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_; diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index 1ff15f5b..e81c96a2 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();