Use g_memdup2() where available and add fallback for older GLib versions
[platform/upstream/gstreamer.git] / gst-libs / gst / riff / riff-read.c
index 5b03021..5e9f331 100644 (file)
@@ -15,8 +15,8 @@
  *
  * 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.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -40,8 +40,8 @@ GST_DEBUG_CATEGORY_EXTERN (riff_debug);
  * @tag: fourcc of the chunk (returned by this function).
  * @chunk_data: buffer (returned by this function).
  *
- * Reads a single chunk of data. Since 0.10.8 'JUNK' chunks
- * are skipped automatically.
+ * Reads a single chunk of data. 'JUNK' chunks are skipped
+ * automatically.
  *
  * Returns: flow status.
  */
@@ -235,7 +235,8 @@ gst_riff_parse_file_header (GstElement * element,
     goto too_small;
 
   tag = GST_READ_UINT32_LE (info.data);
-  if (tag != GST_RIFF_TAG_RIFF && tag != GST_RIFF_TAG_AVF0)
+  if (tag != GST_RIFF_TAG_RIFF && tag != GST_RIFF_TAG_AVF0
+      && tag != GST_RIFF_TAG_RF64)
     goto not_riff;
 
   *doctype = GST_READ_UINT32_LE (info.data + 8);
@@ -258,8 +259,7 @@ too_small:
 not_riff:
   {
     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
-        ("Stream is no RIFF stream: %" GST_FOURCC_FORMAT,
-            GST_FOURCC_ARGS (tag)));
+        ("Stream is no RIFF stream: 0x%" G_GINT32_MODIFIER "x", tag));
     gst_buffer_unmap (buf, &info);
     gst_buffer_unref (buf);
     return FALSE;
@@ -293,7 +293,7 @@ gst_riff_parse_strh (GstElement * element,
   if (info.size < sizeof (gst_riff_strh))
     goto too_small;
 
-  strh = g_memdup (info.data, info.size);
+  strh = g_memdup2 (info.data, info.size);
   gst_buffer_unmap (buf, &info);
 
   gst_buffer_unref (buf);
@@ -362,7 +362,7 @@ too_small:
  *        containing extradata for this particular stream (e.g.
  *        palette, codec initialization data).
  *
- * Parses a video stream´s strf structure plus optionally some
+ * Parses a video stream's strf structure plus optionally some
  * extradata from input data. This function takes ownership of @buf.
  *
  * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
@@ -384,7 +384,7 @@ gst_riff_parse_strf_vids (GstElement * element,
   if (info.size < sizeof (gst_riff_strf_vids))
     goto too_small;
 
-  strf = g_memdup (info.data, info.size);
+  strf = g_memdup2 (info.data, info.size);
   gst_buffer_unmap (buf, &info);
 
 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
@@ -460,7 +460,7 @@ too_small:
  *        containing extradata for this particular stream (e.g.
  *        codec initialization data).
  *
- * Parses an audio stream´s strf structure plus optionally some
+ * Parses an audio stream's strf structure plus optionally some
  * extradata from input data. This function takes ownership of @buf.
  * use.
  *
@@ -482,7 +482,7 @@ gst_riff_parse_strf_auds (GstElement * element,
   if (info.size < sizeof (gst_riff_strf_auds))
     goto too_small;
 
-  strf = g_memdup (info.data, info.size);
+  strf = g_memdup2 (info.data, info.size);
 
 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
   strf->format = GUINT16_FROM_LE (strf->format);
@@ -490,7 +490,7 @@ gst_riff_parse_strf_auds (GstElement * element,
   strf->rate = GUINT32_FROM_LE (strf->rate);
   strf->av_bps = GUINT32_FROM_LE (strf->av_bps);
   strf->blockalign = GUINT16_FROM_LE (strf->blockalign);
-  strf->size = GUINT16_FROM_LE (strf->size);
+  strf->bits_per_sample = GUINT16_FROM_LE (strf->bits_per_sample);
 #endif
 
   /* size checking */
@@ -498,10 +498,10 @@ gst_riff_parse_strf_auds (GstElement * element,
   if (info.size > sizeof (gst_riff_strf_auds) + 2) {
     gint len;
 
-    len = GST_READ_UINT16_LE (&data[16]);
+    len = GST_READ_UINT16_LE (&info.data[16]);
     if (len + 2 + sizeof (gst_riff_strf_auds) > info.size) {
       GST_WARNING_OBJECT (element,
-          "Extradata indicated %d bytes, but only %" G_GSSIZE_FORMAT
+          "Extradata indicated %d bytes, but only %" G_GSIZE_FORMAT
           " available", len, info.size - 2 - sizeof (gst_riff_strf_auds));
       len = info.size - 2 - sizeof (gst_riff_strf_auds);
     }
@@ -517,7 +517,7 @@ gst_riff_parse_strf_auds (GstElement * element,
   GST_INFO_OBJECT (element, " rate        %d", strf->rate);
   GST_INFO_OBJECT (element, " av_bps      %d", strf->av_bps);
   GST_INFO_OBJECT (element, " blockalign  %d", strf->blockalign);
-  GST_INFO_OBJECT (element, " size        %d", strf->size);
+  GST_INFO_OBJECT (element, " bits/sample %d", strf->bits_per_sample);
   if (*data)
     GST_INFO_OBJECT (element, " %" G_GSIZE_FORMAT " bytes extradata",
         gst_buffer_get_size (*data));
@@ -534,7 +534,7 @@ too_small:
   {
     GST_ERROR_OBJECT (element,
         "Too small strf_auds (%" G_GSIZE_FORMAT " available"
-        ", %" G_GSSIZE_FORMAT " needed)", info.size,
+        ", %" G_GSIZE_FORMAT " needed)", info.size,
         sizeof (gst_riff_strf_auds));
     gst_buffer_unmap (buf, &info);
     gst_buffer_unref (buf);
@@ -574,7 +574,7 @@ gst_riff_parse_strf_iavs (GstElement * element,
   if (info.size < sizeof (gst_riff_strf_iavs))
     goto too_small;
 
-  strf = g_memdup (info.data, info.size);
+  strf = g_memdup2 (info.data, info.size);
   gst_buffer_unmap (buf, &info);
 
   gst_buffer_unref (buf);
@@ -611,7 +611,7 @@ too_small:
   {
     GST_ERROR_OBJECT (element,
         "Too small strf_iavs (%" G_GSIZE_FORMAT "available"
-        ", %" G_GSSIZE_FORMAT " needed)", info.size,
+        ", %" G_GSIZE_FORMAT " needed)", info.size,
         sizeof (gst_riff_strf_iavs));
     gst_buffer_unmap (buf, &info);
     gst_buffer_unref (buf);
@@ -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).
@@ -657,6 +691,9 @@ gst_riff_parse_info (GstElement * element,
   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;
 
@@ -670,11 +707,17 @@ gst_riff_parse_info (GstElement * element,
       tsize = left;
     }
 
+    /* make uppercase */
+    tag = tag & 0xDFDFDFDF;
+
     /* find out the type of metadata */
     switch (tag) {
       case GST_RIFF_INFO_IARL:
         type = GST_TAG_LOCATION;
         break;
+      case GST_RIFF_INFO_IAAR:
+        type = GST_TAG_ALBUM_ARTIST;
+        break;
       case GST_RIFF_INFO_IART:
         type = GST_TAG_ARTIST;
         break;
@@ -688,7 +731,7 @@ gst_riff_parse_info (GstElement * element,
         type = GST_TAG_COPYRIGHT;
         break;
       case GST_RIFF_INFO_ICRD:
-        type = GST_TAG_DATE;
+        type = GST_TAG_DATE_TIME;
         break;
       case GST_RIFF_INFO_ICRP:
         type = NULL;            /*"Cropped"; */
@@ -721,10 +764,10 @@ gst_riff_parse_info (GstElement * element,
         type = NULL;            /*"Palette"; */
         break;
       case GST_RIFF_INFO_IPRD:
-        type = NULL;            /*"Product"; */
+        type = GST_TAG_ALBUM;
         break;
       case GST_RIFF_INFO_ISBJ:
-        type = NULL;            /*"Subject"; */
+        type = GST_TAG_ALBUM_ARTIST;
         break;
       case GST_RIFF_INFO_ISFT:
         type = GST_TAG_ENCODER;
@@ -741,6 +784,9 @@ gst_riff_parse_info (GstElement * element,
       case GST_RIFF_INFO_ITCH:
         type = NULL;            /*"Technician"; */
         break;
+      case GST_RIFF_INFO_ITRK:
+        type = GST_TAG_TRACK_NUMBER;
+        break;
       default:
         type = NULL;
         GST_WARNING_OBJECT (element,
@@ -750,19 +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
-      };
-      gchar *val;
-
-      val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
+      GST_DEBUG_OBJECT (element, "mapped tag %" GST_FOURCC_FORMAT " to tag %s",
+          GST_FOURCC_ARGS (tag), type);
 
-      if (val) {
-        gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
-        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) {
@@ -776,10 +813,11 @@ gst_riff_parse_info (GstElement * element,
   }
 
   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_free (taglist);
+    gst_tag_list_unref (taglist);
   }
   gst_buffer_unmap (buf, &info);