Browse Source

Support writing the framerate metadata for CinemaDNG

Martijn Braam 7 months ago
parent
commit
8cd947179a
6 changed files with 35 additions and 1 deletions
  1. 4 0
      include/libdng.h
  2. 5 0
      src/dng.h
  3. 14 0
      src/libdng.c
  4. 1 0
      tests/check_dng.c
  5. 1 0
      tests/test_dng_validate.sh
  6. 10 1
      util/makedng.c

+ 4 - 0
include/libdng.h

@@ -21,6 +21,7 @@ typedef struct {
 		float fnumber;
 		float focal_length;
 		float crop_factor;
+		float frame_rate;
 
 		// Raw image data
 		uint16_t bayer_pattern_dimensions[2];
@@ -141,6 +142,9 @@ libdng_set_fnumber(libdng_info *dng, float fnumber);
 EXPORT int
 libdng_set_focal_length(libdng_info *dng, float focal_length, float crop_factor);
 
+EXPORT int
+libdng_set_frame_rate(libdng_info *dng, float framerate);
+
 EXPORT int
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	size_t length);

+ 5 - 0
src/dng.h

@@ -131,6 +131,10 @@
 #define DNGTAG_FORWARD_MATRIX_1 50964
 #define DNGTAG_FORWARD_MATRIX_2 50965
 
+// Tags from the CinemaDNG specification
+#define DNGTAG_TIMECODES 51043
+#define DNGTAG_FRAMERATE 51044
+#define DNGTAG_TSTOP 51058
 
 /*
  * Field definitions for the tags in the DNG spec
@@ -147,4 +151,5 @@ static const TIFFFieldInfo custom_dng_fields[] = {
 	{DNGTAG_CFAREPEATPATTERNDIM,        -1, -1, TIFF_SHORT,     FIELD_CUSTOM, 1, 1, "CFARepeatPatternDim"},
 	{DNGTAG_CFAPATTERN,                 -1, -1, TIFF_BYTE,      FIELD_CUSTOM, 1, 1, "CFAPattern"},
 	{DNGTAG_LINEARIZATIONTABLE,         -1, -1, TIFF_SHORT,     FIELD_CUSTOM, 1, 1, "LinearizationTable"},
+	{DNGTAG_FRAMERATE,                  -1,  -1,  TIFF_SRATIONAL, FIELD_CUSTOM, 1, 1, "FrameRate"},
 };

+ 14 - 0
src/libdng.c

@@ -63,6 +63,7 @@ libdng_new(libdng_info *dng)
 	dng->fnumber = 0.0f;
 	dng->crop_factor = 1.0f;
 	dng->focal_length = 0.0f;
+	dng->frame_rate = 0.0f;
 }
 
 int
@@ -256,6 +257,16 @@ libdng_set_focal_length(libdng_info *dng, float focal_length, float crop_factor)
 	return 1;
 }
 
+int
+libdng_set_frame_rate(libdng_info *dng, float framerate)
+{
+	if (dng == NULL)
+		return 0;
+
+	dng->frame_rate = framerate;
+	return 1;
+}
+
 int
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	size_t length)
@@ -332,6 +343,9 @@ libdng_write_with_thumbnail(libdng_info *dng, const char *path, unsigned int wid
 		snprintf(ucm, sizeof(ucm), "%s %s", dng->camera_make, dng->camera_model);
 	}
 	TIFFSetField(tif, DNGTAG_UNIQUECAMERAMODEL, ucm);
+	if (dng->frame_rate != 0.0f) {
+		TIFFSetField(tif, DNGTAG_FRAMERATE, 1, &dng->frame_rate);
+	}
 	TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &ifd0_offsets);
 
 	if (thumb_length == 0) {

+ 1 - 0
tests/check_dng.c

@@ -48,6 +48,7 @@ TEST generate_simple_dng(void)
 		ASSERT_EQm("Set exposuretime", 1, libdng_set_exposure_time(&info, 0.04f));
 		ASSERT_EQm("Set fnumber", 1, libdng_set_fnumber(&info, 2.8f));
 		ASSERT_EQm("Set fnumber", 1, libdng_set_focal_length(&info, 50.0f, 1.5f));
+		ASSERT_EQm("Set framerate", 1, libdng_set_frame_rate(&info, 30.0f));
 	uint8_t *data = malloc(1280 * 720);
 		ASSERT_EQm("Write DNG", 1, libdng_write(&info, "test.dng", 1280, 720, data, 1280 * 720));
 	free(data);

+ 1 - 0
tests/test_dng_validate.sh

@@ -36,6 +36,7 @@ $makedng --width 1280 --height 720 --pixfmt RGGB \
   --iso 1600 \
   --fnumber 2.8 \
   --focal-length 50,1.5 \
+  --frame-rate 30 \
   scratch/data.rgb scratch/fields.dng
 
 # Validate DNG

+ 10 - 1
util/makedng.c

@@ -26,6 +26,7 @@ usage(char *name)
 	fprintf(stderr, "  -i, --iso speed                 Set the ISO speed rating\n");
 	fprintf(stderr, "  -f, --fnumber fnumber           Set the aperture as f/value\n");
 	fprintf(stderr, "  -l, --focal-length length,crop  Set the aperture as f/value\n");
+	fprintf(stderr, "  -F, --frame-rate framerate      Set the CinemaDNG framerate\n");
 }
 
 int
@@ -52,6 +53,7 @@ main(int argc, char *argv[])
 	float exposure_time = 0;
 	uint32_t iso = 0;
 	float fnumber = 0.0f;
+	float framerate = 0.0f;
 	float focal_length = 0.0f;
 	float crop_factor = 1.0f;
 
@@ -70,10 +72,11 @@ main(int argc, char *argv[])
 		{"iso", required_argument, NULL, 'i'},
 		{"fnumber", required_argument, NULL, 'f'},
 		{"focal-length", required_argument, NULL, 'l'},
+		{"frame-rate", required_argument, NULL, 'F'},
 		{"help", no_argument, NULL, 'H'},
 	};
 	int option_index = 0;
-	while ((c = getopt_long(argc, argv, "w:h:p:o:m:s:c:n:b:e:t:i:f:l:", long_options, &option_index)) != -1) {
+	while ((c = getopt_long(argc, argv, "w:h:p:o:m:s:c:n:b:e:t:i:f:l:F:", long_options, &option_index)) != -1) {
 		switch (c) {
 			case 'w':
 				val = strtol(optarg, &end, 10);
@@ -131,6 +134,9 @@ main(int argc, char *argv[])
 			case 'f':
 				fnumber = strtof(optarg, &end);
 				break;
+			case 'F':
+				framerate = strtof(optarg, &end);
+				break;
 			case 'l':
 				val = sscanf(optarg, "%f,%f", &focal_length, &crop_factor);
 				if (val != 2 && val != 1) {
@@ -218,6 +224,9 @@ main(int argc, char *argv[])
 	if (focal_length > 0) {
 		libdng_set_focal_length(&info, focal_length, crop_factor);
 	}
+	if (framerate > 0) {
+		libdng_set_frame_rate(&info, framerate);
+	}
 
 	printf("Reading %s...\n", argv[optind]);
 	FILE *src = fopen(argv[optind], "r");