summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>2010-08-17 15:56:34 -0300
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>2010-08-24 22:24:36 -0300
commit10d680b74d742f8a4efb3731944190cf56ced169 (patch)
tree01aeb0ddb06a5d952a34fff9e0e94f0b85f1110b
parent57013ae63e681057d7525d6e09532995177127ce (diff)
tag: exif: Adds photography tags mappings
Adds the following mappings for the exif helper: * GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO -> DigitalZoomRatio * GST_TAG_CAPTURING_FOCAL_LENGTH -> FocalLength * GST_TAG_CAPTURING_SHUTTER_SPEED -> ExposureTime, ShutterSpeedValue * GST_TAG_CAPTURING_FOCAL_RATIO -> FNumber, ApertureValue * GST_TAG_CAPTURING_ISO_SPEED -> ISOSpeed, PhotographicSensitivity Tests included.
-rw-r--r--gst-libs/gst/tag/gstexiftag.c504
-rw-r--r--tests/check/libs/tag.c50
2 files changed, 521 insertions, 33 deletions
diff --git a/gst-libs/gst/tag/gstexiftag.c b/gst-libs/gst/tag/gstexiftag.c
index a443ba722..8a4fbf274 100644
--- a/gst-libs/gst/tag/gstexiftag.c
+++ b/gst-libs/gst/tag/gstexiftag.c
@@ -41,6 +41,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <math.h>
/* Some useful constants */
#define TIFF_LITTLE_ENDIAN 0x4949
@@ -141,13 +142,20 @@ struct _GstExifReader
const GstBuffer *buffer;
guint32 base_offset;
gint byte_order;
+
+ /* tags waiting for their complementary tags */
+ GSList *pending_tags;
};
EXIF_SERIALIZATION_DESERIALIZATION_FUNC (orientation);
EXIF_SERIALIZATION_DESERIALIZATION_FUNC (geo_coordinate);
EXIF_SERIALIZATION_DESERIALIZATION_FUNC (geo_direction);
EXIF_SERIALIZATION_DESERIALIZATION_FUNC (geo_elevation);
+EXIF_SERIALIZATION_DESERIALIZATION_FUNC (shutter_speed);
+EXIF_SERIALIZATION_DESERIALIZATION_FUNC (aperture_value);
+EXIF_SERIALIZATION_DESERIALIZATION_FUNC (sensitivity_type);
EXIF_SERIALIZATION_DESERIALIZATION_FUNC (speed);
+EXIF_DESERIALIZATION_FUNC (add_to_pending_tags);
/* FIXME copyright tag has a weird "artist\0editor\0" format that is
* not yet handled */
@@ -173,6 +181,16 @@ static const GstExifTagMatch tag_map_ifd0[] = {
{GST_TAG_DATE_TIME, 0x132, EXIF_TYPE_ASCII, 0, NULL, NULL},
{GST_TAG_ARTIST, 0x13B, EXIF_TYPE_ASCII, 0, NULL, NULL},
{GST_TAG_COPYRIGHT, 0x8298, EXIF_TYPE_ASCII, 0, NULL, NULL},
+ {GST_TAG_CAPTURING_SHUTTER_SPEED, 0x829A, EXIF_TYPE_RATIONAL, 0, NULL, NULL},
+ {GST_TAG_CAPTURING_FOCAL_RATIO, 0x829D, EXIF_TYPE_RATIONAL, 0, NULL, NULL},
+
+ /* don't need the serializer as we always write the iso speed alone */
+ {GST_TAG_CAPTURING_ISO_SPEED, 0x8827, EXIF_TYPE_SHORT, 0, NULL,
+ deserialize_add_to_pending_tags},
+
+ {GST_TAG_CAPTURING_ISO_SPEED, 0x8830, EXIF_TYPE_SHORT, 0,
+ serialize_sensitivity_type, deserialize_sensitivity_type},
+ {GST_TAG_CAPTURING_ISO_SPEED, 0x8833, EXIF_TYPE_LONG, 0, NULL, NULL},
{NULL, EXIF_IFD_TAG, EXIF_TYPE_LONG, 0, NULL, NULL},
{NULL, EXIF_GPS_IFD_TAG, EXIF_TYPE_LONG, 0, NULL, NULL},
{NULL, 0, 0, 0, NULL, NULL}
@@ -181,7 +199,14 @@ static const GstExifTagMatch tag_map_ifd0[] = {
static const GstExifTagMatch tag_map_exif[] = {
{NULL, EXIF_VERSION_TAG, EXIF_TYPE_UNDEFINED, 0, NULL, NULL},
{GST_TAG_DATE_TIME, 0x9003, EXIF_TYPE_ASCII, 0, NULL, NULL},
+ {GST_TAG_CAPTURING_SHUTTER_SPEED, 0x9201, EXIF_TYPE_SRATIONAL, 0,
+ serialize_shutter_speed, deserialize_shutter_speed},
+ {GST_TAG_CAPTURING_FOCAL_RATIO, 0x9202, EXIF_TYPE_RATIONAL, 0,
+ serialize_aperture_value, deserialize_aperture_value},
+ {GST_TAG_CAPTURING_FOCAL_LENGTH, 0x920A, EXIF_TYPE_RATIONAL, 0, NULL, NULL},
{GST_TAG_APPLICATION_DATA, 0x927C, EXIF_TYPE_UNDEFINED, 0, NULL, NULL},
+ {GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, 0xA404, EXIF_TYPE_RATIONAL, 0, NULL,
+ NULL},
{NULL, 0, 0, 0, NULL, NULL}
};
@@ -210,6 +235,7 @@ gst_exif_reader_init (GstExifReader * reader, gint byte_order,
reader->buffer = buf;
reader->base_offset = base_offset;
reader->byte_order = byte_order;
+ reader->pending_tags = NULL;
if (reader->byte_order != G_LITTLE_ENDIAN &&
reader->byte_order != G_BIG_ENDIAN) {
GST_WARNING ("Unexpected byte order %d, using system default: %d",
@@ -218,6 +244,56 @@ gst_exif_reader_init (GstExifReader * reader, gint byte_order,
}
}
+static void
+gst_exif_reader_add_pending_tag (GstExifReader * reader, GstExifTagData * data)
+{
+ GstExifTagData *copy;
+
+ copy = g_slice_new (GstExifTagData);
+ memcpy (copy, data, sizeof (GstExifTagData));
+
+ reader->pending_tags = g_slist_prepend (reader->pending_tags, copy);
+}
+
+static GstExifTagData *
+gst_exif_reader_get_pending_tag (GstExifReader * reader, gint tagid)
+{
+ GSList *walker;
+
+ for (walker = reader->pending_tags; walker; walker = g_slist_next (walker)) {
+ GstExifTagData *data = (GstExifTagData *) walker->data;
+ if (data->tag == tagid)
+ return data;
+ }
+
+ return NULL;
+}
+
+static GstTagList *
+gst_exif_reader_reset (GstExifReader * reader, gboolean return_taglist)
+{
+ GstTagList *ret = NULL;
+ GSList *walker;
+
+ for (walker = reader->pending_tags; walker; walker = g_slist_next (walker)) {
+ GstExifTagData *data = (GstExifTagData *) walker->data;
+
+ g_slice_free (GstExifTagData, data);
+ }
+ g_slist_free (reader->pending_tags);
+
+ if (return_taglist) {
+ ret = reader->taglist;
+ reader->taglist = NULL;
+ }
+
+ if (reader->taglist) {
+ gst_tag_list_free (reader->taglist);
+ }
+
+ return ret;
+}
+
/* GstExifWriter functions */
static void
@@ -347,6 +423,19 @@ gst_exif_writer_write_rational_data (GstExifWriter * writer, guint32 frac_n,
}
static void
+gst_exif_writer_write_signed_rational_data (GstExifWriter * writer,
+ gint32 frac_n, gint32 frac_d)
+{
+ if (writer->byte_order == G_LITTLE_ENDIAN) {
+ gst_byte_writer_put_int32_le (&writer->datawriter, frac_n);
+ gst_byte_writer_put_int32_le (&writer->datawriter, frac_d);
+ } else {
+ gst_byte_writer_put_int32_be (&writer->datawriter, frac_n);
+ gst_byte_writer_put_int32_be (&writer->datawriter, frac_d);
+ }
+}
+
+static void
gst_exif_writer_write_rational_tag (GstExifWriter * writer,
guint16 tag, guint32 frac_n, guint32 frac_d)
{
@@ -359,6 +448,18 @@ gst_exif_writer_write_rational_tag (GstExifWriter * writer,
}
static void
+gst_exif_writer_write_signed_rational_tag (GstExifWriter * writer,
+ guint16 tag, gint32 frac_n, gint32 frac_d)
+{
+ guint32 offset = gst_byte_writer_get_size (&writer->datawriter);
+
+ gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_SRATIONAL,
+ 1, offset, FALSE);
+
+ gst_exif_writer_write_signed_rational_data (writer, frac_n, frac_d);
+}
+
+static void
gst_exif_writer_write_rational_tag_from_double (GstExifWriter * writer,
guint16 tag, gdouble value)
{
@@ -371,6 +472,18 @@ gst_exif_writer_write_rational_tag_from_double (GstExifWriter * writer,
}
static void
+gst_exif_writer_write_signed_rational_tag_from_double (GstExifWriter * writer,
+ guint16 tag, gdouble value)
+{
+ gint frac_n;
+ gint frac_d;
+
+ gst_util_double_to_fraction (value, &frac_n, &frac_d);
+
+ gst_exif_writer_write_signed_rational_tag (writer, tag, frac_n, frac_d);
+}
+
+static void
gst_exif_writer_write_byte_tag (GstExifWriter * writer, guint16 tag,
guint8 value)
{
@@ -398,6 +511,22 @@ gst_exif_writer_write_short_tag (GstExifWriter * writer, guint16 tag,
}
static void
+gst_exif_writer_write_long_tag (GstExifWriter * writer, guint16 tag,
+ guint32 value)
+{
+ guint32 offset = 0;
+ if (writer->byte_order == G_LITTLE_ENDIAN) {
+ GST_WRITE_UINT32_LE ((guint8 *) & offset, value);
+ } else {
+ GST_WRITE_UINT32_BE ((guint8 *) & offset, value);
+ }
+
+ gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_LONG,
+ 1, offset, TRUE);
+}
+
+
+static void
write_exif_undefined_tag (GstExifWriter * writer, guint16 tag,
const guint8 * data, gint size)
{
@@ -535,6 +664,79 @@ write_exif_undefined_tag_from_taglist (GstExifWriter * writer,
}
static void
+write_exif_rational_tag_from_taglist (GstExifWriter * writer,
+ const GstTagList * taglist, const GstExifTagMatch * exiftag)
+{
+ const GValue *value;
+ gdouble num = 0;
+ gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
+
+ if (tag_size != 1) {
+ GST_WARNING ("Only the first item in the taglist will be serialized");
+ return;
+ }
+
+ value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
+
+ /* do some conversion if needed */
+ switch (G_VALUE_TYPE (value)) {
+ case G_TYPE_DOUBLE:
+ num = g_value_get_double (value);
+ gst_exif_writer_write_rational_tag_from_double (writer, exiftag->exif_tag,
+ num);
+ break;
+ default:
+ if (G_VALUE_TYPE (value) == GST_TYPE_FRACTION) {
+ gst_exif_writer_write_rational_tag (writer, exiftag->exif_tag,
+ gst_value_get_fraction_numerator (value),
+ gst_value_get_fraction_denominator (value));
+ } else {
+ GST_WARNING ("Conversion from %s to rational not supported",
+ G_VALUE_TYPE_NAME (value));
+ }
+ break;
+ }
+}
+
+static void
+write_exif_integer_tag_from_taglist (GstExifWriter * writer,
+ const GstTagList * taglist, const GstExifTagMatch * exiftag)
+{
+ const GValue *value;
+ guint32 num = 0;
+ gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
+
+ if (tag_size != 1) {
+ GST_WARNING ("Only the first item in the taglist will be serialized");
+ return;
+ }
+
+ value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
+
+ /* do some conversion if needed */
+ switch (G_VALUE_TYPE (value)) {
+ case G_TYPE_INT:
+ num = g_value_get_int (value);
+ break;
+ default:
+ GST_WARNING ("Conversion from %s to int not supported",
+ G_VALUE_TYPE_NAME (value));
+ break;
+ }
+
+ switch (exiftag->exif_type) {
+ case EXIF_TYPE_LONG:
+ gst_exif_writer_write_long_tag (writer, exiftag->exif_tag, num);
+ break;
+ case EXIF_TYPE_SHORT:
+ gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, num);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
write_exif_tag_from_taglist (GstExifWriter * writer, const GstTagList * taglist,
const GstExifTagMatch * exiftag)
{
@@ -553,6 +755,13 @@ write_exif_tag_from_taglist (GstExifWriter * writer, const GstTagList * taglist,
case EXIF_TYPE_UNDEFINED:
write_exif_undefined_tag_from_taglist (writer, taglist, exiftag);
break;
+ case EXIF_TYPE_RATIONAL:
+ write_exif_rational_tag_from_taglist (writer, taglist, exiftag);
+ break;
+ case EXIF_TYPE_LONG:
+ case EXIF_TYPE_SHORT:
+ write_exif_integer_tag_from_taglist (writer, taglist, exiftag);
+ break;
default:
GST_WARNING ("Unhandled tag type %d", exiftag->exif_type);
}
@@ -734,6 +943,28 @@ parse_exif_ascii_tag (GstExifReader * reader, const GstExifTagMatch * tag,
}
static void
+parse_exif_long_tag (GstExifReader * reader, const GstExifTagMatch * tag,
+ guint32 count, guint32 offset, const guint8 * offset_as_data)
+{
+ GType tagtype;
+
+ if (count > 1) {
+ GST_WARNING ("Long tags with more than one value are not supported");
+ return;
+ }
+
+ tagtype = gst_tag_get_type (tag->gst_tag);
+ if (tagtype == G_TYPE_INT) {
+ gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE, tag->gst_tag,
+ offset, NULL);
+ } else {
+ GST_WARNING ("No parsing function associated to %x(%s)", tag->exif_tag,
+ tag->gst_tag);
+ }
+}
+
+
+static void
parse_exif_undefined_tag (GstExifReader * reader, const GstExifTagMatch * tag,
guint32 count, guint32 offset, const guint8 * offset_as_data)
{
@@ -785,15 +1016,15 @@ parse_exif_undefined_tag (GstExifReader * reader, const GstExifTagMatch * tag,
g_free (data);
}
-static void
-parse_exif_rational_tag (GstExifReader * exif_reader,
- const gchar * gst_tag, guint32 count, guint32 offset, gdouble multiplier)
+static gboolean
+exif_reader_read_rational_tag (GstExifReader * exif_reader,
+ guint32 count, guint32 offset, gboolean is_signed,
+ gint32 * _frac_n, gint32 * _frac_d)
{
GstByteReader data_reader;
guint32 real_offset;
- guint32 frac_n = 0;
- guint32 frac_d = 1;
- gdouble value;
+ gint32 frac_n;
+ gint32 frac_d;
if (count > 1) {
GST_WARNING ("Rationals with multiple entries are not supported");
@@ -801,43 +1032,96 @@ parse_exif_rational_tag (GstExifReader * exif_reader,
if (offset < exif_reader->base_offset) {
GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
exif_reader->base_offset);
- return;
+ return FALSE;
}
real_offset = offset - exif_reader->base_offset;
if (real_offset >= GST_BUFFER_SIZE (exif_reader->buffer)) {
- GST_WARNING ("Invalid offset %u for buffer of size %u, not adding tag %s",
- real_offset, GST_BUFFER_SIZE (exif_reader->buffer), gst_tag);
- return;
+ GST_WARNING ("Invalid offset %u for buffer of size %u",
+ real_offset, GST_BUFFER_SIZE (exif_reader->buffer));
+ return FALSE;
}
gst_byte_reader_init_from_buffer (&data_reader, exif_reader->buffer);
if (!gst_byte_reader_set_pos (&data_reader, real_offset))
goto reader_fail;
- if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
- if (!gst_byte_reader_get_uint32_le (&data_reader, &frac_n) ||
- !gst_byte_reader_get_uint32_le (&data_reader, &frac_d))
- goto reader_fail;
+ if (!is_signed) {
+ guint32 aux_n, aux_d;
+ if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
+ if (!gst_byte_reader_get_uint32_le (&data_reader, &aux_n) ||
+ !gst_byte_reader_get_uint32_le (&data_reader, &aux_d))
+ goto reader_fail;
+ } else {
+ if (!gst_byte_reader_get_uint32_be (&data_reader, &aux_n) ||
+ !gst_byte_reader_get_uint32_be (&data_reader, &aux_d))
+ goto reader_fail;
+ }
+ frac_n = (gint32) aux_n;
+ frac_d = (gint32) aux_d;
} else {
- if (!gst_byte_reader_get_uint32_be (&data_reader, &frac_n) ||
- !gst_byte_reader_get_uint32_be (&data_reader, &frac_d))
- goto reader_fail;
+ if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
+ if (!gst_byte_reader_get_int32_le (&data_reader, &frac_n) ||
+ !gst_byte_reader_get_int32_le (&data_reader, &frac_d))
+ goto reader_fail;
+ } else {
+ if (!gst_byte_reader_get_int32_be (&data_reader, &frac_n) ||
+ !gst_byte_reader_get_int32_be (&data_reader, &frac_d))
+ goto reader_fail;
+ }
}
- GST_DEBUG ("Read fraction for tag %s: %u/%u", gst_tag, frac_n, frac_d);
-
- gst_util_fraction_to_double (frac_n, frac_d, &value);
+ if (_frac_n)
+ *_frac_n = frac_n;
+ if (_frac_d)
+ *_frac_d = frac_d;
- value *= multiplier;
- GST_DEBUG ("Adding %s tag: %lf", gst_tag, value);
- gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, gst_tag, value,
- NULL);
-
- return;
+ return TRUE;
reader_fail:
GST_WARNING ("Failed to read from byte reader. (Buffer too short?)");
+ return FALSE;
+}
+
+static void
+parse_exif_rational_tag (GstExifReader * exif_reader,
+ const gchar * gst_tag, guint32 count, guint32 offset, gdouble multiplier,
+ gboolean is_signed)
+{
+ GType type;
+ gint32 frac_n = 0;
+ gint32 frac_d = 1;
+ gdouble value;
+
+ GST_DEBUG ("Reading fraction for tag %s...", gst_tag);
+ if (!exif_reader_read_rational_tag (exif_reader, count, offset, is_signed,
+ &frac_n, &frac_d))
+ return;
+ GST_DEBUG ("Read fraction for tag %s: %d/%d", gst_tag, frac_n, frac_d);
+
+ type = gst_tag_get_type (gst_tag);
+ switch (type) {
+ case G_TYPE_DOUBLE:
+ gst_util_fraction_to_double (frac_n, frac_d, &value);
+ value *= multiplier;
+ GST_DEBUG ("Adding %s tag: %lf", gst_tag, value);
+ gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, gst_tag,
+ value, NULL);
+ break;
+ default:
+ if (type == GST_TYPE_FRACTION) {
+ GValue fraction = { 0 };
+
+ g_value_init (&fraction, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&fraction, frac_n * multiplier, frac_d);
+ gst_tag_list_add_value (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
+ gst_tag, &fraction);
+ g_value_unset (&fraction);
+ } else {
+ GST_WARNING ("Can't convert from fraction into %s", g_type_name (type));
+ }
+ }
+
}
static GstBuffer *
@@ -1041,11 +1325,15 @@ parse_exif_ifd (GstExifReader * exif_reader, gint buf_offset,
break;
case EXIF_TYPE_RATIONAL:
parse_exif_rational_tag (exif_reader, tag_map[map_index].gst_tag,
- tagdata.count, tagdata.offset, 1);
+ tagdata.count, tagdata.offset, 1, FALSE);
break;
case EXIF_TYPE_UNDEFINED:
parse_exif_undefined_tag (exif_reader, &tag_map[map_index],
tagdata.count, tagdata.offset, tagdata.offset_as_data);
+ case EXIF_TYPE_LONG:
+ parse_exif_long_tag (exif_reader, &tag_map[map_index],
+ tagdata.count, tagdata.offset, tagdata.offset_as_data);
+ break;
default:
GST_WARNING ("Unhandled tag type: %u", tagdata.tag_type);
break;
@@ -1160,12 +1448,11 @@ gst_tag_list_from_exif_buffer (const GstBuffer * buffer, gint byte_order,
if (!parse_exif_ifd (&reader, 0, tag_map_ifd0))
goto read_error;
- return reader.taglist;
+ return gst_exif_reader_reset (&reader, TRUE);
read_error:
{
- if (reader.taglist)
- gst_tag_list_free (reader.taglist);
+ gst_exif_reader_reset (&reader, FALSE);
GST_WARNING ("Failed to parse the exif buffer");
return NULL;
}
@@ -1558,7 +1845,7 @@ deserialize_geo_direction (GstExifReader * exif_reader,
}
parse_exif_rational_tag (exif_reader,
- exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, 1);
+ exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, 1, FALSE);
return ret;
@@ -1656,7 +1943,8 @@ deserialize_geo_elevation (GstExifReader * exif_reader,
}
parse_exif_rational_tag (exif_reader,
- exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, multiplier);
+ exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, multiplier,
+ FALSE);
return ret;
@@ -1755,7 +2043,8 @@ deserialize_speed (GstExifReader * exif_reader,
}
parse_exif_rational_tag (exif_reader,
- exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, multiplier);
+ exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, multiplier,
+ FALSE);
return ret;
@@ -1764,6 +2053,155 @@ reader_fail:
return ret;
}
+static void
+serialize_shutter_speed (GstExifWriter * writer, const GstTagList * taglist,
+ const GstExifTagMatch * exiftag)
+{
+ const GValue *value = NULL;
+ gdouble num;
+
+ value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
+ if (!value) {
+ GST_WARNING ("Failed to get shutter speed from from tag list");
+ return;
+ }
+ gst_util_fraction_to_double (gst_value_get_fraction_numerator (value),
+ gst_value_get_fraction_denominator (value), &num);
+
+ num = -log2 (num);
+
+ /* now the value */
+ gst_exif_writer_write_signed_rational_tag_from_double (writer,
+ exiftag->exif_tag, num);
+}
+
+static gint
+deserialize_shutter_speed (GstExifReader * exif_reader,
+ GstByteReader * reader, const GstExifTagMatch * exiftag,
+ GstExifTagData * tagdata)
+{
+ gint32 frac_n, frac_d;
+ gdouble d;
+ GValue value = { 0 };
+
+ GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
+ exiftag->exif_tag);
+
+ if (!exif_reader_read_rational_tag (exif_reader, tagdata->count,
+ tagdata->offset, TRUE, &frac_n, &frac_d))
+ return 0;
+
+ gst_util_fraction_to_double (frac_n, frac_d, &d);
+ d = pow (2, -d);
+ gst_util_double_to_fraction (d, &frac_n, &frac_d);
+
+ g_value_init (&value, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&value, frac_n, frac_d);
+ gst_tag_list_add_value (exif_reader->taglist, GST_TAG_MERGE_KEEP,
+ exiftag->gst_tag, &value);
+ g_value_unset (&value);
+
+ return 0;
+}
+
+static void
+serialize_aperture_value (GstExifWriter * writer, const GstTagList * taglist,
+ const GstExifTagMatch * exiftag)
+{
+ gdouble num;
+
+ if (!gst_tag_list_get_double_index (taglist, exiftag->gst_tag, 0, &num)) {
+ GST_WARNING ("Failed to get focal ratio from from tag list");
+ return;
+ }
+ num = 2 * log2 (num);
+
+ /* now the value */
+ gst_exif_writer_write_rational_tag_from_double (writer,
+ exiftag->exif_tag, num);
+}
+
+static gint
+deserialize_aperture_value (GstExifReader * exif_reader,
+ GstByteReader * reader, const GstExifTagMatch * exiftag,
+ GstExifTagData * tagdata)
+{
+ gint32 frac_n, frac_d;
+ gdouble d;
+
+ GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
+ exiftag->exif_tag);
+
+ if (!exif_reader_read_rational_tag (exif_reader, tagdata->count,
+ tagdata->offset, FALSE, &frac_n, &frac_d))
+ return 0;
+
+ gst_util_fraction_to_double (frac_n, frac_d, &d);
+ d = pow (2, d / 2);
+
+ gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_KEEP,
+ exiftag->gst_tag, d, NULL);
+
+ return 0;
+}
+
+static void
+serialize_sensitivity_type (GstExifWriter * writer, const GstTagList * taglist,
+ const GstExifTagMatch * exiftag)
+{
+ /* we only support ISOSpeed as the sensitivity type (3) */
+ gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, 3);
+}
+
+static gint
+deserialize_sensitivity_type (GstExifReader * exif_reader,
+ GstByteReader * reader, const GstExifTagMatch * exiftag,
+ GstExifTagData * tagdata)
+{
+ GstExifTagData *sensitivity = NULL;
+ guint16 type_data;
+
+ if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
+ type_data = GST_READ_UINT16_LE (tagdata->offset_as_data);
+ } else {
+ type_data = GST_READ_UINT16_BE (tagdata->offset_as_data);
+ }
+
+ if (type_data != 3) {
+ GST_WARNING ("We only support SensitivityType=3");
+ return 0;
+ }
+
+ /* check the pending tags for the PhotographicSensitivity tag */
+ sensitivity = gst_exif_reader_get_pending_tag (exif_reader, 0x8827);
+ if (sensitivity == NULL) {
+ GST_WARNING ("PhotographicSensitivity tag not found");
+ return 0;
+ }
+
+ GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
+ exiftag->exif_tag);
+
+ gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_KEEP,
+ GST_TAG_CAPTURING_ISO_SPEED, sensitivity->offset_as_data, NULL);
+
+ return 0;
+}
+
+static gint
+deserialize_add_to_pending_tags (GstExifReader * exif_reader,
+ GstByteReader * reader, const GstExifTagMatch * exiftag,
+ GstExifTagData * tagdata)
+{
+ GST_LOG ("Adding %s tag in exif 0x%x to pending tags", exiftag->gst_tag,
+ exiftag->exif_tag);
+
+ /* add it to the pending tags, as we can only parse it when we find the
+ * SensitivityType tag */
+ gst_exif_reader_add_pending_tag (exif_reader, tagdata);
+ return 0;
+}
+
#undef EXIF_SERIALIZATION_FUNC
#undef EXIF_DESERIALIZATION_FUNC
#undef EXIF_SERIALIZATION_DESERIALIZATION_FUNC
diff --git a/tests/check/libs/tag.c b/tests/check/libs/tag.c
index 94c5978ad..c036a57a4 100644
--- a/tests/check/libs/tag.c
+++ b/tests/check/libs/tag.c
@@ -1246,6 +1246,8 @@ GST_START_TEST (test_exif_tags_serialization_deserialization)
GstBuffer *buf = NULL;
gint i;
+ gst_tag_register_musicbrainz_tags ();
+
g_value_init (&value, G_TYPE_STRING);
g_value_set_static_string (&value, "my string");
do_simple_exif_tag_serialization_deserialization (GST_TAG_COPYRIGHT, &value);
@@ -1328,6 +1330,39 @@ GST_START_TEST (test_exif_tags_serialization_deserialization)
g_value_set_double (&value, 100 / 3.6);
do_simple_exif_tag_serialization_deserialization
(GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, &value);
+
+ g_value_set_double (&value, 0);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, &value);
+ g_value_set_double (&value, 2.5);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, &value);
+ g_value_set_double (&value, 8.75);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, &value);
+
+ g_value_set_double (&value, 20.0);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_FOCAL_LENGTH, &value);
+ g_value_set_double (&value, 5.5);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_FOCAL_LENGTH, &value);
+
+ g_value_set_double (&value, 16);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_FOCAL_RATIO, &value);
+ g_value_set_double (&value, 2.7);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_FOCAL_LENGTH, &value);
+ g_value_unset (&value);
+
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, 400);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_ISO_SPEED, &value);
+ g_value_set_int (&value, 1600);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_ISO_SPEED, &value);
g_value_unset (&value);
g_value_init (&value, GST_TYPE_DATE_TIME);
@@ -1346,6 +1381,21 @@ GST_START_TEST (test_exif_tags_serialization_deserialization)
do_simple_exif_tag_serialization_deserialization (GST_TAG_APPLICATION_DATA,
&value);
g_value_unset (&value);
+
+ g_value_init (&value, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&value, 1, 1);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_SHUTTER_SPEED, &value);
+ gst_value_set_fraction (&value, 1, 30);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_SHUTTER_SPEED, &value);
+ gst_value_set_fraction (&value, 1, 200);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_SHUTTER_SPEED, &value);
+ gst_value_set_fraction (&value, 1, 8000);
+ do_simple_exif_tag_serialization_deserialization
+ (GST_TAG_CAPTURING_SHUTTER_SPEED, &value);
+ g_value_unset (&value);
}
GST_END_TEST;