media: avoid doing _get_state() for state changes

When preparing, use the ASYNC_DONE and ERROR messages in the bus handler to wait
until the media is prerolled or in error. This avoids doing a blocking call of
gst_element_get_state() that can cause lockups when there is an error.

Fixes #611899
This commit is contained in:
Wim Taymans 2010-03-05 17:51:26 +01:00
parent d45eae2edd
commit c7ca9b74eb
3 changed files with 90 additions and 32 deletions

View file

@ -109,6 +109,8 @@ static void
gst_rtsp_media_init (GstRTSPMedia * media) gst_rtsp_media_init (GstRTSPMedia * media)
{ {
media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *)); media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
media->lock = g_mutex_new ();
media->cond = g_cond_new ();
} }
static void static void
@ -168,6 +170,8 @@ gst_rtsp_media_finalize (GObject * obj)
g_source_destroy (media->source); g_source_destroy (media->source);
g_source_unref (media->source); g_source_unref (media->source);
} }
g_mutex_free (media->lock);
g_cond_free (media->cond);
G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj); G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
} }
@ -467,8 +471,6 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
GST_INFO ("done seeking %d", res); GST_INFO ("done seeking %d", res);
gst_element_get_state (media->pipeline, NULL, NULL, -1); gst_element_get_state (media->pipeline, NULL, NULL, -1);
GST_INFO ("prerolled again"); GST_INFO ("prerolled again");
collect_media_stats (media);
} else { } else {
GST_INFO ("no seek needed"); GST_INFO ("no seek needed");
res = TRUE; res = TRUE;
@ -1097,6 +1099,37 @@ unlock_streams (GstRTSPMedia * media)
} }
} }
static void
gst_rtsp_media_set_status (GstRTSPMedia *media, GstRTSPMediaStatus status)
{
g_mutex_lock (media->lock);
/* never overwrite the error status */
if (media->status != GST_RTSP_MEDIA_STATUS_ERROR)
media->status = status;
GST_DEBUG ("setting new status to %d", status);
g_cond_broadcast (media->cond);
g_mutex_unlock (media->lock);
}
static GstRTSPMediaStatus
gst_rtsp_media_get_status (GstRTSPMedia *media)
{
GstRTSPMediaStatus result;
g_mutex_lock (media->lock);
/* while we are preparing, wait */
while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
GST_DEBUG ("waiting for status change");
g_cond_wait (media->cond, media->lock);
}
/* could be success or error */
result = media->status;
GST_DEBUG ("got status %d", result);
g_mutex_unlock (media->lock);
return result;
}
static gboolean static gboolean
default_handle_message (GstRTSPMedia * media, GstMessage * message) default_handle_message (GstRTSPMedia * media, GstMessage * message)
{ {
@ -1156,6 +1189,8 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message)
GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug); GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
g_error_free (gerror); g_error_free (gerror);
g_free (debug); g_free (debug);
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
break; break;
} }
case GST_MESSAGE_WARNING: case GST_MESSAGE_WARNING:
@ -1173,6 +1208,12 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message)
break; break;
case GST_MESSAGE_STREAM_STATUS: case GST_MESSAGE_STREAM_STATUS:
break; break;
case GST_MESSAGE_ASYNC_DONE:
GST_INFO ("%p: got ASYNC_DONE", media);
collect_media_stats (media);
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
break;
default: default:
GST_INFO ("%p: got message type %s", media, GST_INFO ("%p: got message type %s", media,
gst_message_type_get_name (type)); gst_message_type_get_name (type));
@ -1263,12 +1304,13 @@ gboolean
gst_rtsp_media_prepare (GstRTSPMedia * media) gst_rtsp_media_prepare (GstRTSPMedia * media)
{ {
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstRTSPMediaStatus status;
guint i, n_streams; guint i, n_streams;
GstRTSPMediaClass *klass; GstRTSPMediaClass *klass;
GstBus *bus; GstBus *bus;
GList *walk; GList *walk;
if (media->prepared) if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED)
goto was_prepared; goto was_prepared;
if (!media->reusable && media->reused) if (!media->reusable && media->reused)
@ -1279,6 +1321,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media)
/* reset some variables */ /* reset some variables */
media->is_live = FALSE; media->is_live = FALSE;
media->buffering = FALSE; media->buffering = FALSE;
/* we're preparing now */
media->status = GST_RTSP_MEDIA_STATUS_PREPARING;
bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline)); bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
@ -1344,17 +1388,12 @@ gst_rtsp_media_prepare (GstRTSPMedia * media)
} }
/* now wait for all pads to be prerolled */ /* now wait for all pads to be prerolled */
ret = gst_element_get_state (media->pipeline, NULL, NULL, -1); status = gst_rtsp_media_get_status (media);
if (ret == GST_STATE_CHANGE_FAILURE) if (status == GST_RTSP_MEDIA_STATUS_ERROR)
goto state_failed; goto state_failed;
/* collect stats about the media */
collect_media_stats (media);
GST_INFO ("object %p is prerolled", media); GST_INFO ("object %p is prerolled", media);
media->prepared = TRUE;
return TRUE; return TRUE;
/* OK */ /* OK */
@ -1393,7 +1432,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media)
GstRTSPMediaClass *klass; GstRTSPMediaClass *klass;
gboolean success; gboolean success;
if (!media->prepared) if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
return TRUE; return TRUE;
GST_INFO ("unprepare media %p", media); GST_INFO ("unprepare media %p", media);
@ -1405,7 +1444,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media)
else else
success = TRUE; success = TRUE;
media->prepared = FALSE; media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
media->reused = TRUE; media->reused = TRUE;
/* when the media is not reusable, this will effectively unref the media and /* when the media is not reusable, this will effectively unref the media and

View file

@ -139,13 +139,29 @@ struct _GstRTSPMediaStream {
GList *transports; GList *transports;
}; };
/**
* GstRTSPMediaStatus:
* @GST_RTSP_MEDIA_STATUS_UNPREPARED: media pipeline not prerolled
* @GST_RTSP_MEDIA_STATUS_PREPARING: media pipeline is prerolling
* @GST_RTSP_MEDIA_STATUS_PREPARED: media pipeline is prerolled
* @GST_RTSP_MEDIA_STATUS_ERROR: media pipeline is in error
*
* The state of the media pipeline.
*/
typedef enum {
GST_RTSP_MEDIA_STATUS_UNPREPARED = 0,
GST_RTSP_MEDIA_STATUS_PREPARING = 1,
GST_RTSP_MEDIA_STATUS_PREPARED = 2,
GST_RTSP_MEDIA_STATUS_ERROR = 3
} GstRTSPMediaStatus;
/** /**
* GstRTSPMedia: * GstRTSPMedia:
* @shared: if this media can be shared between clients * @shared: if this media can be shared between clients
* @reusable: if this media can be reused after an unprepare * @reusable: if this media can be reused after an unprepare
* @element: the data providing element * @element: the data providing element
* @streams: the different streams provided by @element * @streams: the different streams provided by @element
* @prepared: if the media is prepared for streaming * @status: the status of the media pipeline
* @pipeline: the toplevel pipeline * @pipeline: the toplevel pipeline
* @source: the bus watch for pipeline messages. * @source: the bus watch for pipeline messages.
* @id: the id of the watch * @id: the id of the watch
@ -163,6 +179,9 @@ struct _GstRTSPMediaStream {
struct _GstRTSPMedia { struct _GstRTSPMedia {
GObject parent; GObject parent;
GMutex *lock;
GCond *cond;
gboolean shared; gboolean shared;
gboolean reusable; gboolean reusable;
gboolean reused; gboolean reused;
@ -170,7 +189,7 @@ struct _GstRTSPMedia {
GstElement *element; GstElement *element;
GArray *streams; GArray *streams;
GList *dynamic; GList *dynamic;
gboolean prepared; GstRTSPMediaStatus status;
gint active; gint active;
/* the pipeline for the media */ /* the pipeline for the media */

View file

@ -197,7 +197,7 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri,
g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL); g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
g_return_val_if_fail (uri != NULL, NULL); g_return_val_if_fail (uri != NULL, NULL);
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL); g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
g_return_val_if_fail (media->prepared, NULL); g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
result = g_new0 (GstRTSPSessionMedia, 1); result = g_new0 (GstRTSPSessionMedia, 1);
result->media = media; result->media = media;