2 * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
4 * gstexiftag.c: library for reading / modifying exif tags
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
24 * @short_description: tag mappings and support functions for plugins
25 * dealing with exif tags
26 * @see_also: #GstTagList
28 * Contains utility function to parse #GstTagList<!-- -->s from exif
29 * buffers and to create exif buffers from #GstTagList<!-- -->s
31 * Note that next IFD fields on the created exif buffers are set to 0.
37 #include <gst/gsttagsetter.h>
38 #include <gst/base/gstbytewriter.h>
39 #include "gsttageditingprivate.h"
44 #include <gst/math-compat.h>
46 /* Some useful constants */
47 #define TIFF_LITTLE_ENDIAN 0x4949
48 #define TIFF_BIG_ENDIAN 0x4D4D
49 #define TIFF_HEADER_SIZE 8
50 #define EXIF_TAG_ENTRY_SIZE (2 + 2 + 4 + 4)
53 #define EXIF_TYPE_BYTE 1
54 #define EXIF_TYPE_ASCII 2
55 #define EXIF_TYPE_SHORT 3
56 #define EXIF_TYPE_LONG 4
57 #define EXIF_TYPE_RATIONAL 5
58 #define EXIF_TYPE_UNDEFINED 7
59 #define EXIF_TYPE_SLONG 9
60 #define EXIF_TYPE_SRATIONAL 10
62 typedef struct _GstExifTagMatch GstExifTagMatch;
63 typedef struct _GstExifWriter GstExifWriter;
64 typedef struct _GstExifReader GstExifReader;
65 typedef struct _GstExifTagData GstExifTagData;
67 typedef void (*GstExifSerializationFunc) (GstExifWriter * writer,
68 const GstTagList * taglist, const GstExifTagMatch * exiftag);
71 * Function used to deserialize tags that don't follow the usual
72 * deserialization conversions. Usually those that have 'Ref' complementary
75 * Those functions receive a exif tag data in the parameters, plus the taglist
76 * and the reader and buffer if they need to get more information to build
77 * its tags. There are lots of parameters, but this is needed to make it
78 * versatile. Explanation of them follows:
80 * exif_reader: The #GstExifReader with the reading parameter and taglist for
82 * reader: The #GstByteReader pointing to the start of the next tag entry in
83 * the ifd, useful for tags that use other complementary tags.
85 * exiftag: The #GstExifTagMatch that contains this tag info
86 * tagdata: values from the already parsed tag
88 typedef gint (*GstExifDeserializationFunc) (GstExifReader * exif_reader,
89 GstByteReader * reader, const GstExifTagMatch * exiftag,
90 GstExifTagData * tagdata);
92 #define EXIF_SERIALIZATION_FUNC(name) \
93 static void serialize_ ## name (GstExifWriter * writer, \
94 const GstTagList * taglist, const GstExifTagMatch * exiftag)
96 #define EXIF_DESERIALIZATION_FUNC(name) \
97 static gint deserialize_ ## name (GstExifReader * exif_reader, \
98 GstByteReader * reader, const GstExifTagMatch * exiftag, \
99 GstExifTagData * tagdata)
101 #define EXIF_SERIALIZATION_DESERIALIZATION_FUNC(name) \
102 EXIF_SERIALIZATION_FUNC (name); \
103 EXIF_DESERIALIZATION_FUNC (name)
106 * A common case among serialization/deserialization routines is that
107 * the gstreamer tag is a string (with a predefined set of allowed values)
108 * and exif is an int. These macros cover these cases
110 #define EXIF_SERIALIZATION_MAP_STRING_TO_INT_FUNC(name,funcname) \
112 serialize_ ## name (GstExifWriter * writer, const GstTagList * taglist, \
113 const GstExifTagMatch * exiftag) \
118 if (!gst_tag_list_get_string_index (taglist, exiftag->gst_tag, 0, &str)) { \
119 GST_WARNING ("No %s tag present in taglist", exiftag->gst_tag); \
123 exif_value = __exif_tag_ ## funcname ## _to_exif_value (str); \
124 if (exif_value == -1) { \
130 switch (exiftag->exif_type) { \
131 case EXIF_TYPE_SHORT: \
132 gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, exif_value); \
134 case EXIF_TYPE_LONG: \
135 gst_exif_writer_write_long_tag (writer, exiftag->exif_tag, exif_value); \
137 case EXIF_TYPE_UNDEFINED: \
139 guint8 data = (guint8) exif_value; \
140 write_exif_undefined_tag (writer, exiftag->exif_tag, &data, 1); \
144 g_assert_not_reached (); \
145 GST_WARNING ("Unmapped serialization for type %d", exiftag->exif_type); \
150 #define EXIF_DESERIALIZATION_MAP_STRING_TO_INT_FUNC(name,funcname) \
152 deserialize_ ## name (GstExifReader * exif_reader, \
153 GstByteReader * reader, const GstExifTagMatch * exiftag, \
154 GstExifTagData * tagdata) \
156 const gchar *str = NULL; \
159 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag, \
160 exiftag->exif_tag); \
163 if (tagdata->count != 1) { \
164 GST_WARNING ("0x%X has unexpected count", tagdata->count); \
168 if (tagdata->tag_type == EXIF_TYPE_SHORT) { \
169 if (exif_reader->byte_order == G_LITTLE_ENDIAN) { \
170 value = GST_READ_UINT16_LE (tagdata->offset_as_data); \
172 value = GST_READ_UINT16_BE (tagdata->offset_as_data); \
174 } else if (tagdata->tag_type == EXIF_TYPE_UNDEFINED) { \
175 value = GST_READ_UINT8 (tagdata->offset_as_data); \
177 GST_WARNING ("0x%X has unexpected type %d", exiftag->exif_tag, \
178 tagdata->tag_type); \
182 str = __exif_tag_## funcname ## _from_exif_value (value); \
184 GST_WARNING ("Invalid value for tag 0x%X: %d", tagdata->tag, value); \
187 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, \
188 exiftag->gst_tag, str, NULL); \
193 #define EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC(name,funcname) \
194 EXIF_SERIALIZATION_MAP_STRING_TO_INT_FUNC(name,funcname); \
195 EXIF_DESERIALIZATION_MAP_STRING_TO_INT_FUNC(name,funcname);
197 struct _GstExifTagMatch
199 const gchar *gst_tag;
203 /* for tags that need special handling */
204 guint16 complementary_tag;
205 GstExifSerializationFunc serialize;
206 GstExifDeserializationFunc deserialize;
209 struct _GstExifTagData
215 const guint8 *offset_as_data;
219 * Holds the info and variables necessary to write
220 * the exif tags properly
222 struct _GstExifWriter
224 GstByteWriter tagwriter;
225 GstByteWriter datawriter;
231 struct _GstExifReader
238 /* tags waiting for their complementary tags */
239 GSList *pending_tags;
242 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (aperture_value);
243 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (contrast);
244 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (exposure_program);
245 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (exposure_mode);
246 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (flash);
247 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (gain_control);
248 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (geo_coordinate);
249 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (geo_direction);
250 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (geo_elevation);
251 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (metering_mode);
252 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (orientation);
253 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (saturation);
254 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (scene_capture_type);
255 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (scene_type);
256 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (sensitivity_type);
257 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (sharpness);
258 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (shutter_speed);
259 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (source);
260 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (speed);
261 EXIF_SERIALIZATION_DESERIALIZATION_FUNC (white_balance);
263 EXIF_DESERIALIZATION_FUNC (resolution);
264 EXIF_DESERIALIZATION_FUNC (add_to_pending_tags);
266 /* FIXME copyright tag has a weird "artist\0editor\0" format that is
269 /* exif tag numbers */
270 #define EXIF_TAG_GPS_LATITUDE_REF 0x1
271 #define EXIF_TAG_GPS_LATITUDE 0x2
272 #define EXIF_TAG_GPS_LONGITUDE_REF 0x3
273 #define EXIF_TAG_GPS_LONGITUDE 0x4
274 #define EXIF_TAG_GPS_ALTITUDE_REF 0x5
275 #define EXIF_TAG_GPS_ALTITUDE 0x6
276 #define EXIF_TAG_GPS_SPEED_REF 0xC
277 #define EXIF_TAG_GPS_SPEED 0xD
278 #define EXIF_TAG_GPS_TRACK_REF 0xE
279 #define EXIF_TAG_GPS_TRACK 0xF
280 #define EXIF_TAG_GPS_IMAGE_DIRECTION_REF 0x10
281 #define EXIF_TAG_GPS_IMAGE_DIRECTION 0x11
282 #define EXIF_TAG_GPS_HORIZONTAL_POSITIONING_ERROR 0x1F
283 #define EXIF_TAG_IMAGE_DESCRIPTION 0x10E
284 #define EXIF_TAG_MAKE 0x10F
285 #define EXIF_TAG_MODEL 0x110
286 #define EXIF_TAG_ORIENTATION 0x112
287 #define EXIF_TAG_XRESOLUTION 0x11A
288 #define EXIF_TAG_YRESOLUTION 0x11B
289 #define EXIF_TAG_RESOLUTION_UNIT 0x128
290 #define EXIF_TAG_SOFTWARE 0x131
291 #define EXIF_TAG_DATE_TIME 0x132
292 #define EXIF_TAG_ARTIST 0x13B
293 #define EXIF_TAG_COPYRIGHT 0x8298
294 #define EXIF_TAG_EXPOSURE_TIME 0x829A
295 #define EXIF_TAG_F_NUMBER 0x829D
296 #define EXIF_TAG_EXPOSURE_PROGRAM 0x8822
297 #define EXIF_TAG_PHOTOGRAPHIC_SENSITIVITY 0x8827
298 #define EXIF_TAG_SENSITIVITY_TYPE 0x8830
299 #define EXIF_TAG_ISO_SPEED 0x8833
300 #define EXIF_TAG_DATE_TIME_ORIGINAL 0x9003
301 #define EXIF_TAG_DATE_TIME_DIGITIZED 0x9004
302 #define EXIF_TAG_SHUTTER_SPEED_VALUE 0x9201
303 #define EXIF_TAG_APERTURE_VALUE 0x9202
304 #define EXIF_TAG_EXPOSURE_BIAS 0x9204
305 #define EXIF_TAG_METERING_MODE 0x9207
306 #define EXIF_TAG_FLASH 0x9209
307 #define EXIF_TAG_FOCAL_LENGTH 0x920A
308 #define EXIF_TAG_MAKER_NOTE 0x927C
309 #define EXIF_TAG_FILE_SOURCE 0xA300
310 #define EXIF_TAG_SCENE_TYPE 0xA301
311 #define EXIF_TAG_EXPOSURE_MODE 0xA402
312 #define EXIF_TAG_WHITE_BALANCE 0xA403
313 #define EXIF_TAG_DIGITAL_ZOOM_RATIO 0xA404
314 #define EXIF_TAG_SCENE_CAPTURE_TYPE 0xA406
315 #define EXIF_TAG_GAIN_CONTROL 0xA407
316 #define EXIF_TAG_CONTRAST 0xA408
317 #define EXIF_TAG_SATURATION 0xA409
318 #define EXIF_TAG_SHARPNESS 0xA40A
320 /* IFD pointer tags */
321 #define EXIF_IFD_TAG 0x8769
322 #define EXIF_GPS_IFD_TAG 0x8825
325 #define EXIF_VERSION_TAG 0x9000
326 #define EXIF_FLASHPIX_VERSION_TAG 0xA000
328 /* useful macros for speed tag */
329 #define METERS_PER_SECOND_TO_KILOMETERS_PER_HOUR (3.6)
330 #define KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND (1/3.6)
331 #define MILES_PER_HOUR_TO_METERS_PER_SECOND (0.44704)
332 #define KNOTS_TO_METERS_PER_SECOND (0.514444)
335 * Should be kept in ascending id order
337 * {gst-tag, exif-tag, exig-type, complementary-exif-tag, serialization-func,
338 * deserialization-func}
340 static const GstExifTagMatch tag_map_ifd0[] = {
341 {GST_TAG_IMAGE_HORIZONTAL_PPI, EXIF_TAG_XRESOLUTION, EXIF_TYPE_RATIONAL,
342 0, NULL, deserialize_add_to_pending_tags},
343 {GST_TAG_IMAGE_VERTICAL_PPI, EXIF_TAG_YRESOLUTION, EXIF_TYPE_RATIONAL,
344 0, NULL, deserialize_add_to_pending_tags},
345 {NULL, EXIF_TAG_RESOLUTION_UNIT, EXIF_TYPE_SHORT, 0, NULL,
346 deserialize_resolution},
347 {GST_TAG_DESCRIPTION, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_TYPE_ASCII, 0, NULL,
349 {GST_TAG_DEVICE_MANUFACTURER, EXIF_TAG_MAKE, EXIF_TYPE_ASCII, 0, NULL, NULL},
350 {GST_TAG_DEVICE_MODEL, EXIF_TAG_MODEL, EXIF_TYPE_ASCII, 0, NULL, NULL},
351 {GST_TAG_IMAGE_ORIENTATION, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, 0,
352 serialize_orientation,
353 deserialize_orientation},
354 {GST_TAG_APPLICATION_NAME, EXIF_TAG_SOFTWARE, EXIF_TYPE_ASCII, 0, NULL, NULL},
355 {GST_TAG_DATE_TIME, EXIF_TAG_DATE_TIME, EXIF_TYPE_ASCII, 0, NULL, NULL},
356 {GST_TAG_ARTIST, EXIF_TAG_ARTIST, EXIF_TYPE_ASCII, 0, NULL, NULL},
357 {GST_TAG_COPYRIGHT, EXIF_TAG_COPYRIGHT, EXIF_TYPE_ASCII, 0, NULL, NULL},
358 {NULL, EXIF_IFD_TAG, EXIF_TYPE_LONG, 0, NULL, NULL},
359 {NULL, EXIF_GPS_IFD_TAG, EXIF_TYPE_LONG, 0, NULL, NULL},
360 {NULL, 0, 0, 0, NULL, NULL}
363 static const GstExifTagMatch tag_map_exif[] = {
364 {GST_TAG_CAPTURING_SHUTTER_SPEED, EXIF_TAG_EXPOSURE_TIME, EXIF_TYPE_RATIONAL,
367 {GST_TAG_CAPTURING_FOCAL_RATIO, EXIF_TAG_F_NUMBER, EXIF_TYPE_RATIONAL, 0,
370 {GST_TAG_CAPTURING_EXPOSURE_PROGRAM, EXIF_TAG_EXPOSURE_PROGRAM,
371 EXIF_TYPE_SHORT, 0, serialize_exposure_program,
372 deserialize_exposure_program},
374 /* don't need the serializer as we always write the iso speed alone */
375 {GST_TAG_CAPTURING_ISO_SPEED, EXIF_TAG_PHOTOGRAPHIC_SENSITIVITY,
376 EXIF_TYPE_SHORT, 0, NULL,
377 deserialize_add_to_pending_tags},
379 {GST_TAG_CAPTURING_ISO_SPEED, EXIF_TAG_SENSITIVITY_TYPE, EXIF_TYPE_SHORT, 0,
380 serialize_sensitivity_type, deserialize_sensitivity_type},
381 {GST_TAG_CAPTURING_ISO_SPEED, EXIF_TAG_ISO_SPEED, EXIF_TYPE_LONG, 0, NULL,
383 {NULL, EXIF_VERSION_TAG, EXIF_TYPE_UNDEFINED, 0, NULL, NULL},
384 {GST_TAG_DATE_TIME, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_TYPE_ASCII, 0, NULL,
386 {GST_TAG_CAPTURING_SHUTTER_SPEED, EXIF_TAG_SHUTTER_SPEED_VALUE,
387 EXIF_TYPE_SRATIONAL, 0,
388 serialize_shutter_speed, deserialize_shutter_speed},
389 {GST_TAG_CAPTURING_FOCAL_RATIO, EXIF_TAG_APERTURE_VALUE, EXIF_TYPE_RATIONAL,
391 serialize_aperture_value, deserialize_aperture_value},
392 {GST_TAG_CAPTURING_EXPOSURE_COMPENSATION, EXIF_TAG_EXPOSURE_BIAS,
393 EXIF_TYPE_SRATIONAL, 0, NULL, NULL},
394 {GST_TAG_CAPTURING_METERING_MODE, EXIF_TAG_METERING_MODE, EXIF_TYPE_SHORT, 0,
395 serialize_metering_mode, deserialize_metering_mode},
396 {GST_TAG_CAPTURING_FLASH_FIRED, EXIF_TAG_FLASH, EXIF_TYPE_SHORT, 0,
397 serialize_flash, deserialize_flash},
398 {GST_TAG_CAPTURING_FOCAL_LENGTH, EXIF_TAG_FOCAL_LENGTH, EXIF_TYPE_RATIONAL, 0,
400 {GST_TAG_APPLICATION_DATA, EXIF_TAG_MAKER_NOTE, EXIF_TYPE_UNDEFINED, 0, NULL,
402 {NULL, EXIF_FLASHPIX_VERSION_TAG, EXIF_TYPE_UNDEFINED, 0, NULL, NULL},
403 {GST_TAG_CAPTURING_SOURCE, EXIF_TAG_FILE_SOURCE, EXIF_TYPE_UNDEFINED,
404 0, serialize_source, deserialize_source},
405 {GST_TAG_CAPTURING_SOURCE, EXIF_TAG_SCENE_TYPE, EXIF_TYPE_UNDEFINED,
406 0, serialize_scene_type, deserialize_scene_type},
407 {GST_TAG_CAPTURING_EXPOSURE_MODE, EXIF_TAG_EXPOSURE_MODE, EXIF_TYPE_SHORT,
408 0, serialize_exposure_mode, deserialize_exposure_mode},
409 {GST_TAG_CAPTURING_WHITE_BALANCE, EXIF_TAG_WHITE_BALANCE, EXIF_TYPE_SHORT,
410 0, serialize_white_balance, deserialize_white_balance},
411 {GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, EXIF_TAG_DIGITAL_ZOOM_RATIO,
412 EXIF_TYPE_RATIONAL, 0, NULL,
414 {GST_TAG_CAPTURING_SCENE_CAPTURE_TYPE, EXIF_TAG_SCENE_CAPTURE_TYPE,
415 EXIF_TYPE_SHORT, 0, serialize_scene_capture_type,
416 deserialize_scene_capture_type},
417 {GST_TAG_CAPTURING_GAIN_ADJUSTMENT, EXIF_TAG_GAIN_CONTROL,
418 EXIF_TYPE_SHORT, 0, serialize_gain_control,
419 deserialize_gain_control},
420 {GST_TAG_CAPTURING_CONTRAST, EXIF_TAG_CONTRAST, EXIF_TYPE_SHORT, 0,
421 serialize_contrast, deserialize_contrast},
422 {GST_TAG_CAPTURING_SATURATION, EXIF_TAG_SATURATION, EXIF_TYPE_SHORT, 0,
423 serialize_saturation, deserialize_saturation},
424 {GST_TAG_CAPTURING_SHARPNESS, EXIF_TAG_SHARPNESS, EXIF_TYPE_SHORT, 0,
425 serialize_sharpness, deserialize_sharpness},
426 {NULL, 0, 0, 0, NULL, NULL}
429 static const GstExifTagMatch tag_map_gps[] = {
430 {GST_TAG_GEO_LOCATION_LATITUDE, EXIF_TAG_GPS_LATITUDE, EXIF_TYPE_RATIONAL,
431 EXIF_TAG_GPS_LATITUDE_REF,
432 serialize_geo_coordinate, deserialize_geo_coordinate},
433 {GST_TAG_GEO_LOCATION_LONGITUDE, EXIF_TAG_GPS_LONGITUDE, EXIF_TYPE_RATIONAL,
434 EXIF_TAG_GPS_LONGITUDE_REF,
435 serialize_geo_coordinate, deserialize_geo_coordinate},
436 {GST_TAG_GEO_LOCATION_ELEVATION, EXIF_TAG_GPS_ALTITUDE, EXIF_TYPE_RATIONAL,
437 EXIF_TAG_GPS_ALTITUDE_REF,
438 serialize_geo_elevation, deserialize_geo_elevation},
439 {GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, EXIF_TAG_GPS_SPEED, EXIF_TYPE_RATIONAL,
440 EXIF_TAG_GPS_SPEED_REF,
441 serialize_speed, deserialize_speed},
442 {GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION, EXIF_TAG_GPS_TRACK,
443 EXIF_TYPE_RATIONAL, EXIF_TAG_GPS_TRACK_REF,
444 serialize_geo_direction, deserialize_geo_direction},
445 {GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION, EXIF_TAG_GPS_IMAGE_DIRECTION,
446 EXIF_TYPE_RATIONAL, EXIF_TAG_GPS_IMAGE_DIRECTION_REF,
447 serialize_geo_direction, deserialize_geo_direction},
448 {GST_TAG_GEO_LOCATION_HORIZONTAL_ERROR,
449 EXIF_TAG_GPS_HORIZONTAL_POSITIONING_ERROR,
450 EXIF_TYPE_RATIONAL, 0, NULL, NULL},
451 {NULL, 0, 0, 0, NULL, NULL}
454 /* GstExifReader functions */
456 gst_exif_reader_init (GstExifReader * reader, gint byte_order,
457 GstBuffer * buf, guint32 base_offset)
461 reader->taglist = gst_tag_list_new_empty ();
462 reader->buffer = buf;
463 reader->base_offset = base_offset;
464 reader->byte_order = byte_order;
465 reader->pending_tags = NULL;
466 if (reader->byte_order != G_LITTLE_ENDIAN &&
467 reader->byte_order != G_BIG_ENDIAN) {
468 GST_WARNING ("Unexpected byte order %d, using system default: %d",
469 reader->byte_order, G_BYTE_ORDER);
470 reader->byte_order = G_BYTE_ORDER;
475 gst_exif_reader_add_pending_tag (GstExifReader * reader, GstExifTagData * data)
477 GstExifTagData *copy;
479 copy = g_slice_new (GstExifTagData);
480 memcpy (copy, data, sizeof (GstExifTagData));
482 reader->pending_tags = g_slist_prepend (reader->pending_tags, copy);
485 static GstExifTagData *
486 gst_exif_reader_get_pending_tag (GstExifReader * reader, gint tagid)
490 for (walker = reader->pending_tags; walker; walker = g_slist_next (walker)) {
491 GstExifTagData *data = (GstExifTagData *) walker->data;
492 if (data->tag == tagid)
500 gst_exif_reader_reset (GstExifReader * reader, gboolean return_taglist)
502 GstTagList *ret = NULL;
505 for (walker = reader->pending_tags; walker; walker = g_slist_next (walker)) {
506 GstExifTagData *data = (GstExifTagData *) walker->data;
508 g_slice_free (GstExifTagData, data);
510 g_slist_free (reader->pending_tags);
512 if (return_taglist) {
513 ret = reader->taglist;
514 reader->taglist = NULL;
517 if (reader->taglist) {
518 gst_tag_list_free (reader->taglist);
524 /* GstExifWriter functions */
527 gst_exif_writer_init (GstExifWriter * writer, gint byte_order)
531 gst_byte_writer_init (&writer->tagwriter);
532 gst_byte_writer_init (&writer->datawriter);
534 writer->byte_order = byte_order;
535 writer->tags_total = 0;
536 if (writer->byte_order != G_LITTLE_ENDIAN &&
537 writer->byte_order != G_BIG_ENDIAN) {
538 GST_WARNING ("Unexpected byte order %d, using system default: %d",
539 writer->byte_order, G_BYTE_ORDER);
540 writer->byte_order = G_BYTE_ORDER;
545 gst_exif_writer_reset_and_get_buffer (GstExifWriter * writer)
550 header = gst_byte_writer_reset_and_get_buffer (&writer->tagwriter);
551 data = gst_byte_writer_reset_and_get_buffer (&writer->datawriter);
553 return gst_buffer_join (header, data);
557 * Given the exif tag with the passed id, returns the map index of the tag
558 * corresponding to it. If use_complementary is true, then the complementary
559 * are also used in the search.
561 * Returns -1 if not found
564 exif_tag_map_find_reverse (guint16 exif_tag, const GstExifTagMatch * tag_map,
565 gboolean use_complementary)
569 for (i = 0; tag_map[i].exif_tag != 0; i++) {
570 if (exif_tag == tag_map[i].exif_tag || (use_complementary &&
571 exif_tag == tag_map[i].complementary_tag)) {
579 gst_tag_list_has_ifd_tags (const GstTagList * taglist,
580 const GstExifTagMatch * tag_map)
584 for (i = 0; tag_map[i].exif_tag != 0; i++) {
585 if (tag_map[i].gst_tag == NULL) {
586 if (tag_map[i].exif_tag == EXIF_GPS_IFD_TAG &&
587 gst_tag_list_has_ifd_tags (taglist, tag_map_gps))
589 if (tag_map[i].exif_tag == EXIF_IFD_TAG &&
590 gst_tag_list_has_ifd_tags (taglist, tag_map_exif))
595 if (gst_tag_list_get_value_index (taglist, tag_map[i].gst_tag, 0)) {
603 * Writes the tag entry.
605 * The tag entry is the tag id, the tag type,
606 * the count and the offset.
608 * The offset is the on the amount of data writen so far, as one
609 * can't predict the total bytes that the tag entries will take.
610 * This means those fields requires being updated later.
613 gst_exif_writer_write_tag_header (GstExifWriter * writer,
614 guint16 exif_tag, guint16 exif_type, guint32 count, guint32 offset,
617 GST_DEBUG ("Writing tag entry: id %x, type %u, count %u, offset %u",
618 exif_tag, exif_type, count, offset);
620 if (writer->byte_order == G_LITTLE_ENDIAN) {
621 gst_byte_writer_put_uint16_le (&writer->tagwriter, exif_tag);
622 gst_byte_writer_put_uint16_le (&writer->tagwriter, exif_type);
623 gst_byte_writer_put_uint32_le (&writer->tagwriter, count);
624 gst_byte_writer_put_uint32_le (&writer->tagwriter, offset);
625 } else if (writer->byte_order == G_BIG_ENDIAN) {
626 gst_byte_writer_put_uint16_be (&writer->tagwriter, exif_tag);
627 gst_byte_writer_put_uint16_be (&writer->tagwriter, exif_type);
628 gst_byte_writer_put_uint32_be (&writer->tagwriter, count);
630 gst_byte_writer_put_uint32_le (&writer->tagwriter, offset);
632 gst_byte_writer_put_uint32_be (&writer->tagwriter, offset);
635 g_assert_not_reached ();
638 writer->tags_total++;
642 gst_exif_writer_write_rational_data (GstExifWriter * writer, guint32 frac_n,
645 if (writer->byte_order == G_LITTLE_ENDIAN) {
646 gst_byte_writer_put_uint32_le (&writer->datawriter, frac_n);
647 gst_byte_writer_put_uint32_le (&writer->datawriter, frac_d);
649 gst_byte_writer_put_uint32_be (&writer->datawriter, frac_n);
650 gst_byte_writer_put_uint32_be (&writer->datawriter, frac_d);
655 gst_exif_writer_write_signed_rational_data (GstExifWriter * writer,
656 gint32 frac_n, gint32 frac_d)
658 if (writer->byte_order == G_LITTLE_ENDIAN) {
659 gst_byte_writer_put_int32_le (&writer->datawriter, frac_n);
660 gst_byte_writer_put_int32_le (&writer->datawriter, frac_d);
662 gst_byte_writer_put_int32_be (&writer->datawriter, frac_n);
663 gst_byte_writer_put_int32_be (&writer->datawriter, frac_d);
668 gst_exif_writer_write_rational_tag (GstExifWriter * writer,
669 guint16 tag, guint32 frac_n, guint32 frac_d)
671 guint32 offset = gst_byte_writer_get_size (&writer->datawriter);
673 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_RATIONAL,
676 gst_exif_writer_write_rational_data (writer, frac_n, frac_d);
680 gst_exif_writer_write_signed_rational_tag (GstExifWriter * writer,
681 guint16 tag, gint32 frac_n, gint32 frac_d)
683 guint32 offset = gst_byte_writer_get_size (&writer->datawriter);
685 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_SRATIONAL,
688 gst_exif_writer_write_signed_rational_data (writer, frac_n, frac_d);
692 gst_exif_writer_write_rational_tag_from_double (GstExifWriter * writer,
693 guint16 tag, gdouble value)
698 gst_util_double_to_fraction (value, &frac_n, &frac_d);
700 gst_exif_writer_write_rational_tag (writer, tag, frac_n, frac_d);
704 gst_exif_writer_write_signed_rational_tag_from_double (GstExifWriter * writer,
705 guint16 tag, gdouble value)
710 gst_util_double_to_fraction (value, &frac_n, &frac_d);
712 gst_exif_writer_write_signed_rational_tag (writer, tag, frac_n, frac_d);
716 gst_exif_writer_write_byte_tag (GstExifWriter * writer, guint16 tag,
721 GST_WRITE_UINT8 ((guint8 *) & offset, value);
722 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_BYTE,
727 gst_exif_writer_write_short_tag (GstExifWriter * writer, guint16 tag,
732 if (writer->byte_order == G_LITTLE_ENDIAN) {
733 GST_WRITE_UINT16_LE ((guint8 *) & offset, value);
735 GST_WRITE_UINT16_BE ((guint8 *) & offset, value);
738 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_SHORT,
743 gst_exif_writer_write_long_tag (GstExifWriter * writer, guint16 tag,
747 if (writer->byte_order == G_LITTLE_ENDIAN) {
748 GST_WRITE_UINT32_LE ((guint8 *) & offset, value);
750 GST_WRITE_UINT32_BE ((guint8 *) & offset, value);
753 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_LONG,
759 write_exif_undefined_tag (GstExifWriter * writer, guint16 tag,
760 const guint8 * data, gint size)
765 /* we only use the data offset here, later we add up the
766 * resulting tag headers offset and the base offset */
767 offset = gst_byte_writer_get_size (&writer->datawriter);
768 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_UNDEFINED,
769 size, offset, FALSE);
770 gst_byte_writer_put_data (&writer->datawriter, data, size);
772 /* small enough to go in the offset */
773 memcpy ((guint8 *) & offset, data, size);
774 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_UNDEFINED,
780 write_exif_ascii_tag (GstExifWriter * writer, guint16 tag, const gchar * str)
786 GError *error = NULL;
788 size = strlen (str) + 1;
791 g_convert (str, size, "latin1", "utf8", NULL, &ascii_size, &error);
794 GST_WARNING ("Failed to convert exif tag to ascii: 0x%x - %s. Error: %s",
795 tag, str, error->message);
796 g_error_free (error);
801 /* add the \0 at the end */
804 if (ascii_size > 4) {
805 /* we only use the data offset here, later we add up the
806 * resulting tag headers offset and the base offset */
807 offset = gst_byte_writer_get_size (&writer->datawriter);
808 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_ASCII,
809 ascii_size, offset, FALSE);
810 gst_byte_writer_put_string (&writer->datawriter, ascii_str);
812 /* small enough to go in the offset */
813 memcpy ((guint8 *) & offset, ascii_str, ascii_size);
814 gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_ASCII,
815 ascii_size, offset, TRUE);
822 write_exif_ascii_tag_from_taglist (GstExifWriter * writer,
823 const GstTagList * taglist, const GstExifTagMatch * exiftag)
826 gboolean cleanup = FALSE;
828 gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
831 /* FIXME support this by serializing them with a ','? */
832 GST_WARNING ("Multiple string tags not supported yet");
836 value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
838 /* do some conversion if needed */
839 switch (G_VALUE_TYPE (value)) {
841 str = (gchar *) g_value_get_string (value);
844 if (G_VALUE_TYPE (value) == GST_TYPE_DATE_TIME) {
845 GstDateTime *dt = (GstDateTime *) g_value_get_boxed (value);
848 GST_WARNING ("NULL datetime received");
852 str = g_strdup_printf ("%04d:%02d:%02d %02d:%02d:%02d",
853 gst_date_time_get_year (dt), gst_date_time_get_month (dt),
854 gst_date_time_get_day (dt), gst_date_time_get_hour (dt),
855 gst_date_time_get_minute (dt), gst_date_time_get_second (dt));
859 GST_WARNING ("Conversion from %s to ascii string not supported",
860 G_VALUE_TYPE_NAME (value));
868 write_exif_ascii_tag (writer, exiftag->exif_tag, str);
874 write_exif_undefined_tag_from_taglist (GstExifWriter * writer,
875 const GstTagList * taglist, const GstExifTagMatch * exiftag)
880 gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
881 GstBuffer *buf = NULL;
884 GST_WARNING ("Only the first item in the taglist will be serialized");
888 value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
890 /* do some conversion if needed */
891 switch (G_VALUE_TYPE (value)) {
893 data = (guint8 *) g_value_get_string (value);
894 size = strlen ((gchar *) data); /* no need to +1, undefined doesn't require it */
897 if (G_VALUE_TYPE (value) == GST_TYPE_BUFFER) {
898 buf = gst_value_get_buffer (value);
899 data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
901 GST_WARNING ("Conversion from %s to raw data not supported",
902 G_VALUE_TYPE_NAME (value));
908 write_exif_undefined_tag (writer, exiftag->exif_tag, data, size);
911 gst_buffer_unmap (buf, data, size);
915 write_exif_rational_tag_from_taglist (GstExifWriter * writer,
916 const GstTagList * taglist, const GstExifTagMatch * exiftag)
920 gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
923 GST_WARNING ("Only the first item in the taglist will be serialized");
927 value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
929 /* do some conversion if needed */
930 switch (G_VALUE_TYPE (value)) {
932 num = g_value_get_double (value);
933 gst_exif_writer_write_rational_tag_from_double (writer, exiftag->exif_tag,
937 if (G_VALUE_TYPE (value) == GST_TYPE_FRACTION) {
938 gst_exif_writer_write_rational_tag (writer, exiftag->exif_tag,
939 gst_value_get_fraction_numerator (value),
940 gst_value_get_fraction_denominator (value));
942 GST_WARNING ("Conversion from %s to rational not supported",
943 G_VALUE_TYPE_NAME (value));
950 write_exif_signed_rational_tag_from_taglist (GstExifWriter * writer,
951 const GstTagList * taglist, const GstExifTagMatch * exiftag)
955 gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
958 GST_WARNING ("Only the first item in the taglist will be serialized");
962 value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
964 /* do some conversion if needed */
965 switch (G_VALUE_TYPE (value)) {
967 num = g_value_get_double (value);
968 gst_exif_writer_write_signed_rational_tag_from_double (writer,
969 exiftag->exif_tag, num);
972 if (G_VALUE_TYPE (value) == GST_TYPE_FRACTION) {
973 gst_exif_writer_write_signed_rational_tag (writer, exiftag->exif_tag,
974 gst_value_get_fraction_numerator (value),
975 gst_value_get_fraction_denominator (value));
977 GST_WARNING ("Conversion from %s to signed rational not supported",
978 G_VALUE_TYPE_NAME (value));
985 write_exif_integer_tag_from_taglist (GstExifWriter * writer,
986 const GstTagList * taglist, const GstExifTagMatch * exiftag)
990 gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
993 GST_WARNING ("Only the first item in the taglist will be serialized");
997 value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
999 /* do some conversion if needed */
1000 switch (G_VALUE_TYPE (value)) {
1002 num = g_value_get_int (value);
1005 GST_WARNING ("Conversion from %s to int not supported",
1006 G_VALUE_TYPE_NAME (value));
1010 switch (exiftag->exif_type) {
1011 case EXIF_TYPE_LONG:
1012 gst_exif_writer_write_long_tag (writer, exiftag->exif_tag, num);
1014 case EXIF_TYPE_SHORT:
1015 gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, num);
1023 write_exif_tag_from_taglist (GstExifWriter * writer, const GstTagList * taglist,
1024 const GstExifTagMatch * exiftag)
1026 GST_DEBUG ("Writing tag %s", exiftag->gst_tag);
1028 /* check for special handling */
1029 if (exiftag->serialize) {
1030 exiftag->serialize (writer, taglist, exiftag);
1034 switch (exiftag->exif_type) {
1035 case EXIF_TYPE_ASCII:
1036 write_exif_ascii_tag_from_taglist (writer, taglist, exiftag);
1038 case EXIF_TYPE_UNDEFINED:
1039 write_exif_undefined_tag_from_taglist (writer, taglist, exiftag);
1041 case EXIF_TYPE_RATIONAL:
1042 write_exif_rational_tag_from_taglist (writer, taglist, exiftag);
1044 case EXIF_TYPE_SRATIONAL:
1045 write_exif_signed_rational_tag_from_taglist (writer, taglist, exiftag);
1047 case EXIF_TYPE_LONG:
1048 case EXIF_TYPE_SHORT:
1049 write_exif_integer_tag_from_taglist (writer, taglist, exiftag);
1052 GST_WARNING ("Unhandled tag type %d", exiftag->exif_type);
1057 tagdata_copy (GstExifTagData * to, const GstExifTagData * from)
1059 to->tag = from->tag;
1060 to->tag_type = from->tag_type;
1061 to->count = from->count;
1062 to->offset = from->offset;
1063 to->offset_as_data = from->offset_as_data;
1067 gst_exif_tag_rewrite_offsets (GstByteWriter * writer, gint byte_order,
1068 guint32 offset, gint num_tags, GstByteWriter * inner_ifds_data)
1070 GstByteReader *reader;
1072 guint16 aux = G_MAXUINT16;
1074 GST_LOG ("Rewriting tag entries offsets");
1076 reader = (GstByteReader *) writer;
1078 if (num_tags == -1) {
1079 if (byte_order == G_LITTLE_ENDIAN) {
1080 gst_byte_reader_get_uint16_le (reader, &aux);
1082 gst_byte_reader_get_uint16_be (reader, &aux);
1084 if (aux == G_MAXUINT16) {
1085 GST_WARNING ("Failed to read number of tags, won't rewrite offsets");
1088 num_tags = (gint) aux;
1091 g_return_if_fail (num_tags != -1);
1093 GST_DEBUG ("number of tags %d", num_tags);
1095 for (i = 0; i < num_tags; i++) {
1097 guint32 cur_offset = 0;
1102 g_assert (gst_byte_writer_get_pos (writer) <
1103 gst_byte_writer_get_size (writer));
1106 if (byte_order == G_LITTLE_ENDIAN) {
1107 if (!gst_byte_reader_get_uint16_le (reader, &tag_id))
1109 if (!gst_byte_reader_get_uint16_le (reader, &type))
1111 if (!gst_byte_reader_get_uint32_le (reader, &count))
1114 if (!gst_byte_reader_get_uint16_be (reader, &tag_id))
1116 if (!gst_byte_reader_get_uint16_be (reader, &type))
1118 if (!gst_byte_reader_get_uint32_be (reader, &count))
1122 GST_LOG ("Parsed tag %x of type %u and count %u", tag_id, type, count);
1125 case EXIF_TYPE_BYTE:
1126 case EXIF_TYPE_ASCII:
1127 case EXIF_TYPE_UNDEFINED:
1130 case EXIF_TYPE_SHORT:
1131 byte_size = count * 2; /* 2 bytes */
1133 case EXIF_TYPE_LONG:
1134 case EXIF_TYPE_SLONG:
1135 byte_size = count * 4; /* 4 bytes */
1137 case EXIF_TYPE_RATIONAL:
1138 case EXIF_TYPE_SRATIONAL:
1139 byte_size = count * 8; /* 8 bytes */
1142 g_assert_not_reached ();
1146 /* adjust the offset if needed */
1147 if (byte_size > 4 || tag_id == EXIF_GPS_IFD_TAG || tag_id == EXIF_IFD_TAG) {
1148 if (byte_order == G_LITTLE_ENDIAN) {
1149 if (gst_byte_reader_peek_uint32_le (reader, &cur_offset)) {
1150 gst_byte_writer_put_uint32_le (writer, cur_offset + offset);
1153 if (gst_byte_reader_peek_uint32_be (reader, &cur_offset)) {
1154 gst_byte_writer_put_uint32_be (writer, cur_offset + offset);
1157 GST_DEBUG ("Rewriting tag offset from %u to (%u + %u) %u",
1158 cur_offset, cur_offset, offset, cur_offset + offset);
1160 if ((tag_id == EXIF_GPS_IFD_TAG || tag_id == EXIF_IFD_TAG) &&
1161 inner_ifds_data != NULL) {
1162 /* needs special handling */
1163 if (!gst_byte_writer_set_pos (inner_ifds_data, cur_offset)) {
1164 GST_WARNING ("Failed to position writer to rewrite inner ifd "
1169 gst_exif_tag_rewrite_offsets (inner_ifds_data, byte_order, offset, -1,
1173 gst_byte_reader_skip (reader, 4);
1174 GST_DEBUG ("No need to rewrite tag offset");
1177 GST_LOG ("Done rewriting offsets");
1181 parse_exif_ascii_tag (GstExifReader * reader, const GstExifTagMatch * tag,
1182 guint32 count, guint32 offset, const guint8 * offset_as_data)
1187 guint32 real_offset;
1188 GError *error = NULL;
1194 if (offset < reader->base_offset) {
1195 GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
1196 reader->base_offset);
1200 real_offset = offset - reader->base_offset;
1202 data = gst_buffer_map (reader->buffer, &size, NULL, GST_MAP_READ);
1203 if (real_offset >= size) {
1204 GST_WARNING ("Invalid offset %u for buffer of size %" G_GSIZE_FORMAT
1205 ", not adding tag %s", real_offset, size, tag->gst_tag);
1206 gst_buffer_unmap (reader->buffer, data, size);
1210 str = g_strndup ((gchar *) (data + real_offset), count);
1211 gst_buffer_unmap (reader->buffer, data, size);
1213 str = g_strndup ((gchar *) offset_as_data, count);
1216 /* convert from ascii to utf8 */
1217 if (g_utf8_validate (str, -1, NULL)) {
1218 GST_DEBUG ("Exif string is already on utf8: %s", str);
1221 GST_DEBUG ("Exif string isn't utf8, trying to convert from latin1: %s",
1223 utfstr = g_convert (str, count, "utf8", "latin1", NULL, NULL, &error);
1226 GST_WARNING ("Skipping tag %d:%s. Failed to convert ascii string "
1227 "to utf8 : %s - %s", tag->exif_tag, tag->gst_tag, str,
1229 g_error_free (error);
1235 tagtype = gst_tag_get_type (tag->gst_tag);
1236 if (tagtype == GST_TYPE_DATE_TIME) {
1237 gint year = 0, month = 1, day = 1, hour = 0, minute = 0, second = 0;
1239 if (sscanf (utfstr, "%04d:%02d:%02d %02d:%02d:%02d", &year, &month, &day,
1240 &hour, &minute, &second) > 0) {
1243 d = gst_date_time_new_local_time (year, month, day, hour, minute, second);
1244 gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE,
1245 tag->gst_tag, d, NULL);
1246 gst_date_time_unref (d);
1248 GST_WARNING ("Failed to parse %s into a datetime tag", str);
1250 } else if (tagtype == G_TYPE_STRING) {
1251 gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE, tag->gst_tag,
1254 GST_WARNING ("No parsing function associated to %x(%s)", tag->exif_tag,
1261 parse_exif_long_tag (GstExifReader * reader, const GstExifTagMatch * tag,
1262 guint32 count, guint32 offset, const guint8 * offset_as_data)
1267 GST_WARNING ("Long tags with more than one value are not supported");
1271 tagtype = gst_tag_get_type (tag->gst_tag);
1272 if (tagtype == G_TYPE_INT) {
1273 gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE, tag->gst_tag,
1276 GST_WARNING ("No parsing function associated to %x(%s)", tag->exif_tag,
1283 parse_exif_undefined_tag (GstExifReader * reader, const GstExifTagMatch * tag,
1284 guint32 count, guint32 offset, const guint8 * offset_as_data)
1288 guint32 real_offset;
1294 if (offset < reader->base_offset) {
1295 GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
1296 reader->base_offset);
1300 real_offset = offset - reader->base_offset;
1302 bdata = gst_buffer_map (reader->buffer, &bsize, NULL, GST_MAP_READ);
1304 if (real_offset >= bsize) {
1305 GST_WARNING ("Invalid offset %u for buffer of size %" G_GSIZE_FORMAT
1306 ", not adding tag %s", real_offset, bsize, tag->gst_tag);
1307 gst_buffer_unmap (reader->buffer, bdata, bsize);
1311 /* +1 because it could be a string without the \0 */
1312 data = malloc (sizeof (guint8) * count + 1);
1313 memcpy (data, bdata + real_offset, count);
1316 gst_buffer_unmap (reader->buffer, bdata, bsize);
1318 data = malloc (sizeof (guint8) * count + 1);
1319 memcpy (data, (guint8 *) offset_as_data, count);
1323 tagtype = gst_tag_get_type (tag->gst_tag);
1324 if (tagtype == GST_TYPE_BUFFER) {
1327 buf = gst_buffer_new ();
1328 gst_buffer_take_memory (buf, -1,
1329 gst_memory_new_wrapped (0, data, g_free, count, 0, count));
1332 gst_tag_list_add (reader->taglist, GST_TAG_MERGE_APPEND, tag->gst_tag,
1335 gst_buffer_unref (buf);
1336 } else if (tagtype == G_TYPE_STRING) {
1337 gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE, tag->gst_tag,
1340 GST_WARNING ("No parsing function associated to %x(%s)", tag->exif_tag,
1347 exif_reader_read_rational_tag (GstExifReader * exif_reader,
1348 guint32 count, guint32 offset, gboolean is_signed,
1349 gint32 * _frac_n, gint32 * _frac_d)
1351 GstByteReader data_reader;
1352 guint32 real_offset;
1359 GST_WARNING ("Rationals with multiple entries are not supported");
1361 if (offset < exif_reader->base_offset) {
1362 GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
1363 exif_reader->base_offset);
1367 real_offset = offset - exif_reader->base_offset;
1369 data = gst_buffer_map (exif_reader->buffer, &size, NULL, GST_MAP_READ);
1371 if (real_offset >= size) {
1372 GST_WARNING ("Invalid offset %u for buffer of size %" G_GSIZE_FORMAT,
1377 gst_byte_reader_init (&data_reader, data, size);
1378 if (!gst_byte_reader_set_pos (&data_reader, real_offset))
1382 guint32 aux_n = 0, aux_d = 0;
1383 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
1384 if (!gst_byte_reader_get_uint32_le (&data_reader, &aux_n) ||
1385 !gst_byte_reader_get_uint32_le (&data_reader, &aux_d))
1388 if (!gst_byte_reader_get_uint32_be (&data_reader, &aux_n) ||
1389 !gst_byte_reader_get_uint32_be (&data_reader, &aux_d))
1392 frac_n = (gint32) aux_n;
1393 frac_d = (gint32) aux_d;
1395 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
1396 if (!gst_byte_reader_get_int32_le (&data_reader, &frac_n) ||
1397 !gst_byte_reader_get_int32_le (&data_reader, &frac_d))
1400 if (!gst_byte_reader_get_int32_be (&data_reader, &frac_n) ||
1401 !gst_byte_reader_get_int32_be (&data_reader, &frac_d))
1411 gst_buffer_unmap (exif_reader->buffer, data, size);
1416 GST_WARNING ("Failed to read from byte reader. (Buffer too short?)");
1417 gst_buffer_unmap (exif_reader->buffer, data, size);
1422 parse_exif_rational_tag (GstExifReader * exif_reader,
1423 const gchar * gst_tag, guint32 count, guint32 offset, gdouble multiplier,
1431 GST_DEBUG ("Reading fraction for tag %s...", gst_tag);
1432 if (!exif_reader_read_rational_tag (exif_reader, count, offset, is_signed,
1435 GST_DEBUG ("Read fraction for tag %s: %d/%d", gst_tag, frac_n, frac_d);
1437 type = gst_tag_get_type (gst_tag);
1440 gst_util_fraction_to_double (frac_n, frac_d, &value);
1441 value *= multiplier;
1442 GST_DEBUG ("Adding %s tag: %lf", gst_tag, value);
1443 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, gst_tag,
1447 if (type == GST_TYPE_FRACTION) {
1448 GValue fraction = { 0 };
1450 g_value_init (&fraction, GST_TYPE_FRACTION);
1451 gst_value_set_fraction (&fraction, frac_n * multiplier, frac_d);
1452 gst_tag_list_add_value (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
1453 gst_tag, &fraction);
1454 g_value_unset (&fraction);
1456 GST_WARNING ("Can't convert from fraction into %s", g_type_name (type));
1463 write_exif_ifd (const GstTagList * taglist, gboolean byte_order,
1464 guint32 base_offset, const GstExifTagMatch * tag_map)
1466 GstExifWriter writer;
1469 GST_DEBUG ("Formatting taglist %p as exif buffer. Byte order: %d, "
1470 "base_offset: %u", taglist, byte_order, base_offset);
1472 g_assert (byte_order == G_LITTLE_ENDIAN || byte_order == G_BIG_ENDIAN);
1474 if (!gst_tag_list_has_ifd_tags (taglist, tag_map)) {
1475 GST_DEBUG ("No tags for this ifd");
1479 gst_exif_writer_init (&writer, byte_order);
1481 /* write tag number as 0 */
1482 gst_byte_writer_put_uint16_le (&writer.tagwriter, 0);
1484 /* write both tag headers and data
1485 * in ascending id order */
1487 for (i = 0; tag_map[i].exif_tag != 0; i++) {
1489 /* special cases have NULL gst tag */
1490 if (tag_map[i].gst_tag == NULL) {
1491 GstBuffer *inner_ifd = NULL;
1492 const GstExifTagMatch *inner_tag_map = NULL;
1494 GST_LOG ("Inner ifd tag: %x", tag_map[i].exif_tag);
1496 if (tag_map[i].exif_tag == EXIF_GPS_IFD_TAG) {
1497 inner_tag_map = tag_map_gps;
1498 } else if (tag_map[i].exif_tag == EXIF_IFD_TAG) {
1499 inner_tag_map = tag_map_exif;
1500 } else if (tag_map[i].exif_tag == EXIF_VERSION_TAG) {
1501 /* special case where we write the exif version */
1502 write_exif_undefined_tag (&writer, EXIF_VERSION_TAG, (guint8 *) "0230",
1504 } else if (tag_map[i].exif_tag == EXIF_FLASHPIX_VERSION_TAG) {
1505 /* special case where we write the flashpix version */
1506 write_exif_undefined_tag (&writer, EXIF_FLASHPIX_VERSION_TAG,
1507 (guint8 *) "0100", 4);
1510 if (inner_tag_map) {
1511 /* base offset and tagheader size are added when rewriting offset */
1512 inner_ifd = write_exif_ifd (taglist, byte_order,
1513 gst_byte_writer_get_size (&writer.datawriter), inner_tag_map);
1520 GST_DEBUG ("Adding inner ifd: %x", tag_map[i].exif_tag);
1521 gst_exif_writer_write_tag_header (&writer, tag_map[i].exif_tag,
1523 gst_byte_writer_get_size (&writer.datawriter), FALSE);
1525 data = gst_buffer_map (inner_ifd, &size, NULL, GST_MAP_READ);
1526 gst_byte_writer_put_data (&writer.datawriter, data, size);
1527 gst_buffer_unmap (inner_ifd, data, size);
1528 gst_buffer_unref (inner_ifd);
1533 GST_LOG ("Checking tag %s", tag_map[i].gst_tag);
1534 if (gst_tag_list_get_value_index (taglist, tag_map[i].gst_tag, 0) == NULL)
1537 write_exif_tag_from_taglist (&writer, taglist, &tag_map[i]);
1540 /* Add the next IFD offset, we just set it to 0 because
1541 * there is no easy way to predict what it is going to be.
1542 * The user might rewrite the value if needed */
1543 gst_byte_writer_put_uint32_le (&writer.tagwriter, 0);
1545 /* write the number of tags */
1546 gst_byte_writer_set_pos (&writer.tagwriter, 0);
1547 if (writer.byte_order == G_LITTLE_ENDIAN)
1548 gst_byte_writer_put_uint16_le (&writer.tagwriter, writer.tags_total);
1550 gst_byte_writer_put_uint16_be (&writer.tagwriter, writer.tags_total);
1552 GST_DEBUG ("Number of tags rewritten to %d", writer.tags_total);
1554 /* now that we know the tag headers size, we can add the offsets */
1555 gst_exif_tag_rewrite_offsets (&writer.tagwriter, writer.byte_order,
1556 base_offset + gst_byte_writer_get_size (&writer.tagwriter),
1557 writer.tags_total, &writer.datawriter);
1559 return gst_exif_writer_reset_and_get_buffer (&writer);
1563 parse_exif_tag_header (GstByteReader * reader, gint byte_order,
1564 GstExifTagData * _tagdata)
1566 g_assert (_tagdata);
1568 /* read the fields */
1569 if (byte_order == G_LITTLE_ENDIAN) {
1570 if (!gst_byte_reader_get_uint16_le (reader, &_tagdata->tag) ||
1571 !gst_byte_reader_get_uint16_le (reader, &_tagdata->tag_type) ||
1572 !gst_byte_reader_get_uint32_le (reader, &_tagdata->count) ||
1573 !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) {
1576 _tagdata->offset = GST_READ_UINT32_LE (_tagdata->offset_as_data);
1578 if (!gst_byte_reader_get_uint16_be (reader, &_tagdata->tag) ||
1579 !gst_byte_reader_get_uint16_be (reader, &_tagdata->tag_type) ||
1580 !gst_byte_reader_get_uint32_be (reader, &_tagdata->count) ||
1581 !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) {
1584 _tagdata->offset = GST_READ_UINT32_BE (_tagdata->offset_as_data);
1591 parse_exif_ifd (GstExifReader * exif_reader, gint buf_offset,
1592 const GstExifTagMatch * tag_map)
1594 GstByteReader reader;
1595 guint16 entries = 0;
1600 g_return_val_if_fail (exif_reader->byte_order == G_LITTLE_ENDIAN
1601 || exif_reader->byte_order == G_BIG_ENDIAN, FALSE);
1603 data = gst_buffer_map (exif_reader->buffer, &size, NULL, GST_MAP_READ);
1605 gst_byte_reader_init (&reader, data, size);
1606 if (!gst_byte_reader_set_pos (&reader, buf_offset))
1607 goto invalid_offset;
1609 /* read the IFD entries number */
1610 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
1611 if (!gst_byte_reader_get_uint16_le (&reader, &entries))
1614 if (!gst_byte_reader_get_uint16_be (&reader, &entries))
1617 GST_DEBUG ("Read number of entries: %u", entries);
1619 /* iterate over the buffer and find the tags and stuff */
1620 for (i = 0; i < entries; i++) {
1621 GstExifTagData tagdata;
1624 GST_LOG ("Reading entry: %u", i);
1626 if (!parse_exif_tag_header (&reader, exif_reader->byte_order, &tagdata))
1629 GST_DEBUG ("Parsed tag: id 0x%x, type %u, count %u, offset %u (0x%x)"
1630 ", buf size: %u", tagdata.tag, tagdata.tag_type, tagdata.count,
1631 tagdata.offset, tagdata.offset, gst_byte_reader_get_size (&reader));
1633 map_index = exif_tag_map_find_reverse (tagdata.tag, tag_map, TRUE);
1634 if (map_index == -1) {
1635 GST_WARNING ("Unmapped exif tag: 0x%x", tagdata.tag);
1640 * inner ifd tags handling, errors processing those are being ignored
1641 * and we try to continue the parsing
1643 if (tagdata.tag == EXIF_GPS_IFD_TAG) {
1644 parse_exif_ifd (exif_reader,
1645 tagdata.offset - exif_reader->base_offset, tag_map_gps);
1649 if (tagdata.tag == EXIF_IFD_TAG) {
1650 parse_exif_ifd (exif_reader,
1651 tagdata.offset - exif_reader->base_offset, tag_map_exif);
1655 if (tagdata.tag == EXIF_VERSION_TAG ||
1656 tagdata.tag == EXIF_FLASHPIX_VERSION_TAG) {
1661 /* tags that need specialized deserialization */
1662 if (tag_map[map_index].deserialize) {
1663 i += tag_map[map_index].deserialize (exif_reader, &reader,
1664 &tag_map[map_index], &tagdata);
1668 switch (tagdata.tag_type) {
1669 case EXIF_TYPE_ASCII:
1670 parse_exif_ascii_tag (exif_reader, &tag_map[map_index],
1671 tagdata.count, tagdata.offset, tagdata.offset_as_data);
1673 case EXIF_TYPE_RATIONAL:
1674 parse_exif_rational_tag (exif_reader, tag_map[map_index].gst_tag,
1675 tagdata.count, tagdata.offset, 1, FALSE);
1677 case EXIF_TYPE_SRATIONAL:
1678 parse_exif_rational_tag (exif_reader, tag_map[map_index].gst_tag,
1679 tagdata.count, tagdata.offset, 1, TRUE);
1681 case EXIF_TYPE_UNDEFINED:
1682 parse_exif_undefined_tag (exif_reader, &tag_map[map_index],
1683 tagdata.count, tagdata.offset, tagdata.offset_as_data);
1684 case EXIF_TYPE_LONG:
1685 parse_exif_long_tag (exif_reader, &tag_map[map_index],
1686 tagdata.count, tagdata.offset, tagdata.offset_as_data);
1689 GST_WARNING ("Unhandled tag type: %u", tagdata.tag_type);
1694 /* check if the pending tags have something that can still be added */
1697 GstExifTagData *data;
1699 for (walker = exif_reader->pending_tags; walker;
1700 walker = g_slist_next (walker)) {
1701 data = (GstExifTagData *) walker->data;
1702 switch (data->tag) {
1703 case EXIF_TAG_XRESOLUTION:
1704 parse_exif_rational_tag (exif_reader, GST_TAG_IMAGE_HORIZONTAL_PPI,
1705 data->count, data->offset, 1, FALSE);
1707 case EXIF_TAG_YRESOLUTION:
1708 parse_exif_rational_tag (exif_reader, GST_TAG_IMAGE_VERTICAL_PPI,
1709 data->count, data->offset, 1, FALSE);
1717 gst_buffer_unmap (exif_reader->buffer, data, size);
1723 GST_WARNING ("Buffer offset invalid when parsing exif ifd");
1724 gst_buffer_unmap (exif_reader->buffer, data, size);
1729 GST_WARNING ("Failed to parse the exif ifd");
1730 gst_buffer_unmap (exif_reader->buffer, data, size);
1736 * gst_tag_list_to_exif_buffer:
1737 * @taglist: The taglist
1738 * @byte_order: byte order used in writing (G_LITTLE_ENDIAN or G_BIG_ENDIAN)
1739 * @base_offset: Offset from the tiff header first byte
1741 * Formats the tags in taglist on exif format. The resulting buffer contains
1742 * the tags IFD and is followed by the data pointed by the tag entries.
1744 * Returns: A GstBuffer containing the tag entries followed by the tag data
1749 gst_tag_list_to_exif_buffer (const GstTagList * taglist, gint byte_order,
1750 guint32 base_offset)
1752 return write_exif_ifd (taglist, byte_order, base_offset, tag_map_ifd0);
1756 * gst_tag_list_to_exif_buffer_with_tiff_header:
1757 * @taglist: The taglist
1759 * Formats the tags in taglist into exif structure, a tiff header
1760 * is put in the beginning of the buffer.
1762 * Returns: A GstBuffer containing the data
1767 gst_tag_list_to_exif_buffer_with_tiff_header (const GstTagList * taglist)
1770 GstByteWriter writer;
1774 ifd = gst_tag_list_to_exif_buffer (taglist, G_BYTE_ORDER, 8);
1776 GST_WARNING ("Failed to create exif buffer");
1780 data = gst_buffer_map (ifd, &size, NULL, GST_MAP_READ);
1782 size += TIFF_HEADER_SIZE;
1784 /* TODO what is the correct endianness here? */
1785 gst_byte_writer_init_with_size (&writer, size, FALSE);
1787 if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
1788 gst_byte_writer_put_uint16_le (&writer, TIFF_LITTLE_ENDIAN);
1789 gst_byte_writer_put_uint16_le (&writer, 42);
1790 gst_byte_writer_put_uint32_le (&writer, 8);
1792 gst_byte_writer_put_uint16_be (&writer, TIFF_BIG_ENDIAN);
1793 gst_byte_writer_put_uint16_be (&writer, 42);
1794 gst_byte_writer_put_uint32_be (&writer, 8);
1796 if (!gst_byte_writer_put_data (&writer, data, size)) {
1797 GST_WARNING ("Byte writer size mismatch");
1798 /* reaching here is a programming error because we should have a buffer
1800 g_assert_not_reached ();
1801 gst_buffer_unmap (ifd, data, size);
1802 gst_buffer_unref (ifd);
1803 gst_byte_writer_reset (&writer);
1806 gst_buffer_unmap (ifd, data, size);
1807 gst_buffer_unref (ifd);
1809 return gst_byte_writer_reset_and_get_buffer (&writer);
1813 * gst_tag_list_from_exif_buffer:
1814 * @buffer: The exif buffer
1815 * @byte_order: byte order of the data
1816 * @base_offset: Offset from the tiff header to this buffer
1818 * Parses the IFD and IFD tags data contained in the buffer and puts it
1819 * on a taglist. The base_offset is used to subtract from the offset in
1820 * the tag entries and be able to get the offset relative to the buffer
1823 * Returns: The parsed taglist
1828 gst_tag_list_from_exif_buffer (GstBuffer * buffer, gint byte_order,
1829 guint32 base_offset)
1831 GstExifReader reader;
1832 g_return_val_if_fail (byte_order == G_LITTLE_ENDIAN
1833 || byte_order == G_BIG_ENDIAN, NULL);
1835 gst_exif_reader_init (&reader, byte_order, buffer, base_offset);
1837 if (!parse_exif_ifd (&reader, 0, tag_map_ifd0))
1840 return gst_exif_reader_reset (&reader, TRUE);
1844 gst_exif_reader_reset (&reader, FALSE);
1845 GST_WARNING ("Failed to parse the exif buffer");
1851 * gst_tag_list_from_exif_buffer_with_tiff_header:
1852 * @buffer: The exif buffer
1854 * Parses the exif tags starting with a tiff header structure.
1856 * Returns: The taglist
1861 gst_tag_list_from_exif_buffer_with_tiff_header (GstBuffer * buffer)
1863 GstByteReader reader;
1864 guint16 fortytwo = 42;
1865 guint16 endianness = 0;
1867 GstTagList *taglist = NULL;
1868 GstBuffer *subbuffer;
1869 guint8 *data, *sdata;
1872 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1874 GST_LOG ("Parsing exif tags with tiff header of size %" G_GSIZE_FORMAT, size);
1876 gst_byte_reader_init (&reader, data, size);
1878 GST_LOG ("Parsing the tiff header");
1879 if (!gst_byte_reader_get_uint16_be (&reader, &endianness)) {
1880 goto byte_reader_fail;
1883 if (endianness == TIFF_LITTLE_ENDIAN) {
1884 if (!gst_byte_reader_get_uint16_le (&reader, &fortytwo) ||
1885 !gst_byte_reader_get_uint32_le (&reader, &offset))
1886 goto byte_reader_fail;
1887 } else if (endianness == TIFF_BIG_ENDIAN) {
1888 if (!gst_byte_reader_get_uint16_be (&reader, &fortytwo) ||
1889 !gst_byte_reader_get_uint32_be (&reader, &offset))
1890 goto byte_reader_fail;
1892 goto invalid_endianness;
1897 subbuffer = gst_buffer_new_and_alloc (size - (TIFF_HEADER_SIZE - 2));
1899 sdata = gst_buffer_map (subbuffer, &ssize, NULL, GST_MAP_WRITE);
1900 memcpy (sdata, data + TIFF_HEADER_SIZE, size - TIFF_HEADER_SIZE);
1901 gst_buffer_unmap (subbuffer, sdata, ssize);
1903 taglist = gst_tag_list_from_exif_buffer (subbuffer,
1904 endianness == TIFF_LITTLE_ENDIAN ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, 8);
1906 gst_buffer_unref (subbuffer);
1909 gst_buffer_unmap (buffer, data, size);
1915 GST_WARNING ("Failed to read values from buffer");
1920 GST_WARNING ("Invalid endianness number %u", endianness);
1925 GST_WARNING ("Invalid magic number %u, should be 42", fortytwo);
1930 /* special serialization functions */
1931 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (contrast,
1932 capturing_contrast);
1933 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (exposure_mode,
1934 capturing_exposure_mode);
1935 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (exposure_program,
1936 capturing_exposure_program);
1937 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (gain_control,
1938 capturing_gain_adjustment);
1939 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (metering_mode,
1940 capturing_metering_mode);
1941 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (orientation,
1943 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (saturation,
1944 capturing_saturation);
1945 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (scene_capture_type,
1946 capturing_scene_capture_type);
1947 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (sharpness,
1948 capturing_sharpness);
1949 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (source,
1951 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (white_balance,
1952 capturing_white_balance);
1955 serialize_geo_coordinate (GstExifWriter * writer, const GstTagList * taglist,
1956 const GstExifTagMatch * exiftag)
1965 latitude = exiftag->exif_tag == EXIF_TAG_GPS_LATITUDE; /* exif tag for latitude */
1966 if (!gst_tag_list_get_double (taglist, exiftag->gst_tag, &value)) {
1967 GST_WARNING ("Failed to get double from tag list for tag: %s",
1972 /* first write the Latitude or Longitude Ref */
1975 write_exif_ascii_tag (writer, exiftag->complementary_tag, "N");
1978 write_exif_ascii_tag (writer, exiftag->complementary_tag, "S");
1982 write_exif_ascii_tag (writer, exiftag->complementary_tag, "E");
1985 write_exif_ascii_tag (writer, exiftag->complementary_tag, "W");
1989 /* now write the degrees stuff */
1990 GST_LOG ("Converting geo location %lf to degrees", value);
1991 degrees = (gint) value;
1993 minutes = (gint) (value * 60);
1994 value = (value * 60) - minutes;
1995 seconds = (gint) (value * 60);
1996 GST_LOG ("Converted geo location to %d.%d'%d'' degrees", degrees,
1999 offset = gst_byte_writer_get_size (&writer->datawriter);
2000 gst_exif_writer_write_tag_header (writer, exiftag->exif_tag,
2001 EXIF_TYPE_RATIONAL, 3, offset, FALSE);
2002 gst_exif_writer_write_rational_data (writer, degrees, 1);
2003 gst_exif_writer_write_rational_data (writer, minutes, 1);
2004 gst_exif_writer_write_rational_data (writer, seconds, 1);
2008 deserialize_geo_coordinate (GstExifReader * exif_reader,
2009 GstByteReader * reader, const GstExifTagMatch * exiftag,
2010 GstExifTagData * tagdata)
2012 GstByteReader fractions_reader;
2014 GstExifTagData next_tagdata;
2016 /* for the conversion */
2017 guint32 degrees_n = 0;
2018 guint32 degrees_d = 1;
2019 guint32 minutes_n = 0;
2020 guint32 minutes_d = 1;
2021 guint32 seconds_n = 0;
2022 guint32 seconds_d = 1;
2026 guint8 *data = NULL;
2029 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2032 if (exiftag->complementary_tag != tagdata->tag) {
2033 /* First should come the 'Ref' tags */
2034 GST_WARNING ("Tag %d is not the 'Ref' tag for latitude nor longitude",
2039 if (tagdata->offset_as_data[0] == 'N' || tagdata->offset_as_data[0] == 'E') {
2041 } else if (tagdata->offset_as_data[0] == 'S'
2042 || tagdata->offset_as_data[0] == 'W') {
2045 GST_WARNING ("Invalid LatitudeRef or LongitudeRef %c",
2046 tagdata->offset_as_data[0]);
2050 /* now read the following tag that must be the latitude or longitude */
2051 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2052 if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
2055 if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
2059 if (exiftag->exif_tag != next_tagdata.tag) {
2060 GST_WARNING ("This is not a geo coordinate tag");
2064 /* read the remaining tag entry data */
2065 if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
2073 if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
2074 GST_WARNING ("Invalid type %d for geo coordinate (latitude/longitude)",
2075 next_tagdata.tag_type);
2078 if (next_tagdata.count != 3) {
2079 GST_WARNING ("Geo coordinate should use 3 fractions, we have %u",
2080 next_tagdata.count);
2084 data = gst_buffer_map (exif_reader->buffer, &size, NULL, GST_MAP_READ);
2086 /* now parse the fractions */
2087 gst_byte_reader_init (&fractions_reader, data, size);
2089 if (!gst_byte_reader_set_pos (&fractions_reader,
2090 next_tagdata.offset - exif_reader->base_offset))
2093 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2094 if (!gst_byte_reader_get_uint32_le (&fractions_reader, °rees_n) ||
2095 !gst_byte_reader_get_uint32_le (&fractions_reader, °rees_d) ||
2096 !gst_byte_reader_get_uint32_le (&fractions_reader, &minutes_n) ||
2097 !gst_byte_reader_get_uint32_le (&fractions_reader, &minutes_d) ||
2098 !gst_byte_reader_get_uint32_le (&fractions_reader, &seconds_n) ||
2099 !gst_byte_reader_get_uint32_le (&fractions_reader, &seconds_d))
2102 if (!gst_byte_reader_get_uint32_be (&fractions_reader, °rees_n) ||
2103 !gst_byte_reader_get_uint32_be (&fractions_reader, °rees_d) ||
2104 !gst_byte_reader_get_uint32_be (&fractions_reader, &minutes_n) ||
2105 !gst_byte_reader_get_uint32_be (&fractions_reader, &minutes_d) ||
2106 !gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_n) ||
2107 !gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_d))
2110 gst_buffer_unmap (exif_reader->buffer, data, size);
2112 GST_DEBUG ("Read degrees fraction for tag %s: %u/%u %u/%u %u/%u",
2113 exiftag->gst_tag, degrees_n, degrees_d, minutes_n, minutes_d,
2114 seconds_n, seconds_d);
2116 gst_util_fraction_to_double (degrees_n, degrees_d, °rees);
2117 gst_util_fraction_to_double (minutes_n, minutes_d, &minutes);
2118 gst_util_fraction_to_double (seconds_n, seconds_d, &seconds);
2120 minutes += seconds / 60;
2121 degrees += minutes / 60;
2122 degrees *= multiplier;
2124 GST_DEBUG ("Adding %s tag: %lf", exiftag->gst_tag, degrees);
2125 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
2126 exiftag->gst_tag, degrees, NULL);
2131 GST_WARNING ("Failed to read fields from buffer (too short?)");
2133 gst_buffer_unmap (exif_reader->buffer, data, size);
2139 serialize_geo_direction (GstExifWriter * writer, const GstTagList * taglist,
2140 const GstExifTagMatch * exiftag)
2144 if (!gst_tag_list_get_double (taglist, exiftag->gst_tag, &value)) {
2145 GST_WARNING ("Failed to get double from tag list for tag: %s",
2150 /* first write the direction ref */
2151 write_exif_ascii_tag (writer, exiftag->complementary_tag, "T");
2152 gst_exif_writer_write_rational_tag_from_double (writer,
2153 exiftag->exif_tag, value);
2157 deserialize_geo_direction (GstExifReader * exif_reader,
2158 GstByteReader * reader, const GstExifTagMatch * exiftag,
2159 GstExifTagData * tagdata)
2161 GstExifTagData next_tagdata = { 0, };
2164 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2167 if (exiftag->complementary_tag == tagdata->tag) {
2168 /* First should come the 'Ref' tags */
2169 if (tagdata->offset_as_data[0] == 'M') {
2170 GST_WARNING ("Magnetic direction is not supported");
2172 } else if (tagdata->offset_as_data[0] == 'T') {
2175 GST_WARNING ("Invalid Ref for direction or track %c",
2176 tagdata->offset_as_data[0]);
2180 GST_DEBUG ("No Direction Ref, using default=T");
2181 if (tagdata->tag == exiftag->exif_tag) {
2182 /* this is the main tag */
2183 tagdata_copy (&next_tagdata, tagdata);
2187 if (next_tagdata.tag == 0) {
2188 /* now read the following tag that must be the exif_tag */
2189 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2190 if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
2193 if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
2197 if (exiftag->exif_tag != next_tagdata.tag) {
2198 GST_WARNING ("Unexpected tag");
2202 /* read the remaining tag entry data */
2203 if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
2211 if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
2212 GST_WARNING ("Invalid type %d for 0x%x", next_tagdata.tag_type,
2216 if (next_tagdata.count != 1) {
2217 GST_WARNING ("0x%x tag must have a single fraction, we have %u",
2218 next_tagdata.tag_type, next_tagdata.count);
2222 parse_exif_rational_tag (exif_reader,
2223 exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, 1, FALSE);
2228 GST_WARNING ("Failed to read fields from buffer (too short?)");
2234 serialize_geo_elevation (GstExifWriter * writer, const GstTagList * taglist,
2235 const GstExifTagMatch * exiftag)
2239 if (!gst_tag_list_get_double (taglist, exiftag->gst_tag, &value)) {
2240 GST_WARNING ("Failed to get double from tag list for tag: %s",
2245 /* first write the Ref */
2246 gst_exif_writer_write_byte_tag (writer,
2247 exiftag->complementary_tag, value >= 0 ? 0 : 1);
2253 gst_exif_writer_write_rational_tag_from_double (writer,
2254 exiftag->exif_tag, value);
2258 deserialize_geo_elevation (GstExifReader * exif_reader,
2259 GstByteReader * reader, const GstExifTagMatch * exiftag,
2260 GstExifTagData * tagdata)
2262 GstExifTagData next_tagdata = { 0, };
2263 gint multiplier = 1;
2266 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2269 if (exiftag->complementary_tag == tagdata->tag) {
2270 if (tagdata->offset_as_data[0] == 0) {
2272 } else if (tagdata->offset_as_data[0] == 1) {
2275 GST_WARNING ("Invalid GPSAltitudeRef %u", tagdata->offset_as_data[0]);
2279 GST_DEBUG ("No GPSAltitudeRef, using default=0");
2280 if (tagdata->tag == exiftag->exif_tag) {
2281 tagdata_copy (&next_tagdata, tagdata);
2285 /* now read the following tag that must be the exif_tag */
2286 if (next_tagdata.tag == 0) {
2287 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2288 if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
2291 if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
2295 if (exiftag->exif_tag != next_tagdata.tag) {
2296 GST_WARNING ("Unexpected tag");
2300 /* read the remaining tag entry data */
2301 if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
2309 if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
2310 GST_WARNING ("Invalid type %d for 0x%x", next_tagdata.tag_type,
2314 if (next_tagdata.count != 1) {
2315 GST_WARNING ("0x%x tag must have a single fraction, we have %u",
2316 next_tagdata.tag_type, next_tagdata.count);
2320 parse_exif_rational_tag (exif_reader,
2321 exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, multiplier,
2327 GST_WARNING ("Failed to read fields from buffer (too short?)");
2333 serialize_speed (GstExifWriter * writer, const GstTagList * taglist,
2334 const GstExifTagMatch * exiftag)
2338 if (!gst_tag_list_get_double (taglist, exiftag->gst_tag, &value)) {
2339 GST_WARNING ("Failed to get double from tag list for tag: %s",
2344 /* first write the Ref */
2345 write_exif_ascii_tag (writer, exiftag->complementary_tag, "K");
2348 gst_exif_writer_write_rational_tag_from_double (writer,
2349 exiftag->exif_tag, value * METERS_PER_SECOND_TO_KILOMETERS_PER_HOUR);
2353 deserialize_speed (GstExifReader * exif_reader,
2354 GstByteReader * reader, const GstExifTagMatch * exiftag,
2355 GstExifTagData * tagdata)
2357 GstExifTagData next_tagdata = { 0, };
2358 gdouble multiplier = 1;
2361 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2364 if (exiftag->complementary_tag == tagdata->tag) {
2365 if (tagdata->offset_as_data[0] == 'K') {
2366 multiplier = KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND;
2367 } else if (tagdata->offset_as_data[0] == 'M') {
2368 multiplier = MILES_PER_HOUR_TO_METERS_PER_SECOND;
2369 } else if (tagdata->offset_as_data[0] == 'N') {
2370 multiplier = KNOTS_TO_METERS_PER_SECOND;
2372 GST_WARNING ("Invalid GPSSpeedRed %c", tagdata->offset_as_data[0]);
2376 GST_DEBUG ("No GPSSpeedRef, using default=K");
2377 multiplier = KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND;
2379 if (tagdata->tag == exiftag->exif_tag) {
2380 tagdata_copy (&next_tagdata, tagdata);
2384 /* now read the following tag that must be the exif_tag */
2385 if (next_tagdata.tag == 0) {
2386 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2387 if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
2390 if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
2394 if (exiftag->exif_tag != next_tagdata.tag) {
2395 GST_WARNING ("Unexpected tag");
2399 /* read the remaining tag entry data */
2400 if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
2409 if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
2410 GST_WARNING ("Invalid type %d for 0x%x", next_tagdata.tag_type,
2414 if (next_tagdata.count != 1) {
2415 GST_WARNING ("0x%x tag must have a single fraction, we have %u",
2416 next_tagdata.tag_type, next_tagdata.count);
2420 parse_exif_rational_tag (exif_reader,
2421 exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, multiplier,
2427 GST_WARNING ("Failed to read fields from buffer (too short?)");
2432 serialize_shutter_speed (GstExifWriter * writer, const GstTagList * taglist,
2433 const GstExifTagMatch * exiftag)
2435 const GValue *value = NULL;
2438 value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
2440 GST_WARNING ("Failed to get shutter speed from from tag list");
2443 gst_util_fraction_to_double (gst_value_get_fraction_numerator (value),
2444 gst_value_get_fraction_denominator (value), &num);
2449 num = -log (num) / M_LN2;
2453 gst_exif_writer_write_signed_rational_tag_from_double (writer,
2454 exiftag->exif_tag, num);
2458 deserialize_shutter_speed (GstExifReader * exif_reader,
2459 GstByteReader * reader, const GstExifTagMatch * exiftag,
2460 GstExifTagData * tagdata)
2462 gint32 frac_n, frac_d;
2464 GValue value = { 0 };
2466 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2469 if (!exif_reader_read_rational_tag (exif_reader, tagdata->count,
2470 tagdata->offset, TRUE, &frac_n, &frac_d))
2473 gst_util_fraction_to_double (frac_n, frac_d, &d);
2475 gst_util_double_to_fraction (d, &frac_n, &frac_d);
2477 g_value_init (&value, GST_TYPE_FRACTION);
2478 gst_value_set_fraction (&value, frac_n, frac_d);
2479 gst_tag_list_add_value (exif_reader->taglist, GST_TAG_MERGE_KEEP,
2480 exiftag->gst_tag, &value);
2481 g_value_unset (&value);
2487 serialize_aperture_value (GstExifWriter * writer, const GstTagList * taglist,
2488 const GstExifTagMatch * exiftag)
2492 if (!gst_tag_list_get_double_index (taglist, exiftag->gst_tag, 0, &num)) {
2493 GST_WARNING ("Failed to get focal ratio from from tag list");
2497 num = 2 * log2 (num);
2499 num = 2 * (log (num) / M_LN2);
2503 gst_exif_writer_write_rational_tag_from_double (writer,
2504 exiftag->exif_tag, num);
2508 deserialize_aperture_value (GstExifReader * exif_reader,
2509 GstByteReader * reader, const GstExifTagMatch * exiftag,
2510 GstExifTagData * tagdata)
2512 gint32 frac_n, frac_d;
2515 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2518 if (!exif_reader_read_rational_tag (exif_reader, tagdata->count,
2519 tagdata->offset, FALSE, &frac_n, &frac_d))
2522 gst_util_fraction_to_double (frac_n, frac_d, &d);
2525 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_KEEP,
2526 exiftag->gst_tag, d, NULL);
2532 serialize_sensitivity_type (GstExifWriter * writer, const GstTagList * taglist,
2533 const GstExifTagMatch * exiftag)
2535 /* we only support ISOSpeed as the sensitivity type (3) */
2536 gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, 3);
2540 deserialize_sensitivity_type (GstExifReader * exif_reader,
2541 GstByteReader * reader, const GstExifTagMatch * exiftag,
2542 GstExifTagData * tagdata)
2544 GstExifTagData *sensitivity = NULL;
2547 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2548 type_data = GST_READ_UINT16_LE (tagdata->offset_as_data);
2550 type_data = GST_READ_UINT16_BE (tagdata->offset_as_data);
2553 if (type_data != 3) {
2554 GST_WARNING ("We only support SensitivityType=3");
2558 /* check the pending tags for the PhotographicSensitivity tag */
2560 gst_exif_reader_get_pending_tag (exif_reader,
2561 EXIF_TAG_PHOTOGRAPHIC_SENSITIVITY);
2562 if (sensitivity == NULL) {
2563 GST_WARNING ("PhotographicSensitivity tag not found");
2567 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2570 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_KEEP,
2571 GST_TAG_CAPTURING_ISO_SPEED, sensitivity->offset_as_data, NULL);
2577 serialize_flash (GstExifWriter * writer, const GstTagList * taglist,
2578 const GstExifTagMatch * exiftag)
2580 gboolean flash_fired;
2581 const gchar *flash_mode;
2582 guint16 tagvalue = 0;
2584 if (!gst_tag_list_get_boolean_index (taglist, exiftag->gst_tag, 0,
2586 GST_WARNING ("Failed to get flash fired from from tag list");
2593 if (gst_tag_list_peek_string_index (taglist, GST_TAG_CAPTURING_FLASH_MODE, 0,
2596 if (strcmp (flash_mode, "auto") == 0) {
2598 } else if (strcmp (flash_mode, "always") == 0) {
2600 } else if (strcmp (flash_mode, "never") == 0) {
2604 tagvalue = tagvalue | (mode << 3);
2606 GST_DEBUG ("flash-mode not available");
2609 gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, tagvalue);
2613 deserialize_flash (GstExifReader * exif_reader,
2614 GstByteReader * reader, const GstExifTagMatch * exiftag,
2615 GstExifTagData * tagdata)
2619 const gchar *mode_str = NULL;
2621 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2624 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2625 value = GST_READ_UINT16_LE (tagdata->offset_as_data);
2627 value = GST_READ_UINT16_BE (tagdata->offset_as_data);
2630 /* check flash fired */
2632 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
2633 GST_TAG_CAPTURING_FLASH_FIRED, TRUE, NULL);
2635 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
2636 GST_TAG_CAPTURING_FLASH_FIRED, FALSE, NULL);
2639 mode = (value >> 3) & 0x3;
2641 mode_str = "always";
2642 } else if (mode == 2) {
2644 } else if (mode == 3) {
2649 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
2650 GST_TAG_CAPTURING_FLASH_MODE, mode_str, NULL);
2656 deserialize_resolution (GstExifReader * exif_reader,
2657 GstByteReader * reader, const GstExifTagMatch * exiftag,
2658 GstExifTagData * tagdata)
2660 GstExifTagData *xres = NULL;
2661 GstExifTagData *yres = NULL;
2665 if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2666 unit = GST_READ_UINT16_LE (tagdata->offset_as_data);
2668 unit = GST_READ_UINT16_BE (tagdata->offset_as_data);
2676 multiplier = 1 / 2.54;
2679 GST_WARNING ("Invalid resolution unit, ignoring PPI tags");
2683 xres = gst_exif_reader_get_pending_tag (exif_reader, EXIF_TAG_XRESOLUTION);
2685 parse_exif_rational_tag (exif_reader, GST_TAG_IMAGE_HORIZONTAL_PPI,
2686 xres->count, xres->offset, multiplier, FALSE);
2688 yres = gst_exif_reader_get_pending_tag (exif_reader, EXIF_TAG_YRESOLUTION);
2690 parse_exif_rational_tag (exif_reader, GST_TAG_IMAGE_VERTICAL_PPI,
2691 yres->count, yres->offset, multiplier, FALSE);
2698 serialize_scene_type (GstExifWriter * writer, const GstTagList * taglist,
2699 const GstExifTagMatch * exiftag)
2704 if (gst_tag_list_peek_string_index (taglist, GST_TAG_CAPTURING_SOURCE, 0,
2706 if (strcmp (str, "dsc") == 0) {
2712 write_exif_undefined_tag (writer, exiftag->exif_tag, &value, 1);
2716 deserialize_scene_type (GstExifReader * exif_reader,
2717 GstByteReader * reader, const GstExifTagMatch * exiftag,
2718 GstExifTagData * tagdata)
2722 GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2725 value = GST_READ_UINT8 (tagdata->offset_as_data);
2728 gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_KEEP,
2729 GST_TAG_CAPTURING_SOURCE, "dsc", NULL);
2736 deserialize_add_to_pending_tags (GstExifReader * exif_reader,
2737 GstByteReader * reader, const GstExifTagMatch * exiftag,
2738 GstExifTagData * tagdata)
2740 GST_LOG ("Adding %s tag in exif 0x%x to pending tags", exiftag->gst_tag,
2743 /* add it to the pending tags, as we can only parse it when we find the
2744 * SensitivityType tag */
2745 gst_exif_reader_add_pending_tag (exif_reader, tagdata);
2749 #undef EXIF_SERIALIZATION_FUNC
2750 #undef EXIF_DESERIALIZATION_FUNC
2751 #undef EXIF_SERIALIZATION_DESERIALIZATION_FUNC