From 1dcaa1fc4bb5453ceb29c86587abc42fb31670a0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Mar 2006 11:27:57 +0000 Subject: [PATCH] libs/gst/base/gstbasetransform.*: Make basetransform virtual method for src events too. Original commit message from CVS: * libs/gst/base/gstbasetransform.c: (gst_base_transform_class_init), (gst_base_transform_init), (gst_base_transform_sink_event), (gst_base_transform_sink_eventfunc), (gst_base_transform_src_event), (gst_base_transform_src_eventfunc), (gst_base_transform_handle_buffer), (gst_base_transform_chain), (gst_base_transform_set_property), (gst_base_transform_get_property), (gst_base_transform_change_state), (gst_base_transform_update_qos), (gst_base_transform_set_qos_enabled), (gst_base_transform_is_qos_enabled): * libs/gst/base/gstbasetransform.h: Make basetransform virtual method for src events too. Handle QOS in basetransform. API: gst_base_transform_update_qos API: gst_base_transform_set_qos_enabled API: gst_base_transform_is_qos_enabled --- ChangeLog | 20 +++ libs/gst/base/gstbasetransform.c | 216 +++++++++++++++++++++++++++++-- libs/gst/base/gstbasetransform.h | 19 ++- 3 files changed, 242 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6575b7ff0f..9258ed660b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2006-03-13 Wim Taymans + + * libs/gst/base/gstbasetransform.c: + (gst_base_transform_class_init), (gst_base_transform_init), + (gst_base_transform_sink_event), + (gst_base_transform_sink_eventfunc), + (gst_base_transform_src_event), (gst_base_transform_src_eventfunc), + (gst_base_transform_handle_buffer), (gst_base_transform_chain), + (gst_base_transform_set_property), + (gst_base_transform_get_property), + (gst_base_transform_change_state), (gst_base_transform_update_qos), + (gst_base_transform_set_qos_enabled), + (gst_base_transform_is_qos_enabled): + * libs/gst/base/gstbasetransform.h: + Make basetransform virtual method for src events too. + Handle QOS in basetransform. + API: gst_base_transform_update_qos + API: gst_base_transform_set_qos_enabled + API: gst_base_transform_is_qos_enabled + 2006-03-13 Wim Taymans * libs/gst/base/gstbasesink.c: (gst_base_sink_init), diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index 7d36195640..ad57e90f00 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -188,6 +188,7 @@ #include #include +#include "../../../gst/gst_private.h" #include "../../../gst/gst-i18n-lib.h" #include "gstbasetransform.h" #include @@ -202,9 +203,23 @@ enum LAST_SIGNAL }; +#define DEFAULT_PROP_QOS FALSE + enum { PROP_0, + PROP_QOS +}; + +#define GST_BASE_TRANSFORM_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate)) + +struct _GstBaseTransformPrivate +{ + /* QoS *//* with LOCK */ + gboolean qos_enabled; + gdouble proportion; + GstClockTime earliest_time; }; static GstElementClass *parent_class = NULL; @@ -255,8 +270,11 @@ static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans, static GstStateChangeReturn gst_base_transform_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_base_transform_event (GstPad * pad, GstEvent * event); -static gboolean gst_base_transform_eventfunc (GstBaseTransform * trans, +static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans, + GstEvent * event); +static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event); static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset, guint length, GstBuffer ** buffer); @@ -297,6 +315,8 @@ gst_base_transform_class_init (GstBaseTransformClass * klass) gobject_class = G_OBJECT_CLASS (klass); gstelement_class = GST_ELEMENT_CLASS (klass); + g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate)); + parent_class = g_type_class_peek_parent (klass); gobject_class->set_property = @@ -304,13 +324,18 @@ gst_base_transform_class_init (GstBaseTransformClass * klass) gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_transform_get_property); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QOS, + g_param_spec_boolean ("qos", "QoS", "handle QoS messages", + DEFAULT_PROP_QOS, G_PARAM_READWRITE)); + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_base_transform_change_state); klass->passthrough_on_same_caps = FALSE; - klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_eventfunc); + klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc); + klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc); } static void @@ -321,6 +346,8 @@ gst_base_transform_init (GstBaseTransform * trans, GST_DEBUG ("gst_base_transform_init"); + trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans); + pad_template = gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink"); g_return_if_fail (pad_template != NULL); @@ -330,7 +357,7 @@ gst_base_transform_init (GstBaseTransform * trans, gst_pad_set_setcaps_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); gst_pad_set_event_function (trans->sinkpad, - GST_DEBUG_FUNCPTR (gst_base_transform_event)); + GST_DEBUG_FUNCPTR (gst_base_transform_sink_event)); gst_pad_set_chain_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_chain)); gst_pad_set_activatepush_function (trans->sinkpad, @@ -347,6 +374,8 @@ gst_base_transform_init (GstBaseTransform * trans, GST_DEBUG_FUNCPTR (gst_base_transform_getcaps)); gst_pad_set_setcaps_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); + gst_pad_set_event_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_src_event)); gst_pad_set_getrange_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_getrange)); gst_pad_set_activatepull_function (trans->srcpad, @@ -356,6 +385,7 @@ gst_base_transform_init (GstBaseTransform * trans, trans->transform_lock = g_mutex_new (); trans->delay_configure = FALSE; trans->pending_configure = FALSE; + trans->priv->qos_enabled = DEFAULT_PROP_QOS; trans->cache_caps1 = NULL; trans->cache_caps2 = NULL; @@ -1085,7 +1115,7 @@ unknown_size: } static gboolean -gst_base_transform_event (GstPad * pad, GstEvent * event) +gst_base_transform_sink_event (GstPad * pad, GstEvent * event) { GstBaseTransform *trans; GstBaseTransformClass *bclass; @@ -1100,7 +1130,7 @@ gst_base_transform_event (GstPad * pad, GstEvent * event) /* FIXME, do this in the default event handler so the subclass can do * something different. */ if (ret) - ret = gst_pad_event_default (pad, event); + ret = gst_pad_push_event (trans->srcpad, event); gst_object_unref (trans); @@ -1108,12 +1138,17 @@ gst_base_transform_event (GstPad * pad, GstEvent * event) } static gboolean -gst_base_transform_eventfunc (GstBaseTransform * trans, GstEvent * event) +gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event) { switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: break; case GST_EVENT_FLUSH_STOP: + GST_OBJECT_LOCK (trans); + /* reset QoS parameters */ + trans->priv->proportion = 1.0; + trans->priv->earliest_time = -1; + GST_OBJECT_UNLOCK (trans); /* we need new segment info after the flush. */ gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED); break; @@ -1163,6 +1198,53 @@ gst_base_transform_eventfunc (GstBaseTransform * trans, GstEvent * event) return TRUE; } +static gboolean +gst_base_transform_src_event (GstPad * pad, GstEvent * event) +{ + GstBaseTransform *trans; + GstBaseTransformClass *bclass; + gboolean ret = TRUE; + + trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad)); + bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); + + if (bclass->src_event) + ret = bclass->src_event (trans, event); + + gst_object_unref (trans); + + return ret; +} + +static gboolean +gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event) +{ + gboolean ret; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + break; + case GST_EVENT_NAVIGATION: + break; + case GST_EVENT_QOS: + { + gdouble proportion; + GstClockTimeDiff diff; + GstClockTime timestamp; + + gst_event_parse_qos (event, &proportion, &diff, ×tamp); + gst_base_transform_update_qos (trans, proportion, diff, timestamp); + break; + } + default: + break; + } + + ret = gst_pad_push_event (trans->sinkpad, event); + + return ret; +} + static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer ** outbuf) @@ -1171,6 +1253,7 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, GstFlowReturn ret = GST_FLOW_OK; guint out_size; gboolean want_in_place; + GstClockTime outtime; bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); @@ -1189,6 +1272,26 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL)) goto not_negotiated; + if ((outtime = GST_BUFFER_TIMESTAMP (inbuf)) != -1) { + gboolean need_skip; + GstClockTime earliest_time; + + GST_OBJECT_LOCK (trans); + earliest_time = trans->priv->earliest_time; + /* check for QoS, don't perform conversion for buffers + * that are known to be late. */ + need_skip = trans->priv->qos_enabled && + earliest_time != -1 && outtime <= earliest_time; + GST_OBJECT_UNLOCK (trans); + + if (need_skip) { + GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: outtime %" + GST_TIME_FORMAT " <= %" GST_TIME_FORMAT, + GST_TIME_ARGS (outtime), GST_TIME_ARGS (earliest_time)); + goto skip; + } + } + if (trans->passthrough) { /* In passthrough mode, give transform_ip a look at the * buffer, without making it writable, or just push the @@ -1260,6 +1363,7 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, if (!success) goto configure_failed; } +skip: gst_buffer_unref (inbuf); return ret; @@ -1334,10 +1438,13 @@ gst_base_transform_chain (GstPad * pad, GstBuffer * buffer) ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf); g_mutex_unlock (trans->transform_lock); - if (ret == GST_FLOW_OK) { - ret = gst_pad_push (trans->srcpad, outbuf); - } else if (outbuf != NULL) - gst_buffer_unref (outbuf); + /* outbuf can be NULL, this means a dropped buffer */ + if (outbuf != NULL) { + if (ret == GST_FLOW_OK) + ret = gst_pad_push (trans->srcpad, outbuf); + else + gst_buffer_unref (outbuf); + } gst_object_unref (trans); @@ -1353,6 +1460,9 @@ gst_base_transform_set_property (GObject * object, guint prop_id, trans = GST_BASE_TRANSFORM (object); switch (prop_id) { + case PROP_QOS: + gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1368,6 +1478,9 @@ gst_base_transform_get_property (GObject * object, guint prop_id, trans = GST_BASE_TRANSFORM (object); switch (prop_id) { + case PROP_QOS: + g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1441,6 +1554,8 @@ gst_base_transform_change_state (GstElement * element, trans->negotiated = FALSE; trans->have_newsegment = FALSE; gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED); + trans->priv->proportion = 1.0; + trans->priv->earliest_time = -1; GST_OBJECT_UNLOCK (trans); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: @@ -1598,3 +1713,82 @@ gst_base_transform_is_in_place (GstBaseTransform * trans) return result; } + +/** + * gst_base_transform_update_qos: + * @trans: a #GstBaseTransform + * @proportion: the proportion + * @diff: the diff against the clock + * @timestamp: the timestamp of the buffer generating the QoS + * + * Set the QoS parameters in the transform. + * + * Since: 0.10.5 + * + * MT safe. + */ +void +gst_base_transform_update_qos (GstBaseTransform * trans, + gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp) +{ + + g_return_if_fail (trans != NULL); + + GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, + "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %" + GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp)); + + GST_OBJECT_LOCK (trans); + trans->priv->proportion = proportion; + trans->priv->earliest_time = timestamp + diff; + GST_OBJECT_UNLOCK (trans); +} + +/** + * gst_base_transform_set_qos_enabled: + * @trans: a #GstBaseTransform + * @enabled: new state + * + * Enable or disable QoS handling in the transform. + * + * Since: 0.10.5 + * + * MT safe. + */ +void +gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled) +{ + g_return_if_fail (trans != NULL); + + GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled); + + GST_OBJECT_LOCK (trans); + trans->priv->qos_enabled = enabled; + GST_OBJECT_UNLOCK (trans); +} + +/** + * gst_base_transform_is_qos_enabled: + * @trans: a #GstBaseTransform + * + * Queries if the transform will handle QoS. + * + * Returns: TRUE if QoS is enabled. + * + * Since: 0.10.5 + * + * MT safe. + */ +gboolean +gst_base_transform_is_qos_enabled (GstBaseTransform * trans) +{ + gboolean result; + + g_return_val_if_fail (trans != NULL, FALSE); + + GST_OBJECT_LOCK (trans); + result = trans->priv->qos_enabled; + GST_OBJECT_UNLOCK (trans); + + return result; +} diff --git a/libs/gst/base/gstbasetransform.h b/libs/gst/base/gstbasetransform.h index 3310c20ccf..bf3a6e5f9c 100644 --- a/libs/gst/base/gstbasetransform.h +++ b/libs/gst/base/gstbasetransform.h @@ -70,6 +70,8 @@ G_BEGIN_DECLS typedef struct _GstBaseTransform GstBaseTransform; typedef struct _GstBaseTransformClass GstBaseTransformClass; +typedef struct _GstBaseTransformPrivate GstBaseTransformPrivate; + /** * GstBaseTransform: @@ -107,7 +109,9 @@ struct _GstBaseTransform { GMutex *transform_lock; /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; + GstBaseTransformPrivate *priv; + + gpointer _gst_reserved[GST_PADDING_LARGE - 1]; }; /** @@ -157,6 +161,7 @@ struct _GstBaseTransformClass { gboolean (*start) (GstBaseTransform *trans); gboolean (*stop) (GstBaseTransform *trans); + /* sink event */ gboolean (*event) (GstBaseTransform *trans, GstEvent *event); /* transform one incoming buffer to one outgoing buffer. @@ -180,8 +185,11 @@ struct _GstBaseTransformClass { GstFlowReturn (*prepare_output_buffer) (GstBaseTransform * trans, GstBuffer *input, gint size, GstCaps *caps, GstBuffer **buf); + /* src event */ + gboolean (*src_event) (GstBaseTransform *trans, GstEvent *event); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; + gpointer _gst_reserved[GST_PADDING_LARGE - 1]; }; GType gst_base_transform_get_type (void); @@ -194,6 +202,13 @@ void gst_base_transform_set_in_place (GstBaseTransform *trans, gboolean in_place); gboolean gst_base_transform_is_in_place (GstBaseTransform *trans); +void gst_base_transform_update_qos (GstBaseTransform *trans, + gdouble proportion, + GstClockTimeDiff diff, + GstClockTime timestamp); +void gst_base_transform_set_qos_enabled (GstBaseTransform *trans, + gboolean enabled); +gboolean gst_base_transform_is_qos_enabled (GstBaseTransform *trans); G_END_DECLS