sdpdemux: add property to disable redirect

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
This commit is contained in:
Wim Taymans 2010-09-21 19:07:05 +02:00
parent 9db0d94364
commit 528f6e0573
2 changed files with 132 additions and 61 deletions

View file

@ -103,13 +103,16 @@ enum
#define DEFAULT_DEBUG FALSE #define DEFAULT_DEBUG FALSE
#define DEFAULT_TIMEOUT 10000000 #define DEFAULT_TIMEOUT 10000000
#define DEFAULT_LATENCY_MS 200 #define DEFAULT_LATENCY_MS 200
#define DEFAULT_REDIRECT TRUE
enum enum
{ {
PROP_0, PROP_0,
PROP_DEBUG, PROP_DEBUG,
PROP_TIMEOUT, PROP_TIMEOUT,
PROP_LATENCY PROP_LATENCY,
PROP_REDIRECT,
PROP_LAST
}; };
static void gst_sdp_demux_finalize (GObject * object); 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, "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); 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; gstelement_class->change_state = gst_sdp_demux_change_state;
gstbin_class->handle_message = gst_sdp_demux_handle_message; 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: case PROP_LATENCY:
demux->latency = g_value_get_uint (value); demux->latency = g_value_get_uint (value);
break; break;
case PROP_REDIRECT:
demux->redirect = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -273,6 +284,9 @@ gst_sdp_demux_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_LATENCY: case PROP_LATENCY:
g_value_set_uint (value, demux->latency); g_value_set_uint (value, demux->latency);
break; break;
case PROP_REDIRECT:
g_value_set_boolean (value, demux->redirect);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -382,12 +396,12 @@ is_multicast_address (const gchar * host_name)
for (ai = res; !ret && ai; ai = ai->ai_next) { for (ai = res; !ret && ai; ai = ai->ai_next) {
if (ai->ai_family == AF_INET) if (ai->ai_family == AF_INET)
ret = ret =
IN_MULTICAST (ntohl (((struct sockaddr_in *) ai->ai_addr)->sin_addr. IN_MULTICAST (ntohl (((struct sockaddr_in *) ai->ai_addr)->
s_addr)); sin_addr.s_addr));
else else
ret = ret =
IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) ai->ai_addr)-> IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) ai->
sin6_addr); ai_addr)->sin6_addr);
} }
freeaddrinfo (res); freeaddrinfo (res);
@ -489,6 +503,14 @@ gst_sdp_demux_cleanup (GstSDPDemux * demux)
g_signal_handler_disconnect (demux->session, demux->session_sig_id); g_signal_handler_disconnect (demux->session, demux->session_sig_id);
demux->session_sig_id = 0; 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_element_set_state (demux->session, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (demux), demux->session); gst_bin_remove (GST_BIN_CAST (demux), demux->session);
demux->session = NULL; 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 * static GstCaps *
request_pt_map (GstElement * sess, guint session, guint pt, GstSDPDemux * demux) 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 */ /* try to get and configure a manager */
static gboolean 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 */ /* configure the session manager */
if (!(demux->session = gst_element_factory_make ("gstrtpbin", NULL))) if (rtsp_sdp != NULL) {
goto manager_failed; if (!(demux->session = gst_element_factory_make ("rtspsrc", NULL)))
goto rtspsrc_failed;
/* we manage this element */ g_object_set (demux->session, "location", rtsp_sdp, NULL);
gst_bin_add (GST_BIN_CAST (demux), demux->session);
ret = gst_element_set_state (demux->session, GST_STATE_PAUSED); GST_DEBUG_OBJECT (demux, "connect to signals on rtspsrc");
if (ret == GST_STATE_CHANGE_FAILURE) demux->session_sig_id =
goto start_session_failure; 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); g_object_set (demux->session, "latency", demux->latency, NULL);
/* connect to signals if we did not already do so */ /* we manage this element */
GST_DEBUG_OBJECT (demux, "connect to signals on session manager"); gst_bin_add (GST_BIN_CAST (demux), demux->session);
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);
return TRUE; return TRUE;
@ -920,12 +974,9 @@ manager_failed:
GST_DEBUG_OBJECT (demux, "no session manager element gstrtpbin found"); GST_DEBUG_OBJECT (demux, "no session manager element gstrtpbin found");
return FALSE; return FALSE;
} }
start_session_failure: rtspsrc_failed:
{ {
GST_DEBUG_OBJECT (demux, "could not start session"); GST_DEBUG_OBJECT (demux, "no manager element rtspsrc found");
gst_element_set_state (demux->session, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (demux), demux->session);
demux->session = NULL;
return FALSE; return FALSE;
} }
} }
@ -1245,6 +1296,8 @@ gst_sdp_demux_start (GstSDPDemux * demux)
GstSDPMessage sdp = { 0 }; GstSDPMessage sdp = { 0 };
GstSDPStream *stream = NULL; GstSDPStream *stream = NULL;
GList *walk; GList *walk;
gchar *uri = NULL;
GstStateChangeReturn ret;
/* grab the lock so that no state change can interfere */ /* grab the lock so that no state change can interfere */
GST_SDP_STREAM_LOCK (demux); GST_SDP_STREAM_LOCK (demux);
@ -1305,48 +1358,56 @@ gst_sdp_demux_start (GstSDPDemux * demux)
} }
if (control) { if (control) {
gchar *uri; /* we have RTSP now */
/* we have RTSP redirect now */
uri = gst_sdp_message_as_uri ("rtsp-sdp", &sdp); 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_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_element (GST_OBJECT_CAST (demux), gst_message_new_element (GST_OBJECT_CAST (demux),
gst_structure_new ("redirect", gst_structure_new ("redirect",
"new-location", G_TYPE_STRING, uri, NULL))); "new-location", G_TYPE_STRING, uri, NULL)));
goto sent_redirect; goto sent_redirect;
}
} }
} }
/* try to get and configure a manager */ /* try to get and configure a manager */
if (!gst_sdp_demux_configure_manager (demux)) if (uri) {
goto no_manager; /* 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 */ /* create streams with UDP sources and sinks */
n_streams = gst_sdp_message_medias_len (&sdp); n_streams = gst_sdp_message_medias_len (&sdp);
for (i = 0; i < n_streams; i++) { for (i = 0; i < n_streams; i++) {
stream = gst_sdp_demux_create_stream (demux, &sdp, 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)) if (!gst_sdp_demux_stream_configure_udp (demux, stream))
goto transport_failed; goto transport_failed;
if (!gst_sdp_demux_stream_configure_udp_sink (demux, stream)) if (!gst_sdp_demux_stream_configure_udp_sink (demux, stream))
goto transport_failed; goto transport_failed;
}
} }
/* set target state on session manager */ /* 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 */ if (!uri) {
for (walk = demux->streams; walk; walk = g_list_next (walk)) { /* activate all streams */
stream = (GstSDPStream *) walk->data; for (walk = demux->streams; walk; walk = g_list_next (walk)) {
stream = (GstSDPStream *) walk->data;
/* configure target state on udp sources */ /* configure target state on udp sources */
gst_element_set_state (stream->udpsrc[0], demux->target); gst_element_set_state (stream->udpsrc[0], demux->target);
gst_element_set_state (stream->udpsrc[1], demux->target); gst_element_set_state (stream->udpsrc[1], demux->target);
}
} }
GST_SDP_STREAM_UNLOCK (demux); GST_SDP_STREAM_UNLOCK (demux);
@ -1384,6 +1445,14 @@ sent_redirect:
GST_SDP_STREAM_UNLOCK (demux); GST_SDP_STREAM_UNLOCK (demux);
return FALSE; 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 static gboolean

View file

@ -97,11 +97,13 @@ struct _GstSDPDemux {
gboolean debug; gboolean debug;
guint64 udp_timeout; guint64 udp_timeout;
guint latency; guint latency;
gboolean redirect;
/* session management */ /* session management */
GstElement *session; GstElement *session;
gulong session_sig_id; gulong session_sig_id;
gulong session_ptmap_id; gulong session_ptmap_id;
gulong session_nmp_id;
}; };
struct _GstSDPDemuxClass { struct _GstSDPDemuxClass {