diff --git a/ChangeLog b/ChangeLog index 62e7a97636..c32c150ecc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +2005-07-01 Andy Wingo + + * tests/network-clock.scm: Commentary update. + + * gst/elements/gstidentity.c (PROP_DUPLICATE): Gone daddy gone. + Didn't really make sense, not implementable with basetransform, + etc. + (gst_identity_transform): Unref inbuf via make_writable. Feeble + attempt at implementing the sync property, needs an unlock method. + + * gst/base/gstbasetransform.c (gst_base_transform_transform_caps): + New func, by default returns the same caps (the identity + transformation). + (gst_base_transform_getcaps): Uses transform_caps to return + something sensible. + (gst_base_transform_setcaps): Complicated logic to get caps on + both pads, even if they are different, and to call set_caps once + for every time both pads get their caps set. + (gst_base_transform_handle_buffer): Give the ref to the transform + function. Allows in-place modification of the buffer. + + * gst/base/gstbasetransform.h (transform_caps): New class method. + Given caps on one side, what can I do on the other. + (set_caps): Take two caps, one for each side of the element. + + * gst/gstpad.h: + * gst/gstpad.c (gst_pad_fixate_caps): Change prototype to modify + caps in place. This is safe because we can check the mutability of + the caps, and a good idea because fixate functions are just called + as a matter of last resort. (Not actually implemented.) + (gst_pad_set_caps): If the caps we're setting is actually the same + as the existing pad caps, just update the pointer without calling + setcaps. Assert that caps is either NULL or fixed, as per the + docs. + + * gst/gstghostpad.c: Update for fixate changes. + +2005-07-02 Andy Wingo + + * gst/gstcaps.c: + * gst/gstcaps.h (gst_static_caps_get): Not const return, having + two refcounts makes it immutable, which is enough. Doc more. + 2005-07-02 Jan Schmidt * gst/gstpad.c: (gst_pad_emit_have_data_signal): diff --git a/docs/gst/tmpl/gstbasetransform.sgml b/docs/gst/tmpl/gstbasetransform.sgml index ce816ed5ee..a9eaaa2b1d 100644 --- a/docs/gst/tmpl/gstbasetransform.sgml +++ b/docs/gst/tmpl/gstbasetransform.sgml @@ -26,6 +26,7 @@ GstBaseTransform @parent_class: +@transform_caps: @set_caps: @start: @stop: diff --git a/docs/gst/tmpl/gstpad.sgml b/docs/gst/tmpl/gstpad.sgml index 0c0568d450..fc15412362 100644 --- a/docs/gst/tmpl/gstpad.sgml +++ b/docs/gst/tmpl/gstpad.sgml @@ -90,8 +90,8 @@ Last reviewed on December 13th, 2002 (0.5.0.1) @queryfunc: @intlinkfunc: @bufferallocfunc: -@emit_buffer_signals: -@emit_event_signals: +@do_buffer_signals: +@do_event_signals: diff --git a/gst/base/gstbasetransform.c b/gst/base/gstbasetransform.c index 0a29b36332..feff3a17b5 100644 --- a/gst/base/gstbasetransform.c +++ b/gst/base/gstbasetransform.c @@ -98,7 +98,7 @@ static GstFlowReturn gst_base_transform_chain (GstPad * pad, GstBuffer * buffer); static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer ** outbuf); -static GstCaps *gst_base_transform_proxy_getcaps (GstPad * pad); +static GstCaps *gst_base_transform_getcaps (GstPad * pad); static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps); /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */ @@ -150,7 +150,7 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) g_return_if_fail (pad_template != NULL); trans->sinkpad = gst_pad_new_from_template (pad_template, "sink"); gst_pad_set_getcaps_function (trans->sinkpad, - GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); + GST_DEBUG_FUNCPTR (gst_base_transform_getcaps)); gst_pad_set_setcaps_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); gst_pad_set_event_function (trans->sinkpad, @@ -166,7 +166,9 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) g_return_if_fail (pad_template != NULL); trans->srcpad = gst_pad_new_from_template (pad_template, "src"); gst_pad_set_getcaps_function (trans->srcpad, - GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); + GST_DEBUG_FUNCPTR (gst_base_transform_getcaps)); + gst_pad_set_setcaps_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); gst_pad_set_getrange_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_getrange)); gst_pad_set_activatepull_function (trans->srcpad, @@ -175,46 +177,135 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) } static GstCaps * -gst_base_transform_proxy_getcaps (GstPad * pad) +gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad, + GstCaps * caps) +{ + GstBaseTransformClass *klass; + + klass = GST_BASE_TRANSFORM_GET_CLASS (trans); + + if (klass->transform_caps) + return klass->transform_caps (trans, pad, caps); + else + return gst_caps_ref (caps); +} + +static GstCaps * +gst_base_transform_getcaps (GstPad * pad) { - GstPad *otherpad; GstBaseTransform *trans; + GstPad *otherpad; GstCaps *caps; - const GstCaps *templcaps; - trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); - otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad; + otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad; - /* we can do whatever the peer can do */ + /* we can do what the peer can */ caps = gst_pad_peer_get_caps (otherpad); - templcaps = gst_pad_get_pad_template_caps (pad); - if (caps == NULL) { - /* no peer, then the padtemplate is enough */ - return gst_caps_copy (templcaps); - } else { - GstCaps *ret = gst_caps_intersect (caps, templcaps); + if (caps) { + GstCaps *temp; + temp = gst_base_transform_transform_caps (trans, otherpad, caps); gst_caps_unref (caps); - return ret; + caps = gst_caps_intersect (temp, gst_pad_get_pad_template_caps (pad)); + gst_caps_unref (temp); + } else { + /* no peer, our padtemplate is enough then */ + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); } + + return caps; } static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps) { GstBaseTransform *trans; - GstBaseTransformClass *bclass; - gboolean result = TRUE; + GstBaseTransformClass *klass; + GstStructure *structure; + GstPad *otherpad, *otherpeer; + gboolean ret = TRUE; trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); - bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); + klass = GST_BASE_TRANSFORM_GET_CLASS (trans); - if (bclass->set_caps) - result = bclass->set_caps (trans, caps); + otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad; + otherpeer = gst_pad_get_peer (otherpad); - return result; + if (GST_PAD_IS_IN_SETCAPS (otherpad)) + goto done; + + if (otherpeer == NULL || gst_pad_accept_caps (otherpeer, caps)) { + + /* the peer accepts the caps as they are */ + gst_pad_set_caps (otherpad, caps); + + /* let the element know */ + if (klass->set_caps) + klass->set_caps (trans, caps, caps); + + ret = TRUE; + } else { + GstCaps *peercaps; + GstCaps *intersect; + GstCaps *transform = NULL; + GstCaps *othercaps; + + ret = FALSE; + + /* other pad has a peer, so we have to figure out how to do the conversion + */ + /* see how we can transform the input caps */ + transform = gst_base_transform_transform_caps (trans, pad, caps); + + if (!transform) + goto done; + + /* see what the peer can do */ + peercaps = gst_pad_get_caps (otherpeer); + + GST_DEBUG ("icaps %" GST_PTR_FORMAT, peercaps); + GST_DEBUG ("transform %" GST_PTR_FORMAT, transform); + + /* filter against our possibilities */ + intersect = gst_caps_intersect (peercaps, transform); + gst_caps_unref (peercaps); + gst_caps_unref (transform); + + GST_DEBUG ("intersect %" GST_PTR_FORMAT, intersect); + + /* take first possibility */ + othercaps = gst_caps_copy_nth (intersect, 0); + gst_caps_unref (intersect); + structure = gst_caps_get_structure (othercaps, 0); + + /* and fixate if necessary */ + gst_pad_fixate_caps (otherpad, othercaps); + + g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE); + + gst_pad_set_caps (otherpad, othercaps); + + /* let the element know */ + if (klass->set_caps) { + if (pad == trans->sinkpad) { + klass->set_caps (trans, caps, othercaps); + } else { + klass->set_caps (trans, othercaps, caps); + } + } + + ret = TRUE; + } + +done: + + if (otherpeer) + gst_object_unref (otherpeer); + + return ret; } static gboolean @@ -308,8 +399,6 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, if (bclass->transform) ret = bclass->transform (trans, inbuf, outbuf); - gst_buffer_unref (inbuf); - return ret; } diff --git a/gst/base/gstbasetransform.h b/gst/base/gstbasetransform.h index 66b4176f39..e0581e6f76 100644 --- a/gst/base/gstbasetransform.h +++ b/gst/base/gstbasetransform.h @@ -57,9 +57,13 @@ struct _GstBaseTransformClass { /*< public >*/ /* virtual methods for subclasses */ + /* given caps on one pad, what can I do on the other pad */ + GstCaps* (*transform_caps) (GstBaseTransform *trans, GstPad *pad, + GstCaps *caps); /* notify the subclass of new caps */ - gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *caps); + gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *incaps, + GstCaps *outcaps); /* start and stop processing, ideal for opening/closing the resource */ gboolean (*start) (GstBaseTransform *trans); @@ -68,7 +72,8 @@ struct _GstBaseTransformClass { gboolean (*event) (GstBaseTransform *trans, GstEvent *event); /* transform one incoming buffer to one outgoing buffer */ - GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf); + GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf, + GstBuffer **outbuf); }; GType gst_base_transform_get_type (void); diff --git a/gst/elements/gstidentity.c b/gst/elements/gstidentity.c index 37c42deaef..7c2ac82cfb 100644 --- a/gst/elements/gstidentity.c +++ b/gst/elements/gstidentity.c @@ -73,7 +73,6 @@ enum { PROP_0, PROP_SLEEP_TIME, - PROP_DUPLICATE, PROP_ERROR_AFTER, PROP_DROP_PROBABILITY, PROP_DATARATE, @@ -147,10 +146,6 @@ gst_identity_class_init (GstIdentityClass * klass) g_param_spec_uint ("sleep-time", "Sleep time", "Microseconds to sleep between processing", 0, G_MAXUINT, DEFAULT_SLEEP_TIME, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUPLICATE, - g_param_spec_uint ("duplicate", "Duplicate Buffers", - "Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE, - G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ERROR_AFTER, g_param_spec_int ("error_after", "Error After", "Error after N buffers", G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE)); @@ -196,7 +191,6 @@ static void gst_identity_init (GstIdentity * identity) { identity->sleep_time = DEFAULT_SLEEP_TIME; - identity->duplicate = DEFAULT_DUPLICATE; identity->error_after = DEFAULT_ERROR_AFTER; identity->drop_probability = DEFAULT_DROP_PROBABILITY; identity->datarate = DEFAULT_DATARATE; @@ -271,7 +265,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, { GstFlowReturn ret = GST_FLOW_OK; GstIdentity *identity = GST_IDENTITY (trans); - guint i; if (identity->check_perfect) gst_identity_check_perfect (identity, inbuf); @@ -281,6 +274,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, if (identity->error_after == 0) { GST_ELEMENT_ERROR (identity, CORE, FAILED, (_("Failed after iterations as requested.")), (NULL)); + gst_buffer_unref (inbuf); return GST_FLOW_ERROR; } } @@ -300,6 +294,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, GST_BUFFER_FLAGS (inbuf), inbuf); GST_UNLOCK (identity); g_object_notify (G_OBJECT (identity), "last-message"); + gst_buffer_unref (inbuf); return GST_FLOW_OK; } } @@ -308,56 +303,66 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf)); } - for (i = identity->duplicate; i; i--) { - GstClockTime time; - - if (!identity->silent) { - GST_LOCK (identity); - g_free (identity->last_message); - identity->last_message = - g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %" - GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" - G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", - GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), - GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf), - GST_BUFFER_FLAGS (inbuf), inbuf); - GST_UNLOCK (identity); - g_object_notify (G_OBJECT (identity), "last-message"); - } - - time = GST_BUFFER_TIMESTAMP (inbuf); - - if (identity->datarate > 0) { - time = identity->offset * GST_SECOND / identity->datarate; - - GST_BUFFER_TIMESTAMP (inbuf) = time; - GST_BUFFER_DURATION (inbuf) = - GST_BUFFER_SIZE (inbuf) * GST_SECOND / identity->datarate; - } - - g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0, - inbuf); - - if (i > 1) - gst_buffer_ref (inbuf); - - if (identity->sync) { - if (GST_ELEMENT (identity)->clock) { - /* gst_element_wait (GST_ELEMENT (identity), time); */ - } - } - - identity->offset += GST_BUFFER_SIZE (inbuf); - - if (identity->sleep_time) - g_usleep (identity->sleep_time); - - gst_buffer_ref (inbuf); - *outbuf = inbuf; + if (!identity->silent) { + GST_LOCK (identity); + g_free (identity->last_message); + identity->last_message = + g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %" + GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" + G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", + GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), + GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf), + GST_BUFFER_FLAGS (inbuf), inbuf); + GST_UNLOCK (identity); + g_object_notify (G_OBJECT (identity), "last-message"); } + *outbuf = gst_buffer_make_writable (inbuf); + /* inbuf is no longer usable */ + + if (identity->datarate > 0) { + GstClockTime time = identity->offset * GST_SECOND / identity->datarate; + + GST_BUFFER_TIMESTAMP (*outbuf) = time; + GST_BUFFER_DURATION (*outbuf) = + GST_BUFFER_SIZE (*outbuf) * GST_SECOND / identity->datarate; + } + + g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0, + *outbuf); + + if (identity->sync) { + GstClock *clock; + GstClockReturn cret; + + clock = GST_ELEMENT (identity)->clock; + + if (clock) { + /* save id if we need to unlock */ + /* FIXME: actually unlock this somewhere if the state changes */ + GST_LOCK (identity); + identity->clock_id = gst_clock_new_single_shot_id (clock, + GST_BUFFER_TIMESTAMP (*outbuf) + GST_ELEMENT (identity)->base_time); + GST_UNLOCK (identity); + cret = gst_clock_id_wait (identity->clock_id, NULL); + GST_LOCK (identity); + if (identity->clock_id) { + gst_clock_id_unref (identity->clock_id); + identity->clock_id = NULL; + } + GST_UNLOCK (identity); + if (cret == GST_CLOCK_UNSCHEDULED) + ret = GST_FLOW_UNEXPECTED; + } + } + + identity->offset += GST_BUFFER_SIZE (*outbuf); + + if (identity->sleep_time && ret == GST_FLOW_OK) + g_usleep (identity->sleep_time); + return ret; } @@ -376,9 +381,6 @@ gst_identity_set_property (GObject * object, guint prop_id, case PROP_SILENT: identity->silent = g_value_get_boolean (value); break; - case PROP_DUPLICATE: - identity->duplicate = g_value_get_uint (value); - break; case PROP_DUMP: identity->dump = g_value_get_boolean (value); break; @@ -415,9 +417,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value, case PROP_SLEEP_TIME: g_value_set_uint (value, identity->sleep_time); break; - case PROP_DUPLICATE: - g_value_set_uint (value, identity->duplicate); - break; case PROP_ERROR_AFTER: g_value_set_int (value, identity->error_after); break; diff --git a/gst/elements/gstidentity.h b/gst/elements/gstidentity.h index 4a51a070b4..79ffac351f 100644 --- a/gst/elements/gstidentity.h +++ b/gst/elements/gstidentity.h @@ -48,7 +48,7 @@ typedef struct _GstIdentityClass GstIdentityClass; struct _GstIdentity { GstBaseTransform element; - guint duplicate; + GstClockID clock_id; gint error_after; gfloat drop_probability; gint datarate; diff --git a/gst/gstcaps.c b/gst/gstcaps.c index caeaa5b3ad..3188930612 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -347,9 +347,11 @@ gst_caps_unref (GstCaps * caps) * * Converts a #GstStaticCaps to a #GstCaps. * - * Returns: the new #GstCaps + * Returns: A pointer to the #GstCaps. Although you do not have a reference on + * the caps, the core will never drop its references. (The core has two + * references on the caps so it will be immutable.) */ -const GstCaps * +GstCaps * gst_static_caps_get (GstStaticCaps * static_caps) { GstCaps *caps = (GstCaps *) static_caps; diff --git a/gst/gstcaps.h b/gst/gstcaps.h index de458af7fb..c15f558d42 100644 --- a/gst/gstcaps.h +++ b/gst/gstcaps.h @@ -98,7 +98,7 @@ GstCaps * gst_caps_copy (const GstCaps * caps); GstCaps * gst_caps_make_writable (GstCaps *caps); void gst_caps_unref (GstCaps* caps); -G_CONST_RETURN GstCaps * gst_static_caps_get (GstStaticCaps *static_caps); +GstCaps * gst_static_caps_get (GstStaticCaps *static_caps); /* manipulation */ void gst_caps_append (GstCaps *caps1, diff --git a/gst/gstghostpad.c b/gst/gstghostpad.c index 0aa5dd1685..7dbb12c9f5 100644 --- a/gst/gstghostpad.c +++ b/gst/gstghostpad.c @@ -279,14 +279,14 @@ gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps) return gst_pad_accept_caps (target, caps); } -static GstCaps * +static void gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps) { GstPad *target = GST_PROXY_PAD_TARGET (pad); - g_return_val_if_fail (target != NULL, NULL); + g_return_if_fail (target != NULL); - return gst_pad_fixate_caps (target, caps); + gst_pad_fixate_caps (target, caps); } static gboolean diff --git a/gst/gstpad.c b/gst/gstpad.c index 9f632bc786..cf420b9652 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -1748,15 +1748,13 @@ was_dispatching: * gst_pad_fixate_caps: * @pad: a #GstPad to fixate * - * Fixate a caps on the given pad. - * - * Returns: a fixated #GstCaps. + * Fixate a caps on the given pad. Modifies the caps in place, so you should be + * that the caps are actually writable (see gst_caps_make_writable()). */ -GstCaps * +void gst_pad_fixate_caps (GstPad * pad, GstCaps * caps) { /* FIXME, implement me, call the fixate function for the pad */ - return caps; } /** @@ -1857,12 +1855,20 @@ gboolean gst_pad_set_caps (GstPad * pad, GstCaps * caps) { GstPadSetCapsFunction setcaps; + GstCaps *existing; g_return_val_if_fail (GST_IS_PAD (pad), FALSE); + g_return_val_if_fail (caps == NULL || gst_caps_is_fixed (caps), FALSE); GST_LOCK (pad); setcaps = GST_PAD_SETCAPSFUNC (pad); + existing = GST_PAD_CAPS (pad); + if (caps == existing) + goto setting_same_caps; + else if (caps && existing && gst_caps_is_equal (caps, existing)) + goto setting_same_caps; + /* call setcaps function to configure the pad */ if (setcaps != NULL && caps) { if (!GST_PAD_IS_IN_SETCAPS (pad)) { @@ -1887,6 +1893,15 @@ gst_pad_set_caps (GstPad * pad, GstCaps * caps) return TRUE; +setting_same_caps: + { + GST_UNLOCK (pad); + gst_caps_replace (&GST_PAD_CAPS (pad), caps); + GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, + "caps %" GST_PTR_FORMAT " same as existing, updating ptr only", caps); + return TRUE; + } +/* errors */ could_not_set: { GST_LOCK (pad); diff --git a/gst/gstpad.h b/gst/gstpad.h index 29c2c1a6d4..9e827d2522 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -117,7 +117,7 @@ typedef void (*GstPadUnlinkFunction) (GstPad *pad); typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad); typedef gboolean (*GstPadSetCapsFunction) (GstPad *pad, GstCaps *caps); typedef gboolean (*GstPadAcceptCapsFunction) (GstPad *pad, GstCaps *caps); -typedef GstCaps* (*GstPadFixateCapsFunction) (GstPad *pad, GstCaps *caps); +typedef void (*GstPadFixateCapsFunction) (GstPad *pad, GstCaps *caps); typedef GstFlowReturn (*GstPadBufferAllocFunction) (GstPad *pad, guint64 offset, guint size, GstCaps *caps, GstBuffer **buf); /* misc */ @@ -414,7 +414,7 @@ G_CONST_RETURN GstCaps* gst_pad_get_pad_template_caps (GstPad *pad); /* capsnego function for connected/unconnected pads */ GstCaps * gst_pad_get_caps (GstPad * pad); -GstCaps* gst_pad_fixate_caps (GstPad * pad, GstCaps *caps); +void gst_pad_fixate_caps (GstPad * pad, GstCaps *caps); gboolean gst_pad_accept_caps (GstPad * pad, GstCaps *caps); gboolean gst_pad_set_caps (GstPad * pad, GstCaps *caps); diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index 0a29b36332..feff3a17b5 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -98,7 +98,7 @@ static GstFlowReturn gst_base_transform_chain (GstPad * pad, GstBuffer * buffer); static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer ** outbuf); -static GstCaps *gst_base_transform_proxy_getcaps (GstPad * pad); +static GstCaps *gst_base_transform_getcaps (GstPad * pad); static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps); /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */ @@ -150,7 +150,7 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) g_return_if_fail (pad_template != NULL); trans->sinkpad = gst_pad_new_from_template (pad_template, "sink"); gst_pad_set_getcaps_function (trans->sinkpad, - GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); + GST_DEBUG_FUNCPTR (gst_base_transform_getcaps)); gst_pad_set_setcaps_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); gst_pad_set_event_function (trans->sinkpad, @@ -166,7 +166,9 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) g_return_if_fail (pad_template != NULL); trans->srcpad = gst_pad_new_from_template (pad_template, "src"); gst_pad_set_getcaps_function (trans->srcpad, - GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); + GST_DEBUG_FUNCPTR (gst_base_transform_getcaps)); + gst_pad_set_setcaps_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); gst_pad_set_getrange_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_getrange)); gst_pad_set_activatepull_function (trans->srcpad, @@ -175,46 +177,135 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) } static GstCaps * -gst_base_transform_proxy_getcaps (GstPad * pad) +gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad, + GstCaps * caps) +{ + GstBaseTransformClass *klass; + + klass = GST_BASE_TRANSFORM_GET_CLASS (trans); + + if (klass->transform_caps) + return klass->transform_caps (trans, pad, caps); + else + return gst_caps_ref (caps); +} + +static GstCaps * +gst_base_transform_getcaps (GstPad * pad) { - GstPad *otherpad; GstBaseTransform *trans; + GstPad *otherpad; GstCaps *caps; - const GstCaps *templcaps; - trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); - otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad; + otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad; - /* we can do whatever the peer can do */ + /* we can do what the peer can */ caps = gst_pad_peer_get_caps (otherpad); - templcaps = gst_pad_get_pad_template_caps (pad); - if (caps == NULL) { - /* no peer, then the padtemplate is enough */ - return gst_caps_copy (templcaps); - } else { - GstCaps *ret = gst_caps_intersect (caps, templcaps); + if (caps) { + GstCaps *temp; + temp = gst_base_transform_transform_caps (trans, otherpad, caps); gst_caps_unref (caps); - return ret; + caps = gst_caps_intersect (temp, gst_pad_get_pad_template_caps (pad)); + gst_caps_unref (temp); + } else { + /* no peer, our padtemplate is enough then */ + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); } + + return caps; } static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps) { GstBaseTransform *trans; - GstBaseTransformClass *bclass; - gboolean result = TRUE; + GstBaseTransformClass *klass; + GstStructure *structure; + GstPad *otherpad, *otherpeer; + gboolean ret = TRUE; trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); - bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); + klass = GST_BASE_TRANSFORM_GET_CLASS (trans); - if (bclass->set_caps) - result = bclass->set_caps (trans, caps); + otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad; + otherpeer = gst_pad_get_peer (otherpad); - return result; + if (GST_PAD_IS_IN_SETCAPS (otherpad)) + goto done; + + if (otherpeer == NULL || gst_pad_accept_caps (otherpeer, caps)) { + + /* the peer accepts the caps as they are */ + gst_pad_set_caps (otherpad, caps); + + /* let the element know */ + if (klass->set_caps) + klass->set_caps (trans, caps, caps); + + ret = TRUE; + } else { + GstCaps *peercaps; + GstCaps *intersect; + GstCaps *transform = NULL; + GstCaps *othercaps; + + ret = FALSE; + + /* other pad has a peer, so we have to figure out how to do the conversion + */ + /* see how we can transform the input caps */ + transform = gst_base_transform_transform_caps (trans, pad, caps); + + if (!transform) + goto done; + + /* see what the peer can do */ + peercaps = gst_pad_get_caps (otherpeer); + + GST_DEBUG ("icaps %" GST_PTR_FORMAT, peercaps); + GST_DEBUG ("transform %" GST_PTR_FORMAT, transform); + + /* filter against our possibilities */ + intersect = gst_caps_intersect (peercaps, transform); + gst_caps_unref (peercaps); + gst_caps_unref (transform); + + GST_DEBUG ("intersect %" GST_PTR_FORMAT, intersect); + + /* take first possibility */ + othercaps = gst_caps_copy_nth (intersect, 0); + gst_caps_unref (intersect); + structure = gst_caps_get_structure (othercaps, 0); + + /* and fixate if necessary */ + gst_pad_fixate_caps (otherpad, othercaps); + + g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE); + + gst_pad_set_caps (otherpad, othercaps); + + /* let the element know */ + if (klass->set_caps) { + if (pad == trans->sinkpad) { + klass->set_caps (trans, caps, othercaps); + } else { + klass->set_caps (trans, othercaps, caps); + } + } + + ret = TRUE; + } + +done: + + if (otherpeer) + gst_object_unref (otherpeer); + + return ret; } static gboolean @@ -308,8 +399,6 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, if (bclass->transform) ret = bclass->transform (trans, inbuf, outbuf); - gst_buffer_unref (inbuf); - return ret; } diff --git a/libs/gst/base/gstbasetransform.h b/libs/gst/base/gstbasetransform.h index 66b4176f39..e0581e6f76 100644 --- a/libs/gst/base/gstbasetransform.h +++ b/libs/gst/base/gstbasetransform.h @@ -57,9 +57,13 @@ struct _GstBaseTransformClass { /*< public >*/ /* virtual methods for subclasses */ + /* given caps on one pad, what can I do on the other pad */ + GstCaps* (*transform_caps) (GstBaseTransform *trans, GstPad *pad, + GstCaps *caps); /* notify the subclass of new caps */ - gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *caps); + gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *incaps, + GstCaps *outcaps); /* start and stop processing, ideal for opening/closing the resource */ gboolean (*start) (GstBaseTransform *trans); @@ -68,7 +72,8 @@ struct _GstBaseTransformClass { gboolean (*event) (GstBaseTransform *trans, GstEvent *event); /* transform one incoming buffer to one outgoing buffer */ - GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf); + GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf, + GstBuffer **outbuf); }; GType gst_base_transform_get_type (void); diff --git a/plugins/elements/gstidentity.c b/plugins/elements/gstidentity.c index 37c42deaef..7c2ac82cfb 100644 --- a/plugins/elements/gstidentity.c +++ b/plugins/elements/gstidentity.c @@ -73,7 +73,6 @@ enum { PROP_0, PROP_SLEEP_TIME, - PROP_DUPLICATE, PROP_ERROR_AFTER, PROP_DROP_PROBABILITY, PROP_DATARATE, @@ -147,10 +146,6 @@ gst_identity_class_init (GstIdentityClass * klass) g_param_spec_uint ("sleep-time", "Sleep time", "Microseconds to sleep between processing", 0, G_MAXUINT, DEFAULT_SLEEP_TIME, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUPLICATE, - g_param_spec_uint ("duplicate", "Duplicate Buffers", - "Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE, - G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ERROR_AFTER, g_param_spec_int ("error_after", "Error After", "Error after N buffers", G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE)); @@ -196,7 +191,6 @@ static void gst_identity_init (GstIdentity * identity) { identity->sleep_time = DEFAULT_SLEEP_TIME; - identity->duplicate = DEFAULT_DUPLICATE; identity->error_after = DEFAULT_ERROR_AFTER; identity->drop_probability = DEFAULT_DROP_PROBABILITY; identity->datarate = DEFAULT_DATARATE; @@ -271,7 +265,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, { GstFlowReturn ret = GST_FLOW_OK; GstIdentity *identity = GST_IDENTITY (trans); - guint i; if (identity->check_perfect) gst_identity_check_perfect (identity, inbuf); @@ -281,6 +274,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, if (identity->error_after == 0) { GST_ELEMENT_ERROR (identity, CORE, FAILED, (_("Failed after iterations as requested.")), (NULL)); + gst_buffer_unref (inbuf); return GST_FLOW_ERROR; } } @@ -300,6 +294,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, GST_BUFFER_FLAGS (inbuf), inbuf); GST_UNLOCK (identity); g_object_notify (G_OBJECT (identity), "last-message"); + gst_buffer_unref (inbuf); return GST_FLOW_OK; } } @@ -308,56 +303,66 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf)); } - for (i = identity->duplicate; i; i--) { - GstClockTime time; - - if (!identity->silent) { - GST_LOCK (identity); - g_free (identity->last_message); - identity->last_message = - g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %" - GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" - G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", - GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), - GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf), - GST_BUFFER_FLAGS (inbuf), inbuf); - GST_UNLOCK (identity); - g_object_notify (G_OBJECT (identity), "last-message"); - } - - time = GST_BUFFER_TIMESTAMP (inbuf); - - if (identity->datarate > 0) { - time = identity->offset * GST_SECOND / identity->datarate; - - GST_BUFFER_TIMESTAMP (inbuf) = time; - GST_BUFFER_DURATION (inbuf) = - GST_BUFFER_SIZE (inbuf) * GST_SECOND / identity->datarate; - } - - g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0, - inbuf); - - if (i > 1) - gst_buffer_ref (inbuf); - - if (identity->sync) { - if (GST_ELEMENT (identity)->clock) { - /* gst_element_wait (GST_ELEMENT (identity), time); */ - } - } - - identity->offset += GST_BUFFER_SIZE (inbuf); - - if (identity->sleep_time) - g_usleep (identity->sleep_time); - - gst_buffer_ref (inbuf); - *outbuf = inbuf; + if (!identity->silent) { + GST_LOCK (identity); + g_free (identity->last_message); + identity->last_message = + g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %" + GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" + G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", + GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), + GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf), + GST_BUFFER_FLAGS (inbuf), inbuf); + GST_UNLOCK (identity); + g_object_notify (G_OBJECT (identity), "last-message"); } + *outbuf = gst_buffer_make_writable (inbuf); + /* inbuf is no longer usable */ + + if (identity->datarate > 0) { + GstClockTime time = identity->offset * GST_SECOND / identity->datarate; + + GST_BUFFER_TIMESTAMP (*outbuf) = time; + GST_BUFFER_DURATION (*outbuf) = + GST_BUFFER_SIZE (*outbuf) * GST_SECOND / identity->datarate; + } + + g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0, + *outbuf); + + if (identity->sync) { + GstClock *clock; + GstClockReturn cret; + + clock = GST_ELEMENT (identity)->clock; + + if (clock) { + /* save id if we need to unlock */ + /* FIXME: actually unlock this somewhere if the state changes */ + GST_LOCK (identity); + identity->clock_id = gst_clock_new_single_shot_id (clock, + GST_BUFFER_TIMESTAMP (*outbuf) + GST_ELEMENT (identity)->base_time); + GST_UNLOCK (identity); + cret = gst_clock_id_wait (identity->clock_id, NULL); + GST_LOCK (identity); + if (identity->clock_id) { + gst_clock_id_unref (identity->clock_id); + identity->clock_id = NULL; + } + GST_UNLOCK (identity); + if (cret == GST_CLOCK_UNSCHEDULED) + ret = GST_FLOW_UNEXPECTED; + } + } + + identity->offset += GST_BUFFER_SIZE (*outbuf); + + if (identity->sleep_time && ret == GST_FLOW_OK) + g_usleep (identity->sleep_time); + return ret; } @@ -376,9 +381,6 @@ gst_identity_set_property (GObject * object, guint prop_id, case PROP_SILENT: identity->silent = g_value_get_boolean (value); break; - case PROP_DUPLICATE: - identity->duplicate = g_value_get_uint (value); - break; case PROP_DUMP: identity->dump = g_value_get_boolean (value); break; @@ -415,9 +417,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value, case PROP_SLEEP_TIME: g_value_set_uint (value, identity->sleep_time); break; - case PROP_DUPLICATE: - g_value_set_uint (value, identity->duplicate); - break; case PROP_ERROR_AFTER: g_value_set_int (value, identity->error_after); break; diff --git a/plugins/elements/gstidentity.h b/plugins/elements/gstidentity.h index 4a51a070b4..79ffac351f 100644 --- a/plugins/elements/gstidentity.h +++ b/plugins/elements/gstidentity.h @@ -48,7 +48,7 @@ typedef struct _GstIdentityClass GstIdentityClass; struct _GstIdentity { GstBaseTransform element; - guint duplicate; + GstClockID clock_id; gint error_after; gfloat drop_probability; gint datarate; diff --git a/tests/misc/network-clock.scm b/tests/misc/network-clock.scm index c575645446..513977343c 100755 --- a/tests/misc/network-clock.scm +++ b/tests/misc/network-clock.scm @@ -54,9 +54,7 @@ exec guile --debug -l $0 -e main -- "$@" ;; second argument, rather deferring that calculation until stream-cdr ;; is called. In that way all times are actually infinite series. ;; -;; Knobs: sample rate, send delay, receive delay, send noise, receive -;; noise, queue length, rate of remote clock, rate of local clock. See -;; network-clock.scm --help. +;; Usage: See network-clock.scm --help. ;; ;;; Code: diff --git a/tests/network-clock.scm b/tests/network-clock.scm index c575645446..513977343c 100755 --- a/tests/network-clock.scm +++ b/tests/network-clock.scm @@ -54,9 +54,7 @@ exec guile --debug -l $0 -e main -- "$@" ;; second argument, rather deferring that calculation until stream-cdr ;; is called. In that way all times are actually infinite series. ;; -;; Knobs: sample rate, send delay, receive delay, send noise, receive -;; noise, queue length, rate of remote clock, rate of local clock. See -;; network-clock.scm --help. +;; Usage: See network-clock.scm --help. ;; ;;; Code: