2 * (c) 2010, 2012 Alexander Saprykin <xelfium@gmail.com>
4 * gsttoc.c: GstToc initialization and parsing/creation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
24 * @short_description: Generic table of contents support
25 * @see_also: #GstStructure, #GstEvent, #GstMessage, #GstQuery, #GstPad
27 * #GstToc functions are used to create/free #GstToc and #GstTocEntry structures.
28 * Also they are used to convert #GstToc into #GstStructure and vice versa.
30 * #GstToc lets you to inform other elements in pipeline or application that playing
31 * source has some kind of table of contents (TOC). These may be chapters, editions,
32 * angles or other types. For example: DVD chapters, Matroska chapters or cue sheet
33 * TOC. Such TOC will be useful for applications to display instead of just a
36 * Using TOC is very easy. Firstly, create #GstToc structure which represents root
37 * contents of the source. You can also attach TOC-specific tags to it. Then fill
38 * it with #GstTocEntry entries by appending them to #GstToc.entries #GstTocEntry.subentries
39 * lists. You should use GST_TOC_ENTRY_TYPE_CHAPTER for generic TOC entry and
40 * GST_TOC_ENTRY_TYPE_EDITION for the entries which are considered to be alternatives
41 * (like DVD angles, Matroska editions and so on).
43 * Note that root level of the TOC can contain only either editions or chapters. You
44 * should not mix them together at the same level. Otherwise you will get serialization
45 * /deserialization errors. Make sure that no one of the entries has negative start and
48 * Please, use #GstToc.info and #GstTocEntry.info fields in that way: create a #GstStructure,
49 * put all info related to your element there and put this structure into the info field under
50 * the name of your element. Some fields in the info structure can be used for internal purposes,
51 * so you should use it in the way described above to not to overwrite already existent fields.
53 * Use gst_event_new_toc() to create a new TOC #GstEvent, and gst_event_parse_toc() to
54 * parse received TOC event. Use gst_event_new_toc_select() to create a new TOC select #GstEvent,
55 * and gst_event_parse_toc_select() to parse received TOC select event. The same rule for
56 * the #GstMessage: gst_message_new_toc() to create new TOC #GstMessage, and
57 * gst_message_parse_toc() to parse received TOC message. Also you can create a new TOC query
58 * with gst_query_new_toc(), set it with gst_query_set_toc() and parse it with
59 * gst_query_parse_toc().
66 #include "gst_private.h"
67 #include "gstenumtypes.h"
68 #include "gsttaglist.h"
69 #include "gststructure.h"
75 G_DEFINE_BOXED_TYPE (GstToc, gst_toc,
76 (GBoxedCopyFunc) gst_toc_copy, (GBoxedFreeFunc) gst_toc_free);
77 G_DEFINE_BOXED_TYPE (GstTocEntry, gst_toc_entry,
78 (GBoxedCopyFunc) gst_toc_entry_copy, (GBoxedFreeFunc) gst_toc_entry_free);
83 * Create new #GstToc structure.
85 * Returns: newly allocated #GstToc structure, free it with gst_toc_free().
94 toc = g_slice_new0 (GstToc);
95 toc->tags = gst_tag_list_new_empty ();
96 toc->info = gst_structure_new_id_empty (GST_QUARK (INFO_STRUCTURE));
104 * @uid: unique ID (UID) in the whole TOC.
106 * Create new #GstTocEntry structure.
108 * Returns: newly allocated #GstTocEntry structure, free it with gst_toc_entry_free().
113 gst_toc_entry_new (GstTocEntryType type, const gchar * uid)
117 g_return_val_if_fail (uid != NULL, NULL);
119 entry = g_slice_new0 (GstTocEntry);
120 entry->uid = g_strdup (uid);
122 entry->tags = gst_tag_list_new_empty ();
123 entry->info = gst_structure_new_id_empty (GST_QUARK (INFO_STRUCTURE));
129 * gst_toc_entry_new_with_pad:
131 * @uid: unique ID (UID) in the whole TOC.
132 * @pad: #GstPad related to this entry.
134 * Create new #GstTocEntry structure with #GstPad related.
136 * Returns: newly allocated #GstTocEntry structure, free it with gst_toc_entry_free()
142 gst_toc_entry_new_with_pad (GstTocEntryType type, const gchar * uid,
147 g_return_val_if_fail (uid != NULL, NULL);
149 entry = g_slice_new0 (GstTocEntry);
150 entry->uid = g_strdup (uid);
152 entry->tags = gst_tag_list_new_empty ();
153 entry->info = gst_structure_new_id_empty (GST_QUARK (INFO_STRUCTURE));
155 if (pad != NULL && GST_IS_PAD (pad))
156 entry->pads = g_list_append (entry->pads, gst_object_ref (pad));
163 * @toc: #GstToc structure to free.
165 * Free unused #GstToc structure.
170 gst_toc_free (GstToc * toc)
172 g_return_if_fail (toc != NULL);
174 g_list_foreach (toc->entries, (GFunc) gst_toc_entry_free, NULL);
175 g_list_free (toc->entries);
177 if (toc->tags != NULL)
178 gst_tag_list_unref (toc->tags);
180 if (toc->info != NULL)
181 gst_structure_free (toc->info);
183 g_slice_free (GstToc, toc);
187 * gst_toc_entry_free:
188 * @entry: #GstTocEntry structure to free.
190 * Free unused #GstTocEntry structure. Note that #GstTocEntry.uid will
191 * be freed with g_free() and all #GstPad objects in the #GstTocEntry.pads
192 * list will be unrefed with gst_object_unref().
197 gst_toc_entry_free (GstTocEntry * entry)
201 g_return_if_fail (entry != NULL);
203 g_list_foreach (entry->subentries, (GFunc) gst_toc_entry_free, NULL);
204 g_list_free (entry->subentries);
208 if (entry->tags != NULL)
209 gst_tag_list_unref (entry->tags);
211 if (entry->info != NULL)
212 gst_structure_free (entry->info);
215 while (cur != NULL) {
216 if (GST_IS_PAD (cur->data))
217 gst_object_unref (cur->data);
221 g_list_free (entry->pads);
223 g_slice_free (GstTocEntry, entry);
226 static GstStructure *
227 gst_toc_structure_new (GstTagList * tags, GstStructure * info)
231 ret = gst_structure_new_id_empty (GST_QUARK (TOC));
234 gst_structure_id_set (ret, GST_QUARK (TAGS), GST_TYPE_TAG_LIST, tags, NULL);
238 gst_structure_id_set (ret, GST_QUARK (INFO), GST_TYPE_STRUCTURE, info,
245 static GstStructure *
246 gst_toc_entry_structure_new (GstTocEntryType type, const gchar * uid,
247 GstTagList * tags, GstStructure * info)
251 ret = gst_structure_new_id_empty (GST_QUARK (TOC_ENTRY));
253 gst_structure_id_set (ret, GST_QUARK (TYPE), GST_TYPE_TOC_ENTRY_TYPE, type,
255 gst_structure_id_set (ret, GST_QUARK (UID), G_TYPE_STRING, uid, NULL);
258 gst_structure_id_set (ret, GST_QUARK (TAGS), GST_TYPE_TAG_LIST, tags, NULL);
262 gst_structure_id_set (ret, GST_QUARK (INFO), GST_TYPE_STRUCTURE, info,
270 gst_toc_entry_structure_n_subentries (const GstStructure * entry)
272 if (G_UNLIKELY (!gst_structure_id_has_field_typed (entry,
273 GST_QUARK (SUB_ENTRIES), GST_TYPE_ARRAY)))
276 return gst_value_array_get_size ((gst_structure_id_get_value (entry,
277 GST_QUARK (SUB_ENTRIES))));
280 static const GstStructure *
281 gst_toc_entry_structure_nth_subentry (const GstStructure * entry, guint nth)
286 count = gst_toc_entry_structure_n_subentries (entry);
291 if (G_UNLIKELY (!gst_structure_id_has_field_typed (entry,
292 GST_QUARK (SUB_ENTRIES), GST_TYPE_ARRAY)))
296 gst_value_array_get_value (gst_structure_id_get_value (entry,
297 GST_QUARK (SUB_ENTRIES)), nth);
298 return gst_value_get_structure (array);
303 gst_toc_entry_from_structure (const GstStructure * entry, guint level)
305 GstTocEntry *ret, *subentry;
307 const GstStructure *subentry_struct;
312 guint chapters_count = 0, editions_count = 0;
314 g_return_val_if_fail (entry != NULL, NULL);
315 g_return_val_if_fail (gst_structure_id_has_field_typed (entry,
316 GST_QUARK (UID), G_TYPE_STRING), NULL);
317 g_return_val_if_fail (gst_structure_id_has_field_typed (entry,
318 GST_QUARK (TYPE), GST_TYPE_TOC_ENTRY_TYPE), NULL);
320 val = gst_structure_id_get_value (entry, GST_QUARK (UID));
321 uid = g_value_get_string (val);
323 ret = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, uid);
325 gst_structure_get_enum (entry, g_quark_to_string (GST_QUARK (TYPE)),
326 GST_TYPE_TOC_ENTRY_TYPE, (gint *) & (ret->type));
328 if (gst_structure_id_has_field_typed (entry,
329 GST_QUARK (SUB_ENTRIES), GST_TYPE_ARRAY)) {
330 count = gst_toc_entry_structure_n_subentries (entry);
332 for (i = 0; i < count; ++i) {
333 subentry_struct = gst_toc_entry_structure_nth_subentry (entry, i);
334 subentry = gst_toc_entry_from_structure (subentry_struct, level + 1);
336 /* skip empty editions */
337 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
338 && subentry->subentries == NULL)) {
340 ("Empty edition found while deserializing TOC from GstStructure, skipping");
344 if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION)
349 /* check for mixed content */
350 if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) {
352 ("Mixed editions and chapters in the TOC contents, the TOC is broken");
353 gst_toc_entry_free (subentry);
354 gst_toc_entry_free (ret);
358 if (G_UNLIKELY (subentry == NULL)) {
359 gst_toc_entry_free (ret);
363 ret->subentries = g_list_prepend (ret->subentries, subentry);
366 ret->subentries = g_list_reverse (ret->subentries);
369 if (gst_structure_id_has_field_typed (entry, GST_QUARK (TAGS),
370 GST_TYPE_TAG_LIST)) {
371 val = gst_structure_id_get_value (entry, GST_QUARK (TAGS));
373 if (G_LIKELY (GST_IS_TAG_LIST (g_value_get_boxed (val)))) {
374 list = gst_tag_list_copy (GST_TAG_LIST (g_value_get_boxed (val)));
375 gst_tag_list_unref (ret->tags);
380 if (gst_structure_id_has_field_typed (entry,
381 GST_QUARK (INFO), GST_TYPE_STRUCTURE)) {
382 val = gst_structure_id_get_value (entry, GST_QUARK (INFO));
384 if (G_LIKELY (GST_IS_STRUCTURE (gst_value_get_structure (val)))) {
385 st = gst_structure_copy (gst_value_get_structure (val));
386 gst_structure_free (ret->info);
395 __gst_toc_from_structure (const GstStructure * toc)
398 GstTocEntry *subentry;
399 const GstStructure *subentry_struct;
404 guint editions_count = 0, chapters_count = 0;
406 g_return_val_if_fail (toc != NULL, NULL);
408 ret = gst_toc_new ();
410 if (gst_structure_id_has_field_typed (toc,
411 GST_QUARK (SUB_ENTRIES), GST_TYPE_ARRAY)) {
412 count = gst_toc_entry_structure_n_subentries (toc);
414 for (i = 0; i < count; ++i) {
415 subentry_struct = gst_toc_entry_structure_nth_subentry (toc, i);
416 subentry = gst_toc_entry_from_structure (subentry_struct, 0);
418 /* skip empty editions */
419 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
420 && subentry->subentries == NULL)) {
422 ("Empty edition found while deserializing TOC from GstStructure, skipping");
426 /* check for success */
427 if (G_UNLIKELY (subentry == NULL)) {
428 g_critical ("Couldn't serialize deserializing TOC from GstStructure");
433 if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION)
438 /* check for mixed content */
439 if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) {
441 ("Mixed editions and chapters in the TOC contents, the TOC is broken");
442 gst_toc_entry_free (subentry);
447 ret->entries = g_list_prepend (ret->entries, subentry);
450 ret->entries = g_list_reverse (ret->entries);
453 if (gst_structure_id_has_field_typed (toc, GST_QUARK (TAGS),
454 GST_TYPE_TAG_LIST)) {
455 val = gst_structure_id_get_value (toc, GST_QUARK (TAGS));
457 if (G_LIKELY (GST_IS_TAG_LIST (g_value_get_boxed (val)))) {
458 list = gst_tag_list_copy (GST_TAG_LIST (g_value_get_boxed (val)));
459 gst_tag_list_unref (ret->tags);
464 if (gst_structure_id_has_field_typed (toc,
465 GST_QUARK (INFO), GST_TYPE_STRUCTURE)) {
466 val = gst_structure_id_get_value (toc, GST_QUARK (INFO));
468 if (G_LIKELY (GST_IS_STRUCTURE (gst_value_get_structure (val)))) {
469 st = gst_structure_copy (gst_value_get_structure (val));
470 gst_structure_free (ret->info);
475 if (G_UNLIKELY (ret->entries == NULL)) {
483 static GstStructure *
484 gst_toc_entry_to_structure (const GstTocEntry * entry, guint level)
486 GstStructure *ret, *subentry_struct;
487 GstTocEntry *subentry;
489 GValue subentries_val = { 0 };
490 GValue entry_val = { 0 };
491 guint chapters_count = 0, editions_count = 0;
493 g_return_val_if_fail (entry != NULL, NULL);
496 gst_toc_entry_structure_new (entry->type, entry->uid, entry->tags,
499 g_value_init (&subentries_val, GST_TYPE_ARRAY);
500 g_value_init (&entry_val, GST_TYPE_STRUCTURE);
502 cur = entry->subentries;
503 while (cur != NULL) {
504 subentry = cur->data;
506 if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION)
511 /* check for mixed content */
512 if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) {
514 ("Mixed editions and chapters in the TOC contents, the TOC is broken");
515 gst_structure_free (ret);
516 g_value_unset (&entry_val);
517 g_value_unset (&subentries_val);
521 /* skip empty editions */
522 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
523 && subentry->subentries == NULL)) {
525 ("Empty edition found while serializing TOC to GstStructure, skipping");
530 subentry_struct = gst_toc_entry_to_structure (subentry, level + 1);
532 /* check for success */
533 if (G_UNLIKELY (subentry_struct == NULL)) {
534 gst_structure_free (ret);
535 g_value_unset (&subentries_val);
536 g_value_unset (&entry_val);
540 /* skip empty editions */
541 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
542 && subentry->subentries == NULL)) {
544 ("Empty edition found while serializing TOC to GstStructure, skipping");
549 gst_value_set_structure (&entry_val, subentry_struct);
550 gst_value_array_append_value (&subentries_val, &entry_val);
551 gst_structure_free (subentry_struct);
556 gst_structure_id_set_value (ret, GST_QUARK (SUB_ENTRIES), &subentries_val);
558 g_value_unset (&subentries_val);
559 g_value_unset (&entry_val);
564 __gst_toc_to_structure (const GstToc * toc)
567 GValue subentries_val = { 0 };
568 GstStructure *ret, *subentry_struct;
569 GstTocEntry *subentry;
571 guint editions_count = 0, chapters_count = 0;
573 g_return_val_if_fail (toc != NULL, NULL);
574 g_return_val_if_fail (toc->entries != NULL, NULL);
576 ret = gst_toc_structure_new (toc->tags, toc->info);
578 g_value_init (&val, GST_TYPE_STRUCTURE);
579 g_value_init (&subentries_val, GST_TYPE_ARRAY);
582 while (cur != NULL) {
583 subentry = cur->data;
585 if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION)
590 /* check for mixed content */
591 if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) {
593 ("Mixed editions and chapters in the TOC contents, the TOC is broken");
594 gst_structure_free (ret);
595 g_value_unset (&val);
596 g_value_unset (&subentries_val);
600 /* skip empty editions */
601 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
602 && subentry->subentries == NULL)) {
604 ("Empty edition found while serializing TOC to GstStructure, skipping");
609 subentry_struct = gst_toc_entry_to_structure (subentry, 0);
611 /* check for success */
612 if (G_UNLIKELY (subentry_struct == NULL)) {
613 g_critical ("Couldn't serialize TOC to GstStructure");
614 gst_structure_free (ret);
615 g_value_unset (&val);
616 g_value_unset (&subentries_val);
620 gst_value_set_structure (&val, subentry_struct);
621 gst_value_array_append_value (&subentries_val, &val);
622 gst_structure_free (subentry_struct);
627 gst_structure_id_set_value (ret, GST_QUARK (SUB_ENTRIES), &subentries_val);
629 g_value_unset (&val);
630 g_value_unset (&subentries_val);
635 gst_toc_check_entry_for_uid (const GstTocEntry * entry, const gchar * uid)
639 g_return_val_if_fail (entry != NULL, FALSE);
640 g_return_val_if_fail (uid != NULL, FALSE);
642 if (g_strcmp0 (entry->uid, uid) == 0)
645 cur = entry->subentries;
646 while (cur != NULL) {
647 if (gst_toc_check_entry_for_uid (cur->data, uid))
656 * gst_toc_find_entry:
657 * @toc: #GstToc to search in.
658 * @uid: UID to find #GstTocEntry with.
660 * Find #GstTocEntry with given @uid in the @toc.
662 * Returns: #GstTocEntry with specified @uid from the @toc, or NULL if not found.
667 gst_toc_find_entry (const GstToc * toc, const gchar * uid)
671 g_return_val_if_fail (toc != NULL, NULL);
672 g_return_val_if_fail (uid != NULL, NULL);
675 while (cur != NULL) {
676 if (gst_toc_check_entry_for_uid (cur->data, uid))
685 * gst_toc_entry_copy:
686 * @entry: #GstTocEntry to copy.
688 * Copy #GstTocEntry with all subentries (deep copy).
690 * Returns: newly allocated #GstTocEntry in case of success, NULL otherwise;
691 * free it when done with gst_toc_entry_free().
696 gst_toc_entry_copy (const GstTocEntry * entry)
698 GstTocEntry *ret, *sub;
703 g_return_val_if_fail (entry != NULL, NULL);
705 ret = gst_toc_entry_new (entry->type, entry->uid);
707 if (GST_IS_STRUCTURE (entry->info)) {
708 st = gst_structure_copy (entry->info);
709 gst_structure_free (ret->info);
713 if (GST_IS_TAG_LIST (entry->tags)) {
714 list = gst_tag_list_copy (entry->tags);
715 gst_tag_list_unref (ret->tags);
720 while (cur != NULL) {
721 if (GST_IS_PAD (cur->data))
722 ret->pads = g_list_prepend (ret->pads, gst_object_ref (cur->data));
725 ret->pads = g_list_reverse (ret->pads);
727 cur = entry->subentries;
728 while (cur != NULL) {
729 sub = gst_toc_entry_copy (cur->data);
732 ret->subentries = g_list_prepend (ret->subentries, sub);
736 ret->subentries = g_list_reverse (ret->subentries);
743 * @toc: #GstToc to copy.
745 * Copy #GstToc with all subentries (deep copy).
747 * Returns: newly allocated #GstToc in case of success, NULL otherwise;
748 * free it when done with gst_toc_free().
753 gst_toc_copy (const GstToc * toc)
761 g_return_val_if_fail (toc != NULL, NULL);
763 ret = gst_toc_new ();
765 if (GST_IS_STRUCTURE (toc->info)) {
766 st = gst_structure_copy (toc->info);
767 gst_structure_free (ret->info);
771 if (GST_IS_TAG_LIST (toc->tags)) {
772 list = gst_tag_list_copy (toc->tags);
773 gst_tag_list_unref (ret->tags);
778 while (cur != NULL) {
779 entry = gst_toc_entry_copy (cur->data);
782 ret->entries = g_list_prepend (ret->entries, entry);
786 ret->entries = g_list_reverse (ret->entries);
792 * gst_toc_entry_set_start_stop:
793 * @entry: #GstTocEntry to set values.
794 * @start: start value to set.
795 * @stop: stop value to set.
797 * Set @start and @stop values for the @entry.
802 gst_toc_entry_set_start_stop (GstTocEntry * entry, gint64 start, gint64 stop)
805 GstStructure *structure = NULL;
807 g_return_if_fail (entry != NULL);
808 g_return_if_fail (GST_IS_STRUCTURE (entry->info));
810 if (gst_structure_id_has_field_typed (entry->info, GST_QUARK (TIME),
811 GST_TYPE_STRUCTURE)) {
812 val = gst_structure_id_get_value (entry->info, GST_QUARK (TIME));
813 structure = gst_structure_copy (gst_value_get_structure (val));
816 if (structure == NULL)
817 structure = gst_structure_new_id_empty (GST_QUARK (TIME_STRUCTURE));
819 gst_structure_id_set (structure, GST_QUARK (START),
820 G_TYPE_INT64, start, GST_QUARK (STOP), G_TYPE_INT64, stop, NULL);
822 gst_structure_id_set (entry->info, GST_QUARK (TIME),
823 GST_TYPE_STRUCTURE, structure, NULL);
825 gst_structure_free (structure);
829 * gst_toc_entry_get_start_stop:
830 * @entry: #GstTocEntry to get values from.
831 * @start: (out): the storage for the start value, leave #NULL if not need.
832 * @stop: (out): the storage for the stop value, leave #NULL if not need.
834 * Get start and stop values from the @entry and write them into appropriate storages.
836 * Returns: TRUE if all non-NULL storage pointers were filled with appropriate values,
842 gst_toc_entry_get_start_stop (const GstTocEntry * entry, gint64 * start,
847 const GstStructure *structure;
849 g_return_val_if_fail (entry != NULL, FALSE);
850 g_return_val_if_fail (GST_IS_STRUCTURE (entry->info), FALSE);
852 if (!gst_structure_id_has_field_typed (entry->info,
853 GST_QUARK (TIME), GST_TYPE_STRUCTURE))
856 val = gst_structure_id_get_value (entry->info, GST_QUARK (TIME));
857 structure = gst_value_get_structure (val);
860 if (gst_structure_id_has_field_typed (structure,
861 GST_QUARK (START), G_TYPE_INT64))
863 g_value_get_int64 (gst_structure_id_get_value (structure,
870 if (gst_structure_id_has_field_typed (structure,
871 GST_QUARK (STOP), G_TYPE_INT64))
873 g_value_get_int64 (gst_structure_id_get_value (structure,
883 * gst_toc_entry_type_get_nick:
884 * @type: a #GstTocEntryType.
886 * Converts @type to a string representation.
888 * Returns: Returns the human-readable @type. Can be NULL if an error occurred.
892 gst_toc_entry_type_get_nick (GstTocEntryType type)
894 const gchar *entry_types[] = { "chapter", "edition" };
896 g_return_val_if_fail ((gint) type >= 0
897 && (gint) type < G_N_ELEMENTS (entry_types), NULL);
898 return entry_types[type];
902 __gst_toc_structure_get_updated (const GstStructure * toc)
906 g_return_val_if_fail (GST_IS_STRUCTURE (toc), FALSE);
908 if (G_LIKELY (gst_structure_id_has_field_typed (toc,
909 GST_QUARK (UPDATED), G_TYPE_BOOLEAN))) {
910 val = gst_structure_id_get_value (toc, GST_QUARK (UPDATED));
911 return g_value_get_boolean (val);
918 __gst_toc_structure_set_updated (GstStructure * toc, gboolean updated)
920 g_return_if_fail (toc != NULL);
922 gst_structure_id_set (toc, GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated,
927 __gst_toc_structure_get_extend_uid (const GstStructure * toc)
931 g_return_val_if_fail (GST_IS_STRUCTURE (toc), NULL);
933 if (G_LIKELY (gst_structure_id_has_field_typed (toc,
934 GST_QUARK (EXTEND_UID), G_TYPE_STRING))) {
935 val = gst_structure_id_get_value (toc, GST_QUARK (EXTEND_UID));
936 return g_strdup (g_value_get_string (val));
943 __gst_toc_structure_set_extend_uid (GstStructure * toc,
944 const gchar * extend_uid)
946 g_return_if_fail (toc != NULL);
947 g_return_if_fail (extend_uid != NULL);
949 gst_structure_id_set (toc, GST_QUARK (EXTEND_UID), G_TYPE_STRING, extend_uid,