static void udpsink_test (gboolean use_buffer_lists) { GstSegment segment; GstElement *udpsink; GstPad *srcpad; GstBufferList *list; guint data_size; list = create_buffer_list (&data_size); udpsink = gst_check_setup_element ("udpsink"); if (use_buffer_lists) set_render_list_function (udpsink); srcpad = gst_check_setup_src_pad_by_name (udpsink, &srctemplate, "sink"); gst_element_set_state (udpsink, GST_STATE_PLAYING); gst_pad_set_active (srcpad, TRUE); gst_pad_push_event (srcpad, gst_event_new_stream_start ("hey there!")); gst_segment_init (&segment, GST_FORMAT_TIME); gst_pad_push_event (srcpad, gst_event_new_segment (&segment)); fail_unless_equals_int (gst_pad_push_list (srcpad, list), GST_FLOW_OK); gst_check_teardown_pad_by_name (udpsink, "sink"); gst_check_teardown_element (udpsink); if (use_buffer_lists) fail_unless_equals_int (data_size, render_list_bytes_received); }
static void udpsink_test (gboolean use_buffer_lists) { GstElement *udpsink; GstPad *srcpad; GstBufferList *list; guint data_size; list = _create_buffer_list (&data_size); udpsink = gst_check_setup_element ("udpsink"); if (use_buffer_lists) _set_render_function (udpsink); srcpad = gst_check_setup_src_pad_by_name (udpsink, &srctemplate, "sink"); gst_element_set_state (udpsink, GST_STATE_PLAYING); gst_pad_push_event (srcpad, gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME, 0, -1, 0)); gst_pad_push_list (srcpad, list); gst_check_teardown_pad_by_name (udpsink, "sink"); gst_check_teardown_element (udpsink); if (use_buffer_lists) fail_if (data_size != render_list_bytes_received); }
static GstFlowReturn gst_funnel_sink_chain_object (GstPad * pad, GstFunnel * funnel, gboolean is_list, GstMiniObject * obj) { GstFlowReturn res; GST_DEBUG_OBJECT (pad, "received %" GST_PTR_FORMAT, obj); GST_PAD_STREAM_LOCK (funnel->srcpad); if ((funnel->last_sinkpad == NULL) || ((funnel->forward_sticky_events_mode != GST_FUNNEL_FORWARD_STICKY_EVENTS_MODE_NEVER) && (funnel->last_sinkpad != pad))) { GST_DEBUG_OBJECT (pad, "Forwarding sticky events"); gst_pad_sticky_events_foreach (pad, forward_events_on_stream_changed, funnel); gst_object_replace ((GstObject **) & funnel->last_sinkpad, GST_OBJECT (pad)); } if (is_list) res = gst_pad_push_list (funnel->srcpad, GST_BUFFER_LIST_CAST (obj)); else res = gst_pad_push (funnel->srcpad, GST_BUFFER_CAST (obj)); GST_PAD_STREAM_UNLOCK (funnel->srcpad); GST_LOG_OBJECT (pad, "handled buffer%s %s", (is_list ? "list" : ""), gst_flow_get_name (res)); return res; }
static GstFlowReturn mpegpsmux_push_gop_list (MpegPsMux * mux) { GstFlowReturn flow; g_assert (mux->gop_list != NULL); GST_DEBUG_OBJECT (mux, "Sending pending GOP of %u buffers", gst_buffer_list_length (mux->gop_list)); flow = gst_pad_push_list (mux->srcpad, mux->gop_list); mux->gop_list = NULL; return flow; }
/** * gst_rtp_base_payload_push_list: * @payload: a #GstRTPBasePayload * @list: a #GstBufferList * * Push @list to the peer element of the payloader. The SSRC, payload type, * seqnum and timestamp of the RTP buffer will be updated first. * * This function takes ownership of @list. * * Returns: a #GstFlowReturn. */ GstFlowReturn gst_rtp_base_payload_push_list (GstRTPBasePayload * payload, GstBufferList * list) { GstFlowReturn res; res = gst_rtp_base_payload_prepare_push (payload, list, TRUE); if (G_LIKELY (res == GST_FLOW_OK)) res = gst_pad_push_list (payload->srcpad, list); else gst_buffer_list_unref (list); return res; }
/** * gst_proxy_pad_chain_list_default: * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not. * @parent: the parent of @pad or NULL * @list: (transfer full): the #GstBufferList to send, return GST_FLOW_ERROR * if not. * * Invoke the default chain list function of the proxy pad. * * Returns: a #GstFlowReturn from the pad. */ GstFlowReturn gst_proxy_pad_chain_list_default (GstPad * pad, GstObject * parent, GstBufferList * list) { GstFlowReturn res; GstPad *internal; g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR); internal = GST_PROXY_PAD_INTERNAL (pad); res = gst_pad_push_list (internal, list); return res; }
/** * gst_rtp_base_depayload_push_list: * @filter: a #GstRTPBaseDepayload * @out_list: a #GstBufferList * * Push @out_list to the peer of @filter. This function takes ownership of * @out_list. * * Returns: a #GstFlowReturn. */ GstFlowReturn gst_rtp_base_depayload_push_list (GstRTPBaseDepayload * filter, GstBufferList * out_list) { GstFlowReturn res; res = gst_rtp_base_depayload_prepare_push (filter, TRUE, &out_list); if (G_LIKELY (res == GST_FLOW_OK)) res = gst_pad_push_list (filter->srcpad, out_list); else gst_buffer_list_unref (out_list); return res; }
static GstFlowReturn gst_tee_do_push (GstTee * tee, GstPad * pad, gpointer data, gboolean is_list) { GstFlowReturn res; /* Push */ if (pad == tee->pull_pad) { /* don't push on the pad we're pulling from */ res = GST_FLOW_OK; } else if (is_list) { res = gst_pad_push_list (pad, gst_buffer_list_ref (GST_BUFFER_LIST_CAST (data))); } else { res = gst_pad_push (pad, gst_buffer_ref (GST_BUFFER_CAST (data))); } return res; }
static GstFlowReturn gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent, GstBufferList * bufferlist) { GstRTPMux *rtp_mux; GstFlowReturn ret; GstRTPMuxPadPrivate *padpriv; struct BufferListData bd; rtp_mux = GST_RTP_MUX (parent); GST_OBJECT_LOCK (rtp_mux); padpriv = gst_pad_get_element_private (pad); if (!padpriv) { GST_OBJECT_UNLOCK (rtp_mux); ret = GST_FLOW_NOT_LINKED; gst_buffer_list_unref (bufferlist); goto out; } bd.rtp_mux = rtp_mux; bd.padpriv = padpriv; bd.drop = FALSE; bufferlist = gst_buffer_list_make_writable (bufferlist); gst_buffer_list_foreach (bufferlist, process_list_item, &bd); GST_OBJECT_UNLOCK (rtp_mux); if (bd.drop) { gst_buffer_list_unref (bufferlist); ret = GST_FLOW_OK; } else { ret = gst_pad_push_list (rtp_mux->srcpad, bufferlist); } out: return ret; }
static GstFlowReturn sink_chain_list (GstPad * pad, GstObject * parent, GstBufferList * list) { GstDtlsDec *self = GST_DTLS_DEC (parent); GstFlowReturn ret = GST_FLOW_OK; GstPad *other_pad; list = gst_buffer_list_make_writable (list); gst_buffer_list_foreach (list, process_buffer_from_list, self); if (gst_buffer_list_length (list) == 0) { GST_DEBUG_OBJECT (self, "Not produced any buffers"); gst_buffer_list_unref (list); return GST_FLOW_OK; } g_mutex_lock (&self->src_mutex); other_pad = self->src; if (other_pad) gst_object_ref (other_pad); g_mutex_unlock (&self->src_mutex); if (other_pad) { GST_LOG_OBJECT (self, "decoded buffer list with length %u, pushing", gst_buffer_list_length (list)); ret = gst_pad_push_list (other_pad, list); gst_object_unref (other_pad); } else { GST_LOG_OBJECT (self, "dropped buffer list with length %d, not linked", gst_buffer_list_length (list)); gst_buffer_list_unref (list); } return ret; }
static GstFlowReturn gst_tee_handle_data (GstTee * tee, gpointer data, gboolean is_list) { GList *pads; guint32 cookie; GstFlowReturn ret, cret; if (G_UNLIKELY (!tee->silent)) gst_tee_do_message (tee, tee->sinkpad, data, is_list); GST_OBJECT_LOCK (tee); pads = GST_ELEMENT_CAST (tee)->srcpads; /* special case for zero pads */ if (G_UNLIKELY (!pads)) goto no_pads; /* special case for just one pad that avoids reffing the buffer */ if (!pads->next) { GstPad *pad = GST_PAD_CAST (pads->data); /* Keep another ref around, a pad probe * might release and destroy the pad */ gst_object_ref (pad); GST_OBJECT_UNLOCK (tee); if (pad == tee->pull_pad) { ret = GST_FLOW_OK; } else if (is_list) { ret = gst_pad_push_list (pad, GST_BUFFER_LIST_CAST (data)); } else { ret = gst_pad_push (pad, GST_BUFFER_CAST (data)); } gst_object_unref (pad); if (ret == GST_FLOW_NOT_LINKED && tee->allow_not_linked) { ret = GST_FLOW_OK; } return ret; } /* mark all pads as 'not pushed on yet' */ g_list_foreach (pads, (GFunc) clear_pads, tee); restart: if (tee->allow_not_linked) { cret = GST_FLOW_OK; } else { cret = GST_FLOW_NOT_LINKED; } pads = GST_ELEMENT_CAST (tee)->srcpads; cookie = GST_ELEMENT_CAST (tee)->pads_cookie; while (pads) { GstPad *pad; pad = GST_PAD_CAST (pads->data); if (G_LIKELY (!GST_TEE_PAD_CAST (pad)->pushed)) { /* not yet pushed, release lock and start pushing */ gst_object_ref (pad); GST_OBJECT_UNLOCK (tee); GST_LOG_OBJECT (pad, "Starting to push %s %p", is_list ? "list" : "buffer", data); ret = gst_tee_do_push (tee, pad, data, is_list); GST_LOG_OBJECT (pad, "Pushing item %p yielded result %s", data, gst_flow_get_name (ret)); GST_OBJECT_LOCK (tee); /* keep track of which pad we pushed and the result value */ GST_TEE_PAD_CAST (pad)->pushed = TRUE; GST_TEE_PAD_CAST (pad)->result = ret; gst_object_unref (pad); pad = NULL; } else { /* already pushed, use previous return value */ ret = GST_TEE_PAD_CAST (pad)->result; GST_LOG_OBJECT (pad, "pad already pushed with %s", gst_flow_get_name (ret)); } /* before we go combining the return value, check if the pad list is still * the same. It could be possible that the pad we just pushed was removed * and the return value it not valid anymore */ if (G_UNLIKELY (GST_ELEMENT_CAST (tee)->pads_cookie != cookie)) { GST_LOG_OBJECT (tee, "pad list changed"); /* the list of pads changed, restart iteration. Pads that we already * pushed on and are still in the new list, will not be pushed on * again. */ goto restart; } /* stop pushing more buffers when we have a fatal error */ if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)) goto error; /* keep all other return values, overwriting the previous one. */ if (G_LIKELY (ret != GST_FLOW_NOT_LINKED)) { GST_LOG_OBJECT (tee, "Replacing ret val %d with %d", cret, ret); cret = ret; } pads = g_list_next (pads); } GST_OBJECT_UNLOCK (tee); gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); /* no need to unset gvalue */ return cret; /* ERRORS */ no_pads: { if (tee->allow_not_linked) { GST_DEBUG_OBJECT (tee, "there are no pads, dropping %s", is_list ? "buffer-list" : "buffer"); ret = GST_FLOW_OK; } else { GST_DEBUG_OBJECT (tee, "there are no pads, return not-linked"); ret = GST_FLOW_NOT_LINKED; } goto end; } error: { GST_DEBUG_OBJECT (tee, "received error %s", gst_flow_get_name (ret)); goto end; } end: { GST_OBJECT_UNLOCK (tee); gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); return ret; } }
static GstFlowReturn gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent, GstBufferList * bufferlist) { GstRTPMux *rtp_mux; GstFlowReturn ret; GstRTPMuxPadPrivate *padpriv; gboolean changed = FALSE; struct BufferListData bd; rtp_mux = GST_RTP_MUX (parent); if (gst_pad_check_reconfigure (rtp_mux->srcpad)) { GstCaps *current_caps = gst_pad_get_current_caps (pad); if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) { ret = GST_FLOW_NOT_NEGOTIATED; gst_buffer_list_unref (bufferlist); goto out; } gst_caps_unref (current_caps); } GST_OBJECT_LOCK (rtp_mux); padpriv = gst_pad_get_element_private (pad); if (!padpriv) { GST_OBJECT_UNLOCK (rtp_mux); ret = GST_FLOW_NOT_LINKED; gst_buffer_list_unref (bufferlist); goto out; } bd.rtp_mux = rtp_mux; bd.padpriv = padpriv; bd.drop = FALSE; bufferlist = gst_buffer_list_make_writable (bufferlist); gst_buffer_list_foreach (bufferlist, process_list_item, &bd); if (!bd.drop && pad != rtp_mux->last_pad) { changed = TRUE; g_clear_object (&rtp_mux->last_pad); rtp_mux->last_pad = g_object_ref (pad); } GST_OBJECT_UNLOCK (rtp_mux); if (changed) gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux); if (bd.drop) { gst_buffer_list_unref (bufferlist); ret = GST_FLOW_OK; } else { ret = gst_pad_push_list (rtp_mux->srcpad, bufferlist); } out: return ret; }