summaryrefslogtreecommitdiff
path: root/src/qcam
diff options
context:
space:
mode:
authorNiklas Söderlund <niklas.soderlund@ragnatech.se>2020-05-03 02:17:38 +0200
committerNiklas Söderlund <niklas.soderlund@ragnatech.se>2020-06-15 17:36:12 +0200
commit5a3cfc33db235dd33aa7bdee02390a9e74437108 (patch)
treee35f839528f05172ce2877e2f030287d248bb569 /src/qcam
parent96fab38e02792a109c0d35ca2154e95a7b4c8fcb (diff)
qcam: dng_writer: Add support for IPU3 Bayer formats
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@ragnatech.se> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src/qcam')
-rw-r--r--src/qcam/dng_writer.cpp122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/qcam/dng_writer.cpp b/src/qcam/dng_writer.cpp
index cbd8bed3..84709088 100644
--- a/src/qcam/dng_writer.cpp
+++ b/src/qcam/dng_writer.cpp
@@ -82,6 +82,104 @@ 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)
+ return;
+
+ *out++ = (in[2] & 0x0f) << 12 | (in[1] & 0xfc) << 4;
+ if (++x >= width)
+ return;
+
+ *out++ = (in[3] & 0x3f) << 10 | (in[2] & 0xf0) << 2;
+ if (++x >= width)
+ return;
+
+ *out++ = (in[4] & 0xff) << 8 | (in[3] & 0xc0) << 0;
+ if (++x >= width)
+ return;
+
+ in += 5;
+ }
+
+ *out++ = (in[1] & 0x03) << 14 | (in[0] & 0xff) << 6;
+ if (++x >= width)
+ return;
+
+ 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;
+ break;
+ }
+
+ uint8_t value = (val1 + val2 + val3 + val4) >> 10;
+ *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 +229,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,