summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2007-04-06 12:54:16 +0000
committerWim Taymans <wim.taymans@gmail.com>2007-04-06 12:54:16 +0000
commitf80444aaece651265c16121339c65c561ef2e7af (patch)
tree61158f866cd946510626f9b427006162867b9087
parent86b40a1c70dddd25487fc0153dcc29af55a22799 (diff)
gst/rtsp/: Morph RTPDec into something compatible with RTPBin as a fallback.
Original commit message from CVS: * gst/rtsp/Makefile.am: * gst/rtsp/gstrtpdec.c: (find_session_by_id), (create_session), (free_session), (gst_rtp_dec_base_init), (gst_rtp_dec_class_init), (gst_rtp_dec_init), (gst_rtp_dec_finalize), (gst_rtp_dec_query_src), (gst_rtp_dec_chain_rtp), (gst_rtp_dec_chain_rtcp), (gst_rtp_dec_set_property), (gst_rtp_dec_get_property), (gst_rtp_dec_provide_clock), (gst_rtp_dec_change_state), (create_recv_rtp), (create_recv_rtcp), (create_rtcp), (gst_rtp_dec_request_new_pad), (gst_rtp_dec_release_pad): * gst/rtsp/gstrtpdec.h: * gst/rtsp/gstrtsp.c: (plugin_init): Morph RTPDec into something compatible with RTPBin as a fallback. Various other style fixes. * gst/rtsp/gstrtspsrc.c: (find_stream_by_id), (find_stream_by_udpsrc), (gst_rtspsrc_stream_free), (gst_rtspsrc_cleanup), (gst_rtspsrc_media_to_caps), (new_session_pad), (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_loop_udp), (gst_rtspsrc_setup_auth), (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state): * gst/rtsp/gstrtspsrc.h: Implement RTPBin session manager handling. Don't try to add empty properties to caps. Implement fallback session manager, handling. Don't combine errors from RTCP streams, just ignore them. * gst/rtsp/rtsptransport.c: (rtsp_transport_get_manager): * gst/rtsp/rtsptransport.h: Implement fallback session manager. Make RTPBin the default one when available.
-rw-r--r--ChangeLog35
-rw-r--r--gst/rtsp/Makefile.am6
-rw-r--r--gst/rtsp/gstrtpdec.c702
-rw-r--r--gst/rtsp/gstrtpdec.h29
-rw-r--r--gst/rtsp/gstrtsp.c2
-rw-r--r--gst/rtsp/gstrtspsrc.c219
-rw-r--r--gst/rtsp/gstrtspsrc.h7
-rw-r--r--gst/rtsp/rtsptransport.c21
-rw-r--r--gst/rtsp/rtsptransport.h2
9 files changed, 811 insertions, 212 deletions
diff --git a/ChangeLog b/ChangeLog
index 5fa4c3c7..af8c0dcc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2007-04-06 Wim Taymans <wim@fluendo.com>
+
+ * gst/rtsp/Makefile.am:
+ * gst/rtsp/gstrtpdec.c: (find_session_by_id), (create_session),
+ (free_session), (gst_rtp_dec_base_init), (gst_rtp_dec_class_init),
+ (gst_rtp_dec_init), (gst_rtp_dec_finalize),
+ (gst_rtp_dec_query_src), (gst_rtp_dec_chain_rtp),
+ (gst_rtp_dec_chain_rtcp), (gst_rtp_dec_set_property),
+ (gst_rtp_dec_get_property), (gst_rtp_dec_provide_clock),
+ (gst_rtp_dec_change_state), (create_recv_rtp), (create_recv_rtcp),
+ (create_rtcp), (gst_rtp_dec_request_new_pad),
+ (gst_rtp_dec_release_pad):
+ * gst/rtsp/gstrtpdec.h:
+ * gst/rtsp/gstrtsp.c: (plugin_init):
+ Morph RTPDec into something compatible with RTPBin as a fallback.
+ Various other style fixes.
+
+ * gst/rtsp/gstrtspsrc.c: (find_stream_by_id),
+ (find_stream_by_udpsrc), (gst_rtspsrc_stream_free),
+ (gst_rtspsrc_cleanup), (gst_rtspsrc_media_to_caps),
+ (new_session_pad), (gst_rtspsrc_stream_configure_transport),
+ (gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_interleaved),
+ (gst_rtspsrc_loop_udp), (gst_rtspsrc_setup_auth),
+ (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+ * gst/rtsp/gstrtspsrc.h:
+ Implement RTPBin session manager handling.
+ Don't try to add empty properties to caps.
+ Implement fallback session manager, handling.
+ Don't combine errors from RTCP streams, just ignore them.
+
+ * gst/rtsp/rtsptransport.c: (rtsp_transport_get_manager):
+ * gst/rtsp/rtsptransport.h:
+ Implement fallback session manager.
+ Make RTPBin the default one when available.
+
2007-04-05 Wim Taymans <wim@fluendo.com>
* gst/rtp/gstrtpmp4adepay.c: (gst_rtp_mp4a_depay_class_init),
diff --git a/gst/rtsp/Makefile.am b/gst/rtsp/Makefile.am
index 8f0049c7..86c144b4 100644
--- a/gst/rtsp/Makefile.am
+++ b/gst/rtsp/Makefile.am
@@ -11,10 +11,12 @@ libgstrtsp_la_SOURCES = gstrtsp.c gstrtspsrc.c \
sdpmessage.c \
base64.c
-libgstrtsp_la_CFLAGS = $(GST_CFLAGS)
-libgstrtsp_la_LIBADD = $(GST_LIBS) $(WIN32_LIBS)
+libgstrtsp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstrtsp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
+ -lgstrtp-@GST_MAJORMINOR@ $(GST_LIBS) $(WIN32_LIBS)
libgstrtsp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
check_PROGRAMS = test
test_SOURCES = test.c rtspdefs.c rtspurl.c rtspconnection.c rtspmessage.c rtsptransport.c sdpmessage.c base64.c
diff --git a/gst/rtsp/gstrtpdec.c b/gst/rtsp/gstrtpdec.c
index 9320f7df..ed119a5d 100644
--- a/gst/rtsp/gstrtpdec.c
+++ b/gst/rtsp/gstrtpdec.c
@@ -53,6 +53,14 @@
* Last reviewed on 2006-06-20 (0.10.4)
*/
+/* #define HAVE_RTCP */
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#ifdef HAVE_RTCP
+#include <gst/rtp/gstrtcpbuffer.h>
+#endif
+
#include "gstrtpdec.h"
GST_DEBUG_CATEGORY_STATIC (rtpdec_debug);
@@ -68,89 +76,144 @@ GST_ELEMENT_DETAILS ("RTP Decoder",
/* GstRTPDec signals and args */
enum
{
- /* FILL ME */
LAST_SIGNAL
};
enum
{
- ARG_0,
- ARG_SKIP
- /* FILL ME */
+ PROP_0,
};
-static GstStaticPadTemplate gst_rtpdec_src_rtp_template =
-GST_STATIC_PAD_TEMPLATE ("srcrtp",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
+static GstStaticPadTemplate gst_rtp_dec_recv_rtp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
GST_STATIC_CAPS ("application/x-rtp")
);
-static GstStaticPadTemplate gst_rtpdec_src_rtcp_template =
-GST_STATIC_PAD_TEMPLATE ("srcrtcp",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
+static GstStaticPadTemplate gst_rtp_dec_recv_rtcp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
GST_STATIC_CAPS ("application/x-rtcp")
);
-static GstStaticPadTemplate gst_rtpdec_sink_rtp_template =
-GST_STATIC_PAD_TEMPLATE ("sinkrtp",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
+static GstStaticPadTemplate gst_rtp_dec_recv_rtp_src_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("application/x-rtp")
);
-static GstStaticPadTemplate gst_rtpdec_sink_rtcp_template =
-GST_STATIC_PAD_TEMPLATE ("sinkrtcp",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
+static GstStaticPadTemplate gst_rtp_dec_rtcp_src_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
+ GST_PAD_SRC,
+ GST_PAD_REQUEST,
GST_STATIC_CAPS ("application/x-rtcp")
);
-static void gst_rtpdec_class_init (gpointer g_class);
-static void gst_rtpdec_init (GstRTPDec * rtpdec);
-
-static GstCaps *gst_rtpdec_getcaps (GstPad * pad);
-static GstFlowReturn gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer);
-static GstFlowReturn gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
-
-static void gst_rtpdec_set_property (GObject * object,
+static void gst_rtp_dec_finalize (GObject * object);
+static void gst_rtp_dec_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_rtpdec_get_property (GObject * object,
+static void gst_rtp_dec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
-static GstStateChangeReturn gst_rtpdec_change_state (GstElement * element,
+static GstClock *gst_rtp_dec_provide_clock (GstElement * element);
+static GstStateChangeReturn gst_rtp_dec_change_state (GstElement * element,
GstStateChange transition);
+static GstPad *gst_rtp_dec_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name);
+static void gst_rtp_dec_release_pad (GstElement * element, GstPad * pad);
-static GstElementClass *parent_class = NULL;
+static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstBuffer * buffer);
+static GstFlowReturn gst_rtp_dec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
-/*static guint gst_rtpdec_signals[LAST_SIGNAL] = { 0 };*/
-GType
-gst_rtpdec_get_type (void)
+/* Manages the receiving end of the packets.
+ *
+ * There is one such structure for each RTP session (audio/video/...).
+ * We get the RTP/RTCP packets and stuff them into the session manager.
+ */
+struct _GstRTPDecSession
{
- static GType rtpdec_type = 0;
-
- if (!rtpdec_type) {
- static const GTypeInfo rtpdec_info = {
- sizeof (GstRTPDecClass), NULL,
- NULL,
- (GClassInitFunc) gst_rtpdec_class_init,
- NULL,
- NULL,
- sizeof (GstRTPDec),
- 0,
- (GInstanceInitFunc) gst_rtpdec_init,
- };
-
- rtpdec_type =
- g_type_register_static (GST_TYPE_ELEMENT, "GstRTPDec", &rtpdec_info, 0);
+ /* session id */
+ gint id;
+ /* the parent bin */
+ GstRTPDec *dec;
+
+ gboolean active;
+ /* we only support one ssrc and one pt */
+ guint32 ssrc;
+ guint8 pt;
+ GstCaps *caps;
+
+ /* the pads of the session */
+ GstPad *recv_rtp_sink;
+ GstPad *recv_rtp_src;
+ GstPad *recv_rtcp_sink;
+ GstPad *rtcp_src;
+};
+
+/* find a session with the given id */
+static GstRTPDecSession *
+find_session_by_id (GstRTPDec * rtpdec, gint id)
+{
+ GSList *walk;
+
+ for (walk = rtpdec->sessions; walk; walk = g_slist_next (walk)) {
+ GstRTPDecSession *sess = (GstRTPDecSession *) walk->data;
+
+ if (sess->id == id)
+ return sess;
}
- return rtpdec_type;
+ return NULL;
+}
+
+/* create a session with the given id */
+static GstRTPDecSession *
+create_session (GstRTPDec * rtpdec, gint id)
+{
+ GstRTPDecSession *sess;
+
+ sess = g_new0 (GstRTPDecSession, 1);
+ sess->id = id;
+ sess->dec = rtpdec;
+ rtpdec->sessions = g_slist_prepend (rtpdec->sessions, sess);
+
+ return sess;
+}
+
+static void
+free_session (GstRTPDecSession * session)
+{
+ g_free (session);
+}
+
+/*static guint gst_rtp_dec_signals[LAST_SIGNAL] = { 0 };*/
+
+GST_BOILERPLATE (GstRTPDec, gst_rtp_dec, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_rtp_dec_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ /* sink pads */
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_dec_recv_rtcp_sink_template));
+ /* src pads */
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_dec_rtcp_src_template));
+
+ gst_element_class_set_details (element_class, &rtpdec_details);
}
static void
-gst_rtpdec_class_init (gpointer g_class)
+gst_rtp_dec_class_init (GstRTPDecClass * g_class)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
@@ -160,157 +223,324 @@ gst_rtpdec_class_init (gpointer g_class)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtpdec_src_rtp_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtpdec_src_rtcp_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtpdec_sink_rtp_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtpdec_sink_rtcp_template));
- gst_element_class_set_details (gstelement_class, &rtpdec_details);
-
- gobject_class->set_property = gst_rtpdec_set_property;
- gobject_class->get_property = gst_rtpdec_get_property;
+ gobject_class->finalize = gst_rtp_dec_finalize;
+ gobject_class->set_property = gst_rtp_dec_set_property;
+ gobject_class->get_property = gst_rtp_dec_get_property;
- /* FIXME, this is unused and probably copied from somewhere */
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SKIP,
- g_param_spec_int ("skip", "Skip", "skip (unused)", G_MININT, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- parent_class = g_type_class_peek_parent (klass);
-
- gstelement_class->change_state = gst_rtpdec_change_state;
+ gstelement_class->provide_clock =
+ GST_DEBUG_FUNCPTR (gst_rtp_dec_provide_clock);
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_dec_change_state);
+ gstelement_class->request_new_pad =
+ GST_DEBUG_FUNCPTR (gst_rtp_dec_request_new_pad);
+ gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_dec_release_pad);
GST_DEBUG_CATEGORY_INIT (rtpdec_debug, "rtpdec", 0, "RTP decoder");
}
static void
-gst_rtpdec_init (GstRTPDec * rtpdec)
+gst_rtp_dec_init (GstRTPDec * rtpdec, GstRTPDecClass * klass)
{
- /* the input rtp pad */
- rtpdec->sink_rtp =
- gst_pad_new_from_static_template (&gst_rtpdec_sink_rtp_template,
- "sinkrtp");
- gst_pad_set_getcaps_function (rtpdec->sink_rtp, gst_rtpdec_getcaps);
- gst_pad_set_chain_function (rtpdec->sink_rtp, gst_rtpdec_chain_rtp);
- gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtp);
-
- /* the input rtcp pad */
- rtpdec->sink_rtcp =
- gst_pad_new_from_static_template (&gst_rtpdec_sink_rtcp_template,
- "sinkrtcp");
- gst_pad_set_chain_function (rtpdec->sink_rtcp, gst_rtpdec_chain_rtcp);
- gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtcp);
-
- /* the output rtp pad */
- rtpdec->src_rtp =
- gst_pad_new_from_static_template (&gst_rtpdec_src_rtp_template, "srcrtp");
- gst_pad_set_getcaps_function (rtpdec->src_rtp, gst_rtpdec_getcaps);
- gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtp);
-
- /* the output rtcp pad */
- rtpdec->src_rtcp =
- gst_pad_new_from_static_template (&gst_rtpdec_src_rtcp_template,
- "srcrtcp");
- gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtcp);
+ rtpdec->provided_clock = gst_system_clock_obtain ();
}
-static GstCaps *
-gst_rtpdec_getcaps (GstPad * pad)
+static void
+gst_rtp_dec_finalize (GObject * object)
{
- GstRTPDec *src;
- GstPad *other;
- GstCaps *caps;
- const GstCaps *templ;
-
- src = GST_RTPDEC (GST_PAD_PARENT (pad));
+ GstRTPDec *rtpdec;
- other = (pad == src->src_rtp ? src->sink_rtp : src->src_rtp);
+ rtpdec = GST_RTP_DEC (object);
- caps = gst_pad_peer_get_caps (other);
+ g_slist_foreach (rtpdec->sessions, (GFunc) free_session, NULL);
+ g_slist_free (rtpdec->sessions);
- templ = gst_pad_get_pad_template_caps (pad);
- if (caps == NULL) {
- GST_DEBUG_OBJECT (src, "copy template");
- caps = gst_caps_copy (templ);
- } else {
- GstCaps *intersect;
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
- GST_DEBUG_OBJECT (src, "intersect with template");
+static gboolean
+gst_rtp_dec_query_src (GstPad * pad, GstQuery * query)
+{
+ GstRTPDec *rtpdec;
+ gboolean res;
- intersect = gst_caps_intersect (caps, templ);
- gst_caps_unref (caps);
+ rtpdec = GST_RTP_DEC (GST_PAD_PARENT (pad));
- caps = intersect;
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:
+ {
+ /* we pretend to be live with a 3 second latency */
+ gst_query_set_latency (query, TRUE, 3 * GST_SECOND, -1);
+ res = TRUE;
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, query);
+ break;
}
-
- return caps;
+ return res;
}
static GstFlowReturn
-gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer)
+gst_rtp_dec_chain_rtp (GstPad * pad, GstBuffer * buffer)
{
- GstRTPDec *src;
+ GstFlowReturn res;
+ GstRTPDec *rtpdec;
+ GstRTPDecSession *session;
+ guint32 ssrc;
+ guint8 pt;
+
+ rtpdec = GST_RTP_DEC (GST_PAD_PARENT (pad));
+
+ GST_DEBUG_OBJECT (rtpdec, "got rtp packet");
+
+ if (!gst_rtp_buffer_validate (buffer))
+ goto bad_packet;
+
+ ssrc = gst_rtp_buffer_get_ssrc (buffer);
+ pt = gst_rtp_buffer_get_payload_type (buffer);
+
+ GST_DEBUG_OBJECT (rtpdec, "SSRC %d, PT %d", ssrc, pt);
+
+ /* find session */
+ session = gst_pad_get_element_private (pad);
+
+ /* see if we have the pad */
+ if (!session->active) {
+ GstPadTemplate *templ;
+ GstElementClass *klass;
+ gchar *name;
+
+ GST_DEBUG_OBJECT (rtpdec, "creating stream");
+
+ session->ssrc = ssrc;
+ session->pt = pt;
+
+ name = g_strdup_printf ("recv_rtp_src_%d_%u_%d", session->id, ssrc, pt);
+ klass = GST_ELEMENT_GET_CLASS (rtpdec);
+ templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
+ 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_rtp_dec_query_src);
+ gst_pad_set_active (session->recv_rtp_src, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src);
+
+ session->active = TRUE;
+ }
- src = GST_RTPDEC (GST_PAD_PARENT (pad));
+ res = gst_pad_push (session->recv_rtp_src, buffer);
- GST_DEBUG_OBJECT (src, "got rtp packet");
- return gst_pad_push (src->src_rtp, buffer);
+ return res;
+
+bad_packet:
+ {
+ GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
+ ("RTP packet did not validate, dropping"));
+ return GST_FLOW_OK;
+ }
}
static GstFlowReturn
-gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer)
+gst_rtp_dec_chain_rtcp (GstPad * pad, GstBuffer * buffer)
{
GstRTPDec *src;
- src = GST_RTPDEC (GST_PAD_PARENT (pad));
+#ifdef HAVE_RTCP
+ gboolean valid;
+ GstRTCPPacket packet;
+ gboolean more;
+#endif
+
+ src = GST_RTP_DEC (GST_PAD_PARENT (pad));
GST_DEBUG_OBJECT (src, "got rtcp packet");
+#ifdef HAVE_RTCP
+ valid = gst_rtcp_buffer_validate (buffer);
+ if (!valid)
+ goto bad_packet;
+
+ /* position on first packet */
+ more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
+ while (more) {
+ switch (gst_rtcp_packet_get_type (&packet)) {
+ case GST_RTCP_TYPE_SR:
+ {
+ guint32 ssrc, rtptime, packet_count, octet_count;
+ guint64 ntptime;
+ guint count, i;
+
+ gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
+ &packet_count, &octet_count);
+
+ GST_DEBUG_OBJECT (src,
+ "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
+ ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
+ octet_count);
+
+ count = gst_rtcp_packet_get_rb_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+ guint8 fractionlost;
+ gint32 packetslost;
+
+ gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
+ &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+ GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
+ ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
+ packetslost, exthighestseq, jitter, lsr, dlsr);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_RR:
+ {
+ guint32 ssrc;
+ guint count, i;
+
+ ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
+
+ GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
+
+ count = gst_rtcp_packet_get_rb_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+ guint8 fractionlost;
+ gint32 packetslost;
+
+ gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
+ &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+ GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
+ ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
+ packetslost, exthighestseq, jitter, lsr, dlsr);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_SDES:
+ {
+ guint chunks, i, j;
+ gboolean more_chunks, more_items;
+
+ chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
+ GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
+
+ more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
+ i = 0;
+ while (more_chunks) {
+ guint32 ssrc;
+
+ ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
+
+ GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
+
+ more_items = gst_rtcp_packet_sdes_first_item (&packet);
+ j = 0;
+ while (more_items) {
+ GstRTCPSDESType type;
+ guint8 len;
+ gchar *data;
+
+ gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
+
+ GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
+ type, len, data);
+
+ more_items = gst_rtcp_packet_sdes_next_item (&packet);
+ j++;
+ }
+ more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
+ i++;
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_BYE:
+ {
+ guint count, i;
+ gchar *reason;
+
+ reason = gst_rtcp_packet_bye_get_reason (&packet);
+ GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
+ GST_STR_NULL (reason));
+ g_free (reason);
+
+ count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc;
+
+
+ ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
+
+ GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_APP:
+ GST_DEBUG_OBJECT (src, "got APP packet");
+ break;
+ default:
+ GST_WARNING_OBJECT (src, "got unknown RTCP packet");
+ break;
+ }
+ more = gst_rtcp_packet_move_to_next (&packet);
+ }
gst_buffer_unref (buffer);
return GST_FLOW_OK;
+
+bad_packet:
+ {
+ GST_WARNING_OBJECT (src, "got invalid RTCP packet");
+ return GST_FLOW_OK;
+ }
+#else
+ return GST_FLOW_OK;
+#endif
}
static void
-gst_rtpdec_set_property (GObject * object, guint prop_id,
+gst_rtp_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstRTPDec *src;
- src = GST_RTPDEC (object);
+ src = GST_RTP_DEC (object);
switch (prop_id) {
- case ARG_SKIP:
- break;
default:
break;
}
}
static void
-gst_rtpdec_get_property (GObject * object, guint prop_id, GValue * value,
+gst_rtp_dec_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstRTPDec *src;
- src = GST_RTPDEC (object);
+ src = GST_RTP_DEC (object);
switch (prop_id) {
- case ARG_SKIP:
- break;
default:
break;
}
}
+static GstClock *
+gst_rtp_dec_provide_clock (GstElement * element)
+{
+ GstRTPDec *rtpdec;
+
+ rtpdec = GST_RTP_DEC (element);
+
+ return GST_CLOCK_CAST (gst_object_ref (rtpdec->provided_clock));
+}
+
static GstStateChangeReturn
-gst_rtpdec_change_state (GstElement * element, GstStateChange transition)
+gst_rtp_dec_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
GstRTPDec *rtpdec;
- rtpdec = GST_RTPDEC (element);
+ rtpdec = GST_RTP_DEC (element);
switch (transition) {
default:
@@ -322,6 +552,7 @@ gst_rtpdec_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ /* we're NO_PREROLL when going to PAUSED */
ret = GST_STATE_CHANGE_NO_PREROLL;
break;
default:
@@ -330,3 +561,198 @@ gst_rtpdec_change_state (GstElement * element, GstStateChange transition)
return ret;
}
+
+/* Create a pad for receiving RTP for the session in @name
+ */
+static GstPad *
+create_recv_rtp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
+{
+ guint sessid;
+ GstRTPDecSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
+ goto no_name;
+
+ GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
+
+ /* get or create session */
+ session = find_session_by_id (rtpdec, sessid);
+ if (!session) {
+ GST_DEBUG_OBJECT (rtpdec, "creating session %d", sessid);
+ /* create session now */
+ session = create_session (rtpdec, sessid);
+ if (session == NULL)
+ goto create_error;
+ }
+ /* check if pad was requested */
+ if (session->recv_rtp_sink != NULL)
+ goto existed;
+
+ GST_DEBUG_OBJECT (rtpdec, "getting RTP sink pad");
+
+ session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (session->recv_rtp_sink, session);
+ gst_pad_set_chain_function (session->recv_rtp_sink, gst_rtp_dec_chain_rtp);
+ gst_pad_set_active (session->recv_rtp_sink, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_sink);
+
+ return session->recv_rtp_sink;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rtpdec: invalid name given");
+ return NULL;
+ }
+create_error:
+ {
+ /* create_session already warned */
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rtpdec: recv_rtp pad already requested for session %d", sessid);
+ return NULL;
+ }
+}
+
+/* Create a pad for receiving RTCP for the session in @name
+ */
+static GstPad *
+create_recv_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ,
+ const gchar * name)
+{
+ guint sessid;
+ GstRTPDecSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
+ goto no_name;
+
+ GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
+
+ /* get the session, it must exist or we error */
+ session = find_session_by_id (rtpdec, sessid);
+ if (!session)
+ goto no_session;
+
+ /* check if pad was requested */
+ if (session->recv_rtcp_sink != NULL)
+ goto existed;
+
+ GST_DEBUG_OBJECT (rtpdec, "getting RTCP sink pad");
+
+ session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (session->recv_rtp_sink, session);
+ gst_pad_set_chain_function (session->recv_rtcp_sink, gst_rtp_dec_chain_rtcp);
+ gst_pad_set_active (session->recv_rtcp_sink, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtcp_sink);
+
+ return session->recv_rtcp_sink;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rtpdec: invalid name given");
+ return NULL;
+ }
+no_session:
+ {
+ g_warning ("rtpdec: no session with id %d", sessid);
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rtpdec: recv_rtcp pad already requested for session %d",
+ sessid);
+ return NULL;
+ }
+}
+
+/* Create a pad for sending RTCP for the session in @name
+ */
+static GstPad *
+create_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
+{
+ guint sessid;
+ GstRTPDecSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "rtcp_src_%d", &sessid) != 1)
+ goto no_name;
+
+ /* get or create session */
+ session = find_session_by_id (rtpdec, sessid);
+ if (!session)
+ goto no_session;
+
+ /* check if pad was requested */
+ if (session->rtcp_src != NULL)
+ goto existed;
+
+ session->rtcp_src = gst_pad_new_from_template (templ, name);
+ gst_pad_set_active (session->rtcp_src, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->rtcp_src);
+
+ return session->rtcp_src;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rtpdec: invalid name given");
+ return NULL;
+ }
+no_session:
+ {
+ g_warning ("rtpdec: session with id %d does not exist", sessid);
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rtpdec: rtcp_src pad already requested for session %d", sessid);
+ return NULL;
+ }
+}
+
+/*
+ */
+static GstPad *
+gst_rtp_dec_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name)
+{
+ GstRTPDec *rtpdec;
+ GstElementClass *klass;
+ GstPad *result;
+
+ g_return_val_if_fail (templ != NULL, NULL);
+ g_return_val_if_fail (GST_IS_RTP_DEC (element), NULL);
+
+ rtpdec = GST_RTP_DEC (element);
+ klass = GST_ELEMENT_GET_CLASS (element);
+
+ /* figure out the template */
+ if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
+ result = create_recv_rtp (rtpdec, templ, name);
+ } else if (templ == gst_element_class_get_pad_template (klass,
+ "recv_rtcp_sink_%d")) {
+ result = create_recv_rtcp (rtpdec, templ, name);
+ } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
+ result = create_rtcp (rtpdec, templ, name);
+ } else
+ goto wrong_template;
+
+ return result;
+
+ /* ERRORS */
+wrong_template:
+ {
+ g_warning ("rtpdec: this is not our template");
+ return NULL;
+ }
+}
+
+static void
+gst_rtp_dec_release_pad (GstElement * element, GstPad * pad)
+{
+}
diff --git a/gst/rtsp/gstrtpdec.h b/gst/rtsp/gstrtpdec.h
index 3475f4c4..9c8e9365 100644
--- a/gst/rtsp/gstrtpdec.h
+++ b/gst/rtsp/gstrtpdec.h
@@ -40,39 +40,36 @@
* SOFTWARE.
*/
-#ifndef __GST_RTPDEC_H__
-#define __GST_RTPDEC_H__
+#ifndef __GST_RTP_DEC_H__
+#define __GST_RTP_DEC_H__
#include <gst/gst.h>
G_BEGIN_DECLS
-#define GST_TYPE_RTPDEC (gst_rtpdec_get_type())
-#define GST_IS_RTPDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTPDEC))
-#define GST_IS_RTPDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTPDEC))
-#define GST_RTPDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTPDEC, GstRTPDec))
-#define GST_RTPDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTPDEC, GstRTPDecClass))
+#define GST_TYPE_RTP_DEC (gst_rtp_dec_get_type())
+#define GST_IS_RTP_DEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DEC))
+#define GST_IS_RTP_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DEC))
+#define GST_RTP_DEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DEC, GstRTPDec))
+#define GST_RTP_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DEC, GstRTPDecClass))
typedef struct _GstRTPDec GstRTPDec;
typedef struct _GstRTPDecClass GstRTPDecClass;
+typedef struct _GstRTPDecSession GstRTPDecSession;
struct _GstRTPDec {
- GstElement element;
+ GstElement element;
- GstPad *sink_rtp;
- GstPad *sink_rtcp;
- GstPad *src_rtp;
- GstPad *src_rtcp;
+ GSList *sessions;
+ GstClock *provided_clock;
};
struct _GstRTPDecClass {
GstElementClass parent_class;
};
-gboolean gst_rtpdec_plugin_init (GstPlugin * plugin);
-
-GType gst_rtpdec_get_type(void);
+GType gst_rtp_dec_get_type(void);
G_END_DECLS
-#endif /* __GST_RTPDEC_H__ */
+#endif /* __GST_RTP_DEC_H__ */
diff --git a/gst/rtsp/gstrtsp.c b/gst/rtsp/gstrtsp.c
index 311fe713..045c03a6 100644
--- a/gst/rtsp/gstrtsp.c
+++ b/gst/rtsp/gstrtsp.c
@@ -54,7 +54,7 @@ plugin_init (GstPlugin * plugin)
if (!gst_element_register (plugin, "rtspsrc", GST_RANK_NONE,
GST_TYPE_RTSPSRC))
return FALSE;
- if (!gst_element_register (plugin, "rtpdec", GST_RANK_NONE, GST_TYPE_RTPDEC))
+ if (!gst_element_register (plugin, "rtpdec", GST_RANK_NONE, GST_TYPE_RTP_DEC))
return FALSE;
return TRUE;
diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c
index 1726cc60..d64da033 100644
--- a/gst/rtsp/gstrtspsrc.c
+++ b/gst/rtsp/gstrtspsrc.c
@@ -385,6 +385,17 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
}
static gint
+find_stream_by_id (GstRTSPStream * stream, gconstpointer a)
+{
+ gint id = GPOINTER_TO_INT (a);
+
+ if (stream->id == id)
+ return 0;
+
+ return -1;
+}
+
+static gint
find_stream_by_channel (GstRTSPStream * stream, gconstpointer a)
{
gint channel = GPOINTER_TO_INT (a);
@@ -413,6 +424,8 @@ find_stream_by_udpsrc (GstRTSPStream * stream, gconstpointer a)
if (stream->udpsrc[0] == src)
return 0;
+ if (stream->udpsrc[1] == src)
+ return 0;
return -1;
}
@@ -541,11 +554,6 @@ gst_rtspsrc_stream_free (GstRTSPSrc * src, GstRTSPStream * stream)
stream->udpsrc[i] = NULL;
}
}
- if (stream->sess) {
- gst_element_set_state (stream->sess, GST_STATE_NULL);
- gst_bin_remove (GST_BIN_CAST (src), stream->sess);
- stream->sess = NULL;
- }
if (stream->srcpad) {
gst_pad_set_active (stream->srcpad, FALSE);
if (stream->added) {
@@ -571,6 +579,15 @@ gst_rtspsrc_cleanup (GstRTSPSrc * src)
}
g_list_free (src->streams);
src->streams = NULL;
+ if (src->session) {
+ if (src->session_sig_id) {
+ g_signal_handler_disconnect (src->session, src->session_sig_id);
+ src->session_sig_id = 0;
+ }
+ gst_element_set_state (src->session, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN_CAST (src), src->session);
+ src->session = NULL;
+ }
src->numstreams = 0;
if (src->props)
gst_structure_free (src->props);
@@ -803,9 +820,11 @@ gst_rtspsrc_media_to_caps (gint pt, SDPMedia * media)
}
/* strip the key of spaces, convert key to lowercase but not the value. */
key = g_strstrip (pairs[i]);
- tmp = g_ascii_strdown (key, -1);
- gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL);
- g_free (tmp);
+ if (strlen (key) > 1) {
+ tmp = g_ascii_strdown (key, -1);
+ gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL);
+ g_free (tmp);
+ }
}
g_strfreev (pairs);
}
@@ -998,6 +1017,66 @@ was_ok:
}
}
+/* this callback is called when the session manager generated a new src pad with
+ * payloaded RTP packets. We simply ghost the pad here. */
+static void
+new_session_pad (GstElement * session, GstPad * pad, GstRTSPSrc * src)
+{
+ gchar *name;
+ GstPadTemplate *template;
+ gint id, ssrc, pt;
+ GList *lstream;
+ GstRTSPStream *stream;
+
+ GST_DEBUG_OBJECT (src, "got new session pad %" GST_PTR_FORMAT, pad);
+
+ /* find stream */
+ name = gst_object_get_name (GST_OBJECT_CAST (pad));
+ if (sscanf (name, "recv_rtp_src_%d_%d_%d", &id, &ssrc, &pt) != 3)
+ goto unknown_stream;
+
+ GST_DEBUG_OBJECT (src, "stream: %u, SSRC %d, PT %d", id, ssrc, pt);
+
+ lstream = g_list_find_custom (src->streams, GINT_TO_POINTER (id),
+ (GCompareFunc) find_stream_by_id);
+ if (lstream == NULL)
+ goto unknown_stream;
+
+ /* get stream */
+ stream = (GstRTSPStream *) lstream->data;
+
+ /* create a new pad we will use to stream to */
+ template = gst_static_pad_template_get (&rtptemplate);
+ stream->srcpad = gst_ghost_pad_new_from_template (name, pad, template);
+ gst_object_unref (template);
+ g_free (name);
+
+ stream->added = TRUE;
+ gst_pad_set_active (stream->srcpad, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
+
+ /* check if we added all streams */
+ for (lstream = src->streams; lstream; lstream = g_list_next (lstream)) {
+ stream = (GstRTSPStream *) lstream->data;
+ if (!stream->added)
+ goto done;
+ }
+ /* when we get here, all stream are added and we can fire the no-more-pads
+ * signal. */
+ gst_element_no_more_pads (GST_ELEMENT_CAST (src));
+
+done:
+ return;
+
+ /* ERRORS */
+unknown_stream:
+ {
+ GST_DEBUG_OBJECT (src, "ignoring unknown stream");
+ g_free (name);
+ return;
+ }
+}
+
/* sets up all elements needed for streaming over the specified transport.
* Does not yet expose the element pads, this will be done when there is actuall
* dataflow detected, which might never happen when UDP is blocked in a
@@ -1033,27 +1112,45 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
gst_structure_set_name (s, mime);
/* find a manager */
- if ((res = rtsp_transport_get_manager (transport->trans, &manager)) < 0)
+ if ((res = rtsp_transport_get_manager (transport->trans, &manager, 0)) < 0)
goto no_manager;
if (manager) {
GST_DEBUG_OBJECT (src, "using manager %s", manager);
- /* FIXME, the session manager needs to be shared with all the streams */
- if (!(stream->sess = gst_element_factory_make (manager, NULL)))
- goto no_element;
- /* we manage this element */
- gst_bin_add (GST_BIN_CAST (src), stream->sess);
+ /* configure the manager */
+ if (src->session == NULL) {
+ if (!(src->session = gst_element_factory_make (manager, NULL))) {
+ /* fallback */
+ if ((res =
+ rtsp_transport_get_manager (transport->trans, &manager, 1)) < 0)
+ goto no_manager;
+
+ if (!manager)
+ goto use_no_manager;
- ret = gst_element_set_state (stream->sess, GST_STATE_PAUSED);
- if (ret == GST_STATE_CHANGE_FAILURE)
- goto start_session_failure;
+ if (!(src->session = gst_element_factory_make (manager, NULL)))
+ goto manager_failed;
+ }
+
+ /* we manage this element */
+ gst_bin_add (GST_BIN_CAST (src), src->session);
- /* we stream directly to the manager, FIXME, pad names should not be
- * hardcoded. */
- stream->channelpad[0] = gst_element_get_pad (stream->sess, "sinkrtp");
- stream->channelpad[1] = gst_element_get_pad (stream->sess, "sinkrtcp");
+ ret = gst_element_set_state (src->session, GST_STATE_PAUSED);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ goto start_session_failure;
+ }
+
+ /* we stream directly to the manager, get some pads. Each RTSP stream goes
+ * into a separate RTP session. */
+ name = g_strdup_printf ("recv_rtp_sink_%d", stream->id);
+ stream->channelpad[0] = gst_element_get_request_pad (src->session, name);
+ g_free (name);
+ name = g_strdup_printf ("recv_rtcp_sink_%d", stream->id);
+ stream->channelpad[1] = gst_element_get_request_pad (src->session, name);
+ g_free (name);
}
+use_no_manager:
if (transport->lower_transport == RTSP_LOWER_TRANS_TCP) {
gint i;
@@ -1093,7 +1190,7 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
outpad = gst_object_ref (stream->channelpad[0]);
} else {
GST_DEBUG_OBJECT (src, "using manager source pad");
- outpad = gst_element_get_pad (stream->sess, "srcrtp");
+ /* we connected to pad-added signal to get pads from the manager */
}
} else {
/* multicast was selected, create UDP sources and join the multicast
@@ -1168,8 +1265,8 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
* the session plugin. */
gst_pad_link (outpad, stream->channelpad[0]);
gst_object_unref (outpad);
- /* the real output pad is that of the session manager */
- outpad = gst_element_get_pad (stream->sess, "srcrtp");
+ outpad = NULL;
+ /* we connected to pad-added signal to get pads from the manager */
} else {
GST_DEBUG_OBJECT (src, "using UDP src pad as output");
}
@@ -1190,6 +1287,13 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
}
}
+ if (src->session && !src->session_sig_id) {
+ GST_DEBUG_OBJECT (src, "connect to pad-added on session manager");
+ src->session_sig_id =
+ g_signal_connect (src->session, "pad-added",
+ (GCallback) new_session_pad, src);
+ }
+
if (outpad) {
GST_DEBUG_OBJECT (src, "creating ghostpad");
@@ -1221,9 +1325,14 @@ no_manager:
GST_DEBUG_OBJECT (src, "cannot get a session manager");
return FALSE;
}
+manager_failed:
+ {
+ GST_DEBUG_OBJECT (src, "no session manager element %d found", manager);
+ return FALSE;
+ }
no_element:
{
- GST_DEBUG_OBJECT (src, "no rtpdec element found");
+ GST_DEBUG_OBJECT (src, "no UDP source element found");
return FALSE;
}
start_session_failure:
@@ -1278,10 +1387,6 @@ gst_rtspsrc_activate_streams (GstRTSPSrc * src)
}
}
- /* if we got here all was configured. We have dynamic pads so we notify that
- * we are done */
- gst_element_no_more_pads (GST_ELEMENT_CAST (src));
-
/* unblock all pads */
for (walk = src->streams; walk; walk = g_list_next (walk)) {
GstRTSPStream *stream = (GstRTSPStream *) walk->data;
@@ -1296,7 +1401,6 @@ gst_rtspsrc_activate_streams (GstRTSPSrc * src)
return TRUE;
}
-
static GstFlowReturn
gst_rtspsrc_combine_flows (GstRTSPSrc * src, GstRTSPStream * stream,
GstFlowReturn ret)
@@ -1376,6 +1480,7 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
GstFlowReturn ret = GST_FLOW_OK;
GstCaps *caps = NULL;
GstBuffer *buf;
+ gboolean is_rtcp = FALSE;
do {
GST_DEBUG_OBJECT (src, "doing receive");
@@ -1399,6 +1504,7 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
caps = stream->caps;
} else if (channel == stream->channel[1]) {
outpad = stream->channelpad[1];
+ is_rtcp = TRUE;
}
/* take a look at the body to figure out what we have */
@@ -1410,6 +1516,7 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
if (data[1] >= 200 && data[1] <= 204) {
/* hmm RTCP message switch to the RTCP pad of the same stream. */
outpad = stream->channelpad[1];
+ is_rtcp = TRUE;
}
/* we have no clue what this is, just ignore then. */
@@ -1447,11 +1554,12 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
else
ret = gst_pad_push (outpad, buf);
- /* combine all stream flows */
- ret = gst_rtspsrc_combine_flows (src, stream, ret);
- if (ret != GST_FLOW_OK)
- goto need_pause;
-
+ if (!is_rtcp) {
+ /* combine all stream flows for the data transport */
+ ret = gst_rtspsrc_combine_flows (src, stream, ret);
+ if (ret != GST_FLOW_OK)
+ goto need_pause;
+ }
return;
/* ERRORS */
@@ -1522,6 +1630,8 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src)
if (src->loop_cmd == CMD_STOP)
goto stopping;
+ /* FIXME, we should continue reading the TCP socket because the server might
+ * send us requests */
while (src->loop_cmd == CMD_WAIT) {
GST_DEBUG_OBJECT (src, "waiting");
GST_RTSP_LOOP_WAIT (src);
@@ -1530,7 +1640,7 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src)
goto stopping;
}
if (src->loop_cmd == CMD_RECONNECT) {
- /* FIXME, when we get here we have to reconnect using tcp */
+ /* when we get here we have to reconnect using tcp */
src->loop_cmd = CMD_WAIT;
/* only restart when the pads were not yet activated, else we were
@@ -1573,6 +1683,12 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src)
if (!gst_rtspsrc_open (src))
goto open_failed;
+ /* flush previous state */
+ gst_element_post_message (GST_ELEMENT_CAST (src),
+ gst_message_new_async_start (GST_OBJECT_CAST (src), TRUE));
+ gst_element_post_message (GST_ELEMENT_CAST (src),
+ gst_message_new_async_done (GST_OBJECT_CAST (src)));
+
/* start playback */
if (!gst_rtspsrc_play (src))
goto play_failed;
@@ -1784,15 +1900,19 @@ gst_rtspsrc_setup_auth (GstRTSPSrc * src, RTSPMessage * response)
return TRUE;
no_auth_available:
- /* Output an error indicating that we couldn't connect because there were
- * no supported authentication protocols */
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
- ("No supported authentication protocol was found"));
- return FALSE;
+ {
+ /* Output an error indicating that we couldn't connect because there were
+ * no supported authentication protocols */
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+ ("No supported authentication protocol was found"));
+ return FALSE;
+ }
no_user_pass:
- /* We don't fire an error message, we just return FALSE and let the
- * normal NOT_AUTHORIZED error be propagated */
- return FALSE;
+ {
+ /* We don't fire an error message, we just return FALSE and let the
+ * normal NOT_AUTHORIZED error be propagated */
+ return FALSE;
+ }
}
/**
@@ -2799,6 +2919,9 @@ gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message)
udpsrc = GST_MESSAGE_SRC (message);
+ GST_DEBUG_OBJECT (rtspsrc, "got error from %s",
+ GST_ELEMENT_NAME (udpsrc));
+
lstream = g_list_find_custom (rtspsrc->streams, udpsrc,
(GCompareFunc) find_stream_by_udpsrc);
if (!lstream)
@@ -2806,13 +2929,19 @@ gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message)
stream = (GstRTSPStream *) lstream->data;
+ /* we ignore the RTCP udpsrc */
+ if (stream->udpsrc[1] == GST_ELEMENT_CAST (udpsrc))
+ goto done;
+
/* if we get error messages from the udp sources, that's not a problem as
* long as not all of them error out. We also don't really know what the
* problem is, the message does not give enough detail... */
ret = gst_rtspsrc_combine_flows (rtspsrc, stream, GST_FLOW_NOT_LINKED);
+ GST_DEBUG_OBJECT (rtspsrc, "combined flows: %s", gst_flow_get_name (ret));
if (ret != GST_FLOW_OK)
goto forward;
+ done:
gst_message_unref (message);
break;
@@ -2847,6 +2976,8 @@ gst_rtspsrc_change_state (GstElement * element, GstStateChange transition)
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
rtsp_connection_flush (rtspsrc->connection, FALSE);
+ /* FIXME, the server might send UDP packets before we activate the UDP
+ * ports */
gst_rtspsrc_play (rtspsrc);
break;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h
index c3780756..d628dffc 100644
--- a/gst/rtsp/gstrtspsrc.h
+++ b/gst/rtsp/gstrtspsrc.h
@@ -97,9 +97,6 @@ struct _GstRTSPStream {
/* our udp sink back to the server */
GstElement *udpsink;
- /* the session manager */
- GstElement *sess;
-
/* state */
gint pt;
gboolean container;
@@ -149,6 +146,10 @@ struct _GstRTSPSrc {
/* supported methods */
gint methods;
+ /* session management */
+ GstElement *session;
+ gulong session_sig_id;
+
RTSPConnection *connection;
RTSPExtensionCtx *extension;
diff --git a/gst/rtsp/rtsptransport.c b/gst/rtsp/rtsptransport.c
index e833080a..567df96c 100644
--- a/gst/rtsp/rtsptransport.c
+++ b/gst/rtsp/rtsptransport.c
@@ -45,19 +45,21 @@
#include "rtsptransport.h"
+#define MAX_MANAGERS 2
+
typedef struct
{
const gchar *name;
const RTSPTransMode mode;
const gchar *gst_mime;
- const gchar *manager;
+ const gchar *manager[MAX_MANAGERS];
} RTSPTransMap;
static const RTSPTransMap transports[] = {
- {"rtp", RTSP_TRANS_RTP, "application/x-rtp", "rtpdec"},
- {"x-real-rdt", RTSP_TRANS_RDT, "application/x-rdt", NULL},
- {"x-pn-tng", RTSP_TRANS_RDT, "application/x-rdt", NULL},
- {NULL, RTSP_TRANS_UNKNOWN, NULL, NULL}
+ {"rtp", RTSP_TRANS_RTP, "application/x-rtp", {"rtpbin", "rtpdec"}},
+ {"x-real-rdt", RTSP_TRANS_RDT, "application/x-rdt", {NULL, NULL}},
+ {"x-pn-tng", RTSP_TRANS_RDT, "application/x-rdt", {NULL, NULL}},
+ {NULL, RTSP_TRANS_UNKNOWN, NULL, {NULL, NULL}}
};
typedef struct
@@ -135,7 +137,8 @@ rtsp_transport_get_mime (RTSPTransMode trans, const gchar ** mime)
}
RTSPResult
-rtsp_transport_get_manager (RTSPTransMode trans, const gchar ** manager)
+rtsp_transport_get_manager (RTSPTransMode trans, const gchar ** manager,
+ guint option)
{
gint i;
@@ -144,7 +147,11 @@ rtsp_transport_get_manager (RTSPTransMode trans, const gchar ** manager)
for (i = 0; transports[i].name; i++)
if (transports[i].mode == trans)
break;
- *manager = transports[i].manager;
+
+ if (option < MAX_MANAGERS)
+ *manager = transports[i].manager[option];
+ else
+ *manager = NULL;
return RTSP_OK;
}
diff --git a/gst/rtsp/rtsptransport.h b/gst/rtsp/rtsptransport.h
index 84c0996e..76e29105 100644
--- a/gst/rtsp/rtsptransport.h
+++ b/gst/rtsp/rtsptransport.h
@@ -103,7 +103,7 @@ RTSPResult rtsp_transport_init (RTSPTransport *transport);
RTSPResult rtsp_transport_parse (const gchar *str, RTSPTransport *transport);
RTSPResult rtsp_transport_get_mime (RTSPTransMode trans, const gchar **mime);
-RTSPResult rtsp_transport_get_manager (RTSPTransMode trans, const gchar **manager);
+RTSPResult rtsp_transport_get_manager (RTSPTransMode trans, const gchar **manager, guint option);
RTSPResult rtsp_transport_free (RTSPTransport *transport);