Commit 6f9e6d35 authored by Thibault Saunier's avatar Thibault Saunier 🌵

formatter: Enhance error reporting

And add a "loading-error" signal in GESProject so we can report
issue when loading async elements for the timeline.
parent c125093b
...@@ -88,6 +88,8 @@ struct _GESBaseXmlFormatterPrivate ...@@ -88,6 +88,8 @@ struct _GESBaseXmlFormatterPrivate
/* List of asset waited to be created */ /* List of asset waited to be created */
GList *pending_assets; GList *pending_assets;
GError *asset_error;
/* current track element */ /* current track element */
GESTrackElement *current_track_element; GESTrackElement *current_track_element;
...@@ -273,6 +275,7 @@ _load_from_uri (GESFormatter * self, GESTimeline * timeline, const gchar * uri, ...@@ -273,6 +275,7 @@ _load_from_uri (GESFormatter * self, GESTimeline * timeline, const gchar * uri,
{ {
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
GST_INFO_OBJECT (self, "Loading %s in %" GST_PTR_FORMAT, uri, timeline);
ges_timeline_set_auto_transition (timeline, FALSE); ges_timeline_set_auto_transition (timeline, FALSE);
priv->parsecontext = priv->parsecontext =
...@@ -431,7 +434,7 @@ ges_base_xml_formatter_class_init (GESBaseXmlFormatterClass * self_class) ...@@ -431,7 +434,7 @@ ges_base_xml_formatter_class_init (GESBaseXmlFormatterClass * self_class)
self_class->save = NULL; self_class->save = NULL;
GST_DEBUG_CATEGORY_INIT (base_xml_formatter, "base-xml-formatter", GST_DEBUG_CATEGORY_INIT (base_xml_formatter, "gesbasexmlformatter",
GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "Base XML Formatter"); GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "Base XML Formatter");
} }
...@@ -490,9 +493,9 @@ static void ...@@ -490,9 +493,9 @@ static void
_loading_done (GESFormatter * self) _loading_done (GESFormatter * self)
{ {
GList *assets, *tmp; GList *assets, *tmp;
GError *error = NULL;
GESBaseXmlFormatterPrivate *priv = GES_BASE_XML_FORMATTER (self)->priv; GESBaseXmlFormatterPrivate *priv = GES_BASE_XML_FORMATTER (self)->priv;
if (priv->parsecontext) if (priv->parsecontext)
g_markup_parse_context_free (priv->parsecontext); g_markup_parse_context_free (priv->parsecontext);
priv->parsecontext = NULL; priv->parsecontext = NULL;
...@@ -504,10 +507,16 @@ _loading_done (GESFormatter * self) ...@@ -504,10 +507,16 @@ _loading_done (GESFormatter * self)
} }
g_list_free_full (assets, g_object_unref); g_list_free_full (assets, g_object_unref);
if (priv->state == STATE_LOADING_ASSETS_AND_SYNC) { if (priv->asset_error) {
error = priv->asset_error;
priv->asset_error = NULL;
} else if (priv->state == STATE_LOADING_ASSETS_AND_SYNC) {
GMarkupParseContext *context =
_parse (GES_BASE_XML_FORMATTER (self), &error, STATE_LOADING_CLIPS);
GST_INFO_OBJECT (self, "Assets cached... now loading the timeline."); GST_INFO_OBJECT (self, "Assets cached... now loading the timeline.");
g_markup_parse_context_free (_parse (GES_BASE_XML_FORMATTER (self), NULL,
STATE_LOADING_CLIPS)); if (context)
g_markup_parse_context_free (context);
g_assert (priv->pending_assets == NULL); g_assert (priv->pending_assets == NULL);
} }
...@@ -516,7 +525,8 @@ _loading_done (GESFormatter * self) ...@@ -516,7 +525,8 @@ _loading_done (GESFormatter * self)
priv->timeline_auto_transition); priv->timeline_auto_transition);
g_hash_table_foreach (priv->layers, (GHFunc) _set_auto_transition, NULL); g_hash_table_foreach (priv->layers, (GHFunc) _set_auto_transition, NULL);
ges_project_set_loaded (self->project, self); ges_project_set_loaded (self->project, self, error);
g_clear_error (&error);
} }
static gboolean static gboolean
...@@ -565,14 +575,17 @@ _add_object_to_layer (GESBaseXmlFormatterPrivate * priv, const gchar * id, ...@@ -565,14 +575,17 @@ _add_object_to_layer (GESBaseXmlFormatterPrivate * priv, const gchar * id,
GESLayer * layer, GESAsset * asset, GstClockTime start, GESLayer * layer, GESAsset * asset, GstClockTime start,
GstClockTime inpoint, GstClockTime duration, GstClockTime inpoint, GstClockTime duration,
GESTrackType track_types, const gchar * metadatas, GESTrackType track_types, const gchar * metadatas,
GstStructure * properties, GstStructure * children_properties) GstStructure * properties, GstStructure * children_properties,
GError ** error)
{ {
GESClip *clip = ges_layer_add_asset (layer, GESClip *clip = ges_layer_add_asset (layer,
asset, start, inpoint, duration, track_types); asset, start, inpoint, duration, track_types);
if (clip == NULL) { if (clip == NULL) {
GST_WARNING_OBJECT (clip, "Could not add object from asset: %s", g_set_error (error, GES_ERROR, GES_ERROR_FORMATTER_MALFORMED_INPUT_FILE,
ges_asset_get_id (asset)); "Could not add clip %s [ %" GST_TIME_FORMAT ", ( %" GST_TIME_FORMAT
") - %" GST_TIME_FORMAT "]", id, GST_TIME_ARGS (start),
GST_TIME_ARGS (inpoint), GST_TIME_ARGS (duration));
return NULL; return NULL;
} }
...@@ -667,6 +680,8 @@ new_asset_cb (GESAsset * source, GAsyncResult * res, PendingAsset * passet) ...@@ -667,6 +680,8 @@ new_asset_cb (GESAsset * source, GAsyncResult * res, PendingAsset * passet)
error->message); error->message);
_free_pending_asset (priv, passet); _free_pending_asset (priv, passet);
if (!priv->asset_error)
priv->asset_error = g_error_copy (error);
goto done; goto done;
} }
...@@ -827,7 +842,7 @@ ges_base_xml_formatter_add_asset (GESBaseXmlFormatter * self, ...@@ -827,7 +842,7 @@ ges_base_xml_formatter_add_asset (GESBaseXmlFormatter * self,
GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
if (priv->state != STATE_LOADING_ASSETS_AND_SYNC) { if (priv->state != STATE_LOADING_ASSETS_AND_SYNC) {
GST_INFO ("Not parsing assets in %s state", GST_DEBUG_OBJECT (self, "Not parsing assets in %s state",
loading_state_name (priv->state)); loading_state_name (priv->state));
return; return;
...@@ -880,15 +895,14 @@ ges_base_xml_formatter_add_clip (GESBaseXmlFormatter * self, ...@@ -880,15 +895,14 @@ ges_base_xml_formatter_add_clip (GESBaseXmlFormatter * self,
asset = ges_asset_request (type, asset_id, NULL); asset = ges_asset_request (type, asset_id, NULL);
if (!asset) { if (!asset) {
g_set_error (error, GES_ERROR, GES_ERROR_FORMATTER_MALFORMED_INPUT_FILE, g_set_error (error, GES_ERROR, GES_ERROR_FORMATTER_MALFORMED_INPUT_FILE,
"Clip references asset %s which was not present in the list of ressource" "Clip references asset %s of type %s which was not present in the list of ressource,"
" the file seems to be malformed.", asset_id); " the file seems to be malformed.", asset_id, g_type_name (type));
GST_ERROR_OBJECT (self, "%s", (*error)->message);
return; return;
} }
nclip = _add_object_to_layer (priv, id, entry->layer, nclip = _add_object_to_layer (priv, id, entry->layer,
asset, start, inpoint, duration, track_types, metadatas, properties, asset, start, inpoint, duration, track_types, metadatas, properties,
children_properties); children_properties, error);
gst_object_unref (asset); gst_object_unref (asset);
if (!nclip) if (!nclip)
......
...@@ -229,7 +229,8 @@ _find_formatter_asset_for_id (const gchar *id); ...@@ -229,7 +229,8 @@ _find_formatter_asset_for_id (const gchar *id);
/* FIXME This should probably become public, but we need to make sure it /* FIXME This should probably become public, but we need to make sure it
* is the right API before doing so */ * is the right API before doing so */
G_GNUC_INTERNAL gboolean ges_project_set_loaded (GESProject * project, G_GNUC_INTERNAL gboolean ges_project_set_loaded (GESProject * project,
GESFormatter *formatter); GESFormatter *formatter,
GError *error);
G_GNUC_INTERNAL gchar * ges_project_try_updating_id (GESProject *self, G_GNUC_INTERNAL gchar * ges_project_try_updating_id (GESProject *self,
GESAsset *asset, GESAsset *asset,
GError *error); GError *error);
......
...@@ -437,7 +437,7 @@ track_element_added_cb (GESClip * clip, ...@@ -437,7 +437,7 @@ track_element_added_cb (GESClip * clip,
priv->sources_to_load = g_list_remove (priv->sources_to_load, clip); priv->sources_to_load = g_list_remove (priv->sources_to_load, clip);
if (!priv->sources_to_load && GES_FORMATTER (formatter)->project) if (!priv->sources_to_load && GES_FORMATTER (formatter)->project)
ges_project_set_loaded (GES_FORMATTER (formatter)->project, ges_project_set_loaded (GES_FORMATTER (formatter)->project,
GES_FORMATTER (formatter)); GES_FORMATTER (formatter), NULL);
} }
/* Disconnect the signal */ /* Disconnect the signal */
...@@ -668,7 +668,7 @@ load_pitivi_file_from_uri (GESFormatter * self, ...@@ -668,7 +668,7 @@ load_pitivi_file_from_uri (GESFormatter * self,
*/ */
if (!g_hash_table_size (priv->clips_table) && GES_FORMATTER (self)->project) { if (!g_hash_table_size (priv->clips_table) && GES_FORMATTER (self)->project) {
ges_project_set_loaded (GES_FORMATTER (self)->project, ges_project_set_loaded (GES_FORMATTER (self)->project,
GES_FORMATTER (self)); GES_FORMATTER (self), NULL);
} else { } else {
if (!make_clips (self)) { if (!make_clips (self)) {
GST_ERROR ("Couldn't deserialise the project properly"); GST_ERROR ("Couldn't deserialise the project properly");
......
...@@ -97,6 +97,7 @@ enum ...@@ -97,6 +97,7 @@ enum
{ {
LOADING_SIGNAL, LOADING_SIGNAL,
LOADED_SIGNAL, LOADED_SIGNAL,
ERROR_LOADING,
ERROR_LOADING_ASSET, ERROR_LOADING_ASSET,
ASSET_ADDED_SIGNAL, ASSET_ADDED_SIGNAL,
ASSET_REMOVED_SIGNAL, ASSET_REMOVED_SIGNAL,
...@@ -591,6 +592,20 @@ ges_project_class_init (GESProjectClass * klass) ...@@ -591,6 +592,20 @@ ges_project_class_init (GESProjectClass * klass)
NULL, NULL, g_cclosure_marshal_generic, NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_NONE, 3, G_TYPE_ERROR, G_TYPE_STRING, G_TYPE_GTYPE); G_TYPE_NONE, 3, G_TYPE_ERROR, G_TYPE_STRING, G_TYPE_GTYPE);
/**
* GESProject::error-loading:
* @project: the #GESProject on which a problem happend when creted a #GESAsset
* @timeline: The timeline that failed loading
* @error: The #GError defining the error that occured
*
* Since: 1.18
*/
_signals[ERROR_LOADING] =
g_signal_new ("error-loading", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0,
NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GES_TYPE_TIMELINE,
G_TYPE_ERROR);
object_class->dispose = _dispose; object_class->dispose = _dispose;
object_class->finalize = _finalize; object_class->finalize = _finalize;
...@@ -731,8 +746,15 @@ new_asset_cb (GESAsset * source, GAsyncResult * res, GESProject * project) ...@@ -731,8 +746,15 @@ new_asset_cb (GESAsset * source, GAsyncResult * res, GESProject * project)
* Returns: %TRUE if the signale could be emitted %FALSE otherwize * Returns: %TRUE if the signale could be emitted %FALSE otherwize
*/ */
gboolean gboolean
ges_project_set_loaded (GESProject * project, GESFormatter * formatter) ges_project_set_loaded (GESProject * project, GESFormatter * formatter,
GError * error)
{ {
if (error) {
GST_ERROR_OBJECT (project, "Emit project error-loading %s", error->message);
g_signal_emit (project, _signals[ERROR_LOADING], 0, formatter->timeline,
error);
}
GST_INFO_OBJECT (project, "Emit project loaded"); GST_INFO_OBJECT (project, "Emit project loaded");
if (GST_STATE (formatter->timeline) < GST_STATE_PAUSED) { if (GST_STATE (formatter->timeline) < GST_STATE_PAUSED) {
timeline_fill_gaps (formatter->timeline); timeline_fill_gaps (formatter->timeline);
......
...@@ -142,6 +142,7 @@ typedef struct ...@@ -142,6 +142,7 @@ typedef struct
GError *error; GError *error;
gulong loaded_sigid; gulong loaded_sigid;
gulong error_sigid; gulong error_sigid;
gulong error_asset_sigid;
} TimelineConstructionData; } TimelineConstructionData;
static void static void
...@@ -156,8 +157,8 @@ project_loaded_cb (GESProject * project, GESTimeline * timeline, ...@@ -156,8 +157,8 @@ project_loaded_cb (GESProject * project, GESTimeline * timeline,
} }
static void static void
error_loading_asset_cb (GESProject * project, GError * error, gchar * id, error_loading_cb (GESProject * project, GESTimeline * timeline,
GType extractable_type, TimelineConstructionData * data) GError * error, TimelineConstructionData * data)
{ {
data->error = g_error_copy (error); data->error = g_error_copy (error);
g_signal_handler_disconnect (project, data->error_sigid); g_signal_handler_disconnect (project, data->error_sigid);
...@@ -166,6 +167,17 @@ error_loading_asset_cb (GESProject * project, GError * error, gchar * id, ...@@ -166,6 +167,17 @@ error_loading_asset_cb (GESProject * project, GError * error, gchar * id,
g_main_loop_quit (data->ml); g_main_loop_quit (data->ml);
} }
static void
error_loading_asset_cb (GESProject * project, GError * error, gchar * id,
GType extractable_type, TimelineConstructionData * data)
{
data->error = g_error_copy (error);
g_signal_handler_disconnect (project, data->error_asset_sigid);
data->error_asset_sigid = 0;
g_main_loop_quit (data->ml);
}
static gboolean static gboolean
ges_demux_src_probe (GstPad * pad, GstPadProbeInfo * info, GstElement * parent) ges_demux_src_probe (GstPad * pad, GstPadProbeInfo * info, GstElement * parent)
{ {
...@@ -337,9 +349,12 @@ ges_demux_create_timeline (GESDemux * self, gchar * uri, GError ** error) ...@@ -337,9 +349,12 @@ ges_demux_create_timeline (GESDemux * self, gchar * uri, GError ** error)
data.loaded_sigid = data.loaded_sigid =
g_signal_connect (project, "loaded", G_CALLBACK (project_loaded_cb), g_signal_connect (project, "loaded", G_CALLBACK (project_loaded_cb),
&data); &data);
data.error_sigid = data.error_asset_sigid =
g_signal_connect_after (project, "error-loading-asset", g_signal_connect_after (project, "error-loading-asset",
G_CALLBACK (error_loading_asset_cb), &data); G_CALLBACK (error_loading_asset_cb), &data);
data.error_sigid =
g_signal_connect_after (project, "error-loading",
G_CALLBACK (error_loading_cb), &data);
unused = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), &data.error)); unused = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), &data.error));
if (data.error) { if (data.error) {
...@@ -350,6 +365,9 @@ ges_demux_create_timeline (GESDemux * self, gchar * uri, GError ** error) ...@@ -350,6 +365,9 @@ ges_demux_create_timeline (GESDemux * self, gchar * uri, GError ** error)
g_main_loop_run (data.ml); g_main_loop_run (data.ml);
g_main_loop_unref (data.ml); g_main_loop_unref (data.ml);
if (data.error)
goto done;
ges_demux_adapt_timeline_duration (self, data.timeline); ges_demux_adapt_timeline_duration (self, data.timeline);
query = gst_query_new_uri (); query = gst_query_new_uri ();
...@@ -387,13 +405,21 @@ done: ...@@ -387,13 +405,21 @@ done:
if (data.error_sigid) if (data.error_sigid)
g_signal_handler_disconnect (project, data.error_sigid); g_signal_handler_disconnect (project, data.error_sigid);
if (data.error_asset_sigid)
g_signal_handler_disconnect (project, data.error_asset_sigid);
g_clear_object (&project); g_clear_object (&project);
GST_INFO_OBJECT (self, "Timeline properly loaded: %" GST_PTR_FORMAT, GST_INFO_OBJECT (self, "Timeline properly loaded: %" GST_PTR_FORMAT,
data.timeline); data.timeline);
ges_base_bin_set_timeline (GES_BASE_BIN (self), data.timeline);
gst_element_foreach_src_pad (GST_ELEMENT (self), ges_demux_set_srcpad_probe, if (!data.error) {
NULL); ges_base_bin_set_timeline (GES_BASE_BIN (self), data.timeline);
gst_element_foreach_src_pad (GST_ELEMENT (self), ges_demux_set_srcpad_probe,
NULL);
} else {
*error = data.error;
}
g_main_context_pop_thread_default (ctx); g_main_context_pop_thread_default (ctx);
......
...@@ -172,6 +172,16 @@ retry: ...@@ -172,6 +172,16 @@ retry:
return TRUE; return TRUE;
} }
static void
_project_loading_error_cb (GESProject * project, GESTimeline * timeline,
GError * error, GESLauncher * self)
{
g_printerr ("Error loading timeline: '%s'\n", error->message);
self->priv->seenerrors = TRUE;
g_application_quit (G_APPLICATION (self));
}
static void static void
_project_loaded_cb (GESProject * project, GESTimeline * timeline, _project_loaded_cb (GESProject * project, GESTimeline * timeline,
GESLauncher * self) GESLauncher * self)
...@@ -256,6 +266,8 @@ _create_timeline (GESLauncher * self, const gchar * serialized_timeline, ...@@ -256,6 +266,8 @@ _create_timeline (GESLauncher * self, const gchar * serialized_timeline,
g_signal_connect (project, "error-loading-asset", g_signal_connect (project, "error-loading-asset",
G_CALLBACK (_error_loading_asset_cb), self); G_CALLBACK (_error_loading_asset_cb), self);
g_signal_connect (project, "loaded", G_CALLBACK (_project_loaded_cb), self); g_signal_connect (project, "loaded", G_CALLBACK (_project_loaded_cb), self);
g_signal_connect (project, "error-loading",
G_CALLBACK (_project_loading_error_cb), self);
self->priv->timeline = self->priv->timeline =
GES_TIMELINE (ges_asset_extract (GES_ASSET (project), &error)); GES_TIMELINE (ges_asset_extract (GES_ASSET (project), &error));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment