gstreamer/plugins/nle/nleobject.c
2020-06-23 12:09:12 -04:00

859 lines
27 KiB
C

/* Gnonlin
* Copyright (C) <2001> Wim Taymans <wim.taymans@gmail.com>
* <2004-2008> Edward Hervey <bilboed@bilboed.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "nle.h"
/**
* SECTION:nleobject
* @short_description: Base class for GNonLin elements
*
* NleObject encapsulates default behaviour and implements standard
* properties provided by all the GNonLin elements.
*/
GST_DEBUG_CATEGORY_STATIC (nleobject_debug);
#define GST_CAT_DEFAULT nleobject_debug
static GObjectClass *parent_class = NULL;
/****************************************************
* Helper macros *
****************************************************/
#define CHECK_AND_SET(PROPERTY, property, prop_str, print_format) \
{ \
if (object->pending_##property != object->property) { \
object->property = object->pending_##property; \
GST_DEBUG_OBJECT(object, "Setting " prop_str " to %" \
print_format, object->property); \
} else \
GST_DEBUG_OBJECT(object, "Nothing to do for " prop_str); \
}
#define SET_PENDING_VALUE(property, property_str, type, print_format) \
nleobject->pending_##property = g_value_get_##type (value); \
if (nleobject->property != nleobject->pending_##property) { \
GST_DEBUG_OBJECT(object, "Setting pending " property_str " to %" \
print_format, nleobject->pending_##property); \
nle_object_set_commit_needed (nleobject); \
} else \
GST_DEBUG_OBJECT(object, "Pending " property_str " did not change");
enum
{
PROP_0,
PROP_START,
PROP_DURATION,
PROP_STOP,
PROP_INPOINT,
PROP_PRIORITY,
PROP_ACTIVE,
PROP_CAPS,
PROP_EXPANDABLE,
PROP_MEDIA_DURATION_FACTOR,
PROP_LAST
};
enum
{
COMMIT_SIGNAL,
LAST_SIGNAL
};
static guint _signals[LAST_SIGNAL] = { 0 };
static GParamSpec *properties[PROP_LAST];
static void nle_object_dispose (GObject * object);
static void nle_object_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void nle_object_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void nle_object_constructed (GObject * object);
static GstStateChangeReturn nle_object_change_state (GstElement * element,
GstStateChange transition);
static gboolean nle_object_prepare_func (NleObject * object);
static gboolean nle_object_cleanup_func (NleObject * object);
static gboolean nle_object_commit_func (NleObject * object, gboolean recurse);
static GstStateChangeReturn nle_object_prepare (NleObject * object);
static void
nle_object_class_init (NleObjectClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
NleObjectClass *nleobject_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
nleobject_class = (NleObjectClass *) klass;
GST_DEBUG_CATEGORY_INIT (nleobject_debug, "nleobject",
GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin object");
parent_class = g_type_class_ref (GST_TYPE_BIN);
gobject_class->set_property = GST_DEBUG_FUNCPTR (nle_object_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (nle_object_get_property);
gobject_class->constructed = GST_DEBUG_FUNCPTR (nle_object_constructed);
gobject_class->dispose = GST_DEBUG_FUNCPTR (nle_object_dispose);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (nle_object_change_state);
nleobject_class->prepare = GST_DEBUG_FUNCPTR (nle_object_prepare_func);
nleobject_class->cleanup = GST_DEBUG_FUNCPTR (nle_object_cleanup_func);
nleobject_class->commit_signal_handler =
GST_DEBUG_FUNCPTR (nle_object_commit);
nleobject_class->commit = GST_DEBUG_FUNCPTR (nle_object_commit_func);
/**
* NleObject:start
*
* The start position relative to the parent in nanoseconds.
*/
properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
"The start position relative to the parent (in nanoseconds)",
0, G_MAXUINT64, 0, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_START,
properties[PROP_START]);
/**
* NleObject:duration
*
* The outgoing duration in nanoseconds.
*/
properties[PROP_DURATION] = g_param_spec_int64 ("duration", "Duration",
"Outgoing duration (in nanoseconds)", 0, G_MAXINT64, 0,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_DURATION,
properties[PROP_DURATION]);
/**
* NleObject:stop
*
* The stop position relative to the parent in nanoseconds.
*
* This value is computed based on the values of start and duration.
*/
properties[PROP_STOP] = g_param_spec_uint64 ("stop", "Stop",
"The stop position relative to the parent (in nanoseconds)",
0, G_MAXUINT64, 0, G_PARAM_READABLE);
g_object_class_install_property (gobject_class, PROP_STOP,
properties[PROP_STOP]);
/**
* NleObject:inpoint
*
* The media start position in nanoseconds.
*
* Also called 'in-point' in video-editing, this corresponds to
* what position in the 'contained' object we should start outputting from.
*/
properties[PROP_INPOINT] =
g_param_spec_uint64 ("inpoint", "Media start",
"The media start position (in nanoseconds)", 0, G_MAXUINT64,
GST_CLOCK_TIME_NONE, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_INPOINT,
properties[PROP_INPOINT]);
/**
* NleObject:priority
*
* The priority of the object in the container.
*
* The highest priority is 0, meaning this object will be selected over
* any other between start and stop.
*
* The lowest priority is G_MAXUINT32.
*
* Objects whose priority is (-1) will be considered as 'default' objects
* in NleComposition and their start/stop values will be modified as to
* fit the whole duration of the composition.
*/
properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
"The priority of the object (0 = highest priority)", 0, G_MAXUINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_PRIORITY,
properties[PROP_PRIORITY]);
/**
* NleObject:active
*
* Indicates whether this object should be used by its container.
*
* Set to #TRUE to temporarily disable this object in a #NleComposition.
*/
properties[PROP_ACTIVE] = g_param_spec_boolean ("active", "Active",
"Use this object in the NleComposition", TRUE, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_ACTIVE,
properties[PROP_ACTIVE]);
/**
* NleObject:caps
*
* Caps used to filter/choose the output stream.
*
* If the controlled object produces several stream, you can set this
* property to choose a specific stream.
*
* If nothing is specified then a source pad will be chosen at random.
*/
properties[PROP_CAPS] = g_param_spec_boxed ("caps", "Caps",
"Caps used to filter/choose the output stream",
GST_TYPE_CAPS, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_CAPS,
properties[PROP_CAPS]);
/**
* NleObject:expandable
*
* Indicates whether this object should expand to the full duration of its
* container #NleComposition.
*/
properties[PROP_EXPANDABLE] =
g_param_spec_boolean ("expandable", "Expandable",
"Expand to the full duration of the container composition", FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_EXPANDABLE,
properties[PROP_EXPANDABLE]);
/**
* NleObject:media-duration-factor
*
* Indicates the relative rate caused by this object, in other words, the
* relation between the rate of media entering and leaving this object. I.e.
* if object pulls data at twice the speed it sends it (e.g. `pitch
* tempo=2.0`), this value is set to 2.0.
*
* Deprecated: 1.18: This property is ignored since the wrapped
* #GstElement-s themselves should internally perform any additional time
* translations.
*/
properties[PROP_MEDIA_DURATION_FACTOR] =
g_param_spec_double ("media-duration-factor", "Media duration factor",
"The relative rate caused by this object", 0.01, G_MAXDOUBLE,
1.0, G_PARAM_READWRITE | G_PARAM_DEPRECATED);
g_object_class_install_property (gobject_class, PROP_MEDIA_DURATION_FACTOR,
properties[PROP_MEDIA_DURATION_FACTOR]);
/**
* NleObject::commit
* @object: a #NleObject
* @recurse: Whether to commit recursiverly into (NleComposition) children of
* @object. This is used in case we have composition inside
* a nlesource composition, telling it to commit the included
* composition state.
*
* Action signal to commit all the pending changes of the composition and
* its children timing properties
*
* Returns: %TRUE if changes have been commited, %FALSE if nothing had to
* be commited
*/
_signals[COMMIT_SIGNAL] = g_signal_new ("commit", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (NleObjectClass, commit_signal_handler), NULL, NULL, NULL,
G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN);
gst_type_mark_as_plugin_api (NLE_TYPE_OBJECT, 0);
}
static void
nle_object_init (NleObject * object, NleObjectClass * klass)
{
object->start = object->pending_start = 0;
object->duration = object->pending_duration = 0;
object->stop = 0;
object->inpoint = object->pending_inpoint = GST_CLOCK_TIME_NONE;
object->priority = object->pending_priority = 0;
object->active = object->pending_active = TRUE;
object->caps = gst_caps_new_any ();
object->segment_rate = 1.0;
object->segment_start = -1;
object->segment_stop = -1;
object->srcpad = nle_object_ghost_pad_no_target (object,
"src", GST_PAD_SRC,
gst_element_class_get_pad_template ((GstElementClass *) klass, "src"));
gst_element_add_pad (GST_ELEMENT (object), object->srcpad);
}
static void
nle_object_dispose (GObject * object)
{
NleObject *nle = (NleObject *) object;
if (nle->caps) {
gst_caps_unref (nle->caps);
nle->caps = NULL;
}
if (nle->srcpad) {
nle_object_remove_ghost_pad (nle, nle->srcpad);
nle->srcpad = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
/**
* nle_object_to_media_time:
* @object: a #NleObject
* @objecttime: The #GstClockTime we want to convert
* @mediatime: A pointer on a #GstClockTime to fill
*
* Converts a #GstClockTime timestamp received from another nleobject pad
* in the same nlecomposition, or from the nlecomposition itself, to an
* internal source time.
*
* If the object is furthest downstream in the nlecomposition (highest
* priority in the current stack), this will convert the timestamp from
* the composition coordinate time to the internal source coordinate time
* of the object.
*
* If the object is upstream from another nleobject, then this can convert
* the timestamp received from the downstream sink pad to the internal
* source coordinates of the object, to be passed to its internal
* elements.
*
* If the object is downstream from another nleobject, then this can
* convert the timestamp received from the upstream source pad to the
* internal sink coordinates of the object, to be passed to its internal
* elements.
*
* In these latter two cases, the timestamp should have been converted
* by the peer pad using nle_media_to_object_time().
*
* Note, if an object introduces a time effect, it must have a 0 in-point
* and the same #nleobject:start and #nleobject:duration as all the other
* objects that are further upstream.
*
* Returns: TRUE if @objecttime was below the @object start time,
* FALSE otherwise.
*/
gboolean
nle_object_to_media_time (NleObject * object, GstClockTime otime,
GstClockTime * mtime)
{
gboolean ret = TRUE;
g_return_val_if_fail (mtime, FALSE);
GST_DEBUG_OBJECT (object, "ObjectTime : %" GST_TIME_FORMAT,
GST_TIME_ARGS (otime));
GST_DEBUG_OBJECT (object,
"Start/Stop:[%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT "] "
"Media start: %" GST_TIME_FORMAT, GST_TIME_ARGS (object->start),
GST_TIME_ARGS (object->stop), GST_TIME_ARGS (object->inpoint));
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (otime))) {
GST_DEBUG_OBJECT (object, "converting none object time to none");
*mtime = GST_CLOCK_TIME_NONE;
return TRUE;
}
/* We do not allow @otime to be below the start of the object.
* If it was below, then the object would have a negative external
* source/sink time.
*
* Note that ges only supports time effects that map the time 0 to
* 0. Such time effects would also not produce an external timestamp
* below start, nor can they receive such a timestamp. */
if (G_UNLIKELY ((otime < object->start))) {
GST_DEBUG_OBJECT (object, "ObjectTime is before start");
otime = object->start;
ret = FALSE;
}
/* NOTE: if an nlecomposition contains time effect operations, then
* @otime can reasonably exceed the stop time of the object. So we
* do not limit it here. */
/* first we convert the timestamp to the object's external source/sink
* coordinates:
* + For an object that is furthest downstream, we translate from the
* composition coordinates to the external source coordinates by
* subtracting the object start.
* + For an object that is upstream from d_object, we need to
* translate from its external sink coordinates to our external
* source coordinates. This is done by adding
* (d_object->start - object->start)
* However, the sink pad of d_object should have already added the
* d_object->start to the timestamp (see nle_media_to_object_time)
* so we also only need to subtract the object start.
* + For an object that is downstream from u_object, we need to
* translate from its external source coordinates to our external
* sink coordinates. This is similarly done by adding
* (u_object->start - object->start)
* However, the source pad of u_object should have already added the
* u_object->start to the timestamp (see nle_media_to_object_time)
* so we also only need to subtract the object start.
*/
*mtime = otime - object->start;
/* we then convert the timestamp from the object's external source/sink
* coordinates to its internal source/sink coordinates, to be used by
* internal elements that the object wraps. This is done by adding
* the object in-point. */
if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (object->inpoint)))
*mtime += object->inpoint;
GST_DEBUG_OBJECT (object, "Returning MediaTime : %" GST_TIME_FORMAT,
GST_TIME_ARGS (*mtime));
return ret;
}
/**
* nle_media_to_object_time:
* @object: The #NleObject
* @mediatime: The #GstClockTime we want to convert
* @objecttime: A pointer on a #GstClockTime to fill
*
* Converts a #GstClockTime timestamp from an internal time to an
* nleobject pad time.
*
* If the object is furthest downstream in an nlecomposition (highest
* priority in the current stack), this will convert the timestamp from
* the internal source coordinate time of the object to the composition
* coordinate time.
*
* If the object is upstream from another nleobject, then this can convert
* the timestamp from the internal source coordinates of the object to be
* sent to the downstream sink pad.
*
* If the object is downstream from another nleobject, then this can
* convert the timestamp from the internal sink coordinates of the object
* to be sent to the upstream source pad.
*
* Note, if an object introduces a time effect, it must have a 0 in-point
* and the same #nleobject:start and #nleobject:duration as all the other
* objects that are further upstream.
*
* Returns: TRUE if @objecttime was below the @object in-point time,
* FALSE otherwise.
*/
gboolean
nle_media_to_object_time (NleObject * object, GstClockTime mtime,
GstClockTime * otime)
{
g_return_val_if_fail (otime, FALSE);
GST_DEBUG_OBJECT (object, "MediaTime : %" GST_TIME_FORMAT,
GST_TIME_ARGS (mtime));
GST_DEBUG_OBJECT (object,
"Start/Stop:[%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT "] "
"inpoint %" GST_TIME_FORMAT, GST_TIME_ARGS (object->start),
GST_TIME_ARGS (object->stop), GST_TIME_ARGS (object->inpoint));
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (mtime))) {
GST_DEBUG_OBJECT (object, "converting none media time to none");
*otime = GST_CLOCK_TIME_NONE;
return TRUE;
}
/* the internal time should never go below the in-point! */
if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (object->inpoint)
&& (mtime < object->inpoint))) {
GST_DEBUG_OBJECT (object, "media time is before inpoint, forcing to start");
*otime = object->start;
return FALSE;
}
/* first we convert the timestamp to the object's external source/sink
* coordinates by removing the in-point */
if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (object->inpoint)))
*otime = mtime - object->inpoint;
else
*otime = mtime;
/* then we convert the timestamp by adding start.
* If the object is furthest downstream, this will translate it from
* the external source coordinates to the composition coordinates.
* Otherwise, this will perform part of the conversion from the object's
* source/sink coordinates to the downstream/upstream sink/source
* coordinates (the conversion is completed in
* nle_object_to_media_time). */
*otime += object->start;
GST_DEBUG_OBJECT (object, "Returning ObjectTime : %" GST_TIME_FORMAT,
GST_TIME_ARGS (*otime));
return TRUE;
}
static gboolean
nle_object_prepare_func (NleObject * object)
{
GST_DEBUG_OBJECT (object, "default prepare function, returning TRUE");
return TRUE;
}
static GstStateChangeReturn
nle_object_prepare (NleObject * object)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GST_DEBUG_OBJECT (object, "preparing");
if (!(NLE_OBJECT_GET_CLASS (object)->prepare (object)))
ret = GST_STATE_CHANGE_FAILURE;
GST_DEBUG_OBJECT (object, "finished preparing, returning %d", ret);
return ret;
}
static gboolean
nle_object_cleanup_func (NleObject * object)
{
GST_DEBUG_OBJECT (object, "default cleanup function, returning TRUE");
return TRUE;
}
GstStateChangeReturn
nle_object_cleanup (NleObject * object)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GST_DEBUG_OBJECT (object, "cleaning-up");
if (!(NLE_OBJECT_GET_CLASS (object)->cleanup (object)))
ret = GST_STATE_CHANGE_FAILURE;
GST_DEBUG_OBJECT (object, "finished preparing, returning %d", ret);
return ret;
}
void
nle_object_set_caps (NleObject * object, const GstCaps * caps)
{
if (object->caps)
gst_caps_unref (object->caps);
object->caps = gst_caps_copy (caps);
}
static inline void
_update_stop (NleObject * nleobject)
{
/* check if start/duration has changed */
if ((nleobject->pending_start + nleobject->pending_duration) !=
nleobject->stop) {
nleobject->stop = nleobject->pending_start + nleobject->pending_duration;
GST_LOG_OBJECT (nleobject,
"Updating stop value : %" GST_TIME_FORMAT " [start:%" GST_TIME_FORMAT
", duration:%" GST_TIME_FORMAT "]", GST_TIME_ARGS (nleobject->stop),
GST_TIME_ARGS (nleobject->pending_start),
GST_TIME_ARGS (nleobject->pending_duration));
g_object_notify_by_pspec (G_OBJECT (nleobject), properties[PROP_STOP]);
}
}
static void
update_values (NleObject * object)
{
CHECK_AND_SET (START, start, "start", G_GUINT64_FORMAT);
CHECK_AND_SET (INPOINT, inpoint, "inpoint", G_GUINT64_FORMAT);
CHECK_AND_SET (DURATION, duration, "duration", G_GINT64_FORMAT);
CHECK_AND_SET (PRIORITY, priority, "priority", G_GUINT32_FORMAT);
CHECK_AND_SET (ACTIVE, active, "active", G_GUINT32_FORMAT);
_update_stop (object);
}
static gboolean
nle_object_commit_func (NleObject * object, gboolean recurse)
{
GST_DEBUG_OBJECT (object, "Commiting object changed");
if (object->commit_needed == FALSE) {
GST_INFO_OBJECT (object, "No changes to commit");
return FALSE;
}
update_values (object);
GST_DEBUG_OBJECT (object, "Done commiting");
return TRUE;
}
static void
nle_object_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
NleObject *nleobject = (NleObject *) object;
g_return_if_fail (NLE_IS_OBJECT (object));
GST_OBJECT_LOCK (object);
switch (prop_id) {
case PROP_START:
SET_PENDING_VALUE (start, "start", uint64, G_GUINT64_FORMAT);
break;
case PROP_DURATION:
SET_PENDING_VALUE (duration, "duration", int64, G_GINT64_FORMAT);
break;
case PROP_INPOINT:
SET_PENDING_VALUE (inpoint, "inpoint", uint64, G_GUINT64_FORMAT);
break;
case PROP_PRIORITY:
SET_PENDING_VALUE (priority, "priority", uint, G_GUINT32_FORMAT);
break;
case PROP_ACTIVE:
SET_PENDING_VALUE (active, "active", boolean, G_GUINT32_FORMAT);
break;
case PROP_CAPS:
nle_object_set_caps (nleobject, gst_value_get_caps (value));
break;
case PROP_EXPANDABLE:
if (g_value_get_boolean (value))
GST_OBJECT_FLAG_SET (nleobject, NLE_OBJECT_EXPANDABLE);
else
GST_OBJECT_FLAG_UNSET (nleobject, NLE_OBJECT_EXPANDABLE);
break;
case PROP_MEDIA_DURATION_FACTOR:
{
gdouble val = g_value_get_double (value);
if (val != 1.0)
g_warning ("Ignoring media-duration-factor value of %g since the "
"property is deprecated", val);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_OBJECT_UNLOCK (object);
}
static void
nle_object_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
NleObject *nleobject = (NleObject *) object;
switch (prop_id) {
case PROP_START:
g_value_set_uint64 (value, nleobject->pending_start);
break;
case PROP_DURATION:
g_value_set_int64 (value, nleobject->pending_duration);
break;
case PROP_STOP:
g_value_set_uint64 (value, nleobject->stop);
break;
case PROP_INPOINT:
g_value_set_uint64 (value, nleobject->pending_inpoint);
break;
case PROP_PRIORITY:
g_value_set_uint (value, nleobject->pending_priority);
break;
case PROP_ACTIVE:
g_value_set_boolean (value, nleobject->pending_active);
break;
case PROP_CAPS:
gst_value_set_caps (value, nleobject->caps);
break;
case PROP_EXPANDABLE:
g_value_set_boolean (value, NLE_OBJECT_IS_EXPANDABLE (object));
break;
case PROP_MEDIA_DURATION_FACTOR:
g_value_set_double (value, 1.0);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nle_object_constructed (GObject * object)
{
NleObject *nleobject = (NleObject *) object;
_update_stop (nleobject);
}
static GstStateChangeReturn
nle_object_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
{
GstObject *parent = gst_object_get_parent (GST_OBJECT (element));
/* Going to READY and if we are not in a composition, we need to make
* sure that the object positioning state is properly commited */
if (parent) {
if (g_strcmp0 (GST_ELEMENT_NAME (GST_ELEMENT (parent)), "current-bin")
&& !NLE_OBJECT_IS_COMPOSITION (NLE_OBJECT (element))) {
GST_INFO ("Adding nleobject to something that is not a composition,"
" commiting ourself");
nle_object_commit (NLE_OBJECT (element), FALSE);
}
gst_object_unref (parent);
}
}
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
if (nle_object_prepare (NLE_OBJECT (element)) == GST_STATE_CHANGE_FAILURE) {
ret = GST_STATE_CHANGE_FAILURE;
goto beach;
}
break;
default:
break;
}
GST_DEBUG_OBJECT (element, "Calling parent change_state");
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
GST_DEBUG_OBJECT (element, "Return from parent change_state was %d", ret);
if (ret == GST_STATE_CHANGE_FAILURE)
goto beach;
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
/* cleanup nleobject */
if (nle_object_cleanup (NLE_OBJECT (element)) == GST_STATE_CHANGE_FAILURE)
ret = GST_STATE_CHANGE_FAILURE;
break;
default:
break;
}
beach:
return ret;
}
void
nle_object_set_commit_needed (NleObject * object)
{
if (G_UNLIKELY (object->commiting)) {
GST_WARNING_OBJECT (object,
"Trying to set 'commit-needed' while commiting");
return;
}
GST_DEBUG_OBJECT (object, "Setting 'commit_needed'");
object->commit_needed = TRUE;
}
gboolean
nle_object_commit (NleObject * object, gboolean recurse)
{
gboolean ret;
GST_DEBUG_OBJECT (object, "Commiting object state");
object->commiting = TRUE;
ret = NLE_OBJECT_GET_CLASS (object)->commit (object, recurse);
object->commiting = FALSE;
return ret;
}
static void
_send_seek_event (const GValue * item, gpointer seek_event)
{
GstElement *child = g_value_get_object (item);
gst_element_send_event (child, gst_event_ref (seek_event));
}
void
nle_object_seek_all_children (NleObject * object, GstEvent * seek_event)
{
GstIterator *it = gst_bin_iterate_recurse (GST_BIN (object));
while (gst_iterator_foreach (it, _send_seek_event,
seek_event) == GST_ITERATOR_RESYNC)
gst_iterator_resync (it);
gst_iterator_free (it);
gst_event_unref (seek_event);
}
void
nle_object_reset (NleObject * object)
{
GST_INFO_OBJECT (object, "Resetting child timing values to default");
object->start = 0;
object->duration = 0;
object->stop = 0;
object->inpoint = GST_CLOCK_TIME_NONE;
object->priority = 0;
object->active = TRUE;
object->in_composition = FALSE;
}
GType
nle_object_get_type (void)
{
static volatile gsize type = 0;
if (g_once_init_enter (&type)) {
GType _type;
static const GTypeInfo info = {
sizeof (NleObjectClass),
NULL,
NULL,
(GClassInitFunc) nle_object_class_init,
NULL,
NULL,
sizeof (NleObject),
0,
(GInstanceInitFunc) nle_object_init,
};
_type = g_type_register_static (GST_TYPE_BIN,
"NleObject", &info, G_TYPE_FLAG_ABSTRACT);
g_once_init_leave (&type, _type);
}
return type;
}