EXPORT_C #endif GstTagList * gst_tag_list_merge (const GstTagList * list1, const GstTagList * list2, GstTagMergeMode mode) { g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL); g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL); g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL); if (!list1 && !list2) { return NULL; } else if (!list1) { return gst_tag_list_copy (list2); } else if (!list2) { return gst_tag_list_copy (list1); } else { GstTagList *ret; ret = gst_tag_list_copy (list1); gst_tag_list_insert (ret, list2, mode); return ret; } }
/** * gst_toc_entry_copy: * @entry: #GstTocEntry to copy. * * Copy #GstTocEntry with all subentries (deep copy). * * Returns: newly allocated #GstTocEntry in case of success, NULL otherwise; * free it when done with gst_toc_entry_unref(). */ static GstTocEntry * gst_toc_entry_copy (const GstTocEntry * entry) { GstTocEntry *ret, *sub; GstTagList *list; GList *cur; g_return_val_if_fail (entry != NULL, NULL); ret = gst_toc_entry_new (entry->type, entry->uid); ret->start = entry->start; ret->stop = entry->stop; if (GST_IS_TAG_LIST (entry->tags)) { list = gst_tag_list_copy (entry->tags); if (ret->tags) gst_tag_list_unref (ret->tags); ret->tags = list; } cur = entry->subentries; while (cur != NULL) { sub = gst_toc_entry_copy (cur->data); if (sub != NULL) ret->subentries = g_list_prepend (ret->subentries, sub); cur = cur->next; } ret->subentries = g_list_reverse (ret->subentries); return ret; }
/** * gst_toc_copy: * @toc: #GstToc to copy. * * Copy #GstToc with all subentries (deep copy). * * Returns: newly allocated #GstToc in case of success, NULL otherwise; * free it when done with gst_toc_unref(). */ static GstToc * gst_toc_copy (const GstToc * toc) { GstToc *ret; GstTocEntry *entry; GList *cur; GstTagList *list; g_return_val_if_fail (toc != NULL, NULL); ret = gst_toc_new (toc->scope); if (GST_IS_TAG_LIST (toc->tags)) { list = gst_tag_list_copy (toc->tags); gst_tag_list_unref (ret->tags); ret->tags = list; } cur = toc->entries; while (cur != NULL) { entry = gst_toc_entry_copy (cur->data); if (entry != NULL) ret->entries = g_list_prepend (ret->entries, entry); cur = cur->next; } ret->entries = g_list_reverse (ret->entries); return ret; }
EXPORT_C #endif gboolean gst_tag_list_copy_value (GValue * dest, const GstTagList * list, const gchar * tag) { const GValue *src; g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); g_return_val_if_fail (tag != NULL, FALSE); g_return_val_if_fail (dest != NULL, FALSE); g_return_val_if_fail (G_VALUE_TYPE (dest) == 0, FALSE); src = gst_structure_get_value ((GstStructure *) list, tag); if (!src) return FALSE; if (G_VALUE_TYPE (src) == GST_TYPE_LIST) { GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag)); /* must be there or lists aren't allowed */ g_assert (info->merge_func); info->merge_func (dest, src); } else { g_value_init (dest, G_VALUE_TYPE (src)); g_value_copy (src, dest); } return TRUE; }
EXPORT_C #endif G_CONST_RETURN GValue * gst_tag_list_get_value_index (const GstTagList * list, const gchar * tag, guint index) { const GValue *value; g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL); g_return_val_if_fail (tag != NULL, NULL); value = gst_structure_get_value ((GstStructure *) list, tag); if (value == NULL) return NULL; if (GST_VALUE_HOLDS_LIST (value)) { if (index >= gst_value_list_get_size (value)) return NULL; return gst_value_list_get_value (value, index); } else { if (index > 0) return NULL; return value; } }
/** * 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; }
EXPORT_C #endif void gst_tag_list_free (GstTagList * list) { g_return_if_fail (GST_IS_TAG_LIST (list)); gst_structure_free ((GstStructure *) list); }
EXPORT_C #endif GstTagList * gst_tag_list_copy (const GstTagList * list) { g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL); return GST_TAG_LIST (gst_structure_copy ((GstStructure *) list)); }
EXPORT_C #endif gboolean gst_tag_list_is_empty (const GstTagList * list) { g_return_val_if_fail (list != NULL, FALSE); g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); return (gst_structure_n_fields ((GstStructure *) list) == 0); }
/** * gst_tag_list_to_xmp_buffer: * @list: tags * @read_only: does the container forbid inplace editing * * Formats a taglist as a xmp packet. * * Returns: new buffer or %NULL, unref the buffer when done * * Since: 0.10.29 */ GstBuffer * gst_tag_list_to_xmp_buffer (const GstTagList * list, gboolean read_only) { GstBuffer *buffer = NULL; GString *data = g_string_sized_new (4096); guint i; xmp_tags_initialize (); g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL); /* xmp header */ g_string_append (data, "<?xpacket begin=\"\xEF\xBB\xBF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"); g_string_append (data, "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"GStreamer\">\n"); g_string_append (data, "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\""); i = 0; while (ns_match[i].ns_prefix) { g_string_append_printf (data, " xmlns:%s=\"%s\"", ns_match[i].ns_prefix, ns_match[i].ns_uri); i++; } g_string_append (data, ">\n"); g_string_append (data, "<rdf:Description rdf:about=\"\">\n"); /* iterate the taglist */ gst_tag_list_foreach (list, write_one_tag, data); /* xmp footer */ g_string_append (data, "</rdf:Description>\n"); g_string_append (data, "</rdf:RDF>\n"); g_string_append (data, "</x:xmpmeta>\n"); if (!read_only) { /* the xmp spec recommand to add 2-4KB padding for in-place editable xmp */ guint i; for (i = 0; i < 32; i++) { g_string_append (data, " " " " " " " " "\n"); } } g_string_append_printf (data, "<?xpacket end=\"%c\"?>\n", (read_only ? 'r' : 'w')); buffer = gst_buffer_new (); GST_BUFFER_SIZE (buffer) = data->len + 1; GST_BUFFER_DATA (buffer) = (guint8 *) g_string_free (data, FALSE); GST_BUFFER_MALLOCDATA (buffer) = GST_BUFFER_DATA (buffer); return buffer; }
EXPORT_C #endif void gst_tag_list_remove_tag (GstTagList * list, const gchar * tag) { g_return_if_fail (GST_IS_TAG_LIST (list)); g_return_if_fail (tag != NULL); gst_structure_remove_field ((GstStructure *) list, tag); }
EXPORT_C #endif void gst_tag_list_insert (GstTagList * into, const GstTagList * from, GstTagMergeMode mode) { GstTagCopyData data; g_return_if_fail (GST_IS_TAG_LIST (into)); g_return_if_fail (GST_IS_TAG_LIST (from)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); data.list = (GstStructure *) into; data.mode = mode; if (mode == GST_TAG_MERGE_REPLACE_ALL) { gst_structure_remove_all_fields (data.list); } gst_structure_foreach ((GstStructure *) from, gst_tag_list_copy_foreach, &data); }
EXPORT_C #endif void gst_tag_list_add_values (GstTagList * list, GstTagMergeMode mode, const gchar * tag, ...) { va_list args; g_return_if_fail (GST_IS_TAG_LIST (list)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (tag != NULL); va_start (args, tag); gst_tag_list_add_valist_values (list, mode, tag, args); va_end (args); }
static gboolean bbd_pipeline_bus_callback (GstBus *bus, GstMessage *message, gpointer data) { BansheeBpmDetector *detector = (BansheeBpmDetector *)data; g_return_val_if_fail (detector != NULL, FALSE); switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_TAG: { GstTagList *tags; gst_message_parse_tag (message, &tags); if (GST_IS_TAG_LIST (tags)) { gst_tag_list_foreach (tags, (GstTagForeachFunc)bbd_pipeline_process_tag, detector); gst_tag_list_free (tags); } break; } case GST_MESSAGE_ERROR: { GError *error; gchar *debug; gst_message_parse_error (message, &error, &debug); bbd_raise_error (detector, error->message, debug); g_error_free (error); g_free (debug); detector->is_detecting = FALSE; break; } case GST_MESSAGE_EOS: { detector->is_detecting = FALSE; gst_element_set_state (GST_ELEMENT (detector->pipeline), GST_STATE_NULL); if (detector->finished_cb != NULL) { detector->finished_cb (); } break; } default: break; } return TRUE; }
/** * gst_tag_setter_merge_tags: * @setter: a #GstTagSetter * @list: a tag list to merge from * @mode: the mode to merge with * * Merges the given list into the setter's list using the given mode. */ void gst_tag_setter_merge_tags (GstTagSetter * setter, const GstTagList * list, GstTagMergeMode mode) { GstTagData *data; g_return_if_fail (GST_IS_TAG_SETTER (setter)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (GST_IS_TAG_LIST (list)); data = gst_tag_setter_get_data (setter); if (data->list == NULL) { if (mode != GST_TAG_MERGE_KEEP_ALL) data->list = gst_tag_list_copy (list); } else { gst_tag_list_insert (data->list, list, mode); } }
EXPORT_C #endif void gst_tag_list_foreach (const GstTagList * list, GstTagForeachFunc func, gpointer user_data) { TagForeachData data; g_return_if_fail (GST_IS_TAG_LIST (list)); g_return_if_fail (func != NULL); data.func = func; data.tag_list = list; data.data = user_data; gst_structure_foreach ((GstStructure *) list, structure_foreach_wrapper, &data); }
EXPORT_C #endif guint gst_tag_list_get_tag_size (const GstTagList * list, const gchar * tag) { const GValue *value; g_return_val_if_fail (GST_IS_TAG_LIST (list), 0); value = gst_structure_get_value ((GstStructure *) list, tag); if (value == NULL) return 0; if (G_VALUE_TYPE (value) != GST_TYPE_LIST) return 1; return gst_value_list_get_size (value); }
EXPORT_C #endif gboolean gst_tag_list_get_date_index (const GstTagList * list, const gchar * tag, guint index, GDate ** value) { const GValue *v; g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); g_return_val_if_fail (tag != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL) return FALSE; *value = (GDate *) g_value_dup_boxed (v); return (*value != NULL); }
EXPORT_C #endif gboolean gst_tag_list_get_date (const GstTagList * list, const gchar * tag, GDate ** value) { GValue v = { 0, }; g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); g_return_val_if_fail (tag != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); if (!gst_tag_list_copy_value (&v, list, tag)) return FALSE; *value = (GDate *) g_value_dup_boxed (&v); g_value_unset (&v); return (*value != NULL); }
/** * gst_aggregator_merge_tags: * @self: a #GstAggregator * @tags: a #GstTagList to merge * @mode: the #GstTagMergeMode to use * * Adds tags to so-called pending tags, which will be processed * before pushing out data downstream. * * Note that this is provided for convenience, and the subclass is * not required to use this and can still do tag handling on its own. * * MT safe. */ void gst_aggregator_merge_tags (GstAggregator * self, const GstTagList * tags, GstTagMergeMode mode) { GstTagList *otags; g_return_if_fail (GST_IS_AGGREGATOR (self)); g_return_if_fail (tags == NULL || GST_IS_TAG_LIST (tags)); /* FIXME Check if we can use OBJECT lock here! */ GST_OBJECT_LOCK (self); if (tags) GST_DEBUG_OBJECT (self, "merging tags %" GST_PTR_FORMAT, tags); otags = self->priv->tags; self->priv->tags = gst_tag_list_merge (self->priv->tags, tags, mode); if (otags) gst_tag_list_unref (otags); self->priv->tags_changed = TRUE; GST_OBJECT_UNLOCK (self); }
EXPORT_C #endif 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; }
/** * 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; }
EXPORT_C #endif void gst_tag_list_add_valist (GstTagList * list, GstTagMergeMode mode, const gchar * tag, va_list var_args) { GstTagInfo *info; GQuark quark; gchar *error = NULL; g_return_if_fail (GST_IS_TAG_LIST (list)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (tag != NULL); while (tag != NULL) { GValue value = { 0, }; quark = g_quark_from_string (tag); info = gst_tag_lookup (quark); if (info == NULL) g_warning ("no GstTag for %s", tag); g_return_if_fail (info != NULL); g_value_init (&value, info->type); G_VALUE_COLLECT (&value, var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); g_free (error); /* we purposely leak the value here, it might not be * in a sane state if an error condition occoured */ return; } gst_tag_list_add_value_internal (list, mode, quark, &value); g_value_unset (&value); tag = va_arg (var_args, gchar *); } }
EXPORT_C #endif void gst_tag_list_add_valist_values (GstTagList * list, GstTagMergeMode mode, const gchar * tag, va_list var_args) { GstTagInfo *info; GQuark quark; g_return_if_fail (GST_IS_TAG_LIST (list)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (tag != NULL); while (tag != NULL) { quark = g_quark_from_string (tag); info = gst_tag_lookup (quark); g_return_if_fail (info != NULL); gst_tag_list_add_value_internal (list, mode, quark, va_arg (var_args, GValue *)); tag = va_arg (var_args, gchar *); } }