X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgsttoc.c;h=fd6bd665eb14b73b8536410ea9147cd404690b34;hb=dac5966da6a0f53d0443dfa1ac239289028c415d;hp=7cd18dcd3f21419021428ebd67621bede90a9f2a;hpb=730c263842782d1570f4068ce5969a3c94658125;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gsttoc.c b/gst/gsttoc.c index 7cd18dc..fd6bd66 100644 --- a/gst/gsttoc.c +++ b/gst/gsttoc.c @@ -15,14 +15,15 @@ * * 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. */ /** * SECTION:gsttoc + * @title: GstToc * @short_description: Generic table of contents support - * @see_also: #GstStructure, #GstEvent, #GstMessage, #GstQuery, #GstPad + * @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. @@ -35,28 +36,40 @@ * * 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 #GstToc.entries #GstTocEntry.subentries - * lists. You should use GST_TOC_ENTRY_TYPE_CHAPTER for generic TOC entry and - * GST_TOC_ENTRY_TYPE_EDITION for the entries which are considered to be alternatives - * (like DVD angles, Matroska editions and so on). + * 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. * - * Please, use #GstToc.info and #GstTocEntry.info fields in that way: create a #GstStructure, - * put all info related to your element there and put this structure into the info field under - * the name of your element. Some fields in the info structure can be used for internal purposes, - * so you should use it in the way described above to not to overwrite already existent fields. - * * 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. Also you can create a new TOC query - * with gst_query_new_toc(), set it with gst_query_set_toc() and parse it with - * gst_query_parse_toc(). + * 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 @@ -70,671 +83,283 @@ #include "gstvalue.h" #include "gsttoc.h" #include "gstpad.h" +#include "gstquark.h" -#define GST_TOC_TOC_NAME "toc" -#define GST_TOC_ENTRY_NAME "entry" - -#define GST_TOC_TOC_UPDATED_FIELD "updated" -#define GST_TOC_TOC_EXTENDUID_FIELD "extenduid" -#define GST_TOC_INFO_FIELD "info" - -#define GST_TOC_ENTRY_UID_FIELD "uid" -#define GST_TOC_ENTRY_TYPE_FIELD "type" -#define GST_TOC_ENTRY_TAGS_FIELD "tags" - -#define GST_TOC_TOC_ENTRIES_FIELD "subentries" - -#define GST_TOC_INFO_NAME "info-structure" -#define GST_TOC_INFO_TIME_FIELD "time" - -#define GST_TOC_TIME_NAME "time-structure" -#define GST_TOC_TIME_START_FIELD "start" -#define GST_TOC_TIME_STOP_FIELD "stop" +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; +}; -enum +struct _GstToc { - GST_TOC_TOC = 0, - GST_TOC_ENTRY = 1, - GST_TOC_UPDATED = 2, - GST_TOC_EXTENDUID = 3, - GST_TOC_UID = 4, - GST_TOC_TYPE = 5, - GST_TOC_TAGS = 6, - GST_TOC_SUBENTRIES = 7, - GST_TOC_INFO = 8, - GST_TOC_INFONAME = 9, - GST_TOC_TIME = 10, - GST_TOC_TIMENAME = 11, - GST_TOC_TIME_START = 12, - GST_TOC_TIME_STOP = 13, - GST_TOC_LAST = 14 + GstMiniObject mini_object; + + GstTocScope scope; + GList *entries; + GstTagList *tags; }; -static GQuark gst_toc_fields[GST_TOC_LAST] = { 0 }; +#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); -void -_priv_gst_toc_initialize (void) -{ - static gboolean inited = FALSE; - - if (G_LIKELY (!inited)) { - gst_toc_fields[GST_TOC_TOC] = g_quark_from_static_string (GST_TOC_TOC_NAME); - gst_toc_fields[GST_TOC_ENTRY] = - g_quark_from_static_string (GST_TOC_ENTRY_NAME); - - gst_toc_fields[GST_TOC_UPDATED] = - g_quark_from_static_string (GST_TOC_TOC_UPDATED_FIELD); - gst_toc_fields[GST_TOC_EXTENDUID] = - g_quark_from_static_string (GST_TOC_TOC_EXTENDUID_FIELD); - gst_toc_fields[GST_TOC_INFO] = - g_quark_from_static_string (GST_TOC_INFO_FIELD); - - gst_toc_fields[GST_TOC_UID] = - g_quark_from_static_string (GST_TOC_ENTRY_UID_FIELD); - gst_toc_fields[GST_TOC_TYPE] = - g_quark_from_static_string (GST_TOC_ENTRY_TYPE_FIELD); - gst_toc_fields[GST_TOC_TAGS] = - g_quark_from_static_string (GST_TOC_ENTRY_TAGS_FIELD); - - gst_toc_fields[GST_TOC_SUBENTRIES] = - g_quark_from_static_string (GST_TOC_TOC_ENTRIES_FIELD); - - gst_toc_fields[GST_TOC_INFONAME] = - g_quark_from_static_string (GST_TOC_INFO_NAME); - gst_toc_fields[GST_TOC_TIME] = - g_quark_from_static_string (GST_TOC_INFO_TIME_FIELD); - gst_toc_fields[GST_TOC_TIMENAME] = - g_quark_from_static_string (GST_TOC_TIME_NAME); - gst_toc_fields[GST_TOC_TIME_START] = - g_quark_from_static_string (GST_TOC_TIME_START_FIELD); - gst_toc_fields[GST_TOC_TIME_STOP] = - g_quark_from_static_string (GST_TOC_TIME_STOP_FIELD); - - inited = TRUE; - } -} +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 new #GstToc structure. - * - * Returns: newly allocated #GstToc structure, free it with gst_toc_free(). + * Create a new #GstToc structure. * - * Since: 0.10.37 + * Returns: (transfer full): newly allocated #GstToc structure, free it + * with gst_toc_unref(). */ GstToc * -gst_toc_new (void) +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 (); - toc->info = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_INFONAME]); return toc; } /** - * gst_toc_entry_new: - * @type: entry type. - * @uid: unique ID (UID) in the whole TOC. + * gst_toc_get_scope: + * @toc: a #GstToc instance * - * Create new #GstTocEntry structure. - * - * Returns: newly allocated #GstTocEntry structure, free it with gst_toc_entry_free(). - * - * Since: 0.10.37 + * Returns: scope of @toc */ -GstTocEntry * -gst_toc_entry_new (GstTocEntryType type, const gchar * uid) +GstTocScope +gst_toc_get_scope (const GstToc * toc) { - GstTocEntry *entry; - - g_return_val_if_fail (uid != NULL, NULL); - - entry = g_slice_new0 (GstTocEntry); - entry->uid = g_strdup (uid); - entry->type = type; - entry->tags = gst_tag_list_new_empty (); - entry->info = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_INFONAME]); + g_return_val_if_fail (toc != NULL, GST_TOC_SCOPE_GLOBAL); - return entry; + return toc->scope; } /** - * gst_toc_entry_new_with_pad: - * @type: entry type. - * @uid: unique ID (UID) in the whole TOC. - * @pad: #GstPad related to this entry. - * - * Create new #GstTocEntry structure with #GstPad related. - * - * Returns: newly allocated #GstTocEntry structure, free it with gst_toc_entry_free() - * when done. + * gst_toc_set_tags: + * @toc: A #GstToc instance + * @tags: (allow-none) (transfer full): A #GstTagList or %NULL * - * Since: 0.10.37 + * Set a #GstTagList with tags for the complete @toc. */ -GstTocEntry * -gst_toc_entry_new_with_pad (GstTocEntryType type, const gchar * uid, - gpointer pad) +void +gst_toc_set_tags (GstToc * toc, GstTagList * tags) { - GstTocEntry *entry; - - g_return_val_if_fail (uid != NULL, NULL); - - entry = g_slice_new0 (GstTocEntry); - entry->uid = g_strdup (uid); - entry->type = type; - entry->tags = gst_tag_list_new_empty (); - - if (pad != NULL && GST_IS_PAD (pad)) - entry->pads = g_list_append (entry->pads, gst_object_ref (pad)); + g_return_if_fail (toc != NULL); + g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (toc))); - return entry; + if (toc->tags) + gst_tag_list_unref (toc->tags); + toc->tags = tags; } /** - * gst_toc_free: - * @toc: #GstToc structure to free. - * - * Free unused #GstToc structure. + * gst_toc_merge_tags: + * @toc: A #GstToc instance + * @tags: (allow-none): A #GstTagList or %NULL + * @mode: A #GstTagMergeMode * - * Since: 0.10.37 + * Merge @tags into the existing tags of @toc using @mode. */ void -gst_toc_free (GstToc * toc) +gst_toc_merge_tags (GstToc * toc, GstTagList * tags, GstTagMergeMode mode) { g_return_if_fail (toc != NULL); - - g_list_foreach (toc->entries, (GFunc) gst_toc_entry_free, NULL); - g_list_free (toc->entries); - - if (toc->tags != NULL) - gst_tag_list_free (toc->tags); - - if (toc->info != NULL) - gst_structure_free (toc->info); - - g_slice_free (GstToc, toc); + 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_entry_free: - * @entry: #GstTocEntry structure to free. + * gst_toc_get_tags: + * @toc: A #GstToc instance * - * Free unused #GstTocEntry structure. Note that #GstTocEntry.uid will - * be freed with g_free() and all #GstPad objects in the #GstTocEntry.pads - * list will be unrefed with gst_object_unref(). + * Gets the tags for @toc. * - * Since: 0.10.37 + * Returns: (transfer none): A #GstTagList for @entry */ -void -gst_toc_entry_free (GstTocEntry * entry) +GstTagList * +gst_toc_get_tags (const GstToc * toc) { - GList *cur; - - g_return_if_fail (entry != NULL); - - g_list_foreach (entry->subentries, (GFunc) gst_toc_entry_free, NULL); - g_list_free (entry->subentries); - - g_free (entry->uid); - - if (entry->tags != NULL) - gst_tag_list_free (entry->tags); - - if (entry->info != NULL) - gst_structure_free (entry->info); - - cur = entry->pads; - while (cur != NULL) { - if (GST_IS_PAD (cur->data)) - gst_object_unref (cur->data); - cur = cur->next; - } - - g_list_free (entry->pads); + g_return_val_if_fail (toc != NULL, NULL); - g_slice_free (GstTocEntry, entry); + return toc->tags; } -static GstStructure * -gst_toc_structure_new (GstTagList * tags, GstStructure * info) +/** + * 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) { - GstStructure *ret; - GValue val = { 0 }; + 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); - ret = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_TOC]); + toc->entries = g_list_append (toc->entries, entry); + entry->toc = toc; - if (tags != NULL) { - g_value_init (&val, GST_TYPE_STRUCTURE); - gst_value_set_structure (&val, GST_STRUCTURE (tags)); - gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_TAGS], &val); - g_value_unset (&val); - } + GST_LOG ("appended %s entry with uid %s to toc %p", + gst_toc_entry_type_get_nick (entry->type), entry->uid, toc); - if (info != NULL) { - g_value_init (&val, GST_TYPE_STRUCTURE); - gst_value_set_structure (&val, info); - gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_INFO], &val); - g_value_unset (&val); - } - - return ret; + gst_toc_dump (toc); } -static GstStructure * -gst_toc_entry_structure_new (GstTocEntryType type, const gchar * uid, - GstTagList * tags, GstStructure * info) +/** + * 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) { - GValue val = { 0 }; - GstStructure *ret; - - ret = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_ENTRY]); - - gst_structure_id_set (ret, gst_toc_fields[GST_TOC_TYPE], - GST_TYPE_TOC_ENTRY_TYPE, type, NULL); - - g_value_init (&val, G_TYPE_STRING); - g_value_set_string (&val, uid); - gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_UID], &val); - g_value_unset (&val); - - if (tags != NULL) { - g_value_init (&val, GST_TYPE_STRUCTURE); - gst_value_set_structure (&val, GST_STRUCTURE (tags)); - gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_TAGS], &val); - g_value_unset (&val); - } - - if (info != NULL) { - g_value_init (&val, GST_TYPE_STRUCTURE); - gst_value_set_structure (&val, info); - gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_INFO], &val); - g_value_unset (&val); - } + g_return_val_if_fail (toc != NULL, NULL); - return ret; + return toc->entries; } -static guint -gst_toc_entry_structure_n_subentries (const GstStructure * entry) +static GstTocEntry * +gst_toc_entry_new_internal (GstTocEntryType type, const gchar * uid) { - if (G_UNLIKELY (!gst_structure_id_has_field_typed (entry, - gst_toc_fields[GST_TOC_SUBENTRIES], GST_TYPE_ARRAY))) - return 0; - else - return gst_value_array_get_size ((gst_structure_id_get_value (entry, - gst_toc_fields[GST_TOC_SUBENTRIES]))); -} + GstTocEntry *entry; -static const GstStructure * -gst_toc_entry_structure_nth_subentry (const GstStructure * entry, guint nth) -{ - guint count; - const GValue *array; + entry = g_slice_new0 (GstTocEntry); - count = gst_toc_entry_structure_n_subentries (entry); + 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); - if (count < nth) - return NULL; + entry->uid = g_strdup (uid); + entry->type = type; + entry->tags = NULL; + entry->start = entry->stop = GST_CLOCK_TIME_NONE; - if (G_UNLIKELY (!gst_structure_id_has_field_typed (entry, - gst_toc_fields[GST_TOC_SUBENTRIES], GST_TYPE_ARRAY))) - return NULL; - else { - array = - gst_value_array_get_value (gst_structure_id_get_value (entry, - gst_toc_fields[GST_TOC_SUBENTRIES]), nth); - return gst_value_get_structure (array); - } + return entry; } -static GstTocEntry * -gst_toc_entry_from_structure (const GstStructure * entry, guint level) +/** + * 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) { - GstTocEntry *ret, *subentry; - const GValue *val; - const GstTagList *entry_tags; - const GstStructure *subentry_struct; - gint count, i; - const gchar *uid; - guint chapters_count = 0, editions_count = 0; - - g_return_val_if_fail (entry != NULL, NULL); - g_return_val_if_fail (gst_structure_id_has_field_typed (entry, - gst_toc_fields[GST_TOC_UID], G_TYPE_STRING), NULL); - g_return_val_if_fail (gst_structure_id_has_field_typed (entry, - gst_toc_fields[GST_TOC_TYPE], GST_TYPE_TOC_ENTRY_TYPE), NULL); - - val = gst_structure_id_get_value (entry, gst_toc_fields[GST_TOC_UID]); - uid = g_value_get_string (val); - - ret = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, uid); - - gst_structure_get_enum (entry, GST_TOC_ENTRY_TYPE_FIELD, - GST_TYPE_TOC_ENTRY_TYPE, (gint *) & (ret->type)); - - if (gst_structure_id_has_field_typed (entry, - gst_toc_fields[GST_TOC_SUBENTRIES], GST_TYPE_ARRAY)) { - count = gst_toc_entry_structure_n_subentries (entry); - - for (i = 0; i < count; ++i) { - subentry_struct = gst_toc_entry_structure_nth_subentry (entry, i); - subentry = gst_toc_entry_from_structure (subentry_struct, level + 1); - - /* skip empty editions */ - if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION - && subentry->subentries == NULL)) { - g_warning - ("Empty edition found while deserializing TOC from GstStructure, skipping"); - continue; - } - - if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION) - ++editions_count; - else - ++chapters_count; - - /* check for mixed content */ - if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) { - g_critical - ("Mixed editions and chapters in the TOC contents, the TOC is broken"); - gst_toc_entry_free (subentry); - gst_toc_entry_free (ret); - return NULL; - } - - if (G_UNLIKELY (subentry == NULL)) { - gst_toc_entry_free (ret); - return NULL; - } - - ret->subentries = g_list_prepend (ret->subentries, subentry); - } - - ret->subentries = g_list_reverse (ret->subentries); - } + g_return_val_if_fail (uid != NULL, NULL); - if (gst_structure_id_has_field_typed (entry, - gst_toc_fields[GST_TOC_TAGS], GST_TYPE_STRUCTURE)) { - val = gst_structure_id_get_value (entry, gst_toc_fields[GST_TOC_TAGS]); + return gst_toc_entry_new_internal (type, uid); +} - if (G_LIKELY (GST_IS_TAG_LIST (gst_value_get_structure (val)))) { - entry_tags = GST_TAG_LIST (gst_value_get_structure (val)); - ret->tags = gst_tag_list_copy (entry_tags); - } - } +static void +gst_toc_free (GstToc * toc) +{ + g_list_foreach (toc->entries, (GFunc) gst_mini_object_unref, NULL); + g_list_free (toc->entries); - if (gst_structure_id_has_field_typed (entry, - gst_toc_fields[GST_TOC_INFO], GST_TYPE_STRUCTURE)) { - val = gst_structure_id_get_value (entry, gst_toc_fields[GST_TOC_INFO]); + if (toc->tags != NULL) + gst_tag_list_unref (toc->tags); - if (G_LIKELY (GST_IS_STRUCTURE (gst_value_get_structure (val)))) - ret->info = gst_structure_copy (gst_value_get_structure (val)); - } +#ifdef USE_POISONING + memset (toc, 0xff, sizeof (GstToc)); +#endif - return ret; + g_slice_free (GstToc, toc); } -GstToc * -__gst_toc_from_structure (const GstStructure * toc) +static void +gst_toc_entry_free (GstTocEntry * entry) { - GstToc *ret; - GstTocEntry *subentry; - const GstStructure *subentry_struct; - const GValue *val; - const GstTagList *entry_tags; - guint count, i; - guint editions_count = 0, chapters_count = 0; - - g_return_val_if_fail (toc != NULL, NULL); - - ret = gst_toc_new (); - - if (gst_structure_id_has_field_typed (toc, - gst_toc_fields[GST_TOC_SUBENTRIES], GST_TYPE_ARRAY)) { - count = gst_toc_entry_structure_n_subentries (toc); - - for (i = 0; i < count; ++i) { - subentry_struct = gst_toc_entry_structure_nth_subentry (toc, i); - subentry = gst_toc_entry_from_structure (subentry_struct, 0); - - /* skip empty editions */ - if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION - && subentry->subentries == NULL)) { - g_warning - ("Empty edition found while deserializing TOC from GstStructure, skipping"); - continue; - } - - /* check for success */ - if (G_UNLIKELY (subentry == NULL)) { - g_critical ("Couldn't serialize deserializing TOC from GstStructure"); - gst_toc_free (ret); - return NULL; - } - - if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION) - ++editions_count; - else - ++chapters_count; - - /* check for mixed content */ - if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) { - g_critical - ("Mixed editions and chapters in the TOC contents, the TOC is broken"); - gst_toc_entry_free (subentry); - gst_toc_free (ret); - return NULL; - } - - ret->entries = g_list_prepend (ret->entries, subentry); - } - - ret->entries = g_list_reverse (ret->entries); - } - - if (gst_structure_id_has_field_typed (toc, - gst_toc_fields[GST_TOC_TAGS], GST_TYPE_STRUCTURE)) { - val = gst_structure_id_get_value (toc, gst_toc_fields[GST_TOC_TAGS]); + g_return_if_fail (entry != NULL); - if (G_LIKELY (GST_IS_TAG_LIST (gst_value_get_structure (val)))) { - entry_tags = GST_TAG_LIST (gst_value_get_structure (val)); - ret->tags = gst_tag_list_copy (entry_tags); - } - } + g_list_foreach (entry->subentries, (GFunc) gst_mini_object_unref, NULL); + g_list_free (entry->subentries); - if (gst_structure_id_has_field_typed (toc, - gst_toc_fields[GST_TOC_INFO], GST_TYPE_STRUCTURE)) { - val = gst_structure_id_get_value (toc, gst_toc_fields[GST_TOC_INFO]); + g_free (entry->uid); - if (G_LIKELY (GST_IS_STRUCTURE (gst_value_get_structure (val)))) - ret->info = gst_structure_copy (gst_value_get_structure (val)); - } + if (entry->tags != NULL) + gst_tag_list_unref (entry->tags); - if (G_UNLIKELY (ret->entries == NULL)) { - gst_toc_free (ret); - return NULL; - } +#ifdef USE_POISONING + memset (entry, 0xff, sizeof (GstTocEntry)); +#endif - return ret; + g_slice_free (GstTocEntry, entry); } -static GstStructure * -gst_toc_entry_to_structure (const GstTocEntry * entry, guint level) +static GstTocEntry * +gst_toc_entry_find_sub_entry (const GstTocEntry * entry, const gchar * uid) { - GstStructure *ret, *subentry_struct; - GstTocEntry *subentry; GList *cur; - GValue subentries_val = { 0 }; - GValue entry_val = { 0 }; - guint chapters_count = 0, editions_count = 0; + GstTocEntry *subentry, *subsubentry; g_return_val_if_fail (entry != NULL, NULL); - - ret = - gst_toc_entry_structure_new (entry->type, entry->uid, entry->tags, - entry->info); - - g_value_init (&subentries_val, GST_TYPE_ARRAY); - g_value_init (&entry_val, GST_TYPE_STRUCTURE); + g_return_val_if_fail (uid != NULL, NULL); cur = entry->subentries; while (cur != NULL) { subentry = cur->data; - if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION) - ++editions_count; - else - ++chapters_count; - - /* check for mixed content */ - if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) { - g_critical - ("Mixed editions and chapters in the TOC contents, the TOC is broken"); - gst_structure_free (ret); - g_value_unset (&entry_val); - g_value_unset (&subentries_val); - return NULL; - } - - /* skip empty editions */ - if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION - && subentry->subentries == NULL)) { - g_warning - ("Empty edition found while serializing TOC to GstStructure, skipping"); - cur = cur->next; - continue; - } - - subentry_struct = gst_toc_entry_to_structure (subentry, level + 1); - - /* check for success */ - if (G_UNLIKELY (subentry_struct == NULL)) { - gst_structure_free (ret); - g_value_unset (&subentries_val); - g_value_unset (&entry_val); - return NULL; - } - - /* skip empty editions */ - if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION - && subentry->subentries == NULL)) { - g_warning - ("Empty edition found while serializing TOC to GstStructure, skipping"); - cur = cur->next; - continue; - } - - gst_value_set_structure (&entry_val, subentry_struct); - gst_value_array_append_value (&subentries_val, &entry_val); - gst_structure_free (subentry_struct); - - cur = cur->next; - } - - gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_SUBENTRIES], - &subentries_val); - - g_value_unset (&subentries_val); - g_value_unset (&entry_val); - return ret; -} - -GstStructure * -__gst_toc_to_structure (const GstToc * toc) -{ - GValue val = { 0 }; - GValue subentries_val = { 0 }; - GstStructure *ret, *subentry_struct; - GstTocEntry *subentry; - GList *cur; - guint editions_count = 0, chapters_count = 0; - - g_return_val_if_fail (toc != NULL, NULL); - g_return_val_if_fail (toc->entries != NULL, NULL); - - ret = gst_toc_structure_new (toc->tags, toc->info); + if (g_strcmp0 (subentry->uid, uid) == 0) + return subentry; - g_value_init (&val, GST_TYPE_STRUCTURE); - g_value_init (&subentries_val, GST_TYPE_ARRAY); - cur = toc->entries; - - while (cur != NULL) { - subentry = cur->data; - - if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION) - ++editions_count; - else - ++chapters_count; - - /* check for mixed content */ - if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) { - g_critical - ("Mixed editions and chapters in the TOC contents, the TOC is broken"); - gst_structure_free (ret); - g_value_unset (&val); - g_value_unset (&subentries_val); - return NULL; - } - - /* skip empty editions */ - if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION - && subentry->subentries == NULL)) { - g_warning - ("Empty edition found while serializing TOC to GstStructure, skipping"); - cur = cur->next; - continue; - } - - subentry_struct = gst_toc_entry_to_structure (subentry, 0); - - /* check for success */ - if (G_UNLIKELY (subentry_struct == NULL)) { - g_critical ("Couldn't serialize TOC to GstStructure"); - gst_structure_free (ret); - g_value_unset (&val); - g_value_unset (&subentries_val); - return NULL; - } - - gst_value_set_structure (&val, subentry_struct); - gst_value_array_append_value (&subentries_val, &val); - gst_structure_free (subentry_struct); + subsubentry = gst_toc_entry_find_sub_entry (subentry, uid); + if (subsubentry != NULL) + return subsubentry; cur = cur->next; } - gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_SUBENTRIES], - &subentries_val); - - g_value_unset (&val); - g_value_unset (&subentries_val); - return ret; -} - -static gboolean -gst_toc_check_entry_for_uid (const GstTocEntry * entry, const gchar * uid) -{ - GList *cur; - - g_return_val_if_fail (entry != NULL, FALSE); - g_return_val_if_fail (uid != NULL, FALSE); - - if (g_strcmp0 (entry->uid, uid) == 0) - return TRUE; - - cur = entry->subentries; - while (cur != NULL) { - if (gst_toc_check_entry_for_uid (cur->data, uid)) - return TRUE; - cur = cur->next; - } - - return FALSE; + return NULL; } /** @@ -744,73 +369,77 @@ gst_toc_check_entry_for_uid (const GstTocEntry * entry, const gchar * uid) * * Find #GstTocEntry with given @uid in the @toc. * - * Returns: #GstTocEntry with specified @uid from the @toc, or NULL if not found. - * - * Since: 0.10.37 + * 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) { - if (gst_toc_check_entry_for_uid (cur->data, uid)) - return cur->data; + 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: newly allocated #GstTocEntry in case of success, NULL otherwise; - * free it when done with gst_toc_entry_free(). - * - * Since: 0.10.37 + * Returns: (nullable): newly allocated #GstTocEntry in case of + * success, %NULL otherwise; free it when done with + * gst_toc_entry_unref(). */ -GstTocEntry * +static GstTocEntry * gst_toc_entry_copy (const GstTocEntry * entry) { - GstTocEntry *ret, *sub; - GList *cur; + GstTocEntry *ret; + GstTagList *list; g_return_val_if_fail (entry != NULL, NULL); ret = gst_toc_entry_new (entry->type, entry->uid); - if (GST_IS_STRUCTURE (entry->info)) - ret->info = gst_structure_copy (entry->info); + ret->start = entry->start; + ret->stop = entry->stop; - if (GST_IS_TAG_LIST (entry->tags)) - ret->tags = gst_tag_list_copy (entry->tags); - - cur = entry->pads; - while (cur != NULL) { - if (GST_IS_PAD (cur->data)) - ret->pads = g_list_prepend (ret->pads, gst_object_ref (cur->data)); - cur = cur->next; + 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->pads = g_list_reverse (ret->pads); - 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); + ret->subentries = gst_toc_deep_copy_toc_entries (entry->subentries); return ret; } @@ -821,191 +450,388 @@ gst_toc_entry_copy (const GstTocEntry * entry) * * Copy #GstToc with all subentries (deep copy). * - * Returns: newly allocated #GstToc in case of success, NULL otherwise; - * free it when done with gst_toc_free(). - * - * Since: 0.10.37 + * Returns: (nullable): newly allocated #GstToc in case of success, + * %NULL otherwise; free it when done with gst_toc_unref(). */ -GstToc * +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 (); - - if (GST_IS_STRUCTURE (toc->info)) - ret->info = gst_structure_copy (toc->info); - - if (GST_IS_TAG_LIST (toc->tags)) - ret->tags = gst_tag_list_copy (toc->tags); - - cur = toc->entries; - while (cur != NULL) { - entry = gst_toc_entry_copy (cur->data); - - if (entry != NULL) - ret->entries = g_list_prepend (ret->entries, entry); + ret = gst_toc_new (toc->scope); - cur = cur->next; + 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 = g_list_reverse (ret->entries); + + ret->entries = gst_toc_deep_copy_toc_entries (toc->entries); return ret; } /** - * gst_toc_entry_set_start_stop: + * 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. - * - * Since: 0.10.37 */ void -gst_toc_entry_set_start_stop (GstTocEntry * entry, gint64 start, gint64 stop) +gst_toc_entry_set_start_stop_times (GstTocEntry * entry, gint64 start, + gint64 stop) { - const GValue *val; - GstStructure *structure = NULL; - g_return_if_fail (entry != NULL); - g_return_if_fail (GST_IS_STRUCTURE (entry->info)); - if (gst_structure_id_has_field_typed (entry->info, - gst_toc_fields[GST_TOC_TIME], GST_TYPE_STRUCTURE)) { - val = - gst_structure_id_get_value (entry->info, gst_toc_fields[GST_TOC_TIME]); - structure = gst_structure_copy (gst_value_get_structure (val)); - } + 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 (structure == NULL) - structure = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_TIMENAME]); + if (start != NULL) + *start = entry->start; + if (stop != NULL) + *stop = entry->stop; - gst_structure_id_set (structure, gst_toc_fields[GST_TOC_TIME_START], - G_TYPE_INT64, start, gst_toc_fields[GST_TOC_TIME_STOP], G_TYPE_INT64, - stop, NULL); + return TRUE; +} - gst_structure_id_set (entry->info, gst_toc_fields[GST_TOC_TIME], - GST_TYPE_STRUCTURE, structure, NULL); +/** + * 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); - gst_structure_free (structure); + entry->loop_type = loop_type; + entry->repeat_count = repeat_count; } /** - * gst_toc_entry_get_start_stop: + * gst_toc_entry_get_loop: * @entry: #GstTocEntry to get values from. - * @start: (out): the storage for the start value, leave #NULL if not need. - * @stop: (out): the storage for the stop value, leave #NULL if not need. + * @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 start and stop values from the @entry and write them into appropriate storages. + * 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. + * Returns: %TRUE if all non-%NULL storage pointers were filled with appropriate + * values, %FALSE otherwise. * - * Since: 0.10.37 + * Since: 1.4 */ gboolean -gst_toc_entry_get_start_stop (const GstTocEntry * entry, gint64 * start, - gint64 * stop) +gst_toc_entry_get_loop (const GstTocEntry * entry, GstTocLoopType * loop_type, + gint * repeat_count) { - gboolean ret = TRUE; - const GValue *val; - const GstStructure *structure; - g_return_val_if_fail (entry != NULL, FALSE); - g_return_val_if_fail (GST_IS_STRUCTURE (entry->info), FALSE); - - if (!gst_structure_id_has_field_typed (entry->info, - gst_toc_fields[GST_TOC_TIME], GST_TYPE_STRUCTURE)) - return FALSE; - - val = gst_structure_id_get_value (entry->info, gst_toc_fields[GST_TOC_TIME]); - structure = gst_value_get_structure (val); - - if (start != NULL) { - if (gst_structure_id_has_field_typed (structure, - gst_toc_fields[GST_TOC_TIME_START], G_TYPE_INT64)) - *start = - g_value_get_int64 (gst_structure_id_get_value (structure, - gst_toc_fields[GST_TOC_TIME_START])); - else - ret = FALSE; - } - if (stop != NULL) { - if (gst_structure_id_has_field_typed (structure, - gst_toc_fields[GST_TOC_TIME_STOP], G_TYPE_INT64)) - *stop = - g_value_get_int64 (gst_structure_id_get_value (structure, - gst_toc_fields[GST_TOC_TIME_STOP])); - else - ret = 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"; +} - return ret; +/** + * 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_structure_get_updated (const GstStructure * toc) +gst_toc_entry_is_alternative (const GstTocEntry * entry) { - const GValue *val; + g_return_val_if_fail (entry != NULL, FALSE); - g_return_val_if_fail (GST_IS_STRUCTURE (toc), FALSE); + return GST_TOC_ENTRY_TYPE_IS_ALTERNATIVE (entry->type); +} - if (G_LIKELY (gst_structure_id_has_field_typed (toc, - gst_toc_fields[GST_TOC_UPDATED], G_TYPE_BOOLEAN))) { - val = gst_structure_id_get_value (toc, gst_toc_fields[GST_TOC_UPDATED]); - return g_value_get_boolean (val); - } +/** + * 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 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_structure_set_updated (GstStructure * toc, gboolean updated) +gst_toc_entry_append_sub_entry (GstTocEntry * entry, GstTocEntry * subentry) { - GValue val = { 0 }; + 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); +} - g_return_if_fail (toc != NULL); +/** + * 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); - g_value_init (&val, G_TYPE_BOOLEAN); - g_value_set_boolean (&val, updated); - gst_structure_id_set_value (toc, gst_toc_fields[GST_TOC_UPDATED], &val); - g_value_unset (&val); + return entry->subentries; } -gchar * -__gst_toc_structure_get_extend_uid (const GstStructure * toc) +/** + * 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) { - const GValue *val; + g_return_if_fail (entry != NULL); + g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (entry))); - g_return_val_if_fail (GST_IS_STRUCTURE (toc), NULL); + if (entry->tags) + gst_tag_list_unref (entry->tags); + entry->tags = tags; +} - if (G_LIKELY (gst_structure_id_has_field_typed (toc, - gst_toc_fields[GST_TOC_EXTENDUID], G_TYPE_STRING))) { - val = gst_structure_id_get_value (toc, gst_toc_fields[GST_TOC_EXTENDUID]); - return g_strdup (g_value_get_string (val)); +/** + * 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; } +} - return NULL; +/** + * 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; } -void -__gst_toc_structure_set_extend_uid (GstStructure * toc, - const gchar * extend_uid) +/** + * 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) { - GValue val = { 0 }; + g_return_val_if_fail (entry != NULL, NULL); - g_return_if_fail (toc != NULL); - g_return_if_fail (extend_uid != 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 - g_value_init (&val, G_TYPE_STRING); - g_value_set_string (&val, extend_uid); - gst_structure_id_set_value (toc, gst_toc_fields[GST_TOC_EXTENDUID], &val); - g_value_unset (&val); +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 (); }