riff: add support for nikon tags
authorStefan Sauer <ensonic@users.sf.net>
Sat, 4 Jan 2014 20:31:07 +0000 (21:31 +0100)
committerStefan Sauer <ensonic@users.sf.net>
Sat, 4 Jan 2014 20:35:29 +0000 (21:35 +0100)
Nikon cameras store metadata in a custom format. Add parsing of the chunk and
extract some initial data.
API: gst_riff_parse_ncdt()
Fixes #636143

gst-libs/gst/riff/riff-ids.h
gst-libs/gst/riff/riff-read.c
gst-libs/gst/riff/riff-read.h

index 9542c596227cffb92fc4aaa1ad870cf51b412c43..690a6513add8a4fcf3fadd35b28bc410feba0a0b 100644 (file)
@@ -71,6 +71,7 @@ G_BEGIN_DECLS
 #define GST_RIFF_LIST_INFO GST_MAKE_FOURCC ('I','N','F','O')
 #define GST_RIFF_LIST_AVIX GST_MAKE_FOURCC ('A','V','I','X')
 #define GST_RIFF_LIST_adtl GST_MAKE_FOURCC ('a','d','t','l')
+#define GST_RIFF_LIST_ncdt GST_MAKE_FOURCC ('n','c','d','t')
 
 /* fcc types */
 #define GST_RIFF_FCC_vids GST_MAKE_FOURCC ('v','i','d','s')
@@ -112,6 +113,9 @@ G_BEGIN_DECLS
 #define GST_RIFF_INFO_IAAR GST_MAKE_FOURCC ('I','A','A','R') /* album artist */
 #define GST_RIFF_INFO_ITRK GST_MAKE_FOURCC ('I','T','R','K') /* track number */
 
+/* ncdt types - see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCDT */
+#define GST_RIFF_LIST_nctg GST_MAKE_FOURCC ('n','c','t','g')
+
 /*********Chunk Names***************/
 #define GST_RIFF_FF00 GST_MAKE_FOURCC (0xFF,0xFF,0x00,0x00)
 #define GST_RIFF_00   GST_MAKE_FOURCC ('0', '0',0x00,0x00)
index 8bc5fa682e95c44cf77a8cdc2e47f1bfb5c60e21..6afaa1ef139d450436c0534c13dc052c8256ea14 100644 (file)
@@ -619,6 +619,40 @@ too_small:
   }
 }
 
+static void
+parse_tag_value (GstElement * element, GstTagList * taglist, const gchar * type,
+    guint8 * ptr, guint tsize)
+{
+  static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
+    "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
+  };
+  GType tag_type;
+  gchar *val;
+
+  tag_type = gst_tag_get_type (type);
+  val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
+
+  if (val != NULL) {
+    if (tag_type == G_TYPE_STRING) {
+      gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
+    } else {
+      GValue tag_val = { 0, };
+
+      g_value_init (&tag_val, tag_type);
+      if (gst_value_deserialize (&tag_val, val)) {
+        gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type, &tag_val);
+      } else {
+        GST_WARNING_OBJECT (element, "could not deserialize '%s' into a "
+            "tag %s of type %s", val, type, g_type_name (tag_type));
+      }
+      g_value_unset (&tag_val);
+    }
+    g_free (val);
+  } else {
+    GST_WARNING_OBJECT (element, "could not extract %s tag", type);
+  }
+}
+
 /**
  * gst_riff_parse_info:
  * @element: caller element (used for debugging/error).
@@ -762,38 +796,10 @@ gst_riff_parse_info (GstElement * element,
     }
 
     if (type != NULL && ptr[0] != '\0') {
-      static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
-        "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
-      };
-      GType tag_type;
-      gchar *val;
-
       GST_DEBUG_OBJECT (element, "mapped tag %" GST_FOURCC_FORMAT " to tag %s",
           GST_FOURCC_ARGS (tag), type);
 
-      tag_type = gst_tag_get_type (type);
-      val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
-
-      if (val != NULL) {
-        if (tag_type == G_TYPE_STRING) {
-          gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
-        } else {
-          GValue tag_val = { 0, };
-
-          g_value_init (&tag_val, tag_type);
-          if (gst_value_deserialize (&tag_val, val)) {
-            gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type,
-                &tag_val);
-          } else {
-            GST_WARNING_OBJECT (element, "could not deserialize '%s' into a "
-                "tag %s of type %s", val, type, g_type_name (tag_type));
-          }
-          g_value_unset (&tag_val);
-        }
-        g_free (val);
-      } else {
-        GST_WARNING_OBJECT (element, "could not extract %s tag", type);
-      }
+      parse_tag_value (element, taglist, type, ptr, tsize);
     }
 
     if (tsize & 1) {
@@ -817,3 +823,136 @@ gst_riff_parse_info (GstElement * element,
 
   return;
 }
+
+/**
+ * gst_riff_parse_ncdt:
+ * @element: caller element (used for debugging/error).
+ * @buf: input data to be used for parsing, stripped from header.
+ * @taglist: a pointer to a taglist (returned by this function)
+ *           containing information about this stream. May be
+ *           NULL if no supported tags were found.
+ *
+ * Parses Nikon metadata from input data.
+ *
+ * Since: 1.4
+ */
+void
+gst_riff_parse_ncdt (GstElement * element,
+    GstBuffer * buf, GstTagList ** _taglist)
+{
+  GstMapInfo info;
+  guint8 *ptr;
+  gsize left;
+  guint tsize;
+  guint32 tag;
+  const gchar *type;
+  GstTagList *taglist;
+
+  g_return_if_fail (_taglist != NULL);
+
+  if (!buf) {
+    *_taglist = NULL;
+    return;
+  }
+  gst_buffer_map (buf, &info, GST_MAP_READ);
+
+  taglist = gst_tag_list_new_empty ();
+
+  ptr = info.data;
+  left = info.size;
+
+  while (left > 8) {
+    tag = GST_READ_UINT32_LE (ptr);
+    tsize = GST_READ_UINT32_LE (ptr + 4);
+
+    GST_MEMDUMP_OBJECT (element, "tag chunk", ptr, MIN (tsize + 8, left));
+
+    left -= 8;
+    ptr += 8;
+
+    GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u",
+        GST_FOURCC_ARGS (tag), tsize);
+
+    if (tsize > left) {
+      GST_WARNING_OBJECT (element,
+          "Tagsize %d is larger than available data %" G_GSIZE_FORMAT,
+          tsize, left);
+      tsize = left;
+    }
+
+    /* find out the type of metadata */
+    switch (tag) {
+      case GST_RIFF_LIST_nctg:{
+        while (tsize > 4) {
+          guint16 sub_tag = GST_READ_UINT16_LE (ptr);
+          guint16 sub_size = GST_READ_UINT16_LE (ptr + 2);
+
+          tsize -= 4;
+          ptr += 4;
+
+          GST_DEBUG ("sub-tag %u, size %u", sub_tag, sub_size);
+          /* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
+           * for some reason the sub_tag has a +2 offset
+           */
+          switch (sub_tag) {
+            case 0x03:         /* Make */
+              type = GST_TAG_DEVICE_MANUFACTURER;
+              break;
+            case 0x04:         /* Model */
+              type = GST_TAG_DEVICE_MODEL;
+              break;
+              /* TODO: 0x05: is software version, like V1.0 */
+            case 0x06:         /* Software */
+              type = GST_TAG_ENCODER;
+              break;
+            case 0x13:         /* CreationDate */
+              type = GST_TAG_DATE_TIME;
+              if (ptr[4] == ':')
+                ptr[4] = '-';
+              if (ptr[7] == ':')
+                ptr[7] = '-';
+              break;
+            default:
+              type = NULL;
+              break;
+          }
+          if (type != NULL && ptr[0] != '\0') {
+            GST_DEBUG_OBJECT (element, "mapped tag %u to tag %s", sub_tag,
+                type);
+
+            parse_tag_value (element, taglist, type, ptr, sub_size);
+          }
+
+          ptr += sub_size;
+          tsize -= sub_size;
+        }
+        break;
+      default:
+        type = NULL;
+        GST_WARNING_OBJECT (element,
+            "Unknown ncdt (metadata) tag entry %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (tag));
+        break;
+      }
+
+        if (tsize & 1) {
+          tsize++;
+          if (tsize > left)
+            tsize = left;
+        }
+
+        ptr += tsize;
+        left -= tsize;
+    }
+
+    if (!gst_tag_list_is_empty (taglist)) {
+      GST_INFO_OBJECT (element, "extracted tags: %" GST_PTR_FORMAT, taglist);
+      *_taglist = taglist;
+    } else {
+      *_taglist = NULL;
+      gst_tag_list_unref (taglist);
+    }
+    gst_buffer_unmap (buf, &info);
+
+    return;
+  }
index 918b997628312a495247ef945d23e5635c4f44cb..57e8bfe260beb7a0beb2fe8c5815aa23b50b9d96 100644 (file)
@@ -77,6 +77,9 @@ void gst_riff_parse_info            (GstElement  * element,
                                      GstBuffer   * buf,
                                      GstTagList ** taglist);
 
+void gst_riff_parse_ncdt            (GstElement  * element,
+                                     GstBuffer   * buf,
+                                     GstTagList ** taglist);
 /*
  * Init.
  */