Doc updates.

Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* docs/design/part-clocks.txt:
* docs/design/part-gstelement.txt:
* docs/design/part-gstobject.txt:
* docs/design/part-standards.txt:
* gst/gstbin.c: (gst_bin_add_func), (gst_bin_add),
(gst_bin_remove_func), (gst_bin_remove):
* gst/gstbin.h:
* gst/gstbuffer.c:
* gst/gstcaps.h:
* testsuite/clock/clock1.c: (main):
* testsuite/clock/clock2.c: (gst_clock_debug), (element_wait),
(main):
* testsuite/dlopen/loadgst.c: (do_test):
* testsuite/refcounting/bin.c: (add_remove_test1),
(add_remove_test2), (main):
* testsuite/refcounting/element.c: (main):
* testsuite/refcounting/element_pad.c: (main):
* testsuite/refcounting/pad.c: (main):
* tools/gst-launch.c: (sigint_handler_sighandler):
* tools/gst-typefind.c: (main):
Doc updates.
Added doc about clock.
removed gst_bin_iterate_recurse_up(), marked methods
for removal.
Fix more testsuites.
This commit is contained in:
Wim Taymans 2005-03-10 12:51:45 +00:00
parent e82e7b604a
commit 007cff6d75
26 changed files with 334 additions and 100 deletions

View file

@ -1,3 +1,32 @@
2005-03-10 Wim Taymans <wim@fluendo.com>
* docs/design/part-MT-refcounting.txt:
* docs/design/part-clocks.txt:
* docs/design/part-gstelement.txt:
* docs/design/part-gstobject.txt:
* docs/design/part-standards.txt:
* gst/gstbin.c: (gst_bin_add_func), (gst_bin_add),
(gst_bin_remove_func), (gst_bin_remove):
* gst/gstbin.h:
* gst/gstbuffer.c:
* gst/gstcaps.h:
* testsuite/clock/clock1.c: (main):
* testsuite/clock/clock2.c: (gst_clock_debug), (element_wait),
(main):
* testsuite/dlopen/loadgst.c: (do_test):
* testsuite/refcounting/bin.c: (add_remove_test1),
(add_remove_test2), (main):
* testsuite/refcounting/element.c: (main):
* testsuite/refcounting/element_pad.c: (main):
* testsuite/refcounting/pad.c: (main):
* tools/gst-launch.c: (sigint_handler_sighandler):
* tools/gst-typefind.c: (main):
Doc updates.
Added doc about clock.
removed gst_bin_iterate_recurse_up(), marked methods
for removal.
Fix more testsuites.
2005-03-09 Wim Taymans <wim@fluendo.com>
* gst/gstpad.c: (gst_pad_get_direction),

View file

@ -123,6 +123,15 @@ Atomic operations
Atomic operations are generally used for refcounting and for the allocation of
small fixed size objects in a memchunk. They can also be used to implement a
lockfree list or stack.
Compare and swap
As part of the atomic operations, compare-and-swap (CAS) can be used to access
or update a single property or pointer in an object without having to take a
lock.
This technique is currently not used in GStreamer but might be added in the
future in performance critical places.
Objects

106
docs/design/part-clocks.txt Normal file
View file

@ -0,0 +1,106 @@
Clocks
------
To synchronize the different elements, the GstPipeline is responsible for
selecting and distributing a global GstClock for all the elements in it.
This selection happens whenever an element is added or removed from the
pipeline. Whever the clock changes in a pipeline, a message is posted on
the bus signaling the new clock to the application.
The GstClock returns a monotonically increasing time with the method
_get_time(). Its accuracy and base time depends on the specific clock
implementation but time is always expessed in nanoseconds. Since the
baseline of the clock is undefined, the clock time returned is not
meaningfull in itself, what matters are the deltas between two clock
times.
The time reported by the clock is called the absolute time.
Time in GStreamer
-----------------
The absolute time is used to calculate the stream time. The stream time
is defined as follows:
- If the pipeline is NULL/READY, the stream time is undefined.
- In PAUSED, the stream time remains at the time when it was last
PAUSED. When the stream is PAUSED for the first time, the stream time
is 0.
- In PLAYING, the stream time is the delta between the absolute time
and the base time. The base time is defined as the absolute time minus
the stream time at the time when the pipeline is set to PLAYING.
- after a seek, the stream time is set to seek time.
The stream time is completely managed by the GstPipeline object using the
GstClock absolute time.
Timestamps
----------
Timestamps on buffers are always expressed in stream time. This means that
all elements that require synchronizing to the clock need to be aware of
the clock base time in order to know the absolute time of the timestamp.
Converting a timestamp (in stream time) to absolute time is performed using
the following formula:
AT = BT + ST where: AT = absolute time
BT = base time
ST = stream time
The pipeline base time is propagated to all the element during the PAUSED
to PLAYING state change. All elements are therefore able to convert the
stream time to the absolute time. It is possible to specify an aditional
delay to the base time to compensate for the delay it takes to perform
the state change.
Clock features
--------------
The clock supports periodic and single shot clock notifications both
synchronous and asynchronous.
One first needs to create a GstClockID for the periodic or single shot
notification using _clock_new_single_shot_id() or _clock_new_periodic_id().
To perform a blocking wait for the specific time of the GstClockID use the
gst_clock_id_wait(). To receive a callback when the specific time is reached
in the clock use gst_clock_id_wait_async(). Both these calls can be interrupted
with the gst_clock_id_unschedule() call. If the blocking wait is unscheduled
a return value of GST_CLOCK_UNSCHEDULED is returned.
The async callbacks can happen from any thread, either provided by the
core or from a streaming thread. The application should be prepared for this.
A GstClockID that has been unscheduled cannot be used again for any wait
operation.
It is possible to perform a blocking wait on the same ID from multiple
threads. However, registering the same ID for multiple async notifications is
not possible, the callback will only be called once.
None of the wait operations unref the GstClockID, the application is
responsible for unreffing the ids itself. This holds for both periodic and
single shot notifications.
These clock operations do not operate on the stream time, so the callbacks
will also occur when not in PLAYING state as if the clock just keeps on
running.
Clock implementations
---------------------
The GStreamer core provides a GstSystemClock based on the system time.
Asynchronous callbacks are scheduled from an internal thread.
Clock implementors are encouraged to subclass this systemclock as it
implements the async notification.
Subclasses can however override all of the important methods for sync and
async notifications to implement their own callback methods or blocking
wait operations.

View file

@ -10,15 +10,20 @@
GstElement
==========
The Element is the most important object in the entire GStreamer system, as it defines the structure of the pipeline.
Elements include sources, filters, sinks, and containers (Bins). They may be an intrinsic part of the core GStreamer
library, or may be loaded from a plugin. In some cases they're even fabricated from completely different systems (see
the LADSPA plugin). They are generally created from a GstElementFactory, which will be covered in another chapter, but
for the intrinsic types they can be created with specific functions.
The Element is the most important object in the entire GStreamer system, as it
defines the structure of the pipeline. Elements include sources, filters,
sinks, and containers (Bins). They may be an intrinsic part of the core
GStreamer library, or may be loaded from a plugin. In some cases they're even
fabricated from completely different systems (see the LADSPA plugin). They
are generally created from a GstElementFactory, which will be covered in
another chapter, but for the intrinsic types they can be created with specific
functions.
Elements contains GstPads (also covered in another chapter), which are subsequently used to connect the Elements
together to form a pipeline capable of passing and processing data. They have a parent, which must be another Element.
This allows deeply nested pipelines, and the possibility of "black-box" meta-elements.
Elements contains GstPads (also covered in another chapter), which are
subsequently used to connect the Elements together to form a pipeline capable
of passing and processing data. They have a parent, which must be another
Element. This allows deeply nested pipelines, and the possibility of
"black-box" meta-elements.
Name
----

View file

@ -50,6 +50,9 @@ The GstObject contains the necessary primitives to lock the object in a
thread-safe manner. This will be used to provide general thread-safety as
needed. However, this lock is generic, i.e. it covers the whole object.
The object LOCK is a very lowlevel lock that should only be held to access
the object properties for short periods of code.
All members of the GstObject structure marked as
/*< public >*/ /* with LOCK */
are protected by this lock. These members can only be accessed for reading
@ -66,6 +69,20 @@ reasonable, since they are the only possible things to protect in the
GstObject.
Locking order
-------------
In parent-child situations the lock of the parent must always be taken first
before taking the lock of the child. It is NOT allowed to hold the child
lock before taking the parent lock.
This policy allows for parents to iterate their children and setting properties
on them.
Whenever a nested lock needs to be taken on objects not involved in a
parent-child relation (eg. pads), an explictic locking order has to be defined.
Path Generation
---------------

View file

@ -1,12 +1,54 @@
Ownership of dynamic objects
----------------------------
Any object-oriented system or language that doesn't have automatic garbage collection has many potential pitfalls as
far as the pointers go. Therefore, some standards must be adhered to as far as who owns what.
Any object-oriented system or language that doesn't have automatic garbage
collection has many potential pitfalls as far as the pointers go. Therefore,
some standards must be adhered to as far as who owns what.
Strings:
Arguments passed into a function are owned by the caller, and the function will make a copy of the string for its own
internal use. The string should be const gchar *. Strings returned from a function are always a copy of the
Strings
-------
Arguments passed into a function are owned by the caller, and the function
will make a copy of the string for its own internal use. The string should
be const gchar *. Strings returned from a function are always a copy of the
original and should be freed after usage by the caller.
Objects:
ex:
name = gst_element_get_name (element); /* copy of name is made */
.. use name ..
g_free (name); /* free after usage */
Objects
-------
Objects passed into a function are owned by the caller, any additional
reference held to the object after leaving the function should increase the
refcount of that object.
Objects returned from a function are owned by the caller. This means that the
called should _free() or _unref() the object after usage.
ex:
peer = gst_pad_get_peer (pad); /* peer with increased refcount */
if (peer) {
.. use peer ..
gst_object_unref (GST_OBJECT (peer)); /* unref peer after usage */
}
Iterators
---------
When retrieving multiple objects from an object an iterator should be used.
The iterator allows you to access the objects one after another while making
sure that the set of objects retrieved remains consistent.
Each object retrieved from an iterator has its refcount increased or is a
copy of the original. In any case the object should be unreffed or freed
after usage.

View file

@ -300,6 +300,7 @@ gst_bin_get_clock_func (GstElement * element)
return result;
}
/* will be removed */
static void
gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
{
@ -359,6 +360,7 @@ gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
}
}
/* will be removed */
static void
gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
{
@ -452,8 +454,8 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
goto duplicate_name;
/* set the element's parent and add the element to the bin's list of children */
if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT (element),
GST_OBJECT (bin))))
if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT_CAST (element),
GST_OBJECT_CAST (bin))))
goto had_parent;
bin->children = g_list_prepend (bin->children, element);
@ -573,12 +575,12 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
/* we ref here because after the _unparent() the element can be disposed
* and we still need it to fire a signal. */
gst_object_ref (GST_OBJECT (element));
gst_object_unparent (GST_OBJECT (element));
gst_object_ref (GST_OBJECT_CAST (element));
gst_object_unparent (GST_OBJECT_CAST (element));
g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_REMOVED], 0, element);
/* element is really out of our control now */
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT_CAST (element));
return TRUE;
@ -731,12 +733,6 @@ gst_bin_iterate_recurse (GstBin * bin)
return result;
}
GstIterator *
gst_bin_iterate_recurse_up (GstBin * bin)
{
return NULL;
}
/* returns 0 if the element is a sink, this is made so that
* we can use this function as a filter
*
@ -820,6 +816,8 @@ bin_element_is_sink (GstElement * child, GstBin * bin)
* Each element will have its refcount increased, so unref
* after usage.
*
* The sink elements are those without any linked srcpads.
*
* Returns: a #GstIterator of #GstElements. gst_iterator_free after use.
*
* MT safe.
@ -848,6 +846,8 @@ gst_bin_iterate_sinks (GstBin * bin)
*
* An internal function to inform the parent bin about a state change
* of a child.
*
* Marked for removal.
*/
void
gst_bin_child_state_change (GstBin * bin, GstElementState oldstate,
@ -873,6 +873,7 @@ gst_bin_child_state_change (GstBin * bin, GstElementState oldstate,
}
}
/* will be removed */
static void
gst_bin_child_state_change_func (GstBin * bin, GstElementState oldstate,
GstElementState newstate, GstElement * child)
@ -937,6 +938,8 @@ typedef gboolean (*GstBinForeachFunc) (GstBin * bin, GstElement * element,
* called, and that are still in @bin when the child is reached.
*
* Returns: TRUE if @func always returned TRUE, FALSE otherwise
*
* Marked for removal.
**/
static gboolean
gst_bin_foreach (GstBin * bin, GstBinForeachFunc func, gpointer data)
@ -1283,6 +1286,7 @@ gst_bin_get_by_interface (GstBin * bin, GType interface)
*
* Returns: An iterator for the elements inside the bin implementing the interface.
*
* MT safe.
*/
GstIterator *
gst_bin_iterate_all_by_interface (GstBin * bin, GType interface)

View file

@ -129,7 +129,6 @@ GstElement* gst_bin_get_by_interface (GstBin *bin, GType interface);
/* retrieve multiple children */
GstIterator* gst_bin_iterate_elements (GstBin *bin);
GstIterator* gst_bin_iterate_recurse (GstBin *bin);
GstIterator* gst_bin_iterate_recurse_up (GstBin *bin);
GstIterator* gst_bin_iterate_sinks (GstBin *bin);
GstIterator* gst_bin_iterate_all_by_interface (GstBin *bin, GType interface);

View file

@ -271,7 +271,8 @@ gst_buffer_new_and_alloc (guint size)
* Returns: the #GstCaps, or NULL if there was an error or there
* were no caps on this buffer.
*/
/* FIXME can we make this threadsafe without a lock on the buffer? */
/* FIXME can we make this threadsafe without a lock on the buffer?
* We can use compare and swap and atomic reads. */
GstCaps *
gst_buffer_get_caps (GstBuffer * buffer)
{
@ -289,7 +290,10 @@ gst_buffer_get_caps (GstBuffer * buffer)
* be increased and any previous caps on the buffer will be
* unreffed.
*/
/* FIXME can we make this threadsafe without a lock on the buffer? */
/* FIXME can we make this threadsafe without a lock on the buffer?
* We can use compare and swap and atomic reads. Another idea is to
* not attach the caps to the buffer but use an event to signal a caps
* change. */
void
gst_buffer_set_caps (GstBuffer * buffer, GstCaps * caps)
{

View file

@ -148,13 +148,6 @@ void gst_caps_replace (GstCaps
gchar * gst_caps_to_string (const GstCaps *caps);
GstCaps * gst_caps_from_string (const gchar *string);
gboolean gst_caps_structure_fixate_field_nearest_int (GstStructure *structure,
const char *field_name,
int target);
gboolean gst_caps_structure_fixate_field_nearest_double (GstStructure *structure,
const char *field_name,
double target);
G_END_DECLS
#endif /* __GST_CAPS_H__ */

View file

@ -43,13 +43,12 @@ main (int argc, char *argv[])
gst_bin_add_many (GST_BIN (pipeline), src, id, sink, NULL);
gst_element_link_many (src, id, sink, NULL);
clock = gst_bin_get_clock (GST_BIN (pipeline));
clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
g_assert (clock != NULL);
gst_clock_debug (clock);
gst_clock_debug (clock);
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
gst_bin_iterate (GST_BIN (pipeline));
gst_clock_debug (clock);
gst_clock_debug (clock);
gst_clock_debug (clock);

View file

@ -7,12 +7,26 @@
*/
#include <gst/gst.h>
void
gst_clock_debug (GstClock * clock, GstElement * fakesink)
{
g_print ("Clock info: time %" G_GUINT64_FORMAT " - Element info: time %"
G_GUINT64_FORMAT "\n", gst_clock_get_time (clock),
gst_element_get_time (fakesink));
GstClockTime time;
time = gst_clock_get_time (clock);
g_print ("Clock info: time %" G_GUINT64_FORMAT " Element %" GST_TIME_FORMAT
"\n", time, GST_TIME_ARGS (time - fakesink->base_time));
}
static void
element_wait (GstElement * element, GstClockTime time)
{
GstClockID id;
id = gst_clock_new_single_shot_id (clock, time + element->base_time);
gst_clock_id_wait (id, NULL);
gst_clock_id_unref (id);
}
int
@ -41,10 +55,10 @@ main (int argc, char *argv[])
g_usleep (G_USEC_PER_SEC);
gst_clock_debug (clock, fakesink);
gst_element_wait (fakesink, 2 * GST_SECOND);
element_wait (fakesink, 2 * GST_SECOND);
gst_clock_debug (clock, fakesink);
gst_element_wait (fakesink, 5 * GST_SECOND);
element_wait (fakesink, 5 * GST_SECOND);
gst_clock_debug (clock, fakesink);
g_usleep (G_USEC_PER_SEC);

View file

@ -7,22 +7,20 @@ do_test (void)
{
GstElement *pipeline;
int i;
gboolean ret;
gst_init (NULL, NULL);
pipeline = gst_parse_launch ("fakesrc ! fakesink", NULL);
g_assert (pipeline != NULL);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
for (i = 0; i < 100; i++) {
ret = gst_bin_iterate (GST_BIN (pipeline));
g_assert (ret);
g_usleep (1000);
g_print ("%s", (i & 1) ? "+" : "-");
}
g_print ("\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
}

View file

@ -50,9 +50,9 @@ add_remove_test1 (void)
bin = gst_bin_new ("testbin");
element = gst_element_factory_make ("fakesrc", NULL);
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
g_assert (GST_OBJECT_IS_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_IS_FLOATING (element));
gst_bin_remove (GST_BIN (bin), element);
gst_object_unref (GST_OBJECT (bin));
@ -68,16 +68,16 @@ add_remove_test2 (void)
element = gst_element_factory_make ("fakesrc", NULL);
gst_element_set_name (element, "test1");
gst_object_ref (GST_OBJECT (element));
g_assert (GST_OBJECT_FLOATING (element));
g_assert (GST_OBJECT_IS_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_IS_FLOATING (element));
gst_bin_remove (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_DESTROYED (element));
g_assert (!GST_OBJECT_IS_FLOATING (element));
g_assert (!GST_OBJECT_IS_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
#if 0
g_assert (GST_OBJECT_DESTROYED (element));
g_assert (GST_OBJECT_IS_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
#endif
@ -169,10 +169,10 @@ main (int argc, gchar * argv[])
gst_alloc_trace_live_all () - usage1);
bin = gst_bin_new ("somebin");
g_assert (GST_OBJECT_FLOATING (bin));
g_assert (GST_OBJECT_IS_FLOATING (bin));
gst_object_ref (GST_OBJECT (bin));
gst_object_sink (GST_OBJECT (bin));
g_assert (!GST_OBJECT_FLOATING (bin));
g_assert (!GST_OBJECT_IS_FLOATING (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("create/ref/sink/unref new bin %d\n",
gst_alloc_trace_live_all () - usage1);
@ -188,10 +188,10 @@ main (int argc, gchar * argv[])
gst_alloc_trace_live_all () - usage1);
bin = gst_bin_new ("somebin");
g_assert (!GST_OBJECT_DESTROYED (bin));
g_assert (!GST_OBJECT_IS_DESTROYED (bin));
gst_object_unref (GST_OBJECT (bin));
#if 0
g_assert (GST_OBJECT_DESTROYED (bin));
g_assert (GST_OBJECT_IS_DESTROYED (bin));
gst_object_unref (GST_OBJECT (bin));
#endif
g_print ("create/destroy/unref new bin %d\n",

View file

@ -35,10 +35,10 @@ main (int argc, gchar * argv[])
gst_alloc_trace_live_all () - usage1);
element = gst_element_factory_make ("fakesrc", NULL);
g_assert (GST_OBJECT_FLOATING (element));
g_assert (GST_OBJECT_IS_FLOATING (element));
gst_object_ref (GST_OBJECT (element));
gst_object_sink (GST_OBJECT (element));
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_IS_FLOATING (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/ref/sink/unref new element %d\n",
gst_alloc_trace_live_all () - usage1);
@ -55,9 +55,9 @@ main (int argc, gchar * argv[])
#if 0
element = gst_element_factory_make ("fakesrc", NULL);
g_assert (!GST_OBJECT_DESTROYED (element));
g_assert (!GST_OBJECT_IS_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
g_assert (GST_OBJECT_IS_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/destroy/unref new element %d\n",
gst_alloc_trace_live_all () - usage1);

View file

@ -27,8 +27,8 @@ main (int argc, gchar * argv[])
g_assert (GST_IS_ELEMENT (element));
pad = gst_element_get_pad (element, "sink");
g_assert (GST_IS_PAD (pad));
g_assert (GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_FLOATING (pad));
g_assert (GST_OBJECT_IS_FLOATING (element));
g_assert (!GST_OBJECT_IS_FLOATING (pad));
g_assert (gst_pad_get_parent (pad) == element);
gst_object_unref (GST_OBJECT (element));
g_print ("create/addpad/unref 1 new element: %ld\n", vmsize () - usage1);

View file

@ -52,10 +52,10 @@ main (int argc, gchar * argv[])
pad =
gst_pad_new_from_template (gst_static_pad_template_get (&templ),
"padname");
g_assert (GST_OBJECT_FLOATING (pad));
g_assert (GST_OBJECT_IS_FLOATING (pad));
gst_object_ref (GST_OBJECT (pad));
gst_object_sink (GST_OBJECT (pad));
g_assert (!GST_OBJECT_FLOATING (pad));
g_assert (!GST_OBJECT_IS_FLOATING (pad));
gst_object_unref (GST_OBJECT (pad));
g_print ("create/ref/sink/unref new pad %ld\n", vmsize () - usage1);

View file

@ -43,13 +43,12 @@ main (int argc, char *argv[])
gst_bin_add_many (GST_BIN (pipeline), src, id, sink, NULL);
gst_element_link_many (src, id, sink, NULL);
clock = gst_bin_get_clock (GST_BIN (pipeline));
clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
g_assert (clock != NULL);
gst_clock_debug (clock);
gst_clock_debug (clock);
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
gst_bin_iterate (GST_BIN (pipeline));
gst_clock_debug (clock);
gst_clock_debug (clock);
gst_clock_debug (clock);

View file

@ -7,12 +7,26 @@
*/
#include <gst/gst.h>
void
gst_clock_debug (GstClock * clock, GstElement * fakesink)
{
g_print ("Clock info: time %" G_GUINT64_FORMAT " - Element info: time %"
G_GUINT64_FORMAT "\n", gst_clock_get_time (clock),
gst_element_get_time (fakesink));
GstClockTime time;
time = gst_clock_get_time (clock);
g_print ("Clock info: time %" G_GUINT64_FORMAT " Element %" GST_TIME_FORMAT
"\n", time, GST_TIME_ARGS (time - fakesink->base_time));
}
static void
element_wait (GstElement * element, GstClockTime time)
{
GstClockID id;
id = gst_clock_new_single_shot_id (clock, time + element->base_time);
gst_clock_id_wait (id, NULL);
gst_clock_id_unref (id);
}
int
@ -41,10 +55,10 @@ main (int argc, char *argv[])
g_usleep (G_USEC_PER_SEC);
gst_clock_debug (clock, fakesink);
gst_element_wait (fakesink, 2 * GST_SECOND);
element_wait (fakesink, 2 * GST_SECOND);
gst_clock_debug (clock, fakesink);
gst_element_wait (fakesink, 5 * GST_SECOND);
element_wait (fakesink, 5 * GST_SECOND);
gst_clock_debug (clock, fakesink);
g_usleep (G_USEC_PER_SEC);

View file

@ -7,22 +7,20 @@ do_test (void)
{
GstElement *pipeline;
int i;
gboolean ret;
gst_init (NULL, NULL);
pipeline = gst_parse_launch ("fakesrc ! fakesink", NULL);
g_assert (pipeline != NULL);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
for (i = 0; i < 100; i++) {
ret = gst_bin_iterate (GST_BIN (pipeline));
g_assert (ret);
g_usleep (1000);
g_print ("%s", (i & 1) ? "+" : "-");
}
g_print ("\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
}

View file

@ -50,9 +50,9 @@ add_remove_test1 (void)
bin = gst_bin_new ("testbin");
element = gst_element_factory_make ("fakesrc", NULL);
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
g_assert (GST_OBJECT_IS_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_IS_FLOATING (element));
gst_bin_remove (GST_BIN (bin), element);
gst_object_unref (GST_OBJECT (bin));
@ -68,16 +68,16 @@ add_remove_test2 (void)
element = gst_element_factory_make ("fakesrc", NULL);
gst_element_set_name (element, "test1");
gst_object_ref (GST_OBJECT (element));
g_assert (GST_OBJECT_FLOATING (element));
g_assert (GST_OBJECT_IS_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_IS_FLOATING (element));
gst_bin_remove (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_DESTROYED (element));
g_assert (!GST_OBJECT_IS_FLOATING (element));
g_assert (!GST_OBJECT_IS_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
#if 0
g_assert (GST_OBJECT_DESTROYED (element));
g_assert (GST_OBJECT_IS_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
#endif
@ -169,10 +169,10 @@ main (int argc, gchar * argv[])
gst_alloc_trace_live_all () - usage1);
bin = gst_bin_new ("somebin");
g_assert (GST_OBJECT_FLOATING (bin));
g_assert (GST_OBJECT_IS_FLOATING (bin));
gst_object_ref (GST_OBJECT (bin));
gst_object_sink (GST_OBJECT (bin));
g_assert (!GST_OBJECT_FLOATING (bin));
g_assert (!GST_OBJECT_IS_FLOATING (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("create/ref/sink/unref new bin %d\n",
gst_alloc_trace_live_all () - usage1);
@ -188,10 +188,10 @@ main (int argc, gchar * argv[])
gst_alloc_trace_live_all () - usage1);
bin = gst_bin_new ("somebin");
g_assert (!GST_OBJECT_DESTROYED (bin));
g_assert (!GST_OBJECT_IS_DESTROYED (bin));
gst_object_unref (GST_OBJECT (bin));
#if 0
g_assert (GST_OBJECT_DESTROYED (bin));
g_assert (GST_OBJECT_IS_DESTROYED (bin));
gst_object_unref (GST_OBJECT (bin));
#endif
g_print ("create/destroy/unref new bin %d\n",

View file

@ -35,10 +35,10 @@ main (int argc, gchar * argv[])
gst_alloc_trace_live_all () - usage1);
element = gst_element_factory_make ("fakesrc", NULL);
g_assert (GST_OBJECT_FLOATING (element));
g_assert (GST_OBJECT_IS_FLOATING (element));
gst_object_ref (GST_OBJECT (element));
gst_object_sink (GST_OBJECT (element));
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_IS_FLOATING (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/ref/sink/unref new element %d\n",
gst_alloc_trace_live_all () - usage1);
@ -55,9 +55,9 @@ main (int argc, gchar * argv[])
#if 0
element = gst_element_factory_make ("fakesrc", NULL);
g_assert (!GST_OBJECT_DESTROYED (element));
g_assert (!GST_OBJECT_IS_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
g_assert (GST_OBJECT_IS_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/destroy/unref new element %d\n",
gst_alloc_trace_live_all () - usage1);

View file

@ -27,8 +27,8 @@ main (int argc, gchar * argv[])
g_assert (GST_IS_ELEMENT (element));
pad = gst_element_get_pad (element, "sink");
g_assert (GST_IS_PAD (pad));
g_assert (GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_FLOATING (pad));
g_assert (GST_OBJECT_IS_FLOATING (element));
g_assert (!GST_OBJECT_IS_FLOATING (pad));
g_assert (gst_pad_get_parent (pad) == element);
gst_object_unref (GST_OBJECT (element));
g_print ("create/addpad/unref 1 new element: %ld\n", vmsize () - usage1);

View file

@ -52,10 +52,10 @@ main (int argc, gchar * argv[])
pad =
gst_pad_new_from_template (gst_static_pad_template_get (&templ),
"padname");
g_assert (GST_OBJECT_FLOATING (pad));
g_assert (GST_OBJECT_IS_FLOATING (pad));
gst_object_ref (GST_OBJECT (pad));
gst_object_sink (GST_OBJECT (pad));
g_assert (!GST_OBJECT_FLOATING (pad));
g_assert (!GST_OBJECT_IS_FLOATING (pad));
gst_object_unref (GST_OBJECT (pad));
g_print ("create/ref/sink/unref new pad %ld\n", vmsize () - usage1);

View file

@ -221,7 +221,7 @@ fault_handler_sighandler (int signum)
fault_spin ();
}
#else
#else /* USE_SIGINFO */
static void
fault_handler_sigaction (int signum, siginfo_t * si, void *misc)
@ -246,7 +246,7 @@ fault_handler_sigaction (int signum, siginfo_t * si, void *misc)
fault_spin ();
}
#endif
#endif /* USE_SIGINFO */
static void
fault_spin (void)
@ -293,7 +293,7 @@ fault_setup (void)
sigaction (SIGSEGV, &action, NULL);
sigaction (SIGQUIT, &action, NULL);
}
#endif
#endif /* DISABLE_FAULT_HANDLER */
static void
print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
@ -343,6 +343,8 @@ error_cb (GObject * object, GstObject * source, GError * error, gchar * debug)
static void
sigint_handler_sighandler (int signum)
{
g_print ("Caught interrupt -- ");
sigint_restore ();
caught_intr = TRUE;

View file

@ -52,8 +52,10 @@ main (int argc, char *argv[])
g_assert (GST_IS_ELEMENT (source));
typefind = gst_element_factory_make ("typefind", "typefind");
g_assert (GST_IS_ELEMENT (typefind));
gst_bin_add_many (GST_BIN (pipeline), source, typefind, NULL);
gst_element_link (source, typefind);
gst_bin_add (GST_BIN (pipeline), source);
gst_bin_add (GST_BIN (pipeline), typefind);
gst_pad_link (gst_element_get_pad (source, "src"),
gst_element_get_pad (typefind, "sink"));
g_signal_connect (G_OBJECT (typefind), "have-type",
G_CALLBACK (have_type_handler), NULL);