فهرست منبع

Repack V4L packed formats before saving it in the DNG

Martijn Braam 1 سال پیش
والد
کامیت
93eff6a316
8فایلهای تغییر یافته به همراه163 افزوده شده و 2 حذف شده
  1. 1 1
      CMakeLists.txt
  2. 3 0
      include/libdng.h
  3. 15 1
      src/libdng.c
  4. 20 0
      src/mode.c
  5. 7 0
      src/mode.h
  6. 111 0
      src/repack.c
  7. 4 0
      src/repack.h
  8. 2 0
      tests/test_dng_validate.sh

+ 1 - 1
CMakeLists.txt

@@ -6,7 +6,7 @@ set(LIBRARY_VERSION_MAJOR 0)
 set(LIBRARY_VERSION_STRING 0.1)
 set(CMAKE_C_VISIBILITY_PRESET hidden)
 
-add_library(libdng SHARED include/libdng.h src/libdng.c src/dng.h src/mode.c)
+add_library(libdng SHARED include/libdng.h src/libdng.c src/dng.h src/mode.c src/repack.c src/repack.h)
 
 set_target_properties(libdng PROPERTIES
         VERSION ${LIBRARY_VERSION_STRING}

+ 3 - 0
include/libdng.h

@@ -21,6 +21,9 @@ typedef struct {
 		float colormatrix2[9];
 		float neutral[3];
 		uint8_t cfapattern[4];
+
+		uint16_t bit_depth;
+		bool needs_repack;
 } libdng_info;
 
 #define LIBDNG_ORIENTATION_TOPLEFT 1

+ 15 - 1
src/libdng.c

@@ -1,6 +1,7 @@
 #include "libdng.h"
 #include "dng.h"
 #include "mode.h"
+#include "repack.h"
 
 #include <stdio.h>
 #include <tiffio.h>
@@ -58,6 +59,8 @@ libdng_set_mode_from_index(libdng_info *dng, int index)
 	dng->cfapattern[1] = (cfa >> 16) & 0xFF;
 	dng->cfapattern[2] = (cfa >> 8) & 0xFF;
 	dng->cfapattern[3] = (cfa >> 0) & 0xFF;
+	dng->needs_repack = dng_mode_needs_repack(index);
+	dng->bit_depth = dng_bitdepth_from_mode(index);
 	return 1;
 }
 
@@ -151,6 +154,13 @@ int
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	size_t length)
 {
+
+	uint8_t *raw_frame = (uint8_t *) data;
+	if (dng->needs_repack) {
+		raw_frame = malloc(length);
+		dng_repack(data, raw_frame, width, height, dng->bit_depth);
+	}
+
 	TIFF *tif = TIFFOpen(path, "w");
 	if (!tif) {
 		return -1;
@@ -230,7 +240,7 @@ libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned in
 
 	unsigned int stride = width;
 	for (int row = 0; row < height; row++) {
-		TIFFWriteScanline(tif, (void *) data + (row * stride), row, 0);
+		TIFFWriteScanline(tif, (void *) raw_frame + (row * stride), row, 0);
 	}
 	if (!TIFFWriteDirectory(tif)) {
 		return -1;
@@ -263,5 +273,9 @@ libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned in
 
 	TIFFClose(tif);
 
+	if (dng->needs_repack) {
+		free(raw_frame);
+	}
+	
 	return 0;
 }

+ 20 - 0
src/mode.c

@@ -72,6 +72,7 @@ static struct pixelformat pixelformat_lut[] = {
 		.pixfmt = V4L2_PIX_FMT_SRGGB10P,
 		.cfa = CFA_RGGB,
 		.bits_per_sample = 10,
+		.repack = true,
 	},
 	{
 		.fourcc = "pgAA",
@@ -79,6 +80,7 @@ static struct pixelformat pixelformat_lut[] = {
 		.pixfmt = V4L2_PIX_FMT_SGRBG10P,
 		.cfa = CFA_GRBG,
 		.bits_per_sample = 10,
+		.repack = true,
 	},
 	{
 		.fourcc = "pGAA",
@@ -86,6 +88,7 @@ static struct pixelformat pixelformat_lut[] = {
 		.pixfmt = V4L2_PIX_FMT_SGBRG10P,
 		.cfa = CFA_GBRG,
 		.bits_per_sample = 10,
+		.repack = true,
 	},
 	{
 		.fourcc = "pBAA",
@@ -93,6 +96,7 @@ static struct pixelformat pixelformat_lut[] = {
 		.pixfmt = V4L2_PIX_FMT_SBGGR10P,
 		.cfa = CFA_BGGR,
 		.bits_per_sample = 10,
+		.repack = true,
 	},
 	{
 		.fourcc = "RG12",
@@ -128,6 +132,7 @@ static struct pixelformat pixelformat_lut[] = {
 		.pixfmt = V4L2_PIX_FMT_SRGGB12P,
 		.cfa = CFA_RGGB,
 		.bits_per_sample = 12,
+		.repack = true,
 	},
 	{
 		.fourcc = "pgCC",
@@ -135,6 +140,7 @@ static struct pixelformat pixelformat_lut[] = {
 		.pixfmt = V4L2_PIX_FMT_SGRBG12P,
 		.cfa = CFA_GRBG,
 		.bits_per_sample = 12,
+		.repack = true,
 	},
 	{
 		.fourcc = "pGCC",
@@ -142,6 +148,7 @@ static struct pixelformat pixelformat_lut[] = {
 		.pixfmt = V4L2_PIX_FMT_SGBRG12P,
 		.cfa = CFA_GBRG,
 		.bits_per_sample = 12,
+		.repack = true,
 	},
 	{
 		.fourcc = "pBCC",
@@ -149,6 +156,7 @@ static struct pixelformat pixelformat_lut[] = {
 		.pixfmt = V4L2_PIX_FMT_SBGGR12P,
 		.cfa = CFA_BGGR,
 		.bits_per_sample = 12,
+		.repack = true,
 	},
 	{
 		.fourcc = "RG16",
@@ -211,4 +219,16 @@ uint32_t
 dng_cfa_from_mode(int index)
 {
 	return pixelformat_lut[index].cfa;
+}
+
+int
+dng_bitdepth_from_mode(int index)
+{
+	return pixelformat_lut[index].bits_per_sample;
+}
+
+bool
+dng_mode_needs_repack(int index)
+{
+	return pixelformat_lut[index].repack;
 }

+ 7 - 0
src/mode.h

@@ -15,6 +15,7 @@ struct pixelformat {
 		uint32_t pixfmt;
 		uint32_t cfa;
 		int bits_per_sample;
+		bool repack;
 };
 
 int
@@ -25,3 +26,9 @@ dng_mode_from_pixfmt(uint32_t pixfmt);
 
 uint32_t
 dng_cfa_from_mode(int index);
+
+int
+dng_bitdepth_from_mode(int index);
+
+bool
+dng_mode_needs_repack(int index);

+ 111 - 0
src/repack.c

@@ -0,0 +1,111 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include "repack.h"
+
+void
+dng_repack_10bit(const uint8_t *src_buf, uint8_t *dst_buf, uint32_t width, uint32_t height)
+{
+	uint16_t pixels[4];
+	uint64_t bits_per_width = (uint64_t) width * 10;
+	uint64_t remainder = bits_per_width % 8;
+	uint32_t stride;
+	uint32_t padding_bytes = 0;
+	if (remainder == 0) {
+		stride = bits_per_width / 8;
+	} else {
+		stride = (bits_per_width + 8 - remainder) / 8;
+		padding_bytes = 8 - remainder;
+	}
+
+	size_t si = 0;
+
+	/*
+	 * Repack 40 bits stored in sensor format into sequential format
+	 *
+	 * src_buf: 11111111 22222222 33333333 44444444 11223344 ...
+	 * dst_buf: 11111111 11222222 22223333 33333344 44444444 ...
+	 */
+	for (size_t i = 0; i < stride * height; i += 5) {
+		// Skip padding bytes in source buffer
+		if (i && i % stride == 0)
+			si += padding_bytes;
+
+		/* Extract pixels from packed sensor format */
+		pixels[0] = (src_buf[si + 0] << 2) | (src_buf[si + 4] >> 6);
+		pixels[1] = (src_buf[si + 1] << 2) | (src_buf[si + 4] >> 4 & 0x03);
+		pixels[2] = (src_buf[si + 2] << 2) | (src_buf[si + 4] >> 2 & 0x03);
+		pixels[3] = (src_buf[si + 3] << 2) | (src_buf[si + 4] & 0x03);
+
+		/* Pack pixels into sequential format */
+		dst_buf[i + 0] = (pixels[0] >> 2 & 0xff);
+		dst_buf[i + 1] = (pixels[0] << 6 & 0xff) | (pixels[1] >> 4 & 0x3f);
+		dst_buf[i + 2] = (pixels[1] << 4 & 0xff) | (pixels[2] >> 6 & 0x0f);
+		dst_buf[i + 3] = (pixels[2] << 2 & 0xff) | (pixels[3] >> 8 & 0x03);
+		dst_buf[i + 4] = (pixels[3] & 0xff);
+
+		si += 5;
+	}
+}
+
+void
+dng_repack_12bit(const uint8_t *src_buf, uint8_t *dst_buf, uint32_t width, uint32_t height)
+{
+	uint16_t pixels[4];
+	uint64_t bits_per_width = (uint64_t) width * 12;
+	uint64_t remainder = bits_per_width % 8;
+	uint32_t stride;
+	uint32_t padding_bytes = 0;
+	if (remainder == 0) {
+		stride = bits_per_width / 8;
+	} else {
+		stride = (bits_per_width + 8 - remainder) / 8;
+		padding_bytes = 8 - remainder;
+	}
+
+	size_t si = 0;
+
+	/*
+	 * Repack 48 bits stored in sensor format into sequential format
+	 *
+	 * src_buf: 11111111 22222222 11112222 33333333 44444444 33334444 ...
+	 * dst_buf: 11111111 11112222 22222222 33333333 33334444 44444444 ...
+	 */
+	for (size_t i = 0; i < stride * height; i += 6) {
+		// Skip padding bytes in source buffer
+		if (i && i % stride == 0)
+			si += padding_bytes;
+
+		/* Extract pixels from packed sensor format */
+		pixels[0] = (src_buf[si + 0] << 4) | (src_buf[si + 2] >> 4);
+		pixels[1] = (src_buf[si + 1] << 4) | (src_buf[si + 2] & 0xF);
+		pixels[2] = (src_buf[si + 3] << 4) | (src_buf[si + 5] >> 4);
+		pixels[3] = (src_buf[si + 4] << 4) | (src_buf[si + 5] & 0xF);
+
+		/* Pack pixels into sequential format */
+		// TODO: This is wrong, fix when there's actual testing data
+		dst_buf[i + 0] = (pixels[0] >> 4 & 0xff);
+		dst_buf[i + 1] = (pixels[0] << 4 & 0xff) | (pixels[1] >> 4 & 0xF);
+		dst_buf[i + 2] = (pixels[1] >> 4 & 0xff) | (pixels[2] >> 6 & 0x0f);
+		dst_buf[i + 3] = (pixels[2] << 2 & 0xff) | (pixels[3] >> 8 & 0x03);
+		dst_buf[i + 4] = (pixels[3] & 0xff);
+		dst_buf[i + 5] = (pixels[3] & 0xff);
+
+		si += 6;
+	}
+}
+
+
+void
+dng_repack(const uint8_t *src_buf, uint8_t *dst_buf, uint32_t width, uint32_t height, int bitdepth)
+{
+	switch (bitdepth) {
+		case 10:
+			return dng_repack_10bit(src_buf, dst_buf, width, height);
+		case 12:
+			return dng_repack_12bit(src_buf, dst_buf, width, height);
+		default:
+			fprintf(stderr, "dng_repack: invalid bitdepth %d\n", bitdepth);
+			break;
+	}
+}

+ 4 - 0
src/repack.h

@@ -0,0 +1,4 @@
+#pragma once
+
+void
+dng_repack(const uint8_t *src_buf, uint8_t *dst_buf, uint32_t width, uint32_t height, int bitdepth);

+ 2 - 0
tests/test_dng_validate.sh

@@ -24,6 +24,7 @@ $makedng -w 1280 -h 720 -p GBRG -m Test,GBRG scratch/data.rgb scratch/GBRG.dng
 $makedng -w 1280 -h 720 -p BGGR -m Test,BGGR scratch/data.rgb scratch/BGGR.dng
 
 $makedng -w 1280 -h 720 -p RG10 scratch/data.rgb scratch/RG10.dng
+$makedng -w 1280 -h 720 -p SRGGB10P scratch/data.rgb scratch/SRGGB10P.dng
 
 $makedng -w 1280 -h 720 -p RGGB \
   -s "Testsuite" \
@@ -37,5 +38,6 @@ dng_validate scratch/GBRG.dng
 dng_validate scratch/BGGR.dng
 
 dng_validate scratch/RG10.dng
+dng_validate scratch/SRGGB10P.dng
 
 dng_validate scratch/fields.dng