qtdemux: Parse xmp packet in uuid atom
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Thu, 16 Sep 2010 01:13:43 +0000 (22:13 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Tue, 21 Sep 2010 01:37:26 +0000 (22:37 -0300)
xmp packet is placed into a top-level uuid atom for
isom/mp4 variants.

This patch makes qtdemux parse all top-level atoms
in pull-mode before starting to push data, making
it able to find those tags.

https://bugzilla.gnome.org/show_bug.cgi?id=629839

gst/qtdemux/qtdemux.c
gst/qtdemux/qtdemux_fourcc.h

index 3997457..f310fda 100644 (file)
@@ -1734,6 +1734,59 @@ qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
 }
 
 static void
+qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
+{
+  /* Strip out bogus fields */
+  if (taglist) {
+    gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
+
+    GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
+
+    if (qtdemux->tag_list) {
+      /* prioritize native tags using _KEEP mode */
+      gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
+      gst_tag_list_free (taglist);
+    } else
+      qtdemux->tag_list = taglist;
+  }
+}
+
+static void
+qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+{
+  static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
+    0x97, 0xA9, 0x42, 0xE8,
+    0x9C, 0x71, 0x99, 0x94,
+    0x91, 0xE3, 0xAF, 0xAC
+  };
+  guint offset;
+
+  offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
+
+  if (length <= offset + 16) {
+    GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
+    return;
+  }
+
+  if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
+    GstBuffer *buf;
+    GstTagList *taglist;
+
+    buf = gst_buffer_new ();
+    GST_BUFFER_DATA (buf) = (guint8 *) buffer + offset + 16;
+    GST_BUFFER_SIZE (buf) = length - offset - 16;
+
+    taglist = gst_tag_list_from_xmp_buffer (buf);
+    gst_buffer_unref (buf);
+
+    qtdemux_handle_xmp_taglist (qtdemux, taglist);
+
+  } else {
+    GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid");
+  }
+}
+
+static void
 extract_initial_length_and_fourcc (const guint8 * data, guint64 * plength,
     guint32 * pfourcc)
 {
@@ -1802,6 +1855,12 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
     {
       GstBuffer *moov;
 
+      if (qtdemux->got_moov) {
+        GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
+        qtdemux->offset += length;
+        goto beach;
+      }
+
       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
       if (ret != GST_FLOW_OK)
         goto beach;
@@ -1851,9 +1910,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
       g_node_destroy (qtdemux->moov_node);
       gst_buffer_unref (moov);
       qtdemux->moov_node = NULL;
-      qtdemux->state = QTDEMUX_STATE_MOVIE;
-      GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
-          qtdemux->state);
+      qtdemux->got_moov = TRUE;
       break;
     }
     case FOURCC_ftyp:
@@ -1870,6 +1927,20 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
       gst_buffer_unref (ftyp);
       break;
     }
+    case FOURCC_uuid:
+    {
+      GstBuffer *uuid;
+
+      /* uuid are extension atoms */
+      ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
+      if (ret != GST_FLOW_OK)
+        goto beach;
+      qtdemux->offset += length;
+      qtdemux_parse_uuid (qtdemux, GST_BUFFER_DATA (uuid),
+          GST_BUFFER_SIZE (uuid));
+      gst_buffer_unref (uuid);
+      break;
+    }
     default:
     {
       GstBuffer *unknown;
@@ -1890,6 +1961,12 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
   }
 
 beach:
+  if (ret == GST_FLOW_UNEXPECTED && qtdemux->got_moov) {
+    qtdemux->state = QTDEMUX_STATE_MOVIE;
+    GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
+        qtdemux->state);
+    return GST_FLOW_OK;
+  }
   return ret;
 }
 
@@ -7003,19 +7080,7 @@ qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
     taglist = gst_tag_list_from_xmp_buffer (buf);
     gst_buffer_unref (buf);
 
-    /* Strip out bogus fields */
-
-    if (taglist) {
-      gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
-      if (qtdemux->tag_list) {
-        GST_DEBUG_OBJECT (qtdemux, "Found XMP tags");
-
-        /* prioritize native tags using _KEEP mode */
-        gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
-        gst_tag_list_free (taglist);
-      } else
-        qtdemux->tag_list = taglist;
-    }
+    qtdemux_handle_xmp_taglist (qtdemux, taglist);
   } else {
     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
   }
index 345fe5e..c4c0841 100644 (file)
@@ -205,6 +205,7 @@ G_BEGIN_DECLS
 #define FOURCC_tCtC     GST_MAKE_FOURCC('t','C','t','C')
 
 #define FOURCC_XMP_     GST_MAKE_FOURCC('X','M','P','_')
+#define FOURCC_uuid     GST_MAKE_FOURCC('u','u','i','d')
 
 G_END_DECLS