From patchwork Mon Sep 1 16:25:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24281 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 D757DBEFBE for ; Mon, 1 Sep 2025 16:26:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8A31769338; Mon, 1 Sep 2025 18:26:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="ZtfN35zz"; 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 508FB69324 for ; Mon, 1 Sep 2025 18:26:22 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1756743981; 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=NAeZx4gJvFN9WlZgAw3qSSo6h26o4W9S34ygZAnEBBI=; b=ZtfN35zzYyBLecNEZrRk0KZu44N+abLchdONLpQ7x1yqXw8LdvCmrEHrCOi5Rco77zVpK5 /wqmIS7QEN85gWcEddp5uGRtXlW+2nzpTTDnvq83IsYZ/dX+kwzpYPoKmOHHUoQxB0fhmn fAprtkX0C5wq2GP+N7iCUVZ1Xxaccgw= Received: from mx-prod-mc-02.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-541-gjAIB4uPM92fjTSeKj9kYw-1; Mon, 01 Sep 2025 12:26:17 -0400 X-MC-Unique: gjAIB4uPM92fjTSeKj9kYw-1 X-Mimecast-MFC-AGG-ID: gjAIB4uPM92fjTSeKj9kYw_1756743976 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B0BED195608D; Mon, 1 Sep 2025 16:26:15 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.12]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 5EF3C1955EA4; Mon, 1 Sep 2025 16:26:13 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , "Bryan O'Donoghue" , Kieran Bingham , Pavel Machek , Laurent Pinchart Subject: [PATCH v3 1/1] apps: cam: Support PPM output for other RGB formats Date: Mon, 1 Sep 2025 18:25:15 +0200 Message-ID: <20250901162606.44139-2-mzamazal@redhat.com> In-Reply-To: <20250901162606.44139-1-mzamazal@redhat.com> References: <20250901162606.44139-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: lUSoHAESnCulVtppgxHcT1iOTSN2-eWMtriQEMtE3H8_1756743976 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" GPU ISP can produce only 32-bit output. Let's add support to the PPM writer for all the common RGB image formats so that we can store GPU ISP output as PPM files. Contingent alpha values are ignored as there is no support for the alpha channel in PPM. There is no obvious performance penalty in my environment compared to output in the raw format. Signed-off-by: Pavel Machek Signed-off-by: Milan Zamazal Reviewed-by: Pavel Machek Reviewed-by: Paul Elder --- src/apps/common/ppm_writer.cpp | 48 +++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/apps/common/ppm_writer.cpp b/src/apps/common/ppm_writer.cpp index 368de8bf6..6f0bbbe9e 100644 --- a/src/apps/common/ppm_writer.cpp +++ b/src/apps/common/ppm_writer.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -20,9 +21,34 @@ int PPMWriter::write(const char *filename, const StreamConfiguration &config, const Span &data) { - if (config.pixelFormat != formats::BGR888) { - std::cerr << "Only BGR888 output pixel format is supported (" - << config.pixelFormat << " requested)" << std::endl; + struct FormatTransformation { + unsigned int rPos; + unsigned int gPos; + unsigned int bPos; + unsigned int bytesPerPixel; + }; + + static const std::map transforms = { + { libcamera::formats::R8, { 0, 0, 0, 1 } }, + { libcamera::formats::RGB888, { 2, 1, 0, 3 } }, + { libcamera::formats::BGR888, { 0, 1, 2, 3 } }, + { libcamera::formats::ARGB8888, { 2, 1, 0, 4 } }, + { libcamera::formats::XRGB8888, { 2, 1, 0, 4 } }, + { libcamera::formats::ABGR8888, { 0, 1, 2, 4 } }, + { libcamera::formats::XBGR8888, { 0, 1, 2, 4 } }, + { libcamera::formats::RGBA8888, { 3, 2, 1, 4 } }, + { libcamera::formats::RGBX8888, { 3, 2, 1, 4 } }, + { libcamera::formats::BGRA8888, { 1, 2, 3, 4 } }, + { libcamera::formats::BGRX8888, { 1, 2, 3, 4 } }, + }; + + FormatTransformation transformation; + if (auto search = transforms.find(config.pixelFormat); search != transforms.end()) { + transformation = search->second; + } else { + std::cerr + << "Only RGB output pixel formats are supported (" + << config.pixelFormat << " requested)" << std::endl; return -EINVAL; } @@ -42,8 +68,22 @@ int PPMWriter::write(const char *filename, const unsigned int rowLength = config.size.width * 3; const char *row = reinterpret_cast(data.data()); + const bool transform = config.pixelFormat != formats::BGR888; + std::vector transformedRow(transform ? rowLength : 0); + for (unsigned int y = 0; y < config.size.height; y++, row += config.stride) { - output.write(row, rowLength); + if (transform) { + for (unsigned int x = 0; x < config.size.width; x++) { + transformedRow[x * 3] = + row[x * transformation.bytesPerPixel + transformation.rPos]; + transformedRow[x * 3 + 1] = + row[x * transformation.bytesPerPixel + transformation.gPos]; + transformedRow[x * 3 + 2] = + row[x * transformation.bytesPerPixel + transformation.bPos]; + } + } + + output.write(transform ? transformedRow.data() : row, rowLength); if (!output) { std::cerr << "Failed to write image data at row " << y << std::endl; return -EIO;