static GstPad * gst_output_selector_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * name, const GstCaps * caps) { gchar *padname; GstPad *srcpad; GstOutputSelector *osel; osel = GST_OUTPUT_SELECTOR (element); GST_DEBUG_OBJECT (osel, "requesting pad"); GST_OBJECT_LOCK (osel); padname = g_strdup_printf ("src_%u", osel->nb_srcpads++); srcpad = gst_pad_new_from_template (templ, padname); GST_OBJECT_UNLOCK (osel); gst_pad_set_active (srcpad, TRUE); /* Forward sticky events to the new srcpad */ gst_pad_sticky_events_foreach (osel->sinkpad, forward_sticky_events, srcpad); gst_element_add_pad (GST_ELEMENT (osel), srcpad); /* Set the first requested src pad as active by default */ if (osel->active_srcpad == NULL) { osel->active_srcpad = srcpad; } g_free (padname); return srcpad; }
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 void update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media) { GstPad *src_pad; src_pad = gst_rtsp_stream_get_srcpad (stream); gst_pad_sticky_events_foreach (src_pad, get_info_from_tags, stream_media); gst_object_unref (src_pad); }
static gboolean gst_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstFunnel *funnel = GST_FUNNEL (parent); GstFunnelPad *fpad = GST_FUNNEL_PAD_CAST (pad); gboolean forward = TRUE; gboolean res = TRUE; gboolean unlock = FALSE; GST_DEBUG_OBJECT (pad, "received event %" GST_PTR_FORMAT, event); if (GST_EVENT_IS_STICKY (event)) { unlock = TRUE; GST_PAD_STREAM_LOCK (funnel->srcpad); if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { GST_OBJECT_LOCK (funnel); fpad->got_eos = TRUE; if (!gst_funnel_all_sinkpads_eos_unlocked (funnel, pad)) { forward = FALSE; } else { forward = TRUE; } GST_OBJECT_UNLOCK (funnel); } else if (pad != funnel->last_sinkpad) { forward = FALSE; } } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) { unlock = TRUE; GST_PAD_STREAM_LOCK (funnel->srcpad); GST_OBJECT_LOCK (funnel); fpad->got_eos = FALSE; GST_OBJECT_UNLOCK (funnel); } else if (GST_EVENT_TYPE (event) == GST_EVENT_GAP) { /* If no data is coming and we receive GAP event, need to forward sticky events. */ unlock = TRUE; GST_PAD_STREAM_LOCK (funnel->srcpad); GST_OBJECT_LOCK (funnel); gst_object_replace ((GstObject **) & funnel->last_sinkpad, GST_OBJECT (pad)); GST_OBJECT_UNLOCK (funnel); gst_pad_sticky_events_foreach (pad, forward_events, funnel->srcpad); } if (forward) res = gst_pad_push_event (funnel->srcpad, event); else gst_event_unref (event); if (unlock) GST_PAD_STREAM_UNLOCK (funnel->srcpad); return res; }
static void restart_context (MqStreamCtx * ctx, GstSplitMuxSink * splitmux) { GstPad *peer = gst_pad_get_peer (ctx->srcpad); gst_pad_sticky_events_foreach (ctx->srcpad, (GstPadStickyEventsForeachFunction) (resend_sticky), peer); /* Clear EOS flag */ ctx->out_eos = FALSE; gst_object_unref (peer); }
static void gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps) { GstPad *pad; guint i; for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&self->audio_info); i++) { gchar *name = g_strdup_printf ("src_%u", i); GstCaps *srccaps; GstAudioInfo info; GstAudioFormat format = GST_AUDIO_INFO_FORMAT (&self->audio_info); gint rate = GST_AUDIO_INFO_RATE (&self->audio_info); GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_MONO; CopyStickyEventsData data; /* Set channel position if we know it */ if (self->keep_positions) position = GST_AUDIO_INFO_POSITION (&self->audio_info, i); gst_audio_info_init (&info); gst_audio_info_set_format (&info, format, rate, 1, &position); srccaps = gst_audio_info_to_caps (&info); pad = gst_pad_new_from_static_template (&src_template, name); g_free (name); gst_pad_use_fixed_caps (pad); gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_deinterleave_src_query)); gst_pad_set_active (pad, TRUE); data.pad = pad; data.caps = srccaps; gst_pad_sticky_events_foreach (self->sink, copy_sticky_events, &data); if (data.caps) gst_pad_set_caps (pad, data.caps); gst_element_add_pad (GST_ELEMENT (self), pad); self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad)); gst_caps_unref (srccaps); } gst_element_no_more_pads (GST_ELEMENT (self)); self->srcpads = g_list_reverse (self->srcpads); }
static void forward_initial_events (GstRtpSsrcDemux * demux, guint32 ssrc, GstPad * pad, PadType padtype) { struct ForwardStickyEventData fdata; GstPad *sinkpad = NULL; if (padtype == RTP_PAD) sinkpad = demux->rtp_sink; else if (padtype == RTCP_PAD) sinkpad = demux->rtcp_sink; else g_assert_not_reached (); fdata.ssrc = ssrc; fdata.pad = pad; gst_pad_sticky_events_foreach (sinkpad, forward_sticky_events, &fdata); }
static GstPad * gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * name_templ, const GstCaps * caps) { gchar *name; GstPad *srcpad; GstTee *tee; GstPadMode mode; gboolean res; guint index = 0; tee = GST_TEE (element); GST_DEBUG_OBJECT (tee, "requesting pad"); GST_OBJECT_LOCK (tee); if (name_templ) { sscanf (name_templ, "src_%u", &index); GST_LOG_OBJECT (element, "name: %s (index %d)", name_templ, index); if (g_hash_table_contains (tee->pad_indexes, GUINT_TO_POINTER (index))) { GST_ERROR_OBJECT (element, "pad name %s is not unique", name_templ); GST_OBJECT_UNLOCK (tee); return NULL; } if (index >= tee->next_pad_index) tee->next_pad_index = index + 1; } else { index = tee->next_pad_index; while (g_hash_table_contains (tee->pad_indexes, GUINT_TO_POINTER (index))) index++; tee->next_pad_index = index + 1; } g_hash_table_insert (tee->pad_indexes, GUINT_TO_POINTER (index), NULL); name = g_strdup_printf ("src_%u", index); srcpad = GST_PAD_CAST (g_object_new (GST_TYPE_TEE_PAD, "name", name, "direction", templ->direction, "template", templ, NULL)); GST_TEE_PAD_CAST (srcpad)->index = index; g_free (name); mode = tee->sink_mode; GST_OBJECT_UNLOCK (tee); switch (mode) { case GST_PAD_MODE_PULL: /* we already have a src pad in pull mode, and our pull mode can only be SINGLE, so fall through to activate this new pad in push mode */ case GST_PAD_MODE_PUSH: res = gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE); break; default: res = TRUE; break; } if (!res) goto activate_failed; gst_pad_set_activatemode_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_src_activate_mode)); gst_pad_set_query_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_src_query)); gst_pad_set_getrange_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_src_get_range)); /* Forward sticky events to the new srcpad */ gst_pad_sticky_events_foreach (tee->sinkpad, forward_sticky_events, srcpad); GST_OBJECT_FLAG_SET (srcpad, GST_PAD_FLAG_PROXY_CAPS); gst_element_add_pad (GST_ELEMENT_CAST (tee), srcpad); return srcpad; /* ERRORS */ activate_failed: { gboolean changed = FALSE; GST_OBJECT_LOCK (tee); GST_DEBUG_OBJECT (tee, "warning failed to activate request pad"); if (tee->allocpad == srcpad) { tee->allocpad = NULL; changed = TRUE; } GST_OBJECT_UNLOCK (tee); gst_object_unref (srcpad); if (changed) { gst_tee_notify_alloc_pad (tee); } return NULL; } }
static void gst_valve_repush_sticky (GstValve * valve) { valve->need_repush_sticky = FALSE; gst_pad_sticky_events_foreach (valve->sinkpad, forward_sticky_events, valve); }
static gboolean gst_output_selector_switch (GstOutputSelector * osel) { gboolean res = FALSE; GstEvent *ev = NULL; GstSegment *seg = NULL; GstPad *active_srcpad; /* Switch */ GST_OBJECT_LOCK (osel); GST_INFO_OBJECT (osel, "switching to pad %" GST_PTR_FORMAT, osel->pending_srcpad); if (!osel->pending_srcpad) { GST_OBJECT_UNLOCK (osel); return TRUE; } if (gst_pad_is_linked (osel->pending_srcpad)) { osel->active_srcpad = osel->pending_srcpad; res = TRUE; } gst_object_unref (osel->pending_srcpad); osel->pending_srcpad = NULL; active_srcpad = res ? gst_object_ref (osel->active_srcpad) : NULL; GST_OBJECT_UNLOCK (osel); /* Send SEGMENT event and latest buffer if switching succeeded * and we already have a valid segment configured */ if (res) { GstBuffer *latest_buffer; g_object_notify (G_OBJECT (osel), "active-pad"); GST_OBJECT_LOCK (osel); latest_buffer = osel->latest_buffer ? gst_buffer_ref (osel->latest_buffer) : NULL; GST_OBJECT_UNLOCK (osel); gst_pad_sticky_events_foreach (osel->sinkpad, forward_sticky_events, active_srcpad); /* update segment if required */ if (osel->segment.format != GST_FORMAT_UNDEFINED) { /* Send SEGMENT to the pad we are going to switch to */ seg = &osel->segment; /* If resending then mark segment start and position accordingly */ if (osel->resend_latest && latest_buffer && GST_BUFFER_TIMESTAMP_IS_VALID (latest_buffer)) { seg->position = GST_BUFFER_TIMESTAMP (latest_buffer); } ev = gst_event_new_segment (seg); if (!gst_pad_push_event (active_srcpad, ev)) { GST_WARNING_OBJECT (osel, "newsegment handling failed in %" GST_PTR_FORMAT, active_srcpad); } } /* Resend latest buffer to newly switched pad */ if (osel->resend_latest && latest_buffer) { GST_INFO ("resending latest buffer"); gst_pad_push (active_srcpad, latest_buffer); } else if (latest_buffer) { gst_buffer_unref (latest_buffer); } gst_object_unref (active_srcpad); } else { GST_WARNING_OBJECT (osel, "switch failed, pad not linked"); } return res; }
static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstRtpPtDemux *rtpdemux; guint8 pt; GstPad *srcpad; GstCaps *caps; GstRTPBuffer rtp = { NULL }; rtpdemux = GST_RTP_PT_DEMUX (parent); if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp)) goto invalid_buffer; pt = gst_rtp_buffer_get_payload_type (&rtp); gst_rtp_buffer_unmap (&rtp); GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt); srcpad = find_pad_for_pt (rtpdemux, pt); if (srcpad == NULL) { /* new PT, create a src pad */ GstRtpPtDemuxPad *rtpdemuxpad; GstElementClass *klass; GstPadTemplate *templ; gchar *padname; caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; klass = GST_ELEMENT_GET_CLASS (rtpdemux); templ = gst_element_class_get_pad_template (klass, "src_%u"); padname = g_strdup_printf ("src_%u", pt); srcpad = gst_pad_new_from_template (templ, padname); gst_pad_use_fixed_caps (srcpad); g_free (padname); gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event); GST_DEBUG ("Adding pt=%d to the list.", pt); rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad); rtpdemuxpad->pt = pt; rtpdemuxpad->newcaps = FALSE; rtpdemuxpad->pad = srcpad; gst_object_ref (srcpad); GST_OBJECT_LOCK (rtpdemux); rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad); GST_OBJECT_UNLOCK (rtpdemux); gst_pad_set_active (srcpad, TRUE); /* First push the stream-start event, it must always come first */ gst_pad_push_event (srcpad, gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0)); /* Then caps event is sent */ caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); /* First sticky events on sink pad are forwarded to the new src pad */ gst_pad_sticky_events_foreach (rtpdemux->sink, forward_sticky_events, srcpad); gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad); GST_DEBUG ("emitting new-payload-type for pt %d", pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad); } if (pt != rtpdemux->last_pt) { gint emit_pt = pt; /* our own signal with an extra flag that this is the only pad */ rtpdemux->last_pt = pt; GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt); } while (need_caps_for_pt (rtpdemux, pt)) { GST_DEBUG ("need new caps for %d", pt); caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; clear_newcaps_for_pt (rtpdemux, pt); caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); } /* push to srcpad */ ret = gst_pad_push (srcpad, buf); gst_object_unref (srcpad); return ret; /* ERRORS */ invalid_buffer: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL), ("Dropping invalid RTP payload")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } no_caps: { GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL), ("Could not get caps for payload")); gst_buffer_unref (buf); if (srcpad) gst_object_unref (srcpad); return GST_FLOW_ERROR; } }
static gboolean activate_session (GstRDTManager * rdtmanager, GstRDTManagerSession * session, guint32 ssrc, guint8 pt) { GstPadTemplate *templ; GstElementClass *klass; gchar *name; GstCaps *caps; GValue ret = { 0 }; GValue args[3] = { {0} , {0} , {0} }; GST_DEBUG_OBJECT (rdtmanager, "creating stream"); session->ssrc = ssrc; session->pt = pt; /* get pt map */ g_value_init (&args[0], GST_TYPE_ELEMENT); g_value_set_object (&args[0], rdtmanager); g_value_init (&args[1], G_TYPE_UINT); g_value_set_uint (&args[1], session->id); g_value_init (&args[2], G_TYPE_UINT); g_value_set_uint (&args[2], pt); g_value_init (&ret, GST_TYPE_CAPS); g_value_set_boxed (&ret, NULL); g_signal_emitv (args, gst_rdt_manager_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret); g_value_unset (&args[0]); g_value_unset (&args[1]); g_value_unset (&args[2]); caps = (GstCaps *) g_value_dup_boxed (&ret); g_value_unset (&ret); if (caps) gst_rdt_manager_parse_caps (rdtmanager, session, caps); name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt); klass = GST_ELEMENT_GET_CLASS (rdtmanager); templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u"); session->recv_rtp_src = gst_pad_new_from_template (templ, name); g_free (name); gst_pad_set_element_private (session->recv_rtp_src, session); gst_pad_set_query_function (session->recv_rtp_src, gst_rdt_manager_query_src); gst_pad_set_activatemode_function (session->recv_rtp_src, gst_rdt_manager_src_activate_mode); gst_pad_set_active (session->recv_rtp_src, TRUE); gst_pad_sticky_events_foreach (session->recv_rtp_sink, forward_sticky_events, session->recv_rtp_src); gst_pad_set_caps (session->recv_rtp_src, caps); gst_caps_unref (caps); gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->recv_rtp_src); return TRUE; }
static gboolean gst_streamid_demux_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; GstStreamidDemux *demux; const gchar *stream_id = NULL; GstPad *active_srcpad = NULL; demux = GST_STREAMID_DEMUX (parent); GST_DEBUG_OBJECT (demux, "event = %s, sticky = %d", GST_EVENT_TYPE_NAME (event), GST_EVENT_IS_STICKY (event)); if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START) { gst_event_parse_stream_start (event, &stream_id); if (!stream_id) goto no_stream_id; GST_OBJECT_LOCK (demux); active_srcpad = gst_streamid_demux_get_srcpad_by_stream_id (demux, stream_id); if (!active_srcpad) { /* try to generate a srcpad */ if (gst_streamid_demux_srcpad_create (demux, pad, stream_id)) { GST_OBJECT_UNLOCK (demux); gst_pad_set_active (demux->active_srcpad, TRUE); /* Forward sticky events to the new srcpad */ gst_pad_sticky_events_foreach (demux->sinkpad, forward_sticky_events, demux->active_srcpad); gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->active_srcpad); } else { GST_OBJECT_UNLOCK (demux); goto fail_create_srcpad; } } else if (demux->active_srcpad != active_srcpad) { demux->active_srcpad = active_srcpad; GST_OBJECT_UNLOCK (demux); g_object_notify (G_OBJECT (demux), "active-pad"); } else GST_OBJECT_UNLOCK (demux); } if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START || GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP || GST_EVENT_TYPE (event) == GST_EVENT_EOS) { res = gst_pad_event_default (pad, parent, event); } else if (demux->active_srcpad) { GstPad *srcpad = NULL; GST_OBJECT_LOCK (demux); srcpad = gst_object_ref (demux->active_srcpad); GST_OBJECT_UNLOCK (demux); res = gst_pad_push_event (srcpad, event); gst_object_unref (srcpad); } else { gst_event_unref (event); } return res; /* ERRORS */ no_stream_id: { GST_ELEMENT_ERROR (demux, STREAM, DEMUX, ("Error occurred trying to get stream-id to create a srcpad"), ("no stream-id found at %s", GST_EVENT_TYPE_NAME (event))); gst_event_unref (event); return FALSE; } fail_create_srcpad: { GST_ELEMENT_ERROR (demux, STREAM, FAILED, ("Error occurred trying to create a srcpad"), ("Failed to create a srcpad via stream-id:%s", stream_id)); gst_event_unref (event); return FALSE; } }
static GstPad * find_or_create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc, PadType padtype) { GstPad *rtp_pad, *rtcp_pad; GstElementClass *klass; GstPadTemplate *templ; gchar *padname; GstRtpSsrcDemuxPad *demuxpad; GstCaps *caps; struct ForwardEventData fdata; GstPad *retpad; gulong rtp_block, rtcp_block; GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc); GST_PAD_LOCK (demux); demuxpad = find_demux_pad_for_ssrc (demux, ssrc); if (demuxpad != NULL) { switch (padtype) { case RTP_PAD: retpad = gst_object_ref (demuxpad->rtp_pad); break; case RTCP_PAD: retpad = gst_object_ref (demuxpad->rtcp_pad); break; default: retpad = NULL; g_assert_not_reached (); } GST_PAD_UNLOCK (demux); return retpad; } klass = GST_ELEMENT_GET_CLASS (demux); templ = gst_element_class_get_pad_template (klass, "src_%u"); padname = g_strdup_printf ("src_%u", ssrc); rtp_pad = gst_pad_new_from_template (templ, padname); g_free (padname); templ = gst_element_class_get_pad_template (klass, "rtcp_src_%u"); padname = g_strdup_printf ("rtcp_src_%u", ssrc); rtcp_pad = gst_pad_new_from_template (templ, padname); g_free (padname); /* wrap in structure and add to list */ demuxpad = g_new0 (GstRtpSsrcDemuxPad, 1); demuxpad->ssrc = ssrc; demuxpad->rtp_pad = rtp_pad; demuxpad->rtcp_pad = rtcp_pad; fdata.ssrc = ssrc; gst_pad_set_element_private (rtp_pad, demuxpad); gst_pad_set_element_private (rtcp_pad, demuxpad); demux->srcpads = g_slist_prepend (demux->srcpads, demuxpad); gst_pad_set_query_function (rtp_pad, gst_rtp_ssrc_demux_src_query); gst_pad_set_iterate_internal_links_function (rtp_pad, gst_rtp_ssrc_demux_iterate_internal_links_src); gst_pad_set_event_function (rtp_pad, gst_rtp_ssrc_demux_src_event); gst_pad_use_fixed_caps (rtp_pad); gst_pad_set_active (rtp_pad, TRUE); fdata.pad = rtp_pad; gst_pad_sticky_events_foreach (demux->rtp_sink, forward_sticky_events, &fdata); gst_pad_set_event_function (rtcp_pad, gst_rtp_ssrc_demux_src_event); gst_pad_set_iterate_internal_links_function (rtcp_pad, gst_rtp_ssrc_demux_iterate_internal_links_src); gst_pad_use_fixed_caps (rtcp_pad); gst_pad_set_active (rtcp_pad, TRUE); fdata.pad = rtcp_pad; gst_pad_sticky_events_foreach (demux->rtcp_sink, forward_sticky_events, &fdata); /* copy caps from input */ if ((caps = gst_pad_get_current_caps (demux->rtp_sink))) { gst_pad_set_caps (rtp_pad, caps); gst_caps_unref (caps); } if ((caps = gst_pad_get_current_caps (demux->rtcp_sink))) { gst_pad_set_caps (rtcp_pad, caps); gst_caps_unref (caps); } gst_element_add_pad (GST_ELEMENT_CAST (demux), rtp_pad); gst_element_add_pad (GST_ELEMENT_CAST (demux), rtcp_pad); switch (padtype) { case RTP_PAD: retpad = gst_object_ref (demuxpad->rtp_pad); break; case RTCP_PAD: retpad = gst_object_ref (demuxpad->rtcp_pad); break; default: retpad = NULL; g_assert_not_reached (); } gst_object_ref (rtp_pad); gst_object_ref (rtcp_pad); rtp_block = gst_pad_add_probe (rtp_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, NULL, NULL, NULL); rtcp_block = gst_pad_add_probe (rtcp_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, NULL, NULL, NULL); GST_PAD_UNLOCK (demux); g_signal_emit (G_OBJECT (demux), gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD], 0, ssrc, rtp_pad); gst_pad_remove_probe (rtp_pad, rtp_block); gst_pad_remove_probe (rtcp_pad, rtcp_block); gst_object_unref (rtp_pad); gst_object_unref (rtcp_pad); return retpad; }
static GstFlowReturn gst_rtp_mux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstRTPMux *rtp_mux; GstFlowReturn ret; GstRTPMuxPadPrivate *padpriv; gboolean drop; gboolean changed = FALSE; GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; 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_unref (buffer); 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); gst_buffer_unref (buffer); return GST_FLOW_NOT_LINKED; } buffer = gst_buffer_make_writable (buffer); if (!gst_rtp_buffer_map (buffer, GST_MAP_READWRITE, &rtpbuffer)) { GST_OBJECT_UNLOCK (rtp_mux); gst_buffer_unref (buffer); GST_ERROR_OBJECT (rtp_mux, "Invalid RTP buffer"); return GST_FLOW_ERROR; } drop = !process_buffer_locked (rtp_mux, padpriv, &rtpbuffer); gst_rtp_buffer_unmap (&rtpbuffer); if (!drop) { if (pad != rtp_mux->last_pad) { changed = TRUE; g_clear_object (&rtp_mux->last_pad); rtp_mux->last_pad = g_object_ref (pad); } if (GST_BUFFER_DURATION_IS_VALID (buffer) && GST_BUFFER_PTS_IS_VALID (buffer)) rtp_mux->last_stop = GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer); else rtp_mux->last_stop = GST_CLOCK_TIME_NONE; } GST_OBJECT_UNLOCK (rtp_mux); if (changed) gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux); if (drop) { gst_buffer_unref (buffer); ret = GST_FLOW_OK; } else { ret = gst_pad_push (rtp_mux->srcpad, buffer); } out: 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; }
/* with PAD_LOCK */ static GstRtpSsrcDemuxPad * find_or_create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc) { GstPad *rtp_pad, *rtcp_pad; GstElementClass *klass; GstPadTemplate *templ; gchar *padname; GstRtpSsrcDemuxPad *demuxpad; GstCaps *caps; struct ForwardEventData fdata; GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc); demuxpad = find_demux_pad_for_ssrc (demux, ssrc); if (demuxpad != NULL) { return demuxpad; } klass = GST_ELEMENT_GET_CLASS (demux); templ = gst_element_class_get_pad_template (klass, "src_%u"); padname = g_strdup_printf ("src_%u", ssrc); rtp_pad = gst_pad_new_from_template (templ, padname); g_free (padname); templ = gst_element_class_get_pad_template (klass, "rtcp_src_%u"); padname = g_strdup_printf ("rtcp_src_%u", ssrc); rtcp_pad = gst_pad_new_from_template (templ, padname); g_free (padname); /* wrap in structure and add to list */ demuxpad = g_new0 (GstRtpSsrcDemuxPad, 1); demuxpad->ssrc = ssrc; demuxpad->rtp_pad = rtp_pad; demuxpad->rtcp_pad = rtcp_pad; fdata.ssrc = ssrc; gst_pad_set_element_private (rtp_pad, demuxpad); gst_pad_set_element_private (rtcp_pad, demuxpad); demux->srcpads = g_slist_prepend (demux->srcpads, demuxpad); gst_pad_set_query_function (rtp_pad, gst_rtp_ssrc_demux_src_query); gst_pad_set_iterate_internal_links_function (rtp_pad, gst_rtp_ssrc_demux_iterate_internal_links_src); gst_pad_set_event_function (rtp_pad, gst_rtp_ssrc_demux_src_event); gst_pad_use_fixed_caps (rtp_pad); gst_pad_set_active (rtp_pad, TRUE); fdata.pad = rtp_pad; gst_pad_sticky_events_foreach (demux->rtp_sink, forward_sticky_events, &fdata); gst_pad_set_event_function (rtcp_pad, gst_rtp_ssrc_demux_src_event); gst_pad_set_iterate_internal_links_function (rtcp_pad, gst_rtp_ssrc_demux_iterate_internal_links_src); gst_pad_use_fixed_caps (rtcp_pad); gst_pad_set_active (rtcp_pad, TRUE); fdata.pad = rtcp_pad; gst_pad_sticky_events_foreach (demux->rtcp_sink, forward_sticky_events, &fdata); /* copy caps from input */ if ((caps = gst_pad_get_current_caps (demux->rtp_sink))) { gst_pad_set_caps (rtp_pad, caps); gst_caps_unref (caps); } if ((caps = gst_pad_get_current_caps (demux->rtcp_sink))) { gst_pad_set_caps (rtcp_pad, caps); gst_caps_unref (caps); } gst_element_add_pad (GST_ELEMENT_CAST (demux), rtp_pad); gst_element_add_pad (GST_ELEMENT_CAST (demux), rtcp_pad); g_signal_emit (G_OBJECT (demux), gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD], 0, ssrc, rtp_pad); return demuxpad; }