diff --git a/ChangeLog b/ChangeLog index cc85fa7dbe..276f951815 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,31 @@ 2007-01-12 Andy Wingo + * libs/gst/base/gstbasetransform.c (_GstBaseTransformPrivate): + (gst_base_transform_init, gst_base_transform_sink_activate_push) + (gst_base_transform_src_activate_pull): + Track the activation mode. + (gst_base_transform_setcaps): In pull mode, when activating the + src pad, after activating the sink pad, activate the sink pad's + peer, as discussed in part-negotiation.txt. + + * libs/gst/base/gstbasesrc.h: + * libs/gst/base/gstbasesrc.c (gst_base_src_fixate): Add fixate + vmethod, as in basesink. + + * libs/gst/base/gstbasesink.h: Reformat docs, add fixate vmethod. + + * libs/gst/base/gstbasesink.c (gst_base_sink_pad_setcaps): In pull + mode, first proxy the setcaps to the peer pad. + (gst_base_sink_pad_fixate): Add a fixate function that calls the + new fixate vmethod. + (gst_base_sink_default_activate_pull): Rename from + gst_base_sink_activate_pull. + (gst_base_sink_negotiate_pull): New function, performs negotiation + in pull mode before calling ::activate_pull(). + (gst_base_sink_pad_activate_pull): Actually call the activate_pull + vmethod instead of the default implementation. I have no idea how + this worked before. Negotiate before calling activate_pull. + * gst/gstpad.c (gst_pad_activate_pull): Refuse to activate unlinked sink pads in pull mode. In addition to being correct, fixes filesrc ! decodebin ! identity ! fakesink. diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index 3607b9ea9c..8f0d411480 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -274,7 +274,7 @@ static void gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer, GstClockTime * start, GstClockTime * end); static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad, gboolean flushing); -static gboolean gst_base_sink_activate_pull (GstBaseSink * basesink, +static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink, gboolean active); static GstStateChangeReturn gst_base_sink_change_state (GstElement * element, @@ -346,7 +346,8 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps); klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc); klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times); - klass->activate_pull = GST_DEBUG_FUNCPTR (gst_base_sink_activate_pull); + klass->activate_pull = + GST_DEBUG_FUNCPTR (gst_base_sink_default_activate_pull); } static GstCaps * @@ -380,12 +381,24 @@ gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps) { GstBaseSinkClass *bclass; GstBaseSink *bsink; - gboolean res = FALSE; + gboolean res = TRUE; bsink = GST_BASE_SINK (gst_pad_get_parent (pad)); bclass = GST_BASE_SINK_GET_CLASS (bsink); - if (bclass->set_caps) + if (bsink->pad_mode == GST_ACTIVATE_PULL) { + GstPad *peer = gst_pad_get_peer (pad); + + if (peer) + res = gst_pad_set_caps (peer, caps); + else + res = FALSE; + + if (!res) + GST_DEBUG_OBJECT (bsink, "peer setcaps() failed"); + } + + if (res && bclass->set_caps) res = bclass->set_caps (bsink, caps); gst_object_unref (bsink); @@ -393,6 +406,21 @@ gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps) return res; } +static void +gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps) +{ + GstBaseSinkClass *bclass; + GstBaseSink *bsink; + + bsink = GST_BASE_SINK (gst_pad_get_parent (pad)); + bclass = GST_BASE_SINK_GET_CLASS (bsink); + + if (bclass->fixate) + bclass->fixate (bsink, caps); + + gst_object_unref (bsink); +} + static GstFlowReturn gst_base_sink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf) @@ -432,6 +460,8 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class) GST_DEBUG_FUNCPTR (gst_base_sink_pad_getcaps)); gst_pad_set_setcaps_function (basesink->sinkpad, GST_DEBUG_FUNCPTR (gst_base_sink_pad_setcaps)); + gst_pad_set_fixatecaps_function (basesink->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_sink_pad_fixate)); gst_pad_set_bufferalloc_function (basesink->sinkpad, GST_DEBUG_FUNCPTR (gst_base_sink_pad_buffer_alloc)); gst_pad_set_activate_function (basesink->sinkpad, @@ -2121,7 +2151,7 @@ gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad, } static gboolean -gst_base_sink_activate_pull (GstBaseSink * basesink, gboolean active) +gst_base_sink_default_activate_pull (GstBaseSink * basesink, gboolean active) { gboolean result; @@ -2203,6 +2233,48 @@ gst_base_sink_pad_activate_push (GstPad * pad, gboolean active) return result; } +static gboolean +gst_base_sink_negotiate_pull (GstBaseSink * basesink) +{ + GstCaps *caps; + GstPad *pad; + + GST_OBJECT_LOCK (basesink); + pad = basesink->sinkpad; + gst_object_ref (pad); + GST_OBJECT_UNLOCK (basesink); + + caps = gst_pad_get_allowed_caps (pad); + if (gst_caps_is_empty (caps)) + goto no_caps_possible; + + caps = gst_caps_make_writable (caps); + gst_pad_fixate_caps (pad, caps); + + if (!gst_pad_set_caps (pad, caps)) + goto could_not_set_caps; + + gst_caps_unref (caps); + gst_object_unref (pad); + + return TRUE; + +no_caps_possible: + { + GST_INFO_OBJECT (basesink, "Pipeline could not agree on caps"); + GST_DEBUG_OBJECT (basesink, "get_allowed_caps() returned EMPTY"); + gst_object_unref (pad); + return FALSE; + } +could_not_set_caps: + { + GST_INFO_OBJECT (basesink, "Could not set caps: %" GST_PTR_FORMAT, caps); + gst_caps_unref (caps); + gst_object_unref (pad); + return FALSE; + } +} + /* this won't get called until we implement an activate function */ static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active) @@ -2236,9 +2308,15 @@ gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active) basesink->have_newsegment = TRUE; /* set the pad mode before starting the task so that it's in the - correct state for the new thread... */ + correct state for the new thread. also the sink set_caps function + checks this */ basesink->pad_mode = GST_ACTIVATE_PULL; - result = gst_base_sink_activate_pull (basesink, TRUE); + if ((result = gst_base_sink_negotiate_pull (basesink))) { + if (bclass->activate_pull) + result = bclass->activate_pull (basesink, TRUE); + else + result = FALSE; + } /* but if starting the thread fails, set it back */ if (!result) basesink->pad_mode = GST_ACTIVATE_NONE; diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h index a86ecf9e5e..0f10a7e759 100644 --- a/libs/gst/base/gstbasesink.h +++ b/libs/gst/base/gstbasesink.h @@ -108,25 +108,26 @@ struct _GstBaseSink { * @set_caps: Notify subclass of changed caps * @buffer_alloc: Subclasses can override to perform custom buffer allocations * @get_times: Called to get the start and end times for synchronising - * the passed buffer to the clock + * the passed buffer to the clock * @start: Start processing. Ideal for opening resources in the subclass * @stop: Stop processing. Subclasses should use this to close resources. * @unlock: Unlock any pending access to the resource. Subclasses should - * unblock any blocked function ASAP + * unblock any blocked function ASAP * @event: Override this to handle events arriving on the sink pad * @preroll: Called to present the preroll buffer if desired * @render: Called when a buffer should be presented or output, at the - * correct moment if the #GstBaseSink has been set to sync to - * the clock. + * correct moment if the #GstBaseSink has been set to sync to the clock. * @async_play: Subclasses should override this when they need to perform - * special processing when changing to the PLAYING state - * asynchronously. Called with the OBJECT_LOCK held. + * special processing when changing to the PLAYING state asynchronously. + * Called with the OBJECT_LOCK held. * @activate_pull: Subclasses should override this when they can provide an - * alternate method of spawning a thread to drive the pipeline - * in pull mode. Should start or stop the pulling thread, - * depending on the value of the "active" argument. Called after - * actually activating the sink pad in pull mode. The default - * implementation starts a task on the sink pad. + * alternate method of spawning a thread to drive the pipeline in pull mode. + * Should start or stop the pulling thread, depending on the value of the + * "active" argument. Called after actually activating the sink pad in pull + * mode. The default implementation starts a task on the sink pad. + * @fixate: Only useful in pull mode, this vmethod will be called in response to + * gst_pad_fixate_caps() being called on the sink pad. Implement if you have + * ideas about what should be the default values for the caps you support. * * Subclasses can override any of the available virtual methods or not, as * needed. At the minimum, the render method should be overridden to @@ -169,8 +170,11 @@ struct _GstBaseSinkClass { /* start or stop a pulling thread */ gboolean (*activate_pull)(GstBaseSink *sink, gboolean active); + /* fixate sink caps during pull-mode negotiation */ + void (*fixate) (GstBaseSink *sink, GstCaps *caps); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-2]; + gpointer _gst_reserved[GST_PADDING_LARGE-3]; }; GType gst_base_sink_get_type(void); diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c index e1d015e602..9bc3ae50ef 100644 --- a/libs/gst/base/gstbasesrc.c +++ b/libs/gst/base/gstbasesrc.c @@ -269,6 +269,7 @@ gst_base_src_get_type (void) } static GstCaps *gst_base_src_getcaps (GstPad * pad); static gboolean gst_base_src_setcaps (GstPad * pad, GstCaps * caps); +static void gst_base_src_fixate (GstPad * pad, GstCaps * caps); static gboolean gst_base_src_activate_push (GstPad * pad, gboolean active); static gboolean gst_base_src_activate_pull (GstPad * pad, gboolean active); @@ -391,6 +392,8 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class) GST_DEBUG_FUNCPTR (gst_base_src_pad_get_range)); gst_pad_set_getcaps_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_getcaps)); gst_pad_set_setcaps_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_setcaps)); + gst_pad_set_fixatecaps_function (pad, + GST_DEBUG_FUNCPTR (gst_base_src_fixate)); /* hold pointer to pad */ basesrc->srcpad = pad; @@ -578,6 +581,21 @@ gst_base_src_getcaps (GstPad * pad) return caps; } +static void +gst_base_src_fixate (GstPad * pad, GstCaps * caps) +{ + GstBaseSrcClass *bclass; + GstBaseSrc *bsrc; + + bsrc = GST_BASE_SRC (gst_pad_get_parent (pad)); + bclass = GST_BASE_SRC_GET_CLASS (bsrc); + + if (bclass->fixate) + bclass->fixate (bsrc, caps); + + gst_object_unref (bsrc); +} + static gboolean gst_base_src_default_query (GstBaseSrc * src, GstQuery * query) { diff --git a/libs/gst/base/gstbasesrc.h b/libs/gst/base/gstbasesrc.h index 13e2e0daf4..76a5dff055 100644 --- a/libs/gst/base/gstbasesrc.h +++ b/libs/gst/base/gstbasesrc.h @@ -142,6 +142,8 @@ struct _GstBaseSrc { * cycles. The default implementation will open and close the resource * to find out whether get_range is supported, and that is usually * undesirable. + * @fixate: Called during negotation if caps need fixating. Implement instead of + * setting a fixate function on the source pad. */ struct _GstBaseSrcClass { GstElementClass parent_class; @@ -199,8 +201,11 @@ struct _GstBaseSrcClass { * undesirable. */ gboolean (*check_get_range) (GstBaseSrc *src); + /* called if, in negotation, caps need fixating */ + void (*fixate) (GstBaseSrc *src, GstCaps *caps); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE - 3]; + gpointer _gst_reserved[GST_PADDING_LARGE - 4]; }; GType gst_base_src_get_type (void); diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index 22cedf404b..802ada895c 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -230,6 +230,8 @@ struct _GstBaseTransformPrivate gboolean qos_enabled; gdouble proportion; GstClockTime earliest_time; + + GstActivateMode pad_mode; }; static GstElementClass *parent_class = NULL; @@ -398,6 +400,7 @@ gst_base_transform_init (GstBaseTransform * trans, trans->priv->qos_enabled = DEFAULT_PROP_QOS; trans->cache_caps1 = NULL; trans->cache_caps2 = NULL; + trans->priv->pad_mode = GST_ACTIVATE_NONE; trans->passthrough = FALSE; if (bclass->transform == NULL) { @@ -811,6 +814,14 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps) /* we know this will work, we implement the setcaps */ gst_pad_set_caps (otherpad, othercaps); + if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) { + ret &= gst_pad_set_caps (otherpeer, othercaps); + if (!ret) { + GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed", + othercaps); + } + } + done: if (otherpeer) gst_object_unref (otherpeer); @@ -1604,7 +1615,12 @@ gst_base_transform_sink_activate_push (GstPad * pad, gboolean active) if (active) { if (bclass->start) result = bclass->start (trans); + if (result) + trans->priv->pad_mode = GST_ACTIVATE_PUSH; + } else { + trans->priv->pad_mode = GST_ACTIVATE_NONE; } + gst_object_unref (trans); return result; @@ -1625,7 +1641,12 @@ gst_base_transform_src_activate_pull (GstPad * pad, gboolean active) if (active) { if (result && bclass->start) result &= bclass->start (trans); + if (result) + trans->priv->pad_mode = GST_ACTIVATE_PULL; + } else { + trans->priv->pad_mode = GST_ACTIVATE_NONE; } + gst_object_unref (trans); return result;