mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 23:18:52 +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>
|
2005-01-04 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* gst/elements/gstfilesrc.c: (gst_filesrc_getrange),
|
* 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 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 };
|
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
@ -778,13 +778,12 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_fakesrc_loop (GstPad * pad)
|
gst_fakesrc_loop (GstPad * pad)
|
||||||
{
|
{
|
||||||
GstFakeSrc *src;
|
GstFakeSrc *src;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
GstClockTime time;
|
GstClockTime time;
|
||||||
gboolean result = TRUE;
|
|
||||||
|
|
||||||
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
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));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||||
} else {
|
} else {
|
||||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
result = FALSE;
|
gst_task_pause (src->task);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->rt_num_buffers == 0) {
|
if (src->rt_num_buffers == 0) {
|
||||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
result = FALSE;
|
gst_task_pause (src->task);
|
||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
if (src->rt_num_buffers > 0)
|
if (src->rt_num_buffers > 0)
|
||||||
|
@ -816,7 +815,7 @@ gst_fakesrc_loop (GstPad * pad)
|
||||||
if (src->eos) {
|
if (src->eos) {
|
||||||
GST_INFO ("fakesrc is setting eos on pad");
|
GST_INFO ("fakesrc is setting eos on pad");
|
||||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
result = FALSE;
|
gst_task_pause (src->task);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,8 +859,6 @@ gst_fakesrc_loop (GstPad * pad)
|
||||||
|
|
||||||
done:
|
done:
|
||||||
GST_STREAM_UNLOCK (pad);
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -881,7 +881,7 @@ gst_filesrc_close_file (GstFileSrc * src)
|
||||||
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_filesrc_loop (GstElement * element)
|
gst_filesrc_loop (GstElement * element)
|
||||||
{
|
{
|
||||||
GstFileSrc *filesrc;
|
GstFileSrc *filesrc;
|
||||||
|
@ -892,14 +892,13 @@ gst_filesrc_loop (GstElement * element)
|
||||||
|
|
||||||
result = gst_filesrc_get (filesrc->srcpad, &buffer);
|
result = gst_filesrc_get (filesrc->srcpad, &buffer);
|
||||||
if (result != GST_FLOW_OK) {
|
if (result != GST_FLOW_OK) {
|
||||||
return FALSE;
|
gst_task_stop (filesrc->task);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
result = gst_pad_push (filesrc->srcpad, buffer);
|
result = gst_pad_push (filesrc->srcpad, buffer);
|
||||||
if (result != GST_FLOW_OK) {
|
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);
|
return gst_element_factory_make ("bin", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the index on all elements in this bin
|
||||||
|
*
|
||||||
|
* MT safe
|
||||||
|
*/
|
||||||
#ifndef GST_DISABLE_INDEX
|
#ifndef GST_DISABLE_INDEX
|
||||||
static void
|
static void
|
||||||
gst_bin_set_index (GstElement * element, GstIndex * index)
|
gst_bin_set_index (GstElement * element, GstIndex * index)
|
||||||
|
@ -217,6 +221,10 @@ gst_bin_set_index (GstElement * element, GstIndex * index)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* set the clock on all elements in this bin
|
||||||
|
*
|
||||||
|
* MT safe
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
gst_bin_set_clock (GstElement * element, GstClock * clock)
|
gst_bin_set_clock (GstElement * element, GstClock * clock)
|
||||||
{
|
{
|
||||||
|
@ -234,6 +242,10 @@ gst_bin_set_clock (GstElement * element, GstClock * clock)
|
||||||
GST_UNLOCK (bin);
|
GST_UNLOCK (bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get the clock for this bin by asking all of the children in this bin
|
||||||
|
*
|
||||||
|
* MT safe
|
||||||
|
*/
|
||||||
static GstClock *
|
static GstClock *
|
||||||
gst_bin_get_clock (GstElement * element)
|
gst_bin_get_clock (GstElement * element)
|
||||||
{
|
{
|
||||||
|
@ -256,6 +268,10 @@ gst_bin_get_clock (GstElement * element)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the bus on all of the children in this bin
|
||||||
|
*
|
||||||
|
* MT safe
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
gst_bin_set_bus (GstElement * element, GstBus * bus)
|
gst_bin_set_bus (GstElement * element, GstBus * bus)
|
||||||
{
|
{
|
||||||
|
@ -275,6 +291,10 @@ gst_bin_set_bus (GstElement * element, GstBus * bus)
|
||||||
GST_UNLOCK (bin);
|
GST_UNLOCK (bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the scheduler on all of the children in this bin
|
||||||
|
*
|
||||||
|
* MT safe
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
gst_bin_set_scheduler (GstElement * element, GstScheduler * sched)
|
gst_bin_set_scheduler (GstElement * element, GstScheduler * sched)
|
||||||
{
|
{
|
||||||
|
@ -294,6 +314,10 @@ gst_bin_set_scheduler (GstElement * element, GstScheduler * sched)
|
||||||
GST_UNLOCK (bin);
|
GST_UNLOCK (bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* add an element to this bin
|
||||||
|
*
|
||||||
|
* MT safe
|
||||||
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_bin_add_func (GstBin * bin, GstElement * element)
|
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)))
|
if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin)))
|
||||||
goto adding_itself;
|
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);
|
GST_LOCK (element);
|
||||||
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
|
@ -399,11 +425,16 @@ no_function:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove an element from the bin
|
||||||
|
*
|
||||||
|
* MT safe
|
||||||
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_bin_remove_func (GstBin * bin, GstElement * element)
|
gst_bin_remove_func (GstBin * bin, GstElement * element)
|
||||||
{
|
{
|
||||||
gchar *elem_name;
|
gchar *elem_name;
|
||||||
|
|
||||||
|
/* grab element name so we can print it */
|
||||||
GST_LOCK (element);
|
GST_LOCK (element);
|
||||||
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
elem_name = g_strdup (GST_ELEMENT_NAME (element));
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
|
@ -424,6 +455,8 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
|
||||||
g_free (elem_name);
|
g_free (elem_name);
|
||||||
|
|
||||||
gst_element_set_manager (element, NULL);
|
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
|
/* we ref here because after the _unparent() the element can be disposed
|
||||||
* and we still need it to fire a signal. */
|
* 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);
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
||||||
|
|
||||||
GST_LOCK (bin);
|
GST_LOCK (bin);
|
||||||
|
/* add ref because the iterator refs the bin */
|
||||||
gst_object_ref (GST_OBJECT (bin));
|
gst_object_ref (GST_OBJECT (bin));
|
||||||
result = gst_iterator_new_list (GST_GET_LOCK (bin),
|
result = gst_iterator_new_list (GST_GET_LOCK (bin),
|
||||||
&bin->children_cookie,
|
&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
|
/* 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
|
static gint
|
||||||
bin_element_is_sink (GstElement * child, GstBin * bin)
|
bin_element_is_sink (GstElement * child, GstBin * bin)
|
||||||
{
|
{
|
||||||
gint ret = 1;
|
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
|
/* check if this is a sink element, these are the elements
|
||||||
* without (linked) source pads. */
|
* without (linked) source pads. */
|
||||||
if (child->numsrcpads == 0) {
|
if (child->numsrcpads == 0) {
|
||||||
/* shortcut */
|
/* shortcut */
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
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;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
/* loop over all pads, try to figure out if this element
|
/* 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;
|
GList *pads;
|
||||||
gboolean connected_src = FALSE;
|
gboolean connected_src = FALSE;
|
||||||
|
|
||||||
/* FIXME not MT safe */
|
pads = child->srcpads;
|
||||||
for (pads = child->srcpads; pads; pads = g_list_next (pads)) {
|
while (pads) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
|
|
||||||
if (GST_PAD_IS_LINKED (pad)) {
|
if (GST_PAD_IS_LINKED (pad)) {
|
||||||
connected_src = TRUE;
|
connected_src = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
pads = g_list_next (pads);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connected_src) {
|
if (connected_src) {
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
||||||
"not adding child %s as sink: linked source pads",
|
"not adding child %s as sink: linked source pads",
|
||||||
gst_element_get_name (child));
|
GST_OBJECT_NAME (child));
|
||||||
} else {
|
} else {
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
||||||
"adding child %s as sink since it has unlinked source pads",
|
"adding child %s as sink since it has unlinked source pads",
|
||||||
gst_element_get_name (child));
|
GST_OBJECT_NAME (child));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (child);
|
||||||
|
|
||||||
/* we did not find the element, need to release the ref
|
/* we did not find the element, need to release the ref
|
||||||
* added by the iterator */
|
* added by the iterator */
|
||||||
if (ret == 1)
|
if (ret == 1)
|
||||||
|
@ -595,52 +640,64 @@ gst_bin_iterate_sinks (GstBin * bin)
|
||||||
return result;
|
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
|
/* 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
|
static gboolean
|
||||||
gst_bin_get_state (GstElement * element, GstElementState * state,
|
gst_bin_get_state (GstElement * element, GstElementState * state,
|
||||||
GstElementState * pending, GTimeVal * timeout)
|
GstElementState * pending, GTimeVal * timeout)
|
||||||
{
|
{
|
||||||
gboolean ret = TRUE;
|
|
||||||
GstBin *bin = GST_BIN (element);
|
GstBin *bin = GST_BIN (element);
|
||||||
GstIterator *children;
|
gboolean ret;
|
||||||
gboolean have_async = FALSE;
|
GList *children;
|
||||||
gpointer child;
|
guint32 children_cookie;
|
||||||
|
|
||||||
/* we cannot take the state lock yet as we might block when querying
|
/* we cannot take the state lock yet as we might block when querying
|
||||||
* the children, holding the lock too long for no reason */
|
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* 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 */
|
/* now we can take the state lock */
|
||||||
GST_STATE_LOCK (bin);
|
GST_STATE_LOCK (bin);
|
||||||
if (!have_async) {
|
if (ret) {
|
||||||
/* no async children, we can commit the state */
|
/* no async children, we can commit the state */
|
||||||
gst_element_commit_state (element);
|
gst_element_commit_state (element);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and report the state */
|
/* and report the state if needed */
|
||||||
if (state)
|
if (state)
|
||||||
*state = GST_STATE (element);
|
*state = GST_STATE (element);
|
||||||
if (pending)
|
if (pending)
|
||||||
|
@ -651,7 +708,10 @@ gst_bin_get_state (GstElement * element, GstElementState * state,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this function is called with the STATE_LOCK held */
|
/* this function is called with the STATE_LOCK held.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_bin_change_state (GstElement * element)
|
gst_bin_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
@ -659,9 +719,8 @@ gst_bin_change_state (GstElement * element)
|
||||||
GstElementStateReturn ret;
|
GstElementStateReturn ret;
|
||||||
GstElementState old_state, pending;
|
GstElementState old_state, pending;
|
||||||
gboolean have_async = FALSE;
|
gboolean have_async = FALSE;
|
||||||
GstIterator *sinks;
|
GList *children;
|
||||||
gboolean done = FALSE;
|
guint32 children_cookie;
|
||||||
|
|
||||||
GQueue *elem_queue; /* list of elements waiting for a state change */
|
GQueue *elem_queue; /* list of elements waiting for a state change */
|
||||||
|
|
||||||
bin = GST_BIN (element);
|
bin = GST_BIN (element);
|
||||||
|
@ -677,44 +736,51 @@ gst_bin_change_state (GstElement * element)
|
||||||
if (pending == GST_STATE_VOID_PENDING)
|
if (pending == GST_STATE_VOID_PENDING)
|
||||||
return GST_STATE_SUCCESS;
|
return GST_STATE_SUCCESS;
|
||||||
|
|
||||||
|
/* all elements added to this queue should have their refcount
|
||||||
|
* incremented */
|
||||||
elem_queue = g_queue_new ();
|
elem_queue = g_queue_new ();
|
||||||
|
|
||||||
/* first step, find all sink elements, these are the elements
|
/* first step, find all sink elements, these are the elements
|
||||||
* without (linked) source pads. */
|
* without (linked) source pads. */
|
||||||
/* FIXME, we can iterate the list ourselves */
|
GST_LOCK (bin);
|
||||||
sinks = gst_bin_iterate_sinks (bin);
|
restart:
|
||||||
while (!done) {
|
children = bin->children;
|
||||||
gpointer child;
|
children_cookie = bin->children_cookie;
|
||||||
|
while (children) {
|
||||||
|
GstElement *child = GST_ELEMENT_CAST (children->data);
|
||||||
|
|
||||||
switch (gst_iterator_next (sinks, &child)) {
|
gst_object_ref (GST_OBJECT_CAST (child));
|
||||||
case GST_ITERATOR_OK:
|
GST_UNLOCK (bin);
|
||||||
/* this also keeps the refcount on the element */
|
|
||||||
g_queue_push_tail (elem_queue, child);
|
if (bin_element_is_sink (child, bin) == 0) {
|
||||||
break;
|
/* this also keeps the refcount on the element, note that
|
||||||
case GST_ITERATOR_RESYNC:
|
* the _is_sink function unrefs the element when it is not
|
||||||
/* undo what we had */
|
* a sink. */
|
||||||
g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL);
|
g_queue_push_tail (elem_queue, child);
|
||||||
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_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 */
|
/* second step, change state of elements in the queue */
|
||||||
while (!g_queue_is_empty (elem_queue)) {
|
while (!g_queue_is_empty (elem_queue)) {
|
||||||
GstElement *qelement = g_queue_pop_head (elem_queue);
|
GstElement *qelement = g_queue_pop_head (elem_queue);
|
||||||
GList *pads;
|
GList *pads;
|
||||||
|
gboolean locked;
|
||||||
|
|
||||||
/* queue all elements connected to the sinkpads of this element */
|
/* queue all elements connected to the sinkpads of this element */
|
||||||
/* FIXME, not MT safe !! */
|
GST_LOCK (qelement);
|
||||||
for (pads = qelement->sinkpads; pads; pads = g_list_next (pads)) {
|
pads = qelement->sinkpads;
|
||||||
|
while (pads) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
GstPad *peer;
|
GstPad *peer;
|
||||||
|
|
||||||
|
@ -730,9 +796,10 @@ gst_bin_change_state (GstElement * element)
|
||||||
|
|
||||||
if (peer_elem) {
|
if (peer_elem) {
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
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);
|
g_queue_push_tail (elem_queue, peer_elem);
|
||||||
}
|
}
|
||||||
gst_object_unref (GST_OBJECT (peer));
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
@ -740,12 +807,15 @@ gst_bin_change_state (GstElement * element)
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||||
"pad %s:%s does not have a peer", GST_DEBUG_PAD_NAME (pad));
|
"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;
|
goto next_element;
|
||||||
|
|
||||||
|
|
||||||
qelement->base_time = element->base_time;
|
qelement->base_time = element->base_time;
|
||||||
ret = gst_element_set_state (qelement, pending);
|
ret = gst_element_set_state (qelement, pending);
|
||||||
switch (ret) {
|
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_CAT_INFO (GST_CAT_PARENTAGE, "[%s]: looking up child element %s",
|
||||||
GST_ELEMENT_NAME (bin), name);
|
GST_ELEMENT_NAME (bin), name);
|
||||||
|
|
||||||
|
/* we recursively lock all elements, this might be a bit too much.. */
|
||||||
GST_LOCK (bin);
|
GST_LOCK (bin);
|
||||||
for (children = bin->children; children; children = g_list_next (children)) {
|
for (children = bin->children; children; children = g_list_next (children)) {
|
||||||
GstElement *child = GST_ELEMENT_CAST (children->data);
|
GstElement *child = GST_ELEMENT_CAST (children->data);
|
||||||
|
@ -861,6 +932,7 @@ gst_bin_get_by_name (GstBin * bin, const gchar * name)
|
||||||
GST_LOCK (child);
|
GST_LOCK (child);
|
||||||
eq = strcmp (GST_ELEMENT_NAME (child), name) == 0;
|
eq = strcmp (GST_ELEMENT_NAME (child), name) == 0;
|
||||||
GST_UNLOCK (child);
|
GST_UNLOCK (child);
|
||||||
|
|
||||||
if (eq) {
|
if (eq) {
|
||||||
result = child;
|
result = child;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include "gstmemchunk.h"
|
#include "gstmemchunk.h"
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
|
|
||||||
GType _gst_buffer_type;
|
GType _gst_buffer_type = 0;
|
||||||
|
|
||||||
#ifndef GST_DISABLE_TRACE
|
#ifndef GST_DISABLE_TRACE
|
||||||
/* #define GST_WITH_ALLOC_TRACE */
|
/* #define GST_WITH_ALLOC_TRACE */
|
||||||
|
@ -60,7 +60,7 @@ _gst_buffer_initialize (void)
|
||||||
GType
|
GType
|
||||||
gst_buffer_get_type (void)
|
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",
|
_gst_buffer_type = g_boxed_type_register_static ("GstBuffer",
|
||||||
(GBoxedCopyFunc) gst_data_copy, (GBoxedFreeFunc) gst_data_unref);
|
(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,
|
* 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.
|
* unless the GST_BUFFER_DONTFREE flags was set or the buffer data is NULL.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_buffer_default_free (GstBuffer * buffer)
|
gst_buffer_default_free (GstBuffer * buffer)
|
||||||
|
@ -121,6 +123,8 @@ gst_buffer_default_free (GstBuffer * buffer)
|
||||||
* is increased.
|
* is increased.
|
||||||
*
|
*
|
||||||
* Returns: the new #GstBuffer.
|
* Returns: the new #GstBuffer.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstBuffer *
|
GstBuffer *
|
||||||
gst_buffer_default_copy (GstBuffer * buffer)
|
gst_buffer_default_copy (GstBuffer * buffer)
|
||||||
|
@ -194,6 +198,8 @@ gst_buffer_free_chunk (GstBuffer * buffer)
|
||||||
* Creates a newly allocated buffer without any data.
|
* Creates a newly allocated buffer without any data.
|
||||||
*
|
*
|
||||||
* Returns: the new #GstBuffer.
|
* Returns: the new #GstBuffer.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstBuffer *
|
GstBuffer *
|
||||||
gst_buffer_new (void)
|
gst_buffer_new (void)
|
||||||
|
@ -231,6 +237,8 @@ gst_buffer_new (void)
|
||||||
* Creates a newly allocated buffer with data of the given size.
|
* Creates a newly allocated buffer with data of the given size.
|
||||||
*
|
*
|
||||||
* Returns: the new #GstBuffer.
|
* Returns: the new #GstBuffer.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstBuffer *
|
GstBuffer *
|
||||||
gst_buffer_new_and_alloc (guint size)
|
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
|
* is not media type attached to this buffer or when the media
|
||||||
* type is the same as the previous received buffer.
|
* 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
|
* Returns: the #GstCaps, or NULL if there was an error or there
|
||||||
* were no caps on this buffer.
|
* were no caps on this buffer.
|
||||||
*/
|
*/
|
||||||
|
/* FIXME can we make this threadsafe without a lock on the buffer? */
|
||||||
GstCaps *
|
GstCaps *
|
||||||
gst_buffer_get_caps (GstBuffer * buffer)
|
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
|
* be increased and any previous caps on the buffer will be
|
||||||
* unreffed.
|
* unreffed.
|
||||||
*/
|
*/
|
||||||
|
/* FIXME can we make this threadsafe without a lock on the buffer? */
|
||||||
void
|
void
|
||||||
gst_buffer_set_caps (GstBuffer * buffer, GstCaps * caps)
|
gst_buffer_set_caps (GstBuffer * buffer, GstCaps * caps)
|
||||||
{
|
{
|
||||||
|
GstCaps *oldcaps;
|
||||||
|
|
||||||
g_return_if_fail (buffer != NULL);
|
g_return_if_fail (buffer != NULL);
|
||||||
|
|
||||||
/* unref old caps if any */
|
/* get old caps */
|
||||||
if (GST_BUFFER_CAPS (buffer)) {
|
oldcaps = GST_BUFFER_CAPS (buffer);
|
||||||
gst_caps_unref (GST_BUFFER_CAPS (buffer));
|
|
||||||
}
|
|
||||||
/* ref new caps if any */
|
/* ref new caps if any */
|
||||||
if (caps)
|
if (caps)
|
||||||
caps = gst_caps_ref (caps);
|
caps = gst_caps_ref (caps);
|
||||||
|
|
||||||
/* set caps */
|
/* set caps */
|
||||||
GST_BUFFER_CAPS (buffer) = 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.
|
* 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.
|
* Returns: the new #GstBuffer, or NULL if there was an error.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstBuffer *
|
GstBuffer *
|
||||||
gst_buffer_create_sub (GstBuffer * parent, guint offset, guint size)
|
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.
|
* is created without copying the data.
|
||||||
*
|
*
|
||||||
* Returns: the new #GstBuffer that's the concatenation of the source buffers.
|
* Returns: the new #GstBuffer that's the concatenation of the source buffers.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstBuffer *
|
GstBuffer *
|
||||||
gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
|
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,
|
* Returns: TRUE if the buffers are contiguous,
|
||||||
* FALSE if a copy would be required.
|
* FALSE if a copy would be required.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_buffer_is_span_fast (GstBuffer * buf1, GstBuffer * buf2)
|
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.
|
* gst_buffer_is_span_fast() to determine if a memcpy will be needed.
|
||||||
*
|
*
|
||||||
* Returns: the new #GstBuffer that spans the two source buffers.
|
* Returns: the new #GstBuffer that spans the two source buffers.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstBuffer *
|
GstBuffer *
|
||||||
gst_buffer_span (GstBuffer * buf1, guint32 offset, GstBuffer * buf2,
|
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_ORIGINAL: buffer is not a copy of another buffer.
|
||||||
* @GST_BUFFER_DONTFREE: do not try to free the data when this buffer is
|
* @GST_BUFFER_DONTFREE: do not try to free the data when this buffer is
|
||||||
* unreferenced.
|
* unreferenced.
|
||||||
* @GST_BUFFER_KEY_UNIT: the buffer holds a key unit, a unit that can be
|
* @GST_BUFFER_PREROLL: The buffer is part of the preroll phase and should not
|
||||||
* decoded independently of other buffers.
|
* be displayed.
|
||||||
* This flag has been deprecated, see #GST_BUFFER_DELTA_UNIT.
|
* @GST_BUFFER_DISCONT: The buffer is the first after a discontinuity in the
|
||||||
* @GST_BUFFER_DONTKEEP:
|
* stream.
|
||||||
* @GST_BUFFER_IN_CAPS: the buffer has been added as a field in a #GstCaps.
|
* @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.
|
* @GST_BUFFER_DELTA_UNIT: this unit cannot be decoded independently.
|
||||||
* Since 0.8.5
|
* Since 0.8.5
|
||||||
* @GST_BUFFER_FLAG_LAST: additional flags can be added starting from this flag.
|
* @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
|
gboolean
|
||||||
gst_bus_post (GstBus * bus, GstMessage * message)
|
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_BUS (bus), FALSE);
|
||||||
g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE);
|
g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE);
|
||||||
|
|
||||||
|
/* first call the sync handler if it is installed */
|
||||||
if (bus->sync_handler) {
|
if (bus->sync_handler) {
|
||||||
reply = bus->sync_handler (bus, message, bus->sync_handler_data);
|
reply = bus->sync_handler (bus, message, bus->sync_handler_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* now see what we should do with the message */
|
||||||
switch (reply) {
|
switch (reply) {
|
||||||
case GST_BUS_DROP:
|
case GST_BUS_DROP:
|
||||||
|
/* drop the message */
|
||||||
break;
|
break;
|
||||||
case GST_BUS_PASS:
|
case GST_BUS_PASS:
|
||||||
|
/* pass the message to the async queue */
|
||||||
g_async_queue_push (bus->queue, message);
|
g_async_queue_push (bus->queue, message);
|
||||||
c = 'p';
|
c = 'p';
|
||||||
write (bus->control_socket[1], &c, 1);
|
write (bus->control_socket[1], &c, 1);
|
||||||
break;
|
break;
|
||||||
case GST_BUS_ASYNC:
|
case GST_BUS_ASYNC:
|
||||||
{
|
{
|
||||||
|
/* async delivery, we need a mutex and a cond to block
|
||||||
|
* on */
|
||||||
GMutex *lock = g_mutex_new ();
|
GMutex *lock = g_mutex_new ();
|
||||||
GCond *cond = g_cond_new ();
|
GCond *cond = g_cond_new ();
|
||||||
|
|
||||||
message->cond = cond;
|
GST_MESSAGE_COND (message) = cond;
|
||||||
message->lock = lock;
|
GST_MESSAGE_GET_LOCK (message) = lock;
|
||||||
|
|
||||||
GST_DEBUG ("waiting for async delivery of message %p", message);
|
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_mutex_lock (lock);
|
||||||
g_async_queue_push (bus->queue, message);
|
g_async_queue_push (bus->queue, message);
|
||||||
c = 'p';
|
c = 'p';
|
||||||
write (bus->control_socket[1], &c, 1);
|
write (bus->control_socket[1], &c, 1);
|
||||||
|
/* now block till the message is freed */
|
||||||
g_cond_wait (cond, lock);
|
g_cond_wait (cond, lock);
|
||||||
g_mutex_unlock (lock);
|
g_mutex_unlock (lock);
|
||||||
|
|
||||||
|
@ -191,6 +210,15 @@ gst_bus_post (GstBus * bus, GstMessage * message)
|
||||||
return TRUE;
|
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
|
gboolean
|
||||||
gst_bus_have_pending (GstBus * bus)
|
gst_bus_have_pending (GstBus * bus)
|
||||||
{
|
{
|
||||||
|
@ -203,6 +231,15 @@ gst_bus_have_pending (GstBus * bus)
|
||||||
return (length > 0);
|
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 *
|
GstMessage *
|
||||||
gst_bus_pop (GstBus * bus)
|
gst_bus_pop (GstBus * bus)
|
||||||
{
|
{
|
||||||
|
@ -217,6 +254,16 @@ gst_bus_pop (GstBus * bus)
|
||||||
return message;
|
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
|
void
|
||||||
gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func, gpointer data)
|
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;
|
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 *
|
GSource *
|
||||||
gst_bus_create_watch (GstBus * bus)
|
gst_bus_create_watch (GstBus * bus)
|
||||||
{
|
{
|
||||||
GSource *source;
|
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);
|
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
|
static void
|
||||||
bus_destroy (GstBusWatch * watch)
|
bus_destroy (GstBusWatch * watch)
|
||||||
{
|
{
|
||||||
g_print ("destroy\n");
|
|
||||||
if (watch->notify) {
|
if (watch->notify) {
|
||||||
watch->notify (watch->user_data);
|
watch->notify (watch->user_data);
|
||||||
}
|
}
|
||||||
g_free (watch);
|
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
|
guint
|
||||||
gst_bus_add_watch_full (GstBus * bus, gint priority,
|
gst_bus_add_watch_full (GstBus * bus, gint priority,
|
||||||
GstBusHandler handler, gpointer user_data, GDestroyNotify notify)
|
GstBusHandler handler, gpointer user_data, GDestroyNotify notify)
|
||||||
|
@ -303,6 +365,14 @@ gst_bus_add_watch_full (GstBus * bus, gint priority,
|
||||||
return id;
|
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
|
guint
|
||||||
gst_bus_add_watch (GstBus * bus, GstBusHandler handler, gpointer user_data)
|
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>
|
#include <gst/gstmessage.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
/* --- standard type macros --- */
|
/* --- standard type macros --- */
|
||||||
#define GST_TYPE_BUS (gst_bus_get_type ())
|
#define GST_TYPE_BUS (gst_bus_get_type ())
|
||||||
#define GST_BUS(bus) (G_TYPE_CHECK_INSTANCE_CAST ((bus), GST_TYPE_BUS, GstBus))
|
#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_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_GET_CLASS(bus) (G_TYPE_INSTANCE_GET_CLASS ((bus), GST_TYPE_BUS, GstBusClass))
|
||||||
#define GST_BUS_CAST(bus) ((GstBus*)(bus))
|
#define GST_BUS_CAST(bus) ((GstBus*)(bus))
|
||||||
typedef enum
|
|
||||||
|
typedef enum
|
||||||
{
|
{
|
||||||
GST_BUS_DROP = 0, /* drop message */
|
GST_BUS_DROP = 0, /* drop message */
|
||||||
GST_BUS_PASS = 1, /* pass message to async queue */
|
GST_BUS_PASS = 1, /* pass message to async queue */
|
||||||
GST_BUS_ASYNC = 2, /* pass message to async queue, continue if message is handled */
|
GST_BUS_ASYNC = 2, /* pass message to async queue, continue if message is handled */
|
||||||
} GstBusSyncReply;
|
} GstBusSyncReply;
|
||||||
|
|
||||||
typedef GstBusSyncReply (*GstBusSyncHandler) (GstBus * bus,
|
typedef GstBusSyncReply (*GstBusSyncHandler) (GstBus * bus, GstMessage * message, gpointer data);
|
||||||
GstMessage * message, gpointer data);
|
typedef gboolean (*GstBusHandler) (GstBus * bus, GstMessage * message, gpointer data);
|
||||||
typedef gboolean (*GstBusHandler) (GstBus * bus, GstMessage * message,
|
|
||||||
gpointer data);
|
|
||||||
|
|
||||||
struct _GstBus
|
struct _GstBus
|
||||||
{
|
{
|
||||||
GstObject object;
|
GstObject object;
|
||||||
|
|
||||||
/*< private > */
|
/*< private > */
|
||||||
GAsyncQueue *queue;
|
GAsyncQueue *queue;
|
||||||
|
|
||||||
GstBusSyncHandler sync_handler;
|
GstBusSyncHandler sync_handler;
|
||||||
gpointer sync_handler_data;
|
gpointer sync_handler_data;
|
||||||
|
|
||||||
gint control_socket[2];
|
gint control_socket[2];
|
||||||
GIOChannel *io_channel;
|
GIOChannel *io_channel;
|
||||||
|
|
||||||
/*< private > */
|
/*< private > */
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
|
@ -71,23 +71,26 @@ struct _GstBusClass
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
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);
|
gboolean gst_bus_have_pending (GstBus * bus);
|
||||||
const GstMessage *gst_bus_peek (GstBus * bus);
|
const GstMessage * gst_bus_peek (GstBus * bus);
|
||||||
GstMessage *gst_bus_pop (GstBus * bus);
|
GstMessage * gst_bus_pop (GstBus * bus);
|
||||||
|
|
||||||
void gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func,
|
void gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
|
||||||
GSource *gst_bus_create_watch (GstBus * bus);
|
GSource * gst_bus_create_watch (GstBus * bus);
|
||||||
guint gst_bus_add_watch_full (GstBus * bus,
|
guint gst_bus_add_watch_full (GstBus * bus,
|
||||||
gint priority,
|
gint priority,
|
||||||
GstBusHandler handler, gpointer user_data, GDestroyNotify notify);
|
GstBusHandler handler,
|
||||||
guint gst_bus_add_watch (GstBus * bus,
|
gpointer user_data,
|
||||||
GstBusHandler handler, gpointer user_data);
|
GDestroyNotify notify);
|
||||||
|
guint gst_bus_add_watch (GstBus * bus,
|
||||||
|
GstBusHandler handler,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
#endif /* __GST_BUS_H__ */
|
#endif /* __GST_BUS_H__ */
|
||||||
|
|
294
gst/gstclock.c
294
gst/gstclock.c
|
@ -1,6 +1,7 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
* 2000 Wim Taymans <wtay@chello.be>
|
||||||
|
* 2004 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstclock.c: Clock subsystem for maintaining time sync
|
* gstclock.c: Clock subsystem for maintaining time sync
|
||||||
*
|
*
|
||||||
|
@ -47,9 +48,6 @@ enum
|
||||||
|
|
||||||
static GstMemChunk *_gst_clock_entries_chunk;
|
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_class_init (GstClockClass * klass);
|
||||||
static void gst_clock_init (GstClock * clock);
|
static void gst_clock_init (GstClock * clock);
|
||||||
static void gst_clock_dispose (GObject * object);
|
static void gst_clock_dispose (GObject * object);
|
||||||
|
@ -75,25 +73,86 @@ gst_clock_entry_new (GstClock * clock, GstClockTime time,
|
||||||
#ifndef GST_DISABLE_TRACE
|
#ifndef GST_DISABLE_TRACE
|
||||||
gst_alloc_trace_new (_gst_clock_entry_trace, entry);
|
gst_alloc_trace_new (_gst_clock_entry_trace, entry);
|
||||||
#endif
|
#endif
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "created entry %p", entry);
|
||||||
|
|
||||||
|
gst_atomic_int_init (&entry->refcount, 1);
|
||||||
entry->clock = clock;
|
entry->clock = clock;
|
||||||
entry->time = time;
|
entry->time = time;
|
||||||
entry->interval = interval;
|
entry->interval = interval;
|
||||||
entry->type = type;
|
entry->type = type;
|
||||||
entry->status = GST_CLOCK_ENTRY_OK;
|
entry->status = GST_CLOCK_BUSY;
|
||||||
|
|
||||||
return (GstClockID) entry;
|
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
|
* gst_clock_new_single_shot_id
|
||||||
* @clock: The clockid to get a single shot notification from
|
* @clock: The clockid to get a single shot notification from
|
||||||
* @time: the requested time
|
* @time: the requested time
|
||||||
*
|
*
|
||||||
* Get an ID from the given clock to trigger a single shot
|
* 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.
|
* Returns: An id that can be used to request the time notification.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstClockID
|
GstClockID
|
||||||
gst_clock_new_single_shot_id (GstClock * clock, GstClockTime time)
|
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.
|
* Get an ID from the given clock to trigger a periodic notification.
|
||||||
* The periodeic notifications will be start at time start_time and
|
* 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.
|
* Returns: An id that can be used to request the time notification.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstClockID
|
GstClockID
|
||||||
gst_clock_new_periodic_id (GstClock * clock, GstClockTime start_time,
|
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);
|
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
|
* gst_clock_id_get_time
|
||||||
* @id: The clockid to query
|
* @id: The clockid to query
|
||||||
*
|
*
|
||||||
* Get the time of the clock ID
|
* 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
|
GstClockTime
|
||||||
gst_clock_id_get_time (GstClockID id)
|
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
|
* @jitter: A pointer that will contain the jitter
|
||||||
*
|
*
|
||||||
* Perform a blocking wait on the given ID. The jitter arg can be
|
* Perform a blocking wait on the given ID. The jitter arg can be
|
||||||
* NULL
|
* NULL.
|
||||||
*
|
*
|
||||||
* Returns: the result of the blocking wait.
|
* Returns: the result of the blocking wait.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstClockReturn
|
GstClockReturn
|
||||||
gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
|
gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
|
||||||
{
|
{
|
||||||
GstClockEntry *entry;
|
GstClockEntry *entry;
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
GstClockReturn res = GST_CLOCK_UNSUPPORTED;
|
GstClockReturn res;
|
||||||
GstClockTime requested;
|
GstClockTime requested;
|
||||||
GstClockClass *cclass;
|
GstClockClass *cclass;
|
||||||
|
|
||||||
|
@ -169,43 +258,38 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
|
||||||
entry = (GstClockEntry *) id;
|
entry = (GstClockEntry *) id;
|
||||||
requested = GST_CLOCK_ENTRY_TIME (entry);
|
requested = GST_CLOCK_ENTRY_TIME (entry);
|
||||||
|
|
||||||
if (!GST_CLOCK_TIME_IS_VALID (requested)) {
|
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _TIMEOUT");
|
goto invalid_time;
|
||||||
return GST_CLOCK_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
clock = GST_CLOCK_ENTRY_CLOCK (entry);
|
clock = GST_CLOCK_ENTRY_CLOCK (entry);
|
||||||
cclass = GST_CLOCK_GET_CLASS (clock);
|
cclass = GST_CLOCK_GET_CLASS (clock);
|
||||||
|
|
||||||
if (cclass->wait) {
|
if (G_LIKELY (cclass->wait)) {
|
||||||
GstClockTime now;
|
|
||||||
|
|
||||||
GST_LOCK (clock);
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock entry %p", id);
|
||||||
clock->entries = g_list_prepend (clock->entries, entry);
|
res = cclass->wait (clock, entry);
|
||||||
GST_UNLOCK (clock);
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting entry %p", id);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (jitter) {
|
if (jitter) {
|
||||||
now = gst_clock_get_time (clock);
|
GstClockTime now = gst_clock_get_time (clock);
|
||||||
|
|
||||||
*jitter = now - requested;
|
*jitter = now - requested;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clock->stats) {
|
if (clock->stats) {
|
||||||
gst_clock_update_stats (clock);
|
gst_clock_update_stats (clock);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
res = GST_CLOCK_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
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
|
* @user_data: User data passed in the calback
|
||||||
*
|
*
|
||||||
* Register a callback on the given clockid with the given
|
* 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.
|
* Returns: the result of the non blocking wait.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstClockReturn
|
GstClockReturn
|
||||||
gst_clock_id_wait_async (GstClockID id,
|
gst_clock_id_wait_async (GstClockID id,
|
||||||
|
@ -225,19 +314,19 @@ gst_clock_id_wait_async (GstClockID id,
|
||||||
{
|
{
|
||||||
GstClockEntry *entry;
|
GstClockEntry *entry;
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
GstClockReturn res = GST_CLOCK_UNSUPPORTED;
|
GstClockReturn res;
|
||||||
GstClockClass *cclass;
|
GstClockClass *cclass;
|
||||||
|
GstClockTime requested;
|
||||||
|
|
||||||
g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
|
g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
|
||||||
g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
|
g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
|
||||||
|
|
||||||
entry = (GstClockEntry *) id;
|
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))) {
|
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
|
||||||
(func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
|
goto invalid_time;
|
||||||
return GST_CLOCK_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
cclass = GST_CLOCK_GET_CLASS (clock);
|
cclass = GST_CLOCK_GET_CLASS (clock);
|
||||||
|
|
||||||
|
@ -246,26 +335,28 @@ gst_clock_id_wait_async (GstClockID id,
|
||||||
entry->user_data = user_data;
|
entry->user_data = user_data;
|
||||||
|
|
||||||
res = cclass->wait_async (clock, entry);
|
res = cclass->wait_async (clock, entry);
|
||||||
|
} else {
|
||||||
|
res = GST_CLOCK_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
/* ERRORS */
|
||||||
static void
|
invalid_time:
|
||||||
gst_clock_reschedule_func (GstClockEntry * entry)
|
{
|
||||||
{
|
(func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
|
||||||
entry->status = GST_CLOCK_ENTRY_OK;
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
|
||||||
|
return GST_CLOCK_BADTIME;
|
||||||
gst_clock_id_unlock ((GstClockID) entry);
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_clock_id_unschedule:
|
* gst_clock_id_unschedule:
|
||||||
* @id: The id to 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
|
void
|
||||||
gst_clock_id_unschedule (GstClockID id)
|
gst_clock_id_unschedule (GstClockID id)
|
||||||
|
@ -285,47 +376,6 @@ gst_clock_id_unschedule (GstClockID id)
|
||||||
cclass->unschedule (clock, entry);
|
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
|
* 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_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATS,
|
||||||
g_param_spec_boolean ("stats", "Stats", "Enable clock stats",
|
g_param_spec_boolean ("stats", "Stats", "Enable clock stats",
|
||||||
FALSE, G_PARAM_READWRITE));
|
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
|
static void
|
||||||
|
@ -401,6 +442,7 @@ gst_clock_init (GstClock * clock)
|
||||||
clock->adjust = 0;
|
clock->adjust = 0;
|
||||||
clock->last_time = 0;
|
clock->last_time = 0;
|
||||||
clock->entries = NULL;
|
clock->entries = NULL;
|
||||||
|
clock->entries_changed = g_cond_new ();
|
||||||
clock->flags = 0;
|
clock->flags = 0;
|
||||||
clock->stats = FALSE;
|
clock->stats = FALSE;
|
||||||
}
|
}
|
||||||
|
@ -408,7 +450,9 @@ gst_clock_init (GstClock * clock)
|
||||||
static void
|
static void
|
||||||
gst_clock_dispose (GObject * object)
|
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);
|
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
|
* Gets the current time of the given clock. The time is always
|
||||||
* monotonically increasing.
|
* 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
|
GstClockTime
|
||||||
gst_clock_get_time (GstClock * clock)
|
gst_clock_get_time (GstClock * clock)
|
||||||
{
|
{
|
||||||
GstClockTime ret = G_GINT64_CONSTANT (0);
|
GstClockTime ret;
|
||||||
GstClockClass *cclass;
|
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);
|
cclass = GST_CLOCK_GET_CLASS (clock);
|
||||||
|
|
||||||
if (cclass->get_internal_time) {
|
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 */
|
/* make sure the time is increasing, else return last_time */
|
||||||
|
GST_LOCK (clock);
|
||||||
|
ret += clock->adjust;
|
||||||
if ((gint64) ret < (gint64) clock->last_time) {
|
if ((gint64) ret < (gint64) clock->last_time) {
|
||||||
ret = clock->last_time;
|
ret = clock->last_time;
|
||||||
} else {
|
} else {
|
||||||
clock->last_time = ret;
|
clock->last_time = ret;
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (clock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -504,36 +557,17 @@ gst_clock_get_time (GstClock * clock)
|
||||||
* moves it backwards. Note that _get_time() always returns
|
* moves it backwards. Note that _get_time() always returns
|
||||||
* increasing values so when you move the clock backwards, _get_time()
|
* increasing values so when you move the clock backwards, _get_time()
|
||||||
* will report the previous value until the clock catches up.
|
* will report the previous value until the clock catches up.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_clock_set_time_adjust (GstClock * clock, GstClockTime adjust)
|
gst_clock_set_time_adjust (GstClock * clock, GstClockTime adjust)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_IS_CLOCK (clock));
|
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);
|
GST_LOCK (clock);
|
||||||
if (clock->entries)
|
clock->adjust = adjust;
|
||||||
entry = GST_CLOCK_ENTRY (clock->entries->data);
|
|
||||||
GST_UNLOCK (clock);
|
GST_UNLOCK (clock);
|
||||||
|
|
||||||
return (GstClockID *) entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -554,10 +588,6 @@ gst_clock_set_property (GObject * object, guint prop_id,
|
||||||
clock->stats = g_value_get_boolean (value);
|
clock->stats = g_value_get_boolean (value);
|
||||||
g_object_notify (object, "stats");
|
g_object_notify (object, "stats");
|
||||||
break;
|
break;
|
||||||
case ARG_MAX_DIFF:
|
|
||||||
break;
|
|
||||||
case ARG_EVENT_DIFF:
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -576,10 +606,6 @@ gst_clock_get_property (GObject * object, guint prop_id,
|
||||||
case ARG_STATS:
|
case ARG_STATS:
|
||||||
g_value_set_boolean (value, clock->stats);
|
g_value_set_boolean (value, clock->stats);
|
||||||
break;
|
break;
|
||||||
case ARG_MAX_DIFF:
|
|
||||||
break;
|
|
||||||
case ARG_EVENT_DIFF:
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -81,15 +81,18 @@ typedef struct _GstClockClass GstClockClass;
|
||||||
typedef gboolean (*GstClockCallback) (GstClock *clock, GstClockTime time,
|
typedef gboolean (*GstClockCallback) (GstClock *clock, GstClockTime time,
|
||||||
GstClockID id, gpointer user_data);
|
GstClockID id, gpointer user_data);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
/*< protected >*/
|
{
|
||||||
GST_CLOCK_ENTRY_OK,
|
GST_CLOCK_OK = 0,
|
||||||
GST_CLOCK_ENTRY_EARLY,
|
GST_CLOCK_EARLY = 1,
|
||||||
GST_CLOCK_ENTRY_RESTART
|
GST_CLOCK_UNSCHEDULED = 2,
|
||||||
} GstClockEntryStatus;
|
GST_CLOCK_BUSY = 3,
|
||||||
|
GST_CLOCK_BADTIME = 4,
|
||||||
|
GST_CLOCK_ERROR = 5,
|
||||||
|
GST_CLOCK_UNSUPPORTED = 6,
|
||||||
|
} GstClockReturn;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/*< protected >*/
|
|
||||||
GST_CLOCK_ENTRY_SINGLE,
|
GST_CLOCK_ENTRY_SINGLE,
|
||||||
GST_CLOCK_ENTRY_PERIODIC
|
GST_CLOCK_ENTRY_PERIODIC
|
||||||
} GstClockEntryType;
|
} GstClockEntryType;
|
||||||
|
@ -102,26 +105,17 @@ typedef enum {
|
||||||
#define GST_CLOCK_ENTRY_STATUS(entry) ((entry)->status)
|
#define GST_CLOCK_ENTRY_STATUS(entry) ((entry)->status)
|
||||||
|
|
||||||
struct _GstClockEntry {
|
struct _GstClockEntry {
|
||||||
|
GstAtomicInt refcount;
|
||||||
/*< protected >*/
|
/*< protected >*/
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
GstClockEntryType type;
|
GstClockEntryType type;
|
||||||
GstClockTime time;
|
GstClockTime time;
|
||||||
GstClockTime interval;
|
GstClockTime interval;
|
||||||
GstClockEntryStatus status;
|
GstClockReturn status;
|
||||||
GstClockCallback func;
|
GstClockCallback func;
|
||||||
gpointer user_data;
|
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
|
typedef enum
|
||||||
{
|
{
|
||||||
GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC = (1 << 1),
|
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_SYNC = (1 << 3),
|
||||||
GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC = (1 << 4),
|
GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC = (1 << 4),
|
||||||
GST_CLOCK_FLAG_CAN_SET_RESOLUTION = (1 << 5),
|
GST_CLOCK_FLAG_CAN_SET_RESOLUTION = (1 << 5),
|
||||||
GST_CLOCK_FLAG_CAN_SET_SPEED = (1 << 6)
|
|
||||||
} GstClockFlags;
|
} GstClockFlags;
|
||||||
|
|
||||||
#define GST_CLOCK_FLAGS(clock) (GST_CLOCK(clock)->flags)
|
#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 {
|
struct _GstClock {
|
||||||
GstObject object;
|
GstObject object;
|
||||||
|
|
||||||
|
@ -144,6 +142,7 @@ struct _GstClock {
|
||||||
GstClockTime adjust;
|
GstClockTime adjust;
|
||||||
GstClockTime last_time;
|
GstClockTime last_time;
|
||||||
GList *entries;
|
GList *entries;
|
||||||
|
GCond *entries_changed;
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
guint64 resolution;
|
guint64 resolution;
|
||||||
|
@ -164,10 +163,9 @@ struct _GstClockClass {
|
||||||
GstClockTime (*get_internal_time) (GstClock *clock);
|
GstClockTime (*get_internal_time) (GstClock *clock);
|
||||||
|
|
||||||
/* waiting on an ID */
|
/* waiting on an ID */
|
||||||
GstClockEntryStatus (*wait) (GstClock *clock, GstClockEntry *entry);
|
GstClockReturn (*wait) (GstClock *clock, GstClockEntry *entry);
|
||||||
GstClockEntryStatus (*wait_async) (GstClock *clock, GstClockEntry *entry);
|
GstClockReturn (*wait_async) (GstClock *clock, GstClockEntry *entry);
|
||||||
void (*unschedule) (GstClock *clock, GstClockEntry *entry);
|
void (*unschedule) (GstClock *clock, GstClockEntry *entry);
|
||||||
void (*unlock) (GstClock *clock, GstClockEntry *entry);
|
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
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,
|
GstClockID gst_clock_new_periodic_id (GstClock *clock,
|
||||||
GstClockTime start_time,
|
GstClockTime start_time,
|
||||||
GstClockTime interval);
|
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 */
|
/* operations on IDs */
|
||||||
|
gint gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2);
|
||||||
|
|
||||||
GstClockTime gst_clock_id_get_time (GstClockID id);
|
GstClockTime gst_clock_id_get_time (GstClockID id);
|
||||||
GstClockReturn gst_clock_id_wait (GstClockID id,
|
GstClockReturn gst_clock_id_wait (GstClockID id,
|
||||||
GstClockTimeDiff *jitter);
|
GstClockTimeDiff *jitter);
|
||||||
|
@ -198,8 +201,6 @@ GstClockReturn gst_clock_id_wait_async (GstClockID id,
|
||||||
GstClockCallback func,
|
GstClockCallback func,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
void gst_clock_id_unschedule (GstClockID id);
|
void gst_clock_id_unschedule (GstClockID id);
|
||||||
void gst_clock_id_unlock (GstClockID id);
|
|
||||||
void gst_clock_id_free (GstClockID id);
|
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
111
gst/gstelement.c
111
gst/gstelement.c
|
@ -435,34 +435,29 @@ gst_element_get_index (GstElement * element)
|
||||||
gboolean
|
gboolean
|
||||||
gst_element_add_pad (GstElement * element, GstPad * pad)
|
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_ELEMENT (element), FALSE);
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), 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 */
|
/* locking pad to look at the name */
|
||||||
GST_LOCK (pad);
|
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,
|
/* then check to see if there's already a pad by that name here */
|
||||||
GST_PAD_NAME (pad))))
|
GST_LOCK (element);
|
||||||
|
if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads, pad_name)))
|
||||||
goto name_exists;
|
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_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'",
|
||||||
GST_STR_NULL (GST_PAD_NAME (pad)));
|
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 */
|
/* add it to the list */
|
||||||
switch (gst_pad_get_direction (pad)) {
|
switch (gst_pad_get_direction (pad)) {
|
||||||
case GST_PAD_SRC:
|
case GST_PAD_SRC:
|
||||||
|
@ -474,7 +469,7 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
|
||||||
element->numsinkpads++;
|
element->numsinkpads++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
/* can happen for ghost pads */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
element->pads = g_list_prepend (element->pads, pad);
|
element->pads = g_list_prepend (element->pads, pad);
|
||||||
|
@ -494,29 +489,23 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
had_parent:
|
name_exists:
|
||||||
{
|
{
|
||||||
gchar *parent_name = gst_element_get_name (old_parent);
|
g_critical ("Padname %s is not unique in element %s, not adding",
|
||||||
|
pad_name, GST_ELEMENT_NAME (element));
|
||||||
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));
|
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
GST_UNLOCK (pad);
|
g_free (pad_name);
|
||||||
g_free (parent_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;
|
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))
|
if (G_UNLIKELY (current_parent != element))
|
||||||
goto not_our_pad;
|
goto not_our_pad;
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT_CAST (current_parent));
|
||||||
|
|
||||||
/* FIXME, is this redundant with pad disposal? */
|
/* FIXME, is this redundant with pad disposal? */
|
||||||
if (GST_IS_REAL_PAD (pad)) {
|
if (GST_IS_REAL_PAD (pad)) {
|
||||||
GstPad *peer = gst_pad_get_peer (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));
|
gst_pad_unlink (pad, GST_PAD_CAST (peer));
|
||||||
else
|
else
|
||||||
gst_pad_unlink (GST_PAD_CAST (peer), pad);
|
gst_pad_unlink (GST_PAD_CAST (peer), pad);
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (peer));
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
}
|
}
|
||||||
} else if (GST_IS_GHOST_PAD (pad)) {
|
} 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.
|
* Retrieves an iterattor of @element's pads.
|
||||||
*
|
*
|
||||||
* Returns: the #GstIterator of pads.
|
* Returns: the #GstIterator of pads.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstIterator *
|
GstIterator *
|
||||||
gst_element_iterate_pads (GstElement * element)
|
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.
|
* forwards the query to a random usable sinkpad of this element.
|
||||||
*
|
*
|
||||||
* Returns: TRUE if the query could be performed.
|
* Returns: TRUE if the query could be performed.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_element_query (GstElement * element, GstQueryType type,
|
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.
|
* the query will be forwarded to a random sink pad.
|
||||||
*
|
*
|
||||||
* Returns: An array of #GstFormat elements.
|
* Returns: An array of #GstFormat elements.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
const GstFormat *
|
const GstFormat *
|
||||||
gst_element_get_formats (GstElement * element)
|
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.
|
* the query will be forwarded to a random sink pad.
|
||||||
*
|
*
|
||||||
* Returns: TRUE if the conversion could be performed.
|
* Returns: TRUE if the conversion could be performed.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_element_convert (GstElement * element,
|
gst_element_convert (GstElement * element,
|
||||||
|
@ -1330,7 +1330,7 @@ gst_element_post_message (GstElement * element, GstMessage * message)
|
||||||
GST_LOCK (element);
|
GST_LOCK (element);
|
||||||
bus = element->bus;
|
bus = element->bus;
|
||||||
|
|
||||||
if (bus == NULL) {
|
if (G_UNLIKELY (bus == NULL)) {
|
||||||
GST_DEBUG ("... but I won't because I have no bus");
|
GST_DEBUG ("... but I won't because I have no bus");
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
gst_data_unref (GST_DATA (message));
|
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);
|
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
||||||
|
|
||||||
GST_LOCK (element);
|
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))
|
if (G_UNLIKELY (old == locked_state))
|
||||||
goto was_ok;
|
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_state_get_name (GST_STATE (element)),
|
||||||
GST_ELEMENT_NAME (parent),
|
GST_ELEMENT_NAME (parent),
|
||||||
gst_element_state_get_name (GST_STATE (parent)));
|
gst_element_state_get_name (GST_STATE (parent)));
|
||||||
|
|
||||||
if (gst_element_set_state (element, GST_STATE (parent)) == GST_STATE_FAILURE) {
|
if (gst_element_set_state (element, GST_STATE (parent)) == GST_STATE_FAILURE) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1565,6 +1566,7 @@ gst_element_get_state_func (GstElement * element,
|
||||||
GST_STATE_LOCK (element);
|
GST_STATE_LOCK (element);
|
||||||
old_pending = GST_STATE_PENDING (element);
|
old_pending = GST_STATE_PENDING (element);
|
||||||
if (old_pending != GST_STATE_VOID_PENDING) {
|
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)) {
|
if (!GST_STATE_TIMED_WAIT (element, timeout)) {
|
||||||
/* timeout triggered */
|
/* timeout triggered */
|
||||||
if (state)
|
if (state)
|
||||||
|
@ -1578,7 +1580,7 @@ gst_element_get_state_func (GstElement * element,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* if nothing is pending anymore we can return TRUE and
|
/* 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 (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) {
|
||||||
if (state)
|
if (state)
|
||||||
*state = GST_STATE (element);
|
*state = GST_STATE (element);
|
||||||
|
@ -1654,7 +1656,7 @@ gst_element_abort_state (GstElement * element)
|
||||||
|
|
||||||
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
|
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],
|
g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
|
||||||
0, old_state, pending);
|
0, old_state, pending);
|
||||||
g_cond_broadcast (GST_STATE_GET_COND (element));
|
GST_STATE_BROADCAST (element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1798,7 +1800,13 @@ exit:
|
||||||
return return_val;
|
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
|
static gboolean
|
||||||
gst_element_pads_activate (GstElement * element, gboolean active)
|
gst_element_pads_activate (GstElement * element, gboolean active)
|
||||||
{
|
{
|
||||||
|
@ -1817,11 +1825,14 @@ restart:
|
||||||
gst_object_ref (GST_OBJECT (pad));
|
gst_object_ref (GST_OBJECT (pad));
|
||||||
GST_UNLOCK (element);
|
GST_UNLOCK (element);
|
||||||
|
|
||||||
|
/* we only care about real pads */
|
||||||
if (GST_IS_REAL_PAD (pad)) {
|
if (GST_IS_REAL_PAD (pad)) {
|
||||||
GstRealPad *peer;
|
GstRealPad *peer;
|
||||||
gboolean pad_loop;
|
gboolean pad_loop;
|
||||||
gboolean delay = FALSE;
|
gboolean delay = FALSE;
|
||||||
|
|
||||||
|
/* see if the pad has a loop function and grab
|
||||||
|
* the peer */
|
||||||
GST_LOCK (pad);
|
GST_LOCK (pad);
|
||||||
pad_loop = GST_RPAD_LOOPFUNC (pad) != NULL;
|
pad_loop = GST_RPAD_LOOPFUNC (pad) != NULL;
|
||||||
peer = GST_RPAD_PEER (pad);
|
peer = GST_RPAD_PEER (pad);
|
||||||
|
@ -1832,13 +1843,18 @@ restart:
|
||||||
if (peer) {
|
if (peer) {
|
||||||
gboolean peer_loop;
|
gboolean peer_loop;
|
||||||
|
|
||||||
|
/* see if the peer has a loop function */
|
||||||
peer_loop = GST_RPAD_LOOPFUNC (peer) != NULL;
|
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) {
|
if (GST_PAD_IS_SINK (pad) && pad_loop) {
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||||
"delaying pad %s", GST_OBJECT_NAME (pad));
|
"delaying pad %s", GST_OBJECT_NAME (pad));
|
||||||
delay = TRUE;
|
delay = TRUE;
|
||||||
} else if (GST_PAD_IS_SRC (pad) && peer_loop) {
|
} 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,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||||
"%sactivating pad %s", (active ? "" : "(de)"),
|
"%sactivating pad %s", (active ? "" : "(de)"),
|
||||||
GST_OBJECT_NAME (pad));
|
GST_OBJECT_NAME (pad));
|
||||||
|
@ -1846,15 +1862,19 @@ restart:
|
||||||
(active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE));
|
(active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE));
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
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),
|
result &= gst_pad_set_active (GST_PAD (peer),
|
||||||
(active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE));
|
(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;
|
delay = TRUE;
|
||||||
}
|
}
|
||||||
gst_object_unref (GST_OBJECT (peer));
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* all other conditions are just push based pads */
|
||||||
if (!delay) {
|
if (!delay) {
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||||
"%sactivating pad %s", (active ? "" : "(de)"),
|
"%sactivating pad %s", (active ? "" : "(de)"),
|
||||||
|
@ -2307,11 +2327,12 @@ gst_element_get_scheduler (GstElement * element)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_element_create_task:
|
* 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
|
* @func: the taskfunction to run
|
||||||
* @data: user data passed to the taskfunction.
|
* @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.
|
* 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_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),\
|
#define GST_STATE_TIMED_WAIT(elem, timeval) g_cond_timed_wait (GST_STATE_GET_COND (elem), GST_STATE_GET_LOCK (elem),\
|
||||||
timeval)
|
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 _GstElementFactory GstElementFactory;
|
||||||
typedef struct _GstElementFactoryClass GstElementFactoryClass;
|
typedef struct _GstElementFactoryClass GstElementFactoryClass;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||||
|
* 2005 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstformat.c: GstFormat registration
|
* gstformat.c: GstFormat registration
|
||||||
*
|
*
|
||||||
|
@ -25,10 +26,11 @@
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
#include "gstformat.h"
|
#include "gstformat.h"
|
||||||
|
|
||||||
|
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
|
||||||
static GList *_gst_formats = NULL;
|
static GList *_gst_formats = NULL;
|
||||||
static GHashTable *_nick_to_format = NULL;
|
static GHashTable *_nick_to_format = NULL;
|
||||||
static GHashTable *_format_to_nick = 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[] = {
|
static GstFormatDefinition standard_definitions[] = {
|
||||||
{GST_FORMAT_DEFAULT, "default", "Default format for the media type"},
|
{GST_FORMAT_DEFAULT, "default", "Default format for the media type"},
|
||||||
|
@ -44,6 +46,7 @@ _gst_format_initialize (void)
|
||||||
{
|
{
|
||||||
GstFormatDefinition *standards = standard_definitions;
|
GstFormatDefinition *standards = standard_definitions;
|
||||||
|
|
||||||
|
g_static_mutex_lock (&mutex);
|
||||||
if (_nick_to_format == NULL) {
|
if (_nick_to_format == NULL) {
|
||||||
_nick_to_format = g_hash_table_new (g_str_hash, g_str_equal);
|
_nick_to_format = g_hash_table_new (g_str_hash, g_str_equal);
|
||||||
_format_to_nick = g_hash_table_new (NULL, NULL);
|
_format_to_nick = g_hash_table_new (NULL, NULL);
|
||||||
|
@ -58,6 +61,7 @@ _gst_format_initialize (void)
|
||||||
standards++;
|
standards++;
|
||||||
_n_values++;
|
_n_values++;
|
||||||
}
|
}
|
||||||
|
g_static_mutex_unlock (&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,10 +70,12 @@ _gst_format_initialize (void)
|
||||||
* @description: The description of the new format
|
* @description: The description of the new format
|
||||||
*
|
*
|
||||||
* Create a new GstFormat based on the nick or return an
|
* 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
|
* Returns: A new GstFormat or an already registered format
|
||||||
* with the same nick.
|
* with the same nick.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstFormat
|
GstFormat
|
||||||
gst_format_register (const gchar * nick, const gchar * description)
|
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->nick = g_strdup (nick);
|
||||||
format->description = g_strdup (description);
|
format->description = g_strdup (description);
|
||||||
|
|
||||||
|
g_static_mutex_lock (&mutex);
|
||||||
g_hash_table_insert (_nick_to_format, format->nick, format);
|
g_hash_table_insert (_nick_to_format, format->nick, format);
|
||||||
g_hash_table_insert (_format_to_nick, GINT_TO_POINTER (format->value),
|
g_hash_table_insert (_format_to_nick, GINT_TO_POINTER (format->value),
|
||||||
format);
|
format);
|
||||||
_gst_formats = g_list_append (_gst_formats, format);
|
_gst_formats = g_list_append (_gst_formats, format);
|
||||||
_n_values++;
|
_n_values++;
|
||||||
|
g_static_mutex_unlock (&mutex);
|
||||||
|
|
||||||
return format->value;
|
return format->value;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +122,9 @@ gst_format_get_by_nick (const gchar * nick)
|
||||||
|
|
||||||
g_return_val_if_fail (nick != NULL, 0);
|
g_return_val_if_fail (nick != NULL, 0);
|
||||||
|
|
||||||
|
g_static_mutex_lock (&mutex);
|
||||||
format = g_hash_table_lookup (_nick_to_format, nick);
|
format = g_hash_table_lookup (_nick_to_format, nick);
|
||||||
|
g_static_mutex_unlock (&mutex);
|
||||||
|
|
||||||
if (format != NULL)
|
if (format != NULL)
|
||||||
return format->value;
|
return format->value;
|
||||||
|
@ -154,22 +164,38 @@ gst_formats_contains (const GstFormat * formats, GstFormat format)
|
||||||
* Get details about the given format.
|
* Get details about the given format.
|
||||||
*
|
*
|
||||||
* Returns: The #GstFormatDefinition for @format or NULL on failure.
|
* Returns: The #GstFormatDefinition for @format or NULL on failure.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
const GstFormatDefinition *
|
const GstFormatDefinition *
|
||||||
gst_format_get_details (GstFormat format)
|
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 *
|
GstIterator *
|
||||||
gst_format_get_definitions (void)
|
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 <glib.h>
|
||||||
|
|
||||||
|
#include <gst/gstiterator.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -88,8 +90,7 @@ gboolean gst_formats_contains (const GstFormat *formats, GstFormat format);
|
||||||
/* query for format details */
|
/* query for format details */
|
||||||
G_CONST_RETURN GstFormatDefinition*
|
G_CONST_RETURN GstFormatDefinition*
|
||||||
gst_format_get_details (GstFormat format);
|
gst_format_get_details (GstFormat format);
|
||||||
G_CONST_RETURN GList*
|
GstIterator* gst_format_iterate_definitions (void);
|
||||||
gst_format_get_definitions (void);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -37,6 +37,22 @@ gst_iterator_init (GstIterator * it,
|
||||||
it->free = free;
|
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 *
|
GstIterator *
|
||||||
gst_iterator_new (guint size,
|
gst_iterator_new (guint size,
|
||||||
GMutex * lock,
|
GMutex * lock,
|
||||||
|
@ -102,6 +118,22 @@ gst_list_iterator_free (GstListIterator * it)
|
||||||
g_free (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 *
|
GstIterator *
|
||||||
gst_iterator_new_list (GMutex * lock,
|
gst_iterator_new_list (GMutex * lock,
|
||||||
guint32 * master_cookie,
|
guint32 * master_cookie,
|
||||||
|
@ -130,6 +162,17 @@ gst_iterator_new_list (GMutex * lock,
|
||||||
return GST_ITERATOR (result);
|
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
|
GstIteratorResult
|
||||||
gst_iterator_next (GstIterator * it, gpointer * elem)
|
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 (it != NULL, GST_ITERATOR_ERROR);
|
||||||
g_return_val_if_fail (elem != 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);
|
g_mutex_lock (it->lock);
|
||||||
if (*it->master_cookie != it->cookie) {
|
if (G_UNLIKELY (*it->master_cookie != it->cookie)) {
|
||||||
result = GST_ITERATOR_RESYNC;
|
result = GST_ITERATOR_RESYNC;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -148,25 +191,42 @@ gst_iterator_next (GstIterator * it, gpointer * elem)
|
||||||
result = it->next (it, elem);
|
result = it->next (it, elem);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (it->lock)
|
if (G_LIKELY (it->lock))
|
||||||
g_mutex_unlock (it->lock);
|
g_mutex_unlock (it->lock);
|
||||||
|
|
||||||
return result;
|
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
|
void
|
||||||
gst_iterator_resync (GstIterator * it)
|
gst_iterator_resync (GstIterator * it)
|
||||||
{
|
{
|
||||||
g_return_if_fail (it != NULL);
|
g_return_if_fail (it != NULL);
|
||||||
|
|
||||||
if (it->lock)
|
if (G_LIKELY (it->lock))
|
||||||
g_mutex_lock (it->lock);
|
g_mutex_lock (it->lock);
|
||||||
it->resync (it);
|
it->resync (it);
|
||||||
it->cookie = *it->master_cookie;
|
it->cookie = *it->master_cookie;
|
||||||
if (it->lock)
|
if (G_LIKELY (it->lock))
|
||||||
g_mutex_unlock (it->lock);
|
g_mutex_unlock (it->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_iterator_free:
|
||||||
|
* @it: The #GstIterator to free
|
||||||
|
*
|
||||||
|
* Free the iterator.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
gst_iterator_free (GstIterator * it)
|
gst_iterator_free (GstIterator * it)
|
||||||
{
|
{
|
||||||
|
@ -189,6 +249,9 @@ typedef struct _GstIteratorFilter
|
||||||
|
|
||||||
} GstIteratorFilter;
|
} GstIteratorFilter;
|
||||||
|
|
||||||
|
/* this function can iterate in 3 modes:
|
||||||
|
* filter, foreach and find_custom.
|
||||||
|
*/
|
||||||
static GstIteratorResult
|
static GstIteratorResult
|
||||||
filter_next (GstIteratorFilter * it, gpointer * elem)
|
filter_next (GstIteratorFilter * it, gpointer * elem)
|
||||||
{
|
{
|
||||||
|
@ -197,16 +260,16 @@ filter_next (GstIteratorFilter * it, gpointer * elem)
|
||||||
|
|
||||||
*elem = NULL;
|
*elem = NULL;
|
||||||
|
|
||||||
if (it->found)
|
if (G_UNLIKELY (it->found))
|
||||||
return GST_ITERATOR_DONE;
|
return GST_ITERATOR_DONE;
|
||||||
|
|
||||||
while (!done) {
|
while (G_LIKELY (!done)) {
|
||||||
gpointer item;
|
gpointer item;
|
||||||
|
|
||||||
result = gst_iterator_next (it->slave, &item);
|
result = gst_iterator_next (it->slave, &item);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case GST_ITERATOR_OK:
|
case GST_ITERATOR_OK:
|
||||||
if (GST_ITERATOR (it)->lock)
|
if (G_LIKELY (GST_ITERATOR (it)->lock))
|
||||||
g_mutex_unlock (GST_ITERATOR (it)->lock);
|
g_mutex_unlock (GST_ITERATOR (it)->lock);
|
||||||
if (it->compare) {
|
if (it->compare) {
|
||||||
if (it->func (item, it->user_data) == 0) {
|
if (it->func (item, it->user_data) == 0) {
|
||||||
|
@ -218,7 +281,7 @@ filter_next (GstIteratorFilter * it, gpointer * elem)
|
||||||
} else {
|
} else {
|
||||||
it->func (item, it->user_data);
|
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);
|
g_mutex_lock (GST_ITERATOR (it)->lock);
|
||||||
break;
|
break;
|
||||||
case GST_ITERATOR_RESYNC:
|
case GST_ITERATOR_RESYNC:
|
||||||
|
@ -254,6 +317,23 @@ filter_free (GstIteratorFilter * it)
|
||||||
g_free (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 *
|
GstIterator *
|
||||||
gst_iterator_filter (GstIterator * it, gpointer user_data, GCompareFunc func)
|
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);
|
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
|
void
|
||||||
gst_iterator_foreach (GstIterator * it, GFunc function, gpointer user_data)
|
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_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
|
gpointer
|
||||||
gst_iterator_find_custom (GstIterator * it, gpointer user_data,
|
gst_iterator_find_custom (GstIterator * it, gpointer user_data,
|
||||||
GCompareFunc func)
|
GCompareFunc func)
|
||||||
|
|
|
@ -27,10 +27,10 @@
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_ITERATOR_DONE = 0,
|
GST_ITERATOR_DONE = 0, /* no more items in the iterator */
|
||||||
GST_ITERATOR_OK = 1,
|
GST_ITERATOR_OK = 1, /* item retrieved */
|
||||||
GST_ITERATOR_RESYNC = 2,
|
GST_ITERATOR_RESYNC = 2, /* datastructures changed while iterating */
|
||||||
GST_ITERATOR_ERROR = 3,
|
GST_ITERATOR_ERROR = 3, /* some error happened */
|
||||||
} GstIteratorResult;
|
} GstIteratorResult;
|
||||||
|
|
||||||
typedef struct _GstIterator GstIterator;
|
typedef struct _GstIterator GstIterator;
|
||||||
|
@ -59,6 +59,7 @@ struct _GstIterator {
|
||||||
iterator was created */
|
iterator was created */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* creating iterators */
|
||||||
GstIterator* gst_iterator_new (guint size,
|
GstIterator* gst_iterator_new (guint size,
|
||||||
GMutex *lock,
|
GMutex *lock,
|
||||||
guint32 *master_cookie,
|
guint32 *master_cookie,
|
||||||
|
@ -74,10 +75,12 @@ GstIterator* gst_iterator_new_list (GMutex *lock,
|
||||||
GstIteratorUnrefFunction unref,
|
GstIteratorUnrefFunction unref,
|
||||||
GstIteratorDisposeFunction free);
|
GstIteratorDisposeFunction free);
|
||||||
|
|
||||||
|
/* using iterators */
|
||||||
GstIteratorResult gst_iterator_next (GstIterator *it, gpointer *result);
|
GstIteratorResult gst_iterator_next (GstIterator *it, gpointer *result);
|
||||||
void gst_iterator_resync (GstIterator *it);
|
void gst_iterator_resync (GstIterator *it);
|
||||||
void gst_iterator_free (GstIterator *it);
|
void gst_iterator_free (GstIterator *it);
|
||||||
|
|
||||||
|
/* special functions that operate on iterators */
|
||||||
void gst_iterator_foreach (GstIterator *it, GFunc function,
|
void gst_iterator_foreach (GstIterator *it, GFunc function,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
gpointer gst_iterator_find_custom (GstIterator *it, gpointer user_data,
|
gpointer gst_iterator_find_custom (GstIterator *it, gpointer user_data,
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -28,7 +32,6 @@
|
||||||
#include <valgrind/valgrind.h>
|
#include <valgrind/valgrind.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
|
#define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
|
||||||
#define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
|
#define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
|
||||||
#define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
|
#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)
|
* when it is too small (with a small overhead when that happens)
|
||||||
*
|
*
|
||||||
* Returns: a new #GstMemChunk
|
* Returns: a new #GstMemChunk
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstMemChunk *
|
GstMemChunk *
|
||||||
gst_mem_chunk_new (gchar * name, gint atom_size, gulong area_size, gint type)
|
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:
|
* gst_mem_chunk_destroy:
|
||||||
* @mem_chunk: the GstMemChunk to 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
|
void
|
||||||
gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
|
gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
|
||||||
|
@ -186,6 +193,8 @@ gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
|
||||||
* was created.
|
* was created.
|
||||||
*
|
*
|
||||||
* Returns: a pointer to the allocated memory region.
|
* Returns: a pointer to the allocated memory region.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gpointer
|
gpointer
|
||||||
gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
|
gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
|
||||||
|
@ -197,15 +206,20 @@ gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
|
||||||
again:
|
again:
|
||||||
chunk = gst_trash_stack_pop (&mem_chunk->stack);
|
chunk = gst_trash_stack_pop (&mem_chunk->stack);
|
||||||
/* chunk is empty, try to refill */
|
/* chunk is empty, try to refill */
|
||||||
if (!chunk) {
|
if (G_UNLIKELY (!chunk)) {
|
||||||
if (populate (mem_chunk))
|
if (G_LIKELY (populate (mem_chunk))) {
|
||||||
goto again;
|
goto again;
|
||||||
else
|
} else {
|
||||||
|
/* this happens when we are in cleanup mode and we
|
||||||
|
* allocate all remaining chunks for cleanup */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef HAVE_VALGRIND
|
#ifdef HAVE_VALGRIND
|
||||||
VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
|
if (G_UNLIKELY (__gst_in_valgrind ())) {
|
||||||
0, 0);
|
VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return GST_MEM_CHUNK_DATA (chunk);
|
return GST_MEM_CHUNK_DATA (chunk);
|
||||||
}
|
}
|
||||||
|
@ -219,13 +233,15 @@ again:
|
||||||
* was created. The memory will be set to all zeroes.
|
* was created. The memory will be set to all zeroes.
|
||||||
*
|
*
|
||||||
* Returns: a pointer to the allocated memory region.
|
* Returns: a pointer to the allocated memory region.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gpointer
|
gpointer
|
||||||
gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
|
gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
|
||||||
{
|
{
|
||||||
gpointer mem = gst_mem_chunk_alloc (mem_chunk);
|
gpointer mem = gst_mem_chunk_alloc (mem_chunk);
|
||||||
|
|
||||||
if (mem)
|
if (G_LIKELY (mem))
|
||||||
memset (mem, 0, mem_chunk->atom_size);
|
memset (mem, 0, mem_chunk->atom_size);
|
||||||
|
|
||||||
return mem;
|
return mem;
|
||||||
|
@ -237,6 +253,8 @@ gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
|
||||||
* @mem: the memory region to hand back to the chunk
|
* @mem: the memory region to hand back to the chunk
|
||||||
*
|
*
|
||||||
* Free the memeory region allocated from the chunk.
|
* Free the memeory region allocated from the chunk.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
|
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);
|
chunk = GST_MEM_CHUNK_LINK (mem);
|
||||||
|
|
||||||
#ifdef HAVE_VALGRIND
|
#ifdef HAVE_VALGRIND
|
||||||
VALGRIND_FREELIKE_BLOCK (mem, 0);
|
if (G_UNLIKELY (__gst_in_valgrind ())) {
|
||||||
|
VALGRIND_FREELIKE_BLOCK (mem, 0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
gst_trash_stack_push (&mem_chunk->stack, chunk);
|
gst_trash_stack_push (&mem_chunk->stack, chunk);
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,9 +96,9 @@ _gst_message_free (GstMessage * message)
|
||||||
gst_object_unref (GST_MESSAGE_SRC (message));
|
gst_object_unref (GST_MESSAGE_SRC (message));
|
||||||
}
|
}
|
||||||
if (message->lock) {
|
if (message->lock) {
|
||||||
g_mutex_lock (message->lock);
|
GST_MESSAGE_LOCK (message);
|
||||||
g_cond_signal (message->cond);
|
GST_MESSAGE_SIGNAL (message);
|
||||||
g_mutex_unlock (message->lock);
|
GST_MESSAGE_UNLOCK (message);
|
||||||
}
|
}
|
||||||
switch (GST_MESSAGE_TYPE (message)) {
|
switch (GST_MESSAGE_TYPE (message)) {
|
||||||
case GST_MESSAGE_ERROR:
|
case GST_MESSAGE_ERROR:
|
||||||
|
@ -137,6 +137,8 @@ gst_message_get_type (void)
|
||||||
* Allocate a new message of the given type.
|
* Allocate a new message of the given type.
|
||||||
*
|
*
|
||||||
* Returns: A new message.
|
* Returns: A new message.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstMessage *
|
GstMessage *
|
||||||
gst_message_new (GstMessageType type, GstObject * src)
|
gst_message_new (GstMessageType type, GstObject * src)
|
||||||
|
@ -171,6 +173,8 @@ gst_message_new (GstMessageType type, GstObject * src)
|
||||||
* Create a new eos message.
|
* Create a new eos message.
|
||||||
*
|
*
|
||||||
* Returns: The new eos message.
|
* Returns: The new eos message.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstMessage *
|
GstMessage *
|
||||||
gst_message_new_eos (GstObject * src)
|
gst_message_new_eos (GstObject * src)
|
||||||
|
@ -188,6 +192,8 @@ gst_message_new_eos (GstObject * src)
|
||||||
* Create a new error message.
|
* Create a new error message.
|
||||||
*
|
*
|
||||||
* Returns: The new error message.
|
* Returns: The new error message.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstMessage *
|
GstMessage *
|
||||||
gst_message_new_error (GstObject * src, GError * error, gchar * debug)
|
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.
|
* Create a new warning message.
|
||||||
*
|
*
|
||||||
* Returns: The new warning message.
|
* Returns: The new warning message.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstMessage *
|
GstMessage *
|
||||||
gst_message_new_warning (GstObject * src, GError * error, gchar * debug)
|
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.
|
* Create a new tag message.
|
||||||
*
|
*
|
||||||
* Returns: The new tag message.
|
* Returns: The new tag message.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstMessage *
|
GstMessage *
|
||||||
gst_message_new_tag (GstObject * src, GstTagList * tag_list)
|
gst_message_new_tag (GstObject * src, GstTagList * tag_list)
|
||||||
|
|
|
@ -49,6 +49,13 @@ typedef enum
|
||||||
#define GST_MESSAGE(message) ((GstMessage*)(message))
|
#define GST_MESSAGE(message) ((GstMessage*)(message))
|
||||||
#define GST_IS_MESSAGE(message) (GST_DATA_TYPE(message) == GST_TYPE_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_TYPE(message) (GST_MESSAGE(message)->type)
|
||||||
#define GST_MESSAGE_TIMESTAMP(message) (GST_MESSAGE(message)->timestamp)
|
#define GST_MESSAGE_TIMESTAMP(message) (GST_MESSAGE(message)->timestamp)
|
||||||
#define GST_MESSAGE_SRC(message) (GST_MESSAGE(message)->src)
|
#define GST_MESSAGE_SRC(message) (GST_MESSAGE(message)->src)
|
||||||
|
@ -94,10 +101,10 @@ struct _GstMessage
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
void _gst_message_initialize (void);
|
void _gst_message_initialize (void);
|
||||||
|
|
||||||
GType gst_message_get_type (void);
|
GType gst_message_get_type (void);
|
||||||
GstMessage *gst_message_new (GstMessageType type, GstObject * src);
|
GstMessage * gst_message_new (GstMessageType type, GstObject * src);
|
||||||
|
|
||||||
/* refcounting */
|
/* refcounting */
|
||||||
#define gst_message_ref(ev) GST_MESSAGE (gst_data_ref (GST_DATA (ev)))
|
#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 */
|
/* copy message */
|
||||||
#define gst_message_copy(ev) GST_MESSAGE (gst_data_copy (GST_DATA (ev)))
|
#define gst_message_copy(ev) GST_MESSAGE (gst_data_copy (GST_DATA (ev)))
|
||||||
|
|
||||||
GstMessage *gst_message_new_eos (GstObject * src);
|
GstMessage * gst_message_new_eos (GstObject * src);
|
||||||
GstMessage *gst_message_new_error (GstObject * src, GError * error,
|
GstMessage * gst_message_new_error (GstObject * src, GError * error, gchar * debug);
|
||||||
gchar * debug);
|
GstMessage * gst_message_new_warning (GstObject * src, GError * error, gchar * debug);
|
||||||
GstMessage *gst_message_new_warning (GstObject * src, GError * error,
|
GstMessage * gst_message_new_tag (GstObject * src, GstTagList * tag_list);
|
||||||
gchar * debug);
|
|
||||||
GstMessage *gst_message_new_tag (GstObject * src, GstTagList * tag_list);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
#endif /* __GST_MESSAGE_H__ */
|
#endif /* __GST_MESSAGE_H__ */
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
* 2000 Wim Taymans <wtay@chello.be>
|
||||||
|
* 2005 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstobject.c: Fundamental class used for all of GStreamer
|
* gstobject.c: Fundamental class used for all of GStreamer
|
||||||
*
|
*
|
||||||
|
@ -33,6 +34,15 @@
|
||||||
#define DEBUG_REFCOUNT
|
#define DEBUG_REFCOUNT
|
||||||
#define REFCOUNT_HACK
|
#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
|
#ifdef REFCOUNT_HACK
|
||||||
#define PATCH_REFCOUNT(obj) ((GObject*)(obj))->ref_count = 100000;
|
#define PATCH_REFCOUNT(obj) ((GObject*)(obj))->ref_count = 100000;
|
||||||
#define PATCH_REFCOUNT1(obj) ((GObject*)(obj))->ref_count = 1;
|
#define PATCH_REFCOUNT1(obj) ((GObject*)(obj))->ref_count = 1;
|
||||||
|
@ -196,9 +206,7 @@ gst_object_init (GstObject * object)
|
||||||
object->parent = NULL;
|
object->parent = NULL;
|
||||||
object->name = NULL;
|
object->name = NULL;
|
||||||
gst_atomic_int_init (&(object)->refcount, 1);
|
gst_atomic_int_init (&(object)->refcount, 1);
|
||||||
#ifdef REFCOUNT_HACK
|
|
||||||
PATCH_REFCOUNT (object);
|
PATCH_REFCOUNT (object);
|
||||||
#endif
|
|
||||||
|
|
||||||
object->flags = 0;
|
object->flags = 0;
|
||||||
GST_FLAG_SET (object, GST_OBJECT_FLOATING);
|
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)
|
gst_object_set_name_default (GstObject * object)
|
||||||
{
|
{
|
||||||
gint count;
|
gint count;
|
||||||
gchar *name, *tmp;
|
gchar *name, *tmp;
|
||||||
const gchar *type_name;
|
const gchar *type_name;
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
type_name = G_OBJECT_TYPE_NAME (object);
|
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));
|
name = g_ascii_strdown (tmp, strlen (tmp));
|
||||||
g_free (tmp);
|
g_free (tmp);
|
||||||
|
|
||||||
gst_object_set_name (object, name);
|
result = gst_object_set_name (object, name);
|
||||||
g_free (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
|
* This function makes a copy of the provided name, so the caller
|
||||||
* retains ownership of the name it sent.
|
* 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.
|
* MT safe. This function grabs and releases the object's LOCK.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_object_set_name (GstObject * object, const gchar * name)
|
gst_object_set_name (GstObject * object, const gchar * name)
|
||||||
{
|
{
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
|
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
|
||||||
|
|
||||||
GST_LOCK (object);
|
GST_LOCK (object);
|
||||||
|
|
||||||
/* parented objects cannot be renamed */
|
/* parented objects cannot be renamed */
|
||||||
if (object->parent != NULL) {
|
if (G_UNLIKELY (object->parent != NULL))
|
||||||
GST_UNLOCK (object);
|
goto had_parent;
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
g_free (object->name);
|
g_free (object->name);
|
||||||
object->name = g_strdup (name);
|
object->name = g_strdup (name);
|
||||||
GST_UNLOCK (object);
|
GST_UNLOCK (object);
|
||||||
|
result = TRUE;
|
||||||
} else {
|
} else {
|
||||||
GST_UNLOCK (object);
|
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
|
* This function makes a copy of the provided name prefix, so the caller
|
||||||
* retains ownership of the name prefix it sent.
|
* retains ownership of the name prefix it sent.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* MT safe. This function grabs and releases the object's LOCK.
|
* MT safe. This function grabs and releases the object's LOCK.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -858,15 +877,18 @@ gst_object_check_uniqueness (GList * list, const gchar * name)
|
||||||
|
|
||||||
for (; list; list = g_list_next (list)) {
|
for (; list; list = g_list_next (list)) {
|
||||||
GstObject *child;
|
GstObject *child;
|
||||||
|
gboolean eq;
|
||||||
|
|
||||||
child = GST_OBJECT (list->data);
|
child = GST_OBJECT (list->data);
|
||||||
|
|
||||||
GST_LOCK (child);
|
GST_LOCK (child);
|
||||||
if (strcmp (GST_OBJECT_NAME (child), name) == 0) {
|
eq = strcmp (GST_OBJECT_NAME (child), name) == 0;
|
||||||
GST_UNLOCK (child);
|
GST_UNLOCK (child);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (eq)) {
|
||||||
result = FALSE;
|
result = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
GST_UNLOCK (child);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
74
gst/gstpad.c
74
gst/gstpad.c
|
@ -47,6 +47,7 @@ GST_DEBUG_CATEGORY_STATIC (debug_dataflow);
|
||||||
}G_STMT_END
|
}G_STMT_END
|
||||||
#define GST_CAT_DEFAULT GST_CAT_PADS
|
#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) \
|
#define GST_PAD_REALIZE_AND_LOCK(pad, realpad, lost_ghostpad) \
|
||||||
GST_LOCK (pad); \
|
GST_LOCK (pad); \
|
||||||
realpad = GST_PAD_REALIZE (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.
|
* 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.
|
* Returns: a new #GstPad, or NULL in case of an error.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstPad *
|
GstPad *
|
||||||
gst_pad_new (const gchar * name, GstPadDirection direction)
|
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);
|
old = GST_PAD_IS_ACTIVE (realpad);
|
||||||
|
|
||||||
|
/* if nothing changed, we can just exit */
|
||||||
if (G_UNLIKELY (old == active))
|
if (G_UNLIKELY (old == active))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
@ -544,7 +548,7 @@ lost_ghostpad:
|
||||||
* reasons stated above.
|
* reasons stated above.
|
||||||
*
|
*
|
||||||
* Returns: TRUE if the pad could be blocked. This function can fail
|
* 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.
|
* requested state.
|
||||||
*
|
*
|
||||||
* MT safe.
|
* MT safe.
|
||||||
|
@ -707,7 +711,7 @@ gst_pad_set_loop_function (GstPad * pad, GstPadLoopFunction loop)
|
||||||
* @chain: the #GstPadChainFunction to set.
|
* @chain: the #GstPadChainFunction to set.
|
||||||
*
|
*
|
||||||
* Sets the given chain function for the pad. The chain function is called to
|
* 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
|
void
|
||||||
gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain)
|
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 */
|
/* this function would need checks if it weren't static */
|
||||||
|
|
||||||
|
GST_LOCK (pad);
|
||||||
gst_object_replace ((GstObject **) & pad->padtemplate, (GstObject *) templ);
|
gst_object_replace ((GstObject **) & pad->padtemplate, (GstObject *) templ);
|
||||||
|
GST_UNLOCK (pad);
|
||||||
|
|
||||||
if (templ) {
|
if (templ) {
|
||||||
gst_object_sink (GST_OBJECT (templ));
|
gst_object_sink (GST_OBJECT (templ));
|
||||||
|
@ -1711,6 +1717,7 @@ not_linked_together:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* should be called with the pad LOCK held */
|
||||||
static GstCaps *
|
static GstCaps *
|
||||||
gst_real_pad_get_caps_unlocked (GstRealPad * realpad)
|
gst_real_pad_get_caps_unlocked (GstRealPad * realpad)
|
||||||
{
|
{
|
||||||
|
@ -1784,9 +1791,12 @@ done:
|
||||||
filter = GST_RPAD_APPFILTER (realpad);
|
filter = GST_RPAD_APPFILTER (realpad);
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
|
GstCaps *temp = result;
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CAPS,
|
GST_CAT_DEBUG (GST_CAT_CAPS,
|
||||||
"app filter %p %" GST_PTR_FORMAT, filter, filter);
|
"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,
|
GST_CAT_DEBUG (GST_CAT_CAPS,
|
||||||
"caps after intersection with app filter %p %" GST_PTR_FORMAT, result,
|
"caps after intersection with app filter %p %" GST_PTR_FORMAT, result,
|
||||||
result);
|
result);
|
||||||
|
@ -1802,6 +1812,8 @@ done:
|
||||||
*
|
*
|
||||||
* Returns: the #GstCaps of this pad. This function returns a new caps, so use
|
* Returns: the #GstCaps of this pad. This function returns a new caps, so use
|
||||||
* gst_caps_unref to get rid of it.
|
* gst_caps_unref to get rid of it.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstCaps *
|
GstCaps *
|
||||||
gst_pad_get_caps (GstPad * pad)
|
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)))
|
if (G_UNLIKELY (GST_RPAD_IS_IN_GETCAPS (peerpad)))
|
||||||
goto was_dispatching;
|
goto was_dispatching;
|
||||||
|
|
||||||
result = gst_pad_get_caps (GST_PAD_CAST (peerpad));
|
gst_object_ref (GST_OBJECT (peerpad));
|
||||||
GST_UNLOCK (realpad);
|
GST_UNLOCK (realpad);
|
||||||
|
|
||||||
|
result = gst_pad_get_caps (GST_PAD_CAST (peerpad));
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (peerpad));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
lost_ghostpad:
|
lost_ghostpad:
|
||||||
|
@ -2727,8 +2743,7 @@ handle_pad_block (GstRealPad * pad)
|
||||||
* @pad: a source #GstPad.
|
* @pad: a source #GstPad.
|
||||||
* @buffer: the #GstBuffer to push.
|
* @buffer: the #GstBuffer to push.
|
||||||
*
|
*
|
||||||
* Pushes a buffer to the peer of @pad. @pad must be linked. May
|
* Pushes a buffer to the peer of @pad. @pad must be linked.
|
||||||
* only be called by @pad's parent.
|
|
||||||
*
|
*
|
||||||
* Returns: a #GstFlowReturn from the peer pad.
|
* Returns: a #GstFlowReturn from the peer pad.
|
||||||
*
|
*
|
||||||
|
@ -2837,8 +2852,7 @@ no_function:
|
||||||
* @offset: The start offset of the buffer
|
* @offset: The start offset of the buffer
|
||||||
* @length: The length of the buffer
|
* @length: The length of the buffer
|
||||||
*
|
*
|
||||||
* Pulls a buffer from the peer pad. May only be called by @pad's
|
* Pulls a buffer from the peer pad. @pad must be linked.
|
||||||
* parent.
|
|
||||||
*
|
*
|
||||||
* Returns: a #GstFlowReturn from the peer pad.
|
* Returns: a #GstFlowReturn from the peer pad.
|
||||||
*
|
*
|
||||||
|
@ -2884,16 +2898,19 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
|
||||||
|
|
||||||
/* ERROR recovery here */
|
/* ERROR recovery here */
|
||||||
not_connected:
|
not_connected:
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
{
|
||||||
"pulling range, but it was not linked");
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
|
||||||
GST_UNLOCK_RETURN (pad, GST_FLOW_NOT_CONNECTED);
|
"pulling range, but it was not linked");
|
||||||
|
GST_UNLOCK_RETURN (pad, GST_FLOW_NOT_CONNECTED);
|
||||||
|
}
|
||||||
no_function:
|
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_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
|
||||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
("pullrange on pad %s:%s but the peer pad %s:%s has no getrangefunction",
|
||||||
gst_object_unref (GST_OBJECT (peer));
|
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
|
||||||
return GST_FLOW_ERROR;
|
gst_object_unref (GST_OBJECT (peer));
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
|
@ -3477,13 +3494,10 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
|
||||||
|
|
||||||
/* ERROR handling */
|
/* ERROR handling */
|
||||||
not_linked:
|
not_linked:
|
||||||
result = FALSE;
|
{
|
||||||
goto error;
|
GST_UNLOCK (pad);
|
||||||
|
return FALSE;
|
||||||
error:
|
}
|
||||||
GST_UNLOCK (pad);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3538,12 +3552,12 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
|
||||||
|
|
||||||
/* ERROR handling */
|
/* ERROR handling */
|
||||||
no_function:
|
no_function:
|
||||||
g_warning ("pad %s:%s has no event handler, file a bug.",
|
{
|
||||||
GST_DEBUG_PAD_NAME (rpad));
|
g_warning ("pad %s:%s has no event handler, file a bug.",
|
||||||
result = FALSE;
|
GST_DEBUG_PAD_NAME (rpad));
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
return FALSE;
|
||||||
return result;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
|
@ -132,7 +132,7 @@ typedef enum {
|
||||||
typedef gboolean (*GstPadActivateFunction) (GstPad *pad, GstActivateMode mode);
|
typedef gboolean (*GstPadActivateFunction) (GstPad *pad, GstActivateMode mode);
|
||||||
|
|
||||||
/* data passing */
|
/* data passing */
|
||||||
typedef gboolean (*GstPadLoopFunction) (GstPad *pad);
|
typedef void (*GstPadLoopFunction) (GstPad *pad);
|
||||||
typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer);
|
typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer);
|
||||||
typedef GstFlowReturn (*GstPadGetRangeFunction) (GstPad *pad, guint64 offset,
|
typedef GstFlowReturn (*GstPadGetRangeFunction) (GstPad *pad, guint64 offset,
|
||||||
guint length, GstBuffer **buffer);
|
guint length, GstBuffer **buffer);
|
||||||
|
|
|
@ -209,6 +209,7 @@ is_eos (GstPipeline * pipeline)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME, make me threadsafe */
|
||||||
static GstBusSyncReply
|
static GstBusSyncReply
|
||||||
pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
||||||
GstPipeline * pipeline)
|
GstPipeline * pipeline)
|
||||||
|
@ -224,8 +225,10 @@ pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
||||||
switch (GST_MESSAGE_TYPE (message)) {
|
switch (GST_MESSAGE_TYPE (message)) {
|
||||||
case GST_MESSAGE_EOS:
|
case GST_MESSAGE_EOS:
|
||||||
if (GST_MESSAGE_SRC (message) != GST_OBJECT (pipeline)) {
|
if (GST_MESSAGE_SRC (message) != GST_OBJECT (pipeline)) {
|
||||||
|
GST_LOCK (bus);
|
||||||
pipeline->eosed =
|
pipeline->eosed =
|
||||||
g_list_prepend (pipeline->eosed, GST_MESSAGE_SRC (message));
|
g_list_prepend (pipeline->eosed, GST_MESSAGE_SRC (message));
|
||||||
|
GST_UNLOCK (bus);
|
||||||
if (is_eos (pipeline)) {
|
if (is_eos (pipeline)) {
|
||||||
posteos = TRUE;
|
posteos = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -257,6 +260,8 @@ pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
||||||
* Create a new pipeline with the given name.
|
* Create a new pipeline with the given name.
|
||||||
*
|
*
|
||||||
* Returns: newly created GstPipeline
|
* Returns: newly created GstPipeline
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstElement *
|
GstElement *
|
||||||
gst_pipeline_new (const gchar * name)
|
gst_pipeline_new (const gchar * name)
|
||||||
|
@ -264,6 +269,7 @@ gst_pipeline_new (const gchar * name)
|
||||||
return gst_element_factory_make ("pipeline", name);
|
return gst_element_factory_make ("pipeline", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MT safe */
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_pipeline_change_state (GstElement * element)
|
gst_pipeline_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
@ -276,14 +282,18 @@ gst_pipeline_change_state (GstElement * element)
|
||||||
gst_scheduler_setup (GST_ELEMENT_SCHEDULER (pipeline));
|
gst_scheduler_setup (GST_ELEMENT_SCHEDULER (pipeline));
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
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;
|
pipeline->eosed = NULL;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
if (element->clock) {
|
if (element->clock) {
|
||||||
/* we set time slightly ahead because of context switches */
|
/* we set time slightly ahead because of context switches */
|
||||||
pipeline->start_time =
|
pipeline->start_time = gst_clock_get_time (element->clock); // + 10*GST_MSECOND;
|
||||||
gst_clock_get_time (element->clock) + 10 * GST_MSECOND;
|
|
||||||
element->base_time = pipeline->start_time - pipeline->stream_time;
|
element->base_time = pipeline->start_time - pipeline->stream_time;
|
||||||
}
|
}
|
||||||
GST_DEBUG ("stream_time=%" G_GUINT64_FORMAT ", start_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.
|
* Gets the #GstScheduler of this pipeline.
|
||||||
*
|
*
|
||||||
* Returns: a GstScheduler.
|
* Returns: a GstScheduler.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstScheduler *
|
GstScheduler *
|
||||||
gst_pipeline_get_scheduler (GstPipeline * pipeline)
|
gst_pipeline_get_scheduler (GstPipeline * pipeline)
|
||||||
|
@ -349,6 +361,8 @@ gst_pipeline_get_scheduler (GstPipeline * pipeline)
|
||||||
* Gets the #GstBus of this pipeline.
|
* Gets the #GstBus of this pipeline.
|
||||||
*
|
*
|
||||||
* Returns: a GstBus
|
* Returns: a GstBus
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstBus *
|
GstBus *
|
||||||
gst_pipeline_get_bus (GstPipeline * pipeline)
|
gst_pipeline_get_bus (GstPipeline * pipeline)
|
||||||
|
@ -363,12 +377,16 @@ gst_pipeline_get_clock_func (GstElement * element)
|
||||||
GstPipeline *pipeline = GST_PIPELINE (element);
|
GstPipeline *pipeline = GST_PIPELINE (element);
|
||||||
|
|
||||||
/* if we have a fixed clock, use that one */
|
/* if we have a fixed clock, use that one */
|
||||||
|
GST_LOCK (pipeline);
|
||||||
if (GST_FLAG_IS_SET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK)) {
|
if (GST_FLAG_IS_SET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK)) {
|
||||||
clock = pipeline->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)",
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using fixed clock %p (%s)",
|
||||||
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
||||||
} else {
|
} else {
|
||||||
|
GST_UNLOCK (pipeline);
|
||||||
clock =
|
clock =
|
||||||
GST_ELEMENT_CLASS (parent_class)->get_clock (GST_ELEMENT (pipeline));
|
GST_ELEMENT_CLASS (parent_class)->get_clock (GST_ELEMENT (pipeline));
|
||||||
/* no clock, use a system clock */
|
/* 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
|
* Force the pipeline to use the given clock. The pipeline will
|
||||||
* always use the given clock even if new clock providers are added
|
* always use the given clock even if new clock providers are added
|
||||||
* to this pipeline.
|
* to this pipeline.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_pipeline_use_clock (GstPipeline * pipeline, GstClock * clock)
|
gst_pipeline_use_clock (GstPipeline * pipeline, GstClock * clock)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_IS_PIPELINE (pipeline));
|
g_return_if_fail (GST_IS_PIPELINE (pipeline));
|
||||||
|
|
||||||
|
GST_LOCK (pipeline);
|
||||||
GST_FLAG_SET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK);
|
GST_FLAG_SET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK);
|
||||||
|
|
||||||
gst_object_replace ((GstObject **) & pipeline->fixed_clock,
|
gst_object_replace ((GstObject **) & pipeline->fixed_clock,
|
||||||
(GstObject *) clock);
|
(GstObject *) clock);
|
||||||
|
GST_LOCK (pipeline);
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using fixed clock %p (%s)", clock,
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using fixed clock %p (%s)", clock,
|
||||||
(clock ? GST_OBJECT_NAME (clock) : "nil"));
|
(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
|
* Set the clock for the pipeline. The clock will be distributed
|
||||||
* to all the elements managed by the pipeline.
|
* to all the elements managed by the pipeline.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_pipeline_set_clock (GstPipeline * pipeline, GstClock * clock)
|
gst_pipeline_set_clock (GstPipeline * pipeline, GstClock * clock)
|
||||||
|
@ -450,6 +474,8 @@ gst_pipeline_set_clock (GstPipeline * pipeline, GstClock * clock)
|
||||||
* @pipeline: the pipeline
|
* @pipeline: the pipeline
|
||||||
*
|
*
|
||||||
* Let the pipeline select a clock automatically.
|
* Let the pipeline select a clock automatically.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_pipeline_auto_clock (GstPipeline * pipeline)
|
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_FLAG_UNSET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK);
|
||||||
|
|
||||||
|
GST_LOCK (pipeline);
|
||||||
gst_object_replace ((GstObject **) & pipeline->fixed_clock, NULL);
|
gst_object_replace ((GstObject **) & pipeline->fixed_clock, NULL);
|
||||||
|
GST_UNLOCK (pipeline);
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using automatic clock");
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using automatic clock");
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,18 +48,21 @@ typedef enum {
|
||||||
struct _GstPipeline {
|
struct _GstPipeline {
|
||||||
GstBin bin;
|
GstBin bin;
|
||||||
|
|
||||||
|
/*< public >*/ /* with LOCK */
|
||||||
GstClock *fixed_clock; /* fixed clock if any */
|
GstClock *fixed_clock; /* fixed clock if any */
|
||||||
GstClockTime start_time;
|
GstClockTime start_time;
|
||||||
GstClockTime stream_time;
|
GstClockTime stream_time;
|
||||||
|
|
||||||
GList *eosed; /* list of elements that posted EOS */
|
GList *eosed; /* list of elements that posted EOS */
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstPipelineClass {
|
struct _GstPipelineClass {
|
||||||
GstBinClass parent_class;
|
GstBinClass parent_class;
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
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))));
|
|| !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:
|
* gst_plugin_feature_set_name:
|
||||||
* @feature: a feature
|
* @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
|
* 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
|
* 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
|
void
|
||||||
gst_plugin_feature_set_name (GstPluginFeature * feature, const gchar * name)
|
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:
|
* gst_plugin_feature_get_name:
|
||||||
* @feature: a feature
|
* @feature: a feature
|
||||||
|
@ -213,3 +181,36 @@ gst_plugin_feature_get_name (GstPluginFeature * feature)
|
||||||
|
|
||||||
return feature->name;
|
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);
|
void (*unload_thyself) (GstPluginFeature *feature);
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,9 @@
|
||||||
* @callback: the function to call when the probe is triggered
|
* @callback: the function to call when the probe is triggered
|
||||||
* @user_data: data passed to the callback function
|
* @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.
|
* Returns: a new #GstProbe.
|
||||||
*/
|
*/
|
||||||
|
@ -221,7 +223,8 @@ gst_probe_dispatcher_dispatch (GstProbeDispatcher * disp, GstData ** data)
|
||||||
if (probe->single_shot) {
|
if (probe->single_shot) {
|
||||||
disp->probes = g_slist_remove (disp->probes, probe);
|
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
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||||
|
* 2005 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstquery.c: GstQueryType registration
|
* gstquery.c: GstQueryType registration
|
||||||
*
|
*
|
||||||
|
@ -25,10 +26,11 @@
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
#include "gstquery.h"
|
#include "gstquery.h"
|
||||||
|
|
||||||
|
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
|
||||||
static GList *_gst_queries = NULL;
|
static GList *_gst_queries = NULL;
|
||||||
static GHashTable *_nick_to_query = NULL;
|
static GHashTable *_nick_to_query = NULL;
|
||||||
static GHashTable *_query_type_to_nick = 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[] = {
|
static GstQueryTypeDefinition standard_definitions[] = {
|
||||||
{GST_QUERY_TOTAL, "total", "Total length"},
|
{GST_QUERY_TOTAL, "total", "Total length"},
|
||||||
|
@ -46,6 +48,7 @@ _gst_query_type_initialize (void)
|
||||||
{
|
{
|
||||||
GstQueryTypeDefinition *standards = standard_definitions;
|
GstQueryTypeDefinition *standards = standard_definitions;
|
||||||
|
|
||||||
|
g_static_mutex_lock (&mutex);
|
||||||
if (_nick_to_query == NULL) {
|
if (_nick_to_query == NULL) {
|
||||||
_nick_to_query = g_hash_table_new (g_str_hash, g_str_equal);
|
_nick_to_query = g_hash_table_new (g_str_hash, g_str_equal);
|
||||||
_query_type_to_nick = g_hash_table_new (NULL, NULL);
|
_query_type_to_nick = g_hash_table_new (NULL, NULL);
|
||||||
|
@ -60,6 +63,7 @@ _gst_query_type_initialize (void)
|
||||||
standards++;
|
standards++;
|
||||||
_n_values++;
|
_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->nick = g_strdup (nick);
|
||||||
query->description = g_strdup (description);
|
query->description = g_strdup (description);
|
||||||
|
|
||||||
|
g_static_mutex_lock (&mutex);
|
||||||
g_hash_table_insert (_nick_to_query, query->nick, query);
|
g_hash_table_insert (_nick_to_query, query->nick, query);
|
||||||
g_hash_table_insert (_query_type_to_nick, GINT_TO_POINTER (query->value),
|
g_hash_table_insert (_query_type_to_nick, GINT_TO_POINTER (query->value),
|
||||||
query);
|
query);
|
||||||
_gst_queries = g_list_append (_gst_queries, query);
|
_gst_queries = g_list_append (_gst_queries, query);
|
||||||
_n_values++;
|
_n_values++;
|
||||||
|
g_static_mutex_unlock (&mutex);
|
||||||
|
|
||||||
return query->value;
|
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_return_val_if_fail (nick != NULL, 0);
|
||||||
|
|
||||||
|
g_static_mutex_lock (&mutex);
|
||||||
query = g_hash_table_lookup (_nick_to_query, nick);
|
query = g_hash_table_lookup (_nick_to_query, nick);
|
||||||
|
g_static_mutex_unlock (&mutex);
|
||||||
|
|
||||||
if (query != NULL)
|
if (query != NULL)
|
||||||
return query->value;
|
return query->value;
|
||||||
|
@ -160,18 +168,32 @@ gst_query_types_contains (const GstQueryType * types, GstQueryType type)
|
||||||
const GstQueryTypeDefinition *
|
const GstQueryTypeDefinition *
|
||||||
gst_query_type_get_details (GstQueryType type)
|
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 *
|
GstIterator *
|
||||||
gst_query_type_get_definitions (void)
|
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
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||||
|
* 2005 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstquery.h: GstQuery API declaration
|
* gstquery.h: GstQuery API declaration
|
||||||
*
|
*
|
||||||
|
@ -26,6 +27,8 @@
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <gst/gstiterator.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -87,8 +90,8 @@ gboolean gst_query_types_contains (const GstQueryType *types, GstQ
|
||||||
|
|
||||||
/* query for query details */
|
/* query for query details */
|
||||||
G_CONST_RETURN GstQueryTypeDefinition*
|
G_CONST_RETURN GstQueryTypeDefinition*
|
||||||
gst_query_type_get_details (GstQueryType type);
|
gst_query_type_get_details (GstQueryType type);
|
||||||
G_CONST_RETURN GList* gst_query_type_get_definitions (void);
|
GstIterator* gst_query_type_iterate_definitions (void);
|
||||||
|
|
||||||
G_END_DECLS
|
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 GstFlowReturn gst_queue_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static GstBuffer *gst_queue_bufferalloc (GstPad * pad, guint64 offset,
|
static GstBuffer *gst_queue_bufferalloc (GstPad * pad, guint64 offset,
|
||||||
guint size, GstCaps * caps);
|
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);
|
static gboolean gst_queue_handle_sink_event (GstPad * pad, GstEvent * event);
|
||||||
|
|
||||||
|
@ -644,7 +644,7 @@ out_unref:
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_queue_loop (GstPad * pad)
|
gst_queue_loop (GstPad * pad)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
|
@ -697,6 +697,7 @@ restart:
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
} else {
|
} else {
|
||||||
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) {
|
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) {
|
||||||
|
gst_task_pause (queue->task);
|
||||||
result = FALSE;
|
result = FALSE;
|
||||||
}
|
}
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
@ -711,8 +712,6 @@ restart:
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
||||||
g_cond_signal (queue->item_del);
|
g_cond_signal (queue->item_del);
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* 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
|
* gstsystemclock.c: Default clock, uses the system clock
|
||||||
*
|
*
|
||||||
|
@ -20,13 +20,12 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
|
|
||||||
#include "gstsystemclock.h"
|
#include "gstsystemclock.h"
|
||||||
|
|
||||||
|
/* the one instance of the systemclock */
|
||||||
static GstClock *_the_system_clock = NULL;
|
static GstClock *_the_system_clock = NULL;
|
||||||
|
|
||||||
static void gst_system_clock_class_init (GstSystemClockClass * klass);
|
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 GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
|
||||||
static guint64 gst_system_clock_get_resolution (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);
|
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;
|
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_internal_time = gst_system_clock_get_internal_time;
|
||||||
gstclock_class->get_resolution = gst_system_clock_get_resolution;
|
gstclock_class->get_resolution = gst_system_clock_get_resolution;
|
||||||
gstclock_class->wait = gst_system_clock_wait;
|
gstclock_class->wait = gst_system_clock_id_wait;
|
||||||
gstclock_class->unlock = gst_system_clock_unlock;
|
gstclock_class->wait_async = gst_system_clock_id_wait_async;
|
||||||
|
gstclock_class->unschedule = gst_system_clock_id_unschedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_system_clock_init (GstSystemClock * clock)
|
gst_system_clock_init (GstSystemClock * clock)
|
||||||
{
|
{
|
||||||
clock->mutex = g_mutex_new ();
|
GError *error = NULL;
|
||||||
clock->cond = g_cond_new ();
|
|
||||||
|
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
|
static void
|
||||||
gst_system_clock_dispose (GObject * object)
|
gst_system_clock_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
GstClock *clock = (GstClock *) object;
|
GstClock *clock = (GstClock *) object;
|
||||||
GstSystemClock *sysclock = (GstSystemClock *) object;
|
|
||||||
|
|
||||||
/* there are subclasses of GstSystemClock running around... */
|
/* there are subclasses of GstSystemClock running around... */
|
||||||
if (_the_system_clock == clock) {
|
if (_the_system_clock == clock) {
|
||||||
|
@ -111,19 +135,19 @@ gst_system_clock_dispose (GObject * object)
|
||||||
/* no parent dispose here, this is bad enough already */
|
/* no parent dispose here, this is bad enough already */
|
||||||
} else {
|
} else {
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
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
|
* 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.
|
* Returns: the default clock.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstClock *
|
GstClock *
|
||||||
gst_system_clock_obtain (void)
|
gst_system_clock_obtain (void)
|
||||||
|
@ -164,6 +188,95 @@ have_clock:
|
||||||
return 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
|
static GstClockTime
|
||||||
gst_system_clock_get_internal_time (GstClock * clock)
|
gst_system_clock_get_internal_time (GstClock * clock)
|
||||||
{
|
{
|
||||||
|
@ -180,23 +293,36 @@ gst_system_clock_get_resolution (GstClock * clock)
|
||||||
return 1 * GST_USECOND;
|
return 1 * GST_USECOND;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstClockEntryStatus
|
/* synchronously wait on the given GstClockEntry.
|
||||||
gst_system_clock_wait (GstClock * clock, GstClockEntry * entry)
|
*
|
||||||
|
* 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;
|
GstClockTime current, target;
|
||||||
gint64 diff;
|
gint64 diff;
|
||||||
GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
|
|
||||||
|
|
||||||
current = gst_clock_get_time (clock);
|
current = gst_clock_get_time (clock);
|
||||||
diff = GST_CLOCK_ENTRY_TIME (entry) - current;
|
diff = GST_CLOCK_ENTRY_TIME (entry) - current;
|
||||||
|
|
||||||
target = GST_CLOCK_ENTRY_TIME (entry);
|
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
|
" target %" GST_TIME_FORMAT
|
||||||
" now %" GST_TIME_FORMAT
|
" now %" GST_TIME_FORMAT
|
||||||
" diff %" G_GINT64_FORMAT,
|
" diff %" G_GINT64_FORMAT,
|
||||||
|
entry,
|
||||||
GST_TIME_ARGS (target),
|
GST_TIME_ARGS (target),
|
||||||
GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)),
|
GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)),
|
||||||
GST_TIME_ARGS (current), diff);
|
GST_TIME_ARGS (current), diff);
|
||||||
|
@ -205,23 +331,77 @@ gst_system_clock_wait (GstClock * clock, GstClockEntry * entry)
|
||||||
GTimeVal tv;
|
GTimeVal tv;
|
||||||
|
|
||||||
GST_TIME_TO_TIMEVAL (target, 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 {
|
} else {
|
||||||
res = GST_CLOCK_ENTRY_EARLY;
|
entry->status = GST_CLOCK_EARLY;
|
||||||
}
|
}
|
||||||
return res;
|
return entry->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/* Add an entry to the list of pending async waits. The entry is inserted
|
||||||
gst_system_clock_unlock (GstClock * clock, GstClockEntry * entry)
|
* 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);
|
GST_LOCK (clock);
|
||||||
g_cond_broadcast (sysclock->cond);
|
/* need to take a ref */
|
||||||
g_mutex_unlock (sysclock->mutex);
|
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 {
|
struct _GstSystemClock {
|
||||||
GstClock clock;
|
GstClock clock;
|
||||||
|
|
||||||
GMutex * mutex;
|
/*< private >*/
|
||||||
GCond * cond;
|
GThread *thread; /* thread for async notify */
|
||||||
|
gboolean stopping;
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
@ -51,6 +52,7 @@ struct _GstSystemClock {
|
||||||
struct _GstSystemClockClass {
|
struct _GstSystemClockClass {
|
||||||
GstClockClass parent_class;
|
GstClockClass parent_class;
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* 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
|
* gsttask.c: Streaming tasks
|
||||||
*
|
*
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
#include "gsttask.h"
|
#include "gsttask.h"
|
||||||
|
|
||||||
static void gst_task_class_init (GstTaskClass * klass);
|
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 void gst_task_dispose (GObject * object);
|
||||||
|
|
||||||
static GstObjectClass *parent_class = NULL;
|
static GstObjectClass *parent_class = NULL;
|
||||||
|
@ -70,8 +70,10 @@ gst_task_class_init (GstTaskClass * klass)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_task_init (GstTask * sched)
|
gst_task_init (GstTask * task)
|
||||||
{
|
{
|
||||||
|
task->cond = g_cond_new ();
|
||||||
|
task->state = GST_TASK_STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -79,19 +81,73 @@ gst_task_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
GstTask *task = GST_TASK (object);
|
GstTask *task = GST_TASK (object);
|
||||||
|
|
||||||
/* thse lists should all be NULL */
|
|
||||||
GST_DEBUG ("task %p dispose", task);
|
GST_DEBUG ("task %p dispose", task);
|
||||||
|
|
||||||
|
g_cond_free (task->cond);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
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
|
gboolean
|
||||||
gst_task_start (GstTask * task)
|
gst_task_start (GstTask * task)
|
||||||
{
|
{
|
||||||
GstTaskClass *tclass;
|
GstTaskClass *tclass;
|
||||||
gboolean result = FALSE;
|
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);
|
tclass = GST_TASK_GET_CLASS (task);
|
||||||
|
|
||||||
|
@ -101,13 +157,23 @@ gst_task_start (GstTask * task)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_task_stop:
|
||||||
|
* @task: The #GstTask to stop
|
||||||
|
*
|
||||||
|
* Stops @task.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the task could be stopped.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_task_stop (GstTask * task)
|
gst_task_stop (GstTask * task)
|
||||||
{
|
{
|
||||||
GstTaskClass *tclass;
|
GstTaskClass *tclass;
|
||||||
gboolean result = FALSE;
|
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);
|
tclass = GST_TASK_GET_CLASS (task);
|
||||||
|
|
||||||
|
@ -117,13 +183,23 @@ gst_task_stop (GstTask * task)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_task_pause:
|
||||||
|
* @task: The #GstTask to pause
|
||||||
|
*
|
||||||
|
* Pauses @task.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the task could be paused.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_task_pause (GstTask * task)
|
gst_task_pause (GstTask * task)
|
||||||
{
|
{
|
||||||
GstTaskClass *tclass;
|
GstTaskClass *tclass;
|
||||||
gboolean result = FALSE;
|
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);
|
tclass = GST_TASK_GET_CLASS (task);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -25,7 +27,7 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef gboolean (*GstTaskFunction) (void *data);
|
typedef void (*GstTaskFunction) (void *data);
|
||||||
|
|
||||||
/* --- standard type macros --- */
|
/* --- standard type macros --- */
|
||||||
#define GST_TYPE_TASK (gst_task_get_type ())
|
#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_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_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_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 _GstTask GstTask;
|
||||||
typedef struct _GstTaskClass GstTaskClass;
|
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 {
|
struct _GstTask {
|
||||||
GstObject object;
|
GstObject object;
|
||||||
|
|
||||||
|
/*< public >*/ /* with LOCK */
|
||||||
|
GstTaskState state;
|
||||||
|
GCond *cond;
|
||||||
|
|
||||||
|
GstTaskFunction func;
|
||||||
|
gpointer data;
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstTaskClass {
|
struct _GstTaskClass {
|
||||||
GstObjectClass parent_class;
|
GstObjectClass parent_class;
|
||||||
|
|
||||||
|
/*< protected >*/
|
||||||
gboolean (*start) (GstTask *task);
|
gboolean (*start) (GstTask *task);
|
||||||
gboolean (*stop) (GstTask *task);
|
gboolean (*stop) (GstTask *task);
|
||||||
gboolean (*pause) (GstTask *task);
|
gboolean (*pause) (GstTask *task);
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_task_get_type (void);
|
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_start (GstTask *task);
|
||||||
gboolean gst_task_stop (GstTask *task);
|
gboolean gst_task_stop (GstTask *task);
|
||||||
gboolean gst_task_pause (GstTask *task);
|
gboolean gst_task_pause (GstTask *task);
|
||||||
|
|
|
@ -124,6 +124,7 @@ gst_trash_stack_pop (GstTrashStack *stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
#warning "using fallback trashstack implementation, performance may suffer"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generic implementation
|
* generic implementation
|
||||||
|
|
|
@ -76,30 +76,14 @@ struct _GstThreadSchedulerClass
|
||||||
typedef struct _GstThreadSchedulerTask GstThreadSchedulerTask;
|
typedef struct _GstThreadSchedulerTask GstThreadSchedulerTask;
|
||||||
typedef struct _GstThreadSchedulerTaskClass GstThreadSchedulerTaskClass;
|
typedef struct _GstThreadSchedulerTaskClass GstThreadSchedulerTaskClass;
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
STATE_STOPPED,
|
|
||||||
STATE_STARTED,
|
|
||||||
STATE_PAUSED
|
|
||||||
} TaskState;
|
|
||||||
|
|
||||||
|
|
||||||
struct _GstThreadSchedulerTask
|
struct _GstThreadSchedulerTask
|
||||||
{
|
{
|
||||||
GstTask task;
|
GstTask task;
|
||||||
|
|
||||||
TaskState state;
|
|
||||||
GMutex *lock;
|
|
||||||
GCond *cond;
|
|
||||||
|
|
||||||
GstTaskFunction func;
|
|
||||||
gpointer data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstThreadSchedulerTaskClass
|
struct _GstThreadSchedulerTaskClass
|
||||||
{
|
{
|
||||||
GstTaskClass parent_class;
|
GstTaskClass parent_class;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_thread_scheduler_task_class_init (gpointer g_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
|
static void
|
||||||
gst_thread_scheduler_task_init (GstThreadSchedulerTask * task)
|
gst_thread_scheduler_task_init (GstThreadSchedulerTask * task)
|
||||||
{
|
{
|
||||||
task->state = STATE_STOPPED;
|
GST_TASK (task)->state = GST_TASK_STOPPED;
|
||||||
task->lock = g_mutex_new ();
|
|
||||||
task->cond = g_cond_new ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -158,17 +140,23 @@ gst_thread_scheduler_task_start (GstTask * task)
|
||||||
{
|
{
|
||||||
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
|
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
|
||||||
GstThreadScheduler *tsched =
|
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);
|
GST_LOCK (ttask);
|
||||||
if (ttask->state == STATE_STOPPED) {
|
old = GST_TASK_CAST (ttask)->state;
|
||||||
ttask->state = STATE_STARTED;
|
GST_TASK_CAST (ttask)->state = GST_TASK_STARTED;
|
||||||
g_thread_pool_push (tsched->pool, task, NULL);
|
switch (old) {
|
||||||
} else {
|
case GST_TASK_STOPPED:
|
||||||
ttask->state = STATE_STARTED;
|
g_thread_pool_push (tsched->pool, task, NULL);
|
||||||
g_cond_signal (ttask->cond);
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -177,13 +165,22 @@ static gboolean
|
||||||
gst_thread_scheduler_task_stop (GstTask * task)
|
gst_thread_scheduler_task_stop (GstTask * task)
|
||||||
{
|
{
|
||||||
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
|
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
|
||||||
|
GstTaskState old;
|
||||||
|
|
||||||
g_mutex_lock (ttask->lock);
|
GST_LOCK (ttask);
|
||||||
if (ttask->state != STATE_STOPPED) {
|
old = GST_TASK_CAST (ttask)->state;
|
||||||
ttask->state = STATE_STOPPED;
|
GST_TASK_CAST (ttask)->state = GST_TASK_STOPPED;
|
||||||
g_cond_signal (ttask->cond);
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,12 +188,24 @@ static gboolean
|
||||||
gst_thread_scheduler_task_pause (GstTask * task)
|
gst_thread_scheduler_task_pause (GstTask * task)
|
||||||
{
|
{
|
||||||
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (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);
|
GST_LOCK (ttask);
|
||||||
if (ttask->state != STATE_PAUSED) {
|
old = GST_TASK_CAST (ttask)->state;
|
||||||
ttask->state = STATE_PAUSED;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,32 +262,35 @@ gst_thread_scheduler_class_init (gpointer klass, gpointer class_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_thread_scheduler_func (GstThreadSchedulerTask * task,
|
gst_thread_scheduler_func (GstThreadSchedulerTask * ttask,
|
||||||
GstThreadScheduler * sched)
|
GstThreadScheduler * sched)
|
||||||
{
|
{
|
||||||
gboolean res;
|
GstTask *task = GST_TASK (ttask);
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (task));
|
gst_object_ref (GST_OBJECT (task));
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (sched, "Entering task %p, thread %p", task,
|
GST_DEBUG_OBJECT (sched, "Entering task %p, thread %p", task,
|
||||||
g_thread_self ());
|
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);
|
GST_LOCK (task);
|
||||||
|
while (G_LIKELY (task->state != GST_TASK_STOPPED)) {
|
||||||
g_mutex_lock (task->lock);
|
while (G_UNLIKELY (task->state == GST_TASK_PAUSED)) {
|
||||||
if (G_UNLIKELY (!res)) {
|
GST_TASK_SIGNAL (task);
|
||||||
task->state = STATE_STOPPED;
|
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_DEBUG_OBJECT (sched, "Exit task %p, thread %p", task, g_thread_self ());
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (task));
|
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,
|
GST_THREAD_SCHEDULER_TASK (g_object_new (GST_TYPE_THREAD_SCHEDULER_TASK,
|
||||||
NULL));
|
NULL));
|
||||||
gst_object_set_parent (GST_OBJECT (task), GST_OBJECT (sched));
|
gst_object_set_parent (GST_OBJECT (task), GST_OBJECT (sched));
|
||||||
task->func = func;
|
GST_TASK_CAST (task)->func = func;
|
||||||
task->data = data;
|
GST_TASK_CAST (task)->data = data;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (sched, "Created task %p", task);
|
GST_DEBUG_OBJECT (sched, "Created task %p", task);
|
||||||
|
|
||||||
return GST_TASK (task);
|
return GST_TASK_CAST (task);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 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 };
|
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
@ -778,13 +778,12 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_fakesrc_loop (GstPad * pad)
|
gst_fakesrc_loop (GstPad * pad)
|
||||||
{
|
{
|
||||||
GstFakeSrc *src;
|
GstFakeSrc *src;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
GstClockTime time;
|
GstClockTime time;
|
||||||
gboolean result = TRUE;
|
|
||||||
|
|
||||||
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
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));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||||
} else {
|
} else {
|
||||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
result = FALSE;
|
gst_task_pause (src->task);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->rt_num_buffers == 0) {
|
if (src->rt_num_buffers == 0) {
|
||||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
result = FALSE;
|
gst_task_pause (src->task);
|
||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
if (src->rt_num_buffers > 0)
|
if (src->rt_num_buffers > 0)
|
||||||
|
@ -816,7 +815,7 @@ gst_fakesrc_loop (GstPad * pad)
|
||||||
if (src->eos) {
|
if (src->eos) {
|
||||||
GST_INFO ("fakesrc is setting eos on pad");
|
GST_INFO ("fakesrc is setting eos on pad");
|
||||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
result = FALSE;
|
gst_task_pause (src->task);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,8 +859,6 @@ gst_fakesrc_loop (GstPad * pad)
|
||||||
|
|
||||||
done:
|
done:
|
||||||
GST_STREAM_UNLOCK (pad);
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -881,7 +881,7 @@ gst_filesrc_close_file (GstFileSrc * src)
|
||||||
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_filesrc_loop (GstElement * element)
|
gst_filesrc_loop (GstElement * element)
|
||||||
{
|
{
|
||||||
GstFileSrc *filesrc;
|
GstFileSrc *filesrc;
|
||||||
|
@ -892,14 +892,13 @@ gst_filesrc_loop (GstElement * element)
|
||||||
|
|
||||||
result = gst_filesrc_get (filesrc->srcpad, &buffer);
|
result = gst_filesrc_get (filesrc->srcpad, &buffer);
|
||||||
if (result != GST_FLOW_OK) {
|
if (result != GST_FLOW_OK) {
|
||||||
return FALSE;
|
gst_task_stop (filesrc->task);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
result = gst_pad_push (filesrc->srcpad, buffer);
|
result = gst_pad_push (filesrc->srcpad, buffer);
|
||||||
if (result != GST_FLOW_OK) {
|
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 GstFlowReturn gst_queue_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static GstBuffer *gst_queue_bufferalloc (GstPad * pad, guint64 offset,
|
static GstBuffer *gst_queue_bufferalloc (GstPad * pad, guint64 offset,
|
||||||
guint size, GstCaps * caps);
|
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);
|
static gboolean gst_queue_handle_sink_event (GstPad * pad, GstEvent * event);
|
||||||
|
|
||||||
|
@ -644,7 +644,7 @@ out_unref:
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_queue_loop (GstPad * pad)
|
gst_queue_loop (GstPad * pad)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
|
@ -697,6 +697,7 @@ restart:
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
} else {
|
} else {
|
||||||
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) {
|
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) {
|
||||||
|
gst_task_pause (queue->task);
|
||||||
result = FALSE;
|
result = FALSE;
|
||||||
}
|
}
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
@ -711,8 +712,6 @@ restart:
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
||||||
g_cond_signal (queue->item_del);
|
g_cond_signal (queue->item_del);
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
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
|
clock1
|
||||||
clock2
|
clock2
|
||||||
|
clock3
|
||||||
signedness
|
signedness
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
include ../Rules
|
include ../Rules
|
||||||
|
|
||||||
tests_pass = signedness clock1 clock2
|
tests_pass = signedness clock1 clock2 clock3
|
||||||
tests_fail =
|
tests_fail =
|
||||||
tests_ignore =
|
tests_ignore =
|
||||||
|
|
|
@ -43,13 +43,12 @@ main (int argc, char *argv[])
|
||||||
gst_bin_add_many (GST_BIN (pipeline), src, id, sink, NULL);
|
gst_bin_add_many (GST_BIN (pipeline), src, id, sink, NULL);
|
||||||
gst_element_link_many (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);
|
g_assert (clock != NULL);
|
||||||
gst_clock_debug (clock);
|
gst_clock_debug (clock);
|
||||||
gst_clock_debug (clock);
|
gst_clock_debug (clock);
|
||||||
|
|
||||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
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);
|
gst_clock_debug (clock);
|
||||||
gst_clock_debug (clock);
|
gst_clock_debug (clock);
|
||||||
|
|
|
@ -7,18 +7,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
static GstClock *clock = NULL;
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_clock_debug (GstClock * clock, GstElement * fakesink)
|
gst_clock_debug (GstClock * clock, GstElement * fakesink)
|
||||||
{
|
{
|
||||||
g_print ("Clock info: time %" G_GUINT64_FORMAT " - Element info: time %"
|
GstClockTime time;
|
||||||
G_GUINT64_FORMAT "\n", gst_clock_get_time (clock),
|
|
||||||
gst_element_get_time (fakesink));
|
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
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
GstClock *clock = NULL;
|
|
||||||
GstElement *pipeline, *fakesrc, *fakesink;
|
GstElement *pipeline, *fakesrc, *fakesink;
|
||||||
|
|
||||||
gst_init (&argc, &argv);
|
gst_init (&argc, &argv);
|
||||||
|
@ -41,10 +56,10 @@ main (int argc, char *argv[])
|
||||||
g_usleep (G_USEC_PER_SEC);
|
g_usleep (G_USEC_PER_SEC);
|
||||||
gst_clock_debug (clock, fakesink);
|
gst_clock_debug (clock, fakesink);
|
||||||
|
|
||||||
gst_element_wait (fakesink, 2 * GST_SECOND);
|
element_wait (fakesink, 2 * GST_SECOND);
|
||||||
gst_clock_debug (clock, fakesink);
|
gst_clock_debug (clock, fakesink);
|
||||||
|
|
||||||
gst_element_wait (fakesink, 5 * GST_SECOND);
|
element_wait (fakesink, 5 * GST_SECOND);
|
||||||
gst_clock_debug (clock, fakesink);
|
gst_clock_debug (clock, fakesink);
|
||||||
|
|
||||||
g_usleep (G_USEC_PER_SEC);
|
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
|
clock1
|
||||||
clock2
|
clock2
|
||||||
|
clock3
|
||||||
signedness
|
signedness
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
include ../Rules
|
include ../Rules
|
||||||
|
|
||||||
tests_pass = signedness clock1 clock2
|
tests_pass = signedness clock1 clock2 clock3
|
||||||
tests_fail =
|
tests_fail =
|
||||||
tests_ignore =
|
tests_ignore =
|
||||||
|
|
|
@ -43,13 +43,12 @@ main (int argc, char *argv[])
|
||||||
gst_bin_add_many (GST_BIN (pipeline), src, id, sink, NULL);
|
gst_bin_add_many (GST_BIN (pipeline), src, id, sink, NULL);
|
||||||
gst_element_link_many (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);
|
g_assert (clock != NULL);
|
||||||
gst_clock_debug (clock);
|
gst_clock_debug (clock);
|
||||||
gst_clock_debug (clock);
|
gst_clock_debug (clock);
|
||||||
|
|
||||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
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);
|
gst_clock_debug (clock);
|
||||||
gst_clock_debug (clock);
|
gst_clock_debug (clock);
|
||||||
|
|
|
@ -7,18 +7,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
static GstClock *clock = NULL;
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_clock_debug (GstClock * clock, GstElement * fakesink)
|
gst_clock_debug (GstClock * clock, GstElement * fakesink)
|
||||||
{
|
{
|
||||||
g_print ("Clock info: time %" G_GUINT64_FORMAT " - Element info: time %"
|
GstClockTime time;
|
||||||
G_GUINT64_FORMAT "\n", gst_clock_get_time (clock),
|
|
||||||
gst_element_get_time (fakesink));
|
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
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
GstClock *clock = NULL;
|
|
||||||
GstElement *pipeline, *fakesrc, *fakesink;
|
GstElement *pipeline, *fakesrc, *fakesink;
|
||||||
|
|
||||||
gst_init (&argc, &argv);
|
gst_init (&argc, &argv);
|
||||||
|
@ -41,10 +56,10 @@ main (int argc, char *argv[])
|
||||||
g_usleep (G_USEC_PER_SEC);
|
g_usleep (G_USEC_PER_SEC);
|
||||||
gst_clock_debug (clock, fakesink);
|
gst_clock_debug (clock, fakesink);
|
||||||
|
|
||||||
gst_element_wait (fakesink, 2 * GST_SECOND);
|
element_wait (fakesink, 2 * GST_SECOND);
|
||||||
gst_clock_debug (clock, fakesink);
|
gst_clock_debug (clock, fakesink);
|
||||||
|
|
||||||
gst_element_wait (fakesink, 5 * GST_SECOND);
|
element_wait (fakesink, 5 * GST_SECOND);
|
||||||
gst_clock_debug (clock, fakesink);
|
gst_clock_debug (clock, fakesink);
|
||||||
|
|
||||||
g_usleep (G_USEC_PER_SEC);
|
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