mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-22 14:06:23 +00:00
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:
parent
d45eae2edd
commit
c7ca9b74eb
3 changed files with 90 additions and 32 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue