jpegformat: Add exif support
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Thu, 29 Apr 2010 02:52:12 +0000 (23:52 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Wed, 9 Jun 2010 20:29:32 +0000 (17:29 -0300)
Adds exif writing support to jifmux.
Adds parsing support to jpegparse.

Fixes #614872

gst/jpegformat/gstjifmux.c
gst/jpegformat/gstjpegparse.c

index 15e26f9950b1a9143bec9706af241acc55d63ba7..43e562323a7f2d9367914d5ea1cd8fdfc22bddf5 100644 (file)
@@ -338,7 +338,8 @@ static gboolean
 gst_jif_mux_mangle_markers (GstJifMux * self)
 {
   gboolean modified = FALSE;
-  const GstTagList *tags;
+  GstTagList *tags = NULL;
+  gboolean cleanup_tags;
   GstJifMuxMarker *m;
   GList *node, *file_hdr = NULL, *frame_hdr = NULL, *scan_hdr = NULL;
   GList *app0_jfif = NULL, *app1_exif = NULL, *app1_xmp = NULL, *com = NULL;
@@ -367,7 +368,8 @@ gst_jif_mux_mangle_markers (GstJifMux * self)
         }
         break;
       case APP1:
-        if (m->size > 6 && !memcmp (m->data, "EXIF\0\0", 6)) {
+        if (m->size > 6 && (!memcmp (m->data, "EXIF\0\0", 6) ||
+                !memcmp (m->data, "Exif\0\0", 6))) {
           GST_DEBUG_OBJECT (self, "found APP1 EXIF");
           if (!app1_exif)
             app1_exif = node;
@@ -435,25 +437,66 @@ gst_jif_mux_mangle_markers (GstJifMux * self)
   /* else */
   /* remove JFIF if exists */
 
-  /* if we want combined or EXIF */
-  /* check if we don't have EXIF APP1 */
-  if (!app1_exif) {
-    /* exif_data = gst_tag_list_to_exif_buffer (tags); */
-    /* insert into self->markers list */
+  /* Existing exif tags will be removed and our own will be added */
+  if (!tags) {
+    tags = (GstTagList *) gst_tag_setter_get_tag_list (GST_TAG_SETTER (self));
+    cleanup_tags = FALSE;
   }
-  /* else */
-  /* remove EXIF if exists */
-
-  tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (self));
   if (!tags) {
     tags = gst_tag_list_new ();
   }
+
   /* FIXME: not happy with those
    * - else where we would use VIDEO_CODEC = "Jpeg"
    gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
    GST_TAG_VIDEO_CODEC, "image/jpeg", NULL);
    */
 
+  /* Add EXIF */
+  {
+    GstBuffer *exif_data;
+    guint8 *data;
+    GstJifMuxMarker *m;
+    GList *pos;
+
+    /* insert into self->markers list */
+    exif_data = gst_tag_list_to_exif_buffer_with_tiff_header (tags);
+    if (exif_data &&
+        GST_BUFFER_SIZE (exif_data) + 8 >= G_GUINT64_CONSTANT (65536)) {
+      GST_WARNING_OBJECT (self, "Exif tags data size exceed maximum size");
+      gst_buffer_unref (exif_data);
+      exif_data = NULL;
+    }
+    if (exif_data) {
+      data = g_malloc0 (GST_BUFFER_SIZE (exif_data) + 6);
+      memcpy (data, "Exif", 4);
+      memcpy (data + 6, GST_BUFFER_DATA (exif_data),
+          GST_BUFFER_SIZE (exif_data));
+      m = gst_jif_mux_new_marker (APP1, GST_BUFFER_SIZE (exif_data) + 6, data,
+          TRUE);
+      gst_buffer_unref (exif_data);
+
+      if (app1_exif) {
+        gst_jif_mux_marker_free ((GstJifMuxMarker *) app1_exif->data);
+        app1_exif->data = m;
+      } else {
+        pos = file_hdr;
+        if (app0_jfif)
+          pos = app0_jfif;
+        pos = g_list_next (pos);
+
+        self->priv->markers =
+            g_list_insert_before (self->priv->markers, pos, m);
+        if (pos) {
+          app1_exif = g_list_previous (pos);
+        } else {
+          app1_exif = g_list_last (self->priv->markers);
+        }
+      }
+      modified = TRUE;
+    }
+  }
+
   /* add xmp */
   xmp_data = gst_tag_list_to_xmp_buffer (tags, FALSE);
   if (xmp_data) {
@@ -506,6 +549,9 @@ gst_jif_mux_mangle_markers (GstJifMux * self)
 
     modified = TRUE;
   }
+
+  if (tags && cleanup_tags)
+    gst_tag_list_free (tags);
   return modified;
 }
 
index 4217c6aff831d6af85dfe4ed7f60c122915330f9..2653e7da7dcfbccffcb7c3cae5e42bb99650f6d4 100644 (file)
@@ -578,7 +578,32 @@ gst_jpeg_parse_read_header (GstJpegParse * parse, GstBuffer * buffer)
         if (!gst_byte_reader_get_string_utf8 (&reader, &id_str))
           goto error;
 
-        if (!strcmp (id_str, "http://ns.adobe.com/xap/1.0/")) {
+        if (!strcmp (id_str, "Exif")) {
+          const guint8 *exif_data = NULL;
+          guint exif_size = size - 2;
+          GstTagList *tags;
+          GstBuffer *buf;
+
+          /* skip padding */
+          gst_byte_reader_skip (&reader, 1);
+
+          /* handle exif metadata */
+          if (!gst_byte_reader_get_data (&reader, exif_size, &exif_data))
+            goto error;
+
+          buf = gst_buffer_new ();
+          GST_BUFFER_DATA (buf) = (guint8 *) exif_data;
+          GST_BUFFER_SIZE (buf) = exif_size;
+          tags = gst_tag_list_from_exif_buffer_with_tiff_header (buf);
+          gst_buffer_unref (buf);
+          if (tags) {
+            GST_INFO_OBJECT (parse, "post exif metadata");
+            gst_element_found_tags_for_pad (GST_ELEMENT_CAST (parse),
+                parse->priv->srcpad, tags);
+          }
+          GST_LOG_OBJECT (parse, "parsed marker %x: '%s' %u bytes",
+              marker, id_str, size - 2);
+        } else if (!strcmp (id_str, "http://ns.adobe.com/xap/1.0/")) {
           const guint8 *xmp_data = NULL;
           guint xmp_size = size - 2 - 29;
           GstTagList *tags;