mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
Handle media bus messages
Handle media bus messages in a custom mainloop and dispatch them to the RTSPMedia objects. Let the default implementation handle some common messages.
This commit is contained in:
parent
e1154c92d6
commit
cd29e2a454
3 changed files with 202 additions and 14 deletions
|
@ -77,7 +77,6 @@ struct _GstRTSPMediaFactory {
|
||||||
* pay%d to create the streams.
|
* pay%d to create the streams.
|
||||||
* @configure: configure the media created with @construct. The default
|
* @configure: configure the media created with @construct. The default
|
||||||
* implementation will configure the 'shared' property of the media.
|
* implementation will configure the 'shared' property of the media.
|
||||||
* @handle_message: Handle a bus message for @media created from @factory.
|
|
||||||
*
|
*
|
||||||
* The #GstRTSPMediaFactory class structure.
|
* The #GstRTSPMediaFactory class structure.
|
||||||
*/
|
*/
|
||||||
|
@ -89,9 +88,6 @@ struct _GstRTSPMediaFactoryClass {
|
||||||
GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
|
GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
|
||||||
GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
|
GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
|
||||||
void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media);
|
void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media);
|
||||||
|
|
||||||
void (*handle_message) (GstRTSPMediaFactory *factory, GstRTSPMedia *media,
|
|
||||||
GstMessage *message);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_rtsp_media_factory_get_type (void);
|
GType gst_rtsp_media_factory_get_type (void);
|
||||||
|
|
|
@ -34,12 +34,16 @@ static void gst_rtsp_media_set_property (GObject *object, guint propid,
|
||||||
const GValue *value, GParamSpec *pspec);
|
const GValue *value, GParamSpec *pspec);
|
||||||
static void gst_rtsp_media_finalize (GObject * obj);
|
static void gst_rtsp_media_finalize (GObject * obj);
|
||||||
|
|
||||||
|
static gpointer do_loop (GstRTSPMediaClass *klass);
|
||||||
|
static gboolean default_handle_message (GstRTSPMedia *media, GstMessage *message);
|
||||||
|
|
||||||
G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
|
G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
|
gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
gobject_class = G_OBJECT_CLASS (klass);
|
gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
@ -50,6 +54,15 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
|
||||||
g_object_class_install_property (gobject_class, PROP_SHARED,
|
g_object_class_install_property (gobject_class, PROP_SHARED,
|
||||||
g_param_spec_boolean ("shared", "Shared", "If this media pipeline can be shared",
|
g_param_spec_boolean ("shared", "Shared", "If this media pipeline can be shared",
|
||||||
DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
klass->context = g_main_context_new ();
|
||||||
|
klass->loop = g_main_loop_new (klass->context, TRUE);
|
||||||
|
|
||||||
|
klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error);
|
||||||
|
if (error != NULL) {
|
||||||
|
g_critical ("could not start bus thread: %s", error->message);
|
||||||
|
}
|
||||||
|
klass->handle_message = default_handle_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -57,6 +70,8 @@ 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->complete = FALSE;
|
media->complete = FALSE;
|
||||||
|
media->is_live = FALSE;
|
||||||
|
media->buffering = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -87,6 +102,11 @@ gst_rtsp_media_finalize (GObject * obj)
|
||||||
}
|
}
|
||||||
g_array_free (media->streams, TRUE);
|
g_array_free (media->streams, TRUE);
|
||||||
|
|
||||||
|
if (media->source) {
|
||||||
|
g_source_destroy (media->source);
|
||||||
|
g_source_unref (media->source);
|
||||||
|
}
|
||||||
|
|
||||||
if (media->pipeline)
|
if (media->pipeline)
|
||||||
gst_object_unref (media->pipeline);
|
gst_object_unref (media->pipeline);
|
||||||
|
|
||||||
|
@ -123,6 +143,16 @@ gst_rtsp_media_set_property (GObject *object, guint propid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
do_loop (GstRTSPMediaClass *klass)
|
||||||
|
{
|
||||||
|
g_message ("enter mainloop");
|
||||||
|
g_main_loop_run (klass->loop);
|
||||||
|
g_message ("exit mainloop");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_new:
|
* gst_rtsp_media_new:
|
||||||
*
|
*
|
||||||
|
@ -449,6 +479,23 @@ setup_stream (GstRTSPMediaStream *stream, guint idx, GstRTSPMedia *media)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unlock_streams (GstRTSPMedia *media)
|
||||||
|
{
|
||||||
|
guint i, n_streams;
|
||||||
|
|
||||||
|
/* unlock the udp src elements */
|
||||||
|
n_streams = gst_rtsp_media_n_streams (media);
|
||||||
|
for (i = 0; i < n_streams; i++) {
|
||||||
|
GstRTSPMediaStream *stream;
|
||||||
|
|
||||||
|
stream = gst_rtsp_media_get_stream (media, i);
|
||||||
|
|
||||||
|
gst_element_set_locked_state (stream->udpsrc[0], FALSE);
|
||||||
|
gst_element_set_locked_state (stream->udpsrc[1], FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
collect_media_stats (GstRTSPMedia *media)
|
collect_media_stats (GstRTSPMedia *media)
|
||||||
{
|
{
|
||||||
|
@ -474,6 +521,92 @@ collect_media_stats (GstRTSPMedia *media)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
default_handle_message (GstRTSPMedia *media, GstMessage *message)
|
||||||
|
{
|
||||||
|
GstMessageType type;
|
||||||
|
|
||||||
|
type = GST_MESSAGE_TYPE (message);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GST_MESSAGE_STATE_CHANGED:
|
||||||
|
break;
|
||||||
|
case GST_MESSAGE_BUFFERING:
|
||||||
|
{
|
||||||
|
gint percent;
|
||||||
|
|
||||||
|
gst_message_parse_buffering (message, &percent);
|
||||||
|
|
||||||
|
/* no state management needed for live pipelines */
|
||||||
|
if (media->is_live)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (percent == 100) {
|
||||||
|
/* a 100% message means buffering is done */
|
||||||
|
media->buffering = FALSE;
|
||||||
|
/* if the desired state is playing, go back */
|
||||||
|
if (media->target_state == GST_STATE_PLAYING) {
|
||||||
|
g_message ("Buffering done, setting pipeline to PLAYING");
|
||||||
|
gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_message ("Buffering done");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* buffering busy */
|
||||||
|
if (media->buffering == FALSE) {
|
||||||
|
if (media->target_state == GST_STATE_PLAYING) {
|
||||||
|
/* we were not buffering but PLAYING, PAUSE the pipeline. */
|
||||||
|
g_message ("Buffering, setting pipeline to PAUSED ...");
|
||||||
|
gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_message ("Buffering ...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
media->buffering = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_MESSAGE_LATENCY:
|
||||||
|
{
|
||||||
|
gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_MESSAGE_ERROR:
|
||||||
|
{
|
||||||
|
GError *gerror;
|
||||||
|
gchar *debug;
|
||||||
|
|
||||||
|
gst_message_parse_error (message, &gerror, &debug);
|
||||||
|
g_warning ("%p: got error %s (%s)", media, gerror->message, debug);
|
||||||
|
g_error_free (gerror);
|
||||||
|
g_free (debug);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
g_message ("%p: got message type %s", media, gst_message_type_get_name (type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
bus_message (GstBus *bus, GstMessage *message, GstRTSPMedia *media)
|
||||||
|
{
|
||||||
|
GstRTSPMediaClass *klass;
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
klass = GST_RTSP_MEDIA_GET_CLASS (media);
|
||||||
|
|
||||||
|
if (klass->handle_message)
|
||||||
|
ret = klass->handle_message (media, message);
|
||||||
|
else
|
||||||
|
ret = FALSE;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_prepare:
|
* gst_rtsp_media_prepare:
|
||||||
* @obj: a #GstRTSPMedia
|
* @obj: a #GstRTSPMedia
|
||||||
|
@ -488,6 +621,8 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
|
||||||
{
|
{
|
||||||
GstStateChangeReturn ret;
|
GstStateChangeReturn ret;
|
||||||
guint i, n_streams;
|
guint i, n_streams;
|
||||||
|
GstRTSPMediaClass *klass;
|
||||||
|
GstBus *bus;
|
||||||
|
|
||||||
if (media->prepared)
|
if (media->prepared)
|
||||||
goto was_prepared;
|
goto was_prepared;
|
||||||
|
@ -495,6 +630,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
|
||||||
g_message ("preparing media %p", media);
|
g_message ("preparing media %p", media);
|
||||||
|
|
||||||
media->pipeline = gst_pipeline_new ("media-pipeline");
|
media->pipeline = gst_pipeline_new ("media-pipeline");
|
||||||
|
bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
|
||||||
|
|
||||||
gst_bin_add (GST_BIN_CAST (media->pipeline), media->element);
|
gst_bin_add (GST_BIN_CAST (media->pipeline), media->element);
|
||||||
|
|
||||||
|
@ -515,6 +651,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
|
||||||
|
|
||||||
/* first go to PAUSED */
|
/* first go to PAUSED */
|
||||||
ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
|
ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
|
||||||
|
media->target_state = GST_STATE_PAUSED;
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case GST_STATE_CHANGE_SUCCESS:
|
case GST_STATE_CHANGE_SUCCESS:
|
||||||
|
@ -524,6 +661,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
|
||||||
case GST_STATE_CHANGE_NO_PREROLL:
|
case GST_STATE_CHANGE_NO_PREROLL:
|
||||||
/* we need to go to PLAYING */
|
/* we need to go to PLAYING */
|
||||||
g_message ("live media %p", media);
|
g_message ("live media %p", media);
|
||||||
|
media->is_live = TRUE;
|
||||||
ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
|
ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_FAILURE:
|
case GST_STATE_CHANGE_FAILURE:
|
||||||
|
@ -539,18 +677,21 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
|
||||||
/* collect stats about the media */
|
/* collect stats about the media */
|
||||||
collect_media_stats (media);
|
collect_media_stats (media);
|
||||||
|
|
||||||
/* unlock the udp src elements */
|
/* unlock the streams so that they follow the state changes from now on */
|
||||||
n_streams = gst_rtsp_media_n_streams (media);
|
unlock_streams (media);
|
||||||
for (i = 0; i < n_streams; i++) {
|
|
||||||
GstRTSPMediaStream *stream;
|
|
||||||
|
|
||||||
stream = gst_rtsp_media_get_stream (media, i);
|
|
||||||
|
|
||||||
gst_element_set_locked_state (stream->udpsrc[0], FALSE);
|
|
||||||
gst_element_set_locked_state (stream->udpsrc[1], FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_message ("object %p is prerolled", media);
|
g_message ("object %p is prerolled", media);
|
||||||
|
|
||||||
|
/* add the pipeline bus to our custom mainloop */
|
||||||
|
bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
|
||||||
|
media->source = gst_bus_create_watch (bus);
|
||||||
|
gst_object_unref (bus);
|
||||||
|
|
||||||
|
g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL);
|
||||||
|
|
||||||
|
klass = GST_RTSP_MEDIA_GET_CLASS (media);
|
||||||
|
media->id = g_source_attach (media->source, klass->context);
|
||||||
|
|
||||||
media->prepared = TRUE;
|
media->prepared = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -563,7 +704,33 @@ was_prepared:
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
state_failed:
|
state_failed:
|
||||||
{
|
{
|
||||||
|
GstMessage *message;
|
||||||
|
|
||||||
g_message ("state change failed for media %p", media);
|
g_message ("state change failed for media %p", media);
|
||||||
|
while ((message = gst_bus_pop (bus))) {
|
||||||
|
GstMessageType type;
|
||||||
|
|
||||||
|
type = GST_MESSAGE_TYPE (message);
|
||||||
|
switch (type) {
|
||||||
|
case GST_MESSAGE_ERROR:
|
||||||
|
{
|
||||||
|
GError *gerror;
|
||||||
|
gchar *debug;
|
||||||
|
|
||||||
|
gst_message_parse_error (message, &gerror, &debug);
|
||||||
|
g_warning ("%p: got error %s (%s)", media, gerror->message, debug);
|
||||||
|
g_error_free (gerror);
|
||||||
|
g_free (debug);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gst_message_unref (message);
|
||||||
|
}
|
||||||
|
unlock_streams (media);
|
||||||
|
gst_element_set_state (media->pipeline, GST_STATE_NULL);
|
||||||
|
gst_object_unref (bus);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -611,6 +778,7 @@ gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports)
|
||||||
}
|
}
|
||||||
|
|
||||||
g_message ("playing");
|
g_message ("playing");
|
||||||
|
media->target_state = GST_STATE_PLAYING;
|
||||||
ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
|
ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -659,6 +827,7 @@ gst_rtsp_media_pause (GstRTSPMedia *media, GArray *transports)
|
||||||
}
|
}
|
||||||
|
|
||||||
g_message ("pause");
|
g_message ("pause");
|
||||||
|
media->target_state = GST_STATE_PAUSED;
|
||||||
ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
|
ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -685,6 +854,7 @@ gst_rtsp_media_stop (GstRTSPMedia *media, GArray *transports)
|
||||||
gst_rtsp_media_pause (media, transports);
|
gst_rtsp_media_pause (media, transports);
|
||||||
|
|
||||||
g_message ("stop");
|
g_message ("stop");
|
||||||
|
media->target_state = GST_STATE_NULL;
|
||||||
ret = gst_element_set_state (media->pipeline, GST_STATE_NULL);
|
ret = gst_element_set_state (media->pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
|
@ -124,6 +124,12 @@ struct _GstRTSPMedia {
|
||||||
|
|
||||||
/* the pipeline for the media */
|
/* the pipeline for the media */
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
|
GSource *source;
|
||||||
|
guint id;
|
||||||
|
|
||||||
|
gboolean is_live;
|
||||||
|
gboolean buffering;
|
||||||
|
GstState target_state;
|
||||||
|
|
||||||
/* RTP session manager */
|
/* RTP session manager */
|
||||||
GstElement *rtpbin;
|
GstElement *rtpbin;
|
||||||
|
@ -135,8 +141,24 @@ struct _GstRTSPMedia {
|
||||||
GstRTSPTimeRange range;
|
GstRTSPTimeRange range;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstRTSPMediaClass:
|
||||||
|
* @context: the main context for dispatching messages
|
||||||
|
* @loop: the mainloop for message.
|
||||||
|
* @thread: the thread dispatching messages.
|
||||||
|
* @handle_message: handle a message
|
||||||
|
*
|
||||||
|
* The RTSP media class
|
||||||
|
*/
|
||||||
struct _GstRTSPMediaClass {
|
struct _GstRTSPMediaClass {
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
/* thread for the mainloop */
|
||||||
|
GMainContext *context;
|
||||||
|
GMainLoop *loop;
|
||||||
|
GThread *thread;
|
||||||
|
|
||||||
|
gboolean (*handle_message) (GstRTSPMedia *media, GstMessage *message);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_rtsp_media_get_type (void);
|
GType gst_rtsp_media_get_type (void);
|
||||||
|
|
Loading…
Reference in a new issue