mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
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.
This commit is contained in:
parent
d59b7f81b7
commit
b83e66be46
1 changed files with 84 additions and 48 deletions
132
gst/gstpad.c
132
gst/gstpad.c
|
@ -99,8 +99,10 @@ typedef struct _GstPadPushCache GstPadPushCache;
|
||||||
|
|
||||||
struct _GstPadPushCache
|
struct _GstPadPushCache
|
||||||
{
|
{
|
||||||
|
gboolean valid;
|
||||||
GstPad *peer; /* reffed peer pad */
|
GstPad *peer; /* reffed peer pad */
|
||||||
GstCaps *caps; /* caps for this link */
|
GstCaps *caps; /* caps for this link */
|
||||||
|
GstPadChainFunction chainfunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GST_PAD_GET_PRIVATE(obj) \
|
#define GST_PAD_GET_PRIVATE(obj) \
|
||||||
|
@ -2098,28 +2100,9 @@ gst_pad_link_full (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
|
||||||
GST_OBJECT_LOCK (sinkpad);
|
GST_OBJECT_LOCK (sinkpad);
|
||||||
|
|
||||||
if (result == GST_PAD_LINK_OK) {
|
if (result == GST_PAD_LINK_OK) {
|
||||||
GstPadPushCache *cache, *old;
|
|
||||||
gpointer *cache_ptr;
|
|
||||||
GST_OBJECT_UNLOCK (sinkpad);
|
GST_OBJECT_UNLOCK (sinkpad);
|
||||||
GST_OBJECT_UNLOCK (srcpad);
|
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
|
/* fire off a signal to each of the pads telling them
|
||||||
* that they've been linked */
|
* that they've been linked */
|
||||||
g_signal_emit (srcpad, gst_pad_signals[PAD_LINKED], 0, sinkpad);
|
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.
|
* checking for that little extra speed.
|
||||||
*/
|
*/
|
||||||
static inline GstFlowReturn
|
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;
|
GstCaps *caps;
|
||||||
gboolean caps_changed;
|
gboolean caps_changed;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
gboolean emit_signal;
|
gboolean emit_signal;
|
||||||
|
gboolean do_cache;
|
||||||
|
|
||||||
|
do_cache = cache ? cache->valid : FALSE;
|
||||||
|
|
||||||
GST_PAD_STREAM_LOCK (pad);
|
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
|
/* see if the signal should be emited, we emit before caps nego as
|
||||||
* we might drop the buffer and do capsnego for nothing. */
|
* we might drop the buffer and do capsnego for nothing. */
|
||||||
if (G_UNLIKELY (emit_signal)) {
|
if (G_UNLIKELY (emit_signal)) {
|
||||||
|
do_cache = FALSE;
|
||||||
if (G_LIKELY (is_buffer)) {
|
if (G_LIKELY (is_buffer)) {
|
||||||
if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (data)))
|
if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (data)))
|
||||||
goto dropping;
|
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,
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||||
"calling chainfunction &%s", GST_DEBUG_FUNCPTR_NAME (chainfunc));
|
"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));
|
ret = chainfunc (pad, GST_BUFFER_CAST (data));
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
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));
|
GST_DEBUG_FUNCPTR_NAME (chainfunc), gst_flow_get_name (ret));
|
||||||
} else {
|
} else {
|
||||||
GstPadChainListFunction chainlistfunc;
|
GstPadChainListFunction chainlistfunc;
|
||||||
|
cache->valid = FALSE;
|
||||||
|
|
||||||
if (G_UNLIKELY ((chainlistfunc = GST_PAD_CHAINLISTFUNC (pad)) == NULL))
|
if (G_UNLIKELY ((chainlistfunc = GST_PAD_CHAINLISTFUNC (pad)) == NULL))
|
||||||
goto chain_groups;
|
goto chain_groups;
|
||||||
|
@ -4268,11 +4265,11 @@ chain_groups:
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group");
|
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));
|
} while (ret == GST_FLOW_OK && gst_buffer_list_iterator_next_group (it));
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
|
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);
|
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_PAD_IS_SINK (pad), GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (GST_IS_BUFFER (buffer), 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_PAD_IS_SINK (pad), GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (GST_IS_BUFFER_LIST (list), 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
|
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;
|
GstPad *peer;
|
||||||
GstFlowReturn ret;
|
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
|
/* we emit signals on the pad arg, the peer will have a chance to
|
||||||
* emit in the _chain() function */
|
* emit in the _chain() function */
|
||||||
if (G_UNLIKELY (GST_PAD_DO_BUFFER_SIGNALS (pad) > 0)) {
|
if (G_UNLIKELY (GST_PAD_DO_BUFFER_SIGNALS (pad) > 0)) {
|
||||||
|
if (cache)
|
||||||
|
cache->valid = FALSE;
|
||||||
/* unlock before emitting */
|
/* unlock before emitting */
|
||||||
GST_OBJECT_UNLOCK (pad);
|
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 */
|
/* take ref to peer pad before releasing the lock */
|
||||||
gst_object_ref (peer);
|
gst_object_ref (peer);
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (pad);
|
GST_OBJECT_UNLOCK (pad);
|
||||||
|
|
||||||
/* we got a new datatype from the pad, it had better handle it */
|
/* 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;
|
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);
|
gst_object_unref (peer);
|
||||||
|
|
||||||
|
@ -4475,11 +4474,11 @@ push_groups:
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing group");
|
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));
|
} while (ret == GST_FLOW_OK && gst_buffer_list_iterator_next_group (it));
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing empty group");
|
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);
|
gst_buffer_list_iterator_free (it);
|
||||||
|
@ -4535,15 +4534,21 @@ pad_take_cache (GstPad * pad, gpointer * cache_ptr)
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pad_free_cache (GstPadPushCache * cache)
|
||||||
|
{
|
||||||
|
gst_object_unref (cache->peer);
|
||||||
|
gst_caps_unref (cache->caps);
|
||||||
|
g_slice_free (GstPadPushCache, cache);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pad_put_cache (GstPad * pad, GstPadPushCache * cache, gpointer * cache_ptr)
|
pad_put_cache (GstPad * pad, GstPadPushCache * cache, gpointer * cache_ptr)
|
||||||
{
|
{
|
||||||
/* put it back */
|
/* put it back */
|
||||||
if (!g_atomic_pointer_compare_and_exchange (cache_ptr, NULL, cache)) {
|
if (!g_atomic_pointer_compare_and_exchange (cache_ptr, NULL, cache)) {
|
||||||
/* something changed, clean up our cache */
|
/* something changed, clean up our cache */
|
||||||
gst_object_unref (cache->peer);
|
pad_free_cache (cache);
|
||||||
gst_caps_unref (cache->caps);
|
|
||||||
g_slice_free (GstPadPushCache, cache);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4579,6 +4584,8 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
|
||||||
GstPadPushCache *cache;
|
GstPadPushCache *cache;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
gpointer *cache_ptr;
|
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_IS_PAD (pad), GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (GST_PAD_IS_SRC (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);
|
cache = pad_take_cache (pad, cache_ptr);
|
||||||
|
|
||||||
if (G_LIKELY (cache)) {
|
if (G_UNLIKELY (cache == NULL))
|
||||||
GstPad *peer = cache->peer;
|
goto slow_path;
|
||||||
|
|
||||||
/* FIXME check cookies and caps */
|
/* check caps */
|
||||||
|
caps = GST_BUFFER_CAPS (buffer);
|
||||||
GST_PAD_STREAM_LOCK (peer);
|
if (G_UNLIKELY (caps && caps != cache->caps)) {
|
||||||
|
pad_free_cache (cache);
|
||||||
/* fast path */
|
goto slow_path;
|
||||||
ret = GST_PAD_CHAINFUNC (peer) (peer, buffer);
|
|
||||||
|
|
||||||
GST_PAD_STREAM_UNLOCK (peer);
|
|
||||||
|
|
||||||
pad_put_cache (pad, cache, cache_ptr);
|
|
||||||
} else {
|
|
||||||
/* slow path */
|
|
||||||
ret = gst_pad_push_data (pad, TRUE, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peer = cache->peer;
|
||||||
|
|
||||||
|
GST_PAD_STREAM_LOCK (peer);
|
||||||
|
|
||||||
|
ret = cache->chainfunc (peer, buffer);
|
||||||
|
|
||||||
|
GST_PAD_STREAM_UNLOCK (peer);
|
||||||
|
|
||||||
|
pad_put_cache (pad, cache, cache_ptr);
|
||||||
|
|
||||||
return ret;
|
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_PAD_IS_SRC (pad), GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (GST_IS_BUFFER_LIST (list), 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue