diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2011-03-31 13:23:09 +0200 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2011-03-31 13:23:09 +0200 |
commit | 2e45698e56147b82bb24e5957dbd58950592221d (patch) | |
tree | a845fcd210321a61a45744e0c0c986a540539b08 | |
parent | 34da2a68f93c2597b9a72112f1d3329c41d71842 (diff) |
bufferlist: attempt at removing bufferlists0.11-bufferlist-remove
An attempt ar removing the bufferlist but instead use a simple array of
GstBuffer objects to gst_pad_chain_array().
It turns out that this is a bad idea, basesink needs lots of changes and
refcounting of the buffers in the list is probelematic.
-rw-r--r-- | gst/Makefile.am | 2 | ||||
-rw-r--r-- | gst/gst.c | 3 | ||||
-rw-r--r-- | gst/gst.h | 1 | ||||
-rw-r--r-- | gst/gstghostpad.c | 11 | ||||
-rw-r--r-- | gst/gstpad.c | 226 | ||||
-rw-r--r-- | gst/gstpad.h | 35 | ||||
-rw-r--r-- | libs/gst/base/gstbasesink.c | 330 | ||||
-rw-r--r-- | libs/gst/base/gstbasesink.h | 8 | ||||
-rw-r--r-- | plugins/elements/gsttee.c | 16 | ||||
-rw-r--r-- | tests/check/Makefile.am | 1 |
10 files changed, 301 insertions, 332 deletions
diff --git a/gst/Makefile.am b/gst/Makefile.am index 633756594..0689fb611 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -50,7 +50,6 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \ gstobject.c \ gstbin.c \ gstbuffer.c \ - gstbufferlist.c \ gstbufferpool.c \ gstbus.c \ gstcaps.c \ @@ -144,7 +143,6 @@ gst_headers = \ gstobject.h \ gstbin.h \ gstbuffer.h \ - gstbufferlist.h \ gstbufferpool.h \ gstbus.h \ gstcaps.h \ @@ -688,7 +688,6 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data, g_type_class_ref (gst_bin_flags_get_type ()); g_type_class_ref (gst_buffer_flag_get_type ()); g_type_class_ref (gst_buffer_copy_flags_get_type ()); - g_type_class_ref (gst_buffer_list_item_get_type ()); g_type_class_ref (gst_bus_flags_get_type ()); g_type_class_ref (gst_bus_sync_reply_get_type ()); g_type_class_ref (gst_caps_flags_get_type ()); @@ -760,7 +759,6 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data, _gst_event_initialize (); _gst_buffer_initialize (); _gst_message_initialize (); - _gst_buffer_list_initialize (); _gst_value_initialize (); g_type_class_ref (gst_param_spec_fraction_get_type ()); _gst_tag_initialize (); @@ -1052,7 +1050,6 @@ gst_deinit (void) g_type_class_unref (g_type_class_peek (gst_bin_flags_get_type ())); g_type_class_unref (g_type_class_peek (gst_buffer_flag_get_type ())); g_type_class_unref (g_type_class_peek (gst_buffer_copy_flags_get_type ())); - g_type_class_unref (g_type_class_peek (gst_buffer_list_item_get_type ())); g_type_class_unref (g_type_class_peek (gst_bus_flags_get_type ())); g_type_class_unref (g_type_class_peek (gst_bus_sync_reply_get_type ())); g_type_class_unref (g_type_class_peek (gst_caps_flags_get_type ())); @@ -33,7 +33,6 @@ #include <gst/gstbin.h> #include <gst/gstbuffer.h> -#include <gst/gstbufferlist.h> #include <gst/gstbufferpool.h> #include <gst/gstcaps.h> #include <gst/gstchildproxy.h> diff --git a/gst/gstghostpad.c b/gst/gstghostpad.c index 451123b16..11f8b5a30 100644 --- a/gst/gstghostpad.c +++ b/gst/gstghostpad.c @@ -159,12 +159,13 @@ gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer) } static GstFlowReturn -gst_proxy_pad_do_chain_list (GstPad * pad, GstBufferList * list) +gst_proxy_pad_do_chain_array (GstPad * pad, GstBuffer ** buffers, + guint n_buffers) { GstFlowReturn res; GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); - res = gst_pad_push_list (internal, list); + res = gst_pad_push_array (internal, buffers, n_buffers); return res; } @@ -389,7 +390,7 @@ gst_proxy_pad_class_init (GstProxyPadClass * klass) GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_unlink); GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_bufferalloc); GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_chain); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_chain_list); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_chain_array); GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_getrange); GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_checkgetrange); } @@ -835,7 +836,7 @@ gst_ghost_pad_construct (GstGhostPad * gpad) if (dir == GST_PAD_SINK) { gst_pad_set_bufferalloc_function (pad, gst_proxy_pad_do_bufferalloc); gst_pad_set_chain_function (pad, gst_proxy_pad_do_chain); - gst_pad_set_chain_list_function (pad, gst_proxy_pad_do_chain_list); + gst_pad_set_chain_array_function (pad, gst_proxy_pad_do_chain_array); } else { gst_pad_set_getrange_function (pad, gst_proxy_pad_do_getrange); gst_pad_set_checkgetrange_function (pad, gst_proxy_pad_do_checkgetrange); @@ -864,7 +865,7 @@ gst_ghost_pad_construct (GstGhostPad * gpad) if (dir == GST_PAD_SRC) { gst_pad_set_bufferalloc_function (internal, gst_proxy_pad_do_bufferalloc); gst_pad_set_chain_function (internal, gst_proxy_pad_do_chain); - gst_pad_set_chain_list_function (internal, gst_proxy_pad_do_chain_list); + gst_pad_set_chain_array_function (internal, gst_proxy_pad_do_chain_array); } else { gst_pad_set_getrange_function (internal, gst_proxy_pad_do_getrange); gst_pad_set_checkgetrange_function (internal, diff --git a/gst/gstpad.c b/gst/gstpad.c index e0643869a..315fc2d05 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -1269,9 +1269,9 @@ gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain) } /** - * gst_pad_set_chain_list_function: + * gst_pad_set_chain_array_function: * @pad: a sink #GstPad. - * @chainlist: the #GstPadChainListFunction to set. + * @chainarray: the #GstPadChainArrayFunction to set. * * Sets the given chain list function for the pad. The chainlist function is * called to process a #GstBufferList input buffer list. See @@ -1280,15 +1280,15 @@ gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain) * Since: 0.10.24 */ void -gst_pad_set_chain_list_function (GstPad * pad, - GstPadChainListFunction chainlist) +gst_pad_set_chain_array_function (GstPad * pad, + GstPadChainArrayFunction chainarray) { g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (GST_PAD_IS_SINK (pad)); - GST_PAD_CHAINLISTFUNC (pad) = chainlist; - GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "chainlistfunc set to %s", - GST_DEBUG_FUNCPTR_NAME (chainlist)); + GST_PAD_CHAINARRAYFUNC (pad) = chainarray; + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "chainarrayfunc set to %s", + GST_DEBUG_FUNCPTR_NAME (chainarray)); } /** @@ -3665,40 +3665,20 @@ gst_pad_emit_have_data_signal (GstPad * pad, GstMiniObject * obj) return res; } +/* unref the buffers after idx */ static void -gst_pad_data_unref (gboolean is_buffer, void *data) +gst_pad_data_unref (GstBuffer ** buffers, guint n_buffers, guint idx) { - if (G_LIKELY (is_buffer)) { - gst_buffer_unref (data); - } else { - gst_buffer_list_unref (data); - } -} - -static GstCaps * -gst_pad_data_get_caps (gboolean is_buffer, void *data) -{ - GstCaps *caps; - - if (G_LIKELY (is_buffer)) { - caps = GST_BUFFER_CAPS (data); - } else { - GstBuffer *buf; - - if ((buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (data), 0, 0))) - caps = GST_BUFFER_CAPS (buf); - else - caps = NULL; - } - return caps; + for (; idx < n_buffers; idx++) + gst_buffer_unref (buffers[idx]); } /* this is the chain function that does not perform the additional argument * checking for that little extra speed. */ static inline GstFlowReturn -gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data, - GstPadPushCache * cache) +gst_pad_chain_data_unchecked (GstPad * pad, GstBuffer ** buffers, + guint n_buffers, GstPadPushCache * cache) { GstCaps *caps; gboolean caps_changed; @@ -3711,7 +3691,7 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data, if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad))) goto flushing; - caps = gst_pad_data_get_caps (is_buffer, data); + caps = GST_BUFFER_CAPS (buffers[0]); caps_changed = caps && caps != GST_PAD_CAPS (pad); emit_signal = GST_PAD_DO_BUFFER_SIGNALS (pad) > 0; @@ -3721,13 +3701,14 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data, * we might drop the buffer and do capsnego for nothing. */ if (G_UNLIKELY (emit_signal)) { cache = NULL; - if (G_LIKELY (is_buffer)) { - if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT_CAST (data))) + if (n_buffers == 1) { + if (!gst_pad_emit_have_data_signal (pad, + GST_MINI_OBJECT_CAST (buffers[0]))) goto dropping; } else { - /* chain all groups in the buffer list one by one to avoid problems with + /* chain all buffers in the array one by one to avoid problems with * buffer probes that push buffers or events */ - goto chain_groups; + goto chain_array; } } @@ -3743,7 +3724,7 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data, * the data to the wrong function. This is not really a * problem since functions are assigned at creation time * and don't change that often... */ - if (G_LIKELY (is_buffer)) { + if (n_buffers == 1) { GstPadChainFunction chainfunc; if (G_UNLIKELY ((chainfunc = GST_PAD_CHAINFUNC (pad)) == NULL)) @@ -3757,71 +3738,56 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data, cache->caps = caps ? gst_caps_ref (caps) : NULL; } - ret = chainfunc (pad, GST_BUFFER_CAST (data)); + ret = chainfunc (pad, buffers[0]); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "called chainfunction &%s, returned %s", GST_DEBUG_FUNCPTR_NAME (chainfunc), gst_flow_get_name (ret)); } else { - GstPadChainListFunction chainlistfunc; + GstPadChainArrayFunction chainarrayfunc; - if (G_UNLIKELY ((chainlistfunc = GST_PAD_CHAINLISTFUNC (pad)) == NULL)) - goto chain_groups; + if (G_UNLIKELY ((chainarrayfunc = GST_PAD_CHAINARRAYFUNC (pad)) == NULL)) + goto chain_array; GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, - "calling chainlistfunction &%s", - GST_DEBUG_FUNCPTR_NAME (chainlistfunc)); + "calling chainarrayfunction &%s", + GST_DEBUG_FUNCPTR_NAME (chainarrayfunc)); - ret = chainlistfunc (pad, GST_BUFFER_LIST_CAST (data)); + ret = chainarrayfunc (pad, buffers, n_buffers); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, - "called chainlistfunction &%s, returned %s", - GST_DEBUG_FUNCPTR_NAME (chainlistfunc), gst_flow_get_name (ret)); + "called chainarrayfunction &%s, returned %s", + GST_DEBUG_FUNCPTR_NAME (chainarrayfunc), gst_flow_get_name (ret)); } GST_PAD_STREAM_UNLOCK (pad); return ret; -chain_groups: +chain_array: { - GstBufferList *list; - GstBufferListIterator *it; - GstBuffer *group; + guint idx; GST_PAD_STREAM_UNLOCK (pad); - GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer"); + GST_INFO_OBJECT (pad, "chaining each buffer in array"); - list = GST_BUFFER_LIST_CAST (data); - it = gst_buffer_list_iterate (list); - - if (gst_buffer_list_iterator_next_group (it)) { - do { - group = gst_buffer_list_iterator_merge_group (it); - if (group == NULL) { - group = gst_buffer_new (); - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group"); - } else { - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining 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 (), NULL); + ret = GST_FLOW_OK; + for (idx = 0; idx < n_buffers; idx++) { + ret = gst_pad_chain_data_unchecked (pad, &buffers[idx], 1, NULL); + if (ret != GST_FLOW_OK) + break; } - - gst_buffer_list_iterator_free (it); - gst_buffer_list_unref (list); - + /* flush buffers we could not push, idx was the last one pushed and + * unreffed */ + gst_pad_data_unref (buffers, n_buffers, idx + 1); return ret; } /* ERRORS */ flushing: { - gst_pad_data_unref (is_buffer, data); + gst_pad_data_unref (buffers, n_buffers, 0); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but pad was flushing"); GST_OBJECT_UNLOCK (pad); @@ -3830,14 +3796,14 @@ flushing: } dropping: { - gst_pad_data_unref (is_buffer, data); + gst_pad_data_unref (buffers, n_buffers, 0); GST_DEBUG_OBJECT (pad, "Dropping buffer due to FALSE probe return"); GST_PAD_STREAM_UNLOCK (pad); return GST_FLOW_OK; } not_negotiated: { - gst_pad_data_unref (is_buffer, data); + gst_pad_data_unref (buffers, n_buffers, 0); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing data but pad did not accept"); GST_PAD_STREAM_UNLOCK (pad); @@ -3845,7 +3811,7 @@ not_negotiated: } no_function: { - gst_pad_data_unref (is_buffer, data); + gst_pad_data_unref (buffers, n_buffers, 0); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but not chainhandler"); GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL), @@ -3890,16 +3856,17 @@ 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, NULL); + return gst_pad_chain_data_unchecked (pad, &buffer, 1, NULL); } /** - * gst_pad_chain_list: + * gst_pad_chain_array: * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not. - * @list: (transfer full): the #GstBufferList to send, return GST_FLOW_ERROR - * if not. + * @buffers: (transfer full): an array of #GstBuffer to send, + * return GST_FLOW_ERROR if not. + * @n_buffers: the length of the array * - * Chain a bufferlist to @pad. + * Chain a bufferarray to @pad. * * The function returns #GST_FLOW_WRONG_STATE if the pad was flushing. * @@ -3923,17 +3890,18 @@ gst_pad_chain (GstPad * pad, GstBuffer * buffer) * Since: 0.10.24 */ GstFlowReturn -gst_pad_chain_list (GstPad * pad, GstBufferList * list) +gst_pad_chain_array (GstPad * pad, GstBuffer ** buffers, guint n_buffers) { g_return_val_if_fail (GST_IS_PAD (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 (buffers != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (n_buffers > 0, GST_FLOW_ERROR); - return gst_pad_chain_data_unchecked (pad, FALSE, list, NULL); + return gst_pad_chain_data_unchecked (pad, buffers, n_buffers, NULL); } static GstFlowReturn -gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data, +gst_pad_push_data (GstPad * pad, GstBuffer ** buffers, guint n_buffers, GstPadPushCache * cache) { GstPad *peer; @@ -3956,14 +3924,15 @@ gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data, /* unlock before emitting */ GST_OBJECT_UNLOCK (pad); - if (G_LIKELY (is_buffer)) { + if (G_LIKELY (n_buffers == 1)) { /* if the signal handler returned FALSE, it means we should just drop the * buffer */ - if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT_CAST (data))) + if (!gst_pad_emit_have_data_signal (pad, + GST_MINI_OBJECT_CAST (buffers[0]))) goto dropped; } else { - /* push all buffers in the list */ - goto push_groups; + /* push all buffers in the array */ + goto push_array; } GST_OBJECT_LOCK (pad); } @@ -3973,7 +3942,7 @@ gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data, /* Before pushing the buffer to the peer pad, ensure that caps * are set on this pad */ - caps = gst_pad_data_get_caps (is_buffer, data); + caps = GST_BUFFER_CAPS (buffers[0]); caps_changed = caps && caps != GST_PAD_CAPS (pad); /* take ref to peer pad before releasing the lock */ @@ -3989,62 +3958,49 @@ gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data, goto not_negotiated; } - ret = gst_pad_chain_data_unchecked (peer, is_buffer, data, cache); + ret = gst_pad_chain_data_unchecked (peer, buffers, n_buffers, cache); gst_object_unref (peer); return ret; -push_groups: +push_array: { - GstBufferList *list; - GstBufferListIterator *it; - GstBuffer *group; + guint idx; - GST_INFO_OBJECT (pad, "pushing each group in list as a merged buffer"); + GST_PAD_STREAM_UNLOCK (pad); - list = GST_BUFFER_LIST_CAST (data); - it = gst_buffer_list_iterate (list); + GST_INFO_OBJECT (pad, "pushing each buffer in array"); - if (gst_buffer_list_iterator_next_group (it)) { - do { - group = gst_buffer_list_iterator_merge_group (it); - if (group == NULL) { - group = gst_buffer_new (); - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing empty group"); - } else { - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing 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 (), NULL); + ret = GST_FLOW_OK; + for (idx = 0; idx < n_buffers; idx++) { + ret = gst_pad_push_data (pad, &buffers[idx], 1, NULL); + if (ret != GST_FLOW_OK) + break; } - - gst_buffer_list_iterator_free (it); - gst_buffer_list_unref (list); - + /* flush buffers we could not push, idx was the last one pushed and + * unreffed */ + gst_pad_data_unref (buffers, n_buffers, idx + 1); return ret; } /* ERROR recovery here */ flushed: { - gst_pad_data_unref (is_buffer, data); + gst_pad_data_unref (buffers, n_buffers, 0); GST_DEBUG_OBJECT (pad, "pad block stopped by flush"); GST_OBJECT_UNLOCK (pad); return ret; } dropped: { - gst_pad_data_unref (is_buffer, data); + gst_pad_data_unref (buffers, n_buffers, 0); GST_DEBUG_OBJECT (pad, "Dropping buffer due to FALSE probe return"); return GST_FLOW_OK; } not_linked: { - gst_pad_data_unref (is_buffer, data); + gst_pad_data_unref (buffers, n_buffers, 0); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but it was not linked"); GST_OBJECT_UNLOCK (pad); @@ -4052,7 +4008,7 @@ not_linked: } not_negotiated: { - gst_pad_data_unref (is_buffer, data); + gst_pad_data_unref (buffers, n_buffers, 0); gst_object_unref (peer); GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad, "element pushed data then refused to accept the caps"); @@ -4213,7 +4169,7 @@ slow_path: GST_LOG_OBJECT (pad, "Taking slow path"); - ret = gst_pad_push_data (pad, TRUE, buffer, &scache); + ret = gst_pad_push_data (pad, &buffer, 1, &scache); if (scache.peer) { GstPadPushCache *ncache; @@ -4237,12 +4193,13 @@ invalid: } /** - * gst_pad_push_list: + * gst_pad_push_array: * @pad: a source #GstPad, returns #GST_FLOW_ERROR if not. - * @list: (transfer full): the #GstBufferList to push returns GST_FLOW_ERROR + * @buffers: (transfer full): an array of #GstBuffer to push returns GST_FLOW_ERROR * if not. + * @n_buffers: the amount of buffers in @buffers * - * Pushes a buffer list to the peer of @pad. + * Pushes a buffer array to the peer of @pad. * * This function will call an installed pad block before triggering any * installed pad probes. @@ -4269,13 +4226,10 @@ invalid: * Returns: a #GstFlowReturn from the peer pad. * * MT safe. - * - * Since: 0.10.24 */ GstFlowReturn -gst_pad_push_list (GstPad * pad, GstBufferList * list) +gst_pad_push_array (GstPad * pad, GstBuffer ** buffers, guint n_buffers) { - GstBuffer *buf; GstPadPushCache *cache; GstFlowReturn ret; gpointer *cache_ptr; @@ -4284,7 +4238,8 @@ gst_pad_push_list (GstPad * pad, GstBufferList * list) 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_IS_BUFFER_LIST (list), GST_FLOW_ERROR); + g_return_val_if_fail (buffers != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (n_buffers > 0, GST_FLOW_ERROR); cache_ptr = (gpointer *) & pad->priv->cache_ptr; @@ -4294,10 +4249,7 @@ gst_pad_push_list (GstPad * pad, GstBufferList * list) goto slow_path; /* check caps */ - if ((buf = gst_buffer_list_get (list, 0, 0))) - caps = GST_BUFFER_CAPS (buf); - else - caps = NULL; + caps = GST_BUFFER_CAPS (buffers[0]); if (G_UNLIKELY (caps && caps != cache->caps)) { pad_free_cache (cache); @@ -4310,7 +4262,7 @@ gst_pad_push_list (GstPad * pad, GstBufferList * list) if (G_UNLIKELY (g_atomic_pointer_get (cache_ptr) == PAD_CACHE_INVALID)) goto invalid; - ret = GST_PAD_CHAINLISTFUNC (peer) (peer, list); + ret = GST_PAD_CHAINARRAYFUNC (peer) (peer, buffers, n_buffers); GST_PAD_STREAM_UNLOCK (peer); @@ -4325,7 +4277,7 @@ slow_path: GST_LOG_OBJECT (pad, "Taking slow path"); - ret = gst_pad_push_data (pad, FALSE, list, &scache); + ret = gst_pad_push_data (pad, buffers, n_buffers, &scache); if (scache.peer) { GstPadPushCache *ncache; diff --git a/gst/gstpad.h b/gst/gstpad.h index da94c1646..3f4881f8f 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -266,23 +266,30 @@ typedef gboolean (*GstPadActivateModeFunction) (GstPad *pad, gboolean active); typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer); /** - * GstPadChainListFunction: + * GstPadChainArrayFunction: * @pad: the sink #GstPad that performed the chain. - * @list: the #GstBufferList that is chained, not %NULL. + * @buffers: an array of #GstBuffer that is chained, not %NULL. + * @n_buffer: the number of buffers in the array * - * A function that will be called on sinkpads when chaining buffer lists. - * The function typically processes the data contained in the buffer list and + * A function that will be called on sinkpads when chaining an array of buffers. + * The function typically processes the data contained in the buffer array and * either consumes the data or passes it on to the internally linked pad(s). * - * The implementer of this function receives a refcount to @list and - * should gst_buffer_list_unref() when the list is no longer needed. + * The implementer of this function does not own the pointer to the array buta + * it owns the buffers inside the array. This means that the array should not be + * freed, the caller of this function will do that. This allows the caller to + * allocate the array on the stack, when needed, or reuse its internal array. * - * When a chainlist function detects an error in the data stream, it must + * When a chainarray function detects an error in the data stream, it must * post an error on the bus and return an appropriate #GstFlowReturn value. * + * The default chainarray function on a pad will call GstPadChainFunction + * repeadedly for each buffer in the array. + * * Returns: #GST_FLOW_OK for success */ -typedef GstFlowReturn (*GstPadChainListFunction) (GstPad *pad, GstBufferList *list); +typedef GstFlowReturn (*GstPadChainArrayFunction) (GstPad *pad, GstBuffer **buffers, + guint n_buffers); /** * GstPadGetRangeFunction: @@ -646,7 +653,7 @@ struct _GstPad { /* data transport functions */ GstPadChainFunction chainfunc; - GstPadChainListFunction chainlistfunc; + GstPadChainArrayFunction chainarrayfunc; GstPadCheckGetRangeFunction checkgetrangefunc; GstPadGetRangeFunction getrangefunc; GstPadEventFunction eventfunc; @@ -701,7 +708,7 @@ struct _GstPadClass { #define GST_PAD_ACTIVATEPUSHFUNC(pad) (GST_PAD_CAST(pad)->activatepushfunc) #define GST_PAD_ACTIVATEPULLFUNC(pad) (GST_PAD_CAST(pad)->activatepullfunc) #define GST_PAD_CHAINFUNC(pad) (GST_PAD_CAST(pad)->chainfunc) -#define GST_PAD_CHAINLISTFUNC(pad) (GST_PAD_CAST(pad)->chainlistfunc) +#define GST_PAD_CHAINARRAYFUNC(pad) (GST_PAD_CAST(pad)->chainarrayfunc) #define GST_PAD_CHECKGETRANGEFUNC(pad) (GST_PAD_CAST(pad)->checkgetrangefunc) #define GST_PAD_GETRANGEFUNC(pad) (GST_PAD_CAST(pad)->getrangefunc) #define GST_PAD_EVENTFUNC(pad) (GST_PAD_CAST(pad)->eventfunc) @@ -858,7 +865,7 @@ void gst_pad_set_activate_function (GstPad *pad, GstPadActivateFunction activ void gst_pad_set_activatepull_function (GstPad *pad, GstPadActivateModeFunction activatepull); void gst_pad_set_activatepush_function (GstPad *pad, GstPadActivateModeFunction activatepush); void gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain); -void gst_pad_set_chain_list_function (GstPad *pad, GstPadChainListFunction chainlist); +void gst_pad_set_chain_array_function (GstPad *pad, GstPadChainArrayFunction chainarray); void gst_pad_set_getrange_function (GstPad *pad, GstPadGetRangeFunction get); void gst_pad_set_checkgetrange_function (GstPad *pad, GstPadCheckGetRangeFunction check); void gst_pad_set_event_function (GstPad *pad, GstPadEventFunction event); @@ -898,7 +905,8 @@ GstCaps * gst_pad_get_negotiated_caps (GstPad * pad); /* data passing functions to peer */ GstFlowReturn gst_pad_push (GstPad *pad, GstBuffer *buffer); -GstFlowReturn gst_pad_push_list (GstPad *pad, GstBufferList *list); +GstFlowReturn gst_pad_push_array (GstPad *pad, GstBuffer **buffers, + guint n_buffers); gboolean gst_pad_check_pull_range (GstPad *pad); GstFlowReturn gst_pad_pull_range (GstPad *pad, guint64 offset, guint size, GstBuffer **buffer); @@ -907,7 +915,8 @@ gboolean gst_pad_event_default (GstPad *pad, GstEvent *event); /* data passing functions on pad */ GstFlowReturn gst_pad_chain (GstPad *pad, GstBuffer *buffer); -GstFlowReturn gst_pad_chain_list (GstPad *pad, GstBufferList *list); +GstFlowReturn gst_pad_chain_array (GstPad *pad, GstBuffer **buffers, + guint n_buffers); GstFlowReturn gst_pad_get_range (GstPad *pad, guint64 offset, guint size, GstBuffer **buffer); gboolean gst_pad_send_event (GstPad *pad, GstEvent *event); diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index 356aa4134..504cb3b11 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -279,18 +279,80 @@ struct _GstBaseSinkPrivate #define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16) #define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4) -enum +typedef enum { _PR_IS_NOTHING = 1 << 0, _PR_IS_BUFFER = 1 << 1, - _PR_IS_BUFFERLIST = 1 << 2, + _PR_IS_BUFFERARRAY = 1 << 2, _PR_IS_EVENT = 1 << 3 } PrivateObjectType; -#define OBJ_IS_BUFFER(a) ((a) & _PR_IS_BUFFER) -#define OBJ_IS_BUFFERLIST(a) ((a) & _PR_IS_BUFFERLIST) -#define OBJ_IS_EVENT(a) ((a) & _PR_IS_EVENT) -#define OBJ_IS_BUFFERFULL(a) ((a) & (_PR_IS_BUFFER | _PR_IS_BUFFERLIST)) +typedef struct +{ + PrivateObjectType type; + gpointer obj; + gpointer *objs; + guint n_objs; +} SinkObject; + +static void +sink_object_init (SinkObject * obj, gpointer mobj) +{ + if (GST_IS_BUFFER (mobj)) + obj->type = _PR_IS_BUFFER; + if (GST_IS_EVENT (mobj)) + obj->type = _PR_IS_EVENT; + else + obj->type = _PR_IS_NOTHING; + obj->obj = mobj; + obj->objs = &obj->obj; + obj->n_objs = 1; +} + +static void +sink_object_init_array (SinkObject * obj, gpointer * objs, guint n_objs) +{ + obj->type = _PR_IS_BUFFERARRAY; + obj->objs = objs; + obj->n_objs = n_objs; +} + +static SinkObject * +sink_object_dup (SinkObject * obj) +{ + SinkObject *res; + + res = g_slice_new (SinkObject); + memcpy (res, obj, sizeof (SinkObject)); + memset (obj, 0, sizeof (SinkObject)); + + return res; +} + +#define OBJ_GET_ITEM(obj) (GST_EVENT_CAST ((obj)->objs[0])) +#define OBJ_GET_BUFFER(obj,i) (GST_BUFFER_CAST ((obj)->objs[i])) +#define OBJ_GET_EVENT(obj) (OBJ_GET_ITEM (obj)) + +static void +sink_object_clear (SinkObject * obj) +{ + guint i, len; + + len = obj->n_objs; + for (i = 0; i < len; i++) + gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj->objs[i])); +} + +static void +sink_object_free (SinkObject * obj) +{ + g_slice_free (SinkObject, obj); +} + +#define OBJ_IS_BUFFER(obj) ((obj->type) & _PR_IS_BUFFER) +#define OBJ_IS_BUFFERARRAY(obj) ((obj->type) & _PR_IS_BUFFERARRAY) +#define OBJ_IS_EVENT(obj) ((obj->type) & _PR_IS_EVENT) +#define OBJ_IS_BUFFERFULL(obj) ((obj->type) & (_PR_IS_BUFFER | _PR_IS_BUFFERARRAY)) /* BaseSink properties */ @@ -386,8 +448,8 @@ static GstStateChangeReturn gst_base_sink_change_state (GstElement * element, GstStateChange transition); static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer); -static GstFlowReturn gst_base_sink_chain_list (GstPad * pad, - GstBufferList * list); +static GstFlowReturn gst_base_sink_chain_array (GstPad * pad, + GstBuffer ** buffers, guint n_buffers); static void gst_base_sink_loop (GstPad * pad); static gboolean gst_base_sink_pad_activate (GstPad * pad); @@ -405,10 +467,10 @@ static GstFlowReturn gst_base_sink_pad_buffer_alloc (GstPad * pad, /* check if an object was too late */ static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink, - GstMiniObject * obj, GstClockTime rstart, GstClockTime rstop, + SinkObject * obj, GstClockTime rstart, GstClockTime rstop, GstClockReturn status, GstClockTimeDiff jitter); static GstFlowReturn gst_base_sink_preroll_object (GstBaseSink * basesink, - guint8 obj_type, GstMiniObject * obj); + SinkObject * obj); static void gst_base_sink_class_init (GstBaseSinkClass * klass) @@ -571,7 +633,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_pull); GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_event); GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain); - GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain_list); + GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain_array); } static GstCaps * @@ -691,7 +753,8 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class) gst_base_sink_pad_activate_pull); gst_pad_set_event_function (basesink->sinkpad, gst_base_sink_event); gst_pad_set_chain_function (basesink->sinkpad, gst_base_sink_chain); - gst_pad_set_chain_list_function (basesink->sinkpad, gst_base_sink_chain_list); + gst_pad_set_chain_array_function (basesink->sinkpad, + gst_base_sink_chain_array); gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad); basesink->pad_mode = GST_ACTIVATE_NONE; @@ -1474,12 +1537,13 @@ gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size, static void gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad) { - GstMiniObject *obj; + SinkObject *obj; GST_DEBUG_OBJECT (basesink, "flushing queue %p", basesink); while ((obj = g_queue_pop_head (basesink->preroll_queue))) { GST_DEBUG_OBJECT (basesink, "popped %p", obj); - gst_mini_object_unref (obj); + sink_object_clear (obj); + sink_object_free (obj); } /* we can't have EOS anymore now */ basesink->eos = FALSE; @@ -1901,11 +1965,11 @@ handle_stepping (GstBaseSink * sink, GstSegment * segment, * rrstart/rrstop contain the start/stop in running time. */ static gboolean -gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj, +gst_base_sink_get_sync_times (GstBaseSink * basesink, SinkObject * obj, GstClockTime * rsstart, GstClockTime * rsstop, GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync, gboolean * stepped, GstSegment * segment, GstStepInfo * step, - gboolean * step_end, guint8 obj_type) + gboolean * step_end) { GstBaseSinkClass *bclass; GstBuffer *buffer; @@ -1922,8 +1986,8 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj, /* start with nothing */ start = stop = GST_CLOCK_TIME_NONE; - if (G_UNLIKELY (OBJ_IS_EVENT (obj_type))) { - GstEvent *event = GST_EVENT_CAST (obj); + if (G_UNLIKELY (OBJ_IS_EVENT (obj))) { + GstEvent *event = GST_EVENT_CAST (obj->objs[0]); switch (GST_EVENT_TYPE (event)) { /* EOS event needs syncing */ @@ -2268,22 +2332,6 @@ step_unlocked: } } -static inline guint8 -get_object_type (GstMiniObject * obj) -{ - guint8 obj_type; - - if (G_LIKELY (GST_IS_BUFFER (obj))) - obj_type = _PR_IS_BUFFER; - else if (GST_IS_EVENT (obj)) - obj_type = _PR_IS_EVENT; - else if (GST_IS_BUFFER_LIST (obj)) - obj_type = _PR_IS_BUFFERLIST; - else - obj_type = _PR_IS_NOTHING; - - return obj_type; -} /** * gst_base_sink_do_preroll: @@ -2308,12 +2356,13 @@ gst_base_sink_do_preroll (GstBaseSink * sink, GstMiniObject * obj) GstFlowReturn ret; while (G_UNLIKELY (sink->need_preroll)) { - guint8 obj_type; + SinkObject sobj; + GST_DEBUG_OBJECT (sink, "prerolling object %p", obj); - obj_type = get_object_type (obj); + sink_object_init (&sobj, obj); - ret = gst_base_sink_preroll_object (sink, obj_type, obj); + ret = gst_base_sink_preroll_object (sink, &sobj); if (ret != GST_FLOW_OK) goto preroll_failed; @@ -2437,7 +2486,7 @@ flushing: */ static GstFlowReturn gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad, - GstMiniObject * obj, gboolean * late, gboolean * step_end, guint8 obj_type) + SinkObject * obj, gboolean * late, gboolean * step_end) { GstClockTimeDiff jitter = 0; gboolean syncable; @@ -2465,7 +2514,7 @@ do_step: /* get timing information for this object against the render segment */ syncable = gst_base_sink_get_sync_times (basesink, obj, &sstart, &sstop, &rstart, &rstop, &do_sync, &stepped, &basesink->segment, - current, step_end, obj_type); + current, step_end); if (G_UNLIKELY (stepped)) goto step_skipped; @@ -2507,7 +2556,7 @@ again: /* first do preroll, this makes sure we commit our state * to PAUSED and can continue to PLAYING. We cannot perform * any clock sync in PAUSED because there is no clock. */ - ret = gst_base_sink_do_preroll (basesink, obj); + ret = gst_base_sink_do_preroll (basesink, obj->objs[0]); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto preroll_failed; @@ -2796,7 +2845,7 @@ gst_base_sink_reset_qos (GstBaseSink * sink) * returns TRUE if the buffer was too late. */ static gboolean -gst_base_sink_is_too_late (GstBaseSink * basesink, GstMiniObject * obj, +gst_base_sink_is_too_late (GstBaseSink * basesink, SinkObject * obj, GstClockTime rstart, GstClockTime rstop, GstClockReturn status, GstClockTimeDiff jitter) { @@ -2819,7 +2868,7 @@ gst_base_sink_is_too_late (GstBaseSink * basesink, GstMiniObject * obj, goto no_drop; /* only check for buffers */ - if (G_UNLIKELY (!GST_IS_BUFFER (obj))) + if (G_UNLIKELY (!OBJ_IS_BUFFERFULL (obj))) goto not_buffer; /* can't do check if we don't have a timestamp */ @@ -2925,49 +2974,35 @@ gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start) */ static GstFlowReturn gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad, - guint8 obj_type, gpointer obj) + SinkObject * obj) { GstFlowReturn ret; GstBaseSinkClass *bclass; gboolean late, step_end; - gpointer sync_obj; GstBaseSinkPrivate *priv; priv = basesink->priv; - if (OBJ_IS_BUFFERLIST (obj_type)) { - /* - * If buffer list, use the first group buffer within the list - * for syncing - */ - sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); - g_assert (NULL != sync_obj); - } else { - sync_obj = obj; - } - again: late = FALSE; step_end = FALSE; /* synchronize this object, non syncable objects return OK * immediatly. */ - ret = - gst_base_sink_do_sync (basesink, pad, sync_obj, &late, &step_end, - obj_type); + ret = gst_base_sink_do_sync (basesink, pad, obj, &late, &step_end); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto sync_failed; /* and now render, event or buffer/buffer list. */ - if (G_LIKELY (OBJ_IS_BUFFERFULL (obj_type))) { + if (G_LIKELY (OBJ_IS_BUFFERFULL (obj))) { /* drop late buffers unconditionally, let's hope it's unlikely */ if (G_UNLIKELY (late)) goto dropped; bclass = GST_BASE_SINK_GET_CLASS (basesink); - if (G_LIKELY ((OBJ_IS_BUFFERLIST (obj_type) && bclass->render_list) || - (!OBJ_IS_BUFFERLIST (obj_type) && bclass->render))) { + if (G_LIKELY ((OBJ_IS_BUFFERARRAY (obj) && bclass->render_array) || + (!OBJ_IS_BUFFERARRAY (obj) && bclass->render))) { gint do_qos; /* read once, to get same value before and after */ @@ -2979,22 +3014,24 @@ again: if (do_qos) gst_base_sink_do_render_stats (basesink, TRUE); - if (!OBJ_IS_BUFFERLIST (obj_type)) { + if (!OBJ_IS_BUFFERARRAY (obj)) { GstBuffer *buf; /* For buffer lists do not set last buffer. Creating buffer * with meaningful data can be done only with memcpy which will * significantly affect performance */ - buf = GST_BUFFER_CAST (obj); + buf = OBJ_GET_BUFFER (obj, 0); gst_base_sink_set_last_buffer (basesink, buf); ret = bclass->render (basesink, buf); } else { - GstBufferList *buflist; + GstBuffer **buffers; + guint n_buffers; - buflist = GST_BUFFER_LIST_CAST (obj); + buffers = (GstBuffer **) obj->objs; + n_buffers = obj->n_objs; - ret = bclass->render_list (basesink, buflist); + ret = bclass->render_array (basesink, buffers, n_buffers); } if (do_qos) @@ -3008,8 +3045,8 @@ again: priv->rendered++; } - } else if (G_LIKELY (OBJ_IS_EVENT (obj_type))) { - GstEvent *event = GST_EVENT_CAST (obj); + } else if (G_LIKELY (OBJ_IS_EVENT (obj))) { + GstEvent *event = OBJ_GET_EVENT (obj); gboolean event_res = TRUE; GstEventType type; @@ -3088,7 +3125,7 @@ done: gst_base_sink_perform_qos (basesink, late); GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj); - gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); + sink_object_clear (obj); return ret; /* ERRORS */ @@ -3105,9 +3142,12 @@ dropped: if (g_atomic_int_get (&priv->qos_enabled)) { GstMessage *qos_msg; GstClockTime timestamp, duration; + GstBuffer *buf; - timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (sync_obj)); - duration = GST_BUFFER_DURATION (GST_BUFFER_CAST (sync_obj)); + buf = OBJ_GET_BUFFER (obj, 0); + + timestamp = GST_BUFFER_TIMESTAMP (buf); + duration = GST_BUFFER_DURATION (buf); GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink, "qos: dropped buffer rt %" GST_TIME_FORMAT ", st %" GST_TIME_FORMAT @@ -3133,7 +3173,7 @@ dropped: flushing: { GST_DEBUG_OBJECT (basesink, "we are flushing, ignore object"); - gst_mini_object_unref (obj); + sink_object_clear (obj); return GST_FLOW_WRONG_STATE; } } @@ -3147,39 +3187,26 @@ flushing: * function does not take ownership of obj. */ static GstFlowReturn -gst_base_sink_preroll_object (GstBaseSink * basesink, guint8 obj_type, - GstMiniObject * obj) +gst_base_sink_preroll_object (GstBaseSink * basesink, SinkObject * obj) { GstFlowReturn ret; GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj); /* if it's a buffer, we need to call the preroll method */ - if (G_LIKELY (OBJ_IS_BUFFERFULL (obj_type) && basesink->priv->call_preroll)) { + if (G_LIKELY (OBJ_IS_BUFFERFULL (obj) && basesink->priv->call_preroll)) { GstBaseSinkClass *bclass; GstBuffer *buf; GstClockTime timestamp; - if (OBJ_IS_BUFFERLIST (obj_type)) { - buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); - g_assert (NULL != buf); - } else { - buf = GST_BUFFER_CAST (obj); - } + buf = OBJ_GET_BUFFER (obj, 0); timestamp = GST_BUFFER_TIMESTAMP (buf); GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); - /* - * For buffer lists do not set last buffer. Creating buffer - * with meaningful data can be done only with memcpy which will - * significantly affect performance - */ - if (!OBJ_IS_BUFFERLIST (obj_type)) { - gst_base_sink_set_last_buffer (basesink, buf); - } + gst_base_sink_set_last_buffer (basesink, buf); bclass = GST_BASE_SINK_GET_CLASS (basesink); if (bclass->preroll) @@ -3221,7 +3248,7 @@ stopping: */ static GstFlowReturn gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad, - guint8 obj_type, gpointer obj, gboolean prerollable) + SinkObject * obj, gboolean prerollable) { GstFlowReturn ret = GST_FLOW_OK; gint length; @@ -3237,7 +3264,7 @@ gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad, /* first prerollable item needs to finish the preroll */ if (length == 1) { - ret = gst_base_sink_preroll_object (basesink, obj_type, obj); + ret = gst_base_sink_preroll_object (basesink, obj); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto preroll_failed; } @@ -3254,22 +3281,21 @@ gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad, * if any. */ q = basesink->preroll_queue; while (G_UNLIKELY (!g_queue_is_empty (q))) { - GstMiniObject *o; - guint8 ot; + SinkObject *o; o = g_queue_pop_head (q); GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o); - ot = get_object_type (o); - /* do something with the return value */ - ret = gst_base_sink_render_object (basesink, pad, ot, o); + ret = gst_base_sink_render_object (basesink, pad, o); + sink_object_free (o); + if (ret != GST_FLOW_OK) goto dequeue_failed; } /* now render the object */ - ret = gst_base_sink_render_object (basesink, pad, obj_type, obj); + ret = gst_base_sink_render_object (basesink, pad, obj); basesink->preroll_queued = 0; return ret; @@ -3279,7 +3305,7 @@ preroll_failed: { GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s", gst_flow_get_name (ret)); - gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); + sink_object_clear (obj); return ret; } more_preroll: @@ -3287,14 +3313,14 @@ more_preroll: /* add object to the queue and return */ GST_DEBUG_OBJECT (basesink, "need more preroll data %d <= %d", length, basesink->preroll_queue_max_len); - g_queue_push_tail (basesink->preroll_queue, obj); + g_queue_push_tail (basesink->preroll_queue, sink_object_dup (obj)); return GST_FLOW_OK; } dequeue_failed: { GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s", gst_flow_get_name (ret)); - gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); + sink_object_clear (obj); return ret; } } @@ -3310,7 +3336,7 @@ dequeue_failed: */ static GstFlowReturn gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad, - GstMiniObject * obj, gboolean prerollable) + SinkObject * obj, gboolean prerollable) { GstFlowReturn ret; @@ -3321,9 +3347,7 @@ gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad, if (G_UNLIKELY (basesink->priv->received_eos)) goto was_eos; - ret = - gst_base_sink_queue_object_unlocked (basesink, pad, _PR_IS_EVENT, obj, - prerollable); + ret = gst_base_sink_queue_object_unlocked (basesink, pad, obj, prerollable); GST_BASE_SINK_PREROLL_UNLOCK (basesink); return ret; @@ -3333,7 +3357,7 @@ flushing: { GST_DEBUG_OBJECT (basesink, "sink is flushing"); GST_BASE_SINK_PREROLL_UNLOCK (basesink); - gst_mini_object_unref (obj); + sink_object_clear (obj); return GST_FLOW_WRONG_STATE; } was_eos: @@ -3341,7 +3365,7 @@ was_eos: GST_DEBUG_OBJECT (basesink, "we are EOS, dropping object, return UNEXPECTED"); GST_BASE_SINK_PREROLL_UNLOCK (basesink); - gst_mini_object_unref (obj); + sink_object_clear (obj); return GST_FLOW_UNEXPECTED; } } @@ -3400,11 +3424,14 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) GstBaseSink *basesink; gboolean result = TRUE; GstBaseSinkClass *bclass; + SinkObject obj; basesink = GST_BASE_SINK (gst_pad_get_parent (pad)); bclass = GST_BASE_SINK_GET_CLASS (basesink); + sink_object_init (&obj, event); + GST_DEBUG_OBJECT (basesink, "received event %p %" GST_PTR_FORMAT, event, event); @@ -3428,8 +3455,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) /* EOS is a prerollable object, we call the unlocked version because it * does not check the received_eos flag. */ - ret = gst_base_sink_queue_object_unlocked (basesink, pad, - _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE); + ret = gst_base_sink_queue_object_unlocked (basesink, pad, &obj, TRUE); if (G_UNLIKELY (ret != GST_FLOW_OK)) result = FALSE; } @@ -3461,9 +3487,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) gst_base_sink_configure_segment (basesink, pad, event, basesink->clip_segment); - ret = - gst_base_sink_queue_object_unlocked (basesink, pad, - _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), FALSE); + ret = gst_base_sink_queue_object_unlocked (basesink, pad, &obj, FALSE); if (G_UNLIKELY (ret != GST_FLOW_OK)) result = FALSE; else { @@ -3499,12 +3523,11 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) /* other events are sent to queue or subclass depending on if they * are serialized. */ if (GST_EVENT_IS_SERIALIZED (event)) { - gst_base_sink_queue_object (basesink, pad, - GST_MINI_OBJECT_CAST (event), FALSE); + gst_base_sink_queue_object (basesink, pad, &obj, FALSE); } else { if (bclass->event) bclass->event (basesink, event); - gst_event_unref (event); + sink_object_clear (&obj); } break; } @@ -3519,7 +3542,7 @@ flushing: GST_DEBUG_OBJECT (basesink, "we are flushing"); GST_BASE_SINK_PREROLL_UNLOCK (basesink); result = FALSE; - gst_event_unref (event); + sink_object_clear (&obj); goto done; } } @@ -3574,7 +3597,7 @@ gst_base_sink_needs_preroll (GstBaseSink * basesink) */ static GstFlowReturn gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, - guint8 obj_type, gpointer obj) + SinkObject * obj) { GstBaseSinkClass *bclass; GstFlowReturn result; @@ -3588,12 +3611,7 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, if (G_UNLIKELY (basesink->priv->received_eos)) goto was_eos; - if (OBJ_IS_BUFFERLIST (obj_type)) { - time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); - g_assert (NULL != time_buf); - } else { - time_buf = GST_BUFFER_CAST (obj); - } + time_buf = OBJ_GET_BUFFER (obj, 0); /* for code clarity */ clip_segment = basesink->clip_segment; @@ -3644,28 +3662,27 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, /* now we can process the buffer in the queue, this function takes ownership * of the buffer */ - result = gst_base_sink_queue_object_unlocked (basesink, pad, - obj_type, obj, TRUE); + result = gst_base_sink_queue_object_unlocked (basesink, pad, obj, TRUE); return result; /* ERRORS */ flushing: { GST_DEBUG_OBJECT (basesink, "sink is flushing"); - gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); + sink_object_clear (obj); return GST_FLOW_WRONG_STATE; } was_eos: { GST_DEBUG_OBJECT (basesink, "we are EOS, dropping object, return UNEXPECTED"); - gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); + sink_object_clear (obj); return GST_FLOW_UNEXPECTED; } out_of_segment: { GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment"); - gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); + sink_object_clear (obj); return GST_FLOW_OK; } } @@ -3674,7 +3691,7 @@ out_of_segment: */ static GstFlowReturn gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad, - guint8 obj_type, gpointer obj) + SinkObject * obj) { GstFlowReturn result; @@ -3682,7 +3699,7 @@ gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad, goto wrong_mode; GST_BASE_SINK_PREROLL_LOCK (basesink); - result = gst_base_sink_chain_unlocked (basesink, pad, obj_type, obj); + result = gst_base_sink_chain_unlocked (basesink, pad, obj); GST_BASE_SINK_PREROLL_UNLOCK (basesink); done: @@ -3696,7 +3713,7 @@ wrong_mode: "Push on pad %s:%s, but it was not activated in push mode", GST_DEBUG_PAD_NAME (pad)); GST_OBJECT_UNLOCK (pad); - gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); + sink_object_clear (obj); /* we don't post an error message this will signal to the peer * pushing that EOS is reached. */ result = GST_FLOW_UNEXPECTED; @@ -3708,52 +3725,44 @@ static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buf) { GstBaseSink *basesink; + SinkObject obj; basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad)); - return gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, buf); + obj.type = _PR_IS_BUFFER; + obj.objs[0] = buf; + obj.n_objs = 1; + + return gst_base_sink_chain_main (basesink, pad, &obj); } static GstFlowReturn -gst_base_sink_chain_list (GstPad * pad, GstBufferList * list) +gst_base_sink_chain_array (GstPad * pad, GstBuffer ** buffers, guint n_buffers) { GstBaseSink *basesink; GstBaseSinkClass *bclass; GstFlowReturn result; + SinkObject obj; basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad)); bclass = GST_BASE_SINK_GET_CLASS (basesink); - if (G_LIKELY (bclass->render_list)) { - result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFERLIST, list); - } else { - GstBufferListIterator *it; - GstBuffer *group; + if (G_LIKELY (bclass->render_array)) { + sink_object_init_array (&obj, (gpointer *) buffers, n_buffers); - GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer"); + result = gst_base_sink_chain_main (basesink, pad, &obj); + } else { + guint idx; - it = gst_buffer_list_iterate (list); + GST_INFO_OBJECT (pad, "chaining each buffer in array"); - if (gst_buffer_list_iterator_next_group (it)) { - do { - group = gst_buffer_list_iterator_merge_group (it); - if (group == NULL) { - group = gst_buffer_new (); - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group"); - } else { - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group"); - } - result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, group); - } while (result == GST_FLOW_OK - && gst_buffer_list_iterator_next_group (it)); - } else { - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group"); - result = - gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, - gst_buffer_new ()); + result = GST_FLOW_OK; + for (idx = 0; idx < n_buffers; idx++) { + if (G_LIKELY (result == GST_FLOW_OK)) { + result = gst_base_sink_chain (pad, buffers[idx]); + } else + gst_buffer_unref (buffers[idx]); } - gst_buffer_list_iterator_free (it); - gst_buffer_list_unref (list); } return result; } @@ -4068,6 +4077,7 @@ gst_base_sink_loop (GstPad * pad) GstFlowReturn result; guint blocksize; guint64 offset; + SinkObject obj; basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad)); @@ -4088,12 +4098,14 @@ gst_base_sink_loop (GstPad * pad) if (G_UNLIKELY (buf == NULL)) goto no_buffer; + sink_object_init (&obj, buf); + offset += gst_buffer_get_size (buf); gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset); GST_BASE_SINK_PREROLL_LOCK (basesink); - result = gst_base_sink_chain_unlocked (basesink, pad, _PR_IS_BUFFER, buf); + result = gst_base_sink_chain_unlocked (basesink, pad, &obj); GST_BASE_SINK_PREROLL_UNLOCK (basesink); if (G_UNLIKELY (result != GST_FLOW_OK)) goto paused; diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h index 92ee1f784..17e0e2022 100644 --- a/libs/gst/base/gstbasesink.h +++ b/libs/gst/base/gstbasesink.h @@ -130,8 +130,8 @@ struct _GstBaseSink { * @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. - * @render_list: Same as @render but used whith buffer lists instead of - * buffers. Since: 0.10.24 + * @render_array: Same as @render but used whith buffer arrays instead of + * buffers. * @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. @@ -186,8 +186,8 @@ struct _GstBaseSinkClass { GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer); GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer); - /* Render a BufferList */ - GstFlowReturn (*render_list) (GstBaseSink *sink, GstBufferList *buffer_list); + /* Render a buffer array */ + GstFlowReturn (*render_array) (GstBaseSink *sink, GstBuffer **buffers, guint n_buffers); /*< private >*/ gpointer _gst_reserved[GST_PADDING_LARGE]; diff --git a/plugins/elements/gsttee.c b/plugins/elements/gsttee.c index ef80db475..20fe1d56f 100644 --- a/plugins/elements/gsttee.c +++ b/plugins/elements/gsttee.c @@ -135,7 +135,8 @@ static void gst_tee_get_property (GObject * object, guint prop_id, static void gst_tee_dispose (GObject * object); static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer); -static GstFlowReturn gst_tee_chain_list (GstPad * pad, GstBufferList * list); +static GstFlowReturn gst_tee_chain_array (GstPad * pad, GstBuffer ** buffers, + guint n_buffers); static GstFlowReturn gst_tee_buffer_alloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); static gboolean gst_tee_sink_acceptcaps (GstPad * pad, GstCaps * caps); @@ -266,8 +267,8 @@ gst_tee_init (GstTee * tee, GstTeeClass * g_class) gst_pad_set_activatepush_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_sink_activate_push)); gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain)); - gst_pad_set_chain_list_function (tee->sinkpad, - GST_DEBUG_FUNCPTR (gst_tee_chain_list)); + gst_pad_set_chain_array_function (tee->sinkpad, + GST_DEBUG_FUNCPTR (gst_tee_chain_array)); gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad); tee->last_message = NULL; @@ -665,7 +666,7 @@ gst_tee_do_push (GstTee * tee, GstPad * pad, gpointer data, gboolean is_list) res = GST_FLOW_OK; } else if (is_list) { res = - gst_pad_push_list (pad, + gst_pad_push_array (pad, gst_buffer_list_ref (GST_BUFFER_LIST_CAST (data))); } else { res = gst_pad_push (pad, gst_buffer_ref (GST_BUFFER_CAST (data))); @@ -688,7 +689,8 @@ clear_pads (GstPad * pad, GstTee * tee) } static GstFlowReturn -gst_tee_handle_data (GstTee * tee, gpointer data, gboolean is_list) +gst_tee_handle_data (GstTee * tee, gpointer data, guint n_data, + gboolean is_list) { GList *pads; guint32 cookie; @@ -713,7 +715,7 @@ gst_tee_handle_data (GstTee * tee, gpointer data, gboolean is_list) if (pad == tee->pull_pad) { ret = GST_FLOW_OK; } else if (is_list) { - ret = gst_pad_push_list (pad, GST_BUFFER_LIST_CAST (data)); + ret = gst_pad_push_array (pad, (GstBuffer **) data, n_data); } else { ret = gst_pad_push (pad, GST_BUFFER_CAST (data)); } @@ -829,7 +831,7 @@ gst_tee_chain (GstPad * pad, GstBuffer * buffer) } static GstFlowReturn -gst_tee_chain_list (GstPad * pad, GstBufferList * list) +gst_tee_chain_array (GstPad * pad, GstBuffer ** buffer) { GstFlowReturn res; GstTee *tee; diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index b8968df4f..90dd63ecf 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -101,7 +101,6 @@ endif check_PROGRAMS = \ $(ABI_CHECKS) \ gst/gstbuffer \ - gst/gstbufferlist \ gst/gstmeta \ gst/gstbus \ gst/gstcaps \ |