Add documentation. Fix test app compilation. Fix pull mode.
authorEdgard Lima <edgard.lima@indt.org.br>
Wed, 30 Jan 2008 12:56:51 +0000 (12:56 +0000)
committerEdgard Lima <edgard.lima@indt.org.br>
Wed, 30 Jan 2008 12:56:51 +0000 (12:56 +0000)
Original commit message from CVS:
Add documentation. Fix test app compilation. Fix pull mode.

12 files changed:
ChangeLog
ext/Makefile.am
ext/metadata/TODO
ext/metadata/gstbasemetadata.c
ext/metadata/gstbasemetadata.h
ext/metadata/metadatamuxjpeg.c
ext/metadata/metadatamuxjpeg.h
ext/metadata/metadatamuxpng.c
ext/metadata/metadatamuxpng.h
ext/metadata/metadataparsejpeg.c
ext/metadata/metadataparsepng.c
tests/icles/Makefile.am

index 6dc80ba..d527bfb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2008-01-30  Edgard Lima  <edgard.lima@indt.org.br>
+
+       * ext/Makefile.am:
+       * ext/metadata/TODO:
+       * ext/metadata/gstbasemetadata.c:
+       * ext/metadata/gstbasemetadata.h:
+       * ext/metadata/metadatamuxjpeg.c:
+       * ext/metadata/metadatamuxjpeg.h:
+       * ext/metadata/metadatamuxpng.c:
+       * ext/metadata/metadatamuxpng.h:
+       * ext/metadata/metadataparsejpeg.c:
+       * ext/metadata/metadataparsepng.c:
+       * tests/icles/Makefile.am:
+         Add documentation. Fix test app compilation. Fix pull mode.
+
 2008-01-29  Wim Taymans  <wim.taymans@collabora.co.uk>
 
        Patch by: Thijs Vermeir  <thijsvermeir at gmail dot com>
index db2fe1b..0bf562e 100644 (file)
@@ -76,12 +76,6 @@ else
 DTS_DIR=
 endif
 
-if USE_METADATA
-METADATA_DIR=metadata
-else
-METADATA_DIR=
-endif
-
 if USE_FAAC
 FAAC_DIR=faac
 else
@@ -160,6 +154,12 @@ else
 MPEG2ENC_DIR=
 endif
 
+if USE_METADATA
+METADATA_DIR=metadata
+else
+METADATA_DIR=
+endif
+
 # if USE_MPLEX
 # MPLEX_DIR=mplex
 # else
@@ -313,6 +313,7 @@ SUBDIRS=\
        $(LIBFAME_DIR) \
        $(LIBMMS_DIR) \
        $(MPEG2ENC_DIR) \
+       $(METADATA_DIR) \
        $(MPLEX_DIR) \
        $(MUSEPACK_DIR) \
        $(MUSICBRAINZ_DIR) \
@@ -342,7 +343,6 @@ DIST_SUBDIRS = \
        cdaudio \
        dc1394 \
        directfb \
-       metadata \
        faac \
        faad \
        gio \
@@ -353,6 +353,7 @@ DIST_SUBDIRS = \
        libmms \
        dts \
        divx \
+       metadata \
        mpeg2enc \
        musepack \
        musicbrainz \
index 5aa1516..aa7169f 100644 (file)
@@ -26,12 +26,4 @@ OPEN ISSUES:
 
 KNOWN BUGS
 
-1- gst-launch-0.10 filesrc location=BlueSquare.png ! metadatademux ! metadatamux ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
-
-the following pipelines work fine:
-
-gst-launch-0.10 filesrc location=BlueSquare.png ! metadatamux   ! metadatademux       ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
-gst-launch-0.10 filesrc location=BlueSquare.png ! metadatademux ! metadatamux ! queue ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
-gst-launch-0.10 filesrc location=BlueSquare.png !               ! metadatamux         ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
-gst-launch-0.10 filesrc location=BlueSquare.png ! metadatademux !                     ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
 
index 6d82660..92a13fa 100644 (file)
@@ -159,7 +159,8 @@ gst_base_metadata_parse (GstBaseMetadata * filter, const guint8 * buf,
 
 static gboolean
 gst_base_metadata_strip_push_buffer (GstBaseMetadata * base,
-    gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf);
+    const gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf,
+    gboolean inject_begin);
 
 static int
 gst_base_metadata_buf_get_intersection_seg (const gint64 offset, guint32 size,
@@ -168,7 +169,7 @@ gst_base_metadata_buf_get_intersection_seg (const gint64 offset, guint32 size,
 
 static gboolean
 gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
-    gint64 pos, gint64 * orig_pos, GstBuffer ** buf);
+    gint64 pos, gint64 * orig_pos, GstBuffer ** buf, guint32 max_size);
 
 static gboolean gst_base_metadata_calculate_offsets (GstBaseMetadata * base);
 
@@ -639,6 +640,7 @@ done:
  * beginning og @buf
  * @buf: a pointer to a buffer that will be modified (data striped/injected or
  * prepended)
+ * @inject_begin: is TRUE can inject a chunk start exactly in @offset_orig
  *
  * Strip bytes from @buf that are part of some chunk that will be striped. Add
  * a whole injected chunk if some inject chunk starts into the buffer. Prepend
@@ -658,7 +660,8 @@ done:
 
 static gboolean
 gst_base_metadata_strip_push_buffer (GstBaseMetadata * base,
-    gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf)
+    const gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf,
+    gboolean inject_begin)
 {
   MetadataChunk *strip = META_DATA_STRIP_CHUNKS (base->metadata).chunk;
   MetadataChunk *inject = META_DATA_INJECT_CHUNKS (base->metadata).chunk;
@@ -692,11 +695,13 @@ gst_base_metadata_strip_push_buffer (GstBaseMetadata * base,
       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;
+        if (G_LIKELY (inject_begin || 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;
+          }
         }
       }
     }
@@ -846,20 +851,22 @@ inject:
          original buffer */
 
       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;
+        if (G_LIKELY (inject_begin || 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;
+          }
         }
       }
     }
@@ -988,6 +995,7 @@ done:
  * @orig_pos: position in original stream
  * @buf: if not NULL, will have data that starts at some point into a injected
  * chunk
+ * @max_size: the maximum size to allocate to @buf. pass 0 if don't care
  *
  * Given a position in output stream (@pos), returns the position in original 
  * stream (@orig_pos) that contains the same data. If @pos is into a injected
@@ -1006,7 +1014,7 @@ done:
 
 static gboolean
 gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
-    gint64 pos, gint64 * orig_pos, GstBuffer ** buf)
+    gint64 pos, gint64 * orig_pos, GstBuffer ** buf, guint32 max_size)
 {
   MetadataChunk *strip = META_DATA_STRIP_CHUNKS (base->metadata).chunk;
   MetadataChunk *inject = META_DATA_INJECT_CHUNKS (base->metadata).chunk;
@@ -1014,9 +1022,11 @@ gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
   const gsize inject_len = META_DATA_INJECT_CHUNKS (base->metadata).len;
   const gint64 duration_orig = base->duration_orig;
   const gint64 duration = base->duration;
+  gboolean ret = TRUE;
+  const gint64 saved_pos = pos;
 
   int i;
-  gboolean ret = TRUE;
+
   guint64 new_buf_size = 0;
   guint64 injected_before = 0;
 
@@ -1032,56 +1042,67 @@ gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
   /* 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) {
       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;
+        /* pos is inside the chunk */
+        const guint32 offset_in_chunk = pos - inject[i].offset;
+
         ret = FALSE;
+        pos = inject[i].offset + inject[i].size;        /* put pos just after chunk */
+        new_buf_size += inject[i].size - offset_in_chunk;
+        /* we still continue, 'cause the next chunk could be just after this */
       } else {
         /* in case pos is not inside a injected chunk */
         injected_before += inject[i].size;
       }
     } else {
+      /* pos is before the chunk */
       break;
     }
   }
 
   /* alloc buffer and calcute original pos */
-  if (buf && ret == FALSE) {
-    guint8 *data;
+  if (ret == FALSE) {
 
-    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;
+    *orig_pos = pos;
+
+    if (buf) {
+      guint8 *data;
+
+      if (max_size > 0)
+        if (new_buf_size > max_size)
+          new_buf_size = max_size;
+
+      if (*buf)
+        gst_buffer_unref (*buf);
+      *buf = gst_buffer_new_and_alloc (new_buf_size);
+      data = GST_BUFFER_DATA (*buf);
+      pos = saved_pos;
+      for (i = 0; i < inject_len && new_buf_size > 0; ++i) {
+        if (inject[i].offset > pos) {
+          break;
+        }
+        if (pos < inject[i].offset + inject[i].size) {
+          const guint32 offset = pos - inject[i].offset;
+          guint32 size = inject[i].size - offset;
+
+          if (size > new_buf_size)
+            size = new_buf_size;
+          memcpy (data, inject[i].data + offset, size);
+          data += size;
+          pos = inject[i].offset + inject[i].size;
+          new_buf_size -= size;
+        }
       }
     }
-  }
 
-  if (ret == FALSE) {
-    /* if it inside a injected is already done */
     goto done;
   }
 
   /* calculate for striped */
 
-  *orig_pos = pos - injected_before;
+  *orig_pos = saved_pos - injected_before;
   for (i = 0; i < strip_len; ++i) {
     if (strip[i].offset_orig > pos) {
       break;
@@ -1479,7 +1500,7 @@ gst_base_metadata_src_event (GstPad * pad, GstEvent * event)
          striped/injected buffer in next 'chain' calling */
       filter->offset = start;
       gst_base_metadata_translate_pos_to_orig (filter, start, &start,
-          &filter->prepend_buffer);
+          &filter->prepend_buffer, 0);
       filter->offset_orig = start;
 
       if (stop_type == GST_SEEK_TYPE_CUR)
@@ -1491,7 +1512,7 @@ gst_base_metadata_src_event (GstPad * pad, GstEvent * event)
       }
       stop_type == GST_SEEK_TYPE_SET;
 
-      gst_base_metadata_translate_pos_to_orig (filter, stop, &stop, NULL);
+      gst_base_metadata_translate_pos_to_orig (filter, stop, &stop, NULL, 0);
 
       gst_event_unref (event);
       event = gst_event_new_seek (rate, format, flags,
@@ -1569,6 +1590,7 @@ gst_base_metadata_get_range (GstPad * pad,
   guint size_orig;
   GstBuffer *prepend = NULL;
   gboolean need_append = FALSE;
+  gboolean into_inject;
 
   filter = GST_BASE_METADATA (GST_PAD_PARENT (pad));
 
@@ -1583,34 +1605,45 @@ gst_base_metadata_get_range (GstPad * pad,
 
   size_orig = size;
 
-  gst_base_metadata_translate_pos_to_orig (filter, offset,
-      &offset_orig, &prepend);
+  into_inject = !gst_base_metadata_translate_pos_to_orig (filter, offset,
+      &offset_orig, &prepend, size);
+
+  if (into_inject) {
+    size_orig = GST_BUFFER_SIZE (prepend) < size_orig ?
+        size_orig - GST_BUFFER_SIZE (prepend) : 0;
+  }
+
+  if (size_orig == 0) {
+    /* enough data in prepend */
+    *buf = prepend;
+    goto done;
+  }
 
-  if (size > 1) {
+  if (size_orig > 1) {
     gint64 pos;
 
     pos = offset + size - 1;
-    gst_base_metadata_translate_pos_to_orig (filter, pos, &pos, NULL);
+    into_inject = gst_base_metadata_translate_pos_to_orig (filter, pos, &pos,
+        NULL, 0);
     size_orig = pos + 1 - offset_orig;
   }
 
-  if (size_orig) {
-
-    ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf);
+  ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf);
 
-    if (ret == GST_FLOW_OK && *buf) {
-      gst_base_metadata_strip_push_buffer (filter, offset_orig, &prepend, buf);
-
-      if (GST_BUFFER_SIZE (*buf) < size) {
-        /* need append */
-        need_append = TRUE;
-      }
+  if (ret == GST_FLOW_OK && *buf) {
+    gst_base_metadata_strip_push_buffer (filter, offset_orig, &prepend, buf,
+        FALSE);
 
+    if (GST_BUFFER_SIZE (*buf) < size) {
+      /* need append */
+      need_append = TRUE;
+    } else {
+      /* hide extra bytes */
+      GST_BUFFER_SIZE (*buf) = size;
     }
-  } else {
-    *buf = prepend;
   }
 
+
 done:
 
   if (need_append) {
@@ -1715,7 +1748,7 @@ gst_base_metadata_chain (GstPad * pad, GstBuffer * buf)
     buf_size = GST_BUFFER_SIZE (buf);
 
     gst_base_metadata_strip_push_buffer (filter, filter->offset_orig,
-        &filter->prepend_buffer, &buf);
+        &filter->prepend_buffer, &buf, TRUE);
 
     if (buf) {                  /* may be all buffer has been striped */
       gst_buffer_set_caps (buf, GST_PAD_CAPS (filter->srcpad));
@@ -1848,6 +1881,7 @@ gst_base_metadata_src_query (GstPad * pad, GstQuery * query)
         gst_query_set_position (query, GST_FORMAT_BYTES, filter->offset);
         ret = TRUE;
       }
+
       break;
     case GST_QUERY_DURATION:
 
@@ -1864,6 +1898,7 @@ gst_base_metadata_src_query (GstPad * pad, GstQuery * query)
           ret = TRUE;
         }
       }
+
       break;
     case GST_QUERY_FORMATS:
       gst_query_set_formats (query, 1, GST_FORMAT_BYTES);
index 9a3c08c..427496c 100644 (file)
@@ -73,27 +73,57 @@ typedef enum _tag_BaseMetadataType {
 } BaseMetadataType;
 
 
-/**
+/*
  * GST_BASE_METADATA_SRC_PAD:
  * @obj: base metadata instance
  *
  * Gives the pointer to the #GstPad object of the element.
  */
-#define GST_BASE_METADATA_SRC_PAD(obj)      (GST_BASE_METADATA_CAST (obj)->srcpad)
+#define GST_BASE_METADATA_SRC_PAD(obj) (GST_BASE_METADATA_CAST (obj)->srcpad)
 
-/**
+/*
  * GST_BASE_METADATA_SINK_PAD:
  * @obj: base metadata instance
  *
  * Gives the pointer to the #GstPad object of the element.
  */
-#define GST_BASE_METADATA_SINK_PAD(obj)     (GST_BASE_METADATA_CAST (obj)->sinkpad)
+#define GST_BASE_METADATA_SINK_PAD(obj) (GST_BASE_METADATA_CAST (obj)->sinkpad)
+
+/*
+ * GST_BASE_METADATA_EXIF_ADAPTER
+ * @obj: base metadata instance
+ *
+ * Gives the pointer to the EXIF #GstAdapter of the element.
+ */
+#define GST_BASE_METADATA_EXIF_ADAPTER(obj) \
+    (GST_BASE_METADATA_CAST (obj)->metadata->exif_adapter)
+
+/*
+ * GST_BASE_METADATA_IPTC_ADAPTER
+ * @obj: base metadata instance
+ *
+ * Gives the pointer to the IPTC #GstAdapter of the element.
+ */
+#define GST_BASE_METADATA_IPTC_ADAPTER(obj) \
+    (GST_BASE_METADATA_CAST (obj)->metadata->iptc_adapter)
 
-#define GST_BASE_METADATA_EXIF_ADAPTER(obj) (GST_BASE_METADATA_CAST (obj)->metadata->exif_adapter)
-#define GST_BASE_METADATA_IPTC_ADAPTER(obj) (GST_BASE_METADATA_CAST (obj)->metadata->iptc_adapter)
-#define GST_BASE_METADATA_XMP_ADAPTER(obj) (GST_BASE_METADATA_CAST (obj)->metadata->xmp_adapter)
+/*
+ * GST_BASE_METADATA_XMP_ADAPTER
+ * @obj: base metadata instance
+ *
+ * Gives the pointer to the XMP #GstAdapter of the element.
+ */
+#define GST_BASE_METADATA_XMP_ADAPTER(obj) \
+    (GST_BASE_METADATA_CAST (obj)->metadata->xmp_adapter)
 
-#define GST_BASE_METADATA_IMG_TYPE(obj) (GST_BASE_METADATA_CAST (obj)->img_type)
+/*
+ * GST_BASE_METADATA_IMG_TYPE
+ * @obj: base metadata instance
+ *
+ * Gives the type indentified by the parser of the element.
+ */
+#define GST_BASE_METADATA_IMG_TYPE(obj) \
+    (GST_BASE_METADATA_CAST (obj)->img_type)
 
 
 typedef enum _tag_MetadataState
@@ -127,7 +157,7 @@ struct _GstBaseMetadata
 
   MetaOptions options;
 
-  gboolean need_processing; /* still need some action before send first buffer */
+  gboolean need_processing; /* still need a action before send first buffer */
 
   GstAdapter *adapter_parsing;
   GstAdapter *adapter_holding;
@@ -161,10 +191,12 @@ extern GType
 gst_base_metadata_get_type (void);
 
 extern void
-gst_base_metadata_set_option_flag(GstBaseMetadata *base, const MetaOptions options);
+gst_base_metadata_set_option_flag(GstBaseMetadata *base,
+    const MetaOptions options);
 
 extern void
-gst_base_metadata_unset_option_flag(GstBaseMetadata *base, const MetaOptions options);
+gst_base_metadata_unset_option_flag(GstBaseMetadata *base,
+    const MetaOptions options);
 
 extern MetaOptions
 gst_base_metadata_get_option_flag(const GstBaseMetadata *base);
index 5384f30..d8aa2cd 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/*
+ * SECTION: metadatamuxjpeg
+ * @short_description: This module provides functions to parse JPEG files in
+ * order to write metadata to it.
+ *
+ * This module parses a JPEG stream to find the places in which metadata (EXIF,
+ * IPTC, XMP) chunks would be written. It also wraps metadata chunks with JPEG
+ * marks according to the specification.
+ *
+ * <refsect2>
+ * <para>
+ * #metadatamux_jpeg_init must be called before any other function in this
+ * module and must be paired with a call to #metadatamux_jpeg_dispose.
+ * #metadatamux_jpeg_parse is used to parse the stream (find the place
+ * metadata chunks should be written to).
+ * #metadatamux_jpeg_lazy_update do nothing.
+ * </para>
+ * <para>
+ * EXIF chunks will always be the first chunk (replaces JFIF). IPTC and XMP
+ * chunks will be placed or second chunk (after JFIF or EXIF) or third chunk
+ * if both (IPTC and XMP) are written to the file.
+ * </para>
+ * <para>
+ * When a EXIF chunk is written to the JPEG stream, if there is a JFIF chunk
+ * as the first chunk, it will be stripped out.
+ * </para>
+ * </refsect2>
+ *
+ * Last reviewed on 2008-01-24 (0.10.15)
+ */
+
+/*
+ * includes
+ */
+
 #include "metadatamuxjpeg.h"
 
 #include <string.h>
 #include <libiptcdata/iptc-jpeg.h>
 #endif
 
+/*
+ * defines and macros
+ */
+
+#define READ(buf, size) ( (size)--, *((buf)++) )
+
+/*
+ * static helper functions declaration
+ */
+
 static MetadataParsingReturn
 metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
     guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
     guint8 ** next_start, guint32 * next_size);
 
-#define READ(buf, size) ( (size)--, *((buf)++) )
-
 static void
 metadatamux_wrap_chunk (MetadataChunk * chunk, const guint8 * buf,
-    guint32 buf_size, guint8 a, guint8 b)
-{
-  guint8 *data = g_new (guint8, 4 + buf_size + chunk->size);
-
-  memcpy (data + 4 + buf_size, chunk->data, chunk->size);
-  g_free (chunk->data);
-  chunk->data = data;
-  chunk->size += 4 + buf_size;
-  data[0] = a;
-  data[1] = b;
-  data[2] = ((chunk->size - 2) >> 8) & 0xFF;
-  data[3] = (chunk->size - 2) & 0xFF;
-  if (buf && buf_size) {
-    memcpy (data + 4, buf, buf_size);
-  }
-}
+    guint32 buf_size, guint8 a, guint8 b);
 
 #ifdef HAVE_IPTC
 static gboolean
-metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size)
-{
-  unsigned int out_size = *buf_size + 4096;
-  unsigned char *outbuf = g_new (unsigned char, out_size);
-  int size_written;
-  gboolean ret = TRUE;
-
-  size_written =
-      iptc_jpeg_ps3_save_iptc (NULL, 0, *buf, *buf_size, outbuf, out_size);
-
-  g_free (*buf);
-  *buf = NULL;
-  *buf_size = 0;
-
-  if (size_written < 0) {
-    g_free (outbuf);
-    ret = FALSE;
-  } else {
-    *buf_size = size_written;
-    *buf = outbuf;
-  }
-
-  return ret;
-
-}
+metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size);
 #endif /* #ifdef HAVE_IPTC */
 
-void
-metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data)
-{
-  gsize i;
-  gboolean has_exif = FALSE;
 
-  for (i = 0; i < jpeg_data->inject_chunks->len; ++i) {
-    if (jpeg_data->inject_chunks->chunk[i].size > 0 &&
-        jpeg_data->inject_chunks->chunk[i].data) {
-      switch (jpeg_data->inject_chunks->chunk[i].type) {
-        case MD_CHUNK_EXIF:
-          metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i], NULL, 0,
-              0xFF, 0xE1);
-          has_exif = TRUE;
-          break;
-        case MD_CHUNK_IPTC:
-#ifdef HAVE_IPTC
-        {
-          if (metadatamux_wrap_iptc_with_ps3 (&jpeg_data->inject_chunks->
-                  chunk[i].data, &jpeg_data->inject_chunks->chunk[i].size)) {
-            metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i], NULL,
-                0, 0xFF, 0xED);
-          } else {
-            GST_ERROR ("Invalid IPTC chunk\n");
-            /* FIXME: remove entry from list */
-          }
-        }
-#endif /* #ifdef HAVE_IPTC */
-          break;
-        case MD_CHUNK_XMP:
-        {
-          static const char XmpHeader[] = "http://ns.adobe.com/xap/1.0/";
-
-          metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i],
-              XmpHeader, sizeof (XmpHeader), 0xFF, 0xE1);
-        }
-          break;
-        default:
-          break;
-      }
-    }
-  }
-  if (!has_exif) {
-    /* EXIF not injected so not strip JFIF anymore */
-    metadata_chunk_array_clear (jpeg_data->strip_chunks);
-  }
+/*
+ * extern functions implementations
+ */
 
-}
+/*
+ * metadatamux_jpeg_init:
+ * @jpeg_data: [in] jpeg data handler to be inited
+ * @strip_chunks: Array of chunks (offset and size) marked for removal
+ * @inject_chunks: Array of chunks (offset, data, size) marked for injection
+ * adapter (@exif_adpt, @iptc_adpt, @xmp_adpt). Or FALSE if should also put
+ * them on @strip_chunks.
+ *
+ * Init jpeg data handle.
+ * This function must be called before any other function from this module.
+ * This function must not be called twice without call to
+ * #metadatamux_jpeg_dispose beteween them.
+ * @see_also: #metadatamux_jpeg_dispose #metadatamux_jpeg_parse
+ *
+ * Returns: nothing
+ */
 
 void
 metadatamux_jpeg_init (JpegMuxData * jpeg_data,
@@ -164,6 +141,16 @@ metadatamux_jpeg_init (JpegMuxData * jpeg_data,
 
 }
 
+/*
+ * metadatamux_jpeg_dispose:
+ * @jpeg_data: [in] jpeg data handler to be freed
+ *
+ * Call this function to free any resource allocated by #metadatamux_jpeg_init
+ * @see_also: #metadatamux_jpeg_init
+ *
+ * Returns: nothing
+ */
+
 void
 metadatamux_jpeg_dispose (JpegMuxData * jpeg_data)
 {
@@ -173,6 +160,42 @@ metadatamux_jpeg_dispose (JpegMuxData * jpeg_data)
   jpeg_data->state = JPEG_MUX_NULL;
 }
 
+/*
+ * metadatamux_jpeg_parse:
+ * @jpeg_data: [in] jpeg data handle
+ * @buf: [in] data to be parsed
+ * @bufsize: [in] size of @buf in bytes
+ * @offset: is the offset where @buf starts from the beginnig of the whole 
+ * stream
+ * @next_start: is a pointer after @buf which indicates where @buf should start
+ * on the next call to this function. It means, that after returning, this
+ * function has consumed *@next_start - @buf bytes. Which also means 
+ * that @offset should also be incremanted by (*@next_start - @buf) for the
+ * next time.
+ * @next_size: [out] number of minimal bytes in @buf for the next call to this
+ * function
+ *
+ * This function is used to parse a JPEG stream step-by-step incrementally.
+ * Basically this function works like a state machine, that will run in a loop
+ * while there is still bytes in @buf to be read or it has finished parsing.
+ * If the it hasn't parsed yet and there is no more data in @buf, then the
+ * current state is saved and a indication will be make about the buffer to
+ * be passed by the caller function.
+ * @see_also: #metadatamux_jpeg_init
+ *
+ * Returns:
+ * <itemizedlist>
+ * <listitem><para>%META_PARSING_ERROR
+ * </para></listitem>
+ * <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
+ * inject chunks has been found
+ * </para></listitem>
+ * <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
+ * called again (look @next_start and @next_size)
+ * </para></listitem>
+ * </itemizedlist>
+ */
+
 MetadataParsingReturn
 metadatamux_jpeg_parse (JpegMuxData * jpeg_data, guint8 * buf,
     guint32 * bufsize, const guint32 offset, guint8 ** next_start,
@@ -227,8 +250,114 @@ done:
 
 }
 
+/*
+ * metadatamux_jpeg_lazy_update:
+ * @jpeg_data: [in] jpeg data handle
+ * 
+ * This function wrap metadata chunk with proper JPEG marks. In case of IPTC
+ * it will be wrapped by PhotoShop and then by JPEG mark.
+ * @see_also: #metadata_lazy_update
+ *
+ * Returns: nothing
+ */
+
+void
+metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data)
+{
+  gsize i;
+  gboolean has_exif = FALSE;
+
+  for (i = 0; i < jpeg_data->inject_chunks->len; ++i) {
+    if (jpeg_data->inject_chunks->chunk[i].size > 0 &&
+        jpeg_data->inject_chunks->chunk[i].data) {
+      switch (jpeg_data->inject_chunks->chunk[i].type) {
+        case MD_CHUNK_EXIF:
+          metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i], NULL, 0,
+              0xFF, 0xE1);
+          has_exif = TRUE;
+          break;
+        case MD_CHUNK_IPTC:
+#ifdef HAVE_IPTC
+        {
+          if (metadatamux_wrap_iptc_with_ps3 (&jpeg_data->inject_chunks->
+                  chunk[i].data, &jpeg_data->inject_chunks->chunk[i].size)) {
+            metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i], NULL,
+                0, 0xFF, 0xED);
+          } else {
+            GST_ERROR ("Invalid IPTC chunk\n");
+            /* FIXME: remove entry from list */
+          }
+        }
+#endif /* #ifdef HAVE_IPTC */
+          break;
+        case MD_CHUNK_XMP:
+        {
+          static const char XmpHeader[] = "http://ns.adobe.com/xap/1.0/";
+
+          metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i],
+              XmpHeader, sizeof (XmpHeader), 0xFF, 0xE1);
+        }
+          break;
+        default:
+          break;
+      }
+    }
+  }
+  if (!has_exif) {
+    /* EXIF not injected so not strip JFIF anymore */
+    metadata_chunk_array_clear (jpeg_data->strip_chunks);
+  }
+
+}
+
+
+
+/*
+ * static helper functions implementation
+ */
+
+/*
+ * metadatamux_jpeg_reading:
+ * @jpeg_data: [in] jpeg data handle
+ * @buf: [in] data to be parsed. @buf will increment during the parsing step.
+ * So it will hold the next byte to be read inside a parsing function or on
+ * the next nested parsing function. And so, @bufsize will decrement.
+ * @bufsize: [in] size of @buf in bytes. This value will decrement during the
+ * parsing for the same reason that @buf will advance.
+ * @offset: is the offset where @step_buf starts from the beginnig of the
+ * stream
+ * @step_buf: holds the pointer to the buffer passed to
+ * #metadatamux_jpeg_parse. It means that any point inside this function
+ * the offset (related to the beginning of the whole stream) after the last 
+ * byte read so far is "(*buf - step_buf) + offset"
+ * @next_start: is a pointer after @step_buf which indicates where the next
+ * call to #metadatamux_jpeg_parse should start on the next call to this
+ * function. It means, that after return, this function has
+ * consumed *@next_start - @buf bytes. Which also means that @offset should
+ * also be incremanted by (*@next_start - @buf) for the next time.
+ * @next_size: [out] number of minimal bytes in @buf for the next call to this
+ * function
+ *
+ * This function is used to parse a JPEG stream step-by-step incrementally.
+ * If this function quickly finds the place (offset) in which EXIF, IPTC and
+ * XMP chunk should be written to.
+ * The found places are written to @jpeg_data->inject_chunks
+ * @see_also: #metadatamux_jpeg_init
+ *
+ * Returns:
+ * <itemizedlist>
+ * <listitem><para>%META_PARSING_ERROR
+ * </para></listitem>
+ * <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
+ * inject chunks has been found. Or some chunk has been found and should be
+ * held or jumped.
+ * </para></listitem>
+ * <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
+ * called again (look @next_start and @next_size)
+ * </para></listitem>
+ * </itemizedlist>
+ */
 
-/* look for markers */
 static MetadataParsingReturn
 metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
     guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
@@ -338,3 +467,65 @@ done:
 
 
 }
+
+/*
+ * metadatamux_wrap_chunk:
+ * @chunk: chunk to be wrapped
+ * @buf: data to inject in the beginning of @chunk->data and after @a and @b
+ * @buf_size: size in bytes of @buf
+ * @a: together with @b forms the JPEG mark to be injected in the beginning
+ * @b: look at @a
+ *
+ * Wraps a chunk if a JPEG mark (@a@b) and, if @buf_size > 0, with some data
+ * (@buf)
+ *
+ * Returns: nothing
+ */
+
+static void
+metadatamux_wrap_chunk (MetadataChunk * chunk, const guint8 * buf,
+    guint32 buf_size, guint8 a, guint8 b)
+{
+  guint8 *data = g_new (guint8, 4 + buf_size + chunk->size);
+
+  memcpy (data + 4 + buf_size, chunk->data, chunk->size);
+  g_free (chunk->data);
+  chunk->data = data;
+  chunk->size += 4 + buf_size;
+  data[0] = a;
+  data[1] = b;
+  data[2] = ((chunk->size - 2) >> 8) & 0xFF;
+  data[3] = (chunk->size - 2) & 0xFF;
+  if (buf && buf_size) {
+    memcpy (data + 4, buf, buf_size);
+  }
+}
+
+#ifdef HAVE_IPTC
+static gboolean
+metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size)
+{
+  unsigned int out_size = *buf_size + 4096;
+  unsigned char *outbuf = g_new (unsigned char, out_size);
+  int size_written;
+  gboolean ret = TRUE;
+
+  size_written =
+      iptc_jpeg_ps3_save_iptc (NULL, 0, *buf, *buf_size, outbuf, out_size);
+
+  g_free (*buf);
+  *buf = NULL;
+  *buf_size = 0;
+
+  if (size_written < 0) {
+    g_free (outbuf);
+    ret = FALSE;
+  } else {
+    *buf_size = size_written;
+    *buf = outbuf;
+  }
+
+  return ret;
+
+}
+#endif /* #ifdef HAVE_IPTC */
index f57b7df..0185832 100644 (file)
 #ifndef __METADATAMUX_JPEG_H__
 #define __METADATAMUX_JPEG_H__
 
+/*
+ * includes
+ */
+
 #include <gst/base/gstadapter.h>
 
 #include "metadatatypes.h"
 
+/*
+ * enum and types
+ */
+
 G_BEGIN_DECLS
 
 typedef enum _tag_JpegMuxState
@@ -67,6 +75,9 @@ typedef struct _tag_JpegMuxData
 
 } JpegMuxData;
 
+/*
+ * external function prototypes
+ */
 
 extern void
 metadatamux_jpeg_init (JpegMuxData * jpeg_data, 
@@ -74,11 +85,12 @@ metadatamux_jpeg_init (JpegMuxData * jpeg_data,
 
 extern void metadatamux_jpeg_dispose (JpegMuxData * jpeg_data);
 
-extern void metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data);
-
 extern MetadataParsingReturn
 metadatamux_jpeg_parse (JpegMuxData * jpeg_data, guint8 * buf,
-    guint32 * bufsize, const guint32 offset, guint8 ** next_start, guint32 * next_size);
+    guint32 * bufsize, const guint32 offset, guint8 ** next_start,
+    guint32 * next_size);
+
+extern void metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data);
 
 G_END_DECLS
 #endif /* __METADATAMUX_JPEG_H__ */
index ac8e86b..dd3828c 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/*
+ * SECTION: metadatamuxpng
+ * @short_description: This module provides functions to parse PNG files in
+ * order to write metadata to it.
+ *
+ * This module parses a PNG stream to find the places in which XMP metadata
+ * chunks would be written. It also wraps metadata chunks with PNG marks
+ * according to the specification.
+ *
+ * <refsect2>
+ * <para>
+ * #metadatamux_png_init must be called before any other function in this
+ * module and must be paired with a call to #metadatamux_png_dispose.
+ * #metadatamux_png_parse is used to parse the stream (find the place
+ * metadata chunks should be written to).
+ * #metadatamux_png_lazy_update do nothing.
+ * </para>
+ * <para>
+ * EXIF chunks will always be the first chunk (replaces JFIF). IPTC and XMP
+ * chunks will be placed or second chunk (after JFIF or EXIF) or third chunk
+ * if both (IPTC and XMP) are written to the file.
+ * </para>
+ * <para>
+ * When a EXIF chunk is written to the PNG stream, if there is a JFIF chunk
+ * as the first chunk, it will be stripped out.
+ * </para>
+ * </refsect2>
+ *
+ * Last reviewed on 2008-01-24 (0.10.15)
+ */
+
+/*
+ * includes
+ */
+
 #include "metadatamuxpng.h"
 
 #include <string.h>
 
-static MetadataParsingReturn
-metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
-    guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
-    guint8 ** next_start, guint32 * next_size);
+/*
+ * defines and macros
+ */
 
 #define READ(buf, size) ( (size)--, *((buf)++) )
 
-static void
-make_crc_table (guint32 crc_table[])
-{
-  guint32 c;
-  guint16 n, k;
-
-  for (n = 0; n < 256; n++) {
-    c = (guint32) n;
-    for (k = 0; k < 8; k++) {
-      if (c & 1)
-        c = 0xedb88320L ^ (c >> 1);
-      else
-        c = c >> 1;
-    }
-    crc_table[n] = c;
-  }
-}
-
-static guint32
-update_crc (guint32 crc, guint8 * buf, guint32 len)
-{
-  guint32 c = crc;
-  guint32 n;
-  guint32 crc_table[256];
-
-  /* FIXME:  make_crc_table should be done once in life 
-     for speed up */
-  make_crc_table (crc_table);
+/*
+ * static helper functions declaration
+ */
 
-  for (n = 0; n < len; n++) {
-    c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
-  }
-  return c;
-}
+static MetadataParsingReturn
+metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
+    guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
+    guint8 ** next_start, guint32 * next_size);
 
-/* Return the CRC of the bytes buf[0..len-1]. */
-static guint32
-calc_crc (guint8 * buf, guint32 len)
-{
-  return update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
-}
+static void metadatamux_make_crc_table (guint32 crc_table[]);
 
+static guint32 metadatamux_update_crc (guint32 crc, guint8 * buf, guint32 len);
 
-static void
-metadatamux_wrap_xmp_chunk (MetadataChunk * chunk)
-{
-  static const char XmpHeader[] = "XML:com.adobe.xmp";
-  guint8 *data = NULL;
-  guint32 crc;
+static guint32 metadatamux_calc_crc (guint8 * buf, guint32 len);
 
-  data = g_new (guint8, 12 + 18 + 4 + chunk->size);
+static void metadatamux_wrap_xmp_chunk (MetadataChunk * chunk);
 
-  memcpy (data + 8, XmpHeader, 18);
-  memset (data + 8 + 18, 0x00, 4);
-  memcpy (data + 8 + 18 + 4, chunk->data, chunk->size);
-  g_free (chunk->data);
-  chunk->data = data;
-  chunk->size += 18 + 4;
-  data[0] = (chunk->size >> 24) & 0xFF;
-  data[1] = (chunk->size >> 16) & 0xFF;
-  data[2] = (chunk->size >> 8) & 0xFF;
-  data[3] = chunk->size & 0xFF;
-  data[4] = 'i';
-  data[5] = 'T';
-  data[6] = 'X';
-  data[7] = 't';
-  crc = calc_crc (data + 4, chunk->size + 4 + 18);
-  data[chunk->size + 8] = (crc >> 24) & 0xFF;
-  data[chunk->size + 9] = (crc >> 16) & 0xFF;
-  data[chunk->size + 10] = (crc >> 8) & 0xFF;
-  data[chunk->size + 11] = crc & 0xFF;
-  chunk->size += 12;
-
-}
-
-void
-metadatamux_png_lazy_update (PngMuxData * png_data)
-{
-  gsize i;
+/*
+ * extern functions implementations
+ */
 
-  for (i = 0; i < png_data->inject_chunks->len; ++i) {
-    if (png_data->inject_chunks->chunk[i].size > 0 &&
-        png_data->inject_chunks->chunk[i].data) {
-      switch (png_data->inject_chunks->chunk[i].type) {
-        case MD_CHUNK_XMP:
-        {
-          metadatamux_wrap_xmp_chunk (&png_data->inject_chunks->chunk[i]);
-        }
-          break;
-        default:
-          GST_ERROR ("Unexpected chunk for PNG muxer.");
-          break;
-      }
-    }
-  }
-}
+/*
+ * metadatamux_png_init:
+ * @png_data: [in] png data handler to be inited
+ * @strip_chunks: Array of chunks (offset and size) marked for removal
+ * @inject_chunks: Array of chunks (offset, data, size) marked for injection
+ * adapter (@exif_adpt, @iptc_adpt, @xmp_adpt). Or FALSE if should also put
+ * them on @strip_chunks.
+ *
+ * Init png data handle.
+ * This function must be called before any other function from this module.
+ * This function must not be called twice without call to
+ * #metadatamux_png_dispose beteween them.
+ * @see_also: #metadatamux_png_dispose #metadatamux_png_parse
+ *
+ * Returns: nothing
+ */
 
 void
 metadatamux_png_init (PngMuxData * png_data,
@@ -159,6 +134,16 @@ metadatamux_png_init (PngMuxData * png_data,
   png_data->inject_chunks = inject_chunks;
 }
 
+/*
+ * metadatamux_png_dispose:
+ * png_data: [in] png data handler to be freed
+ *
+ * Call this function to free any resource allocated by #metadatamux_png_init
+ * @see_also: #metadatamux_png_init
+ *
+ * Returns: nothing
+ */
+
 void
 metadatamux_png_dispose (PngMuxData * png_data)
 {
@@ -168,6 +153,42 @@ metadatamux_png_dispose (PngMuxData * png_data)
   png_data->state = PNG_MUX_NULL;
 }
 
+/*
+ * metadatamux_png_parse:
+ * @png_data: [in] png data handle
+ * @buf: [in] data to be parsed
+ * @bufsize: [in] size of @buf in bytes
+ * @offset: is the offset where @buf starts from the beginnig of the whole 
+ * stream
+ * @next_start: is a pointer after @buf which indicates where @buf should start
+ * on the next call to this function. It means, that after returning, this
+ * function has consumed *@next_start - @buf bytes. Which also means 
+ * that @offset should also be incremanted by (*@next_start - @buf) for the
+ * next time.
+ * @next_size: [out] number of minimal bytes in @buf for the next call to this
+ * function
+ *
+ * This function is used to parse a PNG stream step-by-step incrementally.
+ * Basically this function works like a state machine, that will run in a loop
+ * while there is still bytes in @buf to be read or it has finished parsing.
+ * If the it hasn't parsed yet and there is no more data in @buf, then the
+ * current state is saved and a indication will be make about the buffer to
+ * be passed by the caller function.
+ * @see_also: #metadatamux_png_init
+ *
+ * Returns:
+ * <itemizedlist>
+ * <listitem><para>%META_PARSING_ERROR
+ * </para></listitem>
+ * <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
+ * inject chunks has been found
+ * </para></listitem>
+ * <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
+ * called again (look @next_start and @next_size)
+ * </para></listitem>
+ * </itemizedlist>
+ */
+
 MetadataParsingReturn
 metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
     guint32 * bufsize, const guint32 offset, guint8 ** next_start,
@@ -230,8 +251,86 @@ done:
 
 }
 
+/*
+ * metadatamux_png_lazy_update:
+ * @png_data: [in] png data handle
+ * 
+ * This function wrap metadata chunk with proper PNG bytes.
+ * @see_also: #metadata_lazy_update
+ *
+ * Returns: nothing
+ */
+
+void
+metadatamux_png_lazy_update (PngMuxData * png_data)
+{
+  gsize i;
+
+  for (i = 0; i < png_data->inject_chunks->len; ++i) {
+    if (png_data->inject_chunks->chunk[i].size > 0 &&
+        png_data->inject_chunks->chunk[i].data) {
+      switch (png_data->inject_chunks->chunk[i].type) {
+        case MD_CHUNK_XMP:
+        {
+          metadatamux_wrap_xmp_chunk (&png_data->inject_chunks->chunk[i]);
+        }
+          break;
+        default:
+          GST_ERROR ("Unexpected chunk for PNG muxer.");
+          break;
+      }
+    }
+  }
+}
+
+
+/*
+ * static helper functions implementation
+ */
+
+/*
+ * metadatamux_png_reading:
+ * @png_data: [in] png data handle
+ * @buf: [in] data to be parsed. @buf will increment during the parsing step.
+ * So it will hold the next byte to be read inside a parsing function or on
+ * the next nested parsing function. And so, @bufsize will decrement.
+ * @bufsize: [in] size of @buf in bytes. This value will decrement during the
+ * parsing for the same reason that @buf will advance.
+ * @offset: is the offset where @step_buf starts from the beginnig of the
+ * stream
+ * @step_buf: holds the pointer to the buffer passed to
+ * #metadatamux_png_parse. It means that any point inside this function
+ * the offset (related to the beginning of the whole stream) after the last 
+ * byte read so far is "(*buf - step_buf) + offset"
+ * @next_start: is a pointer after @step_buf which indicates where the next
+ * call to #metadatamux_png_parse should start on the next call to this
+ * function. It means, that after return, this function has
+ * consumed *@next_start - @buf bytes. Which also means that @offset should
+ * also be incremanted by (*@next_start - @buf) for the next time.
+ * @next_size: [out] number of minimal bytes in @buf for the next call to this
+ * function
+ *
+ * This function is used to parse a PNG stream step-by-step incrementally.
+ * If this function quickly finds the place (offset) in which EXIF, IPTC and
+ * XMP chunk should be written to.
+ * The found places are written to @png_data->inject_chunks
+ * @see_also: #metadatamux_png_init
+ *
+ * Returns:
+ * <itemizedlist>
+ * <listitem><para>%META_PARSING_ERROR
+ * </para></listitem>
+ * <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
+ * inject chunks has been found. Or some chunk has been found and should be
+ * held or jumped.
+ * </para></listitem>
+ * <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
+ * called again (look @next_start and @next_size)
+ * </para></listitem>
+ * </itemizedlist>
+ */
+
 
-/* look for markers */
 static MetadataParsingReturn
 metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
     guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
@@ -287,3 +386,119 @@ done:
 
 
 }
+
+/*
+ * metadatamux_make_crc_table:
+ * @crc_table: table to be written to.
+ *
+ * Creates a startup CRC table. For optimization it should be done only once.
+ * @see_also: #metadatamux_update_crc
+ *
+ * Returns: nothing.
+ */
+
+static void
+metadatamux_make_crc_table (guint32 crc_table[])
+{
+  guint32 c;
+  guint16 n, k;
+
+  for (n = 0; n < 256; n++) {
+    c = (guint32) n;
+    for (k = 0; k < 8; k++) {
+      if (c & 1)
+        c = 0xedb88320L ^ (c >> 1);
+      else
+        c = c >> 1;
+    }
+    crc_table[n] = c;
+  }
+}
+
+/*
+ * metadatamux_update_crc:
+ * @crc: seed to calculate the CRC
+ * @buf: data to calculate the CRC for
+ * @len: size in bytes of @buf
+ *
+ * Calculates the CRC of a data buffer for a seed @crc.
+ * @see_also: #metadatamux_make_crc_table #metadatamux_calc_crc
+ *
+ * Returns: the CRC of the bytes buf[0..len-1].
+ */
+
+static guint32
+metadatamux_update_crc (guint32 crc, guint8 * buf, guint32 len)
+{
+  guint32 c = crc;
+  guint32 n;
+  guint32 crc_table[256];
+
+  /* FIXME:  make_crc_table should be done once in life 
+     for speed up. It could be written hard coded to a file */
+  metadatamux_make_crc_table (crc_table);
+
+  for (n = 0; n < len; n++) {
+    c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+  }
+  return c;
+}
+
+/*
+ * metadatamux_calc_crc:
+ * @buf: data to calculate the CRC for
+ * @len: size in bytes of @buf
+ *
+ * Calculates the CRC of a data buffer.
+ *
+ * Returns: the CRC of the bytes buf[0..len-1].
+ */
+
+static guint32
+metadatamux_calc_crc (guint8 * buf, guint32 len)
+{
+  return metadatamux_update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
+}
+
+
+/*
+ * metadatamux_wrap_xmp_chunk:
+ * @chunk: chunk to be wrapped
+ *
+ * Wraps a XMP chunk with proper PNG bytes (mark, size and crc in the end)
+ *
+ * Returns: nothing
+ */
+
+static void
+metadatamux_wrap_xmp_chunk (MetadataChunk * chunk)
+{
+  static const char XmpHeader[] = "XML:com.adobe.xmp";
+  guint8 *data = NULL;
+  guint32 crc;
+
+  data = g_new (guint8, 12 + 18 + 4 + chunk->size);
+
+  memcpy (data + 8, XmpHeader, 18);
+  memset (data + 8 + 18, 0x00, 4);
+  memcpy (data + 8 + 18 + 4, chunk->data, chunk->size);
+  g_free (chunk->data);
+  chunk->data = data;
+  chunk->size += 18 + 4;
+  data[0] = (chunk->size >> 24) & 0xFF;
+  data[1] = (chunk->size >> 16) & 0xFF;
+  data[2] = (chunk->size >> 8) & 0xFF;
+  data[3] = chunk->size & 0xFF;
+  data[4] = 'i';
+  data[5] = 'T';
+  data[6] = 'X';
+  data[7] = 't';
+  crc = metadatamux_calc_crc (data + 4, chunk->size + 4);
+  data[chunk->size + 8] = (crc >> 24) & 0xFF;
+  data[chunk->size + 9] = (crc >> 16) & 0xFF;
+  data[chunk->size + 10] = (crc >> 8) & 0xFF;
+  data[chunk->size + 11] = crc & 0xFF;
+
+  chunk->size += 12;
+
+}
index 96eb7bd..8680ca5 100644 (file)
 #ifndef __METADATAMUX_PNG_H__
 #define __METADATAMUX_PNG_H__
 
+/*
+ * includes
+ */
+
 #include <gst/base/gstadapter.h>
 
 #include "metadatatypes.h"
 
 G_BEGIN_DECLS
 
+/*
+ * enum and types
+ */
+
 typedef enum _tag_PngMuxState
 {
   PNG_MUX_NULL,
@@ -69,6 +77,9 @@ typedef struct _tag_PngMuxData
 
 } PngMuxData;
 
+/*
+ * external function prototypes
+ */
 
 extern void
 metadatamux_png_init (PngMuxData * png_data,
@@ -80,7 +91,8 @@ extern void metadatamux_png_lazy_update (PngMuxData * png_data);
 
 extern MetadataParsingReturn
 metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
-    guint32 * bufsize, const guint32 offset, guint8 ** next_start, guint32 * next_size);
+    guint32 * bufsize, const guint32 offset, guint8 ** next_start,
+    guint32 * next_size);
 
 G_END_DECLS
 #endif /* __METADATAMUX_PNG_H__ */
index ce6a161..fb950b3 100644 (file)
@@ -185,7 +185,7 @@ metadataparse_jpeg_dispose (JpegParseData * jpeg_data)
 }
 
 /*
- * metadata_parse:
+ * metadataparse_jpeg_parse:
  * @jpeg_data: [in] jpeg data handle
  * @buf: [in] data to be parsed
  * @bufsize: [in] size of @buf in bytes
@@ -310,7 +310,7 @@ done:
  * @jpeg_data: [in] jpeg data handle
  * 
  * This function do nothing
- * @see_also: metadata_lazy_update
+ * @see_also: #metadata_lazy_update
  *
  * Returns: nothing
  */
index b5a8e77..3999d59 100644 (file)
@@ -152,7 +152,7 @@ metadataparse_png_dispose (PngParseData * png_data)
 }
 
 /*
- * metadata_parse:
+ * metadataparse_png_parse:
  * @png_data: [in] png data handle
  * @buf: [in] data to be parsed
  * @bufsize: [in] size of @buf in bytes
@@ -273,7 +273,7 @@ done:
  * @png_data: [in] png data handle
  * 
  * This function do nothing
- * @see_also: metadata_lazy_update
+ * @see_also: #metadata_lazy_update
  *
  * Returns: nothing
  */
index 79d2031..be1649b 100644 (file)
@@ -22,7 +22,8 @@ metadata_editor_SOURCES = metadata_editor.c
 metadata_editor_CFLAGS  = \
        $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GLADE_CFLAGS)
 metadata_editor_LDADD   = \
-       $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-0.10 $(GST_LIBS) $(GLADE_LIBS)
+       $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-0.10 $(GST_LIBS) \
+       $(GLADE_LIBS) -Wl -export-dynamic
 metadata_editor_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 else
 GST_METADATA_TESTS =