static void
set_shout_metadata (const GstTagList * list, const gchar * tag,
    gpointer user_data)
{
  GstShout2send *shout2send = (GstShout2send *) user_data;
  char **shout_metadata = &(shout2send->songmetadata);
  char **song_artist = &(shout2send->songartist);
  char **song_title = &(shout2send->songtitle);

  gchar *value;

  GST_DEBUG ("tag: %s being added", tag);
  if (strcmp (tag, GST_TAG_ARTIST) == 0) {
    if (gst_tag_get_type (tag) == G_TYPE_STRING) {
      if (!gst_tag_list_get_string (list, tag, &value)) {
        GST_DEBUG ("Error reading \"%s\" tag value", tag);
        return;
      }

      if (*song_artist != NULL)
        g_free (*song_artist);

      *song_artist = g_strdup (value);
    }
  } else if (strcmp (tag, GST_TAG_TITLE) == 0) {
    if (gst_tag_get_type (tag) == G_TYPE_STRING) {
      if (!gst_tag_list_get_string (list, tag, &value)) {
        GST_DEBUG ("Error reading \"%s\" tag value", tag);
        return;
      }

      if (*song_title != NULL)
        g_free (*song_title);

      *song_title = g_strdup (value);
    }
  }

  if (*shout_metadata != NULL)
    g_free (*shout_metadata);


  if (*song_title && *song_artist) {
    *shout_metadata = g_strdup_printf ("%s - %s", *song_artist, *song_title);
  } else if (*song_title && *song_artist == NULL) {
    *shout_metadata = g_strdup_printf ("Unknown - %s", *song_title);
  } else if (*song_title == NULL && *song_artist) {
    *shout_metadata = g_strdup_printf ("%s - Unknown", *song_artist);
  } else {
    *shout_metadata = g_strdup_printf ("Unknown - Unknown");
  }

  GST_LOG ("shout metadata is now: %s", *shout_metadata);
}
Example #2
0
/*
 * lomo_tag_get_gtype:
 * @tag: (in) (transfer none): a #LomoTag
 *
 * Queries for the #GType corresponding for the tag
 *
 * Returns: the #GType for tag
 */
GType
lomo_tag_get_gtype(const gchar *tag)
{
	if (g_str_equal(tag, "uri"))
		return G_TYPE_STRING;
	return gst_tag_get_type(tag);
}
/**
 * gst_pb_utils_add_codec_description_to_tag_list:
 * @taglist: a #GstTagList
 * @codec_tag: a GStreamer codec tag such as #GST_TAG_AUDIO_CODEC,
 *             #GST_TAG_VIDEO_CODEC or #GST_TAG_CODEC
 * @caps: the (fixed) #GstCaps for which a codec tag should be added.
 *
 * Adds a codec tag describing the format specified by @caps to @taglist.
 *
 * Returns: TRUE if a codec tag was added, FALSE otherwise.
 */
gboolean
gst_pb_utils_add_codec_description_to_tag_list (GstTagList * taglist,
    const gchar * codec_tag, const GstCaps * caps)
{
  const FormatInfo *info;
  gchar *desc;

  g_return_val_if_fail (taglist != NULL, FALSE);
  g_return_val_if_fail (GST_IS_TAG_LIST (taglist), FALSE);
  g_return_val_if_fail (codec_tag != NULL, FALSE);
  g_return_val_if_fail (gst_tag_exists (codec_tag), FALSE);
  g_return_val_if_fail (gst_tag_get_type (codec_tag) == G_TYPE_STRING, FALSE);
  g_return_val_if_fail (caps != NULL, FALSE);
  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);

  info = find_format_info (caps);
  if (info == NULL)
    return FALSE;

  desc = format_info_get_desc (info, caps);
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, codec_tag, desc, NULL);
  g_free (desc);

  return TRUE;
}
Example #4
0
static void
read_one_tag (GstTagList * list, const gchar * tag, XmpTag * xmptag,
    const gchar * v, GSList ** pending_tags)
{
  GType tag_type;

  if (xmptag && xmptag->deserialize) {
    xmptag->deserialize (list, tag, xmptag->tag_name, v, pending_tags);
    return;
  }

  tag_type = gst_tag_get_type (tag);

  /* add gstreamer tag depending on type */
  switch (tag_type) {
    case G_TYPE_STRING:{
      gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, tag, v, NULL);
      break;
    }
    default:
      if (tag_type == GST_TYPE_DATE) {
        GDate *date;
        gint d, m, y;

        /* this is ISO 8601 Date and Time Format
         * %F     Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99)
         * %T     The time in 24-hour notation (%H:%M:%S). (SU)
         * e.g. 2009-05-30T18:26:14+03:00 */

        /* FIXME: this would be the proper way, but needs
           #define _XOPEN_SOURCE before #include <time.h>

           date = g_date_new ();
           struct tm tm={0,};
           strptime (dts, "%FT%TZ", &tm);
           g_date_set_time_t (date, mktime(&tm));
         */
        /* FIXME: this cannot parse the date
           date = g_date_new ();
           g_date_set_parse (date, v);
           if (g_date_valid (date)) {
           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, tag,
           date, NULL);
           } else {
           GST_WARNING ("unparsable date: '%s'", v);
           }
         */
        /* poor mans straw */
        sscanf (v, "%04d-%02d-%02dT", &y, &m, &d);
        date = g_date_new_dmy (d, m, y);
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
        g_date_free (date);
      } else {
        GST_WARNING ("unhandled type for %s from xmp", tag);
      }
      break;
  }
}
Example #5
0
static void
print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
{
  gint i, count;

  count = gst_tag_list_get_tag_size (list, tag);

  for (i = 0; i < count; i++) {
    gchar *str;

    if (gst_tag_get_type (tag) == G_TYPE_STRING) {
      if (!gst_tag_list_get_string_index (list, tag, i, &str))
        g_assert_not_reached ();
    } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) {
      GstBuffer *img;

      img = gst_value_get_buffer (gst_tag_list_get_value_index (list, tag, i));
      if (img) {
        gchar *caps_str;

        caps_str = GST_BUFFER_CAPS (img) ?
            gst_caps_to_string (GST_BUFFER_CAPS (img)) : g_strdup ("unknown");
        str = g_strdup_printf ("buffer of %u bytes, type: %s",
            GST_BUFFER_SIZE (img), caps_str);
        g_free (caps_str);
      } else {
        str = g_strdup ("NULL buffer");
      }
    } else {
      str =
          g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
    }

    if (i == 0) {
      g_print ("%16s: %s\n", gst_tag_get_nick (tag), str);
    } else {
      g_print ("%16s: %s\n", "", str);
    }

    g_free (str);
  }
}
Example #6
0
static const gchar *
metadataparse_exif_get_tag_from_exif (ExifTag exif, GType * type)
{
  int i = 0;

  while (mappedTags[i].exif) {
    if (exif == mappedTags[i].exif) {
      *type = gst_tag_get_type (mappedTags[i].str);
      break;
    }
    ++i;
  }

  return mappedTags[i].str;

}
Example #7
0
static ExifTag
metadatamux_exif_get_exif_from_tag (const gchar * tag, GType * type,
    ExifIfd * ifd)
{
  int i = 0;

  while (mappedTags[i].exif) {
    if (0 == strcmp (mappedTags[i].str, tag)) {
      *type = gst_tag_get_type (tag);
      *ifd = mappedTags[i].ifd;
      break;
    }
    ++i;
  }

  return mappedTags[i].exif;

}
static gboolean
ape_demux_get_gst_tag_from_tag (const gchar * ape_tag,
    const gchar ** gst_tag, GType * gst_tag_type)
{
  gint i;

  for (i = 0; i < G_N_ELEMENTS (tag_table); ++i) {
    if (g_ascii_strcasecmp (tag_table[i].ape_tag, ape_tag) == 0) {
      *gst_tag = tag_table[i].gst_tag;
      *gst_tag_type = gst_tag_get_type (tag_table[i].gst_tag);
      GST_LOG ("Mapped APE tag '%s' to GStreamer tag '%s'", ape_tag, *gst_tag);
      return TRUE;
    }
  }

  GST_WARNING ("Could not map APE tag '%s' to a GStreamer tag", ape_tag);
  return FALSE;
}
Example #9
0
void handleGstTag(const GstTagList * list, const gchar * tag, void * user_data_track){
    gchar * val;
    QString qs_val;
    Track * track = (Track*)user_data_track;

    if( G_TYPE_STRING == gst_tag_get_type(tag) ){
        gst_tag_list_get_string(list,tag,&val);
        //QLOG_TRACE() << " --TAG-- " << tag << " => " << val;

        qs_val = QString(val);
        if( 0 == QString::compare(QString(GST_TAG_ARTIST),QString(tag))){
//            QLOG_TRACE() << "It's an artist";
            track->setArtist(&qs_val);
        }else if (0 == QString::compare(QString(GST_TAG_TITLE),QString(tag))){
//            QLOG_TRACE() << "It's a title";
           track->setTitle(&qs_val);
        }


    }
}
/**
 * gst_pb_utils_add_codec_description_to_tag_list:
 * @taglist: a #GstTagList
 * @codec_tag: (allow-none): a GStreamer codec tag such as #GST_TAG_AUDIO_CODEC,
 *             #GST_TAG_VIDEO_CODEC or #GST_TAG_CODEC. If none is specified,
 *             the function will attempt to detect the appropriate category.
 * @caps: the (fixed) #GstCaps for which a codec tag should be added.
 *
 * Adds a codec tag describing the format specified by @caps to @taglist.
 *
 * Returns: TRUE if a codec tag was added, FALSE otherwise.
 */
gboolean
gst_pb_utils_add_codec_description_to_tag_list (GstTagList * taglist,
    const gchar * codec_tag, const GstCaps * caps)
{
  const FormatInfo *info;
  gchar *desc;

  g_return_val_if_fail (taglist != NULL, FALSE);
  g_return_val_if_fail (GST_IS_TAG_LIST (taglist), FALSE);
  g_return_val_if_fail (codec_tag == NULL || (gst_tag_exists (codec_tag)
          && gst_tag_get_type (codec_tag) == G_TYPE_STRING), FALSE);
  g_return_val_if_fail (caps != NULL, FALSE);
  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);

  info = find_format_info (caps);
  if (info == NULL)
    return FALSE;

  /* Attempt to find tag classification */
  if (codec_tag == NULL) {
    if (info->flags & FLAG_CONTAINER)
      codec_tag = GST_TAG_CONTAINER_FORMAT;
    else if (info->flags & FLAG_AUDIO)
      codec_tag = GST_TAG_AUDIO_CODEC;
    else if (info->flags & FLAG_VIDEO)
      codec_tag = GST_TAG_VIDEO_CODEC;
    else if (info->flags & FLAG_SUB)
      codec_tag = GST_TAG_SUBTITLE_CODEC;
    else
      codec_tag = GST_TAG_CODEC;
  }

  desc = format_info_get_desc (info, caps);
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, codec_tag, desc, NULL);
  g_free (desc);

  return TRUE;
}
Example #11
0
/* outputs the cmml head element and send TITLE and CMML_HEAD tags.
 * This callback is registered with dec->parser. It is called when the
 * head element is parsed.
 */
static void
gst_cmml_dec_parse_head (GstCmmlDec * dec, GstCmmlTagHead * head)
{
  GstTagList *tags;
  GValue str_val = { 0 }, title_val = {
  0};
  guchar *head_str;
  GstBuffer *buffer;

  GST_DEBUG_OBJECT (dec, "found CMML head (title: %s base: %s)",
      head->title, head->base);

  /* create the GST_TAG_TITLE tag */
  g_value_init (&str_val, G_TYPE_STRING);
  g_value_init (&title_val, gst_tag_get_type (GST_TAG_TITLE));
  g_value_set_string (&str_val, (gchar *) head->title);
  g_value_transform (&str_val, &title_val);

  tags = gst_tag_list_new ();
  gst_tag_list_add_values (tags, GST_TAG_MERGE_APPEND,
      GST_TAG_TITLE, &title_val, NULL);
  gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_CMML_HEAD, head, NULL);
  gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, tags);

  g_value_unset (&str_val);
  g_value_unset (&title_val);

  head_str = gst_cmml_parser_tag_head_to_string (dec->parser, head);

  dec->flow_return = gst_cmml_dec_new_buffer (dec,
      head_str, strlen ((gchar *) head_str), &buffer);
  g_free (head_str);
  if (dec->flow_return == GST_FLOW_OK)
    dec->flow_return = gst_pad_push (dec->srcpad, buffer);
  if (dec->flow_return == GST_FLOW_NOT_LINKED)
    dec->flow_return = GST_FLOW_OK;     /* Ignore NOT_LINKED */
}
static void
send_tag (const GstTagList * list, const gchar * tag, gpointer data)
{
  InsanityGstPipelineTest *ptest = INSANITY_GST_PIPELINE_TEST (data);
  gint i, count;
  GValue string_value = { 0 };
  char label[48];

  count = gst_tag_list_get_tag_size (list, tag);
  g_value_init (&string_value, G_TYPE_STRING);

  ptest->priv->tag_count++;

  for (i = 0; i < count; i++) {
    gchar *str;

    if (gst_tag_get_type (tag) == G_TYPE_STRING) {
      if (!gst_tag_list_get_string_index (list, tag, i, &str))
        g_assert_not_reached ();
    } else if (gst_tag_get_type (tag) == GST_TYPE_SAMPLE) {
      GstSample *img;

      img = gst_value_get_sample (gst_tag_list_get_value_index (list, tag, i));
      if (img) {
        GstBuffer *buffer;
        GstCaps *caps;
        gchar *caps_str;

        buffer = gst_sample_get_buffer (img);
        caps = gst_sample_get_caps (img);

        caps_str = caps ? gst_caps_to_string (caps) : g_strdup ("unknown");
        str = g_strdup_printf ("sample of %" G_GSIZE_FORMAT " bytes, type: %s",
            gst_buffer_get_size (buffer), caps_str);
        g_free (caps_str);
      } else {
        str = g_strdup ("NULL sample");
      }
    } else if (gst_tag_get_type (tag) == GST_TYPE_DATE_TIME) {
      GstDateTime *dt = NULL;

      gst_tag_list_get_date_time_index (list, tag, i, &dt);
      str = gst_date_time_to_iso8601_string (dt);
      gst_date_time_unref (dt);
    } else {
      str =
          g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
    }

    if (i == 0) {
      g_value_set_string (&string_value, gst_tag_get_nick (tag));
      snprintf (label, sizeof (label), "tags.%u.id", ptest->priv->tag_count);
      insanity_test_set_extra_info (INSANITY_TEST (ptest), label,
          &string_value);
      g_value_reset (&string_value);
    }
    g_value_set_string (&string_value, str);
    if (count > 1)
      snprintf (label, sizeof (label), "tags.%u.value.%u",
          ptest->priv->tag_count, i);
    else
      snprintf (label, sizeof (label), "tags.%u.value", ptest->priv->tag_count);
    insanity_test_set_extra_info (INSANITY_TEST (ptest), label, &string_value);
    g_value_reset (&string_value);

    g_free (str);
  }
}
Example #13
0
static void
add_metadata_from_tag (GFileInfo         *info,
		       const GstTagList  *list,
		       const char        *tag,
		       const char        *tag_key)
{
	GType tag_type;

	tag_type = gst_tag_get_type (tag);

	if (tag_type == G_TYPE_BOOLEAN) {
		gboolean ret;
		if (gst_tag_list_get_boolean (list, tag, &ret)) {
			if (ret)
				add_metadata (info, tag_key, g_strdup ("TRUE"), NULL);
			else
				add_metadata (info, tag_key, g_strdup ("FALSE"), NULL);
		}
	}

	if (tag_type == G_TYPE_STRING) {
		char *ret = NULL;
		if (gst_tag_list_get_string (list, tag, &ret))
			add_metadata (info, tag_key, ret, NULL);
	}

        if (tag_type == G_TYPE_UCHAR) {
                guint ret = 0;
                if (gst_tag_list_get_uint (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%u", ret), NULL);
        }

        if (tag_type == G_TYPE_CHAR) {
                int ret = 0;
                if (gst_tag_list_get_int (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%d", ret), NULL);
        }

        if (tag_type == G_TYPE_UINT) {
                guint ret = 0;
                if (gst_tag_list_get_uint (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%u", ret), NULL);
        }

        if (tag_type == G_TYPE_INT) {
                gint ret = 0;
                if (gst_tag_list_get_int (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%d", ret), NULL);
        }

        if (tag_type == G_TYPE_ULONG) {
                guint64 ret = 0;
                if (gst_tag_list_get_uint64 (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%" G_GUINT64_FORMAT, ret), NULL);
        }

        if (tag_type == G_TYPE_LONG) {
                gint64 ret = 0;
                if (gst_tag_list_get_int64 (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%" G_GINT64_FORMAT, ret), NULL);
        }

        if (tag_type == G_TYPE_INT64) {
                gint64 ret = 0;
                if (gst_tag_list_get_int64 (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%" G_GINT64_FORMAT, ret), NULL);
        }

        if (tag_type == G_TYPE_UINT64) {
                guint64 ret = 0;
                if (gst_tag_list_get_uint64 (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%" G_GUINT64_FORMAT, ret), NULL);
        }

        if (tag_type == G_TYPE_DOUBLE) {
                gdouble ret = 0;
                if (gst_tag_list_get_double (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%f", ret), NULL);
        }

        if (tag_type == G_TYPE_FLOAT) {
                gfloat ret = 0;
                if (gst_tag_list_get_float (list, tag, &ret))
                        add_metadata (info, tag_key, g_strdup_printf ("%f", ret), NULL);
        }

        if (tag_type == G_TYPE_DATE) {
                GDate *ret = NULL;
                if (gst_tag_list_get_date (list, tag, &ret)) {
			if (ret != NULL) {
				char  buf[128];
				char *raw;
				char *formatted;

				g_date_strftime (buf, 10, "%F %T", ret);
				raw = g_strdup (buf);

				g_date_strftime (buf, 10, "%x %X", ret);
				formatted = g_strdup (buf);
				add_metadata (info, tag_key, raw, formatted);
			}
			g_free (ret);
		}
        }
}
Example #14
0
/**
 * gst_riff_parse_info:
 * @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 stream metadata from input data.
 */
void
gst_riff_parse_info (GstElement * element,
    GstBuffer * buf, GstTagList ** _taglist)
{
  guint8 *data;
  guint size, tsize;
  guint32 tag;
  const gchar *type;
  GstTagList *taglist;

  g_return_if_fail (_taglist != NULL);

  if (!buf) {
    *_taglist = NULL;
    return;
  }
  data = GST_BUFFER_DATA (buf);
  size = GST_BUFFER_SIZE (buf);
  taglist = gst_tag_list_new ();

  while (size > 8) {
    tag = GST_READ_UINT32_LE (data);
    tsize = GST_READ_UINT32_LE (data + 4);

    GST_MEMDUMP_OBJECT (element, "tag chunk", data, MIN (tsize + 8, size));

    size -= 8;
    data += 8;

    GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u",
        GST_FOURCC_ARGS (tag), tsize);

    if (tsize > size) {
      GST_WARNING_OBJECT (element,
          "Tagsize %d is larger than available data %d", tsize, size);
      tsize = size;
    }

    /* 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;
      case GST_RIFF_INFO_ICMS:
        type = NULL;            /*"Commissioner"; */
        break;
      case GST_RIFF_INFO_ICMT:
        type = GST_TAG_COMMENT;
        break;
      case GST_RIFF_INFO_ICOP:
        type = GST_TAG_COPYRIGHT;
        break;
      case GST_RIFF_INFO_ICRD:
        type = GST_TAG_DATE;
        break;
      case GST_RIFF_INFO_ICRP:
        type = NULL;            /*"Cropped"; */
        break;
      case GST_RIFF_INFO_IDIM:
        type = NULL;            /*"Dimensions"; */
        break;
      case GST_RIFF_INFO_IDPI:
        type = NULL;            /*"Dots per Inch"; */
        break;
      case GST_RIFF_INFO_IENG:
        type = NULL;            /*"Engineer"; */
        break;
      case GST_RIFF_INFO_IGNR:
        type = GST_TAG_GENRE;
        break;
      case GST_RIFF_INFO_IKEY:
        type = GST_TAG_KEYWORDS;
        break;
      case GST_RIFF_INFO_ILGT:
        type = NULL;            /*"Lightness"; */
        break;
      case GST_RIFF_INFO_IMED:
        type = NULL;            /*"Medium"; */
        break;
      case GST_RIFF_INFO_INAM:
        type = GST_TAG_TITLE;
        break;
      case GST_RIFF_INFO_IPLT:
        type = NULL;            /*"Palette"; */
        break;
      case GST_RIFF_INFO_IPRD:
        type = GST_TAG_ALBUM;
        break;
      case GST_RIFF_INFO_ISBJ:
        type = GST_TAG_ALBUM_ARTIST;
        break;
      case GST_RIFF_INFO_ISFT:
        type = GST_TAG_ENCODER;
        break;
      case GST_RIFF_INFO_ISHP:
        type = NULL;            /*"Sharpness"; */
        break;
      case GST_RIFF_INFO_ISRC:
        type = GST_TAG_ISRC;
        break;
      case GST_RIFF_INFO_ISRF:
        type = NULL;            /*"Source Form"; */
        break;
      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,
            "Unknown INFO (metadata) tag entry %" GST_FOURCC_FORMAT,
            GST_FOURCC_ARGS (tag));
        break;
    }

    if (type != NULL && data[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 *) data, 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);
      }
    }

    if (tsize & 1) {
      tsize++;
      if (tsize > size)
        tsize = size;
    }

    data += tsize;
    size -= 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_free (taglist);
  }

  return;
}