From 864a9acf69de8701f90e8f1eb9915231871ba14c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 18 Jan 2005 10:52:08 +0000 Subject: [PATCH] More state change fixes. Original commit message from CVS: More state change fixes. Added/fixed some testcases. Threadsafety fixes. --- ChangeLog | 62 +++++++ docs/design/part-states.txt | 2 +- gst/elements/gstfilesrc.c | 100 +++++++++++ gst/gstbin.c | 83 ++++++--- gst/gstbus.c | 44 ++++- gst/gstbus.h | 2 + gst/gstclock.c | 2 + gst/gstcpu.c | 17 +- gst/gstdata.c | 24 ++- gst/gstelement.c | 144 +++++++++------- gst/gstelement.h | 3 - gst/gstobject.c | 2 +- gst/gstpad.h | 5 + gst/gstpipeline.c | 7 +- gst/gstplugin.c | 2 +- gst/gsttypes.h | 30 ++-- gst/gstutils.c | 2 +- plugins/elements/gstfilesrc.c | 100 +++++++++++ tests/old/testsuite/states/.gitignore | 4 + tests/old/testsuite/states/Makefile.am | 4 +- tests/old/testsuite/states/locked.c | 13 +- tests/old/testsuite/states/parent.c | 22 ++- tests/old/testsuite/states/test1.c | 208 ++++++++++++++++++++++ tests/old/testsuite/states/test2.c | 131 ++++++++++++++ tests/old/testsuite/states/test3.c | 136 +++++++++++++++ tests/old/testsuite/states/test4.c | 230 +++++++++++++++++++++++++ testsuite/states/.gitignore | 4 + testsuite/states/Makefile.am | 4 +- testsuite/states/locked.c | 13 +- testsuite/states/parent.c | 22 ++- testsuite/states/test1.c | 208 ++++++++++++++++++++++ testsuite/states/test2.c | 131 ++++++++++++++ testsuite/states/test3.c | 136 +++++++++++++++ testsuite/states/test4.c | 230 +++++++++++++++++++++++++ 34 files changed, 1975 insertions(+), 152 deletions(-) create mode 100644 tests/old/testsuite/states/test1.c create mode 100644 tests/old/testsuite/states/test2.c create mode 100644 tests/old/testsuite/states/test3.c create mode 100644 tests/old/testsuite/states/test4.c create mode 100644 testsuite/states/test1.c create mode 100644 testsuite/states/test2.c create mode 100644 testsuite/states/test3.c create mode 100644 testsuite/states/test4.c diff --git a/ChangeLog b/ChangeLog index 88fce0157a..11dd77a457 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,65 @@ +2005-01-18 Wim Taymans + + * docs/design/part-states.txt: + * gst/elements/gstfakesrc.c: (gst_fakesrc_loop), + (gst_fakesrc_activate): + * gst/elements/gstfilesrc.c: (gst_filesrc_getrange), + (gst_filesrc_open_file), (gst_filesrc_activate), + (filesrc_find_peek), (filesrc_find_suggest), + (gst_filesrc_type_find): + * gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock), + (gst_bin_set_bus), (gst_bin_set_scheduler), (gst_bin_add_func), + (gst_bin_iterate_elements), (bin_element_is_sink), + (gst_bin_get_state), (gst_bin_change_state), + (gst_bin_get_by_name_recurse_up): + * gst/gstbus.c: (gst_bus_dispose), (gst_bus_new), (gst_bus_post), + (gst_bus_set_sync_handler), (gst_bus_create_watch), (bus_destroy), + (gst_bus_add_watch_full): + * gst/gstbus.h: + * gst/gstclock.c: (gst_clock_id_ref), (gst_clock_id_unref), + (gst_clock_id_compare_func), (gst_clock_id_wait), + (gst_clock_id_wait_async), (gst_clock_init), (gst_clock_get_time): + * gst/gstcpu.c: (_gst_cpu_initialize_i386), (gst_cpu_get_flags): + * gst/gstdata.c: (gst_data_is_writable), (gst_data_copy_on_write): + * gst/gstelement.c: (gst_element_class_init), + (gst_element_add_pad), (gst_element_remove_pad), + (gst_element_get_static_pad), (gst_element_is_locked_state), + (gst_element_get_state_func), (gst_element_abort_state), + (gst_element_set_state), (gst_element_pads_activate), + (gst_element_change_state), (gst_element_dispose), + (gst_element_finalize), (gst_element_get_scheduler): + * gst/gstelement.h: + * gst/gstobject.c: (gst_object_class_init), (gst_object_ref), + (gst_object_unref), (gst_object_sink), (gst_object_replace), + (gst_object_dispose), (gst_object_dispatch_properties_changed), + (gst_object_set_name), (gst_object_set_parent), + (gst_object_unparent), (gst_object_check_uniqueness), + (gst_object_get_path_string): + * gst/gstpad.h: + * gst/gstpipeline.c: (is_eos), (pipeline_bus_handler), + (gst_pipeline_change_state): + * gst/gstplugin.c: + * gst/gsttypes.h: + * gst/gstutils.c: (gst_element_finish_preroll), + (gst_element_get_compatible_pad_filtered), + (gst_element_state_get_name), (gst_element_link_pads_filtered), + (gst_element_unlink): + * testsuite/states/.cvsignore: + * testsuite/states/Makefile.am: + * testsuite/states/locked.c: (message_received), (main): + * testsuite/states/parent.c: (main): + * testsuite/states/test1.c: (message_received), (set_state), + (get_state), (commit_callback), (abort_callback), (main): + * testsuite/states/test2.c: (message_received), (set_state), + (get_state), (main): + * testsuite/states/test3.c: (message_received), (set_state), + (get_state), (main): + * testsuite/states/test4.c: (message_received), (set_state), + (get_state), (commit_callback), (abort_callback), (main): + More state change fixes. + Added/fixed some testcases. + Threadsafety fixes. + 2005-01-12 Wim Taymans * gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock), diff --git a/docs/design/part-states.txt b/docs/design/part-states.txt index 48ffdeba43..5d45ee57fd 100644 --- a/docs/design/part-states.txt +++ b/docs/design/part-states.txt @@ -59,7 +59,7 @@ The _set_state() function can return 3 possible values: In the case of an async state change, it is not possible to proceed to the next state until the current state change completed. After receiving an ASYNC return -value, you can use _element_get_state() to poll the status of the plugin. +value, you can use _element_get_state() to poll the status of the element. When setting the state of an element, the PENDING_STATE is set to the required state and the STATE_ERROR flag is cleared. Then the state change function of the diff --git a/gst/elements/gstfilesrc.c b/gst/elements/gstfilesrc.c index c5ade2a121..e562b82259 100644 --- a/gst/elements/gstfilesrc.c +++ b/gst/elements/gstfilesrc.c @@ -180,6 +180,7 @@ static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type, static gboolean gst_filesrc_activate (GstPad * pad, GstActivateMode mode); static GstElementStateReturn gst_filesrc_change_state (GstElement * element); +static GstCaps *gst_filesrc_type_find (GstFileSrc * src); static void gst_filesrc_uri_handler_init (gpointer g_iface, gpointer iface_data); @@ -854,6 +855,22 @@ gst_filesrc_open_file (GstFileSrc * src) src->curoffset = 0; GST_FLAG_SET (src, GST_FILESRC_OPEN); + + { + GstCaps *caps; + guint64 offset; + guint length; + + offset = src->curoffset; + length = src->block_size; + + caps = gst_filesrc_type_find (src); + gst_pad_set_caps (src->srcpad, caps); + + src->curoffset = offset; + src->block_size = length; + } + } return TRUE; } @@ -1122,6 +1139,89 @@ error: return FALSE; } +typedef struct +{ + GstFileSrc *src; + guint best_probability; + GstCaps *caps; + + GstBuffer *buffer; +} +FileSrcTypeFind; + +static guint8 * +filesrc_find_peek (gpointer data, gint64 offset, guint size) +{ + FileSrcTypeFind *find; + GstBuffer *buffer; + GstFileSrc *src; + + if (size == 0) + return NULL; + + find = (FileSrcTypeFind *) data; + src = find->src; + + if (offset < 0) { + offset += src->filelen; + } + + buffer = NULL; + gst_filesrc_getrange (src->srcpad, offset, size, &buffer); + + if (find->buffer) { + gst_buffer_unref (find->buffer); + } + find->buffer = buffer; + + return GST_BUFFER_DATA (buffer); +} + +static void +filesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps) +{ + FileSrcTypeFind *find = (FileSrcTypeFind *) data; + + if (probability > find->best_probability) { + gst_caps_replace (&find->caps, gst_caps_copy (caps)); + find->best_probability = probability; + } +} + + +static GstCaps * +gst_filesrc_type_find (GstFileSrc * src) +{ + GstTypeFind gst_find; + FileSrcTypeFind find; + GList *walk, *type_list = NULL; + GstCaps *result = NULL; + + walk = type_list = gst_type_find_factory_get_list (); + + find.src = src; + find.best_probability = 0; + find.caps = NULL; + gst_find.data = &find; + gst_find.peek = filesrc_find_peek; + gst_find.suggest = filesrc_find_suggest; + gst_find.get_length = NULL; + + while (walk) { + GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data); + + gst_type_find_factory_call_function (factory, &gst_find); + if (find.best_probability >= GST_TYPE_FIND_MAXIMUM) + break; + walk = g_list_next (walk); + } + + if (find.best_probability > 0) + result = find.caps; + + return result; +} + /*** GSTURIHANDLER INTERFACE *************************************************/ static guint diff --git a/gst/gstbin.c b/gst/gstbin.c index fecd87f57b..cace33a425 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -19,6 +19,8 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. + * + * MT safe. */ #include "gst_private.h" @@ -581,15 +583,31 @@ bin_element_is_sink (GstElement * child, GstBin * bin) GList *pads; gboolean connected_src = FALSE; - pads = child->srcpads; - while (pads) { - GstPad *pad = GST_PAD (pads->data); + for (pads = child->srcpads; pads; pads = g_list_next (pads)) { + GstPad *peer; - if (GST_PAD_IS_LINKED (pad)) { - connected_src = TRUE; - break; + peer = gst_pad_get_peer (GST_PAD_CAST (pads->data)); + if (peer) { + GstElement *parent; + + parent = gst_pad_get_parent (peer); + if (parent) { + GstObject *grandparent; + + grandparent = gst_object_get_parent (GST_OBJECT_CAST (parent)); + if (grandparent == GST_OBJECT_CAST (bin)) { + connected_src = TRUE; + } + if (grandparent) { + gst_object_unref (GST_OBJECT_CAST (grandparent)); + } + gst_object_unref (GST_OBJECT_CAST (parent)); + } + gst_object_unref (GST_OBJECT_CAST (peer)); + if (connected_src) { + break; + } } - pads = g_list_next (pads); } if (connected_src) { @@ -598,7 +616,7 @@ bin_element_is_sink (GstElement * child, GstBin * bin) GST_OBJECT_NAME (child)); } else { GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin, - "adding child %s as sink since it has unlinked source pads", + "adding child %s as sink since it has unlinked source pads in this bin", GST_OBJECT_NAME (child)); ret = 0; } @@ -640,8 +658,8 @@ gst_bin_iterate_sinks (GstBin * bin) return result; } -/* this functions loops over all children, as soon as one is - * still performing the state change, FALSE is returned. +/* this functions loops over all children, as soon as one does + * not return SUCCESS, we return that value. * * MT safe */ @@ -718,7 +736,17 @@ done: return ret; } -/* this function is called with the STATE_LOCK held. +/* this function is called with the STATE_LOCK held. It works + * as follows: + * + * 1) put all sink elements on the queue. + * 2) change state of elements in queue, put linked elements to queue. + * 3) while queue not empty goto 2) + * + * This will effectively change the state of all elements in the bin + * from the sinks to the sources. We have to change the states this + * way so that when a source element pushes data, the downstream element + * is in the right state to receive the data. * * MT safe. */ @@ -735,6 +763,7 @@ gst_bin_change_state (GstElement * element) bin = GST_BIN (element); + /* we don't need to take the STATE_LOCK, it is already taken */ old_state = GST_STATE (element); pending = GST_STATE_PENDING (element); @@ -791,7 +820,7 @@ restart: GST_LOCK (qelement); pads = qelement->sinkpads; while (pads) { - GstPad *pad = GST_PAD (pads->data); + GstPad *pad = GST_PAD_CAST (pads->data); GstPad *peer; GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, @@ -799,20 +828,32 @@ restart: peer = gst_pad_get_peer (pad); if (peer) { - GstElement *peer_elem; + GstObject *peer_elem; - /* FIXME does not work for bins etc */ - peer_elem = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (peer))); + peer_elem = gst_object_get_parent (GST_OBJECT_CAST (peer)); if (peer_elem) { - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "adding element %s to queue", GST_ELEMENT_NAME (peer_elem)); + GstObject *parent; - /* was reffed before pushing on the queue by the - * gst_object_get_parent() call we used to get the element. */ - g_queue_push_tail (elem_queue, peer_elem); + /* see if this element is in the bin we are currently handling */ + parent = gst_object_get_parent (GST_OBJECT_CAST (peer_elem)); + if (parent && parent == GST_OBJECT_CAST (bin)) { + GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, + "adding element %s to queue", GST_ELEMENT_NAME (peer_elem)); + + /* was reffed before pushing on the queue by the + * gst_object_get_parent() call we used to get the element. */ + g_queue_push_tail (elem_queue, peer_elem); + } else { + GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, + "not adding element %s to queue, it is in another bin", + GST_ELEMENT_NAME (peer_elem)); + } + if (parent) { + gst_object_unref (GST_OBJECT_CAST (parent)); + } } - gst_object_unref (GST_OBJECT (peer)); + gst_object_unref (GST_OBJECT_CAST (peer)); } else { GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "pad %s:%s does not have a peer", GST_DEBUG_PAD_NAME (pad)); diff --git a/gst/gstbus.c b/gst/gstbus.c index 0024f549f2..873ead06dc 100644 --- a/gst/gstbus.c +++ b/gst/gstbus.c @@ -125,7 +125,10 @@ gst_bus_dispose (GObject * object) close (bus->control_socket[0]); close (bus->control_socket[1]); - g_async_queue_unref (bus->queue); + if (bus->queue) { + g_async_queue_unref (bus->queue); + bus->queue = NULL; + } G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -160,6 +163,16 @@ gst_bus_get_property (GObject * object, guint prop_id, } } +GstBus * +gst_bus_new (void) +{ + GstBus *result; + + result = g_object_new (gst_bus_get_type (), NULL); + + return result; +} + /** * gst_bus_post: * @bus: a #GstBus to post on @@ -167,20 +180,29 @@ gst_bus_get_property (GObject * object, guint prop_id, * * Post a message on the given bus. * - * Returns: the new #GstBuffer. + * Returns: TRUE if the message could be posted. + * + * MT safe. */ gboolean gst_bus_post (GstBus * bus, GstMessage * message) { gchar c; GstBusSyncReply reply = GST_BUS_PASS; + GstBusSyncHandler handler; + gpointer handler_data; g_return_val_if_fail (GST_IS_BUS (bus), FALSE); g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE); + GST_LOCK (bus); + handler = bus->sync_handler; + handler_data = bus->sync_handler_data; + GST_UNLOCK (bus); + /* first call the sync handler if it is installed */ - if (bus->sync_handler) { - reply = bus->sync_handler (bus, message, bus->sync_handler_data); + if (handler) { + reply = handler (bus, message, handler_data); } /* now see what we should do with the message */ @@ -236,6 +258,8 @@ gst_bus_post (GstBus * bus, GstMessage * message) * handled. * * Returns: TRUE if there are messages on the bus to be handled. + * + * MT safe. */ gboolean gst_bus_have_pending (GstBus * bus) @@ -257,6 +281,8 @@ gst_bus_have_pending (GstBus * bus) * * Returns: The #GstMessage that is on the bus or NULL when there are no * messages available. + * + * MT safe. */ GstMessage * gst_bus_pop (GstBus * bus) @@ -287,8 +313,10 @@ gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func, gpointer data) { g_return_if_fail (GST_IS_BUS (bus)); + GST_LOCK (bus); bus->sync_handler = func; bus->sync_handler_data = data; + GST_UNLOCK (bus); } /** @@ -306,6 +334,8 @@ gst_bus_create_watch (GstBus * bus) g_return_val_if_fail (GST_IS_BUS (bus), NULL); + /* FIXME, we need to ref the bus and unref it when the source + * is destroyed */ source = g_io_create_watch (bus->io_channel, G_IO_IN); return source; @@ -342,6 +372,7 @@ bus_destroy (GstBusWatch * watch) if (watch->notify) { watch->notify (watch->user_data); } + gst_object_unref (GST_OBJECT_CAST (watch->bus)); g_free (watch); } @@ -352,6 +383,8 @@ bus_destroy (GstBusWatch * watch) * Adds the bus to the mainloop with the given priority. * * Returns: The event source id. + * + * MT safe. */ guint gst_bus_add_watch_full (GstBus * bus, gint priority, @@ -364,6 +397,7 @@ gst_bus_add_watch_full (GstBus * bus, gint priority, watch = g_new (GstBusWatch, 1); + gst_object_ref (GST_OBJECT_CAST (bus)); watch->source = gst_bus_create_watch (bus); watch->bus = bus; watch->priority = priority; @@ -390,6 +424,8 @@ gst_bus_add_watch_full (GstBus * bus, gint priority, * Adds the bus to the mainloop with the default priority. * * Returns: The event source id. + * + * MT safe. */ guint gst_bus_add_watch (GstBus * bus, GstBusHandler handler, gpointer user_data) diff --git a/gst/gstbus.h b/gst/gstbus.h index badbda240c..804ffc831c 100644 --- a/gst/gstbus.h +++ b/gst/gstbus.h @@ -73,6 +73,8 @@ struct _GstBusClass GType gst_bus_get_type (void); +GstBus* gst_bus_new (void); + gboolean gst_bus_post (GstBus * bus, GstMessage * message); gboolean gst_bus_have_pending (GstBus * bus); diff --git a/gst/gstclock.c b/gst/gstclock.c index 8b14def936..80a06f0fc8 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -490,6 +490,8 @@ gst_clock_set_resolution (GstClock * clock, guint64 resolution) * Get the accuracy of the clock. * * Returns: the resolution of the clock in microseconds. + * + * MT safe. */ guint64 gst_clock_get_resolution (GstClock * clock) diff --git a/gst/gstcpu.c b/gst/gstcpu.c index c8e00750d9..88f186354b 100644 --- a/gst/gstcpu.c +++ b/gst/gstcpu.c @@ -28,6 +28,7 @@ #include "gstcpu.h" #include "gstinfo.h" +static GStaticMutex _cpu_mutex = G_STATIC_MUTEX_INIT; static guint32 _gst_cpu_flags = 0; #if defined(HAVE_CPU_I386) && defined(__GNUC__) @@ -89,7 +90,9 @@ _gst_cpu_initialize_i386 (gulong * flags, GString * featurelist) { gboolean AMD; gulong eax = 0, ebx = 0, ecx = 0, edx = 0; + gboolean res = FALSE; + g_static_mutex_lock (&_cpu_mutex); gst_cpuid_i386 (0, &eax, &ebx, &ecx, &edx); AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65); @@ -124,13 +127,21 @@ _gst_cpu_initialize_i386 (gulong * flags, GString * featurelist) } *flags = eax; if (_gst_cpu_flags) - return TRUE; - return FALSE; + res = TRUE; + g_static_mutex_unlock (&_cpu_mutex); + + return res; } #endif GstCPUFlags gst_cpu_get_flags (void) { - return _gst_cpu_flags; + GstCPUFlags res; + + g_static_mutex_lock (&_cpu_mutex); + res = _gst_cpu_flags; + g_static_mutex_unlock (&_cpu_mutex); + + return res; } diff --git a/gst/gstdata.c b/gst/gstdata.c index 833f41ccaf..abd7cd43c7 100644 --- a/gst/gstdata.c +++ b/gst/gstdata.c @@ -99,6 +99,8 @@ gst_data_dispose (GstData * data) * Returns: a copy of the data or NULL if the data cannot be copied. * The refcount of the original buffer is not changed so you should unref it * when you don't need it anymore. + * + * MT safe. */ GstData * gst_data_copy (const GstData * data) @@ -119,6 +121,8 @@ gst_data_copy (const GstData * data) * * Returns: FALSE if the given #GstData is potentially shared and needs to * be copied before it can be modified safely. + * + * MT safe. */ gboolean gst_data_is_writable (GstData * data) @@ -129,12 +133,12 @@ gst_data_is_writable (GstData * data) refcount = gst_atomic_int_read (&data->refcount); - if (refcount > 1) - return FALSE; - if (GST_DATA_FLAG_IS_SET (data, GST_DATA_READONLY)) - return FALSE; + /* if we have the only ref and the data is not readonly, we can + * safely write */ + if (refcount == 1 && !GST_DATA_FLAG_IS_SET (data, GST_DATA_READONLY)) + return TRUE; - return TRUE; + return FALSE; } /** @@ -150,6 +154,8 @@ gst_data_is_writable (GstData * data) * * The refcount of the passed @data is decreased when a copy is made, so * you are not supposed to use it anymore after a call to this function. + * + * MT safe. */ GstData * gst_data_copy_on_write (GstData * data) @@ -160,6 +166,8 @@ gst_data_copy_on_write (GstData * data) refcount = gst_atomic_int_read (&data->refcount); + /* if we have the only ref and the data is not readonly, we can + * safely write, so we return the input data */ if (refcount == 1 && !GST_DATA_FLAG_IS_SET (data, GST_DATA_READONLY)) return GST_DATA (data); @@ -180,6 +188,8 @@ gst_data_copy_on_write (GstData * data) * Increments the reference count of this data. * * Returns: the data + * + * MT safe. */ GstData * gst_data_ref (GstData * data) @@ -203,6 +213,8 @@ gst_data_ref (GstData * data) * Increments the reference count of this data by the given number. * * Returns: the data + * + * MT safe. */ GstData * gst_data_ref_by_count (GstData * data, gint count) @@ -230,6 +242,8 @@ gst_data_ref_by_count (GstData * data, gint count) * the pipeline takes ownership of the * data. When the data has been consumed by some element, it must unref() it. * Applications usually don't need to unref() @data. + * + * MT safe. */ void gst_data_unref (GstData * data) diff --git a/gst/gstelement.c b/gst/gstelement.c index 6c7e582cf0..05ef242d01 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -64,6 +64,7 @@ static void gst_element_base_class_init (gpointer g_class); static void gst_element_base_class_finalize (gpointer g_class); static void gst_element_dispose (GObject * object); +static void gst_element_finalize (GObject * object); static GstElementStateReturn gst_element_change_state (GstElement * element); static GstElementStateReturn gst_element_get_state_func (GstElement * element, @@ -137,6 +138,7 @@ gst_element_class_init (GstElementClass * klass) NULL, gst_marshal_VOID__VOID, G_TYPE_NONE, 0); gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose); + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_element_finalize); #ifndef GST_DISABLE_LOADSAVE gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself); @@ -457,6 +459,8 @@ gst_element_add_pad (GstElement * element, GstPad * pad) GST_OBJECT_CAST (element)))) goto had_parent; + g_free (pad_name); + /* add it to the list */ switch (gst_pad_get_direction (pad)) { case GST_PAD_SRC: @@ -486,10 +490,9 @@ gst_element_add_pad (GstElement * element, GstPad * pad) /* emit the NEW_PAD signal */ g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad); - g_free (pad_name); - return TRUE; + /* ERROR cases */ name_exists: { g_critical ("Padname %s is not unique in element %s, not adding", @@ -575,6 +578,8 @@ gst_element_remove_pad (GstElement * element, GstPad * pad) goto not_our_pad; GST_UNLOCK (pad); + g_free (pad_name); + /* FIXME, is this redundant with pad disposal? */ if (GST_IS_REAL_PAD (pad)) { GstPad *peer = gst_pad_get_peer (pad); @@ -619,12 +624,11 @@ gst_element_remove_pad (GstElement * element, GstPad * pad) gst_object_unparent (GST_OBJECT (pad)); - g_free (pad_name); - return TRUE; not_our_pad: { + /* FIXME, locking order? */ GST_LOCK (element); g_critical ("Padname %s:%s does not belong to element %s when removing", GST_ELEMENT_NAME (GST_PAD_PARENT (pad)), GST_PAD_NAME (pad), @@ -694,8 +698,8 @@ gst_element_get_static_pad (GstElement * element, const gchar * name) find = g_list_find_custom (element->pads, name, (GCompareFunc) pad_compare_name); if (find) { - result = GST_PAD (find->data); - gst_object_ref (GST_OBJECT (result)); + result = GST_PAD_CAST (find->data); + gst_object_ref (GST_OBJECT_CAST (result)); } if (result == NULL) { @@ -1476,8 +1480,7 @@ gst_element_is_locked_state (GstElement * element) g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); GST_LOCK (element); - /* be careful with the flag tests */ - result = !!GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE); + result = GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE); GST_UNLOCK (element); return result; @@ -1569,15 +1572,15 @@ gst_element_get_state_func (GstElement * element, g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); GST_STATE_LOCK (element); + /* we got an error, report immediatly */ + if (GST_STATE_ERROR (element)) + goto done; + old_pending = GST_STATE_PENDING (element); if (old_pending != GST_STATE_VOID_PENDING) { /* we have a pending state change, wait for it to complete */ if (!GST_STATE_TIMED_WAIT (element, timeout)) { /* timeout triggered */ - if (state) - *state = GST_STATE (element); - if (pending) - *pending = GST_STATE_PENDING (element); ret = GST_STATE_ASYNC; } else { /* could be success or failure */ @@ -1588,15 +1591,17 @@ gst_element_get_state_func (GstElement * element, } } } - /* if nothing is pending anymore we can return TRUE and - * set the values of the current and pending state */ + /* if nothing is pending anymore we can return SUCCESS */ if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) { - if (state) - *state = GST_STATE (element); - if (pending) - *pending = GST_STATE_VOID_PENDING; ret = GST_STATE_SUCCESS; } + +done: + if (state) + *state = GST_STATE (element); + if (pending) + *pending = GST_STATE_PENDING (element); + GST_STATE_UNLOCK (element); return ret; @@ -1672,6 +1677,7 @@ gst_element_abort_state (GstElement * element) "aborting state from %s to %s", gst_element_state_get_name (old_state), gst_element_state_get_name (pending)); + /* flag error */ GST_STATE_ERROR (element) = TRUE; GST_STATE_BROADCAST (element); @@ -1734,11 +1740,18 @@ gst_element_set_state (GstElement * element, GstElementState state) GstElementState current; GstElementStateReturn return_val = GST_STATE_SUCCESS; - oclass = GST_ELEMENT_GET_CLASS (element); - /* get the element state lock */ GST_STATE_LOCK (element); +#if 0 + /* a state change is pending and we are not in error, the element is busy + * with a state change and we cannot proceed. + * FIXME, does not work for a bin.*/ + if (G_UNLIKELY (GST_STATE_PENDING (element) != GST_STATE_VOID_PENDING && + !GST_STATE_ERROR (element))) + goto was_busy; +#endif + /* clear the error flag */ GST_STATE_ERROR (element) = FALSE; @@ -1748,6 +1761,8 @@ gst_element_set_state (GstElement * element, GstElementState state) GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "setting state from %s to %s", gst_element_state_get_name (current), gst_element_state_get_name (state)); + oclass = GST_ELEMENT_GET_CLASS (element); + /* We always perform at least one state change, even if the * current state is equal to the required state. This is needed * for bins that sync their children. */ @@ -1798,8 +1813,7 @@ gst_element_set_state (GstElement * element, GstElementState state) GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "commited state"); break; default: - /* somebody added a GST_STATE_ and forgot to do stuff here ! */ - g_assert_not_reached (); + goto invalid_return; } /* get the current state of the element and see if we need to do more * state changes */ @@ -1813,15 +1827,35 @@ exit: GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "exit state change"); return return_val; + + /* ERROR */ +#if 0 +was_busy: + { + GST_STATE_UNLOCK (element); + GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, + "was busy with a state change"); + + return GST_STATE_BUSY; + } +#endif +invalid_return: + { + GST_STATE_UNLOCK (element); + /* somebody added a GST_STATE_ and forgot to do stuff here ! */ + g_critical ("unkown return value from a state change function"); + return GST_STATE_FAILURE; + } } /* is called with STATE_LOCK * * This function activates the pads of a given element. * - * TODO: activates pads from src to sinks? - * - * */ + * TODO: activate pads from src to sinks? + * move pad activate logic to GstPad because we also need this + * when pads are added to elements? + */ static gboolean gst_element_pads_activate (GstElement * element, gboolean active) { @@ -1950,16 +1984,17 @@ gst_element_change_state (GstElement * element) GST_LOCK (element); if (GST_ELEMENT_MANAGER (element)) { element->base_time = - GST_ELEMENT (GST_ELEMENT_MANAGER (element))->base_time; + GST_ELEMENT_CAST (GST_ELEMENT_MANAGER (element))->base_time; } GST_UNLOCK (element); break; case GST_STATE_PLAYING_TO_PAUSED: break; case GST_STATE_PAUSED_TO_READY: - element->base_time = 0; if (!gst_element_pads_activate (element, FALSE)) { result = GST_STATE_FAILURE; + } else { + element->base_time = 0; } break; case GST_STATE_READY_TO_NULL: @@ -2010,25 +2045,38 @@ gst_element_dispose (GObject * object) while (element->pads) { gst_element_remove_pad (element, GST_PAD (element->pads->data)); } - - g_assert (element->pads == 0); + if (G_UNLIKELY (element->pads != 0)) { + g_critical ("could not remove pads from element %s", + GST_STR_NULL (GST_OBJECT_NAME (object))); + } GST_LOCK (element); gst_object_replace ((GstObject **) & element->manager, NULL); gst_object_replace ((GstObject **) & element->clock, NULL); GST_UNLOCK (element); + GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose parent"); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_element_finalize (GObject * object) +{ + GstElement *element = GST_ELEMENT (object); + + GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize"); + GST_STATE_LOCK (element); if (element->state_cond) g_cond_free (element->state_cond); element->state_cond = NULL; GST_STATE_UNLOCK (element); - g_mutex_free (element->state_lock); - GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose parent"); + GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize parent"); - G_OBJECT_CLASS (parent_class)->dispose (object); + G_OBJECT_CLASS (parent_class)->finalize (object); } #ifndef GST_DISABLE_LOADSAVE @@ -2349,35 +2397,3 @@ gst_element_get_scheduler (GstElement * element) return result; } - -/** - * gst_element_create_task: - * @element: a #GstElement to create the task for. - * @func: the taskfunction to run - * @data: user data passed to the taskfunction. - * - * Creates a new GstTask. This function uses the current manager of - * the element to instantiate a new task. - * - * Returns: the newly created #GstTask. - * - * MT safe. - */ -GstTask * -gst_element_create_task (GstElement * element, GstTaskFunction func, - gpointer data) -{ - GstScheduler *sched; - GstTask *result = NULL; - - GST_LOCK (element); - sched = GST_ELEMENT_SCHEDULER (element); - gst_object_ref (GST_OBJECT (sched)); - GST_UNLOCK (element); - if (sched) { - result = gst_scheduler_create_task (sched, func, data); - gst_object_unref (GST_OBJECT (sched)); - } - - return result; -} diff --git a/gst/gstelement.h b/gst/gstelement.h index 1e0d1ebbed..06b6c454cf 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -35,7 +35,6 @@ #include #include #include -#include #include G_BEGIN_DECLS typedef struct _GstElementDetails GstElementDetails; @@ -315,8 +314,6 @@ void gst_element_set_bus (GstElement * element, GstBus * bus); GstBus *gst_element_get_bus (GstElement * element); void gst_element_set_scheduler (GstElement * element, GstScheduler * scheduler); GstScheduler *gst_element_get_scheduler (GstElement * element); -GstTask *gst_element_create_task (GstElement * element, GstTaskFunction func, - gpointer data); /* pad management */ gboolean gst_element_add_pad (GstElement * element, GstPad * pad); diff --git a/gst/gstobject.c b/gst/gstobject.c index 14b1ccc2ea..6aa9b91061 100644 --- a/gst/gstobject.c +++ b/gst/gstobject.c @@ -394,7 +394,7 @@ gst_object_replace (GstObject ** oldobj, GstObject * newobj) #endif #endif - if (G_UNLIKELY (*oldobj != newobj)) { + if (G_LIKELY (*oldobj != newobj)) { if (newobj) gst_object_ref (newobj); if (*oldobj) diff --git a/gst/gstpad.h b/gst/gstpad.h index bae7abbab9..cfc8c9c9db 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -518,6 +518,11 @@ gboolean gst_pad_push_event (GstPad *pad, GstEvent *event); gboolean gst_pad_send_event (GstPad *pad, GstEvent *event); gboolean gst_pad_event_default (GstPad *pad, GstEvent *event); +/* pad tasks */ +gboolean gst_pad_start_task (GstPad *pad); +gboolean gst_pad_pause_task (GstPad *pad); +gboolean gst_pad_stop_task (GstPad *pad); + /* convert/query/format functions */ void gst_pad_set_formats_function (GstPad *pad, GstPadFormatsFunction formats); diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c index b445346a35..6b82090287 100644 --- a/gst/gstpipeline.c +++ b/gst/gstpipeline.c @@ -168,13 +168,13 @@ is_eos (GstPipeline * pipeline) GstElement *element = GST_ELEMENT (data); GList *eosed; GstElementState state, pending; - gboolean complete; + GstElementStateReturn complete; gchar *name; complete = gst_element_get_state (element, &state, &pending, NULL); name = gst_element_get_name (element); - if (!complete) { + if (complete == GST_STATE_ASYNC) { GST_DEBUG ("element %s still performing state change", name); result = FALSE; done = TRUE; @@ -332,9 +332,8 @@ gst_pipeline_change_state (GstElement * element) /* we wait for async state changes ourselves */ if (result == GST_STATE_ASYNC) { GST_STATE_UNLOCK (pipeline); - gst_element_get_state (element, NULL, NULL, NULL); + result = gst_element_get_state (element, NULL, NULL, NULL); GST_STATE_LOCK (pipeline); - result = GST_STATE_SUCCESS; } return result; diff --git a/gst/gstplugin.c b/gst/gstplugin.c index 9ae0b75fdb..6795cac1a6 100644 --- a/gst/gstplugin.c +++ b/gst/gstplugin.c @@ -114,7 +114,7 @@ gst_plugin_error_quark (void) * plugin description in a list to initialize it when we open the main * module later on. * When the main module is known, we can register the plugin right away. - * */ + */ void _gst_plugin_register_static (GstPluginDesc * desc) { diff --git a/gst/gsttypes.h b/gst/gsttypes.h index 335f7024c6..fcc206c4b7 100644 --- a/gst/gsttypes.h +++ b/gst/gsttypes.h @@ -22,7 +22,9 @@ #include -G_BEGIN_DECLS typedef struct _GstObject GstObject; +G_BEGIN_DECLS + +typedef struct _GstObject GstObject; typedef struct _GstObjectClass GstObjectClass; typedef struct _GstPad GstPad; typedef struct _GstPadClass GstPadClass; @@ -43,18 +45,19 @@ typedef struct _GstMessage GstMessage; typedef enum { - GST_STATE_VOID_PENDING = 0, - GST_STATE_NULL = (1 << 0), - GST_STATE_READY = (1 << 1), - GST_STATE_PAUSED = (1 << 2), - GST_STATE_PLAYING = (1 << 3) + GST_STATE_VOID_PENDING = 0, + GST_STATE_NULL = (1 << 0), + GST_STATE_READY = (1 << 1), + GST_STATE_PAUSED = (1 << 2), + GST_STATE_PLAYING = (1 << 3) } GstElementState; typedef enum { - GST_STATE_FAILURE = 0, - GST_STATE_SUCCESS = 1, - GST_STATE_ASYNC = 2 + GST_STATE_FAILURE = 0, + GST_STATE_SUCCESS = 1, + GST_STATE_ASYNC = 2, + GST_STATE_BUSY = 3 } GstElementStateReturn; typedef enum @@ -66,15 +69,14 @@ typedef enum typedef enum { - GST_RANK_NONE = 0, - GST_RANK_MARGINAL = 64, - GST_RANK_SECONDARY = 128, - GST_RANK_PRIMARY = 256 + GST_RANK_NONE = 0, + GST_RANK_MARGINAL = 64, + GST_RANK_SECONDARY = 128, + GST_RANK_PRIMARY = 256 } GstRank; #define GST_PADDING 4 #define GST_PADDING_INIT { 0 } - G_END_DECLS #endif /* __GST_TYPES_H__ */ diff --git a/gst/gstutils.c b/gst/gstutils.c index c39c5de7a9..d5d7180b02 100644 --- a/gst/gstutils.c +++ b/gst/gstutils.c @@ -773,7 +773,7 @@ gst_element_state_get_name (GstElementState state) return "PAUSED"; break; default: - return "UNKNOWN!"; + return g_strdup_printf ("UNKNOWN!(%d)", state); #endif } return ""; diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index c5ade2a121..e562b82259 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -180,6 +180,7 @@ static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type, static gboolean gst_filesrc_activate (GstPad * pad, GstActivateMode mode); static GstElementStateReturn gst_filesrc_change_state (GstElement * element); +static GstCaps *gst_filesrc_type_find (GstFileSrc * src); static void gst_filesrc_uri_handler_init (gpointer g_iface, gpointer iface_data); @@ -854,6 +855,22 @@ gst_filesrc_open_file (GstFileSrc * src) src->curoffset = 0; GST_FLAG_SET (src, GST_FILESRC_OPEN); + + { + GstCaps *caps; + guint64 offset; + guint length; + + offset = src->curoffset; + length = src->block_size; + + caps = gst_filesrc_type_find (src); + gst_pad_set_caps (src->srcpad, caps); + + src->curoffset = offset; + src->block_size = length; + } + } return TRUE; } @@ -1122,6 +1139,89 @@ error: return FALSE; } +typedef struct +{ + GstFileSrc *src; + guint best_probability; + GstCaps *caps; + + GstBuffer *buffer; +} +FileSrcTypeFind; + +static guint8 * +filesrc_find_peek (gpointer data, gint64 offset, guint size) +{ + FileSrcTypeFind *find; + GstBuffer *buffer; + GstFileSrc *src; + + if (size == 0) + return NULL; + + find = (FileSrcTypeFind *) data; + src = find->src; + + if (offset < 0) { + offset += src->filelen; + } + + buffer = NULL; + gst_filesrc_getrange (src->srcpad, offset, size, &buffer); + + if (find->buffer) { + gst_buffer_unref (find->buffer); + } + find->buffer = buffer; + + return GST_BUFFER_DATA (buffer); +} + +static void +filesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps) +{ + FileSrcTypeFind *find = (FileSrcTypeFind *) data; + + if (probability > find->best_probability) { + gst_caps_replace (&find->caps, gst_caps_copy (caps)); + find->best_probability = probability; + } +} + + +static GstCaps * +gst_filesrc_type_find (GstFileSrc * src) +{ + GstTypeFind gst_find; + FileSrcTypeFind find; + GList *walk, *type_list = NULL; + GstCaps *result = NULL; + + walk = type_list = gst_type_find_factory_get_list (); + + find.src = src; + find.best_probability = 0; + find.caps = NULL; + gst_find.data = &find; + gst_find.peek = filesrc_find_peek; + gst_find.suggest = filesrc_find_suggest; + gst_find.get_length = NULL; + + while (walk) { + GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data); + + gst_type_find_factory_call_function (factory, &gst_find); + if (find.best_probability >= GST_TYPE_FIND_MAXIMUM) + break; + walk = g_list_next (walk); + } + + if (find.best_probability > 0) + result = find.caps; + + return result; +} + /*** GSTURIHANDLER INTERFACE *************************************************/ static guint diff --git a/tests/old/testsuite/states/.gitignore b/tests/old/testsuite/states/.gitignore index 9d274cca42..ae643e03fd 100644 --- a/tests/old/testsuite/states/.gitignore +++ b/tests/old/testsuite/states/.gitignore @@ -6,6 +6,10 @@ Makefile.in .deps .libs +test1 +test2 +test3 +test4 bin locked parent diff --git a/tests/old/testsuite/states/Makefile.am b/tests/old/testsuite/states/Makefile.am index 2a01e7553e..5aa2c0d078 100644 --- a/tests/old/testsuite/states/Makefile.am +++ b/tests/old/testsuite/states/Makefile.am @@ -1,5 +1,5 @@ include ../Rules -tests_pass = locked parent +tests_pass = test1 test2 test3 test4 locked parent tests_fail = -tests_ignore = bin +tests_ignore = diff --git a/tests/old/testsuite/states/locked.c b/tests/old/testsuite/states/locked.c index e73413c273..d66565ddeb 100644 --- a/tests/old/testsuite/states/locked.c +++ b/tests/old/testsuite/states/locked.c @@ -21,6 +21,8 @@ #include +static GMainLoop *loop; + static gboolean message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline) { @@ -28,7 +30,8 @@ message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline) if (message->type == GST_MESSAGE_EOS) { g_print ("EOS!!\n"); - gst_main_quit (); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); } gst_message_unref (message); @@ -47,8 +50,10 @@ main (gint argc, gchar * argv[]) pipeline = gst_pipeline_new ("pipeline"); - bus = GST_PIPELINE (pipeline)->bus; + loop = g_main_loop_new (NULL, FALSE); + bus = gst_element_get_bus (pipeline); gst_bus_add_watch (bus, (GstBusHandler) message_received, pipeline); + gst_object_unref (GST_OBJECT (bus)); fakesrc1 = gst_element_factory_make ("fakesrc", "fakesrc1"); g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL); @@ -77,7 +82,7 @@ main (gint argc, gchar * argv[]) g_print ("play..\n"); gst_element_set_state (pipeline, GST_STATE_PLAYING); - gst_main (); + g_main_loop_run (loop); g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL); @@ -89,7 +94,7 @@ main (gint argc, gchar * argv[]) g_print ("play..\n"); gst_element_set_state (pipeline, GST_STATE_PLAYING); - gst_main (); + g_main_loop_run (loop); gst_element_set_state (pipeline, GST_STATE_NULL); diff --git a/tests/old/testsuite/states/parent.c b/tests/old/testsuite/states/parent.c index aa583c5aa3..fe8b2441c6 100644 --- a/tests/old/testsuite/states/parent.c +++ b/tests/old/testsuite/states/parent.c @@ -67,7 +67,7 @@ main (gint argc, gchar * argv[]) gst_bin_add (GST_BIN (pipeline), bin2); g_signal_connect (G_OBJECT (pipeline), "deep_notify", - G_CALLBACK (gst_element_default_deep_notify), NULL); + G_CALLBACK (gst_object_default_deep_notify), NULL); /* setting pipeline to READY should bring in all children to READY */ gst_element_set_state (pipeline, GST_STATE_READY); @@ -77,31 +77,35 @@ main (gint argc, gchar * argv[]) g_assert (GST_STATE (identity) == GST_STATE_READY); g_assert (GST_STATE (fakesink) == GST_STATE_READY); - /* setting fakesink to PAUSED should set pipeline and bin2 to PAUSED */ + /* setting fakesink to PAUSED should not affect pipeline and bin2 */ gst_element_set_state (fakesink, GST_STATE_PAUSED); g_assert (GST_STATE (bin1) == GST_STATE_READY); - g_assert (GST_STATE (bin2) == GST_STATE_PAUSED); + g_assert (GST_STATE (bin2) == GST_STATE_READY); g_assert (GST_STATE (fakesrc) == GST_STATE_READY); g_assert (GST_STATE (identity) == GST_STATE_READY); - g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED); + g_assert (GST_STATE (fakesink) == GST_STATE_READY); - /* setting fakesrc to PAUSED should set bin1 and fakesrc to PAUSED */ + /* setting fakesrc to PAUSED should not affect bin1 */ gst_element_set_state (fakesrc, GST_STATE_PAUSED); - g_assert (GST_STATE (bin1) == GST_STATE_PAUSED); - g_assert (GST_STATE (bin2) == GST_STATE_PAUSED); + g_assert (GST_STATE (bin1) == GST_STATE_READY); + g_assert (GST_STATE (bin2) == GST_STATE_READY); g_assert (GST_STATE (fakesrc) == GST_STATE_PAUSED); g_assert (GST_STATE (identity) == GST_STATE_READY); - g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED); + g_assert (GST_STATE (fakesink) == GST_STATE_READY); /* setting bin1 to PAUSED, even though it is already, should set * identity to PAUSED as well */ gst_element_set_state (bin1, GST_STATE_PAUSED); + gst_element_get_state (bin2, NULL, NULL, NULL); g_assert (GST_STATE (bin1) == GST_STATE_PAUSED); - g_assert (GST_STATE (bin2) == GST_STATE_PAUSED); + g_assert (GST_STATE (bin2) == GST_STATE_READY); g_assert (GST_STATE (fakesrc) == GST_STATE_PAUSED); g_assert (GST_STATE (identity) == GST_STATE_PAUSED); g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_usleep (1000000); + g_print ("passed.\n"); return 0; } diff --git a/tests/old/testsuite/states/test1.c b/tests/old/testsuite/states/test1.c new file mode 100644 index 0000000000..9a8ced3678 --- /dev/null +++ b/tests/old/testsuite/states/test1.c @@ -0,0 +1,208 @@ +/* GStreamer + * Copyright (C) <2005> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "unistd.h" + +#include + +static GMainLoop *loop; + +static gboolean +message_received (GstBus * bus, GstMessage * message, gpointer ignored) +{ + g_print ("message %p\n", message); + + if (message->type == GST_MESSAGE_EOS) { + g_print ("EOS!!\n"); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } + gst_message_unref (message); + + return TRUE; +} + +static gboolean +set_state (GstElement * element, GstElementState state, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + + g_print ("setting state to %s, expecting %d...", + gst_element_state_get_name (state), expected); + ret = gst_element_set_state (element, state); + res = (ret == expected); + g_print ("%s\n", res ? "OK" : "failed"); + + return res; +} + +static gboolean +get_state (GstElement * element, GstElementState exp_state, + GstElementState exp_pending, GTimeVal * timeval, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + GstElementState state, pending; + + g_print ("getting state: expecting %s, %s, %d...", + gst_element_state_get_name (exp_state), + gst_element_state_get_name (exp_pending), expected); + + ret = gst_element_get_state (element, &state, &pending, timeval); + + res = (ret == expected); + res &= (state == exp_state); + res &= (pending == exp_pending); + + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %s, %s, %d\n", + gst_element_state_get_name (state), + gst_element_state_get_name (pending), ret); + } + + return res; +} + +static gboolean +commit_callback (GstClock * clock, GstClockTime time, + GstClockID id, GstElement * element) +{ + g_print ("commiting state change.."); + gst_element_commit_state (element); + + return FALSE; +} + +static gboolean +abort_callback (GstClock * clock, GstClockTime time, + GstClockID id, GstElement * element) +{ + g_print ("aborting state change.."); + gst_element_abort_state (element); + + return FALSE; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstElement *fakesink; + GstBus *bus; + GTimeVal timeval; + GstClock *clock; + GstClockID id; + GstClockTime base; + GstClockReturn result; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + bus = gst_bus_new (); + gst_bus_add_watch (bus, (GstBusHandler) message_received, NULL); + + clock = gst_system_clock_obtain (); + g_assert (clock != NULL); + + fakesink = gst_element_factory_make ("fakesink", "fakesink"); + g_assert (fakesink); + + gst_element_set_bus (fakesink, bus); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + g_get_current_time (&timeval); + g_time_val_add (&timeval, G_USEC_PER_SEC * 1); + + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_print ("aborting state change..\n"); + gst_element_abort_state (fakesink); + + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_FAILURE)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_print ("commiting state change..\n"); + gst_element_commit_state (fakesink); + + g_assert (get_state (fakesink, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, + &timeval, GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, + &timeval, GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + base = gst_clock_get_time (clock); + id = gst_clock_new_single_shot_id (clock, base + 1 * GST_SECOND); + g_print ("waiting one second async id %p to abort state\n", id); + result = + gst_clock_id_wait_async (id, (GstClockCallback) abort_callback, fakesink); + gst_clock_id_unref (id); + g_assert (result == GST_CLOCK_OK); + + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, NULL, + GST_STATE_FAILURE)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, NULL, + GST_STATE_FAILURE)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + id = gst_clock_new_single_shot_id (clock, base + 1 * GST_SECOND); + g_print ("waiting one second async id %p to commit state\n", id); + result = + gst_clock_id_wait_async (id, (GstClockCallback) commit_callback, + fakesink); + gst_clock_id_unref (id); + g_assert (result == GST_CLOCK_OK); + + g_assert (get_state (fakesink, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_print ("passed..\n"); + gst_object_unref (GST_OBJECT (fakesink)); + + return 0; +} diff --git a/tests/old/testsuite/states/test2.c b/tests/old/testsuite/states/test2.c new file mode 100644 index 0000000000..260e362246 --- /dev/null +++ b/tests/old/testsuite/states/test2.c @@ -0,0 +1,131 @@ +/* GStreamer + * Copyright (C) <2005> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "unistd.h" + +#include + +static GMainLoop *loop; + +static gboolean +message_received (GstBus * bus, GstMessage * message, gpointer ignored) +{ + g_print ("message %p\n", message); + + if (message->type == GST_MESSAGE_EOS) { + g_print ("EOS!!\n"); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } + gst_message_unref (message); + + return TRUE; +} + +static gboolean +set_state (GstElement * element, GstElementState state, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + + g_print ("setting state to %s, expecting %d...", + gst_element_state_get_name (state), expected); + ret = gst_element_set_state (element, state); + res = (ret == expected); + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %d\n", ret); + } + + return res; +} + +static gboolean +get_state (GstElement * element, GstElementState exp_state, + GstElementState exp_pending, GTimeVal * timeval, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + GstElementState state, pending; + + g_print ("getting state: expecting %s, %s, %d...", + gst_element_state_get_name (exp_state), + gst_element_state_get_name (exp_pending), expected); + + ret = gst_element_get_state (element, &state, &pending, timeval); + + res = (ret == expected); + res &= (state == exp_state); + res &= (pending == exp_pending); + + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %s, %s, %d\n", + gst_element_state_get_name (state), + gst_element_state_get_name (pending), ret); + } + + return res; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstElement *fakesink; + GstBus *bus; + GTimeVal timeval; + GstClock *clock; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + bus = gst_bus_new (); + gst_bus_add_watch (bus, (GstBusHandler) message_received, NULL); + + clock = gst_system_clock_obtain (); + g_assert (clock != NULL); + + fakesink = gst_element_factory_make ("fakesink", "fakesink"); + g_assert (fakesink); + + gst_element_set_bus (fakesink, bus); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + g_assert (set_state (fakesink, GST_STATE_PLAYING, GST_STATE_ASYNC)); + + g_get_current_time (&timeval); + g_time_val_add (&timeval, G_USEC_PER_SEC * 1); + + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_print ("passed..\n"); + gst_object_unref (GST_OBJECT (fakesink)); + + return 0; +} diff --git a/tests/old/testsuite/states/test3.c b/tests/old/testsuite/states/test3.c new file mode 100644 index 0000000000..c49e9d0fec --- /dev/null +++ b/tests/old/testsuite/states/test3.c @@ -0,0 +1,136 @@ +/* GStreamer + * Copyright (C) <2005> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "unistd.h" + +#include + +static GMainLoop *loop; + +static gboolean +message_received (GstBus * bus, GstMessage * message, gpointer ignored) +{ + g_print ("message %p\n", message); + + if (message->type == GST_MESSAGE_EOS) { + g_print ("EOS!!\n"); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } + gst_message_unref (message); + + return TRUE; +} + +static gboolean +set_state (GstElement * element, GstElementState state, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + + g_print ("setting state to %s, expecting %d...", + gst_element_state_get_name (state), expected); + ret = gst_element_set_state (element, state); + res = (ret == expected); + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %d\n", ret); + } + + return res; +} + +static gboolean +get_state (GstElement * element, GstElementState exp_state, + GstElementState exp_pending, GTimeVal * timeval, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + GstElementState state, pending; + + g_print ("getting state: expecting %s, %s, %d...", + gst_element_state_get_name (exp_state), + gst_element_state_get_name (exp_pending), expected); + + ret = gst_element_get_state (element, &state, &pending, timeval); + + res = (ret == expected); + res &= (state == exp_state); + res &= (pending == exp_pending); + + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %s, %s, %d\n", + gst_element_state_get_name (state), + gst_element_state_get_name (pending), ret); + } + + return res; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstElement *bin; + GstBus *bus; + GstClock *clock; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + bus = gst_bus_new (); + gst_bus_add_watch (bus, (GstBusHandler) message_received, NULL); + + clock = gst_system_clock_obtain (); + g_assert (clock != NULL); + + bin = gst_element_factory_make ("bin", "bin"); + g_assert (bin); + + gst_element_set_bus (bin, bus); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PLAYING, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_PLAYING, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_print ("passed..\n"); + gst_object_unref (GST_OBJECT (bin)); + + return 0; +} diff --git a/tests/old/testsuite/states/test4.c b/tests/old/testsuite/states/test4.c new file mode 100644 index 0000000000..d664adb2c4 --- /dev/null +++ b/tests/old/testsuite/states/test4.c @@ -0,0 +1,230 @@ +/* GStreamer + * Copyright (C) <2005> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "unistd.h" + +#include + +static GMainLoop *loop; + +static gboolean +message_received (GstBus * bus, GstMessage * message, gpointer ignored) +{ + g_print ("message %p\n", message); + + if (message->type == GST_MESSAGE_EOS) { + g_print ("EOS!!\n"); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } + gst_message_unref (message); + + return TRUE; +} + +static gboolean +set_state (GstElement * element, GstElementState state, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + + g_print ("setting %s state to %s, expecting %d...", + gst_element_get_name (element), + gst_element_state_get_name (state), expected); + ret = gst_element_set_state (element, state); + res = (ret == expected); + g_print ("%s\n", res ? "OK" : "failed"); + + return res; +} + +static gboolean +get_state (GstElement * element, GstElementState exp_state, + GstElementState exp_pending, GTimeVal * timeval, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + GstElementState state, pending; + + g_print ("getting state %s: expecting %s, %s, %d...", + gst_element_get_name (element), + gst_element_state_get_name (exp_state), + gst_element_state_get_name (exp_pending), expected); + + ret = gst_element_get_state (element, &state, &pending, timeval); + + res = (ret == expected); + res &= (state == exp_state); + res &= (pending == exp_pending); + + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %s, %s, %d\n", + gst_element_state_get_name (state), + gst_element_state_get_name (pending), ret); + } + + return res; +} + +static gboolean +commit_callback (GstClock * clock, GstClockTime time, + GstClockID id, GstElement * element) +{ + g_print ("commiting state change.."); + gst_element_commit_state (element); + + return FALSE; +} + +static gboolean +abort_callback (GstClock * clock, GstClockTime time, + GstClockID id, GstElement * element) +{ + g_print ("aborting state change.."); + gst_element_abort_state (element); + + return FALSE; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstElement *fakesink, *bin; + GstBus *bus; + GTimeVal timeval; + GstClock *clock; + GstClockID id; + GstClockTime base; + GstClockReturn result; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + bus = gst_bus_new (); + gst_bus_add_watch (bus, (GstBusHandler) message_received, NULL); + + clock = gst_system_clock_obtain (); + g_assert (clock != NULL); + + fakesink = gst_element_factory_make ("fakesink", "fakesink"); + g_assert (fakesink); + bin = gst_element_factory_make ("bin", "bin"); + g_assert (bin); + + gst_bin_add (GST_BIN (bin), fakesink); + + gst_element_set_bus (bin, bus); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_NULL, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_NULL, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_get_current_time (&timeval); + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_ASYNC)); + + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_ASYNC)); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, + &timeval, GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + g_assert (get_state (bin, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + base = gst_clock_get_time (clock); + id = gst_clock_new_single_shot_id (clock, base + 1 * GST_SECOND); + g_print ("waiting one second async id %p to abort state\n", id); + result = + gst_clock_id_wait_async (id, (GstClockCallback) abort_callback, fakesink); + gst_clock_id_unref (id); + g_assert (result == GST_CLOCK_OK); + + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_PAUSED, NULL, + GST_STATE_FAILURE)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + base = gst_clock_get_time (clock); + id = gst_clock_new_single_shot_id (clock, base + 1 * GST_SECOND); + g_print ("waiting one second async id %p to commit state\n", id); + result = + gst_clock_id_wait_async (id, (GstClockCallback) commit_callback, + fakesink); + gst_clock_id_unref (id); + g_assert (result == GST_CLOCK_OK); + + g_assert (get_state (bin, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_print ("passed..\n"); + gst_object_unref (GST_OBJECT (fakesink)); + + return 0; +} diff --git a/testsuite/states/.gitignore b/testsuite/states/.gitignore index 9d274cca42..ae643e03fd 100644 --- a/testsuite/states/.gitignore +++ b/testsuite/states/.gitignore @@ -6,6 +6,10 @@ Makefile.in .deps .libs +test1 +test2 +test3 +test4 bin locked parent diff --git a/testsuite/states/Makefile.am b/testsuite/states/Makefile.am index 2a01e7553e..5aa2c0d078 100644 --- a/testsuite/states/Makefile.am +++ b/testsuite/states/Makefile.am @@ -1,5 +1,5 @@ include ../Rules -tests_pass = locked parent +tests_pass = test1 test2 test3 test4 locked parent tests_fail = -tests_ignore = bin +tests_ignore = diff --git a/testsuite/states/locked.c b/testsuite/states/locked.c index e73413c273..d66565ddeb 100644 --- a/testsuite/states/locked.c +++ b/testsuite/states/locked.c @@ -21,6 +21,8 @@ #include +static GMainLoop *loop; + static gboolean message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline) { @@ -28,7 +30,8 @@ message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline) if (message->type == GST_MESSAGE_EOS) { g_print ("EOS!!\n"); - gst_main_quit (); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); } gst_message_unref (message); @@ -47,8 +50,10 @@ main (gint argc, gchar * argv[]) pipeline = gst_pipeline_new ("pipeline"); - bus = GST_PIPELINE (pipeline)->bus; + loop = g_main_loop_new (NULL, FALSE); + bus = gst_element_get_bus (pipeline); gst_bus_add_watch (bus, (GstBusHandler) message_received, pipeline); + gst_object_unref (GST_OBJECT (bus)); fakesrc1 = gst_element_factory_make ("fakesrc", "fakesrc1"); g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL); @@ -77,7 +82,7 @@ main (gint argc, gchar * argv[]) g_print ("play..\n"); gst_element_set_state (pipeline, GST_STATE_PLAYING); - gst_main (); + g_main_loop_run (loop); g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL); @@ -89,7 +94,7 @@ main (gint argc, gchar * argv[]) g_print ("play..\n"); gst_element_set_state (pipeline, GST_STATE_PLAYING); - gst_main (); + g_main_loop_run (loop); gst_element_set_state (pipeline, GST_STATE_NULL); diff --git a/testsuite/states/parent.c b/testsuite/states/parent.c index aa583c5aa3..fe8b2441c6 100644 --- a/testsuite/states/parent.c +++ b/testsuite/states/parent.c @@ -67,7 +67,7 @@ main (gint argc, gchar * argv[]) gst_bin_add (GST_BIN (pipeline), bin2); g_signal_connect (G_OBJECT (pipeline), "deep_notify", - G_CALLBACK (gst_element_default_deep_notify), NULL); + G_CALLBACK (gst_object_default_deep_notify), NULL); /* setting pipeline to READY should bring in all children to READY */ gst_element_set_state (pipeline, GST_STATE_READY); @@ -77,31 +77,35 @@ main (gint argc, gchar * argv[]) g_assert (GST_STATE (identity) == GST_STATE_READY); g_assert (GST_STATE (fakesink) == GST_STATE_READY); - /* setting fakesink to PAUSED should set pipeline and bin2 to PAUSED */ + /* setting fakesink to PAUSED should not affect pipeline and bin2 */ gst_element_set_state (fakesink, GST_STATE_PAUSED); g_assert (GST_STATE (bin1) == GST_STATE_READY); - g_assert (GST_STATE (bin2) == GST_STATE_PAUSED); + g_assert (GST_STATE (bin2) == GST_STATE_READY); g_assert (GST_STATE (fakesrc) == GST_STATE_READY); g_assert (GST_STATE (identity) == GST_STATE_READY); - g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED); + g_assert (GST_STATE (fakesink) == GST_STATE_READY); - /* setting fakesrc to PAUSED should set bin1 and fakesrc to PAUSED */ + /* setting fakesrc to PAUSED should not affect bin1 */ gst_element_set_state (fakesrc, GST_STATE_PAUSED); - g_assert (GST_STATE (bin1) == GST_STATE_PAUSED); - g_assert (GST_STATE (bin2) == GST_STATE_PAUSED); + g_assert (GST_STATE (bin1) == GST_STATE_READY); + g_assert (GST_STATE (bin2) == GST_STATE_READY); g_assert (GST_STATE (fakesrc) == GST_STATE_PAUSED); g_assert (GST_STATE (identity) == GST_STATE_READY); - g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED); + g_assert (GST_STATE (fakesink) == GST_STATE_READY); /* setting bin1 to PAUSED, even though it is already, should set * identity to PAUSED as well */ gst_element_set_state (bin1, GST_STATE_PAUSED); + gst_element_get_state (bin2, NULL, NULL, NULL); g_assert (GST_STATE (bin1) == GST_STATE_PAUSED); - g_assert (GST_STATE (bin2) == GST_STATE_PAUSED); + g_assert (GST_STATE (bin2) == GST_STATE_READY); g_assert (GST_STATE (fakesrc) == GST_STATE_PAUSED); g_assert (GST_STATE (identity) == GST_STATE_PAUSED); g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_usleep (1000000); + g_print ("passed.\n"); return 0; } diff --git a/testsuite/states/test1.c b/testsuite/states/test1.c new file mode 100644 index 0000000000..9a8ced3678 --- /dev/null +++ b/testsuite/states/test1.c @@ -0,0 +1,208 @@ +/* GStreamer + * Copyright (C) <2005> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "unistd.h" + +#include + +static GMainLoop *loop; + +static gboolean +message_received (GstBus * bus, GstMessage * message, gpointer ignored) +{ + g_print ("message %p\n", message); + + if (message->type == GST_MESSAGE_EOS) { + g_print ("EOS!!\n"); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } + gst_message_unref (message); + + return TRUE; +} + +static gboolean +set_state (GstElement * element, GstElementState state, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + + g_print ("setting state to %s, expecting %d...", + gst_element_state_get_name (state), expected); + ret = gst_element_set_state (element, state); + res = (ret == expected); + g_print ("%s\n", res ? "OK" : "failed"); + + return res; +} + +static gboolean +get_state (GstElement * element, GstElementState exp_state, + GstElementState exp_pending, GTimeVal * timeval, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + GstElementState state, pending; + + g_print ("getting state: expecting %s, %s, %d...", + gst_element_state_get_name (exp_state), + gst_element_state_get_name (exp_pending), expected); + + ret = gst_element_get_state (element, &state, &pending, timeval); + + res = (ret == expected); + res &= (state == exp_state); + res &= (pending == exp_pending); + + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %s, %s, %d\n", + gst_element_state_get_name (state), + gst_element_state_get_name (pending), ret); + } + + return res; +} + +static gboolean +commit_callback (GstClock * clock, GstClockTime time, + GstClockID id, GstElement * element) +{ + g_print ("commiting state change.."); + gst_element_commit_state (element); + + return FALSE; +} + +static gboolean +abort_callback (GstClock * clock, GstClockTime time, + GstClockID id, GstElement * element) +{ + g_print ("aborting state change.."); + gst_element_abort_state (element); + + return FALSE; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstElement *fakesink; + GstBus *bus; + GTimeVal timeval; + GstClock *clock; + GstClockID id; + GstClockTime base; + GstClockReturn result; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + bus = gst_bus_new (); + gst_bus_add_watch (bus, (GstBusHandler) message_received, NULL); + + clock = gst_system_clock_obtain (); + g_assert (clock != NULL); + + fakesink = gst_element_factory_make ("fakesink", "fakesink"); + g_assert (fakesink); + + gst_element_set_bus (fakesink, bus); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + g_get_current_time (&timeval); + g_time_val_add (&timeval, G_USEC_PER_SEC * 1); + + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_print ("aborting state change..\n"); + gst_element_abort_state (fakesink); + + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_FAILURE)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_print ("commiting state change..\n"); + gst_element_commit_state (fakesink); + + g_assert (get_state (fakesink, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, + &timeval, GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, + &timeval, GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + base = gst_clock_get_time (clock); + id = gst_clock_new_single_shot_id (clock, base + 1 * GST_SECOND); + g_print ("waiting one second async id %p to abort state\n", id); + result = + gst_clock_id_wait_async (id, (GstClockCallback) abort_callback, fakesink); + gst_clock_id_unref (id); + g_assert (result == GST_CLOCK_OK); + + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, NULL, + GST_STATE_FAILURE)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, NULL, + GST_STATE_FAILURE)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + id = gst_clock_new_single_shot_id (clock, base + 1 * GST_SECOND); + g_print ("waiting one second async id %p to commit state\n", id); + result = + gst_clock_id_wait_async (id, (GstClockCallback) commit_callback, + fakesink); + gst_clock_id_unref (id); + g_assert (result == GST_CLOCK_OK); + + g_assert (get_state (fakesink, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_print ("passed..\n"); + gst_object_unref (GST_OBJECT (fakesink)); + + return 0; +} diff --git a/testsuite/states/test2.c b/testsuite/states/test2.c new file mode 100644 index 0000000000..260e362246 --- /dev/null +++ b/testsuite/states/test2.c @@ -0,0 +1,131 @@ +/* GStreamer + * Copyright (C) <2005> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "unistd.h" + +#include + +static GMainLoop *loop; + +static gboolean +message_received (GstBus * bus, GstMessage * message, gpointer ignored) +{ + g_print ("message %p\n", message); + + if (message->type == GST_MESSAGE_EOS) { + g_print ("EOS!!\n"); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } + gst_message_unref (message); + + return TRUE; +} + +static gboolean +set_state (GstElement * element, GstElementState state, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + + g_print ("setting state to %s, expecting %d...", + gst_element_state_get_name (state), expected); + ret = gst_element_set_state (element, state); + res = (ret == expected); + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %d\n", ret); + } + + return res; +} + +static gboolean +get_state (GstElement * element, GstElementState exp_state, + GstElementState exp_pending, GTimeVal * timeval, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + GstElementState state, pending; + + g_print ("getting state: expecting %s, %s, %d...", + gst_element_state_get_name (exp_state), + gst_element_state_get_name (exp_pending), expected); + + ret = gst_element_get_state (element, &state, &pending, timeval); + + res = (ret == expected); + res &= (state == exp_state); + res &= (pending == exp_pending); + + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %s, %s, %d\n", + gst_element_state_get_name (state), + gst_element_state_get_name (pending), ret); + } + + return res; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstElement *fakesink; + GstBus *bus; + GTimeVal timeval; + GstClock *clock; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + bus = gst_bus_new (); + gst_bus_add_watch (bus, (GstBusHandler) message_received, NULL); + + clock = gst_system_clock_obtain (); + g_assert (clock != NULL); + + fakesink = gst_element_factory_make ("fakesink", "fakesink"); + g_assert (fakesink); + + gst_element_set_bus (fakesink, bus); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + g_assert (set_state (fakesink, GST_STATE_PLAYING, GST_STATE_ASYNC)); + + g_get_current_time (&timeval); + g_time_val_add (&timeval, G_USEC_PER_SEC * 1); + + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_print ("passed..\n"); + gst_object_unref (GST_OBJECT (fakesink)); + + return 0; +} diff --git a/testsuite/states/test3.c b/testsuite/states/test3.c new file mode 100644 index 0000000000..c49e9d0fec --- /dev/null +++ b/testsuite/states/test3.c @@ -0,0 +1,136 @@ +/* GStreamer + * Copyright (C) <2005> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "unistd.h" + +#include + +static GMainLoop *loop; + +static gboolean +message_received (GstBus * bus, GstMessage * message, gpointer ignored) +{ + g_print ("message %p\n", message); + + if (message->type == GST_MESSAGE_EOS) { + g_print ("EOS!!\n"); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } + gst_message_unref (message); + + return TRUE; +} + +static gboolean +set_state (GstElement * element, GstElementState state, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + + g_print ("setting state to %s, expecting %d...", + gst_element_state_get_name (state), expected); + ret = gst_element_set_state (element, state); + res = (ret == expected); + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %d\n", ret); + } + + return res; +} + +static gboolean +get_state (GstElement * element, GstElementState exp_state, + GstElementState exp_pending, GTimeVal * timeval, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + GstElementState state, pending; + + g_print ("getting state: expecting %s, %s, %d...", + gst_element_state_get_name (exp_state), + gst_element_state_get_name (exp_pending), expected); + + ret = gst_element_get_state (element, &state, &pending, timeval); + + res = (ret == expected); + res &= (state == exp_state); + res &= (pending == exp_pending); + + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %s, %s, %d\n", + gst_element_state_get_name (state), + gst_element_state_get_name (pending), ret); + } + + return res; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstElement *bin; + GstBus *bus; + GstClock *clock; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + bus = gst_bus_new (); + gst_bus_add_watch (bus, (GstBusHandler) message_received, NULL); + + clock = gst_system_clock_obtain (); + g_assert (clock != NULL); + + bin = gst_element_factory_make ("bin", "bin"); + g_assert (bin); + + gst_element_set_bus (bin, bus); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PLAYING, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_PLAYING, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_print ("passed..\n"); + gst_object_unref (GST_OBJECT (bin)); + + return 0; +} diff --git a/testsuite/states/test4.c b/testsuite/states/test4.c new file mode 100644 index 0000000000..d664adb2c4 --- /dev/null +++ b/testsuite/states/test4.c @@ -0,0 +1,230 @@ +/* GStreamer + * Copyright (C) <2005> Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "unistd.h" + +#include + +static GMainLoop *loop; + +static gboolean +message_received (GstBus * bus, GstMessage * message, gpointer ignored) +{ + g_print ("message %p\n", message); + + if (message->type == GST_MESSAGE_EOS) { + g_print ("EOS!!\n"); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + } + gst_message_unref (message); + + return TRUE; +} + +static gboolean +set_state (GstElement * element, GstElementState state, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + + g_print ("setting %s state to %s, expecting %d...", + gst_element_get_name (element), + gst_element_state_get_name (state), expected); + ret = gst_element_set_state (element, state); + res = (ret == expected); + g_print ("%s\n", res ? "OK" : "failed"); + + return res; +} + +static gboolean +get_state (GstElement * element, GstElementState exp_state, + GstElementState exp_pending, GTimeVal * timeval, + GstElementStateReturn expected) +{ + GstElementStateReturn ret; + gboolean res; + GstElementState state, pending; + + g_print ("getting state %s: expecting %s, %s, %d...", + gst_element_get_name (element), + gst_element_state_get_name (exp_state), + gst_element_state_get_name (exp_pending), expected); + + ret = gst_element_get_state (element, &state, &pending, timeval); + + res = (ret == expected); + res &= (state == exp_state); + res &= (pending == exp_pending); + + if (res) { + g_print ("OK\n"); + } else { + g_print ("failed, got %s, %s, %d\n", + gst_element_state_get_name (state), + gst_element_state_get_name (pending), ret); + } + + return res; +} + +static gboolean +commit_callback (GstClock * clock, GstClockTime time, + GstClockID id, GstElement * element) +{ + g_print ("commiting state change.."); + gst_element_commit_state (element); + + return FALSE; +} + +static gboolean +abort_callback (GstClock * clock, GstClockTime time, + GstClockID id, GstElement * element) +{ + g_print ("aborting state change.."); + gst_element_abort_state (element); + + return FALSE; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstElement *fakesink, *bin; + GstBus *bus; + GTimeVal timeval; + GstClock *clock; + GstClockID id; + GstClockTime base; + GstClockReturn result; + + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + bus = gst_bus_new (); + gst_bus_add_watch (bus, (GstBusHandler) message_received, NULL); + + clock = gst_system_clock_obtain (); + g_assert (clock != NULL); + + fakesink = gst_element_factory_make ("fakesink", "fakesink"); + g_assert (fakesink); + bin = gst_element_factory_make ("bin", "bin"); + g_assert (bin); + + gst_bin_add (GST_BIN (bin), fakesink); + + gst_element_set_bus (bin, bus); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (fakesink, GST_STATE_NULL, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_NULL, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_get_current_time (&timeval); + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + + g_assert (set_state (fakesink, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_ASYNC)); + + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_ASYNC)); + + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_PAUSED, &timeval, + GST_STATE_ASYNC)); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_SUCCESS)); + g_assert (get_state (fakesink, GST_STATE_READY, GST_STATE_VOID_PENDING, + &timeval, GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_ASYNC)); + g_assert (set_state (fakesink, GST_STATE_READY, GST_STATE_SUCCESS)); + g_time_val_add (&timeval, G_USEC_PER_SEC / 2); + g_assert (get_state (bin, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_READY, GST_STATE_SUCCESS)); + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_VOID_PENDING, &timeval, + GST_STATE_SUCCESS)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + base = gst_clock_get_time (clock); + id = gst_clock_new_single_shot_id (clock, base + 1 * GST_SECOND); + g_print ("waiting one second async id %p to abort state\n", id); + result = + gst_clock_id_wait_async (id, (GstClockCallback) abort_callback, fakesink); + gst_clock_id_unref (id); + g_assert (result == GST_CLOCK_OK); + + g_assert (get_state (bin, GST_STATE_READY, GST_STATE_PAUSED, NULL, + GST_STATE_FAILURE)); + + g_assert (set_state (bin, GST_STATE_PAUSED, GST_STATE_ASYNC)); + + base = gst_clock_get_time (clock); + id = gst_clock_new_single_shot_id (clock, base + 1 * GST_SECOND); + g_print ("waiting one second async id %p to commit state\n", id); + result = + gst_clock_id_wait_async (id, (GstClockCallback) commit_callback, + fakesink); + gst_clock_id_unref (id); + g_assert (result == GST_CLOCK_OK); + + g_assert (get_state (bin, GST_STATE_PAUSED, GST_STATE_VOID_PENDING, NULL, + GST_STATE_SUCCESS)); + + g_print ("passed..\n"); + gst_object_unref (GST_OBJECT (fakesink)); + + return 0; +}