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)
{
media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
media->lock = g_mutex_new ();
media->cond = g_cond_new ();
}
static void
@ -168,6 +170,8 @@ gst_rtsp_media_finalize (GObject * obj)
g_source_destroy (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);
}
@ -467,8 +471,6 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
GST_INFO ("done seeking %d", res);
gst_element_get_state (media->pipeline, NULL, NULL, -1);
GST_INFO ("prerolled again");
collect_media_stats (media);
} else {
GST_INFO ("no seek needed");
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
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);
g_error_free (gerror);
g_free (debug);
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
break;
}
case GST_MESSAGE_WARNING:
@ -1173,6 +1208,12 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message)
break;
case GST_MESSAGE_STREAM_STATUS:
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:
GST_INFO ("%p: got message type %s", media,
gst_message_type_get_name (type));
@ -1263,12 +1304,13 @@ gboolean
gst_rtsp_media_prepare (GstRTSPMedia * media)
{
GstStateChangeReturn ret;
GstRTSPMediaStatus status;
guint i, n_streams;
GstRTSPMediaClass *klass;
GstBus *bus;
GList *walk;
if (media->prepared)
if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED)
goto was_prepared;
if (!media->reusable && media->reused)
@ -1279,6 +1321,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media)
/* reset some variables */
media->is_live = 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));
@ -1344,17 +1388,12 @@ gst_rtsp_media_prepare (GstRTSPMedia * media)
}
/* now wait for all pads to be prerolled */
ret = gst_element_get_state (media->pipeline, NULL, NULL, -1);
if (ret == GST_STATE_CHANGE_FAILURE)
status = gst_rtsp_media_get_status (media);
if (status == GST_RTSP_MEDIA_STATUS_ERROR)
goto state_failed;
/* collect stats about the media */
collect_media_stats (media);
GST_INFO ("object %p is prerolled", media);
media->prepared = TRUE;
return TRUE;
/* OK */
@ -1393,7 +1432,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media)
GstRTSPMediaClass *klass;
gboolean success;
if (!media->prepared)
if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
return TRUE;
GST_INFO ("unprepare media %p", media);
@ -1405,7 +1444,7 @@ gst_rtsp_media_unprepare (GstRTSPMedia * media)
else
success = TRUE;
media->prepared = FALSE;
media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
media->reused = TRUE;
/* when the media is not reusable, this will effectively unref the media and

View file

@ -139,13 +139,29 @@ struct _GstRTSPMediaStream {
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:
* @shared: if this media can be shared between clients
* @reusable: if this media can be reused after an unprepare
* @element: the data providing 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
* @source: the bus watch for pipeline messages.
* @id: the id of the watch
@ -161,33 +177,36 @@ struct _GstRTSPMediaStream {
* This object is usually created from a #GstRTSPMediaFactory.
*/
struct _GstRTSPMedia {
GObject parent;
GObject parent;
gboolean shared;
gboolean reusable;
gboolean reused;
GMutex *lock;
GCond *cond;
GstElement *element;
GArray *streams;
GList *dynamic;
gboolean prepared;
gint active;
gboolean shared;
gboolean reusable;
gboolean reused;
GstElement *element;
GArray *streams;
GList *dynamic;
GstRTSPMediaStatus status;
gint active;
/* the pipeline for the media */
GstElement *pipeline;
GstElement *fakesink;
GSource *source;
guint id;
GstElement *pipeline;
GstElement *fakesink;
GSource *source;
guint id;
gboolean is_live;
gboolean buffering;
GstState target_state;
gboolean is_live;
gboolean buffering;
GstState target_state;
/* RTP session manager */
GstElement *rtpbin;
GstElement *rtpbin;
/* the range of media */
GstRTSPTimeRange range;
GstRTSPTimeRange range;
};
/**

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 (uri != NULL, 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->media = media;