gst-libs/gst/tag/: API: add gst_tag_image_data_to_image_buffer()
authorTim-Philipp Müller <tim@centricular.net>
Tue, 3 Jun 2008 19:29:06 +0000 (19:29 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Tue, 3 Jun 2008 19:29:06 +0000 (19:29 +0000)
Original commit message from CVS:
* gst-libs/gst/tag/gstid3tag.c: (gst_tag_list_add_id3_image):
* gst-libs/gst/tag/tag.h: (GST_TAG_IMAGE_TYPE_NONE),
* gst-libs/gst/tag/tags.c: (register_tag_image_type_enum),
(gst_tag_image_type_get_type), (gst_tag_image_type_is_valid),
(gst_tag_image_data_to_image_buffer):
Add two utility functions to avoid code duplication (#512333):
API: add gst_tag_image_data_to_image_buffer()
API: add gst_tag_list_add_id3_image()

ChangeLog
gst-libs/gst/tag/gstid3tag.c
gst-libs/gst/tag/tag.h
gst-libs/gst/tag/tags.c

index 0dcee28..ff89caa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2008-06-03  Tim-Philipp Müller  <tim.muller at collabora co uk>
+
+       * gst-libs/gst/tag/gstid3tag.c: (gst_tag_list_add_id3_image):
+       * gst-libs/gst/tag/tag.h: (GST_TAG_IMAGE_TYPE_NONE),
+       * gst-libs/gst/tag/tags.c: (register_tag_image_type_enum),
+         (gst_tag_image_type_get_type), (gst_tag_image_type_is_valid),
+         (gst_tag_image_data_to_image_buffer):
+         Add two utility functions to avoid code duplication (#512333):
+         API: add gst_tag_image_data_to_image_buffer()
+         API: add gst_tag_list_add_id3_image()
+
 2008-06-03  Sebastian Dröge  <slomo@circular-chaos.org>
 
        * win32/common/libgstaudio.def:
index b32b8fc..2ab433f 100644 (file)
@@ -428,3 +428,58 @@ gst_tag_id3_genre_get (const guint id)
     return NULL;
   return genres[id];
 }
+
+/**
+ * gst_tag_list_add_id3_image:
+ * @tag_list: a tag list
+ * @image_data: the (encoded) image
+ * @image_data_len: the length of the encoded image data at @image_data
+ * @id3_picture_type: picture type as per the ID3 (v2.4.0) specification for
+ *    the APIC frame (0 = unknown/other)
+ *
+ * Adds an image from an ID3 APIC frame (or similar, such as used in FLAC)
+ * to the given tag list. Also see gst_tag_image_data_to_image_buffer() for
+ * more information on image tags in GStreamer.
+ *
+ * Returns: %TRUE if the image was processed, otherwise %FALSE
+ *
+ * Since: 0.10.20
+ */
+gboolean
+gst_tag_list_add_id3_image (GstTagList * tag_list, const guint8 * image_data,
+    guint image_data_len, guint id3_picture_type)
+{
+  GstTagImageType tag_image_type;
+  const gchar *tag_name;
+  GstBuffer *image;
+
+  g_return_val_if_fail (GST_IS_TAG_LIST (tag_list), FALSE);
+  g_return_val_if_fail (image_data != NULL, FALSE);
+  g_return_val_if_fail (image_data_len > 0, FALSE);
+
+  if (id3_picture_type == 0x01 || id3_picture_type == 0x02) {
+    /* file icon for preview. Don't add image-type to caps, since there
+     * is only supposed to be one of these, and the type is already indicated
+     * via the special tag */
+    tag_name = GST_TAG_PREVIEW_IMAGE;
+    tag_image_type = GST_TAG_IMAGE_TYPE_NONE;
+  } else {
+    tag_name = GST_TAG_IMAGE;
+
+    /* Remap the ID3v2 APIC type our ImageType enum */
+    if (id3_picture_type >= 0x3 && id3_picture_type <= 0x14)
+      tag_image_type = (GstTagImageType) (id3_picture_type - 2);
+    else
+      tag_image_type = GST_TAG_IMAGE_TYPE_UNDEFINED;
+  }
+
+  image = gst_tag_image_data_to_image_buffer (image_data, image_data_len,
+      tag_image_type);
+
+  if (image == NULL)
+    return FALSE;
+
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, tag_name, image, NULL);
+  gst_buffer_unref (image);
+  return TRUE;
+}
index 48bc549..ec680d2 100644 (file)
@@ -126,6 +126,9 @@ G_BEGIN_DECLS
 
 /**
  * GstTagImageType:
+ * @GST_TAG_IMAGE_TYPE_NONE                  : No image type. Can be used to
+ *      tell functions such as gst_tag_image_data_to_image_buffer() that no
+ *      image type should be set. (Since: 0.10.20)
  * @GST_TAG_IMAGE_TYPE_UNDEFINED             : Undefined/other image type
  * @GST_TAG_IMAGE_TYPE_FRONT_COVER           : Cover (front)
  * @GST_TAG_IMAGE_TYPE_BACK_COVER            : Cover (back)
@@ -152,7 +155,8 @@ G_BEGIN_DECLS
  * Since: 0.10.9
  */
 typedef enum {
-  GST_TAG_IMAGE_TYPE_UNDEFINED,
+  GST_TAG_IMAGE_TYPE_NONE = -1,
+  GST_TAG_IMAGE_TYPE_UNDEFINED = 0,
   GST_TAG_IMAGE_TYPE_FRONT_COVER,
   GST_TAG_IMAGE_TYPE_BACK_COVER,
   GST_TAG_IMAGE_TYPE_LEAFLET_PAGE,
@@ -209,6 +213,11 @@ G_CONST_RETURN gchar *  gst_tag_from_id3_user_tag               (const gchar *
                                                                  const gchar *          id3_user_tag);
 G_CONST_RETURN gchar *  gst_tag_to_id3_tag                      (const gchar *          gst_tag);
 
+gboolean                gst_tag_list_add_id3_image (GstTagList   * tag_list,
+                                                    const guint8 * image_data,
+                                                    guint          image_data_len,
+                                                    guint          id3_picture_type);
+
 /* other tag-related functions */
 
 gboolean                gst_tag_parse_extended_comment (const gchar  * ext_comment,
@@ -221,6 +230,10 @@ gchar                 * gst_tag_freeform_string_to_utf8 (const gchar  * data,
                                                          gint           size,
                                                          const gchar ** env_vars);
 
+GstBuffer             * gst_tag_image_data_to_image_buffer (const guint8   * image_data,
+                                                            guint            image_data_len,
+                                                            GstTagImageType  image_type);
+
 /* FIXME 0.11: replace with a more general gst_tag_library_init() */
 void                    gst_tag_register_musicbrainz_tags (void);
 
index acd72ad..68aed1a 100644 (file)
@@ -1,6 +1,6 @@
 /* GStreamer non-core tag registration and tag utility functions
  * Copyright (C) 2005 Ross Burton <ross@burtonini.com>
- * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -23,6 +23,7 @@
 #endif
 
 #include <gst/gst-i18n-plugin.h>
+#include <gst/base/gsttypefindhelper.h>
 #include <gst/gst.h>
 #include "tag.h"
 
@@ -144,6 +145,9 @@ register_tag_image_type_enum (GType * id)
   };
 
   *id = g_enum_register_static ("GstTagImageType", image_types);
+
+  /* work around thread-safety issue with class creation in GLib */
+  g_type_class_ref (*id);
 }
 
 GType
@@ -156,6 +160,19 @@ gst_tag_image_type_get_type (void)
   return id;
 }
 
+static inline gboolean
+gst_tag_image_type_is_valid (GstTagImageType type)
+{
+  GEnumClass *klass;
+  gboolean res;
+
+  klass = g_type_class_ref (gst_tag_image_type_get_type ());
+  res = (g_enum_get_value (klass, type) != NULL);
+  g_type_class_unref (klass);
+
+  return res;
+}
+
 /**
  * gst_tag_parse_extended_comment:
  * @ext_comment: an extended comment string, see #GST_TAG_EXTENDED_COMMENT
@@ -326,3 +343,108 @@ beach:
   g_free (utf8);
   return NULL;
 }
+
+/**
+ * gst_tag_image_data_to_image_buffer:
+ * @image_data: the (encoded) image
+ * @image_data_len: the length of the encoded image data at @image_data
+ * @image_type: type of the image, or #GST_TAG_IMAGE_TYPE_UNDEFINED. Pass
+ *     #GST_TAG_IMAGE_TYPE_NONE if no image type should be set at all (e.g.
+ *     for preview images)
+ *
+ * Helper function for tag-reading plugins to create a #GstBuffer suitable to
+ * add to a #GstTagList as an image tag (such as #GST_TAG_IMAGE or
+ * #GST_TAG_PREVIEW_IMAGE) from the encoded image data and an (optional) image
+ * type.
+ *
+ * Background: cover art and other images in tags are usually stored as a
+ * blob of binary image data, often accompanied by a MIME type or some other
+ * content type string (e.g. 'png', 'jpeg', 'jpg'). Sometimes there is also an
+ * 'image type' to indicate what kind of image this is (e.g. front cover,
+ * back cover, artist, etc.). The image data may also be an URI to the image
+ * rather than the image itself.
+ *
+ * In GStreamer, image tags are #GstBuffer<!-- -->s containing the raw image
+ * data, with the buffer caps describing the content type of the image
+ * (e.g. image/jpeg, image/png, text/uri-list). The buffer caps may contain
+ * an additional 'image-type' field of #GST_TYPE_TAG_IMAGE_TYPE to describe
+ * the type of image (front cover, back cover etc.). #GST_TAG_PREVIEW_IMAGE
+ * tags should not carry an image type, their type is already indicated via
+ * the special tag name.
+ *
+ * This function will do various checks and typefind the encoded image
+ * data (we can't trust the declared mime type).
+ *
+ * Returns: a newly-allocated image buffer for use in tag lists, or NULL
+ *
+ * Since: 0.10.20
+ */
+GstBuffer *
+gst_tag_image_data_to_image_buffer (const guint8 * image_data,
+    guint image_data_len, GstTagImageType image_type)
+{
+  const gchar *name;
+  GstBuffer *image;
+  GstCaps *caps;
+
+  g_return_val_if_fail (image_data != NULL, NULL);
+  g_return_val_if_fail (image_data_len > 0, NULL);
+  g_return_val_if_fail (gst_tag_image_type_is_valid (image_type), NULL);
+
+  GST_DEBUG ("image data len: %u bytes", image_data_len);
+
+  /* allocate space for a NUL terminator for an uri too */
+  image = gst_buffer_try_new_and_alloc (image_data_len + 1);
+  if (image == NULL) {
+    GST_WARNING ("failed to allocate buffer of %d for image", image_data_len);
+    return NULL;
+  }
+
+  memcpy (GST_BUFFER_DATA (image), image_data, image_data_len);
+  GST_BUFFER_DATA (image)[image_data_len] = '\0';
+  GST_BUFFER_SIZE (image) = image_data_len;
+
+  /* Find GStreamer media type, can't trust declared type */
+  caps = gst_type_find_helper_for_buffer (NULL, image, NULL);
+
+  if (caps == NULL)
+    goto no_type;
+
+  GST_DEBUG ("Found GStreamer media type: %" GST_PTR_FORMAT, caps);
+
+  /* sanity check: make sure typefound/declared caps are either URI or image */
+  name = gst_structure_get_name (gst_caps_get_structure (caps, 0));
+
+  if (!g_str_has_prefix (name, "image/") &&
+      !g_str_has_prefix (name, "video/") &&
+      !g_str_equal (name, "text/uri-list")) {
+    GST_DEBUG ("Unexpected image type '%s', ignoring image frame", name);
+    goto error;
+  }
+
+  if (image_type != GST_TAG_IMAGE_TYPE_NONE) {
+    GST_LOG ("Setting image type: %d", image_type);
+    caps = gst_caps_make_writable (caps);
+    gst_caps_set_simple (caps, "image-type", GST_TYPE_TAG_IMAGE_TYPE,
+        image_type, NULL);
+  }
+
+  gst_buffer_set_caps (image, caps);
+  gst_caps_unref (caps);
+  return image;
+
+/* ERRORS */
+no_type:
+  {
+    GST_DEBUG ("Could not determine GStreamer media type, ignoring image");
+    /* fall through */
+  }
+error:
+  {
+    if (image)
+      gst_buffer_unref (image);
+    if (caps)
+      gst_caps_unref (caps);
+    return NULL;
+  }
+}