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 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_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; } }
/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer * before the buffer is pushed. */ static GstFlowReturn gst_rtp_base_payload_prepare_push (GstRTPBasePayload * payload, gpointer obj, gboolean is_list) { GstRTPBasePayloadPrivate *priv; HeaderData data; if (payload->clock_rate == 0) goto no_rate; priv = payload->priv; /* update first, so that the property is set to the last * seqnum pushed */ payload->seqnum = priv->next_seqnum; /* fill in the fields we want to set on all headers */ data.payload = payload; data.seqnum = payload->seqnum; data.ssrc = payload->current_ssrc; data.pt = payload->pt; /* find the first buffer with a timestamp */ if (is_list) { data.dts = -1; data.pts = -1; data.offset = GST_BUFFER_OFFSET_NONE; gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), find_timestamp, &data); } else { data.dts = GST_BUFFER_DTS (GST_BUFFER_CAST (obj)); data.pts = GST_BUFFER_PTS (GST_BUFFER_CAST (obj)); data.offset = GST_BUFFER_OFFSET (GST_BUFFER_CAST (obj)); } /* convert to RTP time */ if (priv->perfect_rtptime && data.offset != GST_BUFFER_OFFSET_NONE && priv->base_offset != GST_BUFFER_OFFSET_NONE) { /* if we have an offset, use that for making an RTP timestamp */ data.rtptime = payload->ts_base + priv->base_rtime + data.offset - priv->base_offset; GST_LOG_OBJECT (payload, "Using offset %" G_GUINT64_FORMAT " for RTP timestamp", data.offset); } else if (GST_CLOCK_TIME_IS_VALID (data.pts)) { gint64 rtime; /* no offset, use the gstreamer pts */ rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME, data.pts); if (rtime == -1) { GST_LOG_OBJECT (payload, "Clipped pts, using base RTP timestamp"); rtime = 0; } else { GST_LOG_OBJECT (payload, "Using running_time %" GST_TIME_FORMAT " for RTP timestamp", GST_TIME_ARGS (rtime)); rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND); priv->base_offset = data.offset; priv->base_rtime = rtime; } /* add running_time in clock-rate units to the base timestamp */ data.rtptime = payload->ts_base + rtime; } else { GST_LOG_OBJECT (payload, "Using previous RTP timestamp %" G_GUINT32_FORMAT, payload->timestamp); /* no timestamp to convert, take previous timestamp */ data.rtptime = payload->timestamp; } /* set ssrc, payload type, seq number, caps and rtptime */ if (is_list) { gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), set_headers, &data); } else { GstBuffer *buf = GST_BUFFER_CAST (obj); set_headers (&buf, 0, &data); } priv->next_seqnum = data.seqnum; payload->timestamp = data.rtptime; GST_LOG_OBJECT (payload, "Preparing to push packet with size %" G_GSIZE_FORMAT ", seq=%d, rtptime=%u, pts %" GST_TIME_FORMAT, (is_list) ? -1 : gst_buffer_get_size (GST_BUFFER (obj)), payload->seqnum, data.rtptime, GST_TIME_ARGS (data.pts)); if (g_atomic_int_compare_and_exchange (&payload-> priv->notified_first_timestamp, 1, 0)) { g_object_notify (G_OBJECT (payload), "timestamp"); g_object_notify (G_OBJECT (payload), "seqnum"); } return GST_FLOW_OK; /* ERRORS */ no_rate: { GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL), ("subclass did not specify clock-rate")); return GST_FLOW_ERROR; } }
/** * gst_app_sink_pull_buffer_list: * @appsink: a #GstAppSink * * This function blocks until a buffer list or EOS becomes available or the * appsink element is set to the READY/NULL state. * * This function will only return buffer lists when the appsink is in the * PLAYING state. All rendered buffer lists will be put in a queue so that * the application can pull buffer lists at its own rate. Note that when * the application does not pull buffer lists fast enough, the queued buffer * lists could consume a lot of memory, especially when dealing with raw * video frames. * * If an EOS event was received before any buffer lists, this function returns * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. * * Returns: a #GstBufferList or NULL when the appsink is stopped or EOS. */ EXPORT_C GstBufferList * gst_app_sink_pull_buffer_list (GstAppSink * appsink) { GST_DEBUG_OBJECT (appsink, "pull a buffer list"); return GST_BUFFER_LIST_CAST (gst_app_sink_pull_object (appsink)); }