summaryrefslogtreecommitdiffstats
path: root/gst/rtpmanager/gstrtpssrcdemux.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/rtpmanager/gstrtpssrcdemux.c')
-rw-r--r--gst/rtpmanager/gstrtpssrcdemux.c210
1 files changed, 184 insertions, 26 deletions
diff --git a/gst/rtpmanager/gstrtpssrcdemux.c b/gst/rtpmanager/gstrtpssrcdemux.c
index 539b03c7..5457bc35 100644
--- a/gst/rtpmanager/gstrtpssrcdemux.c
+++ b/gst/rtpmanager/gstrtpssrcdemux.c
@@ -52,6 +52,7 @@
#include <string.h>
#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
#include "gstrtpbin-marshal.h"
#include "gstrtpssrcdemux.h"
@@ -67,6 +68,13 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_STATIC_CAPS ("application/x-rtp")
);
+static GstStaticPadTemplate rtp_ssrc_demux_rtcp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtcp")
+ );
+
static GstStaticPadTemplate rtp_ssrc_demux_src_template =
GST_STATIC_PAD_TEMPLATE ("src_%d",
GST_PAD_SRC,
@@ -74,6 +82,13 @@ GST_STATIC_PAD_TEMPLATE ("src_%d",
GST_STATIC_CAPS ("application/x-rtp")
);
+static GstStaticPadTemplate rtp_ssrc_demux_rtcp_src_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("application/x-rtcp")
+ );
+
static GstElementDetails gst_rtp_ssrc_demux_details = {
"RTP SSRC Demux",
"Demux/Network/RTP",
@@ -103,6 +118,11 @@ static GstStateChangeReturn gst_rtp_ssrc_demux_change_state (GstElement *
static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad,
+ GstBuffer * buf);
+static gboolean gst_rtp_ssrc_demux_rtcp_sink_event (GstPad * pad,
+ GstEvent * event);
+
/* srcpad stuff */
static gboolean gst_rtp_ssrc_demux_src_event (GstPad * pad, GstEvent * event);
@@ -113,59 +133,78 @@ static guint gst_rtp_ssrc_demux_signals[LAST_SIGNAL] = { 0 };
*/
struct _GstRtpSsrcDemuxPad
{
- GstPad *pad;
guint32 ssrc;
+ GstPad *rtp_pad;
GstCaps *caps;
+ GstPad *rtcp_pad;
};
/* find a src pad for a given SSRC, returns NULL if the SSRC was not found
*/
-static GstPad *
-find_rtp_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
+static GstRtpSsrcDemuxPad *
+find_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
{
GSList *walk;
- for (walk = demux->rtp_srcpads; walk; walk = g_slist_next (walk)) {
+ for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;
if (pad->ssrc == ssrc)
- return pad->pad;
+ return pad;
}
return NULL;
}
-static GstPad *
-create_rtp_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
+static GstRtpSsrcDemuxPad *
+create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
{
- GstPad *result;
+ GstPad *rtp_pad, *rtcp_pad;
GstElementClass *klass;
GstPadTemplate *templ;
gchar *padname;
GstRtpSsrcDemuxPad *demuxpad;
+ GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc);
+
klass = GST_ELEMENT_GET_CLASS (demux);
templ = gst_element_class_get_pad_template (klass, "src_%d");
padname = g_strdup_printf ("src_%d", ssrc);
- result = gst_pad_new_from_template (templ, padname);
+ rtp_pad = gst_pad_new_from_template (templ, padname);
+ g_free (padname);
+
+ templ = gst_element_class_get_pad_template (klass, "rtcp_src_%d");
+ padname = g_strdup_printf ("rtcp_src_%d", 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->pad = result;
- demux->rtp_srcpads = g_slist_prepend (demux->rtp_srcpads, demuxpad);
+ demuxpad->rtp_pad = rtp_pad;
+ demuxpad->rtcp_pad = rtcp_pad;
+
+ demux->srcpads = g_slist_prepend (demux->srcpads, demuxpad);
+ GST_OBJECT_UNLOCK (demux);
/* copy caps from input */
- gst_pad_set_caps (result, GST_PAD_CAPS (demux->rtp_sink));
+ gst_pad_set_caps (rtp_pad, GST_PAD_CAPS (demux->rtp_sink));
+ gst_pad_use_fixed_caps (rtp_pad);
+ gst_pad_set_caps (rtcp_pad, GST_PAD_CAPS (demux->rtcp_sink));
+ gst_pad_use_fixed_caps (rtcp_pad);
- gst_pad_set_event_function (result, gst_rtp_ssrc_demux_src_event);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (demux), result);
+ gst_pad_set_event_function (rtp_pad, gst_rtp_ssrc_demux_src_event);
+ gst_pad_set_active (rtp_pad, TRUE);
+ gst_pad_set_active (rtcp_pad, TRUE);
+
+ 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, result);
+ gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD], 0, ssrc, rtp_pad);
+
+ GST_OBJECT_LOCK (demux);
- return result;
+ return demuxpad;
}
static void
@@ -176,7 +215,11 @@ gst_rtp_ssrc_demux_base_init (gpointer g_class)
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&rtp_ssrc_demux_sink_template));
gst_element_class_add_pad_template (gstelement_klass,
+ gst_static_pad_template_get (&rtp_ssrc_demux_rtcp_sink_template));
+ gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&rtp_ssrc_demux_src_template));
+ gst_element_class_add_pad_template (gstelement_klass,
+ gst_static_pad_template_get (&rtp_ssrc_demux_rtcp_src_template));
gst_element_class_set_details (gstelement_klass, &gst_rtp_ssrc_demux_details);
}
@@ -226,6 +269,14 @@ gst_rtp_ssrc_demux_init (GstRtpSsrcDemux * demux,
gst_pad_set_chain_function (demux->rtp_sink, gst_rtp_ssrc_demux_chain);
gst_pad_set_event_function (demux->rtp_sink, gst_rtp_ssrc_demux_sink_event);
gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->rtp_sink);
+
+ demux->rtcp_sink =
+ gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+ "rtcp_sink"), "rtcp_sink");
+ gst_pad_set_chain_function (demux->rtcp_sink, gst_rtp_ssrc_demux_rtcp_chain);
+ gst_pad_set_event_function (demux->rtcp_sink,
+ gst_rtp_ssrc_demux_rtcp_sink_event);
+ gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->rtcp_sink);
}
static void
@@ -249,21 +300,63 @@ gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT:
default:
- res = gst_pad_event_default (pad, event);
+ {
+ GSList *walk;
+
+ res = TRUE;
+ GST_OBJECT_LOCK (demux);
+ for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
+ GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;
+
+ gst_event_ref (event);
+ res &= gst_pad_push_event (pad->rtp_pad, event);
+ }
+ GST_OBJECT_UNLOCK (demux);
+ gst_event_unref (event);
break;
+ }
}
gst_object_unref (demux);
return 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;
+
+ res = TRUE;
+ GST_OBJECT_LOCK (demux);
+ for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
+ GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;
+
+ res &= gst_pad_push_event (pad->rtcp_pad, event);
+ }
+ GST_OBJECT_UNLOCK (demux);
+ break;
+ }
+ }
+ gst_object_unref (demux);
+ return res;
+}
+
static GstFlowReturn
gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf)
{
GstFlowReturn ret;
GstRtpSsrcDemux *demux;
guint32 ssrc;
- GstPad *srcpad;
+ GstRtpSsrcDemuxPad *dpad;
demux = GST_RTP_SSRC_DEMUX (GST_OBJECT_PARENT (pad));
@@ -274,16 +367,16 @@ gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf)
GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc);
- srcpad = find_rtp_pad_for_ssrc (demux, ssrc);
- if (srcpad == NULL) {
- GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc);
- srcpad = create_rtp_pad_for_ssrc (demux, ssrc);
- if (!srcpad)
+ GST_OBJECT_LOCK (demux);
+ dpad = find_demux_pad_for_ssrc (demux, ssrc);
+ if (dpad == NULL) {
+ if (!(dpad = create_demux_pad_for_ssrc (demux, ssrc)))
goto create_failed;
}
+ GST_OBJECT_UNLOCK (demux);
/* push to srcpad */
- ret = gst_pad_push (srcpad, buf);
+ ret = gst_pad_push (dpad->rtp_pad, buf);
return ret;
@@ -298,9 +391,74 @@ invalid_payload:
}
create_failed:
{
- /* this is not fatal yet */
GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
("Could not create new pad"));
+ GST_OBJECT_UNLOCK (demux);
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstFlowReturn ret;
+ GstRtpSsrcDemux *demux;
+ guint32 ssrc;
+ GstRtpSsrcDemuxPad *dpad;
+ GstRTCPPacket packet;
+
+ demux = GST_RTP_SSRC_DEMUX (GST_OBJECT_PARENT (pad));
+
+ if (!gst_rtcp_buffer_validate (buf))
+ goto invalid_rtcp;
+
+ if (!gst_rtcp_buffer_get_first_packet (buf, &packet))
+ 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:
+ 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;
+ default:
+ goto invalid_rtcp;
+ }
+
+ GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);
+
+ GST_OBJECT_LOCK (demux);
+ dpad = find_demux_pad_for_ssrc (demux, ssrc);
+ if (dpad == NULL) {
+ GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc);
+ if (!(dpad = create_demux_pad_for_ssrc (demux, ssrc)))
+ goto create_failed;
+ }
+ GST_OBJECT_UNLOCK (demux);
+
+ /* push to srcpad */
+ ret = gst_pad_push (dpad->rtcp_pad, buf);
+
+ 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;
+ }
+create_failed:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
+ ("Could not create new pad"));
+ GST_OBJECT_UNLOCK (demux);
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}