mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-23 06:26: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)
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -161,33 +177,36 @@ struct _GstRTSPMediaStream {
|
||||||
* This object is usually created from a #GstRTSPMediaFactory.
|
* This object is usually created from a #GstRTSPMediaFactory.
|
||||||
*/
|
*/
|
||||||
struct _GstRTSPMedia {
|
struct _GstRTSPMedia {
|
||||||
GObject parent;
|
GObject parent;
|
||||||
|
|
||||||
gboolean shared;
|
GMutex *lock;
|
||||||
gboolean reusable;
|
GCond *cond;
|
||||||
gboolean reused;
|
|
||||||
|
|
||||||
GstElement *element;
|
gboolean shared;
|
||||||
GArray *streams;
|
gboolean reusable;
|
||||||
GList *dynamic;
|
gboolean reused;
|
||||||
gboolean prepared;
|
|
||||||
gint active;
|
GstElement *element;
|
||||||
|
GArray *streams;
|
||||||
|
GList *dynamic;
|
||||||
|
GstRTSPMediaStatus status;
|
||||||
|
gint active;
|
||||||
|
|
||||||
/* the pipeline for the media */
|
/* the pipeline for the media */
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
GstElement *fakesink;
|
GstElement *fakesink;
|
||||||
GSource *source;
|
GSource *source;
|
||||||
guint id;
|
guint id;
|
||||||
|
|
||||||
gboolean is_live;
|
gboolean is_live;
|
||||||
gboolean buffering;
|
gboolean buffering;
|
||||||
GstState target_state;
|
GstState target_state;
|
||||||
|
|
||||||
/* RTP session manager */
|
/* RTP session manager */
|
||||||
GstElement *rtpbin;
|
GstElement *rtpbin;
|
||||||
|
|
||||||
/* the range of media */
|
/* 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 (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;
|
||||||
|
|
Loading…
Reference in a new issue