mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-14 13:21:28 +00:00
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.
This commit is contained in:
parent
70d423575d
commit
a55296314c
3 changed files with 88 additions and 13 deletions
|
@ -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, ¤ttime, &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,
|
||||
|
|
Loading…
Reference in a new issue