Commit 2c532aa8 authored by Tim-Philipp Müller's avatar Tim-Philipp Müller

toc: put toc directly into event/message/query structure

Now that TOCs are refcounted and have a GType, we can just
stuff a ref of the TOC directly into the various toc
event/message/query structures and get rid of lots of
cracktastic GstStructure <-> GstToc serialisation and
deserialisation code. We lose some TOC sanity checking
in the process, but that should really be done when
it's being created anyway.
parent 0cb9ad01
......@@ -114,15 +114,6 @@ void _priv_gst_tag_initialize (void);
void _priv_gst_value_initialize (void);
void _priv_gst_debug_init (void);
/* TOC functions */
/* These functions are used to parse TOC messages, events and queries */
GstToc* __gst_toc_from_structure (const GstStructure *toc);
GstStructure* __gst_toc_to_structure (const GstToc *toc);
gboolean __gst_toc_structure_get_updated (const GstStructure * toc);
void __gst_toc_structure_set_updated (GstStructure * toc, gboolean updated);
gchar* __gst_toc_structure_get_extend_uid (const GstStructure * toc);
void __gst_toc_structure_set_extend_uid (GstStructure * toc, const gchar * extend_uid);
/* Private registry functions */
gboolean _priv_gst_registry_remove_cache_plugins (GstRegistry *registry);
void _priv_gst_registry_cleanup (void);
......
......@@ -1632,13 +1632,13 @@ gst_event_new_stream_start (void)
/**
* gst_event_new_toc:
* @toc: #GstToc structure.
* @toc: (transfer none): #GstToc structure.
* @updated: whether @toc was updated or not.
*
* Generate a TOC event from the given @toc. The purpose of the TOC event is to
* inform elements that some kind of the TOC was found.
*
* Returns: a new #GstEvent.
* Returns: (transfer full): a new #GstEvent.
*
* Since: 0.10.37
*/
......@@ -1651,19 +1651,17 @@ gst_event_new_toc (GstToc * toc, gboolean updated)
GST_CAT_INFO (GST_CAT_EVENT, "creating toc event");
toc_struct = __gst_toc_to_structure (toc);
toc_struct = gst_structure_new_id (GST_QUARK (EVENT_TOC),
GST_QUARK (TOC), GST_TYPE_TOC, toc,
GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated, NULL);
if (G_LIKELY (toc_struct != NULL)) {
__gst_toc_structure_set_updated (toc_struct, updated);
return gst_event_new_custom (GST_EVENT_TOC, toc_struct);
} else
return NULL;
return gst_event_new_custom (GST_EVENT_TOC, toc_struct);
}
/**
* gst_event_parse_toc:
* @event: a TOC event.
* @toc: (out): pointer to #GstToc structure.
* @toc: (out) (transfer full): pointer to #GstToc structure.
* @updated: (out): pointer to store TOC updated flag.
*
* Parse a TOC @event and store the results in the given @toc and @updated locations.
......@@ -1680,10 +1678,10 @@ gst_event_parse_toc (GstEvent * event, GstToc ** toc, gboolean * updated)
g_return_if_fail (toc != NULL);
structure = gst_event_get_structure (event);
*toc = __gst_toc_from_structure (structure);
if (updated != NULL)
*updated = __gst_toc_structure_get_updated (structure);
gst_structure_id_get (structure,
GST_QUARK (TOC), GST_TYPE_TOC, toc,
GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated, NULL);
}
/**
......
......@@ -2174,13 +2174,13 @@ gst_message_parse_progress (GstMessage * message, GstProgressType * type,
/**
* gst_message_new_toc:
* @src: the object originating the message.
* @toc: #GstToc structure for the message.
* @toc: (transfer none): #GstToc structure for the message.
* @updated: whether TOC was updated or not.
*
* Create a new TOC message. The message is posted by elements
* that discovered or updated a TOC.
*
* Returns: a new TOC message.
* Returns: (transfer full): a new TOC message.
*
* MT safe.
*
......@@ -2193,24 +2193,22 @@ gst_message_new_toc (GstObject * src, GstToc * toc, gboolean updated)
g_return_val_if_fail (toc != NULL, NULL);
toc_struct = __gst_toc_to_structure (toc);
toc_struct = gst_structure_new_id (GST_QUARK (MESSAGE_TOC),
GST_QUARK (TOC), GST_TYPE_TOC, toc,
GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated, NULL);
if (G_LIKELY (toc_struct != NULL)) {
__gst_toc_structure_set_updated (toc_struct, updated);
return gst_message_new_custom (GST_MESSAGE_TOC, src, toc_struct);
} else
return NULL;
return gst_message_new_custom (GST_MESSAGE_TOC, src, toc_struct);
}
/**
* gst_message_parse_toc:
* @message: a valid #GstMessage of type GST_MESSAGE_TOC.
* @toc: (out): return location for the TOC.
* @toc: (out) (transfer full): return location for the TOC.
* @updated: (out): return location for the updated flag.
*
* Extract thef TOC from the #GstMessage. The TOC returned in the
* output argument is a copy; the caller must free it with
* gst_toc_free() when done.
* gst_toc_unref() when done.
*
* MT safe.
*
......@@ -2223,11 +2221,9 @@ gst_message_parse_toc (GstMessage * message, GstToc ** toc, gboolean * updated)
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_TOC);
g_return_if_fail (toc != NULL);
*toc = __gst_toc_from_structure (GST_MESSAGE_STRUCTURE (message));
if (updated != NULL)
*updated =
__gst_toc_structure_get_updated (GST_MESSAGE_STRUCTURE (message));
gst_structure_id_get (GST_MESSAGE_STRUCTURE (message),
GST_QUARK (TOC), GST_TYPE_TOC, toc,
GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated, NULL);
}
/**
......
......@@ -62,7 +62,8 @@ static const gchar *_quark_strings[] = {
GST_ELEMENT_METADATA_KLASS, GST_ELEMENT_METADATA_DESCRIPTION,
GST_ELEMENT_METADATA_AUTHOR, "toc", "toc-entry", "updated", "extend-uid",
"uid", "tags", "sub-entries", "info", "info-structure",
"time-structure", "GstMessageTag", "GstEventTag", "GstMessageResetTime"
"time-structure", "GstMessageTag", "GstEventTag", "GstMessageResetTime",
"GstMessageToc", "GstEventToc"
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];
......
......@@ -184,7 +184,9 @@ typedef enum _GstQuarkId
GST_QUARK_MESSAGE_TAG = 155,
GST_QUARK_EVENT_TAG = 156,
GST_QUARK_MESSAGE_RESET_TIME = 157,
GST_QUARK_MAX = 158
GST_QUARK_MESSAGE_TOC = 158,
GST_QUARK_EVENT_TOC = 159,
GST_QUARK_MAX = 160
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
......
......@@ -2359,7 +2359,7 @@ gst_query_new_toc (void)
/**
* gst_query_set_toc:
* @query: a #GstQuery with query type GST_QUERY_TOC.
* @toc: the GstToc to set.
* @toc: (transfer none): the GstToc to set.
* @extend_uid: UID which can be used for TOC extending (may be NULL),
* 0 means root TOC level.
*
......@@ -2368,43 +2368,29 @@ gst_query_new_toc (void)
void
gst_query_set_toc (GstQuery * query, GstToc * toc, const gchar * extend_uid)
{
GstStructure *structure;
GstStructure *old_structure;
g_return_if_fail (query != NULL);
g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_TOC);
g_return_if_fail (gst_query_is_writable (query));
g_return_if_fail (toc != NULL);
structure = __gst_toc_to_structure (toc);
g_return_if_fail (structure != NULL);
/* that shouldn't be happen in normal usage */
old_structure = GST_QUERY_STRUCTURE (query);
if (old_structure) {
gst_structure_set_parent_refcount (old_structure, NULL);
gst_structure_free (old_structure);
}
if (extend_uid != NULL)
__gst_toc_structure_set_extend_uid (structure, extend_uid);
gst_structure_set_parent_refcount (structure, &(query->mini_object.refcount));
GST_QUERY_STRUCTURE (query) = structure;
gst_structure_id_set (GST_QUERY_STRUCTURE (query),
GST_QUARK (TOC), GST_TYPE_TOC, toc,
GST_QUARK (EXTEND_UID), G_TYPE_STRING, extend_uid, NULL);
}
/**
* gst_query_parse_toc:
* @query: a #GstQuery.
* @toc: (out): the storage for the received TOC (may be NULL).
* @extend_uid: (out): the storage for the received extend UID marker (may be NULL),
* 0 means root TOC level.
* @toc: (out) (allow-none) (transfer full): the storage for the received
* TOC (may be NULL).
* @extend_uid: (out) (allow-none) (transfer full): the storage for the
received extend UID marker (may be NULL), 0 means root TOC level.
*
* Parse a TOC query, writing the TOC into @toc as a newly
* allocated #GstToc and extend UID into @extend_uid, if the respective parameters
* are non-NULL. Use @extend_uid value to insert new entries into the TOC (@extend_uid will
* act as root entry for newly inserted entries).
* Free @toc with gst_toc_free() and @extend_uid with g_free() after usage.
* are non-NULL. Use @extend_uid value to insert new entries into the TOC
* (@extend_uid will act as root entry for newly inserted entries).
* Free @toc with gst_toc_unref() and @extend_uid with g_free() after usage.
*/
void
gst_query_parse_toc (GstQuery * query, GstToc ** toc, gchar ** extend_uid)
......@@ -2416,11 +2402,7 @@ gst_query_parse_toc (GstQuery * query, GstToc ** toc, gchar ** extend_uid)
structure = gst_query_get_structure (query);
g_return_if_fail (structure != NULL);
if (toc != NULL)
*toc = __gst_toc_from_structure (structure);
if (extend_uid != NULL)
*extend_uid = __gst_toc_structure_get_extend_uid (structure);
gst_structure_id_get (structure,
GST_QUARK (TOC), GST_TYPE_TOC, toc,
GST_QUARK (EXTEND_UID), G_TYPE_STRING, extend_uid, NULL);
}
......@@ -218,414 +218,6 @@ gst_toc_entry_free (GstTocEntry * entry)
g_slice_free (GstTocEntry, entry);
}
static GstStructure *
gst_toc_structure_new (GstTagList * tags, GstStructure * info)
{
GstStructure *ret;
ret = gst_structure_new_id_empty (GST_QUARK (TOC));
if (tags != NULL) {
gst_structure_id_set (ret, GST_QUARK (TAGS), GST_TYPE_TAG_LIST, tags, NULL);
}
if (info != NULL) {
gst_structure_id_set (ret, GST_QUARK (INFO), GST_TYPE_STRUCTURE, info,
NULL);
}
return ret;
}
static GstStructure *
gst_toc_entry_structure_new (GstTocEntryType type, const gchar * uid,
GstTagList * tags, GstStructure * info)
{
GstStructure *ret;
ret = gst_structure_new_id_empty (GST_QUARK (TOC_ENTRY));
gst_structure_id_set (ret, GST_QUARK (TYPE), GST_TYPE_TOC_ENTRY_TYPE, type,
NULL);
gst_structure_id_set (ret, GST_QUARK (UID), G_TYPE_STRING, uid, NULL);
if (tags != NULL) {
gst_structure_id_set (ret, GST_QUARK (TAGS), GST_TYPE_TAG_LIST, tags, NULL);
}
if (info != NULL) {
gst_structure_id_set (ret, GST_QUARK (INFO), GST_TYPE_STRUCTURE, info,
NULL);
}
return ret;
}
static guint
gst_toc_entry_structure_n_subentries (const GstStructure * entry)
{
if (G_UNLIKELY (!gst_structure_id_has_field_typed (entry,
GST_QUARK (SUB_ENTRIES), GST_TYPE_ARRAY)))
return 0;
else
return gst_value_array_get_size ((gst_structure_id_get_value (entry,
GST_QUARK (SUB_ENTRIES))));
}
static const GstStructure *
gst_toc_entry_structure_nth_subentry (const GstStructure * entry, guint nth)
{
guint count;
const GValue *array;
count = gst_toc_entry_structure_n_subentries (entry);
if (count < nth)
return NULL;
if (G_UNLIKELY (!gst_structure_id_has_field_typed (entry,
GST_QUARK (SUB_ENTRIES), GST_TYPE_ARRAY)))
return NULL;
else {
array =
gst_value_array_get_value (gst_structure_id_get_value (entry,
GST_QUARK (SUB_ENTRIES)), nth);
return gst_value_get_structure (array);
}
}
static GstTocEntry *
gst_toc_entry_from_structure (const GstStructure * entry, guint level)
{
GstTocEntry *ret, *subentry;
const GValue *val;
const GstStructure *subentry_struct;
GstTagList *list;
GstStructure *st;
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_QUARK (UID), G_TYPE_STRING), NULL);
g_return_val_if_fail (gst_structure_id_has_field_typed (entry,
GST_QUARK (TYPE), GST_TYPE_TOC_ENTRY_TYPE), NULL);
val = gst_structure_id_get_value (entry, GST_QUARK (UID));
uid = g_value_get_string (val);
ret = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, uid);
gst_structure_get_enum (entry, g_quark_to_string (GST_QUARK (TYPE)),
GST_TYPE_TOC_ENTRY_TYPE, (gint *) & (ret->type));
if (gst_structure_id_has_field_typed (entry,
GST_QUARK (SUB_ENTRIES), 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_unref (subentry);
gst_toc_entry_unref (ret);
return NULL;
}
if (G_UNLIKELY (subentry == NULL)) {
gst_toc_entry_unref (ret);
return NULL;
}
ret->subentries = g_list_prepend (ret->subentries, subentry);
}
ret->subentries = g_list_reverse (ret->subentries);
}
if (gst_structure_id_has_field_typed (entry, GST_QUARK (TAGS),
GST_TYPE_TAG_LIST)) {
val = gst_structure_id_get_value (entry, GST_QUARK (TAGS));
if (G_LIKELY (GST_IS_TAG_LIST (g_value_get_boxed (val)))) {
list = gst_tag_list_copy (GST_TAG_LIST (g_value_get_boxed (val)));
gst_tag_list_unref (ret->tags);
ret->tags = list;
}
}
if (gst_structure_id_has_field_typed (entry,
GST_QUARK (INFO), GST_TYPE_STRUCTURE)) {
val = gst_structure_id_get_value (entry, GST_QUARK (INFO));
if (G_LIKELY (GST_IS_STRUCTURE (gst_value_get_structure (val)))) {
st = gst_structure_copy (gst_value_get_structure (val));
gst_structure_free (ret->info);
ret->info = st;
}
}
return ret;
}
GstToc *
__gst_toc_from_structure (const GstStructure * toc)
{
GstToc *ret;
GstTocEntry *subentry;
const GstStructure *subentry_struct;
const GValue *val;
GstTagList *list;
GstStructure *st;
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_QUARK (SUB_ENTRIES), 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_unref (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_QUARK (TAGS),
GST_TYPE_TAG_LIST)) {
val = gst_structure_id_get_value (toc, GST_QUARK (TAGS));
if (G_LIKELY (GST_IS_TAG_LIST (g_value_get_boxed (val)))) {
list = gst_tag_list_copy (GST_TAG_LIST (g_value_get_boxed (val)));
gst_tag_list_unref (ret->tags);
ret->tags = list;
}
}
if (gst_structure_id_has_field_typed (toc,
GST_QUARK (INFO), GST_TYPE_STRUCTURE)) {
val = gst_structure_id_get_value (toc, GST_QUARK (INFO));
if (G_LIKELY (GST_IS_STRUCTURE (gst_value_get_structure (val)))) {
st = gst_structure_copy (gst_value_get_structure (val));
gst_structure_free (ret->info);
ret->info = st;
}
}
if (G_UNLIKELY (ret->entries == NULL)) {
gst_toc_free (ret);
return NULL;
}
return ret;
}
static GstStructure *
gst_toc_entry_to_structure (const GstTocEntry * entry, guint level)
{
GstStructure *ret, *subentry_struct;
GstTocEntry *subentry;
GList *cur;
GValue subentries_val = { 0 };
GValue entry_val = { 0 };
guint chapters_count = 0, editions_count = 0;
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);
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_QUARK (SUB_ENTRIES), &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);
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);
cur = cur->next;
}
gst_structure_id_set_value (ret, GST_QUARK (SUB_ENTRIES), &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)
{
......@@ -947,56 +539,3 @@ gst_toc_entry_is_sequence (GstTocEntry * entry)
return GST_TOC_ENTRY_TYPE_IS_SEQUENCE (entry->type);
}