[libcamera-devel] [PATCH v2] qcam: dng_writer: Add support for IPU3 Bayer formats

Niklas Söderlund niklas.soderlund at ragnatech.se
Thu Jun 11 03:45:36 CEST 2020


Add support for the Bayer formats produced on the IPU3. The format uses
a memory layout that is hard to repack and keep the 10-bit sample size,
therefore scale the samples to 16-bit when creating the scanlines.

Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
---
 src/qcam/dng_writer.cpp | 121 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)

diff --git a/src/qcam/dng_writer.cpp b/src/qcam/dng_writer.cpp
index cbd8bed3e6d02269..330b169af25b7ac7 100644
--- a/src/qcam/dng_writer.cpp
+++ b/src/qcam/dng_writer.cpp
@@ -82,6 +82,103 @@ void thumbScanlineSBGGRxxP(const FormatInfo &info, void *output,
 	}
 }
 
+void packScanlineIPU3(void *output, const void *input, unsigned int width)
+{
+	const uint8_t *in = static_cast<const uint8_t *>(input);
+	uint16_t *out = static_cast<uint16_t *>(output);
+
+	/*
+	 * Upscale the 10-bit format to 16-bit as it's not trivial to pack it
+	 * as 10-bit without gaps.
+	 *
+	 * \todo Improve packing to keep the 10-bit sample size.
+	 */
+	unsigned int x = 0;
+	while (true) {
+		for (unsigned int i = 0; i < 6; i++) {
+			*out++ = (in[1] & 0x03) << 14 | (in[0] & 0xff) << 6;
+			if (++x >= width)
+				break;
+
+			*out++ = (in[2] & 0x0f) << 12 | (in[1] & 0xfc) << 4;
+			if (++x >= width)
+				break;
+
+			*out++ = (in[3] & 0x3f) << 10 | (in[2] & 0xf0) << 2;
+			if (++x >= width)
+				break;
+
+			*out++ = (in[4] & 0xff) <<  8 | (in[3] & 0xc0) << 0;
+			if (++x >= width)
+				break;
+
+			in += 5;
+		}
+
+		*out++ = (in[1] & 0x03) << 14 | (in[0] & 0xff) << 6;
+		if (++x >= width)
+			break;
+
+		in += 2;
+	}
+}
+
+void thumbScanlineIPU3(const FormatInfo &info, void *output,
+		       const void *input, unsigned int width,
+		       unsigned int stride)
+{
+	uint8_t *out = static_cast<uint8_t *>(output);
+
+	for (unsigned int x = 0; x < width; x++) {
+		unsigned int pixel = x * 16;
+		unsigned int block = pixel / 25;
+		unsigned int pixelInBlock = pixel - block * 25;
+
+		/*
+		 * If the pixel is the last in the block cheat a little and
+		 * move one pixel backward to avoid reading between two blocks
+		 * and having to deal with the padding bits.
+		 */
+		if (pixelInBlock == 24)
+			pixelInBlock--;
+
+		const uint8_t *in = static_cast<const uint8_t *>(input)
+			+ block * 32 + (pixelInBlock / 4) * 5;
+
+		uint16_t val1, val2, val3, val4;
+		switch (pixelInBlock % 4) {
+		case 0:
+			val1 = (in[1] & 0x03) << 14 | (in[0] & 0xff) << 6;
+			val2 = (in[2] & 0x0f) << 12 | (in[1] & 0xfc) << 4;
+			val3 = (in[stride + 1] & 0x03) << 14 | (in[stride + 0] & 0xff) << 6;
+			val4 = (in[stride + 2] & 0x0f) << 12 | (in[stride + 1] & 0xfc) << 4;
+			break;
+		case 1:
+			val1 = (in[2] & 0x0f) << 12 | (in[1] & 0xfc) << 4;
+			val2 = (in[3] & 0x3f) << 10 | (in[2] & 0xf0) << 2;
+			val3 = (in[stride + 2] & 0x0f) << 12 | (in[stride + 1] & 0xfc) << 4;
+			val4 = (in[stride + 3] & 0x3f) << 10 | (in[stride + 2] & 0xf0) << 2;
+			break;
+		case 2:
+			val1 = (in[3] & 0x3f) << 10 | (in[2] & 0xf0) << 2;
+			val2 = (in[4] & 0xff) <<  8 | (in[3] & 0xc0) << 0;
+			val3 = (in[stride + 3] & 0x3f) << 10 | (in[stride + 2] & 0xf0) << 2;
+			val4 = (in[stride + 4] & 0xff) <<  8 | (in[stride + 3] & 0xc0) << 0;
+			break;
+		case 3:
+			val1 = (in[4] & 0xff) <<  8 | (in[3] & 0xc0) << 0;
+			val2 = (in[6] & 0x03) << 14 | (in[5] & 0xff) << 6;
+			val3 = (in[stride + 4] & 0xff) <<  8 | (in[stride + 3] & 0xc0) << 0;
+			val4 = (in[stride + 6] & 0x03) << 14 | (in[stride + 5] & 0xff) << 6;
+		}
+
+		uint8_t value = (val1 + val2 + val3 + val4) >> 8;
+		*out++ = value;
+		*out++ = value;
+		*out++ = value;
+	}
+}
+
 static const std::map<PixelFormat, FormatInfo> formatInfo = {
 	{ PixelFormat(DRM_FORMAT_SBGGR10, MIPI_FORMAT_MOD_CSI2_PACKED), {
 		.bitsPerSample = 10,
@@ -131,6 +228,30 @@ static const std::map<PixelFormat, FormatInfo> formatInfo = {
 		.packScanline = packScanlineSBGGR12P,
 		.thumbScanline = thumbScanlineSBGGRxxP,
 	} },
+	{ PixelFormat(DRM_FORMAT_SBGGR10, IPU3_FORMAT_MOD_PACKED), {
+		.bitsPerSample = 16,
+		.pattern = { CFAPatternBlue, CFAPatternGreen, CFAPatternGreen, CFAPatternRed },
+		.packScanline = packScanlineIPU3,
+		.thumbScanline = thumbScanlineIPU3,
+	} },
+	{ PixelFormat(DRM_FORMAT_SGBRG10, IPU3_FORMAT_MOD_PACKED), {
+		.bitsPerSample = 16,
+		.pattern = { CFAPatternGreen, CFAPatternBlue, CFAPatternRed, CFAPatternGreen },
+		.packScanline = packScanlineIPU3,
+		.thumbScanline = thumbScanlineIPU3,
+	} },
+	{ PixelFormat(DRM_FORMAT_SGRBG10, IPU3_FORMAT_MOD_PACKED), {
+		.bitsPerSample = 16,
+		.pattern = { CFAPatternGreen, CFAPatternRed, CFAPatternBlue, CFAPatternGreen },
+		.packScanline = packScanlineIPU3,
+		.thumbScanline = thumbScanlineIPU3,
+	} },
+	{ PixelFormat(DRM_FORMAT_SRGGB10, IPU3_FORMAT_MOD_PACKED), {
+		.bitsPerSample = 16,
+		.pattern = { CFAPatternRed, CFAPatternGreen, CFAPatternGreen, CFAPatternBlue },
+		.packScanline = packScanlineIPU3,
+		.thumbScanline = thumbScanlineIPU3,
+	} },
 };
 
 int DNGWriter::write(const char *filename, const Camera *camera,
-- 
2.27.0



More information about the libcamera-devel mailing list