Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / gst-libs / gst / tag / gstexiftag.c
1 /* GStreamer
2  * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
3  *
4  * gstexiftag.c: library for reading / modifying exif tags
5  *
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.
10  *
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.
15  *
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.
20  */
21
22 /**
23  * SECTION:gsttagexif
24  * @short_description: tag mappings and support functions for plugins
25  *                     dealing with exif tags
26  * @see_also: #GstTagList
27  *
28  * Contains utility function to parse #GstTagList<!-- -->s from exif
29  * buffers and to create exif buffers from #GstTagList<!-- -->s
30  *
31  * Note that next IFD fields on the created exif buffers are set to 0.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 #include <gst/gsttagsetter.h>
38 #include <gst/base/gstbytewriter.h>
39 #include "gsttageditingprivate.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <gst/math-compat.h>
45
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)
51
52 /* Exif tag types */
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
61
62 typedef struct _GstExifTagMatch GstExifTagMatch;
63 typedef struct _GstExifWriter GstExifWriter;
64 typedef struct _GstExifReader GstExifReader;
65 typedef struct _GstExifTagData GstExifTagData;
66
67 typedef void (*GstExifSerializationFunc) (GstExifWriter * writer,
68     const GstTagList * taglist, const GstExifTagMatch * exiftag);
69
70 /*
71  * Function used to deserialize tags that don't follow the usual
72  * deserialization conversions. Usually those that have 'Ref' complementary
73  * tags.
74  *
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:
79  *
80  * exif_reader: The #GstExifReader with the reading parameter and taglist for
81  * results.
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.
84  * the buffer start
85  * exiftag: The #GstExifTagMatch that contains this tag info
86  * tagdata: values from the already parsed tag
87  */
88 typedef gint (*GstExifDeserializationFunc) (GstExifReader * exif_reader,
89     GstByteReader * reader, const GstExifTagMatch * exiftag,
90     GstExifTagData * tagdata);
91
92 #define EXIF_SERIALIZATION_FUNC(name) \
93 static void serialize_ ## name (GstExifWriter * writer, \
94     const GstTagList * taglist, const GstExifTagMatch * exiftag)
95
96 #define EXIF_DESERIALIZATION_FUNC(name) \
97 static gint deserialize_ ## name (GstExifReader * exif_reader, \
98     GstByteReader * reader, const GstExifTagMatch * exiftag, \
99     GstExifTagData * tagdata)
100
101 #define EXIF_SERIALIZATION_DESERIALIZATION_FUNC(name) \
102   EXIF_SERIALIZATION_FUNC (name); \
103   EXIF_DESERIALIZATION_FUNC (name)
104
105 /*
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
109  */
110 #define EXIF_SERIALIZATION_MAP_STRING_TO_INT_FUNC(name,funcname) \
111 static void \
112 serialize_ ## name (GstExifWriter * writer, const GstTagList * taglist, \
113     const GstExifTagMatch * exiftag) \
114 { \
115   gchar *str = NULL; \
116   gint exif_value; \
117 \
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); \
120     return; \
121   } \
122 \
123   exif_value = __exif_tag_ ## funcname ## _to_exif_value (str); \
124   if (exif_value == -1) { \
125     g_free (str); \
126     return; \
127   } \
128   g_free (str); \
129 \
130   switch (exiftag->exif_type) { \
131     case EXIF_TYPE_SHORT: \
132       gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, exif_value); \
133       break; \
134     case EXIF_TYPE_LONG: \
135       gst_exif_writer_write_long_tag (writer, exiftag->exif_tag, exif_value); \
136       break; \
137     case EXIF_TYPE_UNDEFINED: \
138     { \
139         guint8 data = (guint8) exif_value; \
140         write_exif_undefined_tag (writer, exiftag->exif_tag, &data, 1); \
141     } \
142       break; \
143     default: \
144       g_assert_not_reached (); \
145       GST_WARNING ("Unmapped serialization for type %d", exiftag->exif_type); \
146       break; \
147    } \
148 }
149
150 #define EXIF_DESERIALIZATION_MAP_STRING_TO_INT_FUNC(name,funcname) \
151 static gint \
152 deserialize_ ## name (GstExifReader * exif_reader, \
153     GstByteReader * reader, const GstExifTagMatch * exiftag, \
154     GstExifTagData * tagdata) \
155 { \
156   const gchar *str = NULL; \
157   gint value; \
158 \
159   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag, \
160       exiftag->exif_tag); \
161 \
162   /* validate tag */ \
163   if (tagdata->count != 1) { \
164     GST_WARNING ("0x%X has unexpected count", tagdata->count); \
165     return 0; \
166   } \
167 \
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); \
171     } else { \
172       value = GST_READ_UINT16_BE (tagdata->offset_as_data); \
173     } \
174   } else if (tagdata->tag_type == EXIF_TYPE_UNDEFINED) { \
175     value = GST_READ_UINT8 (tagdata->offset_as_data); \
176   } else { \
177     GST_WARNING ("0x%X has unexpected type %d", exiftag->exif_tag, \
178         tagdata->tag_type); \
179     return 0; \
180   } \
181 \
182   str = __exif_tag_## funcname ## _from_exif_value (value); \
183   if (str == NULL) { \
184     GST_WARNING ("Invalid value for tag 0x%X: %d", tagdata->tag, value); \
185     return 0; \
186   } \
187   gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, \
188       exiftag->gst_tag, str, NULL); \
189 \
190   return 0; \
191 }
192
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);
196
197 struct _GstExifTagMatch
198 {
199   const gchar *gst_tag;
200   guint16 exif_tag;
201   guint16 exif_type;
202
203   /* for tags that need special handling */
204   guint16 complementary_tag;
205   GstExifSerializationFunc serialize;
206   GstExifDeserializationFunc deserialize;
207 };
208
209 struct _GstExifTagData
210 {
211   guint16 tag;
212   guint16 tag_type;
213   guint32 count;
214   guint32 offset;
215   const guint8 *offset_as_data;
216 };
217
218 /*
219  * Holds the info and variables necessary to write
220  * the exif tags properly
221  */
222 struct _GstExifWriter
223 {
224   GstByteWriter tagwriter;
225   GstByteWriter datawriter;
226
227   gint byte_order;
228   guint tags_total;
229 };
230
231 struct _GstExifReader
232 {
233   GstTagList *taglist;
234   const GstBuffer *buffer;
235   guint32 base_offset;
236   gint byte_order;
237
238   /* tags waiting for their complementary tags */
239   GSList *pending_tags;
240 };
241
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);
262
263 EXIF_DESERIALIZATION_FUNC (resolution);
264 EXIF_DESERIALIZATION_FUNC (add_to_pending_tags);
265
266 /* FIXME copyright tag has a weird "artist\0editor\0" format that is
267  * not yet handled */
268
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
319
320 /* IFD pointer tags */
321 #define EXIF_IFD_TAG 0x8769
322 #define EXIF_GPS_IFD_TAG 0x8825
323
324 /* version tags */
325 #define EXIF_VERSION_TAG 0x9000
326 #define EXIF_FLASHPIX_VERSION_TAG 0xA000
327
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)
333
334 /*
335  * Should be kept in ascending id order
336  *
337  * {gst-tag, exif-tag, exig-type, complementary-exif-tag, serialization-func,
338  *     deserialization-func}
339  */
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,
348       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}
361 };
362
363 static const GstExifTagMatch tag_map_exif[] = {
364   {GST_TAG_CAPTURING_SHUTTER_SPEED, EXIF_TAG_EXPOSURE_TIME, EXIF_TYPE_RATIONAL,
365         0,
366       NULL, NULL},
367   {GST_TAG_CAPTURING_FOCAL_RATIO, EXIF_TAG_F_NUMBER, EXIF_TYPE_RATIONAL, 0,
368         NULL,
369       NULL},
370   {GST_TAG_CAPTURING_EXPOSURE_PROGRAM, EXIF_TAG_EXPOSURE_PROGRAM,
371         EXIF_TYPE_SHORT, 0, serialize_exposure_program,
372       deserialize_exposure_program},
373
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},
378
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,
382       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,
385       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,
390         0,
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,
399       NULL, NULL},
400   {GST_TAG_APPLICATION_DATA, EXIF_TAG_MAKER_NOTE, EXIF_TYPE_UNDEFINED, 0, NULL,
401       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,
413       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}
427 };
428
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}
452 };
453
454 /* GstExifReader functions */
455 static void
456 gst_exif_reader_init (GstExifReader * reader, gint byte_order,
457     const GstBuffer * buf, guint32 base_offset)
458 {
459   ensure_exif_tags ();
460
461   reader->taglist = gst_tag_list_new ();
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;
471   }
472 }
473
474 static void
475 gst_exif_reader_add_pending_tag (GstExifReader * reader, GstExifTagData * data)
476 {
477   GstExifTagData *copy;
478
479   copy = g_slice_new (GstExifTagData);
480   memcpy (copy, data, sizeof (GstExifTagData));
481
482   reader->pending_tags = g_slist_prepend (reader->pending_tags, copy);
483 }
484
485 static GstExifTagData *
486 gst_exif_reader_get_pending_tag (GstExifReader * reader, gint tagid)
487 {
488   GSList *walker;
489
490   for (walker = reader->pending_tags; walker; walker = g_slist_next (walker)) {
491     GstExifTagData *data = (GstExifTagData *) walker->data;
492     if (data->tag == tagid)
493       return data;
494   }
495
496   return NULL;
497 }
498
499 static GstTagList *
500 gst_exif_reader_reset (GstExifReader * reader, gboolean return_taglist)
501 {
502   GstTagList *ret = NULL;
503   GSList *walker;
504
505   for (walker = reader->pending_tags; walker; walker = g_slist_next (walker)) {
506     GstExifTagData *data = (GstExifTagData *) walker->data;
507
508     g_slice_free (GstExifTagData, data);
509   }
510   g_slist_free (reader->pending_tags);
511
512   if (return_taglist) {
513     ret = reader->taglist;
514     reader->taglist = NULL;
515   }
516
517   if (reader->taglist) {
518     gst_tag_list_free (reader->taglist);
519   }
520
521   return ret;
522 }
523
524 /* GstExifWriter functions */
525
526 static void
527 gst_exif_writer_init (GstExifWriter * writer, gint byte_order)
528 {
529   ensure_exif_tags ();
530
531   gst_byte_writer_init (&writer->tagwriter);
532   gst_byte_writer_init (&writer->datawriter);
533
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;
541   }
542 }
543
544 static GstBuffer *
545 gst_exif_writer_reset_and_get_buffer (GstExifWriter * writer)
546 {
547   GstBuffer *header;
548   GstBuffer *data;
549
550   header = gst_byte_writer_reset_and_get_buffer (&writer->tagwriter);
551   data = gst_byte_writer_reset_and_get_buffer (&writer->datawriter);
552
553   return gst_buffer_join (header, data);
554 }
555
556 /*
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.
560  *
561  * Returns -1 if not found
562  */
563 static gint
564 exif_tag_map_find_reverse (guint16 exif_tag, const GstExifTagMatch * tag_map,
565     gboolean use_complementary)
566 {
567   gint i;
568
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)) {
572       return i;
573     }
574   }
575   return -1;
576 }
577
578 static gboolean
579 gst_tag_list_has_ifd_tags (const GstTagList * taglist,
580     const GstExifTagMatch * tag_map)
581 {
582   gint i;
583
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))
588         return TRUE;
589       if (tag_map[i].exif_tag == EXIF_IFD_TAG &&
590           gst_tag_list_has_ifd_tags (taglist, tag_map_exif))
591         return TRUE;
592       continue;
593     }
594
595     if (gst_tag_list_get_value_index (taglist, tag_map[i].gst_tag, 0)) {
596       return TRUE;
597     }
598   }
599   return FALSE;
600 }
601
602 /*
603  * Writes the tag entry.
604  *
605  * The tag entry is the tag id, the tag type,
606  * the count and the offset.
607  *
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.
611  */
612 static void
613 gst_exif_writer_write_tag_header (GstExifWriter * writer,
614     guint16 exif_tag, guint16 exif_type, guint32 count, guint32 offset,
615     gboolean is_data)
616 {
617   GST_DEBUG ("Writing tag entry: id %x, type %u, count %u, offset %u",
618       exif_tag, exif_type, count, offset);
619
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);
629     if (is_data) {
630       gst_byte_writer_put_uint32_le (&writer->tagwriter, offset);
631     } else {
632       gst_byte_writer_put_uint32_be (&writer->tagwriter, offset);
633     }
634   } else {
635     g_assert_not_reached ();
636   }
637
638   writer->tags_total++;
639 }
640
641 static void
642 gst_exif_writer_write_rational_data (GstExifWriter * writer, guint32 frac_n,
643     guint32 frac_d)
644 {
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);
648   } else {
649     gst_byte_writer_put_uint32_be (&writer->datawriter, frac_n);
650     gst_byte_writer_put_uint32_be (&writer->datawriter, frac_d);
651   }
652 }
653
654 static void
655 gst_exif_writer_write_signed_rational_data (GstExifWriter * writer,
656     gint32 frac_n, gint32 frac_d)
657 {
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);
661   } else {
662     gst_byte_writer_put_int32_be (&writer->datawriter, frac_n);
663     gst_byte_writer_put_int32_be (&writer->datawriter, frac_d);
664   }
665 }
666
667 static void
668 gst_exif_writer_write_rational_tag (GstExifWriter * writer,
669     guint16 tag, guint32 frac_n, guint32 frac_d)
670 {
671   guint32 offset = gst_byte_writer_get_size (&writer->datawriter);
672
673   gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_RATIONAL,
674       1, offset, FALSE);
675
676   gst_exif_writer_write_rational_data (writer, frac_n, frac_d);
677 }
678
679 static void
680 gst_exif_writer_write_signed_rational_tag (GstExifWriter * writer,
681     guint16 tag, gint32 frac_n, gint32 frac_d)
682 {
683   guint32 offset = gst_byte_writer_get_size (&writer->datawriter);
684
685   gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_SRATIONAL,
686       1, offset, FALSE);
687
688   gst_exif_writer_write_signed_rational_data (writer, frac_n, frac_d);
689 }
690
691 static void
692 gst_exif_writer_write_rational_tag_from_double (GstExifWriter * writer,
693     guint16 tag, gdouble value)
694 {
695   gint frac_n;
696   gint frac_d;
697
698   gst_util_double_to_fraction (value, &frac_n, &frac_d);
699
700   gst_exif_writer_write_rational_tag (writer, tag, frac_n, frac_d);
701 }
702
703 static void
704 gst_exif_writer_write_signed_rational_tag_from_double (GstExifWriter * writer,
705     guint16 tag, gdouble value)
706 {
707   gint frac_n;
708   gint frac_d;
709
710   gst_util_double_to_fraction (value, &frac_n, &frac_d);
711
712   gst_exif_writer_write_signed_rational_tag (writer, tag, frac_n, frac_d);
713 }
714
715 static void
716 gst_exif_writer_write_byte_tag (GstExifWriter * writer, guint16 tag,
717     guint8 value)
718 {
719   guint32 offset = 0;
720
721   GST_WRITE_UINT8 ((guint8 *) & offset, value);
722   gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_BYTE,
723       1, offset, TRUE);
724 }
725
726 static void
727 gst_exif_writer_write_short_tag (GstExifWriter * writer, guint16 tag,
728     guint16 value)
729 {
730   guint32 offset = 0;
731
732   if (writer->byte_order == G_LITTLE_ENDIAN) {
733     GST_WRITE_UINT16_LE ((guint8 *) & offset, value);
734   } else {
735     GST_WRITE_UINT16_BE ((guint8 *) & offset, value);
736   }
737
738   gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_SHORT,
739       1, offset, TRUE);
740 }
741
742 static void
743 gst_exif_writer_write_long_tag (GstExifWriter * writer, guint16 tag,
744     guint32 value)
745 {
746   guint32 offset = 0;
747   if (writer->byte_order == G_LITTLE_ENDIAN) {
748     GST_WRITE_UINT32_LE ((guint8 *) & offset, value);
749   } else {
750     GST_WRITE_UINT32_BE ((guint8 *) & offset, value);
751   }
752
753   gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_LONG,
754       1, offset, TRUE);
755 }
756
757
758 static void
759 write_exif_undefined_tag (GstExifWriter * writer, guint16 tag,
760     const guint8 * data, gint size)
761 {
762   guint32 offset = 0;
763
764   if (size > 4) {
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);
771   } else {
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,
775         size, offset, TRUE);
776   }
777 }
778
779 static void
780 write_exif_ascii_tag (GstExifWriter * writer, guint16 tag, const gchar * str)
781 {
782   gint size;
783   guint32 offset = 0;
784
785   size = strlen (str) + 1;
786
787   if (size > 4) {
788     /* we only use the data offset here, later we add up the
789      * resulting tag headers offset and the base offset */
790     offset = gst_byte_writer_get_size (&writer->datawriter);
791     gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_ASCII,
792         size, offset, FALSE);
793     gst_byte_writer_put_string (&writer->datawriter, str);
794   } else {
795     /* small enough to go in the offset */
796     memcpy ((guint8 *) & offset, str, size);
797     gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_ASCII,
798         size, offset, TRUE);
799   }
800 }
801
802 static void
803 write_exif_ascii_tag_from_taglist (GstExifWriter * writer,
804     const GstTagList * taglist, const GstExifTagMatch * exiftag)
805 {
806   gchar *str = NULL;
807   gboolean cleanup = FALSE;
808   const GValue *value;
809   gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
810
811   if (tag_size != 1) {
812     /* FIXME support this by serializing them with a ','? */
813     GST_WARNING ("Multiple string tags not supported yet");
814     return;
815   }
816
817   value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
818
819   /* do some conversion if needed */
820   switch (G_VALUE_TYPE (value)) {
821     case G_TYPE_STRING:
822       str = (gchar *) g_value_get_string (value);
823       break;
824     default:
825       if (G_VALUE_TYPE (value) == GST_TYPE_DATE_TIME) {
826         GstDateTime *dt = (GstDateTime *) g_value_get_boxed (value);
827
828         if (dt == NULL) {
829           GST_WARNING ("NULL datetime received");
830           break;
831         }
832
833         str = g_strdup_printf ("%04d:%02d:%02d %02d:%02d:%02d",
834             gst_date_time_get_year (dt), gst_date_time_get_month (dt),
835             gst_date_time_get_day (dt), gst_date_time_get_hour (dt),
836             gst_date_time_get_minute (dt), gst_date_time_get_second (dt));
837
838         cleanup = TRUE;
839       } else {
840         GST_WARNING ("Conversion from %s to ascii string not supported",
841             G_VALUE_TYPE_NAME (value));
842       }
843       break;
844   }
845
846   if (str == NULL)
847     return;
848
849   write_exif_ascii_tag (writer, exiftag->exif_tag, str);
850   if (cleanup)
851     g_free (str);
852 }
853
854 static void
855 write_exif_undefined_tag_from_taglist (GstExifWriter * writer,
856     const GstTagList * taglist, const GstExifTagMatch * exiftag)
857 {
858   const GValue *value;
859   const guint8 *data = NULL;
860   gint size = 0;
861   gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
862
863   if (tag_size != 1) {
864     GST_WARNING ("Only the first item in the taglist will be serialized");
865     return;
866   }
867
868   value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
869
870   /* do some conversion if needed */
871   switch (G_VALUE_TYPE (value)) {
872     case G_TYPE_STRING:
873       data = (guint8 *) g_value_get_string (value);
874       size = strlen ((gchar *) data);   /* no need to +1, undefined doesn't require it */
875       break;
876     default:
877       if (G_VALUE_TYPE (value) == GST_TYPE_BUFFER) {
878         GstBuffer *buf = gst_value_get_buffer (value);
879
880         data = GST_BUFFER_DATA (buf);
881         size = GST_BUFFER_SIZE (buf);
882       } else {
883         GST_WARNING ("Conversion from %s to raw data not supported",
884             G_VALUE_TYPE_NAME (value));
885       }
886       break;
887   }
888
889   if (size == 0)
890     return;
891
892   write_exif_undefined_tag (writer, exiftag->exif_tag, data, size);
893 }
894
895 static void
896 write_exif_rational_tag_from_taglist (GstExifWriter * writer,
897     const GstTagList * taglist, const GstExifTagMatch * exiftag)
898 {
899   const GValue *value;
900   gdouble num = 0;
901   gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
902
903   if (tag_size != 1) {
904     GST_WARNING ("Only the first item in the taglist will be serialized");
905     return;
906   }
907
908   value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
909
910   /* do some conversion if needed */
911   switch (G_VALUE_TYPE (value)) {
912     case G_TYPE_DOUBLE:
913       num = g_value_get_double (value);
914       gst_exif_writer_write_rational_tag_from_double (writer, exiftag->exif_tag,
915           num);
916       break;
917     default:
918       if (G_VALUE_TYPE (value) == GST_TYPE_FRACTION) {
919         gst_exif_writer_write_rational_tag (writer, exiftag->exif_tag,
920             gst_value_get_fraction_numerator (value),
921             gst_value_get_fraction_denominator (value));
922       } else {
923         GST_WARNING ("Conversion from %s to rational not supported",
924             G_VALUE_TYPE_NAME (value));
925       }
926       break;
927   }
928 }
929
930 static void
931 write_exif_signed_rational_tag_from_taglist (GstExifWriter * writer,
932     const GstTagList * taglist, const GstExifTagMatch * exiftag)
933 {
934   const GValue *value;
935   gdouble num = 0;
936   gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
937
938   if (tag_size != 1) {
939     GST_WARNING ("Only the first item in the taglist will be serialized");
940     return;
941   }
942
943   value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
944
945   /* do some conversion if needed */
946   switch (G_VALUE_TYPE (value)) {
947     case G_TYPE_DOUBLE:
948       num = g_value_get_double (value);
949       gst_exif_writer_write_signed_rational_tag_from_double (writer,
950           exiftag->exif_tag, num);
951       break;
952     default:
953       if (G_VALUE_TYPE (value) == GST_TYPE_FRACTION) {
954         gst_exif_writer_write_signed_rational_tag (writer, exiftag->exif_tag,
955             gst_value_get_fraction_numerator (value),
956             gst_value_get_fraction_denominator (value));
957       } else {
958         GST_WARNING ("Conversion from %s to signed rational not supported",
959             G_VALUE_TYPE_NAME (value));
960       }
961       break;
962   }
963 }
964
965 static void
966 write_exif_integer_tag_from_taglist (GstExifWriter * writer,
967     const GstTagList * taglist, const GstExifTagMatch * exiftag)
968 {
969   const GValue *value;
970   guint32 num = 0;
971   gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
972
973   if (tag_size != 1) {
974     GST_WARNING ("Only the first item in the taglist will be serialized");
975     return;
976   }
977
978   value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
979
980   /* do some conversion if needed */
981   switch (G_VALUE_TYPE (value)) {
982     case G_TYPE_INT:
983       num = g_value_get_int (value);
984       break;
985     default:
986       GST_WARNING ("Conversion from %s to int not supported",
987           G_VALUE_TYPE_NAME (value));
988       break;
989   }
990
991   switch (exiftag->exif_type) {
992     case EXIF_TYPE_LONG:
993       gst_exif_writer_write_long_tag (writer, exiftag->exif_tag, num);
994       break;
995     case EXIF_TYPE_SHORT:
996       gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, num);
997       break;
998     default:
999       break;
1000   }
1001 }
1002
1003 static void
1004 write_exif_tag_from_taglist (GstExifWriter * writer, const GstTagList * taglist,
1005     const GstExifTagMatch * exiftag)
1006 {
1007   GST_DEBUG ("Writing tag %s", exiftag->gst_tag);
1008
1009   /* check for special handling */
1010   if (exiftag->serialize) {
1011     exiftag->serialize (writer, taglist, exiftag);
1012     return;
1013   }
1014
1015   switch (exiftag->exif_type) {
1016     case EXIF_TYPE_ASCII:
1017       write_exif_ascii_tag_from_taglist (writer, taglist, exiftag);
1018       break;
1019     case EXIF_TYPE_UNDEFINED:
1020       write_exif_undefined_tag_from_taglist (writer, taglist, exiftag);
1021       break;
1022     case EXIF_TYPE_RATIONAL:
1023       write_exif_rational_tag_from_taglist (writer, taglist, exiftag);
1024       break;
1025     case EXIF_TYPE_SRATIONAL:
1026       write_exif_signed_rational_tag_from_taglist (writer, taglist, exiftag);
1027       break;
1028     case EXIF_TYPE_LONG:
1029     case EXIF_TYPE_SHORT:
1030       write_exif_integer_tag_from_taglist (writer, taglist, exiftag);
1031       break;
1032     default:
1033       GST_WARNING ("Unhandled tag type %d", exiftag->exif_type);
1034   }
1035 }
1036
1037 static void
1038 tagdata_copy (GstExifTagData * to, const GstExifTagData * from)
1039 {
1040   to->tag = from->tag;
1041   to->tag_type = from->tag_type;
1042   to->count = from->count;
1043   to->offset = from->offset;
1044   to->offset_as_data = from->offset_as_data;
1045 }
1046
1047 static void
1048 gst_exif_tag_rewrite_offsets (GstByteWriter * writer, gint byte_order,
1049     guint32 offset, gint num_tags, GstByteWriter * inner_ifds_data)
1050 {
1051   GstByteReader *reader;
1052   gint i;
1053   guint16 aux = G_MAXUINT16;
1054
1055   GST_LOG ("Rewriting tag entries offsets");
1056
1057   reader = (GstByteReader *) writer;
1058
1059   if (num_tags == -1) {
1060     if (byte_order == G_LITTLE_ENDIAN) {
1061       gst_byte_reader_get_uint16_le (reader, &aux);
1062     } else {
1063       gst_byte_reader_get_uint16_be (reader, &aux);
1064     }
1065     if (aux == G_MAXUINT16) {
1066       GST_WARNING ("Failed to read number of tags, won't rewrite offsets");
1067       return;
1068     }
1069     num_tags = (gint) aux;
1070   }
1071
1072   g_return_if_fail (num_tags != -1);
1073
1074   GST_DEBUG ("number of tags %d", num_tags);
1075
1076   for (i = 0; i < num_tags; i++) {
1077     guint16 type = 0;
1078     guint32 cur_offset = 0;
1079     gint byte_size = 0;
1080     guint32 count = 0;
1081     guint16 tag_id = 0;
1082
1083     g_assert (gst_byte_writer_get_pos (writer) <
1084         gst_byte_writer_get_size (writer));
1085
1086     /* read the type */
1087     if (byte_order == G_LITTLE_ENDIAN) {
1088       if (!gst_byte_reader_get_uint16_le (reader, &tag_id))
1089         break;
1090       if (!gst_byte_reader_get_uint16_le (reader, &type))
1091         break;
1092       if (!gst_byte_reader_get_uint32_le (reader, &count))
1093         break;
1094     } else {
1095       if (!gst_byte_reader_get_uint16_be (reader, &tag_id))
1096         break;
1097       if (!gst_byte_reader_get_uint16_be (reader, &type))
1098         break;
1099       if (!gst_byte_reader_get_uint32_be (reader, &count))
1100         break;
1101     }
1102
1103     GST_LOG ("Parsed tag %x of type %u and count %u", tag_id, type, count);
1104
1105     switch (type) {
1106       case EXIF_TYPE_BYTE:
1107       case EXIF_TYPE_ASCII:
1108       case EXIF_TYPE_UNDEFINED:
1109         byte_size = count;
1110         break;
1111       case EXIF_TYPE_SHORT:
1112         byte_size = count * 2;  /* 2 bytes */
1113         break;
1114       case EXIF_TYPE_LONG:
1115       case EXIF_TYPE_SLONG:
1116         byte_size = count * 4;  /* 4 bytes */
1117         break;
1118       case EXIF_TYPE_RATIONAL:
1119       case EXIF_TYPE_SRATIONAL:
1120         byte_size = count * 8;  /* 8 bytes */
1121         break;
1122       default:
1123         g_assert_not_reached ();
1124         break;
1125     }
1126
1127     /* adjust the offset if needed */
1128     if (byte_size > 4 || tag_id == EXIF_GPS_IFD_TAG || tag_id == EXIF_IFD_TAG) {
1129       if (byte_order == G_LITTLE_ENDIAN) {
1130         if (gst_byte_reader_peek_uint32_le (reader, &cur_offset)) {
1131           gst_byte_writer_put_uint32_le (writer, cur_offset + offset);
1132         }
1133       } else {
1134         if (gst_byte_reader_peek_uint32_be (reader, &cur_offset)) {
1135           gst_byte_writer_put_uint32_be (writer, cur_offset + offset);
1136         }
1137       }
1138       GST_DEBUG ("Rewriting tag offset from %u to (%u + %u) %u",
1139           cur_offset, cur_offset, offset, cur_offset + offset);
1140
1141       if ((tag_id == EXIF_GPS_IFD_TAG || tag_id == EXIF_IFD_TAG) &&
1142           inner_ifds_data != NULL) {
1143         /* needs special handling */
1144         if (!gst_byte_writer_set_pos (inner_ifds_data, cur_offset)) {
1145           GST_WARNING ("Failed to position writer to rewrite inner ifd "
1146               "offsets");
1147           continue;
1148         }
1149
1150         gst_exif_tag_rewrite_offsets (inner_ifds_data, byte_order, offset, -1,
1151             NULL);
1152       }
1153     } else {
1154       gst_byte_reader_skip (reader, 4);
1155       GST_DEBUG ("No need to rewrite tag offset");
1156     }
1157   }
1158   GST_LOG ("Done rewriting offsets");
1159 }
1160
1161 static void
1162 parse_exif_ascii_tag (GstExifReader * reader, const GstExifTagMatch * tag,
1163     guint32 count, guint32 offset, const guint8 * offset_as_data)
1164 {
1165   GType tagtype;
1166   gchar *str;
1167   guint32 real_offset;
1168
1169   if (count > 4) {
1170     if (offset < reader->base_offset) {
1171       GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
1172           reader->base_offset);
1173       return;
1174     }
1175
1176     real_offset = offset - reader->base_offset;
1177     if (real_offset >= GST_BUFFER_SIZE (reader->buffer)) {
1178       GST_WARNING ("Invalid offset %u for buffer of size %u, not adding tag %s",
1179           real_offset, GST_BUFFER_SIZE (reader->buffer), tag->gst_tag);
1180       return;
1181     }
1182
1183     str =
1184         g_strndup ((gchar *) (GST_BUFFER_DATA (reader->buffer) + real_offset),
1185         count);
1186   } else {
1187     str = g_strndup ((gchar *) offset_as_data, count);
1188   }
1189
1190   tagtype = gst_tag_get_type (tag->gst_tag);
1191   if (tagtype == GST_TYPE_DATE_TIME) {
1192     gint year = 0, month = 1, day = 1, hour = 0, minute = 0, second = 0;
1193
1194     if (sscanf (str, "%04d:%02d:%02d %02d:%02d:%02d", &year, &month, &day,
1195             &hour, &minute, &second) > 0) {
1196       GstDateTime *d;
1197
1198       d = gst_date_time_new_local_time (year, month, day, hour, minute, second);
1199       gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE,
1200           tag->gst_tag, d, NULL);
1201       gst_date_time_unref (d);
1202     } else {
1203       GST_WARNING ("Failed to parse %s into a datetime tag", str);
1204     }
1205   } else if (tagtype == G_TYPE_STRING) {
1206     gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE, tag->gst_tag, str,
1207         NULL);
1208   } else {
1209     GST_WARNING ("No parsing function associated to %x(%s)", tag->exif_tag,
1210         tag->gst_tag);
1211   }
1212   g_free (str);
1213 }
1214
1215 static void
1216 parse_exif_long_tag (GstExifReader * reader, const GstExifTagMatch * tag,
1217     guint32 count, guint32 offset, const guint8 * offset_as_data)
1218 {
1219   GType tagtype;
1220
1221   if (count > 1) {
1222     GST_WARNING ("Long tags with more than one value are not supported");
1223     return;
1224   }
1225
1226   tagtype = gst_tag_get_type (tag->gst_tag);
1227   if (tagtype == G_TYPE_INT) {
1228     gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE, tag->gst_tag,
1229         offset, NULL);
1230   } else {
1231     GST_WARNING ("No parsing function associated to %x(%s)", tag->exif_tag,
1232         tag->gst_tag);
1233   }
1234 }
1235
1236
1237 static void
1238 parse_exif_undefined_tag (GstExifReader * reader, const GstExifTagMatch * tag,
1239     guint32 count, guint32 offset, const guint8 * offset_as_data)
1240 {
1241   GType tagtype;
1242   guint8 *data;
1243   guint32 real_offset;
1244
1245   if (count > 4) {
1246     if (offset < reader->base_offset) {
1247       GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
1248           reader->base_offset);
1249       return;
1250     }
1251
1252     real_offset = offset - reader->base_offset;
1253     if (real_offset >= GST_BUFFER_SIZE (reader->buffer)) {
1254       GST_WARNING ("Invalid offset %u for buffer of size %u, not adding tag %s",
1255           real_offset, GST_BUFFER_SIZE (reader->buffer), tag->gst_tag);
1256       return;
1257     }
1258
1259     /* +1 because it could be a string without the \0 */
1260     data = malloc (sizeof (guint8) * count + 1);
1261     memcpy (data, GST_BUFFER_DATA (reader->buffer) + real_offset, count);
1262     data[count] = 0;
1263   } else {
1264     data = malloc (sizeof (guint8) * count + 1);
1265     memcpy (data, (guint8 *) offset_as_data, count);
1266     data[count] = 0;
1267   }
1268
1269   tagtype = gst_tag_get_type (tag->gst_tag);
1270   if (tagtype == GST_TYPE_BUFFER) {
1271     GstBuffer *buf;
1272
1273     buf = gst_buffer_new ();
1274     GST_BUFFER_DATA (buf) = data;
1275     GST_BUFFER_MALLOCDATA (buf) = data;
1276     GST_BUFFER_SIZE (buf) = count;
1277     data = NULL;
1278
1279     gst_tag_list_add (reader->taglist, GST_TAG_MERGE_APPEND, tag->gst_tag,
1280         buf, NULL);
1281
1282     gst_buffer_unref (buf);
1283   } else if (tagtype == G_TYPE_STRING) {
1284     gst_tag_list_add (reader->taglist, GST_TAG_MERGE_REPLACE, tag->gst_tag,
1285         data, NULL);
1286   } else {
1287     GST_WARNING ("No parsing function associated to %x(%s)", tag->exif_tag,
1288         tag->gst_tag);
1289   }
1290   g_free (data);
1291 }
1292
1293 static gboolean
1294 exif_reader_read_rational_tag (GstExifReader * exif_reader,
1295     guint32 count, guint32 offset, gboolean is_signed,
1296     gint32 * _frac_n, gint32 * _frac_d)
1297 {
1298   GstByteReader data_reader;
1299   guint32 real_offset;
1300   gint32 frac_n = 0;
1301   gint32 frac_d = 0;
1302
1303   if (count > 1) {
1304     GST_WARNING ("Rationals with multiple entries are not supported");
1305   }
1306   if (offset < exif_reader->base_offset) {
1307     GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
1308         exif_reader->base_offset);
1309     return FALSE;
1310   }
1311
1312   real_offset = offset - exif_reader->base_offset;
1313   if (real_offset >= GST_BUFFER_SIZE (exif_reader->buffer)) {
1314     GST_WARNING ("Invalid offset %u for buffer of size %u",
1315         real_offset, GST_BUFFER_SIZE (exif_reader->buffer));
1316     return FALSE;
1317   }
1318
1319   gst_byte_reader_init_from_buffer (&data_reader, exif_reader->buffer);
1320   if (!gst_byte_reader_set_pos (&data_reader, real_offset))
1321     goto reader_fail;
1322
1323   if (!is_signed) {
1324     guint32 aux_n = 0, aux_d = 0;
1325     if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
1326       if (!gst_byte_reader_get_uint32_le (&data_reader, &aux_n) ||
1327           !gst_byte_reader_get_uint32_le (&data_reader, &aux_d))
1328         goto reader_fail;
1329     } else {
1330       if (!gst_byte_reader_get_uint32_be (&data_reader, &aux_n) ||
1331           !gst_byte_reader_get_uint32_be (&data_reader, &aux_d))
1332         goto reader_fail;
1333     }
1334     frac_n = (gint32) aux_n;
1335     frac_d = (gint32) aux_d;
1336   } else {
1337     if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
1338       if (!gst_byte_reader_get_int32_le (&data_reader, &frac_n) ||
1339           !gst_byte_reader_get_int32_le (&data_reader, &frac_d))
1340         goto reader_fail;
1341     } else {
1342       if (!gst_byte_reader_get_int32_be (&data_reader, &frac_n) ||
1343           !gst_byte_reader_get_int32_be (&data_reader, &frac_d))
1344         goto reader_fail;
1345     }
1346   }
1347
1348   if (_frac_n)
1349     *_frac_n = frac_n;
1350   if (_frac_d)
1351     *_frac_d = frac_d;
1352
1353   return TRUE;
1354
1355 reader_fail:
1356   GST_WARNING ("Failed to read from byte reader. (Buffer too short?)");
1357   return FALSE;
1358 }
1359
1360 static void
1361 parse_exif_rational_tag (GstExifReader * exif_reader,
1362     const gchar * gst_tag, guint32 count, guint32 offset, gdouble multiplier,
1363     gboolean is_signed)
1364 {
1365   GType type;
1366   gint32 frac_n = 0;
1367   gint32 frac_d = 1;
1368   gdouble value;
1369
1370   GST_DEBUG ("Reading fraction for tag %s...", gst_tag);
1371   if (!exif_reader_read_rational_tag (exif_reader, count, offset, is_signed,
1372           &frac_n, &frac_d))
1373     return;
1374   GST_DEBUG ("Read fraction for tag %s: %d/%d", gst_tag, frac_n, frac_d);
1375
1376   type = gst_tag_get_type (gst_tag);
1377   switch (type) {
1378     case G_TYPE_DOUBLE:
1379       gst_util_fraction_to_double (frac_n, frac_d, &value);
1380       value *= multiplier;
1381       GST_DEBUG ("Adding %s tag: %lf", gst_tag, value);
1382       gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, gst_tag,
1383           value, NULL);
1384       break;
1385     default:
1386       if (type == GST_TYPE_FRACTION) {
1387         GValue fraction = { 0 };
1388
1389         g_value_init (&fraction, GST_TYPE_FRACTION);
1390         gst_value_set_fraction (&fraction, frac_n * multiplier, frac_d);
1391         gst_tag_list_add_value (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
1392             gst_tag, &fraction);
1393         g_value_unset (&fraction);
1394       } else {
1395         GST_WARNING ("Can't convert from fraction into %s", g_type_name (type));
1396       }
1397   }
1398
1399 }
1400
1401 static GstBuffer *
1402 write_exif_ifd (const GstTagList * taglist, gboolean byte_order,
1403     guint32 base_offset, const GstExifTagMatch * tag_map)
1404 {
1405   GstExifWriter writer;
1406   gint i;
1407
1408   GST_DEBUG ("Formatting taglist %p as exif buffer. Byte order: %d, "
1409       "base_offset: %u", taglist, byte_order, base_offset);
1410
1411   g_assert (byte_order == G_LITTLE_ENDIAN || byte_order == G_BIG_ENDIAN);
1412
1413   if (!gst_tag_list_has_ifd_tags (taglist, tag_map)) {
1414     GST_DEBUG ("No tags for this ifd");
1415     return NULL;
1416   }
1417
1418   gst_exif_writer_init (&writer, byte_order);
1419
1420   /* write tag number as 0 */
1421   gst_byte_writer_put_uint16_le (&writer.tagwriter, 0);
1422
1423   /* write both tag headers and data
1424    * in ascending id order */
1425
1426   for (i = 0; tag_map[i].exif_tag != 0; i++) {
1427
1428     /* special cases have NULL gst tag */
1429     if (tag_map[i].gst_tag == NULL) {
1430       GstBuffer *inner_ifd = NULL;
1431       const GstExifTagMatch *inner_tag_map = NULL;
1432
1433       GST_LOG ("Inner ifd tag: %x", tag_map[i].exif_tag);
1434
1435       if (tag_map[i].exif_tag == EXIF_GPS_IFD_TAG) {
1436         inner_tag_map = tag_map_gps;
1437       } else if (tag_map[i].exif_tag == EXIF_IFD_TAG) {
1438         inner_tag_map = tag_map_exif;
1439       } else if (tag_map[i].exif_tag == EXIF_VERSION_TAG) {
1440         /* special case where we write the exif version */
1441         write_exif_undefined_tag (&writer, EXIF_VERSION_TAG, (guint8 *) "0230",
1442             4);
1443       } else if (tag_map[i].exif_tag == EXIF_FLASHPIX_VERSION_TAG) {
1444         /* special case where we write the flashpix version */
1445         write_exif_undefined_tag (&writer, EXIF_FLASHPIX_VERSION_TAG,
1446             (guint8 *) "0100", 4);
1447       }
1448
1449       if (inner_tag_map) {
1450         /* base offset and tagheader size are added when rewriting offset */
1451         inner_ifd = write_exif_ifd (taglist, byte_order,
1452             gst_byte_writer_get_size (&writer.datawriter), inner_tag_map);
1453       }
1454
1455       if (inner_ifd) {
1456         GST_DEBUG ("Adding inner ifd: %x", tag_map[i].exif_tag);
1457         gst_exif_writer_write_tag_header (&writer, tag_map[i].exif_tag,
1458             EXIF_TYPE_LONG, 1,
1459             gst_byte_writer_get_size (&writer.datawriter), FALSE);
1460         gst_byte_writer_put_data (&writer.datawriter,
1461             GST_BUFFER_DATA (inner_ifd), GST_BUFFER_SIZE (inner_ifd));
1462         gst_buffer_unref (inner_ifd);
1463       }
1464       continue;
1465     }
1466
1467     GST_LOG ("Checking tag %s", tag_map[i].gst_tag);
1468     if (gst_tag_list_get_value_index (taglist, tag_map[i].gst_tag, 0) == NULL)
1469       continue;
1470
1471     write_exif_tag_from_taglist (&writer, taglist, &tag_map[i]);
1472   }
1473
1474   /* Add the next IFD offset, we just set it to 0 because
1475    * there is no easy way to predict what it is going to be.
1476    * The user might rewrite the value if needed */
1477   gst_byte_writer_put_uint32_le (&writer.tagwriter, 0);
1478
1479   /* write the number of tags */
1480   gst_byte_writer_set_pos (&writer.tagwriter, 0);
1481   if (writer.byte_order == G_LITTLE_ENDIAN)
1482     gst_byte_writer_put_uint16_le (&writer.tagwriter, writer.tags_total);
1483   else
1484     gst_byte_writer_put_uint16_be (&writer.tagwriter, writer.tags_total);
1485
1486   GST_DEBUG ("Number of tags rewriten to %d", writer.tags_total);
1487
1488   /* now that we know the tag headers size, we can add the offsets */
1489   gst_exif_tag_rewrite_offsets (&writer.tagwriter, writer.byte_order,
1490       base_offset + gst_byte_writer_get_size (&writer.tagwriter),
1491       writer.tags_total, &writer.datawriter);
1492
1493   return gst_exif_writer_reset_and_get_buffer (&writer);
1494 }
1495
1496 static gboolean
1497 parse_exif_tag_header (GstByteReader * reader, gint byte_order,
1498     GstExifTagData * _tagdata)
1499 {
1500   g_assert (_tagdata);
1501
1502   /* read the fields */
1503   if (byte_order == G_LITTLE_ENDIAN) {
1504     if (!gst_byte_reader_get_uint16_le (reader, &_tagdata->tag) ||
1505         !gst_byte_reader_get_uint16_le (reader, &_tagdata->tag_type) ||
1506         !gst_byte_reader_get_uint32_le (reader, &_tagdata->count) ||
1507         !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) {
1508       return FALSE;
1509     }
1510     _tagdata->offset = GST_READ_UINT32_LE (_tagdata->offset_as_data);
1511   } else {
1512     if (!gst_byte_reader_get_uint16_be (reader, &_tagdata->tag) ||
1513         !gst_byte_reader_get_uint16_be (reader, &_tagdata->tag_type) ||
1514         !gst_byte_reader_get_uint32_be (reader, &_tagdata->count) ||
1515         !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) {
1516       return FALSE;
1517     }
1518     _tagdata->offset = GST_READ_UINT32_BE (_tagdata->offset_as_data);
1519   }
1520
1521   return TRUE;
1522 }
1523
1524 static gboolean
1525 parse_exif_ifd (GstExifReader * exif_reader, gint buf_offset,
1526     const GstExifTagMatch * tag_map)
1527 {
1528   GstByteReader reader;
1529   guint16 entries = 0;
1530   guint16 i;
1531
1532   g_return_val_if_fail (exif_reader->byte_order == G_LITTLE_ENDIAN
1533       || exif_reader->byte_order == G_BIG_ENDIAN, FALSE);
1534
1535   gst_byte_reader_init_from_buffer (&reader, exif_reader->buffer);
1536   if (!gst_byte_reader_set_pos (&reader, buf_offset)) {
1537     GST_WARNING ("Buffer offset invalid when parsing exif ifd");
1538     return FALSE;
1539   }
1540
1541   /* read the IFD entries number */
1542   if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
1543     if (!gst_byte_reader_get_uint16_le (&reader, &entries))
1544       goto read_error;
1545   } else {
1546     if (!gst_byte_reader_get_uint16_be (&reader, &entries))
1547       goto read_error;
1548   }
1549   GST_DEBUG ("Read number of entries: %u", entries);
1550
1551   /* iterate over the buffer and find the tags and stuff */
1552   for (i = 0; i < entries; i++) {
1553     GstExifTagData tagdata;
1554     gint map_index;
1555
1556     GST_LOG ("Reading entry: %u", i);
1557
1558     if (!parse_exif_tag_header (&reader, exif_reader->byte_order, &tagdata))
1559       goto read_error;
1560
1561     GST_DEBUG ("Parsed tag: id 0x%x, type %u, count %u, offset %u (0x%x)"
1562         ", buf size: %u", tagdata.tag, tagdata.tag_type, tagdata.count,
1563         tagdata.offset, tagdata.offset, gst_byte_reader_get_size (&reader));
1564
1565     map_index = exif_tag_map_find_reverse (tagdata.tag, tag_map, TRUE);
1566     if (map_index == -1) {
1567       GST_WARNING ("Unmapped exif tag: 0x%x", tagdata.tag);
1568       continue;
1569     }
1570
1571     /*
1572      * inner ifd tags handling, errors processing those are being ignored
1573      * and we try to continue the parsing
1574      */
1575     if (tagdata.tag == EXIF_GPS_IFD_TAG) {
1576       parse_exif_ifd (exif_reader,
1577           tagdata.offset - exif_reader->base_offset, tag_map_gps);
1578
1579       continue;
1580     }
1581     if (tagdata.tag == EXIF_IFD_TAG) {
1582       parse_exif_ifd (exif_reader,
1583           tagdata.offset - exif_reader->base_offset, tag_map_exif);
1584
1585       continue;
1586     }
1587     if (tagdata.tag == EXIF_VERSION_TAG ||
1588         tagdata.tag == EXIF_FLASHPIX_VERSION_TAG) {
1589       /* skip */
1590       continue;
1591     }
1592
1593     /* tags that need specialized deserialization */
1594     if (tag_map[map_index].deserialize) {
1595       i += tag_map[map_index].deserialize (exif_reader, &reader,
1596           &tag_map[map_index], &tagdata);
1597       continue;
1598     }
1599
1600     switch (tagdata.tag_type) {
1601       case EXIF_TYPE_ASCII:
1602         parse_exif_ascii_tag (exif_reader, &tag_map[map_index],
1603             tagdata.count, tagdata.offset, tagdata.offset_as_data);
1604         break;
1605       case EXIF_TYPE_RATIONAL:
1606         parse_exif_rational_tag (exif_reader, tag_map[map_index].gst_tag,
1607             tagdata.count, tagdata.offset, 1, FALSE);
1608         break;
1609       case EXIF_TYPE_SRATIONAL:
1610         parse_exif_rational_tag (exif_reader, tag_map[map_index].gst_tag,
1611             tagdata.count, tagdata.offset, 1, TRUE);
1612         break;
1613       case EXIF_TYPE_UNDEFINED:
1614         parse_exif_undefined_tag (exif_reader, &tag_map[map_index],
1615             tagdata.count, tagdata.offset, tagdata.offset_as_data);
1616       case EXIF_TYPE_LONG:
1617         parse_exif_long_tag (exif_reader, &tag_map[map_index],
1618             tagdata.count, tagdata.offset, tagdata.offset_as_data);
1619         break;
1620       default:
1621         GST_WARNING ("Unhandled tag type: %u", tagdata.tag_type);
1622         break;
1623     }
1624   }
1625
1626   /* check if the pending tags have something that can still be added */
1627   {
1628     GSList *walker;
1629     GstExifTagData *data;
1630
1631     for (walker = exif_reader->pending_tags; walker;
1632         walker = g_slist_next (walker)) {
1633       data = (GstExifTagData *) walker->data;
1634       switch (data->tag) {
1635         case EXIF_TAG_XRESOLUTION:
1636           parse_exif_rational_tag (exif_reader, GST_TAG_IMAGE_HORIZONTAL_PPI,
1637               data->count, data->offset, 1, FALSE);
1638           break;
1639         case EXIF_TAG_YRESOLUTION:
1640           parse_exif_rational_tag (exif_reader, GST_TAG_IMAGE_VERTICAL_PPI,
1641               data->count, data->offset, 1, FALSE);
1642           break;
1643         default:
1644           /* NOP */
1645           break;
1646       }
1647     }
1648   }
1649
1650   return TRUE;
1651
1652 read_error:
1653   {
1654     GST_WARNING ("Failed to parse the exif ifd");
1655     return FALSE;
1656   }
1657 }
1658
1659 /**
1660  * gst_tag_list_to_exif_buffer:
1661  * @taglist: The taglist
1662  * @byte_order: byte order used in writing (G_LITTLE_ENDIAN or G_BIG_ENDIAN)
1663  * @base_offset: Offset from the tiff header first byte
1664  *
1665  * Formats the tags in taglist on exif format. The resulting buffer contains
1666  * the tags IFD and is followed by the data pointed by the tag entries.
1667  *
1668  * Returns: A GstBuffer containing the tag entries followed by the tag data
1669  *
1670  * Since: 0.10.30
1671  */
1672 GstBuffer *
1673 gst_tag_list_to_exif_buffer (const GstTagList * taglist, gint byte_order,
1674     guint32 base_offset)
1675 {
1676   return write_exif_ifd (taglist, byte_order, base_offset, tag_map_ifd0);
1677 }
1678
1679 /**
1680  * gst_tag_list_to_exif_buffer_with_tiff_header:
1681  * @taglist: The taglist
1682  *
1683  * Formats the tags in taglist into exif structure, a tiff header
1684  * is put in the beginning of the buffer.
1685  *
1686  * Returns: A GstBuffer containing the data
1687  *
1688  * Since: 0.10.30
1689  */
1690 GstBuffer *
1691 gst_tag_list_to_exif_buffer_with_tiff_header (const GstTagList * taglist)
1692 {
1693   GstBuffer *ifd;
1694   GstByteWriter writer;
1695   guint size;
1696
1697   ifd = gst_tag_list_to_exif_buffer (taglist, G_BYTE_ORDER, 8);
1698   if (ifd == NULL) {
1699     GST_WARNING ("Failed to create exif buffer");
1700     return NULL;
1701   }
1702   size = TIFF_HEADER_SIZE + GST_BUFFER_SIZE (ifd);
1703
1704   /* TODO what is the correct endianness here? */
1705   gst_byte_writer_init_with_size (&writer, size, FALSE);
1706   /* TIFF header */
1707   if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
1708     gst_byte_writer_put_uint16_le (&writer, TIFF_LITTLE_ENDIAN);
1709     gst_byte_writer_put_uint16_le (&writer, 42);
1710     gst_byte_writer_put_uint32_le (&writer, 8);
1711   } else {
1712     gst_byte_writer_put_uint16_be (&writer, TIFF_BIG_ENDIAN);
1713     gst_byte_writer_put_uint16_be (&writer, 42);
1714     gst_byte_writer_put_uint32_be (&writer, 8);
1715   }
1716   if (!gst_byte_writer_put_data (&writer, GST_BUFFER_DATA (ifd),
1717           GST_BUFFER_SIZE (ifd))) {
1718     GST_WARNING ("Byte writer size mismatch");
1719     /* reaching here is a programming error because we should have a buffer
1720      * large enough */
1721     g_assert_not_reached ();
1722     gst_buffer_unref (ifd);
1723     gst_byte_writer_reset (&writer);
1724     return NULL;
1725   }
1726   gst_buffer_unref (ifd);
1727   return gst_byte_writer_reset_and_get_buffer (&writer);
1728 }
1729
1730 /**
1731  * gst_tag_list_from_exif_buffer:
1732  * @buffer: The exif buffer
1733  * @byte_order: byte order of the data
1734  * @base_offset: Offset from the tiff header to this buffer
1735  *
1736  * Parses the IFD and IFD tags data contained in the buffer and puts it
1737  * on a taglist. The base_offset is used to subtract from the offset in
1738  * the tag entries and be able to get the offset relative to the buffer
1739  * start
1740  *
1741  * Returns: The parsed taglist
1742  *
1743  * Since: 0.10.30
1744  */
1745 GstTagList *
1746 gst_tag_list_from_exif_buffer (const GstBuffer * buffer, gint byte_order,
1747     guint32 base_offset)
1748 {
1749   GstExifReader reader;
1750   g_return_val_if_fail (byte_order == G_LITTLE_ENDIAN
1751       || byte_order == G_BIG_ENDIAN, NULL);
1752
1753   gst_exif_reader_init (&reader, byte_order, buffer, base_offset);
1754
1755   if (!parse_exif_ifd (&reader, 0, tag_map_ifd0))
1756     goto read_error;
1757
1758   return gst_exif_reader_reset (&reader, TRUE);
1759
1760 read_error:
1761   {
1762     gst_exif_reader_reset (&reader, FALSE);
1763     GST_WARNING ("Failed to parse the exif buffer");
1764     return NULL;
1765   }
1766 }
1767
1768 /**
1769  * gst_tag_list_from_exif_buffer_with_tiff_header:
1770  * @buffer: The exif buffer
1771  *
1772  * Parses the exif tags starting with a tiff header structure.
1773  *
1774  * Returns: The taglist
1775  *
1776  * Since: 0.10.30
1777  */
1778 GstTagList *
1779 gst_tag_list_from_exif_buffer_with_tiff_header (const GstBuffer * buffer)
1780 {
1781   GstByteReader reader;
1782   guint16 fortytwo = 42;
1783   guint16 endianness = 0;
1784   guint32 offset;
1785   GstTagList *taglist = NULL;
1786   GstBuffer *subbuffer;
1787
1788   GST_LOG ("Parsing exif tags with tiff header of size %u",
1789       GST_BUFFER_SIZE (buffer));
1790
1791   gst_byte_reader_init_from_buffer (&reader, buffer);
1792
1793   GST_LOG ("Parsing the tiff header");
1794   if (!gst_byte_reader_get_uint16_be (&reader, &endianness)) {
1795     goto byte_reader_fail;
1796   }
1797
1798   if (endianness == TIFF_LITTLE_ENDIAN) {
1799     if (!gst_byte_reader_get_uint16_le (&reader, &fortytwo) ||
1800         !gst_byte_reader_get_uint32_le (&reader, &offset))
1801       goto byte_reader_fail;
1802   } else if (endianness == TIFF_BIG_ENDIAN) {
1803     if (!gst_byte_reader_get_uint16_be (&reader, &fortytwo) ||
1804         !gst_byte_reader_get_uint32_be (&reader, &offset))
1805       goto byte_reader_fail;
1806   } else {
1807     GST_WARNING ("Invalid endianness number %u", endianness);
1808     return NULL;
1809   }
1810
1811   if (fortytwo != 42) {
1812     GST_WARNING ("Invalid magic number %u, should be 42", fortytwo);
1813     return NULL;
1814   }
1815
1816   subbuffer = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buffer) -
1817       (TIFF_HEADER_SIZE - 2));
1818   memcpy (GST_BUFFER_DATA (subbuffer),
1819       GST_BUFFER_DATA (buffer) + TIFF_HEADER_SIZE,
1820       GST_BUFFER_SIZE (buffer) - TIFF_HEADER_SIZE);
1821
1822   taglist = gst_tag_list_from_exif_buffer (subbuffer,
1823       endianness == TIFF_LITTLE_ENDIAN ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, 8);
1824
1825   gst_buffer_unref (subbuffer);
1826   return taglist;
1827
1828 byte_reader_fail:
1829   {
1830     GST_WARNING ("Failed to read values from buffer");
1831     return NULL;
1832   }
1833 }
1834
1835 /* special serialization functions */
1836 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (contrast,
1837     capturing_contrast);
1838 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (exposure_mode,
1839     capturing_exposure_mode);
1840 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (exposure_program,
1841     capturing_exposure_program);
1842 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (gain_control,
1843     capturing_gain_adjustment);
1844 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (metering_mode,
1845     capturing_metering_mode);
1846 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (orientation,
1847     image_orientation);
1848 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (saturation,
1849     capturing_saturation);
1850 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (scene_capture_type,
1851     capturing_scene_capture_type);
1852 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (sharpness,
1853     capturing_sharpness);
1854 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (source,
1855     capturing_source);
1856 EXIF_SERIALIZATION_DESERIALIZATION_MAP_STRING_TO_INT_FUNC (white_balance,
1857     capturing_white_balance);
1858
1859 static void
1860 serialize_geo_coordinate (GstExifWriter * writer, const GstTagList * taglist,
1861     const GstExifTagMatch * exiftag)
1862 {
1863   gboolean latitude;
1864   gdouble value;
1865   gint degrees;
1866   gint minutes;
1867   gint seconds;
1868   guint32 offset;
1869
1870   latitude = exiftag->exif_tag == EXIF_TAG_GPS_LATITUDE;        /* exif tag for latitude */
1871   if (!gst_tag_list_get_double (taglist, exiftag->gst_tag, &value)) {
1872     GST_WARNING ("Failed to get double from tag list for tag: %s",
1873         exiftag->gst_tag);
1874     return;
1875   }
1876
1877   /* first write the Latitude or Longitude Ref */
1878   if (latitude) {
1879     if (value >= 0) {
1880       write_exif_ascii_tag (writer, exiftag->complementary_tag, "N");
1881     } else {
1882       value *= -1;
1883       write_exif_ascii_tag (writer, exiftag->complementary_tag, "S");
1884     }
1885   } else {
1886     if (value >= 0) {
1887       write_exif_ascii_tag (writer, exiftag->complementary_tag, "E");
1888     } else {
1889       value *= -1;
1890       write_exif_ascii_tag (writer, exiftag->complementary_tag, "W");
1891     }
1892   }
1893
1894   /* now write the degrees stuff */
1895   GST_LOG ("Converting geo location %lf to degrees", value);
1896   degrees = (gint) value;
1897   value -= degrees;
1898   minutes = (gint) (value * 60);
1899   value = (value * 60) - minutes;
1900   seconds = (gint) (value * 60);
1901   GST_LOG ("Converted geo location to %d.%d'%d'' degrees", degrees,
1902       minutes, seconds);
1903
1904   offset = gst_byte_writer_get_size (&writer->datawriter);
1905   gst_exif_writer_write_tag_header (writer, exiftag->exif_tag,
1906       EXIF_TYPE_RATIONAL, 3, offset, FALSE);
1907   gst_exif_writer_write_rational_data (writer, degrees, 1);
1908   gst_exif_writer_write_rational_data (writer, minutes, 1);
1909   gst_exif_writer_write_rational_data (writer, seconds, 1);
1910 }
1911
1912 static gint
1913 deserialize_geo_coordinate (GstExifReader * exif_reader,
1914     GstByteReader * reader, const GstExifTagMatch * exiftag,
1915     GstExifTagData * tagdata)
1916 {
1917   GstByteReader fractions_reader;
1918   gint multiplier;
1919   GstExifTagData next_tagdata;
1920   gint ret = 0;
1921   /* for the conversion */
1922   guint32 degrees_n = 0;
1923   guint32 degrees_d = 1;
1924   guint32 minutes_n = 0;
1925   guint32 minutes_d = 1;
1926   guint32 seconds_n = 0;
1927   guint32 seconds_d = 1;
1928   gdouble degrees;
1929   gdouble minutes;
1930   gdouble seconds;
1931
1932   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
1933       exiftag->exif_tag);
1934
1935   if (exiftag->complementary_tag != tagdata->tag) {
1936     /* First should come the 'Ref' tags */
1937     GST_WARNING ("Tag %d is not the 'Ref' tag for latitude nor longitude",
1938         tagdata->tag);
1939     return ret;
1940   }
1941
1942   if (tagdata->offset_as_data[0] == 'N' || tagdata->offset_as_data[0] == 'E') {
1943     multiplier = 1;
1944   } else if (tagdata->offset_as_data[0] == 'S'
1945       || tagdata->offset_as_data[0] == 'W') {
1946     multiplier = -1;
1947   } else {
1948     GST_WARNING ("Invalid LatitudeRef or LongitudeRef %c",
1949         tagdata->offset_as_data[0]);
1950     return ret;
1951   }
1952
1953   /* now read the following tag that must be the latitude or longitude */
1954   if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
1955     if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
1956       goto reader_fail;
1957   } else {
1958     if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
1959       goto reader_fail;
1960   }
1961
1962   if (exiftag->exif_tag != next_tagdata.tag) {
1963     GST_WARNING ("This is not a geo cordinate tag");
1964     return ret;
1965   }
1966
1967   /* read the remaining tag entry data */
1968   if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
1969     ret = -1;
1970     goto reader_fail;
1971   }
1972
1973   ret = 1;
1974
1975   /* some checking */
1976   if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
1977     GST_WARNING ("Invalid type %d for geo coordinate (latitude/longitude)",
1978         next_tagdata.tag_type);
1979     return ret;
1980   }
1981   if (next_tagdata.count != 3) {
1982     GST_WARNING ("Geo coordinate should use 3 fractions, we have %u",
1983         next_tagdata.count);
1984     return ret;
1985   }
1986
1987   /* now parse the fractions */
1988   gst_byte_reader_init_from_buffer (&fractions_reader, exif_reader->buffer);
1989   if (!gst_byte_reader_set_pos (&fractions_reader,
1990           next_tagdata.offset - exif_reader->base_offset))
1991     goto reader_fail;
1992
1993   if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
1994     if (!gst_byte_reader_get_uint32_le (&fractions_reader, &degrees_n) ||
1995         !gst_byte_reader_get_uint32_le (&fractions_reader, &degrees_d) ||
1996         !gst_byte_reader_get_uint32_le (&fractions_reader, &minutes_n) ||
1997         !gst_byte_reader_get_uint32_le (&fractions_reader, &minutes_d) ||
1998         !gst_byte_reader_get_uint32_le (&fractions_reader, &seconds_n) ||
1999         !gst_byte_reader_get_uint32_le (&fractions_reader, &seconds_d))
2000       goto reader_fail;
2001   } else {
2002     if (!gst_byte_reader_get_uint32_be (&fractions_reader, &degrees_n) ||
2003         !gst_byte_reader_get_uint32_be (&fractions_reader, &degrees_d) ||
2004         !gst_byte_reader_get_uint32_be (&fractions_reader, &minutes_n) ||
2005         !gst_byte_reader_get_uint32_be (&fractions_reader, &minutes_d) ||
2006         !gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_n) ||
2007         !gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_d))
2008       goto reader_fail;
2009   }
2010
2011   GST_DEBUG ("Read degrees fraction for tag %s: %u/%u %u/%u %u/%u",
2012       exiftag->gst_tag, degrees_n, degrees_d, minutes_n, minutes_d,
2013       seconds_n, seconds_d);
2014
2015   gst_util_fraction_to_double (degrees_n, degrees_d, &degrees);
2016   gst_util_fraction_to_double (minutes_n, minutes_d, &minutes);
2017   gst_util_fraction_to_double (seconds_n, seconds_d, &seconds);
2018
2019   minutes += seconds / 60;
2020   degrees += minutes / 60;
2021   degrees *= multiplier;
2022
2023   GST_DEBUG ("Adding %s tag: %lf", exiftag->gst_tag, degrees);
2024   gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
2025       exiftag->gst_tag, degrees, NULL);
2026
2027   return ret;
2028
2029 reader_fail:
2030   GST_WARNING ("Failed to read fields from buffer (too short?)");
2031   return ret;
2032 }
2033
2034
2035 static void
2036 serialize_geo_direction (GstExifWriter * writer, const GstTagList * taglist,
2037     const GstExifTagMatch * exiftag)
2038 {
2039   gdouble value;
2040
2041   if (!gst_tag_list_get_double (taglist, exiftag->gst_tag, &value)) {
2042     GST_WARNING ("Failed to get double from tag list for tag: %s",
2043         exiftag->gst_tag);
2044     return;
2045   }
2046
2047   /* first write the direction ref */
2048   write_exif_ascii_tag (writer, exiftag->complementary_tag, "T");
2049   gst_exif_writer_write_rational_tag_from_double (writer,
2050       exiftag->exif_tag, value);
2051 }
2052
2053 static gint
2054 deserialize_geo_direction (GstExifReader * exif_reader,
2055     GstByteReader * reader, const GstExifTagMatch * exiftag,
2056     GstExifTagData * tagdata)
2057 {
2058   GstExifTagData next_tagdata = { 0, };
2059   gint ret = 0;
2060
2061   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2062       exiftag->exif_tag);
2063
2064   if (exiftag->complementary_tag == tagdata->tag) {
2065     /* First should come the 'Ref' tags */
2066     if (tagdata->offset_as_data[0] == 'M') {
2067       GST_WARNING ("Magnetic direction is not supported");
2068       return ret;
2069     } else if (tagdata->offset_as_data[0] == 'T') {
2070       /* nop */
2071     } else {
2072       GST_WARNING ("Invalid Ref for direction or track %c",
2073           tagdata->offset_as_data[0]);
2074       return ret;
2075     }
2076   } else {
2077     GST_DEBUG ("No Direction Ref, using default=T");
2078     if (tagdata->tag == exiftag->exif_tag) {
2079       /* this is the main tag */
2080       tagdata_copy (&next_tagdata, tagdata);
2081     }
2082   }
2083
2084   if (next_tagdata.tag == 0) {
2085     /* now read the following tag that must be the exif_tag */
2086     if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2087       if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
2088         goto reader_fail;
2089     } else {
2090       if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
2091         goto reader_fail;
2092     }
2093
2094     if (exiftag->exif_tag != next_tagdata.tag) {
2095       GST_WARNING ("Unexpected tag");
2096       return ret;
2097     }
2098
2099     /* read the remaining tag entry data */
2100     if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
2101       ret = -1;
2102       goto reader_fail;
2103     }
2104     ret = 1;
2105   }
2106
2107   /* some checking */
2108   if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
2109     GST_WARNING ("Invalid type %d for 0x%x", next_tagdata.tag_type,
2110         next_tagdata.tag);
2111     return ret;
2112   }
2113   if (next_tagdata.count != 1) {
2114     GST_WARNING ("0x%x tag must have a single fraction, we have %u",
2115         next_tagdata.tag_type, next_tagdata.count);
2116     return ret;
2117   }
2118
2119   parse_exif_rational_tag (exif_reader,
2120       exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, 1, FALSE);
2121
2122   return ret;
2123
2124 reader_fail:
2125   GST_WARNING ("Failed to read fields from buffer (too short?)");
2126   return ret;
2127 }
2128
2129
2130 static void
2131 serialize_geo_elevation (GstExifWriter * writer, const GstTagList * taglist,
2132     const GstExifTagMatch * exiftag)
2133 {
2134   gdouble value;
2135
2136   if (!gst_tag_list_get_double (taglist, exiftag->gst_tag, &value)) {
2137     GST_WARNING ("Failed to get double from tag list for tag: %s",
2138         exiftag->gst_tag);
2139     return;
2140   }
2141
2142   /* first write the Ref */
2143   gst_exif_writer_write_byte_tag (writer,
2144       exiftag->complementary_tag, value >= 0 ? 0 : 1);
2145
2146   if (value < 0)
2147     value *= -1;
2148
2149   /* now the value */
2150   gst_exif_writer_write_rational_tag_from_double (writer,
2151       exiftag->exif_tag, value);
2152 }
2153
2154 static gint
2155 deserialize_geo_elevation (GstExifReader * exif_reader,
2156     GstByteReader * reader, const GstExifTagMatch * exiftag,
2157     GstExifTagData * tagdata)
2158 {
2159   GstExifTagData next_tagdata = { 0, };
2160   gint multiplier = 1;
2161   gint ret = 0;
2162
2163   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2164       exiftag->exif_tag);
2165
2166   if (exiftag->complementary_tag == tagdata->tag) {
2167     if (tagdata->offset_as_data[0] == 0) {
2168       /* NOP */
2169     } else if (tagdata->offset_as_data[0] == 1) {
2170       multiplier = -1;
2171     } else {
2172       GST_WARNING ("Invalid GPSAltitudeRef %u", tagdata->offset_as_data[0]);
2173       return ret;
2174     }
2175   } else {
2176     GST_DEBUG ("No GPSAltitudeRef, using default=0");
2177     if (tagdata->tag == exiftag->exif_tag) {
2178       tagdata_copy (&next_tagdata, tagdata);
2179     }
2180   }
2181
2182   /* now read the following tag that must be the exif_tag */
2183   if (next_tagdata.tag == 0) {
2184     if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2185       if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
2186         goto reader_fail;
2187     } else {
2188       if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
2189         goto reader_fail;
2190     }
2191
2192     if (exiftag->exif_tag != next_tagdata.tag) {
2193       GST_WARNING ("Unexpected tag");
2194       return ret;
2195     }
2196
2197     /* read the remaining tag entry data */
2198     if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
2199       ret = -1;
2200       goto reader_fail;
2201     }
2202     ret = 1;
2203   }
2204
2205   /* some checking */
2206   if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
2207     GST_WARNING ("Invalid type %d for 0x%x", next_tagdata.tag_type,
2208         next_tagdata.tag);
2209     return ret;
2210   }
2211   if (next_tagdata.count != 1) {
2212     GST_WARNING ("0x%x tag must have a single fraction, we have %u",
2213         next_tagdata.tag_type, next_tagdata.count);
2214     return ret;
2215   }
2216
2217   parse_exif_rational_tag (exif_reader,
2218       exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, multiplier,
2219       FALSE);
2220
2221   return ret;
2222
2223 reader_fail:
2224   GST_WARNING ("Failed to read fields from buffer (too short?)");
2225   return ret;
2226 }
2227
2228
2229 static void
2230 serialize_speed (GstExifWriter * writer, const GstTagList * taglist,
2231     const GstExifTagMatch * exiftag)
2232 {
2233   gdouble value;
2234
2235   if (!gst_tag_list_get_double (taglist, exiftag->gst_tag, &value)) {
2236     GST_WARNING ("Failed to get double from tag list for tag: %s",
2237         exiftag->gst_tag);
2238     return;
2239   }
2240
2241   /* first write the Ref */
2242   write_exif_ascii_tag (writer, exiftag->complementary_tag, "K");
2243
2244   /* now the value */
2245   gst_exif_writer_write_rational_tag_from_double (writer,
2246       exiftag->exif_tag, value * METERS_PER_SECOND_TO_KILOMETERS_PER_HOUR);
2247 }
2248
2249 static gint
2250 deserialize_speed (GstExifReader * exif_reader,
2251     GstByteReader * reader, const GstExifTagMatch * exiftag,
2252     GstExifTagData * tagdata)
2253 {
2254   GstExifTagData next_tagdata = { 0, };
2255   gdouble multiplier = 1;
2256   gint ret = 0;
2257
2258   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2259       exiftag->exif_tag);
2260
2261   if (exiftag->complementary_tag == tagdata->tag) {
2262     if (tagdata->offset_as_data[0] == 'K') {
2263       multiplier = KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND;
2264     } else if (tagdata->offset_as_data[0] == 'M') {
2265       multiplier = MILES_PER_HOUR_TO_METERS_PER_SECOND;
2266     } else if (tagdata->offset_as_data[0] == 'N') {
2267       multiplier = KNOTS_TO_METERS_PER_SECOND;
2268     } else {
2269       GST_WARNING ("Invalid GPSSpeedRed %c", tagdata->offset_as_data[0]);
2270       return ret;
2271     }
2272   } else {
2273     GST_DEBUG ("No GPSSpeedRef, using default=K");
2274     multiplier = KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND;
2275
2276     if (tagdata->tag == exiftag->exif_tag) {
2277       tagdata_copy (&next_tagdata, tagdata);
2278     }
2279   }
2280
2281   /* now read the following tag that must be the exif_tag */
2282   if (next_tagdata.tag == 0) {
2283     if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2284       if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
2285         goto reader_fail;
2286     } else {
2287       if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
2288         goto reader_fail;
2289     }
2290
2291     if (exiftag->exif_tag != next_tagdata.tag) {
2292       GST_WARNING ("Unexpected tag");
2293       return ret;
2294     }
2295
2296     /* read the remaining tag entry data */
2297     if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
2298       ret = -1;
2299       goto reader_fail;
2300     }
2301     ret = 1;
2302   }
2303
2304
2305   /* some checking */
2306   if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
2307     GST_WARNING ("Invalid type %d for 0x%x", next_tagdata.tag_type,
2308         next_tagdata.tag);
2309     return ret;
2310   }
2311   if (next_tagdata.count != 1) {
2312     GST_WARNING ("0x%x tag must have a single fraction, we have %u",
2313         next_tagdata.tag_type, next_tagdata.count);
2314     return ret;
2315   }
2316
2317   parse_exif_rational_tag (exif_reader,
2318       exiftag->gst_tag, next_tagdata.count, next_tagdata.offset, multiplier,
2319       FALSE);
2320
2321   return ret;
2322
2323 reader_fail:
2324   GST_WARNING ("Failed to read fields from buffer (too short?)");
2325   return ret;
2326 }
2327
2328 static void
2329 serialize_shutter_speed (GstExifWriter * writer, const GstTagList * taglist,
2330     const GstExifTagMatch * exiftag)
2331 {
2332   const GValue *value = NULL;
2333   gdouble num;
2334
2335   value = gst_tag_list_get_value_index (taglist, exiftag->gst_tag, 0);
2336   if (!value) {
2337     GST_WARNING ("Failed to get shutter speed from from tag list");
2338     return;
2339   }
2340   gst_util_fraction_to_double (gst_value_get_fraction_numerator (value),
2341       gst_value_get_fraction_denominator (value), &num);
2342
2343 #ifdef HAVE_LOG2
2344   num = -log2 (num);
2345 #else
2346   num = -log (num) / M_LN2;
2347 #endif
2348
2349   /* now the value */
2350   gst_exif_writer_write_signed_rational_tag_from_double (writer,
2351       exiftag->exif_tag, num);
2352 }
2353
2354 static gint
2355 deserialize_shutter_speed (GstExifReader * exif_reader,
2356     GstByteReader * reader, const GstExifTagMatch * exiftag,
2357     GstExifTagData * tagdata)
2358 {
2359   gint32 frac_n, frac_d;
2360   gdouble d;
2361   GValue value = { 0 };
2362
2363   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2364       exiftag->exif_tag);
2365
2366   if (!exif_reader_read_rational_tag (exif_reader, tagdata->count,
2367           tagdata->offset, TRUE, &frac_n, &frac_d))
2368     return 0;
2369
2370   gst_util_fraction_to_double (frac_n, frac_d, &d);
2371   d = pow (2, -d);
2372   gst_util_double_to_fraction (d, &frac_n, &frac_d);
2373
2374   g_value_init (&value, GST_TYPE_FRACTION);
2375   gst_value_set_fraction (&value, frac_n, frac_d);
2376   gst_tag_list_add_value (exif_reader->taglist, GST_TAG_MERGE_KEEP,
2377       exiftag->gst_tag, &value);
2378   g_value_unset (&value);
2379
2380   return 0;
2381 }
2382
2383 static void
2384 serialize_aperture_value (GstExifWriter * writer, const GstTagList * taglist,
2385     const GstExifTagMatch * exiftag)
2386 {
2387   gdouble num;
2388
2389   if (!gst_tag_list_get_double_index (taglist, exiftag->gst_tag, 0, &num)) {
2390     GST_WARNING ("Failed to get focal ratio from from tag list");
2391     return;
2392   }
2393 #ifdef HAVE_LOG2
2394   num = 2 * log2 (num);
2395 #else
2396   num = 2 * (log (num) / M_LN2);
2397 #endif
2398
2399   /* now the value */
2400   gst_exif_writer_write_rational_tag_from_double (writer,
2401       exiftag->exif_tag, num);
2402 }
2403
2404 static gint
2405 deserialize_aperture_value (GstExifReader * exif_reader,
2406     GstByteReader * reader, const GstExifTagMatch * exiftag,
2407     GstExifTagData * tagdata)
2408 {
2409   gint32 frac_n, frac_d;
2410   gdouble d;
2411
2412   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2413       exiftag->exif_tag);
2414
2415   if (!exif_reader_read_rational_tag (exif_reader, tagdata->count,
2416           tagdata->offset, FALSE, &frac_n, &frac_d))
2417     return 0;
2418
2419   gst_util_fraction_to_double (frac_n, frac_d, &d);
2420   d = pow (2, d / 2);
2421
2422   gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_KEEP,
2423       exiftag->gst_tag, d, NULL);
2424
2425   return 0;
2426 }
2427
2428 static void
2429 serialize_sensitivity_type (GstExifWriter * writer, const GstTagList * taglist,
2430     const GstExifTagMatch * exiftag)
2431 {
2432   /* we only support ISOSpeed as the sensitivity type (3) */
2433   gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, 3);
2434 }
2435
2436 static gint
2437 deserialize_sensitivity_type (GstExifReader * exif_reader,
2438     GstByteReader * reader, const GstExifTagMatch * exiftag,
2439     GstExifTagData * tagdata)
2440 {
2441   GstExifTagData *sensitivity = NULL;
2442   guint16 type_data;
2443
2444   if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2445     type_data = GST_READ_UINT16_LE (tagdata->offset_as_data);
2446   } else {
2447     type_data = GST_READ_UINT16_BE (tagdata->offset_as_data);
2448   }
2449
2450   if (type_data != 3) {
2451     GST_WARNING ("We only support SensitivityType=3");
2452     return 0;
2453   }
2454
2455   /* check the pending tags for the PhotographicSensitivity tag */
2456   sensitivity =
2457       gst_exif_reader_get_pending_tag (exif_reader,
2458       EXIF_TAG_PHOTOGRAPHIC_SENSITIVITY);
2459   if (sensitivity == NULL) {
2460     GST_WARNING ("PhotographicSensitivity tag not found");
2461     return 0;
2462   }
2463
2464   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2465       exiftag->exif_tag);
2466
2467   gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_KEEP,
2468       GST_TAG_CAPTURING_ISO_SPEED, sensitivity->offset_as_data, NULL);
2469
2470   return 0;
2471 }
2472
2473 static void
2474 serialize_flash (GstExifWriter * writer, const GstTagList * taglist,
2475     const GstExifTagMatch * exiftag)
2476 {
2477   gboolean flash_fired;
2478   const gchar *flash_mode;
2479   guint16 tagvalue = 0;
2480
2481   if (!gst_tag_list_get_boolean_index (taglist, exiftag->gst_tag, 0,
2482           &flash_fired)) {
2483     GST_WARNING ("Failed to get flash fired from from tag list");
2484     return;
2485   }
2486
2487   if (flash_fired)
2488     tagvalue = 1;
2489
2490   if (gst_tag_list_peek_string_index (taglist, GST_TAG_CAPTURING_FLASH_MODE, 0,
2491           &flash_mode)) {
2492     guint16 mode = 0;
2493     if (strcmp (flash_mode, "auto") == 0) {
2494       mode = 3;
2495     } else if (strcmp (flash_mode, "always") == 0) {
2496       mode = 1;
2497     } else if (strcmp (flash_mode, "never") == 0) {
2498       mode = 2;
2499     }
2500
2501     tagvalue = tagvalue | (mode << 3);
2502   } else {
2503     GST_DEBUG ("flash-mode not available");
2504   }
2505
2506   gst_exif_writer_write_short_tag (writer, exiftag->exif_tag, tagvalue);
2507 }
2508
2509 static gint
2510 deserialize_flash (GstExifReader * exif_reader,
2511     GstByteReader * reader, const GstExifTagMatch * exiftag,
2512     GstExifTagData * tagdata)
2513 {
2514   guint16 value = 0;
2515   guint mode = 0;
2516   const gchar *mode_str = NULL;
2517
2518   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2519       exiftag->exif_tag);
2520
2521   if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2522     value = GST_READ_UINT16_LE (tagdata->offset_as_data);
2523   } else {
2524     value = GST_READ_UINT16_BE (tagdata->offset_as_data);
2525   }
2526
2527   /* check flash fired */
2528   if (value & 0x1) {
2529     gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
2530         GST_TAG_CAPTURING_FLASH_FIRED, TRUE, NULL);
2531   } else {
2532     gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
2533         GST_TAG_CAPTURING_FLASH_FIRED, FALSE, NULL);
2534   }
2535
2536   mode = (value >> 3) & 0x3;
2537   if (mode == 1) {
2538     mode_str = "always";
2539   } else if (mode == 2) {
2540     mode_str = "never";
2541   } else if (mode == 3) {
2542     mode_str = "auto";
2543   }
2544
2545   if (mode_str)
2546     gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
2547         GST_TAG_CAPTURING_FLASH_MODE, mode_str, NULL);
2548
2549   return 0;
2550 }
2551
2552 static gint
2553 deserialize_resolution (GstExifReader * exif_reader,
2554     GstByteReader * reader, const GstExifTagMatch * exiftag,
2555     GstExifTagData * tagdata)
2556 {
2557   GstExifTagData *xres = NULL;
2558   GstExifTagData *yres = NULL;
2559   guint16 unit;
2560   gdouble multiplier;
2561
2562   if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
2563     unit = GST_READ_UINT16_LE (tagdata->offset_as_data);
2564   } else {
2565     unit = GST_READ_UINT16_BE (tagdata->offset_as_data);
2566   }
2567
2568   if (unit != 2 && unit != 3) {
2569     GST_WARNING ("Invalid resolution unit, ignoring PPI tags");
2570     return 0;
2571   }
2572
2573   xres = gst_exif_reader_get_pending_tag (exif_reader, EXIF_TAG_XRESOLUTION);
2574   yres = gst_exif_reader_get_pending_tag (exif_reader, EXIF_TAG_YRESOLUTION);
2575
2576   switch (unit) {
2577     case 2:                    /* inch */
2578       multiplier = 1;
2579       break;
2580     case 3:                    /* cm */
2581       multiplier = 1 / 2.54;
2582       break;
2583     default:
2584       multiplier = 1;
2585       g_assert_not_reached ();
2586       break;
2587   }
2588
2589   if (xres) {
2590     parse_exif_rational_tag (exif_reader, GST_TAG_IMAGE_HORIZONTAL_PPI,
2591         xres->count, xres->offset, multiplier, FALSE);
2592   }
2593   if (yres) {
2594     parse_exif_rational_tag (exif_reader, GST_TAG_IMAGE_VERTICAL_PPI,
2595         yres->count, yres->offset, multiplier, FALSE);
2596   }
2597
2598   return 0;
2599 }
2600
2601 static void
2602 serialize_scene_type (GstExifWriter * writer, const GstTagList * taglist,
2603     const GstExifTagMatch * exiftag)
2604 {
2605   const gchar *str;
2606   guint8 value = 0;
2607
2608   if (gst_tag_list_peek_string_index (taglist, GST_TAG_CAPTURING_SOURCE, 0,
2609           &str)) {
2610     if (strcmp (str, "dsc") == 0) {
2611       value = 0;
2612     }
2613   }
2614
2615   if (value != 0)
2616     write_exif_undefined_tag (writer, exiftag->exif_tag, &value, 1);
2617 }
2618
2619 static gint
2620 deserialize_scene_type (GstExifReader * exif_reader,
2621     GstByteReader * reader, const GstExifTagMatch * exiftag,
2622     GstExifTagData * tagdata)
2623 {
2624   guint8 value = 0;
2625
2626   GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
2627       exiftag->exif_tag);
2628
2629   value = GST_READ_UINT8 (tagdata->offset_as_data);
2630
2631   if (value == 1) {
2632     gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_KEEP,
2633         GST_TAG_CAPTURING_SOURCE, "dsc", NULL);
2634   }
2635
2636   return 0;
2637 }
2638
2639 static gint
2640 deserialize_add_to_pending_tags (GstExifReader * exif_reader,
2641     GstByteReader * reader, const GstExifTagMatch * exiftag,
2642     GstExifTagData * tagdata)
2643 {
2644   GST_LOG ("Adding %s tag in exif 0x%x to pending tags", exiftag->gst_tag,
2645       exiftag->exif_tag);
2646
2647   /* add it to the pending tags, as we can only parse it when we find the
2648    * SensitivityType tag */
2649   gst_exif_reader_add_pending_tag (exif_reader, tagdata);
2650   return 0;
2651 }
2652
2653 #undef EXIF_SERIALIZATION_FUNC
2654 #undef EXIF_DESERIALIZATION_FUNC
2655 #undef EXIF_SERIALIZATION_DESERIALIZATION_FUNC