sdpdemux: add property to disable redirect
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 21 Sep 2010 17:07:05 +0000 (19:07 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 21 Sep 2010 17:15:27 +0000 (19:15 +0200)
Add a property to avoid redirection to the rtsp-sdp:// url but instead embeds an
rtspsrc element inside sdpdemux as the session manager.

Based on patch by Marco Ballesio.

Fixes #630046

gst/sdp/gstsdpdemux.c
gst/sdp/gstsdpdemux.h

index 5efc30b..72ac8c7 100644 (file)
@@ -103,13 +103,16 @@ enum
 #define DEFAULT_DEBUG            FALSE
 #define DEFAULT_TIMEOUT          10000000
 #define DEFAULT_LATENCY_MS       200
+#define DEFAULT_REDIRECT         TRUE
 
 enum
 {
   PROP_0,
   PROP_DEBUG,
   PROP_TIMEOUT,
-  PROP_LATENCY
+  PROP_LATENCY,
+  PROP_REDIRECT,
+  PROP_LAST
 };
 
 static void gst_sdp_demux_finalize (GObject * object);
@@ -192,6 +195,11 @@ gst_sdp_demux_class_init (GstSDPDemuxClass * klass)
           "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
+  g_object_class_install_property (gobject_class, PROP_REDIRECT,
+      g_param_spec_boolean ("redirect", "Redirect",
+          "Sends a redirection message instead of using a custom session element",
+          DEFAULT_REDIRECT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
   gstelement_class->change_state = gst_sdp_demux_change_state;
 
   gstbin_class->handle_message = gst_sdp_demux_handle_message;
@@ -249,6 +257,9 @@ gst_sdp_demux_set_property (GObject * object, guint prop_id,
     case PROP_LATENCY:
       demux->latency = g_value_get_uint (value);
       break;
+    case PROP_REDIRECT:
+      demux->redirect = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -273,6 +284,9 @@ gst_sdp_demux_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_LATENCY:
       g_value_set_uint (value, demux->latency);
       break;
+    case PROP_REDIRECT:
+      g_value_set_boolean (value, demux->redirect);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -382,12 +396,12 @@ is_multicast_address (const gchar * host_name)
   for (ai = res; !ret && ai; ai = ai->ai_next) {
     if (ai->ai_family == AF_INET)
       ret =
-          IN_MULTICAST (ntohl (((struct sockaddr_in *) ai->ai_addr)->sin_addr.
-              s_addr));
+          IN_MULTICAST (ntohl (((struct sockaddr_in *) ai->ai_addr)->
+              sin_addr.s_addr));
     else
       ret =
-          IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) ai->ai_addr)->
-          sin6_addr);
+          IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) ai->
+              ai_addr)->sin6_addr);
   }
 
   freeaddrinfo (res);
@@ -489,6 +503,14 @@ gst_sdp_demux_cleanup (GstSDPDemux * demux)
       g_signal_handler_disconnect (demux->session, demux->session_sig_id);
       demux->session_sig_id = 0;
     }
+    if (demux->session_nmp_id) {
+      g_signal_handler_disconnect (demux->session, demux->session_nmp_id);
+      demux->session_nmp_id = 0;
+    }
+    if (demux->session_ptmap_id) {
+      g_signal_handler_disconnect (demux->session, demux->session_ptmap_id);
+      demux->session_ptmap_id = 0;
+    }
     gst_element_set_state (demux->session, GST_STATE_NULL);
     gst_bin_remove (GST_BIN_CAST (demux), demux->session);
     demux->session = NULL;
@@ -794,6 +816,29 @@ unknown_stream:
   }
 }
 
+static void
+rtsp_session_pad_added (GstElement * session, GstPad * pad, GstSDPDemux * demux)
+{
+  GstPad *srcpad = NULL;
+  gchar *name;
+
+  GST_DEBUG_OBJECT (demux, "got new session pad %" GST_PTR_FORMAT, pad);
+
+  name = gst_pad_get_name (pad);
+  srcpad = gst_ghost_pad_new (name, pad);
+  g_free (name);
+
+  gst_pad_set_active (srcpad, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (demux), srcpad);
+}
+
+static void
+rtsp_session_no_more_pads (GstElement * session, GstSDPDemux * demux)
+{
+  GST_DEBUG_OBJECT (demux, "got no-more-pads");
+  gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
+}
+
 static GstCaps *
 request_pt_map (GstElement * sess, guint session, guint pt, GstSDPDemux * demux)
 {
@@ -880,37 +925,46 @@ on_timeout (GstElement * manager, guint session, guint32 ssrc,
 
 /* try to get and configure a manager */
 static gboolean
-gst_sdp_demux_configure_manager (GstSDPDemux * demux)
+gst_sdp_demux_configure_manager (GstSDPDemux * demux, char *rtsp_sdp)
 {
-  GstStateChangeReturn ret;
-
   /* configure the session manager */
-  if (!(demux->session = gst_element_factory_make ("gstrtpbin", NULL)))
-    goto manager_failed;
-
-  /* we manage this element */
-  gst_bin_add (GST_BIN_CAST (demux), demux->session);
-
-  ret = gst_element_set_state (demux->session, GST_STATE_PAUSED);
-  if (ret == GST_STATE_CHANGE_FAILURE)
-    goto start_session_failure;
+  if (rtsp_sdp != NULL) {
+    if (!(demux->session = gst_element_factory_make ("rtspsrc", NULL)))
+      goto rtspsrc_failed;
+
+    g_object_set (demux->session, "location", rtsp_sdp, NULL);
+
+    GST_DEBUG_OBJECT (demux, "connect to signals on rtspsrc");
+    demux->session_sig_id =
+        g_signal_connect (demux->session, "pad-added",
+        (GCallback) rtsp_session_pad_added, demux);
+    demux->session_nmp_id =
+        g_signal_connect (demux->session, "no-more-pads",
+        (GCallback) rtsp_session_no_more_pads, demux);
+  } else {
+    if (!(demux->session = gst_element_factory_make ("gstrtpbin", NULL)))
+      goto manager_failed;
+
+    /* connect to signals if we did not already do so */
+    GST_DEBUG_OBJECT (demux, "connect to signals on session manager");
+    demux->session_sig_id =
+        g_signal_connect (demux->session, "pad-added",
+        (GCallback) new_session_pad, demux);
+    demux->session_ptmap_id =
+        g_signal_connect (demux->session, "request-pt-map",
+        (GCallback) request_pt_map, demux);
+    g_signal_connect (demux->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
+        demux);
+    g_signal_connect (demux->session, "on-bye-timeout", (GCallback) on_timeout,
+        demux);
+    g_signal_connect (demux->session, "on-timeout", (GCallback) on_timeout,
+        demux);
+  }
 
   g_object_set (demux->session, "latency", demux->latency, NULL);
 
-  /* connect to signals if we did not already do so */
-  GST_DEBUG_OBJECT (demux, "connect to signals on session manager");
-  demux->session_sig_id =
-      g_signal_connect (demux->session, "pad-added",
-      (GCallback) new_session_pad, demux);
-  demux->session_ptmap_id =
-      g_signal_connect (demux->session, "request-pt-map",
-      (GCallback) request_pt_map, demux);
-  g_signal_connect (demux->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
-      demux);
-  g_signal_connect (demux->session, "on-bye-timeout", (GCallback) on_timeout,
-      demux);
-  g_signal_connect (demux->session, "on-timeout", (GCallback) on_timeout,
-      demux);
+  /* we manage this element */
+  gst_bin_add (GST_BIN_CAST (demux), demux->session);
 
   return TRUE;
 
@@ -920,12 +974,9 @@ manager_failed:
     GST_DEBUG_OBJECT (demux, "no session manager element gstrtpbin found");
     return FALSE;
   }
-start_session_failure:
+rtspsrc_failed:
   {
-    GST_DEBUG_OBJECT (demux, "could not start session");
-    gst_element_set_state (demux->session, GST_STATE_NULL);
-    gst_bin_remove (GST_BIN_CAST (demux), demux->session);
-    demux->session = NULL;
+    GST_DEBUG_OBJECT (demux, "no manager element rtspsrc found");
     return FALSE;
   }
 }
@@ -1245,6 +1296,8 @@ gst_sdp_demux_start (GstSDPDemux * demux)
   GstSDPMessage sdp = { 0 };
   GstSDPStream *stream = NULL;
   GList *walk;
+  gchar *uri = NULL;
+  GstStateChangeReturn ret;
 
   /* grab the lock so that no state change can interfere */
   GST_SDP_STREAM_LOCK (demux);
@@ -1305,48 +1358,56 @@ gst_sdp_demux_start (GstSDPDemux * demux)
     }
 
     if (control) {
-      gchar *uri;
-
-      /* we have RTSP redirect now */
+      /* we have RTSP now */
       uri = gst_sdp_message_as_uri ("rtsp-sdp", &sdp);
 
-      GST_INFO_OBJECT (demux, "redirect to %s", uri);
+      if (demux->redirect) {
+        GST_INFO_OBJECT (demux, "redirect to %s", uri);
 
-      gst_element_post_message (GST_ELEMENT_CAST (demux),
-          gst_message_new_element (GST_OBJECT_CAST (demux),
-              gst_structure_new ("redirect",
-                  "new-location", G_TYPE_STRING, uri, NULL)));
-      goto sent_redirect;
+        gst_element_post_message (GST_ELEMENT_CAST (demux),
+            gst_message_new_element (GST_OBJECT_CAST (demux),
+                gst_structure_new ("redirect",
+                    "new-location", G_TYPE_STRING, uri, NULL)));
+        goto sent_redirect;
+      }
     }
   }
 
   /* try to get and configure a manager */
-  if (!gst_sdp_demux_configure_manager (demux))
-    goto no_manager;
+  if (uri) {
+    /* we get here when we didn't do a redirect */
+    if (!gst_sdp_demux_configure_manager (demux, uri))
+      goto no_manager;
+  } else {
 
-  /* create streams with UDP sources and sinks */
-  n_streams = gst_sdp_message_medias_len (&sdp);
-  for (i = 0; i < n_streams; i++) {
-    stream = gst_sdp_demux_create_stream (demux, &sdp, i);
+    /* create streams with UDP sources and sinks */
+    n_streams = gst_sdp_message_medias_len (&sdp);
+    for (i = 0; i < n_streams; i++) {
+      stream = gst_sdp_demux_create_stream (demux, &sdp, i);
 
-    GST_DEBUG_OBJECT (demux, "configuring transport for stream %p", stream);
+      GST_DEBUG_OBJECT (demux, "configuring transport for stream %p", stream);
 
-    if (!gst_sdp_demux_stream_configure_udp (demux, stream))
-      goto transport_failed;
-    if (!gst_sdp_demux_stream_configure_udp_sink (demux, stream))
-      goto transport_failed;
+      if (!gst_sdp_demux_stream_configure_udp (demux, stream))
+        goto transport_failed;
+      if (!gst_sdp_demux_stream_configure_udp_sink (demux, stream))
+        goto transport_failed;
+    }
   }
 
   /* set target state on session manager */
-  gst_element_set_state (demux->session, demux->target);
+  ret = gst_element_set_state (demux->session, demux->target);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto start_session_failure;
 
-  /* activate all streams */
-  for (walk = demux->streams; walk; walk = g_list_next (walk)) {
-    stream = (GstSDPStream *) walk->data;
+  if (!uri) {
+    /* activate all streams */
+    for (walk = demux->streams; walk; walk = g_list_next (walk)) {
+      stream = (GstSDPStream *) walk->data;
 
-    /* configure target state on udp sources */
-    gst_element_set_state (stream->udpsrc[0], demux->target);
-    gst_element_set_state (stream->udpsrc[1], demux->target);
+      /* configure target state on udp sources */
+      gst_element_set_state (stream->udpsrc[0], demux->target);
+      gst_element_set_state (stream->udpsrc[1], demux->target);
+    }
   }
   GST_SDP_STREAM_UNLOCK (demux);
 
@@ -1384,6 +1445,14 @@ sent_redirect:
     GST_SDP_STREAM_UNLOCK (demux);
     return FALSE;
   }
+start_session_failure:
+  {
+    GST_DEBUG_OBJECT (demux, "could not start session");
+    gst_element_set_state (demux->session, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN_CAST (demux), demux->session);
+    demux->session = NULL;
+    return FALSE;
+  }
 }
 
 static gboolean
index 32a5329..94db8d6 100644 (file)
@@ -97,11 +97,13 @@ struct _GstSDPDemux {
   gboolean          debug;
   guint64           udp_timeout;
   guint             latency;
+  gboolean          redirect;
 
   /* session management */
   GstElement      *session;
   gulong           session_sig_id;
   gulong           session_ptmap_id;
+  gulong           session_nmp_id;
 };
 
 struct _GstSDPDemuxClass {