Added new module for common functions. Using GST_TYPE_FRACTION for Exif (S)Rational...
authorEdgard Lima <edgard.lima@indt.org.br>
Fri, 14 Dec 2007 18:18:37 +0000 (18:18 +0000)
committerEdgard Lima <edgard.lima@indt.org.br>
Fri, 14 Dec 2007 18:18:37 +0000 (18:18 +0000)
Original commit message from CVS:
Added new module for common functions. Using GST_TYPE_FRACTION for Exif (S)Rational types.

15 files changed:
ChangeLog
ext/metadata/Makefile.am
ext/metadata/TODO
ext/metadata/gstmetadata.c
ext/metadata/gstmetadatacommon.c [new file with mode: 0644]
ext/metadata/gstmetadatacommon.h [new file with mode: 0644]
ext/metadata/gstmetadatademux.c [new file with mode: 0644]
ext/metadata/gstmetadatademux.h [new file with mode: 0644]
ext/metadata/gstmetadatamux.c
ext/metadata/gstmetadatamux.h
ext/metadata/gstmetadataparse.c [deleted file]
ext/metadata/gstmetadataparse.h [deleted file]
ext/metadata/metadataexif.c
ext/metadata/metadatatags.c
ext/metadata/test/metadata_editor.c

index d1a433416294907ee37af5aba23fbcb3d21dca2b..ef24b9ae1be771a2d79ab8fa78cb15c627959f81 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2007-12-14  Edgard Lima,,,,  <edgard.lima@indt.org.br>
+
+       * ext/metadata/Makefile.am:
+       * ext/metadata/TODO:
+       * ext/metadata/gstmetadata.c:
+       * ext/metadata/gstmetadatacommon.c:
+       * ext/metadata/gstmetadatacommon.h:
+       * ext/metadata/gstmetadatademux.c:
+       * ext/metadata/gstmetadatademux.h:
+       * ext/metadata/gstmetadatamux.c:
+       * ext/metadata/gstmetadatamux.h:
+       * ext/metadata/gstmetadataparse.c:
+       * ext/metadata/gstmetadataparse.h:
+       * ext/metadata/metadataexif.c:
+       * ext/metadata/metadatatags.c:
+       * ext/metadata/test/metadata_editor.c:
+         Added new module for common functions. Using GST_TYPE_FRACTION for
+         Exif (S)Rational types.
+
 2007-12-14  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
 
        * gst/mpegtsparse/mpegtspacketizer.c:
index 753aceff9021c31243fb5b9ad886ee17e21c7e2b..aa6fac48914d5c6a306a68f2280f40c88eb9ee4c 100644 (file)
@@ -1,7 +1,8 @@
 plugin_LTLIBRARIES = libgstmetadata.la
 
 libgstmetadata_la_SOURCES =    gstmetadata.c       \
-                               gstmetadataparse.c  \
+                               gstmetadatacommon.c \
+                               gstmetadatademux.c  \
                                metadata.c          \
                                metadataparsejpeg.c \
                                metadatamuxjpeg.c   \
@@ -15,11 +16,15 @@ libgstmetadata_la_SOURCES = gstmetadata.c       \
                                gstmetadatamux.c    \
                                metadatatags.c
 
+libgstmetadata_ladir = $(includedir)/gstreamer-@GST_MAJORMINOR@/metadata
+libgstmetadata_la_HEADERS = metadatatags.h
+
 libgstmetadata_la_CFLAGS = $(METADATA_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS)
 libgstmetadata_la_LIBADD = $(METADATA_LIBS) -lgsttag-@GST_MAJORMINOR@ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS)
 libgstmetadata_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 
-noinst_HEADERS =       gstmetadataparse.h   \
+noinst_HEADERS =       gstmetadatademux.h   \
+                       gstmetadatacommon.h  \
                        metadata.h           \
                        metadataparsejpeg.h  \
                        metadatamuxjpeg.h    \
index 8b51c87131e63fb829d96f6fc5a71ab039e64d22..d44c2f331dc615a44cbfba838eab08105919cbb8 100644 (file)
@@ -4,10 +4,9 @@ This file contains a list of things to be done as well some open issues (questio
 TODO:
 
 1- Add individual tags IPTC and XMP (and more for EXIF)
-2- Use GST_TYPE_FRACTION for Rational and SRational (metadataexif.c)
-3- Get properties like 'width' and 'height' from caps
-4- Review the code (in order to move to gst-plugins-good)
-5- Document how the plugin works (atchitecture and interaction beteween modules)
+2- Get properties like 'width' and 'height' from caps
+3- Review the code (in order to move to gst-plugins-good)
+4- Document how the plugin works (atchitecture and interaction beteween modules)
 
 OPEN ISSUES:
 
@@ -15,4 +14,7 @@ OPEN ISSUES:
 2- How to change metadata when the orignal image was modified.
   ex: file.jpeg has XMP, then we do filesrc ! metadataparse ! jpegdec ! pngenc ! metadatamux ! files
   is the metadata still valid? which fields are no valid anymore?
+3- Add GST_TYPE_FRACTION support for GStreamer TAGS
+4- Have parse, demux and mux? (or just demux and must) see issue (5)
+5- After decided issue (4) put more things to gstmetadatacommon (or else create a Class)
 
index 4b150a2657cea7309b76f55bdc972215794c6c2d..2e729252db1b8b660f54f1656946f1ae87f354d5 100644 (file)
@@ -49,7 +49,7 @@
 
 #include "metadatatags.h"
 
-extern gboolean gst_metadata_parse_plugin_init (GstPlugin * plugin);
+extern gboolean gst_metadata_demux_plugin_init (GstPlugin * plugin);
 extern gboolean gst_metadata_mux_plugin_init (GstPlugin * plugin);
 
 GST_DEBUG_CATEGORY_EXTERN (gst_metadata_exif_debug);
@@ -71,7 +71,7 @@ plugin_init (GstPlugin * plugin)
 
   metadata_tags_register ();
 
-  ret = gst_metadata_parse_plugin_init (plugin);
+  ret = gst_metadata_demux_plugin_init (plugin);
 
   ret = ret && gst_metadata_mux_plugin_init (plugin);
 
@@ -82,5 +82,5 @@ plugin_init (GstPlugin * plugin)
 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
     GST_VERSION_MINOR,
     "metadata",
-    "Metadata (EXIF, IPTC and XMP) image (JPEG, TIFF) parser and muxer",
+    "Metadata (EXIF, IPTC and XMP) image (JPEG, TIFF) demuxer and muxer",
     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/metadata/gstmetadatacommon.c b/ext/metadata/gstmetadatacommon.c
new file mode 100644 (file)
index 0000000..07704ce
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * GStreamer
+ * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:metadatamux-metadata
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch -v -m filesrc location=./test.jpeg ! metadatamux ! fakesink silent=TRUE
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+/*
+ * static functions declaration
+ */
+
+#include "gstmetadatacommon.h"
+
+/*
+ * offset - offset of buffer in original stream
+ * size - size of buffer
+ * seg_offset - offset of segment in original stream
+ * seg_size - size of segment
+ * boffset - offset inside buffer where segment starts (-1 for no intersection)
+ * bsize - size of intersection
+ * seg_binter - if segment start inside buffer is zero. if segment start before
+ *               buffer and intersect, it is the offset inside segment.
+ *
+ * ret:
+ *  -1 - segment before buffer
+ *   0 - segment intersects
+ *   1 - segment after buffer
+ */
+
+static int
+gst_metadata_common_get_strip_seg (const gint64 offset, guint32 size,
+    const gint64 seg_offset, const guint32 seg_size,
+    gint64 * boffset, guint32 * bsize, guint32 * seg_binter)
+{
+  int ret = -1;
+
+  *boffset = -1;
+  *bsize = 0;
+  *seg_binter = -1;
+
+  /* all segment after buffer */
+  if (seg_offset >= offset + size) {
+    ret = 1;
+    goto done;
+  }
+
+  if (seg_offset < offset) {
+    /* segment start somewhere before buffer */
+
+    /* all segment before buffer */
+    if (seg_offset + seg_size <= offset) {
+      ret = -1;
+      goto done;
+    }
+
+    *seg_binter = offset - seg_offset;
+    *boffset = 0;
+
+    /* FIXME : optimize to >= size -> = size */
+    if (seg_offset + seg_size >= offset + size) {
+      /* segment cover all buffer */
+      *bsize = size;
+    } else {
+      /* segment goes from start of buffer to somewhere before end */
+      *bsize = seg_size - *seg_binter;
+    }
+
+    ret = 0;
+
+  } else {
+    /* segment start somewhere into buffer */
+
+    *boffset = seg_offset - offset;
+    *seg_binter = 0;
+
+    if (seg_offset + seg_size <= offset + size) {
+      /* all segment into buffer */
+      *bsize = seg_size;
+    } else {
+      *bsize = size - *boffset;
+    }
+
+    ret = 0;
+
+  }
+
+done:
+
+  return ret;
+
+}
+
+/*
+ * extern functions declaration
+ */
+
+void
+gst_metadata_common_init (GstMetadataCommon * common, gboolean parse,
+    guint8 options)
+{
+  metadata_init (&common->metadata, parse, options);
+}
+
+void
+gst_metadata_common_dispose (GstMetadataCommon * common)
+{
+  if (common->append_buffer) {
+    gst_buffer_unref (common->append_buffer);
+    common->append_buffer = NULL;
+  }
+  metadata_dispose (&common->metadata);
+}
+
+/*
+
+/*
+ *  TRUE -> buffer striped or injeted
+ *  FALSE -> buffer unmodified
+ */
+
+gboolean
+gst_metadata_common_strip_push_buffer (GstMetadataCommon * common,
+    gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf)
+{
+  MetadataChunk *strip = common->metadata.strip_chunks.chunk;
+  MetadataChunk *inject = common->metadata.inject_chunks.chunk;
+  const gsize strip_len = common->metadata.strip_chunks.len;
+  const gsize inject_len = common->metadata.inject_chunks.len;
+
+  gboolean buffer_reallocated = FALSE;
+
+  guint32 size_buf_in = GST_BUFFER_SIZE (*buf);
+
+  gint64 *boffset_strip = NULL;
+  guint32 *bsize_strip = NULL;
+  guint32 *seg_binter_strip = NULL;
+
+  int i, j;
+  gboolean need_free_strip = FALSE;
+
+  guint32 striped_bytes = 0;
+  guint32 injected_bytes = 0;
+
+  guint32 prepend_size = prepend && *prepend ? GST_BUFFER_SIZE (*prepend) : 0;
+
+  if (inject_len) {
+
+    for (i = 0; i < inject_len; ++i) {
+      int res;
+
+      if (inject[i].offset_orig >= offset_orig) {
+        if (inject[i].offset_orig < offset_orig + size_buf_in) {
+          injected_bytes += inject[i].size;
+        } else {
+          /* segment is after size (segments are sorted) */
+          break;
+        }
+      }
+    }
+
+  }
+
+  /*
+   * strip segments
+   */
+
+  if (strip_len == 0)
+    goto inject;
+
+  if (G_UNLIKELY (strip_len > 16)) {
+    boffset_strip = g_new (gint64, strip_len);
+    bsize_strip = g_new (guint32, strip_len);
+    seg_binter_strip = g_new (guint32, strip_len);
+    need_free_strip = TRUE;
+  } else {
+    boffset_strip = g_alloca (sizeof (boffset_strip[0]) * strip_len);
+    bsize_strip = g_alloca (sizeof (bsize_strip[0]) * strip_len);
+    seg_binter_strip = g_alloca (sizeof (seg_binter_strip[0]) * strip_len);
+  }
+
+  memset (bsize_strip, 0x00, sizeof (bsize_strip[0]) * strip_len);
+
+  for (i = 0; i < strip_len; ++i) {
+    int res;
+
+    res = gst_metadata_common_get_strip_seg (offset_orig, size_buf_in,
+        strip[i].offset_orig, strip[i].size, &boffset_strip[i], &bsize_strip[i],
+        &seg_binter_strip[i]);
+
+    /* segment is after size (segments are sorted) */
+    striped_bytes += bsize_strip[i];
+    if (res > 0) {
+      break;
+    }
+
+  }
+
+  if (striped_bytes) {
+
+    guint8 *data;
+
+    if (!buffer_reallocated) {
+      buffer_reallocated = TRUE;
+      if (injected_bytes + prepend_size > striped_bytes) {
+        GstBuffer *new_buf =
+            gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes +
+            prepend_size - striped_bytes);
+
+        memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf),
+            GST_BUFFER_SIZE (*buf));
+
+        gst_buffer_unref (*buf);
+        *buf = new_buf;
+
+      } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) {
+        GstBuffer *new_buf = gst_buffer_copy (*buf);
+
+        gst_buffer_unref (*buf);
+        *buf = new_buf;
+        GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
+        GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes;
+      }
+    }
+
+    data = GST_BUFFER_DATA (*buf);
+
+    striped_bytes = 0;
+    for (i = 0; i < strip_len; ++i) {
+      /* intersect */
+      if (bsize_strip[i]) {
+        memmove (data + boffset_strip[i] - striped_bytes,
+            data + boffset_strip[i] + bsize_strip[i] - striped_bytes,
+            size_buf_in - boffset_strip[i] - bsize_strip[i]);
+        striped_bytes += bsize_strip[i];
+      }
+    }
+    size_buf_in -= striped_bytes;
+
+  }
+
+inject:
+
+  /*
+   * inject segments
+   */
+
+  if (inject_len) {
+
+    guint8 *data;
+    guint32 striped_so_far;
+
+    if (!buffer_reallocated) {
+      buffer_reallocated = TRUE;
+      if (injected_bytes + prepend_size > striped_bytes) {
+        GstBuffer *new_buf =
+            gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes +
+            prepend_size - striped_bytes);
+
+        memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf),
+            GST_BUFFER_SIZE (*buf));
+
+        gst_buffer_unref (*buf);
+        *buf = new_buf;
+
+      } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) {
+        GstBuffer *new_buf = gst_buffer_copy (*buf);
+
+        gst_buffer_unref (*buf);
+        *buf = new_buf;
+        GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
+        GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes;
+      }
+    }
+
+    data = GST_BUFFER_DATA (*buf);
+
+    injected_bytes = 0;
+    striped_so_far = 0;
+    j = 0;
+    for (i = 0; i < inject_len; ++i) {
+      int res;
+
+      while (j < strip_len) {
+        if (strip[j].offset_orig < inject[i].offset_orig)
+          striped_so_far += bsize_strip[j++];
+        else
+          break;
+      }
+
+      if (inject[i].offset_orig >= offset_orig) {
+        if (inject[i].offset_orig <
+            offset_orig + size_buf_in + striped_bytes - injected_bytes) {
+          /* insert */
+          guint32 buf_off =
+              inject[i].offset_orig - offset_orig - striped_so_far +
+              injected_bytes;
+          memmove (data + buf_off + inject[i].size, data + buf_off,
+              size_buf_in - buf_off);
+          memcpy (data + buf_off, inject[i].data, inject[i].size);
+          injected_bytes += inject[i].size;
+          size_buf_in += inject[i].size;
+        } else {
+          /* segment is after size (segments are sorted) */
+          break;
+        }
+      }
+    }
+
+  }
+
+
+done:
+
+  if (prepend_size) {
+    if (injected_bytes == 0 && striped_bytes == 0) {
+      GstBuffer *new_buf =
+          gst_buffer_new_and_alloc (size_buf_in + prepend_size);
+
+      memcpy (GST_BUFFER_DATA (new_buf) + prepend_size, GST_BUFFER_DATA (*buf),
+          size_buf_in);
+
+      gst_buffer_unref (*buf);
+      *buf = new_buf;
+    } else {
+      memmove (GST_BUFFER_DATA (*buf) + prepend_size, GST_BUFFER_DATA (*buf),
+          size_buf_in);
+    }
+    memcpy (GST_BUFFER_DATA (*buf), GST_BUFFER_DATA (*prepend), prepend_size);
+    gst_buffer_unref (*prepend);
+    *prepend = NULL;
+  }
+
+  GST_BUFFER_SIZE (*buf) = size_buf_in + prepend_size;
+
+  if (need_free_strip) {
+    g_free (boffset_strip);
+    g_free (bsize_strip);
+    g_free (seg_binter_strip);
+  }
+
+  return injected_bytes || striped_bytes;
+
+}
+
+/*
+ * pos - position in stream striped
+ * orig_pos - position in original stream
+ * return TRUE - position in original buffer
+ *        FALSE - position in inserted chunk
+ */
+gboolean
+gst_metadata_common_translate_pos_to_orig (GstMetadataCommon * common,
+    gint64 pos, gint64 * orig_pos, GstBuffer ** buf)
+{
+  MetadataChunk *strip = common->metadata.strip_chunks.chunk;
+  MetadataChunk *inject = common->metadata.inject_chunks.chunk;
+  const gsize strip_len = common->metadata.strip_chunks.len;
+  const gsize inject_len = common->metadata.inject_chunks.len;
+  const gint64 duration_orig = common->duration_orig;
+  const gint64 duration = common->duration;
+
+  int i;
+  gboolean ret = TRUE;
+  guint64 new_buf_size = 0;
+  guint64 injected_before = 0;
+
+  if (G_UNLIKELY (pos == -1)) {
+    *orig_pos = -1;
+    return TRUE;
+  } else if (G_UNLIKELY (pos >= duration)) {
+    /* this should never happen */
+    *orig_pos = duration_orig;
+    return TRUE;
+  }
+
+  /* calculate for injected */
+
+  /* just calculate size */
+  *orig_pos = pos;              /* save pos */
+  for (i = 0; i < inject_len; ++i) {
+    /* check if pos in inside chunk */
+    if (inject[i].offset <= pos) {
+      if (pos < inject[i].offset + inject[i].size) {
+        /* orig pos points after insert chunk */
+        new_buf_size += inject[i].size;
+        /* put pos after current chunk */
+        pos = inject[i].offset + inject[i].size;
+        ret = FALSE;
+      } else {
+        /* in case pos is not inside a injected chunk */
+        injected_before += inject[i].size;
+      }
+    } else {
+      break;
+    }
+  }
+
+  /* alloc buffer and calcute original pos */
+  if (buf && ret == FALSE) {
+    guint8 *data;
+
+    if (*buf)
+      gst_buffer_unref (*buf);
+    *buf = gst_buffer_new_and_alloc (new_buf_size);
+    data = GST_BUFFER_DATA (*buf);
+    pos = *orig_pos;            /* recover saved pos */
+    for (i = 0; i < inject_len; ++i) {
+      if (inject[i].offset > pos) {
+        break;
+      }
+      if (inject[i].offset <= pos && pos < inject[i].offset + inject[i].size) {
+        memcpy (data, inject[i].data, inject[i].size);
+        data += inject[i].size;
+        pos = inject[i].offset + inject[i].size;
+        /* out position after insert chunk orig */
+        *orig_pos = inject[i].offset_orig + inject[i].size;
+      }
+    }
+  }
+
+  if (ret == FALSE) {
+    /* if it inside a injected is already done */
+    goto done;
+  }
+
+  /* calculate for striped */
+
+  *orig_pos = pos - injected_before;
+  for (i = 0; i < strip_len; ++i) {
+    if (strip[i].offset_orig > pos) {
+      break;
+    }
+    *orig_pos += strip[i].size;
+  }
+
+done:
+
+  if (G_UNLIKELY (*orig_pos >= duration_orig)) {
+    *orig_pos = duration_orig - 1;
+  }
+
+  return ret;
+
+}
+
+/*
+ * return:
+ *   -1 -> error
+ *    0 -> succeded
+ *    1 -> need more data
+ */
+
+gboolean
+gst_metadata_common_calculate_offsets (GstMetadataCommon * common)
+{
+  int i, j;
+  guint32 append_size;
+  guint32 bytes_striped, bytes_inject;
+  MetadataChunk *strip = common->metadata.strip_chunks.chunk;
+  MetadataChunk *inject = common->metadata.inject_chunks.chunk;
+  gsize strip_len;
+  gsize inject_len;
+
+  if (common->state != MT_STATE_PARSED)
+    return FALSE;
+
+  metadata_lazy_update (&common->metadata);
+
+  strip_len = common->metadata.strip_chunks.len;
+  inject_len = common->metadata.inject_chunks.len;
+
+  bytes_striped = 0;
+  bytes_inject = 0;
+
+  /* calculate the new position off injected chunks */
+  j = 0;
+  for (i = 0; i < inject_len; ++i) {
+    for (; j < strip_len; ++j) {
+      if (strip[j].offset_orig >= inject[i].offset_orig) {
+        break;
+      }
+      bytes_striped += strip[j].size;
+    }
+    inject[i].offset = inject[i].offset_orig - bytes_striped + bytes_inject;
+    bytes_inject += inject[i].size;
+  }
+
+  /* calculate append (doesnt make much sense, but, anyway..) */
+  append_size = 0;
+  for (i = inject_len - 1; i >= 0; --i) {
+    if (inject[i].offset_orig == common->duration_orig)
+      append_size += inject[i].size;
+    else
+      break;
+  }
+  if (append_size) {
+    guint8 *data;
+
+    common->append_buffer = gst_buffer_new_and_alloc (append_size);
+    GST_BUFFER_FLAG_SET (common->append_buffer, GST_BUFFER_FLAG_READONLY);
+    data = GST_BUFFER_DATA (common->append_buffer);
+    for (i = inject_len - 1; i >= 0; --i) {
+      if (inject[i].offset_orig == common->duration_orig) {
+        memcpy (data, inject[i].data, inject[i].size);
+        data += inject[i].size;
+      } else {
+        break;
+      }
+    }
+  }
+
+  if (common->duration_orig) {
+    common->duration = common->duration_orig;
+    for (i = 0; i < inject_len; ++i) {
+      common->duration += inject[i].size;
+    }
+    for (i = 0; i < strip_len; ++i) {
+      common->duration -= strip[i].size;
+    }
+  }
+
+  return TRUE;
+
+}
+
+void
+gst_metadata_common_update_segment_with_new_buffer (GstMetadataCommon * common,
+    guint8 ** buf, guint32 * size, MetadataChunkType type)
+{
+  int i;
+  MetadataChunk *inject = common->metadata.inject_chunks.chunk;
+  const gsize inject_len = common->metadata.inject_chunks.len;
+
+  if (!(buf && size))
+    goto done;
+  if (*buf == 0)
+    goto done;
+  if (*size == 0)
+    goto done;
+
+  for (i = 0; i < inject_len; ++i) {
+    if (inject[i].type == type) {
+      inject[i].size = *size;
+      if (inject[i].data)
+        g_free (inject[i].data);
+      inject[i].data = *buf;
+      *size = 0;
+      *buf = 0;
+      break;
+    }
+  }
+
+done:
+
+  return;
+
+}
+
+const gchar *
+gst_metadata_common_get_type_name (int img_type)
+{
+  gchar *type_name = NULL;
+
+  switch (img_type) {
+    case IMG_JPEG:
+      type_name = "jpeg";
+      break;
+    case IMG_PNG:
+      type_name = "png";
+      break;
+    default:
+      type_name = "invalid type";
+      break;
+  }
+  return type_name;
+}
diff --git a/ext/metadata/gstmetadatacommon.h b/ext/metadata/gstmetadatacommon.h
new file mode 100644 (file)
index 0000000..7f2169c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * GStreamer
+ * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_METADATA_COMMON_H__
+#define __GST_METADATA_COMMON_H__
+
+#include "metadata.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstMetadataCommon GstMetadataCommon;
+
+typedef enum _tag_MetadataState
+{
+  MT_STATE_NULL,                /* still need to check media type */
+  MT_STATE_PARSED
+} MetadataState;
+
+struct _GstMetadataCommon {
+
+  MetaData metadata;
+  gint64 duration_orig;     /* durarion of stream */
+  gint64 duration;          /* durarion of modified stream */
+
+  GstBuffer * append_buffer;
+  MetadataState state;
+
+};
+
+extern void
+gst_metadata_common_init(GstMetadataCommon *common, gboolean parse, guint8 options);
+
+extern void
+gst_metadata_common_dispose(GstMetadataCommon *common);
+
+extern gboolean
+gst_metadata_common_strip_push_buffer (GstMetadataCommon *common, gint64 offset_orig,
+    GstBuffer ** prepend, GstBuffer ** buf);
+
+extern gboolean
+gst_metadata_common_translate_pos_to_orig (GstMetadataCommon *common,
+    gint64 pos, gint64 * orig_pos, GstBuffer ** buf);
+
+extern gboolean
+gst_metadata_common_calculate_offsets (GstMetadataCommon *common);
+
+extern void
+gst_metadata_common_update_segment_with_new_buffer (GstMetadataCommon *common,
+    guint8 ** buf, guint32 * size, MetadataChunkType type);
+
+extern const gchar *
+gst_metadata_common_get_type_name (int img_type);
+
+G_END_DECLS
+#endif /* __GST_METADATA_COMMON_H__ */
diff --git a/ext/metadata/gstmetadatademux.c b/ext/metadata/gstmetadatademux.c
new file mode 100644 (file)
index 0000000..9e53be5
--- /dev/null
@@ -0,0 +1,1291 @@
+/*
+ * GStreamer
+ * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:metadatademux-metadata
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch -v -m filesrc location=./test.jpeg ! metadatademux ! fakesink silent=TRUE
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gst/gst.h>
+
+#include "gstmetadatademux.h"
+
+#include "metadataexif.h"
+
+#include "metadataiptc.h"
+
+#include "metadataxmp.h"
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_metadata_demux_debug);
+#define GST_CAT_DEFAULT gst_metadata_demux_debug
+
+#define GOTO_DONE_IF_NULL(ptr) do { if ( NULL == (ptr) ) goto done; } while(FALSE)
+#define GOTO_DONE_IF_NULL_AND_FAIL(ptr, ret) do { if ( NULL == (ptr) ) { (ret) = FALSE; goto done; } } while(FALSE)
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0,
+  ARG_EXIF,
+  ARG_IPTC,
+  ARG_XMP
+};
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/jpeg, "
+        "tags-extracted = (bool) false;"
+        "image/png, " "tags-extracted = (bool) false")
+    );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/jpeg, "
+        "tags-extracted = (bool) true;"
+        "image/png, " "tags-extracted = (bool) true")
+    );
+
+GST_BOILERPLATE (GstMetadataDemux, gst_metadata_demux, GstElement,
+    GST_TYPE_ELEMENT);
+
+static GstMetadataDemuxClass *metadata_parent_class = NULL;
+
+static void gst_metadata_demux_dispose (GObject * object);
+
+static void gst_metadata_demux_finalize (GObject * object);
+
+static void gst_metadata_demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_metadata_demux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn
+gst_metadata_demux_change_state (GstElement * element,
+    GstStateChange transition);
+
+static GstCaps *gst_metadata_demux_get_caps (GstPad * pad);
+static gboolean gst_metadata_demux_set_caps (GstPad * pad, GstCaps * caps);
+static gboolean gst_metadata_demux_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_metadata_demux_sink_event (GstPad * pad, GstEvent * event);
+
+static GstFlowReturn gst_metadata_demux_chain (GstPad * pad, GstBuffer * buf);
+
+static gboolean gst_metadata_demux_checkgetrange (GstPad * srcpad);
+
+static GstFlowReturn
+gst_metadata_demux_get_range (GstPad * pad, guint64 offset_orig, guint size,
+    GstBuffer ** buf);
+
+static gboolean gst_metadata_demux_sink_activate (GstPad * pad);
+
+static gboolean
+gst_metadata_demux_src_activate_pull (GstPad * pad, gboolean active);
+
+static gboolean gst_metadata_demux_pull_range_demux (GstMetadataDemux * filter);
+
+static void gst_metadata_demux_init_members (GstMetadataDemux * filter);
+static void gst_metadata_demux_dispose_members (GstMetadataDemux * filter);
+
+static gboolean
+gst_metadata_demux_configure_srccaps (GstMetadataDemux * filter);
+
+static gboolean gst_metadata_demux_configure_caps (GstMetadataDemux * filter);
+
+static int
+gst_metadata_demux_parse (GstMetadataDemux * filter, const guint8 * buf,
+    guint32 size);
+
+static void gst_metadata_demux_send_tags (GstMetadataDemux * filter);
+
+static const GstQueryType *gst_metadata_demux_get_query_types (GstPad * pad);
+
+static gboolean gst_metadata_demux_src_query (GstPad * pad, GstQuery * query);
+
+static void
+gst_metadata_demux_base_init (gpointer gclass)
+{
+  static GstElementDetails element_details = {
+    "Metadata demuxr",
+    "Demuxr/Extracter/Metadata",
+    "Send metadata tags (EXIF, IPTC and XMP) and remove metadata chunks from stream",
+    "Edgard Lima <edgard.lima@indt.org.br>"
+  };
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&src_factory));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sink_factory));
+  gst_element_class_set_details (element_class, &element_details);
+}
+
+/* initialize the plugin's class */
+static void
+gst_metadata_demux_class_init (GstMetadataDemuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  metadata_parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_metadata_demux_dispose);
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_metadata_demux_finalize);
+
+  gobject_class->set_property = gst_metadata_demux_set_property;
+  gobject_class->get_property = gst_metadata_demux_get_property;
+
+  g_object_class_install_property (gobject_class, ARG_EXIF,
+      g_param_spec_boolean ("exif", "EXIF", "Send EXIF metadata ?",
+          TRUE, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, ARG_IPTC,
+      g_param_spec_boolean ("iptc", "IPTC", "Send IPTC metadata ?",
+          TRUE, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, ARG_XMP,
+      g_param_spec_boolean ("xmp", "XMP", "Send XMP metadata ?",
+          TRUE, G_PARAM_READWRITE));
+
+  gstelement_class->change_state = gst_metadata_demux_change_state;
+
+}
+
+/* initialize the new element
+ * instantiate pads and add them to element
+ * set functions
+ * initialize structure
+ */
+static void
+gst_metadata_demux_init (GstMetadataDemux * filter,
+    GstMetadataDemuxClass * gclass)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
+
+  /* sink pad */
+
+  filter->sinkpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "sink"), "sink");
+  gst_pad_set_setcaps_function (filter->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_metadata_demux_set_caps));
+  gst_pad_set_getcaps_function (filter->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_metadata_demux_get_caps));
+  gst_pad_set_event_function (filter->sinkpad, gst_metadata_demux_sink_event);
+  gst_pad_set_chain_function (filter->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_metadata_demux_chain));
+  gst_pad_set_activate_function (filter->sinkpad,
+      gst_metadata_demux_sink_activate);
+
+  /* source pad */
+
+  filter->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "src"), "src");
+  gst_pad_set_getcaps_function (filter->srcpad,
+      GST_DEBUG_FUNCPTR (gst_metadata_demux_get_caps));
+  gst_pad_set_event_function (filter->srcpad, gst_metadata_demux_src_event);
+  gst_pad_set_query_function (filter->srcpad,
+      GST_DEBUG_FUNCPTR (gst_metadata_demux_src_query));
+  gst_pad_set_query_type_function (filter->srcpad,
+      GST_DEBUG_FUNCPTR (gst_metadata_demux_get_query_types));
+  gst_pad_use_fixed_caps (filter->srcpad);
+
+  gst_pad_set_checkgetrange_function (filter->srcpad,
+      GST_DEBUG_FUNCPTR (gst_metadata_demux_checkgetrange));
+  gst_pad_set_getrange_function (filter->srcpad, gst_metadata_demux_get_range);
+
+  gst_pad_set_activatepull_function (filter->srcpad,
+      GST_DEBUG_FUNCPTR (gst_metadata_demux_src_activate_pull));
+  /* addind pads */
+
+  gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
+  gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
+
+  metadataparse_xmp_init ();
+  /* init members */
+
+  filter->options = META_OPT_EXIF | META_OPT_IPTC | META_OPT_XMP;
+
+  gst_metadata_demux_init_members (filter);
+
+}
+
+static void
+gst_metadata_demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMetadataDemux *filter = GST_METADATA_DEMUX (object);
+
+  switch (prop_id) {
+    case ARG_EXIF:
+      if (g_value_get_boolean (value))
+        filter->options |= META_OPT_EXIF;
+      else
+        filter->options &= ~META_OPT_EXIF;
+      break;
+    case ARG_IPTC:
+      if (g_value_get_boolean (value))
+        filter->options |= META_OPT_IPTC;
+      else
+        filter->options &= ~META_OPT_IPTC;
+      break;
+    case ARG_XMP:
+      if (g_value_get_boolean (value))
+        filter->options |= META_OPT_XMP;
+      else
+        filter->options &= ~META_OPT_XMP;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_metadata_demux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstMetadataDemux *filter = GST_METADATA_DEMUX (object);
+
+  switch (prop_id) {
+    case ARG_EXIF:
+      g_value_set_boolean (value, filter->options & META_OPT_EXIF);
+      break;
+    case ARG_IPTC:
+      g_value_set_boolean (value, filter->options & META_OPT_IPTC);
+      break;
+    case ARG_XMP:
+      g_value_set_boolean (value, filter->options & META_OPT_XMP);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstElement vmethod implementations */
+
+static GstCaps *
+gst_metadata_demux_get_caps (GstPad * pad)
+{
+  GstMetadataDemux *filter = NULL;
+  GstPad *otherpad;
+  GstCaps *caps_new = NULL;
+  GstCaps *caps_otherpad_peer = NULL;
+
+  filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
+
+  (filter->srcpad == pad) ? (otherpad = filter->sinkpad) : (otherpad =
+      filter->srcpad);
+
+  caps_new = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+
+  caps_otherpad_peer = gst_pad_get_allowed_caps (otherpad);
+  GOTO_DONE_IF_NULL (caps_otherpad_peer);
+
+  if (gst_caps_is_empty (caps_otherpad_peer)
+      || gst_caps_is_any (caps_otherpad_peer)) {
+    goto done;
+  } else {
+
+    guint i;
+    guint caps_size = 0;
+
+    caps_size = gst_caps_get_size (caps_otherpad_peer);
+
+    gst_caps_unref (caps_new);
+
+    caps_new = gst_caps_new_empty ();
+
+    for (i = 0; i < caps_size; ++i) {
+      GstStructure *structure = NULL;
+      GstStructure *structure_new = NULL;
+      const gchar *mime = NULL;
+
+      structure = gst_caps_get_structure (caps_otherpad_peer, i);
+
+      mime = gst_structure_get_name (structure);
+
+      if (pad == filter->sinkpad) {
+        structure_new =
+            gst_structure_new (mime, "tags-extracted", G_TYPE_BOOLEAN, FALSE,
+            NULL);
+      } else {
+        structure_new =
+            gst_structure_new (mime, "tags-extracted", G_TYPE_BOOLEAN, TRUE,
+            NULL);
+      }
+
+      gst_caps_append_structure (caps_new, structure_new);
+
+    }
+
+  }
+
+done:
+
+  if (caps_otherpad_peer) {
+    gst_caps_unref (caps_otherpad_peer);
+    caps_otherpad_peer = NULL;
+  }
+
+  gst_object_unref (filter);
+
+  return caps_new;
+
+}
+
+static gboolean
+gst_metadata_demux_src_event (GstPad * pad, GstEvent * event)
+{
+  GstMetadataDemux *filter = NULL;
+  gboolean ret = FALSE;
+
+  filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+    {
+      gdouble rate;
+      GstFormat format;
+      GstSeekFlags flags;
+      GstSeekType start_type;
+      gint64 start;
+      GstSeekType stop_type;
+      gint64 stop;
+
+      /* we don't know where are the chunks to be stripped before demux */
+      if (filter->common.state != MT_STATE_PARSED)
+        goto done;
+
+      gst_event_parse_seek (event, &rate, &format, &flags,
+          &start_type, &start, &stop_type, &stop);
+
+      switch (format) {
+        case GST_FORMAT_BYTES:
+          break;
+        case GST_FORMAT_PERCENT:
+          if (filter->common.duration < 0)
+            goto done;
+          start = start * filter->common.duration / 100;
+          stop = stop * filter->common.duration / 100;
+          break;
+        default:
+          goto done;
+      }
+      format = GST_FORMAT_BYTES;
+
+      if (start_type == GST_SEEK_TYPE_CUR)
+        start = filter->offset + start;
+      else if (start_type == GST_SEEK_TYPE_END) {
+        if (filter->common.duration < 0)
+          goto done;
+        start = filter->common.duration + start;
+      }
+      start_type == GST_SEEK_TYPE_SET;
+
+      if (filter->prepend_buffer) {
+        gst_buffer_unref (filter->prepend_buffer);
+        filter->prepend_buffer = NULL;
+      }
+
+      /* FIXME: related to append */
+      filter->offset = start;
+      gst_metadata_common_translate_pos_to_orig (&filter->common, start, &start,
+          &filter->prepend_buffer);
+      filter->offset_orig = start;
+
+      if (stop_type == GST_SEEK_TYPE_CUR)
+        stop = filter->offset + stop;
+      else if (stop_type == GST_SEEK_TYPE_END) {
+        if (filter->common.duration < 0)
+          goto done;
+        stop = filter->common.duration + stop;
+      }
+      stop_type == GST_SEEK_TYPE_SET;
+
+      gst_metadata_common_translate_pos_to_orig (&filter->common, stop, &stop,
+          NULL);
+
+      gst_event_unref (event);
+      event = gst_event_new_seek (rate, format, flags,
+          start_type, start, stop_type, stop);
+
+    }
+      break;
+    default:
+      break;
+  }
+
+  ret = gst_pad_event_default (pad, event);
+  event = NULL;                 /* event has another owner */
+
+done:
+
+  if (event) {
+    gst_event_unref (event);
+  }
+
+  gst_object_unref (filter);
+
+  return ret;
+
+}
+
+static gboolean
+gst_metadata_demux_sink_event (GstPad * pad, GstEvent * event)
+{
+  GstMetadataDemux *filter = NULL;
+  gboolean ret = FALSE;
+
+  filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      if (filter->need_more_data) {
+        GST_ELEMENT_WARNING (filter, STREAM, DEMUX, (NULL),
+            ("Need more data. Unexpected EOS"));
+      }
+      break;
+    case GST_EVENT_TAG:
+      break;
+    default:
+      break;
+  }
+
+  ret = gst_pad_event_default (pad, event);
+
+  gst_object_unref (filter);
+
+  return ret;
+
+}
+
+static void
+gst_metadata_demux_dispose (GObject * object)
+{
+  GstMetadataDemux *filter = NULL;
+
+  filter = GST_METADATA_DEMUX (object);
+
+  gst_metadata_demux_dispose_members (filter);
+
+  metadataparse_xmp_dispose ();
+
+  G_OBJECT_CLASS (metadata_parent_class)->dispose (object);
+}
+
+static void
+gst_metadata_demux_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (metadata_parent_class)->finalize (object);
+}
+
+static void
+gst_metadata_demux_dispose_members (GstMetadataDemux * filter)
+{
+  gst_metadata_common_dispose (&filter->common);
+
+  if (filter->adapter_parsing) {
+    gst_object_unref (filter->adapter_parsing);
+    filter->adapter_parsing = NULL;
+  }
+
+  if (filter->adapter_holding) {
+    gst_object_unref (filter->adapter_holding);
+    filter->adapter_holding = NULL;
+  }
+
+  if (filter->prepend_buffer) {
+    gst_buffer_unref (filter->prepend_buffer);
+    filter->prepend_buffer = NULL;
+  }
+}
+
+static void
+gst_metadata_demux_init_members (GstMetadataDemux * filter)
+{
+  filter->need_send_tag = FALSE;
+
+  filter->adapter_parsing = NULL;
+  filter->adapter_holding = NULL;
+  filter->next_offset = 0;
+  filter->next_size = 0;
+  filter->img_type = IMG_NONE;
+  filter->offset_orig = 0;
+  filter->offset = 0;
+  filter->need_more_data = FALSE;
+
+  filter->prepend_buffer = NULL;
+
+  memset (&filter->common, 0x00, sizeof (filter->common));
+
+}
+
+static gboolean
+gst_metadata_demux_configure_srccaps (GstMetadataDemux * filter)
+{
+  GstCaps *caps = NULL;
+  gboolean ret = FALSE;
+  gchar *mime = NULL;
+
+  switch (filter->img_type) {
+    case IMG_JPEG:
+      mime = "image/jpeg";
+      break;
+    case IMG_PNG:
+      mime = "image/png";
+      break;
+    default:
+      ret = FALSE;
+      goto done;
+      break;
+  }
+
+  caps =
+      gst_caps_new_simple (mime, "tags-extracted", G_TYPE_BOOLEAN, TRUE, NULL);
+
+  ret = gst_pad_set_caps (filter->srcpad, caps);
+
+done:
+
+  if (caps) {
+    gst_caps_unref (caps);
+    caps = NULL;
+  }
+
+  return ret;
+
+}
+
+static gboolean
+gst_metadata_demux_configure_caps (GstMetadataDemux * filter)
+{
+  GstCaps *caps = NULL;
+  gboolean ret = FALSE;
+  gchar *mime = NULL;
+  GstPad *peer = NULL;
+
+  peer = gst_pad_get_peer (filter->sinkpad);
+
+  switch (filter->img_type) {
+    case IMG_JPEG:
+      mime = "image/jpeg";
+      break;
+    case IMG_PNG:
+      mime = "image/png";
+      break;
+    default:
+      goto done;
+      break;
+  }
+
+  caps = gst_caps_new_simple (mime, NULL);
+
+  if (!gst_pad_set_caps (peer, caps)) {
+    goto done;
+  }
+
+  ret = gst_pad_set_caps (filter->sinkpad, caps);
+
+done:
+
+  if (caps) {
+    gst_caps_unref (caps);
+    caps = NULL;
+  }
+
+  if (peer) {
+    gst_object_unref (peer);
+    peer = NULL;
+  }
+
+  return ret;
+
+}
+
+/* this function handles the link with other elements */
+static gboolean
+gst_metadata_demux_set_caps (GstPad * pad, GstCaps * caps)
+{
+  GstMetadataDemux *filter = NULL;
+  GstStructure *structure = NULL;
+  const gchar *mime = NULL;
+  gboolean ret = FALSE;
+  gboolean demuxd = TRUE;
+
+  filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  mime = gst_structure_get_name (structure);
+
+  if (strcmp (mime, "image/jpeg") == 0) {
+    filter->img_type = IMG_JPEG;
+  } else if (strcmp (mime, "image/png") == 0) {
+    filter->img_type = IMG_PNG;
+  } else {
+    ret = FALSE;
+    goto done;
+  }
+
+  if (gst_structure_get_boolean (structure, "tags-extracted", &demuxd)) {
+    if (demuxd == TRUE) {
+      ret = FALSE;
+      goto done;
+    }
+  }
+
+  ret = gst_metadata_demux_configure_srccaps (filter);
+
+done:
+
+  gst_object_unref (filter);
+
+  return ret;
+}
+
+static void
+gst_metadata_demux_send_tags (GstMetadataDemux * filter)
+{
+
+  GstMessage *msg;
+  GstTagList *taglist = gst_tag_list_new ();
+  GstEvent *event;
+
+  if (filter->options & META_OPT_EXIF)
+    metadataparse_exif_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
+        filter->common.metadata.exif_adapter, METADATA_TAG_MAP_WHOLECHUNK);
+  if (filter->options & META_OPT_IPTC)
+    metadataparse_iptc_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
+        filter->common.metadata.iptc_adapter, METADATA_TAG_MAP_WHOLECHUNK);
+  if (filter->options & META_OPT_XMP)
+    metadataparse_xmp_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
+        filter->common.metadata.xmp_adapter, METADATA_TAG_MAP_WHOLECHUNK);
+
+  if (taglist && !gst_tag_list_is_empty (taglist)) {
+
+    msg =
+        gst_message_new_tag (GST_OBJECT (filter), gst_tag_list_copy (taglist));
+    gst_element_post_message (GST_ELEMENT (filter), msg);
+
+    event = gst_event_new_tag (taglist);
+    gst_pad_push_event (filter->srcpad, event);
+    taglist = NULL;
+  }
+
+  if (!taglist)
+    taglist = gst_tag_list_new ();
+
+  if (filter->options & META_OPT_EXIF)
+    metadataparse_exif_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
+        filter->common.metadata.exif_adapter, METADATA_TAG_MAP_INDIVIDUALS);
+  if (filter->options & META_OPT_IPTC)
+    metadataparse_iptc_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
+        filter->common.metadata.iptc_adapter, METADATA_TAG_MAP_INDIVIDUALS);
+  if (filter->options & META_OPT_XMP)
+    metadataparse_xmp_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
+        filter->common.metadata.xmp_adapter, METADATA_TAG_MAP_INDIVIDUALS);
+
+  if (taglist && !gst_tag_list_is_empty (taglist)) {
+
+    msg = gst_message_new_tag (GST_OBJECT (filter), taglist);
+    gst_element_post_message (GST_ELEMENT (filter), msg);
+    taglist = NULL;
+  }
+
+  if (taglist)
+    gst_tag_list_free (taglist);
+
+  filter->need_send_tag = FALSE;
+}
+
+static const GstQueryType *
+gst_metadata_demux_get_query_types (GstPad * pad)
+{
+  static const GstQueryType gst_metadata_demux_src_query_types[] = {
+    GST_QUERY_POSITION,
+    GST_QUERY_DURATION,
+    GST_QUERY_FORMATS,
+    0
+  };
+
+  return gst_metadata_demux_src_query_types;
+}
+
+static gboolean
+gst_metadata_demux_src_query (GstPad * pad, GstQuery * query)
+{
+  gboolean ret = FALSE;
+  GstFormat format;
+  GstMetadataDemux *filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+      gst_query_parse_position (query, &format, NULL);
+
+      if (format == GST_FORMAT_BYTES) {
+        gst_query_set_position (query, GST_FORMAT_BYTES, filter->offset);
+        ret = TRUE;
+      }
+      break;
+    case GST_QUERY_DURATION:
+      if (filter->common.state != MT_STATE_PARSED)
+        goto done;
+
+      gst_query_parse_duration (query, &format, NULL);
+
+      if (format == GST_FORMAT_BYTES) {
+        if (filter->common.duration >= 0) {
+          gst_query_set_duration (query, GST_FORMAT_BYTES,
+              filter->common.duration);
+          ret = TRUE;
+        }
+      }
+      break;
+    case GST_QUERY_FORMATS:
+      gst_query_set_formats (query, 1, GST_FORMAT_BYTES);
+      ret = TRUE;
+      break;
+    default:
+      break;
+  }
+
+done:
+
+  gst_object_unref (filter);
+
+  return ret;
+
+}
+
+/*
+ * Do parsing step-by-step and reconfigure caps if need
+ * return:
+ *   META_PARSING_ERROR
+ *   META_PARSING_DONE
+ *   META_PARSING_NEED_MORE_DATA
+ */
+
+static int
+gst_metadata_demux_parse (GstMetadataDemux * filter, const guint8 * buf,
+    guint32 size)
+{
+
+  int ret = META_PARSING_ERROR;
+
+  filter->next_offset = 0;
+  filter->next_size = 0;
+
+  ret = metadata_parse (&filter->common.metadata, buf, size,
+      &filter->next_offset, &filter->next_size);
+
+  if (ret == META_PARSING_ERROR) {
+    if (META_DATA_IMG_TYPE (filter->common.metadata) == IMG_NONE) {
+      /* image type not recognized */
+      GST_ELEMENT_ERROR (filter, STREAM, TYPE_NOT_FOUND, (NULL),
+          ("Only jpeg and png are supported"));
+      goto done;
+    }
+  } else if (ret == META_PARSING_NEED_MORE_DATA) {
+    filter->need_more_data = TRUE;
+  } else {
+    filter->common.state = MT_STATE_PARSED;
+    gst_metadata_common_calculate_offsets (&filter->common);
+    filter->need_more_data = FALSE;
+    filter->need_send_tag = TRUE;
+  }
+
+  /* reconfigure caps if it is different from type detected by 'metadata_demux' function */
+  if (filter->img_type != META_DATA_IMG_TYPE (filter->common.metadata)) {
+    filter->img_type = META_DATA_IMG_TYPE (filter->common.metadata);
+    if (!gst_metadata_demux_configure_caps (filter)) {
+      GST_ELEMENT_ERROR (filter, STREAM, FORMAT, (NULL),
+          ("Couldn't reconfigure caps for %s",
+              gst_metadata_common_get_type_name (filter->img_type)));
+      ret = META_PARSING_ERROR;
+      goto done;
+    }
+  }
+
+done:
+
+  return ret;
+
+}
+
+/* chain function
+ * this function does the actual processing
+ */
+
+/* FIXME */
+/* Current demux is just done before is pull mode could be activated */
+/* may be it is possible to demux in chain mode by doing some trick with gst-adapter */
+/* the pipeline below would be a test for that case */
+/* gst-launch-0.10 filesrc location=Exif.jpg ! queue !  metadatademux ! filesink location=gen3.jpg */
+
+static GstFlowReturn
+gst_metadata_demux_chain (GstPad * pad, GstBuffer * buf)
+{
+  GstMetadataDemux *filter = NULL;
+  GstFlowReturn ret = GST_FLOW_ERROR;
+  guint32 buf_size = 0;
+  guint32 new_buf_size = 0;
+  gboolean append = FALSE;
+
+  filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
+
+  if (filter->common.state != MT_STATE_PARSED) {
+    guint32 adpt_size = gst_adapter_available (filter->adapter_parsing);
+
+    if (filter->next_offset) {
+      if (filter->next_offset >= adpt_size) {
+        /* clean adapter */
+        gst_adapter_clear (filter->adapter_parsing);
+        filter->next_offset -= adpt_size;
+        if (filter->next_offset >= GST_BUFFER_SIZE (buf)) {
+          /* we don't need data in this buffer */
+          filter->next_offset -= GST_BUFFER_SIZE (buf);
+        } else {
+          GstBuffer *new_buf;
+
+          /* add to adapter just need part from buf */
+          new_buf =
+              gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) -
+              filter->next_offset);
+          memcpy (GST_BUFFER_DATA (new_buf),
+              GST_BUFFER_DATA (buf) + filter->next_offset,
+              GST_BUFFER_SIZE (buf) - filter->next_offset);
+          filter->next_offset = 0;
+          gst_adapter_push (filter->adapter_parsing, new_buf);
+        }
+      } else {
+        /* remove first bytes and add buffer */
+        gst_adapter_flush (filter->adapter_parsing, filter->next_offset);
+        filter->next_offset = 0;
+        gst_adapter_push (filter->adapter_parsing, gst_buffer_copy (buf));
+      }
+    } else {
+      /* just push buffer */
+      gst_adapter_push (filter->adapter_parsing, gst_buffer_copy (buf));
+    }
+
+    adpt_size = gst_adapter_available (filter->adapter_parsing);
+
+    if (adpt_size && filter->next_size <= adpt_size) {
+      const guint8 *new_buf =
+          gst_adapter_peek (filter->adapter_parsing, adpt_size);
+
+      if (gst_metadata_demux_parse (filter, new_buf,
+              adpt_size) == META_PARSING_ERROR) {
+        ret = GST_FLOW_ERROR;
+        goto done;
+      }
+    }
+  }
+
+  if (filter->common.state == MT_STATE_PARSED) {
+
+    if (filter->adapter_holding) {
+      gst_adapter_push (filter->adapter_holding, buf);
+      buf = gst_adapter_take_buffer (filter->adapter_holding,
+          gst_adapter_available (filter->adapter_holding));
+      g_object_unref (filter->adapter_holding);
+      filter->adapter_holding = NULL;
+    }
+
+    if (filter->need_send_tag) {
+      gst_metadata_demux_send_tags (filter);
+    }
+
+    if (filter->offset_orig + GST_BUFFER_SIZE (buf) ==
+        filter->common.duration_orig)
+      append = TRUE;
+
+    buf_size = GST_BUFFER_SIZE (buf);
+
+    gst_metadata_common_strip_push_buffer (&filter->common, filter->offset_orig,
+        &filter->prepend_buffer, &buf);
+
+    if (buf) {                  /* may be all buffer has been striped */
+      gst_buffer_set_caps (buf, GST_PAD_CAPS (filter->srcpad));
+      new_buf_size = GST_BUFFER_SIZE (buf);
+
+      ret = gst_pad_push (filter->srcpad, buf);
+      buf = NULL;               /* this function don't owner it anymore */
+      if (ret != GST_FLOW_OK)
+        goto done;
+    } else {
+      ret = GST_FLOW_OK;
+    }
+
+    if (append && filter->common.append_buffer) {
+      gst_buffer_set_caps (filter->common.append_buffer,
+          GST_PAD_CAPS (filter->srcpad));
+      gst_buffer_ref (filter->common.append_buffer);
+      ret = gst_pad_push (filter->srcpad, filter->common.append_buffer);
+      if (ret != GST_FLOW_OK)
+        goto done;
+    }
+
+    filter->offset_orig += buf_size;
+    filter->offset += new_buf_size;
+
+  } else {
+    /* just store while still not demuxd */
+    if (!filter->adapter_holding)
+      filter->adapter_holding = gst_adapter_new ();
+    gst_adapter_push (filter->adapter_holding, buf);
+    buf = NULL;
+    ret = GST_FLOW_OK;
+  }
+
+done:
+
+
+  if (buf) {
+    /* there was an error and buffer wasn't pushed */
+    gst_buffer_unref (buf);
+    buf = NULL;
+  }
+
+  gst_object_unref (filter);
+
+  return ret;
+
+}
+
+static gboolean
+gst_metadata_demux_pull_range_demux (GstMetadataDemux * filter)
+{
+
+  int res;
+  gboolean ret = TRUE;
+  guint32 offset = 0;
+  gint64 duration = 0;
+  GstFormat format = GST_FORMAT_BYTES;
+
+  if (!(ret =
+          gst_pad_query_peer_duration (filter->sinkpad, &format, &duration))) {
+    /* this should never happen, but try chain anyway */
+    ret = TRUE;
+    goto done;
+  }
+  filter->common.duration_orig = duration;
+
+  if (format != GST_FORMAT_BYTES) {
+    /* this should never happen, but try chain anyway */
+    ret = TRUE;
+    goto done;
+  }
+
+  do {
+    GstFlowReturn flow;
+    GstBuffer *buf = NULL;
+
+    offset += filter->next_offset;
+
+    /* 'filter->next_size' only says the minimum required number of bytes.
+       We try provided more bytes (4096) just to avoid a lot of calls to 'metadata_demux'
+       returning META_PARSING_NEED_MORE_DATA */
+    if (filter->next_size < 4096) {
+      if (duration - offset < 4096) {
+        /* In case there is no 4096 bytes available upstream.
+           It should be done upstream but we do here for safety */
+        filter->next_size = duration - offset;
+      } else {
+        filter->next_size = 4096;
+      }
+    }
+
+    flow =
+        gst_pad_pull_range (filter->sinkpad, offset, filter->next_size, &buf);
+    if (GST_FLOW_OK != flow) {
+      ret = FALSE;
+      goto done;
+    }
+
+    res =
+        gst_metadata_demux_parse (filter, GST_BUFFER_DATA (buf),
+        GST_BUFFER_SIZE (buf));
+    if (res == META_PARSING_ERROR) {
+      ret = FALSE;
+      goto done;
+    }
+
+    gst_buffer_unref (buf);
+
+  } while (res == META_PARSING_NEED_MORE_DATA);
+
+done:
+
+  return ret;
+
+}
+
+static gboolean
+gst_metadata_demux_sink_activate (GstPad * pad)
+{
+  GstMetadataDemux *filter = NULL;
+  gboolean ret = TRUE;
+
+
+  filter = GST_METADATA_DEMUX (GST_PAD_PARENT (pad));
+
+  if (!gst_pad_check_pull_range (pad) ||
+      !gst_pad_activate_pull (filter->sinkpad, TRUE)) {
+    /* FIXME: currently it is not possible to demux in chain. Fail here ? */
+    /* nothing to be done by now, activate push mode */
+    return gst_pad_activate_push (pad, TRUE);
+  }
+
+  /* try to demux */
+  if (filter->common.state == MT_STATE_NULL) {
+    ret = gst_metadata_demux_pull_range_demux (filter);
+  }
+
+done:
+
+  if (ret) {
+    gst_pad_activate_pull (pad, FALSE);
+    gst_pad_activate_push (filter->srcpad, FALSE);
+    if (!gst_pad_is_active (pad)) {
+      ret = gst_pad_activate_push (filter->srcpad, TRUE);
+      ret = ret && gst_pad_activate_push (pad, TRUE);
+    }
+  }
+
+  return ret;
+
+}
+
+static gboolean
+gst_metadata_demux_checkgetrange (GstPad * srcpad)
+{
+  GstMetadataDemux *filter = NULL;
+
+  filter = GST_METADATA_DEMUX (GST_PAD_PARENT (srcpad));
+
+  return gst_pad_check_pull_range (filter->sinkpad);
+}
+
+static GstFlowReturn
+gst_metadata_demux_get_range (GstPad * pad,
+    guint64 offset, guint size, GstBuffer ** buf)
+{
+  GstMetadataDemux *filter = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  gint64 offset_orig = 0;
+  guint size_orig;
+  GstBuffer *prepend = NULL;
+  gboolean need_append = FALSE;
+
+  filter = GST_METADATA_DEMUX (GST_PAD_PARENT (pad));
+
+  if (filter->common.state != MT_STATE_PARSED) {
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+
+  if (offset + size > filter->common.duration) {
+    size = filter->common.duration - offset;
+  }
+
+  size_orig = size;
+
+  if (filter->need_send_tag) {
+    gst_metadata_demux_send_tags (filter);
+  }
+
+  gst_metadata_common_translate_pos_to_orig (&filter->common, offset,
+      &offset_orig, &prepend);
+
+  if (size > 1) {
+    gint64 pos;
+
+    pos = offset + size - 1;
+    gst_metadata_common_translate_pos_to_orig (&filter->common, pos, &pos,
+        NULL);
+    size_orig = pos + 1 - offset_orig;
+  }
+
+  if (size_orig) {
+
+    ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf);
+
+    if (ret == GST_FLOW_OK && *buf) {
+      gst_metadata_common_strip_push_buffer (&filter->common, offset_orig,
+          &prepend, buf);
+
+      if (GST_BUFFER_SIZE (*buf) < size) {
+        /* need append */
+        need_append = TRUE;
+      }
+
+    }
+  } else {
+    *buf = prepend;
+  }
+
+done:
+
+  if (need_append) {
+    /* FIXME: together with SEEK and
+     * gst_metadata_common_translate_pos_to_orig
+     * this way if chunk is added in the end we are in trolble
+     * ...still not implemented 'cause it will not be the
+     * case for the time being
+     */
+  }
+
+  return ret;
+
+}
+
+static gboolean
+gst_metadata_demux_src_activate_pull (GstPad * pad, gboolean active)
+{
+  GstMetadataDemux *filter = NULL;
+  gboolean ret;
+
+  filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
+
+  ret = gst_pad_activate_pull (filter->sinkpad, active);
+
+  if (ret && filter->common.state == MT_STATE_NULL) {
+    ret = gst_metadata_demux_pull_range_demux (filter);
+  }
+
+  gst_object_unref (filter);
+
+  return ret;
+}
+
+
+static GstStateChangeReturn
+gst_metadata_demux_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstMetadataDemux *filter = GST_METADATA_DEMUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      gst_metadata_demux_init_members (filter);
+      filter->adapter_parsing = gst_adapter_new ();
+      gst_metadata_common_init (&filter->common, TRUE, filter->options);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto done;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      filter->offset = 0;
+      filter->offset_orig = 0;
+      if (filter->adapter_parsing) {
+        gst_adapter_clear (filter->adapter_parsing);
+      }
+      if (filter->adapter_holding) {
+        gst_adapter_clear (filter->adapter_holding);
+      }
+      if (filter->common.state != MT_STATE_PARSED) {
+        /* cleanup demuxr */
+        gst_metadata_common_dispose (&filter->common);
+        gst_metadata_common_init (&filter->common, TRUE, filter->options);
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_metadata_demux_dispose_members (filter);
+      break;
+    default:
+      break;
+  }
+
+done:
+
+  return ret;
+}
+
+/*
+ * element plugin init function
+ */
+
+gboolean
+gst_metadata_demux_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_metadata_demux_debug, "metadatademux", 0,
+      "Metadata demuxer");
+
+  return gst_element_register (plugin, "metadatademux",
+      GST_RANK_PRIMARY + 1, GST_TYPE_METADATA_DEMUX);
+}
diff --git a/ext/metadata/gstmetadatademux.h b/ext/metadata/gstmetadatademux.h
new file mode 100644 (file)
index 0000000..2170a87
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * GStreamer
+ * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_METADATA_DEMUX_H__
+#define __GST_METADATA_DEMUX_H__
+
+#include <gst/gst.h>
+
+#include "gstmetadatacommon.h"
+
+G_BEGIN_DECLS
+/* #defines don't like whitespacey bits */
+#define GST_TYPE_METADATA_DEMUX \
+  (gst_metadata_demux_get_type())
+#define GST_METADATA_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_METADATA_DEMUX,GstMetadataDemux))
+#define GST_METADATA_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_METADATA_DEMUX,GstMetadataDemuxClass))
+#define GST_IS_METADATA_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_METADATA_DEMUX))
+#define GST_IS_METADATA_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_METADATA_DEMUX))
+typedef struct _GstMetadataDemux GstMetadataDemux;
+typedef struct _GstMetadataDemuxClass GstMetadataDemuxClass;
+
+struct _GstMetadataDemux
+{
+  GstElement element;
+
+  GstPad *sinkpad, *srcpad;
+
+  GstMetadataCommon common;
+
+  guint8 options;
+
+  gboolean need_send_tag;
+
+  GstAdapter *adapter_parsing;
+  GstAdapter *adapter_holding;
+  guint32 next_offset;
+  guint32 next_size;
+  ImageType img_type;
+
+  gint64 offset_orig;  /* offset in original stream */
+  gint64 offset;       /* offset in current stream */
+
+  GstBuffer * prepend_buffer;
+
+  gboolean need_more_data;
+
+
+
+};
+
+struct _GstMetadataDemuxClass
+{
+  GstElementClass parent_class;
+};
+
+extern GType gst_metadata_demux_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_METADATA_DEMUX_H__ */
index 5c1a3bed0da3765e7ff5df46aa068d599b3942f0..f2c2a8951ce00edb20521a6dca1d55825ed25609 100644 (file)
@@ -154,6 +154,7 @@ static void gst_metadata_mux_init_members (GstMetadataMux * filter);
 static void gst_metadata_mux_dispose_members (GstMetadataMux * filter);
 
 static gboolean gst_metadata_mux_configure_srccaps (GstMetadataMux * filter);
+
 static gboolean gst_metadata_mux_configure_caps (GstMetadataMux * filter);
 
 static int
@@ -162,25 +163,10 @@ gst_metadata_mux_parse (GstMetadataMux * filter, const guint8 * buf,
 
 static void gst_metadata_mux_create_chunks_from_tags (GstMetadataMux * filter);
 
-static int
-gst_metadata_mux_get_strip_seg (const gint64 offset, guint32 size,
-    const gint64 seg_offset, const guint32 seg_size,
-    gint64 * boffset, guint32 * bsize, guint32 * seg_binter);
-
-static gboolean
-gst_metadata_mux_strip_push_buffer (GstMetadataMux * filter,
-    gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf);
-
-static gboolean
-gst_metadata_mux_translate_pos_to_orig (GstMetadataMux * filter, gint64 pos,
-    gint64 * orig_pos, GstBuffer ** buf);
-
 static const GstQueryType *gst_metadata_mux_get_query_types (GstPad * pad);
 
 static gboolean gst_metadata_mux_src_query (GstPad * pad, GstQuery * query);
 
-static gboolean gst_metadata_mux_calculate_offsets (GstMetadataMux * filter);
-
 static void
 gst_metadata_mux_base_init (gpointer gclass)
 {
@@ -283,11 +269,11 @@ gst_metadata_mux_init (GstMetadataMux * filter, GstMetadataMuxClass * gclass)
   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
 
-
   metadataparse_xmp_init ();
   /* init members */
 
   filter->options = META_OPT_EXIF | META_OPT_IPTC | META_OPT_XMP;
+
   gst_metadata_mux_init_members (filter);
 
 }
@@ -415,6 +401,48 @@ done:
 
 }
 
+static void
+gst_metadata_create_chunks_from_tags (GstMetadataMux * filter)
+{
+
+  GstMessage *msg;
+  GstTagSetter *setter = GST_TAG_SETTER (filter);
+  const GstTagList *taglist = gst_tag_setter_get_tag_list (setter);
+  GstEvent *event;
+  guint8 *buf = NULL;
+  guint32 size = 0;
+
+  if (taglist) {
+
+    if (filter->options & META_OPT_EXIF) {
+      metadatamux_exif_create_chunk_from_tag_list (&buf, &size, taglist);
+      gst_metadata_common_update_segment_with_new_buffer (&filter->common, &buf,
+          &size, MD_CHUNK_EXIF);
+    }
+
+    if (filter->options & META_OPT_IPTC) {
+      metadatamux_iptc_create_chunk_from_tag_list (&buf, &size, taglist);
+      gst_metadata_common_update_segment_with_new_buffer (&filter->common, &buf,
+          &size, MD_CHUNK_IPTC);
+    }
+
+    if (filter->options & META_OPT_XMP) {
+      metadatamux_xmp_create_chunk_from_tag_list (&buf, &size, taglist);
+      gst_metadata_common_update_segment_with_new_buffer (&filter->common, &buf,
+          &size, MD_CHUNK_XMP);
+    }
+
+  }
+
+  if (buf) {
+    g_free (buf);
+  }
+
+  metadata_chunk_array_remove_zero_size (&filter->common.metadata.
+      inject_chunks);
+
+}
+
 static gboolean
 gst_metadata_mux_src_event (GstPad * pad, GstEvent * event)
 {
@@ -436,7 +464,10 @@ gst_metadata_mux_src_event (GstPad * pad, GstEvent * event)
 
       /* we don't know where are the chunks to be stripped before mux */
       if (filter->need_calculate_offset) {
-        if (!gst_metadata_mux_calculate_offsets (filter))
+        gst_metadata_create_chunks_from_tags (filter);
+        if (gst_metadata_common_calculate_offsets (&filter->common))
+          filter->need_calculate_offset = FALSE;
+        else
           goto done;
       }
 
@@ -447,10 +478,10 @@ gst_metadata_mux_src_event (GstPad * pad, GstEvent * event)
         case GST_FORMAT_BYTES:
           break;
         case GST_FORMAT_PERCENT:
-          if (filter->duration < 0)
+          if (filter->common.duration < 0)
             goto done;
-          start = start * filter->duration / 100;
-          stop = stop * filter->duration / 100;
+          start = start * filter->common.duration / 100;
+          stop = stop * filter->common.duration / 100;
           break;
         default:
           goto done;
@@ -460,9 +491,9 @@ gst_metadata_mux_src_event (GstPad * pad, GstEvent * event)
       if (start_type == GST_SEEK_TYPE_CUR)
         start = filter->offset + start;
       else if (start_type == GST_SEEK_TYPE_END) {
-        if (filter->duration < 0)
+        if (filter->common.duration < 0)
           goto done;
-        start = filter->duration + start;
+        start = filter->common.duration + start;
       }
       start_type == GST_SEEK_TYPE_SET;
 
@@ -473,20 +504,21 @@ gst_metadata_mux_src_event (GstPad * pad, GstEvent * event)
 
       /* FIXME: related to append */
       filter->offset = start;
-      gst_metadata_mux_translate_pos_to_orig (filter, start, &start,
+      gst_metadata_common_translate_pos_to_orig (&filter->common, start, &start,
           &filter->prepend_buffer);
       filter->offset_orig = start;
 
       if (stop_type == GST_SEEK_TYPE_CUR)
         stop = filter->offset + stop;
       else if (stop_type == GST_SEEK_TYPE_END) {
-        if (filter->duration < 0)
+        if (filter->common.duration < 0)
           goto done;
-        stop = filter->duration + stop;
+        stop = filter->common.duration + stop;
       }
       stop_type == GST_SEEK_TYPE_SET;
 
-      gst_metadata_mux_translate_pos_to_orig (filter, stop, &stop, NULL);
+      gst_metadata_common_translate_pos_to_orig (&filter->common, stop, &stop,
+          NULL);
 
       gst_event_unref (event);
       event = gst_event_new_seek (rate, format, flags,
@@ -573,7 +605,7 @@ gst_metadata_mux_finalize (GObject * object)
 static void
 gst_metadata_mux_dispose_members (GstMetadataMux * filter)
 {
-  metadata_dispose (&filter->mux_data);
+  gst_metadata_common_dispose (&filter->common);
 
   if (filter->adapter_parsing) {
     gst_object_unref (filter->adapter_parsing);
@@ -585,11 +617,6 @@ gst_metadata_mux_dispose_members (GstMetadataMux * filter)
     filter->adapter_holding = NULL;
   }
 
-  if (filter->append_buffer) {
-    gst_buffer_unref (filter->append_buffer);
-    filter->append_buffer = NULL;
-  }
-
   if (filter->prepend_buffer) {
     gst_buffer_unref (filter->prepend_buffer);
     filter->prepend_buffer = NULL;
@@ -607,16 +634,12 @@ gst_metadata_mux_init_members (GstMetadataMux * filter)
   filter->next_size = 0;
   filter->img_type = IMG_NONE;
   filter->offset_orig = 0;
-  filter->duration_orig = 0;
   filter->offset = 0;
-  filter->duration = 0;
-  filter->state = MT_STATE_NULL;
   filter->need_more_data = FALSE;
 
-  filter->append_buffer = NULL;
   filter->prepend_buffer = NULL;
 
-  memset (&filter->mux_data, 0x00, sizeof (MetaData));
+  memset (&filter->common, 0x00, sizeof (filter->common));
 
 }
 
@@ -742,96 +765,6 @@ done:
   return ret;
 }
 
-static const gchar *
-gst_metadata_mux_get_type_name (int img_type)
-{
-  gchar *type_name = NULL;
-
-  switch (img_type) {
-    case IMG_JPEG:
-      type_name = "jpeg";
-      break;
-    case IMG_PNG:
-      type_name = "png";
-      break;
-    default:
-      type_name = "invalid type";
-      break;
-  }
-  return type_name;
-}
-
-static void
-gst_metadata_update_segment (GstMetadataMux * filter, guint8 ** buf,
-    guint32 * size, MetadataChunkType type)
-{
-  int i;
-  MetadataChunk *inject = filter->mux_data.inject_chunks.chunk;
-  const gsize inject_len = filter->mux_data.inject_chunks.len;
-
-  if (!(buf && size))
-    goto done;
-  if (*buf == 0)
-    goto done;
-  if (*size == 0)
-    goto done;
-
-  for (i = 0; i < inject_len; ++i) {
-    if (inject[i].type == type) {
-      inject[i].size = *size;
-      if (inject[i].data)
-        g_free (inject[i].data);
-      inject[i].data = *buf;
-      *size = 0;
-      *buf = 0;
-      break;
-    }
-  }
-
-done:
-
-  return;
-
-}
-
-static void
-gst_metadata_create_chunks_from_tags (GstMetadataMux * filter)
-{
-
-  GstMessage *msg;
-  GstTagSetter *setter = GST_TAG_SETTER (filter);
-  const GstTagList *taglist = gst_tag_setter_get_tag_list (setter);
-  GstEvent *event;
-  guint8 *buf = NULL;
-  guint32 size = 0;
-
-  if (taglist) {
-
-    if (filter->options & META_OPT_EXIF) {
-      metadatamux_exif_create_chunk_from_tag_list (&buf, &size, taglist);
-      gst_metadata_update_segment (filter, &buf, &size, MD_CHUNK_EXIF);
-    }
-
-    if (filter->options & META_OPT_IPTC) {
-      metadatamux_iptc_create_chunk_from_tag_list (&buf, &size, taglist);
-      gst_metadata_update_segment (filter, &buf, &size, MD_CHUNK_IPTC);
-    }
-
-    if (filter->options & META_OPT_XMP) {
-      metadatamux_xmp_create_chunk_from_tag_list (&buf, &size, taglist);
-      gst_metadata_update_segment (filter, &buf, &size, MD_CHUNK_XMP);
-    }
-
-  }
-
-  if (buf) {
-    g_free (buf);
-  }
-
-  metadata_chunk_array_remove_zero_size (&filter->mux_data.inject_chunks);
-
-}
-
 static const GstQueryType *
 gst_metadata_mux_get_query_types (GstPad * pad)
 {
@@ -863,15 +796,19 @@ gst_metadata_mux_src_query (GstPad * pad, GstQuery * query)
       break;
     case GST_QUERY_DURATION:
       if (filter->need_calculate_offset) {
-        if (!gst_metadata_mux_calculate_offsets (filter))
+        gst_metadata_create_chunks_from_tags (filter);
+        if (gst_metadata_common_calculate_offsets (&filter->common))
+          filter->need_calculate_offset = FALSE;
+        else
           goto done;
       }
 
       gst_query_parse_duration (query, &format, NULL);
 
       if (format == GST_FORMAT_BYTES) {
-        if (filter->duration >= 0) {
-          gst_query_set_duration (query, GST_FORMAT_BYTES, filter->duration);
+        if (filter->common.duration >= 0) {
+          gst_query_set_duration (query, GST_FORMAT_BYTES,
+              filter->common.duration);
           ret = TRUE;
         }
       }
@@ -892,91 +829,6 @@ done:
 
 }
 
-/*
- * return:
- *   -1 -> error
- *    0 -> succeded
- *    1 -> need more data
- */
-
-static gboolean
-gst_metadata_mux_calculate_offsets (GstMetadataMux * filter)
-{
-  int i, j;
-  guint32 append_size;
-  guint32 bytes_striped, bytes_inject;
-  MetadataChunk *strip = filter->mux_data.strip_chunks.chunk;
-  MetadataChunk *inject = filter->mux_data.inject_chunks.chunk;
-  gsize strip_len;
-  gsize inject_len;
-
-  if (filter->state != MT_STATE_MUXED)
-    return FALSE;
-
-  gst_metadata_create_chunks_from_tags (filter);
-
-  metadata_lazy_update (&filter->mux_data);
-
-  strip_len = filter->mux_data.strip_chunks.len;
-  inject_len = filter->mux_data.inject_chunks.len;
-
-  bytes_striped = 0;
-  bytes_inject = 0;
-
-  /* calculate the new position off injected chunks */
-  j = 0;
-  for (i = 0; i < inject_len; ++i) {
-    for (; j < strip_len; ++j) {
-      if (strip[j].offset_orig >= inject[i].offset_orig) {
-        break;
-      }
-      bytes_striped += strip[j].size;
-    }
-    inject[i].offset = inject[i].offset_orig - bytes_striped + bytes_inject;
-    bytes_inject += inject[i].size;
-  }
-
-  /* calculate append (doesnt make much sense, but, anyway..) */
-  append_size = 0;
-  for (i = inject_len - 1; i >= 0; --i) {
-    if (inject[i].offset_orig == filter->duration_orig)
-      append_size += inject[i].size;
-    else
-      break;
-  }
-  if (append_size) {
-    guint8 *data;
-
-    filter->append_buffer = gst_buffer_new_and_alloc (append_size);
-    GST_BUFFER_FLAG_SET (filter->append_buffer, GST_BUFFER_FLAG_READONLY);
-    data = GST_BUFFER_DATA (filter->append_buffer);
-    for (i = inject_len - 1; i >= 0; --i) {
-      if (inject[i].offset_orig == filter->duration_orig) {
-        memcpy (data, inject[i].data, inject[i].size);
-        data += inject[i].size;
-      } else {
-        break;
-      }
-    }
-  }
-
-  if (filter->duration_orig) {
-    filter->duration = filter->duration_orig;
-    for (i = 0; i < inject_len; ++i) {
-      filter->duration += inject[i].size;
-    }
-    for (i = 0; i < strip_len; ++i) {
-      filter->duration -= strip[i].size;
-    }
-  }
-
-  filter->need_calculate_offset = FALSE;
-
-  return TRUE;
-
-}
-
-
 /*
  * Do parsing step-by-step and reconfigure caps if need
  * return:
@@ -995,11 +847,11 @@ gst_metadata_mux_parse (GstMetadataMux * filter, const guint8 * buf,
   filter->next_offset = 0;
   filter->next_size = 0;
 
-  ret = metadata_parse (&filter->mux_data, buf, size,
+  ret = metadata_parse (&filter->common.metadata, buf, size,
       &filter->next_offset, &filter->next_size);
 
   if (ret == META_PARSING_ERROR) {
-    if (META_DATA_IMG_TYPE (filter->mux_data) == IMG_NONE) {
+    if (META_DATA_IMG_TYPE (filter->common.metadata) == IMG_NONE) {
       /* image type not recognized */
       GST_ELEMENT_ERROR (filter, STREAM, TYPE_NOT_FOUND, (NULL),
           ("Only jpeg and png are supported"));
@@ -1008,17 +860,18 @@ gst_metadata_mux_parse (GstMetadataMux * filter, const guint8 * buf,
   } else if (ret == META_PARSING_NEED_MORE_DATA) {
     filter->need_more_data = TRUE;
   } else {
-    filter->state = MT_STATE_MUXED;
+    filter->common.state = MT_STATE_PARSED;
     filter->need_more_data = FALSE;
     filter->need_calculate_offset = TRUE;
   }
 
-  if (filter->img_type != META_DATA_IMG_TYPE (filter->mux_data)) {
-    filter->img_type = META_DATA_IMG_TYPE (filter->mux_data);
+  /* reconfigure caps if it is different from type detected by 'metadata_mux' function */
+  if (filter->img_type != META_DATA_IMG_TYPE (filter->common.metadata)) {
+    filter->img_type = META_DATA_IMG_TYPE (filter->common.metadata);
     if (!gst_metadata_mux_configure_caps (filter)) {
       GST_ELEMENT_ERROR (filter, STREAM, FORMAT, (NULL),
           ("Couldn't reconfigure caps for %s",
-              gst_metadata_mux_get_type_name (filter->img_type)));
+              gst_metadata_common_get_type_name (filter->img_type)));
       ret = META_PARSING_ERROR;
       goto done;
     }
@@ -1051,7 +904,7 @@ gst_metadata_mux_chain (GstPad * pad, GstBuffer * buf)
 
   filter = GST_METADATA_MUX (gst_pad_get_parent (pad));
 
-  if (filter->state != MT_STATE_MUXED) {
+  if (filter->common.state != MT_STATE_PARSED) {
     guint32 adpt_size = gst_adapter_available (filter->adapter_parsing);
 
     if (filter->next_offset) {
@@ -1100,7 +953,7 @@ gst_metadata_mux_chain (GstPad * pad, GstBuffer * buf)
     }
   }
 
-  if (filter->state == MT_STATE_MUXED) {
+  if (filter->common.state == MT_STATE_PARSED) {
 
     if (filter->adapter_holding) {
       gst_adapter_push (filter->adapter_holding, buf);
@@ -1111,18 +964,22 @@ gst_metadata_mux_chain (GstPad * pad, GstBuffer * buf)
     }
 
     if (filter->need_calculate_offset) {
-      if (!gst_metadata_mux_calculate_offsets (filter)) {
+      gst_metadata_create_chunks_from_tags (filter);
+      if (gst_metadata_common_calculate_offsets (&filter->common)) {
+        filter->need_calculate_offset = FALSE;
+      } else {
         ret = GST_FLOW_ERROR;
         goto done;
       }
     }
 
-    if (filter->offset_orig + GST_BUFFER_SIZE (buf) == filter->duration_orig)
+    if (filter->offset_orig + GST_BUFFER_SIZE (buf) ==
+        filter->common.duration_orig)
       append = TRUE;
 
     buf_size = GST_BUFFER_SIZE (buf);
 
-    gst_metadata_mux_strip_push_buffer (filter, filter->offset_orig,
+    gst_metadata_common_strip_push_buffer (&filter->common, filter->offset_orig,
         &filter->prepend_buffer, &buf);
 
     if (buf) {                  /* may be all buffer has been striped */
@@ -1137,11 +994,11 @@ gst_metadata_mux_chain (GstPad * pad, GstBuffer * buf)
       ret = GST_FLOW_OK;
     }
 
-    if (append && filter->append_buffer) {
-      gst_buffer_set_caps (filter->append_buffer,
+    if (append && filter->common.append_buffer) {
+      gst_buffer_set_caps (filter->common.append_buffer,
           GST_PAD_CAPS (filter->srcpad));
-      gst_buffer_ref (filter->append_buffer);
-      ret = gst_pad_push (filter->srcpad, filter->append_buffer);
+      gst_buffer_ref (filter->common.append_buffer);
+      ret = gst_pad_push (filter->srcpad, filter->common.append_buffer);
       if (ret != GST_FLOW_OK)
         goto done;
     }
@@ -1189,7 +1046,7 @@ gst_metadata_mux_pull_range_mux (GstMetadataMux * filter)
     ret = TRUE;
     goto done;
   }
-  filter->duration_orig = duration;
+  filter->common.duration_orig = duration;
 
   if (format != GST_FORMAT_BYTES) {
     /* this should never happen, but try chain anyway */
@@ -1235,7 +1092,6 @@ gst_metadata_mux_pull_range_mux (GstMetadataMux * filter)
 
   } while (res == META_PARSING_NEED_MORE_DATA);
 
-
 done:
 
   return ret;
@@ -1259,7 +1115,7 @@ gst_metadata_mux_sink_activate (GstPad * pad)
   }
 
   /* try to mux */
-  if (filter->state == MT_STATE_NULL) {
+  if (filter->common.state == MT_STATE_NULL) {
     ret = gst_metadata_mux_pull_range_mux (filter);
   }
 
@@ -1278,411 +1134,6 @@ done:
 
 }
 
-/*
- * offset - offset of buffer in original stream
- * size - size of buffer
- * seg_offset - offset of segment in original stream
- * seg_size - size of segment
- * boffset - offset inside buffer where segment starts (-1 for no intersection)
- * bsize - size of intersection
- * seg_binter - if segment start inside buffer is zero. if segment start before
- *               buffer and intersect, it is the offset inside segment.
- *
- * ret:
- *  -1 - segment before buffer
- *   0 - segment intersects
- *   1 - segment after buffer
- */
-
-static int
-gst_metadata_mux_get_strip_seg (const gint64 offset, guint32 size,
-    const gint64 seg_offset, const guint32 seg_size,
-    gint64 * boffset, guint32 * bsize, guint32 * seg_binter)
-{
-  int ret = -1;
-
-  *boffset = -1;
-  *bsize = 0;
-  *seg_binter = -1;
-
-  /* all segment after buffer */
-  if (seg_offset >= offset + size) {
-    ret = 1;
-    goto done;
-  }
-
-  if (seg_offset < offset) {
-    /* segment start somewhere before buffer */
-
-    /* all segment before buffer */
-    if (seg_offset + seg_size <= offset) {
-      ret = -1;
-      goto done;
-    }
-
-    *seg_binter = offset - seg_offset;
-    *boffset = 0;
-
-    /* FIXME : optimize to >= size -> = size */
-    if (seg_offset + seg_size >= offset + size) {
-      /* segment cover all buffer */
-      *bsize = size;
-    } else {
-      /* segment goes from start of buffer to somewhere before end */
-      *bsize = seg_size - *seg_binter;
-    }
-
-    ret = 0;
-
-  } else {
-    /* segment start somewhere into buffer */
-
-    *boffset = seg_offset - offset;
-    *seg_binter = 0;
-
-    if (seg_offset + seg_size <= offset + size) {
-      /* all segment into buffer */
-      *bsize = seg_size;
-    } else {
-      *bsize = size - *boffset;
-    }
-
-    ret = 0;
-
-  }
-
-done:
-
-  return ret;
-
-}
-
-/*
- *  TRUE -> buffer striped or injeted
- *  FALSE -> buffer unmodified
- */
-
-static gboolean
-gst_metadata_mux_strip_push_buffer (GstMetadataMux * filter,
-    gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf)
-{
-  MetadataChunk *strip = filter->mux_data.strip_chunks.chunk;
-  MetadataChunk *inject = filter->mux_data.inject_chunks.chunk;
-  const gsize strip_len = filter->mux_data.strip_chunks.len;
-  const gsize inject_len = filter->mux_data.inject_chunks.len;
-  gboolean buffer_reallocated = FALSE;
-
-  guint32 size_buf_in = GST_BUFFER_SIZE (*buf);
-
-  gint64 *boffset_strip = NULL;
-  guint32 *bsize_strip = NULL;
-  guint32 *seg_binter_strip = NULL;
-
-  int i, j;
-  gboolean need_free_strip = FALSE;
-
-  guint32 striped_bytes = 0;
-  guint32 injected_bytes = 0;
-
-  guint32 prepend_size = prepend && *prepend ? GST_BUFFER_SIZE (*prepend) : 0;
-
-  if (inject_len) {
-
-    for (i = 0; i < inject_len; ++i) {
-      int res;
-
-      if (inject[i].offset_orig >= offset_orig) {
-        if (inject[i].offset_orig < offset_orig + size_buf_in) {
-          injected_bytes += inject[i].size;
-        } else {
-          /* segment is after size (segments are sorted) */
-          break;
-        }
-      }
-    }
-
-  }
-
-  /*
-   * strip segments
-   */
-
-  if (strip_len == 0)
-    goto inject;
-
-  if (G_UNLIKELY (strip_len > 16)) {
-    boffset_strip = g_new (gint64, strip_len);
-    bsize_strip = g_new (guint32, strip_len);
-    seg_binter_strip = g_new (guint32, strip_len);
-    need_free_strip = TRUE;
-  } else {
-    boffset_strip = g_alloca (sizeof (boffset_strip[0]) * strip_len);
-    bsize_strip = g_alloca (sizeof (bsize_strip[0]) * strip_len);
-    seg_binter_strip = g_alloca (sizeof (seg_binter_strip[0]) * strip_len);
-  }
-
-  memset (bsize_strip, 0x00, sizeof (bsize_strip[0]) * strip_len);
-
-  for (i = 0; i < strip_len; ++i) {
-    int res;
-
-    res = gst_metadata_mux_get_strip_seg (offset_orig, size_buf_in,
-        strip[i].offset_orig, strip[i].size, &boffset_strip[i], &bsize_strip[i],
-        &seg_binter_strip[i]);
-
-    /* segment is after size (segments are sorted) */
-    striped_bytes += bsize_strip[i];
-    if (res > 0) {
-      break;
-    }
-
-  }
-
-  if (striped_bytes) {
-
-    guint8 *data;
-
-    if (!buffer_reallocated) {
-      buffer_reallocated = TRUE;
-      if (injected_bytes + prepend_size > striped_bytes) {
-        GstBuffer *new_buf =
-            gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes +
-            prepend_size - striped_bytes);
-
-        memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf),
-            GST_BUFFER_SIZE (*buf));
-
-        gst_buffer_unref (*buf);
-        *buf = new_buf;
-
-      } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) {
-        GstBuffer *new_buf = gst_buffer_copy (*buf);
-
-        gst_buffer_unref (*buf);
-        *buf = new_buf;
-        GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
-        GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes;
-      }
-    }
-
-    data = GST_BUFFER_DATA (*buf);
-
-    striped_bytes = 0;
-    for (i = 0; i < strip_len; ++i) {
-      /* intersect */
-      if (bsize_strip[i]) {
-        memmove (data + boffset_strip[i] - striped_bytes,
-            data + boffset_strip[i] + bsize_strip[i] - striped_bytes,
-            size_buf_in - boffset_strip[i] - bsize_strip[i]);
-        striped_bytes += bsize_strip[i];
-      }
-    }
-    size_buf_in -= striped_bytes;
-
-  }
-
-inject:
-
-  /*
-   * inject segments
-   */
-
-  if (inject_len) {
-
-    guint8 *data;
-    guint32 striped_so_far;
-
-    if (!buffer_reallocated) {
-      buffer_reallocated = TRUE;
-      if (injected_bytes + prepend_size > striped_bytes) {
-        GstBuffer *new_buf =
-            gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes +
-            prepend_size - striped_bytes);
-
-        memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf),
-            GST_BUFFER_SIZE (*buf));
-
-        gst_buffer_unref (*buf);
-        *buf = new_buf;
-
-      } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) {
-        GstBuffer *new_buf = gst_buffer_copy (*buf);
-
-        gst_buffer_unref (*buf);
-        *buf = new_buf;
-        GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
-        GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes;
-      }
-    }
-
-    data = GST_BUFFER_DATA (*buf);
-
-    injected_bytes = 0;
-    striped_so_far = 0;
-    j = 0;
-    for (i = 0; i < inject_len; ++i) {
-      int res;
-
-      while (j < strip_len) {
-        if (strip[j].offset_orig < inject[i].offset_orig)
-          striped_so_far += bsize_strip[j++];
-        else
-          break;
-      }
-
-      if (inject[i].offset_orig >= offset_orig) {
-        if (inject[i].offset_orig <
-            offset_orig + size_buf_in + striped_bytes - injected_bytes) {
-          /* insert */
-          guint32 buf_off =
-              inject[i].offset_orig - offset_orig - striped_so_far +
-              injected_bytes;
-          memmove (data + buf_off + inject[i].size, data + buf_off,
-              size_buf_in - buf_off);
-          memcpy (data + buf_off, inject[i].data, inject[i].size);
-          injected_bytes += inject[i].size;
-          size_buf_in += inject[i].size;
-        } else {
-          /* segment is after size (segments are sorted) */
-          break;
-        }
-      }
-    }
-
-  }
-
-
-done:
-
-  if (prepend_size) {
-    if (injected_bytes == 0 && striped_bytes == 0) {
-      GstBuffer *new_buf =
-          gst_buffer_new_and_alloc (size_buf_in + prepend_size);
-
-      memcpy (GST_BUFFER_DATA (new_buf) + prepend_size, GST_BUFFER_DATA (*buf),
-          size_buf_in);
-
-      gst_buffer_unref (*buf);
-      *buf = new_buf;
-    } else {
-      memmove (GST_BUFFER_DATA (*buf) + prepend_size, GST_BUFFER_DATA (*buf),
-          size_buf_in);
-    }
-    memcpy (GST_BUFFER_DATA (*buf), GST_BUFFER_DATA (*prepend), prepend_size);
-    gst_buffer_unref (*prepend);
-    *prepend = NULL;
-  }
-
-  GST_BUFFER_SIZE (*buf) = size_buf_in + prepend_size;
-
-  if (need_free_strip) {
-    g_free (boffset_strip);
-    g_free (bsize_strip);
-    g_free (seg_binter_strip);
-  }
-
-  return injected_bytes || striped_bytes;
-
-}
-
-/*
- * pos - position in stream striped
- * orig_pos - position in original stream
- * return TRUE - position in original buffer
- *        FALSE - position in inserted chunk
- */
-static gboolean
-gst_metadata_mux_translate_pos_to_orig (GstMetadataMux * filter, gint64 pos,
-    gint64 * orig_pos, GstBuffer ** buf)
-{
-  int i;
-  MetadataChunk *strip = filter->mux_data.strip_chunks.chunk;
-  MetadataChunk *inject = filter->mux_data.inject_chunks.chunk;
-  const gsize strip_len = filter->mux_data.strip_chunks.len;
-  const gsize inject_len = filter->mux_data.inject_chunks.len;
-  gboolean ret = TRUE;
-  guint64 new_buf_size = 0;
-  guint64 injected_before = 0;
-
-  if (G_UNLIKELY (pos == -1)) {
-    *orig_pos = -1;
-    return TRUE;
-  } else if (G_UNLIKELY (pos >= filter->duration)) {
-    /* this should never happen */
-    *orig_pos = filter->duration_orig;
-    return TRUE;
-  }
-
-  /* calculate for injected */
-
-  /* just calculate size */
-  *orig_pos = pos;              /* save pos */
-  for (i = 0; i < inject_len; ++i) {
-    /* check if pos in inside chunk */
-    if (inject[i].offset <= pos) {
-      if (pos < inject[i].offset + inject[i].size) {
-        /* orig pos points after insert chunk */
-        new_buf_size += inject[i].size;
-        /* put pos after current chunk */
-        pos = inject[i].offset + inject[i].size;
-        ret = FALSE;
-      } else {
-        /* in case pos is not inside a injected chunk */
-        injected_before += inject[i].size;
-      }
-    } else {
-      break;
-    }
-  }
-
-  /* alloc buffer and calcute original pos */
-  if (buf && ret == FALSE) {
-    guint8 *data;
-
-    if (*buf)
-      gst_buffer_unref (*buf);
-    *buf = gst_buffer_new_and_alloc (new_buf_size);
-    data = GST_BUFFER_DATA (*buf);
-    pos = *orig_pos;            /* recover saved pos */
-    for (i = 0; i < inject_len; ++i) {
-      if (inject[i].offset > pos) {
-        break;
-      }
-      if (inject[i].offset <= pos && pos < inject[i].offset + inject[i].size) {
-        memcpy (data, inject[i].data, inject[i].size);
-        data += inject[i].size;
-        pos = inject[i].offset + inject[i].size;
-        /* out position after insert chunk orig */
-        *orig_pos = inject[i].offset_orig + inject[i].size;
-      }
-    }
-  }
-
-  if (ret == FALSE) {
-    /* if it inside a injected is already done */
-    goto done;
-  }
-
-  /* calculate for striped */
-
-  *orig_pos = pos - injected_before;
-  for (i = 0; i < strip_len; ++i) {
-    if (strip[i].offset_orig > pos) {
-      break;
-    }
-    *orig_pos += strip[i].size;
-  }
-
-done:
-
-  if (G_UNLIKELY (*orig_pos >= filter->duration_orig)) {
-    *orig_pos = filter->duration_orig - 1;
-  }
-
-  return ret;
-
-}
-
 static gboolean
 gst_metadata_mux_checkgetrange (GstPad * srcpad)
 {
@@ -1707,26 +1158,30 @@ gst_metadata_mux_get_range (GstPad * pad,
   filter = GST_METADATA_MUX (GST_PAD_PARENT (pad));
 
   if (filter->need_calculate_offset) {
-    if (!gst_metadata_mux_calculate_offsets (filter)) {
+    gst_metadata_create_chunks_from_tags (filter);
+    if (gst_metadata_common_calculate_offsets (&filter->common)) {
+      filter->need_calculate_offset = FALSE;
+    } else {
       ret = GST_FLOW_ERROR;
       goto done;
     }
   }
 
-  if (offset + size > filter->duration) {
-    size = filter->duration - offset;
+  if (offset + size > filter->common.duration) {
+    size = filter->common.duration - offset;
   }
 
   size_orig = size;
 
-  gst_metadata_mux_translate_pos_to_orig (filter, offset, &offset_orig,
-      &prepend);
+  gst_metadata_common_translate_pos_to_orig (&filter->common, offset,
+      &offset_orig, &prepend);
 
   if (size > 1) {
     gint64 pos;
 
     pos = offset + size - 1;
-    gst_metadata_mux_translate_pos_to_orig (filter, pos, &pos, NULL);
+    gst_metadata_common_translate_pos_to_orig (&filter->common, pos, &pos,
+        NULL);
     size_orig = pos + 1 - offset_orig;
   }
 
@@ -1735,7 +1190,8 @@ gst_metadata_mux_get_range (GstPad * pad,
     ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf);
 
     if (ret == GST_FLOW_OK && *buf) {
-      gst_metadata_mux_strip_push_buffer (filter, offset_orig, &prepend, buf);
+      gst_metadata_common_strip_push_buffer (&filter->common, offset_orig,
+          &prepend, buf);
 
       if (GST_BUFFER_SIZE (*buf) < size) {
         /* need append */
@@ -1751,7 +1207,7 @@ done:
 
   if (need_append) {
     /* FIXME: together with SEEK and
-     * gst_metadata_parse_translate_pos_to_orig
+     * gst_metadata_common_translate_pos_to_orig
      * this way if chunk is added in the end we are in trolble
      * ...still not implemented 'cause it will not be the
      * case for the time being
@@ -1772,7 +1228,7 @@ gst_metadata_mux_src_activate_pull (GstPad * pad, gboolean active)
 
   ret = gst_pad_activate_pull (filter->sinkpad, active);
 
-  if (ret && filter->state == MT_STATE_NULL) {
+  if (ret && filter->common.state == MT_STATE_NULL) {
     ret = gst_metadata_mux_pull_range_mux (filter);
   }
 
@@ -1792,7 +1248,7 @@ gst_metadata_mux_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_NULL_TO_READY:
       gst_metadata_mux_init_members (filter);
       filter->adapter_parsing = gst_adapter_new ();
-      metadata_init (&filter->mux_data, FALSE, filter->options);
+      gst_metadata_common_init (&filter->common, FALSE, filter->options);
       break;
     default:
       break;
@@ -1812,11 +1268,10 @@ gst_metadata_mux_change_state (GstElement * element, GstStateChange transition)
       if (filter->adapter_holding) {
         gst_adapter_clear (filter->adapter_holding);
       }
-      if (filter->state != MT_STATE_MUXED) {
+      if (filter->common.state != MT_STATE_PARSED) {
         /* cleanup parser */
-        /* FIXME: could be improved a bit to avoid mem allocation */
-        metadata_dispose (&filter->mux_data);
-        metadata_init (&filter->mux_data, FALSE, filter->options);
+        gst_metadata_common_dispose (&filter->common);
+        gst_metadata_common_init (&filter->common, FALSE, filter->options);
       }
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
index c7cb40ba13bec478b482fabd9b11bdb5a6e89e7b..8b123f5115e4f91ec46a9a9b46f10a390cc23833 100644 (file)
@@ -46,7 +46,7 @@
 
 #include <gst/gst.h>
 
-#include "metadata.h"
+#include "gstmetadatacommon.h"
 
 G_BEGIN_DECLS
 /* #defines don't like whitespacey bits */
@@ -63,21 +63,16 @@ G_BEGIN_DECLS
 typedef struct _GstMetadataMux GstMetadataMux;
 typedef struct _GstMetadataMuxClass GstMetadataMuxClass;
 
-typedef enum _tag_MetadataState
-{
-  MT_STATE_NULL,                /* still need to check media type */
-  MT_STATE_MUXED
-} MetadataState;
-
 struct _GstMetadataMux
 {
   GstElement element;
 
   GstPad *sinkpad, *srcpad;
 
+  GstMetadataCommon common;
+
   guint8 options;
 
-  MetaData mux_data;
   GstAdapter *adapter_parsing;
   GstAdapter *adapter_holding;
   guint32 next_offset;
@@ -85,14 +80,9 @@ struct _GstMetadataMux
   ImageType img_type;
 
   gint64 offset_orig;  /* offset in original stream */
-  gint64 duration_orig;     /* durarion of stream */
   gint64 offset;       /* offset in current stream */
-  gint64 duration;     /* durarion of modified stream */
-
-  MetadataState state;
 
   GstBuffer * prepend_buffer;
-  GstBuffer * append_buffer;
 
   gboolean need_more_data;
 
diff --git a/ext/metadata/gstmetadataparse.c b/ext/metadata/gstmetadataparse.c
deleted file mode 100644 (file)
index d95a939..0000000
+++ /dev/null
@@ -1,1801 +0,0 @@
-/*
- * GStreamer
- * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br>
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Alternatively, the contents of this file may be used under the
- * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
- * which case the following provisions apply instead of the ones
- * mentioned above:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:metadataparse-metadata
- *
- * <refsect2>
- * <title>Example launch line</title>
- * <para>
- * <programlisting>
- * gst-launch -v -m filesrc location=./test.jpeg ! metadataparse ! fakesink silent=TRUE
- * </programlisting>
- * </para>
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <gst/gst.h>
-
-#include "gstmetadataparse.h"
-
-#include "metadataexif.h"
-
-#include "metadataiptc.h"
-
-#include "metadataxmp.h"
-
-#include <string.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_metadata_parse_debug);
-#define GST_CAT_DEFAULT gst_metadata_parse_debug
-
-#define GOTO_DONE_IF_NULL(ptr) do { if ( NULL == (ptr) ) goto done; } while(FALSE)
-#define GOTO_DONE_IF_NULL_AND_FAIL(ptr, ret) do { if ( NULL == (ptr) ) { (ret) = FALSE; goto done; } } while(FALSE)
-
-/* Filter signals and args */
-enum
-{
-  /* FILL ME */
-  LAST_SIGNAL
-};
-
-enum
-{
-  ARG_0,
-  ARG_EXIF,
-  ARG_IPTC,
-  ARG_XMP
-};
-
-static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
-    GST_PAD_SINK,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("image/jpeg, "
-        "tags-extracted = (bool) false;"
-        "image/png, " "tags-extracted = (bool) false")
-    );
-
-static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
-    GST_PAD_SRC,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("image/jpeg, "
-        "tags-extracted = (bool) true;"
-        "image/png, " "tags-extracted = (bool) true")
-    );
-
-GST_BOILERPLATE (GstMetadataParse, gst_metadata_parse, GstElement,
-    GST_TYPE_ELEMENT);
-
-static GstMetadataParseClass *metadata_parent_class = NULL;
-
-static void gst_metadata_parse_dispose (GObject * object);
-
-static void gst_metadata_parse_finalize (GObject * object);
-
-static void gst_metadata_parse_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec);
-static void gst_metadata_parse_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec);
-
-static GstStateChangeReturn
-gst_metadata_parse_change_state (GstElement * element,
-    GstStateChange transition);
-
-static GstCaps *gst_metadata_parse_get_caps (GstPad * pad);
-static gboolean gst_metadata_parse_set_caps (GstPad * pad, GstCaps * caps);
-static gboolean gst_metadata_parse_src_event (GstPad * pad, GstEvent * event);
-static gboolean gst_metadata_parse_sink_event (GstPad * pad, GstEvent * event);
-
-static GstFlowReturn gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf);
-
-static gboolean gst_metadata_parse_checkgetrange (GstPad * srcpad);
-
-static GstFlowReturn
-gst_metadata_parse_get_range (GstPad * pad, guint64 offset_orig, guint size,
-    GstBuffer ** buf);
-
-static gboolean gst_metadata_parse_sink_activate (GstPad * pad);
-
-static gboolean
-gst_metadata_parse_src_activate_pull (GstPad * pad, gboolean active);
-
-static gboolean gst_metadata_parse_pull_range_parse (GstMetadataParse * filter);
-
-static void gst_metadata_parse_init_members (GstMetadataParse * filter);
-static void gst_metadata_parse_dispose_members (GstMetadataParse * filter);
-
-static gboolean
-gst_metadata_parse_configure_srccaps (GstMetadataParse * filter);
-static gboolean gst_metadata_parse_configure_caps (GstMetadataParse * filter);
-
-static int
-gst_metadata_parse_parse (GstMetadataParse * filter, const guint8 * buf,
-    guint32 size);
-
-static void gst_metadata_parse_send_tags (GstMetadataParse * filter);
-
-
-
-static int
-gst_metadata_parse_get_strip_seg (const gint64 offset, guint32 size,
-    const gint64 seg_offset, const guint32 seg_size,
-    gint64 * boffset, guint32 * bsize, guint32 * seg_binter);
-
-static gboolean
-gst_metadata_parse_strip_push_buffer (GstMetadataParse * filter,
-    gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf);
-
-static gboolean
-gst_metadata_parse_translate_pos_to_orig (GstMetadataParse * filter, gint64 pos,
-    gint64 * orig_pos, GstBuffer ** buf);
-
-static const GstQueryType *gst_metadata_parse_get_query_types (GstPad * pad);
-
-static gboolean gst_metadata_parse_src_query (GstPad * pad, GstQuery * query);
-
-static void
-gst_metadata_parse_base_init (gpointer gclass)
-{
-  static GstElementDetails element_details = {
-    "Metadata parser",
-    "Parser/Extracter/Metadata",
-    "Send metadata tags (EXIF, IPTC and XMP) while passing throught the contents",
-    "Edgard Lima <edgard.lima@indt.org.br>"
-  };
-  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&src_factory));
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&sink_factory));
-  gst_element_class_set_details (element_class, &element_details);
-}
-
-/* initialize the plugin's class */
-static void
-gst_metadata_parse_class_init (GstMetadataParseClass * klass)
-{
-  GObjectClass *gobject_class;
-  GstElementClass *gstelement_class;
-
-  gobject_class = (GObjectClass *) klass;
-  gstelement_class = (GstElementClass *) klass;
-
-  metadata_parent_class = g_type_class_peek_parent (klass);
-
-  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_metadata_parse_dispose);
-  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_metadata_parse_finalize);
-
-  gobject_class->set_property = gst_metadata_parse_set_property;
-  gobject_class->get_property = gst_metadata_parse_get_property;
-
-  g_object_class_install_property (gobject_class, ARG_EXIF,
-      g_param_spec_boolean ("exif", "EXIF", "Send EXIF metadata ?",
-          TRUE, G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class, ARG_IPTC,
-      g_param_spec_boolean ("iptc", "IPTC", "Send IPTC metadata ?",
-          TRUE, G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class, ARG_XMP,
-      g_param_spec_boolean ("xmp", "XMP", "Send XMP metadata ?",
-          TRUE, G_PARAM_READWRITE));
-
-  gstelement_class->change_state = gst_metadata_parse_change_state;
-
-}
-
-/* initialize the new element
- * instantiate pads and add them to element
- * set functions
- * initialize structure
- */
-static void
-gst_metadata_parse_init (GstMetadataParse * filter,
-    GstMetadataParseClass * gclass)
-{
-  GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
-
-  /* sink pad */
-
-  filter->sinkpad =
-      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
-          "sink"), "sink");
-  gst_pad_set_setcaps_function (filter->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_metadata_parse_set_caps));
-  gst_pad_set_getcaps_function (filter->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_metadata_parse_get_caps));
-  gst_pad_set_event_function (filter->sinkpad, gst_metadata_parse_sink_event);
-  gst_pad_set_chain_function (filter->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_metadata_parse_chain));
-  gst_pad_set_activate_function (filter->sinkpad,
-      gst_metadata_parse_sink_activate);
-
-  /* source pad */
-
-  filter->srcpad =
-      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
-          "src"), "src");
-  gst_pad_set_getcaps_function (filter->srcpad,
-      GST_DEBUG_FUNCPTR (gst_metadata_parse_get_caps));
-  gst_pad_set_event_function (filter->srcpad, gst_metadata_parse_src_event);
-  gst_pad_set_query_function (filter->srcpad,
-      GST_DEBUG_FUNCPTR (gst_metadata_parse_src_query));
-  gst_pad_set_query_type_function (filter->srcpad,
-      GST_DEBUG_FUNCPTR (gst_metadata_parse_get_query_types));
-  gst_pad_use_fixed_caps (filter->srcpad);
-
-  gst_pad_set_checkgetrange_function (filter->srcpad,
-      GST_DEBUG_FUNCPTR (gst_metadata_parse_checkgetrange));
-  gst_pad_set_getrange_function (filter->srcpad, gst_metadata_parse_get_range);
-
-  gst_pad_set_activatepull_function (filter->srcpad,
-      GST_DEBUG_FUNCPTR (gst_metadata_parse_src_activate_pull));
-  /* addind pads */
-
-  gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
-  gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
-
-  metadataparse_xmp_init ();
-  /* init members */
-
-  filter->options = META_OPT_EXIF | META_OPT_IPTC | META_OPT_XMP;
-
-  gst_metadata_parse_init_members (filter);
-
-}
-
-static void
-gst_metadata_parse_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstMetadataParse *filter = GST_METADATA_PARSE (object);
-
-  switch (prop_id) {
-    case ARG_EXIF:
-      if (g_value_get_boolean (value))
-        filter->options |= META_OPT_EXIF;
-      else
-        filter->options &= ~META_OPT_EXIF;
-      break;
-    case ARG_IPTC:
-      if (g_value_get_boolean (value))
-        filter->options |= META_OPT_IPTC;
-      else
-        filter->options &= ~META_OPT_IPTC;
-      break;
-    case ARG_XMP:
-      if (g_value_get_boolean (value))
-        filter->options |= META_OPT_XMP;
-      else
-        filter->options &= ~META_OPT_XMP;
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_metadata_parse_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec)
-{
-  GstMetadataParse *filter = GST_METADATA_PARSE (object);
-
-  switch (prop_id) {
-    case ARG_EXIF:
-      g_value_set_boolean (value, filter->options & META_OPT_EXIF);
-      break;
-    case ARG_IPTC:
-      g_value_set_boolean (value, filter->options & META_OPT_IPTC);
-      break;
-    case ARG_XMP:
-      g_value_set_boolean (value, filter->options & META_OPT_XMP);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-/* GstElement vmethod implementations */
-
-static GstCaps *
-gst_metadata_parse_get_caps (GstPad * pad)
-{
-  GstMetadataParse *filter = NULL;
-  GstPad *otherpad;
-  GstCaps *caps_new = NULL;
-  GstCaps *caps_otherpad_peer = NULL;
-
-  filter = GST_METADATA_PARSE (gst_pad_get_parent (pad));
-
-  (filter->srcpad == pad) ? (otherpad = filter->sinkpad) : (otherpad =
-      filter->srcpad);
-
-  caps_new = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
-
-  caps_otherpad_peer = gst_pad_get_allowed_caps (otherpad);
-  GOTO_DONE_IF_NULL (caps_otherpad_peer);
-
-  if (gst_caps_is_empty (caps_otherpad_peer)
-      || gst_caps_is_any (caps_otherpad_peer)) {
-    goto done;
-  } else {
-
-    guint i;
-    guint caps_size = 0;
-
-    caps_size = gst_caps_get_size (caps_otherpad_peer);
-
-    gst_caps_unref (caps_new);
-
-    caps_new = gst_caps_new_empty ();
-
-    for (i = 0; i < caps_size; ++i) {
-      GstStructure *structure = NULL;
-      GstStructure *structure_new = NULL;
-      const gchar *mime = NULL;
-
-      structure = gst_caps_get_structure (caps_otherpad_peer, i);
-
-      mime = gst_structure_get_name (structure);
-
-      if (pad == filter->sinkpad) {
-        structure_new =
-            gst_structure_new (mime, "tags-extracted", G_TYPE_BOOLEAN, FALSE,
-            NULL);
-      } else {
-        structure_new =
-            gst_structure_new (mime, "tags-extracted", G_TYPE_BOOLEAN, TRUE,
-            NULL);
-      }
-
-      gst_caps_append_structure (caps_new, structure_new);
-
-    }
-
-  }
-
-done:
-
-  if (caps_otherpad_peer) {
-    gst_caps_unref (caps_otherpad_peer);
-    caps_otherpad_peer = NULL;
-  }
-
-  gst_object_unref (filter);
-
-  return caps_new;
-
-}
-
-static gboolean
-gst_metadata_parse_src_event (GstPad * pad, GstEvent * event)
-{
-  GstMetadataParse *filter = NULL;
-  gboolean ret = FALSE;
-
-  filter = GST_METADATA_PARSE (gst_pad_get_parent (pad));
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_SEEK:
-    {
-      gdouble rate;
-      GstFormat format;
-      GstSeekFlags flags;
-      GstSeekType start_type;
-      gint64 start;
-      GstSeekType stop_type;
-      gint64 stop;
-
-      /* we don't know where are the chunks to be stripped before parse */
-      if (filter->state != MT_STATE_PARSED)
-        goto done;
-
-      gst_event_parse_seek (event, &rate, &format, &flags,
-          &start_type, &start, &stop_type, &stop);
-
-      switch (format) {
-        case GST_FORMAT_BYTES:
-          break;
-        case GST_FORMAT_PERCENT:
-          if (filter->duration < 0)
-            goto done;
-          start = start * filter->duration / 100;
-          stop = stop * filter->duration / 100;
-          break;
-        default:
-          goto done;
-      }
-      format = GST_FORMAT_BYTES;
-
-      if (start_type == GST_SEEK_TYPE_CUR)
-        start = filter->offset + start;
-      else if (start_type == GST_SEEK_TYPE_END) {
-        if (filter->duration < 0)
-          goto done;
-        start = filter->duration + start;
-      }
-      start_type == GST_SEEK_TYPE_SET;
-
-      if (filter->prepend_buffer) {
-        gst_buffer_unref (filter->prepend_buffer);
-        filter->prepend_buffer = NULL;
-      }
-
-      /* FIXME: related to append */
-      filter->offset = start;
-      gst_metadata_parse_translate_pos_to_orig (filter, start, &start,
-          &filter->prepend_buffer);
-      filter->offset_orig = start;
-
-      if (stop_type == GST_SEEK_TYPE_CUR)
-        stop = filter->offset + stop;
-      else if (stop_type == GST_SEEK_TYPE_END) {
-        if (filter->duration < 0)
-          goto done;
-        stop = filter->duration + stop;
-      }
-      stop_type == GST_SEEK_TYPE_SET;
-
-      gst_metadata_parse_translate_pos_to_orig (filter, stop, &stop, NULL);
-
-      gst_event_unref (event);
-      event = gst_event_new_seek (rate, format, flags,
-          start_type, start, stop_type, stop);
-
-    }
-      break;
-    default:
-      break;
-  }
-
-  ret = gst_pad_event_default (pad, event);
-  event = NULL;                 /* event has another owner */
-
-done:
-
-  if (event) {
-    gst_event_unref (event);
-  }
-
-  gst_object_unref (filter);
-
-  return ret;
-
-}
-
-static gboolean
-gst_metadata_parse_sink_event (GstPad * pad, GstEvent * event)
-{
-  GstMetadataParse *filter = NULL;
-  gboolean ret = FALSE;
-
-  filter = GST_METADATA_PARSE (gst_pad_get_parent (pad));
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_EOS:
-      if (filter->need_more_data) {
-        GST_ELEMENT_WARNING (filter, STREAM, DEMUX, (NULL),
-            ("Need more data. Unexpected EOS"));
-      }
-      break;
-    case GST_EVENT_TAG:
-      break;
-    default:
-      break;
-  }
-
-  ret = gst_pad_event_default (pad, event);
-
-  gst_object_unref (filter);
-
-  return ret;
-
-}
-
-static void
-gst_metadata_parse_dispose (GObject * object)
-{
-  GstMetadataParse *filter = NULL;
-
-  filter = GST_METADATA_PARSE (object);
-
-  gst_metadata_parse_dispose_members (filter);
-
-  metadataparse_xmp_dispose ();
-
-  G_OBJECT_CLASS (metadata_parent_class)->dispose (object);
-
-}
-
-static void
-gst_metadata_parse_finalize (GObject * object)
-{
-  G_OBJECT_CLASS (metadata_parent_class)->finalize (object);
-}
-
-static void
-gst_metadata_parse_dispose_members (GstMetadataParse * filter)
-{
-  metadata_dispose (&filter->parse_data);
-
-  if (filter->adapter_parsing) {
-    gst_object_unref (filter->adapter_parsing);
-    filter->adapter_parsing = NULL;
-  }
-
-  if (filter->adapter_holding) {
-    gst_object_unref (filter->adapter_holding);
-    filter->adapter_holding = NULL;
-  }
-
-  if (filter->append_buffer) {
-    gst_buffer_unref (filter->append_buffer);
-    filter->append_buffer = NULL;
-  }
-
-  if (filter->prepend_buffer) {
-    gst_buffer_unref (filter->prepend_buffer);
-    filter->prepend_buffer = NULL;
-  }
-}
-
-static void
-gst_metadata_parse_init_members (GstMetadataParse * filter)
-{
-  filter->need_send_tag = FALSE;
-
-  filter->adapter_parsing = NULL;
-  filter->adapter_holding = NULL;
-  filter->next_offset = 0;
-  filter->next_size = 0;
-  filter->img_type = IMG_NONE;
-  filter->offset_orig = 0;
-  filter->duration_orig = 0;
-  filter->offset = 0;
-  filter->duration = 0;
-  filter->state = MT_STATE_NULL;
-  filter->need_more_data = FALSE;
-
-  filter->append_buffer = NULL;
-  filter->prepend_buffer = NULL;
-
-  memset (&filter->parse_data, 0x00, sizeof (MetaData));
-
-}
-
-static gboolean
-gst_metadata_parse_configure_srccaps (GstMetadataParse * filter)
-{
-  GstCaps *caps = NULL;
-  gboolean ret = FALSE;
-  gchar *mime = NULL;
-
-  switch (filter->img_type) {
-    case IMG_JPEG:
-      mime = "image/jpeg";
-      break;
-    case IMG_PNG:
-      mime = "image/png";
-      break;
-    default:
-      ret = FALSE;
-      goto done;
-      break;
-  }
-
-  caps =
-      gst_caps_new_simple (mime, "tags-extracted", G_TYPE_BOOLEAN, TRUE, NULL);
-
-  ret = gst_pad_set_caps (filter->srcpad, caps);
-
-done:
-
-  if (caps) {
-    gst_caps_unref (caps);
-    caps = NULL;
-  }
-
-  return ret;
-
-}
-
-static gboolean
-gst_metadata_parse_configure_caps (GstMetadataParse * filter)
-{
-  GstCaps *caps = NULL;
-  gboolean ret = FALSE;
-  gchar *mime = NULL;
-  GstPad *peer = NULL;
-
-  peer = gst_pad_get_peer (filter->sinkpad);
-
-  switch (filter->img_type) {
-    case IMG_JPEG:
-      mime = "image/jpeg";
-      break;
-    case IMG_PNG:
-      mime = "image/png";
-      break;
-    default:
-      goto done;
-      break;
-  }
-
-  caps = gst_caps_new_simple (mime, NULL);
-
-  if (!gst_pad_set_caps (peer, caps)) {
-    goto done;
-  }
-
-  ret = gst_pad_set_caps (filter->sinkpad, caps);
-
-done:
-
-  if (caps) {
-    gst_caps_unref (caps);
-    caps = NULL;
-  }
-
-  if (peer) {
-    gst_object_unref (peer);
-    peer = NULL;
-  }
-
-  return ret;
-
-}
-
-/* this function handles the link with other elements */
-static gboolean
-gst_metadata_parse_set_caps (GstPad * pad, GstCaps * caps)
-{
-  GstMetadataParse *filter = NULL;
-  GstStructure *structure = NULL;
-  const gchar *mime = NULL;
-  gboolean ret = FALSE;
-  gboolean parsed = TRUE;
-
-  filter = GST_METADATA_PARSE (gst_pad_get_parent (pad));
-
-  structure = gst_caps_get_structure (caps, 0);
-
-  mime = gst_structure_get_name (structure);
-
-  if (strcmp (mime, "image/jpeg") == 0) {
-    filter->img_type = IMG_JPEG;
-  } else if (strcmp (mime, "image/png") == 0) {
-    filter->img_type = IMG_PNG;
-  } else {
-    ret = FALSE;
-    goto done;
-  }
-
-  if (gst_structure_get_boolean (structure, "tags-extracted", &parsed)) {
-    if (parsed == TRUE) {
-      ret = FALSE;
-      goto done;
-    }
-  }
-
-  ret = gst_metadata_parse_configure_srccaps (filter);
-
-done:
-
-  gst_object_unref (filter);
-
-  return ret;
-}
-
-static const gchar *
-gst_metadata_parse_get_type_name (int img_type)
-{
-  gchar *type_name = NULL;
-
-  switch (img_type) {
-    case IMG_JPEG:
-      type_name = "jpeg";
-      break;
-    case IMG_PNG:
-      type_name = "png";
-      break;
-    default:
-      type_name = "invalid type";
-      break;
-  }
-  return type_name;
-}
-
-static void
-gst_metadata_parse_send_tags (GstMetadataParse * filter)
-{
-
-  GstMessage *msg;
-  GstTagList *taglist = gst_tag_list_new ();
-  GstEvent *event;
-
-  if (filter->options & META_OPT_EXIF)
-    metadataparse_exif_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
-        filter->parse_data.exif_adapter, METADATA_TAG_MAP_WHOLECHUNK);
-  if (filter->options & META_OPT_IPTC)
-    metadataparse_iptc_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
-        filter->parse_data.iptc_adapter, METADATA_TAG_MAP_WHOLECHUNK);
-  if (filter->options & META_OPT_XMP)
-    metadataparse_xmp_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
-        filter->parse_data.xmp_adapter, METADATA_TAG_MAP_WHOLECHUNK);
-
-  if (taglist && !gst_tag_list_is_empty (taglist)) {
-
-    msg =
-        gst_message_new_tag (GST_OBJECT (filter), gst_tag_list_copy (taglist));
-    gst_element_post_message (GST_ELEMENT (filter), msg);
-
-    event = gst_event_new_tag (taglist);
-    gst_pad_push_event (filter->srcpad, event);
-    taglist = NULL;
-  }
-
-  if (!taglist)
-    taglist = gst_tag_list_new ();
-
-  if (filter->options & META_OPT_EXIF)
-    metadataparse_exif_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
-        filter->parse_data.exif_adapter, METADATA_TAG_MAP_INDIVIDUALS);
-  if (filter->options & META_OPT_IPTC)
-    metadataparse_iptc_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
-        filter->parse_data.iptc_adapter, METADATA_TAG_MAP_INDIVIDUALS);
-  if (filter->options & META_OPT_XMP)
-    metadataparse_xmp_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
-        filter->parse_data.xmp_adapter, METADATA_TAG_MAP_INDIVIDUALS);
-
-  if (taglist && !gst_tag_list_is_empty (taglist)) {
-
-    msg = gst_message_new_tag (GST_OBJECT (filter), taglist);
-    gst_element_post_message (GST_ELEMENT (filter), msg);
-    taglist = NULL;
-  }
-
-  if (taglist)
-    gst_tag_list_free (taglist);
-
-  filter->need_send_tag = FALSE;
-}
-
-static const GstQueryType *
-gst_metadata_parse_get_query_types (GstPad * pad)
-{
-  static const GstQueryType gst_metadata_parse_src_query_types[] = {
-    GST_QUERY_POSITION,
-    GST_QUERY_DURATION,
-    GST_QUERY_FORMATS,
-    0
-  };
-
-  return gst_metadata_parse_src_query_types;
-}
-
-static gboolean
-gst_metadata_parse_src_query (GstPad * pad, GstQuery * query)
-{
-  gboolean ret = FALSE;
-  GstFormat format;
-  GstMetadataParse *filter = GST_METADATA_PARSE (gst_pad_get_parent (pad));
-
-  switch (GST_QUERY_TYPE (query)) {
-    case GST_QUERY_POSITION:
-      gst_query_parse_position (query, &format, NULL);
-
-      if (format == GST_FORMAT_BYTES) {
-        gst_query_set_position (query, GST_FORMAT_BYTES, filter->offset);
-        ret = TRUE;
-      }
-      break;
-    case GST_QUERY_DURATION:
-      if (filter->state != MT_STATE_PARSED)
-        goto done;
-
-      gst_query_parse_duration (query, &format, NULL);
-
-      if (format == GST_FORMAT_BYTES) {
-        if (filter->duration >= 0) {
-          gst_query_set_duration (query, GST_FORMAT_BYTES, filter->duration);
-          ret = TRUE;
-        }
-      }
-      break;
-    case GST_QUERY_FORMATS:
-      gst_query_set_formats (query, 1, GST_FORMAT_BYTES);
-      ret = TRUE;
-      break;
-    default:
-      break;
-  }
-
-done:
-
-  gst_object_unref (filter);
-
-  return ret;
-
-}
-
-static void
-gst_metadata_parse_calculate_offsets (GstMetadataParse * filter)
-{
-  int i, j;
-  guint32 append_size;
-  guint32 bytes_striped, bytes_inject;
-  MetadataChunk *strip = filter->parse_data.strip_chunks.chunk;
-  MetadataChunk *inject = filter->parse_data.inject_chunks.chunk;
-  const gsize strip_len = filter->parse_data.strip_chunks.len;
-  const gsize inject_len = filter->parse_data.inject_chunks.len;
-
-  bytes_striped = 0;
-  bytes_inject = 0;
-
-  /* calculate the new position off injected chunks */
-  j = 0;
-  for (i = 0; i < inject_len; ++i) {
-    for (; j < strip_len; ++j) {
-      if (strip[j].offset_orig >= inject[i].offset_orig) {
-        break;
-      }
-      bytes_striped += strip[j].size;
-    }
-    inject[i].offset = inject[i].offset_orig - bytes_striped + bytes_inject;
-    bytes_inject += inject[i].size;
-  }
-
-  /* calculate append (doesnt make much sense, but, anyway..) */
-  append_size = 0;
-  for (i = inject_len - 1; i >= 0; --i) {
-    if (inject[i].offset_orig == filter->duration_orig)
-      append_size += inject[i].size;
-    else
-      break;
-  }
-  if (append_size) {
-    guint8 *data;
-
-    filter->append_buffer = gst_buffer_new_and_alloc (append_size);
-    GST_BUFFER_FLAG_SET (filter->append_buffer, GST_BUFFER_FLAG_READONLY);
-    data = GST_BUFFER_DATA (filter->append_buffer);
-    for (i = inject_len - 1; i >= 0; --i) {
-      if (inject[i].offset_orig == filter->duration_orig) {
-        memcpy (data, inject[i].data, inject[i].size);
-        data += inject[i].size;
-      } else {
-        break;
-      }
-    }
-  }
-
-  /* do nothing but just call for consistence */
-  metadata_lazy_update (&filter->parse_data);
-
-  if (filter->duration_orig) {
-    filter->duration = filter->duration_orig;
-    for (i = 0; i < inject_len; ++i) {
-      filter->duration += inject[i].size;
-    }
-    for (i = 0; i < strip_len; ++i) {
-      filter->duration -= strip[i].size;
-    }
-  }
-
-}
-
-/*
- * Do parsing step-by-step and reconfigure caps if need
- * return:
- *   META_PARSING_ERROR
- *   META_PARSING_DONE
- *   META_PARSING_NEED_MORE_DATA
- */
-
-static int
-gst_metadata_parse_parse (GstMetadataParse * filter, const guint8 * buf,
-    guint32 size)
-{
-
-  int ret = META_PARSING_ERROR;
-
-  filter->next_offset = 0;
-  filter->next_size = 0;
-
-  ret = metadata_parse (&filter->parse_data, buf, size,
-      &filter->next_offset, &filter->next_size);
-
-  if (ret == META_PARSING_ERROR) {
-    if (META_DATA_IMG_TYPE (filter->parse_data) == IMG_NONE) {
-      /* image type not recognized */
-      GST_ELEMENT_ERROR (filter, STREAM, TYPE_NOT_FOUND, (NULL),
-          ("Only jpeg and png are supported"));
-      goto done;
-    }
-  } else if (ret == META_PARSING_NEED_MORE_DATA) {
-    filter->need_more_data = TRUE;
-  } else {
-    gst_metadata_parse_calculate_offsets (filter);
-
-    filter->state = MT_STATE_PARSED;
-    filter->need_more_data = FALSE;
-    filter->need_send_tag = TRUE;
-  }
-
-  /* reconfigure caps if it is different from type detected by 'metadata_parse' function */
-  if (filter->img_type != META_DATA_IMG_TYPE (filter->parse_data)) {
-    filter->img_type = META_DATA_IMG_TYPE (filter->parse_data);
-    if (!gst_metadata_parse_configure_caps (filter)) {
-      GST_ELEMENT_ERROR (filter, STREAM, FORMAT, (NULL),
-          ("Couldn't reconfigure caps for %s",
-              gst_metadata_parse_get_type_name (filter->img_type)));
-      ret = META_PARSING_ERROR;
-      goto done;
-    }
-  }
-
-done:
-
-  return ret;
-
-}
-
-/* chain function
- * this function does the actual processing
- */
-
-/* FIXME */
-/* Current parse is just done before is pull mode could be activated */
-/* may be it is possible to parse in chain mode by doing some trick with gst-adapter */
-/* the pipeline below would be a test for that case */
-/* gst-launch-0.10 filesrc location=Exif.jpg ! queue !  metadataparse ! filesink location=gen3.jpg */
-
-static GstFlowReturn
-gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf)
-{
-  GstMetadataParse *filter = NULL;
-  GstFlowReturn ret = GST_FLOW_ERROR;
-  guint32 buf_size = 0;
-  guint32 new_buf_size = 0;
-  gboolean append = FALSE;
-
-  filter = GST_METADATA_PARSE (gst_pad_get_parent (pad));
-
-  if (filter->state != MT_STATE_PARSED) {
-    guint32 adpt_size = gst_adapter_available (filter->adapter_parsing);
-
-    if (filter->next_offset) {
-      if (filter->next_offset >= adpt_size) {
-        /* clean adapter */
-        gst_adapter_clear (filter->adapter_parsing);
-        filter->next_offset -= adpt_size;
-        if (filter->next_offset >= GST_BUFFER_SIZE (buf)) {
-          /* we don't need data in this buffer */
-          filter->next_offset -= GST_BUFFER_SIZE (buf);
-        } else {
-          GstBuffer *new_buf;
-
-          /* add to adapter just need part from buf */
-          new_buf =
-              gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) -
-              filter->next_offset);
-          memcpy (GST_BUFFER_DATA (new_buf),
-              GST_BUFFER_DATA (buf) + filter->next_offset,
-              GST_BUFFER_SIZE (buf) - filter->next_offset);
-          filter->next_offset = 0;
-          gst_adapter_push (filter->adapter_parsing, new_buf);
-        }
-      } else {
-        /* remove first bytes and add buffer */
-        gst_adapter_flush (filter->adapter_parsing, filter->next_offset);
-        filter->next_offset = 0;
-        gst_adapter_push (filter->adapter_parsing, gst_buffer_copy (buf));
-      }
-    } else {
-      /* just push buffer */
-      gst_adapter_push (filter->adapter_parsing, gst_buffer_copy (buf));
-    }
-
-    adpt_size = gst_adapter_available (filter->adapter_parsing);
-
-    if (adpt_size && filter->next_size <= adpt_size) {
-      const guint8 *new_buf =
-          gst_adapter_peek (filter->adapter_parsing, adpt_size);
-
-      if (gst_metadata_parse_parse (filter, new_buf,
-              adpt_size) == META_PARSING_ERROR) {
-        ret = GST_FLOW_ERROR;
-        goto done;
-      }
-    }
-  }
-
-  if (filter->state == MT_STATE_PARSED) {
-
-    if (filter->adapter_holding) {
-      gst_adapter_push (filter->adapter_holding, buf);
-      buf = gst_adapter_take_buffer (filter->adapter_holding,
-          gst_adapter_available (filter->adapter_holding));
-      g_object_unref (filter->adapter_holding);
-      filter->adapter_holding = NULL;
-    }
-
-    if (filter->need_send_tag) {
-      gst_metadata_parse_send_tags (filter);
-    }
-
-    if (filter->offset_orig + GST_BUFFER_SIZE (buf) == filter->duration_orig)
-      append = TRUE;
-
-    buf_size = GST_BUFFER_SIZE (buf);
-
-    gst_metadata_parse_strip_push_buffer (filter, filter->offset_orig,
-        &filter->prepend_buffer, &buf);
-
-    if (buf) {                  /* may be all buffer has been striped */
-      gst_buffer_set_caps (buf, GST_PAD_CAPS (filter->srcpad));
-      new_buf_size = GST_BUFFER_SIZE (buf);
-
-      ret = gst_pad_push (filter->srcpad, buf);
-      buf = NULL;               /* this function don't owner it anymore */
-      if (ret != GST_FLOW_OK)
-        goto done;
-    } else {
-      ret = GST_FLOW_OK;
-    }
-
-    if (append && filter->append_buffer) {
-      gst_buffer_set_caps (filter->append_buffer,
-          GST_PAD_CAPS (filter->srcpad));
-      gst_buffer_ref (filter->append_buffer);
-      ret = gst_pad_push (filter->srcpad, filter->append_buffer);
-      if (ret != GST_FLOW_OK)
-        goto done;
-    }
-
-    filter->offset_orig += buf_size;
-    filter->offset += new_buf_size;
-
-  } else {
-    /* just store while still not parsed */
-    if (!filter->adapter_holding)
-      filter->adapter_holding = gst_adapter_new ();
-    gst_adapter_push (filter->adapter_holding, buf);
-    buf = NULL;
-    ret = GST_FLOW_OK;
-  }
-
-done:
-
-
-  if (buf) {
-    /* there was an error and buffer wasn't pushed */
-    gst_buffer_unref (buf);
-    buf = NULL;
-  }
-
-  gst_object_unref (filter);
-
-  return ret;
-
-}
-
-static gboolean
-gst_metadata_parse_pull_range_parse (GstMetadataParse * filter)
-{
-
-  int res;
-  gboolean ret = TRUE;
-  guint32 offset = 0;
-  gint64 duration = 0;
-  GstFormat format = GST_FORMAT_BYTES;
-
-  if (!(ret =
-          gst_pad_query_peer_duration (filter->sinkpad, &format, &duration))) {
-    /* this should never happen, but try chain anyway */
-    ret = TRUE;
-    goto done;
-  }
-  filter->duration_orig = duration;
-  if (format != GST_FORMAT_BYTES) {
-    /* this should never happen, but try chain anyway */
-    ret = TRUE;
-    goto done;
-  }
-
-  do {
-    GstFlowReturn flow;
-    GstBuffer *buf = NULL;
-
-    offset += filter->next_offset;
-
-    /* 'filter->next_size' only says the minimum required number of bytes.
-       We try provided more bytes (4096) just to avoid a lot of calls to 'metadata_parse'
-       returning META_PARSING_NEED_MORE_DATA */
-    if (filter->next_size < 4096) {
-      if (duration - offset < 4096) {
-        /* In case there is no 4096 bytes available upstream.
-           It should be done upstream but we do here for safety */
-        filter->next_size = duration - offset;
-      } else {
-        filter->next_size = 4096;
-      }
-    }
-
-    flow =
-        gst_pad_pull_range (filter->sinkpad, offset, filter->next_size, &buf);
-    if (GST_FLOW_OK != flow) {
-      ret = FALSE;
-      goto done;
-    }
-
-    res =
-        gst_metadata_parse_parse (filter, GST_BUFFER_DATA (buf),
-        GST_BUFFER_SIZE (buf));
-    if (res == META_PARSING_ERROR) {
-      ret = FALSE;
-      goto done;
-    }
-
-    gst_buffer_unref (buf);
-
-  } while (res == META_PARSING_NEED_MORE_DATA);
-
-done:
-
-  return ret;
-
-}
-
-static gboolean
-gst_metadata_parse_sink_activate (GstPad * pad)
-{
-  GstMetadataParse *filter = NULL;
-  gboolean ret = TRUE;
-
-
-  filter = GST_METADATA_PARSE (GST_PAD_PARENT (pad));
-
-  if (!gst_pad_check_pull_range (pad) ||
-      !gst_pad_activate_pull (filter->sinkpad, TRUE)) {
-    /* FIXME: currently it is not possible to parse in chain. Fail here ? */
-    /* nothing to be done by now, activate push mode */
-    return gst_pad_activate_push (pad, TRUE);
-  }
-
-  /* try to parse */
-  if (filter->state == MT_STATE_NULL) {
-    ret = gst_metadata_parse_pull_range_parse (filter);
-  }
-
-done:
-
-  if (ret) {
-    gst_pad_activate_pull (pad, FALSE);
-    gst_pad_activate_push (filter->srcpad, FALSE);
-    if (!gst_pad_is_active (pad)) {
-      ret = gst_pad_activate_push (filter->srcpad, TRUE);
-      ret = ret && gst_pad_activate_push (pad, TRUE);
-    }
-  }
-
-  return ret;
-
-}
-
-/*
- * offset - offset of buffer in original stream
- * size - size of buffer
- * seg_offset - offset of segment in original stream
- * seg_size - size of segment
- * boffset - offset inside buffer where segment starts (-1 for no intersection)
- * bsize - size of intersection
- * seg_binter - if segment start inside buffer is zero. if segment start before
- *               buffer and intersect, it is the offset inside segment.
- *
- * ret:
- *  -1 - segment before buffer
- *   0 - segment intersects
- *   1 - segment after buffer
- */
-
-static int
-gst_metadata_parse_get_strip_seg (const gint64 offset, guint32 size,
-    const gint64 seg_offset, const guint32 seg_size,
-    gint64 * boffset, guint32 * bsize, guint32 * seg_binter)
-{
-  int ret = -1;
-
-  *boffset = -1;
-  *bsize = 0;
-  *seg_binter = -1;
-
-  /* all segment after buffer */
-  if (seg_offset >= offset + size) {
-    ret = 1;
-    goto done;
-  }
-
-  if (seg_offset < offset) {
-    /* segment start somewhere before buffer */
-
-    /* all segment before buffer */
-    if (seg_offset + seg_size <= offset) {
-      ret = -1;
-      goto done;
-    }
-
-    *seg_binter = offset - seg_offset;
-    *boffset = 0;
-
-    /* FIXME : optimize to >= size -> = size */
-    if (seg_offset + seg_size >= offset + size) {
-      /* segment cover all buffer */
-      *bsize = size;
-    } else {
-      /* segment goes from start of buffer to somewhere before end */
-      *bsize = seg_size - *seg_binter;
-    }
-
-    ret = 0;
-
-  } else {
-    /* segment start somewhere into buffer */
-
-    *boffset = seg_offset - offset;
-    *seg_binter = 0;
-
-    if (seg_offset + seg_size <= offset + size) {
-      /* all segment into buffer */
-      *bsize = seg_size;
-    } else {
-      *bsize = size - *boffset;
-    }
-
-    ret = 0;
-
-  }
-
-done:
-
-  return ret;
-
-}
-
-/*
- *  TRUE -> buffer striped or injeted
- *  FALSE -> buffer unmodified
- */
-
-static gboolean
-gst_metadata_parse_strip_push_buffer (GstMetadataParse * filter,
-    gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf)
-{
-  MetadataChunk *strip = filter->parse_data.strip_chunks.chunk;
-  MetadataChunk *inject = filter->parse_data.inject_chunks.chunk;
-  const gsize strip_len = filter->parse_data.strip_chunks.len;
-  const gsize inject_len = filter->parse_data.inject_chunks.len;
-  gboolean buffer_reallocated = FALSE;
-
-  guint32 size_buf_in = GST_BUFFER_SIZE (*buf);
-
-  gint64 *boffset_strip = NULL;
-  guint32 *bsize_strip = NULL;
-  guint32 *seg_binter_strip = NULL;
-
-  int i, j;
-  gboolean need_free_strip = FALSE;
-
-  guint32 striped_bytes = 0;
-  guint32 injected_bytes = 0;
-
-  guint32 prepend_size = prepend && *prepend ? GST_BUFFER_SIZE (*prepend) : 0;
-
-  if (inject_len) {
-
-    for (i = 0; i < inject_len; ++i) {
-      int res;
-
-      if (inject[i].offset_orig >= offset_orig) {
-        if (inject[i].offset_orig < offset_orig + size_buf_in) {
-          injected_bytes += inject[i].size;
-        } else {
-          /* segment is after size (segments are sorted) */
-          break;
-        }
-      }
-    }
-
-  }
-
-  /*
-   * strip segments
-   */
-
-  if (strip_len == 0)
-    goto inject;
-
-  if (G_UNLIKELY (strip_len > 16)) {
-    boffset_strip = g_new (gint64, strip_len);
-    bsize_strip = g_new (guint32, strip_len);
-    seg_binter_strip = g_new (guint32, strip_len);
-    need_free_strip = TRUE;
-  } else {
-    boffset_strip = g_alloca (sizeof (boffset_strip[0]) * strip_len);
-    bsize_strip = g_alloca (sizeof (bsize_strip[0]) * strip_len);
-    seg_binter_strip = g_alloca (sizeof (seg_binter_strip[0]) * strip_len);
-  }
-
-  memset (bsize_strip, 0x00, sizeof (bsize_strip[0]) * strip_len);
-
-  for (i = 0; i < strip_len; ++i) {
-    int res;
-
-    res = gst_metadata_parse_get_strip_seg (offset_orig, size_buf_in,
-        strip[i].offset_orig, strip[i].size, &boffset_strip[i], &bsize_strip[i],
-        &seg_binter_strip[i]);
-
-    /* segment is after size (segments are sorted) */
-    striped_bytes += bsize_strip[i];
-    if (res > 0) {
-      break;
-    }
-
-  }
-
-  if (striped_bytes) {
-
-    guint8 *data;
-
-    if (!buffer_reallocated) {
-      buffer_reallocated = TRUE;
-      if (injected_bytes + prepend_size > striped_bytes) {
-        GstBuffer *new_buf =
-            gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes +
-            prepend_size - striped_bytes);
-
-        memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf),
-            GST_BUFFER_SIZE (*buf));
-
-        gst_buffer_unref (*buf);
-        *buf = new_buf;
-
-      } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) {
-        GstBuffer *new_buf = gst_buffer_copy (*buf);
-
-        gst_buffer_unref (*buf);
-        *buf = new_buf;
-        GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
-        GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes;
-      }
-    }
-
-    data = GST_BUFFER_DATA (*buf);
-
-    striped_bytes = 0;
-    for (i = 0; i < strip_len; ++i) {
-      /* intersect */
-      if (bsize_strip[i]) {
-        memmove (data + boffset_strip[i] - striped_bytes,
-            data + boffset_strip[i] + bsize_strip[i] - striped_bytes,
-            size_buf_in - boffset_strip[i] - bsize_strip[i]);
-        striped_bytes += bsize_strip[i];
-      }
-    }
-    size_buf_in -= striped_bytes;
-
-  }
-
-inject:
-
-  /*
-   * inject segments
-   */
-
-  if (inject_len) {
-
-    guint8 *data;
-    guint32 striped_so_far;
-
-    if (!buffer_reallocated) {
-      buffer_reallocated = TRUE;
-      if (injected_bytes + prepend_size > striped_bytes) {
-        GstBuffer *new_buf =
-            gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes +
-            prepend_size - striped_bytes);
-
-        memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf),
-            GST_BUFFER_SIZE (*buf));
-
-        gst_buffer_unref (*buf);
-        *buf = new_buf;
-
-      } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) {
-        GstBuffer *new_buf = gst_buffer_copy (*buf);
-
-        gst_buffer_unref (*buf);
-        *buf = new_buf;
-        GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
-        GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes;
-      }
-    }
-
-    data = GST_BUFFER_DATA (*buf);
-
-    injected_bytes = 0;
-    striped_so_far = 0;
-    j = 0;
-    for (i = 0; i < inject_len; ++i) {
-      int res;
-
-      while (j < strip_len) {
-        if (strip[j].offset_orig < inject[i].offset_orig)
-          striped_so_far += bsize_strip[j++];
-        else
-          break;
-      }
-
-      if (inject[i].offset_orig >= offset_orig) {
-        if (inject[i].offset_orig <
-            offset_orig + size_buf_in + striped_bytes - injected_bytes) {
-          /* insert */
-          guint32 buf_off =
-              inject[i].offset_orig - offset_orig - striped_so_far +
-              injected_bytes;
-          memmove (data + buf_off + inject[i].size, data + buf_off,
-              size_buf_in - buf_off);
-          memcpy (data + buf_off, inject[i].data, inject[i].size);
-          injected_bytes += inject[i].size;
-          size_buf_in += inject[i].size;
-        } else {
-          /* segment is after size (segments are sorted) */
-          break;
-        }
-      }
-    }
-
-  }
-
-
-done:
-
-  if (prepend_size) {
-    if (injected_bytes == 0 && striped_bytes == 0) {
-      GstBuffer *new_buf =
-          gst_buffer_new_and_alloc (size_buf_in + prepend_size);
-
-      memcpy (GST_BUFFER_DATA (new_buf) + prepend_size, GST_BUFFER_DATA (*buf),
-          size_buf_in);
-
-      gst_buffer_unref (*buf);
-      *buf = new_buf;
-    } else {
-      memmove (GST_BUFFER_DATA (*buf) + prepend_size, GST_BUFFER_DATA (*buf),
-          size_buf_in);
-    }
-    memcpy (GST_BUFFER_DATA (*buf), GST_BUFFER_DATA (*prepend), prepend_size);
-    gst_buffer_unref (*prepend);
-    *prepend = NULL;
-  }
-
-  GST_BUFFER_SIZE (*buf) = size_buf_in + prepend_size;
-
-  if (need_free_strip) {
-    g_free (boffset_strip);
-    g_free (bsize_strip);
-    g_free (seg_binter_strip);
-  }
-
-  return injected_bytes || striped_bytes;
-
-}
-
-/*
- * pos - position in stream striped
- * orig_pos - position in original stream
- * return TRUE - position in original buffer
- *        FALSE - position in inserted chunk
- */
-static gboolean
-gst_metadata_parse_translate_pos_to_orig (GstMetadataParse * filter, gint64 pos,
-    gint64 * orig_pos, GstBuffer ** buf)
-{
-  int i;
-  MetadataChunk *strip = filter->parse_data.strip_chunks.chunk;
-  MetadataChunk *inject = filter->parse_data.inject_chunks.chunk;
-  const gsize strip_len = filter->parse_data.strip_chunks.len;
-  const gsize inject_len = filter->parse_data.inject_chunks.len;
-  gboolean ret = TRUE;
-  guint64 new_buf_size = 0;
-  guint64 injected_before = 0;
-
-  if (G_UNLIKELY (pos == -1)) {
-    *orig_pos = -1;
-    return TRUE;
-  } else if (G_UNLIKELY (pos >= filter->duration)) {
-    /* this should never happen */
-    *orig_pos = filter->duration_orig;
-    return TRUE;
-  }
-
-  /* calculate for injected */
-
-  /* just calculate size */
-  *orig_pos = pos;              /* save pos */
-  for (i = 0; i < inject_len; ++i) {
-    /* check if pos in inside chunk */
-    if (inject[i].offset <= pos) {
-      if (pos < inject[i].offset + inject[i].size) {
-        /* orig pos points after insert chunk */
-        new_buf_size += inject[i].size;
-        /* put pos after current chunk */
-        pos = inject[i].offset + inject[i].size;
-        ret = FALSE;
-      } else {
-        /* in case pos is not inside a injected chunk */
-        injected_before += inject[i].size;
-      }
-    } else {
-      break;
-    }
-  }
-
-  /* alloc buffer and calcute original pos */
-  if (buf && ret == FALSE) {
-    guint8 *data;
-
-    if (*buf)
-      gst_buffer_unref (*buf);
-    *buf = gst_buffer_new_and_alloc (new_buf_size);
-    data = GST_BUFFER_DATA (*buf);
-    pos = *orig_pos;            /* recover saved pos */
-    for (i = 0; i < inject_len; ++i) {
-      if (inject[i].offset > pos) {
-        break;
-      }
-      if (inject[i].offset <= pos && pos < inject[i].offset + inject[i].size) {
-        memcpy (data, inject[i].data, inject[i].size);
-        data += inject[i].size;
-        pos = inject[i].offset + inject[i].size;
-        /* out position after insert chunk orig */
-        *orig_pos = inject[i].offset_orig + inject[i].size;
-      }
-    }
-  }
-
-  if (ret == FALSE) {
-    /* if it inside a injected is already done */
-    goto done;
-  }
-
-  /* calculate for striped */
-
-  *orig_pos = pos - injected_before;
-  for (i = 0; i < strip_len; ++i) {
-    if (strip[i].offset_orig > pos) {
-      break;
-    }
-    *orig_pos += strip[i].size;
-  }
-
-done:
-
-  if (G_UNLIKELY (*orig_pos >= filter->duration_orig)) {
-    *orig_pos = filter->duration_orig - 1;
-  }
-
-  return ret;
-
-}
-
-static gboolean
-gst_metadata_parse_checkgetrange (GstPad * srcpad)
-{
-  GstMetadataParse *filter = NULL;
-
-  filter = GST_METADATA_PARSE (GST_PAD_PARENT (srcpad));
-
-  return gst_pad_check_pull_range (filter->sinkpad);
-}
-
-static GstFlowReturn
-gst_metadata_parse_get_range (GstPad * pad,
-    guint64 offset, guint size, GstBuffer ** buf)
-{
-  GstMetadataParse *filter = NULL;
-  GstFlowReturn ret = GST_FLOW_OK;
-  gint64 offset_orig = 0;
-  guint size_orig;
-  GstBuffer *prepend = NULL;
-  gboolean need_append = FALSE;
-
-  filter = GST_METADATA_PARSE (GST_PAD_PARENT (pad));
-
-  if (filter->state != MT_STATE_PARSED) {
-    ret = GST_FLOW_ERROR;
-    goto done;
-  }
-
-  if (offset + size > filter->duration) {
-    size = filter->duration - offset;
-  }
-
-  size_orig = size;
-
-  if (filter->need_send_tag) {
-    gst_metadata_parse_send_tags (filter);
-  }
-
-  gst_metadata_parse_translate_pos_to_orig (filter, offset, &offset_orig,
-      &prepend);
-
-  if (size > 1) {
-    gint64 pos;
-
-    pos = offset + size - 1;
-    gst_metadata_parse_translate_pos_to_orig (filter, pos, &pos, NULL);
-    size_orig = pos + 1 - offset_orig;
-  }
-
-  if (size_orig) {
-
-    ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf);
-
-    if (ret == GST_FLOW_OK && *buf) {
-      gst_metadata_parse_strip_push_buffer (filter, offset_orig, &prepend, buf);
-
-      if (GST_BUFFER_SIZE (*buf) < size) {
-        /* need append */
-        need_append = TRUE;
-      }
-
-    }
-  } else {
-    *buf = prepend;
-  }
-
-done:
-
-  if (need_append) {
-    /* FIXME: together with SEEK and
-     * gst_metadata_parse_translate_pos_to_orig
-     * this way if chunk is added in the end we are in trolble
-     * ...still not implemented 'cause it will not be the
-     * case for the time being
-     */
-  }
-
-  return ret;
-
-}
-
-static gboolean
-gst_metadata_parse_src_activate_pull (GstPad * pad, gboolean active)
-{
-  GstMetadataParse *filter = NULL;
-  gboolean ret;
-
-  filter = GST_METADATA_PARSE (gst_pad_get_parent (pad));
-
-  ret = gst_pad_activate_pull (filter->sinkpad, active);
-
-  if (ret && filter->state == MT_STATE_NULL) {
-    ret = gst_metadata_parse_pull_range_parse (filter);
-  }
-
-  gst_object_unref (filter);
-
-  return ret;
-}
-
-
-static GstStateChangeReturn
-gst_metadata_parse_change_state (GstElement * element,
-    GstStateChange transition)
-{
-  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
-  GstMetadataParse *filter = GST_METADATA_PARSE (element);
-
-  switch (transition) {
-    case GST_STATE_CHANGE_NULL_TO_READY:
-      gst_metadata_parse_init_members (filter);
-      filter->adapter_parsing = gst_adapter_new ();
-      metadata_init (&filter->parse_data, TRUE, filter->options);
-      break;
-    default:
-      break;
-  }
-
-  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-  if (ret == GST_STATE_CHANGE_FAILURE)
-    goto done;
-
-  switch (transition) {
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-      filter->offset = 0;
-      filter->offset_orig = 0;
-      if (filter->adapter_parsing) {
-        gst_adapter_clear (filter->adapter_parsing);
-      }
-      if (filter->adapter_holding) {
-        gst_adapter_clear (filter->adapter_holding);
-      }
-      if (filter->state != MT_STATE_PARSED) {
-        /* cleanup parser */
-        /* FIXME: could be improved a bit to avoid mem allocation */
-        metadata_dispose (&filter->parse_data);
-        metadata_init (&filter->parse_data, TRUE, filter->options);
-      }
-      break;
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      gst_metadata_parse_dispose_members (filter);
-      break;
-    default:
-      break;
-  }
-
-done:
-
-  return ret;
-}
-
-/*
- * element plugin init function
- */
-
-gboolean
-gst_metadata_parse_plugin_init (GstPlugin * plugin)
-{
-  GST_DEBUG_CATEGORY_INIT (gst_metadata_parse_debug, "metadataparse", 0,
-      "Metadata demuxer");
-
-  return gst_element_register (plugin, "metadataparse",
-      GST_RANK_PRIMARY + 1, GST_TYPE_METADATA_PARSE);
-}
diff --git a/ext/metadata/gstmetadataparse.h b/ext/metadata/gstmetadataparse.h
deleted file mode 100644 (file)
index fa1c9b7..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * GStreamer
- * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br>
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Alternatively, the contents of this file may be used under the
- * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
- * which case the following provisions apply instead of the ones
- * mentioned above:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_METADATA_PARSE_H__
-#define __GST_METADATA_PARSE_H__
-
-#include <gst/gst.h>
-
-#include "metadata.h"
-
-G_BEGIN_DECLS
-/* #defines don't like whitespacey bits */
-#define GST_TYPE_METADATA_PARSE \
-  (gst_metadata_parse_get_type())
-#define GST_METADATA_PARSE(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_METADATA_PARSE,GstMetadataParse))
-#define GST_METADATA_PARSE_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_METADATA_PARSE,GstMetadataParseClass))
-#define GST_IS_METADATA_PARSE(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_METADATA_PARSE))
-#define GST_IS_METADATA_PARSE_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_METADATA_PARSE))
-typedef struct _GstMetadataParse GstMetadataParse;
-typedef struct _GstMetadataParseClass GstMetadataParseClass;
-
-typedef enum _tag_MetadataState
-{
-  MT_STATE_NULL,                /* still need to check media type */
-  MT_STATE_PARSED
-} MetadataState;
-
-struct _GstMetadataParse
-{
-  GstElement element;
-
-  GstPad *sinkpad, *srcpad;
-
-  guint8 options;
-
-  gboolean need_send_tag;
-
-  MetaData parse_data;
-  GstAdapter *adapter_parsing;
-  GstAdapter *adapter_holding;
-  guint32 next_offset;
-  guint32 next_size;
-  ImageType img_type;
-
-  gint64 offset_orig;  /* offset in original stream */
-  gint64 duration_orig;     /* durarion of stream */
-  gint64 offset;       /* offset in current stream */
-  gint64 duration;     /* durarion of modified stream */
-
-  MetadataState state;
-
-  GstBuffer * prepend_buffer;
-  GstBuffer * append_buffer;
-
-  gboolean need_more_data;
-
-
-
-};
-
-struct _GstMetadataParseClass
-{
-  GstElementClass parent_class;
-};
-
-extern GType gst_metadata_parse_get_type (void);
-
-G_END_DECLS
-#endif /* __GST_METADATA_PARSE_H__ */
index 65ade6eaae37b1529c3f6f55a6a9d699aaf99846..5b745a7af05fd663cf51d623f1828e81bcaa21f1 100644 (file)
@@ -89,7 +89,6 @@ typedef struct _tag_MapIntStr
 {
   ExifTag exif;
   const gchar *str;
-  GType type;
 } MapIntStr;
 
 static void
@@ -99,21 +98,21 @@ static void exif_content_foreach_entry_func (ExifEntry * entry, void *);
 
 /* *INDENT-OFF* */
 static MapIntStr mappedTags[] = {
-  {EXIF_TAG_MAKE,               /*EXIF_FORMAT_ASCII,*/     GST_TAG_DEVICE_MAKE,              G_TYPE_STRING},
-  {EXIF_TAG_MODEL,              /*EXIF_FORMAT_ASCII,*/     GST_TAG_DEVICE_MODEL,             G_TYPE_STRING},
-  {EXIF_TAG_SOFTWARE,           /*EXIF_FORMAT_ASCII,*/     GST_TAG_CREATOR_TOOL,             G_TYPE_STRING},
-  {EXIF_TAG_X_RESOLUTION,       /*EXIF_FORMAT_RATIONAL,*/  GST_TAG_IMAGE_XRESOLUTION,        G_TYPE_FLOAT},   /* inches */
-  {EXIF_TAG_Y_RESOLUTION,       /*EXIF_FORMAT_RATIONAL,*/  GST_TAG_IMAGE_YRESOLUTION,        G_TYPE_FLOAT},   /* inches */
-  {EXIF_TAG_EXPOSURE_TIME,      /*EXIF_FORMAT_RATIONAL,*/  GST_TAG_CAPTURE_EXPOSURE_TIME,    G_TYPE_FLOAT},
-  {EXIF_TAG_FNUMBER,            /*EXIF_FORMAT_RATIONAL,*/  GST_TAG_CAPTURE_FNUMBER,          G_TYPE_FLOAT},
-  {EXIF_TAG_EXPOSURE_PROGRAM,   /*EXIF_FORMAT_SHORT,*/     GST_TAG_CAPTURE_EXPOSURE_PROGRAM, G_TYPE_UINT},
-  {EXIF_TAG_BRIGHTNESS_VALUE,   /*EXIF_FORMAT_SRATIONAL,*/ GST_TAG_CAPTURE_BRIGHTNESS,       G_TYPE_FLOAT},
-  {EXIF_TAG_WHITE_BALANCE,      /*EXIF_FORMAT_SHORT,*/     GST_TAG_CAPTURE_WHITE_BALANCE,    G_TYPE_UINT},
-  {EXIF_TAG_DIGITAL_ZOOM_RATIO, /*EXIF_FORMAT_RATIONAL,*/  GST_TAG_CAPTURE_DIGITAL_ZOOM,     G_TYPE_FLOAT},
-  {EXIF_TAG_GAIN_CONTROL,       /*EXIF_FORMAT_SHORT,*/     GST_TAG_CAPTURE_GAIN,             G_TYPE_UINT},
-  {EXIF_TAG_CONTRAST,           /*EXIF_FORMAT_SHORT,*/     GST_TAG_CAPTURE_CONTRAST,         G_TYPE_INT},
-  {EXIF_TAG_SATURATION,         /*EXIF_FORMAT_SHORT,*/     GST_TAG_CAPTURE_SATURATION,       G_TYPE_INT},
-  {0, NULL, G_TYPE_NONE}
+  {EXIF_TAG_MAKE,               /*ASCII,*/     GST_TAG_DEVICE_MAKE,              /*STRING*/},
+  {EXIF_TAG_MODEL,              /*ASCII,*/     GST_TAG_DEVICE_MODEL,             /*STRING*/},
+  {EXIF_TAG_SOFTWARE,           /*ASCII,*/     GST_TAG_CREATOR_TOOL,             /*STRING*/},
+  {EXIF_TAG_X_RESOLUTION,       /*RATIONAL,*/  GST_TAG_IMAGE_XRESOLUTION,        /*FRACTION*/},   /* inches */
+  {EXIF_TAG_Y_RESOLUTION,       /*RATIONAL,*/  GST_TAG_IMAGE_YRESOLUTION,        /*FRACTION*/},   /* inches */
+  {EXIF_TAG_EXPOSURE_TIME,      /*RATIONAL,*/  GST_TAG_CAPTURE_EXPOSURE_TIME,    /*FRACTION*/},
+  {EXIF_TAG_FNUMBER,            /*RATIONAL,*/  GST_TAG_CAPTURE_FNUMBER,          /*FRACTION*/},
+  {EXIF_TAG_EXPOSURE_PROGRAM,   /*SHORT,*/     GST_TAG_CAPTURE_EXPOSURE_PROGRAM, /*UINT*/},
+  {EXIF_TAG_BRIGHTNESS_VALUE,   /*SRATIONAL,*/ GST_TAG_CAPTURE_BRIGHTNESS,       /*FRACTION*/},
+  {EXIF_TAG_WHITE_BALANCE,      /*SHORT,*/     GST_TAG_CAPTURE_WHITE_BALANCE,    /*UINT*/},
+  {EXIF_TAG_DIGITAL_ZOOM_RATIO, /*RATIONAL,*/  GST_TAG_CAPTURE_DIGITAL_ZOOM,     /*FRACTION*/},
+  {EXIF_TAG_GAIN_CONTROL,       /*SHORT,*/     GST_TAG_CAPTURE_GAIN,             /*UINT*/},
+  {EXIF_TAG_CONTRAST,           /*SHORT,*/     GST_TAG_CAPTURE_CONTRAST,         /*INT*/},
+  {EXIF_TAG_SATURATION,         /*SHORT,*/     GST_TAG_CAPTURE_SATURATION,       /*INT*/},
+  {0, NULL}
 };
 /* *INDENT-ON* */
 
@@ -123,12 +122,13 @@ metadataparse_exif_get_tag_from_exif (ExifTag exif, GType * type)
   int i = 0;
 
   while (mappedTags[i].exif) {
-    if (exif == mappedTags[i].exif)
+    if (exif == mappedTags[i].exif) {
+      *type = gst_tag_get_type (mappedTags[i].str);
       break;
+    }
     ++i;
   }
 
-  *type = mappedTags[i].type;
   return mappedTags[i].str;
 
 }
@@ -139,12 +139,13 @@ metadataparse_exif_get_exif_from_tag (const gchar * tag, GType * type)
   int i = 0;
 
   while (mappedTags[i].exif) {
-    if (0 == strcmp (mappedTags[i].str, tag))
+    if (0 == strcmp (mappedTags[i].str, tag)) {
+      *type = gst_tag_get_type (tag);
       break;
+    }
     ++i;
   }
 
-  *type = mappedTags[i].type;
   return mappedTags[i].exif;
 
 }
@@ -257,61 +258,59 @@ exif_content_foreach_entry_func (ExifEntry * entry, void *user_data)
     goto done;
   }
 
-  if (tag) {
-    /* FIXME: create a generic function for this */
-    /* could also be used with entry->format */
-    switch (type) {
-      case G_TYPE_STRING:
-        gst_tag_list_add (meudata->taglist, meudata->mode, tag,
-            exif_entry_get_value (entry, buf, sizeof (buf)), NULL);
+  if (!tag)
+    goto done;
+
+  if (type == GST_TYPE_FRACTION) {
+    gint numerator = 0;
+    gint denominator = 1;
+
+    switch (entry->format) {
+      case EXIF_FORMAT_SRATIONAL:
+      {
+        ExifSRational v_srat;
+
+        v_srat = exif_get_srational (entry->data, byte_order);
+        if (v_srat.denominator) {
+          numerator = (gint) v_srat.numerator;
+          denominator = (gint) v_srat.denominator;
+        }
+      }
         break;
-      case G_TYPE_FLOAT:
+      case EXIF_FORMAT_RATIONAL:
       {
-        gfloat f_value;
+        ExifRational v_rat;
 
-        switch (entry->format) {
-          case EXIF_FORMAT_SRATIONAL:
-          {
-            ExifSRational v_srat;
-
-            v_srat = exif_get_srational (entry->data, byte_order);
-            if (v_srat.denominator == 0)
-              f_value = 0.0f;
-            else
-              f_value = (float) v_srat.numerator / (float) v_srat.denominator;
-            if (v_srat.numerator == 0xFFFFFFFF) {
-              if (entry->tag == EXIF_TAG_BRIGHTNESS_VALUE) {
-                f_value = 100.0f;
-              }
-            }
-          }
-            break;
-          case EXIF_FORMAT_RATIONAL:
-          {
-            ExifRational v_rat;
-
-            v_rat = exif_get_rational (entry->data, byte_order);
-            if (v_rat.denominator == 0)
-              f_value = 0.0f;
-            else
-              f_value = (float) v_rat.numerator / (float) v_rat.denominator;
-            if (meudata->resolution_unit == 3) {
-              /* converts from cm to inches */
-              if (entry->tag == EXIF_TAG_X_RESOLUTION
-                  || entry->tag == EXIF_TAG_Y_RESOLUTION) {
-                f_value *= 0.4f;
-              }
-            }
+        v_rat = exif_get_rational (entry->data, byte_order);
+        if (v_rat.denominator) {
+          numerator = (gint) v_rat.numerator;
+          denominator = (gint) v_rat.denominator;
+        }
+        if (meudata->resolution_unit == 3) {
+          /* converts from cm to inches */
+          if (entry->tag == EXIF_TAG_X_RESOLUTION
+              || entry->tag == EXIF_TAG_Y_RESOLUTION) {
+            numerator *= 2;
+            denominator *= 5;
           }
-            break;
-          default:
-            GST_ERROR ("Unexpected Tag Type");
-            goto done;
-            break;
         }
-        gst_tag_list_add (meudata->taglist, meudata->mode, tag, f_value, NULL);
       }
         break;
+      default:
+        GST_ERROR ("Unexpected Tag Type");
+        goto done;
+        break;
+    }
+    gst_tag_list_add (meudata->taglist, meudata->mode, tag, numerator,
+        denominator, NULL);
+
+  } else {
+
+    switch (type) {
+      case G_TYPE_STRING:
+        gst_tag_list_add (meudata->taglist, meudata->mode, tag,
+            exif_entry_get_value (entry, buf, sizeof (buf)), NULL);
+        break;
       case G_TYPE_INT:
         /* fall through */
       case G_TYPE_UINT:
@@ -350,8 +349,10 @@ exif_content_foreach_entry_func (ExifEntry * entry, void *user_data)
       default:
         break;
     }
+
   }
 
+
 done:
 
   GST_LOG ("\n    Entry %p: %s (%s)\n"
@@ -465,90 +466,82 @@ metadataexif_for_each_tag_in_list (const GstTagList * list, const gchar * tag,
     exif_entry_initialize (entry, exif_tag);
   }
 
-  switch (type) {
-    case G_TYPE_STRING:
-    {
-      gchar *value = NULL;
+  if (type == GST_TYPE_FRACTION) {
+    const GValue *gvalue = gst_tag_list_get_value_index (list, tag, 0);
+    gint numerator = gst_value_get_fraction_numerator (gvalue);
+    gint denominator = gst_value_get_fraction_denominator (gvalue);
 
-      if (gst_tag_list_get_string (list, tag, &value)) {
-        entry->components = strlen (value) + 1;
-        entry->size = exif_format_get_size (entry->format) * entry->components;
-        entry->data = value;
+    switch (entry->format) {
+      case EXIF_FORMAT_SRATIONAL:
+      {
+        ExifSRational sr = { numerator, denominator };
+
+        exif_set_srational (entry->data, byte_order, sr);
       }
-    }
-      break;
-    case G_TYPE_FLOAT:
-    {
-      gfloat value;
+        break;
+      case EXIF_FORMAT_RATIONAL:
+      {
+        ExifRational r = { numerator, denominator };
 
-      gst_tag_list_get_float (list, tag, &value);
+        exif_set_rational (entry->data, byte_order, r);
+        if (entry->tag == EXIF_TAG_X_RESOLUTION ||
+            entry->tag == EXIF_TAG_Y_RESOLUTION) {
+          ExifEntry *unit_entry = NULL;
 
-      switch (entry->format) {
-        case EXIF_FORMAT_SRATIONAL:
-        {
-          ExifSRational sr;
+          if ((unit_entry = exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT))) {
+            ExifShort vsh = exif_get_short (unit_entry->data, byte_order);
 
-          sr = float_to_srational (value);
-          if (entry->tag == EXIF_TAG_BRIGHTNESS_VALUE) {
-            if (value == 100.0f) {
-              sr.numerator = 0xFFFFFFFF;
-              sr.denominator = 1;
-            }
+            if (vsh != 2)       /* inches */
+              exif_set_short (unit_entry->data, byte_order, 2);
           }
-
-          exif_set_srational (entry->data, byte_order, sr);
         }
-          break;
-        case EXIF_FORMAT_RATIONAL:
-        {
-          ExifRational r;
-
-          r = float_to_rational (value);
-          exif_set_rational (entry->data, byte_order, r);
-          if (entry->tag == EXIF_TAG_X_RESOLUTION ||
-              entry->tag == EXIF_TAG_Y_RESOLUTION) {
-            ExifEntry *unit_entry = NULL;
-
-            if ((unit_entry =
-                    exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT))) {
-              ExifShort vsh = exif_get_short (unit_entry->data, byte_order);
-
-              if (vsh != 2)     /* inches */
-                exif_set_short (unit_entry->data, byte_order, 2);
-            }
-          }
-        }
-          break;
-        default:
-          break;
       }
+        break;
+      default:
+        break;
     }
-      break;
-    case G_TYPE_UINT:
-    case G_TYPE_INT:
-    {
-      gint value;
-      ExifShort v_short;
-
-      if (G_TYPE_UINT == type) {
-        gst_tag_list_get_uint (list, tag, &value);
-      } else {
-        gst_tag_list_get_int (list, tag, &value);
+  } else {
+
+    switch (type) {
+      case G_TYPE_STRING:
+      {
+        gchar *value = NULL;
+
+        if (gst_tag_list_get_string (list, tag, &value)) {
+          entry->components = strlen (value) + 1;
+          entry->size =
+              exif_format_get_size (entry->format) * entry->components;
+          entry->data = value;
+        }
       }
-      if (entry->tag == EXIF_TAG_CONTRAST || entry->tag == EXIF_TAG_SATURATION) {
-        if (value < -33)
-          value = 1;            /* low */
-        else if (value < 34)
-          value = 0;            /* normal */
-        else
-          value = 2;            /* high */
+        break;
+      case G_TYPE_UINT:
+      case G_TYPE_INT:
+      {
+        gint value;
+        ExifShort v_short;
+
+        if (G_TYPE_UINT == type) {
+          gst_tag_list_get_uint (list, tag, &value);
+        } else {
+          gst_tag_list_get_int (list, tag, &value);
+        }
+        if (entry->tag == EXIF_TAG_CONTRAST
+            || entry->tag == EXIF_TAG_SATURATION) {
+          if (value < -33)
+            value = 1;          /* low */
+          else if (value < 34)
+            value = 0;          /* normal */
+          else
+            value = 2;          /* high */
+        }
+        v_short = value;
+        exif_set_short (entry->data, byte_order, v_short);
       }
-      v_short = value;
-      exif_set_short (entry->data, byte_order, v_short);
+        break;
+      default:
+        break;
     }
-      break;
-    default:
-      break;
   }
 
 done:
index 00f3956b388e7f2375f41ff832900c9ba8407fcd..6250c25671cb0c300e41ef1f2ad74ebb0dc3e8c1 100644 (file)
 
 static void
 metadata_tags_exif_register (void)
-{
-  gst_tag_register (GST_TAG_EXIF, GST_TAG_FLAG_META,
-      GST_TYPE_BUFFER, GST_TAG_EXIF, "exif metadata chunk", NULL);
-}
-
-/*
- * IPTC tags
- */
-
-static void
-metadata_tags_iptc_register (void)
-{
-  gst_tag_register (GST_TAG_IPTC, GST_TAG_FLAG_META,
-      GST_TYPE_BUFFER, GST_TAG_IPTC, "iptc metadata chunk", NULL);
-}
-
-/*
- * XMP tags
- */
-
-static void
-metadata_tags_xmp_register (void)
-{
-  gst_tag_register (GST_TAG_XMP, GST_TAG_FLAG_META,
-      GST_TYPE_BUFFER, GST_TAG_XMP, "xmp metadata chunk", NULL);
-}
-
-/*
- *
- */
-
-void
-metadata_tags_register (void)
 {
   /* devices tags */
 
@@ -101,20 +68,21 @@ metadata_tags_register (void)
 
   /* image tags */
 
-  gst_tag_register (GST_TAG_IMAGE_XRESOLUTION, GST_TAG_FLAG_META, G_TYPE_FLOAT,
-      GST_TAG_IMAGE_XRESOLUTION, "Horizontal resolution in pixels per inch",
-      NULL);
-  gst_tag_register (GST_TAG_IMAGE_YRESOLUTION, GST_TAG_FLAG_META, G_TYPE_FLOAT,
-      GST_TAG_IMAGE_YRESOLUTION, "Vertical resolution in pixels per inch",
-      NULL);
+  gst_tag_register (GST_TAG_IMAGE_XRESOLUTION, GST_TAG_FLAG_META,
+      GST_TYPE_FRACTION, GST_TAG_IMAGE_XRESOLUTION,
+      "Horizontal resolution in pixels per inch", NULL);
+  gst_tag_register (GST_TAG_IMAGE_YRESOLUTION, GST_TAG_FLAG_META,
+      GST_TYPE_FRACTION, GST_TAG_IMAGE_YRESOLUTION,
+      "Vertical resolution in pixels per inch", NULL);
 
   /* capture tags */
 
   gst_tag_register (GST_TAG_CAPTURE_EXPOSURE_TIME, GST_TAG_FLAG_META,
-      G_TYPE_FLOAT, GST_TAG_CAPTURE_EXPOSURE_TIME, "Exposure time in seconds",
+      GST_TYPE_FRACTION, GST_TAG_CAPTURE_EXPOSURE_TIME,
+      "Exposure time in seconds", NULL);
+  gst_tag_register (GST_TAG_CAPTURE_FNUMBER, GST_TAG_FLAG_META,
+      GST_TYPE_FRACTION, GST_TAG_CAPTURE_FNUMBER, "F number (focal ratio)",
       NULL);
-  gst_tag_register (GST_TAG_CAPTURE_FNUMBER, GST_TAG_FLAG_META, G_TYPE_FLOAT,
-      GST_TAG_CAPTURE_FNUMBER, "F number (focal ratio)", NULL);
   /**
     0 - not defined
     1- Manual
@@ -137,11 +105,11 @@ metadata_tags_register (void)
       "Class of program used for exposure", NULL);
   /** The unit is the APEX value.
       Ordinarily it is given in the range of -99.99 to 99.99.
-      100.0 mean unknown      
+      if numerator is 0xFFFFFFFF means unknown      
   */
-  gst_tag_register (GST_TAG_CAPTURE_BRIGHTNESS, GST_TAG_FLAG_META, G_TYPE_FLOAT,
-      GST_TAG_CAPTURE_BRIGHTNESS, "Brightness (APEX from -99.99 to 99.99)",
-      NULL);
+  gst_tag_register (GST_TAG_CAPTURE_BRIGHTNESS, GST_TAG_FLAG_META,
+      GST_TYPE_FRACTION, GST_TAG_CAPTURE_BRIGHTNESS,
+      "Brightness (APEX from -99.99 to 99.99)", NULL);
   /**
      0- Auto
      1- Off
@@ -160,7 +128,8 @@ metadata_tags_register (void)
   /** if Zero ZOOM not used
    */
   gst_tag_register (GST_TAG_CAPTURE_DIGITAL_ZOOM, GST_TAG_FLAG_META,
-      G_TYPE_FLOAT, GST_TAG_CAPTURE_DIGITAL_ZOOM, "Digital zoom ratio", NULL);
+      GST_TYPE_FRACTION, GST_TAG_CAPTURE_DIGITAL_ZOOM, "Digital zoom ratio",
+      NULL);
   /**
      0- None
      1- Low gain up
@@ -189,6 +158,49 @@ metadata_tags_register (void)
   gst_tag_register (GST_TAG_CAPTURE_SATURATION, GST_TAG_FLAG_META, G_TYPE_INT,
       GST_TAG_CAPTURE_SATURATION, "", NULL);
 
+}
+
+/*
+ * IPTC tags
+ */
+
+static void
+metadata_tags_iptc_register (void)
+{
+
+}
+
+/*
+ * XMP tags
+ */
+
+static void
+metadata_tags_xmp_register (void)
+{
+
+}
+
+/*
+ *
+ */
+
+void
+metadata_tags_register (void)
+{
+
+  /* whole chunk tags */
+
+  gst_tag_register (GST_TAG_EXIF, GST_TAG_FLAG_META,
+      GST_TYPE_BUFFER, GST_TAG_EXIF, "exif metadata chunk", NULL);
+
+  gst_tag_register (GST_TAG_IPTC, GST_TAG_FLAG_META,
+      GST_TYPE_BUFFER, GST_TAG_IPTC, "iptc metadata chunk", NULL);
+
+  gst_tag_register (GST_TAG_XMP, GST_TAG_FLAG_META,
+      GST_TYPE_BUFFER, GST_TAG_XMP, "xmp metadata chunk", NULL);
+
+  /* tags related to some metadata */
+
   metadata_tags_exif_register ();
   metadata_tags_iptc_register ();
   metadata_tags_xmp_register ();
index 4228b2270a4aca80e2ee84dafe4d32f63c6eeb18..e3b1cee573256a0ac676543b25fb0158adc0ecf0 100644 (file)
@@ -160,33 +160,43 @@ change_tag_list (GstTagList ** list, const gchar * tag, const gchar * value)
 
   type = gst_tag_get_type (tag);
 
-  switch (type) {
-    case G_TYPE_STRING:
-      gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
-      ret = TRUE;
-      break;
-    case G_TYPE_FLOAT:
-    {
-      gfloat fv = (gfloat) g_strtod (value, NULL);
+  if (type == GST_TYPE_FRACTION) {
+    /* FIXME: Ask GStreamer guys to add GST_FRACTION support to TAGS */
+    /* Even better: ask GLib guys to add this type */
+    gint n, d;
 
-      gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, fv, NULL);
-      ret = TRUE;
-    }
-      break;
-    case G_TYPE_INT:
-      /* fall through */
-    case G_TYPE_UINT:
-    {
-      gint iv = atoi (value);
-
-      gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, iv, NULL);
-      ret = TRUE;
+    sscanf (value, "%d/%d", &n, &d);
+    gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, n, d, NULL);
+    ret = TRUE;
+  } else {
+    switch (type) {
+      case G_TYPE_STRING:
+        gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
+        ret = TRUE;
+        break;
+      case G_TYPE_FLOAT:
+      {
+        gfloat fv = (gfloat) g_strtod (value, NULL);
+
+        gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, fv, NULL);
+        ret = TRUE;
+      }
+        break;
+      case G_TYPE_INT:
+        /* fall through */
+      case G_TYPE_UINT:
+      {
+        gint iv = atoi (value);
+
+        gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, iv, NULL);
+        ret = TRUE;
+      }
+        break;
+      default:
+        fprintf (stderr, "This app still doesn't handle type (%s)(%ld)\n",
+            g_type_name (type), type);
+        break;
     }
-      break;
-    default:
-      fprintf (stderr, "This app still doesn't handle type (%s)(%ld)\n",
-          g_type_name (type), type);
-      break;
   }
 
 done:
@@ -700,7 +710,7 @@ me_gst_setup_encode_pipeline (const gchar * src_file, const gchar * dest_file,
 
   /* create elements */
   gst_source = gst_element_factory_make ("filesrc", NULL);
-  gst_metadata_demux = gst_element_factory_make ("metadataparse", NULL);
+  gst_metadata_demux = gst_element_factory_make ("metadatademux", NULL);
   gst_metadata_mux = gst_element_factory_make ("metadatamux", NULL);
   gst_file_sink = gst_element_factory_make ("filesink", NULL);
 
@@ -767,7 +777,7 @@ me_gst_setup_view_pipeline (const gchar * filename, GdkWindow * window)
 
   /* create elements */
   gst_source = gst_element_factory_make ("filesrc", NULL);
-  gst_metadata_demux = gst_element_factory_make ("metadataparse", NULL);
+  gst_metadata_demux = gst_element_factory_make ("metadatademux", NULL);
   /* let's do a dummy stuff to avoid decodebin */
   if (is_png (filename))
     gst_image_dec = gst_element_factory_make ("pngdec", NULL);