mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-20 22:28:22 +00:00
Clock fixes. Added async callbacks and clock unscheduling.
Original commit message from CVS: Clock fixes. Added async callbacks and clock unscheduling. Threading fixes. Fixed race condition in GstTask and possible deadlock in _pad_get_caps(). Made various subsystems (query, format,..) threadsafe. Lots of cleanups and documentation.
This commit is contained in:
parent
2b58a38a2b
commit
74ca793b0a
49 changed files with 1732 additions and 603 deletions
105
ChangeLog
105
ChangeLog
|
@ -1,3 +1,108 @@
|
|||
2005-01-06 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/elements/gstfakesrc.c: (gst_fakesrc_loop),
|
||||
(gst_fakesrc_activate):
|
||||
* gst/elements/gstfilesrc.c: (gst_filesrc_getrange),
|
||||
(gst_filesrc_loop), (gst_filesrc_activate):
|
||||
* 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_remove_func), (gst_bin_iterate_elements),
|
||||
(bin_element_is_sink), (gst_bin_get_state), (gst_bin_change_state),
|
||||
(gst_bin_get_by_name), (gst_bin_get_by_name_recurse_up):
|
||||
* gst/gstbuffer.c: (gst_buffer_get_type), (gst_buffer_set_caps):
|
||||
* gst/gstbuffer.h:
|
||||
* gst/gstbus.c: (gst_bus_post), (gst_bus_create_watch),
|
||||
(bus_destroy):
|
||||
* gst/gstbus.h:
|
||||
* gst/gstclock.c: (gst_clock_entry_new), (gst_clock_id_ref),
|
||||
(_gst_clock_id_free), (gst_clock_id_unref),
|
||||
(gst_clock_id_compare_func), (gst_clock_id_wait),
|
||||
(gst_clock_id_wait_async), (gst_clock_class_init),
|
||||
(gst_clock_init), (gst_clock_dispose), (gst_clock_get_time),
|
||||
(gst_clock_set_time_adjust), (gst_clock_set_property),
|
||||
(gst_clock_get_property):
|
||||
* gst/gstclock.h:
|
||||
* gst/gstelement.c: (gst_element_add_pad),
|
||||
(gst_element_remove_pad), (gst_element_post_message),
|
||||
(gst_element_set_locked_state),
|
||||
(gst_element_sync_state_with_parent), (gst_element_get_state_func),
|
||||
(gst_element_abort_state), (gst_element_commit_state),
|
||||
(gst_element_pads_activate):
|
||||
* gst/gstelement.h:
|
||||
* gst/gstformat.c: (_gst_format_initialize), (gst_format_register),
|
||||
(gst_format_get_by_nick), (gst_format_get_details),
|
||||
(gst_format_iterate_definitions):
|
||||
* gst/gstformat.h:
|
||||
* gst/gstiterator.c: (gst_iterator_new), (gst_list_iterator_next),
|
||||
(gst_list_iterator_free), (gst_iterator_new_list),
|
||||
(gst_iterator_next), (gst_iterator_resync), (filter_next):
|
||||
* gst/gstiterator.h:
|
||||
* gst/gstmemchunk.c: (gst_mem_chunk_alloc), (gst_mem_chunk_alloc0),
|
||||
(gst_mem_chunk_free):
|
||||
* gst/gstmessage.c: (_gst_message_free):
|
||||
* gst/gstmessage.h:
|
||||
* gst/gstobject.c: (gst_object_class_init), (gst_object_init),
|
||||
(gst_object_ref), (gst_object_unref), (gst_object_sink),
|
||||
(gst_object_dispose), (gst_object_dispatch_properties_changed),
|
||||
(gst_object_set_name_default), (gst_object_set_name),
|
||||
(gst_object_set_parent), (gst_object_unparent),
|
||||
(gst_object_check_uniqueness), (gst_object_get_path_string):
|
||||
* gst/gstpad.c: (gst_pad_set_active), (gst_pad_set_blocked_async),
|
||||
(gst_pad_set_acceptcaps_function),
|
||||
(gst_pad_set_fixatecaps_function), (gst_pad_unlink),
|
||||
(gst_pad_link_prepare_filtered), (gst_pad_link_filtered),
|
||||
(gst_pad_set_pad_template), (gst_pad_relink_filtered),
|
||||
(gst_real_pad_get_caps_unlocked), (gst_pad_peer_get_caps),
|
||||
(gst_pad_fixate_caps), (gst_pad_accept_caps),
|
||||
(gst_pad_peer_accept_caps), (gst_pad_set_caps),
|
||||
(gst_pad_configure_sink), (gst_pad_configure_src),
|
||||
(gst_pad_realize), (gst_pad_alloc_buffer), (gst_pad_push),
|
||||
(gst_pad_pull_range), (gst_pad_push_event), (gst_pad_send_event):
|
||||
* gst/gstpad.h:
|
||||
* gst/gstpipeline.c: (is_eos), (pipeline_bus_handler),
|
||||
(gst_pipeline_change_state), (gst_pipeline_get_clock_func),
|
||||
(gst_pipeline_use_clock), (gst_pipeline_auto_clock):
|
||||
* gst/gstpipeline.h:
|
||||
* gst/gstpluginfeature.c: (gst_plugin_feature_get_name),
|
||||
(gst_plugin_feature_set_rank), (gst_plugin_feature_get_rank):
|
||||
* gst/gstpluginfeature.h:
|
||||
* gst/gstprobe.c: (gst_probe_dispatcher_dispatch):
|
||||
* gst/gstquery.c: (_gst_query_type_initialize),
|
||||
(gst_query_type_register), (gst_query_type_get_by_nick),
|
||||
(gst_query_type_get_details), (gst_query_type_iterate_definitions):
|
||||
* gst/gstquery.h:
|
||||
* gst/gstqueue.c: (gst_queue_init), (gst_queue_bufferalloc),
|
||||
(gst_queue_loop):
|
||||
* gst/gstsystemclock.c: (gst_system_clock_class_init),
|
||||
(gst_system_clock_init), (gst_system_clock_dispose),
|
||||
(gst_system_clock_async_thread), (gst_system_clock_id_wait),
|
||||
(gst_system_clock_id_wait_async), (gst_system_clock_id_unschedule):
|
||||
* gst/gstsystemclock.h:
|
||||
* gst/gsttask.c: (gst_task_init), (gst_task_dispose),
|
||||
(gst_task_create), (gst_task_get_state), (gst_task_start),
|
||||
(gst_task_stop), (gst_task_pause):
|
||||
* gst/gsttask.h:
|
||||
* gst/gsttrashstack.h:
|
||||
* gst/schedulers/threadscheduler.c:
|
||||
(gst_thread_scheduler_task_init),
|
||||
(gst_thread_scheduler_task_start),
|
||||
(gst_thread_scheduler_task_stop),
|
||||
(gst_thread_scheduler_task_pause), (gst_thread_scheduler_func),
|
||||
(gst_thread_scheduler_create_task):
|
||||
* testsuite/clock/.cvsignore:
|
||||
* testsuite/clock/Makefile.am:
|
||||
* testsuite/clock/clock1.c: (main):
|
||||
* testsuite/clock/clock2.c: (gst_clock_debug), (element_wait),
|
||||
(main):
|
||||
* testsuite/clock/clock3.c: (gst_clock_debug), (ok_callback),
|
||||
(error_callback), (main):
|
||||
Clock fixes. Added async callbacks and clock unscheduling.
|
||||
Threading fixes. Fixed race condition in GstTask and possible
|
||||
deadlock in _pad_get_caps(). Made various subsystems (query,
|
||||
format,..) threadsafe.
|
||||
Lots of cleanups and documentation.
|
||||
|
||||
|
||||
2005-01-04 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/elements/gstfilesrc.c: (gst_filesrc_getrange),
|
||||
|
|
|
@ -189,7 +189,7 @@ static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
|
|||
|
||||
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
|
||||
|
||||
static gboolean gst_fakesrc_loop (GstPad * pad);
|
||||
static void gst_fakesrc_loop (GstPad * pad);
|
||||
|
||||
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
@ -778,13 +778,12 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
|
|||
return buf;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
gst_fakesrc_loop (GstPad * pad)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
GstBuffer *buf;
|
||||
GstClockTime time;
|
||||
gboolean result = TRUE;
|
||||
|
||||
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
|
@ -799,14 +798,14 @@ gst_fakesrc_loop (GstPad * pad)
|
|||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||
} else {
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
result = FALSE;
|
||||
gst_task_pause (src->task);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (src->rt_num_buffers == 0) {
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
result = FALSE;
|
||||
gst_task_pause (src->task);
|
||||
goto done;
|
||||
} else {
|
||||
if (src->rt_num_buffers > 0)
|
||||
|
@ -816,7 +815,7 @@ gst_fakesrc_loop (GstPad * pad)
|
|||
if (src->eos) {
|
||||
GST_INFO ("fakesrc is setting eos on pad");
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
result = FALSE;
|
||||
gst_task_pause (src->task);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -860,8 +859,6 @@ gst_fakesrc_loop (GstPad * pad)
|
|||
|
||||
done:
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -881,7 +881,7 @@ gst_filesrc_close_file (GstFileSrc * src)
|
|||
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
gst_filesrc_loop (GstElement * element)
|
||||
{
|
||||
GstFileSrc *filesrc;
|
||||
|
@ -892,14 +892,13 @@ gst_filesrc_loop (GstElement * element)
|
|||
|
||||
result = gst_filesrc_get (filesrc->srcpad, &buffer);
|
||||
if (result != GST_FLOW_OK) {
|
||||
return FALSE;
|
||||
gst_task_stop (filesrc->task);
|
||||
return;
|
||||
}
|
||||
result = gst_pad_push (filesrc->srcpad, buffer);
|
||||
if (result != GST_FLOW_OK) {
|
||||
return FALSE;
|
||||
gst_task_stop (filesrc->task);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
210
gst/gstbin.c
210
gst/gstbin.c
|
@ -198,6 +198,10 @@ gst_bin_new (const gchar * name)
|
|||
return gst_element_factory_make ("bin", name);
|
||||
}
|
||||
|
||||
/* set the index on all elements in this bin
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
#ifndef GST_DISABLE_INDEX
|
||||
static void
|
||||
gst_bin_set_index (GstElement * element, GstIndex * index)
|
||||
|
@ -217,6 +221,10 @@ gst_bin_set_index (GstElement * element, GstIndex * index)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* set the clock on all elements in this bin
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
static void
|
||||
gst_bin_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
|
@ -234,6 +242,10 @@ gst_bin_set_clock (GstElement * element, GstClock * clock)
|
|||
GST_UNLOCK (bin);
|
||||
}
|
||||
|
||||
/* get the clock for this bin by asking all of the children in this bin
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
static GstClock *
|
||||
gst_bin_get_clock (GstElement * element)
|
||||
{
|
||||
|
@ -256,6 +268,10 @@ gst_bin_get_clock (GstElement * element)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* set the bus on all of the children in this bin
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
static void
|
||||
gst_bin_set_bus (GstElement * element, GstBus * bus)
|
||||
{
|
||||
|
@ -275,6 +291,10 @@ gst_bin_set_bus (GstElement * element, GstBus * bus)
|
|||
GST_UNLOCK (bin);
|
||||
}
|
||||
|
||||
/* set the scheduler on all of the children in this bin
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
static void
|
||||
gst_bin_set_scheduler (GstElement * element, GstScheduler * sched)
|
||||
{
|
||||
|
@ -294,6 +314,10 @@ gst_bin_set_scheduler (GstElement * element, GstScheduler * sched)
|
|||
GST_UNLOCK (bin);
|
||||
}
|
||||
|
||||
/* add an element to this bin
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
static gboolean
|
||||
gst_bin_add_func (GstBin * bin, GstElement * element)
|
||||
{
|
||||
|
@ -303,6 +327,8 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
|
|||
if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin)))
|
||||
goto adding_itself;
|
||||
|
||||
/* get the element name to make sure it is unique in this bin, FIXME, another
|
||||
* thread can change the name after the unlock. */
|
||||
GST_LOCK (element);
|
||||
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
||||
GST_UNLOCK (element);
|
||||
|
@ -399,11 +425,16 @@ no_function:
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* remove an element from the bin
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
static gboolean
|
||||
gst_bin_remove_func (GstBin * bin, GstElement * element)
|
||||
{
|
||||
gchar *elem_name;
|
||||
|
||||
/* grab element name so we can print it */
|
||||
GST_LOCK (element);
|
||||
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
||||
GST_UNLOCK (element);
|
||||
|
@ -424,6 +455,8 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
|
|||
g_free (elem_name);
|
||||
|
||||
gst_element_set_manager (element, NULL);
|
||||
gst_element_set_bus (element, NULL);
|
||||
gst_element_set_scheduler (element, NULL);
|
||||
|
||||
/* we ref here because after the _unparent() the element can be disposed
|
||||
* and we still need it to fire a signal. */
|
||||
|
@ -507,6 +540,7 @@ gst_bin_iterate_elements (GstBin * bin)
|
|||
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
||||
|
||||
GST_LOCK (bin);
|
||||
/* add ref because the iterator refs the bin */
|
||||
gst_object_ref (GST_OBJECT (bin));
|
||||
result = gst_iterator_new_list (GST_GET_LOCK (bin),
|
||||
&bin->children_cookie,
|
||||
|
@ -521,18 +555,25 @@ gst_bin_iterate_elements (GstBin * bin)
|
|||
}
|
||||
|
||||
/* returns 0 if the element is a sink, this is made so that
|
||||
* we can use this function as a filter */
|
||||
* we can use this function as a filter
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
static gint
|
||||
bin_element_is_sink (GstElement * child, GstBin * bin)
|
||||
{
|
||||
gint ret = 1;
|
||||
|
||||
/* we lock the child here for the remainder of the function to
|
||||
* get its pads and name safely. */
|
||||
GST_LOCK (child);
|
||||
|
||||
/* check if this is a sink element, these are the elements
|
||||
* without (linked) source pads. */
|
||||
if (child->numsrcpads == 0) {
|
||||
/* shortcut */
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
||||
"adding child %s as sink", gst_element_get_name (child));
|
||||
"adding child %s as sink", GST_OBJECT_NAME (child));
|
||||
ret = 0;
|
||||
} else {
|
||||
/* loop over all pads, try to figure out if this element
|
||||
|
@ -540,26 +581,30 @@ bin_element_is_sink (GstElement * child, GstBin * bin)
|
|||
GList *pads;
|
||||
gboolean connected_src = FALSE;
|
||||
|
||||
/* FIXME not MT safe */
|
||||
for (pads = child->srcpads; pads; pads = g_list_next (pads)) {
|
||||
pads = child->srcpads;
|
||||
while (pads) {
|
||||
GstPad *pad = GST_PAD (pads->data);
|
||||
|
||||
if (GST_PAD_IS_LINKED (pad)) {
|
||||
connected_src = TRUE;
|
||||
break;
|
||||
}
|
||||
pads = g_list_next (pads);
|
||||
}
|
||||
|
||||
if (connected_src) {
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
||||
"not adding child %s as sink: linked source pads",
|
||||
gst_element_get_name (child));
|
||||
GST_OBJECT_NAME (child));
|
||||
} else {
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
||||
"adding child %s as sink since it has unlinked source pads",
|
||||
gst_element_get_name (child));
|
||||
GST_OBJECT_NAME (child));
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
GST_UNLOCK (child);
|
||||
|
||||
/* we did not find the element, need to release the ref
|
||||
* added by the iterator */
|
||||
if (ret == 1)
|
||||
|
@ -595,52 +640,64 @@ gst_bin_iterate_sinks (GstBin * bin)
|
|||
return result;
|
||||
}
|
||||
|
||||
static gint
|
||||
bin_find_pending_child (GstElement * child, GTimeVal * timeout)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
ret = gst_element_get_state (GST_ELEMENT (child), NULL, NULL, timeout);
|
||||
/* ret is false if some child is still performing the state change */
|
||||
gst_object_unref (GST_OBJECT (child));
|
||||
|
||||
return (ret == FALSE ? 0 : 1);
|
||||
}
|
||||
|
||||
/* this functions loops over all children, as soon as one is
|
||||
* still performing the state change, FALSE is returned. */
|
||||
* still performing the state change, FALSE is returned.
|
||||
*
|
||||
* MT safe
|
||||
*/
|
||||
static gboolean
|
||||
gst_bin_get_state (GstElement * element, GstElementState * state,
|
||||
GstElementState * pending, GTimeVal * timeout)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
GstBin *bin = GST_BIN (element);
|
||||
GstIterator *children;
|
||||
gboolean have_async = FALSE;
|
||||
gpointer child;
|
||||
gboolean ret;
|
||||
GList *children;
|
||||
guint32 children_cookie;
|
||||
|
||||
/* we cannot take the state lock yet as we might block when querying
|
||||
* the children, holding the lock too long for no reason */
|
||||
/* FIXME, we can loop the list ourselves instead of creating the
|
||||
* iterator */
|
||||
children = gst_bin_iterate_sinks (bin);
|
||||
child = gst_iterator_find_custom (children, timeout,
|
||||
(GCompareFunc) bin_find_pending_child);
|
||||
gst_iterator_free (children);
|
||||
/* we unreffed the child in the comparefunc */
|
||||
if (child) {
|
||||
have_async = TRUE;
|
||||
ret = FALSE;
|
||||
}
|
||||
* the children, holding the lock too long for no reason. */
|
||||
|
||||
/* next we poll all children for their state to see if one of them
|
||||
* is still busy with its state change. */
|
||||
GST_LOCK (bin);
|
||||
restart:
|
||||
ret = TRUE;
|
||||
children = bin->children;
|
||||
children_cookie = bin->children_cookie;
|
||||
while (children) {
|
||||
GstElement *child = GST_ELEMENT_CAST (children->data);
|
||||
|
||||
gst_object_ref (GST_OBJECT_CAST (child));
|
||||
GST_UNLOCK (bin);
|
||||
|
||||
/* ret is false if some child is still performing the state change */
|
||||
ret = gst_element_get_state (child, NULL, NULL, timeout);
|
||||
|
||||
gst_object_unref (GST_OBJECT_CAST (child));
|
||||
|
||||
if (!ret) {
|
||||
/* some child is still busy, return FALSE */
|
||||
goto done;
|
||||
}
|
||||
/* now grab the lock to iterate to the next child */
|
||||
GST_LOCK (bin);
|
||||
if (G_UNLIKELY (children_cookie != bin->children_cookie))
|
||||
/* child added/removed during state change, restart */
|
||||
goto restart;
|
||||
|
||||
children = g_list_next (children);
|
||||
}
|
||||
GST_UNLOCK (bin);
|
||||
|
||||
done:
|
||||
/* now we can take the state lock */
|
||||
GST_STATE_LOCK (bin);
|
||||
if (!have_async) {
|
||||
if (ret) {
|
||||
/* no async children, we can commit the state */
|
||||
gst_element_commit_state (element);
|
||||
}
|
||||
|
||||
/* and report the state */
|
||||
/* and report the state if needed */
|
||||
if (state)
|
||||
*state = GST_STATE (element);
|
||||
if (pending)
|
||||
|
@ -651,7 +708,10 @@ gst_bin_get_state (GstElement * element, GstElementState * state,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* this function is called with the STATE_LOCK held */
|
||||
/* this function is called with the STATE_LOCK held.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
static GstElementStateReturn
|
||||
gst_bin_change_state (GstElement * element)
|
||||
{
|
||||
|
@ -659,9 +719,8 @@ gst_bin_change_state (GstElement * element)
|
|||
GstElementStateReturn ret;
|
||||
GstElementState old_state, pending;
|
||||
gboolean have_async = FALSE;
|
||||
GstIterator *sinks;
|
||||
gboolean done = FALSE;
|
||||
|
||||
GList *children;
|
||||
guint32 children_cookie;
|
||||
GQueue *elem_queue; /* list of elements waiting for a state change */
|
||||
|
||||
bin = GST_BIN (element);
|
||||
|
@ -677,44 +736,51 @@ gst_bin_change_state (GstElement * element)
|
|||
if (pending == GST_STATE_VOID_PENDING)
|
||||
return GST_STATE_SUCCESS;
|
||||
|
||||
/* all elements added to this queue should have their refcount
|
||||
* incremented */
|
||||
elem_queue = g_queue_new ();
|
||||
|
||||
/* first step, find all sink elements, these are the elements
|
||||
* without (linked) source pads. */
|
||||
/* FIXME, we can iterate the list ourselves */
|
||||
sinks = gst_bin_iterate_sinks (bin);
|
||||
while (!done) {
|
||||
gpointer child;
|
||||
GST_LOCK (bin);
|
||||
restart:
|
||||
children = bin->children;
|
||||
children_cookie = bin->children_cookie;
|
||||
while (children) {
|
||||
GstElement *child = GST_ELEMENT_CAST (children->data);
|
||||
|
||||
switch (gst_iterator_next (sinks, &child)) {
|
||||
case GST_ITERATOR_OK:
|
||||
/* this also keeps the refcount on the element */
|
||||
g_queue_push_tail (elem_queue, child);
|
||||
break;
|
||||
case GST_ITERATOR_RESYNC:
|
||||
/* undo what we had */
|
||||
g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL);
|
||||
while (g_queue_pop_head (elem_queue));
|
||||
gst_iterator_resync (sinks);
|
||||
break;
|
||||
case GST_ITERATOR_DONE:
|
||||
done = TRUE;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
gst_object_ref (GST_OBJECT_CAST (child));
|
||||
GST_UNLOCK (bin);
|
||||
|
||||
if (bin_element_is_sink (child, bin) == 0) {
|
||||
/* this also keeps the refcount on the element, note that
|
||||
* the _is_sink function unrefs the element when it is not
|
||||
* a sink. */
|
||||
g_queue_push_tail (elem_queue, child);
|
||||
}
|
||||
|
||||
GST_LOCK (bin);
|
||||
if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
|
||||
/* undo what we had */
|
||||
g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL);
|
||||
while (g_queue_pop_head (elem_queue));
|
||||
goto restart;
|
||||
}
|
||||
|
||||
children = g_list_next (children);
|
||||
}
|
||||
gst_iterator_free (sinks);
|
||||
GST_UNLOCK (bin);
|
||||
|
||||
/* second step, change state of elements in the queue */
|
||||
while (!g_queue_is_empty (elem_queue)) {
|
||||
GstElement *qelement = g_queue_pop_head (elem_queue);
|
||||
GList *pads;
|
||||
gboolean locked;
|
||||
|
||||
/* queue all elements connected to the sinkpads of this element */
|
||||
/* FIXME, not MT safe !! */
|
||||
for (pads = qelement->sinkpads; pads; pads = g_list_next (pads)) {
|
||||
GST_LOCK (qelement);
|
||||
pads = qelement->sinkpads;
|
||||
while (pads) {
|
||||
GstPad *pad = GST_PAD (pads->data);
|
||||
GstPad *peer;
|
||||
|
||||
|
@ -730,9 +796,10 @@ gst_bin_change_state (GstElement * element)
|
|||
|
||||
if (peer_elem) {
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||
"adding element %s to queue", gst_element_get_name (peer_elem));
|
||||
"adding element %s to queue", GST_ELEMENT_NAME (peer_elem));
|
||||
|
||||
/* is reffed before pushing on the queue */
|
||||
/* 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);
|
||||
}
|
||||
gst_object_unref (GST_OBJECT (peer));
|
||||
|
@ -740,12 +807,15 @@ gst_bin_change_state (GstElement * element)
|
|||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||
"pad %s:%s does not have a peer", GST_DEBUG_PAD_NAME (pad));
|
||||
}
|
||||
pads = g_list_next (pads);
|
||||
}
|
||||
/* peel off the locked flag and release the element lock */
|
||||
locked = GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE);
|
||||
GST_UNLOCK (qelement);
|
||||
|
||||
if (GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE))
|
||||
if (G_UNLIKELY (locked))
|
||||
goto next_element;
|
||||
|
||||
|
||||
qelement->base_time = element->base_time;
|
||||
ret = gst_element_set_state (qelement, pending);
|
||||
switch (ret) {
|
||||
|
@ -853,6 +923,7 @@ gst_bin_get_by_name (GstBin * bin, const gchar * name)
|
|||
GST_CAT_INFO (GST_CAT_PARENTAGE, "[%s]: looking up child element %s",
|
||||
GST_ELEMENT_NAME (bin), name);
|
||||
|
||||
/* we recursively lock all elements, this might be a bit too much.. */
|
||||
GST_LOCK (bin);
|
||||
for (children = bin->children; children; children = g_list_next (children)) {
|
||||
GstElement *child = GST_ELEMENT_CAST (children->data);
|
||||
|
@ -861,6 +932,7 @@ gst_bin_get_by_name (GstBin * bin, const gchar * name)
|
|||
GST_LOCK (child);
|
||||
eq = strcmp (GST_ELEMENT_NAME (child), name) == 0;
|
||||
GST_UNLOCK (child);
|
||||
|
||||
if (eq) {
|
||||
result = child;
|
||||
break;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "gstmemchunk.h"
|
||||
#include "gstinfo.h"
|
||||
|
||||
GType _gst_buffer_type;
|
||||
GType _gst_buffer_type = 0;
|
||||
|
||||
#ifndef GST_DISABLE_TRACE
|
||||
/* #define GST_WITH_ALLOC_TRACE */
|
||||
|
@ -60,7 +60,7 @@ _gst_buffer_initialize (void)
|
|||
GType
|
||||
gst_buffer_get_type (void)
|
||||
{
|
||||
if (_gst_buffer_type == 0) {
|
||||
if (G_UNLIKELY (_gst_buffer_type == 0)) {
|
||||
_gst_buffer_type = g_boxed_type_register_static ("GstBuffer",
|
||||
(GBoxedCopyFunc) gst_data_copy, (GBoxedFreeFunc) gst_data_unref);
|
||||
}
|
||||
|
@ -88,6 +88,8 @@ _gst_buffer_sub_free (GstBuffer * buffer)
|
|||
*
|
||||
* Frees the memory associated with the buffer including the buffer data,
|
||||
* unless the GST_BUFFER_DONTFREE flags was set or the buffer data is NULL.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_buffer_default_free (GstBuffer * buffer)
|
||||
|
@ -121,6 +123,8 @@ gst_buffer_default_free (GstBuffer * buffer)
|
|||
* is increased.
|
||||
*
|
||||
* Returns: the new #GstBuffer.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_buffer_default_copy (GstBuffer * buffer)
|
||||
|
@ -194,6 +198,8 @@ gst_buffer_free_chunk (GstBuffer * buffer)
|
|||
* Creates a newly allocated buffer without any data.
|
||||
*
|
||||
* Returns: the new #GstBuffer.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_buffer_new (void)
|
||||
|
@ -231,6 +237,8 @@ gst_buffer_new (void)
|
|||
* Creates a newly allocated buffer with data of the given size.
|
||||
*
|
||||
* Returns: the new #GstBuffer.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_buffer_new_and_alloc (guint size)
|
||||
|
@ -255,9 +263,14 @@ gst_buffer_new_and_alloc (guint size)
|
|||
* is not media type attached to this buffer or when the media
|
||||
* type is the same as the previous received buffer.
|
||||
*
|
||||
* This function does not increment the refcount of the caps. The
|
||||
* caps pointer will therefore remain valid until the buffer is
|
||||
* unreffed.
|
||||
*
|
||||
* Returns: the #GstCaps, or NULL if there was an error or there
|
||||
* were no caps on this buffer.
|
||||
*/
|
||||
/* FIXME can we make this threadsafe without a lock on the buffer? */
|
||||
GstCaps *
|
||||
gst_buffer_get_caps (GstBuffer * buffer)
|
||||
{
|
||||
|
@ -275,21 +288,26 @@ gst_buffer_get_caps (GstBuffer * buffer)
|
|||
* be increased and any previous caps on the buffer will be
|
||||
* unreffed.
|
||||
*/
|
||||
/* FIXME can we make this threadsafe without a lock on the buffer? */
|
||||
void
|
||||
gst_buffer_set_caps (GstBuffer * buffer, GstCaps * caps)
|
||||
{
|
||||
GstCaps *oldcaps;
|
||||
|
||||
g_return_if_fail (buffer != NULL);
|
||||
|
||||
/* unref old caps if any */
|
||||
if (GST_BUFFER_CAPS (buffer)) {
|
||||
gst_caps_unref (GST_BUFFER_CAPS (buffer));
|
||||
}
|
||||
/* get old caps */
|
||||
oldcaps = GST_BUFFER_CAPS (buffer);
|
||||
/* ref new caps if any */
|
||||
if (caps)
|
||||
caps = gst_caps_ref (caps);
|
||||
|
||||
/* set caps */
|
||||
GST_BUFFER_CAPS (buffer) = caps;
|
||||
|
||||
/* unref old caps if any */
|
||||
if (oldcaps) {
|
||||
gst_caps_unref (oldcaps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,6 +323,8 @@ gst_buffer_set_caps (GstBuffer * buffer, GstCaps * caps)
|
|||
* The duration field of the new buffer are set to GST_CLOCK_TIME_NONE.
|
||||
*
|
||||
* Returns: the new #GstBuffer, or NULL if there was an error.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_buffer_create_sub (GstBuffer * parent, guint offset, guint size)
|
||||
|
@ -381,6 +401,8 @@ gst_buffer_create_sub (GstBuffer * parent, guint offset, guint size)
|
|||
* is created without copying the data.
|
||||
*
|
||||
* Returns: the new #GstBuffer that's the concatenation of the source buffers.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
|
||||
|
@ -403,6 +425,8 @@ gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
|
|||
*
|
||||
* Returns: TRUE if the buffers are contiguous,
|
||||
* FALSE if a copy would be required.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gboolean
|
||||
gst_buffer_is_span_fast (GstBuffer * buf1, GstBuffer * buf2)
|
||||
|
@ -437,6 +461,8 @@ gst_buffer_is_span_fast (GstBuffer * buf1, GstBuffer * buf2)
|
|||
* gst_buffer_is_span_fast() to determine if a memcpy will be needed.
|
||||
*
|
||||
* Returns: the new #GstBuffer that spans the two source buffers.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_buffer_span (GstBuffer * buf1, guint32 offset, GstBuffer * buf2,
|
||||
|
|
|
@ -81,11 +81,12 @@ extern GType _gst_buffer_type;
|
|||
* @GST_BUFFER_ORIGINAL: buffer is not a copy of another buffer.
|
||||
* @GST_BUFFER_DONTFREE: do not try to free the data when this buffer is
|
||||
* unreferenced.
|
||||
* @GST_BUFFER_KEY_UNIT: the buffer holds a key unit, a unit that can be
|
||||
* decoded independently of other buffers.
|
||||
* This flag has been deprecated, see #GST_BUFFER_DELTA_UNIT.
|
||||
* @GST_BUFFER_DONTKEEP:
|
||||
* @GST_BUFFER_PREROLL: The buffer is part of the preroll phase and should not
|
||||
* be displayed.
|
||||
* @GST_BUFFER_DISCONT: The buffer is the first after a discontinuity in the
|
||||
* stream.
|
||||
* @GST_BUFFER_IN_CAPS: the buffer has been added as a field in a #GstCaps.
|
||||
* @GST_BUFFER_GAP: the buffer has been created to fill a gap in the stream.
|
||||
* @GST_BUFFER_DELTA_UNIT: this unit cannot be decoded independently.
|
||||
* Since 0.8.5
|
||||
* @GST_BUFFER_FLAG_LAST: additional flags can be added starting from this flag.
|
||||
|
|
78
gst/gstbus.c
78
gst/gstbus.c
|
@ -142,6 +142,15 @@ gst_bus_get_property (GObject * object, guint prop_id,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bus_post:
|
||||
* @bus: a #GstBus to post on
|
||||
* @message: The #GstMessage to post
|
||||
*
|
||||
* Post a message on the given bus.
|
||||
*
|
||||
* Returns: the new #GstBuffer.
|
||||
*/
|
||||
gboolean
|
||||
gst_bus_post (GstBus * bus, GstMessage * message)
|
||||
{
|
||||
|
@ -151,32 +160,42 @@ gst_bus_post (GstBus * bus, GstMessage * message)
|
|||
g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
|
||||
g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE);
|
||||
|
||||
/* first call the sync handler if it is installed */
|
||||
if (bus->sync_handler) {
|
||||
reply = bus->sync_handler (bus, message, bus->sync_handler_data);
|
||||
}
|
||||
|
||||
/* now see what we should do with the message */
|
||||
switch (reply) {
|
||||
case GST_BUS_DROP:
|
||||
/* drop the message */
|
||||
break;
|
||||
case GST_BUS_PASS:
|
||||
/* pass the message to the async queue */
|
||||
g_async_queue_push (bus->queue, message);
|
||||
c = 'p';
|
||||
write (bus->control_socket[1], &c, 1);
|
||||
break;
|
||||
case GST_BUS_ASYNC:
|
||||
{
|
||||
/* async delivery, we need a mutex and a cond to block
|
||||
* on */
|
||||
GMutex *lock = g_mutex_new ();
|
||||
GCond *cond = g_cond_new ();
|
||||
|
||||
message->cond = cond;
|
||||
message->lock = lock;
|
||||
GST_MESSAGE_COND (message) = cond;
|
||||
GST_MESSAGE_GET_LOCK (message) = lock;
|
||||
|
||||
GST_DEBUG ("waiting for async delivery of message %p", message);
|
||||
|
||||
/* now we lock the message mutex, send the message to the async
|
||||
* 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);
|
||||
c = 'p';
|
||||
write (bus->control_socket[1], &c, 1);
|
||||
/* now block till the message is freed */
|
||||
g_cond_wait (cond, lock);
|
||||
g_mutex_unlock (lock);
|
||||
|
||||
|
@ -191,6 +210,15 @@ gst_bus_post (GstBus * bus, GstMessage * message)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bus_have_pending:
|
||||
* @bus: a #GstBus to check
|
||||
*
|
||||
* Check if there are pending messages on the bus that should be
|
||||
* handled.
|
||||
*
|
||||
* Returns: TRUE if there are messages on the bus to be handled.
|
||||
*/
|
||||
gboolean
|
||||
gst_bus_have_pending (GstBus * bus)
|
||||
{
|
||||
|
@ -203,6 +231,15 @@ gst_bus_have_pending (GstBus * bus)
|
|||
return (length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bus_pop:
|
||||
* @bus: a #GstBus to pop
|
||||
*
|
||||
* Get a message from the bus.
|
||||
*
|
||||
* Returns: The #GstMessage that is on the bus or NULL when there are no
|
||||
* messages available.
|
||||
*/
|
||||
GstMessage *
|
||||
gst_bus_pop (GstBus * bus)
|
||||
{
|
||||
|
@ -217,6 +254,16 @@ gst_bus_pop (GstBus * bus)
|
|||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bus_set_sync_handler:
|
||||
* @bus: a #GstBus to install the handler on
|
||||
* @func: The handler function to install
|
||||
* @data: User data that will be sent to the handler function.
|
||||
*
|
||||
* Install a synchronous handler on the bus. The function will be called
|
||||
* every time a new message is posted on the bus. Note that the function
|
||||
* will be called in the same thread context as the posting object.
|
||||
*/
|
||||
void
|
||||
gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func, gpointer data)
|
||||
{
|
||||
|
@ -226,12 +273,20 @@ gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func, gpointer data)
|
|||
bus->sync_handler_data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bus_create_watch:
|
||||
* @bus: a #GstBus to create the watch for
|
||||
*
|
||||
* Create watch for this bus.
|
||||
*
|
||||
* Returns: A #GSource that can be added to a mainloop.
|
||||
*/
|
||||
GSource *
|
||||
gst_bus_create_watch (GstBus * bus)
|
||||
{
|
||||
GSource *source;
|
||||
|
||||
g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
|
||||
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
|
||||
|
||||
source = g_io_create_watch (bus->io_channel, G_IO_IN);
|
||||
|
||||
|
@ -266,13 +321,20 @@ bus_callback (GIOChannel * channel, GIOCondition cond, GstBusWatch * watch)
|
|||
static void
|
||||
bus_destroy (GstBusWatch * watch)
|
||||
{
|
||||
g_print ("destroy\n");
|
||||
if (watch->notify) {
|
||||
watch->notify (watch->user_data);
|
||||
}
|
||||
g_free (watch);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bus_add_watch_full:
|
||||
* @bus: a #GstBus to create the watch for
|
||||
*
|
||||
* Adds the bus to the mainloop with the given priority.
|
||||
*
|
||||
* Returns: The event source id.
|
||||
*/
|
||||
guint
|
||||
gst_bus_add_watch_full (GstBus * bus, gint priority,
|
||||
GstBusHandler handler, gpointer user_data, GDestroyNotify notify)
|
||||
|
@ -303,6 +365,14 @@ gst_bus_add_watch_full (GstBus * bus, gint priority,
|
|||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bus_add_watch:
|
||||
* @bus: a #GstBus to create the watch for
|
||||
*
|
||||
* Adds the bus to the mainloop with the default priority.
|
||||
*
|
||||
* Returns: The event source id.
|
||||
*/
|
||||
guint
|
||||
gst_bus_add_watch (GstBus * bus, GstBusHandler handler, gpointer user_data)
|
||||
{
|
||||
|
|
49
gst/gstbus.h
49
gst/gstbus.h
|
@ -26,6 +26,7 @@
|
|||
#include <gst/gstmessage.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* --- standard type macros --- */
|
||||
#define GST_TYPE_BUS (gst_bus_get_type ())
|
||||
#define GST_BUS(bus) (G_TYPE_CHECK_INSTANCE_CAST ((bus), GST_TYPE_BUS, GstBus))
|
||||
|
@ -34,30 +35,29 @@ G_BEGIN_DECLS
|
|||
#define GST_IS_BUS_CLASS(bclass) (G_TYPE_CHECK_CLASS_TYPE ((bclass), GST_TYPE_BUS))
|
||||
#define GST_BUS_GET_CLASS(bus) (G_TYPE_INSTANCE_GET_CLASS ((bus), GST_TYPE_BUS, GstBusClass))
|
||||
#define GST_BUS_CAST(bus) ((GstBus*)(bus))
|
||||
typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_BUS_DROP = 0, /* drop message */
|
||||
GST_BUS_PASS = 1, /* pass message to async queue */
|
||||
GST_BUS_ASYNC = 2, /* pass message to async queue, continue if message is handled */
|
||||
} GstBusSyncReply;
|
||||
|
||||
typedef GstBusSyncReply (*GstBusSyncHandler) (GstBus * bus,
|
||||
GstMessage * message, gpointer data);
|
||||
typedef gboolean (*GstBusHandler) (GstBus * bus, GstMessage * message,
|
||||
gpointer data);
|
||||
typedef GstBusSyncReply (*GstBusSyncHandler) (GstBus * bus, GstMessage * message, gpointer data);
|
||||
typedef gboolean (*GstBusHandler) (GstBus * bus, GstMessage * message, gpointer data);
|
||||
|
||||
struct _GstBus
|
||||
{
|
||||
GstObject object;
|
||||
GstObject object;
|
||||
|
||||
/*< private > */
|
||||
GAsyncQueue *queue;
|
||||
GAsyncQueue *queue;
|
||||
|
||||
GstBusSyncHandler sync_handler;
|
||||
gpointer sync_handler_data;
|
||||
gpointer sync_handler_data;
|
||||
|
||||
gint control_socket[2];
|
||||
GIOChannel *io_channel;
|
||||
gint control_socket[2];
|
||||
GIOChannel *io_channel;
|
||||
|
||||
/*< private > */
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
|
@ -71,23 +71,26 @@ struct _GstBusClass
|
|||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
GType gst_bus_get_type (void);
|
||||
GType gst_bus_get_type (void);
|
||||
|
||||
gboolean gst_bus_post (GstBus * bus, GstMessage * message);
|
||||
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_pop (GstBus * bus);
|
||||
gboolean gst_bus_have_pending (GstBus * bus);
|
||||
const GstMessage * gst_bus_peek (GstBus * bus);
|
||||
GstMessage * gst_bus_pop (GstBus * bus);
|
||||
|
||||
void gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func,
|
||||
gpointer data);
|
||||
void gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func,
|
||||
gpointer data);
|
||||
|
||||
GSource *gst_bus_create_watch (GstBus * bus);
|
||||
guint gst_bus_add_watch_full (GstBus * bus,
|
||||
gint priority,
|
||||
GstBusHandler handler, gpointer user_data, GDestroyNotify notify);
|
||||
guint gst_bus_add_watch (GstBus * bus,
|
||||
GstBusHandler handler, gpointer user_data);
|
||||
GSource * gst_bus_create_watch (GstBus * bus);
|
||||
guint gst_bus_add_watch_full (GstBus * bus,
|
||||
gint priority,
|
||||
GstBusHandler handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
guint gst_bus_add_watch (GstBus * bus,
|
||||
GstBusHandler handler,
|
||||
gpointer user_data);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GST_BUS_H__ */
|
||||
|
|
294
gst/gstclock.c
294
gst/gstclock.c
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2004 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstclock.c: Clock subsystem for maintaining time sync
|
||||
*
|
||||
|
@ -47,9 +48,6 @@ enum
|
|||
|
||||
static GstMemChunk *_gst_clock_entries_chunk;
|
||||
|
||||
void gst_clock_id_unlock (GstClockID id);
|
||||
|
||||
|
||||
static void gst_clock_class_init (GstClockClass * klass);
|
||||
static void gst_clock_init (GstClock * clock);
|
||||
static void gst_clock_dispose (GObject * object);
|
||||
|
@ -75,25 +73,86 @@ gst_clock_entry_new (GstClock * clock, GstClockTime time,
|
|||
#ifndef GST_DISABLE_TRACE
|
||||
gst_alloc_trace_new (_gst_clock_entry_trace, entry);
|
||||
#endif
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "created entry %p", entry);
|
||||
|
||||
gst_atomic_int_init (&entry->refcount, 1);
|
||||
entry->clock = clock;
|
||||
entry->time = time;
|
||||
entry->interval = interval;
|
||||
entry->type = type;
|
||||
entry->status = GST_CLOCK_ENTRY_OK;
|
||||
entry->status = GST_CLOCK_BUSY;
|
||||
|
||||
return (GstClockID) entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clock_id_ref:
|
||||
* @id: The clockid to ref
|
||||
*
|
||||
* Increase the refcount of the given clockid.
|
||||
*
|
||||
* Returns: The same #GstClockID with increased refcount.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstClockID
|
||||
gst_clock_id_ref (GstClockID id)
|
||||
{
|
||||
g_return_val_if_fail (id != NULL, NULL);
|
||||
|
||||
gst_atomic_int_inc (&((GstClockEntry *) id)->refcount);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
_gst_clock_id_free (GstClockID id)
|
||||
{
|
||||
g_return_if_fail (id != NULL);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "freed entry %p", id);
|
||||
|
||||
#ifndef GST_DISABLE_TRACE
|
||||
gst_alloc_trace_free (_gst_clock_entry_trace, id);
|
||||
#endif
|
||||
gst_mem_chunk_free (_gst_clock_entries_chunk, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clock_id_unref:
|
||||
* @id: The clockid to unref
|
||||
*
|
||||
* Unref the given clockid. When the refcount reaches 0 the
|
||||
* #GstClockID will be freed.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_clock_id_unref (GstClockID id)
|
||||
{
|
||||
gint zero;
|
||||
|
||||
g_return_if_fail (id != NULL);
|
||||
|
||||
zero = gst_atomic_int_dec_and_test (&((GstClockEntry *) id)->refcount);
|
||||
/* if we ended up with the refcount at zero, free the id */
|
||||
if (zero) {
|
||||
_gst_clock_id_free (id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clock_new_single_shot_id
|
||||
* @clock: The clockid to get a single shot notification from
|
||||
* @time: the requested time
|
||||
*
|
||||
* Get an ID from the given clock to trigger a single shot
|
||||
* notification at the requested time.
|
||||
* notification at the requested time. The single shot id should be
|
||||
* unreffed after usage.
|
||||
*
|
||||
* Returns: An id that can be used to request the time notification.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstClockID
|
||||
gst_clock_new_single_shot_id (GstClock * clock, GstClockTime time)
|
||||
|
@ -112,9 +171,12 @@ gst_clock_new_single_shot_id (GstClock * clock, GstClockTime time)
|
|||
*
|
||||
* Get an ID from the given clock to trigger a periodic notification.
|
||||
* The periodeic notifications will be start at time start_time and
|
||||
* will then be fired with the given interval.
|
||||
* will then be fired with the given interval. The id should be unreffed
|
||||
* after usage.
|
||||
*
|
||||
* Returns: An id that can be used to request the time notification.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstClockID
|
||||
gst_clock_new_periodic_id (GstClock * clock, GstClockTime start_time,
|
||||
|
@ -128,13 +190,38 @@ gst_clock_new_periodic_id (GstClock * clock, GstClockTime start_time,
|
|||
start_time, interval, GST_CLOCK_ENTRY_PERIODIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clock_id_compare_func
|
||||
* @id1: A clockid
|
||||
* @id2: A clockid to compare with
|
||||
*
|
||||
* Compares the two GstClockID instances. This function can be used
|
||||
* as a GCompareFunc when sorting ids.
|
||||
*
|
||||
* Returns: negative value if a < b; zero if a = b; positive value if a > b
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gint
|
||||
gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2)
|
||||
{
|
||||
GstClockEntry *entry1, *entry2;
|
||||
|
||||
entry1 = (GstClockEntry *) id1;
|
||||
entry2 = (GstClockEntry *) id2;
|
||||
|
||||
return GST_CLOCK_ENTRY_TIME (entry1) - GST_CLOCK_ENTRY_TIME (entry2);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clock_id_get_time
|
||||
* @id: The clockid to query
|
||||
*
|
||||
* Get the time of the clock ID
|
||||
*
|
||||
* Returns: the time of the given clock id
|
||||
* Returns: the time of the given clock id.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstClockTime
|
||||
gst_clock_id_get_time (GstClockID id)
|
||||
|
@ -151,16 +238,18 @@ gst_clock_id_get_time (GstClockID id)
|
|||
* @jitter: A pointer that will contain the jitter
|
||||
*
|
||||
* Perform a blocking wait on the given ID. The jitter arg can be
|
||||
* NULL
|
||||
* NULL.
|
||||
*
|
||||
* Returns: the result of the blocking wait.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstClockReturn
|
||||
gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
|
||||
{
|
||||
GstClockEntry *entry;
|
||||
GstClock *clock;
|
||||
GstClockReturn res = GST_CLOCK_UNSUPPORTED;
|
||||
GstClockReturn res;
|
||||
GstClockTime requested;
|
||||
GstClockClass *cclass;
|
||||
|
||||
|
@ -169,43 +258,38 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
|
|||
entry = (GstClockEntry *) id;
|
||||
requested = GST_CLOCK_ENTRY_TIME (entry);
|
||||
|
||||
if (!GST_CLOCK_TIME_IS_VALID (requested)) {
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _TIMEOUT");
|
||||
return GST_CLOCK_TIMEOUT;
|
||||
}
|
||||
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
|
||||
goto invalid_time;
|
||||
|
||||
clock = GST_CLOCK_ENTRY_CLOCK (entry);
|
||||
cclass = GST_CLOCK_GET_CLASS (clock);
|
||||
|
||||
if (cclass->wait) {
|
||||
GstClockTime now;
|
||||
if (G_LIKELY (cclass->wait)) {
|
||||
|
||||
GST_LOCK (clock);
|
||||
clock->entries = g_list_prepend (clock->entries, entry);
|
||||
GST_UNLOCK (clock);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock");
|
||||
do {
|
||||
res = cclass->wait (clock, entry);
|
||||
}
|
||||
while (res == GST_CLOCK_ENTRY_RESTART);
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting");
|
||||
|
||||
GST_LOCK (clock);
|
||||
clock->entries = g_list_remove (clock->entries, entry);
|
||||
GST_UNLOCK (clock);
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock entry %p", id);
|
||||
res = cclass->wait (clock, entry);
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting entry %p", id);
|
||||
|
||||
if (jitter) {
|
||||
now = gst_clock_get_time (clock);
|
||||
GstClockTime now = gst_clock_get_time (clock);
|
||||
|
||||
*jitter = now - requested;
|
||||
}
|
||||
|
||||
if (clock->stats) {
|
||||
gst_clock_update_stats (clock);
|
||||
}
|
||||
} else {
|
||||
res = GST_CLOCK_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
/* ERRORS */
|
||||
invalid_time:
|
||||
{
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
|
||||
return GST_CLOCK_BADTIME;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -215,9 +299,14 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
|
|||
* @user_data: User data passed in the calback
|
||||
*
|
||||
* Register a callback on the given clockid with the given
|
||||
* function and user_data.
|
||||
* function and user_data. When passing an id with an invalid
|
||||
* time to this function, the callback will be called immediatly
|
||||
* with a time set to GST_CLOCK_TIME_NONE. The callback will
|
||||
* be called when the time of the id has been reached.
|
||||
*
|
||||
* Returns: the result of the non blocking wait.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstClockReturn
|
||||
gst_clock_id_wait_async (GstClockID id,
|
||||
|
@ -225,19 +314,19 @@ gst_clock_id_wait_async (GstClockID id,
|
|||
{
|
||||
GstClockEntry *entry;
|
||||
GstClock *clock;
|
||||
GstClockReturn res = GST_CLOCK_UNSUPPORTED;
|
||||
GstClockReturn res;
|
||||
GstClockClass *cclass;
|
||||
GstClockTime requested;
|
||||
|
||||
g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
|
||||
g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
|
||||
|
||||
entry = (GstClockEntry *) id;
|
||||
clock = entry->clock;
|
||||
requested = GST_CLOCK_ENTRY_TIME (entry);
|
||||
clock = GST_CLOCK_ENTRY_CLOCK (entry);
|
||||
|
||||
if (!GST_CLOCK_TIME_IS_VALID (GST_CLOCK_ENTRY_TIME (entry))) {
|
||||
(func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
|
||||
return GST_CLOCK_TIMEOUT;
|
||||
}
|
||||
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
|
||||
goto invalid_time;
|
||||
|
||||
cclass = GST_CLOCK_GET_CLASS (clock);
|
||||
|
||||
|
@ -246,26 +335,28 @@ gst_clock_id_wait_async (GstClockID id,
|
|||
entry->user_data = user_data;
|
||||
|
||||
res = cclass->wait_async (clock, entry);
|
||||
} else {
|
||||
res = GST_CLOCK_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
gst_clock_reschedule_func (GstClockEntry * entry)
|
||||
{
|
||||
entry->status = GST_CLOCK_ENTRY_OK;
|
||||
|
||||
gst_clock_id_unlock ((GstClockID) entry);
|
||||
/* ERRORS */
|
||||
invalid_time:
|
||||
{
|
||||
(func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
|
||||
return GST_CLOCK_BADTIME;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* gst_clock_id_unschedule:
|
||||
* @id: The id to unschedule
|
||||
*
|
||||
* Cancel an outstanding async notification request with the given ID.
|
||||
* Cancel an outstanding request with the given ID. This can either
|
||||
* be an outstanding async notification or a pending sync notification.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_clock_id_unschedule (GstClockID id)
|
||||
|
@ -285,47 +376,6 @@ gst_clock_id_unschedule (GstClockID id)
|
|||
cclass->unschedule (clock, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clock_id_free:
|
||||
* @id: The clockid to free
|
||||
*
|
||||
* Free the resources held by the given id
|
||||
*/
|
||||
void
|
||||
gst_clock_id_free (GstClockID id)
|
||||
{
|
||||
g_return_if_fail (id != NULL);
|
||||
|
||||
#ifndef GST_DISABLE_TRACE
|
||||
gst_alloc_trace_free (_gst_clock_entry_trace, id);
|
||||
#endif
|
||||
gst_mem_chunk_free (_gst_clock_entries_chunk, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clock_id_unlock:
|
||||
* @id: The clockid to unlock
|
||||
*
|
||||
* Unlock the givan ClockID.
|
||||
*/
|
||||
void
|
||||
gst_clock_id_unlock (GstClockID id)
|
||||
{
|
||||
GstClockEntry *entry;
|
||||
GstClock *clock;
|
||||
GstClockClass *cclass;
|
||||
|
||||
g_return_if_fail (id != NULL);
|
||||
|
||||
entry = (GstClockEntry *) id;
|
||||
clock = entry->clock;
|
||||
|
||||
cclass = GST_CLOCK_GET_CLASS (clock);
|
||||
|
||||
if (cclass->unlock)
|
||||
cclass->unlock (clock, entry);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* GstClock abstract base class implementation
|
||||
|
@ -384,15 +434,6 @@ gst_clock_class_init (GstClockClass * klass)
|
|||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATS,
|
||||
g_param_spec_boolean ("stats", "Stats", "Enable clock stats",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_DIFF,
|
||||
g_param_spec_int64 ("max-diff", "Max diff",
|
||||
"The maximum amount of time to wait in nanoseconds", 0, G_MAXINT64,
|
||||
DEFAULT_MAX_DIFF, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENT_DIFF,
|
||||
g_param_spec_uint64 ("event-diff", "event diff",
|
||||
"The amount of time that may elapse until 2 events are treated as happening at different times",
|
||||
0, G_MAXUINT64, DEFAULT_EVENT_DIFF,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -401,6 +442,7 @@ gst_clock_init (GstClock * clock)
|
|||
clock->adjust = 0;
|
||||
clock->last_time = 0;
|
||||
clock->entries = NULL;
|
||||
clock->entries_changed = g_cond_new ();
|
||||
clock->flags = 0;
|
||||
clock->stats = FALSE;
|
||||
}
|
||||
|
@ -408,7 +450,9 @@ gst_clock_init (GstClock * clock)
|
|||
static void
|
||||
gst_clock_dispose (GObject * object)
|
||||
{
|
||||
//GstClock *clock = GST_CLOCK (object);
|
||||
GstClock *clock = GST_CLOCK (object);
|
||||
|
||||
g_cond_free (clock->entries_changed);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
@ -469,27 +513,36 @@ gst_clock_get_resolution (GstClock * clock)
|
|||
* Gets the current time of the given clock. The time is always
|
||||
* monotonically increasing.
|
||||
*
|
||||
* Returns: the time of the clock.
|
||||
* Returns: the time of the clock. Or GST_CLOCK_TIME_NONE when
|
||||
* giving wrong input.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstClockTime
|
||||
gst_clock_get_time (GstClock * clock)
|
||||
{
|
||||
GstClockTime ret = G_GINT64_CONSTANT (0);
|
||||
GstClockTime ret;
|
||||
GstClockClass *cclass;
|
||||
|
||||
g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
|
||||
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
|
||||
|
||||
cclass = GST_CLOCK_GET_CLASS (clock);
|
||||
|
||||
if (cclass->get_internal_time) {
|
||||
ret = cclass->get_internal_time (clock) + clock->adjust;
|
||||
ret = cclass->get_internal_time (clock);
|
||||
} else {
|
||||
ret = G_GINT64_CONSTANT (0);
|
||||
}
|
||||
|
||||
/* make sure the time is increasing, else return last_time */
|
||||
GST_LOCK (clock);
|
||||
ret += clock->adjust;
|
||||
if ((gint64) ret < (gint64) clock->last_time) {
|
||||
ret = clock->last_time;
|
||||
} else {
|
||||
clock->last_time = ret;
|
||||
}
|
||||
GST_UNLOCK (clock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -504,36 +557,17 @@ gst_clock_get_time (GstClock * clock)
|
|||
* moves it backwards. Note that _get_time() always returns
|
||||
* increasing values so when you move the clock backwards, _get_time()
|
||||
* will report the previous value until the clock catches up.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_clock_set_time_adjust (GstClock * clock, GstClockTime adjust)
|
||||
{
|
||||
g_return_if_fail (GST_IS_CLOCK (clock));
|
||||
|
||||
clock->adjust = adjust;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_clock_get_next_id
|
||||
* @clock: The clock to query
|
||||
*
|
||||
* Get the clockid of the next event.
|
||||
*
|
||||
* Returns: a clockid or NULL is no event is pending.
|
||||
*/
|
||||
GstClockID
|
||||
gst_clock_get_next_id (GstClock * clock)
|
||||
{
|
||||
GstClockEntry *entry = NULL;
|
||||
|
||||
g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
|
||||
|
||||
GST_LOCK (clock);
|
||||
if (clock->entries)
|
||||
entry = GST_CLOCK_ENTRY (clock->entries->data);
|
||||
clock->adjust = adjust;
|
||||
GST_UNLOCK (clock);
|
||||
|
||||
return (GstClockID *) entry;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -554,10 +588,6 @@ gst_clock_set_property (GObject * object, guint prop_id,
|
|||
clock->stats = g_value_get_boolean (value);
|
||||
g_object_notify (object, "stats");
|
||||
break;
|
||||
case ARG_MAX_DIFF:
|
||||
break;
|
||||
case ARG_EVENT_DIFF:
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -576,10 +606,6 @@ gst_clock_get_property (GObject * object, guint prop_id,
|
|||
case ARG_STATS:
|
||||
g_value_set_boolean (value, clock->stats);
|
||||
break;
|
||||
case ARG_MAX_DIFF:
|
||||
break;
|
||||
case ARG_EVENT_DIFF:
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -81,15 +81,18 @@ typedef struct _GstClockClass GstClockClass;
|
|||
typedef gboolean (*GstClockCallback) (GstClock *clock, GstClockTime time,
|
||||
GstClockID id, gpointer user_data);
|
||||
|
||||
typedef enum {
|
||||
/*< protected >*/
|
||||
GST_CLOCK_ENTRY_OK,
|
||||
GST_CLOCK_ENTRY_EARLY,
|
||||
GST_CLOCK_ENTRY_RESTART
|
||||
} GstClockEntryStatus;
|
||||
typedef enum
|
||||
{
|
||||
GST_CLOCK_OK = 0,
|
||||
GST_CLOCK_EARLY = 1,
|
||||
GST_CLOCK_UNSCHEDULED = 2,
|
||||
GST_CLOCK_BUSY = 3,
|
||||
GST_CLOCK_BADTIME = 4,
|
||||
GST_CLOCK_ERROR = 5,
|
||||
GST_CLOCK_UNSUPPORTED = 6,
|
||||
} GstClockReturn;
|
||||
|
||||
typedef enum {
|
||||
/*< protected >*/
|
||||
GST_CLOCK_ENTRY_SINGLE,
|
||||
GST_CLOCK_ENTRY_PERIODIC
|
||||
} GstClockEntryType;
|
||||
|
@ -102,26 +105,17 @@ typedef enum {
|
|||
#define GST_CLOCK_ENTRY_STATUS(entry) ((entry)->status)
|
||||
|
||||
struct _GstClockEntry {
|
||||
GstAtomicInt refcount;
|
||||
/*< protected >*/
|
||||
GstClock *clock;
|
||||
GstClockEntryType type;
|
||||
GstClockTime time;
|
||||
GstClockTime interval;
|
||||
GstClockEntryStatus status;
|
||||
GstClockReturn status;
|
||||
GstClockCallback func;
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_CLOCK_UNSCHEDULED = 0,
|
||||
GST_CLOCK_TIMEOUT = 1,
|
||||
GST_CLOCK_EARLY = 2,
|
||||
GST_CLOCK_ERROR = 3,
|
||||
GST_CLOCK_UNSUPPORTED = 4,
|
||||
GST_CLOCK_OK = 5
|
||||
} GstClockReturn;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC = (1 << 1),
|
||||
|
@ -129,11 +123,15 @@ typedef enum
|
|||
GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC = (1 << 3),
|
||||
GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC = (1 << 4),
|
||||
GST_CLOCK_FLAG_CAN_SET_RESOLUTION = (1 << 5),
|
||||
GST_CLOCK_FLAG_CAN_SET_SPEED = (1 << 6)
|
||||
} GstClockFlags;
|
||||
|
||||
#define GST_CLOCK_FLAGS(clock) (GST_CLOCK(clock)->flags)
|
||||
|
||||
#define GST_CLOCK_COND(clock) (GST_CLOCK_CAST(clock)->entries_changed)
|
||||
#define GST_CLOCK_WAIT(clock) g_cond_wait(GST_CLOCK_COND(clock),GST_GET_LOCK(clock))
|
||||
#define GST_CLOCK_TIMED_WAIT(clock,tv) g_cond_timed_wait(GST_CLOCK_COND(clock),GST_GET_LOCK(clock),tv)
|
||||
#define GST_CLOCK_SIGNAL(clock) g_cond_broadcast(GST_CLOCK_COND(clock))
|
||||
|
||||
struct _GstClock {
|
||||
GstObject object;
|
||||
|
||||
|
@ -144,6 +142,7 @@ struct _GstClock {
|
|||
GstClockTime adjust;
|
||||
GstClockTime last_time;
|
||||
GList *entries;
|
||||
GCond *entries_changed;
|
||||
|
||||
/*< private >*/
|
||||
guint64 resolution;
|
||||
|
@ -164,10 +163,9 @@ struct _GstClockClass {
|
|||
GstClockTime (*get_internal_time) (GstClock *clock);
|
||||
|
||||
/* waiting on an ID */
|
||||
GstClockEntryStatus (*wait) (GstClock *clock, GstClockEntry *entry);
|
||||
GstClockEntryStatus (*wait_async) (GstClock *clock, GstClockEntry *entry);
|
||||
GstClockReturn (*wait) (GstClock *clock, GstClockEntry *entry);
|
||||
GstClockReturn (*wait_async) (GstClock *clock, GstClockEntry *entry);
|
||||
void (*unschedule) (GstClock *clock, GstClockEntry *entry);
|
||||
void (*unlock) (GstClock *clock, GstClockEntry *entry);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
|
@ -188,9 +186,14 @@ GstClockID gst_clock_new_single_shot_id (GstClock *clock,
|
|||
GstClockID gst_clock_new_periodic_id (GstClock *clock,
|
||||
GstClockTime start_time,
|
||||
GstClockTime interval);
|
||||
GstClockID gst_clock_get_next_id (GstClock *clock);
|
||||
|
||||
/* reference counting */
|
||||
GstClockID gst_clock_id_ref (GstClockID id);
|
||||
void gst_clock_id_unref (GstClockID id);
|
||||
|
||||
/* operations on IDs */
|
||||
gint gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2);
|
||||
|
||||
GstClockTime gst_clock_id_get_time (GstClockID id);
|
||||
GstClockReturn gst_clock_id_wait (GstClockID id,
|
||||
GstClockTimeDiff *jitter);
|
||||
|
@ -198,8 +201,6 @@ GstClockReturn gst_clock_id_wait_async (GstClockID id,
|
|||
GstClockCallback func,
|
||||
gpointer user_data);
|
||||
void gst_clock_id_unschedule (GstClockID id);
|
||||
void gst_clock_id_unlock (GstClockID id);
|
||||
void gst_clock_id_free (GstClockID id);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
|
111
gst/gstelement.c
111
gst/gstelement.c
|
@ -435,34 +435,29 @@ gst_element_get_index (GstElement * element)
|
|||
gboolean
|
||||
gst_element_add_pad (GstElement * element, GstPad * pad)
|
||||
{
|
||||
GstElement *old_parent;
|
||||
gchar *pad_name;
|
||||
|
||||
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||
|
||||
/* first check to make sure the pad hasn't already been added to another
|
||||
* element */
|
||||
old_parent = gst_pad_get_parent (pad);
|
||||
if (G_UNLIKELY (old_parent != NULL))
|
||||
goto had_parent;
|
||||
|
||||
GST_LOCK (element);
|
||||
/* locking pad to look at the name */
|
||||
GST_LOCK (pad);
|
||||
/* then check to see if there's already a pad by that name here */
|
||||
pad_name = g_strdup (GST_PAD_NAME (pad));
|
||||
GST_UNLOCK (pad);
|
||||
|
||||
if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads,
|
||||
GST_PAD_NAME (pad))))
|
||||
/* then check to see if there's already a pad by that name here */
|
||||
GST_LOCK (element);
|
||||
if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads, pad_name)))
|
||||
goto name_exists;
|
||||
|
||||
/* try to set the pad's parent */
|
||||
if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT_CAST (pad),
|
||||
GST_OBJECT_CAST (element))))
|
||||
goto had_parent;
|
||||
|
||||
GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'",
|
||||
GST_STR_NULL (GST_PAD_NAME (pad)));
|
||||
|
||||
GST_UNLOCK (pad);
|
||||
|
||||
/* set the pad's parent */
|
||||
gst_object_set_parent (GST_OBJECT_CAST (pad), GST_OBJECT_CAST (element));
|
||||
|
||||
/* add it to the list */
|
||||
switch (gst_pad_get_direction (pad)) {
|
||||
case GST_PAD_SRC:
|
||||
|
@ -474,7 +469,7 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
|
|||
element->numsinkpads++;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
/* can happen for ghost pads */
|
||||
break;
|
||||
}
|
||||
element->pads = g_list_prepend (element->pads, pad);
|
||||
|
@ -494,29 +489,23 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
|
|||
|
||||
return TRUE;
|
||||
|
||||
had_parent:
|
||||
name_exists:
|
||||
{
|
||||
gchar *parent_name = gst_element_get_name (old_parent);
|
||||
|
||||
gst_object_unref (GST_OBJECT (old_parent));
|
||||
GST_LOCK (pad);
|
||||
GST_LOCK (element);
|
||||
g_critical
|
||||
("Padname %s:%s already has parent when trying to add to element %s",
|
||||
parent_name, GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
|
||||
g_critical ("Padname %s is not unique in element %s, not adding",
|
||||
pad_name, GST_ELEMENT_NAME (element));
|
||||
GST_UNLOCK (element);
|
||||
GST_UNLOCK (pad);
|
||||
g_free (parent_name);
|
||||
g_free (pad_name);
|
||||
return FALSE;
|
||||
}
|
||||
had_parent:
|
||||
{
|
||||
g_critical
|
||||
("Pad %s already has parent when trying to add to element %s",
|
||||
pad_name, GST_ELEMENT_NAME (element));
|
||||
GST_UNLOCK (element);
|
||||
g_free (pad_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
name_exists:
|
||||
g_critical ("Padname %s is not unique in element %s, not adding\n",
|
||||
GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
|
||||
|
||||
GST_UNLOCK (pad);
|
||||
GST_UNLOCK (element);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -578,6 +567,8 @@ gst_element_remove_pad (GstElement * element, GstPad * pad)
|
|||
if (G_UNLIKELY (current_parent != element))
|
||||
goto not_our_pad;
|
||||
|
||||
gst_object_unref (GST_OBJECT_CAST (current_parent));
|
||||
|
||||
/* FIXME, is this redundant with pad disposal? */
|
||||
if (GST_IS_REAL_PAD (pad)) {
|
||||
GstPad *peer = gst_pad_get_peer (pad);
|
||||
|
@ -591,6 +582,7 @@ gst_element_remove_pad (GstElement * element, GstPad * pad)
|
|||
gst_pad_unlink (pad, GST_PAD_CAST (peer));
|
||||
else
|
||||
gst_pad_unlink (GST_PAD_CAST (peer), pad);
|
||||
|
||||
gst_object_unref (GST_OBJECT (peer));
|
||||
}
|
||||
} else if (GST_IS_GHOST_PAD (pad)) {
|
||||
|
@ -836,6 +828,8 @@ gst_element_get_pad (GstElement * element, const gchar * name)
|
|||
* Retrieves an iterattor of @element's pads.
|
||||
*
|
||||
* Returns: the #GstIterator of pads.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstIterator *
|
||||
gst_element_iterate_pads (GstElement * element)
|
||||
|
@ -1171,6 +1165,8 @@ gst_element_get_query_types (GstElement * element)
|
|||
* forwards the query to a random usable sinkpad of this element.
|
||||
*
|
||||
* Returns: TRUE if the query could be performed.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gboolean
|
||||
gst_element_query (GstElement * element, GstQueryType type,
|
||||
|
@ -1220,6 +1216,8 @@ gst_element_query (GstElement * element, GstQueryType type,
|
|||
* the query will be forwarded to a random sink pad.
|
||||
*
|
||||
* Returns: An array of #GstFormat elements.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
const GstFormat *
|
||||
gst_element_get_formats (GstElement * element)
|
||||
|
@ -1264,6 +1262,8 @@ gst_element_get_formats (GstElement * element)
|
|||
* the query will be forwarded to a random sink pad.
|
||||
*
|
||||
* Returns: TRUE if the conversion could be performed.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gboolean
|
||||
gst_element_convert (GstElement * element,
|
||||
|
@ -1330,7 +1330,7 @@ gst_element_post_message (GstElement * element, GstMessage * message)
|
|||
GST_LOCK (element);
|
||||
bus = element->bus;
|
||||
|
||||
if (bus == NULL) {
|
||||
if (G_UNLIKELY (bus == NULL)) {
|
||||
GST_DEBUG ("... but I won't because I have no bus");
|
||||
GST_UNLOCK (element);
|
||||
gst_data_unref (GST_DATA (message));
|
||||
|
@ -1499,7 +1499,7 @@ gst_element_set_locked_state (GstElement * element, gboolean locked_state)
|
|||
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||
|
||||
GST_LOCK (element);
|
||||
old = !!GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
|
||||
old = GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
|
||||
|
||||
if (G_UNLIKELY (old == locked_state))
|
||||
goto was_ok;
|
||||
|
@ -1546,6 +1546,7 @@ gst_element_sync_state_with_parent (GstElement * element)
|
|||
gst_element_state_get_name (GST_STATE (element)),
|
||||
GST_ELEMENT_NAME (parent),
|
||||
gst_element_state_get_name (GST_STATE (parent)));
|
||||
|
||||
if (gst_element_set_state (element, GST_STATE (parent)) == GST_STATE_FAILURE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1565,6 +1566,7 @@ gst_element_get_state_func (GstElement * element,
|
|||
GST_STATE_LOCK (element);
|
||||
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)
|
||||
|
@ -1578,7 +1580,7 @@ gst_element_get_state_func (GstElement * element,
|
|||
}
|
||||
}
|
||||
/* if nothing is pending anymore we can return TRUE and
|
||||
* set the values of the current and panding state */
|
||||
* set the values of the current and pending state */
|
||||
if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) {
|
||||
if (state)
|
||||
*state = GST_STATE (element);
|
||||
|
@ -1654,7 +1656,7 @@ gst_element_abort_state (GstElement * element)
|
|||
|
||||
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
|
||||
|
||||
g_cond_broadcast (GST_STATE_GET_COND (element));
|
||||
GST_STATE_BROADCAST (element);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1690,7 +1692,7 @@ gst_element_commit_state (GstElement * element)
|
|||
|
||||
g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
|
||||
0, old_state, pending);
|
||||
g_cond_broadcast (GST_STATE_GET_COND (element));
|
||||
GST_STATE_BROADCAST (element);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1798,7 +1800,13 @@ exit:
|
|||
return return_val;
|
||||
}
|
||||
|
||||
/* is called with STATE_LOCK */
|
||||
/* is called with STATE_LOCK
|
||||
*
|
||||
* This function activates the pads of a given element.
|
||||
*
|
||||
* TODO: activates pads from src to sinks?
|
||||
*
|
||||
* */
|
||||
static gboolean
|
||||
gst_element_pads_activate (GstElement * element, gboolean active)
|
||||
{
|
||||
|
@ -1817,11 +1825,14 @@ restart:
|
|||
gst_object_ref (GST_OBJECT (pad));
|
||||
GST_UNLOCK (element);
|
||||
|
||||
/* we only care about real pads */
|
||||
if (GST_IS_REAL_PAD (pad)) {
|
||||
GstRealPad *peer;
|
||||
gboolean pad_loop;
|
||||
gboolean delay = FALSE;
|
||||
|
||||
/* see if the pad has a loop function and grab
|
||||
* the peer */
|
||||
GST_LOCK (pad);
|
||||
pad_loop = GST_RPAD_LOOPFUNC (pad) != NULL;
|
||||
peer = GST_RPAD_PEER (pad);
|
||||
|
@ -1832,13 +1843,18 @@ restart:
|
|||
if (peer) {
|
||||
gboolean peer_loop;
|
||||
|
||||
/* see if the peer has a loop function */
|
||||
peer_loop = GST_RPAD_LOOPFUNC (peer) != NULL;
|
||||
|
||||
/* sinkpads with a loop function are delayed since they
|
||||
* need the srcpad to be active first */
|
||||
if (GST_PAD_IS_SINK (pad) && pad_loop) {
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||
"delaying pad %s", GST_OBJECT_NAME (pad));
|
||||
delay = TRUE;
|
||||
} else if (GST_PAD_IS_SRC (pad) && peer_loop) {
|
||||
/* If the pad is a source and the peer has a loop function,
|
||||
* we can activate the srcpad and then the loopbased sinkpad */
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||
"%sactivating pad %s", (active ? "" : "(de)"),
|
||||
GST_OBJECT_NAME (pad));
|
||||
|
@ -1846,15 +1862,19 @@ restart:
|
|||
(active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE));
|
||||
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||
"activating delayed pad %s", GST_OBJECT_NAME (peer));
|
||||
"%sactivating delayed pad %s", (active ? "" : "(de)"),
|
||||
GST_OBJECT_NAME (peer));
|
||||
result &= gst_pad_set_active (GST_PAD (peer),
|
||||
(active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE));
|
||||
|
||||
/* set flag here since we don't want the code below to activate
|
||||
* the pad again */
|
||||
delay = TRUE;
|
||||
}
|
||||
gst_object_unref (GST_OBJECT (peer));
|
||||
}
|
||||
|
||||
/* all other conditions are just push based pads */
|
||||
if (!delay) {
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||
"%sactivating pad %s", (active ? "" : "(de)"),
|
||||
|
@ -2307,11 +2327,12 @@ gst_element_get_scheduler (GstElement * element)
|
|||
|
||||
/**
|
||||
* gst_element_create_task:
|
||||
* @element: a #GstElement to get the manager of.
|
||||
* @element: a #GstElement to create the task for.
|
||||
* @func: the taskfunction to run
|
||||
* @data: user data passed to the taskfunction.
|
||||
*
|
||||
* Creates a new GstTask.
|
||||
* Creates a new GstTask. This function uses the current manager of
|
||||
* the element to instantiate a new task.
|
||||
*
|
||||
* Returns: the newly created #GstTask.
|
||||
*
|
||||
|
|
|
@ -161,6 +161,8 @@ G_STMT_START { \
|
|||
#define GST_STATE_WAIT(elem) g_cond_wait (GST_STATE_GET_COND (elem), GST_STATE_GET_LOCK (elem))
|
||||
#define GST_STATE_TIMED_WAIT(elem, timeval) g_cond_timed_wait (GST_STATE_GET_COND (elem), GST_STATE_GET_LOCK (elem),\
|
||||
timeval)
|
||||
#define GST_STATE_SIGNAL(elem) g_cond_signal (GST_STATE_GET_COND (elem));
|
||||
#define GST_STATE_BROADCAST(elem) g_cond_broadcast (GST_STATE_GET_COND (elem));
|
||||
|
||||
typedef struct _GstElementFactory GstElementFactory;
|
||||
typedef struct _GstElementFactoryClass GstElementFactoryClass;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstformat.c: GstFormat registration
|
||||
*
|
||||
|
@ -25,10 +26,11 @@
|
|||
#include "gst_private.h"
|
||||
#include "gstformat.h"
|
||||
|
||||
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
|
||||
static GList *_gst_formats = NULL;
|
||||
static GHashTable *_nick_to_format = NULL;
|
||||
static GHashTable *_format_to_nick = NULL;
|
||||
static gint _n_values = 1; /* we start from 1 because 0 reserved for UNDEFINED */
|
||||
static guint32 _n_values = 1; /* we start from 1 because 0 reserved for UNDEFINED */
|
||||
|
||||
static GstFormatDefinition standard_definitions[] = {
|
||||
{GST_FORMAT_DEFAULT, "default", "Default format for the media type"},
|
||||
|
@ -44,6 +46,7 @@ _gst_format_initialize (void)
|
|||
{
|
||||
GstFormatDefinition *standards = standard_definitions;
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
if (_nick_to_format == NULL) {
|
||||
_nick_to_format = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
_format_to_nick = g_hash_table_new (NULL, NULL);
|
||||
|
@ -58,6 +61,7 @@ _gst_format_initialize (void)
|
|||
standards++;
|
||||
_n_values++;
|
||||
}
|
||||
g_static_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,10 +70,12 @@ _gst_format_initialize (void)
|
|||
* @description: The description of the new format
|
||||
*
|
||||
* Create a new GstFormat based on the nick or return an
|
||||
* allrady registered format with that nick
|
||||
* already registered format with that nick.
|
||||
*
|
||||
* Returns: A new GstFormat or an already registered format
|
||||
* with the same nick.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstFormat
|
||||
gst_format_register (const gchar * nick, const gchar * description)
|
||||
|
@ -89,11 +95,13 @@ gst_format_register (const gchar * nick, const gchar * description)
|
|||
format->nick = g_strdup (nick);
|
||||
format->description = g_strdup (description);
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
g_hash_table_insert (_nick_to_format, format->nick, format);
|
||||
g_hash_table_insert (_format_to_nick, GINT_TO_POINTER (format->value),
|
||||
format);
|
||||
_gst_formats = g_list_append (_gst_formats, format);
|
||||
_n_values++;
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
return format->value;
|
||||
}
|
||||
|
@ -114,7 +122,9 @@ gst_format_get_by_nick (const gchar * nick)
|
|||
|
||||
g_return_val_if_fail (nick != NULL, 0);
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
format = g_hash_table_lookup (_nick_to_format, nick);
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
if (format != NULL)
|
||||
return format->value;
|
||||
|
@ -154,22 +164,38 @@ gst_formats_contains (const GstFormat * formats, GstFormat format)
|
|||
* Get details about the given format.
|
||||
*
|
||||
* Returns: The #GstFormatDefinition for @format or NULL on failure.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
const GstFormatDefinition *
|
||||
gst_format_get_details (GstFormat format)
|
||||
{
|
||||
return g_hash_table_lookup (_format_to_nick, GINT_TO_POINTER (format));
|
||||
const GstFormatDefinition *result;
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
result = g_hash_table_lookup (_format_to_nick, GINT_TO_POINTER (format));
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_format_get_definitions:
|
||||
* gst_format_iterate_definitions:
|
||||
*
|
||||
* Get a list of all the registered formats.
|
||||
* Iterate all the registered formats. The format definition is read
|
||||
* only.
|
||||
*
|
||||
* Returns: A GList of #GstFormatDefinition.
|
||||
* Returns: A GstIterator of #GstFormatDefinition.
|
||||
*/
|
||||
const GList *
|
||||
gst_format_get_definitions (void)
|
||||
GstIterator *
|
||||
gst_format_iterate_definitions (void)
|
||||
{
|
||||
return _gst_formats;
|
||||
GstIterator *result;
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
result = gst_iterator_new_list (g_static_mutex_get_mutex (&mutex),
|
||||
&_n_values, &_gst_formats, NULL, NULL, NULL, NULL);
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include <glib.h>
|
||||
|
||||
#include <gst/gstiterator.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
|
@ -88,8 +90,7 @@ gboolean gst_formats_contains (const GstFormat *formats, GstFormat format);
|
|||
/* query for format details */
|
||||
G_CONST_RETURN GstFormatDefinition*
|
||||
gst_format_get_details (GstFormat format);
|
||||
G_CONST_RETURN GList*
|
||||
gst_format_get_definitions (void);
|
||||
GstIterator* gst_format_iterate_definitions (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstiterator.h: Base class for iterating lists.
|
||||
* gstiterator.h: Base class for iterating datastructures.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -37,6 +37,22 @@ gst_iterator_init (GstIterator * it,
|
|||
it->free = free;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_iterator_new:
|
||||
* @size: the size of the iterator structure
|
||||
* @lock: pointer to a #GMutex.
|
||||
* @master_cookie: pointer to a guint32 to protect the iterated object.
|
||||
* @next: function to get next item
|
||||
* @resync: function to resync the iterator
|
||||
* @free: function to free the iterator
|
||||
*
|
||||
* Create a new iterator. This function is mainly used for objects
|
||||
* implementing the next/resync/free function to iterate a data structure.
|
||||
*
|
||||
* Returns: the new #GstIterator.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstIterator *
|
||||
gst_iterator_new (guint size,
|
||||
GMutex * lock,
|
||||
|
@ -102,6 +118,22 @@ gst_list_iterator_free (GstListIterator * it)
|
|||
g_free (it);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_iterator_new_list:
|
||||
* @lock: pointer to a #GMutex protecting the list.
|
||||
* @master_cookie: pointer to a guint32 to protect the list.
|
||||
* @list: pointer to the list
|
||||
* @owner: object owning the list
|
||||
* @ref: function to ref each item
|
||||
* @unref: function to unref each item
|
||||
* @free: function to free the owner of the list
|
||||
*
|
||||
* Create a new iterator designed for iterating @list.
|
||||
*
|
||||
* Returns: the new #GstIterator for @list.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstIterator *
|
||||
gst_iterator_new_list (GMutex * lock,
|
||||
guint32 * master_cookie,
|
||||
|
@ -130,6 +162,17 @@ gst_iterator_new_list (GMutex * lock,
|
|||
return GST_ITERATOR (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_iterator_next:
|
||||
* @it: The #GstIterator to iterate
|
||||
* @elem: pointer to hold next element
|
||||
*
|
||||
* Get the next item from the iterator.
|
||||
*
|
||||
* Returns: The result of the iteration.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstIteratorResult
|
||||
gst_iterator_next (GstIterator * it, gpointer * elem)
|
||||
{
|
||||
|
@ -138,9 +181,9 @@ gst_iterator_next (GstIterator * it, gpointer * elem)
|
|||
g_return_val_if_fail (it != NULL, GST_ITERATOR_ERROR);
|
||||
g_return_val_if_fail (elem != NULL, GST_ITERATOR_ERROR);
|
||||
|
||||
if (it->lock)
|
||||
if (G_LIKELY (it->lock))
|
||||
g_mutex_lock (it->lock);
|
||||
if (*it->master_cookie != it->cookie) {
|
||||
if (G_UNLIKELY (*it->master_cookie != it->cookie)) {
|
||||
result = GST_ITERATOR_RESYNC;
|
||||
goto done;
|
||||
}
|
||||
|
@ -148,25 +191,42 @@ gst_iterator_next (GstIterator * it, gpointer * elem)
|
|||
result = it->next (it, elem);
|
||||
|
||||
done:
|
||||
if (it->lock)
|
||||
if (G_LIKELY (it->lock))
|
||||
g_mutex_unlock (it->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_iterator_resync:
|
||||
* @it: The #GstIterator to resync
|
||||
*
|
||||
* Resync the iterator. this function is mostly called
|
||||
* after #gst_iterator_next() returned #GST_ITERATOR_RESYNC.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_iterator_resync (GstIterator * it)
|
||||
{
|
||||
g_return_if_fail (it != NULL);
|
||||
|
||||
if (it->lock)
|
||||
if (G_LIKELY (it->lock))
|
||||
g_mutex_lock (it->lock);
|
||||
it->resync (it);
|
||||
it->cookie = *it->master_cookie;
|
||||
if (it->lock)
|
||||
if (G_LIKELY (it->lock))
|
||||
g_mutex_unlock (it->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_iterator_free:
|
||||
* @it: The #GstIterator to free
|
||||
*
|
||||
* Free the iterator.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_iterator_free (GstIterator * it)
|
||||
{
|
||||
|
@ -189,6 +249,9 @@ typedef struct _GstIteratorFilter
|
|||
|
||||
} GstIteratorFilter;
|
||||
|
||||
/* this function can iterate in 3 modes:
|
||||
* filter, foreach and find_custom.
|
||||
*/
|
||||
static GstIteratorResult
|
||||
filter_next (GstIteratorFilter * it, gpointer * elem)
|
||||
{
|
||||
|
@ -197,16 +260,16 @@ filter_next (GstIteratorFilter * it, gpointer * elem)
|
|||
|
||||
*elem = NULL;
|
||||
|
||||
if (it->found)
|
||||
if (G_UNLIKELY (it->found))
|
||||
return GST_ITERATOR_DONE;
|
||||
|
||||
while (!done) {
|
||||
while (G_LIKELY (!done)) {
|
||||
gpointer item;
|
||||
|
||||
result = gst_iterator_next (it->slave, &item);
|
||||
switch (result) {
|
||||
case GST_ITERATOR_OK:
|
||||
if (GST_ITERATOR (it)->lock)
|
||||
if (G_LIKELY (GST_ITERATOR (it)->lock))
|
||||
g_mutex_unlock (GST_ITERATOR (it)->lock);
|
||||
if (it->compare) {
|
||||
if (it->func (item, it->user_data) == 0) {
|
||||
|
@ -218,7 +281,7 @@ filter_next (GstIteratorFilter * it, gpointer * elem)
|
|||
} else {
|
||||
it->func (item, it->user_data);
|
||||
}
|
||||
if (GST_ITERATOR (it)->lock)
|
||||
if (G_LIKELY (GST_ITERATOR (it)->lock))
|
||||
g_mutex_lock (GST_ITERATOR (it)->lock);
|
||||
break;
|
||||
case GST_ITERATOR_RESYNC:
|
||||
|
@ -254,6 +317,23 @@ filter_free (GstIteratorFilter * it)
|
|||
g_free (it);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_iterator_filter:
|
||||
* @it: The #GstIterator to filter
|
||||
* @user_data: user data passed to the compare function
|
||||
* @func: the compare function to select elements
|
||||
*
|
||||
* Create a new iterator from an existing iterator. The new iterator
|
||||
* will only return those elements that match the given compare function.
|
||||
* The GCompareFunc should return 0 for elements that should be included
|
||||
* in the iterator.
|
||||
*
|
||||
* When this iterator is freed, @it will also be freed.
|
||||
*
|
||||
* Returns: a new #GstIterator.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstIterator *
|
||||
gst_iterator_filter (GstIterator * it, gpointer user_data, GCompareFunc func)
|
||||
{
|
||||
|
@ -278,6 +358,17 @@ gst_iterator_filter (GstIterator * it, gpointer user_data, GCompareFunc func)
|
|||
return GST_ITERATOR (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_iterator_foreach:
|
||||
* @it: The #GstIterator to iterate
|
||||
* @function: the function to call for each element.
|
||||
* @user_data: user data passed to the function
|
||||
*
|
||||
* Iterate over all element of @it and call the given function for
|
||||
* each element.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_iterator_foreach (GstIterator * it, GFunc function, gpointer user_data)
|
||||
{
|
||||
|
@ -303,6 +394,20 @@ gst_iterator_foreach (GstIterator * it, GFunc function, gpointer user_data)
|
|||
gst_iterator_free (GST_ITERATOR (&filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_iterator_find_custom:
|
||||
* @it: The #GstIterator to iterate
|
||||
* @user_data: user data passed to the compare function
|
||||
* @func: the compare function to use
|
||||
*
|
||||
* Find the first element in @it that matches the compare function.
|
||||
* The compare function should return 0 when the element is found.
|
||||
*
|
||||
* Returns: The element in the iterator that matches the compare
|
||||
* function or NULL when no element matched.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gpointer
|
||||
gst_iterator_find_custom (GstIterator * it, gpointer user_data,
|
||||
GCompareFunc func)
|
||||
|
|
|
@ -27,10 +27,10 @@
|
|||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
GST_ITERATOR_DONE = 0,
|
||||
GST_ITERATOR_OK = 1,
|
||||
GST_ITERATOR_RESYNC = 2,
|
||||
GST_ITERATOR_ERROR = 3,
|
||||
GST_ITERATOR_DONE = 0, /* no more items in the iterator */
|
||||
GST_ITERATOR_OK = 1, /* item retrieved */
|
||||
GST_ITERATOR_RESYNC = 2, /* datastructures changed while iterating */
|
||||
GST_ITERATOR_ERROR = 3, /* some error happened */
|
||||
} GstIteratorResult;
|
||||
|
||||
typedef struct _GstIterator GstIterator;
|
||||
|
@ -59,6 +59,7 @@ struct _GstIterator {
|
|||
iterator was created */
|
||||
};
|
||||
|
||||
/* creating iterators */
|
||||
GstIterator* gst_iterator_new (guint size,
|
||||
GMutex *lock,
|
||||
guint32 *master_cookie,
|
||||
|
@ -74,10 +75,12 @@ GstIterator* gst_iterator_new_list (GMutex *lock,
|
|||
GstIteratorUnrefFunction unref,
|
||||
GstIteratorDisposeFunction free);
|
||||
|
||||
/* using iterators */
|
||||
GstIteratorResult gst_iterator_next (GstIterator *it, gpointer *result);
|
||||
void gst_iterator_resync (GstIterator *it);
|
||||
void gst_iterator_free (GstIterator *it);
|
||||
|
||||
/* special functions that operate on iterators */
|
||||
void gst_iterator_foreach (GstIterator *it, GFunc function,
|
||||
gpointer user_data);
|
||||
gpointer gst_iterator_find_custom (GstIterator *it, gpointer user_data,
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* <2005> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstmemchunk.c: implementation of lockfree allocation of fixed
|
||||
* size memory chunks.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -28,7 +32,6 @@
|
|||
#include <valgrind/valgrind.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
|
||||
#define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
|
||||
#define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
|
||||
|
@ -105,6 +108,8 @@ populate (GstMemChunk * mem_chunk)
|
|||
* when it is too small (with a small overhead when that happens)
|
||||
*
|
||||
* Returns: a new #GstMemChunk
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstMemChunk *
|
||||
gst_mem_chunk_new (gchar * name, gint atom_size, gulong area_size, gint type)
|
||||
|
@ -152,7 +157,9 @@ free_area (gpointer key, gpointer value, gpointer user_data)
|
|||
* gst_mem_chunk_destroy:
|
||||
* @mem_chunk: the GstMemChunk to destroy
|
||||
*
|
||||
* Free the memory allocated by the memchunk
|
||||
* Free the memory allocated by the memchunk. This function
|
||||
* is not Threadsafe as it does not wait for all outstanding
|
||||
* allocations to be freed.
|
||||
*/
|
||||
void
|
||||
gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
|
||||
|
@ -186,6 +193,8 @@ gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
|
|||
* was created.
|
||||
*
|
||||
* Returns: a pointer to the allocated memory region.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gpointer
|
||||
gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
|
||||
|
@ -197,15 +206,20 @@ gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
|
|||
again:
|
||||
chunk = gst_trash_stack_pop (&mem_chunk->stack);
|
||||
/* chunk is empty, try to refill */
|
||||
if (!chunk) {
|
||||
if (populate (mem_chunk))
|
||||
if (G_UNLIKELY (!chunk)) {
|
||||
if (G_LIKELY (populate (mem_chunk))) {
|
||||
goto again;
|
||||
else
|
||||
} else {
|
||||
/* this happens when we are in cleanup mode and we
|
||||
* allocate all remaining chunks for cleanup */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_VALGRIND
|
||||
VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
|
||||
0, 0);
|
||||
if (G_UNLIKELY (__gst_in_valgrind ())) {
|
||||
VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
|
||||
0, 0);
|
||||
}
|
||||
#endif
|
||||
return GST_MEM_CHUNK_DATA (chunk);
|
||||
}
|
||||
|
@ -219,13 +233,15 @@ again:
|
|||
* was created. The memory will be set to all zeroes.
|
||||
*
|
||||
* Returns: a pointer to the allocated memory region.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gpointer
|
||||
gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
|
||||
{
|
||||
gpointer mem = gst_mem_chunk_alloc (mem_chunk);
|
||||
|
||||
if (mem)
|
||||
if (G_LIKELY (mem))
|
||||
memset (mem, 0, mem_chunk->atom_size);
|
||||
|
||||
return mem;
|
||||
|
@ -237,6 +253,8 @@ gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
|
|||
* @mem: the memory region to hand back to the chunk
|
||||
*
|
||||
* Free the memeory region allocated from the chunk.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
|
||||
|
@ -249,7 +267,9 @@ gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
|
|||
chunk = GST_MEM_CHUNK_LINK (mem);
|
||||
|
||||
#ifdef HAVE_VALGRIND
|
||||
VALGRIND_FREELIKE_BLOCK (mem, 0);
|
||||
if (G_UNLIKELY (__gst_in_valgrind ())) {
|
||||
VALGRIND_FREELIKE_BLOCK (mem, 0);
|
||||
}
|
||||
#endif
|
||||
gst_trash_stack_push (&mem_chunk->stack, chunk);
|
||||
}
|
||||
|
|
|
@ -96,9 +96,9 @@ _gst_message_free (GstMessage * message)
|
|||
gst_object_unref (GST_MESSAGE_SRC (message));
|
||||
}
|
||||
if (message->lock) {
|
||||
g_mutex_lock (message->lock);
|
||||
g_cond_signal (message->cond);
|
||||
g_mutex_unlock (message->lock);
|
||||
GST_MESSAGE_LOCK (message);
|
||||
GST_MESSAGE_SIGNAL (message);
|
||||
GST_MESSAGE_UNLOCK (message);
|
||||
}
|
||||
switch (GST_MESSAGE_TYPE (message)) {
|
||||
case GST_MESSAGE_ERROR:
|
||||
|
@ -137,6 +137,8 @@ gst_message_get_type (void)
|
|||
* Allocate a new message of the given type.
|
||||
*
|
||||
* Returns: A new message.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstMessage *
|
||||
gst_message_new (GstMessageType type, GstObject * src)
|
||||
|
@ -171,6 +173,8 @@ gst_message_new (GstMessageType type, GstObject * src)
|
|||
* Create a new eos message.
|
||||
*
|
||||
* Returns: The new eos message.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstMessage *
|
||||
gst_message_new_eos (GstObject * src)
|
||||
|
@ -188,6 +192,8 @@ gst_message_new_eos (GstObject * src)
|
|||
* Create a new error message.
|
||||
*
|
||||
* Returns: The new error message.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstMessage *
|
||||
gst_message_new_error (GstObject * src, GError * error, gchar * debug)
|
||||
|
@ -207,6 +213,8 @@ gst_message_new_error (GstObject * src, GError * error, gchar * debug)
|
|||
* Create a new warning message.
|
||||
*
|
||||
* Returns: The new warning message.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstMessage *
|
||||
gst_message_new_warning (GstObject * src, GError * error, gchar * debug)
|
||||
|
@ -226,6 +234,8 @@ gst_message_new_warning (GstObject * src, GError * error, gchar * debug)
|
|||
* Create a new tag message.
|
||||
*
|
||||
* Returns: The new tag message.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstMessage *
|
||||
gst_message_new_tag (GstObject * src, GstTagList * tag_list)
|
||||
|
|
|
@ -49,6 +49,13 @@ typedef enum
|
|||
#define GST_MESSAGE(message) ((GstMessage*)(message))
|
||||
#define GST_IS_MESSAGE(message) (GST_DATA_TYPE(message) == GST_TYPE_MESSAGE)
|
||||
|
||||
#define GST_MESSAGE_GET_LOCK(message) (GST_MESSAGE(message)->lock)
|
||||
#define GST_MESSAGE_LOCK(message) g_mutex_lock(GST_MESSAGE_GET_LOCK(message))
|
||||
#define GST_MESSAGE_UNLOCK(message) g_mutex_unlock(GST_MESSAGE_GET_LOCK(message))
|
||||
#define GST_MESSAGE_COND(message) (GST_MESSAGE(message)->cond)
|
||||
#define GST_MESSAGE_WAIT(message) g_cond_wait(GST_MESSAGE_COND(message),GST_MESSAGE_GET_LOCK(message))
|
||||
#define GST_MESSAGE_SIGNAL(message) g_cond_signal(GST_MESSAGE_COND(message))
|
||||
|
||||
#define GST_MESSAGE_TYPE(message) (GST_MESSAGE(message)->type)
|
||||
#define GST_MESSAGE_TIMESTAMP(message) (GST_MESSAGE(message)->timestamp)
|
||||
#define GST_MESSAGE_SRC(message) (GST_MESSAGE(message)->src)
|
||||
|
@ -94,10 +101,10 @@ struct _GstMessage
|
|||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
void _gst_message_initialize (void);
|
||||
void _gst_message_initialize (void);
|
||||
|
||||
GType gst_message_get_type (void);
|
||||
GstMessage *gst_message_new (GstMessageType type, GstObject * src);
|
||||
GType gst_message_get_type (void);
|
||||
GstMessage * gst_message_new (GstMessageType type, GstObject * src);
|
||||
|
||||
/* refcounting */
|
||||
#define gst_message_ref(ev) GST_MESSAGE (gst_data_ref (GST_DATA (ev)))
|
||||
|
@ -106,12 +113,10 @@ GstMessage *gst_message_new (GstMessageType type, GstObject * src);
|
|||
/* copy message */
|
||||
#define gst_message_copy(ev) GST_MESSAGE (gst_data_copy (GST_DATA (ev)))
|
||||
|
||||
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_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);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GST_MESSAGE_H__ */
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstobject.c: Fundamental class used for all of GStreamer
|
||||
*
|
||||
|
@ -33,6 +34,15 @@
|
|||
#define DEBUG_REFCOUNT
|
||||
#define REFCOUNT_HACK
|
||||
|
||||
/* Refcount hack: since glib is not threadsafe, the glib refcounter can be
|
||||
* screwed up and the object can be freed unexpectedly. We use an evil hack
|
||||
* to work around this problem. We set the glib refcount to a high value so
|
||||
* that glib will never unref the object under realistic circumstances. Then
|
||||
* we use our own atomic refcounting to do proper MT safe refcounting.
|
||||
*
|
||||
* A proper fix is of course to make the glib refcounting threadsafe which is
|
||||
* planned.
|
||||
*/
|
||||
#ifdef REFCOUNT_HACK
|
||||
#define PATCH_REFCOUNT(obj) ((GObject*)(obj))->ref_count = 100000;
|
||||
#define PATCH_REFCOUNT1(obj) ((GObject*)(obj))->ref_count = 1;
|
||||
|
@ -196,9 +206,7 @@ gst_object_init (GstObject * object)
|
|||
object->parent = NULL;
|
||||
object->name = NULL;
|
||||
gst_atomic_int_init (&(object)->refcount, 1);
|
||||
#ifdef REFCOUNT_HACK
|
||||
PATCH_REFCOUNT (object);
|
||||
#endif
|
||||
|
||||
object->flags = 0;
|
||||
GST_FLAG_SET (object, GST_OBJECT_FLOATING);
|
||||
|
@ -568,12 +576,13 @@ gst_object_default_deep_notify (GObject * object, GstObject * orig,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
gst_object_set_name_default (GstObject * object)
|
||||
{
|
||||
gint count;
|
||||
gchar *name, *tmp;
|
||||
const gchar *type_name;
|
||||
gboolean result;
|
||||
|
||||
type_name = G_OBJECT_TYPE_NAME (object);
|
||||
|
||||
|
@ -599,8 +608,10 @@ gst_object_set_name_default (GstObject * object)
|
|||
name = g_ascii_strdown (tmp, strlen (tmp));
|
||||
g_free (tmp);
|
||||
|
||||
gst_object_set_name (object, name);
|
||||
result = gst_object_set_name (object, name);
|
||||
g_free (name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -613,32 +624,41 @@ gst_object_set_name_default (GstObject * object)
|
|||
* This function makes a copy of the provided name, so the caller
|
||||
* retains ownership of the name it sent.
|
||||
*
|
||||
* Returns: TRUE if the name could be set.
|
||||
* Returns: TRUE if the name could be set. Objects that have
|
||||
* a parent cannot be renamed.
|
||||
*
|
||||
* MT safe. This function grabs and releases the object's LOCK.
|
||||
*/
|
||||
gboolean
|
||||
gst_object_set_name (GstObject * object, const gchar * name)
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
|
||||
|
||||
GST_LOCK (object);
|
||||
|
||||
/* parented objects cannot be renamed */
|
||||
if (object->parent != NULL) {
|
||||
GST_UNLOCK (object);
|
||||
return FALSE;
|
||||
}
|
||||
if (G_UNLIKELY (object->parent != NULL))
|
||||
goto had_parent;
|
||||
|
||||
if (name != NULL) {
|
||||
g_free (object->name);
|
||||
object->name = g_strdup (name);
|
||||
GST_UNLOCK (object);
|
||||
result = TRUE;
|
||||
} else {
|
||||
GST_UNLOCK (object);
|
||||
gst_object_set_name_default (object);
|
||||
result = gst_object_set_name_default (object);
|
||||
}
|
||||
return result;
|
||||
|
||||
/* error */
|
||||
had_parent:
|
||||
{
|
||||
GST_UNLOCK (object);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -677,7 +697,6 @@ gst_object_get_name (GstObject * object)
|
|||
* This function makes a copy of the provided name prefix, so the caller
|
||||
* retains ownership of the name prefix it sent.
|
||||
*
|
||||
*
|
||||
* MT safe. This function grabs and releases the object's LOCK.
|
||||
*/
|
||||
void
|
||||
|
@ -858,15 +877,18 @@ gst_object_check_uniqueness (GList * list, const gchar * name)
|
|||
|
||||
for (; list; list = g_list_next (list)) {
|
||||
GstObject *child;
|
||||
gboolean eq;
|
||||
|
||||
child = GST_OBJECT (list->data);
|
||||
|
||||
GST_LOCK (child);
|
||||
if (strcmp (GST_OBJECT_NAME (child), name) == 0) {
|
||||
GST_UNLOCK (child);
|
||||
eq = strcmp (GST_OBJECT_NAME (child), name) == 0;
|
||||
GST_UNLOCK (child);
|
||||
|
||||
if (G_UNLIKELY (eq)) {
|
||||
result = FALSE;
|
||||
break;
|
||||
}
|
||||
GST_UNLOCK (child);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
74
gst/gstpad.c
74
gst/gstpad.c
|
@ -47,6 +47,7 @@ GST_DEBUG_CATEGORY_STATIC (debug_dataflow);
|
|||
}G_STMT_END
|
||||
#define GST_CAT_DEFAULT GST_CAT_PADS
|
||||
|
||||
/* realize and pad and grab the lock of the realized pad. */
|
||||
#define GST_PAD_REALIZE_AND_LOCK(pad, realpad, lost_ghostpad) \
|
||||
GST_LOCK (pad); \
|
||||
realpad = GST_PAD_REALIZE (pad); \
|
||||
|
@ -336,6 +337,8 @@ gst_pad_custom_new (GType type, const gchar * name, GstPadDirection direction)
|
|||
* This function makes a copy of the name so you can safely free the name.
|
||||
*
|
||||
* Returns: a new #GstPad, or NULL in case of an error.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstPad *
|
||||
gst_pad_new (const gchar * name, GstPadDirection direction)
|
||||
|
@ -444,6 +447,7 @@ gst_pad_set_active (GstPad * pad, GstActivateMode mode)
|
|||
|
||||
old = GST_PAD_IS_ACTIVE (realpad);
|
||||
|
||||
/* if nothing changed, we can just exit */
|
||||
if (G_UNLIKELY (old == active))
|
||||
goto exit;
|
||||
|
||||
|
@ -544,7 +548,7 @@ lost_ghostpad:
|
|||
* reasons stated above.
|
||||
*
|
||||
* Returns: TRUE if the pad could be blocked. This function can fail
|
||||
* wrong parameters were passed or the pad was already in the
|
||||
* if wrong parameters were passed or the pad was already in the
|
||||
* requested state.
|
||||
*
|
||||
* MT safe.
|
||||
|
@ -707,7 +711,7 @@ gst_pad_set_loop_function (GstPad * pad, GstPadLoopFunction loop)
|
|||
* @chain: the #GstPadChainFunction to set.
|
||||
*
|
||||
* Sets the given chain function for the pad. The chain function is called to
|
||||
* process a #GstData input buffer.
|
||||
* process a #GstBuffer input buffer.
|
||||
*/
|
||||
void
|
||||
gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain)
|
||||
|
@ -1511,7 +1515,9 @@ gst_pad_set_pad_template (GstPad * pad, GstPadTemplate * templ)
|
|||
{
|
||||
/* this function would need checks if it weren't static */
|
||||
|
||||
GST_LOCK (pad);
|
||||
gst_object_replace ((GstObject **) & pad->padtemplate, (GstObject *) templ);
|
||||
GST_UNLOCK (pad);
|
||||
|
||||
if (templ) {
|
||||
gst_object_sink (GST_OBJECT (templ));
|
||||
|
@ -1711,6 +1717,7 @@ not_linked_together:
|
|||
}
|
||||
}
|
||||
|
||||
/* should be called with the pad LOCK held */
|
||||
static GstCaps *
|
||||
gst_real_pad_get_caps_unlocked (GstRealPad * realpad)
|
||||
{
|
||||
|
@ -1784,9 +1791,12 @@ done:
|
|||
filter = GST_RPAD_APPFILTER (realpad);
|
||||
|
||||
if (filter) {
|
||||
GstCaps *temp = result;
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_CAPS,
|
||||
"app filter %p %" GST_PTR_FORMAT, filter, filter);
|
||||
result = gst_caps_intersect (result, filter);
|
||||
result = gst_caps_intersect (temp, filter);
|
||||
gst_caps_unref (temp);
|
||||
GST_CAT_DEBUG (GST_CAT_CAPS,
|
||||
"caps after intersection with app filter %p %" GST_PTR_FORMAT, result,
|
||||
result);
|
||||
|
@ -1802,6 +1812,8 @@ done:
|
|||
*
|
||||
* Returns: the #GstCaps of this pad. This function returns a new caps, so use
|
||||
* gst_caps_unref to get rid of it.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstCaps *
|
||||
gst_pad_get_caps (GstPad * pad)
|
||||
|
@ -1870,9 +1882,13 @@ gst_pad_peer_get_caps (GstPad * pad)
|
|||
if (G_UNLIKELY (GST_RPAD_IS_IN_GETCAPS (peerpad)))
|
||||
goto was_dispatching;
|
||||
|
||||
result = gst_pad_get_caps (GST_PAD_CAST (peerpad));
|
||||
gst_object_ref (GST_OBJECT (peerpad));
|
||||
GST_UNLOCK (realpad);
|
||||
|
||||
result = gst_pad_get_caps (GST_PAD_CAST (peerpad));
|
||||
|
||||
gst_object_unref (GST_OBJECT (peerpad));
|
||||
|
||||
return result;
|
||||
|
||||
lost_ghostpad:
|
||||
|
@ -2727,8 +2743,7 @@ handle_pad_block (GstRealPad * pad)
|
|||
* @pad: a source #GstPad.
|
||||
* @buffer: the #GstBuffer to push.
|
||||
*
|
||||
* Pushes a buffer to the peer of @pad. @pad must be linked. May
|
||||
* only be called by @pad's parent.
|
||||
* Pushes a buffer to the peer of @pad. @pad must be linked.
|
||||
*
|
||||
* Returns: a #GstFlowReturn from the peer pad.
|
||||
*
|
||||
|
@ -2837,8 +2852,7 @@ no_function:
|
|||
* @offset: The start offset of the buffer
|
||||
* @length: The length of the buffer
|
||||
*
|
||||
* Pulls a buffer from the peer pad. May only be called by @pad's
|
||||
* parent.
|
||||
* Pulls a buffer from the peer pad. @pad must be linked.
|
||||
*
|
||||
* Returns: a #GstFlowReturn from the peer pad.
|
||||
*
|
||||
|
@ -2884,16 +2898,19 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
|
|||
|
||||
/* ERROR recovery here */
|
||||
not_connected:
|
||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||
"pulling range, but it was not linked");
|
||||
GST_UNLOCK_RETURN (pad, GST_FLOW_NOT_CONNECTED);
|
||||
|
||||
{
|
||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||
"pulling range, but it was not linked");
|
||||
GST_UNLOCK_RETURN (pad, GST_FLOW_NOT_CONNECTED);
|
||||
}
|
||||
no_function:
|
||||
GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
|
||||
("pullrange on pad %s:%s but the peer pad %s:%s has no getrangefunction",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
||||
gst_object_unref (GST_OBJECT (peer));
|
||||
return GST_FLOW_ERROR;
|
||||
{
|
||||
GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
|
||||
("pullrange on pad %s:%s but the peer pad %s:%s has no getrangefunction",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
||||
gst_object_unref (GST_OBJECT (peer));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
@ -3477,13 +3494,10 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
|
|||
|
||||
/* ERROR handling */
|
||||
not_linked:
|
||||
result = FALSE;
|
||||
goto error;
|
||||
|
||||
error:
|
||||
GST_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
{
|
||||
GST_UNLOCK (pad);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3538,12 +3552,12 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
|
|||
|
||||
/* ERROR handling */
|
||||
no_function:
|
||||
g_warning ("pad %s:%s has no event handler, file a bug.",
|
||||
GST_DEBUG_PAD_NAME (rpad));
|
||||
result = FALSE;
|
||||
gst_event_unref (event);
|
||||
|
||||
return result;
|
||||
{
|
||||
g_warning ("pad %s:%s has no event handler, file a bug.",
|
||||
GST_DEBUG_PAD_NAME (rpad));
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
|
|
|
@ -132,7 +132,7 @@ typedef enum {
|
|||
typedef gboolean (*GstPadActivateFunction) (GstPad *pad, GstActivateMode mode);
|
||||
|
||||
/* data passing */
|
||||
typedef gboolean (*GstPadLoopFunction) (GstPad *pad);
|
||||
typedef void (*GstPadLoopFunction) (GstPad *pad);
|
||||
typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer);
|
||||
typedef GstFlowReturn (*GstPadGetRangeFunction) (GstPad *pad, guint64 offset,
|
||||
guint length, GstBuffer **buffer);
|
||||
|
|
|
@ -209,6 +209,7 @@ is_eos (GstPipeline * pipeline)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* FIXME, make me threadsafe */
|
||||
static GstBusSyncReply
|
||||
pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
||||
GstPipeline * pipeline)
|
||||
|
@ -224,8 +225,10 @@ pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
|||
switch (GST_MESSAGE_TYPE (message)) {
|
||||
case GST_MESSAGE_EOS:
|
||||
if (GST_MESSAGE_SRC (message) != GST_OBJECT (pipeline)) {
|
||||
GST_LOCK (bus);
|
||||
pipeline->eosed =
|
||||
g_list_prepend (pipeline->eosed, GST_MESSAGE_SRC (message));
|
||||
GST_UNLOCK (bus);
|
||||
if (is_eos (pipeline)) {
|
||||
posteos = TRUE;
|
||||
}
|
||||
|
@ -257,6 +260,8 @@ pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
|||
* Create a new pipeline with the given name.
|
||||
*
|
||||
* Returns: newly created GstPipeline
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstElement *
|
||||
gst_pipeline_new (const gchar * name)
|
||||
|
@ -264,6 +269,7 @@ gst_pipeline_new (const gchar * name)
|
|||
return gst_element_factory_make ("pipeline", name);
|
||||
}
|
||||
|
||||
/* MT safe */
|
||||
static GstElementStateReturn
|
||||
gst_pipeline_change_state (GstElement * element)
|
||||
{
|
||||
|
@ -276,14 +282,18 @@ gst_pipeline_change_state (GstElement * element)
|
|||
gst_scheduler_setup (GST_ELEMENT_SCHEDULER (pipeline));
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
gst_element_set_clock (element, gst_element_get_clock (element));
|
||||
{
|
||||
GstClock *clock;
|
||||
|
||||
clock = gst_element_get_clock (element);
|
||||
gst_element_set_clock (element, clock);
|
||||
pipeline->eosed = NULL;
|
||||
break;
|
||||
}
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
if (element->clock) {
|
||||
/* we set time slightly ahead because of context switches */
|
||||
pipeline->start_time =
|
||||
gst_clock_get_time (element->clock) + 10 * GST_MSECOND;
|
||||
pipeline->start_time = gst_clock_get_time (element->clock); // + 10*GST_MSECOND;
|
||||
element->base_time = pipeline->start_time - pipeline->stream_time;
|
||||
}
|
||||
GST_DEBUG ("stream_time=%" G_GUINT64_FORMAT ", start_time=%"
|
||||
|
@ -335,6 +345,8 @@ gst_pipeline_change_state (GstElement * element)
|
|||
* Gets the #GstScheduler of this pipeline.
|
||||
*
|
||||
* Returns: a GstScheduler.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstScheduler *
|
||||
gst_pipeline_get_scheduler (GstPipeline * pipeline)
|
||||
|
@ -349,6 +361,8 @@ gst_pipeline_get_scheduler (GstPipeline * pipeline)
|
|||
* Gets the #GstBus of this pipeline.
|
||||
*
|
||||
* Returns: a GstBus
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstBus *
|
||||
gst_pipeline_get_bus (GstPipeline * pipeline)
|
||||
|
@ -363,12 +377,16 @@ gst_pipeline_get_clock_func (GstElement * element)
|
|||
GstPipeline *pipeline = GST_PIPELINE (element);
|
||||
|
||||
/* if we have a fixed clock, use that one */
|
||||
GST_LOCK (pipeline);
|
||||
if (GST_FLAG_IS_SET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK)) {
|
||||
clock = pipeline->fixed_clock;
|
||||
gst_object_ref (GST_OBJECT (clock));
|
||||
GST_UNLOCK (pipeline);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using fixed clock %p (%s)",
|
||||
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
||||
} else {
|
||||
GST_UNLOCK (pipeline);
|
||||
clock =
|
||||
GST_ELEMENT_CLASS (parent_class)->get_clock (GST_ELEMENT (pipeline));
|
||||
/* no clock, use a system clock */
|
||||
|
@ -413,16 +431,20 @@ gst_pipeline_get_clock (GstPipeline * pipeline)
|
|||
* Force the pipeline to use the given clock. The pipeline will
|
||||
* always use the given clock even if new clock providers are added
|
||||
* to this pipeline.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_pipeline_use_clock (GstPipeline * pipeline, GstClock * clock)
|
||||
{
|
||||
g_return_if_fail (GST_IS_PIPELINE (pipeline));
|
||||
|
||||
GST_LOCK (pipeline);
|
||||
GST_FLAG_SET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK);
|
||||
|
||||
gst_object_replace ((GstObject **) & pipeline->fixed_clock,
|
||||
(GstObject *) clock);
|
||||
GST_LOCK (pipeline);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using fixed clock %p (%s)", clock,
|
||||
(clock ? GST_OBJECT_NAME (clock) : "nil"));
|
||||
|
@ -435,6 +457,8 @@ gst_pipeline_use_clock (GstPipeline * pipeline, GstClock * clock)
|
|||
*
|
||||
* Set the clock for the pipeline. The clock will be distributed
|
||||
* to all the elements managed by the pipeline.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_pipeline_set_clock (GstPipeline * pipeline, GstClock * clock)
|
||||
|
@ -450,6 +474,8 @@ gst_pipeline_set_clock (GstPipeline * pipeline, GstClock * clock)
|
|||
* @pipeline: the pipeline
|
||||
*
|
||||
* Let the pipeline select a clock automatically.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_pipeline_auto_clock (GstPipeline * pipeline)
|
||||
|
@ -459,7 +485,9 @@ gst_pipeline_auto_clock (GstPipeline * pipeline)
|
|||
|
||||
GST_FLAG_UNSET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK);
|
||||
|
||||
GST_LOCK (pipeline);
|
||||
gst_object_replace ((GstObject **) & pipeline->fixed_clock, NULL);
|
||||
GST_UNLOCK (pipeline);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using automatic clock");
|
||||
}
|
||||
|
|
|
@ -48,18 +48,21 @@ typedef enum {
|
|||
struct _GstPipeline {
|
||||
GstBin bin;
|
||||
|
||||
/*< public >*/ /* with LOCK */
|
||||
GstClock *fixed_clock; /* fixed clock if any */
|
||||
GstClockTime start_time;
|
||||
GstClockTime stream_time;
|
||||
|
||||
GList *eosed; /* list of elements that posted EOS */
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
struct _GstPipelineClass {
|
||||
GstBinClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
|
|
|
@ -143,23 +143,6 @@ gst_plugin_feature_type_name_filter (GstPluginFeature * feature,
|
|||
|| !strcmp (data->name, GST_PLUGIN_FEATURE_NAME (feature))));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_plugin_feature_set_rank:
|
||||
* @feature: feature to rank
|
||||
* @rank: rank value - higher number means more priority rank
|
||||
*
|
||||
* Specifies a rank for a plugin feature, so that autoplugging uses
|
||||
* the most appropriate feature.
|
||||
*/
|
||||
void
|
||||
gst_plugin_feature_set_rank (GstPluginFeature * feature, guint rank)
|
||||
{
|
||||
g_return_if_fail (feature != NULL);
|
||||
g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
|
||||
|
||||
feature->rank = rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_plugin_feature_set_name:
|
||||
* @feature: a feature
|
||||
|
@ -167,7 +150,8 @@ gst_plugin_feature_set_rank (GstPluginFeature * feature, guint rank)
|
|||
*
|
||||
* Sets the name of a plugin feature. The name uniquely identifies a feature
|
||||
* within all features of the same type. Renaming a plugin feature is not
|
||||
* allowed.
|
||||
* allowed. A copy is made of the name so you should free the supplied @name
|
||||
* after calling this function.
|
||||
*/
|
||||
void
|
||||
gst_plugin_feature_set_name (GstPluginFeature * feature, const gchar * name)
|
||||
|
@ -182,22 +166,6 @@ gst_plugin_feature_set_name (GstPluginFeature * feature, const gchar * name)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_plugin_feature_get rank:
|
||||
* @feature: a feature
|
||||
*
|
||||
* Gets the rank of a plugin feature.
|
||||
*
|
||||
* Returns: The rank of the feature
|
||||
*/
|
||||
guint
|
||||
gst_plugin_feature_get_rank (GstPluginFeature * feature)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), GST_RANK_NONE);
|
||||
|
||||
return feature->rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_plugin_feature_get_name:
|
||||
* @feature: a feature
|
||||
|
@ -213,3 +181,36 @@ gst_plugin_feature_get_name (GstPluginFeature * feature)
|
|||
|
||||
return feature->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_plugin_feature_set_rank:
|
||||
* @feature: feature to rank
|
||||
* @rank: rank value - higher number means more priority rank
|
||||
*
|
||||
* Specifies a rank for a plugin feature, so that autoplugging uses
|
||||
* the most appropriate feature.
|
||||
*/
|
||||
void
|
||||
gst_plugin_feature_set_rank (GstPluginFeature * feature, guint rank)
|
||||
{
|
||||
g_return_if_fail (feature != NULL);
|
||||
g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
|
||||
|
||||
feature->rank = rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_plugin_feature_get rank:
|
||||
* @feature: a feature
|
||||
*
|
||||
* Gets the rank of a plugin feature.
|
||||
*
|
||||
* Returns: The rank of the feature
|
||||
*/
|
||||
guint
|
||||
gst_plugin_feature_get_rank (GstPluginFeature * feature)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), GST_RANK_NONE);
|
||||
|
||||
return feature->rank;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ struct _GstPluginFeatureClass {
|
|||
|
||||
void (*unload_thyself) (GstPluginFeature *feature);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
|
|
|
@ -30,7 +30,9 @@
|
|||
* @callback: the function to call when the probe is triggered
|
||||
* @user_data: data passed to the callback function
|
||||
*
|
||||
* Create a new probe with the specified parameters
|
||||
* Create a new probe with the specified parameters. The single shot
|
||||
* probe will be fired only once. It is the responsability of the
|
||||
* application to free the single probe after it has been fired.
|
||||
*
|
||||
* Returns: a new #GstProbe.
|
||||
*/
|
||||
|
@ -221,7 +223,8 @@ gst_probe_dispatcher_dispatch (GstProbeDispatcher * disp, GstData ** data)
|
|||
if (probe->single_shot) {
|
||||
disp->probes = g_slist_remove (disp->probes, probe);
|
||||
|
||||
gst_probe_destroy (probe);
|
||||
/* do not free the probe here as it cannot be made threadsafe */
|
||||
//gst_probe_destroy (probe);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstquery.c: GstQueryType registration
|
||||
*
|
||||
|
@ -25,10 +26,11 @@
|
|||
#include "gst_private.h"
|
||||
#include "gstquery.h"
|
||||
|
||||
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
|
||||
static GList *_gst_queries = NULL;
|
||||
static GHashTable *_nick_to_query = NULL;
|
||||
static GHashTable *_query_type_to_nick = NULL;
|
||||
static gint _n_values = 1; /* we start from 1 because 0 reserved for NONE */
|
||||
static guint32 _n_values = 1; /* we start from 1 because 0 reserved for NONE */
|
||||
|
||||
static GstQueryTypeDefinition standard_definitions[] = {
|
||||
{GST_QUERY_TOTAL, "total", "Total length"},
|
||||
|
@ -46,6 +48,7 @@ _gst_query_type_initialize (void)
|
|||
{
|
||||
GstQueryTypeDefinition *standards = standard_definitions;
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
if (_nick_to_query == NULL) {
|
||||
_nick_to_query = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
_query_type_to_nick = g_hash_table_new (NULL, NULL);
|
||||
|
@ -60,6 +63,7 @@ _gst_query_type_initialize (void)
|
|||
standards++;
|
||||
_n_values++;
|
||||
}
|
||||
g_static_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,11 +95,13 @@ gst_query_type_register (const gchar * nick, const gchar * description)
|
|||
query->nick = g_strdup (nick);
|
||||
query->description = g_strdup (description);
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
g_hash_table_insert (_nick_to_query, query->nick, query);
|
||||
g_hash_table_insert (_query_type_to_nick, GINT_TO_POINTER (query->value),
|
||||
query);
|
||||
_gst_queries = g_list_append (_gst_queries, query);
|
||||
_n_values++;
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
return query->value;
|
||||
}
|
||||
|
@ -116,7 +122,9 @@ gst_query_type_get_by_nick (const gchar * nick)
|
|||
|
||||
g_return_val_if_fail (nick != NULL, 0);
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
query = g_hash_table_lookup (_nick_to_query, nick);
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
if (query != NULL)
|
||||
return query->value;
|
||||
|
@ -160,18 +168,32 @@ gst_query_types_contains (const GstQueryType * types, GstQueryType type)
|
|||
const GstQueryTypeDefinition *
|
||||
gst_query_type_get_details (GstQueryType type)
|
||||
{
|
||||
return g_hash_table_lookup (_query_type_to_nick, GINT_TO_POINTER (type));
|
||||
const GstQueryTypeDefinition *result;
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
result = g_hash_table_lookup (_query_type_to_nick, GINT_TO_POINTER (type));
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_query_type_get_definitions:
|
||||
* gst_query_type_iterate_definitions:
|
||||
*
|
||||
* Get a list of all the registered query types.
|
||||
* Get an Iterator of all the registered query types. The querytype
|
||||
* definition is read only.
|
||||
*
|
||||
* Returns: A GList of #GstQueryTypeDefinition.
|
||||
* Returns: A #GstIterator of #GstQueryTypeDefinition.
|
||||
*/
|
||||
const GList *
|
||||
gst_query_type_get_definitions (void)
|
||||
GstIterator *
|
||||
gst_query_type_iterate_definitions (void)
|
||||
{
|
||||
return _gst_queries;
|
||||
GstIterator *result;
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
result = gst_iterator_new_list (g_static_mutex_get_mutex (&mutex),
|
||||
&_n_values, &_gst_queries, NULL, NULL, NULL, NULL);
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstquery.h: GstQuery API declaration
|
||||
*
|
||||
|
@ -26,6 +27,8 @@
|
|||
|
||||
#include <glib.h>
|
||||
|
||||
#include <gst/gstiterator.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
|
@ -87,8 +90,8 @@ gboolean gst_query_types_contains (const GstQueryType *types, GstQ
|
|||
|
||||
/* query for query details */
|
||||
G_CONST_RETURN GstQueryTypeDefinition*
|
||||
gst_query_type_get_details (GstQueryType type);
|
||||
G_CONST_RETURN GList* gst_query_type_get_definitions (void);
|
||||
gst_query_type_get_details (GstQueryType type);
|
||||
GstIterator* gst_query_type_iterate_definitions (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ static void gst_queue_get_property (GObject * object,
|
|||
static GstFlowReturn gst_queue_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static GstBuffer *gst_queue_bufferalloc (GstPad * pad, guint64 offset,
|
||||
guint size, GstCaps * caps);
|
||||
static gboolean gst_queue_loop (GstPad * pad);
|
||||
static void gst_queue_loop (GstPad * pad);
|
||||
|
||||
static gboolean gst_queue_handle_sink_event (GstPad * pad, GstEvent * event);
|
||||
|
||||
|
@ -644,7 +644,7 @@ out_unref:
|
|||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
gst_queue_loop (GstPad * pad)
|
||||
{
|
||||
GstQueue *queue;
|
||||
|
@ -697,6 +697,7 @@ restart:
|
|||
GST_QUEUE_MUTEX_LOCK;
|
||||
} else {
|
||||
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) {
|
||||
gst_task_pause (queue->task);
|
||||
result = FALSE;
|
||||
}
|
||||
GST_QUEUE_MUTEX_UNLOCK;
|
||||
|
@ -711,8 +712,6 @@ restart:
|
|||
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
||||
g_cond_signal (queue->item_del);
|
||||
GST_QUEUE_MUTEX_UNLOCK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
* 2004 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstsystemclock.c: Default clock, uses the system clock
|
||||
*
|
||||
|
@ -20,13 +20,12 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "gst_private.h"
|
||||
#include "gstinfo.h"
|
||||
|
||||
#include "gstsystemclock.h"
|
||||
|
||||
/* the one instance of the systemclock */
|
||||
static GstClock *_the_system_clock = NULL;
|
||||
|
||||
static void gst_system_clock_class_init (GstSystemClockClass * klass);
|
||||
|
@ -35,9 +34,13 @@ static void gst_system_clock_dispose (GObject * object);
|
|||
|
||||
static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
|
||||
static guint64 gst_system_clock_get_resolution (GstClock * clock);
|
||||
static GstClockEntryStatus gst_system_clock_wait (GstClock * clock,
|
||||
static GstClockReturn gst_system_clock_id_wait (GstClock * clock,
|
||||
GstClockEntry * entry);
|
||||
static void gst_system_clock_unlock (GstClock * clock, GstClockEntry * entry);
|
||||
static GstClockReturn gst_system_clock_id_wait_async (GstClock * clock,
|
||||
GstClockEntry * entry);
|
||||
static void gst_system_clock_id_unschedule (GstClock * clock,
|
||||
GstClockEntry * entry);
|
||||
static void gst_system_clock_async_thread (GstClock * clock);
|
||||
|
||||
static GStaticMutex _gst_sysclock_mutex = G_STATIC_MUTEX_INIT;
|
||||
|
||||
|
@ -87,22 +90,43 @@ gst_system_clock_class_init (GstSystemClockClass * klass)
|
|||
|
||||
gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
|
||||
gstclock_class->get_resolution = gst_system_clock_get_resolution;
|
||||
gstclock_class->wait = gst_system_clock_wait;
|
||||
gstclock_class->unlock = gst_system_clock_unlock;
|
||||
gstclock_class->wait = gst_system_clock_id_wait;
|
||||
gstclock_class->wait_async = gst_system_clock_id_wait_async;
|
||||
gstclock_class->unschedule = gst_system_clock_id_unschedule;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_system_clock_init (GstSystemClock * clock)
|
||||
{
|
||||
clock->mutex = g_mutex_new ();
|
||||
clock->cond = g_cond_new ();
|
||||
GError *error = NULL;
|
||||
|
||||
GST_CLOCK_FLAGS (clock) =
|
||||
GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
|
||||
GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
|
||||
GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
|
||||
GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC;
|
||||
|
||||
GST_LOCK (clock);
|
||||
clock->thread = g_thread_create ((GThreadFunc) gst_system_clock_async_thread,
|
||||
clock, TRUE, &error);
|
||||
if (error)
|
||||
goto no_thread;
|
||||
|
||||
/* wait for it to spin up */
|
||||
GST_CLOCK_WAIT (clock);
|
||||
GST_UNLOCK (clock);
|
||||
return;
|
||||
|
||||
no_thread:
|
||||
{
|
||||
g_warning ("could not create async clock thread: %s", error->message);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_system_clock_dispose (GObject * object)
|
||||
{
|
||||
GstClock *clock = (GstClock *) object;
|
||||
GstSystemClock *sysclock = (GstSystemClock *) object;
|
||||
|
||||
/* there are subclasses of GstSystemClock running around... */
|
||||
if (_the_system_clock == clock) {
|
||||
|
@ -111,19 +135,19 @@ gst_system_clock_dispose (GObject * object)
|
|||
/* no parent dispose here, this is bad enough already */
|
||||
} else {
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
|
||||
/* FIXME: Notifying before freeing? */
|
||||
g_cond_free (sysclock->cond);
|
||||
g_mutex_free (sysclock->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_system_clock_obtain
|
||||
*
|
||||
* Get a handle to the default system clock.
|
||||
* Get a handle to the default system clock. The refcount of the
|
||||
* clock will be increased so you need to unref the clock after
|
||||
* usage.
|
||||
*
|
||||
* Returns: the default clock.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstClock *
|
||||
gst_system_clock_obtain (void)
|
||||
|
@ -164,6 +188,95 @@ have_clock:
|
|||
return clock;
|
||||
}
|
||||
|
||||
/* this thread reads the sorted clock entries from the queue.
|
||||
*
|
||||
* It waits on each of them and fires the callback when the timeout occurs.
|
||||
*
|
||||
* When an entry in the queue was canceled, it is simply skipped.
|
||||
*
|
||||
* When waiting for an entry, it can become canceled, in that case we don't
|
||||
* call the callback but move to the next item in the queue.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
static void
|
||||
gst_system_clock_async_thread (GstClock * clock)
|
||||
{
|
||||
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "enter system clock thread");
|
||||
GST_LOCK (clock);
|
||||
/* signal spinup */
|
||||
GST_CLOCK_SIGNAL (clock);
|
||||
/* now enter our infinite loop */
|
||||
while (!sysclock->stopping) {
|
||||
GstClockEntry *entry;
|
||||
GstClockReturn res;
|
||||
|
||||
/* check if something to be done */
|
||||
while (clock->entries == NULL) {
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "nothing to wait for");
|
||||
/* wait for work to do */
|
||||
GST_CLOCK_WAIT (clock);
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "got signal");
|
||||
/* clock was stopping, exit */
|
||||
if (sysclock->stopping)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* pick the next entry */
|
||||
entry = clock->entries->data;
|
||||
/* if it was unscheduled, just move on to the next entry */
|
||||
if (entry->status == GST_CLOCK_UNSCHEDULED) {
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p was unscheduled", entry);
|
||||
goto next_entry;
|
||||
}
|
||||
|
||||
/* now wait for the entry, it's a bit stupid to release the lock
|
||||
* here but we have to since the next function grabs the lock... */
|
||||
GST_UNLOCK (clock);
|
||||
res = gst_system_clock_id_wait (clock, (GstClockID) entry);
|
||||
GST_LOCK (clock);
|
||||
switch (res) {
|
||||
case GST_CLOCK_UNSCHEDULED:
|
||||
/* entry was unscheduled, move to the next */
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unscheduled", entry);
|
||||
goto next_entry;
|
||||
case GST_CLOCK_OK:
|
||||
case GST_CLOCK_EARLY:
|
||||
/* entry timed out normally, fire the callback and move to the next
|
||||
* entry */
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unlocked", entry);
|
||||
if (entry->func) {
|
||||
entry->func (clock, entry->time, (GstClockID) entry,
|
||||
entry->user_data);
|
||||
}
|
||||
goto next_entry;
|
||||
case GST_CLOCK_BUSY:
|
||||
/* somebody unlocked the entry but is was not canceled, This means that
|
||||
* either a new entry was added in front of the queue or some other entry
|
||||
* was canceled. Whatever it is, pick the head entry of the list and
|
||||
* continue waiting. */
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p needs restart", entry);
|
||||
continue;
|
||||
default:
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
||||
"strange result %d waiting for %p, skipping", res, entry);
|
||||
goto next_entry;
|
||||
}
|
||||
next_entry:
|
||||
/* we remove the current entry and unref it */
|
||||
clock->entries = g_list_remove (clock->entries, entry);
|
||||
gst_clock_id_unref ((GstClockID) entry);
|
||||
}
|
||||
exit:
|
||||
/* signal exit */
|
||||
GST_CLOCK_SIGNAL (clock);
|
||||
GST_UNLOCK (clock);
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "exit system clock thread");
|
||||
}
|
||||
|
||||
/* MT safe */
|
||||
static GstClockTime
|
||||
gst_system_clock_get_internal_time (GstClock * clock)
|
||||
{
|
||||
|
@ -180,23 +293,36 @@ gst_system_clock_get_resolution (GstClock * clock)
|
|||
return 1 * GST_USECOND;
|
||||
}
|
||||
|
||||
static GstClockEntryStatus
|
||||
gst_system_clock_wait (GstClock * clock, GstClockEntry * entry)
|
||||
/* synchronously wait on the given GstClockEntry.
|
||||
*
|
||||
* We do this by blocking on the global clock GCond variable with
|
||||
* the requested time as a timeout. This allows us to unblock the
|
||||
* entry by signaling the GCond variable.
|
||||
*
|
||||
* Note that signaling the global GCond unlocks all waiting entries. So
|
||||
* we need to check if an unlocked entry has changed when it unlocks.
|
||||
*
|
||||
* Entries that arrive too late are simply not waited on and a
|
||||
* GST_CLOCK_EARLY result is returned.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
static GstClockReturn
|
||||
gst_system_clock_id_wait (GstClock * clock, GstClockEntry * entry)
|
||||
{
|
||||
GstClockEntryStatus res;
|
||||
GstClockTime current, target;
|
||||
gint64 diff;
|
||||
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
|
||||
|
||||
current = gst_clock_get_time (clock);
|
||||
diff = GST_CLOCK_ENTRY_TIME (entry) - current;
|
||||
|
||||
target = GST_CLOCK_ENTRY_TIME (entry);
|
||||
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "real_target %" GST_TIME_FORMAT
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p real_target %" GST_TIME_FORMAT
|
||||
" target %" GST_TIME_FORMAT
|
||||
" now %" GST_TIME_FORMAT
|
||||
" diff %" G_GINT64_FORMAT,
|
||||
entry,
|
||||
GST_TIME_ARGS (target),
|
||||
GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)),
|
||||
GST_TIME_ARGS (current), diff);
|
||||
|
@ -205,23 +331,77 @@ gst_system_clock_wait (GstClock * clock, GstClockEntry * entry)
|
|||
GTimeVal tv;
|
||||
|
||||
GST_TIME_TO_TIMEVAL (target, tv);
|
||||
g_mutex_lock (sysclock->mutex);
|
||||
g_cond_timed_wait (sysclock->cond, sysclock->mutex, &tv);
|
||||
g_mutex_unlock (sysclock->mutex);
|
||||
|
||||
res = entry->status;
|
||||
GST_LOCK (clock);
|
||||
while (TRUE) {
|
||||
/* now wait on the entry, it either times out or the cond is signaled. */
|
||||
if (!GST_CLOCK_TIMED_WAIT (clock, &tv)) {
|
||||
/* timeout, this is fine, we can report success now */
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked after timeout", entry);
|
||||
entry->status = GST_CLOCK_OK;
|
||||
break;
|
||||
} else {
|
||||
/* the waiting is interrupted because the GCond was signaled. This can
|
||||
* be because this or some other entry was unscheduled. */
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked with signal", entry);
|
||||
/* if the entry is unscheduled, we can stop waiting for it */
|
||||
if (entry->status == GST_CLOCK_UNSCHEDULED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
GST_UNLOCK (clock);
|
||||
} else {
|
||||
res = GST_CLOCK_ENTRY_EARLY;
|
||||
entry->status = GST_CLOCK_EARLY;
|
||||
}
|
||||
return res;
|
||||
return entry->status;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_system_clock_unlock (GstClock * clock, GstClockEntry * entry)
|
||||
/* Add an entry to the list of pending async waits. The entry is inserted
|
||||
* in sorted order. If we inserted the entry at the head of the list, we
|
||||
* need to signal the thread as it might either be waiting on it or waiting
|
||||
* for a new entry.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
static GstClockReturn
|
||||
gst_system_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
|
||||
{
|
||||
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "adding entry %p", entry);
|
||||
|
||||
g_mutex_lock (sysclock->mutex);
|
||||
g_cond_broadcast (sysclock->cond);
|
||||
g_mutex_unlock (sysclock->mutex);
|
||||
GST_LOCK (clock);
|
||||
/* need to take a ref */
|
||||
gst_clock_id_ref ((GstClockID) entry);
|
||||
/* insert the entry in sorted order */
|
||||
clock->entries = g_list_insert_sorted (clock->entries, entry,
|
||||
gst_clock_id_compare_func);
|
||||
|
||||
/* only need to send the signal if the entry was added to the
|
||||
* front, else the thread is just waiting for another entry and
|
||||
* will discard this entry automatically. */
|
||||
if (clock->entries->data == entry) {
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "send signal");
|
||||
GST_CLOCK_SIGNAL (clock);
|
||||
}
|
||||
GST_UNLOCK (clock);
|
||||
|
||||
return GST_CLOCK_OK;
|
||||
}
|
||||
|
||||
/* unschedule an entry. This will set the state of the entry to GST_CLOCK_UNSCHEDULED
|
||||
* and will signal any thread waiting for entries to recheck their entry.
|
||||
* We cannot really decide if the signal is needed or not because the entry
|
||||
* could be waited on in async or sync mode.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
static void
|
||||
gst_system_clock_id_unschedule (GstClock * clock, GstClockEntry * entry)
|
||||
{
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
|
||||
|
||||
GST_LOCK (clock);
|
||||
entry->status = GST_CLOCK_UNSCHEDULED;
|
||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "send signal");
|
||||
GST_CLOCK_SIGNAL (clock);
|
||||
GST_UNLOCK (clock);
|
||||
}
|
||||
|
|
|
@ -42,8 +42,9 @@ typedef struct _GstSystemClockClass GstSystemClockClass;
|
|||
struct _GstSystemClock {
|
||||
GstClock clock;
|
||||
|
||||
GMutex * mutex;
|
||||
GCond * cond;
|
||||
/*< private >*/
|
||||
GThread *thread; /* thread for async notify */
|
||||
gboolean stopping;
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
@ -51,6 +52,7 @@ struct _GstSystemClock {
|
|||
struct _GstSystemClockClass {
|
||||
GstClockClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gsttask.c: Streaming tasks
|
||||
*
|
||||
|
@ -26,7 +26,7 @@
|
|||
#include "gsttask.h"
|
||||
|
||||
static void gst_task_class_init (GstTaskClass * klass);
|
||||
static void gst_task_init (GstTask * sched);
|
||||
static void gst_task_init (GstTask * task);
|
||||
static void gst_task_dispose (GObject * object);
|
||||
|
||||
static GstObjectClass *parent_class = NULL;
|
||||
|
@ -70,8 +70,10 @@ gst_task_class_init (GstTaskClass * klass)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_task_init (GstTask * sched)
|
||||
gst_task_init (GstTask * task)
|
||||
{
|
||||
task->cond = g_cond_new ();
|
||||
task->state = GST_TASK_STOPPED;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -79,19 +81,73 @@ gst_task_dispose (GObject * object)
|
|||
{
|
||||
GstTask *task = GST_TASK (object);
|
||||
|
||||
/* thse lists should all be NULL */
|
||||
GST_DEBUG ("task %p dispose", task);
|
||||
|
||||
g_cond_free (task->cond);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_task_create:
|
||||
* @func: The #GstTaskFunction to use
|
||||
* @data: User data to pass to @func
|
||||
*
|
||||
* Create a new Task that will repeadedly call the provided @func
|
||||
* with @data as a parameter. Typically the task will run in
|
||||
* a new thread.
|
||||
*
|
||||
* Returns: A new #GstTask.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstTask *
|
||||
gst_task_create (GstTaskFunction func, gpointer data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_task_get_state:
|
||||
* @task: The #GstTask to query
|
||||
*
|
||||
* Get the current state of the task.
|
||||
*
|
||||
* Returns: The #GstTaskState of the task
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
GstTaskState
|
||||
gst_task_get_state (GstTask * task)
|
||||
{
|
||||
GstTaskState result;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TASK (task), GST_TASK_STOPPED);
|
||||
|
||||
GST_LOCK (task);
|
||||
result = task->state;
|
||||
GST_UNLOCK (task);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_task_start:
|
||||
* @task: The #GstTask to start
|
||||
*
|
||||
* Starts @task.
|
||||
*
|
||||
* Returns: TRUE if the task could be started.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gboolean
|
||||
gst_task_start (GstTask * task)
|
||||
{
|
||||
GstTaskClass *tclass;
|
||||
gboolean result = FALSE;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TASK (task), result);
|
||||
g_return_val_if_fail (GST_IS_TASK (task), FALSE);
|
||||
|
||||
tclass = GST_TASK_GET_CLASS (task);
|
||||
|
||||
|
@ -101,13 +157,23 @@ gst_task_start (GstTask * task)
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_task_stop:
|
||||
* @task: The #GstTask to stop
|
||||
*
|
||||
* Stops @task.
|
||||
*
|
||||
* Returns: TRUE if the task could be stopped.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gboolean
|
||||
gst_task_stop (GstTask * task)
|
||||
{
|
||||
GstTaskClass *tclass;
|
||||
gboolean result = FALSE;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TASK (task), result);
|
||||
g_return_val_if_fail (GST_IS_TASK (task), FALSE);
|
||||
|
||||
tclass = GST_TASK_GET_CLASS (task);
|
||||
|
||||
|
@ -117,13 +183,23 @@ gst_task_stop (GstTask * task)
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_task_pause:
|
||||
* @task: The #GstTask to pause
|
||||
*
|
||||
* Pauses @task.
|
||||
*
|
||||
* Returns: TRUE if the task could be paused.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gboolean
|
||||
gst_task_pause (GstTask * task)
|
||||
{
|
||||
GstTaskClass *tclass;
|
||||
gboolean result = FALSE;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TASK (task), result);
|
||||
g_return_val_if_fail (GST_IS_TASK (task), FALSE);
|
||||
|
||||
tclass = GST_TASK_GET_CLASS (task);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* <2004> Wim Taymans <wim@fluendo.com>
|
||||
* <2005> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gsttask.h: Streaming tasks
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -25,7 +27,7 @@
|
|||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef gboolean (*GstTaskFunction) (void *data);
|
||||
typedef void (*GstTaskFunction) (void *data);
|
||||
|
||||
/* --- standard type macros --- */
|
||||
#define GST_TYPE_TASK (gst_task_get_type ())
|
||||
|
@ -34,28 +36,56 @@ typedef gboolean (*GstTaskFunction) (void *data);
|
|||
#define GST_TASK_CLASS(tclass) (G_TYPE_CHECK_CLASS_CAST ((tclass), GST_TYPE_TASK, GstTaskClass))
|
||||
#define GST_IS_TASK_CLASS(tclass) (G_TYPE_CHECK_CLASS_TYPE ((tclass), GST_TYPE_TASK))
|
||||
#define GST_TASK_GET_CLASS(task) (G_TYPE_INSTANCE_GET_CLASS ((task), GST_TYPE_TASK, GstTaskClass))
|
||||
#define GST_TASK_CAST(task) ((GstTask*)(task))
|
||||
|
||||
typedef struct _GstTask GstTask;
|
||||
typedef struct _GstTaskClass GstTaskClass;
|
||||
|
||||
typedef enum {
|
||||
GST_TASK_STARTED,
|
||||
GST_TASK_STOPPED,
|
||||
GST_TASK_PAUSED,
|
||||
} GstTaskState;
|
||||
|
||||
#define GST_TASK_STATE(task) (GST_TASK_CAST(task)->state)
|
||||
|
||||
#define GST_TASK_GET_COND(task) (GST_TASK_CAST(task)->cond)
|
||||
#define GST_TASK_WAIT(task) g_cond_wait(GST_TASK_GET_COND (task), GST_GET_LOCK (task))
|
||||
#define GST_TASK_SIGNAL(task) g_cond_signal(GST_TASK_GET_COND (task))
|
||||
#define GST_TASK_BROADCAST(task) g_cond_breadcast(GST_TASK_GET_COND (task))
|
||||
|
||||
struct _GstTask {
|
||||
GstObject object;
|
||||
|
||||
/*< public >*/ /* with LOCK */
|
||||
GstTaskState state;
|
||||
GCond *cond;
|
||||
|
||||
GstTaskFunction func;
|
||||
gpointer data;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
struct _GstTaskClass {
|
||||
GstObjectClass parent_class;
|
||||
|
||||
/*< protected >*/
|
||||
gboolean (*start) (GstTask *task);
|
||||
gboolean (*stop) (GstTask *task);
|
||||
gboolean (*pause) (GstTask *task);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
GType gst_task_get_type (void);
|
||||
|
||||
GstTask* gst_task_create (GstTaskFunction func, gpointer data);
|
||||
|
||||
GstTaskState gst_task_get_state (GstTask *task);
|
||||
|
||||
gboolean gst_task_start (GstTask *task);
|
||||
gboolean gst_task_stop (GstTask *task);
|
||||
gboolean gst_task_pause (GstTask *task);
|
||||
|
|
|
@ -124,6 +124,7 @@ gst_trash_stack_pop (GstTrashStack *stack)
|
|||
}
|
||||
|
||||
#else
|
||||
#warning "using fallback trashstack implementation, performance may suffer"
|
||||
|
||||
/*
|
||||
* generic implementation
|
||||
|
|
|
@ -76,30 +76,14 @@ struct _GstThreadSchedulerClass
|
|||
typedef struct _GstThreadSchedulerTask GstThreadSchedulerTask;
|
||||
typedef struct _GstThreadSchedulerTaskClass GstThreadSchedulerTaskClass;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_STOPPED,
|
||||
STATE_STARTED,
|
||||
STATE_PAUSED
|
||||
} TaskState;
|
||||
|
||||
|
||||
struct _GstThreadSchedulerTask
|
||||
{
|
||||
GstTask task;
|
||||
|
||||
TaskState state;
|
||||
GMutex *lock;
|
||||
GCond *cond;
|
||||
|
||||
GstTaskFunction func;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct _GstThreadSchedulerTaskClass
|
||||
{
|
||||
GstTaskClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
static void gst_thread_scheduler_task_class_init (gpointer g_class,
|
||||
|
@ -148,9 +132,7 @@ gst_thread_scheduler_task_class_init (gpointer klass, gpointer class_data)
|
|||
static void
|
||||
gst_thread_scheduler_task_init (GstThreadSchedulerTask * task)
|
||||
{
|
||||
task->state = STATE_STOPPED;
|
||||
task->lock = g_mutex_new ();
|
||||
task->cond = g_cond_new ();
|
||||
GST_TASK (task)->state = GST_TASK_STOPPED;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -158,17 +140,23 @@ gst_thread_scheduler_task_start (GstTask * task)
|
|||
{
|
||||
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
|
||||
GstThreadScheduler *tsched =
|
||||
GST_THREAD_SCHEDULER (gst_object_get_parent (GST_OBJECT (task)));
|
||||
GST_THREAD_SCHEDULER (GST_OBJECT_PARENT (GST_OBJECT (task)));
|
||||
GstTaskState old;
|
||||
|
||||
g_mutex_lock (ttask->lock);
|
||||
if (ttask->state == STATE_STOPPED) {
|
||||
ttask->state = STATE_STARTED;
|
||||
g_thread_pool_push (tsched->pool, task, NULL);
|
||||
} else {
|
||||
ttask->state = STATE_STARTED;
|
||||
g_cond_signal (ttask->cond);
|
||||
GST_LOCK (ttask);
|
||||
old = GST_TASK_CAST (ttask)->state;
|
||||
GST_TASK_CAST (ttask)->state = GST_TASK_STARTED;
|
||||
switch (old) {
|
||||
case GST_TASK_STOPPED:
|
||||
g_thread_pool_push (tsched->pool, task, NULL);
|
||||
break;
|
||||
case GST_TASK_PAUSED:
|
||||
GST_TASK_SIGNAL (ttask);
|
||||
break;
|
||||
case GST_TASK_STARTED:
|
||||
break;
|
||||
}
|
||||
g_mutex_unlock (ttask->lock);
|
||||
GST_UNLOCK (ttask);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -177,13 +165,22 @@ static gboolean
|
|||
gst_thread_scheduler_task_stop (GstTask * task)
|
||||
{
|
||||
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
|
||||
GstTaskState old;
|
||||
|
||||
g_mutex_lock (ttask->lock);
|
||||
if (ttask->state != STATE_STOPPED) {
|
||||
ttask->state = STATE_STOPPED;
|
||||
g_cond_signal (ttask->cond);
|
||||
GST_LOCK (ttask);
|
||||
old = GST_TASK_CAST (ttask)->state;
|
||||
GST_TASK_CAST (ttask)->state = GST_TASK_STOPPED;
|
||||
switch (old) {
|
||||
case GST_TASK_STOPPED:
|
||||
break;
|
||||
case GST_TASK_PAUSED:
|
||||
GST_TASK_SIGNAL (ttask);
|
||||
break;
|
||||
case GST_TASK_STARTED:
|
||||
break;
|
||||
}
|
||||
g_mutex_unlock (ttask->lock);
|
||||
GST_UNLOCK (ttask);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -191,12 +188,24 @@ static gboolean
|
|||
gst_thread_scheduler_task_pause (GstTask * task)
|
||||
{
|
||||
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
|
||||
GstThreadScheduler *tsched =
|
||||
GST_THREAD_SCHEDULER (GST_OBJECT_PARENT (GST_OBJECT (task)));
|
||||
GstTaskState old;
|
||||
|
||||
g_mutex_lock (ttask->lock);
|
||||
if (ttask->state != STATE_PAUSED) {
|
||||
ttask->state = STATE_PAUSED;
|
||||
GST_LOCK (ttask);
|
||||
old = GST_TASK_CAST (ttask)->state;
|
||||
GST_TASK_CAST (ttask)->state = GST_TASK_PAUSED;
|
||||
switch (old) {
|
||||
case GST_TASK_STOPPED:
|
||||
g_thread_pool_push (tsched->pool, task, NULL);
|
||||
break;
|
||||
case GST_TASK_PAUSED:
|
||||
break;
|
||||
case GST_TASK_STARTED:
|
||||
break;
|
||||
}
|
||||
g_mutex_unlock (ttask->lock);
|
||||
GST_UNLOCK (ttask);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -253,32 +262,35 @@ gst_thread_scheduler_class_init (gpointer klass, gpointer class_data)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_thread_scheduler_func (GstThreadSchedulerTask * task,
|
||||
gst_thread_scheduler_func (GstThreadSchedulerTask * ttask,
|
||||
GstThreadScheduler * sched)
|
||||
{
|
||||
gboolean res;
|
||||
GstTask *task = GST_TASK (ttask);
|
||||
|
||||
gst_object_ref (GST_OBJECT (task));
|
||||
|
||||
GST_DEBUG_OBJECT (sched, "Entering task %p, thread %p", task,
|
||||
g_thread_self ());
|
||||
g_mutex_lock (task->lock);
|
||||
while (G_LIKELY (task->state != STATE_STOPPED)) {
|
||||
if (task->state == STATE_PAUSED) {
|
||||
g_cond_wait (task->cond, task->lock);
|
||||
if (task->state == STATE_STOPPED)
|
||||
break;
|
||||
}
|
||||
g_mutex_unlock (task->lock);
|
||||
|
||||
res = task->func (task->data);
|
||||
|
||||
g_mutex_lock (task->lock);
|
||||
if (G_UNLIKELY (!res)) {
|
||||
task->state = STATE_STOPPED;
|
||||
GST_LOCK (task);
|
||||
while (G_LIKELY (task->state != GST_TASK_STOPPED)) {
|
||||
while (G_UNLIKELY (task->state == GST_TASK_PAUSED)) {
|
||||
GST_TASK_SIGNAL (task);
|
||||
GST_TASK_WAIT (task);
|
||||
if (task->state == GST_TASK_STOPPED)
|
||||
goto done;
|
||||
}
|
||||
GST_UNLOCK (task);
|
||||
|
||||
task->func (task->data);
|
||||
|
||||
GST_LOCK (task);
|
||||
}
|
||||
g_mutex_unlock (task->lock);
|
||||
done:
|
||||
GST_UNLOCK (task);
|
||||
|
||||
GST_DEBUG_OBJECT (sched, "Exit task %p, thread %p", task, g_thread_self ());
|
||||
|
||||
gst_object_unref (GST_OBJECT (task));
|
||||
}
|
||||
|
||||
|
@ -299,12 +311,12 @@ gst_thread_scheduler_create_task (GstScheduler * sched, GstTaskFunction func,
|
|||
GST_THREAD_SCHEDULER_TASK (g_object_new (GST_TYPE_THREAD_SCHEDULER_TASK,
|
||||
NULL));
|
||||
gst_object_set_parent (GST_OBJECT (task), GST_OBJECT (sched));
|
||||
task->func = func;
|
||||
task->data = data;
|
||||
GST_TASK_CAST (task)->func = func;
|
||||
GST_TASK_CAST (task)->data = data;
|
||||
|
||||
GST_DEBUG_OBJECT (sched, "Created task %p", task);
|
||||
|
||||
return GST_TASK (task);
|
||||
return GST_TASK_CAST (task);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -189,7 +189,7 @@ static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
|
|||
|
||||
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
|
||||
|
||||
static gboolean gst_fakesrc_loop (GstPad * pad);
|
||||
static void gst_fakesrc_loop (GstPad * pad);
|
||||
|
||||
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
@ -778,13 +778,12 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
|
|||
return buf;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
gst_fakesrc_loop (GstPad * pad)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
GstBuffer *buf;
|
||||
GstClockTime time;
|
||||
gboolean result = TRUE;
|
||||
|
||||
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
|
@ -799,14 +798,14 @@ gst_fakesrc_loop (GstPad * pad)
|
|||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||
} else {
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
result = FALSE;
|
||||
gst_task_pause (src->task);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (src->rt_num_buffers == 0) {
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
result = FALSE;
|
||||
gst_task_pause (src->task);
|
||||
goto done;
|
||||
} else {
|
||||
if (src->rt_num_buffers > 0)
|
||||
|
@ -816,7 +815,7 @@ gst_fakesrc_loop (GstPad * pad)
|
|||
if (src->eos) {
|
||||
GST_INFO ("fakesrc is setting eos on pad");
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
result = FALSE;
|
||||
gst_task_pause (src->task);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -860,8 +859,6 @@ gst_fakesrc_loop (GstPad * pad)
|
|||
|
||||
done:
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -881,7 +881,7 @@ gst_filesrc_close_file (GstFileSrc * src)
|
|||
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
gst_filesrc_loop (GstElement * element)
|
||||
{
|
||||
GstFileSrc *filesrc;
|
||||
|
@ -892,14 +892,13 @@ gst_filesrc_loop (GstElement * element)
|
|||
|
||||
result = gst_filesrc_get (filesrc->srcpad, &buffer);
|
||||
if (result != GST_FLOW_OK) {
|
||||
return FALSE;
|
||||
gst_task_stop (filesrc->task);
|
||||
return;
|
||||
}
|
||||
result = gst_pad_push (filesrc->srcpad, buffer);
|
||||
if (result != GST_FLOW_OK) {
|
||||
return FALSE;
|
||||
gst_task_stop (filesrc->task);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ static void gst_queue_get_property (GObject * object,
|
|||
static GstFlowReturn gst_queue_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static GstBuffer *gst_queue_bufferalloc (GstPad * pad, guint64 offset,
|
||||
guint size, GstCaps * caps);
|
||||
static gboolean gst_queue_loop (GstPad * pad);
|
||||
static void gst_queue_loop (GstPad * pad);
|
||||
|
||||
static gboolean gst_queue_handle_sink_event (GstPad * pad, GstEvent * event);
|
||||
|
||||
|
@ -644,7 +644,7 @@ out_unref:
|
|||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
gst_queue_loop (GstPad * pad)
|
||||
{
|
||||
GstQueue *queue;
|
||||
|
@ -697,6 +697,7 @@ restart:
|
|||
GST_QUEUE_MUTEX_LOCK;
|
||||
} else {
|
||||
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) {
|
||||
gst_task_pause (queue->task);
|
||||
result = FALSE;
|
||||
}
|
||||
GST_QUEUE_MUTEX_UNLOCK;
|
||||
|
@ -711,8 +712,6 @@ restart:
|
|||
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
||||
g_cond_signal (queue->item_del);
|
||||
GST_QUEUE_MUTEX_UNLOCK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
1
tests/old/testsuite/clock/.gitignore
vendored
1
tests/old/testsuite/clock/.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
clock1
|
||||
clock2
|
||||
clock3
|
||||
signedness
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
include ../Rules
|
||||
|
||||
tests_pass = signedness clock1 clock2
|
||||
tests_pass = signedness clock1 clock2 clock3
|
||||
tests_fail =
|
||||
tests_ignore =
|
||||
|
|
|
@ -43,13 +43,12 @@ main (int argc, char *argv[])
|
|||
gst_bin_add_many (GST_BIN (pipeline), src, id, sink, NULL);
|
||||
gst_element_link_many (src, id, sink, NULL);
|
||||
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
|
||||
g_assert (clock != NULL);
|
||||
gst_clock_debug (clock);
|
||||
gst_clock_debug (clock);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
gst_bin_iterate (GST_BIN (pipeline));
|
||||
gst_clock_debug (clock);
|
||||
gst_clock_debug (clock);
|
||||
gst_clock_debug (clock);
|
||||
|
|
|
@ -7,18 +7,33 @@
|
|||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static GstClock *clock = NULL;
|
||||
|
||||
void
|
||||
gst_clock_debug (GstClock * clock, GstElement * fakesink)
|
||||
{
|
||||
g_print ("Clock info: time %" G_GUINT64_FORMAT " - Element info: time %"
|
||||
G_GUINT64_FORMAT "\n", gst_clock_get_time (clock),
|
||||
gst_element_get_time (fakesink));
|
||||
GstClockTime time;
|
||||
|
||||
time = gst_clock_get_time (clock);
|
||||
|
||||
g_print ("Clock info: time %" G_GUINT64_FORMAT " Element %" GST_TIME_FORMAT
|
||||
"\n", time, GST_TIME_ARGS (time - fakesink->base_time));
|
||||
}
|
||||
|
||||
static void
|
||||
element_wait (GstElement * element, GstClockTime time)
|
||||
{
|
||||
GstClockID id;
|
||||
|
||||
id = gst_clock_new_single_shot_id (clock, time + element->base_time);
|
||||
|
||||
gst_clock_id_wait (id, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GstClock *clock = NULL;
|
||||
GstElement *pipeline, *fakesrc, *fakesink;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
@ -41,10 +56,10 @@ main (int argc, char *argv[])
|
|||
g_usleep (G_USEC_PER_SEC);
|
||||
gst_clock_debug (clock, fakesink);
|
||||
|
||||
gst_element_wait (fakesink, 2 * GST_SECOND);
|
||||
element_wait (fakesink, 2 * GST_SECOND);
|
||||
gst_clock_debug (clock, fakesink);
|
||||
|
||||
gst_element_wait (fakesink, 5 * GST_SECOND);
|
||||
element_wait (fakesink, 5 * GST_SECOND);
|
||||
gst_clock_debug (clock, fakesink);
|
||||
|
||||
g_usleep (G_USEC_PER_SEC);
|
||||
|
|
107
tests/old/testsuite/clock/clock3.c
Normal file
107
tests/old/testsuite/clock/clock3.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* testsuite program to test clock behaviour
|
||||
*
|
||||
* creates a fakesrc ! identity ! fakesink pipeline
|
||||
* registers a callback on fakesrc and one on fakesink
|
||||
* also register a normal GLib timeout which should not be reached
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static GstClock *clock = NULL;
|
||||
|
||||
void
|
||||
gst_clock_debug (GstClock * clock)
|
||||
{
|
||||
GstClockTime time;
|
||||
|
||||
time = gst_clock_get_time (clock);
|
||||
|
||||
g_print ("Clock info: time %" G_GUINT64_FORMAT "\n", time);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ok_callback (GstClock * clock, GstClockTime time,
|
||||
GstClockID id, gpointer user_data)
|
||||
{
|
||||
g_print ("unlocked async id %p\n", id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
error_callback (GstClock * clock, GstClockTime time,
|
||||
GstClockID id, gpointer user_data)
|
||||
{
|
||||
g_print ("unlocked unscheduled async id %p, this is wrong\n", id);
|
||||
g_assert_not_reached ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GstClockID id, id2;
|
||||
GstClockTime base;
|
||||
GstClockReturn result;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
clock = gst_system_clock_obtain ();
|
||||
g_assert (clock != NULL);
|
||||
|
||||
gst_clock_debug (clock);
|
||||
base = gst_clock_get_time (clock);
|
||||
|
||||
id = gst_clock_new_single_shot_id (clock, base + GST_SECOND);
|
||||
g_assert (id);
|
||||
|
||||
g_print ("waiting one second\n");
|
||||
result = gst_clock_id_wait (id, NULL);
|
||||
gst_clock_debug (clock);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
|
||||
g_print ("waiting in the past\n");
|
||||
result = gst_clock_id_wait (id, NULL);
|
||||
gst_clock_debug (clock);
|
||||
g_assert (result == GST_CLOCK_EARLY);
|
||||
gst_clock_id_unref (id);
|
||||
|
||||
id = gst_clock_new_single_shot_id (clock, base + 2 * GST_SECOND);
|
||||
g_print ("waiting one second async id %p\n", id);
|
||||
result = gst_clock_id_wait_async (id, ok_callback, NULL);
|
||||
gst_clock_id_unref (id);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
g_usleep (2 * G_USEC_PER_SEC);
|
||||
|
||||
id = gst_clock_new_single_shot_id (clock, base + 5 * GST_SECOND);
|
||||
g_print ("waiting one second async, with cancel on id %p\n", id);
|
||||
result = gst_clock_id_wait_async (id, error_callback, NULL);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
g_usleep (G_USEC_PER_SEC / 2);
|
||||
g_print ("cancel id %p after 0.5 seconds\n", id);
|
||||
gst_clock_id_unschedule (id);
|
||||
gst_clock_id_unref (id);
|
||||
g_print ("canceled id %p\n", id);
|
||||
|
||||
g_print ("waiting multiple one second async, with cancel\n");
|
||||
id = gst_clock_new_single_shot_id (clock, base + 5 * GST_SECOND);
|
||||
id2 = gst_clock_new_single_shot_id (clock, base + 6 * GST_SECOND);
|
||||
g_print ("waiting id %p\n", id);
|
||||
result = gst_clock_id_wait_async (id, ok_callback, NULL);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
gst_clock_id_unref (id);
|
||||
g_print ("waiting id %p\n", id2);
|
||||
result = gst_clock_id_wait_async (id2, error_callback, NULL);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
g_usleep (G_USEC_PER_SEC / 2);
|
||||
g_print ("cancel id %p after 0.5 seconds\n", id2);
|
||||
gst_clock_id_unschedule (id2);
|
||||
gst_clock_id_unref (id2);
|
||||
g_print ("canceled id %p\n", id2);
|
||||
|
||||
g_usleep (2 * G_USEC_PER_SEC);
|
||||
|
||||
/* success */
|
||||
return 0;
|
||||
}
|
1
testsuite/clock/.gitignore
vendored
1
testsuite/clock/.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
clock1
|
||||
clock2
|
||||
clock3
|
||||
signedness
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
include ../Rules
|
||||
|
||||
tests_pass = signedness clock1 clock2
|
||||
tests_pass = signedness clock1 clock2 clock3
|
||||
tests_fail =
|
||||
tests_ignore =
|
||||
|
|
|
@ -43,13 +43,12 @@ main (int argc, char *argv[])
|
|||
gst_bin_add_many (GST_BIN (pipeline), src, id, sink, NULL);
|
||||
gst_element_link_many (src, id, sink, NULL);
|
||||
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
|
||||
g_assert (clock != NULL);
|
||||
gst_clock_debug (clock);
|
||||
gst_clock_debug (clock);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
gst_bin_iterate (GST_BIN (pipeline));
|
||||
gst_clock_debug (clock);
|
||||
gst_clock_debug (clock);
|
||||
gst_clock_debug (clock);
|
||||
|
|
|
@ -7,18 +7,33 @@
|
|||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static GstClock *clock = NULL;
|
||||
|
||||
void
|
||||
gst_clock_debug (GstClock * clock, GstElement * fakesink)
|
||||
{
|
||||
g_print ("Clock info: time %" G_GUINT64_FORMAT " - Element info: time %"
|
||||
G_GUINT64_FORMAT "\n", gst_clock_get_time (clock),
|
||||
gst_element_get_time (fakesink));
|
||||
GstClockTime time;
|
||||
|
||||
time = gst_clock_get_time (clock);
|
||||
|
||||
g_print ("Clock info: time %" G_GUINT64_FORMAT " Element %" GST_TIME_FORMAT
|
||||
"\n", time, GST_TIME_ARGS (time - fakesink->base_time));
|
||||
}
|
||||
|
||||
static void
|
||||
element_wait (GstElement * element, GstClockTime time)
|
||||
{
|
||||
GstClockID id;
|
||||
|
||||
id = gst_clock_new_single_shot_id (clock, time + element->base_time);
|
||||
|
||||
gst_clock_id_wait (id, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GstClock *clock = NULL;
|
||||
GstElement *pipeline, *fakesrc, *fakesink;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
@ -41,10 +56,10 @@ main (int argc, char *argv[])
|
|||
g_usleep (G_USEC_PER_SEC);
|
||||
gst_clock_debug (clock, fakesink);
|
||||
|
||||
gst_element_wait (fakesink, 2 * GST_SECOND);
|
||||
element_wait (fakesink, 2 * GST_SECOND);
|
||||
gst_clock_debug (clock, fakesink);
|
||||
|
||||
gst_element_wait (fakesink, 5 * GST_SECOND);
|
||||
element_wait (fakesink, 5 * GST_SECOND);
|
||||
gst_clock_debug (clock, fakesink);
|
||||
|
||||
g_usleep (G_USEC_PER_SEC);
|
||||
|
|
107
testsuite/clock/clock3.c
Normal file
107
testsuite/clock/clock3.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* testsuite program to test clock behaviour
|
||||
*
|
||||
* creates a fakesrc ! identity ! fakesink pipeline
|
||||
* registers a callback on fakesrc and one on fakesink
|
||||
* also register a normal GLib timeout which should not be reached
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static GstClock *clock = NULL;
|
||||
|
||||
void
|
||||
gst_clock_debug (GstClock * clock)
|
||||
{
|
||||
GstClockTime time;
|
||||
|
||||
time = gst_clock_get_time (clock);
|
||||
|
||||
g_print ("Clock info: time %" G_GUINT64_FORMAT "\n", time);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ok_callback (GstClock * clock, GstClockTime time,
|
||||
GstClockID id, gpointer user_data)
|
||||
{
|
||||
g_print ("unlocked async id %p\n", id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
error_callback (GstClock * clock, GstClockTime time,
|
||||
GstClockID id, gpointer user_data)
|
||||
{
|
||||
g_print ("unlocked unscheduled async id %p, this is wrong\n", id);
|
||||
g_assert_not_reached ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GstClockID id, id2;
|
||||
GstClockTime base;
|
||||
GstClockReturn result;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
clock = gst_system_clock_obtain ();
|
||||
g_assert (clock != NULL);
|
||||
|
||||
gst_clock_debug (clock);
|
||||
base = gst_clock_get_time (clock);
|
||||
|
||||
id = gst_clock_new_single_shot_id (clock, base + GST_SECOND);
|
||||
g_assert (id);
|
||||
|
||||
g_print ("waiting one second\n");
|
||||
result = gst_clock_id_wait (id, NULL);
|
||||
gst_clock_debug (clock);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
|
||||
g_print ("waiting in the past\n");
|
||||
result = gst_clock_id_wait (id, NULL);
|
||||
gst_clock_debug (clock);
|
||||
g_assert (result == GST_CLOCK_EARLY);
|
||||
gst_clock_id_unref (id);
|
||||
|
||||
id = gst_clock_new_single_shot_id (clock, base + 2 * GST_SECOND);
|
||||
g_print ("waiting one second async id %p\n", id);
|
||||
result = gst_clock_id_wait_async (id, ok_callback, NULL);
|
||||
gst_clock_id_unref (id);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
g_usleep (2 * G_USEC_PER_SEC);
|
||||
|
||||
id = gst_clock_new_single_shot_id (clock, base + 5 * GST_SECOND);
|
||||
g_print ("waiting one second async, with cancel on id %p\n", id);
|
||||
result = gst_clock_id_wait_async (id, error_callback, NULL);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
g_usleep (G_USEC_PER_SEC / 2);
|
||||
g_print ("cancel id %p after 0.5 seconds\n", id);
|
||||
gst_clock_id_unschedule (id);
|
||||
gst_clock_id_unref (id);
|
||||
g_print ("canceled id %p\n", id);
|
||||
|
||||
g_print ("waiting multiple one second async, with cancel\n");
|
||||
id = gst_clock_new_single_shot_id (clock, base + 5 * GST_SECOND);
|
||||
id2 = gst_clock_new_single_shot_id (clock, base + 6 * GST_SECOND);
|
||||
g_print ("waiting id %p\n", id);
|
||||
result = gst_clock_id_wait_async (id, ok_callback, NULL);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
gst_clock_id_unref (id);
|
||||
g_print ("waiting id %p\n", id2);
|
||||
result = gst_clock_id_wait_async (id2, error_callback, NULL);
|
||||
g_assert (result == GST_CLOCK_OK);
|
||||
g_usleep (G_USEC_PER_SEC / 2);
|
||||
g_print ("cancel id %p after 0.5 seconds\n", id2);
|
||||
gst_clock_id_unschedule (id2);
|
||||
gst_clock_id_unref (id2);
|
||||
g_print ("canceled id %p\n", id2);
|
||||
|
||||
g_usleep (2 * G_USEC_PER_SEC);
|
||||
|
||||
/* success */
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue