diff options
author | Niklas Söderlund <niklas.soderlund@ragnatech.se> | 2020-05-03 02:17:38 +0200 |
---|---|---|
committer | Niklas Söderlund <niklas.soderlund@ragnatech.se> | 2020-06-15 17:36:12 +0200 |
commit | 5a3cfc33db235dd33aa7bdee02390a9e74437108 (patch) | |
tree | e35f839528f05172ce2877e2f030287d248bb569 /src/qcam | |
parent | 96fab38e02792a109c0d35ca2154e95a7b4c8fcb (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.cpp | 122 |
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, |