From 10d680b74d742f8a4efb3731944190cf56ced169 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 17 Aug 2010 15:56:34 -0300 Subject: [PATCH] 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. --- gst-libs/gst/tag/gstexiftag.c | 504 +++++++++++++++++++++++++++++++++++++++--- tests/check/libs/tag.c | 50 +++++ 2 files changed, 521 insertions(+), 33 deletions(-) diff --git a/gst-libs/gst/tag/gstexiftag.c b/gst-libs/gst/tag/gstexiftag.c index a443ba7..8a4fbf2 100644 --- a/gst-libs/gst/tag/gstexiftag.c +++ b/gst-libs/gst/tag/gstexiftag.c @@ -41,6 +41,7 @@ #include #include #include +#include /* 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 94c5978..c036a57 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; -- 2.7.4