xml-formatter: Refactor the way we handle loading state

This commit is contained in:
Thibault Saunier 2019-06-15 16:44:50 -04:00
parent 33bac10cc8
commit 90943667ce

View file

@ -59,12 +59,24 @@ typedef struct PendingAsset
gchar *id; gchar *id;
} PendingAsset; } PendingAsset;
/* @STATE_CHECK_LOADABLE: Quickly check if XML is valid
* @STATE_ASSETS: start loading all assets asynchronously
* and setup all elements that are synchronously loadable (tracks, and layers basically).
* @STATE_LOADING_CLIPS: adding clips and groups to the timeline
*/
typedef enum
{
STATE_CHECK_LOADABLE,
STATE_LOADING_ASSETS_AND_SYNC,
STATE_LOADING_CLIPS,
} LoadingState;
struct _GESBaseXmlFormatterPrivate struct _GESBaseXmlFormatterPrivate
{ {
GMarkupParseContext *parsecontext; GMarkupParseContext *parsecontext;
gchar *xmlcontent; gchar *xmlcontent;
gsize xmlsize; gsize xmlsize;
gboolean check_only; LoadingState state;
/* Clip.ID -> Clip */ /* Clip.ID -> Clip */
GHashTable *containers; GHashTable *containers;
@ -86,20 +98,26 @@ struct _GESBaseXmlFormatterPrivate
gboolean timeline_auto_transition; gboolean timeline_auto_transition;
GList *groups; GList *groups;
/* %TRUE if running the first pass, %FALSE otherwise.
* During the first pass we start loading all assets asynchronously
* and setup all elements that are synchronously loadable (tracks, and layers basically).
*
* In the second pass we add clips and groups o the timeline
*/
gboolean first_pass;
}; };
static void new_asset_cb (GESAsset * source, GAsyncResult * res, static void new_asset_cb (GESAsset * source, GAsyncResult * res,
PendingAsset * passet); PendingAsset * passet);
static const gchar *
loading_state_name (LoadingState state)
{
switch (state) {
case STATE_CHECK_LOADABLE:
return "check-loadable";
case STATE_LOADING_ASSETS_AND_SYNC:
return "loading-assets-and-sync";
case STATE_LOADING_CLIPS:
return "loading-clips";
}
return "??";
}
static void static void
_free_layer_entry (LayerEntry * entry) _free_layer_entry (LayerEntry * entry)
@ -132,7 +150,7 @@ compare_assets_for_loading (PendingAsset * a, PendingAsset * b)
} }
static GMarkupParseContext * static GMarkupParseContext *
_parse (GESBaseXmlFormatter * self, GError ** error, gboolean first_pass) _parse (GESBaseXmlFormatter * self, GError ** error, LoadingState state)
{ {
GError *err = NULL; GError *err = NULL;
GMarkupParseContext *parsecontext = NULL; GMarkupParseContext *parsecontext = NULL;
@ -150,8 +168,8 @@ _parse (GESBaseXmlFormatter * self, GError ** error, gboolean first_pass)
parsecontext = g_markup_parse_context_new (&self_class->content_parser, parsecontext = g_markup_parse_context_new (&self_class->content_parser,
G_MARKUP_TREAT_CDATA_AS_TEXT, self, NULL); G_MARKUP_TREAT_CDATA_AS_TEXT, self, NULL);
priv->first_pass = first_pass; priv->state = state;
GST_DEBUG_OBJECT (self, "Running %s pass", first_pass ? "first" : "second"); GST_DEBUG_OBJECT (self, "Running %s pass", loading_state_name (state));
if (!g_markup_parse_context_parse (parsecontext, priv->xmlcontent, if (!g_markup_parse_context_parse (parsecontext, priv->xmlcontent,
priv->xmlsize, &err)) priv->xmlsize, &err))
goto failed; goto failed;
@ -191,7 +209,7 @@ failed:
static GMarkupParseContext * static GMarkupParseContext *
_load_and_parse (GESBaseXmlFormatter * self, const gchar * uri, GError ** error, _load_and_parse (GESBaseXmlFormatter * self, const gchar * uri, GError ** error,
gboolean first_pass) LoadingState state)
{ {
GFile *file = NULL; GFile *file = NULL;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
@ -213,7 +231,7 @@ _load_and_parse (GESBaseXmlFormatter * self, const gchar * uri, GError ** error,
NULL, &err)) NULL, &err))
goto failed; goto failed;
return _parse (self, error, first_pass); return _parse (self, error, state);
failed: failed:
GST_WARNING ("failed to load contents from \"%s\"", uri); GST_WARNING ("failed to load contents from \"%s\"", uri);
@ -234,11 +252,7 @@ _can_load_uri (GESFormatter * dummy_formatter, const gchar * uri,
GMarkupParseContext *ctx; GMarkupParseContext *ctx;
GESBaseXmlFormatter *self = GES_BASE_XML_FORMATTER (dummy_formatter); GESBaseXmlFormatter *self = GES_BASE_XML_FORMATTER (dummy_formatter);
/* we create a temporary object so we can use it as a context */ ctx = _load_and_parse (self, uri, error, STATE_CHECK_LOADABLE);
_GET_PRIV (self)->check_only = TRUE;
ctx = _load_and_parse (self, uri, error, TRUE);
if (!ctx) if (!ctx)
return FALSE; return FALSE;
@ -255,7 +269,8 @@ _load_from_uri (GESFormatter * self, GESTimeline * timeline, const gchar * uri,
ges_timeline_set_auto_transition (timeline, FALSE); ges_timeline_set_auto_transition (timeline, FALSE);
priv->parsecontext = priv->parsecontext =
_load_and_parse (GES_BASE_XML_FORMATTER (self), uri, error, TRUE); _load_and_parse (GES_BASE_XML_FORMATTER (self), uri, error,
STATE_LOADING_ASSETS_AND_SYNC);
if (!priv->parsecontext) if (!priv->parsecontext)
return FALSE; return FALSE;
@ -379,7 +394,6 @@ ges_base_xml_formatter_init (GESBaseXmlFormatter * self)
priv = self->priv; priv = self->priv;
priv->check_only = FALSE;
priv->parsecontext = NULL; priv->parsecontext = NULL;
priv->pending_assets = NULL; priv->pending_assets = NULL;
@ -482,9 +496,9 @@ _loading_done (GESFormatter * self)
} }
g_list_free_full (assets, g_object_unref); g_list_free_full (assets, g_object_unref);
if (priv->first_pass) { if (priv->state == STATE_LOADING_ASSETS_AND_SYNC) {
GST_INFO_OBJECT (self, "Assets cached... now loading the timeline."); GST_INFO_OBJECT (self, "Assets cached... now loading the timeline.");
_parse (GES_BASE_XML_FORMATTER (self), NULL, FALSE); _parse (GES_BASE_XML_FORMATTER (self), NULL, STATE_LOADING_CLIPS);
g_assert (priv->pending_assets == NULL); g_assert (priv->pending_assets == NULL);
} }
@ -803,15 +817,13 @@ ges_base_xml_formatter_add_asset (GESBaseXmlFormatter * self,
PendingAsset *passet; PendingAsset *passet;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (!priv->first_pass) { if (priv->state != STATE_LOADING_ASSETS_AND_SYNC) {
GST_INFO ("Already parsed assets"); GST_INFO ("Not parsing assets in %s state",
loading_state_name (priv->state));
return; return;
} }
if (priv->check_only)
return;
passet = g_slice_new0 (PendingAsset); passet = g_slice_new0 (PendingAsset);
passet->metadatas = g_strdup (metadatas); passet->metadatas = g_strdup (metadatas);
passet->id = g_strdup (id); passet->id = g_strdup (id);
@ -836,14 +848,12 @@ ges_base_xml_formatter_add_clip (GESBaseXmlFormatter * self,
LayerEntry *entry; LayerEntry *entry;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (priv->first_pass) { if (priv->state != STATE_LOADING_CLIPS) {
GST_DEBUG_OBJECT (self, "First pass, not adding clip related objects"); GST_DEBUG_OBJECT (self, "Not adding clip in %s state.",
loading_state_name (priv->state));
return; return;
} }
if (priv->check_only)
return;
entry = g_hash_table_lookup (priv->layers, GINT_TO_POINTER (layer_prio)); entry = g_hash_table_lookup (priv->layers, GINT_TO_POINTER (layer_prio));
if (entry == NULL) { if (entry == NULL) {
g_set_error (error, GES_ERROR, GES_ERROR_FORMATTER_MALFORMED_INPUT_FILE, g_set_error (error, GES_ERROR, GES_ERROR_FORMATTER_MALFORMED_INPUT_FILE,
@ -917,14 +927,12 @@ ges_base_xml_formatter_add_layer (GESBaseXmlFormatter * self,
gboolean auto_transition = FALSE; gboolean auto_transition = FALSE;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (!priv->first_pass) { if (priv->state != STATE_LOADING_ASSETS_AND_SYNC) {
GST_INFO_OBJECT (self, "Second pass, layers are already loaded."); GST_INFO_OBJECT (self, "Not loading layer in %s state.",
loading_state_name (priv->state));
return; return;
} }
if (priv->check_only)
return;
if (extractable_type == G_TYPE_NONE) if (extractable_type == G_TYPE_NONE)
layer = ges_layer_new (); layer = ges_layer_new ();
else { else {
@ -971,12 +979,9 @@ ges_base_xml_formatter_add_track (GESBaseXmlFormatter * self,
GESTrack *track; GESTrack *track;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (!priv->first_pass) { if (priv->state != STATE_LOADING_ASSETS_AND_SYNC) {
GST_DEBUG_OBJECT (self, "Second pass, tracks are already set."); GST_INFO_OBJECT (self, "Not loading track in %s state.",
return; loading_state_name (priv->state));
}
if (priv->check_only) {
return; return;
} }
@ -1016,8 +1021,9 @@ ges_base_xml_formatter_add_control_binding (GESBaseXmlFormatter * self,
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
GESTrackElement *element = NULL; GESTrackElement *element = NULL;
if (priv->first_pass) { if (priv->state != STATE_LOADING_CLIPS) {
GST_DEBUG_OBJECT (self, "First pass, not adding clip related objects"); GST_DEBUG_OBJECT (self, "Not loading control bindings in %s state.",
loading_state_name (priv->state));
return; return;
} }
@ -1053,8 +1059,9 @@ ges_base_xml_formatter_add_source (GESBaseXmlFormatter * self,
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
GESTrackElement *element = NULL; GESTrackElement *element = NULL;
if (priv->first_pass) { if (priv->state == STATE_LOADING_CLIPS) {
GST_DEBUG_OBJECT (self, "First pass, not adding clip related objects"); GST_DEBUG_OBJECT (self, "Not loading source elements in %s state.",
loading_state_name (priv->state));
return; return;
} }
@ -1085,14 +1092,12 @@ ges_base_xml_formatter_add_track_element (GESBaseXmlFormatter * self,
GESAsset *asset = NULL; GESAsset *asset = NULL;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (priv->first_pass) { if (priv->state != STATE_LOADING_CLIPS) {
GST_INFO_OBJECT (self, "First pass, not adding clip related objects"); GST_DEBUG_OBJECT (self, "Not loading track elements in %s state.",
loading_state_name (priv->state));
return; return;
} }
if (priv->check_only)
return;
if (g_type_is_a (track_element_type, GES_TYPE_TRACK_ELEMENT) == FALSE) { if (g_type_is_a (track_element_type, GES_TYPE_TRACK_ELEMENT) == FALSE) {
GST_DEBUG_OBJECT (self, "%s is not a TrackElement, can not create it", GST_DEBUG_OBJECT (self, "%s is not a TrackElement, can not create it",
g_type_name (track_element_type)); g_type_name (track_element_type));
@ -1152,15 +1157,12 @@ ges_base_xml_formatter_add_encoding_profile (GESBaseXmlFormatter * self,
GstEncodingContainerProfile *parent_profile = NULL; GstEncodingContainerProfile *parent_profile = NULL;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (!priv->first_pass) { if (priv->state != STATE_LOADING_ASSETS_AND_SYNC) {
GST_DEBUG_OBJECT (self, GST_DEBUG_OBJECT (self, "Not loading encoding profiles in %s state.",
"Second pass, encoding profiles are already ready."); loading_state_name (priv->state));
return; return;
} }
if (priv->check_only)
goto done;
if (parent == NULL) { if (parent == NULL) {
profile = profile =
_create_profile (self, type, parent, name, description, format, preset, _create_profile (self, type, parent, name, description, format, preset,
@ -1220,14 +1222,12 @@ ges_base_xml_formatter_add_group (GESBaseXmlFormatter * self,
PendingGroup *pgroup; PendingGroup *pgroup;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (!priv->first_pass) { if (priv->state != STATE_LOADING_ASSETS_AND_SYNC) {
GST_DEBUG_OBJECT (self, "First pass, not adding clip related objects"); GST_DEBUG_OBJECT (self, "Not loading groups in %s state.",
loading_state_name (priv->state));
return; return;
} }
if (priv->check_only)
return;
pgroup = g_slice_new0 (PendingGroup); pgroup = g_slice_new0 (PendingGroup);
pgroup->group = ges_group_new (); pgroup->group = ges_group_new ();
@ -1249,14 +1249,13 @@ ges_base_xml_formatter_last_group_add_child (GESBaseXmlFormatter * self,
PendingGroup *pgroup; PendingGroup *pgroup;
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (priv->first_pass) { if (priv->state != STATE_LOADING_CLIPS) {
GST_DEBUG_OBJECT (self, "First pass, not adding clip related objects"); GST_DEBUG_OBJECT (self, "Not adding children to groups in %s state.",
loading_state_name (priv->state));
return; return;
} }
if (priv->check_only)
return;
g_return_if_fail (priv->groups); g_return_if_fail (priv->groups);
pgroup = priv->groups->data; pgroup = priv->groups->data;