ges: Add support for sources reverse playback

It introduces a `reverse` property at the `nlesource` level which will
basically reverse playback of the clip.

We guarantee that outside that clip, the data flow looks like it was
playing forward as we add an 'identity' element with `single-segment=true`.

This start making use of the newly introduced concept of
`CHILD_PROP_FLAG_SET_ON_ALL_INSTANCES` as it is natural that
doing `source_clip.set_child_property("reverse", True)` will make
the whole clip go reverse, meaning that all the GESSource children
properties will be set. To set an individual source "reverse" child
property as the desired effect.

Fixes: https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/24
Depends on: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/451

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/918>
This commit is contained in:
Thibault Saunier 2020-05-01 22:56:38 -04:00 committed by GStreamer Marge Bot
parent 526f00b07f
commit a342d14ba9
13 changed files with 409 additions and 43 deletions

View file

@ -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": {}
},

View file

@ -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;

View file

@ -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;
}

View file

@ -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)

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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