mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-18 12:15:19 +00:00
ges: Add a way to set layer activeness by track
a.k.a muting layers. Adding unit tests and making sure serialization works properly
This commit is contained in:
parent
7ccc7aa7ca
commit
f9f30c4ced
15 changed files with 707 additions and 59 deletions
|
@ -943,7 +943,7 @@ ges_base_xml_formatter_set_timeline_properties (GESBaseXmlFormatter * self,
|
||||||
void
|
void
|
||||||
ges_base_xml_formatter_add_layer (GESBaseXmlFormatter * self,
|
ges_base_xml_formatter_add_layer (GESBaseXmlFormatter * self,
|
||||||
GType extractable_type, guint priority, GstStructure * properties,
|
GType extractable_type, guint priority, GstStructure * properties,
|
||||||
const gchar * metadatas, GError ** error)
|
const gchar * metadatas, gchar ** deactivated_tracks, GError ** error)
|
||||||
{
|
{
|
||||||
LayerEntry *entry;
|
LayerEntry *entry;
|
||||||
GESAsset *asset;
|
GESAsset *asset;
|
||||||
|
@ -967,10 +967,11 @@ ges_base_xml_formatter_add_layer (GESBaseXmlFormatter * self,
|
||||||
G_MARKUP_ERROR_INVALID_CONTENT,
|
G_MARKUP_ERROR_INVALID_CONTENT,
|
||||||
"Layer type %s could not be created'",
|
"Layer type %s could not be created'",
|
||||||
g_type_name (extractable_type));
|
g_type_name (extractable_type));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
layer = GES_LAYER (ges_asset_extract (asset, error));
|
layer = GES_LAYER (ges_asset_extract (asset, error));
|
||||||
|
gst_object_unref (asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ges_layer_set_priority (layer, priority);
|
ges_layer_set_priority (layer, priority);
|
||||||
|
@ -988,6 +989,27 @@ ges_base_xml_formatter_add_layer (GESBaseXmlFormatter * self,
|
||||||
ges_meta_container_add_metas_from_string (GES_META_CONTAINER (layer),
|
ges_meta_container_add_metas_from_string (GES_META_CONTAINER (layer),
|
||||||
metadatas);
|
metadatas);
|
||||||
|
|
||||||
|
if (deactivated_tracks) {
|
||||||
|
gint i;
|
||||||
|
GList *tracks = NULL;
|
||||||
|
|
||||||
|
for (i = 0; deactivated_tracks[i] && deactivated_tracks[i][0] != '\0'; i++) {
|
||||||
|
GESTrack *track =
|
||||||
|
g_hash_table_lookup (priv->tracks, deactivated_tracks[i]);
|
||||||
|
|
||||||
|
if (!track) {
|
||||||
|
GST_ERROR_OBJECT (self,
|
||||||
|
"Unknown deactivated track: %s", deactivated_tracks[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks = g_list_append (tracks, track);
|
||||||
|
}
|
||||||
|
|
||||||
|
ges_layer_set_active_for_tracks (layer, FALSE, tracks);
|
||||||
|
g_list_free (tracks);
|
||||||
|
}
|
||||||
|
|
||||||
entry = g_slice_new0 (LayerEntry);
|
entry = g_slice_new0 (LayerEntry);
|
||||||
entry->layer = gst_object_ref (layer);
|
entry->layer = gst_object_ref (layer);
|
||||||
entry->auto_trans = auto_transition;
|
entry->auto_trans = auto_transition;
|
||||||
|
|
|
@ -291,6 +291,7 @@ G_GNUC_INTERNAL void ges_base_xml_formatter_add_layer (GESBaseXmlForma
|
||||||
guint priority,
|
guint priority,
|
||||||
GstStructure *properties,
|
GstStructure *properties,
|
||||||
const gchar *metadatas,
|
const gchar *metadatas,
|
||||||
|
gchar **deactivated_tracks,
|
||||||
GError **error);
|
GError **error);
|
||||||
G_GNUC_INTERNAL void ges_base_xml_formatter_add_track (GESBaseXmlFormatter *self,
|
G_GNUC_INTERNAL void ges_base_xml_formatter_add_track (GESBaseXmlFormatter *self,
|
||||||
GESTrackType track_type,
|
GESTrackType track_type,
|
||||||
|
@ -418,6 +419,7 @@ G_GNUC_INTERNAL void layer_set_priority (GESLayer * layer, guint p
|
||||||
G_GNUC_INTERNAL gboolean ges_track_element_set_track (GESTrackElement * object, GESTrack * track);
|
G_GNUC_INTERNAL gboolean ges_track_element_set_track (GESTrackElement * object, GESTrack * track);
|
||||||
G_GNUC_INTERNAL void ges_track_element_copy_properties (GESTimelineElement * element,
|
G_GNUC_INTERNAL void ges_track_element_copy_properties (GESTimelineElement * element,
|
||||||
GESTimelineElement * elementcopy);
|
GESTimelineElement * elementcopy);
|
||||||
|
G_GNUC_INTERNAL void ges_track_element_set_layer_active (GESTrackElement *element, gboolean active);
|
||||||
|
|
||||||
G_GNUC_INTERNAL void ges_track_element_copy_bindings (GESTrackElement *element,
|
G_GNUC_INTERNAL void ges_track_element_copy_bindings (GESTrackElement *element,
|
||||||
GESTrackElement *new_element,
|
GESTrackElement *new_element,
|
||||||
|
|
158
ges/ges-layer.c
158
ges/ges-layer.c
|
@ -65,6 +65,8 @@ struct _GESLayerPrivate
|
||||||
guint32 priority; /* The priority of the layer within the
|
guint32 priority; /* The priority of the layer within the
|
||||||
* containing timeline */
|
* containing timeline */
|
||||||
gboolean auto_transition;
|
gboolean auto_transition;
|
||||||
|
|
||||||
|
GHashTable *tracks_activness;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -73,6 +75,43 @@ typedef struct
|
||||||
GESLayer *layer;
|
GESLayer *layer;
|
||||||
} NewAssetUData;
|
} NewAssetUData;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GESTrack *track;
|
||||||
|
GESLayer *layer;
|
||||||
|
gboolean active;
|
||||||
|
gboolean track_disposed;
|
||||||
|
} LayerActivnessData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
_track_disposed_cb (LayerActivnessData * data, GObject * disposed_track)
|
||||||
|
{
|
||||||
|
data->track_disposed = TRUE;
|
||||||
|
g_hash_table_remove (data->layer->priv->tracks_activness, data->track);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
layer_activness_data_free (LayerActivnessData * data)
|
||||||
|
{
|
||||||
|
if (!data->track_disposed)
|
||||||
|
g_object_weak_unref ((GObject *) data->track,
|
||||||
|
(GWeakNotify) _track_disposed_cb, data);
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LayerActivnessData *
|
||||||
|
layer_activness_data_new (GESTrack * track, GESLayer * layer, gboolean active)
|
||||||
|
{
|
||||||
|
LayerActivnessData *data = g_new0 (LayerActivnessData, 1);
|
||||||
|
|
||||||
|
data->layer = layer;
|
||||||
|
data->track = track;
|
||||||
|
data->active = active;
|
||||||
|
g_object_weak_ref (G_OBJECT (track), (GWeakNotify) _track_disposed_cb, data);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
|
@ -85,6 +124,7 @@ enum
|
||||||
{
|
{
|
||||||
OBJECT_ADDED,
|
OBJECT_ADDED,
|
||||||
OBJECT_REMOVED,
|
OBJECT_REMOVED,
|
||||||
|
ACTIVE_CHANGED,
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,6 +185,8 @@ ges_layer_dispose (GObject * object)
|
||||||
while (priv->clips_start)
|
while (priv->clips_start)
|
||||||
ges_layer_remove_clip (layer, (GESClip *) priv->clips_start->data);
|
ges_layer_remove_clip (layer, (GESClip *) priv->clips_start->data);
|
||||||
|
|
||||||
|
g_clear_pointer (&layer->priv->tracks_activness, g_hash_table_unref);
|
||||||
|
|
||||||
G_OBJECT_CLASS (ges_layer_parent_class)->dispose (object);
|
G_OBJECT_CLASS (ges_layer_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +287,21 @@ ges_layer_class_init (GESLayerClass * klass)
|
||||||
g_signal_new ("clip-removed", G_TYPE_FROM_CLASS (klass),
|
g_signal_new ("clip-removed", G_TYPE_FROM_CLASS (klass),
|
||||||
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESLayerClass,
|
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESLayerClass,
|
||||||
object_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, GES_TYPE_CLIP);
|
object_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, GES_TYPE_CLIP);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GESLayer::active-changed:
|
||||||
|
* @layer: The #GESLayer
|
||||||
|
* @active: Whether @layer has been made active or de-active in the @tracks
|
||||||
|
* @tracks: (element-type GESTrack) (transfer none): A list of #GESTrack
|
||||||
|
* which have been activated or deactivated
|
||||||
|
*
|
||||||
|
* Will be emitted whenever the layer is activated or deactivated
|
||||||
|
* for some #GESTrack. See ges_layer_set_active_for_tracks().
|
||||||
|
*/
|
||||||
|
ges_layer_signals[ACTIVE_CHANGED] =
|
||||||
|
g_signal_new ("active-changed", G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2,
|
||||||
|
G_TYPE_BOOLEAN, G_TYPE_PTR_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -257,6 +314,10 @@ ges_layer_init (GESLayer * self)
|
||||||
self->min_nle_priority = MIN_NLE_PRIO;
|
self->min_nle_priority = MIN_NLE_PRIO;
|
||||||
self->max_nle_priority = LAYER_HEIGHT + MIN_NLE_PRIO;
|
self->max_nle_priority = LAYER_HEIGHT + MIN_NLE_PRIO;
|
||||||
|
|
||||||
|
self->priv->tracks_activness =
|
||||||
|
g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||||
|
NULL, (GDestroyNotify) layer_activness_data_free);
|
||||||
|
|
||||||
_register_metas (self);
|
_register_metas (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,6 +481,7 @@ ges_layer_remove_clip_internal (GESLayer * layer, GESClip * clip,
|
||||||
gboolean emit_removed)
|
gboolean emit_removed)
|
||||||
{
|
{
|
||||||
GESLayer *current_layer;
|
GESLayer *current_layer;
|
||||||
|
GList *tmp;
|
||||||
|
|
||||||
GST_DEBUG ("layer:%p, clip:%p", layer, clip);
|
GST_DEBUG ("layer:%p, clip:%p", layer, clip);
|
||||||
|
|
||||||
|
@ -448,6 +510,9 @@ ges_layer_remove_clip_internal (GESLayer * layer, GESClip * clip,
|
||||||
if (layer->timeline)
|
if (layer->timeline)
|
||||||
ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (clip), NULL);
|
ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (clip), NULL);
|
||||||
|
|
||||||
|
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next)
|
||||||
|
ges_track_element_set_layer_active (tmp->data, TRUE);
|
||||||
|
|
||||||
/* Remove our reference to the clip */
|
/* Remove our reference to the clip */
|
||||||
gst_object_unref (clip);
|
gst_object_unref (clip);
|
||||||
|
|
||||||
|
@ -618,6 +683,7 @@ ges_layer_is_empty (GESLayer * layer)
|
||||||
gboolean
|
gboolean
|
||||||
ges_layer_add_clip (GESLayer * layer, GESClip * clip)
|
ges_layer_add_clip (GESLayer * layer, GESClip * clip)
|
||||||
{
|
{
|
||||||
|
GList *tmp;
|
||||||
GESAsset *asset;
|
GESAsset *asset;
|
||||||
GESLayerPrivate *priv;
|
GESLayerPrivate *priv;
|
||||||
GESLayer *current_layer;
|
GESLayer *current_layer;
|
||||||
|
@ -723,6 +789,14 @@ ges_layer_add_clip (GESLayer * layer, GESClip * clip)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
|
||||||
|
GESTrack *track = ges_track_element_get_track (tmp->data);
|
||||||
|
|
||||||
|
if (track)
|
||||||
|
ges_track_element_set_layer_active (tmp->data,
|
||||||
|
ges_layer_get_active_for_track (layer, track));
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -879,3 +953,87 @@ ges_layer_get_clips_in_interval (GESLayer * layer, GstClockTime start,
|
||||||
}
|
}
|
||||||
return intersecting_clips;
|
return intersecting_clips;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ges_layer_get_active_for_track:
|
||||||
|
* @layer: The #GESLayer
|
||||||
|
* @track: The #GESTrack to check if @layer is currently active for
|
||||||
|
*
|
||||||
|
* Gets whether the layer is active for the given track. See
|
||||||
|
* ges_layer_set_active_for_tracks().
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if @layer is active for @track, or %FALSE otherwise.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
ges_layer_get_active_for_track (GESLayer * layer, GESTrack * track)
|
||||||
|
{
|
||||||
|
LayerActivnessData *d;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
|
||||||
|
g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
|
||||||
|
g_return_val_if_fail (layer->timeline == ges_track_get_timeline (track),
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
d = g_hash_table_lookup (layer->priv->tracks_activness, track);
|
||||||
|
|
||||||
|
return d ? d->active : TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ges_layer_set_active_for_tracks:
|
||||||
|
* @layer: The #GESLayer
|
||||||
|
* @active: Whether elements in @tracks should be active or not
|
||||||
|
* @tracks: (transfer none) (element-type GESTrack) (allow-none): The list of
|
||||||
|
* tracks @layer should be (de-)active in, or %NULL to include all the tracks
|
||||||
|
* in the @layer's timeline
|
||||||
|
*
|
||||||
|
* Activate or deactivate track elements in @tracks (or in all tracks if @tracks
|
||||||
|
* is %NULL).
|
||||||
|
*
|
||||||
|
* When a layer is deactivated for a track, all the #GESTrackElement-s in
|
||||||
|
* the track that belong to a #GESClip in the layer will no longer be
|
||||||
|
* active in the track, regardless of their individual
|
||||||
|
* #GESTrackElement:active value.
|
||||||
|
*
|
||||||
|
* Note that by default a layer will be active for all of its
|
||||||
|
* timeline's tracks.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the operation worked %FALSE otherwise.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
ges_layer_set_active_for_tracks (GESLayer * layer, gboolean active,
|
||||||
|
GList * tracks)
|
||||||
|
{
|
||||||
|
GList *tmp, *owned_tracks = NULL;
|
||||||
|
GPtrArray *changed_tracks = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
|
||||||
|
|
||||||
|
if (!tracks && layer->timeline)
|
||||||
|
owned_tracks = tracks = ges_timeline_get_tracks (layer->timeline);
|
||||||
|
|
||||||
|
for (tmp = tracks; tmp; tmp = tmp->next) {
|
||||||
|
GESTrack *track = tmp->data;
|
||||||
|
|
||||||
|
/* Handle setting timeline later */
|
||||||
|
g_return_val_if_fail (layer->timeline == ges_track_get_timeline (track),
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if (ges_layer_get_active_for_track (layer, track) != active) {
|
||||||
|
if (changed_tracks == NULL)
|
||||||
|
changed_tracks = g_ptr_array_new ();
|
||||||
|
g_ptr_array_add (changed_tracks, track);
|
||||||
|
}
|
||||||
|
g_hash_table_insert (layer->priv->tracks_activness, track,
|
||||||
|
layer_activness_data_new (track, layer, active));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed_tracks) {
|
||||||
|
g_signal_emit (layer, ges_layer_signals[ACTIVE_CHANGED], 0, active,
|
||||||
|
changed_tracks);
|
||||||
|
g_ptr_array_unref (changed_tracks);
|
||||||
|
}
|
||||||
|
g_list_free_full (owned_tracks, gst_object_unref);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
|
@ -121,5 +121,11 @@ GES_API
|
||||||
GList* ges_layer_get_clips (GESLayer * layer);
|
GList* ges_layer_get_clips (GESLayer * layer);
|
||||||
GES_API
|
GES_API
|
||||||
GstClockTime ges_layer_get_duration (GESLayer *layer);
|
GstClockTime ges_layer_get_duration (GESLayer *layer);
|
||||||
|
GES_API
|
||||||
|
gboolean ges_layer_set_active_for_tracks(GESLayer *layer, gboolean active,
|
||||||
|
GList *tracks);
|
||||||
|
|
||||||
|
GES_API gboolean ges_layer_get_active_for_track(GESLayer *layer,
|
||||||
|
GESTrack *track);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -1333,3 +1333,30 @@ timeline_tree_get_duration (GNode * root)
|
||||||
|
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
reset_layer_activness (GNode * node, GESLayer * layer)
|
||||||
|
{
|
||||||
|
GESTrack *track;
|
||||||
|
|
||||||
|
|
||||||
|
if (!GES_IS_TRACK_ELEMENT (node->data))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
track = ges_track_element_get_track (node->data);
|
||||||
|
if (!track || (ges_timeline_element_get_layer_priority (node->data) !=
|
||||||
|
ges_layer_get_priority (layer)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ges_track_element_set_layer_active (node->data,
|
||||||
|
ges_layer_get_active_for_track (layer, track));
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
timeline_tree_reset_layer_active (GNode * root, GESLayer * layer)
|
||||||
|
{
|
||||||
|
g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_LEAFS, -1,
|
||||||
|
(GNodeTraverseFunc) reset_layer_activness, layer);
|
||||||
|
}
|
||||||
|
|
|
@ -73,4 +73,6 @@ ges_timeline_find_auto_transition (GESTimeline * timeline, GESTrackEleme
|
||||||
void
|
void
|
||||||
timeline_update_duration (GESTimeline * timeline);
|
timeline_update_duration (GESTimeline * timeline);
|
||||||
|
|
||||||
|
void timeline_tree_reset_layer_active (GNode *root, GESLayer *layer);
|
||||||
|
|
||||||
void timeline_tree_init_debug (void);
|
void timeline_tree_init_debug (void);
|
||||||
|
|
|
@ -1350,6 +1350,13 @@ add_object_to_tracks (GESTimeline * timeline, GESClip * clip, GESTrack * track)
|
||||||
UNLOCK_DYN (timeline);
|
UNLOCK_DYN (timeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
layer_active_changed_cb (GESLayer * layer, gboolean active G_GNUC_UNUSED,
|
||||||
|
GPtrArray * tracks G_GNUC_UNUSED, GESTimeline * timeline)
|
||||||
|
{
|
||||||
|
timeline_tree_reset_layer_active (timeline->priv->tree, layer);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
layer_auto_transition_changed_cb (GESLayer * layer,
|
layer_auto_transition_changed_cb (GESLayer * layer,
|
||||||
GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
|
GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
|
||||||
|
@ -2050,6 +2057,8 @@ ges_timeline_add_layer (GESTimeline * timeline, GESLayer * layer)
|
||||||
G_CALLBACK (layer_priority_changed_cb), timeline);
|
G_CALLBACK (layer_priority_changed_cb), timeline);
|
||||||
g_signal_connect (layer, "notify::auto-transition",
|
g_signal_connect (layer, "notify::auto-transition",
|
||||||
G_CALLBACK (layer_auto_transition_changed_cb), timeline);
|
G_CALLBACK (layer_auto_transition_changed_cb), timeline);
|
||||||
|
g_signal_connect_after (layer, "active-changed",
|
||||||
|
G_CALLBACK (layer_active_changed_cb), timeline);
|
||||||
|
|
||||||
GST_DEBUG ("Done adding layer, emitting 'layer-added' signal");
|
GST_DEBUG ("Done adding layer, emitting 'layer-added' signal");
|
||||||
g_signal_emit (timeline, ges_timeline_signals[LAYER_ADDED], 0, layer);
|
g_signal_emit (timeline, ges_timeline_signals[LAYER_ADDED], 0, layer);
|
||||||
|
@ -2111,6 +2120,8 @@ ges_timeline_remove_layer (GESTimeline * timeline, GESLayer * layer)
|
||||||
timeline);
|
timeline);
|
||||||
g_signal_handlers_disconnect_by_func (layer,
|
g_signal_handlers_disconnect_by_func (layer,
|
||||||
layer_auto_transition_changed_cb, timeline);
|
layer_auto_transition_changed_cb, timeline);
|
||||||
|
g_signal_handlers_disconnect_by_func (layer, layer_active_changed_cb,
|
||||||
|
timeline);
|
||||||
|
|
||||||
timeline->layers = g_list_remove (timeline->layers, layer);
|
timeline->layers = g_list_remove (timeline->layers, layer);
|
||||||
ges_layer_set_timeline (layer, NULL);
|
ges_layer_set_timeline (layer, NULL);
|
||||||
|
|
|
@ -63,6 +63,7 @@ struct _GESTrackElementPrivate
|
||||||
|
|
||||||
gboolean locked; /* If TRUE, then moves in sync with its controlling
|
gboolean locked; /* If TRUE, then moves in sync with its controlling
|
||||||
* GESClip */
|
* GESClip */
|
||||||
|
gboolean layer_active;
|
||||||
|
|
||||||
GHashTable *bindings_hashtable; /* We need this if we want to be able to serialize
|
GHashTable *bindings_hashtable; /* We need this if we want to be able to serialize
|
||||||
and deserialize keyframes */
|
and deserialize keyframes */
|
||||||
|
@ -302,7 +303,7 @@ ges_track_element_constructed (GObject * gobject)
|
||||||
"inpoint", GES_TIMELINE_ELEMENT_INPOINT (object),
|
"inpoint", GES_TIMELINE_ELEMENT_INPOINT (object),
|
||||||
"duration", GES_TIMELINE_ELEMENT_DURATION (object),
|
"duration", GES_TIMELINE_ELEMENT_DURATION (object),
|
||||||
"priority", GES_TIMELINE_ELEMENT_PRIORITY (object),
|
"priority", GES_TIMELINE_ELEMENT_PRIORITY (object),
|
||||||
"active", object->active, NULL);
|
"active", object->active & object->priv->layer_active, NULL);
|
||||||
|
|
||||||
media_duration_factor =
|
media_duration_factor =
|
||||||
ges_timeline_element_get_media_duration_factor (GES_TIMELINE_ELEMENT
|
ges_timeline_element_get_media_duration_factor (GES_TIMELINE_ELEMENT
|
||||||
|
@ -467,6 +468,7 @@ ges_track_element_init (GESTrackElement * self)
|
||||||
GES_TIMELINE_ELEMENT_DURATION (self) = GST_SECOND;
|
GES_TIMELINE_ELEMENT_DURATION (self) = GST_SECOND;
|
||||||
GES_TIMELINE_ELEMENT_PRIORITY (self) = 0;
|
GES_TIMELINE_ELEMENT_PRIORITY (self) = 0;
|
||||||
self->active = TRUE;
|
self->active = TRUE;
|
||||||
|
self->priv->layer_active = TRUE;
|
||||||
|
|
||||||
priv->bindings_hashtable = g_hash_table_new_full (g_str_hash, g_str_equal,
|
priv->bindings_hashtable = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
g_free, NULL);
|
g_free, NULL);
|
||||||
|
@ -740,7 +742,8 @@ ges_track_element_set_active (GESTrackElement * object, gboolean active)
|
||||||
if (G_UNLIKELY (active == object->active))
|
if (G_UNLIKELY (active == object->active))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
g_object_set (object->priv->nleobject, "active", active, NULL);
|
g_object_set (object->priv->nleobject, "active",
|
||||||
|
active & object->priv->layer_active, NULL);
|
||||||
|
|
||||||
object->active = active;
|
object->active = active;
|
||||||
if (GES_TRACK_ELEMENT_GET_CLASS (object)->active_changed)
|
if (GES_TRACK_ELEMENT_GET_CLASS (object)->active_changed)
|
||||||
|
@ -1050,6 +1053,17 @@ ges_track_element_set_track (GESTrackElement * object, GESTrack * track)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ges_track_element_set_layer_active (GESTrackElement * element, gboolean active)
|
||||||
|
{
|
||||||
|
if (element->priv->layer_active == active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
element->priv->layer_active = active;
|
||||||
|
g_object_set (element->priv->nleobject, "active", active & element->active,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ges_track_element_get_all_control_bindings
|
* ges_track_element_get_all_control_bindings
|
||||||
* @trackelement: A #GESTrackElement
|
* @trackelement: A #GESTrackElement
|
||||||
|
|
|
@ -232,6 +232,17 @@ update_gaps (GESTrack * track)
|
||||||
if (!ges_track_element_is_active (trackelement))
|
if (!ges_track_element_is_active (trackelement))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (priv->timeline) {
|
||||||
|
guint32 layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (trackelement);
|
||||||
|
|
||||||
|
if (layer_prio != GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY) {
|
||||||
|
GESLayer *layer = g_list_nth_data (priv->timeline->layers, layer_prio);
|
||||||
|
|
||||||
|
if (!ges_layer_get_active_for_track (layer, track))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
start = _START (trackelement);
|
start = _START (trackelement);
|
||||||
end = start + _DURATION (trackelement);
|
end = start + _DURATION (trackelement);
|
||||||
|
|
||||||
|
|
|
@ -1066,6 +1066,74 @@ done:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
set_layer_active (GstValidateScenario * scenario, GstValidateAction * action)
|
||||||
|
{
|
||||||
|
gboolean active;
|
||||||
|
gint i, layer_prio;
|
||||||
|
GESLayer *layer;
|
||||||
|
GList *tracks = NULL;
|
||||||
|
GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||||
|
gchar **track_names =
|
||||||
|
gst_validate_utils_get_strv (action->structure, "tracks");
|
||||||
|
|
||||||
|
DECLARE_AND_GET_TIMELINE (scenario, action);
|
||||||
|
|
||||||
|
for (i = 0; track_names[i]; i++) {
|
||||||
|
GESTrack *track =
|
||||||
|
(GESTrack *) gst_bin_get_by_name (GST_BIN (timeline), track_names[i]);
|
||||||
|
|
||||||
|
if (!track) {
|
||||||
|
GST_VALIDATE_REPORT_ACTION (scenario, action,
|
||||||
|
SCENARIO_ACTION_EXECUTION_ERROR,
|
||||||
|
"Could not find track %s", track_names[i]);
|
||||||
|
res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks = g_list_prepend (tracks, track);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_structure_get_int (action->structure, "layer-priority", &layer_prio)) {
|
||||||
|
GST_VALIDATE_REPORT_ACTION (scenario, action,
|
||||||
|
SCENARIO_ACTION_EXECUTION_ERROR,
|
||||||
|
"Could not find layer from %" GST_PTR_FORMAT, action->structure);
|
||||||
|
res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (!(layer = g_list_nth_data (timeline->layers, layer_prio))) {
|
||||||
|
GST_VALIDATE_REPORT_ACTION (scenario, action,
|
||||||
|
SCENARIO_ACTION_EXECUTION_ERROR, "Could not find layer %d", layer_prio);
|
||||||
|
res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_structure_get_boolean (action->structure, "active", &active)) {
|
||||||
|
GST_VALIDATE_REPORT_ACTION (scenario, action,
|
||||||
|
SCENARIO_ACTION_EXECUTION_ERROR,
|
||||||
|
"Could not find 'active' boolean in %" GST_PTR_FORMAT,
|
||||||
|
action->structure);
|
||||||
|
res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ges_layer_set_active_for_tracks (layer, active, tracks)) {
|
||||||
|
GST_VALIDATE_REPORT_ACTION (scenario, action,
|
||||||
|
SCENARIO_ACTION_EXECUTION_ERROR,
|
||||||
|
"Could not set active for track defined in %" GST_PTR_FORMAT,
|
||||||
|
action->structure);
|
||||||
|
res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
g_strfreev (track_names);
|
||||||
|
gst_object_unref (timeline);
|
||||||
|
g_list_free_full (tracks, gst_object_unref);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
@ -1404,6 +1472,43 @@ ges_validate_register_action_types (void)
|
||||||
{NULL}
|
{NULL}
|
||||||
}, "Allows to change child property of an object", GST_VALIDATE_ACTION_TYPE_NONE);
|
}, "Allows to change child property of an object", GST_VALIDATE_ACTION_TYPE_NONE);
|
||||||
|
|
||||||
|
gst_validate_register_action_type ("set-layer-active", "ges", set_layer_active,
|
||||||
|
(GstValidateActionParameter []) {
|
||||||
|
{
|
||||||
|
.name = "layer-priority",
|
||||||
|
.description = "The priority of the layer to set activness on",
|
||||||
|
.types = "gint",
|
||||||
|
.mandatory = TRUE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "active",
|
||||||
|
.description = "The activness of the layer",
|
||||||
|
.types = "gboolean",
|
||||||
|
.mandatory = TRUE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "tracks",
|
||||||
|
.description = "tracks",
|
||||||
|
.types = "{string, }",
|
||||||
|
.mandatory = FALSE,
|
||||||
|
},
|
||||||
|
{NULL}
|
||||||
|
}, "Set activness of a layer (on optional tracks).",
|
||||||
|
GST_VALIDATE_ACTION_TYPE_NONE);
|
||||||
|
|
||||||
|
gst_validate_register_action_type ("set-ges-properties", "ges", set_or_check_properties,
|
||||||
|
(GstValidateActionParameter []) {
|
||||||
|
{
|
||||||
|
.name = "element-name",
|
||||||
|
.description = "The name of the element on which to set properties",
|
||||||
|
.types = "string",
|
||||||
|
.mandatory = TRUE,
|
||||||
|
},
|
||||||
|
{NULL}
|
||||||
|
}, "Set `element-name` properties values defined by the"
|
||||||
|
" fields in the following format: `property_name=expected-value`",
|
||||||
|
GST_VALIDATE_ACTION_TYPE_NONE);
|
||||||
|
|
||||||
gst_validate_register_action_type ("check-ges-properties", "ges", set_or_check_properties,
|
gst_validate_register_action_type ("check-ges-properties", "ges", set_or_check_properties,
|
||||||
(GstValidateActionParameter []) {
|
(GstValidateActionParameter []) {
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
|
|
||||||
#define parent_class ges_xml_formatter_parent_class
|
#define parent_class ges_xml_formatter_parent_class
|
||||||
#define API_VERSION 0
|
#define API_VERSION 0
|
||||||
#define MINOR_VERSION 6
|
#define MINOR_VERSION 7
|
||||||
#define VERSION 0.5
|
#define VERSION 0.7
|
||||||
|
|
||||||
#define COLLECT_STR_OPT (G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL)
|
#define COLLECT_STR_OPT (G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL)
|
||||||
|
|
||||||
|
@ -471,13 +471,16 @@ _parse_layer (GMarkupParseContext * context, const gchar * element_name,
|
||||||
guint priority;
|
guint priority;
|
||||||
GType extractable_type = G_TYPE_NONE;
|
GType extractable_type = G_TYPE_NONE;
|
||||||
const gchar *metadatas = NULL, *properties = NULL, *strprio = NULL,
|
const gchar *metadatas = NULL, *properties = NULL, *strprio = NULL,
|
||||||
*extractable_type_name;
|
*extractable_type_name, *deactivated_tracks_str;
|
||||||
|
|
||||||
|
gchar **deactivated_tracks = NULL;
|
||||||
|
|
||||||
if (!g_markup_collect_attributes (element_name, attribute_names,
|
if (!g_markup_collect_attributes (element_name, attribute_names,
|
||||||
attribute_values, error,
|
attribute_values, error,
|
||||||
G_MARKUP_COLLECT_STRING, "priority", &strprio,
|
G_MARKUP_COLLECT_STRING, "priority", &strprio,
|
||||||
COLLECT_STR_OPT, "extractable-type-name", &extractable_type_name,
|
COLLECT_STR_OPT, "extractable-type-name", &extractable_type_name,
|
||||||
COLLECT_STR_OPT, "properties", &properties,
|
COLLECT_STR_OPT, "properties", &properties,
|
||||||
|
COLLECT_STR_OPT, "deactivated-tracks", &deactivated_tracks_str,
|
||||||
COLLECT_STR_OPT, "metadatas", &metadatas, G_MARKUP_COLLECT_INVALID))
|
COLLECT_STR_OPT, "metadatas", &metadatas, G_MARKUP_COLLECT_INVALID))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -511,8 +514,13 @@ _parse_layer (GMarkupParseContext * context, const gchar * element_name,
|
||||||
if (errno)
|
if (errno)
|
||||||
goto convertion_failed;
|
goto convertion_failed;
|
||||||
|
|
||||||
|
if (deactivated_tracks_str)
|
||||||
|
deactivated_tracks = g_strsplit (deactivated_tracks_str, " ", -1);
|
||||||
|
|
||||||
ges_base_xml_formatter_add_layer (GES_BASE_XML_FORMATTER (self),
|
ges_base_xml_formatter_add_layer (GES_BASE_XML_FORMATTER (self),
|
||||||
extractable_type, priority, props, metadatas, error);
|
extractable_type, priority, props, metadatas, deactivated_tracks, error);
|
||||||
|
|
||||||
|
g_strfreev (deactivated_tracks);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (props)
|
if (props)
|
||||||
|
@ -1084,7 +1092,8 @@ _init_value_from_spec_for_serialization (GValue * value, GParamSpec * spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
_serialize_properties (GObject * object, const gchar * fieldname, ...)
|
_serialize_properties (GObject * object, gint * ret_n_props,
|
||||||
|
const gchar * fieldname, ...)
|
||||||
{
|
{
|
||||||
gchar *ret;
|
gchar *ret;
|
||||||
guint n_props, j;
|
guint n_props, j;
|
||||||
|
@ -1097,22 +1106,31 @@ _serialize_properties (GObject * object, const gchar * fieldname, ...)
|
||||||
GValue val = { 0 };
|
GValue val = { 0 };
|
||||||
|
|
||||||
spec = pspecs[j];
|
spec = pspecs[j];
|
||||||
if (spec->value_type == GST_TYPE_CAPS) {
|
if (!_can_serialize_spec (spec))
|
||||||
GstCaps *caps;
|
continue;
|
||||||
gchar *caps_str;
|
|
||||||
|
_init_value_from_spec_for_serialization (&val, spec);
|
||||||
|
g_object_get_property (object, spec->name, &val);
|
||||||
|
if (gst_value_compare (g_param_spec_get_default_value (spec),
|
||||||
|
&val) == GST_VALUE_EQUAL) {
|
||||||
|
GST_INFO ("Ignoring %s as it is using the default value", spec->name);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec->value_type == GST_TYPE_CAPS) {
|
||||||
|
gchar *caps_str;
|
||||||
|
const GstCaps *caps = gst_value_get_caps (&val);
|
||||||
|
|
||||||
g_object_get (object, spec->name, &caps, NULL);
|
|
||||||
caps_str = gst_caps_to_string (caps);
|
caps_str = gst_caps_to_string (caps);
|
||||||
gst_structure_set (structure, spec->name, G_TYPE_STRING, caps_str, NULL);
|
gst_structure_set (structure, spec->name, G_TYPE_STRING, caps_str, NULL);
|
||||||
if (caps)
|
|
||||||
gst_caps_unref (caps);
|
|
||||||
g_free (caps_str);
|
g_free (caps_str);
|
||||||
} else if (_can_serialize_spec (spec)) {
|
goto next;
|
||||||
_init_value_from_spec_for_serialization (&val, spec);
|
|
||||||
g_object_get_property (object, spec->name, &val);
|
|
||||||
gst_structure_set_value (structure, spec->name, &val);
|
|
||||||
g_value_unset (&val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_structure_set_value (structure, spec->name, &val);
|
||||||
|
|
||||||
|
next:
|
||||||
|
g_value_unset (&val);
|
||||||
}
|
}
|
||||||
g_free (pspecs);
|
g_free (pspecs);
|
||||||
|
|
||||||
|
@ -1124,6 +1142,8 @@ _serialize_properties (GObject * object, const gchar * fieldname, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gst_structure_to_string (structure);
|
ret = gst_structure_to_string (structure);
|
||||||
|
if (ret_n_props)
|
||||||
|
*ret_n_props = gst_structure_n_fields (structure);
|
||||||
gst_structure_free (structure);
|
gst_structure_free (structure);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1190,7 +1210,7 @@ _save_subproject (GESXmlFormatter * self, GString * str, GESProject * project,
|
||||||
|
|
||||||
subproject = ges_extractable_get_asset (GES_EXTRACTABLE (timeline));
|
subproject = ges_extractable_get_asset (GES_EXTRACTABLE (timeline));
|
||||||
substr = g_string_new (NULL);
|
substr = g_string_new (NULL);
|
||||||
properties = _serialize_properties (G_OBJECT (subproject), NULL);
|
properties = _serialize_properties (G_OBJECT (subproject), NULL, NULL);
|
||||||
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (subproject));
|
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (subproject));
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
g_markup_printf_escaped
|
g_markup_printf_escaped
|
||||||
|
@ -1248,7 +1268,7 @@ _serialize_streams (GESXmlFormatter * self, GString * str,
|
||||||
ges_uri_source_asset_get_stream_info (tmp->data);
|
ges_uri_source_asset_get_stream_info (tmp->data);
|
||||||
GstCaps *caps = gst_discoverer_stream_info_get_caps (sinfo);
|
GstCaps *caps = gst_discoverer_stream_info_get_caps (sinfo);
|
||||||
|
|
||||||
properties = _serialize_properties (tmp->data, NULL);
|
properties = _serialize_properties (tmp->data, NULL, NULL);
|
||||||
metas = ges_meta_container_metas_to_string (tmp->data);
|
metas = ges_meta_container_metas_to_string (tmp->data);
|
||||||
capsstr = gst_caps_to_string (caps);
|
capsstr = gst_caps_to_string (caps);
|
||||||
|
|
||||||
|
@ -1299,7 +1319,7 @@ _save_assets (GESXmlFormatter * self, GString * str, GESProject * project,
|
||||||
G_UNLOCK (uri_subprojects_map_lock);
|
G_UNLOCK (uri_subprojects_map_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
properties = _serialize_properties (G_OBJECT (asset), NULL);
|
properties = _serialize_properties (G_OBJECT (asset), NULL, NULL);
|
||||||
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (asset));
|
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (asset));
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
g_markup_printf_escaped
|
g_markup_printf_escaped
|
||||||
|
@ -1363,7 +1383,7 @@ _save_tracks (GESXmlFormatter * self, GString * str, GESTimeline * timeline,
|
||||||
tracks = ges_timeline_get_tracks (timeline);
|
tracks = ges_timeline_get_tracks (timeline);
|
||||||
for (tmp = tracks; tmp; tmp = tmp->next) {
|
for (tmp = tracks; tmp; tmp = tmp->next) {
|
||||||
track = GES_TRACK (tmp->data);
|
track = GES_TRACK (tmp->data);
|
||||||
properties = _serialize_properties (G_OBJECT (track), "caps", NULL);
|
properties = _serialize_properties (G_OBJECT (track), NULL, "caps", NULL);
|
||||||
strtmp = gst_caps_to_string (ges_track_get_caps (track));
|
strtmp = gst_caps_to_string (ges_track_get_caps (track));
|
||||||
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (track));
|
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (track));
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
|
@ -1512,7 +1532,7 @@ _save_effect (GString * str, guint clip_id, GESTrackElement * trackelement,
|
||||||
}
|
}
|
||||||
g_list_free_full (tracks, gst_object_unref);
|
g_list_free_full (tracks, gst_object_unref);
|
||||||
|
|
||||||
properties = _serialize_properties (G_OBJECT (trackelement), "start",
|
properties = _serialize_properties (G_OBJECT (trackelement), NULL, "start",
|
||||||
"in-point", "duration", "locked", "max-duration", "name", "priority",
|
"in-point", "duration", "locked", "max-duration", "name", "priority",
|
||||||
NULL);
|
NULL);
|
||||||
metas =
|
metas =
|
||||||
|
@ -1537,6 +1557,79 @@ _save_effect (GString * str, guint clip_id, GESTrackElement * trackelement,
|
||||||
depth);
|
depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
_save_layer_track_activness (GESXmlFormatter * self, GESLayer * layer,
|
||||||
|
GString * str, GESTimeline * timeline, guint depth)
|
||||||
|
{
|
||||||
|
guint nb_tracks = 0, i;
|
||||||
|
GList *tmp, *tracks = ges_timeline_get_tracks (timeline);
|
||||||
|
GArray *deactivated_tracks = g_array_new (TRUE, FALSE, sizeof (gint32));
|
||||||
|
|
||||||
|
for (tmp = tracks; tmp; tmp = tmp->next, nb_tracks++) {
|
||||||
|
if (!ges_layer_get_active_for_track (layer, tmp->data))
|
||||||
|
g_array_append_val (deactivated_tracks, nb_tracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deactivated_tracks->len) {
|
||||||
|
g_string_append (str, ">\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->priv->min_version = MAX (self->priv->min_version, 7);
|
||||||
|
g_string_append (str, " deactivated-tracks='");
|
||||||
|
for (i = 0; i < deactivated_tracks->len; i++)
|
||||||
|
g_string_append_printf (str, "%d ", g_array_index (deactivated_tracks, gint,
|
||||||
|
i));
|
||||||
|
g_string_append (str, "'>\n");
|
||||||
|
|
||||||
|
done:
|
||||||
|
g_array_free (deactivated_tracks, TRUE);
|
||||||
|
g_list_free_full (tracks, gst_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_save_source (GESXmlFormatter * self, GString * str,
|
||||||
|
GESTimelineElement * element, GESTimeline * timeline, GList * tracks,
|
||||||
|
guint depth)
|
||||||
|
{
|
||||||
|
gint index, n_props;
|
||||||
|
gboolean serialize;
|
||||||
|
gchar *properties;
|
||||||
|
|
||||||
|
if (!GES_IS_SOURCE (element))
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_object_get (element, "serialize", &serialize, NULL);
|
||||||
|
if (!serialize) {
|
||||||
|
GST_DEBUG_OBJECT (element, "Should not be serialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
index =
|
||||||
|
g_list_index (tracks,
|
||||||
|
ges_track_element_get_track (GES_TRACK_ELEMENT (element)));
|
||||||
|
append_escaped (str,
|
||||||
|
g_markup_printf_escaped
|
||||||
|
(" <source track-id='%i' ", index), depth);
|
||||||
|
|
||||||
|
properties = _serialize_properties (G_OBJECT (element), &n_props,
|
||||||
|
"in-point", "priority", "start", "duration", "track", "track-type"
|
||||||
|
"uri", "name", "max-duration", NULL);
|
||||||
|
|
||||||
|
/* Try as possible to allow older versions of GES to load the files */
|
||||||
|
if (n_props) {
|
||||||
|
self->priv->min_version = MAX (self->priv->min_version, 7);
|
||||||
|
g_string_append_printf (str, "properties='%s' ", properties);
|
||||||
|
}
|
||||||
|
g_free (properties);
|
||||||
|
|
||||||
|
_save_children_properties (str, element, depth);
|
||||||
|
append_escaped (str, g_markup_printf_escaped (">\n"), depth);
|
||||||
|
_save_keyframes (str, GES_TRACK_ELEMENT (element), index, depth);
|
||||||
|
append_escaped (str, g_markup_printf_escaped (" </source>\n"),
|
||||||
|
depth);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
_save_layers (GESXmlFormatter * self, GString * str, GESTimeline * timeline,
|
_save_layers (GESXmlFormatter * self, GString * str, GESTimeline * timeline,
|
||||||
guint depth)
|
guint depth)
|
||||||
|
@ -1552,15 +1645,18 @@ _save_layers (GESXmlFormatter * self, GString * str, GESTimeline * timeline,
|
||||||
layer = GES_LAYER (tmplayer->data);
|
layer = GES_LAYER (tmplayer->data);
|
||||||
|
|
||||||
priority = ges_layer_get_priority (layer);
|
priority = ges_layer_get_priority (layer);
|
||||||
properties = _serialize_properties (G_OBJECT (layer), "priority", NULL);
|
properties =
|
||||||
|
_serialize_properties (G_OBJECT (layer), NULL, "priority", NULL);
|
||||||
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (layer));
|
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (layer));
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
g_markup_printf_escaped
|
g_markup_printf_escaped
|
||||||
(" <layer priority='%i' properties='%s' metadatas='%s'>\n",
|
(" <layer priority='%i' properties='%s' metadatas='%s'",
|
||||||
priority, properties, metas), depth);
|
priority, properties, metas), depth);
|
||||||
g_free (properties);
|
g_free (properties);
|
||||||
g_free (metas);
|
g_free (metas);
|
||||||
|
|
||||||
|
_save_layer_track_activness (self, layer, str, timeline, depth);
|
||||||
|
|
||||||
clips = ges_layer_get_clips (layer);
|
clips = ges_layer_get_clips (layer);
|
||||||
for (tmpclip = clips; tmpclip; tmpclip = tmpclip->next) {
|
for (tmpclip = clips; tmpclip; tmpclip = tmpclip->next) {
|
||||||
GList *effects, *tmpeffect;
|
GList *effects, *tmpeffect;
|
||||||
|
@ -1579,7 +1675,7 @@ _save_layers (GESXmlFormatter * self, GString * str, GESTimeline * timeline,
|
||||||
|
|
||||||
/* We escape all mandatrorry properties that are handled sparetely
|
/* We escape all mandatrorry properties that are handled sparetely
|
||||||
* and vtype for StandarTransition as it is the asset ID */
|
* and vtype for StandarTransition as it is the asset ID */
|
||||||
properties = _serialize_properties (G_OBJECT (clip),
|
properties = _serialize_properties (G_OBJECT (clip), NULL,
|
||||||
"supported-formats", "rate", "in-point", "start", "duration",
|
"supported-formats", "rate", "in-point", "start", "duration",
|
||||||
"max-duration", "priority", "vtype", "uri", NULL);
|
"max-duration", "priority", "vtype", "uri", NULL);
|
||||||
extractable_id = ges_extractable_get_id (GES_EXTRACTABLE (clip));
|
extractable_id = ges_extractable_get_id (GES_EXTRACTABLE (clip));
|
||||||
|
@ -1629,31 +1725,9 @@ _save_layers (GESXmlFormatter * self, GString * str, GESTimeline * timeline,
|
||||||
|
|
||||||
for (tmptrackelement = GES_CONTAINER_CHILDREN (clip); tmptrackelement;
|
for (tmptrackelement = GES_CONTAINER_CHILDREN (clip); tmptrackelement;
|
||||||
tmptrackelement = tmptrackelement->next) {
|
tmptrackelement = tmptrackelement->next) {
|
||||||
gint index;
|
_save_source (self, str, tmptrackelement->data, timeline, tracks,
|
||||||
gboolean serialize;
|
|
||||||
|
|
||||||
if (!GES_IS_SOURCE (tmptrackelement->data))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
g_object_get (tmptrackelement->data, "serialize", &serialize, NULL);
|
|
||||||
if (!serialize) {
|
|
||||||
GST_DEBUG_OBJECT (tmptrackelement->data, "Should not be serialized");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
index =
|
|
||||||
g_list_index (tracks,
|
|
||||||
ges_track_element_get_track (tmptrackelement->data));
|
|
||||||
append_escaped (str,
|
|
||||||
g_markup_printf_escaped (" <source track-id='%i'", index),
|
|
||||||
depth);
|
|
||||||
_save_children_properties (str, tmptrackelement->data, depth);
|
|
||||||
append_escaped (str, g_markup_printf_escaped (">\n"), depth);
|
|
||||||
_save_keyframes (str, tmptrackelement->data, index, depth);
|
|
||||||
append_escaped (str, g_markup_printf_escaped (" </source>\n"),
|
|
||||||
depth);
|
depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_free_full (tracks, gst_object_unref);
|
g_list_free_full (tracks, gst_object_unref);
|
||||||
|
|
||||||
string_append_with_depth (str, " </clip>\n", depth);
|
string_append_with_depth (str, " </clip>\n", depth);
|
||||||
|
@ -1695,7 +1769,7 @@ _save_group (GESXmlFormatter * self, GString * str, GList ** seen_groups,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
properties = _serialize_properties (G_OBJECT (group), NULL);
|
properties = _serialize_properties (G_OBJECT (group), NULL, NULL);
|
||||||
|
|
||||||
metadatas = ges_meta_container_metas_to_string (GES_META_CONTAINER (group));
|
metadatas = ges_meta_container_metas_to_string (GES_META_CONTAINER (group));
|
||||||
self->priv->min_version = MAX (self->priv->min_version, 5);
|
self->priv->min_version = MAX (self->priv->min_version, 5);
|
||||||
|
@ -1742,7 +1816,8 @@ _save_timeline (GESXmlFormatter * self, GString * str, GESTimeline * timeline,
|
||||||
{
|
{
|
||||||
gchar *properties = NULL, *metas = NULL;
|
gchar *properties = NULL, *metas = NULL;
|
||||||
|
|
||||||
properties = _serialize_properties (G_OBJECT (timeline), "update", "name",
|
properties =
|
||||||
|
_serialize_properties (G_OBJECT (timeline), NULL, "update", "name",
|
||||||
"async-handling", "message-forward", NULL);
|
"async-handling", "message-forward", NULL);
|
||||||
|
|
||||||
ges_meta_container_set_uint64 (GES_META_CONTAINER (timeline), "duration",
|
ges_meta_container_set_uint64 (GES_META_CONTAINER (timeline), "duration",
|
||||||
|
@ -1815,10 +1890,10 @@ _save_stream_profiles (GESXmlFormatter * self, GString * str,
|
||||||
if (GST_IS_PRESET (encoder) &&
|
if (GST_IS_PRESET (encoder) &&
|
||||||
gst_preset_load_preset (GST_PRESET (encoder), preset)) {
|
gst_preset_load_preset (GST_PRESET (encoder), preset)) {
|
||||||
|
|
||||||
gchar *settings = _serialize_properties (G_OBJECT (encoder), NULL);
|
gchar *settings =
|
||||||
append_escaped (str,
|
_serialize_properties (G_OBJECT (encoder), NULL, NULL);
|
||||||
g_markup_printf_escaped ("preset-properties='%s' ", settings),
|
append_escaped (str, g_markup_printf_escaped ("preset-properties='%s' ",
|
||||||
depth);
|
settings), depth);
|
||||||
g_free (settings);
|
g_free (settings);
|
||||||
}
|
}
|
||||||
gst_object_unref (encoder);
|
gst_object_unref (encoder);
|
||||||
|
@ -1893,7 +1968,8 @@ _save_encoding_profiles (GESXmlFormatter * self, GString * str,
|
||||||
if (element) {
|
if (element) {
|
||||||
if (GST_IS_PRESET (element) &&
|
if (GST_IS_PRESET (element) &&
|
||||||
gst_preset_load_preset (GST_PRESET (element), profpreset)) {
|
gst_preset_load_preset (GST_PRESET (element), profpreset)) {
|
||||||
gchar *settings = _serialize_properties (G_OBJECT (element), NULL);
|
gchar *settings =
|
||||||
|
_serialize_properties (G_OBJECT (element), NULL, NULL);
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
g_markup_printf_escaped ("preset-properties='%s' ", settings),
|
g_markup_printf_escaped ("preset-properties='%s' ", settings),
|
||||||
depth);
|
depth);
|
||||||
|
@ -1960,7 +2036,7 @@ _save_project (GESFormatter * formatter, GString * str, GESProject * project,
|
||||||
GESXmlFormatter *self = GES_XML_FORMATTER (formatter);
|
GESXmlFormatter *self = GES_XML_FORMATTER (formatter);
|
||||||
GESXmlFormatterPrivate *priv = _GET_PRIV (formatter);
|
GESXmlFormatterPrivate *priv = _GET_PRIV (formatter);
|
||||||
|
|
||||||
properties = _serialize_properties (G_OBJECT (project), NULL);
|
properties = _serialize_properties (G_OBJECT (project), NULL, NULL);
|
||||||
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (project));
|
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (project));
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
g_markup_printf_escaped (" <project properties='%s' metadatas='%s'>\n",
|
g_markup_printf_escaped (" <project properties='%s' metadatas='%s'>\n",
|
||||||
|
|
|
@ -77,6 +77,7 @@ if gstvalidate_dep.found()
|
||||||
'check_video_track_restriction_scale_with_keyframes',
|
'check_video_track_restriction_scale_with_keyframes',
|
||||||
'check_edit_in_frames',
|
'check_edit_in_frames',
|
||||||
'check_edit_in_frames_with_framerate_mismatch',
|
'check_edit_in_frames_with_framerate_mismatch',
|
||||||
|
'check_layer_activness_gaps',
|
||||||
]
|
]
|
||||||
|
|
||||||
env = environment()
|
env = environment()
|
||||||
|
|
|
@ -26,6 +26,7 @@ gi.require_version("GES", "1.0")
|
||||||
from gi.repository import Gst # noqa
|
from gi.repository import Gst # noqa
|
||||||
from gi.repository import GES # noqa
|
from gi.repository import GES # noqa
|
||||||
from gi.repository import GLib # noqa
|
from gi.repository import GLib # noqa
|
||||||
|
from gi.repository import GObject # noqa
|
||||||
import contextlib # noqa
|
import contextlib # noqa
|
||||||
import os #noqa
|
import os #noqa
|
||||||
import unittest # noqa
|
import unittest # noqa
|
||||||
|
@ -208,6 +209,93 @@ class GESSimpleTimelineTest(GESTest):
|
||||||
|
|
||||||
return clip
|
return clip
|
||||||
|
|
||||||
|
def assertElementAreEqual(self, ref, element):
|
||||||
|
self.assertTrue(isinstance(element, type(ref)), "%s and %s do not have the same type!" % (ref, element))
|
||||||
|
|
||||||
|
props = [p for p in ref.list_properties() if p.name not in ['name']
|
||||||
|
and not GObject.type_is_a(p.value_type, GObject.Object)]
|
||||||
|
for p in props:
|
||||||
|
pname = p.name
|
||||||
|
v0 = GObject.Value()
|
||||||
|
v0.init(p.value_type)
|
||||||
|
v0.set_value(ref.get_property(pname))
|
||||||
|
|
||||||
|
v1 = GObject.Value()
|
||||||
|
v1.init(p.value_type)
|
||||||
|
v1.set_value(element.get_property(pname))
|
||||||
|
|
||||||
|
self.assertTrue(Gst.value_compare(v0, v1) == Gst.VALUE_EQUAL,
|
||||||
|
"%s are not equal: %s != %s" % (pname, v0, v1))
|
||||||
|
|
||||||
|
if isinstance(ref, GES.TrackElement):
|
||||||
|
self.assertElementAreEqual(ref.get_nleobject(), element.get_nleobject())
|
||||||
|
return
|
||||||
|
|
||||||
|
if not isinstance(ref, GES.Clip):
|
||||||
|
return
|
||||||
|
|
||||||
|
ttypes = [track.type for track in self.timeline.get_tracks()]
|
||||||
|
for ttype in ttypes:
|
||||||
|
if ttypes.count(ttype) > 1:
|
||||||
|
self.warning("Can't deeply check %s and %s "
|
||||||
|
"(only one track per type supported %s %s found)" % (ref,
|
||||||
|
element, ttypes.count(ttype), ttype))
|
||||||
|
return
|
||||||
|
|
||||||
|
children = element.get_children(False)
|
||||||
|
for ref_child in ref.get_children(False):
|
||||||
|
ref_track = ref_child.get_track()
|
||||||
|
if not ref_track:
|
||||||
|
self.warning("Can't check %s as not in a track" % (ref_child))
|
||||||
|
continue
|
||||||
|
|
||||||
|
child = None
|
||||||
|
for tmpchild in children:
|
||||||
|
if not isinstance(tmpchild, type(ref_child)):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ref_track.type != tmpchild.get_track().type:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not isinstance(ref_child, GES.Effect):
|
||||||
|
child = tmpchild
|
||||||
|
break
|
||||||
|
elif ref_child.props.bin_description == child.props.bin_description:
|
||||||
|
child = tmpchild
|
||||||
|
break
|
||||||
|
|
||||||
|
self.assertIsNotNone(child, "Could not find equivalent child %s in %s(%s)" % (ref_child,
|
||||||
|
element, children))
|
||||||
|
|
||||||
|
self.assertElementAreEqual(ref_child, child)
|
||||||
|
|
||||||
|
def check_reload_timeline(self):
|
||||||
|
tmpf = tempfile.NamedTemporaryFile(suffix='.xges')
|
||||||
|
uri = Gst.filename_to_uri(tmpf.name)
|
||||||
|
self.assertTrue(self.timeline.save_to_uri(uri, None, True))
|
||||||
|
project = GES.Project.new(uri)
|
||||||
|
mainloop = create_main_loop()
|
||||||
|
def loaded_cb(unused_project, unused_timeline):
|
||||||
|
mainloop.quit()
|
||||||
|
|
||||||
|
project.connect("loaded", loaded_cb)
|
||||||
|
reloaded_timeline = project.extract()
|
||||||
|
|
||||||
|
mainloop.run()
|
||||||
|
self.assertIsNotNone(reloaded_timeline)
|
||||||
|
|
||||||
|
layers = self.timeline.get_layers()
|
||||||
|
reloaded_layers = reloaded_timeline.get_layers()
|
||||||
|
self.assertEqual(len(layers), len(reloaded_layers))
|
||||||
|
for layer, reloaded_layer in zip(layers, reloaded_layers):
|
||||||
|
clips = layer.get_clips()
|
||||||
|
reloaded_clips = reloaded_layer.get_clips()
|
||||||
|
self.assertEqual(len(clips), len(reloaded_clips))
|
||||||
|
for clip, reloaded_clip in zip(clips, reloaded_clips):
|
||||||
|
self.assertElementAreEqual(clip, reloaded_clip)
|
||||||
|
|
||||||
|
return reloaded_timeline
|
||||||
|
|
||||||
def assertTimelineTopology(self, topology, groups=[]):
|
def assertTimelineTopology(self, topology, groups=[]):
|
||||||
res = []
|
res = []
|
||||||
for layer in self.timeline.get_layers():
|
for layer in self.timeline.get_layers():
|
||||||
|
|
|
@ -222,6 +222,107 @@ class TestTimeline(common.GESSimpleTimelineTest):
|
||||||
self.assertEqual(self.timeline.get_frame_at(Gst.SECOND), 60)
|
self.assertEqual(self.timeline.get_frame_at(Gst.SECOND), 60)
|
||||||
self.assertEqual(clip.props.max_duration, Gst.SECOND)
|
self.assertEqual(clip.props.max_duration, Gst.SECOND)
|
||||||
|
|
||||||
|
def test_layer_active(self):
|
||||||
|
def check_nle_object_activeness(clip, track_type, active=None, ref_clip=None):
|
||||||
|
assert ref_clip is not None or active is not None
|
||||||
|
|
||||||
|
if ref_clip:
|
||||||
|
ref_elem, = ref_clip.find_track_elements(None, track_type, GES.Source)
|
||||||
|
active = ref_elem.get_nleobject().props.active
|
||||||
|
|
||||||
|
elem, = clip.find_track_elements(None, track_type, GES.Source)
|
||||||
|
self.assertIsNotNone(elem)
|
||||||
|
self.assertEqual(elem.get_nleobject().props.active, active)
|
||||||
|
|
||||||
|
def get_tracks(timeline):
|
||||||
|
for track in self.timeline.get_tracks():
|
||||||
|
if track.props.track_type == GES.TrackType.VIDEO:
|
||||||
|
video_track = track
|
||||||
|
else:
|
||||||
|
audio_track = track
|
||||||
|
return video_track, audio_track
|
||||||
|
|
||||||
|
|
||||||
|
def check_set_active_for_tracks(layer, active, tracks, expected_changed_tracks):
|
||||||
|
callback_called = []
|
||||||
|
def _check_active_changed_cb(layer, active, tracks, expected_tracks, expected_active):
|
||||||
|
self.assertEqual(set(tracks), set(expected_tracks))
|
||||||
|
self.assertEqual(active, expected_active)
|
||||||
|
callback_called.append(True)
|
||||||
|
|
||||||
|
layer.connect("active-changed", _check_active_changed_cb, expected_changed_tracks, active)
|
||||||
|
self.assertTrue(layer.set_active_for_tracks(active, tracks))
|
||||||
|
self.layer.disconnect_by_func(_check_active_changed_cb)
|
||||||
|
self.assertEqual(callback_called, [True])
|
||||||
|
|
||||||
|
c0 = self.append_clip()
|
||||||
|
check_nle_object_activeness(c0, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c0, GES.TrackType.AUDIO, True)
|
||||||
|
|
||||||
|
elem, = c0.find_track_elements(None, GES.TrackType.AUDIO, GES.Source)
|
||||||
|
elem.props.active = False
|
||||||
|
check_nle_object_activeness(c0, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c0, GES.TrackType.AUDIO, False)
|
||||||
|
self.check_reload_timeline()
|
||||||
|
elem.props.active = True
|
||||||
|
|
||||||
|
# Muting audio track
|
||||||
|
video_track, audio_track = get_tracks(self.timeline)
|
||||||
|
|
||||||
|
check_set_active_for_tracks(self.layer, False, [audio_track], [audio_track])
|
||||||
|
|
||||||
|
check_nle_object_activeness(c0, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c0, GES.TrackType.AUDIO, False)
|
||||||
|
self.check_reload_timeline()
|
||||||
|
|
||||||
|
c1 = self.append_clip()
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, False)
|
||||||
|
|
||||||
|
l1 = self.timeline.append_layer()
|
||||||
|
c1.move_to_layer(l1)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, True)
|
||||||
|
|
||||||
|
self.assertTrue(c1.edit([], self.layer.get_priority(), GES.EditMode.EDIT_NORMAL,
|
||||||
|
GES.Edge.EDGE_NONE, c1.props.start))
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, False)
|
||||||
|
self.check_reload_timeline()
|
||||||
|
|
||||||
|
self.assertTrue(self.layer.remove_clip(c1))
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, True)
|
||||||
|
|
||||||
|
self.assertTrue(self.layer.add_clip(c1))
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, False)
|
||||||
|
|
||||||
|
check_set_active_for_tracks(self.layer, True, None, [audio_track])
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, True)
|
||||||
|
|
||||||
|
elem, = c1.find_track_elements(None, GES.TrackType.AUDIO, GES.Source)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, True)
|
||||||
|
|
||||||
|
# Force deactivating a specific TrackElement
|
||||||
|
elem.props.active = False
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, True)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, False)
|
||||||
|
self.check_reload_timeline()
|
||||||
|
|
||||||
|
# Try activating a specific TrackElement, that won't change the
|
||||||
|
# underlying nleobject activness
|
||||||
|
check_set_active_for_tracks(self.layer, False, None, [audio_track, video_track])
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, False)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, False)
|
||||||
|
|
||||||
|
elem.props.active = True
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.VIDEO, False)
|
||||||
|
check_nle_object_activeness(c1, GES.TrackType.AUDIO, False)
|
||||||
|
self.check_reload_timeline()
|
||||||
|
|
||||||
|
|
||||||
class TestEditing(common.GESSimpleTimelineTest):
|
class TestEditing(common.GESSimpleTimelineTest):
|
||||||
|
|
||||||
|
|
24
tests/check/scenarios/check_layer_activness_gaps.scenario
Normal file
24
tests/check/scenarios/check_layer_activness_gaps.scenario
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
description, handles-states=true,
|
||||||
|
ges-options={\
|
||||||
|
"--disable-mixing",
|
||||||
|
"--videosink=fakevideosink",
|
||||||
|
"--audiosink=fakesink"\
|
||||||
|
}
|
||||||
|
|
||||||
|
add-clip, name=clip, asset-id="framerate=30/1", layer-priority=0, type=GESTestClip, pattern=blue, duration=5000.0
|
||||||
|
set-layer-active, tracks={gesvideotrack0}, active=false, layer-priority=0
|
||||||
|
|
||||||
|
pause;
|
||||||
|
|
||||||
|
# Make sure the video test src is a gap test src.
|
||||||
|
check-property, target-element-factory-name=videotestsrc, property-name=pattern, property-value="100% Black"
|
||||||
|
check-property, target-element-factory-name=audiotestsrc, property-name=wave, property-value="Sine"
|
||||||
|
|
||||||
|
set-layer-active, tracks={gesvideotrack0}, active=true, layer-priority=0
|
||||||
|
set-layer-active, tracks={gesaudiotrack0}, active=false, layer-priority=0
|
||||||
|
commit;
|
||||||
|
# Make sure the video test src is the GESVideoTestSource and the audio test source is a gap
|
||||||
|
check-property, target-element-factory-name=videotestsrc, property-name=pattern, property-value="Blue"
|
||||||
|
check-property, target-element-factory-name=audiotestsrc, property-name=wave, property-value="Silence"
|
||||||
|
|
||||||
|
stop;
|
Loading…
Reference in a new issue