summaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@collabora.co.uk>2010-10-13 01:25:27 +0200
committerWim Taymans <wim.taymans@collabora.co.uk>2010-12-03 11:28:52 +0100
commitb83e66be4641a23ea1e17f2374e252f0400ddeb5 (patch)
treea069ff623abfc9a49d65d25533dbbbbf80ae9569 /gst
parentd59b7f81b70009fd2283efc8c304ecdca9c75003 (diff)
pad: improve pad push caching
Build the cache while we push data. When we don't have a cache, we run the slowpath and collect cacheable properties. When all conditions are met, keep the cached data around so that we can more efficiently push data around.
Diffstat (limited to 'gst')
-rw-r--r--gst/gstpad.c126
1 files changed, 81 insertions, 45 deletions
diff --git a/gst/gstpad.c b/gst/gstpad.c
index 0706abdfd3..f73b431a35 100644
--- a/gst/gstpad.c
+++ b/gst/gstpad.c
@@ -99,8 +99,10 @@ typedef struct _GstPadPushCache GstPadPushCache;
struct _GstPadPushCache
{
+ gboolean valid;
GstPad *peer; /* reffed peer pad */
GstCaps *caps; /* caps for this link */
+ GstPadChainFunction chainfunc;
};
#define GST_PAD_GET_PRIVATE(obj) \
@@ -2098,28 +2100,9 @@ gst_pad_link_full (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
GST_OBJECT_LOCK (sinkpad);
if (result == GST_PAD_LINK_OK) {
- GstPadPushCache *cache, *old;
- gpointer *cache_ptr;
GST_OBJECT_UNLOCK (sinkpad);
GST_OBJECT_UNLOCK (srcpad);
- cache_ptr = (gpointer *) & srcpad->abidata.ABI.priv->cache_ptr;
-
- /* make cache structure */
- cache = g_slice_new (GstPadPushCache);
- cache->peer = gst_object_ref (sinkpad);
- cache->caps = NULL;
-
- do {
- old = g_atomic_pointer_get (cache_ptr);
- } while (!g_atomic_pointer_compare_and_exchange (cache_ptr, old, cache));
-
- if (old) {
- gst_object_unref (old->peer);
- gst_caps_unref (old->caps);
- g_slice_free (GstPadPushCache, old);
- }
-
/* fire off a signal to each of the pads telling them
* that they've been linked */
g_signal_emit (srcpad, gst_pad_signals[PAD_LINKED], 0, sinkpad);
@@ -4167,12 +4150,16 @@ gst_pad_data_get_caps (gboolean is_buffer, void *data)
* checking for that little extra speed.
*/
static inline GstFlowReturn
-gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data)
+gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,
+ GstPadPushCache * cache)
{
GstCaps *caps;
gboolean caps_changed;
GstFlowReturn ret;
gboolean emit_signal;
+ gboolean do_cache;
+
+ do_cache = cache ? cache->valid : FALSE;
GST_PAD_STREAM_LOCK (pad);
@@ -4189,6 +4176,7 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data)
/* see if the signal should be emited, we emit before caps nego as
* we might drop the buffer and do capsnego for nothing. */
if (G_UNLIKELY (emit_signal)) {
+ do_cache = FALSE;
if (G_LIKELY (is_buffer)) {
if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (data)))
goto dropping;
@@ -4220,6 +4208,14 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data)
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"calling chainfunction &%s", GST_DEBUG_FUNCPTR_NAME (chainfunc));
+ if (do_cache) {
+ cache->peer = gst_object_ref (pad);
+ cache->caps = caps ? gst_caps_ref (caps) : NULL;
+ cache->chainfunc = chainfunc;
+ } else if (cache) {
+ cache->valid = FALSE;
+ }
+
ret = chainfunc (pad, GST_BUFFER_CAST (data));
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
@@ -4227,6 +4223,7 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data)
GST_DEBUG_FUNCPTR_NAME (chainfunc), gst_flow_get_name (ret));
} else {
GstPadChainListFunction chainlistfunc;
+ cache->valid = FALSE;
if (G_UNLIKELY ((chainlistfunc = GST_PAD_CHAINLISTFUNC (pad)) == NULL))
goto chain_groups;
@@ -4268,11 +4265,11 @@ chain_groups:
} else {
GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group");
}
- ret = gst_pad_chain_data_unchecked (pad, TRUE, group);
+ ret = gst_pad_chain_data_unchecked (pad, TRUE, group, NULL);
} while (ret == GST_FLOW_OK && gst_buffer_list_iterator_next_group (it));
} else {
GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
- ret = gst_pad_chain_data_unchecked (pad, TRUE, gst_buffer_new ());
+ ret = gst_pad_chain_data_unchecked (pad, TRUE, gst_buffer_new (), NULL);
}
gst_buffer_list_iterator_free (it);
@@ -4352,7 +4349,7 @@ gst_pad_chain (GstPad * pad, GstBuffer * buffer)
g_return_val_if_fail (GST_PAD_IS_SINK (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
- return gst_pad_chain_data_unchecked (pad, TRUE, buffer);
+ return gst_pad_chain_data_unchecked (pad, TRUE, buffer, NULL);
}
/**
@@ -4390,11 +4387,12 @@ gst_pad_chain_list (GstPad * pad, GstBufferList * list)
g_return_val_if_fail (GST_PAD_IS_SINK (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR);
- return gst_pad_chain_data_unchecked (pad, FALSE, list);
+ return gst_pad_chain_data_unchecked (pad, FALSE, list, NULL);
}
static GstFlowReturn
-gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data)
+gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data,
+ GstPadPushCache * cache)
{
GstPad *peer;
GstFlowReturn ret;
@@ -4412,6 +4410,8 @@ gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data)
/* we emit signals on the pad arg, the peer will have a chance to
* emit in the _chain() function */
if (G_UNLIKELY (GST_PAD_DO_BUFFER_SIGNALS (pad) > 0)) {
+ if (cache)
+ cache->valid = FALSE;
/* unlock before emitting */
GST_OBJECT_UNLOCK (pad);
@@ -4437,7 +4437,6 @@ gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data)
/* take ref to peer pad before releasing the lock */
gst_object_ref (peer);
-
GST_OBJECT_UNLOCK (pad);
/* we got a new datatype from the pad, it had better handle it */
@@ -4449,7 +4448,7 @@ gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data)
goto not_negotiated;
}
- ret = gst_pad_chain_data_unchecked (peer, is_buffer, data);
+ ret = gst_pad_chain_data_unchecked (peer, is_buffer, data, cache);
gst_object_unref (peer);
@@ -4475,11 +4474,11 @@ push_groups:
} else {
GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing group");
}
- ret = gst_pad_push_data (pad, TRUE, group);
+ ret = gst_pad_push_data (pad, TRUE, group, NULL);
} while (ret == GST_FLOW_OK && gst_buffer_list_iterator_next_group (it));
} else {
GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing empty group");
- ret = gst_pad_push_data (pad, TRUE, gst_buffer_new ());
+ ret = gst_pad_push_data (pad, TRUE, gst_buffer_new (), NULL);
}
gst_buffer_list_iterator_free (it);
@@ -4536,14 +4535,20 @@ pad_take_cache (GstPad * pad, gpointer * cache_ptr)
}
static void
+pad_free_cache (GstPadPushCache * cache)
+{
+ gst_object_unref (cache->peer);
+ gst_caps_unref (cache->caps);
+ g_slice_free (GstPadPushCache, cache);
+}
+
+static void
pad_put_cache (GstPad * pad, GstPadPushCache * cache, gpointer * cache_ptr)
{
/* put it back */
if (!g_atomic_pointer_compare_and_exchange (cache_ptr, NULL, cache)) {
/* something changed, clean up our cache */
- gst_object_unref (cache->peer);
- gst_caps_unref (cache->caps);
- g_slice_free (GstPadPushCache, cache);
+ pad_free_cache (cache);
}
}
@@ -4579,6 +4584,8 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
GstPadPushCache *cache;
GstFlowReturn ret;
gpointer *cache_ptr;
+ GstPad *peer;
+ GstCaps *caps;
g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
@@ -4588,24 +4595,53 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
cache = pad_take_cache (pad, cache_ptr);
- if (G_LIKELY (cache)) {
- GstPad *peer = cache->peer;
+ if (G_UNLIKELY (cache == NULL))
+ goto slow_path;
- /* FIXME check cookies and caps */
+ /* check caps */
+ caps = GST_BUFFER_CAPS (buffer);
+ if (G_UNLIKELY (caps && caps != cache->caps)) {
+ pad_free_cache (cache);
+ goto slow_path;
+ }
- GST_PAD_STREAM_LOCK (peer);
+ peer = cache->peer;
- /* fast path */
- ret = GST_PAD_CHAINFUNC (peer) (peer, buffer);
+ GST_PAD_STREAM_LOCK (peer);
- GST_PAD_STREAM_UNLOCK (peer);
+ ret = cache->chainfunc (peer, buffer);
+
+ GST_PAD_STREAM_UNLOCK (peer);
+
+ pad_put_cache (pad, cache, cache_ptr);
- pad_put_cache (pad, cache, cache_ptr);
- } else {
- /* slow path */
- ret = gst_pad_push_data (pad, TRUE, buffer);
- }
return ret;
+
+ /* slow path */
+slow_path:
+ {
+ GstPadPushCache scache = { TRUE, NULL, NULL };
+
+ GST_LOG_OBJECT (pad, "Taking slow path");
+
+ ret = gst_pad_push_data (pad, TRUE, buffer, &scache);
+
+ if (scache.valid) {
+ GstPadPushCache *ncache;
+ gpointer *cache_ptr;
+
+ GST_LOG_OBJECT (pad, "Caching push data");
+
+ /* make cache structure */
+ ncache = g_slice_new (GstPadPushCache);
+ *ncache = scache;
+
+ cache_ptr = (gpointer *) & pad->abidata.ABI.priv->cache_ptr;
+
+ pad_put_cache (pad, ncache, cache_ptr);
+ }
+ return ret;
+ }
}
/**
@@ -4650,7 +4686,7 @@ gst_pad_push_list (GstPad * pad, GstBufferList * list)
g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR);
- return gst_pad_push_data (pad, FALSE, list);
+ return gst_pad_push_data (pad, FALSE, list, NULL);
}
/**