[{"id":34183,"web_url":"https://patchwork.libcamera.org/comment/34183/","msgid":"<174697641091.4078945.18095444268403185687@ping.linuxembedded.co.uk>","date":"2025-05-11T15:13:30","subject":"Re: [PATCH v2 6/8] libcamera: swstats_cpu: Add support for YUV420","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Hans de Goede (2025-05-10 15:12:18)\n> Add support for processing YUV420 data.\n> \n> Signed-off-by: Hans de Goede <hdegoede@redhat.com>\n> ---\n>  .../internal/software_isp/swstats_cpu.h       |  6 ++\n>  src/libcamera/software_isp/swstats_cpu.cpp    | 89 +++++++++++++++++++\n>  2 files changed, 95 insertions(+)\n> \n> diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h\n> index fa47cec9..a043861c 100644\n> --- a/include/libcamera/internal/software_isp/swstats_cpu.h\n> +++ b/include/libcamera/internal/software_isp/swstats_cpu.h\n> @@ -71,6 +71,7 @@ public:\n>  private:\n>         using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[]);\n>         using processFrameFn = void (SwStatsCpu::*)(MappedFrameBuffer &in);\n> +       using finishFrameFn = void (SwStatsCpu::*)();\n>  \n>         int setupStandardBayerOrder(BayerFormat::Order order);\n>         /* Bayer 8 bpp unpacked */\n> @@ -82,10 +83,15 @@ private:\n>         /* Bayer 10 bpp packed */\n>         void statsBGGR10PLine0(const uint8_t *src[]);\n>         void statsGBRG10PLine0(const uint8_t *src[]);\n> +       /* YUV420 3 planes */\n> +       void statsYUV420Line0(const uint8_t *src[]);\n>  \n>         void processBayerFrame2(MappedFrameBuffer &in);\n> +       void processYUV420Frame(MappedFrameBuffer &in);\n> +       void finishYUV420Frame();\n>  \n>         processFrameFn processFrame_;\n> +       finishFrameFn finishFrame_;\n>  \n>         /* Variables set by configure(), used every line */\n>         statsProcessFn stats0_;\n> diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\n> index 1ff15f5b..e81c96a2 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>         SWSTATS_FINISH_LINE_STATS()\n>  }\n>  \n> +void SwStatsCpu::statsYUV420Line0(const uint8_t *src[])\n> +{\n> +       uint64_t sumY = 0;\n> +       uint64_t sumU = 0;\n> +       uint64_t sumV = 0;\n> +       uint8_t y, u, v;\n> +\n> +       /* Adjust src[] for starting at window_.x */\n> +       src[0] += window_.x;\n> +       src[1] += window_.x / 2;\n> +       src[2] += window_.x / 2;\n> +\n> +       /* x += 4 sample every other 2x2 block */\n> +       for (int x = 0; x < (int)window_.width; x += 4) {\n> +               /*\n> +                * Take y from the top left corner of the 2x2 block instead\n> +                * of averaging 4 y-s.\n> +                */\n> +               y = src[0][x];\n> +               u = src[1][x];\n> +               v = src[2][x];\n> +\n> +               sumY += y;\n> +               sumU += u;\n> +               sumV += v;\n> +\n> +               stats_.yHistogram[y * SwIspStats::kYHistogramSize / 256]++;\n> +       }\n> +\n> +       stats_.sumR_ += sumY;\n> +       stats_.sumG_ += sumU;\n> +       stats_.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> +       if (finishFrame_)\n> +               (this->*finishFrame_)();\n> +\n>         *sharedStats_ = stats_;\n>         statsReady.emit(frame, bufferId);\n>  }\n> @@ -362,6 +400,20 @@ int SwStatsCpu::setupStandardBayerOrder(BayerFormat::Order order)\n>  int SwStatsCpu::configure(const StreamConfiguration &inputCfg)\n>  {\n>         stride_ = inputCfg.stride;\n> +       finishFrame_ = NULL;\n> +\n> +       if (inputCfg.pixelFormat == formats::YUV420) {\n> +               patternSize_.height = 2;\n> +               patternSize_.width = 2;\n> +               /* Skip every 3th and 4th line, sample every other 2x2 block */\n> +               ySkipMask_ = 0x02;\n> +               xShift_ = 0;\n> +               swapLines_ = false;\n> +               stats0_ = &SwStatsCpu::statsYUV420Line0;\n> +               processFrame_ = &SwStatsCpu::processYUV420Frame;\n> +               finishFrame_ = &SwStatsCpu::finishYUV420Frame;\n> +               return 0;\n> +       }\n>  \n>         BayerFormat bayerFormat =\n>                 BayerFormat::fromPixelFormat(inputCfg.pixelFormat);\n> @@ -430,6 +482,43 @@ void SwStatsCpu::setWindow(const Rectangle &window)\n>         window_.height &= ~(patternSize_.height - 1);\n>  }\n>  \n> +void SwStatsCpu::processYUV420Frame(MappedFrameBuffer &in)\n> +{\n> +       const uint8_t *linePointers[3];\n> +\n> +       linePointers[0] = in.planes()[0].data();\n> +       linePointers[1] = in.planes()[1].data();\n> +       linePointers[2] = in.planes()[2].data();\n> +\n> +       /* Adjust linePointers for starting at window_.y */\n> +       linePointers[0] += window_.y * stride_;\n> +       linePointers[1] += window_.y * stride_ / 4;\n> +       linePointers[2] += window_.y * stride_ / 4;\n> +\n> +       for (unsigned int y = 0; y < window_.height; y += 2) {\n> +               if (!(y & ySkipMask_))\n> +                       (this->*stats0_)(linePointers);\n> +\n> +               linePointers[0] += stride_ * 2;\n> +               linePointers[1] += stride_ / 2;\n> +               linePointers[2] += stride_ / 2;\n> +       }\n> +}\n> +\n> +void SwStatsCpu::finishYUV420Frame()\n> +{\n> +       /* sumR_ / G_ / B_ contain Y / U / V sums convert this */\n> +       double divider = (uint64_t)window_.width * window_.height * 256 / 16;\n> +       double Y = (double)stats_.sumR_ / divider;\n> +       /* U and V 0 - 255 values represent -128 - 127 range */\n> +       double U = (double)stats_.sumG_ / divider - 0.5;\n> +       double V = (double)stats_.sumB_ / divider - 0.5;\n> +\n> +       stats_.sumR_ = (Y + 1.140 * V) * divider;\n> +       stats_.sumG_ = (Y - 0.395 * U - 0.581 * V) * divider;\n> +       stats_.sumB_ = (Y + 2.032 * U) * divider;\n\nCould this be better expressed with the Matrix/Vector classes ? Is the\nconversion a specific colour space conversion that could be named? Or\nis there a way we can abstract these (common in libcamera) color\nconversions in named/explicit ways?\n\n\n\n> +}\n> +\n>  void SwStatsCpu::processBayerFrame2(MappedFrameBuffer &in)\n>  {\n>         const uint8_t *src = in.planes()[0].data();\n> -- \n> 2.49.0\n>","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 A7946C3226\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 11 May 2025 15:13:36 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E319668B65;\n\tSun, 11 May 2025 17:13:35 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 068B368B60\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 11 May 2025 17:13:34 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A9EBE605;\n\tSun, 11 May 2025 17:13:19 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"YEDsc8Wa\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1746976399;\n\tbh=w0T2b20zSYXDev+liql7xhhp8kVe9Xv/BiKmjP66yAA=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=YEDsc8Way38Hx/Plykl3m+xYuB5g0Avz8QU4dDEH69t+JdK2qhuX1cLRf5J5XPh4p\n\t8gtbOQUzvyY9I0WPVSNqfKIXYwDntZEYxmkUSlDWHZpzFZaWlTMGmD86gfFxgF1Yn+\n\t/iFR9SmC1ea0KRV5AFZfRd9rNklIx/Ans99MZa6w=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20250510141220.54872-7-hdegoede@redhat.com>","References":"<20250510141220.54872-1-hdegoede@redhat.com>\n\t<20250510141220.54872-7-hdegoede@redhat.com>","Subject":"Re: [PATCH v2 6/8] libcamera: swstats_cpu: Add support for YUV420","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Milan Zamazal <mzamazal@redhat.com>, Hans de Goede <hdegoede@redhat.com>","To":"Hans de Goede <hdegoede@redhat.com>, libcamera-devel@lists.libcamera.org","Date":"Sun, 11 May 2025 16:13:30 +0100","Message-ID":"<174697641091.4078945.18095444268403185687@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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>"}},{"id":34225,"web_url":"https://patchwork.libcamera.org/comment/34225/","msgid":"<85v7q4h94t.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2025-05-13T14:34:42","subject":"Re: [PATCH v2 6/8] libcamera: swstats_cpu: Add support for YUV420","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Hi Hans,\n\nHans de Goede <hdegoede@redhat.com> writes:\n\n> Add support for processing YUV420 data.\n>\n> Signed-off-by: Hans de Goede <hdegoede@redhat.com>\n> ---\n>  .../internal/software_isp/swstats_cpu.h       |  6 ++\n>  src/libcamera/software_isp/swstats_cpu.cpp    | 89 +++++++++++++++++++\n>  2 files changed, 95 insertions(+)\n>\n> diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h\n> index fa47cec9..a043861c 100644\n> --- a/include/libcamera/internal/software_isp/swstats_cpu.h\n> +++ b/include/libcamera/internal/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> diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\n> index 1ff15f5b..e81c96a2 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\nShould the `src' values be really modified?  Why not to use *src0\netc. variables like in the other methods?\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\nOh, storing YUV to \"RGB\" is really confusing.  Would it be possible to\nuse aliases or separate variables?\n\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\nnullptr\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\nWhy is the Y step four times the U/V step here and below while only\ntwice in adjusting window_.x above?\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\nThe \"256 / 16\" part deserves a comment.  I suppose 256 is to convert\nfrom 0..255 to 0.0..0.996 and 16 to approximately compensate for getting\nonly 1 pixel from 4x4 but the poor reader shouldn't be forced to deduce\nthis.\n\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\nI think static_cast should be used.\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\nSource of the numbers?\n\n> +}\n> +\n>  void SwStatsCpu::processBayerFrame2(MappedFrameBuffer &in)\n>  {\n>  \tconst uint8_t *src = in.planes()[0].data();","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 1D068C3220\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 13 May 2025 14:34:52 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E9EEA68B61;\n\tTue, 13 May 2025 16:34:50 +0200 (CEST)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F2E4968B40\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 13 May 2025 16:34:48 +0200 (CEST)","from mail-wr1-f69.google.com (mail-wr1-f69.google.com\n\t[209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-418-f6qk7SeFObqNqVsWZFpX2Q-1; Tue, 13 May 2025 10:34:45 -0400","by mail-wr1-f69.google.com with SMTP id\n\tffacd0b85a97d-3a0bd786a53so2420003f8f.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 13 May 2025 07:34:45 -0700 (PDT)","from mzamazal-thinkpadp1gen7.tpbc.csb ([85.93.96.130])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-3a1f5a2d37fsm16723436f8f.68.2025.05.13.07.34.42\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 13 May 2025 07:34:43 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"IHHjnLot\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1747146887;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=vR8KN0iigvLfbooOwCEfPU56dXZKLZMV5NDjvtT2osQ=;\n\tb=IHHjnLotyjLTo3vyAgVvuBQEDHj7kb+suYFKt8ysIrk7fJq6JbpmnjDFDxrDmGTfg++5c8\n\tfi5OiCpm/Xtup0whzjA5TOssfuLDKjHgwvtM+++++FdZR6s9ovNBxI04KWCLObVp0JeCOv\n\tTkWa79rOhlrTeqUzys+zKuNWvZc5e7k=","X-MC-Unique":"f6qk7SeFObqNqVsWZFpX2Q-1","X-Mimecast-MFC-AGG-ID":"f6qk7SeFObqNqVsWZFpX2Q_1747146885","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1747146884; x=1747751684;\n\th=mime-version:user-agent:message-id:date:references:in-reply-to\n\t:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=vR8KN0iigvLfbooOwCEfPU56dXZKLZMV5NDjvtT2osQ=;\n\tb=kTa0sUDJnYZF5HnYRAJp0i/qr0d/GRtzlsexqKPhFtNtRF8uojSnvSF4Flipa71zIk\n\tHCYOdA0JkhmpHh6tXCIwHAfliUD/vUyEq51LzBa1OD2NEkNngEs4ZdZiSROkOo+/tL7r\n\tdePS/3zmr1Qx5xA8Zsj/P0/x7Umggr335EN64hOXOB/YFnBIMfvhRNd/otJs9j5lwD4h\n\t9U5xFmy4lQwGamaBWzaHWoa/IxKcusWx8uG+rkDDJqdKfnb2NwWRjYpStyNcQd7Ay8et\n\t6ON/SoCYmHi2QnBbjSGRcL2twAxHSY1gjsiUdA2g652rjZJo4xEI8TRBsv+XDK3R2iKy\n\tbzCw==","X-Gm-Message-State":"AOJu0YzZOU9iWO8lWMnyxQYMo5JL8lNYkHFHQKjVR5ViELmL7s4G0dQB\n\txEADaufbj3JFxQcvv6E860epreHcftY8Y6HzdV6ENR09XqsgQnV5FDiY5sRZAC1FX7Ma/bpQzm6\n\tiJJYRvCjcaswc2VY1x379asg/FXzrdXJmyEpUp0p160AzayEudgcCBrRuSD4hVI98sIyOLrNVtv\n\t3qWldwn5RwnMiHFakq5v0PBNDujOhswHHj/oPN8rNm/TTcTr9kXObhNqY=","X-Gm-Gg":"ASbGncs+sLtnfqKtGiDsVJmI53szT+KlR4+LPj2/SoEYvaYAdyv+6eBBCXl/l7PgkeA\n\tbeadRwrHlM9gk4BvJScuGl20zUdLnZ5jglxaAvFRsqv9fMrlS1psH6U+Dw8k0Aq7G3Jv1yy8Xwk\n\tEmocj8ojPUcFlCIOkLzDp1GOoxvwhsqlnnMZyVkabU6xqtKlBoqareiY6lDo+aMmaJNBURttNqQ\n\tHAo/GjlvwaJmIs5T4UCjBc1F9+L1oFuZXl1V/G7DGRuejpC9srmLIW5FHdC3VQELUUPGEx8m8eF\n\tsqcjrm7z66DENnIHJHfMGKfuUufz5yDOM7w8","X-Received":["by 2002:a5d:5f47:0:b0:3a3:44a6:d77e with SMTP id\n\tffacd0b85a97d-3a344a6d857mr2277483f8f.3.1747146884219; \n\tTue, 13 May 2025 07:34:44 -0700 (PDT)","by 2002:a5d:5f47:0:b0:3a3:44a6:d77e with SMTP id\n\tffacd0b85a97d-3a344a6d857mr2277459f8f.3.1747146883700; \n\tTue, 13 May 2025 07:34:43 -0700 (PDT)"],"X-Google-Smtp-Source":"AGHT+IEBqdC0z0TEnQaKP+i4QarE5doAVHKK3v9z3tjTcF3NGsnwET7quZqnBySQB8UVaIyeFMBbUg==","From":"Milan Zamazal <mzamazal@redhat.com>","To":"Hans de Goede <hdegoede@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v2 6/8] libcamera: swstats_cpu: Add support for YUV420","In-Reply-To":"<20250510141220.54872-7-hdegoede@redhat.com> (Hans de Goede's\n\tmessage of \"Sat, 10 May 2025 16:12:18 +0200\")","References":"<20250510141220.54872-1-hdegoede@redhat.com>\n\t<20250510141220.54872-7-hdegoede@redhat.com>","Date":"Tue, 13 May 2025 16:34:42 +0200","Message-ID":"<85v7q4h94t.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"D90nFue054WdzkV5OgzZDUKfoRrhJ4Ph6_a_cGtSy3A_1747146885","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain","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>"}}]