From patchwork Fri Oct 23 10:58:34 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jai Luthra X-Patchwork-Id: 28596 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 D8918C324C for ; Fri, 23 Oct 2026 11:01:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9224D68FD8; Fri, 23 Oct 2026 13:01:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XS31QMQe"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4756368FCF for ; Fri, 23 Oct 2026 13:01:02 +0200 (CEST) Received: from mail.ideasonboard.com (unknown [IPv6:2401:4900:1c30:59f6:be2b:2877:6bc4:392]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 08BDC4F05; Fri, 23 Oct 2026 12:58:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1792753133; bh=hV1xM93sZeH73N+ZqTsYnz4VtRes6iTO5GcbpDGX3/Y=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=XS31QMQekdWQXXxx4CGzRB/1ru/Bu22tTJmzMh6xWbTMtP5l0zGdHVmf6GY31lSIH ea+ET+v2EzIjmN8Biu1H7hlyCuOTmvgl6JhomrE5P/Uhq+WoisTmI5XcOVj2xFcc6b De8bZyW/gYtlHHEhyEUwbXnQYCnARXyLrYjdSnko= From: Jai Luthra Date: Fri, 23 Oct 2026 16:28:34 +0530 Subject: [PATCH WIP RFC 26/26] apps: dng_writer: Split cfa pattern handling MIME-Version: 1.0 Message-Id: <20261023-b4-raw-model-v1-26-eadb9948901b@ideasonboard.com> References: <20261023-b4-raw-model-v1-0-eadb9948901b@ideasonboard.com> In-Reply-To: <20261023-b4-raw-model-v1-0-eadb9948901b@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Laurent Pinchart , Kieran Bingham , Sakari Ailus , Naushir Patuck , Jai Luthra X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=10571; i=jai.luthra@ideasonboard.com; h=from:subject:message-id; bh=hV1xM93sZeH73N+ZqTsYnz4VtRes6iTO5GcbpDGX3/Y=; b=owEBbQKS/ZANAwAKAUPekfkkmnFFAcsmYgBq2z3brmOP52V5syHMzLLABxQUIpXFA0dKqyhNI dVqpDQiUM6JAjMEAAEKAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCats92wAKCRBD3pH5JJpx RUWUEADJ5quJEtSmgyQPNyN9H66WzrukUdx+1l1zdllCdheLkckG16A1NTi1aU0nWjfs2Klih/E d1lbg4ZYfd1NOSbaBIDiVKDDFVr5A81R0admhCGTL3JOCedAc4DHBkSNJED+qQnmG+Gmkb5MoBI a1Ahm3Hpb/URn7ObC6XAkGdqcWu69vlAfxT6dFbSk0Ukmal4drfHotFcxs/JKN7ZXTrPf8F2VO8 hty36Kdd8t7vbujLMGJZn+CN7E8L9KihSe2LoEpqFDGNjwa52GVvK4rEeeslCuAJkoJeYFD3App Z8v0s7aP8vhBaRDs5mHHlM5U4hkktrkYnK5oTBOI2Lz+2TJDbWcEzJJr4NihYE5O2f5KaIRk9mr TFbANiN9MVHsPsHlx6P2sbeU5eeBkNDOoTw56JHTL4tTqMWVLtuidVgv2lbBnVLxW8H3sP65UUW aFonjHrswb6b2+Mb4x+XWyR2jQmmHYD05xkEbfR9nk8mXZ521FynKTgmr0OYW/59PP0eYxbix0A ePK9fBd8RpfLjyoMYADBhwEy8NUtMe5oeF3WIKK8k0hmNDAg+RsYU4TUnKfQGmJOFN+Aa1U3vEx CyrYTlhng5cwbqahlYmwM0mR12M/6+4QZtZ0XjxjaqbK7nWEn809BS8+MZPrSL49BFvckvf+eMC c8R11nWX6leVvGQ== X-Developer-Key: i=jai.luthra@ideasonboard.com; a=openpgp; fpr=4DE0D818E5D575E8D45AAFC543DE91F9249A7145 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" Simplify the formatInfo table by switching to the new generic pixel formats. For populating the color filter array pattern fields in the TIFF metadata, read it from the StreamConfiguration. Signed-off-by: Jai Luthra --- src/apps/common/dng_writer.cpp | 189 ++++++++++------------------------------- 1 file changed, 43 insertions(+), 146 deletions(-) diff --git a/src/apps/common/dng_writer.cpp b/src/apps/common/dng_writer.cpp index 0d9b725b939f..ab2b244b1cdf 100644 --- a/src/apps/common/dng_writer.cpp +++ b/src/apps/common/dng_writer.cpp @@ -8,13 +8,16 @@ #include "dng_writer.h" #include +#include #include #include #include +#include #include #include +#include #include #include #include @@ -27,9 +30,10 @@ enum CFAPatternColour : uint8_t { CFAPatternBlue = 2, }; +typedef std::array CFAPattern; + struct FormatInfo { uint8_t bitsPerSample; - CFAPatternColour pattern[4]; void (*packScanline)(void *output, const void *input, unsigned int width); void (*thumbScanline)(const FormatInfo &info, void *output, @@ -347,176 +351,63 @@ void thumbScanlineIPU3([[maybe_unused]] const FormatInfo &info, void *output, } const std::map formatInfo = { - { formats::SBGGR8, { + { formats::RAW8, { .bitsPerSample = 8, - .pattern = { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed }, .packScanline = packScanlineRaw8, .thumbScanline = thumbScanlineRaw_CSI2P, } }, - { formats::SGBRG8, { - .bitsPerSample = 8, - .pattern = { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen }, - .packScanline = packScanlineRaw8, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SGRBG8, { - .bitsPerSample = 8, - .pattern = { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen }, - .packScanline = packScanlineRaw8, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SRGGB8, { - .bitsPerSample = 8, - .pattern = { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue }, - .packScanline = packScanlineRaw8, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SBGGR10, { + { formats::RAW10, { .bitsPerSample = 10, - .pattern = { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed }, .packScanline = packScanlineRaw10, .thumbScanline = thumbScanlineRaw, } }, - { formats::SGBRG10, { - .bitsPerSample = 10, - .pattern = { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen }, - .packScanline = packScanlineRaw10, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SGRBG10, { - .bitsPerSample = 10, - .pattern = { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen }, - .packScanline = packScanlineRaw10, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SRGGB10, { - .bitsPerSample = 10, - .pattern = { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue }, - .packScanline = packScanlineRaw10, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SBGGR12, { + { formats::RAW12, { .bitsPerSample = 12, - .pattern = { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed }, .packScanline = packScanlineRaw12, .thumbScanline = thumbScanlineRaw, } }, - { formats::SGBRG12, { - .bitsPerSample = 12, - .pattern = { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen }, - .packScanline = packScanlineRaw12, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SGRBG12, { - .bitsPerSample = 12, - .pattern = { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen }, - .packScanline = packScanlineRaw12, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SRGGB12, { - .bitsPerSample = 12, - .pattern = { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue }, - .packScanline = packScanlineRaw12, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SBGGR16, { + { formats::RAW16, { .bitsPerSample = 16, - .pattern = { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed }, .packScanline = packScanlineRaw16, .thumbScanline = thumbScanlineRaw, } }, - { formats::SGBRG16, { - .bitsPerSample = 16, - .pattern = { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen }, - .packScanline = packScanlineRaw16, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SGRBG16, { - .bitsPerSample = 16, - .pattern = { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen }, - .packScanline = packScanlineRaw16, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SRGGB16, { - .bitsPerSample = 16, - .pattern = { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue }, - .packScanline = packScanlineRaw16, - .thumbScanline = thumbScanlineRaw, - } }, - { formats::SBGGR10_CSI2P, { + { formats::RAW10_CSI2P, { .bitsPerSample = 10, - .pattern = { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed }, .packScanline = packScanlineRaw10_CSI2P, .thumbScanline = thumbScanlineRaw_CSI2P, } }, - { formats::SGBRG10_CSI2P, { - .bitsPerSample = 10, - .pattern = { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen }, - .packScanline = packScanlineRaw10_CSI2P, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SGRBG10_CSI2P, { - .bitsPerSample = 10, - .pattern = { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen }, - .packScanline = packScanlineRaw10_CSI2P, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SRGGB10_CSI2P, { - .bitsPerSample = 10, - .pattern = { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue }, - .packScanline = packScanlineRaw10_CSI2P, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SBGGR12_CSI2P, { + { formats::RAW12_CSI2P, { .bitsPerSample = 12, - .pattern = { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed }, .packScanline = packScanlineRaw12_CSI2P, .thumbScanline = thumbScanlineRaw_CSI2P, } }, - { formats::SGBRG12_CSI2P, { - .bitsPerSample = 12, - .pattern = { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen }, - .packScanline = packScanlineRaw12_CSI2P, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SGRBG12_CSI2P, { - .bitsPerSample = 12, - .pattern = { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen }, - .packScanline = packScanlineRaw12_CSI2P, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SRGGB12_CSI2P, { - .bitsPerSample = 12, - .pattern = { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue }, - .packScanline = packScanlineRaw12_CSI2P, - .thumbScanline = thumbScanlineRaw_CSI2P, - } }, - { formats::SBGGR10_IPU3, { + { formats::RAW10_IPU3, { .bitsPerSample = 16, - .pattern = { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed }, - .packScanline = packScanlineIPU3, - .thumbScanline = thumbScanlineIPU3, - } }, - { formats::SGBRG10_IPU3, { - .bitsPerSample = 16, - .pattern = { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen }, - .packScanline = packScanlineIPU3, - .thumbScanline = thumbScanlineIPU3, - } }, - { formats::SGRBG10_IPU3, { - .bitsPerSample = 16, - .pattern = { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen }, - .packScanline = packScanlineIPU3, - .thumbScanline = thumbScanlineIPU3, - } }, - { formats::SRGGB10_IPU3, { - .bitsPerSample = 16, - .pattern = { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue }, .packScanline = packScanlineIPU3, .thumbScanline = thumbScanlineIPU3, } }, }; +static constexpr std::pair patterns[] = { + { ColorFilterArray::BGGR, { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed } }, + { ColorFilterArray::GBRG, { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen } }, + { ColorFilterArray::GRBG, { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen } }, + { ColorFilterArray::RGGB, { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue } }, +}; + +static std::optional findCfaPattern(const std::optional cfa) +{ + if (!cfa) + return std::nullopt; + + for (const auto &[key, pattern] : patterns) { + if (key.order == cfa.value().order) + return pattern; + } + + return std::nullopt; +} + } /* namespace */ int DNGWriter::write(const char *filename, const Camera *camera, @@ -534,6 +425,12 @@ int DNGWriter::write(const char *filename, const Camera *camera, } const FormatInfo *info = &it->second; + const auto pattern = findCfaPattern(config.bayerOrder); + if (!pattern) { + std::cerr << "Unknown color filter array pattern" << std::endl; + return -EINVAL; + } + TIFF *tif = TIFFOpen(filename, "w"); if (!tif) { std::cerr << "Failed to open tiff file" << std::endl; @@ -696,9 +593,9 @@ int DNGWriter::write(const char *filename, const Camera *camera, TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, cfaRepeatPatternDim); if (TIFFLIB_VERSION < 20201219) - TIFFSetField(tif, TIFFTAG_CFAPATTERN, info->pattern); + TIFFSetField(tif, TIFFTAG_CFAPATTERN, pattern.value().data()); else - TIFFSetField(tif, TIFFTAG_CFAPATTERN, 4, info->pattern); + TIFFSetField(tif, TIFFTAG_CFAPATTERN, 4, pattern.value().data()); TIFFSetField(tif, TIFFTAG_CFAPLANECOLOR, 3, cfaPlaneColor); TIFFSetField(tif, TIFFTAG_CFALAYOUT, 1); @@ -715,14 +612,14 @@ int DNGWriter::write(const char *filename, const Camera *camera, * Map it to the TIFF tag that is specified in CFA pattern * order. */ - unsigned int green = (info->pattern[0] == CFAPatternRed || - info->pattern[1] == CFAPatternRed) + unsigned int green = (pattern.value()[0] == CFAPatternRed || + pattern.value()[1] == CFAPatternRed) ? 0 : 1; for (unsigned int i = 0; i < 4; ++i) { unsigned int level; - switch (info->pattern[i]) { + switch (pattern.value()[i]) { case CFAPatternRed: level = levels[0]; break;