[PATCH] cam: Convert RGB variations to BGR

Laurent Pinchart laurent.pinchart at ideasonboard.com
Mon Apr 21 16:16:06 CEST 2025


Hi Pavel,

On Sat, Apr 19, 2025 at 12:05:34PM +0200, Pavel Machek wrote:
> Hi!
> 
> > Thank you for the patch.
> > 
> > On Sun, Apr 13, 2025 at 10:21:33AM +0200, Pavel Machek wrote:
> > > swIsp with libcamera produces ARGB data by default, which needs
> > > conversion during write. Implement it and similar conversions.
> > >     
> > > Signed-off-by: Pavel Machek <pavel at ucw.cz>
> 
> > > +	case libcamera::formats::BGRA8888:
> > > +	case libcamera::formats::BGRX8888:
> > > +		r_pos = 1;
> > > +		g_pos = 2;
> > > +		b_pos = 3;
> > > +		bpp = 4;
> > > +		break;
> > > +	default:
> > > +		std::cerr << "Only RGB output pixel formats are supported ("
> > >  			  << config.pixelFormat << " requested)" << std::endl;
> > >  		return -EINVAL;
> > >  	}
> > > @@ -41,14 +89,35 @@ int PPMWriter::write(const char *filename,
> > >  	}
> > >  
> > >  	const unsigned int rowLength = config.size.width * 3;
> > > -	const char *row = reinterpret_cast<const char *>(data.data());
> > > -	for (unsigned int y = 0; y < config.size.height; y++, row += config.stride) {
> > > -		output.write(row, rowLength);
> > > +	// Output without any conversion will be slightly faster
> > 
> > We use C-style coments.
> 
> Can you adjust that while applying?

If that's the only change required, yes.

> > > +	if (config.pixelFormat == formats::BGR888) {
> > > +		const char *row = reinterpret_cast<const char *>(data.data());
> > > +		for (unsigned int y = 0; y < config.size.height; y++, row += config.stride) {
> > > +			output.write(row, rowLength);
> > > +			if (!output) {
> > > +				std::cerr << "Failed to write image data at row " << y << std::endl;
> > > +				return -EIO;
> > > +			}
> > > +		}
> > > +		return 0;
> > > +	}
> > > +
> > > +	const unsigned int inputRowBytes = config.stride; // should be >= width * 4
> > > +	// Create a temporary buffer to hold one output row.
> > > +	std::vector<char> rowBuffer(rowLength);
> > > +	const uint8_t *row = reinterpret_cast<const uint8_t *>(data.data());
> > > +	for (unsigned int y = 0; y < config.size.height; y++, row += inputRowBytes) {
> > > +		for (unsigned int x = 0; x < config.size.width; x++) {
> > > +			const uint8_t *pixel = row + x * bpp;
> > > +			rowBuffer[x * 3 + 0] = static_cast<char>(pixel[r_pos]);
> > > +			rowBuffer[x * 3 + 1] = static_cast<char>(pixel[g_pos]);
> > > +			rowBuffer[x * 3 + 2] = static_cast<char>(pixel[b_pos]);
> > > +		}
> > 
> > I'm curious, what's the performance impact of the conversion ?
> 
> I hacked Librem 5 a lot to get libcamera working, and previous config
> was not working at all, so ... I can't easily benchmark that.
> 
> So, this one is not free as it does one more copy of image
> data. Compared to swIsp, it is going to be lost in the noise.
> 
> There's easy optimalization in the original case not to do writes per
> row if width == stride. There are other options, but they will
> complicate the code.

I wonder if it would make sense for the soft ISP to support other RGB
formats. CC'ing Milan and Hans to get their opinion.

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list