diff --git a/subprojects/gst-editing-services/docs/gst_plugins_cache.json b/subprojects/gst-editing-services/docs/gst_plugins_cache.json index b3186450e0..ff1713ef93 100644 --- a/subprojects/gst-editing-services/docs/gst_plugins_cache.json +++ b/subprojects/gst-editing-services/docs/gst_plugins_cache.json @@ -265,7 +265,20 @@ "presence": "always" } }, - "properties": {}, + "properties": { + "reverse": { + "blurb": "Whether to playback the source reverse or not", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + } + }, "rank": "none", "signals": {} }, diff --git a/subprojects/gst-editing-services/ges/ges-source.c b/subprojects/gst-editing-services/ges/ges-source.c index 9ee6ce8d29..9b65289480 100644 --- a/subprojects/gst-editing-services/ges/ges-source.c +++ b/subprojects/gst-editing-services/ges/ges-source.c @@ -266,6 +266,36 @@ ges_source_get_rendering_smartly (GESSource * source) return source->priv->is_rendering_smartly; } +static GstElement * +ges_source_create_nle_object (GESTrackElement * self) +{ + GParamSpec *pspec; + GstElement *nleobject; + + nleobject = + GES_TRACK_ELEMENT_CLASS (ges_source_parent_class)->create_gnl_object + (self); + + if (!nleobject) + return NULL; + + pspec = + g_object_class_find_property (G_OBJECT_GET_CLASS (nleobject), "reverse"); + g_assert (pspec); + + + if (!ges_timeline_element_add_child_property_full (GES_TIMELINE_ELEMENT + (self), NULL, pspec, G_OBJECT (nleobject), + GES_TIMELINE_ELEMENT_CHILD_PROP_FLAG_SET_ON_ALL_INSTANCES)) + GST_ERROR_OBJECT (self, + "Could not register the child property 'reverse' for %" GST_PTR_FORMAT, + nleobject); + + g_param_spec_unref (pspec); + + return nleobject; +} + static void ges_source_dispose (GObject * object) { @@ -290,6 +320,7 @@ ges_source_class_init (GESSourceClass * klass) track_class->nleobject_factorytype = "nlesource"; track_class->create_element = NULL; + track_class->create_gnl_object = ges_source_create_nle_object; object_class->dispose = ges_source_dispose; GES_TRACK_ELEMENT_CLASS_DEFAULT_HAS_INTERNAL_SOURCE (klass) = TRUE; diff --git a/subprojects/gst-editing-services/ges/ges-timeline-element.c b/subprojects/gst-editing-services/ges/ges-timeline-element.c index 3bb80ae0f3..c5136f58d4 100644 --- a/subprojects/gst-editing-services/ges/ges-timeline-element.c +++ b/subprojects/gst-editing-services/ges/ges-timeline-element.c @@ -408,17 +408,16 @@ ges_timeline_element_finalize (GObject * self) } static void -_child_prop_spec (ChildPropSpec * childprop) +_child_prop_spec_free (ChildPropSpec * childprop) { g_object_freeze_notify (childprop->child); if (childprop->handler_id) g_signal_handler_disconnect (childprop->child, childprop->handler_id); g_object_thaw_notify (childprop->child); - if (handler->child != (GObject *) handler->self && - handler->child != (GObject *) handler->owner) - gst_object_unref (handler->child); - g_free (handler); + if (childprop->child != (GObject *) childprop->self && + childprop->child != (GObject *) childprop->owner) + gst_object_unref (childprop->child); } static gboolean @@ -439,7 +438,7 @@ ges_timeline_element_init (GESTimelineElement * self) self->priv->children_props = g_array_new (TRUE, TRUE, sizeof (ChildPropSpec)); g_array_set_clear_func (self->priv->children_props, - (GDestroyNotify) _child_prop_spec); + (GDestroyNotify) _child_prop_spec_free); } static void @@ -809,7 +808,7 @@ child_prop_changed_cb (GObject * child, GParamSpec * arg, static gboolean set_child_property (GESTimelineElement * self, ChildPropSpec * childprop, - const GValue * value, GError **error) + const GValue * value, GError ** error) { GESTimelineElement *setter = self; GESTimelineElementClass *klass; @@ -823,7 +822,7 @@ set_child_property (GESTimelineElement * self, ChildPropSpec * childprop, if (klass->set_child_property_full) return klass->set_child_property_full (setter, childprop->child, - childprop->pspec, value, error); + childprop->pspec, value, error); g_assert (klass->set_child_property); klass->set_child_property (setter, childprop->child, childprop->pspec, @@ -901,8 +900,7 @@ ges_timeline_element_add_child_property_full (GESTimelineElement * self, child, pspec->name); signame = g_strconcat ("notify::", pspec->name, NULL); - handler = (ChildPropHandler *) g_new0 (ChildPropHandler, 1); - handler->self = self; + childprop.self = self; if (child == G_OBJECT (self) || child == G_OBJECT (owner)) childprop.child = child; else @@ -2321,12 +2319,12 @@ ges_timeline_element_remove_child_property_full (GESTimelineElement * self, g_array_set_clear_func (self->priv->children_props, NULL); g_array_remove_index (self->priv->children_props, index); g_array_set_clear_func (self->priv->children_props, - (GDestroyNotify) _child_prop_spec); + (GDestroyNotify) _child_prop_spec_free); g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_REMOVED], 0, handler_copy.child, handler_copy.pspec); - _child_prop_spec (&handler_copy); + _child_prop_spec_free (&handler_copy); return TRUE; } diff --git a/subprojects/gst-editing-services/plugins/nle/nleghostpad.c b/subprojects/gst-editing-services/plugins/nle/nleghostpad.c index eeefdc0997..06ccb1e3ce 100644 --- a/subprojects/gst-editing-services/plugins/nle/nleghostpad.c +++ b/subprojects/gst-editing-services/plugins/nle/nleghostpad.c @@ -72,6 +72,12 @@ nle_object_translate_incoming_seek (NleObject * object, GstEvent * event) if (G_UNLIKELY (format != GST_FORMAT_TIME)) goto invalid_format; + + if (NLE_IS_SOURCE (object) && NLE_SOURCE (object)->reverse) { + GST_DEBUG_OBJECT (object, "Reverse playback! %d", seqnum); + rate = -rate; + } + /* convert cur */ ncurtype = GST_SEEK_TYPE_SET; if (G_LIKELY ((curtype == GST_SEEK_TYPE_SET) diff --git a/subprojects/gst-editing-services/plugins/nle/nlesource.c b/subprojects/gst-editing-services/plugins/nle/nlesource.c index db5316ce4f..4c94885e6b 100644 --- a/subprojects/gst-editing-services/plugins/nle/nlesource.c +++ b/subprojects/gst-editing-services/plugins/nle/nlesource.c @@ -38,12 +38,20 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); +enum +{ + PROP_0, + PROP_REVERSE, + PROP_LAST, +}; + GST_DEBUG_CATEGORY_STATIC (nlesource); #define GST_CAT_DEFAULT nlesource #define _do_init \ GST_DEBUG_CATEGORY_INIT (nlesource, "nlesource", GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin Source Element"); #define nle_source_parent_class parent_class + struct _NleSourcePrivate { gboolean dispose_has_run; @@ -62,6 +70,10 @@ struct _NleSourcePrivate GstEvent *seek_event; guint32 flush_seqnum; gulong probeid; + + + /* Identity automatically created to handle reverse playback */ + GstElement *identity; }; G_DEFINE_TYPE_WITH_CODE (NleSource, nle_source, NLE_TYPE_OBJECT, @@ -80,6 +92,57 @@ nle_source_control_element_func (NleSource * source, GstElement * element); static GstStateChangeReturn nle_source_change_state (GstElement * element, GstStateChange transition); +static gboolean +nle_source_commit (NleObject * object, gboolean recurse) +{ + NleSource *self = NLE_SOURCE (object); + + if (!NLE_OBJECT_CLASS (parent_class)->commit (object, recurse)) + return FALSE; + + self->reverse = self->pending_reverse; + g_object_set (self->priv->identity, "single-segment", self->reverse, NULL); + + return TRUE; +} + +static void +nle_source_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + NleSource *self = NLE_SOURCE (object); + + GST_OBJECT_LOCK (self); + switch (property_id) { + case PROP_REVERSE: + g_value_set_boolean (value, self->pending_reverse); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } + GST_OBJECT_UNLOCK (self); +} + +static void +nle_source_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + NleSource *self = NLE_SOURCE (object); + + GST_OBJECT_LOCK (self); + switch (property_id) { + case PROP_REVERSE: + self->pending_reverse = g_value_get_boolean (value); + if (self->pending_reverse != self->reverse) + nle_object_set_commit_needed ((NleObject *) self); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } + GST_OBJECT_UNLOCK (self); +} + + static void nle_source_class_init (NleSourceClass * klass) { @@ -93,6 +156,20 @@ nle_source_class_init (NleSourceClass * klass) gstbin_class = (GstBinClass *) klass; nleobject_class = (NleObjectClass *) klass; + gobject_class->get_property = nle_source_get_property; + gobject_class->set_property = nle_source_set_property; + + /** + * NleSource:reverse: + * @reverse: Whether to playback the source reverse or not + * + * Since: 1.26 + */ + g_object_class_install_property (gobject_class, PROP_REVERSE, + g_param_spec_boolean ("reverse", "Reverse", + "Whether to playback the source reverse or not", FALSE, + G_PARAM_READWRITE)); + gst_element_class_set_static_metadata (gstelement_class, "GNonLin Source", "Filter/Editor", "Manages source elements", @@ -106,6 +183,7 @@ nle_source_class_init (NleSourceClass * klass) klass->control_element = GST_DEBUG_FUNCPTR (nle_source_control_element_func); nleobject_class->prepare = GST_DEBUG_FUNCPTR (nle_source_prepare); + nleobject_class->commit = GST_DEBUG_FUNCPTR (nle_source_commit); gstbin_class->add_element = GST_DEBUG_FUNCPTR (nle_source_add_element); gstbin_class->remove_element = GST_DEBUG_FUNCPTR (nle_source_remove_element); @@ -139,10 +217,19 @@ srcpad_probe_cb (GstPad * pad, GstPadProbeInfo * info, NleSource * source) static void nle_source_init (NleSource * source) { + NleSourcePrivate *priv; + NleObject *nleobject = NLE_OBJECT (source); + GST_OBJECT_FLAG_SET (source, NLE_OBJECT_SOURCE); source->element = NULL; - source->priv = nle_source_get_instance_private (source); - g_mutex_init (&source->priv->seek_lock); + priv = source->priv = nle_source_get_instance_private (source); + priv->identity = gst_element_factory_make ("identity", NULL); + + gst_bin_add (GST_BIN (source), priv->identity); + nle_object_ghost_pad_set_target (nleobject, nleobject->srcpad, + priv->identity->srcpads->data); + + g_mutex_init (&priv->seek_lock); gst_pad_add_probe (NLE_OBJECT_SRC (source), GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, (GstPadProbeCallback) srcpad_probe_cb, @@ -158,6 +245,8 @@ nle_source_dispose (GObject * object) NleObject *nleobject = (NleObject *) object; NleSource *source = (NleSource *) object; NleSourcePrivate *priv = source->priv; + GstElement *tmpidentity; + GST_DEBUG_OBJECT (object, "dispose"); @@ -173,26 +262,18 @@ nle_source_dispose (GObject * object) } GST_OBJECT_UNLOCK (object); - - if (source->element) { - gst_object_unref (source->element); - source->element = NULL; - } + gst_clear_object (&source->element); + tmpidentity = priv->identity; + priv->identity = NULL; + gst_bin_remove (GST_BIN (source), tmpidentity); priv->dispose_has_run = TRUE; - if (priv->ghostedpad) - nle_object_ghost_pad_set_target (nleobject, nleobject->srcpad, NULL); + nle_object_ghost_pad_set_target (nleobject, nleobject->srcpad, NULL); - if (priv->staticpad) { - gst_object_unref (priv->staticpad); - priv->staticpad = NULL; - } + gst_clear_object (&priv->staticpad); g_mutex_lock (&priv->seek_lock); - if (priv->seek_event) { - gst_event_unref (priv->seek_event); - priv->seek_event = NULL; - } + gst_clear_event (&priv->seek_event); g_mutex_unlock (&priv->seek_lock); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -225,12 +306,14 @@ element_pad_added_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad, } gst_caps_unref (srccaps); - priv->ghostedpad = pad; - GST_DEBUG_OBJECT (nleobject, "SET target %" GST_PTR_FORMAT, pad); - nle_object_ghost_pad_set_target (nleobject, nleobject->srcpad, pad); - - GST_DEBUG_OBJECT (source, "Using pad pad %s:%s as a target now!", - GST_DEBUG_PAD_NAME (pad)); + if (gst_pad_link (pad, priv->identity->sinkpads->data) != GST_PAD_LINK_OK) { + GST_ERROR_OBJECT (source, "Could not link pads: %" GST_PTR_FORMAT + " and %" GST_PTR_FORMAT, pad, priv->identity->sinkpads->data); + } else { + GST_DEBUG_OBJECT (source, "Linked pads: %" GST_PTR_FORMAT + " and %" GST_PTR_FORMAT, pad, priv->identity->sinkpads->data); + priv->ghostedpad = pad; + } } static void @@ -238,7 +321,6 @@ element_pad_removed_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad, NleSource * source) { NleSourcePrivate *priv = source->priv; - NleObject *nleobject = (NleObject *) source; GST_DEBUG_OBJECT (source, "pad %s:%s (controlled pad %s:%s)", GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (priv->ghostedpad)); @@ -249,9 +331,9 @@ element_pad_removed_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad, GST_DEBUG_OBJECT (source, "Clearing up ghostpad"); - if (nleobject->srcpad) - nle_object_ghost_pad_set_target (NLE_OBJECT (source), nleobject->srcpad, - NULL); + if (priv->identity && !gst_pad_unlink (pad, priv->identity->sinkpads->data)) + GST_ERROR_OBJECT (source, "Could not unlink pads: %" GST_PTR_FORMAT + " and %" GST_PTR_FORMAT, pad, priv->identity->sinkpads->data); priv->ghostedpad = NULL; } else { GST_DEBUG_OBJECT (source, "The removed pad is NOT our controlled pad"); @@ -343,6 +425,9 @@ nle_source_control_element_func (NleSource * source, GstElement * element) NleSourcePrivate *priv = source->priv; GstPad *pad = NULL; + if (element == priv->identity) + return TRUE; + g_return_val_if_fail (source->element == NULL, FALSE); GST_DEBUG_OBJECT (source, "element: %" GST_PTR_FORMAT ", source->element:%" @@ -353,8 +438,13 @@ nle_source_control_element_func (NleSource * source, GstElement * element) if (get_valid_src_pad (source, source->element, &pad)) { priv->staticpad = pad; - nle_object_ghost_pad_set_target (NLE_OBJECT (source), - NLE_OBJECT_SRC (source), pad); + if (gst_pad_link (pad, priv->identity->sinkpads->data) != GST_PAD_LINK_OK) { + GST_ERROR_OBJECT (source, "Could not link pads: %" GST_PTR_FORMAT + " and %" GST_PTR_FORMAT, pad, priv->identity->sinkpads->data); + } else { + GST_DEBUG_OBJECT (source, "Linked pads: %" GST_PTR_FORMAT + " and %" GST_PTR_FORMAT, pad, priv->identity->sinkpads->data); + } priv->dynamicpads = FALSE; } else { priv->dynamicpads = has_dynamic_srcpads (element); @@ -544,7 +634,8 @@ nle_source_prepare (NleObject * object) stop = object->inpoint + object->duration; g_mutex_lock (&source->priv->seek_lock); - source->priv->seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME, + source->priv->seek_event = gst_event_new_seek (source->reverse ? -1.0 : 1.0, + GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop); g_mutex_unlock (&source->priv->seek_lock); diff --git a/subprojects/gst-editing-services/plugins/nle/nlesource.h b/subprojects/gst-editing-services/plugins/nle/nlesource.h index 6fcb1af4a2..1a6f7169c3 100644 --- a/subprojects/gst-editing-services/plugins/nle/nlesource.h +++ b/subprojects/gst-editing-services/plugins/nle/nlesource.h @@ -45,6 +45,8 @@ typedef struct _NleSourcePrivate NleSourcePrivate; struct _NleSource { NleObject parent; + gboolean reverse; + gboolean pending_reverse; /* controlled source element, acces with gst_bin_[add|remove]_element */ GstElement *element; diff --git a/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source.validatetest b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source.validatetest new file mode 100644 index 0000000000..96a4709b8d --- /dev/null +++ b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source.validatetest @@ -0,0 +1,25 @@ +meta, + tool = "ges-launch-$(gst_api_version)", + args = { + --videosink, "fakevideosink name=videosink qos=false", + --audiosink, "fakeaudiosink name=audiosink qos=false", + --video-caps, "video/x-raw,width=1280,height=720,framerate=30/1,format=I420", + --audio-caps, "audio/x-raw,rate=44100,format=S32LE,channels=2,layout=interleaved", + }, + handles-states = true, + ignore-eos = true, + configs = { + # We can't record buffers on sources as we have no timing guarantees + "$(validateflow), pad=videosrcbin:src, ignored-fields=\"stream-start={stream-id, group-id, stream}\"", + "$(validateflow), pad=videosink:sink, record-buffers=true, ignored-fields=\"stream-start={stream-id, group-id, stream}\"", + "$(validateflow), pad=audiosrcbin:src, ignored-fields=\"stream-start={stream-id, group-id, stream}\"", + "$(validateflow), pad=audiosink:sink, record-buffers=true, ignored-fields=\"stream-start={stream-id, group-id, stream}\"", + } + +add-clip, name=c0, asset-id="time-overlay,disable-timecodestamper=true", layer-priority=0, type=GESTestClip, start=0, duration=1.0 +set-child-properties, element-name=c0, pattern=blue, valignment=center, halignment=center, reverse=true +play + +pause, on-message=eos +check-position, expected-position=1000000001 +stop diff --git a/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-audiosink-sink-expected b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-audiosink-sink-expected new file mode 100644 index 0000000000..1c918cfb9d --- /dev/null +++ b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-audiosink-sink-expected @@ -0,0 +1,107 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE; +event caps: audio/x-raw, channel-mask=(bitmask)0x0000000000000003, channels=(int)2, format=(string)S32LE, layout=(string)interleaved, rate=(int)44100; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:01.000000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +buffer: pts=0:00:00.000000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.010000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.020000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.030000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.040000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.050000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.060000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.070000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.080000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.090000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.100000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.110000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.120000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.130000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.140000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.150000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.160000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.170000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.180000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.190000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.200000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.210000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.220000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.230000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.240000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.250000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.260000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.270000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.280000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.290000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.300000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.310000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.320000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.330000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.340000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.350000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.360000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.370000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.380000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.390000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.400000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.410000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.420000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.430000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.440000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.450000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.460000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.470000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.480000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.490000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.500000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.510000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.520000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.530000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.540000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.550000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.560000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.570000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.580000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.590000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.600000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.610000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.620000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.630000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.640000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.650000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.660000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.670000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.680000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.690000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.700000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.710000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.720000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.730000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.740000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.750000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.760000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.770000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.780000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.790000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.800000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.810000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.820000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.830000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.840000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.850000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.860000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.870000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.880000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.890000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.900000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.910000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.920000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.930000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.940000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.950000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.960000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.970000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.980000000, dur=0:00:00.010000000 +buffer: pts=0:00:00.990000000, dur=0:00:00.010000000 +event segment: format=TIME, start=0:00:01.000000000, offset=0:00:00.000000000, stop=0:00:01.000000001, flags=0x01, time=0:00:01.000000000, base=0:00:01.000000000, position=0:00:01.000000000 +buffer: pts=0:00:01.000000000, dur=0:00:00.000000001, flags=gap +event gap: GstEventGap, duration=(guint64)18446744073709551615, timestamp=(guint64)1000022675; +event eos: (no structure) diff --git a/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-audiosrcbin-src-expected b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-audiosrcbin-src-expected new file mode 100644 index 0000000000..f66b32d7c3 --- /dev/null +++ b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-audiosrcbin-src-expected @@ -0,0 +1,8 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE; +event caps: audio/x-raw, channel-mask=(bitmask)0x0000000000000003, channels=(int)2, format=(string)S32LE, layout=(string)interleaved, rate=(int)44100; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ description\=\(string\)\"audiotest\\\ wave\"\;"; +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:01.000000000, rate=-1.000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:01.000000000 +event eos: (no structure) diff --git a/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-videosink-sink-expected b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-videosink-sink-expected new file mode 100644 index 0000000000..0dbaa790ca --- /dev/null +++ b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-videosink-sink-expected @@ -0,0 +1,37 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE; +event caps: video/x-raw, colorimetry=(string)bt709, format=(string)I420, framerate=(fraction)30/1, height=(int)720, width=(int)1280; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:01.000000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=none +buffer: pts=0:00:00.000000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.033333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.066666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.100000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.133333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.166666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.200000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.233333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.266666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.300000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.333333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.366666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.400000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.433333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.466666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.500000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.533333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.566666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.600000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.633333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.666666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.700000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.733333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.766666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.800000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.833333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.866666666, dur=0:00:00.033333334, meta=GstVideoMeta +buffer: pts=0:00:00.900000000, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.933333333, dur=0:00:00.033333333, meta=GstVideoMeta +buffer: pts=0:00:00.966666666, dur=0:00:00.033333334, meta=GstVideoMeta +event caps: video/x-raw, colorimetry=(string)bt601, format=(string)I420, framerate=(fraction)30/1, height=(int)720, width=(int)1280; +event segment: format=TIME, start=0:00:01.000000000, offset=0:00:00.000000000, stop=0:00:01.000000001, flags=0x01, time=0:00:01.000000000, base=0:00:01.000000000, position=none +buffer: pts=0:00:01.000000000, dur=0:00:00.000000001, meta=GstVideoMeta +event eos: (no structure) diff --git a/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-videosrcbin-src-expected b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-videosrcbin-src-expected new file mode 100644 index 0000000000..70fc6bf616 --- /dev/null +++ b/subprojects/gst-integration-testsuites/ges/scenarios/check_reverse_source/flow-expectations/log-videosrcbin-src-expected @@ -0,0 +1,7 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE; +event caps: video/x-raw, format=(string)AYUV, framerate=(fraction)30/1, height=(int)720, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)1280; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:01.000000000, rate=-1.000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:01.000000000 +event eos: (no structure) diff --git a/subprojects/gst-integration-testsuites/ges/scenarios/timelineelement.set_child_prop_on_all_instances.validatetest b/subprojects/gst-integration-testsuites/ges/scenarios/timelineelement.set_child_prop_on_all_instances.validatetest new file mode 100644 index 0000000000..5e59808492 --- /dev/null +++ b/subprojects/gst-integration-testsuites/ges/scenarios/timelineelement.set_child_prop_on_all_instances.validatetest @@ -0,0 +1,39 @@ +meta, + tool = "ges-launch-$(gst_api_version)", + handles-states = true + +add-clip, name=c0, asset-id="time-overlay", layer-priority=0, type=GESTestClip, start=0, duration=1.0 +check-child-properties, element-name=videotestsource0, reverse=false +check-child-properties, element-name=audiotestsource0, reverse=false + +set-child-properties, element-name=c0, pattern=blue, valignment=center, halignment=center, reverse=true +check-child-properties, element-name=videotestsource0, reverse=true +check-child-properties, element-name=audiotestsource0, reverse=true + +set-child-properties, element-name=videotestsource0, reverse=false +check-child-properties, element-name=videotestsource0, reverse=false +check-child-properties, element-name=audiotestsource0, reverse=true + + +add-clip, name=c1, asset-id=GESTestClip, layer-priority=0, type=GESTestClip, start=1.0, duration=2.0 +group, containers={c0, c1}, container-name=g0 + +set-child-properties, element-name=g0, reverse=true +check-child-properties, element-name=videotestsource0, reverse=true +check-child-properties, element-name=audiotestsource0, reverse=true +check-child-properties, element-name=videotestsource1, reverse=true +check-child-properties, element-name=audiotestsource1, reverse=true + +set-child-properties, element-name=audiotestsource1, reverse=false +check-child-properties, element-name=videotestsource0, reverse=true +check-child-properties, element-name=audiotestsource0, reverse=true +check-child-properties, element-name=videotestsource1, reverse=true +check-child-properties, element-name=audiotestsource1, reverse=false + +ungroup-container, container-name=g0 +check-child-properties, element-name=videotestsource0, reverse=true +check-child-properties, element-name=audiotestsource0, reverse=true +check-child-properties, element-name=videotestsource1, reverse=true +check-child-properties, element-name=audiotestsource1, reverse=false + +stop diff --git a/subprojects/gst-integration-testsuites/testsuites/ges.testslist b/subprojects/gst-integration-testsuites/testsuites/ges.testslist index 93e7544c42..dcafaf11d2 100644 --- a/subprojects/gst-integration-testsuites/testsuites/ges.testslist +++ b/subprojects/gst-integration-testsuites/testsuites/ges.testslist @@ -762,3 +762,5 @@ ges.test.play_two_nested_back_to_back ges.test.seek_on_stack_change_on_internal_subtimeline ges.test.videoscale_effect ges.test.backward_playback_with_start +ges.test.check_reverse_source +ges.test.timelineelement.set_child_prop_on_all_instances