From 1a5201826cb9b6204dcc8f0e5eeea0e1dd47eebb Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Mon, 21 Feb 2005 11:54:55 +0000 Subject: [PATCH] gst/gstmessage.h (GstMessageType): Turned into flags. Added Original commit message from CVS: 2005-02-21 Andy Wingo * gst/gstmessage.h (GstMessageType): Turned into flags. Added GST_MESSAGE_ANY as an OR of all flags. (GST_MESSAGE_PARSE_STATE_CHANGED): New terrible macro. Will be made into a function soon. (GstMessage): Add a state_changed structure to the union. The union will die soon in favor of a single GstStructure tho. (gst_message_new_state_changed): New API. * gst/gstmessage.c (gst_message_new_state_changed): New API. * tools/gst-launch.c (check_intr): Set the state of the pipeline to PAUSED here; the poll will catch the state change. (event_loop): New function, polls the pipeline bus for events. Can block until eos/error/state change, or just handle the pending events. (main): Changed to use event_loop instead of running a main loop. * gst/gstbus.h (gst_bus_poll): Added. (gst_bus_peek): Return non-const; the message is refcounted anyway. * gst/gstbus.c (gst_bus_init): Replace the GAsyncQueue with a GQueue+mutex to allow for _peek. (The wake-up functionality provided by GAsyncQueue is already done by our socketpair.) All queue users changed to lock, operate, and unlock. (gst_bus_post): Check the retval of write(2) and handle errno. (gst_bus_peek): Implemented. (gst_bus_pop, gst_bus_peek, bus_callback): Because the socketpair is used to wake up the GSource, read off the character in the GSource handler and not in pop/peek. This is because a peek will require a pop in the future, and you can't read off the char twice. Deal with errno in the read. (bus_callback): Interpret the handler return value as whether or not to pop the message from the bus. (poll_handler, poll_timeout, gst_bus_poll): New API. gst_bus_poll is meant to replace the while(gst_bin_iterate()) idiom. --- ChangeLog | 39 +++++++++ gst/gstbus.c | 194 +++++++++++++++++++++++++++++++++++++++++---- gst/gstbus.h | 9 ++- gst/gstelement.c | 55 ++++++------- gst/gstmessage.c | 22 +++++ gst/gstmessage.h | 32 +++++--- tools/gst-launch.c | 110 +++++++++++++++---------- 7 files changed, 360 insertions(+), 101 deletions(-) diff --git a/ChangeLog b/ChangeLog index 139095f7e4..777a4ae92a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2005-02-21 Andy Wingo + + * gst/gstmessage.h (GstMessageType): Turned into flags. Added + GST_MESSAGE_ANY as an OR of all flags. + (GST_MESSAGE_PARSE_STATE_CHANGED): New terrible macro. Will be + made into a function soon. + (GstMessage): Add a state_changed structure to the union. The + union will die soon in favor of a single GstStructure tho. + (gst_message_new_state_changed): New API. + + * gst/gstmessage.c (gst_message_new_state_changed): New API. + + * tools/gst-launch.c (check_intr): Set the state of the pipeline + to PAUSED here; the poll will catch the state change. + (event_loop): New function, polls the pipeline bus for events. Can + block until eos/error/state change, or just handle the pending + events. + (main): Changed to use event_loop instead of running a main loop. + + * gst/gstbus.h (gst_bus_poll): Added. + (gst_bus_peek): Return non-const; the message is refcounted + anyway. + + * gst/gstbus.c (gst_bus_init): Replace the GAsyncQueue with a + GQueue+mutex to allow for _peek. (The wake-up functionality + provided by GAsyncQueue is already done by our socketpair.) All + queue users changed to lock, operate, and unlock. + (gst_bus_post): Check the retval of write(2) and handle errno. + (gst_bus_peek): Implemented. + (gst_bus_pop, gst_bus_peek, bus_callback): Because the socketpair + is used to wake up the GSource, read off the character in the + GSource handler and not in pop/peek. This is because a peek will + require a pop in the future, and you can't read off the char + twice. Deal with errno in the read. + (bus_callback): Interpret the handler return value as whether or + not to pop the message from the bus. + (poll_handler, poll_timeout, gst_bus_poll): New API. gst_bus_poll + is meant to replace the while(gst_bin_iterate()) idiom. + 2005-02-18 Andy Wingo * gst/elements/gstfakesrc.c (gst_fakesrc_class_init): Add HAS_LOOP diff --git a/gst/gstbus.c b/gst/gstbus.c index 2c0d4cc782..23d368dc29 100644 --- a/gst/gstbus.c +++ b/gst/gstbus.c @@ -20,6 +20,7 @@ */ +#include #include #include #include @@ -93,7 +94,8 @@ gst_bus_class_init (GstBusClass * klass) static void gst_bus_init (GstBus * bus) { - bus->queue = g_async_queue_new (); + bus->queue = g_queue_new (); + bus->queue_lock = g_mutex_new (); if (socketpair (PF_UNIX, SOCK_STREAM, 0, bus->control_socket) < 0) goto no_socketpair; @@ -126,8 +128,12 @@ gst_bus_dispose (GObject * object) close (bus->control_socket[1]); if (bus->queue) { - g_async_queue_unref (bus->queue); + g_mutex_lock (bus->queue_lock); + g_queue_free (bus->queue); bus->queue = NULL; + g_mutex_unlock (bus->queue_lock); + g_mutex_free (bus->queue_lock); + bus->queue_lock = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); @@ -191,6 +197,7 @@ gst_bus_post (GstBus * bus, GstMessage * message) GstBusSyncReply reply = GST_BUS_PASS; GstBusSyncHandler handler; gpointer handler_data; + ssize_t write_ret = -1; g_return_val_if_fail (GST_IS_BUS (bus), FALSE); g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE); @@ -214,9 +221,22 @@ gst_bus_post (GstBus * bus, GstMessage * message) break; case GST_BUS_PASS: /* pass the message to the async queue */ - g_async_queue_push (bus->queue, message); + g_mutex_lock (bus->queue_lock); + g_queue_push_tail (bus->queue, message); + g_mutex_unlock (bus->queue_lock); c = 'p'; - write (bus->control_socket[1], &c, 1); + errno = EAGAIN; + while (write_ret == -1) { + switch (errno) { + case EAGAIN: + case EINTR: + break; + default: + perror ("gst_bus_post: could not write to fd"); + return FALSE; + } + write_ret = write (bus->control_socket[1], &c, 1); + } break; case GST_BUS_ASYNC: { @@ -234,9 +254,22 @@ gst_bus_post (GstBus * bus, GstMessage * message) * queue. When the message is handled by the app and destroyed, * the cond will be signalled and we can continue */ g_mutex_lock (lock); - g_async_queue_push (bus->queue, message); + g_mutex_lock (bus->queue_lock); + g_queue_push_tail (bus->queue, message); + g_mutex_unlock (bus->queue_lock); c = 'p'; - write (bus->control_socket[1], &c, 1); + errno = EAGAIN; + while (write_ret == -1) { + switch (errno) { + case EAGAIN: + case EINTR: + break; + default: + perror ("gst_bus_post: could not write to fd"); + return FALSE; + } + write_ret = write (bus->control_socket[1], &c, 1); + } /* now block till the message is freed */ g_cond_wait (cond, lock); g_mutex_unlock (lock); @@ -270,7 +303,9 @@ gst_bus_have_pending (GstBus * bus) g_return_val_if_fail (GST_IS_BUS (bus), FALSE); - length = g_async_queue_length (bus->queue); + g_mutex_lock (bus->queue_lock); + length = g_queue_get_length (bus->queue); + g_mutex_unlock (bus->queue_lock); return (length > 0); } @@ -281,8 +316,7 @@ gst_bus_have_pending (GstBus * bus) * * Get a message from the bus. * - * Returns: The #GstMessage that is on the bus or NULL when there are no - * messages available. + * Returns: The #GstMessage that is on the bus, or NULL if the bus is empty. * * MT safe. */ @@ -290,12 +324,37 @@ GstMessage * gst_bus_pop (GstBus * bus) { GstMessage *message; - gchar c; - g_return_val_if_fail (GST_IS_BUS (bus), FALSE); + g_return_val_if_fail (GST_IS_BUS (bus), NULL); - message = g_async_queue_pop (bus->queue); - read (bus->control_socket[0], &c, 1); + g_mutex_lock (bus->queue_lock); + message = g_queue_pop_head (bus->queue); + g_mutex_unlock (bus->queue_lock); + + return message; +} + +/** + * gst_bus_peek: + * @bus: a #GstBus + * + * Peek the message on the top of the bus' queue. The bus maintains ownership of + * the message, and the message will remain on the bus' message queue. + * + * Returns: The #GstMessage that is on the bus, or NULL if the bus is empty. + * + * MT safe. + */ +GstMessage * +gst_bus_peek (GstBus * bus) +{ + GstMessage *message; + + g_return_val_if_fail (GST_IS_BUS (bus), NULL); + + g_mutex_lock (bus->queue_lock); + message = g_queue_peek_head (bus->queue); + g_mutex_unlock (bus->queue_lock); return message; } @@ -357,13 +416,36 @@ static gboolean bus_callback (GIOChannel * channel, GIOCondition cond, GstBusWatch * watch) { GstMessage *message; + gboolean needs_pop = TRUE; + gchar c; + ssize_t read_ret = -1; g_return_val_if_fail (GST_IS_BUS (watch->bus), FALSE); - message = gst_bus_pop (watch->bus); + /* the char in the fd is essentially just a way to wake us up. read it off so + we're not woken up again. */ + errno = EAGAIN; + while (read_ret == -1) { + switch (errno) { + case EAGAIN: + case EINTR: + break; + default: + perror ("gst_bus_pop: could not read from fd"); + return TRUE; + } + read_ret = read (watch->bus->control_socket[0], &c, 1); + } + + message = gst_bus_peek (watch->bus); + + g_return_val_if_fail (message != NULL, TRUE); if (watch->handler) - watch->handler (watch->bus, message, watch->user_data); + needs_pop = watch->handler (watch->bus, message, watch->user_data); + + if (needs_pop) + gst_message_unref (gst_bus_pop (watch->bus)); return TRUE; } @@ -381,8 +463,12 @@ bus_destroy (GstBusWatch * watch) /** * gst_bus_add_watch_full: * @bus: a #GstBus to create the watch for + * @handler: A function to call when a message is received. * - * Adds the bus to the mainloop with the given priority. + * Adds the bus to the mainloop with the given priority. If the handler returns + * TRUE, the message will then be popped off the queue. When the handler is + * called, the message belongs to the caller; if you want to keep a copy of it, + * call gst_message_ref before leaving the handler. * * Returns: The event source id. * @@ -435,3 +521,79 @@ gst_bus_add_watch (GstBus * bus, GstBusHandler handler, gpointer user_data) return gst_bus_add_watch_full (bus, G_PRIORITY_DEFAULT, handler, user_data, NULL); } + +typedef struct +{ + GMainLoop *loop; + guint timeout_id; + GstMessageType events; + GstMessageType revent; +} GstBusPollData; + +static gboolean +poll_handler (GstBus * bus, GstMessage * message, GstBusPollData * poll_data) +{ + if (GST_MESSAGE_TYPE (message) & poll_data->events) { + poll_data->revent = GST_MESSAGE_TYPE (message); + if (g_main_loop_is_running (poll_data->loop)) + g_main_loop_quit (poll_data->loop); + /* keep the message on the queue */ + return FALSE; + } else { + /* pop and unref the message */ + return TRUE; + } +} + +static gboolean +poll_timeout (GstBusPollData * poll_data) +{ + poll_data->timeout_id = 0; + g_main_loop_quit (poll_data->loop); + /* returning FALSE will remove the source id */ + return FALSE; +} + +/** + * gst_bus_poll: + * @bus: a #GstBus + * @events: a mask of #GstMessageType, representing the set of message types to + * poll for. + * @timeout: the poll timeout, as a #GstClockTimeDiff, or -1 to poll indefinitely. + * + * Poll the bus for events. Will block while waiting for events to come. You can + * specify a maximum time to poll with the @timeout parameter. If @timeout is + * negative, this function will block indefinitely. + * + * Returns: The type of the message that was received, or GST_MESSAGE_UNKNOWN if + * the poll timed out. The message will remain in the bus queue; you will need + * to gst_bus_pop() it off before entering gst_bus_poll() again. + */ +GstMessageType +gst_bus_poll (GstBus * bus, GstMessageType events, GstClockTimeDiff timeout) +{ + GstBusPollData *poll_data; + GstMessageType ret; + guint id; + + poll_data = g_new0 (GstBusPollData, 1); + if (timeout >= 0) + poll_data->timeout_id = g_timeout_add (timeout / GST_MSECOND, + (GSourceFunc) poll_timeout, poll_data); + poll_data->loop = g_main_loop_new (NULL, FALSE); + poll_data->events = events; + poll_data->revent = GST_MESSAGE_UNKNOWN; + + id = gst_bus_add_watch (bus, (GstBusHandler) poll_handler, poll_data); + g_main_loop_run (poll_data->loop); + g_source_remove (id); + + ret = poll_data->revent; + + if (poll_data->timeout_id) + g_source_remove (poll_data->timeout_id); + g_main_loop_unref (poll_data->loop); + g_free (poll_data); + + return ret; +} diff --git a/gst/gstbus.h b/gst/gstbus.h index 804ffc831c..cc49f63b29 100644 --- a/gst/gstbus.h +++ b/gst/gstbus.h @@ -24,6 +24,7 @@ #include #include +#include G_BEGIN_DECLS @@ -51,7 +52,8 @@ struct _GstBus GstObject object; /*< private > */ - GAsyncQueue *queue; + GQueue *queue; + GMutex *queue_lock; GstBusSyncHandler sync_handler; gpointer sync_handler_data; @@ -78,7 +80,7 @@ GstBus* gst_bus_new (void); gboolean gst_bus_post (GstBus * bus, GstMessage * message); gboolean gst_bus_have_pending (GstBus * bus); -const GstMessage * gst_bus_peek (GstBus * bus); +GstMessage * gst_bus_peek (GstBus * bus); GstMessage * gst_bus_pop (GstBus * bus); void gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func, @@ -93,6 +95,9 @@ guint gst_bus_add_watch_full (GstBus * bus, guint gst_bus_add_watch (GstBus * bus, GstBusHandler handler, gpointer user_data); +GstMessageType gst_bus_poll (GstBus *bus, GstMessageType events, + GstClockTimeDiff timeout); + G_END_DECLS #endif /* __GST_BUS_H__ */ diff --git a/gst/gstelement.c b/gst/gstelement.c index 7c06e57dc0..bf3cccfed2 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -1717,6 +1717,7 @@ void gst_element_commit_state (GstElement * element) { GstElementState pending; + GstMessage *message; g_return_if_fail (GST_IS_ELEMENT (element)); @@ -1735,6 +1736,9 @@ gst_element_commit_state (GstElement * element) g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], 0, old_state, pending); + message = gst_message_new_state_changed (GST_OBJECT (element), + old_state, pending)); + gst_element_post_message (element, message); GST_STATE_BROADCAST (element); } } @@ -1753,8 +1757,7 @@ gst_element_commit_state (GstElement * element) * MT safe. */ GstElementStateReturn -gst_element_set_state (GstElement * element, GstElementState state) -{ + gst_element_set_state (GstElement * element, GstElementState state) { GstElementClass *oclass; GstElementState current; GstElementStateReturn return_val = GST_STATE_SUCCESS; @@ -1876,7 +1879,7 @@ invalid_return: * when pads are added to elements? */ static gboolean -gst_element_pads_activate (GstElement * element, gboolean active) + gst_element_pads_activate (GstElement * element, gboolean active) { GList *pads; gboolean result; @@ -1967,8 +1970,7 @@ restart: } /* is called with STATE_LOCK */ -static GstElementStateReturn -gst_element_change_state (GstElement * element) +static GstElementStateReturn gst_element_change_state (GstElement * element) { GstElementState old_state; gint old_pending, old_transition; @@ -2044,16 +2046,14 @@ gst_element_change_state (GstElement * element) * * Returns: the #GstElementFactory used for creating this element. */ -GstElementFactory * -gst_element_get_factory (GstElement * element) +GstElementFactory *gst_element_get_factory (GstElement * element) { g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); return GST_ELEMENT_GET_CLASS (element)->elementfactory; } -static void -gst_element_dispose (GObject * object) +static void gst_element_dispose (GObject * object) { GstElement *element = GST_ELEMENT (object); @@ -2081,8 +2081,7 @@ gst_element_dispose (GObject * object) G_OBJECT_CLASS (parent_class)->dispose (object); } -static void -gst_element_finalize (GObject * object) +static void gst_element_finalize (GObject * object) { GstElement *element = GST_ELEMENT (object); @@ -2111,13 +2110,14 @@ gst_element_finalize (GObject * object) * Returns: the new #xmlNodePtr. */ static xmlNodePtr -gst_element_save_thyself (GstObject * object, xmlNodePtr parent) + gst_element_save_thyself (GstObject * object, xmlNodePtr parent) { GList *pads; GstElementClass *oclass; GParamSpec **specs, *spec; gint nspecs, i; - GValue value = { 0, }; + GValue value = { + 0,}; GstElement *element; g_return_val_if_fail (GST_IS_ELEMENT (object), parent); @@ -2187,8 +2187,7 @@ gst_element_save_thyself (GstObject * object, xmlNodePtr parent) return parent; } -static void -gst_element_restore_thyself (GstObject * object, xmlNodePtr self) +static void gst_element_restore_thyself (GstObject * object, xmlNodePtr self) { xmlNodePtr children; GstElement *element; @@ -2236,7 +2235,7 @@ gst_element_restore_thyself (GstObject * object, xmlNodePtr self) #endif /* GST_DISABLE_LOADSAVE */ static void -gst_element_set_manager_func (GstElement * element, GstPipeline * manager) + gst_element_set_manager_func (GstElement * element, GstPipeline * manager) { g_return_if_fail (GST_IS_ELEMENT (element)); @@ -2249,8 +2248,7 @@ gst_element_set_manager_func (GstElement * element, GstPipeline * manager) GST_UNLOCK (element); } -static void -gst_element_set_bus_func (GstElement * element, GstBus * bus) +static void gst_element_set_bus_func (GstElement * element, GstBus * bus) { g_return_if_fail (GST_IS_ELEMENT (element)); @@ -2263,7 +2261,8 @@ gst_element_set_bus_func (GstElement * element, GstBus * bus) } static void -gst_element_set_scheduler_func (GstElement * element, GstScheduler * scheduler) + gst_element_set_scheduler_func (GstElement * element, + GstScheduler * scheduler) { g_return_if_fail (GST_IS_ELEMENT (element)); @@ -2286,8 +2285,7 @@ gst_element_set_scheduler_func (GstElement * element, GstScheduler * scheduler) * * MT safe. */ -void -gst_element_set_manager (GstElement * element, GstPipeline * manager) +void gst_element_set_manager (GstElement * element, GstPipeline * manager) { GstElementClass *oclass; @@ -2310,8 +2308,7 @@ gst_element_set_manager (GstElement * element, GstPipeline * manager) * * MT safe. */ -GstPipeline * -gst_element_get_manager (GstElement * element) +GstPipeline *gst_element_get_manager (GstElement * element) { GstPipeline *result = NULL; @@ -2335,8 +2332,7 @@ gst_element_get_manager (GstElement * element) * * MT safe. */ -void -gst_element_set_bus (GstElement * element, GstBus * bus) +void gst_element_set_bus (GstElement * element, GstBus * bus) { GstElementClass *oclass; @@ -2358,8 +2354,7 @@ gst_element_set_bus (GstElement * element, GstBus * bus) * * MT safe. */ -GstBus * -gst_element_get_bus (GstElement * element) +GstBus *gst_element_get_bus (GstElement * element) { GstBus *result = NULL; @@ -2382,8 +2377,7 @@ gst_element_get_bus (GstElement * element) * * MT safe. */ -void -gst_element_set_scheduler (GstElement * element, GstScheduler * scheduler) +void gst_element_set_scheduler (GstElement * element, GstScheduler * scheduler) { GstElementClass *oclass; @@ -2405,8 +2399,7 @@ gst_element_set_scheduler (GstElement * element, GstScheduler * scheduler) * * MT safe. */ -GstScheduler * -gst_element_get_scheduler (GstElement * element) +GstScheduler *gst_element_get_scheduler (GstElement * element) { GstScheduler *result = NULL; diff --git a/gst/gstmessage.c b/gst/gstmessage.c index 619494dd16..2da7acb46c 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -247,3 +247,25 @@ gst_message_new_tag (GstObject * src, GstTagList * tag_list) return message; } + +/** + * gst_message_new_state_change: + * + * Create a state change message. + * + * Returns: The new state change message. + * + * MT safe. + */ +GstMessage * +gst_message_new_state_changed (GstObject * src, GstElementState old, + GstElementState new) +{ + GstMessage *message; + + message = gst_message_new (GST_MESSAGE_STATE_CHANGED, src); + message->message_data.state_changed.old = old; + message->message_data.state_changed.new = new; + + return message; +} diff --git a/gst/gstmessage.h b/gst/gstmessage.h index 7b29b933ce..16af4c6592 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -32,15 +32,16 @@ G_BEGIN_DECLS GST_EXPORT GType _gst_message_type; typedef enum { - GST_MESSAGE_UNKNOWN = 0, - GST_MESSAGE_EOS = 1, - GST_MESSAGE_ERROR = 2, - GST_MESSAGE_WARNING = 3, - GST_MESSAGE_INFO = 4, - GST_MESSAGE_TAG = 5, - GST_MESSAGE_BUFFERING = 6, - GST_MESSAGE_STATE_CHANGED = 7, - GST_MESSAGE_STEP_DONE = 8, + GST_MESSAGE_UNKNOWN = 0, + GST_MESSAGE_EOS = (1 << 0), + GST_MESSAGE_ERROR = (1 << 1), + GST_MESSAGE_WARNING = (1 << 2), + GST_MESSAGE_INFO = (1 << 3), + GST_MESSAGE_TAG = (1 << 4), + GST_MESSAGE_BUFFERING = (1 << 5), + GST_MESSAGE_STATE_CHANGED = (1 << 6), + GST_MESSAGE_STEP_DONE = (1 << 7), + GST_MESSAGE_ANY = 0xffffffff } GstMessageType; #define GST_MESSAGE_TRACE_NAME "GstMessage" @@ -62,6 +63,12 @@ typedef enum #define GST_MESSAGE_TAG_LIST(message) (GST_MESSAGE(message)->message_data.tag.list) +/* this is terribly nasty cause I'm going to make these all functions soon */ +#define GST_MESSAGE_PARSE_STATE_CHANGED(message, pold, pnew) G_STMT_START{ \ + *pold = GST_MESSAGE(message)->message_data.state_changed.old; \ + *pnew = GST_MESSAGE(message)->message_data.state_changed.new; \ +}G_STMT_END + #define GST_MESSAGE_ERROR_GERROR(message) (GST_MESSAGE(message)->message_data.error.gerror) #define GST_MESSAGE_ERROR_DEBUG(message) (GST_MESSAGE(message)->message_data.error.debug) #define GST_MESSAGE_WARNING_GERROR(message) (GST_MESSAGE(message)->message_data.error.gerror) @@ -95,6 +102,11 @@ struct _GstMessage { GstTagList *list; } tag; + struct + { + GstElementState old; + GstElementState new; + } state_changed; } message_data; /*< private > */ @@ -117,6 +129,8 @@ GstMessage * gst_message_new_eos (GstObject * src); GstMessage * gst_message_new_error (GstObject * src, GError * error, gchar * debug); GstMessage * gst_message_new_warning (GstObject * src, GError * error, gchar * debug); GstMessage * gst_message_new_tag (GstObject * src, GstTagList * tag_list); +GstMessage * gst_message_new_state_changed (GstObject * src, GstElementState old, + GstElementState new); G_END_DECLS #endif /* __GST_MESSAGE_H__ */ diff --git a/tools/gst-launch.c b/tools/gst-launch.c index e89c94d521..f3b924d9b8 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -63,7 +63,6 @@ static GstElement *pipeline; gboolean caught_intr = FALSE; gboolean caught_error = FALSE; gboolean tags = FALSE; -GMainLoop *loop; #ifndef GST_DISABLE_LOADSAVE @@ -159,7 +158,7 @@ fault_handler_sighandler (int signum) fault_spin (); } -#else +#else /* USE_SIGINFO */ static void fault_handler_sigaction (int signum, siginfo_t * si, void *misc) @@ -182,7 +181,7 @@ fault_handler_sigaction (int signum, siginfo_t * si, void *misc) fault_spin (); } -#endif +#endif /* USE_SIGINFO */ static void fault_spin (void) @@ -229,7 +228,7 @@ fault_setup (void) sigaction (SIGSEGV, &action, NULL); sigaction (SIGQUIT, &action, NULL); } -#endif +#endif /* DISABLE_FAULT_HANDLER */ static void print_tag (const GstTagList * list, const gchar * tag, gpointer unused) @@ -272,15 +271,15 @@ sigint_handler_sighandler (int signum) } static gboolean -check_intr (user_data) +check_intr (GstElement * pipeline) { if (!caught_intr) { return TRUE; } else { + caught_intr = FALSE; g_print ("Pausing pipeline.\n"); gst_element_set_state (pipeline, GST_STATE_PAUSED); - g_print ("Paused pipeline.\n"); - g_main_loop_quit (loop); + return FALSE; } } @@ -332,37 +331,67 @@ play_signal_setup (void) sigaction (SIGUSR1, &action, NULL); sigaction (SIGUSR2, &action, NULL); } -#endif +#endif /* DISABLE_FAULT_HANDLER */ static gboolean -message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline) +event_loop (GstElement * pipeline, gboolean blocking) { - switch (GST_MESSAGE_TYPE (message)) { - case GST_MESSAGE_EOS: - if (g_main_loop_is_running (loop)) - g_main_loop_quit (loop); - break; - case GST_MESSAGE_TAG: - if (tags) { - g_print (_("FOUND TAG : found by element \"%s\".\n"), - GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); - gst_tag_list_foreach (GST_MESSAGE_TAG_LIST (message), print_tag, NULL); - } - break; - case GST_MESSAGE_ERROR: - gst_object_default_error (GST_MESSAGE_SRC (message), - GST_MESSAGE_ERROR_GERROR (message), - GST_MESSAGE_ERROR_DEBUG (message)); - caught_error = TRUE; - gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); - if (g_main_loop_is_running (loop)) - g_main_loop_quit (loop); - break; - default: - break; - } - gst_message_unref (message); + GstBus *bus; + GstMessageType revent; + GstMessage *message = NULL; + GstElementState old, new; + bus = gst_element_get_bus (GST_ELEMENT (pipeline)); + + g_timeout_add (50, (GSourceFunc) check_intr, pipeline); + + while (TRUE) { + revent = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0); + + /* if the poll timed out, only when !blocking */ + if (revent == GST_MESSAGE_UNKNOWN) + return FALSE; + + message = gst_bus_pop (bus); + g_return_val_if_fail (message != NULL, TRUE); + + switch (revent) { + case GST_MESSAGE_EOS: + gst_message_unref (message); + return FALSE; + case GST_MESSAGE_TAG: + if (tags) { + g_print (_("FOUND TAG : found by element \"%s\".\n"), + GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); + gst_tag_list_foreach (GST_MESSAGE_TAG_LIST (message), print_tag, + NULL); + } + gst_message_unref (message); + break; + case GST_MESSAGE_ERROR: + gst_object_default_error (GST_MESSAGE_SRC (message), + GST_MESSAGE_ERROR_GERROR (message), + GST_MESSAGE_ERROR_DEBUG (message)); + gst_message_unref (message); + return TRUE; + case GST_MESSAGE_STATE_CHANGED: + GST_MESSAGE_PARSE_STATE_CHANGED (message, &old, &new); + gst_message_unref (message); + if (!(old == GST_STATE_PLAYING && new == GST_STATE_PAUSED)) + break; + g_print (_ + ("Element \"%s\" has gone from PLAYING to PAUSED, quitting.\n"), + GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); + /* cut out of the event loop if check_intr set us to PAUSED */ + return FALSE; + default: + /* just be quiet by default */ + gst_message_unref (message); + break; + } + } + + g_assert_not_reached (); return TRUE; } @@ -483,12 +512,6 @@ main (int argc, char *argv[]) g_signal_connect (pipeline, "deep_notify", G_CALLBACK (gst_object_default_deep_notify), exclude_list); } - - loop = g_main_loop_new (NULL, FALSE); - gst_bus_add_watch (gst_element_get_bus (GST_ELEMENT (pipeline)), - (GstBusHandler) message_received, pipeline); - - #ifndef GST_DISABLE_LOADSAVE if (savefile) { gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w")); @@ -515,7 +538,10 @@ main (int argc, char *argv[]) res = -1; goto end; } + gst_element_get_state (pipeline, &state, &pending, NULL); + caught_error = event_loop (pipeline, FALSE); + /* see if we got any messages */ while (g_main_context_iteration (NULL, FALSE)); @@ -533,10 +559,8 @@ main (int argc, char *argv[]) goto end; } - g_timeout_add (50, check_intr, NULL); - g_get_current_time (&tfthen); - g_main_loop_run (loop); + caught_error = event_loop (pipeline, TRUE); g_get_current_time (&tfnow); diff = GST_TIMEVAL_TO_TIME (tfnow) - GST_TIMEVAL_TO_TIME (tfthen);