return TRUE;
}
+gboolean
+_ges_save_timeline_if_needed (GESTimeline * timeline, GstStructure * structure,
+ GError ** error)
+{
+ gboolean res = TRUE;
+ const gchar *nested_timeline_id =
+ gst_structure_get_string (structure, "project-uri");
+
+ if (nested_timeline_id) {
+ res = ges_timeline_save_to_uri (timeline, nested_timeline_id, NULL, TRUE,
+ error);
+ }
+
+ return res;
+}
gboolean
_ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
gboolean ret = FALSE;
const gchar *valid_fields[] =
- { "element-name", "property-name", "value", "timestamp",
+ { "element-name", "property-name", "value", "timestamp", "project-uri",
NULL
};
GST_TIME_ARGS (timestamp));
}
}
+ ret = _ges_save_timeline_if_needed (timeline, structure, error);
done:
if (source)
const gchar *text;
const gchar *pattern;
const gchar *track_types_str;
+ const gchar *nested_timeline_id;
gchar *asset_id = NULL;
gchar *check_asset_id = NULL;
const gchar *type_string;
const gchar *valid_fields[] =
{ "asset-id", "pattern", "name", "layer-priority", "layer", "type",
- "start", "inpoint", "duration", "text", "track-types", NULL
+ "start", "inpoint", "duration", "text", "track-types", "project-uri",
+ NULL
};
FieldsError fields_error = { valid_fields, NULL };
TRY_GET ("inpoint", GST_TYPE_CLOCK_TIME, &inpoint, 0);
TRY_GET ("duration", GST_TYPE_CLOCK_TIME, &duration, GST_CLOCK_TIME_NONE);
TRY_GET_STRING ("track-types", &track_types_str, NULL);
+ TRY_GET_STRING ("project-uri", &nested_timeline_id, NULL);
if (track_types_str) {
if (!get_flags_from_string (GES_TYPE_TRACK_TYPE, track_types_str,
}
gst_object_unref (layer);
+ res = _ges_save_timeline_if_needed (timeline, structure, error);
beach:
g_free (asset_id);
gboolean res = TRUE;
const gchar *valid_fields[] = { "container-name", "asset-id",
- "child-type", "child-name", NULL
+ "child-type", "child-name", "project-uri", NULL
};
FieldsError fields_error = { valid_fields, NULL };
} else {
g_object_set_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA, child);
}
+ res = _ges_save_timeline_if_needed (timeline, structure, error);
beach:
return res;
GESTimelineElement *element;
const gchar *property_name, *element_name;
- const gchar *valid_fields[] = { "element-name", "property", "value", NULL };
+ const gchar *valid_fields[] =
+ { "element-name", "property", "value", "project-uri", NULL };
FieldsError fields_error = { valid_fields, NULL };
ges_timeline_element_set_child_property (element, property_name,
(GValue *) value);
-
- return TRUE;
+ return _ges_save_timeline_if_needed (timeline, structure, error);
}
#undef GET_AND_CHECK
#define MONITOR_ON_PIPELINE "validate-monitor"
#define RUNNER_ON_PIPELINE "runner-monitor"
-#define DECLARE_AND_GET_TIMELINE_AND_PIPELINE(scenario, action) \
- GESTimeline *timeline; \
- GstElement * pipeline = gst_validate_scenario_get_pipeline (scenario); \
- if (pipeline == NULL) { \
- GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR,\
- "Can't execute a '%s' action after the pipeline "\
- "has been destroyed.", action->type);\
- return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;\
- }\
- g_object_get (pipeline, "timeline", &timeline, NULL);
-
-#define DECLARE_AND_GET_TIMELINE(scenario, action) \
- DECLARE_AND_GET_TIMELINE_AND_PIPELINE(scenario, action);\
- gst_object_unref(pipeline);
+typedef struct
+{
+ GMainLoop *ml;
+ GError *error;
+} LoadTimelineData;
+
+static void
+project_loaded_cb (GESProject * project, GESTimeline * timeline,
+ LoadTimelineData * data)
+{
+ g_main_loop_quit (data->ml);
+}
+
+static void
+error_loading_asset_cb (GESProject * project, GError * err,
+ const gchar * unused_id, GType extractable_type, LoadTimelineData * data)
+{
+ data->error = g_error_copy (err);
+ g_main_loop_quit (data->ml);
+}
+
+static GESTimeline *
+_ges_load_timeline (GstValidateScenario * scenario, const gchar * project_uri)
+{
+ GESProject *project = ges_project_new (project_uri);
+ GESTimeline *timeline;
+ LoadTimelineData data = { 0 };
+
+ data.ml = g_main_loop_new (NULL, TRUE);
+ timeline =
+ GES_TIMELINE (ges_asset_extract (GES_ASSET (project), &data.error));
+ if (!timeline)
+ goto done;
+
+ g_signal_connect (project, "loaded", (GCallback) project_loaded_cb, &data);
+ g_signal_connect (project, "error-loading-asset",
+ (GCallback) error_loading_asset_cb, &data);
+ g_main_loop_run (data.ml);
+ g_signal_handlers_disconnect_by_func (project, project_loaded_cb, &data);
+ g_signal_handlers_disconnect_by_func (project, error_loading_asset_cb, &data);
+ GST_INFO_OBJECT (scenario, "Loaded timeline from %s", project_uri);
+
+done:
+ if (data.error) {
+ GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR,
+ "Can not load timeline from: %s (%s)", project_uri,
+ data.error->message);
+ g_clear_error (&data.error);
+ gst_clear_object (&timeline);
+ }
+
+ g_main_loop_unref (data.ml);
+ gst_object_unref (project);
+ return timeline;
+}
+
+#define DECLARE_AND_GET_TIMELINE_AND_PIPELINE(scenario, action) \
+ GESTimeline* timeline; \
+ GstElement* pipeline = NULL; \
+ const gchar* project_uri = gst_structure_get_string(action->structure, "project-uri"); \
+ if (!project_uri) { \
+ pipeline = gst_validate_scenario_get_pipeline(scenario); \
+ if (pipeline == NULL) { \
+ GST_VALIDATE_REPORT(scenario, SCENARIO_ACTION_EXECUTION_ERROR, \
+ "Can't execute a '%s' action after the pipeline " \
+ "has been destroyed.", \
+ action->type); \
+ return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; \
+ } \
+ g_object_get(pipeline, "timeline", &timeline, NULL); \
+ } else { \
+ timeline = _ges_load_timeline(scenario, project_uri); \
+ if (!timeline) \
+ return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; \
+ }
+
+#define DECLARE_AND_GET_TIMELINE(scenario, action) \
+ DECLARE_AND_GET_TIMELINE_AND_PIPELINE(scenario, action); \
+ if (pipeline) \
+ gst_object_unref(pipeline); \
+
+#define SAVE_TIMELINE_IF_NEEDED(scenario, timeline, action) \
+ { \
+ if (!_ges_save_timeline_if_needed(timeline, action->structure, NULL)) { \
+ GST_VALIDATE_REPORT(scenario, \
+ g_quark_from_string("scenario::execution-error"), \
+ "Could not save timeline to %s", gst_structure_get_string(action->structure, "project-id")); \
+ gst_object_unref(timeline); \
+ return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; \
+ } \
+ }
static gboolean
_serialize_project (GstValidateScenario * scenario, GstValidateAction * action)
}
res = ges_project_remove_asset (project, asset);
-
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
beach:
g_object_unref (timeline);
return res;
}
res = ges_project_add_asset (project, asset);
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
beach:
g_object_unref (timeline);
NULL);
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
beach:
g_object_unref (timeline);
return res;
GST_ERROR ("No layer with priority %d", priority);
}
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
beach:
g_object_unref (timeline);
return res;
GST_ERROR ("No layer for clip %s", ges_timeline_element_get_name (clip));
}
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
g_object_unref (timeline);
return res;
}
}
gst_object_unref (container);
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
beach:
g_object_unref (timeline);
return res;
}
gst_object_unref (bus);
gst_object_unref (timeline);
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
return GST_VALIDATE_EXECUTE_ACTION_ASYNC;
}
}
}
gst_caps_unref (caps);
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
gst_object_unref (timeline);
return res;
}
res = ges_extractable_set_asset (GES_EXTRACTABLE (element), asset);
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
beach:
gst_object_unref (timeline);
res = ges_container_remove (container, child);
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
gst_object_unref (timeline);
return res;
g_list_free (ges_container_ungroup (container, recursive));
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
gst_object_unref (timeline);
return res;
ret = ges_track_element_set_control_source (element,
source, property_name, binding_type);
-
done:
- gst_object_unref (timeline);
g_free (element_name);
g_free (binding_type);
g_free (source_type);
g_free (interpolation_mode);
+ SAVE_TIMELINE_IF_NEEDED (scenario, timeline, action);
+ gst_object_unref (timeline);
+
return ret;
}
.types = "int",
.def = "-1",
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
},
"Allows to edit a container (like a GESClip), for more details, have a look at:\n"
.mandatory = TRUE,
NULL
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
},
"Allows to add an asset to the current project", GST_VALIDATE_ACTION_TYPE_NONE);
.mandatory = TRUE,
NULL
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{ NULL }
},
"Allows to remove an asset from the current project", GST_VALIDATE_ACTION_TYPE_NONE);
.mandatory = FALSE,
NULL
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{ NULL }
},
"Allows to add a layer to the current timeline", GST_VALIDATE_ACTION_TYPE_NONE);
.types="boolean",
.def = "False"
},
+ {
+ .name = "project-uri",
+ .description = "The nested timeline to add clip to",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{ NULL }
},
"Allows to remove a layer from the current timeline", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "double or string",
.mandatory = FALSE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Allows to add a clip to a given layer", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "string",
.mandatory = TRUE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Allows to remove a clip from a given layer", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "gvalue",
.mandatory = TRUE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Allows to change child property of an object", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "double or string",
.mandatory = TRUE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Split a clip at a specified position.", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "string",
.mandatory = TRUE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Sets restriction caps on tracks of a specific type.", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "string",
.mandatory = TRUE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Sets restriction caps on tracks of a specific type.", GST_VALIDATE_ACTION_TYPE_NONE);
.mandatory = FALSE,
.def = "NULL"
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Add a child to @container-name. If asset-id and child-type are specified,"
" the child will be created and added. Otherwize @child-name has to be specified"
.types = "string",
.mandatory = TRUE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Remove a child from @container-name.", FALSE);
.types = "boolean",
.mandatory = FALSE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Ungroup children of @container-name.", FALSE);
.mandatory = FALSE,
.def = "linear",
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Adds a GstControlSource on @element-name::@property-name"
" allowing you to then add keyframes on that property.", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "float",
.mandatory = TRUE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Remove a child from @container-name.", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "string",
.mandatory = FALSE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Remove a child from @container-name.", GST_VALIDATE_ACTION_TYPE_NONE);
.types = "string or float",
.mandatory = TRUE,
},
+ {
+ .name = "project-uri",
+ .description = "The project URI with the serialized timeline to execute the action on",
+ .types = "string",
+ .mandatory = FALSE,
+ },
{NULL}
}, "Remove a child from @container-name.", GST_VALIDATE_ACTION_TYPE_NONE);