From 22a48fb08cd76f36dc922284cf8ecf4fae11ce77 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Tue, 12 May 2009 13:10:55 +0200 Subject: [PATCH] bufferlist: hook up the pad functions Reuse buffer code for bufferlists. Not sure if this measurably impacts performance for the simple buffer case, if it does after doing some benchmarks, we can decouple it later. Fixes #572285 --- docs/gst/gstreamer-sections.txt | 7 + gst/gstpad.c | 353 +++++++++++++++++++++++++++++++++------- gst/gstpad.h | 31 +++- tests/check/gst/gstpad.c | 82 ++++++++++ win32/common/libgstreamer.def | 3 + 5 files changed, 419 insertions(+), 57 deletions(-) diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 38aafbf..b4447d5 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -134,6 +134,7 @@ gst_bus_sync_reply_get_type GstBusPrivate +
gstbuffer GstBuffer @@ -1354,6 +1355,9 @@ GstPadBufferAllocFunction gst_pad_set_chain_function GstPadChainFunction +gst_pad_set_chain_list_function +GstPadChainListFunction + gst_pad_set_checkgetrange_function GstPadCheckGetRangeFunction @@ -1398,6 +1402,7 @@ GstPadActivateModeFunction gst_pad_push gst_pad_push_event +gst_pad_push_list gst_pad_check_pull_range gst_pad_pull_range gst_pad_activate_pull @@ -1441,6 +1446,7 @@ gst_pad_get_element_private gst_pad_chain +gst_pad_chain_list gst_pad_start_task gst_pad_pause_task @@ -1516,6 +1522,7 @@ GST_PAD_ACTIVATEPULLFUNC GST_PAD_ACTIVATEPUSHFUNC GST_PAD_BUFFERALLOCFUNC GST_PAD_CHAINFUNC +GST_PAD_CHAINLISTFUNC GST_PAD_CHECKGETRANGEFUNC GST_PAD_EVENTFUNC GST_PAD_FIXATECAPSFUNC diff --git a/gst/gstpad.c b/gst/gstpad.c index d9398c3..724d087 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -1235,6 +1235,29 @@ gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain) } /** + * gst_pad_set_chain_list_function: + * @pad: a sink #GstPad. + * @chainlist: the #GstPadChainListFunction to set. + * + * Sets the given chain list function for the pad. The chainlist function is + * called to process a #GstBufferList input buffer list. See + * #GstPadChainListFunction for more details. + * + * Since: 0.10.24 + */ +void +gst_pad_set_chain_list_function (GstPad * pad, + GstPadChainListFunction chainlist) +{ + 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_set_getrange_function: * @pad: a source #GstPad. * @get: the #GstPadGetRangeFunction to set. @@ -3925,15 +3948,48 @@ gst_pad_emit_have_data_signal (GstPad * pad, GstMiniObject * obj) return res; } +static void +gst_pad_data_unref (gboolean is_buffer, void *data) +{ + 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 { + GstBufferListIterator *it; + GstBuffer *buf; + + caps = NULL; + it = gst_buffer_list_iterate (GST_BUFFER_LIST_CAST (data)); + if (gst_buffer_list_iterator_next_group (it)) { + buf = gst_buffer_list_iterator_next (it); + if (buf != NULL) { + caps = GST_BUFFER_CAPS (buf); + } + } + gst_buffer_list_iterator_free (it); + } + return caps; +} + /* this is the chain function that does not perform the additional argument * checking for that little extra speed. */ static inline GstFlowReturn -gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer) +gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data) { GstCaps *caps; gboolean caps_changed; - GstPadChainFunction chainfunc; GstFlowReturn ret; gboolean emit_signal; @@ -3943,7 +3999,7 @@ gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer) if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad))) goto flushing; - caps = GST_BUFFER_CAPS (buffer); + caps = gst_pad_data_get_caps (is_buffer, data); caps_changed = caps && caps != GST_PAD_CAPS (pad); emit_signal = GST_PAD_DO_BUFFER_SIGNALS (pad) > 0; @@ -3952,8 +4008,14 @@ gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer) /* 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)) { - if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (buffer))) - goto dropping; + if (G_LIKELY (is_buffer)) { + if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (data))) + goto dropping; + } else { + /* chain all groups in the buffer list one by one to avoid problems with + * buffer probes that push buffers or events */ + goto chain_groups; + } } /* we got a new datatype on the pad, see if it can handle it */ @@ -3968,26 +4030,81 @@ gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer) * 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_UNLIKELY ((chainfunc = GST_PAD_CHAINFUNC (pad)) == NULL)) - goto no_function; + if (G_LIKELY (is_buffer)) { + GstPadChainFunction chainfunc; - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, - "calling chainfunction &%s", GST_DEBUG_FUNCPTR_NAME (chainfunc)); + if (G_UNLIKELY ((chainfunc = GST_PAD_CHAINFUNC (pad)) == NULL)) + goto no_function; - ret = chainfunc (pad, buffer); + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, + "calling chainfunction &%s", GST_DEBUG_FUNCPTR_NAME (chainfunc)); - GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, - "called chainfunction &%s, returned %s", - GST_DEBUG_FUNCPTR_NAME (chainfunc), gst_flow_get_name (ret)); + ret = chainfunc (pad, GST_BUFFER_CAST (data)); + + 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; + + if (G_UNLIKELY ((chainlistfunc = GST_PAD_CHAINLISTFUNC (pad)) == NULL)) + goto chain_groups; + + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, + "calling chainlistfunction &%s", + GST_DEBUG_FUNCPTR_NAME (chainlistfunc)); + + ret = chainlistfunc (pad, GST_BUFFER_LIST_CAST (data)); + + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, + "called chainlistfunction &%s, returned %s", + GST_DEBUG_FUNCPTR_NAME (chainlistfunc), gst_flow_get_name (ret)); + } GST_PAD_STREAM_UNLOCK (pad); return ret; +chain_groups: + { + GstBufferList *list; + GstBufferListIterator *it; + GstBuffer *group; + + GST_PAD_STREAM_UNLOCK (pad); + + GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer"); + + list = GST_BUFFER_LIST_CAST (data); + it = gst_buffer_list_iterate (list); + + ret = GST_FLOW_OK; + 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); + } 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 ()); + } + + gst_buffer_list_iterator_free (it); + gst_buffer_list_unref (list); + + return ret; + } + /* ERRORS */ flushing: { - gst_buffer_unref (buffer); + gst_pad_data_unref (is_buffer, data); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but pad was flushing"); GST_OBJECT_UNLOCK (pad); @@ -3996,22 +4113,22 @@ flushing: } dropping: { - gst_buffer_unref (buffer); + gst_pad_data_unref (is_buffer, data); GST_DEBUG_OBJECT (pad, "Dropping buffer due to FALSE probe return"); GST_PAD_STREAM_UNLOCK (pad); return GST_FLOW_OK; } not_negotiated: { - gst_buffer_unref (buffer); + gst_pad_data_unref (is_buffer, data); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, - "pushing buffer but pad did not accept"); + "pushing data but pad did not accept"); GST_PAD_STREAM_UNLOCK (pad); return GST_FLOW_NOT_NEGOTIATED; } no_function: { - gst_buffer_unref (buffer); + gst_pad_data_unref (is_buffer, data); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but not chainhandler"); GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL), @@ -4055,48 +4172,55 @@ 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_unchecked (pad, buffer); + return gst_pad_chain_data_unchecked (pad, TRUE, buffer); } /** - * gst_pad_push: - * @pad: a source #GstPad, returns #GST_FLOW_ERROR if not. - * @buffer: the #GstBuffer to push returns GST_FLOW_ERROR if not. + * gst_pad_chain_list: + * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not. + * @list: the #GstBufferList to send, return GST_FLOW_ERROR if not. * - * Pushes a buffer to the peer of @pad. + * Chain a bufferlist to @pad. * - * This function will call an installed pad block before triggering any - * installed pad probes. + * The function returns #GST_FLOW_WRONG_STATE if the pad was flushing. * - * If the caps on @buffer are different from the currently configured caps on - * @pad, this function will call any installed setcaps function on @pad (see - * gst_pad_set_setcaps_function()). In case of failure to renegotiate the new - * format, this function returns #GST_FLOW_NOT_NEGOTIATED. + * If the caps on the first buffer of @list are different from the current + * caps on @pad, this function will call any setcaps function + * (see gst_pad_set_setcaps_function()) installed on @pad. If the new caps + * are not acceptable for @pad, this function returns #GST_FLOW_NOT_NEGOTIATED. * - * The function proceeds calling gst_pad_chain() on the peer pad and returns - * the value from that function. If @pad has no peer, #GST_FLOW_NOT_LINKED will - * be returned. + * The function proceeds calling the chainlist function installed on @pad (see + * gst_pad_set_chain_list_function()) and the return value of that function is + * returned to the caller. #GST_FLOW_NOT_SUPPORTED is returned if @pad has no + * chainlist function. * - * In all cases, success or failure, the caller loses its reference to @buffer + * In all cases, success or failure, the caller loses its reference to @list * after calling this function. * - * Returns: a #GstFlowReturn from the peer pad. + * Returns: a #GstFlowReturn from the pad. + * + * Since: 0.10.24 * * MT safe. */ GstFlowReturn -gst_pad_push (GstPad * pad, GstBuffer * buffer) +gst_pad_chain_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_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); +} + +static GstFlowReturn +gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data) { GstPad *peer; GstFlowReturn ret; - GstCaps *caps; gboolean caps_changed; - 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 (buffer), GST_FLOW_ERROR); - GST_OBJECT_LOCK (pad); /* FIXME: this check can go away; pad_set_blocked could be implemented with @@ -4111,25 +4235,29 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer) /* unlock before emitting */ GST_OBJECT_UNLOCK (pad); - /* 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 (buffer))) - goto dropped; - + if (G_LIKELY (is_buffer)) { + /* 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 (data))) + goto dropped; + } else { + /* push all buffers in the list */ + goto push_groups; + } GST_OBJECT_LOCK (pad); } if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL)) goto not_linked; - /* take ref to peer pad before releasing the lock */ - gst_object_ref (peer); - /* Before pushing the buffer to the peer pad, ensure that caps * are set on this pad */ - caps = GST_BUFFER_CAPS (buffer); + caps = gst_pad_data_get_caps (is_buffer, data); caps_changed = caps && caps != GST_PAD_CAPS (pad); + /* 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 */ @@ -4141,29 +4269,63 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer) goto not_negotiated; } - ret = gst_pad_chain_unchecked (peer, buffer); + ret = gst_pad_chain_data_unchecked (peer, is_buffer, data); gst_object_unref (peer); return ret; +push_groups: + { + GstBufferList *list; + GstBufferListIterator *it; + GstBuffer *group; + + GST_INFO_OBJECT (pad, "pushing each group in list as a merged buffer"); + + list = GST_BUFFER_LIST_CAST (data); + it = gst_buffer_list_iterate (list); + + ret = GST_FLOW_OK; + 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); + } 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 ()); + } + + gst_buffer_list_iterator_free (it); + gst_buffer_list_unref (list); + + return ret; + } + /* ERROR recovery here */ flushed: { - gst_buffer_unref (buffer); + gst_pad_data_unref (is_buffer, data); GST_DEBUG_OBJECT (pad, "pad block stopped by flush"); GST_OBJECT_UNLOCK (pad); return ret; } dropped: { - gst_buffer_unref (buffer); + gst_pad_data_unref (is_buffer, data); GST_DEBUG_OBJECT (pad, "Dropping buffer due to FALSE probe return"); return GST_FLOW_OK; } not_linked: { - gst_buffer_unref (buffer); + gst_pad_data_unref (is_buffer, data); GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pushing, but it was not linked"); GST_OBJECT_UNLOCK (pad); @@ -4171,15 +4333,96 @@ not_linked: } not_negotiated: { - gst_buffer_unref (buffer); + gst_pad_data_unref (is_buffer, data); gst_object_unref (peer); GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad, - "element pushed buffer then refused to accept the caps"); + "element pushed data then refused to accept the caps"); return GST_FLOW_NOT_NEGOTIATED; } } /** + * gst_pad_push: + * @pad: a source #GstPad, returns #GST_FLOW_ERROR if not. + * @buffer: the #GstBuffer to push returns GST_FLOW_ERROR if not. + * + * Pushes a buffer to the peer of @pad. + * + * This function will call an installed pad block before triggering any + * installed pad probes. + * + * If the caps on @buffer are different from the currently configured caps on + * @pad, this function will call any installed setcaps function on @pad (see + * gst_pad_set_setcaps_function()). In case of failure to renegotiate the new + * format, this function returns #GST_FLOW_NOT_NEGOTIATED. + * + * The function proceeds calling gst_pad_chain() on the peer pad and returns + * the value from that function. If @pad has no peer, #GST_FLOW_NOT_LINKED will + * be returned. + * + * In all cases, success or failure, the caller loses its reference to @buffer + * after calling this function. + * + * Returns: a #GstFlowReturn from the peer pad. + * + * MT safe. + */ +GstFlowReturn +gst_pad_push (GstPad * pad, GstBuffer * buffer) +{ + 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 (buffer), GST_FLOW_ERROR); + + return gst_pad_push_data (pad, TRUE, buffer); +} + +/** + * gst_pad_push_list: + * @pad: a source #GstPad, returns #GST_FLOW_ERROR if not. + * @list: the #GstBufferList to push returns GST_FLOW_ERROR if not. + * + * Pushes a buffer list to the peer of @pad. + * + * This function will call an installed pad block before triggering any + * installed pad probes. + * + * If the caps on the first buffer in the first group of @list are different + * from the currently configured caps on @pad, this function will call any + * installed setcaps function on @pad (see gst_pad_set_setcaps_function()). In + * case of failure to renegotiate the new format, this function returns + * #GST_FLOW_NOT_NEGOTIATED. + * + * If there are any probes installed on @pad every group of the buffer list + * will be merged into a normal #GstBuffer and pushed via gst_pad_push and the + * buffer list will be unreffed. + * + * The function proceeds calling the chain function on the peer pad and returns + * the value from that function. If @pad has no peer, #GST_FLOW_NOT_LINKED will + * be returned. If the peer pad does not have any installed chainlist function + * every group buffer of the list will be merged into a normal #GstBuffer and + * chained via gst_pad_chain(). + * + * In all cases, success or failure, the caller loses its reference to @list + * after calling this function. + * + * Returns: a #GstFlowReturn from the peer pad. + * + * MT safe. + * + * Since: 0.10.24 + */ +GstFlowReturn +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); + + return gst_pad_push_data (pad, FALSE, list); +} + +/** * gst_pad_check_pull_range: * @pad: a sink #GstPad. * diff --git a/gst/gstpad.h b/gst/gstpad.h index 2f167ca..2b71939 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -230,6 +231,26 @@ typedef gboolean (*GstPadActivateModeFunction) (GstPad *pad, gboolean active); * Returns: #GST_FLOW_OK for success */ typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer); + +/** + * GstPadChainListFunction: + * @pad: the sink #GstPad that performed the chain. + * @list: the #GstBufferList that is chained, not %NULL. + * + * A function that will be called on sinkpads when chaining buffer lists. + * The function typically processes the data contained in the buffer list 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. + * + * When a chainlist function detects an error in the data stream, it must + * post an error on the bus and return an appropriate #GstFlowReturn value. + * + * Returns: #GST_FLOW_OK for success + */ +typedef GstFlowReturn (*GstPadChainListFunction) (GstPad *pad, GstBufferList *list); + /** * GstPadGetRangeFunction: * @pad: the src #GstPad to perform the getrange on. @@ -546,7 +567,8 @@ typedef struct _GstPadTemplate GstPadTemplate; * @unlinkfunc: function called when pad is unlinked * @peer: the pad this pad is linked to * @sched_private: private storage for the scheduler - * @chainfunc: function to chain data to pad + * @chainfunc: function to chain buffer to pad + * @chainlistfunc: function to chain buffer list to pad * @checkgetrangefunc: function to check if pad can operate in pull mode * @getrangefunc: function to get a range of data from a pad * @eventfunc: function to send an event to a pad @@ -629,6 +651,7 @@ struct _GstPad { /* ABI added */ /* iterate internal links */ GstPadIterIntLinkFunction iterintlinkfunc; + GstPadChainListFunction chainlistfunc; /* free block_data */ GDestroyNotify block_destroy_data; @@ -638,7 +661,7 @@ struct _GstPad { struct { gboolean block_callback_called; } ABI; - gpointer _gst_reserved[GST_PADDING - 2]; + gpointer _gst_reserved[GST_PADDING - 3]; } abidata; }; @@ -670,6 +693,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_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) @@ -840,6 +864,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_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); @@ -878,6 +903,7 @@ 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); gboolean gst_pad_check_pull_range (GstPad *pad); GstFlowReturn gst_pad_pull_range (GstPad *pad, guint64 offset, guint size, GstBuffer **buffer); @@ -886,6 +912,7 @@ 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_get_range (GstPad *pad, guint64 offset, guint size, GstBuffer **buffer); gboolean gst_pad_send_event (GstPad *pad, GstEvent *event); diff --git a/tests/check/gst/gstpad.c b/tests/check/gst/gstpad.c index 2c40379..a3a6f67 100644 --- a/tests/check/gst/gstpad.c +++ b/tests/check/gst/gstpad.c @@ -399,6 +399,87 @@ GST_START_TEST (test_push_linked) GST_END_TEST; +static GstBuffer * +buffer_from_string (gchar * str) +{ + guint size; + GstBuffer *buf; + + size = strlen (str); + buf = gst_buffer_new_and_alloc (size); + memcpy (GST_BUFFER_DATA (buf), str, size); + GST_BUFFER_SIZE (buf) = size; + + return buf; +} + +GST_START_TEST (test_push_buffer_list_compat) +{ + GstPad *src, *sink; + GstPadLinkReturn plr; + GstCaps *caps; + GstBufferList *list; + GstBufferListIterator *it; + GstBuffer *buffer; + + /* setup */ + sink = gst_pad_new ("sink", GST_PAD_SINK); + fail_if (sink == NULL); + gst_pad_set_chain_function (sink, gst_check_chain_func); + /* leave chainlistfunc unset */ + + src = gst_pad_new ("src", GST_PAD_SRC); + fail_if (src == NULL); + + caps = gst_caps_from_string ("foo/bar"); + + gst_pad_set_caps (src, caps); + gst_pad_set_caps (sink, caps); + + plr = gst_pad_link (src, sink); + fail_unless (GST_PAD_LINK_SUCCESSFUL (plr)); + + list = gst_buffer_list_new (); + + /* activate pads */ + gst_pad_set_active (src, TRUE); + gst_pad_set_active (sink, TRUE); + + /* test */ + /* adding to a buffer list will drop the ref to the buffer */ + it = gst_buffer_list_iterate (list); + gst_buffer_list_iterator_add_group (it); + gst_buffer_list_iterator_add (it, buffer_from_string ("List")); + gst_buffer_list_iterator_add (it, buffer_from_string ("Group")); + gst_buffer_list_iterator_add_group (it); + gst_buffer_list_iterator_add (it, buffer_from_string ("Another")); + gst_buffer_list_iterator_add (it, buffer_from_string ("List")); + gst_buffer_list_iterator_add (it, buffer_from_string ("Group")); + gst_buffer_list_iterator_free (it); + fail_unless (gst_pad_push_list (src, list) == GST_FLOW_OK); + fail_unless_equals_int (g_list_length (buffers), 2); + buffer = GST_BUFFER (buffers->data); + ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1); + fail_unless (memcmp (GST_BUFFER_DATA (buffer), "ListGroup", 9) == 0); + gst_buffer_unref (buffer); + buffers = g_list_delete_link (buffers, buffers); + buffer = GST_BUFFER (buffers->data); + ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1); + fail_unless (memcmp (GST_BUFFER_DATA (buffer), "AnotherListGroup", 16) == 0); + gst_buffer_unref (buffer); + buffers = g_list_delete_link (buffers, buffers); + fail_unless (buffers == NULL); + + /* teardown */ + gst_pad_unlink (src, sink); + gst_object_unref (src); + gst_object_unref (sink); + ASSERT_CAPS_REFCOUNT (caps, "caps", 1); + gst_caps_unref (caps); +} + +GST_END_TEST; + GST_START_TEST (test_flowreturn) { GstFlowReturn ret; @@ -904,6 +985,7 @@ gst_pad_suite (void) tcase_add_test (tc_chain, test_name_is_valid); tcase_add_test (tc_chain, test_push_unlinked); tcase_add_test (tc_chain, test_push_linked); + tcase_add_test (tc_chain, test_push_buffer_list_compat); tcase_add_test (tc_chain, test_flowreturn); tcase_add_test (tc_chain, test_push_negotiation); tcase_add_test (tc_chain, test_src_unref_unlink); diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index febcb4a..c2ef238 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -556,6 +556,7 @@ EXPORTS gst_pad_alloc_buffer_and_set_caps gst_pad_can_link gst_pad_chain + gst_pad_chain_list gst_pad_check_pull_range gst_pad_direction_get_type gst_pad_dispatcher @@ -600,6 +601,7 @@ EXPORTS gst_pad_pull_range gst_pad_push gst_pad_push_event + gst_pad_push_list gst_pad_query gst_pad_query_convert gst_pad_query_default @@ -623,6 +625,7 @@ EXPORTS gst_pad_set_bufferalloc_function gst_pad_set_caps gst_pad_set_chain_function + gst_pad_set_chain_list_function gst_pad_set_checkgetrange_function gst_pad_set_element_private gst_pad_set_event_function -- 2.7.4