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"
74 #define GST_TOC_TOC_NAME "toc"
75 #define GST_TOC_ENTRY_NAME "entry"
77 #define GST_TOC_TOC_UPDATED_FIELD "updated"
78 #define GST_TOC_TOC_EXTENDUID_FIELD "extenduid"
79 #define GST_TOC_INFO_FIELD "info"
81 #define GST_TOC_ENTRY_UID_FIELD "uid"
82 #define GST_TOC_ENTRY_TYPE_FIELD "type"
83 #define GST_TOC_ENTRY_TAGS_FIELD "tags"
85 #define GST_TOC_TOC_ENTRIES_FIELD "subentries"
87 #define GST_TOC_INFO_NAME "info-structure"
88 #define GST_TOC_INFO_TIME_FIELD "time"
90 #define GST_TOC_TIME_NAME "time-structure"
91 #define GST_TOC_TIME_START_FIELD "start"
92 #define GST_TOC_TIME_STOP_FIELD "stop"
100 GST_TOC_EXTENDUID = 3,
104 GST_TOC_SUBENTRIES = 7,
106 GST_TOC_INFONAME = 9,
108 GST_TOC_TIMENAME = 11,
109 GST_TOC_TIME_START = 12,
110 GST_TOC_TIME_STOP = 13,
114 static GQuark gst_toc_fields[GST_TOC_LAST] = { 0 };
117 _priv_gst_toc_initialize (void)
119 static gboolean inited = FALSE;
121 if (G_LIKELY (!inited)) {
122 gst_toc_fields[GST_TOC_TOC] = g_quark_from_static_string (GST_TOC_TOC_NAME);
123 gst_toc_fields[GST_TOC_ENTRY] =
124 g_quark_from_static_string (GST_TOC_ENTRY_NAME);
126 gst_toc_fields[GST_TOC_UPDATED] =
127 g_quark_from_static_string (GST_TOC_TOC_UPDATED_FIELD);
128 gst_toc_fields[GST_TOC_EXTENDUID] =
129 g_quark_from_static_string (GST_TOC_TOC_EXTENDUID_FIELD);
130 gst_toc_fields[GST_TOC_INFO] =
131 g_quark_from_static_string (GST_TOC_INFO_FIELD);
133 gst_toc_fields[GST_TOC_UID] =
134 g_quark_from_static_string (GST_TOC_ENTRY_UID_FIELD);
135 gst_toc_fields[GST_TOC_TYPE] =
136 g_quark_from_static_string (GST_TOC_ENTRY_TYPE_FIELD);
137 gst_toc_fields[GST_TOC_TAGS] =
138 g_quark_from_static_string (GST_TOC_ENTRY_TAGS_FIELD);
140 gst_toc_fields[GST_TOC_SUBENTRIES] =
141 g_quark_from_static_string (GST_TOC_TOC_ENTRIES_FIELD);
143 gst_toc_fields[GST_TOC_INFONAME] =
144 g_quark_from_static_string (GST_TOC_INFO_NAME);
145 gst_toc_fields[GST_TOC_TIME] =
146 g_quark_from_static_string (GST_TOC_INFO_TIME_FIELD);
147 gst_toc_fields[GST_TOC_TIMENAME] =
148 g_quark_from_static_string (GST_TOC_TIME_NAME);
149 gst_toc_fields[GST_TOC_TIME_START] =
150 g_quark_from_static_string (GST_TOC_TIME_START_FIELD);
151 gst_toc_fields[GST_TOC_TIME_STOP] =
152 g_quark_from_static_string (GST_TOC_TIME_STOP_FIELD);
161 * Create new #GstToc structure.
163 * Returns: newly allocated #GstToc structure, free it with gst_toc_free().
172 toc = g_slice_new0 (GstToc);
173 toc->tags = gst_tag_list_new_empty ();
174 toc->info = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_INFONAME]);
182 * @uid: unique ID (UID) in the whole TOC.
184 * Create new #GstTocEntry structure.
186 * Returns: newly allocated #GstTocEntry structure, free it with gst_toc_entry_free().
191 gst_toc_entry_new (GstTocEntryType type, const gchar * uid)
195 g_return_val_if_fail (uid != NULL, NULL);
197 entry = g_slice_new0 (GstTocEntry);
198 entry->uid = g_strdup (uid);
200 entry->tags = gst_tag_list_new_empty ();
201 entry->info = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_INFONAME]);
207 * gst_toc_entry_new_with_pad:
209 * @uid: unique ID (UID) in the whole TOC.
210 * @pad: #GstPad related to this entry.
212 * Create new #GstTocEntry structure with #GstPad related.
214 * Returns: newly allocated #GstTocEntry structure, free it with gst_toc_entry_free()
220 gst_toc_entry_new_with_pad (GstTocEntryType type, const gchar * uid,
225 g_return_val_if_fail (uid != NULL, NULL);
227 entry = g_slice_new0 (GstTocEntry);
228 entry->uid = g_strdup (uid);
230 entry->tags = gst_tag_list_new_empty ();
231 entry->info = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_INFONAME]);
233 if (pad != NULL && GST_IS_PAD (pad))
234 entry->pads = g_list_append (entry->pads, gst_object_ref (pad));
241 * @toc: #GstToc structure to free.
243 * Free unused #GstToc structure.
248 gst_toc_free (GstToc * toc)
250 g_return_if_fail (toc != NULL);
252 g_list_foreach (toc->entries, (GFunc) gst_toc_entry_free, NULL);
253 g_list_free (toc->entries);
255 if (toc->tags != NULL)
256 gst_tag_list_free (toc->tags);
258 if (toc->info != NULL)
259 gst_structure_free (toc->info);
261 g_slice_free (GstToc, toc);
265 * gst_toc_entry_free:
266 * @entry: #GstTocEntry structure to free.
268 * Free unused #GstTocEntry structure. Note that #GstTocEntry.uid will
269 * be freed with g_free() and all #GstPad objects in the #GstTocEntry.pads
270 * list will be unrefed with gst_object_unref().
275 gst_toc_entry_free (GstTocEntry * entry)
279 g_return_if_fail (entry != NULL);
281 g_list_foreach (entry->subentries, (GFunc) gst_toc_entry_free, NULL);
282 g_list_free (entry->subentries);
286 if (entry->tags != NULL)
287 gst_tag_list_free (entry->tags);
289 if (entry->info != NULL)
290 gst_structure_free (entry->info);
293 while (cur != NULL) {
294 if (GST_IS_PAD (cur->data))
295 gst_object_unref (cur->data);
299 g_list_free (entry->pads);
301 g_slice_free (GstTocEntry, entry);
304 static GstStructure *
305 gst_toc_structure_new (GstTagList * tags, GstStructure * info)
310 ret = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_TOC]);
313 g_value_init (&val, GST_TYPE_STRUCTURE);
314 gst_value_set_structure (&val, GST_STRUCTURE (tags));
315 gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_TAGS], &val);
316 g_value_unset (&val);
320 g_value_init (&val, GST_TYPE_STRUCTURE);
321 gst_value_set_structure (&val, info);
322 gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_INFO], &val);
323 g_value_unset (&val);
329 static GstStructure *
330 gst_toc_entry_structure_new (GstTocEntryType type, const gchar * uid,
331 GstTagList * tags, GstStructure * info)
336 ret = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_ENTRY]);
338 gst_structure_id_set (ret, gst_toc_fields[GST_TOC_TYPE],
339 GST_TYPE_TOC_ENTRY_TYPE, type, NULL);
341 g_value_init (&val, G_TYPE_STRING);
342 g_value_set_string (&val, uid);
343 gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_UID], &val);
344 g_value_unset (&val);
347 g_value_init (&val, GST_TYPE_STRUCTURE);
348 gst_value_set_structure (&val, GST_STRUCTURE (tags));
349 gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_TAGS], &val);
350 g_value_unset (&val);
354 g_value_init (&val, GST_TYPE_STRUCTURE);
355 gst_value_set_structure (&val, info);
356 gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_INFO], &val);
357 g_value_unset (&val);
364 gst_toc_entry_structure_n_subentries (const GstStructure * entry)
366 if (G_UNLIKELY (!gst_structure_id_has_field_typed (entry,
367 gst_toc_fields[GST_TOC_SUBENTRIES], GST_TYPE_ARRAY)))
370 return gst_value_array_get_size ((gst_structure_id_get_value (entry,
371 gst_toc_fields[GST_TOC_SUBENTRIES])));
374 static const GstStructure *
375 gst_toc_entry_structure_nth_subentry (const GstStructure * entry, guint nth)
380 count = gst_toc_entry_structure_n_subentries (entry);
385 if (G_UNLIKELY (!gst_structure_id_has_field_typed (entry,
386 gst_toc_fields[GST_TOC_SUBENTRIES], GST_TYPE_ARRAY)))
390 gst_value_array_get_value (gst_structure_id_get_value (entry,
391 gst_toc_fields[GST_TOC_SUBENTRIES]), nth);
392 return gst_value_get_structure (array);
397 gst_toc_entry_from_structure (const GstStructure * entry, guint level)
399 GstTocEntry *ret, *subentry;
401 const GstStructure *subentry_struct;
406 guint chapters_count = 0, editions_count = 0;
408 g_return_val_if_fail (entry != NULL, NULL);
409 g_return_val_if_fail (gst_structure_id_has_field_typed (entry,
410 gst_toc_fields[GST_TOC_UID], G_TYPE_STRING), NULL);
411 g_return_val_if_fail (gst_structure_id_has_field_typed (entry,
412 gst_toc_fields[GST_TOC_TYPE], GST_TYPE_TOC_ENTRY_TYPE), NULL);
414 val = gst_structure_id_get_value (entry, gst_toc_fields[GST_TOC_UID]);
415 uid = g_value_get_string (val);
417 ret = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, uid);
419 gst_structure_get_enum (entry, GST_TOC_ENTRY_TYPE_FIELD,
420 GST_TYPE_TOC_ENTRY_TYPE, (gint *) & (ret->type));
422 if (gst_structure_id_has_field_typed (entry,
423 gst_toc_fields[GST_TOC_SUBENTRIES], GST_TYPE_ARRAY)) {
424 count = gst_toc_entry_structure_n_subentries (entry);
426 for (i = 0; i < count; ++i) {
427 subentry_struct = gst_toc_entry_structure_nth_subentry (entry, i);
428 subentry = gst_toc_entry_from_structure (subentry_struct, level + 1);
430 /* skip empty editions */
431 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
432 && subentry->subentries == NULL)) {
434 ("Empty edition found while deserializing TOC from GstStructure, skipping");
438 if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION)
443 /* check for mixed content */
444 if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) {
446 ("Mixed editions and chapters in the TOC contents, the TOC is broken");
447 gst_toc_entry_free (subentry);
448 gst_toc_entry_free (ret);
452 if (G_UNLIKELY (subentry == NULL)) {
453 gst_toc_entry_free (ret);
457 ret->subentries = g_list_prepend (ret->subentries, subentry);
460 ret->subentries = g_list_reverse (ret->subentries);
463 if (gst_structure_id_has_field_typed (entry,
464 gst_toc_fields[GST_TOC_TAGS], GST_TYPE_STRUCTURE)) {
465 val = gst_structure_id_get_value (entry, gst_toc_fields[GST_TOC_TAGS]);
467 if (G_LIKELY (GST_IS_TAG_LIST (gst_value_get_structure (val)))) {
468 list = gst_tag_list_copy (GST_TAG_LIST (gst_value_get_structure (val)));
469 gst_tag_list_free (ret->tags);
474 if (gst_structure_id_has_field_typed (entry,
475 gst_toc_fields[GST_TOC_INFO], GST_TYPE_STRUCTURE)) {
476 val = gst_structure_id_get_value (entry, gst_toc_fields[GST_TOC_INFO]);
478 if (G_LIKELY (GST_IS_STRUCTURE (gst_value_get_structure (val)))) {
479 st = gst_structure_copy (gst_value_get_structure (val));
480 gst_structure_free (ret->info);
489 __gst_toc_from_structure (const GstStructure * toc)
492 GstTocEntry *subentry;
493 const GstStructure *subentry_struct;
498 guint editions_count = 0, chapters_count = 0;
500 g_return_val_if_fail (toc != NULL, NULL);
502 ret = gst_toc_new ();
504 if (gst_structure_id_has_field_typed (toc,
505 gst_toc_fields[GST_TOC_SUBENTRIES], GST_TYPE_ARRAY)) {
506 count = gst_toc_entry_structure_n_subentries (toc);
508 for (i = 0; i < count; ++i) {
509 subentry_struct = gst_toc_entry_structure_nth_subentry (toc, i);
510 subentry = gst_toc_entry_from_structure (subentry_struct, 0);
512 /* skip empty editions */
513 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
514 && subentry->subentries == NULL)) {
516 ("Empty edition found while deserializing TOC from GstStructure, skipping");
520 /* check for success */
521 if (G_UNLIKELY (subentry == NULL)) {
522 g_critical ("Couldn't serialize deserializing TOC from GstStructure");
527 if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION)
532 /* check for mixed content */
533 if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) {
535 ("Mixed editions and chapters in the TOC contents, the TOC is broken");
536 gst_toc_entry_free (subentry);
541 ret->entries = g_list_prepend (ret->entries, subentry);
544 ret->entries = g_list_reverse (ret->entries);
547 if (gst_structure_id_has_field_typed (toc,
548 gst_toc_fields[GST_TOC_TAGS], GST_TYPE_STRUCTURE)) {
549 val = gst_structure_id_get_value (toc, gst_toc_fields[GST_TOC_TAGS]);
551 if (G_LIKELY (GST_IS_TAG_LIST (gst_value_get_structure (val)))) {
552 list = gst_tag_list_copy (GST_TAG_LIST (gst_value_get_structure (val)));
553 gst_tag_list_free (ret->tags);
558 if (gst_structure_id_has_field_typed (toc,
559 gst_toc_fields[GST_TOC_INFO], GST_TYPE_STRUCTURE)) {
560 val = gst_structure_id_get_value (toc, gst_toc_fields[GST_TOC_INFO]);
562 if (G_LIKELY (GST_IS_STRUCTURE (gst_value_get_structure (val)))) {
563 st = gst_structure_copy (gst_value_get_structure (val));
564 gst_structure_free (ret->info);
569 if (G_UNLIKELY (ret->entries == NULL)) {
577 static GstStructure *
578 gst_toc_entry_to_structure (const GstTocEntry * entry, guint level)
580 GstStructure *ret, *subentry_struct;
581 GstTocEntry *subentry;
583 GValue subentries_val = { 0 };
584 GValue entry_val = { 0 };
585 guint chapters_count = 0, editions_count = 0;
587 g_return_val_if_fail (entry != NULL, NULL);
590 gst_toc_entry_structure_new (entry->type, entry->uid, entry->tags,
593 g_value_init (&subentries_val, GST_TYPE_ARRAY);
594 g_value_init (&entry_val, GST_TYPE_STRUCTURE);
596 cur = entry->subentries;
597 while (cur != NULL) {
598 subentry = cur->data;
600 if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION)
605 /* check for mixed content */
606 if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) {
608 ("Mixed editions and chapters in the TOC contents, the TOC is broken");
609 gst_structure_free (ret);
610 g_value_unset (&entry_val);
611 g_value_unset (&subentries_val);
615 /* skip empty editions */
616 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
617 && subentry->subentries == NULL)) {
619 ("Empty edition found while serializing TOC to GstStructure, skipping");
624 subentry_struct = gst_toc_entry_to_structure (subentry, level + 1);
626 /* check for success */
627 if (G_UNLIKELY (subentry_struct == NULL)) {
628 gst_structure_free (ret);
629 g_value_unset (&subentries_val);
630 g_value_unset (&entry_val);
634 /* skip empty editions */
635 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
636 && subentry->subentries == NULL)) {
638 ("Empty edition found while serializing TOC to GstStructure, skipping");
643 gst_value_set_structure (&entry_val, subentry_struct);
644 gst_value_array_append_value (&subentries_val, &entry_val);
645 gst_structure_free (subentry_struct);
650 gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_SUBENTRIES],
653 g_value_unset (&subentries_val);
654 g_value_unset (&entry_val);
659 __gst_toc_to_structure (const GstToc * toc)
662 GValue subentries_val = { 0 };
663 GstStructure *ret, *subentry_struct;
664 GstTocEntry *subentry;
666 guint editions_count = 0, chapters_count = 0;
668 g_return_val_if_fail (toc != NULL, NULL);
669 g_return_val_if_fail (toc->entries != NULL, NULL);
671 ret = gst_toc_structure_new (toc->tags, toc->info);
673 g_value_init (&val, GST_TYPE_STRUCTURE);
674 g_value_init (&subentries_val, GST_TYPE_ARRAY);
677 while (cur != NULL) {
678 subentry = cur->data;
680 if (subentry->type == GST_TOC_ENTRY_TYPE_EDITION)
685 /* check for mixed content */
686 if (G_UNLIKELY (chapters_count > 0 && editions_count > 0)) {
688 ("Mixed editions and chapters in the TOC contents, the TOC is broken");
689 gst_structure_free (ret);
690 g_value_unset (&val);
691 g_value_unset (&subentries_val);
695 /* skip empty editions */
696 if (G_UNLIKELY (subentry->type == GST_TOC_ENTRY_TYPE_EDITION
697 && subentry->subentries == NULL)) {
699 ("Empty edition found while serializing TOC to GstStructure, skipping");
704 subentry_struct = gst_toc_entry_to_structure (subentry, 0);
706 /* check for success */
707 if (G_UNLIKELY (subentry_struct == NULL)) {
708 g_critical ("Couldn't serialize TOC to GstStructure");
709 gst_structure_free (ret);
710 g_value_unset (&val);
711 g_value_unset (&subentries_val);
715 gst_value_set_structure (&val, subentry_struct);
716 gst_value_array_append_value (&subentries_val, &val);
717 gst_structure_free (subentry_struct);
722 gst_structure_id_set_value (ret, gst_toc_fields[GST_TOC_SUBENTRIES],
725 g_value_unset (&val);
726 g_value_unset (&subentries_val);
731 gst_toc_check_entry_for_uid (const GstTocEntry * entry, const gchar * uid)
735 g_return_val_if_fail (entry != NULL, FALSE);
736 g_return_val_if_fail (uid != NULL, FALSE);
738 if (g_strcmp0 (entry->uid, uid) == 0)
741 cur = entry->subentries;
742 while (cur != NULL) {
743 if (gst_toc_check_entry_for_uid (cur->data, uid))
752 * gst_toc_find_entry:
753 * @toc: #GstToc to search in.
754 * @uid: UID to find #GstTocEntry with.
756 * Find #GstTocEntry with given @uid in the @toc.
758 * Returns: #GstTocEntry with specified @uid from the @toc, or NULL if not found.
763 gst_toc_find_entry (const GstToc * toc, const gchar * uid)
767 g_return_val_if_fail (toc != NULL, NULL);
768 g_return_val_if_fail (uid != NULL, NULL);
771 while (cur != NULL) {
772 if (gst_toc_check_entry_for_uid (cur->data, uid))
781 * gst_toc_entry_copy:
782 * @entry: #GstTocEntry to copy.
784 * Copy #GstTocEntry with all subentries (deep copy).
786 * Returns: newly allocated #GstTocEntry in case of success, NULL otherwise;
787 * free it when done with gst_toc_entry_free().
792 gst_toc_entry_copy (const GstTocEntry * entry)
794 GstTocEntry *ret, *sub;
799 g_return_val_if_fail (entry != NULL, NULL);
801 ret = gst_toc_entry_new (entry->type, entry->uid);
803 if (GST_IS_STRUCTURE (entry->info)) {
804 st = gst_structure_copy (entry->info);
805 gst_structure_free (ret->info);
809 if (GST_IS_TAG_LIST (entry->tags)) {
810 list = gst_tag_list_copy (entry->tags);
811 gst_tag_list_free (ret->tags);
816 while (cur != NULL) {
817 if (GST_IS_PAD (cur->data))
818 ret->pads = g_list_prepend (ret->pads, gst_object_ref (cur->data));
821 ret->pads = g_list_reverse (ret->pads);
823 cur = entry->subentries;
824 while (cur != NULL) {
825 sub = gst_toc_entry_copy (cur->data);
828 ret->subentries = g_list_prepend (ret->subentries, sub);
832 ret->subentries = g_list_reverse (ret->subentries);
839 * @toc: #GstToc to copy.
841 * Copy #GstToc with all subentries (deep copy).
843 * Returns: newly allocated #GstToc in case of success, NULL otherwise;
844 * free it when done with gst_toc_free().
849 gst_toc_copy (const GstToc * toc)
857 g_return_val_if_fail (toc != NULL, NULL);
859 ret = gst_toc_new ();
861 if (GST_IS_STRUCTURE (toc->info)) {
862 st = gst_structure_copy (toc->info);
863 gst_structure_free (ret->info);
867 if (GST_IS_TAG_LIST (toc->tags)) {
868 list = gst_tag_list_copy (toc->tags);
869 gst_tag_list_free (ret->tags);
874 while (cur != NULL) {
875 entry = gst_toc_entry_copy (cur->data);
878 ret->entries = g_list_prepend (ret->entries, entry);
882 ret->entries = g_list_reverse (ret->entries);
888 * gst_toc_entry_set_start_stop:
889 * @entry: #GstTocEntry to set values.
890 * @start: start value to set.
891 * @stop: stop value to set.
893 * Set @start and @stop values for the @entry.
898 gst_toc_entry_set_start_stop (GstTocEntry * entry, gint64 start, gint64 stop)
901 GstStructure *structure = NULL;
903 g_return_if_fail (entry != NULL);
904 g_return_if_fail (GST_IS_STRUCTURE (entry->info));
906 if (gst_structure_id_has_field_typed (entry->info,
907 gst_toc_fields[GST_TOC_TIME], GST_TYPE_STRUCTURE)) {
909 gst_structure_id_get_value (entry->info, gst_toc_fields[GST_TOC_TIME]);
910 structure = gst_structure_copy (gst_value_get_structure (val));
913 if (structure == NULL)
914 structure = gst_structure_new_id_empty (gst_toc_fields[GST_TOC_TIMENAME]);
916 gst_structure_id_set (structure, gst_toc_fields[GST_TOC_TIME_START],
917 G_TYPE_INT64, start, gst_toc_fields[GST_TOC_TIME_STOP], G_TYPE_INT64,
920 gst_structure_id_set (entry->info, gst_toc_fields[GST_TOC_TIME],
921 GST_TYPE_STRUCTURE, structure, NULL);
923 gst_structure_free (structure);
927 * gst_toc_entry_get_start_stop:
928 * @entry: #GstTocEntry to get values from.
929 * @start: (out): the storage for the start value, leave #NULL if not need.
930 * @stop: (out): the storage for the stop value, leave #NULL if not need.
932 * Get start and stop values from the @entry and write them into appropriate storages.
934 * Returns: TRUE if all non-NULL storage pointers were filled with appropriate values,
940 gst_toc_entry_get_start_stop (const GstTocEntry * entry, gint64 * start,
945 const GstStructure *structure;
947 g_return_val_if_fail (entry != NULL, FALSE);
948 g_return_val_if_fail (GST_IS_STRUCTURE (entry->info), FALSE);
950 if (!gst_structure_id_has_field_typed (entry->info,
951 gst_toc_fields[GST_TOC_TIME], GST_TYPE_STRUCTURE))
954 val = gst_structure_id_get_value (entry->info, gst_toc_fields[GST_TOC_TIME]);
955 structure = gst_value_get_structure (val);
958 if (gst_structure_id_has_field_typed (structure,
959 gst_toc_fields[GST_TOC_TIME_START], G_TYPE_INT64))
961 g_value_get_int64 (gst_structure_id_get_value (structure,
962 gst_toc_fields[GST_TOC_TIME_START]));
968 if (gst_structure_id_has_field_typed (structure,
969 gst_toc_fields[GST_TOC_TIME_STOP], G_TYPE_INT64))
971 g_value_get_int64 (gst_structure_id_get_value (structure,
972 gst_toc_fields[GST_TOC_TIME_STOP]));
981 __gst_toc_structure_get_updated (const GstStructure * toc)
985 g_return_val_if_fail (GST_IS_STRUCTURE (toc), FALSE);
987 if (G_LIKELY (gst_structure_id_has_field_typed (toc,
988 gst_toc_fields[GST_TOC_UPDATED], G_TYPE_BOOLEAN))) {
989 val = gst_structure_id_get_value (toc, gst_toc_fields[GST_TOC_UPDATED]);
990 return g_value_get_boolean (val);
997 __gst_toc_structure_set_updated (GstStructure * toc, gboolean updated)
1001 g_return_if_fail (toc != NULL);
1003 g_value_init (&val, G_TYPE_BOOLEAN);
1004 g_value_set_boolean (&val, updated);
1005 gst_structure_id_set_value (toc, gst_toc_fields[GST_TOC_UPDATED], &val);
1006 g_value_unset (&val);
1010 __gst_toc_structure_get_extend_uid (const GstStructure * toc)
1014 g_return_val_if_fail (GST_IS_STRUCTURE (toc), NULL);
1016 if (G_LIKELY (gst_structure_id_has_field_typed (toc,
1017 gst_toc_fields[GST_TOC_EXTENDUID], G_TYPE_STRING))) {
1018 val = gst_structure_id_get_value (toc, gst_toc_fields[GST_TOC_EXTENDUID]);
1019 return g_strdup (g_value_get_string (val));
1026 __gst_toc_structure_set_extend_uid (GstStructure * toc,
1027 const gchar * extend_uid)
1031 g_return_if_fail (toc != NULL);
1032 g_return_if_fail (extend_uid != NULL);
1034 g_value_init (&val, G_TYPE_STRING);
1035 g_value_set_string (&val, extend_uid);
1036 gst_structure_id_set_value (toc, gst_toc_fields[GST_TOC_EXTENDUID], &val);
1037 g_value_unset (&val);