static gboolean gst_rtp_ssrc_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRtpSsrcDemux *demux; const GstStructure *s; demux = GST_RTP_SSRC_DEMUX (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_UPSTREAM: case GST_EVENT_CUSTOM_BOTH: case GST_EVENT_CUSTOM_BOTH_OOB: s = gst_event_get_structure (event); if (s && !gst_structure_has_field (s, "ssrc")) { GstRtpSsrcDemuxPad *dpad = find_demux_pad_for_pad (demux, pad); if (dpad) { GstStructure *ws; event = gst_event_make_writable (event); ws = gst_event_writable_structure (event); gst_structure_set (ws, "ssrc", G_TYPE_UINT, dpad->ssrc, NULL); } } break; default: break; } return gst_pad_event_default (pad, parent, event); }
static GstIterator * gst_rtp_ssrc_demux_iterate_internal_links (GstPad * pad) { GstRtpSsrcDemux *demux; GstPad *otherpad = NULL; GstIterator *it; GSList *current; demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad)); GST_PAD_LOCK (demux); for (current = demux->srcpads; current; current = g_slist_next (current)) { GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) current->data; if (pad == demux->rtp_sink) { otherpad = dpad->rtp_pad; break; } else if (pad == demux->rtcp_sink) { otherpad = dpad->rtcp_pad; } else if (pad == dpad->rtp_pad) { otherpad = demux->rtp_sink; break; } else if (pad == dpad->rtcp_pad) { otherpad = demux->rtcp_sink; break; } } it = gst_iterator_new_single (GST_TYPE_PAD, otherpad, (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref); GST_PAD_UNLOCK (demux); gst_object_unref (demux); return it; }
static GstIterator * gst_rtp_ssrc_demux_iterate_internal_links_src (GstPad * pad, GstObject * parent) { GstRtpSsrcDemux *demux; GstPad *otherpad = NULL; GstIterator *it = NULL; GSList *current; demux = GST_RTP_SSRC_DEMUX (parent); GST_PAD_LOCK (demux); for (current = demux->srcpads; current; current = g_slist_next (current)) { GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) current->data; if (pad == dpad->rtp_pad) { otherpad = demux->rtp_sink; break; } else if (pad == dpad->rtcp_pad) { otherpad = demux->rtcp_sink; break; } } if (otherpad) { GValue val = { 0, }; g_value_init (&val, GST_TYPE_PAD); g_value_set_object (&val, otherpad); it = gst_iterator_new_single (GST_TYPE_PAD, &val); g_value_unset (&val); } GST_PAD_UNLOCK (demux); return it; }
static GstStateChangeReturn gst_rtp_ssrc_demux_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstRtpSsrcDemux *demux; demux = GST_RTP_SSRC_DEMUX (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_PAUSED_TO_PLAYING: default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: gst_rtp_ssrc_demux_reset (demux); break; case GST_STATE_CHANGE_READY_TO_NULL: default: break; } return ret; }
static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn ret; GstRtpSsrcDemux *demux; guint32 ssrc; GstRTPBuffer rtp = { NULL }; GstPad *srcpad; GstRtpSsrcDemuxPad *dpad; demux = GST_RTP_SSRC_DEMUX (parent); if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp)) goto invalid_payload; ssrc = gst_rtp_buffer_get_ssrc (&rtp); gst_rtp_buffer_unmap (&rtp); GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc); srcpad = find_or_create_demux_pad_for_ssrc (demux, ssrc, RTP_PAD); if (srcpad == NULL) goto create_failed; /* push to srcpad */ ret = gst_pad_push (srcpad, buf); if (ret != GST_FLOW_OK) { /* check if the ssrc still there, may have been removed */ GST_PAD_LOCK (demux); dpad = find_demux_pad_for_ssrc (demux, ssrc); if (dpad == NULL || dpad->rtp_pad != srcpad) { /* SSRC was removed during the push ... ignore the error */ ret = GST_FLOW_OK; } GST_PAD_UNLOCK (demux); } gst_object_unref (srcpad); return ret; /* ERRORS */ invalid_payload: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Dropping invalid RTP payload")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } create_failed: { GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Could not create new pad")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }
static void gst_rtp_ssrc_demux_finalize (GObject * object) { GstRtpSsrcDemux *demux; demux = GST_RTP_SSRC_DEMUX (object); g_rec_mutex_clear (&demux->padlock); G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gst_rtp_ssrc_demux_dispose (GObject * object) { GstRtpSsrcDemux *demux; demux = GST_RTP_SSRC_DEMUX (object); gst_rtp_ssrc_demux_reset (demux); G_OBJECT_CLASS (parent_class)->dispose (object); }
static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRtpSsrcDemux *demux; gboolean res = FALSE; demux = GST_RTP_SSRC_DEMUX (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED); /* fallthrough */ default: { GSList *walk; GSList *pads = NULL; res = TRUE; /* need local snapshot of pads; * should not push downstream while holding lock as that might deadlock * with stuff traveling upstream tyring to get this lock while holding * other (stream)lock */ GST_PAD_LOCK (demux); for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) { GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data; pad = g_slice_dup (GstRtpSsrcDemuxPad, pad); gst_object_ref (pad->rtp_pad); pads = g_slist_prepend (pads, pad); } GST_PAD_UNLOCK (demux); for (walk = pads; walk; walk = g_slist_next (walk)) { GstRtpSsrcDemuxPad *dpad = walk->data; GstEvent *newevent; newevent = add_ssrc_and_ref (event, dpad->ssrc); res &= gst_pad_push_event (dpad->rtp_pad, newevent); gst_object_unref (dpad->rtp_pad); g_slice_free (GstRtpSsrcDemuxPad, dpad); } g_slist_free (pads); gst_event_unref (event); break; } } return res; }
static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf) { GstFlowReturn ret; GstRtpSsrcDemux *demux; guint32 ssrc; GstRtpSsrcDemuxPad *dpad; demux = GST_RTP_SSRC_DEMUX (GST_OBJECT_PARENT (pad)); if (!gst_rtp_buffer_validate (buf)) goto invalid_payload; ssrc = gst_rtp_buffer_get_ssrc (buf); GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc); GST_PAD_LOCK (demux); dpad = find_demux_pad_for_ssrc (demux, ssrc); if (dpad == NULL) { if (!(dpad = create_demux_pad_for_ssrc (demux, ssrc, GST_BUFFER_TIMESTAMP (buf)))) goto create_failed; } GST_PAD_UNLOCK (demux); /* push to srcpad */ ret = gst_pad_push (dpad->rtp_pad, buf); return ret; /* ERRORS */ invalid_payload: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Dropping invalid RTP payload")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } create_failed: { GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Could not create new pad")); GST_PAD_UNLOCK (demux); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn ret; GstRtpSsrcDemux *demux; guint32 ssrc; GstRTPBuffer rtp = { NULL }; GstPad *srcpad; demux = GST_RTP_SSRC_DEMUX (parent); if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp)) goto invalid_payload; ssrc = gst_rtp_buffer_get_ssrc (&rtp); gst_rtp_buffer_unmap (&rtp); GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc); srcpad = find_or_create_demux_pad_for_ssrc (demux, ssrc, RTP_PAD); if (srcpad == NULL) goto create_failed; /* push to srcpad */ ret = gst_pad_push (srcpad, buf); gst_object_unref (srcpad); return ret; /* ERRORS */ invalid_payload: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Dropping invalid RTP payload")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } create_failed: { GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Could not create new pad")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }
static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRtpSsrcDemux *demux; struct ForwardEventData fdata; demux = GST_RTP_SSRC_DEMUX (parent); fdata.demux = demux; fdata.pad = pad; fdata.event = event; fdata.res = TRUE; gst_pad_forward (pad, forward_event, &fdata); gst_event_unref (event); return fdata.res; }
static gboolean gst_rtp_ssrc_demux_rtcp_sink_event (GstPad * pad, GstEvent * event) { GstRtpSsrcDemux *demux; gboolean res = FALSE; demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT: default: { GSList *walk; GSList *pads = NULL; res = TRUE; GST_PAD_LOCK (demux); for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) { GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data; pads = g_slist_prepend (pads, gst_object_ref (pad->rtcp_pad)); } GST_PAD_UNLOCK (demux); for (walk = pads; walk; walk = g_slist_next (walk)) { GstPad *pad = (GstPad *) walk->data; gst_event_ref (event); res &= gst_pad_push_event (pad, event); gst_object_unref (pad); } g_slist_free (pads); gst_event_unref (event); break; } } gst_object_unref (demux); return res; }
static gboolean gst_rtp_ssrc_demux_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstRtpSsrcDemux *demux; gboolean res = FALSE; demux = GST_RTP_SSRC_DEMUX (parent); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { if ((res = gst_pad_peer_query (demux->rtp_sink, query))) { gboolean live; GstClockTime min_latency, max_latency; GstRtpSsrcDemuxPad *demuxpad; demuxpad = gst_pad_get_element_private (pad); gst_query_parse_latency (query, &live, &min_latency, &max_latency); GST_DEBUG_OBJECT (demux, "peer min latency %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency)); GST_DEBUG_OBJECT (demux, "latency for SSRC %08x", demuxpad->ssrc); gst_query_set_latency (query, live, min_latency, max_latency); } break; } default: res = gst_pad_query_default (pad, parent, query); break; } return res; }
static gboolean gst_rtp_ssrc_demux_src_event (GstPad * pad, GstEvent * event) { GstRtpSsrcDemux *demux; const GstStructure *s; demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_UPSTREAM: case GST_EVENT_CUSTOM_BOTH: case GST_EVENT_CUSTOM_BOTH_OOB: s = gst_event_get_structure (event); if (s && !gst_structure_has_field (s, "ssrc")) { GSList *walk; for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) { GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) walk->data; if (dpad->rtp_pad == pad || dpad->rtcp_pad == pad) { event = GST_EVENT_CAST (gst_mini_object_make_writable (GST_MINI_OBJECT_CAST (event))); gst_structure_set (event->structure, "ssrc", G_TYPE_UINT, dpad->ssrc, NULL); break; } } } break; default: break; } gst_object_unref (demux); return gst_pad_event_default (pad, event); }
static GstIterator * gst_rtp_ssrc_demux_iterate_internal_links_sink (GstPad * pad, GstObject * parent) { GstRtpSsrcDemux *demux; GstIterator *it = NULL; GValue gval = { 0, }; demux = GST_RTP_SSRC_DEMUX (parent); g_value_init (&gval, G_TYPE_STRING); if (pad == demux->rtp_sink) g_value_set_static_string (&gval, "src_"); else if (pad == demux->rtcp_sink) g_value_set_static_string (&gval, "rtcp_src_"); else g_assert_not_reached (); it = gst_element_iterate_src_pads (GST_ELEMENT_CAST (demux)); it = gst_iterator_filter (it, src_pad_compare_func, &gval); return it; }
static gboolean gst_rtp_ssrc_demux_rtcp_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRtpSsrcDemux *demux; gboolean res = TRUE; GSList *walk; GSList *pads = NULL; demux = GST_RTP_SSRC_DEMUX (parent); GST_PAD_LOCK (demux); for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) { GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data; pad = g_slice_dup (GstRtpSsrcDemuxPad, pad); gst_object_ref (pad->rtcp_pad); pads = g_slist_prepend (pads, pad); } GST_PAD_UNLOCK (demux); for (walk = pads; walk; walk = g_slist_next (walk)) { GstRtpSsrcDemuxPad *dpad = walk->data; GstEvent *newevent; newevent = add_ssrc_and_ref (event, dpad->ssrc); res &= gst_pad_push_event (dpad->rtcp_pad, newevent); gst_object_unref (dpad->rtcp_pad); g_slice_free (GstRtpSsrcDemuxPad, dpad); } g_slist_free (pads); gst_event_unref (event); return res; }
static GstFlowReturn gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn ret; GstRtpSsrcDemux *demux; guint32 ssrc; GstRTCPPacket packet; GstRTCPBuffer rtcp = { NULL, }; GstPad *srcpad; GstRtpSsrcDemuxPad *dpad; demux = GST_RTP_SSRC_DEMUX (parent); if (!gst_rtcp_buffer_validate_reduced (buf)) goto invalid_rtcp; gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp); if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) { gst_rtcp_buffer_unmap (&rtcp); goto invalid_rtcp; } /* first packet must be SR or RR, or in case of a reduced size RTCP packet * it must be APP, RTPFB or PSFB feeadback, or else the validate would * have failed */ switch (gst_rtcp_packet_get_type (&packet)) { case GST_RTCP_TYPE_SR: /* get the ssrc so that we can route it to the right source pad */ gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL, NULL); break; case GST_RTCP_TYPE_RR: ssrc = gst_rtcp_packet_rr_get_ssrc (&packet); break; case GST_RTCP_TYPE_APP: case GST_RTCP_TYPE_RTPFB: case GST_RTCP_TYPE_PSFB: ssrc = gst_rtcp_packet_fb_get_sender_ssrc (&packet); break; default: goto unexpected_rtcp; } gst_rtcp_buffer_unmap (&rtcp); GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc); srcpad = find_or_create_demux_pad_for_ssrc (demux, ssrc, RTCP_PAD); if (srcpad == NULL) goto create_failed; /* push to srcpad */ ret = gst_pad_push (srcpad, buf); if (ret != GST_FLOW_OK) { /* check if the ssrc still there, may have been removed */ GST_PAD_LOCK (demux); dpad = find_demux_pad_for_ssrc (demux, ssrc); if (dpad == NULL || dpad->rtcp_pad != srcpad) { /* SSRC was removed during the push ... ignore the error */ ret = GST_FLOW_OK; } GST_PAD_UNLOCK (demux); } gst_object_unref (srcpad); return ret; /* ERRORS */ invalid_rtcp: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Dropping invalid RTCP packet")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } unexpected_rtcp: { GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet"); gst_buffer_unref (buf); return GST_FLOW_OK; } create_failed: { GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Could not create new pad")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn ret; GstRtpSsrcDemux *demux; guint32 ssrc; GstRtpSsrcDemuxPad *dpad; GstRTCPPacket packet; GstRTCPBuffer rtcp = { NULL, }; GstPad *srcpad; demux = GST_RTP_SSRC_DEMUX (parent); if (!gst_rtcp_buffer_validate (buf)) goto invalid_rtcp; gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp); if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) { gst_rtcp_buffer_unmap (&rtcp); goto invalid_rtcp; } /* first packet must be SR or RR or else the validate would have failed */ switch (gst_rtcp_packet_get_type (&packet)) { case GST_RTCP_TYPE_SR: /* get the ssrc so that we can route it to the right source pad */ gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL, NULL); break; default: goto unexpected_rtcp; } gst_rtcp_buffer_unmap (&rtcp); GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc); GST_PAD_LOCK (demux); dpad = find_or_create_demux_pad_for_ssrc (demux, ssrc); if (dpad == NULL) { GST_PAD_UNLOCK (demux); goto create_failed; } srcpad = gst_object_ref (dpad->rtcp_pad); GST_PAD_UNLOCK (demux); /* push to srcpad */ ret = gst_pad_push (srcpad, buf); gst_object_unref (srcpad); return ret; /* ERRORS */ invalid_rtcp: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Dropping invalid RTCP packet")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } unexpected_rtcp: { GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet"); gst_buffer_unref (buf); return GST_FLOW_OK; } create_failed: { GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), ("Could not create new pad")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }