Commit a5529631 authored by Thibault Saunier's avatar Thibault Saunier 🌵

nle: Handle nested timelines update when file changes

When we have nested timelines, we need to make sure the underlying
formatted file is reloaded when commiting the main composition to
take into account the new timeline.

In other to make the implementation as simple as possible we make
sure that whenever the toplevel composition is commited, the decodebin
holding the gesdemux is torn down so that a new demuxer is created
with the new content of the timeline.

To do that a we do a NleCompositionQueryNeedsTearDown query to which
gesdemux answers leading to a full nlecomposition stack
deactivation/activation cycle.
parent 70d42357
......@@ -150,7 +150,6 @@ _check_fields (GstStructure * structure, FieldsError fields_error,
if (error)
*error = g_error_new_literal (GES_ERROR, 0, msg->str);
GST_ERROR ("%s", msg->str);
g_string_free (msg, TRUE);
......
......@@ -62,6 +62,9 @@ struct _GESDemux
GstPad *sinkpad;
GstAdapter *input_adapter;
gchar *upstream_uri;
GStatBuf stats;
};
G_DEFINE_TYPE (GESDemux, ges_demux, ges_base_bin_get_type ());
......@@ -166,8 +169,54 @@ error_loading_asset_cb (GESProject * project, GError * error, gchar * id,
static gboolean
ges_demux_src_probe (GstPad * pad, GstPadProbeInfo * info, GstElement * parent)
{
GstEvent *event = info->data;
GESDemux *self = GES_DEMUX (parent);
GstEvent *event;
if (info->type & (GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM)) {
GstQuery *query = info->data;
if (GST_QUERY_TYPE (query) == GST_QUERY_CUSTOM) {
GstStructure *structure =
(GstStructure *) gst_query_get_structure (query);
if (gst_structure_has_name (structure,
"NleCompositionQueryNeedsTearDown")) {
GstQuery *uri_query = gst_query_new_uri ();
if (gst_pad_peer_query (self->sinkpad, uri_query)) {
gchar *upstream_uri = NULL;
GStatBuf stats;
gst_query_parse_uri (uri_query, &upstream_uri);
if (gst_uri_has_protocol (upstream_uri, "file")) {
gchar *location = gst_uri_get_location (upstream_uri);
g_stat (location, &stats);
g_free (location);
GST_OBJECT_LOCK (self);
if (g_strcmp0 (upstream_uri, self->upstream_uri)
|| stats.st_mtime != self->stats.st_mtime
|| stats.st_size != self->stats.st_size) {
GST_INFO_OBJECT (self,
"Underlying file changed, asking for an update");
gst_structure_set (structure, "result", G_TYPE_BOOLEAN, TRUE,
NULL);
g_free (self->upstream_uri);
self->upstream_uri = upstream_uri;
self->stats = stats;
} else {
g_free (upstream_uri);
}
GST_OBJECT_UNLOCK (self);
}
}
gst_query_unref (uri_query);
}
}
return GST_PAD_PROBE_OK;
}
event = info->data;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_STREAM_START:
{
......@@ -198,7 +247,8 @@ static gboolean
ges_demux_set_srcpad_probe (GstElement * element, GstPad * pad,
gpointer user_data)
{
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
gst_pad_add_probe (pad,
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_QUERY_UPSTREAM,
(GstPadProbeCallback) ges_demux_src_probe, element, NULL);
return TRUE;
}
......@@ -234,21 +284,29 @@ ges_demux_create_timeline (GESDemux * self, gchar * uri, GError ** error)
query = gst_query_new_uri ();
if (gst_pad_peer_query (self->sinkpad, query)) {
gchar *upstream_uri = NULL;
GList *assets, *tmp;
gst_query_parse_uri (query, &upstream_uri);
GST_OBJECT_LOCK (self);
g_free (self->upstream_uri);
gst_query_parse_uri (query, &self->upstream_uri);
if (gst_uri_has_protocol (self->upstream_uri, "file")) {
gchar *location = gst_uri_get_location (self->upstream_uri);
g_stat (location, &self->stats);
g_free (location);
}
assets = ges_project_list_assets (project, GES_TYPE_URI_CLIP);
for (tmp = assets; tmp; tmp = tmp->next) {
const gchar *id = ges_asset_get_id (tmp->data);
if (!g_strcmp0 (id, upstream_uri)) {
if (!g_strcmp0 (id, self->upstream_uri)) {
g_set_error (error, GST_STREAM_ERROR, GST_STREAM_ERROR_DEMUX,
"Recursively loading uri: %s", upstream_uri);
"Recursively loading uri: %s", self->upstream_uri);
break;
}
}
GST_OBJECT_UNLOCK (self);
g_list_free_full (assets, g_object_unref);
}
......
......@@ -3108,6 +3108,23 @@ _dump_stack (NleComposition * comp, GNode * stack)
#endif
}
static gboolean
nle_composition_query_needs_teardown (NleComposition * comp,
NleUpdateStackReason reason)
{
gboolean res = FALSE;
GstStructure *structure =
gst_structure_new ("NleCompositionQueryNeedsTearDown", "reason",
G_TYPE_STRING, UPDATE_PIPELINE_REASONS[reason], NULL);
GstQuery *query = gst_query_new_custom (GST_QUERY_CUSTOM, structure);
gst_pad_query (NLE_OBJECT_SRC (comp), query);
gst_structure_get_boolean (structure, "result", &res);
gst_query_unref (query);
return res;
}
/*
* update_pipeline:
* @comp: The #NleComposition
......@@ -3129,7 +3146,7 @@ update_pipeline (NleComposition * comp, GstClockTime currenttime, gint32 seqnum,
GstEvent *toplevel_seek;
GNode *stack = NULL;
gboolean samestack = FALSE;
gboolean tear_down = FALSE;
gboolean updatestoponly = FALSE;
GstState state = GST_STATE (comp);
NleCompositionPrivate *priv = comp->priv;
......@@ -3167,7 +3184,8 @@ update_pipeline (NleComposition * comp, GstClockTime currenttime, gint32 seqnum,
/* Get new stack and compare it to current one */
stack = get_clean_toplevel_stack (comp, &currenttime, &new_start, &new_stop);
samestack = are_same_stacks (priv->current, stack);
tear_down = !are_same_stacks (priv->current, stack)
|| nle_composition_query_needs_teardown (comp, update_reason);
/* set new current_stack_start/stop (the current zone over which the new stack
* is valid) */
......@@ -3194,7 +3212,7 @@ update_pipeline (NleComposition * comp, GstClockTime currenttime, gint32 seqnum,
stopchanged = priv->current_stack_stop != currenttime;
}
if (samestack) {
if (!tear_down) {
if (startchanged || stopchanged) {
/* Update seek events need to be flushing if not in PLAYING,
* else we will encounter deadlocks. */
......@@ -3210,7 +3228,7 @@ update_pipeline (NleComposition * comp, GstClockTime currenttime, gint32 seqnum,
_remove_update_actions (comp);
/* If stacks are different, unlink/relink objects */
if (!samestack) {
if (tear_down) {
_dump_stack (comp, stack);
_deactivate_stack (comp, update_reason);
_relink_new_stack (comp, stack, toplevel_seek);
......@@ -3248,7 +3266,7 @@ update_pipeline (NleComposition * comp, GstClockTime currenttime, gint32 seqnum,
}
/* Activate stack */
if (!samestack)
if (tear_down)
return _activate_new_stack (comp);
else
return _seek_current_stack (comp, toplevel_seek,
......
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