summaryrefslogtreecommitdiffstats
path: root/ext/metadata/metadataexif.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/metadata/metadataexif.c')
-rw-r--r--ext/metadata/metadataexif.c331
1 files changed, 288 insertions, 43 deletions
diff --git a/ext/metadata/metadataexif.c b/ext/metadata/metadataexif.c
index c45a93e4..65ade6ea 100644
--- a/ext/metadata/metadataexif.c
+++ b/ext/metadata/metadataexif.c
@@ -75,6 +75,8 @@ metadatamux_exif_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
#include <libexif/exif-data.h>
#include <stdlib.h>
+#include <string.h>
+#include <math.h>
typedef struct _tag_MEUserData
{
@@ -95,37 +97,55 @@ exif_data_foreach_content_func (ExifContent * content, void *callback_data);
static void exif_content_foreach_entry_func (ExifEntry * entry, void *);
-const gchar *
+/* *INDENT-OFF* */
+static MapIntStr mappedTags[] = {
+ {EXIF_TAG_MAKE, /*EXIF_FORMAT_ASCII,*/ GST_TAG_DEVICE_MAKE, G_TYPE_STRING},
+ {EXIF_TAG_MODEL, /*EXIF_FORMAT_ASCII,*/ GST_TAG_DEVICE_MODEL, G_TYPE_STRING},
+ {EXIF_TAG_SOFTWARE, /*EXIF_FORMAT_ASCII,*/ GST_TAG_CREATOR_TOOL, G_TYPE_STRING},
+ {EXIF_TAG_X_RESOLUTION, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_IMAGE_XRESOLUTION, G_TYPE_FLOAT}, /* inches */
+ {EXIF_TAG_Y_RESOLUTION, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_IMAGE_YRESOLUTION, G_TYPE_FLOAT}, /* inches */
+ {EXIF_TAG_EXPOSURE_TIME, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_CAPTURE_EXPOSURE_TIME, G_TYPE_FLOAT},
+ {EXIF_TAG_FNUMBER, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_CAPTURE_FNUMBER, G_TYPE_FLOAT},
+ {EXIF_TAG_EXPOSURE_PROGRAM, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_EXPOSURE_PROGRAM, G_TYPE_UINT},
+ {EXIF_TAG_BRIGHTNESS_VALUE, /*EXIF_FORMAT_SRATIONAL,*/ GST_TAG_CAPTURE_BRIGHTNESS, G_TYPE_FLOAT},
+ {EXIF_TAG_WHITE_BALANCE, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_WHITE_BALANCE, G_TYPE_UINT},
+ {EXIF_TAG_DIGITAL_ZOOM_RATIO, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_CAPTURE_DIGITAL_ZOOM, G_TYPE_FLOAT},
+ {EXIF_TAG_GAIN_CONTROL, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_GAIN, G_TYPE_UINT},
+ {EXIF_TAG_CONTRAST, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_CONTRAST, G_TYPE_INT},
+ {EXIF_TAG_SATURATION, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_SATURATION, G_TYPE_INT},
+ {0, NULL, G_TYPE_NONE}
+};
+/* *INDENT-ON* */
+
+static const gchar *
metadataparse_exif_get_tag_from_exif (ExifTag exif, GType * type)
{
- /* FIXEME: sorted with binary search */
- static MapIntStr array[] = {
- {EXIF_TAG_MAKE, GST_TAG_DEVICE_MAKE, G_TYPE_STRING},
- {EXIF_TAG_MODEL, GST_TAG_DEVICE_MODEL, G_TYPE_STRING},
- {EXIF_TAG_SOFTWARE, GST_TAG_CREATOR_TOOL, G_TYPE_STRING},
- {EXIF_TAG_X_RESOLUTION, GST_TAG_IMAGE_XRESOLUTION, G_TYPE_FLOAT}, /* asure inches */
- {EXIF_TAG_Y_RESOLUTION, GST_TAG_IMAGE_YRESOLUTION, G_TYPE_FLOAT}, /* asure inches */
- {EXIF_TAG_EXPOSURE_TIME, GST_TAG_CAPTURE_EXPOSURE_TIME, G_TYPE_FLOAT},
- {EXIF_TAG_FNUMBER, GST_TAG_CAPTURE_FNUMBER, G_TYPE_FLOAT},
- {EXIF_TAG_EXPOSURE_PROGRAM, GST_TAG_CAPTURE_EXPOSURE_PROGRAM, G_TYPE_UINT},
- {EXIF_TAG_BRIGHTNESS_VALUE, GST_TAG_CAPTURE_BRIGHTNESS, G_TYPE_FLOAT},
- {EXIF_TAG_WHITE_BALANCE, GST_TAG_CAPTURE_WHITE_BALANCE, G_TYPE_UINT},
- {EXIF_TAG_DIGITAL_ZOOM_RATIO, GST_TAG_CAPTURE_DIGITAL_ZOOM, G_TYPE_FLOAT},
- {EXIF_TAG_GAIN_CONTROL, GST_TAG_CAPTURE_GAIN, G_TYPE_UINT},
- {EXIF_TAG_CONTRAST, GST_TAG_CAPTURE_CONTRAST, G_TYPE_UINT},
- {EXIF_TAG_SATURATION, GST_TAG_CAPTURE_SATURATION, G_TYPE_UINT},
- {0, NULL, G_TYPE_NONE, G_TYPE_UINT}
- };
int i = 0;
- while (array[i].exif) {
- if (exif == array[i].exif)
+ while (mappedTags[i].exif) {
+ if (exif == mappedTags[i].exif)
break;
++i;
}
- *type = array[i].type;
- return array[i].str;
+ *type = mappedTags[i].type;
+ return mappedTags[i].str;
+
+}
+
+static ExifTag
+metadataparse_exif_get_exif_from_tag (const gchar * tag, GType * type)
+{
+ int i = 0;
+
+ while (mappedTags[i].exif) {
+ if (0 == strcmp (mappedTags[i].str, tag))
+ break;
+ ++i;
+ }
+
+ *type = mappedTags[i].type;
+ return mappedTags[i].exif;
}
@@ -180,6 +200,31 @@ exif_data_foreach_content_func (ExifContent * content, void *user_data)
user_data);
}
+#if 0
+static gboolean
+exif_fast_mdc (glong n, glong d, gulong * m)
+{
+ gboolean ret = FALSE;
+
+ static const int a[] =
+ { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 39, 41, 43, 47, 49, 53, 0 };
+ int i = 0;
+
+ *m = 1;
+
+ while (a[i] <= n && a[i] <= d) {
+ while ((n % a[i] == 0) && (d % a[i]) == 0) {
+ *m *= a[i];
+ ret = TRUE;
+ }
+ ++i;
+ }
+
+ return ret;
+
+}
+#endif
+
static void
exif_content_foreach_entry_func (ExifEntry * entry, void *user_data)
{
@@ -223,65 +268,83 @@ exif_content_foreach_entry_func (ExifEntry * entry, void *user_data)
case G_TYPE_FLOAT:
{
gfloat f_value;
- ExifRational v_rat;
switch (entry->format) {
+ case EXIF_FORMAT_SRATIONAL:
+ {
+ ExifSRational v_srat;
+
+ v_srat = exif_get_srational (entry->data, byte_order);
+ if (v_srat.denominator == 0)
+ f_value = 0.0f;
+ else
+ f_value = (float) v_srat.numerator / (float) v_srat.denominator;
+ if (v_srat.numerator == 0xFFFFFFFF) {
+ if (entry->tag == EXIF_TAG_BRIGHTNESS_VALUE) {
+ f_value = 100.0f;
+ }
+ }
+ }
+ break;
case EXIF_FORMAT_RATIONAL:
+ {
+ ExifRational v_rat;
+
v_rat = exif_get_rational (entry->data, byte_order);
- if (v_rat.numerator == 0)
+ if (v_rat.denominator == 0)
f_value = 0.0f;
else
f_value = (float) v_rat.numerator / (float) v_rat.denominator;
- if (v_rat.numerator == 0xFFFFFFFF) {
- if (entry->tag == GST_TAG_CAPTURE_BRIGHTNESS) {
- f_value = 100.0f;
+ if (meudata->resolution_unit == 3) {
+ /* converts from cm to inches */
+ if (entry->tag == EXIF_TAG_X_RESOLUTION
+ || entry->tag == EXIF_TAG_Y_RESOLUTION) {
+ f_value *= 0.4f;
}
}
+ }
break;
default:
GST_ERROR ("Unexpected Tag Type");
goto done;
break;
}
- if (meudata->resolution_unit == 3) {
- /* converts from cm to inches */
- if (entry->tag == EXIF_TAG_X_RESOLUTION
- || entry->tag == EXIF_TAG_Y_RESOLUTION) {
- f_value *= 0.4f;
- }
- }
gst_tag_list_add (meudata->taglist, meudata->mode, tag, f_value, NULL);
}
+ break;
+ case G_TYPE_INT:
+ /* fall through */
case G_TYPE_UINT:
{
- ExifShort v_short;
+ gint value;
switch (entry->format) {
case EXIF_FORMAT_SHORT:
- v_short = exif_get_short (entry->data, byte_order);
+ value = exif_get_short (entry->data, byte_order);
break;
default:
- GST_ERROR ("Unexpected Tag Type");
+ GST_ERROR ("Unexpected Exif Tag Type (%s - %s)",
+ tag, exif_format_get_name (entry->format));
goto done;
break;
}
if (entry->tag == EXIF_TAG_CONTRAST ||
entry->tag == EXIF_TAG_SATURATION) {
- switch (v_short) {
+ switch (value) {
case 0:
break;
case 1:
- v_short = -67;
+ value = -67; /* -100-34 /2 */
break;
case 2:
- v_short = 66;
+ value = 67; /* 100+34 /2 */
break;
default:
GST_ERROR ("Unexpected value");
break;
}
}
- gst_tag_list_add (meudata->taglist, meudata->mode, tag, v_short, NULL);
+ gst_tag_list_add (meudata->taglist, meudata->mode, tag, value, NULL);
}
break;
default:
@@ -313,6 +376,188 @@ done:
*
*/
+static ExifRational
+float_to_rational (gfloat f)
+{
+ ExifRational r;
+ int i = 6; /* precision */
+
+ r.denominator = 1;
+
+ while (i--) {
+ if (f == floorf (f)) {
+ break;
+ }
+ f *= 10.0f;
+ r.denominator *= 10;
+ }
+
+ r.numerator = f;
+
+ if (!(r.numerator & 0x1 || r.denominator & 0x1)) {
+ /* divide both by 2 */
+ r.numerator >>= 1;
+ r.denominator >>= 1;
+ }
+ if (r.numerator % 5 == 0 && r.denominator % 5 == 0) {
+ r.numerator /= 5;
+ r.denominator /= 5;
+ }
+
+ return r;
+
+}
+
+static ExifSRational
+float_to_srational (gfloat f)
+{
+ ExifSRational sr;
+ int i = 6; /* precision */
+
+ sr.denominator = 1;
+
+ while (i--) {
+ if (f == floorf (f)) {
+ break;
+ }
+ f *= 10.0f;
+ sr.denominator *= 10;
+ }
+
+ sr.numerator = f;
+
+ if (!(sr.numerator & 0x1 || sr.denominator & 0x1)) {
+ /* divide both by 2 */
+ sr.numerator >>= 1;
+ sr.denominator >>= 1;
+ }
+ if (sr.numerator % 5 == 0 && sr.denominator % 5 == 0) {
+ sr.numerator /= 5;
+ sr.denominator /= 5;
+ }
+
+ return sr;
+
+}
+
+static void
+metadataexif_for_each_tag_in_list (const GstTagList * list, const gchar * tag,
+ gpointer user_data)
+{
+ ExifData *ed = (ExifData *) user_data;
+ ExifTag exif_tag;
+ GType type;
+ ExifEntry *entry = NULL;
+ const ExifByteOrder byte_order = exif_data_get_byte_order (ed);
+
+ exif_tag = metadataparse_exif_get_exif_from_tag (tag, &type);
+
+ if (!exif_tag)
+ goto done;
+
+ entry = exif_data_get_entry (ed, exif_tag);
+
+ if (entry)
+ exif_entry_ref (entry);
+ else {
+ entry = exif_entry_new ();
+ exif_content_add_entry (ed->ifd[EXIF_IFD_0], entry);
+ exif_entry_initialize (entry, exif_tag);
+ }
+
+ switch (type) {
+ case G_TYPE_STRING:
+ {
+ gchar *value = NULL;
+
+ if (gst_tag_list_get_string (list, tag, &value)) {
+ entry->components = strlen (value) + 1;
+ entry->size = exif_format_get_size (entry->format) * entry->components;
+ entry->data = value;
+ }
+ }
+ break;
+ case G_TYPE_FLOAT:
+ {
+ gfloat value;
+
+ gst_tag_list_get_float (list, tag, &value);
+
+ switch (entry->format) {
+ case EXIF_FORMAT_SRATIONAL:
+ {
+ ExifSRational sr;
+
+ sr = float_to_srational (value);
+ if (entry->tag == EXIF_TAG_BRIGHTNESS_VALUE) {
+ if (value == 100.0f) {
+ sr.numerator = 0xFFFFFFFF;
+ sr.denominator = 1;
+ }
+ }
+
+ exif_set_srational (entry->data, byte_order, sr);
+ }
+ break;
+ case EXIF_FORMAT_RATIONAL:
+ {
+ ExifRational r;
+
+ r = float_to_rational (value);
+ exif_set_rational (entry->data, byte_order, r);
+ if (entry->tag == EXIF_TAG_X_RESOLUTION ||
+ entry->tag == EXIF_TAG_Y_RESOLUTION) {
+ ExifEntry *unit_entry = NULL;
+
+ if ((unit_entry =
+ exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT))) {
+ ExifShort vsh = exif_get_short (unit_entry->data, byte_order);
+
+ if (vsh != 2) /* inches */
+ exif_set_short (unit_entry->data, byte_order, 2);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case G_TYPE_UINT:
+ case G_TYPE_INT:
+ {
+ gint value;
+ ExifShort v_short;
+
+ if (G_TYPE_UINT == type) {
+ gst_tag_list_get_uint (list, tag, &value);
+ } else {
+ gst_tag_list_get_int (list, tag, &value);
+ }
+ if (entry->tag == EXIF_TAG_CONTRAST || entry->tag == EXIF_TAG_SATURATION) {
+ if (value < -33)
+ value = 1; /* low */
+ else if (value < 34)
+ value = 0; /* normal */
+ else
+ value = 2; /* high */
+ }
+ v_short = value;
+ exif_set_short (entry->data, byte_order, v_short);
+ }
+ break;
+ default:
+ break;
+ }
+
+done:
+
+ if (entry)
+ exif_entry_unref (entry);
+
+}
+
void
metadatamux_exif_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
const GstTagList * taglist)
@@ -344,7 +589,7 @@ metadatamux_exif_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
exif_data_fix (ed);
}
- /* FIXME: consider individual tags */
+ gst_tag_list_foreach (taglist, metadataexif_for_each_tag_in_list, ed);
exif_data_save_data (ed, buf, size);