apps: cam: Support PPM output for other RGB formats

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 <pavel@ucw.cz>
Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Pavel Machek <pavel@ucw.cz>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Milan Zamazal
2025-09-01 18:25:15 +02:00
committed by Kieran Bingham
parent 67220496ed
commit baea40a8a5

View File

@@ -10,6 +10,7 @@
#include <errno.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <libcamera/formats.h>
#include <libcamera/pixel_format.h>
@@ -20,9 +21,34 @@ int PPMWriter::write(const char *filename,
const StreamConfiguration &config,
const Span<uint8_t> &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<libcamera::PixelFormat, FormatTransformation> 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<const char *>(data.data());
const bool transform = config.pixelFormat != formats::BGR888;
std::vector<char> 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;