gst/rtsp/URLS: Add some more URLs.

Original commit message from CVS:
* gst/rtsp/URLS:
Add some more URLs.
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init),
(gst_rtspsrc_init), (gst_rtspsrc_finalize),
(gst_rtspsrc_set_property), (gst_rtspsrc_get_property),
(gst_rtspsrc_stream_setup_rtp), (gst_rtspsrc_loop_interleaved),
(gst_rtspsrc_loop_udp), (gst_rtspsrc_loop_send_cmd),
(gst_rtspsrc_loop), (gst_rtspsrc_send),
(gst_rtspsrc_parse_methods), (gst_rtspsrc_open),
(gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
(gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
* gst/rtsp/gstrtspsrc.h:
Add timeout property to control UDP timeouts.
Fix error messages.
Also start a loop function when operating in UDP mode so that we can
do some more stuff async.
Handle element messages from udpsrc to detect timeouts. If a timeout
happens we currently generate an error.
API: rtspsrc::timeout property.
* gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
(gst_udpsrc_create):
Really implement the timeout in microseconds and not milliseconds.
This commit is contained in:
Wim Taymans 2006-09-29 15:37:29 +00:00
parent fcd901a5bf
commit 6e08550345
5 changed files with 221 additions and 74 deletions

View file

@ -1,3 +1,30 @@
2006-09-29 Wim Taymans <wim@fluendo.com>
* gst/rtsp/URLS:
Add some more URLs.
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init),
(gst_rtspsrc_init), (gst_rtspsrc_finalize),
(gst_rtspsrc_set_property), (gst_rtspsrc_get_property),
(gst_rtspsrc_stream_setup_rtp), (gst_rtspsrc_loop_interleaved),
(gst_rtspsrc_loop_udp), (gst_rtspsrc_loop_send_cmd),
(gst_rtspsrc_loop), (gst_rtspsrc_send),
(gst_rtspsrc_parse_methods), (gst_rtspsrc_open),
(gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
(gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
* gst/rtsp/gstrtspsrc.h:
Add timeout property to control UDP timeouts.
Fix error messages.
Also start a loop function when operating in UDP mode so that we can
do some more stuff async.
Handle element messages from udpsrc to detect timeouts. If a timeout
happens we currently generate an error.
API: rtspsrc::timeout property.
* gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
(gst_udpsrc_create):
Really implement the timeout in microseconds and not milliseconds.
2006-09-29 Wim Taymans <wim@fluendo.com> 2006-09-29 Wim Taymans <wim@fluendo.com>
* gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init), * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),

View file

@ -2,6 +2,7 @@ Some test URLS:
SVQ3 video: SVQ3 video:
rtsp://cumulus.creative.auckland.ac.nz/~shado/nelson_iv_512k.mov rtsp://cumulus.creative.auckland.ac.nz/~shado/nelson_iv_512k.mov
rtsp://streamr.hitpops.jp/ngc/mov/m0609.mov
ASF (audio/video): ASF (audio/video):
rtsp://aod.mylisten.com/aod/8/03/069803_0903135.wma rtsp://aod.mylisten.com/aod/8/03/069803_0903135.wma
@ -11,3 +12,7 @@ ASF (audio/video):
MP4V-ES/mpeg4-generic(ACC): MP4V-ES/mpeg4-generic(ACC):
rtsp://vod.nwec.jp/quicktime/505.mov rtsp://vod.nwec.jp/quicktime/505.mov
rtsp://203.140.68.241:554/hirakataeizou9.mp4
REAL:
rtsp://213.254.239.61/farm/*/encoder/tagesschau/live1high.rm

View file

@ -123,6 +123,7 @@ enum
#define DEFAULT_PROTOCOLS GST_RTSP_PROTO_UDP_UNICAST | GST_RTSP_PROTO_UDP_MULTICAST | GST_RTSP_PROTO_TCP #define DEFAULT_PROTOCOLS GST_RTSP_PROTO_UDP_UNICAST | GST_RTSP_PROTO_UDP_MULTICAST | GST_RTSP_PROTO_TCP
#define DEFAULT_DEBUG FALSE #define DEFAULT_DEBUG FALSE
#define DEFAULT_RETRY 20 #define DEFAULT_RETRY 20
#define DEFAULT_TIMEOUT 5000000
enum enum
{ {
@ -131,7 +132,7 @@ enum
PROP_PROTOCOLS, PROP_PROTOCOLS,
PROP_DEBUG, PROP_DEBUG,
PROP_RETRY, PROP_RETRY,
/* FILL ME */ PROP_TIMEOUT,
}; };
#define GST_TYPE_RTSP_PROTO (gst_rtsp_proto_get_type()) #define GST_TYPE_RTSP_PROTO (gst_rtsp_proto_get_type())
@ -161,6 +162,7 @@ static GstCaps *gst_rtspsrc_media_to_caps (gint pt, SDPMedia * media);
static GstStateChangeReturn gst_rtspsrc_change_state (GstElement * element, static GstStateChangeReturn gst_rtspsrc_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
static void gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message);
static void gst_rtspsrc_set_property (GObject * object, guint prop_id, static void gst_rtspsrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
@ -172,6 +174,11 @@ static gboolean gst_rtspsrc_uri_set_uri (GstURIHandler * handler,
static void gst_rtspsrc_loop (GstRTSPSrc * src); static void gst_rtspsrc_loop (GstRTSPSrc * src);
/* commands we send to out loop to notify it of events */
#define CMD_WAIT 0
#define CMD_RECONNECT 1
#define CMD_STOP 2
/*static guint gst_rtspsrc_signals[LAST_SIGNAL] = { 0 }; */ /*static guint gst_rtspsrc_signals[LAST_SIGNAL] = { 0 }; */
static void static void
@ -239,7 +246,15 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
0, G_MAXUINT16, DEFAULT_RETRY, 0, G_MAXUINT16, DEFAULT_RETRY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_TIMEOUT,
g_param_spec_uint64 ("timeout", "Timeout",
"Retry TCP transport after timeout microseconds (0 = disabled)",
0, G_MAXUINT64, DEFAULT_TIMEOUT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
gstelement_class->change_state = gst_rtspsrc_change_state; gstelement_class->change_state = gst_rtspsrc_change_state;
gstbin_class->handle_message = gst_rtspsrc_handle_message;
} }
static void static void
@ -248,6 +263,8 @@ gst_rtspsrc_init (GstRTSPSrc * src, GstRTSPSrcClass * g_class)
src->stream_rec_lock = g_new (GStaticRecMutex, 1); src->stream_rec_lock = g_new (GStaticRecMutex, 1);
g_static_rec_mutex_init (src->stream_rec_lock); g_static_rec_mutex_init (src->stream_rec_lock);
src->loop_cond = g_cond_new ();
src->location = DEFAULT_LOCATION; src->location = DEFAULT_LOCATION;
src->url = NULL; src->url = NULL;
} }
@ -261,6 +278,7 @@ gst_rtspsrc_finalize (GObject * object)
g_static_rec_mutex_free (rtspsrc->stream_rec_lock); g_static_rec_mutex_free (rtspsrc->stream_rec_lock);
g_free (rtspsrc->stream_rec_lock); g_free (rtspsrc->stream_rec_lock);
g_cond_free (rtspsrc->loop_cond);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
@ -287,6 +305,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
case PROP_RETRY: case PROP_RETRY:
rtspsrc->retry = g_value_get_uint (value); rtspsrc->retry = g_value_get_uint (value);
break; break;
case PROP_TIMEOUT:
rtspsrc->timeout = g_value_get_uint64 (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;
@ -314,6 +335,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_RETRY: case PROP_RETRY:
g_value_set_uint (value, rtspsrc->retry); g_value_set_uint (value, rtspsrc->retry);
break; break;
case PROP_TIMEOUT:
g_value_set_uint64 (value, rtspsrc->timeout);
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;
@ -666,6 +690,9 @@ again:
if (*rtpport != tmp_rtp || *rtcpport != tmp_rtcp) if (*rtpport != tmp_rtp || *rtcpport != tmp_rtcp)
goto port_error; goto port_error;
/* configure a timeout */
g_object_set (G_OBJECT (rtpsrc), "timeout", src->timeout, NULL);
/* we manage these elements, we set the caps in configure_transport */ /* we manage these elements, we set the caps in configure_transport */
stream->rtpsrc = rtpsrc; stream->rtpsrc = rtpsrc;
stream->rtcpsrc = rtcpsrc; stream->rtcpsrc = rtcpsrc;
@ -910,7 +937,7 @@ gst_rtspsrc_push_event (GstRTSPSrc * src, GstEvent * event)
} }
static void static void
gst_rtspsrc_loop (GstRTSPSrc * src) gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
{ {
RTSPMessage response = { 0 }; RTSPMessage response = { 0 };
RTSPResult res; RTSPResult res;
@ -928,6 +955,7 @@ gst_rtspsrc_loop (GstRTSPSrc * src)
GST_DEBUG_OBJECT (src, "doing receive"); GST_DEBUG_OBJECT (src, "doing receive");
if ((res = rtsp_connection_receive (src->connection, &response)) < 0) if ((res = rtsp_connection_receive (src->connection, &response)) < 0)
goto receive_error; goto receive_error;
GST_DEBUG_OBJECT (src, "got packet type %d", response.type); GST_DEBUG_OBJECT (src, "got packet type %d", response.type);
} }
while (response.type != RTSP_MESSAGE_DATA); while (response.type != RTSP_MESSAGE_DATA);
@ -1003,8 +1031,8 @@ receive_error:
{ {
gchar *str = rtsp_strresult (res); gchar *str = rtsp_strresult (res);
GST_ELEMENT_ERROR (src, RESOURCE, READ, GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
("Could not receive message. (%s)", str), (NULL)); ("Could not receive message. (%s)", str));
g_free (str); g_free (str);
if (src->debug) if (src->debug)
rtsp_message_dump (&response); rtsp_message_dump (&response);
@ -1014,8 +1042,8 @@ receive_error:
} }
invalid_length: invalid_length:
{ {
GST_ELEMENT_WARNING (src, RESOURCE, READ, GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL),
("Short message received."), (NULL)); ("Short message received."));
rtsp_message_unset (&response); rtsp_message_unset (&response);
return; return;
} }
@ -1049,6 +1077,55 @@ need_pause:
} }
} }
static void
gst_rtspsrc_loop_udp (GstRTSPSrc * src)
{
GST_OBJECT_LOCK (src);
if (src->loop_cmd == CMD_STOP)
goto stopping;
while (src->loop_cmd == CMD_WAIT) {
GST_DEBUG_OBJECT (src, "waiting");
GST_RTSP_LOOP_WAIT (src);
GST_DEBUG_OBJECT (src, "waiting done");
if (src->loop_cmd == CMD_STOP)
goto stopping;
}
if (src->loop_cmd == CMD_RECONNECT) {
/* FIXME, when we get here we have to reconnect using tcp */
src->loop_cmd = CMD_WAIT;
}
GST_OBJECT_UNLOCK (src);
return;
/* ERRORS */
stopping:
{
GST_OBJECT_UNLOCK (src);
src->running = FALSE;
gst_task_pause (src->task);
return;
}
}
static void
gst_rtspsrc_loop_send_cmd (GstRTSPSrc * src, gint cmd)
{
GST_OBJECT_LOCK (src);
src->loop_cmd = cmd;
GST_RTSP_LOOP_SIGNAL (src);
GST_OBJECT_UNLOCK (src);
}
static void
gst_rtspsrc_loop (GstRTSPSrc * src)
{
if (src->interleaved)
gst_rtspsrc_loop_interleaved (src);
else
gst_rtspsrc_loop_udp (src);
}
/** /**
* gst_rtspsrc_send: * gst_rtspsrc_send:
* @src: the rtsp source * @src: the rtsp source
@ -1100,8 +1177,8 @@ send_error:
{ {
gchar *str = rtsp_strresult (res); gchar *str = rtsp_strresult (res);
GST_ELEMENT_ERROR (src, RESOURCE, WRITE, GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
("Could not send message. (%s)", res), (NULL)); ("Could not send message. (%s)", res));
g_free (str); g_free (str);
return FALSE; return FALSE;
} }
@ -1109,8 +1186,8 @@ receive_error:
{ {
gchar *str = rtsp_strresult (res); gchar *str = rtsp_strresult (res);
GST_ELEMENT_ERROR (src, RESOURCE, READ, GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
("Could not receive message. (%s)", str), (NULL)); ("Could not receive message. (%s)", str));
g_free (str); g_free (str);
return FALSE; return FALSE;
} }
@ -1118,13 +1195,13 @@ error_response:
{ {
switch (response->type_data.response.code) { switch (response->type_data.response.code) {
case RTSP_STS_NOT_FOUND: case RTSP_STS_NOT_FOUND:
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), ("%s",
response->type_data.response.reason), (NULL)); response->type_data.response.reason));
break; break;
default: default:
GST_ELEMENT_ERROR (src, RESOURCE, READ, ("Got error response: %d (%s).", GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
response->type_data.response.code, ("Got error response: %d (%s).", response->type_data.response.code,
response->type_data.response.reason), (NULL)); response->type_data.response.reason));
break; break;
} }
/* we return FALSE so we should unset the response ourselves */ /* we return FALSE so we should unset the response ourselves */
@ -1192,14 +1269,14 @@ done:
/* ERRORS */ /* ERRORS */
no_describe: no_describe:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
("Server does not support DESCRIBE."), (NULL)); ("Server does not support DESCRIBE."));
return FALSE; return FALSE;
} }
no_setup: no_setup:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
("Server does not support SETUP."), (NULL)); ("Server does not support SETUP."));
return FALSE; return FALSE;
} }
} }
@ -1216,6 +1293,7 @@ gst_rtspsrc_open (GstRTSPSrc * src)
SDPMessage sdp = { 0 }; SDPMessage sdp = { 0 };
GstRTSPProto protocols; GstRTSPProto protocols;
GstRTSPStream *stream = NULL; GstRTSPStream *stream = NULL;
gchar *respcont = NULL;
/* can't continue without a valid url */ /* can't continue without a valid url */
if (G_UNLIKELY (src->url == NULL)) if (G_UNLIKELY (src->url == NULL))
@ -1261,22 +1339,18 @@ gst_rtspsrc_open (GstRTSPSrc * src)
goto send_error; goto send_error;
/* check if reply is SDP */ /* check if reply is SDP */
{ rtsp_message_get_header (&response, RTSP_HDR_CONTENT_TYPE, &respcont);
gchar *respcont = NULL; /* could not be set but since the request returned OK, we assume it
* was SDP, else check it. */
rtsp_message_get_header (&response, RTSP_HDR_CONTENT_TYPE, &respcont); if (respcont) {
/* could not be set but since the request returned OK, we assume it if (!g_ascii_strcasecmp (respcont, "application/sdp") == 0)
* was SDP, else check it. */ goto wrong_content_type;
if (respcont) {
if (!g_ascii_strcasecmp (respcont, "application/sdp") == 0)
goto wrong_content_type;
}
} }
/* get message body and parse as SDP */ /* get message body and parse as SDP */
rtsp_message_get_body (&response, &data, &size); rtsp_message_get_body (&response, &data, &size);
GST_DEBUG_OBJECT (src, "parse sdp..."); GST_DEBUG_OBJECT (src, "parse SDP...");
sdp_message_init (&sdp); sdp_message_init (&sdp);
sdp_message_parse_buffer (data, size, &sdp); sdp_message_parse_buffer (data, size, &sdp);
@ -1462,16 +1536,16 @@ gst_rtspsrc_open (GstRTSPSrc * src)
/* ERRORS */ /* ERRORS */
no_url: no_url:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
("No valid RTSP url was provided"), (NULL)); ("No valid RTSP URL was provided"));
goto cleanup_error; goto cleanup_error;
} }
could_not_create: could_not_create:
{ {
gchar *str = rtsp_strresult (res); gchar *str = rtsp_strresult (res);
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
("Could not create connection. (%s)", str), (NULL)); ("Could not create connection. (%s)", str));
g_free (str); g_free (str);
goto cleanup_error; goto cleanup_error;
} }
@ -1479,8 +1553,8 @@ could_not_connect:
{ {
gchar *str = rtsp_strresult (res); gchar *str = rtsp_strresult (res);
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
("Could not connect to server. (%s)", str), (NULL)); ("Could not connect to server. (%s)", str));
g_free (str); g_free (str);
goto cleanup_error; goto cleanup_error;
} }
@ -1488,8 +1562,8 @@ create_request_failed:
{ {
gchar *str = rtsp_strresult (res); gchar *str = rtsp_strresult (res);
GST_ELEMENT_ERROR (src, LIBRARY, INIT, GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
("Could not create request. (%s)", str), (NULL)); ("Could not create request. (%s)", str));
g_free (str); g_free (str);
goto cleanup_error; goto cleanup_error;
} }
@ -1497,8 +1571,8 @@ send_error:
{ {
gchar *str = rtsp_strresult (res); gchar *str = rtsp_strresult (res);
GST_ELEMENT_ERROR (src, RESOURCE, WRITE, GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
("Could not send message. (%s)", str), (NULL)); ("Could not send message. (%s)", str));
g_free (str); g_free (str);
goto cleanup_error; goto cleanup_error;
} }
@ -1509,20 +1583,20 @@ methods_error:
} }
wrong_content_type: wrong_content_type:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
("Server does not support SDP."), (NULL)); ("Server does not support SDP, got %s.", respcont));
goto cleanup_error; goto cleanup_error;
} }
setup_rtp_failed: setup_rtp_failed:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, ("Could not setup rtp."), GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
(NULL)); ("Could not setup rtp."));
goto cleanup_error; goto cleanup_error;
} }
no_transport: no_transport:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
("Server did not select transport."), (NULL)); ("Server did not select transport."));
goto cleanup_error; goto cleanup_error;
} }
cleanup_error: cleanup_error:
@ -1542,6 +1616,8 @@ gst_rtspsrc_close (GstRTSPSrc * src)
GST_DEBUG_OBJECT (src, "TEARDOWN..."); GST_DEBUG_OBJECT (src, "TEARDOWN...");
gst_rtspsrc_loop_send_cmd (src, CMD_STOP);
/* stop task if any */ /* stop task if any */
if (src->task) { if (src->task) {
gst_task_stop (src->task); gst_task_stop (src->task);
@ -1582,20 +1658,20 @@ gst_rtspsrc_close (GstRTSPSrc * src)
/* ERRORS */ /* ERRORS */
create_request_failed: create_request_failed:
{ {
GST_ELEMENT_ERROR (src, LIBRARY, INIT, GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
("Could not create request."), (NULL)); ("Could not create request."));
return FALSE; return FALSE;
} }
send_error: send_error:
{ {
rtsp_message_unset (&request); rtsp_message_unset (&request);
GST_ELEMENT_ERROR (src, RESOURCE, WRITE, GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
("Could not send message."), (NULL)); ("Could not send message."));
return FALSE; return FALSE;
} }
close_failed: close_failed:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, ("Close failed."), (NULL)); GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, (NULL), ("Close failed."));
return FALSE; return FALSE;
} }
} }
@ -1660,29 +1736,28 @@ gst_rtspsrc_play (GstRTSPSrc * src)
/* for interleaved transport, we receive the data on the RTSP connection /* for interleaved transport, we receive the data on the RTSP connection
* instead of UDP. We start a task to select and read from that connection. */ * instead of UDP. We start a task to select and read from that connection. */
if (src->interleaved) { if (src->task == NULL) {
if (src->task == NULL) { src->task = gst_task_create ((GstTaskFunction) gst_rtspsrc_loop, src);
src->task = gst_task_create ((GstTaskFunction) gst_rtspsrc_loop, src); gst_task_set_lock (src->task, src->stream_rec_lock);
gst_task_set_lock (src->task, src->stream_rec_lock);
}
src->running = TRUE;
gst_task_start (src->task);
} }
src->running = TRUE;
gst_rtspsrc_loop_send_cmd (src, CMD_WAIT);
gst_task_start (src->task);
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
create_request_failed: create_request_failed:
{ {
GST_ELEMENT_ERROR (src, LIBRARY, INIT, GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
("Could not create request."), (NULL)); ("Could not create request."));
return FALSE; return FALSE;
} }
send_error: send_error:
{ {
rtsp_message_unset (&request); rtsp_message_unset (&request);
GST_ELEMENT_ERROR (src, RESOURCE, WRITE, GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
("Could not send message."), (NULL)); ("Could not send message."));
return FALSE; return FALSE;
} }
} }
@ -1714,19 +1789,49 @@ gst_rtspsrc_pause (GstRTSPSrc * src)
/* ERRORS */ /* ERRORS */
create_request_failed: create_request_failed:
{ {
GST_ELEMENT_ERROR (src, LIBRARY, INIT, GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
("Could not create request."), (NULL)); ("Could not create request."));
return FALSE; return FALSE;
} }
send_error: send_error:
{ {
rtsp_message_unset (&request); rtsp_message_unset (&request);
GST_ELEMENT_ERROR (src, RESOURCE, WRITE, GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
("Could not send message."), (NULL)); ("Could not send message."));
return FALSE; return FALSE;
} }
} }
static void
gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message)
{
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ELEMENT:
{
GstRTSPSrc *rtspsrc;
const GstStructure *s = gst_message_get_structure (message);
rtspsrc = GST_RTSPSRC (bin);
if (gst_structure_has_name (s, "GstUDPSrcTimeout")) {
GST_DEBUG_OBJECT (bin, "timeout on UDP port");
gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_RECONNECT);
/* FIXME, we post an error message now to inform the user
* that nothing happened. It's most likely a firewall thing. */
GST_ELEMENT_ERROR (rtspsrc, RESOURCE, READ, (NULL),
("Could not receive any UDP packets for %" G_GUINT64_FORMAT
".%d seconds, maybe your firewall is blocking it.",
rtspsrc->timeout / 1000000, rtspsrc->timeout % 1000000));
return;
}
}
/* Fallthrough */
default:
GST_BIN_CLASS (parent_class)->handle_message (bin, message);
break;
}
}
static GstStateChangeReturn static GstStateChangeReturn
gst_rtspsrc_change_state (GstElement * element, GstStateChange transition) gst_rtspsrc_change_state (GstElement * element, GstStateChange transition)
{ {
@ -1735,7 +1840,6 @@ gst_rtspsrc_change_state (GstElement * element, GstStateChange transition)
rtspsrc = GST_RTSPSRC (element); rtspsrc = GST_RTSPSRC (element);
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_NULL_TO_READY:
break; break;

View file

@ -61,10 +61,16 @@ G_BEGIN_DECLS
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTSPSRC)) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTSPSRC))
#define GST_IS_RTSPSRC_CLASS(klass) \ #define GST_IS_RTSPSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTSPSRC)) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTSPSRC))
#define GST_RTSPSRC_CAST(obj) \
((GstRTSPSrc *)(obj))
typedef struct _GstRTSPSrc GstRTSPSrc; typedef struct _GstRTSPSrc GstRTSPSrc;
typedef struct _GstRTSPSrcClass GstRTSPSrcClass; typedef struct _GstRTSPSrcClass GstRTSPSrcClass;
#define GST_RTSP_LOOP_GET_COND(rtsp) (GST_RTSPSRC_CAST(rtsp)->loop_cond)
#define GST_RTSP_LOOP_WAIT(rtsp) (g_cond_wait(GST_RTSP_LOOP_GET_COND (rtsp), GST_OBJECT_GET_LOCK (rtsp)))
#define GST_RTSP_LOOP_SIGNAL(rtsp) (g_cond_signal(GST_RTSP_LOOP_GET_COND (rtsp)))
/** /**
* GstRTSPProto: * GstRTSPProto:
* @GST_RTSP_PROTO_UDP_UNICAST: Use unicast UDP transfer. * @GST_RTSP_PROTO_UDP_UNICAST: Use unicast UDP transfer.
@ -126,16 +132,21 @@ struct _GstRTSPSrc {
GstSegment segment; GstSegment segment;
gboolean running; gboolean running;
/* cond to signal loop */
GCond *loop_cond;
gint loop_cmd;
gint numstreams; gint numstreams;
GList *streams; GList *streams;
GstStructure *props; GstStructure *props;
gchar *location; gchar *location;
RTSPUrl *url; RTSPUrl *url;
GstRTSPProto protocols;
gboolean debug; gboolean debug;
guint retry; guint retry;
guint64 timeout;
GstRTSPProto protocols;
/* supported methods */ /* supported methods */
gint methods; gint methods;

View file

@ -89,8 +89,8 @@
* <listitem> * <listitem>
* <para> * <para>
* #guint64 * #guint64
* <classname>&quot;timeout&quot;</classname>: the timeout that expired when * <classname>&quot;timeout&quot;</classname>: the timeout in microseconds that
* waiting for data. * expired when waiting for data.
* </para> * </para>
* </listitem> * </listitem>
* </itemizedlist> * </itemizedlist>
@ -250,8 +250,8 @@ gst_udpsrc_class_init (GstUDPSrcClass * klass)
UDP_DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE)); UDP_DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMEOUT, g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMEOUT,
g_param_spec_uint64 ("timeout", "Timeout", g_param_spec_uint64 ("timeout", "Timeout",
"Post a message after this timeout (in microseconds) (0 = disabled)", "Post a message after timeout microseconds (0 = disabled)", 0,
0, G_MAXUINT64, UDP_DEFAULT_TIMEOUT, G_PARAM_READWRITE)); G_MAXUINT64, UDP_DEFAULT_TIMEOUT, G_PARAM_READWRITE));
gstbasesrc_class->start = gst_udpsrc_start; gstbasesrc_class->start = gst_udpsrc_start;
gstbasesrc_class->stop = gst_udpsrc_stop; gstbasesrc_class->stop = gst_udpsrc_stop;
@ -331,8 +331,8 @@ gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
udpsrc->timeout); udpsrc->timeout);
if (udpsrc->timeout > 0) { if (udpsrc->timeout > 0) {
timeval.tv_sec = udpsrc->timeout / 1000; timeval.tv_sec = udpsrc->timeout / 1000000;
timeval.tv_usec = (udpsrc->timeout % 1000) * 1000; timeval.tv_usec = udpsrc->timeout % 1000000;
timeout = &timeval; timeout = &timeval;
} else { } else {
timeout = NULL; timeout = NULL;