| /* GStreamer |
| * (c) 2010, 2012 Alexander Saprykin <xelfium@gmail.com> |
| * |
| * gsttoc.c: GstToc initialization and parsing/creation |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * 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., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| /** |
| * SECTION:gsttoc |
| * @title: GstToc |
| * @short_description: Generic table of contents support |
| * @see_also: #GstStructure, #GstEvent, #GstMessage, #GstQuery |
| * |
| * #GstToc functions are used to create/free #GstToc and #GstTocEntry structures. |
| * Also they are used to convert #GstToc into #GstStructure and vice versa. |
| * |
| * #GstToc lets you to inform other elements in pipeline or application that playing |
| * source has some kind of table of contents (TOC). These may be chapters, editions, |
| * angles or other types. For example: DVD chapters, Matroska chapters or cue sheet |
| * TOC. Such TOC will be useful for applications to display instead of just a |
| * playlist. |
| * |
| * Using TOC is very easy. Firstly, create #GstToc structure which represents root |
| * contents of the source. You can also attach TOC-specific tags to it. Then fill |
| * it with #GstTocEntry entries by appending them to the #GstToc using |
| * gst_toc_append_entry(), and appending subentries to a #GstTocEntry using |
| * gst_toc_entry_append_sub_entry(). |
| * |
| * Note that root level of the TOC can contain only either editions or chapters. You |
| * should not mix them together at the same level. Otherwise you will get serialization |
| * /deserialization errors. Make sure that no one of the entries has negative start and |
| * stop values. |
| * |
| * Use gst_event_new_toc() to create a new TOC #GstEvent, and gst_event_parse_toc() to |
| * parse received TOC event. Use gst_event_new_toc_select() to create a new TOC select #GstEvent, |
| * and gst_event_parse_toc_select() to parse received TOC select event. The same rule for |
| * the #GstMessage: gst_message_new_toc() to create new TOC #GstMessage, and |
| * gst_message_parse_toc() to parse received TOC message. |
| * |
| * TOCs can have global scope or current scope. Global scope TOCs contain |
| * all entries that can possibly be selected using a toc select event, and |
| * are what an application is usually interested in. TOCs with current scope |
| * only contain the parts of the TOC relevant to the currently selected/playing |
| * stream; the current scope TOC is used by downstream elements such as muxers |
| * to write correct TOC entries when transcoding files, for example. When |
| * playing a DVD, the global TOC would contain a hierarchy of all titles, |
| * chapters and angles, for example, while the current TOC would only contain |
| * the chapters for the currently playing title if playback of a specific |
| * title was requested. |
| * |
| * Applications and plugins should not rely on TOCs having a certain kind of |
| * structure, but should allow for different alternatives. For example, a |
| * simple CUE sheet embedded in a file may be presented as a flat list of |
| * track entries, or could have a top-level edition node (or some other |
| * alternative type entry) with track entries underneath that node; or even |
| * multiple top-level edition nodes (or some other alternative type entries) |
| * each with track entries underneath, in case the source file has extracted |
| * a track listing from different sources). |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| #include "gst_private.h" |
| #include "gstenumtypes.h" |
| #include "gsttaglist.h" |
| #include "gststructure.h" |
| #include "gstvalue.h" |
| #include "gsttoc.h" |
| #include "gstpad.h" |
| #include "gstquark.h" |
| |
| struct _GstTocEntry |
| { |
| GstMiniObject mini_object; |
| |
| GstToc *toc; |
| GstTocEntry *parent; |
| |
| gchar *uid; |
| GstTocEntryType type; |
| GstClockTime start, stop; |
| GList *subentries; |
| GstTagList *tags; |
| GstTocLoopType loop_type; |
| gint repeat_count; |
| }; |
| |
| struct _GstToc |
| { |
| GstMiniObject mini_object; |
| |
| GstTocScope scope; |
| GList *entries; |
| GstTagList *tags; |
| }; |
| |
| #undef gst_toc_copy |
| static GstToc *gst_toc_copy (const GstToc * toc); |
| static void gst_toc_free (GstToc * toc); |
| #undef gst_toc_entry_copy |
| static GstTocEntry *gst_toc_entry_copy (const GstTocEntry * toc); |
| static void gst_toc_entry_free (GstTocEntry * toc); |
| |
| GType _gst_toc_type = 0; |
| GType _gst_toc_entry_type = 0; |
| |
| GST_DEFINE_MINI_OBJECT_TYPE (GstToc, gst_toc); |
| GST_DEFINE_MINI_OBJECT_TYPE (GstTocEntry, gst_toc_entry); |
| |
| /** |
| * gst_toc_new: |
| * @scope: scope of this TOC |
| * |
| * Create a new #GstToc structure. |
| * |
| * Returns: (transfer full): newly allocated #GstToc structure, free it |
| * with gst_toc_unref(). |
| */ |
| GstToc * |
| gst_toc_new (GstTocScope scope) |
| { |
| GstToc *toc; |
| |
| g_return_val_if_fail (scope == GST_TOC_SCOPE_GLOBAL || |
| scope == GST_TOC_SCOPE_CURRENT, NULL); |
| |
| toc = g_slice_new0 (GstToc); |
| |
| gst_mini_object_init (GST_MINI_OBJECT_CAST (toc), 0, GST_TYPE_TOC, |
| (GstMiniObjectCopyFunction) gst_toc_copy, NULL, |
| (GstMiniObjectFreeFunction) gst_toc_free); |
| |
| toc->scope = scope; |
| toc->tags = gst_tag_list_new_empty (); |
| |
| return toc; |
| } |
| |
| /** |
| * gst_toc_get_scope: |
| * @toc: a #GstToc instance |
| * |
| * Returns: scope of @toc |
| */ |
| GstTocScope |
| gst_toc_get_scope (const GstToc * toc) |
| { |
| g_return_val_if_fail (toc != NULL, GST_TOC_SCOPE_GLOBAL); |
| |
| return toc->scope; |
| } |
| |
| /** |
| * gst_toc_set_tags: |
| * @toc: A #GstToc instance |
| * @tags: (allow-none) (transfer full): A #GstTagList or %NULL |
| * |
| * Set a #GstTagList with tags for the complete @toc. |
| */ |
| void |
| gst_toc_set_tags (GstToc * toc, GstTagList * tags) |
| { |
| g_return_if_fail (toc != NULL); |
| g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (toc))); |
| |
| if (toc->tags) |
| gst_tag_list_unref (toc->tags); |
| toc->tags = tags; |
| } |
| |
| /** |
| * gst_toc_merge_tags: |
| * @toc: A #GstToc instance |
| * @tags: (allow-none): A #GstTagList or %NULL |
| * @mode: A #GstTagMergeMode |
| * |
| * Merge @tags into the existing tags of @toc using @mode. |
| */ |
| void |
| gst_toc_merge_tags (GstToc * toc, GstTagList * tags, GstTagMergeMode mode) |
| { |
| g_return_if_fail (toc != NULL); |
| g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (toc))); |
| |
| if (!toc->tags) { |
| toc->tags = gst_tag_list_ref (tags); |
| } else { |
| GstTagList *tmp = gst_tag_list_merge (toc->tags, tags, mode); |
| gst_tag_list_unref (toc->tags); |
| toc->tags = tmp; |
| } |
| } |
| |
| /** |
| * gst_toc_get_tags: |
| * @toc: A #GstToc instance |
| * |
| * Gets the tags for @toc. |
| * |
| * Returns: (transfer none): A #GstTagList for @entry |
| */ |
| GstTagList * |
| gst_toc_get_tags (const GstToc * toc) |
| { |
| g_return_val_if_fail (toc != NULL, NULL); |
| |
| return toc->tags; |
| } |
| |
| /** |
| * gst_toc_append_entry: |
| * @toc: A #GstToc instance |
| * @entry: (transfer full): A #GstTocEntry |
| * |
| * Appends the #GstTocEntry @entry to @toc. |
| */ |
| void |
| gst_toc_append_entry (GstToc * toc, GstTocEntry * entry) |
| { |
| g_return_if_fail (toc != NULL); |
| g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (toc))); |
| g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (entry))); |
| g_return_if_fail (entry->toc == NULL); |
| g_return_if_fail (entry->parent == NULL); |
| |
| toc->entries = g_list_append (toc->entries, entry); |
| entry->toc = toc; |
| |
| GST_LOG ("appended %s entry with uid %s to toc %p", |
| gst_toc_entry_type_get_nick (entry->type), entry->uid, toc); |
| |
| gst_toc_dump (toc); |
| } |
| |
| /** |
| * gst_toc_get_entries: |
| * @toc: A #GstToc instance |
| * |
| * Gets the list of #GstTocEntry of @toc. |
| * |
| * Returns: (transfer none) (element-type Gst.TocEntry): A #GList of #GstTocEntry for @entry |
| */ |
| GList * |
| gst_toc_get_entries (const GstToc * toc) |
| { |
| g_return_val_if_fail (toc != NULL, NULL); |
| |
| return toc->entries; |
| } |
| |
| static GstTocEntry * |
| gst_toc_entry_new_internal (GstTocEntryType type, const gchar * uid) |
| { |
| GstTocEntry *entry; |
| |
| entry = g_slice_new0 (GstTocEntry); |
| |
| gst_mini_object_init (GST_MINI_OBJECT_CAST (entry), 0, GST_TYPE_TOC_ENTRY, |
| (GstMiniObjectCopyFunction) gst_toc_entry_copy, NULL, |
| (GstMiniObjectFreeFunction) gst_toc_entry_free); |
| |
| entry->uid = g_strdup (uid); |
| entry->type = type; |
| entry->tags = NULL; |
| entry->start = entry->stop = GST_CLOCK_TIME_NONE; |
| |
| return entry; |
| } |
| |
| /** |
| * gst_toc_entry_new: |
| * @type: entry type. |
| * @uid: unique ID (UID) in the whole TOC. |
| * |
| * Create new #GstTocEntry structure. |
| * |
| * Returns: newly allocated #GstTocEntry structure, free it with gst_toc_entry_unref(). |
| */ |
| GstTocEntry * |
| gst_toc_entry_new (GstTocEntryType type, const gchar * uid) |
| { |
| g_return_val_if_fail (uid != NULL, NULL); |
| |
| return gst_toc_entry_new_internal (type, uid); |
| } |
| |
| static void |
| gst_toc_free (GstToc * toc) |
| { |
| g_list_foreach (toc->entries, (GFunc) gst_mini_object_unref, NULL); |
| g_list_free (toc->entries); |
| |
| if (toc->tags != NULL) |
| gst_tag_list_unref (toc->tags); |
| |
| g_slice_free (GstToc, toc); |
| } |
| |
| static void |
| gst_toc_entry_free (GstTocEntry * entry) |
| { |
| g_return_if_fail (entry != NULL); |
| |
| g_list_foreach (entry->subentries, (GFunc) gst_mini_object_unref, NULL); |
| g_list_free (entry->subentries); |
| |
| g_free (entry->uid); |
| |
| if (entry->tags != NULL) |
| gst_tag_list_unref (entry->tags); |
| |
| g_slice_free (GstTocEntry, entry); |
| } |
| |
| static GstTocEntry * |
| gst_toc_entry_find_sub_entry (const GstTocEntry * entry, const gchar * uid) |
| { |
| GList *cur; |
| GstTocEntry *subentry, *subsubentry; |
| |
| g_return_val_if_fail (entry != NULL, NULL); |
| g_return_val_if_fail (uid != NULL, NULL); |
| |
| cur = entry->subentries; |
| while (cur != NULL) { |
| subentry = cur->data; |
| |
| if (g_strcmp0 (subentry->uid, uid) == 0) |
| return subentry; |
| |
| subsubentry = gst_toc_entry_find_sub_entry (subentry, uid); |
| if (subsubentry != NULL) |
| return subsubentry; |
| |
| cur = cur->next; |
| } |
| |
| return NULL; |
| } |
| |
| /** |
| * gst_toc_find_entry: |
| * @toc: #GstToc to search in. |
| * @uid: UID to find #GstTocEntry with. |
| * |
| * Find #GstTocEntry with given @uid in the @toc. |
| * |
| * Returns: (transfer none) (nullable): #GstTocEntry with specified |
| * @uid from the @toc, or %NULL if not found. |
| */ |
| GstTocEntry * |
| gst_toc_find_entry (const GstToc * toc, const gchar * uid) |
| { |
| GList *cur; |
| GstTocEntry *entry, *subentry; |
| |
| g_return_val_if_fail (toc != NULL, NULL); |
| g_return_val_if_fail (uid != NULL, NULL); |
| |
| cur = toc->entries; |
| while (cur != NULL) { |
| entry = cur->data; |
| |
| if (g_strcmp0 (entry->uid, uid) == 0) |
| return entry; |
| |
| subentry = gst_toc_entry_find_sub_entry (entry, uid); |
| if (subentry != NULL) |
| return subentry; |
| cur = cur->next; |
| } |
| |
| return NULL; |
| } |
| |
| static GList * |
| gst_toc_deep_copy_toc_entries (GList * entry_list) |
| { |
| GQueue new_entries = G_QUEUE_INIT; |
| GList *l; |
| |
| for (l = entry_list; l != NULL; l = l->next) |
| g_queue_push_tail (&new_entries, gst_toc_entry_copy (l->data)); |
| |
| return new_entries.head; |
| } |
| |
| /** |
| * gst_toc_entry_copy: |
| * @entry: #GstTocEntry to copy. |
| * |
| * Copy #GstTocEntry with all subentries (deep copy). |
| * |
| * Returns: (nullable): 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; |
| GstTagList *list; |
| |
| 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; |
| } |
| |
| ret->subentries = gst_toc_deep_copy_toc_entries (entry->subentries); |
| |
| return ret; |
| } |
| |
| /** |
| * gst_toc_copy: |
| * @toc: #GstToc to copy. |
| * |
| * Copy #GstToc with all subentries (deep copy). |
| * |
| * Returns: (nullable): 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; |
| 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; |
| } |
| |
| ret->entries = gst_toc_deep_copy_toc_entries (toc->entries); |
| |
| return ret; |
| } |
| |
| /** |
| * gst_toc_entry_set_start_stop_times: |
| * @entry: #GstTocEntry to set values. |
| * @start: start value to set. |
| * @stop: stop value to set. |
| * |
| * Set @start and @stop values for the @entry. |
| */ |
| void |
| gst_toc_entry_set_start_stop_times (GstTocEntry * entry, gint64 start, |
| gint64 stop) |
| { |
| g_return_if_fail (entry != NULL); |
| |
| entry->start = start; |
| entry->stop = stop; |
| } |
| |
| /** |
| * gst_toc_entry_get_start_stop_times: |
| * @entry: #GstTocEntry to get values from. |
| * @start: (out) (allow-none): the storage for the start value, leave |
| * %NULL if not need. |
| * @stop: (out) (allow-none): the storage for the stop value, leave |
| * %NULL if not need. |
| * |
| * Get @start and @stop values from the @entry and write them into appropriate |
| * storages. |
| * |
| * Returns: %TRUE if all non-%NULL storage pointers were filled with appropriate |
| * values, %FALSE otherwise. |
| */ |
| gboolean |
| gst_toc_entry_get_start_stop_times (const GstTocEntry * entry, gint64 * start, |
| gint64 * stop) |
| { |
| g_return_val_if_fail (entry != NULL, FALSE); |
| |
| if (start != NULL) |
| *start = entry->start; |
| if (stop != NULL) |
| *stop = entry->stop; |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_toc_entry_set_loop: |
| * @entry: #GstTocEntry to set values. |
| * @loop_type: loop_type value to set. |
| * @repeat_count: repeat_count value to set. |
| * |
| * Set @loop_type and @repeat_count values for the @entry. |
| * |
| * Since: 1.4 |
| */ |
| void |
| gst_toc_entry_set_loop (GstTocEntry * entry, GstTocLoopType loop_type, |
| gint repeat_count) |
| { |
| g_return_if_fail (entry != NULL); |
| |
| entry->loop_type = loop_type; |
| entry->repeat_count = repeat_count; |
| } |
| |
| /** |
| * gst_toc_entry_get_loop: |
| * @entry: #GstTocEntry to get values from. |
| * @loop_type: (out) (allow-none): the storage for the loop_type |
| * value, leave %NULL if not need. |
| * @repeat_count: (out) (allow-none): the storage for the repeat_count |
| * value, leave %NULL if not need. |
| * |
| * Get @loop_type and @repeat_count values from the @entry and write them into |
| * appropriate storages. Loops are e.g. used by sampled instruments. GStreamer |
| * is not automatically applying the loop. The application can process this |
| * meta data and use it e.g. to send a seek-event to loop a section. |
| * |
| * Returns: %TRUE if all non-%NULL storage pointers were filled with appropriate |
| * values, %FALSE otherwise. |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_toc_entry_get_loop (const GstTocEntry * entry, GstTocLoopType * loop_type, |
| gint * repeat_count) |
| { |
| g_return_val_if_fail (entry != NULL, FALSE); |
| |
| if (loop_type != NULL) |
| *loop_type = entry->loop_type; |
| if (repeat_count != NULL) |
| *repeat_count = entry->repeat_count; |
| |
| return TRUE; |
| } |
| |
| |
| /** |
| * gst_toc_entry_type_get_nick: |
| * @type: a #GstTocEntryType. |
| * |
| * Converts @type to a string representation. |
| * |
| * Returns: Returns a human-readable string for @type. This string is |
| * only for debugging purpose and should not be displayed in a user |
| * interface. |
| */ |
| const gchar * |
| gst_toc_entry_type_get_nick (GstTocEntryType type) |
| { |
| switch (type) { |
| case GST_TOC_ENTRY_TYPE_ANGLE: |
| return "angle"; |
| case GST_TOC_ENTRY_TYPE_VERSION: |
| return "version"; |
| case GST_TOC_ENTRY_TYPE_EDITION: |
| return "edition"; |
| case GST_TOC_ENTRY_TYPE_TITLE: |
| return "title"; |
| case GST_TOC_ENTRY_TYPE_TRACK: |
| return "track"; |
| case GST_TOC_ENTRY_TYPE_CHAPTER: |
| return "chapter"; |
| default: |
| break; |
| } |
| return "invalid"; |
| } |
| |
| /** |
| * gst_toc_entry_get_entry_type: |
| * @entry: a #GstTocEntry |
| * |
| * Returns: @entry's entry type |
| */ |
| GstTocEntryType |
| gst_toc_entry_get_entry_type (const GstTocEntry * entry) |
| { |
| g_return_val_if_fail (entry != NULL, GST_TOC_ENTRY_TYPE_INVALID); |
| |
| return entry->type; |
| } |
| |
| /** |
| * gst_toc_entry_is_alternative: |
| * @entry: a #GstTocEntry |
| * |
| * Returns: %TRUE if @entry's type is an alternative type, otherwise %FALSE |
| */ |
| gboolean |
| gst_toc_entry_is_alternative (const GstTocEntry * entry) |
| { |
| g_return_val_if_fail (entry != NULL, FALSE); |
| |
| return GST_TOC_ENTRY_TYPE_IS_ALTERNATIVE (entry->type); |
| } |
| |
| /** |
| * gst_toc_entry_is_sequence: |
| * @entry: a #GstTocEntry |
| * |
| * Returns: %TRUE if @entry's type is a sequence type, otherwise %FALSE |
| */ |
| gboolean |
| gst_toc_entry_is_sequence (const GstTocEntry * entry) |
| { |
| g_return_val_if_fail (entry != NULL, FALSE); |
| |
| return GST_TOC_ENTRY_TYPE_IS_SEQUENCE (entry->type); |
| } |
| |
| /** |
| * gst_toc_entry_get_uid: |
| * @entry: A #GstTocEntry instance |
| * |
| * Gets the UID of @entry. |
| * |
| * Returns: (transfer none): The UID of @entry |
| */ |
| const gchar * |
| gst_toc_entry_get_uid (const GstTocEntry * entry) |
| { |
| g_return_val_if_fail (entry != NULL, NULL); |
| |
| return entry->uid; |
| } |
| |
| /** |
| * gst_toc_entry_append_sub_entry: |
| * @entry: A #GstTocEntry instance |
| * @subentry: (transfer full): A #GstTocEntry |
| * |
| * Appends the #GstTocEntry @subentry to @entry. |
| */ |
| void |
| gst_toc_entry_append_sub_entry (GstTocEntry * entry, GstTocEntry * subentry) |
| { |
| g_return_if_fail (entry != NULL); |
| g_return_if_fail (subentry != NULL); |
| g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (entry))); |
| g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST |
| (subentry))); |
| g_return_if_fail (subentry->toc == NULL); |
| g_return_if_fail (subentry->parent == NULL); |
| |
| entry->subentries = g_list_append (entry->subentries, subentry); |
| subentry->toc = entry->toc; |
| subentry->parent = entry; |
| |
| GST_LOG ("appended %s subentry with uid %s to entry %s", |
| gst_toc_entry_type_get_nick (subentry->type), subentry->uid, entry->uid); |
| } |
| |
| /** |
| * gst_toc_entry_get_sub_entries: |
| * @entry: A #GstTocEntry instance |
| * |
| * Gets the sub-entries of @entry. |
| * |
| * Returns: (transfer none) (element-type Gst.TocEntry): A #GList of #GstTocEntry of @entry |
| */ |
| GList * |
| gst_toc_entry_get_sub_entries (const GstTocEntry * entry) |
| { |
| g_return_val_if_fail (entry != NULL, NULL); |
| |
| return entry->subentries; |
| } |
| |
| /** |
| * gst_toc_entry_set_tags: |
| * @entry: A #GstTocEntry instance |
| * @tags: (allow-none) (transfer full): A #GstTagList or %NULL |
| * |
| * Set a #GstTagList with tags for the complete @entry. |
| */ |
| void |
| gst_toc_entry_set_tags (GstTocEntry * entry, GstTagList * tags) |
| { |
| g_return_if_fail (entry != NULL); |
| g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (entry))); |
| |
| if (entry->tags) |
| gst_tag_list_unref (entry->tags); |
| entry->tags = tags; |
| } |
| |
| /** |
| * gst_toc_entry_merge_tags: |
| * @entry: A #GstTocEntry instance |
| * @tags: (allow-none): A #GstTagList or %NULL |
| * @mode: A #GstTagMergeMode |
| * |
| * Merge @tags into the existing tags of @entry using @mode. |
| */ |
| void |
| gst_toc_entry_merge_tags (GstTocEntry * entry, GstTagList * tags, |
| GstTagMergeMode mode) |
| { |
| g_return_if_fail (entry != NULL); |
| g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (entry))); |
| |
| if (!entry->tags) { |
| entry->tags = gst_tag_list_ref (tags); |
| } else { |
| GstTagList *tmp = gst_tag_list_merge (entry->tags, tags, mode); |
| gst_tag_list_unref (entry->tags); |
| entry->tags = tmp; |
| } |
| } |
| |
| /** |
| * gst_toc_entry_get_tags: |
| * @entry: A #GstTocEntry instance |
| * |
| * Gets the tags for @entry. |
| * |
| * Returns: (transfer none): A #GstTagList for @entry |
| */ |
| GstTagList * |
| gst_toc_entry_get_tags (const GstTocEntry * entry) |
| { |
| g_return_val_if_fail (entry != NULL, NULL); |
| |
| return entry->tags; |
| } |
| |
| /** |
| * gst_toc_entry_get_toc: |
| * @entry: A #GstTocEntry instance |
| * |
| * Gets the parent #GstToc of @entry. |
| * |
| * Returns: (transfer none): The parent #GstToc of @entry |
| */ |
| GstToc * |
| gst_toc_entry_get_toc (GstTocEntry * entry) |
| { |
| g_return_val_if_fail (entry != NULL, NULL); |
| |
| return entry->toc; |
| } |
| |
| /** |
| * gst_toc_entry_get_parent: |
| * @entry: A #GstTocEntry instance |
| * |
| * Gets the parent #GstTocEntry of @entry. |
| * |
| * Returns: (transfer none) (nullable): The parent #GstTocEntry of @entry |
| */ |
| GstTocEntry * |
| gst_toc_entry_get_parent (GstTocEntry * entry) |
| { |
| g_return_val_if_fail (entry != NULL, NULL); |
| |
| return entry->parent; |
| } |
| |
| #ifndef GST_DISABLE_GST_DEBUG |
| static void |
| gst_toc_dump_entries (GList * entries, guint depth) |
| { |
| GList *e; |
| gchar *indent; |
| |
| indent = g_malloc0 (depth + 1); |
| memset (indent, ' ', depth); |
| for (e = entries; e != NULL; e = e->next) { |
| GstTocEntry *entry = e->data; |
| |
| GST_TRACE ("%s+ %s (%s), %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT ", " |
| "tags: %" GST_PTR_FORMAT, indent, entry->uid, |
| gst_toc_entry_type_get_nick (entry->type), |
| GST_TIME_ARGS (entry->start), GST_TIME_ARGS (entry->stop), entry->tags); |
| |
| if (entry->subentries != NULL) |
| gst_toc_dump_entries (entry->subentries, depth + 2); |
| } |
| g_free (indent); |
| } |
| #endif |
| |
| void |
| gst_toc_dump (GstToc * toc) |
| { |
| #ifndef GST_DISABLE_GST_DEBUG |
| GST_TRACE (" Toc %p, scope: %s, tags: %" GST_PTR_FORMAT, toc, |
| (toc->scope == GST_TOC_SCOPE_GLOBAL) ? "global" : "current", toc->tags); |
| gst_toc_dump_entries (toc->entries, 2); |
| #endif |
| } |
| |
| void |
| _priv_gst_toc_initialize (void) |
| { |
| _gst_toc_type = gst_toc_get_type (); |
| _gst_toc_entry_type = gst_toc_entry_get_type (); |
| } |